Skip to content

Commit

Permalink
secp256r1: ecdsa sig verify
Browse files Browse the repository at this point in the history
  • Loading branch information
0x0ece committed Nov 27, 2024
1 parent a4239a5 commit 767eafb
Show file tree
Hide file tree
Showing 5 changed files with 1,932 additions and 35 deletions.
44 changes: 34 additions & 10 deletions src/ballet/secp256r1/fd_secp256r1.c
Original file line number Diff line number Diff line change
@@ -1,21 +1,45 @@
#include "fd_secp256r1.h"

#include <stdint.h>
#include <s2n-bignum.h>
#include "fd_secp256r1_private.h"

int
fd_secp256r1_verify( uchar const msg[], /* msg_sz */
ulong msg_sz,
uchar const sig[ 64 ],
uchar const public_key[ 33 ],
fd_sha256_t * sha ) {
(void)msg;
(void)msg_sz;
(void)sig;
(void)public_key;
(void)sha;
fd_secp256r1_scalar_t r[1], s[1], u1[1], u2[1];
fd_secp256r1_point_t pub[1], Rcmp[1];

/* Deserialize signature.
Note: we enforce 0 < r < n, 0 < s <= (n-1)/2.
The condition on s is required to avoid signature malleability. */
if( FD_UNLIKELY( !fd_secp256r1_scalar_frombytes( r, sig ) ) ) {
return FD_SECP256R1_FAILURE;
}
if( FD_UNLIKELY( !fd_secp256r1_scalar_frombytes_positive( s, sig+32 ) ) ) {
return FD_SECP256R1_FAILURE;
}
if( FD_UNLIKELY( fd_secp256r1_scalar_is_zero( r ) || fd_secp256r1_scalar_is_zero( s ) ) ) {
return FD_SECP256R1_FAILURE;
}

/* Deserialize public key. */
if( FD_UNLIKELY( !fd_secp256r1_point_frombytes( pub, public_key ) ) ) {
return FD_SECP256R1_FAILURE;
}

/* Hash message. */
uchar hash[ FD_SHA256_HASH_SZ ];
fd_sha256_fini( fd_sha256_append( fd_sha256_init( sha ), msg, msg_sz ), hash );
fd_secp256r1_scalar_from_digest( u1, hash );

//TODO
/* ECDSA sig verify. */
fd_secp256r1_scalar_inv( s, s );
fd_secp256r1_scalar_mul( u1, u1, s );
fd_secp256r1_scalar_mul( u2, r, s );
fd_secp256r1_double_scalar_mul_base( Rcmp, u1, pub, u2 );
if( FD_LIKELY( fd_secp256r1_point_eq_x( Rcmp, r ) ) ) {
return FD_SECP256R1_SUCCESS;
}

return FD_SECP256R1_FAILURE;
}
75 changes: 75 additions & 0 deletions src/ballet/secp256r1/fd_secp256r1_private.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#ifndef HEADER_fd_src_ballet_secp256r1_fd_secp256r1_private_h
#define HEADER_fd_src_ballet_secp256r1_fd_secp256r1_private_h

/* fd_secp256r1 provides APIs for secp256r1 signature verification. */

#include "fd_secp256r1.h"
#include "../bigint/fd_uint256.h"

FD_PROTOTYPES_BEGIN

/* Field element: uint256 */
typedef fd_uint256_t fd_secp256r1_fp_t;

/* Scalar field element: uint256 */
typedef fd_uint256_t fd_secp256r1_scalar_t;

/* Point, in Jacobian coordinates (X : Y : Z).
These correspond to affine x=X/Z^2, y=Y/Z^3.
Field elements are in Montgomery form. */
struct fd_secp256r1_point {
fd_secp256r1_fp_t x[1];
fd_secp256r1_fp_t y[1];
fd_secp256r1_fp_t z[1];
};
typedef struct fd_secp256r1_point fd_secp256r1_point_t;

/* const 0. */
static const fd_uint256_t fd_secp256r1_const_zero[1] = {{{
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
}}};

/* const p, used to validate a field element.
NOT Montgomery.
0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff */
static const fd_secp256r1_fp_t fd_secp256r1_const_p[1] = {{{
0xffffffffffffffff, 0x00000000ffffffff, 0x0000000000000000, 0xffffffff00000001,
}}};

/* const 1. Montgomery.
0x00000000fffffffeffffffffffffffffffffffff000000000000000000000001 */
static const fd_secp256r1_fp_t fd_secp256r1_const_one_mont[1] = {{{
0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff, 0x00000000fffffffe,
}}};

/* const a=-3, in curve equation y^2 = x^3 + ax + b. Montgomery.
0xfffffffc00000004000000000000000000000003fffffffffffffffffffffffc */
static const fd_secp256r1_fp_t fd_secp256r1_const_a_mont[1] = {{{
0xfffffffffffffffc, 0x00000003ffffffff, 0x0000000000000000, 0xfffffffc00000004,
}}};

