Start with Elliptic Curve point math. Slow, but it works.
This commit is contained in:
439
src/ecdsa/curve.rs
Normal file
439
src/ecdsa/curve.rs
Normal file
@@ -0,0 +1,439 @@
|
|||||||
|
use cryptonum::signed::{I192,I256,I384,I576};
|
||||||
|
use cryptonum::unsigned::{Decoder};
|
||||||
|
use cryptonum::unsigned::{U192,U256,U384,U576};
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub trait EllipticCurve {
|
||||||
|
type Unsigned : Clone;
|
||||||
|
type Signed : Clone;
|
||||||
|
|
||||||
|
fn p() -> Self::Unsigned;
|
||||||
|
fn n() -> Self::Unsigned;
|
||||||
|
fn SEED() -> Self::Unsigned;
|
||||||
|
fn c() -> Self::Unsigned;
|
||||||
|
fn a() -> Self::Unsigned;
|
||||||
|
fn b() -> Self::Unsigned;
|
||||||
|
fn Gx() -> Self::Signed;
|
||||||
|
fn Gy() -> Self::Signed;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum P192 {}
|
||||||
|
|
||||||
|
impl EllipticCurve for P192 {
|
||||||
|
type Unsigned = U192;
|
||||||
|
type Signed = I192;
|
||||||
|
|
||||||
|
fn p() -> U192 {
|
||||||
|
U192::from_bytes(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn n() -> U192 {
|
||||||
|
U192::from_bytes(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0x99, 0xde, 0xf8, 0x36,
|
||||||
|
0x14, 0x6b, 0xc9, 0xb1, 0xb4, 0xd2, 0x28, 0x31])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SEED() -> U192 {
|
||||||
|
U192::from_bytes(&[0x30, 0x45, 0xae, 0x6f, 0xc8, 0x42, 0x2f, 0x64,
|
||||||
|
0xed, 0x57, 0x95, 0x28, 0xd3, 0x81, 0x20, 0xea,
|
||||||
|
0xe1, 0x21, 0x96, 0xd5])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c() -> U192 {
|
||||||
|
U192::from_bytes(&[0x30, 0x99, 0xd2, 0xbb, 0xbf, 0xcb, 0x25, 0x38,
|
||||||
|
0x54, 0x2d, 0xcd, 0x5f, 0xb0, 0x78, 0xb6, 0xef,
|
||||||
|
0x5f, 0x3d, 0x6f, 0xe2, 0xc7, 0x45, 0xde, 0x65])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a() -> U192 {
|
||||||
|
U192::from_bytes(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() -> U192 {
|
||||||
|
U192::from_bytes(&[0x64, 0x21, 0x05, 0x19, 0xe5, 0x9c, 0x80, 0xe7,
|
||||||
|
0x0f, 0xa7, 0xe9, 0xab, 0x72, 0x24, 0x30, 0x49,
|
||||||
|
0xfe, 0xb8, 0xde, 0xec, 0xc1, 0x46, 0xb9, 0xb1])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Gx() -> I192 {
|
||||||
|
I192::from(U192::from_bytes(&[
|
||||||
|
0x18, 0x8d, 0xa8, 0x0e, 0xb0, 0x30, 0x90, 0xf6,
|
||||||
|
0x7c, 0xbf, 0x20, 0xeb, 0x43, 0xa1, 0x88, 0x00,
|
||||||
|
0xf4, 0xff, 0x0a, 0xfd, 0x82, 0xff, 0x10, 0x12
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Gy() -> I192 {
|
||||||
|
I192::from(U192::from_bytes(&[
|
||||||
|
0x07, 0x19, 0x2b, 0x95, 0xff, 0xc8, 0xda, 0x78,
|
||||||
|
0x63, 0x10, 0x11, 0xed, 0x6b, 0x24, 0xcd, 0xd5,
|
||||||
|
0x73, 0xf9, 0x77, 0xa1, 0x1e, 0x79, 0x48, 0x11
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum P224 {}
|
||||||
|
|
||||||
|
impl EllipticCurve for P224 {
|
||||||
|
type Unsigned = U256;
|
||||||
|
type Signed = I256;
|
||||||
|
|
||||||
|
fn p() -> U256 {
|
||||||
|
U256::from_bytes(&[
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x01
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn n() -> U256 {
|
||||||
|
U256::from_bytes(&[
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
|
||||||
|
0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
|
||||||
|
0x5c, 0x5c, 0x2a, 0x3d
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SEED() -> U256 {
|
||||||
|
U256::from_bytes(&[
|
||||||
|
0xbd, 0x71, 0x34, 0x47, 0x99, 0xd5, 0xc7, 0xfc,
|
||||||
|
0xdc, 0x45, 0xb5, 0x9f, 0xa3, 0xb9, 0xab, 0x8f,
|
||||||
|
0x6a, 0x94, 0x8b, 0xc5
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c() -> U256 {
|
||||||
|
U256::from_bytes(&[
|
||||||
|
0x5b, 0x05, 0x6c, 0x7e, 0x11, 0xdd, 0x68, 0xf4,
|
||||||
|
0x04, 0x69, 0xee, 0x7f, 0x3c, 0x7a, 0x7d, 0x74,
|
||||||
|
0xf7, 0xd1, 0x21, 0x11, 0x65, 0x06, 0xd0, 0x31,
|
||||||
|
0x21, 0x82, 0x91, 0xfb
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a() -> U256 {
|
||||||
|
U256::from_bytes(&[
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xfe
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() -> U256 {
|
||||||
|
U256::from_bytes(&[
|
||||||
|
0xb4, 0x05, 0x0a, 0x85, 0x0c, 0x04, 0xb3, 0xab,
|
||||||
|
0xf5, 0x41, 0x32, 0x56, 0x50, 0x44, 0xb0, 0xb7,
|
||||||
|
0xd7, 0xbf, 0xd8, 0xba, 0x27, 0x0b, 0x39, 0x43,
|
||||||
|
0x23, 0x55, 0xff, 0xb4
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Gx() -> I256 {
|
||||||
|
I256::from(U256::from_bytes(&[
|
||||||
|
0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f,
|
||||||
|
0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3,
|
||||||
|
0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6,
|
||||||
|
0x11, 0x5c, 0x1d, 0x21
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Gy() -> I256 {
|
||||||
|
I256::from(U256::from_bytes(&[
|
||||||
|
0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb,
|
||||||
|
0x4c, 0x22, 0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0,
|
||||||
|
0x5a, 0x07, 0x47, 0x64, 0x44, 0xd5, 0x81, 0x99,
|
||||||
|
0x85, 0x00, 0x7e, 0x34
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum P256 {}
|
||||||
|
|
||||||
|
impl EllipticCurve for P256 {
|
||||||
|
type Signed = I256;
|
||||||
|
type Unsigned = U256;
|
||||||
|
|
||||||
|
fn p() -> U256 {
|
||||||
|
U256::from_bytes(&[
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn n() -> U256 {
|
||||||
|
U256::from_bytes(&[
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84,
|
||||||
|
0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SEED() -> U256 {
|
||||||
|
U256::from_bytes(&[
|
||||||
|
0xc4, 0x9d, 0x36, 0x08, 0x86, 0xe7, 0x04, 0x93,
|
||||||
|
0x6a, 0x66, 0x78, 0xe1, 0x13, 0x9d, 0x26, 0xb7,
|
||||||
|
0x81, 0x9f, 0x7e, 0x90
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn c() -> U256 {
|
||||||
|
U256::from_bytes(&[
|
||||||
|
0x7e, 0xfb, 0xa1, 0x66, 0x29, 0x85, 0xbe, 0x94,
|
||||||
|
0x03, 0xcb, 0x05, 0x5c, 0x75, 0xd4, 0xf7, 0xe0,
|
||||||
|
0xce, 0x8d, 0x84, 0xa9, 0xc5, 0x11, 0x4a, 0xbc,
|
||||||
|
0xaf, 0x31, 0x77, 0x68, 0x01, 0x04, 0xfa, 0x0d
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a() -> U256 {
|
||||||
|
U256::from_bytes(&[
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() -> U256 {
|
||||||
|
U256::from_bytes(&[
|
||||||
|
0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7,
|
||||||
|
0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc,
|
||||||
|
0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53, 0xb0, 0xf6,
|
||||||
|
0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Gx() -> I256 {
|
||||||
|
I256::from(U256::from_bytes(&[
|
||||||
|
0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47,
|
||||||
|
0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2,
|
||||||
|
0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0,
|
||||||
|
0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Gy() -> I256 {
|
||||||
|
I256::from(U256::from_bytes(&[
|
||||||
|
0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b,
|
||||||
|
0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16,
|
||||||
|
0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce,
|
||||||
|
0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum P384 {}
|
||||||
|
|
||||||
|
impl EllipticCurve for P384 {
|
||||||
|
type Signed = I384;
|
||||||
|
type Unsigned = U384;
|
||||||
|
|
||||||
|
fn p() -> U384 {
|
||||||
|
U384::from_bytes(&[
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn n() -> U384 {
|
||||||
|
U384::from_bytes(&[
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf,
|
||||||
|
0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a,
|
||||||
|
0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x73
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SEED() -> U384 {
|
||||||
|
U384::from_bytes(&[
|
||||||
|
0xa3, 0x35, 0x92, 0x6a, 0xa3, 0x19, 0xa2, 0x7a,
|
||||||
|
0x1d, 0x00, 0x89, 0x6a, 0x67, 0x73, 0xa4, 0x82,
|
||||||
|
0x7a, 0xcd, 0xac, 0x73
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c() -> U384 {
|
||||||
|
U384::from_bytes(&[
|
||||||
|
0x79, 0xd1, 0xe6, 0x55, 0xf8, 0x68, 0xf0, 0x2f,
|
||||||
|
0xff, 0x48, 0xdc, 0xde, 0xe1, 0x41, 0x51, 0xdd,
|
||||||
|
0xb8, 0x06, 0x43, 0xc1, 0x40, 0x6d, 0x0c, 0xa1,
|
||||||
|
0x0d, 0xfe, 0x6f, 0xc5, 0x20, 0x09, 0x54, 0x0a,
|
||||||
|
0x49, 0x5e, 0x80, 0x42, 0xea, 0x5f, 0x74, 0x4f,
|
||||||
|
0x6e, 0x18, 0x46, 0x67, 0xcc, 0x72, 0x24, 0x83
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a() -> U384 {
|
||||||
|
U384::from_bytes(&[
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfc
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() -> U384 {
|
||||||
|
U384::from_bytes(&[
|
||||||
|
0xb3, 0x31, 0x2f, 0xa7, 0xe2, 0x3e, 0xe7, 0xe4,
|
||||||
|
0x98, 0x8e, 0x05, 0x6b, 0xe3, 0xf8, 0x2d, 0x19,
|
||||||
|
0x18, 0x1d, 0x9c, 0x6e, 0xfe, 0x81, 0x41, 0x12,
|
||||||
|
0x03, 0x14, 0x08, 0x8f, 0x50, 0x13, 0x87, 0x5a,
|
||||||
|
0xc6, 0x56, 0x39, 0x8d, 0x8a, 0x2e, 0xd1, 0x9d,
|
||||||
|
0x2a, 0x85, 0xc8, 0xed, 0xd3, 0xec, 0x2a, 0xef
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Gx() -> I384 {
|
||||||
|
I384::from(U384::from_bytes(&[
|
||||||
|
0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37,
|
||||||
|
0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74,
|
||||||
|
0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98,
|
||||||
|
0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38,
|
||||||
|
0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c,
|
||||||
|
0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Gy() -> I384 {
|
||||||
|
I384::from(U384::from_bytes(&[
|
||||||
|
0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f,
|
||||||
|
0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29,
|
||||||
|
0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c,
|
||||||
|
0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0,
|
||||||
|
0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d,
|
||||||
|
0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum P521 {}
|
||||||
|
|
||||||
|
impl EllipticCurve for P521 {
|
||||||
|
type Signed = I576;
|
||||||
|
type Unsigned = U576;
|
||||||
|
|
||||||
|
fn p() -> U576 {
|
||||||
|
U576::from_bytes(&[
|
||||||
|
0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn n() -> U576 {
|
||||||
|
U576::from_bytes(&[
|
||||||
|
0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xfa, 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f,
|
||||||
|
0x96, 0x6b, 0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09,
|
||||||
|
0xa5, 0xd0, 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c,
|
||||||
|
0x47, 0xae, 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38,
|
||||||
|
0x64, 0x09
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SEED() -> U576 {
|
||||||
|
U576::from_bytes(&[
|
||||||
|
0xd0, 0x9e, 0x88, 0x00, 0x29, 0x1c, 0xb8, 0x53,
|
||||||
|
0x96, 0xcc, 0x67, 0x17, 0x39, 0x32, 0x84, 0xaa,
|
||||||
|
0xa0, 0xda, 0x64, 0xba
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c() -> U576 {
|
||||||
|
U576::from_bytes(&[
|
||||||
|
0xb4, 0x8b, 0xfa, 0x5f, 0x42, 0x0a, 0x34, 0x94,
|
||||||
|
0x95, 0x39, 0xd2, 0xbd, 0xfc, 0x26, 0x4e, 0xee,
|
||||||
|
0xeb, 0x07, 0x76, 0x88, 0xe4, 0x4f, 0xbf, 0x0a,
|
||||||
|
0xd8, 0xf6, 0xd0, 0xed, 0xb3, 0x7b, 0xd6, 0xb5,
|
||||||
|
0x33, 0x28, 0x10, 0x00, 0x51, 0x8e, 0x19, 0xf1,
|
||||||
|
0xb9, 0xff, 0xbe, 0x0f, 0xe9, 0xed, 0x8a, 0x3c,
|
||||||
|
0x22, 0x00, 0xb8, 0xf8, 0x75, 0xe5, 0x23, 0x86,
|
||||||
|
0x8c, 0x70, 0xc1, 0xe5, 0xbf, 0x55, 0xba, 0xd6,
|
||||||
|
0x37
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a() -> U576 {
|
||||||
|
U576::from_bytes(&[
|
||||||
|
0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xfc
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() -> U576 {
|
||||||
|
U576::from_bytes(&[
|
||||||
|
0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c, 0x9a,
|
||||||
|
0x1f, 0x92, 0x9a, 0x21, 0xa0, 0xb6, 0x85, 0x40,
|
||||||
|
0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3, 0x15,
|
||||||
|
0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1, 0x09,
|
||||||
|
0xe1, 0x56, 0x19, 0x39, 0x51, 0xec, 0x7e, 0x93,
|
||||||
|
0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1, 0xbf,
|
||||||
|
0x07, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c, 0x34,
|
||||||
|
0xf1, 0xef, 0x45, 0x1f, 0xd4, 0x6b, 0x50, 0x3f,
|
||||||
|
0x00
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Gx() -> I576 {
|
||||||
|
I576::from(U576::from_bytes(&[
|
||||||
|
0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04, 0xe9,
|
||||||
|
0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95, 0xb4,
|
||||||
|
0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f, 0xb5,
|
||||||
|
0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d, 0x3d,
|
||||||
|
0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7, 0x59,
|
||||||
|
0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff, 0xa8,
|
||||||
|
0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a, 0x42,
|
||||||
|
0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5, 0xbd,
|
||||||
|
0x66
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Gy() -> I576 {
|
||||||
|
I576::from(U576::from_bytes(&[
|
||||||
|
0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, 0xc0,
|
||||||
|
0x04, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d, 0x1b,
|
||||||
|
0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b, 0x44,
|
||||||
|
0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e, 0x66,
|
||||||
|
0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4, 0x26,
|
||||||
|
0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad, 0x07,
|
||||||
|
0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72, 0xc2,
|
||||||
|
0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1, 0x66,
|
||||||
|
0x50
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}
|
||||||
2
src/ecdsa/mod.rs
Normal file
2
src/ecdsa/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod curve;
|
||||||
|
pub mod point;
|
||||||
216
src/ecdsa/point.rs
Normal file
216
src/ecdsa/point.rs
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
use cryptonum::signed::*;
|
||||||
|
use cryptonum::unsigned::*;
|
||||||
|
use ecdsa::curve::*;
|
||||||
|
|
||||||
|
pub trait ECCPoint {
|
||||||
|
type Curve: EllipticCurve;
|
||||||
|
type Scale;
|
||||||
|
|
||||||
|
fn default() -> Self;
|
||||||
|
fn negate(&self) -> Self;
|
||||||
|
fn double(&self) -> Self;
|
||||||
|
fn add(&self, other: &Self) -> Self;
|
||||||
|
fn scale(&self, amt: &Self::Scale) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Point<T: EllipticCurve>
|
||||||
|
{
|
||||||
|
pub x: T::Signed,
|
||||||
|
pub y: T::Signed
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Point<P192> {
|
||||||
|
fn clone(&self) -> Point<P192> {
|
||||||
|
Point {
|
||||||
|
x: self.x.clone(),
|
||||||
|
y: self.y.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ECCPoint for Point<P192> {
|
||||||
|
type Curve = P192;
|
||||||
|
type Scale = U192;
|
||||||
|
|
||||||
|
fn default() -> Point<P192>
|
||||||
|
{
|
||||||
|
Point {
|
||||||
|
x: P192::Gx(),
|
||||||
|
y: P192::Gy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn negate(&self) -> Point<P192>
|
||||||
|
{
|
||||||
|
let mut newy = I192::new(false, P192::p());
|
||||||
|
newy -= &self.y;
|
||||||
|
Point{ x: self.x.clone(), y: newy }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn double(&self) -> Point<P192>
|
||||||
|
{
|
||||||
|
let ua = P192::a();
|
||||||
|
let up = P192::p();
|
||||||
|
let bigp = I384::new(false, U384::from(&up));
|
||||||
|
// lambda = (3 * xp ^ 2 + a) / 2 yp
|
||||||
|
let mut lambda_top = I384::from(3i64) * (&self.x * &self.x);
|
||||||
|
lambda_top += I768::new(false, U768::from(ua));
|
||||||
|
let mut lambda_bot = I768::from(&self.y);
|
||||||
|
lambda_bot <<= 1;
|
||||||
|
let lambda = I192::from(lambda_top.moddiv(&lambda_bot, &I768::from(&bigp)));
|
||||||
|
// xr = lambda^2 - 2 xp
|
||||||
|
let mut xr = &lambda * λ
|
||||||
|
let mut xr_right = I384::from(&self.x);
|
||||||
|
xr_right <<= 1;
|
||||||
|
xr -= xr_right;
|
||||||
|
xr %= &bigp;
|
||||||
|
let x = I192::from(xr);
|
||||||
|
// yr = lambda (xp - xr) - yp
|
||||||
|
let xdiff = I192::from(&self.x - &x);
|
||||||
|
let mut yr = &lambda * &xdiff;
|
||||||
|
yr -= I384::from(&self.y);
|
||||||
|
let y = I192::from(&yr % &bigp);
|
||||||
|
//
|
||||||
|
Point{ x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add(&self, other: &Point<P192>) -> Point<P192>
|
||||||
|
{
|
||||||
|
let xdiff: I256 = &self.x - &other.x;
|
||||||
|
let ydiff: I256 = &self.y - &other.y;
|
||||||
|
let signedp = I256::from(U256::from(P192::p()));
|
||||||
|
let s = ydiff.moddiv(&xdiff, &signedp);
|
||||||
|
let mut xr = &s * &s;
|
||||||
|
xr -= I512::from(&self.x);
|
||||||
|
xr -= I512::from(&other.x);
|
||||||
|
let bigsignedp = I512::from(&signedp);
|
||||||
|
xr %= &bigsignedp;
|
||||||
|
let mut yr = I512::from(&self.x);
|
||||||
|
yr -= &xr;
|
||||||
|
yr *= I512::from(&s);
|
||||||
|
yr -= I512::from(&self.y);
|
||||||
|
yr %= &bigsignedp;
|
||||||
|
Point{ x: I192::from(xr), y: I192::from(yr) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scale(&self, d: &U192) -> Point<P192>
|
||||||
|
{
|
||||||
|
assert!(!d.is_zero());
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
let mut Q: Point<P192> = self.clone();
|
||||||
|
let mut bit = 191;
|
||||||
|
|
||||||
|
// Skip down until we hit a set bit
|
||||||
|
while !d.testbit(bit as usize) {
|
||||||
|
bit -= 1;
|
||||||
|
}
|
||||||
|
// drop one
|
||||||
|
bit -= 1;
|
||||||
|
// do the double and add algorithm
|
||||||
|
while bit >= 0 {
|
||||||
|
Q = Q.double();
|
||||||
|
|
||||||
|
let test = d.testbit(bit as usize);
|
||||||
|
if test {
|
||||||
|
Q = Q.add(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
bit -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use testing::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn p192_negate() {
|
||||||
|
let fname = build_test_path("ecc/negate","P192");
|
||||||
|
run_test(fname.to_string(), 4, |case| {
|
||||||
|
let (negx, xbytes) = case.get("x").unwrap();
|
||||||
|
let (negy, ybytes) = case.get("y").unwrap();
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
|
||||||
|
let x = I192::new(*negx, U192::from_bytes(xbytes));
|
||||||
|
let y = I192::new(*negy, U192::from_bytes(ybytes));
|
||||||
|
let a = I192::new(*nega, U192::from_bytes(abytes));
|
||||||
|
let b = I192::new(*negb, U192::from_bytes(bbytes));
|
||||||
|
let point = Point{ x, y };
|
||||||
|
let dbl = point.negate();
|
||||||
|
assert_eq!(a, dbl.x, "x equivalence");
|
||||||
|
assert_eq!(b, dbl.y, "y equivalence");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn p192_double() {
|
||||||
|
let fname = build_test_path("ecc/double","P192");
|
||||||
|
run_test(fname.to_string(), 4, |case| {
|
||||||
|
let (negx, xbytes) = case.get("x").unwrap();
|
||||||
|
let (negy, ybytes) = case.get("y").unwrap();
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
|
||||||
|
let x = I192::new(*negx, U192::from_bytes(xbytes));
|
||||||
|
let y = I192::new(*negy, U192::from_bytes(ybytes));
|
||||||
|
let a = I192::new(*nega, U192::from_bytes(abytes));
|
||||||
|
let b = I192::new(*negb, U192::from_bytes(bbytes));
|
||||||
|
let point = Point{ x, y };
|
||||||
|
let dbl = point.double();
|
||||||
|
assert_eq!(a, dbl.x, "x equivalence");
|
||||||
|
assert_eq!(b, dbl.y, "y equivalence");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn p192_add() {
|
||||||
|
let fname = build_test_path("ecc/add","P192");
|
||||||
|
run_test(fname.to_string(), 6, move |case| {
|
||||||
|
let (negx, xbytes) = case.get("x").unwrap();
|
||||||
|
let (negy, ybytes) = case.get("y").unwrap();
|
||||||
|
let (negu, ubytes) = case.get("u").unwrap();
|
||||||
|
let (negv, vbytes) = case.get("v").unwrap();
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
|
||||||
|
let x = I192::new(*negx, U192::from_bytes(xbytes));
|
||||||
|
let y = I192::new(*negy, U192::from_bytes(ybytes));
|
||||||
|
let u = I192::new(*negu, U192::from_bytes(ubytes));
|
||||||
|
let v = I192::new(*negv, U192::from_bytes(vbytes));
|
||||||
|
let a = I192::new(*nega, U192::from_bytes(abytes));
|
||||||
|
let b = I192::new(*negb, U192::from_bytes(bbytes));
|
||||||
|
let point1 = Point{ x: x, y: y };
|
||||||
|
let point2 = Point{ x: u, y: v };
|
||||||
|
let res = point1.add(&point2);
|
||||||
|
assert_eq!(a, res.x, "x equivalence");
|
||||||
|
assert_eq!(b, res.y, "y equivalence");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn p192_scale() {
|
||||||
|
let fname = build_test_path("ecc/scale","P192");
|
||||||
|
run_test(fname.to_string(), 5, |case| {
|
||||||
|
let (negx, xbytes) = case.get("x").unwrap();
|
||||||
|
let (negy, ybytes) = case.get("y").unwrap();
|
||||||
|
let (negk, kbytes) = case.get("k").unwrap();
|
||||||
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
|
||||||
|
let x = I192::new(*negx, U192::from_bytes(xbytes));
|
||||||
|
let y = I192::new(*negy, U192::from_bytes(ybytes));
|
||||||
|
let k = U192::from_bytes(kbytes);
|
||||||
|
let a = I192::new(*nega, U192::from_bytes(abytes));
|
||||||
|
let b = I192::new(*negb, U192::from_bytes(bbytes));
|
||||||
|
let point = Point{ x: x, y: y };
|
||||||
|
let res = point.scale(&k);
|
||||||
|
assert_eq!(a, res.x, "x equivalence");
|
||||||
|
assert_eq!(b, res.y, "y equivalence");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,9 @@ pub mod rsa;
|
|||||||
/// new system, but might need to use them to interact with legacy systems or
|
/// new system, but might need to use them to interact with legacy systems or
|
||||||
/// protocols.
|
/// protocols.
|
||||||
pub mod dsa;
|
pub mod dsa;
|
||||||
|
/// The `ecdsa` module provides bare-bones support for ECDSA signing,
|
||||||
|
/// verification, and key generation.
|
||||||
|
pub mod ecdsa;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod testing;
|
mod testing;
|
||||||
|
|||||||
@@ -3,6 +3,11 @@ use std::fs::File;
|
|||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::str::Lines;
|
use std::str::Lines;
|
||||||
|
|
||||||
|
pub fn build_test_path(dir: &str, typename: &str) -> String
|
||||||
|
{
|
||||||
|
format!("testdata/{}/{}.test", dir, typename)
|
||||||
|
}
|
||||||
|
|
||||||
fn next_value_set(line: &str) -> (String, bool, Vec<u8>)
|
fn next_value_set(line: &str) -> (String, bool, Vec<u8>)
|
||||||
{
|
{
|
||||||
assert!(line.is_ascii());
|
assert!(line.is_ascii());
|
||||||
@@ -10,7 +15,7 @@ fn next_value_set(line: &str) -> (String, bool, Vec<u8>)
|
|||||||
let key = items.next().unwrap();
|
let key = items.next().unwrap();
|
||||||
let valbits = items.next().unwrap();
|
let valbits = items.next().unwrap();
|
||||||
let neg = valbits.contains('-');
|
let neg = valbits.contains('-');
|
||||||
let valbitsnoneg = valbits.trim_left_matches("-");
|
let valbitsnoneg = valbits.trim_start_matches("-");
|
||||||
|
|
||||||
let mut nibble_iter = valbitsnoneg.chars().rev();
|
let mut nibble_iter = valbitsnoneg.chars().rev();
|
||||||
let mut val = Vec::new();
|
let mut val = Vec::new();
|
||||||
|
|||||||
2
test-generator/.gitignore
vendored
Normal file
2
test-generator/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
dist/
|
||||||
|
dist-newstyle/
|
||||||
41
test-generator/Database.hs
Normal file
41
test-generator/Database.hs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
module Database(
|
||||||
|
Database,
|
||||||
|
emptyDatabase,
|
||||||
|
generateNum, genSign
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
import Crypto.Random(DRG(..),SystemDRG)
|
||||||
|
import Data.Bits(shiftL,testBit)
|
||||||
|
import qualified Data.ByteString as S
|
||||||
|
import Data.Map.Strict(Map)
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
|
||||||
|
type Database = (Map String [Integer], SystemDRG)
|
||||||
|
|
||||||
|
emptyDatabase :: SystemDRG -> Database
|
||||||
|
emptyDatabase g0 = (Map.empty, g0)
|
||||||
|
|
||||||
|
generateNum :: Database -> String -> Int -> (Integer, Database)
|
||||||
|
generateNum (db, rng0) varname size =
|
||||||
|
let (x, rng1) = randomBytesGenerate (size `div` 8) rng0
|
||||||
|
x' = integerize x
|
||||||
|
before = Map.findWithDefault [] varname db
|
||||||
|
in if length (filter (== x') before) < 10
|
||||||
|
then (x', (Map.insert varname (x':before) db, rng1))
|
||||||
|
else generateNum (db, rng1) varname size
|
||||||
|
|
||||||
|
genSign :: (Integer, Database) -> (Integer, Database)
|
||||||
|
genSign (x, (db, rng0)) =
|
||||||
|
let (n, rng1) = randomBytesGenerate 0 rng0
|
||||||
|
n' = integerize n
|
||||||
|
in if testBit n' 0 then (0 - x, (db, rng1)) else (x, (db, rng1))
|
||||||
|
|
||||||
|
integerize :: S.ByteString -> Integer
|
||||||
|
integerize = go 0
|
||||||
|
where
|
||||||
|
go acc bstr =
|
||||||
|
case S.uncons bstr of
|
||||||
|
Nothing -> acc
|
||||||
|
Just (v,rest) ->
|
||||||
|
go ((acc `shiftL` 8) + fromIntegral v) rest
|
||||||
108
test-generator/ECDSATesting.hs
Normal file
108
test-generator/ECDSATesting.hs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
module ECDSATesting(
|
||||||
|
ecdsaTasks
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
import Crypto.PubKey.ECC.Prim(scalarGenerate,pointAdd,pointNegate,pointDouble,pointBaseMul,pointMul)
|
||||||
|
import Crypto.PubKey.ECC.Types(Curve,CurveName(..),Point(..),getCurveByName)
|
||||||
|
import Crypto.Random(withDRG)
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
import Math(showX)
|
||||||
|
import Task(Task(..))
|
||||||
|
|
||||||
|
curves :: [(String, Curve)]
|
||||||
|
curves = [("P192", getCurveByName SEC_p192r1)]
|
||||||
|
|
||||||
|
negateTest :: String -> Curve -> Task
|
||||||
|
negateTest name curve = Task {
|
||||||
|
taskName = name ++ " point negation",
|
||||||
|
taskFile = "../testdata/ecc/negate/" ++ name ++ ".test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = 1000
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg) =
|
||||||
|
let (scalar, drg') = withDRG drg (scalarGenerate curve)
|
||||||
|
point = pointBaseMul curve scalar
|
||||||
|
dbl = pointNegate curve point
|
||||||
|
in case (point, dbl) of
|
||||||
|
(PointO, _) -> go (memory0, drg')
|
||||||
|
(_, PointO) -> go (memory0, drg')
|
||||||
|
(Point basex basey, Point dblx dbly) ->
|
||||||
|
let res = Map.fromList [("x", showX basex), ("y", showX basey),
|
||||||
|
("a", showX dblx), ("b", showX dbly)]
|
||||||
|
in (res, scalar, (memory0, drg'))
|
||||||
|
|
||||||
|
doubleTest :: String -> Curve -> Task
|
||||||
|
doubleTest name curve = Task {
|
||||||
|
taskName = name ++ " point doubling",
|
||||||
|
taskFile = "../testdata/ecc/double/" ++ name ++ ".test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = 1000
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg) =
|
||||||
|
let (scalar, drg') = withDRG drg (scalarGenerate curve)
|
||||||
|
point = pointBaseMul curve scalar
|
||||||
|
dbl = pointDouble curve point
|
||||||
|
in case (point, dbl) of
|
||||||
|
(PointO, _) -> go (memory0, drg')
|
||||||
|
(_, PointO) -> go (memory0, drg')
|
||||||
|
(Point basex basey, Point dblx dbly) ->
|
||||||
|
let res = Map.fromList [("x", showX basex), ("y", showX basey),
|
||||||
|
("a", showX dblx), ("b", showX dbly)]
|
||||||
|
in (res, scalar, (memory0, drg'))
|
||||||
|
|
||||||
|
addTest :: String -> Curve -> Task
|
||||||
|
addTest name curve = Task {
|
||||||
|
taskName = name ++ " point addition",
|
||||||
|
taskFile = "../testdata/ecc/add/" ++ name ++ ".test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = 1000
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
let (scalar1, drg1) = withDRG drg0 (scalarGenerate curve)
|
||||||
|
(scalar2, drg2) = withDRG drg1 (scalarGenerate curve)
|
||||||
|
point1 = pointBaseMul curve scalar1
|
||||||
|
point2 = pointBaseMul curve scalar2
|
||||||
|
pointr = pointAdd curve point1 point2
|
||||||
|
in case (point1, point2, pointr) of
|
||||||
|
(Point x1 y1, Point x2 y2, Point xr yr) ->
|
||||||
|
let res = Map.fromList [("x", showX x1), ("y", showX y1),
|
||||||
|
("u", showX x2), ("v", showX y2),
|
||||||
|
("a", showX xr), ("b", showX yr)]
|
||||||
|
in (res, scalar1, (memory0, drg2))
|
||||||
|
_ ->
|
||||||
|
go (memory0, drg2)
|
||||||
|
|
||||||
|
scaleTest :: String -> Curve -> Task
|
||||||
|
scaleTest name curve = Task {
|
||||||
|
taskName = name ++ " point scaling",
|
||||||
|
taskFile = "../testdata/ecc/scale/" ++ name ++ ".test",
|
||||||
|
taskTest = go,
|
||||||
|
taskCount = 1000
|
||||||
|
}
|
||||||
|
where
|
||||||
|
go (memory0, drg0) =
|
||||||
|
let (scalar0, drg1) = withDRG drg0 (scalarGenerate curve)
|
||||||
|
(scalar1, drg2) = withDRG drg1 (scalarGenerate curve)
|
||||||
|
point = pointBaseMul curve scalar0
|
||||||
|
respnt = pointMul curve scalar1 point
|
||||||
|
in case (point, respnt) of
|
||||||
|
(PointO, _) -> go (memory0, drg2)
|
||||||
|
(_, PointO) -> go (memory0, drg2)
|
||||||
|
(Point basex basey, Point resx resy) ->
|
||||||
|
let res = Map.fromList [("x", showX basex), ("y", showX basey),
|
||||||
|
("k", showX scalar1),
|
||||||
|
("a", showX resx), ("b", showX resy)]
|
||||||
|
in (res, scalar0, (memory0, drg2))
|
||||||
|
|
||||||
|
generateTasks :: (String, Curve) -> [Task]
|
||||||
|
generateTasks (name, curve) = [negateTest name curve,
|
||||||
|
doubleTest name curve,
|
||||||
|
addTest name curve,
|
||||||
|
scaleTest name curve]
|
||||||
|
|
||||||
|
ecdsaTasks :: [Task]
|
||||||
|
ecdsaTasks = concatMap generateTasks curves
|
||||||
39
test-generator/Main.hs
Normal file
39
test-generator/Main.hs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{-# LANGUAGE LambdaCase #-}
|
||||||
|
import Control.Concurrent(forkIO)
|
||||||
|
import Control.Concurrent.Chan(Chan,newChan,readChan,writeChan)
|
||||||
|
import Control.Concurrent.MVar(MVar,newMVar,modifyMVar)
|
||||||
|
import Control.Exception(SomeException,catch)
|
||||||
|
import Control.Monad(replicateM_,void)
|
||||||
|
import Crypto.Random(SystemDRG,getSystemDRG)
|
||||||
|
import ECDSATesting(ecdsaTasks)
|
||||||
|
import GHC.Conc(getNumCapabilities)
|
||||||
|
import System.Console.AsciiProgress
|
||||||
|
import Task(Task, runTask)
|
||||||
|
|
||||||
|
taskExecutor :: MVar [Task] -> Chan () -> SystemDRG -> IO SystemDRG
|
||||||
|
taskExecutor taskList done gen =
|
||||||
|
do mnext <- modifyMVar taskList (\case
|
||||||
|
[] -> return ([], Nothing)
|
||||||
|
(x:xs) -> return (xs, Just x))
|
||||||
|
case mnext of
|
||||||
|
Nothing -> do writeChan done ()
|
||||||
|
return gen
|
||||||
|
Just x -> do gen' <- runTask gen x
|
||||||
|
taskExecutor taskList done gen'
|
||||||
|
|
||||||
|
spawnExecutor :: MVar [Task] -> Chan () -> IO ()
|
||||||
|
spawnExecutor tasks done =
|
||||||
|
do gen <- getSystemDRG
|
||||||
|
void (forkIO (catch (void (taskExecutor tasks done gen)) handler))
|
||||||
|
where
|
||||||
|
handler :: SomeException -> IO ()
|
||||||
|
handler e = putStrLn ("ERROR: " ++ show e)
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = displayConsoleRegions $
|
||||||
|
do
|
||||||
|
executors <- getNumCapabilities
|
||||||
|
done <- newChan
|
||||||
|
tasks <- newMVar (ecdsaTasks)
|
||||||
|
replicateM_ executors (spawnExecutor tasks done)
|
||||||
|
replicateM_ executors (void $ readChan done)
|
||||||
158
test-generator/Math.hs
Normal file
158
test-generator/Math.hs
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
|
module Math(
|
||||||
|
extendedGCD
|
||||||
|
, barrett, computeK, base
|
||||||
|
, modulate, modulate'
|
||||||
|
, isqrt
|
||||||
|
, divmod
|
||||||
|
, showX, showB
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
import Data.Bits(shiftL,shiftR)
|
||||||
|
import GHC.Integer.GMP.Internals(recipModInteger)
|
||||||
|
import Numeric(showHex)
|
||||||
|
|
||||||
|
data AlgState = AlgState {
|
||||||
|
u :: Integer,
|
||||||
|
v :: Integer,
|
||||||
|
bigA :: Integer,
|
||||||
|
bigB :: Integer,
|
||||||
|
bigC :: Integer,
|
||||||
|
bigD :: Integer
|
||||||
|
}
|
||||||
|
|
||||||
|
printState :: AlgState -> IO ()
|
||||||
|
printState a =
|
||||||
|
do putStrLn ("u: " ++ showX (u a))
|
||||||
|
putStrLn ("v: " ++ showX (v a))
|
||||||
|
putStrLn ("A: " ++ showX (bigA a))
|
||||||
|
putStrLn ("B: " ++ showX (bigB a))
|
||||||
|
putStrLn ("C: " ++ showX (bigC a))
|
||||||
|
putStrLn ("D: " ++ showX (bigD a))
|
||||||
|
|
||||||
|
extendedGCD :: Integer -> Integer -> (Integer, Integer, Integer)
|
||||||
|
extendedGCD x y = (a, b, g * (v finalState))
|
||||||
|
where
|
||||||
|
(x', y', g, initState) = initialState x y 1
|
||||||
|
finalState = runAlgorithm x' y' initState
|
||||||
|
a = bigC finalState
|
||||||
|
b = bigD finalState
|
||||||
|
|
||||||
|
initialState :: Integer -> Integer -> Integer -> (Integer, Integer, Integer, AlgState)
|
||||||
|
initialState x y g | even x && even y = initialState (x `div` 2) (y `div` 2) (g * 2)
|
||||||
|
| otherwise = (x, y, g, AlgState x y 1 0 0 1)
|
||||||
|
|
||||||
|
runAlgorithm :: Integer -> Integer -> AlgState -> AlgState
|
||||||
|
runAlgorithm x y state | u state == 0 = state
|
||||||
|
| otherwise = runAlgorithm x y state6
|
||||||
|
where
|
||||||
|
state4 = step4 x y state
|
||||||
|
state5 = step5 x y state4
|
||||||
|
state6 = step6 state5
|
||||||
|
|
||||||
|
step4 :: Integer -> Integer -> AlgState -> AlgState
|
||||||
|
step4 x y input@AlgState{..} | even u = step4 x y input'
|
||||||
|
| otherwise = input
|
||||||
|
where
|
||||||
|
input' = AlgState u' v bigA' bigB' bigC bigD
|
||||||
|
u' = u `div` 2
|
||||||
|
bigA' | even bigA && even bigB = bigA `div` 2
|
||||||
|
| otherwise = (bigA + y) `div` 2
|
||||||
|
bigB' | even bigA && even bigB = bigB `div` 2
|
||||||
|
| otherwise = (bigB - x) `div` 2
|
||||||
|
|
||||||
|
step5 :: Integer -> Integer -> AlgState -> AlgState
|
||||||
|
step5 x y input@AlgState{..} | even v = step5 x y input'
|
||||||
|
| otherwise = input
|
||||||
|
where
|
||||||
|
input' = AlgState u v' bigA bigB bigC' bigD'
|
||||||
|
v' = v `div` 2
|
||||||
|
bigC' | even bigC && even bigD = bigC `div` 2
|
||||||
|
| otherwise = (bigC + y) `div` 2
|
||||||
|
bigD' | even bigC && even bigD = bigD `div` 2
|
||||||
|
| otherwise = (bigD - x) `div` 2
|
||||||
|
|
||||||
|
step6 :: AlgState -> AlgState
|
||||||
|
step6 AlgState{..}
|
||||||
|
| u >= v = AlgState (u - v) v (bigA - bigC) (bigB - bigD) bigC bigD
|
||||||
|
| otherwise = AlgState u (v - u) bigA bigB (bigC - bigA) (bigD - bigB)
|
||||||
|
|
||||||
|
barrett :: Integer -> Integer
|
||||||
|
barrett m = (base ^ (2 * k)) `div` m
|
||||||
|
where
|
||||||
|
k = computeK m
|
||||||
|
|
||||||
|
computeK :: Integer -> Int
|
||||||
|
computeK v = go 0 1
|
||||||
|
where
|
||||||
|
go k acc | v <= acc = k
|
||||||
|
| otherwise = go (k + 1) (acc * base)
|
||||||
|
|
||||||
|
base :: Integer
|
||||||
|
base = 2 ^ (64 :: Integer)
|
||||||
|
|
||||||
|
modulate :: Integer -> Int -> Integer
|
||||||
|
modulate x size = x `mod` (2 ^ size)
|
||||||
|
|
||||||
|
modulate' :: Integer -> Int -> Integer
|
||||||
|
modulate' x size = signum x * (abs x `mod` (2 ^ size))
|
||||||
|
|
||||||
|
showX :: (Integral a, Show a) => a -> String
|
||||||
|
showX x | x < 0 = "-" ++ showX (abs x)
|
||||||
|
| otherwise = showHex x ""
|
||||||
|
|
||||||
|
showB :: Bool -> String
|
||||||
|
showB False = "0"
|
||||||
|
showB True = "1"
|
||||||
|
|
||||||
|
isqrt :: Int -> Integer -> Integer
|
||||||
|
isqrt bits val = final
|
||||||
|
where
|
||||||
|
bit' = part1 (1 `shiftL` (bits - 2))
|
||||||
|
--
|
||||||
|
part1 x | x > val = part1 (x `shiftR` 2)
|
||||||
|
| otherwise = x
|
||||||
|
--
|
||||||
|
final = loop val 0 bit'
|
||||||
|
--
|
||||||
|
loop num res bit
|
||||||
|
| bit == 0 = res
|
||||||
|
| otherwise = let (num', res') = adjust num res bit
|
||||||
|
in loop num' (res' `shiftR` 1) (bit `shiftR` 2)
|
||||||
|
adjust num res bit
|
||||||
|
| num >= (res + bit) = (num - (res + bit), res + (bit `shiftL` 1))
|
||||||
|
| otherwise = (num, res)
|
||||||
|
|
||||||
|
divmod :: Integer -> Integer -> Integer -> Maybe Integer
|
||||||
|
divmod x y m =
|
||||||
|
let y' = y `mod` m
|
||||||
|
in case recipModInteger y' m of
|
||||||
|
0 -> Nothing
|
||||||
|
i -> Just ((x * i) `mod` m)
|
||||||
|
|
||||||
|
_run :: Integer -> Integer -> IO ()
|
||||||
|
_run inputx inputy =
|
||||||
|
do let (x, y, g, initState) = initialState inputx inputy 1
|
||||||
|
finalState <- go x y initState
|
||||||
|
putStrLn ("-- FINAL STATE -----------------------")
|
||||||
|
printState finalState
|
||||||
|
putStrLn ("Final value: " ++ showX (g * v finalState))
|
||||||
|
putStrLn ("-- RUN ------")
|
||||||
|
printState (runAlgorithm x y initState)
|
||||||
|
putStrLn ("-- NORMAL ------")
|
||||||
|
let (a, b, v) = extendedGCD inputx inputy
|
||||||
|
putStrLn ("a: " ++ showX a)
|
||||||
|
putStrLn ("b: " ++ showX b)
|
||||||
|
putStrLn ("v: " ++ showX v)
|
||||||
|
|
||||||
|
where
|
||||||
|
go x y state =
|
||||||
|
do putStrLn "-- STATE -----------------------------"
|
||||||
|
printState state
|
||||||
|
if u state == 0
|
||||||
|
then return state
|
||||||
|
else do let state' = step4 x y state
|
||||||
|
state'' = step5 x y state'
|
||||||
|
state''' = step6 state''
|
||||||
|
go x y state'''
|
||||||
50
test-generator/Task.hs
Normal file
50
test-generator/Task.hs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
module Task(
|
||||||
|
Test,
|
||||||
|
Task(..),
|
||||||
|
runTask
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
import Control.Monad(foldM, forM_)
|
||||||
|
import Crypto.Random(SystemDRG)
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
import Database
|
||||||
|
import System.Console.AsciiProgress
|
||||||
|
import System.Directory(createDirectoryIfMissing,doesFileExist)
|
||||||
|
import System.FilePath(takeDirectory)
|
||||||
|
import System.IO(Handle,IOMode(..),hPutStrLn,withFile)
|
||||||
|
|
||||||
|
type Test = Database -> (Map.Map String String, Integer, Database)
|
||||||
|
|
||||||
|
data Task = Task {
|
||||||
|
taskName :: String,
|
||||||
|
taskFile :: FilePath,
|
||||||
|
taskTest :: Test,
|
||||||
|
taskCount :: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
runTask :: SystemDRG -> Task -> IO SystemDRG
|
||||||
|
runTask gen task =
|
||||||
|
do createDirectoryIfMissing True (takeDirectory (taskFile task))
|
||||||
|
alreadyDone <- doesFileExist (taskFile task)
|
||||||
|
if alreadyDone
|
||||||
|
then return gen
|
||||||
|
else withFile (taskFile task) WriteMode $ \ hndl ->
|
||||||
|
do pg <- newProgressBar def{ pgOnCompletion = Just ("Finished " ++ taskName task),
|
||||||
|
pgFormat = taskName task ++ " " ++ pgFormat def,
|
||||||
|
pgTotal = fromIntegral (taskCount task) }
|
||||||
|
let initval = emptyDatabase gen
|
||||||
|
(_, gen') <- foldM (writer hndl pg (taskTest task)) initval [0..taskCount task]
|
||||||
|
return gen'
|
||||||
|
where
|
||||||
|
writer :: Handle -> ProgressBar -> Test -> Database -> Int -> IO Database
|
||||||
|
writer hndl pg runner db x =
|
||||||
|
do let (output, key, acc@(db',gen')) = runner db
|
||||||
|
before = Map.findWithDefault [] "RESULT" db'
|
||||||
|
if length (filter (== key) before) >= 10
|
||||||
|
then writer hndl pg runner acc x
|
||||||
|
else do forM_ (Map.toList output) $ \ (outkey, val) ->
|
||||||
|
hPutStrLn hndl (outkey ++ ": " ++ val)
|
||||||
|
tick pg
|
||||||
|
return (Map.insert "RESULT" (key : before) db', gen')
|
||||||
|
|
||||||
34
test-generator/gcd.hs
Normal file
34
test-generator/gcd.hs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import Numeric
|
||||||
|
|
||||||
|
data Set = Set { r :: Integer, s :: Integer, t :: Integer }
|
||||||
|
|
||||||
|
step :: Set -> Set -> Set
|
||||||
|
step old new = Set r' s' t'
|
||||||
|
where
|
||||||
|
quotient = r old `div` r new
|
||||||
|
r' = r old - (r new * quotient)
|
||||||
|
s' = s old - (s new * quotient)
|
||||||
|
t' = t old - (t new * quotient)
|
||||||
|
|
||||||
|
run :: Integer -> Integer -> IO Set
|
||||||
|
run self rhs = go (Set self 1 0) (Set rhs 0 1)
|
||||||
|
where
|
||||||
|
go old new | r new == 0 =
|
||||||
|
do putStrLn "------------------------------"
|
||||||
|
putStrLn ("res_r: " ++ showX (r old))
|
||||||
|
putStrLn ("res_s: " ++ showX (s old))
|
||||||
|
putStrLn ("res_t: " ++ showX (t old))
|
||||||
|
return old
|
||||||
|
| otherwise =
|
||||||
|
do putStrLn "------------------------------"
|
||||||
|
putStrLn ("old_r: " ++ showX (r old))
|
||||||
|
putStrLn ("old_s: " ++ showX (s old))
|
||||||
|
putStrLn ("old_t: " ++ showX (t old))
|
||||||
|
putStrLn ("new_r: " ++ showX (r new))
|
||||||
|
putStrLn ("new_s: " ++ showX (s new))
|
||||||
|
putStrLn ("new_t: " ++ showX (t new))
|
||||||
|
go new (step old new)
|
||||||
|
|
||||||
|
showX :: Integer -> String
|
||||||
|
showX x | x < 0 = "-" ++ showX (abs x)
|
||||||
|
| otherwise = showHex x ""
|
||||||
28
test-generator/test-generator.cabal
Normal file
28
test-generator/test-generator.cabal
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
cabal-version: >=1.10
|
||||||
|
-- Initial package description 'test-generator.cabal' generated by 'cabal
|
||||||
|
-- init'. For further documentation, see
|
||||||
|
-- http://haskell.org/cabal/users-guide/
|
||||||
|
|
||||||
|
name: test-generator
|
||||||
|
version: 0.1.0.0
|
||||||
|
synopsis: Test generation helper
|
||||||
|
-- description:
|
||||||
|
homepage: http://github.com/acw
|
||||||
|
-- bug-reports:
|
||||||
|
license: ISC
|
||||||
|
license-file: ../LICENSE
|
||||||
|
author: Adam Wick
|
||||||
|
maintainer: awick@uhsure.com
|
||||||
|
-- copyright:
|
||||||
|
category: Testing
|
||||||
|
build-type: Simple
|
||||||
|
extra-source-files: CHANGELOG.md
|
||||||
|
|
||||||
|
executable gen-tests
|
||||||
|
main-is: Main.hs
|
||||||
|
other-modules: Database, ECDSATesting, Math, Task
|
||||||
|
-- other-extensions:
|
||||||
|
build-depends: base >=4.11 && < 4.14, ascii-progress, bytestring, containers, cryptonite, directory, filepath, integer-gmp, random
|
||||||
|
hs-source-dirs: .
|
||||||
|
default-language: Haskell2010
|
||||||
|
ghc-options: -Wall -O2 -threaded -rtsopts -with-rtsopts=-N
|
||||||
6006
testdata/ecc/add/P192.test
vendored
Normal file
6006
testdata/ecc/add/P192.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4004
testdata/ecc/double/P192.test
vendored
Normal file
4004
testdata/ecc/double/P192.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4004
testdata/ecc/negate/P192.test
vendored
Normal file
4004
testdata/ecc/negate/P192.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5005
testdata/ecc/scale/P192.test
vendored
Normal file
5005
testdata/ecc/scale/P192.test
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user