Skip to content

Commit

Permalink
Fix affine multiplication: remove skipping a last bit to generelize
Browse files Browse the repository at this point in the history
  • Loading branch information
kilic committed Jun 9, 2022
1 parent bb6e391 commit bbd4cee
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 5 deletions.
10 changes: 5 additions & 5 deletions src/derive/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,10 @@ macro_rules! new_curve_impl {
impl<'a, 'b> Mul<&'b $scalar> for &'a $name {
type Output = $name;

// This is a simple double-and-add implementation of point
// multiplication, moving from most significant to least
// significant bit of the scalar.

fn mul(self, other: &'b $scalar) -> Self::Output {
let mut acc = $name::identity();
for bit in other
Expand Down Expand Up @@ -935,21 +939,17 @@ macro_rules! new_curve_impl {
type Output = $name;

fn mul(self, other: &'b $scalar) -> Self::Output {
// TODO: make this faster

let mut acc = $name::identity();

// This is a simple double-and-add implementation of point
// multiplication, moving from most significant to least
// significant bit of the scalar.
//
// NOTE: We skip the leading bit because it's always unset.

for bit in other
.to_repr()
.iter()
.rev()
.flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
.skip(1)
{
acc = acc.double();
acc = $name::conditional_select(&acc, &(acc + self), bit);
Expand Down
59 changes: 59 additions & 0 deletions src/secp256k1/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,62 @@ impl CurveAffineExt for Secp256k1Affine {
fn test_curve() {
crate::tests::curve::curve_tests::<Secp256k1>();
}

#[test]
fn ecdsa_example() {
use crate::group::Curve;
use crate::{CurveAffine, FieldExt};
use rand_core::OsRng;

fn mod_n(x: Fp) -> Fq {
let mut x_repr = [0u8; 32];
x_repr.copy_from_slice(x.to_repr().as_ref());
let mut x_bytes = [0u8; 64];
x_bytes[..32].copy_from_slice(&x_repr[..]);
Fq::from_bytes_wide(&x_bytes)
}

let g = Secp256k1::generator();

for _ in 0..1000 {
// Generate a key pair
let sk = Fq::random(OsRng);
let pk = (g * sk).to_affine();

// Generate a valid signature
// Suppose `m_hash` is the message hash
let msg_hash = Fq::random(OsRng);

let (r, s) = {
// Draw arandomness
let k = Fq::random(OsRng);
let k_inv = k.invert().unwrap();

// Calculate `r`
let r_point = (g * k).to_affine().coordinates().unwrap();
let x = r_point.x();
let r = mod_n(*x);

// Calculate `s`
let s = k_inv * (msg_hash + (r * sk));

(r, s)
};

{
// Verify
let s_inv = s.invert().unwrap();
let u_1 = msg_hash * s_inv;
let u_2 = r * s_inv;

let v_1 = g * u_1;
let v_2 = pk * u_2;

let r_point = (v_1 + v_2).to_affine().coordinates().unwrap();
let x_candidate = r_point.x();
let r_candidate = mod_n(*x_candidate);

assert_eq!(r, r_candidate);
}
}
}

0 comments on commit bbd4cee

Please sign in to comment.