Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions benches/bench_csidh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,32 @@ mod benchmark_csidh {

fn benchmark_action(c: &mut Criterion) {
let mut rng = DRNG::from_seed("csidh_action".as_bytes());
let bench_id = format!("Benchmarking Action for CSIDH-512 Parameters",);
let bench_id = format!("Action for CSIDH-512 Parameters",);

let (alice_sk, alice_pk) = CSIDH_512.keygen(&mut rng);

// for simplicity, we just use alice pk and sk
c.bench_function(&bench_id, |b| {
b.iter(|| CSIDH_512.derive_shared_key(&alice_pk, &alice_sk, &mut rng))
b.iter(|| CSIDH_512.action(&alice_pk, &alice_sk, &mut rng))
});
}

fn benchmark_verify(c: &mut Criterion) {
let mut rng = DRNG::from_seed("csidh_action".as_bytes());
let bench_id = format!("Verify for CSIDH-512 Parameters",);

let (_, alice_pk) = CSIDH_512.keygen(&mut rng);

// for simplicity, we just use alice pk and sk
c.bench_function(&bench_id, |b| {
b.iter(|| CSIDH_512.verify(&alice_pk, &mut rng))
});
}

criterion_group! {
name = csidh_benchmarks;
config = Criterion::default().measurement_time(Duration::from_secs(15));
targets = benchmark_action,
targets = benchmark_action, benchmark_verify
}
}

Expand Down
41 changes: 21 additions & 20 deletions src/protocols/csidh.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
use std::{error::Error, usize};
use std::fmt::Display;


use fp2::traits::Fp as FqTrait;

use crate::{
elliptic::{curve::Curve, point::PointX},
polynomial_ring::poly::Polynomial,
utilities::bn::{mul_bn_by_u64_vartime, bn_compare_vartime},
utilities::bn::{Bn, mul_bn_by_u64_vartime, bn_compare_vartime},
};

use rand_core::{CryptoRng, RngCore};