/* const b, in curve equation y^2 = x^3 + ax + b. Montgomery.
0xdc30061d04874834e5a220abf7212ed6acf005cd78843090d89cdf6229c4bddf */
static const fd_secp256r1_fp_t fd_secp256r1_const_b_mont[1] = {{{
0xd89cdf6229c4bddf, 0xacf005cd78843090, 0xe5a220abf7212ed6, 0xdc30061d04874834
}}};

/* const n, used to validate a scalar field element.
NOT Montgomery.
0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 */
static const fd_secp256r1_scalar_t fd_secp256r1_const_n[1] = {{{
0xf3b9cac2fc632551, 0xbce6faada7179e84, 0xffffffffffffffff, 0xffffffff00000000,
}}};

/* const (n-1)/2, used to validate a signature s component.
NOT Montgomery.
0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8 */
static const fd_secp256r1_scalar_t fd_secp256r1_const_n_m1_half[1] = {{{
0x79dce5617e3192a8, 0xde737d56d38bcf42, 0x7fffffffffffffff, 0x7fffffff80000000,
}}};

FD_PROTOTYPES_END

#include "fd_secp256r1_s2n.c"

#endif /* HEADER_fd_src_ballet_secp256r1_fd_secp256r1_private_h */
194 changes: 194 additions & 0 deletions src/ballet/secp256r1/fd_secp256r1_s2n.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
#include "fd_secp256r1_private.h"
#include <stdint.h>
#include <s2n-bignum.h>

#include "fd_secp256r1_table.c"

/* Scalars */

static inline int
fd_secp256r1_scalar_is_zero( fd_secp256r1_scalar_t const * a ) {
return fd_uint256_eq( a, fd_secp256r1_const_zero );
}

static inline fd_secp256r1_scalar_t *
fd_secp256r1_scalar_frombytes( fd_secp256r1_scalar_t * r,
uchar const in[ 32 ] ) {
memcpy( r, in, 32 );
fd_uint256_bswap( r, r );
if( FD_LIKELY( fd_uint256_cmp( r, fd_secp256r1_const_n )<0 ) ) {
return r;
};
return NULL;
}

static inline fd_secp256r1_scalar_t *
fd_secp256r1_scalar_frombytes_positive( fd_secp256r1_scalar_t * r,
uchar const in[ 32 ] ) {
memcpy( r, in, 32 );
fd_uint256_bswap( r, r );
if( FD_LIKELY( fd_uint256_cmp( r, fd_secp256r1_const_n_m1_half )<=0 ) ) {
return r;
};
return NULL;
}

static inline void
fd_secp256r1_scalar_from_digest( fd_secp256r1_scalar_t * r,
uchar const in[ 32 ] ) {
memcpy( r, in, 32 );
fd_uint256_bswap( r, r );
bignum_mod_n256_4( r->limbs, r->limbs );
}

static inline fd_secp256r1_scalar_t *
fd_secp256r1_scalar_mul( fd_secp256r1_scalar_t * r,
fd_secp256r1_scalar_t const * a,
fd_secp256r1_scalar_t const * b ) {
ulong t[ 8 ];
bignum_mul_4_8( t, (ulong *)a->limbs, (ulong *)b->limbs );
bignum_mod_n256( r->limbs, 8, t );
return r;
}

static inline fd_secp256r1_scalar_t *
fd_secp256r1_scalar_inv( fd_secp256r1_scalar_t * r,
fd_secp256r1_scalar_t const * a ) {
ulong t[ 12 ];
bignum_modinv( 4, r->limbs, (ulong *)a->limbs, (ulong *)fd_secp256r1_const_n[0].limbs, t );
return r;
}

/* Field */

static inline fd_secp256r1_fp_t *
fd_secp256r1_fp_set( fd_secp256r1_fp_t * r,
fd_secp256r1_fp_t const * a ) {
r->limbs[0] = a->limbs[0];
r->limbs[1] = a->limbs[1];
r->limbs[2] = a->limbs[2];
r->limbs[3] = a->limbs[3];
return r;
}

static inline fd_secp256r1_fp_t *
fd_secp256r1_fp_frombytes( fd_secp256r1_fp_t * r,
uchar const in[ 32 ] ) {
memcpy( r, in, 32 );
fd_uint256_bswap( r, r );
if( FD_LIKELY( fd_uint256_cmp( r, fd_secp256r1_const_p )<0 ) ) {
return r;
};
return NULL;
}

