mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-09 14:47:56 -05:00
feat(tfhe): add zk-pok code base
- integration of work done by Sarah in the repo Co-authored-by: sarah el kazdadi <sarah.elkazdadi@zama.ai>
This commit is contained in:
4
.github/workflows/aws_tfhe_fast_tests.yml
vendored
4
.github/workflows/aws_tfhe_fast_tests.yml
vendored
@@ -60,6 +60,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
make test_concrete_csprng
|
make test_concrete_csprng
|
||||||
|
|
||||||
|
- name: Run tfhe-zk-pok tests
|
||||||
|
run: |
|
||||||
|
make test_zk_pok
|
||||||
|
|
||||||
- name: Run core tests
|
- name: Run core tests
|
||||||
run: |
|
run: |
|
||||||
AVX512_SUPPORT=ON make test_core_crypto
|
AVX512_SUPPORT=ON make test_core_crypto
|
||||||
|
|||||||
4
.github/workflows/aws_tfhe_tests.yml
vendored
4
.github/workflows/aws_tfhe_tests.yml
vendored
@@ -61,6 +61,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
make test_concrete_csprng
|
make test_concrete_csprng
|
||||||
|
|
||||||
|
- name: Run tfhe-zk-pok tests
|
||||||
|
run: |
|
||||||
|
make test_zk_pok
|
||||||
|
|
||||||
- name: Run core tests
|
- name: Run core tests
|
||||||
run: |
|
run: |
|
||||||
AVX512_SUPPORT=ON make test_core_crypto
|
AVX512_SUPPORT=ON make test_core_crypto
|
||||||
|
|||||||
4
.github/workflows/m1_tests.yml
vendored
4
.github/workflows/m1_tests.yml
vendored
@@ -74,6 +74,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
make test_concrete_csprng
|
make test_concrete_csprng
|
||||||
|
|
||||||
|
- name: Run tfhe-zk-pok tests
|
||||||
|
run: |
|
||||||
|
make test_zk_pok
|
||||||
|
|
||||||
- name: Run core tests
|
- name: Run core tests
|
||||||
run: |
|
run: |
|
||||||
make test_core_crypto
|
make test_core_crypto
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
"tfhe",
|
"tfhe",
|
||||||
|
"tfhe-zk-pok",
|
||||||
"tasks",
|
"tasks",
|
||||||
"apps/trivium",
|
"apps/trivium",
|
||||||
"concrete-csprng",
|
"concrete-csprng",
|
||||||
|
|||||||
12
Makefile
12
Makefile
@@ -283,9 +283,14 @@ clippy_concrete_csprng:
|
|||||||
--features=$(TARGET_ARCH_FEATURE) \
|
--features=$(TARGET_ARCH_FEATURE) \
|
||||||
-p concrete-csprng -- --no-deps -D warnings
|
-p concrete-csprng -- --no-deps -D warnings
|
||||||
|
|
||||||
|
.PHONY: clippy_zk_pok # Run clippy lints on tfhe-zk-pok
|
||||||
|
clippy_zk_pok:
|
||||||
|
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy --all-targets \
|
||||||
|
-p tfhe-zk-pok -- --no-deps -D warnings
|
||||||
|
|
||||||
.PHONY: clippy_all # Run all clippy targets
|
.PHONY: clippy_all # Run all clippy targets
|
||||||
clippy_all: clippy clippy_boolean clippy_shortint clippy_integer clippy_all_targets clippy_c_api \
|
clippy_all: clippy clippy_boolean clippy_shortint clippy_integer clippy_all_targets clippy_c_api \
|
||||||
clippy_js_wasm_api clippy_tasks clippy_core clippy_concrete_csprng clippy_trivium
|
clippy_js_wasm_api clippy_tasks clippy_core clippy_concrete_csprng clippy_zk_pok clippy_trivium
|
||||||
|
|
||||||
.PHONY: clippy_fast # Run main clippy targets
|
.PHONY: clippy_fast # Run main clippy targets
|
||||||
clippy_fast: clippy clippy_all_targets clippy_c_api clippy_js_wasm_api clippy_tasks clippy_core \
|
clippy_fast: clippy clippy_all_targets clippy_c_api clippy_js_wasm_api clippy_tasks clippy_core \
|
||||||
@@ -628,6 +633,11 @@ test_concrete_csprng:
|
|||||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
||||||
--features=$(TARGET_ARCH_FEATURE) -p concrete-csprng
|
--features=$(TARGET_ARCH_FEATURE) -p concrete-csprng
|
||||||
|
|
||||||
|
.PHONY: test_zk_pok # Run tfhe-zk-pok tests
|
||||||
|
test_zk_pok:
|
||||||
|
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
||||||
|
-p tfhe-zk-pok
|
||||||
|
|
||||||
.PHONY: doc # Build rust doc
|
.PHONY: doc # Build rust doc
|
||||||
doc: install_rs_check_toolchain
|
doc: install_rs_check_toolchain
|
||||||
@# Even though we are not in docs.rs, this allows to "just" build the doc
|
@# Even though we are not in docs.rs, this allows to "just" build the doc
|
||||||
|
|||||||
1
tfhe-zk-pok/.gitignore
vendored
Normal file
1
tfhe-zk-pok/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
21
tfhe-zk-pok/Cargo.toml
Normal file
21
tfhe-zk-pok/Cargo.toml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
[package]
|
||||||
|
name = "tfhe-zk-pok"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ark-bls12-381 = "0.4.0"
|
||||||
|
ark-ec = "0.4.2"
|
||||||
|
ark-ff = "0.4.2"
|
||||||
|
ark-poly = "0.4.2"
|
||||||
|
rand = "0.8.5"
|
||||||
|
rayon = "1.8.0"
|
||||||
|
sha3 = "0.10.8"
|
||||||
|
serde = { version = "~1.0", features = ["derive"] }
|
||||||
|
ark-serialize = { version = "0.4.2" }
|
||||||
|
zeroize = "1.7.0"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
serde_json = "~1.0"
|
||||||
772
tfhe-zk-pok/src/curve_446/mod.rs
Normal file
772
tfhe-zk-pok/src/curve_446/mod.rs
Normal file
@@ -0,0 +1,772 @@
|
|||||||
|
use ark_ec::bls12::{Bls12, Bls12Config, TwistType};
|
||||||
|
use ark_ff::fields::*;
|
||||||
|
use ark_ff::MontFp;
|
||||||
|
|
||||||
|
#[derive(MontConfig)]
|
||||||
|
#[modulus = "645383785691237230677916041525710377746967055506026847120930304831624105190538527824412673"]
|
||||||
|
#[generator = "7"]
|
||||||
|
#[small_subgroup_base = "3"]
|
||||||
|
#[small_subgroup_power = "1"]
|
||||||
|
pub struct FrConfig;
|
||||||
|
pub type Fr = Fp320<MontBackend<FrConfig, 5>>;
|
||||||
|
|
||||||
|
#[derive(MontConfig)]
|
||||||
|
#[modulus = "172824703542857155980071276579495962243492693522789898437834836356385656662277472896902502740297183690175962001546428467344062165330603"]
|
||||||
|
#[generator = "2"]
|
||||||
|
#[small_subgroup_base = "3"]
|
||||||
|
#[small_subgroup_power = "1"]
|
||||||
|
pub struct FqConfig;
|
||||||
|
pub type Fq = Fp448<MontBackend<FqConfig, 7>>;
|
||||||
|
|
||||||
|
pub type Fq2 = Fp2<Fq2Config>;
|
||||||
|
|
||||||
|
pub struct Fq2Config;
|
||||||
|
|
||||||
|
impl Fp2Config for Fq2Config {
|
||||||
|
type Fp = Fq;
|
||||||
|
|
||||||
|
/// NONRESIDUE = -1
|
||||||
|
const NONRESIDUE: Fq = MontFp!("-1");
|
||||||
|
|
||||||
|
/// Coefficients for the Frobenius automorphism.
|
||||||
|
const FROBENIUS_COEFF_FP2_C1: &'static [Fq] = &[
|
||||||
|
// Fq(-1)**(((q^0) - 1) / 2)
|
||||||
|
Fq::ONE,
|
||||||
|
// Fq(-1)**(((q^1) - 1) / 2)
|
||||||
|
MontFp!("-1"),
|
||||||
|
];
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn mul_fp_by_nonresidue_in_place(fp: &mut Self::Fp) -> &mut Self::Fp {
|
||||||
|
fp.neg_in_place()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn sub_and_mul_fp_by_nonresidue(y: &mut Self::Fp, x: &Self::Fp) {
|
||||||
|
*y += x;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn mul_fp_by_nonresidue_plus_one_and_add(y: &mut Self::Fp, x: &Self::Fp) {
|
||||||
|
*y = *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mul_fp_by_nonresidue_and_add(y: &mut Self::Fp, x: &Self::Fp) {
|
||||||
|
y.neg_in_place();
|
||||||
|
*y += x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Fq6 = Fp6<Fq6Config>;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Fq6Config;
|
||||||
|
|
||||||
|
impl Fp6Config for Fq6Config {
|
||||||
|
type Fp2Config = Fq2Config;
|
||||||
|
|
||||||
|
/// NONRESIDUE = (U + 1)
|
||||||
|
const NONRESIDUE: Fq2 = Fq2::new(Fq::ONE, Fq::ONE);
|
||||||
|
|
||||||
|
const FROBENIUS_COEFF_FP6_C1: &'static [Fq2] = &[
|
||||||
|
// Fp2::NONRESIDUE^(((q^0) - 1) / 3)
|
||||||
|
Fq2::new(
|
||||||
|
Fq::ONE,
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^1) - 1) / 3)
|
||||||
|
Fq2::new(
|
||||||
|
Fq::ZERO,
|
||||||
|
MontFp!("-18292478899820133222385880210918854254706405831091403105831645830694649873798259945392135397923436410689931051013"),
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^2) - 1) / 3)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("18292478899820133222385880210918854254706405831091403105831645830694649873798259945392135397923436410689931051012"),
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^3) - 1) / 3)
|
||||||
|
Fq2::new(
|
||||||
|
Fq::ZERO,
|
||||||
|
Fq::ONE,
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^4) - 1) / 3)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("-18292478899820133222385880210918854254706405831091403105831645830694649873798259945392135397923436410689931051013"),
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^5) - 1) / 3)
|
||||||
|
Fq2::new(
|
||||||
|
Fq::ZERO,
|
||||||
|
MontFp!("18292478899820133222385880210918854254706405831091403105831645830694649873798259945392135397923436410689931051012"),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
const FROBENIUS_COEFF_FP6_C2: &'static [Fq2] = &[
|
||||||
|
// Fq2(u + 1)**(((2q^0) - 2) / 3)
|
||||||
|
Fq2::new(
|
||||||
|
Fq::ONE,
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
// Fq2(u + 1)**(((2q^1) - 2) / 3)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("-18292478899820133222385880210918854254706405831091403105831645830694649873798259945392135397923436410689931051012"),
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
// Fq2(u + 1)**(((2q^2) - 2) / 3)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("-18292478899820133222385880210918854254706405831091403105831645830694649873798259945392135397923436410689931051013"),
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
// Fq2(u + 1)**(((2q^3) - 2) / 3)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("-1"),
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
// Fq2(u + 1)**(((2q^4) - 2) / 3)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("18292478899820133222385880210918854254706405831091403105831645830694649873798259945392135397923436410689931051012"),
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
// Fq2(u + 1)**(((2q^5) - 2) / 3)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("18292478899820133222385880210918854254706405831091403105831645830694649873798259945392135397923436410689931051013"),
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Multiply this element by the quadratic nonresidue 1 + u.
|
||||||
|
/// Make this generic.
|
||||||
|
fn mul_fp2_by_nonresidue_in_place(fe: &mut Fq2) -> &mut Fq2 {
|
||||||
|
let t0 = fe.c0;
|
||||||
|
fe.c0 -= &fe.c1;
|
||||||
|
fe.c1 += &t0;
|
||||||
|
fe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Fq12 = Fp12<Fq12Config>;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Fq12Config;
|
||||||
|
|
||||||
|
impl Fp12Config for Fq12Config {
|
||||||
|
type Fp6Config = Fq6Config;
|
||||||
|
|
||||||
|
const NONRESIDUE: Fq6 = Fq6::new(Fq2::ZERO, Fq2::ONE, Fq2::ZERO);
|
||||||
|
|
||||||
|
const FROBENIUS_COEFF_FP12_C1: &'static [Fq2] = &[
|
||||||
|
// Fp2::NONRESIDUE^(((q^0) - 1) / 6)
|
||||||
|
Fq2::new(
|
||||||
|
Fq::ONE,
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^1) - 1) / 6)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("22118644822122453894295732432166425368368980329889476319266915965514828099635526724748286229964921634997234117686841299669336163301597"),
|
||||||
|
MontFp!("-22118644822122453894295732432166425368368980329889476319266915965514828099635526724748286229964921634997234117686841299669336163301597"),
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^2) - 1) / 6)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("18292478899820133222385880210918854254706405831091403105831645830694649873798259945392135397923436410689931051013"),
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^3) - 1) / 6)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("-84459159508829117195668840503504856816171858703899096210464197465513610215112549935889502423482516188066933947513637464187184810836060"),
|
||||||
|
MontFp!("84459159508829117195668840503504856816171858703899096210464197465513610215112549935889502423482516188066933947513637464187184810836060"),
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^4) - 1) / 6)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("18292478899820133222385880210918854254706405831091403105831645830694649873798259945392135397923436410689931051012"),
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^5) - 1) / 6)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("66246899211905584890106703643824680058951854489001325908103722925357218347529396236264714086849745867111793936345949703487541191192946"),
|
||||||
|
MontFp!("-66246899211905584890106703643824680058951854489001325908103722925357218347529396236264714086849745867111793936345949703487541191192946"),
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^6) - 1) / 6)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("-1"),
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^7) - 1) / 6)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("-22118644822122453894295732432166425368368980329889476319266915965514828099635526724748286229964921634997234117686841299669336163301597"),
|
||||||
|
MontFp!("22118644822122453894295732432166425368368980329889476319266915965514828099635526724748286229964921634997234117686841299669336163301597"),
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^8) - 1) / 6)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("-18292478899820133222385880210918854254706405831091403105831645830694649873798259945392135397923436410689931051013"),
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^9) - 1) / 6)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("84459159508829117195668840503504856816171858703899096210464197465513610215112549935889502423482516188066933947513637464187184810836060"),
|
||||||
|
MontFp!("-84459159508829117195668840503504856816171858703899096210464197465513610215112549935889502423482516188066933947513637464187184810836060"),
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^10) - 1) / 6)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("-18292478899820133222385880210918854254706405831091403105831645830694649873798259945392135397923436410689931051012"),
|
||||||
|
Fq::ZERO,
|
||||||
|
),
|
||||||
|
// Fp2::NONRESIDUE^(((q^11) - 1) / 6)
|
||||||
|
Fq2::new(
|
||||||
|
MontFp!("-66246899211905584890106703643824680058951854489001325908103722925357218347529396236264714086849745867111793936345949703487541191192946"),
|
||||||
|
MontFp!("66246899211905584890106703643824680058951854489001325908103722925357218347529396236264714086849745867111793936345949703487541191192946"),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Bls12_446 = Bls12<Config>;
|
||||||
|
use g1::G1Affine;
|
||||||
|
use g2::G2Affine;
|
||||||
|
|
||||||
|
pub struct Config;
|
||||||
|
|
||||||
|
impl Bls12Config for Config {
|
||||||
|
const X: &'static [u64] = &[0x8204000000020001, 0x600];
|
||||||
|
const X_IS_NEGATIVE: bool = true;
|
||||||
|
const TWIST_TYPE: TwistType = TwistType::M;
|
||||||
|
type Fp = Fq;
|
||||||
|
type Fp2Config = Fq2Config;
|
||||||
|
type Fp6Config = Fq6Config;
|
||||||
|
type Fp12Config = Fq12Config;
|
||||||
|
type G1Config = g1::Config;
|
||||||
|
type G2Config = g2::Config;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod util {
|
||||||
|
use ark_ec::short_weierstrass::Affine;
|
||||||
|
use ark_ec::AffineRepr;
|
||||||
|
use ark_ff::{BigInteger448, PrimeField};
|
||||||
|
use ark_serialize::SerializationError;
|
||||||
|
|
||||||
|
use super::g1::Config as G1Config;
|
||||||
|
use super::g2::Config as G2Config;
|
||||||
|
use super::{Fq, Fq2, G1Affine, G2Affine};
|
||||||
|
|
||||||
|
pub const G1_SERIALIZED_SIZE: usize = 57;
|
||||||
|
pub const G2_SERIALIZED_SIZE: usize = 114;
|
||||||
|
|
||||||
|
pub struct EncodingFlags {
|
||||||
|
pub is_compressed: bool,
|
||||||
|
pub is_infinity: bool,
|
||||||
|
pub is_lexographically_largest: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncodingFlags {
|
||||||
|
pub fn get_flags(bytes: &[u8]) -> Self {
|
||||||
|
let compression_flag_set = (bytes[0] >> 7) & 1;
|
||||||
|
let infinity_flag_set = (bytes[0] >> 6) & 1;
|
||||||
|
let sort_flag_set = (bytes[0] >> 5) & 1;
|
||||||
|
|
||||||
|
Self {
|
||||||
|
is_compressed: compression_flag_set == 1,
|
||||||
|
is_infinity: infinity_flag_set == 1,
|
||||||
|
is_lexographically_largest: sort_flag_set == 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn encode_flags(&self, bytes: &mut [u8]) {
|
||||||
|
if self.is_compressed {
|
||||||
|
bytes[0] |= 1 << 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.is_infinity {
|
||||||
|
bytes[0] |= 1 << 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.is_compressed && !self.is_infinity && self.is_lexographically_largest {
|
||||||
|
bytes[0] |= 1 << 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn deserialize_fq(bytes: [u8; 56]) -> Option<Fq> {
|
||||||
|
let mut tmp = BigInteger448::new([0, 0, 0, 0, 0, 0, 0]);
|
||||||
|
|
||||||
|
// Note: The following unwraps are if the compiler cannot convert
|
||||||
|
// the byte slice into [u8;8], we know this is infallible since we
|
||||||
|
// are providing the indices at compile time and bytes has a fixed size
|
||||||
|
tmp.0[6] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[0..8]).unwrap());
|
||||||
|
tmp.0[5] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[8..16]).unwrap());
|
||||||
|
tmp.0[4] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[16..24]).unwrap());
|
||||||
|
tmp.0[3] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[24..32]).unwrap());
|
||||||
|
tmp.0[2] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[32..40]).unwrap());
|
||||||
|
tmp.0[1] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[40..48]).unwrap());
|
||||||
|
tmp.0[0] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[48..56]).unwrap());
|
||||||
|
|
||||||
|
Fq::from_bigint(tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn serialize_fq(field: Fq) -> [u8; 56] {
|
||||||
|
let mut result = [0u8; 56];
|
||||||
|
|
||||||
|
let rep = field.into_bigint();
|
||||||
|
|
||||||
|
result[0..8].copy_from_slice(&rep.0[6].to_be_bytes());
|
||||||
|
result[8..16].copy_from_slice(&rep.0[5].to_be_bytes());
|
||||||
|
result[16..24].copy_from_slice(&rep.0[4].to_be_bytes());
|
||||||
|
result[24..32].copy_from_slice(&rep.0[3].to_be_bytes());
|
||||||
|
result[32..40].copy_from_slice(&rep.0[2].to_be_bytes());
|
||||||
|
result[40..48].copy_from_slice(&rep.0[1].to_be_bytes());
|
||||||
|
result[48..56].copy_from_slice(&rep.0[0].to_be_bytes());
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_fq_with_offset(
|
||||||
|
bytes: &[u8],
|
||||||
|
offset: usize,
|
||||||
|
) -> Result<Fq, ark_serialize::SerializationError> {
|
||||||
|
let mut tmp = [0; G1_SERIALIZED_SIZE - 1];
|
||||||
|
// read `G1_SERIALIZED_SIZE` bytes
|
||||||
|
tmp.copy_from_slice(
|
||||||
|
&bytes[offset * G1_SERIALIZED_SIZE + 1..G1_SERIALIZED_SIZE * (offset + 1)],
|
||||||
|
);
|
||||||
|
|
||||||
|
deserialize_fq(tmp).ok_or(SerializationError::InvalidData)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_g1_compressed<R: ark_serialize::Read>(
|
||||||
|
mut reader: R,
|
||||||
|
) -> Result<Affine<G1Config>, ark_serialize::SerializationError> {
|
||||||
|
let mut bytes = [0u8; G1_SERIALIZED_SIZE];
|
||||||
|
reader
|
||||||
|
.read_exact(&mut bytes)
|
||||||
|
.ok()
|
||||||
|
.ok_or(SerializationError::InvalidData)?;
|
||||||
|
|
||||||
|
// Obtain the three flags from the start of the byte sequence
|
||||||
|
let flags = EncodingFlags::get_flags(&bytes[..]);
|
||||||
|
|
||||||
|
// we expect to be deserializing a compressed point
|
||||||
|
if !flags.is_compressed {
|
||||||
|
return Err(SerializationError::UnexpectedFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if flags.is_infinity {
|
||||||
|
return Ok(G1Affine::zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to obtain the x-coordinate
|
||||||
|
let x = read_fq_with_offset(&bytes, 0)?;
|
||||||
|
|
||||||
|
let p = G1Affine::get_point_from_x_unchecked(x, flags.is_lexographically_largest)
|
||||||
|
.ok_or(SerializationError::InvalidData)?;
|
||||||
|
|
||||||
|
Ok(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_g1_uncompressed<R: ark_serialize::Read>(
|
||||||
|
mut reader: R,
|
||||||
|
) -> Result<Affine<G1Config>, ark_serialize::SerializationError> {
|
||||||
|
let mut bytes = [0u8; 2 * G1_SERIALIZED_SIZE];
|
||||||
|
reader
|
||||||
|
.read_exact(&mut bytes)
|
||||||
|
.map_err(|_| SerializationError::InvalidData)?;
|
||||||
|
|
||||||
|
// Obtain the three flags from the start of the byte sequence
|
||||||
|
let flags = EncodingFlags::get_flags(&bytes[..]);
|
||||||
|
|
||||||
|
// we expect to be deserializing an uncompressed point
|
||||||
|
if flags.is_compressed {
|
||||||
|
return Err(SerializationError::UnexpectedFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if flags.is_infinity {
|
||||||
|
return Ok(G1Affine::zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to obtain the x-coordinate
|
||||||
|
let x = read_fq_with_offset(&bytes, 0)?;
|
||||||
|
// Attempt to obtain the y-coordinate
|
||||||
|
let y = read_fq_with_offset(&bytes, 1)?;
|
||||||
|
|
||||||
|
let p = G1Affine::new_unchecked(x, y);
|
||||||
|
|
||||||
|
Ok(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_g2_compressed<R: ark_serialize::Read>(
|
||||||
|
mut reader: R,
|
||||||
|
) -> Result<Affine<G2Config>, ark_serialize::SerializationError> {
|
||||||
|
let mut bytes = [0u8; G2_SERIALIZED_SIZE];
|
||||||
|
reader
|
||||||
|
.read_exact(&mut bytes)
|
||||||
|
.map_err(|_| SerializationError::InvalidData)?;
|
||||||
|
|
||||||
|
// Obtain the three flags from the start of the byte sequence
|
||||||
|
let flags = EncodingFlags::get_flags(&bytes);
|
||||||
|
|
||||||
|
// we expect to be deserializing a compressed point
|
||||||
|
if !flags.is_compressed {
|
||||||
|
return Err(SerializationError::UnexpectedFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if flags.is_infinity {
|
||||||
|
return Ok(G2Affine::zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to obtain the x-coordinate
|
||||||
|
let xc1 = read_fq_with_offset(&bytes, 0)?;
|
||||||
|
let xc0 = read_fq_with_offset(&bytes, 1)?;
|
||||||
|
|
||||||
|
let x = Fq2::new(xc0, xc1);
|
||||||
|
|
||||||
|
let p = G2Affine::get_point_from_x_unchecked(x, flags.is_lexographically_largest)
|
||||||
|
.ok_or(SerializationError::InvalidData)?;
|
||||||
|
|
||||||
|
Ok(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_g2_uncompressed<R: ark_serialize::Read>(
|
||||||
|
mut reader: R,
|
||||||
|
) -> Result<Affine<G2Config>, ark_serialize::SerializationError> {
|
||||||
|
let mut bytes = [0u8; 2 * G2_SERIALIZED_SIZE];
|
||||||
|
reader
|
||||||
|
.read_exact(&mut bytes)
|
||||||
|
.map_err(|_| SerializationError::InvalidData)?;
|
||||||
|
|
||||||
|
// Obtain the three flags from the start of the byte sequence
|
||||||
|
let flags = EncodingFlags::get_flags(&bytes);
|
||||||
|
|
||||||
|
// we expect to be deserializing an uncompressed point
|
||||||
|
if flags.is_compressed {
|
||||||
|
return Err(SerializationError::UnexpectedFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if flags.is_infinity {
|
||||||
|
return Ok(G2Affine::zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to obtain the x-coordinate
|
||||||
|
let xc1 = read_fq_with_offset(&bytes, 0)?;
|
||||||
|
let xc0 = read_fq_with_offset(&bytes, 1)?;
|
||||||
|
let x = Fq2::new(xc0, xc1);
|
||||||
|
|
||||||
|
// Attempt to obtain the y-coordinate
|
||||||
|
let yc1 = read_fq_with_offset(&bytes, 2)?;
|
||||||
|
let yc0 = read_fq_with_offset(&bytes, 3)?;
|
||||||
|
let y = Fq2::new(yc0, yc1);
|
||||||
|
|
||||||
|
let p = G2Affine::new_unchecked(x, y);
|
||||||
|
|
||||||
|
Ok(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod g1 {
|
||||||
|
use super::util::{
|
||||||
|
read_g1_compressed, read_g1_uncompressed, serialize_fq, EncodingFlags, G1_SERIALIZED_SIZE,
|
||||||
|
};
|
||||||
|
use super::{Fq, Fr};
|
||||||
|
use ark_ec::bls12::Bls12Config;
|
||||||
|
use ark_ec::models::CurveConfig;
|
||||||
|
use ark_ec::short_weierstrass::{Affine, SWCurveConfig};
|
||||||
|
use ark_ec::{bls12, AffineRepr, Group};
|
||||||
|
use ark_ff::{Field, MontFp, One, PrimeField, Zero};
|
||||||
|
use ark_serialize::{Compress, SerializationError};
|
||||||
|
use core::ops::Neg;
|
||||||
|
|
||||||
|
#[derive(Clone, Default, PartialEq, Eq)]
|
||||||
|
pub struct Config;
|
||||||
|
|
||||||
|
impl CurveConfig for Config {
|
||||||
|
type BaseField = Fq;
|
||||||
|
type ScalarField = Fr;
|
||||||
|
|
||||||
|
/// COFACTOR = (x - 1)^2 / 3 = 267785939737784928360481681640896166738700972
|
||||||
|
const COFACTOR: &'static [u64] = &[0xad5aaaac0002aaac, 0x2602b0055d560ab0, 0xc0208];
|
||||||
|
|
||||||
|
/// COFACTOR_INV = COFACTOR^{-1} mod r
|
||||||
|
/// = 645383785691237230677779421366207365261112665008071669867241543525136277620937226389553150
|
||||||
|
const COFACTOR_INV: Fr =
|
||||||
|
MontFp!("645383785691237230677779421366207365261112665008071669867241543525136277620937226389553150");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type G1Affine = bls12::G1Affine<super::Config>;
|
||||||
|
pub type G1Projective = bls12::G1Projective<super::Config>;
|
||||||
|
|
||||||
|
impl SWCurveConfig for Config {
|
||||||
|
/// COEFF_A = 0
|
||||||
|
const COEFF_A: Fq = Fq::ZERO;
|
||||||
|
|
||||||
|
/// COEFF_B = 1
|
||||||
|
const COEFF_B: Fq = MontFp!("1");
|
||||||
|
|
||||||
|
/// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y)
|
||||||
|
const GENERATOR: G1Affine = G1Affine::new_unchecked(G1_GENERATOR_X, G1_GENERATOR_Y);
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn mul_by_a(_: Self::BaseField) -> Self::BaseField {
|
||||||
|
Self::BaseField::zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_in_correct_subgroup_assuming_on_curve(p: &G1Affine) -> bool {
|
||||||
|
// Algorithm from Section 6 of https://eprint.iacr.org/2021/1130.
|
||||||
|
//
|
||||||
|
// Check that endomorphism_p(P) == -[X^2]P
|
||||||
|
|
||||||
|
// An early-out optimization described in Section 6.
|
||||||
|
// If uP == P but P != point of infinity, then the point is not in the right
|
||||||
|
// subgroup.
|
||||||
|
let x_times_p = p.mul_bigint(super::Config::X);
|
||||||
|
if x_times_p.eq(p) && !p.infinity {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let minus_x_squared_times_p = x_times_p.mul_bigint(super::Config::X).neg();
|
||||||
|
let endomorphism_p = endomorphism(p);
|
||||||
|
minus_x_squared_times_p.eq(&endomorphism_p)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn clear_cofactor(p: &G1Affine) -> G1Affine {
|
||||||
|
// Using the effective cofactor, as explained in
|
||||||
|
// Section 5 of https://eprint.iacr.org/2019/403.pdf.
|
||||||
|
//
|
||||||
|
// It is enough to multiply by (1 - x), instead of (x - 1)^2 / 3
|
||||||
|
let h_eff = one_minus_x().into_bigint();
|
||||||
|
Config::mul_affine(p, h_eff.as_ref()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_with_mode<R: ark_serialize::Read>(
|
||||||
|
mut reader: R,
|
||||||
|
compress: ark_serialize::Compress,
|
||||||
|
validate: ark_serialize::Validate,
|
||||||
|
) -> Result<Affine<Self>, ark_serialize::SerializationError> {
|
||||||
|
let p = if compress == ark_serialize::Compress::Yes {
|
||||||
|
read_g1_compressed(&mut reader)?
|
||||||
|
} else {
|
||||||
|
read_g1_uncompressed(&mut reader)?
|
||||||
|
};
|
||||||
|
|
||||||
|
if validate == ark_serialize::Validate::Yes
|
||||||
|
&& !p.is_in_correct_subgroup_assuming_on_curve()
|
||||||
|
{
|
||||||
|
return Err(SerializationError::InvalidData);
|
||||||
|
}
|
||||||
|
Ok(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_with_mode<W: ark_serialize::Write>(
|
||||||
|
item: &Affine<Self>,
|
||||||
|
mut writer: W,
|
||||||
|
compress: ark_serialize::Compress,
|
||||||
|
) -> Result<(), SerializationError> {
|
||||||
|
let encoding = EncodingFlags {
|
||||||
|
is_compressed: compress == ark_serialize::Compress::Yes,
|
||||||
|
is_infinity: item.is_zero(),
|
||||||
|
is_lexographically_largest: item.y > -item.y,
|
||||||
|
};
|
||||||
|
let mut p = *item;
|
||||||
|
if encoding.is_infinity {
|
||||||
|
p = G1Affine::zero();
|
||||||
|
}
|
||||||
|
// need to access the field struct `x` directly, otherwise we get None from xy()
|
||||||
|
// method
|
||||||
|
let x_bytes = serialize_fq(p.x);
|
||||||
|
if encoding.is_compressed {
|
||||||
|
let mut bytes = [0u8; G1_SERIALIZED_SIZE];
|
||||||
|
bytes[1..].copy_from_slice(&x_bytes);
|
||||||
|
|
||||||
|
encoding.encode_flags(&mut bytes);
|
||||||
|
writer.write_all(&bytes)?;
|
||||||
|
} else {
|
||||||
|
let mut bytes = [0u8; 2 * G1_SERIALIZED_SIZE];
|
||||||
|
bytes[1..1 + G1_SERIALIZED_SIZE].copy_from_slice(&x_bytes[..]);
|
||||||
|
bytes[2 + G1_SERIALIZED_SIZE..].copy_from_slice(&serialize_fq(p.y)[..]);
|
||||||
|
|
||||||
|
encoding.encode_flags(&mut bytes);
|
||||||
|
writer.write_all(&bytes)?;
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialized_size(compress: Compress) -> usize {
|
||||||
|
if compress == Compress::Yes {
|
||||||
|
G1_SERIALIZED_SIZE
|
||||||
|
} else {
|
||||||
|
G1_SERIALIZED_SIZE * 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn one_minus_x() -> Fr {
|
||||||
|
const X: Fr = Fr::from_sign_and_limbs(!super::Config::X_IS_NEGATIVE, super::Config::X);
|
||||||
|
Fr::one() - X
|
||||||
|
}
|
||||||
|
|
||||||
|
/// G1_GENERATOR_X =
|
||||||
|
/// 143189966182216199425404656824735381247272236095050141599848381692039676741476615087722874458136990266833440576646963466074693171606778
|
||||||
|
pub const G1_GENERATOR_X: Fq = MontFp!("143189966182216199425404656824735381247272236095050141599848381692039676741476615087722874458136990266833440576646963466074693171606778");
|
||||||
|
|
||||||
|
/// G1_GENERATOR_Y =
|
||||||
|
/// 75202396197342917254523279069469674666303680671605970245803554133573745859131002231546341942288521574682619325841484506619191207488304
|
||||||
|
pub const G1_GENERATOR_Y: Fq = MontFp!("75202396197342917254523279069469674666303680671605970245803554133573745859131002231546341942288521574682619325841484506619191207488304");
|
||||||
|
|
||||||
|
/// BETA is a non-trivial cubic root of unity in Fq.
|
||||||
|
pub const BETA: Fq = MontFp!("18292478899820133222385880210918854254706405831091403105831645830694649873798259945392135397923436410689931051012");
|
||||||
|
|
||||||
|
pub fn endomorphism(p: &Affine<Config>) -> Affine<Config> {
|
||||||
|
// Endomorphism of the points on the curve.
|
||||||
|
// endomorphism_p(x,y) = (BETA * x, y)
|
||||||
|
// where BETA is a non-trivial cubic root of unity in Fq.
|
||||||
|
let mut res = *p;
|
||||||
|
res.x *= BETA;
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod g2 {
|
||||||
|
use super::util::{
|
||||||
|
read_g2_compressed, read_g2_uncompressed, serialize_fq, EncodingFlags, G2_SERIALIZED_SIZE,
|
||||||
|
};
|
||||||
|
use super::*;
|
||||||
|
use ark_ec::models::CurveConfig;
|
||||||
|
use ark_ec::short_weierstrass::{Affine, SWCurveConfig};
|
||||||
|
use ark_ec::{bls12, AffineRepr};
|
||||||
|
use ark_ff::{MontFp, Zero};
|
||||||
|
use ark_serialize::{Compress, SerializationError};
|
||||||
|
|
||||||
|
pub type G2Affine = bls12::G2Affine<super::Config>;
|
||||||
|
pub type G2Projective = bls12::G2Projective<super::Config>;
|
||||||
|
|
||||||
|
#[derive(Clone, Default, PartialEq, Eq)]
|
||||||
|
pub struct Config;
|
||||||
|
|
||||||
|
impl CurveConfig for Config {
|
||||||
|
type BaseField = Fq2;
|
||||||
|
type ScalarField = Fr;
|
||||||
|
|
||||||
|
/// COFACTOR = (x^8 - 4 x^7 + 5 x^6) - (4 x^4 + 6 x^3 - 4 x^2 - 4 x + 13) //
|
||||||
|
/// 9
|
||||||
|
/// = 46280025648128091779281203587029183771098593081950199160533444883894201638329761721685747232785203763275581499269893683911356926248942802726857101798724933488377584092259436345573
|
||||||
|
const COFACTOR: &'static [u64] = &[
|
||||||
|
0xce555594000638e5,
|
||||||
|
0xa75088593e6a92ef,
|
||||||
|
0xc81e026dd55b51d6,
|
||||||
|
0x47f8e24b79369c54,
|
||||||
|
0x74c3560ced298d51,
|
||||||
|
0x7cefe5c3dd2555cb,
|
||||||
|
0x657742bf55690156,
|
||||||
|
0x5780484639bf731d,
|
||||||
|
0x3988a06f1bb3444d,
|
||||||
|
0x2daee,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// COFACTOR_INV = COFACTOR^{-1} mod r
|
||||||
|
/// 420747440395392227734782296805460539842466911252881029283882861015362447833828968293150382
|
||||||
|
const COFACTOR_INV: Fr = MontFp!(
|
||||||
|
"420747440395392227734782296805460539842466911252881029283882861015362447833828968293150382"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SWCurveConfig for Config {
|
||||||
|
/// COEFF_A = [0, 0]
|
||||||
|
const COEFF_A: Fq2 = Fq2::new(g1::Config::COEFF_A, g1::Config::COEFF_A);
|
||||||
|
|
||||||
|
/// COEFF_B = [1, 1]
|
||||||
|
const COEFF_B: Fq2 = Fq2::new(g1::Config::COEFF_B, g1::Config::COEFF_B);
|
||||||
|
|
||||||
|
/// AFFINE_GENERATOR_COEFFS = (G2_GENERATOR_X, G2_GENERATOR_Y)
|
||||||
|
const GENERATOR: G2Affine = G2Affine::new_unchecked(G2_GENERATOR_X, G2_GENERATOR_Y);
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn mul_by_a(_: Self::BaseField) -> Self::BaseField {
|
||||||
|
Self::BaseField::zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_with_mode<R: ark_serialize::Read>(
|
||||||
|
mut reader: R,
|
||||||
|
compress: ark_serialize::Compress,
|
||||||
|
validate: ark_serialize::Validate,
|
||||||
|
) -> Result<Affine<Self>, ark_serialize::SerializationError> {
|
||||||
|
let p = if compress == ark_serialize::Compress::Yes {
|
||||||
|
read_g2_compressed(&mut reader)?
|
||||||
|
} else {
|
||||||
|
read_g2_uncompressed(&mut reader)?
|
||||||
|
};
|
||||||
|
|
||||||
|
if validate == ark_serialize::Validate::Yes
|
||||||
|
&& !p.is_in_correct_subgroup_assuming_on_curve()
|
||||||
|
{
|
||||||
|
return Err(SerializationError::InvalidData);
|
||||||
|
}
|
||||||
|
Ok(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_with_mode<W: ark_serialize::Write>(
|
||||||
|
item: &Affine<Self>,
|
||||||
|
mut writer: W,
|
||||||
|
compress: ark_serialize::Compress,
|
||||||
|
) -> Result<(), SerializationError> {
|
||||||
|
let encoding = EncodingFlags {
|
||||||
|
is_compressed: compress == ark_serialize::Compress::Yes,
|
||||||
|
is_infinity: item.is_zero(),
|
||||||
|
is_lexographically_largest: item.y > -item.y,
|
||||||
|
};
|
||||||
|
let mut p = *item;
|
||||||
|
if encoding.is_infinity {
|
||||||
|
p = G2Affine::zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut x_bytes = [0u8; G2_SERIALIZED_SIZE];
|
||||||
|
let c1_bytes = serialize_fq(p.x.c1);
|
||||||
|
let c0_bytes = serialize_fq(p.x.c0);
|
||||||
|
x_bytes[1..56 + 1].copy_from_slice(&c1_bytes[..]);
|
||||||
|
x_bytes[56 + 2..114].copy_from_slice(&c0_bytes[..]);
|
||||||
|
if encoding.is_compressed {
|
||||||
|
let mut bytes: [u8; G2_SERIALIZED_SIZE] = x_bytes;
|
||||||
|
|
||||||
|
encoding.encode_flags(&mut bytes);
|
||||||
|
writer.write_all(&bytes)?;
|
||||||
|
} else {
|
||||||
|
let mut bytes = [0u8; 2 * G2_SERIALIZED_SIZE];
|
||||||
|
|
||||||
|
let mut y_bytes = [0u8; G2_SERIALIZED_SIZE];
|
||||||
|
let c1_bytes = serialize_fq(p.y.c1);
|
||||||
|
let c0_bytes = serialize_fq(p.y.c0);
|
||||||
|
y_bytes[1..56 + 1].copy_from_slice(&c1_bytes[..]);
|
||||||
|
y_bytes[56 + 2..114].copy_from_slice(&c0_bytes[..]);
|
||||||
|
bytes[0..G2_SERIALIZED_SIZE].copy_from_slice(&x_bytes);
|
||||||
|
bytes[G2_SERIALIZED_SIZE..].copy_from_slice(&y_bytes);
|
||||||
|
|
||||||
|
encoding.encode_flags(&mut bytes);
|
||||||
|
writer.write_all(&bytes)?;
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialized_size(compress: ark_serialize::Compress) -> usize {
|
||||||
|
if compress == Compress::Yes {
|
||||||
|
G2_SERIALIZED_SIZE
|
||||||
|
} else {
|
||||||
|
2 * G2_SERIALIZED_SIZE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const G2_GENERATOR_X: Fq2 = Fq2::new(G2_GENERATOR_X_C0, G2_GENERATOR_X_C1);
|
||||||
|
pub const G2_GENERATOR_Y: Fq2 = Fq2::new(G2_GENERATOR_Y_C0, G2_GENERATOR_Y_C1);
|
||||||
|
|
||||||
|
/// G2_GENERATOR_X_C0 =
|
||||||
|
/// 96453755443802578867745476081903764610578492683850270111202389209355548711427786327510993588141991264564812146530214503491136289085725
|
||||||
|
pub const G2_GENERATOR_X_C0: Fq = MontFp!("96453755443802578867745476081903764610578492683850270111202389209355548711427786327510993588141991264564812146530214503491136289085725");
|
||||||
|
|
||||||
|
/// G2_GENERATOR_X_C1 =
|
||||||
|
/// 85346509177292795277012009839788781950274202400882571466460158277083221521663169974265433098009350061415973662678938824527658049065530
|
||||||
|
pub const G2_GENERATOR_X_C1: Fq = MontFp!("85346509177292795277012009839788781950274202400882571466460158277083221521663169974265433098009350061415973662678938824527658049065530");
|
||||||
|
|
||||||
|
/// G2_GENERATOR_Y_C0 =
|
||||||
|
/// 49316184343270950587272132771103279293158283984999436491292404103501221698714795975575879957605051223501287444864258801515822358837529
|
||||||
|
pub const G2_GENERATOR_Y_C0: Fq = MontFp!("49316184343270950587272132771103279293158283984999436491292404103501221698714795975575879957605051223501287444864258801515822358837529");
|
||||||
|
|
||||||
|
/// G2_GENERATOR_Y_C1 =
|
||||||
|
/// 107680854723992552431070996218129928499826544031468382031848626814251381379173928074140221537929995580031433096217223703806029068859074
|
||||||
|
pub const G2_GENERATOR_Y_C1: Fq = MontFp!("107680854723992552431070996218129928499826544031468382031848626814251381379173928074140221537929995580031433096217223703806029068859074");
|
||||||
|
}
|
||||||
341
tfhe-zk-pok/src/curve_api.rs
Normal file
341
tfhe-zk-pok/src/curve_api.rs
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
use ark_ec::{CurveGroup, Group, VariableBaseMSM};
|
||||||
|
use ark_ff::{BigInt, Field, MontFp, Zero};
|
||||||
|
use ark_poly::univariate::DensePolynomial;
|
||||||
|
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate};
|
||||||
|
use core::fmt;
|
||||||
|
use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
fn ark_se<S, A: CanonicalSerialize>(a: &A, s: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
let mut bytes = vec![];
|
||||||
|
a.serialize_with_mode(&mut bytes, Compress::Yes)
|
||||||
|
.map_err(serde::ser::Error::custom)?;
|
||||||
|
s.serialize_bytes(&bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ark_de<'de, D, A: CanonicalDeserialize>(data: D) -> Result<A, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::de::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let s: Vec<u8> = serde::de::Deserialize::deserialize(data)?;
|
||||||
|
let a = A::deserialize_with_mode(s.as_slice(), Compress::Yes, Validate::Yes);
|
||||||
|
a.map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MontIntDisplay<'a, T>(&'a T);
|
||||||
|
|
||||||
|
impl<T: fmt::Display + PartialEq + Field> fmt::Debug for MontIntDisplay<'_, T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if *self.0 == T::ZERO {
|
||||||
|
f.write_str("0")
|
||||||
|
} else {
|
||||||
|
f.write_fmt(format_args!("{}", self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod bls12_381;
|
||||||
|
pub mod bls12_446;
|
||||||
|
|
||||||
|
pub trait FieldOps:
|
||||||
|
Copy
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ core::ops::AddAssign<Self>
|
||||||
|
+ core::ops::SubAssign<Self>
|
||||||
|
+ core::ops::Add<Self, Output = Self>
|
||||||
|
+ core::ops::Sub<Self, Output = Self>
|
||||||
|
+ core::ops::Mul<Self, Output = Self>
|
||||||
|
+ core::ops::Div<Self, Output = Self>
|
||||||
|
+ core::ops::Neg<Output = Self>
|
||||||
|
+ core::iter::Sum
|
||||||
|
{
|
||||||
|
const ZERO: Self;
|
||||||
|
const ONE: Self;
|
||||||
|
|
||||||
|
fn from_u128(n: u128) -> Self;
|
||||||
|
fn from_u64(n: u64) -> Self;
|
||||||
|
fn from_i64(n: i64) -> Self;
|
||||||
|
fn to_bytes(self) -> impl AsRef<[u8]>;
|
||||||
|
fn rand(rng: &mut dyn rand::RngCore) -> Self;
|
||||||
|
fn hash(values: &mut [Self], data: &[&[u8]]);
|
||||||
|
fn poly_mul(p: &[Self], q: &[Self]) -> Vec<Self>;
|
||||||
|
fn poly_sub(p: &[Self], q: &[Self]) -> Vec<Self> {
|
||||||
|
use core::iter::zip;
|
||||||
|
let mut out = vec![Self::ZERO; Ord::max(p.len(), q.len())];
|
||||||
|
|
||||||
|
for (out, (p, q)) in zip(
|
||||||
|
&mut out,
|
||||||
|
zip(
|
||||||
|
p.iter().copied().chain(core::iter::repeat(Self::ZERO)),
|
||||||
|
q.iter().copied().chain(core::iter::repeat(Self::ZERO)),
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
*out = p - q;
|
||||||
|
}
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
fn poly_add(p: &[Self], q: &[Self]) -> Vec<Self> {
|
||||||
|
use core::iter::zip;
|
||||||
|
let mut out = vec![Self::ZERO; Ord::max(p.len(), q.len())];
|
||||||
|
|
||||||
|
for (out, (p, q)) in zip(
|
||||||
|
&mut out,
|
||||||
|
zip(
|
||||||
|
p.iter().copied().chain(core::iter::repeat(Self::ZERO)),
|
||||||
|
q.iter().copied().chain(core::iter::repeat(Self::ZERO)),
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
*out = p + q;
|
||||||
|
}
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CurveGroupOps<Zp>:
|
||||||
|
Copy
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ core::fmt::Debug
|
||||||
|
+ core::ops::AddAssign<Self>
|
||||||
|
+ core::ops::SubAssign<Self>
|
||||||
|
+ core::ops::Add<Self, Output = Self>
|
||||||
|
+ core::ops::Sub<Self, Output = Self>
|
||||||
|
+ core::ops::Neg<Output = Self>
|
||||||
|
+ core::iter::Sum
|
||||||
|
{
|
||||||
|
const ZERO: Self;
|
||||||
|
const GENERATOR: Self;
|
||||||
|
const BYTE_SIZE: usize;
|
||||||
|
|
||||||
|
fn mul_scalar(self, scalar: Zp) -> Self;
|
||||||
|
fn multi_mul_scalar(bases: &[Self], scalars: &[Zp]) -> Self;
|
||||||
|
fn to_bytes(self) -> impl AsRef<[u8]>;
|
||||||
|
fn double(self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait PairingGroupOps<Zp, G1, G2>:
|
||||||
|
Copy
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ PartialEq
|
||||||
|
+ core::fmt::Debug
|
||||||
|
+ core::ops::AddAssign<Self>
|
||||||
|
+ core::ops::SubAssign<Self>
|
||||||
|
+ core::ops::Add<Self, Output = Self>
|
||||||
|
+ core::ops::Sub<Self, Output = Self>
|
||||||
|
+ core::ops::Neg<Output = Self>
|
||||||
|
{
|
||||||
|
fn mul_scalar(self, scalar: Zp) -> Self;
|
||||||
|
fn pairing(x: G1, y: G2) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Curve {
|
||||||
|
type Zp: FieldOps;
|
||||||
|
type G1: CurveGroupOps<Self::Zp> + serde::Serialize + for<'de> serde::Deserialize<'de>;
|
||||||
|
type G2: CurveGroupOps<Self::Zp> + serde::Serialize + for<'de> serde::Deserialize<'de>;
|
||||||
|
type Gt: PairingGroupOps<Self::Zp, Self::G1, Self::G2>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FieldOps for bls12_381::Zp {
|
||||||
|
const ZERO: Self = Self::ZERO;
|
||||||
|
const ONE: Self = Self::ONE;
|
||||||
|
|
||||||
|
fn from_u128(n: u128) -> Self {
|
||||||
|
Self::from_bigint([n as u64, (n >> 64) as u64, 0, 0])
|
||||||
|
}
|
||||||
|
fn from_u64(n: u64) -> Self {
|
||||||
|
Self::from_u64(n)
|
||||||
|
}
|
||||||
|
fn from_i64(n: i64) -> Self {
|
||||||
|
Self::from_i64(n)
|
||||||
|
}
|
||||||
|
fn to_bytes(self) -> impl AsRef<[u8]> {
|
||||||
|
self.to_bytes()
|
||||||
|
}
|
||||||
|
fn rand(rng: &mut dyn rand::RngCore) -> Self {
|
||||||
|
Self::rand(rng)
|
||||||
|
}
|
||||||
|
fn hash(values: &mut [Self], data: &[&[u8]]) {
|
||||||
|
Self::hash(values, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poly_mul(p: &[Self], q: &[Self]) -> Vec<Self> {
|
||||||
|
let p = p.iter().map(|x| x.inner).collect();
|
||||||
|
let q = q.iter().map(|x| x.inner).collect();
|
||||||
|
let p = DensePolynomial { coeffs: p };
|
||||||
|
let q = DensePolynomial { coeffs: q };
|
||||||
|
(&p * &q)
|
||||||
|
.coeffs
|
||||||
|
.into_iter()
|
||||||
|
.map(|inner| bls12_381::Zp { inner })
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CurveGroupOps<bls12_381::Zp> for bls12_381::G1 {
|
||||||
|
const ZERO: Self = Self::ZERO;
|
||||||
|
const GENERATOR: Self = Self::GENERATOR;
|
||||||
|
const BYTE_SIZE: usize = Self::BYTE_SIZE;
|
||||||
|
|
||||||
|
fn mul_scalar(self, scalar: bls12_381::Zp) -> Self {
|
||||||
|
self.mul_scalar(scalar)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn multi_mul_scalar(bases: &[Self], scalars: &[bls12_381::Zp]) -> Self {
|
||||||
|
Self::multi_mul_scalar(bases, scalars)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bytes(self) -> impl AsRef<[u8]> {
|
||||||
|
self.to_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn double(self) -> Self {
|
||||||
|
self.double()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CurveGroupOps<bls12_381::Zp> for bls12_381::G2 {
|
||||||
|
const ZERO: Self = Self::ZERO;
|
||||||
|
const GENERATOR: Self = Self::GENERATOR;
|
||||||
|
const BYTE_SIZE: usize = Self::BYTE_SIZE;
|
||||||
|
|
||||||
|
fn mul_scalar(self, scalar: bls12_381::Zp) -> Self {
|
||||||
|
self.mul_scalar(scalar)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn multi_mul_scalar(bases: &[Self], scalars: &[bls12_381::Zp]) -> Self {
|
||||||
|
Self::multi_mul_scalar(bases, scalars)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bytes(self) -> impl AsRef<[u8]> {
|
||||||
|
self.to_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn double(self) -> Self {
|
||||||
|
self.double()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PairingGroupOps<bls12_381::Zp, bls12_381::G1, bls12_381::G2> for bls12_381::Gt {
|
||||||
|
fn mul_scalar(self, scalar: bls12_381::Zp) -> Self {
|
||||||
|
self.mul_scalar(scalar)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pairing(x: bls12_381::G1, y: bls12_381::G2) -> Self {
|
||||||
|
Self::pairing(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FieldOps for bls12_446::Zp {
|
||||||
|
const ZERO: Self = Self::ZERO;
|
||||||
|
const ONE: Self = Self::ONE;
|
||||||
|
|
||||||
|
fn from_u128(n: u128) -> Self {
|
||||||
|
Self::from_bigint([n as u64, (n >> 64) as u64, 0, 0, 0])
|
||||||
|
}
|
||||||
|
fn from_u64(n: u64) -> Self {
|
||||||
|
Self::from_u64(n)
|
||||||
|
}
|
||||||
|
fn from_i64(n: i64) -> Self {
|
||||||
|
Self::from_i64(n)
|
||||||
|
}
|
||||||
|
fn to_bytes(self) -> impl AsRef<[u8]> {
|
||||||
|
self.to_bytes()
|
||||||
|
}
|
||||||
|
fn rand(rng: &mut dyn rand::RngCore) -> Self {
|
||||||
|
Self::rand(rng)
|
||||||
|
}
|
||||||
|
fn hash(values: &mut [Self], data: &[&[u8]]) {
|
||||||
|
Self::hash(values, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poly_mul(p: &[Self], q: &[Self]) -> Vec<Self> {
|
||||||
|
let p = p.iter().map(|x| x.inner).collect();
|
||||||
|
let q = q.iter().map(|x| x.inner).collect();
|
||||||
|
let p = DensePolynomial { coeffs: p };
|
||||||
|
let q = DensePolynomial { coeffs: q };
|
||||||
|
(&p * &q)
|
||||||
|
.coeffs
|
||||||
|
.into_iter()
|
||||||
|
.map(|inner| bls12_446::Zp { inner })
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CurveGroupOps<bls12_446::Zp> for bls12_446::G1 {
|
||||||
|
const ZERO: Self = Self::ZERO;
|
||||||
|
const GENERATOR: Self = Self::GENERATOR;
|
||||||
|
const BYTE_SIZE: usize = Self::BYTE_SIZE;
|
||||||
|
|
||||||
|
fn mul_scalar(self, scalar: bls12_446::Zp) -> Self {
|
||||||
|
self.mul_scalar(scalar)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn multi_mul_scalar(bases: &[Self], scalars: &[bls12_446::Zp]) -> Self {
|
||||||
|
Self::multi_mul_scalar(bases, scalars)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bytes(self) -> impl AsRef<[u8]> {
|
||||||
|
self.to_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn double(self) -> Self {
|
||||||
|
self.double()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CurveGroupOps<bls12_446::Zp> for bls12_446::G2 {
|
||||||
|
const ZERO: Self = Self::ZERO;
|
||||||
|
const GENERATOR: Self = Self::GENERATOR;
|
||||||
|
const BYTE_SIZE: usize = Self::BYTE_SIZE;
|
||||||
|
|
||||||
|
fn mul_scalar(self, scalar: bls12_446::Zp) -> Self {
|
||||||
|
self.mul_scalar(scalar)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn multi_mul_scalar(bases: &[Self], scalars: &[bls12_446::Zp]) -> Self {
|
||||||
|
Self::multi_mul_scalar(bases, scalars)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bytes(self) -> impl AsRef<[u8]> {
|
||||||
|
self.to_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn double(self) -> Self {
|
||||||
|
self.double()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PairingGroupOps<bls12_446::Zp, bls12_446::G1, bls12_446::G2> for bls12_446::Gt {
|
||||||
|
fn mul_scalar(self, scalar: bls12_446::Zp) -> Self {
|
||||||
|
self.mul_scalar(scalar)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pairing(x: bls12_446::G1, y: bls12_446::G2) -> Self {
|
||||||
|
Self::pairing(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct Bls12_381;
|
||||||
|
#[derive(Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct Bls12_446;
|
||||||
|
|
||||||
|
impl Curve for Bls12_381 {
|
||||||
|
type Zp = bls12_381::Zp;
|
||||||
|
type G1 = bls12_381::G1;
|
||||||
|
type G2 = bls12_381::G2;
|
||||||
|
type Gt = bls12_381::Gt;
|
||||||
|
}
|
||||||
|
impl Curve for Bls12_446 {
|
||||||
|
type Zp = bls12_446::Zp;
|
||||||
|
type G1 = bls12_446::G1;
|
||||||
|
type G2 = bls12_446::G2;
|
||||||
|
type Gt = bls12_446::Gt;
|
||||||
|
}
|
||||||
776
tfhe-zk-pok/src/curve_api/bls12_381.rs
Normal file
776
tfhe-zk-pok/src/curve_api/bls12_381.rs
Normal file
@@ -0,0 +1,776 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// multiply EC point with scalar (= exponentiation in multiplicative notation)
|
||||||
|
fn mul_zp<T: Copy + Zero + Add<Output = T> + Group>(x: T, scalar: Zp) -> T {
|
||||||
|
let zero = T::zero();
|
||||||
|
let n: BigInt<4> = scalar.inner.into();
|
||||||
|
|
||||||
|
if n == BigInt([0; 4]) {
|
||||||
|
return zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut y = zero;
|
||||||
|
let mut x = x;
|
||||||
|
|
||||||
|
let n = n.0;
|
||||||
|
for word in n {
|
||||||
|
for idx in 0..64 {
|
||||||
|
let bit = (word >> idx) & 1;
|
||||||
|
if bit == 1 {
|
||||||
|
y += x;
|
||||||
|
}
|
||||||
|
x.double_in_place();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
y
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bigint_to_bytes(x: [u64; 6]) -> [u8; 6 * 8] {
|
||||||
|
let mut buf = [0u8; 6 * 8];
|
||||||
|
for (i, &xi) in x.iter().enumerate() {
|
||||||
|
buf[i * 8..][..8].copy_from_slice(&xi.to_le_bytes());
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
mod g1 {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct G1 {
|
||||||
|
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
|
||||||
|
pub(crate) inner: ark_bls12_381::G1Projective,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for G1 {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("G1")
|
||||||
|
.field("x", &MontIntDisplay(&self.inner.x))
|
||||||
|
.field("y", &MontIntDisplay(&self.inner.y))
|
||||||
|
.field("z", &MontIntDisplay(&self.inner.z))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl G1 {
|
||||||
|
pub const ZERO: Self = Self {
|
||||||
|
inner: ark_bls12_381::G1Projective {
|
||||||
|
x: MontFp!("1"),
|
||||||
|
y: MontFp!("1"),
|
||||||
|
z: MontFp!("0"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://github.com/zcash/librustzcash/blob/6e0364cd42a2b3d2b958a54771ef51a8db79dd29/pairing/src/bls12_381/README.md#g1
|
||||||
|
pub const GENERATOR: Self = Self {
|
||||||
|
inner: ark_bls12_381::G1Projective {
|
||||||
|
x: MontFp!("3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507"),
|
||||||
|
y: MontFp!("1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569"),
|
||||||
|
z: MontFp!("1"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Size in number of bytes when the [to_bytes]
|
||||||
|
// function is called.
|
||||||
|
// This is not the size after serialization!
|
||||||
|
pub const BYTE_SIZE: usize = 2 * 6 * 8 + 1;
|
||||||
|
|
||||||
|
pub fn mul_scalar(self, scalar: Zp) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: mul_zp(self.inner, scalar),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn multi_mul_scalar(bases: &[Self], scalars: &[Zp]) -> Self {
|
||||||
|
use rayon::prelude::*;
|
||||||
|
let n_threads = rayon::current_num_threads();
|
||||||
|
let chunk_size = bases.len().div_ceil(n_threads);
|
||||||
|
bases
|
||||||
|
.par_iter()
|
||||||
|
.map(|&x| x.inner.into_affine())
|
||||||
|
.chunks(chunk_size)
|
||||||
|
.zip(scalars.par_iter().map(|&x| x.inner).chunks(chunk_size))
|
||||||
|
.map(|(bases, scalars)| Self {
|
||||||
|
inner: ark_bls12_381::G1Projective::msm(&bases, &scalars).unwrap(),
|
||||||
|
})
|
||||||
|
.sum::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(self) -> [u8; Self::BYTE_SIZE] {
|
||||||
|
let g = self.inner.into_affine();
|
||||||
|
let x = bigint_to_bytes(g.x.0 .0);
|
||||||
|
let y = bigint_to_bytes(g.y.0 .0);
|
||||||
|
let mut buf = [0u8; 2 * 6 * 8 + 1];
|
||||||
|
buf[..6 * 8].copy_from_slice(&x);
|
||||||
|
buf[6 * 8..][..6 * 8].copy_from_slice(&y);
|
||||||
|
buf[2 * 6 * 8] = g.infinity as u8;
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn double(self) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: self.inner.double(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for G1 {
|
||||||
|
type Output = G1;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
G1 {
|
||||||
|
inner: self.inner + rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for G1 {
|
||||||
|
type Output = G1;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
G1 {
|
||||||
|
inner: self.inner - rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for G1 {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner += rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for G1 {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner -= rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::iter::Sum for G1 {
|
||||||
|
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
||||||
|
iter.fold(G1::ZERO, Add::add)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for G1 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
Self { inner: -self.inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod g2 {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct G2 {
|
||||||
|
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
|
||||||
|
pub(super) inner: ark_bls12_381::G2Projective,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for G2 {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct QuadExtField<T> {
|
||||||
|
c0: T,
|
||||||
|
c1: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
f.debug_struct("G2")
|
||||||
|
.field(
|
||||||
|
"x",
|
||||||
|
&QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.x.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.x.c1),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.field(
|
||||||
|
"y",
|
||||||
|
&QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.y.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.y.c1),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.field(
|
||||||
|
"z",
|
||||||
|
&QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.z.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.z.c1),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl G2 {
|
||||||
|
pub const ZERO: Self = Self {
|
||||||
|
inner: ark_bls12_381::G2Projective {
|
||||||
|
x: ark_ff::QuadExtField {
|
||||||
|
c0: MontFp!("1"),
|
||||||
|
c1: MontFp!("0"),
|
||||||
|
},
|
||||||
|
y: ark_ff::QuadExtField {
|
||||||
|
c0: MontFp!("1"),
|
||||||
|
c1: MontFp!("0"),
|
||||||
|
},
|
||||||
|
z: ark_ff::QuadExtField {
|
||||||
|
c0: MontFp!("0"),
|
||||||
|
c1: MontFp!("0"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://github.com/zcash/librustzcash/blob/6e0364cd42a2b3d2b958a54771ef51a8db79dd29/pairing/src/bls12_381/README.md#g2
|
||||||
|
pub const GENERATOR: Self = Self {
|
||||||
|
inner: ark_bls12_381::G2Projective {
|
||||||
|
x: ark_ff::QuadExtField {
|
||||||
|
c0: MontFp!("352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160"),
|
||||||
|
c1: MontFp!("3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758"),
|
||||||
|
},
|
||||||
|
y: ark_ff::QuadExtField {
|
||||||
|
c0: MontFp!("1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905"),
|
||||||
|
c1: MontFp!("927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582"),
|
||||||
|
},
|
||||||
|
z: ark_ff::QuadExtField {
|
||||||
|
c0: MontFp!("1"),
|
||||||
|
c1: MontFp!("0") ,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Size in number of bytes when the [to_bytes]
|
||||||
|
// function is called.
|
||||||
|
// This is not the size after serialization!
|
||||||
|
pub const BYTE_SIZE: usize = 4 * 6 * 8 + 1;
|
||||||
|
|
||||||
|
pub fn mul_scalar(self, scalar: Zp) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: mul_zp(self.inner, scalar),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn multi_mul_scalar(bases: &[Self], scalars: &[Zp]) -> Self {
|
||||||
|
use rayon::prelude::*;
|
||||||
|
let n_threads = rayon::current_num_threads();
|
||||||
|
let chunk_size = bases.len().div_ceil(n_threads);
|
||||||
|
bases
|
||||||
|
.par_iter()
|
||||||
|
.map(|&x| x.inner.into_affine())
|
||||||
|
.chunks(chunk_size)
|
||||||
|
.zip(scalars.par_iter().map(|&x| x.inner).chunks(chunk_size))
|
||||||
|
.map(|(bases, scalars)| Self {
|
||||||
|
inner: ark_bls12_381::G2Projective::msm(&bases, &scalars).unwrap(),
|
||||||
|
})
|
||||||
|
.sum::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(self) -> [u8; Self::BYTE_SIZE] {
|
||||||
|
let g = self.inner.into_affine();
|
||||||
|
let xc0 = bigint_to_bytes(g.x.c0.0 .0);
|
||||||
|
let xc1 = bigint_to_bytes(g.x.c1.0 .0);
|
||||||
|
let yc0 = bigint_to_bytes(g.y.c0.0 .0);
|
||||||
|
let yc1 = bigint_to_bytes(g.y.c1.0 .0);
|
||||||
|
let mut buf = [0u8; 4 * 6 * 8 + 1];
|
||||||
|
buf[..6 * 8].copy_from_slice(&xc0);
|
||||||
|
buf[6 * 8..][..6 * 8].copy_from_slice(&xc1);
|
||||||
|
buf[2 * 6 * 8..][..6 * 8].copy_from_slice(&yc0);
|
||||||
|
buf[3 * 6 * 8..][..6 * 8].copy_from_slice(&yc1);
|
||||||
|
buf[4 * 6 * 8] = g.infinity as u8;
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn double(self) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: self.inner.double(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for G2 {
|
||||||
|
type Output = G2;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
G2 {
|
||||||
|
inner: self.inner + rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for G2 {
|
||||||
|
type Output = G2;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
G2 {
|
||||||
|
inner: self.inner - rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for G2 {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner += rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for G2 {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner -= rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::iter::Sum for G2 {
|
||||||
|
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
||||||
|
iter.fold(G2::ZERO, Add::add)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for G2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
Self { inner: -self.inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod gt {
|
||||||
|
use super::*;
|
||||||
|
use ark_ec::pairing::Pairing;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Gt {
|
||||||
|
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
|
||||||
|
inner: ark_ec::pairing::PairingOutput<ark_bls12_381::Bls12_381>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Gt {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct QuadExtField<T> {
|
||||||
|
c0: T,
|
||||||
|
c1: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct CubicExtField<T> {
|
||||||
|
c0: T,
|
||||||
|
c1: T,
|
||||||
|
c2: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Gt<T> {
|
||||||
|
inner: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
f.debug_struct("Gt")
|
||||||
|
.field(
|
||||||
|
"inner",
|
||||||
|
&Gt {
|
||||||
|
inner: QuadExtField {
|
||||||
|
c0: CubicExtField {
|
||||||
|
c0: QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.0.c0.c0.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.0.c0.c0.c1),
|
||||||
|
},
|
||||||
|
c1: QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.0.c0.c1.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.0.c0.c1.c1),
|
||||||
|
},
|
||||||
|
c2: QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.0.c0.c2.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.0.c0.c2.c1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
c1: CubicExtField {
|
||||||
|
c0: QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.0.c1.c0.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.0.c1.c0.c1),
|
||||||
|
},
|
||||||
|
c1: QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.0.c1.c1.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.0.c1.c1.c1),
|
||||||
|
},
|
||||||
|
c2: QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.0.c1.c2.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.0.c1.c2.c1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Gt {
|
||||||
|
pub fn pairing(g1: G1, g2: G2) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: ark_bls12_381::Bls12_381::pairing(g1.inner, g2.inner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mul_scalar(self, scalar: Zp) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: mul_zp(self.inner, scalar),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Gt {
|
||||||
|
type Output = Gt;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Gt {
|
||||||
|
inner: self.inner + rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Gt {
|
||||||
|
type Output = Gt;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Gt {
|
||||||
|
inner: self.inner - rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for Gt {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner += rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for Gt {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner -= rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for Gt {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
Self { inner: -self.inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod zp {
|
||||||
|
use super::*;
|
||||||
|
use ark_ff::Fp;
|
||||||
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
|
fn redc(n: [u64; 4], nprime: u64, mut t: [u64; 6]) -> [u64; 4] {
|
||||||
|
for i in 0..2 {
|
||||||
|
let mut c = 0u64;
|
||||||
|
let m = u64::wrapping_mul(t[i], nprime);
|
||||||
|
|
||||||
|
for j in 0..4 {
|
||||||
|
let x = t[i + j] as u128 + m as u128 * n[j] as u128 + c as u128;
|
||||||
|
t[i + j] = x as u64;
|
||||||
|
c = (x >> 64) as u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
for j in 4..6 - i {
|
||||||
|
let x = t[i + j] as u128 + c as u128;
|
||||||
|
t[i + j] = x as u64;
|
||||||
|
c = (x >> 64) as u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut t = [t[2], t[3], t[4], t[5]];
|
||||||
|
|
||||||
|
if t.into_iter().rev().ge(n.into_iter().rev()) {
|
||||||
|
let mut o = false;
|
||||||
|
for i in 0..4 {
|
||||||
|
let (ti, o0) = u64::overflowing_sub(t[i], n[i]);
|
||||||
|
let (ti, o1) = u64::overflowing_sub(ti, o as u64);
|
||||||
|
o = o0 | o1;
|
||||||
|
t[i] = ti;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(t.into_iter().rev().lt(n.into_iter().rev()));
|
||||||
|
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Zeroize)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Zp {
|
||||||
|
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
|
||||||
|
pub(crate) inner: ark_bls12_381::Fr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Zp {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("Zp")
|
||||||
|
.field(&MontIntDisplay(&self.inner))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Zp {
|
||||||
|
pub const ZERO: Self = Self {
|
||||||
|
inner: MontFp!("0"),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ONE: Self = Self {
|
||||||
|
inner: MontFp!("1"),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn from_bigint(n: [u64; 4]) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: BigInt(n).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_u64(n: u64) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: BigInt([n, 0, 0, 0]).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_i64(n: i64) -> Self {
|
||||||
|
let n_abs = Self::from_u64(n.unsigned_abs());
|
||||||
|
if n > 0 {
|
||||||
|
n_abs
|
||||||
|
} else {
|
||||||
|
-n_abs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(self) -> [u8; 4 * 8] {
|
||||||
|
let buf = [
|
||||||
|
self.inner.0 .0[0].to_le_bytes(),
|
||||||
|
self.inner.0 .0[1].to_le_bytes(),
|
||||||
|
self.inner.0 .0[2].to_le_bytes(),
|
||||||
|
self.inner.0 .0[3].to_le_bytes(),
|
||||||
|
];
|
||||||
|
unsafe { core::mem::transmute(buf) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_raw_u64x6(n: [u64; 6]) -> Self {
|
||||||
|
const MODULUS: BigInt<4> = BigInt!(
|
||||||
|
"52435875175126190479447740508185965837690552500527637822603658699938581184513"
|
||||||
|
);
|
||||||
|
|
||||||
|
const MODULUS_MONTGOMERY: u64 = 18446744069414584319;
|
||||||
|
|
||||||
|
let mut n = n;
|
||||||
|
// zero the two leading bits, so the result is <= MODULUS * 2^128
|
||||||
|
n[5] &= (1 << 62) - 1;
|
||||||
|
Zp {
|
||||||
|
inner: Fp(
|
||||||
|
BigInt(redc(MODULUS.0, MODULUS_MONTGOMERY, n)),
|
||||||
|
core::marker::PhantomData,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rand(rng: &mut dyn rand::RngCore) -> Self {
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
Self::from_raw_u64x6([
|
||||||
|
rng.gen::<u64>(),
|
||||||
|
rng.gen::<u64>(),
|
||||||
|
rng.gen::<u64>(),
|
||||||
|
rng.gen::<u64>(),
|
||||||
|
rng.gen::<u64>(),
|
||||||
|
rng.gen::<u64>(),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash(values: &mut [Zp], data: &[&[u8]]) {
|
||||||
|
use sha3::digest::{ExtendableOutput, Update, XofReader};
|
||||||
|
|
||||||
|
let mut hasher = sha3::Shake256::default();
|
||||||
|
for data in data {
|
||||||
|
hasher.update(data);
|
||||||
|
}
|
||||||
|
let mut reader = hasher.finalize_xof();
|
||||||
|
|
||||||
|
for value in values {
|
||||||
|
let mut bytes = [0u8; 6 * 8];
|
||||||
|
reader.read(&mut bytes);
|
||||||
|
let bytes: [[u8; 8]; 6] = unsafe { core::mem::transmute(bytes) };
|
||||||
|
*value = Zp::from_raw_u64x6(bytes.map(u64::from_le_bytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Zp {
|
||||||
|
type Output = Zp;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Zp {
|
||||||
|
inner: self.inner + rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Zp {
|
||||||
|
type Output = Zp;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Zp {
|
||||||
|
inner: self.inner - rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul for Zp {
|
||||||
|
type Output = Zp;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
Zp {
|
||||||
|
inner: self.inner * rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div for Zp {
|
||||||
|
type Output = Zp;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn div(self, rhs: Self) -> Self::Output {
|
||||||
|
Zp {
|
||||||
|
inner: self.inner / rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AddAssign for Zp {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner += rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for Zp {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner -= rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for Zp {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
Self { inner: -self.inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::iter::Sum for Zp {
|
||||||
|
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
||||||
|
iter.fold(Zp::ZERO, Add::add)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use g1::G1;
|
||||||
|
pub use g2::G2;
|
||||||
|
pub use gt::Gt;
|
||||||
|
pub use zp::Zp;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use rand::rngs::StdRng;
|
||||||
|
use rand::SeedableRng;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_distributivity() {
|
||||||
|
let a = Zp {
|
||||||
|
inner: MontFp!(
|
||||||
|
"20799633726231143268782044631117354647259165363910905818134484248029981143850"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let b = Zp {
|
||||||
|
inner: MontFp!(
|
||||||
|
"42333504039292951860879669847432876299949385605895551964353185488509497658948"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let c = Zp {
|
||||||
|
inner: MontFp!(
|
||||||
|
"6797004509292554067788526429737434481164547177696793280652530849910670196287"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!((((a - b) * c) - (a * c - b * c)).inner, Zp::ZERO.inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialization() {
|
||||||
|
let rng = &mut StdRng::seed_from_u64(0);
|
||||||
|
let alpha = Zp::rand(rng);
|
||||||
|
let g_cur = G1::GENERATOR.mul_scalar(alpha);
|
||||||
|
let g_hat_cur = G2::GENERATOR.mul_scalar(alpha);
|
||||||
|
|
||||||
|
let alpha2: Zp = serde_json::from_str(&serde_json::to_string(&alpha).unwrap()).unwrap();
|
||||||
|
assert_eq!(alpha, alpha2);
|
||||||
|
|
||||||
|
let g_cur2: G1 = serde_json::from_str(&serde_json::to_string(&g_cur).unwrap()).unwrap();
|
||||||
|
assert_eq!(g_cur, g_cur2);
|
||||||
|
|
||||||
|
let g_hat_cur2: G2 =
|
||||||
|
serde_json::from_str(&serde_json::to_string(&g_hat_cur).unwrap()).unwrap();
|
||||||
|
assert_eq!(g_hat_cur, g_hat_cur2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hasher_and_eq() {
|
||||||
|
// we need to make sure if the points are the same
|
||||||
|
// but the projective representations are different
|
||||||
|
// then they still hash into the same thing
|
||||||
|
let rng = &mut StdRng::seed_from_u64(0);
|
||||||
|
let alpha = Zp::rand(rng);
|
||||||
|
let a = G1::GENERATOR.mul_scalar(alpha);
|
||||||
|
|
||||||
|
// serialization should convert the point to affine representation
|
||||||
|
// after deserializing it we should have the same point
|
||||||
|
// but with a different representation
|
||||||
|
let a_affine: G1 = serde_json::from_str(&serde_json::to_string(&a).unwrap()).unwrap();
|
||||||
|
|
||||||
|
// the internal elements should be different
|
||||||
|
assert_ne!(a.inner.x, a_affine.inner.x);
|
||||||
|
assert_ne!(a.inner.y, a_affine.inner.y);
|
||||||
|
assert_ne!(a.inner.z, a_affine.inner.z);
|
||||||
|
|
||||||
|
// but equality and hasher should see the two as the same point
|
||||||
|
assert_eq!(a, a_affine);
|
||||||
|
let mut hm = HashMap::new();
|
||||||
|
hm.insert(a, 1);
|
||||||
|
assert_eq!(hm.len(), 1);
|
||||||
|
hm.insert(a_affine, 2);
|
||||||
|
assert_eq!(hm.len(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
970
tfhe-zk-pok/src/curve_api/bls12_446.rs
Normal file
970
tfhe-zk-pok/src/curve_api/bls12_446.rs
Normal file
@@ -0,0 +1,970 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// multiply EC point with scalar (= exponentiation in multiplicative notation)
|
||||||
|
fn mul_zp<T: Copy + Zero + Add<Output = T> + Group>(x: T, scalar: Zp) -> T {
|
||||||
|
let zero = T::zero();
|
||||||
|
let n: BigInt<5> = scalar.inner.into();
|
||||||
|
|
||||||
|
if n == BigInt([0; 5]) {
|
||||||
|
return zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut y = zero;
|
||||||
|
let mut x = x;
|
||||||
|
|
||||||
|
let n = n.0;
|
||||||
|
for word in n {
|
||||||
|
for idx in 0..64 {
|
||||||
|
let bit = (word >> idx) & 1;
|
||||||
|
if bit == 1 {
|
||||||
|
y += x;
|
||||||
|
}
|
||||||
|
x.double_in_place();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
y
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bigint_to_bytes(x: [u64; 7]) -> [u8; 7 * 8] {
|
||||||
|
let mut buf = [0u8; 7 * 8];
|
||||||
|
for (i, &xi) in x.iter().enumerate() {
|
||||||
|
buf[i * 8..][..8].copy_from_slice(&xi.to_le_bytes());
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
mod g1 {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct G1 {
|
||||||
|
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
|
||||||
|
pub(crate) inner: crate::curve_446::g1::G1Projective,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for G1 {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("G1")
|
||||||
|
.field("x", &MontIntDisplay(&self.inner.x))
|
||||||
|
.field("y", &MontIntDisplay(&self.inner.y))
|
||||||
|
.field("z", &MontIntDisplay(&self.inner.z))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl G1 {
|
||||||
|
pub const ZERO: Self = Self {
|
||||||
|
inner: crate::curve_446::g1::G1Projective {
|
||||||
|
x: MontFp!("1"),
|
||||||
|
y: MontFp!("1"),
|
||||||
|
z: MontFp!("0"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const GENERATOR: Self = Self {
|
||||||
|
inner: crate::curve_446::g1::G1Projective {
|
||||||
|
x: MontFp!("143189966182216199425404656824735381247272236095050141599848381692039676741476615087722874458136990266833440576646963466074693171606778"),
|
||||||
|
y: MontFp!("75202396197342917254523279069469674666303680671605970245803554133573745859131002231546341942288521574682619325841484506619191207488304"),
|
||||||
|
z: MontFp!("1"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Size in number of bytes when the [to_bytes]
|
||||||
|
// function is called.
|
||||||
|
// This is not the size after serialization!
|
||||||
|
pub const BYTE_SIZE: usize = 2 * 7 * 8 + 1;
|
||||||
|
|
||||||
|
pub fn mul_scalar(self, scalar: Zp) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: mul_zp(self.inner, scalar),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn multi_mul_scalar(bases: &[Self], scalars: &[Zp]) -> Self {
|
||||||
|
use rayon::prelude::*;
|
||||||
|
let n_threads = rayon::current_num_threads();
|
||||||
|
let chunk_size = bases.len().div_ceil(n_threads);
|
||||||
|
bases
|
||||||
|
.par_iter()
|
||||||
|
.map(|&x| x.inner.into_affine())
|
||||||
|
.chunks(chunk_size)
|
||||||
|
.zip(scalars.par_iter().map(|&x| x.inner).chunks(chunk_size))
|
||||||
|
.map(|(bases, scalars)| Self {
|
||||||
|
inner: crate::curve_446::g1::G1Projective::msm(&bases, &scalars).unwrap(),
|
||||||
|
})
|
||||||
|
.sum::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(self) -> [u8; Self::BYTE_SIZE] {
|
||||||
|
let g = self.inner.into_affine();
|
||||||
|
let x = bigint_to_bytes(g.x.0 .0);
|
||||||
|
let y = bigint_to_bytes(g.y.0 .0);
|
||||||
|
let mut buf = [0u8; 2 * 7 * 8 + 1];
|
||||||
|
buf[..7 * 8].copy_from_slice(&x);
|
||||||
|
buf[7 * 8..][..7 * 8].copy_from_slice(&y);
|
||||||
|
buf[2 * 7 * 8] = g.infinity as u8;
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn double(self) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: self.inner.double(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for G1 {
|
||||||
|
type Output = G1;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
G1 {
|
||||||
|
inner: self.inner + rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for G1 {
|
||||||
|
type Output = G1;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
G1 {
|
||||||
|
inner: self.inner - rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for G1 {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner += rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for G1 {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner -= rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::iter::Sum for G1 {
|
||||||
|
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
||||||
|
iter.fold(G1::ZERO, Add::add)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for G1 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
Self { inner: -self.inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod g2 {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct G2 {
|
||||||
|
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
|
||||||
|
pub(super) inner: crate::curve_446::g2::G2Projective,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for G2 {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct QuadExtField<T> {
|
||||||
|
c0: T,
|
||||||
|
c1: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
f.debug_struct("G2")
|
||||||
|
.field(
|
||||||
|
"x",
|
||||||
|
&QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.x.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.x.c1),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.field(
|
||||||
|
"y",
|
||||||
|
&QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.y.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.y.c1),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.field(
|
||||||
|
"z",
|
||||||
|
&QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.z.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.z.c1),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl G2 {
|
||||||
|
pub const ZERO: Self = Self {
|
||||||
|
inner: crate::curve_446::g2::G2Projective {
|
||||||
|
x: ark_ff::QuadExtField {
|
||||||
|
c0: MontFp!("1"),
|
||||||
|
c1: MontFp!("0"),
|
||||||
|
},
|
||||||
|
y: ark_ff::QuadExtField {
|
||||||
|
c0: MontFp!("1"),
|
||||||
|
c1: MontFp!("0"),
|
||||||
|
},
|
||||||
|
z: ark_ff::QuadExtField {
|
||||||
|
c0: MontFp!("0"),
|
||||||
|
c1: MontFp!("0"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const GENERATOR: Self = Self {
|
||||||
|
inner: crate::curve_446::g2::G2Projective {
|
||||||
|
x: ark_ff::QuadExtField {
|
||||||
|
c0: MontFp!("96453755443802578867745476081903764610578492683850270111202389209355548711427786327510993588141991264564812146530214503491136289085725"),
|
||||||
|
c1: MontFp!("85346509177292795277012009839788781950274202400882571466460158277083221521663169974265433098009350061415973662678938824527658049065530"),
|
||||||
|
},
|
||||||
|
y: ark_ff::QuadExtField {
|
||||||
|
c0: MontFp!("49316184343270950587272132771103279293158283984999436491292404103501221698714795975575879957605051223501287444864258801515822358837529"),
|
||||||
|
c1: MontFp!("107680854723992552431070996218129928499826544031468382031848626814251381379173928074140221537929995580031433096217223703806029068859074"),
|
||||||
|
},
|
||||||
|
z: ark_ff::QuadExtField {
|
||||||
|
c0: MontFp!("1"),
|
||||||
|
c1: MontFp!("0") ,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Size in number of bytes when the [to_bytes]
|
||||||
|
// function is called.
|
||||||
|
// This is not the size after serialization!
|
||||||
|
pub const BYTE_SIZE: usize = 4 * 7 * 8 + 1;
|
||||||
|
|
||||||
|
pub fn mul_scalar(self, scalar: Zp) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: mul_zp(self.inner, scalar),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn multi_mul_scalar(bases: &[Self], scalars: &[Zp]) -> Self {
|
||||||
|
use rayon::prelude::*;
|
||||||
|
let n_threads = rayon::current_num_threads();
|
||||||
|
let chunk_size = bases.len().div_ceil(n_threads);
|
||||||
|
bases
|
||||||
|
.par_iter()
|
||||||
|
.map(|&x| x.inner.into_affine())
|
||||||
|
.chunks(chunk_size)
|
||||||
|
.zip(scalars.par_iter().map(|&x| x.inner).chunks(chunk_size))
|
||||||
|
.map(|(bases, scalars)| Self {
|
||||||
|
inner: crate::curve_446::g2::G2Projective::msm(&bases, &scalars).unwrap(),
|
||||||
|
})
|
||||||
|
.sum::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(self) -> [u8; Self::BYTE_SIZE] {
|
||||||
|
let g = self.inner.into_affine();
|
||||||
|
let xc0 = bigint_to_bytes(g.x.c0.0 .0);
|
||||||
|
let xc1 = bigint_to_bytes(g.x.c1.0 .0);
|
||||||
|
let yc0 = bigint_to_bytes(g.y.c0.0 .0);
|
||||||
|
let yc1 = bigint_to_bytes(g.y.c1.0 .0);
|
||||||
|
let mut buf = [0u8; 4 * 7 * 8 + 1];
|
||||||
|
buf[..7 * 8].copy_from_slice(&xc0);
|
||||||
|
buf[7 * 8..][..7 * 8].copy_from_slice(&xc1);
|
||||||
|
buf[2 * 7 * 8..][..7 * 8].copy_from_slice(&yc0);
|
||||||
|
buf[3 * 7 * 8..][..7 * 8].copy_from_slice(&yc1);
|
||||||
|
buf[4 * 7 * 8] = g.infinity as u8;
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn double(self) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: self.inner.double(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for G2 {
|
||||||
|
type Output = G2;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
G2 {
|
||||||
|
inner: self.inner + rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for G2 {
|
||||||
|
type Output = G2;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
G2 {
|
||||||
|
inner: self.inner - rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for G2 {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner += rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for G2 {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner -= rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::iter::Sum for G2 {
|
||||||
|
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
||||||
|
iter.fold(G2::ZERO, Add::add)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for G2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
Self { inner: -self.inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod gt {
|
||||||
|
use super::*;
|
||||||
|
use ark_ec::bls12::Bls12Config;
|
||||||
|
use ark_ec::pairing::{MillerLoopOutput, Pairing};
|
||||||
|
use ark_ff::{CubicExtField, Fp12, Fp2, QuadExtField};
|
||||||
|
|
||||||
|
type Bls = crate::curve_446::Bls12_446;
|
||||||
|
type Config = crate::curve_446::Config;
|
||||||
|
|
||||||
|
const ONE: Fp2<<Config as Bls12Config>::Fp2Config> = QuadExtField {
|
||||||
|
c0: MontFp!("1"),
|
||||||
|
c1: MontFp!("0"),
|
||||||
|
};
|
||||||
|
const ZERO: Fp2<<Config as Bls12Config>::Fp2Config> = QuadExtField {
|
||||||
|
c0: MontFp!("0"),
|
||||||
|
c1: MontFp!("0"),
|
||||||
|
};
|
||||||
|
|
||||||
|
const U1: Fp12<<Config as Bls12Config>::Fp12Config> = QuadExtField {
|
||||||
|
c0: CubicExtField {
|
||||||
|
c0: ZERO,
|
||||||
|
c1: ZERO,
|
||||||
|
c2: ZERO,
|
||||||
|
},
|
||||||
|
c1: CubicExtField {
|
||||||
|
c0: ONE,
|
||||||
|
c1: ZERO,
|
||||||
|
c2: ZERO,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const U3: Fp12<<Config as Bls12Config>::Fp12Config> = QuadExtField {
|
||||||
|
c0: CubicExtField {
|
||||||
|
c0: ZERO,
|
||||||
|
c1: ZERO,
|
||||||
|
c2: ZERO,
|
||||||
|
},
|
||||||
|
c1: CubicExtField {
|
||||||
|
c0: ZERO,
|
||||||
|
c1: ONE,
|
||||||
|
c2: ZERO,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const fn fp2_to_fp12(
|
||||||
|
x: Fp2<<Config as Bls12Config>::Fp2Config>,
|
||||||
|
) -> Fp12<<Config as Bls12Config>::Fp12Config> {
|
||||||
|
QuadExtField {
|
||||||
|
c0: CubicExtField {
|
||||||
|
c0: x,
|
||||||
|
c1: ZERO,
|
||||||
|
c2: ZERO,
|
||||||
|
},
|
||||||
|
c1: CubicExtField {
|
||||||
|
c0: ZERO,
|
||||||
|
c1: ZERO,
|
||||||
|
c2: ZERO,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn fp_to_fp12(
|
||||||
|
x: <Config as Bls12Config>::Fp,
|
||||||
|
) -> Fp12<<Config as Bls12Config>::Fp12Config> {
|
||||||
|
fp2_to_fp12(QuadExtField {
|
||||||
|
c0: x,
|
||||||
|
c1: MontFp!("0"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ate_tangent_ev(qt: G2, evpt: G1) -> Fp12<<Config as Bls12Config>::Fp12Config> {
|
||||||
|
let qt = qt.inner.into_affine();
|
||||||
|
let evpt = evpt.inner.into_affine();
|
||||||
|
|
||||||
|
let (xt, yt) = (qt.x, qt.y);
|
||||||
|
let (xe, ye) = (evpt.x, evpt.y);
|
||||||
|
|
||||||
|
let xt = fp2_to_fp12(xt);
|
||||||
|
let yt = fp2_to_fp12(yt);
|
||||||
|
let xe = fp_to_fp12(xe);
|
||||||
|
let ye = fp_to_fp12(ye);
|
||||||
|
|
||||||
|
let three = fp_to_fp12(MontFp!("3"));
|
||||||
|
let two = fp_to_fp12(MontFp!("2"));
|
||||||
|
|
||||||
|
let l = three * xt.square() / (two * yt);
|
||||||
|
ye - (l * xe) / U1 + (l * xt - yt) / U3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ate_line_ev(q1: G2, q2: G2, evpt: G1) -> Fp12<<Config as Bls12Config>::Fp12Config> {
|
||||||
|
let q1 = q1.inner.into_affine();
|
||||||
|
let q2 = q2.inner.into_affine();
|
||||||
|
let evpt = evpt.inner.into_affine();
|
||||||
|
|
||||||
|
let (x1, y1) = (q1.x, q1.y);
|
||||||
|
let (x2, y2) = (q2.x, q2.y);
|
||||||
|
let (xe, ye) = (evpt.x, evpt.y);
|
||||||
|
|
||||||
|
let x1 = fp2_to_fp12(x1);
|
||||||
|
let y1 = fp2_to_fp12(y1);
|
||||||
|
let x2 = fp2_to_fp12(x2);
|
||||||
|
let y2 = fp2_to_fp12(y2);
|
||||||
|
let xe = fp_to_fp12(xe);
|
||||||
|
let ye = fp_to_fp12(ye);
|
||||||
|
|
||||||
|
let l = (y2 - y1) / (x2 - x1);
|
||||||
|
ye - (l * xe) / U1 + (l * x1 - y1) / U3
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::needless_range_loop)]
|
||||||
|
fn ate_pairing(p: G1, q: G2) -> Gt {
|
||||||
|
let t_log2 = 75;
|
||||||
|
let t_bits = b"110000000001000001000000100000000000000000000000000000000100000000000000001";
|
||||||
|
|
||||||
|
let mut fk = fp_to_fp12(MontFp!("1"));
|
||||||
|
let mut qk = q;
|
||||||
|
|
||||||
|
for k in 1..t_log2 {
|
||||||
|
let lkk = ate_tangent_ev(qk, p);
|
||||||
|
qk = qk + qk;
|
||||||
|
fk = fk.square() * lkk;
|
||||||
|
|
||||||
|
if t_bits[k] == b'1' {
|
||||||
|
assert_ne!(q, qk);
|
||||||
|
let lkp1 = if q != -qk {
|
||||||
|
ate_line_ev(q, qk, p)
|
||||||
|
} else {
|
||||||
|
fp_to_fp12(MontFp!("1"))
|
||||||
|
};
|
||||||
|
qk += q;
|
||||||
|
fk *= lkp1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mlo = MillerLoopOutput(fk);
|
||||||
|
Gt {
|
||||||
|
inner: Bls::final_exponentiation(mlo).unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Gt {
|
||||||
|
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
|
||||||
|
pub(crate) inner: ark_ec::pairing::PairingOutput<crate::curve_446::Bls12_446>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Gt {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct QuadExtField<T> {
|
||||||
|
c0: T,
|
||||||
|
c1: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct CubicExtField<T> {
|
||||||
|
c0: T,
|
||||||
|
c1: T,
|
||||||
|
c2: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Gt<T> {
|
||||||
|
inner: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
f.debug_struct("Gt")
|
||||||
|
.field(
|
||||||
|
"inner",
|
||||||
|
&Gt {
|
||||||
|
inner: QuadExtField {
|
||||||
|
c0: CubicExtField {
|
||||||
|
c0: QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.0.c0.c0.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.0.c0.c0.c1),
|
||||||
|
},
|
||||||
|
c1: QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.0.c0.c1.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.0.c0.c1.c1),
|
||||||
|
},
|
||||||
|
c2: QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.0.c0.c2.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.0.c0.c2.c1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
c1: CubicExtField {
|
||||||
|
c0: QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.0.c1.c0.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.0.c1.c0.c1),
|
||||||
|
},
|
||||||
|
c1: QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.0.c1.c1.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.0.c1.c1.c1),
|
||||||
|
},
|
||||||
|
c2: QuadExtField {
|
||||||
|
c0: MontIntDisplay(&self.inner.0.c1.c2.c0),
|
||||||
|
c1: MontIntDisplay(&self.inner.0.c1.c2.c1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Gt {
|
||||||
|
pub fn pairing(g1: G1, g2: G2) -> Self {
|
||||||
|
ate_pairing(g1, -g2)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mul_scalar(self, scalar: Zp) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: mul_zp(self.inner, scalar),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Gt {
|
||||||
|
type Output = Gt;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Gt {
|
||||||
|
inner: self.inner + rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Gt {
|
||||||
|
type Output = Gt;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Gt {
|
||||||
|
inner: self.inner - rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for Gt {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner += rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for Gt {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner -= rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for Gt {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
Self { inner: -self.inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod zp {
|
||||||
|
use super::*;
|
||||||
|
use ark_ff::Fp;
|
||||||
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
|
fn redc(n: [u64; 5], nprime: u64, mut t: [u64; 7]) -> [u64; 5] {
|
||||||
|
for i in 0..2 {
|
||||||
|
let mut c = 0u64;
|
||||||
|
let m = u64::wrapping_mul(t[i], nprime);
|
||||||
|
|
||||||
|
for j in 0..5 {
|
||||||
|
let x = t[i + j] as u128 + m as u128 * n[j] as u128 + c as u128;
|
||||||
|
t[i + j] = x as u64;
|
||||||
|
c = (x >> 64) as u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
for j in 5..7 - i {
|
||||||
|
let x = t[i + j] as u128 + c as u128;
|
||||||
|
t[i + j] = x as u64;
|
||||||
|
c = (x >> 64) as u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut t = [t[2], t[3], t[4], t[5], t[6]];
|
||||||
|
|
||||||
|
if t.into_iter().rev().ge(n.into_iter().rev()) {
|
||||||
|
let mut o = false;
|
||||||
|
for i in 0..5 {
|
||||||
|
let (ti, o0) = u64::overflowing_sub(t[i], n[i]);
|
||||||
|
let (ti, o1) = u64::overflowing_sub(ti, o as u64);
|
||||||
|
o = o0 | o1;
|
||||||
|
t[i] = ti;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(t.into_iter().rev().lt(n.into_iter().rev()));
|
||||||
|
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Zeroize)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Zp {
|
||||||
|
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
|
||||||
|
pub(crate) inner: crate::curve_446::Fr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Zp {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("Zp")
|
||||||
|
.field(&MontIntDisplay(&self.inner))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Zp {
|
||||||
|
pub const ZERO: Self = Self {
|
||||||
|
inner: MontFp!("0"),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ONE: Self = Self {
|
||||||
|
inner: MontFp!("1"),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn from_bigint(n: [u64; 5]) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: BigInt(n).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_u64(n: u64) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: BigInt([n, 0, 0, 0, 0]).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_i64(n: i64) -> Self {
|
||||||
|
let n_abs = Self::from_u64(n.unsigned_abs());
|
||||||
|
if n > 0 {
|
||||||
|
n_abs
|
||||||
|
} else {
|
||||||
|
-n_abs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(self) -> [u8; 5 * 8] {
|
||||||
|
let buf = [
|
||||||
|
self.inner.0 .0[0].to_le_bytes(),
|
||||||
|
self.inner.0 .0[1].to_le_bytes(),
|
||||||
|
self.inner.0 .0[2].to_le_bytes(),
|
||||||
|
self.inner.0 .0[3].to_le_bytes(),
|
||||||
|
self.inner.0 .0[4].to_le_bytes(),
|
||||||
|
];
|
||||||
|
unsafe { core::mem::transmute(buf) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_raw_u64x7(n: [u64; 7]) -> Self {
|
||||||
|
const MODULUS: BigInt<5> = BigInt!(
|
||||||
|
"645383785691237230677916041525710377746967055506026847120930304831624105190538527824412673"
|
||||||
|
);
|
||||||
|
|
||||||
|
const MODULUS_MONTGOMERY: u64 = 272467794636046335;
|
||||||
|
|
||||||
|
let mut n = n;
|
||||||
|
// zero the 22 leading bits, so the result is <= MODULUS * 2^128
|
||||||
|
n[6] &= (1 << 42) - 1;
|
||||||
|
Zp {
|
||||||
|
inner: Fp(
|
||||||
|
BigInt(redc(MODULUS.0, MODULUS_MONTGOMERY, n)),
|
||||||
|
core::marker::PhantomData,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rand(rng: &mut dyn rand::RngCore) -> Self {
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
Self::from_raw_u64x7([
|
||||||
|
rng.gen::<u64>(),
|
||||||
|
rng.gen::<u64>(),
|
||||||
|
rng.gen::<u64>(),
|
||||||
|
rng.gen::<u64>(),
|
||||||
|
rng.gen::<u64>(),
|
||||||
|
rng.gen::<u64>(),
|
||||||
|
rng.gen::<u64>(),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash(values: &mut [Zp], data: &[&[u8]]) {
|
||||||
|
use sha3::digest::{ExtendableOutput, Update, XofReader};
|
||||||
|
|
||||||
|
let mut hasher = sha3::Shake256::default();
|
||||||
|
for data in data {
|
||||||
|
hasher.update(data);
|
||||||
|
}
|
||||||
|
let mut reader = hasher.finalize_xof();
|
||||||
|
|
||||||
|
for value in values {
|
||||||
|
let mut bytes = [0u8; 7 * 8];
|
||||||
|
reader.read(&mut bytes);
|
||||||
|
let bytes: [[u8; 8]; 7] = unsafe { core::mem::transmute(bytes) };
|
||||||
|
*value = Zp::from_raw_u64x7(bytes.map(u64::from_le_bytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Zp {
|
||||||
|
type Output = Zp;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Zp {
|
||||||
|
inner: self.inner + rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Zp {
|
||||||
|
type Output = Zp;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Zp {
|
||||||
|
inner: self.inner - rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul for Zp {
|
||||||
|
type Output = Zp;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
Zp {
|
||||||
|
inner: self.inner * rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div for Zp {
|
||||||
|
type Output = Zp;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn div(self, rhs: Self) -> Self::Output {
|
||||||
|
Zp {
|
||||||
|
inner: self.inner / rhs.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AddAssign for Zp {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner += rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for Zp {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
self.inner -= rhs.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for Zp {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
Self { inner: -self.inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::iter::Sum for Zp {
|
||||||
|
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
||||||
|
iter.fold(Zp::ZERO, Add::add)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use g1::G1;
|
||||||
|
pub use g2::G2;
|
||||||
|
pub use gt::Gt;
|
||||||
|
pub use zp::Zp;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use rand::rngs::StdRng;
|
||||||
|
use rand::SeedableRng;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_g1() {
|
||||||
|
let x = G1::GENERATOR;
|
||||||
|
let y = x.mul_scalar(Zp::from_i64(-2) * Zp::from_u64(2));
|
||||||
|
assert_eq!(x - x, G1::ZERO);
|
||||||
|
assert_eq!(x + y - x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_g2() {
|
||||||
|
let x = G2::GENERATOR;
|
||||||
|
let y = x.mul_scalar(Zp::from_i64(-2) * Zp::from_u64(2));
|
||||||
|
assert_eq!(x - x, G2::ZERO);
|
||||||
|
assert_eq!(x + y - x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_g1_msm() {
|
||||||
|
let n = 1024;
|
||||||
|
let x = vec![G1::GENERATOR.mul_scalar(Zp::from_i64(-1)); n];
|
||||||
|
let mut p = vec![Zp::ZERO; n];
|
||||||
|
Zp::hash(&mut p, &[&[0]]);
|
||||||
|
|
||||||
|
let result = G1::multi_mul_scalar(&x, &p);
|
||||||
|
let expected = x
|
||||||
|
.iter()
|
||||||
|
.zip(p.iter())
|
||||||
|
.map(|(&x, &p)| x.mul_scalar(p))
|
||||||
|
.sum::<G1>();
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_g2_msm() {
|
||||||
|
let n = 1024;
|
||||||
|
let x = vec![G2::GENERATOR.mul_scalar(Zp::from_i64(-1)); n];
|
||||||
|
let mut p = vec![Zp::ZERO; n];
|
||||||
|
Zp::hash(&mut p, &[&[0]]);
|
||||||
|
|
||||||
|
let result = G2::multi_mul_scalar(&x, &p);
|
||||||
|
let expected = x
|
||||||
|
.iter()
|
||||||
|
.zip(p.iter())
|
||||||
|
.map(|(&x, &p)| x.mul_scalar(p))
|
||||||
|
.sum::<G2>();
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pairing() {
|
||||||
|
let rng = &mut StdRng::seed_from_u64(0);
|
||||||
|
let p1 = Zp::rand(rng);
|
||||||
|
let p2 = Zp::rand(rng);
|
||||||
|
|
||||||
|
let x1 = G1::GENERATOR.mul_scalar(p1);
|
||||||
|
let x2 = G2::GENERATOR.mul_scalar(p2);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Gt::pairing(x1, x2),
|
||||||
|
Gt::pairing(G1::GENERATOR, G2::GENERATOR).mul_scalar(p1 * p2),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_distributivity() {
|
||||||
|
let a = Zp {
|
||||||
|
inner: MontFp!(
|
||||||
|
"20799633726231143268782044631117354647259165363910905818134484248029981143850"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let b = Zp {
|
||||||
|
inner: MontFp!(
|
||||||
|
"42333504039292951860879669847432876299949385605895551964353185488509497658948"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let c = Zp {
|
||||||
|
inner: MontFp!(
|
||||||
|
"6797004509292554067788526429737434481164547177696793280652530849910670196287"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!((((a - b) * c) - (a * c - b * c)).inner, Zp::ZERO.inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialization() {
|
||||||
|
let rng = &mut StdRng::seed_from_u64(0);
|
||||||
|
let alpha = Zp::rand(rng);
|
||||||
|
let g_cur = G1::GENERATOR.mul_scalar(alpha);
|
||||||
|
let g_hat_cur = G2::GENERATOR.mul_scalar(alpha);
|
||||||
|
|
||||||
|
let alpha2: Zp = serde_json::from_str(&serde_json::to_string(&alpha).unwrap()).unwrap();
|
||||||
|
assert_eq!(alpha, alpha2);
|
||||||
|
|
||||||
|
let g_cur2: G1 = serde_json::from_str(&serde_json::to_string(&g_cur).unwrap()).unwrap();
|
||||||
|
assert_eq!(g_cur, g_cur2);
|
||||||
|
|
||||||
|
let g_hat_cur2: G2 =
|
||||||
|
serde_json::from_str(&serde_json::to_string(&g_hat_cur).unwrap()).unwrap();
|
||||||
|
assert_eq!(g_hat_cur, g_hat_cur2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hasher_and_eq() {
|
||||||
|
// we need to make sure if the points are the same
|
||||||
|
// but the projective representations are different
|
||||||
|
// then they still hash into the same thing
|
||||||
|
let rng = &mut StdRng::seed_from_u64(0);
|
||||||
|
let alpha = Zp::rand(rng);
|
||||||
|
let a = G1::GENERATOR.mul_scalar(alpha);
|
||||||
|
|
||||||
|
// serialization should convert the point to affine representation
|
||||||
|
// after deserializing it we should have the same point
|
||||||
|
// but with a different representation
|
||||||
|
let a_affine: G1 = serde_json::from_str(&serde_json::to_string(&a).unwrap()).unwrap();
|
||||||
|
|
||||||
|
// the internal elements should be different
|
||||||
|
assert_ne!(a.inner.x, a_affine.inner.x);
|
||||||
|
assert_ne!(a.inner.y, a_affine.inner.y);
|
||||||
|
assert_ne!(a.inner.z, a_affine.inner.z);
|
||||||
|
|
||||||
|
// but equality and hasher should see the two as the same point
|
||||||
|
assert_eq!(a, a_affine);
|
||||||
|
let mut hm = HashMap::new();
|
||||||
|
hm.insert(a, 1);
|
||||||
|
assert_eq!(hm.len(), 1);
|
||||||
|
hm.insert(a_affine, 2);
|
||||||
|
assert_eq!(hm.len(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
3
tfhe-zk-pok/src/lib.rs
Normal file
3
tfhe-zk-pok/src/lib.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod curve_446;
|
||||||
|
pub mod curve_api;
|
||||||
|
pub mod proofs;
|
||||||
213
tfhe-zk-pok/src/proofs/binary.rs
Normal file
213
tfhe-zk-pok/src/proofs/binary.rs
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PublicParams<G: Curve> {
|
||||||
|
g_lists: GroupElements<G>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G: Curve> PublicParams<G> {
|
||||||
|
pub fn from_vec(g_list: Vec<G::G1>, g_hat_list: Vec<G::G2>) -> Self {
|
||||||
|
Self {
|
||||||
|
g_lists: GroupElements::from_vec(g_list, g_hat_list),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PrivateParams<G: Curve> {
|
||||||
|
alpha: G::Zp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PublicCommit<G: Curve> {
|
||||||
|
c_hat: G::G2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PrivateCommit<G: Curve> {
|
||||||
|
message: Vec<u64>,
|
||||||
|
gamma: G::Zp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Proof<G: Curve> {
|
||||||
|
c_y: G::G1,
|
||||||
|
pi: G::G1,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn crs_gen<G: Curve>(message_len: usize, rng: &mut dyn RngCore) -> PublicParams<G> {
|
||||||
|
let alpha = G::Zp::rand(rng);
|
||||||
|
PublicParams {
|
||||||
|
g_lists: GroupElements::new(message_len, alpha),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn commit<G: Curve>(
|
||||||
|
message: &[u64],
|
||||||
|
public: &PublicParams<G>,
|
||||||
|
rng: &mut dyn RngCore,
|
||||||
|
) -> (PublicCommit<G>, PrivateCommit<G>) {
|
||||||
|
let g_hat = G::G2::GENERATOR;
|
||||||
|
let n = message.len();
|
||||||
|
|
||||||
|
let gamma = G::Zp::rand(rng);
|
||||||
|
let x = OneBased::new_ref(message);
|
||||||
|
|
||||||
|
let mut c_hat = g_hat.mul_scalar(gamma);
|
||||||
|
for j in 1..n + 1 {
|
||||||
|
let term = if x[j] != 0 {
|
||||||
|
public.g_lists.g_hat_list[j]
|
||||||
|
} else {
|
||||||
|
G::G2::ZERO
|
||||||
|
};
|
||||||
|
c_hat += term;
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
PublicCommit { c_hat },
|
||||||
|
PrivateCommit {
|
||||||
|
message: message.to_vec(),
|
||||||
|
gamma,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prove<G: Curve>(
|
||||||
|
public: (&PublicParams<G>, &PublicCommit<G>),
|
||||||
|
private_commit: &PrivateCommit<G>,
|
||||||
|
rng: &mut dyn RngCore,
|
||||||
|
) -> Proof<G> {
|
||||||
|
let n = private_commit.message.len();
|
||||||
|
let g = G::G1::GENERATOR;
|
||||||
|
let x = OneBased::new_ref(&*private_commit.message);
|
||||||
|
let c_hat = public.1.c_hat;
|
||||||
|
let gamma = private_commit.gamma;
|
||||||
|
let gamma_y = G::Zp::rand(rng);
|
||||||
|
let g_list = &public.0.g_lists.g_list;
|
||||||
|
|
||||||
|
let mut y = OneBased(vec![G::Zp::ZERO; n]);
|
||||||
|
G::Zp::hash(&mut y.0, &[c_hat.to_bytes().as_ref()]);
|
||||||
|
|
||||||
|
let mut c_y = g.mul_scalar(gamma_y);
|
||||||
|
for j in 1..n + 1 {
|
||||||
|
c_y += (g_list[n + 1 - j]).mul_scalar(y[j] * G::Zp::from_u64(x[j]));
|
||||||
|
}
|
||||||
|
|
||||||
|
let y_bytes = &*(1..n + 1)
|
||||||
|
.flat_map(|i| y[i].to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<_>>();
|
||||||
|
let mut t = OneBased(vec![G::Zp::ZERO; n]);
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut t.0,
|
||||||
|
&[y_bytes, c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref()],
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut delta = [G::Zp::ZERO; 2];
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut delta,
|
||||||
|
&[c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref()],
|
||||||
|
);
|
||||||
|
let [delta_eq, delta_y] = delta;
|
||||||
|
|
||||||
|
let proof = {
|
||||||
|
let mut poly_0 = vec![G::Zp::ZERO; n + 1];
|
||||||
|
let mut poly_1 = vec![G::Zp::ZERO; n + 1];
|
||||||
|
let mut poly_2 = vec![G::Zp::ZERO; n + 1];
|
||||||
|
let mut poly_3 = vec![G::Zp::ZERO; n + 1];
|
||||||
|
|
||||||
|
poly_0[0] = gamma_y * delta_y;
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
poly_0[n + 1 - i] =
|
||||||
|
delta_y * (G::Zp::from_u64(x[i]) * y[i]) + (delta_eq * t[i] - delta_y) * y[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
poly_1[0] = gamma;
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
poly_1[i] = G::Zp::from_u64(x[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
poly_2[0] = gamma_y;
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
poly_2[n + 1 - i] = y[i] * G::Zp::from_u64(x[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
poly_3[i] = delta_eq * t[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
let poly = G::Zp::poly_sub(
|
||||||
|
&G::Zp::poly_mul(&poly_0, &poly_1),
|
||||||
|
&G::Zp::poly_mul(&poly_2, &poly_3),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut proof = g.mul_scalar(poly[0]);
|
||||||
|
for i in 1..poly.len() {
|
||||||
|
proof += g_list[i].mul_scalar(poly[i]);
|
||||||
|
}
|
||||||
|
proof
|
||||||
|
};
|
||||||
|
|
||||||
|
Proof { pi: proof, c_y }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::result_unit_err)]
|
||||||
|
pub fn verify<G: Curve>(
|
||||||
|
proof: &Proof<G>,
|
||||||
|
public: (&PublicParams<G>, &PublicCommit<G>),
|
||||||
|
) -> Result<(), ()> {
|
||||||
|
let e = G::Gt::pairing;
|
||||||
|
let c_hat = public.1.c_hat;
|
||||||
|
let g_hat = G::G2::GENERATOR;
|
||||||
|
let g_list = &public.0.g_lists.g_list;
|
||||||
|
let g_hat_list = &public.0.g_lists.g_hat_list;
|
||||||
|
let n = public.0.g_lists.message_len;
|
||||||
|
|
||||||
|
let pi = proof.pi;
|
||||||
|
let c_y = proof.c_y;
|
||||||
|
|
||||||
|
let mut y = OneBased(vec![G::Zp::ZERO; n]);
|
||||||
|
G::Zp::hash(&mut y.0, &[c_hat.to_bytes().as_ref()]);
|
||||||
|
|
||||||
|
let y_bytes = &*(1..n + 1)
|
||||||
|
.flat_map(|i| y[i].to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<_>>();
|
||||||
|
let mut t = OneBased(vec![G::Zp::ZERO; n]);
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut t.0,
|
||||||
|
&[y_bytes, c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref()],
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut delta = [G::Zp::ZERO; 2];
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut delta,
|
||||||
|
&[c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref()],
|
||||||
|
);
|
||||||
|
let [delta_eq, delta_y] = delta;
|
||||||
|
|
||||||
|
let rhs = e(pi, g_hat);
|
||||||
|
let lhs = {
|
||||||
|
let numerator = {
|
||||||
|
let mut p = c_y.mul_scalar(delta_y);
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
let gy = g_list[n + 1 - i].mul_scalar(y[i]);
|
||||||
|
p += gy.mul_scalar(delta_eq).mul_scalar(t[i]) - gy.mul_scalar(delta_y);
|
||||||
|
}
|
||||||
|
e(p, c_hat)
|
||||||
|
};
|
||||||
|
let denominator = {
|
||||||
|
let mut q = G::G2::ZERO;
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
q += g_hat_list[i].mul_scalar(delta_eq).mul_scalar(t[i]);
|
||||||
|
}
|
||||||
|
e(c_y, q)
|
||||||
|
};
|
||||||
|
numerator - denominator
|
||||||
|
};
|
||||||
|
|
||||||
|
if lhs == rhs {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
121
tfhe-zk-pok/src/proofs/index.rs
Normal file
121
tfhe-zk-pok/src/proofs/index.rs
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PublicParams<G: Curve> {
|
||||||
|
g_lists: GroupElements<G>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G: Curve> PublicParams<G> {
|
||||||
|
pub fn from_vec(g_list: Vec<G::G1>, g_hat_list: Vec<G::G2>) -> Self {
|
||||||
|
Self {
|
||||||
|
g_lists: GroupElements::from_vec(g_list, g_hat_list),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PrivateParams<G: Curve> {
|
||||||
|
alpha: G::Zp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PublicCommit<G: Curve> {
|
||||||
|
c: G::G1,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PrivateCommit<G: Curve> {
|
||||||
|
message: Vec<u64>,
|
||||||
|
gamma: G::Zp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Proof<G: Curve> {
|
||||||
|
pi: G::G1,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn crs_gen<G: Curve>(message_len: usize, rng: &mut dyn RngCore) -> PublicParams<G> {
|
||||||
|
let alpha = G::Zp::rand(rng);
|
||||||
|
PublicParams {
|
||||||
|
g_lists: GroupElements::new(message_len, alpha),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn commit<G: Curve>(
|
||||||
|
message: &[u64],
|
||||||
|
public: &PublicParams<G>,
|
||||||
|
rng: &mut dyn RngCore,
|
||||||
|
) -> (PublicCommit<G>, PrivateCommit<G>) {
|
||||||
|
let g = G::G1::GENERATOR;
|
||||||
|
let n = message.len();
|
||||||
|
|
||||||
|
let gamma = G::Zp::rand(rng);
|
||||||
|
let m = OneBased::new_ref(message);
|
||||||
|
|
||||||
|
let mut c = g.mul_scalar(gamma);
|
||||||
|
for j in 1..n + 1 {
|
||||||
|
let term = public.g_lists.g_list[j].mul_scalar(G::Zp::from_u64(m[j]));
|
||||||
|
c += term;
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
PublicCommit { c },
|
||||||
|
PrivateCommit {
|
||||||
|
message: message.to_vec(),
|
||||||
|
gamma,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prove<G: Curve>(
|
||||||
|
i: usize,
|
||||||
|
public: (&PublicParams<G>, &PublicCommit<G>),
|
||||||
|
private: &PrivateCommit<G>,
|
||||||
|
rng: &mut dyn RngCore,
|
||||||
|
) -> Proof<G> {
|
||||||
|
let _ = rng;
|
||||||
|
let n = private.message.len();
|
||||||
|
let m = OneBased::new_ref(&*private.message);
|
||||||
|
let gamma = private.gamma;
|
||||||
|
let g_list = &public.0.g_lists.g_list;
|
||||||
|
|
||||||
|
let mut pi = g_list[n + 1 - i].mul_scalar(gamma);
|
||||||
|
for j in 1..n + 1 {
|
||||||
|
if i != j {
|
||||||
|
let term = if m[j] & 1 == 1 {
|
||||||
|
g_list[n + 1 - i + j]
|
||||||
|
} else {
|
||||||
|
G::G1::ZERO
|
||||||
|
};
|
||||||
|
|
||||||
|
pi += term;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Proof { pi }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::result_unit_err)]
|
||||||
|
pub fn verify<G: Curve>(
|
||||||
|
proof: &Proof<G>,
|
||||||
|
(index, mi): (usize, u64),
|
||||||
|
public: (&PublicParams<G>, &PublicCommit<G>),
|
||||||
|
) -> Result<(), ()> {
|
||||||
|
let e = G::Gt::pairing;
|
||||||
|
let c = public.1.c;
|
||||||
|
let g_hat = G::G2::GENERATOR;
|
||||||
|
let g_list = &public.0.g_lists.g_list;
|
||||||
|
let g_hat_list = &public.0.g_lists.g_hat_list;
|
||||||
|
let n = public.0.g_lists.message_len;
|
||||||
|
let i = index + 1;
|
||||||
|
|
||||||
|
let lhs = e(c, g_hat_list[n + 1 - i]);
|
||||||
|
let rhs = e(proof.pi, g_hat) + (e(g_list[1], g_hat_list[n])).mul_scalar(G::Zp::from_u64(mi));
|
||||||
|
|
||||||
|
if lhs == rhs {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
95
tfhe-zk-pok/src/proofs/mod.rs
Normal file
95
tfhe-zk-pok/src/proofs/mod.rs
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
use crate::curve_api::{Curve, CurveGroupOps, FieldOps, PairingGroupOps};
|
||||||
|
|
||||||
|
use core::ops::{Index, IndexMut};
|
||||||
|
use rand::RngCore;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
struct OneBased<T: ?Sized>(T);
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum ComputeLoad {
|
||||||
|
Proof,
|
||||||
|
Verify,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> OneBased<T> {
|
||||||
|
pub fn new(inner: T) -> Self
|
||||||
|
where
|
||||||
|
T: Sized,
|
||||||
|
{
|
||||||
|
Self(inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_ref(inner: &T) -> &Self {
|
||||||
|
unsafe { &*(inner as *const T as *const Self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + Index<usize>> Index<usize> for OneBased<T> {
|
||||||
|
type Output = T::Output;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
&self.0[index - 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + IndexMut<usize>> IndexMut<usize> for OneBased<T> {
|
||||||
|
#[inline]
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
&mut self.0[index - 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
struct GroupElements<G: Curve> {
|
||||||
|
g_list: OneBased<Vec<G::G1>>,
|
||||||
|
g_hat_list: OneBased<Vec<G::G2>>,
|
||||||
|
message_len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G: Curve> GroupElements<G> {
|
||||||
|
pub fn new(message_len: usize, alpha: G::Zp) -> Self {
|
||||||
|
let mut g_list = Vec::new();
|
||||||
|
let mut g_hat_list = Vec::new();
|
||||||
|
|
||||||
|
let mut g_cur = G::G1::GENERATOR.mul_scalar(alpha);
|
||||||
|
|
||||||
|
for i in 0..2 * message_len {
|
||||||
|
if i == message_len {
|
||||||
|
g_list.push(G::G1::ZERO);
|
||||||
|
} else {
|
||||||
|
g_list.push(g_cur);
|
||||||
|
}
|
||||||
|
g_cur = g_cur.mul_scalar(alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut g_hat_cur = G::G2::GENERATOR.mul_scalar(alpha);
|
||||||
|
for _ in 0..message_len {
|
||||||
|
g_hat_list.push(g_hat_cur);
|
||||||
|
g_hat_cur = (g_hat_cur).mul_scalar(alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
g_list: OneBased::new(g_list),
|
||||||
|
g_hat_list: OneBased::new(g_hat_list),
|
||||||
|
message_len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_vec(g_list: Vec<G::G1>, g_hat_list: Vec<G::G2>) -> Self {
|
||||||
|
let message_len = g_hat_list.len();
|
||||||
|
Self {
|
||||||
|
g_list: OneBased::new(g_list),
|
||||||
|
g_hat_list: OneBased::new(g_hat_list),
|
||||||
|
message_len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod binary;
|
||||||
|
pub mod index;
|
||||||
|
pub mod pke;
|
||||||
|
pub mod range;
|
||||||
|
pub mod rlwe;
|
||||||
1043
tfhe-zk-pok/src/proofs/pke.rs
Normal file
1043
tfhe-zk-pok/src/proofs/pke.rs
Normal file
File diff suppressed because it is too large
Load Diff
354
tfhe-zk-pok/src/proofs/range.rs
Normal file
354
tfhe-zk-pok/src/proofs/range.rs
Normal file
@@ -0,0 +1,354 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PublicParams<G: Curve> {
|
||||||
|
g_lists: GroupElements<G>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G: Curve> PublicParams<G> {
|
||||||
|
pub fn from_vec(g_list: Vec<G::G1>, g_hat_list: Vec<G::G2>) -> Self {
|
||||||
|
Self {
|
||||||
|
g_lists: GroupElements::from_vec(g_list, g_hat_list),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PrivateParams<G: Curve> {
|
||||||
|
alpha: G::Zp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PublicCommit<G: Curve> {
|
||||||
|
l: usize,
|
||||||
|
v_hat: G::G2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PrivateCommit<G: Curve> {
|
||||||
|
x: u64,
|
||||||
|
r: G::Zp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Proof<G: Curve> {
|
||||||
|
c_y: G::G1,
|
||||||
|
c_hat: G::G2,
|
||||||
|
pi: G::G1,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn crs_gen<G: Curve>(max_nbits: usize, rng: &mut dyn RngCore) -> PublicParams<G> {
|
||||||
|
let alpha = G::Zp::rand(rng);
|
||||||
|
PublicParams {
|
||||||
|
g_lists: GroupElements::new(max_nbits, alpha),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn commit<G: Curve>(
|
||||||
|
x: u64,
|
||||||
|
l: usize,
|
||||||
|
public: &PublicParams<G>,
|
||||||
|
rng: &mut dyn RngCore,
|
||||||
|
) -> (PublicCommit<G>, PrivateCommit<G>) {
|
||||||
|
let g_hat = G::G2::GENERATOR;
|
||||||
|
|
||||||
|
let r = G::Zp::rand(rng);
|
||||||
|
let v_hat = g_hat.mul_scalar(r) + public.g_lists.g_hat_list[1].mul_scalar(G::Zp::from_u64(x));
|
||||||
|
|
||||||
|
(PublicCommit { l, v_hat }, PrivateCommit { x, r })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prove<G: Curve>(
|
||||||
|
public: (&PublicParams<G>, &PublicCommit<G>),
|
||||||
|
private_commit: &PrivateCommit<G>,
|
||||||
|
rng: &mut dyn RngCore,
|
||||||
|
) -> Proof<G> {
|
||||||
|
let &PrivateCommit { x, r } = private_commit;
|
||||||
|
let &PublicCommit { l, v_hat } = public.1;
|
||||||
|
let PublicParams { g_lists } = public.0;
|
||||||
|
let n = g_lists.message_len;
|
||||||
|
|
||||||
|
let g_list = &g_lists.g_list;
|
||||||
|
let g_hat_list = &g_lists.g_hat_list;
|
||||||
|
|
||||||
|
let g = G::G1::GENERATOR;
|
||||||
|
let g_hat = G::G2::GENERATOR;
|
||||||
|
let gamma = G::Zp::rand(rng);
|
||||||
|
let gamma_y = G::Zp::rand(rng);
|
||||||
|
|
||||||
|
let mut x_bits = vec![0u64; n];
|
||||||
|
for (i, x_bits) in x_bits[0..l].iter_mut().enumerate() {
|
||||||
|
*x_bits = (x >> i) & 1;
|
||||||
|
}
|
||||||
|
let x_bits = OneBased(x_bits);
|
||||||
|
|
||||||
|
let c_hat = {
|
||||||
|
let mut c = g_hat.mul_scalar(gamma);
|
||||||
|
for j in 1..l + 1 {
|
||||||
|
let term = if x_bits[j] != 0 {
|
||||||
|
g_hat_list[j]
|
||||||
|
} else {
|
||||||
|
G::G2::ZERO
|
||||||
|
};
|
||||||
|
c += term;
|
||||||
|
}
|
||||||
|
c
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut proof_x = -g_list[n].mul_scalar(r);
|
||||||
|
for i in 1..l + 1 {
|
||||||
|
let mut term = g_list[n + 1 - i].mul_scalar(gamma);
|
||||||
|
for j in 1..l + 1 {
|
||||||
|
if j != i {
|
||||||
|
let term_inner = if x_bits[j] != 0 {
|
||||||
|
g_list[n + 1 - i + j]
|
||||||
|
} else {
|
||||||
|
G::G1::ZERO
|
||||||
|
};
|
||||||
|
term += term_inner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 1..i {
|
||||||
|
term = term.double();
|
||||||
|
}
|
||||||
|
proof_x += term;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut y = vec![G::Zp::ZERO; n];
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut y,
|
||||||
|
&[v_hat.to_bytes().as_ref(), c_hat.to_bytes().as_ref()],
|
||||||
|
);
|
||||||
|
let y = OneBased(y);
|
||||||
|
let mut c_y = g.mul_scalar(gamma_y);
|
||||||
|
for j in 1..l + 1 {
|
||||||
|
c_y += g_list[n + 1 - j].mul_scalar(y[j] * G::Zp::from_u64(x_bits[j]));
|
||||||
|
}
|
||||||
|
|
||||||
|
let y_bytes = &*(1..n + 1)
|
||||||
|
.flat_map(|i| y[i].to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<_>>();
|
||||||
|
|
||||||
|
let mut t = vec![G::Zp::ZERO; n];
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut t,
|
||||||
|
&[
|
||||||
|
y_bytes,
|
||||||
|
v_hat.to_bytes().as_ref(),
|
||||||
|
c_hat.to_bytes().as_ref(),
|
||||||
|
c_y.to_bytes().as_ref(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let t = OneBased(t);
|
||||||
|
|
||||||
|
let mut proof_eq = G::G1::ZERO;
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
let mut numerator = g_list[n + 1 - i].mul_scalar(gamma);
|
||||||
|
for j in 1..n + 1 {
|
||||||
|
if j != i {
|
||||||
|
let term = if x_bits[j] != 0 {
|
||||||
|
g_list[n + 1 - i + j]
|
||||||
|
} else {
|
||||||
|
G::G1::ZERO
|
||||||
|
};
|
||||||
|
numerator += term;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numerator = numerator.mul_scalar(t[i] * y[i]);
|
||||||
|
|
||||||
|
let mut denominator = g_list[i].mul_scalar(gamma_y);
|
||||||
|
for j in 1..n + 1 {
|
||||||
|
if j != i {
|
||||||
|
denominator += g_list[n + 1 - j + i].mul_scalar(y[j] * G::Zp::from_u64(x_bits[j]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
denominator = denominator.mul_scalar(t[i]);
|
||||||
|
|
||||||
|
proof_eq += numerator - denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut proof_y = g.mul_scalar(gamma_y);
|
||||||
|
for j in 1..n + 1 {
|
||||||
|
proof_y -= g_list[n + 1 - j].mul_scalar(y[j] * G::Zp::from_u64(1 - x_bits[j]));
|
||||||
|
}
|
||||||
|
proof_y = proof_y.mul_scalar(gamma);
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
let mut term = g_list[i].mul_scalar(gamma_y);
|
||||||
|
for j in 1..n + 1 {
|
||||||
|
if j != i {
|
||||||
|
term -= g_list[n + 1 - j + i].mul_scalar(y[j] * G::Zp::from_u64(1 - x_bits[j]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let term = if x_bits[i] != 0 { term } else { G::G1::ZERO };
|
||||||
|
proof_y += term;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut s = vec![G::Zp::ZERO; n];
|
||||||
|
for (i, s) in s.iter_mut().enumerate() {
|
||||||
|
G::Zp::hash(
|
||||||
|
core::slice::from_mut(s),
|
||||||
|
&[
|
||||||
|
&i.to_le_bytes(),
|
||||||
|
v_hat.to_bytes().as_ref(),
|
||||||
|
c_hat.to_bytes().as_ref(),
|
||||||
|
c_y.to_bytes().as_ref(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let s = OneBased(s);
|
||||||
|
|
||||||
|
let mut proof_v = G::G1::ZERO;
|
||||||
|
for i in 2..n + 1 {
|
||||||
|
proof_v += G::G1::mul_scalar(
|
||||||
|
g_list[n + 1 - i].mul_scalar(r) + g_list[n + 2 - i].mul_scalar(G::Zp::from_u64(x)),
|
||||||
|
s[i],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut delta = [G::Zp::ZERO; 4];
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut delta,
|
||||||
|
&[
|
||||||
|
v_hat.to_bytes().as_ref(),
|
||||||
|
c_hat.to_bytes().as_ref(),
|
||||||
|
c_y.to_bytes().as_ref(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let [delta_x, delta_eq, delta_y, delta_v] = delta;
|
||||||
|
|
||||||
|
let proof = proof_x.mul_scalar(delta_x)
|
||||||
|
+ proof_eq.mul_scalar(delta_eq)
|
||||||
|
+ proof_y.mul_scalar(delta_y)
|
||||||
|
+ proof_v.mul_scalar(delta_v);
|
||||||
|
|
||||||
|
Proof {
|
||||||
|
c_y,
|
||||||
|
c_hat,
|
||||||
|
pi: proof,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::result_unit_err)]
|
||||||
|
pub fn verify<G: Curve>(
|
||||||
|
proof: &Proof<G>,
|
||||||
|
public: (&PublicParams<G>, &PublicCommit<G>),
|
||||||
|
) -> Result<(), ()> {
|
||||||
|
let e = G::Gt::pairing;
|
||||||
|
let &PublicCommit { l, v_hat } = public.1;
|
||||||
|
let PublicParams { g_lists } = public.0;
|
||||||
|
let n = g_lists.message_len;
|
||||||
|
|
||||||
|
let g_list = &g_lists.g_list;
|
||||||
|
let g_hat_list = &g_lists.g_hat_list;
|
||||||
|
|
||||||
|
let g_hat = G::G2::GENERATOR;
|
||||||
|
|
||||||
|
let &Proof { c_y, c_hat, pi } = proof;
|
||||||
|
|
||||||
|
let mut y = vec![G::Zp::ZERO; n];
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut y,
|
||||||
|
&[v_hat.to_bytes().as_ref(), c_hat.to_bytes().as_ref()],
|
||||||
|
);
|
||||||
|
let y = OneBased(y);
|
||||||
|
|
||||||
|
let y_bytes = &*(1..n + 1)
|
||||||
|
.flat_map(|i| y[i].to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<_>>();
|
||||||
|
|
||||||
|
let mut t = vec![G::Zp::ZERO; n];
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut t,
|
||||||
|
&[
|
||||||
|
y_bytes,
|
||||||
|
v_hat.to_bytes().as_ref(),
|
||||||
|
c_hat.to_bytes().as_ref(),
|
||||||
|
c_y.to_bytes().as_ref(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let t = OneBased(t);
|
||||||
|
|
||||||
|
let mut delta = [G::Zp::ZERO; 4];
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut delta,
|
||||||
|
&[
|
||||||
|
v_hat.to_bytes().as_ref(),
|
||||||
|
c_hat.to_bytes().as_ref(),
|
||||||
|
c_y.to_bytes().as_ref(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let [delta_x, delta_eq, delta_y, delta_v] = delta;
|
||||||
|
|
||||||
|
let mut s = vec![G::Zp::ZERO; n];
|
||||||
|
for (i, s) in s.iter_mut().enumerate() {
|
||||||
|
G::Zp::hash(
|
||||||
|
core::slice::from_mut(s),
|
||||||
|
&[
|
||||||
|
&i.to_le_bytes(),
|
||||||
|
v_hat.to_bytes().as_ref(),
|
||||||
|
c_hat.to_bytes().as_ref(),
|
||||||
|
c_y.to_bytes().as_ref(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let s = OneBased(s);
|
||||||
|
|
||||||
|
let rhs = e(pi, g_hat);
|
||||||
|
let lhs = {
|
||||||
|
let numerator = {
|
||||||
|
let mut p = c_y.mul_scalar(delta_y);
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
let g = g_list[n + 1 - i];
|
||||||
|
if i <= l {
|
||||||
|
p += g.mul_scalar(delta_x * G::Zp::from_u64(1 << (i - 1)));
|
||||||
|
}
|
||||||
|
p += g.mul_scalar((delta_eq * t[i] - delta_y) * y[i]);
|
||||||
|
}
|
||||||
|
e(p, c_hat)
|
||||||
|
};
|
||||||
|
let denominator_0 = {
|
||||||
|
let mut p = g_list[n].mul_scalar(delta_x);
|
||||||
|
for i in 2..n + 1 {
|
||||||
|
p -= g_list[n + 1 - i].mul_scalar(delta_v * s[i]);
|
||||||
|
}
|
||||||
|
e(p, v_hat)
|
||||||
|
};
|
||||||
|
let denominator_1 = {
|
||||||
|
let mut q = G::G2::ZERO;
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
q += g_hat_list[i].mul_scalar(delta_eq * t[i]);
|
||||||
|
}
|
||||||
|
e(c_y, q)
|
||||||
|
};
|
||||||
|
numerator - denominator_0 - denominator_1
|
||||||
|
};
|
||||||
|
|
||||||
|
if lhs == rhs {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use rand::rngs::StdRng;
|
||||||
|
use rand::{Rng, SeedableRng};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_range() {
|
||||||
|
let rng = &mut StdRng::seed_from_u64(0);
|
||||||
|
|
||||||
|
let max_nbits = 10;
|
||||||
|
let l = 6;
|
||||||
|
let x = rng.gen::<u64>() % (1 << l);
|
||||||
|
let public_params = crs_gen::<crate::curve_api::Bls12_446>(max_nbits, rng);
|
||||||
|
let (public_commit, private_commit) = commit(x, l, &public_params, rng);
|
||||||
|
let proof = prove((&public_params, &public_commit), &private_commit, rng);
|
||||||
|
let verify = verify(&proof, (&public_params, &public_commit));
|
||||||
|
assert!(verify.is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
932
tfhe-zk-pok/src/proofs/rlwe.rs
Normal file
932
tfhe-zk-pok/src/proofs/rlwe.rs
Normal file
@@ -0,0 +1,932 @@
|
|||||||
|
use super::*;
|
||||||
|
use core::iter::zip;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use rayon::prelude::*;
|
||||||
|
|
||||||
|
fn bit_iter(x: u64, nbits: u32) -> impl Iterator<Item = bool> {
|
||||||
|
(0..nbits).map(move |idx| ((x >> idx) & 1) == 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PublicParams<G: Curve> {
|
||||||
|
g_lists: GroupElements<G>,
|
||||||
|
d: usize,
|
||||||
|
big_n: usize,
|
||||||
|
big_m: usize,
|
||||||
|
b_i: u64,
|
||||||
|
q: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G: Curve> PublicParams<G> {
|
||||||
|
pub fn from_vec(
|
||||||
|
g_list: Vec<G::G1>,
|
||||||
|
g_hat_list: Vec<G::G2>,
|
||||||
|
d: usize,
|
||||||
|
big_n: usize,
|
||||||
|
big_m: usize,
|
||||||
|
b_i: u64,
|
||||||
|
q: u64,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
g_lists: GroupElements::from_vec(g_list, g_hat_list),
|
||||||
|
d,
|
||||||
|
big_n,
|
||||||
|
big_m,
|
||||||
|
b_i,
|
||||||
|
q,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PrivateParams<G: Curve> {
|
||||||
|
alpha: G::Zp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PublicCommit<G: Curve> {
|
||||||
|
a: Matrix<i64>,
|
||||||
|
c: Vector<i64>,
|
||||||
|
__marker: PhantomData<G>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PrivateCommit<G: Curve> {
|
||||||
|
s: Vector<i64>,
|
||||||
|
__marker: PhantomData<G>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Proof<G: Curve> {
|
||||||
|
c_hat: G::G2,
|
||||||
|
c_y: G::G1,
|
||||||
|
pi: G::G1,
|
||||||
|
c_hat_t: Option<G::G2>,
|
||||||
|
c_h: Option<G::G1>,
|
||||||
|
pi_kzg: Option<G::G1>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn crs_gen<G: Curve>(
|
||||||
|
d: usize,
|
||||||
|
big_n: usize,
|
||||||
|
big_m: usize,
|
||||||
|
b_i: u64,
|
||||||
|
q: u64,
|
||||||
|
rng: &mut dyn RngCore,
|
||||||
|
) -> PublicParams<G> {
|
||||||
|
let alpha = G::Zp::rand(rng);
|
||||||
|
let b_r = ((d * big_m) as u64 * b_i) / 2;
|
||||||
|
let big_d = d * (big_m * (1 + b_i.ilog2() as usize) + (big_n * (1 + b_r.ilog2() as usize)));
|
||||||
|
let n = big_d + 1;
|
||||||
|
PublicParams {
|
||||||
|
g_lists: GroupElements::new(n, alpha),
|
||||||
|
d,
|
||||||
|
big_n,
|
||||||
|
big_m,
|
||||||
|
b_i,
|
||||||
|
q,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Vector<T> {
|
||||||
|
pub data: Vec<T>,
|
||||||
|
pub polynomial_size: usize,
|
||||||
|
pub nrows: usize,
|
||||||
|
}
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Matrix<T> {
|
||||||
|
pub data: Vec<T>,
|
||||||
|
pub polynomial_size: usize,
|
||||||
|
pub nrows: usize,
|
||||||
|
pub ncols: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Copy> Matrix<T> {
|
||||||
|
pub fn new(polynomial_size: usize, nrows: usize, ncols: usize, value: T) -> Self {
|
||||||
|
Self {
|
||||||
|
data: vec![value; polynomial_size * nrows * ncols],
|
||||||
|
polynomial_size,
|
||||||
|
nrows,
|
||||||
|
ncols,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Copy> Vector<T> {
|
||||||
|
pub fn new(polynomial_size: usize, nrows: usize, value: T) -> Self {
|
||||||
|
Self {
|
||||||
|
data: vec![value; polynomial_size * nrows],
|
||||||
|
polynomial_size,
|
||||||
|
nrows,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Index<usize> for Vector<T> {
|
||||||
|
type Output = [T];
|
||||||
|
|
||||||
|
fn index(&self, row: usize) -> &Self::Output {
|
||||||
|
let row = row - 1;
|
||||||
|
&self.data[self.polynomial_size * row..][..self.polynomial_size]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> IndexMut<usize> for Vector<T> {
|
||||||
|
fn index_mut(&mut self, row: usize) -> &mut Self::Output {
|
||||||
|
let row = row - 1;
|
||||||
|
&mut self.data[self.polynomial_size * row..][..self.polynomial_size]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Index<(usize, usize)> for Matrix<T> {
|
||||||
|
type Output = [T];
|
||||||
|
|
||||||
|
fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
|
||||||
|
let row = row - 1;
|
||||||
|
let col = col - 1;
|
||||||
|
&self.data[self.polynomial_size * (row * self.ncols + col)..][..self.polynomial_size]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> IndexMut<(usize, usize)> for Matrix<T> {
|
||||||
|
fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut Self::Output {
|
||||||
|
let row = row - 1;
|
||||||
|
let col = col - 1;
|
||||||
|
&mut self.data[self.polynomial_size * (row * self.ncols + col)..][..self.polynomial_size]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn commit<G: Curve>(
|
||||||
|
a: Matrix<i64>,
|
||||||
|
c: Vector<i64>,
|
||||||
|
s: Vector<i64>,
|
||||||
|
public: &PublicParams<G>,
|
||||||
|
rng: &mut dyn RngCore,
|
||||||
|
) -> (PublicCommit<G>, PrivateCommit<G>) {
|
||||||
|
let _ = (public, rng);
|
||||||
|
(
|
||||||
|
PublicCommit {
|
||||||
|
a,
|
||||||
|
c,
|
||||||
|
__marker: PhantomData,
|
||||||
|
},
|
||||||
|
PrivateCommit {
|
||||||
|
s,
|
||||||
|
__marker: PhantomData,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prove<G: Curve>(
|
||||||
|
public: (&PublicParams<G>, &PublicCommit<G>),
|
||||||
|
private_commit: &PrivateCommit<G>,
|
||||||
|
load: ComputeLoad,
|
||||||
|
rng: &mut dyn RngCore,
|
||||||
|
) -> Proof<G> {
|
||||||
|
let &PublicParams {
|
||||||
|
ref g_lists,
|
||||||
|
d,
|
||||||
|
big_n,
|
||||||
|
big_m,
|
||||||
|
b_i,
|
||||||
|
q,
|
||||||
|
} = public.0;
|
||||||
|
let g_list = &g_lists.g_list;
|
||||||
|
let g_hat_list = &g_lists.g_hat_list;
|
||||||
|
let s = &private_commit.s;
|
||||||
|
let a = &public.1.a;
|
||||||
|
|
||||||
|
let b_r = ((d * big_m) as u64 * b_i) / 2;
|
||||||
|
let big_d = d * (big_m * (1 + b_i.ilog2() as usize) + (big_n * (1 + b_r.ilog2() as usize)));
|
||||||
|
let n = big_d + 1;
|
||||||
|
|
||||||
|
let g = G::G1::GENERATOR;
|
||||||
|
let g_hat = G::G2::GENERATOR;
|
||||||
|
let gamma = G::Zp::rand(rng);
|
||||||
|
let gamma_y = G::Zp::rand(rng);
|
||||||
|
|
||||||
|
let mut c = Vector {
|
||||||
|
data: vec![0i64; d],
|
||||||
|
polynomial_size: d,
|
||||||
|
nrows: big_n,
|
||||||
|
};
|
||||||
|
let mut r = Vector {
|
||||||
|
data: vec![0i64; d],
|
||||||
|
polynomial_size: d,
|
||||||
|
nrows: big_n,
|
||||||
|
};
|
||||||
|
|
||||||
|
for j in 1..big_n + 1 {
|
||||||
|
let c = &mut c[j];
|
||||||
|
let r = &mut r[j];
|
||||||
|
|
||||||
|
let mut polymul = vec![0i128; d];
|
||||||
|
for i in 1..big_m + 1 {
|
||||||
|
let si = &s[i];
|
||||||
|
let aij = &a[(i, j)];
|
||||||
|
|
||||||
|
for ii in 0..d {
|
||||||
|
for jj in 0..d {
|
||||||
|
let p = (aij[ii] as i128) * si[jj] as i128;
|
||||||
|
if ii + jj < d {
|
||||||
|
polymul[ii + jj] += p;
|
||||||
|
} else {
|
||||||
|
polymul[ii + jj - d] -= p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((ck, rk), old_ck) in zip(zip(c, r), &polymul) {
|
||||||
|
let q = if q == 0 { q as i128 } else { 1i128 << 64 };
|
||||||
|
let mut new_ck = old_ck.rem_euclid(q);
|
||||||
|
if new_ck >= q / 2 {
|
||||||
|
new_ck -= q;
|
||||||
|
}
|
||||||
|
assert!((old_ck - new_ck) % q == 0);
|
||||||
|
assert!((*rk).unsigned_abs() < b_r);
|
||||||
|
|
||||||
|
*ck = new_ck as i64;
|
||||||
|
*rk = ((old_ck - new_ck) / q) as i64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let w_tilde = Iterator::chain(
|
||||||
|
(1..big_m + 1).flat_map(|i| {
|
||||||
|
s[i].iter()
|
||||||
|
.copied()
|
||||||
|
.flat_map(|x| bit_iter(x as u64, b_i.ilog2() + 1))
|
||||||
|
}),
|
||||||
|
(1..big_n + 1).flat_map(|i| {
|
||||||
|
r[i].iter()
|
||||||
|
.copied()
|
||||||
|
.flat_map(|x| bit_iter(x as u64, b_r.ilog2() + 1))
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.collect::<Box<_>>();
|
||||||
|
let mut w = vec![false; n].into_boxed_slice();
|
||||||
|
w[..big_d].copy_from_slice(&w_tilde);
|
||||||
|
let w = OneBased::new_ref(&*w);
|
||||||
|
|
||||||
|
let mut c_hat = g_hat.mul_scalar(gamma);
|
||||||
|
for j in 1..big_d + 1 {
|
||||||
|
let term = if w[j] { g_hat_list[j] } else { G::G2::ZERO };
|
||||||
|
c_hat += term;
|
||||||
|
}
|
||||||
|
|
||||||
|
let x_bytes = &*[
|
||||||
|
&q.to_le_bytes(),
|
||||||
|
&(d as u64).to_le_bytes(),
|
||||||
|
&(big_m as u64).to_le_bytes(),
|
||||||
|
&(big_n as u64).to_le_bytes(),
|
||||||
|
&b_i.to_le_bytes(),
|
||||||
|
&*(1..big_m + 1)
|
||||||
|
.flat_map(|i| {
|
||||||
|
(1..big_n + 1).flat_map(move |j| a[(i, j)].iter().flat_map(|ai| ai.to_le_bytes()))
|
||||||
|
})
|
||||||
|
.collect::<Box<_>>(),
|
||||||
|
&(1..big_n + 1)
|
||||||
|
.flat_map(|j| c[j].iter().flat_map(|ci| ci.to_le_bytes()))
|
||||||
|
.collect::<Box<_>>(),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.flatten()
|
||||||
|
.copied()
|
||||||
|
.collect::<Box<_>>();
|
||||||
|
|
||||||
|
let mut y = vec![G::Zp::ZERO; n];
|
||||||
|
G::Zp::hash(&mut y, &[x_bytes, c_hat.to_bytes().as_ref()]);
|
||||||
|
let y = OneBased(y);
|
||||||
|
|
||||||
|
let scalars = (n + 1 - big_d..n + 1)
|
||||||
|
.map(|j| (y[n + 1 - j] * G::Zp::from_u64(w[n + 1 - j] as u64)))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let c_y = g.mul_scalar(gamma_y) + G::G1::multi_mul_scalar(&g_list.0[n - big_d..n], &scalars);
|
||||||
|
|
||||||
|
let mut t = vec![G::Zp::ZERO; n];
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut t,
|
||||||
|
&[
|
||||||
|
&(1..n + 1)
|
||||||
|
.flat_map(|i| y[i].to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<_>>(),
|
||||||
|
x_bytes,
|
||||||
|
c_hat.to_bytes().as_ref(),
|
||||||
|
c_y.to_bytes().as_ref(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let t = OneBased(t);
|
||||||
|
|
||||||
|
let mut theta_bar = vec![G::Zp::ZERO; big_n * d + 1];
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut theta_bar,
|
||||||
|
&[x_bytes, c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref()],
|
||||||
|
);
|
||||||
|
let theta = (0..big_n * d + 1).map(|k| theta_bar[k]).collect::<Box<_>>();
|
||||||
|
let theta0 = theta[..big_n * d].to_vec().into_boxed_slice();
|
||||||
|
let delta_theta = theta[big_n * d];
|
||||||
|
|
||||||
|
let mut t_theta = G::Zp::ZERO;
|
||||||
|
for j in 0..big_n {
|
||||||
|
let cj = &c[j + 1];
|
||||||
|
let theta0j = &theta0[j * d..][..d];
|
||||||
|
for k in 0..d {
|
||||||
|
t_theta += theta0j[k] * G::Zp::from_i64(cj[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut a_theta = vec![G::Zp::ZERO; big_d];
|
||||||
|
let b_step = 1 + b_i.ilog2() as usize;
|
||||||
|
let step = d * b_step;
|
||||||
|
for i in 0..big_m {
|
||||||
|
// a_theta_i = A_tilde_{i + 1}.T × theta0
|
||||||
|
let a_theta_i = &mut a_theta[step * i..][..step];
|
||||||
|
|
||||||
|
for j in 0..big_n {
|
||||||
|
let aij = &a[(i + 1, j + 1)];
|
||||||
|
let theta0_j = &theta0[d * j..][..d];
|
||||||
|
|
||||||
|
let mut rot_aij_theta0_j = vec![G::Zp::ZERO; d];
|
||||||
|
for p in 0..d {
|
||||||
|
let mut dot = G::Zp::ZERO;
|
||||||
|
|
||||||
|
for q in 0..d {
|
||||||
|
let a = if p <= q {
|
||||||
|
G::Zp::from_i64(aij[q - p])
|
||||||
|
} else {
|
||||||
|
-G::Zp::from_i64(aij[d + q - p])
|
||||||
|
};
|
||||||
|
dot += a * theta0_j[q];
|
||||||
|
}
|
||||||
|
|
||||||
|
rot_aij_theta0_j[p] = dot;
|
||||||
|
}
|
||||||
|
|
||||||
|
for k in 0..b_step {
|
||||||
|
let a_theta_ik = &mut a_theta_i[k..];
|
||||||
|
let mut c = G::Zp::from_u64(1 << k);
|
||||||
|
if k + 1 == b_step {
|
||||||
|
c = -c;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dst, src) in zip(a_theta_ik.iter_mut().step_by(b_step), &rot_aij_theta0_j) {
|
||||||
|
*dst = c * *src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let offset_m = step * big_m;
|
||||||
|
let b_step = 1 + b_r.ilog2() as usize;
|
||||||
|
let step = d * b_step;
|
||||||
|
for j in 0..big_n {
|
||||||
|
// a_theta_j -= q G.T theta0_j
|
||||||
|
let a_theta_j = &mut a_theta[offset_m + step * j..][..step];
|
||||||
|
let theta0_j = &theta0[d * j..][..d];
|
||||||
|
|
||||||
|
for k in 0..b_step {
|
||||||
|
let a_theta_jk = &mut a_theta_j[k..];
|
||||||
|
let mut c = -G::Zp::from_u64(1 << k) * G::Zp::from_u64(q);
|
||||||
|
if k + 1 == b_step {
|
||||||
|
c = -c;
|
||||||
|
}
|
||||||
|
for (dst, src) in zip(a_theta_jk.iter_mut().step_by(b_step), theta0_j) {
|
||||||
|
*dst = c * *src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut delta = [G::Zp::ZERO; 2];
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut delta,
|
||||||
|
&[x_bytes, c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref()],
|
||||||
|
);
|
||||||
|
let [delta_eq, delta_y] = delta;
|
||||||
|
let mut poly_0 = vec![G::Zp::ZERO; n + 1];
|
||||||
|
let mut poly_1 = vec![G::Zp::ZERO; n + 1];
|
||||||
|
let mut poly_2 = vec![G::Zp::ZERO; n + 1];
|
||||||
|
let mut poly_3 = vec![G::Zp::ZERO; n + 1];
|
||||||
|
|
||||||
|
poly_0[0] = delta_y * gamma_y;
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
poly_0[n + 1 - i] =
|
||||||
|
delta_y * (y[i] * G::Zp::from_u64(w[i] as u64)) + (delta_eq * t[i] - delta_y) * y[i];
|
||||||
|
|
||||||
|
if i < big_d + 1 {
|
||||||
|
poly_0[n + 1 - i] += delta_theta * a_theta[i - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
poly_1[0] = gamma;
|
||||||
|
for i in 1..big_d + 1 {
|
||||||
|
poly_1[i] = G::Zp::from_u64(w[i] as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
poly_2[0] = gamma_y;
|
||||||
|
for i in 1..big_d + 1 {
|
||||||
|
poly_2[n + 1 - i] = y[i] * G::Zp::from_u64(w[i] as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
poly_3[i] = delta_eq * t[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut poly = G::Zp::poly_sub(
|
||||||
|
&G::Zp::poly_mul(&poly_0, &poly_1),
|
||||||
|
&G::Zp::poly_mul(&poly_2, &poly_3),
|
||||||
|
);
|
||||||
|
|
||||||
|
if poly.len() > n + 1 {
|
||||||
|
poly[n + 1] -= t_theta * delta_theta;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pi =
|
||||||
|
g.mul_scalar(poly[0]) + G::G1::multi_mul_scalar(&g_list.0[..poly.len() - 1], &poly[1..]);
|
||||||
|
|
||||||
|
if load == ComputeLoad::Proof {
|
||||||
|
let c_hat_t = G::G2::multi_mul_scalar(&g_hat_list.0, &t.0);
|
||||||
|
let scalars = (1..n + 1)
|
||||||
|
.into_par_iter()
|
||||||
|
.map(|i| {
|
||||||
|
let i = n + 1 - i;
|
||||||
|
(delta_eq * t[i] - delta_y) * y[i]
|
||||||
|
+ if i < big_d + 1 {
|
||||||
|
delta_theta * a_theta[i - 1]
|
||||||
|
} else {
|
||||||
|
G::Zp::ZERO
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let c_h = G::G1::multi_mul_scalar(&g_list.0[..n], &scalars);
|
||||||
|
|
||||||
|
let mut z = G::Zp::ZERO;
|
||||||
|
G::Zp::hash(
|
||||||
|
core::array::from_mut(&mut z),
|
||||||
|
&[
|
||||||
|
x_bytes,
|
||||||
|
c_hat.to_bytes().as_ref(),
|
||||||
|
c_y.to_bytes().as_ref(),
|
||||||
|
pi.to_bytes().as_ref(),
|
||||||
|
c_h.to_bytes().as_ref(),
|
||||||
|
c_hat_t.to_bytes().as_ref(),
|
||||||
|
&y.0.iter()
|
||||||
|
.flat_map(|x| x.to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<[_]>>(),
|
||||||
|
&t.0.iter()
|
||||||
|
.flat_map(|x| x.to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<[_]>>(),
|
||||||
|
&delta
|
||||||
|
.iter()
|
||||||
|
.flat_map(|x| x.to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<[_]>>(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut pow = z;
|
||||||
|
let mut p_t = G::Zp::ZERO;
|
||||||
|
let mut p_h = G::Zp::ZERO;
|
||||||
|
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
p_t += t[i] * pow;
|
||||||
|
if n - i < big_d {
|
||||||
|
p_h += ((delta_eq * t[n + 1 - i] - delta_y) * y[n + 1 - i]
|
||||||
|
+ delta_theta * a_theta[n - i])
|
||||||
|
* pow;
|
||||||
|
} else {
|
||||||
|
p_h += ((delta_eq * t[n + 1 - i] - delta_y) * y[n + 1 - i]) * pow;
|
||||||
|
}
|
||||||
|
pow = pow * z;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut w = G::Zp::ZERO;
|
||||||
|
G::Zp::hash(
|
||||||
|
core::array::from_mut(&mut w),
|
||||||
|
&[
|
||||||
|
x_bytes,
|
||||||
|
c_hat.to_bytes().as_ref(),
|
||||||
|
c_y.to_bytes().as_ref(),
|
||||||
|
pi.to_bytes().as_ref(),
|
||||||
|
c_h.to_bytes().as_ref(),
|
||||||
|
c_hat_t.to_bytes().as_ref(),
|
||||||
|
&y.0.iter()
|
||||||
|
.flat_map(|x| x.to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<[_]>>(),
|
||||||
|
&t.0.iter()
|
||||||
|
.flat_map(|x| x.to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<[_]>>(),
|
||||||
|
&delta
|
||||||
|
.iter()
|
||||||
|
.flat_map(|x| x.to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<[_]>>(),
|
||||||
|
z.to_bytes().as_ref(),
|
||||||
|
p_h.to_bytes().as_ref(),
|
||||||
|
p_t.to_bytes().as_ref(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut poly = vec![G::Zp::ZERO; n + 1];
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
poly[i] += w * t[i];
|
||||||
|
if i < big_d + 1 {
|
||||||
|
poly[n + 1 - i] +=
|
||||||
|
(delta_eq * t[i] - delta_y) * y[i] + delta_theta * a_theta[i - 1];
|
||||||
|
} else {
|
||||||
|
poly[n + 1 - i] += (delta_eq * t[i] - delta_y) * y[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut q = vec![G::Zp::ZERO; n];
|
||||||
|
for i in (0..n).rev() {
|
||||||
|
poly[i] = poly[i] + z * poly[i + 1];
|
||||||
|
q[i] = poly[i + 1];
|
||||||
|
poly[i + 1] = G::Zp::ZERO;
|
||||||
|
}
|
||||||
|
let pi_kzg = g.mul_scalar(q[0]) + G::G1::multi_mul_scalar(&g_list.0[..n - 1], &q[1..n]);
|
||||||
|
|
||||||
|
Proof {
|
||||||
|
c_hat,
|
||||||
|
c_y,
|
||||||
|
pi,
|
||||||
|
c_hat_t: Some(c_hat_t),
|
||||||
|
c_h: Some(c_h),
|
||||||
|
pi_kzg: Some(pi_kzg),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Proof {
|
||||||
|
c_hat,
|
||||||
|
c_y,
|
||||||
|
pi,
|
||||||
|
c_hat_t: None,
|
||||||
|
c_h: None,
|
||||||
|
pi_kzg: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::result_unit_err)]
|
||||||
|
pub fn verify<G: Curve>(
|
||||||
|
proof: &Proof<G>,
|
||||||
|
public: (&PublicParams<G>, &PublicCommit<G>),
|
||||||
|
) -> Result<(), ()> {
|
||||||
|
let &Proof {
|
||||||
|
c_hat,
|
||||||
|
c_y,
|
||||||
|
pi,
|
||||||
|
c_hat_t,
|
||||||
|
c_h,
|
||||||
|
pi_kzg,
|
||||||
|
} = proof;
|
||||||
|
let e = G::Gt::pairing;
|
||||||
|
|
||||||
|
let &PublicParams {
|
||||||
|
ref g_lists,
|
||||||
|
d,
|
||||||
|
big_n,
|
||||||
|
big_m,
|
||||||
|
b_i,
|
||||||
|
q,
|
||||||
|
} = public.0;
|
||||||
|
let g_list = &g_lists.g_list;
|
||||||
|
let g_hat_list = &g_lists.g_hat_list;
|
||||||
|
|
||||||
|
let b_r = ((d * big_m) as u64 * b_i) / 2;
|
||||||
|
let big_d = d * (big_m * (1 + b_i.ilog2() as usize) + (big_n * (1 + b_r.ilog2() as usize)));
|
||||||
|
let n = big_d + 1;
|
||||||
|
|
||||||
|
let a = &public.1.a;
|
||||||
|
let c = &public.1.c;
|
||||||
|
|
||||||
|
let x_bytes = &*[
|
||||||
|
&q.to_le_bytes(),
|
||||||
|
&(d as u64).to_le_bytes(),
|
||||||
|
&(big_m as u64).to_le_bytes(),
|
||||||
|
&(big_n as u64).to_le_bytes(),
|
||||||
|
&b_i.to_le_bytes(),
|
||||||
|
&*(1..big_m + 1)
|
||||||
|
.flat_map(|i| {
|
||||||
|
(1..big_n + 1).flat_map(move |j| a[(i, j)].iter().flat_map(|ai| ai.to_le_bytes()))
|
||||||
|
})
|
||||||
|
.collect::<Box<_>>(),
|
||||||
|
&(1..big_n + 1)
|
||||||
|
.flat_map(|j| c[j].iter().flat_map(|ci| ci.to_le_bytes()))
|
||||||
|
.collect::<Box<_>>(),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.flatten()
|
||||||
|
.copied()
|
||||||
|
.collect::<Box<_>>();
|
||||||
|
|
||||||
|
let mut delta = [G::Zp::ZERO; 2];
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut delta,
|
||||||
|
&[x_bytes, c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref()],
|
||||||
|
);
|
||||||
|
let [delta_eq, delta_y] = delta;
|
||||||
|
|
||||||
|
let mut y = vec![G::Zp::ZERO; n];
|
||||||
|
G::Zp::hash(&mut y, &[x_bytes, c_hat.to_bytes().as_ref()]);
|
||||||
|
let y = OneBased(y);
|
||||||
|
|
||||||
|
let mut t = vec![G::Zp::ZERO; n];
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut t,
|
||||||
|
&[
|
||||||
|
&(1..n + 1)
|
||||||
|
.flat_map(|i| y[i].to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<_>>(),
|
||||||
|
x_bytes,
|
||||||
|
c_hat.to_bytes().as_ref(),
|
||||||
|
c_y.to_bytes().as_ref(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let t = OneBased(t);
|
||||||
|
|
||||||
|
let mut theta_bar = vec![G::Zp::ZERO; big_n * d + 1];
|
||||||
|
G::Zp::hash(
|
||||||
|
&mut theta_bar,
|
||||||
|
&[x_bytes, c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref()],
|
||||||
|
);
|
||||||
|
let theta = (0..big_n * d + 1).map(|k| theta_bar[k]).collect::<Box<_>>();
|
||||||
|
let theta0 = theta[..big_n * d].to_vec().into_boxed_slice();
|
||||||
|
let delta_theta = theta[big_n * d];
|
||||||
|
|
||||||
|
let mut t_theta = G::Zp::ZERO;
|
||||||
|
for j in 0..big_n {
|
||||||
|
let cj = &c[j + 1];
|
||||||
|
let theta0j = &theta0[j * d..][..d];
|
||||||
|
for k in 0..d {
|
||||||
|
t_theta += theta0j[k] * G::Zp::from_i64(cj[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut a_theta = vec![G::Zp::ZERO; big_d];
|
||||||
|
let b_step = 1 + b_i.ilog2() as usize;
|
||||||
|
let step = d * b_step;
|
||||||
|
for i in 0..big_m {
|
||||||
|
// a_theta_i = A_tilde_{i + 1}.T × theta0
|
||||||
|
let a_theta_i = &mut a_theta[step * i..][..step];
|
||||||
|
|
||||||
|
for j in 0..big_n {
|
||||||
|
let aij = &a[(i + 1, j + 1)];
|
||||||
|
let theta0_j = &theta0[d * j..][..d];
|
||||||
|
|
||||||
|
let mut rot_aij_theta0_j = vec![G::Zp::ZERO; d];
|
||||||
|
for p in 0..d {
|
||||||
|
let mut dot = G::Zp::ZERO;
|
||||||
|
|
||||||
|
for q in 0..d {
|
||||||
|
let a = if p <= q {
|
||||||
|
G::Zp::from_i64(aij[q - p])
|
||||||
|
} else {
|
||||||
|
-G::Zp::from_i64(aij[d + q - p])
|
||||||
|
};
|
||||||
|
dot += a * theta0_j[q];
|
||||||
|
}
|
||||||
|
|
||||||
|
rot_aij_theta0_j[p] = dot;
|
||||||
|
}
|
||||||
|
|
||||||
|
for k in 0..b_step {
|
||||||
|
let a_theta_ik = &mut a_theta_i[k..];
|
||||||
|
let mut c = G::Zp::from_u64(1 << k);
|
||||||
|
if k + 1 == b_step {
|
||||||
|
c = -c;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dst, src) in zip(a_theta_ik.iter_mut().step_by(b_step), &rot_aij_theta0_j) {
|
||||||
|
*dst = c * *src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let offset_m = step * big_m;
|
||||||
|
let b_step = 1 + b_r.ilog2() as usize;
|
||||||
|
let step = d * b_step;
|
||||||
|
for j in 0..big_n {
|
||||||
|
// a_theta_j -= q G.T theta0_j
|
||||||
|
let a_theta_j = &mut a_theta[offset_m + step * j..][..step];
|
||||||
|
let theta0_j = &theta0[d * j..][..d];
|
||||||
|
|
||||||
|
for k in 0..b_step {
|
||||||
|
let a_theta_jk = &mut a_theta_j[k..];
|
||||||
|
let mut c = -G::Zp::from_u64(1 << k) * G::Zp::from_u64(q);
|
||||||
|
if k + 1 == b_step {
|
||||||
|
c = -c;
|
||||||
|
}
|
||||||
|
for (dst, src) in zip(a_theta_jk.iter_mut().step_by(b_step), theta0_j) {
|
||||||
|
*dst = c * *src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let (Some(pi_kzg), Some(c_hat_t), Some(c_h)) = (pi_kzg, c_hat_t, c_h) {
|
||||||
|
let mut z = G::Zp::ZERO;
|
||||||
|
G::Zp::hash(
|
||||||
|
core::array::from_mut(&mut z),
|
||||||
|
&[
|
||||||
|
x_bytes,
|
||||||
|
c_hat.to_bytes().as_ref(),
|
||||||
|
c_y.to_bytes().as_ref(),
|
||||||
|
pi.to_bytes().as_ref(),
|
||||||
|
c_h.to_bytes().as_ref(),
|
||||||
|
c_hat_t.to_bytes().as_ref(),
|
||||||
|
&y.0.iter()
|
||||||
|
.flat_map(|x| x.to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<[_]>>(),
|
||||||
|
&t.0.iter()
|
||||||
|
.flat_map(|x| x.to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<[_]>>(),
|
||||||
|
&delta
|
||||||
|
.iter()
|
||||||
|
.flat_map(|x| x.to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<[_]>>(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut pow = z;
|
||||||
|
let mut p_t = G::Zp::ZERO;
|
||||||
|
let mut p_h = G::Zp::ZERO;
|
||||||
|
|
||||||
|
for i in 1..n + 1 {
|
||||||
|
p_t += t[i] * pow;
|
||||||
|
if n - i < big_d {
|
||||||
|
p_h += ((delta_eq * t[n + 1 - i] - delta_y) * y[n + 1 - i]
|
||||||
|
+ delta_theta * a_theta[n - i])
|
||||||
|
* pow;
|
||||||
|
} else {
|
||||||
|
p_h += ((delta_eq * t[n + 1 - i] - delta_y) * y[n + 1 - i]) * pow;
|
||||||
|
}
|
||||||
|
pow = pow * z;
|
||||||
|
}
|
||||||
|
|
||||||
|
if e(pi, G::G2::GENERATOR)
|
||||||
|
!= e(c_y.mul_scalar(delta_y) + c_h, c_hat)
|
||||||
|
- e(c_y.mul_scalar(delta_eq), c_hat_t)
|
||||||
|
- e(g_list[1], g_hat_list[n]).mul_scalar(t_theta * delta_theta)
|
||||||
|
{
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut w = G::Zp::ZERO;
|
||||||
|
G::Zp::hash(
|
||||||
|
core::array::from_mut(&mut w),
|
||||||
|
&[
|
||||||
|
x_bytes,
|
||||||
|
c_hat.to_bytes().as_ref(),
|
||||||
|
c_y.to_bytes().as_ref(),
|
||||||
|
pi.to_bytes().as_ref(),
|
||||||
|
c_h.to_bytes().as_ref(),
|
||||||
|
c_hat_t.to_bytes().as_ref(),
|
||||||
|
&y.0.iter()
|
||||||
|
.flat_map(|x| x.to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<[_]>>(),
|
||||||
|
&t.0.iter()
|
||||||
|
.flat_map(|x| x.to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<[_]>>(),
|
||||||
|
&delta
|
||||||
|
.iter()
|
||||||
|
.flat_map(|x| x.to_bytes().as_ref().to_vec())
|
||||||
|
.collect::<Box<[_]>>(),
|
||||||
|
z.to_bytes().as_ref(),
|
||||||
|
p_h.to_bytes().as_ref(),
|
||||||
|
p_t.to_bytes().as_ref(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
if e(c_h - G::G1::GENERATOR.mul_scalar(p_h), G::G2::GENERATOR)
|
||||||
|
+ e(G::G1::GENERATOR, c_hat_t - G::G2::GENERATOR.mul_scalar(p_t)).mul_scalar(w)
|
||||||
|
== e(pi_kzg, g_hat_list[1] - G::G2::GENERATOR.mul_scalar(z))
|
||||||
|
{
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let (term0, term1) = rayon::join(
|
||||||
|
|| {
|
||||||
|
let p = c_y.mul_scalar(delta_y)
|
||||||
|
+ (1..n + 1)
|
||||||
|
.into_par_iter()
|
||||||
|
.map(|i| {
|
||||||
|
let mut factor = (delta_eq * t[i] - delta_y) * y[i];
|
||||||
|
if i < big_d + 1 {
|
||||||
|
factor += delta_theta * a_theta[i - 1];
|
||||||
|
}
|
||||||
|
g_list[n + 1 - i].mul_scalar(factor)
|
||||||
|
})
|
||||||
|
.sum::<G::G1>();
|
||||||
|
let q = c_hat;
|
||||||
|
e(p, q)
|
||||||
|
},
|
||||||
|
|| {
|
||||||
|
let p = c_y;
|
||||||
|
let q = (1..n + 1)
|
||||||
|
.into_par_iter()
|
||||||
|
.map(|i| g_hat_list[i].mul_scalar(delta_eq * t[i]))
|
||||||
|
.sum::<G::G2>();
|
||||||
|
e(p, q)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let term2 = {
|
||||||
|
let p = g_list[1];
|
||||||
|
let q = g_hat_list[n];
|
||||||
|
e(p, q)
|
||||||
|
};
|
||||||
|
|
||||||
|
let lhs = e(pi, G::G2::GENERATOR);
|
||||||
|
let rhs = term0 - term1 - term2.mul_scalar(t_theta * delta_theta);
|
||||||
|
|
||||||
|
if lhs == rhs {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use rand::rngs::StdRng;
|
||||||
|
use rand::{Rng, SeedableRng};
|
||||||
|
|
||||||
|
fn time<R>(f: impl FnOnce() -> R) -> R {
|
||||||
|
let time = std::time::Instant::now();
|
||||||
|
let r = f();
|
||||||
|
println!("{:?}", time.elapsed());
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rlwe() {
|
||||||
|
let rng = &mut StdRng::seed_from_u64(0);
|
||||||
|
let d: usize = 2048;
|
||||||
|
let big_m: usize = 1;
|
||||||
|
let big_n: usize = 1;
|
||||||
|
|
||||||
|
let q = 1217;
|
||||||
|
let b_i: u64 = 512;
|
||||||
|
|
||||||
|
let mut a = Matrix::new(d, big_m, big_n, 0i64);
|
||||||
|
let mut c = Vector::new(d, big_n, 0i64);
|
||||||
|
let mut s = Vector::new(d, big_m, 0i64);
|
||||||
|
|
||||||
|
for i in 0..big_m {
|
||||||
|
for k in 0..d {
|
||||||
|
s[i + 1][k] = (rng.gen::<u64>() % (2 * b_i)) as i64 - b_i as i64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..big_m {
|
||||||
|
for j in 0..big_n {
|
||||||
|
for k in 0..d {
|
||||||
|
let mut x = (rng.gen::<u64>() % q) as i64;
|
||||||
|
if x >= q as i64 / 2 {
|
||||||
|
x -= q as i64;
|
||||||
|
}
|
||||||
|
a[(i + 1, j + 1)][k] = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for j in 1..big_n + 1 {
|
||||||
|
let c = &mut c[j];
|
||||||
|
|
||||||
|
let mut polymul = vec![0i128; d];
|
||||||
|
for i in 1..big_m + 1 {
|
||||||
|
let si = &s[i];
|
||||||
|
let aij = &a[(i, j)];
|
||||||
|
|
||||||
|
for ii in 0..d {
|
||||||
|
for jj in 0..d {
|
||||||
|
let p = (aij[ii] as i128) * si[jj] as i128;
|
||||||
|
if ii + jj < d {
|
||||||
|
polymul[ii + jj] += p;
|
||||||
|
} else {
|
||||||
|
polymul[ii + jj - d] -= p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ck, old_ck) in core::iter::zip(c, &polymul) {
|
||||||
|
let q = if q == 0 { q as i128 } else { 1i128 << 64 };
|
||||||
|
let mut new_ck = old_ck.rem_euclid(q);
|
||||||
|
if new_ck >= q / 2 {
|
||||||
|
new_ck -= q;
|
||||||
|
}
|
||||||
|
*ck = new_ck as i64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let public_params = crs_gen::<crate::curve_api::Bls12_446>(d, big_n, big_m, b_i, q, rng);
|
||||||
|
let (public_commit, private_commit) = commit(a, c, s, &public_params, rng);
|
||||||
|
for load in [ComputeLoad::Proof, ComputeLoad::Verify] {
|
||||||
|
let proof =
|
||||||
|
time(|| prove((&public_params, &public_commit), &private_commit, load, rng));
|
||||||
|
let verify = time(|| verify(&proof, (&public_params, &public_commit)));
|
||||||
|
assert!(verify.is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user