#[derive(Clone, Copy, Debug)]
pub struct CsidhParameters<const NUM_ELLS: usize, const FSQRTP: usize> {
pub struct CsidhParameters<const NUM_ELLS: usize> {
pub max_exponent: usize,
pub two_cofactor: usize,
pub primes: [u64; NUM_ELLS],
pub four_sqrt_p: [u64; FSQRTP],
pub four_sqrt_p: Bn,
}

pub struct Csidh<Fp: FqTrait, const NUM_ELLS: usize, const FSQRTP: usize> {
pub struct Csidh<Fp: FqTrait, const NUM_ELLS: usize> {
max_exponent: usize,
two_cofactor: usize,
base: Fp,
primes: [u64; NUM_ELLS],
pub four_sqrt_p: [u64; FSQRTP],
four_sqrt_p: Bn,
}

pub struct CsidhPrivateKey<const NUM_ELLS: usize> {
Expand Down Expand Up @@ -60,8 +61,8 @@ impl<Fp: FqTrait> PartialEq for CsidhPublicKey<Fp> {
}
}

impl<Fp: FqTrait + std::fmt::Debug, const NUM_ELLS: usize, const FSQRTP: usize> Csidh<Fp, NUM_ELLS, FSQRTP> {
pub const fn new(params: &CsidhParameters<NUM_ELLS, FSQRTP>) -> Self {
impl<Fp: FqTrait + std::fmt::Debug, const NUM_ELLS: usize> Csidh<Fp, NUM_ELLS> {
pub const fn new(params: &CsidhParameters<NUM_ELLS>) -> Self {
Self {
max_exponent: params.max_exponent,
two_cofactor: params.two_cofactor,
Expand All @@ -87,18 +88,16 @@ impl<Fp: FqTrait + std::fmt::Debug, const NUM_ELLS: usize, const FSQRTP: usize>
let x = Fp::rand(rng);
let P = PointX::from_x_coord(&x);

// projective curve: x^3C+4Ax^2−2x^2C2+XC​
let tmp = (*A24*x)+(*A24*x);
let four_Ax = tmp+tmp;
// projective curve: x^3C+4Ax^2−2x^2C+XC​
let tmp = *A24*x;
let four_Ax = tmp+tmp+tmp+tmp;
Copy link
Owner

Choose a reason for hiding this comment

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

we have a mul4() method available in fp2_rs

let tmp = *C24*x;
let Cxx = tmp*x;
let two_Cx = tmp+tmp;
Copy link
Owner

Choose a reason for hiding this comment

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

Same here, we have a mul2()


// if RHS i a sqrt, it is on the curve
// if RHS is a sqrt, it is on the curve
let RHS = (Cxx+four_Ax-two_Cx+(*C24))*x;
let (_, is_sqrt) = RHS.sqrt();

(P, is_sqrt == u32::MAX)
(P, RHS.is_square() == u32::MAX)
}

fn sample_secret_key<R: CryptoRng + RngCore>(&self, rng: &mut R) -> CsidhPrivateKey<NUM_ELLS> {
Expand All @@ -123,9 +122,8 @@ impl<Fp: FqTrait + std::fmt::Debug, const NUM_ELLS: usize, const FSQRTP: usize>

//
// ACTION
//

fn action<R: CryptoRng + RngCore>(
//
pub fn action<R: CryptoRng + RngCore>(
&self,
public_key: &CsidhPublicKey<Fp>,
private_key: &CsidhPrivateKey<NUM_ELLS>,
Expand Down Expand Up @@ -211,7 +209,7 @@ impl<Fp: FqTrait + std::fmt::Debug, const NUM_ELLS: usize, const FSQRTP: usize>
// VERIFICATION
//

/// recursily computes [p+1/l] for all l
/// recursively computes [p+1/l] for all l (primes)
fn cofactor_multiples(&self, P : &mut [PointX<Fp>;NUM_ELLS], A24: &Fp , C24: &Fp, lower: usize, upper: usize) {
if upper - lower == 1 {
return;
Expand All @@ -236,10 +234,13 @@ impl<Fp: FqTrait + std::fmt::Debug, const NUM_ELLS: usize, const FSQRTP: usize>
self.cofactor_multiples(P, A24, C24, mid, upper);
}

fn verify<R: CryptoRng + RngCore>(&self, public_key: &CsidhPublicKey<Fp>, rng: &mut R) -> bool {

pub fn verify<R: CryptoRng + RngCore>(&self, public_key: &CsidhPublicKey<Fp>, rng: &mut R) -> bool {
let A24 = public_key.A + Fp::TWO;
let C24 = Fp::FOUR;

let fsqrtp = &self.four_sqrt_p.limbs[..self.four_sqrt_p.len];
Copy link
Owner

Choose a reason for hiding this comment

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

This looks like we might want to make a method out of it? maybe a Bn to_slice() ?


loop {
let mut P : [PointX<Fp>; NUM_ELLS] = [PointX::INFINITY ; NUM_ELLS];

Expand All @@ -266,7 +267,7 @@ impl<Fp: FqTrait + std::fmt::Debug, const NUM_ELLS: usize, const FSQRTP: usize>

// if the order of out starting Point is > 4sqrt(p), the curve must be supersingular
order = mul_bn_by_u64_vartime(&order[..], self.primes[i]);
match bn_compare_vartime(&order[..], &self.four_sqrt_p[..]) {
match bn_compare_vartime(&order[..], fsqrtp) {
std::cmp::Ordering::Greater => return true,
_ => {},
}
Expand Down
15 changes: 10 additions & 5 deletions src/protocols/csidh_parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::fields::csidh::Csidh512;

mod csidh_512 {
use crate::protocols::csidh::CsidhParameters;
use crate::utilities::bn::Bn;

pub const NUM_PRIMES: usize = 74;
const MAX_EXPONENT: usize = 5;
Expand All @@ -15,23 +16,27 @@ mod csidh_512 {
];

// not the best place for this...
pub const LEN_4SQRTP: usize = 5;
const FOUR_SQRT_P: [u64; LEN_4SQRTP] = [
const FOUR_SQRT_P: Bn = Bn { limbs : [
0x17895e71e1a20b3f,
0x38d0cd95f8636a56,
0x142b9541e59682cd,
0x856f1399d91d6592,
0x0000000000000002,
];
0x0000000000000000,
Copy link
Owner

Choose a reason for hiding this comment

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

why the extra 0x00?

0x0000000000000000,
0x0000000000000000,
], len : 5};


pub const CSIDH_PARAMS: CsidhParameters<NUM_PRIMES, LEN_4SQRTP> = CsidhParameters {
pub const CSIDH_PARAMS: CsidhParameters<NUM_PRIMES> = CsidhParameters {
max_exponent: MAX_EXPONENT,
two_cofactor: COFACTOR,
primes: PRIMES,
four_sqrt_p: FOUR_SQRT_P,
Copy link
Owner

Choose a reason for hiding this comment

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

Cant we have this value as a Fp and then avoid the need for , 5? Similar to how we have constants in the sidh impl

Copy link
Author

Choose a reason for hiding this comment

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

Yeah, this part is quite ugly.

The issue is that we need 4sqrt(p) as a bigint (bn), not as a Fp, in the verification, to check against the order of the random point.
The cleanest way would probably be to have a struct for bn.

I'll try to come up with something.

Copy link
Owner

Choose a reason for hiding this comment

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

We do we need it to be a big number? For scalar multiplication? One option would be to use a Fp element and then encode this to bytes for scalar multiplication? Another, yes, would be to make a BN type

Copy link
Author

Choose a reason for hiding this comment

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

We only use this constant to check if the order of a point is > 4sqrt(p).

Copy link
Owner

Choose a reason for hiding this comment

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

Oh I see, this is alg 2 of (https://eprint.iacr.org/2022/880.pdf)...

Copy link
Owner

Choose a reason for hiding this comment

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

I think the "best" method at the moment is have $4 \sqrt{p}$ as a Fp type in the structure and then in verify we can do something like

    bound = bytes_to_bn_vartime(&self.four_sqrt_p.encode())

where &self.four_sqrt_p.encode() will have type &[u8] and bytes_to_bn_vartime can convert from base 2^8 to base 2^64?

Copy link
Author

Choose a reason for hiding this comment

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

I ended up adding a small Bn struct as a wrapper.
Let me know what you think about this approach.
If you think it's suitable I can also extend the struct.

};
}

pub const CSIDH_512: Csidh<Csidh512, { csidh_512::NUM_PRIMES }, { csidh_512::LEN_4SQRTP}> =
pub const CSIDH_512: Csidh<Csidh512, { csidh_512::NUM_PRIMES }> =
Csidh::new(&csidh_512::CSIDH_PARAMS);


39 changes: 11 additions & 28 deletions src/utilities/bn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,31 +46,6 @@ pub fn mul_bn_by_u64_vartime(a: &[u64], b: u64) -> Vec<u64> {
res
}

pub fn div_bn_by_u64_vartime(a: &[u64], b: u64) -> Vec<u64> {
if b == 0 {
panic!("division by zero");
}

let mut result = vec![0u64; a.len()];
let mut rem: u128 = 0;

for i in (0..a.len()).rev() {
let dividend = (rem << 64) | a[i] as u128;
let q = dividend / b as u128;
rem = dividend % b as u128;
result[i] = q as u64;
}

// trim leading zeros
let mut trim_len = result.len();
while trim_len > 1 && result[trim_len - 1] == 0 {
trim_len -= 1;
}
result.truncate(trim_len);

result
}

/// Given two integers represented as u64 words (little endian) compute their
/// product.
fn mul_bn_vartime(a: &[u64], b: &[u64]) -> Vec<u64> {
Expand Down Expand Up @@ -173,14 +148,12 @@ pub fn bn_compare_vartime(x: &[u64], y: &[u64]) -> std::cmp::Ordering {
let len1 = x.len();
let len2 = y.len();

// Wenn eines der Arrays länger ist, ist es sicher größer.
if len1 > len2 {
return std::cmp::Ordering::Greater;
} else if len1 < len2 {
return std::cmp::Ordering::Less;
}

// Wenn die Längen gleich sind, vergleiche jedes Element.
for i in (0..len1).rev() {
if x[i] > y[i] {
return std::cmp::Ordering::Greater;
Expand All @@ -189,6 +162,16 @@ pub fn bn_compare_vartime(x: &[u64], y: &[u64]) -> std::cmp::Ordering {
}
}

// Wenn alle Elemente gleich sind, sind die Arrays gleich.
std::cmp::Ordering::Equal
}



// This is a small wrapper to use a bn as constant
const BN_MAXLIMBS : usize = 8;
Copy link
Owner

Choose a reason for hiding this comment

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

oooh this is why... Maybe we should use a vector and dynamically allocate? This could be refactored later I suppose though.

Copy link
Author

Choose a reason for hiding this comment

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

Vectors and constants don't like each other much.

What about putting Bn behind a macro, similar to Fp?
It's quite a bit of overhead for a single constant, but it should be the cleanest solution and might be helpful for other protocols.


#[derive(Clone, Copy, Debug)]
pub struct Bn {
pub limbs : [u64; BN_MAXLIMBS],
pub len : usize,
}