static inline fd_secp256r1_fp_t *
fd_secp256r1_fp_sqrt( fd_secp256r1_fp_t * r,
fd_secp256r1_fp_t const * a ) {
/* https://github.com/golang/go/blob/master/src/crypto/internal/fips140/nistec/p256.go#L656 */
fd_secp256r1_fp_t _t0[1], _t1[1];
ulong * t0 = _t0->limbs;
ulong * t1 = _t1->limbs;
ulong * x = (ulong *)a->limbs;

bignum_montsqr_p256( t0, x );
bignum_montmul_p256( t0, t0, x );
bignum_montsqr_p256( t1, t0 ); for( int i=1; i<2; i++ ) bignum_montsqr_p256( t1, t1 );
bignum_montmul_p256( t0, t0, t1);
bignum_montsqr_p256( t1, t0 ); for( int i=1; i<4; i++ ) bignum_montsqr_p256( t1, t1 );
bignum_montmul_p256( t0, t0, t1);
bignum_montsqr_p256( t1, t0 ); for( int i=1; i<8; i++ ) bignum_montsqr_p256( t1, t1 );
bignum_montmul_p256( t0, t0, t1);
bignum_montsqr_p256( t1, t0 ); for( int i=1; i<16; i++ ) bignum_montsqr_p256( t1, t1 );
bignum_montmul_p256( t0, t0, t1);
for( int i=0; i<32; i++ ) bignum_montsqr_p256( t0, t0 );
bignum_montmul_p256( t0, t0, x );
for( int i=0; i<96; i++ ) bignum_montsqr_p256( t0, t0 );
bignum_montmul_p256( t0, t0, x );
for( int i=0; i<94; i++ ) bignum_montsqr_p256( t0, t0 );

bignum_montsqr_p256( t1, t0 );
if( FD_UNLIKELY( !fd_uint256_eq( _t1, a ) ) ) {
return NULL;
}

return fd_secp256r1_fp_set( r, _t0 );
}

/* Points */

static inline fd_secp256r1_point_t *
fd_secp256r1_point_frombytes( fd_secp256r1_point_t * r,
uchar const in[ 33 ] ) {
fd_secp256r1_fp_t y2[1], neg_y[1];

uchar sgn = in[0];
if( FD_UNLIKELY( sgn!=2U && sgn!=3U ) ) {
return FD_SECP256R1_FAILURE;
}

if( FD_UNLIKELY( !fd_secp256r1_fp_frombytes( r->x, in+1 ) ) ) {
return FD_SECP256R1_FAILURE;
}

bignum_tomont_p256( r->x->limbs, r->x->limbs );

/* y^2 = x^3 + ax + b */
bignum_montsqr_p256( y2->limbs, r->x->limbs );
bignum_add_p256 ( y2->limbs, y2->limbs, (ulong *)fd_secp256r1_const_a_mont[0].limbs );
bignum_montmul_p256( y2->limbs, y2->limbs, r->x->limbs );
bignum_add_p256 ( y2->limbs, y2->limbs, (ulong *)fd_secp256r1_const_b_mont[0].limbs );

/* y = sqrt(y^2) */
if( FD_UNLIKELY( !fd_secp256r1_fp_sqrt( r->y, y2 ) ) ) {
return FD_SECP256R1_FAILURE;
}

/* choose y or -y */
bignum_neg_p256( neg_y->limbs, r->y->limbs );
ulong cond = fd_uint256_cmp( neg_y, r->y ) == (sgn == 2 ? -1 : 1);
bignum_mux_4( cond, r->y->limbs, r->y->limbs, neg_y->limbs );

fd_secp256r1_fp_set( r->z, fd_secp256r1_const_one_mont );

return r;
}

static inline int
fd_secp256r1_point_eq_x( fd_secp256r1_point_t const * p,
fd_secp256r1_scalar_t const * r ) {
fd_secp256r1_fp_t affine_x[1];
fd_secp256r1_scalar_t * affine_x_mod_n = affine_x;

if( FD_UNLIKELY( fd_uint256_eq( p->z, fd_secp256r1_const_zero ) ) ) {
return FD_SECP256R1_FAILURE;
}

/* x = demont(X / Z^2) mod n */
bignum_montinv_p256( affine_x->limbs, (ulong *)p->z->limbs );
bignum_montsqr_p256( affine_x->limbs, affine_x->limbs );
bignum_montmul_p256( affine_x->limbs, affine_x->limbs, (ulong *)p->x->limbs );
bignum_demont_p256( affine_x_mod_n->limbs, affine_x->limbs );
bignum_mod_n256_4 ( affine_x_mod_n->limbs, affine_x_mod_n->limbs );

if( FD_LIKELY( fd_uint256_eq( r, affine_x_mod_n ) ) ) {
return FD_SECP256R1_SUCCESS;
}
return FD_SECP256R1_FAILURE;
}

static inline void
fd_secp256r1_double_scalar_mul_base( fd_secp256r1_point_t * r,
fd_secp256r1_scalar_t const * u1,
fd_secp256r1_point_t const * a,
fd_secp256r1_scalar_t const * u2 ) {
/* u1*G + u2*A */
ulong rtmp[ 8 ];
p256_scalarmulbase( rtmp, (ulong *)u1->limbs, 6, (ulong *)fd_secp256r1_base_point_table );
bignum_tomont_p256( rtmp, rtmp );
bignum_tomont_p256( rtmp+4, rtmp+4 );

p256_montjscalarmul( (ulong *)r, (ulong *)u2->limbs, (ulong *)a );

p256_montjmixadd( (ulong *)r, (ulong *)r, rtmp );
}
Loading

0 comments on commit 767eafb

Please sign in to comment.