66 Commits

Author SHA1 Message Date
bdf7f81b20 [BROKEN] Trying to get elliptic curve working, which is much too slow at the moment. 2018-05-31 18:37:18 +01:00
dde1092f49 Start building out ECC infrastructure. 2018-05-21 18:38:56 +01:00
6fabbe6af1 Initial port-over of ECDSA signing. 2018-05-16 22:00:17 -07:00
f83b8a3fe5 Ignore more things. 2018-05-15 15:42:51 -07:00
61f4a009a0 Update the Travis build to use stable, and to leave some time for the tests to run. 2018-05-15 14:45:39 -07:00
1d67b4c775 Split the encryption test suite into two parts, to help reduce the cost of the test suite. 2018-05-15 07:28:00 -07:00
81ccf3e06b Trying to cut down the time taken running the test suite, so that we fit in Travis's expectations. 2018-05-12 16:41:55 -07:00
219641da5e Try to speed up DSA a bit using Barrett reduction. 2018-05-12 16:41:33 -07:00
f0f4891abe DSA! Working, with tests! 2018-05-12 08:04:33 -07:00
3d767c3e13 Switch to a Java-based test generator, which seems to work better. 2018-05-06 21:22:10 -07:00
a2b4baa087 Initial DSA support.
Should be upgraded with faster modulo operations and a
more full test suite.
2018-05-05 21:06:11 -07:00
213c75ad51 Add some #[ignore]s for the longer-running tests. 2018-05-05 19:47:59 -07:00
29a14b39e6 Fix the bits() implementation, and add is_multiple_of() and gcd(). 2018-05-05 19:42:21 -07:00
c34629aa47 Add conversions for BigInt/BigUint. 2018-05-05 19:41:30 -07:00
b01c59a094 I've started playing with IDEs, let's ignore their leavings. 2018-05-05 19:38:48 -07:00
fa04efa5fe Encryption! With test cases. 2018-05-02 17:05:17 -07:00
bd0ddd848b A very slightly faster modexp. 2018-05-01 23:04:06 -07:00
9c60a3bc3e Ignore the Haskell executable I generated. 2018-05-01 22:31:04 -07:00
7c28727f73 RSA signature verification. 2018-05-01 22:30:07 -07:00
c9092ffe6a Slightly better test generation for RSA signatures. 2018-05-01 22:29:37 -07:00
296bb6ad90 Remove an unnecessary mut. 2018-05-01 22:28:59 -07:00
d9df506920 Start with RSA signing! Looks like it works against Haskell RSA test vectors. 2018-04-30 13:05:57 -07:00
2eacea8ff9 Factor out the testing code, so we can use it later. 2018-04-30 13:05:10 -07:00
153d88237f Clean up (and make a lot more flexible) the code to translate to/from bytes. 2018-04-30 13:04:46 -07:00
5758b6e22b Factor out the gold testing infrastructure so we can use it elsewhere. 2018-04-23 20:31:02 -07:00
baa70a6ce6 Starting to include RSA crypto. 2018-04-14 10:45:11 -07:00
b5a5cbdd98 Serialization routines. 2018-04-14 07:56:03 -07:00
4985426e74 Prospective prime support. 2018-04-14 07:16:50 -07:00
c45235473a Support modular inverses. 2018-04-14 07:05:57 -07:00
b1c659087d Add a quick test to ensure that our GCD algorithm works. 2018-04-14 07:01:59 -07:00
0d08f53d70 Make sure we print 0. 2018-04-14 06:59:49 -07:00
109e23789a Support fast modular exponentiation for when your base is roughly the same order of magnitude as the modulo. 2018-04-13 11:51:39 -04:00
551ebeac3b Fix some println!() leavings. 2018-04-13 11:06:42 -04:00
017392ff6c Fix the conversion functions, make sure we can do usize, too. 2018-04-13 10:57:22 -04:00
d98baa1381 Fix Barrett reduction. 2018-04-13 10:56:59 -04:00
330dabe017 Shift the gold testing infrastructure into its own module, and add the Haskell program I used to generate the tests. 2018-04-13 10:56:42 -04:00
675f8adc7e [BROKEN] Division seems to be broken? Might need better test vectors. 2018-04-05 18:02:03 -07:00
5868553c74 First whack at prime numbers and such. 2018-04-04 17:27:07 -07:00
ceb1e9eb58 Fix some shifting issues. 2018-04-04 17:26:49 -07:00
3cd37a881d First whack at modular inverses. 2018-04-04 18:47:02 -04:00
2f16a45784 Quickcheck properties for signed numbers. 2018-04-04 18:28:01 -04:00
f06f83583f Whoops. Don't correct for rounding if there's no remainder on the division. 2018-04-04 18:13:50 -04:00
ae6a33f4b8 Support negation for signed numbers. 2018-04-04 18:12:30 -04:00
8a4693d30d Zero is a problem for me. 2018-04-04 17:57:11 -04:00
20592a3d65 I guess i128_type isn't stable in the beta after all. 2018-04-03 07:04:38 -04:00
acda294bac Signed numbers! 2018-04-02 16:36:28 -04:00
c4409d9c25 Fix some printlns and other bad bits. 2018-04-02 15:26:41 -04:00
ec0f0dc597 Add support for gold value testing, as well, and test some stuff. 2018-04-02 15:26:16 -04:00
80f57b9f22 Fix division by not returning a weirdly-shifted remainder when the quotient is zero. 2018-04-02 15:24:48 -04:00
fa33de88db Fix subtraction. 2018-04-02 15:23:38 -04:00
b92b47d971 [BROKEN] First crach at division. 2018-04-01 20:43:19 -07:00
a4e65fa35f Fix multiplication when either argument is zero. 2018-04-01 20:42:49 -07:00
30bff2a22f Multiplication. 2018-03-31 21:25:10 -07:00
185881df91 Addition and subtraction. 2018-03-31 18:03:17 -07:00
824718eafc Also now enable beta builds in the Travis file. 2018-03-29 21:45:14 -07:00
bfdede4241 Remove the i128 feature, as it's now good in nightlies. 2018-03-29 21:26:15 -07:00
d6c59b5037 Fix shifts! 2018-03-29 21:25:51 -07:00
fd9254a322 [BROKEN] Broken definitions of the shift operators. 2018-03-27 17:02:54 -07:00
f9b25ab03a Add lowercase hex formatting. 2018-03-25 20:18:13 -07:00
d53cdb6c97 And, or, and xor. 2018-03-25 20:14:25 -07:00
a595eb349d Negation. 2018-03-24 16:00:02 -07:00
03765c2ff6 Shrink to clean. 2018-03-24 15:56:02 -07:00
edd7c7fee3 Add a shrink function to clean up 0s at the end of numbers. 2018-03-24 13:06:50 -07:00
6b9783c69a Comparisons! 2018-03-24 12:03:29 -07:00
9c4ea7ae26 Start working variable-length numbers. 2018-03-23 22:12:34 -07:00
7a8bb7b4fd Nevermind on the whole fixed size thing? 2018-03-23 22:11:09 -07:00
285 changed files with 377035 additions and 350512 deletions

21
.gitignore vendored
View File

@@ -11,16 +11,17 @@ Cargo.lock
# And these are just annoying
.DS_Store
.vscode
# Ignore testing files
**/*.o
**/*.hi
**/gen
**/.cabal-sandbox
# And some Haskell stuff, because I can't shake it!
**/cabal.sandbox.config
FlameGraph
*.user_stacks
**/.ghc.environment.*
**/.cabal-sandbox
test.ed25519
# Test generation leavings
**/*.hi
**/*.o
**/gen
**/*.class
**/*.jar
# And I started playing with IDEs, so ...
.vscode

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "cryptonum"]
path = cryptonum
url = https://github.com/acw/cryptonum.git

View File

@@ -3,7 +3,6 @@ rust:
- stable
- beta
- nightly
matrix:
allow_failures:
- nightly
fast_finish: true
script:
- cargo build --verbose
- travis_wait 25 cargo test --verbose

View File

@@ -9,23 +9,20 @@ license-file = "LICENSE"
repository = "https://github.com/acw/simple_crypto"
[dependencies]
base64 = "^0.10.1"
byteorder = "^1.3.1"
chrono = "^0.4.6"
cryptonum = { path = "cryptonum" }
num = "^0.2.0"
rand = "^0.6.5"
simple_asn1 = "^0.2.0"
base64 = "^0.9.1"
digest = "^0.7.1"
hmac = "^0.5.0"
num = "^0.1.42"
rand = "^0.3"
sha-1 = "^0.7.0"
sha2 = "^0.7.0"
simple_asn1 = "^0.1.0"
[dev-dependencies]
quickcheck = "^0.7.2"
[profile.dev]
opt-level = 1
overflow-checks = false
quickcheck = "^0.4.1"
[profile.test]
opt-level = 2
debug = true
debug-assertions = true
overflow-checks = false

View File

@@ -1,11 +0,0 @@
- Add negative test cases (RSA, DSA, ECDSA)
- Make Point::double_scalar_mult() not truly awful
- Use std::Default instead of the bespoke default() in Point?
- Run rustfmt on this stuff
- Run clippy on this stuff
- De-macro. Surely some of this stuff could be turned into trait invocations?
- Test cases for key generation
- Better, timing-resistant ECC point math
- Make the x.509 library not terrible
- Ability to generate a SSH public key line / file
- Extend SSH examples with public key reading/writing

Submodule cryptonum deleted from 666378b14b

View File

@@ -0,0 +1,126 @@
macro_rules! derive_arithmetic_operators
{
($type: ident, $cl: ident, $fn: ident, $asncl: ident, $asnfn: ident) => {
impl $asncl for $type {
fn $asnfn(&mut self, other: $type) {
self.$asnfn(&other)
}
}
impl $cl for $type {
type Output = $type;
fn $fn(self, other: $type) -> $type {
let mut res = self.clone();
res.$asnfn(&other);
res
}
}
impl<'a> $cl<&'a $type> for $type {
type Output = $type;
fn $fn(self, other: &$type) -> $type {
let mut res = self.clone();
res.$asnfn(other);
res
}
}
impl<'a> $cl<$type> for &'a $type {
type Output = $type;
fn $fn(self, other: $type) -> $type {
let mut res = self.clone();
res.$asnfn(&other);
res
}
}
impl<'a,'b> $cl<&'a $type> for &'b $type {
type Output = $type;
fn $fn(self, other: &$type) -> $type {
let mut res = self.clone();
res.$asnfn(other);
res
}
}
}
}
macro_rules! derive_shift_operators
{
($type: ident, $asncl: ident, $cl: ident,
$asnfn: ident, $fn: ident,
$base: ident) =>
{
impl $asncl<$base> for $type {
fn $asnfn(&mut self, rhs: $base) {
self.$asnfn(rhs as u64);
}
}
derive_shifts_from_shift_assign!($type, $asncl, $cl,
$asnfn, $fn,
$base);
}
}
macro_rules! derive_shifts_from_shift_assign
{
($type: ident, $asncl: ident, $cl: ident,
$asnfn: ident, $fn: ident,
$base: ident) =>
{
impl $cl<$base> for $type {
type Output = $type;
fn $fn(self, rhs: $base) -> $type {
let mut copy = self.clone();
copy.$asnfn(rhs as u64);
copy
}
}
impl<'a> $cl<$base> for &'a $type {
type Output = $type;
fn $fn(self, rhs: $base) -> $type {
let mut copy = self.clone();
copy.$asnfn(rhs as u64);
copy
}
}
}
}
macro_rules! derive_signed_shift_operators
{
($type: ident, $base: ident, $signed_base: ident) => {
impl ShlAssign<$signed_base> for $type {
fn shl_assign(&mut self, rhs: $signed_base) {
if rhs < 0 {
self.shr_assign(-rhs);
} else {
self.shl_assign(rhs as $base);
}
}
}
impl ShrAssign<$signed_base> for $type {
fn shr_assign(&mut self, rhs: $signed_base) {
if rhs < 0 {
self.shl_assign(-rhs);
} else {
self.shr_assign(rhs as $base);
}
}
}
derive_shifts_from_shift_assign!($type, ShlAssign, Shl,
shl_assign, shl, $signed_base);
derive_shifts_from_shift_assign!($type, ShrAssign, Shr,
shr_assign, shr, $signed_base);
}
}

View File

@@ -0,0 +1,85 @@
macro_rules! define_from
{
($type: ident, $base: ident) => {
impl From<$base> for $type {
fn from(x: $base) -> $type {
if x == 0 {
UCN{ contents: Vec::new() }
} else {
UCN{ contents: vec![x as u64] }
}
}
}
}
}
macro_rules! define_signed_from
{
($type: ident, $base: ident, $uns: ident) => {
impl From<$uns> for $type {
fn from(x: $uns) -> $type {
SCN{ negative: false, value: UCN::from(x) }
}
}
impl From<$base> for $type {
fn from(x: $base) -> $type {
let neg = x < 0;
let absx = x.abs();
SCN{ negative: neg, value: UCN::from(absx as $uns) }
}
}
}
}
macro_rules! define_into
{
($type: ident, $base: ident) => {
impl<'a> From<&'a $type> for $base {
fn from(x: &$type) -> $base {
if x.contents.is_empty() {
0
} else {
x.contents[0] as $base
}
}
}
impl From<$type> for $base {
fn from(x: $type) -> $base {
$base::from(&x)
}
}
}
}
macro_rules! define_signed_into
{
($type: ident, $base: ident, $uns: ident) => {
impl<'a> From<&'a $type> for $uns {
fn from(x: &$type) -> $uns {
let res: $uns = $uns::from(&x.value);
if x.negative { 0-res } else { res }
}
}
impl<'a> From<&'a $type> for $base {
fn from(x: &$type) -> $base {
let res: $uns = $uns::from(&x.value);
if x.negative { (0-res) as $base } else { res as $base }
}
}
impl From<$type> for $uns {
fn from(x: $type) -> $uns {
$uns::from(&x)
}
}
impl From<$type> for $base {
fn from(x: $type) -> $base {
$base::from(&x)
}
}
}
}

187
src/cryptonum/gold_tests.rs Normal file
View File

@@ -0,0 +1,187 @@
use cryptonum::unsigned::BarrettUCN;
use testing::{make_signed,make_unsigned,run_test};
#[test]
fn unsigned_sum_test()
{
run_test("tests/math/unsigned_add.tests", 3, |scase| {
let case = make_unsigned(scase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
let res = x + y;
assert_eq!(res, *z);
});
}
#[test]
fn signed_sum_test()
{
run_test("tests/math/signed_add.tests", 3, |bcase| {
let case = make_signed(bcase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x + y, *z);
});
}
#[test]
fn unsigned_sub_test()
{
run_test("tests/math/unsigned_sub.tests", 3, |scase| {
let case = make_unsigned(scase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x - y, *z);
});
}
#[test]
fn signed_sub_test()
{
run_test("tests/math/signed_sub.tests", 3, |bcase| {
let case = make_signed(bcase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x - y, *z);
});
}
#[test]
fn unsigned_mul_test()
{
run_test("tests/math/unsigned_mul.tests", 3, |scase| {
let case = make_unsigned(scase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x * y, *z);
});
}
#[test]
fn signed_mul_test()
{
run_test("tests/math/signed_mul.tests", 3, |bcase| {
let case = make_signed(bcase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x * y, *z);
});
}
#[test]
fn unsigned_div_test()
{
run_test("tests/math/unsigned_div.tests", 3, |scase| {
let case = make_unsigned(scase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x / y, *z);
});
}
#[test]
fn signed_div_test()
{
run_test("tests/math/signed_div.tests", 3, |bcase| {
let case = make_signed(bcase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x / y, *z);
});
}
#[test]
fn unsigned_mod_test()
{
run_test("tests/math/unsigned_mod.tests", 3, |scase| {
let case = make_unsigned(scase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x % y, *z);
});
}
#[test]
fn signed_mod_test()
{
run_test("tests/math/signed_mod.tests", 3, |bcase| {
let case = make_signed(bcase);
let x = case.get("x").unwrap();
let y = case.get("y").unwrap();
let z = case.get("z").unwrap();
assert_eq!(x % y, *z);
});
}
#[test]
#[ignore]
fn modular_exponentiation_test()
{
run_test("tests/math/modexp.tests", 4, |scase| {
let case = make_unsigned(scase);
let a = case.get("a").unwrap();
let b = case.get("b").unwrap();
let m = case.get("m").unwrap();
let z = case.get("z").unwrap();
assert_eq!(a.modexp(&b, &m), *z);
});
}
#[test]
fn fast_modular_exponentiation_test()
{
run_test("tests/math/fastmodexp.tests", 6, |scase| {
let case = make_unsigned(scase);
let a = case.get("a").unwrap();
let b = case.get("b").unwrap();
let kbig = case.get("k").unwrap();
let k = usize::from(kbig);
let m = case.get("m").unwrap();
let u = case.get("u").unwrap();
let z = case.get("z").unwrap();
let mu = BarrettUCN{ k: k, u: u.clone(), m: m.clone() };
assert_eq!(a.fastmodexp(&b, &mu), *z);
});
}
#[test]
fn barrett_reduction_test()
{
run_test("tests/math/barrett.tests", 5, |scase| {
let case = make_unsigned(scase);
let kbig = case.get("k").unwrap();
let m = case.get("m").unwrap();
let r = case.get("r").unwrap();
let u = case.get("u").unwrap();
let v = case.get("v").unwrap();
let k = usize::from(kbig);
let barrett = m.barrett_u();
let result = v.reduce(&barrett);
assert_eq!(barrett.k, k);
assert_eq!(&barrett.u, u);
assert_eq!(&barrett.m, m);
assert_eq!(&result, r);
});
}
#[test]
fn modular_inverse_test()
{
run_test("tests/math/modinv.tests", 3, |scase| {
let case = make_unsigned(scase);
let a = case.get("x").unwrap();
let m = case.get("y").unwrap();
let r = case.get("z").unwrap();
let result = a.modinv(m);
assert_eq!(r, &result);
});
}

13
src/cryptonum/mod.rs Normal file
View File

@@ -0,0 +1,13 @@
#[macro_use]
mod conversions;
#[macro_use]
mod complete_arith;
mod primes;
mod signed;
mod unsigned;
#[cfg(test)]
mod gold_tests;
pub use self::signed::SCN;
pub use self::unsigned::{BarrettUCN,UCN};
pub use self::primes::*;

139
src/cryptonum/primes.rs Normal file
View File

@@ -0,0 +1,139 @@
use cryptonum::unsigned::UCN;
use rand::Rng;
static SMALL_PRIMES: [u32; 310] = [
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013,
1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069,
1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223,
1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373,
1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451,
1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511,
1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583,
1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657,
1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811,
1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889,
1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987,
1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053];
impl UCN {
pub fn generate_prime<F,G>(rng: &mut G,
bitlen: usize,
iterations: usize,
check_value: F)
-> UCN
where
G: Rng,
F: Fn(UCN) -> Option<UCN>
{
let one = UCN::from(1 as u8);
assert!((bitlen % 64) == 0);
loop {
let base = random_number(rng, bitlen);
let candidate = base | &one;
if let Some(proposed) = check_value(candidate) {
if proposed.probably_prime(rng, bitlen, iterations) {
return proposed;
}
}
}
}
fn probably_prime<G: Rng>(&self, g: &mut G, size: usize, iters: usize)
-> bool
{
for tester in SMALL_PRIMES.iter() {
if (self % UCN::from(*tester)).is_zero() {
return false;
}
}
miller_rabin(g, &self, size, iters)
}
}
fn miller_rabin<G: Rng>(g: &mut G, n: &UCN, size: usize, iters: usize) -> bool {
let one = UCN::from(1 as u8);
let two = UCN::from(2 as u8);
let nm1 = n - &one;
// Quoth Wikipedia:
// write n - 1 as 2^r*d with d odd by factoring powers of 2 from n - 1
let mut d = nm1.clone();
let mut r = 0;
while d.is_even() {
d >>= 1;
r += 1;
assert!(r < n.bits());
}
// WitnessLoop: repeat k times
'WitnessLoop: for _k in 0..iters {
// pick a random integer a in the range [2, n - 2]
let a = random_in_range(g, size, &two, &nm1);
// x <- a^d mod n
let mut x = a.modexp(&d, &n);
// if x = 1 or x = n - 1 then
if (&x == &one) || (&x == &nm1) {
// continue WitnessLoop
continue 'WitnessLoop;
}
// repeat r - 1 times:
for _i in 0..r {
// x <- x^2 mod n
x = x.modexp(&two, &n);
// if x = 1 then
if &x == &one {
// return composite
return false;
}
// if x = n - 1 then
if &x == &nm1 {
// continue WitnessLoop
continue 'WitnessLoop;
}
}
// return composite
return false;
}
// return probably prime
true
}
fn random_in_range<G: Rng>(rng: &mut G, bitlen: usize, min: &UCN, max: &UCN)
-> UCN
{
loop {
let candidate = random_number(rng, bitlen);
if (&candidate >= min) && (&candidate < max) {
return candidate;
}
}
}
fn random_number<G: Rng>(rng: &mut G, bitlen: usize) -> UCN {
assert!(bitlen % 64 == 0);
let wordlen = bitlen / 64;
let components = rng.gen_iter().take(wordlen).collect();
UCN{ contents: components }
}

406
src/cryptonum/signed.rs Normal file
View File

@@ -0,0 +1,406 @@
use cryptonum::unsigned::{BarrettUCN,UCN,divmod};
use num::BigInt;
use num::bigint::Sign;
use std::fmt;
use std::cmp::Ordering;
use std::fmt::Write;
use std::ops::*;
/// In case you were wondering, it stands for "Signed Crypto Num".
#[derive(Clone,Debug,PartialEq,Eq)]
pub struct SCN {
pub(crate) negative: bool,
pub(crate) value: UCN
}
impl SCN {
pub fn zero() -> SCN {
SCN{ negative: false, value: UCN::zero() }
}
pub fn is_zero(&self) -> bool {
self.value.is_zero()
}
pub fn is_negative(&self) -> bool {
self.negative
}
pub fn from_str(x: &str) -> SCN {
if x.get(0..1) == Some("-") {
SCN{ negative: true, value: UCN::from_str(&x[1..]) }
} else {
SCN{ negative: false, value: UCN::from_str(x) }
}
}
fn cleanup(&mut self) {
if self.value.is_zero() {
self.negative = false;
}
}
pub fn egcd(self, b: SCN) -> (SCN, SCN, SCN) {
let mut s = SCN::zero();
let mut old_s = SCN::from(1 as u8);
let mut t = SCN::from(1 as u8);
let mut old_t = SCN::zero();
let mut r = b;
let mut old_r = self;
while !r.is_zero() {
let quotient = old_r.clone() / r.clone();
let prov_r = r.clone();
let prov_s = s.clone();
let prov_t = t.clone();
r = old_r - (r * &quotient);
s = old_s - (s * &quotient);
t = old_t - (t * &quotient);
old_r = prov_r;
old_s = prov_s;
old_t = prov_t;
}
(old_r, old_s, old_t)
}
pub fn reduce(&self, m: &BarrettUCN) -> SCN {
println!("signed reduce");
SCN{ negative: false, value: self.value.reduce(m) }
}
pub fn divmod(&self, x: &SCN, m: &BarrettUCN) -> SCN {
println!("STEP1");
let xmod = x.reduce(m);
println!("STEP2");
assert!(!xmod.negative);
println!("STEP3");
let i = xmod.value.modinv(&m.m);
println!("STEP4");
let si = SCN::from(i);
println!("STEP5");
let yi = self * si;
println!("STEP6: {:X}", yi);
println!(" mod {:X}", m.m);
let res = yi.reduce(m);
println!("STEP7");
res
}
}
impl fmt::UpperHex for SCN {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(),fmt::Error> {
if self.negative {
fmt.write_char('-')?;
}
self.value.fmt(fmt)
}
}
//------------------------------------------------------------------------------
//
// Conversions to/from crypto nums.
//
//------------------------------------------------------------------------------
define_signed_from!(SCN, i8, u8);
define_signed_from!(SCN, i16, u16);
define_signed_from!(SCN, i32, u32);
define_signed_from!(SCN, i64, u64);
define_signed_into!(SCN, i8, u8);
define_signed_into!(SCN, i16, u16);
define_signed_into!(SCN, i32, u32);
define_signed_into!(SCN, i64, u64);
impl From<UCN> for SCN {
fn from(x: UCN) -> SCN {
SCN{ negative: false, value: x }
}
}
impl Into<UCN> for SCN {
fn into(self) -> UCN {
self.value
}
}
impl From<SCN> for BigInt {
fn from(x: SCN) -> BigInt {
let sign = if x.is_negative() { Sign::Minus } else { Sign::Plus };
let numbytes = x.value.contents.len() * 8;
let bytes = x.value.to_bytes(numbytes);
BigInt::from_bytes_be(sign, &bytes)
}
}
//------------------------------------------------------------------------------
//
// Comparisons
//
//------------------------------------------------------------------------------
impl PartialOrd for SCN {
fn partial_cmp(&self, other: &SCN) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for SCN {
fn cmp(&self, other: &SCN) -> Ordering {
match (self.negative, other.negative) {
(false, false) => self.value.cmp(&other.value),
(false, true) => Ordering::Greater,
(true, false) => Ordering::Less,
(true, true) => self.value.cmp(&other.value).reverse()
}
}
}
//------------------------------------------------------------------------------
//
// Shifts
//
//------------------------------------------------------------------------------
impl ShlAssign<u64> for SCN {
fn shl_assign(&mut self, rhs: u64) {
self.value <<= rhs;
}
}
impl Shl<u64> for SCN {
type Output = SCN;
fn shl(self, rhs: u64) -> SCN {
let mut copy = self.clone();
copy.shl_assign(rhs);
copy
}
}
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, usize);
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u32);
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u16);
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u8);
impl ShrAssign<u64> for SCN {
fn shr_assign(&mut self, rhs: u64) {
self.value >>= rhs;
}
}
impl Shr<u64> for SCN {
type Output = SCN;
fn shr(self, rhs: u64) -> SCN {
let mut copy = self.clone();
copy.shr_assign(rhs);
copy
}
}
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, usize);
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u32);
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u16);
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u8);
derive_signed_shift_operators!(SCN, usize, isize);
derive_signed_shift_operators!(SCN, u64, i64);
derive_signed_shift_operators!(SCN, u32, i32);
derive_signed_shift_operators!(SCN, u16, i16);
derive_signed_shift_operators!(SCN, u8, i8);
//------------------------------------------------------------------------------
//
// Arithmetic
//
//------------------------------------------------------------------------------
impl Neg for SCN {
type Output = SCN;
fn neg(self) -> SCN {
if self.is_zero() {
self
} else {
SCN{ negative: !self.negative, value: self.value }
}
}
}
impl<'a> Neg for &'a SCN {
type Output = SCN;
fn neg(self) -> SCN {
if self.is_zero() {
self.clone()
} else {
SCN{ negative: !self.negative, value: self.value.clone() }
}
}
}
impl<'a> AddAssign<&'a SCN> for SCN {
fn add_assign(&mut self, rhs: &SCN) {
if self.negative == rhs.negative {
self.value.add_assign(&rhs.value);
} else {
if self.value >= rhs.value {
self.value.sub_assign(&rhs.value);
} else {
self.negative = !self.negative;
self.value = &rhs.value - &self.value;
}
}
self.cleanup();
}
}
impl<'a> SubAssign<&'a SCN> for SCN {
fn sub_assign(&mut self, rhs: &SCN) {
let flipped = SCN{ negative: !rhs.negative, value: rhs.value.clone() };
self.add_assign(&flipped);
self.cleanup();
}
}
impl<'a> MulAssign<&'a SCN> for SCN {
fn mul_assign(&mut self, rhs: &SCN) {
self.negative ^= rhs.negative;
self.value.mul_assign(&rhs.value);
self.cleanup();
}
}
impl<'a> DivAssign<&'a SCN> for SCN {
fn div_assign(&mut self, rhs: &SCN) {
self.negative ^= rhs.negative;
// rounding makes me grumpy
let mut remainder = Vec::new();
let copy = self.value.contents.clone();
divmod(&mut self.value.contents, &mut remainder,
&copy, &rhs.value.contents);
if self.negative && !remainder.is_empty() {
let one = UCN{ contents: vec![1] };
self.sub_assign(SCN{ negative: false, value: one});
}
self.cleanup();
}
}
impl<'a> RemAssign<&'a SCN> for SCN {
fn rem_assign(&mut self, rhs: &SCN) {
let base = &self.value % &rhs.value;
if self.negative == rhs.negative {
self.value = base;
} else {
self.negative = rhs.negative;
self.value = &rhs.value - &base;
}
self.cleanup();
}
}
derive_arithmetic_operators!(SCN, Add, add, AddAssign, add_assign);
derive_arithmetic_operators!(SCN, Sub, sub, SubAssign, sub_assign);
derive_arithmetic_operators!(SCN, Mul, mul, MulAssign, mul_assign);
derive_arithmetic_operators!(SCN, Div, div, DivAssign, div_assign);
derive_arithmetic_operators!(SCN, Rem, rem, RemAssign, rem_assign);
//------------------------------------------------------------------------------
//
// Tests!
//
//------------------------------------------------------------------------------
#[cfg(test)]
mod test {
use quickcheck::{Arbitrary,Gen};
use super::*;
impl Arbitrary for SCN {
fn arbitrary<G: Gen>(g: &mut G) -> SCN {
let neg = (g.next_u32() & 1) == 1;
SCN{ negative: neg, value: UCN::arbitrary(g) }
}
}
fn one() -> SCN {
SCN{ negative: false, value: UCN::from(1 as u8) }
}
quickcheck! {
fn additive_identity(x: SCN) -> bool {
(&x + &SCN::zero()) == x
}
fn subtractive_identity(x: SCN) -> bool {
(&x - &SCN::zero()) == x
}
fn multiplicative_identity(x: SCN) -> bool {
(&x * &one()) == x
}
fn division_identity(x: SCN) -> bool {
let result = &x / &one();
result == x
}
fn additive_destructor(x: SCN) -> bool {
(&x + (- &x)) == SCN::zero()
}
fn subtractive_destructor(x: SCN) -> bool {
(&x - &x) == SCN::zero()
}
fn multiplicative_destructor(x: SCN) -> bool {
(x * SCN::zero()) == SCN::zero()
}
fn division_deastructor(x: SCN) -> bool {
(&x / &x) == one()
}
fn remainder_destructor(x: SCN) -> bool {
(&x % &x) == SCN::zero()
}
fn addition_commutes(a: SCN, b: SCN) -> bool {
(&a + &b) == (&b + &a)
}
fn multiplication_commutes(a: SCN, b: SCN) -> bool {
(&a * &b) == (&b * &a)
}
fn addition_associates(a: SCN, b: SCN, c: SCN) -> bool {
((&a + &b) + &c) == (&a + (&b + &c))
}
fn multiplication_associates(a: SCN, b: SCN, c: SCN) -> bool {
((&a * &b) * &c) == (&a * (&b * &c))
}
fn distribution_works(a: SCN, b: SCN, c: SCN) -> bool {
(&a * (&b + &c)) == ((&a * &b) + (&a * &c))
}
fn negation_works(a: SCN) -> bool {
(- &a) == (&a * &SCN{ negative: true, value: UCN::from(1 as u8) })
}
fn double_negation_works(a: SCN) -> bool {
(- (- &a)) == a
}
fn negation_commutes(a: SCN, b: SCN) -> bool {
((- &a) * &b) == (&a * (- &b))
}
fn negation_cancels(a: SCN, b: SCN) -> bool {
((- &a) * (- &b)) == (&a * &b)
}
fn negation_distributes(a: SCN, b: SCN) -> bool {
(- (&a + &b)) == ((- &a) + (- &b))
}
}
quickcheck! {
fn egcd_works(a: SCN, b: SCN) -> bool {
let (d, x, y) = a.clone().egcd(b.clone());
((a * x) + (b * y)) == d
}
}
}

1304
src/cryptonum/unsigned.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,10 @@
use simple_asn1::ASN1DecodeErr;
use rand;
use std::io;
#[derive(Debug)]
pub enum DSAError {
RandomGenError(rand::Error),
ASN1DecodeErr(ASN1DecodeErr)
}
impl From<rand::Error> for DSAError {
fn from(e: rand::Error) -> DSAError {
DSAError::RandomGenError(e)
}
ASN1DecodeErr(ASN1DecodeErr),
InvalidParamSize
}
impl From<ASN1DecodeErr> for DSAError {
@@ -18,3 +12,17 @@ impl From<ASN1DecodeErr> for DSAError {
DSAError::ASN1DecodeErr(e)
}
}
#[derive(Debug)]
pub enum DSAGenError {
RngFailure(io::Error),
InvalidSeedLength, InvalidPrimeLength, TooManyGenAttempts
}
impl From<io::Error> for DSAGenError {
fn from(e: io::Error) -> DSAGenError {
DSAGenError::RngFailure(e)
}
}

585
src/dsa/generation.rs Normal file
View File

@@ -0,0 +1,585 @@
use cryptonum::{BarrettUCN,UCN};
use digest::{FixedOutput,Input};
use dsa::errors::DSAGenError;
use dsa::parameters::{DSAParameterSize,n_bits,l_bits};
use rand::Rng;
use sha2::Sha256;
use std::ops::{Add,Div,Rem,Sub};
#[derive(Debug,PartialEq)]
pub struct DSAGenEvidence {
pub first_seed: UCN,
pub p_seed: UCN,
pub q_seed: UCN,
pub pgen_counter: usize,
pub qgen_counter: usize
}
fn get_domain_parameter_seed(ev: &DSAGenEvidence) -> Vec<u8> {
let mut output = Vec::new();
let fssize = (ev.first_seed.bits() + 7) / 8;
output.append(&mut ev.first_seed.to_bytes(fssize));
let psize = (ev.p_seed.bits() + 7) / 8;
output.append(&mut ev.p_seed.to_bytes(psize));
let qsize = (ev.q_seed.bits() + 7) / 8;
output.append(&mut ev.q_seed.to_bytes(qsize));
output
}
pub fn generate_provable_primes<G: Rng>(rng: &mut G,
firstseed: &UCN,
ps: DSAParameterSize)
-> Result<(UCN, UCN, DSAGenEvidence),DSAGenError>
{
let one: UCN = UCN::from(1u64);
let two: UCN = UCN::from(2u64);
let three: UCN = UCN::from(3u64);
// See Page 38 of FIPS 186-4!
let n = n_bits(ps);
let l = l_bits(ps);
// 1. Check that the (L, N) pair is in the list of acceptable (L, N) pairs
// (see Section 4.2). If the pair is not in the list, return FAILURE.
//
// Done because sum types are cool.
//
// 2. Using N as the length and firstseed as the input_seed, use the random
// prime generation routine in Appendix C.6 to obtain q, qseed and
// qgen_counter. If FAILURE is returned, then return FAILURE.
let (q, qseed, qgen_counter) = shawe_taylor(rng, n, &firstseed)?;
// 3. Using ceiling(L / 2 + 1) as the length and qseed as the input_seed,
// use the random prime generation routine in Appendix C.6 to obtain
// p0, pseed, and pgen_counter. If FAILURE is returned, then return
// FAILURE.
//
// NOTE: The ceiling isn't required. All of the values of L divide
// evenly by 2, so it's just l / 2 + 1. I'm not sure why the
// spec mentions it, frankly.
let (p0, mut pseed, mut pgen_counter) = shawe_taylor(rng, l/2 + 1, &qseed)?;
// 4. iterations = ceiling(L / outlen) - 1.
let iterations = ceildiv(&l, &256) - 1;
// 5. old_counter = pgen_counter.
let old_counter = pgen_counter;
// 6. x = 0.
let mut x_bytes = Vec::new();
// 7. For i = 0 to iterations fo
// x + x + (Hash(pseed + i) * 2^(i * outlen).
// NOTE: WE run this backwards, much like we do in shawe_taylor()
let mut i: i64 = iterations as i64;
while i >= 0 {
let bigi = UCN::from(i as u64);
let prime_i = &pseed + &bigi;
let mut hash_i = hash(&prime_i, l);
x_bytes.append(&mut hash_i);
i -= 1;
}
let x = UCN::from_bytes(&x_bytes);
// 8. pseed = pseed + iterations + 1.
pseed = &pseed + UCN::from(iterations) + &one;
// 9. x = 2^(L-1) + (x mod 2^(L-1));
let twol1: UCN = &one << (l - 1);
// 10. t = ceiling(x / (2 * q * p_0))
let twoqp0 = &two * &q * &p0;
let mut t = ceildiv(&x, &twoqp0);
loop {
// 11. If (2tqp_0 + 1) > 2^L, then t = ceiling(2^(L-1)/2qp0).
let twotqp0p1 = (&t * &twoqp0) + &one;
let twol = &one << l;
if &twotqp0p1 > &twol {
t = ceildiv(&twol1, &twoqp0);
}
// 12. p = 2tqp_0 + 1
let p = twotqp0p1;
// 13. pgen_counter = pgen_counter + 1
pgen_counter = &pgen_counter + 1;
// 14. a = 0
let mut a_bytes = Vec::new();
// 15. For i = 0 to iterations do
// a = a + (Hash(pseed + i) * 2^(i*outlen).
i = iterations as i64;
while i >= 0 {
let bigi = UCN::from(i as u64);
let prime_i = &pseed + &bigi;
let mut hash_i = hash(&prime_i, l);
a_bytes.append(&mut hash_i);
i -= 1;
}
let mut a = UCN::from_bytes(&a_bytes);
// 16. pseed = pseed + iterations + 1.
pseed = &pseed + UCN::from(iterations) + &one;
// 17. a = 2 + (a mod (p - 3))
let pm3 = &p - &three;
let amodpm3 = &a % &pm3;
a = &two + &amodpm3;
// 18. z = a^(2tq) mod p.
let twotq = &two * &t * &q;
let z = a.modexp(&twotq, &p);
// 19. If ((1 = GCD(z-1,p)) and (1 = z^p0 mod p)), then return SUCCESS
// and the values of p, q, and (optionally) pseed, qseed, pgen_counter,
// and qgen_counter.
let zm1 = &z - &one;
if (&one == &zm1.gcd(&p)) && (&one == &z.modexp(&p0, &p)) {
let evidence = DSAGenEvidence {
first_seed: firstseed.clone(),
p_seed: pseed,
q_seed: qseed,
pgen_counter: pgen_counter,
qgen_counter: qgen_counter
};
return Ok((p, q, evidence));
}
// 20. If (pgen_counter > (4L + old_counter)), then return FAILURE.
if pgen_counter > ((4 * l) + old_counter) {
return Err(DSAGenError::TooManyGenAttempts);
}
// 21. t = t + 1
t = &t + &one;
// 22. Go to step 11.
}
}
pub fn validate_provable_primes<G: Rng>(rng: &mut G,
p: &UCN, q: &UCN,
ev: &DSAGenEvidence)
-> bool
{
let one = UCN::from(1u64);
// This is from Page 40 of 186-4, section A.1.2.2.
// 1. L = len(p);
let l = ((p.bits() + 255) / 256) * 256;
// 2. N = len(q);
let n = ((q.bits() + 15) / 16) * 16;
// 3. Check that the (L, N) pair is in the list of acceptable (L, N) pairs.
// If the pair is not in the list, then return failure.
let params = match (l, n) {
(1024, 160) => DSAParameterSize::L1024N160,
(2048, 224) => DSAParameterSize::L2048N224,
(2048, 256) => DSAParameterSize::L2048N256,
(3072, 256) => DSAParameterSize::L3072N256,
_ => return false
};
// 4. If (firstseed < 2^(n-1), then return FAILURE.
let twon1 = &one << (n - 1);
if &ev.first_seed < &twon1 {
return false;
}
// 5. If (2^n <= q), then return FAILURE.
let twon = &one << n;
if &twon <= q {
return false;
}
// 6. If (2^l <= p), then return FAILURE.
let twol = &one << l;
if &twol <= p {
return false;
}
// 7. If ((p - 1) mod q /= 0), then return FAILURE.
let pm1 = p - &one;
if !pm1.rem(q).is_zero() {
return false;
}
// 8. Using L, N and firstseed, perform the constructive prime generation
// procedure in Appendix A.1.2.1.2 to obtain p_val, q_val, pseed_val,
// qseed_val, pgen_counter_val, and qgen_counter_val. If FAILURE is
// returned, or if (q_val ≠ q) or (qseed_val ≠ qseed) or
// (qgen_counter_val ≠ qgen_counter) or (p_val ≠ p) or (pseed_val ≠
// pseed) or (pgen_counter_val ≠ pgen_counter), then return FAILURE.
match generate_provable_primes(rng, &ev.first_seed, params) {
Err(_) => false,
Ok((p_val, q_val, ev2)) => {
// 9. Return SUCCESS
(&q_val == q) && (&p_val == p) && (ev == &ev2)
}
}
}
pub fn generate_verifiable_generator(p: &UCN, pu: &BarrettUCN,
q: &UCN,
ev: &DSAGenEvidence,
index: u8)
-> Result<UCN,DSAGenError>
{
// See FIPS 186-4, Section A.2.3: Verifiable Canonical Generatio of the
// Generator g
let one = UCN::from(1u64);
let two = UCN::from(2u64);
// 1. If (index is incorrect), then return INVALID.
// NOTE: Can't happen, because types.
// 2. N = len(q)
let _n = q.bits();
// 3. e = (p - 1)/q.
let e = (p - &one) / q;
// 4. count = 0.
let mut count: u16 = 0;
loop {
// 5. count = count + 1;
count = count + 1;
// 6. if (count = 0), then return INVALID.
if count == 0 {
return Err(DSAGenError::TooManyGenAttempts);
}
// 7. U = domain_parameter_seed || "ggen" || index || count
// Comment: "ggen" is the bit string 0x6767656E.
let mut u = get_domain_parameter_seed(&ev);
u.push(0x67); u.push(0x67); u.push(0x65); u.push(0x6E);
u.push(index);
u.push((count >> 8) as u8); u.push((count & 0xFF) as u8);
// 8. W = hash(U)
let mut dgst = Sha256::default();
dgst.process(&u);
let w = UCN::from_bytes(dgst.fixed_result().as_slice());
// 9. g = W^e mod p
let g = w.fastmodexp(&e, &pu);
// 10. if (g < 2), then go to step 5.
if &g >= &two {
// 11. Return VALID and the value of g.
return Ok(g);
}
}
}
pub fn verify_generator(p: &UCN, q: &UCN, ev: &DSAGenEvidence,
index: u8, g: &UCN)
-> bool
{
// FIPS 186.4, Section A.2.4!
let one = UCN::from(1u64);
let two = UCN::from(2u64);
// 1. If (index is incorrect), then return INVALID.
// NOTE: Not sure how this can be invalid.
// 2. Verify that 2 <= g <= (p - 1). If not true, return INVALID.
if g < &two {
return false;
}
if g >= p {
return false;
}
// 3. If (g^q /= 1 mod p), then return INVALID.
if g.modexp(q, p) != one {
return false;
}
// 4. N = len(q)
// let n = ((q.bits() + 15) / 15) * 15;
// 5. e = (p - 1) / q
let e = (p - &one) / q;
// 6. count = 0
let mut count: u16 = 0;
loop {
// 7. count = count + 1
count = count + 1;
// 8. if (count == 0), then return INVALID
if count == 0 {
return false;
}
// 9. U = domain_parameter_seed || "ggen" || index || count.
let mut u = get_domain_parameter_seed(&ev);
u.push(0x67); u.push(0x67); u.push(0x65); u.push(0x6E);
u.push(index);
u.push((count >> 8) as u8); u.push((count & 0xFF) as u8);
// 10. W = Hash(U)
let mut dgst = Sha256::default();
dgst.process(&u);
let w = UCN::from_bytes(dgst.fixed_result().as_slice());
// 11. computed_g = W^e mod p
let computed_g = w.modexp(&e, &p);
// 12. if (computed_g < 2), then go to step 7.
if &computed_g < &two {
continue;
}
// 13. if (computed_g == g), then return VALID, else return INVALID
return &computed_g == g;
}
}
pub fn get_input_seed<G: Rng>(rng: &mut G,
size: DSAParameterSize,
seedlen: usize)
-> Result<UCN,DSAGenError>
{
let mut firstseed = UCN::from(0u64);
let one = UCN::from(1u64);
let n = n_bits(size);
// 3. If (seedlen < N), then return FAILURE
if seedlen < n {
return Err(DSAGenError::InvalidSeedLength)
}
// 4. While firstseed < 2^(n-1) ...
let twonm1 = one << (n - 1);
while &firstseed < &twonm1 {
// Get an arbitrary sequence of seedlen bits as firstseed.
let bytes: Vec<u8> = rng.gen_iter().take(seedlen / 8).collect();
firstseed = UCN::from_bytes(&bytes);
}
// 5. Return SUCCESS and the value of firstseed
Ok(firstseed)
}
// Appendix C.6: Shawe-Taylor Random_Prime Routine. Also referenced in 186-4
// as ST_Random_Prime, so when you see that in a bit, understand that it's a
// recursive call.
fn shawe_taylor<G: Rng>(rng: &mut G, length: usize, input_seed: &UCN)
-> Result<(UCN,UCN,usize),DSAGenError>
{
// 1. If (length < 2), then return (FAILURE, 0, 0 {, 0}).
if length < 2 {
return Err(DSAGenError::InvalidPrimeLength);
}
// 2. If (length ≥ 33), then go to step 14.
if length >= 33 {
shawe_taylor_large(rng, length, input_seed)
} else {
shawe_taylor_small(length, input_seed)
}
}
fn shawe_taylor_small(length: usize, input_seed: &UCN)
-> Result<(UCN,UCN,usize),DSAGenError>
{
let one = UCN::from(1u64);
let two = UCN::from(2u64);
// 3. prime_seed = input_seed.
let mut prime_seed: UCN = input_seed.clone();
// 4. prime_gen_counter = 0
let mut prime_gen_counter = 0;
loop {
// 5. c = Hash(prime_seed) ⊕ Hash(prime_seed + 1).
let cbs = xorvecs(hash(&prime_seed, length),
hash(&(&prime_seed + &one), length));
let mut c = UCN::from_bytes(&cbs);
// 6. c = 2^(length 1) + (c mod 2^(length 1))
let twolm1: UCN = &one << (length - 1);
c = &twolm1 + (c % &twolm1);
// 7. c = (2 floor(c / 2)) + 1.
c = ((c >> 1) << 1) + &one;
// 8. prime_gen_counter = prime_gen_counter + 1.
prime_gen_counter = prime_gen_counter + 1;
// 9. prime_seed = prime_seed + 2.
prime_seed = prime_seed + &two;
// 10. Perform a deterministic primality test on c. For example, since
// c is small, its primality can be tested by trial division. See
// Appendix C.7.
let c_is_prime = prime_test(&c);
// 11. If (c is a prime number), then
if c_is_prime {
// 11.1 prime = c.
let prime = c;
// 11.2 Return (SUCCESS, prime, prime_seed {, prime_gen_counter}).
return Ok((prime, prime_seed.clone(), prime_gen_counter))
}
// 12. If (prime_gen_counter > (4 length)), then
// return (FAILURE, 0, 0 {, 0}).
if prime_gen_counter > (4 * length) {
return Err(DSAGenError::TooManyGenAttempts);
}
// 13. Go to step 5.
}
}
fn shawe_taylor_large<G: Rng>(rng: &mut G, length: usize, input_seed: &UCN)
-> Result<(UCN,UCN,usize),DSAGenError>
{
let one = UCN::from(1u64);
let two = UCN::from(2u64);
let three = UCN::from(3u64);
// 14. (status, c0, prime_seed, prime_gen_counter) =
// (ST_Random_Prime ((ceiling(length / 2) + 1), input_seed).
let len2: usize = ceildiv(&length, &2);
let (c0, mut prime_seed, mut prime_gen_counter) =
shawe_taylor( rng, len2 + 1, input_seed )?;
// 15. If FAILURE is returned, return (FAILURE, 0, 0 {, 0}).
// 16. iterations = ceiling(length / outlen) 1.
let outlen = 256; // the size of the hash function output in bits
let iterations = ceildiv(&length, &outlen) - 1;
// 17. old_counter = prime_gen_counter.
let old_counter = prime_gen_counter;
// 18. x = 0.
let mut x_bytes = Vec::new();
// 19. For i = 0 to iterations do
// x = x + (Hash(prime_seed + i) 2^(i * outlen)).
//
// We're going to actually run this backwards. What this computation
// does is essentially built up a large vector of hashes, one per
// iteration, shifting them bast each other via the 2^(i * outlen)
// term. So we'll just do this directly.
let mut i: i64 = iterations as i64;
while i >= 0 {
let bigi = UCN::from(i as u64);
let prime_i = &prime_seed + &bigi;
let mut hash_i = hash(&prime_i, length);
x_bytes.append(&mut hash_i);
i -= 1;
}
let mut x = UCN::from_bytes(&x_bytes);
// 20. prime_seed = prime_seed + iterations + 1.
prime_seed = &prime_seed + UCN::from(iterations) + &one;
// 21. x = 2^(length 1) + (x mod 2^(length 1)).
let twolm1 = &one << (length - 1);
x = &twolm1 + (&x % &twolm1);
// 22. t = ceiling(x / (2c0)).
let twoc0 = &two * &c0;
let mut t: UCN = ceildiv(&x, &twoc0);
loop {
// 23. If (2tc0 + 1 > 2^length), then
// t = ceiling(2^(length 1) / (2c0)).
let twotc0 = &t * &twoc0;
if (&twotc0 + &one) > (&one << length) {
t = ceildiv(&twolm1, &twoc0);
}
// 24. c = 2tc0 + 1.
let c = &twotc0 + &one;
// 25. prime_gen_counter = prime_gen_counter + 1.
prime_gen_counter = prime_gen_counter + 1;
// 26. a = 0.
let mut a_bytes = Vec::new();
// 27. For i = 0 to iterations do
// a = a + (Hash(prime_seed + i) 2 i * outlen).
//
// As with the last time we did this, we're going to do this more
// constructively
i = iterations as i64;
while i >= 0 {
let bigi = UCN::from(i as u64);
let prime_i = &prime_seed + &bigi;
let mut hash_i = hash(&prime_i, length);
a_bytes.append(&mut hash_i);
i -= 1;
}
let mut a = UCN::from_bytes(&a_bytes);
// 28. prime_seed = prime_seed + iterations + 1.
prime_seed = &prime_seed + UCN::from(iterations) + &one;
// 29. a = 2 + (a mod (c 3)).
a = &two + (a % (&c - &three));
// 30. z = a^2t mod c.
let z: UCN = a.modexp(&(&two * &t), &c);
// 31. If ((1 = GCD(z 1, c)) and (1 = z^c_0 mod c)), then
let gcd_ok = &one == &c.gcd(&(&z - &one));
let modexp_ok = &one == &z.modexp(&c0, &c);
if gcd_ok && modexp_ok {
// 31.1 prime = c.
let prime = c;
// 31.2 Return (SUCCESS, prime, prime_seed {, prime_gen_counter}).
return Ok((prime, prime_seed, prime_gen_counter));
}
// 32. If (prime_gen_counter ≥ ((4 length) + old_counter)), then
// return (FAILURE, 0, 0 {, 0}).
let limit = (4 * length) + old_counter;
if prime_gen_counter >= limit {
return Err(DSAGenError::TooManyGenAttempts)
}
// 33. t = t + 1.
t = t + &one;
// 34. Go to step 23.
}
}
fn ceildiv<T>(a: &T, b: &T) -> T
where T: Add<Output=T>,
T: Sub<Output=T>,
T: Div<Output=T>,
T: From<usize>,
T: Clone
{
let aclone: T = a.clone();
let bclone: T = b.clone();
let one: T = T::from(1 as usize);
let x: T = (aclone + bclone.clone()) - one;
let res = x / bclone;
res
}
fn prime_test(x: &UCN) -> bool {
let two = UCN::from(2 as u64);
let three = UCN::from(3 as u64);
let five = UCN::from(5 as u64);
if x.is_even() {
if x == &two {
return true;
}
return false;
}
if x.is_multiple_of(&three) {
return false;
}
if x.is_multiple_of(&five) {
return false;
}
let mut divisor = UCN::from(7 as u32);
let sqrtx = isqrt(&x);
while &divisor < &sqrtx {
if x.is_multiple_of(&divisor) {
return false;
}
divisor = next_divisor(divisor);
}
true
}
fn isqrt(x: &UCN) -> UCN {
let mut num = x.clone();
let mut res = UCN::from(0u64);
let one = UCN::from(1u64);
let mut bit = one << num.bits();
while &bit > &num {
bit >>= 2;
}
while !bit.is_zero() {
if num >= (&res + &bit) {
num = &num - (&res + &bit);
res = (&res >> 1) + &bit;
} else {
res >>= 1;
}
bit >>= 2;
}
res
}
fn next_divisor(input: UCN) -> UCN {
let two = UCN::from(2 as u64);
let three = UCN::from(3 as u64);
let five = UCN::from(5 as u64);
let mut x = input;
loop {
x = &x + &two;
if x.is_multiple_of(&three) {
continue;
}
if x.is_multiple_of(&five) {
continue;
}
return x;
}
}
fn hash(x: &UCN, len: usize) -> Vec<u8> {
let bytelen = len / 8;
let base = x.to_bytes(bytelen);
let mut dgst = Sha256::default();
dgst.process(&base);
dgst.fixed_result().as_slice().to_vec()
}
fn xorvecs(a: Vec<u8>, b: Vec<u8>) -> Vec<u8> {
assert!(a.len() == b.len());
let mut c = Vec::with_capacity(a.len());
for (a,b) in a.iter().zip(b.iter()) {
c.push(a ^ b);
}
c
}

View File

@@ -1,27 +1,138 @@
use cryptonum::unsigned::*;
use sha::{Hash,SHA1,SHA224,SHA256,SHA384,SHA512};
use cryptonum::UCN;
use digest::{FixedOutput,Input};
use dsa::generation::*;
use dsa::rfc6979::*;
use dsa::parameters::*;
use dsa::private::DSAPrivate;
use dsa::public::DSAPublic;
use rand::{OsRng,Rng};
use sha1::Sha1;
use sha2::{Sha224,Sha256,Sha384,Sha512};
use simple_asn1::{der_decode,der_encode};
use dsa::params::{DSAParameters,L1024N160,L2048N256};
use dsa::private::DSAPrivateKey;
use dsa::public::DSAPublicKey;
use dsa::rfc6979::KIterator;
use testing::run_test;
const NUM_TESTS: u32 = 2;
#[test]
#[ignore]
fn pqg_generation_checks() {
let mut rng = OsRng::new().unwrap();
let params = DSAParameterSize::L1024N160;
for _ in 0..NUM_TESTS {
let seed = get_input_seed(&mut rng,params,n_bits(params)).unwrap();
let (p, q, ev) =
generate_provable_primes(&mut rng, &seed, params).unwrap();
assert!(validate_provable_primes(&mut rng, &p, &q, &ev));
let index = rng.gen::<u8>();
let pu = p.barrett_u();
let g = generate_verifiable_generator(&p, &pu, &q, &ev, index).unwrap();
assert!(verify_generator(&p, &q, &ev, index, &g));
}
}
#[test]
fn dsa_verification_tests()
{
run_test("tests/dsa/signature.test", 9, |case| {
let (neg0, pbytes) = case.get("p").unwrap();
let (neg1, gbytes) = case.get("g").unwrap();
let (neg2, qbytes) = case.get("q").unwrap();
let (neg4, ybytes) = case.get("y").unwrap();
let (neg5, hbytes) = case.get("h").unwrap();
let (neg6, msg) = case.get("m").unwrap();
let (neg7, rbytes) = case.get("r").unwrap();
let (neg8, sbytes) = case.get("s").unwrap();
assert!(!neg0 & !neg1 & !neg2 & !neg4 &
!neg5 & !neg6 & !neg7 & !neg8);
let p = UCN::from_bytes(pbytes);
let g = UCN::from_bytes(gbytes);
let q = UCN::from_bytes(qbytes);
let params = DSAParameters::new(p, g, q).unwrap();
let y = UCN::from_bytes(ybytes);
let public = DSAPublic::new(&params, y);
let r = UCN::from_bytes(rbytes);
let s = UCN::from_bytes(sbytes);
let sig = DSASignature{ r: r, s: s };
match usize::from(UCN::from_bytes(hbytes)) {
0x1 => assert!(public.verify::<Sha1>(msg, &sig)),
0x224 => assert!(public.verify::<Sha224>(msg, &sig)),
0x256 => assert!(public.verify::<Sha256>(msg, &sig)),
0x384 => assert!(public.verify::<Sha384>(msg, &sig)),
0x512 => assert!(public.verify::<Sha512>(msg, &sig)),
v => panic!("Bad hash size {}!", v)
}
});
}
#[test]
#[ignore]
fn dsa_signing_tests()
{
run_test("tests/dsa/signature.test", 9, |case| {
let (neg0, pbytes) = case.get("p").unwrap();
let (neg1, gbytes) = case.get("g").unwrap();
let (neg2, qbytes) = case.get("q").unwrap();
let (neg3, xbytes) = case.get("x").unwrap();
let (neg4, ybytes) = case.get("y").unwrap();
let (neg5, hbytes) = case.get("h").unwrap();
let (neg6, msg) = case.get("m").unwrap();
assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4 & !neg5 & !neg6);
let p = UCN::from_bytes(pbytes);
let g = UCN::from_bytes(gbytes);
let q = UCN::from_bytes(qbytes);
let params = DSAParameters::new(p, g, q).unwrap();
let y = UCN::from_bytes(ybytes);
let public = DSAPublic::new(&params, y);
let x = UCN::from_bytes(xbytes);
let private = DSAPrivate::new(&params, x);
let hash_size = usize::from(UCN::from_bytes(hbytes));
let sig = match hash_size {
0x1 => private.sign::<Sha1>(msg),
0x224 => private.sign::<Sha224>(msg),
0x256 => private.sign::<Sha256>(msg),
0x384 => private.sign::<Sha384>(msg),
0x512 => private.sign::<Sha512>(msg),
v => panic!("Bad hash size {}!", v)
};
match usize::from(UCN::from_bytes(hbytes)) {
0x1 => assert!(public.verify::<Sha1>(msg, &sig)),
0x224 => assert!(public.verify::<Sha224>(msg, &sig)),
0x256 => assert!(public.verify::<Sha256>(msg, &sig)),
0x384 => assert!(public.verify::<Sha384>(msg, &sig)),
0x512 => assert!(public.verify::<Sha512>(msg, &sig)),
v => panic!("Bad hash size {}!", v)
}
});
}
macro_rules! run_rfc6979_test {
($hash: ty, $ntype: ident, $val: ident, $params: ident, $public: ident, $private: ident,
($hash: ty, $val: ident, $public: ident, $private: ident,
k $k: expr,
r $r: expr,
s $s: expr) => ({
let h1 = <$hash>::hash(&$val);
let mut digest = <$hash>::default();
digest.process(&$val);
let h1 = digest.fixed_result().as_slice().to_vec();
let rbytes = $r;
let sbytes = $s;
let r = $ntype::from_bytes(&rbytes);
let s = $ntype::from_bytes(&sbytes);
let mut iter = KIterator::<$hash,$ntype>::new(&h1, $params.n_bits(), &$params.q, &$private.x);
let mut k1 = iter.next().unwrap().to_bytes().to_vec();
while k1.len() > $k.len() {
assert_eq!(k1[0], 0);
k1.remove(0);
}
let r = UCN::from_bytes(&rbytes);
let s = UCN::from_bytes(&sbytes);
let mut iter = KIterator::<$hash>::new(&h1,
n_bits($public.params.size),
&$public.params.q,
&$private.x);
let next = iter.next().unwrap();
let size = (next.bits() + 7) / 8;
let k1 = next.to_bytes(size);
assert_eq!($k, k1);
let sig = $private.sign::<$hash>(&$val);
assert_eq!(sig.r, r);
@@ -91,14 +202,14 @@ fn appendix_a21() {
0x86, 0xE2, 0x22, 0x31, 0x70, 0xB4, 0x4E, 0xAA,
0x7D, 0xA5, 0xDD, 0x9F, 0xFC, 0xFB, 0x7F, 0x3B];
//
let p = U1024::from_bytes(&pbytes);
let q = U192::from_bytes(&qbytes);
let g = U1024::from_bytes(&gbytes);
let params = L1024N160::new(p, g, q);
let x = U192::from_bytes(&xbytes);
let y = U1024::from_bytes(&ybytes);
let private = DSAPrivateKey::<L1024N160>::new(params.clone(), x);
let public = DSAPublicKey::<L1024N160>::new(params.clone(), y);
let p = UCN::from_bytes(&pbytes);
let q = UCN::from_bytes(&qbytes);
let g = UCN::from_bytes(&gbytes);
let params = DSAParameters::new(p, g, q).unwrap();
let x = UCN::from_bytes(&xbytes);
let y = UCN::from_bytes(&ybytes);
let private = DSAPrivate::new(&params, x);
let public = DSAPublic::new(&params, y);
//
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
@@ -106,7 +217,7 @@ fn appendix_a21() {
// k = 7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B
// r = 2E1A0C2562B2912CAAF89186FB0F42001585DA55
// s = 29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5
run_rfc6979_test!(SHA1, U192, sample, params, public, private,
run_rfc6979_test!(Sha1, sample, public, private,
k vec![0x7B, 0xDB, 0x6B, 0x0F, 0xF7, 0x56, 0xE1, 0xBB,
0x5D, 0x53, 0x58, 0x3E, 0xF9, 0x79, 0x08, 0x2F,
0x9A, 0xD5, 0xBD, 0x5B],
@@ -120,7 +231,7 @@ fn appendix_a21() {
// k = 562097C06782D60C3037BA7BE104774344687649
// r = 4BC3B686AEA70145856814A6F1BB53346F02101E
// s = 410697B92295D994D21EDD2F4ADA85566F6F94C1
run_rfc6979_test!(SHA224, U192, sample, params, public, private,
run_rfc6979_test!(Sha224, sample, public, private,
k vec![0x56, 0x20, 0x97, 0xC0, 0x67, 0x82, 0xD6, 0x0C,
0x30, 0x37, 0xBA, 0x7B, 0xE1, 0x04, 0x77, 0x43,
0x44, 0x68, 0x76, 0x49],
@@ -134,7 +245,7 @@ fn appendix_a21() {
// k = 519BA0546D0C39202A7D34D7DFA5E760B318BCFB
// r = 81F2F5850BE5BC123C43F71A3033E9384611C545
// s = 4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89
run_rfc6979_test!(SHA256, U192, sample, params, public, private,
run_rfc6979_test!(Sha256, sample, public, private,
k vec![0x51, 0x9B, 0xA0, 0x54, 0x6D, 0x0C, 0x39, 0x20,
0x2A, 0x7D, 0x34, 0xD7, 0xDF, 0xA5, 0xE7, 0x60,
0xB3, 0x18, 0xBC, 0xFB],
@@ -148,7 +259,7 @@ fn appendix_a21() {
// k = 95897CD7BBB944AA932DBC579C1C09EB6FCFC595
// r = 07F2108557EE0E3921BC1774F1CA9B410B4CE65A
// s = 54DF70456C86FAC10FAB47C1949AB83F2C6F7595
run_rfc6979_test!(SHA384, U192, sample, params, public, private,
run_rfc6979_test!(Sha384, sample, public, private,
k vec![0x95, 0x89, 0x7C, 0xD7, 0xBB, 0xB9, 0x44, 0xAA,
0x93, 0x2D, 0xBC, 0x57, 0x9C, 0x1C, 0x09, 0xEB,
0x6F, 0xCF, 0xC5, 0x95],
@@ -162,7 +273,7 @@ fn appendix_a21() {
// k = 09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B
// r = 16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B
// s = 02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C
run_rfc6979_test!(SHA512, U192, sample, params, public, private,
run_rfc6979_test!(Sha512, sample, public, private,
k vec![0x09, 0xEC, 0xE7, 0xCA, 0x27, 0xD0, 0xF5, 0xA4,
0xDD, 0x4E, 0x55, 0x6C, 0x9D, 0xF1, 0xD2, 0x1D,
0x28, 0x10, 0x4F, 0x8B],
@@ -176,7 +287,7 @@ fn appendix_a21() {
// k = 5C842DF4F9E344EE09F056838B42C7A17F4A6433
// r = 42AB2052FD43E123F0607F115052A67DCD9C5C77
// s = 183916B0230D45B9931491D4C6B0BD2FB4AAF088
run_rfc6979_test!(SHA1, U192, test, params, public, private,
run_rfc6979_test!(Sha1, test, public, private,
k vec![0x5C, 0x84, 0x2D, 0xF4, 0xF9, 0xE3, 0x44, 0xEE,
0x09, 0xF0, 0x56, 0x83, 0x8B, 0x42, 0xC7, 0xA1,
0x7F, 0x4A, 0x64, 0x33],
@@ -190,7 +301,7 @@ fn appendix_a21() {
// k = 4598B8EFC1A53BC8AECD58D1ABBB0C0C71E67297
// r = 6868E9964E36C1689F6037F91F28D5F2C30610F2
// s = 49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F
run_rfc6979_test!(SHA224, U192, test, params, public, private,
run_rfc6979_test!(Sha224, test, public, private,
k vec![0x45, 0x98, 0xB8, 0xEF, 0xC1, 0xA5, 0x3B, 0xC8,
0xAE, 0xCD, 0x58, 0xD1, 0xAB, 0xBB, 0x0C, 0x0C,
0x71, 0xE6, 0x72, 0x97],
@@ -204,7 +315,7 @@ fn appendix_a21() {
// k = 5A67592E8128E03A417B0484410FB72C0B630E1A
// r = 22518C127299B0F6FDC9872B282B9E70D0790812
// s = 6837EC18F150D55DE95B5E29BE7AF5D01E4FE160
run_rfc6979_test!(SHA256, U192, test, params, public, private,
run_rfc6979_test!(Sha256, test, public, private,
k vec![0x5A, 0x67, 0x59, 0x2E, 0x81, 0x28, 0xE0, 0x3A,
0x41, 0x7B, 0x04, 0x84, 0x41, 0x0F, 0xB7, 0x2C,
0x0B, 0x63, 0x0E, 0x1A],
@@ -218,7 +329,7 @@ fn appendix_a21() {
// k = 220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89
// r = 854CF929B58D73C3CBFDC421E8D5430CD6DB5E66
// s = 91D0E0F53E22F898D158380676A871A157CDA622
run_rfc6979_test!(SHA384, U192, test, params, public, private,
run_rfc6979_test!(Sha384, test, public, private,
k vec![0x22, 0x01, 0x56, 0xB7, 0x61, 0xF6, 0xCA, 0x5E,
0x6C, 0x9F, 0x1B, 0x9C, 0xF9, 0xC2, 0x4B, 0xE2,
0x5F, 0x98, 0xCD, 0x89],
@@ -232,7 +343,7 @@ fn appendix_a21() {
// k = 65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C
// r = 8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0
// s = 7C670C7AD72B6C050C109E1790008097125433E8
run_rfc6979_test!(SHA512, U192, test, params, public, private,
run_rfc6979_test!(Sha512, test, public, private,
k vec![0x65, 0xD2, 0xC2, 0xEE, 0xB1, 0x75, 0xE3, 0x70,
0xF2, 0x8C, 0x75, 0xBF, 0xCD, 0xC0, 0x28, 0xD2,
0x2C, 0x7D, 0xBE, 0x9C],
@@ -351,14 +462,14 @@ fn appendix_a22() {
0xD4,0xA0,0x98,0x63,0x15,0xDA,0x8E,0xEC,
0x65,0x61,0xC9,0x38,0x99,0x6B,0xEA,0xDF];
//
let p = U2048::from_bytes(&pbytes);
let q = U256::from_bytes(&qbytes);
let g = U2048::from_bytes(&gbytes);
let params = L2048N256::new(p, g, q);
let x = U256::from_bytes(&xbytes);
let y = U2048::from_bytes(&ybytes);
let private = DSAPrivateKey::<L2048N256>::new(params.clone(), x);
let public = DSAPublicKey::<L2048N256>::new(params.clone(), y);
let p = UCN::from_bytes(&pbytes);
let q = UCN::from_bytes(&qbytes);
let g = UCN::from_bytes(&gbytes);
let params = DSAParameters::new(p, g, q).unwrap();
let x = UCN::from_bytes(&xbytes);
let y = UCN::from_bytes(&ybytes);
let private = DSAPrivate::new(&params, x);
let public = DSAPublic::new(&params, y);
//
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
@@ -366,7 +477,7 @@ fn appendix_a22() {
// k = 888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E
// r = 3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A
// s = D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF
run_rfc6979_test!(SHA1, U256, sample, params, public, private,
run_rfc6979_test!(Sha1, sample, public, private,
k vec![0x88,0x8F,0xA6,0xF7,0x73,0x8A,0x41,0xBD,
0xC9,0x84,0x64,0x66,0xAB,0xDB,0x81,0x74,
0xC0,0x33,0x82,0x50,0xAE,0x50,0xCE,0x95,
@@ -383,7 +494,7 @@ fn appendix_a22() {
// k = BC372967702082E1AA4FCE892209F71AE4AD25A6DFD869334E6F153BD0C4D806
// r = DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C
// s = A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC
run_rfc6979_test!(SHA224, U256, sample, params, public, private,
run_rfc6979_test!(Sha224, sample, public, private,
k vec![0xBC,0x37,0x29,0x67,0x70,0x20,0x82,0xE1,
0xAA,0x4F,0xCE,0x89,0x22,0x09,0xF7,0x1A,
0xE4,0xAD,0x25,0xA6,0xDF,0xD8,0x69,0x33,
@@ -400,7 +511,7 @@ fn appendix_a22() {
// k = 8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52
// r = EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809
// s = 7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53
run_rfc6979_test!(SHA256, U256, sample, params, public, private,
run_rfc6979_test!(Sha256, sample, public, private,
k vec![0x89,0x26,0xA2,0x7C,0x40,0x48,0x42,0x16,
0xF0,0x52,0xF4,0x42,0x7C,0xFD,0x56,0x47,
0x33,0x8B,0x7B,0x39,0x39,0xBC,0x65,0x73,
@@ -417,7 +528,7 @@ fn appendix_a22() {
// k = C345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920
// r = B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B
// s = 19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B
run_rfc6979_test!(SHA384, U256, sample, params, public, private,
run_rfc6979_test!(Sha384, sample, public, private,
k vec![0xC3,0x45,0xD5,0xAB,0x3D,0xA0,0xA5,0xBC,
0xB7,0xEC,0x8F,0x8F,0xB7,0xA7,0xE9,0x60,
0x69,0xE0,0x3B,0x20,0x63,0x71,0xEF,0x7D,
@@ -434,7 +545,7 @@ fn appendix_a22() {
// k = 5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC
// r = 2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E
// s = D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351
run_rfc6979_test!(SHA512, U256, sample, params, public, private,
run_rfc6979_test!(Sha512, sample, public, private,
k vec![0x5A,0x12,0x99,0x44,0x31,0x78,0x54,0x85,
0xB3,0xF5,0xF0,0x67,0x22,0x15,0x17,0x79,
0x1B,0x85,0xA5,0x97,0xB7,0xA9,0x43,0x69,
@@ -451,7 +562,7 @@ fn appendix_a22() {
// k = 6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F
// r = C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0
// s = 414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA
run_rfc6979_test!(SHA1, U256, test, params, public, private,
run_rfc6979_test!(Sha1, test, public, private,
k vec![0x6E,0xEA,0x48,0x6F,0x9D,0x41,0xA0,0x37,
0xB2,0xC6,0x40,0xBC,0x56,0x45,0x69,0x4F,
0xF8,0xFF,0x4B,0x98,0xD0,0x66,0xA2,0x5F,
@@ -468,7 +579,7 @@ fn appendix_a22() {
// k = 06BD4C05ED74719106223BE33F2D95DA6B3B541DAD7BFBD7AC508213B6DA6670
// r = 272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3
// s = E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806
run_rfc6979_test!(SHA224, U256, test, params, public, private,
run_rfc6979_test!(Sha224, test, public, private,
k vec![0x06,0xBD,0x4C,0x05,0xED,0x74,0x71,0x91,
0x06,0x22,0x3B,0xE3,0x3F,0x2D,0x95,0xDA,
0x6B,0x3B,0x54,0x1D,0xAD,0x7B,0xFB,0xD7,
@@ -485,7 +596,7 @@ fn appendix_a22() {
// k = 1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7
// r = 8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0
// s = 7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E
run_rfc6979_test!(SHA256, U256, test, params, public, private,
run_rfc6979_test!(Sha256, test, public, private,
k vec![0x1D,0x6C,0xE6,0xDD,0xA1,0xC5,0xD3,0x73,
0x07,0x83,0x9C,0xD0,0x3A,0xB0,0xA5,0xCB,
0xB1,0x8E,0x60,0xD8,0x00,0x93,0x7D,0x67,
@@ -502,7 +613,7 @@ fn appendix_a22() {
// k = 206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C
// r = 239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE
// s = 6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961
run_rfc6979_test!(SHA384, U256, test, params, public, private,
run_rfc6979_test!(Sha384, test, public, private,
k vec![0x20,0x6E,0x61,0xF7,0x3D,0xBE,0x1B,0x2D,
0xC8,0xBE,0x73,0x6B,0x22,0xB0,0x79,0xE9,
0xDA,0xCD,0x97,0x4D,0xB0,0x0E,0xEB,0xBC,
@@ -519,7 +630,7 @@ fn appendix_a22() {
// k = AFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA
// r = 89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307
// s = C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1
run_rfc6979_test!(SHA512, U256, test, params, public, private,
run_rfc6979_test!(Sha512, test, public, private,
k vec![0xAF,0xF1,0x65,0x1E,0x4C,0xD6,0x03,0x6D,
0x57,0xAA,0x8B,0x2A,0x05,0xCC,0xF1,0xA9,
0xD5,0xA4,0x01,0x66,0x34,0x0E,0xCB,0xBD,

View File

@@ -1,91 +1,55 @@
//! If you want to use this module to generate keys, which you really
//! really shouldn't, there are two ways to do so, depending on whether
//! you've previously agreed on a set of DSA parameters for this key
//! pair. If you haven't, you can generate the parameters using a good
//! random number generator.
//!
//! ```rust
//! use simple_crypto::dsa::{DSAKeyPair,DSAParameters,L2048N256};
//! use simple_crypto::sha::SHA224;
//!
//! // Generate a set of DSA parameters, assuming you don't have
//! // them already
//! let mut rng = rand::rngs::OsRng::new().unwrap();
//! let params = L2048N256::generate(&mut rng);
//!
//! // Given those parameters, you can generate a key pair like so:
//! let kp = DSAKeyPair::<L2048N256>::generate(&params, &mut rng);
//! // Keeping in mind that you can re-use the parameters across multiple
//! // keys, and that their secrecy isn't paramout for the security of the
//! // algorithm.
//!
//! // Now that you have this key pair, you can sign and verify messages
//! // using it. For example, to sign the vector [0,1,2,3,4] with SHA224
//! // and then verify that signature, we would write:
//! let msg = vec![0,1,2,3,4];
//! let sig = kp.private.sign::<SHA224>(&msg);
//! assert!( kp.public.verify::<SHA224>(&msg, &sig) );
//! ```
mod errors;
mod params;
mod private;
mod public;
/// Support for RFC6979 signing, which provides a secure way to generate
/// signatures without the use of a random number generator. This is used
/// in DSA signing as well as in ECDSA signing, but appears here because
/// ... well, because it was written for DSA first, both historically
/// (I think) and by me.
pub mod rfc6979;
mod generation;
#[cfg(test)]
mod tests;
mod gold_tests;
mod parameters;
mod public;
mod private;
pub(crate) mod rfc6979;
pub use self::params::*;
pub use self::private::*;
pub use self::public::*;
pub use self::public::DSAPublic;
pub use self::private::DSAPrivate;
pub use self::rfc6979::DSASignature;
use cryptonum::unsigned::*;
use rand::Rng;
use rand::distributions::Standard;
use super::KeyPair;
use cryptonum::UCN;
use rand::{OsRng,Rng};
use self::errors::*;
use self::parameters::*;
/// A DSA key pair, for use in signing and signature verification. Note
/// that you probably shouldn't be using DSA any more; ECDSA or ED25519
/// are probably better options.
///
/// DSA key pairs are parameterized by their DSA parameters, so that
/// you can't accidentally use them in the wrong place.
pub struct DSAKeyPair<P: DSAParameters>
{
pub private: DSAPrivateKey<P>,
pub public: DSAPublicKey<P>
/// A DSA key pair
#[derive(Clone,Debug,PartialEq)]
pub struct DSAKeyPair {
pub private: DSAPrivate,
pub public: DSAPublic
}
impl<P: DSAParameters> KeyPair for DSAKeyPair<P>
impl DSAKeyPair {
pub fn generate(size: DSAParameterSize)
-> Result<DSAKeyPair,DSAGenError>
{
type Private = DSAPrivateKey<P>;
type Public = DSAPublicKey<P>;
fn new(public: DSAPublicKey<P>, private: DSAPrivateKey<P>) -> DSAKeyPair<P>
{
DSAKeyPair{ private, public }
}
let mut rng = OsRng::new()?;
DSAKeyPair::generate_rng(&mut rng, size)
}
macro_rules! generate_dsa_pair {
($ptype: ident, $ltype: ident, $ntype: ident, $nbig: ident) => {
impl DSAKeyPair<$ptype>
pub fn generate_rng<G: Rng>(rng: &mut G, size: DSAParameterSize)
-> Result<DSAKeyPair,DSAGenError>
{
/// Generate a DSA key pair using the given parameters and random
/// number generator. Please make sure that the RNG you're using
/// is suitable for key generators (look for the term "cryptographic"
/// or "crypto strong" in its documentation, or see if it matches
/// any of the NIST-suggested RNG algorithms).
pub fn generate<G: Rng>(params: &$ptype, rng: &mut G) -> Self
let params = DSAParameters::generate_w_rng(rng, size)?;
DSAKeyPair::generate_w_params_rng(rng, &params)
}
pub fn generate_w_params(params: &DSAParameters)
-> Result<DSAKeyPair,DSAGenError>
{
let mut rng = OsRng::new()?;
DSAKeyPair::generate_w_params_rng(&mut rng, params)
}
pub fn generate_w_params_rng<G: Rng>(rng: &mut G, params: &DSAParameters)
-> Result<DSAKeyPair,DSAGenError>
{
// 1. N = len(q); L = len(p);
let n = $ptype::n_size();
let n = n_bits(params.size);
// 2. If the (L,N) pair is invalid, then return an ERROR indicator,
// Invalid_x, and Invalid_y.
// 3. requested_security_strength = the security strength associated
@@ -94,25 +58,20 @@ macro_rules! generate_dsa_pair {
// strength of requested_security_strength or more. If an ERROR
// indication is returned, then return an ERROR indication,
// Invalid_x, and Invalid_y.
let returned_bits: Vec<u8> = rng.sample_iter(&Standard).take( (n + 64) / 8 ).collect();
let returned_bits: Vec<u8> = rng.gen_iter().take(n + 8).collect();
// 5. Convert returned_bits to the (non-negative) integer c.
let c = $nbig::from_bytes(&returned_bits);
let c = UCN::from_bytes(&returned_bits);
// 6. x = (c mod (q-1)) + 1.
let one = $nbig::from(1 as u64);
let qbig = $nbig::from(&params.q);
let x = $ntype::from( (&c % (&qbig - &one)) + &one );
let one = UCN::from(1 as u64);
let x = (&c % (&params.q - &one)) + &one;
// 7. y = g^x mod p
let y = params.g.modexp(&$ltype::from(&x), &params.p);
let y = params.g.fastmodexp(&x, &params.pu);
// 8. Return SUCCESS, x, and y.
let private = DSAPrivateKey::<$ptype>::new(params.clone(), x);
let public = DSAPublicKey::<$ptype>::new(params.clone(), y);
DSAKeyPair { private, public }
let private = DSAPrivate { params: params.clone(), x: x };
let public = DSAPublic { params: params.clone(), y: y };
Ok(DSAKeyPair {
private: private,
public: public
})
}
}
};
}
generate_dsa_pair!(L1024N160, U1024, U192, U256);
generate_dsa_pair!(L2048N224, U2048, U256, U384);
generate_dsa_pair!(L2048N256, U2048, U256, U384);
generate_dsa_pair!(L3072N256, U3072, U256, U384);

119
src/dsa/parameters.rs Normal file
View File

@@ -0,0 +1,119 @@
use cryptonum::{BarrettUCN,UCN};
use dsa::errors::*;
use dsa::generation::{DSAGenEvidence,verify_generator,
get_input_seed,generate_provable_primes,
generate_verifiable_generator,
validate_provable_primes};
use rand::{OsRng,Rng};
/// These are the legal lengths for L and N when using DSA; essentially,
/// the bit sizes available for the algorithms.
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum DSAParameterSize { L1024N160, L2048N224, L2048N256, L3072N256 }
pub fn n_bits(ps: DSAParameterSize) -> usize {
match ps {
DSAParameterSize::L1024N160 => 160,
DSAParameterSize::L2048N224 => 224,
DSAParameterSize::L2048N256 => 256,
DSAParameterSize::L3072N256 => 256,
}
}
pub fn l_bits(ps: DSAParameterSize) -> usize {
match ps {
DSAParameterSize::L1024N160 => 1024,
DSAParameterSize::L2048N224 => 2048,
DSAParameterSize::L2048N256 => 2048,
DSAParameterSize::L3072N256 => 3072,
}
}
/// A set of DSA parameters, which are shared across both the public and private
/// keys.
#[derive(Clone,Debug,PartialEq)]
pub struct DSAParameters {
pub size: DSAParameterSize,
pub p: UCN,
pub g: UCN,
pub q: UCN,
pub pu: BarrettUCN,
pub qu: BarrettUCN
}
impl DSAParameters {
/// Generate a new set of DSA parameters, from a certificate file or some
/// other source. This will try to find an appropriate size based on the
/// size of the values provided, but will fail (returning
/// `DSAError::InvalidParamSize`) if it can't find a reasonable one.
pub fn new(p: UCN, g: UCN, q: UCN)
-> Result<DSAParameters,DSAError>
{
let l = ((p.bits() + 255) / 256) * 256;
let n = ((q.bits() + 15) / 16) * 16;
let size = match (l, n) {
(1024, 160) => DSAParameterSize::L1024N160,
(2048, 224) => DSAParameterSize::L2048N224,
(2048, 256) => DSAParameterSize::L2048N256,
(3072, 256) => DSAParameterSize::L3072N256,
_ => return Err(DSAError::InvalidParamSize)
};
let pu = p.barrett_u();
let qu = q.barrett_u();
Ok(DSAParameters{ size: size, p: p, g: g, q: q, pu: pu, qu: qu })
}
/// Generate a new set of DSA parameters for use. You probably shouldn't be
/// doing this. This is equivalent to calling `generate_w_rng` with
/// `OsRng`, which is supposed to be cryptographically sound.
pub fn generate(ps: DSAParameterSize)
-> Result<DSAParameters,DSAGenError>
{
let mut rng = OsRng::new()?;
DSAParameters::generate_w_rng(&mut rng, ps)
}
/// Generate a new set of DSA parameters for use, using the given entropy
/// source. I would normally include a note here about making sure to use
/// a good one, but if you're using DSA you've already given up a little
/// bit of the high ground, there.
pub fn generate_w_rng<G: Rng>(rng: &mut G, ps: DSAParameterSize)
-> Result<DSAParameters,DSAGenError>
{
let firstseed = get_input_seed(rng, ps, n_bits(ps))?;
let (p, q, ev) = generate_provable_primes(rng, &firstseed, ps)?;
DSAParameters::generate_g(ps, p, q, ev, 0)
}
/// Using the given p and q values and an index, create a new DSAParameters
/// by creating a new generator g that works with p and q.
fn generate_g(ps: DSAParameterSize,
p: UCN, q: UCN,
ev: DSAGenEvidence,
idx: u8)
-> Result<DSAParameters, DSAGenError>
{
let pu = p.barrett_u();
let qu = q.barrett_u();
let g = generate_verifiable_generator(&p, &pu, &q, &ev, idx)?;
Ok(DSAParameters{ size: ps, p: p, q: q, g: g, pu: pu, qu: qu })
}
/// Given the provided evidence, validate that the domain parameters
/// were appropriately constructed.
pub fn verify(&self, ev: &DSAGenEvidence, idx: u8) -> bool {
let mut rng = OsRng::new().unwrap();
self.verify_w_rng(&mut rng, ev, idx)
}
/// Given the set of inputs you used to generate your system, verify that
/// everything makes sense.
pub fn verify_w_rng<G: Rng>(&self, r: &mut G, ev: &DSAGenEvidence, idx: u8)
-> bool
{
validate_provable_primes(r, &self.p, &self.q, ev) &&
verify_generator(&self.p, &self.q, ev, idx, &self.g)
}
}

View File

@@ -1,225 +0,0 @@
use cryptonum::unsigned::{CryptoNum,Decoder,Encoder,ModExp,PrimeGen};
use cryptonum::unsigned::{U192,U256,U1024,U2048,U3072};
use sha::{Hash,SHA256};
use simple_asn1::{ToASN1,ASN1Block,ASN1Class,ASN1EncodeErr};
use rand::Rng;
use utils::TranslateNums;
/// A trait that describes what a set of DSA parameters must support in
/// order to be used by the rest of the system.
pub trait DSAParameters : ToASN1
{
/// The fixed-width, unsigned type of values in L.
type L;
/// The fixed-width, unsigned type of values in N.
type N;
/// Given a `p`, `g`, and `q`, generate a new structure that includes
/// this information. Optionally, do any cross-checks needed.
fn new(p: Self::L, g: Self::L, q: Self::N) -> Self;
/// Generate a new set of DSA parameters given the provided random
/// number generator. Just as with key generation, this should be a
/// cryptographically-strong random number generator. If it's not,
/// you may be writing compromisable code.
fn generate<G: Rng>(rng: &mut G) -> Self;
/// Return the size of values of N in bits.
fn n_size() -> usize;
/// Return the size of values of L in bits.
fn l_size() -> usize;
/// Return the size of `q` in this particular instance of the parameters.
/// (Should be the same as `n_size()`, and the default implementation
/// simply uses `n_size(), but included for convenience)
fn n_bits(&self) -> usize {
Self::n_size()
}
}
macro_rules! generate_parameters {
($name: ident, $ltype: ident, $ntype: ident, $l: expr, $n: expr) => {
/// DSA parameters to the given L and N, with the values given in bits.
#[derive(Clone,PartialEq)]
pub struct $name {
pub p: $ltype,
pub g: $ltype,
pub q: $ntype
}
impl ToASN1 for $name {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let p = ASN1Block::Integer(c, 0, self.p.to_num());
let q = ASN1Block::Integer(c, 0, self.q.to_num());
let g = ASN1Block::Integer(c, 0, self.g.to_num());
Ok(vec![ASN1Block::Sequence(c, 0, vec![p, q, g])])
}
}
impl DSAParameters for $name
{
type L = $ltype;
type N = $ntype;
fn new(p: $ltype, g: $ltype, q: $ntype) -> $name
{
$name{ p: p, g: g, q: q }
}
fn generate<G: Rng>(rng: &mut G) -> $name
{
let (p, q, _, _) = $name::generate_primes(rng);
let g = $name::generate_g(rng, &p, &q);
$name{ p: p, g: g, q: q }
}
fn l_size() -> usize {
$l
}
fn n_size() -> usize {
$n
}
}
impl $name
{
pub fn generate_primes<G: Rng>(rng: &mut G) -> ($ltype,$ntype,U256,usize)
{
// This is A.1.1.2 from FIPS 186-4, with seedlen hardcoded to 256
// (since that's guaranteed to be >= N), and with the hash
// hardcoded as SHA-256.
#[allow(non_snake_case)]
let L = $ltype::bit_length();
#[allow(non_snake_case)]
let N = $ntype::bit_length();
let seedlen = 256;
let outlen = 256;
//
// 1. Check that the (L,N) pair is in the list of acceptable
// (L,N) pairs (see Section 4.2). If the pair is not in the
// list, then return INVALID.
// [This is always true.]
//
// 2. If (seedlen < N), then return INVALID.
// [This is always true.]
//
// 3. n = L/outlen 1.
let n = ((L + 255) / 256) - 1;
// 4. b = L 1 (n outlen).
let b = L - 1 - (n * outlen);
loop {
// 5. Get an arbitrary sequence of seedlen bits as the
// domain_parameter_seed.
let domain_parameter_seed: U256 = rng.gen();
// 6. U = Hash (domain_parameter_seed) mod 2^(N1).
let mut ubytes = hash(&domain_parameter_seed, 32);
while ubytes.len() > (N / 8) { ubytes.remove(0); }
#[allow(non_snake_case)]
let U = $ntype::from_bytes(&ubytes);
// 7. q = 2^(N1) + U + 1 (U mod 2).
let highbit = $ntype::from(1u64) << (N - 1);
let lowbit = $ntype::from(1u64);
let q = U | highbit | lowbit;
// 8. Test whether or not q is prime as specified in Appendix C.3.
let q_is_prime = q.probably_prime(rng, 40);
// 9. If q is not a prime, then go to step 5.
if !q_is_prime {
continue;
}
// 10. offset = 1.
let mut offset = 1;
// 11. For counter = 0 to (4L 1) do
for counter in 0..(4*L)-1 {
// 11.1 For j = 0 to n do
// Vj = Hash ((domain_parameter_seed + offset + j) mod 2^seedlen).
#[allow(non_snake_case)]
let mut V = Vec::new();
for j in 0..n {
let val = &domain_parameter_seed + U256::from(offset + j);
let bytes = hash(&val, 32);
assert_eq!(seedlen, bytes.len() * 8);
V.push(bytes);
}
// 11.2 W = V_0 + ( V_1 2^outlen) + ... + ( V_(n1) 2^(n 1) outlen) + ((V_n mod 2^b) 2^(n outlen).
#[allow(non_snake_case)]
let mut W = $ltype::zero();
for (idx, val) in V.iter().enumerate() {
if idx < n {
let mut base = val.clone();
let baselen = base.len();
base.resize(baselen + (idx * (outlen / 8)), 0);
W += $ltype::from_bytes(&base);
} else {
let base = $ltype::from_bytes(val);
let twob = $ltype::from(1u64) << b;
let val = base % twob;
W += val << (n * outlen);
}
}
// 11.3 X = W + 2^(L 1).
// Comment: 0 ≤ W < 2 L 1 ; hence, 2 L 1 ≤ X < 2 L .
#[allow(non_snake_case)]
let mut X = $ltype::from(1u64) << (L - 1);
X += W;
// 11.4 c = X mod 2q.
let c = &X % ($ltype::from(&q) << 1);
// 11.5 p = X ( c 1).
// Comment: p ≡ 1 ( mod 2 q) .
let p = &X - (c - $ltype::from(1u64));
// 11.6 If ( p < 2L 1), then go to step 11.9.
if p >= $ltype::from((2*L) - 1) {
// 11.7 Test whether or not p is prime as specified in Appendix C .3.
if p.probably_prime(rng, 40) {
// 11.8 If p is determined to be prime, then return VALID and the values of p , q and (optionally) the values of domain_parameter_seed and counter .
return (p, q, domain_parameter_seed, counter);
}
}
// 11.9 offset = offset + n + 1.
offset = offset + n + 1;
}
}
}
fn generate_g<G: Rng>(rng: &mut G, p: &$ltype, q: &$ntype) -> $ltype
{
let bigq = $ltype::from(q);
let p_minus_1 = p - $ltype::from(1u64);
// This is A.2.1 (Unverifiable Generation of g) from FIPS 186-4.
// 1. e = (p 1) / q.
let e = (p - $ltype::from(1u64)) / bigq;
loop {
// 2. Set h = any integer satisfying 1 < h < ( p 1), such that
// h differs from any value previously tried. Note that h could
// be obtained from a random number generator or from a counter
// that changes after each use.
let h = rng.gen_range($ltype::from(2u64), &p_minus_1);
// 3. g = h^e mod p.
let g = h.modexp(&e, p);
// 4. If ( g = 1), then go to step 2.
if g != $ltype::from(1u64) {
// 5. Return g
return g;
}
}
}
}
};
}
generate_parameters!(L1024N160, U1024, U192, 1024, 160);
generate_parameters!(L2048N224, U2048, U256, 2048, 224);
generate_parameters!(L2048N256, U2048, U256, 2048, 256);
generate_parameters!(L3072N256, U3072, U256, 3072, 256);
fn hash<T>(x: &T, len: usize) -> Vec<u8>
where T: Encoder
{
let mut base = x.to_bytes();
let bytelen = len / 8;
while base.len() < bytelen {
base.insert(0,0);
}
SHA256::hash(&base)
}

View File

@@ -1,36 +1,31 @@
use cryptonum::unsigned::*;
use cryptonum::signed::ModInv;
use dsa::params::*;
use dsa::rfc6979::*;
use sha::Hash;
use cryptonum::UCN;
use digest::{BlockInput,FixedOutput,Input};
use digest::generic_array::ArrayLength;
use dsa::parameters::{DSAParameters,n_bits};
use dsa::rfc6979::{DSASignature,KIterator,bits2int};
use hmac::Hmac;
use std::ops::Rem;
/// A DSA private key, parameterized by its DSA parameters (so that you don't
/// accidentally pass the wrong key to the wrong routine).
pub struct DSAPrivateKey<Params: DSAParameters>
{
pub(crate) params: Params,
pub(crate) x: Params::N
/// A DSA private key.
#[derive(Clone,Debug,PartialEq)]
pub struct DSAPrivate {
pub params: DSAParameters,
pub(crate) x: UCN
}
/// A generic DSA private key enum, which masks which kind of DSA key (1024,
/// 2048 with the small `n`, 2048 with the normal `n`, or 3072) you're using.
pub enum DSAPrivate {
DSA1024Private(DSAPrivateKey<L1024N160>),
DSA2048SmallPrivate(DSAPrivateKey<L2048N224>),
DSA2048Private(DSAPrivateKey<L2048N256>),
DSA3072Private(DSAPrivateKey<L3072N256>)
impl DSAPrivate {
pub fn new(params: &DSAParameters, x: UCN) -> DSAPrivate {
DSAPrivate {
params: params.clone(),
x: x
}
}
macro_rules! privkey_impls {
($ptype: ident, $ltype: ident, $ntype: ident, $big: ident, $bigger: ident, $biggest: ident) => {
impl DSAPrivateKey<$ptype>
{
pub fn new(params: $ptype, x: $ntype) -> DSAPrivateKey<$ptype>
{
DSAPrivateKey{ params, x }
}
pub fn sign<H: Hash + Clone>(&self, m: &[u8]) -> DSASignature<$ntype>
pub fn sign<Hash>(&self, m: &[u8]) -> DSASignature
where
Hash: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<Hash>: Clone,
Hash::BlockSize: ArrayLength<u8>
{
// This algorithm is per RFC 6979, which has a nice, relatively
// straightforward description of how to do DSA signing.
@@ -43,11 +38,16 @@ macro_rules! privkey_impls {
// As was noted in the description of bits2octets, the extra
// modular reduction is no more than a conditional subtraction.
//
let h1 = <H>::hash(m);
let n = $ptype::n_size();
let h0: $ntype = bits2int(&h1, $ptype::n_size());
let q = &self.params.q;
let h = h0 % q;
let mut digest = <Hash>::default();
digest.process(m);
let n = n_bits(self.params.size);
let h1: Vec<u8> = digest.fixed_result()
.as_slice()
.iter()
.map(|x| *x)
.collect();
let h0 = bits2int(&h1, n);
let h = h0.reduce(&self.params.qu);
// 2. A random value modulo q, dubbed k, is generated. That value
// shall not be 0; hence, it lies in the [1, q-1] range. Most
@@ -55,7 +55,7 @@ macro_rules! privkey_impls {
// process used to generate k. In plain DSA or ECDSA, k should
// be selected through a random selection that chooses a value
// among the q-1 possible values with uniform probability.
for k in KIterator::<H,$ntype>::new(&h1, n, q, &self.x) {
for k in KIterator::<Hash>::new(&h1, n, &self.params.q, &self.x) {
// 3. A value r (modulo q) is computed from k and the key
// parameters:
// * For DSA:
@@ -68,92 +68,22 @@ macro_rules! privkey_impls {
//
// If r turns out to be zero, a new k should be selected and r
// computed again (this is an utterly improbable occurrence).
let bigk = $ltype::from(&k);
let bigr = self.params.g.modexp(&bigk, &self.params.p) % $ltype::from(q);
if bigr.is_zero() {
let r = self.params.g.fastmodexp(&k, &self.params.pu)
.rem(&self.params.q);
if r.is_zero() {
continue;
}
let r = $ntype::from(bigr);
// 4. The value s (modulo q) is computed:
//
// s = (h+x*r)/k mod q
//
// The pair (r, s) is the signature.
if let Some(kinv) = k.modinv(&q) {
let xr = &self.x * &r;
let top = xr + $big::from(&h);
let left = top * $bigger::from(kinv);
let bigs = left % $biggest::from(q);
return DSASignature::new(r, $ntype::from(bigs));
}
let kinv = k.modinv(&self.params.q);
let s = ((&h + (&self.x * &r)) * &kinv).rem(&self.params.q);
return DSASignature{ r: r, s: s };
}
panic!("The world is broken; couldn't find a k in sign().");
}
}
};
}
privkey_impls!(L1024N160, U1024, U192, U384, U448, U896);
privkey_impls!(L2048N224, U2048, U256, U512, U576, U1152);
privkey_impls!(L2048N256, U2048, U256, U512, U576, U1152);
privkey_impls!(L3072N256, U3072, U256, U512, U576, U1152);
macro_rules! generate_tests {
( $( ($mod: ident, $params: ident, $lt: ident, $nt: ident) ),* ) => {
$(
#[cfg(test)]
#[allow(non_snake_case)]
mod $mod {
use cryptonum::unsigned::Decoder;
use super::*;
use testing::run_test;
use sha::{SHA224,SHA256,SHA384,SHA512};
#[test]
fn verify() {
let fname = format!("testdata/dsa/sign{}.test", stringify!($params));
run_test(fname.to_string(), 9, |case| {
let (neg0, pbytes) = case.get("p").unwrap();
let (neg1, qbytes) = case.get("q").unwrap();
let (neg2, gbytes) = case.get("g").unwrap();
let (neg3, _bytes) = case.get("y").unwrap();
let (neg4, xbytes) = case.get("x").unwrap();
let (neg5, mbytes) = case.get("m").unwrap();
let (neg6, hbytes) = case.get("h").unwrap();
let (neg7, rbytes) = case.get("r").unwrap();
let (neg8, sbytes) = case.get("s").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 &&
!neg5 && !neg6 && !neg7 && !neg8);
let p = $lt::from_bytes(pbytes);
let q = $nt::from_bytes(qbytes);
let g = $lt::from_bytes(gbytes);
let x = $nt::from_bytes(xbytes);
//let y = $lt::from_bytes(ybytes);
let h = usize::from($nt::from_bytes(hbytes));
let r = $nt::from_bytes(rbytes);
let s = $nt::from_bytes(sbytes);
let params = $params::new(p,g,q);
let private = DSAPrivateKey::<$params>::new(params, x);
let sig = match h {
224 => private.sign::<SHA224>(mbytes),
256 => private.sign::<SHA256>(mbytes),
384 => private.sign::<SHA384>(mbytes),
512 => private.sign::<SHA512>(mbytes),
_ => panic!("Unexpected hash {}", h)
};
assert_eq!(r, sig.r);
assert_eq!(s, sig.s);
});
}
}
)*
}
}
generate_tests!( (DSA1024N160, L1024N160, U1024, U192),
(DSA2048N224, L2048N224, U2048, U256),
(DSA2048N256, L2048N256, U2048, U256),
(DSA3072N256, L3072N256, U3072, U256)
);

View File

@@ -1,38 +1,29 @@
use cryptonum::unsigned::*;
use cryptonum::signed::ModInv;
use dsa::params::*;
use cryptonum::{SCN,UCN};
use digest::{FixedOutput,Input};
use dsa::parameters::{DSAParameters,n_bits};
use dsa::rfc6979::DSASignature;
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,ToASN1};
use sha::Hash;
use num::BigInt;
use simple_asn1::{ASN1Block,ToASN1,ASN1EncodeErr,ASN1Class};
use std::cmp::min;
use utils::TranslateNums;
use std::ops::Rem;
/// A DSA public key, parameterized by its DSA parameters (so that you don't
/// accidentally pass the wrong thing to the wrong function).
pub struct DSAPublicKey<Params: DSAParameters> {
pub(crate) params: Params,
pub(crate) y: Params::L
/// A DSA key pair
#[derive(Clone,Debug,PartialEq)]
pub struct DSAPublic {
pub params: DSAParameters,
pub y: UCN
}
/// An enumeration that hides exactly which parameters you're using. Use at
/// your own risk, as the types won't save you.
pub enum DSAPublic {
DSAPublicL1024N160(DSAPublicKey<L1024N160>),
DSAPublicL2048N224(DSAPublicKey<L2048N224>),
DSAPublicL2048N256(DSAPublicKey<L2048N256>),
DSAPublicL3072N256(DSAPublicKey<L3072N256>)
impl DSAPublic {
pub fn new(params: &DSAParameters, y: UCN) -> DSAPublic {
DSAPublic {
params: params.clone(),
y: y
}
}
macro_rules! pubkey_impls {
($ptype: ident, $ltype: ident, $ntype: ident, $dbl: ident, $bdbl: ident) => {
impl DSAPublicKey<$ptype>
{
pub fn new(params: $ptype, y: $ltype) -> DSAPublicKey<$ptype>
{
DSAPublicKey{ params, y }
}
pub fn verify<H: Hash>(&self, m: &[u8], sig: &DSASignature<$ntype>) -> bool
pub fn verify<Hash>(&self, m: &[u8], sig: &DSASignature) -> bool
where Hash: Clone + Default + Input + FixedOutput
{
if sig.r >= self.params.q {
return false;
@@ -41,105 +32,41 @@ macro_rules! pubkey_impls {
return false;
}
// w = (s')^-1 mod q;
if let Some(w) = sig.s.modinv(&self.params.q) {
let w = sig.s.modinv(&self.params.q);
// z = the leftmost min(N, outlen) bits of Hash(M').
let mut digest_bytes = <H>::hash(m);
let len = min(digest_bytes.len(), $ptype::n_size() / 8);
digest_bytes.truncate(len);
let z = $ntype::from_bytes(&digest_bytes);
let mut digest = <Hash>::default();
digest.process(m);
let z = { let mut bytes: Vec<u8> = digest.fixed_result()
.as_slice()
.iter()
.map(|x| *x)
.collect();
let n = n_bits(self.params.size) / 8;
let len = min(n, bytes.len());
bytes.truncate(len);
UCN::from_bytes(&bytes) };
// u1 = (zw) mod q
let qdbl = $dbl::from(&self.params.q);
let u1 = $ltype::from( (&z * &w) % &qdbl );
let u1 = (&z * &w).reduce(&self.params.qu);
// u2 = (rw) mod q
let u2 = $ltype::from( (&sig.r * &w) % &qdbl );
let u2 = (&sig.r * &w).reduce(&self.params.qu);
// v = (((g)^u1(y)^u2) mod p) mod q
let v_1 = self.params.g.modexp(&u1, &self.params.p);
let v_2 = self.y.modexp(&u2, &self.params.p);
let bigp = $bdbl::from(&self.params.p);
let v_first_mod = (v_1 * v_2) % bigp;
let v = $ltype::from(v_first_mod) % $ltype::from(&self.params.q);
let v_1 = self.params.g.fastmodexp(&u1, &self.params.pu);
let v_2 = self.y.fastmodexp(&u2, &self.params.pu);
let v = (&v_1 * &v_2).reduce(&self.params.pu)
.rem(&self.params.q);
// if v = r, then the signature is verified
return $ntype::from(v) == sig.r
}
false
v == sig.r
}
}
impl ToASN1 for DSAPublicKey<$ptype> {
impl ToASN1 for DSAPublic {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let inty = self.y.to_num();
let yblock = ASN1Block::Integer(c, 0, inty);
let inty = SCN::from(self.y.clone());
let yblock = ASN1Block::Integer(c, 0, BigInt::from(inty));
Ok(vec![yblock])
}
}
};
}
pubkey_impls!(L1024N160, U1024, U192, U384, U2048);
pubkey_impls!(L2048N224, U2048, U256, U512, U4096);
pubkey_impls!(L2048N256, U2048, U256, U512, U4096);
pubkey_impls!(L3072N256, U3072, U256, U512, U6144);
macro_rules! generate_tests {
( $( ($mod: ident, $params: ident, $lt: ident, $nt: ident) ),* ) => {
$(
#[cfg(test)]
#[allow(non_snake_case)]
mod $mod {
use cryptonum::unsigned::Decoder;
use super::*;
use testing::run_test;
use sha::{SHA224,SHA256,SHA384,SHA512};
#[test]
fn verify() {
let fname = format!("testdata/dsa/sign{}.test", stringify!($params));
run_test(fname.to_string(), 9, |case| {
let (neg0, pbytes) = case.get("p").unwrap();
let (neg1, qbytes) = case.get("q").unwrap();
let (neg2, gbytes) = case.get("g").unwrap();
let (neg3, ybytes) = case.get("y").unwrap();
let (neg4, _bytes) = case.get("x").unwrap();
let (neg5, mbytes) = case.get("m").unwrap();
let (neg6, hbytes) = case.get("h").unwrap();
let (neg7, rbytes) = case.get("r").unwrap();
let (neg8, sbytes) = case.get("s").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 &&
!neg5 && !neg6 && !neg7 && !neg8);
let p = $lt::from_bytes(pbytes);
let q = $nt::from_bytes(qbytes);
let g = $lt::from_bytes(gbytes);
//let x = $lt::from_bytes(xbytes);
let y = $lt::from_bytes(ybytes);
let h = usize::from($nt::from_bytes(hbytes));
let r = $nt::from_bytes(rbytes);
let s = $nt::from_bytes(sbytes);
let params = $params::new(p,g,q);
let public = DSAPublicKey::<$params>::new(params, y);
let sig = DSASignature::<$nt>::new(r, s);
match h {
224 => assert!(public.verify::<SHA224>(mbytes, &sig)),
256 => assert!(public.verify::<SHA256>(mbytes, &sig)),
384 => assert!(public.verify::<SHA384>(mbytes, &sig)),
512 => assert!(public.verify::<SHA512>(mbytes, &sig)),
_ => panic!("Unexpected hash {}", h)
}
});
}
}
)*
}
}
generate_tests!( (DSA1024N160, L1024N160, U1024, U192),
(DSA2048N224, L2048N224, U2048, U256),
(DSA2048N256, L2048N256, U2048, U256),
(DSA3072N256, L3072N256, U3072, U256)
);

View File

@@ -1,45 +1,31 @@
use cryptonum::unsigned::{CryptoNum,Decoder,Encoder};
use hmac::HMAC;
use sha::Hash;
use num::BigInt;
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr};
use simple_asn1::{FromASN1,ToASN1};
use utils::TranslateNums;
use std::ops::{Shr,Sub};
#[derive(Debug,PartialEq)]
pub struct DSASignature<N>
{
pub r: N,
pub s: N
}
impl<N> DSASignature<N>
{
pub fn new(r: N, s: N) -> DSASignature<N>
{
DSASignature{ r, s }
}
}
use cryptonum::UCN;
use digest::{BlockInput,FixedOutput,Input};
use digest::generic_array::ArrayLength;
use hmac::{Hmac,Mac};
use num::{BigInt,Signed};
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,
FromASN1, ToASN1};
use std::clone::Clone;
#[allow(non_snake_case)]
pub struct KIterator<H,N>
pub struct KIterator<H>
where
H: Hash + Clone,
N: Clone + Decoder + Encoder + PartialOrd + Shr<usize,Output=N>,
H: Clone + BlockInput + Input + FixedOutput + Default,
H::BlockSize : ArrayLength<u8>
{
hmac_k: HMAC<H>,
hmac_k: Hmac<H>,
V: Vec<u8>,
q: N,
q: UCN,
qlen: usize
}
impl<H,N> KIterator<H,N>
impl<H> KIterator<H>
where
H: Hash + Clone,
N: Clone + Decoder + Encoder + PartialOrd + Shr<usize,Output=N> + Sub<Output=N>,
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H::BlockSize : ArrayLength<u8>
{
pub fn new(h1: &[u8], qlen: usize, q: &N, x: &N) -> KIterator<H,N>
pub fn new(h1: &[u8], qlen: usize, q: &UCN, x: &UCN) -> KIterator<H>
{
// Given the input message m, the following process is applied:
//
@@ -92,11 +78,11 @@ impl<H,N> KIterator<H,N>
input.push(0x00);
input.extend_from_slice(&xbytes);
input.extend_from_slice(&h1bytes);
K = HMAC::<H>::hmac(&K, &input);
K = hmac(&K, &input);
// e. Set:
//
// V = HMAC_K(V)
V = HMAC::<H>::hmac(&K, &V);
V = hmac(&K, &V);
// f. Set:
//
// K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1))
@@ -107,14 +93,14 @@ impl<H,N> KIterator<H,N>
input.push(0x01);
input.extend_from_slice(&xbytes);
input.extend_from_slice(&h1bytes);
K = HMAC::<H>::hmac(&K, &input);
K = hmac(&K, &input);
// g. Set:
//
// V = HMAC_K(V)
V = HMAC::<H>::hmac(&K, &V);
V = hmac(&K, &V);
// h is for later ...
KIterator {
hmac_k: HMAC::<H>::new(&K),
hmac_k: Hmac::<H>::new(&K).unwrap(),
V: V,
q: q.clone(),
qlen: qlen
@@ -122,15 +108,15 @@ impl<H,N> KIterator<H,N>
}
}
impl<H,N> Iterator for KIterator<H,N>
impl<H> Iterator for KIterator<H>
where
H: Hash + Clone,
N: Clone + CryptoNum + Decoder + Encoder + PartialOrd + Shr<usize,Output=N>,
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H::BlockSize : ArrayLength<u8>
{
type Item = N;
type Item = UCN;
fn next(&mut self) -> Option<N>
{
fn next(&mut self) -> Option<UCN> {
loop {
// h. Apply the following algorithm until a proper value is found
// for k:
@@ -152,7 +138,7 @@ impl<H,N> Iterator for KIterator<H,N>
// 3. Compute:
//
// k = bits2int(T)
let resk: N = bits2int(&t, self.qlen);
let resk = bits2int(&t, self.qlen);
//
// If that value of k is within the [1,q-1] range, and is
// suitable for DSA or ECDSA (i.e., it results in an r value
@@ -166,73 +152,74 @@ impl<H,N> Iterator for KIterator<H,N>
#[allow(non_snake_case)]
let K = runhmac(&self.hmac_k, &input);
// V = HMAC_K(V)
self.hmac_k = HMAC::<H>::new(&K);
self.hmac_k = Hmac::<H>::new(&K).unwrap();
self.V = runhmac(&self.hmac_k, &self.V);
//
// and loop (try to generate a new T, and so on).
//
if !resk.is_zero() && (resk < self.q) {
if !resk.is_zero() && (&resk < &self.q) {
return Some(resk);
}
}
}
}
pub fn bits2int<X>(x: &[u8], qlen: usize) -> X
where
X: Decoder + Shr<usize,Output=X>
{
pub fn bits2int(x: &[u8], qlen: usize) -> UCN {
let mut value = UCN::from_bytes(x);
let vlen = x.len() * 8;
if qlen < (x.len() * 8) {
let mut fixed_x = Vec::from(x);
let qlen_bytes = (qlen + 7) / 8;
let rounded_qlen = qlen_bytes * 8;
fixed_x.resize(qlen_bytes, 0);
X::from_bytes(&fixed_x) >> (rounded_qlen - qlen)
} else {
X::from_bytes(x)
}
if vlen > qlen {
value >>= vlen - qlen;
}
fn bits2octets<X>(x: &[u8], q: &X, qlen: usize) -> Vec<u8>
where
X: Clone + Decoder + Encoder + PartialOrd + Sub<Output=X> + Shr<usize,Output=X>
{
let z1: X = bits2int(x, qlen);
let res = if &z1 > q { z1 - q.clone() } else { z1 };
value
}
fn bits2octets(x: &[u8], q: &UCN, qlen: usize) -> Vec<u8> {
let z1 = bits2int(x, qlen);
let res = if &z1 > q { z1 - q } else { z1 };
int2octets(&res, qlen)
}
fn int2octets<X>(x: &X, qlen_bits: usize) -> Vec<u8>
where X: Encoder
{
fn int2octets(x: &UCN, qlen_bits: usize) -> Vec<u8> {
let qlen_bytes = (qlen_bits + 7) / 8;
let mut base = x.to_bytes();
while base.len() < qlen_bytes {
base.insert(0,0);
x.to_bytes(qlen_bytes)
}
while base.len() > qlen_bytes {
base.remove(0);
}
base
}
fn runhmac<H: Hash + Clone>(base: &HMAC<H>, m: &[u8]) -> Vec<u8>
fn runhmac<H>(base: &Hmac<H>, m: &[u8]) -> Vec<u8>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H::BlockSize : ArrayLength<u8>
{
let mut runner = base.clone();
runner.update(&m);
runner.finalize()
runner.input(&m);
runner.result().code().as_slice().to_vec()
}
fn hmac<H>(k: &[u8], m: &[u8]) -> Vec<u8>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H::BlockSize : ArrayLength<u8>
{
let mut runner = Hmac::<H>::new(&k).unwrap();
runner.input(&m);
runner.result().code().as_slice().to_vec()
}
/// A DSA Signature
#[derive(Clone,Debug,PartialEq)]
pub struct DSASignature {
pub r: UCN,
pub s: UCN
}
#[derive(Clone,Debug,PartialEq)]
pub enum DSADecodeError {
ASN1Error(ASN1DecodeErr),
NoSignatureFound,
InvalidRValue,
InvalidSValue
NegativeSigValues
}
impl From<ASN1DecodeErr> for DSADecodeError {
@@ -241,13 +228,11 @@ impl From<ASN1DecodeErr> for DSADecodeError {
}
}
impl<N> FromASN1 for DSASignature<N>
where N: TranslateNums<BigInt>
{
impl FromASN1 for DSASignature {
type Error = DSADecodeError;
fn from_asn1(v: &[ASN1Block])
-> Result<(DSASignature<N>,&[ASN1Block]),DSADecodeError>
-> Result<(DSASignature,&[ASN1Block]),DSADecodeError>
{
match v.split_first() {
Some((&ASN1Block::Sequence(_,_,ref info), rest))
@@ -256,9 +241,12 @@ impl<N> FromASN1 for DSASignature<N>
match (&info[0], &info[1]) {
(&ASN1Block::Integer(_,_,ref rint),
&ASN1Block::Integer(_,_,ref sint)) => {
let r = N::from_num(rint).ok_or(DSADecodeError::InvalidRValue)?;
let s = N::from_num(sint).ok_or(DSADecodeError::InvalidSValue)?;
Ok((DSASignature{ r, s }, rest))
if rint.is_negative() || sint.is_negative() {
return Err(DSADecodeError::NegativeSigValues)
}
let r = UCN::from(rint);
let s = UCN::from(sint);
Ok((DSASignature{ r: r, s: s }, rest))
}
_ => Err(DSADecodeError::NoSignatureFound)
}
@@ -268,26 +256,22 @@ impl<N> FromASN1 for DSASignature<N>
}
}
impl<N> ToASN1 for DSASignature<N>
where N: TranslateNums<BigInt>
{
impl ToASN1 for DSASignature {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let rb = ASN1Block::Integer(c, 0, self.r.to_num());
let sb = ASN1Block::Integer(c, 0, self.s.to_num());
let rb = ASN1Block::Integer(c, 0, BigInt::from(self.r.clone()));
let sb = ASN1Block::Integer(c, 0, BigInt::from(self.s.clone()));
Ok(vec![ASN1Block::Sequence(c, 0, vec![rb,sb])])
}
}
#[cfg(test)]
mod tests {
use cryptonum::unsigned::U192;
use sha::{SHA224,SHA256,SHA384,SHA512};
use sha2::Sha256;
use super::*;
use testing::*;
const QBYTES: [u8; 21] = [0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x01, 0x08, 0xA2, 0xE0, 0xCC,
@@ -302,7 +286,7 @@ mod tests {
#[test]
fn int2octets_example() {
let x = U192::from_bytes(&XBYTES);
let x = UCN::from_bytes(&XBYTES);
let octets = int2octets(&x, 163);
let target = vec![0x00, 0x9A, 0x4D, 0x67, 0x92, 0x29, 0x5A, 0x7F,
0x73, 0x0F, 0xC3, 0xF2, 0xB4, 0x9C, 0xBC, 0x0F,
@@ -312,7 +296,7 @@ mod tests {
#[test]
fn bits2octets_example() {
let q = U192::from_bytes(&QBYTES);
let q = UCN::from_bytes(&QBYTES);
let octets = bits2octets(&H1, &q, 163);
let target = vec![0x01, 0x79, 0x5E, 0xDF, 0x0D, 0x54, 0xDB, 0x76,
0x0F, 0x15, 0x6D, 0x0D, 0xAC, 0x04, 0xC0, 0x32,
@@ -322,9 +306,9 @@ mod tests {
#[test]
fn k_gen_example() {
let q = U192::from_bytes(&QBYTES);
let x = U192::from_bytes(&XBYTES);
let mut iter = KIterator::<SHA256,U192>::new(&H1, 163, &q, &x);
let q = UCN::from_bytes(&QBYTES);
let x = UCN::from_bytes(&XBYTES);
let mut iter = KIterator::<Sha256>::new(&H1, 163, &q, &x);
match iter.next() {
None =>
assert!(false),
@@ -332,86 +316,9 @@ mod tests {
let target = vec![0x02, 0x3A, 0xF4, 0x07, 0x4C, 0x90, 0xA0,
0x2B, 0x3F, 0xE6, 0x1D, 0x28, 0x6D, 0x5C,
0x87, 0xF4, 0x25, 0xE6, 0xBD, 0xD8, 0x1B];
let x2 = U192::from_bytes(&target);
let x2 = UCN::from_bytes(&target);
assert_eq!(x, x2);
}
}
}
use cryptonum::unsigned::*;
macro_rules! k_generator_tests {
($testname: ident, $hash: ident, $fname: expr) => {
#[test]
fn $testname() {
let fname = build_test_path("rfc6979", $fname);
run_test(fname.to_string(), 7, |case| {
let (negq, qbytes) = case.get("q").unwrap();
let (negl, lbytes) = case.get("l").unwrap();
let (negx, xbytes) = case.get("x").unwrap();
let (negh, h1) = case.get("h").unwrap();
let (negk, kbytes) = case.get("k").unwrap();
let (negy, ybytes) = case.get("y").unwrap();
let (negz, zbytes) = case.get("z").unwrap();
assert!(!negq && !negl && !negx && !negh &&
!negk && !negy && !negz);
let qlen = usize::from(U192::from_bytes(lbytes));
assert!(qlen >= 160); assert!(qlen <= 521);
if qlen < 192 {
let q = U192::from_bytes(qbytes);
let x = U192::from_bytes(xbytes);
let k = U192::from_bytes(kbytes);
let y = U192::from_bytes(ybytes);
let z = U192::from_bytes(zbytes);
let mut kiter = KIterator::<$hash,U192>::new(h1,qlen,&q,&x);
assert_eq!(Some(k), kiter.next(), "first value test");
assert_eq!(Some(y), kiter.next(), "second value test");
assert_eq!(Some(z), kiter.next(), "third value test");
} else if qlen < 256 {
let q = U256::from_bytes(qbytes);
let x = U256::from_bytes(xbytes);
let k = U256::from_bytes(kbytes);
let y = U256::from_bytes(ybytes);
let z = U256::from_bytes(zbytes);
let mut kiter = KIterator::<$hash,U256>::new(h1,qlen,&q,&x);
assert_eq!(Some(k), kiter.next(), "first value test");
assert_eq!(Some(y), kiter.next(), "second value test");
assert_eq!(Some(z), kiter.next(), "third value test");
} else if qlen < 512 {
let q = U512::from_bytes(qbytes);
let x = U512::from_bytes(xbytes);
let k = U512::from_bytes(kbytes);
let y = U512::from_bytes(ybytes);
let z = U512::from_bytes(zbytes);
let mut kiter = KIterator::<$hash,U512>::new(h1,qlen,&q,&x);
assert_eq!(Some(k), kiter.next(), "first value test");
assert_eq!(Some(y), kiter.next(), "second value test");
assert_eq!(Some(z), kiter.next(), "third value test");
} else {
let q = U576::from_bytes(qbytes);
let x = U576::from_bytes(xbytes);
let k = U576::from_bytes(kbytes);
let y = U576::from_bytes(ybytes);
let z = U576::from_bytes(zbytes);
let mut kiter = KIterator::<$hash,U576>::new(h1,qlen,&q,&x);
assert_eq!(Some(k), kiter.next(), "first value test");
assert_eq!(Some(y), kiter.next(), "second value test");
assert_eq!(Some(z), kiter.next(), "third value test");
}
});
}
};
}
k_generator_tests!(kgen_sha224, SHA224, "SHA224");
k_generator_tests!(kgen_sha256, SHA256, "SHA256");
k_generator_tests!(kgen_sha384, SHA384, "SHA384");
k_generator_tests!(kgen_sha512, SHA512, "SHA512");
}

View File

@@ -1,498 +0,0 @@
use cryptonum::signed::{I192,I256,I384,I576};
use cryptonum::unsigned::{Decoder};
use cryptonum::unsigned::{U192,U256,U384,U576};
use ecdsa::point::Point;
use std::fmt::Debug;
/// Elliptic curves must implement this trait in order to work with the rest
/// of the ECDSA system. I've included instances for the core NIST curves
/// used in most systems, but this could be extended without issues.
/// (Eventually the curves defined here should actually be extended in
/// interesting ways to make the math faster, but we haven't gotten there
/// yet.)
#[allow(non_snake_case)]
pub trait EllipticCurve {
/// The unsigned numeric type that fits constants for this curve.
type Unsigned : Clone;
/// The signed numeric type that fits constants for this curve.
type Signed : Clone + Debug + PartialEq;
/// The type of a point on the curve
type Point;
/// The size of the curve in bits.
fn size() -> usize;
/// The `p` value for the curve.
fn p() -> Self::Unsigned;
/// The `p` value for the curve.
fn n() -> Self::Unsigned;
/// The seed value for the curve.
fn SEED() -> Self::Unsigned;
/// The `c` value for the curve.
fn c() -> Self::Unsigned;
/// The `a` value for the curve.
fn a() -> Self::Unsigned;
/// The `b` value for the curve.
fn b() -> Self::Unsigned;
/// The `x` coordinate of the base point for the curve.
fn Gx() -> Self::Signed;
/// The `y` coordinate of the base point for the curve.
fn Gy() -> Self::Signed;
/// Generate a point for the curve given the provided values.
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point;
}
/// NIST curve P-192 (FIPS 186-4, page 101-102), a.k.a. secp192r1 from RFC5480
#[derive(Debug,PartialEq)]
pub struct P192 {}
impl EllipticCurve for P192 {
type Unsigned = U192;
type Signed = I192;
type Point = Point<P192>;
fn size() -> usize {
192
}
fn p() -> U192 {
U192::from([0xffffffffffffffff, 0xfffffffffffffffe, 0xffffffffffffffff])
}
fn n() -> U192 {
U192::from([0x146bc9b1b4d22831, 0xffffffff99def836, 0xffffffffffffffff])
}
fn SEED() -> U192 {
U192::from([0xd38020eae12196d5, 0xc8422f64ed579528, 0x3045ae6f])
}
fn c() -> U192 {
U192::from([0x5f3d6fe2c745de65, 0x542dcd5fb078b6ef, 0x3099d2bbbfcb2538])
}
fn a() -> U192 {
U192::from([0xfffffffffffffffc, 0xfffffffffffffffe, 0xffffffffffffffff])
}
fn b() -> U192 {
U192::from([0xfeb8deecc146b9b1, 0x0fa7e9ab72243049, 0x64210519e59c80e7])
}
fn Gx() -> I192 {
I192::from(U192::from([0xf4ff0afd82ff1012, 0x7cbf20eb43a18800, 0x188da80eb03090f6]))
}
fn Gy() -> I192 {
I192::from(U192::from([0x73f977a11e794811, 0x631011ed6b24cdd5, 0x07192b95ffc8da78]))
}
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
Point::<P192>{ x: I192::from(x), y: I192::from(y) }
}
}
/// NIST curve P-224 (FIPS 186-4, page 102), a.k.a. secp224r1 from RFC5480
#[derive(Debug,PartialEq)]
pub struct P224 {}
impl EllipticCurve for P224 {
type Unsigned = U256;
type Signed = I256;
type Point = Point<P224>;
fn size() -> usize {
224
}
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
]))
}
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
Point::<P224>{ x: I256::from(x), y: I256::from(y) }
}
}
/// NIST curve P-256 (FIPS 186-4, page 102-103), a.k.a. secp256r1 from RFC5480
#[derive(Debug,PartialEq)]
pub struct P256 {}
impl EllipticCurve for P256 {
type Signed = I256;
type Unsigned = U256;
type Point = Point<P256>;
fn size() -> usize {
256
}
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
]))
}
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
Point::<P256>{ x: I256::from(x), y: I256::from(y) }
}
}
/// NIST curve P-384 (FIPS 186-4, page 103-104), a.k.a. secp384r1 from RFC5480
#[derive(Debug,PartialEq)]
pub struct P384 {}
impl EllipticCurve for P384 {
type Signed = I384;
type Unsigned = U384;
type Point = Point<P384>;
fn size() -> usize {
384
}
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
]))
}
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
Point::<P384>{ x: I384::from(x), y: I384::from(y) }
}
}
/// NIST curve P-521 (FIPS 186-4, page 104), a.k.a. secp521r1 from RFC5480
#[derive(Debug,PartialEq)]
pub struct P521 {}
impl EllipticCurve for P521 {
type Signed = I576;
type Unsigned = U576;
type Point = Point<P521>;
fn size() -> usize {
521
}
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(&[
0x00, 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(&[
0x01, 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
]))
}
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
Point::<P521>{ x: I576::from(x), y: I576::from(y) }
}
}

443
src/ecdsa/curves.rs Normal file
View File

@@ -0,0 +1,443 @@
use cryptonum::{BarrettUCN,SCN,UCN};
use ecdsa::point::ECPoint;
use std::fmt;
pub struct EllipticCurve {
pub name: &'static str,
pub p: [u8; 66],
pub n: [u8; 66],
pub seed: [u8; 66],
pub c: [u8; 66],
pub a: [u8; 66],
pub b: [u8; 66],
pub gx: [u8; 66],
pub gy: [u8; 66]
}
impl fmt::Debug for EllipticCurve {
fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)
}
}
impl PartialEq for EllipticCurve {
fn eq(&self, other: &EllipticCurve) -> bool {
self.name == other.name
}
}
impl EllipticCurve {
pub fn get_p(&self) -> UCN {
UCN::from_bytes(&self.p)
}
pub fn get_pu(&self) -> BarrettUCN {
self.get_p().barrett_uk(self.get_p().contents.len() + 4)
}
pub fn get_n(&self) -> UCN {
UCN::from_bytes(&self.n)
}
pub fn get_seed(&self) -> UCN {
UCN::from_bytes(&self.seed)
}
pub fn get_c(&self) -> UCN {
UCN::from_bytes(&self.c)
}
pub fn get_a(&self) -> UCN {
UCN::from_bytes(&self.a)
}
pub fn get_b(&self) -> UCN {
UCN::from_bytes(&self.b)
}
pub fn default(&'static self) -> ECPoint {
let x = SCN::from(UCN::from_bytes(&self.gx));
let y = SCN::from(UCN::from_bytes(&self.gy));
ECPoint::new(self, x, y)
}
}
pub const NIST_P192: EllipticCurve = EllipticCurve {
name: "secp192r1",
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff ],
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99, 0xde,
0xf8, 0x36, 0x14, 0x6b, 0xc9, 0xb1, 0xb4, 0xd2,
0x28, 0x31 ],
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x45,
0xae, 0x6f, 0xc8, 0x42, 0x2f, 0x64, 0xed, 0x57,
0x95, 0x28, 0xd3, 0x81, 0x20, 0xea, 0xe1, 0x21,
0x96, 0xd5 ],
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x99, 0xd2, 0xbb, 0xbf, 0xcb,
0x25, 0x38, 0x54, 0x2d, 0xcd, 0x5f, 0xb0, 0x78,
0xb6, 0xef, 0x5f, 0x3d, 0x6f, 0xe2, 0xc7, 0x45,
0xde, 0x65 ],
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfc ],
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x64, 0x21, 0x05, 0x19, 0xe5, 0x9c,
0x80, 0xe7, 0x0f, 0xa7, 0xe9, 0xab, 0x72, 0x24,
0x30, 0x49, 0xfe, 0xb8, 0xde, 0xec, 0xc1, 0x46,
0xb9, 0xb1 ],
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x8d, 0xa8, 0x0e, 0xb0, 0x30,
0x90, 0xf6, 0x7c, 0xbf, 0x20, 0xeb, 0x43, 0xa1,
0x88, 0x00, 0xf4, 0xff, 0x0a, 0xfd, 0x82, 0xff,
0x10, 0x12 ],
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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 const NIST_P224: EllipticCurve = EllipticCurve {
name: "secp224r1",
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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],
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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],
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x71,
0x34, 0x47, 0x99, 0xd5, 0xc7, 0xfc, 0xdc, 0x45,
0xb5, 0x9f, 0xa3, 0xb9, 0xab, 0x8f, 0x6a, 0x94,
0x8b, 0xc5],
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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],
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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],
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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],
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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],
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 const NIST_P256: EllipticCurve = EllipticCurve {
name: "secp256r1",
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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],
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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],
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x9d,
0x36, 0x08, 0x86, 0xe7, 0x04, 0x93, 0x6a, 0x66,
0x78, 0xe1, 0x13, 0x9d, 0x26, 0xb7, 0x81, 0x9f,
0x7e, 0x90],
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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],
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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],
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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],
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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],
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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 const NIST_P384: EllipticCurve = EllipticCurve {
name: "secp384r1",
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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],
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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],
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x35,
0x92, 0x6a, 0xa3, 0x19, 0xa2, 0x7a, 0x1d, 0x00,
0x89, 0x6a, 0x67, 0x73, 0xa4, 0x82, 0x7a, 0xcd,
0xac, 0x73],
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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],
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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],
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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],
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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],
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 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 const NIST_P521: EllipticCurve = EllipticCurve {
name: "secp521r1",
p: [ 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 ],
n: [ 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 ],
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x9e,
0x88, 0x00, 0x29, 0x1c, 0xb8, 0x53, 0x96, 0xcc,
0x67, 0x17, 0x39, 0x32, 0x84, 0xaa, 0xa0, 0xda,
0x64, 0xba ],
c: [ 0x00, 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 ],
a: [ 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 ],
b: [ 0x00, 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 ],
gx: [ 0x00, 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 ],
gy: [ 0x00, 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 ]
};

187
src/ecdsa/gold_tests.rs Normal file
View File

@@ -0,0 +1,187 @@
use cryptonum::{SCN,UCN};
//use dsa::rfc6979::*;
use ecdsa::curves::*;
use ecdsa::point::ECPoint;
//use ecdsa::private::ECDSAPrivate;
//use ecdsa::public::ECDSAPublic;
//use sha1::Sha1;
//use sha2::{Sha224,Sha256,Sha384,Sha512};
use testing::run_test;
fn get_curve(cbytes: &[u8]) -> &'static EllipticCurve {
match usize::from(UCN::from_bytes(cbytes)) {
0x192 => &NIST_P192,
0x224 => &NIST_P224,
0x256 => &NIST_P256,
0x384 => &NIST_P384,
0x521 => &NIST_P521,
x => panic!("Unacceptable curve identifier {}", x)
}
}
#[test]
fn point_negate()
{
run_test("tests/ecdsa/ec_negate.test", 5, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, cbytes) = case.get("c").unwrap();
let (neg3, xbytes) = case.get("x").unwrap();
let (neg4, ybytes) = case.get("y").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4);
let curve = get_curve(&cbytes);
let x = SCN::from(UCN::from_bytes(xbytes));
let y = SCN::from(UCN::from_bytes(ybytes));
let orig = ECPoint::new(curve, x, y);
let a = SCN::from(UCN::from_bytes(abytes));
let b = SCN::from(UCN::from_bytes(bbytes));
let inverted = ECPoint::new(curve, a, b);
assert_eq!(inverted, orig.negate());
});
}
#[test]
fn point_double()
{
run_test("tests/ecdsa/ec_dble.test", 5, |case| {
println!("START");
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, cbytes) = case.get("c").unwrap();
let (neg3, xbytes) = case.get("x").unwrap();
let (neg4, ybytes) = case.get("y").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4);
println!("SEC1");
let curve = get_curve(&cbytes);
println!("SEC2");
let x = SCN::from(UCN::from_bytes(xbytes));
let y = SCN::from(UCN::from_bytes(ybytes));
let orig = ECPoint::new(curve, x, y);
println!("SEC3");
let a = SCN::from(UCN::from_bytes(abytes));
let b = SCN::from(UCN::from_bytes(bbytes));
let doubled = ECPoint::new(curve, a, b);
println!("SEC4");
assert_eq!(doubled, orig.double());
});
}
#[test]
fn point_add()
{
run_test("tests/ecdsa/ec_add.test", 7, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, qbytes) = case.get("q").unwrap();
let (neg3, rbytes) = case.get("r").unwrap();
let (neg4, cbytes) = case.get("c").unwrap();
let (neg5, xbytes) = case.get("x").unwrap();
let (neg6, ybytes) = case.get("y").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5 && !neg6);
let curve = get_curve(&cbytes);
let x = SCN::from(UCN::from_bytes(xbytes));
let y = SCN::from(UCN::from_bytes(ybytes));
let p1 = ECPoint::new(curve, x, y);
let q = SCN::from(UCN::from_bytes(qbytes));
let r = SCN::from(UCN::from_bytes(rbytes));
let p2 = ECPoint::new(curve, q, r);
let a = SCN::from(UCN::from_bytes(abytes));
let b = SCN::from(UCN::from_bytes(bbytes));
let result = ECPoint::new(curve, a, b);
assert_eq!(result, p1.add(&p2));
});
}
#[test]
fn point_scale()
{
run_test("tests/ecdsa/ec_mul.test", 6, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, kbytes) = case.get("k").unwrap();
let (neg3, cbytes) = case.get("c").unwrap();
let (neg4, xbytes) = case.get("x").unwrap();
let (neg5, ybytes) = case.get("y").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5);
let curve = get_curve(&cbytes);
let x = SCN::from(UCN::from_bytes(xbytes));
let y = SCN::from(UCN::from_bytes(ybytes));
let base = ECPoint::new(curve, x, y);
let k = UCN::from_bytes(kbytes);
let a = SCN::from(UCN::from_bytes(abytes));
let b = SCN::from(UCN::from_bytes(bbytes));
let result = ECPoint::new(curve, a, b);
assert_eq!(result, base.scale(&k));
});
}
//#[test]
//fn verification_tests()
//{
// run_test("tests/ecdsa/signature.test", 8, |case| {
// let (neg0, cbytes) = case.get("c").unwrap();
// let (negx, xbytes) = case.get("x").unwrap();
// let (negy, ybytes) = case.get("y").unwrap();
// let (neg1, hbytes) = case.get("h").unwrap();
// let (neg2, msg) = case.get("m").unwrap();
// let (neg3, rbytes) = case.get("r").unwrap();
// let (neg4, sbytes) = case.get("s").unwrap();
//
// assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4);
// let curve = get_curve(cbytes);
// let ux = UCN::from_bytes(xbytes);
// let uy = UCN::from_bytes(ybytes);
// let x = SCN{ negative: *negx, value: ux };
// let y = SCN{ negative: *negy, value: uy };
// let point = ECCPoint::new(&curve, x, y);
// let public = ECDSAPublic::new(&curve, &point);
// let r = UCN::from_bytes(rbytes);
// let s = UCN::from_bytes(sbytes);
// println!("r: {:X}", r);
// let sig = DSASignature{ r: r, s: s };
//
// match usize::from(UCN::from_bytes(hbytes)) {
// 0x1 => assert!(public.verify::<Sha1>(msg, &sig)),
// 0x224 => assert!(public.verify::<Sha224>(msg, &sig)),
// 0x256 => assert!(public.verify::<Sha256>(msg, &sig)),
// 0x384 => assert!(public.verify::<Sha384>(msg, &sig)),
// 0x512 => assert!(public.verify::<Sha512>(msg, &sig)),
// v => panic!("Bad hash size {}!", v)
// }
// });
//}
//
//#[test]
//fn signing_tests()
//{
// run_test("tests/ecdsa/signature.test", 8, |case| {
// let (neg0, cbytes) = case.get("c").unwrap();
// let (neg1, dbytes) = case.get("d").unwrap();
// let (neg2, hbytes) = case.get("h").unwrap();
// let (neg3, msg) = case.get("m").unwrap();
// let (neg4, rbytes) = case.get("r").unwrap();
// let (neg5, sbytes) = case.get("s").unwrap();
//
// assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4 & !neg5);
// let curve = get_curve(cbytes);
// let d = UCN::from_bytes(dbytes);
// let private = ECDSAPrivate::new(&curve, &d);
// let r = UCN::from_bytes(rbytes);
// let s = UCN::from_bytes(sbytes);
// let sig = DSASignature{ r: r, s: s };
//
// match usize::from(UCN::from_bytes(hbytes)) {
// 0x1 => assert_eq!(sig, private.sign::<Sha1>(msg)),
// 0x224 => assert_eq!(sig, private.sign::<Sha224>(msg)),
// 0x256 => assert_eq!(sig, private.sign::<Sha256>(msg)),
// 0x384 => assert_eq!(sig, private.sign::<Sha384>(msg)),
// 0x512 => assert_eq!(sig, private.sign::<Sha512>(msg)),
// v => panic!("Bad hash size {}!", v)
// }
// });
//}

View File

@@ -1,121 +1,61 @@
//! The generation and use of ECDSA keys is pretty straightforward, compared
//! to DSA and RSA. You should be able to find what you want to do in the
//! following code snippet, as an example:
//!
//! ```rust
//! use simple_crypto::ecdsa::{ECDSAKeyPair,P384};
//! use simple_crypto::sha::SHA256;
//!
//! // Generate a new ECDSA key for curve P384 (this is a good choice, by
//! // the way, if you're wondering which curve to use).
//! let mut rng = rand::rngs::OsRng::new().unwrap();
//! let kp = ECDSAKeyPair::<P384>::generate(&mut rng);
//!
//! // Now that you have this key pair, you can sign and verify messages
//! // using it. For example, to sign the vector [0,1,2,3,4] with SHA256
//! // and then verify that signature, we would write:
//! let msg = vec![0,1,2,3,4];
//! let sig = kp.private.sign::<SHA256>(&msg);
//! assert!( kp.public.verify::<SHA256>(&msg, &sig) );
//! ```
mod curve;
pub(crate) mod point;
mod private;
mod public;
use cryptonum::signed::{I192,I256,I384,I576};
use cryptonum::unsigned::{CryptoNum,Decoder};
use cryptonum::unsigned::{U192,U256,U384,U576};
use rand::Rng;
use rand::distributions::Standard;
pub use self::curve::{EllipticCurve,P192,P224,P256,P384,P521};
use self::point::{ECCPoint,Point};
pub use self::private::{ECDSAPrivate,ECCPrivateKey};
pub use self::public::{ECDSAPublic,ECCPublicKey};
pub use self::public::{ECDSADecodeErr,ECDSAEncodeErr};
use super::KeyPair;
/// An ECDSA key pair for the given curve.
pub struct ECDSAKeyPair<Curve: EllipticCurve> {
pub public: ECCPublicKey<Curve>,
pub private: ECCPrivateKey<Curve>
}
/// A generic ECDSA key pair that implements one of our known curves, for cases
/// when you're not sure which one you're going to have.
pub enum ECDSAPair {
P192(ECCPublicKey<P192>,ECCPrivateKey<P192>),
P224(ECCPublicKey<P224>,ECCPrivateKey<P224>),
P256(ECCPublicKey<P256>,ECCPrivateKey<P256>),
P384(ECCPublicKey<P384>,ECCPrivateKey<P384>),
P521(ECCPublicKey<P521>,ECCPrivateKey<P521>),
}
impl KeyPair for ECDSAPair {
type Public = ECDSAPublic;
type Private = ECDSAPrivate;
fn new(pu: ECDSAPublic, pr: ECDSAPrivate) -> ECDSAPair
{
match (pu, pr) {
(ECDSAPublic::P192(pbl),ECDSAPrivate::P192(prv)) => ECDSAPair::P192(pbl,prv),
(ECDSAPublic::P224(pbl),ECDSAPrivate::P224(prv)) => ECDSAPair::P224(pbl,prv),
(ECDSAPublic::P256(pbl),ECDSAPrivate::P256(prv)) => ECDSAPair::P256(pbl,prv),
(ECDSAPublic::P384(pbl),ECDSAPrivate::P384(prv)) => ECDSAPair::P384(pbl,prv),
(ECDSAPublic::P521(pbl),ECDSAPrivate::P521(prv)) => ECDSAPair::P521(pbl,prv),
_ =>
panic!("Non-matching public/private pairs in ECDSAPair::new()")
}
}
}
macro_rules! generate_impl {
($curve: ident, $un: ident, $si: ident) => {
impl KeyPair for ECDSAKeyPair<$curve> {
type Public = ECCPublicKey<$curve>;
type Private = ECCPrivateKey<$curve>;
fn new(public: ECCPublicKey<$curve>, private: ECCPrivateKey<$curve>) -> ECDSAKeyPair<$curve>
{
ECDSAKeyPair{ public, private }
}
}
impl ECDSAKeyPair<$curve> {
/// Generate a fresh ECDSA key pair for this curve, given the
/// provided random number generator. THIS MUST BE A CRYPTO
/// STRONG RNG. If it's not, then you're going to generate weak
/// keys and the crypto gremlins will get you.
pub fn generate<G: Rng>(rng: &mut G) -> ECDSAKeyPair<$curve>
{
loop {
let size = ($curve::size() + 7) / 8;
let random_bytes: Vec<u8> = rng.sample_iter(&Standard).take(size).collect();
let proposed_d = $un::from_bytes(&random_bytes);
if proposed_d.is_zero() {
continue;
}
if proposed_d >= $curve::n() {
continue;
}
let d = $si::from(&proposed_d);
let public_point = Point::<$curve>::default().scale(&d);
let public = ECCPublicKey::<$curve>::new(public_point);
let private = ECCPrivateKey::<$curve>::new(proposed_d);
return ECDSAKeyPair{ public, private };
}
}
}
};
}
generate_impl!(P192, U192, I192);
generate_impl!(P224, U256, I256);
generate_impl!(P256, U256, I256);
generate_impl!(P384, U384, I384);
generate_impl!(P521, U576, I576);
mod curves;
#[cfg(test)]
mod gold_tests;
mod point;
//mod private;
//mod public;
//
//pub use self::private::ECDSAPrivate;
//pub use self::public::ECDSAPublic;
pub use self::curves::{NIST_P192,NIST_P224,NIST_P256,NIST_P384,NIST_P521};
//
//use cryptonum::UCN;
//use rand::{Rng,OsRng};
//use self::curves::EllipticCurve;
//use self::math::ECCPoint;
//
//#[derive(Clone,Debug,PartialEq)]
//pub struct ECDSAKeyPair {
// pub private: ECDSAPrivate,
// pub public: ECDSAPublic
//}
//
//impl ECDSAKeyPair {
// pub fn generate(params: &'static EllipticCurve)
// -> ECDSAKeyPair
// {
// let mut rng = OsRng::new().unwrap();
// ECDSAKeyPair::generate_w_rng(&mut rng, params)
//
// }
//
// pub fn generate_w_rng<G: Rng>(rng: &mut G, params: &'static EllipticCurve)
// -> ECDSAKeyPair
// {
// let one = UCN::from(1u64);
// #[allow(non_snake_case)]
// let N = params.n.bits();
// let bits_to_generate = N + 64;
// let bytes_to_generate = (bits_to_generate + 7) / 8;
// let bits: Vec<u8> = rng.gen_iter().take(bytes_to_generate).collect();
// let bits_generated = bytes_to_generate * 8;
// let mut c = UCN::from_bytes(&bits);
// c >>= bits_generated - bits_to_generate;
// let nm1 = &params.n - &one;
// let d = (c % &nm1) + &one;
// #[allow(non_snake_case)]
// let Q = ECCPoint::default(params).scale(&d);
// ECDSAKeyPair {
// private: ECDSAPrivate {
// curve: params,
// d: d
// },
// public: ECDSAPublic {
// curve: params,
// Q: Q
// }
// }
// }
//}
//
//

View File

@@ -1,329 +1,227 @@
use cryptonum::signed::*;
use cryptonum::unsigned::*;
use ecdsa::curve::*;
use cryptonum::{SCN,UCN};
use ecdsa::curves::EllipticCurve;
pub trait ECCPoint : Sized {
type Curve: EllipticCurve;
type Scale;
#[derive(Clone,Debug,PartialEq)]
pub struct ECPoint {
pub curve: &'static EllipticCurve,
pub value: ECPointValue
}
fn default() -> Self;
fn negate(&self) -> Self;
fn double(&self) -> Self;
fn add(&self, other: &Self) -> Self;
fn scale(&self, amt: &Self::Scale) -> Self;
fn double_scalar_mult(x1: &Self::Scale, p1: &Self, x2: &Self::Scale, p2: &Self) -> Self
{
// FIXME: Replace this with something not stupid.
let big1 = p1.scale(x1);
let big2 = p2.scale(x2);
big1.add(&big2)
#[derive(Clone,Debug,PartialEq)]
pub enum ECPointValue {
Infinity,
Point(SCN, SCN)
}
impl ECPoint {
pub fn new(ec: &'static EllipticCurve, x: SCN, y: SCN) -> ECPoint {
ECPoint {
curve: ec,
value: ECPointValue::Point(x, y)
}
}
#[derive(Debug,PartialEq)]
pub struct Point<T: EllipticCurve>
{
pub x: T::Signed,
pub y: T::Signed
pub fn zero(ec: &'static EllipticCurve) -> ECPoint {
ECPoint { curve: ec, value: ECPointValue::Infinity }
}
macro_rules! point_impl
{
($curve: ident, $base: ident,
$s2: ident, $u2: ident,
$s2p1: ident, $u2p1: ident) =>
{
impl Clone for Point<$curve> {
fn clone(&self) -> Point<$curve> {
Point {
x: self.x.clone(),
y: self.y.clone()
pub fn negate(&self) -> ECPoint {
match self.value {
ECPointValue::Infinity =>
self.clone(),
ECPointValue::Point(ref x, ref y) => {
let newy = SCN::from(self.curve.get_p()) - y;
let newv = ECPointValue::Point(x.clone(), newy);
ECPoint{ curve: self.curve, value: newv }
}
}
}
impl ECCPoint for Point<$curve> {
type Curve = $curve;
type Scale = $base;
fn default() -> Point<$curve>
{
Point {
x: $curve::Gx(),
y: $curve::Gy()
pub fn get_x(&self) -> SCN {
match self.value {
ECPointValue::Infinity =>
SCN::zero(),
ECPointValue::Point(ref x, _) =>
x.clone()
}
}
fn negate(&self) -> Point<$curve>
{
let mut newy = $base::new(false, $curve::p());
newy -= &self.y;
Point{ x: self.x.clone(), y: newy }
pub fn get_y(&self) -> SCN {
match self.value {
ECPointValue::Infinity =>
SCN::zero(),
ECPointValue::Point(_, ref y) =>
y.clone()
}
}
fn double(&self) -> Point<$curve>
{
let up = $curve::p();
let bigp = $s2::new(false, $u2::from(&up));
pub fn double(&self) -> ECPoint {
match self.value {
ECPointValue::Infinity =>
self.clone(),
ECPointValue::Point(ref x, ref y) => {
let ua = SCN::from(self.curve.get_a());
let up = SCN::from(self.curve.get_p());
// lambda = (3 * xp ^ 2 + a) / 2 yp
let xsquared = self.x.square();
let mut lambda_top = &xsquared * 3u64;
lambda_top += $s2p1::new(false, $u2p1::from($curve::a()));
let mut lambda_bot = $s2p1::from(&self.y);
lambda_bot <<= 1;
let lambda = $base::from(lambda_top.moddiv(&lambda_bot, &$s2p1::from(&bigp)));
let mut lambda = x * x;
lambda *= SCN::from(3);
lambda += &ua;
let twoy = y << 1;
lambda = lambda.divmod(&twoy, &self.curve.get_pu());
// xr = lambda ^ 2 - 2 xp
let mut xr = lambda.square();
let mut xr_right = $s2::from(&self.x);
xr_right <<= 1;
let mut xr = &lambda * &lambda;
let xr_right = x << 1;
xr -= xr_right;
xr %= &bigp;
let x = $base::from(xr);
assert!(!xr.is_negative());
xr %= &up;
// yr = lambda (xp - xr) - yp
let xdiff = $base::from(&self.x - &x);
let xdiff = x - &xr;
let mut yr = &lambda * &xdiff;
yr -= $s2::from(&self.y);
let y = $base::from(&yr % &bigp);
yr -= y;
assert!(!yr.is_negative());
yr %= up;
//
Point{ x, y }
ECPoint {
curve: self.curve,
value: ECPointValue::Point(xr, yr)
}
}
}
}
fn add(&self, other: &Point<$curve>) -> Point<$curve>
{
let mut xdiff = self.x.clone(); xdiff -= &other.x;
let mut ydiff = self.y.clone(); ydiff -= &other.y;
let signedp = $base::new(false, $curve::p());
let s = ydiff.moddiv(&xdiff, &signedp);
pub fn add(&self, other: &ECPoint) -> ECPoint {
assert_eq!(self.curve, other.curve);
match (&self.value, &other.value) {
(ECPointValue::Infinity, ECPointValue::Infinity) =>
self.clone(),
(ECPointValue::Infinity, _) =>
other.clone(),
(_, ECPointValue::Infinity) =>
self.clone(),
(ECPointValue::Point(ref sx, ref sy),
ECPointValue::Point(ref ox, ref oy)) => {
let xdiff = sx - ox;
let ydiff = sy - oy;
let pu = self.curve.get_pu();
let s = ydiff.divmod(&xdiff, &pu);
let mut xr = &s * &s;
xr -= $s2::from(&self.x);
xr -= $s2::from(&other.x);
let bigsignedp = $s2::from(&signedp);
xr %= &bigsignedp;
let mut yr = $s2::from(&self.x);
yr -= &xr;
yr *= $s2::from(&s);
yr -= $s2::from(&self.y);
yr %= &bigsignedp;
Point{ x: $base::from(xr), y: $base::from(yr) }
}
fn scale(&self, d: &$base) -> Point<$curve>
{
assert!(!d.is_zero());
#[allow(non_snake_case)]
let mut Q: Point<$curve> = self.clone();
let mut bit = ($base::bit_length() - 1) as isize;
// 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;
}
if d.is_negative() {
Q.negate()
} else {
Q
}
}
}
}
}
point_impl!(P192, I192, I384, U384, I448, U448);
point_impl!(P224, I256, I512, U512, I576, U576);
point_impl!(P256, I256, I512, U512, I576, U576);
point_impl!(P384, I384, I768, U768, I832, U832);
point_impl!(P521, I576, I1152, U1152, I1216, U1216);
#[cfg(test)]
macro_rules! negate_test_body
{
($curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
let fname = build_test_path("ecc/negate",stringify!($curve));
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 = $stype::new(*negx, $utype::from_bytes(xbytes));
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
let a = $stype::new(*nega, $utype::from_bytes(abytes));
let b = $stype::new(*negb, $utype::from_bytes(bbytes));
let point = Point::<$curve>{ x, y };
let dbl = point.negate();
assert_eq!(a, dbl.x, "x equivalence");
assert_eq!(b, dbl.y, "y equivalence");
});
}
}
#[cfg(test)]
macro_rules! double_test_body
{
($curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
let fname = build_test_path("ecc/double",stringify!($curve));
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 = $stype::new(*negx, $utype::from_bytes(xbytes));
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
let a = $stype::new(*nega, $utype::from_bytes(abytes));
let b = $stype::new(*negb, $utype::from_bytes(bbytes));
let point = Point::<$curve>{ x, y };
let dbl = point.double();
assert_eq!(a, dbl.x, "x equivalence");
assert_eq!(b, dbl.y, "y equivalence");
});
}
}
#[cfg(test)]
macro_rules! add_test_body
{
($curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
let fname = build_test_path("ecc/add",stringify!($curve));
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 = $stype::new(*negx, $utype::from_bytes(xbytes));
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
let u = $stype::new(*negu, $utype::from_bytes(ubytes));
let v = $stype::new(*negv, $utype::from_bytes(vbytes));
let a = $stype::new(*nega, $utype::from_bytes(abytes));
let b = $stype::new(*negb, $utype::from_bytes(bbytes));
let point1 = Point::<$curve>{ x: x, y: y };
let point2 = Point::<$curve>{ x: u, y: v };
let res = point1.add(&point2);
assert_eq!(a, res.x, "x equivalence");
assert_eq!(b, res.y, "y equivalence");
});
}
}
#[cfg(test)]
macro_rules! scale_test_body
{
($curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
let fname = build_test_path("ecc/scale",stringify!($curve));
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 = $stype::new(*negx, $utype::from_bytes(xbytes));
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
let k = $stype::new(*negk, $utype::from_bytes(kbytes));
let a = $stype::new(*nega, $utype::from_bytes(abytes));
let b = $stype::new(*negb, $utype::from_bytes(bbytes));
let point = Point::<$curve>{ x: x, y: y };
let res = point.scale(&k);
assert_eq!(a, res.x, "x equivalence");
assert_eq!(b, res.y, "y equivalence");
});
}
}
#[cfg(test)]
macro_rules! add_scale2_test_body
{
($curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
let fname = build_test_path("ecc/add_scale2",stringify!($curve));
run_test(fname.to_string(), 8, |case| {
let (negx, xbytes) = case.get("x").unwrap();
let (negy, ybytes) = case.get("y").unwrap();
let (negp, pbytes) = case.get("p").unwrap();
let (negq, qbytes) = case.get("q").unwrap();
let (negn, nbytes) = case.get("n").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negr, rbytes) = case.get("r").unwrap();
let (negs, sbytes) = case.get("s").unwrap();
let x = $stype::new(*negx, $utype::from_bytes(xbytes));
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
let p = $stype::new(*negp, $utype::from_bytes(pbytes));
let q = $stype::new(*negq, $utype::from_bytes(qbytes));
let n = $stype::new(*negn, $utype::from_bytes(nbytes));
let m = $stype::new(*negm, $utype::from_bytes(mbytes));
let r = $stype::new(*negr, $utype::from_bytes(rbytes));
let s = $stype::new(*negs, $utype::from_bytes(sbytes));
let p1 = Point::<$curve>{ x: x, y: y };
let p2 = Point::<$curve>{ x: p, y: q };
let res = Point::<$curve>::double_scalar_mult(&n, &p1, &m, &p2);
assert_eq!(r, res.x, "x equivalence");
assert_eq!(s, res.y, "y equivalence");
});
}
}
macro_rules! point_tests
{
($curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
#[cfg(test)]
mod $lcurve {
use super::*;
use testing::*;
#[test]
fn negate() { negate_test_body!($curve, $lcurve, $stype, $utype); }
#[test]
fn double() { double_test_body!($curve, $lcurve, $stype, $utype); }
#[test]
fn add() { add_test_body!($curve, $lcurve, $stype, $utype); }
#[test]
fn scale() { scale_test_body!($curve, $lcurve, $stype, $utype); }
#[ignore]
#[test]
fn add_scale2() { add_scale2_test_body!($curve, $lcurve, $stype, $utype); }
}
};
(ignore_expensive $curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
#[cfg(test)]
mod $lcurve {
use super::*;
use testing::*;
#[test]
fn negate() { negate_test_body!($curve, $lcurve, $stype, $utype); }
#[test]
fn double() { double_test_body!($curve, $lcurve, $stype, $utype); }
#[test]
fn add() { add_test_body!($curve, $lcurve, $stype, $utype); }
#[ignore]
#[test]
fn scale() { scale_test_body!($curve, $lcurve, $stype, $utype); }
#[ignore]
#[test]
fn add_scale2() { add_scale2_test_body!($curve, $lcurve, $stype, $utype); }
xr -= sx;
xr -= ox;
xr = xr.reduce(&pu);
let mut yr = sx - &xr;
yr *= &s;
yr -= sy;
yr = yr.reduce(&pu);
let val = ECPointValue::Point(xr, yr);
ECPoint{ curve: self.curve, value: val }
}
}
}
point_tests!(P192, p192, I192, U192);
point_tests!(ignore_expensive P224, p224, I256, U256);
point_tests!(ignore_expensive P256, p256, I256, U256);
point_tests!(ignore_expensive P384, p384, I384, U384);
point_tests!(ignore_expensive P521, p521, I576, U576);
pub fn scale(&self, d: &UCN) -> ECPoint {
match self.value {
ECPointValue::Infinity =>
self.clone(),
ECPointValue::Point(_, _) => {
if d.is_zero() {
return ECPoint::zero(self.curve);
}
let mut q = self.clone();
let i = d.bits() - 2;
let mut mask = UCN::from(1u64) << i;
while !mask.is_zero() {
q = q.double();
let test = d & &mask;
if !test.is_zero() {
q = q.add(&self);
}
mask >>= 1;
}
q
}
}
}
}
//
// pub fn bits2int(x: &[u8], qlen: usize) -> UCN {
// let mut value = UCN::from_bytes(x);
// let vlen = x.len() * 8;
//
// if vlen > qlen {
// value >>= vlen - qlen;
// }
//
// value
// }
//
// pub fn point_add_two_muls(k1: &UCN, p1: &ECCPoint, k2: &UCN, p2: &ECCPoint)
// -> ECCPoint
// {
// panic!("point_add_two_muls()")
// }
//
// #[cfg(test)]
// mod tests {
// use super::*;
//
// #[test]
// fn p256_double() {
// let xbytes = vec![0x7c, 0xf2, 0x7b, 0x18, 0x8d, 0x03, 0x4f, 0x7e,
// 0x8a, 0x52, 0x38, 0x03, 0x04, 0xb5, 0x1a, 0xc3,
// 0xc0, 0x89, 0x69, 0xe2, 0x77, 0xf2, 0x1b, 0x35,
// 0xa6, 0x0b, 0x48, 0xfc, 0x47, 0x66, 0x99, 0x78];
// let ybytes = vec![0x07, 0x77, 0x55, 0x10, 0xdb, 0x8e, 0xd0, 0x40,
// 0x29, 0x3d, 0x9a, 0xc6, 0x9f, 0x74, 0x30, 0xdb,
// 0xba, 0x7d, 0xad, 0xe6, 0x3c, 0xe9, 0x82, 0x29,
// 0x9e, 0x04, 0xb7, 0x9d, 0x22, 0x78, 0x73, 0xd1];
// let x = SCN::from(UCN::from_bytes(&xbytes));
// let y = SCN::from(UCN::from_bytes(&ybytes));
// let base = ECCPoint::default(&EllipticCurve::p256());
// let res = base.double();
// let goal = ECCPoint{ curve: base.curve,
// value: ECCPointValue::Point(x,y) };
// assert_eq!(res, goal);
// }
//
// #[test]
// fn p256_add() {
// let xbytes = vec![0x5e, 0xcb, 0xe4, 0xd1, 0xa6, 0x33, 0x0a, 0x44,
// 0xc8, 0xf7, 0xef, 0x95, 0x1d, 0x4b, 0xf1, 0x65,
// 0xe6, 0xc6, 0xb7, 0x21, 0xef, 0xad, 0xa9, 0x85,
// 0xfb, 0x41, 0x66, 0x1b, 0xc6, 0xe7, 0xfd, 0x6c];
// let ybytes = vec![0x87, 0x34, 0x64, 0x0c, 0x49, 0x98, 0xff, 0x7e,
// 0x37, 0x4b, 0x06, 0xce, 0x1a, 0x64, 0xa2, 0xec,
// 0xd8, 0x2a, 0xb0, 0x36, 0x38, 0x4f, 0xb8, 0x3d,
// 0x9a, 0x79, 0xb1, 0x27, 0xa2, 0x7d, 0x50, 0x32];
// let x = SCN::from(UCN::from_bytes(&xbytes));
// let y = SCN::from(UCN::from_bytes(&ybytes));
// let base = ECCPoint::default(&EllipticCurve::p256());
// let res = base.add(&base.double());
// let goal = ECCPoint{ curve: base.curve,
// value: ECCPointValue::Point(x,y) };
// assert_eq!(res, goal);
// }
//
// #[test]
// fn p256_scale() {
// let xbytes = vec![0xea, 0x68, 0xd7, 0xb6, 0xfe, 0xdf, 0x0b, 0x71,
// 0x87, 0x89, 0x38, 0xd5, 0x1d, 0x71, 0xf8, 0x72,
// 0x9e, 0x0a, 0xcb, 0x8c, 0x2c, 0x6d, 0xf8, 0xb3,
// 0xd7, 0x9e, 0x8a, 0x4b, 0x90, 0x94, 0x9e, 0xe0];
// let ybytes = vec![0x2a, 0x27, 0x44, 0xc9, 0x72, 0xc9, 0xfc, 0xe7,
// 0x87, 0x01, 0x4a, 0x96, 0x4a, 0x8e, 0xa0, 0xc8,
// 0x4d, 0x71, 0x4f, 0xea, 0xa4, 0xde, 0x82, 0x3f,
// 0xe8, 0x5a, 0x22, 0x4a, 0x4d, 0xd0, 0x48, 0xfa];
// let x = SCN::from(UCN::from_bytes(&xbytes));
// let y = SCN::from(UCN::from_bytes(&ybytes));
// let base = ECCPoint::default(&EllipticCurve::p256());
// let res = base.scale(&UCN::from(9 as u64));
// let goal = ECCPoint{ curve: base.curve,
// value: ECCPointValue::Point(x,y) };
// assert_eq!(res, goal);
// }
// }

View File

@@ -1,47 +1,32 @@
use cryptonum::signed::*;
use cryptonum::unsigned::*;
use dsa::rfc6979::{DSASignature,KIterator,bits2int};
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
use ecdsa::point::{ECCPoint,Point};
use sha::Hash;
use std::fmt;
use cryptonum::{SCN,UCN};
use digest::{BlockInput,FixedOutput,Input};
use digest::generic_array::ArrayLength;
use dsa::rfc6979::{DSASignature,KIterator};
use ecdsa::curves::EllipticCurve;
use ecdsa::math::{ECCPoint,bits2int};
use hmac::Hmac;
/// A private key for the given curve.
#[derive(PartialEq)]
pub struct ECCPrivateKey<Curve: EllipticCurve> {
pub(crate) d: Curve::Unsigned
#[derive(Clone,Debug,PartialEq)]
pub struct ECDSAPrivate {
pub(crate) curve: &'static EllipticCurve,
pub(crate) d: UCN
}
impl<Curve: EllipticCurve> fmt::Debug for ECCPrivateKey<Curve> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error>
impl ECDSAPrivate {
pub fn new(c: &'static EllipticCurve, d: &UCN)
-> ECDSAPrivate
{
f.write_str("<ECCPrivateKey>")
ECDSAPrivate {
curve: c,
d: d.clone()
}
}
/// A generic private key.
pub enum ECDSAPrivate {
P192(ECCPrivateKey<P192>),
P224(ECCPrivateKey<P224>),
P256(ECCPrivateKey<P256>),
P384(ECCPrivateKey<P384>),
P521(ECCPrivateKey<P521>),
}
macro_rules! generate_privates
{
($curve: ident, $base: ident, $sig: ident, $dbl: ident, $quad: ident) => {
impl ECCPrivateKey<$curve>
{
/// Generate a new private key using the given private scalar.
pub fn new(d: $base) -> ECCPrivateKey<$curve>
{
ECCPrivateKey{ d }
}
/// Sign the given message with the current key, using the hash provided
/// in the type.
pub fn sign<H: Hash + Clone>(&self, m: &[u8]) -> DSASignature<$base>
pub fn sign<Hash>(&self, m: &[u8]) -> DSASignature
where
Hash: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<Hash>: Clone,
Hash::BlockSize: ArrayLength<u8>
{
// This algorithm is per RFC 6979, which has a nice, relatively
// straightforward description of how to do DSA signing.
@@ -54,11 +39,16 @@ macro_rules! generate_privates
// As was noted in the description of bits2octets, the extra
// modular reduction is no more than a conditional subtraction.
//
let h1 = <H>::hash(m);
let size = <$curve>::size();
let h0: $base = bits2int(&h1, size);
let n = <$curve>::n();
let h = h0 % &n;
let mut digest = <Hash>::default();
digest.process(m);
let n = self.curve.p.bits();
let h1: Vec<u8> = digest.fixed_result()
.as_slice()
.iter()
.map(|x| *x)
.collect();
let h0 = bits2int(&h1, n);
let h = h0 % &self.curve.n;
// 2. A random value modulo q, dubbed k, is generated. That value
// shall not be 0; hence, it lies in the [1, q-1] range. Most
@@ -66,114 +56,38 @@ macro_rules! generate_privates
// process used to generate k. In plain DSA or ECDSA, k should
// be selected through a random selection that chooses a value
// among the q-1 possible values with uniform probability.
for k in KIterator::<H,$base>::new(&h1, size, &n, &self.d) {
for k in KIterator::<Hash>::new(&h1, n, &self.curve.n, &self.curve.b) {
// 3. A value r (modulo q) is computed from k and the key
// parameters:
// * For DSA ...
// * For ECDSA ...
// * For ECDSA: the point kG is computed; its X coordinate (a
// member of the field over which E is defined) is converted
// to an integer, which is reduced modulo q, yielding r.
//
// If r turns out to be zero, a new k should be selected and r
// computed again (this is an utterly improbable occurrence).
let g = Point::<$curve>::default();
let ki = $sig::new(false, k.clone());
let kg = g.scale(&ki);
let ni = $sig::from(&n);
let ri = &kg.x % &ni;
if ri.is_zero() {
let g = ECCPoint::default(self.curve);
let kg = g.scale(&k);
let ni = SCN::from(self.curve.n.clone());
let r = &kg.get_x() % &ni;
if r.is_zero() {
continue;
}
if ri.is_negative() {
continue;
}
let r = $base::from(ri);
// 4. The value s (modulo q) is computed:
//
// s = (h+x*r)/k mod q
//
// The pair (r, s) is the signature.
if let Some(kinv) = k.modinv(&n) {
let mut hxr = &self.d * &r;
hxr += $dbl::from(&h);
let base = hxr * $dbl::from(kinv);
let s = $base::from(base % $quad::from(n));
return DSASignature{ r, s };
let kinv = SCN::from(k.modinv(&ni.value));
let s = ((SCN::from(h.clone()) + (&kg.get_x() * &r)) * &kinv) % &ni;
if s.is_zero() {
continue;
}
assert!(!r.is_negative());
assert!(!s.is_negative());
return DSASignature{ r: r.value, s: s.value };
}
panic!("The world is broken; couldn't find a k in sign().");
}
}
}
}
generate_privates!(P192, U192, I192, U384, U768);
generate_privates!(P224, U256, I256, U512, U1024);
generate_privates!(P256, U256, I256, U512, U1024);
generate_privates!(P384, U384, I384, U768, U1536);
generate_privates!(P521, U576, I576, U1152, U2304);
/************* TESTING ********************************************************/
#[cfg(test)]
use sha::{SHA224,SHA256,SHA384,SHA512};
#[cfg(test)]
use testing::*;
#[cfg(test)]
macro_rules! sign_test_body
{
($name: ident, $curve: ident, $base: ident) => {
let fname = build_test_path("ecc/sign",stringify!($curve));
run_test(fname.to_string(), 9, |case| {
let (negd, dbytes) = case.get("d").unwrap();
let (negk, _bytes) = case.get("k").unwrap();
let (negx, xbytes) = case.get("x").unwrap();
let (negy, ybytes) = case.get("y").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negh, hbytes) = case.get("h").unwrap();
let (negr, rbytes) = case.get("r").unwrap();
let (negs, sbytes) = case.get("s").unwrap();
assert!(!negd && !negk && !negx && !negy &&
!negm && !negh && !negr && !negs);
let d = $base::from_bytes(dbytes);
let _ = $base::from_bytes(xbytes);
let _ = $base::from_bytes(ybytes);
let h = $base::from_bytes(hbytes);
let r = $base::from_bytes(rbytes);
let s = $base::from_bytes(sbytes);
let private = ECCPrivateKey::<$curve>::new(d);
let sig = match usize::from(h) {
224 => private.sign::<SHA224>(mbytes),
256 => private.sign::<SHA256>(mbytes),
384 => private.sign::<SHA384>(mbytes),
512 => private.sign::<SHA512>(mbytes),
x => panic!("Unknown hash algorithm {}", x)
};
assert_eq!(r, sig.r, "r signature check");
assert_eq!(s, sig.s, "s signature check");
});
}
}
macro_rules! generate_tests {
($name: ident, $curve: ident, $base: ident) => {
#[test]
fn $name() {
sign_test_body!($name, $curve, $base);
}
};
(ignore $name: ident, $curve: ident, $base: ident) => {
#[ignore]
#[test]
fn $name() {
sign_test_body!($name, $curve, $base);
}
};
}
generate_tests!(p192_sign, P192, U192);
generate_tests!(ignore p224_sign, P224, U256);
generate_tests!(ignore p256_sign, P256, U256);
generate_tests!(ignore p384_sign, P384, U384);
generate_tests!(ignore p521_sign, P521, U576);

View File

@@ -1,230 +1,62 @@
use cryptonum::signed::*;
use cryptonum::unsigned::*;
use digest::{BlockInput,FixedOutput,Input};
use digest::generic_array::ArrayLength;
use dsa::rfc6979::DSASignature;
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
use ecdsa::point::{ECCPoint,Point};
use sha::Hash;
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,FromASN1,ToASN1};
use std::cmp::min;
use ecdsa::curves::EllipticCurve;
use ecdsa::math::{ECCPoint,bits2int,point_add_two_muls};
use hmac::Hmac;
/// An ECDSA public key for the given curve.
#[derive(Debug,PartialEq)]
pub struct ECCPublicKey<Curve: EllipticCurve> {
pub(crate) q: Point<Curve>
#[allow(non_snake_case)]
#[derive(Clone,Debug,PartialEq)]
pub struct ECDSAPublic {
pub(crate) curve: &'static EllipticCurve,
pub(crate) Q: ECCPoint
}
/// A generic ECDSA public key, when you're not sure which curve you're
/// going to get.
pub enum ECDSAPublic {
P192(ECCPublicKey<P192>),
P224(ECCPublicKey<P224>),
P256(ECCPublicKey<P256>),
P384(ECCPublicKey<P384>),
P521(ECCPublicKey<P521>),
}
/// An error that can occur when encoding an ECDSA public key as an ASN.1
/// object.
pub enum ECDSAEncodeErr {
ASN1EncodeErr(ASN1EncodeErr),
XValueNegative, YValueNegative
}
impl From<ASN1EncodeErr> for ECDSAEncodeErr {
fn from(x: ASN1EncodeErr) -> ECDSAEncodeErr {
ECDSAEncodeErr::ASN1EncodeErr(x)
}
}
/// An error that can occur when decoding an ECDSA public key from an
/// ASN.1 blob.
#[derive(Debug)]
pub enum ECDSADecodeErr {
ASN1DecodeErr(ASN1DecodeErr),
NoKeyFound,
InvalidKeyFormat,
InvalidKeyBlockSize
}
impl From<ASN1DecodeErr> for ECDSADecodeErr {
fn from(x: ASN1DecodeErr) -> ECDSADecodeErr {
ECDSADecodeErr::ASN1DecodeErr(x)
}
}
macro_rules! public_impl {
($curve: ident, $un: ident, $si: ident) => {
impl ECCPublicKey<$curve>
impl ECDSAPublic {
pub fn new(curve: &'static EllipticCurve, point: &ECCPoint)
-> ECDSAPublic
{
/// Generate a new public key object from the given public point.
pub fn new(q: Point<$curve>) -> ECCPublicKey<$curve>
{
ECCPublicKey{ q }
ECDSAPublic {
curve: curve,
Q: point.clone()
}
}
/// Returns true if the given message matches the given signature,
/// assuming the provided hash function.
pub fn verify<H: Hash>(&self, m: &[u8], sig: &DSASignature<$un>) -> bool
pub fn verify<Hash>(&self, m: &[u8], sig: &DSASignature) -> bool
where
Hash: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<Hash>: Clone,
Hash::BlockSize: ArrayLength<u8>
{
let n = <$curve>::n();
let n = &self.curve.n;
if sig.r.is_zero() || (sig.r >= n) {
if &sig.r > n {
return false;
}
if &sig.s > n {
return false;
}
if sig.s.is_zero() || (sig.s >= n) {
let c = sig.s.modinv(&n);
let mut digest = <Hash>::default();
digest.process(m);
let h1: Vec<u8> = digest.fixed_result()
.as_slice()
.iter()
.map(|x| *x)
.collect();
let h0 = bits2int(&h1, self.curve.p.bits()) % n;
let u1 = (&h0 * &c) % n;
let u2 = (&sig.r * &c) % n;
let x = point_add_two_muls(&u1, &ECCPoint::default(&self.curve),
&u2, &self.Q);
let xx = x.get_x();
if xx.is_negative() {
return false;
}
// e = the leftmost min(N, outlen) bits of Hash(M').
let mut digest_bytes = <H>::hash(m);
let len = min(digest_bytes.len(), $curve::size() / 8);
digest_bytes.truncate(len);
if let Some(c) = sig.s.modinv(&n) {
let e = $un::from_bytes(&digest_bytes);
let u1 = e.modmul(&c, &n);
let u2 = sig.r.modmul(&c, &n);
let g = Point::<$curve>::default();
let u1i = $si::from(u1);
let u2i = $si::from(u2);
let point = Point::<$curve>::double_scalar_mult(&u1i, &g, &u2i, &self.q);
!point.x.is_negative() && (sig.r == $un::from(point.x))
} else {
false
(xx.value % n) == sig.r
}
}
}
impl ToASN1 for ECCPublicKey<$curve> {
type Error = ECDSAEncodeErr;
fn to_asn1_class(&self, c: ASN1Class) -> Result<Vec<ASN1Block>,ECDSAEncodeErr>
{
if self.q.x.is_negative() {
return Err(ECDSAEncodeErr::XValueNegative);
}
if self.q.y.is_negative() {
return Err(ECDSAEncodeErr::YValueNegative);
}
let xval = $un::from(&self.q.x);
let yval = $un::from(&self.q.y);
let mut xbytes = xval.to_bytes();
let mut ybytes = yval.to_bytes();
let goalsize = ($curve::size() + 7) / 8;
let mut target = Vec::with_capacity(1 + (goalsize * 2));
while xbytes.len() > goalsize { xbytes.remove(0); };
while xbytes.len() < goalsize { xbytes.insert(0,0) };
while ybytes.len() > goalsize { ybytes.remove(0); };
while ybytes.len() < goalsize { ybytes.insert(0,0) };
target.push(4);
target.append(&mut xbytes);
target.append(&mut ybytes);
let result = ASN1Block::BitString(c, 0, target.len() * 8, target);
Ok(vec![result])
}
}
impl FromASN1 for ECCPublicKey<$curve> {
type Error = ECDSADecodeErr;
fn from_asn1(bs: &[ASN1Block]) -> Result<(ECCPublicKey<$curve>,&[ASN1Block]),ECDSADecodeErr>
{
let (x, rest) = bs.split_first().ok_or(ECDSADecodeErr::NoKeyFound)?;
if let ASN1Block::BitString(_, _, _, target) = x {
let (hdr, xy_bstr) = target.split_first().ok_or(ECDSADecodeErr::InvalidKeyFormat)?;
if *hdr != 4 {
return Err(ECDSADecodeErr::InvalidKeyFormat);
}
let goalsize = ($curve::size() + 7) / 8;
if xy_bstr.len() != (2 * goalsize) {
return Err(ECDSADecodeErr::InvalidKeyBlockSize);
}
let (xbstr, ybstr) = xy_bstr.split_at(goalsize);
let x = $un::from_bytes(xbstr);
let y = $un::from_bytes(ybstr);
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
let res = ECCPublicKey::<$curve>::new(point);
Ok((res, rest))
} else {
Err(ECDSADecodeErr::InvalidKeyFormat)
}
}
}
};
}
public_impl!(P192, U192, I192);
public_impl!(P224, U256, I256);
public_impl!(P256, U256, I256);
public_impl!(P384, U384, I384);
public_impl!(P521, U576, I576);
#[cfg(test)]
use sha::{SHA224,SHA256,SHA384,SHA512};
#[cfg(test)]
use testing::*;
#[cfg(test)]
macro_rules! verify_test_body
{
($name: ident, $curve: ident, $un: ident, $si: ident) => {
let fname = build_test_path("ecc/sign",stringify!($curve));
run_test(fname.to_string(), 9, |case| {
let (negd, dbytes) = case.get("d").unwrap();
let (negk, _bytes) = case.get("k").unwrap();
let (negx, xbytes) = case.get("x").unwrap();
let (negy, ybytes) = case.get("y").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negh, hbytes) = case.get("h").unwrap();
let (negr, rbytes) = case.get("r").unwrap();
let (negs, sbytes) = case.get("s").unwrap();
assert!(!negd && !negk && !negx && !negy &&
!negm && !negh && !negr && !negs);
let _ = $un::from_bytes(dbytes);
let x = $un::from_bytes(xbytes);
let y = $un::from_bytes(ybytes);
let h = $un::from_bytes(hbytes);
let r = $un::from_bytes(rbytes);
let s = $un::from_bytes(sbytes);
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
let public = ECCPublicKey::<$curve>::new(point);
let sig = DSASignature::new(r, s);
match usize::from(h) {
224 => assert!(public.verify::<SHA224>(mbytes, &sig)),
256 => assert!(public.verify::<SHA256>(mbytes, &sig)),
384 => assert!(public.verify::<SHA384>(mbytes, &sig)),
512 => assert!(public.verify::<SHA512>(mbytes, &sig)),
x => panic!("Unknown hash algorithm {}", x)
};
});
}
}
macro_rules! test_impl {
($name: ident, $curve: ident, $un: ident, $si: ident) => {
#[test]
fn $name() {
verify_test_body!($name, $curve, $un, $si);
}
};
(ignore $name: ident, $curve: ident, $un: ident, $si: ident) => {
#[ignore]
#[test]
fn $name() {
verify_test_body!($name, $curve, $un, $si);
}
};
}
test_impl!(p192,P192,U192,I192);
test_impl!(p224,P224,U256,I256);
test_impl!(ignore p256,P256,U256,I256);
test_impl!(ignore p384,P384,U384,I384);
test_impl!(ignore p521,P521,U576,I576);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,33 +0,0 @@
#[cfg(test)]
use cryptonum::unsigned::{Decoder,U192};
#[cfg(test)]
use testing::run_test;
pub fn load3(x: &[u8]) -> u64
{
(x[0] as u64) | ((x[1] as u64) << 8) | ((x[2] as u64) << 16)
}
pub fn load4(x: &[u8]) -> u64
{
(x[0] as u64) | ((x[1] as u64) << 8) |
((x[2] as u64) << 16) | ((x[3] as u64) << 24)
}
#[cfg(test)]
#[test]
fn loads() {
let fname = "testdata/ed25519/load.test";
run_test(fname.to_string(), 3, |case| {
let (negx, xbytes) = case.get("x").unwrap();
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
assert!(!negx && !nega && !negb);
let res3 = u64::from(U192::from_bytes(abytes));
let res4 = u64::from(U192::from_bytes(bbytes));
assert_eq!(res3, load3(&xbytes), "load3");
assert_eq!(res4, load4(&xbytes), "load4");
});
}

View File

@@ -1,267 +0,0 @@
//! The generation and use of ED25519 keys is the most straightforward
//! of all the asymmetric crypto schemes, because you basically get no
//! choices. There's just one key size, and you're going to use the
//! built-in hash (which is a good one, if you were worried). So if
//! you're not sure, this is a pretty good choice.
//!
//! ```rust
//! use simple_crypto::ed25519::ED25519KeyPair;
//!
//! // Generate a new ED25519 key
//! let mut rng = rand::rngs::OsRng::new().unwrap();
//! let kp = ED25519KeyPair::generate(&mut rng);
//!
//! // Now that you have this key pair, you can sign and verify messages
//! // using it. For example, to sign the vector [0,1,2,3,4] and then
//! // verify that signature, we would write:
//! let msg = vec![0,1,2,3,4];
//! let sig = kp.private.sign(&msg);
//! assert!( kp.public.verify(&msg, &sig) );
//! ```
mod constants;
mod fe;
mod loads;
mod point;
mod scalars;
use rand::Rng;
use sha::{Hash,SHA512};
use self::scalars::{curve25519_scalar_mask,x25519_sc_muladd,x25519_sc_reduce};
use self::point::{Point,Point2};
#[cfg(test)]
use testing::run_test;
#[cfg(test)]
use std::collections::HashMap;
use super::KeyPair;
/// An ED25519 key pair
#[derive(Debug,PartialEq)]
pub struct ED25519KeyPair
{
pub public: ED25519Public,
pub private: ED25519Private
}
impl KeyPair for ED25519KeyPair
{
type Public = ED25519Public;
type Private = ED25519Private;
fn new(pbl: ED25519Public, prv: ED25519Private) -> ED25519KeyPair
{
ED25519KeyPair {
public: pbl,
private: prv
}
}
}
impl ED25519KeyPair
{
/// Generate a random ED25519 key pair, using the given random number
/// generator. You really need to use a good, cryptographically-strong
/// RNG if you want good keys.
pub fn generate<G: Rng>(rng: &mut G) -> ED25519KeyPair
{
let mut seed = [0; 32];
rng.fill_bytes(&mut seed);
let private = ED25519Private::from_seed(&seed);
let public = ED25519Public::from(&private);
ED25519KeyPair::new(public, private)
}
/// Generate the ED25519 key pair defined by the given seed value.
/// This should be a block of 32 bytes.
pub fn from_seed(seed: &[u8]) -> ED25519KeyPair
{
let private = ED25519Private::from_seed(seed);
let public = ED25519Public::from(&private);
ED25519KeyPair{ public, private }
}
}
/// An ED25519 private key.
#[derive(Debug,PartialEq)]
pub struct ED25519Private
{
seed: [u8; 32],
private: [u8; 32],
prefix: [u8; 32],
public: [u8; 32]
}
impl ED25519Private {
/// Generate the ED25519 private key defined by the given 32 byte seed
/// value.
pub fn from_seed(seed: &[u8]) -> ED25519Private {
let mut result = ED25519Private {
seed: [0; 32],
private: [0; 32],
prefix: [0; 32],
public: [0; 32]
};
result.seed.copy_from_slice(seed);
let mut expanded = SHA512::hash(seed);
let (private, prefix) = expanded.split_at_mut(32);
result.private.copy_from_slice(private);
result.prefix.copy_from_slice(prefix);
curve25519_scalar_mask(&mut result.private);
let a = Point::scalarmult_base(&result.private);
result.public.copy_from_slice(&a.encode());
result
}
/// Sign the given message, returning the signature. Unlike most other
/// public/private schemes, you don't get a choice on the hash used to
/// compute this signature. (On the bright side, it's SHA2-512.)
pub fn sign(&self, msg: &[u8]) -> Vec<u8>
{
let mut signature_s = [0u8; 32];
let mut ctx = SHA512::new();
ctx.update(&self.prefix);
ctx.update(&msg);
let nonce = digest_scalar(&ctx.finalize());
let r = Point::scalarmult_base(&nonce);
let signature_r = r.encode();
let hram_digest = eddsa_digest(&signature_r, &self.public, &msg);
let hram = digest_scalar(&hram_digest);
x25519_sc_muladd(&mut signature_s, &hram, &self.private, &nonce);
let mut result = Vec::with_capacity(64);
result.extend_from_slice(&signature_r);
result.extend_from_slice(&signature_s);
result
}
/// Covert the given private key into its byte representation. This is
/// guaranteed to be exactly 32 bytes.
pub fn to_bytes(&self) -> Vec<u8>
{
self.seed.to_vec()
}
}
/// An ED25519 Public key
#[derive(Debug,PartialEq)]
pub struct ED25519Public
{
bytes: [u8; 32],
point: Point
}
impl<'a> From<&'a ED25519Private> for ED25519Public
{
fn from(x: &ED25519Private) -> ED25519Public
{
ED25519Public::new(&x.public).expect("Broke converting private ED25519 to public. (?!)")
}
}
/// The kinds of errors you can get when you try to generate a public key from,
/// for example, an unknown block of bytes.
#[derive(Debug)]
pub enum ED25519PublicImportError
{
WrongNumberOfBytes(usize),
InvalidPublicPoint
}
impl ED25519Public {
/// Generate an ED25519 public key given the provided (32 byte) bytes. This
/// can return errors if the value isn't a reasonable representation of an
/// ED25519 point.
pub fn new(bytes: &[u8]) -> Result<ED25519Public,ED25519PublicImportError>
{
if bytes.len() != 32 {
return Err(ED25519PublicImportError::WrongNumberOfBytes(bytes.len()));
}
match Point::from_bytes(&bytes) {
None =>
Err(ED25519PublicImportError::InvalidPublicPoint),
Some(a) => {
let mut res = ED25519Public{ bytes: [0; 32], point: a };
res.bytes.copy_from_slice(&bytes);
Ok(res)
}
}
}
/// Verify that the given signature matches the given message.
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool
{
assert_eq!(sig.len(), 64);
let signature_r = &sig[..32];
let signature_s = &sig[32..];
if signature_s[31] & 0b11100000 != 0 {
return false;
}
let ainv = self.point.invert();
let h_digest = eddsa_digest(signature_r, &self.bytes, msg);
let h = digest_scalar(&h_digest);
let r = Point2::double_scalarmult_vartime(&h, &ainv, &signature_s);
let r_check = r.encode();
signature_r.to_vec() == r_check
}
/// Turn the ED25519 into its byte representation. This will always be a
/// 32 byte block.
pub fn to_bytes(&self) -> Vec<u8>
{
self.bytes.to_vec()
}
}
fn eddsa_digest(signature_r: &[u8], public_key: &[u8], msg: &[u8]) -> Vec<u8>
{
let mut ctx = SHA512::new();
ctx.update(signature_r);
ctx.update(public_key);
ctx.update(msg);
ctx.finalize()
}
fn digest_scalar(digest: &[u8]) -> Vec<u8> {
assert_eq!(digest.len(), 512/8);
let mut copy = [0; 512/8];
copy.copy_from_slice(digest);
x25519_sc_reduce(&mut copy);
copy[..32].to_vec()
}
#[cfg(test)]
fn run_signing_testcase(case: HashMap<String,(bool,Vec<u8>)>)
{
let (negr, rbytes) = case.get("r").unwrap();
let (negu, ubytes) = case.get("u").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negs, sbytes) = case.get("s").unwrap();
assert!(!negr && !negu && !negm && !negs);
let keypair = ED25519KeyPair::from_seed(rbytes);
assert_eq!(ubytes, &keypair.public.bytes.to_vec());
let mut privpub = Vec::new();
privpub.append(&mut rbytes.clone());
privpub.append(&mut ubytes.clone());
let sig = keypair.private.sign(&mbytes);
assert_eq!(sig.len(), sbytes.len());
assert!(sig.iter().eq(sbytes.iter()));
assert!(keypair.public.verify(&mbytes, &sig));
}
#[cfg(test)]
#[test]
fn rfc8072() {
let fname = "testdata/ed25519/rfc8032.test";
run_test(fname.to_string(), 4, run_signing_testcase);
}
#[cfg(test)]
#[test]
fn signing() {
let fname = "testdata/ed25519/sign.test";
run_test(fname.to_string(), 4, run_signing_testcase);
}

View File

@@ -1,733 +0,0 @@
#[cfg(test)]
use testing::run_test;
use ed25519::fe::*;
use ed25519::constants::*;
use std::ops::*;
// This is ge_p3 in the original source code
#[derive(Clone,Debug,PartialEq)]
pub struct Point {
pub x: FieldElement,
pub y: FieldElement,
pub z: FieldElement,
pub t: FieldElement
}
impl Point {
fn zero() -> Point
{
Point {
x: FieldElement::zero(),
y: FieldElement::one(),
z: FieldElement::one(),
t: FieldElement::zero(),
}
}
#[cfg(test)]
fn load_test_value(xs: &[u8]) -> Point {
assert!(xs.len() == 160);
Point {
x: test_from_bytes(&xs[0..40]),
y: test_from_bytes(&xs[40..80]),
z: test_from_bytes(&xs[80..120]),
t: test_from_bytes(&xs[120..])
}
}
/// Convert 32 bytes into an ED25519 point. This routine is not
/// statically timed, so don't use it if that's important to you.
pub fn from_bytes(s: &[u8]) -> Option<Point>
{
let hy = FieldElement::from_bytes(s);
let hz = FieldElement::one();
let mut u = hy.square();
let mut v = &u * &D;
u = &u - &hz; /* u = y^2-1 */
v += &hz;
let mut v3 = v.square();
v3 *= &v; /* v3 = v^3 */
let mut hx = v3.square();
hx *= &v;
hx *= &u; /* x = uv^7 */
hx = hx.pow22523(); /* x = (uv^7)^((q-5)/8) */
hx *= &v3;
hx *= &u; /* x = uv^3(uv^7)^((q-5)/8) */
let mut vxx = hx.square();
vxx *= &v;
let mut check = &vxx - &u; /* vx^2-u */
if check.isnonzero() {
check = &vxx + &u;
if check.isnonzero() {
return None;
}
hx *= &SQRTM1;
}
if hx.isnegative() != ((s[31] >> 7) == 1) {
hx = -&hx;
}
let ht = &hx * &hy;
return Some(Point{ x: hx, y: hy, z: hz, t: ht });
}
pub fn encode(&self) -> Vec<u8>
{
into_encoded_point(&self.x, &self.y, &self.z)
}
pub fn invert(&self) -> Point
{
Point {
x: -&self.x,
y: self.y.clone(),
z: self.z.clone(),
t: -&self.t,
}
}
}
const D: FieldElement = FieldElement {
value: [-10913610, 13857413, -15372611, 6949391, 114729,
-8787816, -6275908, -3247719, -18696448, -12055116]
};
const SQRTM1: FieldElement = FieldElement {
value: [-32595792, -7943725, 9377950, 3500415, 12389472,
-272473, -25146209, -2005654, 326686, 11406482]
};
#[cfg(test)]
#[test]
fn from_bytes_vartime() {
let fname = "testdata/ed25519/fbv.test";
run_test(fname.to_string(), 3, |case| {
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let (negc, cbytes) = case.get("c").unwrap();
assert!(!nega && !negb && !negc);
let target = Point::load_test_value(&cbytes);
let mine = Point::from_bytes(&abytes);
if bbytes.len() < cbytes.len() {
assert!(mine.is_none());
} else {
assert_eq!(target, mine.unwrap());
}
});
}
#[derive(Debug,PartialEq)]
pub struct Point2 {
pub x: FieldElement,
pub y: FieldElement,
pub z: FieldElement,
}
impl Point2 {
pub fn zero() -> Point2
{
Point2 {
x: FieldElement::zero(),
y: FieldElement::one(),
z: FieldElement::one()
}
}
#[cfg(test)]
fn load_test_value(xs: &[u8]) -> Point2 {
assert!(xs.len() == 120);
Point2 {
x: test_from_bytes(&xs[0..40]),
y: test_from_bytes(&xs[40..80]),
z: test_from_bytes(&xs[80..120]),
}
}
pub fn encode(&self) -> Vec<u8>
{
into_encoded_point(&self.x, &self.y, &self.z)
}
}
impl<'a> From<&'a Point> for Point2 {
fn from(p: &Point) -> Point2 {
Point2 {
x: p.x.clone(),
y: p.y.clone(),
z: p.z.clone(),
}
}
}
#[derive(Debug,PartialEq)]
pub struct PointP1P1 {
x: FieldElement,
y: FieldElement,
z: FieldElement,
t: FieldElement
}
impl PointP1P1 {
#[cfg(test)]
fn load_test_value(xs: &[u8]) -> PointP1P1 {
assert!(xs.len() == 160);
PointP1P1 {
x: test_from_bytes(&xs[0..40]),
y: test_from_bytes(&xs[40..80]),
z: test_from_bytes(&xs[80..120]),
t: test_from_bytes(&xs[120..])
}
}
}
#[derive(Debug,PartialEq)]
struct Cached {
yplusx: FieldElement,
yminusx: FieldElement,
z: FieldElement,
t2d: FieldElement
}
impl Cached
{
fn new() -> Cached
{
Cached {
yplusx: FieldElement::new(),
yminusx: FieldElement::new(),
z: FieldElement::new(),
t2d: FieldElement::new()
}
}
#[cfg(test)]
fn load_test_value(xs: &[u8]) -> Cached {
assert!(xs.len() == 160);
Cached {
yplusx: test_from_bytes(&xs[0..40]),
yminusx: test_from_bytes(&xs[40..80]),
z: test_from_bytes(&xs[80..120]),
t2d: test_from_bytes(&xs[120..])
}
}
}
const D2: FieldElement = FieldElement {
value: [-21827239, -5839606, -30745221, 13898782, 229458,
15978800, -12551817, -6495438, 29715968, 9444199]
};
impl<'a> From<&'a Point> for Cached
{
fn from(p: &Point) -> Cached
{
Cached {
yplusx: &p.y + &p.x,
yminusx: &p.y - &p.x,
z: p.z.clone(),
t2d: &p.t * &D2,
}
}
}
impl<'a> From<&'a PointP1P1> for Point2
{
fn from(p: &PointP1P1) -> Point2
{
Point2 {
x: &p.x * &p.t,
y: &p.y * &p.z,
z: &p.z * &p.t,
}
}
}
impl<'a> From<&'a PointP1P1> for Point
{
fn from(p: &PointP1P1) -> Point
{
Point {
x: &p.x * &p.t,
y: &p.y * &p.z,
z: &p.z * &p.t,
t: &p.x * &p.y,
}
}
}
#[cfg(test)]
#[test]
fn conversion() {
let fname = "testdata/ed25519/conversion.test";
run_test(fname.to_string(), 6, |case| {
let (nega, abytes) = case.get("a").unwrap();
let (negc, cbytes) = case.get("c").unwrap();
let (negt, tbytes) = case.get("t").unwrap();
let (nego, obytes) = case.get("o").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let a = Point::load_test_value(&abytes);
let c = Cached::load_test_value(&cbytes);
let t = Point2::load_test_value(&tbytes);
let o = PointP1P1::load_test_value(&obytes);
let d = Point2::load_test_value(&dbytes);
let b = Point::load_test_value(&bbytes);
assert!(!nega && !negc && !negt && !nego && !negd && !negb);
let myc = Cached::from(&a);
assert_eq!(myc, c);
let myt = Point2::from(&a);
assert_eq!(myt, t);
let myo = a.double();
assert_eq!(myo, o);
let myd = Point2::from(&o);
assert_eq!(myd, d);
let myb = Point::from(&o);
assert_eq!(myb, b);
});
}
/* r = 2 * p */
impl Point2 {
fn double(&self) -> PointP1P1
{
let x0 = self.x.square();
let z0 = self.y.square();
let t0 = self.z.sq2();
let y0 = &self.x + &self.y;
let ry = &z0 + &x0;
let rz = &z0 - &x0;
let rx = &y0.square() - &ry;
let rt = &t0 - &rz;
PointP1P1 { x: rx, y: ry, z: rz, t: rt }
}
}
/* r = 2 * p */
impl Point {
fn double(&self) -> PointP1P1
{
Point2::from(self).double()
}
}
#[cfg(test)]
#[test]
fn double() {
let fname = "testdata/ed25519/pt_double.test";
run_test(fname.to_string(), 4, |case| {
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let (negc, cbytes) = case.get("c").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
assert!(!nega && !negb && !negc && !negd);
let a = Point::load_test_value(abytes);
let b = PointP1P1::load_test_value(bbytes);
let c = Point2::load_test_value(cbytes);
let d = PointP1P1::load_test_value(dbytes);
let myb = a.double();
assert_eq!(myb, b);
let myd = c.double();
assert_eq!(myd, d);
});
}
impl<'a,'b> Add<&'a Precomp> for &'b Point
{
type Output = PointP1P1;
fn add(self, q: &Precomp) -> PointP1P1
{
let mut rx;
let mut ry;
let mut rz;
let mut rt;
rx = &self.y + &self.x;
ry = &self.y - &self.x;
rz = &rx * &q.yplusx;
ry *= &q.yminusx;
rt = &q.xy2d * &self.t;
let t0 = &self.z + &self.z;
rx = &rz - &ry;
ry += &rz;
rz = &t0 + &rt;
rt = &t0 - &rt;
PointP1P1 { x: rx, y: ry, z: rz, t: rt }
}
}
impl<'a,'b> Sub<&'a Precomp> for &'b Point
{
type Output = PointP1P1;
/* r = p - q */
fn sub(self, q: &Precomp) -> PointP1P1
{
let mut rx = &self.y + &self.x;
let mut ry = &self.y - &self.x;
let mut rz = &rx * &q.yminusx;
ry *= &q.yplusx;
let mut rt = &q.xy2d * &self.t;
let t0 = &self.z + &self.z;
rx = &rz - &ry;
ry += &rz;
rz = &t0 - &rt;
rt += &t0;
PointP1P1{ x: rx, y: ry, z: rz, t: rt }
}
}
#[cfg(test)]
#[test]
fn maddsub() {
let fname = "testdata/ed25519/maddsub.test";
run_test(fname.to_string(), 4, |case| {
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let (negc, cbytes) = case.get("c").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
assert!(!nega && !negb && !negc && !negd);
let a = Point::load_test_value(abytes);
let b = PointP1P1::load_test_value(bbytes);
let c = Precomp::load_test_value(cbytes);
let d = PointP1P1::load_test_value(dbytes);
let myb = &a + &c;
assert_eq!(myb, b);
let myd = &a - &c;
assert_eq!(myd, d);
});
}
impl<'a,'b> Add<&'a Cached> for &'b Point
{
type Output = PointP1P1;
fn add(self, q: &Cached) -> PointP1P1
{
let mut rx;
let mut ry;
let mut rz;
let mut rt;
rx = &self.y + &self.x;
ry = &self.y - &self.x;
rz = &rx * &q.yplusx;
ry *= &q.yminusx;
rt = &q.t2d * &self.t;
rx = &self.z * &q.z;
let t0 = &rx + &rx;
rx = &rz - &ry;
ry += &rz;
rz = &t0 + &rt;
rt = &t0 - &rt;
PointP1P1{ x: rx, y: ry, z: rz, t: rt }
}
}
impl<'a,'b> Sub<&'a Cached> for &'b Point
{
type Output = PointP1P1;
fn sub(self, q: &Cached) -> PointP1P1
{
let mut rx;
let mut ry;
let mut rz;
let mut rt;
rx = &self.y + &self.x;
ry = &self.y - &self.x;
rz = &rx * &q.yminusx;
ry *= &q.yplusx;
rt = &q.t2d * &self.t;
rx = &self.z * &q.z;
let t0 = &rx + &rx;
rx = &rz - &ry;
ry += &rz;
rz = &t0 - &rt;
rt += &t0;
PointP1P1{ x: rx, y: ry, z: rz, t: rt }
}
}
#[cfg(test)]
#[test]
fn addsub() {
let fname = "testdata/ed25519/ptaddsub.test";
run_test(fname.to_string(), 4, |case| {
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let (negc, cbytes) = case.get("c").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
assert!(!nega && !negb && !negc && !negd);
let a = Point::load_test_value(abytes);
let b = PointP1P1::load_test_value(bbytes);
let c = Cached::load_test_value(cbytes);
let d = PointP1P1::load_test_value(dbytes);
let myb = &a + &c;
assert_eq!(myb, b);
let myd = &a - &c;
assert_eq!(myd, d);
});
}
impl Point {
/* h = a * B
* where a = a[0]+256*a[1]+...+256^31 a[31]
* B is the Ed25519 base point (x,4/5) with x positive.
*
* Preconditions:
* a[31] <= 127 */
pub fn scalarmult_base(a: &[u8]) -> Point
{
let mut e: [i8; 64] = [0; 64];
for i in 0..32 {
e[2 * i + 0] = ((a[i] >> 0) & 15) as i8;
e[2 * i + 1] = ((a[i] >> 4) & 15) as i8;
}
/* each e[i] is between 0 and 15 */
/* e[63] is between 0 and 7 */
let mut carry = 0;
for i in 0..63 {
e[i] += carry;
carry = e[i] + 8;
carry >>= 4;
e[i] -= carry << 4;
}
e[63] += carry;
/* each e[i] is between -8 and 8 */
let mut r;
let mut t;
let mut h = Point::zero();
for i in &[1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63] {
t = Precomp::table_select(*i / 2, e[*i as usize]);
r = &h + &t;
h = Point::from(&r);
}
r = h.double();
let mut s = Point2::from(&r);
r = s.double();
s = Point2::from(&r);
r = s.double();
s = Point2::from(&r);
r = s.double();
h = Point::from(&r);
for i in &[0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62] {
t = Precomp::table_select(*i / 2, e[*i as usize]);
r = &h + &t;
h = Point::from(&r);
}
h
}
}
#[cfg(test)]
#[test]
fn scalarmult_base() {
let fname = "testdata/ed25519/scalar_mult.test";
run_test(fname.to_string(), 2, |case| {
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
assert!(!nega && !negb);
let b = Point::load_test_value(bbytes);
let mine = Point::scalarmult_base(&abytes);
assert_eq!(mine, b);
});
}
fn slide(r: &mut [i8], a: &[u8])
{
for i in 0..256 {
r[i] = (1 & (a[i >> 3] >> (i & 7))) as i8;
}
for i in 0..256 {
if r[i] != 0 {
let mut b = 1;
while (b <= 6) && ((i + b) < 256) {
if r[i + b] != 0 {
if r[i] + (r[i + b] << b) <= 15 {
r[i] += r[i + b] << b;
r[i + b] = 0;
} else if r[i] - (r[i + b] << b) >= -15 {
r[i] -= r[i + b] << b;
for k in (i+b)..256 {
if r[k] == 0 {
r[k] = 1;
break;
}
r[k] = 0;
}
} else {
break;
}
}
b += 1;
}
}
}
}
#[cfg(test)]
#[test]
fn helper_slide() {
let fname = "testdata/ed25519/slide.test";
run_test(fname.to_string(), 2, |case| {
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
assert!(!nega && !negb);
let mut mine = [0; 256];
slide(&mut mine, &abytes);
for i in 0..256 {
assert_eq!(mine[i], bbytes[i] as i8);
}
});
}
impl Point2
{
/* r = a * A + b * B
* where a = a[0]+256*a[1]+...+256^31 a[31].
* and b = b[0]+256*b[1]+...+256^31 b[31].
* B is the Ed25519 base point (x,4/5) with x positive. */
#[allow(non_snake_case)]
pub fn double_scalarmult_vartime(a: &[u8], A: &Point, b: &[u8]) -> Point2
{
let mut aslide: [i8; 256] = [0; 256];
let mut bslide: [i8; 256] = [0; 256];
#[allow(non_snake_case)]
let mut Ai: [Cached; 8] = [Cached::new(), Cached::new(), Cached::new(), Cached::new(),
Cached::new(), Cached::new(), Cached::new(), Cached::new()];
#[allow(non_snake_case)]
slide(&mut aslide, &a);
slide(&mut bslide, &b);
Ai[0] = Cached::from(A);
let mut t = A.double();
let A2 = Point::from(&t);
t = &A2 + &Ai[0];
let mut u = Point::from(&t);
Ai[1] = Cached::from(&u);
t = &A2 + &Ai[1];
u = Point::from(&t);
Ai[2] = Cached::from(&u);
t = &A2 + &Ai[2];
u = Point::from(&t);
Ai[3] = Cached::from(&u);
t = &A2 + &Ai[3];
u = Point::from(&t);
Ai[4] = Cached::from(&u);
t = &A2 + &Ai[4];
u = Point::from(&t);
Ai[5] = Cached::from(&u);
t = &A2 + &Ai[5];
u = Point::from(&t);
Ai[6] = Cached::from(&u);
t = &A2 + &Ai[6];
u = Point::from(&t);
Ai[7] = Cached::from(&u);
let mut r = Point2::zero();
let mut i: i32 = 255;
loop {
if (aslide[i as usize] != 0) || (bslide[i as usize] != 0) {
break;
}
i -= 1;
if i < 0 {
break;
}
}
while i >= 0 {
t = r.double();
if aslide[i as usize] > 0 {
u = Point::from(&t);
let idx = (aslide[i as usize] / 2) as usize;
t = &u + &Ai[idx]
} else if aslide[i as usize] < 0 {
u = Point::from(&t);
let idx = ((-aslide[i as usize]) / 2) as usize;
t = &u - &Ai[idx];
}
if bslide[i as usize] > 0 {
u = Point::from(&t);
let idx = (bslide[i as usize] / 2) as usize;
t = &u + &BI[idx];
} else if bslide[i as usize] < 0 {
u = Point::from(&t);
let idx = ((-bslide[i as usize]) / 2) as usize;
t = &u - &BI[idx];
}
r = Point2::from(&t);
i -= 1;
}
r
}
}
#[cfg(test)]
#[test]
fn double_scalarmult() {
let fname = "testdata/ed25519/scalar_mult_gen.test";
run_test(fname.to_string(), 4, |case| {
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let (negc, cbytes) = case.get("c").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
assert!(!nega && !negb && !negc && !negd);
let b = Point::load_test_value(bbytes);
let d = Point2::load_test_value(dbytes);
let mine = Point2::double_scalarmult_vartime(&abytes, &b, &cbytes);
assert_eq!(mine, d);
});
}
fn into_encoded_point(x: &FieldElement, y: &FieldElement, z: &FieldElement) -> Vec<u8>
{
let recip = z.invert();
let x_over_z = x * &recip;
let y_over_z = y * &recip;
let mut bytes = y_over_z.to_bytes();
let sign_bit = if x_over_z.isnegative() { 1 } else { 0 };
// The preceding computations must execute in constant time, but this
// doesn't need to.
bytes[31] ^= sign_bit << 7;
bytes
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,881 +0,0 @@
use ed25519::loads::{load3,load4};
#[cfg(test)]
use testing::run_test;
/* The set of scalars is \Z/l
* where l = 2^252 + 27742317777372353535851937790883648493. */
/* Input:
* s[0]+256*s[1]+...+256^63*s[63] = s
*
* Output:
* s[0]+256*s[1]+...+256^31*s[31] = s mod l
* where l = 2^252 + 27742317777372353535851937790883648493.
* Overwrites s in place. */
pub fn x25519_sc_reduce(s: &mut [u8])
{
let mut s0 : i64 = 2097151 & load3(s) as i64;
let mut s1 : i64 = 2097151 & (load4(&s[2..]) >> 5) as i64;
let mut s2 : i64 = 2097151 & (load3(&s[5..]) >> 2) as i64;
let mut s3 : i64 = 2097151 & (load4(&s[7..]) >> 7) as i64;
let mut s4 : i64 = 2097151 & (load4(&s[10..]) >> 4) as i64;
let mut s5 : i64 = 2097151 & (load3(&s[13..]) >> 1) as i64;
let mut s6 : i64 = 2097151 & (load4(&s[15..]) >> 6) as i64;
let mut s7 : i64 = 2097151 & (load3(&s[18..]) >> 3) as i64;
let mut s8 : i64 = 2097151 & load3(&s[21..]) as i64;
let mut s9 : i64 = 2097151 & (load4(&s[23..]) >> 5) as i64;
let mut s10 : i64 = 2097151 & (load3(&s[26..]) >> 2) as i64;
let mut s11 : i64 = 2097151 & (load4(&s[28..]) >> 7) as i64;
let mut s12 : i64 = 2097151 & (load4(&s[31..]) >> 4) as i64;
let mut s13 : i64 = 2097151 & (load3(&s[34..]) >> 1) as i64;
let mut s14 : i64 = 2097151 & (load4(&s[36..]) >> 6) as i64;
let mut s15 : i64 = 2097151 & (load3(&s[39..]) >> 3) as i64;
let mut s16 : i64 = 2097151 & load3(&s[42..]) as i64;
let mut s17 : i64 = 2097151 & (load4(&s[44..]) >> 5) as i64;
let s18 : i64 = 2097151 & (load3(&s[47..]) >> 2) as i64;
let s19 : i64 = 2097151 & (load4(&s[49..]) >> 7) as i64;
let s20 : i64 = 2097151 & (load4(&s[52..]) >> 4) as i64;
let s21 : i64 = 2097151 & (load3(&s[55..]) >> 1) as i64;
let s22 : i64 = 2097151 & (load4(&s[57..]) >> 6) as i64;
let s23 : i64 = (load4(&s[60..]) >> 3) as i64 as i64;
let mut carry0 : i64;
let mut carry1 : i64;
let mut carry2 : i64;
let mut carry3 : i64;
let mut carry4 : i64;
let mut carry5 : i64;
let mut carry6 : i64;
let mut carry7 : i64;
let mut carry8 : i64;
let mut carry9 : i64;
let mut carry10 : i64;
let mut carry11 : i64;
let carry12 : i64;
let carry13 : i64;
let carry14 : i64;
let carry15 : i64;
let carry16 : i64;
s11 += s23 * 666643;
s12 += s23 * 470296;
s13 += s23 * 654183;
s14 -= s23 * 997805;
s15 += s23 * 136657;
s16 -= s23 * 683901;
//s23 = 0;
s10 += s22 * 666643;
s11 += s22 * 470296;
s12 += s22 * 654183;
s13 -= s22 * 997805;
s14 += s22 * 136657;
s15 -= s22 * 683901;
//s22 = 0;
s9 += s21 * 666643;
s10 += s21 * 470296;
s11 += s21 * 654183;
s12 -= s21 * 997805;
s13 += s21 * 136657;
s14 -= s21 * 683901;
//s21 = 0;
s8 += s20 * 666643;
s9 += s20 * 470296;
s10 += s20 * 654183;
s11 -= s20 * 997805;
s12 += s20 * 136657;
s13 -= s20 * 683901;
//s20 = 0;
s7 += s19 * 666643;
s8 += s19 * 470296;
s9 += s19 * 654183;
s10 -= s19 * 997805;
s11 += s19 * 136657;
s12 -= s19 * 683901;
//s19 = 0;
s6 += s18 * 666643;
s7 += s18 * 470296;
s8 += s18 * 654183;
s9 -= s18 * 997805;
s10 += s18 * 136657;
s11 -= s18 * 683901;
//s18 = 0;
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
carry12 = (s12 + (1 << 20)) >> 21;
s13 += carry12;
s12 -= carry12 << 21;
carry14 = (s14 + (1 << 20)) >> 21;
s15 += carry14;
s14 -= carry14 << 21;
carry16 = (s16 + (1 << 20)) >> 21;
s17 += carry16;
s16 -= carry16 << 21;
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
carry13 = (s13 + (1 << 20)) >> 21;
s14 += carry13;
s13 -= carry13 << 21;
carry15 = (s15 + (1 << 20)) >> 21;
s16 += carry15;
s15 -= carry15 << 21;
s5 += s17 * 666643;
s6 += s17 * 470296;
s7 += s17 * 654183;
s8 -= s17 * 997805;
s9 += s17 * 136657;
s10 -= s17 * 683901;
//s17 = 0;
s4 += s16 * 666643;
s5 += s16 * 470296;
s6 += s16 * 654183;
s7 -= s16 * 997805;
s8 += s16 * 136657;
s9 -= s16 * 683901;
//s16 = 0;
s3 += s15 * 666643;
s4 += s15 * 470296;
s5 += s15 * 654183;
s6 -= s15 * 997805;
s7 += s15 * 136657;
s8 -= s15 * 683901;
//s15 = 0;
s2 += s14 * 666643;
s3 += s14 * 470296;
s4 += s14 * 654183;
s5 -= s14 * 997805;
s6 += s14 * 136657;
s7 -= s14 * 683901;
//s14 = 0;
s1 += s13 * 666643;
s2 += s13 * 470296;
s3 += s13 * 654183;
s4 -= s13 * 997805;
s5 += s13 * 136657;
s6 -= s13 * 683901;
//s13 = 0;
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
s3 -= s12 * 997805;
s4 += s12 * 136657;
s5 -= s12 * 683901;
s12 = 0;
carry0 = (s0 + (1 << 20)) >> 21;
s1 += carry0;
s0 -= carry0 << 21;
carry2 = (s2 + (1 << 20)) >> 21;
s3 += carry2;
s2 -= carry2 << 21;
carry4 = (s4 + (1 << 20)) >> 21;
s5 += carry4;
s4 -= carry4 << 21;
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
carry1 = (s1 + (1 << 20)) >> 21;
s2 += carry1;
s1 -= carry1 << 21;
carry3 = (s3 + (1 << 20)) >> 21;
s4 += carry3;
s3 -= carry3 << 21;
carry5 = (s5 + (1 << 20)) >> 21;
s6 += carry5;
s5 -= carry5 << 21;
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
s3 -= s12 * 997805;
s4 += s12 * 136657;
s5 -= s12 * 683901;
s12 = 0;
carry0 = s0 >> 21;
s1 += carry0;
s0 -= carry0 << 21;
carry1 = s1 >> 21;
s2 += carry1;
s1 -= carry1 << 21;
carry2 = s2 >> 21;
s3 += carry2;
s2 -= carry2 << 21;
carry3 = s3 >> 21;
s4 += carry3;
s3 -= carry3 << 21;
carry4 = s4 >> 21;
s5 += carry4;
s4 -= carry4 << 21;
carry5 = s5 >> 21;
s6 += carry5;
s5 -= carry5 << 21;
carry6 = s6 >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry7 = s7 >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry8 = s8 >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry9 = s9 >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry10 = s10 >> 21;
s11 += carry10;
s10 -= carry10 << 21;
carry11 = s11 >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
s3 -= s12 * 997805;
s4 += s12 * 136657;
s5 -= s12 * 683901;
//s12 = 0;
carry0 = s0 >> 21;
s1 += carry0;
s0 -= carry0 << 21;
carry1 = s1 >> 21;
s2 += carry1;
s1 -= carry1 << 21;
carry2 = s2 >> 21;
s3 += carry2;
s2 -= carry2 << 21;
carry3 = s3 >> 21;
s4 += carry3;
s3 -= carry3 << 21;
carry4 = s4 >> 21;
s5 += carry4;
s4 -= carry4 << 21;
carry5 = s5 >> 21;
s6 += carry5;
s5 -= carry5 << 21;
carry6 = s6 >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry7 = s7 >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry8 = s8 >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry9 = s9 >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry10 = s10 >> 21;
s11 += carry10;
s10 -= carry10 << 21;
s[0] = (s0 >> 0) as u8;
s[1] = (s0 >> 8) as u8;
s[2] = ((s0 >> 16) | (s1 << 5)) as u8;
s[3] = (s1 >> 3) as u8;
s[4] = (s1 >> 11) as u8;
s[5] = ((s1 >> 19) | (s2 << 2)) as u8;
s[6] = (s2 >> 6) as u8;
s[7] = ((s2 >> 14) | (s3 << 7)) as u8;
s[8] = (s3 >> 1) as u8;
s[9] = (s3 >> 9) as u8;
s[10] = ((s3 >> 17) | (s4 << 4)) as u8;
s[11] = (s4 >> 4) as u8;
s[12] = (s4 >> 12) as u8;
s[13] = ((s4 >> 20) | (s5 << 1)) as u8;
s[14] = (s5 >> 7) as u8;
s[15] = ((s5 >> 15) | (s6 << 6)) as u8;
s[16] = (s6 >> 2) as u8;
s[17] = (s6 >> 10) as u8;
s[18] = ((s6 >> 18) | (s7 << 3)) as u8;
s[19] = (s7 >> 5) as u8;
s[20] = (s7 >> 13) as u8;
s[21] = (s8 >> 0) as u8;
s[22] = (s8 >> 8) as u8;
s[23] = ((s8 >> 16) | (s9 << 5)) as u8;
s[24] = (s9 >> 3) as u8;
s[25] = (s9 >> 11) as u8;
s[26] = ((s9 >> 19) | (s10 << 2)) as u8;
s[27] = (s10 >> 6) as u8;
s[28] = ((s10 >> 14) | (s11 << 7)) as u8;
s[29] = (s11 >> 1) as u8;
s[30] = (s11 >> 9) as u8;
s[31] = (s11 >> 17) as u8;
}
#[cfg(test)]
#[test]
fn reduce() {
let fname = "testdata/ed25519/reduce.test";
run_test(fname.to_string(), 2, |case| {
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
assert!(!nega && !negb);
assert_eq!(abytes.len(), 64);
assert_eq!(bbytes.len(), 32);
let mut copy = abytes.clone();
x25519_sc_reduce(&mut copy);
assert_eq!(&copy[0..32], &bbytes[0..]);
});
}
/* Input:
* a[0]+256*a[1]+...+256^31*a[31] = a
* b[0]+256*b[1]+...+256^31*b[31] = b
* c[0]+256*c[1]+...+256^31*c[31] = c
*
* Output:
* s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
* where l = 2^252 + 27742317777372353535851937790883648493. */
pub fn x25519_sc_muladd(s: &mut [u8], a: &[u8], b: &[u8], c: &[u8])
{
let a0 : i64 = 2097151 & load3(a) as i64;
let a1 : i64 = 2097151 & (load4(&a[2..]) >> 5) as i64;
let a2 : i64 = 2097151 & (load3(&a[5..]) >> 2) as i64;
let a3 : i64 = 2097151 & (load4(&a[7..]) >> 7) as i64;
let a4 : i64 = 2097151 & (load4(&a[10..]) >> 4) as i64;
let a5 : i64 = 2097151 & (load3(&a[13..]) >> 1) as i64;
let a6 : i64 = 2097151 & (load4(&a[15..]) >> 6) as i64;
let a7 : i64 = 2097151 & (load3(&a[18..]) >> 3) as i64;
let a8 : i64 = 2097151 & load3(&a[21..]) as i64;
let a9 : i64 = 2097151 & (load4(&a[23..]) >> 5) as i64;
let a10 : i64 = 2097151 & (load3(&a[26..]) >> 2) as i64;
let a11 : i64 = (load4(&a[28..]) >> 7) as i64;
let b0 : i64 = 2097151 & load3(b) as i64;
let b1 : i64 = 2097151 & (load4(&b[2..]) >> 5) as i64;
let b2 : i64 = 2097151 & (load3(&b[5..]) >> 2) as i64;
let b3 : i64 = 2097151 & (load4(&b[7..]) >> 7) as i64;
let b4 : i64 = 2097151 & (load4(&b[10..]) >> 4) as i64;
let b5 : i64 = 2097151 & (load3(&b[13..]) >> 1) as i64;
let b6 : i64 = 2097151 & (load4(&b[15..]) >> 6) as i64;
let b7 : i64 = 2097151 & (load3(&b[18..]) >> 3) as i64;
let b8 : i64 = 2097151 & load3(&b[21..]) as i64;
let b9 : i64 = 2097151 & (load4(&b[23..]) >> 5) as i64;
let b10 : i64 = 2097151 & (load3(&b[26..]) >> 2) as i64;
let b11 : i64 = (load4(&b[28..]) >> 7) as i64;
let c0 : i64 = 2097151 & load3(c) as i64;
let c1 : i64 = 2097151 & (load4(&c[2..]) >> 5) as i64;
let c2 : i64 = 2097151 & (load3(&c[5..]) >> 2) as i64;
let c3 : i64 = 2097151 & (load4(&c[7..]) >> 7) as i64;
let c4 : i64 = 2097151 & (load4(&c[10..]) >> 4) as i64;
let c5 : i64 = 2097151 & (load3(&c[13..]) >> 1) as i64;
let c6 : i64 = 2097151 & (load4(&c[15..]) >> 6) as i64;
let c7 : i64 = 2097151 & (load3(&c[18..]) >> 3) as i64;
let c8 : i64 = 2097151 & load3(&c[21..]) as i64;
let c9 : i64 = 2097151 & (load4(&c[23..]) >> 5) as i64;
let c10 : i64 = 2097151 & (load3(&c[26..]) >> 2) as i64;
let c11 : i64 = (load4(&c[28..]) >> 7) as i64;
let mut s0 : i64;
let mut s1 : i64;
let mut s2 : i64;
let mut s3 : i64;
let mut s4 : i64;
let mut s5 : i64;
let mut s6 : i64;
let mut s7 : i64;
let mut s8 : i64;
let mut s9 : i64;
let mut s10 : i64;
let mut s11 : i64;
let mut s12 : i64;
let mut s13 : i64;
let mut s14 : i64;
let mut s15 : i64;
let mut s16 : i64;
let mut s17 : i64;
let mut s18 : i64;
let mut s19 : i64;
let mut s20 : i64;
let mut s21 : i64;
let mut s22 : i64;
let mut s23 : i64;
let mut carry0 : i64;
let mut carry1 : i64;
let mut carry2 : i64;
let mut carry3 : i64;
let mut carry4 : i64;
let mut carry5 : i64;
let mut carry6 : i64;
let mut carry7 : i64;
let mut carry8 : i64;
let mut carry9 : i64;
let mut carry10 : i64;
let mut carry11 : i64;
let mut carry12 : i64;
let mut carry13 : i64;
let mut carry14 : i64;
let mut carry15 : i64;
let mut carry16 : i64;
let carry17 : i64;
let carry18 : i64;
let carry19 : i64;
let carry20 : i64;
let carry21 : i64;
let carry22 : i64;
s0 = c0 + a0 * b0;
s1 = c1 + a0 * b1 + a1 * b0;
s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0;
s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 +
a6 * b1 + a7 * b0;
s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 +
a6 * b2 + a7 * b1 + a8 * b0;
s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 +
a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 +
a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 +
a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 +
a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 +
a9 * b4 + a10 * b3 + a11 * b2;
s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 +
a10 * b4 + a11 * b3;
s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 +
a11 * b4;
s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
s20 = a9 * b11 + a10 * b10 + a11 * b9;
s21 = a10 * b11 + a11 * b10;
s22 = a11 * b11;
s23 = 0;
carry0 = (s0 + (1 << 20)) >> 21;
s1 += carry0;
s0 -= carry0 << 21;
carry2 = (s2 + (1 << 20)) >> 21;
s3 += carry2;
s2 -= carry2 << 21;
carry4 = (s4 + (1 << 20)) >> 21;
s5 += carry4;
s4 -= carry4 << 21;
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
carry12 = (s12 + (1 << 20)) >> 21;
s13 += carry12;
s12 -= carry12 << 21;
carry14 = (s14 + (1 << 20)) >> 21;
s15 += carry14;
s14 -= carry14 << 21;
carry16 = (s16 + (1 << 20)) >> 21;
s17 += carry16;
s16 -= carry16 << 21;
carry18 = (s18 + (1 << 20)) >> 21;
s19 += carry18;
s18 -= carry18 << 21;
carry20 = (s20 + (1 << 20)) >> 21;
s21 += carry20;
s20 -= carry20 << 21;
carry22 = (s22 + (1 << 20)) >> 21;
s23 += carry22;
s22 -= carry22 << 21;
carry1 = (s1 + (1 << 20)) >> 21;
s2 += carry1;
s1 -= carry1 << 21;
carry3 = (s3 + (1 << 20)) >> 21;
s4 += carry3;
s3 -= carry3 << 21;
carry5 = (s5 + (1 << 20)) >> 21;
s6 += carry5;
s5 -= carry5 << 21;
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
carry13 = (s13 + (1 << 20)) >> 21;
s14 += carry13;
s13 -= carry13 << 21;
carry15 = (s15 + (1 << 20)) >> 21;
s16 += carry15;
s15 -= carry15 << 21;
carry17 = (s17 + (1 << 20)) >> 21;
s18 += carry17;
s17 -= carry17 << 21;
carry19 = (s19 + (1 << 20)) >> 21;
s20 += carry19;
s19 -= carry19 << 21;
carry21 = (s21 + (1 << 20)) >> 21;
s22 += carry21;
s21 -= carry21 << 21;
s11 += s23 * 666643;
s12 += s23 * 470296;
s13 += s23 * 654183;
s14 -= s23 * 997805;
s15 += s23 * 136657;
s16 -= s23 * 683901;
//s23 = 0;
s10 += s22 * 666643;
s11 += s22 * 470296;
s12 += s22 * 654183;
s13 -= s22 * 997805;
s14 += s22 * 136657;
s15 -= s22 * 683901;
//s22 = 0;
s9 += s21 * 666643;
s10 += s21 * 470296;
s11 += s21 * 654183;
s12 -= s21 * 997805;
s13 += s21 * 136657;
s14 -= s21 * 683901;
//s21 = 0;
s8 += s20 * 666643;
s9 += s20 * 470296;
s10 += s20 * 654183;
s11 -= s20 * 997805;
s12 += s20 * 136657;
s13 -= s20 * 683901;
//s20 = 0;
s7 += s19 * 666643;
s8 += s19 * 470296;
s9 += s19 * 654183;
s10 -= s19 * 997805;
s11 += s19 * 136657;
s12 -= s19 * 683901;
//s19 = 0;
s6 += s18 * 666643;
s7 += s18 * 470296;
s8 += s18 * 654183;
s9 -= s18 * 997805;
s10 += s18 * 136657;
s11 -= s18 * 683901;
//s18 = 0;
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
carry12 = (s12 + (1 << 20)) >> 21;
s13 += carry12;
s12 -= carry12 << 21;
carry14 = (s14 + (1 << 20)) >> 21;
s15 += carry14;
s14 -= carry14 << 21;
carry16 = (s16 + (1 << 20)) >> 21;
s17 += carry16;
s16 -= carry16 << 21;
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
carry13 = (s13 + (1 << 20)) >> 21;
s14 += carry13;
s13 -= carry13 << 21;
carry15 = (s15 + (1 << 20)) >> 21;
s16 += carry15;
s15 -= carry15 << 21;
s5 += s17 * 666643;
s6 += s17 * 470296;
s7 += s17 * 654183;
s8 -= s17 * 997805;
s9 += s17 * 136657;
s10 -= s17 * 683901;
//s17 = 0;
s4 += s16 * 666643;
s5 += s16 * 470296;
s6 += s16 * 654183;
s7 -= s16 * 997805;
s8 += s16 * 136657;
s9 -= s16 * 683901;
//s16 = 0;
s3 += s15 * 666643;
s4 += s15 * 470296;
s5 += s15 * 654183;
s6 -= s15 * 997805;
s7 += s15 * 136657;
s8 -= s15 * 683901;
//s15 = 0;
s2 += s14 * 666643;
s3 += s14 * 470296;
s4 += s14 * 654183;
s5 -= s14 * 997805;
s6 += s14 * 136657;
s7 -= s14 * 683901;
//s14 = 0;
s1 += s13 * 666643;
s2 += s13 * 470296;
s3 += s13 * 654183;
s4 -= s13 * 997805;
s5 += s13 * 136657;
s6 -= s13 * 683901;
//s13 = 0;
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
s3 -= s12 * 997805;
s4 += s12 * 136657;
s5 -= s12 * 683901;
s12 = 0;
carry0 = (s0 + (1 << 20)) >> 21;
s1 += carry0;
s0 -= carry0 << 21;
carry2 = (s2 + (1 << 20)) >> 21;
s3 += carry2;
s2 -= carry2 << 21;
carry4 = (s4 + (1 << 20)) >> 21;
s5 += carry4;
s4 -= carry4 << 21;
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
carry1 = (s1 + (1 << 20)) >> 21;
s2 += carry1;
s1 -= carry1 << 21;
carry3 = (s3 + (1 << 20)) >> 21;
s4 += carry3;
s3 -= carry3 << 21;
carry5 = (s5 + (1 << 20)) >> 21;
s6 += carry5;
s5 -= carry5 << 21;
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
s3 -= s12 * 997805;
s4 += s12 * 136657;
s5 -= s12 * 683901;
s12 = 0;
carry0 = s0 >> 21;
s1 += carry0;
s0 -= carry0 << 21;
carry1 = s1 >> 21;
s2 += carry1;
s1 -= carry1 << 21;
carry2 = s2 >> 21;
s3 += carry2;
s2 -= carry2 << 21;
carry3 = s3 >> 21;
s4 += carry3;
s3 -= carry3 << 21;
carry4 = s4 >> 21;
s5 += carry4;
s4 -= carry4 << 21;
carry5 = s5 >> 21;
s6 += carry5;
s5 -= carry5 << 21;
carry6 = s6 >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry7 = s7 >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry8 = s8 >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry9 = s9 >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry10 = s10 >> 21;
s11 += carry10;
s10 -= carry10 << 21;
carry11 = s11 >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
s3 -= s12 * 997805;
s4 += s12 * 136657;
s5 -= s12 * 683901;
//s12 = 0;
carry0 = s0 >> 21;
s1 += carry0;
s0 -= carry0 << 21;
carry1 = s1 >> 21;
s2 += carry1;
s1 -= carry1 << 21;
carry2 = s2 >> 21;
s3 += carry2;
s2 -= carry2 << 21;
carry3 = s3 >> 21;
s4 += carry3;
s3 -= carry3 << 21;
carry4 = s4 >> 21;
s5 += carry4;
s4 -= carry4 << 21;
carry5 = s5 >> 21;
s6 += carry5;
s5 -= carry5 << 21;
carry6 = s6 >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry7 = s7 >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry8 = s8 >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry9 = s9 >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry10 = s10 >> 21;
s11 += carry10;
s10 -= carry10 << 21;
s[0] = (s0 >> 0) as u8;
s[1] = (s0 >> 8) as u8;
s[2] = ((s0 >> 16) | (s1 << 5)) as u8;
s[3] = (s1 >> 3) as u8;
s[4] = (s1 >> 11) as u8;
s[5] = ((s1 >> 19) | (s2 << 2)) as u8;
s[6] = (s2 >> 6) as u8;
s[7] = ((s2 >> 14) | (s3 << 7)) as u8;
s[8] = (s3 >> 1) as u8;
s[9] = (s3 >> 9) as u8;
s[10] = ((s3 >> 17) | (s4 << 4)) as u8;
s[11] = (s4 >> 4) as u8;
s[12] = (s4 >> 12) as u8;
s[13] = ((s4 >> 20) | (s5 << 1)) as u8;
s[14] = (s5 >> 7) as u8;
s[15] = ((s5 >> 15) | (s6 << 6)) as u8;
s[16] = (s6 >> 2) as u8;
s[17] = (s6 >> 10) as u8;
s[18] = ((s6 >> 18) | (s7 << 3)) as u8;
s[19] = (s7 >> 5) as u8;
s[20] = (s7 >> 13) as u8;
s[21] = (s8 >> 0) as u8;
s[22] = (s8 >> 8) as u8;
s[23] = ((s8 >> 16) | (s9 << 5)) as u8;
s[24] = (s9 >> 3) as u8;
s[25] = (s9 >> 11) as u8;
s[26] = ((s9 >> 19) | (s10 << 2)) as u8;
s[27] = (s10 >> 6) as u8;
s[28] = ((s10 >> 14) | (s11 << 7)) as u8;
s[29] = (s11 >> 1) as u8;
s[30] = (s11 >> 9) as u8;
s[31] = (s11 >> 17) as u8;
}
#[cfg(test)]
#[test]
fn muladd() {
let fname = "testdata/ed25519/muladd.test";
run_test(fname.to_string(), 4, |case| {
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let (negc, cbytes) = case.get("c").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
assert!(!nega && !negb && !negc && !negd);
let mut mine = [0; 32];
x25519_sc_muladd(&mut mine, abytes, bbytes, cbytes);
for i in 0..32 {
assert_eq!(&mine[i], &dbytes[i]);
}
});
}
pub fn curve25519_scalar_mask(a: &mut [u8])
{
assert_eq!(a.len(), 32);
a[0] &= 248;
a[31] &= 127;
a[31] |= 64;
}

View File

@@ -1,196 +0,0 @@
//! This module implements the Keyed-Hash Message Authentication Code, or HMAC,
//! as defined by NIST 198-1. Now, you might have questions, like:
//! * *Where did the 'K' go in the acronym?* I don't know. Maybe we should
//! always be saying Keyed-HMAC? It's a mystery.
//! * *What is this good for?* I do know the answer to that! HMACs are
//! useful when you want to extend the ability of a hash to tell you if
//! a message has been modified with the ability to determine if the
//! person that sent it had hold of a key. It's thus a version of the
//! message signing capability used in asymmetric crypto (`DSA`, `RSA`,
//! `ECDSA`, and `ED25519`, as implemented in this crate), but with a
//! symmetric key, instead.
//!
//! Because HMAC can be used with a variety of hash functions, this module
//! implements it as a generic structure that takes the associated hash as
//! a type argument. This should provide a reasonable level of flexibility,
//! while allowing the type system from preventing us from making any number
//! of really annoying mistakes. You can specify which of the hash functions
//! you want to use by using your standard turbofish:
//!
//! ```rust
//! use simple_crypto::hmac::HMAC;
//! use simple_crypto::sha::SHA256;
//!
//! let key = [0,1,2,3,4]; // very secure
//! let msg = [5,6,7,8];
//! let hmac = HMAC::<SHA256>::hmac(&key, &msg);
//! ```
//!
//! Much like with `SHAKE128` and `SHAKE256` the interface for HMAC is
//! similar to, but not quite, the interface for `Hash`. We thus try to
//! copy as much of the standard `Hash` interface as we can, but extend
//! `new` with a key, rename `hash` to `hmac`, and extend `hmac` with a
//! key as well. This provides a similar ability to use HMACs both in an
//! incremental mode as well as just do it all at once, as follows:
//!
//! ```rust
//! use simple_crypto::hmac::HMAC;
//! use simple_crypto::sha::SHA256;
//!
//! let key = [0,1,2,3,4]; // like my suitcase
//! let msg = [5,6,7,8];
//!
//! // Compute the HMAC incrementally
//! let mut hmacinc = HMAC::<SHA256>::new(&key);
//! hmacinc.update(&[5,6]);
//! hmacinc.update(&[7,8]);
//! let hmac_incremental = hmacinc.finalize();
//!
//! // Compute the HMAC all at once
//! let hmac_once = HMAC::<SHA256>::hmac(&key, &msg);
//!
//! // ... which should be the same thing
//! assert_eq!(hmac_incremental, hmac_once);
//! ```
/// The HMAC structure, parameterized by its hash function.
///
/// Much like with `SHAKE128` and `SHAKE256` the interface for HMAC is
/// similar to, but not quite, the interface for `Hash`. We thus try to
/// copy as much of the standard `Hash` interface as we can, but extend
/// `new` with a key, rename `hash` to `hmac`, and extend `hmac` with a
/// key as well. This provides a similar ability to use HMACs both in an
/// incremental mode as well as just do it all at once, as follows:
///
/// ```rust
/// use simple_crypto::hmac::HMAC;
/// use simple_crypto::sha::SHA256;
///
/// let key = [0,1,2,3,4]; // like my suitcase
/// let msg = [5,6,7,8];
///
/// // Compute the HMAC incrementally
/// let mut hmacinc = HMAC::<SHA256>::new(&key);
/// hmacinc.update(&[5,6]);
/// hmacinc.update(&[7,8]);
/// let hmac_incremental = hmacinc.finalize();
///
/// // Compute the HMAC all at once
/// let hmac_once = HMAC::<SHA256>::hmac(&key, &msg);
///
/// // ... which should be the same thing
/// assert_eq!(hmac_incremental, hmac_once);
/// ```
use super::Hash;
#[derive(Clone)]
pub struct HMAC<H: Hash + Clone> {
ipad_hash: H,
opad_hash: H,
result: Option<Vec<u8>>
}
impl<H: Hash + Clone> HMAC<H> {
/// Generate a new HMAC construction for the provide underlying hash
/// function, and prep it to start taking input via the `update`
/// method.
pub fn new(inkey: &[u8]) -> Self {
let hash_blocklen_bytes = H::block_size() / 8;
// If the input key is longer than the hash block length, then we
// immediately hash it down to be the block length. Otherwise, we
// leave it be.
let mut key = if inkey.len() > hash_blocklen_bytes { H::hash(inkey) }
else { inkey.to_vec() };
// It may now be too small, or have started too small, in which case
// we pad it out with zeros.
key.resize(hash_blocklen_bytes, 0);
// Generate the inner and outer key pad from this key.
let o_key_pad: Vec<u8> = key.iter().map(|x| *x ^ 0x5c).collect();
let i_key_pad: Vec<u8> = key.iter().map(|x| *x ^ 0x36).collect();
// Now we can start the hashes; obviously we'll have to wait
// until we get the rest of the message to complete them.
let mut ipad_hash = H::new();
ipad_hash.update(&i_key_pad);
let mut opad_hash = H::new();
opad_hash.update(&o_key_pad);
let result = None;
HMAC { ipad_hash, opad_hash, result }
}
/// Add more data as part of the HMAC computation. This can be called
/// zero or more times over the lifetime of the HMAC structure. That
/// being said, once you call `finalize`, this structure is done, and
/// it will ignore further calls to `update`.
pub fn update(&mut self, buffer: &[u8])
{
if self.result.is_none() {
self.ipad_hash.update(&buffer);
}
}
/// Provide the final HMAC value for the bitrstream as read. This shifts
/// this structure into a final mode, in which it will ignore any more
/// data provided to it from `update`. You can, however, call `finalize`
/// more than once; the HMAC structure caches the return value and will
/// return it as many times as you like.
pub fn finalize(&mut self) -> Vec<u8>
{
if let Some(ref res) = self.result {
res.clone()
} else {
self.opad_hash.update(&self.ipad_hash.finalize());
let res = self.opad_hash.finalize();
self.result = Some(res.clone());
res
}
}
/// A useful method for those situations in which you have only one block
/// of data to generate an HMAC for. Runs `new`, `update`, and `finalize`
/// for you, in order.
pub fn hmac(key: &[u8], val: &[u8]) -> Vec<u8>
{
let mut h = Self::new(key);
h.update(val);
h.finalize()
}
}
#[cfg(test)]
use sha::{SHA1,SHA224,SHA256,SHA384,SHA512};
#[cfg(test)]
use testing::run_test;
#[cfg(test)]
use cryptonum::unsigned::{Decoder,U192};
#[cfg(test)]
#[test]
fn nist_vectors() {
let fname = "testdata/sha/hmac.test";
run_test(fname.to_string(), 6, |case| {
let (negh, hbytes) = case.get("h").unwrap();
let (negr, rbytes) = case.get("r").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negk, kbytes) = case.get("k").unwrap();
let (negl, lbytes) = case.get("l").unwrap();
let (negt, tbytes) = case.get("t").unwrap();
assert!(!negh && !negr && !negm && !negk && !negl && !negt);
let l = usize::from(U192::from_bytes(lbytes));
let h = usize::from(U192::from_bytes(hbytes));
assert_eq!(l, kbytes.len());
let mut res = match h {
160 => HMAC::<SHA1>::hmac(&kbytes, &mbytes),
224 => HMAC::<SHA224>::hmac(&kbytes, &mbytes),
256 => HMAC::<SHA256>::hmac(&kbytes, &mbytes),
384 => HMAC::<SHA384>::hmac(&kbytes, &mbytes),
512 => HMAC::<SHA512>::hmac(&kbytes, &mbytes),
_ => panic!("Weird hash size in HMAC test file")
};
let t = usize::from(U192::from_bytes(tbytes));
res.resize(t, 0);
assert_eq!(rbytes, &res);
});
}

View File

@@ -9,92 +9,38 @@
//! that a new user should use, along with documentation regarding how and
//! when they should use it, and examples. For now, it mostly just fowards
//! off to more detailed modules. Help requested!
extern crate base64;
extern crate byteorder;
extern crate chrono;
extern crate cryptonum;
extern crate digest;
extern crate hmac;
extern crate num;
#[cfg(test)]
#[macro_use]
extern crate quickcheck;
extern crate rand;
#[macro_use]
extern crate sha1;
extern crate sha2;
extern crate simple_asn1;
/// The `rsa` module provides bare-bones support for RSA signing, verification,
/// encryption, decryption, and key generation.
/// The `cryptonum` module provides support for large numbers for use in various
/// cryptographically-relevant algorithms.
pub mod cryptonum;
/// The `rsa` module provides support for RSA-related core algorithms, including
/// signing / verification and encryption / decryption. You can also generate
/// key material there.
pub mod rsa;
/// The `dsa` module provides bare-bones support for DSA signing, verification,
/// and key generation. You shouldn't need to use these if you're building a
/// new system, but might need to use them to interact with legacy systems or
/// protocols.
/// The `dsa` module provides support for DSA-related signing and verification
/// algorithms, as well as key generation. That being said: don't use this,
/// unless you've got a legacy application or system that you're trying to
/// interact with. DSA is almost always the wrong choice.
pub mod dsa;
/// The `ecdsa` module provides bare-bones support for ECDSA signing,
/// verification, and key generation.
/// The 'ecdsa' module provides support for ECDSA-related signing and
/// verification algorithms, as well as key generation. This and RSA should be
/// your go-to choice for asymmetric crypto.
pub mod ecdsa;
/// The `ed25519` provides signing and verification using ED25519.
pub mod ed25519;
/// The `ssh` module provides support for parsing OpenSSH-formatted SSH keys,
/// both public and private.
pub mod ssh;
/// The `shake` module provides support for SHAKE128 and SHAKE256, two
/// variable-length hash functions that derive from the same core hash
/// as SHA3.
pub mod shake;
/// The `hmac` module provides support for keyed-hash message authentication,
/// or HMAC, based on any of the hash functions defined in this module.
pub mod hmac;
/// The `x509` module supports parsing and generating x.509 certificates, as
/// used by TLS and others.
pub mod x509;
/// An implementation of the SHA family of hashes, including the relatively
/// weak SHA1 and a bunch of hashes you should use, like the SHA2 and SHA3
/// hashes.
pub mod sha;
/// A generic trait for defining what a key pair looks like. This is useful
/// in a couple places in which we want to define code regardless of the
/// kind of key it is, but is unlikely to be hugely useful to users of the
/// library.
pub trait KeyPair {
/// The type of the public key of this pair.
type Public;
/// The type of the private key of this pair.
type Private;
/// Generate a key pair given the provided public and private keys.
fn new(pbl: Self::Public, prv: Self::Private) -> Self;
}
/// A generic trait for defining a hash function.
pub trait Hash: Sized
{
/// Generate a fresh instance of this hash function, set to the
/// appropriate initial state.
fn new() -> Self;
/// Update the hash function with some more data for it to chew on.
/// Nom nom nom. If you give it more information after calling
/// `finalize`, the implementation is welcome to do anything it
/// wants; mostly they will just ignore additional data, but
/// maybe just don't do that.
fn update(&mut self, data: &[u8]);
/// Finalize the hash function, returning the hash value.
fn finalize(&mut self) -> Vec<u8>;
/// Return the block size of the underlying hash function, in
/// bits. This is mostly useful internally to this crate.
fn block_size() -> usize;
/// This is a convenience routine that runs new(), update(), and
/// finalize() on a piece of data all at once. Because that's
/// mostly what people want to do.
fn hash(data: &[u8]) -> Vec<u8>
{
let mut x = Self::new();
x.update(&data);
x.finalize()
}
}
#[cfg(test)]
mod testing;
mod utils;
#[cfg(test)]
mod test {
}

View File

@@ -1,25 +1,123 @@
use cryptonum::unsigned::*;
use num::bigint::BigUint;
use rsa::errors::RSAError;
use simple_asn1::{ASN1Block,ASN1DecodeErr};
use cryptonum::{BarrettUCN,UCN};
use rand::Rng;
/// A valid key size for RSA keys, basically, and a (slightly annoying)
/// trait that is used to tie these types to their Barrett value types.
pub trait RSAMode {
type Barrett;
pub static ACCEPTABLE_KEY_SIZES: [(usize,usize); 8] =
[(512, 7),
(1024, 7),
(2048, 4),
(3072, 3),
(4096, 3),
(7680, 3),
(8192, 3),
(15360, 3)];
fn iterations_for_size(l: usize) -> usize {
for &(m, i) in ACCEPTABLE_KEY_SIZES.iter() {
if m == l {
return i;
}
}
panic!("Bad key size, can't get M-R iterations")
}
impl RSAMode for U512 { type Barrett = BarrettU512; }
impl RSAMode for U1024 { type Barrett = BarrettU1024; }
impl RSAMode for U2048 { type Barrett = BarrettU2048; }
impl RSAMode for U3072 { type Barrett = BarrettU3072; }
impl RSAMode for U4096 { type Barrett = BarrettU4096; }
impl RSAMode for U8192 { type Barrett = BarrettU8192; }
impl RSAMode for U15360 { type Barrett = BarrettU15360; }
pub fn generate_pq<G: Rng>(rng: &mut G, e: &UCN, bitlen: usize) -> (UCN, UCN) {
let iterations = iterations_for_size(bitlen);
let sqrt2 = UCN::from(6074001000 as u64);
let topbit = UCN::from(1 as u64) << ((bitlen / 2) - 1);
let minval = sqrt2 << ((bitlen / 2) - 33);
let mindiff = UCN::from(1 as u64) << ((bitlen / 2) - 101);
let validate = |inval| {
let x = &inval | &topbit;
if x < minval {
return None
}
if !gcd_is_one(&e, &x) {
return None
}
Some(x)
};
let p = UCN::generate_prime(rng, bitlen / 2, iterations, validate);
loop {
let q = UCN::generate_prime(rng, bitlen / 2, iterations, validate);
if diff(&p, &q) >= mindiff {
return (p, q);
}
}
}
fn diff(a: &UCN, b: &UCN) -> UCN {
if a > b {
a - b
} else {
b - a
}
}
fn gcd_is_one(a: &UCN, b: &UCN) -> bool {
let mut u = a.clone();
let mut v = b.clone();
if u.is_zero() {
return v == UCN::from(1 as u8);
}
if v.is_zero() {
return u == UCN::from(1 as u8);
}
if u.is_even() && v.is_even() {
return false;
}
while u.is_even() {
u >>= 1;
}
loop {
while v.is_even() {
v >>= 1;
}
// u and v guaranteed to be odd right now.
if u > v {
// make sure that v > u, so that our subtraction works
// out.
let t = u;
u = v;
v = t;
}
v = v - &u;
if v.is_zero() {
return u == UCN::from(1 as u64);
}
}
}
pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec<u8>
{
// the RSA encryption function
pub fn ep(nu: &BarrettUCN, e: &UCN, m: &UCN) -> UCN {
m.fastmodexp(e, nu)
}
// the RSA decryption function
pub fn dp(nu: &BarrettUCN, d: &UCN, c: &UCN) -> UCN {
c.fastmodexp(d, nu)
}
// the RSA signature generation function
pub fn sp1(nu: &BarrettUCN, d: &UCN, m: &UCN) -> UCN {
m.fastmodexp(d, nu)
}
// the RSA signature verification function
pub fn vp1(nu: &BarrettUCN, e: &UCN, s: &UCN) -> UCN {
s.fastmodexp(e, nu)
}
// encoding PKCS1 stuff
pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec<u8> {
let mut idhash = Vec::new();
idhash.extend_from_slice(ident);
idhash.extend_from_slice(hash);
@@ -34,31 +132,32 @@ pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec<u8>
result
}
pub fn drop0s(a: &[u8]) -> &[u8] {
let mut idx = 0;
while (idx < a.len()) && (a[idx] == 0) {
idx = idx + 1;
}
&a[idx..]
}
pub fn xor_vecs(a: &Vec<u8>, b: &Vec<u8>) -> Vec<u8> {
a.iter().zip(b.iter()).map(|(a,b)| a^b).collect()
}
pub fn decode_biguint(b: &ASN1Block) -> Result<BigUint,RSAError> {
match b {
&ASN1Block::Integer(_, _, ref v) => {
match v.to_biguint() {
Some(sn) => Ok(sn),
_ => Err(RSAError::InvalidKey)
}
}
_ =>
Err(RSAError::ASN1DecodeErr(ASN1DecodeErr::EmptyBuffer))
}
}
#[cfg(test)]
mod tests {
use rand::OsRng;
use super::*;
#[test]
#[ignore]
fn can_get_p_and_q() {
let mut rng = OsRng::new().unwrap();
let e = UCN::from(65537 as u64);
for &(size, _) in ACCEPTABLE_KEY_SIZES.iter().take(3) {
let (p,q) = generate_pq(&mut rng, &e, size);
let minval = UCN::from(1 as u8) << ((size / 2) - 1);
assert!(p > minval);
assert!(q > minval);
assert!(p != q);
assert!(p.is_odd());
assert!(q.is_odd());
let phi = (p - UCN::from(1 as u64)) * (q - UCN::from(1 as u64));
let d = e.modinv(&phi);
assert_eq!( (&e * &d) % phi, UCN::from(1 as u64) );
}
}
}

View File

@@ -1,8 +1,17 @@
use simple_asn1::ASN1DecodeErr;
use rand;
use std::io;
#[derive(Debug)]
pub enum RSAKeyGenError {
InvalidKeySize(usize), RngFailure(io::Error)
}
impl From<io::Error> for RSAKeyGenError {
fn from(e: io::Error) -> RSAKeyGenError {
RSAKeyGenError::RngFailure(e)
}
}
/// A bunch of errors that you can get generating, reading, or
/// writing RSA keys.
#[derive(Debug)]
pub enum RSAError {
BadMessageSize,
@@ -10,12 +19,12 @@ pub enum RSAError {
DecryptionError,
DecryptHashMismatch,
InvalidKey,
RandomGenError(rand::Error),
RandomGenError(io::Error),
ASN1DecodeErr(ASN1DecodeErr)
}
impl From<rand::Error> for RSAError {
fn from(e: rand::Error) -> RSAError {
impl From<io::Error> for RSAError {
fn from(e: io::Error) -> RSAError {
RSAError::RandomGenError(e)
}
}

208
src/rsa/gold_tests.rs Normal file
View File

@@ -0,0 +1,208 @@
use rsa::*;
use rsa::oaep::OAEPParams;
use sha1::Sha1;
use sha2::{Sha224,Sha256,Sha384,Sha512};
use testing::run_test;
fn get_signing_hash(s: usize) -> &'static SigningHash {
match s {
0x1 => &SIGNING_HASH_SHA1,
0x224 => &SIGNING_HASH_SHA224,
0x256 => &SIGNING_HASH_SHA256,
0x384 => &SIGNING_HASH_SHA384,
0x512 => &SIGNING_HASH_SHA512,
_ => panic!("Unacceptable hash")
}
}
#[test]
#[ignore]
fn rsa_signing_tests()
{
run_test("tests/rsa/signature.test", 7, |case| {
let (neg0, dbytes) = case.get("d").unwrap();
let (neg1, nbytes) = case.get("n").unwrap();
let (neg2, hbytes) = case.get("h").unwrap();
let (neg3, kbytes) = case.get("k").unwrap();
let (neg4, msg) = case.get("m").unwrap();
let (neg5, sig) = case.get("s").unwrap();
assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4 & !neg5);
let hash = get_signing_hash(usize::from(UCN::from_bytes(hbytes)));
let size = usize::from(UCN::from_bytes(kbytes));
let key = RSAPrivate::new(UCN::from_bytes(nbytes),
UCN::from_bytes(dbytes));
assert!(size % 8 == 0);
assert_eq!(key.byte_len * 8, size);
let sig2 = key.sign(hash, &msg);
assert_eq!(*sig, sig2);
});
}
#[test]
fn rsa_verification_tests()
{
run_test("tests/rsa/signature.test", 7, |case| {
let (neg1, nbytes) = case.get("n").unwrap();
let (neg2, hbytes) = case.get("h").unwrap();
let (neg3, kbytes) = case.get("k").unwrap();
let (neg4, msg) = case.get("m").unwrap();
let (neg5, sig) = case.get("s").unwrap();
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5);
let hash = get_signing_hash(usize::from(UCN::from_bytes(hbytes)));
let size = usize::from(UCN::from_bytes(kbytes));
let key = RSAPublic::new(UCN::from_bytes(nbytes),
UCN::from(65537u64));
assert_eq!(key.byte_len * 8, size);
assert!(key.verify(hash, &msg, sig));
});
}
#[test]
fn rsa_decryption_tests()
{
run_test("tests/rsa/encryption.test", 6, |case| {
let (neg1, dbytes) = case.get("d").unwrap();
let (neg2, nbytes) = case.get("n").unwrap();
let (neg3, hbytes) = case.get("h").unwrap();
let (neg4, lbytes) = case.get("l").unwrap();
let (neg5, msg) = case.get("m").unwrap();
let (neg6, cphtxt) = case.get("c").unwrap();
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5 & !neg6);
let label = String::from_utf8(lbytes.clone()).unwrap();
let key = RSAPrivate::new(UCN::from_bytes(nbytes),
UCN::from_bytes(dbytes));
let wrapped = match usize::from(UCN::from_bytes(hbytes)) {
0x1 => key.decrypt(&OAEPParams::new(Sha1::default(), label),cphtxt),
0x224 => key.decrypt(&OAEPParams::new(Sha224::default(),label),cphtxt),
0x256 => key.decrypt(&OAEPParams::new(Sha256::default(),label),cphtxt),
0x384 => key.decrypt(&OAEPParams::new(Sha384::default(),label),cphtxt),
0x512 => key.decrypt(&OAEPParams::new(Sha512::default(),label),cphtxt),
_ => panic!("Unacceptable hash")
};
let mymsg = wrapped.unwrap();
assert_eq!(msg, &mymsg);
});
}
#[test]
#[ignore]
fn rsa_long_decryption_tests()
{
run_test("tests/rsa/encryption.ext.test", 6, |case| {
let (neg1, dbytes) = case.get("d").unwrap();
let (neg2, nbytes) = case.get("n").unwrap();
let (neg3, hbytes) = case.get("h").unwrap();
let (neg4, lbytes) = case.get("l").unwrap();
let (neg5, msg) = case.get("m").unwrap();
let (neg6, cphtxt) = case.get("c").unwrap();
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5 & !neg6);
let label = String::from_utf8(lbytes.clone()).unwrap();
let key = RSAPrivate::new(UCN::from_bytes(nbytes),
UCN::from_bytes(dbytes));
let wrapped = match usize::from(UCN::from_bytes(hbytes)) {
0x1 => key.decrypt(&OAEPParams::new(Sha1::default(), label),cphtxt),
0x224 => key.decrypt(&OAEPParams::new(Sha224::default(),label),cphtxt),
0x256 => key.decrypt(&OAEPParams::new(Sha256::default(),label),cphtxt),
0x384 => key.decrypt(&OAEPParams::new(Sha384::default(),label),cphtxt),
0x512 => key.decrypt(&OAEPParams::new(Sha512::default(),label),cphtxt),
_ => panic!("Unacceptable hash")
};
let mymsg = wrapped.unwrap();
assert_eq!(msg, &mymsg);
});
}
#[test]
fn rsa_encryption_tests()
{
run_test("tests/rsa/encryption.test", 6, |case| {
let (neg1, dbytes) = case.get("d").unwrap();
let (neg2, nbytes) = case.get("n").unwrap();
let (neg3, hbytes) = case.get("h").unwrap();
let (neg4, lbytes) = case.get("l").unwrap();
let (neg5, msg) = case.get("m").unwrap();
// This one's a little tricky, because there's randomness in the
// encryption phase. So we can't just encrypt and see if we get the
// same value. Instead, we just use this as a test vector to round
// trip, and trust that the decryption test above makes sure we're
// not going off into la la land.
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5);
let label = String::from_utf8(lbytes.clone()).unwrap();
let private = RSAPrivate::new(UCN::from_bytes(nbytes),
UCN::from_bytes(dbytes));
let public = RSAPublic::new(UCN::from_bytes(nbytes),
UCN::from(65537u64));
let wrappedc = match usize::from(UCN::from_bytes(hbytes)) {
0x1 => public.encrypt(&OAEPParams::new(Sha1::default(), label.clone()), &msg),
0x224 => public.encrypt(&OAEPParams::new(Sha224::default(),label.clone()), &msg),
0x256 => public.encrypt(&OAEPParams::new(Sha256::default(),label.clone()), &msg),
0x384 => public.encrypt(&OAEPParams::new(Sha384::default(),label.clone()), &msg),
0x512 => public.encrypt(&OAEPParams::new(Sha512::default(),label.clone()), &msg),
_ => panic!("Unacceptable hash")
};
let ciphertext = wrappedc.unwrap();
let wrappedm = match usize::from(UCN::from_bytes(hbytes)) {
0x1 => private.decrypt(&OAEPParams::new(Sha1::default(), label), &ciphertext),
0x224 => private.decrypt(&OAEPParams::new(Sha224::default(),label), &ciphertext),
0x256 => private.decrypt(&OAEPParams::new(Sha256::default(),label), &ciphertext),
0x384 => private.decrypt(&OAEPParams::new(Sha384::default(),label), &ciphertext),
0x512 => private.decrypt(&OAEPParams::new(Sha512::default(),label), &ciphertext),
_ => panic!("Unacceptable hash")
};
let message = wrappedm.unwrap();
assert_eq!(msg, &message);
});
}
#[test]
#[ignore]
fn rsa_long_encryption_tests()
{
run_test("tests/rsa/encryption.ext.test", 6, |case| {
let (neg1, dbytes) = case.get("d").unwrap();
let (neg2, nbytes) = case.get("n").unwrap();
let (neg3, hbytes) = case.get("h").unwrap();
let (neg4, lbytes) = case.get("l").unwrap();
let (neg5, msg) = case.get("m").unwrap();
// This one's a little tricky, because there's randomness in the
// encryption phase. So we can't just encrypt and see if we get the
// same value. Instead, we just use this as a test vector to round
// trip, and trust that the decryption test above makes sure we're
// not going off into la la land.
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5);
let label = String::from_utf8(lbytes.clone()).unwrap();
let private = RSAPrivate::new(UCN::from_bytes(nbytes),
UCN::from_bytes(dbytes));
let public = RSAPublic::new(UCN::from_bytes(nbytes),
UCN::from(65537u64));
let wrappedc = match usize::from(UCN::from_bytes(hbytes)) {
0x1 => public.encrypt(&OAEPParams::new(Sha1::default(), label.clone()), &msg),
0x224 => public.encrypt(&OAEPParams::new(Sha224::default(),label.clone()), &msg),
0x256 => public.encrypt(&OAEPParams::new(Sha256::default(),label.clone()), &msg),
0x384 => public.encrypt(&OAEPParams::new(Sha384::default(),label.clone()), &msg),
0x512 => public.encrypt(&OAEPParams::new(Sha512::default(),label.clone()), &msg),
_ => panic!("Unacceptable hash")
};
let ciphertext = wrappedc.unwrap();
let wrappedm = match usize::from(UCN::from_bytes(hbytes)) {
0x1 => private.decrypt(&OAEPParams::new(Sha1::default(), label), &ciphertext),
0x224 => private.decrypt(&OAEPParams::new(Sha224::default(),label), &ciphertext),
0x256 => private.decrypt(&OAEPParams::new(Sha256::default(),label), &ciphertext),
0x384 => private.decrypt(&OAEPParams::new(Sha384::default(),label), &ciphertext),
0x512 => private.decrypt(&OAEPParams::new(Sha512::default(),label), &ciphertext),
_ => panic!("Unacceptable hash")
};
let message = wrappedm.unwrap();
assert_eq!(msg, &message);
});
}

View File

@@ -1,339 +1,109 @@
//! A simple RSA library.
//!
//! This library performs all the standard bits and pieces that you'd expect
//! from an RSA library, and does so using only Rust. It's a bit slow at the
//! moment, but it gets the job done.
//!
//! Key generation is supported, using either the native `OsRng` or a random
//! number generator of your choice. Obviously, you should be careful to use
//! a cryptographically-sound random number generator sufficient for the
//! security level you're going for.
//!
//! Signing and verification are via standard PKCS1 padding, but can be
//! adjusted based on the exact hash you want. This library also supports
//! somewhat arbitrary signing mechanisms used by your weirder network
//! protocols. (I'm looking at you, Tor.)
//!
//! Encryption and decryption are via the OAEP mechanism, as described in
//! NIST documents.
//!
//! The following is an example of generating an RSA2048 key pair, then using
//! it to sign, verify, encrypt, and decrypt some data.
//!
//! ```rust
//! extern crate cryptonum;
//!
//! use simple_crypto::rsa::RSAKeyPair;
//! use simple_crypto::rsa::SIGNING_HASH_SHA256;
//! use simple_crypto::rsa::OAEPParams;
//! use simple_crypto::sha::SHA256;
//! use cryptonum::unsigned::U2048;
//!
//! // Generate a new RSA with key size 2048. (This is an acceptable but
//! // not great key size, but is a nice compromise given that this little
//! // example runs as part of the test suite.)
//! let mut rng = rand::rngs::OsRng::new().unwrap();
//! let kp = RSAKeyPair::<U2048>::generate(&mut rng);
//!
//! // Now that you have this key pair, you can sign and verify messages
//! // using it. For example, to sign the vector [0,1,2,3,4] with SHA256
//! // and then verify that signature, we would write:
//! let msg = vec![0,1,2,3,4];
//! let sig = kp.private.sign(&SIGNING_HASH_SHA256, &msg);
//! assert!( kp.public.verify(&SIGNING_HASH_SHA256, &msg, &sig) );
//!
//! // We can also use RSA public keys to encrypt data, which can then be
//! // decrypted by the private key.
//! let params = OAEPParams::<SHA256>::new(String::from("example!"));
//! let cipher = kp.public.encrypt(&params, &msg).expect("Encryption error");
//! let msg2 = kp.private.decrypt(&params, &cipher).expect("Decryption error");
//! assert_eq!(msg, msg2);
//! ```
mod core;
mod errors;
#[cfg(test)]
mod gold_tests;
mod oaep;
mod private;
mod public;
mod private;
mod signing_hashes;
pub use self::core::RSAMode;
pub use self::errors::RSAError;
pub use self::public::RSAPublic;
pub use self::private::RSAPrivate;
pub use self::signing_hashes::{SigningHash,
SIGNING_HASH_NULL,
SIGNING_HASH_SHA1,
SIGNING_HASH_SHA224,
SIGNING_HASH_SHA256,
SIGNING_HASH_SHA384,
SIGNING_HASH_SHA512};
pub use self::oaep::OAEPParams;
pub use self::private::{RSAPrivate, RSAPrivateKey};
pub use self::public::{RSAPublic, RSAPublicKey};
use cryptonum::signed::{EGCD,ModInv};
use cryptonum::unsigned::{CryptoNum,PrimeGen};
use cryptonum::unsigned::{U256,U512,U1024,U1536,U2048,U3072,U4096,U7680,U8192,U15360};
use rand::RngCore;
#[cfg(test)]
use std::fmt;
use std::ops::Sub;
use super::KeyPair;
SIGNING_HASH_NULL, SIGNING_HASH_SHA1,
SIGNING_HASH_SHA224, SIGNING_HASH_SHA256,
SIGNING_HASH_SHA384, SIGNING_HASH_SHA512};
fn diff<T>(a: &T, b: &T) -> T
where
T: Clone + PartialOrd,
T: Sub<T,Output=T>
{
if a > b {
a.clone() - b.clone()
} else {
b.clone() - a.clone()
}
use cryptonum::UCN;
use rand::{OsRng,Rng};
use self::core::{ACCEPTABLE_KEY_SIZES,generate_pq};
use self::errors::*;
#[derive(Clone,Debug)]
pub struct RSAKeyPair {
pub public: RSAPublic,
pub private: RSAPrivate
}
/// An RSA key pair containing keys of the given size; keeping them in the
/// type means you'll never forget which one you have.
impl RSAKeyPair {
/// Generates a fresh RSA key pair of the given bit size. Valid bit sizes
/// are 512, 1024, 2048, 3072, 4096, 7680, 8192, and 15360. If you
/// actually want to protect data, use a value greater than or equal to
/// 2048. If you don't want to spend all day waiting for RSA computations
/// to finish, choose a value less than or equal to 4096.
///
/// As an aside:
/// * `U512` should only be used for testing
/// * `U1024` should only be used to support old protocols or devices
/// * `U2048` is probably your bare minimum
/// * `U3072` is a very reasonable choice
/// * **`U4096` is what you should use**
/// * `U8192` is starting to get a bit silly (and slow)
/// * `U15360` is for when you're using encryption to heat your house or server room
pub struct RSAKeyPair<R: RSAMode> {
pub public: RSAPublicKey<R>,
pub private: RSAPrivateKey<R>
/// This routine will use `OsRng` for entropy. If you want to use your
/// own random number generator, use `generate_w_rng`.
pub fn generate(len_bits: usize) -> Result<RSAKeyPair,RSAKeyGenError> {
let mut rng = OsRng::new()?;
RSAKeyPair::generate_w_rng(&mut rng, len_bits)
}
/// A generic RSA key pair that is agnostic about its key size. It's not
/// totally clear why this is useful, at this point.
#[derive(PartialEq)]
pub enum RSAPair {
R512(RSAPublicKey<U512>, RSAPrivateKey<U512>),
R1024(RSAPublicKey<U1024>, RSAPrivateKey<U1024>),
R2048(RSAPublicKey<U2048>, RSAPrivateKey<U2048>),
R3072(RSAPublicKey<U3072>, RSAPrivateKey<U3072>),
R4096(RSAPublicKey<U4096>, RSAPrivateKey<U4096>),
R8192(RSAPublicKey<U8192>, RSAPrivateKey<U8192>),
R15360(RSAPublicKey<U15360>, RSAPrivateKey<U15360>),
}
#[cfg(test)]
impl fmt::Debug for RSAPair {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
/// Generates a fresh RSA key pair of the given bit size. Valid bit sizes
/// are 512, 1024, 2048, 3072, 4096, 7680, 8192, and 15360. If you
/// actually want to protect data, use a value greater than or equal to
/// 2048. If you don't want to spend all day waiting for RSA computations
/// to finish, choose a value less than or equal to 4096.
///
/// If you provide your own random number generator that is not `OsRng`,
/// you should know what you're doing, and be using a cryptographically-
/// strong RNG of your own choosing. We've warned you. Use a good one.
/// So now it's on you.
pub fn generate_w_rng<G: Rng>(rng: &mut G, len_bits: usize)
-> Result<RSAKeyPair,RSAKeyGenError>
{
match self {
RSAPair::R512(_,_) => f.write_str("512-bit RSA key pair"),
RSAPair::R1024(_,_) => f.write_str("1024-bit RSA key pair"),
RSAPair::R2048(_,_) => f.write_str("2048-bit RSA key pair"),
RSAPair::R3072(_,_) => f.write_str("3072-bit RSA key pair"),
RSAPair::R4096(_,_) => f.write_str("4096-bit RSA key pair"),
RSAPair::R8192(_,_) => f.write_str("8192-bit RSA key pair"),
RSAPair::R15360(_,_) => f.write_str("15360-bit RSA key pair"),
}
}
}
let e = UCN::from(65537 as u32);
impl KeyPair for RSAPair {
type Public = RSAPublic;
type Private = RSAPrivate;
fn new(pu: RSAPublic, pr: RSAPrivate) -> RSAPair
{
match (pu, pr) {
(RSAPublic::Key512(pbl), RSAPrivate::Key512(prv)) =>
RSAPair::R512(pbl, prv),
(RSAPublic::Key1024(pbl), RSAPrivate::Key1024(prv)) =>
RSAPair::R1024(pbl, prv),
(RSAPublic::Key2048(pbl), RSAPrivate::Key2048(prv)) =>
RSAPair::R2048(pbl, prv),
(RSAPublic::Key3072(pbl), RSAPrivate::Key3072(prv)) =>
RSAPair::R3072(pbl, prv),
(RSAPublic::Key4096(pbl), RSAPrivate::Key4096(prv)) =>
RSAPair::R4096(pbl, prv),
(RSAPublic::Key8192(pbl), RSAPrivate::Key8192(prv)) =>
RSAPair::R8192(pbl, prv),
(RSAPublic::Key15360(pbl), RSAPrivate::Key15360(prv)) =>
RSAPair::R15360(pbl, prv),
_ =>
panic!("Unmatched public/private arguments to RSAPair::new()")
}
}
}
impl RSAPair {
pub fn sign(&self, signhash: &SigningHash, msg: &[u8]) -> Vec<u8>
{
match self {
RSAPair::R512(_,prv) => prv.sign(signhash, msg),
RSAPair::R1024(_,prv) => prv.sign(signhash, msg),
RSAPair::R2048(_,prv) => prv.sign(signhash, msg),
RSAPair::R3072(_,prv) => prv.sign(signhash, msg),
RSAPair::R4096(_,prv) => prv.sign(signhash, msg),
RSAPair::R8192(_,prv) => prv.sign(signhash, msg),
RSAPair::R15360(_,prv) => prv.sign(signhash, msg),
}
}
pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool
{
match self {
RSAPair::R512(pbl,_) => pbl.verify(signhash, msg, sig),
RSAPair::R1024(pbl,_) => pbl.verify(signhash, msg, sig),
RSAPair::R2048(pbl,_) => pbl.verify(signhash, msg, sig),
RSAPair::R3072(pbl,_) => pbl.verify(signhash, msg, sig),
RSAPair::R4096(pbl,_) => pbl.verify(signhash, msg, sig),
RSAPair::R8192(pbl,_) => pbl.verify(signhash, msg, sig),
RSAPair::R15360(pbl,_) => pbl.verify(signhash, msg, sig),
}
}
pub fn public(&self) -> RSAPublic
{
match self {
&RSAPair::R512(ref pbl,_) => RSAPublic::Key512(pbl.clone()),
&RSAPair::R1024(ref pbl,_) => RSAPublic::Key1024(pbl.clone()),
&RSAPair::R2048(ref pbl,_) => RSAPublic::Key2048(pbl.clone()),
&RSAPair::R3072(ref pbl,_) => RSAPublic::Key3072(pbl.clone()),
&RSAPair::R4096(ref pbl,_) => RSAPublic::Key4096(pbl.clone()),
&RSAPair::R8192(ref pbl,_) => RSAPublic::Key8192(pbl.clone()),
&RSAPair::R15360(ref pbl,_) => RSAPublic::Key15360(pbl.clone()),
}
}
pub fn private(&self) -> RSAPrivate
{
match self {
&RSAPair::R512(_,ref prv) => RSAPrivate::Key512(prv.clone()),
&RSAPair::R1024(_,ref prv) => RSAPrivate::Key1024(prv.clone()),
&RSAPair::R2048(_,ref prv) => RSAPrivate::Key2048(prv.clone()),
&RSAPair::R3072(_,ref prv) => RSAPrivate::Key3072(prv.clone()),
&RSAPair::R4096(_,ref prv) => RSAPrivate::Key4096(prv.clone()),
&RSAPair::R8192(_,ref prv) => RSAPrivate::Key8192(prv.clone()),
&RSAPair::R15360(_,ref prv) => RSAPrivate::Key15360(prv.clone()),
}
}
}
macro_rules! generate_rsa_pair
{
($uint: ident, $half: ident, $iterations: expr) => {
impl KeyPair for RSAKeyPair<$uint> {
type Public = RSAPublicKey<$uint>;
type Private = RSAPrivateKey<$uint>;
fn new(pu: RSAPublicKey<$uint>, pr: RSAPrivateKey<$uint>) -> RSAKeyPair<$uint> {
RSAKeyPair {
public: pu,
private: pr
}
}
}
impl RSAKeyPair<$uint> {
pub fn generate<G>(rng: &mut G) -> RSAKeyPair<$uint>
where G: RngCore
{
loop {
let ebase = 65537u32;
let e = $uint::from(ebase);
let (p, q) = RSAKeyPair::<$uint>::generate_pq(rng, &$half::from(ebase));
let one = $half::from(1u32);
let pminus1 = &p - &one;
let qminus1 = &q - &one;
let phi = pminus1 * qminus1;
for &(length, _) in ACCEPTABLE_KEY_SIZES.iter() {
if length == len_bits {
let (p, q) = generate_pq(rng, &e, len_bits);
let n = &p * &q;
if let Some(d) = e.modinv(&phi) {
let public = RSAPublicKey::<$uint>::new(n.clone(), e);
let private = RSAPrivateKey::<$uint>::new(n, d);
return RSAKeyPair::<$uint>::new(public, private);
}
}
}
fn generate_pq<G>(rng: &mut G, e: &$half) -> ($half, $half)
where G: RngCore
{
let sqrt2_32 = 6074001000u64;
let half_bitlen = $half::bit_length();
let minval = $half::from(sqrt2_32) << (half_bitlen - 33);
let mindiff = $half::from(1u64) << (half_bitlen - 101);
let p = $half::random_primef(rng, $iterations, |x| {
if (x >= minval) && x.gcd_is_one(e) {
Some(x)
} else {
None
}
});
loop {
let q = $half::random_primef(rng, $iterations, |x| {
if (x >= minval) && x.gcd_is_one(e) {
Some(x)
} else {
None
}
});
if diff(&p, &q) >= mindiff {
return (p, q);
}
}
}
}
let one = UCN::from(1 as u8);
let phi = (p - &one) * (q - &one);
let d = e.modinv(&phi);
let public_key = RSAPublic::new(n.clone(), e);
let private_key = RSAPrivate::new(n, d);
return Ok(RSAKeyPair{
private: private_key,
public: public_key
})
}
}
generate_rsa_pair!(U512, U256, 7);
generate_rsa_pair!(U1024, U512, 7);
generate_rsa_pair!(U2048, U1024, 4);
generate_rsa_pair!(U3072, U1536, 3);
generate_rsa_pair!(U4096, U2048, 3);
generate_rsa_pair!(U8192, U4096, 3);
generate_rsa_pair!(U15360, U7680, 3);
Err(RSAKeyGenError::InvalidKeySize(len_bits))
}
}
#[cfg(test)]
mod generation {
mod tests {
use quickcheck::{Arbitrary,Gen};
use std::fmt;
use rsa::core::{ep,dp,sp1,vp1};
use super::*;
impl Clone for RSAKeyPair<U512> {
fn clone(&self) -> RSAKeyPair<U512> {
RSAKeyPair {
public: RSAPublicKey {
n: self.public.n.clone(),
nu: self.public.nu.clone(),
e: self.public.e.clone(),
},
private: RSAPrivateKey {
nu: self.private.nu.clone(),
d: self.private.d.clone()
}
}
}
}
const TEST_KEY_SIZES: [usize; 2] = [512, 1024];
impl fmt::Debug for RSAKeyPair<U512> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RSA512KeyPair")
.field("n", &self.public.n)
.field("e", &self.public.e)
.field("d", &self.private.d)
.finish()
}
}
impl Arbitrary for RSAKeyPair<U512> {
fn arbitrary<G: Gen>(g: &mut G) -> RSAKeyPair<U512> {
RSAKeyPair::<U512>::generate(g)
impl Arbitrary for RSAKeyPair {
fn arbitrary<G: Gen>(g: &mut G) -> RSAKeyPair {
let size = g.choose(&TEST_KEY_SIZES).unwrap();
RSAKeyPair::generate_w_rng(g, *size).unwrap()
}
}
quickcheck! {
fn generate_and_sign(keypair: RSAKeyPair<U512>, msg: Vec<u8>) -> bool {
let sig = keypair.private.sign(&SIGNING_HASH_SHA256, &msg);
keypair.public.verify(&SIGNING_HASH_SHA256, &msg, &sig)
#[ignore]
fn rsa_ep_dp_inversion(kp: RSAKeyPair, n: UCN) -> bool {
let m = n.reduce(&kp.public.nu);
let ciphertext = ep(&kp.public.nu, &kp.public.e, &m);
let mprime = dp(&kp.private.nu, &kp.private.d, &ciphertext);
mprime == m
}
#[ignore]
fn rsa_sp_vp_inversion(kp: RSAKeyPair, n: UCN) -> bool {
let m = n.reduce(&kp.public.nu);
let sig = sp1(&kp.private.nu, &kp.private.d, &m);
let mprime = vp1(&kp.public.nu, &kp.public.e, &sig);
mprime == m
}
}
}

View File

@@ -1,43 +1,44 @@
use byteorder::{BigEndian,ByteOrder};
use sha::Hash;
use std::marker::PhantomData;
use cryptonum::UCN;
use digest::{FixedOutput,Input};
/// Parameters for OAEP encryption and decryption: a hash function to use as
/// part of the message generation function (MGF1, if you're curious),
/// and any labels you want to include as part of the encryption.
pub struct OAEPParams<H: Hash> {
pub label: String,
phantom: PhantomData<H>
/// Parameters for OAEP encryption and decryption: a hash function to use as part of the message
/// generation function (MGF1, if you're curious), and any labels you want to include as part of
/// the encryption.
pub struct OAEPParams<H: Clone + Input + FixedOutput> {
pub hash: H,
pub label: String
}
impl<H: Hash> OAEPParams<H> {
pub fn new(label: String)
impl<H: Clone + Input + FixedOutput> OAEPParams<H> {
pub fn new(hash: H, label: String)
-> OAEPParams<H>
{
OAEPParams { label: label, phantom: PhantomData }
OAEPParams { hash: hash, label: label }
}
pub fn hash_len(&self) -> usize {
H::hash(&[]).len()
self.hash.clone().fixed_result().as_slice().len()
}
pub fn hash(&self, input: &[u8]) -> Vec<u8> {
H::hash(input)
let mut digest = self.hash.clone();
digest.process(input);
digest.fixed_result().as_slice().to_vec()
}
pub fn mgf1(&self, input: &[u8], len: usize) -> Vec<u8> {
let mut res = Vec::with_capacity(len);
let mut counter = 0u32;
let mut counter = UCN::from(0u64);
let one = UCN::from(1u64);
while res.len() < len {
let mut buffer = [0; 4];
BigEndian::write_u32(&mut buffer, counter);
let mut digest = H::new();
digest.update(input);
digest.update(&buffer);
let chunk = digest.finalize();
let c = counter.to_bytes(4);
let mut digest = self.hash.clone();
digest.process(input);
digest.process(&c);
let chunk = digest.fixed_result();
res.extend_from_slice(chunk.as_slice());
counter = counter + 1;
counter = counter + &one;
}
res.truncate(len);

View File

@@ -1,72 +1,87 @@
use cryptonum::unsigned::*;
use rsa::core::{RSAMode,drop0s,pkcs1_pad,xor_vecs};
use cryptonum::{BarrettUCN,UCN};
use digest::{FixedOutput,Input};
use rsa::core::{ACCEPTABLE_KEY_SIZES,dp,pkcs1_pad,sp1,xor_vecs};
use rsa::errors::RSAError;
use rsa::oaep::OAEPParams;
use rsa::signing_hashes::SigningHash;
use sha::Hash;
use std::fmt;
/// An RSA private key. Useful for signing messages and decrypting encrypted
/// content.
#[derive(Clone,PartialEq)]
pub struct RSAPrivateKey<R: RSAMode>
{
pub(crate) nu: R::Barrett,
pub(crate) d: R
#[derive(Clone)]
pub struct RSAPrivate {
pub(crate) byte_len: usize,
pub(crate) n: UCN,
pub(crate) nu: BarrettUCN,
pub(crate) d: UCN
}
/// A generic RSA private key which is agnostic to its key size.
#[derive(Clone,PartialEq)]
pub enum RSAPrivate {
Key512(RSAPrivateKey<U512>),
Key1024(RSAPrivateKey<U1024>),
Key2048(RSAPrivateKey<U2048>),
Key3072(RSAPrivateKey<U3072>),
Key4096(RSAPrivateKey<U4096>),
Key8192(RSAPrivateKey<U8192>),
Key15360(RSAPrivateKey<U15360>)
#[cfg(test)]
impl fmt::Debug for RSAPrivate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RSAPrivate")
.field("byte_len", &self.byte_len)
.field("n", &self.n)
.field("nu", &self.nu)
.field("d", &self.d)
.finish()
}
}
macro_rules! generate_rsa_private
{
($num: ident, $bar: ident, $size: expr) => {
impl RSAPrivateKey<$num> {
/// Generate a new private key with the given modulus and private
/// number (`d`). This operation actually does a bit of computation
/// under the hood, in order to speed up future ones, so you might
/// want to strongly consider sharing rather than multiple
/// instantiation. But you do you.
pub fn new(n: $num, d: $num) -> RSAPrivateKey<$num> {
let nu = $bar::new(n.clone());
RSAPrivateKey{ nu: nu, d: d }
#[cfg(test)]
impl PartialEq for RSAPrivate {
fn eq(&self, rhs: &RSAPrivate) -> bool {
(self.byte_len == rhs.byte_len) &&
(self.n == rhs.n) &&
(self.nu == rhs.nu) &&
(self.d == rhs.d)
}
}
/// Sign the given message with the given SigningHash, returning
/// the signature. This uses a deterministic PKCS1 method for
/// signing messages, so no RNG required.
pub fn sign(&self, signhash: &SigningHash, msg: &[u8])
-> Vec<u8>
{
let hash = (signhash.run)(msg);
let em = pkcs1_pad(&signhash.ident, &hash, $size/8);
let m = $num::from_bytes(&em);
let s = self.sp1(&m);
let sig = s.to_bytes();
#[cfg(test)]
impl Eq for RSAPrivate {}
#[cfg(not(test))]
impl fmt::Debug for RSAPrivate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("RSAPrivateKey<PRIVATE>")
}
}
impl RSAPrivate {
/// Create a new RSA public key from the given components, which you found
/// via some other mechanism.
pub fn new(n: UCN, d: UCN) -> RSAPrivate {
let len = n.bits();
for &(valid_bits, _) in ACCEPTABLE_KEY_SIZES.iter() {
if valid_bits >= len {
return RSAPrivate {
byte_len: valid_bits / 8,
n: n.clone(),
nu: n.barrett_u(),
d: d.clone()
};
}
}
panic!("Invalid RSA key size in new()")
}
/// Sign a message using the given hash.
pub fn sign(&self, sighash: &SigningHash, msg: &[u8]) -> Vec<u8> {
let hash = (sighash.run)(msg);
let em = pkcs1_pad(&sighash.ident, &hash, self.byte_len);
let m = UCN::from_bytes(&em);
let s = sp1(&self.nu, &self.d, &m);
let sig = s.to_bytes(self.byte_len);
sig
}
/// Decrypted the provided encrypted blob using the given
/// parameters. This does standard RSA OAEP decryption, which is
/// rather slow. If you have a choice, you should probably do
/// something clever, like only use this encryption/decryption
/// method to encrypt/decrypt a shared symmetric key, like an
/// AES key. That way, you only do this operation (which is
/// SO SLOW) for a relatively small amount of data.
pub fn decrypt<H: Hash>(&self, oaep: &OAEPParams<H>, msg: &[u8])
/// Decrypt a message with the given parameters.
pub fn decrypt<H: Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
{
let mut res = Vec::new();
for chunk in msg.chunks($size/8) {
for chunk in msg.chunks(self.byte_len) {
let mut dchunk = self.oaep_decrypt(oaep, chunk)?;
res.append(&mut dchunk);
}
@@ -74,32 +89,23 @@ macro_rules! generate_rsa_private
Ok(res)
}
fn sp1(&self, m: &$num) -> $num {
m.modexp(&self.d, &self.nu)
}
fn dp(&self, c: &$num) -> $num {
c.modexp(&self.d, &self.nu)
}
fn oaep_decrypt<H: Hash>(&self, oaep: &OAEPParams<H>, c: &[u8])
fn oaep_decrypt<H: Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, c: &[u8])
-> Result<Vec<u8>,RSAError>
{
let byte_len = $size / 8;
// Step 1b
if c.len() != byte_len {
if c.len() != self.byte_len {
return Err(RSAError::DecryptionError);
}
// Step 1c
if byte_len < ((2 * oaep.hash_len()) + 2) {
if self.byte_len < ((2 * oaep.hash_len()) + 2) {
return Err(RSAError::DecryptHashMismatch);
}
// Step 2a
let c_ip = $num::from_bytes(&c);
let c_ip = UCN::from_bytes(&c.to_vec());
// Step 2b
let m_ip = self.dp(&c_ip);
let m_ip = dp(&self.nu, &self.d, &c_ip);
// Step 2c
let em = m_ip.to_bytes();
let em = &m_ip.to_bytes(self.byte_len);
// Step 3a
let l_hash = oaep.hash(oaep.label.as_bytes());
// Step 3b
@@ -110,7 +116,7 @@ macro_rules! generate_rsa_private
// Step 3d
let seed = xor_vecs(&masked_seed.to_vec(), &seed_mask);
// Step 3e
let db_mask = oaep.mgf1(&seed, byte_len - oaep.hash_len() - 1);
let db_mask = oaep.mgf1(&seed, self.byte_len - oaep.hash_len() - 1);
// Step 3f
let db = xor_vecs(&masked_db.to_vec(), &db_mask);
// Step 3g
@@ -131,139 +137,13 @@ macro_rules! generate_rsa_private
Ok(m.to_vec())
}
}
}
fn drop0s(a: &[u8]) -> &[u8] {
let mut idx = 0;
while (idx < a.len()) && (a[idx] == 0) {
idx = idx + 1;
}
generate_rsa_private!(U512, BarrettU512, 512);
generate_rsa_private!(U1024, BarrettU1024, 1024);
generate_rsa_private!(U2048, BarrettU2048, 2048);
generate_rsa_private!(U3072, BarrettU3072, 3072);
generate_rsa_private!(U4096, BarrettU4096, 4096);
generate_rsa_private!(U8192, BarrettU8192, 8192);
generate_rsa_private!(U15360, BarrettU15360, 15360);
#[cfg(test)]
macro_rules! sign_test_body {
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
let fname = format!("testdata/rsa/sign{}.test", $size);
run_test(fname.to_string(), 7, |case| {
let (neg0, dbytes) = case.get("d").unwrap();
let (neg1, nbytes) = case.get("n").unwrap();
let (neg2, hbytes) = case.get("h").unwrap();
let (neg3, mbytes) = case.get("m").unwrap();
let (neg4, sbytes) = case.get("s").unwrap();
let (neg5, ubytes) = case.get("u").unwrap();
let (neg6, kbytes) = case.get("k").unwrap();
assert!(!neg0&&!neg1&&!neg2&&!neg3&&!neg4&&!neg5&&!neg6);
let n = $num64::from_bytes(nbytes);
let nu = $num64::from_bytes(ubytes);
let bigk = $num::from_bytes(kbytes);
let k = usize::from(bigk);
let d = $num::from_bytes(dbytes);
let sighash = match usize::from($num::from_bytes(hbytes)) {
224 => &SIGNING_HASH_SHA224,
256 => &SIGNING_HASH_SHA256,
384 => &SIGNING_HASH_SHA384,
512 => &SIGNING_HASH_SHA512,
x => panic!("Bad signing hash: {}", x)
};
let privkey = RSAPrivateKey{ nu: $bar::from_components(k, n.clone(), nu), d: d };
let sig = privkey.sign(sighash, &mbytes);
assert_eq!(*sbytes, sig);
});
};
&a[idx..]
}
#[cfg(test)]
macro_rules! decrypt_test_body {
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
let fname = format!("testdata/rsa/encrypt{}.test", $size);
run_test(fname.to_string(), 9, |case| {
let (neg0, nbytes) = case.get("n").unwrap();
let (neg1, hbytes) = case.get("h").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, _bytes) = case.get("e").unwrap();
let (neg4, ubytes) = case.get("u").unwrap();
let (neg5, kbytes) = case.get("k").unwrap();
let (neg6, dbytes) = case.get("d").unwrap();
let (neg7, lbytes) = case.get("l").unwrap();
let (neg8, cbytes) = case.get("c").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5 && !neg6 && !neg7 && !neg8);
let n = $num::from_bytes(nbytes);
let n64 = $num64::from(&n);
let nu = $num64::from_bytes(ubytes);
let bigk = $num::from_bytes(kbytes);
let k = usize::from(bigk);
let d = $num::from_bytes(dbytes);
let nu = $bar::from_components(k, n64, nu);
let privkey = RSAPrivateKey{ nu: nu, d: d };
let lstr = String::from_utf8(lbytes.clone()).unwrap();
let message = match usize::from($num::from_bytes(hbytes)) {
224 => privkey.decrypt(&OAEPParams::<SHA224>::new(lstr), &cbytes),
256 => privkey.decrypt(&OAEPParams::<SHA256>::new(lstr), &cbytes),
384 => privkey.decrypt(&OAEPParams::<SHA384>::new(lstr), &cbytes),
512 => privkey.decrypt(&OAEPParams::<SHA512>::new(lstr), &cbytes),
x => panic!("Unknown hash number: {}", x)
};
assert!(message.is_ok());
assert_eq!(mbytes, &message.unwrap());
});
};
}
macro_rules! generate_tests {
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
#[cfg(test)]
#[allow(non_snake_case)]
mod $mod {
use cryptonum::unsigned::Decoder;
use super::*;
use testing::run_test;
use rsa::signing_hashes::*;
use sha::{SHA224,SHA256,SHA384,SHA512};
#[test]
fn sign() {
sign_test_body!($mod, $num, $bar, $num64, $size);
}
#[test]
fn decrypt() {
decrypt_test_body!($mod, $num, $bar, $num64, $size);
}
}
};
(ignore $mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
#[cfg(test)]
#[allow(non_snake_case)]
mod $mod {
use cryptonum::unsigned::Decoder;
use super::*;
use testing::run_test;
use rsa::signing_hashes::*;
use sha::{SHA224,SHA256,SHA384,SHA512};
#[ignore]
#[test]
fn sign() {
sign_test_body!($mod, $num, $bar, $num64, $size);
}
#[ignore]
#[test]
fn decrypt() {
decrypt_test_body!($mod, $num, $bar, $num64, $size);
}
}
}
}
generate_tests!( RSA512, U512, BarrettU512, U576, 512);
generate_tests!( RSA1024, U1024, BarrettU1024, U1088, 1024);
generate_tests!( RSA2048, U2048, BarrettU2048, U2112, 2048);
generate_tests!( RSA3072, U3072, BarrettU3072, U3136, 3072);
generate_tests!( RSA4096, U4096, BarrettU4096, U4160, 4096);
generate_tests!(ignore RSA8192, U8192, BarrettU8192, U8256, 8192);
generate_tests!(ignore RSA15360, U15360, BarrettU15360, U15424, 15360);

View File

@@ -1,259 +1,95 @@
use cryptonum::unsigned::*;
use rand::Rng;
use rand::rngs::OsRng;
use rsa::core::{RSAMode,decode_biguint,pkcs1_pad,xor_vecs};
use cryptonum::{BarrettUCN,UCN};
use digest::{FixedOutput,Input};
use rand::{OsRng,Rng};
use rsa::core::{ACCEPTABLE_KEY_SIZES,ep,pkcs1_pad,vp1,xor_vecs};
use rsa::errors::RSAError;
use rsa::oaep::OAEPParams;
use rsa::signing_hashes::SigningHash;
use sha::Hash;
use simple_asn1::{ASN1Block,ASN1DecodeErr,ASN1EncodeErr,
ASN1Class,FromASN1,ToASN1};
#[cfg(test)]
use std::fmt;
use utils::TranslateNums;
/// An RSA public key. Useful for verifying signatures or encrypting data to
/// send to the private key holder.
#[derive(Clone,PartialEq)]
pub struct RSAPublicKey<R: RSAMode> {
pub(crate) n: R,
pub(crate) nu: R::Barrett,
pub(crate) e: R
}
/// A generic private key that is agnostic to the key size.
#[derive(Clone,PartialEq)]
pub enum RSAPublic {
Key512( RSAPublicKey<U512>),
Key1024( RSAPublicKey<U1024>),
Key2048( RSAPublicKey<U2048>),
Key3072( RSAPublicKey<U3072>),
Key4096( RSAPublicKey<U4096>),
Key8192( RSAPublicKey<U8192>),
Key15360(RSAPublicKey<U15360>)
#[derive(Clone,Debug,PartialEq,Eq)]
pub struct RSAPublic {
pub(crate) byte_len: usize,
pub(crate) n: UCN,
pub(crate) nu: BarrettUCN,
pub(crate) e: UCN
}
impl RSAPublic {
/// Verify that the given signature is for the given message, passing
/// in the same signing arguments used to sign the message in the
/// first place.
pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool
{
match self {
RSAPublic::Key512(x) => x.verify(signhash, msg, sig),
RSAPublic::Key1024(x) => x.verify(signhash, msg, sig),
RSAPublic::Key2048(x) => x.verify(signhash, msg, sig),
RSAPublic::Key3072(x) => x.verify(signhash, msg, sig),
RSAPublic::Key4096(x) => x.verify(signhash, msg, sig),
RSAPublic::Key8192(x) => x.verify(signhash, msg, sig),
RSAPublic::Key15360(x) => x.verify(signhash, msg, sig)
/// Create a new RSA public key from the given components, which you found
/// via some other mechanism.
pub fn new(n: UCN, e: UCN) -> RSAPublic {
let len = n.bits();
for &(valid_bits, _) in ACCEPTABLE_KEY_SIZES.iter() {
if valid_bits >= len {
return RSAPublic{
byte_len: valid_bits / 8,
n: n.clone(),
nu: n.barrett_u(),
e: e.clone()
};
}
}
panic!("Invalid RSA key size in new()")
}
impl FromASN1 for RSAPublic {
type Error = RSAError;
fn from_asn1(bs: &[ASN1Block])
-> Result<(RSAPublic,&[ASN1Block]),RSAError>
{
match bs.split_first() {
None =>
Err(RSAError::ASN1DecodeErr(ASN1DecodeErr::EmptyBuffer)),
Some((&ASN1Block::Sequence(_, _, ref items), rest))
if items.len() == 2 =>
{
let n = decode_biguint(&items[0])?;
let e = decode_biguint(&items[1])?;
let nsize = n.bits();
let mut rsa_size = 512;
while rsa_size < nsize {
rsa_size = rsa_size + 256;
}
match rsa_size {
512 => {
let n2 = U512::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U512::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSAPublicKey::<U512>::new(n2, e2);
Ok((RSAPublic::Key512(res), rest))
}
1024 => {
let n2 = U1024::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U1024::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSAPublicKey::<U1024>::new(n2, e2);
Ok((RSAPublic::Key1024(res), rest))
}
2048 => {
let n2 = U2048::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U2048::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSAPublicKey::<U2048>::new(n2, e2);
Ok((RSAPublic::Key2048(res), rest))
}
3072 => {
let n2 = U3072::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U3072::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSAPublicKey::<U3072>::new(n2, e2);
Ok((RSAPublic::Key3072(res), rest))
}
4096 => {
let n2 = U4096::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U4096::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSAPublicKey::<U4096>::new(n2, e2);
Ok((RSAPublic::Key4096(res), rest))
}
8192 => {
let n2 = U8192::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U8192::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSAPublicKey::<U8192>::new(n2, e2);
Ok((RSAPublic::Key8192(res), rest))
}
15360 => {
let n2 = U15360::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U15360::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSAPublicKey::<U15360>::new(n2, e2);
Ok((RSAPublic::Key15360(res), rest))
}
_ =>
Err(RSAError::InvalidKey)
}
}
Some(_) =>
Err(RSAError::InvalidKey)
}
}
/// Verify the signature for a given message, using the given signing hash,
/// returning true iff the signature validates.
pub fn verify(&self, shash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool {
let hash = (shash.run)(msg);
let s = UCN::from_bytes(&sig);
let m = vp1(&self.nu, &self.e, &s);
let em = m.to_bytes(self.byte_len);
let em_ = pkcs1_pad(&shash.ident, &hash, self.byte_len);
(em == em_)
}
impl ToASN1 for RSAPublic {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,Self::Error>
{
match self {
RSAPublic::Key512(x) => x.to_asn1_class(c),
RSAPublic::Key1024(x) => x.to_asn1_class(c),
RSAPublic::Key2048(x) => x.to_asn1_class(c),
RSAPublic::Key3072(x) => x.to_asn1_class(c),
RSAPublic::Key4096(x) => x.to_asn1_class(c),
RSAPublic::Key8192(x) => x.to_asn1_class(c),
RSAPublic::Key15360(x) => x.to_asn1_class(c)
}
}
}
#[cfg(test)]
impl fmt::Debug for RSAPublic {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
RSAPublic::Key512(x) => write!(fmt, "RSA:{:?}", x),
RSAPublic::Key1024(x) => write!(fmt, "RSA:{:?}", x),
RSAPublic::Key2048(x) => write!(fmt, "RSA:{:?}", x),
RSAPublic::Key3072(x) => write!(fmt, "RSA:{:?}", x),
RSAPublic::Key4096(x) => write!(fmt, "RSA:{:?}", x),
RSAPublic::Key8192(x) => write!(fmt, "RSA:{:?}", x),
RSAPublic::Key15360(x) => write!(fmt, "RSA:{:?}", x)
}
}
}
macro_rules! generate_rsa_public
{
($num: ident, $bar: ident, $var: ident, $size: expr) => {
impl RSAPublicKey<$num> {
/// Generate a new public key pair for the given modulus and
/// exponent. You should probably not call this directly unless
/// you're writing a key generation function or writing your own
/// public key parser.
pub fn new(n: $num, e: $num) -> RSAPublicKey<$num> {
let nu = $bar::new(n.clone());
RSAPublicKey{ n: n, nu: nu, e: e }
}
/// Verify that the provided signature is valid; that the private
/// key associated with this public key sent exactly this message.
/// The hash used here must exactly match the hash used to sign
/// the message, including its ASN.1 metadata.
pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8])
-> bool
{
let hash: Vec<u8> = (signhash.run)(msg);
let s = $num::from_bytes(&sig);
let m = self.vp1(&s);
let em = m.to_bytes();
let em_ = pkcs1_pad(signhash.ident, &hash, $size/8);
em == em_
}
/// Encrypt the message with a hash function, given the appropriate
/// label. Please note that RSA encryption is not particularly fast,
/// and decryption is very slow indeed. Thus, most crypto systems that
/// need asymmetric encryption should generate a symmetric key, encrypt
/// that key with RSA encryption, and then encrypt the actual message
/// with that symmetric key.
/// Encrypt the given data with the public key and parameters, returning
/// the encrypted blob or an error encountered during encryption.
///
/// In this variant of the function, we use an explicit random number
/// generator, just in case you have one you really like. It better be
/// cryptographically strong, though, as some of the padding protections
/// are relying on it.
pub fn encrypt_rng<G,H>(&self,g: &mut G,oaep: &OAEPParams<H>,msg: &[u8])
/// OAEP encoding is used for this process, which requires a random number
/// generator. This version of the function uses `OsRng`. If you want to
/// use your own RNG, use `encrypt_w_rng`.
pub fn encrypt<H:Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where
G: Rng,
H: Hash
{
let byte_len = $size / 8;
let mut res = Vec::new();
let mut g = OsRng::new()?;
self.encrypt_with_rng(&mut g, oaep, msg)
}
if byte_len <= ((2 * oaep.hash_len()) + 2) {
/// Encrypt the given data with the public key and parameters, returning
/// the encrypted blob or an error encountered during encryption. This
/// version also allows you to provide your own RNG, if you really feel
/// like shooting yourself in the foot.
pub fn encrypt_with_rng<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where G: Rng, H: Clone + Input + FixedOutput
{
if self.byte_len <= ((2 * oaep.hash_len()) + 2) {
return Err(RSAError::KeyTooSmallForHash);
}
for chunk in msg.chunks(byte_len - (2 * oaep.hash_len()) - 2) {
let mut res = Vec::new();
for chunk in msg.chunks(self.byte_len - (2 * oaep.hash_len()) - 2) {
let mut newchunk = self.oaep_encrypt(g, oaep, chunk)?;
res.append(&mut newchunk);
res.append(&mut newchunk)
}
Ok(res)
}
/// Encrypt the message with a hash function, given the appropriate
/// label. Please note that RSA encryption is not particularly fast,
/// and decryption is very slow indeed. Thus, most crypto systems that
/// need asymmetric encryption should generate a symmetric key, encrypt
/// that key with RSA encryption, and then encrypt the actual message
/// with that symmetric key.
///
/// This variant will just use the system RNG for its randomness.
pub fn encrypt<H: Hash>(&self,oaep:&OAEPParams<H>,msg:&[u8])
fn oaep_encrypt<G: Rng,H:Clone + Input + FixedOutput>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
{
let mut g = OsRng::new()?;
self.encrypt_rng(&mut g, oaep, msg)
}
fn vp1(&self, s: &$num) -> $num {
s.modexp(&self.e, &self.nu)
}
fn ep(&self, m: &$num) -> $num {
m.modexp(&self.e, &self.nu)
}
fn oaep_encrypt<G,H>(&self,g: &mut G,oaep: &OAEPParams<H>,m: &[u8])
-> Result<Vec<u8>,RSAError>
where
G: Rng,
H: Hash
{
let byte_len = $size / 8;
// Step 1b
if m.len() > (byte_len - (2 * oaep.hash_len()) - 2) {
if msg.len() > (self.byte_len - (2 * oaep.hash_len()) - 2) {
return Err(RSAError::BadMessageSize)
}
// Step 2a
let mut lhash = oaep.hash(oaep.label.as_bytes());
// Step 2b
let num0s = byte_len - m.len() - (2 * oaep.hash_len()) - 2;
let num0s = self.byte_len - msg.len() - (2 * oaep.hash_len()) - 2;
let mut ps = Vec::new();
ps.resize(num0s, 0);
// Step 2c
@@ -261,13 +97,11 @@ macro_rules! generate_rsa_public
db.append(&mut lhash);
db.append(&mut ps);
db.push(1);
db.extend_from_slice(m);
db.extend_from_slice(msg);
// Step 2d
let mut seed: Vec<u8> = Vec::with_capacity(oaep.hash_len());
seed.resize(oaep.hash_len(), 0);
g.fill(seed.as_mut_slice());
let seed : Vec<u8> = g.gen_iter().take(oaep.hash_len()).collect();
// Step 2e
let db_mask = oaep.mgf1(&seed, byte_len - oaep.hash_len() - 1);
let db_mask = oaep.mgf1(&seed, self.byte_len - oaep.hash_len() - 1);
// Step 2f
let mut masked_db = xor_vecs(&db, &db_mask);
// Step 2g
@@ -280,247 +114,11 @@ macro_rules! generate_rsa_public
em.append(&mut masked_seed);
em.append(&mut masked_db);
// Step 3a
let m_i = $num::from_bytes(&em);
let m_i = UCN::from_bytes(&em);
// Step 3b
let c_i = self.ep(&m_i);
let c_i = ep(&self.nu, &self.e, &m_i);
// Step 3c
let c = c_i.to_bytes();
let c = c_i.to_bytes(self.byte_len);
Ok(c)
}
}
impl FromASN1 for RSAPublicKey<$num> {
type Error = RSAError;
fn from_asn1(bs: &[ASN1Block])
-> Result<(RSAPublicKey<$num>,&[ASN1Block]),RSAError>
{
let (core, rest) = RSAPublic::from_asn1(bs)?;
match core {
RSAPublic::$var(x) => Ok((x, rest)),
_ => Err(RSAError::InvalidKey)
}
}
}
impl ToASN1 for RSAPublicKey<$num> {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,Self::Error>
{
let n = self.n.to_num();
let e = self.e.to_num();
let enc_n = ASN1Block::Integer(c, 0, n);
let enc_e = ASN1Block::Integer(c, 0, e);
let seq = ASN1Block::Sequence(c, 0, vec![enc_n, enc_e]);
Ok(vec![seq])
}
}
#[cfg(test)]
impl fmt::Debug for RSAPublicKey<$num> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct(stringify!($rsa))
.field("n", &self.n)
.field("nu", &self.nu)
.field("e", &self.e)
.finish()
}
}
}
}
generate_rsa_public!(U512, BarrettU512, Key512, 512);
generate_rsa_public!(U1024, BarrettU1024, Key1024, 1024);
generate_rsa_public!(U2048, BarrettU2048, Key2048, 2048);
generate_rsa_public!(U3072, BarrettU3072, Key3072, 3072);
generate_rsa_public!(U4096, BarrettU4096, Key4096, 4096);
generate_rsa_public!(U8192, BarrettU8192, Key8192, 8192);
generate_rsa_public!(U15360, BarrettU15360, Key15360, 15360);
#[cfg(test)]
macro_rules! new_test_body {
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
let fname = format!("testdata/rsa/sign{}.test", $size);
run_test(fname.to_string(), 7, |case| {
let (neg0, nbytes) = case.get("n").unwrap();
let (neg1, ubytes) = case.get("u").unwrap();
let (neg2, kbytes) = case.get("k").unwrap();
assert!(!neg0&&!neg1&&!neg2);
let n = $num::from_bytes(nbytes);
let n64 = $num64::from(&n);
let nu = $num64::from_bytes(ubytes);
let bigk = $num::from_bytes(kbytes);
let k = usize::from(bigk);
let e = $num::from(65537u64);
let pubkey2 = RSAPublicKey::<$num>::new(n.clone(), e.clone());
let pubkey1 = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
assert_eq!(pubkey1, pubkey2);
});
};
}
#[cfg(test)]
macro_rules! encode_test_body {
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
let fname = format!("testdata/rsa/sign{}.test", $size);
run_test(fname.to_string(), 7, |case| {
let (neg0, nbytes) = case.get("n").unwrap();
let (neg1, ubytes) = case.get("u").unwrap();
let (neg2, kbytes) = case.get("k").unwrap();
assert!(!neg0&&!neg1&&!neg2);
let n = $num::from_bytes(nbytes);
let n64 = $num64::from(&n);
let nu = $num64::from_bytes(ubytes);
let bigk = $num::from_bytes(kbytes);
let k = usize::from(bigk);
let e = $num::from(65537u64);
let pubkey = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
let asn1 = pubkey.to_asn1().unwrap();
let (pubkey2, _) = RSAPublicKey::from_asn1(&asn1).unwrap();
assert_eq!(pubkey, pubkey2);
});
};
}
#[cfg(test)]
macro_rules! verify_test_body {
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
let fname = format!("testdata/rsa/sign{}.test", $size);
run_test(fname.to_string(), 7, |case| {
let (neg0, nbytes) = case.get("n").unwrap();
let (neg1, hbytes) = case.get("h").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, sbytes) = case.get("s").unwrap();
let (neg4, ubytes) = case.get("u").unwrap();
let (neg5, kbytes) = case.get("k").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5);
let n = $num::from_bytes(nbytes);
let n64 = $num64::from(&n);
let nu = $num64::from_bytes(ubytes);
let bigk = $num::from_bytes(kbytes);
let k = usize::from(bigk);
let e = $num::from(65537u64);
let pubkey = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
let hashnum = u64::from($num::from_bytes(hbytes));
let sighash = match hashnum {
160 => &SIGNING_HASH_SHA1,
224 => &SIGNING_HASH_SHA224,
256 => &SIGNING_HASH_SHA256,
384 => &SIGNING_HASH_SHA384,
512 => &SIGNING_HASH_SHA512,
_ => panic!("Bad signing hash: {}", hashnum)
};
assert!(pubkey.verify(sighash, &mbytes, &sbytes));
});
};
}
#[cfg(test)]
macro_rules! encrypt_test_body {
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
let fname = format!("testdata/rsa/encrypt{}.test", $size);
run_test(fname.to_string(), 9, |case| {
let (neg0, nbytes) = case.get("n").unwrap();
let (neg1, hbytes) = case.get("h").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, _bytes) = case.get("e").unwrap();
let (neg4, ubytes) = case.get("u").unwrap();
let (neg5, kbytes) = case.get("k").unwrap();
let (neg6, dbytes) = case.get("d").unwrap();
let (neg7, lbytes) = case.get("l").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5 && !neg6 && !neg7);
let n = $num::from_bytes(nbytes);
let n64 = $num64::from(&n);
let nu = $num64::from_bytes(ubytes);
let bigk = $num::from_bytes(kbytes);
let k = usize::from(bigk);
let e = $num::from(65537u64);
let d = $num::from_bytes(dbytes);
let nu = $bar::from_components(k, n64, nu);
let pubkey = RSAPublicKey{ n: n.clone(), nu: nu.clone(), e: e };
let privkey = RSAPrivateKey{ nu: nu, d: d };
let lstr = String::from_utf8(lbytes.clone()).unwrap();
let cipher = match usize::from($num::from_bytes(hbytes)) {
224 => pubkey.encrypt(&OAEPParams::<SHA224>::new(lstr.clone()), mbytes),
256 => pubkey.encrypt(&OAEPParams::<SHA256>::new(lstr.clone()), mbytes),
384 => pubkey.encrypt(&OAEPParams::<SHA384>::new(lstr.clone()), mbytes),
512 => pubkey.encrypt(&OAEPParams::<SHA512>::new(lstr.clone()), mbytes),
x => panic!("Unknown hash number: {}", x)
};
assert!(cipher.is_ok());
let message = match usize::from($num::from_bytes(hbytes)) {
224 => privkey.decrypt(&OAEPParams::<SHA224>::new(lstr), &cipher.unwrap()),
256 => privkey.decrypt(&OAEPParams::<SHA256>::new(lstr), &cipher.unwrap()),
384 => privkey.decrypt(&OAEPParams::<SHA384>::new(lstr), &cipher.unwrap()),
512 => privkey.decrypt(&OAEPParams::<SHA512>::new(lstr), &cipher.unwrap()),
x => panic!("Unknown hash number: {}", x)
};
assert!(message.is_ok());
assert_eq!(mbytes, &message.unwrap());
});
};
}
macro_rules! generate_tests {
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
#[cfg(test)]
#[allow(non_snake_case)]
mod $mod {
use cryptonum::unsigned::Decoder;
use super::*;
use testing::run_test;
use rsa::private::*;
use rsa::signing_hashes::*;
use sha::{SHA224,SHA256,SHA384,SHA512};
#[test]
fn new() { new_test_body!($mod, $num, $bar, $num64, $size); }
#[test]
fn encode() { encode_test_body!($mod, $num, $bar, $num64, $size); }
#[test]
fn verify() { verify_test_body!($mod, $num, $bar, $num64, $size); }
#[test]
fn encrypt() { encrypt_test_body!($mod, $num, $bar, $num64, $size); }
}
};
(ignore $mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
#[cfg(test)]
#[allow(non_snake_case)]
mod $mod {
use cryptonum::unsigned::Decoder;
use super::*;
use testing::run_test;
use rsa::private::*;
use rsa::signing_hashes::*;
use sha::{SHA224,SHA256,SHA384,SHA512};
#[ignore]
#[test]
fn new() { new_test_body!($mod, $num, $bar, $num64, $size); }
#[ignore]
#[test]
fn encode() { encode_test_body!($mod, $num, $bar, $num64, $size); }
#[ignore]
#[test]
fn verify() { verify_test_body!($mod, $num, $bar, $num64, $size); }
#[ignore]
#[test]
fn encrypt() { encrypt_test_body!($mod, $num, $bar, $num64, $size); }
}
};
}
generate_tests!( RSA512, U512, BarrettU512, U576, 512);
generate_tests!( RSA1024, U1024, BarrettU1024, U1088, 1024);
generate_tests!( RSA2048, U2048, BarrettU2048, U2112, 2048);
generate_tests!( RSA3072, U3072, BarrettU3072, U3136, 3072);
generate_tests!( RSA4096, U4096, BarrettU4096, U4160, 4096);
generate_tests!(ignore RSA8192, U8192, BarrettU8192, U8256, 8192);
generate_tests!(ignore RSA15360, U15360, BarrettU15360, U15424, 15360);

View File

@@ -1,4 +1,6 @@
use sha::{Hash,SHA1,SHA224,SHA256,SHA384,SHA512};
use digest::{FixedOutput,Input};
use sha1::Sha1;
use sha2::{Sha224,Sha256,Sha384,Sha512};
use std::fmt;
/// A hash that can be used to sign a message.
@@ -26,9 +28,13 @@ impl fmt::Debug for SigningHash {
pub static SIGNING_HASH_NULL: SigningHash = SigningHash {
name: "NULL",
ident: &[],
run: |x| { x.to_vec() }
run: nohash
};
fn nohash(i: &[u8]) -> Vec<u8> {
i.to_vec()
}
/// Sign a hash based on SHA1. You shouldn't use this unless you're using
/// very small keys, and this is the only one available to you. Even then,
/// why are you using such small keys?!
@@ -36,9 +42,15 @@ pub static SIGNING_HASH_SHA1: SigningHash = SigningHash {
name: "SHA1",
ident: &[0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,
0x02,0x1a,0x05,0x00,0x04,0x14],
run: |x| { SHA1::hash(x) }
run: runsha1
};
fn runsha1(i: &[u8]) -> Vec<u8> {
let mut d = Sha1::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
}
/// Sign a hash based on SHA2-224. This is the first reasonable choice
/// we've come across, and is useful when you have smaller RSA key sizes.
/// I wouldn't recommend it, though.
@@ -47,18 +59,30 @@ pub static SIGNING_HASH_SHA224: SigningHash = SigningHash {
ident: &[0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,
0x1c],
run: |x| { SHA224::hash(x) }
run: runsha224
};
fn runsha224(i: &[u8]) -> Vec<u8> {
let mut d = Sha224::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
}
/// Sign a hash based on SHA2-256. The first one I'd recommend!
pub static SIGNING_HASH_SHA256: SigningHash = SigningHash {
name: "SHA256",
ident: &[0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,
0x20],
run: |x| { SHA256::hash(x) }
run: runsha256
};
fn runsha256(i: &[u8]) -> Vec<u8> {
let mut d = Sha256::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
}
/// Sign a hash based on SHA2-384. Approximately 50% better than
/// SHA-256.
pub static SIGNING_HASH_SHA384: SigningHash = SigningHash {
@@ -66,9 +90,15 @@ pub static SIGNING_HASH_SHA384: SigningHash = SigningHash {
ident: &[0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,
0x30],
run: |x| { SHA384::hash(x) }
run: runsha384
};
fn runsha384(i: &[u8]) -> Vec<u8> {
let mut d = Sha384::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
}
/// Sign a hash based on SHA2-512. At this point, you're getting a bit
/// silly. But if you want to through 8kbit RSA keys with a 512 bit SHA2
/// signing hash, we're totally behind you.
@@ -77,5 +107,13 @@ pub static SIGNING_HASH_SHA512: SigningHash = SigningHash {
ident: &[0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,
0x40],
run: |x| { SHA512::hash(x) }
run: runsha512
};
fn runsha512(i: &[u8]) -> Vec<u8> {
let mut d = Sha512::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
}

View File

@@ -1,64 +0,0 @@
//! The SHA family of hash functions, as defined by NIST; specifically, from
//! NIST 180-4 (for SHA1 and SHA2) and NIST 202 (for SHA3).
//!
//! These hash functions are used through their instantiation of the `Hash`
//! trait, located in the parent `simple_crypto` module and re-exported
//! here for convenience. Thus, you're not going to see a lot of functions
//! or macros, here, just the type declarations.
//!
//! To use SHA2-384, as an example, you could run the following code:
//!
//! ```rust
//! use simple_crypto::sha::{Hash,SHA384};
//!
//! let empty: [u8; 0] = [0; 0];
//! let mut digest_incremental = SHA384::new();
//! digest_incremental.update(&empty);
//! digest_incremental.update(&empty);
//! digest_incremental.update(&empty);
//! let result = digest_incremental.finalize();
//!
//! assert_eq!(result, vec![0x38,0xb0,0x60,0xa7,0x51,0xac,0x96,0x38,
//! 0x4c,0xd9,0x32,0x7e,0xb1,0xb1,0xe3,0x6a,
//! 0x21,0xfd,0xb7,0x11,0x14,0xbe,0x07,0x43,
//! 0x4c,0x0c,0xc7,0xbf,0x63,0xf6,0xe1,0xda,
//! 0x27,0x4e,0xde,0xbf,0xe7,0x6f,0x65,0xfb,
//! 0xd5,0x1a,0xd2,0xf1,0x48,0x98,0xb9,0x5b]);
//! ```
//!
//! For other hashes, just substitute the appropriate hash structure for
//! `SHA384`. The `Hash` trait also includes a do-it-all-at-once built-in
//! function for those cases when you just have a single blob of data
//! you want to hash, rather than an incremental set of data:
//!
//! ```rust
//! use simple_crypto::sha::{Hash,SHA3_256};
//!
//! let empty: [u8; 0] = [0; 0];
//! let result = SHA3_256::hash(&empty);
//!
//! assert_eq!(result, vec![0xa7,0xff,0xc6,0xf8,0xbf,0x1e,0xd7,0x66,
//! 0x51,0xc1,0x47,0x56,0xa0,0x61,0xd6,0x62,
//! 0xf5,0x80,0xff,0x4d,0xe4,0x3b,0x49,0xfa,
//! 0x82,0xd8,0x0a,0x4b,0x80,0xf8,0x43,0x4a]);
//! ```
//!
//! In general, you should not use SHA1 for anything but supporting legacy
//! systems. We recommend either SHA2 or SHA3 at their 256-, 384-, or 512-bit
//! sizes. NIST claims (in FIPS 202, page 23-24) that SHA2 and SHA3 are
//! approximately equivalent in terms of security for collision, preimate,
//! and second preimage attacks, but that SHA3 improves upon SHA2 against
//! length-extension and other attacks. On the other hand, SHA2 has been
//! banged on for a little longer, and there's some claims that it's more
//! resistant to quantum attacks. So ... make your own decisions.
#[macro_use]
mod shared;
mod sha1;
mod sha2;
mod sha3;
pub use super::Hash;
pub use self::sha1::SHA1;
pub use self::sha2::{SHA224,SHA256,SHA384,SHA512};
pub use self::sha3::{SHA3_224,SHA3_256,SHA3_384,SHA3_512};
pub(crate) use self::sha3::Keccak;

View File

@@ -1,306 +0,0 @@
use byteorder::{BigEndian,WriteBytesExt};
use super::super::Hash;
use sha::shared::calculate_k;
/// The SHA1 hash. Don't use this except to support legacy systems.
///
/// To use, you can run it in incremental mode -- by calling new(),
/// update() zero or more times, and then finalize() -- or you can
/// just invoke the hash directly. For example:
///
/// ```rust
/// use simple_crypto::sha::{Hash,SHA1};
///
/// let empty = [0; 0];
/// // Do the hash using the incremental API
/// let mut hashf = SHA1::new();
/// hashf.update(&empty);
/// let result_incremental = hashf.finalize();
/// // Do the hash using the direct API
/// let result_direct = SHA1::hash(&empty);
/// // ... and they should be the same
/// assert_eq!(result_incremental,result_direct);
/// ```
#[derive(Clone)]
pub struct SHA1 {
state: [u32; 5],
buffer: Vec<u8>,
done: bool,
l: usize
}
macro_rules! sha1_step {
($op: ident, $out: ident, $ins: expr, $k: expr, $w: ident) => {
let $out = {
let [a,b,c,d,e] = $ins;
let ap = a.rotate_left(5) + $op!(b,c,d) + e + $k + $w;
let bp = a;
let cp = b.rotate_left(30);
let dp = c;
let ep = d;
[ap, bp, cp, dp, ep]
};
};
}
impl SHA1 {
fn process(&mut self, w00: u32, w01: u32, w02: u32, w03: u32,
w04: u32, w05: u32, w06: u32, w07: u32,
w08: u32, w09: u32, w10: u32, w11: u32,
w12: u32, w13: u32, w14: u32, w15: u32)
{
let w16 = (w13 ^ w08 ^ w02 ^ w00).rotate_left(1);
let w17 = (w14 ^ w09 ^ w03 ^ w01).rotate_left(1);
let w18 = (w15 ^ w10 ^ w04 ^ w02).rotate_left(1);
let w19 = (w16 ^ w11 ^ w05 ^ w03).rotate_left(1);
let w20 = (w17 ^ w12 ^ w06 ^ w04).rotate_left(1);
let w21 = (w18 ^ w13 ^ w07 ^ w05).rotate_left(1);
let w22 = (w19 ^ w14 ^ w08 ^ w06).rotate_left(1);
let w23 = (w20 ^ w15 ^ w09 ^ w07).rotate_left(1);
let w24 = (w21 ^ w16 ^ w10 ^ w08).rotate_left(1);
let w25 = (w22 ^ w17 ^ w11 ^ w09).rotate_left(1);
let w26 = (w23 ^ w18 ^ w12 ^ w10).rotate_left(1);
let w27 = (w24 ^ w19 ^ w13 ^ w11).rotate_left(1);
let w28 = (w25 ^ w20 ^ w14 ^ w12).rotate_left(1);
let w29 = (w26 ^ w21 ^ w15 ^ w13).rotate_left(1);
let w30 = (w27 ^ w22 ^ w16 ^ w14).rotate_left(1);
let w31 = (w28 ^ w23 ^ w17 ^ w15).rotate_left(1);
let w32 = (w29 ^ w24 ^ w18 ^ w16).rotate_left(1);
let w33 = (w30 ^ w25 ^ w19 ^ w17).rotate_left(1);
let w34 = (w31 ^ w26 ^ w20 ^ w18).rotate_left(1);
let w35 = (w32 ^ w27 ^ w21 ^ w19).rotate_left(1);
let w36 = (w33 ^ w28 ^ w22 ^ w20).rotate_left(1);
let w37 = (w34 ^ w29 ^ w23 ^ w21).rotate_left(1);
let w38 = (w35 ^ w30 ^ w24 ^ w22).rotate_left(1);
let w39 = (w36 ^ w31 ^ w25 ^ w23).rotate_left(1);
let w40 = (w37 ^ w32 ^ w26 ^ w24).rotate_left(1);
let w41 = (w38 ^ w33 ^ w27 ^ w25).rotate_left(1);
let w42 = (w39 ^ w34 ^ w28 ^ w26).rotate_left(1);
let w43 = (w40 ^ w35 ^ w29 ^ w27).rotate_left(1);
let w44 = (w41 ^ w36 ^ w30 ^ w28).rotate_left(1);
let w45 = (w42 ^ w37 ^ w31 ^ w29).rotate_left(1);
let w46 = (w43 ^ w38 ^ w32 ^ w30).rotate_left(1);
let w47 = (w44 ^ w39 ^ w33 ^ w31).rotate_left(1);
let w48 = (w45 ^ w40 ^ w34 ^ w32).rotate_left(1);
let w49 = (w46 ^ w41 ^ w35 ^ w33).rotate_left(1);
let w50 = (w47 ^ w42 ^ w36 ^ w34).rotate_left(1);
let w51 = (w48 ^ w43 ^ w37 ^ w35).rotate_left(1);
let w52 = (w49 ^ w44 ^ w38 ^ w36).rotate_left(1);
let w53 = (w50 ^ w45 ^ w39 ^ w37).rotate_left(1);
let w54 = (w51 ^ w46 ^ w40 ^ w38).rotate_left(1);
let w55 = (w52 ^ w47 ^ w41 ^ w39).rotate_left(1);
let w56 = (w53 ^ w48 ^ w42 ^ w40).rotate_left(1);
let w57 = (w54 ^ w49 ^ w43 ^ w41).rotate_left(1);
let w58 = (w55 ^ w50 ^ w44 ^ w42).rotate_left(1);
let w59 = (w56 ^ w51 ^ w45 ^ w43).rotate_left(1);
let w60 = (w57 ^ w52 ^ w46 ^ w44).rotate_left(1);
let w61 = (w58 ^ w53 ^ w47 ^ w45).rotate_left(1);
let w62 = (w59 ^ w54 ^ w48 ^ w46).rotate_left(1);
let w63 = (w60 ^ w55 ^ w49 ^ w47).rotate_left(1);
let w64 = (w61 ^ w56 ^ w50 ^ w48).rotate_left(1);
let w65 = (w62 ^ w57 ^ w51 ^ w49).rotate_left(1);
let w66 = (w63 ^ w58 ^ w52 ^ w50).rotate_left(1);
let w67 = (w64 ^ w59 ^ w53 ^ w51).rotate_left(1);
let w68 = (w65 ^ w60 ^ w54 ^ w52).rotate_left(1);
let w69 = (w66 ^ w61 ^ w55 ^ w53).rotate_left(1);
let w70 = (w67 ^ w62 ^ w56 ^ w54).rotate_left(1);
let w71 = (w68 ^ w63 ^ w57 ^ w55).rotate_left(1);
let w72 = (w69 ^ w64 ^ w58 ^ w56).rotate_left(1);
let w73 = (w70 ^ w65 ^ w59 ^ w57).rotate_left(1);
let w74 = (w71 ^ w66 ^ w60 ^ w58).rotate_left(1);
let w75 = (w72 ^ w67 ^ w61 ^ w59).rotate_left(1);
let w76 = (w73 ^ w68 ^ w62 ^ w60).rotate_left(1);
let w77 = (w74 ^ w69 ^ w63 ^ w61).rotate_left(1);
let w78 = (w75 ^ w70 ^ w64 ^ w62).rotate_left(1);
let w79 = (w76 ^ w71 ^ w65 ^ w63).rotate_left(1);
sha1_step!(ch, s01, self.state, 0x5a827999, w00);
sha1_step!(ch, s02, s01, 0x5a827999, w01);
sha1_step!(ch, s03, s02, 0x5a827999, w02);
sha1_step!(ch, s04, s03, 0x5a827999, w03);
sha1_step!(ch, s05, s04, 0x5a827999, w04);
sha1_step!(ch, s06, s05, 0x5a827999, w05);
sha1_step!(ch, s07, s06, 0x5a827999, w06);
sha1_step!(ch, s08, s07, 0x5a827999, w07);
sha1_step!(ch, s09, s08, 0x5a827999, w08);
sha1_step!(ch, s10, s09, 0x5a827999, w09);
sha1_step!(ch, s11, s10, 0x5a827999, w10);
sha1_step!(ch, s12, s11, 0x5a827999, w11);
sha1_step!(ch, s13, s12, 0x5a827999, w12);
sha1_step!(ch, s14, s13, 0x5a827999, w13);
sha1_step!(ch, s15, s14, 0x5a827999, w14);
sha1_step!(ch, s16, s15, 0x5a827999, w15);
sha1_step!(ch, s17, s16, 0x5a827999, w16);
sha1_step!(ch, s18, s17, 0x5a827999, w17);
sha1_step!(ch, s19, s18, 0x5a827999, w18);
sha1_step!(ch, s20, s19, 0x5a827999, w19);
sha1_step!(parity, s21, s20, 0x6ed9eba1, w20);
sha1_step!(parity, s22, s21, 0x6ed9eba1, w21);
sha1_step!(parity, s23, s22, 0x6ed9eba1, w22);
sha1_step!(parity, s24, s23, 0x6ed9eba1, w23);
sha1_step!(parity, s25, s24, 0x6ed9eba1, w24);
sha1_step!(parity, s26, s25, 0x6ed9eba1, w25);
sha1_step!(parity, s27, s26, 0x6ed9eba1, w26);
sha1_step!(parity, s28, s27, 0x6ed9eba1, w27);
sha1_step!(parity, s29, s28, 0x6ed9eba1, w28);
sha1_step!(parity, s30, s29, 0x6ed9eba1, w29);
sha1_step!(parity, s31, s30, 0x6ed9eba1, w30);
sha1_step!(parity, s32, s31, 0x6ed9eba1, w31);
sha1_step!(parity, s33, s32, 0x6ed9eba1, w32);
sha1_step!(parity, s34, s33, 0x6ed9eba1, w33);
sha1_step!(parity, s35, s34, 0x6ed9eba1, w34);
sha1_step!(parity, s36, s35, 0x6ed9eba1, w35);
sha1_step!(parity, s37, s36, 0x6ed9eba1, w36);
sha1_step!(parity, s38, s37, 0x6ed9eba1, w37);
sha1_step!(parity, s39, s38, 0x6ed9eba1, w38);
sha1_step!(parity, s40, s39, 0x6ed9eba1, w39);
sha1_step!(maj, s41, s40, 0x8f1bbcdc, w40);
sha1_step!(maj, s42, s41, 0x8f1bbcdc, w41);
sha1_step!(maj, s43, s42, 0x8f1bbcdc, w42);
sha1_step!(maj, s44, s43, 0x8f1bbcdc, w43);
sha1_step!(maj, s45, s44, 0x8f1bbcdc, w44);
sha1_step!(maj, s46, s45, 0x8f1bbcdc, w45);
sha1_step!(maj, s47, s46, 0x8f1bbcdc, w46);
sha1_step!(maj, s48, s47, 0x8f1bbcdc, w47);
sha1_step!(maj, s49, s48, 0x8f1bbcdc, w48);
sha1_step!(maj, s50, s49, 0x8f1bbcdc, w49);
sha1_step!(maj, s51, s50, 0x8f1bbcdc, w50);
sha1_step!(maj, s52, s51, 0x8f1bbcdc, w51);
sha1_step!(maj, s53, s52, 0x8f1bbcdc, w52);
sha1_step!(maj, s54, s53, 0x8f1bbcdc, w53);
sha1_step!(maj, s55, s54, 0x8f1bbcdc, w54);
sha1_step!(maj, s56, s55, 0x8f1bbcdc, w55);
sha1_step!(maj, s57, s56, 0x8f1bbcdc, w56);
sha1_step!(maj, s58, s57, 0x8f1bbcdc, w57);
sha1_step!(maj, s59, s58, 0x8f1bbcdc, w58);
sha1_step!(maj, s60, s59, 0x8f1bbcdc, w59);
sha1_step!(parity, s61, s60, 0xca62c1d6, w60);
sha1_step!(parity, s62, s61, 0xca62c1d6, w61);
sha1_step!(parity, s63, s62, 0xca62c1d6, w62);
sha1_step!(parity, s64, s63, 0xca62c1d6, w63);
sha1_step!(parity, s65, s64, 0xca62c1d6, w64);
sha1_step!(parity, s66, s65, 0xca62c1d6, w65);
sha1_step!(parity, s67, s66, 0xca62c1d6, w66);
sha1_step!(parity, s68, s67, 0xca62c1d6, w67);
sha1_step!(parity, s69, s68, 0xca62c1d6, w68);
sha1_step!(parity, s70, s69, 0xca62c1d6, w69);
sha1_step!(parity, s71, s70, 0xca62c1d6, w70);
sha1_step!(parity, s72, s71, 0xca62c1d6, w71);
sha1_step!(parity, s73, s72, 0xca62c1d6, w72);
sha1_step!(parity, s74, s73, 0xca62c1d6, w73);
sha1_step!(parity, s75, s74, 0xca62c1d6, w74);
sha1_step!(parity, s76, s75, 0xca62c1d6, w75);
sha1_step!(parity, s77, s76, 0xca62c1d6, w76);
sha1_step!(parity, s78, s77, 0xca62c1d6, w77);
sha1_step!(parity, s79, s78, 0xca62c1d6, w78);
sha1_step!(parity, s80, s79, 0xca62c1d6, w79);
self.state[0] += s80[0];
self.state[1] += s80[1];
self.state[2] += s80[2];
self.state[3] += s80[3];
self.state[4] += s80[4];
}
fn finish(&mut self)
{
let bitlen = self.l * 8;
let k = calculate_k(448, 512, bitlen);
// INVARIANT: k is necessarily > 0, and (k + 1) is a multiple of 8
let bytes_to_add = (k + 1) / 8;
let mut padvec = Vec::with_capacity(bytes_to_add + 8);
padvec.push(0x80); // Set the high bit, since the first bit after the data
// should be set
padvec.resize(bytes_to_add, 0);
padvec.write_u64::<BigEndian>(bitlen as u64).expect("Broken writing value to pre-allocated Vec?");
self.update(&padvec);
self.done = true;
assert_eq!(self.buffer.len(), 0);
}
}
impl Hash for SHA1
{
fn new() -> SHA1
{
SHA1 {
state: [ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 ],
buffer: Vec::with_capacity(64),
done: false,
l: 0
}
}
fn update(&mut self, block: &[u8])
{
if !self.done {
let mut offset = 0;
self.l += block.len();
if self.buffer.len() + block.len() < 64 {
self.buffer.extend_from_slice(block);
return;
}
if self.buffer.len() > 0 {
// We must be able to build up a 64 byte chunk, at this point, otherwise
// the math above would've been wrong.
while self.buffer.len() < 64 {
self.buffer.push(block[offset]);
offset += 1;
}
process_u32_block!(self.buffer, 0, self);
// Reset the buffer now, we're done with that nonsense for the moment
self.buffer.resize(0,0);
}
while (offset + 64) <= block.len() {
process_u32_block!(block, offset, self);
offset += 64;
}
if offset < block.len() {
self.buffer.extend_from_slice(&block[offset..]);
}
}
}
fn finalize(&mut self) -> Vec<u8>
{
if !self.done {
self.finish();
}
let mut output = Vec::with_capacity(20);
output.write_u32::<BigEndian>(self.state[0]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state[1]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state[2]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state[3]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state[4]).expect("Broken writing value to pre-allocated Vec?");
output
}
fn block_size() -> usize
{
512
}
}
#[cfg(test)]
use testing::run_test;
#[cfg(test)]
#[test]
fn nist() {
let fname = "testdata/sha/nist_sha1.test";
run_test(fname.to_string(), 3, |case| {
let (negl, lbytes) = case.get("l").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
assert!(!negl && !negm && !negd);
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
let digest = SHA1::hash(&msg);
assert_eq!(dbytes, &digest);
});
}

View File

@@ -1,842 +0,0 @@
use byteorder::{BigEndian,ByteOrder,WriteBytesExt};
use sha::shared::calculate_k;
use super::super::Hash;
/// The SHA2-224 hash.
///
/// To use, you can run it in incremental mode -- by calling new(),
/// update() zero or more times, and then finalize() -- or you can
/// just invoke the hash directly. For example:
///
/// ```rust
/// use simple_crypto::sha::{Hash,SHA224};
///
/// let empty = [0; 0];
/// // Do the hash using the incremental API
/// let mut hashf = SHA224::new();
/// hashf.update(&empty);
/// let result_incremental = hashf.finalize();
/// // Do the hash using the direct API
/// let result_direct = SHA224::hash(&empty);
/// // ... and they should be the same
/// assert_eq!(result_incremental,result_direct);
/// ```
#[derive(Clone)]
pub struct SHA224 {
state: SHA256State
}
impl Hash for SHA224 {
fn new() -> Self
{
let state = SHA256State::new([0xc1059ed8,0x367cd507,0x3070dd17,0xf70e5939,
0xffc00b31,0x68581511,0x64f98fa7,0xbefa4fa4]);
SHA224{ state }
}
fn update(&mut self, data: &[u8])
{
self.state.update(data);
}
fn finalize(&mut self) -> Vec<u8>
{
if !self.state.done {
self.state.finish();
}
let mut output = Vec::with_capacity(28);
output.write_u32::<BigEndian>(self.state.state[0]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state.state[1]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state.state[2]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state.state[3]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state.state[4]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state.state[5]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state.state[6]).expect("Broken writing value to pre-allocated Vec?");
output
}
fn block_size() -> usize
{
512
}
}
/// The SHA2-256 hash. [GOOD]
///
/// To use, you can run it in incremental mode -- by calling new(),
/// update() zero or more times, and then finalize() -- or you can
/// just invoke the hash directly. For example:
///
/// ```rust
/// use simple_crypto::sha::{Hash,SHA256};
///
/// let empty = [0; 0];
/// // Do the hash using the incremental API
/// let mut hashf = SHA256::new();
/// hashf.update(&empty);
/// let result_incremental = hashf.finalize();
/// // Do the hash using the direct API
/// let result_direct = SHA256::hash(&empty);
/// // ... and they should be the same
/// assert_eq!(result_incremental,result_direct);
/// ```
#[derive(Clone)]
pub struct SHA256 {
state: SHA256State
}
impl Hash for SHA256 {
fn new() -> Self
{
let state = SHA256State::new([0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,
0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19]);
SHA256{ state }
}
fn update(&mut self, data: &[u8])
{
self.state.update(data);
}
fn finalize(&mut self) -> Vec<u8>
{
if !self.state.done {
self.state.finish();
}
let mut output = Vec::with_capacity(28);
output.write_u32::<BigEndian>(self.state.state[0]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state.state[1]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state.state[2]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state.state[3]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state.state[4]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state.state[5]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state.state[6]).expect("Broken writing value to pre-allocated Vec?");
output.write_u32::<BigEndian>(self.state.state[7]).expect("Broken writing value to pre-allocated Vec?");
output
}
fn block_size() -> usize
{
512
}
}
/// The SHA2-384 hash. [BETTER]
///
/// To use, you can run it in incremental mode -- by calling new(),
/// update() zero or more times, and then finalize() -- or you can
/// just invoke the hash directly. For example:
///
/// ```rust
/// use simple_crypto::sha::{Hash,SHA384};
///
/// let empty = [0; 0];
/// // Do the hash using the incremental API
/// let mut hashf = SHA384::new();
/// hashf.update(&empty);
/// let result_incremental = hashf.finalize();
/// // Do the hash using the direct API
/// let result_direct = SHA384::hash(&empty);
/// // ... and they should be the same
/// assert_eq!(result_incremental,result_direct);
/// ```
#[derive(Clone)]
pub struct SHA384 {
state: SHA512State
}
impl Hash for SHA384 {
fn new() -> Self
{
let state = SHA512State::new([0xcbbb9d5dc1059ed8,0x629a292a367cd507,
0x9159015a3070dd17,0x152fecd8f70e5939,
0x67332667ffc00b31,0x8eb44a8768581511,
0xdb0c2e0d64f98fa7,0x47b5481dbefa4fa4]);
SHA384{ state }
}
fn update(&mut self, data: &[u8])
{
self.state.update(data);
}
fn finalize(&mut self) -> Vec<u8>
{
if !self.state.done {
self.state.finish();
}
let mut output = Vec::with_capacity(64);
output.write_u64::<BigEndian>(self.state.state[0]).expect("Broken writing value to pre-allocated Vec?");
output.write_u64::<BigEndian>(self.state.state[1]).expect("Broken writing value to pre-allocated Vec?");
output.write_u64::<BigEndian>(self.state.state[2]).expect("Broken writing value to pre-allocated Vec?");
output.write_u64::<BigEndian>(self.state.state[3]).expect("Broken writing value to pre-allocated Vec?");
output.write_u64::<BigEndian>(self.state.state[4]).expect("Broken writing value to pre-allocated Vec?");
output.write_u64::<BigEndian>(self.state.state[5]).expect("Broken writing value to pre-allocated Vec?");
output
}
fn block_size() -> usize
{
1024
}
}
/// The SHA2-512 hash. [BEST]
///
/// To use, you can run it in incremental mode -- by calling new(),
/// update() zero or more times, and then finalize() -- or you can
/// just invoke the hash directly. For example:
///
/// ```rust
/// use simple_crypto::sha::{Hash,SHA512};
///
/// let empty = [0; 0];
/// // Do the hash using the incremental API
/// let mut hashf = SHA512::new();
/// hashf.update(&empty);
/// let result_incremental = hashf.finalize();
/// // Do the hash using the direct API
/// let result_direct = SHA512::hash(&empty);
/// // ... and they should be the same
/// assert_eq!(result_incremental,result_direct);
/// ```
#[derive(Clone)]
pub struct SHA512 {
state: SHA512State
}
impl Hash for SHA512 {
fn new() -> Self
{
let state = SHA512State::new([0x6a09e667f3bcc908,0xbb67ae8584caa73b,
0x3c6ef372fe94f82b,0xa54ff53a5f1d36f1,
0x510e527fade682d1,0x9b05688c2b3e6c1f,
0x1f83d9abfb41bd6b,0x5be0cd19137e2179]);
SHA512{ state }
}
fn update(&mut self, data: &[u8])
{
self.state.update(data);
}
fn finalize(&mut self) -> Vec<u8>
{
if !self.state.done {
self.state.finish();
}
let mut output = Vec::with_capacity(64);
output.write_u64::<BigEndian>(self.state.state[0]).expect("Broken writing value to pre-allocated Vec?");
output.write_u64::<BigEndian>(self.state.state[1]).expect("Broken writing value to pre-allocated Vec?");
output.write_u64::<BigEndian>(self.state.state[2]).expect("Broken writing value to pre-allocated Vec?");
output.write_u64::<BigEndian>(self.state.state[3]).expect("Broken writing value to pre-allocated Vec?");
output.write_u64::<BigEndian>(self.state.state[4]).expect("Broken writing value to pre-allocated Vec?");
output.write_u64::<BigEndian>(self.state.state[5]).expect("Broken writing value to pre-allocated Vec?");
output.write_u64::<BigEndian>(self.state.state[6]).expect("Broken writing value to pre-allocated Vec?");
output.write_u64::<BigEndian>(self.state.state[7]).expect("Broken writing value to pre-allocated Vec?");
output
}
fn block_size() -> usize
{
1024
}
}
macro_rules! bsig256_0 {
($x: ident) => {
$x.rotate_right(2) ^ $x.rotate_right(13) ^ $x.rotate_right(22)
};
}
macro_rules! bsig256_1 {
($x: ident) => {
$x.rotate_right(6) ^ $x.rotate_right(11) ^ $x.rotate_right(25)
};
}
macro_rules! lsig256_0 {
($x: ident) => {
$x.rotate_right(7) ^ $x.rotate_right(18) ^ ($x >> 3)
};
}
macro_rules! lsig256_1 {
($x: ident) => {
$x.rotate_right(17) ^ $x.rotate_right(19) ^ ($x >> 10)
};
}
#[derive(Clone)]
struct SHA256State {
state: [u32; 8],
buffer: Vec<u8>,
done: bool,
l: usize
}
impl SHA256State {
fn new(values: [u32; 8]) -> Self {
SHA256State {
state: values,
buffer: Vec::with_capacity(64),
done: false,
l: 0,
}
}
fn process(&mut self, w00: u32, w01: u32, w02: u32, w03: u32,
w04: u32, w05: u32, w06: u32, w07: u32,
w08: u32, w09: u32, w10: u32, w11: u32,
w12: u32, w13: u32, w14: u32, w15: u32)
{
let w16 = lsig256_1!(w14) + w09 + lsig256_0!(w01) + w00;
let w17 = lsig256_1!(w15) + w10 + lsig256_0!(w02) + w01;
let w18 = lsig256_1!(w16) + w11 + lsig256_0!(w03) + w02;
let w19 = lsig256_1!(w17) + w12 + lsig256_0!(w04) + w03;
let w20 = lsig256_1!(w18) + w13 + lsig256_0!(w05) + w04;
let w21 = lsig256_1!(w19) + w14 + lsig256_0!(w06) + w05;
let w22 = lsig256_1!(w20) + w15 + lsig256_0!(w07) + w06;
let w23 = lsig256_1!(w21) + w16 + lsig256_0!(w08) + w07;
let w24 = lsig256_1!(w22) + w17 + lsig256_0!(w09) + w08;
let w25 = lsig256_1!(w23) + w18 + lsig256_0!(w10) + w09;
let w26 = lsig256_1!(w24) + w19 + lsig256_0!(w11) + w10;
let w27 = lsig256_1!(w25) + w20 + lsig256_0!(w12) + w11;
let w28 = lsig256_1!(w26) + w21 + lsig256_0!(w13) + w12;
let w29 = lsig256_1!(w27) + w22 + lsig256_0!(w14) + w13;
let w30 = lsig256_1!(w28) + w23 + lsig256_0!(w15) + w14;
let w31 = lsig256_1!(w29) + w24 + lsig256_0!(w16) + w15;
let w32 = lsig256_1!(w30) + w25 + lsig256_0!(w17) + w16;
let w33 = lsig256_1!(w31) + w26 + lsig256_0!(w18) + w17;
let w34 = lsig256_1!(w32) + w27 + lsig256_0!(w19) + w18;
let w35 = lsig256_1!(w33) + w28 + lsig256_0!(w20) + w19;
let w36 = lsig256_1!(w34) + w29 + lsig256_0!(w21) + w20;
let w37 = lsig256_1!(w35) + w30 + lsig256_0!(w22) + w21;
let w38 = lsig256_1!(w36) + w31 + lsig256_0!(w23) + w22;
let w39 = lsig256_1!(w37) + w32 + lsig256_0!(w24) + w23;
let w40 = lsig256_1!(w38) + w33 + lsig256_0!(w25) + w24;
let w41 = lsig256_1!(w39) + w34 + lsig256_0!(w26) + w25;
let w42 = lsig256_1!(w40) + w35 + lsig256_0!(w27) + w26;
let w43 = lsig256_1!(w41) + w36 + lsig256_0!(w28) + w27;
let w44 = lsig256_1!(w42) + w37 + lsig256_0!(w29) + w28;
let w45 = lsig256_1!(w43) + w38 + lsig256_0!(w30) + w29;
let w46 = lsig256_1!(w44) + w39 + lsig256_0!(w31) + w30;
let w47 = lsig256_1!(w45) + w40 + lsig256_0!(w32) + w31;
let w48 = lsig256_1!(w46) + w41 + lsig256_0!(w33) + w32;
let w49 = lsig256_1!(w47) + w42 + lsig256_0!(w34) + w33;
let w50 = lsig256_1!(w48) + w43 + lsig256_0!(w35) + w34;
let w51 = lsig256_1!(w49) + w44 + lsig256_0!(w36) + w35;
let w52 = lsig256_1!(w50) + w45 + lsig256_0!(w37) + w36;
let w53 = lsig256_1!(w51) + w46 + lsig256_0!(w38) + w37;
let w54 = lsig256_1!(w52) + w47 + lsig256_0!(w39) + w38;
let w55 = lsig256_1!(w53) + w48 + lsig256_0!(w40) + w39;
let w56 = lsig256_1!(w54) + w49 + lsig256_0!(w41) + w40;
let w57 = lsig256_1!(w55) + w50 + lsig256_0!(w42) + w41;
let w58 = lsig256_1!(w56) + w51 + lsig256_0!(w43) + w42;
let w59 = lsig256_1!(w57) + w52 + lsig256_0!(w44) + w43;
let w60 = lsig256_1!(w58) + w53 + lsig256_0!(w45) + w44;
let w61 = lsig256_1!(w59) + w54 + lsig256_0!(w46) + w45;
let w62 = lsig256_1!(w60) + w55 + lsig256_0!(w47) + w46;
let w63 = lsig256_1!(w61) + w56 + lsig256_0!(w48) + w47;
let s01 = step256(self.state,0x428a2f98,w00);
let s02 = step256(s01,0x71374491,w01);
let s03 = step256(s02,0xb5c0fbcf,w02);
let s04 = step256(s03,0xe9b5dba5,w03);
let s05 = step256(s04,0x3956c25b,w04);
let s06 = step256(s05,0x59f111f1,w05);
let s07 = step256(s06,0x923f82a4,w06);
let s08 = step256(s07,0xab1c5ed5,w07);
let s09 = step256(s08,0xd807aa98,w08);
let s10 = step256(s09,0x12835b01,w09);
let s11 = step256(s10,0x243185be,w10);
let s12 = step256(s11,0x550c7dc3,w11);
let s13 = step256(s12,0x72be5d74,w12);
let s14 = step256(s13,0x80deb1fe,w13);
let s15 = step256(s14,0x9bdc06a7,w14);
let s16 = step256(s15,0xc19bf174,w15);
let s17 = step256(s16,0xe49b69c1,w16);
let s18 = step256(s17,0xefbe4786,w17);
let s19 = step256(s18,0x0fc19dc6,w18);
let s20 = step256(s19,0x240ca1cc,w19);
let s21 = step256(s20,0x2de92c6f,w20);
let s22 = step256(s21,0x4a7484aa,w21);
let s23 = step256(s22,0x5cb0a9dc,w22);
let s24 = step256(s23,0x76f988da,w23);
let s25 = step256(s24,0x983e5152,w24);
let s26 = step256(s25,0xa831c66d,w25);
let s27 = step256(s26,0xb00327c8,w26);
let s28 = step256(s27,0xbf597fc7,w27);
let s29 = step256(s28,0xc6e00bf3,w28);
let s30 = step256(s29,0xd5a79147,w29);
let s31 = step256(s30,0x06ca6351,w30);
let s32 = step256(s31,0x14292967,w31);
let s33 = step256(s32,0x27b70a85,w32);
let s34 = step256(s33,0x2e1b2138,w33);
let s35 = step256(s34,0x4d2c6dfc,w34);
let s36 = step256(s35,0x53380d13,w35);
let s37 = step256(s36,0x650a7354,w36);
let s38 = step256(s37,0x766a0abb,w37);
let s39 = step256(s38,0x81c2c92e,w38);
let s40 = step256(s39,0x92722c85,w39);
let s41 = step256(s40,0xa2bfe8a1,w40);
let s42 = step256(s41,0xa81a664b,w41);
let s43 = step256(s42,0xc24b8b70,w42);
let s44 = step256(s43,0xc76c51a3,w43);
let s45 = step256(s44,0xd192e819,w44);
let s46 = step256(s45,0xd6990624,w45);
let s47 = step256(s46,0xf40e3585,w46);
let s48 = step256(s47,0x106aa070,w47);
let s49 = step256(s48,0x19a4c116,w48);
let s50 = step256(s49,0x1e376c08,w49);
let s51 = step256(s50,0x2748774c,w50);
let s52 = step256(s51,0x34b0bcb5,w51);
let s53 = step256(s52,0x391c0cb3,w52);
let s54 = step256(s53,0x4ed8aa4a,w53);
let s55 = step256(s54,0x5b9cca4f,w54);
let s56 = step256(s55,0x682e6ff3,w55);
let s57 = step256(s56,0x748f82ee,w56);
let s58 = step256(s57,0x78a5636f,w57);
let s59 = step256(s58,0x84c87814,w58);
let s60 = step256(s59,0x8cc70208,w59);
let s61 = step256(s60,0x90befffa,w60);
let s62 = step256(s61,0xa4506ceb,w61);
let s63 = step256(s62,0xbef9a3f7,w62);
let s64 = step256(s63,0xc67178f2,w63);
self.state[0] += s64[0];
self.state[1] += s64[1];
self.state[2] += s64[2];
self.state[3] += s64[3];
self.state[4] += s64[4];
self.state[5] += s64[5];
self.state[6] += s64[6];
self.state[7] += s64[7];
}
fn update(&mut self, block: &[u8]) {
if !self.done {
let mut offset = 0;
self.l += block.len();
if self.buffer.len() + block.len() < 64 {
self.buffer.extend_from_slice(block);
return;
}
if self.buffer.len() > 0 {
// We must be able to build up a 64 byte chunk, at this point, otherwise
// the math above would've been wrong.
while self.buffer.len() < 64 {
self.buffer.push(block[offset]);
offset += 1;
}
process_u32_block!(self.buffer, 0, self);
// Reset the buffer now, we're done with that nonsense for the moment
self.buffer.resize(0,0);
}
while (offset + 64) <= block.len() {
process_u32_block!(block, offset, self);
offset += 64;
}
if offset < block.len() {
self.buffer.extend_from_slice(&block[offset..]);
}
}
}
fn finish(&mut self) {
let bitlen = self.l * 8;
let k = calculate_k(448, 512, bitlen);
// INVARIANT: k is necessarily > 0, and (k + 1) is a multiple of 8
let bytes_to_add = (k + 1) / 8;
let mut padvec = Vec::with_capacity(bytes_to_add + 8);
padvec.push(0x80); // Set the high bit, since the first bit after the data
// should be set
padvec.resize(bytes_to_add, 0);
padvec.write_u64::<BigEndian>(bitlen as u64).expect("Broken writing value to pre-allocated Vec?");
self.update(&padvec);
self.done = true;
assert_eq!(self.buffer.len(), 0);
}
}
#[inline(always)]
fn step256(state0: [u32; 8], k: u32, w: u32) -> [u32; 8]
{
let [a,b,c,d,e,f,g,h] = state0;
let t1 = h + bsig256_1!(e) + ch!(e,f,g) + k + w;
let t2 = bsig256_0!(a) + maj!(a,b,c);
let hp = g;
let gp = f;
let fp = e;
let ep = d + t1;
let dp = c;
let cp = b;
let bp = a;
let ap = t1 + t2;
[ap,bp,cp,dp,ep,fp,gp,hp]
}
macro_rules! bsig512_0 {
($x: ident) => {
$x.rotate_right(28) ^ $x.rotate_right(34) ^ $x.rotate_right(39)
};
}
macro_rules! bsig512_1 {
($x: ident) => {
$x.rotate_right(14) ^ $x.rotate_right(18) ^ $x.rotate_right(41)
};
}
macro_rules! lsig512_0 {
($x: ident) => {
$x.rotate_right(1) ^ $x.rotate_right(8) ^ ($x >> 7)
};
}
macro_rules! lsig512_1 {
($x: ident) => {
$x.rotate_right(19) ^ $x.rotate_right(61) ^ ($x >> 6)
};
}
macro_rules! process_u64_block {
($buf: expr, $off: expr, $self: ident) => {{
let w00 = BigEndian::read_u64(&$buf[$off+0..]);
let w01 = BigEndian::read_u64(&$buf[$off+8..]);
let w02 = BigEndian::read_u64(&$buf[$off+16..]);
let w03 = BigEndian::read_u64(&$buf[$off+24..]);
let w04 = BigEndian::read_u64(&$buf[$off+32..]);
let w05 = BigEndian::read_u64(&$buf[$off+40..]);
let w06 = BigEndian::read_u64(&$buf[$off+48..]);
let w07 = BigEndian::read_u64(&$buf[$off+56..]);
let w08 = BigEndian::read_u64(&$buf[$off+64..]);
let w09 = BigEndian::read_u64(&$buf[$off+72..]);
let w10 = BigEndian::read_u64(&$buf[$off+80..]);
let w11 = BigEndian::read_u64(&$buf[$off+88..]);
let w12 = BigEndian::read_u64(&$buf[$off+96..]);
let w13 = BigEndian::read_u64(&$buf[$off+104..]);
let w14 = BigEndian::read_u64(&$buf[$off+112..]);
let w15 = BigEndian::read_u64(&$buf[$off+120..]);
$self.process(w00, w01, w02, w03, w04, w05, w06, w07,
w08, w09, w10, w11, w12, w13, w14, w15);
}};
}
#[derive(Clone)]
struct SHA512State {
state: [u64; 8],
buffer: Vec<u8>,
done: bool,
l: usize
}
impl SHA512State {
fn new(values: [u64; 8]) -> Self {
SHA512State {
state: values,
buffer: Vec::with_capacity(128),
done: false,
l: 0,
}
}
fn process(&mut self, w00: u64, w01: u64, w02: u64, w03: u64,
w04: u64, w05: u64, w06: u64, w07: u64,
w08: u64, w09: u64, w10: u64, w11: u64,
w12: u64, w13: u64, w14: u64, w15: u64)
{
let w16 = lsig512_1!(w14) + w09 + lsig512_0!(w01) + w00;
let w17 = lsig512_1!(w15) + w10 + lsig512_0!(w02) + w01;
let w18 = lsig512_1!(w16) + w11 + lsig512_0!(w03) + w02;
let w19 = lsig512_1!(w17) + w12 + lsig512_0!(w04) + w03;
let w20 = lsig512_1!(w18) + w13 + lsig512_0!(w05) + w04;
let w21 = lsig512_1!(w19) + w14 + lsig512_0!(w06) + w05;
let w22 = lsig512_1!(w20) + w15 + lsig512_0!(w07) + w06;
let w23 = lsig512_1!(w21) + w16 + lsig512_0!(w08) + w07;
let w24 = lsig512_1!(w22) + w17 + lsig512_0!(w09) + w08;
let w25 = lsig512_1!(w23) + w18 + lsig512_0!(w10) + w09;
let w26 = lsig512_1!(w24) + w19 + lsig512_0!(w11) + w10;
let w27 = lsig512_1!(w25) + w20 + lsig512_0!(w12) + w11;
let w28 = lsig512_1!(w26) + w21 + lsig512_0!(w13) + w12;
let w29 = lsig512_1!(w27) + w22 + lsig512_0!(w14) + w13;
let w30 = lsig512_1!(w28) + w23 + lsig512_0!(w15) + w14;
let w31 = lsig512_1!(w29) + w24 + lsig512_0!(w16) + w15;
let w32 = lsig512_1!(w30) + w25 + lsig512_0!(w17) + w16;
let w33 = lsig512_1!(w31) + w26 + lsig512_0!(w18) + w17;
let w34 = lsig512_1!(w32) + w27 + lsig512_0!(w19) + w18;
let w35 = lsig512_1!(w33) + w28 + lsig512_0!(w20) + w19;
let w36 = lsig512_1!(w34) + w29 + lsig512_0!(w21) + w20;
let w37 = lsig512_1!(w35) + w30 + lsig512_0!(w22) + w21;
let w38 = lsig512_1!(w36) + w31 + lsig512_0!(w23) + w22;
let w39 = lsig512_1!(w37) + w32 + lsig512_0!(w24) + w23;
let w40 = lsig512_1!(w38) + w33 + lsig512_0!(w25) + w24;
let w41 = lsig512_1!(w39) + w34 + lsig512_0!(w26) + w25;
let w42 = lsig512_1!(w40) + w35 + lsig512_0!(w27) + w26;
let w43 = lsig512_1!(w41) + w36 + lsig512_0!(w28) + w27;
let w44 = lsig512_1!(w42) + w37 + lsig512_0!(w29) + w28;
let w45 = lsig512_1!(w43) + w38 + lsig512_0!(w30) + w29;
let w46 = lsig512_1!(w44) + w39 + lsig512_0!(w31) + w30;
let w47 = lsig512_1!(w45) + w40 + lsig512_0!(w32) + w31;
let w48 = lsig512_1!(w46) + w41 + lsig512_0!(w33) + w32;
let w49 = lsig512_1!(w47) + w42 + lsig512_0!(w34) + w33;
let w50 = lsig512_1!(w48) + w43 + lsig512_0!(w35) + w34;
let w51 = lsig512_1!(w49) + w44 + lsig512_0!(w36) + w35;
let w52 = lsig512_1!(w50) + w45 + lsig512_0!(w37) + w36;
let w53 = lsig512_1!(w51) + w46 + lsig512_0!(w38) + w37;
let w54 = lsig512_1!(w52) + w47 + lsig512_0!(w39) + w38;
let w55 = lsig512_1!(w53) + w48 + lsig512_0!(w40) + w39;
let w56 = lsig512_1!(w54) + w49 + lsig512_0!(w41) + w40;
let w57 = lsig512_1!(w55) + w50 + lsig512_0!(w42) + w41;
let w58 = lsig512_1!(w56) + w51 + lsig512_0!(w43) + w42;
let w59 = lsig512_1!(w57) + w52 + lsig512_0!(w44) + w43;
let w60 = lsig512_1!(w58) + w53 + lsig512_0!(w45) + w44;
let w61 = lsig512_1!(w59) + w54 + lsig512_0!(w46) + w45;
let w62 = lsig512_1!(w60) + w55 + lsig512_0!(w47) + w46;
let w63 = lsig512_1!(w61) + w56 + lsig512_0!(w48) + w47;
let w64 = lsig512_1!(w62) + w57 + lsig512_0!(w49) + w48;
let w65 = lsig512_1!(w63) + w58 + lsig512_0!(w50) + w49;
let w66 = lsig512_1!(w64) + w59 + lsig512_0!(w51) + w50;
let w67 = lsig512_1!(w65) + w60 + lsig512_0!(w52) + w51;
let w68 = lsig512_1!(w66) + w61 + lsig512_0!(w53) + w52;
let w69 = lsig512_1!(w67) + w62 + lsig512_0!(w54) + w53;
let w70 = lsig512_1!(w68) + w63 + lsig512_0!(w55) + w54;
let w71 = lsig512_1!(w69) + w64 + lsig512_0!(w56) + w55;
let w72 = lsig512_1!(w70) + w65 + lsig512_0!(w57) + w56;
let w73 = lsig512_1!(w71) + w66 + lsig512_0!(w58) + w57;
let w74 = lsig512_1!(w72) + w67 + lsig512_0!(w59) + w58;
let w75 = lsig512_1!(w73) + w68 + lsig512_0!(w60) + w59;
let w76 = lsig512_1!(w74) + w69 + lsig512_0!(w61) + w60;
let w77 = lsig512_1!(w75) + w70 + lsig512_0!(w62) + w61;
let w78 = lsig512_1!(w76) + w71 + lsig512_0!(w63) + w62;
let w79 = lsig512_1!(w77) + w72 + lsig512_0!(w64) + w63;
let s01 = step512(self.state,0x428a2f98d728ae22,w00);
let s02 = step512(s01,0x7137449123ef65cd,w01);
let s03 = step512(s02,0xb5c0fbcfec4d3b2f,w02);
let s04 = step512(s03,0xe9b5dba58189dbbc,w03);
let s05 = step512(s04,0x3956c25bf348b538,w04);
let s06 = step512(s05,0x59f111f1b605d019,w05);
let s07 = step512(s06,0x923f82a4af194f9b,w06);
let s08 = step512(s07,0xab1c5ed5da6d8118,w07);
let s09 = step512(s08,0xd807aa98a3030242,w08);
let s10 = step512(s09,0x12835b0145706fbe,w09);
let s11 = step512(s10,0x243185be4ee4b28c,w10);
let s12 = step512(s11,0x550c7dc3d5ffb4e2,w11);
let s13 = step512(s12,0x72be5d74f27b896f,w12);
let s14 = step512(s13,0x80deb1fe3b1696b1,w13);
let s15 = step512(s14,0x9bdc06a725c71235,w14);
let s16 = step512(s15,0xc19bf174cf692694,w15);
let s17 = step512(s16,0xe49b69c19ef14ad2,w16);
let s18 = step512(s17,0xefbe4786384f25e3,w17);
let s19 = step512(s18,0x0fc19dc68b8cd5b5,w18);
let s20 = step512(s19,0x240ca1cc77ac9c65,w19);
let s21 = step512(s20,0x2de92c6f592b0275,w20);
let s22 = step512(s21,0x4a7484aa6ea6e483,w21);
let s23 = step512(s22,0x5cb0a9dcbd41fbd4,w22);
let s24 = step512(s23,0x76f988da831153b5,w23);
let s25 = step512(s24,0x983e5152ee66dfab,w24);
let s26 = step512(s25,0xa831c66d2db43210,w25);
let s27 = step512(s26,0xb00327c898fb213f,w26);
let s28 = step512(s27,0xbf597fc7beef0ee4,w27);
let s29 = step512(s28,0xc6e00bf33da88fc2,w28);
let s30 = step512(s29,0xd5a79147930aa725,w29);
let s31 = step512(s30,0x06ca6351e003826f,w30);
let s32 = step512(s31,0x142929670a0e6e70,w31);
let s33 = step512(s32,0x27b70a8546d22ffc,w32);
let s34 = step512(s33,0x2e1b21385c26c926,w33);
let s35 = step512(s34,0x4d2c6dfc5ac42aed,w34);
let s36 = step512(s35,0x53380d139d95b3df,w35);
let s37 = step512(s36,0x650a73548baf63de,w36);
let s38 = step512(s37,0x766a0abb3c77b2a8,w37);
let s39 = step512(s38,0x81c2c92e47edaee6,w38);
let s40 = step512(s39,0x92722c851482353b,w39);
let s41 = step512(s40,0xa2bfe8a14cf10364,w40);
let s42 = step512(s41,0xa81a664bbc423001,w41);
let s43 = step512(s42,0xc24b8b70d0f89791,w42);
let s44 = step512(s43,0xc76c51a30654be30,w43);
let s45 = step512(s44,0xd192e819d6ef5218,w44);
let s46 = step512(s45,0xd69906245565a910,w45);
let s47 = step512(s46,0xf40e35855771202a,w46);
let s48 = step512(s47,0x106aa07032bbd1b8,w47);
let s49 = step512(s48,0x19a4c116b8d2d0c8,w48);
let s50 = step512(s49,0x1e376c085141ab53,w49);
let s51 = step512(s50,0x2748774cdf8eeb99,w50);
let s52 = step512(s51,0x34b0bcb5e19b48a8,w51);
let s53 = step512(s52,0x391c0cb3c5c95a63,w52);
let s54 = step512(s53,0x4ed8aa4ae3418acb,w53);
let s55 = step512(s54,0x5b9cca4f7763e373,w54);
let s56 = step512(s55,0x682e6ff3d6b2b8a3,w55);
let s57 = step512(s56,0x748f82ee5defb2fc,w56);
let s58 = step512(s57,0x78a5636f43172f60,w57);
let s59 = step512(s58,0x84c87814a1f0ab72,w58);
let s60 = step512(s59,0x8cc702081a6439ec,w59);
let s61 = step512(s60,0x90befffa23631e28,w60);
let s62 = step512(s61,0xa4506cebde82bde9,w61);
let s63 = step512(s62,0xbef9a3f7b2c67915,w62);
let s64 = step512(s63,0xc67178f2e372532b,w63);
let s65 = step512(s64,0xca273eceea26619c,w64);
let s66 = step512(s65,0xd186b8c721c0c207,w65);
let s67 = step512(s66,0xeada7dd6cde0eb1e,w66);
let s68 = step512(s67,0xf57d4f7fee6ed178,w67);
let s69 = step512(s68,0x06f067aa72176fba,w68);
let s70 = step512(s69,0x0a637dc5a2c898a6,w69);
let s71 = step512(s70,0x113f9804bef90dae,w70);
let s72 = step512(s71,0x1b710b35131c471b,w71);
let s73 = step512(s72,0x28db77f523047d84,w72);
let s74 = step512(s73,0x32caab7b40c72493,w73);
let s75 = step512(s74,0x3c9ebe0a15c9bebc,w74);
let s76 = step512(s75,0x431d67c49c100d4c,w75);
let s77 = step512(s76,0x4cc5d4becb3e42b6,w76);
let s78 = step512(s77,0x597f299cfc657e2a,w77);
let s79 = step512(s78,0x5fcb6fab3ad6faec,w78);
let s80 = step512(s79,0x6c44198c4a475817,w79);
self.state[0] += s80[0];
self.state[1] += s80[1];
self.state[2] += s80[2];
self.state[3] += s80[3];
self.state[4] += s80[4];
self.state[5] += s80[5];
self.state[6] += s80[6];
self.state[7] += s80[7];
}
fn update(&mut self, block: &[u8]) {
if !self.done {
let mut offset = 0;
self.l += block.len();
if self.buffer.len() + block.len() < 128 {
self.buffer.extend_from_slice(block);
return;
}
if self.buffer.len() > 0 {
// We must be able to build up a 128 byte chunk, at this point, otherwise
// the math above would've been wrong.
while self.buffer.len() < 128 {
self.buffer.push(block[offset]);
offset += 1;
}
process_u64_block!(self.buffer, 0, self);
// Reset the buffer now, we're done with that nonsense for the moment
self.buffer.resize(0,0);
}
while (offset + 128) <= block.len() {
process_u64_block!(block, offset, self);
offset += 128;
}
if offset < block.len() {
self.buffer.extend_from_slice(&block[offset..]);
}
}
}
fn finish(&mut self) {
let bitlen = self.l * 8;
let k = calculate_k(896, 1024, bitlen);
// INVARIANT: k is necessarily > 0, and (k + 1) is a multiple of 8
let bytes_to_add = (k + 1) / 8;
let mut padvec = Vec::with_capacity(bytes_to_add + 16);
padvec.push(0x80); // Set the high bit, since the first bit after the data
// should be set
padvec.resize(bytes_to_add, 0);
padvec.write_u128::<BigEndian>(bitlen as u128).expect("Broken writing value to pre-allocated Vec?");
self.update(&padvec);
self.done = true;
assert_eq!(self.buffer.len(), 0);
}
}
#[inline(always)]
fn step512(state0: [u64; 8], k: u64, w: u64) -> [u64; 8]
{
let [a,b,c,d,e,f,g,h] = state0;
let t1 = h + bsig512_1!(e) + ch!(e,f,g) + k + w;
let t2 = bsig512_0!(a) + maj!(a,b,c);
let hp = g;
let gp = f;
let fp = e;
let ep = d + t1;
let dp = c;
let cp = b;
let bp = a;
let ap = t1 + t2;
[ap,bp,cp,dp,ep,fp,gp,hp]
}
#[cfg(test)]
use testing::run_test;
#[cfg(test)]
#[test]
fn nist_sha224() {
let fname = "testdata/sha/nist_sha224.test";
run_test(fname.to_string(), 3, |case| {
let (negl, lbytes) = case.get("l").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
assert!(!negl && !negm && !negd);
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
let digest = SHA224::hash(&msg);
assert_eq!(dbytes, &digest);
});
}
#[cfg(test)]
#[test]
fn nist_sha256() {
let fname = "testdata/sha/nist_sha256.test";
run_test(fname.to_string(), 3, |case| {
let (negl, lbytes) = case.get("l").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
assert!(!negl && !negm && !negd);
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
let digest = SHA256::hash(&msg);
assert_eq!(dbytes, &digest);
});
}
#[cfg(test)]
#[test]
fn nist_sha384() {
let fname = "testdata/sha/nist_sha384.test";
run_test(fname.to_string(), 3, |case| {
let (negl, lbytes) = case.get("l").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
assert!(!negl && !negm && !negd);
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
let digest = SHA384::hash(&msg);
assert_eq!(dbytes, &digest);
});
}
#[cfg(test)]
#[test]
fn nist_sha512() {
let fname = "testdata/sha/nist_sha512.test";
run_test(fname.to_string(), 3, |case| {
let (negl, lbytes) = case.get("l").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
assert!(!negl && !negm && !negd);
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
let digest = SHA512::hash(&msg);
assert_eq!(dbytes, &digest);
});
}

View File

@@ -1,610 +0,0 @@
use super::super::Hash;
#[derive(Clone)]
pub(crate) struct Keccak {
rate_in_bytes: usize,
rate_in_longs: usize,
buffer: Vec<u8>,
state: [u64; 25], // This is Keccak-f[1600]
output: Option<Vec<u8>>
}
const KECCAK_ROUND_CONSTANTS: [u64; 24] =
[ 0x0000000000000001u64, 0x0000000000008082u64,
0x800000000000808au64, 0x8000000080008000u64,
0x000000000000808bu64, 0x0000000080000001u64,
0x8000000080008081u64, 0x8000000000008009u64,
0x000000000000008au64, 0x0000000000000088u64,
0x0000000080008009u64, 0x000000008000000au64,
0x000000008000808bu64, 0x800000000000008bu64,
0x8000000000008089u64, 0x8000000000008003u64,
0x8000000000008002u64, 0x8000000000000080u64,
0x000000000000800au64, 0x800000008000000au64,
0x8000000080008081u64, 0x8000000000008080u64,
0x0000000080000001u64, 0x8000000080008008u64,
];
macro_rules! absorb {
($self: ident, $block: expr, $sidx: expr) => {{
let mut i = 0;
let mut off = 0;
while i < $self.rate_in_longs {
let word = ($block[$sidx+off+0] as u64) << 00 |
($block[$sidx+off+1] as u64) << 08 |
($block[$sidx+off+2] as u64) << 16 |
($block[$sidx+off+3] as u64) << 24 |
($block[$sidx+off+4] as u64) << 32 |
($block[$sidx+off+5] as u64) << 40 |
($block[$sidx+off+6] as u64) << 48 |
($block[$sidx+off+7] as u64) << 56;
$self.state[i] ^= word;
off += 8;
i += 1;
}
$self.permute();
}};
}
impl Keccak {
pub fn new(rate: usize) -> Self
{
assert_eq!(rate % 64, 0);
Keccak {
rate_in_bytes: rate / 8,
rate_in_longs: rate / 64,
buffer: Vec::with_capacity(rate),
state: [0; 25],
output: None,
}
}
fn permute(&mut self)
{
// This is a translation of the very easy-to-read implementation in BouncyCastle
for i in 0..24 {
// Theta!
let c0 = self.state[0] ^ self.state[5] ^ self.state[10] ^ self.state[15] ^ self.state[20];
let c1 = self.state[1] ^ self.state[6] ^ self.state[11] ^ self.state[16] ^ self.state[21];
let c2 = self.state[2] ^ self.state[7] ^ self.state[12] ^ self.state[17] ^ self.state[22];
let c3 = self.state[3] ^ self.state[8] ^ self.state[13] ^ self.state[18] ^ self.state[23];
let c4 = self.state[4] ^ self.state[9] ^ self.state[14] ^ self.state[19] ^ self.state[24];
let d0 = c0.rotate_left(1) ^ c3;
let d1 = c1.rotate_left(1) ^ c4;
let d2 = c2.rotate_left(1) ^ c0;
let d3 = c3.rotate_left(1) ^ c1;
let d4 = c4.rotate_left(1) ^ c2;
self.state[0] ^= d1; self.state[5] ^= d1; self.state[10] ^= d1; self.state[15] ^= d1; self.state[20] ^= d1;
self.state[1] ^= d2; self.state[6] ^= d2; self.state[11] ^= d2; self.state[16] ^= d2; self.state[21] ^= d2;
self.state[2] ^= d3; self.state[7] ^= d3; self.state[12] ^= d3; self.state[17] ^= d3; self.state[22] ^= d3;
self.state[3] ^= d4; self.state[8] ^= d4; self.state[13] ^= d4; self.state[18] ^= d4; self.state[23] ^= d4;
self.state[4] ^= d0; self.state[9] ^= d0; self.state[14] ^= d0; self.state[19] ^= d0; self.state[24] ^= d0;
// Rho & Pi!
let t1 = self.state[01].rotate_left(1);
self.state[01] = self.state[06].rotate_left(44);
self.state[06] = self.state[09].rotate_left(20);
self.state[09] = self.state[22].rotate_left(61);
self.state[22] = self.state[14].rotate_left(39);
self.state[14] = self.state[20].rotate_left(18);
self.state[20] = self.state[02].rotate_left(62);
self.state[02] = self.state[12].rotate_left(43);
self.state[12] = self.state[13].rotate_left(25);
self.state[13] = self.state[19].rotate_left(8);
self.state[19] = self.state[23].rotate_left(56);
self.state[23] = self.state[15].rotate_left(41);
self.state[15] = self.state[04].rotate_left(27);
self.state[04] = self.state[24].rotate_left(14);
self.state[24] = self.state[21].rotate_left(2);
self.state[21] = self.state[08].rotate_left(55);
self.state[08] = self.state[16].rotate_left(45);
self.state[16] = self.state[05].rotate_left(36);
self.state[05] = self.state[03].rotate_left(28);
self.state[03] = self.state[18].rotate_left(21);
self.state[18] = self.state[17].rotate_left(15);
self.state[17] = self.state[11].rotate_left(10);
self.state[11] = self.state[07].rotate_left(6);
self.state[07] = self.state[10].rotate_left(3);
self.state[10] = t1;
// Chi!
let t2 = self.state[00] ^ (!self.state[01] & self.state[02]);
let t3 = self.state[01] ^ (!self.state[02] & self.state[03]);
self.state[02] ^= !self.state[03] & self.state[04];
self.state[03] ^= !self.state[04] & self.state[00];
self.state[04] ^= !self.state[00] & self.state[01];
self.state[00] = t2;
self.state[01] = t3;
let t4 = self.state[05] ^ (!self.state[06] & self.state[07]);
let t5 = self.state[06] ^ (!self.state[07] & self.state[08]);
self.state[07] ^= !self.state[08] & self.state[09];
self.state[08] ^= !self.state[09] & self.state[05];
self.state[09] ^= !self.state[05] & self.state[06];
self.state[05] = t4;
self.state[06] = t5;
let t6 = self.state[10] ^ (!self.state[11] & self.state[12]);
let t7 = self.state[11] ^ (!self.state[12] & self.state[13]);
self.state[12] ^= !self.state[13] & self.state[14];
self.state[13] ^= !self.state[14] & self.state[10];
self.state[14] ^= !self.state[10] & self.state[11];
self.state[10] = t6;
self.state[11] = t7;
let t8 = self.state[15] ^ (!self.state[16] & self.state[17]);
let t9 = self.state[16] ^ (!self.state[17] & self.state[18]);
self.state[17] ^= !self.state[18] & self.state[19];
self.state[18] ^= !self.state[19] & self.state[15];
self.state[19] ^= !self.state[15] & self.state[16];
self.state[15] = t8;
self.state[16] = t9;
let ta = self.state[20] ^ (!self.state[21] & self.state[22]);
let tb = self.state[21] ^ (!self.state[22] & self.state[23]);
self.state[22] ^= !self.state[23] & self.state[24];
self.state[23] ^= !self.state[24] & self.state[20];
self.state[24] ^= !self.state[20] & self.state[21];
self.state[20] = ta;
self.state[21] = tb;
// iota
self.state[00] ^= KECCAK_ROUND_CONSTANTS[i];
}
}
pub fn process(&mut self, bytes: &[u8])
{
if self.output.is_none() {
let mut offset = 0;
if self.buffer.len() + bytes.len() < self.rate_in_bytes {
self.buffer.extend_from_slice(bytes);
return;
}
if self.buffer.len() > 0 {
// We must be able to build up a chunk at our absorbtion rate, at this
// point, otherwise the math above would've been wrong.
while self.buffer.len() < self.rate_in_bytes {
self.buffer.push(bytes[offset]);
offset += 1;
}
absorb!(self, self.buffer, 0);
// Reset the buffer now, we're done with that nonsense for the moment
self.buffer.resize(0,0);
}
while (offset + self.rate_in_bytes) <= bytes.len() {
absorb!(self, bytes, offset);
offset += self.rate_in_bytes;
}
if offset < bytes.len() {
self.buffer.extend_from_slice(&bytes[offset..]);
}
}
}
pub fn tag_and_pad(&mut self, tag_byte: u8)
{
if self.output.is_none() {
assert!(self.buffer.len() < self.rate_in_bytes);
// what we need to do here is tag on a final 01, to tag that as SHA3,
// and then pad it out, with an 0x80 at the end.
self.buffer.push(tag_byte);
self.buffer.resize(self.rate_in_bytes, 0);
self.buffer[self.rate_in_bytes-1] |= 0x80;
absorb!(self, self.buffer, 0);
}
}
pub fn squeeze(&mut self, output_len: usize) -> Vec<u8>
{
if let Some(ref result) = self.output {
result.clone()
} else {
let mut res = Vec::new();
while res.len() < output_len {
for i in 0..self.rate_in_longs {
res.push( (self.state[i] >> 00) as u8 );
res.push( (self.state[i] >> 08) as u8 );
res.push( (self.state[i] >> 16) as u8 );
res.push( (self.state[i] >> 24) as u8 );
res.push( (self.state[i] >> 32) as u8 );
res.push( (self.state[i] >> 40) as u8 );
res.push( (self.state[i] >> 48) as u8 );
res.push( (self.state[i] >> 56) as u8 );
}
self.permute();
}
res.resize(output_len, 0);
self.output = Some(res.clone());
res
}
}
}
/// The SHA3-224 hash.
///
/// To use, you can run it in incremental mode -- by calling new(),
/// update() zero or more times, and then finalize() -- or you can
/// just invoke the hash directly. For example:
///
/// ```rust
/// use simple_crypto::sha::{Hash,SHA3_224};
///
/// let empty = [0; 0];
/// // Do the hash using the incremental API
/// let mut hashf = SHA3_224::new();
/// hashf.update(&empty);
/// let result_incremental = hashf.finalize();
/// // Do the hash using the direct API
/// let result_direct = SHA3_224::hash(&empty);
/// // ... and they should be the same
/// assert_eq!(result_incremental,result_direct);
/// ```
#[derive(Clone)]
pub struct SHA3_224 {
state: Keccak
}
impl Hash for SHA3_224 {
fn new() -> Self
{
SHA3_224{ state: Keccak::new(1600 - 448) }
}
fn update(&mut self, buffer: &[u8])
{
self.state.process(&buffer);
}
fn finalize(&mut self) -> Vec<u8>
{
self.state.tag_and_pad(0x06);
self.state.squeeze(224 / 8)
}
fn block_size() -> usize
{
1152
}
}
#[cfg(test)]
mod sha224 {
use super::*;
use testing::run_test;
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-224_Msg0.pdf
#[test]
fn nist_empty_example() {
let empty = [0; 0];
let hashres = [0x6B,0x4E,0x03,0x42,0x36,0x67,0xDB,0xB7,0x3B,0x6E,0x15,
0x45,0x4F,0x0E,0xB1,0xAB,0xD4,0x59,0x7F,0x9A,0x1B,0x07,
0x8E,0x3F,0x5B,0x5A,0x6B,0xC7];
let mine = SHA3_224::hash(&empty);
assert_eq!(hashres.to_vec(), mine);
}
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-224_1600.pdf
#[test]
fn nist_1600_example() {
let example = [0xA3; 200];
let hashres = [0x93,0x76,0x81,0x6A,0xBA,0x50,0x3F,0x72,
0xF9,0x6C,0xE7,0xEB,0x65,0xAC,0x09,0x5D,
0xEE,0xE3,0xBE,0x4B,0xF9,0xBB,0xC2,0xA1,
0xCB,0x7E,0x11,0xE0];
let mine = SHA3_224::hash(&example);
assert_eq!(hashres.to_vec(), mine);
}
#[cfg(test)]
#[test]
fn nist_test_vectors() {
let fname = "testdata/sha/nist_sha3_224.test";
run_test(fname.to_string(), 3, |case| {
let (negl, lbytes) = case.get("l").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
assert!(!negl && !negm && !negd);
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
let digest = SHA3_224::hash(&msg);
assert_eq!(dbytes, &digest);
});
}
}
/// The SHA3-256 hash. [GOOD]
///
/// To use, you can run it in incremental mode -- by calling new(),
/// update() zero or more times, and then finalize() -- or you can
/// just invoke the hash directly. For example:
///
/// ```rust
/// use simple_crypto::sha::{Hash,SHA3_256};
///
/// let empty = [0; 0];
/// // Do the hash using the incremental API
/// let mut hashf = SHA3_256::new();
/// hashf.update(&empty);
/// let result_incremental = hashf.finalize();
/// // Do the hash using the direct API
/// let result_direct = SHA3_256::hash(&empty);
/// // ... and they should be the same
/// assert_eq!(result_incremental,result_direct);
/// ```
#[derive(Clone)]
pub struct SHA3_256 {
state: Keccak
}
impl Hash for SHA3_256 {
fn new() -> Self
{
SHA3_256{ state: Keccak::new(1600 - 512) }
}
fn update(&mut self, buffer: &[u8])
{
self.state.process(&buffer);
}
fn finalize(&mut self) -> Vec<u8>
{
self.state.tag_and_pad(0x06);
self.state.squeeze(256 / 8)
}
fn block_size() -> usize
{
1088
}
}
#[cfg(test)]
mod sha256 {
use super::*;
use testing::run_test;
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-256.pdf
#[test]
fn nist_empty_example() {
let empty = [0; 0];
let hashres = [0xA7,0xFF,0xC6,0xF8,0xBF,0x1E,0xD7,0x66,
0x51,0xC1,0x47,0x56,0xA0,0x61,0xD6,0x62,
0xF5,0x80,0xFF,0x4D,0xE4,0x3B,0x49,0xFA,
0x82,0xD8,0x0A,0x4B,0x80,0xF8,0x43,0x4A];
let mine = SHA3_256::hash(&empty);
assert_eq!(hashres.to_vec(), mine);
}
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-256_1600.pdf
#[test]
fn nist_1600_example() {
let example = [0xA3; 200];
let hashres = [0x79,0xF3,0x8A,0xDE,0xC5,0xC2,0x03,0x07,
0xA9,0x8E,0xF7,0x6E,0x83,0x24,0xAF,0xBF,
0xD4,0x6C,0xFD,0x81,0xB2,0x2E,0x39,0x73,
0xC6,0x5F,0xA1,0xBD,0x9D,0xE3,0x17,0x87];
let mine = SHA3_256::hash(&example);
assert_eq!(hashres.to_vec(), mine);
}
#[cfg(test)]
#[test]
fn nist_test_vectors() {
let fname = "testdata/sha/nist_sha3_256.test";
run_test(fname.to_string(), 3, |case| {
let (negl, lbytes) = case.get("l").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
assert!(!negl && !negm && !negd);
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
let digest = SHA3_256::hash(&msg);
assert_eq!(dbytes, &digest);
});
}
}
/// The SHA3-384 hash. [BETTER]
///
/// To use, you can run it in incremental mode -- by calling new(),
/// update() zero or more times, and then finalize() -- or you can
/// just invoke the hash directly. For example:
///
/// ```rust
/// use simple_crypto::sha::{Hash,SHA3_384};
///
/// let empty = [0; 0];
/// // Do the hash using the incremental API
/// let mut hashf = SHA3_384::new();
/// hashf.update(&empty);
/// let result_incremental = hashf.finalize();
/// // Do the hash using the direct API
/// let result_direct = SHA3_384::hash(&empty);
/// // ... and they should be the same
/// assert_eq!(result_incremental,result_direct);
/// ```
#[derive(Clone)]
pub struct SHA3_384 {
state: Keccak
}
impl Hash for SHA3_384 {
fn new() -> Self
{
SHA3_384{ state: Keccak::new(1600 - 768) }
}
fn update(&mut self, buffer: &[u8])
{
self.state.process(&buffer);
}
fn finalize(&mut self) -> Vec<u8>
{
self.state.tag_and_pad(0x06);
self.state.squeeze(384 / 8)
}
fn block_size() -> usize
{
832
}
}
#[cfg(test)]
mod sha384 {
use super::*;
use testing::run_test;
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-384_Msg0.pdf
#[test]
fn nist_empty_example() {
let empty = [0; 0];
let hashres = [0x0C,0x63,0xA7,0x5B,0x84,0x5E,0x4F,0x7D,
0x01,0x10,0x7D,0x85,0x2E,0x4C,0x24,0x85,
0xC5,0x1A,0x50,0xAA,0xAA,0x94,0xFC,0x61,
0x99,0x5E,0x71,0xBB,0xEE,0x98,0x3A,0x2A,
0xC3,0x71,0x38,0x31,0x26,0x4A,0xDB,0x47,
0xFB,0x6B,0xD1,0xE0,0x58,0xD5,0xF0,0x04];
let mine = SHA3_384::hash(&empty);
assert_eq!(hashres.to_vec(), mine);
}
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-384_1600.pdf
#[test]
fn nist_1600_example() {
let example = [0xA3; 200];
let hashres = [0x18,0x81,0xDE,0x2C,0xA7,0xE4,0x1E,0xF9,
0x5D,0xC4,0x73,0x2B,0x8F,0x5F,0x00,0x2B,
0x18,0x9C,0xC1,0xE4,0x2B,0x74,0x16,0x8E,
0xD1,0x73,0x26,0x49,0xCE,0x1D,0xBC,0xDD,
0x76,0x19,0x7A,0x31,0xFD,0x55,0xEE,0x98,
0x9F,0x2D,0x70,0x50,0xDD,0x47,0x3E,0x8F];
let mine = SHA3_384::hash(&example);
assert_eq!(hashres.to_vec(), mine);
}
#[cfg(test)]
#[test]
fn nist_test_vectors() {
let fname = "testdata/sha/nist_sha3_384.test";
run_test(fname.to_string(), 3, |case| {
let (negl, lbytes) = case.get("l").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
assert!(!negl && !negm && !negd);
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
let digest = SHA3_384::hash(&msg);
assert_eq!(dbytes, &digest);
});
}
}
/// The SHA3-512 hash. [BEST]
///
/// To use, you can run it in incremental mode -- by calling new(),
/// update() zero or more times, and then finalize() -- or you can
/// just invoke the hash directly. For example:
///
/// ```rust
/// use simple_crypto::sha::{Hash,SHA3_512};
///
/// let empty = [0; 0];
/// // Do the hash using the incremental API
/// let mut hashf = SHA3_512::new();
/// hashf.update(&empty);
/// let result_incremental = hashf.finalize();
/// // Do the hash using the direct API
/// let result_direct = SHA3_512::hash(&empty);
/// // ... and they should be the same
/// assert_eq!(result_incremental,result_direct);
/// ```
#[derive(Clone)]
pub struct SHA3_512 {
state: Keccak
}
impl Hash for SHA3_512 {
fn new() -> Self
{
SHA3_512{ state: Keccak::new(1600 - 1024) }
}
fn update(&mut self, buffer: &[u8])
{
self.state.process(&buffer);
}
fn finalize(&mut self) -> Vec<u8>
{
self.state.tag_and_pad(0x06);
self.state.squeeze(512 / 8)
}
fn block_size() -> usize
{
576
}
}
#[cfg(test)]
mod sha512 {
use super::*;
use testing::run_test;
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-512_Msg0.pdf
#[test]
fn nist_empty_example() {
let empty = [0; 0];
let hashres = [0xA6,0x9F,0x73,0xCC,0xA2,0x3A,0x9A,0xC5,
0xC8,0xB5,0x67,0xDC,0x18,0x5A,0x75,0x6E,
0x97,0xC9,0x82,0x16,0x4F,0xE2,0x58,0x59,
0xE0,0xD1,0xDC,0xC1,0x47,0x5C,0x80,0xA6,
0x15,0xB2,0x12,0x3A,0xF1,0xF5,0xF9,0x4C,
0x11,0xE3,0xE9,0x40,0x2C,0x3A,0xC5,0x58,
0xF5,0x00,0x19,0x9D,0x95,0xB6,0xD3,0xE3,
0x01,0x75,0x85,0x86,0x28,0x1D,0xCD,0x26];
let mine = SHA3_512::hash(&empty);
assert_eq!(hashres.to_vec(), mine);
}
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-512_1600.pdf
#[test]
fn nist_1600_example() {
let example = [0xA3; 200];
let hashres = [0xE7,0x6D,0xFA,0xD2,0x20,0x84,0xA8,0xB1,
0x46,0x7F,0xCF,0x2F,0xFA,0x58,0x36,0x1B,
0xEC,0x76,0x28,0xED,0xF5,0xF3,0xFD,0xC0,
0xE4,0x80,0x5D,0xC4,0x8C,0xAE,0xEC,0xA8,
0x1B,0x7C,0x13,0xC3,0x0A,0xDF,0x52,0xA3,
0x65,0x95,0x84,0x73,0x9A,0x2D,0xF4,0x6B,
0xE5,0x89,0xC5,0x1C,0xA1,0xA4,0xA8,0x41,
0x6D,0xF6,0x54,0x5A,0x1C,0xE8,0xBA,0x00];
let mine = SHA3_512::hash(&example);
assert_eq!(hashres.to_vec(), mine);
}
#[cfg(test)]
#[test]
fn nist_test_vectors() {
let fname = "testdata/sha/nist_sha3_512.test";
run_test(fname.to_string(), 3, |case| {
let (negl, lbytes) = case.get("l").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
assert!(!negl && !negm && !negd);
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
let digest = SHA3_512::hash(&msg);
assert_eq!(dbytes, &digest);
});
}
}

View File

@@ -1,101 +0,0 @@
macro_rules! ch {
($x: expr, $y: expr, $z: expr) => {{
let xval = $x;
(xval & $y) ^ (!xval & $z)
}};
}
macro_rules! parity {
($x: expr, $y: expr, $z: expr) => {
$x ^ $y ^ $z
};
}
macro_rules! maj {
($x: expr, $y: expr, $z: expr) => {{
/* the original function is (x & y) ^ (x & z) ^ (y & z).
if you fire off truth tables, this is equivalent to
(x & y) | (x & z) | (y & z)
which you can then use distribution on:
(x & (y | z)) | (y & z)
which saves one operation */
let yval = $y;
let zval = $z;
($x & (yval | zval)) | (yval & zval)
}};
}
macro_rules! process_u32_block {
($buf: expr, $off: expr, $self: ident) => {{
let w00 = ($buf[$off+0] as u32) << 24 | ($buf[$off+1] as u32) << 16 |
($buf[$off+2] as u32) << 8 | ($buf[$off+3] as u32);
let w01 = ($buf[$off+4] as u32) << 24 | ($buf[$off+5] as u32) << 16 |
($buf[$off+6] as u32) << 8 | ($buf[$off+7] as u32);
let w02 = ($buf[$off+8] as u32) << 24 | ($buf[$off+9] as u32) << 16 |
($buf[$off+10] as u32) << 8 | ($buf[$off+11] as u32);
let w03 = ($buf[$off+12] as u32) << 24 | ($buf[$off+13] as u32) << 16 |
($buf[$off+14] as u32) << 8 | ($buf[$off+15] as u32);
let w04 = ($buf[$off+16] as u32) << 24 | ($buf[$off+17] as u32) << 16 |
($buf[$off+18] as u32) << 8 | ($buf[$off+19] as u32);
let w05 = ($buf[$off+20] as u32) << 24 | ($buf[$off+21] as u32) << 16 |
($buf[$off+22] as u32) << 8 | ($buf[$off+23] as u32);
let w06 = ($buf[$off+24] as u32) << 24 | ($buf[$off+25] as u32) << 16 |
($buf[$off+26] as u32) << 8 | ($buf[$off+27] as u32);
let w07 = ($buf[$off+28] as u32) << 24 | ($buf[$off+29] as u32) << 16 |
($buf[$off+30] as u32) << 8 | ($buf[$off+31] as u32);
let w08 = ($buf[$off+32] as u32) << 24 | ($buf[$off+33] as u32) << 16 |
($buf[$off+34] as u32) << 8 | ($buf[$off+35] as u32);
let w09 = ($buf[$off+36] as u32) << 24 | ($buf[$off+37] as u32) << 16 |
($buf[$off+38] as u32) << 8 | ($buf[$off+39] as u32);
let w10 = ($buf[$off+40] as u32) << 24 | ($buf[$off+41] as u32) << 16 |
($buf[$off+42] as u32) << 8 | ($buf[$off+43] as u32);
let w11 = ($buf[$off+44] as u32) << 24 | ($buf[$off+45] as u32) << 16 |
($buf[$off+46] as u32) << 8 | ($buf[$off+47] as u32);
let w12 = ($buf[$off+48] as u32) << 24 | ($buf[$off+49] as u32) << 16 |
($buf[$off+50] as u32) << 8 | ($buf[$off+51] as u32);
let w13 = ($buf[$off+52] as u32) << 24 | ($buf[$off+53] as u32) << 16 |
($buf[$off+54] as u32) << 8 | ($buf[$off+55] as u32);
let w14 = ($buf[$off+56] as u32) << 24 | ($buf[$off+57] as u32) << 16 |
($buf[$off+58] as u32) << 8 | ($buf[$off+59] as u32);
let w15 = ($buf[$off+60] as u32) << 24 | ($buf[$off+61] as u32) << 16 |
($buf[$off+62] as u32) << 8 | ($buf[$off+63] as u32);
$self.process(w00, w01, w02, w03, w04, w05, w06, w07,
w08, w09, w10, w11, w12, w13, w14, w15);
}};
}
// Calculate the value `k` used in the padding for all the hashes, solving the
// equation (l + 1 + k) mod b = a.
pub fn calculate_k(a: usize, b: usize, l: usize) -> usize
{
(a - (l + 1)) % b
}
#[cfg(test)]
quickcheck!
{
fn maj_rewrite_ok(x: u64, y: u64, z: u64) -> bool
{
let orig = (x & y) ^ (x & z) ^ (y & z);
maj!(x, y, z) == orig
}
// Note, these two laws hold because we hash with bytes as the atomic size,
// not bits. If we hashed true bit streams, we'd be in trouble.
fn sha1_k_plus_1_multiple_of_8(lbytes: usize) -> bool
{
let l = lbytes * 8;
(calculate_k(448,512,l) + 1) % 8 == 0
}
// Note, these two laws hold because we hash with bytes as the atomic size,
// not bits. If we hashed true bit streams, we'd be in trouble.
fn sha2_k_plus_1_multiple_of_8(lbytes: usize) -> bool
{
let l = lbytes * 8;
(calculate_k(896,1024,l) + 1) % 8 == 0
}
}

View File

@@ -1,215 +0,0 @@
//! This module implements the SHAKE family of variable-length hash functions,
//! which NIST also referes to as Extendable-Output Functions (XOFs). They are
//! based on the same underlying hashing mechanism used in SHA3, but can be
//! tuned to output a variety of different hash lengths. One trick is that the
//! security of the hash is the minimum of the defined bit size (128 for
//! SHAKE128, or 256 for SHAKE256) and the output hash length, so if you use
//! shorter hashes you lose some amount of collision protection.
//!
//! Because the output is variable length, these don't quite fit into the
//! normal `Hash` trait. Instead, they implement the same basic functions,
//! but with `hash` and `finalize` functions extended with an additional
//! output length function. Usage is thus in the analagous way to normal
//! hashing:
//!
//! ```rust
//! use simple_crypto::shake::SHAKE128;
//!
//! // Use SHAKE incrementally
//! let empty = [0; 0];
//! let mut shakef = SHAKE128::new();
//! shakef.update(&empty);
//! let result_inc = shakef.finalize(384);
//! // Use SHAKE directly
//! let result_dir = SHAKE128::hash(&empty, 384);
//! // ... and the answers should be the same.
//! assert_eq!(result_inc, result_dir);
//! ```
use sha::Keccak;
/// The SHAKE128 variable-length hash.
///
/// This generates a variable-length hash value, although it's not necessarily as
/// strong as a hash of the same value. My understanding (which is admittedly
/// limited; I've never seen these used) is that this is more for convenience
/// when you want to fit into particularly-sized regions. The 128 is the
/// approximate maximum bit strength of the hash in bits; the true strength is
/// the minimum of the length of the output hash and 128.
///
/// `SHAKE128` does not implement `Hash`, because it is finalized differently,
/// but we've kept something of the flavor of the `Hash` interface for
/// familiarity.
///
/// Like the SHA3 variants, this can be used incrementally or directly, as per
/// usual:
///
/// ```rust
/// use simple_crypto::shake::SHAKE128;
///
/// // Use SHAKE incrementally
/// let empty = [0; 0];
/// let mut shakef = SHAKE128::new();
/// shakef.update(&empty);
/// let result_inc = shakef.finalize(384);
/// // Use SHAKE directly
/// let result_dir = SHAKE128::hash(&empty, 384);
/// // ... and the answers should be the same.
/// assert_eq!(result_inc, result_dir);
/// ```
pub struct SHAKE128 {
state: Keccak
}
impl SHAKE128 {
/// Create a fresh, new SHAKE128 instance for incremental use.
pub fn new() -> Self
{
SHAKE128{
state: Keccak::new(1600 - 256)
}
}
/// Add more data into the hash function for processing.
pub fn update(&mut self, buffer: &[u8])
{
self.state.process(&buffer);
}
/// Generate the final hash. Because this is a variable-length hash,
/// you will need to provide the output size in bits. Note that this
/// output size *must* be a multiple of 8, and that the security
/// strength of the whole hash is approximately the minimum of this
/// length and 128 bits.
pub fn finalize(&mut self, outsize: usize) -> Vec<u8>
{
assert_eq!(outsize % 8, 0);
self.state.tag_and_pad(0x1F);
self.state.squeeze(outsize / 8)
}
/// Directly generate the SHAKE128 hash of the given buffer, returning
/// a hash value of the given size (in bits). Presently, the output
/// size *must* be a multiple of 8, although this may change in the
/// future.
pub fn hash(buffer: &[u8], outsize: usize) -> Vec<u8>
{
let mut x = Self::new();
x.update(&buffer);
x.finalize(outsize)
}
}
#[cfg(test)]
use testing::run_test;
#[cfg(test)]
use cryptonum::unsigned::{Decoder,U192};
#[cfg(test)]
#[test]
fn shake128() {
let fname = "testdata/sha/shake128.test";
run_test(fname.to_string(), 4, |case| {
let (negl, lbytes) = case.get("l").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
let (nego, obytes) = case.get("o").unwrap();
assert!(!negl && !negm && !negd && !nego);
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
let osize = usize::from(U192::from_bytes(obytes));
let digest = SHAKE128::hash(&msg, osize);;
assert_eq!(dbytes, &digest);
});
}
/// The SHAKE256 variable-length hash.
///
/// This generates a variable-length hash value, although it's not necessarily as
/// strong as a hash of the same value. My understanding (which is admittedly
/// limited; I've never seen these used) is that this is more for convenience
/// when you want to fit into particularly-sized regions. The 256 is the
/// approximate maximum bit strength of the hash in bits; the true strength is
/// the minimum of the length of the output hash and 256.
///
/// `SHAKE256` does not implement `Hash`, because it is finalized differently,
/// but we've kept something of the flavor of the `Hash` interface for
/// familiarity.
///
/// Like the SHA3 variants, this can be used incrementally or directly, as per
/// usual:
///
/// ```rust
/// use simple_crypto::shake::SHAKE256;
///
/// // Use SHAKE incrementally
/// let empty = [0; 0];
/// let mut shakef = SHAKE256::new();
/// shakef.update(&empty);
/// let result_inc = shakef.finalize(384);
/// // Use SHAKE directly
/// let result_dir = SHAKE256::hash(&empty, 384);
/// // ... and the answers should be the same.
/// assert_eq!(result_inc, result_dir);
/// ```
pub struct SHAKE256 {
state: Keccak
}
impl SHAKE256 {
/// Create a fresh, new SHAKE256 instance for incremental use.
pub fn new() -> Self
{
SHAKE256{
state: Keccak::new(1600 - 512)
}
}
/// Add more data into the hash function for processing.
pub fn update(&mut self, buffer: &[u8])
{
self.state.process(&buffer);
}
/// Generate the final hash. Because this is a variable-length hash,
/// you will need to provide the output size in bits. Note that this
/// output size *must* be a multiple of 8, and that the security
/// strength of the whole hash is approximately the minimum of this
/// length and 256 bits.
pub fn finalize(&mut self, outsize: usize) -> Vec<u8>
{
assert_eq!(outsize % 8, 0);
self.state.tag_and_pad(0x1F);
self.state.squeeze(outsize / 8)
}
/// Directly generate the SHAKE256 hash of the given buffer, returning
/// a hash value of the given size (in bits). Presently, the output
/// size *must* be a multiple of 8, although this may change in the
/// future.
pub fn hash(buffer: &[u8], outsize: usize) -> Vec<u8>
{
let mut x = Self::new();
x.update(&buffer);
x.finalize(outsize)
}
}
#[cfg(test)]
#[test]
fn shake256() {
let fname = "testdata/sha/shake256.test";
run_test(fname.to_string(), 4, |case| {
let (negl, lbytes) = case.get("l").unwrap();
let (negm, mbytes) = case.get("m").unwrap();
let (negd, dbytes) = case.get("d").unwrap();
let (nego, obytes) = case.get("o").unwrap();
assert!(!negl && !negm && !negd && !nego);
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
let osize = usize::from(U192::from_bytes(obytes));
let digest = SHAKE256::hash(&msg, osize);;
assert_eq!(dbytes, &digest);
});
}

View File

@@ -1,75 +0,0 @@
use cryptonum::unsigned::*;
use dsa::{DSAKeyPair,DSAParameters,DSAPublicKey,DSAPrivateKey,L1024N160};
use std::io::{Read,Write};
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
use ssh::frame::*;
use ssh::SSHKey;
impl SSHKey for DSAKeyPair<L1024N160> {
fn valid_keytype(s: &str) -> bool {
(s == "ssh-dss") || (s == "dss")
}
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>
{
let pubkey_type = parse_openssh_string(inp)?;
if !Self::valid_keytype(&pubkey_type) {
return Err(SSHKeyParseError::UnknownKeyType(pubkey_type));
}
let pubp = parse_openssh_number(inp)?;
let pubq = parse_openssh_number(inp)?;
let pubg = parse_openssh_number(inp)?;
let pubparams = L1024N160::new(pubp, pubg, pubq);
let puby: U1024 = parse_openssh_number(inp)?;
for _ in inp.bytes() { return Err(SSHKeyParseError::UnknownTrailingData); }
Ok(DSAPublicKey::<L1024N160>::new(pubparams.clone(), puby.clone()))
}
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>
{
let check1 = parse_openssh_u32(inp)?;
let check2 = parse_openssh_u32(inp)?;
if check1 != check2 {
return Err(SSHKeyParseError::PrivateKeyCorruption);
}
let privkey_type = parse_openssh_string(inp)?;
if !Self::valid_keytype(&privkey_type) {
return Err(SSHKeyParseError::InconsistentKeyTypes("ssh-dss".to_string(), privkey_type));
}
let privp = parse_openssh_number(inp)?;
let privq = parse_openssh_number(inp)?;
let privg = parse_openssh_number(inp)?;
let privparams = L1024N160::new(privp, privg, privq);
let _ = parse_openssh_buffer(inp)?; // a copy of y we don't need
let privx = parse_openssh_number(inp)?;
let privkey = DSAPrivateKey::<L1024N160>::new(privparams, privx);
let comment = parse_openssh_string(inp)?;
for (idx,byte) in inp.bytes().enumerate() {
if ((idx+1) as u8) != byte? {
return Err(SSHKeyParseError::InvalidPadding);
}
}
Ok((privkey,comment))
}
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
{
render_openssh_string(out, "ssh-dss")?;
render_openssh_number(out, &self.public.params.p)?;
render_openssh_number(out, &self.public.params.q)?;
render_openssh_number(out, &self.public.params.g)?;
render_openssh_number(out, &self.public.y)
}
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
{
render_openssh_string(out, "ssh-dss")?;
render_openssh_number(out, &self.private.params.p)?;
render_openssh_number(out, &self.private.params.q)?;
render_openssh_number(out, &self.private.params.g)?;
render_openssh_number(out, &self.public.y)?;
render_openssh_number(out, &self.private.x)
}
}

View File

@@ -1,171 +0,0 @@
use cryptonum::unsigned::*;
use ecdsa::{ECDSAPair,ECDSAPublic,ECCPublicKey,ECDSAPrivate,ECCPrivateKey};
use ecdsa::{EllipticCurve,P256,P384,P521};
use std::io::{Read,Write};
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
use ssh::frame::*;
use ssh::SSHKey;
impl SSHKey for ECDSAPair {
fn valid_keytype(s: &str) -> bool {
(s == "ssh-ecdsa") || (s == "ecdsa") || (s == "ecdsa-sha2-nistp256") ||
(s == "ecdsa-sha2-nistp384") || (s == "ecdsa-sha2-nistp521")
}
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>
{
let pubkey_type = parse_openssh_string(inp)?;
if !Self::valid_keytype(&pubkey_type) {
return Err(SSHKeyParseError::UnknownKeyType(pubkey_type));
}
// this peaks a little under the cover a bit (it'd be nice to pretend
// that we didn't know the number format was the same as the buffer
// one), but we need to infer what kind of key this is, and this appears
// to be the easiest / fastest way.
let curve = parse_openssh_string(inp)?;
match curve.as_ref() {
"nistp256" => {
let val = parse_openssh_buffer(inp)?;
if val[0] != 4 || val.len() != 65 {
return Err(SSHKeyParseError::InvalidECPointCompression);
}
let x = U256::from_bytes(&val[1..33]);
let y = U256::from_bytes(&val[33..]);
let p = P256::new_point(x, y);
let pbl = ECCPublicKey::<P256>::new(p);
Ok(ECDSAPublic::P256(pbl))
}
"nistp384" => {
let val = parse_openssh_buffer(inp)?;
if val[0] != 4 || val.len() != 97 {
return Err(SSHKeyParseError::InvalidECPointCompression);
}
let x = U384::from_bytes(&val[1..49]);
let y = U384::from_bytes(&val[49..]);
let p = P384::new_point(x, y);
let pbl = ECCPublicKey::<P384>::new(p);
Ok(ECDSAPublic::P384(pbl))
}
"nistp521" => {
let val = parse_openssh_buffer(inp)?;
if val[0] != 4 || val.len() != 133 {
return Err(SSHKeyParseError::InvalidECPointCompression);
}
let x = U576::from_bytes(&val[1..67]);
let y = U576::from_bytes(&val[67..]);
let p = P521::new_point(x, y);
let pbl = ECCPublicKey::<P521>::new(p);
Ok(ECDSAPublic::P521(pbl))
}
_ => {
return Err(SSHKeyParseError::UnknownECDSACurve(curve))
}
}
}
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>
{
let check1 = parse_openssh_u32(inp)?;
let check2 = parse_openssh_u32(inp)?;
if check1 != check2 {
return Err(SSHKeyParseError::PrivateKeyCorruption);
}
let res = match ECDSAPair::parse_ssh_public_info(inp)? {
ECDSAPublic::P192(_) => return Err(SSHKeyParseError::PrivateKeyCorruption),
ECDSAPublic::P224(_) => return Err(SSHKeyParseError::PrivateKeyCorruption),
ECDSAPublic::P256(_) => {
let mut dbytes = parse_openssh_buffer(inp)?;
while dbytes[0] == 0 { dbytes.remove(0); }
assert!(dbytes.len() <= 32);
let d = U256::from_bytes(&dbytes);
ECDSAPrivate::P256(ECCPrivateKey::<P256>::new(d))
}
ECDSAPublic::P384(_) => {
let mut dbytes = parse_openssh_buffer(inp)?;
while dbytes[0] == 0 { dbytes.remove(0); }
assert!(dbytes.len() <= 48);
let d = U384::from_bytes(&dbytes);
ECDSAPrivate::P384(ECCPrivateKey::<P384>::new(d))
}
ECDSAPublic::P521(_) => {
let mut dbytes = parse_openssh_buffer(inp)?;
while dbytes[0] == 0 { dbytes.remove(0); }
assert!(dbytes.len() <= 66);
let d = U576::from_bytes(&dbytes);
ECDSAPrivate::P521(ECCPrivateKey::<P521>::new(d))
}
};
let comment = parse_openssh_string(inp)?;
for (idx,byte) in inp.bytes().enumerate() {
if ((idx+1) as u8) != byte? {
return Err(SSHKeyParseError::InvalidPadding);
}
}
Ok((res, comment))
}
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
{
render_openssh_string(out, "ssh-ecdsa")?;
match self {
ECDSAPair::P192(_,_) =>
return Err(SSHKeyRenderError::IllegalECDSAKeyType("P192".to_string())),
ECDSAPair::P224(_,_) =>
return Err(SSHKeyRenderError::IllegalECDSAKeyType("P224".to_string())),
ECDSAPair::P256(pu,_) => {
render_openssh_string(out, "nistp256")?;
let mut vec = Vec::with_capacity(66);
vec.write(&[4u8])?;
render_number(256, &mut vec, &U256::from(pu.q.x.clone()))?;
render_number(256, &mut vec, &U256::from(pu.q.y.clone()))?;
render_openssh_buffer(out, &vec)?;
}
ECDSAPair::P384(pu,_) => {
render_openssh_string(out, "nistp384")?;
let mut vec = Vec::with_capacity(66);
vec.write(&[4u8])?;
render_number(384, &mut vec, &U384::from(pu.q.x.clone()))?;
render_number(384, &mut vec, &U384::from(pu.q.y.clone()))?;
render_openssh_buffer(out, &vec)?;
}
ECDSAPair::P521(pu,_) => {
render_openssh_string(out, "nistp521")?;
let mut vec = Vec::with_capacity(66);
vec.write(&[4u8])?;
render_number(521, &mut vec, &U576::from(pu.q.x.clone()))?;
render_number(521, &mut vec, &U576::from(pu.q.y.clone()))?;
render_openssh_buffer(out, &vec)?;
}
}
Ok(())
}
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
{
self.render_ssh_public_info(out)?;
match self {
ECDSAPair::P192(_,_) =>
return Err(SSHKeyRenderError::IllegalECDSAKeyType("P192".to_string())),
ECDSAPair::P224(_,_) =>
return Err(SSHKeyRenderError::IllegalECDSAKeyType("P224".to_string())),
ECDSAPair::P256(_,pr) => { render_openssh_u32(out, 256/8)?; render_number(256, out, &pr.d)?; }
ECDSAPair::P384(_,pr) => { render_openssh_u32(out, 384/8)?; render_number(384, out, &pr.d)?; }
ECDSAPair::P521(_,pr) => { render_openssh_u32(out, 528/8)?; render_number(521, out, &pr.d)?; }
}
Ok(())
}
}
fn render_number<O,N>(bitlen: usize, out: &mut O, val: &N) -> Result<(),SSHKeyRenderError>
where
O: Write,
N: Encoder
{
let mut outvec = Vec::new();
outvec.write(&val.to_bytes())?;
while outvec.len() < ((bitlen + 7) / 8) { outvec.insert(0,0); }
while outvec.len() > ((bitlen + 7) / 8) { outvec.remove(0); }
out.write(&outvec)?;
Ok(())
}

View File

@@ -1,58 +0,0 @@
use ed25519::{ED25519KeyPair,ED25519Private,ED25519Public};
use std::io::{Read,Write};
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
use ssh::frame::*;
use ssh::SSHKey;
impl SSHKey for ED25519KeyPair {
fn valid_keytype(s: &str) -> bool {
(s == "ssh-ed25519")
}
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>
{
let pubkey_type = parse_openssh_string(inp)?;
if !Self::valid_keytype(&pubkey_type) {
return Err(SSHKeyParseError::UnknownKeyType(pubkey_type));
}
let pubkey_bytes = parse_openssh_buffer(inp)?;
Ok(ED25519Public::new(&pubkey_bytes)?)
}
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>
{
let check1 = parse_openssh_u32(inp)?;
let check2 = parse_openssh_u32(inp)?;
if check1 != check2 {
return Err(SSHKeyParseError::PrivateKeyCorruption);
}
let public = ED25519KeyPair::parse_ssh_public_info(inp)?;
let private_bytes = parse_openssh_buffer(inp)?;
let private = ED25519Private::from_seed(&private_bytes[0..32]);
let comment = parse_openssh_string(inp)?;
for (idx,byte) in inp.bytes().enumerate() {
if ((idx+1) as u8) != byte? {
return Err(SSHKeyParseError::InvalidPadding);
}
}
assert_eq!(public, ED25519Public::from(&private));
Ok((private, comment))
}
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
{
render_openssh_string(out, "ssh-ed25519")?;
render_openssh_buffer(out, &self.public.to_bytes())?;
Ok(())
}
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
{
self.render_ssh_public_info(out)?;
let mut private_bytes = self.private.to_bytes();
private_bytes.append(&mut self.public.to_bytes());
render_openssh_buffer(out, &private_bytes)?;
Ok(())
}
}

View File

@@ -1,68 +0,0 @@
use base64::DecodeError;
use ed25519::ED25519PublicImportError;
use std::io;
/// A whole pile of errors that you can get when parsing an SSH key from
/// disk or memory.
#[derive(Debug)]
pub enum SSHKeyParseError
{
DecodeError(DecodeError),
IOError(io::Error),
NoBeginBannerFound, NoEndBannerFound,
NoOpenSSHMagicHeader,
UnknownKeyCipher(String),
UnknownKDF(String), UnexpectedKDFOptions,
InvalidNumberOfKeys(u32),
UnknownTrailingData,
UnknownKeyType(String),
InvalidPublicKeyMaterial,
PrivateKeyCorruption,
InconsistentKeyTypes(String,String),
InconsistentPublicKeyValue,
InvalidPrivateKeyValue,
InvalidPadding,
InvalidPublicKeyType,
BrokenPublicKeyLine,
UnknownECDSACurve(String),
InvalidECPointCompression
}
impl From<DecodeError> for SSHKeyParseError {
fn from(e: DecodeError) -> SSHKeyParseError {
SSHKeyParseError::DecodeError(e)
}
}
impl From<io::Error> for SSHKeyParseError {
fn from(e: io::Error) -> SSHKeyParseError {
SSHKeyParseError::IOError(e)
}
}
impl From<ED25519PublicImportError> for SSHKeyParseError {
fn from(e: ED25519PublicImportError) -> SSHKeyParseError {
match e {
ED25519PublicImportError::WrongNumberOfBytes(_) =>
SSHKeyParseError::InvalidPublicKeyMaterial,
ED25519PublicImportError::InvalidPublicPoint =>
SSHKeyParseError::InvalidPublicKeyMaterial,
}
}
}
/// A much smaller set of errors you can get when rendering an SSH key into
/// a file or memory block.
#[derive(Debug)]
pub enum SSHKeyRenderError {
IOError(io::Error),
StringTooLong,
BufferTooLarge,
IllegalECDSAKeyType(String)
}
impl From<io::Error> for SSHKeyRenderError {
fn from(e: io::Error) -> SSHKeyRenderError {
SSHKeyRenderError::IOError(e)
}
}

View File

@@ -1,320 +0,0 @@
use base64::{decode,encode};
use byteorder::{BigEndian,ReadBytesExt,WriteBytesExt};
use cryptonum::unsigned::{Decoder,Encoder};
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
#[cfg(test)]
use std::io::Cursor;
#[cfg(test)]
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::iter::Iterator;
const OPENER: &'static str = "-----BEGIN OPENSSH PRIVATE KEY-----";
const CLOSER: &'static str = "-----END OPENSSH PRIVATE KEY-----";
/// Given a string defining an ASCII SSH key blob (one that starts with
/// "--BEGIN..."), decode the body of the blob and return it as binary
/// data.
pub fn parse_ssh_private_key_data(s: &str) -> Result<Vec<u8>,SSHKeyParseError>
{
if s.starts_with(OPENER) {
if let Some(endidx) = s.find(CLOSER) {
let b64str: String = s[OPENER.len()..endidx].chars().filter(|x| !x.is_whitespace()).collect();
let bytes = decode(&b64str)?;
Ok(bytes)
} else {
Err(SSHKeyParseError::NoEndBannerFound)
}
} else {
Err(SSHKeyParseError::NoBeginBannerFound)
}
}
/// Once you've figured out the binary data you want to produce for an SSH key
/// blob, use this routine to render it into its ASCII encoding.
pub fn render_ssh_private_key_data(bytes: &[u8]) -> String
{
let mut bytestr = encode(bytes);
let mut output = String::new();
output.push_str(OPENER);
#[cfg(target_os="windows")]
output.push_str("\r");
output.push_str("\n");
while bytestr.len() > 70 {
let rest = bytestr.split_off(70);
output.push_str(&bytestr);
#[cfg(target_os="windows")]
output.push_str("\r");
output.push_str("\n");
bytestr = rest;
}
output.push_str(&bytestr);
#[cfg(target_os="windows")]
output.push_str("\r");
output.push_str("\n");
output.push_str(CLOSER);
output
}
//------------------------------------------------------------------------------
const OPENSSH_MAGIC_HEADER: &'static str = "openssh-key-v1\0";
const OPENSSH_MAGIC_HEADER_LEN: usize = 15;
/// Parse the magic header in an SSH key file.
pub fn parse_openssh_header<R: Read>(input: &mut R) -> Result<(),SSHKeyParseError>
{
let mut limited_input_header = input.take(OPENSSH_MAGIC_HEADER_LEN as u64);
let mut header: [u8; OPENSSH_MAGIC_HEADER_LEN] = [0; OPENSSH_MAGIC_HEADER_LEN];
assert_eq!(OPENSSH_MAGIC_HEADER.len(), OPENSSH_MAGIC_HEADER_LEN);
limited_input_header.read_exact(&mut header)?;
for (left, right) in OPENSSH_MAGIC_HEADER.bytes().zip(header.iter()) {
if left != *right {
return Err(SSHKeyParseError::NoOpenSSHMagicHeader)
}
}
Ok(())
}
/// Render the magic header in an SSH key file.
pub fn render_openssh_header<O: Write>(output: &mut O) -> Result<(),SSHKeyRenderError>
{
Ok(output.write_all(OPENSSH_MAGIC_HEADER.as_bytes())?)
}
//------------------------------------------------------------------------------
/// Parse an unsigned u32 from the SSH key stream. (This does the appropriate
/// conversion from network order to native order.)
pub fn parse_openssh_u32<I: Read>(input: &mut I) -> Result<u32,SSHKeyParseError>
{
let mut limited_input_header = input.take(4);
let res = limited_input_header.read_u32::<BigEndian>()?;
Ok(res)
}
/// Render an unsigned u32 from the SSH key stream. (This does the appropriate
/// conversion from network order to native order.)
pub fn render_openssh_u32<O: Write>(output: &mut O, val: u32) -> Result<(),SSHKeyRenderError>
{
Ok(output.write_u32::<BigEndian>(val)?)
}
//------------------------------------------------------------------------------
/// Parse a string from the SSH key stream. This does some validation to ensure
/// that the data being read is actually in a form that Rust will recognize as
/// being a valid string.
pub fn parse_openssh_string<I: Read>(input: &mut I) -> Result<String,SSHKeyParseError>
{
let length = parse_openssh_u32(input)?;
let mut limited_input = input.take(length as u64);
let mut result = String::new();
limited_input.read_to_string(&mut result)?;
Ok(result)
}
/// Render a string into the SSH key stream.
pub fn render_openssh_string<O: Write>(output: &mut O, v: &str) -> Result<(),SSHKeyRenderError>
{
let vbytes: Vec<u8> = v.bytes().collect();
let len = vbytes.len();
if len > 0xFFFFFFFF {
return Err(SSHKeyRenderError::StringTooLong);
}
render_openssh_u32(output, vbytes.len() as u32)?;
output.write_all(&vbytes)?;
Ok(())
}
//------------------------------------------------------------------------------
/// Read a buffer from the SSH key stream.
pub fn parse_openssh_buffer<I: Read>(input: &mut I) -> Result<Vec<u8>,SSHKeyParseError>
{
let length = parse_openssh_u32(input)?;
let mut limited_input = input.take(length as u64);
let mut res = Vec::with_capacity(length as usize);
limited_input.read_to_end(&mut res)?;
Ok(res)
}
/// Render a buffer into the SSH key stream.
pub fn render_openssh_buffer<O: Write>(output: &mut O, b: &[u8]) -> Result<(),SSHKeyRenderError>
{
if b.len() > 0xFFFFFFFF {
return Err(SSHKeyRenderError::BufferTooLarge);
}
render_openssh_u32(output, b.len() as u32)?;
if b.len() > 0 {
output.write_all(b)?;
}
Ok(())
}
//------------------------------------------------------------------------------
/// Parse a fixed-width number from the SSH key stream and return it.
pub fn parse_openssh_number<I,D>(input: &mut I) -> Result<D,SSHKeyParseError>
where
I: Read,
D: Decoder
{
let mut buffer = parse_openssh_buffer(input)?;
while buffer[0] == 0 { buffer.remove(0); }
Ok(D::from_bytes(&buffer))
}
/// Render a fixed-width number into the SSH key stream.
pub fn render_openssh_number<O,D>(output: &mut O, n: &D) -> Result<(),SSHKeyRenderError>
where
O: Write,
D: Encoder
{
let bytes = n.to_bytes();
render_openssh_buffer(output, &bytes)
}
//------------------------------------------------------------------------------
#[cfg(test)]
use cryptonum::unsigned::{U192,U1024,U2048,U4096};
#[cfg(test)]
quickcheck! {
fn bytes_roundtrip(x: Vec<u8>) -> bool {
let rendered = render_ssh_private_key_data(&x);
let returned = parse_ssh_private_key_data(&rendered).unwrap();
returned == x
}
fn blocks_formatted(x: Vec<u8>) -> bool {
let rendered = render_ssh_private_key_data(&x);
let mut is_ok = true;
for line in rendered.lines() {
let clean_line: String = line.chars().filter(|x| *x != '\r').collect();
is_ok &= clean_line.len() <= 70;
}
is_ok
}
fn u32s_roundtrip_rp(x: u32) -> bool {
let mut buffer = vec![];
render_openssh_u32(&mut buffer, x).unwrap();
let mut cursor = Cursor::new(buffer);
let check = parse_openssh_u32(&mut cursor).unwrap();
x == check
}
fn u32s_roundtrip_pr(a: u8, b: u8, c: u8, d: u8) -> bool {
let block = [a,b,c,d];
let mut cursor = Cursor::new(block);
let base = parse_openssh_u32(&mut cursor).unwrap();
let mut rendered = vec![];
render_openssh_u32(&mut rendered, base).unwrap();
(block[0] == rendered[0]) &&
(block[1] == rendered[1]) &&
(block[2] == rendered[2]) &&
(block[3] == rendered[3])
}
fn string_roundtrip(s: String) -> bool {
let mut buffer = vec![];
render_openssh_string(&mut buffer, &s).unwrap();
let mut cursor = Cursor::new(buffer);
let check = parse_openssh_string(&mut cursor).unwrap();
s == check
}
fn buffer(os: Vec<u8>) -> bool {
let mut buffer = vec![];
render_openssh_buffer(&mut buffer, &os).unwrap();
let mut cursor = Cursor::new(buffer);
let check = parse_openssh_buffer(&mut cursor).unwrap();
os == check
}
fn u192(x: U192) -> bool {
let mut buffer = vec![];
render_openssh_number(&mut buffer, &x).unwrap();
let mut cursor = Cursor::new(buffer);
let check: U192 = parse_openssh_number(&mut cursor).unwrap();
check == x
}
fn u1024(x: U1024) -> bool {
let mut buffer = vec![];
render_openssh_number(&mut buffer, &x).unwrap();
let mut cursor = Cursor::new(buffer);
let check: U1024 = parse_openssh_number(&mut cursor).unwrap();
check == x
}
fn u2048(x: U2048) -> bool {
let mut buffer = vec![];
render_openssh_number(&mut buffer, &x).unwrap();
let mut cursor = Cursor::new(buffer);
let check: U2048 = parse_openssh_number(&mut cursor).unwrap();
check == x
}
fn u4096(x: U4096) -> bool {
let mut buffer = vec![];
render_openssh_number(&mut buffer, &x).unwrap();
let mut cursor = Cursor::new(buffer);
let check: U4096 = parse_openssh_number(&mut cursor).unwrap();
check == x
}
}
#[cfg(test)]
#[test]
fn pregenerated_reencode() {
let test_files = ["dsa1024-1", "dsa1024-2", "dsa1024-3",
"ecdsa256-1", "ecdsa256-2", "ecdsa256-3",
"ecdsa384-1", "ecdsa384-2", "ecdsa384-3",
"ecdsa521-1", "ecdsa521-2", "ecdsa521-3",
"ed25519-1", "ed25519-2", "ed25519-3",
"rsa1024-1", "rsa1024-2", "rsa1024-3",
"rsa2048-1", "rsa2048-2", "rsa2048-3",
"rsa3072-1", "rsa3072-2", "rsa3072-3",
"rsa4096-1", "rsa4096-2", "rsa4096-3",
"rsa8192-1", "rsa8192-2", "rsa8192-3" ];
for file in test_files.iter() {
let path = format!("testdata/ssh/{}",file);
let mut fd = File::open(path).unwrap();
let mut contents = String::new();
fd.read_to_string(&mut contents).unwrap();
let parsed = parse_ssh_private_key_data(&contents).unwrap();
let rendered = render_ssh_private_key_data(&parsed);
// we remove white space in this to avoid a couple issues with files
// generated in Windows or not, as well as trailing white space that
// doesn't really matter.
let cleaned_orig: String = contents.chars().filter(|x| !x.is_whitespace()).collect();
let cleaned_rend: String = rendered.chars().filter(|x| !x.is_whitespace()).collect();
assert_eq!(cleaned_orig, cleaned_rend);
}
}
#[cfg(test)]
#[test]
fn header_roundtrips() {
let mut vec = Vec::new();
assert!(render_openssh_header(&mut vec).is_ok());
let mut cursor = Cursor::new(vec);
assert!(parse_openssh_header(&mut cursor).is_ok());
}

View File

@@ -1,428 +0,0 @@
//! Most of the routines you want are exported from this module as functions,
//! not as structs, macros, enums, or what have you. In particular, you
//! probably want the `decode` or `encode` functions, or one of the functions
//! that `load`s data from disk or `write`s it. Here's some example code
//! to get you started, using a generated ED25519 key for fun:
//!
//! ```rust
//! use simple_crypto::ed25519::ED25519KeyPair;
//! use simple_crypto::ssh::*;
//!
//! // Generate a new ED25519 key
//! let mut rng = rand::rngs::OsRng::new().unwrap();
//! let kp = ED25519KeyPair::generate(&mut rng);
//!
//! // Now that we have it, we can encode it as a handy ASCII string in memory,
//! // using a totally fake email address for fun:
//! let ascii_rep = encode_ssh(&kp, "fake@email.addr").expect("Encode failure!");
//!
//! // As usual, we should be able to decode anything we encode, and the
//! // keys should match:
//! let (kp2, addr2) = decode_ssh(&ascii_rep).expect("Decode failure!");
//! assert_eq!(kp, kp2);
//! assert_eq!(&addr2, "fake@email.addr");
//!
//! // If you want to write this to a file, you can just do so directly:
//! write_ssh_keyfile("test.ed25519", &kp, "fake@email.addr").expect("write error");
//! // And then load it back:
//! let (kp3, addr3) = load_ssh_keyfile("test.ed25519").expect("load error");
//! // And, of course, it should be the same.
//! assert_eq!(kp, kp3);
//! assert_eq!(addr2, addr3);
//! ```
mod dsa;
mod ecdsa;
mod ed25519;
mod errors;
pub mod frame;
mod rsa;
pub use self::errors::{SSHKeyParseError,SSHKeyRenderError};
use base64::decode;
use self::frame::*;
use std::fs::File;
use std::io::{Cursor,Read,Write};
use std::path::Path;
use super::KeyPair;
/// A trait defining keys that can be parsed / rendered by this library. Note
/// that you probably don't want to use these routines directly; they're mostly
/// used by the internal functions. Perhaps the only reason to use them is to
/// implement them, because you've got another kind of key you want to parse that
/// isn't already part of the library. (In that case, though ... maybe send a
/// patch?)
pub trait SSHKey: Sized + KeyPair {
/// Return true if the given string is a valid key type identifier for this
/// key type. (i.e., "ssh-ed25519" is the identifier for ED25519, and "dss"
/// and "ssh-dss" are both valid identifiers for DSA keys.)
fn valid_keytype(s: &str) -> bool;
/// Parse the public blob info within an SSH blob. I strongly recommend
/// using the functions in `ssh::frame` for this.
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>;
/// Parse the private blob info within an SSH blob. I strongly recommend
/// using the functions in `ssh::frame` for this.
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>;
/// Render the public blob info within an SSH blob. I strongly recommend
/// using the functions in `ssh::frame` for this.
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>;
/// Render the private blob info within an SSH blob. I strongly recommend
/// using the functions in `ssh::frame` for this.
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>;
}
/// Decode a string containing a private key into the appropriate key type and
/// the comment associated with it, usually an email address or similar.
pub fn decode_ssh<KP: SSHKey>(x: &str) -> Result<(KP, String),SSHKeyParseError>
{
let bytes = parse_ssh_private_key_data(x)?;
let data_size = bytes.len() as u64;
let mut byte_cursor = Cursor::new(bytes);
parse_openssh_header(&mut byte_cursor)?;
let ciphername = parse_openssh_string(&mut byte_cursor)?;
if ciphername != "none" {
return Err(SSHKeyParseError::UnknownKeyCipher(ciphername));
}
let kdfname = parse_openssh_string(&mut byte_cursor)?;
if kdfname != "none" {
return Err(SSHKeyParseError::UnknownKeyCipher(kdfname));
}
let kdfoptions = parse_openssh_buffer(&mut byte_cursor)?;
if kdfoptions.len() > 0 {
return Err(SSHKeyParseError::UnexpectedKDFOptions);
}
let numkeys = parse_openssh_u32(&mut byte_cursor)?;
if numkeys != 1 {
return Err(SSHKeyParseError::InvalidNumberOfKeys(numkeys));
}
let pubkey0 = parse_openssh_buffer(&mut byte_cursor)?;
let privkeys = parse_openssh_buffer(&mut byte_cursor)?;
if byte_cursor.position() < data_size {
return Err(SSHKeyParseError::UnknownTrailingData);
}
let mut pubcursor = Cursor::new(pubkey0);
let public = KP::parse_ssh_public_info(&mut pubcursor)?;
let mut privcursor = Cursor::new(privkeys);
let (private, comment) = KP::parse_ssh_private_info(&mut privcursor)?;
Ok((KP::new(public, private), comment))
}
/// Decode a string containing a public key into an appropriate key type and
/// the comment associated with it, usually an email address or similar.
pub fn decode_ssh_pubkey<KP: SSHKey>(s: &str) -> Result<(KP::Public, String),SSHKeyParseError>
{
let mut splitter = s.split_whitespace();
match (splitter.next(), splitter.next(), splitter.next(), splitter.next()) {
(Some(keytype), Some(keymaterial), Some(comment), None) => {
if !KP::valid_keytype(keytype) {
return Err(SSHKeyParseError::InvalidPublicKeyType);
}
let bytes = decode(keymaterial)?;
let mut byte_cursor = Cursor::new(bytes);
let key = KP::parse_ssh_public_info(&mut byte_cursor)?;
Ok((key, comment.to_string()))
}
_ =>
Err(SSHKeyParseError::BrokenPublicKeyLine)
}
}
/// Load an SSH private key file, returning the appropriate key type and the
/// comment associated with it.
pub fn load_ssh_keyfile<KP,P>(path: P) -> Result<(KP, String),SSHKeyParseError>
where
KP: SSHKey,
P: AsRef<Path>
{
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
decode_ssh(&contents)
}
/// Load all the public keys from a file into memory.
pub fn load_ssh_pubkeys<KP,P>(path: P) -> Result<Vec<(KP::Public, String)>,SSHKeyParseError>
where
KP: SSHKey,
P: AsRef<Path>
{
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let mut result = Vec::new();
for line in contents.lines() {
result.push( decode_ssh_pubkey::<KP>(line)? );
}
Ok(result)
}
/// Encode a supported key into its ASCII SSH format, with the given comment.
pub fn encode_ssh<KP: SSHKey>(x: &KP, comment: &str) -> Result<String,SSHKeyRenderError>
{
let mut pubkeybin = Vec::with_capacity(8192);
let mut privkeybin = Vec::with_capacity(8192);
let mut binary = Vec::with_capacity(16384);
// create the public key bits
x.render_ssh_public_info(&mut pubkeybin)?;
// create the private key bits
render_openssh_u32(&mut privkeybin, 0xDEADBEEF)?; // FIXME: Any reason for this to be random?
render_openssh_u32(&mut privkeybin, 0xDEADBEEF)?; // ditto
x.render_ssh_private_info(&mut privkeybin)?;
render_openssh_string(&mut privkeybin, comment)?;
// add some padding (not quite sure why)
let mut i = comment.len();
while (i % 16) != 0 {
privkeybin.write(&[(i - comment.len() + 1) as u8])?;
i += 1;
}
// render a bunch of the framing stuff
render_openssh_header(&mut binary)?;
render_openssh_string(&mut binary, "none")?; // ciphername
render_openssh_string(&mut binary, "none")?; // kdfname
render_openssh_buffer(&mut binary, &[])?; // kdfoptions
render_openssh_u32(&mut binary, 1)?; // numkeys
render_openssh_buffer(&mut binary, &pubkeybin)?;
render_openssh_buffer(&mut binary, &privkeybin)?;
Ok(render_ssh_private_key_data(&binary))
}
/// Encode a supported key into the given file, with the given comment.
pub fn write_ssh_keyfile<KP,P>(path: P, x: &KP, comment: &str) -> Result<(),SSHKeyRenderError>
where
KP: SSHKey,
P: AsRef<Path>
{
let mut file = File::create(path)?;
let contents = encode_ssh(x, comment)?;
let bytes = contents.into_bytes();
file.write_all(&bytes)?;
file.sync_all()?;
Ok(())
}
#[cfg(test)]
use dsa::{DSAKeyPair,DSAPublicKey,L1024N160};
#[cfg(test)]
use ecdsa::ECDSAPair;
#[cfg(test)]
use ed25519::ED25519KeyPair;
#[cfg(test)]
use rsa::{RSAPair,RSAPublic,SIGNING_HASH_SHA256};
#[cfg(test)]
use sha::SHA256;
#[cfg(test)]
#[test]
fn dsa_examples() {
let test_files = ["dsa1024-1", "dsa1024-2", "dsa1024-3"];
for file in test_files.iter() {
let path = format!("testdata/ssh/{}",file);
let mkeypair = load_ssh_keyfile(path);
match mkeypair {
Err(e) => assert!(false, format!("reading error: {:?}", e)),
Ok((keypair, comment)) => {
let buffer = [0,1,2,3,4,6,2];
let _ : DSAKeyPair<L1024N160> = keypair;
let sig = keypair.private.sign::<SHA256>(&buffer);
assert!(keypair.public.verify::<SHA256>(&buffer, &sig));
let buffer2 = [0,1,2,3,4,6,5];
assert!(!keypair.public.verify::<SHA256>(&buffer2, &sig));
match encode_ssh(&keypair, &comment) {
Err(e2) => assert!(false, format!("render error: {:?}", e2)),
Ok(encodedstr) => {
match decode_ssh(&encodedstr) {
Err(e3) => assert!(false, format!("reparse error: {:?}", e3)),
Ok((keypair2,comment2)) => {
let _ : DSAKeyPair<L1024N160> = keypair2;
assert_eq!(keypair.public.params.p,keypair2.public.params.p,"failed to reparse key pair (p)");
assert_eq!(keypair.public.params.q,keypair2.public.params.q,"failed to reparse key pair (q)");
assert_eq!(keypair.public.params.g,keypair2.public.params.g,"failed to reparse key pair (g)");
assert_eq!(keypair.private.params.p,keypair2.private.params.p,"failed to reparse key pair (p)");
assert_eq!(keypair.private.params.q,keypair2.private.params.q,"failed to reparse key pair (q)");
assert_eq!(keypair.private.params.g,keypair2.private.params.g,"failed to reparse key pair (g)");
assert_eq!(keypair.public.y,keypair2.public.y,"failed to reparse key pair (y)");
assert_eq!(keypair.private.x,keypair2.private.x,"failed to reparse key pair (x)");
assert_eq!(comment,comment2,"failed to reparse comment");
let ppath = format!("testdata/ssh/{}.pub",file);
match load_ssh_pubkeys::<DSAKeyPair<L1024N160>,String>(ppath) {
Err(e4) => assert!(false, format!("pubkey error: {:?}", e4)),
Ok(pubkeys) => {
let _ : Vec<(DSAPublicKey<L1024N160>,String)> = pubkeys;
for (pubkey, comment3) in pubkeys {
assert_eq!(pubkey.params.p, keypair.public.params.p, "public key check (p)");
assert_eq!(pubkey.params.q, keypair.public.params.q, "public key check (q)");
assert_eq!(pubkey.params.g, keypair.public.params.g, "public key check (g)");
assert_eq!(pubkey.y, keypair.public.y, "public key check (y)");
assert_eq!(comment, comment3, "public key check comment")
}
}
}
}
}
}
}
}
}
}
}
#[cfg(test)]
#[test]
fn rsa_examples() {
let test_files = ["rsa1024-1", "rsa1024-2", "rsa1024-3",
"rsa2048-1", "rsa2048-2", "rsa2048-3",
"rsa3072-1", "rsa3072-2", "rsa3072-3",
"rsa4096-1", "rsa4096-2", "rsa4096-3",
"rsa8192-1", "rsa8192-2", "rsa8192-3"];
for file in test_files.iter() {
let path = format!("testdata/ssh/{}",file);
let mkeypair = load_ssh_keyfile::<RSAPair,String>(path);
match mkeypair {
Err(e) => assert!(false, format!("reading error: {:?}", e)),
Ok((keypair, comment)) => {
let buffer = [0,1,2,3,4,6,2];
let sig = keypair.sign(&SIGNING_HASH_SHA256, &buffer);
assert!(keypair.verify(&SIGNING_HASH_SHA256, &buffer, &sig));
match encode_ssh(&keypair, &comment) {
Err(e2) => assert!(false, format!("render error: {:?}", e2)),
Ok(encodedstr) => {
match decode_ssh(&encodedstr) {
Err(e3) => assert!(false, format!("reparse error: {:?}", e3)),
Ok((keypair2,comment2)) => {
assert_eq!(keypair,keypair2,"failed to reparse key pair");
assert_eq!(comment,comment2,"failed to reparse comment");
let ppath = format!("testdata/ssh/{}.pub",file);
match load_ssh_pubkeys::<RSAPair,String>(ppath) {
Err(e4) => assert!(false, format!("pubkey error: {:?}", e4)),
Ok(pubkeys) => {
let _ : Vec<(RSAPublic,String)> = pubkeys;
for (pubkey, comment3) in pubkeys {
assert_eq!(pubkey, keypair.public(), "public key check");
assert_eq!(comment, comment3, "public key check comment");
}
}
}
}
}
}
}
}
}
}
}
#[cfg(test)]
#[test]
fn ecdsa_examples() {
let test_files = ["ecdsa256-1", "ecdsa256-2", "ecdsa256-3",
"ecdsa384-1", "ecdsa384-2", "ecdsa384-3",
"ecdsa521-1", "ecdsa521-2", "ecdsa521-3"];
for file in test_files.iter() {
let path = format!("testdata/ssh/{}",file);
match load_ssh_keyfile::<ECDSAPair,String>(path) {
Err(e) =>
assert!(false, "SSH ECDSA parse error: {:?}", e),
Ok((keypair,comment)) => {
// first see if this roundtrips
let buffer = vec![0,1,2,4,5,6,9];
match keypair {
ECDSAPair::P192(_,_) =>
assert!(false, "Somehow got a P192 in read test"),
ECDSAPair::P224(_,_) =>
assert!(false, "Somehow got a P224 in read test"),
ECDSAPair::P256(ref pu, ref pr) => {
let sig = pr.sign::<SHA256>(&buffer);
assert!(pu.verify::<SHA256>(&buffer, &sig));
}
ECDSAPair::P384(ref pu, ref pr) => {
let sig = pr.sign::<SHA256>(&buffer);
assert!(pu.verify::<SHA256>(&buffer, &sig));
}
ECDSAPair::P521(ref pu, ref pr) => {
let sig = pr.sign::<SHA256>(&buffer);
assert!(pu.verify::<SHA256>(&buffer, &sig));
}
}
// encode this, parse it again
match encode_ssh(&keypair, &comment) {
Err(e) =>
assert!(false, "SSH ECDSA encoding error: {:?}", e),
Ok(coded) => {
match (decode_ssh(&coded), keypair) {
(Err(e), _) =>
assert!(false, "SSSH ECDSA redecoding error: {:?}", e),
(Ok((ECDSAPair::P256(pu2, pr2), comment2)), ECDSAPair::P256(pu,pr)) => {
assert_eq!(pu, pu2, "public key mismatch");
assert_eq!(pr, pr2, "public key mismatch");
assert_eq!(comment, comment2, "comment mismatch");
}
(Ok((ECDSAPair::P384(pu2, pr2), comment2)), ECDSAPair::P384(pu,pr)) => {
assert_eq!(pu, pu2, "public key mismatch");
assert_eq!(pr, pr2, "public key mismatch");
assert_eq!(comment, comment2, "comment mismatch");
}
(Ok((ECDSAPair::P521(pu2, pr2), comment2)), ECDSAPair::P521(pu,pr)) => {
assert_eq!(pu, pu2, "public key mismatch");
assert_eq!(pr, pr2, "public key mismatch");
assert_eq!(comment, comment2, "comment mismatch");
}
_ =>
assert!(false, "Failed to accurately re-parse key")
}
}
}
}
}
}
}
#[cfg(test)]
#[test]
fn ed25519_examples() {
let test_files = ["ed25519-1", "ed25519-2", "ed25519-3"];
for file in test_files.iter() {
let path = format!("testdata/ssh/{}",file);
match load_ssh_keyfile::<ED25519KeyPair,String>(path) {
Err(e) =>
assert!(false, "SSH ED25519 parse error: {:?}", e),
Ok((keypair,comment)) => {
// first see if this roundtrips
let buffer = vec![0,1,2,4,5,6,9];
let sig = keypair.private.sign(&buffer);
assert!(keypair.public.verify(&buffer, &sig));
match encode_ssh(&keypair, &comment) {
Err(e) =>
assert!(false, "SSH ED25519 encoding error: {:?}", e),
Ok(coded) => {
match decode_ssh(&coded) {
Err(e) =>
assert!(false, "SSSH ECDSA redecoding error: {:?}", e),
Ok((keypair2, comment2)) => {
let _ : ED25519KeyPair = keypair2;
assert_eq!(keypair.public, keypair2.public, "public key mismatch");
assert_eq!(keypair.private, keypair2.private, "public key mismatch");
assert_eq!(comment, comment2, "comment mismatch");
}
}
}
}
}
}
}
}

View File

@@ -1,201 +0,0 @@
use cryptonum::unsigned::*;
use rsa::{RSAPair,RSAPublic,RSAPublicKey,RSAPrivate,RSAPrivateKey};
use std::io::{Read,Write};
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
use ssh::frame::*;
use ssh::SSHKey;
impl SSHKey for RSAPair {
fn valid_keytype(s: &str) -> bool {
(s == "ssh-rsa") || (s == "rsa")
}
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>
{
let pubkey_type = parse_openssh_string(inp)?;
if !Self::valid_keytype(&pubkey_type) {
return Err(SSHKeyParseError::UnknownKeyType(pubkey_type));
}
// this peaks a little under the cover a bit (it'd be nice to pretend
// that we didn't know the number format was the same as the buffer
// one), but we need to infer what kind of key this is, and this appears
// to be the easiest / fastest way.
let mut ebuf = parse_openssh_buffer(inp)?;
let mut nbuf = parse_openssh_buffer(inp)?;
while ebuf[0] == 0 { ebuf.remove(0); }
while nbuf[0] == 0 { nbuf.remove(0); }
if nbuf.len() > (8192 / 8) {
let e = U15360::from_bytes(&ebuf);
let n = U15360::from_bytes(&nbuf);
Ok(RSAPublic::Key15360(RSAPublicKey::<U15360>::new(n, e)))
} else if nbuf.len() > (4096 / 8) {
let e = U8192::from_bytes(&ebuf);
let n = U8192::from_bytes(&nbuf);
Ok(RSAPublic::Key8192(RSAPublicKey::<U8192>::new(n, e)))
} else if nbuf.len() > (3072 / 8) {
let e = U4096::from_bytes(&ebuf);
let n = U4096::from_bytes(&nbuf);
Ok(RSAPublic::Key4096(RSAPublicKey::<U4096>::new(n, e)))
} else if nbuf.len() > (2048 / 8) {
let e = U3072::from_bytes(&ebuf);
let n = U3072::from_bytes(&nbuf);
Ok(RSAPublic::Key3072(RSAPublicKey::<U3072>::new(n, e)))
} else if nbuf.len() > (1024 / 8) {
let e = U2048::from_bytes(&ebuf);
let n = U2048::from_bytes(&nbuf);
Ok(RSAPublic::Key2048(RSAPublicKey::<U2048>::new(n, e)))
} else if nbuf.len() > (512 / 8) {
let e = U1024::from_bytes(&ebuf);
let n = U1024::from_bytes(&nbuf);
Ok(RSAPublic::Key1024(RSAPublicKey::<U1024>::new(n, e)))
} else {
let e = U512::from_bytes(&ebuf);
let n = U512::from_bytes(&nbuf);
Ok(RSAPublic::Key512(RSAPublicKey::<U512>::new(n, e)))
}
}
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>
{
let check1 = parse_openssh_u32(inp)?;
let check2 = parse_openssh_u32(inp)?;
if check1 != check2 {
return Err(SSHKeyParseError::PrivateKeyCorruption);
}
let privkey_type = parse_openssh_string(inp)?;
if !Self::valid_keytype(&privkey_type) {
return Err(SSHKeyParseError::InconsistentKeyTypes("ssh-rsa".to_string(), privkey_type));
}
// See the comment in the public key section.
let mut nbuf = parse_openssh_buffer(inp)?;
let _ebuf = parse_openssh_buffer(inp)?;
let mut dbuf = parse_openssh_buffer(inp)?;
let _iqmp = parse_openssh_buffer(inp)?;
let _pbuf = parse_openssh_buffer(inp)?;
let _qbuf = parse_openssh_buffer(inp)?;
let comment = parse_openssh_string(inp)?;
for (idx,byte) in inp.bytes().enumerate() {
if ((idx+1) as u8) != byte? {
return Err(SSHKeyParseError::InvalidPadding);
}
}
while dbuf[0] == 0 { dbuf.remove(0); }
while nbuf[0] == 0 { nbuf.remove(0); }
if nbuf.len() > (8192 / 8) {
let d = U15360::from_bytes(&dbuf);
let n = U15360::from_bytes(&nbuf);
Ok((RSAPrivate::Key15360(RSAPrivateKey::<U15360>::new(n, d)), comment))
} else if nbuf.len() > (4096 / 8) {
let d = U8192::from_bytes(&dbuf);
let n = U8192::from_bytes(&nbuf);
Ok((RSAPrivate::Key8192(RSAPrivateKey::<U8192>::new(n, d)), comment))
} else if nbuf.len() > (3072 / 8) {
let d = U4096::from_bytes(&dbuf);
let n = U4096::from_bytes(&nbuf);
Ok((RSAPrivate::Key4096(RSAPrivateKey::<U4096>::new(n, d)), comment))
} else if nbuf.len() > (2048 / 8) {
let d = U3072::from_bytes(&dbuf);
let n = U3072::from_bytes(&nbuf);
Ok((RSAPrivate::Key3072(RSAPrivateKey::<U3072>::new(n, d)), comment))
} else if nbuf.len() > (1024 / 8) {
let d = U2048::from_bytes(&dbuf);
let n = U2048::from_bytes(&nbuf);
Ok((RSAPrivate::Key2048(RSAPrivateKey::<U2048>::new(n, d)), comment))
} else if nbuf.len() > (512 / 8) {
let d = U1024::from_bytes(&dbuf);
let n = U1024::from_bytes(&nbuf);
Ok((RSAPrivate::Key1024(RSAPrivateKey::<U1024>::new(n, d)), comment))
} else {
let d = U512::from_bytes(&dbuf);
let n = U512::from_bytes(&nbuf);
Ok((RSAPrivate::Key512(RSAPrivateKey::<U512>::new(n, d)), comment))
}
}
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
{
render_openssh_string(out, "ssh-rsa")?;
match self {
RSAPair::R512(pbl,_) => {
render_openssh_number(out, &pbl.e)?;
render_openssh_number(out, &pbl.n)?;
}
RSAPair::R1024(pbl,_) => {
render_openssh_number(out, &pbl.e)?;
render_openssh_number(out, &pbl.n)?;
}
RSAPair::R2048(pbl,_) => {
render_openssh_number(out, &pbl.e)?;
render_openssh_number(out, &pbl.n)?;
}
RSAPair::R3072(pbl,_) => {
render_openssh_number(out, &pbl.e)?;
render_openssh_number(out, &pbl.n)?;
}
RSAPair::R4096(pbl,_) => {
render_openssh_number(out, &pbl.e)?;
render_openssh_number(out, &pbl.n)?;
}
RSAPair::R8192(pbl,_) => {
render_openssh_number(out, &pbl.e)?;
render_openssh_number(out, &pbl.n)?;
}
RSAPair::R15360(pbl,_) => {
render_openssh_number(out, &pbl.e)?;
render_openssh_number(out, &pbl.n)?;
}
}
Ok(())
}
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
{
render_openssh_string(out, "ssh-rsa")?;
match self {
RSAPair::R512(pbl,prv) => {
render_openssh_number(out, &pbl.n)?;
render_openssh_number(out, &pbl.e)?;
render_openssh_number(out, &prv.d)?;
}
RSAPair::R1024(pbl,prv) => {
render_openssh_number(out, &pbl.n)?;
render_openssh_number(out, &pbl.e)?;
render_openssh_number(out, &prv.d)?;
}
RSAPair::R2048(pbl,prv) => {
render_openssh_number(out, &pbl.n)?;
render_openssh_number(out, &pbl.e)?;
render_openssh_number(out, &prv.d)?;
}
RSAPair::R3072(pbl,prv) => {
render_openssh_number(out, &pbl.n)?;
render_openssh_number(out, &pbl.e)?;
render_openssh_number(out, &prv.d)?;
}
RSAPair::R4096(pbl,prv) => {
render_openssh_number(out, &pbl.n)?;
render_openssh_number(out, &pbl.e)?;
render_openssh_number(out, &prv.d)?;
}
RSAPair::R8192(pbl,prv) => {
render_openssh_number(out, &pbl.n)?;
render_openssh_number(out, &pbl.e)?;
render_openssh_number(out, &prv.d)?;
}
RSAPair::R15360(pbl,prv) => {
render_openssh_number(out, &pbl.n)?;
render_openssh_number(out, &pbl.e)?;
render_openssh_number(out, &prv.d)?;
}
}
/* iqmp */ render_openssh_buffer(out, &vec![])?;
/* p */ render_openssh_buffer(out, &vec![])?;
/* q */ render_openssh_buffer(out, &vec![])?;
Ok(())
}
}

View File

@@ -1,13 +1,9 @@
use cryptonum::{SCN,UCN};
use std::collections::HashMap;
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());
@@ -15,7 +11,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_start_matches("-");
let valbitsnoneg = valbits.trim_left_matches("-");
let mut nibble_iter = valbitsnoneg.chars().rev();
let mut val = Vec::new();
@@ -23,11 +19,11 @@ fn next_value_set(line: &str) -> (String, bool, Vec<u8>)
while let Some(c1) = nibble_iter.next() {
match nibble_iter.next() {
None => {
val.push( c1.to_digit(16).expect(&format!("Unexpected character: |{}|", c1)) as u8 );
val.push( c1.to_digit(16).unwrap() as u8 );
}
Some(c2) => {
let b1 = c1.to_digit(16).expect(&format!("Unexpected character: |{}|", c1)) as u8;
let b2 = c2.to_digit(16).expect(&format!("Unexpected character: |{}|", c2)) as u8;
let b1 = c1.to_digit(16).unwrap() as u8;
let b2 = c2.to_digit(16).unwrap() as u8;
val.push( (b2 << 4) | b1 );
}
}
@@ -53,7 +49,32 @@ fn next_test_case(contents: &mut Lines, lines: usize) ->
Some(res)
}
pub fn run_test<F>(fname: String, i: usize, f: F)
pub fn make_signed(m: HashMap<String,(bool,Vec<u8>)>) -> HashMap<String,SCN>
{
let mut res: HashMap<String,SCN> = HashMap::new();
for (key, (neg, bval)) in m.iter() {
let base = UCN::from_bytes(bval);
let val = SCN{ negative: *neg, value: base };
res.insert(key.clone(), val);
}
res
}
pub fn make_unsigned(m: HashMap<String,(bool,Vec<u8>)>) -> HashMap<String,UCN>
{
let mut res: HashMap<String,UCN> = HashMap::new();
for (key, (neg, bval)) in m.iter() {
assert!(!neg);
res.insert(key.clone(), UCN::from_bytes(bval));
}
res
}
pub fn run_test<F>(fname: &'static str, i: usize, f: F)
where F: Fn(HashMap<String,(bool,Vec<u8>)>)
{
let mut file = File::open(fname).unwrap();

View File

@@ -1,57 +0,0 @@
use cryptonum::unsigned::*;
use num::{BigInt,BigUint};
use num::bigint::Sign;
pub trait TranslateNums<N>: Sized {
fn from_num(x: &N) -> Option<Self>;
fn to_num(&self) -> N;
}
macro_rules! from_biguint {
($uname: ident, $size: expr) => {
impl TranslateNums<BigUint> for $uname {
fn from_num(x: &BigUint) -> Option<$uname> {
let mut base_vec = x.to_bytes_be();
let target_bytes = $size / 8;
if target_bytes < base_vec.len() {
return None;
}
while target_bytes > base_vec.len() {
base_vec.insert(0,0);
}
Some($uname::from_bytes(&base_vec))
}
fn to_num(&self) -> BigUint {
let bytes = self.to_bytes();
BigUint::from_bytes_be(&bytes)
}
}
impl TranslateNums<BigInt> for $uname {
fn from_num(x: &BigInt) -> Option<$uname> {
let ux = x.to_biguint()?;
$uname::from_num(&ux)
}
fn to_num(&self) -> BigInt {
BigInt::from_biguint(Sign::Plus, self.to_num())
}
}
};
}
from_biguint!(U192, 192);
from_biguint!(U256, 256);
from_biguint!(U384, 384);
from_biguint!(U512, 512);
from_biguint!(U576, 576);
from_biguint!(U1024, 1024);
from_biguint!(U2048, 2048);
from_biguint!(U3072, 3072);
from_biguint!(U4096, 4096);
from_biguint!(U8192, 8192);
from_biguint!(U15360, 15360);

View File

@@ -1,393 +0,0 @@
use num::BigUint;
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
use x509::error::X509ParseError;
/// A supported x509 hash algorithm
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum HashAlgorithm { SHA1, SHA224, SHA256, SHA384, SHA512 }
/// A supported x509 asymmetric crypto algorithm
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum PublicKeyInfo { RSA, DSA, ECDSA }
/// The algorithm used, either in a certificate or as part of the signing
/// process. We only actually support a subset of the possible values,
/// here, although we try to catch them all.
///
/// Specifically, this library supports:
///
/// | | *RSA* | *DSA* | *ECDSA* |
/// |----------|-------|-------|---------|
/// | *SHA1* | X | X | X |
/// | *SHA224* | X | X | X |
/// | *SHA256* | X | X | X |
/// | *SHA384* | X | | X |
/// | *SHA512* | X | | X |
///
#[derive(Clone,Debug,PartialEq)]
pub struct AlgorithmIdentifier {
pub hash: HashAlgorithm,
pub algo: PublicKeyInfo
}
impl FromASN1 for AlgorithmIdentifier {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block])
-> Result<(AlgorithmIdentifier,&[ASN1Block]),X509ParseError>
{
match v.split_first() {
None =>
Err(X509ParseError::NotEnoughData),
Some((x, rest)) => {
let v = decode_algorithm_ident(&x)?;
Ok((v, rest))
}
}
}
}
pub fn decode_algorithm_ident(x: &ASN1Block)
-> Result<AlgorithmIdentifier,X509ParseError>
{
// AlgorithmIdentifier ::= SEQUENCE {
// algorithm OBJECT IDENTIFIER,
// parameters ANY DEFINED BY algorithm OPTIONAL }
match x {
&ASN1Block::Sequence(_, _, ref v) if v.len() >= 1 => {
match v[0] {
ASN1Block::ObjectIdentifier(_, _, ref oid) => {
if oid == oid!(1,2,840,113549,1,1,5) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA1,
algo: PublicKeyInfo::RSA
});
}
if oid == oid!(1,2,840,113549,1,1,11) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA256,
algo: PublicKeyInfo::RSA
});
}
if oid == oid!(1,2,840,113549,1,1,12) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA384,
algo: PublicKeyInfo::RSA
});
}
if oid == oid!(1,2,840,113549,1,1,13) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA512,
algo: PublicKeyInfo::RSA
});
}
if oid == oid!(1,2,840,113549,1,1,14) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA224,
algo: PublicKeyInfo::RSA
});
}
if oid == oid!(1,2,840,10040,4,3) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA1,
algo: PublicKeyInfo::DSA
});
}
if oid == oid!(1,2,840,10045,4,1) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA1,
algo: PublicKeyInfo::ECDSA
});
}
if oid == oid!(1,2,840,10045,4,3,1) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA224,
algo: PublicKeyInfo::ECDSA
});
}
if oid == oid!(1,2,840,10045,4,3,2) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA256,
algo: PublicKeyInfo::ECDSA
});
}
if oid == oid!(1,2,840,10045,4,3,3) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA384,
algo: PublicKeyInfo::ECDSA
});
}
if oid == oid!(1,2,840,10045,4,3,4) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA512,
algo: PublicKeyInfo::ECDSA
});
}
// if oid == oid!(2,16,840,1,101,3,4,2,1) {
// return Ok(AlgorithmIdentifier {
// hash: HashAlgorithm::SHA256,
// algo: PublicKeyInfo::RSAPSS
// });
// }
// if oid == oid!(2,16,840,1,101,3,4,2,2) {
// return Ok(AlgorithmIdentifier {
// hash: HashAlgorithm::SHA384,
// algo: PublicKeyInfo::RSAPSS
// });
// }
// if oid == oid!(2,16,840,1,101,3,4,2,3) {
// return Ok(AlgorithmIdentifier {
// hash: HashAlgorithm::SHA512,
// algo: PublicKeyInfo::RSAPSS
// });
// }
// if oid == oid!(2,16,840,1,101,3,4,2,4) {
// return Ok(AlgorithmIdentifier {
// hash: HashAlgorithm::SHA224,
// algo: PublicKeyInfo::RSAPSS
// });
// }
if oid == oid!(2,16,840,1,101,3,4,3,1) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA224,
algo: PublicKeyInfo::DSA
});
}
if oid == oid!(2,16,840,1,101,3,4,3,2) {
return Ok(AlgorithmIdentifier {
hash: HashAlgorithm::SHA256,
algo: PublicKeyInfo::DSA
});
}
Err(X509ParseError::UnknownAlgorithm)
}
_ =>
Err(X509ParseError::UnknownAlgorithm)
}
}
_ =>
Err(X509ParseError::IllFormedAlgoInfo)
}
}
pub enum SigAlgEncodeError {
ASN1Error(ASN1EncodeErr),
InvalidDSAValue, InvalidHash
}
impl From<ASN1EncodeErr> for SigAlgEncodeError {
fn from(e: ASN1EncodeErr) -> SigAlgEncodeError {
SigAlgEncodeError::ASN1Error(e)
}
}
impl ToASN1 for AlgorithmIdentifier {
type Error = SigAlgEncodeError;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,SigAlgEncodeError>
{
let block = encode_algorithm_ident(c, self)?;
Ok(vec![block])
}
}
fn encode_algorithm_ident(c: ASN1Class, x: &AlgorithmIdentifier)
-> Result<ASN1Block,SigAlgEncodeError>
{
match x.algo {
PublicKeyInfo::RSA => {
match x.hash {
HashAlgorithm::SHA1 => {
let o = oid!(1,2,840,113549,1,1,5);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA224 => {
let o = oid!(1,2,840,113549,1,1,14);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA256 => {
let o = oid!(1,2,840,113549,1,1,11);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA384 => {
let o = oid!(1,2,840,113549,1,1,12);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA512 => {
let o = oid!(1,2,840,113549,1,1,13);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
}
}
PublicKeyInfo::DSA => {
match x.hash {
HashAlgorithm::SHA1 => {
let o = oid!(1,2,840,10040,4,3);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA224 => {
let o = oid!(2,16,840,1,101,3,4,3,1);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA256 => {
let o = oid!(2,16,840,1,101,3,4,3,2);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
_ =>
Err(SigAlgEncodeError::InvalidHash),
}
}
PublicKeyInfo::ECDSA=> {
match x.hash {
HashAlgorithm::SHA1 => {
let o = oid!(1,2,840,10045,4,1);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA224 => {
let o = oid!(1,2,840,10045,4,3,1);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA256 => {
let o = oid!(1,2,840,10045,4,3,2);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA384 => {
let o = oid!(1,2,840,10045,4,3,3);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
HashAlgorithm::SHA512 => {
let o = oid!(1,2,840,10045,4,3,4);
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
}
}
}
}
}
#[cfg(test)]
mod test {
use quickcheck::{Arbitrary,Gen};
use rand::prelude::SliceRandom;
use super::*;
const RSA1: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA1,
algo: PublicKeyInfo::RSA
};
const RSA224: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA224,
algo: PublicKeyInfo::RSA
};
const RSA256: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA256,
algo: PublicKeyInfo::RSA
};
const RSA384: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA384,
algo: PublicKeyInfo::RSA
};
const RSA512: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA512,
algo: PublicKeyInfo::RSA
};
const DSA1: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA1,
algo: PublicKeyInfo::DSA
};
const DSA224: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA224,
algo: PublicKeyInfo::DSA
};
const DSA256: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA256,
algo: PublicKeyInfo::DSA
};
const EC1: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA1,
algo: PublicKeyInfo::ECDSA
};
const EC224: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA224,
algo: PublicKeyInfo::ECDSA
};
const EC256: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA256,
algo: PublicKeyInfo::ECDSA
};
const EC384: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA384,
algo: PublicKeyInfo::ECDSA
};
const EC512: AlgorithmIdentifier =
AlgorithmIdentifier{
hash: HashAlgorithm::SHA512,
algo: PublicKeyInfo::ECDSA
};
impl Arbitrary for AlgorithmIdentifier {
fn arbitrary<G: Gen>(g: &mut G) -> AlgorithmIdentifier {
let opts = [RSA1, RSA224, RSA256, RSA384, RSA512,
DSA1, DSA224, DSA256,
EC1, EC224, EC256, EC384, EC512];
opts.choose(g).unwrap().clone()
}
}
quickcheck!{
fn algident_roundtrips(v: AlgorithmIdentifier) -> bool {
match encode_algorithm_ident(ASN1Class::Universal, &v) {
Err(_) =>
false,
Ok(block) => {
match decode_algorithm_ident(&block) {
Err(_) =>
false,
Ok(v2) =>
v == v2
}
}
}
}
}
}

View File

@@ -1,370 +0,0 @@
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
use std::ops::Index;
use x509::error::X509ParseError;
pub use x509::name::X520Name;
/// All of the various bits of information that are encoded within an x.509
/// certificate.
#[derive(Clone,Debug)]
pub struct InfoBlock {
pub fields: Vec<AttributeTypeValue>
}
const EMPTY_STRING: &'static str = "";
impl Index<X520Name> for InfoBlock {
type Output = str;
fn index(&self, name: X520Name) -> &str {
for atv in self.fields.iter() {
if name == atv.attrtype {
return &atv.value;
}
}
&EMPTY_STRING
}
}
impl PartialEq for InfoBlock {
fn eq(&self, other: &InfoBlock) -> bool {
for x in self.fields.iter() {
if !other.fields.contains(x) {
return false;
}
}
for x in other.fields.iter() {
if !self.fields.contains(x) {
return false;
}
}
true
}
}
fn decode_info_block(x: &ASN1Block)
-> Result<InfoBlock,X509ParseError>
{
// Name ::= CHOICE { -- only one possibility for now --
// rdnSequence RDNSequence }
//
// RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
//
// RelativeDistinguishedName ::=
// SET SIZE (1..MAX) OF AttributeTypeAndValue
match x {
&ASN1Block::Sequence(_, _, ref items) => {
let mut atvs = Vec::new();
for set in items.iter() {
match set {
&ASN1Block::Set(_, _, ref setitems) => {
for atv in setitems.iter() {
let v = decode_attribute_type_value(atv)?;
atvs.push(v);
}
}
_ =>
return Err(X509ParseError::IllFormedInfoBlock)
}
}
Ok(InfoBlock{ fields: atvs })
}
_ =>
Err(X509ParseError::IllFormedInfoBlock)
}
}
impl FromASN1 for InfoBlock {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block])
-> Result<(InfoBlock,&[ASN1Block]),X509ParseError>
{
match v.split_first() {
None =>
Err(X509ParseError::NotEnoughData),
Some((x, rest)) => {
let v = decode_info_block(&x)?;
Ok((v, rest))
}
}
}
}
fn encode_info_block(c: ASN1Class, b: &InfoBlock)
-> Result<ASN1Block,ASN1EncodeErr>
{
let mut encoded_fields = Vec::with_capacity(b.fields.len());
for fld in b.fields.iter() {
let val = encode_attribute_type_value(c, fld)?;
encoded_fields.push(val);
}
let set = ASN1Block::Set(c, 0, encoded_fields);
Ok(ASN1Block::Sequence(c, 0, vec![set]))
}
impl ToASN1 for InfoBlock {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let block = encode_info_block(c, self)?;
Ok(vec![block])
}
}
/// An attribute within an x.509 key and its associated string value.
#[derive(Clone,Debug,PartialEq)]
pub struct AttributeTypeValue {
pub attrtype: X520Name,
pub value: String
}
fn decode_attribute_type_value(x: &ASN1Block)
-> Result<AttributeTypeValue,X509ParseError>
{
// AttributeTypeAndValue ::= SEQUENCE {
// type AttributeType,
// value AttributeValue }
match x {
&ASN1Block::Sequence(_, _, ref xs) => {
let (name, rest) = X520Name::from_asn1(xs)?;
match rest.first() {
None => Err(X509ParseError::NotEnoughData),
Some(ref x) => {
let atvstr = get_atv_string(name, x)?;
Ok(AttributeTypeValue{
attrtype: name,
value: atvstr
})
}
}
}
_ =>
Err(X509ParseError::IllFormedAttrTypeValue)
}
}
impl FromASN1 for AttributeTypeValue {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block])
-> Result<(AttributeTypeValue,&[ASN1Block]),X509ParseError>
{
match v.split_first() {
None =>
Err(X509ParseError::NotEnoughData),
Some((x, rest)) => {
let v = decode_attribute_type_value(&x)?;
Ok((v, rest))
}
}
}
}
fn encode_attribute_type_value(c: ASN1Class, x: &AttributeTypeValue)
-> Result<ASN1Block,ASN1EncodeErr>
{
let mut resvec = x.attrtype.to_asn1_class(c)?;
let value = match x.attrtype {
X520Name::CountryName =>
ASN1Block::PrintableString(c,0,x.value.clone()),
X520Name::SerialNumber =>
ASN1Block::PrintableString(c,0,x.value.clone()),
X520Name::DomainComponent =>
ASN1Block::IA5String(c,0,x.value.clone()),
X520Name::EmailAddress =>
ASN1Block::IA5String(c,0,x.value.clone()),
_ =>
ASN1Block::UTF8String(c,0,x.value.clone())
};
resvec.push(value);
Ok(ASN1Block::Sequence(c, 0, resvec))
}
impl ToASN1 for AttributeTypeValue {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let block = encode_attribute_type_value(c, self)?;
Ok(vec![block])
}
}
fn get_atv_string(n: X520Name, x: &ASN1Block)
-> Result<String,X509ParseError>
{
match n {
X520Name::CountryName => {
let res = get_printable_val(x)?;
if res.len() != 2 {
return Err(X509ParseError::IllegalStringValue);
}
Ok(res)
}
X520Name::SerialNumber => get_printable_val(x),
X520Name::DomainComponent => get_ia5_val(x),
X520Name::EmailAddress => get_ia5_val(x),
_ => get_string_val(x),
}
}
fn get_string_val(a: &ASN1Block) -> Result<String,X509ParseError>
{
match a {
&ASN1Block::TeletexString(_,_,ref v) => Ok(v.clone()),
&ASN1Block::PrintableString(_,_,ref v) => Ok(v.clone()),
&ASN1Block::UniversalString(_,_,ref v) => Ok(v.clone()),
&ASN1Block::UTF8String(_,_,ref v) => Ok(v.clone()),
&ASN1Block::BMPString(_,_,ref v) => Ok(v.clone()),
_ =>
Err(X509ParseError::IllegalStringValue)
}
}
fn get_printable_val(a: &ASN1Block) -> Result<String,X509ParseError>
{
match a {
&ASN1Block::PrintableString(_,_,ref v) => Ok(v.clone()),
_ =>
Err(X509ParseError::IllegalStringValue)
}
}
fn get_ia5_val(a: &ASN1Block) -> Result<String,X509ParseError>
{
match a {
&ASN1Block::IA5String(_,_,ref v) => Ok(v.clone()),
_ =>
Err(X509ParseError::IllegalStringValue)
}
}
#[cfg(test)]
mod test {
use quickcheck::{Arbitrary,Gen};
use rand::Rng;
use rand::prelude::SliceRandom;
use std::iter::FromIterator;
use super::*;
impl Arbitrary for X520Name {
fn arbitrary<G: Gen>(g: &mut G) -> X520Name {
let names = vec![X520Name::Name,
X520Name::Surname,
X520Name::GivenName,
X520Name::Initials,
X520Name::GenerationQualifier,
X520Name::CommonName,
X520Name::LocalityName,
X520Name::StateOrProvinceName,
X520Name::OrganizationName,
X520Name::OrganizationalUnit,
X520Name::Title,
X520Name::DNQualifier,
X520Name::CountryName,
X520Name::SerialNumber,
X520Name::Pseudonym,
X520Name::DomainComponent,
X520Name::EmailAddress];
names.choose(g).unwrap().clone()
}
}
impl Arbitrary for AttributeTypeValue {
fn arbitrary<G: Gen>(g: &mut G) -> AttributeTypeValue {
let name = X520Name::arbitrary(g);
let val = match name {
X520Name::CountryName => {
let mut base = gen_printable(g);
base.push('U');
base.push('S');
base.truncate(2);
base
}
X520Name::SerialNumber => gen_printable(g),
X520Name::DomainComponent => gen_ia5(g),
X520Name::EmailAddress => gen_ia5(g),
_ => gen_utf8(g)
};
AttributeTypeValue{ attrtype: name, value: val }
}
}
const PRINTABLE_CHARS: &'static str =
"ABCDEFGHIJKLMOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'()+,-./:=? ";
fn gen_printable<G: Gen>(g: &mut G) -> String {
let count = g.gen_range(0, 384);
let mut items = Vec::with_capacity(count);
for _ in 0..count {
let v = PRINTABLE_CHARS.as_bytes().choose(g).unwrap();
items.push(*v as char);
}
String::from_iter(items.iter())
}
fn gen_ia5<G: Gen>(g: &mut G) -> String {
let count = g.gen_range(0, 384);
let mut items = Vec::with_capacity(count);
for _ in 0..count {
items.push(g.gen::<u8>() as char);
}
String::from_iter(items.iter())
}
fn gen_utf8<G: Gen>(g: &mut G) -> String {
String::arbitrary(g)
}
impl Arbitrary for InfoBlock {
fn arbitrary<G: Gen>(g: &mut G) -> InfoBlock {
let count = g.gen_range(0,12);
let mut items = Vec::with_capacity(count);
let mut names = Vec::with_capacity(count);
while items.len() < count {
let atv = AttributeTypeValue::arbitrary(g);
if !names.contains(&atv.attrtype) {
names.push(atv.attrtype);
items.push(atv);
}
}
InfoBlock{ fields: items }
}
}
quickcheck! {
fn attrtypeval_roundtrips(v: AttributeTypeValue) -> bool {
match encode_attribute_type_value(ASN1Class::Universal, &v) {
Err(_) => false,
Ok(bstr) =>
match decode_attribute_type_value(&bstr) {
Err(_) => false,
Ok(v2) => v == v2
}
}
}
fn infoblock_roundtrips(v: InfoBlock) -> bool {
match encode_info_block(ASN1Class::Universal, &v) {
Err(_) => false,
Ok(bstr) =>
match decode_info_block(&bstr) {
Err(_) => false,
Ok(v2) => v == v2
}
}
}
}
}

View File

@@ -1,53 +0,0 @@
use dsa::rfc6979::DSADecodeError;
use ecdsa::ECDSADecodeErr;
use rsa::RSAError;
use simple_asn1::{ASN1DecodeErr,ASN1EncodeErr};
/// The error type for parsing and validating an X.509 certificate.
#[derive(Debug)]
pub enum X509ParseError {
ASN1DecodeError(ASN1DecodeErr), ASN1EncodeError(ASN1EncodeErr),
RSAError(RSAError), DSADecodeError(DSADecodeError), ECDSADecodeError(ECDSADecodeErr),
RSASignatureWrong, DSASignatureWrong,
NotEnoughData,
IllFormedName, IllFormedAttrTypeValue, IllFormedInfoBlock,
IllFormedValidity, IllFormedCertificateInfo, IllFormedSerialNumber,
IllFormedAlgoInfo, IllFormedKey, IllFormedEverything,
IllegalStringValue, NoSerialNumber, InvalidDSAInfo, ItemNotFound,
UnknownAlgorithm, InvalidRSAKey, InvalidDSAKey, InvalidSignatureData,
InvalidSignatureHash, InvalidECDSAKey, InvalidPointForm,
UnknownEllipticCurve,
CompressedPointUnsupported,
KeyNotFound,
SignatureNotFound, SignatureVerificationFailed
}
impl From<ASN1DecodeErr> for X509ParseError {
fn from(e: ASN1DecodeErr) -> X509ParseError {
X509ParseError::ASN1DecodeError(e)
}
}
impl From<ASN1EncodeErr> for X509ParseError {
fn from(e: ASN1EncodeErr) -> X509ParseError {
X509ParseError::ASN1EncodeError(e)
}
}
impl From<RSAError> for X509ParseError {
fn from(e: RSAError) -> X509ParseError {
X509ParseError::RSAError(e)
}
}
impl From<ECDSADecodeErr> for X509ParseError {
fn from(e: ECDSADecodeErr) -> X509ParseError {
X509ParseError::ECDSADecodeError(e)
}
}
impl From<DSADecodeError> for X509ParseError {
fn from(e: DSADecodeError) -> X509ParseError {
X509ParseError::DSADecodeError(e)
}
}

View File

@@ -1,197 +0,0 @@
use num::{BigInt,BigUint,One,ToPrimitive,Zero};
use num::bigint::ToBigInt;
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
use x509::error::X509ParseError;
/// Which version of x.509 certificate this is.
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum X509Version { V1, V2, V3 }
fn decode_version(bs: &[ASN1Block])
-> Result<(X509Version,&[ASN1Block]),X509ParseError>
{
match bs.split_first() {
Some((&ASN1Block::Integer(_, _, ref v), rest)) => {
match v.to_u8() {
Some(0) => Ok((X509Version::V1, rest)),
Some(1) => Ok((X509Version::V2, rest)),
Some(2) => Ok((X509Version::V3, rest)),
_ => Ok((X509Version::V1, &bs))
}
}
_ =>
Err(X509ParseError::NotEnoughData)
}
}
impl FromASN1 for X509Version {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block])
-> Result<(X509Version,&[ASN1Block]),X509ParseError>
{
decode_version(v)
}
}
fn encode_version(c: ASN1Class, v: X509Version) -> Vec<ASN1Block> {
match v {
X509Version::V1 => {
let zero: BigInt = Zero::zero();
let block = ASN1Block::Integer(c, 0, zero);
vec![block]
}
X509Version::V2 => {
let one: BigInt = One::one();
let block = ASN1Block::Integer(c, 0, one);
vec![block]
}
X509Version::V3 => {
let two: BigInt = BigInt::from(2 as u64);
let block = ASN1Block::Integer(c, 0, two);
vec![block]
}
}
}
impl ToASN1 for X509Version {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
Ok(encode_version(c, *self))
}
}
/******************************************************************************/
/// The serial number for this certificate.
#[derive(Clone,Debug,PartialEq)]
pub struct X509Serial {
num: BigUint
}
fn decode_serial(x: &ASN1Block)
-> Result<X509Serial,X509ParseError>
{
match x {
&ASN1Block::Integer(_, _, ref v) => {
match v.to_biguint() {
None =>
Err(X509ParseError::IllFormedSerialNumber),
Some(n) =>
Ok(X509Serial{ num: n })
}
}
_ =>
Err(X509ParseError::NoSerialNumber)
}
}
impl FromASN1 for X509Serial {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block])
-> Result<(X509Serial,&[ASN1Block]),X509ParseError>
{
match v.split_first() {
None =>
Err(X509ParseError::NoSerialNumber),
Some((x, rest)) => {
let v = decode_serial(x)?;
Ok((v, rest))
}
}
}
}
pub enum SerialEncodeErr { ASN1Error(ASN1EncodeErr), InvalidSerialNumber }
impl From<ASN1EncodeErr> for SerialEncodeErr {
fn from(e: ASN1EncodeErr) -> SerialEncodeErr {
SerialEncodeErr::ASN1Error(e)
}
}
fn encode_serial(c: ASN1Class, serial: &X509Serial)
-> Result<ASN1Block,SerialEncodeErr>
{
match serial.num.to_bigint() {
None =>
Err(SerialEncodeErr::InvalidSerialNumber),
Some(n) =>
Ok(ASN1Block::Integer(c, 0, n))
}
}
impl ToASN1 for X509Serial {
type Error = SerialEncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,SerialEncodeErr>
{
let v = encode_serial(c, self)?;
Ok(vec![v])
}
}
pub fn decode_signature(x: &ASN1Block)
-> Result<Vec<u8>,X509ParseError>
{
match x {
&ASN1Block::BitString(_, _, size, ref sig) if size % 8 == 0 => {
Ok(sig.to_vec())
}
_ =>
Err(X509ParseError::SignatureNotFound)
}
}
#[cfg(test)]
mod test {
use quickcheck::{Arbitrary,Gen};
use rand::Rng;
use rand::distributions::Uniform;
use super::*;
fn check_version_roundtrip(v: X509Version) {
let blocks = encode_version(ASN1Class::Universal, v);
match decode_version(&blocks) {
Err(_) =>
assert!(false),
Ok((v2,_)) =>
assert_eq!(v, v2)
}
}
#[test]
fn versions_roundtrip() {
check_version_roundtrip(X509Version::V1);
check_version_roundtrip(X509Version::V2);
check_version_roundtrip(X509Version::V3);
}
impl Arbitrary for X509Serial {
fn arbitrary<G: Gen>(g: &mut G) -> X509Serial {
let count = g.gen_range(0,16);
let dist = Uniform::new_inclusive(0,255);
let bits = g.sample_iter(&dist).take(count).collect();
let val = BigUint::new(bits);
X509Serial{ num: val }
}
}
quickcheck! {
fn serial_roundtrips(s: X509Serial) -> bool {
match encode_serial(ASN1Class::Universal, &s) {
Err(_) => false,
Ok(block) =>
match decode_serial(&block) {
Err(_) => false,
Ok(s2) => s == s2
}
}
}
}
}

View File

@@ -1,295 +0,0 @@
mod algident;
mod atv;
mod error;
mod misc;
mod name;
mod publickey;
mod validity;
use dsa::DSAPublic;
use ecdsa::ECDSAPublic;
use rsa::{SIGNING_HASH_SHA1,SIGNING_HASH_SHA224,SIGNING_HASH_SHA256,SIGNING_HASH_SHA384,SIGNING_HASH_SHA512};
use sha::{SHA1,SHA224,SHA256,SHA384,SHA512};
use simple_asn1::{ASN1Block,FromASN1,der_decode,from_der};
pub use x509::validity::Validity;
pub use x509::algident::{AlgorithmIdentifier,HashAlgorithm,PublicKeyInfo};
use x509::algident::{decode_algorithm_ident};
pub use x509::atv::InfoBlock;
use x509::error::X509ParseError;
pub use x509::misc::{X509Serial,X509Version};
use x509::misc::{decode_signature};
pub use x509::publickey::X509PublicKey;
/*******************************************************************************
*
* The actual certificate data type and methods
*
******************************************************************************/
/// The type of an X.509 certificate.
pub struct GenericCertificate {
pub version: X509Version,
pub serial: X509Serial,
pub signature_alg: AlgorithmIdentifier,
pub issuer: InfoBlock,
pub subject: InfoBlock,
pub validity: Validity,
pub subject_key: X509PublicKey,
pub extensions: Vec<()>
}
fn decode_certificate(x: &ASN1Block)
-> Result<GenericCertificate,X509ParseError>
{
//
// TBSCertificate ::= SEQUENCE {
// version [0] Version DEFAULT v1,
// serialNumber CertificateSerialNumber,
// signature AlgorithmIdentifier,
// issuer Name,
// validity Validity,
// subject Name,
// subjectPublicKeyInfo SubjectPublicKeyInfo,
// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
// -- If present, version MUST be v2 or v3
// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
// -- If present, version MUST be v2 or v3
// extensions [3] Extensions OPTIONAL
// -- If present, version MUST be v3 -- }
//
match x {
&ASN1Block::Sequence(_, _, ref b0) => {
let (version, b1) = X509Version::from_asn1(b0)?;
let (serial, b2) = X509Serial::from_asn1(b1)?;
let (ident, b3) = AlgorithmIdentifier::from_asn1(b2)?;
let (issuer, b4) = InfoBlock::from_asn1(b3)?;
let (validity, b5) = Validity::from_asn1(b4)?;
let (subject, b6) = InfoBlock::from_asn1(b5)?;
let (subkey, _ ) = X509PublicKey::from_asn1(b6)?;
Ok(GenericCertificate {
version: version,
serial: serial,
signature_alg: ident,
issuer: issuer,
subject: subject,
validity: validity,
subject_key: subkey,
extensions: vec![]
})
}
_ =>
Err(X509ParseError::IllFormedCertificateInfo)
}
}
/*******************************************************************************
*
* X.509 parsing routines
*
******************************************************************************/
/// Parse an X.590 certificate in memory into a generic certificate that can
/// be used by a program.
pub fn parse_x509(buffer: &[u8]) -> Result<GenericCertificate,X509ParseError> {
let blocks = from_der(&buffer[..])?;
match blocks.first() {
None =>
Err(X509ParseError::NotEnoughData),
Some(&ASN1Block::Sequence(_, _, ref x)) => {
let cert = decode_certificate(&x[0])?;
let cert_block_start = x[0].offset();
let cert_block_end = x[1].offset();
let cert_block = &buffer[cert_block_start..cert_block_end];
let alginfo = decode_algorithm_ident(&x[1])?;
let sig = decode_signature(&x[2])?;
check_signature(&alginfo, &cert.subject_key, cert_block, sig)?;
Ok(cert)
}
Some(_) =>
Err(X509ParseError::IllFormedEverything)
}
}
fn check_signature(alg: &AlgorithmIdentifier,
key: &X509PublicKey,
block: &[u8],
sig: Vec<u8>)
-> Result<(),X509ParseError>
{
match (alg.algo, key) {
(PublicKeyInfo::RSA, &X509PublicKey::RSA(ref key)) => {
let sighash = match alg.hash {
HashAlgorithm::SHA1 => &SIGNING_HASH_SHA1,
HashAlgorithm::SHA224 => &SIGNING_HASH_SHA224,
HashAlgorithm::SHA256 => &SIGNING_HASH_SHA256,
HashAlgorithm::SHA384 => &SIGNING_HASH_SHA384,
HashAlgorithm::SHA512 => &SIGNING_HASH_SHA512,
};
if !key.verify(sighash, block, &sig) {
return Err(X509ParseError::RSASignatureWrong);
}
Ok(())
}
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL1024N160(ref key))) => {
let dsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1
if key.verify::<SHA1>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA224
if key.verify::<SHA224>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &dsa_sig) =>
Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL2048N224(ref key))) => {
let dsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1
if key.verify::<SHA1>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA224
if key.verify::<SHA224>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &dsa_sig) =>
Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL2048N256(ref key))) => {
let dsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1
if key.verify::<SHA1>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA224
if key.verify::<SHA224>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &dsa_sig) =>
Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL3072N256(ref key))) => {
let dsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1
if key.verify::<SHA1>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA224
if key.verify::<SHA224>(block, &dsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &dsa_sig) =>
Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P192(ref key))) => {
let ecdsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA224 if key.verify::<SHA224>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P224(ref key))) => {
let ecdsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA224 if key.verify::<SHA224>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P256(ref key))) => {
let ecdsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA224 if key.verify::<SHA224>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P384(ref key))) => {
let ecdsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA224 if key.verify::<SHA224>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P521(ref key))) => {
let ecdsa_sig = der_decode(&sig)?;
match alg.hash {
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA224 if key.verify::<SHA224>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
_ =>
Err(X509ParseError::InvalidSignatureHash)
}
}
_ =>
Err(X509ParseError::InvalidSignatureData)
}
}
/*******************************************************************************
*
* Testing is for winners!
*
******************************************************************************/
#[cfg(test)]
mod tests {
use std::fs::File;
use std::io::Read;
use super::*;
fn can_parse(f: &str) -> Result<GenericCertificate,X509ParseError> {
let mut fd = File::open(f).unwrap();
let mut buffer = Vec::new();
let _amt = fd.read_to_end(&mut buffer);
parse_x509(&buffer)
}
#[test]
fn rsa_tests() {
assert!(can_parse("testdata/x509/rsa2048-1.der").is_ok());
assert!(can_parse("testdata/x509/rsa2048-2.der").is_ok());
assert!(can_parse("testdata/x509/rsa4096-1.der").is_ok());
assert!(can_parse("testdata/x509/rsa4096-2.der").is_ok());
assert!(can_parse("testdata/x509/rsa4096-3.der").is_ok());
}
#[test]
fn dsa_tests() {
assert!(can_parse("testdata/x509/dsa2048-1.der").is_ok());
assert!(can_parse("testdata/x509/dsa2048-2.der").is_ok());
assert!(can_parse("testdata/x509/dsa3072-1.der").is_ok());
assert!(can_parse("testdata/x509/dsa3072-2.der").is_ok());
}
#[test]
fn ecc_tests() {
assert!(can_parse("testdata/x509/ec384-1.der").is_ok());
assert!(can_parse("testdata/x509/ec384-2.der").is_ok());
assert!(can_parse("testdata/x509/ec384-3.der").is_ok());
}
}

View File

@@ -1,138 +0,0 @@
use num::BigUint;
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
use x509::error::X509ParseError;
/// One of the various attributes that can be encoded within an x.509 name. To
/// see one of these paired with its value, consider `AttributeTypeValue`.
#[derive(Copy,Clone,Debug,Eq,Hash,PartialEq)]
pub enum X520Name {
Name, Surname, GivenName, Initials, GenerationQualifier, CommonName,
LocalityName, StateOrProvinceName, OrganizationName, OrganizationalUnit,
Title, DNQualifier, CountryName, SerialNumber, Pseudonym, DomainComponent,
EmailAddress
}
impl FromASN1 for X520Name {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block])
-> Result<(X520Name,&[ASN1Block]),X509ParseError>
{
match v.split_first() {
None =>
Err(X509ParseError::NotEnoughData),
Some((x,rest)) => {
let name = decode_name(&x)?;
Ok((name,rest))
}
}
}
}
fn decode_name(val: &ASN1Block)
-> Result<X520Name,X509ParseError>
{
match val {
&ASN1Block::ObjectIdentifier(_, _, ref oid) => {
if oid == oid!(2,5,4,41) {return Ok(X520Name::Name) }
if oid == oid!(2,5,4,4) {return Ok(X520Name::Surname) }
if oid == oid!(2,5,4,42) {return Ok(X520Name::GivenName) }
if oid == oid!(2,5,4,43) {return Ok(X520Name::Initials) }
if oid == oid!(2,5,4,44) {return Ok(X520Name::GenerationQualifier)}
if oid == oid!(2,5,4,3) {return Ok(X520Name::CommonName) }
if oid == oid!(2,5,4,7) {return Ok(X520Name::LocalityName) }
if oid == oid!(2,5,4,8) {return Ok(X520Name::StateOrProvinceName)}
if oid == oid!(2,5,4,10) {return Ok(X520Name::OrganizationName) }
if oid == oid!(2,5,4,11) {return Ok(X520Name::OrganizationalUnit) }
if oid == oid!(2,5,4,12) {return Ok(X520Name::Title) }
if oid == oid!(2,5,4,46) {return Ok(X520Name::DNQualifier) }
if oid == oid!(2,5,4,6) {return Ok(X520Name::CountryName) }
if oid == oid!(2,5,4,5) {return Ok(X520Name::SerialNumber) }
if oid == oid!(2,5,4,65) {return Ok(X520Name::Pseudonym) }
if oid == oid!(0,9,2342,19200300,100,1,25) {
return Ok(X520Name::DomainComponent);
}
if oid == oid!(1,2,840,113549,1,9,1) {
return Ok(X520Name::EmailAddress);
}
Err(X509ParseError::IllFormedName)
}
_ =>
Err(X509ParseError::IllFormedName)
}
}
impl ToASN1 for X520Name {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let block = encode_name(c, *self);
Ok(vec![block])
}
}
fn encode_name(class: ASN1Class, name: X520Name)
-> ASN1Block
{
let oid = match name {
X520Name::Name => oid!(2,5,4,41),
X520Name::Surname => oid!(2,5,4,4),
X520Name::GivenName => oid!(2,5,4,42),
X520Name::Initials => oid!(2,5,4,43),
X520Name::GenerationQualifier => oid!(2,5,4,44),
X520Name::CommonName => oid!(2,5,4,3),
X520Name::LocalityName => oid!(2,5,4,7),
X520Name::StateOrProvinceName => oid!(2,5,4,8),
X520Name::OrganizationName => oid!(2,5,4,10),
X520Name::OrganizationalUnit => oid!(2,5,4,11),
X520Name::Title => oid!(2,5,4,12),
X520Name::DNQualifier => oid!(2,5,4,46),
X520Name::CountryName => oid!(2,5,4,6),
X520Name::SerialNumber => oid!(2,5,4,5),
X520Name::Pseudonym => oid!(2,5,4,65),
X520Name::DomainComponent => oid!(0,9,2342,19200300,100,1,25),
X520Name::EmailAddress => oid!(1,2,840,113549,1,9,1)
};
ASN1Block::ObjectIdentifier(class, 0, oid)
}
#[cfg(test)]
mod tests {
use super::*;
fn encdec_test(n: X520Name) {
let block = encode_name(ASN1Class::Universal, n);
let vec = vec![block];
match X520Name::from_asn1(&vec) {
Err(_) =>
assert!(false),
Ok((m, _)) =>
assert_eq!(n,m)
}
}
#[test]
fn name_encoding_roundtrips() {
encdec_test(X520Name::Name);
encdec_test(X520Name::Surname);
encdec_test(X520Name::GivenName);
encdec_test(X520Name::Initials);
encdec_test(X520Name::GenerationQualifier);
encdec_test(X520Name::CommonName);
encdec_test(X520Name::LocalityName);
encdec_test(X520Name::StateOrProvinceName);
encdec_test(X520Name::OrganizationName);
encdec_test(X520Name::OrganizationalUnit);
encdec_test(X520Name::Title);
encdec_test(X520Name::DNQualifier);
encdec_test(X520Name::CountryName);
encdec_test(X520Name::SerialNumber);
encdec_test(X520Name::Pseudonym);
encdec_test(X520Name::DomainComponent);
encdec_test(X520Name::EmailAddress);
}
}

View File

@@ -1,330 +0,0 @@
use cryptonum::unsigned::{U3072,U2048,U1024,U256,U192};
use dsa::{DSAPublic,DSAPublicKey,DSAParameters};
use dsa::{L3072N256,L2048N256,L2048N224,L1024N160};
use ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPublicKey};
use ecdsa::{P192,P224,P256,P384,P521};
use num::BigUint;
use rsa::RSAPublic;
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1,
der_decode,der_encode,from_der};
use utils::TranslateNums;
use x509::error::X509ParseError;
/// A general type that includes all the supported public key types that we
/// could read in an x.509 certificate.
pub enum X509PublicKey {
DSA(DSAPublic),
RSA(RSAPublic),
ECDSA(ECDSAPublic)
}
impl From<X509PublicKey> for Option<DSAPublic> {
fn from(x: X509PublicKey) -> Option<DSAPublic> {
match x {
X509PublicKey::DSA(x) => Some(x),
_ => None
}
}
}
impl From<X509PublicKey> for Option<RSAPublic> {
fn from(x: X509PublicKey) -> Option<RSAPublic> {
match x {
X509PublicKey::RSA(x) => Some(x),
_ => None
}
}
}
impl From<X509PublicKey> for Option<ECDSAPublic> {
fn from(x: X509PublicKey) -> Option<ECDSAPublic> {
match x {
X509PublicKey::ECDSA(x) => Some(x),
_ => None
}
}
}
pub enum X509EncodeErr {
ASN1EncodeErr(ASN1EncodeErr),
ECDSAEncodeErr(ECDSAEncodeErr)
}
impl From<ASN1EncodeErr> for X509EncodeErr {
fn from(x: ASN1EncodeErr) -> X509EncodeErr {
X509EncodeErr::ASN1EncodeErr(x)
}
}
impl From<ECDSAEncodeErr> for X509EncodeErr {
fn from(x: ECDSAEncodeErr) -> X509EncodeErr {
X509EncodeErr::ECDSAEncodeErr(x)
}
}
impl ToASN1 for X509PublicKey {
type Error = X509EncodeErr;
fn to_asn1_class(&self, c: ASN1Class) -> Result<Vec<ASN1Block>,X509EncodeErr> {
let block = match self {
X509PublicKey::RSA(x) => encode_rsa_key(c, x)?,
X509PublicKey::DSA(x) => encode_dsa_key(c, x)?,
X509PublicKey::ECDSA(x) => encode_ecdsa_key(c, x)?,
};
Ok(vec![block])
}
}
impl FromASN1 for X509PublicKey {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block]) -> Result<(X509PublicKey, &[ASN1Block]), Self::Error>
{
let (block, rest) = v.split_first().ok_or(X509ParseError::NotEnoughData)?;
// SubjectPublicKeyInfo ::= SEQUENCE {
// algorithm AlgorithmIdentifier,
// subjectPublicKey BIT STRING }
if let &ASN1Block::Sequence(_, _, ref info) = block {
let (id, malginfo) = strip_algident(&info[0])?;
if id == oid!(1,2,840,113549,1,1,1) {
let key = decode_rsa_key(&info[1])?;
return Ok((X509PublicKey::RSA(key), rest));
}
if id == oid!(1,2,840,10040,4,1) {
if let Some(alginfo) = malginfo {
let key = decode_dsa_key(alginfo, &info[1])?;
return Ok((X509PublicKey::DSA(key), rest));
}
}
if id == oid!(1,2,840,10045,2,1) {
if let Some(alginfo) = malginfo {
let key = decode_ecdsa_key(alginfo, &info[1..])?;
return Ok((X509PublicKey::ECDSA(key), rest));
}
}
}
Err(X509ParseError::IllFormedKey)
}
}
//------------------------------------------------------------------------------
//
// RSA Public Key encoding / decoding
//
//------------------------------------------------------------------------------
fn encode_rsa_key(c: ASN1Class, x: &RSAPublic) -> Result<ASN1Block,ASN1EncodeErr>
{
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,113549,1,1,1));
let bstr = der_encode(x)?;
let objkey = ASN1Block::BitString(c, 0, bstr.len() * 8, bstr);
Ok(ASN1Block::Sequence(c, 0, vec![objoid, objkey]))
}
fn decode_rsa_key(x: &ASN1Block) -> Result<RSAPublic,X509ParseError>
{
if let &ASN1Block::BitString(_, _, _, ref bstr) = x {
der_decode(bstr).map_err(|x| X509ParseError::RSAError(x))
} else {
Err(X509ParseError::NotEnoughData)
}
}
//------------------------------------------------------------------------------
//
// DSA Public Key encoding / decoding
//
//------------------------------------------------------------------------------
fn encode_dsa_key(c: ASN1Class, x: &DSAPublic) -> Result<ASN1Block,ASN1EncodeErr>
{
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,10040,4,1));
let (mut objparams, bstr) = match x {
DSAPublic::DSAPublicL1024N160(x) => (x.params.to_asn1_class(c)?, der_encode(x)?),
DSAPublic::DSAPublicL2048N224(x) => (x.params.to_asn1_class(c)?, der_encode(x)?),
DSAPublic::DSAPublicL2048N256(x) => (x.params.to_asn1_class(c)?, der_encode(x)?),
DSAPublic::DSAPublicL3072N256(x) => (x.params.to_asn1_class(c)?, der_encode(x)?)
};
objparams.insert(0, objoid);
let headinfo = ASN1Block::Sequence(c, 0, objparams);
let objkey = ASN1Block::BitString(c, 0, bstr.len() * 8, bstr);
Ok(ASN1Block::Sequence(c, 0, vec![headinfo, objkey]))
}
fn decode_dsa_key(info: ASN1Block, key: &ASN1Block) -> Result<DSAPublic,X509ParseError>
{
if let ASN1Block::Sequence(_, _, pqg) = info {
if pqg.len() != 3 { return Err(X509ParseError::InvalidDSAInfo); }
let puint = decode_biguint(&pqg[0])?;
let guint = decode_biguint(&pqg[1])?;
let quint = decode_biguint(&pqg[2])?;
if puint.bits() > 2048 {
let p = U3072::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
let q = U3072::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
let g = U256::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
let params = L3072N256::new(p, q, g);
if let ASN1Block::BitString(_, _, _, ybstr) = key {
let blocks = from_der(ybstr)?;
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
if let ASN1Block::Integer(_,_,ynum) = iblk {
let y = U3072::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
let key = DSAPublicKey::<L3072N256>::new(params, y);
let reskey = DSAPublic::DSAPublicL3072N256(key);
return Ok(reskey);
}
}
return Err(X509ParseError::InvalidDSAKey)
}
if puint.bits() > 1024 {
if guint.bits() > 224 {
let p = U2048::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
let q = U2048::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
let g = U256::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
let params = L2048N256::new(p, q, g);
if let ASN1Block::BitString(_, _, _, ybstr) = key {
let blocks = from_der(ybstr)?;
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
if let ASN1Block::Integer(_,_,ynum) = iblk {
let y = U2048::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
let key = DSAPublicKey::<L2048N256>::new(params, y);
let reskey = DSAPublic::DSAPublicL2048N256(key);
return Ok(reskey);
}
}
return Err(X509ParseError::InvalidDSAKey)
} else {
let p = U2048::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
let q = U2048::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
let g = U256::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
let params = L2048N224::new(p, q, g);
if let ASN1Block::BitString(_, _, _, ybstr) = key {
let blocks = from_der(ybstr)?;
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
if let ASN1Block::Integer(_,_,ynum) = iblk {
let y = U2048::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
let key = DSAPublicKey::<L2048N224>::new(params, y);
let reskey = DSAPublic::DSAPublicL2048N224(key);
return Ok(reskey);
}
}
return Err(X509ParseError::InvalidDSAKey)
}
}
let p = U1024::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
let q = U1024::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
let g = U192::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
let params = L1024N160::new(p, q, g);
if let ASN1Block::BitString(_, _, _, ybstr) = key {
let blocks = from_der(ybstr)?;
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
if let ASN1Block::Integer(_,_,ynum) = iblk {
let y = U1024::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
let key = DSAPublicKey::<L1024N160>::new(params, y);
let reskey = DSAPublic::DSAPublicL1024N160(key);
return Ok(reskey);
}
}
return Err(X509ParseError::InvalidDSAKey)
}
Err(X509ParseError::InvalidDSAInfo)
}
//------------------------------------------------------------------------------
//
// ECDSA Public Key encoding
//
//------------------------------------------------------------------------------
fn encode_ecdsa_key(c: ASN1Class, x: &ECDSAPublic) -> Result<ASN1Block,ECDSAEncodeErr>
{
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,10045,2,1));
let (base_curve_oid, mut keyvec) = match x {
ECDSAPublic::P192(k) => (oid!(1,2,840,10045,3,1,1), k.to_asn1_class(c)?),
ECDSAPublic::P224(k) => (oid!(1,3,132,0,33), k.to_asn1_class(c)?),
ECDSAPublic::P256(k) => (oid!(1,2,840,10045,3,1,7), k.to_asn1_class(c)?),
ECDSAPublic::P384(k) => (oid!(1,3,132,0,34), k.to_asn1_class(c)?),
ECDSAPublic::P521(k) => (oid!(1,3,132,0,35), k.to_asn1_class(c)?),
};
let curve_oid = ASN1Block::ObjectIdentifier(c, 0, base_curve_oid);
let header = ASN1Block::Sequence(c, 0, vec![objoid, curve_oid]);
keyvec.insert(0, header);
Ok(ASN1Block::Sequence(c, 0, keyvec))
}
fn decode_ecdsa_key(info: ASN1Block, keybls: &[ASN1Block]) -> Result<ECDSAPublic,X509ParseError>
{
if let ASN1Block::ObjectIdentifier(_, _, oid) = info {
if oid == oid!(1,2,840,10045,3,1,1) {
let (res, _) = ECCPublicKey::<P192>::from_asn1(keybls)?;
return Ok(ECDSAPublic::P192(res));
}
if oid == oid!(1,3,132,0,33) {
let (res, _) = ECCPublicKey::<P224>::from_asn1(keybls)?;
return Ok(ECDSAPublic::P224(res));
}
if oid == oid!(1,2,840,10045,3,1,7) {
let (res, _) = ECCPublicKey::<P256>::from_asn1(keybls)?;
return Ok(ECDSAPublic::P256(res));
}
if oid == oid!(1,3,132,0,34) {
let (res, _) = ECCPublicKey::<P384>::from_asn1(keybls)?;
return Ok(ECDSAPublic::P384(res));
}
if oid == oid!(1,3,132,0,35) {
let (res, _) = ECCPublicKey::<P521>::from_asn1(keybls)?;
return Ok(ECDSAPublic::P521(res));
}
}
Err(X509ParseError::UnknownEllipticCurve)
}
fn strip_algident(block: &ASN1Block)
-> Result<(OID, Option<ASN1Block>),X509ParseError>
{
match block {
&ASN1Block::ObjectIdentifier(_, _, ref oid) => {
Ok((oid.clone(), None))
}
&ASN1Block::Sequence(_, _, ref items) => {
let (oid, _) = strip_algident(&items[0])?;
Ok((oid, Some(items[1].clone())))
}
_ => Err(X509ParseError::IllFormedAlgoInfo)
}
}
fn decode_biguint(b: &ASN1Block) -> Result<BigUint,X509ParseError> {
match b {
&ASN1Block::Integer(_, _, ref v) => {
match v.to_biguint() {
Some(sn) => Ok(sn),
_ => Err(X509ParseError::InvalidDSAInfo)
}
}
_ =>
Err(X509ParseError::InvalidDSAInfo)
}
}

View File

@@ -1,119 +0,0 @@
use chrono::{DateTime,Utc};
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
use x509::error::X509ParseError;
/// The range of dates in which this certificate is valid.
#[derive(Clone,Debug,PartialEq)]
pub struct Validity {
pub not_before: DateTime<Utc>,
pub not_after: DateTime<Utc>
}
fn decode_validity_data(bs: &ASN1Block) -> Result<Validity,X509ParseError> {
// Validity ::= SEQUENCE {
// notBefore Time,
// notAfter Time }
match bs {
&ASN1Block::Sequence(_, _, ref valxs) => {
if valxs.len() != 2 {
return Err(X509ParseError::IllFormedValidity);
}
let nb = get_time(&valxs[0])?;
let na = get_time(&valxs[1])?;
Ok(Validity{ not_before: nb, not_after: na })
}
_ =>
Err(X509ParseError::IllFormedValidity)
}
}
impl FromASN1 for Validity {
type Error = X509ParseError;
fn from_asn1(v: &[ASN1Block])
-> Result<(Validity,&[ASN1Block]),X509ParseError>
{
match v.split_first() {
None =>
Err(X509ParseError::NotEnoughData),
Some((x, rest)) => {
let v = decode_validity_data(&x)?;
Ok((v, rest))
}
}
}
}
fn encode_validity_data(c: ASN1Class, v: &Validity) -> ASN1Block {
let mut vs = Vec::with_capacity(2);
vs.push(ASN1Block::GeneralizedTime(c, 0, v.not_before));
vs.push(ASN1Block::GeneralizedTime(c, 0, v.not_after));
ASN1Block::Sequence(c, 0, vs)
}
impl ToASN1 for Validity {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let block = encode_validity_data(c, self);
Ok(vec![block])
}
}
fn get_time(b: &ASN1Block) -> Result<DateTime<Utc>, X509ParseError> {
match b {
&ASN1Block::UTCTime(_, _, v) => Ok(v.clone()),
&ASN1Block::GeneralizedTime(_, _, v) => Ok(v.clone()),
_ =>
Err(X509ParseError::IllFormedValidity)
}
}
#[cfg(test)]
mod test {
use chrono::TimeZone;
use chrono::offset::LocalResult;
use quickcheck::{Arbitrary,Gen};
use rand::Rng;
use super::*;
fn arbitrary_date<G: Gen>(g: &mut G) -> DateTime<Utc> {
loop {
let y = g.gen_range(1900,3000);
let mo = g.gen_range(0,12);
let d = g.gen_range(0,31);
let h = g.gen_range(0,24);
let mi = g.gen_range(0,60);
let s = g.gen_range(0,60);
match Utc.ymd_opt(y,mo,d).and_hms_opt(h,mi,s) {
LocalResult::None =>
continue,
LocalResult::Single(x) =>
return x,
LocalResult::Ambiguous(x,_) =>
return x
}
}
}
impl Arbitrary for Validity {
fn arbitrary<G: Gen>(g: &mut G) -> Validity {
Validity {
not_before: arbitrary_date(g),
not_after: arbitrary_date(g)
}
}
}
quickcheck! {
fn validity_roundtrips(v: Validity) -> bool {
let bstr = encode_validity_data(ASN1Class::Universal, &v);
match decode_validity_data(&bstr) {
Err(_) => false,
Ok(v2) => v == v2
}
}
}
}

View File

@@ -1,2 +0,0 @@
dist/
dist-newstyle/

View File

@@ -1,84 +0,0 @@
{-# LANGUAGE PackageImports #-}
module DSA(dsaTasks)
where
import Codec.Crypto.DSA.Pure
import Crypto.Hash(Digest, SHA256, hash)
import "cryptonite" Crypto.Random(DRG(..),getRandomBytes,withDRG)
import Data.ByteArray(convert)
import qualified Data.ByteString as BS
import Data.ByteString.Lazy(ByteString)
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Map.Strict as Map
import Math(showX,showBin)
import Task(Task(..),liftTest)
import Utils(HashAlg(..),generateHash,showHash)
dsaSizes :: [(ParameterSizes, Int)]
dsaSizes = [(L1024_N160, 400),
(L2048_N224, 100),
(L2048_N256, 50),
(L3072_N256, 25)]
dsaTasks :: [Task]
dsaTasks = concatMap generateTask dsaSizes
generateTask :: (ParameterSizes, Int) -> [Task]
generateTask (s, c) = [signTest s c]
showParam :: ParameterSizes -> String
showParam L1024_N160 = "L1024N160"
showParam L2048_N224 = "L2048N224"
showParam L2048_N256 = "L2048N256"
showParam L3072_N256 = "L3072N256"
signTest :: ParameterSizes -> Int -> Task
signTest sz cnt = Task {
taskName = "DSA " ++ show sz ++ " signing",
taskFile = "../testdata/dsa/sign" ++ showParam sz ++ ".test",
taskTest = liftTest go,
taskCount = cnt
}
where
go (memory, drg0) =
case generateProbablePrimes sz drg0 sha256 Nothing of
Left _ -> goAdvance memory drg0
Right (p, q, _, drg1) ->
case generateUnverifiableGenerator p q of
Nothing -> goAdvance memory drg1
Just g ->
let params = Params p g q
in case generateKeyPairWithParams params drg1 of
Left _ -> goAdvance memory drg1
Right (pub, priv, drg2) ->
let (msg, drg3) = withDRG drg2 $ getRandomBytes =<< ((fromIntegral . BS.head) `fmap` getRandomBytes 1)
(hashf, drg4) = withDRG drg3 generateHash
in case signMessage' (translateHash hashf) kViaRFC6979 drg4 priv (BSL.fromStrict msg) of
Left _ ->
go (memory, drg4)
Right (sig, drg5) ->
let res = Map.fromList [("p", showX p),
("q", showX q),
("g", showX g),
("y", showX (public_y pub)),
("x", showX (private_x priv)),
("m", showBin msg),
("h", showHash hashf),
("r", showX (sign_r sig)),
("s", showX (sign_s sig))]
in (res, p, (memory, drg5))
--
goAdvance memory drg0 =
let (bstr, drg1) = randomBytesGenerate 37 drg0
in BS.null bstr `seq` go (memory, drg1)
--
translateHash Sha224 = Codec.Crypto.DSA.Pure.SHA224
translateHash Sha256 = Codec.Crypto.DSA.Pure.SHA256
translateHash Sha384 = Codec.Crypto.DSA.Pure.SHA384
translateHash Sha512 = Codec.Crypto.DSA.Pure.SHA512
sha256 :: ByteString -> ByteString
sha256 = BSL.fromStrict . convert' . hash . BSL.toStrict
where
convert' :: Digest SHA256 -> BS.ByteString
convert' = convert

View File

@@ -1,50 +0,0 @@
{-# LANGUAGE PackageImports #-}
module Database(
Database,
emptyDatabase,
generateNum, genSign
)
where
import "crypto-api" Crypto.Random(CryptoRandomGen(..),SystemRandom)
import "cryptonite" Crypto.Random(DRG(..))
import Data.ByteArray(convert)
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], SystemRandom)
instance DRG SystemRandom where
randomBytesGenerate x g =
case genBytes x g of
Left e -> error ("Data generation error: " ++ show e)
Right (res, g') -> (convert res, g')
emptyDatabase :: SystemRandom -> 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 1 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

View File

@@ -1,193 +0,0 @@
{-# LANGUAGE PackageImports #-}
module ECDSATesting(
ecdsaTasks
)
where
import Crypto.Hash(SHA224(..),SHA256(..),SHA384(..),SHA512(..))
import Crypto.Number.Generate(generateBetween)
import Crypto.PubKey.ECC.ECDSA(PrivateKey(..),PublicKey(..),Signature(..),signWith)
import Crypto.PubKey.ECC.Generate(generate)
import Crypto.PubKey.ECC.Prim(scalarGenerate,pointAdd,pointNegate,pointDouble,pointBaseMul,pointMul,pointAddTwoMuls)
import Crypto.PubKey.ECC.Types(Curve,CurveName(..),Point(..),common_curve,curveSizeBits,ecc_n,getCurveByName)
import "cryptonite" Crypto.Random(DRG(..),getRandomBytes,withDRG)
import qualified Data.ByteString as S
import qualified Data.Map.Strict as Map
import Math(showX,showBin)
import RFC6979(generateKStream)
import Task(Task(..),liftTest)
import Utils(HashAlg(..),generateHash,runHash,showHash)
curves :: [(String, Curve)]
curves = [("P192", getCurveByName SEC_p192r1),
("P224", getCurveByName SEC_p224r1),
("P256", getCurveByName SEC_p256r1),
("P384", getCurveByName SEC_p384r1),
("P521", getCurveByName SEC_p521r1)]
negateTest :: String -> Curve -> Task
negateTest name curve = Task {
taskName = name ++ " point negation",
taskFile = "../testdata/ecc/negate/" ++ name ++ ".test",
taskTest = liftTest 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 = liftTest 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 = liftTest 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 = liftTest go,
taskCount = 1000
}
where
go (memory0, drg0) =
let (scalar0, drg1) = withDRG drg0 (scalarGenerate curve)
(scalar1, drg2) = withDRG drg1 (scalarGenerate curve)
(negbs, drg3) = randomBytesGenerate 1 drg2
[negbyte] = S.unpack negbs
k = if odd negbyte then scalar1 else -scalar1
point = pointBaseMul curve scalar0
respnt = pointMul curve k point
in case (point, respnt) of
(PointO, _) -> go (memory0, drg3)
(_, PointO) -> go (memory0, drg3)
(Point basex basey, Point resx resy) ->
let res = Map.fromList [("x", showX basex), ("y", showX basey),
("k", showX k),
("a", showX resx), ("b", showX resy)]
in (res, scalar0, (memory0, drg3))
addScaleTest :: String -> Curve -> Task
addScaleTest name curve = Task {
taskName = name ++ " point addition of two scalings",
taskFile = "../testdata/ecc/add_scale2/" ++ name ++ ".test",
taskTest = liftTest go,
taskCount = 1000
}
where
go (memory0, drg0) =
let (scalar1, drg1) = withDRG drg0 (scalarGenerate curve)
(scalar2, drg2) = withDRG drg1 (scalarGenerate curve)
(n, drg3) = withDRG drg2 (scalarGenerate curve)
(m, drg4) = withDRG drg3 (scalarGenerate curve)
point1 = pointBaseMul curve scalar1
point2 = pointBaseMul curve scalar2
pointr = pointAddTwoMuls curve n point1 m 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),
("p", showX x2), ("q", showX y2),
("n", showX n), ("m", showX m),
("r", showX xr), ("s", showX yr)]
in (res, scalar1, (memory0, drg4))
_ ->
go (memory0, drg4)
signTest :: String -> Curve -> Task
signTest name curve = Task {
taskName = name ++ " curve signing",
taskFile = "../testdata/ecc/sign/" ++ name ++ ".test",
taskTest = liftTest go,
taskCount = 1000
}
where
go (memory0, drg0) =
let ((pub, priv), drg1) = withDRG drg0 (generate curve)
(msg, drg2) = withDRG drg1 $ do x <- generateBetween 0 256
getRandomBytes (fromIntegral x)
(hash, drg3) = withDRG drg2 generateHash
n = ecc_n (common_curve curve)
PrivateKey _ d = priv
kStream = generateKStream hash msg d n (curveSizeBits curve)
findGoodK stream =
case stream of
[] ->
go (memory0, drg3)
(k : restks) ->
case signWith' k priv hash msg of
Nothing ->
findGoodK restks
Just sig ->
let PublicKey _ (Point x y) = pub
res = Map.fromList [("d", showX d), ("k", showX k),
("x", showX x), ("y", showX y),
("m", showBin msg), ("h", showHash hash),
("n", showBin (runHash hash msg)),
("r", showX (sign_r sig)),
("s", showX (sign_s sig))]
in (res, d, (memory0, drg3))
in findGoodK kStream
signWith' :: Integer -> PrivateKey -> HashAlg -> S.ByteString -> Maybe Signature
signWith' k priv Sha224 msg = signWith k priv SHA224 msg
signWith' k priv Sha256 msg = signWith k priv SHA256 msg
signWith' k priv Sha384 msg = signWith k priv SHA384 msg
signWith' k priv Sha512 msg = signWith k priv SHA512 msg
generateTasks :: (String, Curve) -> [Task]
generateTasks (name, curve) = [negateTest name curve,
doubleTest name curve,
addTest name curve,
scaleTest name curve,
addScaleTest name curve,
signTest name curve]
ecdsaTasks :: [Task]
ecdsaTasks = concatMap generateTasks curves

View File

@@ -1,735 +0,0 @@
{-# LANGUAGE PackageImports #-}
module ED25519(ed25519Tasks)
where
import Control.Monad(unless)
import Crypto.Error(CryptoFailable(CryptoPassed))
import "crypto-api" Crypto.Random(SystemRandom)
import "cryptonite" Crypto.Random(getRandomBytes,withDRG)
import Crypto.PubKey.Ed25519
import Data.ByteArray(convert)
import Data.ByteString(ByteString,pack,useAsCString)
import qualified Data.ByteString as BS
import Data.Int(Int32)
import qualified Data.Map.Strict as Map
import Data.Word(Word8,Word32,Word64)
import ED25519.PrecompPoints
import Foreign.C.Types(CChar)
import Foreign.Marshal.Alloc(alloca)
import Foreign.Marshal.Array(allocaArray,peekArray,pokeArray)
import Foreign.Ptr(Ptr,castPtr)
import Foreign.Storable(Storable(..))
import Math(showX,showBin)
import Task(Task(..))
cTEST_COUNT :: Int
cTEST_COUNT = 1000
ed25519Tasks :: [Task]
ed25519Tasks = [ loadTests, byteTests, addsubTests, mulTests,
squaringTests, inversionTests, negateTests,
cmovTests, isTests, square2Tests,
pow22523Tests, fbvTests, conversionTests,
ptDoubleTests, maddsubTests, ptAddSubTests,
scalarMultBaseTests, slideTests, scalarMultTests,
reduceTests, muladdTests, pubPrivTests,
signTest ]
loadTests :: Task
loadTests = Task {
taskName = "ed25519 byte loading",
taskFile = "../testdata/ed25519/load.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
do let (bytes, drg1) = withDRG drg0 (getRandomBytes 4)
res3 <- useAsCString bytes (\ptr -> load_3 ptr)
res4 <- useAsCString bytes (\ptr -> load_4 ptr)
let res = Map.fromList [("x", showBin bytes), ("a", showX res3), ("b", showX res4)]
return (res, fromIntegral res4, (memory0, drg1))
byteTests :: Task
byteTests = Task {
taskName = "ed25519 byte / element conversion",
taskFile = "../testdata/ed25519/bytes.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomPackedBytes drg0 $ \ ptra drg1 ->
alloca $ \ ptrc ->
allocaArray 32 $ \ rptr ->
do clearSpace ptrc
pokeArray (rptr :: Ptr Word8) (replicate 32 0)
fe_frombytes ptrc ptra
b <- convertFE ptrc
fe_tobytes (castPtr rptr) ptrc
start <- peek ptra
end <- peek (castPtr rptr)
unless (start == end) $
fail "field element tobytes/frombytes doesn't round trip"
bytes' <- pack `fmap` peekArray 32 (castPtr ptra :: Ptr Word8)
let res = Map.fromList [("a", showBin bytes'),
("b", showBin b)]
return (res, toNumber b, (memory0, drg1))
addsubTests :: Task
addsubTests = Task {
taskName = "ed25519 addition/subtraction tests",
taskFile = "../testdata/ed25519/addsub.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomElement drg0 $ \ ptrel1 drg1 ->
randomElement drg1 $ \ ptrel2 drg2 ->
alloca $ \ ptrc ->
alloca $ \ ptrd ->
do fe_add ptrc ptrel1 ptrel2
fe_sub ptrd ptrel1 ptrel2
[a, b, c, d] <- mapM convertFE [ptrel1, ptrel2, ptrc, ptrd]
let res = Map.fromList [("a", showBin a),
("b", showBin b),
("c", showBin c),
("d", showBin d)]
return (res, toNumber c, (memory0, drg2))
mulTests :: Task
mulTests = Task {
taskName = "ed25519 multiplication tests",
taskFile = "../testdata/ed25519/mul.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomElement drg0 $ \ ptrel1 drg1 ->
randomElement drg1 $ \ ptrel2 drg2 ->
alloca $ \ ptrc ->
do fe_mul ptrc ptrel1 ptrel2
[a, b, c] <- mapM convertFE [ptrel1, ptrel2, ptrc]
let res = Map.fromList [("a", showBin a),
("b", showBin b),
("c", showBin c)]
return (res, toNumber c, (memory0, drg2))
squaringTests :: Task
squaringTests = Task {
taskName = "ed25519 squaring tests",
taskFile = "../testdata/ed25519/square.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomElement drg0 $ \ ptrel drg1 ->
alloca $ \ ptrc ->
do fe_square ptrc ptrel
[a, c] <- mapM convertFE [ptrel, ptrc]
let res = Map.fromList [("a", showBin a),
("c", showBin c)]
return (res, toNumber c, (memory0, drg1))
inversionTests :: Task
inversionTests = Task {
taskName = "ed25519 inversion tests",
taskFile = "../testdata/ed25519/invert.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomElement drg0 $ \ ptrel drg1 ->
alloca $ \ ptrc ->
do fe_invert ptrc ptrel
a <- convertFE ptrel
c <- convertFE ptrc
let res = Map.fromList [("a", showBin a),
("c", showBin c)]
return (res, toNumber a, (memory0, drg1))
negateTests :: Task
negateTests = Task {
taskName = "ed25519 negation tests",
taskFile = "../testdata/ed25519/negate.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomElement drg0 $ \ ptrel drg1 ->
alloca $ \ ptrc ->
do fe_negate ptrc ptrel
a <- convertFE ptrel
c <- convertFE ptrc
let res = Map.fromList [("a", showBin a),
("c", showBin c)]
return (res, toNumber a, (memory0, drg1))
cmovTests :: Task
cmovTests = Task {
taskName = "ed25519 conditional mov tests",
taskFile = "../testdata/ed25519/cmov.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomElement drg0 $ \ aelptr drg1 ->
do let (bbytes, drg2) = withDRG drg1 (getRandomBytes 1)
b = even (BS.head bbytes)
bvalLib = if b then 0 else 1
bvalOut = if b then 0 else 0xFFFFFF :: Word32
alloca $ \ celptr ->
do clearSpace celptr
fe_cmov celptr aelptr bvalLib
a <- convertFE aelptr
c <- convertFE celptr
let res = Map.fromList [("a", showBin a),
("b", showX bvalOut),
("c", showBin c)]
return (res, toNumber a, (memory0, drg2))
isTests :: Task
isTests = Task {
taskName = "ed25519 predicate tests",
taskFile = "../testdata/ed25519/istests.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomElement drg0 $ \ aptr drg1 ->
do a <- convertFE aptr
z <- fe_isnonzero aptr
n <- fe_isnegative aptr
let res = Map.fromList [("a", showBin a),
("z", showX (if z == 0 then 0 :: Word32 else 0xFFFFFF)),
("n", showX (if n == 0 then 0 :: Word32 else 0xFFFFFF))]
return (res, toNumber a, (memory0, drg1))
square2Tests :: Task
square2Tests = Task {
taskName = "ed25519 square2 tests",
taskFile = "../testdata/ed25519/square2.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomElement drg0 $ \ aptr drg1 ->
alloca $ \ cptr ->
do clearSpace cptr
fe_square2 cptr aptr
a <- convertFE aptr
c <- convertFE cptr
let res = Map.fromList [("a", showBin a), ("c", showBin c)]
return (res, toNumber a, (memory0, drg1))
pow22523Tests :: Task
pow22523Tests = Task {
taskName = "ed25519 pow22523 tests",
taskFile = "../testdata/ed25519/pow22523.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomElement drg0 $ \ aptr drg1 ->
alloca $ \ cptr ->
do clearSpace cptr
fe_pow22523 cptr aptr
a <- convertFE aptr
c <- convertFE cptr
let res = Map.fromList [("a", showBin a), ("c", showBin c)]
return (res, toNumber a, (memory0, drg1))
fbvTests :: Task
fbvTests = Task {
taskName = "ed25519 from bytes (vartime) tests",
taskFile = "../testdata/ed25519/fbv.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
do let (abytes, drg1) = withDRG drg0 (getRandomBytes 32)
useAsCString abytes $ \ aptr ->
do let aptr' = castPtr aptr :: Ptr PackedBytes
curve25519_scalar_mask aptr'
alloca $ \ dest ->
do clearSpace dest
ok <- point_frombytes dest aptr'
a <- pack `fmap` peekArray 32 (castPtr aptr)
c <- pack `fmap` peekArray (4 * 10 * 4) (castPtr dest)
let c' | ok = c
| otherwise = BS.empty
let res = Map.fromList [("a", showBin a),
("b", showBin c'),
("c", showBin c)]
return (res, if ok then (toNumber abytes) else 0, (memory0, drg1))
conversionTests :: Task
conversionTests = Task {
taskName = "ed25519 point form conversion tests",
taskFile = "../testdata/ed25519/conversion.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomPoint3 drg0 $ \ ptr3 drg' ->
alloca $ \ ptrCached ->
alloca $ \ ptr2 ->
alloca $ \ ptrP1P1 ->
alloca $ \ ptr2' ->
alloca $ \ ptr3' ->
do clearSpace ptrCached
clearSpace ptr2
clearSpace ptrP1P1
clearSpace ptr2'
clearSpace ptr3'
p3_to_cached ptrCached ptr3
ge_p3_to_p2 ptr2 ptr3
ge_p3_dbl ptrP1P1 ptr3
p1p1_to_p2 ptr2' ptrP1P1
p1p1_to_p3 ptr3' ptrP1P1
a <- convertPoint ptr3
c <- convertPoint ptrCached
t <- convertPoint ptr2
o <- convertPoint ptrP1P1
d <- convertPoint ptr2'
b <- convertPoint ptr3'
let res = Map.fromList [("a", showBin a), ("c", showBin c),
("t", showBin t), ("o", showBin o),
("d", showBin d), ("b", showBin b)]
return (res, toNumber a, (memory0, drg'))
ptDoubleTests :: Task
ptDoubleTests = Task {
taskName = "ed25519 point doubling tests",
taskFile = "../testdata/ed25519/pt_double.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomPoint3 drg0 $ \ ptra drg1 ->
randomPoint2 drg1 $ \ ptrc drg2 ->
alloca $ \ ptrb ->
alloca $ \ ptrd ->
do clearSpace ptrb
clearSpace ptrd
ge_p3_dbl ptrb ptra
ge_p2_dbl ptrd ptrc
a <- convertPoint ptra
b <- convertPoint ptrb
c <- convertPoint ptrc
d <- convertPoint ptrd
let res = Map.fromList [("a", showBin a), ("b", showBin b),
("c", showBin c), ("d", showBin d)]
return (res, toNumber a, (memory0, drg2))
maddsubTests :: Task
maddsubTests = Task {
taskName = "ed25519 point madd/msub tests",
taskFile = "../testdata/ed25519/maddsub.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomPoint3 drg0 $ \ ptra drg1 ->
randomPointPrecomp drg1 $ \ ptrc drg2 ->
alloca $ \ ptrb ->
alloca $ \ ptrd ->
do clearSpace ptrb
clearSpace ptrd
ge_madd ptrb ptra ptrc
ge_msub ptrd ptra ptrc
a <- convertPoint ptra
b <- convertPoint ptrb
c <- convertPoint ptrc
d <- convertPoint ptrd
let res = Map.fromList [("a", showBin a), ("b", showBin b),
("c", showBin c), ("d", showBin d)]
return (res, toNumber a, (memory0, drg2))
ptAddSubTests :: Task
ptAddSubTests = Task {
taskName = "ed25519 point add/sub tests",
taskFile = "../testdata/ed25519/ptaddsub.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomPoint3 drg0 $ \ ptra drg1 ->
randomPointCached drg1 $ \ ptrc drg2 ->
alloca $ \ ptrb ->
alloca $ \ ptrd ->
do clearSpace ptrb
clearSpace ptrd
ge_add ptrb ptra ptrc
ge_sub ptrd ptra ptrc
a <- convertPoint ptra
b <- convertPoint ptrb
c <- convertPoint ptrc
d <- convertPoint ptrd
let res = Map.fromList [("a", showBin a), ("b", showBin b),
("c", showBin c), ("d", showBin d)]
return (res, toNumber a, (memory0, drg2))
scalarMultBaseTests :: Task
scalarMultBaseTests = Task {
taskName = "ed25519 point add/sub tests",
taskFile = "../testdata/ed25519/scalar_mult.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomPackedBytes drg0 $ \ ptra drg1 ->
alloca $ \ ptrb ->
do clearSpace ptrb
x25519_ge_scalarmult_base ptrb ptra
PB abytes <- peek ptra
let a = pack abytes
b <- convertPoint ptrb
let res = Map.fromList [("a", showBin a), ("b", showBin b)]
return (res, toNumber a, (memory0, drg1))
slideTests :: Task
slideTests = Task {
taskName = "ed25519 slide helper function tests",
taskFile = "../testdata/ed25519/slide.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomPackedBytes drg0 $ \ ptra drg1 ->
allocaArray 256 $ \ ptrb ->
do pokeArray ptrb (replicate 256 0)
slide ptrb ptra
a <- pack `fmap` peekArray 32 (castPtr ptra)
b <- pack `fmap` peekArray 356 ptrb
let res = Map.fromList [("a", showBin a), ("b", showBin b)]
return (res, toNumber a, (memory0, drg1))
scalarMultTests :: Task
scalarMultTests = Task {
taskName = "ed25519 point general scalar multiplication tests",
taskFile = "../testdata/ed25519/scalar_mult_gen.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomPackedBytes drg0 $ \ ptra drg1 ->
randomPoint3 drg1 $ \ ptrb drg2 ->
randomPackedBytes drg2 $ \ ptrc drg3 ->
alloca $ \ ptrd ->
do clearSpace ptrd
ge_double_scalarmult_vartime ptrd ptra ptrb ptrc
PB abytes <- peek ptra
let a = pack abytes
b <- convertPoint ptrb
PB cbytes <- peek ptrc
let c = pack cbytes
d <- convertPoint ptrd
let res = Map.fromList [("a", showBin a), ("b", showBin b),
("c", showBin c), ("d", showBin d)]
return (res, toNumber a, (memory0, drg3))
reduceTests :: Task
reduceTests = Task {
taskName = "ed25519 reduce tests",
taskFile = "../testdata/ed25519/reduce.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
do let (a, drg1) = withDRG drg0 (getRandomBytes 64)
allocaArray 64 $ \ target ->
do pokeArray target (BS.unpack a)
sc_reduce target
b <- pack `fmap` peekArray 32 target
let res = Map.fromList [("a", showBin a), ("b", showBin b)]
return (res, toNumber a, (memory0, drg1))
muladdTests :: Task
muladdTests = Task {
taskName = "ed25519 multiplication+addition tests",
taskFile = "../testdata/ed25519/muladd.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomPackedBytes drg0 $ \ ptra drg1 ->
randomPackedBytes drg1 $ \ ptrb drg2 ->
randomPackedBytes drg2 $ \ ptrc drg3 ->
alloca $ \ ptrd ->
do clearSpace ptrd
sc_muladd ptrd ptra ptrb ptrc
a <- repackBytes ptra
b <- repackBytes ptrb
c <- repackBytes ptrc
d <- repackBytes ptrd
let res = Map.fromList [("a", showBin a), ("b", showBin b),
("c", showBin c), ("d", showBin d)]
return (res, toNumber a, (memory0, drg3))
pubPrivTests :: Task
pubPrivTests = Task {
taskName = "ed25519 private -> public conversion tests",
taskFile = "../testdata/ed25519/pubfrompriv.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
randomPackedBytes drg0 $ \ ptra drg1 ->
alloca $ \ ptrb ->
do clearSpace ptrb
public_from_private ptrb ptra
a <- repackBytes ptra
b <- repackBytes ptrb
let res = Map.fromList [("a", showBin a), ("b", showBin b)]
return (res, toNumber a, (memory0, drg1))
signTest :: Task
signTest = Task {
taskName = "ed25519 signing tests",
taskFile = "../testdata/ed25519/sign.test",
taskTest = go,
taskCount = cTEST_COUNT
}
where
go (memory0, drg0) =
let (priv, drg1) = withDRG drg0 generateSecretKey
(msg, drg2) = withDRG drg1 $ getRandomBytes =<< ((fromIntegral . BS.head) `fmap` getRandomBytes 1)
pub = toPublic priv
privBytes = convert priv
pubBytes = convert pub
sig = convert (sign priv pub msg)
res = Map.fromList [("u", showBin pubBytes), ("r", showBin privBytes),
("m", showBin msg), ("s", showBin sig)]
in return (res, toNumber privBytes, (memory0, drg2))
data PackedBytes = PB [Word8]
deriving (Eq)
instance Storable PackedBytes where
sizeOf _ = 32
alignment _ = 8
peek p = PB `fmap` peekArray 32 (castPtr p)
poke p (PB v) = pokeArray (castPtr p) v
randomPackedBytes :: SystemRandom -> (Ptr PackedBytes -> SystemRandom -> IO a) -> IO a
randomPackedBytes drg action =
do let (bytes, drg') = withDRG drg (getRandomBytes 32)
useAsCString bytes $ \ ptr ->
do let ptr' = castPtr ptr :: Ptr PackedBytes
curve25519_scalar_mask ptr'
action ptr' drg'
repackBytes :: Ptr PackedBytes -> IO ByteString
repackBytes ptr =
do PB xs <- peek ptr
return (pack xs)
data Element = FE [Int32]
instance Storable Element where
sizeOf _ = 10 * sizeOf (undefined :: Int32)
alignment _ = 8
peek p = FE `fmap` peekArray 10 (castPtr p)
poke p (FE v) = pokeArray (castPtr p) v
randomElement :: SystemRandom -> (Ptr Element -> SystemRandom -> IO a) -> IO a
randomElement drg action =
randomPackedBytes drg $ \ ptrpb drg' -> alloca $ \ ptrel ->
do clearSpace ptrel
fe_frombytes ptrel ptrpb
action ptrel drg'
data Point3 = P3 [Element]
instance Storable Point3 where
sizeOf _ = 4 * sizeOf (undefined :: Element)
alignment _ = 8
peek p = P3 `fmap` peekArray 4 (castPtr p)
poke p (P3 v) = pokeArray (castPtr p) v
randomPoint3 :: SystemRandom -> (Ptr Point3 -> SystemRandom -> IO a) -> IO a
randomPoint3 drg0 action = allocaArray (4 * 10) (go drg0)
where
go drg dest =
do mres <- randomPackedBytes drg $ \ aptr drg' ->
do clearSpace dest
worked <- point_frombytes dest aptr
if worked
then Right `fmap` action (castPtr dest) drg'
else return (Left drg')
case mres of
Right x -> return x
Left drg' -> go drg' dest
data PointCached = PC [Element]
instance Storable PointCached where
sizeOf _ = 4 * sizeOf (undefined :: Element)
alignment _ = 8
peek p = PC `fmap` peekArray 4 (castPtr p)
poke p (PC v) = pokeArray (castPtr p) v
randomPointCached :: SystemRandom -> (Ptr PointCached -> SystemRandom -> IO a) -> IO a
randomPointCached drg action =
randomPoint3 drg $ \ ptr drg' ->
allocaArray (4 * 10) $ \ dest ->
do pokeArray (castPtr dest :: Ptr Int32) (replicate (4 * 10) 0)
p3_to_cached dest ptr
action (castPtr dest) drg'
data Point2 = P2 [Element]
instance Storable Point2 where
sizeOf _ = 3 * sizeOf (undefined :: Element)
alignment _ = 8
peek p = P2 `fmap` peekArray 3 (castPtr p)
poke p (P2 v) = pokeArray (castPtr p) v
randomPoint2 :: SystemRandom -> (Ptr Point2 -> SystemRandom -> IO a) -> IO a
randomPoint2 drg action =
randomPoint3 drg $ \ ptr3 drg' ->
allocaArray (3 * 10) $ \ dest ->
do pokeArray (castPtr dest :: Ptr Int32) (replicate (3 * 10) 0)
ge_p3_to_p2 dest ptr3
action (castPtr dest) drg'
data PointP1P1 = P1P1 [Element]
instance Storable PointP1P1 where
sizeOf _ = 4 * sizeOf (undefined :: Element)
alignment _ = 8
peek p = P1P1 `fmap` peekArray 4 (castPtr p)
poke p (P1P1 v) = pokeArray (castPtr p) v
_randomPointP1P1 :: SystemRandom -> (Ptr PointP1P1 -> SystemRandom -> IO a) -> IO a
_randomPointP1P1 drg action =
randomPoint3 drg $ \ ptr3 drg' ->
allocaArray (4 * 10) $ \ dest ->
do pokeArray (castPtr dest :: Ptr Int32) (replicate (4 * 10) 0)
ge_p3_dbl dest ptr3
action (castPtr dest) drg'
data PointPrecomp = PP [Element]
instance Storable PointPrecomp where
sizeOf _ = 4 * sizeOf (undefined :: Element)
alignment _ = 8
peek p = PP `fmap` peekArray 4 (castPtr p)
poke p (PP v) = pokeArray (castPtr p) v
randomPointPrecomp :: SystemRandom -> (Ptr PointPrecomp -> SystemRandom -> IO a) -> IO a
randomPointPrecomp drg action =
do let ([a,b,c,d], drg') = withDRG drg (BS.unpack `fmap` getRandomBytes 4)
mix = fromIntegral a + fromIntegral b + fromIntegral c + fromIntegral d
idx = mix `mod` (length precompPoints)
val = PP (map FE (precompPoints !! idx))
alloca $ \ ptr ->
do poke ptr val
action ptr drg'
clearSpace :: Storable a => Ptr a -> IO ()
clearSpace x = meh x undefined
where
meh :: Storable a => Ptr a -> a -> IO ()
meh p v = pokeArray (castPtr p) (replicate (sizeOf v) (0 :: Word8))
convertFE :: Ptr Element -> IO ByteString
convertFE feptr = pack `fmap` peekArray 40 (castPtr feptr :: Ptr Word8)
convertPoint :: Storable a => Ptr a -> IO ByteString
convertPoint x = meh x undefined
where
meh :: Storable a => Ptr a -> a -> IO ByteString
meh p v = pack `fmap` peekArray (sizeOf v) (castPtr p)
toNumber :: ByteString -> Integer
toNumber = BS.foldr (\ x a -> fromIntegral x + a) 0
foreign import ccall unsafe "load_3"
load_3 :: Ptr CChar -> IO Word64
foreign import ccall unsafe "load_4"
load_4 :: Ptr CChar -> IO Word64
foreign import ccall unsafe "GFp_curve25519_scalar_mask"
curve25519_scalar_mask :: Ptr PackedBytes -> IO ()
foreign import ccall unsafe "fe_frombytes"
fe_frombytes :: Ptr Element -> Ptr PackedBytes -> IO ()
foreign import ccall unsafe "GFp_fe_tobytes"
fe_tobytes :: Ptr PackedBytes -> Ptr Element -> IO ()
foreign import ccall unsafe "fe_add"
fe_add :: Ptr Element -> Ptr Element -> Ptr Element -> IO ()
foreign import ccall unsafe "fe_sub"
fe_sub :: Ptr Element -> Ptr Element -> Ptr Element -> IO ()
foreign import ccall unsafe "GFp_fe_mul"
fe_mul :: Ptr Element -> Ptr Element -> Ptr Element -> IO ()
foreign import ccall unsafe "fe_sq"
fe_square :: Ptr Element -> Ptr Element -> IO ()
foreign import ccall unsafe "GFp_fe_invert"
fe_invert :: Ptr Element -> Ptr Element -> IO ()
foreign import ccall unsafe "fe_neg"
fe_negate :: Ptr Element -> Ptr Element -> IO ()
foreign import ccall unsafe "fe_cmov"
fe_cmov :: Ptr Element -> Ptr Element -> Word32 -> IO ()
foreign import ccall unsafe "fe_isnonzero"
fe_isnonzero :: Ptr Element -> IO Int32
foreign import ccall unsafe "GFp_fe_isnegative"
fe_isnegative :: Ptr Element -> IO Word8
foreign import ccall unsafe "fe_sq2"
fe_square2 :: Ptr Element -> Ptr Element -> IO ()
foreign import ccall unsafe "fe_pow22523"
fe_pow22523 :: Ptr Element -> Ptr Element -> IO ()
foreign import ccall unsafe "GFp_x25519_ge_frombytes_vartime"
point_frombytes :: Ptr Point3 -> Ptr PackedBytes -> IO Bool
foreign import ccall unsafe "x25519_ge_p3_to_cached"
p3_to_cached :: Ptr PointCached -> Ptr Point3 -> IO ()
foreign import ccall unsafe "x25519_ge_p1p1_to_p2"
p1p1_to_p2 :: Ptr Point2 -> Ptr PointP1P1 -> IO ()
foreign import ccall unsafe "x25519_ge_p1p1_to_p3"
p1p1_to_p3 :: Ptr Point3 -> Ptr PointP1P1 -> IO ()
foreign import ccall unsafe "ge_p2_dbl"
ge_p2_dbl :: Ptr PointP1P1 -> Ptr Point2 -> IO ()
foreign import ccall unsafe "ge_p3_dbl"
ge_p3_dbl :: Ptr PointP1P1 -> Ptr Point3 -> IO ()
foreign import ccall unsafe "ge_p3_to_p2"
ge_p3_to_p2 :: Ptr Point2 -> Ptr Point3 -> IO ()
foreign import ccall unsafe "ge_madd"
ge_madd :: Ptr PointP1P1 -> Ptr Point3 -> Ptr PointPrecomp -> IO ()
foreign import ccall unsafe "ge_msub"
ge_msub :: Ptr PointP1P1 -> Ptr Point3 -> Ptr PointPrecomp -> IO ()
foreign import ccall unsafe "x25519_ge_add"
ge_add :: Ptr PointP1P1 -> Ptr Point3 -> Ptr PointCached -> IO ()
foreign import ccall unsafe "x25519_ge_sub"
ge_sub :: Ptr PointP1P1 -> Ptr Point3 -> Ptr PointCached -> IO ()
foreign import ccall unsafe "GFp_x25519_ge_scalarmult_base"
x25519_ge_scalarmult_base :: Ptr Point3 -> Ptr PackedBytes -> IO ()
foreign import ccall unsafe "slide"
slide :: Ptr Word8 -> Ptr PackedBytes -> IO ()
foreign import ccall unsafe "GFp_ge_double_scalarmult_vartime"
ge_double_scalarmult_vartime :: Ptr Point2 -> Ptr PackedBytes -> Ptr Point3 -> Ptr PackedBytes -> IO ()
foreign import ccall unsafe "GFp_x25519_sc_reduce"
sc_reduce :: Ptr Word8 -> IO ()
foreign import ccall unsafe "GFp_x25519_sc_muladd"
sc_muladd :: Ptr PackedBytes -> Ptr PackedBytes -> Ptr PackedBytes -> Ptr PackedBytes -> IO ()
foreign import ccall unsafe "GFp_x25519_public_from_private"
public_from_private :: Ptr PackedBytes -> Ptr PackedBytes -> IO ()

File diff suppressed because it is too large Load Diff

View File

@@ -1,44 +0,0 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PackageImports #-}
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-api" Crypto.Random(CryptoRandomGen(..),SystemRandom)
import DSA(dsaTasks)
import ECDSATesting(ecdsaTasks)
import ED25519(ed25519Tasks)
import GHC.Conc(getNumCapabilities)
import RFC6979(rfcTasks)
import RSA(rsaTasks)
import System.Console.AsciiProgress
import Task(Task, runTask)
taskExecutor :: MVar [Task] -> Chan () -> SystemRandom -> IO SystemRandom
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 <- newGenIO
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 (dsaTasks ++ ecdsaTasks ++ rfcTasks ++ rsaTasks ++ ed25519Tasks)
replicateM_ executors (spawnExecutor tasks done)
replicateM_ executors (void $ readChan done)

View File

@@ -1,166 +0,0 @@
{-# LANGUAGE RecordWildCards #-}
module Math(
extendedGCD
, barrett, computeK, base
, modulate, modulate'
, isqrt
, divmod
, showX, showB, showBin
)
where
import Data.Bits(shiftL,shiftR,(.&.))
import qualified Data.ByteString as S
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"
showBin :: S.ByteString -> String
showBin bstr =
case S.uncons bstr of
Nothing -> ""
Just (x,rest) ->
showX (x `shiftR` 4) ++ showX (x .&. 0xF) ++ showBin rest
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'''

View File

@@ -1,113 +0,0 @@
{-# LANGUAGE PackageImports #-}
module RFC6979
-- (
-- rfcTasks
-- )
where
import Crypto.Hash(SHA224(..),SHA256(..),SHA384(..),SHA512(..))
import Crypto.MAC.HMAC(HMAC,hmac)
import Crypto.Number.Generate(generateBetween)
import "cryptonite" Crypto.Random(getRandomBytes,withDRG)
import Data.Bits(shiftL,shiftR,(.&.))
import qualified Data.ByteArray as B
import qualified Data.ByteString as S
import Data.Char(toUpper)
import qualified Data.Map.Strict as Map
import Math(showBin,showX)
import Task(Task(..),liftTest)
import Utils(HashAlg(..), runHash)
runHMAC :: HashAlg -> S.ByteString -> S.ByteString -> S.ByteString
runHMAC Sha224 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA224))
runHMAC Sha256 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA256))
runHMAC Sha384 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA384))
runHMAC Sha512 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA512))
generateKStream :: HashAlg -> S.ByteString -> Integer -> Integer -> Int -> [Integer]
generateKStream alg m x q qlen = nextK bigK2 bigV2
where
h1 = runHash alg m
bigV0 = S.replicate (S.length h1) 0x01
bigK0 = S.replicate (S.length h1) 0x00
seed1 = S.concat [bigV0, S.singleton 0x00, int2octets qlen x, bits2octets qlen q h1]
bigK1 = runHMAC alg bigK0 seed1
bigV1 = runHMAC alg bigK1 bigV0
seed2 = S.concat [bigV1, S.singleton 0x01, int2octets qlen x, bits2octets qlen q h1]
bigK2 = runHMAC alg bigK1 seed2
bigV2 = runHMAC alg bigK2 bigV1
--
nextK bigK bigV =
let (bigV', bigT) = buildT bigK bigV S.empty
k = bits2int qlen bigT
bigK' = runHMAC alg bigK (bigV' `S.append` S.singleton 0)
bigV'' = runHMAC alg bigK' bigV'
in if k < q then (k : nextK bigK' bigV'') else nextK bigK' bigV''
buildT bigK bigV bigT
| S.length bigT * 8 >= qlen = (bigV, bigT)
| otherwise =
let bigV' = runHMAC alg bigK bigV
in buildT bigK bigV' (bigT `S.append` bigV')
bits2int :: Int -> S.ByteString -> Integer
bits2int qlen bstr = reduce (go bstr 0)
where
reduce x =
let vlen = S.length bstr * 8
in if vlen > qlen
then x `shiftR` (vlen - qlen)
else x
--
go x acc =
case S.uncons x of
Nothing -> acc
Just (v, rest) ->
go rest ((acc `shiftL` 8) + fromIntegral v)
int2octets :: Int -> Integer -> S.ByteString
int2octets lenBits x =
S.pack (pad (rlen `div` 8) (reverse (go x)))
where
rlen = 8 * ((lenBits + 7) `div` 8)
pad target ls
| length ls > target = drop (length ls - target) ls
| length ls < target = pad target (0 : ls)
| otherwise = ls
--
go 0 = []
go v = (fromIntegral (v .&. 0xFF)) : go (v `shiftR` 8)
bits2octets :: Int -> Integer -> S.ByteString -> S.ByteString
bits2octets qlen q bstr =
let z1 = bits2int qlen bstr
z2 = if z1 > q then z1 - q else z1
in int2octets qlen z2
rfc6979Test :: HashAlg -> Task
rfc6979Test alg = Task {
taskName = name ++ " RFC 6979 deterministic k-generation",
taskFile = "../testdata/rfc6979/" ++ name ++ ".test",
taskTest = liftTest go,
taskCount = 1000
}
where
name = map toUpper (show alg)
go (memory0, drg0) =
let (qlen, drg1) = withDRG drg0 $ generateBetween 160 521
(key, drg2) = withDRG drg1 $ generateBetween 1 ((2 ^ qlen) - 1)
(q, drg3) = withDRG drg2 $ generateBetween 1 ((2 ^ qlen) - 1)
(dataSize, drg4) = withDRG drg3 $ generateBetween 1 1024
(msg, drg5) = withDRG drg4 $ getRandomBytes (fromIntegral dataSize)
h1 = runHash alg msg
ks = generateKStream alg msg key q (fromIntegral qlen)
res = Map.fromList [("q", showX q), ("l", showX qlen),
("x", showX key), ("h", showBin h1),
("k", showX (ks !! 0)),
("y", showX (ks !! 1)),
("z", showX (ks !! 2))]
in (res, qlen, (memory0, drg5))
rfcTasks :: [Task]
rfcTasks = [rfc6979Test Sha224, rfc6979Test Sha256,
rfc6979Test Sha384, rfc6979Test Sha512]

View File

@@ -1,126 +0,0 @@
{-# LANGUAGE PackageImports #-}
module RSA(rsaTasks)
where
import Crypto.Hash(SHA224(..),SHA256(..),SHA384(..),SHA512(..))
import "cryptonite" Crypto.Random(MonadRandom,MonadPseudoRandom,getRandomBytes,withDRG)
import "crypto-api" Crypto.Random(SystemRandom)
import Crypto.PubKey.MaskGenFunction(mgf1)
import Crypto.PubKey.RSA
import Crypto.PubKey.RSA.PKCS15(sign)
import Crypto.PubKey.RSA.OAEP(OAEPParams(..),encrypt)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BSC
import Data.Char(chr,isPrint)
import Data.Map.Strict(Map)
import qualified Data.Map.Strict as Map
import Data.Maybe(fromMaybe,isJust)
import Data.Word(Word8)
import Database(Database)
import Math(barrett,computeK,showX,showBin)
import Task(Task(..),liftTest)
import Utils(HashAlg(..),generateHash,showHash)
rsaSizes :: [(Int, Int)]
rsaSizes = [(512, 400),
(1024, 200),
(2048, 100),
(3072, 50),
(4096, 50),
(8192, 10),
(15360, 5)]
rsaTasks :: [Task]
rsaTasks = concatMap generateTask rsaSizes
generateTask :: (Int, Int) -> [Task]
generateTask (s, c) = [signTest s c, encryptTest s c]
signTest :: Int -> Int -> Task
signTest sz cnt = Task {
taskName = "RSA " ++ show sz ++ " signing",
taskFile = "../testdata/rsa/sign" ++ show sz ++ ".test",
taskTest = liftTest go,
taskCount = cnt
}
where
go db = withDRG' db go2
--
go2 :: MonadRandom m => m (Map String String, Integer)
go2 = do (public, private) <- generate (sz `div` 8) 65537
let d = private_d private
let n = public_n public
msg <- getRandomBytes =<< ((fromIntegral . BS.head) `fmap` getRandomBytes 1)
hash <- generateHash
case signWith hash private msg of
Left _ -> go2
Right sig -> return $ (Map.fromList [("d", showX d),
("n", showX n),
("k", showX (computeK n)),
("u", showX (barrett n)),
("h", showHash hash),
("m", showBin msg),
("s", showBin sig)], n)
withDRG' :: Database -> MonadPseudoRandom SystemRandom (Map String String, Integer) ->
(Map String String, Integer, Database)
withDRG' (memory, drg) action =
let ((res, n), drg') = withDRG drg action
in (res, n, (memory, drg'))
signWith :: HashAlg -> PrivateKey -> BS.ByteString -> Either Error BS.ByteString
signWith Sha224 = sign Nothing (Just SHA224)
signWith Sha256 = sign Nothing (Just SHA256)
signWith Sha384 = sign Nothing (Just SHA384)
signWith Sha512 = sign Nothing (Just SHA512)
encryptTest :: Int -> Int -> Task
encryptTest sz cnt = Task {
taskName = "RSA " ++ show sz ++ " encryption",
taskFile = "../testdata/rsa/encrypt" ++ show sz ++ ".test",
taskTest = liftTest go,
taskCount = cnt
}
where
go db = withDRG' db go2
go2 = do (public, private) <- generate (sz `div` 8) 65537
let d = private_d private
let n = public_n public
msg <- getRandomBytes =<< ((fromIntegral . BS.head) `fmap` getRandomBytes 1)
hash <- generateHash
label <- do len <- BS.head `fmap` getRandomBytes 1
if odd len
then return Nothing
else Just `fmap` genASCII (len `div` 2)
let labelbstr = fromMaybe BS.empty (BSC.pack `fmap` label)
labelAlive = if isJust label then 1 else (0 :: Integer)
res <- encryptWith hash (BSC.pack `fmap` label) public msg
case res of
Left _ -> go2
Right cipher ->
return $ (Map.fromList [("d", showX d),
("n", showX n),
("k", showX (computeK n)),
("u", showX (barrett n)),
("h", showHash hash),
("m", showBin msg),
("l", showBin labelbstr),
("e", showX labelAlive),
("c", showBin cipher)], n)
genASCII :: MonadRandom m => Word8 -> m String
genASCII 0 = return ""
genASCII x =
do v <- (BS.head `fmap` getRandomBytes 1)
let c = chr (fromIntegral v)
if (v < 128) && isPrint c
then (c :) `fmap` genASCII (x - 1)
else genASCII x
encryptWith :: MonadRandom m =>
HashAlg -> Maybe BS.ByteString -> PublicKey -> BS.ByteString ->
m (Either Error BS.ByteString)
encryptWith Sha224 mlabel = encrypt (OAEPParams SHA224 (mgf1 SHA224) mlabel)
encryptWith Sha256 mlabel = encrypt (OAEPParams SHA256 (mgf1 SHA256) mlabel)
encryptWith Sha384 mlabel = encrypt (OAEPParams SHA384 (mgf1 SHA384) mlabel)
encryptWith Sha512 mlabel = encrypt (OAEPParams SHA512 (mgf1 SHA512) mlabel)

View File

@@ -1,56 +0,0 @@
{-# LANGUAGE PackageImports #-}
module Task(
Test,
Task(..),
runTask,
liftTest
)
where
import Control.Monad(foldM, forM_)
import "crypto-api" Crypto.Random(SystemRandom)
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 -> IO (Map.Map String String, Integer, Database)
data Task = Task {
taskName :: String,
taskFile :: FilePath,
taskTest :: Test,
taskCount :: Int
}
liftTest :: (Database -> (Map.Map String String, Integer, Database)) ->
(Database -> IO (Map.Map String String, Integer, Database))
liftTest f db = return (f db)
runTask :: SystemRandom -> Task -> IO SystemRandom
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 (output, key, acc@(db',gen')) <- runner db
let 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')

View File

@@ -1,35 +0,0 @@
{-# LANGUAGE PackageImports #-}
module Utils(HashAlg(..), generateHash, runHash, showHash)
where
import Crypto.Hash(Digest,SHA224(..),SHA256(..),SHA384(..),SHA512(..),hash)
import Crypto.Number.Generate(generateBetween)
import "cryptonite" Crypto.Random(MonadRandom)
import qualified Data.ByteArray as B
import qualified Data.ByteString as S
import Math(showX)
data HashAlg = Sha224 | Sha256 | Sha384 | Sha512
deriving (Eq, Show)
runHash :: HashAlg -> S.ByteString -> S.ByteString
runHash Sha224 x = S.pack (B.unpack (hash x :: Digest SHA224))
runHash Sha256 x = S.pack (B.unpack (hash x :: Digest SHA256))
runHash Sha384 x = S.pack (B.unpack (hash x :: Digest SHA384))
runHash Sha512 x = S.pack (B.unpack (hash x :: Digest SHA512))
showHash :: HashAlg -> String
showHash Sha224 = showX (224 :: Int)
showHash Sha256 = showX (256 :: Int)
showHash Sha384 = showX (384 :: Int)
showHash Sha512 = showX (512 :: Int)
generateHash :: MonadRandom m => m HashAlg
generateHash =
do x <- generateBetween 0 3
case x of
0 -> return Sha224
1 -> return Sha256
2 -> return Sha384
3 -> return Sha512
_ -> fail "Incompatible random number"

View File

@@ -1,96 +0,0 @@
/* ====================================================================
* Copyright (c) 2002-2006 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ==================================================================== */
#ifndef OPENSSL_HEADER_AES_H
#define OPENSSL_HEADER_AES_H
#include <GFp/base.h>
#if defined(__cplusplus)
extern "C" {
#endif
/* Raw AES functions. */
#define AES_ENCRYPT 1
#define AES_DECRYPT 0
/* AES_MAXNR is the maximum number of AES rounds. */
#define AES_MAXNR 14
#define AES_BLOCK_SIZE 16
/* aes_key_st should be an opaque type, but EVP requires that the size be
* known. */
struct aes_key_st {
uint32_t rd_key[4 * (AES_MAXNR + 1)];
unsigned rounds;
};
typedef struct aes_key_st AES_KEY;
/* GFp_AES_set_encrypt_key configures |aeskey| to encrypt with the |bits|-bit
* key, |key|.
*
* WARNING: unlike other OpenSSL functions, this returns zero on success and a
* negative number on error. */
OPENSSL_EXPORT int GFp_AES_set_encrypt_key(const uint8_t *key, unsigned bits,
AES_KEY *aeskey);
/* AES_encrypt encrypts a single block from |in| to |out| with |key|. The |in|
* and |out| pointers may overlap. */
OPENSSL_EXPORT void GFp_AES_encrypt(const uint8_t *in, uint8_t *out,
const AES_KEY *key);
#if defined(__cplusplus)
} /* extern C */
#endif
#endif /* OPENSSL_HEADER_AES_H */

View File

@@ -1,123 +0,0 @@
/* ====================================================================
* Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
#ifndef OPENSSL_HEADER_ARM_ARCH_H
#define OPENSSL_HEADER_ARM_ARCH_H
#if !defined(__ARM_ARCH__)
# if defined(__CC_ARM)
# define __ARM_ARCH__ __TARGET_ARCH_ARM
# if defined(__BIG_ENDIAN)
# define __ARMEB__
# else
# define __ARMEL__
# endif
# elif defined(__GNUC__)
# if defined(__aarch64__)
# define __ARM_ARCH__ 8
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define __ARMEB__
# else
# define __ARMEL__
# endif
/* Why doesn't gcc define __ARM_ARCH__? Instead it defines
* bunch of below macros. See all_architectires[] table in
* gcc/config/arm/arm.c. On a side note it defines
* __ARMEL__/__ARMEB__ for little-/big-endian. */
# elif defined(__ARM_ARCH)
# define __ARM_ARCH__ __ARM_ARCH
# elif defined(__ARM_ARCH_8A__)
# define __ARM_ARCH__ 8
# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__) || \
defined(__ARM_ARCH_7EM__)
# define __ARM_ARCH__ 7
# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__) || \
defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__) || \
defined(__ARM_ARCH_6T2__)
# define __ARM_ARCH__ 6
# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \
defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__) || \
defined(__ARM_ARCH_5TEJ__)
# define __ARM_ARCH__ 5
# elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
# define __ARM_ARCH__ 4
# else
# error "unsupported ARM architecture"
# endif
# endif
#endif
/* Even when building for 32-bit ARM, support for aarch64 crypto instructions
* will be included. */
#if !defined(__ARM_MAX_ARCH__)
#define __ARM_MAX_ARCH__ 8
#endif
/* ARMV7_NEON is true when a NEON unit is present in the current CPU. */
#define ARMV7_NEON (1 << 0)
/* ARMV8_AES indicates support for hardware AES instructions. */
#define ARMV8_AES (1 << 2)
/* ARMV8_SHA1 indicates support for hardware SHA-1 instructions. */
#define ARMV8_SHA1 (1 << 3)
/* ARMV8_SHA256 indicates support for hardware SHA-256 instructions. */
#define ARMV8_SHA256 (1 << 4)
/* ARMV8_PMULL indicates support for carryless multiplication. */
#define ARMV8_PMULL (1 << 5)
#endif /* OPENSSL_HEADER_ARM_ARCH_H */

View File

@@ -1,122 +0,0 @@
/* ====================================================================
* Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
#ifndef OPENSSL_HEADER_BASE_H
#define OPENSSL_HEADER_BASE_H
/* This file should be the first included by all BoringSSL headers. */
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64)
#define OPENSSL_64_BIT
#define OPENSSL_X86_64
#elif defined(__x86) || defined(__i386) || defined(__i386__) || defined(_M_IX86)
#define OPENSSL_32_BIT
#define OPENSSL_X86
#elif defined(__aarch64__)
#define OPENSSL_64_BIT
#define OPENSSL_AARCH64
#elif defined(__arm) || defined(__arm__) || defined(_M_ARM)
#define OPENSSL_32_BIT
#define OPENSSL_ARM
#elif (defined(__PPC64__) || defined(__powerpc64__)) && defined(_LITTLE_ENDIAN)
#define OPENSSL_64_BIT
#define OPENSSL_PPC64LE
#elif defined(__mips__) && !defined(__LP64__)
#define OPENSSL_32_BIT
#define OPENSSL_MIPS
#elif defined(__mips__) && defined(__LP64__)
#define OPENSSL_64_BIT
#define OPENSSL_MIPS64
#elif defined(__pnacl__)
#define OPENSSL_32_BIT
#define OPENSSL_PNACL
#elif defined(__myriad2__)
#define OPENSSL_32_BIT
#else
#error "Unknown target CPU"
#endif
#if defined(__APPLE__)
#define OPENSSL_APPLE
#endif
#if defined(_WIN32)
#define OPENSSL_WINDOWS
#endif
#define OPENSSL_IS_BORINGSSL
#define OPENSSL_IS_RING
#define OPENSSL_VERSION_NUMBER 0x10002000
/* *ring* doesn't support the `BORINGSSL_SHARED_LIBRARY` configuration, so
* the default (usually "hidden") visibility is always used, even for exported
* items. */
#define OPENSSL_EXPORT
typedef struct bignum_st BIGNUM;
#if defined(__cplusplus)
} /* extern C */
#endif
#endif /* OPENSSL_HEADER_BASE_H */

View File

@@ -1,256 +0,0 @@
/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
/* ====================================================================
* Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
/* ====================================================================
* Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
*
* Portions of the attached software ("Contribution") are developed by
* SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
*
* The Contribution is licensed pursuant to the Eric Young open source
* license provided above.
*
* The binary polynomial arithmetic software is originally written by
* Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
* Laboratories. */
#ifndef OPENSSL_HEADER_BN_H
#define OPENSSL_HEADER_BN_H
#include <GFp/base.h>
#if defined(__cplusplus)
extern "C" {
#endif
/* BN provides support for working with arbitrary sized integers. For example,
* although the largest integer supported by the compiler might be 64 bits, BN
* will allow you to work with numbers until you run out of memory. */
/* BN_ULONG is the native word size when working with big integers.
*
* Note: on some platforms, inttypes.h does not define print format macros in
* C++ unless |__STDC_FORMAT_MACROS| defined. As this is a public header, bn.h
* does not define |__STDC_FORMAT_MACROS| itself. C++ source files which use the
* FMT macros must define it externally. */
#if defined(OPENSSL_64_BIT)
#define BN_ULONG uint64_t
#define BN_BITS2 64
#elif defined(OPENSSL_32_BIT)
#define BN_ULONG uint32_t
#define BN_BITS2 32
#else
#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT"
#endif
/* Allocation and freeing. */
/* GFp_BN_init initialises a stack allocated |BIGNUM|. */
OPENSSL_EXPORT void GFp_BN_init(BIGNUM *bn);
/* GFp_BN_free frees the data referenced by |bn| and, if |bn| was originally
* allocated on the heap, frees |bn| also. */
OPENSSL_EXPORT void GFp_BN_free(BIGNUM *bn);
/* GFp_BN_copy sets |dest| equal to |src| and returns one on success or zero on
* failure. */
OPENSSL_EXPORT int GFp_BN_copy(BIGNUM *dest, const BIGNUM *src);
/* Basic functions. */
/* GFp_BN_zero sets |bn| to zero. */
OPENSSL_EXPORT void GFp_BN_zero(BIGNUM *bn);
/* Internal functions.
*
* These functions are useful for code that is doing low-level manipulations of
* BIGNUM values. However, be sure that no other function in this file does
* what you want before turning to these. */
/* bn_correct_top decrements |bn->top| until |bn->d[top-1]| is non-zero or
* until |top| is zero. */
OPENSSL_EXPORT void GFp_bn_correct_top(BIGNUM *bn);
/* bn_wexpand ensures that |bn| has at least |words| works of space without
* altering its value. It returns one on success and zero on allocation
* failure. */
OPENSSL_EXPORT int GFp_bn_wexpand(BIGNUM *bn, size_t words);
/* Simple arithmetic */
/* GFp_BN_mul_no_alias sets |r| = |a| * |b|, where |r| must not be the same pointer
* as |a| or |b|. Returns one on success and zero otherwise. */
OPENSSL_EXPORT int GFp_BN_mul_no_alias(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
/* Comparison functions */
/* GFp_BN_is_odd returns one if |bn| is odd and zero otherwise. */
OPENSSL_EXPORT int GFp_BN_is_odd(const BIGNUM *bn);
/* Bitwise operations. */
/* GFp_BN_is_bit_set returns the value of the |n|th, least-significant bit in
* |a|, or zero if the bit doesn't exist. */
OPENSSL_EXPORT int GFp_BN_is_bit_set(const BIGNUM *a, int n);
/* Modulo arithmetic. */
/* GFp_BN_mod_mul_mont set |r| equal to |a| * |b|, in the Montgomery domain.
* Both |a| and |b| must already be in the Montgomery domain (by
* |GFp_BN_to_mont|). In particular, |a| and |b| are assumed to be in the range
* [0, n), where |n| is the Montgomery modulus. It returns one on success or
* zero on error. */
OPENSSL_EXPORT int GFp_BN_mod_mul_mont(
BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *n,
const BN_ULONG n0[/*BN_MONT_CTX_N0_LIMBS*/]);
/* GFp_BN_reduce_montgomery returns |a % n| in constant-ish time using
* Montgomery reduction. |a| is assumed to be in the range [0, n**2), where |n|
* is the Montgomery modulus. It returns one on success or zero on error. */
int GFp_BN_reduce_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *n,
const BN_ULONG n0[/*BN_MONT_CTX_N0_LIMBS*/]);
/* Exponentiation. */
OPENSSL_EXPORT int GFp_BN_mod_exp_mont_consttime(
BIGNUM *rr, const BIGNUM *a_mont, const BIGNUM *p, size_t p_bits,
const BIGNUM *one_mont, const BIGNUM *n,
const BN_ULONG n0[/*BN_MONT_CTX_N0_LIMBS*/]);
/* Private functions */
/* Keep in sync with `BIGNUM` in `ring::rsa::bigint`. */
struct bignum_st {
BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks in little-endian
order. */
int top; /* Index of last used element in |d|, plus one. */
int dmax; /* Size of |d|, in words. */
int flags; /* bitmask of BN_FLG_* values */
};
#define BN_FLG_MALLOCED 0x01
#define BN_FLG_STATIC_DATA 0x02
#if defined(__cplusplus)
} /* extern C */
#endif
#endif /* OPENSSL_HEADER_BN_H */

View File

@@ -1,189 +0,0 @@
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
#ifndef OPENSSL_HEADER_CPU_H
#define OPENSSL_HEADER_CPU_H
#include <GFp/base.h>
#if defined(__cplusplus)
extern "C" {
#endif
/* Runtime CPU feature support */
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
/* GFp_ia32cap_P contains the Intel CPUID bits when running on an x86 or
* x86-64 system.
*
* Index 0:
* EDX for CPUID where EAX = 1
* Bit 20 is always zero
* Bit 28 is adjusted to reflect whether the data cache is shared between
* multiple logical cores
* Bit 30 is used to indicate an Intel CPU
* Index 1:
* ECX for CPUID where EAX = 1
* Bit 11 is used to indicate AMD XOP support, not SDBG
* Index 2:
* EBX for CPUID where EAX = 7
* Index 3 is set to zero.
*
* Note: the CPUID bits are pre-adjusted for the OSXSAVE bit and the YMM and XMM
* bits in XCR0, so it is not necessary to check those. */
extern uint32_t GFp_ia32cap_P[4];
#endif
#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
#if defined(OPENSSL_APPLE)
/* iOS builds use the static ARM configuration. */
#define OPENSSL_STATIC_ARMCAP
#if defined(OPENSSL_AARCH64)
#define OPENSSL_STATIC_ARMCAP_AES
#define OPENSSL_STATIC_ARMCAP_SHA1
#define OPENSSL_STATIC_ARMCAP_SHA256
#define OPENSSL_STATIC_ARMCAP_PMULL
#endif
#endif
#if !defined(OPENSSL_STATIC_ARMCAP)
/* GFp_is_NEON_capable_at_runtime returns true if the current CPU has a NEON
* unit. Note that |OPENSSL_armcap_P| also exists and contains the same
* information in a form that's easier for assembly to use. */
OPENSSL_EXPORT uint8_t GFp_is_NEON_capable_at_runtime(void);
/* GFp_is_NEON_capable returns true if the current CPU has a NEON unit. If
* this is known statically then it returns one immediately. */
static inline int GFp_is_NEON_capable(void) {
/* On 32-bit ARM, one CPU is known to have a broken NEON unit which is known
* to fail with on some hand-written NEON assembly. Assume that non-Android
* applications will not use that buggy CPU but still support Android users
* that do, even when the compiler is instructed to freely emit NEON code.
* See https://crbug.com/341598 and https://crbug.com/606629. */
#if defined(__ARM_NEON__) && (!defined(OPENSSL_ARM) || !defined(__ANDROID__))
return 1;
#else
return GFp_is_NEON_capable_at_runtime();
#endif
}
#if defined(OPENSSL_ARM)
/* GFp_has_broken_NEON returns one if the current CPU is known to have a
* broken NEON unit. See https://crbug.com/341598. */
OPENSSL_EXPORT int GFp_has_broken_NEON(void);
#endif
/* GFp_is_ARMv8_AES_capable returns true if the current CPU supports the
* ARMv8 AES instruction. */
int GFp_is_ARMv8_AES_capable(void);
/* GFp_is_ARMv8_PMULL_capable returns true if the current CPU supports the
* ARMv8 PMULL instruction. */
int GFp_is_ARMv8_PMULL_capable(void);
#else
static inline int GFp_is_NEON_capable(void) {
#if defined(OPENSSL_STATIC_ARMCAP_NEON) || defined(__ARM_NEON__)
return 1;
#else
return 0;
#endif
}
static inline int GFp_is_ARMv8_AES_capable(void) {
#if defined(OPENSSL_STATIC_ARMCAP_AES)
return 1;
#else
return 0;
#endif
}
static inline int GFp_is_ARMv8_PMULL_capable(void) {
#if defined(OPENSSL_STATIC_ARMCAP_PMULL)
return 1;
#else
return 0;
#endif
}
#endif /* OPENSSL_STATIC_ARMCAP */
#endif /* OPENSSL_ARM || OPENSSL_AARCH64 */
#if defined(OPENSSL_PPC64LE)
/* CRYPTO_is_PPC64LE_vcrypto_capable returns true iff the current CPU supports
* the Vector.AES category of instructions. */
int CRYPTO_is_PPC64LE_vcrypto_capable(void);
#endif /* OPENSSL_PPC64LE */
#if defined(__cplusplus)
} /* extern C */
#endif
#endif /* OPENSSL_HEADER_CPU_H */

View File

@@ -1,93 +0,0 @@
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
#ifndef OPENSSL_HEADER_MEM_H
#define OPENSSL_HEADER_MEM_H
#include <GFp/base.h>
#include <stdlib.h>
#if defined(__cplusplus)
extern "C" {
#endif
/* Memory and string functions, see also buf.h.
*
* OpenSSL has, historically, had a complex set of malloc debugging options.
* However, that was written in a time before Valgrind and ASAN. Since we now
* have those tools, the OpenSSL allocation functions are simply macros around
* the standard memory functions. */
#define OPENSSL_malloc malloc
#define OPENSSL_realloc realloc
#define OPENSSL_free free
/* GFp_memcmp returns zero iff the |len| bytes at |a| and |b| are equal. It
* takes an amount of time dependent on |len|, but independent of the contents
* of |a| and |b|. Unlike memcmp, it cannot be used to put elements into a
* defined order as the return value when a != b is undefined, other than to be
* non-zero. */
OPENSSL_EXPORT int GFp_memcmp(const void *a, const void *b, size_t len);
#if defined(__cplusplus)
} /* extern C */
#endif
#endif /* OPENSSL_HEADER_MEM_H */

View File

@@ -1,75 +0,0 @@
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
#ifndef OPENSSL_HEADER_TYPE_CHECK_H
#define OPENSSL_HEADER_TYPE_CHECK_H
#include <GFp/base.h>
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define OPENSSL_COMPILE_ASSERT(cond, msg) _Static_assert(cond, #msg)
#elif defined(__GNUC__)
#define OPENSSL_COMPILE_ASSERT(cond, msg) \
typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)] \
__attribute__((unused))
#else
#define OPENSSL_COMPILE_ASSERT(cond, msg) \
typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)]
#endif
#endif /* OPENSSL_HEADER_TYPE_CHECK_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,109 +0,0 @@
/* Copyright (c) 2015, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#ifndef OPENSSL_HEADER_CURVE25519_INTERNAL_H
#define OPENSSL_HEADER_CURVE25519_INTERNAL_H
#include <GFp/base.h>
#include <stdint.h>
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(OPENSSL_X86_64) && !defined(OPENSSL_SMALL) && \
!defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_ASM)
/* This isn't compatible with Windows because the asm code makes use of the red
* zone, which Windows doesn't support. */
#define BORINGSSL_X25519_X86_64
void GFp_x25519_x86_64(uint8_t out[32], const uint8_t scalar[32],
const uint8_t point[32]);
#endif
#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
#define BORINGSSL_X25519_NEON
/* x25519_NEON is defined in asm/x25519-arm.S. */
void GFp_x25519_NEON(uint8_t out[32], const uint8_t scalar[32],
const uint8_t point[32]);
#endif
/* fe means field element. Here the field is \Z/(2^255-19). An element t,
* entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
* t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
* context.
*
* Keep in sync with `Elem` and `ELEM_LIMBS` in curve25519/ops.rs. */
typedef int32_t fe[10];
/* ge means group element.
* Here the group is the set of pairs (x,y) of field elements (see fe.h)
* satisfying -x^2 + y^2 = 1 + d x^2y^2
* where d = -121665/121666.
*
* Representations:
* ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
* ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
* ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
* ge_precomp (Duif): (y+x,y-x,2dxy)
*/
/* Keep in sync with `Point` in curve25519/ops.rs. */
typedef struct {
fe X;
fe Y;
fe Z;
} ge_p2;
/* Keep in sync with `ExtPoint` in curve25519/ops.rs. */
typedef struct {
fe X;
fe Y;
fe Z;
fe T;
} ge_p3;
typedef struct {
fe X;
fe Y;
fe Z;
fe T;
} ge_p1p1;
typedef struct {
fe yplusx;
fe yminusx;
fe xy2d;
} ge_precomp;
typedef struct {
fe YplusX;
fe YminusX;
fe Z;
fe T2d;
} ge_cached;
#if defined(__cplusplus)
} /* extern C */
#endif
#endif /* OPENSSL_HEADER_CURVE25519_INTERNAL_H */

View File

@@ -1,361 +0,0 @@
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
/* ====================================================================
* Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
#ifndef OPENSSL_HEADER_CRYPTO_INTERNAL_H
#define OPENSSL_HEADER_CRYPTO_INTERNAL_H
#include <assert.h>
#if defined(__clang__) || defined(_MSC_VER)
#include <string.h>
#endif
#include <stddef.h>
#include <GFp/base.h>
#include <GFp/type_check.h>
#if defined(_MSC_VER)
#pragma warning(push, 3)
#include <intrin.h>
#pragma warning(pop)
#if !defined(__cplusplus)
#define alignas(x) __declspec(align(x))
#define alignof __alignof
#endif
#elif !defined(__clang__) && defined(__GNUC__) && __GNUC__ == 4 && \
__GNUC_MINOR__ <= 6
#define alignas(x) __attribute__((aligned (x)))
#define alignof __alignof__
#else
#include <stdalign.h>
#endif
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM) || \
defined(OPENSSL_AARCH64) || defined(OPENSSL_PPC64LE)
/* OPENSSL_cpuid_setup initializes the platform-specific feature cache. */
void GFp_cpuid_setup(void);
#endif
#define OPENSSL_LITTLE_ENDIAN 1
#define OPENSSL_BIG_ENDIAN 2
#if defined(OPENSSL_X86_64) || defined(OPENSSL_X86) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define OPENSSL_ENDIAN OPENSSL_LITTLE_ENDIAN
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define OPENSSL_ENDIAN OPENSSL_BIG_ENDIAN
#else
#error "Cannot determine endianness"
#endif
#if defined(__GNUC__)
#define bswap_u32(x) __builtin_bswap32(x)
#define bswap_u64(x) __builtin_bswap64(x)
#elif defined(_MSC_VER)
#pragma intrinsic(_byteswap_ulong, _byteswap_uint64)
#define bswap_u32(x) _byteswap_ulong(x)
#define bswap_u64(x) _byteswap_uint64(x)
#endif
#if !defined(_MSC_VER) && defined(OPENSSL_64_BIT)
typedef __int128_t int128_t;
typedef __uint128_t uint128_t;
#endif
/* Constant-time utility functions.
*
* The following methods return a bitmask of all ones (0xff...f) for true and 0
* for false. This is useful for choosing a value based on the result of a
* conditional in constant time. */
/* constant_time_msb returns the given value with the MSB copied to all the
* other bits. */
static inline unsigned int constant_time_msb_unsigned(unsigned int a) {
return (unsigned int)((int)(a) >> (sizeof(int) * 8 - 1));
}
OPENSSL_COMPILE_ASSERT(sizeof(ptrdiff_t) == sizeof(size_t),
ptrdiff_t_and_size_t_are_different_sizes);
static inline size_t constant_time_msb_size_t(size_t a) {
return (size_t)((ptrdiff_t)(a) >> (sizeof(ptrdiff_t) * 8 - 1));
}
/* constant_time_is_zero returns 0xff..f if a == 0 and 0 otherwise. */
static inline unsigned int constant_time_is_zero_unsigned(unsigned int a) {
/* Here is an SMT-LIB verification of this formula:
*
* (define-fun is_zero ((a (_ BitVec 32))) (_ BitVec 32)
* (bvand (bvnot a) (bvsub a #x00000001))
* )
*
* (declare-fun a () (_ BitVec 32))
*
* (assert (not (= (= #x00000001 (bvlshr (is_zero a) #x0000001f)) (= a #x00000000))))
* (check-sat)
* (get-model)
*/
return constant_time_msb_unsigned(~a & (a - 1));
}
/* constant_time_is_zero_size_t is like |constant_time_is_zero_unsigned| but
* operates on |size_t|. */
static inline size_t constant_time_is_zero_size_t(size_t a) {
return constant_time_msb_size_t(~a & (a - 1));
}
static inline size_t constant_time_is_nonzero_size_t(size_t a) {
return constant_time_is_zero_size_t(constant_time_is_zero_size_t(a));
}
/* constant_time_eq_int returns 0xff..f if a == b and 0 otherwise. */
static inline unsigned int constant_time_eq_int(int a, int b) {
return constant_time_is_zero_unsigned((unsigned)(a) ^ (unsigned)(b));
}
/* constant_time_eq_size_t acts like |constant_time_eq_int| but operates on
* |size_t|. */
static inline size_t constant_time_eq_size_t(size_t a, size_t b) {
return constant_time_is_zero_size_t(a ^ b);
}
/* constant_time_select_size_t returns (mask & a) | (~mask & b). When |mask| is
* all 1s or all 0s (as returned by the methods above), the select methods
* return either |a| (if |mask| is nonzero) or |b| (if |mask| is zero). it is
* derived from BoringSSL's |constant_time_select|. */
static inline size_t constant_time_select_size_t(size_t mask, size_t a,
size_t b) {
return (mask & a) | (~mask & b);
}
/* from_be_u32_ptr returns the 32-bit big-endian-encoded value at |data|. */
static inline uint32_t from_be_u32_ptr(const uint8_t *data) {
#if defined(__clang__) || defined(_MSC_VER)
/* XXX: Unlike GCC, Clang doesn't optimize compliant access to unaligned data
* well. See https://llvm.org/bugs/show_bug.cgi?id=20605,
* https://llvm.org/bugs/show_bug.cgi?id=17603,
* http://blog.regehr.org/archives/702, and
* http://blog.regehr.org/archives/1055. MSVC seems to have similar problems.
*/
uint32_t value;
memcpy(&value, data, sizeof(value));
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
value = bswap_u32(value);
#endif
return value;
#else
return ((uint32_t)data[0] << 24) |
((uint32_t)data[1] << 16) |
((uint32_t)data[2] << 8) |
((uint32_t)data[3]);
#endif
}
/* from_be_u64_ptr returns the 64-bit big-endian-encoded value at |data|. */
static inline uint64_t from_be_u64_ptr(const uint8_t *data) {
#if defined(__clang__) || defined(_MSC_VER)
/* XXX: Unlike GCC, Clang doesn't optimize compliant access to unaligned data
* well. See https://llvm.org/bugs/show_bug.cgi?id=20605,
* https://llvm.org/bugs/show_bug.cgi?id=17603,
* http://blog.regehr.org/archives/702, and
* http://blog.regehr.org/archives/1055. MSVC seems to have similar problems.
*/
uint64_t value;
memcpy(&value, data, sizeof(value));
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
value = bswap_u64(value);
#endif
return value;
#else
return ((uint64_t)data[0] << 56) |
((uint64_t)data[1] << 48) |
((uint64_t)data[2] << 40) |
((uint64_t)data[3] << 32) |
((uint64_t)data[4] << 24) |
((uint64_t)data[5] << 16) |
((uint64_t)data[6] << 8) |
((uint64_t)data[7]);
#endif
}
/* to_be_u32_ptr writes the value |x| to the location |out| in big-endian
order. */
static inline void to_be_u32_ptr(uint8_t *out, uint32_t value) {
#if defined(__clang__) || defined(_MSC_VER)
/* XXX: Unlike GCC, Clang doesn't optimize compliant access to unaligned data
* well. See https://llvm.org/bugs/show_bug.cgi?id=20605,
* https://llvm.org/bugs/show_bug.cgi?id=17603,
* http://blog.regehr.org/archives/702, and
* http://blog.regehr.org/archives/1055. MSVC seems to have similar problems.
*/
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
value = bswap_u32(value);
#endif
memcpy(out, &value, sizeof(value));
#else
out[0] = (uint8_t)(value >> 24);
out[1] = (uint8_t)(value >> 16);
out[2] = (uint8_t)(value >> 8);
out[3] = (uint8_t)value;
#endif
}
/* to_be_u64_ptr writes the value |value| to the location |out| in big-endian
order. */
static inline void to_be_u64_ptr(uint8_t *out, uint64_t value) {
#if defined(__clang__) || defined(_MSC_VER)
/* XXX: Unlike GCC, Clang doesn't optimize compliant access to unaligned data
* well. See https://llvm.org/bugs/show_bug.cgi?id=20605,
* https://llvm.org/bugs/show_bug.cgi?id=17603,
* http://blog.regehr.org/archives/702, and
* http://blog.regehr.org/archives/1055. MSVC seems to have similar problems.
*/
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
value = bswap_u64(value);
#endif
memcpy(out, &value, sizeof(value));
#else
out[0] = (uint8_t)(value >> 56);
out[1] = (uint8_t)(value >> 48);
out[2] = (uint8_t)(value >> 40);
out[3] = (uint8_t)(value >> 32);
out[4] = (uint8_t)(value >> 24);
out[5] = (uint8_t)(value >> 16);
out[6] = (uint8_t)(value >> 8);
out[7] = (uint8_t)value;
#endif
}
/* from_be_u64 returns the native representation of the 64-bit
* big-endian-encoded value |x|. */
static inline uint64_t from_be_u64(uint64_t x) {
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
x = bswap_u64(x);
#endif
return x;
}
#if defined(__cplusplus)
} /* extern C */
#endif
#endif /* OPENSSL_HEADER_CRYPTO_INTERNAL_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,244 +0,0 @@
/* Copyright (c) 2015, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
/* This code is mostly taken from the ref10 version of Ed25519 in SUPERCOP
* 20141124 (http://bench.cr.yp.to/supercop.html). That code is released as
* public domain but this file has the ISC license just to keep licencing
* simple.
*
* The field functions are shared by Ed25519 and X25519 where possible. */
#include <string.h>
#include "internal.h"
#if defined(BORINGSSL_X25519_X86_64)
typedef struct { uint64_t v[5]; } fe25519;
/* These functions are defined in asm/x25519-x86_64.S */
void GFp_x25519_x86_64_work_cswap(fe25519 *, uint64_t);
void GFp_x25519_x86_64_mul(fe25519 *out, const fe25519 *a, const fe25519 *b);
void GFp_x25519_x86_64_square(fe25519 *out, const fe25519 *a);
void GFp_x25519_x86_64_freeze(fe25519 *);
void GFp_x25519_x86_64_ladderstep(fe25519 *work);
static void fe25519_setint(fe25519 *r, unsigned v) {
r->v[0] = v;
r->v[1] = 0;
r->v[2] = 0;
r->v[3] = 0;
r->v[4] = 0;
}
/* Assumes input x being reduced below 2^255 */
static void fe25519_pack(unsigned char r[32], const fe25519 *x) {
fe25519 t;
t = *x;
GFp_x25519_x86_64_freeze(&t);
r[0] = (uint8_t)(t.v[0] & 0xff);
r[1] = (uint8_t)((t.v[0] >> 8) & 0xff);
r[2] = (uint8_t)((t.v[0] >> 16) & 0xff);
r[3] = (uint8_t)((t.v[0] >> 24) & 0xff);
r[4] = (uint8_t)((t.v[0] >> 32) & 0xff);
r[5] = (uint8_t)((t.v[0] >> 40) & 0xff);
r[6] = (uint8_t)((t.v[0] >> 48));
r[6] ^= (uint8_t)((t.v[1] << 3) & 0xf8);
r[7] = (uint8_t)((t.v[1] >> 5) & 0xff);
r[8] = (uint8_t)((t.v[1] >> 13) & 0xff);
r[9] = (uint8_t)((t.v[1] >> 21) & 0xff);
r[10] = (uint8_t)((t.v[1] >> 29) & 0xff);
r[11] = (uint8_t)((t.v[1] >> 37) & 0xff);
r[12] = (uint8_t)((t.v[1] >> 45));
r[12] ^= (uint8_t)((t.v[2] << 6) & 0xc0);
r[13] = (uint8_t)((t.v[2] >> 2) & 0xff);
r[14] = (uint8_t)((t.v[2] >> 10) & 0xff);
r[15] = (uint8_t)((t.v[2] >> 18) & 0xff);
r[16] = (uint8_t)((t.v[2] >> 26) & 0xff);
r[17] = (uint8_t)((t.v[2] >> 34) & 0xff);
r[18] = (uint8_t)((t.v[2] >> 42) & 0xff);
r[19] = (uint8_t)((t.v[2] >> 50));
r[19] ^= (uint8_t)((t.v[3] << 1) & 0xfe);
r[20] = (uint8_t)((t.v[3] >> 7) & 0xff);
r[21] = (uint8_t)((t.v[3] >> 15) & 0xff);
r[22] = (uint8_t)((t.v[3] >> 23) & 0xff);
r[23] = (uint8_t)((t.v[3] >> 31) & 0xff);
r[24] = (uint8_t)((t.v[3] >> 39) & 0xff);
r[25] = (uint8_t)((t.v[3] >> 47));
r[25] ^= (uint8_t)((t.v[4] << 4) & 0xf0);
r[26] = (uint8_t)((t.v[4] >> 4) & 0xff);
r[27] = (uint8_t)((t.v[4] >> 12) & 0xff);
r[28] = (uint8_t)((t.v[4] >> 20) & 0xff);
r[29] = (uint8_t)((t.v[4] >> 28) & 0xff);
r[30] = (uint8_t)((t.v[4] >> 36) & 0xff);
r[31] = (uint8_t)((t.v[4] >> 44));
}
static void fe25519_unpack(fe25519 *r, const uint8_t x[32]) {
r->v[0] = x[0];
r->v[0] += (uint64_t)x[1] << 8;
r->v[0] += (uint64_t)x[2] << 16;
r->v[0] += (uint64_t)x[3] << 24;
r->v[0] += (uint64_t)x[4] << 32;
r->v[0] += (uint64_t)x[5] << 40;
r->v[0] += ((uint64_t)x[6] & 7) << 48;
r->v[1] = x[6] >> 3;
r->v[1] += (uint64_t)x[7] << 5;
r->v[1] += (uint64_t)x[8] << 13;
r->v[1] += (uint64_t)x[9] << 21;
r->v[1] += (uint64_t)x[10] << 29;
r->v[1] += (uint64_t)x[11] << 37;
r->v[1] += ((uint64_t)x[12] & 63) << 45;
r->v[2] = x[12] >> 6;
r->v[2] += (uint64_t)x[13] << 2;
r->v[2] += (uint64_t)x[14] << 10;
r->v[2] += (uint64_t)x[15] << 18;
r->v[2] += (uint64_t)x[16] << 26;
r->v[2] += (uint64_t)x[17] << 34;
r->v[2] += (uint64_t)x[18] << 42;
r->v[2] += ((uint64_t)x[19] & 1) << 50;
r->v[3] = x[19] >> 1;
r->v[3] += (uint64_t)x[20] << 7;
r->v[3] += (uint64_t)x[21] << 15;
r->v[3] += (uint64_t)x[22] << 23;
r->v[3] += (uint64_t)x[23] << 31;
r->v[3] += (uint64_t)x[24] << 39;
r->v[3] += ((uint64_t)x[25] & 15) << 47;
r->v[4] = x[25] >> 4;
r->v[4] += (uint64_t)x[26] << 4;
r->v[4] += (uint64_t)x[27] << 12;
r->v[4] += (uint64_t)x[28] << 20;
r->v[4] += (uint64_t)x[29] << 28;
r->v[4] += (uint64_t)x[30] << 36;
r->v[4] += ((uint64_t)x[31] & 127) << 44;
}
static void fe25519_invert(fe25519 *r, const fe25519 *x) {
fe25519 z2;
fe25519 z9;
fe25519 z11;
fe25519 z2_5_0;
fe25519 z2_10_0;
fe25519 z2_20_0;
fe25519 z2_50_0;
fe25519 z2_100_0;
fe25519 t;
int i;
/* 2 */ GFp_x25519_x86_64_square(&z2, x);
/* 4 */ GFp_x25519_x86_64_square(&t, &z2);
/* 8 */ GFp_x25519_x86_64_square(&t, &t);
/* 9 */ GFp_x25519_x86_64_mul(&z9, &t, x);
/* 11 */ GFp_x25519_x86_64_mul(&z11, &z9, &z2);
/* 22 */ GFp_x25519_x86_64_square(&t, &z11);
/* 2^5 - 2^0 = 31 */ GFp_x25519_x86_64_mul(&z2_5_0, &t, &z9);
/* 2^6 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_5_0);
/* 2^20 - 2^10 */ for (i = 1; i < 5; i++) { GFp_x25519_x86_64_square(&t, &t); }
/* 2^10 - 2^0 */ GFp_x25519_x86_64_mul(&z2_10_0, &t, &z2_5_0);
/* 2^11 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_10_0);
/* 2^20 - 2^10 */ for (i = 1; i < 10; i++) { GFp_x25519_x86_64_square(&t, &t); }
/* 2^20 - 2^0 */ GFp_x25519_x86_64_mul(&z2_20_0, &t, &z2_10_0);
/* 2^21 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_20_0);
/* 2^40 - 2^20 */ for (i = 1; i < 20; i++) { GFp_x25519_x86_64_square(&t, &t); }
/* 2^40 - 2^0 */ GFp_x25519_x86_64_mul(&t, &t, &z2_20_0);
/* 2^41 - 2^1 */ GFp_x25519_x86_64_square(&t, &t);
/* 2^50 - 2^10 */ for (i = 1; i < 10; i++) { GFp_x25519_x86_64_square(&t, &t); }
/* 2^50 - 2^0 */ GFp_x25519_x86_64_mul(&z2_50_0, &t, &z2_10_0);
/* 2^51 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_50_0);
/* 2^100 - 2^50 */ for (i = 1; i < 50; i++) { GFp_x25519_x86_64_square(&t, &t); }
/* 2^100 - 2^0 */ GFp_x25519_x86_64_mul(&z2_100_0, &t, &z2_50_0);
/* 2^101 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_100_0);
/* 2^200 - 2^100 */ for (i = 1; i < 100; i++) {
GFp_x25519_x86_64_square(&t, &t);
}
/* 2^200 - 2^0 */ GFp_x25519_x86_64_mul(&t, &t, &z2_100_0);
/* 2^201 - 2^1 */ GFp_x25519_x86_64_square(&t, &t);
/* 2^250 - 2^50 */ for (i = 1; i < 50; i++) { GFp_x25519_x86_64_square(&t, &t); }
/* 2^250 - 2^0 */ GFp_x25519_x86_64_mul(&t, &t, &z2_50_0);
/* 2^251 - 2^1 */ GFp_x25519_x86_64_square(&t, &t);
/* 2^252 - 2^2 */ GFp_x25519_x86_64_square(&t, &t);
/* 2^253 - 2^3 */ GFp_x25519_x86_64_square(&t, &t);
/* 2^254 - 2^4 */ GFp_x25519_x86_64_square(&t, &t);
/* 2^255 - 2^5 */ GFp_x25519_x86_64_square(&t, &t);
/* 2^255 - 21 */ GFp_x25519_x86_64_mul(r, &t, &z11);
}
static void mladder(fe25519 *xr, fe25519 *zr, const uint8_t s[32]) {
fe25519 work[5];
work[0] = *xr;
fe25519_setint(work + 1, 1);
fe25519_setint(work + 2, 0);
work[3] = *xr;
fe25519_setint(work + 4, 1);
int i, j;
uint8_t prevbit = 0;
j = 6;
for (i = 31; i >= 0; i--) {
while (j >= 0) {
const uint8_t bit = 1 & (s[i] >> j);
const uint64_t swap = bit ^ prevbit;
prevbit = bit;
GFp_x25519_x86_64_work_cswap(work + 1, swap);
GFp_x25519_x86_64_ladderstep(work);
j -= 1;
}
j = 7;
}
*xr = work[1];
*zr = work[2];
}
void GFp_x25519_x86_64(uint8_t out[32], const uint8_t scalar[32],
const uint8_t point[32]) {
uint8_t e[32];
memcpy(e, scalar, sizeof(e));
e[0] &= 248;
e[31] &= 127;
e[31] |= 64;
fe25519 t;
fe25519 z;
fe25519_unpack(&t, point);
mladder(&t, &z, e);
fe25519_invert(&z, &z);
GFp_x25519_x86_64_mul(&t, &t, &z);
fe25519_pack(out, &t);
}
#endif /* BORINGSSL_X25519_X86_64 */

View File

@@ -1,34 +0,0 @@
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 ""

View File

@@ -1,32 +0,0 @@
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, DSA, ECDSATesting, ED25519, ED25519.PrecompPoints, Math, RFC6979, RSA, Task, Utils
-- other-extensions:
build-depends: base >=4.11 && < 4.14, ascii-progress, bytestring, containers, crypto-api, cryptonite, directory, DSA, filepath, integer-gmp, memory, random
hs-source-dirs: .
c-sources: cbits/curve25519.c cbits/x25519-x86_64.c cbits/x25519-asm-x86_64.S
include-dirs: cbits
default-language: Haskell2010
ghc-options: -Wall -O2 -threaded -rtsopts -with-rtsopts=-N
if os(Windows) || !arch(x86_64)
buildable: False

File diff suppressed because it is too large Load Diff

View File

@@ -1,909 +0,0 @@
g: 6907a072b81862e4621de1cf1173e5d7b26a0da7eb3877a3fd8e5160e1f3958287f25b8e55635bdea4b3a94282a49b0b89cd962dcd61643bd2a8da0017b85476f951101581c893d67058f0ca37d7bebbfad0857a5f791fed2f505585cefd0839ba2628bcf409e6ea5fc7d2fb709dfd248876051807c0e1dcb5eee9b96c43e17db13f0548b8e0416a764240a33352050f7fd06c1f3fe3492050a6bd1e5432b03b2af8aead27ef9dac53134021478c9b521a41f52f1dd52a6a7883816535ac4057032555c9991992ce65e185fdbb488f9bd6b8ec0d5425df81ec9403b2412e7b620ccd82b0858467902f60d7e0df054da343bb30129bec45ab73ef62f0971fc45d
h: e0
m: 5b9e51587484af8c2957348f419848441ba271829bf358115919d834092df9e2a350af38c64d0e1406aad9e2af9affd112a22420e4230700b8d4579adf6b02f2368eb676a8682506a6c5bf21519605ae47963372eb2cbbab375c7841b7432da5d13ca4b002be02b9be001deec4d7083599b0226e5e7cbaa43f2d22556761a2cae25eff4cd819084a68fb4573dc46c2663e9ce12b0d648e4f1eca3b8197470361a2ee2d284a099feebec8a377662f38443007a9fb1498fd1f179627ff0ab300c2ec2e2050a8f109d8b28d295d983ef88568996b3642eb2757f3daed5109a94fa426cde7d4d281d84bc0190617cb86
p: a4da0f697eed92e72fabb0a538fbf690b7809086a59c7f119ca18dff733699f80f9caa59e9630d9aaf90c2dc17add835ce54197cb95269c3f767d68e5d5e3dd454fccc7a01816a588ca1f4cc7344b20e457c32c4557061f46f6736d932cd5eac60c05ded929dc8ebd9082bf685e478b6bd497f653611e9f8a8c10aaf2409136ab5b5a2563363ded71303e66c03f9a6aa70c19b73def6868c40ed94da2cb296f3f36ca060884c634b69c5e3622767ca6e8b7c8fb81991a5ffabd7aea867b0edfdba5e6cfecc13262a290ed4069116150b25321390bcc19c95c3ca42d0bca04e9012f4f828964fc31f094c032235464a6649f0b222ad86fba3ad6ceab8d3c4c5c7
q: e09ad72fa8ea898997ab1894288e16803641f7f539089414bbf93165
r: 5dc513689b5bc9cda535bf07b3c06214ae12b7b2bb512496445689db
s: c463bd68fe6d7afe144dd62530ecb62c0b084252fedbd3a92b8473b
x: 1427aa251a0b4ed1c664134bd4e7a69e5169ebd225b16de51febb5ca
y: 641c6c8808db6498a3ada4fbf9b3bb84071f2d5b5da68296fdde7f6274713a3ea244e0a6b9da75941d8f36a706df3384d473edd5681e9f9ffa6c6aa3bfd4ad77d8c1164fa2e4f46b3cb07e12dda96c2cdbe80521c459a1c5c0a80ab8f8b5505bf70666b56abfe21ea5f787bd9473f36cafd457c413c9d96bc24d29ac8f1d5defa6307c0bbc45ed11b65ad094257de972691e7dca315bc0054d6ee61bf2577fb190b13f0d4b07bd25a19d6b0913c47844175b09ff0af0344abb08e17736df0e61e16f924c04d9e9b990103ba2926dfed2451c2c79e91b8f863333207ebfa3237be0af3661abbf4f4a98cbb64d1f233a3033fce05006ab41d30072348439a38475
g: c768c234f7113f2d1631b5642275bcafe0a819d744ab8bd4f2f1d4852873b5c7ce22cde75119922239dbc3c6164835efcccb9a1c41d8f2db1bb5e43806ea1940d69e6439f5015fdf58f638d83b57f5f1095d460fe33fb07dca787cc02e21d890cf80e4f13f70925f19416568f90721e1d1ebadb1d6ba40ec528f13b2b2a91b85fdfc3cccb18d49b604b6d93ac61b092e7c094000ed34970ee12934512c394f0813f5be8556c595c2d550c2dbc35730134673541180a757917af95dfacc2550795cf53ccc6a37cc81bb8c68001198cea59dc908c5222b8533e22c08cfebc1d2355f64ae7bed6a4883c60c5aeb3226d0ef2703051d978af5d972318a5fef4d14c
h: 180
m: ba984e8297d8acde096f55bd1fa2b4aed9e5c9dbb3160d5dcf23fd6c29a5e7b71b4e120d3ea07c908c57d0e0104d0ed67c2d41db541c0e19076c6b490cc55cfcc6ca8bdd39f5f38c4200bb15671cf9a0bebfba5d98f76306f436b9ad8b90545402943457895e3543add17f8a
p: c2b3b3adb34dde06655d9dfa8f1f24f909c21a04dccbc33be3c31ec0a0878790aff2e59c8ef8a62e0a50a255569c20a5d38ffe80b876026ec0bb5aa49fe194ffa517b30400dd67b85eb37af2026bc66f659ed4fd60c271351e4992889b163f236e96b2bd9ad5fef239d32afd7699fb8447745ef6c26b4d66cd0c5eba1713d952b752f81a1bef5ffa72e6402497b0be3c88811808161d43f90ee8c8460ef7d5aa52959d8239c29d1f531872f021a9131d0f39120bec78624b159a3a4f96add0664729b549d03403498f81c4a7023301c1b3c4aa385b6c303225027eccf1dc010547eb497976b0c7f6563e37630b241195b5acb7ceaf29cba227d85906d4d10935
q: a8bd009d9dbe5b8768019df747b7e38a5ce16d1a0aee09a7c6dec609
r: 3b9d8fbc9cb3797092f2ad0344adf53484b8fd67eff765d7a68a3822
s: 2817e0ed023d5bf966e8d88fb561ccc3b13297230ff7f2c5594ed961
x: 9163bc5989a16068b8893e0b5e2b72b39f65f5f016c690dadc7f95e4
y: 6577c5494f307facc9f559769e2c8a771afb746a1bd5d479d3e754bf6e5a8385ca92b0e610266af4a910535a26642ff6c9c56bdc366a2e4de634699b9725e523c44c6fe3cf12107cf8cd341be17916377a69e4733dd079ff03de844bc2c1e76e650292cc946a6905ede6c0ce0efdbbe22061d7b15acf3c477a81a098fc80fedb9c0a70a12b9ee78b5059fda201c80a547d5357e3dfa7fea7e3b5e72680297552dfbf5e78da3cb9c2b9bcf94714e3e419ef07348f16ed7dd1dc84a613b2a468a1568e3c9e970c8623f15df26d2e9c3d65646e1f23dffc993e49128b8c74b1542a921268a66e9563b370f6f64d274630525778e2e9ae8124d1f899bd81eeb2d621
g: 7d427bf9f9882dbf7481d2d039e35e120b3648e91ee188104328408a712d8e4a0577be1142c924298e202abd753c0446a76ba79623db7bf25da465e9b289b9123b670b618d2bdace45205494737485398e73805fa929727ce8a6c7ade0395883f058a29767d67f48527bea1979b2c406e790f1676ed97ee5f23d4c231dd41b54d695fbc80916e5ee5e773cf33ee4ebff916c4cfdb47ace8471839e5a238d382095da9b4b278a64bc574cbc9fa6f255ce593489147c847f3a81856396ed344a0c42dfae9652fb5b2e72c9fb04af9a5d35b336293b5cc5f66f554618a7d01a4b2828690b106a60825309dc5dbad5052f9cd67095ed70457ef3c2a29c6a5c56f4a0
h: 180
m: 4ffbe6d0764ab2c15c2f75de350d864c7fc415e018ba66074edba720cc216072c9873ebcc24d7a31ba509bdec09df116e4a8d0110d105f0e67987865ecd71e89d96dade9715c89e74fae3a825cbe2f32e8fe3adabcb2ed202378dedbf2e047b19598aba595198c73d9d4d41c522f2f458ba2feda71916685d1a71f6c1452465a88fc698668b740ec47cf6b6b09936fb5fd4c38cca863c6928d00a050d3a6c8d844137f76518932726b1daf928ea5f1dea7d627ae28e0baf5c79925
p: 88187c27193ff47f07217ddec8a2a5f8f1f8f7cd3b7e4a3a55377a72046a3f7c73cfa7074b063cbdf37623b620fa689350b134fce801e6425978e392896523e510f52e9b6e91b69540c864171ff9125ba1324f81e54f61d1d6763aa6800c999073c4376001e0c11c5bc0f6ed40a670cbab29952d6143621e5f89d84c4e507d32c9dbae5f9a469dff0550769e243700735256bc0454a57754a03354a3ec17d8c90b5e3136846ef5cfa9105fde352820e7df1801253988a0bb89dc083d7925ea6a6d88f80010638e74492d28009f1cd43ba7c645b61281f7dad9ca79f12430183d57768567081bf4c0e78dec0933d0d3059ac4d7c9e9e45ced192f4d37ea2b8229
q: c10ad68517578153a8c1017498bc9d1dc6e57d6ac35a7c44dc4c7465
r: 5d0d48a16093a71905e49909d987552b377ffab255bfda2329467125
s: b2510cac9390e93268343a5fa44d1fdb1ade28507fc50022f69b433e
x: 261d755051573c27c936e9d9fcd3f166258f03eb85b597af373ee9cb
y: 78f47e1998cf8d3af9c5398ad2b0f9f58f2e8e85428bf19cd9fa77446eaa58aecf2a5c33c7b017bdc4877694845b86243d4a8fe451276139c4976b0ffc402f7b2c8b160350d03257ed27be57961d3aac3b603b898345e1bf0e6c1ba92215339b3333a6a5de65b634e004b431026fe8061ab0986f73d59c36c99f63ef890bdbbcdc0af97b27bdc729d5dbd352070cb973b7d9cdcbff94ddad421099d7158c7bb949d87712b21e02d7d32666b402c60736780f3a223482426cbf2da6ab42766617fce3811cd9ca680e972736758e795496c1b4b8d8f577b21517dac2986074c029785373cd91dfa554e13235e237c35f9fcc768f7e5670bb7a0a91d798c94b98ae
g: 78bc8a7893ba31c723f2da3d0b692faf29d7fbd99dccad2ddfb5ae5c413164eda415e7fe79d871c7f93a88b5a26db029c589f3d1d24d766a31ff5a29a85de53e50c183b89f79e84b0d68802afb26e908275a9ce7e226f2fb8eda25f0d1b4294483389567dafd8fccd579f8e76510605b5ae0586fcf7bde4c9822abffbcd5cffe40cc0795e1c5def5ac44acc1851e103c85a7d359d11c7f9fc947b4f57f815196e37a61acb5aeec5e0ddf2fcce5c6d73638657375a4b0a0fe10b0a0002e3530c6b8ee77981e00fa788c57625ef939432203c59e3dd7df9418e752253507c04b99052d1309fa0a11660be9dc8ed7933b090b9ac662b7f15b3a8dd56463b6a78726
h: e0
m: 0106de135125a367dc073135e6e1dda2eb382640278e744084ffde08b11207c6565ea2f71fcc1ad1a01e91203d04604b1281535b89
p: a3a1d7b36890afea91ce89277c435d91010cfee2912360245eed827c8ee1bd495edb53840716b05baff2ece3fbd1838d50546b8d4fbd7c6ccaefa02a7cd97951a47538133f6a4d11242245d94bbeec515c4514d0a60889b9e5dbe404f9d709b1dc05eb027a48b6ce5317c7ee13cb4657452a2842c0ce641588a12c5e267c3c66665e831967137e0c0ae8554302a4d3a8a3cd4f21ed714cfd1b64b2c6aadf3670ca788f0f1e114db1fd498ba95b559fb7a0872833b81ed420125b044bf015c92fff092235450b840c664e9568dbb150bcb69abfe29c588def8250c87ab850d13dfa92296035270b8c5895101658e863db71689047eaf9a742780ad56ee7e37e41
q: f2c374f3963bb3122ade6644fdfe852f3d22d2a4d500e1a07355d673
r: 1e411dbe74af08fc6fbf2df5caeff5ecd2189f6ec48a2edb45b2e5d2
s: cc68f6d65d8055dba5846b6878dbdaecf55697856df1606886257d50
x: e330987fe0fc1c57ddc7fdf7e6a831d9cf2de435de9a2daa4dba4d7b
y: a1fd8b07e7c63c5ccf22467bd773db51d0ab5697da191a5183c56c9f0e3689822eb827ee37b051cc4e7b388ba131d4601508e935d2be54d8ecf646eb9cf547710d9702e507fbefa0c011fb34faa8c66c3dbe49d9119a89f9fa1a963959612b21e27d3552d25a60568d04791f820dca1088754a281ce7592c52487caad52b31eeb750626ef084520a0bf7d930b21da95b43fe5923b9e3ad168d4ed3bc1db16cf7dfda9d847c28f799e0c825bff3ffcbd9883aabe219adbc698896107ff60422d7860d12ab2b85ed7624e89dc79e637790722559e3206c3c40be5fb6d735a9451d538018cb218fe7d93497e2f67e66dccffdb8335df4bb2967d1390d08798fbc7c
g: d1763360ffcf6795a1b5a5b2f8497c7dfc5e71249be4fa1ed71ff73685775855cc893f6d2d4cb2facb60fee81bc3af511e453f7cb062dcb402667c3a46de52c813afa83463eb58bd626aa796d11498cd6d21826f5f2db796c407d27906dda4e4d01c74590a45c0b46e1087bdbfec91ab23649a530cb7d307bb56eaa4c21882d0c58e9a13c911fd97713302a4fddb9f68b17d4cefbcee5276b1a94f3e0418d72daea19987795d5855f7da8a3f0cad900331512df25191eb8037420137d16c5aba07d374e6f5ac0a089bdb45c134a33a3fd7f168b794fb86dce33d8a69d1971e8249621cf7d9aece68bf7fb81c108e89123a9c1947ef8567346c0bd8774ebf4d40
h: 180
m: cfa7665db0c47e11189de1fa549cd0ac5bbb9eae1807f7d372f1f42a2f66640b78e69668127a9f006d6fc6b706a41c60da876081548200fd8f231415fd58653fbdf443446ba527e603bfaeef39eaa07cab
p: ddf469ed437a720b152d52902bb83993a1022105ac817447788719422c674a943dd3a6d645682fd1b034abea529ab4921514148f8f2dd0b5f3ab7ff39e051b82c643f4976608e2d01967b3465e9c52e3621e01682a884a8348d4ac015e4fdd2d5f82aba74f1d3666cdccc0907205f00866e67390fbf990c5163bd9ac825aaf01483c1cfe1c9db81379d9f924926815bc8031adfbd75c2941cad60855f8c5c6182a72b217a8e79f296ae85257f88b8147cef3aee7d5d260647a68ecf3ae44c273b5a1b0b39b1e9aa4b7487d209ee181bef77fe028487de520661ea985432e95d4d91f2e5a62b976319370ba0eee99c728b59a7d50c0e547615e836fb27ba5482b
q: e4a7617f540cbdef0762db0c3418d811e41b22111890413ac23ff39f
r: c71e133201ac408d458ac991af0bf5b874ff7ce8c8e168440b9a687f
s: b43b4f41f0557f48f2832590482afe48a08724befdf6efe0945a7717
x: 8f784a294cb67e1feb9d4bcc3c882045befd8b65d8982640e82f586c
y: c5ca9cc76ce80b5cf48f87726fa1cd43ce2815b536d69551f81ca135001f5e7622d5062fe3e08bc6d58dc57ff925828beb3b2815edb8dc6d9659b5733561488220290f6b319ec7ad328b615b1f91d686eaf03b7a4a0773befb4a03b71932269f7bc6a06b222ef66deb66c7089db6d03ab38c4192333106cd1bef2eecb6a6bab158d666aa415455cc274be6e88cf8e35abe0ec0ddff82adf7a50584e8a2fdde1f139e7a71d63d4abbfc408feb039ff48da9a096b87213bb51902220c840f11873ff922a8aa17aa19c1a945da345d7f66ffe91639070961e145fef3e4ff364dee336330b6f00f7206268d5744da309421e3829f7a22cc20299e01c5b677e1aaa79
g: 3458c42d21eebb814d6fb13de88ce72da42a9ef0c2ed54a782c4bd241fa5974ed892a500b886696f0f83ce744d893bc65dbb1b61f6827739b9ac9ee33d7f8fe2c04a9fd0cec1b4014988f2bb53347f210796ff829f42704ecd54d62185c26d961f4da1c41283fd47aed672cd1fd7bda0b28aa445bf8fc12747cb8b446a87c237b1da49f17c316e541dcb25013dcf32af99292a4bab3092906a2e6030060da150ef37b71beea078158350f86ecdec84eb71de76280156adb06d59267792416e6f0acd5e1343f6ded51d93b28e5616df3048200a7138643b4c471c3b70c325bfef33335f8ef308dc6ed32cfd686a2eddd61fe8311db5e3b73a34701b38e2e6e190
h: e0
m: 96c67b8bb4b501d75f27dcfdad9373794f094911d389f3835e30401a1dca55a3c709595719e7829037f709b2f69a96407afd3d0e3c809552bbe06224d5f6a792e1f1fa6cfc9c5f7912de6025565e432730b367b4076298244a930e92d288c979e4dfefa426ef95042ec158308011eeb23f75441ee1f460a02b6332d6015e9253b03b6ea9b82bfcdb5da4bc7d14306b361bf807964e93ba129dfecef67ad19ec58e00cc94b24d8aada963e450c792ba518d4cd341705c95724a76ecaae54a8b05a671f2c83bc461da4587e4288e41d2df5ed0b73dc284a72be2ea360a32fe84f07f9f35074b7923e5d99f2b8f49c2744fccff9a7b00c904a50b92566ec6
p: bddea458eebe5a8e4c56e3f8a0947527ccf0fd9d2fbc5d911e50c14c3f1eb42a2629cb168df27ea8965cbfdb839fc6d09a9b3255ea4e2797f40162c6bd04e92c575c32a54f97239219004f3eccd9c0fd81603a9d9857d0679a5f4d907432f3c519a9141bca37acb5364643d5621c2661c01bf2d13b77fbb9a80797cc83cb9b709796f8761edd1c6365bef02dce356c2ac8e0c499a12f05cccb1f0701611113493fdb0c3a23a3b16548207d057bb66c53c1f3323f29102c507f12a134731c2e36f9537c2230ca48181e63c90607fc9d72bf8c26cf0cafe10f4f48ceabe9fb62b298da0fa0c09395343fd963ae068524c48435489b591e54d2a40de37bc918891f
q: f59d2f09bfa964dbc0f75c4ace3e5cf76467ba4992903e4f57d40dad
r: b151d2bc3d717468e7afe96d3240b0e04451e83d18b1175f356a8322
s: ea1b98ba9c3d1db3d2a39d12a6e072590bd3c1cf9c13f41dec37b665
x: 3cab737b8a9152846d415eb7d12e0a58a3921873dfb5c0b0f655e6b4
y: 9e778c13495f4366591a73ac40ad60fbe20be19e0f5c94c2f199c77a7dada74fa664509008a2c84bb5e5539570e2fa6111cc5737999c6f9aa54518aeda5b15577000f73f95c020d952a43bbfa85da8706d1557db5e7f38e037827d86984587df1ecd30e959e15d4b5a5c2bdd2242c08d267eda61e336b347bfeed9af5e5ff8c93a8141f85cdb4da78457cbd582aa95b86006cc8da3acca75e62fa5c1c091c82a88b247c3c8841b2d2fc5edf86496e71a986a5a8c63e878307c95098be4d0ea54049a4cd20935ed8a67c2aa7b76ccdfd39da27ae5f837e631bb6efd266f01db05bffbd7ab326fc393698c4efa5a12232a8184e67c62628989148ca02c6421a8
g: 15f4ee8c927a4d6d34bb475aece2ec3c98c4a8638b00df91cd35e7bf1e4396312e415ca1e235741fb174680c48bdff9ab22bf6fc34589f40b1b8cc8d4fba685f73e34fc5fda8a2c59d3e7e65d7d7c889d6f55db2c8902c98e79112b733d207538f1a5d47c37c8b7cccfec28cc1bf77145dcc491724cd7373165d9097675ab9611ea77a694d494c0c85e80dbc15e0681a7b7502e884e37a41c465268e2bcecfbf1df5fde45323e37b6b0d505be66bd7ba7f51d61277b9e595c79f5d87dd2a19dc99b76f1036c2eb560544e0bd122790a342b0e6fb150c2671c714659f2d3185b41d9a676dcc01277915c06c0ca9f01b7b4a988c6efcc3e48b280607f396c12f36
h: 200
m: 13fc4c9c095c832ef248f8156ffe24ceb6c7566149e0ed9000a59a5dc40e14a365f54ab36f37de938a848feb1f5fcb9c825d4a436c4da4adcaf0d81de0489bf6f76e280772fb9596d599ad99c0c879a302dd28c45ba2fc24947d06f072bfd2c5f786b1114d1fc24dedd0ad60b6aed4958ea3d38ded60720f7f0291e888c9bfdaa327b0ee94f4ca179c278cb1cae9e6c3bc88c6b0c13542d2396478b1b53eb014a862119dcc39b4c0210d6a7ae25072ce9c62ef64ce5bc11037976a8ef8f3607bfa177d8c453240896121f197b05d7f73de14a88b5f2a1b268915d32f710169a45c8de18bf160567f15b753
p: ae763b0d058aeb7340b9dbdddd3b293fcea5a3aecd0e9a040da0aaa50af8e23b61d702a50a2dac94246fd072bc1cbfb392caa751050bf2b6b1dceeb0203992875e2c58964b6c700b012cd1892d49832f3d5b7ca89bc14f76e39fc907a023d8be7b4ab3c0718036a1d7aaa9088f122a7bad91116db3d003c2bc631956f2ec36a5968a502977fc700df1c9722af40ad68a6c35e0a60dd8203d8c8f188639c68f6ed9cc2807dc2f0a7db8bc51055b1813d88018d8084f68b79352ea414e18eb2dc2e955434e53816540201dac1313f00b5c653e42e5247fd61e649c5b1c2a801189a70d3bd91f52a6fd9fb155b2b8747f80b85784497547fc1aa06e974b62a961f5
q: d0b2c733663e539712204ee1222e5544660ffb6442706ed2232eca39
r: 6d3720851b5f6bf357db368f90ae422979a71b082639ec2c1e4afa
s: d0231900db79b9d703045ecb7952e8519706aace60880d49a253b064
x: 668a3d8e2f3a6f43ebc4875bf17bc3b2214d09717f4609c79bbdeb29
y: 6b08999e6aaad6fd5fd164807807cda47fcd26e5989c309ff125f5b9567d4e2a828d5ebfe5e6ca18bb0f61c9ebca4a90dd5a9a683a4f8691a28394a702a4bf66527b48481350e0ea7f8c182c56ac150782fa6564a8eb9808886fd7173bc256490c0575d865741db69667496ac0fa7f60215735447efea631f3fc703fe0ead05fb5ae79a919efcf9fa26cfa2b2d6052478c82905b4f57061617224d5e067bc0ceca0f1e31a1ba62f51f675964872798495522ed0b164338bece568f6c60f8b6923c8454ba29c09287db0dc62460e1e93b334394216bf7bf08ae6adee8d34ea387786cac0195af0169cd0c4af8d62a393c8f2fe1dcbeb9c800b33cbc76adfeb118
g: 56277772a87001d18e8f82a7f0505ced957509d734ada4254d41d12bcd5f08940a03878084f84a391d3e05861c89930b969fd0b2d20357814bf18d8264ea74eb0ab7340f07f73374f284f4b4f839099646bf5164dc24658695825380eef0268ec2c23417e4211e58709ea9e0ac3d614800b5172b1f57b4ff1a25f3a7ae27eedb660804910c5614b8b9dbe186e9551e98a5cc085b252abfca757cca0c1ea04472ebf37ded59f21a20b5d553f8d4a1b8fde1956e0ab524d176c82d173103fe16a69870209b3803ef5d3ece9d6e8ce2e5b2df3f192d7e55cce41fba1a6c43cf35d96047a4207cdeb6c136ff0a191e1abf434791615acf30b76b8526760dcc6cd33f
h: e0
m: 8157b242
p: d4c994b7c237829bbce90b5e5a57c6c5b100e8b1b910d95753123b7516e4aee80584f4f9b5f1fd1995a472af28d4ee8c9d765c6532fa91ae68a18b801145f18626542c32cdcb3d1aba136be39bf2943057259da6447ad010a4af30b90130f69d55863d2853a429e2d5e6337690126bd8d111629e77f2d383fddd498491fae709e75fbb7c2c9e0290cdea2ee9b6d457cbdf24cf4a9db923d901d439b2ef4033a89d5bc7921ba5580bca2b6df4dbabfc72af813fe951a1ccf4486c975e50259aa9a55fd3493eb3151749b5496fdf9a970f23a85355573d3c57d8fce8ebe47139c1a9045ee6053977bfc3e9e3ae16625dfedf0197300c8e66076821fab5b67ffd63
q: 8f926164d95fb8192ab91392d0dca1614c7498cdb6ae7a8a21cfe2cb
r: 878afa4e315752102f1293429c233850c741f5c71a595e521b6c4a1e
s: 8e2f4a720594781eb0243b6eab0baf4557ba4f4540c7818f91878ff2
x: 4983fc5e78698d863e274caa663e1c89f45c8e6a4c0948a8f493f99b
y: c23cecd73b0c1aa2d9023c9ddd1bf00379eeb905bf65f119a093acc11f14bf8f5f5fa13ad0b67e41d7fa84445696cdee5bceb349bc7c91942f0b4b83ddbe19e5543f2f272926d2d5589884285093af893113bd90632aecdfff1be94d7bc63d85104adf4db392b5fab1b20e70b136a24a5bb46b8c3ba643ef57af594252ec3725f8c90041583db7ec945efb459eb83a1a9bb5c7063bdfa9331e189cf5bcf09f5f85464efe1c1ff8c54f375ff15c7df50d25e1e881fc483e5abf96f4e1df2080fd1164a88d5815439a1aa0a35785890c650babd4ed9a43b1d5c2ca1f2faa7e431d949e0304c56c2d8b915b7d3e280f50b20d0a482bcaafa58979bd99e56d9e5003
g: da2e54efb7e2026ea65bd56e711a6b8c1084162515d420b5660b3f1787137289bc3496bc94f56414a74cbfac4b1758279b2d793a47a8200c2ea4441128b3c90c64181993aa41002d32f02e252a8183f29cacab842685a5c52c72c952d798d1e33ec67460cb4bcc55de15787d5d902de4238e354c24e74860912d7785e3647454be060f98d64a92804851ad4978c3d295b2653ba1fba2991e2f8947b7a4ace37e8d331554b59889fe5327a8cd365dffd8f44b983005715896d76c6f20471c707064b90fcf42aa8deaf6a089927760fc1a313b7b60dd2cfbb2c78f475313f1f9677f80d66858d6cdb934fda4db96301044e889d52c49e9f0ae967b8203935485a
h: 100
m: cfb318c85f8ce25678d71d89d580d08a99d40bfe1244b5c9215da177ac85e1d700a023f2c2c589ae909e092d4bbd65d6bd14cdc708cd5fef2a125bfaf360c98657a7f127aa6e3a2841699384af023a729b75c9fc97173b577ae9cdd7966fb055f77dbd646a2c844ea3e6321a708509073b593359523dca1b1851464f004c72ad76059347
p: 994957ed456355257d990c606284083d1b22e60a7032f418382794249c6cb75ba0fa02f6f13007bbae58c29b5b4be0276c25f24e98c8826e1cb6aa559460ed878a787ff641905afa4e5c65ed054ae521ec50a6377b1d366cea6c8255539acfc4ab66ec20784e9a8ffbd735448b40959f13228f477ed6bdc149d736763ba3c3533873ae587b9d1aa08ed105847e81934c55c3a285c9dfa52662407acc47cb9c128c989a52e052e35eb21eb1f86bd31f1f4debda27648838ca0a1b76b73f0eedd9708c24d5506fdb9f4872fe7963c804a859cb14432a7775ae35d1c6566e1b5fcd56c2a7d618a944921133e757a981e99bf3448d42df97e4e01b761dbe2e57218b
q: b1a6f6afce2768814ed36567ee873f5e8ac74c1456968f3f453c5b71
r: 34f23ce17b7db4fcc11549354c7e8444c56c864d855a0c5aa8c1b819
s: 32fd0a7926f2d153f5dc3d223936c48a454afb0af6c869242dc7c9ce
x: 62184cf9cbc96a78ba1f59e45521cabe2b84eefc166d76885fba040b
y: 26ba1bf6e4e63a0a1c4314780939119904fb7696978aea62db4bb7d784b2d9cb0b8a04eea3112a0b267a7049281f35cb6d154e05f8831ff120b16821d8d3ba07d4b3bb1c164192f24873619cf0dddb96cbf641ec49dfce7497f4ffba9c28b2cd0cd8e8ee9615e6db13d47db71ec767da8b86f9f6f4242cc8d37c0ca87638c4d19b5c24aff40af45580704b89f617e9c8fb40f4180789b8d1383aa956e3371b877e9d0da257cf07d3270d2d1b33f04cbcd414b1cb6c884d898a05ccc1fee967a4f57b809dd8f4783c4bcf2e02a2fc02a8a33f1ffdec71d03e804066285d889bf950b82c9c8c658ef7a145cf62e9e50d652a1351f5e38850d41b7259a70da5c72b
g: f151f776685c600062aebdf313d7c9213528e650c64ef864ff04d84165011722e282a787073200c98124ca93d770702acb9df26119b3b676e6b5d8d967f2ebaf51400eed1f40aa22887b2e5870d15646c1df235cb88dce1dee6986229835a5d5f5095b3c0ed9ebcd06a757b5bd08adae8f747a6e2aa763c259ed6d6cc704fbb733b692d121e00fdb0cb4009c2791e8c44e14ac88e903c59f2e8328837f45f4655b7afb2cf35b5fbd0cb6f75a54802fa499bbf6b5ada3dde23fa58de74d0d90cc9a621c74e2071e09fdfb5bb600ef3e74c18bdc985f7ffce2274a78cd73655f1acc8008b328a37bd10a915c1b22bd6870a4e5106da252357a377325c87b5c1f74
h: e0
m: 4f93dc748351fe63f11070f67c9958676f6bc1a7d049974cde581fcd123c779ddbba5c99ed6b49d15e649033c4f978e02969e4d0475219c3b003e5666d91b17520b76bc31fd641a0e6e69a9104e0c3f3082b698619ee69f97909b84abfef3940f607cb240011f82ca4f06896128d24d0cd44ea12a98409ff630110828a23718d65876c38ab0bf4ca0572ec6a2dd72035919099e7a08bb6bb86e353065de10a9ebbbc53998fe2cf91bd03df96f4903d0f32bc25c29e98bc8f80691541db39473a6f20c3a6f259
p: f7cdb3ef93c29b6d8c658e1ad8ba33a15af4c27d9ad61fb8bb3da052476848017a8d5d4039e424f6935996384f8c785f2660c311c604252e1ebf21e0baef3b0aefbcabc55b454757040955f4136f2b1b8a53cb2aedadbb0fe0a83e7f3d1ce6292908a750f8eff73f253656d5dc3d9da6e4d0f9592fa3d284e458070cbd2b969e54957cfa3b0df383ec0ad2cc7a2e90eb5b4b119acae07ce5ee20e1a276f6ff191afb9b7b572e48f375a6d40b94ecb84e1cd08573327bd8b2ec6fc0781a4aac89c09ea50660fbb1778e49b8c927e7dda28470d7567451b0721909a6587ccd1a66113dd38b7d3112d596402147effdc953d594665f946e7935a82e1d9009cf39b5
q: 8fce73c7d3262f590691379e56c012904c9d71e255f8e7cd2b54941f
r: 8e4ee117bfdfa307fe29682ce97795be60a6eb3aff2cb6d87baff34c
s: b97b95197aaa4ea707af995c7e7934695f7bfd971b24d9c33865f09
x: 133f7e86aa4e8b26ce7a06f7758f0b469efe860cdbc740f86ef13a47
y: c1e1d6dd155eb0bdf303f2011216795acf597ceb6357a8f861575f31e4f07b8fa75681a43cf221713dd9c090f3781bb0b3cb7e1b938cb5f82b64b1d12cc6082bd412dfd2f40e7bf71a505e418376ade9ef4c177c0aca34a592b10d4e7d2a4c5b45b834a23830a7b30116da00734c1e1e0c890c17b9aed43cc03d2493451717faf04bc969d9c8c49b098f87378d3b381e7e76400a56369734972810ceb2ec8dadbc512c473e87c0e5b52e673aac7efd9535558dfc9e498d764cc0984a95f0b3a5436b3a902efad5c5165bc14c200960fffeacd9b7b3b4139260bba68c72d8ab71992e29f52766fec5759d34327f6b4be929c4680ed9e1ba8e74300c3e030f08cc
g: 5ef368b11ad0c366bf944c15cfd4c70fa8f1fe90e9e058758203cca00a8e244887ddc0026bc1b7541668f72a8ca7aecb538e62f194b245cb9bba45f61ad0ecdbe045312714b38fac454c891c3415aa6eed8a98d4f9c4f3f61dc1505aaccc527847be612d157f3667178a6ed2b61d311eb4c8b76e559d9be57066de92fb973c2c8241e940bcefe5cf2d6c679fb33022d41d742532a073757286cc68f69ce2ad998f8a68fe89d542f7cd7cb15adc3bb6d36d0009aeddb1461ce5f2ffffa670e6f3bf29d00d7bf5f26bbf13281dbf2f7196553602975ea34603af2334069c0caa8e413b7e5ab87b6bfd0c3081561ec5361ff54eca7c2f33d315bb7067a167dddf0d
h: e0
m: 7fb453f703cfb4ac0cd58c459cacce3e28b1bfd61bd64dc9f41a144644bbc07c3f413dd486b67f1f2185ea2a69b994881235356f6dc0357fe1af0526b77b472c16c428aab07494447ba4ade171914098ed4e45b267fe03e2a11604cd3def8e97c22c1ccce2c80cb195707a442e93bcc37329ddbea2b43393babdf0a556c1cef800d7454bd190b6ca2b6f7bc97a0b5a14d757d258825cbd02fba9c54168c03e0ea2d611b8e4486dab547f44ae73e4b6bda08e88ea1c09a7018289e0de28d816
p: edce55217dc9c0d6b452debb21d239726e94ccf408dd46c4d297aa8bb82dc57c1587df50e8f175de3b56bdd16430ce7514fac777b881598e6e315802c3111c51842ff48e5e814341f433f49d6c90bc9fd54656244252c075399db08b8b16634fdc92adcc5a1dba18f96a7fe19274e05d4cb2c18bfbc83fb4878f0116776b6eb374c4a31b8bb8ad4e7efeff152b426c080f2995ee6342120724143e933d66f147b630e655faef568877c04612e6462350c2e5ce8814668f22b78b41dad71e0ee5ca9a5f7d6b1c06642c098fc114ebb3eaf16a3e3c365b5d50403a239d0b80f6f8da6c6a6936cd26e54dd76bf3735e748d5ec557ade521afeb2f610d163241367f
q: b4cb15be8eef2b1f681cad74d4199defcd74b56ae88478a2295ed3cd
r: 8a6c3138d0700b78fe43913d4327a4018c04e0c87faca7b21fad7605
s: 779de55d2b9988f98149ca5eddd4bd0ebb337419e99d619196374849
x: 6ae841f465d3299d5a2b49c24bad536841bce0f4df63bf3aa1b850b0
y: 4b93a4e4d6d9519d98599277cb327ffda47a8656777394badb6cb40c341252b789f4b662baa3a400a1848fa9a763f06063b03b5f9b13291f86ce3b843a7607d4ecd243588caf16c4c802276a415b26f10d608664d1540fd850d9244c5ba943f60f2ff31d7081dfcc55ab236216ae150fba8eed42175e669364372c8edf7118270cb666d838b12fd8d809bfb2e1df3924047d9c5344a0c661764a5aaf2496a1afe807d38a592237968a749334f192a734af11807b522b74601ed164f9a5ae46501add1b083a5666197b0bb747aeca5822f4538c1aa8a0a6452acd56d1a90208a7ac0080b3be6c91b9fa59eb1642cab13e354e8e973997b19249d7b9425d3d408f
g: 9ee298305aeef3f239956729b303e7ffeb87f694920418d1cf4c68f796448537fe0dea6b8691a0678782d1bf281ee3adf74331d762990f76215e8c06a68d062fda1956200928a46f6121c6af1bcffaaceed1fe8393b432f868fe892920c656b792e2fed8dc5337f502278851ce949106308a9220079e7a2b53caf5f3be77803e0947d08dae62bc43d5e2a81dbe127761fe77bdaceb21a8f7d9f205d58105063e999328af5ad4f06677acf7ac1d972fad0e57df4916298cf3af12e67c26895a295093ac9753b0df758527458834d9aa76ddc282ff1284791ff6c4eaaaf868312c17d939baa70dd1e2f256002f199a757e3726ec0badf8cd676241382e54dde988
h: 200
m: 2b41e5342f9c4fc117a575cb933104cfbae195e672af58afe75e9d20edc7d4d685a032f9c2ca8df20580634d688a58c8c13cfcfb9ded2e4f3711c986364773e09bfe33fc8ed2d0463411c993cef870fa72aa8601c2fcde211a733caedf8de994ec2c04336e1a8cf6b8ae26a38db33fcfa4f1dd314d8c571ef13f411b973e87b43ef6a528fefc397cafeac7e48da382cb76ab7d38d24261dbac697073ba624306c2085e8ccb6a832a7a3f
p: dfbef7a74456b64a7649197d4193f14af9359dc3ed9eb2d0d0960d23039ea221304013c5c2e93c99e320ea978b2c1283ff4fe9e26910f79960d21898f3e9ae449124fc765ee4c52d73aeaddba41e900ce0857da2ab727c81da612edf46ea203ff9be39712d1b6827eaa8515667bbf85b8cd0007c0ce55b0fdbb81d98d866df661b1e97fbc55075c2df562052d2600b5a2e9d5c2e28af568f39f8456100e651a67f301f8e446d72c84360c70f07edb9f83dee1f91c7f8aa3e6e6fe42c2d4a0d67388e51f128ef9a528be9b4badaac524d3bf5d443f4cc4a980e7ceaaf7bf0ac5fa10bd0f0547d0907a48d40aacb874d926c36e99fb350bb2ebe8a75fe94cead75
q: 8636d99401dcc62bc8ef2aaaf9eac1576f49e0c7794e8c3420489f95
r: 18633587afa9097818a08f0c48dad5fcd8e1c4a37b07af8158e5b2d4
s: 3164a29ad416fae98c98084cbd70e25c146082c71e62e551de25d796
x: 4238a427de56b23d6585e7878c4f5c96b408721073b4dc1b5b995387
y: ba48870958b29b3a353729e8bdc25612f1942aaaa482c7af2e0aeca884abf1a6148473eef7595b884e57e7b0ab612741bfdb35c5c9a4cfd8c0b1fae8c3dfa1750495eac13bc5a747b9e155375512672adc06bfa0301d2d18b72749a4d37172cd66deb823f51ae06c7a7710490372c9222eea5e05ab2745762ecbeac446b54b5ca3ee5a731b0817840b5591561b781db93e3432a1b4b2a4170609ee7f336f08c619ced35d92a7f87ddaf0a1fd67ebc19cb8e7219c18a9b395870efdc788d0afc51dfca18d709aafe9472455e0329549a6753c45c97d5561481e0c8f8f0a2fbc6204a58f2b1c537475e351876c726134b3c92439f08311b92d1a5522c33e214c36
g: de8455517e4ef1a07d094e3acc4a0445ff4e3eb0e14f9c1a2cbf9e5c307dcf1d31b3a3aee6776c145315caf9ece314cbcebc72de824929e5c5e287e2e47610199459abe4ea5a5ea023fdbf06afd8feab2b92908a44564802cb90ed0f5d3b5251d3c19bcfd99f72feff70f6bca38f8aef8a2e811290b4a9a977665ed8c91dcc4ec5a389750a412ac1f154efdac00e47f147c8f585506d6849cdc017ad8b070e5f7f175051297fd05933bc4c302a2059e1d63a2bfbe0b07f497714e81374f961aa23c6b8e92e711f6fb7bd67f95dee844d5ec2474e1091a15e54fcf68916b72606f36425722d8a7231ce00075326b27f6048250a96f700674ada91f6aa4f6b2ff1
h: 180
m: 09ead7ae2b8bdb6a67735bcccd65b6cd8d2870c72b2712f98523a645547af259f47221d34dcece1c5c84d690eb5054f38e661cdf36626a5f98cca1f1e19ad341e3737b19309dc87152950b549beb52afd901861d2b3884afaca1345fcbcb5be6354b2e25083fc7823ed4d2bb336072827016bbcd4cd718dc1fe7da708f43d565d0b2eca13e216e3ee5a443a841916f74525f6c941a5ed5764a235dc78669ab5de05448335bcb01fabb159285efccab52fe156783ac558c0a4053f6a316921ff123ae5c9b9dbfe1697793cec72612ada8d244f6b8ce64b01d07b6e0479f93
p: f3ca4b159c95bb71a49ff43481957a2e40ec1a82d484aad27ff4ff8bdc5e7550695253bfbe5c93ec6df799ac13696aa6e22ec839cfcf5fd0c5abfa756bfdcca5f6da52cd3b7cdc4cbf1f803812d356ecda89d3307bd3a4090ac8755623a1e54c85a507589274a4120d2d604052ec792fe47fbdfe48d1ed9eca5b1335cdb470279729b0f14d586a7c4dc143936a59cc79d189346fd4d67d56cbbdbcb8d323105474cd13b3103501c35e0e22d8bfec32949a5d112da299a60ca806737c8782523903fe6241ac4e96da37e1c9ca1a4da38e70a549dd25692869980139b2058e95cb6d3439f21bf0958537a7a11d9f5a316c596c036d66593d14843d5f3e53b1fbeb
q: 8b9ab58a48cfb9176c8afe98922dc188b0f1b53722d8135f6c402449
r: 6ef011128d69ebb9124fffda4a3eeafa0a3f536153bcf98a38f25b2a
s: 177f1bde758e8a484e37fc8bd0af1652069727dcbb489cc399119c8
x: 5595f26f65958f794390d4568c2cc904790861674ac80bc5a58ff4d5
y: bbe635c1a563a64573803624b953b002e97ae8268cb37d7faff1f386cad05d9f4d2cb49789645af374d79709dfe7472395ea3274aac73742b707918c620d4214b56bf122cc68c2ea7a4ecf9f582413a3f5500babc79cafddf1033c9fed762844b1c08c054f8798a5c00f20585b940e552c91bb162ae09dda7f25e98844fc1ec7c913691eafad922287080c2d05cd93391598c743893c37215e78e6c2d120efdfc7c3654b5ec3b7a7aaf43d4ef8c4a72a1a9af6f54738351a123b3effa3ed71621fa40ac2cb62e05cd392ea1137ccefbf519e6789e7ae3a478ffdf85aaff2635b679ac934f26e9a45e5bbddeb6e21fbb3ef47c580de3e097294c91af69fcb4199
g: 917c405a9f89b25636886aa1f82b8a2e68b2bcad17735a5be42b42f491fc7f93fa6bba606aa9525a82831cf961791b6b4a4e6ae8a2aebd80b168075a15045701520aa5c5f4494dab7ab506c47691a2a729a6340473d0d621ad59f3b2c397c4d3d91d99c91e48adfc641617f5765c8f9c229e88be9388dfbab7f484a88d817d921645985d3874d0f7586c8f0354932c329c140af6e03728cea4467e4fa5aaf0db354aaa2679410fd1803f9cecae08df8ad5d60cf916b53d3536da88735aaa662ef79db261b16e8eead2f3561e35aba6c595027053d2b95d8d292a2f3cdd4c9ea414ba2a61b5f6ccbbad6f64dd6e140c47015369a74b10e3c1fb2de91084ded855
h: e0
m: f00e6b042477b1b2c4274074a77a138ef76d55bb43fc761588ffa21b3b9562fb69bfde489b5e5624a00943ba8c01c5cbece35eb857bd852a853e1cb9501c53070c1a958b51fe9d95ac7681b9d2050cb0df1cd4fd52ce26d81fc9bdd3ff891ba1de639c0b6bf748f6047d78b3c2d9fd8d0d826dc24b86ddb6dac25ebf71520c5b849813755b7115d7b9f4ed35a67e838c39f7881930b1275f2c0a03c1a37d083e33654c
p: 993c963c70849a6bb531058a5af8f900ed83e024ed200fab07bc73c2de6c1e1ad062fc7dd944d6f24d94fe1fb44b0668a617b4c4fb10effcb6b399c1f489acff5882ac9980bfcbe9036861280fbcba6134f9931ec39365d50704416d63b395d7a7449326db7c6034b5d430cb3d3a7a973fbdfcd6844100749f93d616e94412ba56144586fc2289ca639f2f9c6554132e73f568ae17130aa7b22af121e9b6fd0d1bbd192f2b21ed0cade13d4764d8d04b407ff312f8aa4f00af17ab0de04e249d228a2b7c9cd214ddf67d13014572d8b4867464615aa3db7ffeb24c57cced95b76f3e79a2a8a80d7f6ed0e47de0b33d85bd65ae607d16a969cb22339c12a6cf5f
q: aeb0a320204ac1baf1ca158f766ed7b33e899cb1d89e66d32ddf4cbf
r: 6e6dd782bcc0c52ac77fe203da455c4baf24607598ec1fbdca6e905b
s: 30f0617a24f2a7367c22aa959ae5e1ff7f87990bb8d704ea88125df8
x: 969c467dea2510779cadd959723e04f5ea2368e5203de2e7ec933c7
y: 48fb337e8254834298cac488f5216dd9fb9b61a381366ae9378bc78f5cc435c6f371f61357226cdd6a55fa7a007d544bd515358b31f0f7dc7d44bed29d5a6973966cb13fab3951676aa714f25f5f148bb8864b19d664346b0e45288d3e75b9c04ec2b5866029a5d3b2c62f03b0aa3b3242ae8426e0dcd6e42eb2561dd75a0de7af7599d8f984f55b86db9c8dc8918f5324a8f1b568c6881426038f70e81df6aadc46cbdebbec505e1682d8038932cf1ff4539928b054263f2ee651b71ed379f25f7d93b28bee9f259779d2b234b949e39db7655e6f1d8a201f4573b13e59200e6c3c3d90cc330d4d17fb6485b004def0c071c65158b2b87b99f021d7c735dcd7
g: 86fcf370fda50f695e9caeb2b6639096842c052a4f4843181e51c7e8111e9d334bcf0db3fe2e8b268810d067ff5958ee29c53407b061ff2fec8f91b638e096bbaa8d4b377ae6ecacd57afe9fa2d3faa6a883e95712c1d42262b6c935401104422469be3463c8edd990a39661ac49e1e3fd524c0f6fd605e9b8f5ca99cd9a1bd905e5a04ec5ded4e04688451bf3e0d34da74911e3bf43d597e287d28d0ff162a1dd8f919476484da8e0e108cf96d2b58252b8e8bd450b3aac91b6a9de82118954889970d0631f7563102d959642b4f885ab5433358dc3e24aaa62313541edacabe19b53f14efedfe5ea36a4b0543e4b9f8a0badec7506558a452aff9131b47655
h: 180
m: b337690fa5fc7c9bd62cdcb941d0a64b12b8489895e54e0dc223cd63fef3f73a68d3bcdc7c21fa8ef311cac6ca536127790f16cc4af0d6a7e7864aa5fc25cecaccdbdac7e0a47e0fdbcb29ab28f234fb330c3d1e9ec8dd4ad8781eeacbed60bd83a4bb2635f92f3e1b640474acd33f55c0f070441ec56db72d0b798c4e895a12a816bdd069f0a6ef6567
p: 9d8d4646c8cf6d8dc8f1356fc44204684af7817ad23479ea2ae98763732ea048fd461a422d2d8dd45284758af1ca7aa8100431b8e46618fa08996eb64ea1f62ec4f75e16297cc511920a4731f55eb7b82398572162d2e0b971069af0de4e201c9e71b7abb46a9b9d06913981a5ee5f12c02ebcbb584d15b27ddd19068369d26e9825a596295353f7fcf9e2026f0d5d52303f50b8b06255d6a8494f61e3a8678cb4786c19e0a0faa3a4c5016c525dc3f7e45c2bd307e129f087777c36d68bac38498d30362b49e648807f78118761fe0c2509e127f9ebeabba37f20339fea7157c8c88d9acdc0ac3d7218e9547b5cda5d0df514df7e9216ce31b887dbc469769f
q: b715df304d2200a8f37c04abcae398d85d801f211c502c995da3b2d3
r: 9d1ad56684c4926bf9a48f34186aa9d1a89257639071236247ec86f4
s: 85229b131a67eecd9755bf0b8c76523d1d9af11ff310b8177bac7dc2
x: 48e82d075c93ae881c13024cf3007f79182f2d1327586e67360812e1
y: 3e72e5abef7d3d0aaf53817ce1ffd7afdddeab27631d31dc60be6e9379b1d08c415cb2939e0ca09fcf24d26d0295269f061e81e2c92f6f88c059338160939b25733f285922a4cf2c637d9463b749c9c85ea5110fd2bc4c4e2ad4f4f43b30b0f8a3acae8af35c3745520934c0a6771a3b6f2384a150d8e0b849110f68b7a7121e5d695decd4ba28a8f080b10860dff410dd65d4f004f892249693ac1a760e9c1b59141cba4dd1eaa275f12d6ab70f5acc1323b5939a88289064f45b90c557385dad7fef3f94bda573b5337e3a59aff2c2355527839b7b01813674e1a3ddf3b1aa6cba25611699a36cbfa52c857f6cfec0afec206ae3369103d20f4069b0c04fba
g: 3b6d588b9fec113a6ff2aaa275ca4299100415bb56492bfc983b13c41d55e71182599e0bc64044d0a42e37f373723f4d243a80692827628d414b8b79dc0e767c9e1233a30245edd7866823c33ea9045826c7bd674ac9b29d6187d5069eff6b798c91d3e8ded61f925728a479811c86308d822d13769976c46d0e44f4cb86b22ba9ee2a52a94c250c0d4ecd826f6e1ddd8433429b2e151524b5357f71d18d4681b9a49969490483ccd2569c0fe4ee4e4267f08ff26521ba6a408f1a3f82bcb5978ff20e13f2aca7c20cdbd51052d0e397501d5cfbeac8388a50e2be6e7800e5f9d747d9cfec6d82cd3d6ef70753c7fe41e766142ae4a242bc32e459f06a1c0bcf
h: 100
m: 9b728e1cff164f294b0b076356eb
p: e2d3b45a4035ff720a751d486730c508d8621d60f9f9793fe3d74ed4e45bee113bdefd2cee4ce9e0ffb89fe06af2cd154a6c13b2e2f6e36cb9803cf0cd6b91267e26e8ff3c837e9c9df95109880f6888086c615efcc3777ca7a033832ac9b6adb2b244124c29d8041edc28a343ed699beaa668571c027ee55aad0d8bd0b0cbaea17f2416a84de912c9966c511798004217ad520a3eb09cb318c274ea93da7c79211977bc1d3fe6078c1284304676130c37948f0b627b85adae56f60eff0cbd3d27282c2e024fe0fb47fb2afaba73dfc248a8650cedf38aa6fb0f9a723b5b468fe5a7be435d9ffa81482ce2143e67d08865677604fee0e1741d6e90f31f71bf09
q: 8fd517c975c4b949d75d7623ab955d38e1e8721f0c27792dc2f0a893
r: 57d9baffc630971f47e20009e6776153318adf57981a60071f98775c
s: 872249bf9a961be1aa2f5471670a1c268ecf2ea02381d1d81f4a30f6
x: 109e14f53cbaa6d1a8b6570633a801751dc1965326e7c1fbc5dfb5e7
y: 73fffa4fe5276014f9ac175ac46f46395370db576ea49d83c188889ca2030efb3a0ca57ba026897ca63708483705f6d9e1a81d1e3aa3762b760aecc04ca41b68731bcccc0446c3301c5c5aa1719f2885efac860ab92e29cd78ab846f80b43a52321184cf39444eef379d41bc71c8412ded1c8b346f12e8885a0190b4b17d270fc632655c4d8d7395fd36235adc6f247120e988bef14efe446a56362d77181837a3ca3f40c3d7697b167350ee540100bf66fc2b0f9f2ac5cf09b37968913d82d7f6ca3aeb7df56ed76229dcbeadc448cce7e9533f543f49bd808cd832acc205d63b85a428dfedabd4a54973950bf67a904972da5aa7e620360e2fea5e543cbad7
g: 912fc3a0c1a61718c9f02c3d01d226d320c1cd19f8c039603e70f1fa9b96678bc3dd459d6dcb0c19b11b29bd387c10d21105248cee9302ebd712897a40423d5982412706aed8b6e4711d48cf10cde866c0604f6dda5a6aca3297791156aa7b7267e8c709e861ae0b4dbd6541755ea5d0c8e2c878740fac4c79a40c253e1563f58946d8ee199253d2150daf4928be93cc232e17a0ee991ea8dbe9ab57edfab127b05013dfb304fcd42a15788e4cda79c9912ad99aad24db8f6e294d0b8efd606356a260432f06704d3d1ca3e5c2cb36bcc04e2314107d751fd82ce4af3112cbb17afbd6faa108c15e276763363d2126d1a54bb7177e6413bfde1dea663811b0e5
h: 100
m: 36bd1993ff7d1a10c157b7c4c4eba829e7546b050df1534618e85221df1c1f02184720dadde7c38b80d2d11192e4a262b171e4085243bb3cb6772fe199b9b9a223d3763b16fa568ac738179ebf8503d6f53cb1b7f13ca831057d5562c38ef1260d936e0f80d932f91eb19c727dd98bfc68252bd1
p: 981a1bd7ba432c5b12e83a3bcfbc18474e8ce9a667301782e9b329e65b2db1824628d6253a57a0da647c45aef3b14aed7578c83e3b7a6c5e55f32bb28dfa86b17272dd5c20e519fe55dc26fd8be827642fe41ccc5b0e3ac34880cb93965af777a18d1ea920cbdd351afb58becac8f135bbbc93df6a8751a7bc6433b4ac7a0866c307a077e70846dab6d1d346dff68aa27e08be32a140ee0317b165456683a5aaeb2f92c95881292326121dd3d3aa957bd158391077837872880f146fd1f4426c9fb8d67c74abe2538422d8f8d4c3a425102a8653ca85a71afaf66373b11e0da7d9dd0ddd96d8848afa800789e88d940785f8ee6acfca57ace233dce65656ab17
q: be105c46a4e713c87bbbecdfae0ba4c5f9615189ce6a513c44c38011
r: 599495d3297b51bbc8cab06a00e1d46b7bb766e66f62a34077087095
s: 5d5c4d4d3412eb458e8e5ad681b1c4c2b12e45455445da12855907fb
x: 12f4a64fbd200f921385fae808e891234e4c3513ee95209db2b273a2
y: 2c6b7db4a113ee6933f15ff2063d2145fa803547b8648f828e73c18d548554d73a5a9b3247c8f2fa857209ed46c35e18fc5ae4db2752d199d30767e88bbd1c8ef6b6a7910fe15945ad10a0d1f2cd6cb67c2a1794fa309a4ef00a54e218ea020fab7d7f5a7ef07871388eefe297935fbc1a512241228e281738a8f48fb98da06b5ed06cbc4c59682b6eeb882d51659f58fa79ff2dfb0a924915b19097a66987116aaccc8648e38c976fb64fa3fa1c59a0735be2def2f776dd4900c46345241f51ee0c583932673b7827f3ec5cd7b3a3794d90e19fb9214e9b1a6221f7f63e4aef3ea194b5ee3e39a79dcb4c8cb48195947f62c37670260f48681b79a1d4a4ea8a
g: 593a789eb79089a5d2c2b8f0801aa6d3a31f53bd55e635f99b0104bafd35d3a8570b3ffe2d6d589443e42842b05a2f01a8b63f33624c6758ec1d43384c15c0092e11ea940afa53b24431ba780ee42e386d41627044a7d1204fa2a7062993fd280bd5a3a91cb6e6b8de1f5f09a91b559f21ff7f84ad8f61bbfea544666c30eeb4cdccff841dd81d3b8f60d7448cb18d6eba9fdc02eb580c4af56f3e27f10078f5d326df2c35f98c73b304835dee42bcb47c7023b8532454b6704413e4d1f9118d8d735678001a2530587bdadc213d0db9bd89b2211ea751e278c7360078257deef5d4ce28f8486b674c5ba6b65c430383b57484b03371792c9059cac7a0aec067
h: 180
m: fed4be180727cfb598dc363713fbbd7c7fdaa178585280
p: f6bd6c0d013d23ca3b5079cd8579aa8ccbc9933c7e33f0036c9b1628a8bda002190d8f8c7414dc438dec0ecf77e3d2327c993521638ad569256bbe69ac62347b3127feb14dbd0d7aadb95d5bae30ae6b6044253113e50055a6aaca8da3dc9dcf4d7c8032427f44db49127516e5fe0f28a32c7077bab15062f427cae0a6d9e176a8719939940c8919d7614137b35db8fab167c8ca2c0e73ad84a1a0842ee2789b23963f449f4b80447f07e4dd77b485143d3465caec4e79bcdbed1acd4528d3fc2bcf77a8e6c30a24dd55effdf743d92888ae7b6a48ae8ad75cd6f4ef2b92d5b1145a24277278427338fa18d4e7068a293e4058ce4e9482695173897309f0f8ed
q: 8bc9ec7d332642a0d90e0085ee5c68befde929d6e3de1e69ba6a4625
r: 162a3b83b191efb844bcbd39240df7bd5d06bb27b5410855b49ef8c4
s: 8145ca6cca9e0d04b7603d666bae46078c1da9f10802a719fd5e6716
x: 25ff471174921d840b3b58c9ee6399b69ebc0a1d171fa720e888fb3f
y: 39b0e78f7a72e89cbd63267693b16a6f960dca7abd6e9fe75d22602876e8731141665835fe9141cd418d7b73f028da4aeb4b6d1e2aca3698b97ab37d63a9c2f3ff81bb37e786477e27a79dd3af02584068c4fdde938e635256dd2097e8531eed5f92f89cb71d13d2ffd298ccd8393065f39cf0fc9ea2c90eeff1d4a8bf0030e94b8a19aaa3b677dbf96c4b1583c468d6e5fda7e662c3b0824d418589629c2d9c55a83384c1bc1ade0fd1a4bb8fba46e92146e6dd239d948962cc38bdb96361cf934a1aed8229ccbd7e6eb0825982f41ac4e4a5d76ffc9e8ab95563e2a647ec086bfc1edfdc932bb36c475811593db1a3911245b2b530202da8744e6d3e857751
g: af72ea87c13ee7ab3923d1d9296fe2a0eddf1e1bc48687de608fae485f72d694cb73dc14fefbb1ef855ab463dd8068201126dff1c3e7d0f2c622f1f1d8bffdcccc44193ee8adcecc35193e30ca36695a8a9a1625b937e5ea82e78bf3feafc2bb82dda8638262090f9a0523d448c68941e85b64591fca63c61464901765c48aab6ed2daff54ceab7d05a828a7e02b57177fd3b992191d520959aeb20926a4ba8c22587ecbc8b6bc5bd01c3e5c84a75409ad80b1271c7b4563357639f45505d4adfef88c29df01497f7e1472c125771bdf09605542aaaa6467ccaeba399a0dad9eda90feabbdaab99cc88300985e298da166490264095b9eef3ff4a5420d226b9b
h: 100
m: 703696715c8d31135848e66d8c2a6bdf7925ef0489093e5075ca59aacfc772e2666685a6ff799de4f59e26668ddc2f87d45fb0262c0a1f2a4f4cfcb65ff85319e0f86b095b9cb6bc3321154f180bdb1eadb00730640df30d4225ee8d031d3538b7adaf3cda9d0f8c7148947854e2d86bcdf60b9748ebc51e2508521220945ff1b1fd52c690d95e7ca0bf6339275f669fc78e3f43189c0d72236d70377a6b149f0acb6263926c7ab2392f02561da119d80efcae305d9a860932be5f7b26a5c366d420ca66ebd51d24a210b009b873d3949e3f4061b31057692a9c120d83b81ae8e0747362f1189fa8351ea2bcfd61425d1004e0537c5f
p: bcc3c31321eb2e21c10028a987f09f5346afeac2e2e9fcc9174d333f332ecc2bbbf7b29e81c8c0a4e113babd61ed3d9212d659bb336aa105215a15f795319af5a9c20fe9a1c963a674f73d7bf7efda95188c9a0024e05116de02356a81bc7bb67dbc5d36a1e903052034ac36d40f22eb71869434edb63c324afaf5248d77b1ac8f8239e9c0bf4b4d13627277f710ec18b17d363e01b7bb5e53570b070fa48a9c42ac1ff54e40744d4120be8f2abd01e47184f49ad81924f2f4f4f9a55f530250a34c2720a8cbb1cda2a192a7624a257f62b57eece71323ca332abea557f84a4e80539ee25eb584517c6de364509c4ca5c33060464d26428088338ebcbcb09a35
q: a82df7fc9ea48029cfcdb28c062ac1ce63d3dad7e64effcb20130bfd
r: 61a0d24b7b3721f493d1b392aafc9697ab62d4738fcf6d62e88e11be
s: 7fc7ccd912d48b8279bb3ce7a8ae357aed7abfce8baaeca53f86b85d
x: 1531c423cb564a85fdde6dd896869e886fed9263fd1659dfd4bd1bce
y: 99b6c9d5eafbfa07db1ebf7a3b29409d3aaa34d189d64c28ba3bfebb895f2b392052a50fc60a6636b87c4da6840795877f9b9cd7ed281533e783246bb7e6558d4ae7ea7896e89fe0f22332ff26a1e6028c6b6698df980e1c10d6f356df4cefffa1cab676593af7840b0533cea3b22f25fbba04b7ad5e5cd326a03ddbbb854b787e1f3ed56d947f6cf990ebe2e3786f2d4f167752370c92e46c32632021769d1ee8618ccd8d86e6736797f02aea89d54b3e7d8ed8eb0341a89851117036db04904b516f1501aef8ae2eaa7b7f9399d00a808da3b12b0607e5247bfa88c9930fe20fee5a8a35ebffa9df73f7e9eb7ac8f9429f985190024433cf7cd1ca67d47cec
g: 25f6ce36e41338202267e8c0f57d0c9b459056ad3b0e1f5c3dade9cdfafb7bc401696a3b40c09a0e8d547ddb7c270017f111ea703dd4496bf65f8efd50f8660fb35ce79bf1c74b299ad86cc31d1164e1fa1062531e2879bd42ddce94a7e32ed76de6282ea3c54ff3e11436e3a5537384edc55811a726fc8e0f330c903c2a98e75f48dbc183be583fa20000fd6f104a6fc53548f9d5b4496782d24d2c1226589c757a257892e7e29dc3aa2f9e78bc5bc589a44b1edc4a07e1601bd2ef8c60adc5a726cd5089f5ffe7df806b66bcf525fb65fea57aa468390f8e408bbcb5abc16982c2f8a5d214d7958cebdb693cc7f2a36d8ca3749949ef59504f264141826be6
h: e0
m: 92df7077542fd6cc480a67465a911087706ac3a62a9be72781af054b9b6f9f58d0e18f919d398574afafe1740b91a471aa3098763c686687bb02ab45059fdc1d3b7ce37a3248b2a209f8600d321e9be5b5b1105c8f6085e8a536079b8fee7b31aa9b7df9ab9442738ae9e5651441967ed07ff214812eaa4f0ebbcbb1a35f851a74758dd4ccbfa6f7ad0b64d7e8c1513b6d3ca784caf8580bff403e62b103391ae68c463c82602e5ceecdd01e75e86dd82a3f93e6b17f5d014e0c7be034b746461cc09583a87b58cd8b1b79faf51310f6ea1a32085bad038e91380e
p: 98833ecb12acc9b5376d36ecbdad45311cfd2b847a79ad5e45c68ccebbc7107ab897fa7027457bf19470907cef8e400423aee7f662105986934bd08a18b89cba7e2a2c9fe12166f5e955a723f9db2379e65ea6fb54adcb1e8d169f2a097156ff804d9342820e99f22bd6b2e23400635ebdb8b3a9231c6fd51f9c27bae18ff0fb16c0bab91c5e663196ee000cdf8d063748e607ed109613c2625b719b7fe53487d6f308af87be99ced8447681ee10844539f16a32019fdcce933ad288b6eec3e0d41a1d1416dc7e9e1755ddaccfdb3cb8f973a793d1ae2b608706b0faad800f8a2d2267b19eb358d611ddf4790bc94fa1c6594294dc7af7fc6bf171b39b7833d3
q: e9ac0229b685c49b6ab6d17acc399d8a6839f5b0b459310322d76f19
r: 473ebd5631802582fbbb885f6a7a16116e0955e72a3c41bd851c03bd
s: 8ddf46d58c4cbbfe9a0bcb4814bd7bdf25ff640b5772cca2eee1351c
x: e78fd849400a6f743c1c7db13abe8faa3e8ddc53f08c9ad6f33ffd6d
y: 65a15c5e897ad5452c30e85a2b995c91f258189c3b209b00bfb0d71861ac46350b24a8f5a1286f5d696d3a55f06c010473159bac182a1648a75449771981020cbc7df9715476bdda704123a9958f6d5096ee0109cb1ffd36980c78cf49f2b6833530bb57789d6da675a14bde4f07221f88cbf0991a45e6510c6514440bf3909f9c892575fcb477a45f0fbaf46b074108104918f25b809d651b38c1dea9f1f3bbfdf3b9ae60aaeb30a5a1f2f6f3465bdb4f2e982ec312f9cc81f5156662181ac0c3ffda8d4bfe530b84054f52ce4c781269946ed4f10f7259c15eb24755282a534395a34c5b07a767545e1f26a10ecf0fac5f6bed3ecfa804683f27f3eca919cf
g: 22b59c4b1153e0bc923534262d2a23112ed8979859ca3ef0e549937e5305e2e5599bb963d672056f18d1dcd3b2fab3433894ac417096ed4a4944a00c4c1a139f61a1fa9bc854c7a6167bec7df7a62d1e303d97b217cb81bf735e9bbe45ca12383ae46829cc8a50753a2ce8357ef453b714af196c6d9ee7b0915b12b5994803f26bcf4309b0e608706e03a36f65adc0fa9cc4cd04b617865af1ed3142a15e409a8bb6efaa23da77ba6af52d0b27de7d8d4bcd623b58d1fa8c87b7c1043128f5155f30b30f504c14d19332ae35ac31d2be0f0281a97a389ea1bb12826b6e16364cb99064ce6ad413feb98581fc702a2fa6614be55967a28506ae55d84575da12f7
h: 100
m: 68d1
p: 8e6b74d1df71a5fb988ecb8fc7f47f1e8cde9c3cdd4229a3a82f24a869f2f2cabe6fd6e4cb808f8d94ef56a50ae60dcc93ec619ad109cd7e0e195416c6dd46c34d59050424f56405536c7c571c31d4b81fb79da08d59179769ad5aacfebbd1c5d019fe61907d4bbc8914a34106418d81360eb122972a3edfc29b270444c4fe5e5cdd1587a064c8cebab7cdf47e3ae3eed5ee825d51a3a558ee6ea43f1d79e069dbffd51fc941ce30cf1454d11c9a2fc0c9a76393b52f7f11e51ae580bafdf4b10e0ab4494d5acf8aeb6fe38e039f53200370697e00585cefbe118920fde6b95dd004634e6e941b900c81fae878dd94fdbde52120da84c4a6f5ccdc0063e59605
q: b0bb72eee2fb0c3b52b3b5bbcac8ab2214ee726d355e55931c36b371
r: 2ac98c521a10fec2d04da7ff8a2c775d0b20b167870724c36f82ec0e
s: 324a6f8ba8c58dd8c70cc6dec279e17d62069633254b2a1513456f82
x: 3277affff64d42a70e5c49e3f03873f455c6fb4eec020b8e0153e5bf
y: 6a6695c99483e5144fb46e415390f0c756ccae821420ac080dfb8811ccde45df8ac834c25297df1851d24ae6485d5730278403cfe975760501ef96628a278274638401fe9b2a5aa772e00093d954c2ab588104566156152e1e745f9ad1a4ae1e0ccd5f7d8946ce299c0d0a5bcd0502d8d5445d20c60959654be392e04b4135090dff2a751a2995e1e2b877d3f67e2d326a9a445f194979a79db46b26093edb9743a404e10cb4b27750649504a410be329e8a5fff023ac23234e7be78f88495ddb82850230f770193cc73e49a12d228df276198fa6131d2ed04405de6a33a4a419306e5941c91cbd9572b63e15847cb8fcfdd4e80de393c57a667dca6324a25a5
g: 648a2773d52552c96fed01fd63c067ba8ccf6c3dd5b877ec5764fbc5f81286bc7dad25a56088dc85c596136f22d683b9155df8e459a820c98e4701b3e3a5793e3f36769b60dbcb119c2e64c7fb1622c32db9b36d65f6d5d5a4ff86461871f8c9a1eec9b0f7eeccb82e0e54b8e0fb6d304ee75da9943ae61bb1bfadf7c0df2fd26093f0f3d7b135f4908bb924e27c9d87594dc4730aeb058bc65e317f92d61f00fe31ea654db39f0da772abb7e0578975762e094234c612c64a97cbdbc5685d108da7cad60134142d3565d83b04569972e4e3a961f152f25f33f623ceb4435d6492491a4330cbde0f40958a69ea1aa0ed4ef88bfc755fc67175ad804574e54654
h: e0
m: 7541d261a1c5f1cbd7df6bd1872a3ac98caf95669f8aaaf3d386874c0cfb173b63b283d8da85119b7ad0a237e3b2b55d4290703ee1b4e4d03d504bba102beda23c
p: ad3865b9c1c13b84ef773f3b8d4eefc1ca5c3630b8ae3a496cee26ab78b60c0915483ce2aa2bcefe947ba38b4daea877ad9e1e36e258555e5477157f7005eadcc69da336b15e032a608caf4c6e81c86ab6d892060d809eeec34a364faa3fc14f3815d2d19684f3ece3739ec25d501bcb8e80d060d99b4a59f187d9980a02bc00d797d14a8653ac8f02364e04a7c270bb818122257a7bf949ed80aa4fa60cc881192721358b2260d6302e49003a57d24ded33c68577deeca73ef7437ef1c30c0a4e87b66dc9e59abbab783ee735f79439a115727c40291fc622cd2f4adbae5dbb8606edb1a94a96d489a8853d07714fd77908dc4cda17e746a14d501de96f92af
q: dbb867dc0e56aa48b4dd1ab567d1457f5bc6e5ff8b838c9dad218509
r: 2889263370b7cbdbc933144e05852c121f62361f156f23124d1dfc2a
s: 28e2c3145bcd24e52d05574ac28bfcc77f856b803eda5b455079bf28
x: 9484ee47d91746cd355e6ccdd0aabb18754a180734724b80d9ad82f5
y: 21bb8b5cf74ee51b1b8720d9b90976b3f07a7daf30b8b62dcb1698851410a69b0ed041fa73e8dde17ad50ef8acd3459aad405266116ae555cea1c9491333a89bb346b59fb4c64b1d04f560074b1757e81c91c06b209bbb1040b00302e65fdfe23e81937d20424a795c2b392784ac4f7e7000de81f4e0e52ea2e825302e95872d28a01c173c4564678fc84634dddd38496f2fc3e41b667401563d2484460929f5065fa777bec4e8e22f8543eba9efbef61b695eb35b9450d309f7f203c0e1150a2a1a655ca6278d3afc61e564ca6a96bb50ca17122420475bc2bb2ec164c5a045f712dccde83311bd4bcf0616977e6f0c51e86e87e467c8d36ae3259c67be9d4d
g: 60b67122ad17ce091d5d8bb2ad235b7de0f18c254d1de9d472384f7551a37f84c2b7299c6853a7545642f397fb99a70bbc6808f0d3afd626cc578ef69b46c5a169432fea6eaeb7bc60d32f9ada1d7145e6124059d55e2efcb72632ccd4142bf2b3c58ea2ed4cf76c61e9d57fdfb326f0d0cdfdf3d6781d3b7e17abb74ccf746845118f7086246c49eac4df3a6494af575d933d711283db0e0c13cdc7b53cdc8def3515e6add56a0cc1e4ed2e87eaf8622f7f2664a24afb3cda91f2b4cb1b185876327606a63cb5db6c65622fc7cd66e923d12b7d9bc1c0fcf7d9c52682f058e285aee044f7963e5a769339b09b42aef9c423f8dcae80be913d6075e64d002edf
h: e0
m: 1de638e1f3ef07a62af620f5555ab7b158a5ebc03a544c45107352cd5bcdf1180099ed6b3057f37eef61fc0756929f50d85dcbcab8ea10d23d967a4bc62ad7d057e23a708c8cc4b1e94cbd5599d8ac1547c67df0e166e949f2409e14a830948b96df1fd771db5c1bf4e03c3559dd54639b9be038c74fa2878b2bd127dcedc6af650efc5dfc9ac59db78e773d9277993abd492be923f25dc497ddbec7d44af961fc0210d7fdd7c4653a98215060448cbf65eca3b7c41494fac12a52e59cc75113fb9cee3c2da34b97c58a
p: 80802c75612fdff5c7e6517745ae3df2b7dc7ed90ab17f082f1ce5882163172415d1c710815bbd4ad2f421085d75ce7d1b8e8ace04c7d96c6f4de5f577289ae8f2ea2a9149a5584f12d95648a7c287e8bf7d97706a0cd9c6f6221a78fece78654556efcbf90c9b81a68d4f2b53a6873af004a4f4e658bc3f9af19a148cd21f740662b017e0cc598d39ccdad7eb8630eb8d6869b08a017ea590620e15131569e914fed8da61a6ff0d1d3e2af83a3d58cf208be622f501086022e5a1c4efe959bf4831cfdc232bc477420627e98a4a8b2e69523520a902990bd1e45bddaeb8346c1777238643ba64d36f38ac503b15b5fa011b69d1dbfc373afab6713d5adde815
q: bd3c358a1baec377bbb2b3c5424da2a080a56d830cb7e14636e781a3
r: 6140321c6142d643aaade303e20e70c11cb44903d913c3506b3130bf
s: 9e60de19a7d536aee5175005151e570b7613c7605460471f260b6130
x: 22e4fe758e368c9997f3f380c9975eeab46c68dce9ded344a51b873f
y: 671bf8bdd551ceab91cdce1518d2d44410f9ef481adcfd9101156d376c3df6079de85ee60eb80b342d25c4b12567e6d9c46c021beef0a7a9f4deb2ae101c1f39a778afca988fd49bb699b13720be5d429ccbe3682babfd18e4760e556e3e75313fb138e745d3f4a4c7426e2de0fdf40c72b446f4dbb8b2d9afd04a2707387ab505d216cb5d39275eb792b33dc419df1531506fa5f54a4517272e71ce6aeb56abc8d4d7b2f4d112b312520ac97f1a363ea7eba53e6b3df727f728d8a88d960622d6404da9007d3c07483e14c1b92ae35586e665bbe271600ce061f41174a904026bd6b140fbd952438791b14f75b8ec643785167c078640c43806909d70a72884
g: 257746e903ac167732fb4fbe682b42113f566742883e6893e7efbc73aafc7cffb044f4fd4b185268a0f24715bd205655c21af803ba91d09cf76e9944fcfe4721f90656385e905216b0a5bf9eb634f0096854bd6fa1a507241e82836afd4fb354c53f312e794845ffae2392179a7b9926fd5e3b5a152223a65767d549bed22acc0947cd43c7de7ba13f422d9ccd4a6c0e58529585cd0cbc2ef6d11cab106dcb6268774251c860e3af2eb9f6b0e68e28632d430feeada26ed542ab095068de7ee8476d390e6634b4c4074004676005950e2b1d1ea26440842199ce62ca03e392fb12b43fd90acb8e165216c633e04ff16d64410cb734d2845de8e039759b42fe8
h: 180
m: 6d826b53c55c421336a7948c72c0eca395412b4eacd1326427adb6f868c58e92984a6ff8f3121f27200b24053347c582b8649f8683f05380a181d9370e60bd008daf8433df95259491b11465bae397836094229d1665bc5e855b151023a4825b4252f0ea569e39e7d06c09a6bb64c8be98
p: b0786459b659a2e86263cd817b6733177e95a7ab9f1efbeb2414320ec1391486447c287d55789fdcbc07a65fd8302f6966a681eb7a0727814dcf3bbb83ecf62b5f156dc413f52e90331e235bbda51653e293d1b26a9b14ccf581e2711ca4d98edbde20f9ff6086572075b4a60b44448105e1a569e061fa23ae7a34776ebc25daeccefc72232b53afecd59878f0903f6e20c25355b792222f27ce8376cf104777bca7ea9e226984ebec71fbbcc6b309fe77dc877a1a826bf8cd95621c03bf8fafc555fb7476f0610cec8ab7c6ff4b2f547efda139cbd0e1906f6da018beec9b7c1a03dde981cdb98d85ade99f01a7e3313444f642d872878be4a3ad361077812d
q: ffaab7a8245bac019458c9351bf5248df74c08219da802e05d6aa2dd
r: a489cb7f840fc909c01e2f5dbf56dd71bf8b80ac6bf445a50faa52
s: 5835cfe67ef6a3b7062e6b0293b2e38919a61002ae75fb0ddf321538
x: 6eff90edffba20cdd1b6d3f5f2b833befe71bd6246269b6e2c24b27a
y: 5fdaa398ab81276dcf1594de8ffdc295f1c00cb65b7c721da46e4ef17fad82039acea821701b4c1cb86b7b20794fb13c1d35e5e792433ea1795ed3163e59732ab090f6a3f87e00f63d708e4d8d2bae1bcc55b72023d3545883b92d6a527375b2fd265a895ad96f856b50ba0b403a1fefc0de4954dc05e8896ded337397a8fe0eef1934025f9a005e0529ba64d7efde86ce5a5a7eeafde765ef5030e536ae9ab7a8c62b6111c598d6e82e23159a356a09f15fc28a4f4f5580e89e6fa00cf02009c9d886fa28d629a1efd2d4563d3f85b2f8fcc0db8b6f5487354e54f85367ecffeb005863a6d12bb980fe2a96737359f3f52ac9de679a9122ae7987895499e26b
g: bf1eb1613ea3cb694ab4c777c5f3805bed7a07bb0565f822ad4366b3d0731173349f80eaf4afd7ecde01cdb7337d35695a981959b91aab179fa5b50f16d19398ec3e41010c573706ad59b6f98d32f9ec92fa159ad1fe133f54e3174ddfc8f2b855f9bbe196933c3c8b7b9248959c3e351858da0c68dc7aec49703d4ee6693fbfd137b254509e78b4838c1570b322fe3618354d884f23e79898512576265fb270431e73213dafc3379ef004ddff329843afa901cc7a22ac8335fc8b1276b9f1441af5d292586ba2b4a28ce753b8d736eb781a30ec90f12e38505171182c05aca8f1ab4dab36314374c65e2afe79f674d3595ee54cefbd14be4b8c26421e2c65cd
h: 100
m: d3ea008623e60e26e7197b1d8165d5438a94fda258714eaa86d9344e05292915e7e4a1c58eee14d44b0d102e723ccb1cd3db82aff212dcb29a370f6870f78de4efe55f6de587518e9258f0f61403bb17082aff9a71fb39315df37d5ff104245350bd8c4e4358b933eb7b0efe21a3a2ea2e4f0d60f40ba300041e15d7bba78fde52c9bbdb0a225ce74754afd573c1689366f0e96edabe589fa6496fca9c16a0379b656dbf7fa6aee3a0999d10cfb03a824cf5ef30374a4fd15fdaa40155fe924be99ba3ea58abf965226e6344d8cb82b7fa3ed9b1d494197abe3d081e0f6d4ecf918d84b975be8a2e
p: cf64b03f0e616eaf7a1b4b7e0a42aa5613455aa157e6fa3b7939f372ebbece8d6b6654423215f7641cd25eaf3453dbc2c02cde8571ab362e425824e6cb6e5c78cbc2327a2e8b4c22fad6766ce426ad18b347c2b064fe32c5e77f75b98f784baac22b6274865a1bcc236190a60d3d5c7d4e3085a3ebf581a31c2fca597494029ad04c17f7ea4fa318518f3b104d1ace6fbe0db2a17cbacb9e8cd69d09bff203d7fd4d19f3095a456019d0346f4aa4df7e29e7cfa346b7c52929bbd7ba89cad7bb1cf194679acf5458cb60e8075b0499e954d45a8e9cc5bbeccd548c95a9a206ebacd885c65410d273a69aa7f4997cde52c100a8c4e7816da658926ce83848993d
q: 898ba0a00e5b2fbc8522a895cb2de4a1d7d7de2aa3662273c0fbb183
r: 41ca6a3f0dd8b7d2ac8c57203bc4e99e3265f8b5f5c0aabee9cf0175
s: 4fe9fde8350388693d8b2e76903858c99403e2adb127023d6e1197cf
x: 3801f472df984ab311fcf040a513eb5d816379f395ef92e18ffb7a5e
y: 68c159a9384c7a1eade817db453d98290a38e2c416f83cd1b6ad75878917def3db8a7ce910acfcf644becb2484df9342f8c86027153dc20b52b412c0d4460ffe62101f02c1c60fa69469bf29180d1219a79886c942f6600ba011894e90e46a88fca3e11129326594b593f79e74969af1c22929a71088da802488103c3e2395c8c835f9991f196fdf4017e8d495ce014b105e3d1670c0b3d91891ef4cb8c26a7b1c2c86672a2d99f052facebf4d2105f779dd0185b7f1cc426747f866a075da52f8b9e1f5cc1f06b93647cc40e355e00b858ade53b20dfe72220e10e2a3376d282302ffac5094d39e94b5918a980203d88dcae27ab5a45cc92fe654408c2c4751
g: 1584727688781178f6aecbcd3ddefe19aee49e26340c7be928ffdfe1e9f79608cb57fe10cd67a98e8db554a22386e4fadd3a379950d31933b904cea4e29409c9f0e4619e0408447d5d7d60bb5c6d5819557bfa5763bbac7517e915a0da32857664eaa1f60a008db2e84d35376da11f40e339c2fd05d1bcd17c8051e6849425e91058ad0f190b9b12e90b1cca789b4e4cc22ea7862464d3f92f9c423bf0d41d34a9438fa39f1f70db772b33aab0b13e4ff0f565a2ea5f0da1537bbb8ff909ff32e2ec4a97dcfbfe34dac266340804bea72de4555563144f053b0016e62e2360a9075d7eb34f7879149c3d579dd7dcc6d3096373a0f8649d6587efe291c73aea77
h: 200
m: 771c0510c70a779f9f57f2145abc7eb483f86404715b669ed508e36238597c86c12d0ce25b092b665ea070f5b9413450f381e95ea641a6d746702d7bb893c85e1a92e22a58f6f04e40f3c251f0f515bcf212afdda3af7539c2c5add40108407fd74bf0ef4ea9f3fd43a6c33d6b9fbadf3cff81d59736aafa6dc4999bf29c43773ad1ba47b941b55f874184f1eccb01e23f02259b1af1b97ee49ceca5ddccee07406044150ee76d171c8d1883a9a9bc4a7b039412fce8bc1d782ac2ef490c294db35262d24ef3db78fd89276f8d8987bacc64edd0327cbbb4d3e9
p: a1749ab6c0bef4c46217232c9712e90d76dbeaf4818ac7e138bff366686e22194bc3993548968bdef892a34902719c868cbe9037ffd4acc74524fa8a5857ba9d0238fd3a2c7a7073048bb53d3e8455c4bc556b981486b2a5dcad4f2006d00ac992e37f677f9e7b660681a9572e3bbdce0d68a9577f1296e1c60b070a567e99b432240199565cccb8191982758814e3777e5db0b88cae82f8a1ed05ae5514bd7e68f47cebf4e38e7c80bfe5debded1bff420a5569c42b4ef02101da5623d16ace95fca025ea0ee7c282207dec498225d0cd27ff86b73cb2757efba58de340d4d3fca8bab627c3d6eea7813871305ac96247e6576538ac655f54d8daef40076b9d
q: 98b9b8d5d699eb67863acf54dc585515f8556c4c8e797aa80ca29981
r: 59f8d7276262dd6be4fa772987a7354f403290d5b5f54d8ee445ec91
s: 716b0946762416682e47c7fb8e66684a5e41b53ed3c5e1d179379ee4
x: 278bcfb6ebabcf5fdb4d7ca2d34f747dd772b0c39b985b7c89b387af
y: 3dc886e8c4367c7d55b8b2fc075ca954991ed69e11ecbfffc5cc1b207e1ec2d316fa9645603cf1078f8cf369d5743fe96cb88a6d119ea2a7e647c84881d1642abe540b65d6f5ec3903c21692f069a01fb4ee450f7d173dd2bc5b264e29930bdfdf235b2f7b998aec6e0e8840f112049ace527271da785ba51dd9d02e7710696df12709db35caf35ccaf8c7deedfbdb9752b82648183d81569a896f45ab9d7dcac55927df6df34c8a222feaf0729dce21a748abfbbcf8b7d176510b9871ba9906ce3c729aacbc392031c8cbf346b9e473e1fffd1f811ff572896f02039b143f04a148400d680ab8567be2ca1f0d046557996f4a413f19b2b8b12498d6bd792117
g: 811e541eeddd0f9fd4e29431757e4b78f8d96365e6643b5642f5e0c6930ab60d590f9f7af065d12a62fca4ed8c92fac2c8d2de0c4ef8e8fb2aa56d2b115bb45a34d468353e0d3a29a0d46e40f4ecccee11e7164dc4751bbfe371b17e0a5ddbee7676ebf505f82c39d89f78d2140d23a8abe92d37031e33b1776d807c4fdd5538ffa86dc8433cd91683eaa744315adc402454f95f25b6df9b2443dd7e39b365a8377c17d5d51e2f3b62129b221db9c9bc75ae212636923d92a412b8c30e91d570fe041a76d49d959772ab952d1eb5642b12738ea05377c297ab221e9444bb35e8ee4c706de3db285bcbba2e67bb8a239bf3c129497c46b00ad44bab011e5a94e4
h: 180
m: b21199eed176784bbdc0f0003cf7376e8b502fbad79d16a2
p: cc89f83c9d4b7572be0956a4f303b47d9d6b1456913b7fa362c7b7956080df35b1302099b2a00ef04a07383346c8c80cd6a6593a546ebbbc01791eda0e270185132043dd06a3c5826f147ba784005e4965bc3185273a69f9ecc4a9ed06fba59f61145131f7b206c9eadb000e7070c10472fee16c8d0596d68894355d4891888c578505835bce44ef9b5c679bb5f9ec4f7345037683cc3b32dae9b0504d37125fe9fbf8a8860fdb92645c644ff0b36298e3b3c2e44ed2fd5f4c2b60f7c50029285e8033be43c270739ec466ebcafd1a69cfabeb5f8348d9ceb1aa73934eb867645ad4196f78faa654ed35908594e9f56d658c22f512d599801927da6f156188ff
q: 9dff5ff90a7103cd59d3edaf681f99f65204e7d5714ec9fad7c414a3
r: 7cc4e937ee082f6f5a7239640af805b20199f67835964a6e1f27e8ad
s: 6a7941a5844414d34427879e8d90cfab84a06ac93c731d139d6b0b8
x: 67a20f4ffaa369d2e24eb2ba879a8481c8cfc18c1cfbba8b77e615a7
y: 6c5ca61e32f9e9603ee29c10534e1c827811311e2b062a689649b94179816baf043aed44cc095ca770611c580cc6f339a6361ded866503db710ea058ef8ca4e47ff90bec3e71a77d679580e9279c553a9c12cc9b06d74f94e2146fd70cdfa4da0e5e528743d0e0e3606a267fbd4ef633c8c13637ad34a5b7cc6d0d385d305703d74bf594991a399e02b638b7937d8b7a599b8cc72635ea40f199c5a6528cfeef418a0ac1d9a34292d5a51eff8a08abdc56571f9e121a801e19ef7f7b8c31ca74faba06c56d49ae8d1a21702f7ee36cea85f5adfb62ff8c5e3396c20eceb0e31149c37abfcb4445443cf43c92267188ab0f9db08c7c272d93709905760db6b2e1
g: 4833bdf57b69b6bf9abcad681342406937cebf732e1daaef3d34f07396c6aea9079e057744690410aff26d6c963e9760e50b11961a9450a84e9fbf56bea18321c8c699085aee436760c2faffefd03657242674c4ea464b06c035ef64577227ec72d52f152c877e61ab8159bfa3c12fde85f7c4ea31f610fd383b55b3ba8f193120d363346d84ba5fd177afb4c4eb7235afaff31b94d69cc336924b1cc61e39dd41d422d533a4adcc79054eb22aebe4d633ad5da2a01860a97bba867b783c5793b7f2924247da18b2033dd049123fd2941e03658fdb7bba94bea127a3e8c66b6cf25c711949892527df17171acc57c357b48939e7a0c44702942ad5d552999f96
h: e0
m: 37fa3721338c7ad4344aac8dc50187f92278f7631187de1bae981c34c09c53ca10ea23a2f92644012311c46bd8403f008aa02fa2bede0fb35d182ca632d29d6ff64fea595ef35054ea8d915964e7f89c37416b85f0d64723a6e1df5c39314ba6999ef80288c95569f27072d82e9f520754fb55e4a7d1af2ba2addbeb1010570a2ef39d722b4959c88f3e3f79f63fce6689184957d35f8f80ec078a92a5157f70c16d7f37edfc26f0ad824bc13e8ade98ab909a1e087199e2d0aa0a15d0cea70b413cb6c61887acee1a51c358b4bcaf60d2ad4dbf7be97d422eb375b27ec3e28a8e0f8e38
p: d415a669ee6551d331b12a62ba7748b6d6996a358ec511b70c9525c22a58a3adb38be871f70b4115f709c9c62ed7fced65497344d05705cfe45883a785494dfac0f5223540088f7229234a6182a4fda917b19145b029f4230ac30a3bca3fd144076c42e04bfbc8c57944d693b2a17a30bf9edde05ceb1be41b0abc52ddc9c72320acfa95ba883741df186afbe10db865dd0ad540ecfc1e654fc9816598c8b29fdb5d1aafff6fe178db3aba9d5b850d0238a3262f4d001395c96db92379e76daf089444e575015946f62656738f1231812cd756fd7a92db4dcad7414dc176231a895eac194e8e27dfe895d501e32cf87a9b88af7ed0f900712a337c2af6eaf837
q: 87a2a55e0d1c59fccb6f5073c594356370b9b8ad619bb8d079e16077
r: 581422c06b69b5548061b419492ef80d659bcc2ec17b064ca7fb6fa5
s: 4d5efec20f7ac1b7d192ddce0f2ee79c9626f046835f6db106ee2911
x: 4fe21fc25a1e963df906747e4fc0313ed585d5f5d23c5af81e68a44b
y: acca364adf286020dea6c75bf542488ef57060db16a194307063ac7d96e24ef2d46fd678429f8b9ba4bcf3052c78a4494a959c82bffa2b3784a62198463fa1785243ea8723839b1a3b3952bc8b442e1eb7440fb421b3bc5100f38406a11eb6b67112bed18bb9ad1f2524af3606d74f9f763a9374a67a5f2f9399cdc8c02e0033ba5d3cb6a91be7eff7f13ed9fb1cb5486da97ea4f26f242695403512f77b07d0ecd9333b6c0e923722cf3934b014ad55bf2d50ef836110841d38c4ffc8fe2f47a073152a7b6f764be4556982c2bc1d058f7a6838a72377fd26d02d76178be863f60b4039deacf3cc12672dece4d26bc9c9ad63b433ad6c092471a8156b09b9bb
g: 267bffdd72e9581c333dcbfbf1b6f60e89b495f79ede81e8584e1175b84c6e87e1e0b904ebebdaea4c9916557a652c44ee683ef3d8e984c9fb6b7c5ecef3c4121fc32c68d5595035d2b9e5ea942a19ab019151e551813229dd4fc281b127629d53a811993e0e56af8d9032432aabac547549dd7f1ed8606310d84ea190d81920f06e2b1a2b4bf41858f73864f67bbc69ae4e25bbf15159043a2d85192c5c85673e0c726ada0349692ac1b47b6619be492c5f4cc1f5731aaa6c2b8a6ee0b2172218df603c4e5e1aa274266fe64f26fbaf252ab1b7bdbd43c4660375fe253c1ac2dab8006d77c73bfb553723576399d160aba9a473b4eb8c408261b21a8427eb41
h: 180
m: 6b1c237a16d62320227ba897a69e0730f28d1e7914749719f48d8a83c84fc6733219
p: a1b6ed918a8285a65c44c5bd4e435cf198a43cb74052a98e124ea1e7a1f1ecbfa69cc7827796063a601e33fda97916f39e69a051047db9b88b21bbf5bc88cd79cdfdbe862a372ed0309c8f4ff5b72d66fd28539aecbaba9a59e3215ed26e1bb7de440118832c553dae9ebeda50bcec677d10f6ba7051eb3978390673c9aca8bfaaf9fbe50900598302e8be3bc63f577417243b2c834e50ea46a693d75c4febdd409675f4163354c139006c675aaecb9949739b4d3f41b1059838542c1a5fb04785d9f90466bae5b70112082ef0640218ac892ebafaa3124c279d1e89eb3b5c599b5ad770751da1c00a7173313ce38f0ae0af5dc8f7541da0aeb365b7a9a6b71b
q: 8939cf3ce028a618dd8757132a58602d08e267b1118ebb46156840cf
r: 689e94a9a3990c214df888513170ca0a30371a448c44fed80254e9cd
s: 3dd683bc3e102247d6889074d12599de3101a78a9ee806db2258becd
x: 581bae3ef6b1d9cd92dbbf9f37ce560af5a440d1596a3a2432a792e2
y: 74f2f4b654f483b843ae41ae78fe5b69e48fe8bc289fae6917e063588ecb9e1f2d0324aafe2a761c826522ff7505401690d1b016a366bdd9039d359b2a83830a80eac338a4f67c1c5136c4d3c46829fcc1f2c948427affe7b28c3368be6dc31f8780c31600f8e9ef6b2467171e9bf8fd00f1711e04b19c394d723a7933895c252a2718c5c11d409b8f40b28b39a0015198a49c09e287f4dc4393d78ececcef55019236cfc3e9eaa460f9c89911eb133b752e0f3f996abb80f79c6be85044350797a7755f45bf82196284ce32b9544a286fea7932be52143c15bdace01a3da409a8b85b11c97d0c0d9f4f9caa822a1a2c2c89b4680aba6a4acd65acff9eb924ff
g: c4556043144dcc79548928969f15ae1eceb171e7f96dee0a0a41627d1573e3d74ffd99af66fd8f6a5347e00a5332353426bfbe7bab37a387331c44047890af2a21228e5c00128fef7354049f7173b862ccaa0041639252a66ca3eb19914929d96131b90386100939b99493142c8dfb2cb35dd9d166064fce1b1b91f639bd8510eaf6f509a0e2e96cce642e28231dec781f2ff3789882ad869b787b4d765cab47a90d5d451dfe8fcdeb9419b3e0c4adfa5c8aa02bc622314f43469140ffe5a04df7d080a5042b82af1b559228d39ee74a72fa25df2a200607b8e3f79bfe53997e3d98714f4107b73deacb04adf4aedcaccf786238ae6a5e39e5a0adb1bab3dafd
h: 100
m: 82ad6eb15e872132c38a9f5e7baab68c2b117ee1651a42048d431b461afc6ab2efbf0540d6b9de8d7960fe48d3bf137143e5758f1e78b3f669bc1a3240719b54645db694f59161202c642cf06f89af5dbe79bef1070837ed6c0c496df1604d8605480c47a6a6ccbe47a74f8cdfbde831f694fab676e29d26a2f820f2206f55a3e2c8f23c91ff4b525955bb6939e40a003f4c9cddd75e558d94cefdacf7a10bf3d3e8257484bbe3b258cc6ab4b1a49df95ff16b33aab5f59e8e7c163c7ec938f3a4a7861913171b5c5169c62b994ef36bb8505b70b2e1ffc06273856f7f1e80775b06a45698077cd8e6128eabfa2f67b747b3a01b
p: d1747c3236717b4915a6f5e63c42576a69f5975d41ebd0421b23f95b004ee9231848fc086703305c19108f3d580ad4f1a8e42052a6e93e5495f873cdaea274eb54b8960d7dc28b56b68184ef2418dfb0c84b0f56d4ff797f5c24470cde44037b74c976854d931069a9d400acf8c54495de171485b013e94ab5721c7d5b8989f98acc26f71cc622741db67b9929667f75235ad8988950dca0a34eb2465c64dd8187d6755f138f7104a220fdb47085beeb8561e5149676ef398e1d6e5d6336175e4ccb1b617319af384b0b068acf6cea64aeb0e112095b98271f612ed765c3d03dbb924b1dc7bdc117a1b26f435f95cf9acda153113a13e8c3fa78c5db9563e95d
q: 93bf777b59d7c7814b218674b817de2c64ab448d6696928fca1a4a61
r: 250da6ef1b17e7bb480becbae472a0c626d8621bbb8d3662e4ce2cd6
s: 5f2eeec78d768d1e757a5eaf1d8e01d7455e7d380555599d20dbe85b
x: 669b019864e18ac1435d6be8a3cd19b421bc2a122b29149ae098497b
y: bdccd40964ba1cf8d7e5bf23a61d6a5e789bc3b4263912303f5c794cd9b171e662474293b46a0ca8a6d77752123466a2d5058efb517a5b85578da9909be6f9d578127de4b43bd30c377bb68099a2cc159c2c2d4ba2cc1204e8bdbcf56851148f489438cee580c72071daa9e1b3894424af23733e13280839ef2cff633db4a92b673334640513c0ee5b6dde31848c9aa7a713bd1f93ae12fbe53e9cafab731d2edc95b3923209ba20512e9afabdd4895eedf2c3dd9250cbc1a3829a7b8c346e2db13b10e5f4cd88753fd4f462148b195d98cfdce73d1495f7a4aa0e34c86e89fd4cc59618e5c0619ae4bff3c70823b92b65dc234fd39fb8abd6748e5e134fd75e
g: 25e417d0e8a928027b7d1fb57842d606fa286c585ce1328c7ce0d0df3dd92e3eb76acb2077adb0b02946da2b76fee3ba8a26895e044edfc7ebd03cd684ee2989dcc1a3b30374e4cefa6f37484a9c9bd39e687aebbb7978df2e75c9830eb45bfa3e10c9bd7b22ec3a8709c84bdd272d77f2208be5f1c0aa248e5af43e26041826bd4601dfa0dd47417b6771bd7036a346048421f4553be135f1458e8fe377188f9b497561646aba53548da8d6289108809b7b348ed23562e0efcb5d0c4cf456c116ddc89cf59965cc1a4e3b9e33a23e053c028d90ba34539ef5ea3ca11ed78a8cb1edd710d043fdf5780b0f19dfc7c41c17c735725cd94110c270f3c3ac6035f9
h: e0
m: 59d1dcc21a5d90ff2dd706e97ed42e03b9787a27418cd4a8974545b9d8b354874f5d681e6c66a6d6b9970c860aa8957c0bd8dcbd4fe32c42e6e09fb3c04acb08495ae611387645b3bd0d22f947257a8a7aed723608d58254b291bfcee26e2289d5d7b24532904e77f2fa26911ce576a4b28956efd1c2d172787d7a4221d91e753813bdcb37d0fa67cd8e7d38387d7c1a0cf69b3da2cb1edd38907297803476ddafc85c8e6cce452a62e890b9ffbc1bee643abdfbe4dc192b0be19e23c6801e45b1e7
p: bb7954df68f66ba149cfae385fdf32a273b05913aa879be1f89e9ec700f378ec72a5411866c2eb2edad4700ecc77223842c0d4af37eb1f8206bfa1df761baac9714a54f38468b41c3a333bb174820d54245659f0e613c1f43c922d06aec24844b3a3ff5251994e2e9e90f37e0c64bb60d74a9c42812710cd7c62b850a98e9a5b887266e4afdc0d6c4f65887719730c2b7790311562a9a7c1a9fe1d64959a457e669630cd7e49f9aef709934f496a060114eb7d5a004e566fee8609f560137733cde5b2b6c85a5aef613404838d70087d97a2184975abae8760eb68959ac61e4c003214b63f3a0e89606b8119cf0a29b3bf16080e528e3e1384e87615365a088f
q: 958e8b68d86bba3500fc209cbac79a459c19c350601d80a9774b7ab7
r: 945b8cf9de2aba9427c74d7fc4411a03781bba73db3a1cc149a590b5
s: 91f0f0acc8ec2963071669e22256f03c8192b947e47fd0a8402bca10
x: 87aefcacc712b1c0764e9a4dab6cd997252f4b120061379627a207db
y: 460e197f316d78967d94172bfec9d50ab14d12aa663997c32a08ac62d80885e2623660d390468c12036a31beb7f0f451728a28017b1841fff0a0644415c2b8b7d61256657d3dd6d59821ff996cca41cd419a3221047a37bd8648d352e0fdcdf6239d2c0b091b4382b8aa21a7665d228d11cf846123d235fa5492206c06e3e2f31f51cc72925d2ab030e6b55ef1b07520f9a25ec94f3157b2d3d637d5c257fa97a62459bdeeb9eb30edfcc1f7afe204c5baae17158e0672c484015ce86d27fd903ce91d0e37bad3a73c34dfb0fd4a0567a5b2e84b8741cdb4a7e5db118339cccd87a203cff875983638dc51f864f8cf33174afec59ef893d814eb7185d690935a
g: 1fd2c90c4805186226c6be779c58b4a1f2b10495a94ec48d8c3e9b5686fecbeb19b50aaea65ef0602b293a017d9a1000c0fe75b74adeb6015c03ba2bdb6f2a642c75a1e312f3567df169e84d837c6bd5e176b5999bef0a0da4102892c7ff128947fbf503822052bf3f80920591a0324be830630132d7d5d7c5b7de8471655c6595b2deb45a93490180b42dafc079664fcfcca29e651d828381e7848a55ba0c5307da00883d8515e88e4998f49ef5a3294e73744afd89988801de1c6776d1de7326f39a9e9c808b813f6507b7de3ae1b75e3098c61fdfb3ac3eb539d00f88976ad65f0533b978c3c24a866de86d2773e875a931667a3b56f90d563e680c33010
h: 180
m: 1391d8e30f6a5c5857ed117a3e2468a2a0101e358d765fbc24023eb01eb7861653cd
p: 8a9d5b34a9c009889820c3de356a6570379a908806fc6923e9caca7a0dd9a536dbabcb8771535fba173f554b95c32ba506ffa915d74b3c1a3eb26b71e69416782be569f711f83aa4525a7b9a4e4a42e8608940224659ca88046f31e4c10f15b87195e160743a0b3226194e6e472575dfa198e16b2d4e3fd780afde56a536211c7ac245d2da89b0a2289116823676eb63d06119f6c1de0fecd11d6fc51f5f84371e6adb3963fc49884de3f2fd73e0a7fdc27880b97af20a950df6082af7e99f709feb3690021ce33d6723158921f2b64f995c286f25f7df4c60917eddcbb5ad000f7d3bc3107cb13b16cb578e4411440685e9087f5e88c577c1280106f452a1a5
q: eb3156fa9b703b4fc81a88d73b8b1027e5aa190b4e027bee5b4bcf5f
r: 191023b3891a99f9be78f157609dda119bef122b0d13f5bd593c8d8b
s: 98bb266b279f35abd8c48b7bea8391c9c3edb12cf85bb88b14013ca3
x: 5dc96a783ee46e6478793a2a03fcd71d46b4c2c1a9842978bc4db39c
y: 4509874fb9ec7e6207a3ba2f40533f59a8cb594f77a200ddf2b8c6ce43b476996898072eb4d0e403be0a4cefcedcd3dbd2d3b6343b26819fd3b08c28253069e09f97253fdd8094555ddc94d375c84b905a960b02b6dfc71d455bcf3820bab25d8d52c83f287510e5cfd0cd29ced2efd9546509c17f2cd5a258afbfe59e2a2569490d6879e4c968224dc072603a7255224f910d9d8b72cb6c95a0466f1050b2796d346089335cb89e0222f9c4525b4b10467397c8fb073dc3fa05856ec9e196d0c40019320ac49d9ca5daee371d674e43f8ad2a23f213bb4fb01d84afb8934c4bc251907003f30636b73ab9fc32850cd9b8547db930aba9462cc20fded6e89364
g: 83c70f14c85ab511142edcbb17593c8b26bf2ff126f6e4d215963ed10b05a014bc8da277fb3f9412940e9fcc8f8eb5a09f2f017d98c7d7f5a08359bd0480716fb0157109d33d810fd0d5e94c7721739d2bad7e155df9452911becbebbe42b3202182de415fc761fb3b30a2f929d0818626ad6a83473c44c832e5abd3efac4cc1afe0a1364322f2a07d6f3b0603e8480be9f5dd974f8231cc302f2d27646b552684773b16ac69b7fb255200574a74b7d64819aeff7b7c8c7f1dffdbf4078e445b12bc090abf5aecf83b4b16ae3823b808214814f91fad1daaf94647d09ad97061bec0af07b7189b6fb386e7611e73443f38027080b769a7118d31fa39bceea854
h: 100
m: ed7952cd586d36447d66c12646aaefe45c7684fb4c1c2ef92a250023c6fc36ee8d4c0615a2baf4499809e89c43d3e630e52feaecd1e33d0ce1ee440c4a9b8847f0cf39b0b45817713d7e80bcc2f95a2c12af79a205b1f07da0e9c314afe1694ac3c858a5696e75d09042a260e96d26f3e51296c68d1bf9e569aa4b468572e95ee7363f5e52c618bbb0f66286058e1207bbfc510e35b536a5c26dd6735a04166bc9d08c0d06fa97b4b8b101218b10e01832cc07d19c7d372ccca8d8cc7a6de55bf9032eac200b7deb1edc1867d65a8b987410e73b5abab0394ac1fdc93a3e4f90396c3df8ee83e22eafd110
p: b5996f897bd23f28306a1ebc72a3b226d3405484962b125732eb3af659aef385e260ac5db1f15b4e574bd3a6920fccab6e2a3a330a65f29254ff3cc7774867a9c66a7eb47140900e6864e54a35eaae78badb17eba89732148d78715ca0c13ea9addaac257c761c304e5d09d01aea14ae3beaaae8aacd8102fd932f3ad35161b7dedc20e1deca727d4496deff89a92e72d508e310c1937878ec4677ca610ba56d8a037524c428463dd7f777bb76e5b711d4fd4aded7625afbaa1dc1c2e29b1a574c3a07b2b208b93d5dff2e1960e7c9208e03af5bfff7a592c4b6e56bb041f23f1cbfeea2e39d155beb737a11468b52fb05639b409859d887658b3626c6c63361
q: d9aa50d49312085f55f86e24e8ef83b8398f0a23cf46aa508534243d
r: 631acca69f50f898828e9e4e97f69c07f501260db4e3651a90302c09
s: 43f59d5cd84a6c01f6850d817dc851553a9568bbaf0b160895439e6b
x: 2814abf1b12d69faabb1df4998d28402569addffa9f2d382777e48ec
y: 97a4c7ac05154295293f3abe22f0ab777f8c93a75139cf4fac4c1b41d6077d028ba14cd65aefdb16c6075b063bea7a7897f521d473371ded8a4802e83d10c0e7b3dcd00887fd885c7711f42b1ef6e04d4a7aced8d795fd181f37545af4bbe7477938ff444b5f4068a9c09137e43d056c420dcb3419e20969baf08bbab0b6e2021c87f1d22cfd7d16a8de9d645fe81a7427cbe389815040dc6d6537a62e88404872f4c44e0f9b40f7c575fbcb14ad9379660a6ccfcfed24c8f92e2c41016daf9ef7c9659d941320be5fda4f0264fdc08855afe2d7a49ab749770ac6d13ece1ddc4c14dd31c1a9fd211041f7887ae6f6a22f62292d0a1d757f319d1f087cb9ba91
g: 6a45134e14f0f89d69b01bafaf43a0dc19c7c6c69385627aac47d81bf2334f0c2d466bec936f42ceb0ce4c116488bb158b0b408e19bf55fa756ee525ca4afa10cd6a7b4c01373bed9c833b208e4a61ce312c233f804a1b7d6eaaa2065d94e3b80fb3bf69f02a3ed800f658be570835f76e98f2c9f9e12f3b72053256ec6d3819d6afb5f7315dd0f0bab12f683fa8d0ea03e9a8674e83c86571f618f818cc70c37f28b0f53895f877718a480c9322d92daba02f2e269b43ff0f7ea71cb5ce0dffa6d7756b3f328935ce4324a09ee07b552a382cb18ee82deb68a444b11073b45d6a08af784f59d3fd1cbb039a79ccf1b503186feb1fbbe34de5d08a82b3b7474
h: 180
m: eab7ce44f602e5e46c7387c31136b04c2444de3e3e4babc6e77fcc8582e7b0b2e32d96764048075c852a6624e797b82c05e479035ffa7753a92815405b6c29b905d129975fe782c5a46a5e91bb
p: 8c464bff7e870c496ce105973c5b1e76011943249afd8ba65a9de2b11ae751b1b9b804e2e3004fcc5252c35578c9e2f94123f27aa57e2cc0dcbcf75da07729bd6bb0067b6e467d7df84c68e19b8f8256ef4d518834e1f0415aef0e7770a0e93ac6822d677c01257ef30870d9fa95fe74d41caeb0d73b3846dbb3b93af9f1ca79bde8ff6854bfed0ab2b4bb92735c65c340c8b85bdc9a8c996f6d2203f6f0690d97f9194f79e18fc7095abd45508bc0ab83e62802dfb05d699e0eac4918a2d835b485b20f6578f6c7f31cb44bcbea273cf0057c283b696b73b27711d1a157a2d463510186d6ea54aef189e7b4b1f4babe54b46c4664f3c938dc5cb6098ee114b1
q: 860e8232356998d738fc5396e736c1f3f9ea3ea1d454c6375a69eaa9
r: 562baf5d92f7f4f0ce3bde1dfe59c28a80950c734cd104ba55509f24
s: 81a27c444abc842e0a169fc14ca51c2cdc1a953fca3587908e07da98
x: 122da28d28802a2e221596e372eda8b4a99647a7439dc0af23d9c082
y: c16917a7ef98fbc4b4b418ef627eafaa48c0351659ce2b9340bf06d768898d059985699b6f1643adc323f58a286c17a0a03ceee65ad6a15cb9410b677e915ab63b163bc698c45c8c17111809dfb37b40da712b4207c614c9704b698f02523064cdf11135d7a01050695667685a2554590a4a39be97bbb7c1edf125f0151d1ae6376775463623e574ac5757a2f812064bb7b529dfc9a2cbf9aaf62a072e6455ace8ec21508d0cd586e3383577d9beead1899db2027d691aba126c39a40e49e469b940d0bb08c8936b97d01665c94beab4ee66c96fbc6656c46faecfaa369e9db1219288a430469de7abda0e591277a04e834c00000540300194cedd545829b20
g: ae0d1fc9326a1174a37170a9eea83a8278670d29a9d24671e061c73e8de80727a6cf098134aa2b9c85031dd5b0c3bb84c05ba5f832c6f79f06f22262430b924a3c9b26ad851e38d45fb0328c37ede5ee73e0677936303af4a0be4687f5f620fe44279b2418d2e0a44f8cc9b92a067908dddf657ddcd3fcf6db887141cfcfa2ffb8d20d502314d519877ba077989d30295c6d64b0d4d372090ed791859800893f397903aa9f8d7e1cbaf1dd340bcdf53f651ea8defd25006bdba2a84e70384986569c8d8aa7f89a49c50ddbf2b9a58aaac4ade267835fdb5c2c3ccf1747e12533391240b7a93bcc0dcc361cc52373f80f13ebbe4a7753bb0856ed2047d5feb4f8
h: 100
m: 9f11d784f8e47e86719b56f9cd024f1a4446ace1cba3b14e757932f302e9ffd8d5a8386a3c2f427bf0d8f2b7c090b396cd950ce437acd076b91441815fd02c1ffafa5f
p: da02cff45c76fa856d3a4438a1bb11170bcde1316a560e438bfbf82fb23ed5277dcbabd5a7999b5f624179cff00a91b54b61d2754a99867e627711bf2b71dbbcc7a72ca5a8c034f844b4aecccacf6cfab0806418a882ba15861bd911d7550dc8f230efa785d44a92f7ad0cd8465a25875b0d6bdfcf5cf004080aa29e5e31f2e34f9e39d1a86ecaa3133ab5d30fb1db2b6166a4eab27b86642ed8a7ffa8ea14655be63dbb7d6913be0f1ef014ffa067b0e529f199a73838ef9309110961fe6d0b47e68629bde64320bcf22a6c470c65662a811112a49116958238569f2c513c203f20d7c9ba3d4ddfe52333e6108d24758cd1fdecbb025bef927d5b7de5a170c3
q: 88084dd8a05e65a7d2ccad8bf291c3cfe359d86275fa00d0f6bbfe7b
r: 1177cf0f51ccd66e410637d27369659b9b9fba311315769618fbcc04
s: fde95ca6b8e2a304411b60f948055d1224c160f7ef54c49acf02f70
x: 21ddadcc538d76b1534ccf7d49d33e0386c695739e4d1aed1dab246a
y: 3ace1b3bf51f5dc9116b8145394558831999bbed64b9bc67b86f0bec08a5d4999fb3787b44888272e480c32c98d2c5d10dfcb51c73226398b0e4e52c34d36beb4d68c48cb4ffd4bdaa915b6e88c2cea851215130024fcaeba568f0e4a6ddd12c6f42a632f42a8c4dacf1bd99ed273a7031f0b264a51ab85e5421f75d1682c50793b5d6bdaa7c287b1fec37ee9a1da5cec2343b79faebc2c9905e1ef8062847a925daeb401040b87031f95137a28b4631862c330c41615539066caf87b3bcbe18aea923b7cf0ca20ccb24185534fb0d2aa5840b89bc2d0e4c81b2ba0855537a13a95bb97f73fdb0eb6846e176751ece53d29788a33f35f1a14b558d433431dd63
g: 2e68806e9c519d334d339a560ca4c50c84cfa1a0089ac9e05d227a670d8c467be4d9f135c0bed9ebeeca3639669bb70d037ae7b23666eab8d0d852e4c57dfde9ac01a208a36d676817a6981468e2884fdd172b91023c2b94002b33e263bd5e4ef8d449c0a54e4b31767073a4e90035825f0577159521af7b0f57ad5d118de1a3bd1f306bcdb5738ed83cc3a5636154276eab02db87a7220a9aa7981bdafd4231c9aed0a0c5073b5acd60ea359e6495741278254c7f38a48624a6fd65924e327349927f0d323beab69fadf79e7f776f18391c2bbb7f6540d1debfd41c4e5474ec4dfd5271cc688711e291c108ba16d16b35551e448714218bafc7c63a3b6f1512
h: 100
m: 56bdf9fcf431424707f1f95f8e41d5ae8d233b76ac123ba2a80254890c42a7d630f867695b20845fb7b812a2f6ddc3c6eb80e62af4951370bbd0d5d03bda6729d940f645b5db219aa70753d91f122f3632446ff4d5374930c226c2e67b1e8bce3c5342a61d2c5a743b007da87f91c28632f1356bc7b5105849539573c2400bdb3f63c16ef501a0c3c4b28ae5dbae1d60009c75f6b37b0e882cc50fc0d6613f683c241e9ebbfd1762b123127ec279ca96f73b23
p: b176d1c2ff6123e71ead83b0e53d774ab4819411d51d49374f827c7be67cfd76763a972147e650d7ee2b58b1a424787a1ba5cfcc57885d8fc20d892755ae1b5db7fe0231a4d6726ee0a9473b62f04521bc1fe1e5cb58f6b071f0d1718538901324f01a7391c91385bfee311de7134fa5139a8cc1ddead314c7fb88f923fbd0c203f6858f673bd3af9b2b0756a221e7fb5a4b0aa39a2d6d9a6ee46eeaad9c278decfe8557f496c5956a371691c916bcbe3ab43214ff563a70dcd0db1f374974498c4c138dbf97e54996c4b1791c09f02309ff9483c9aec3e1b8530b9ab6f08ed4290a120db642f02954d3e32ee96f56a813faab1443f8d5c3e998841f61ef21c3
q: fd9b04dc79b9261c1dada8e16ab993209d51cb2baa977b67b25ca4eb
r: 2ffa07252f12b3908608d524295901d2a3ea1245966d919e4cc288f1
s: a003a4ba156cc38c6f68a2732d380cbee66d86cbb6743d7b954649d6
x: f9989142a66b0306295616c27e0f527a8b0424a68ce793b1888ca68b
y: 886c8b64d073beabbb0ff8d23d05ed19951e71e530d998c834c6dc326e787030651ceffd120b2b97ad551155fe00ac9096f4c1d2eaab9529d87309ba8ac5d3d7b7ef056ccffa03b8412d01ca9652cb9fabed1d320aa4469c675af8419b1ac9f59f00b9e836dc714384df193ed824836fef75a2372fd0bec1fe8fa9d8ea09b91b3e2751b87f50fdca8828d87f6a741c4b89ccd5eb1b741b6b9bfc717d1fc05b2056cc9ae9d3219c78038bedc459116e03ca3a86cdede897c818a257ec843f34391e7c7441f746060009e0183ac592e1fb714ced5dcd8091d9fd49c1fc598c627958607d25ec17dc57bdeacc139e960f605448e28620c391331a9d34439e0ec937
g: 20b4663ae2a4f2229a799f174dc895c6cd940c9327ddde58b76bcf6e1975e0f0bd453ad576fc95961dc5e0c9aa5179448776fd83605daea304685bf21c61f374214444250c85c2add2e71af33afaf4a28daba107f3869a0118cc776fc653603604a77b25318e03374c00a56b789131d4ddd6b6addbd62275152f0cbfbd1a7e9ec6805606f72290955dd1753247c164558f2090657943e31e54bfd98accdaccf5ba8f8fd01cbf210cb77f1bfbde62cf4bfde04b6f10e7f394ed8e044125f0d43365f19bcbc6bef14a116a8cbe08328f82f845214b4c45f22643b080049b1b6e55e3021dbb90a2820c10f6a6a0cd29c13300acd0c3afd0ccd3606e7dadc7f937e1
h: 180
m: e63fc61bfc5818aef082f97419329b8adb42be9635ec7715c55614df0b12248c4f5a949785e375c937cc619cf1451a0541a9e96d939e95f76793ca01706d287c178f4224135535b5b816638bea9191ec623da6f564091f1f0c43fc164f4fa85033b287ddfbe358707bdf6bc360b210323d0219b835fc1f0f6c8e0a9f00e5003dfe206611dc758d8cac4b1142acae34a1a17c09bc46c9b67b5e68c8a84238399b3a0a1e0ddada5665
p: eb81f1c0701fbe8a7bfb4de40d577203ca5ca10fd7b2552f25b21861e834b15f7b1698affd6cdf0d8a20e8be52ef8438085b0b90709e047d62ccce7663aae1ba509f0585bf5d4d69560fceec116c8a357f2a9e1f3f5490b178a9050658458b09e14d7995d0a439dfa32348c4f273d3a13912307887067b745eb1895beb819ca407325dbc316192da05cda4f83c1a7fc45f9290e94960752c010289c52a9abde848c2d89816d19c15f77846b0eb66ad97d2744f618af77e40765bcb02ca3a1994435dc29fe5e5d592dc2d4eb6bdfb4dbc6f6b7283d919b0d943d0b75b11bd74c337b0dd2ac638e1c8ef1dff8f448744affdcf58848a2ab7fb3f0198b01e05e85b
q: a106b7dabd59d3fc0a77337ff8aee12dd41c5d5b087a06c1b9316309
r: 50da9d43fbb6ebb59e9b4f89c1c356215b078d88e00608ac3e084a64
s: 2087720ea3501f07fe32112ef4ff5eb029b0620eba4c2c68fccb0847
x: 2d231de663900e2f4cc1c87f8addcbf745e2ab18f31221707368a2d1
y: d9df92ed7c82e6da8ad7cea76226f1f8ee5d24d7897bb915ec69d0e778511d9f6ef9461049c367f21c6dc646db61f489c7048015e82f351a4c57e90bbe1ebd5b5ccb8b3ea6bd477ab8859589f48a2f69e16c03f6816da7572a7f6e59ec3f2f8b102ed070ed46db2fc475d9c325201d295e07fa425d604d26c9f572357c15c6e6d5f5bdbea77cceaf3d7f49bb2ae7fadbf857666cfd47b61c590e16947dc4d4c03c3d04e156d4f68b412fd3bfa07686bf88c8b9bedba7206f7c3527bb22f3e400333087a89007b499c36ea0d16dd32539f56c160d1f6e40798820bc6168354821d2757f34dbf17cbd9bef9fea3891b525bf581fdde0cd030e3b90d133087abc5e
g: 17f4c01edcb16c83ff2a183c9079a74b767cad4c2fb234714d3dc3a9a55938e3e81c05102356b21f024733a04174d04c46c781ebf31b2909a22d42fdede81caab1e627ca1540ed6a802a25376d0c7f3af9a60a4c64af806494c753b937a25eeace16c19eb9a142ec5da70c4c5b843b332db8407e157dafc998cb39e9a67556c6318210872e922d84938619f70060ed5a8196f660d58ff23fffc9981c44f76b5ec0c580b424f04fc6adc13a391cfa1be64d14246612a902c4fb5156e08d2ad23dfd1a0a8c84ce50fe59ebda0e9a842d03608156809d7812a8cc14f920a5434d8f6b0db697dbcb8606fe0f38be0b221dc7b6dd5d143c2f67276358f9578584870f
h: 180
m: 875c4cb3a08b5bc478d925356de76d05
p: 90326d8cee672a0b3ff9fcef581a182cd84b8c97ce86a960f094708e00d8f7d0417c74735f2c65a0569a60e1f17759b0359303a5a1319a3352883be4008c00afc2ba50f897620fcc2a337037abc9447428f91e107901760c3c6a9fc05f142387ccbd823fcb2a0d2aa5c55203f961a8ed68fb94d2ff6aedc5ee0d32930fa6076406b940e50e1aa4b46140d6bce87348f971da55cc3f24a82ee032583d81287dd50264103f5afb82e76ec81ebb3127a136a6c06653075c485bc033c1c09636e4f4b0a22f5430ce8aa4ce2e8a3dc3dbad5b241531730412fff4a5164a8b908b7beadd9922144b8d4c43dcde1f45abfd6b66ef66bb1d16eaabf05847014d659a419b
q: ea85349913754eea1d0c7f5d17fc9d73c0e64a0be281d503e44fa927
r: 925a996eeb5e8c3be19f872114133066fdd68e67fec7e37e4c96e887
s: 8d523959af54ed2c557aea35a3dc4da5267dd6d7a4d796bd585019bb
x: 24a7333c34fb47c3e54290b64b679730b0e6ea00417aa82c08c156f8
y: 88c0777479a23d5fd944e098b0a3dba04b7aabca2a066e43e504ea74e3398417c960474d2ed194152eae7450cbaf4f0a0b06e2d79b4a64788fee3d7d4f122442d3d353f1f62e3b3dedf2f87956c3b849497891ed8335c4092a54ef0c5baa2169d696414f3b9d5dfe2436d99c52156ccaa3453685382a3aaf7c47060bbca32273cc998a9f3cfd6f28d1f997ebb4569e4134d0602fabd1a7f716de552de6e9dc59b7d1716e814cd9f0a1f4c967e447c9d666f295e5421a9e70dfca7ab1d8e57f20c952471d5fedeb266ce5889354ef05f97751e9e8c214138f5a0129fbdb54f1c835773791e8c660b43755df56d942267efe0af2a526ca68cfe6e04d2ae5fdc6eb
g: 5b9a6be90c0f87d8dad70dfae94b6d943ddb3c8e0fca3f0f4afc6eb14109c611aee162f4f168224749cc8d3ee09fd5cad3f7eb309a0528c748187fa841bdd8d44586cd44e6afd1b1110423ee0d46051799b446c59d2f1ce8b06f78aa4675b31a99abc0b014ee85030d60aba14c01340d686ede6bdf6f9d53eff33cf831d6076999d6b4c4679e0955d5481b9dc6288171c77b645cd38139f3e87f8f14db77e3e90cb6df1e3ffff9cff84c258b994d7799ba4563146f146146f1880fc9db1b046d7383c388829f90047b08ba32b7e8b2a4119bee8973f0a894e85c1a7f06ba2eff45e1800255403205e1fee19fd6d70eb7773ca5820586e214562a27ca859c8b3e
h: 200
m: 988af38061c4a11029d5307b92d337a61702232860f3722627db830985282c755ed5ecb15bf2789c4b970342640dfbfde370325977ed8cc111e068da3bc49541fa28702ba98949e09727da7609555dd34194b63b9d1f19105138f4bc9d60d0c348548cd1594a82a94a517461db1f1fe852e3afbf6bcb4a6249a742a6b90a23b8181e07e2ce6f5194a9a5cd16a94862ab27a660fecbdc8a268b
p: bc2392b05907cbef35dee577e735f7ef7b16c2c0d4f0d9d824038ebca5692c412821650cf9e3c5908bbbf2d33d6210491b14f839cc5faaa66adfa37de49bfe022eb2e79141f2954495cb7fb0c0f64549219065a0f9795b87bf3ef6e5c6903f3fabd95fcba0fd58277ad6411d50a456b6f7b8442e1c5c64381ad3c3071db322d4d44e90178f1a72f8b2fdaf89bf57572ca36f72b549ffac4cbe3b121c46f0e65a13191e8f78e4d6867c3003da47ab42491574fdc75fba00c55ead6cdbce078971013d0610f18fdb6a49dd5ad3e96fdf92747d3ddfece0684d597e93fb4384c7b80e267eb31d2ef5021a4577c1348f2e468ad80f85a3c4c1367ee34ee7337c89ab
q: df8ead593056702e1f8cb93ab08b039d3049ac2c96956bc7c772816d
r: a8fdc1da276efcf5fcec4eac7021b1b8634991200363d3d1e32f9029
s: 717cc41555e9f7eac8bdfc7940b62878d6294e7b50cd5f4be03485a
x: 9f04977681f073dca482c945997e213494194ab4b77e72d1eaa956e
y: 1aea5d97768d610c0edd637781b5c5b204f7f8f58088badc7ecd648000d2a1c569b05e4a549a01e9150652c9e8243ab989d1c642d6a4ff9bee6e00d8fc304a2f0abc99c7618d4e83ae4a2da3bef9647e4caf998c99a3581d55326670baf698cf6b97343f015680859cec755987627b0f84ce389bc20f862d758968b1e9655f388445a0cc76b472155eb3936cef3bd31f206ef03a7b03208b6686adb55dfcedeaae8206ae350cc2deafdd65700f8a5b554fb2d2ebb0f01cd2554cff5f98b3738659279fdbb5433e85d5d28ac2b0332b3660eb71f53b723ad09cd624eb95d8751e40f2e1c0dd53029bad6c8509b2452dedcc47190f76eb02a58f4538014f8ee5b3
g: dcb43f91c33f29334f634f868f870ef57c0a53a0a2fe1140ff0bda361e13d870bf30ec5184cc33ba961b584322e192131a819118186aea9898d8fe46889121b4f4d1d739fa04114d1b18b3e0768030afbd9efcc73942e0d57c91764e5e0f4fec8d17b3a72ed5deabb821779654699b9244b609e34ada7f870e07d1004905a6d39b2edb45fbd8708a248e74a32cbda5d1e1cd719f949f07479285f77c6fafbed2948a19cb451544a7b2593451e46c19e8303e378c1ed026b116a49077f5d460f2bb567e453f953836190c8a9cb9fc92a9d580f443e49c3f927a0e5371174737de3ec8ae4da5b83d099b0d9f32ceb5b0c216231e81cd2895c4a589d99ca223e1ea
h: 200
m: e1ce1f690064c2a0f1ed049574e4fc
p: fb578b4776827c4d19d2f47bfa297980e31a8555e76356a60b621693f81d448ead27d48876f661eb1244d33b00c89b7cb79a77aea1314b04fa56eb6f878236fefc557d93688b83beae7ec313fd62628fca59080a6602280269cf94e979661f9899d165d90440d7ca607eb32ddf4a7728fd4f175839374d95c42d8fb9b1dcc01460681c2fceab65e08477897742e8e8ca4b6a18a6c31a517463891476865cd7640ae9b5220b7487277d36e572796e41b6f8d999bd1ca9faceaf1f929caad75cd090e23e1a6da9b6bdf22bd5433d4119a8eb196dd448cad32da3354d5cef388acb38d9443cc4982b3f3cde81d521dde1133e04fe2a0b3ba4bf8f7eed330963aca5
q: b0308cba4cb365d2fb37339da569367bd03ca3f23930f44099686eed
r: 30d68752d02635a13ebbd8f480fdc1b6b7c8597b3f63d6167c406d0b
s: 5993c4c6e4251f0b2799f53af455b72458e6243d3b204e7c29fef703
x: 6ae6c640986d73107c2ccdf9874f96e08b1774412bbe48eb17c6056e
y: abf3d753748c120d216d1e1640d7007966eb3cbf1d80830741cca52591c3092571e1526c052f5b25aff81fdbc9d63c16680d8df8320e284de0d27b01e81cbfa4f84ba4d25034c3ff97e44000dac72a0f12ce774a31ee3f21f0f6b3a2014c0062295253493dca53d0d4b4c94d49acc116d69d7f114ccaf537ff8d5a6e83f8acb7c911d062c6ebd73b87b9c65182d201555a9cf25622ae06933f81689bc5e3df3411a53182c0365d6457628d3988ae8966d048953c837fd8be6f91eb0f12498810eb277a531996f192bedacdc862c9b9fbdebd690c414eaa0640703738e655882a7f2f6d3c6fc1b099cdbd47da65162ce8cc4180656a7a3b00e9dca5c85a59291e
g: 3b5ea62331a5d0b21c4c455e020f128749bececfc4a919f5c877fcc919f1ca2bb5aac6fe81ef181d6331058cf33f4c6c9371768d126c9a60707ffc69510bc28ccf604d2ce1d596be3983039d88cd3400c9c2aa3b7e605950f748a46ac15e712b271a0356cac1d3baaa1b9e07b45dedd73baa8542af5f80c256633e893ddfd9b189def8624a3abed7294b592ed9d13724c998906a6fea0ee7c2d3b6ffa036781a77082609015273b9581ee557cb78af1c931308af842203cb9f7a7a5f26c3ec96f3955160a9009ba0dac6a6a652067a10867d06b95b0d8fff63d8cddd475d45cdc9278a2bc1203f83f59bec85d995fc9785e7d7c5a4f5452cb3ae3250e41af94e
h: 100
m: b0c7201effb15930174cabfcf428f6ad3ceb5ff85d3ddd84ab42a1e10fdf28d3dac7de9e6163a5bf631e662834cd54f96f2973c9441bdd40a471a3b27efb9ab4fbce0c53d05fcd4676058798da6a4128e9225c67f5848207da0f753d6cf8ab9372dcb938a565b5ee5799647fd91747de107a99757c08d49e5e9af205690cb371d7a043ede1b8c22501721886b9b3281c128badc8e76d91a5b709a5e0194079a15ca418eb535438f69de6069ccb7b21ffa10c3d0ce03aee4997a8efceab710cc0c0d8ae7ce29854129bcb629b4040f7fac3b8c968789ec8aa03d7c84e92c6218a3973962cb5c61999584d
p: fb263cf2b81f97b5e55ff5a8e84b65058d721f9b2bc0f96ef8ad3980c1ee80dd69af539c60ac86daa993d150a53b93f838266e6bee6bb234c32784e2018edf370fa30bf9535990deb0c43c376dc224c286aaad6423e01c2596720129b0badda8773804ab266221b156b4f880262d4ada4976de1954d5efbbbea4cbd89b8752df59059706843a904e38a1222a06b463cfb6008689b6d91dc398627ce6352e9110d170ae6a0e7ef09b3f76c65b57e90f789769d3e6305a9d87a1e76c570d7e2ba15cc90c6e2f69147352a6790077571eef983d941952b1ec6fa3da1bd018f20e0a6a50644ce00ec04f5ae55588885d231c005f165d99175061e1843a9a06e1892f
q: 8f6d2992082311367d0e3afb01a86e4b7395381d07760f18aa93a699
r: 1e90a73e89f237ca86bad8e060637432c625476f14dd372447c7604c
s: 142f95be07b2bd52d660b4a6d4ebb9a9d0fd60c2ec5003a0d0b502b
x: 154a292ff521c6919b3524829b5b21238fcb00fabaf38786066461dd
y: dec5227bf4795e73cb2bf1150a7a9fb189811b3c29f472da2af9520bf4771c5cf91946b051f805c9a7c5e2ca790a07b1752d1337b633d0c0a5bc4e7eebdd22d1e9b0e9c689d6b892437d0c17c0fc3007238ef672a53aabe49ef41d802d53b2eeced8c7635f733265c9bf104f573fbaf9614b4221aa2ee70a69f33ec1f6edc76487b62955dae27b735a7012d6d9f17805a82df1c28af63fe7cd0c0403d0b015d0870e2e8a385b587dd7b91e9dcfc437ad2d43f81cce08c3c372240d30853dead0e6c7b34060f1ff7eefddc196189425736d224ff0a2fc1cca76aa8c564deaa22654ffdf34ce87c5d23c2490bee8470c8fdc93d55bc120e653e3a19ce237e49813
g: 5dfb6a757c529e26d3900d19c260b686038d3cbc0a33c73b5b956780b0aeb4c2ee189439e23ec46f034338c2a6f7908c8c8dd7e9a5ded649c24a967188a35096e540ead6ba1ddf76a206b6fbdce8c7fbff0ef4d0c931cae2bffe29cb26cec6d069624d2c981584bd8b8c5de42d3f92886ab85a26c502b309f75e51733fcc478a51aa92a09bd7693166304d518f983984d2d4603fcb5d31f72708af879a700537c53a48cf40b89518be007a69b42e342c637f23e610c381a1d258ee841d9cd5ee8f713605fa2aa828861c838979fd5edd1c35b9651917698710dd96eee654c42a9fff208e4ab9674f11b10f423ffbcd24f70fd62e6e844169739d1007130f0a31
h: e0
m: fd0d1023cd82dc0a90b6a59139bd65e2e5b0188070abfc422459fc77f2c536536e7adeac20023df19254a51a69a81068ab4fb8e964e503486a856725ba7e09a8fecaca13ca372104477bae7db59aad99fc9706f41ed2e98d73c4a49478a2c98dc2d22fd2a6fbb24ab31c44030a98521ab2d84312ba21be24159b56778d32b9ffec50eda59273d116636d50f84ec68937485cc1590c
p: cc96df61b9406b260fae612f3919efeb302ec3f912b17ed5ddf13f0cc88943e6d6e440f3d48470de73c9c77a9e29eb8bb594a52f47a87b3ad15fbe31dd144a37bd590940e0d8629bc50814b5ac732d16f2031070b9776e5cd684038250cd371807e508349a43cb4d6794db47f5aa81983f0120208bdf249a3b505fea49bfce4f725ea47179f2344be81019080d4f3d58896b6d5819b809d36051f77fb9c6644d769956475e335d0e0ee92de7f1588f7017a6ac244441126599481dd1fafa0f9ba6c947d2824fb04bdf5dbbc3c02326038027eb6f8407ba8ed5ba7a4192ce0ccf16b64aaa227d675c36e61e1811ed47235233f6dec87130941305fe565ae1c489
q: d8864ddb2b889744268232c0faa7949bb1efde4d93e59904f4cf7765
r: adb1244036766ccde22c5012443f7dbc421d6bb2fa3d94d63ad8bc47
s: 60a9c1734f89ea29172806dad88588539243905b08e43d99c9bc0269
x: 88de7088e20689122fb5904005ca2b71091221805e96437912ca89ee
y: 4c421ad50bc635cccffd890473f94fd7e93869f7886360be84c5a356391acf60c561106e239f1cdad77a21e3fffaa27d7518c582907fa066447e85ec44a27fa3fade0b61ce9fcfb0a1624d3d7f7411e18312e2ec610bd874fe42c7c24491bf487dabf705f3931346b417602942be82498ee44f72d7758aa58ac2e4dc4e69bc6ea6df4835e71bec484c5a30b32b2323702d94a9de3d5b89c7ded480a4774b3003c3634e0a865fe8f8378833983a735f68389a5adde28765f4ec5d91eeeff86d324e66a238d6ebf019c4ada43c67b4d5bdda7fc35c6a9a9e0e56480233423ddda5cae1614826e306dd617cf78d1d357e2c5757800f6e0071ae8fe9c7c8e29469dd
g: a60b81650d52a438367b7219f9660d56edefb805eec8871125e9d6f229ae44411cb2b82a848fe235ec045a3af9ba4dfb17b09af61da95dc5a01d3217f716335ce6ba03b35d3d41e4f0db1a7bd8d8f1ebff3897fb124b0ac0a7442e1d2c884d181bc428165ddc89db585524b44ad9d9b29b1f30941a80514ca25002271bb66601450cbae746d70262497018f83114eebca18cdd65bda331e43947c66b13f12964b345cfe34b0d36b3fd4b504109366df6dc520ddbb1fd6d16c3391abcd5df32358e09c5e2d5d1187ef46eae51848a4d576fa37735667954f368f434fbb3895810bd029775eb25a6cea165d5073685e8ad9d14d57a4bf80afbd917f584b282a2ec
h: 180
m: d3951cc43ffc634919a5e5a2a51580b4bd8de2b413a7fcb13d05fed3b260e483c91b8d4bb62ab1a91a9a98d96f9e139add1c2c0fcdabc7dc8266426c10529ad0790bdff648572e98296e41113754b5db7c81c2e2fee535f1c6b5ec5edb733abbe9285d37ec7bfca4d5c77cb25a29c73dc8bd5c319784ac98593d1c69e751ea87c0746b704b3b38746e03f879116470b5
p: f6a4c18aeddc4cd03dfd41b0a6f66624828b79eaee52474d9957a48fad4903facad7f04977c83860a236d716a5331ef273205b987bc4813ea7f9e797434c3bb9de419e92f890a7a447e94ebf0ca7d6f0f58237bc2747d2a9e4c367de73f8b83f1e76760305c89f316cf31753f7affae77fb46bb4c199be93f3ffb13fb4b54d1786a3dbea5f24013a4ffe7880fee8efc925180726431b0b5a7badb382f0c053f9c7c3fc8f7773b14561ceb5f2bdda819bca34d7252d70e3bc3dd190dd161497a7d087115c40b087d7df81123fc4c917b75edd3e4e08a870f6fda8d92ca03860200ba6be41f3db6a22e05ea4df77dade736e70260950965b137b61d3ca130782fd
q: 9818eb04452248796eb475c76c717202ffa62da41c97bdbb2c731f17
r: 6fbf6d05b5489e1a5a1f0d44ec33ce9f1ee7a8ca4713af186624820
s: 2c1c4dc0d6de29c859bfcd01ae1c5d6956ce3f73025d186f0ae0c3ce
x: ff7be78b86f3e387b18f8d9c7e123c847fd30497658ac91a35267e2
y: 72ee2330e84aaa034898e53426042de0bf5dfb39b0e4dcb04c3ab986ea73dc3a1cbf592dbbb443e9cab7ce81e92ca5f4aa1156af9932e434c8975e041b69c4d42b8543200140fb02ee48de817f07f185c0cf23a446237b21d733464ebad78e318d48ea1f38066e2b5a61baaa110bc2e86b7c40cb3cf9c10a712e25cd611b30462efd00482c7a27645ee46afe33dd3800a14ae35fe0595187121c03831c2e60210d811b790a73233c410c4f33fece59d0985fe50580cf77af2330d6aacbf57303f9fa597578482a9a155b20710e7955033ce5c009d4e4eae30444066f03103b839a898d82f1b276224361baee7bc0e67199ff5735eca5545dd42846929118c8b6
g: 504ea8f552cf026b84744849a8596cd4a857c371438f44a3a59d28bf060cefa7afb6f15e4c94f03ddb1d1c92e7ecdc820ae2feed6c326643b8d161a3fa863cd0c7663ff2a9c786ec4c59c689314774f8f7d09380c0f5ccd77d3716cfb96684f1e57392e1446ddd1d0374a466c2f3d91842c83446a8d41281c58b35f9168a6aa8c17477956e8a382848f2a115cf2aa4650b86905b581476db9fa4eb4c2b645d73eb64104e8122cd0295f91b5ef4ef7c04a40a6ecca251440540d9d8b2827b519edfed921ffe40b79958246f9ad68edb769046878ccbb24fcd3617b46ffef038f0d4a6cd499182dbf16314037a0c5fd760da8c39d66a0f3c0df77802e5e903910
h: 200
m: 02611fcde38062882444a5b6a5c3d113d3133f63cea4ebda150aa8e6c036770998e4a80d7608216c15bc31ca5a4a9f5c6444e492159b203b0924f78d5d5ee0b636a0eba9db3a7fcef36d799ca9b7f91d0868bfce0bd8c85c255dca3119e0c852fd95d9f489a7867e34b6ae06be414aca5201b83cdbb20e193566a4e108673a3abbb82b215c4b9fa5305d3de8f3d42be100369b4656d5586ddbfc9a79cf91d03a8077f98ccbb7d0cda9e226258d571673279ed7f9bdb08e7671224193fb8b96c8e5aab187526e438066c3da9e
p: fdeb8ea9f5881856c3742d2174bdd9b0225c3ff89cebebd636d03bceb1501123523a20c6d0a243894605debe25bb1b28c88104a4301e4b957fb206c8ab7c9b85310089b86d671289af9b5bbac84928ad9786e1ac7b64c9d25d61169593faddf89585fef62bdabf66fe233ce3bf19f4b11ceca6f40231004295d54127e62ccfe983a8815b869d7723586fdad4fe2d9e47f1d31643ba9112353caa54caaa4f747c7254d568ce854fc7b9ff7563d24be6d9ca7d0a8cb38efc2332607fdf2c4c772926a26768226b6fc9c43acddf923dc6143a7d0edc99221d5887cd4bd478308f882eb6e607f817840db2fee8201cb69cfa121c5358915a97fee79630f4d2931053
q: bc5d91937bea6cce705c9e283bc6a5ffe0ddd52c345274165a9f7141
r: 58714c636e299bae30a22ee9e52d5760b0308d70848c9ae517b045a7
s: 40e600114fc32ae6d904fbe68b857b053c453b5338221f556e1d65fd
x: 88773e09cb596d940033af59011d1333cbbb071341bb0aaa11e55fc0
y: d208e6cf810984e92c3c6c68b8e9955a9248e2820cf3ef7e9dbd4ce3f57c2607690db105361965a62d191f8a14951125a68458ce2a6440e024406a9ad92d999784831f1d484b2ea206d539847afdcb9f6daab94dd9d6fc24b8f6a04ac6d58ff58c32bd8da89a5b7590c62fad986311fa05ffc88a2daad2f2d7a4cd943cb52ec057fdbba815551d25d35b878d0ad5d9178cf226ff8e197d700089d95ee6696595365ac6d22f12ceee99ad6479ec2d5dc2e91810858829a3ac741bc814d705478be8df07b28af8df9cb0af82e691316d11ac0b74dd2a97468076225b3627e13fbc9e9550c3c340566b9541bc7e1e4eca11160323e756298762800a3dc58486cab9
g: 339004a875eb778d79f9d5fb1980d1ee584bd30a34753562b876933028660e33d953b37d546e1994028e9a1c11cbac3b7be646525147bd2db394d039335f6cbe51da8b46455e5f500fd023f62f064538916f003da9a303a00923c0072daaf2e380eb8d210ad4f6299eeda76f76b216af03e85751a3b71d2fbb48c43ba893f53128301aa645a9bc8c73b34a50dd51d1f00bbc94cc3bf8f9744ab2d85d41839f1434d2317993175b2ec9dfd2eabace4730d3f092ef16c44472d6ec8313997c496e1d9bd7694af19d2c6ffcd1f002b3c258bc8097c58aa579e934c7122d036ec483b6e3ee834a2c3942f26a2689d22f39ee95dfd330f338628824d692bcad388115
h: 180
m: 55def5907ce32bb7f5cbc126da21ba22e6e06b2397158d896d77c2e8f85117fd0ed9992a90e697eef8982a0b99d788a02d89e2d488cd3c432deea59e822dc6ecbb0c16e9e5ba65f57a92329c01a6327a64d2398cdef36fd480cf5691727ccf903336f1ef53f80c54ccf4dcb9a26c2048318c44e4987907b8ebfdbaa686a6f3edcc62b9c66d693b41858c9f0b7415762bf72f4d1652b027facb042987ce1fbef45b8283d349b5c7f237bdf036c121f5cb2bcc6d326303426dfbadb32511b4bf902860223d2f3c086b3fda72c602c0
p: d53612a532088b1cbd5a45b28d266851df5cab53d93772bda8d56ed2a59c73ef721316741962f0cd646cdf26eb7e44178b23ffdfe124e1507d6ddafbfc9008aa6a9d5a18cd6884a7f8602039133abdcce7c9c52c5ee7943bd7cba3be993a752a3c25f1358efbca30aeaac008a3705487c01417ade90d5ffd41df2c594b1b8cf9e63f7caeff8ec570c530f59dc7b209abd33652be7a1afd941dfbf0e6754626e7590cdddb690f6dfd1864147f11ceb2c510c045ec4adeb0e99896d61cfc3dfb23f792ab690cf1aebf8adae1883a2b6f8c5bc90fa76a2893a380ae5f9c4591af6f195b8b41033d7996d90b1023cd0bbc0ebcbc935e1f4094a1870ce4ce87aa0b45
q: e38e9541655742ac02e7ff65b7782af8d961507db243965b23992bff
r: d463a099b015848d385976f7083ed444aef9c50fe9a474d0579da2e4
s: 473d9b0c3f15268d76aad9d6db04ab8704fde986a9abd435a19ff8c
x: 1f59104ed4f458de451fcf5c3c07f5bd943dc857a08d5b1ce560893c
y: 8ca19846b839b81928ec711726a170bc0bd9e75a174edbbb81cd9c910baf2eb74558f1459eb0f51f721fe33d3782512879d9b4e381b73d5a1379ef92ea5c65c98e9387c856c81def9f62a12e8f26d2ef9a34f5b949e27266186750be56181a280751ecee25c6d2f7e497586faf29237cdaa61ba2a298414873bb5df50408c5cfe868adec6d7b0dae2b6cea9d7665369ddb5e44cdc948063ae1b971b11a7853ba916caa363021fafa8b32ed90c76ee4eb3060fc7727007e9162bb25b069ce811cdf08f5d16f835312b620aedeca37063b83509bae3eac7846b6ffb9cba85b9b0b5e17aa59c8b34f2c3dddbaef168af40c3566c788abe49e86936cf3b4dfccf1b4
g: 15272e452097f1b5baf2c098a98622859734bc9a04fff302f31998e1cdc52e6110257571736c00cc73088e419591d07df22c400f4c47445c9c6f9f1dc75544be90f954b5f41f513fe0898e976de3ca979d65d498766f23b835ebf7187993167ac1b47917bb3407c89359a0b61ce6621d1b7294979ba0012fa33fbd1526cd27b7f93b5782d37dead4425c7e958000391f91db665165b1a957cf78131523ec60c2fbaed799ee15b049efac0a9d448dd60530b1056811c98acb812f330c6c85e7b91bf4c51dccb12e17e4758da081e581c2d75e783ebd6985e4138c331209c346496ca30d50ea461a0cc14e699fd6d904b11d88282f1913adb227faefd9421db832
h: e0
m: 987a1d94f908dd7b03b73079a19608ea47db2b708852b32d575753ae81597b9878bb20962abc387b603530c0ee38b813c751bdc34ab136e71b8cb41c6220e3eadfc99730507c4b0267558a0aeb03028c5ee1bb37c7dcf7bd202b43a245c469d771a933cbe710545b6ab5b7aa432873b8e3ff0748aaaddb22cd24ec5a213ebcf27da754911d7d5c2b6090911e9df0f15302a6e3896b6b3221a66daf384865bf5959c5c458a0f454c84fce81b0a676447d981591ca0d81d787a6396cb37db1e0c457d124c8dabc
p: 97f2b8c4e179de1e467917790cdf90be70e08d6713de630f9a7be512571f80c467a2e64052c5378b831ef0f4d84c0294d2d68efb910ec96f55eca47654fbc3344f0a610115b3848fd3e789e7f4c131ae81a1f62ec2675aff127475942512945cf162d9ac648622c1486a4100b51c764a4026f87c525e42fe11e5dc6df05d3089524000a875fc3d1f30a68a4342c6007c9325395689a6185c53459eb131436d711d2b96ab46173b88202b4558b426993840d4529052071dab93b6a5282d5da6b05b55b51e100e1aa132d3ea05806061324b5dbea4ef1c919055ac3215d01d5fafd1b23ef226d6981b7d196a9599a3f4768f2822af8c3c08da1b551f29eebd66cf
q: c40af4728fc890581bb8c20e81b9dee3ae73a87b2ac92d02f4712d3b
r: 55dd1fd5e8e5c875da6820cf5498e6baab510b165fea36377cf56492
s: 6e6e758d94dc01f54dff552c095fb0b920bca7fd90fb7b6e7bf28b62
x: b1bd22485d2ae1ca84e80b0595e77c34f6e1f8acbb70cf9d3f8a4d69
y: 29e308b81106cd2f6d5c45a7546dafbfd31e15abe0f42814407ce9e2b5dc5f3aba5560b4eb4aaa1f3c23e08e96bab9b5f81a069168ea1311c700b2296615fedba5a99b8904744d7a251748ca6b7548c88b11492136938ba7efd4941d1a6a0159874b58bdd0c6398b68d2e90280a5758ee0cf08ab79267d18e1075ed3c0f9ab17e0667f40a830381343416be81129576f0c4ee3e53882871f610bf03705b652144e75c08d01706834e423b79bde44570d02cdfa48a7a7ef19c0e41a2cac5a2fbb3cffaa183757dc60be6d1de60e7e83600ca956558e0cdd454076a714ee595801a17ce6493a99bcdfa8734a4a48a28c6ca1470bdbe3963e2844491d2dd96134cf
g: c4ba7aa3734b6ee990be72989b62100aeabbf487b4e8315880577b5d237d93e6ad24850516ddd4068978e3bea39a0b030b1cba360473d0526c30d6b506866b27d26788d25d7ce2163510d8e2072fdce73b3b4f96218cc048d8a82da7b6d18407c1d8a2ffe25ecc654266edc14b1b7fe56c72df87d43da6dbc0e0ff3b6a5383e8c849651fececbfebdaf2b89773eaa69ab746f888e1d0a9ffdc83a72a542d084813c302e6f1ab06108650bfd06466212c341f2f98e29ed82e0a7bc615d6611f508893b6e56e0f75f3ac8f5640a41fc7aa13bdeb25e205abba403cae13e9426d6771b2d85ee104d61090fd5151db8f91079a0c280e630857e385a953e61f5d05c
h: 180
m: b0679fc527deffa88d52a23c15fde67dee871d2c026fcc864f639f76eddbabc0ad7559c1c7fb53d806911d29becccc8b7772909884c30f10dd38e8e38bca03535b5834487fdc5025f61aac5bee1f3205d553a4ade6a239cd6bfffb22931f120e43cf665d6a16cea61dca1cb8bc5f392d231c2cae946e719fa69bbb77c1c22a73414dfb9fb8af1908cf65a782a610262ba2cc4cc3b22b65cff48eebb4666866a46542956d4627a635bf3b6dc87ce2ac2547b0681d9bd8b85c8427f7f5f9d6d9e794464b3f9d45dee80aab873b72fd38ac6b490110c6d53ac8232ab1deed5997d9370d6a
p: e5a15b5e6ab4a53ee0829cfa8e6349152d9f9e324939e626edeff925d145aa1894d5f7dc2795c58678095243379c8c77e77c9aaf7f0e9b969bcfef662abab0c09e63d2ad49ae3469a0ba577ae05ff87ac070cd77e3fa9d9fcbd9b32e2e69cac2373ef33a46f1f1df285bcafc904e5018836ba08b8fd05f116c6b7f6c6f8ce295928c57ce4d42112f12e6d7056008f73b68a96e0e7de03f7a39b2adc253c467e67937345e11e6c543271ccb2c66afce6dce148a4054299441fce615e7eb8418ca97433e3624da79129895ef2f4ec615041311858a0fe24ec5b5b2807f43008bc65385d7a81e2324bff45f9689e2d0a8fcd4f85c39fcef88c995e96f31fd3efa5d
q: a10ad23351175f14f9fd8a1d905cdea273a2ec9ed782d58eada644f9
r: 411b51e54e3852643cd5bd73a75e6aab91161843438d20513d234116
s: 4bd0e160c8532cb6c0826ad62c67865ea24859aa729cbc53f30885e1
x: 916bcb0daf1df5d428ae5d5ca92e1396ca9f41109d9f24eae76a460d
y: 941eee1b52814c58f793d216774553a42f0923f9f1ff9409feeab88102e9887a8b1b362ea7f1656d2f287ac4d23723217f6a7b94357eccd5bea305ac93a4dfcd61b34514105a5d1f8799d4f5e16f9bc9fdf78b6bd62925b3734a0a79233a1694012ff15ef64880fb911b8d0d29dc3c7a47b3be433ce8f26f90317746230c0264616a71685dc6e576ed983ab18160d690febc09de8ac0065bb86b78ad702cda1ec21802a7bfeb06aeb137a53063ec9b8b51806bf4c420917b783e5a6002d2685834df7c1dc022b14ac96f710ce9fde4505cb450191c5219d9f80dd5f02f5ab4ad2816aed508036017a28a7a44940258808f8c037e8174a4b62d7f43ea79d31d9b
g: 4a76e7c3c75efbcd99e1a0a92747180499e1b0f394c3a5cd36f60b264537a86d3b7500df7f058f80da985e88de0eb32ad879d7a434b77643332c5a82712b1bec9d9803110a8352df3470efe69d72b39cd86c6dc57a002b3b4f676307091da78528b2fe01bd3284fe6c039333492a1db50344c41b54d32f5ec513a5b2110f58a32c0213088fde3a61408b9d10e6e1c0ddc60746af1f2246b6bf97b789cce63b644fb7e085e38473a439f0f4c12b80d388fc739f79a405a1e44f459616fa9eeb97801642ae2ecd1de69ebaceb92d8689eee18493c245d2e85c848a050f507874a661c2a541b09bcd612cbe8362b3f06b2ef3c38d1837fc1a10d8b6fc2cf96fcb3d
h: e0
m: 4453a61a8ff6aa9287602e0582d1b86239b7930a2129776ca02c7faafb88b41de5bbffc346b245a71f06d1c3d074210d470a8dfacc6e3fda19c1983f56d626bc46051fb1
p: 87ca958345d017ac656162bfc65ea5f6489f1b3f4cbac525ad11c4c5deb637b3d92b6b32d7902e688449346c15a91671a8204b8a8124e0ab908ce816e3f9714328db13822bc3a222654c6ecfe61ea8e72ce4d5c20da1fa1f4341b8c01a9caaad6f38ad19b35cd4d2448f67b6f58a9bf897509b92e8ee3d4e0f987a333a3a086139e4c96b61a2423658dba02ba0bfe5f9ff2baa0e2a8e1dbc99eb770a22aea7f8a0b236e2f0b7c60dd898b92a8f6cb83d9e9acd752f7b28110a3ca94df68a98ce27fd2cb2871c86f08777a8c890a2eb1081250124e3c6bceed382a5f012d43f08fed3eb886a03cab66eaafc2ccd2574e51a2f712f89fe3fff760381255db073c5
q: a64d1cf2e88b9720c2d4d71e44063512c9b3d3e213c7c219222e90ff
r: 415d3fae30fb6e150eaede5c1c0328a76dc5c2076c1fde4fa36dd6ae
s: 461030c658e6741f3c0179a2e7f5355e8bdc7400506f5d1f94fdc97e
x: 72234df44a16480c7d83ae2414ec02a6213747cac26374eee402b81b
y: 4bc23e4393fa4cbaaaf283566b60bd6893a9b50035ea540783750ea7f88f56b3228fd936abc6a8e7814ac2084dd93fb98efa18cb38ba0f8c556622f897c9a41d610a4a31a2e1eb9e29ee09b4eb013b72dfb0d905ec750ff096faa7421c824dd6f25bfa5ea8fd404205dc0bc197f6d016816ed354e009f45c2381ce48b451da65397b1249d1d58a0533f1f58ddff558f06caff43c3405487508be650af71cb9247ab622b3726f473315ef7d52aefdbfc06e09d832452b0786332e644e7b48b8905549660fddef226d9fb2a4128508048ea120758eb3a935b2c29f76c35f8a7981a691a7bcd4319beb132a8734ef194062aa141b89f959ac81e9caac6e42a33c04
g: ae31ffa170408e74029e1830b447ab092549d61fcb641e134ab2899f2bab96a1dcee67589e4da87f186db5ec4a9cad99b8ad9694880db3b78bafd8c8d7e80bc4bcd4dadf4f041ba926c5c4fabba7d3cf507905e4d7491d78a3942e832eff0ceb78ed04c4ee7fdfc20267fbb702b2bd3a82e3701f678609c8346372e7924521c1fd04b844520eb83be247f07aad95dbdff5e1fc88d0e82db1837d5b5f2bb974e0220055ee4761f6fc1ba026fe8bc659f570f29d715c99d4f648cb43461598baf05052e2511b725682ce54d8970b91ffaf4733935a186bc4c935571ee256279e55752e5f8f8cb1e89978a416248401bacefb50ad45d3ced4e8665931596d24dc00
h: 100
m: 84f66f9b0e93041cb8294ec19df4d471843f7d3aa64753f5a521b7282447497cf89dbd63e56bd12da2596956572a2a8844b8775077862d77b10a1ae0db49efe7ff0897ae4be6edcc68
p: ed8b918621d0fcb3a69f649729dd48f3cd566e4ad4eeb9af1e45c50c3601089ee03c7c7808d931c0775022bee2e1b1d4492d029963fc46a0f17ff16c67d6247d09e9bb4ebecf9bd9afd9c2dc1a5a785f6aaac68cb424e17e0a203ab942341af71ee686f5283514ced5c307fc576d97d331a9b1beda20f2aa016dfaaac85df83756126b71e5ef435b86f43d24daebad922bac5c2ffa2b56e36248fe08677921583a3b417ad6e6005cefc0d60b1e52314e6b7f43c3b0b2c898b63379449068f808d6f6b89914ba05eeaafcb6a7b3cfd207bc9682313fe705bcaa3fb34b0b0024347ed031ecf37c3f1dafa3110fd280e533d53b9bcf8e58c1d2044d8037eabf2b05
q: f6538860b2ba6189ae8c78727ab7735880d6d6dbb38179bf7a42d417
r: 20c684bf8b14bf8abb70223da60a163548efe6b5991891b1008ba9f5
s: 931caa0ebfc47fafe271154236497c1df101ec07aa43ebcf43fb112d
x: 692b6f944ef30b7446793119ae6ce0087c74524972329f38a8d9c102
y: e2b80b32769ab8bcb6ae5bced1f348586da59ef016cb9f3d97c0f1ff00592f2a73918059bf9e8adddcf0ec8a1eebf5407359868f53466205898195776d8fc72e1e288abe14fcbad4d77be80dc07618e3db24f854dbb047a1927fe5e8c5d86f338a22901cc64b0be49e6a6873a680c88d1a61cb58e649c9ea5c17adb43db1a7ac323027dad2bc447f4af5bed702a36475a37b5ffb253c8337d5b2edaf94b8353bb94b2e060fbaf5ddfdda446b7a4f476417aeeb9791125e5c6a03d0b03783db37ca4ea13e15017c491bfccb0b8ad63e42056be910f7e956fb83de338ad1f52915c9b9d496b42551d8b25a73811e387fd8e75a69d5b4b88dbcc080652b1d836f7e
g: cbc65e112646efbe130803c5bce884cfc3357a6c9fcab87e2f9b23f7798a67624f72eb47802172887aeda0187ff158c20cffe79224cd7bb4532287dacfc23c4e2d211f246775806bc9d7f68b57c63f42ebb3e3502e3cac01ddaacba5aa266edb7e0e7ca5b4ab988e4098e553fd0039dec4e131f2baa350f4d00e86dd04479128b8b67c8fca668770dbbaa12cfd0600c2295debd3ae1c81fb22ab751c8ac67029fafb5a9036e4aff9125fce9bea0480dffc4529a4eb648533060105fac230e9820523dc3a9d63d4e04251efd3fd7baf635bf9878047392763321dc21886bdf98e37d8de36625587816744f5d0d1095e656d549fc4ab872b2b944d99165901b03
h: 100
m: 671bde36b2e4798b51a308dbbc4818443f93b33a4d9d7ef5624ac76da8265d876445f40be5971d769aa747b6c84a91d50a066866cf0d37d4d93bfea6b064e10dc4557d1a3e9f9c20036752b8e8ece4ed074c162f1bc261e3b1987417e7b9583b396346769f855a37217c5675d14dbcd1136a17ca772054dd4b750b65afa129f1cd1380e31ab9abb0c35f4171549d8b79b6e6bf02cb45a1131adf4563282f08fa9370d3f582166992d97127f4738e5b95c7fe1d6837c9b6e0324395a20b5e75afe9af2d2d8c1e6931acdd1f15c3d75074d80ad7c51db2f9875252bf8f93acb67310c1
p: b8f9c2c687cdf191cab9eefcb12fb2b62af2fe301b3d680d209f65940304df8e4f983847d6c6a3cff9d15d0bb272f0007441867e6cfa276eb3979d0cb5ac34ff4707657a2422fe6fdefec32220dd96d5844aac1a26d887bef213c6eb9e91071633084fa6729efd805fd6032e7cdf72848930cc024b7553d776bc7cb3f3dc40a5a52c9c7eaa0aa6b970086411a0b806abf8e6b70380a2f23e67f38933d850006b9f00b5b43f1052aa09ae254caf867300af17a55cbcf33165b8a4bf99a1664c1f28d7e6ddf4d7bbe49ab461e9f8bbb43a8f67f0b5a12b8c44e8d11bfce988c6d61d292eae8f4322efbd155fca0e6f2ff86c0d2057ea0bec74d1d662c7cc812cbf
q: c32a07738f02b5182756e499e92cbfbe60defb24dee0c3cf7f9957e5
r: 9111f2967744bbeae703cc72a0b55f510b6b0b6f55daecb9fdb842a7
s: 5f44a2c44731d74f071af8742066a8f939a2e66d71ad0d2dd69b286b
x: 1b83d4f87b4b8e9233160335d75fab21d94b17c68bc7d61e3f068d1b
y: 804e1b31320c3fbe85a4e05caf9a897fa4ef181eb34d39b539d0d60d9c0796afc294cac9ad0c0611efa23494203ce91c5f2dfd78051cfe8a7fe56fb308c87962e50edadc136c69e647772c392dd6879b5af0c264edd38f404e83fc4498bcbce8f2976cde07cbc17ec0424300d54e18f65b07c080152113d13f1d8d77f9e11296ed83db360cc98e4f594832fe917c00fb3c0b5c577278b78f0dc064a62f9b37ae2ff28f684329eeae1305973958f289498d709336c342c053d6c530090324ecece392c56bf2a36a2473664f8e04ea3a79e6981b07e1eb216eb668232ac4c63f9438ef1cc56e223da404c3ef455bf7d3abf49425c4271651ee04a77907c3821a6c
g: 580e939dcf92f407c347248a7a3bda3004e3c0369b879d421554497a3931108e4376c1dad48f765c916caedecd3ed3253a873feff693dca935d0b6b6d3d89b7a8a47d3796df47eb0d605ded12c53f091632af90abc0311d02695c2512c835326a4288033e7f154c529c1fefc8b8b3e6505cc5d5a5f869a4969b84f79b5d33e5ed8b19a2397e93029c68ecc88e3df749164ce9a58fc00cccabee339d59bc8c0397661a944e189b9e07841819ce17289527fa7b936879fbe1aca66567aab57795dd0dd5cbd6c79245697b6ed708f11c936aba54fde376561887055fa6c2d8fa63240d3952aee977b1c1eca498d8cf90721775d8f47d7f709c0d77c8b011f9663cf
h: e0
m: 3f0f120fe78ad61b138c1119e45b0ccf40ec67b1b943fd416411de4e390a1cbab1aafb8f6dac0cf526ae998452644c42280ddb1e6b0dd888a2c6e263fcfc589dd236930ac546c01d7cef15e1e0f56cf2e2f317fb488eeaddaa88ac1c43ac8c31a97b4882349ea1d3b2a74c4c3e6540d1752c717a2204ac2adddd4fe7964745756ed005ae79cbb3f19635b8eee4a02ab2ac6e19c55e8c70b023235454a706a088c25b
p: fc93d66c9faa51c0fef6d2d87d6a8bcfdf812dfe0daa991b9363cb08685c5117c5e6395e26eb667ff61e140234cb2c15be5d197d8fab9d222906635069c85c2d233572661de0c2a949b45b1af76c1a7d8015294f1d45ae304d9a83e3c995387012e9f4bc633767549f29eb0b01db6416cf446fb17b053ab780ec32a28843405261edb7237ddbff9d27980034a24ba6a1fd8c901267d10fdac5ae774a8dc6f742f11a89103c0f968950d420d0abfaaf870835d5034681317fb2391f4731b4b93d4a62c99ad50204892b383781ffe384e90e01ff397c9c281a35cab3c2e28961b81b82e881a97f0cac0d52ee03d705a85a1e69f239d4219382e69d4337889cfdbd
q: cd82a9dd219cfe4f2346007c8e946d812eb389096a4b6109b39c9edd
r: 6799da04e5af4a6858caeb02948a2b64139a3dacd05fa52424762e73
s: 12fe5ce14fee24f674557bf80cf5be3e67ce3f608cf8688bcba2b565
x: 68845ee5952857b002457ce33dd9e110ccc0cdb27fdd9b92d177f3fb
y: a023e46ae9c2f48841bc1fc291550eaf5106be36e71d32ccd2e9a79107afc37a6bb618414f1209cba4a4628d40cbd1f9acc343511dfc1d5c87f3ecb5846b52b2ccc258b6f17132d02d99bcf5f482a484816237af11c14bbef96309ebc2489a57d0605fe7c59a17c9199b4f7e4d1f4bd40f444ed6828ac430179c7a1b5223d60d0bf7e5fe4b2e5700c605d1c18210e141d905981afc99ac5e2666ae1f35f8e9cd4644f13022957cd51cbb034444fe7331198092c9f3823a9851c129204d4eb276dfcbec04f1f594148f99047410336ee2d0869a3b25d76f718ed7eac49a6867a5a61f6da53ea2e285224c175c7f79e2a05ca6f6d5510365fbf46fb02aaa5f915c
g: 80c3d369e4d92d39427d683779bb60c969e2d64ad25e36c584a770d00d8c51e44a544219756d27b8e2965bb382231d1345bf93dcfc517442027115983e67034a2bbde12a4c043305cdcf6d85157f30af655564f21322a8aa5e92b9afa05d0241dffbcc357bd2b1bd96307d973c27c2e4f097425eefdd699451d0dd73dbe793fb9396396973e4283d89a1ed34337a6d755cdcf470c42a6570fdb3f1ec495dd8bff14d4346df57b035ac02dfce79b8d8c0bb43adf679a324b64be938a6d44eb0d1cdc48aa2b829db5a82591acfae6412ff5d74b3ae44dd015a1196afcf0fc42f76307b72015bfcb1ddae1f2021a663bd6016b15518db5e1470a06001330a278590
h: e0
m: 41e82ec0969d77b4551a0fc983029d5c71d5baf115698d318c724e35f20670502589f5d082031cd28d452bd35b087f9828b0e00408f50ed72a530140ff522e0e6d154825eb3fd27987308c57d7d248462068b58ff70a2ae73fefc68b581892119b9007f01fcc84479e1a30066d4ad183cce683113e320a9bfd2372ebe625e33392f03c408a64f680efb3dc75a609a658d0f9794afea4d1844869a176af56fe7eafd6432b048c85778800fe18861402e29171d72914cc04ef4360b575fde8372203840e503fcddbdd2a0e11091ac0ce6d33c69ac7c4300cace45369edc10ea7c4e5bba832ec3f22dd7cc20331aa90ad7bf9797684ebef8424adb9
p: 8e99d53925eba8d0a9eed1863786bbd55c56a25622a0cc42db73357b2e4139d869c1706cd3276be64109bddb36ce4e4952340618a492e74d296c8a516b79bd526cd4f81a1fd6d58f13741ed80d1912ecf1ffda6f5fa674d4742ce2d11088a0e960e544c45c64c3f9253d985b0781b5536ffc9a7b1b8b1c97ba4d013074b016d39d5f958ea676faa8f2f3662f905677a17f3ab8ac85103217e843dcbc6c9d783f60765559ce806d9cd17eea7af87737d5a3f14e196408e109d7f25048ea3ea50ca03aba28049044ad056f2c1d4967cda53e755811fcb92df97259d1c3b02aca43df6ba6c475c8dc990df47f548be4d6f4c8eb5a20677b7731d37fdc65a1358305
q: d5aea02e6516c9dc4fa96787184fd0971142e2889c6a9fe11b9473ab
r: c9ee9f5c836adfc6995f8ae3070259ba6041b90a748fdfb7237d3b71
s: ae0131c9da6076318ed2ffa19775cf4fcaa351093af5c933cfba62e2
x: ccd9e373eae9ef4262bc4eec6f6c6be7086f3c62a524addb0051d760
y: 6d77b0297298c9e406ba4ed8656f3a62c2eef2a2880a430a23a80f03278f583a3114acafe263d63040d6dda8fb4ea99e258f3e6177aa3e059cb7ce2dce1a3cf6b96cc0eea09bbcf8a43e58739a4e6b69018d688c9427105a47d61b942cf3401442f43c3af60613f15ebb83078b17d6eb416e16ff80683340a269842fa4a289010a323868555026da7ec942e93a65dfccc02367fb9ff459e01b11a8b21816cfdfcad4e7b46a4a5e61dc8016703ed79672d897f8b1008aafde3fc4606ec6a0c4e232b2a358fd13ee08070fcdddcb3df4ce4b0c62789c5e211cb80a132665726304c06f76b009b08c9c9ef27ddfc314ddf7bf94497423df27fe852b0fc6bb49c671
g: 9c46da3373dc0e312399ebc0bec8ff437095b842cbb90cd5677613a98231aed6c0fcc66fc099cdcb42dbbc02962006ed02e2ae5e114373b0495c4446c2d51c337deee3a2c69121393be729958d5736ea0ace4aa37cb6fe8a4f8fe60368474d106a4245db7214ba82f4f3f5baefb7eac756ea6d20900d59499337d61d96d6de282e2b7e33b415da0e04317c42a9f27cca7f4d48b1584aa4cf6a3d69ecddb30ca4b0715e15cb69c83ccbcb1ad07b1f8be9c85b7638fe61c2b3ddeaa94ee59948abef693a49e45803439c9992b9c7be8f64f603b2ffc5d0c0680d217c49a5ce95e389ad4709ba921da9d20b1399a8a6880f2079bec9aa52450eef91455a35f5eae6
h: 200
m: beae243894a828b390e6679591b41879023f251ef94bc1be1f4b20220b90815dcf0f22add75f82e49c68056861aa054f81ac0e501389dcf0c0c721cd9906da87969b8c8efee1aa096df14b85934fb3
p: cfd184e5dd54345dd05b2da2defe6b70ce466dd82f7f8c6e0131d9d7cf08500dec0ecbaf76b542a6fda53ac2b35995ef1c15a07a568229ac459a99dce47df6f183103298458e5f771f5eacab8c7323847f38ec93dbf190ee3a871835558ec4da231fe8cbd919bd0314d131544bb015726cb436e9e231ce87df4aef465788a44fe09f579c012e17b4d9b828fa76e3ed9b125049c6d2d86da7d6b1c4683c2a6c7ccd377f57c1c7ba88d763973ed6f6cf67a1c23950e849318b461b10d2b3745f8f42030332703f3ad909ce772a35224bae4db506b87d79be37d69a27c8a2fd128c1291d0db9aec755aeabbe8e6c66046408ef576d5638a5dca8d7962a74825ee87
q: e99ac871cf8cef61c9e7597062183b67e4d76089c8e1f41d189b0ff1
r: 7d5511d9442b3f229b1b5d3febd517971b941ea3801f04b800b5a67a
s: cf7d37e2ef2f69012338bc79413662a7b3d274bc661aff9d15d15cd2
x: 2a98f662c3e1a928507aff57edcfe762310601b15e2e6d6ba98daac7
y: 2548dbcb4dc02af44133b7b6dfd32cf20ad4ccb8ef934299c1a44822a12704e61eb383eb69050738b4188bd0e9c14f2fc15a22510d7f8758b1a13357ca67c71a1bc983458a468dede04cf2ffb3981b5c94ff227ba75c94eec70ec657ad8c55bc37aa5b894996cc7f04d27f3b0d324e5da54c55a73b63f79550532cc7ac9fc77e2520999b8d8b78de0b373038aa6701e447d620142af2459a7b03a49babf1d39fe62c370d0191593d1d5ee56bfae700c2a31d7a353088d589971b8440ae6b41ba1d4a129fabefe745aae22892c5f1d01696b245a62082b81fac6228ffb0d96f8816c759c4f4dde3ef9317d22a3d0e75fad4d55caf57cb749d6809362f8a4eb5c4
g: 453e4da5f146e3b4a7ac12dcde333ce1dfcd28493979e654616e7acf1e41f3f36bba455a4a7ce014a036924f29b31de48597ec10529aed74487c9d797c0313e4ce6517800b8b2ed61ad9ed872c6b118d1a0fdf69c2176851a2476099360954dc781bddefbeebfcf78b84ef2b854a3d6a8ed94a873316798e142d2caaefdf1e713bce3520e0e58049bc9b9c13f3437cf91c3194b916944af697c6171ca10ac9d5a944f04e2a7eae3227217e87654b58cbffd403c9dca937693e657a0791989ef9631a4d9578388fcc34b4ee465ba21bf657203b49f66f72c556eec15bb2b339c3938f8f83aacdc62ce3f63623044bdd74589b2dc81d5f4e0d75e00edfcbf543a0
h: 100
m: 171ef5556865fed87dd6c0c2ebf8ab0499bb499bdd98ac7ef7e733c42ea01f25e3119cd4d0124384c0a1ab9ec4783582d63858b4b1048b2ba1a724089dbb68765ca030161c00f629dfc084ae8756a66a75ece0503e182ff00485f81a63952db86521b77a49101b016905b172d6c64e2677d8054e0ec232693fe0a2829420063690873034224eb44a0178ad5a3e4f21e3996d5141d1c28bfe4bdf5e90f64994f01e196cafd8eb79cd597eb1bd1c11ce53d6014710e983563952d93e448989955c0bf7ccaa9d57da6c7393a4843a0942a418c00725141b4d2d92e89dbba1ed426c3508fd775687b985bac540
p: b5ed35893934cd2fcf4828d13a23adafa3006a3e8f7cba9e9dd833729c4296e130ba3b96c10a98fd7c1208f626f836ee2efc3e01467d5932a26b7ef5912ab39ab956e48152254e827cfc30000753a9e4724bb62b8999b1c5c1a341a0d9227b8a091b7d65d9f07faab94a0b4b002109608b9c78550b33c06ddac21071c72a67b09a970d250f51b89452aa790cb76dc7a55147c8d6554d190f73020e964afeb44bef366c94c58fc9c62f0468ac06a059846b0038747153ba6cb5c93037ac4b18de245af1ea2f258df715638274dbee44bb040f7cb956f95ce3da0bf76d577af48296f778ebe086bc9909dc1b1658712c869100fd25bf3674c8697d07b6a32806a5
q: bdadeb9ed976bc0cce7ca75a318b5016a85e26e67c1aa2e4376de135
r: 9b9cab35494eae7156806bbe74462f8e61535f735198f74a078a4ba9
s: 2299f3fadec636bce903889db7afd928b5a1b5aaf95afc7cab2ba29a
x: 751a207b265d06858e2d63fd18ab370c0a7c4a546d94c90168e49519
y: 5d810eceaf1f9e1813141107e073936efbea24d50bc9b755f01d026f61b5e8cf8be23a62b48551343253420c1f59db42c5c129d2c64b4b1c39eaaba9f9d2cab6ac3e99ee3ea6398c012b8ee1c971bc2f0f264724cb7bef744302f24e42f9cdcc39ebf2d27dde742217c4e8ceccb91930be7bac5964939b42ee68ce9dfeaa548f3b24ff0381c0996745beafc49f08e9c04e2f9ae261d2505d6e1e29de05bd7390fe52c64c36b36b174ced54d9fc77e2f7ba122480c92d8295c4054116cbc7ba3d5e1439399dea5433f14d9d5bf6de275e4e6720bab7914bdef4f36996ee44fa5039e21691e843153e5430799ced0fa3ed65c857e33fe14d611a0b8792a5818f3e
g: a738ea71b71fb6598aa9dd1c5104be3f98a01ea15d0044d16042e2b7cf84816569a4c48fb01a5df6c62ae26e0705b98ce5f64745d4356bd27dc335f07c00304ca08804ed04294771296f3fbb55a8a09b6716e2908385bd0faf9c572107c2080cd59d7d49609412db47757072775b2434de14b516c14d5cd8a91b8f500f5d1287365e9fec0b92678cd43cd97f6eb3344a2600c1ec4710c4d320fd8a52811ebcd35495172c184627153dba8dee136775f945d68ec2e650940cdaf3dd58dd1bfd67e7079b7b5cf02f3df3e21943ce4828b03488f3a436e0d487c87ceaa2ebb08bdd9a15005c4b4953e88caa3a669731dd0df4f13dd243a6c1ce2c891790a5fc33f3
h: 180
m: db754c5e29cd56d09d53bb8686ee
p: ba2df3cf83588c1d78cde00c50968a4b296f234929c18b00c64ec69e5552cd97ff2af464d2af6279cc6d8904edcfe4966a77f0e2554e60772e841bc69d4bf974e87c99e7bed40f1ea7b428ff3b3e9b07f1166df60a43513233c20d1ee7e76ff277a9fc72a0ddddc667ecaf98e1c0d5c323dc8703e4fd35b872e42d87679979785958c30af350c09549d7b98771e78f7a76f26652f00234f88391b52d4ef6a82b53c660ef074609f7aec8f90f4b60a4e333f5b9112cec3304d0e7eb829e2f797e0c2b6ca71d5ad162d53a3ba43d9ffb88b29f9d2f4bd2a8b5ae4345f28fa6ff384183d104b08851870b4007b6afe62c277c01a1d3ac3af65c9ed9730c19346ef1
q: a5fc20c1300b2e62e3707225145a87da26b33de73ac86c3d77d797e9
r: 2e32cfbe4943be369917cc83912641992716b5b46708e6631b71a5a7
s: 6d920908ec2ad831e7a5d6981d27c09c2b6c67a4aed42387557a1cea
x: 6c33715a34bce82fb7fe7a0c00c121d606519b9897f97399dab7a253
y: 86a4bb45980a1b8a8da6bdbfcb0d7195827d1b2acb3dc6b5c3815895c81a124d17f1edbded256515e0c259db4e3fe10bd942ac15f5a6d186edcbcefc1718181781e0a9117367fa370b699fb0902799e9e79e8a57114f8839816aa976705562a407065fb2889d1f3c8a820e90fbe94f533b19c4f0be356e0baada311940d5504c42e8793af2aba43a14affe5d2fc5e745489ba8a48c1a720f70364d59eb969b4d3009320214b6f691d275d9ad33aec25dbdd6db4f4a0f8ad15e016f5b0809937ce1b0f4409708ccbed0461aa3a0fe7804e3fec9450a60423480af158e9f03a0f89d359c9649d9ebc65e405f670390188fa41fb1f2717627fae0cd4c0454fbe963
g: 86bce785ee3960759ba5a21517cd9f9a8d80ade9ca433927ed7bac05d9d93e6492cc7a9cdf8ffa539c9f3bed7be29b3b9ece6956682265a6c76e5df78486d510a804737b4285fb99fa16de20afba6a35d6605a1ea94dcedcb4230cf42c617e55d4746538745d4484a4dd41167cead25b91c9be6d6eb13e4e10cec30e4177f1fddb96fb62eedf3d66ecb2871a91242bd7c59b3137e1173399cb4fd5f42a5ebbca0bb0f595ed28f8ff4e125d3c1159ef4fbfdf6a3a7603860a28c499ad53b9073c4b30c8b671c7337cc77e3a982728949a9951edbe56162f9a1fd4c6504b64fb94b8f48440c47e8da5f61831bd1e8a3ca42cb4aacaa4b3395ccb5ae57b6d4071d4
h: 100
m: 05b6b23ab73d35c686c61684fa67ef8508ae441bc87ddb1a795a5047e0d4
p: c7733d50aeaf27ba860c4b3520a121337484a7af361d1d2575715c8e86168ceae5a445f82b98e4c6bb124795a2663a27d0b45ce3b3c3259cdc445b60c80b714ca5c548a0b3706c9a509ce8448e60c93b9789baf862ab826d892e74a3c07bfcfe5d24d0d55a2b08949e6e66560dfefaf18d4fcbb9fffba5435c46f2df719c7c9f5b0707eafa3c291cb06c7f8bec7a3eebe726a3e8e7b888ab27711be5202a179cd754e6e7baebba9b261ec95657762f9a3d68077be7bb448a4d2b98e80741273f107a7310fcdd5ac739098566e1c9bbd817f59948651234038a1b83743d95d52af1a1491b7d3003e5269370d26258cb656f5f195899e945aed684fceb03327a25
q: 98a603faa78c4298c2eebc636c4b98af2f842be6e6d34a10d3c7d24b
r: 6184147c3d5d60681e15cea03235af9561641afee5dfde0407225cfb
s: 7fe7d07aa35a9542f482f8c2c48aa5935ae13dbc21c967a47a8af792
x: 93f4d5234803ed56b01b8b37e0950edf81061990dae6b75a11f6906f
y: 81bb903f97b689b28fad927f5ec8a79cd6cbde1d7074cccf94d68b01cb153204cc23fac59a5eb639c7a4d690c78cebdd9948122ff108ac0645020a19f16388920906e00561f5a010a1a1a5bcdc2cb6697cd91fb14f3fec0249cefee1d07e1ef51fc0a54ebc552b5622cf031fca16acdf57fe0dbbd48d7324a8c852056f48bfbe7f9aec3ae49166314016ae01c28db6ea4ca8071c98cf74fc74c2418cffe9b0d644b4d4690dbc417c84cdb0fb6b6d9d48d2aa0ce3cf08efe7ea2508e9901af0bccd133a3e3ae793296e94d88c4270e32633a8326cdb5961bf6ae2cb7cabf202b649003ef48a172042c8bafa639fd3af79ff14ecf093a3351f2977b5ebb12cf735
g: 2e442eeb1cd2cf6e70de7b47378ea1ad08b4c59fb394a4df17147585198032839225757d981712cfa0c4711a6af7b0ac7146e0072d9d1e4828e64f1b0ce9222fc3cdb21847dbee96a0b2d033246f93ef02950d8b24d2f9a31ef9c097d9fd7cc889accfdaf962f690afb26abef329b22c5dc7dc44c3dd35a1d157bf17b19e4d4857deaa379bcb7b7b394b8bcc1a92b8e96cba5fe9fd54ac69e074e992926e22de28725f7d3508b582aaa73cf62a69a7b5db6e67aed4f60f81fee5ae4bc544319a6b8f2e027c73668b0ecb574a3dc12de1ea499116385d0fc9dc4feda09ffbf8e93aa34c4915e3b8d6eef0c49711d9729d1cb54e4f6bdf8a44d8183c9af027a7a9
h: 180
m: a3000550
p: b4be8c422fcf2f7738b8d7172ba21905b197dee42f8a2381e55409e93dbf091df3105ece90142e429598dfc8d73c485134c823ea2a665f53d36c5cd3791a7e9210a7eb1b768a78ea82e8d01185a75aaae32d1da61b6baf02969c8a43aa858fb67fc2f797dbd3e9f8b2d24b2f04c414b68c5cdd09e486b2f50fe8d4c93dd54ab8ab9bbf421e8b6aa139eb44fc807be228d2d7dde05bded318b80798b30dc97b1fc2ce68529ca9f8c4487bc0b47618899a59d4563c982de39a66c56b1340f49ad1adfec12199447e3e9e898e2f7c2f48c79d68cd59628b188e3b479a225ce6bc291eedd49efecd117a6830d951acd01b80dece07c056a7ea23ac687fba947e3bd9
q: a7299d55f43412914a78c2d8ffe7b299140a9f4417d9fb82d672b303
r: 7dd5fd7c2c4fab27936da13753844a46f7ce20e0923966712dbbca76
s: 8385958eed65f9613093c06fae1adba4dc9efb6e504baa371360a7b5
x: 4eedc9b1a84e2e7a562155d02fdc7b4f740b8e1cf7c7700256cdc2a4
y: 5958dc9f8ab723d4155c92ffa6a6d088d9b63d8e8837d57d808b9e1f8af350c941a29584c017e92758081fdaadd827e3bf203e325ff35e131ebc0aac492319c2583876b0a93693a012948c896c6d45dddc98a9b39f07b03b4e84c0408e1d5b497890017bf006dfd0d1fd7c0f186db30eb3f58079402c07402a89cc4acb15a2133bb11266a611b1cc3f8e29b02a67d31040da95d7d44b99e2605f471a96a82a721995567cd8337b4ccbd1b5ca688a6b1fa19da8dfa1e5d93d872ffa9c72048d663a17b8290119f1e3e270076f46ca05d55e4d2585f46b69cd6e7b96979bdf6e4f8776857f00c7adf4ab461ed062e4f7711f8c3c14133048c15e9aa15c8a9801c4
g: 3985beaabbc161d212d760d9c6a15a26755ac67b03671837937ecf649bdd61c181cde403f04d81e6e620b88709c767c6726aab332019c16a7d70b81efabd4b1fba145032fc4469aa77e41d3b3b983cdf1f4b05a1da0049102608daf29747270be366a6cde0061ecd978d554c2d77cc621bf5409eb965d48b745a1233afa046ea6b4cf4a0579ea1e9157c8248f3cacbf1ff09428476f9455f972c530b26515d2fa8fd62116467307bb304b83299e8c8606c1884f269fa54117f22097fd17aca12fde520751809bfa0fb5d7024025286c395a9f80230a5383fdbb0df2406f48b26de8837c6b51062ef0bc48e58a577a0982b0256f4ef1a4eb9d58eb5cd2065d7c0
h: 100
m: 71af351e12bfafaf688e721a5765530addf9f922e29e381a8ce2f6f6b607344c8203da7a5113827ec1a13ca683bd0987bf1c5167c5900b0c75a25efa2d345c41ac71feeac9
p: e9726b8fcbf273459e2b90864181d9ad1a2c9b3e11eb91c1bce070abb443d967dea05dc14ecc5963f8a51d9d58ced158ace32b64df2e5b37025efbee254097974ffc9ba806b88c1adcddd674f154489bc18338e76e65f351c1c6a515a26e3f1e35b2d5f0f4df0c6eb9855ca4816cdfec779fe4f4c4aeb313c70e5c480f38d9bf11bb742e90f07d86d89623798c4e39161e5350a9bc598125855bc707e1be3019bfc2fbee3ba6fcad5f934af34a996d3fc9201819f63ce521851d63b53daca4941801a6aaf7b07b25316b7e100e8e85fe13482b167bbb4022fd4cf625e2e586b70c51712159da85f4810c29ffc5f01a1206118d80bbb8ac14e21b8ec603e8d133
q: e3190e6a620e4d90764ee55ee395475ed0850ce40a35681df7c2d99f
r: 2d4f4f8d65e2309dec3d45a2958f161ef072ae323d9492d42c993ad2
s: ba64abe1beebf7bd3f97535a1df8479d5b0715d21f5674b2c41b8e03
x: ccd9bceee702432a7087d98249ebb29c6f4c6a8d560aa9e02ddc7f74
y: 61a73ae04dc5d6a97a60ee3077cb2f9ab1d1f3a89c575cdede58f555bb0b2a0e77a7b610fca07134c0ce79738d832bba5b0262932d6261fc9a2efa1db38f5c4300535a2d7fb05bd9cfedf3a101448881252b0098607d1165a1bbb935327ad31926205794d899d75492ea647cc1e6c8657242c06c71b1f22f027a9024e4da7ae4e8e9aa0a3cd52fd17a510494f4eda9efe1efb946d0744a89e23af552a1d554f15bfc1170f54f4a0ec28e5558c6e023d56a18fc9c8c5606d209034d1d6a5215acb2fbb42663b6c3520ef6ee7c19ca15185ec1edf793b73138c72cc46e712c90ac69931036f98c3fdeab7a3cd0103152023f66fdd26fd7ff2f9a5c9b5c82a3d6c6
g: 8e080f1ae44415033b353a103295ce461780b585ac73b4dd2c228e4ef394dbe8938cb4904e02ad6c80bf8b0df54a41173d64dee46869794757d0d5f537e93551add5116913e6ec75707557bacc6201735ca3e00d45fdf0557567eecd2c33b8ee0c16c9dd84b676c1f3dc30d0651971d9ded004ae6fa8bcb72928e28d04411d39c2553b9546bae92b9d2592baa7a809b061a3611e6ebe9491a09c8fc90817e6950741cad75e4ce359e6fa915059c9522b32e074a514cdeb565352aeb1c285a1cc43a703666410bc80cf76dc8099c8062892f0d9f91c90ad3efa296e4687fb0930be898cf9e62ac8227bcdfb08065571c7c71d301420554e5e357f6c5aaee371a
h: e0
m: 9fa8b6ad550f06912ec512cbf5fe6bf473e003aa3f91097feafbc89376a0b046d5a9a4da9e25fa193624197e97ed3124d3c454e4388853cf29011406e4b6d0a14cf334d0284c31111e0c5b4eb332237046a2cdc015e6a9671779c863ccee9040550847d7e7e67254fc2cdd8dade17bee877b137423131f4903abdc33f5a28c2e673f5100d4a9e75164d1c37fb9c99642
p: a9f1ebd3e3a97e9b365540ce652f0e1a7a04fbd67b59f30910dc868bb40aafdd6e670af8605be846e8135981d664449439b29408e825a9b92e35ca9280af46f40836b7ca4916c1dfecc599fc9fb99d9decf63b2e7fd19ef426702664a73c2bcdfc2a2ff02c5664aa9ebfc82f45f2dc2a0230051818c47eb1a36823686d824a94480d230369c8e9c65fc6a18d4956681af965f0f5ad86aca76b13aa83415753adf07da0fd147a49d444abd51e49d563ac40c94733aa02909c9a8de20aaa521e6be57c25766218b247b3a80379a3fdc4367514f437b56a490893b09082c36756953d718aa4ba7e35e72f89bdcce2726a30f31277f4d097527266ab5db08c1251fb
q: c48115bc09a3c4a8656517b942e2965b70ca315ae52397d8b631bb6f
r: 3fdb43f93dd63ab44e9e2d05a82f9230781aa20f21f5febf377a6151
s: 5b610f346fb2858f51386077fd9ad24dcc97efaac565b5a109bc54d6
x: 4ff49038bc04dcfd7ed381aa3905c6497f6161ad161c0dee57687790
y: 4af63ecd7d0956363d84acd2042a6bc348d4400bf9b8035618d27342a6807642151804d4ea382e192ba6182b41003642a5fee22ae6d00a7eb00a62f9e6c97b2da2df1bca7656a5812ab6e4f9fd172c626b7f8be565216f280441c0fc4daa25c4b30f7c8d8ac72ee7c4689d33298d06d4f1e61eef0b0c8599afdf813dd2e92abd846151509be395a767fd91f0e29364b9d3b1dc29e3dbd67b67e8e30837db7913ffc50a7aa8d9e786859d5c63afd1ddc744fffff558cde6bd98ad53212d40b13e1abaec215109abe68f77345338d0383aab9151567189b6ca08f6d5cfbf2e41016738081c9aa191b9fb482ed8eb405e8514beac41d5575af2260743f69860503
g: 23dc7e43338398db09937cf312f027a9e7739e2e743efb0fe327af438e23360ca00374222b530e9a9f1055606a2798e7801e0dfcf9ed6abda9b8bb9f59e22dc0f8b42d029a4867656bbf6c0dd506a49c732f55c34b1b115fbd56ba5ef57c21704a951efdf2d439d9570c1c63a192045e0fee974fa84763df07b662c26a9df5171b43283cbeaef0bbba4310c4f10dc1e7ab50933a2689823c10309239a86fbd8cc10da93feae18f511cb378dfea68ba9b18d9619081a5372433d9c02a6881c8e4af78294233c3351886cc9216cb46a9dfde0b5fe223f98f790beb09b8b4ea9df0cc6581c6bb674b52120b1d081c766c7d2337ecc40fd404759c527282cf32a51f
h: 180
m: 5c63c596f629d155b601501bead8919761081a3e1021b17e5e3f0d0414d2eb36f23f510f7ef4e9fca9ba90ed4b0eb35b26f58f9bc889119a7bb7b1bad834e404f5f0735a0bcee9a5ffd71212b729a67983363ec23c5154a4becf70bbbc6e0f8bb91c9c98df5472a7f4fa208753d6aa603eb51715d44744e177e0d65b0cea1e5cb29b2ee2b65903ff
p: c3c5ec55bdd1a0e940df1eb748b0129c628b57a6eb492f270ac8ca7531b7add68da08c5ac949de68c6093f376c4536ad38f5f84bbf09b066d327b9c0c8ed58ed9f8be9d80b8ad01650e09f2177cde2e5c76f300e017902b6d989a46b9759defa2f6f0468b0a31856049e32b1eb1f86c45d69587ff2c5b2fa1a0fe3c8d81cf9353817a74feb6c3752d0dde08e1689ee8e7870a9b7afa7826518017269021bfeaa48f9ee4a401d277f2a82dbf237f7f99a1e44d707b953ab56ea8b063e790e153cb69d2fb4c4f54922848d9e34fb5ea8e25434aac3ea037fa1ad1de17107f9f8ba9c059c86748907ba0a670def841df2ec4bbece9671933d8e2062dcfc67023c3b
q: f59d7b37fd04e2f3f0ed5fa43336dd951f2e3cf4b1287fc681c8aced
r: 7c1140bbf1b2aa6a9d8afcc8a0e7babb99e7f3b61c55c1ff9e634e2e
s: 4b68b54db6b0d6f912c0d5791177bb687bef89ac2c0c492301b87934
x: bf2526af70bc55f0cdd4c5c5617bdedb4f44fc56ca6f2604dd080537
y: b392c76b3ae14a2caa6af7553007a57ac21ef60c44797ac1c13ef68904df8b072cb32d0dbe10b2524243cdcabfb8e19ab31e82d693706f953bf29453325993b7278c7e99c09a666760b1ce5dbe36b56cc8c80a0e85a972f4c0076bcc0d349d3c17ee4b7d0e8257eb5aba5a4375929a0b4f4edc350f268c164e6eb204847bf24d23aa072c6596b2022fb48773f8538e3f85aa433e88330b302848a6ebf8f0afac665c98bb7b58ff11753babae22e0974f257bf4b6d00b87cff9e978a65a86cccd593f4c3d42b78142009ac8bf077f69b38a4eeef9c2d425406d06127135e6f5811e4f22f6da9dfd18e24cf8e589c7cc3591dd995e5eef7b07e38b3c99ae7bab9b
g: bbe02d890fd97e0b6b84d07e2e6a849378e01a3d2f78dd32b4cf0b80b51af9565048bf7c1e55512c46e41fb4f52623b95dae011567451235db9e216f6eae605951b19f932cbe98784e5a1b5c74b8efb554de8d155e07aecdecdb6e2a29c8a67700b70a941809e0e84053ee10464f947225040dc3e4294277af421e664ec90ee63779edba49f71ebb3aa40ddb1138bbf869c93bb135b5399b72b18f6c8127b114f80f1d331004718d53d3c959b927c5e8b50e54b48b78353ca2835032c10eab92930475d2b2cf7dc3b0f903935a6ae1dcce248df90ac993b7674b3847319deceb1e13edbeb32c4d126bc62c95d942a9227bb3b1c5fa7323c86d83499644908ec3
h: 180
m: c30aad0e2009b9dae759b38e15f48dbb960264b6d3836c7b28d1f31a84bc9416c9001e5e8f2dc6c5974141af76ed35c1e23bb852faaba5d4319c695d1beef19eb151279cd1d2b3ced4a9a6c921c044d4e4fcc31a168c557b13a8aeab47906da64e6dd3e80126690fc5633dd295c71e6208a096d8ffba2e0a5aa84078df1b0c639cf450aa02dde48fea0ba367d82764a248f4608bc8a2c9301ef3721d7f81b84b19cf11d4aa386254cc061ded39e180a7a3fbdd722b3c3d02ba1a5e682b68c34ae2c122477ca9d65b91530e94374538d824429bc1bce58f8bbf744403359abb96704d61cccb
p: fe8dee38db57a3da152612c5e8ada96f1a39ad0788a40cd2f72c338d37a04fd4698b4481e5040853d525c54810462deadcb9b9f11887124fe23de852aec93c36310e22b5ddc05bc0d713dd48f76e51bdc7606d764aa5e9d2413c894083452ddc395893ad576c018d17256c504251674231b045f818becbfa353ec82ebf7c88cc611e0c5998967ea2823eb3c14bcfc2eb642f40d390301ffc136fa30f79384064430ebbf437af76e8a1510f75b1e11490c5a4763a0bc10b73b61a21682266c2808c5d644a77ee9fe86dc450c41bb641eb3ec0f79ac9440d808b9abe69820fa7f4864b51d3c8b94041f37842abcc0cab94d24e84cc42a7f387c7dd9a2ac7e0ab11
q: afbcd117bc0e36ff2af98973b0d3b04ba4f9a3564bc7df9070c53b2b
r: 1aafdbdbfcd3e4264f01ff233fe2d5dc15b9ec922168e41eab6c6cf1
s: 9de80ab7cd1c95764ff830afbe573dce6768d82e67b76dae3229e1ae
x: 5beb69e84cafc3d551c6bde8fc4d41d535f486ff6ccbc16c0f33ff12
y: ae80b2d7788ef56f55fb81c67c1450a8d8d45ed8aa2b189efaaa6c7110f588f43710281bdd962ae523de629635f2bbc3bfad1f8a32e33380d001b181e2418de0b9909c8aa606428159be928fb7675e9b4eaeb3811de1f4e45fe431adb1241ce12d1430e5f880ee148604c6d88dc4886afd0bd710e523780101b6457158aeafdd1a0e9cdd4b4d29fbe7c2e883df5028ac19243e0a985df90648272ad8cdbfa87bbf1fd10846504459904ab46d977439af6c6154c10e93d15d9e68dac00da025740dcdc414cfb9aee9ab180b451c1a6f025a9d88535afd862ba10f2ef4eb69507cd1c5c80d4fbfb74823176a607e3753de48683bbe4c85d98f3da7fc9e492ad34a
g: b322f91f4bf16fad978a230d65f8dcc8a0e39c520dd81dc7bf25950a55b4410a413b1122bfbe0370876c511768695840f7427ef9a1c93312c554925aa4b50dd6fa66423c37d77fdece7e143bef37c0dba1e68f426744adcae0e9986e23caadf6a169d95adfaeba9ff69aa9710880ff429d7276fe0078ff2e1735edfdce49534a1fdbf624f973233948241d6139863860b10494ae957d8851dd200c64700d1dddeae72fbf14f5f6bfb0e885a0d9360671da190b22d315792232fc12e838fb0b4f901683e53c63ded5ab16198bb9f2671af9f9eab257baf9003de12681e900ff1182d80c69b37e9a9ab674dd48dc88f7020e0f083413ed8f6d35ab0e7cd86fcfb3
h: 200
m: eaa0c500986377044edb3f4afb03024b822f7646c2ef120b241afcb2f0aa8c1f673b9835f32c6f6f0f873b014fc3628b16c8df27775a4654d655b6f2f165eba548df892b0201e456e170aa3989b45c9dba81bc8851d00a19319414dbdcf776ac266cd3b3d07940c74ba7be7441c7227c15f7fbd8ee3fbbec97d5aef6ac640df79bec411acde25cca580d680573ac4d
p: da26211e21a3cd01bbd7fdb4d7a2c71712f1398050c6b2c3633f4f62b5bc88f7013140ddc4b8de7b86e4f85fc522efa9a0198d441610c4674f1b4e5cfda073307db97e917ca1274d588580d1a64eb31a50ba2c41846bb7f4d92b302bf312d206a5b7bab44375b09542647edf8d52b906442a21483ef2aff95357e8ecbb3b234b06f23b93a5e8a6aada365b366c24aadeb209a652c60989c3b35841a45aabba63de76dc482cc800f11539862611d375ae94f41431cd80432aa1cf066fea31ce4d313cb7023724b05f30e85089c105d9044a3d4eafbb9b0db2eb51d3d34b587063d98047972d9110f599a0a0cf636f1491b1e07bf937fc16e40e4143dae60deacb
q: f86719d2d44c3467f241aaffe1a77be6c2cec7cdf40852e724bd681b
r: 93d3607d57db2c3b09a6656903a3ecf92f763568b11db2db5a2e896f
s: 64158980a59418ede8146033cfa5cbf4381fc1f28cdc0bffc398f117
x: 4556f150c46a5156772f243ea7fdd1cfb40141facf27cd8cb8ebcf23
y: 7cc71c7a2b578283f858bfc158588811312600ca6224a86cc7d3911706aabf146044ac8243e42d2c1cc32b2b0771417e452eb4ca9f15aa4d6df1c45124097a9df3d9a3ce9f5e89c2b7e8caf02cb0a083e0b5332b75ad69ff097615fefe1b7aed604dd7b59b770779c6a3fcbd61b5598d122255d8ad67629dc44991fbb30e59727a3bbe6e53084b836dfe91a9dd03a447d0ecce13aabd6b498127a023a214b0a522911a353b853f77f202db7fcad1f212a1a9cfb3cc5be885d29740e19ae9d73f6e9873353080b3d35d05f994e592ff0024318b0b09f9798d45f20a815be52c7bbc75a88a348a7b93e19d68bcca5ae1f76171130fe7b09f4288d95b1ff3256912
g: b301a7e51a6fce40ed388a5a01285ab225dcda486a3fca99be4f1305b98529dad73dc3cdde986b5de3daf925668db5161c0f4f64737086d1db01e7ef6ac5007a553146025314ad69755b3ffb8763b90691519bd3ed85dfdc68b3e610e9db42c04fdec8f371f1f7173d59ef89d58ddb2c8d4c053cbd4e299dd2a973f5d849f3d0717385d3dd0675ebbb93a5ec2cedc3d916caebdff042903c51d4f6671bda8134363f52c8a901dd05551a9da8f4ea83628f9cbbd4d91d66d1f361bf8d8c447a3baf897e27f82e597b27c93ef118f0740601ffba40d4df5496663d55ce5eca53230f6db8bdedfe1a9211714e5faf607aec196be2272132d023f48a1c05695b2efc
h: 180
m: d1472adc75c626f4999ffaf2c295c51ce377f0b74b7d10177bf06c85390d6bb805b0d131c0c8c26d1b2a1c23cc77c7f67fceb7fac17ecfa94497e68c028058292ea8b25039df56fe51020888dd9b8cadb05d7e66b419a8a2fbd8d424021a1b5d8b80fee95d05d7c7a5af00e3e57af3bf52fd80a21c3aed699b4137388c88b390fde55fe9612f75ab0e25a8d7372c692bf519fb5786aa033b54d9f38c9705eb0db1dd5d0b5efb5b57524855a0b2b591f12456993a849859c74e1f6ef1d653e757825995ca014685c5c92ebbb7de686a685130853c09368281
p: bf786720318141a69f9196abf3fadc5cca630ff05b175d1f4e0a0784051129b25633b6de6c26547b2eaeae602eb15fe6ef5b5ad1e1d5a12aa65304b6af9f4d947bf56ef2d2e843ce3dae76d3b35abb7b1b6a7fc4618e719ca9cacb9a18e92ce4656ae404445668c299e5334992a49bd43a3a44ef2e312e486cecbed47c6439460937e485cfbc9e00e23c3d894af29ce2e114d1fd1ff567b1d716e879005fee7d6d4dc8f374a62b85c944a0f541bcbb8193ab76831e1b49218d22a52c777e89cccfa25b9da04c7d212ed2bc9bbc982d7dd1f099a6b5126be739c48ee6255d080a74ad8f30bac24d333bb767a4accc47f19e9f2b1e97792a749f92ef701c5452c9
q: e20001d8ded3f10e26f06163eec1e0fe1f59656874f9477c264bf8f9
r: 2d5582712a96dbda319d8c5c5c12927b891d66530d94563ca1c9cc69
s: ac197e0fce92a336c24313c6ee013d5d3c36a89716b783fb3218ccd4
x: 692bc821f47bc5a063f77c8323a7e41923749a924dcc454f9f086e5
y: 7c1c48a6db0c8f6eec09310c4c44d5816bb76d24cfb305f881b1ec637b1355155b7d40dda0f234b9ade1587be34127416b80a5de69b47580d42579fd0accb81f1b34449124d57ba4d6876a35916eb6d7e3470a3ee36b3b7018751c33b890edbec3f338956edca04bab21513890efc09e284644bc2b6dbfa70232f876b8768e00d58971fafc38a56d072fb633a9f74f3905d00d01d9185f6bafcebf5f40bbb7c9eaf1e941c72a265bd27191cb28e9364fdc76e50a9ab036f5975405f95f88a9ad70dc22514dca36fa3836feba2694712a9acdad031ef7e23d3d177b704ec02c196d9bef4cc7397a59c2e76a0e1a0520e66b89ecfcc93fe635bc357f9147b47eb
g: 3ed7b80b330ace5d9272c0b02e3bf48a3c836a2cd16178df6556dd8be938cbed1504087ea103bb32b789a4d807cf584921d387aede92294a05a8e6d76875852aa11867ce9a776f90c626db3c003c482ef1c1871832bd240f7824d6f1fbb51966e694e8cbd31f6b4d0ecd9adab5eabf1c51025fd5f8bdc51094b0325e54cf3ec4038622e394734e1c5ac57307ad1a4546d0ba043199ad9d2a1349bfcc8009102bdfa42d750473a229ebcdd83d5d165366f187f9ed7b134560edea5d414b2559dcb2d445c1e27792261eb45016987fd609b25221b30efff4020f60e7d39e546dfce4fdc56bae6c9b4b8d0c1ce684ac3ce70f951fa571e7a3b4700d6ec4bbf6e9ab
h: 100
m: ce6d8744756d63c0536cad533393cd50fdbd7c563849989f1bc1ddf42c04078558f906f17e934581a4609a501514e1c083ea4112c594a140759c7a7b09e77db62b3cbacae1f1554f245a59dc336a552eb7ad332a11a854f2dcc7375cb1f3e970049c28b30f8a9b7666386dad70be068633abf6168a4962c40ec6ae8e0b74ce472b4b45209e3a91eb7740a306ab352c8eefc23bd09712843c8e3ebf045b4413788352a7bc9bfa6c6155790eb7df94dc4e3f7933e70120fbfae2c6d9eca41074ca5e155f496ae2237b092bad5936dc3aa8e41c49151b11e14dfd89fc1a5cb8f5b1b9abc1e5d99780168a12a77b0af089b3bd69241b4e
p: d2b2da2141a925888d0a1f06a1deee7f912b362007a9a2f8b7c1af2b80a7223522dd2078f6a20ca962054272a33f10ecdf20d92e7756c2b41da66e3b82b7b04657835160dab105c299e51bb3863c37be75e4320ce6e3e73cc122fcf38beccc52bc0b59da29fe28125da6c6618d96998463edef232441cf19c089add3a376e2803c7ce000d88ee4e7c048fb95a3d0dbd41ff20064441505953e8dffecd9d9167829205603de5442d23880efc5322324d17d91a53ce0c2f3da567b852c4b00ff0042d67a78e3890177a717627d4a8cc2829bcb1fd6ff8a25b4029c00a47511fb58bac6deac28d3188e1032478e364b9f74df9e49c01b6780b7b06b1e074d153afd
q: d5f829f40008fcd9e3ef888dd1b47f0100ca2e68fa12002e5be92f27
r: 2e6f4720336fe39ae486e5813bbb7c66bd0bc27ce90f1e3bae64d0cd
s: 1b9d7e3b00f021ec8cdaa94303655d95a1bac1267d1f42653439862
x: 298ff401ff461420c3a43e2ea18e1271a77b58fb59e4340d2f532c08
y: c533ac2fb59e1d1827537c70833fc65625fd813c121e89ab2154d8965dcf07997fe6f86000bf26bdb5fed5df4c751a49397272bf140093decfc9935afc39f38c3a21fe59a8e6f918b606208116af3f996eada0c02babf8f3ab74fd7bc8d186432715ff8d8ac1591fc61c6ceee3452e77efc8befe1dc9abb5c77306889a45072d3efd63d4395d411785d1993275c90ce481abca8fd8b68b9b47ef37e58dc66d3acfbc214df4e21a8d42fb01d58aaefc40cb0bdbd102f00735f0dcd3b0b7c980d8fd91d59ddd9e42e0ad49afe275ea55c2a9180b747e6bd6ff6abca0dfe521d30058e310486ac9901e8c6c71c3b1be166380ee1534cd5e804e1b963c5c2fed59bc
g: 40c4edfcd24c5ab77ff763759835ae547b4bb1f6ef41b709a5de195bb1beab3488b5082d0b15f4a23adb8008f743ec585386ca97ffd16275332ba3f7150ca0ec2af66f1ba6deb1467c526d376dbf6f3e90d7517ce61de1299814b346e72f581cf89fd14d3a4240296efc3d403058f07586c2a4b9eed2861697bc58986e26206b7528b9a05c1a5f71ec3e52bab752fb439501ac1128f554026e48fd4d92c6007c214a373a94a0918d1a0ca5afe52006e762dccbcaf3890fc2d98d2f640eca079b222ca7f6caeeaf47265f068f83c73c9cbe4e7071d9d22c6b071c038fa727b1a26e3b34a4edb84353adb37645c1cba2dfeaf4077de8ebf2100e7222dbac9c0cc4
h: 100
m: 615978ae7e80086e3f99c5537e3604589a6d832243e6223148d286360090e517a8387060d93743a47ccecc5ab25ed9edf9fbc0e68c3e3a54b69a36bf4d7aaee138dd0f9ab45b2b0eadca4c78f826e86732aff3dc4d68d0f737c0bd6e246b503cf0ebe83f9637788de9d46e4932d1b1a21eda9d9bdb65d98ba7a1df04db2acfa57297ad229ab578fa865d93c93bb4de128be2e671fb7a6c062c29cb6a17281b4f7d1a2889646ff6113c0d896f2ab9c1
p: d205003f44c6c0f33b299b4eb8a05b3506f512778f4d837f8bdd3f408a783a55d674630761d0881ba5b61a6cac40ac55f3e73bc01196660880661b834c59f9614b20c872a9aafcf867078b7487d688335803cd581622b829d39fb9b807086dc30016abd7d612c815ada6a98a5dfcf3f09812edc578d6d36e2b34d83fb478a1afaa9b6a542ec519b3ff8efc85b43326f95b2da6c35b999ee1c7616ae85b4cc1bffef17bc44bcbe78f38a312247d8437f49ec001c8beea62f77eb512731e9a02835a99c207845497939f7169d8d61486c910f00410553a6ecfa11860d4a6d7b2c1d01390d5fb70bca57cc047caa3fc42fbd90149d87e0827903568030b398a2d4d
q: ccb1cd1fb6c4ede3d65f0a2cefca3d507a5f2ce43f1e9716421509d9
r: 88373ba66c99e37e053832396efc6d26f604fd835e859e8b8f1f4b53
s: aba32b5d785478ac6722dd52c0ef3ff945a4ea28a53553f8c3050bcc
x: 89d4394c0b9741544e300d51c0544f6d751f4b9914b9a5681330547e
y: 5a5cac7d833e331ef7e41f5017a869a24b8760e19a4e75a33ad593b2951258f784879c17bfc0071234f5014eab40b34ea195f60b2cd772d2acaa7796a5e4b30e33947b77e9616f6d016363c9c6d2e5019aabe854a7b29e837c6f5cf6af56f44fbc0ab08bc8b015f6291fd74a54f8691a8b2efdeb4a9756864d3376ce53431d6cb41082f569c2efb417674fa6ced28c21f34dac9e07f17858945834eaa4b98935c9583eb2e7354b978f18c414fdecdac6960c6c553bdaacbb97772709a1f3d61ca5841f367d570a7c59aa73cd26c891da647a4774589cabc211b6a75eef6494f63c83285b8ffd559806a6e2205498f54599eb055d9d62dbd8a4b71d777e3f0c61
g: 1a0913bfe15eb8cd01fcfece7bc6222835b11f5aa4fe9ea24e7fb15ab6836e15ed2c2b6d5920538579e08059df747626b019e5ca60440e73e1ce18a15b72d8a6698d479ad302113e79bfd8bd60d0b517db8aa1af230462a7fb5d14600d5aee7d4fb54028a1a21a51e0ab8859c6e6782445c0f0d8d9581579c81393c149c6a198709ffb83a0ac817bf883f6b2be6a349f7741f6c028b99f047a879fc9c16b03619f0af79e2150a6b9eb9873bb5ceea4ee9e5e6a0bae553f7f7df1b8706bba77761fcc60f575d3000610c46560a89c774678a2e66f2fed58f90509036124537277dce03c1c31b55dd72ca2992751f1f356c9a6430e8866459b41b2575d1b0e347f
h: e0
m: 821fc31ce0dae4e3
p: f75345e63e5ac46ba3d1cf9e7bcf1294cc811b3b1e92f6621165898f6e9592bc755de3fea50229a2fa619c813d5889d15579b04d85711128706bb730e60766e2e684d4b3da3f0849ae170954f27fe19caaf6772d5e7d5ed13abbd894f538b87d59c9a330ab617b70bbd56390cb5837f9fe2687a4f148f444e917c33d57285b91aaed34954ff2c66eeeaa77776e5fe40efd769f738a597f5b6199d536cbcd0f681b73ed378d3e3a79f37c58076cb0af67b0c361999d1e19a388904583f32110fc69df0f2595823391a07521e17bd2fadbfba400d366ed5553aa81f6da55b48d77d6737e192420dcc292bf62820507fe48a7df8f9918d6d974089741220d42a345
q: c409444821c410f31492725974f63e177891085b5d7865c5833a2cd3
r: b96498bf7944f31cd2a0c9b7a9b4bf1b0ede948c6b2606b2fbc06f74
s: 303b83241abedc19eaf0675f138d0379baa6c67e8429a4741f90a60a
x: 8c80c4b4a8ef2ebe319d16a1406845e9e88bd3c9c4b400d4b4bc130f
y: 1b156194a993ea73964f56d1a0f4b79266f3e3fb033dd074e18812ed29cf5d9f88b192a06a7aff2a135cf2c2ed3f14cd82813beb05771a69d62b0444938e6b7e0091ba8e992ee03ad0553616928ea5f7ec39f2952b6d75cebd0834d9ae22b30c491b1507378fc99b55488292a6deef73493641a8447789e123f12a4011a176814f24348acc96858714be6d6c461c02dfb45449ccb7096146d721b8f2ad341dae63f1c3fa3e9eb6a9e10c69a3cbc6c98bddb5bb4c5e1e005627c87ffc0685d30580276a81ea7e8fb745dc92f71574c5b50602ba73b4d1e6ea8969aaed52b76e2f875fc103fd54900caf319456336242247f233ae8eef3c7abd9356369a6c36d03
g: 84bb8c33660c6d36ce2fd5db0125f77599d1d1ed8a3c20be3e184182ce7e46744c6243239f897d9e41ca28ddeb3a94996871fb8fd3c20090349acf67eea6e94d40f645a255f05229ba32b67e496c327323b509c8f278e5efe79c1118e354b971678afe22121e0c4be8c6e40415215cb7f42703da5c34e0881b1521b3c8e53c3a23087b63887bf7cb5e0ece56728485e6afc771d83974505eb239e23161129ccc0a0b979cac98003070119dae49216cf216dcd08a7d1802642576b738165d2198d205a09eba54b05d8ec20a2e7ade599252bc3b315e8cdbbbe881b447ad5ee45934808b47ebe09e7a9febcb07b2520d573b1ec1a858ef2886079769d6b0d0e0d
h: 200
m: 6d8a6406ed2b5658742a0087802a31d51b54b4b453177d8b031ab226d5a1ea321db5775ab140870ffdfb54a1c72ad5e1a194c7f76a7a1379eba1ba6d587964099dfb463dc5342329f880b570f7578ad30040942c7ca507ffb6d1240c7caa3cf4489ac76cfb5e972d8fc94f60d14e55d9dc71f87d0d99f3bd7e3d1a423605637afe186e95cbe2eb6068d3df
p: 9c4e42fb45b8b66264a843691c88044e4eb65414fd174adad0c7e866d550195209438a54bda2260a0c86a619d2d02bd9cc09da948b9f8779106850151a16103389fa2649878bd1d615138e8aa7c215721e84ff2cc819f534bb8fa026904d2d84821bf0731ab2106de914d4a2d17438606aa10016cc5eb3597b75cc43fffdb6360d9df891d05354d5429ec84c87ff5d51976c6c9559fd0e21dae49a7f131d703e18c0369c6aa87a4585f5aee1726d4829d8433d2a1d9c745c47befadc1bdc7a12c3aba473becf22d460d38070eb9dc8d644575efd2066902dc9a516d688e113e595338f5104129910d99804ba882718f1cbff057833188a477c611c14eb0b10b7
q: 95ebe86036220d7015467eb80d34a5c59715693658290ef9ce880c31
r: 5224fa6e33f8c977a985680abe9fc6a1bfdc18f54013e9dd5dc56366
s: 733561a1612c23abcaeae3d986742fa8d38c1b74cbb2b15ce20047f8
x: 936969f28045210777ce40c6b0e06f3917d806498528fb972a1652b0
y: 2ae2fe2d77f70bb36f135f84cc1bd1b2b81bf1c18278d87190b0255fae2d342ff6cdda577ccc609d6c6ae1e3a8394525c562ba2fc303ff133fcf4e3c33a56c58d0553e3511a16e172235f99437b3e31f519e6b2d68a70985d2af462fe454f83e9cb5bdf639bf3b83532d731627dba60a5cea01ef45d4d7905930dc9a2b2e68599227d7156aa45ea9d1d28ffd88f0ab7c82acdb13dbebb02f83e6ede89c68843238bc77f7cd3598506df71426b5be6db4b86f6dada3c30dff841a3394e8b8a45cc349dcfb076d17347e9198732c0e066f670bb95f663a8d2a920dca2a067e7b4d84e8b805922767ba58af3187d674dc90c7615ce7c7185f7fcbfc13aab1f56e00
g: a516a43b28074552dccac76e1f9153ef5d979d400d51a16ddc41b659724aa0c577c3f44675792fdd0c0c85d42e808fd2403b4dccf3771224832ba8c4ff9ba5e60cdf5190260e1b7359fe940d711dfc6346fb273c645b6ede5872852bb9f0cee715ba3f2fcb77c1ce93a3c6a5d1b2a1ccf1007741fe13d8ca843c959f159382a1ece5b6784153dbd07853040964b6f7b6336636af10aba97e9f2bac124dec3be6dc8cf6d8e1382103bd4a16840750b87ec4f2bec8a3e9c9bb675f8fb7312a7ce2619f677324b27ec739601c9fe34f7d5f91c05840b9a35f79e7ba51ca93c2e226ca562f8d042d8fe12301cc2299bd9cd2cdac33990d3fda9a4e671071ac77a001
h: e0
m: e3aab0b8b862384bec053ccb80710e28ae003c7a32cc37eada858f9595d5362af48c64e444c6fca3c9a45e779cfdb3e28a248e4eedd38972347a586ab62e93ac61d6d9b847d84267dad39a1f694acdf85a2f372b4a024b72d446220f1d18beb5b01e6758ad6f1bd017cfa23b6703692576783ed4ca094ee1cd29bded021d793e256502be78f22ae35a58631629f578d6770d87d3963b7530dbda49f6ca6c2de3183d4359d0494e3778c84ffac9f9ca8e76d4a0045c68bc21c87aaa6463d9de4b43397f26116b6c5b1d8331fc2bb7c7dc
p: cd8cc07f21148cbf3cad498b37263bd63f8e6d446502fb6c84ced77f2007df2cb6451d6797718ee077234f7f02e5d0ee39c55d1cb4748ba501b35a1cbf468a40d782a6717b7bd627a8d5ede3ddedb16b29f29b45b88a3b92c879e97b26c085ea1409b857ae94269d859424d748575433015e8a86aa9621712667cb972570a090a687db7b24df02295ce432ee6d59fc3d6358a01d5322d52266b23d6e467b958f2bf0c5191d9669c024d9289f67803b07f169f8451c4ccd5910f0da3e781dafb679ab39d9ee914c61c38930f82c34eebef1fa38ab29fc5ea71bfa9423f0370ace21ba1d3fe045b1d5332ac5526935862876a100972cb3703bedccd68d772e3221
q: efb3a7833360b01d1b6c3cabe3bb2e9ac22912ea4a186f9f424a5b41
r: b01ea3ef5bd2ca0d14917c65457b8575f2f99a34396be7a5ad3f7bdf
s: 17ff9400f24a467e9759978f67236f9933e69ca3762801dcc55aa35c
x: 5c8033b048dc52b7129f12c003025b2e72a8625478457c279fc72b91
y: 76190c3ec95dab6fade064480e2d71795c4b9cee8628a003da18d823a4bb69c6b0506ba492f15096a84839190e4732b9cd667726a5fcf8e619d4766a4cfc2f42f5fbd5ea35170d75328b394d06ba6ec5085b88aa331932f9800ccd2cbb295f79492453285647df30861c750b02b7439044ac1c3e3a516a965fb8e516e60082ba7bf23121e52b2fc40967a2db888ba11e299ee2d4f1d4a3ffbd44818bbd19011e667e8c7d817f9e72dbf448eda75fca44581fae7c54c624f8fc169d8ad0a2458f15aeafaf8c54c5ee77a8e60839fe6ef03ce3f32cdb9f9f5e66645e470f78cfb8d28f8b23b7ba49c2f774f0dc4fdde6602b59dfb5a45087f6ef820d03cee2606d
g: 43ed94755abe2c8cfb5a7a2a0af3914721d9f9471023a6214c849a1c6f7bac2efff355edeae224cd974b6e79191f807e533e9347e8b5ccefb771cf40bb32b003fc23f4e41f8f1243dc481aeabf22acd96ee06a12224fc96474fb0f1f789e302d55b50943b69afd3d4d9687cc0143f8ba4c9265cc134752e3dcccd362278f130e8a43e05d5ba81827e46d5dd5d0a186111cad85d5869dc07c7f9f2d6a7ca38817d266716f8b5b31f7b3afdd20f2151ca66b9a4d8c66a0ccd8bfc8347545cb6f05a55d98e1608a36c2d6c45352920d0d769801583bdbb30bf227bf19547d56ecd1749436256b80680b831a0f7513c6a2d21191e3169219bcb8b1cfb7d587ce2383
h: 200
m: 0b3a2b159eb6b90a85487db0e86ef3e48c40221733a5c1e9a74c00b4ece451affdb56fa94bf3453d613c63e507009e4c93b4246fac
p: a39b9105d21606a6964fea76245e06e866e3924be90c95b7e848aab7f9f7f84241263f336cf31006c191d0a9e0712618fac04444bbb1dd090e0ad8ceafeb6c158094065d0bf0c838d33edc29d01adba3dfbd0cd86a465c6d9fab724b7587cbc133a0ebaa4bffe09cf7d872a77445694cc16ace3b1c56956ef765e48c327d79d3628410e46bb378be087ab8b5dc3897ada29826d0d334495f1eb9a504b835f4c98d66c1870998fe8d0a96194efc5b42057aa6f09fe024a92a237f10414f5942f5a84dab005531731fb67ae0e056e7ccb357c3b4b7b93876572d35d7e8c02d5952e500ad60cd5992eba41e75f10bfa56a2273397374d8c0704e567c4268c3b770b
q: b00dd8e0d21e3e4561797f7edfa87c111a06a6a6e94f249d108f99d9
r: 649654fd6d60871ae2ce2dcc75471c88aef5aca3e4d5910ff77aca19
s: a2f15deea9d7940080ee2ecfa65b62c42e953d37891a53c1cff171d3
x: a28fce73421fcc0ea92950e6a4c319d89e223e73a441f5d1afde8041
y: fed9a6a1c234c8fab3c8de87090be7ed462a34d1e97edf180f31ea264f9defc61e004cf5b5ed4a72e3cce449cb8993de1e26ce3bb9c849ad63f93a31a4ae2c7f49b137d44933fe1dbd26feaf5e3b3289dcb1885e2115950bdb2c6d7b0d05dbc6b77f7f1c8cde0f0e7bfa2135343cceda1013ecd93b4f774e5efd4085223a8871077f1ef1625079a08fa8e99d562c9bfa8dd60c8e689a84c071c2528e64608e6b9faab20ec327542d57ec66f093624a24a7a493715c62f1bde8a87b939fbab8c90eb42bb50ca6a652bd554d797ef54cb23b045af41d24ff1513514874d799a1da05fac75d6219b274e969c5d37ae5de5d6724025addcdceade19550ba751ba94
g: 51728bca97842ba96e2d8e4128ac60faa009adae876c0122f63165dee396adb692d1b7b65b95aabcf06bdc259c1a630a0ea9baf80ad3d4f7faa91e3aa1a30d00c762068efd4f5b75c4331121209d06a3eeede04c5ec5a28208fbdc309f86c85f11da215cb727cf88eee1cec488ae4e927724034f08b2d3cb942292072770bd2d26e160b12811181259ea160d55181e17a84a69d5bdb31b415dcd50b65f28831fde054f069402056af102dbd06fecbfc85413aac7a642ea3802eab302e1f5e86f294f2fab8735bf6ee434e2ccf7524a34c4d9f23ba323ecb5722a0fd334a4276c8482e8e0a5d773598f84f3b1359bfdefbf24f190edbfcec192843a4dd8957fac
h: 100
m: 850d1ff994cb6b6b3fad94bddfcc95a5fbc6e659a64b24d129af6bf80c3e13486a7a0d230542e4df16971eac2ac131de337143af186a2494fd91111b61a6dd467616d0b753d351956cae81a59e53fa8056eb7f5c899cdaf9ef5b57f340bd14be57fb801934aedec0460252f568edccf751bf1905e158c45772c5098905edacd761f9bed68389f25661f320020542caa70a08036b3e0bceee57d119be9fe96fa1b9a8315a730187f77e061a0f76a5fbb833284e4bce9ce0d81d68590c21025d7a5a7f205b43505743eb7634fb7c35105fac77974ac269f56962208ea34426714c24
p: cdbb297cb234931ac0686b17834760cf7525a46553f7c4553ee55e47ef35edabaf2cfd5133ded833cd86629cbda0d8d545d38baad4432469d977a9287cd1c9cbc2d17802ec65ddaf7042d0399efdf17804fad10fdd41fc82b3d73d5228fa47d296c37f78b3bd657618c3220530c62b02a19eab1d414b1a42bf0781627946094ffa8890d3b620abeecc762eefc30383be9602faab66fe53e542ec79c3e55f3c7f4771c2b0017040c44aeae537448cb59e7873e9336f295bf0a109a0bb21f021f140a35bb63fb04d193c148a05bca25a2676b137819b19c80b7d3b4ba41c5cdd81cf99ae7b4e623d49ca86ba7b3a899bac79a5467a613130eef2260cac02e6ff13
q: ceb64adbc91e079d692bca8aad942bd126191359d7fe7a91158033cd
r: 4ddcd99af2b5ebca3f13adcc9edba0ef541a14ec7bedb2faeaae1dd6
s: 317b3a61d6ec00a59319d9f1fa948d79143c857261f7a227b83f3eea
x: 6d76dcce94dc2c941040f3244fee951fef92cd3f7af31097a426bb3c
y: 9a4e23beab8376d1e41ceba731e11046f0dd77bea7b6ce5f21beb04153a7f0fa86c2cd1feea941e3afb0c326262ce24489022bb971ebdf8f12ca572ee0f1a9130be4fe8c57a89d621a19cb9723bf3789f0f909000148e87f673374752d40e60e595e1e4942dfadee7441234ea027ec98c6f67c6049f6818141f7ba68eb60e14b48b6adf15354e77bf8e0f8c9389492976889dcb228163fd57a65015574843074cbb8b205f3f49dba417fb736157ddaa2c56dd0e923a449bba48a5c8f1a6880c730ad51bed9a4b0651bf4199baa4c987d3fcf2c94bfe12a8bcb6fdf6f620ba03b3beee6b19eb96410602e66625348dc00664deb0586fac30fc48194b07944dc41
g: 31a2ab38476ccb2f6eb3b64c1b0e532d8c7c8062d718733291693d8c8768cd1b5f76ea56200172b8d841f2050a269b1bb6e833e888f01ff8fc097e1a123a8f8183243932ebedd7ef172cc9a9ba8b5581b06a543eed38da4ef16ec24ac3d0c12de6befa81a1940255f5a15d8a8615a9e7076d4fccc906ee92162922ee1230c6008a279ceabb2cbb28b1b167f46d9a4453715b9dfaa8e0beab255da1f52945f48d804b1edf8d06327c9b04b27772e296cfd18eab97f49ea2ad123cb0cce5f4765014bc334dfaef88782494cc6880d82e24d0825b7fbd600e1b2af44736563adb1168c304ad933f697d1466f7f3bfd8c4e63553c0c4e2310ef10f752b25a894e29e
h: e0
m: 0438a49c64636ea5d0a973b8887cde32f7354252397af4dd128543a60f81805f65b23374f0c4345be504d81d4ab442237fec6217ea5cbf809872fb1fab65fea6f72e270eabe7ab1ce52568762cf0a088a08120e5d9fab8f9a10bb5475fca1631af4082828c872d800e989ebc8107bf9c290fc8fddbe9deae4a6cbea6a943184c2664ead668d6266ac7962f774e171ebbc7dfb7
p: c11efc9e92d6f52c1223473d1ec2a024dae661bbf3671dee10229268824723f801598ff46da0fe8a67853d1ded0fd4bff692c111c0971f7128bab01872d18e4c1c69fe5d5c066d3fb91f3b75c8e3ac25fc1d5725eda726edb0080b464b557920faade45d226bc588d0d8048e4e643ce163147efad703129f9ecad4c843ca2f39a86db736ba3cfa7aae4d5a25482c8dab7479460c466565871c60d356f60e7992c761266009b15f1729df20cca35eb35a5505dfe6782429fec5a3138b02711053d9f36c99b00547e03e9aafa59f902e33a5dbcc96c1a74e5d7bf5fc41cf73bfa2b8887440bd487a969ba808d03483174862e2b91d0f1eb69b5ed38a5fd897dd0d
q: dcde01be27ac72bedbe45d5c8c5817d17bf41a3a612d622eaf88f4f7
r: 99fc764590fed1f37bc460cf7ab72f93dfe0ec3e439f21847d69b7b
s: b7158ad06fb21622f2b3957af17621f66ef9fc324891e61e230e46d
x: c38f89dbab151c633a3c9c71dddc3ecfb540aa47d2943a2cca779182
y: 2be5f3ca9c02f0e12abc0e35e82365490db715cd323f4e11f29f2f02b6a5ebdf67148bbec6ea6f18ef3356b57592e952de91851054aa03d9202c7680eb9594aec883cf1dd9a534a8d18eb428b9c9b9d95cd9433f990178d36914a36d266f67a7546cda5a66450edc1d3e4850e92ddc17438b051c0bbb39e42db129429c4ac78a721fe059203e67afec5092c032fe2d317154a9bfb01b08eb8754495a6462fe9944df64561cb21767255eb9fdc393d3cbd5122a2f534c1f921eea32f0b92925ac57080baa0228c31878d102db179a77a7571b491522ba7234484c3a232dd7ec7415c16a914cc4364276c412769e0a0acaf2c6f752821abcff332b09f3c79a5962
g: 6dea6eba7f8a25170379af7457c383fb149e35e47cf0b7ef00a185e02a4f07556aaf29a20cf5fe7fe6d60d37e24abf325ed0f99ebc7644e23f87f96a09a1b9b1aca3ddccf598ba99ea0ce793ba861eaf54058cc2606e49fe30d5f6d9c9ff7cd132f55077dcb7f7739e893dc290de96d2886f4bfe5ce546f61096e38555f9849c8048db57277893884d176446c14db61b7697a03aad87f60b69c8d4a7ca1e105301bd28a39b4364db169403c2fd3d6a159f08089e5e33bceb77de87a2e613bdf6808df07c7bc15b55ccc6646eb48edf075334df188b22744ebeaf0aa0a5194b4406f6086d5f17cbf7331fd88fe392f7648d9d87d0da60cc1d0f2b217ceb70aab0
h: 200
m: 1d67d5f4ddaa362edc4caec3a5c441dd123459232fd09fefde1c2d65e8eb5e00f0bcb407be753042ace8611370b9b7e1f921cabd75e63760f35e3f16852350477fe6ee6452383eff37a9be64231e0cdcf112b29d457546316139aa8d831d2663d52b7ee3b4
p: f2d27bf9ee65d7d4e54ed3cf58d38a655b28f16ef30eff178c1d63440dcb375d7530fb079482278fe1ba99f5a65190bf4bf373ca7b8468e3f89b55833ab75c6d17813daa7a5df5f1d24786312d53b17b44eef8f394b32f726bf7e620b96d84e9dff62b6452cbfcc7eb4f830dc03b9fc8949b2f586565dc4cf71f5822666dc9b9c66c18559fd908080b1be74738cb9a2ab619576d1329e8f863849fbc87156073419146f03babb6da725497aa1403fd20e83a137344c733cc7cf82af2e1dfc02ca649352682872475174cf79fe9eea2ffebc9cf91eedcb3cdc038f5552cce2532c2954998595bf6dead1a000935ea51f0514990c216e16e49ea8522e7ccd371a3
q: 8f3ec33c9b84d3452621cb9d7cfbc3df044df429299b23f23b8e59f9
r: 12e1a00a35642a20c0bec8af8f075fc5792a906e066ac436cbbdaad4
s: 602c1a579a9c24b5d1fc7c7522ceebbc36f2772f9f8beea13e1ad88f
x: 4d168bf47b3a18053a72f551d47a02b9629762f32e4ac6eca0bc4950
y: 83cf9fc4f3064f06984e1bec9c141e421b0777a1d146e47c3901d1564edbf41c985f7db9ec4d27de243caecb443f6d5f14e9fd6f39974677f19e2ff8572ce5e9898ae2f15f2e5c0e669d8b75d3bf677941e263d575074515b5acd60fbc3545f1f7f153b040793690423674cfc8b7d2e1e44e22aa2f7b48085f1877099d6fa0420a2bd3b73e7602a1bf68a54b4af09c2e13429b05ef5ff3e16792ff32b0ad820fd9d927a0abb4a131fdcd9b9c8ad4cca9b18fe659651dd0d3b31437332829ca6ff495671ec2f0b759254034e19c85321798dcd728792b268a069c0d88be42e6fef1fe5d00f0a7f07a8d0f5b841d1a5e78b8d093609d92d75d62a6476190379caa
g: 1a233a1311d4ed1894ac130e51947875b01750e8559ae352a1e2925df29775bb598e9e73e373c12d55bf60c69fc7e4cb72f085ec0f22dc954f79558fcd6e23cd3889d50c5858c776c336485ce23c064a693b15a92ef1c7e5631d3fa5bf0de572f23a0805efc634b143328d922effdba6b4ae76586083445d971c408090d22261f07e4a906b1ebd74fc02d5f875d2b09ec14cc4eedf675dd2f6cd70f8a8e5ca2bfb68a52d9cd8ba756242fe0fbd5a6ec19bd58f962abb12cc7c7b700b56890bfd96f6c798bca23d780ac5147278174ca4ea8dc61ba00909444d23c05ac2ffdabef9bc3ce6ac6990eb4c8d22d3426cdd8e8703a08939df7aaaeebcb127d2afba20
h: 100
m: bca5a759104c7bf1340667198ac430f56ff2fcf8e341c04881a950873bd22676e20f3523ffdfe05bb4f74fb28bf5b092f02a507f94fbe0414b7da2fe5add8ef4983253ea7350bca07737c6bed5ab9c0c085886c35825ff6a0d97149c50bade8f2bae5fff05c7e30d510da13de5d298f4c593a4d2a678231efeb8570ea56ede665b5cbf0ebd974bccea51002f42
p: a2a46c79a457d8822f5092ba2605ad9be9ced623db73758521a23a74121f92dc328029e3fbd0b8771060be15126ba048fc79c1d06fb02af9ecf99a359baac26c3fbc5019699c6c0d5a81e60f9b09ccd8351a088b74bac6a189f9f56e35cb143af878759545abc3e62d2aab675190b3292b72f17059330bf743e30c279d17fe0877fb787506ef0c3e77a83b1a067e1f7e82ebe5cd515de4bd6c31f727e8aae0b8b59c2182450ffb4d995872cf3402ea71ad8de3c08c79625f4aa72d23f9b3338abbf352466d7131acbb025ab6ebdb8c8b3a44d2f22f4e74f2a594d8b7d53e65a4b6388e3c1c6206baa19052ec82126f0e1e43e5dbea84f69e30648aa04a84354b
q: db78af52026a892f3c8813bb77f0251719d81995a00aefbdcfa25fd3
r: 63beb195b48d56a156b4a11d63043a2fdd0926285b81f51d842a450d
s: 3b3e0ebebbbd87f2406d7118fc45eacf88c8b295d59d481ea06afa31
x: 45323043e71ba5a1302242f9cbf31925c02ed4ff90413747b7a38976
y: 35a2185762ccda7995ec679bb15855268ee9778abd736b738edc832c4dc7e1026fcd13c8eab3de70e522dbbf6d5ecb5caefd4b06aa60975b116d034f7cced0b0dfaa2b42abf357a6278c5d6e9d40248ff5b76d5b74dbfe99346f1b1abeac9b1f2b19d493ac9445ffd7da5833b0bcd262b7789f48c5d663facd839be120e4af97cf4674b4aaac60e762aadeb748fe4a19bce4c2b5ffadfcdf8a3024e2ef0d05ff795c90c8f17d9b1e8047f5879dfaf7424fe6409c90e4df1103f540eebb5146b96bec7ff20053d3cf454a4a0cbc1b4b1d0cb1d42354b598dd81685f6b6ec5a134c98f055ff124cde48982ad409a752e0f2b3bab03a98c23ae1b12e14395799742
g: 27ae9217e20e348af00f9cd070a492a1022ab088bd0cf0e1c83e4319dc29ab14784ca175ac2ef81606a41a27226da6d6dbbaf3a15e49d4db564c18ceaada5674424a17e53c6822e722a841036e59e4009c1a1cf27412373bc25da89d7ed7738999b87f5b75367d2750e7fc5535dfdc3bd4d8c9be9448b74eada6a9f476e9fa3aa4ae77e9447c6551a0666760d3541c993ac046be4eb6e3082ab1ea85399c28ca102597a7fbf792f644948f2ea9555cf2aa0b9b08d33215e56b48d1a74e345f747e100731f3375ce9dfeff79a99e92f14dea2b59ada2006498b43e518f942a95920c688e19e59c302003a183b2eff41b9d6bab85ace9da3831fe8341c2609d0d8
h: 100
m: eac8000ff33efcc25b977821e86939591a4b76a487a45436432ff8d00bcf851ae54bbcb8659520daf3d7833cf5ebca309b5a4b44e46a4c57d55494c222f7561a5e7a6464ba6797e914961a16ede4298f3993ad7aa91809c956563191766481f1
p: a00de4c8a703320df711317f490b18c23c9ff09eb809b48df05ef444cbb9f44219e192d3112bef4e4e8be48ac14572cb7fb11c6b51279d25408b77610f05fd5673d9d13988ef65f5f74bdead7144457c5b07969a10576c626a3adb8eb6dce8c3cd244aa69860b40a1632b3d70387894c709a3c9bd93a337f7583da5703a092695f86002568ca29baa2c9c041c0b8f3751865cbc41e71797a3359d23205895a42767f4dd3045834da9192e3f15696c0df1482508bf15d110a8c9a658a73ab17af5dac32e80b92a4883d18126c010465e49167904300f79a4da147939bffb0d1b90b24d9b0a96b39897381d6d0cd0e2075fdf854578bc8f5f60471bb3bb6b77b97
q: 97c19e3be0291d58aebe99314055cb5f53e9e4f0b2230a517d2fbd3d
r: 3ac0f707bd12fed87237f1b75ce1cacb8d5fd1705e0e59b2ba187f63
s: 1af6733e5f495180ba0cf43e0211a8b03587760e352c9bb0bc6a9590
x: 30ea802a8787cdff6fbbc7f61f436feac394f1e19822e8401c9486cb
y: 7b3dff0ba27dfba956c88c5a4ba9d2df6f8e1dc30a5388703ebc572768fc2cf4e996f44b5dc48fdf8ea049dbefb003266d138b36f0a43ef04e98881f05665008c740f8bebad81ba71afc7186e367aaf24cb886e0672db2b5361c0e4ab7e56cea50fa1d2d35663defd6c8c54ef3edbc15c5a31ba2203e9c1de9e13068cef5b3d923004fc951b92cf34349b25a2d9e5ed8ccd25fadd87615a5c02a3807c210273c7be717d8a0a3fe4e5b58f8baaea7ab853b4a25e16fa7be9576a2715a2b7828644677bfdbc3b283c3f6bff23ee66becf993c650e1f704513f4e80f5d94df87fb732c32e90a97866df5cbd48bc893573a93c48e6bb409e074f99cb4bb4ca6cbc9
g: 9a495b8e471a87d5c9c5cce622092d70019ec20ab98a501f74953cdf467177b49ff166ee21eb21f77f50ea69f054fc4d1d2c4facfbfba602f73f52b4524afdf50787dbb658992a5f94d097280ba46ee91344416a300d3e78cef9b0adc33301805cd4b0d21c3367c5564e8d8f1abc07c182346f3f707a531d6b1e51bc9e510db78aa3214e8ffecc8c525f6ab3183e32139413710322c47deb5073156a5e4df31d7890632bc0b568252a141269a8098884d103f48444861aa360daa132e75ad3502ca376aae889cfeab3504d8946e17208d06bcc5e9538b84f7a494cba1fc6ef1a08358c922ebb9f4518b9cb3a816b35b7380e55b3c6af9bb1d51bdac695272de
h: 180
m: 2fc99b9bb9831b132e6910eca1353f81bea78bf9d307b2ffe84110439979a0bdc5f94cc79f4319589681bc9be4dea978ab29df7e62cd7f91d12f8e00759b5c2dee743f5dabb5f90f37bbc2ec01abdb05b3f18578063a1bd99d6388a763b8bb391d1c521b681505a39ebec02037250a6e6c467df21997dda5bfa5193c15cde28c329b4dce3a6962b3c2e9a0a0d92eb0901a2a87968c01360af00d72b4e47e3be4fa6ea9debf760af14508368e867e57ffd9405fda3a49ff88501b17cb48147868007d08a60d
p: d12a0b227544bb19140da6a17bd08bb92d2e716d87da2fb6d6468be922cb77a8d3269c2b10b7970be132c80c041e265a458881de5a007cd2af71197e10b13b20e93e818eaaae88dfa9726d702d1e98b309577065bbe46045f5a6ebcef6d08cd92ef2bda6c61512198bce02a565768c255020a863844a63bd67c8c5b58389089cd22e1fd5fbcb91736e3ddd3474906a7e9d79584aae5a2b01327ff5011fe2aeaf5e697343810304bce55d096c070ab99adc7d0113b6ac13743116ceed5f8edca162dcb3892aaa2ca833802805f781e1c50c88c2d96a1a304b8fe58c3153d9c46608e87e7f1d1e3c29419e4f11f5c5fc38432a3b60637522324efbb455f2d19c57
q: 9c89242ea3d46e0c33fff758fd61fc10e10dd7bbdc0389730b80446d
r: 661d9490fcaea9d7c8988c87309d8bbb482c0363859e10e89d0d3fc9
s: 44b19c3b1c2a2fb43c2a303b59969ea8bed829fa795d3c149c80fe6e
x: 90f68246c178956ef16e38b44cf3d14105d855c57fde0f3a19f64a15
y: af53e09f7a5913dc1bc168ee2c230cafd3641a72762b38ac02dde9c4f906b4306e9c062f71e4ae11af2bdfe3c32d0b823e621f2c0bd10b51a815f89f5e1b064dcb9b3a6c2746d5d68bf7ebb0eb17a9ecde0a628775d55e73aba50945c2cad156e71d828143cf618f4d6dea633fc7c14a1ff1dd5a52aeb44041f349adc4ae849213c2f58a9bd4b57eea576e58f6230968bd71455e30efe3efbcffedcca7f6ca9fab26442b8a26d512c3708735d0d3095ab0f3d5ad33d2ab74fe944c3943abcb39ef063737e7e5a6c55dee34cca7ab219712a842683bd87c6529d267393922e62884e1e8a2fe4009f19e962aab7716af368ba10013b0edae8e7e4a5f13f450d141
g: a45c4bd62a9ed678de9eca6be8ab3b3c55bd7294f74bbea33c11659178b8cdb8be8a7f24f18fc0478be253600f7121f1510ed060aa67ba191d00ed19374402820dda53306265c7b9f2f7932abe8abf63f1d52d13874c4cb2eea8dbcbac0ab463845456cb0b553bc5f999b0691a16815edc863996b651a0c75a63c96df64e4f99efcbfe24df877a9fbfd923cf9b22b0c57f1c43ce7cf751acf5902e65d34752b7514d699ff4e170a52535e9d8620e8016f9f4512e30ff78b4fe9c787452a4fdc362084b86a234b67d14261a17d4bd9e6103a251f1c73f9b7f6d7b2d2a8b29e75c891530ee9e7d8fb1cc0fc2e0ad7f858d991c57d77e7c6a3d03c11e7f6d32d7d3
h: 200
m: 4dcc7887a1d36698a64384347cf116edb639a4eb3e93fa379e683ae7bea1cfa58f3b5dd7072ea4906e11a23bb3b919900c756d3f3b533f889a2c2191d5f0f6a86306a76f4ee15fb88c71b55ee4a166e70fbba2a887e7cef2aedade7d9e973a0332d9369a1798e892479e019d02a4399b5de586d291325c17580b879d57e4bb98ce06e5a82bb7842ad79a0af99a97a3c343c9ff01a220db
p: bc98945b0c9089e7639657668eb67da6a87bf633d7aa6e98db90207475355e4973fd6a2910ac1a5746a086b666fc4dddbf575cee52c4ab3be46caf20ef5750704d2a50facd4bac27fe25d772e69245c375c8b423354d94be4d6c3bd658faefeaada7fb36539d2b7f76ad448ae764ee5e2a5a41452d8ad0dc20cd34ddea6600c5cf98db34136c56a3ed638037f202bf594b8d0bbe2f958a30d22aaaed618ca04ca30c905f6b3ad542b52e9731d389be9453f4c78731e1c09cef13146aedda9868f48fd4db40937e5436292762171dc43e19c031f614ff982b3c13fdda5dfeebb944f28318ae5b571ba60f62b8d465839829aa51c1c1c4e4ecca8d6808e6300593
q: 8f3d64a23495b4dda79528a3eba43f5b6cd78562a07daab664c46d3d
r: 1630955a8fe8d976dfa3db20375b3f118df68bab908dbe7e9366df2b
s: 568053e0bb668c3e1033d1a5304b4fded0ffa1f16d5d240d2788f8b0
x: 2a7cbabf1e09ea238183d5a286c904b4a65bd623de22de1b66db976b
y: 109e4953433dab109d4bac0862d2e0fa81ea2be91f64eade5c0bd8b30136e76d73696200110b21b31da0111a54cc497a1a4edb17a7b5b7ae54cf7fc62c980518d8d504976c395720117c70b202ff5f4c3ccf30ace2977337b1189851a480fe13dc01db4ab1aae74f913bd178a08a0f24baeaff9e7e0b3fdbad27b4ed87ed4ce3a7746df7f57dd8461d8e53bd413775804dbd7d469297b383f0eee418145904f4a03b952b81b2bb9888b6e5e804e10bc6617c4b654fe8c7dee3efb0798ef18f6637c880e62f3346500d45f4d4bd9b7145e6304064531327ffb962e884f1075f1bab9ac59a189b1e8993c749a32693898604c1c56a8c2a4e166da80b2233f2d2bd
g: 279e26642123f6a952227a2f6fcf0119e562d391411ec0acf8bf0346e28f188fe6809db177c7e21da02d2a3cd1d27579e8120126262429181bb1483a08b62aded0cd0d4766fa5cdd47fb229e594a91dc49478fbd60cd5bcde95ecb40b4483f7172e1142ff943b197858459a129e91cbe814cf78916ea819b5082aec058ebf32eb52180bb3afad2bf39dae3e51b02557257fd0b1cb3a4cfb8f6f052943b2c339008adb279fe5e5cfb7157038e099e296b605d42545b0e522ad00fd7324f1a81051996d7855be9231841e424635b550ddbbc24d6c6f381fbcb6d4ede291cf27f8eddf7ab46d828cee8d1f4561e8ca15d3ef643defce090496d27a77960ec55fc5c
h: 100
m: 1d228c3e82f29939fac978c77d7f986f289946e7d1eb00f546fee875f6b940148698
p: 8b11a4e9180e193d12bbbcf49346d5838410ef52e8b1a2889f5083d95696b9936d9be26aed6737fa6d9b6a204ce9b5b8d8c3baa9441e0c8eed50afb7679482ee6632cf346867f1b048138c80872f66c4d4f1b1634237842dcb8722c4d96ffbcf9ab5feb672035fad471bf325bcf97960ffe3deb5081d23298f998a1f7a026495b2b06685819e2aa6f1567ba37b7108c7e7a2e4d79e5a11e5ee595d3fa804d03e55b169f0926255a43d2c8063fb11c5f8d949d745d339c228d61e51d3c0fcd1b7ffd2c5e40e3fa087b5cd95d7c36507bd309ab6b9e38530cae56afee59706e351e3e5adf534bba368b58766ca28f74a5c7c8c86b0f5f249f49137c0e330f28749
q: 9075d45f3ac52f5995b6fafad1eb94f82961519c306c4e36cc4e5265
r: 442dc63fe77b2682e4f4f61ad4d152be01dddf27660e62664a4241a6
s: 1f4c08097a6f891151231f8131fba53089e9e3c5f1c450beb8b4c089
x: 13920f02359e20635a07f2793ebc4290c585cee32373526f75357346
y: 157ad5af5db70923175eb01bdbbdc6e861df85bb3a8f4db897aff2996ce267ef9dc1dbd6d4bea314dc4746f4bbf51e3178b80f0210e84461f45d7bba317b1161acc63ca59abbf0e6e5b3ed42addf67119deb1793c56b00f738f78c1cf0133705c84697eb6995d9d4cd246c8d5e21b8ef00f5e86ccf4743a54e1d8bb482d5f241b91020b837d7855f073fdfcb9099c18357a32ce32e32304c196ce011d1ebeb94fe2d890bafc97c4414694aaeeb776da2f2a66ee13c61e1aa35ffe27c4524c288d1c9fe33510a8233e45faba5edb399c40f20ae91f8e24c0a406c352db7d59ed86ebdb7376c1e45c3db1be8f63bc9db704365b7dccb15956047b39024a3afe916
g: 468cdbbcc35688fb2c1b84065c2d70ffcd392e865ab5440f30ce2bd5b1c1f92af8c7ff592f0283ac1c7a6d33aa4835a5556caf561bfdb4b4789fa07bfb84cf80f87c0c1477e3f5f079a27f545c8a2829950ec4a8584daca1c9bf2d9591e6b42c5ca740d1b82fe0e052573fe73cb0c2db962d41b4b879f7d1273b8d7cfc1e222bfbaa13160ca13aeeebe3b4a31790fefa348b7bc7e3d61ab7d60c1ce5a396630bb2a4dd7ee6ba8bd89197a572d741d3bf22d75bd227bc099b8a52c3292a2229887cdc7ff5f30eef2b993c84d48e86397e667e4630edd6ac09b47f00fcd9351f867584ac76aa081284b610395c8137d846bb19d3aa1b4764ccb7b0a730763bc196
h: 180
m: 2d104c6f91aca94e9da1db58abedca454fb3d2608a1e9fc47a643a1608614ea1ccfbd489225ed38c811845f0b5262ef7224dbac6050ceb4a5527a46c8f9cfc2d
p: c1fcb56e8fc3af466ca9fca45a99d680aa58f46e28247df1b0dac038d8df661b6d2a9e13caa60d2a8311d7fc684a9b18761d48fc52fb2bf98c2311f32f628dadbafcc1c4ad8019336908db7152a4c03ff3f0494936db5728dc8a58017365673e34c23675cc59975e8234210c8df4a4884e7fdc0e88a634e2ce956b6a956d5c38445b06bd4c813a697ddee6e3c4b552c584e5cae10ef1d0226ad778c79d8574bc0d9100ed4cc6177c58712e7256defed2bde2795fc09539e47fc03d54079afc8f32ea77ecabde6390df402bca7174b88fd3e47ecacb2a51acc359017cd6441c8e78d0a19a354233d9ce840137c7a134282c0728085c73a1c4620bda3ce3f93225
q: ae482d4a4a0f3fcdf0ca44736ee073d5d0952aff6557750cf199c863
r: c087c6f81d1d2cf2fec97807b75ab6eec4402f19808bb83596ff2f4
s: 36efb6709b99515c888916965be667413223759a3761c2a0fc81901
x: 70c6a82cd663f5293fa7eca96d682aced0b392f8fb6a5b29f182b0fb
y: 8c8d60611fbc01e1266928f7a537ad9557980575bcdc618f350985f7d5b648f72bfded937900627e4c5de7ec28d632b5af96a726c628162ccbffd6997d2e0d44cdc1f0ad868e9812de5c6931652c689604eb63bb73373e0c0b4627a4ac54a480204f5c7678150d1a7f22442023674b4327bc1d31fa7e4867d91ab9abb58d2b2ef3cabed3855892de6212fe717c8df5856f24f09cd76ee9aba097980808f36f7ec1589b2d471d10d2e87cb4ffee6314ca90b9aa71e5495e04d8965fbbcbdeba72c2f882d4181ea5cfd0d5d98da293cc03a223024924cfaf93597b429081c844ae933c10a3421563a5dd3c1ff7f910511ebbffedeadfcc34553d6e4f1449a5104e
g: 75a165b20da1883ffb3dde970f8b469132c0fdedba3b203ccc3a47c52a2e8f9f76d6e393d32f9d52486c01d136e118e9e43e69918e402898d1caefe9ba433f3a0348e74450e321cb95ff7b55d8cfa535d308fe588975411d7fa83b2497da0219e7b9a6f1fd1a3ade1c21eefe3baeca207ffc4b5d857c260a4d627ac432b94b3ddfe360162320e64ee6d86b5e1684b80edebc348b3ae62b7b5b66b0b6ef74470fde9650660a10a8c3bf15efe4f98186ec672b366b45d34513d58c7ddd0bda644c50cf2484d4ee75d7775cf2e3f9661628777aa7fd2b62e109dfa54ef1fad042fa8ab54fcc7e5956b6a49073ef5166066b171241a29792ef6302860011e2281cda
h: 180
m: 96916f7331921d7d15b53212d84cbbdfd33681a65c56dbcb8feef5cef8509b185f5900f30c432133e99addb38dfe4d2c5cac9c
p: acc8efbb28e8da47f9de7929366307b75b5938c38ad8ab1bcdb31090b45436576c298ab952329e868f37c29e7f192113c8abce875394c719a006a4088b34e71f301210e928c24e3822d7829dc5385e881ccb5bdf39b189c1d236da3c98ab7084dc24825dbafb7df43a69cee0e984356fe764671008eca8386a8db8966e0dbb742c83b8147113142d1fcd4c4241a7ace1328910cc4d3ac885db4b4604dfd40e0851c1481a82f4f9b56fe007b6f987cdffcdfa1fb32e6fe3315309e9ddde55db6bd840887a9480d6a2e32c3ee29a09856440639fee6ed9d44785a63d03537713b40b71d09f76cdcd4bc121308f40fa1fb2ea7dde717eab120a5211a527ba858e13
q: a3f7247817ad7d27cb798f1ceeae4d8d553be567944489e6b8c8752d
r: af66424e5b6fcb0d02736cba0e75ed378f99a1a95f3b3dabbf4421
s: 3ef17b32767ebd166c21d9c00e05fde6055a2105d42974e72b82750e
x: 6c51aaad103ae26d436008827c5637058dbc0f2ffdd564de20888445
y: 27efa706b08112bd843147886534106c8a81a2575db36e2820d872ae1c2f41c04e709ff4c877d39893ef54973ffcab1730b9150386fd26faf82e1f9a96d58dbba9a4b2d0057ad84c558ac19f6c41b53632688451388e34c093c8bfc44ae25be56328cf1663e3d7ec6e7bfe630426dafb9caa581859e84d25e39b892479f1d31f6de6cb7c07b44fe3c8adb4f4a382ea9e6b3c46b5b87202fa3075bfe3ef5fa2d1da81431befa336a84642edd631db356565201bdcf3202d7d63d71b5208b225a0bb3e6159a9afdd1a4bf2c562530eb9a20ebf4d5bda79cbe4e9d9f798ec8a334c1ec9e98da604b22f7ea6796e84c0f3ae4bb381015f229bf6e6bc0a3af8dec49a
g: 4359bd41e4292cf74c7253050deef639b08a68f65df5830ac57a0bbf29ae902ad82561e6791009076353fdc37ca277a4c5de2bb00bcfeee19b5b495f4ffa923d6fbf316e1d23e19f22696956effcc9a17cee537dc142390fd9fe0ba905c13060a047ecf39ad06ec60086d0b446b6f5c4352e1450633090229e56b2eb8b892294d06170a929bcdbbcbe917cd3394a3c5fc78481752dd18db89c578d0174c41ca79bb92a90bde56d325e34c1e89cc8d525da66664f7a33c56f97d2a8a784fe1c93d09912b47cda6f7b12f690a03c24956fc8f8b0f9f477221c265b667008eb2f76e61fe3a92ceeb527d6f3a9ea67b2ae133cd9f09560efe2a6f1d97f66973aeaf1
h: e0
m: 2fea6778d7dba18b06f4e928595bf059a3329c274dce0d7c6ac50bc6fc76821b8be30743aeee01f6c0aacf5b51ffcd942d5bc7de4943d3e7d3cc697ad076d49ab37a62b554ea1d0ce79e7fa23ce7f916e5657ca71d10768f37195cbfb6b103aa7134100cc84ac1ebb9547ef4738b2bd18b6b74f93773c8af5444d7dbc72c4389dcb15d21a9f5012e9f05aaf623a253f597c2ec7b31a4ba2051229485d64209834e64d4d717d9bb89103d4a253acee2c47d0e69a05685047d0fd5b65ba64cd76cbfd28a88ce0f049575673b43b22a826e4431e09cfc752b4fdb6bf0b8309cee7e8e
p: d59970c58c826ce041ebedc022b36759cadef19191b1e4b9e91b4cf268e8271262eccd89023cddbab79ec1eaa96c641f38735fe55b3edf6b586db873e6e1506be69e64b6c2d1130a9e5ef21acf787fee6dedceb1ce905f9fe797269fd995404f6af858a756039202a96b7e0e76a8ec3832be59a80ca274d8bb94cdc54b2a7c6937f40f826330bc6b7b2611c3bd5c14a0999e04568f3a4bc78158338339875ce076a293915562621fdde9eaee54563bd4abbefb4eab4f5bb79ec173dca0240151cc39f3ebde5e2c2c0798fdc75991ff471852104fc737cc5640b6e9e20b7cc0d0a209b84f420e441043f062cd9414004a59c331dc1cf8b343f1da02dd9c9dfb9f
q: 94e9c7903cf0ffbe3ba033d6de8877b7d47db8a6983c636819c8bba5
r: 561d79691648a72b27836ad8c1f49157e2b4c71a191370040d644f26
s: 4df8bb38ea60c7b410105dc53738e7503dea0cbfc23b5c5a4f96eb7c
x: 3c7bf4ca0d03cef2230eedc9795a26884217de929d21be27fb13caab
y: dbf452bef538267df67c47995e880c50f378023accbf0979118dfa7654e36b440f5010c17d0cd12329aa0411a7d05e3d9808bf369984fd39dfef4ddab6bb409c0d3ac175fd7eae084520a22365e68d86a44f96ea5f18c2ad8661078f8c2e382b5965349f8c667c24cee2f8f5a024bc27605e2f79b0fa8f11813ada77d16e13b31f51f69b66c0b9fea6883397def8daad8d144fcb8885c61bdc221cdfd41db877c71b37b0e56ce0a507c267fba57e487783319e4bc8d014d03cdea99f285dd9996110ac40cc7b36d13a6de6292315baa24b8a1af64fa678040b14f7a0b496fb97f0d4098c606ee9189abfc665c208f2c450424600f6d4a3b37b870b1ba60abb0
g: 10895d8026f54b864ae07953556fa245b7f19bbb88bceff9011a9a2b11ccec3057d2b52a2eac52b4401a63d964e1516b21c929fce9126fced58c2b8f7f9b759c78717e1c89e35dbb0998477470727f283718d7bd4389e8eef14828797e8569b13f1d7f0ee9185d49bdd4e3a027b750ecce01fce1a78e786fe728b7b793317cff15f76e7e5fcf424d6587fa3553f002c21ad48b1670ba6388b641d23de98a7a86794778c293f05bcf12982bae3d3d9949518f0f3ce1dd5192dc0847834d8ba605a477f861ddffc7aa9b1142d817b5aea351fc2d54c2430a70bdf6ef307aaf10a6898142d543113af3d215bafca11927c3cb07cff23f40545509db500979d30d81
h: e0
m: 3ace95ef5a0daac71d18c85f0b94f603a6477d3b91edefe371e5c06806d98e6eba0c4d43f6fa84feb13716912bfa8ae915b37e964216dd65c411e7784492fd0849a654d7139df78da4b8a212b5cfcd3bfd0bafe8723df2718202d90b3d0ec5c07393f0dae3c3eee54055a2f6dde877130a8df9b27c8feb0d937e5c97e8a67e219a129483f4c754011f0e029ead6fd0e98bf3ebbd6ce6253d4c808aea936db4bd6d
p: 948282365ddd8782118b1485121f77fa39412eb709b8369c4928d505823d10f01094ca3d647ea59c16b4575d6719bfe15f3979de569590ec76c68559ca759d8e9ce7885c538d610c5ad6c2614b9bd8406745114f62b0af236710aeb2fdd22d9184b44d04418b8a63f592e98a4027c32211e95c6e047a44b94a18a4529e683b48d459cb589db3ce85b2909abfe24f67e95c87dd2dde82d9415e76905a465f53182299d5b37097e4480d3699aa4ca70c3017c9a91edc3e70d48bf0a584112999380f31918312605acc109cbaaf557ada1a3a8b83133b1f33672f9060e40553f4aea6edf68204ca308c1cc8b0181f2d3342145278a7dd898ddb2c9046d59b41b485
q: 9ed971bff80e4b4adcee5f79a668b4f352d994b3d36b0114d2e441ed
r: 5a3127b5b3531883e084e7b62cb8755ce064e24151e8c13326f6df7b
s: 209b627f13c11a78513e79dadc859e98601b1d08917155fb5377e9c4
x: eec072298e13e1294698348b46ade14db17ee5b35611f1e761d9daf
y: 5771feedcaea12efba9a26896fe9bfb494049df1c45b537c7b71d476d96906a1b6b5bdb5e12fcc529ee6b4a284fd376fffc4a9a72a47c78f5c69c561c9e2a3926d239acb728887b67577b4f1c42d90270e588257f155a74ce3044386c89596a97d6579f2df2567c96ee4f74bd096f09c91eebeda1fec018a4b8e686897d4aabc8fe2e5aec887dd95287fa1fb446147278f99fb4368e685755f7a0cb3817fd356068cff3ed2ca74735434127543524c74d422f6540d8c3c4499b65268c48f99c20c0128784e7ed111b85c08a27c31175c8bb74793b1ec18ebcb38a4da36858e130f7570d7ee9b4ca76bf4dc3a9e2a7fbd6a233023d8fd575eb588957361788542
g: 52944a0dcf9e340dd2e4271b96b522ff35a42161e666566932eb0525dde9002c1ccff21f66fa7d2e59596aeb2387a16c7ca79ed7dff2b775e7bb1aaa83edd18fe3e46bd5a819dc62017661d070de533114cc1c05fafb4d46aebd1e1a25060a969aa471c1c9afd3c91cdeda55d62f427e95fe7f1277f9f0c6eb890d1462705d34265748672e94a468f2011355456d670d30fee0bfe2584bb938464001d6dac4e1b1f501d5b23791a381483aaeaca3fb48282a598c6e6060a6df64b05867c886c055f672b22d25a09fab4ff5195fa9f1df98fa52d2ba22dd033e7a1800ee15b248c422349fa55c7492e03f15325309b666d69036a8e671df85c28494d96d0ea715
h: 200
m: 37cdcc98484c6777d56d0bd5e5a4a70f7f5a7fbdb7926636b7e88d5cdec7f9c4ab439ccea5a06ecab597dd0cf345989e1e8f1b3d0271413329f3cbccc263fb481d48697c2b7c55bc45071eda47abace55dbc3fee3227dc570f936879e7d11d8e854d00d314f8adf1bc67dcd48362540594ad2fb339d51c8dfef221b3041fa4a78c766500b48deba3e8dc8f7766e55fa20e21b0a927beb28bad927beb0ee65097b2127afbdf841ab0f05f2fdd6bd2daa2927e6cfb0694a1f52e8a0a9ddebae9d8de29119c93b358d7f7beb85ef7b946792adfba4b55
p: b280aa377395c7f3168592bad72d37bea3b5c55bc3afd5372b0c70fc4d151998385638c48e1af154fdc8b70e6adb1539fb47fc4b29ceb5c2288083d8d0a18899023bf67ab479c084f9680a109be2225af34d21e7f10714a23ce44a87539acf2c9f16890e4582304ce79d5f34a7d836c14e3db53385f0d0774c752b290b6b4faebddf21faf85aaa7facb5830401cbadcd72231dad16bbaaedb178d247eb1676664a1a8af294e9f754b40bef500a00835d30f08491f5efc0744d3f8fffec35d422de6b92874470c95e8e0aba4aa0ed51b37a568ceb8ae4b16f62aafec195a545a5bc717580eff6956f6ccab797071c0b563ceab3db252be451ff62479a8e3bd007
q: cd2a24b2753302ae9a711371a1f69660cc419abec32b8949ea7490d9
r: 5741a5c49e13d3eb6a0069992c249b6b376a14aedf3119e8b91256ca
s: 25a958e1c3f0ec6ddfcf447833897eb6b4b6c21dcb0cc836276d38a1
x: 2c867afaab859531c2daaf8ca5ddabad8396584fb7f2bbddaca1e76b
y: 722734f30b8f39fd7fc121db75988eca86032a2cbf64f4f0cdbce9c46ec198547fa246b80197407864b18997fcbdb6562de25fa039399b1ae5556eb3c43023b0f717e1a4aebe5eb2e9aad8b53f7f05abf279d0c8c85f2a08c3c094af9bd2ac0819dcc71fa7bf709d6c5091b9fa98f1fb622b36d39dae3b89f3adb3f711e7f6e9abcfaa388a47eb761a105d737348e93e2a8c2f75f622bd216edd4f7088c1502f040109980d88d52cb8ca07c437f882d53995db24c8f71ed1c46ed2ad7744ef7d95c395d7f88c7a7916d4095bba70c4984e5eff14ec35eb7723f6971d2ec8d974160afba8d71b665b5bbf4ede74d95b1c0f678b939bcd7d30f793dff44ca6eba5
g: 24348254dab7d14747206fa395219750569e2b1eede9ad5efbd4e6df9a10a8574b62ab2c699079fe5df04b4b9c9429685ae4f65346a70992ab3f100a68a741fd0aa35469918e039e541e73df9ff846ae9eedf1c0f47de14ddd37d73799da478c1038c2322820fc2cff4ed5ee580098ce2887638f8f262794f3ba0efaab07a5a22e3a51d1bd1c777bc742f8950213562fe61853842c0973a30cbae0907e6abc086abbf8993afb023320d43a18a743bf412537e066b9c99a30686cc19d8bcfb4ac91766bab0bb7da0f95220bd881d6b674a2992b9b1f783ce9aca7340d946ed3113cfe012e93d39ad994df238f8b8ef767c4eadcb8365e33091f898b1ff52d3063
h: 180
m: fec23a4356343ef6d5c45d70b5c90e26730eea09aac93653a6256c6388986b723406
p: de28d34df473deebda4e9160dc3d986a9a18886db1d9b5ea5d2ae6215a8eebf148238f637237ad6077dcefa824570ddec5a96e508038c0278ca03fe4bc53cd149806f6e367be696c475f018f7b192a0fe05120105bc759f06dc3b017c34dbe1e2af421fb9d57f9a4c54b89e6235063912076d8cbbbd636d6491862323065ae64feab23e88bb915ad60d95d7dabd85b64cc87690613a9091cd690adf67344573a60cf80f07506542ac409656efb99b2b5633cdb851998e08c9002bd4013acada1e8663b70c48f4868f8c3ec27dce60cff758b328f41b1260a4ecac959e2560bb862bb7f8c8c7c83fd349d174a7487c6e54880c22d7b09fb223d06b2e8bb0e81b9
q: ea0c2779a444f11ad4dd8728ae6c5fec27519cd858de490cac4339f7
r: 5cef1e2bffe95bd6deca2ebc526c781dcdf4eabb0794b04eeede111a
s: 38973f016eafef11f3198eda55ccbdba1a002ba485d426ba01fb4e53
x: abbbecead270c903761f9e75b4a6406defeeb3ec363b7d91edd274fc
y: 3c1afc61f4f7bc72418144049844c2e152ae936ae6fe166fe24b1372e2b6093e8e07686e47e14920142121110004750a67af3c1fc47ad9b0621887a07f4480991ccf31fe512d7af0d3e9ef9e2f0d2ddee0722eecdb071ca3a8ed6d804871800674a8ccce5e8bcb038e81fb7edbd48b71d96cf913a65ee6f8ceea1e326254c6c9856c3088acb70efcba98ad25a62f764e44440f69c3ecfabd3ecd8906379aab5d86b07eedd9385671769bf6edcc088f2880555f2097de6ae1367b8c4fac2931fe97aada2e368aa71000bbe8beb876df0d73917d2601be1ff3abee887483b2746554c2b1ccaab1d7a7403cabce90835724ff550860406fb1db325225b04c19425
g: 5b229550fec5eeb79799312897c9d67a97cf4ace799cbb327ca884a14336a940f5ea72098021a3c5498167cafcf6ef5838c60843a0a90a4c8f120a8c2a9aaed08308e4e5e74beeb55dbc5b3afae0a45f5aeae400673e35966b8ca5956088cb0ec92e12e36ed7dedd10769ac1e2f0d1e198971d1e27a2429cb48a429a85b6e479b4bffcfe26ea94a01b9799b1bb0354447bd0da467bf6c8927b8988b5d9e73db50d01533c77153fba4744a797dd2ec09263d017c4966ffbd3fed208e5f10fb2196bbdfbcb3026f8664549eb5150add6f6453e9e476230b689f691f2fe2674f85406c64082c1281ac1340868f49d3ef70617cb3adb5ff139868da50b7b6571bffe
h: e0
m: 20f668f0a94383a7f8cfe7b5d44a892ea6e3a782120535415da9eba5824398efd1e603f9da14d00413987fec7865ba22c034592772a76617fe2a5d6a037fcc18e0720610702e39a982a079198698711fd1a6f60a9b15c374a259961832a95b99ebfd
p: a34c1e7bae0105d4cbc858a93ecab000effc5f2f3532e359241e0d11a1ecb889c3b7385722f946db89d21c6c09d7a47dccdfa2adb7749d3470e47bf18325559f45014ed3914b0b4a4cbb103a6ffb0ba25f67f33caa4443afe11242cbf7dd855a550796332ca3cb557d6cd5ae35b86cd0c092b7a1608aa0b7c1d72ef2df8678ce8b0c7355302b8269ed8e431cf623942476dd2a62823ccd9ae54255afd38be5d8742c8341e38fcc936b875ca645f97a7a0f3d253720dfab9edb5dcff3da12c14a8fc8b0e6a9d8bc80106ba9db5cb26d69d72a53451fc096d302db7232bddfd27a05c4ce01583c4d93a99a228ba4af839cddd63acd2a3896246780e979680e8c79
q: c7b19561c22b42a8a796a87bd4547fd31aca5a75b820a027c70f5eeb
r: 2671b4a2e397a9c62ca693db7ee272a70bfae8499fc40769f1fcc282
s: bb7434b0dcfe387f2cb023a62a2a660ac1494ec93b3e816ece16745a
x: 2a213ce1458288a3bfdf99dbd8f83cf1edbecdb0fd6a8308956fddba
y: a126c1e0403fbb64813e289b54c953f448cd397d98682ca7c182045a708d892872b70e397daf69efa4cac95d7e48a0ca5948ba0ec7facbe8a7b47a2c25cbf644a69d2ccc27bc8b86f40d7fdd393cb3add069eba49550a671866244948479b6c4619127f5a897d5f5609b42ab3ba22ff74a7f4bfb2883d5c8cbc6071ea87e9c557efcd6a84c90246b306aad6124eb93189a13f6669000f73e51066acba830d55ef1c1115fed5bd8ec196d7b26895a797ecaa4de70abde0ab6f6ad9836656e98cbeae16625516097014a5f7e0374f3d61f27377c922e1a576c12a7e39a859de9492d79cda74e75c0d9e65cde3695bc5bc933aa7174eececd3fda0c90581df71705
g: ad1cda5ceafc0f2b6e84bd184afcb52f90a5f7fb0c01d8c328106a88dca0d7e07603b88fa6d3b4fa7d188800c9f38a467441dd0573ee0c0539e7c604a3de7bcc0e45fd855c1cb5cc6f3408b475ae8e930cda83c751d2e2e2d5941ed9e7535476271e891bcc41c9cc7525818662f4d424098925f7ba5f944f940217ae20d9637dd3f656228f05aedb5dfba34400ea4440b85eb46fc171253e73eae0c4f04f4153cfe6c30a03da578608ed5575f860234cf7229f1dcf2812b13c4ed47fe53b739e1c704bf3470e8dde36c31daa1280c824ce573cf73559773164c251185e5d737338117c1636c3fe4e21e35fa7d33f6b0485cf3d445c6faaebd5dc7dd0ccb74a00
h: 200
m: bfa30f498a006f07fc8047ba4a506a1684f314012a723a527fa1c3df0020588db149af335a82ca28bb86670c54d196511be1a1c4e599c15ec988dd7e240fab25d478bd6ebe055854ade6a8ec280aa4ea517e711612bed2b1f8211426ddf3277bf99b994136e94aec9724cce31f69141e8b87c9d43f16c3fea3f3593b30c732eed46b202e559a35e807769ceafff631f84ff1828b21909b1f632a0452b374c650097c283f26186c5f43e2b2b87ad6a6c116076a91545ca8cd6e1a7ae28983aa26bae52337f790292f1cf89ac1a9ff4ae75b78fbfbf178fa740b7f45022949eaad50c7f63dbf7c
p: b2de996abd7858941ec76995cce8a695dd67d4eea4c5dd6b32da5d709fe347358dfe19bf67264b3ce82247bc933c8bb9d87c8d5cdcb13783305c52580da0fa48bc8fc3444e38fb2dba430de4dac541f7658ee59fa0f69756c287fa2b7ccd036c094a0178454d8e729f3a83a237982ad7365b6644d75bebb3339f77417cf742afda1dadaa582da89d0efb9864d822b29c05e25ae78e6f4f81f0450dfdf6966e7615cade8f94b9497f77cc17de70e426291f1e2b51166f2dde0e0fc9e9bd76a5413aba248505b0b82d4bdbcce4bb901d138effd67d491324e43586919ec5b098fbc2599bc186b3010d22e56f9c72b8fba5b68ecc39f85b8ece879719a0c2f812b5
q: bd762f7640b4ea7c39630176efc2072362b522e09fff305c9a23943b
r: 770a6ad47ac0908609c86272170c5d7673fe33551d2072cdadaea0a
s: 624c5d7ab0811768e7d2fb2fff8008d98f3e14c9885f095607e1ed27
x: 503f4e1f7a511c41290db2f0c8a99b3de8eff631ad8efcb0f693353c
y: 6f3e788ba66e87f5da758bde843d50aed13a993d95d27de0e016ee823dfcda0136f50a0b94e65b8b381f6090cdc4b26602719bc98f5d415612a95569b977bab73374bed374d832bc7af0ad3940e9848671925ce6f400715ec1e9091b901c95a8026de3db8347e9fe1c8c3aff7a0a943c980628b4fea4196737664fd57ce584e03574a10294950f243620a4b08705e6bf2d14cef5305a5691474e069d6bbda3691b456e7485482e9a4f5befb8c865a3ed2c4315ef9b60da922166af3b7a27bdf692f0bb7854928cb1205c90d4b3a468f48f76e9751d35980bb130e8f5d42a1ae9050dff1198d968f5c50dbae9abaebb492c41d1fb3dbca13e72a53acac0816d6f
g: 9f720f2ddddbfae7343032bf74328dd259862417f649cd36d3ab6e14fd686525c270125d67ded2af785c657792fa38403eba552cf6beefe2369353817eae539d70d2b3f1ee090f171cfe882ec70151df77ede0133507cef2c7f1bda2883f33589c1ae0cc20b261386cc665dcb3495517d211c91ae6a5f16e3ec95fa58dd5e30e3b956b7f3946334c8883a2bc76e97d65cc7e7d2fcab92bc2ef0ab3503be0beb8feb1503c408c7562c05e0e717b9c3b9e2f009881eea7ba3b8e84b24e822c430a2b5e64f902605a11adfa427dfd7a467863cb1316ba716f4a1231954ee5aab2590a9aa2e19fdbe6359e604d6db50040a83bee54f76b2404e1811ca48575dc60c8
h: 180
m: bef23942b2d53a674c7d1ef31fe5412e05d13aa91968d753e0651e45f258060f7abbab91b02515747bca4aaada151178c2eb763b288ee66e1c6a0b282cec44e258fb2509196e9f919c7fcd62266a441b5fa9f86e70d1a26959afe624730c319074a102b790abd7c2ec45d92f727447a98e65ee36d746dfe2548362be009c4dd8d479b87021edee43503ec32ba0813a9c9af2b8d196f1
p: aea4e8148c729129bea8c1bae82c792c90afb761713688220dd6cc31b09803df8ef4d6aa894af28f4b10da2504cda0a79785b3b01d8e517f196651f0870774c87a39835d6df61c10265db6a1625313e6342e8bcae50bae778998896fbebf02443e139425f2fa510762407feaae35b0c8438cf18811b69e15196505d82ddfb636cbbc699b6e8dbc468173c1c9eb75f7ce9360f80d98869fd8b6ad4381e67279cde4f73ce62feb91bb9ad7c6198f106dec6957921f5eda9b8bf3b003c2ee5091cd065ec6781ddf1a45702230fc0b7ef2efebc0ecd74b3bfb01c994ed3e303f7011dd56804b7d090cfcd27d358579ebe9b4b7a39e727f29fa09349e41c3f42d8719
q: c7667ec475c85e475f4055a2c77b5d44a42fdef88ab35341a552d4b1
r: b739e61d474f513228793dc4665e4d9522c93c0547f70d6612bc25c6
s: a736a8a51ef57d477e4bd7541187dbaf69a7284d08e292265573de21
x: 9e18bdad63f10c7926d99e043997eee297250044cf96b8b8cec3e0a7
y: 6dda29ee4fa436bb8c59e01a94209bd1b234e079a94dc696c04d13ce3b43e407829955deb1c49c102c8487d5e8ba4dbd2d6cdf56bd4b61c83595dda202e4e523eb1ae250fe9f6b76e5ccacde147a0d0f75cc841c15515ef83bb9eb5d516d647e5223a14765f8b9b2756c9ca2e113a746d93fda87478ffc924b829e9f5b2cb8dd1c63e0c60bd6819a8c5df4bb64036d35ae08f1e557cfcd9341b885519edcc859930a42cdf02db0aedce712b8125726e1ca96f22170c258a4533a31425b619bd63d38d9f121f4cea178e9410f6e16dff9a09632165de95ed3dd19bd4a120af1e0314a80e0a8f0aca48972c450c9eb65efb467e270fa2c09ec83f4c8c88cff95ae
g: 6ccc6a3a6e950cba7c4d01c0912d22cd8528270b2cf99d5d02d5431add6838d0bb13430a724e853c37bfb175eafcc8c23a9859ec55a07ab0eb37174c3fa4d628ea1d40a42b5f3d76351ecf8d687b4746780d733b52aa56d43ac32b3f5b9974741a0357414894085a67efd2b26409f41956bb0ff8a48768baacdf14c5bb5c199fad1db3589d07eaab84765cc32ad43e2d25c457e6e171c3e823eb7e540db0f9fb174b8c128552be562bba5056d2a3dd6ddd69532536d09c1239d0196a8945c95d56ac636c9b8cf622ec2be52df99c9b717de78937c2ce1311db9ec5a5f91e00e745e170704e38171299f851063972a64de76a69a1040dc56f4a6a43a981fdca89
h: e0
m: 547ec5b6b6bd4e
p: e49e05ae0d98d937fa79871a0124e8b8da5771b038765cd66e5df36b02dbd8fcdfa185fe54f93debb6f5b69678bbf647976ca2eda5e15100bbc8f144a27cc593e6079bbaf86d708e238eb8eb3a7f8a6408376657d390864c2c5d8306cbad4b6942a7c21c657bc5aed7fc2d8c8cd08f55dbda93f8ae4fe59d93dacd2f2cdc14b2e67140edbad64bbdb59d5bd8441f9b6af9d9019402dd9ad2457070701bcf51057d2a7a3f634e8789247c407704f59c83853ae6be3d3777a7eee021f42d940ca4a6e3f381c17342e626c45ce5d9c059c8b22380ef7473f94f6cd471ded0ab82a4b3e0a35a940b414a321d7fd09e878e324a40a90b55048b89c74342ae8c8bf193
q: 8d39c1fe21169a8ac53d32507478975228fe5dbb47ff02e08648b307
r: 44c0b43f1e82f68a4c153fea0a80c6491f831dc16f5a279b51a90391
s: 6b87473bbf573befd373d0f05739f1732a30d9fe1bf5399f091f8b3c
x: 11d912f44f94888e007bded07c0c0b1085b7a06995a7afcbd57abb4a
y: 8ba13000ef4fb7080d8eba8f652dcf82596b8d64463e7dca533af68f913e2dae697846362426ece2319e21bb1b13f7d5ae1fdf7f5acc81805eadbc3111f4ef810e25cc9c0e878ac739ee393a15cf047a4a0af95408bc298921358c1941c04869eeeda102c77dae198e0bc03f85455197b0c27f7923719d97294a066928744f9f82d446c71e6673be048c33434b13a42e5eb46a270b3f7fca0a4c8b31da562ca643d0364fda6d5bebf26a29a2664bc96df6a2346cb30b367d6489fb7d2d8992b957a1e16626c2898b8b2e457a5474f581f9003678a951a92d5e93a490348b11a201635793bff22fc829e7ba2af6a9d3c6f330c21a01283b5a5e0e8e1cdfb7a29e
g: 24d02260b32536be094a53205a113d8027026909d9bb8aec147cc74dcdadb3a883ebdbce8b33e78aee6c8729d32537118ccfddf76edc35323b87eef2548d1610ca2d47943e42f6eac7e48d56c27cc440460dcb3e58b23de3c3ad9bd110781b4dbe57349c70419fd24c495e3b924d1cc60b4aa814cced9b5c2a5d59640430ec13684b3534d447e1c60cf43cd461f72a07c79521003c0d24ce4dc5758957973c693ecd1074753e2a8620b4fb45cf182854fd889633c00d211eb985dcea8b59caaa02df8c9b0cfb213fbf19c536b444223bcf643aa76b183c84490fe65599815e9de4f2201baab1783eb707793a4213987c55b219b24f6c16ab0693b948f80e6b58
h: 180
m: b150c2118c1df086c44a89f5f46ac1e4abdeaf435ee2fcbb6c72d90047280782536aef0b6141600f9bcedf56ea09b60036bca9debed0e7b4b91873407b3eb9794e6668c99c8f997dfbf8eb34ad85ca199f804844e60a3419c710d2e29bc374f1b84b430770781909db4a5e15e74534ce0ff81a2b2f72793baa62e5e204fb846d1b46227bebd772e10370b3c78963e984808b589b7c5b9c3cd88a423c
p: 870c0792520dc2fd9bca856b2cc1122160010b67e74f122cedf31fa36a4ea29a38bbf025d62b1a6b6afe79bf31b824335387c5a2559d4cd2af13792987cda6d60951503fe7ce550f0a0f589b3f675074e6dc0db3dde2941927cfdcba0c9eb3997a35f13352441059cf14375357a8dc82c05eed2bda04f832302365ee52bfcbc5c8356671fb244906a490bc413c12aa0c2ae0719659b02a08735a89cc42e1b0da99c6aa14aad051f3b6a3a56d02d4501bb4bdfdc017b46bc79211519f0517cfec8cee0af4a437ad7862a074883b6040cfcc0b3d4b2d59e2e9dae299d3d8be0a2784a5cbdde1a3758f731b994afe1c6e5b5fc5f74720ba5141453cd0799fc8ae2b
q: bbe17a324adfe8ae7c52935477794d19b1900d59d3088fb540c58aa7
r: 29a7d9e218e6bf003339216927c05cd90d4d37d4ce58d26706ed96dd
s: 89fe2895db21e4733c5f637633f0c0d79d56ceeed749909ff6696fb3
x: 64fa4dfee78b6d8847f0161fd2d26c04314e7753b70c806b4e632555
y: 2e4a4b437ede304daad0efeab79feb1119111d87bd1dc0f98aa9fd8bacc37bd2043ec095e742238fa4479cc2887d75400704ccd8c967ba2780ff9d47c189b4fd2a3cbf00a68f88ea698dc355b69121a4d62c08c0c5ac1ca5ef5cb19e849fd00023549488683805bb6f63ce96ae5bcd723c5661668f3273a693680982f162174db275cc8a0a071653b565e53d071195ea39d6f94410931ede20419b337104878560efe1ba357cb5cfa0d87f311cf4829e1af228eab9d9fb891db708522af104cf610641804ffe6e0624c763d877666ae46caf5ef648e2e6deac505a9ae3837f0bfd9b8f5bd6a2a9729a5f01f84189dd8891359dccf4320fb2e5983ba1e9a8727b
g: 75d64323ea53c568b87322faefc3849d7ef7b8c6fb1aa47e71a0c3005e1c9383ae1790d7f68bb486128155f19577c971ea28b67695cfda51b39dc0f5f5535e4dde6f06eddae53489c8bcf4567d6307447846398f27aecd72cadde56370bacaf4283d95e6f361c1e2695b0fd8dfbc22e5f2a6e6fbdefa1ef3c75643146941faab401496e69d5a0d56d8875598279dc017f3efc4f640e11438f235cbb496372d246049d5e901e4404ed851714605e7f06468dfb739c328ed7d11a569eb1f3b383a0326f6fe0d043a812a96de00a13ceae3e3e9cbd118df2f5e9ec9a8443e36e641523f9b844dfaaa54e2d763aeeb4d53e27f15bc695214460eb4147b8e26947572
h: e0
m: bf384e
p: d80499caa0cef1cef769a2320f0c04136bab4940d4acbcefc898d1e776799be624bcb5ab57e677079ed3b25d425adb0e9e888eee1d7bf5f83c11b184cc80390353990777b042efed9a261672f5d26254815e77dd399a3b40f7c7444c191d187a3f307ebcafd2043070776d57e0ca71ce0f8856c3b629a26589e2b77daf30ae1a63ec68a3057c673638a4e08dd50170a465a4857635e2dc51b1dedf90c81bfa94720d1d0209d8063003e3991903a4b3fb87013affd1dcd9aba87e3d4c4c8cff62f52d3694d9d98996021ff22e2183d9518f001dcf5222b5d2d99fd2d1c6c44f1d424dae10933873c78cd2057fd820a462d54c02985bda6c02fa84d5915426dbf3
q: 882fda1bae239cb8c0dddbd407b81f8f97ccf844fa553f8fe4be956b
r: 4a989e11a3b887e41964b360339c3be052396e063125a96a1658275c
s: 6f0e5c344f4dd476a18dc46e60c09ab8be50143792ef05b0df43a514
x: 6e56d6b89fcbe580617fcad2950646f931e13d4ce0d8806d1f9a14a0
y: a3722cadcac122a472d23f0d3ea0c5a4992c2db13535b2929154012b12024c40d4016f22ff3343d57bdd8030411bb89dfa1774b88a2cf533aa8531cc92c05e93610f5b5479d4666ff1dcdc1dbf00601c5b2e441a2d8a6f054de54abbadb84875442d149d8ace871230bc67014727aff14e1c104257a6db58b3a066b69310778b7e2c41470c92f2e2f6e270474d9cd346e9c07105b55f15e9eb6a280132c5f608a95292ff20e6f176bcb4e3b454b34813cb9b614963f902ee3906b54510bee99acebaae5274c72818788bb22462d75cfdf1e0c085eef1a61113de867dda6c858cd8e50057477e7d9461ff91097133fdcbba04f12dfc7022e004a4a9e72791ef64
g: 87cfa3bb1cc15dbabf2b225167decee1480b8c89f9666b9e0cd39d37221e262190cdf82dded05ce000a1c2a11728385eefa779a56e9fc8aa9b81620495039f53cbf5ffc3f5080cfc301fe5e1be779aa8d71c06534259d6589ce7c201f9e517db5fa1800a5cc61f00abda46a9965761ea7969fde497b5e986419bbafdd2b53ff311a1be4093a749ade4ebb6409364a65e24c8305c57774b3ce464d2b37d76edb31894f361b2ca8914e4e738a1ee142f79e3f1401b7be42098b564bc5997408c298d3d60a5ecfc0a0f63cb5100e59750cd2310c9aefdbceaafdc7b2f0837f9dcb1c1cca5a0e160685f128fca4c281f163960df10c4b8d79bf21a8000f8b19a3f52
h: 100
m: 66017fa571ff11823f5dde2e72e48d55a67a4d25191bd8214c22ec25b167f17f16b913ee8bba7dab1c44782338667bcdc2b92c2e2ecea951a8e613665ebfd996a2efce1ee8a4ab9af26c154f112de2cd318324ffc4fef4bdaf997a69d6464f485be11864b950765d9e08b7cd6f05afcc0095d70c2af1dd023a9921c989ded4bfe4f7ea2972a2e3007471b6adac16529fa6e3
p: c9017cc101cc911f7f7969122cb35db8efd7ad372774bc84913d2d16614a22f8936c200711f493d87fdacb50b5a906d1fa6f1d96748f9c6bea278aca7e083a1ca655981279ed5d6cd61ab05bf66ede546f61ac25df55bb06810a2ca8bb29f8b9d67d8b347de1acdd2faab1698cf802cec24014804902fcbc8bc941d4e50682ae69959001b24a03e764aadacadac5b7a0d26184a8d464eb37b16e378ff5e3d0e65815994f1101b132f188da2351fadbb6a52bb01e7ee3bbc2b875bf0c3974b10cf3f5d335b8c91e294787addb02376b32c6dd1b4dee08b142145d66d34b89ec8e21510d3bdb4b1b29b94905af6a41f42a87fbe77d919050900d4791005e29869b
q: deeca54c111337f74a78d8149b05528b38a5f417101bf2cb6d692e49
r: a30aef48fad8d9b9514d69c0af32a0089c6e9fb629b63f000bd9c256
s: 2dffafafadf39d3b1b87cdb84a95f0d79f762ec4614767740bbe657b
x: a06be67433792c022d6c170621a6c89968a7afcb0dd513524ee7ca76
y: 60a5b1099c07b8067cd41d5e389fff4137fb1dbbe2dbf016213b3ad4ea1073b654cb7876d27386352a935598392f0723a3019d2284c7211538da25f419bce0fce48fcdee3828c3446e7634e9c1ed0928bd4dd5b07f927452e5584ff93d66ce5568d74eb51f0810fbfdb4313a4dfe5a91d296454e76613cf2be780797ad0c5a64f23ccc22d273be2bf39efb83a345218316db8eaf0f93ac0bd96e453d83bc8c7567377150db9a9327f823644e0400be8b76565a908044b1a30a03746d78790a6d50726d4df97e7e57024162df16fbc11efc29ef34972565b6e634f90061ee1d652faf0ee61ac2ec39da1b13804d645794c8faa1948279b995b977870ccc0561ae
g: 65c7fe976d82947960c4d1156c5bf92ac3c90283521846085da562b362a1ca1bd1d98a7a3dc4ade86ee9416c9be1d5268275796aa517f8af3effc432b429ace3c9f3b0c71b0c88ee062b2e27517972929d20c6501076508dc6908324d90086fa521e393c87bdb5c735ed5826e332683dee742c09b6302027d23544c597f86413da5a10f62e0d21987b683a9821d37a6c30d062346cab48af6b864617e1bd1917c3625029f4dcb9741b1e6e3d7bb2db592ad55e71ab1e51da891764d1aef7c9236e50d6c4407856bc12810383ad2a5989cdcf0d9a7c4d33cc8ce26e0ab8b12053202140d5a366bcc46f36a0e5182a6db043c81b7ad49ebd7630f0b2a55ba814c7
h: 200
m: 2a286289942acdd9044afafc7c8756844152f5edee25b172fd8bc5753d7615a3110b7a9226decad5b21ab5b901a35db84e51dda33f8cdd8360bc0ad264ef7ccf6eb426fc85bfc7adadaa6c3ba1f935364da34b3137f5722cf76aef99ea5268c87d1d3e524cf07c3cb1295b63ac43411df41d7ffd9c53bc9f
p: df91aef428570f4b57bedfb3eb6e8cc693bd836fe42714a97051a745ac8ccca3d34fe4fcb9c2a6b0a902158040a1b59091475215feec3f372c0ecb32535f3a27bfc6ee5fa0b82b6cfc2c4bbaa2f7b9bb2fa1bc50de2386768c4e38a1b16446a33168680dfba73dc505da5b3a0dc46f3d2de07eda7fed186fed3b5501e2dcbae365b79b0963e45dea6c8542c832b326696c6fae7ae9b0745eb7c1480e21f87627a1bf31bd4a41b26deef364732fe2949f1fdfbbf6cbf0b51729306ec3f13ef14475796b09d153a12ae213ae8322d53a813afc777031e8ec5bdc6c9a2ce2dbf3270966dbff61954b424a3e53153c5abccc8675ac71118930032ba2c8ae970ff8f5
q: cee328da11f516a35849de75fa51c0ae9dbdfe3ea5bfe2f55f7a6b03
r: 41bd0317c0048d46f200050f495797048c694e6433504d486ebd5843
s: 93e710dcd2e257ac8f6f166692213047a44fba8b24e27a3a7590668e
x: 984cf5a76065019b711ef6b5ae72d1bbffcd9cca79e37c4bcb00b0af
y: 7fd0d6268dd833af64148dc33ab4224f8058e547bcc3b268a2064f51afdddb037a5c01e0d9c2c1bc19df22de5b8767fb41654b108615d4a3e2a6e2170c7b971ff6c803ea858b588713f398f0ccdd99ac4407544febe42dc88a2712836d507844116f149a4c3c6d96e8d602d357c1322d7c7b9aadd866e397249536be9f4d0be95219d302e84e8396473313742768cceab366b5ab1a330f71e46ace15d27a2bdc240015aec976b24791f071df4fe17b0bc058106ae77d7cf8c97dc12bed26c549b0764855d50942daf43c2d57e86cb47b33012ed235d641d09387d07ab7ad9756e8ea2d328f325529a40253cb2138ce37a3edec54ad025b0c8bdb2c4d62559f9a
g: a9be072ce0597f655c690378793da14dcf1ce650e373de0f1af5e1aebda1ddef4500c42dc01a7ea69a89a90ef0bdc6e22e033932dea4f8ddd772db76f8fc06c9bea4b46f681d064673c54f50a8bb1264cd6ad1f0e7fd3076a3b218be4e09f3d177805c7e4baf11c0b3ceede646f474b61ed062819946332d4443e01c9b60236293f530f67a7201e01166c5b4ba9b142cde3205fd52356adefdef6927f3aa74bfad2b8d7b198fcd585a522a82b4422b7b8a9f1cdb5947b7b5742bff6810709b77887b3c03450b9691022f3223f323920af5e9c7b94e33dbcf7814160062326dd01de5c8659acee04ab27b37909303bc0f25c9b2375b8689ece7aab5e5ca8a3d2a
h: 200
m: 03e2e3fb98375867da816add8e6d4a82eb4ca778101fce0baf67b06c46c5f131f82772db149f95e354590d3a2c14d532c86f1702b42dbfd4d5060c094179ed49fc787707fa4cc2652541c8b3256af2aeca0256a60ce70c05baf343da1b0bccc77f7a15b4b018cd341e4f80641af7fa44b7db33ce23d112b0736b96c3366251feeec284fe743a7ffd55da0e481cd2acd971f7b3acc4757447d0fdac7c1ea5238eaee8cfb05f8a52ddb8725c6a8a55f17e27d0eaf50caaa8cf318c44a49b222c2c84a9f27189380096af3f21c0adbf92c543ce5cc06a1ab06ea6a51dfe1fce04a23792aa61
p: e3eb6aaeb1b25c3f3078ad1f9acf04a47675b1cedc136bfa87d7ef07639d7a84472b74c64d2462cdf94fb27abe102d3082bc9fd987fe5378a3458b159752e1de6f29df51b73e1163dda3e228a7350313d05e90e7cd5b918bed71ff70d2a9b6925a1eca4cf85090668a985ea38a43275bffccab4c4b8983461c9f855e0ff249a13e97b5e0a42b3752cb186e1024e06c33e69a5c17a196a57262e324cd976f6f71838a21914ddbe46d5dbf9439d11d27ac8afef0e24857416b43332b947dd7d46d8ba0bb15343d614a2108f582fb78fe32301189ec04d6368e4b13201bc762d8007716a86f8003f6c5cbe112f359ea0e848115dda6ca3ddbeb2a82b573817116df
q: fa0e632b3da513ae32f6945311381dc0b8b2f4602f69c45d2a613c79
r: 7dd67a091087c056f7e0c7fff9455c8717b8929491186ef22a084161
s: 3edcc935a52abefadaa6cb8ce862a019f3560f930449c6993481726f
x: a383e0868354b9474f3308274ec3cda9c00757c4eb56f602be31d6
y: b47df0d129b4cea76fc54829fc2b2f731794afb2342afcede8865ef1a2691e395fe1c4878f8243a16ed3438bb6dcc4f2f7a885a9e8343bb10dcada27ff68d6dd448793adba320eda2158ce647a20b0d01ffd8b563068cc515a0ca14eefed9d89127ae34bcd5c83d6bd7a94ae7dc2028db0125e536b3ff5bdfe984b1b25a16f2c90b33e0022d7f0ca7edc55361a308c2bf51656f622edb05d5b3bf40ca5ca50497ce05dc27a8d132644e100f8cd62736074f599732241fecd416566f85ab35730e7c0d17e5283c42808085979111235969a167ff719f07e50f3756e667b6e0d3c6709daf01c5fb7cc8daa0a935c9221c252fd1db33ad51979d2e332b9edfae6f8
g: 6ccddac671b83941e71f646b9c79d49557f321be8d3c12e6bb85ad192d1087f4ce2d1a0f50f3bc01fb25040fdb693e02bc2f4a433058179a1e55a53aad116b2d57df58b95001e883c6893b77f733bd61df324a861cff3eb730124839b1af3095eb2bf42324d4a731e2e1d496a520cb3fa5939d162c86deff3351a88149f0ac3072a37b2a088996cde1d0b01d8a9c0504d0d271d92c6e5c181359aa556da45cb3b41e92c972a411126507802211073c96617535af1126b65ead2fc04b1fd7a386908d60e7ea87f31e31e5a4389a6101252e3cafc98cabfd77d7b098adcefd5027bc6a3ccd4f12760e447628b36746ed78dc2c764d515e4655edb57fcab8256247
h: 200
m: ecf0ead39c463b473f5dc14f5bc0ba7d3fd49c0e0704e71e17279bf9a4f95a57d5fc318bef02c8c8c9cda539c1cbe39d15e03804326c1a7640292461405558a215c3ccc9f3d4137814180f31cb638993ba5b1f67842f4939bcaa59a893bc7263d3fb5f8c37de90bf57c93fa0f446f7c650770b62026cf23d4c3e2eddc4fbe2366c73a1e83bb5e7c4d10991d9f9975d56139e11025f5d1878f080a065ef74795e23689e6036482c92e0a06a873dac5618995b9d51d1a9b88f9b1fc28d2a13a1379eddf682198f9cc6d81281c88129f7532af7c3d775731ebaf3c328ff5c913241dde4156549fd1ec4a17cbb4c7d9c
p: aa4f0f1b4465a34d2c1b1e6a1f06744908745af870ee626d70a8b64a26682a7032063c8238dc2b49a6d46ba4c4f7935db689bbdeac9924c655eeba70fbadb59f6357921f48b2683c07cb7185d7333f38575b951fbeff8d7e26034eab1e833f400b3123233ba3c77dc6382668f094ae42d7b62e7dd74daf5976f8bcd0ffd2db75c49744f21c58f70822674064107ebbabc9da9b675ff649a2d5c26c98a106fbe3075a77bc68e9bb831218046bc7795a7ad07ab068a7c9f64e4690276a43f93a3423ff387a16935d4eb2367e9f94c268df6c2debcf59392d4b9d38d0c13f432771110e2478dacae7f1705563de33891e63c4fedca7b40cf261c57768b3f88d680d
q: d824d48630ba78ce49c0ab4d3c5ae2673f9d2e314f89e14d7d68d15d
r: 5a80062bda389b2a4416906fe797e7e410bb7f5451bf616cbc9c7f00
s: 856bd4e2e5bc0dfb9d2e524b1d9454c563dccdf7d1facfaa8e0f6420
x: acaa6a3a87bafc8b3b10bdd8c0ee9f81bfb72a8c21ae5dccff0c7574
y: 53b5865e147464c8f36b74c0f8616bfe8ca4e102de9541d630b849367c174535dc2a03e1a8576dc22ae3eb1826e0c0f52455ed670f7472e243643f0106d812d31480fac0821fe6801eedc6b8983e214448da514a049474ef848b9443dfa0ff8299ca6f4d5aa292deb830511882fcf12ab0a27b28eb893298de8463fed0ea2549c7428930fd949bf2d633d47f8d6392c4ad7cfe377ee31d87be9ecbdccb731d783409a1e5b42142df078e74981cd5cdc95e8a5cf3187160372e2b699350c67a9572e7452bad8fda89474c5355eed20b07223b44d0152fbe76f035878677b9807450e4db62d7d41375f493a926c3e76208b9c36fdac19aecb18ed83ecaf820f8d5
g: 870052d6f67b4807702c6169dd6c3353c5d5f46aab6b72f27c846c455b1bf634762653246be07912b5cbf5b9bf15af6e3208e8cdd305e318bcd729d024f29798c0aa250b0065a2b1d8b49ff8bc53843e83189ea261f7fc04212968c199b52312a4b946c0bfb72492c298cd5f1065627fc8b975824c4af69180dc33ac7f1f221ddd8de7ffade22b09190b195852680f1706abf49d13c5cf220a5a055d7d73ce9a24d8d0941c40ac92307e4f7fe458157539795192ae4c0bbd6ab6c6dae5240eefd08755ec48a2bc743eb103c02f0fc76983172d164ffbe0cd01c9d4c9c7c4002e7de59ea3a3f042b5b0349fc4ea483de5845b7deb42e9b353a01548822a2a9396
h: 180
m: 10f3e75820ea903122854d32e15052049840812b461220b60a7f0482f51c7cee03ff17d278f2d17e7dffa51c8f402f0fd418ada776d9c38b44b603a945397b63f508409122ba89131886fb7a75a33389cbe0ca129cd13273f96002b1a892b8cecd435c4c9bd7fc7de71183cb6af09e06046db11802c62d40136b47d3509bb509dbfb21676df2123c37cf6f2d71fa74d4ff4de0856a78c2504dc51b2dce6ee8456a43b49c7bd468cfa8d80aa886386970b0f0af419a7fb159cc46ede50f739d046727979de6bade33ca5ce45ef98dd6900d64f96d2d
p: a23a425464a2caa7d94357f27ffec09294e1fb44f638f22a7dc841a061ea05cea1e54ad1b5b806e08950575bbfa6c0fbdd18449ba73f566096e9733debce6b5a292227c4cd55ffcabbe57c0f381f3cddc93475ac22efe9ce61ef93adb92905579d0552e94786f297dc6f31e310c54acdf1a240c22b808866ecd89f1e78d72e82615ed5d34693a66ee2b05c9f1943929c66f4322b23d47c92c1869f76f4e911977e154fe8ec197cc95edbb3492d4c70b36fdc720ffbb0d9d35ba6b83e6eef91317ba1e989b63bb346f8fccdbb0d8e35ed6117525e91ccf635dcf000120f30e92e41b7bdb7719b3f0a9346fbdb0ce787848b2e4ab6ee9e84a087f7b703ce808575
q: d739719c439d4e5f60d8985b4b26a11f0dda24bfd36c50928eb61661
r: d5420263086476d3bd55339c3d8bf8be7f957bcb90be99d6a2d0baa9
s: 862918007c0eea2b009fe66e4693e3cd1b3e07baee85a0d842c310ae
x: 72f2abc751911ae780649680ad28cdffed45de61adb49c3d12351d54
y: 5ddcf7962244a259abcec9bbde726bec6318c6ea28a86831d5f5fcb671e7f884583249f179bd2ce947acf843bc871a848011ee0cc07158681573902de1fc8aafe7fce113b588205d9ed3ca20e645dc5f677cc90d058cc048607246aa6c0f3cafd9f7104b3f4951a122c8e7ef44963f911df7719b578fb119977cb6f7a0e6a2355e20c94da8fccf9df99af24c99f51840c2a4dc379a34838bd4972a2a71df51d5803f221075951fc791126ff54dbb85cb1ec2745b9542a369dbb30c91a68fb9a163883011a4d2cb11d74838af7f3b89ff75910672fbac9c0b483958bb720df2e4391298df4759c0d112e16ec85655398e4ae0352de55b99015d07265db5a63ccb
g: 26d622c515bbd2179944c8d9e28732454eed9d7c4774c41c0bc71780932ea1bcfe68fb629f6a3fb2ed9df294b97e5241e4c7a1bce749205ad116feb2c67d1c52a1f5236144d7b1733a5bb98aa3107f0e54b3bafb8825b2707ecd7dcb18be0ecebe6aa34e2ecaaa508dc5cceff9a136da1041c7bfed43b0e9781f97f3c9bf843df70c207db45d5bc234521d012bb9f8a18ad71a39018e1034b66ce75cd6325ea51af2cec370f3cb29682a68d70f9c62cda8f93b738ce8247d7c87fded0be6cd4d0d5d89fabe17fee92fabce76e8b31aadea9e05e1e63b2a96ebb7cf5a841f34e4ebc211c1b23c1a143e658a7337d5a8ea6de553e1e55ad2d8cb9171b41b2f6453
h: 180
m: 959c8778fd22ff7404169432a96b20cad155aae3ec8bec2467cea98550909ffddc1a33de9490352a1625003835b2e2a201db12fb285b216b5fa7ae308b45fc9ac97c72d4b478998a16dbe1670ca050790df68a6f8bc3f0d9b89ac03932c1a49fe6092fcf521a4070591e3c08137e935f68887cd368800ed56bf108b1214c0e5fa3637741586bbe35b99840dd9ebe9856128fa7eba2895e3eb910474f
p: 897fed6dca830b525e7197dcc462505366deb5c0ecee0b8dd86e41c99046acd058a09ca13c5d400f31a5d54562dd77034e73d24c55a9056db6e360d87b9e4b488e4bccb81cf4832823a004445e2fe18745a486d7971a97bb3aaa497510922ff65fd0679b221ba7bd0f1c8972bd19d68ad865e3de8056d963ed4ddc16089640aae8476a2dcbac5e2541d07d3ead334f4f82ad9c64a69c915b1608220e310bdf8351d8f54503c02666af38e40248d2525ac4676b3a694e95a447dfa9160bf14cbeeca3e817ba296b3874df43b3cfe888869e52077c0aaf4afa35e85614bf2da71812a83945fde37e3b9959f33b2813ce464fbbe4510940ecf4fe95a481fc0dff39
q: cc4d76b5dc27dca0f50fa9b0b85b67c26f97de6ebd9ca59542aa29fb
r: 6a20c2c5f5b5a3c44904b587498e774bae29e919407a18c8ac1df50c
s: 1a31e5c33580eeeeff765e8b70fc8193b4084c5e0aa004d94806e837
x: 4a9aa4be9fd3dec0d6f00738a5713053bf704093798fff301f4ee30e
y: 71b9dcd25aa3818606e7989dbb5e04516f411dd181d0a937c2dec0fe0081dfb7b9ce73d60d0a567bd42297e644efeb7fdca61df2956558fa9939b838b79320bd91209bec0cb277d1cbeabedfd239c41d2ed3b9b5f68c3bd32e71bb138759e19f667c461a16d522f1ac0984201305eeb58ffc05173a5a6017e2cc931804f78546eedbe69da0b7c2748cdf77636ef0473bca4beef2de8ce28153b9ca282a06514bb8ced0383b8665bffffef01e26478732e722b21cdc9b52558bed81f0c5c9b4fec5680e1fe090e72e740a6dd475365940a2c644faefb6cbecbd81c2a57c0b77f29c404fa53e05f7e181fdafeacc3d375897cf8e9f173519cf3adf5966216028f4
g: 10337c43b477e5510f230a78535ceee07135dbe749bb776810415514cfe8340a16a45d3b48a5f12158eca59065f1baeccf19816ff068ce00d609330cc29dca64f6ab3968808fa95056b3d576153b6febc23138925beaa651a584a04f55d0b7113e7aab8ded9622aa342eeac8f89b0efe03556970cd1150e40c44fae3fdc01d2866690b349ea9776045e4acf22982f18f7737f367b858c617c142f0d07de9231b59b156fd387acbddea610914b666593a76abb5049d3eed79a52c6b30dc5ac16d1cb7f37889c50d9a90ce89c77e2327b12be744ada98afcdb7d639b266f0f339c052dd994497846ddcc299d15a8757e3c1fcab33f65227dc7059bda459850ae57
h: 180
m: 499bbbbc79e51656368fff15e9876c31d1fbfff5eefc7df438ac553eed3821e53f4dd4db57414f72a65f71c406065d330d57b39e2a8fbb5f477c50557998e29de7134c3a30d95d5337d9e8f60599cdda2fbc95c6f240b97930682e8b092e05f1ecbcb8d0a9db308c514d58177b16c47a2c531861daa4fe9b176b595230f19a2106797a844c2b42438d217d793f
p: a299f58d3ab277dc8b7f426750e49a7954f0ef3201ad9e73c6a772f8d82fb391af4b4b12ecef240a4fbc664af4c77f443b6f449b937eeaad23ac1693726d88cf9a4d2597eff61cb884dab7c81c25ebccd2d4f77c5080c153aa2cbab4a063605fb71c677df5e719bd707c30a4c6d98e6814e8ebf4b65910f99aab6a19705310a5df460659689c4680ca89c04334cfb82e5bcb56379fcb28ccf87ef28ad9c946b77d309966004aaec1aa262819990a3e5207200758debd7625959e012e081ec2af78ab90908f962296d62faee66ea47168da2e6f786bd9dcdd7dbed963ec34e582a68c6c563dc74c54509a8ec3189d866d1841931b08212ca3087de19081a1ea7b
q: a156158c92e1087e2311411d59899b84602cfe24fe8147afe612b075
r: 19da8fd681dd05eaa164c76bfa898118a9a11798b636c9195886f4e6
s: 8a56ed8bd2acd2ce4c8957dd8030cd0a8405f755aaa968aaa136f6d5
x: 4930cdb1c058d93a3cbc0f48da2a90ed5a5fbafc1cfb19d6b53dc8f7
y: 9945530acc4579c9e2f8d24a2d1d108c62e7e88adab1c412713a571160057cc4f46b9856453b2e730e0cd3f94f350e70b5bafada6bf20073a01ecfa85b4937116fe09f36868be9f96ea8b9385dbfb5812550fbe5d0c7f00dbe12e5df66f7533079b4f55fa1ce2feeeaab3df86ad074caf682d7ae5f940838f2fb57ffa2700432e11e4c2a14d63ec6b7d718fd8993fb04957e12b046833f9dc0341b7e4acba9d92dc32346ef74879fc4b4a9e3c634630de3d7a32b5a14829db8c24f44442ec807945cf01f9e67af574a14597ca2f3e2602214d4494c1047e40b1a244f64a63e846746661186606508c89248836e48939c3832b03b032a2a0c8bef5e50356bd5a
g: 5d26063f4f8a1e60f6fb40ae830a733c01ecca3df07cb66561f364fdd227bd203d3b38075f0388ed2107feb8c95d86b6c976e6a8f38ed55167ea319bc14840c4521ff869e1aca2242cef6f97d920533b3c017b2910630fefd5470a3d982d8ceb48742356f045368da7743d4ad23436db91309331437bd8bdb77647dc28e6adcbe4b874aff4cb9f30ec0d92a205e0655c63d0be2c9c0b35d7a2e9f8936908ced6926ea5884f1f8534b0c5976fa2687bc4111007f1443b5c0aa67d99eb883cc50d12ba7f46d65de09cfacad981c4bc4036ce1fb32a84b4bab5cf9e0d04cbe0784d4b873ca11e4f6b2c5846e4c93d436d81eb6f171e855b76dd42a04791f4cc325a
h: 200
m: 1a4c514e6f77d885f495cff2975fb8d27364389463baa349bf9965016501279e043da73b019c3fc0b3763ed21df468a53de5a333c8e4b5795f52f2b852707f6774dad2ad6c7b861a849a3f36cad47e85d9a85b85af29be54f38ef2
p: 8651c980f2b9a6f61ff50b21da3ff07c7c3e37b7e3dd4b39edef8d84299bb6b1946a6cdb56fc81e0742dce8dcef0b7a7fbd8a63ec98c1deea6aa597d647b8165f54bd0874ab3985cac3aefe50315936451fee2979256729df379048fbdd702e66fea94e0b873744701ee20d45e10dbad24c78480f25b64b309b77dcf834feafbc72213ff9fc1eb1cb5b2a3594913a27b0de3d6d3b2a6c80df6cac24a16c2a19d42d6e3fa16036bfc367f31b4088d57d6eaacbe428601ff239f3b47504481989394692d8a3a3f172cd6ce9cc9be42977da1610e050aca4f9d89e87b2280c0c670ce58ee0ea7a78c2b068e9a496ff38b3a4f1c18a9df9faeafffc65a9bb873720d
q: f56b14311c589dd4c332753aedb70c3a50525c33e4264c70ce4ec443
r: be7ac9e696236a3c6f43a07d370337244db2631f1682fc517d904d04
s: e1808b7949dfcc5f8389ed4cabce3953f49edad6005d34381905c9a7
x: 82989b208424f015e5fb1ee768ad2decbf5d8e948a2c008a9bc06270
y: 77fc554a280753259d06cdc97926184c637848d0483ac4abd28eafddd26943120a39969a75fa58341dd8d956241862e98417f239c9a2eaae82870ecc179320c7a3bc546a6c88b0a70962655f15c007744dc106f87d2a4c952ac8b10c24004c11ee022bce91a4b31cb0bacb861232de4e0f85372a8d8d869757fdaca54718ac1596ca11640bdeb2fc42c9a735871c0d6a3d07d2a08bf80f51868f383a5b106132a59ca19c74dd24d1e6bd13cc00cd8eea871bec0ddaff15ad67478d11f30b2d72d22683514bd5205af8e438533c619a3425201ac1c3df40d058b0cd1b24390ccf321a25a186e8d24bda71cc735b76b0afb2d61ec50dbbc442c0765e9e3839482d
g: b55604bcdacbfb488912963ee4d2bbffaedcbc8d790eecd9f624f469fd978bd98d4650bc9612bce1f1f331ece2682d0881bd655972d6344049b58e2f6e370eccff71e37c062b329af65363a60dbcb86df5d8ed338e7efcc46e007b396cd5b55e38e38f523f3c5831f42a65f999e2b2c65f37f6fca68b27658b5a5b9067c95a655fcc2f38dab529c8bb6b65a19788e8c545c1483c54adb7e2d68b25aede56424767f7c9060ca05a602b71d70fe409ceb8153ffd2ee3cc42b5266ee3de79dbd9b8ec2e3823c7eeb6cea6d8a2e8e1402f604fda488f17ff24dbdc9d5b6621e96a1309b043f46f24f0dfef9b9eea64174b0eeee07378e9fef9f9b7355cce97860a6d
h: e0
m: d6b8f39bd05df380d28bcf646bdb703b6257b4233be8866843015ccd65c07bf8cf58a2838a34a81a5248bcc96cc01d45b08ea1ac96fda2316736440da765fb53318e720bff6afab7c9d2b97184541aa9f524b307b24783f2a5f51897cbeb14e14abe575d067ff5c5c5d44b729f9887692d1cf6d88d0ba2ae23787d1f126e6b7d751baf614ed5c77e01c220ff28e78d32c95b1106083a195a988e59cf626f210e5c577f44128f7f59540402cd76e8740eecb5f0a1d3d1bad353516f9bbbb2c69a31731ac6177649792704a4cfe945849f48e8bb03b96aa92e277c024df6b37b231d8d5549d286580d4eac00781341d2b91446
p: ba9ba55eac9e2d9d3c971ecfb3fa8c608ae90a9ebf580e67ee02e12f754c6eb912e5810f95ff1dd6e7f3258b339057ca28d9913e41210f3f50ed88d2f8c9079df53a12abd18833baa575b3650910c6cc9545474b53e61ad953d8690bc1d4d1850529ffd66851ec865e1e84033ef60afa2d1e2f3784b45f3297096458893476a68720163c723e9cf86005859caeb1f5f0622f93f1e501c7205292487f962f2aa14bd0f5c9d8f21ef3f70e2fbfc2b2901c87204cd430d1cc6e755e548729689ba1b099b84c06eac344dcd62552f73b33491130fabf5df5c3b7c8eaf472e0c151a65f0f7a2e5b80ad3bef2e3a83f1087a264a78437907017954445ba07c3b6242eb
q: d28c838fb1af5f837faec31f9fa7cbaeb413a05da20e0b865cfc0437
r: 5041b1dcf6e79b46e0c1863b4b556817a9b0f56dcf6db2c19313b1a
s: 6a004f442294b7e7a058692ad67e94f423b55d004f93b0a929000a00
x: a8150a7de89514a9010c7cfda8832705dea0badac2357dee732ad340
y: 4454acd4d4b9369324c9d8834919f1a284f9bbd63a364c56cb01a4a5e22882adad02ab816894e880565b695af1a253636b99edce3b2df155bc28422308fa70f5f20fbd09826bb3dff0bd2ed6100949ca346a111f97c51a1aeb46b6b4aebfe7df61868ff6c641738c51f926e607c5795ddc9a203e578e0138b523607f12f96bff805d1a8deb30ece68c97964ab06db07a38ca633e4b0dcd1f3feec754754eedca917d5ffd2ed503ff4cb92a2751f282d97cb0d4b3b05f9d243d5788a80c01df81d73dcac4721807559fbc4730ad85c321eb2ea464000d5d89d6f4174dc0015c38276773d0382f359364979c5612f965e33ec8a6bdef16cba505d5730d1e302e51
g: 7c3bc89ec219b37f14792421727b7a28a95fabf502dbf398450fb348c7f217f79faa26b95b92c2eb4f2ef91b043746e5e4d04e3cc32540a1c2ea4d1fec03ebd4bf3759169427e8ea8993c90ee1184d098d70eaf7233419260038d9efea3a386786f255ac59caced17ee7daf15b6b15bda4b2cefd5e0a43a691be2cf91238cd234fbaaa69c97cd4dd756f8a20616424d94f20baed3f9fe58b8abcf34b933ff2f0513fd27962cf12510909c611b8c02792dedf229ec1debd14f21be566cd902d21eb114b1cfcf1180d45143eda67cc0ce0f0251f9c2d8508e0101dd60e2da26ebae08c1bf759db806186a770c2372fb133efcb95872cef79fd9e9799078502d183
h: 100
m: 1c28ab2e2ec84b62617ac510db59c43d4815810122e9ea90ee9a84cd832e7f6fb191bf5deb8b2a57655fd6e5e7d03657406ab0f61a7f5cd5a676a54fe775ed9a563e7e2a94b9c62c64f1b0f6739fdf6cde738acaee9624d5f32a586e7b504b9ebadf55aa42827ffe227282240d49f0f046b68250b31941784d4c9a848f93b615d7a7ba0e68b4d7812ad678d4c476dc52f8ac9e8184f4d632178e0aaeed654f8f78a2b16e7a452959dd956fc201584767ad71dee5f40fec96403586a030ef2abd6e58a477cfd5d3adb0ad4bcf110b1f80648032fe96
p: d5fa68d13e297726da801b0d27987a75f7af53e82edae203248943973376db0529b555bcc7551da090dab460e756da16e6e9eed28b979b3745ce7bbb89bd673b4d287680f3615fe0528915a28ac3afacca400bce92792d42bc4d5a5dd49842bbb4a749c926b6efa38fdaef23957ea10bf6b7ed20deb2fbd01a12ae8ab3b5e22b7849d851bdbfde504db275d6c60bf94e9ed5eaeee45079fa7dd5359de561ea21983a3421c1afad491d6baae56c816e611ecc975b073078c464fe653934b9a9eec64c8c07715ac22ff5acb9b22cd762bc661ce73fccb91723e6ce168f91ae3f999fff7c7e34c0cd0323111f8064afb64db11d4537c23adec4071cf13ddc307277
q: 82d6654a6a5dfa810115facf190cafa0fbdaf7058ae1ec6058a24853
r: 2ecc267656e94a88114418f0715f6861f83885d5275a12bc136bc02
s: 69f24af8509e849beee2e38051cae4a1492237e124c282e181f20fdb
x: 105be11543080821326c26691132238f49cecab6bd09040570169076
y: b3c7c0f1a8fb683d786e87a8bf86a811f7b95dc8bf5b6bf1053e07c33850cf2aa963df0dcba35a8ba6879244f65abcc077b75c8dcf69d8143b889991282a210ec07d6b127aa3ee3442d6e32099c0c6e8ff4bcca2a598c8858f416e12834a7b6256b2794e11a05f77f3527ea876214a3a027783a509793afc5242f97ded6a25660e80c0f8349cee906da6f4509715b15260ba21d4ec194d5552ac81650b06e27bd8aeee22ff35afe55cba69da33ab2f252b39b62df2be59496383b60d9fba10510966bc6780af46e26c165e09ed31a8741cedcb08c3768f8142b84045af17e76a325781d446696dcfe869bc5529879f0e4910673ff637c9bdf7fe355ae2811d25
g: d24bfa14d1ec20666f72eb921e540bc6c6df53f8ea5fdacd1c1c2cdb75707847c1b2f9c2ceae7f82116499dfaf95a8f19d2851dfdbc084bdad6f4e77e2ac48540f49460fec12ea321f3f080a136c30306ef6c3271a941d44bba5957388d858330eddfd098056e45e12ad4f7f43b2cc98eb157c1a0b22035a17e92e6d9d7932766b1960e1734fe7f1b2f72914402c22e6733051240b958f65ba8ea649e51c85b791d2a3c51bd372d15010ea3b6c19ed805415adb75b80327eb952411fab2f133b5d36c9863f08afc01e3b57925ab1acd036c5717d96abff7d2501afcc0727d03df63a866a4e45422778e1ef4d6a716f1cdb1323d474840754cd507a9e5282edbd
h: e0
m: b87260c6592d0df5263b4dd4c2d6d4b219c8750830043f708b4498174eb78293775e6eaa20df7a8572ab8f3bbb
p: f60a8cc7a06f33e28b6accb53c1fb8578cf9c7c1195d00f802dc035c2b9bdfe8933b807012ef9feda2a53582c88a00b776d63a519714eb6694714349c9064c7664befea687b46ade42cdce4d28c85a2b659a478b40df460b0f275cea53553d5b0112d503fb14e43c52d8cecb78d84c67e41ea780cb87521ad417cd516d8e79f011e822cabcccd93d2917ca9ecd3c2befce50a0d01194d3d7320d8658f7cdc0b48299fda6ee3f94aaa4667be56a2243daaaebc15b33af79f4f57501649221148750e654a6ed773aef71ae3a5a7cdd1c77ee3e7cbbb8d37962549991f97b76af6bccb5d1a8d65ad4e1863a97a1c27d2a992635d38a63b805309fb10c73ed85dbf9
q: fb17afff01d84d71057e2f2b5411f2479764161ad4ced285c66703bd
r: d0b65e62664a2e035ce9e9dca72d87d492677c9afaf6aab0805193b9
s: 3d94ce41ececede3f3b1f00e6564c599430ef8db68ca0990b3c5dc5a
x: f62c07351a6745dd4fd5c1b526805cc9cf770c675c6d31f610d825d5
y: 53759bc7b20c37681c00ad1f1f0683a51aaba7349fca6dbbc7a6c5eea9807e100ac5c25924c008da4c8536a27169565a2bdbb2b81e839bfff7fd88d705158a287e1e129b46e30fad315c5cdcdf58834c58193be10742226473af027111b535399163a2bae02bbd5aa5c03060b3fe603f72c872976c789cdcb107013da6fa0fdfb610375dcba780e163512ba34b6a246f9c3df3d1520e947921f8e84c47db220af3f21ad622d2d89d5ea944210e0d49c02a494a957b3c610ada20dc61b6d4ef20c4271858eaa818809035c8029a833665835794543682f0a1415b6448b610d4bfafcfb3cddf666043d8b237c011b4d1c0ff88c0aff530a95d75dfc0026e2807da
g: 3db3021d30fcc265b6f4459b54f47bc586533c3b9e66705b1de75aa4c99bf9542af1d503f87c725fb60fb01c3b356e2accfd878d87df328e0532b0b5081c896bc654980a543f43d4630c6c7994736e9e791f64e844647c640bf0ad53a73ddc615746c4371eeb2a34d322ec36a6fc405c0b363208235295bbb268a1b4664c6e8eb98333f427e2778858e9cb5d63d9b4ab3f7872b275059301913590d8ded70a255c715eb5fa4c1e29daaf1ae31a41d98acd97a3fc8855b7a8313d69a7477aedf4d98345f191202a99b1be23c245529708daca00566761e6a181721e9f6ff4a2ba25f3f1ea16d482d738da36cb56b5a617f9b3b35c80c4180fd9fe5d12a7699313
h: 180
m: 2ba5969034deadaf4e4815f898d51fbcb957c44bf4cb5386a03a3a3e828eb8ad92e96d60d6fcccb1e6bf8b0acbe124237bb67b6789bdd03964b785ee1b2cc4529c8aab3880835ac16d2a
p: f1013f7fa39fa8d0afbe5322002d2577f7b081db014c5bbcfe9503b379dcb7227eda0032e56e23c5090cc814530ced2587efed95887de95fcd0f4e40a4d0b1bbbe154628d901d06e4a6c69072a3cfd40b751da88fd316cc1b6df712ccea51a981f9eb20c3150cae92c847ede6f837624f7354087628976ef77ba9efca534ba0539fca779e40773860b5e9a365a7a822707f2cfbeefe78753331598a1215647b57ebd7649e83492c533c5f85af81261647ac410cce4f3aa968383374844cf95b17d730d115ca12a9a78279cdfba785ce92566ccbfc22553eb18d738b9bbdc28a79a61653e77aedefc8177bcec4d5e2a5d3555a5ec6346b23f53b9bfbd9989251f
q: 8ee70200c95034a6d07e9f8f7fadcb5c54ddf8befc6731d4bc01797f
r: 7d07c010fcf91650bfd30e2ed92a515eb0816d43f87f9bfa54e3fbbf
s: 8978b89f966ce017b87d9a4a340aad284f12cc9e0d13b9e59f1afd83
x: 8465720b3e3f50818517634584239b80e2b8651a46e7acab84510d4f
y: 24f02fe60b5eeb43a5b82ef899828f3b4373f06e33f55ba1517b531eaf15947db4c99d3eeb363e45db40c7c152f6955859f3939c2eb7a9a9b00073c00e8455d6e20a89fb911a05c225d8b62bed7e049788f96824147904ba14b46d6077d0823bbe314e3abb1ecc9f926254bfa31650a9864db19664c31679ad9ab44fb028cd9b0a8c1330a340831bf326ad52bfc5c049459e2cb2834680e6c229f9c235d29066c5cd795bbbc234291c0488ce48f9e98f47b2f75e2ae671d4000da85782d9303583dd961807c0129f79bb1938c920c2e908c6071575ade4c5951759ababf8a1d11eb739227a95eb92c89737563004454bcd56b17841bfe7ce2951de6b61026d1a

View File

@@ -1,459 +0,0 @@
g: 3723294e8a68d2de71190ec5088b8c8660ece27710da126a0516988fe494da037a4592a3d674b3784c09e9f1c6874e86dfd99b16158a5a0f1f7d792b7f227e56ade3d515b6e7e7c8824202f9b4cda90b52b93b140101e2140d0217f1d99c01fdddd16e79551ff71a92d92b18df829bcee2967576063c6f204520bb66e26e6b6b039de8dbec0b18b6b8a075974398c6fc9e7e550029ec8da34c29f9a2667e4b837acb18845b5983dc8762f96cb6e6c4a90ce4b8e29a42a5e8b51262c66ef34d3b98a12736ee29e9543d493142fc1f1f97ba333c445826d9bcccf223aa09b8a3c648553feb93ef00045b4880fc4c75796e989955a3a4d84df1dc5817c55668d135
h: 200
m: 1be605ec89ea98c433af398370542efd82d9cd0ca3c9ee935eae055172
p: c15666a4eee2c16b2a9f986ce8dba494a3a62d62748c15183a1c9c162adfe081b42c55327f04753a80673d3d42e394247d235adccb8bc7913f0616b2a68a5f7189b531bec32a031dca71f432f5a14d36be825466b5d95ae15819f78c378f6a47e8c946893c3663789154d17a0857f158693f59fd1c188b638652dfc5e77dea49f107cc07e3be1db267b8194d1e1e72e7fbec4762b14017cee8413d8441d4e3bdabbc1775f1b4e55bb68bf30ddd80dce5aac25f23f7ad111543595f811f4c396621847f1e42037b8fb7499652bc167da4a230cc973f27077a66278f608aeaffc4ebd6e37b7c86ce518be4c7e375ad6da5bbeea0509d4b9d24767f00988b29c12f
q: e7b7b398d905b948ac0bee07a494fad5f7e7ad351ca8c7944ae41c4c7067b657
r: bb70ab67d4c9aa8198103010c855c2408206cd9b1f87a38a82da1fc4b81db02b
s: 4615b7fe007772d68023e3c350827ac10b59cfef328da0662a9939cd9a78ad2c
x: 271afc425c524a2022a8ae3455cd2d4b8b071239b770dc27b037dfefe821e990
y: 7c2b885e2d6b3ef2072550b9cbd5b62736e1fdced6798fb791e79782ce39119362d6ac850406148d917b1efbead9cae36896c463c8497c64b4f695d3583aa47bdd10f2862161610d30837d5e83ef1febd6677767bac51fbbc9393bd504b54a7b443802915179858077bfbd581771c959ef387fe22d1d7fa952364bc8e0e7c7167f28be470fdcf5c09a41be268029a2ebbb75afe96aef36b0628b92a7f91137823601251539cf06ad4738aead2e74c20a8a8a4f7f413f92113c89858b699583ae7e4f0af5b0ac648cf1d1801d6320c53480e653e02868590a86dbf7bbfc7618311da4a17e1ead2ddf9169ee86ce31186feb7a351d9fb8548a404b5b9737d639b7
g: 4a44b54b97efd7f767f0e824e38f75680e22fd0681d828a8cfee860d774ee274f58b4ace823caa487447412fd613ff0588dde6a0e6260e14544b59837a4b6e5e6f51a00b19a7dcda938b4de916edc788667ab38647dd674191eec19b7bff2bc4bb9b8d746deba9494aca7aa26eb85255d75b1a8ab16dbfceb624b99c43c30c333dd567239a99abe155c7af3d376b879963f7b04f146a10f7b2531e35a7a12fefb534ca41a957a3845ee8524e930a3c7f18278c8ec0bf519c9bf7c16ad030a0adab9741a336402f0b84e0e93efb84a41f3d485ee0a599251a986ee931d3e20baec79eccc09bb090154a817d243b58ad914c22f2a214cd4b0b15c058188ef3abdd
h: 200
m: 4a0f7282daf3727975260c582c04727db4a86d4562aa336de8d33276781da4d87f157febbbf8073ed1f3123feda9ca68eeb7676508e5a304f790ac0f29f65b972282f740b0754735487d1355a6f4cf6837834b24d0a198e9a7bb19bc6074f6edfaa7d260e1f0a9b79d7dde951bd4d25bb5eb06259457cd3d7384eecfa56c14bdc442aa0db053966e1768234d4920fb0d1f0707a5196495ac4b2186001ea8c3c71453ced898991ff248013183852e16aa9817e2de7c33
p: 9ceaec731f3c706a5cdf587f4aebd1862ac7ff15397afa3fdfc6c4c537cf04236cc44d1bad4ffdfb325248ff1e22dbed732f1c5e6291b0772eba18308cc20f3248ce62b8c0c5df0168aff913c75dc414c10a2c4521a2833731d7792d3acd528649be17d8d9a7b406d17852df6f308a9c916e6a3356b94d27db3fd05cf9baca2041d619a13c2363fae7cfe8ee32455a7d18516fa13a71d88db345df5fb7e8a97e1e692d57e1a640f07437962cfa7963c2b08a33c864ebb4f7f489dcc219887f526b7d55b7f4b0df7fd503d0bb6c0b4edd079df38b286566d18e7351fe5e34dc808fe9d55c53038b0dd31b53826d5b54ad82a1c464c470227ce86d457b2dc16da3
q: e74b4e501b0f6ea8c0d8a15d85f3b5741a8ae8893798650cfdef92705f730f9b
r: 70f062c9b247f93531f81678d9004c0aab1e7d96a2b607ad32c3cad060143119
s: b1402bf859da0a66e88d9af1600df1f68a2723993f47fa6563664f8ed95dd5c8
x: 13bca13e53fc79cd885b51d2c8a6c243ba85dc29826644c8f0b3bd2d012e72e7
y: 176220e3566743ab3b9bbe4549b955e5f57e58e99d876494f293439aa4f80041290c6de45d36d3916e04bbb7bdaf952ba4d3329dcb19074ef5809ece64a37686d50015e169b089df38b25a7b4875ae983cb8a3ade40fb0804f051891783593245b6ae9d26a6e70490bde95230b148e8e8efe2ebe7d3545782b40c7f54aa595f5ea591088ce89fddd0dbae4af62ea78b5954ec9320c5891bfc4879e78ea2bc599136a3adbb6be5a7ed372bf62b75f28034879f1d2451f32175664360f9598c580d099902ae21cf14c5dffd1a635ae44e17740ff39717016a3bb931e9e8ca57032a1a3fba61aceb7de9a6ad6ff1b385d6b10547ee901115fdd996e14f2ad303ed0
g: 5b132511ea4dd82c71fc64f6a7ccc6e611ed1fb5af214ce499b90a66c3774ed4e83ebae110b6f1e87f1259403a0edf05356e7e2bdc0a181eb28b98aff10ca01439f802387e2d40700cad758ec6ae44cf7798f81184828949f034dbd67118e5ae23c2b4a1a227183b43dd4a912abf283c68d7e0f033441eaa31ab60d8bdf27bb127586e38948f237d73075bd80344f7c386da5717f00f90b6e5be73ec95a19be8e27f9d6fdb14888b7a0beae71efc47d6a8c116e48c9ddb049ffb54e5c54317b24429d36a3ab3c78149eef997314a80450d48f3714995dec29fdd553cec1049be3ddf6874dfcf14db52d0942afd254dceb835b976b5cec0bdd7eb5e516a7bde23
h: e0
m: 50e97b87d28d30a9038d39917153fbaef05046d53d4d7e87eccf816d4d37b90c3364e17a99
p: 9101a8cfa105eb288bd3f16dbc89b262c89a6204aef37400d434b30320a35d4beecb2230e89a12951b6719ef7ff650dc28bb9bce7ee93db2decceae4932a5fa59ccb369cfc39ee054998f5d52c7294eb304cfbb6988d3b3bdda6ce432f9fb14ba22835fc53ecb7fbdf24332fc28001f549f2494ddbabc491e49ad1538825547aad6b263c867cc10495da172f334ed1a4ec1921fa04e6c357c674f9e91e2ed806916feb2e29b2937dc5d0bfdf389b91e4766c71af93f39159ee6c91c1dabf3785089732c6b09d40e7164bb8c991e8d930eb346eff2ecc98552ed9ac59263c18cb7e24f7c7ac38b666b117031e5e19e15eee91787754a4d781df81984f1c23bebb
q: de1ae692f0ecca7ebe72a0b96b8f6f827213f991412e83b9dfa044363806b377
r: 8e2d8ce7183a7daed0019778c980e8b895fb4e34cc201f4a435247a42d892cb4
s: bf32509a7563a6bf9d302f26b09500b2e3b8e6d6c4e1b9fad116b582fd032eb9
x: 9086a90f6cf02f95e89a514a183d7ca166d0f9dbe945fcf874f61e7a9b74fbf4
y: 2c50dbab1a4d301d92bd4e7e216b284f31c22cee1ffb67d38a9501d3de2da3fe024f0bc316f29b5876047d7f4882ac970589510022ab600936a58fbca8263c99b741fcb6dc769b1b016f69ab0b55a0cd84f799759819d31626d0d303126d3aed7b55bf87752abb9752394151363ebdbcfc15effe6dc6a25989df274440106316b08fc46fa020eccf0cd198a1f897c7a26e47d1b608a61ec0d3f1f247d9fc8abd11120349aafde3a830052226258a99049f2cb5e3776f0c7d08bd542ae20bbe114e3f1f16412b23e1e23f74c99e963fa5cc48d11a483852d7bbb53b68eef63a9d22b4146475bc588e3d4ce695eeba753459d14e10f4896c300a8604c17b123ba7
g: 20257c394ff38518fa4a14ca49d20d45694c6d392d6fdb2d2033ba46707249144b1c29206ce08fbc6b40683acc99a4acb204b14d44f4b61e0f04dd106d63571fd6df8fce235a9f290e17c922e07e455f620a958f2c436504ef0909e7c6cf579c457d1b3d7e6072db792e74bf49fe2f9da2d3acc3b970691f9ec64291d672e6f1712ed6f6aef2f5e6e3fc60f8215a9275a6311b85e5f707d0df3dacb42da4df99c7e3cf98b575a0526906bee226343a911c573d3e9880804e80abb88625bb407b89bf7d01d69cd89992a6656cc0060f1517cd8558ae6cdb8729d75482c4dca2a21ec4bc6cd03bf6d1c5cf250b7958190221e99d7db7d52d1f9ef3c62c6884dc37
h: 200
m: 64
p: c6c8355600809da95c969ba155492dcc4a2c51e557eee187d9cd9c5a9bb8e8a0da1aab73dc81257ce0e0d8bc17ae505a813c0625098f5d7197528e1f8ee9c5af8251a19e5b53dd8bbebd8d54d30ae34b90ae83f39636118102806b49a8194536d131e1b2232ba79ab9d1457d66d6ba108f765d1e80fa71e7f35826d579b5ad6d200d7a1729270216aa90310c519777f073d80beacad0821da043d4cd1a51e2b12269e688287e84f93d0899d399c83d72dbfb0c1c81662a1ff5f877c02c327369bbf9127247e7c3af1faafa28f3d38bb973dd7c6bcb4d47359dbcbf041db2fb2dd9e9cb610bcfbfa20d7ca463a14c6bbeb26e825a2c060000c6ec231a6081a691
q: c2c4fd73ae948ba5a72f5cd49e09f406955fb9395649034b4ceda56c519a14a9
r: 3319b4722aa1cc420ae7c3cf1caf936743574fe1ed8a35207e934eeecf27433
s: a3d548621a10e9dae0b9e8477c9a6e1d2acd192232068aafc22680b4632bc563
x: b45f87d480e81a633006621fcaa5c630ab8db6bbdd2a09a93064603355748996
y: b859d1fe410ef7b6252d58a5181faee5d7dea688fcc2866fe5ec6ebb21b2df4c688579f66f62ca4eec409a38bb1b334f65395b3f9826dd868d9a982eb15e6d1fba578128681d64c6b87d83b9df138b3956d48da1c13f6c82b10f8d63bf943f1089191b04cb0177840e61cee8f2d8feacba8c8e3283935f16071483d5c786bb80c6588917160cf0c676cd8401a1f2970b4f8b476c32e215e5cecebe28c0247cb5b028276ce134f136c8bd0f4d93bd856db664f3b199174a818c03f7cb32fe71d82763e7222a6b693b3f92f72d5b6bd31ad730d214478037bcda843bad9fbb8d1fb419e637327e58b5da9c7b76215cf7e3fccad03ccb35a2a17519b46b42afa9b0
g: 72a02738cc0633576e7727a364b6b1c85bf89e1b6e58527fa035dc4399daefadcf83da7a853ab66f2250479c459bfbc3bded589975143779063b3bf9f2bcf166d5f521c4d276b19bddf710eb4f21d0b032b5c74f6386d5a6ef7262f627bea61b18c0906ff56789cf70387768e5ac3a0dfb15f48c18ecf136d3fa5922a8d6789aad4d5454ca812c53c87e68c64d0e07f287ed508db81b434aa331ae8af6fab2d60adba6c448433b04e5012842eb817b64f2981b58297d72e22939498397648a18ecf97ea12670b6b92c37a0b3b5aa225a6064eb106ca820aa5b244408dff5460b0f4af825614022f501154cfcd2e222c7a7cba102c4975667d825fad9e58e352e
h: 180
m: bfebb28b42c0261d4c9b10db95c6507c4ff53b3b19507a34a5061c78ec859813a70badc8bd4da68ecb23fed46c2f22524da51d553508f8f71b3e204961e52abd6166e71404b41c4af2a21da130df61f903bbeeabb7753690276aed516b8f7fa4a246d2d0a2e5334373b911a2b2649e8f33f980aa4d81472c85627cfd6252494ab00b9a
p: e5796c9e9e57e0870389056a798a2865aba0155fdf0a6952aa267413f83f34dec8b4514448aa891ef66ebe38a042dd2d70be653c00d1398fd9307a931f9ea798e727ff21040fcd9286ca09b49670a9086d6e7c1689eea2922b57b5c456d4fb6e2edbbbac43d83ddfbc57d773582aa2f603878434e9e82ba1478afd519e71e6287521e51b90ce4c64d2e4673a25193d072160471b5c6312201cf0125e0da0b0635fb48fcd110e71a552a1ce4a0ffe4064143a525c6ad4fb4abfb51fb75b4d7c3e62974e4cd5d7e69bfa1ea23fb9445da8a2ef11e3280aac9a13ffc429b095083a37ebbd96c106473174442afa71d736a67754b8ecc336646155db15386690d94f
q: 913f4e6246eff6756fb3d48852669f91cc7c3e31c03dd42b1edbc3e5f7cd4bad
r: 40304e5d068cbaaf061a56f991a7829c59235fd59c0b2df0ecb2271b8d6af698
s: 80cabfc8bf1421619127ccc331d0830c1c7c243994436e36e9528df2502879fb
x: 61e555bcab1b482eddfe17800aab2410e1ed8663df197624d0da5bdf4d643993
y: e3f9a25239da793226eac79255f682b5481a4752f1eeceb88546b7a7e5ba76bd1bb06c5e28074c9d3c7e3c5b61616e6bfed3226d0d562183aa68e23247a8bb12257dc576920a56ca52c9af5f3ae90c178f54d3bb70724cd5095c2ca6e020cd8fc1f0234d1ca739600c72c76f9db94c2714be6b3755ab4aa5024f4bac50154c9bd8ff4ac4508df38d2240d35c232cfcdd00e6b60dc46e19d241ed5bc4d4713226273efb3e4c7be2ead6a835850a887110d367fe060e7b19ce9f0139d4421dea12cfd67f85461674b90ca675fa7bc383b62cb076af71e9cea06ff848403a9ba2f5ca3cd60df073fd236d23eec1e8790fad20cca5a69653976787a51e3c0edebb05
g: 3e10ef9a225b2ca3cf3e45832e9865d7460247ee62ad7027a7f2e265c09357215b9699e8b74a6c438a3d64d17b8be12852daf2111f77ec365fda9c45203486ab194b8f0858759477c02c2846c61d695ebb2ac95bf1addaec131a1c4ba3a4a1ac71d6afbbb0b90384ba03598b91954ff4a5393e77dd93d2cf6a2647b581f6d254e63794664a54d9ed34b4d483e39c2eacfdd4ef859555f5b859429d4580a2adfff377875b3c302e6f5185f982d0e1e3b54150af3e438ae5d520a31fecc19aa7ad89a060464ddf774aaf262ec233640378622fe9e0712641017344cbcc1a48bc6d9bff14aca5bc6d6dab2a1f2fc95c4c0b795792f7324f27fd080dfe2c71835c1a
h: 200
m: 9764db6e977846b864da3d97b70ad6a6fa7e630496a4decb09429d8a1fe6ed3d703832eb6518
p: a7b5b6c368ba6d8cb1d55e58b87fc2aecf8ef6d7df5e53753b7de3eb87c67c3aa499fdc53abf5e83b48bd7b395858345f89d1ddca5368130282f439e5a1ed2ad7c92f4c4507ec978182ea76a709d018827192d0673491f0444fbd25341a6bee82f8420ea344e114f4251fd8d6551f342ff3a1d8671c022a9ad24b86fa1405505fdc7dfb0de0c0fd3688b41fd6f5bb4760d4d0e1bc8620bcea7008b5d3f255ec13d556c67be263465ee241101536f4ecdaae230a2f5842b5eea43a1d474d4d990686938b7ced589f310fd90062fd6d8c6ae3c6cc402de2c3bc4ce74c5a65253dc8b94057b70314d145967e9d8d14067b837a02be51eb7b315c49d8d5936cfdae9
q: 8bd1b5f0475433678efa756bb234ef50a4cd98a5b540e519fc934bf8e3467f35
r: e7979153ddd7d8b21eed743d33af7e3425c50109495a92b220004005b461db8
s: 1d756e9a1c41a8465fa7f999cb09395a4a5b89a3b875181fd7f0247d78be724f
x: 3f0ceaad3661ee163823b68a1f921cc699a661d6ddc5d509a457352a6f62e414
y: 13ff0071a9549312efd58b8b3044575e6976527d681ae09c117c91351a58f55b88ef05c1d9242c95b374bdcd609ffad5604bc6bd01c8a2b86a8c3085e1b7319831530da7b0747354ee98c064956335316bb815d07befca8358353b2585a2b585700bd97c1209eecff7e056d819e7aaf75a83050292414bd83b2eadf4af60466c8bec7a9b1a560741cc030229b2129afbfafbddfdbeede1ca2c6568e7f0d7418a3638d07d3c68baf135b50df0aa0dcdc3546e3db8aa9bc9d285d9439e13d0f63f88ced0878bb3c54544ff3f9639207a58d3aab6df4f9097d22166f0f4a28eb00e9e8380a31adfb63c698fb501fe6c22ce8d6c1c8e3fe2f77f4cf8bdec0e5e4562
g: 5601dee6c5dc8fe8b01e1e2feefee8fbb3726c7d8506db67f06327cf0e6479dfde78183d9d135c4cee8f1a9e972fd281c7ce875b475880d8bca540dff2f413ba58d2fe773a4af2d3dbcb8a38a4be2b7d5da37e62d240ad771888abff146c971df34758642721002f5b7d5f14b3c32d61125943eddef41368a0c8e2fb21db16bff7c6f81f9b63f9906081cde0e33cfe92004d5a0fc7c19a69b25d292b22c651113ba6593096085f60cd674c6ba39623a71f6573f6229584d340f791d14fba9f07e6acdfe62ec134a51ac1e7a5665751b31fd37087b48f2967357d75a26b31b5417072ce153036a7c8b22dcf735ce3945a5a73ce7a67c5c5d0a627458931a5b683
h: e0
m: f6039f2c63c24d785ccaf2ce3e5b6177c7d350afb8e350655384595b972c5748f635b01be5139a4b8563584bcdc803c956d2199b12da9a01005fdb4d8e4731e912972273287771164c9d72a1160757651d68f508dc96a62665696f
p: b49275a04039eb172a5577990db00e2bf31d17b1f193f50f64a4d41c359f8dd97770df4023d54a42fc6e832113781c533af2aae2e488c73245be526cd8e7288faaff72c25ca39241d941c91a0ca03026ae7808dbd410031cf0c99b7c2a6516e83ad9c762fff2547cb6f862452a93761e75f449d52e7e30675ca7ede88bca32891940c9f92647e0b8ecbb4e9573a1356c08f4e34f2ae009c066d3c85f93c0115712a49ba8b6ac280d986ea64c95644b6cc4415287790d80a9af6109311af9683c3e72f893b62cde36c5ffca743bf2ba2ee3cb5aa4f996e15694fc9cf1bbe7bfea6111a2e7430230402b2104c3ed8e89246619884177e94e8b3ec3f2d24768ca91
q: d9ea638b88541d282ee5f200cde887c039d5f8fc215fc0f2248aec637b26492f
r: 95422b51110d9bcfd314fa5d566455943265d89138b799975bef4568119c3553
s: 48d5d6b36b852a7b7ba9fe0c288ecbaac4eaadf2aed6738658c24a1fbdc781de
x: 5e70fd65ac76b93162370790464eb3298d4b0e28aa71e8ef777be8f6bbea7a11
y: 19efd86788353c71ab7bfd4e80dd6e8fd4584ba05f539320c4616ad2bb955ebbf9876a34a0b9b5f29bff5fa99d9559d225e87c7d262bb202b917f1d1e4c68181798fd003d53d2bf94bf5822789ac29df2feb99d51afd8c2855832e2a47ccfb38fa23996796162ccc78d512188301747267fbbafac2d5eee7ac4466bf40867ea75162df7cc00e2deb2cb112e6deeed16c5a129ea80c85050afe692781b8977eb678f74dd076acd26c239148c331bc49294e00063be022fd7c191ccf5c4987e833f95c302d7c0bfc6c98a96ea89f92f7392f2724bd5c084089b15d669f6d301cb2a0d7a948fc397449420fca17d0856dd399d4e5777317a0bf3a8eb133512bb48f
g: 81f1930fe641d803233a995ab7b9c664fd2afeabaec9df04901d807e8e0e20eb3afe3e227b6014d53e06fd1e06d2cdf16b1b59fb09fc41f030e1a3490058493d5f31fc62c8a9fb6e2b9648b1b84d628a85ab2ffa59c3c499d4058c392a70c25dbfda2c3a3c6f243d6a9c97e647beb134b06ba129ffaf8b7204fa53f6729da151ed4f627cff93811b9cfa5052823c8d956e6d6dfa6189927143098eb89b0eef210fba4e36421647af5eda5e4a8160d730a035c181743373b2cfe8c8ad6d6a4ad3c729b90230109baaaef33fbdbb54fd84702e95674cb26bc38659b2197838cce4abf6c151ae27a13243772aa6a278ccca705f55826d4bccb641ea50c2aee842a7
h: e0
m: 7cef2a12cb9cee361338f3df15300fdde6bef6cd2a131c371cd61336e0d544fd090494f9e3740f699cbaea8f488309a6620567fa4200b8b5da544acd7e15ac0e78d762ceea977b12870f71f7077b2667624576618fd7009c8f635fae
p: bfc28df62da811722d7462f01d2261f034d87b6a9273e3deeec690a7016e3aac61bf766bc433aed81d559582ddd0b35fd14696aed66a7955ed624bcf8901627a8cc2136bf645b8ac60795f860c69ed91a566a34862d02b6ebafe6489660fdf28c27cea8bda84f048ffed7a195fa6f0a4c79d6fe5e034c61281e948bb19ec12ac330d4554441824f749947758e09ca008b221b0d24b4ab6c821a190f600b5181b46d8281480601f57ad05a799e237a00e602802ca095d71dab367f328522c863e8e88aa93f470606e184a83619f17441627807abb0b1ce2b6c82298213008304942fa3b50418e3885e57a4e5f66e2f66d3173ee4aab11a4cd29b29412accd5519
q: b98beb2e42bb15c89d937128545fcf5e3d4e6939fbc103b4a66e3862b7551e59
r: ac28d4f731b4430a16317cfc161f33af038dded46b7729f27ac6961675926fc5
s: 6fd2f08403af3d683c3f4e16e521d95ca68eb4ee1c30a1acca0eff1ab3b8ab4d
x: a5268197d4b07d7a2ce04966961e700b0fab0c5637a17c7b7a17352373708b66
y: 7fa870da04496f8437d16f198ec2eae0e62258c61b8cbe6188b7d47153c27fda2ed650ac54e67e7e51e62d0fc1b0ae3a390cab5669e5af88cec5940446f40f982db58505d575ba81d93d73be675ea145695cc6873428da6d93a5d669650ba9b92ed4b1a6e9f8815bec0ad32ac453cd209265743c34c861d62f5a08d159f5a750bdaa59f6678ba576021898c06edfd9b074024a997db600fddff367f5fd1d13eebd98947c300c00904f90faadb5a7f784702436d6b9450f28f210186266ccabc9e2e85c794e9f5e7ad941c57487c8106add7060523b8e14ca5dd28e70d662b2b7aedfff366de974c31082f014ff66b82ccdc688cd1f3b4af49f8e1aaf9eb6e883
g: 308e776f8192c010a3d7d86c4c072d034a10a22152cc80e68ec5bb718f433357ae15d95b78dbea777cdbc54bfdd57cfcebc151c173acbaa8250d1e4eb11f852492a12abcf175b4a4c4dbb9275053aba71113552157716fcfd596e65c79087dd5348d0a47b6a3b0c2512713e409f0bf0f1644ad95abb6a46da0d5612842f4acfa2acb0d8cbbf902ce205781c71e72ed3fa113513a608b8d9865f36f0e03f37d9ada20cedabd6e3e16e77ac1f24bf5454682bd46911137ff80d858e7aa9be9e093824420253e229a6b5cde1894b0c78b6b3525716c96236632b227615693eb0477d0ec4070700b2ec2e0e99cd2229715772255848bdf937a144f8880ac49285545
h: 200
m: e84158a7d082c01541e1c89974522b97391745d673b0b3cb9def4f121362aaa80bfc616fe8e40754edb96451c3466b6663cc01aedc34a45147f0d86d775944fbbb9b993551ab81b90472479b8878514d2b1b5cee81bbd0ba346e7070334d53eb87a8940b2c539aad5d31f0a654239e70c335628eafe3d8d8
p: ea62d3303656b3a2a06575f47b8295c4d8c7fee586362b1606a699409a0a4b6fbdcbb3b7050ce5379db1acbeeae53ee306f9571cc16172b6bc4263fab59f8e86cec982be72e1a26aed09194733ec19d8545ccd6e9ea0ba67d86bf4d22d5cd1f83af823d381b4aed6462a642db2e2d3616efe0035d1813823f291a95fb18823960aa0bc741a735ade737f77d3a708bbe555d294d016ff5f0ccf17b67743090d36d6749fccc22b56c850de70edf3967e00af5aa1ad7058c86d786332700ee741d0388e95e0ab038d4f2aa1ae999e250bec90c63b40fb7ece76b923e40f6322c2571f8407327d4cf354db8f1e3dff35aa5c400b0ee91d489ae8938ec1378f4a7421
q: 993c84ec2d07f444caa41ace0a6a63c548107afe0f422ad5fe68dd0558139f59
r: 671f81e8f320e48cb5ee78abf5d8d84513f9220e684534cde26935318f40de3d
s: 4199bde71701590794a75f6d0c25f12f9a297169a59f3ab2eabafc5d6aea9c24
x: 748a8ad45ab2b53748affb598a6f9fd23825790f9486cde9a26ef91b8b46c71b
y: 49a63e1b9b23b17de71b1814c045b9a3beb7be369b5cadcc4aa9b669274f94bc67917a0c958d0f96958e1b37abbffcce931be7a57bd74dd2b43d0d2a6002ce7527dda7d575d01612e46612b596acfb468452c7c5c884a062d3043afd4b0502187d1492e8eba1ef6d8328af4acf5aa501e4296ec7c7572909ae9abc52178ff7fa486b9b33e6f250d97408d552fdd4327404d675f8bc4be9ab4786f1161c1e3ff684fc821c3099871b964a1df9cb982bc53f378d6d4a3c40c36bd88fc19b185d56f67980806e83157704e0adaea1cdf5cccea1adbf5bb7f57f7fa845bdfa5fa037da4dd72e47c3063d39e6baf4c025bdb9f3b7b119b26c91ab5b1d6152a21796a1
g: 1bb4cc9a14981287198b2ba1b8256e854723a7583b26381ddbc405a4f8eab76df604fd5e9216e166a61771a08c384879c344ad3c20d496a56837b76a99efe0991bfbeb59450092d4cd1e1e30d73c9b4a8ad20d3321e93fbc5accf714e5f86494e9e9b9b655e57d9f163beefac04e192ed72163e3790538dffa6a755eaae941427717753d57837dc919a6ff182feaa17fc9f5261012a893f6c55821ac0e8a52c711d740d91f8357f760640393da75b6dc4ea613627a700d2d95050eacf71fdd3b91d5d1c4f605c84d15590ec265573e7e5468297e194789e6d687ca1f53c7ba261f02449e6f4b0854f563f2c7934703dd8770b7e65176db84f4acaaa9f779a36b
h: e0
m: aaac3d8361d0125e4f9bae9ba22933c41bdc4753ba389642c1d5e1751f36848fb68ab326528bbc98aabd6ea7e87dd9c3aef1f3f097063cf7da3dfc39b2ecfbaf28f6543db2719088af0baf3a61fa3adc2e8ff54d65a2e3218d3f565632a1f5c96c2ca20c17b3f0ab2ca4539cd755f35cccb4d59e0c009f33f11666c4a1e53cf88a353feffdda3b6e6391191217e0c2b5a3c9931a71a005a77b8b86f19d9395deb3c46ddd7eeea07b598bb2c8e6b4473afc389732f95c59c432e7
p: ad9a921b47488e9fc698e0b2405e302ddab742b66ced95bda0c3c5bdb8a89e6b2c764c4cc7be2181cc63d3aa592da1b7788753a6103a09b4619c8e1d32283fd4f6cfbe3dcb27aab16bd468ecf3d1fbba96e1d004bda871329db0fe852612a6f5980d7754ed78032cfe55559e2126a9af32c4987949a804d7981842d682a192678b6a90579b943320f23c3f69fe890ec7f415982fd5665bf0fefb47bb2451466cc7beee8067685589231f433656b718dad0054ac65fe248f932d7a8cf93aac54bd7cc648e46ec94a2de42ea224b675cf243f9cf65e08554ccb9ef49d9229f604d279e1e8d935f9be2392025f00f0e53c74d33821bc56aba7d84f3ac8799f0c6b5
q: b7cbf0fa23c7cc6e8e49e8487fda84f8191a32441e571fe7ffb5956bf18e7035
r: 9e08a8ad9a3b6def8ea63bcdb2f3afd4839b95c6d537daa2b3b78c89e091f0fb
s: 7cf83052047d53376de53fdd67913a52b7d686dfb8634c2b42798bec70103220
x: 7983a33de8a33c333fe853c717bd55f5a8ee4b67870f9e4d361ed3abc796d94a
y: 87b2f2d42c095fd0689a4e0cc6b998343534b72cb4465374b80e78d8d7ffc728cf6bfed68dbbe80ab72c2e5f445feb49dba2cd9e855ee9418ab0c3e0ab6da3fe8e9a694bd5155cf0284c13c7085aa7586dea9d37d51d3f013cef0846eb2da49e9805f616ddc5c99172ed0197e9c4c588a6446bcf769348a92b06701b2d656e43ec1b07eb1f2744e4663233ba5e717b25355a71c861467928114394654ffbb923eea378d05038340ed2c15a7c3d58f798f8dc42a27e3a3b19e9990416f0ccd6173fc8d08d5ecd7feeab972d5fbcc1280a10456b870e83270e008559e272b68a346d7bcdeefb56d82b063791e5883b63af2d7cc0c86f47735400312dab9971b75f
g: a8ee7d86355ff45010f5e0545b90791aa5bfba7417b3ef49427410733ba6cdf724529317a520073ff98554252e71da2ec105331d5c25f159c3c69752c4877a803b821d7e5ab1930cd0709864193b78edbe3107155a0de75ff16e2041ff6bea2ccbcd999617b0a04b61b5bb1326425212d89069cdf7b966088713521798d11a95652213cee3dfa3703e220deabfaac1154b1a01c61850f7d4b80c333dc6752445686c449fd0c97eabde0d573e4e5fb6b53ef982bd47f6da4e298f2c524d90e58339448fe0a9f4f743061eff1f9eaeea18736a21c84d8b279eebb8eeadd0a18dd9322d0acf488e4d46ff98e5e16aed18a73e299bc424c9bfa2a0921e24fe980d1f
h: 200
m: f84e9214f581991dfe10205f7a45ad8fcd77eb49d9e89efe2811622a701990baf9c20de6111623bc255cfacc52330b8976ee4cc36c348a15480dc4ab56f4506732ab08ed7690df2f0346069d0a3f129c8e13d9a9a31994e60d248b843e73de1702c4c8c578ac5d8ca95d12eac270a9526dd1c5
p: c5590e400e8af96dda10b398c0cb8e1e704d9b8284344c19ec97375f490aa1a50592fc3009ec0b006dfde3f0195488a807d17086fb69cb3f33413a759ed964c3442a88112abe74fb803dfbe89fa8f442294ed929e113f4f1fafa0ff62d8ebc456f96a5bc1f099063595e2fc35ad49d973214a7e04c3dcd28d7eb5337ed769a387ef543b51f6f763bfca4c308c0768b4fcbcee5d719c54f0bbf9ba51a8ecd711bb63a649187d108f69f9c9d5932ab5b8624ba611b964639d70076e023b40db6228943446477c174d832a2094d6cbe5ad57982d6b3e2fea012b81fb4cdbbf0307329d8f6b596b08332df64c9193239198579fa83c1a1083e656fb88b80736ed92d
q: a2b512968bcd4c30899a63f0c9484be9152b86f5e4746537c9da6cf6347df7ab
r: 65a04d3513cf1e452eeb0aa98f3c2c19d98f423ca7fdc71c056d4e22b9595ce9
s: 9a478002052c16c77f5cd0af2a01b5146272a048af45b1a4a716716fe20d4e54
x: bca5780883e13625bd340501c3ab6eb337a1cf5c9b5bb6c660de47e3aca1973
y: 6b3e7dec84cb76b263b3191b3545643e75296a362d90750c58a3701ee293a965068998fb4e77ab251b7c10b32a63b148ef52479a777c52567815b8332aa27987956d5e09da7c95a38b62f7772bed147d9430155eb864b437a7b30a63ea202af610d1f21ce00fca89f0ad1657422574dba5efbd21d98a85c1345abe02a3ca9e776e934f2fb452eb13bcefe9673535f6bf00d1a0e4a1d48f6e537caf335bd9b1275bd2357137c308a6c03c2fcad88bfc21a6e5cf1eed713e3a811e34814c090f9a1c89cf97586015d2189501129ac37e5ab6f943fa6124a3e0a973772166daabfa0b53cdbd216ae464fca1f4e04bb8bb08072ddfe232f2b0a752b3778eb7d6beb9
g: 955ea1e83cbacdd7d7dd58af1c1f2248189aad2d1d1ce85399e5ba5b9a7d9ca464e588a736507505d16c0f334316314700d91ab93a8832df95f7e9915f03cd38dbee5024bf9c18cebf19c141986aa345cd0d256d0d468ed8f8542616e6fafb0c8fdee74f8398acb6ea7158aead8b3e043dbb002276296b1b3ad80ad0ec499a475eb34fe66a4697bd16cb64adb754b87b82318da3570929ad89fcae1e40665c65b1c195a919a6c5cff87fa5fb198882926fc6766c1c1aca9a23ffbbe07d24a9b1b5e6d1f6e3b817af23c9c0bf75177ee318be80aac2f91a8c6b4a62b2cc1acb1471d4d53777e6cca2056daa5cb18b311113e87aed51565e9128b580ad41c00ec7
h: 200
m: b067eb82dae3f4156f6109d943cf5896d593c601172cf44f9db55a8a53a4a1e66bfb3b4aa5f9b046749e98bb4f62cfa2c6fe05d3779fbae6271cbc413d7933fd41d9dcea7204ebc3583a5535c01246d17c6674477cd917e7ff1dfc8d3fc3722836295e8fc0d84035a592b7a3ee3936a08571a5b71a6de477da4c1d7db88c0fc5f5131e474ec0a8fddf5aa5a8ad8d945cc75e940dd21e568f758f3a8a8629a243e77f30c00ed958ea18bce0a94956c950d5f51c593ff83e87dd6bce434ed33ab902f689d15e24b9f04505030ca5783cec74d253ae3862b2321da4f06044a5c3c4c0cb1772135ea8e873e964633cae07fc638b12932181c713208539ce461a4d
p: f395b07d434e6eef24a81e59d5b9e0fac0da9e778a8ead10e5613daeaf8a3174e8d2d50c6e8f1a85bb36fef5094ec0bc52cf12a35594ac237cdb22809a3c7a88b9547e4377c616cccd0d77f2c774f15e0e13917ce20aa26e789b07b45242fd0fa129b6db8c8f12e92b6c9add5a5e446482fa99b68a75009714e1fae7d7a7c3e72fad368506622815687c964150f36cbebf077ef110004bdff2064e50f66a4ab283d9123c25ca5e3cdac6589c31d45317ee53d3afd5ca6506411b1d24b00b639e25bec45c78b3e1f4cfcba763f277c6178213da178b1da81739c998072c1d7dde87eec1424530c7eff87045f3e9f1aa252d6559b0eefc667115103db677984561
q: d0550a0e3be4378ce54348e5a0ad58076262ac21a88387c4b661ae1da5c62299
r: 768241d35a5f83567f5e3083dc833b1fe0f43bf55a8a594b22f7dc0eebebfdb1
s: 938eb76774f7bcc8ee5ea9961fc79750a6c8067df66b8fa59fd12545fb42f794
x: a6ff50ce67e7afef046db6152455ba03a2b13d314ce32947dff192113ef7de46
y: 9061273d4d5c665f19a53c6624fb9edec986276eb4ea3973aaf1785464f32dc7c1e77e546088c5cc4574bca14d18f8eafdfa372a75ce775e345f7260977fc06436681ecdcafdac16a6d97e8df184163b29ae9627ed0077b9e3909598f88b31fcccd1ec7113cd2850afa351557877db9fa05b7e972fb96c0c244423221931e4d7dc9ffe9115e432ba4d73dddba6de23953318ed7facfa80f6b98f502eaaa838c45cc0da6038f1153094de71c618ed677c385fa0711b1a5f87fe33795b60d1b8fcc22b0e2cc1f90e8f2932b3de8c0449b7043c70a9f0ed453acc0045d3dc9492781339fd645a39378d9c4c4ad2541a7f99e52a920609d162db8549fdb4c56885f6
g: 4b8d16880d812d44eb2708e7f2112f86effd61d83a6eacd69b0f333d5bcc7d4ccf87706dc0b31b85272a6e678c78387fa37b1d48ce4f8175629dc641dca7963cd1bb62abba521f47a998341edb99eb715258997df8cf0af4c1bfadedf45d38bc66907104ec8dabb12ed31309e97f134304e13ff645357b68af1bb5c3b234c6748e2541b09071b92f5031f1606d095242baec9e5b5718edcffe9abe3f1c14708bb7f5e6226c6021bc2d91155dca2fe5886adddee0836f9d5db905fd41748f0700196296e51562b4a5419b1b97bc58bc41010ddd997d843492bd673570cb4df4453a0013c6d70bb8abaf0dafe6125ba05e2c2ada9eab2f52a087e7d72ff9d69bd4
h: e0
m: ff6dc39371606f56bf5988f1130657008f1575e3d58d9a44d44ab5fec9764999694b320c7f227253c0bc5c4bce6abc9daa7a9795b743795643a5d45404bf10b61e952e3c251d668f7b8228f605aa55cab81eb553934e47e8f751d5a7bd4ad815bd385b70995457737b1ddb72b5d2e1859c75ff59b691fd8e45240ac6f312dafb8f7cfb54216d16fe390dae9decb84768427ca1
p: d67996182cce04abb649a3dd90249f3aef162a74b19635689890628094141738e9ebe7f76e1a8f79a1e49e2c26c8eca952eb08ddc2ea9032ec3fa32a9ca2c865941b3df615cf6f0b2c48cd91b3077e9ea073156378a59e77b378b8e154e2a859317dc2c939853e491425dfcc503916e9ce8aed4c3dfdb2e895f03229ce6de6a95bd4b32eaeb42b5151a35ca18b42b6b25ce0679534ee2177664a355981afb6b3c6d2a9dcea8d07da444f670600d72e161c14560e5ce2dc58cbb3f053e08532f58494ac3871953e09cfd8aab398dd22b95f447c30cf2be164991f29a8f6ab2744dae784e3834cef6781a4fad4bb598854fcc2df45c857614cd743baeafc4ebf31
q: aea2961c67b6833f3ff1d484edbaf30f565fa3d2c96518a848c5a0eea288703d
r: 6c1ecc8e508dcd5882d85945c2ce16f10171eabf77626f47296c1141b691bec5
s: 184f7a4fe22bff5d5a7c1de8b690906384b1e3e13788ec9c4c1a944e5014d6d7
x: 18d3156c20c681d6ef0bf0ba5156ca6fafef278fb6c0a9f29633fe849d8e657c
y: a1a82876b28ef5ccb45863b6572ca7b4e5670e5efc97446ad6571de248ae9e482d6c5d61914a894df7b1fc8e49d6f3df9ec7e5a1000e61eb894e6e458cac4c7baa26b45a3afd10857ce0f0d689cbabab991bd7727942d9c3f3918aac076686ea769adc3015e138c16f9564d6828aac58045a0cec1a60fb1a58c7acf9971322253f306429ca6794c4e96e25ac5766a86f8087bc281f925e4432642b7e8604a1d0f1cb03eba5e7f7bb64dbddb2e5d2ddecfcee0adda175761460a1e8e363c995c1a9bbb5587d5b5c91947bf1f1b1c0094ec02e3c66810f39089b7d78b09baf5d9636ae5df8766627613b3bd0779e7997cb938fe9738c4e6c18db1a53532c386b91
g: 961c5f2a8db735b0ada170aa44a959b29382bc65b9be1983874ce4b975333f4ecd2fa2f3f070bed88e367ef13efc2b7bd6f9661d7c8530e43854f702aab72d04aff0eaa5725a7715b608292ad47280dc97d5c51a927b079eb8deed615cec48fd1f6d86813a3b603c78c98dcdb965539e0ace275ee2dda588d6fe2efc360a47319f70c9817f684260f6843e1a790dddaaf3fc9388b46f40ea6e4699d1a5a06ca1c5ef62d18bc044dd80b746b741042d15b86deeccc324bd6259662b8312a73761b83aa06e75d797f48015f45d04c6442ed08dc84918ddd036c1b1bb77c7eea25eb0722076026dea7b0b62f18287680855764e4ece0137f63ed0e51773dd7efcf9
h: e0
m: 19e4f67adc36872e8475a30433a643ec498c8f26d24564ac8945408903b55b3afdf486049806278c70aa3394f07a6809c6d37bed8a3fa078b88570291d0f7b07bdf3e87c6aa89963fa2d28dbe436c4d1467baa7b9e760ca44dd7225a991fbdcb1ad8555cb9a8e19811a7eeab5ea4c8e17ce47737fa7e41e5f125dd72d7e1f8302a829b316eae02a9f3e6822d391b8cbfd82d018326df0ef9d3ec27fb8fd75ed38c366a99354754f96547d781234ee8b6c2a7c41a4941508f8948e05c5fe188653358395ecd2a1cff7885b1bac810b15e5ba431925994da288c8a1548d69b626501532cde95
p: ec4d664b0fff7a282f453df4bd4f36acb3d69a9c48e32c7b7f62976aa79fdecfe9a5b8653a36565526e3f6cfb1932e1fc34817b2cda740c46576c1484758bd7f5a7c5728201544fb2324b42d7a5589e6d10f0bb9c9233b886fbbe699b8c6d364ce59f44cf62d7785fd392a05171c37850b93a9e5eab10dab8727382fbe795a16d989853a13c7ae691df9694ffa3c19933359c47b82a4d3848918e0e7cbaf596205532f202bca2106eb01c160ff8782ffb286cea259d10d7a3cea457c64fb8d5c4423abb9910544698ff60cd285d37c6a75c55c5686cf198103f081c9fcb536cee91b233bc9f15b8291949945d8a0b62aa0240426327de5073546ced39312f301
q: e0cfd88fe31977f93db91de0136a060d5fe3fddb7f6934d46bbec18db6e2eac5
r: 4e8e2668572416f06c45881916aaba41bf688df9236051425e38690142eb61cc
s: 303bfe00d19ef5b7c33279e010fd83bc78d8aa0ae00fa01c249d89e9c440bf9a
x: 9e5aeeae3d4d53cf906c6389cd48806dc6d78ba63910ce4bb9d33b9db6a7981
y: b7bb1375387da456fff61e8005b7a37ed47b752d29a74a424e004a1cdda85a47064f1cb28a763052cf142b76710b539fe8ca8e71fa4871b7ca833ca72a9f1915978cdc0c8ab2f12116ae52cde5f97274cd08f1b98ecc12a9ebc9b9d8fec5926cddc05553640841c7c22187f11eb452f62330e2bda98eec8a7e85c5b01c7e014136969da3efe1ae3e8bdd2686e7b5b0464c3968e15615ebb4a117ffdbbd930b8467ddc627a19bee0cf9078cbff694838455703bdd94567262ead49413426a4ffbf2a569a406a3fcdde5996efa75594b75d62029e10b532f7c0817b49aaf74690f3432eca8bf98c055ebbba7de03bfb8c81ce8c87839ee8ca3dc2b8a5724a13d1f
g: a930d5bb8a2d6b1a6ef95e6fcdeed2f0ada13015951a2942b80196c78ad0c2daf92cb1c80e5768ad746cfaf817b0aa7aedbb0070219e89a972d964fd8ae409d63ed0f296debbfc2926f0a865c7bf8ae7ff700d8c3f1893872c44261b7779c6b086ee8924cc7a9eda73effc0f694922a0ac2ec10999c91e1a47557b7d6bdfa267d2a38a435206fc0d5bb47d97176acbb9d1018b001a8288c9a3b63969c106c10d79dce9fa41ab4810d4c085ef7adff7be02a15d0080051fea7a18825dd97e82145149d5dbdce0b8af1cddf137a1d536729838c8ac9e88d946c029d3eefae9b3e2c0ca66f2f5d7ee249335f648008afb82a9d9b78f08cd08634dc17c5dd202d459
h: 200
m: 39cb6e5003b73ae6f1ecc551c6625154
p: c8062eee734d2dcfc62bdae9b864306906d77adfd71afe18166b04c84e7cb43959a231c7400d37999288820cbbc51d3ffd6f2521eb51e567fa02291456fdf61ed6a6806c4af412919b1c420fad1068901d7921dddc02a14243cc1399f2c931648717f3a55a28b213b94dfb45401b46d4fced9ee83e54e55b7c27535f8e7ae2a148715f54dea531159b9497019a322e9838cac19b8684edb15d4a2432f61ef241e5cd5f20d1ee0828c84db02329119457ff05bc5b15ba279f9233a1c9496ab64f743edb41e6a0bffdb4b3b52aac58eee659ef2aeadd2b1207debbbc47d606b3948b937b2590e35b7513b0837cc2e86c2aff06d0fcddc4e930202f19f9316b130f
q: ef454da53d9728decf112d714afb9242f6231632f86fd6373c30e9e49e10b11b
r: 3ff28bcceba7989a9832f8259b5ae1ceeb9eca73d0cbfa24ab4cb273e64ab25f
s: c87de7445127dcfdcb1194668df3d59cfeab327e3044027b099f2566b9735763
x: 88f1922ab190a7298c95f663e3cc9cc118e946a2baafe137ef8a21abbeaaad96
y: 398275d507d4ec7660fb3549ba0440a7f742227f42268dd07c01bdb67064d39522ebbc7164d274db4e79b6b6bdc35bc46eac51947e45376bfe8914ff5f014bcfcf219a2606dbabd59b8a25270d85812d8af35e4b63f7a19ca7566ad9cd23f931cabc712d80a06f89fad649f423ddf457fffdda4261559386bad2f350465090a626cbf5d6749b2473a2958888a7fecbdfd2a16d92ea54d67a75088be341877438eb4e92831898b4cc36118bc41c4235d31910c0aa4f731058d9d7fcd7741951c568c1342a2e92fa74b8e9c8c92786ec83e02f92e3216f489ec1f7f6c207458712841557eabc87d79b896a85b01c6b0e1dfbde4c8bc48f451f41aa38c17a7da8aa
g: 23d743706b16fa4684c9d3021b9ce528010f584f62c18a5532fb828b866bb17614c63c8a56c5a88cbbbaedcf9ebda81ee9fc676ee4a5d16be07421720365cd88efd6851ac97cf77c2e2afb014913779d7affe3f8999b01034128b958108fa74c0521230fc928f9bd274e30bcae3b173e971c527506e7587fc8a597fbaf92b630233b6c3ad5eea37098b5dbc67620c3fc1dfe5b709b26f6267057103b757cce3598edebfbbfacb6efc396507676af8ad8938d7f965fe2335e9d82a1229212bdb3eb9485af94787c68f9bae9a3e6f0cc8d46e31c432da59b1764577b911bb9b3a5f181954fa44c7e02c1d64a0d4abe9cdedcfbefc01c4bc8fe89861dac43259c2a
h: 180
m: 00c97c21e666cd643877
p: d2ea8cc1302fe090da3d5c98bb909313b8e1f0aa1452f17782e939412b980ccd9aa76aab8e35abddaff432da0b0543f52b88056f5165226ba6a5ea1b168a60ae69e5d617fa3c9c492d92fd736ab3c49504c987dbc7678512fbf3c6a64c55bc0fc76c0009ae95013eebd2698a48ca3570b7d9b9edc268e12d6214d4bb6033de2109ad8c4f636c129d03c43bf856b08af9ad82f1cb4d1f10c7f61f0add1a3fec2e85050015c6540895cbd03071db7bdeea333499438d73d22c32f00465055990d2a2d2c4050371306085854d2607c232a0401cb6580791e1fc8b6c28c659e2abf3977a9c686261b517e1687d93a659bb5d5fd9d9aa62aaad09a5c01c2191b148c3
q: ac2bbb7b01c286e50501047651860c4a9e783f4e326de6af7e0f87eb4c30fc07
r: 996e6473c06c9350f2d4270177391c7df361af2fdbbccd6f8f869263f91bcd3c
s: 2768364708a5f929ed32ca0ac734347ad4e8b773b44ea770ea60698cd061dad0
x: 429c4a24029957cc1b47fd219343f0732f254f9edbe80d69121e086df973e30
y: 2c5e043bee62305321a1bb6057b942a4c983c15499560d19c93e7e3707878b1ba0a6abeb090bc46b6255ceaaf9aef23603f606ae3886fe7d303297bbcd38abcba88827010b068825a6dc59b3a33575987429e44eb694deffca26c07f93dd038a38141fe0864be1808679d80c7ef709a6776b51e34b65884e43ef8884e2ef27327acf07ebfa34c6183e604fd849f0b15ddc4f33a56d33cb637bcd05213477fce4d451c217c5a27558dfd9517cf5322737969f7bc83f7dfef81d34223504f044013449f1259d8ee275d7cccd2753708a09d447db89ec42abd88fc204ee13bb1b6ccc9f535fef26c90a46357c922598876488c8d4e145e52bbc5b50f84f72b12f39
g: 577c75aed2fbd82c2dedafac1a45693147cfb45faecfdd077a10ed6ea0d40e39ddb62d568d73f5400c45ac42df1f2623ebbd8956f23a35d7d149c559b9d03282465bc47b645d7ba7bb4a5eb0dea01c1cc3637e7dff8f148e781450fc12625bf1a20cfb029e33785c4007a9888ddc7e35e50ea9d2a0a25920851bfbd37d959f3fff1dd7a236de07cfb6360fec44bed1c59af1db2fbbb9e6faa2475ed0e49ef7b9434e54f18e7401a1d80dc40b3a8a436006a4d5a9323247a85bdeb50d00de6a7050e61315eaa4d6e43adc067fd4bcfd3ee01d7af9da72095eb1d174772080ed9618ff34b988ba3fb6019462ffb9bc9f25cd2e142be39d8d47ad91bedce1e414a0
h: 100
m: 831f02072ee5daf47051957249aacafcd0b22f73ade72b33580e2a18083b5a329ffed5b9883127212756e63c7c9daa26e92411fdf6d06480bfa0d5a3acdf199e0e9db3ae7e4cd2b40dcd7db38f670ab32a4273d59dabb68055141674e92c784500606e04a63430d564a263d2914aa2d13c5df443bd77e785c83403cb4b14c3e1c68d8a0fd7c4fb1db07bbc7e43b1767c70632b216032823e2e0eee310122005430ddf028b695a6631a663d30653cb10c5c489fd96fcea3bae9834018d7baebe9cba0e4d5572b2ca8f075038e806a3aa2c44cc3279e82449bd23ae04112512733ca2f3fadb121
p: a8eda33605b64654d0b8d9bed1d6481e854d417f510ada5a08955ba0b212aa70317528bc204fa012f99fdb1deb8f41282c0fe425bb06bb9f5ded3963f75e6ff96802cd2e7aa666e9a01d6a7fec9c2b2031d8465e62296910372456b87c0340dd0d50c2bdfc8740ac4ee3958028d757768c90520303f55ffc57bc20a001a27540efee52e5d436c055f9bed0af613f0fd8714831c778270a2ba2601ac920eb9909cecdccfedcb670a6b218f358fdf5822efc15a65ec221021cdba76334511894fed6dd86571a97772fffabc3a7a19a54b9495a724aeccb91d7544c172ffd3713506f3b8fdba2a342817fcf5718d94699db3813ac2a684f4aee3a38fcde27012753
q: d305b00be079018cfdb72cfa7d594cce921dcfbc2d6651b8acbf0a7774c5d841
r: 9e50e9c4f9fc9f9c13ed982931b31a050d9bcbcbf697374ef86c85832dc0faee
s: c8181426d369dbf58f4fb0b3b2d01e05ce60d1cbda09ecf7be12bd921d901189
x: 7af19ba5541ca8ca9c449789341883528da2bf64ddf754439b8d30a527045dff
y: 605c836a8070ba4850008101451c38efbd30ea0eda6770a4b14ac9902fb85ae7731a1d5e52fccabda1d36b5ca3ee821a646d71ae075f80478ef7894239b6baed488474d31e2db2259ab5896616c0797a1254d5b2b0ddec63f408f263143b109ca421281adba13f3cfbe80bd571d52f621a15db04a18ec19981f5166c08e7f3fce94959a2a491662bcc3f0b8b7f6adee4338bc2ec2b4fde960af59c7a8d7218cfb087edfd853efea2ec2558ab797a69a1d4fa87728b54acbb438392debcdccfb549b2300c0e168118b9380a13b979b19c7b23dc9dbc775ab34cd262e917953a157489f539670b8b65241fadc8fc52f644c59988d466246ccfc2fa88b1a81d6abe
g: ace69194079c7ecf821fff3a0ca9455b6e2e105cfa090a82730279b0cd6099f178dec11ee836219168253cf5eaf689478e55f2901e31072b1326aee96e8f4d7cec0b2ff6017e8fdc6fe0572eb85753eaaf773c897dce049971454f8b4901a471586998b30358fabb622997b11e898d002287177e759ff393703b95677ca21266a06c2fc69fd50a7cdca8b32197b0b90a687f10edc1dc3031a34fb8ad88a4709b783b58465e6fa5d16d12b88aabe227dd2e8bc71baf829fe1d49a042e66bd3a27404417b686b6334bc53c76b6482ea8bc243bd17107dd4d535d570042d892ea91c662ce2bcc7ee1574e167e95b2071a3190564bc0d5bb7e934d60d4b7bbd66857
h: 100
m: 42e8ce93f11eae2fcd5dbfa4c3663d757ff9f8d4d507a25e3db258b990aff52fb7cf9f95bb7a9c195d6965fff3cf1d9905aa4499868f7ba6
p: e1bdd4669c50812f22e39a8a1b6afe353f33fc0106ef73d4cfd6eea8934125bc92f3e46054ba1e58d24913599e65859945cea7c919419fd70be25202b76d7ebf78d463ec5a1f2ecf22c83552b05de9e74c0b4930e4fcea347653ae06b88e660e16aa339a87599c1f187113e0e1717bed3d71e79c54b01bac7a76c6a1e680152f72d2c47b954f8213b83ca2ff24d0a5a5623289baac9d3ad9005a00b53ddcc19d92167ec3d590a24c8dc91f17111e1a94daf084581b65a4935af5ed8933a2ad2a323152100e26ad5a115f828f2ac43135d356076051c4ec37d81e0978437f8b9846231d091608711dc7bac4ca23da80e27d8be8844963465fa8e85c3f2c6db055
q: e2b7f96e822cbbaaacd2eb9e7670ffb526f469c861ee1ba8263132bdfd5f8bcf
r: 17fb40e8ffd6f2609d4733ac12104b9281a6618ed74ed31da6698dd7a31b9d5f
s: d1d68b2609328257e58da88d21d47e3da808a4901a4ad19fa6b767b2982bebf4
x: a5b2600d0440574b36425384f7737786e481fdfaa20bfcdef49f1af415a79984
y: cea577574fb5b78f74ae15c467a7731b2492a96390ab6f8e6ee9d321ee09f5fe014d37259f09889766063be6b4367efe9503e2bf0f9789ccd78c62ca5e34fb9dbba6a7d29a552904310ddae38960eca6862ddb8dbaa78a0e00e0eb56ee1c69f43c1f30d9a2a386f3d28986816f71d6ba8d5fc8e4f40aa9e7f826b1577807f99538793bcd4fd3b3099682476b422ed62660aa33ada1275ae50e3d47308fcf5f8c8c4c991aad6870d4f7e5a142e006c27fc646cc0e4352cfe4648208cc60a4e89e8905c862cb9e17586bb4ef2bfeaa39bcbd30b62a194983edd94de76e68c83984bda6561c06ff3f9a0855efeeb2a30a47c83cb62b68005976465dfcdb12874b5f
g: 3f2028351d454975a3f6d02b04cb625a742cc52fb6c7f49d1c5f83616316918655fa56e1dd7606571556422108fb5e5eb3950e7062f105e772f9d0840d1944184fcfa64c3e5cb590b4d226f1b66b63a423a01ed43778aaf64572fad67ff079905ea619271b77dc1a5a57e8751b07a180ae606287f1114ec4671177ab005f8367cd4664fa07a48ce054de88bd7a40fbdc10fb3b950fc9289ca8bb68ce16a4a2256dace7b4c5b430b7a6d17fe5983b1429c04629faa14d73ae3528b926c8d0144cedbc565bdd199aa397a977771308655819656cf6f8aa2d4ecdddf0a3167b984c3ee330a178b04b6dcd4eea17063944e80fe1d0a1e4b69db9442131d639e8722b
h: e0
m: a9ee8f4f857d
p: c275bbdde048f8a42470c43cf08cf098a413725f4fb3f1a4813b7639e702197e8d3eb1b1ed1714271718939dae8be9d1d35b8cdb255fe51f2f99dfe9dc6d03039f9bc5b805b64f943ff843bc0b9a913f5d197a5017f31a080510282db178c0d14138299e307b7e8a714e89ea8ef56ec04859c6b8d91e723e0318a4d60f0321c08481e7f3205e3e1938c4e0ffe0336f72d2d1caf309654639567b14658c96921d1e5811c09025e4964d09e62dcf929f7427ee19a98214bd976376bc2510e1b0ac904d25d5838b99cb7556e3521f02497445c2670f537e11c5e548c0847d332fa7a9451ff9aba0686618ee8e9e9a4d6c352eb73f10528ab691d68d5178b52cf7fb
q: d288fd8335a1a54378a9372beb69996ec7a608eb7c97207580291c0e403266c7
r: 17794e7d3b529db5132c4b752526fec1301deebc7fb47838c92ad571e95af99f
s: b4896fb23af45c31559b8ab9798978b89ff724430c09c21a66f58cabb6cbc5c8
x: 71a0bb903f406145f8204b69827ecef2e542b82cf08fd3e7c020403b4582fc57
y: 51c8313b2731fc50fd99d4780912a3ab86ec6c2fd4da2ca38ff994cfc7658e2bfeb9ad10609944d5a5a122d581994bbb0a523f58985cbbb8127b21dcddc26f26c239a3bd620f55bb6fd1dce2168e21861025afb4d0985d0399c3c7d8cc201790fdea160e00fd0b0bc362e0682b1982f875d7ac68ea4ce40a145fbe1f0748b13dcb67729bb95be99b64e6ecde41ad66537ce0a2d99db96222c528501e6a9e858c5626309931b5d0dd95a62e4ae16fd5eb7b5131994392d0fab16dd4d935e6dc55c7c85b9b6770d288b26842885dc45911086bf495df8d761f7a5755f9a145572ce0952b149f4ac7b9bda398c9416a65c89bc04412955315e08eef7b696662c19e
g: 7406836a7c0178035745400470e31c58180d0cd841c4b9a814581df145bf2bcb062e42faf7d3a3fb12fc282fe01154b8cd36dca6d4f6044fa6814bf660270ad2251e868b3051f4c35a2f03d506c5d4ed147268c72326896d48e249303e32d748c3e8b3787df76db62eb2a941b57c945b95fc563bb2b70a611df9055a2a6bc04a5383f7963708e4ad288573f3247051d2187c2ed3e033dc800bbd0cbae28aee5ae1bb0d65b2d38f4d053de952c63cf320c0964e25f83d69054e767517abef5d025b6535ee1d4a06eee4f72c0ac957e8caf667b6525f0e43a204a9e889301bfd6d2de594206764003a2a197fb48da1e75e16cdc3946f8c6438cba0db8bd3933986
h: 100
m: ccc5419f867ec3b2528bf7f77e16b53684003e91ceedf7f0a392b0d8a5b0cb69
p: ad9bdf1e57b3753873bc919cb3b9c5d6816495ac8c1668595fcdc5b760d1c5aa6eb6f0d6f865b759177bb25b17dccff6a18be59b3896e24db22ad9320388dda291d86931330cd76a06b4a50f73459edbbc553e6350b86515a79f8a17c2f92050db683f88d0c21e332ed04660ed91b976bb5ee47a5afe6be33bd1d4e97b7926ca76dcb7517367172f5f9e18a06b05769cd21100dcb320e88ddd45435b41fbe05be9ab2788a02ed46ccafdb95e133f4472b2c3d052495d15513bc3341783ec458e826685fbf9996334489fdf8d2e540d15fe861e6dec623ff2a2584c041a4182245ae4e100215c74e1b82ab40b0b77c1246681cc5c2888155c237a120e54dbc9cb
q: 91deec60a3b77dc0e867139eb8f39abd2a51a2b4ec143b9f58cbd17ffb499577
r: 229d2953cf39940206f51eb22de85a6de54191afae84aacee826d660e992a357
s: 55acaed98ba90aca72e05ccb95d37c913e7c03e32af416555b5338c24e37c7e6
x: 7bdbd64c954610f0ebf510be20087126162abb3ef375d6b6183b33e5903589a9
y: 13502f838272984bdf9914d8e02d510a596fcdd1809ff807ac847943936c5b258d326958ff03a451b2efd09bf09fbaae26400215601aa0cfde14649ae01c1b03818434b225a743e49cb51819c21b2b17ac4a342d514d98569c36022274d7c999b4a5d5ccc2db51f42c367a36cef98f23946ea507d02847566ffa1fa379218f52f5ccb76c3ab64208c6066510066cbff8346ebe6ccd3987ae6bf57539bfa1645e0584e69b0e9b09a3849a314421427935cbd9e4b063d906f3bffef74c0350a95247da2a49985928ee2f4cfbcf512a5f1d081020a0a7963cc8240ff0b5b5ea0d99a716d452df3518cecb092cb814bab07de668c4c5977b7ba6652952b9978bf1d3
g: 51f0f54e4a4e5ee6ed696573c8cc9166976d299f077f64fcace342832c02e699d42e26c9247167b0dabfc7123906d515335d76a272cc12faf41ac419edd6377916663bfff675e246f47038f3b0b3c80fbf5b20a56072acae5a868c8662b7b4bece9ac32d025eadbd4bf31119060537c6422df93e2c67b51f0a87deedbdd01199453527866349bc6f5665dd6994b9eac9b605465829676750affd57ac63e339825dfca541b72e27c6648b733f47fd7e0453dbf174e833ba5ee9d84af2bbb14fb3b6cbc333d267f26d2f25e84fa4ba3414afa41c8539896d73b7f47d8120b9bd08aca5ad323cde5673aa7da7e8b5d1ee9d45ed15695aa7967dd2886f52afe42ea1
h: 100
m: 0f95ff3b97683d1d7fd07ce417e49a9afb31e090b1a883d3051cea76ab8871ef555b8ef164ccfd71f0304275d5adcac2dbd647243250f4736f7f7e76e6203c5caf60bbbf28122adf71c0b1e9327a8478c57ac2d6e3974a14cef2e2720d1128c9d1da629479d999ec5fb61a1332ae4be25cb8bb99d9c3c73bb9b9e7635e80dbb23e
p: a742043496a622ffcfc1fb47939678867bdfca54e3cd68fcba161043d7faae8854708506b0904096ce6ba7d7042a76a5be9ac5fa316e8761d49effb83c08c6765cd1a6a50248ff804607319a31ee3da393eb4b6b80347891f255867f00f55af2b74b8391b05b6f74640cd56359616bece266dd7c1f1cf1eec0787f3b77fb40ac718fab735b0a0a1aba0a4d4d5669769afd10f77d77b756f2b7c841e13458bf89e7bfe0d9691c7b387961fda8f7c56119980fc4d92a9f6f74fbb33f20f9a1a91170af04b0526496e3a374bff44ac25814f0afe8f50de0c835703170695cf8d47a97d0848a3a0f00f4c613bae5795b45ac002d3f6dc266c1f64d51e4df2266caf7
q: cc8e1988d4d3acc4f5ff515e0d856acd69e55568952a23f41507c73daa33ad51
r: 226f796fc7fe4a13a2a681b34cd2923fe0651860a906d2261fdc0c7492848daa
s: accd4cf3bc38d358ce3fcb8217588cd35d1e44429f2b0d06277fc5c8d75398e2
x: 8d18a6fe96df9fb7e9e9e06d33e7fee9b6954a1034011bdc223a09e4727a52a8
y: 8ee4e1576c96575d9f50a3aa7cd6d8bd6f2a4df2d87d3b638c5b7e2c3031d54052d3d2a9baf808d72ee1d9ee5c5fb00361e3d3f7a9c0444835157f3e489c8394a3c4c90fb1b4f27451766c3702bcb3b0d546d84921188c1aeb6ff673a155b7da9078184204a77b81c46a53429ae83e9c1dc79fbcae4d0577213c5bd0bc7af1fc5228a51e2e2706919e70cee56aa214d244a560280d5595248d26fb88f262fb4b033a30ff5c2c1528e98b18f48d9efb457df983b61d247a4dd2e47a6c697f99945873e72b0c712df8a3f0cd30c6a04e61f722a75c03bdcbadc3565231ec28de8e30f4d1d026ca769e171f44ac08ef246e83aed26b71c0bceb0a6ff90059e4a4a5
g: 84f81c3b2171f1d24f757681705d73c089c6914012a1590c8163f7a40a5b7f04cca8db0fd573e7adc2514ec38cea5fc53e8e0185b738ffdf6e3ce2d5b699746010cba34897020dfaa766b7c00e6304c7eeb915204380d8e925fc3293d0fd0293093f6f8783a4cca045a87c090de79ccd671f978a5cd8fd0ba6f333bb27f0d0a8e2086680d0e0b328bc2367556367e042f35408cb48a5c2190d6f273e1a16f76d4d5fd5a151b6bac6f80cbc05c7d4a643494b0a378868f43e60924d3274da744987f909a820ebfa36a3b5ef03dbcfdb00406ac837a639bd949d3e47e2e3a81cfa6a90c22412505ffe0d0958a4190f29a2cda1bde50ceaf80201e998aacbfae8ae
h: e0
m: 478e7ce9de1bd541b46b472d99c9e3d326ac3bc97bebad93bcafb61df59498d26894d41c18562c57bb3b43a431baa5b9a64fa6a42189a9776757432346f59a9400ce2715cacddc7fd545b1607a7531baafa07226b4a6cf7ce2168989ddf633b471363740fdc80ef49d38
p: fa8b15ecdbed2cd36a4af57b4b9b31c36f34355ba081c40753bb7ba7c593c668332ee24d7412f4b762a578e1eb9006fa86b220cb00c355a3391f132f885bb1f38d67f3749623b0aff954a2862aff1e486eff5c4a0dd5932836b9be4dd6827abaa96f7c4c76f16051693677281d717debd456d063e28d5442acbf15b93439bbcaa51bc9acfee1c17fb3bfa72bbd107bbb2e116cbc7ceb3d6d56c59344c78c45e70cff3e7c66e994d2aa04cb62b1c0c93d0c07831bf2016146a0063d49fb0fe7a291d73aa144f73a52a705d71eb1090a3912d7d8dc14ffc5f8f69f2c501a9d002c297d034b148f315067c2ee404b1f8a39e0f06c8367127be81cbfc17392bdae27
q: 8811cdd48cda5150c19d7a7b81daba90acde023f885e74e2b6bfadfc7e219a77
r: 1652a0aebb5767af4b3609eecb12ff57a062124761e58f35214daa7159c55af0
s: 31853617c51d462ccf551b4d12a5c90ec5007449f518a82ee8dc58c1cd07aab8
x: 2e2a0376d26ca8bb6e96f443a0dab680f77eaee87baa0879e27a2a511093bef9
y: ed8275c783eacbecb164dc2946c082a72bc429aad3b087ff645d4ac265e2bde710f45a1c1e9a4184c1c8b2fb2315296fef6b87ab83f7687ff5f9f08c0dbadbf824c2232b1d50e5bd583848d280751c79973d1bbe7d943ab7425280f4b8ec948c1a67ff837696a3a6d470e03afb890bb44cc169a533e3ef1c64dbc60203a7a0196bd0aaf56cb78415ca3a99b9d98420a1bbb90e4080b42b41dfb55e057b35082e552f29d4e2a623d091798b471406bd5fbaad5ddf8733c36a18a7ad407e9debf53f534367411a952201a0276efd781355d52e522fa764d08af0cd152bf1ae13c90b37515ce09c0e0238c0b7de894cc2fbfc5dd0d5e2650502f77b3a256553d906
g: 2ea7db78543274de385e3c277e5f4e3cd0768f26ee5a4f479cf310d6c3d15539b2afd9308a0be8d0d69f015032438eaf327726217d75263f92a3b0d833cac7ce62ccfbe56159d282a73b22fdd1800e87c1b8acdbfd6ed1c40dc9c6a24c3aeec10001fc3456ffa966ecbb0794b9f890320fad12cc882dedd80739c741e24f337dca727b975126b1cb07f058788ffa57a2a54c948a7ec8f656c37df380bd05dbf766196001115eb3dac84d436be287e612e77c9fe1ce4cd932aadb8848d5fd209a2940a77315e7ed4f133daffc38dad224c83b4d3339834646c982fd032ac6a5a7b1a653f429751af6b3e33a7e3de6f8064d83a09115eebe7dbb4d67291812eac7
h: 180
m: d3
p: 82c3b47755ac0211f7cfa6aee8c184d97108a00016f46639ca1be9342455ff6da2287a0dc744d33f6ebe7e122bc57500742cf70c2025b963124f065b518b96265796df2cedfdd736337b9383a9aed90e53e1e2d020c58b5ff3665adcfaa2347bdc3d6606271865f033cb49e5a0e91d3011f22bc237e32026b9a6b4808ecbe937a7a39d073f808bca3d6644d8edb4b2419aee99372ddde94060ad4204491e719b8d8104cfae0e5b4fd1281a7b9b8e6d7238f965b5bff10728dca2c2a5c9fa24ad5bc1f82ebd25f243ca1cee64cdbac63c441ea275968c5bb5992d749bed0d47475e7353e38f24819a275fb5cce6f1997d99c9ff63b81cccdf464fe3bb056b0287
q: c482c7e3faf442f74e98561b0cc14b41cacf2e5005055fe14d6440d53a19c139
r: 2c9d6818013855ffc3a0e6c85e2a603e0c8e24738eef2ea18338136a48ea0593
s: 71e2c35d473986401a5a7ee068ddfba31a5a1d0c833841ef42dc37aaf5fce712
x: 797f4f061f4bbad13da298c9f10d6fcfad21e915e2a2129e73771e580d843815
y: 1ed11fd81ce77c4de03a2f31185ba794c499ccbd35141a611774945255fbe036ee4c317c7f0372543b175847ac75329373458fb8ed5864c5e2fef037b30e6679f27e57ed99926a7f4527daf0061dd69fc12b0824bb023893840568b879db23f98091bc4a3daf0b0b48c1c766eafb73692c71f6b31a8677fc43f07df9d5c4efa254f363c99e50ef0c7a0a68060b38394396467cf3c9eb178577a12f6ad4efa60bf7c5ea100e7c982dbe76a2e823d775369bcf2d45677fb66c20bd00cd6caafe407a9882829b2948724bf6a06512ecd1456973b3d6e03551658c04463a52e45cb6c3ce50c2d223fa26c97915ad206bd2c8a80d2100edcfec065bb594dc820ce0dc
g: 60190341f6a04ac03a9bac1310dffa2fe29e074eeb4825fe659f871b57424a5eb0a046c9b76f7a085ac7dc4752bf333b8ac54f35e650eee82591b846dc500c638bf88480bf177c6f1ce7144652497a393e7a9fb0554e67f1ce7410f862177026b7d993853e2edc83c7981ead33c728e73d86839d6ff4b10ee095b983020eb2b3507eea397fa4dcee94ca184b0ce79046d61794739784ff7006aa36b36ab6d00db7865f24dc41a94766dd53172c2ebbb23ed44dd80ade2384b17a8af12f088bdfbaf7dc8ef3f7b5b0be6f0c34d1cf260c88bb6afd66d7f45c7f2c7049639b5d1d320829916a46cbee2626dc15c4cc06fa302d4b1e0bcd398a4fda3bfe8ee4c66b
h: 200
m: aba2acce46d95feb5880b3d7e69952491d6d815c126b92dad051c6017e7960e98f3945ffd9cea849c9560e1c275f0f9f1fef0c73abb3f53f10c2e07bcc4a735637b7d92d0643ab4b205e444e911baf14c4a0e6c4f7353cba88fe6a2a418572c4cbc1ce99a9f8c9944f0ea51393d97d823f8a2db40ef04a78de342c3e5b166c2d070e4e4d1525358d5f14e5e5d7988ddcccb4700106764e827ed5795565d7a5bbd3632a2ed4283a9e6d1b035b18ce5293ecd2e7aca437111e16550932ee1d75be24b7610c4ecbb6989b95a5dd21e394697fd70658248188670fccaef73fd9e18312999fe760de
p: aa8f94f5a49c956c1e5973cf89ee16d485884aa6d99210714d384d204a009e0ef3793806ff81cdc5f4e581cbe6afe3e2c8919e7fdeceb921b2351dce7edbec4acf6101b8df7d80affc40c07fb4ad126c040e7f75a78446c5796b924917c1aaadcac132348aeba43619c1805896ae8e96523ed513088cbf1b15d67c5410165824beee1120232c755b6751bdf3b8f0f9e4d993ce27d37a7e507cd1474010079106729e589d6a0851679d24445ad43b91a5caaa8f4787bff4872807330893884d6490d4e5439ad6876540d8b2e61fbd543235d98b885332c4b54d858b356c9329b52607a91e1417b44789b9693789cab10cfadb0541b3d29c427319b6406fb5d38d
q: f4e120b4a58b6cce16abd1f7c238e7454d6bdc112db8df23da12a9336d374f5b
r: 2d0f4808d0f4491a2c7684c82a22351cdd138c0eca331b553f443f1e763fd300
s: 26a23dfc2881cd964b787b6f16c159f6c8e2db3477fa06d276eba3ebb6b4ca5a
x: 956fbd89de1f4c44fcb67784a1e3f54a8ecd607599611ed658a2e80b6fd3e05d
y: 62bcbad2614828379f3ca4a7114f41d0ae01cf1469b1e9e90d2629a601db12926ccc1d4dda88496f41bd113dbc69360b16e03ae3e97976924154ced4ed614e5e60f38ccc4613c918fe6fd8d6cb5cf7b9d9015604ee2fc4d597153089a1f25b540b9f30e2f9590196474c9d74d7295e654afb2b29dc6a5b16a0453d8342c3b92d11d665cb52c3078efe561d8b1f94d459007b51708e544ec11f0a7f9e845c105bc2656ffd96244ee8fc335916a1b191fb8518f99aac57770e653e7941fb86919d689a42a956d3000c9929b85e3b28f3fc44de418de74858d3627d22277552bfbd701d6b7e8e62645e4119d2f8737afb91d9887cfe16ff3f56044c2a3f9f29ea5f
g: ac8eb3f8039a814c713a28a8ff37ba5fb124a849378dfda98d8cf7914f98692c1fb12af205a092a7596ec1b8d7628b58c1453e6e17eb5e55ea8edc5d5bf3f7d9180e8329acba45ba8a1ba4de034523dfbc0bba623f9f8e9a8e057969678c785993d867b0d41b2c9b26c27a60650813bd63ba2ecfd2455754dc794aacfd1358b6627e556e2be0747739c35ea9e5615768e0324b659c7bb3dac376d0bd492d4c11b850dc1fdb568abfce80e8b46662fd17a79f76958766dcf90cbddc984fd46376b0854f2e444baa95e8b3d4f8ea638ad68b3a9fabf203c85fa9ad33b39ac1b14b7a29bcf988975208ccc039d5f6d9794932629629b69ca7f28eb31fa26f21dfad
h: 200
m: fa4f65c77419ec1bad74cad3c1a3ef4ef9ae4c8c6cbb826c9ee6eda60fe8c740f8f80f1a88329422b787fa3181be61d5bad5d025d73692baf5721f487b9079a989641372f1abb80ff754744c40f9aebdce4ad9892a1be802f75ff3bd75374a4e20594e5ac63e0eb0eba631c98cebd6474931dd426f636e1d4cf2a625a374f541bfd1efa5b28395a964d3bdf3c4d9a6925071d4d566b94d1e6b88f415e06b304c0b27304f62db7569061e4807
p: b7bcbbc1f5fb62623dca02d29d7563f8e7222869d65cc3837be8f5a101ccfe8e92bc1483de398b5c43a52ffb33bcde33671f96509f275e62566699d2e2390875f151edcbab34a8839ab4c7b9e2ccade227fe7e16681c2c69fbb9de237222b5c25edce53512cc8690eb88bd16717ce6c09dfc137f959494773b716b929b4304b72c09cb39fef5e9f8da250ec224880355b65affc1972fb95e69421a5515fca5d542e9f6ec337032eb49332c5aa2625f968e5957d69c91250e72c1f52b964066ce6520638cae33efe531214fb7dd0ea0573005879f3b79870807c6042a5b3291a6c810cbdd6baa76639c67923df21ae6794251366f67c17ac6626900748f64ca67
q: f0808df2f2e74b06955cba686138c4ead7fdbef624f0576da97ee9772dd1ba43
r: 5bd38c177236c8cf3813f6bf6c5b97db74d8f372c7547c2e27753e5674753ea0
s: d42f9e5e11a210145e1333379e481b25797d3cb7bf1007ac9b4995360cece830
x: 356822bd1b5aab798a1f13dfadd408be46a7ed5909be5e8aa67ca0dd0c4884e8
y: 3a2fa4d36611684a70fc4d0db09f2111793170882e190fb520dc0f3a0b7a2e0b76910a44d358150f57ac9e79e37582bb3d51a556711202bccfb50b9980ba2b848cfdb886c265389bfed32114c41dea3fab42b5577b205cb14d4f169b2d28a1dd6c20bebbf02fd3bfe911c4efb7851529ebdb9e6a27a09c26937d89d4968a63eb3798c1e833ba6485f54d640574db2d7d22da93a2fb4bef1ccec0b6b7c9b0f02e58a27d3f265f3a97a9131cb76ddf53e3d9d065f3ea51f2664ddf05c1c155941bb4e373333d50ffc32374b74a945b0ed4c342c738ea23ca5a4221625ab1eb72930c7f26cb2a04a24f879dd0ded40b27ff0fd50f416f81b0e6d8774c368bb2a991
g: 61734db989eaba2924c97121d1333bd7be6dd9b2c40772c4b202c869874fd0bd7720ff9cfb70d7701899c8efdf2ea06ad3c05e1f73525c5b6505bf1a251ede6e2f8b5ae38941c622490caad12aaeba139fc9f7b2c204e1540cc379a06921ab9dbc285be694c5b5d4a6de58ce30f0947ed862b3d5caaa5ccc83ceba55665f84a1515886bacd7c3480069fabceee5f0009a6a9f6f3d4f9778f822f3522ba3f1014769649accb61e3c5c03cbe4102a4f20df850e933404c194c9fdd329ce126ebef57c00f5654c301d5bc2222fbafc460a3349c8b7850759d5aec6f79d2545d0e7cf02ce84b0c16a032bebb64d81cbce76350a6a0ce60918e38125609f8c1012d76
h: 200
m: 344e88bfe00b72e89ff5c8be3558d3e0c1acdedf3b37d983db00ea59a4ddd28ab1d90e3f49072f9494fe625cf5424254ca5d7f3b6e86579c9f8789d90e6b750fb3bc24642c3d8890c2b8ebd065a5430b414eaa70d599f993c910cdc65377d4b071165d279b6787d7da327bb874861e5c1b00aee6464affee324a98127966f78b581ddc84f448ab80801a0576e192fa7abe1f63db6efe63ed5f3aabba675d5cc325a958b45010845ca008e5ba670cfd0ed8ad1cb0245b69285d83a9ff8bb763d47dae2877b9774c7dbd18f30011004fa2f621c9ad377a94d754dc108ce4264dac
p: b267238bba20604a2b652e85659e2a31dfa4e2074a6c566efba265eba5b080be1ae83da7b9b4a613e9779e67efb663c5e7b1f08c982031b872113094c06c994637326293911802beec6314ec3516597c2a3f3c8c2519163f4aea095283693bc8792025caa13df1f4be62fae9d9fff2aaf8e5f4fa8eeeda556a1bcde408adc472e6fe684c30b73508b096adf6a22d7524e3de825ba2712267a2bf51cd55b89544bd0f407cc8a2c98a81d5bc7e8a9c880e9eaed204b2d5873cd1e841438324f3730a32e51ad519983c4ec7297f7fa5a184c90e12bdbac4291df584a8704704a18b144f6deff0d023c60a44e9dd519b8446ab02f13751cd3b54b8154f9d513f6b61
q: 93e686de011b7b330c444bca07e59a1b489cad003447bdc8f0ee2070b0e06417
r: 5fd929e6aaea0ad965309bd748bb0f29ed73063174e5b56543fe12632062e621
s: 5951def11ee6bef6f20be51909f21b07c7f8c053859563d605ed4d2b11fd3e2e
x: 4e088b92640938673fd87c16f62d1e93635abb6b2c3f40c21f24fd40f2b6c7b4
y: 626aaaf30fa8182c99144cbf8300cb08673dbcbf6b92fdcb8368c64a612731dac87b53c26189d9adc509ab80b358bfd89c69393861b022d04026b97f52cc9c756fcec03dac564e636433b81e04422f5d713a48968079fb511082f8bcd3c3567ad55a1948c3adedaeea06fcc8a22b72c8ef10a70d692620d1c88192c0e3041e96ca91e7777935cb492d10f347114abcc6a204fd250ab20f0d7d014272c29051816ef22d40570c56109042950c198955e432f0153d4791bed13a9ec0fac379642c45ce9d937b78ab7f1daefcbb154796bd1171b5c9a31d18321afaf39e783bd572a3a8d960b4be609a06de126271ff06112912acd1f88373bdb78bf896da74625d
g: 388f8f779fc84acf4acb5d3d3406319f944baadca5a3c2de4fefc9e1a7b7fa643c628849261a9e405dab8ddcffbc6c93fbe70a9b5495b318e3a5d605629347d8b31688849847e6befebbbf2e79e43ec5a414af5d02f4a95616d05f9896e8d0e3dd90f55773bab4e59bfcb4e5d0f3e276e8e5fe384b6d18652e76022634c77508e43e7956191f4e74fd005930e9a4d909d9aefb25e60ab8120c7ec1707b76afd7b6bc38ae1275c71f00fc099aa2af1f4b6e90bb84fa7d691f3ea74920c5955d36cac9eeb0e8c6a07d9c966beece6bdc8e075334b0c587b3ba2cd030bda697f8f6945700fa4fa4b5258df9e50f4d73d9520654e46d8df6763af645f416ae61f3c2
h: 200
m: 5e4b1bc904fe606a35087cd6c79a9ebbdb253591e9c2fe8e899a136f3c57308a877597a0e1c345e592b5c1dab65a2c3000ed79e244192af67556b213f5b648f3e9fcfd53bba3850e0388f62844c19cd8c38466298718e84c0e2ffe08a16af43c0317c1f7eb8da8b1a5945d549be6f95c051a971bcddb49b5be7cb9a2ff3782b77b2a616637f90c29ccafd815429a46ab954cd19f49967abe3978135d700b9ec9e279351e78d740d460e1150d27d791f9b70ede0b340fb90604544df7b1569b1df63cb38d9a764987bc0556a588384c9d08f8db826d
p: f7d03ece1e31e9b7f6794aeddd406134e6a8bef74966df3f5a53227db6b607df88780953d0560b6b49c56f1efbe24d8192f1692a45fa50990e6367d31e2e65520d70280227eb02b423687f440c50543347b1289da7e424a11ddda443e70386f5065a44ddd485090b05a310476eb5ee839ff1d219fd7c579867875494c3e6e4fcb70f239e2a78426092f9547bfb048f79d95450895291dc73c4242f1f6ea24365ee8212dd4ea4204731f92d7d4f4c4e4c2d9e8f6ae300f37e6a0e192862bbcf57688b4e2417f4a18010d2dd00efe806c5aa123d5a97522feca3dd5c4c5101c006c89af6abace707c0eea0d86578836dc62f3cd1a666d62c47498d3d7d61282eb7
q: e9e563816813e87a6a244ee7d2974b4fb2f80515cdad284816854bf031f6604d
r: 5eb47f1f7e446b42b0a5fba98525fed8bcbd7eacffde2abbd786d935762514eb
s: df66611d2a93db9943f4bd83f23d5a09492bd10c6e008ec70b0267302a3ade4a
x: ce7e7d8b5557f96e1d1d336d3d33a9153ae44eb788201ffde8c7b545242cb0a7
y: 1b9542a2b6484c348e1395c1bfd3fa67ca32c1ce4adedb6d0d8e9b53e2279518aee859a2904b8968c70ac54a564ad8f8d55e210e66dc714bf7281e94d6e0bebc3218944457093cfaa3099d62da4d2cc017f1e913e32be85a60adabde406c3cdd6901e36cdff95de87184a76af4866fbfd2209c03440676126a0daf402ee5149edff07d148d30c4c757fe985d2dca66928c2970fbc2d177fd81821942d25485b0571b0c4f118bdbd7176172ae94d94088432a1b72a5780603f3987e1ba27ae8aac725d0d9b5ab3629b79095d4c401a5c7cd1f9d621b739f75a526084d784ed2498a4bc3ac61bfb2c8af428aa1d52016c91ae7233a007d4af927446cb9301fbb95
g: 19af3cb0ba993ac5f95ca9085690ecc0b133c36615b1ef0d2339b53739d22b4d4e2abf6556f8af9913bfd10b82c1bd0032628ce189795945c23cd3f3b244c77041eb60ff89fad2bb27c12a90a3e623ce547d554d3d3b358437103476924295c1b5dc33d669d16fbd9bf81bf347df9693d0593d1692f16519436e508a70af5175ff56eab93d05a3c50c92ab7a8727b5291815a790071a4fdc18f6bbb1e2759bc3c678175373d6ed7b8c0f2a2e1d5f56da3180a20f01c595766bf0c0b0b03a0503f1526e522c9df5964d435b540d1b241c09f1db57c205ec472edb3bfae8e6316c8d8b2dbd9b010ccce94ef2d00c5dece9d7e6b265f0d8169d0d61c3c9749ca076
h: 100
m: 63932df3ffb07f2797ab749e92af7d202b7642c812313acf729ae4b78d556867bca6ac3ee7718224e0dd2ea7ef25758857384fd903da201d6baca09b3207c7c95083db2db68c333249c57d11bea3f1679cd57bda8c1e37868e5552d77aa5305df56ae689a59f9095a894f62e23ee3ada08114f057b0d8bc876b4930cbe00e36787e54d8221f4977746c33b0a7a817f3e9cbff7c1eb456195f5b956eec5256ce3450baed681acddcc52abdaf54999cfeabdcfa6
p: ee4b77a8c79f3569eaff215714ffccea1554b96501bd33e55582e230850d0f9a66aa390c1ecb32f72b1ecf35497613c6035cf7059a802bb1bc16d0aafc6255fc7c0f11113a7e63d1cd0abb1616fadb48a156e7e8b3dcd3fe95a44c5e81955e2e9f17dd79a81e0d11622e0a4f18d8465c6d839acf443681d00b30d6ddb927fba5d922598aef47d1d87efe92b2f26fa6082f16f96392581b7857e5871e724c71ca6c36c967b2bb43aea87e739d15eb3c32b5e5ee61e36d3390e1259f7ad212ad9a3a22e54e3842ab5a28c650d704aff148cdd3e30c7964fe90e293f8c725589ecd75691f2e28c355c1e31b04320b4e0a79c2b4aa38463ff2562dec88b9aff35983
q: d2b63e06f16125d7ec32cf1a1aaf9071ce69310e5283e7bfa0888d756142b5eb
r: 59c7fddd72639d9a87ad8396bce88465344493b118f6b7e86afa31b2f192f173
s: a883a83e5a2a692b9973c8a24a3188ce12db4e3fbe08c25ebce350ed07f5e3e9
x: 946761321eda5234af454d161cfb9ba8527856fb853e6554e661f24141fe13eb
y: b23069fdb957d8b81b046ac261cac01546d42ef4e68abfbc7a4c144c9d449ae3ea00b4c13b078c800da7190ba610f4e362a2b239146f7503a03880f22ed3dc15cc6e01e384b875df6cbea8ada7f2e67be7c72c83dd7748a858e6603f28b9759786fbff43c722a6d57a839fd45a3c89960d464c2a962fdf4fc23307bd6ae32faa223267113a9bbbe74b5826bb9c7baf83ab0d2893c9ffceb904e7f2c23163a70cbc026da20eac66cb3a5cd0bc2df17e67add12a6b1820bd12e3957c5c924abf5a4112e8463d326f62ccb5c402c2cb53d90b3e717baa14380d136ca1a2ec7d419bbf30cf8f31f0e702b5f2b47d73d9682b196ce087ec754973924e01b389272ffa
g: 7c6c72f8dc74ebc46ac0b8e672c5c6e233989fa88f7a59872dcb848b2e7a0f514da136a51b74c2493d576d3c5f7c2f975a7f680767077810cbe722c37524ed21d39b2cf70e7e484ba7d9d3ceecaa5dac783e56be81bf4f76e09929d011581fd53a0a9b73dfafed3e8436187ca2203044f167cc319773ec5850e9e13dfa13ee5a95eb0be1639c71e851c4a74224be7072358c016841f96b58cb0ea2234424d4a7bca5b8603ac8834a6d166976fdaec86f97b174b5491fac3272dc167713996f74c9ed2b1b27ebf5596f2a422bc2763987b17498ce9c3d8bf9fec77b1485579809197f381ff8994a9e4e1ca9c8b958c1ade7838d5cf9ee45bc1f6774a64ae34b29
h: 100
m: 37f9dde44693ef29e7717fb2ff00e9103d1468213309c651544e4f9fb4fa2f94997a7a1bb75c4c372727fc457a0dd7929c2fdb263a6800e14cdf1ae1d7ffac1d773e30d878eff7f8e0d4037e3a6752ba8169bd089d2196e81526b0952ef7e298b12c43ed5a81b437b4a8e6dffb193faba8e5bd8da3f25cad4cd3577bb4ef37bc65ed64ad8cab3d9f79795c30ee969c5297ba5599d8f016d89201e2875d4b3ff885e6a8ae23cee0ec7d67b26e02652c5fa6f576381bf2874be55e7fc273f62705a0db56ab6452f9ea5143de85db10aec6ccc3
p: 9bb0886277e09edd5c1c1f54757a2f8940b6a539af0110f34d1c6cefa4ee8d21d0d58be5f235a3d171b68d1f01e4cdad81377db81dce2208dcff101160690ac18cda27c0b5af44aefd39e43ca92484b950ff0a5cba5db13827f9bbc4313a36b4950bfad768a10e0ed71252f5794d7baeeeb5f2a089759e62ac03fbed5f8ba58244aa517c9b9fe29fdfe7454e5259149a1654fdeef81138b4a5c7de650b7b74f4894412ec22b7b66eda9f877285932b208f7f362e18ed3fe78aa193afca16146aaddee1c2884891276b222c8cfdedbeeaff5409a34781f16eb2a83622fac07e767699b4b28ca6b0fa7f4ba12e8d32a3b1ed02e330ceeaea9108a59ed9aded5dcf
q: e7e0ae9c0978ee712309f37a28e8de237552d96fdddc3e83cc544403c8a59ad3
r: c62dbaad84de8ed15b28ca9c438ea7d1400009adb4ef982c29058ce9e84a9178
s: d737dee6e9b43b86b3b15d7329adb1a87417ddd2e62c0d2ea6c5410e1c0c0a5e
x: 4b7fc55176b49588be2fb62c85a36f6bbafc75d5b7b8d4089504e73287d394f7
y: 3b3c00e3ad57e45bb5385832f585363573f4cc1720cb5857e84a6e49c02eef3c70cf5b2f52e88db401913d5d4a4fa251f0a572d967fd2562b92dca8ad2a4f066d94bdeeeb9f2b8b1886b9c2ab46fce7d4c16001017febe10db1d0e1b7d03af8901dff5248cdf2704e9f5ea032dd12ca7a9e1af780eb8b47109bf7fb3fad706d4ad3b557652fc5901ae3af9858bced373d06c9ddafc8a9a018c88fa619b8e8920deb3e0a002c91037dd59cbe55a08d2e04a56ddb9a17d6ffb79dc10434d74a19816aea736e0ceb5e8eb1b03eaeef275ef96f639b84e0592c6ee450b104bb1703814bbec2b3cb1782cf08da2b8764a5ef1709edebf61eefe7765ddcb449c9cedfa
g: 8026ab6e5b7629490d7440a768c61a71fdcbf71a9d0f14246eb5038607a41eea962e55688398f4f6b677c66c094c33008ce8ce5f94a6fbb5dbd976d735077f759ee2770db6c423eb14dc53389782d2d1e5f38a9b525f4e266dcee4e3678df6fec436a92cc8a1a6ab86015acf42b7bcefeb95788a862f940022c205e9cc18cb2a9edb5b769eef3a4a23ab1735bf031a430c6e58b7908c96ad658b2936cdd4f7da23d2280bed47a7932085ea9f7e128e7abc6f43dca4f557bcc713d8a611db44f5ae96f496566da6badb53e0346335cbef34161a56c676a751d70378082833fe30c3a417f2c4f524fb40cead58346dc9eef4184a0ec69ed973be3b4fba33d2de30
h: 180
m: 99d6889a5570193b30ed19
p: cf173fc725a4ebd1885bccb5966ce3f5d537d76a1dea2e38732e3904f2607eef3eaf6cedd8473bfda382e0ba116515ddca45115bb8ef474199221adea40d93995bbed31ce144169d96066a01557a50f9261bd1bc492ec321bd13f0c690fa42ff408e1c7a155b202e4083d315c2330ca7570f0f51abb5dfc97e163c41ebfe0649deb0f29c9fa86dea061b4135d8c2feba16766cbc0d7a319e600c90cf851fb3e0c034317f44c53e94bf12f7d814536203000bd3b114a5797335b34408ac2f2b707063c5526045cb6426c4aa17a71dca3c1e722743551104908b8aeb84a6901c0c7f2407e93e790ad246a4dcb1f575f04726179ed49816fbda08db5f62e7f72f3b
q: efb1431558205946d5daafc2ffc70f68d36eee61ffe7bc29ab892844847f6fb3
r: ddce65c1cf83aa2d98e5dc57a6ca2d9da23be063cf1ed5874080d25ca46693f2
s: 66d87a54d9733708d3911099b820184fe1cdb1dc990740b2a8088254603ba6e2
x: d7d22e0576fc1db22da198e737eab989e0beae24661e0a07de0b3679b85aa8cb
y: 95a70c1bd373764a6644064946c18b04a4f1df99ab7805c8801db6ec6b58cb752f7e231c91d2a2183d49b7311669931d1a25ccb2199e0cd6ef934ed2580d5a2afc3dc8137abe0d18e4aabb3115a2b16a6905d27ca8644044a590c2d62cab3f7e88009c03b529d1bcd1ca5ba022deb9044adbf54984d2e4837da5aee8ae90856f3304b5a9f0a15c4222bb4254e0cd604b78805596b64b76486d7381a830c799b0719835ef9770ae9423821b2229ef51c38b208f8af6565719a26c3b1eebf6966f89b34eefaf4952a2c55f50f55302d7fc2f1971746edefc595c9ae00c6fcde57102efdd152d738becee526fd79abb128698033e4bcde6c09b1114ae23624a0116
g: b4e1d2028a6f389133d85e3b061f14e66b773dabe95c74479a6374bc669147f5518d9975eb153ba174f02c6607ad61a0527e77561e16b5502a23c328435d7f559dc22727f2eb7d9a1b094f5e72ed605d7430c9cc9be739c6ddea36d08846909d233a515781c13527e82c4a19b797a521f37f4b75ebe96ca7795ded21bcb3dc9dce2713b2c37eecfb9deb729243ded4f84462605446ed61fa906213dc35638b9a184055d31af876fee604463daaaf1b1aa9c0cde425a7cf7c5a6b0b4b70852e65df0b3d4021478b8a482f0dad940d666056237edee2e3ae23579c8b9cd05ac88b0db66190c3d296b257fc7cdb2f949ece9a4b28b96b0836e11649d67d94bdd403
h: e0
m: 1d212c77a95d98d6d8f9da18f426989401ceb5646856636643041e925339feecdc3ada9eb0afc5e8c6e87a6017ad1c984f13f9330520aa67c482dc5c25d4b8992cdbf95e08ea84f9ab1dd5fb688784b8cfac54e9face7569a8e93a5f19ca47d600e28224f017b28feb02595f06f303e877995415c15ad0d058d203e78c1714e302a2046160533a4307dc853e1d452058bbac2eabd15b695b480ae9e05a107d859e1ed1a787005edafc10f6cb8997dca91708473e66d8ff03f0fe543d0e7b
p: d42a6c750e0b41e0b6ace406f39d148adc383181e63bcb5106d9ad8a41ab5f7611e53de1fcc52e17b453c5bde071970e91bf504ef50d82ac24a7aa682f9a289f36fbaebbc4ff50a29a207b8c1769103345ef16f3dd51367e92aed23d4be71df5e69af483c72857b669d672c60b4367b10176fbca88deba8e8eee938b8ddcc7cb820a8cffb307ab9950458a871e91a5a112aed22bb180319e4869ef03737a9b9210d84b52aeb6f4f529c9c2eb8330033cbca7fbd122a98bc8fe511ffecc241c74c6fa2b0bd6aa7b143467edc383816a5ebee7e0c505a43c5463512f6026bdb4297ebd5540220bb783deeeac8548389c4f538a3a4ef34e6a308cb0f18b0f48207d
q: b2792bd300158895a0d0c4d0f88df3fe04a0c021cd1b705cd7e80190f6765e1f
r: 84b5f531f684862c14ddb6d51008992177fc57dae0d5b3673f6dd841638062f6
s: 35646f89d60b6bad191b7c01e84cfc3d16d9ffd39f4674a9a47ea08a8ba79d3b
x: 4e8e4f2681613b1941d3278323694d0167fe1e19c050b0089e505502fcc81acc
y: d13ddfbbde5b088bbb6e57c845812e310e7ec24cb5ebc4608071ff0e14e115ee5869eec0d4a066f09a80fd6eba955dbb845b28250bf021f6d397f22b33b82131e92a9b8c012ba8ff0aa0ad1d515748622bc7d1eb2458d63c39b885f460805bc3f44ab9d8d228c1da45e645eb253afc472122ea4660180d7d710a397fcf0be898f043cdc2d94191193799bd10b4dc5fb53e551574202149a8e9351d7a8fc2b235752533ce2c2fcfb83a1352be8291b8d82081227b96f9555f9565ff9da968076eca545d1bed3a76770ae729e881e17aefcd00a737176a49fa7e7dc806df1d1e7d1df77af6c9f2dabd2786915d93e0a6a8de9ba62ac331f6ebf1b6ea34f08df7d
g: cca5d135ec9d2bf01158cda42b6b1ddbb37dc317185ec54bd90890b58907039018ab65cf0b5f29599c6eb19a7aadc4268e94ea9f410f7d75b6c68cecdd303d4d4c6766693494d82e73fa58cb7543f865cb510133a370c4df2d269155323f5be3c6f2b19fe58bab0118c3ab99d3bd028d495aab29a9cc3bbc2b1889f5320bd4bb8a671301c98b2840c6e8478819afd5bf49543adea2d0bff84fd4e34cad9b8248d15ab4b28eae6f26e6f403c93c6f9da83fa142d41bc48896ed0cbe456a5d0ce690e3a383d67a73a38c3a59c065516f665137682d83932d463bf916a691cb3b45bf94f8bfcefd55fbc841ce3519803e6eaae82a3ebd770fffe96e12c58e37209e
h: 180
m: 1ad404625afba54046bf87e04c6e5edc7e4c53b42636596d01036897db078b24655d8e623441649bf70f21711b0bd14cfe35257e091e98fb01f8fe5f8d570378b895a996f88768a85831b2ad7e25e415faced740b69af0d64bafd115265a2540fb2654152dbe2c92aaebc948ed0656bf639d6a1cc1eb16efc1f9444b84fea8fe173f36b3
p: ece373c7afa118bf4071cac52f31570f9bb55457346e18fb9f0ed16506cc9d8eaabeb4fa62f584efced2cdb7d3f7f4e881f092d27d5fce09ecabf637b553988e7085c958cfe9fa24db5ec968a007e7555102bbba1085b6d910755e8c2ebfbb3889ef522e9ed13dc49136685774887c46cec3e6bd07a863c73ce0f0e6760cd02d73b73c4151c459465cdc64f4f535ac59ad2dbc5c68edda1e9419f11f4f4404624ab068673004739046c16e38b0e02ee80a57e5938f82bcfd844063d94300cca7affeed923f70a8ab7265c2166e5c0d76c0a1d929b590c0fb57d5983574d4a7c225dc5e0b698087a5090772163c2fe88a3210e13b95fb87d8cf8f45a9c8a1933b
q: fff877e432fcc89d58674e5ebb237acd268ab2a70adb731dacab12618cb20849
r: 9516009e31dae37fe78bd1fb03beff9c753f24f2520fbf07e13bda1649832afb
s: 971fd8a2e073eef11b4a55406f25d30c3501d4fb32531fd49ee017ba9688bea6
x: 8283f67a97d557a8a69eef0688560dc323fb7f6b11f44605604509a978b36d5f
y: c54e6f5017c72c8944bc6c9ba0573046d0aec2dedfbd03bd384a44234fe221877c0d03d6822b04f2c1b6855c138788d0de1da66df3fac91aca328c0e33ea51c595e518169e51783657cbd2981c8ce805b35bcf8af66a30533e0778b43011eb41c2aac42272c2868c55aa9685d610e59a76ad76957fafc7f167bd74494ea5d1ecc10e59aa244025fa364ec4ad213beab9607b308a0b6d8c33175825255ada2188777a692f5466f5559779ab0d1ffe5e5156b2eca8729141e223dfd81d32932c71bebd2b9c226dcfcd7f5ea6b70ccc288d11e9d23e0cb0a6390e74ace293ee172c537b552dcee3f500e2d92e7acbb3af6dc2a2294eab9b034638fb2fef7f51d80a
g: 56dc5c1ef24d9f2f8c73f3f8a7907ea962bf51fb4b0133dfc3c2fad7a4fc50c6dfe6906081b0f5509de0bb678420a8efc232edf92acacd2fb48eb806c86e384ae1fac2ec6b3338f7e7660805008b2e44d13777081f7b2c78674877cb0a891abb32ce86841be35e3fd3fb7aebc362dc1d47714a53c82fd7329216b83321bb968bc8f6d817e4fe71ceceb14cda332668610f66bc8f32088179af6dfd83e33554b58c40dacb725c23a968ab553068829c82c7484d6e34e3b6b5731fb7967fa0703dc532613efeadb4a9dea8d964955db299019e121b9391e846b576c713c89df5f0db930056affffc8ac224f7453d2c8b7647d6b1e7a7535c9df9b43a7e9d03ef36
h: 200
m: 9026ed558df31b65d3d8153b201bbcc887043d024ce6b2a30efcb9b1a694dd95383dcbdec6b1758a4665227346398cde3c2ae4cbc1de959bc42e757bd6e7ec6fd24e1e6a55e0df0224a627f6cf3d65fb904c7d515d707cc61953bc0b79aca78697bcbe952df768d2a3cbc037174e2b4b6c76ab842f826e2c35d68d07b91633617fd9c08e3386c23837ad7f8454f549b33e26f8989c42b4ef075b8598240f6e87d66b27078d6f31ec460ae6ff0ece7daba4e5ef
p: c352dfa974913a5d47cbbb09c839782e582a820662f3fa5ca4e5b69446c7a281bdf713ef9b4cdd1654ababde8648874bbc17d59cca8b21abf8526a829db7ea3ab4463fdac6dfc1ce58441529f20603489401b34e097738e33b792df1c0f2a8ce761814cdfa660e002e100340c512d7404bc8002ec1d5c14728a4a7caf5319df81ed5b8638f4f9bc3b1d17cc25201cf9d8038c994403d84cb482f58dc2211bf6fb876ea81a69b18302ffa432073b1a1093ce726b106cc93cbe3bb242bd32442723c497345f230948c6741a53d9d1cb5b98d80889337e5ea7ff749d1b951672601a04b52920e20ad93647e9345c7093687be7b71dcbce6165ddfc5ba589c0eea87
q: ba7dcb38564e75531d36d642b4d4693721c6a2a6997cf8542dcf206307581d87
r: b9b86c666042877360deb2d39d7fb9c66eda12ee241254353d21e6e0d6833a6a
s: 9b25124b4663190382da29fce5b9e4d43d302cfdd39b0b25be0e99c744027569
x: 9ae7729c62d274c335c00723dac4f60a6c063cd4837a0cb59fd8e08b03e6766b
y: 3e2fc195332100667b7ce4662e63f18129ced06dcaa5f3d06107514dfaff4b880b97a1f8162cf8d9e0e68960928c66d5ff00ae4fadc57a9731ce40deea0061b2d7d7218f2b4b82ede58ecf0f019f03ff20f00ce4db4389e475e29944b4cf09c85f36f1c8f352a10a9fb5cce9c00c98e57dcf8a5e092731888949a67e7d072347969afc54232ed8dbc3d861250b9f57789dfd3e3f2472c82d0edca2e7dbd22804cd7a13e81fd0463c12d89e389a522bb8bb6147888e2bf8b0409413ca9a55318f35c72a0f3f552b6ac6d48012475ef5a8e2c7d973b002abe5678b327f3e3daa206c33251b5e94cb0efc7666688801caf3e37b2bf0754cae1744d3102ae827f690
g: 3bb3d187dea54a6877d3e8b1a2eca5d2f7db982c105956b17e7a975f1c26cb58dd341c5023fcf9a72aeb4fb36b6f51e42cace96203a0bec2d1e368973101ab5c9b2c5c0ce56e6572641ae65450ee13d31273636d3a86c2d19074fac4782a80c5fd61d98184e4029209b4dff231dd21f2f6a6908b8941671cbf2a8be2c095531dad69710130ba72e300a5b379eb1b95215ef60109faaa246effd15d5d67bf7cc745189bc3cd6041e4b4ac5a5860b2f1789d6cc4e801b45ef5eb0bc82d6c9d7af97442f5cfdb9d14c6ec6a292c00684c78103c899612b02ab80e88d0512129b496301b1876a83fc684318cb780f1d1e385578d26510bcde49bc792a20b3ae5e7bc
h: 100
m: 890337b86fc7bdd10bce5cc562806b3c7bd9bc5f65657ff6d1e9caaf4a0517610f247f0707e18ffa3663e040c51ead6d4f7aec91ed8e8d808fc7ed635cfefeb260b01a940198b30f7c0602c932a57aa685e1f433d9692b4fe67b48d53c5ca67b0f235a1f0ae852c6f2f69c0fa64e3fcc5078003093a257dbcec25ccf8ee3dcd199d684f64de36bf17e7b36ee1db3b32a3cc153debf64ee5d52f8fefb
p: ddfd9565909d4a247a9bbf9a8f333c5eb5ea938cd507df896df79066fad8d199f6cba7527ac451ab852291e0a1d328766450fb9452a76542206a59dbb71a15bbd6caef6c68f6edef11d6b1999eadf7df5767d0b3a7d2a3d1e017bc4548d6403481e1979f60b1879240bb380cc2efcd405d4e4e9f7c6d2fe028df2f3cd55133ffe933b7aec7a1fa533f0d5348dfa65c1a6f6be64f41248e584aee93e813173b8378514b329c1184190bf2f34107a8f708f1467c6342470859367fe04be78bddfc4e119be10abf9bbe75ca2cb705ac1737a34a33bbcb1570e21a051e2d9f0eb427065ec757417e0ef894d1aa35e68b922311b39056d1e330d202607fd2a72bb433
q: 80083948949d6bc5f35aa19502e71f5da137102f9754b78fb235d10a6b0ab019
r: 67bd109f6d08acd46d9b62b4c9b0e47c0c53a7af8b12c82a88de323483710fba
s: a28faf9a28d27a393b4982722f87fa0ad9f03122498b60834573a3eec7e8f5
x: 759cb4b9c45b6705c0d0f044ce89d5f0a8ba95a54a97af53db2be52b496f6f5d
y: d088607f3accec36266202ced300e035549b46670fb1b704f379c636ff42e2d650f656be28c24d021f3f852fcc34d21d2979e6900ef96151ca554de550dd2fbf0d2ee555f6daf0eec67894d9899a5cde1d1394db4db4532a12935c81d1f6603286362e632063ceb86a886037e5c0e3a6e226f709baf4a2733e6477c79cf881837710ca93b07eec3eeff60ea96dd0dd57d6fe187688ff5ea3939c1233798a73994ced4b3edaafc4d29dfd801ce08ab626100bb8344d265e01319db4b29bd7abd541c0b634a6bc397c5bc460b4433280e3384d30d3d7cd4c2826ef48cebcca1280ebd50fc315aca00e6269b5458694fa8bf24b971727aa6d8b1b12b8a70fe3e549
g: 6ca2f175cd3b2b52bd2fd40f6faa36da603fca0345dc2c5ccb50e64e9c028b1726ef42196c5b2dd9ed9f5db4a3a987f62cea9e554427c4cc4280abbeca31afb684de63d132a9411d786614dc5faefd6d309a54da7f3396e352e1991fbb34b4f6356d38c43e6851bd3a97c44547e469585fc77ecb397fdb96a738a906193e05f70b4e96ca88e02d7ae619e732fa204889d3a111cd1ecf93b8bd215917bbc06e39321e730c4450b896f638c616cddf7e611bc79dbea607907b7ec2338a4fdbc39a5bf6f6ed41f8e062606df2d271960f28e482c0c02abf5b5e3965286a09331fb15b16e3c4e67fbb8067b867eb054d2474704c4e4ef471b7ff86e6e7fd7a7b98e4
h: 200
m: 6bef6712488c2bdd20324bdf5bcaa1c8c97f82c94ea3406e5bc0bea6b3d6d7c2ef984d4c8dfe6f077cbbce5f0e68486d4bfd1af62b8b05597e0acb3eb8385309287ca6
p: e8634f9616c0fb4354fd4c2dcaf438dbba1ed301dbb71ed1909b9f4844f3d18a7d02ef5ab9a907162678bf170d875140ce1962300c7175acf5f7d61efcbab980d0a509ed48c31180b36e38755c4bff35395180ea3090d6cf4c6f04746cb0494959e97cdb598b393180c1381b181b9d3918917f565a387949eeb0d87385d0a2397394574ebbd49c6cb100c7f29adec9ba8c71f9a8023b29b6fcf00f735ea6980f71f26692ff142fe4d895330611e20539783ecad67466a2c7e944e928d27c94eb183a1af17a0f221eac4de11ab5733bf23c5f3ef6f02d123185744facdb7e532187f60d1d89de294161f32b78b1594ae969722f0cc3b3038be9f80330e971f8eb
q: a8c8e31a4a95eae37996fb6f79de03ceea220724cf9a701663da1af728acb1f1
r: 796e71a88caf22eec9f81b2c0428fe6686153b32f14d20746cb7709a4ce19d5d
s: 308a2967f89a0319811ab4f1143caf651f2e409af7881bdd4bf43207be364168
x: 8186550249e5c62be784bd81cf70fc19e64e10e664d4650f6a4a34de7ecf038a
y: 82f8ff1b3a9ed7548adf3cd4402ccfbe6b4f32a1419ee74e8fc12486616a582c7863ed1678d6bb3bffdbbcdd883d2be2db89b337b54cd9ffa8b5a52025085faad16711be64fe99dd0c1a0ea17a22a9468e23af9e4b6d3fbfdb2b67e98abd912c956d7cbce7064b38d188492391a06b75d2c5f3c19fbf8252c7308c326c6bc63e78c6d5620a43649b60884b041ada3b5cf2b23a46a5ed7c7941dff60fc08a6a727bf7893b57ae0279cc11f876888d0b5dab932fb568c3ebf59d491f04e9ea3487832a29ee8461e1b36b51b3af763432f86f14f0b7cc69b755af9ea0cc9f81fce564a50b8842e1eff67174cad37e139b61edcd21f5bc7b929a3f05ccc06222f0c6
g: 20c7079f6d3348391b29461b6a89d16c0610485a66342408f6fecbe5fbbaa5608fa538026825726fa3b6d0be00dda8b5911f5c5fdbe7789bdedf39dec2aab45c52656fd62b7f4194b8aac0382a6782bb1431b55ec9ef797f96937d99561ef488640b1d7bfe1844105d7f7508b07952df6e8e0a1cbae97437dec4b838f5207a71135955afb862d1186a2b211bfc5e9585de84d64502b3e2075be1cc67ba61695b53522b3052e6f46e09940cec6dec4c147b417f594b2370caed7a1c2d8e34d1bbc02a0d82d10750c088c37d2467d56bc7c60eb2528594d556fe1ba7c5c3b868b14421b9755d05e7b5679b444c00b8db5f9c7188a2770ac04ec7627d5808961cdd
h: 100
m: 2899113a51c5c68765ededd2921ebcadbe27d683c65c6917bd411c3f93a243df0d09c21400a98d8637e185f6a4a06d5d1c6a18c0258b6cabdfbcd39471cfb0bc231f5973ad5eb4547177aa0cbdfa62d1b3
p: 9bbbbda9d29afc32dbdcbc1284a46ca2eda6ba2654337a41842ac0f65fa4896eb9d60ea35776ccf881035c2f6afba24ff46ea3e156cf24c21568416bfd1a2e2f6c6ffa1ca30472308fd33c056a016129e32209bdb0346ef0e1717741bebea31cdd24de90c18ee55c998cbe9fa4f9a8a98673edb6f57f8b4f7e277558e2d3bdd4e452d2c3509afda59cd5aface7a5e056a26213b5e725fb55e2a32f1513c926919c2412bff3b828170e0004d1dd430f677f3a1b954ccc6b30bafab98dd31d2d947acedb59900a5305463878ebca0ca3e62bb91c95b0bda6b51de80257b899491e7827f6805bd7d55809b9d0b241d8523bbd5a9831095afb0a6d3bab1d32206c0b
q: f6b7790c8e3c2804ae76907e7fa14dabb566ce5bda517c7504ccbfcaa740ad2f
r: 15415226a30af81c068778a39f9dd162e3d30e310b4e7eaeef6e3b98bf15c8b2
s: a158c8f1e5779187dc12ef94d7451d35cc9e3ac2a1c21edc09b1d738c153a898
x: 1a9cf01ed5e9eb3e01017561078dce7790e21e4ed9c39d3aaf3b43243fe57af
y: 4406d1f9940d80045d44397582a7a63d0e6efdcc844798f20e1fcc0c2c777d0a468a5f1a06b6fbd7cabf6a8ee20ffe93b3618f4ebf910341812697ce7dccbb92fc515001296140af195837d2fdc40404884bf654d108b5c2af333d472207882c328196a672604228023217b2f2b2067a4aaf066cc53d67c827131e9181f1478cd1badb3e4bd3036c001b5435a7051bf72ece6e3eae0e32228f453a9fa4485e6f5f47a349f08f0c65f24c31f0a434444660526f37d8cdc1337f9ec357b5a44c6a86c9f32b5869e832ab4b664bb482f16df354803ecdc094eb2b9c9d65cc305205d133d7724f1cdf02d2108c020c97b5805096c06e322fe9bca0661d683b1458f8
g: 6e6c230ee7a130a1c099969cbd22ecf583e9eab22eb00fcb0d43c513d4f0771d09b1d545aebdeb86718d1d60059197785c716abca74055d6719a84c03a0fd680affcbd74f5bfd11cf0adf4df98224c804b4002dc0c657d2e42f1ffb87a0245b33e4ae56dd975e165647e46f8d34fcfa3004a6e23f6239a2a5fb00a39d752d94b7dc31967f1fda48a8815057d5794bb1d682c9c64a9b63578090c0a1abc265b85391ceb1b82b49fb22abffae4ce4d8d0806eb5c9ae331f1666ae542ae68a4528abf1852d027131a1e17703c10a5f3bff4694e99f4de5defe110de314af739eb49f0162e0da00bce8a02e8dddb8b8e2c962d32523983672ef075104dddc9e4c6ae
h: 100
m: a343c7c0a91c44aca6b88eab1e3302dbd84adf4ebd20f6ebab85c3bbdd
p: e3908280488206662f49479c7aca2ea085863d80660d87bdc69ab54e40184b747e472a8c824615d66403149674860365556bb606071f67adcb9186e158154ea5f8e5909630788d9f54b6021018c105e2edbf3e6156fa30d753e4d7822088ef6eb431c5a0e603deb5f37d4ae2ee72794de594eb3d45eb84130616db3457a805abf6f80c7f34d4abbe39d257682f0251a6912b939a2ce45d1db664a85d5980aef20d97eb4ef5fb5acefaae4e3de900f2bb70d02cfec0d35ef71cc7982358e5244b16b5ea40e284feb422abb87dec47e2846c040ad4b016c47b5798408fe3986ccda2fae467ea84f0e0a8099e45b45c3c6a0daa36e56899821dd497f828736f63d9
q: f233c2395163266622e121b83ec29dc79ef7f83ce258fa4ce81cf82042127661
r: 3408db8c3e2dec012ca9ac5de29099f06f9c6530716fc796b4e192f7d4013d3d
s: c23a95ad647c780e0be2fbdfe2d42bc57da07b9918700d85cf9e49beeefa3ad7
x: 74a2d6fea2d8f041c10c3737d9747104f5c41f58f89e59d13edaf8591ebe6dac
y: ca3681ef51a692b55e70960ed80b605539a5d9bb625d44f7c9125aec664a88fd37d004575df98e4b0b52ce76116abd93bd64ccfede42113ea7e98bcb17281e14299d703eb8e484040657bdd539acbe4e7731630e2dea3ae3208fac92f180061f0f883493a3c7a37972054d6d4ae646afd60ffd76ac976a404c6758c0baa971356edde9c596d9db04109a2ae1844b33c340560dc75a2511bbb985539839335a57873efd29e30b95b1c17fceede808fd3d412339b1e91b954d0b3fd714dc51cab5270f1bb4e5a296d1bdbddee35cd486191b586ecf0b754f353744977dd9a03b7be100e44b7b7857fe80eabefdfbc4b86582cd912a5ac6330bd35b6f69c21f4a30
g: 3d7be4994c9b044b7de4f66ae796045213ba2df278fa55d4e357acb22f7a38874fbaead347b1a4e5928b6f1f0ca52981276f46406e7333d4830df201a74fd9988473a4b849df3b43a0f4ef03dafae34df95b0d7a22e445283a151785132dec8b30b2e64026704115be684d41b611bc874bd488fbd05f2f4bf983bdb997cd8485db147b1b5b93b25650feaa438248d123fc60f952a687cffd1c7679ad7339943bca6f782eb6f53a4fed98f0f3c7ef1f278d8b82af00e3844905d8dd0ece918aecae0b5e871be4fb6842877116112232a66a0da9920b6de753fbf28008aa9b8964b80464908be860c826d8f767711a70227645bf8329b053a6419433a77c29c11b
h: e0
m: 2e05c0d36fe4c1197df12e6e78764fc4d523064b007578bb0fdb710fb9880a4d34485889f5a938660ae13882f297ec59f8b2be68986b612c2d30f92ccd53b655aa12e830d064a46f6f1b00a6bd6072d03e16d227bbf7588e36f8f849eb3948c9336974ba3fbd99e7c919d8bb37fec8efd79c9d80c087fb1acb416d81732b30b32e141a5b52ccbac2843cd732409f3e729efc86a0a6c14d3e0412c558cc76963d1244d3819f6193d491e75eb7
p: dd4fdba7f8222d5f5c52b127a2f51bd70c45b4e5ced6cf47e2ecfc02cd09f2bba372486d1e301a4662601d27e1586f29d8241c5db63ec1eb69e78ef4b4ed36ac6823077fe0b03ce0b6c6ac5de859f8ce636e140588a5b672a8915e556d030e72463ede70f6a3940b2218d7b0d943490ff6bbc9a8f4f56f959efb11f0ece0f764403b95d97893ea6795f0d99a10291f5123837f227625a0275502599d895e18c98b6b2dac0cfdbe22291821f554b9874a85ea45dcbd601adafb3afbf74c47e075aad09c14567f51afa07bae5db340f1f7d37b89a68d566500ffdeeeb216ab0d8762412e6e73347c3d13b744676965d872749ad909577e6386abc06ee097251c61
q: cfeac6e0b5289d2696b763391afad0cddd6ac18df4bc15b2d1bb3c50af16a9af
r: 7529308e2753398381eb89214c4ebb45fa6c15141d5d427dfa4eb8f63d2fda67
s: c775c99af7c0217ffde06b5bbb2d2fea9a4743b636f72419c1c423f15f21df96
x: c6cdedbd3d6fb9e961ac2196de846a9aa619ca2eb69273ca7939466ff0bb1790
y: 4f6819faac96f054bdbcf6c9b042cfc87a1afdf1100a841c10e5607c90cf14fa172ca007f1df7342049ee27beec27bb80382902080bac15862ffe517e3e08f121d9c0e4366703d4be8822f9052331bddd265a4c45533982e45caff3a77b4aaa339f400648cbf5aabd46f9bc20f0c96d5f74ace61834da4fcda5ce3966324017a1064e6007726fdff6edfafd3e45c252b6852176e83252d89c8ef381fc1842d22884a52dec1a13029f9ed903c293fab5510a949acb39b51a5b80cdd45300000071936fb5c4988a6b9660314512e5aa96aea31699ad38a2a16a861c17ede3ac55edff5ae2c7a03005eab30340ed8d1a731005c268d74841c2d479eced6f17e5a15
g: 7c319f8ebfcead26f4731249bb341713d9ee052cdea7d3fc778b6775c529fbe3fc88ce0100fb5f1ac2e276f6042a0c316074888de69c0268d6f58567ca648b74e7bef708e526feaad05ab1cdf8a51570faf2acfd8a6b9b600002c586d906c353b609e2d71e0d2c99c35644f353292f0112e2fa70477a70a01a29ea04538426389bc70921f752a728f8ca3b26ff7f6b71f0473de8f0b235bf2b25ad795ebae5506a4ba9b954a507a9540d7b9df31bfba004f19884693cda6323daaf8f067e8f4bd119e63e84f61a6bc10842dbac9cbb8f947801b18d0c182ac59bf39f9cc1525f4a4a0479eb00a78686fd4f0865e130fb71dd8b28e2921ff79517a85902f3872d
h: 100
m: 392514fc513d86ce4bd78e8b1e02239bc7534632340c0275feeb302e889951687c530fbfaed16c0895656ae1e89d60c8c94d9a1d3f29fc1196d232202390c7d4853720716fc41f24db90d9a7d65b4680a1f99b475238c4163e4f1089aa534ed781f857f001ae84483611c5ad7768212d1d99082c3623acbb76aa14e5e76e0af14ecbd405619a561d6721c0a4d15ca1fcbd8d1a08386e5f50b41f4a581e0084b3b3f01e86
p: 96c488686f2d4bfb2ef950454506abab4af52fbcabebe24932f84464468cda68888357cd7729e4de1cbebaafadd44ce7031a4083140aa612b2c98f54925a8ae0f7810c775fe2793bd765072aaebab567a5df5f67e61d89c2c0903576c004f63f4d0839fb0eed60fcadea7cbb3fea4a1620d37fee91978da273c95c1751db58abc9b1c45dd35d42f06ae80f86de5a440dc3087bad45f4c20f43a042b6aeaabb59b9a1bcb71c4a12d1362f08068244837e55598e441210683b006bc442c07c3de55effb52679a1dbf43207dd0c8239044ff12927ba396f1faa04496801f1771dd847822a6b43ac5233051f24e7eab91a0c187dc9e9801c3d1278daac1af0d14201
q: dd7f66db32859ed42f75fe6ac4018d576ecbaadb167b7af4b54e183d9d5f5865
r: 40bacc07a1955eb9662072ae51e59651d51b9830246271a3493060c216134d85
s: 62321dd2cc990b7c988547e0b7424a21e9ee8fdf4b195934bceb683a39cf5446
x: 28d8835f9e193b58072ae3c1622bd01febdeaffe8642e72710b6d67711b82873
y: 92208ab5afc4d1954a14944b33b0fd56461ed957e29fa356fe81307c452105ca32381ef4bc3419b46ec14361e074e557ec0fdc7759e66798b0b3ec3ae51418ff27014cb67ac96444cc9266078b281136c0e5e144c0f3ce51fb5499590a02d785fe9b49782606c9b0defedc1d7f64085f105d36ee578cd1e6f8297512830af6025a48f1921a8702cc021786822cf661cded5abae9367478a854bcdd812a45acc42f357ff52c47c45f7626ce91eae66fb4f9efda53862fbc0d77c8ce468e56298f2c8660868151c3509e58a890b26a39b76cce20087a7252bb3c01ded879169af8c856d34aaa32b22fe45a2d2241c9b4fe5a0a8b29bd38f320c68a0081273b564b
g: 668b2d355703381c590ad322d1a950b4e242a946841b0cadf66f12d6396fd6b58be23829359acdc4c4bbf54a04ff4283f2788406df612eb9ad1ae02eececb23e4378756fdcece9ac7acd31802deda157ba69c8d649f13891b0ea9c6ef62e137298a872b3648f8f47850dca2120c916320935c27a0af2faf7ab526fd654833202cb7a7f2c0fb1fb9bda0a15823037770706a7632ba55a7c45160cbad8e6eee5fca7b873a63c3bcee038225592f59417c8cf5c71188bc430fad4eabdc13d64a67605468500816bc84e2f820ca915918bbd64c9d68df25f8ebe8bfdaf2938c02b632ca73e2ad9d2c518ac55c9f180e51a7eef84eedc99b76efdc42ba7fa405822e7
h: 200
m: 7bab985f87aa73cc43f2ef2283bbeae11be1ec8c2420a5d5b7a15ef8
p: d6dc85ac6bd5934ed1f18aae3efc2c4d83a03e76107b32a30b620449105eff0b7d23d147cf55bc57f7dc947a4524a5d8fa24c63f3bb630e9f83b4d221e2f56a9d7525f58ed8214f3ead6504a4514b1d82cfa3e7d7e44e78ab14f880a558909a9a3acb31b1813617e53c4a013c1a7a303193fff2b23beb3e52c0408d668c99fe5154f0d0f86028a34f4cdd5b1c3f00ac082031560a007cd0123847e139e3af4ac3103d51e76ce74fce22c6f69f9a271b253bfb074717ba617f63b03b7afc669fabce6a48947cb63bea9a9b890852d451cd92c1ddd603d4038ec29ae7ba875f013b6b58db60f26bb2954379732fc18798db49420ac985fff6f67312241979f5d3b
q: c5785bf9837bed46ab904237ade7ffbd072fff7d3808bb64740fbe5571702387
r: 637b532d438142623060c7cc96579cdf05de9c87bc1808fa3adf704e3939d0b7
s: 8eac4d64d71ba1884b380018d3f52592d874e71ec4c997de9a4d968c1e1e4f54
x: 923d23d22831679192dfdd0e3479381fe5ba2caa9d588024920ae7c4a65d8ecc
y: 3ac9e2a9614232f366fd62195d367d40ca1344a48971b538bbf4198c5b9f81024399fe6838189b8a3fb29e94a3fde501fbd0114cf8efac231c8101c59b770d1950371b16a69692b112a0f9358dbf9b1a7e5ac9bbf714218f495c74255b47ca4944c8daaaedfe1efc6b68a2dfbab94ce76d382a5f7139df50fa515f0cf83cdaf42f6ca30d5ab6768fe3c1fc60ffd2aa03b57e05cf20914da8a8596fb0efbef501579f36c25986de586c217350d01b14a062c40bbf42315b8c3f5e0ebfe162dd60c74ef51ff23e6b516aa2293c560b7795503d4bacf01c96cc119fa11f1f712bd725a73771e888bbe4af43dd545b99b23ca989ec190b587982c5bfffc3b7959d2a
g: a57923d048b0fc31cfc6cc9497b6a76886dc7f318ef363186dc17aa586011ad8c277b85b453e350d0709eab7e0b64e3fdcd84c0c53ea26a0a2a800a2faf57ec843e9536e0a0554e50d462c4097f4c0f2659cd8edbcb77928d78422dcc602c2c53b351f275f04e328b8775e36409e15be3fa7c067335d66de63b8d06e2329648b1c21bf22778a30baabacc333f75069f8e7a61939ec5007ed614581ff290ca2c7460c83805b6bd17ddb4e281233ca39baedb07b9c85bc72e0d262ef471d27000a0b73f24409af8a7fcc06b2dacb7053b1c6b2c7a6f123c191f3bab8ac9aa3b6e4615fb495744c90cb748e9610e7b734a397e825cdb8905d831d7358561701a545
h: 100
m: 1dc6d51b7c7212f67783cc38a6cbb6d38aea43ffab9950e0a93c
p: fd76fa23c6b7ef204570f852dffeb65d281f721758715e3c21b2874eb0931b85043923e5c8b218fab0d243494ded663438c3c43593c98f7b73cde71e717b6051ba3e621c7a980b99fd22603f785bffe6ce60a224a77dd824afc9840897204666fac84adaf72f097a44cc88c7e829571ddb8d4801cddd690f2ef1b7aecfcb68eed00bfc356a2cf2d77878d9ac1bc128a4aae976edd6ef3bf571c54a4703d64e9051e46a03d53854ac526adfad8e22085534c19f4b8799e901eb553f059ad293b58b3eee61016c3758b45864534eaa831f859d65e05604d6652a26337f4e9acae93f54d80309e81f511beda531b432bfa3a0e3c91978f49f38c9992647521fbd3f
q: dfd1e323f80e205c75cc95c9cd1238ad2550aa4cb799607ffd87a3730a9f6d5d
r: 539a84c54c5cb91f1c1dbf819e54eefe3b1c9717745e36a074f1d7ffd53d82b3
s: 45fa49c386227d1aa799f3b16006061691a8df0064fa5049b5eebf95e0fbbbd9
x: 169e8c6d70e28dd8f4af3c079fb247844abeab2e66c92e05bb03b02765591d6b
y: dbdf192cccb087d53a15840dd941bc8921a7b070a118ceb2232e21ab4318fe95a2be813ef961af62bf1fc7b3598b3f2be00aa246b66f195f049fe9df3005934b417d003f0090778ba7b20f0cc5bc18172af14f99d728b3e872717a1b68e96754d9f3138b3724a000629ec5036637baa4c36568ccb5d70bcd50b12516958d59e2cfa3dc67bb97dd959a1c73b8aa890f7caa72c4171c7d1c5ae130b11ec8d161441fe6f8cdd77c323501eacbe53d49d72435bf251c0cb73f83da40c2967d50bf6a610a370c1e7a7a442f47ad793f4d11acb0b5e7dcb6b5487d8e5a037987708de9c1501febf58d2df359469c06207efb573ecb9c44a57db6d227c5dadd32af720f
g: 43e3bef3a9363273d680b3e77003e3660065b494eae200eae97b547034e4cbc8bc257ee56b459f0981b6bd007894ef5c482af59647db2c2ac58a61dfd478f3a62d3d3b23ef021c5c4c778ba9ce276738e1e790463bbdac810445f7d9b2640a26a40d01504f007b7a63f5a004f3735f7018a3cd2d96c30b33afcb6ac904d81075b9e17f766e3c623247c92f67c8526ed933336a204ae8a4ff9fd9bcb4b4cf7851e8c13125561397b99f50694077663191be102ea36b0e1943b81e1757d96de9ce265995bc6e0d996e93e19437e9b70a927f4144c55aea4f297a102852f1ddfcc7a9d7ea0b6e30f970ad7cdfa1e5ad9f520a8600ff1ede1c6c50eec4764b51b273
h: 180
m: 5b303b1a4827fd149090ecd90bb430c81825f9b5caee42b6fbd4a8496084bb02d7e64cb60b261c52e23da6eb85f2460054683cc1d1477cf6d44876bbd45d1b0a516a9b2243db511175e7ec73cc8efd468ccddfbf639149580d69534e6ab9ef687ba9252955ebf7d4a94b99602f2690f617cb41da4f4e1b19ba20796d3129af7f89f03b905f5fd16247f2b8c9eba9ba0206ccda4e964d
p: e3e3fe78991ce2c2246e556bc8e7f3b2136e837a1f5380b6e922b27475d8afcd6cc06c3b0ce237aa648432fbc2793dd70d8e68c0f945b6da065f8b55e3ef0aa0d0d3c2e17aa25f4136b31eaaea797ef84074247362c803af9bf1523b3fcaccf0121eac658056bf258362d56df0bf4a1f6713e8b0d4000ba47aacba7001e534997d942a684c533f19e3d8c0389e46d429f24f5d2873fb8760d4f3e217a452cab119cf104eb60a9c0029a017d15e0187c1b4e3c7c9d7afd919f596a4f7fd4dcffd23d8f965790a64e5487708f82bc39ec6bc565bc46ebda44ced4ea83e5940e8564f1d730b6458e7f03406f12ea79544a87ce53a6568d0fc87ae715b079c1871e1
q: ea5381f73a0c9c51c816528cfb66ebeba5335de4c0b5f60855a4c9b8dda6ca85
r: 8d1ecf1cee0c9b84ae7e7245ce5b82d4ede8e64fe88b073f1ed46680965e3a05
s: d7aa619d74a0a7096d24c57df2f65efa982891c990c6cf2e562ae573482b645d
x: bf631840f56d3d5395e2ac67b3406cd78a974d9e18b47c423024063a54d60e83
y: 62f0d2f831aa5392e483c9408497c42fe0195cf7a86fe516e7cf3cc87db29728ff13841c4668a8de12e22b17cde7e33fbbcd686c731f2b638158760c10e4c65d1b16cfc57c51e8aafe55c049451fc2752396a1dc075df109c08edaf240228df2183bf2e44456e2409fff46442983babfabe6868cb41c221de6a85d06f21391ad35a22ac0f60acc8156f6ed80a45e966d43708916da91a2ed393625510054386e1fd89e7a63e7aa33c5b0dc891c3d71c16d7d8c0610d511545a771fdface741fae8600a8e23c1c47b71e7c9f19aa5e18634ce1f291e60cfedd201295b6d838cc3b984dde522eb17bd9cb5ba3259136c0f2decba2e3b00bb6be4da02f2207ebfc3
g: 81adf88e3e2c97638faf6d46a80f94d1253e61a57c663839bec900d524c1bdb72be47abbffb59e6483301f0aa86891da547709f2075eca6a93ba8850a5914884b40e2b9892dfb0114813b8c1f69d6fbf7e2964036d27f407bdf7f5c48591cbe50a807590458cdec17f0f203670493cd1d7657db94234bca7f4622fa27942b56e8231b11897412a621edcc6b0b918e357cef742755e1ad0e6ead957b83e8681a2647382cb00d8fa27d1b1d6c0fbfb4a1d1e75266b13fcc470a47f8bc482289a29eb414d8e0ff8c81a81fd289decef24e521ef38acceccd6648e9f81ffb9ed98f68817dfd3084340a263c5a6575f4511c29a6ef106844aaa66f1e5a00f2fbf01dc
h: e0
m: e4933f55b9b675fcb83c3d80fad5e135a8045913d207dcb6ce75765b6e61
p: 93ba1da95cd47488a18c35d86f50de5f7725a5376b67528610da830b98c382618029f80cd4ba90e1cef1e425c64165fbe70fe25ad8e89868f981ebe912d07c153df8566d09732d089f99cdd9ef36c49f76711c474d7b37902415fac96c3c252b05b26f9acc86997a1a537fa9594b943a8531fd285eddff606b7cb27f5a1591a0419d949b7dad706e7fe86d3b1a7714c05359bddb72c64de796ba787cbd9b5fc4ab93966adb1d7180ff19c7765a6dc33dde3c08c277d762803fbec9edfb3bf8a7e6d725056761237a6ccd2d6e24665d69580ed6ecef8a8f6ee78379916e18b6870421c58081ab88af06786f9a483369269b7c6b16448c5fbb24e2bc1db23fe871
q: c97351037de0c970da4fa95e7e00db17d4a9a7dfa14e8b3ba096ca4d8a9544fb
r: 38328f38beb6e1117400b949cd16c91fec581ed2ce1d0a7b145bd87f718e55c0
s: 87880542ed63c171ba390ec715d37e19c54a3adb24bcb3ae42b3c092b0db91f0
x: 38e85de3999b97019bbf7ebc38f37fc95031417a1b305dbe47d4fb74dbb421d2
y: 568b63f09f5e296797c7a36d498b4efd6eebca68a3238b6df74a82e857abd7070cf705e9bc63cafdf01f4bff56f55914b682931aed92453b56d2ee51a95f6c36fe90a22ad3716d5f6781176ef8db9e54a5cd62590c2fe0744199d2770b134135399af6454afe5633cee6c3a10304f7f2a89fbad708474c62d3e1fd019a0fe7c00a42fcc75fb1cb87c6e931223ecc105bf7a39bd97131b1b5172de62321757bf24717d52175e1842c795c8e82e83bc028f058ce69eab35a6c52f7b437dea8c2e5423355683c69281a302a3c7fe2c79e0baee4d900453a04b1789875dc3dfc6915b1a51ee9e27ad5fef5a9ba73668b3c8022d01226fcde29d3eff02b8dea63172
g: ccbf1c7ecec486a9b742fc89205f684063ad0402457cd3b2da6dff0107cb0bf65ae37f1ca3b701de1413a354658be80dfdc4f23a96a7d612f0560c028a870ae2e6a9169088c395e6fd6507ba60b91f1e7652bf1a1db4578c439f317477e4de00777206a6182d66e28a673218822e2ef2a31e2784f9d83dd4e1dfc745287b4dfe7e1e236001ea82d616f67dcd4bbffc12778b663e745a385d42ea3935d42e4d3fb23f3fc5dd82c2f72759c9f304e6b9c991c19a475e7b8403f27f9aab87d62e0038bfdcd4edd3ae5bbc8d2bdf53fe50f3704bfe37af89e6178cbd822e131bd400cca43af4296401de9c31eb448ad2d149e2cc2952ca8e2be01e05e6468b61b29c
h: e0
m: 1ee90766d5d4bb417e0d0da721f8b8244ab8d953af11d2e49dd5f6ff6b0fce24683624d8f02804d5418436d67d
p: f99b520623b031b47705f0e35a462253d991c7dddee70b481a78242a06e5ed9063a90d91e4da80eabdc649c080f50a318f4c64a52ec964aaf791cdc763ca9d399b504783490d335475ad8f93035b6dcf3f9c2dc61839cdceb96b4215ba70621506ab3df9e217a27a790eed5dc8a56e66662bed30f035482fde7f7a491e4832da173a82dc06d42cf669c0b56603c3b618423f058c6bb3af28ea096fdf1c2063bcd93c2221c163dce85d8d7e1fc07c7e4893213f5105e8c82432afe71202710991bfecb9d1a94f679d8298b8b0d72e0a5fafca9da0a319bc849a550fd94fd66cf097029ce945232946761f3193f55089974ee6c0f246706c7d33333f4e3e94ffe9
q: ec1ea4367e635f9bc7771b596e0915b14a4eb6fbe11f51925dedc33e1946abed
r: 44c3edb144027f081106feecd6aa221104289c1befa714720746e286fc5e0812
s: 2882edb4fd571c88d16011ad92117edda814779110a761eafa2227d0c7695bd4
x: d2ef5fe4abf800d6dd9ce2050c14651b9748e49ca5cb79361b936be9a181c27f
y: bd79d75c6b6e2f84a0c5fe021ab7f8914fa8e2e64c2018f622ddc44b47a4840673016830f6cf12a9c0fc81a76d1fca5b46f799f74ff950e17684331a88ada8e4d9d9a886112b4951b80575ac8ab63afdea28239e59f3560b2f981c0b9fdf8949452ecd9a2b5cddd7de51002a183609da4a1983e85a06df8d647e02edf0af114b1a5297de207ac7f603e6c087887c2154bf539f2961b21c9fcdf2e558367c2e5cd6ddf980cd96a6fd6383e793c57c6277fdc317a4166993e534c5e510d74bd6a9995fd59be63ab21ffaa31fa67b575a6d954123d549dca60bd84bf5866a3118060c9a4d16bc89c137d3392bde8afd49369e608e1cfc9524c1f8b07e467f466953
g: 48351df7fdf9f3978da9ecacf4daeb1c73ead457d9555e6f2ee402b53fdc4b3172e9721c31065f6860fc221301665c78800370c408be1a353fc89a91f72ceb466df8d289922b13e8a8ceff054d5e1e379406f3b10ffeb41906f10a61ec87efccbcdcc6ed2a725f3c15f9e6a9811311af65a30baab6999fa84eddc56c67c0d42145f17e27f867d4db2a7d90ddf15efe328aaf77fe3b8173a97653dc567ae5a773c2e7ed80d63c05d553d09b7d4e6f0b67c726744de469d72be0c92c2f782c55c3cba5e9538ba261cb4fa45c537ad17c10ad214723e4370b46b141bd2b8f617592274eb0208b7134ee6f46bfaaf077436e39d9c7d522fd1e2f68179c3362f0039a
h: 180
m: 432d42b307829d3ae768e91e63e0bb09ac801482df5185348ce7e846cc99787f20313629ec2a4ad242fcc1f2f147bd056a259e92b18edd48de9ce1a2bb703b29c921085306d580c8b1b5fdf22539eb5866ccaf4910d525f5de4b1f1bb87e0915235ba41e07870660aaa5cced774fb82f301ab503c1eeea130f
p: bb02edaaf53bab2a89ea97e20f971702fe4f2c8782ba67ae1d3809ab1f4a2df3b53104ac3740581cdb4abe32f6248274c3adfa6988d7cb51adac240d269a0f66189ab9922409233ab7b9c9fddc9b20476d59890e7f23cef3163d2f9745b4ba74e2b348b4cda62e35e16288870fb66c4261ada907096a89c9b66e949245797d2ebf302c3c4471563c28c8ee330f730c527d0ed148e88f4f210d0cc489ee4d84977c9c92b832e8fda76540a62b0ac611b5379e2e2ea446fe2295264f988e1f9ff0dfafa3825e4acfac3dc09983777e38e79ed579a0e0c22c83a6d884caab328d08873882d0ea1ba7157728000be7a5677fc7eba4fa174fb765f1da6e89b327a823
q: e0f83307910923c476232ea2f915a421f8cf798b48d5b39a95e47aa9d8888811
r: d95e68afe6dd506e9ecc3629476f75e05ee933310a4ae4c5933ed999d3978cf5
s: 6e213647f17b0a9eabb40116dd89926ef7fe7c4f3a724ccbcf9e365654d3a065
x: cd1afc9e55977be18a95504cbe42e4cce7166479a5aa1581686316b3c046bc3
y: 5595f77de86023675269a4f8c77b1d77d2452bc3a1dbff78b8867f5eac782b96c76376ac43691d7e01ee51e4bc181b4016bbee4d44a8a965ce09f2aa75e134ac93ea8ee3ef840aff42226274988b1e157b6c73adbec0fffa818ae9eb623ff453a4f78fb4d412fba4e4751d95cc3eced418c3c68c81b46e9185cb8b6e35a9f052840a18c7e858e35c260cb19b582c2e39075df1603cb773d685fba9c4e23fedc712e858975de18bafe80170abda2315f682f32733bfaa3b23df752117c84afa265a9f22cad5a18ec9a4ed426cc3813187664b3588183c0c0584f0593b17a3108746b88407ad6e29ae8cf75509e2719a61e235f203f7e1db0556b7ced873f40565
g: 5325145ccd3397a6ad5c7dc7d13716cd0fcf3647d6a8e2e6eea6f8ec3071d326f09d1dea10c3ec6deb392e293550850e1bd8061759a52f01d84675c61ccf847d9ebfcd740f9b15264c04db488c6d115995bedd96c647ecc8789a89dbfa51c44f23a2bafe7c61b6f97a8f35a5653900168d86d070ab2f7982d021c1f7623516d940f3948774fcac16682d3624ef353997b3c69d8763f3d142c4ff0e6d734402bcd6823daf54684834947d8b9258a5d7aed8f17004b1091d9910252ebb2dc10c95d00b5dfe57e861d409d0709138aed4b505aa5f6532d99f5d8b687ae229e0794066bef5b9e7f1548a9290e2e36190595ddfa2062ef9c70ca77d6705781244e6bd
h: 180
m: 57f0009f31b02b2f39dc808905f901ae4dd6cb966f1ec8020da03b4e038366ad1e924f6b95b693a032f2bfc694317c773ef3cc67a0ae1628a43132b2b98889ee2f60ab4984d3df13ac78235a054913ecd275a59530298f704a4d2d78cd819c241a5b715842f997f7
p: 9065cadabc0b92fc25d2539558a79e14c31478149b317756389c929ee4d4c0e286cb9b8670e26fd8be2e59a7aa5d4b99905225477c6fb689b10bf2414da2d15ca8284e9cb2330487f82dd3336b5e226464c0c4494a2b60c4940974959bb7103f2ada7eb1e1e6a01a44e3ddad1015d8729857439017e1071a09078f7c42ae6bc7883afec3e48cebc30a96c8ccfbaf945662d68eb3b371b7ae010b20ca5e89f8aba186dc530baa1f5d478d75cc26df6a728ec9d48d177978eec9878b3209ce85dbb61d51b6462c99c3072c70ddb25d4a7d8b54c32f9dd4a29efbcbeac4ad9f702371cd3fc397a487b6776d1716567eeeffe04622ebfd556e3b36aa49ce030fea0b
q: f7c79f3699bbcd143187f294e146c2f431221776c972005ba33c6aaa02685967
r: b5e11ed1ca2553fe8cd3919eb75c45a114f565dc5cbcc180aff64e5436de5f1d
s: bb73508ab4c42bd4f0b0a3dc2304da2812147290d18627cd2db46ccd3756473b
x: aee54b7b861818f42005590e0175c7725b4d27cc6b7c6cd2a16e6aa825e66d31
y: 13547903b97d2ee62dc8bb13f6cfe1a4e6903b2677580ae8130703100d3541867575b366338139b304f624cc7989e36a56bcd8d47af002f8f3f6cd79597918f8fb202ee6b8a54557a0cb609af53a52254efcae11c3c528292c0ab4dc983fd88243cbafe92411ec410d24cf1a2a1232f875772d609a3fb4a6bc4cb7ad0f26cacb90bbbe3c3da0560c21c9e2024adc63d1cd15415edfb997d25fc5239a1c84fdfd970e40aa590241fbc50a0d9f5fbbecf32cee79672c23d9d9ccd6d36a67297b694f6e90d9557c82a25f06496806571bcf97ee32870e97675cd7419c2600f227af423a0cf8c44600fc0d0839cbfb6e87abb6b168617af5e1ffae0e7141fcefa81a
g: 1c6ab6a5ea4120f9a1b50e5ce1e92c2cf564eb8b7210a8d3f61fa1946b152327a37a3a5af982911704972f0af2d04ec1efe4bb799e1fbcb1464d60a8cac6d4b634453c818adc464f4b1d0b076b7bfa2e99c6cdb80332e03325125610330693406d58fbcdf46c9f31f161814059e2a7fe3891b7f5f7792327ad4e64865db8a941f0f3a5feebc857151df72aa9eb8979c2aeb37af853640df5f50b0b1221f51a6662481e5c654e54450af451408d5cbf739b6b616ed0dcfbd08e7d2c472c3cad98a328ccad65773a6477b1169dd0bfc03d4a5f152f0c0bd99d2f262dfbde62028d5f340425be6327ca0c303b93b19a274223b9ec630a2788f95e01fb9de882ddf0
h: 100
m: 90040c27654dfabee4648fb0fda74ddf3e0c45e93f5ec80ee5322cabe34c9af4fafa64fc25cabee79ebc2f08c17deac7344ef2a555c095bf9dbcb4bd1906a61cbb1a8025cd905aa507811d1c6328d06518480af605995393f58cb40687a2b76508fd8f5f8f6b4f633b217cb541f7858d91ea15ecd3848c46259af811580c995d95520af50848f6f2af1fbcf1e9c7672a5754e3dfd82a719f4f64683d40ff
p: 8393ddcc5144683aeea20e34f385c91c2b4046bdf95436afe2db1938100bc0b5ecea54bf8299c76eb26bd3dc77c20b216f058ffb597ee88f97aaf439a7309e5df72a012fe3b47d6309bd409905fb2a8b21567252b6148f246857829e904fb7ff74ee466c5d860284aacd0d1350dd78d6eddd0ec23f5e90fb90b296dee94e9735e0ca3fe9b32124062e495ff6c6e9c2b3dbb3e770e3eb752e76d935d5c88a93b28caa9be40832ee9e126077fa1b416d9fae155bc80e85836825e280722c93b8b545a9506b35aae580b57370ddcc9f2dcd6de99098ca1c26ee066bcee8d9be06b2bd8ef89cd0e987ccc334311749cabeab4cf100e71f8e30f26b189cafcf4c2549
q: de3b45a2eaf3cf6f795be99afd0c5542889920dd4d9ba3077c6e4158a83c76cd
r: 8c9913b740725d9e9456c06dbbdf61952ee4bab60611d8f26df5020c503416e7
s: bd4a5b5c1fc798b02719fe7c60359392ea964252919ed7b41268581601d27b65
x: b55628105401645cd7b4f23e01404fa50bf21cae9ebf4d2229bfa0587a5c69f9
y: 5bbfddd0682d02a5dc85520ed73f5dab6d7309a7266f346e6c71b51b95c95e3e00bf76d54bda998a0a1ab27cf6d1452b0bb2cc150c1d5cf7ffe4b2f6ebc3b70b2923b2895a6df5334d2936c505b71d97229d8358a071cc3dc996eef4a3796da4e33835df333477f948454f97235eb27ca987eb6333f8a1ab6fabe4e0301c159d3158490609f97be276657361400e9cf0d8cf0bd7ba20a43dc9f361c4b8ad28d9701ad11f1adad49fee84b3483105bcd4e1291d2b63b43ea15e635efa60729aec4c75c48fb99303b5dd724de8bc58d705ea9aa74918aeb064830071ede20728ff6707c3f7712a128c7d1afb8f97a39c4dbec05bac437a56bf010497861c165ab1
g: 1848533eded65a9cb9c5412c676ed122a594214e629f988e395fe76bae037eb4833c682bfa5281cd43eea170759aa77c9f3314877e9fe9028458a7eacaf8819c75c80af6b7d4617b77f6cdaa552bfb72b1d2a787269a09af3bdf86139a5fbe134f4bee79a28b7cdcae9a6433f424c2bbac818b823b800f7d60984101f6cf3c9acbf10acf9ed3ef9b9144adade816b7f530e18ebf3ebc732238da202d2c67a45af0b43efc05ec56b6c329358dce754cea530956be1d8d3eef7332b0f5fc5c357392d0c6566cc7c9cd291031b4a39086206cae3dde9ecd688bebe64f4876ec166c8f9b416c674f778c742c2986deb73e2088642805c90dd875488d3b2076fd7a13
h: e0
m: 754ef844378a6eaf0012c21e56da93472016e18415a1b4f3be52d8f753acc761fa62ec9b55b1546b4a119a7a7d7832abee73b43e38849d6b4e80dddd0763e77517777d0ecc6738c4cc5642bd222a94f6d037cf6a1419b6f09219d0f60a2ff2058214eda706ee81acca9bfa35e4cd77b9e916e517527a76fb7b902a74d4c0269bf7f70495d18870aa0cfc5e8d852a2918391363993732344b1cf4d0019eed6105ce40f520e2b6241f7ed16ec41b26e1e4bade975d88af20842593faa1fe5bc43226cc596cd519589edcaf0ae09cbf75867e7ecdb393949fd07589cabc12e4aa412868a0808deea6f6fe822031c8b048c46586f90e1d40fb5baf9210
p: caab54f6aaed4284181218e37ecfc6281bc96b0536abe85fcb87d59fe64dbf0cc9a14ddc11662ea21333af005d5b18cd34390eb4120b1b768c13ebf0e74b1bdca75c98566a397a5ea0dad6aa70a04496ee96bff77b5230a6abb407bee8b5bb4c40624d7fce6bfe6d227a075d6915207a769be8c70da9d474552e1725201e96353d3b800716cc8723ba834b5edfc29b7df32f2e0f9cab49d40147b29ac2dc7ef398f300eaa1a81725fff9941b15dd6cc46e3888fdd6c8f2ce5076cf0cf7e93a1ad0390344df8fea5a2b985da2241dd2e915cffe90e16328217aaad55eaa254abe92684c5074ed349a4c8c3f834da27b69d3e5ba0211b9813e8999d9f8ab3e9ca5
q: 9ea50697e3c0165f7828a7fa5983183df26f6d30091bd2fbd344e2fca1348447
r: 803ee01a33ea6d32632bb9e4c73e4ee61e32fd041f4041d2f5002aea64906e48
s: 8b88c04717fcd93c02de19aa6ad993c95c56d9b11076b7834d578a266a45220
x: 356831231ee1b8e3e740e8d4666cd873d2123f8603135fc48c093a06491f6258
y: 41967640b7a72cc0bc2e0a51f09cf068afd9891f0bd7a62c5dec07b2a5f025ffbb09151a6f3ad86bf5f869aaee08f478085cada07870726992ce168720cb26207a204f9fd701258bf51081d0827b77e6e857c6a40a467bb9ed2f3bc83d8941ffdcd9b1996d0452383e10d181dd263edc3042cca53b39f1ce1a2ab2d9dcba5b9b0dcef9bb07f28559326d1b41b037e095aab087f89c2c6f693194ad3a8584b210ba3d6c42182e545bc58404cc3f9d9e211b97437a44db0acfbd741d3ea014b65e742c442dd5c7e43c139bcaa561a6d93ffacaa9818697430f3153191da6b0c93a94363aa92543222e735781686efd0f866677c71f2d2ef11d997ac80cd2945eaa
g: 456f174bf581eb5aa803bf41d7c2a4b4f73a73b990535a3c44729d541a993ed3d777d42769a2ddd0555de29e3f392c3486e2454aceddf7bda99b095d982c3b1f8c2851b8da98112e0f262870c07fbdad69b005a98a85172b51175f27c063998bf9899a65949478cec6baeb32e2b663044bf966be9f6e1fc5912867f20c89c97da296ac045c3c0ca5520c86181a881b31cbfdd4653af43feab8be1fabaa7165529c61b902ba15c900dbf9c77b21d3aa16786a95a9a060b80dd4c4c2ae9fbfc1c3dfd261c572322cf2d506e4d3192a82ca7c54304f41e0ee7e99ba5a6ef2c3a2aa236af65f9a2763aa14d1e92e55d84df3db8ae872d90647b248fc8c235734a157
h: 100
m: a795800548bdcccc9929189cf9f449f84c9fdc2d3e320b6556070d8d98b209b78a1cbd7401a9392c55ef01470d5477b17ae10ec6531dc88f739fc5e5cb37fc3586f895bc27845cd24323cc42d2fb3107
p: 8d4d239e83f4c07561a3384927c0e6a2a708d23b581567d8d2b238b48c8dab7d86e8ebbafffd1f383b20348c974574c89eaf2a16688b0321eb1fd44835375047b4e7d1c4303d1cfe12e260fb8e61153e5cad793faa7890d10fca1ad28da4daf76677888d1f4018921d46c4b63299a178229fb2c68a3ec42bb73f5ffcb826f502768de68c8b740da5a9cb63b4e7760073407b036eeb07e561d4035e4a87d467fd7560c969e1ad659d311c474edd6d526755c7147e45a2213d0d78fdfbf3be48e8aa2a7fcf326d24fe7293467005b9eb34c58a9891224b060126e7bf29b08694f895bf90fbccb2fe1015d2d8546c703355b28c080b2e41f0795a6e7f10030db24d
q: a136471f4322665e90d9b67a5c7f9c3d1c16789ea5472c245d8b22eabe645d77
r: 9a0791d875c6d524b7495b3db7a076018014967470a64c1c6d54cc247b05298f
s: 2a5a22e5e30cb81516ef1d3a849791e64753696e81556e2b3d9a0a2af5fe4064
x: 89b3ace84682a71bbdd0e8c2df57d4833db6ad87c239da2ec8c920e09dfed5c5
y: 262d31682157ba1977e7b40860943a03bd34e30c972b12c193adac02064c16584b4974de432196972b2e5437a5a9e29986fa4121bc92d60e2116fbfd855011dc2dfb66f9f3146b1f853b34f79384d9df378f5b79820c4965b92c45484538ae0b50c73d02cce5024318abc6c27540c2850d27c06326f0186bc1a46992b2813d27d82c5ee8745fe957efc6a6e4b84fe9f7013faae634327dccfc792ea03ba546e44f2634b4c0cda9c3603db0e84ccf7a191b05ba579bb662bd98f55635e12d3fb5b4a83f219be3bb6f989e165ef91c15d5fb563fb670f758028c136bddec6a8a12ab794909b8cb4313808947947c2a26c69413d3a90c40b7c746cfbcfe499a7e49
g: ac2defcb4fee2c630cd5a3f23ba39e4ffd8202e2f9ad64e62b6cbc1711ca442b9365480de72983da1843d450decb83f2c8c83bb105311cd6a905b46339fb2c6691038963741f1f18ffcd253bcaf35eacd52e27d16783fb7743ee2c7679cfe9134c666b24f0251050c0a0db0d78007893c40ab6afe58eb6b16b38b03abf7df38e8a3f948a4dfcf8c5fef8a98eb6b8421c8594b72c24934bb86851bc46d38f5b8ed98454327621569298675afd7f75c92b62e2cafa3ac93051cfcbfcb20691026f3a731bab4ed261d3f1a7a83b77556bc2e297cbcae6cbb1488167edca9221f50d62320c681ae7542aaf44bdbc4351aae09889efe4ae3aabe252090ed92b0d410b
h: 180
m: ffb4b22245b0
p: f0327019093c33acd37718c7acc74d8fda79aaef08c0d70368405f4b0ed468aff9d08b0cfa24c6d74090e54d243d89e56edaeb34728fe8ef61c4f58a935cc70b468d9fa6121272389dd7afab64d53b8a3c06c632576dde2da93cbd496dfa4aea0e21180df056a4a48f49498f2826cfe11b6db29a2ca8d6966235202aff8803a85f766827572b296c2d1f4d61a230278cad46315a63061a97f10387a8f04ed49f2f051d5f5fd5d2c5bf4ea175b13c699de0fceb0be22d99a28bae583cd56317c4a68ce5c174ece77e07f6c5d8ee9558e233bf93bf835341e66f0f7d9205dfad9bf6bd4f200a64aad7d2f74acece12f3c14de6ec2dab43e28dd3550f60ebb84105
q: 8e54333a23335bb7cbbfd4f135a6b5fba5e399f08ac5811c4880185e56346c71
r: 8415df996090bd19708e0e3d65cc47883c9eb326c4b811c05c9badf74e211c4
s: 2575fba4d2f599d01b9117e1ed78152363ea8a332384d26e9a76fd281d931fbd
x: 4000168545efd4efdfbbabf7f610b4876e3bacd9d30acc0ce6167617af61efa6
y: b33b29f2f73f3a76fa1d3e825dee0b1d19255a7461d03b6899fa274fda205aa69c4460a4f8a52e34b9a6c2897ea04320fa2dc522aa58f82a8f9f5304ddfbdf5c65939f477776e0724eda0fa57aaf6eb670d0cfe12afe88ffbbb6aaeba4642d9213fd34c383d1f19d85b0095216b0bb7a79b0111248bb2ac9ccf3a893ae4ab1761a765dd96f8196fcb287abfc21f4125206871781351f52ddabbdc6b59cb8cbf8060c9e0c3162158c17db1643095fb80954673848d5cdb86b9d8eb948ae8b374d754c2764de4c5b9f661c8e838749c1c5bf32cc9425492ca7ee2a7e8f5781090200be139919722cc560cf56606d9c768002ecbd7c0f4b201d25bca9fb4e548377
g: 9a598a0a3c4dee259bb6e8292a7c751dc20caf8dc4f5461b8565c7520f3aa9152f6515756be980fd4949f47ac33c1f4cef115d6a10234f660cab7d8ecd22be02cad3fce2f7eace400357d10500a75238231aa573e66dc28e0538896c22ea35c5c4ecbf75c8f73592ba9f0f5405f3ed3df9f5c9e66043d9ebc49aea812bba086217bf33844e164e0b3582db92f253d904c867805fc916a6da2bd2ef1d85d7d040a6e5d1572a4dc62e60b65d954cc27b97e546af67a747cd465de00f6160f7469f3aab386bf015b74483e14b34d25bc628718cfc03fb8a146a437486f0941f070f9ecadf3fdabb86a7071706066735ce73652bd029f2d767a267e2f03827ecd24a
h: 180
m: 6a347aaa125c9797ba875d6fbaa87497c636d6224ae0bf1db7c6ad21604cf4cbf6e7672baf59c5d75236a677495bf447c3a184c646e37c0956c2b4341bffef51a800db2f7316e02f9135787cbf76620855
p: b4240e6680c00aa99b3e93b40931c516aff1b8c10ff8abdf820652ffaaefb3c2098060c65372a5c08ded509e7405e1e762ce633ab0a372775627a22512514f1f617a665e266196a21d1e6fbfeb5cd13caea325b930251ee95bf072fad364a4c29d2adf06f7bfbdb70708559df40118ed6d671b16de353a067d34075c3672f97aa7aaaf9962a4186eacb28cb7400bc3a6edbb050ce0a7a545201fbc2ec8aebae31bbbad276eb7aeacf3fff8004d252cf3073922239a38703b9871d83d1761b2015219dcd3d1c1619c5dfaa7383912a15bf5eea43e16165fff68fd4214461cf01b2e032b6bfb81d383148cb4534237f12b3e200939dc7888a59fd7221a877f515f
q: fc194bb7eb92ac7c8ed3a037bd4235f3b84cbe467c891308dc334a46dc390a79
r: 3b9161c216640f29617cec2de99cda72821f799d3ef214cf97b02b90e3ec6cc9
s: 50a2a4a267baf151fa2786d5d5cc29ec9fa0e3ebc644743ee690f518f6a12361
x: 556f999b8e92c2237a944686ddfe40173c9000ba00bb5dd8ec11ad34c2462d45
y: 6af6d0239be012aa6478f4e9aac1b8162a112c3e67c81f11b94429a548651444485aa108400eb55079f39e75ea15d730306feb6c190e6ab2cd5d69f481ccbfad5038d1a5438c0e34ca8a426b72d582296535b8c5926e365fa2022a41d998d97e1e3b56ed97596fd5cfeed259367b7b61f8d26dae461bc40fc8bc9b58690d28eca2a3053d7c541dfaf3004370119c176e50e59e13d47ae19b4d9221f568449713c985cb66b5fd951246f76dc3f3b35c00543986ab3167090286c5a1e0f1e77b10de6f501d401c531e3422c265cda5633e6f912d6b6f70e7e48395921beea595ca656affdbab7e24c1ddfb37f6415e521a8795588ca7c72b17c6558ac9201c5179

Some files were not shown because too many files have changed in this diff Show More