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
|
||||
/// protocols.
|
||||
pub mod dsa;
|
||||
/// The `ecdsa` module provides bare-bones support for ECDSA signing,
|
||||
/// verification, and key generation.
|
||||
pub mod ecdsa;
|
||||
|
||||
#[cfg(test)]
|
||||
mod testing;
|
||||
|
||||
@@ -3,6 +3,11 @@ use std::fs::File;
|
||||
use std::io::Read;
|
||||
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>)
|
||||
{
|
||||
assert!(line.is_ascii());
|
||||
@@ -10,7 +15,7 @@ fn next_value_set(line: &str) -> (String, bool, Vec<u8>)
|
||||
let key = items.next().unwrap();
|
||||
let valbits = items.next().unwrap();
|
||||
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 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