61 Commits

Author SHA1 Message Date
06400cc7a5 Do CI integration on stable and beta channels, allow nightly to fail. 2019-03-07 22:01:35 -07:00
3a6ae61707 Add cryptonum as a submodule. 2019-03-07 21:55:56 -07:00
5a69795fdf Limit long-running tests via #[ignore] instead of commenting them out. 2019-03-07 21:38:07 -07:00
40254014d3 Fix DSA test generation. 2019-03-07 16:26:46 -07:00
9d2e56ad06 Add code to run the DSA tests ... which still need fixin'. 2019-03-07 16:00:27 -07:00
95c3dc94df Possible fixes for the DSA test generation code. 2019-03-06 21:20:39 -07:00
cc83b239cc A start at DSA test case generation. 2019-03-05 21:47:48 -07:00
b3276ce2f6 Fix up the RSA decryption testing routines. 2019-03-05 21:35:31 -07:00
91d595ee4b Clean up old debugging infrastructure. 2019-03-05 16:12:25 -07:00
f1f39f8b5f Complete the change to a slightly better testing infrastructure. 2019-03-05 16:12:03 -07:00
038db66c2f Replace the old RSA testing infrastructure with some more integrated stuff. 2019-03-05 16:10:12 -07:00
bf13f4a1e6 Start generating RSA test cases as part of the normal infrastructure. 2019-03-01 20:44:33 -08:00
15ec3c5c9b Merge in a fairly consistent, probably working, super ugly branch. 2019-02-28 16:50:18 -08:00
8d8351e833 Preliminary x.509 support. This is some of the ugliest code I've ever written, but it works. Ish. 2019-02-18 10:54:34 -08:00
4559b80d2f Start tracking a bunch of debt I'm accumulating. 2019-02-11 13:20:36 -08:00
293a93c6d4 Support ECDSA key generation. 2019-02-11 13:19:51 -08:00
a3b0ef8d98 Generalize ECC public key support; still very slow. 2019-02-11 12:36:35 -08:00
9ce976bb6e [FIXED] Fairly ridiculous implementation of ECDSA verification 2019-02-11 12:10:59 -08:00
94defc4e77 [BROKEN] Start adding support for ECDSA public keys. 2019-02-10 17:47:36 -08:00
a426ca3901 Make ecdsa/private.rs a bit more pretty. 2019-02-10 17:47:11 -08:00
3716dba87c Add test cases for scaling and adding two points. 2019-02-10 17:46:19 -08:00
a390a7bb53 Start moving from from_bytes to from in the curve constants. 2019-02-04 19:28:17 -08:00
71cb38ca30 Comment out some very slow test cases. Probably need a better way to do this. 2019-02-04 19:27:58 -08:00
322701ad6c ECC Private key support. 2019-02-04 19:27:23 -08:00
8a771c05a4 Tweak some build flags. 2019-02-04 19:27:01 -08:00
a8174ac47e Fix a typo in the P521 base point. 2019-02-04 19:26:35 -08:00
00b944e30a Remove From<U512> requirement on the k-generator. 2019-02-04 19:25:57 -08:00
63bfda9073 Remove extraneous file. 2019-02-04 19:25:28 -08:00
4529562cb8 This appears to work ... maybe. slowly. 2019-01-27 19:02:52 -08:00
4af5446e80 Start work on ECDSA signing. 2019-01-18 21:55:52 -08:00
04b4c79f7a Add size querying for ECDSA curves. 2019-01-18 21:55:42 -08:00
89deea0337 Cleanups for the RFC 6979 code, plus support for running the test cases. 2019-01-18 21:55:08 -08:00
f60a492a0b Updated cabal file and generated test cases. 2019-01-18 21:54:18 -08:00
c5e9d4be25 Add test generation for RFC 6979 k value generation. 2019-01-18 21:53:52 -08:00
f4e47154c2 Add ECDSA scaling and signing tests. 2019-01-18 21:53:15 -08:00
cdcfd9a3a3 Basic point math, with tests. Distressingly slow. 2019-01-08 09:45:02 -08:00
f3494d8524 Handle negative scaling factors. 2018-12-30 21:16:16 -08:00
eb82edea7e Start with Elliptic Curve point math. Slow, but it works. 2018-12-30 21:00:10 -08:00
62cb276888 DSA support! 2018-12-08 10:59:14 -06:00
160618cdd7 Update some libraries, and now RSA works again! 2018-11-21 22:27:59 -08:00
9d87916cc5 Rewrite against a newer cryptonum. 2018-11-14 20:51:14 -05:00
ef54ed4cda Remove the cryptonum stuff; it's been moved to a different crate. 2018-10-27 15:15:23 -07:00
43b73139cd Checkpoint; not sure where this code is, but I'm rethinking. 2018-10-27 15:11:45 -07:00
b30fe6a75f Modular exponentiation with Barrett reduction. Seems slow. :( 2018-06-18 12:04:11 -07:00
011ebc0c99 Extend modular addition to Barrett constants. 2018-06-18 08:42:01 -07:00
a6def22bd1 Barrett reduction! 2018-06-17 11:01:22 -07:00
c49cd29c43 Barrett reduction 2018-06-10 21:09:53 -07:00
65d7b7e93f Modular exponentiation! 2018-06-10 21:09:35 -07:00
b93286fe60 Make modular addition take a trait argument like the others. 2018-06-10 10:36:49 -07:00
5a5b48569b Switch to the same test naming scheme across modules. 2018-06-10 10:36:34 -07:00
b5afa8fdf9 Modular squaring support (slow, initially) 2018-06-09 17:32:46 -07:00
26eb05ceeb Don't use Vecs in modmul, use fixed-size buffers 2018-06-09 17:32:15 -07:00
fee68cca18 Create a modular multiplication trait, and build a slow implementation using mod. 2018-06-09 17:12:01 -07:00
11c951d29b Fix division; we were computing n wrong. 2018-06-09 17:08:13 -07:00
72a5c4568e Division! (With tests) 2018-06-04 21:36:03 -07:00
eae2ea49a9 My multiplication loops were not, in fact, off by one. 2018-06-04 21:35:13 -07:00
69596c83ec Remove a debugging println!() that I missed in a previous commit. 2018-06-04 21:34:09 -07:00
bebb5b2861 Support for fast squaring. 2018-06-02 20:29:44 -07:00
a5f0179d77 Publish a decoder, to make testing a bit easier. 2018-06-02 20:28:53 -07:00
041f824caf Give credit where credit is due. 2018-06-02 20:28:33 -07:00
f088f0f9a5 A second crack at fixed-sized numbers. 2018-06-02 09:26:34 -07:00
152 changed files with 232489 additions and 376981 deletions

24
.gitignore vendored
View File

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

3
.gitmodules vendored Normal file
View File

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

View File

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

View File

@@ -9,20 +9,26 @@ license-file = "LICENSE"
repository = "https://github.com/acw/simple_crypto"
[dependencies]
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"
byteorder = "^1.2.7"
chrono = "^0.4.6"
cryptonum = { path = "cryptonum" }
digest = "^0.8.0"
hmac = "^0.7.0"
num = "^0.2.0"
rand = "^0.6.0"
sha-1 = "^0.8.1"
sha2 = "^0.8.0"
simple_asn1 = "^0.2.0"
[dev-dependencies]
quickcheck = "^0.4.1"
quickcheck = "^0.7.2"
[profile.dev]
opt-level = 1
overflow-checks = false
[profile.test]
opt-level = 2
debug = true
debug-assertions = true
overflow-checks = false

10
TECHNICAL_DEBT Normal file
View File

@@ -0,0 +1,10 @@
- Build RSA test cases from Haskell examples
- Build DSA test cases from Haskell examples
- 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

1
cryptonum Submodule

Submodule cryptonum added at 037413ad15

View File

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

@@ -1,85 +0,0 @@
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)
}
}
}
}

View File

@@ -1,187 +0,0 @@
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);
});
}

View File

@@ -1,13 +0,0 @@
#[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::*;

View File

@@ -1,139 +0,0 @@
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 }
}

View File

@@ -1,406 +0,0 @@
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
}
}
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,585 +0,0 @@
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,77 +1,69 @@
mod errors;
mod generation;
#[cfg(test)]
mod gold_tests;
mod parameters;
mod public;
mod params;
mod private;
pub(crate) mod rfc6979;
mod public;
pub mod rfc6979;
#[cfg(test)]
mod tests;
pub use self::public::DSAPublic;
pub use self::private::DSAPrivate;
pub use self::rfc6979::DSASignature;
pub use self::params::*;
pub use self::private::*;
pub use self::public::*;
use cryptonum::UCN;
use rand::{OsRng,Rng};
use self::errors::*;
use self::parameters::*;
use cryptonum::unsigned::*;
use rand::Rng;
use rand::distributions::Standard;
/// A DSA key pair
#[derive(Clone,Debug,PartialEq)]
pub struct DSAKeyPair {
pub private: DSAPrivate,
pub public: DSAPublic
pub struct DSAKeyPair<P,L,N>
{
pub private: DSAPrivKey<P,N>,
pub public: DSAPubKey<P,L>
}
impl DSAKeyPair {
pub fn generate(size: DSAParameterSize)
-> Result<DSAKeyPair,DSAGenError>
{
let mut rng = OsRng::new()?;
DSAKeyPair::generate_rng(&mut rng, size)
}
pub trait DSAKeyGeneration
{
type Params;
pub fn generate_rng<G: Rng>(rng: &mut G, size: DSAParameterSize)
-> Result<DSAKeyPair,DSAGenError>
{
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 = 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
// with the (L, N) pair; see SP 800-57.
// 4. Obtain a string of N+64 returned_bits from an RBG with a security
// 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.gen_iter().take(n + 8).collect();
// 5. Convert returned_bits to the (non-negative) integer c.
let c = UCN::from_bytes(&returned_bits);
// 6. x = (c mod (q-1)) + 1.
let one = UCN::from(1 as u64);
let x = (&c % (&params.q - &one)) + &one;
// 7. y = g^x mod p
let y = params.g.fastmodexp(&x, &params.pu);
// 8. Return SUCCESS, x, and y.
let private = DSAPrivate { params: params.clone(), x: x };
let public = DSAPublic { params: params.clone(), y: y };
Ok(DSAKeyPair {
private: private,
public: public
})
}
fn generate<G: Rng>(params: &Self::Params, rng: &mut G) -> Self;
}
macro_rules! generate_dsa_pair {
($ptype: ident, $ltype: ident, $ntype: ident, $nbig: ident) => {
impl DSAKeyGeneration for DSAKeyPair<$ptype,$ltype,$ntype>
{
type Params = $ptype;
fn generate<G: Rng>(params: &$ptype, rng: &mut G) -> Self
{
// 1. N = len(q); L = len(p);
let n = $ptype::n_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
// with the (L, N) pair; see SP 800-57.
// 4. Obtain a string of N+64 returned_bits from an RBG with a security
// 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 + 8).collect();
// 5. Convert returned_bits to the (non-negative) integer c.
let c = $nbig::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 );
// 7. y = g^x mod p
let y = params.g.modexp(&$ltype::from(&x), &params.p);
// 8. Return SUCCESS, x, and y.
let private = DSAPrivKey::new(params.clone(), x);
let public = DSAPubKey::new(params.clone(), y);
DSAKeyPair { private, 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);

View File

@@ -1,119 +0,0 @@
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)
}
}

212
src/dsa/params.rs Normal file
View File

@@ -0,0 +1,212 @@
use cryptonum::unsigned::{CryptoNum,Decoder,Encoder,ModExp,PrimeGen};
use cryptonum::unsigned::{U192,U256,U1024,U2048,U3072};
use digest::Digest;
use sha2::Sha256;
use simple_asn1::{ToASN1,ASN1Block,ASN1Class,ASN1EncodeErr};
use rand::Rng;
use utils::TranslateNums;
pub trait DSAParameters : ToASN1
{
type L;
type N;
fn new(p: Self::L, g: Self::L, q: Self::N) -> Self;
fn generate<G: Rng>(rng: &mut G) -> Self;
fn n_size() -> usize;
fn l_size() -> usize;
fn n_bits(&self) -> usize {
Self::n_size()
}
}
macro_rules! generate_parameters {
($name: ident, $ltype: ident, $ntype: ident, $l: expr, $n: expr) => {
#[derive(Clone)]
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
{
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 ulow = if U.is_even() { 0 } else { 1 };
let mut q = $ntype::from(1u64) << (N - 1);
q += U;
q += $ntype::from(1u64 + ulow);
// 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());
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::digest(&base).as_slice().to_vec()
}

View File

@@ -1,89 +1,179 @@
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;
use cryptonum::unsigned::*;
use cryptonum::signed::ModInv;
use digest::{BlockInput,Digest,Input,FixedOutput,Reset};
use dsa::params::*;
use dsa::rfc6979::*;
use hmac::{Hmac,Mac};
/// A DSA private key.
#[derive(Clone,Debug,PartialEq)]
pub struct DSAPrivate {
pub params: DSAParameters,
pub(crate) x: UCN
pub trait DSAPrivateKey {
type Params;
type L;
type N;
/// Generate a new private key using the given DSA parameters and private
/// key value.
fn new(params: Self::Params, x: Self::N) -> Self;
/// Generate a DSA signature for the given message, using the appropriate
/// hash included in the type invocation.
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<Self::N>
where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac;
}
impl DSAPrivate {
pub fn new(params: &DSAParameters, x: UCN) -> DSAPrivate {
DSAPrivate {
params: params.clone(),
x: x
}
}
pub struct DSAPrivKey<Params,N>
{
pub(crate) params: Params,
pub(crate) x: N
}
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.
//
// 1. H(m) is transformed into an integer modulo q using the bits2int
// transform and an extra modular reduction:
//
// h = bits2int(H(m)) mod q
//
// As was noted in the description of bits2octets, the extra
// modular reduction is no more than a conditional subtraction.
//
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);
pub enum DSAPrivate {
DSA1024Private(DSAPrivKey<L1024N160,U192>),
DSA2048SmallPrivate(DSAPrivKey<L2048N224,U256>),
DSA2048Private(DSAPrivKey<L2048N256,U256>),
DSA3072Private(DSAPrivKey<L3072N256,U256>)
}
// 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
// of the remainder of this document will revolve around the
// 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::<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:
// r = g^k mod p mod q
//
// (The exponentiation is performed modulo p, yielding a
// number between 0 and p-1, which is then further reduced
// modulo q.)
// * For ECDSA ...
//
// If r turns out to be zero, a new k should be selected and r
// computed again (this is an utterly improbable occurrence).
let r = self.params.g.fastmodexp(&k, &self.params.pu)
.rem(&self.params.q);
if r.is_zero() {
continue;
macro_rules! privkey_impls {
($ptype: ident, $ltype: ident, $ntype: ident, $big: ident, $bigger: ident, $biggest: ident) => {
impl DSAPrivateKey for DSAPrivKey<$ptype,$ntype>
{
type Params = $ptype;
type L = $ltype;
type N = $ntype;
fn new(params: $ptype, x: $ntype) -> DSAPrivKey<$ptype,$ntype>
{
DSAPrivKey{ params, x }
}
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<$ntype>
where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac
{
// This algorithm is per RFC 6979, which has a nice, relatively
// straightforward description of how to do DSA signing.
//
// 1. H(m) is transformed into an integer modulo q using the bits2int
// transform and an extra modular reduction:
//
// h = bits2int(H(m)) mod q
//
// As was noted in the description of bits2octets, the extra
// modular reduction is no more than a conditional subtraction.
//
let h1 = <Hash>::digest(m);
let n = $ptype::n_size();
let h0: $ntype = bits2int(&h1, $ptype::n_size());
let q = &self.params.q;
let h = h0 % q;
// 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
// of the remainder of this document will revolve around the
// 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::<Hash,$ntype>::new(&h1, n, q, &self.x) {
// 3. A value r (modulo q) is computed from k and the key
// parameters:
// * For DSA:
// r = g^k mod p mod q
//
// (The exponentiation is performed modulo p, yielding a
// number between 0 and p-1, which is then further reduced
// modulo q.)
// * For ECDSA ...
//
// 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() {
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));
}
}
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 sha2::{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 = DSAPrivKey::<$params,$nt>::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);
});
}
// 4. The value s (modulo q) is computed:
//
// s = (h+x*r)/k mod q
//
// The pair (r, s) is the signature.
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().");
)*
}
}
generate_tests!( (DSA1024N160, L1024N160, U1024, U192),
(DSA2048N224, L2048N224, U2048, U256),
(DSA2048N256, L2048N256, U2048, U256),
(DSA3072N256, L3072N256, U3072, U256)
);

View File

@@ -1,72 +1,159 @@
use cryptonum::{SCN,UCN};
use digest::{FixedOutput,Input};
use dsa::parameters::{DSAParameters,n_bits};
use cryptonum::unsigned::*;
use cryptonum::signed::ModInv;
use digest::Digest;
use dsa::params::*;
use dsa::rfc6979::DSASignature;
use num::BigInt;
use simple_asn1::{ASN1Block,ToASN1,ASN1EncodeErr,ASN1Class};
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,ToASN1};
use std::cmp::min;
use std::ops::Rem;
use utils::TranslateNums;
/// A DSA key pair
#[derive(Clone,Debug,PartialEq)]
pub struct DSAPublic {
pub params: DSAParameters,
pub y: UCN
pub trait DSAPublicKey {
type Params : DSAParameters;
type L;
type N;
/// Generate a new public key given the parameters and public value.
fn new(params: Self::Params, y: Self::L) -> Self;
/// Verify the given signature against the given message, using the
/// appropriate hash function.
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<Self::N>) -> bool
where Hash: Digest;
}
impl DSAPublic {
pub fn new(params: &DSAParameters, y: UCN) -> DSAPublic {
DSAPublic {
params: params.clone(),
y: y
}
}
pub struct DSAPubKey<Params,L> {
pub(crate) params: Params,
pub(crate) y: L
}
pub fn verify<Hash>(&self, m: &[u8], sig: &DSASignature) -> bool
where Hash: Clone + Default + Input + FixedOutput
{
if sig.r >= self.params.q {
return false;
pub enum DSAPublic {
DSAPublicL1024N160(DSAPubKey<L1024N160,U1024>),
DSAPublicL2048N224(DSAPubKey<L2048N224,U2048>),
DSAPublicL2048N256(DSAPubKey<L2048N256,U2048>),
DSAPublicL3072N256(DSAPubKey<L3072N256,U3072>)
}
macro_rules! pubkey_impls {
($ptype: ident, $ltype: ident, $ntype: ident, $dbl: ident, $bdbl: ident) => {
impl DSAPublicKey for DSAPubKey<$ptype,$ltype>
{
type Params = $ptype;
type L = $ltype;
type N = $ntype;
fn new(params: $ptype, y: $ltype) -> DSAPubKey<$ptype,$ltype>
{
DSAPubKey{ params, y }
}
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<$ntype>) -> bool
where Hash: Digest
{
if sig.r >= self.params.q {
return false;
}
if sig.s >= self.params.q {
return false;
}
// w = (s')^-1 mod q;
if let Some(w) = sig.s.modinv(&self.params.q) {
// z = the leftmost min(N, outlen) bits of Hash(M').
let mut digest_bytes = <Hash>::digest(m).to_vec();
let len = min(digest_bytes.len(), $ptype::n_size() / 8);
digest_bytes.truncate(len);
let z = $ntype::from_bytes(&digest_bytes);
// u1 = (zw) mod q
let qdbl = $dbl::from(&self.params.q);
let u1 = $ltype::from( (&z * &w) % &qdbl );
// u2 = (rw) mod q
let u2 = $ltype::from( (&sig.r * &w) % &qdbl );
// 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);
// if v = r, then the signature is verified
return $ntype::from(v) == sig.r
}
false
}
}
if sig.s >= self.params.q {
return false;
impl ToASN1 for DSAPubKey<$ptype,$ltype> {
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);
Ok(vec![yblock])
}
}
// w = (s')^-1 mod q;
let w = sig.s.modinv(&self.params.q);
// z = the leftmost min(N, outlen) bits of Hash(M').
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 u1 = (&z * &w).reduce(&self.params.qu);
// u2 = (rw) mod q
let u2 = (&sig.r * &w).reduce(&self.params.qu);
// v = (((g)^u1(y)^u2) mod p) mod 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
v == sig.r
};
}
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 sha2::{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 = DSAPubKey::<$params,$lt>::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)
}
});
}
}
)*
}
}
impl ToASN1 for DSAPublic {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let inty = SCN::from(self.y.clone());
let yblock = ASN1Block::Integer(c, 0, BigInt::from(inty));
Ok(vec![yblock])
}
}
generate_tests!( (DSA1024N160, L1024N160, U1024, U192),
(DSA2048N224, L2048N224, U2048, U256),
(DSA2048N256, L2048N256, U2048, U256),
(DSA3072N256, L3072N256, U3072, U256)
);

View File

@@ -1,31 +1,48 @@
use cryptonum::UCN;
use digest::{BlockInput,FixedOutput,Input};
use cryptonum::unsigned::{CryptoNum,Decoder,Encoder};
use digest::{BlockInput,Digest,FixedOutput,Input,Reset};
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;
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 }
}
}
#[allow(non_snake_case)]
pub struct KIterator<H>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
H::BlockSize : ArrayLength<u8>
pub struct KIterator<H,N>
where
H: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
N: Clone + Decoder + Encoder + PartialOrd + Shr<usize,Output=N>,
Hmac<H>: Mac
{
hmac_k: Hmac<H>,
V: Vec<u8>,
q: UCN,
q: N,
qlen: usize
}
impl<H> KIterator<H>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H::BlockSize : ArrayLength<u8>
impl<H,N> KIterator<H,N>
where
H: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
N: Clone + Decoder + Encoder + PartialOrd + Shr<usize,Output=N> + Sub<Output=N>,
Hmac<H>: Mac
{
pub fn new(h1: &[u8], qlen: usize, q: &UCN, x: &UCN) -> KIterator<H>
pub fn new(h1: &[u8], qlen: usize, q: &N, x: &N) -> KIterator<H,N>
{
// Given the input message m, the following process is applied:
//
@@ -100,7 +117,7 @@ impl<H> KIterator<H>
V = hmac(&K, &V);
// h is for later ...
KIterator {
hmac_k: Hmac::<H>::new(&K).unwrap(),
hmac_k: Hmac::<H>::new_varkey(&K).unwrap(),
V: V,
q: q.clone(),
qlen: qlen
@@ -108,15 +125,16 @@ impl<H> KIterator<H>
}
}
impl<H> Iterator for KIterator<H>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H::BlockSize : ArrayLength<u8>
impl<H,N> Iterator for KIterator<H,N>
where
H: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
N: Clone + CryptoNum + Decoder + Encoder + PartialOrd + Shr<usize,Output=N>,
Hmac<H>: Mac
{
type Item = UCN;
type Item = N;
fn next(&mut self) -> Option<UCN> {
fn next(&mut self) -> Option<N>
{
loop {
// h. Apply the following algorithm until a proper value is found
// for k:
@@ -138,7 +156,7 @@ impl<H> Iterator for KIterator<H>
// 3. Compute:
//
// k = bits2int(T)
let resk = bits2int(&t, self.qlen);
let resk: N = 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
@@ -152,44 +170,64 @@ impl<H> Iterator for KIterator<H>
#[allow(non_snake_case)]
let K = runhmac(&self.hmac_k, &input);
// V = HMAC_K(V)
self.hmac_k = Hmac::<H>::new(&K).unwrap();
self.hmac_k = Hmac::<H>::new_varkey(&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: &[u8], qlen: usize) -> UCN {
let mut value = UCN::from_bytes(x);
let vlen = x.len() * 8;
pub fn bits2int<X>(x: &[u8], qlen: usize) -> X
where
X: Decoder + Shr<usize,Output=X>
{
if vlen > qlen {
value >>= vlen - qlen;
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)
}
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 };
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 };
int2octets(&res, qlen)
}
fn int2octets(x: &UCN, qlen_bits: usize) -> Vec<u8> {
fn int2octets<X>(x: &X, qlen_bits: usize) -> Vec<u8>
where X: Encoder
{
let qlen_bytes = (qlen_bits + 7) / 8;
x.to_bytes(qlen_bytes)
let mut base = x.to_bytes();
while base.len() < qlen_bytes {
base.insert(0,0);
}
while base.len() > qlen_bytes {
base.remove(0);
}
base
}
fn runhmac<H>(base: &Hmac<H>, m: &[u8]) -> Vec<u8>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H: Clone + BlockInput + Default + Input + FixedOutput + Reset,
Hmac<H>: Clone + Mac,
H::BlockSize : ArrayLength<u8>
{
let mut runner = base.clone();
@@ -199,27 +237,21 @@ fn runhmac<H>(base: &Hmac<H>, m: &[u8]) -> Vec<u8>
fn hmac<H>(k: &[u8], m: &[u8]) -> Vec<u8>
where
H: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<H>: Clone,
H: BlockInput + Clone + Default + Input + FixedOutput + Reset,
Hmac<H>: Clone + Mac,
H::BlockSize : ArrayLength<u8>
{
let mut runner = Hmac::<H>::new(&k).unwrap();
let mut runner = Hmac::<H>::new_varkey(&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,
NegativeSigValues
InvalidRValue,
InvalidSValue
}
impl From<ASN1DecodeErr> for DSADecodeError {
@@ -228,11 +260,13 @@ impl From<ASN1DecodeErr> for DSADecodeError {
}
}
impl FromASN1 for DSASignature {
impl<N> FromASN1 for DSASignature<N>
where N: TranslateNums<BigInt>
{
type Error = DSADecodeError;
fn from_asn1(v: &[ASN1Block])
-> Result<(DSASignature,&[ASN1Block]),DSADecodeError>
-> Result<(DSASignature<N>,&[ASN1Block]),DSADecodeError>
{
match v.split_first() {
Some((&ASN1Block::Sequence(_,_,ref info), rest))
@@ -241,12 +275,9 @@ impl FromASN1 for DSASignature {
match (&info[0], &info[1]) {
(&ASN1Block::Integer(_,_,ref rint),
&ASN1Block::Integer(_,_,ref sint)) => {
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))
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))
}
_ => Err(DSADecodeError::NoSignatureFound)
}
@@ -256,22 +287,26 @@ impl FromASN1 for DSASignature {
}
}
impl ToASN1 for DSASignature {
impl<N> ToASN1 for DSASignature<N>
where N: TranslateNums<BigInt>
{
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
{
let rb = ASN1Block::Integer(c, 0, BigInt::from(self.r.clone()));
let sb = ASN1Block::Integer(c, 0, BigInt::from(self.s.clone()));
let rb = ASN1Block::Integer(c, 0, self.r.to_num());
let sb = ASN1Block::Integer(c, 0, self.s.to_num());
Ok(vec![ASN1Block::Sequence(c, 0, vec![rb,sb])])
}
}
#[cfg(test)]
mod tests {
use sha2::Sha256;
use cryptonum::unsigned::U192;
use sha2::{Sha224,Sha256,Sha384,Sha512};
use super::*;
use testing::*;
const QBYTES: [u8; 21] = [0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x01, 0x08, 0xA2, 0xE0, 0xCC,
@@ -286,7 +321,7 @@ mod tests {
#[test]
fn int2octets_example() {
let x = UCN::from_bytes(&XBYTES);
let x = U192::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,
@@ -296,7 +331,7 @@ mod tests {
#[test]
fn bits2octets_example() {
let q = UCN::from_bytes(&QBYTES);
let q = U192::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,
@@ -306,9 +341,9 @@ mod tests {
#[test]
fn k_gen_example() {
let q = UCN::from_bytes(&QBYTES);
let x = UCN::from_bytes(&XBYTES);
let mut iter = KIterator::<Sha256>::new(&H1, 163, &q, &x);
let q = U192::from_bytes(&QBYTES);
let x = U192::from_bytes(&XBYTES);
let mut iter = KIterator::<Sha256,U192>::new(&H1, 163, &q, &x);
match iter.next() {
None =>
assert!(false),
@@ -316,9 +351,86 @@ 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 = UCN::from_bytes(&target);
let x2 = U192::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,138 +1,29 @@
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 cryptonum::unsigned::*;
use digest::Digest;
use sha1::Sha1;
use sha2::{Sha224,Sha256,Sha384,Sha512};
use simple_asn1::{der_decode,der_encode};
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)
}
});
}
use dsa::params::{DSAParameters,L1024N160,L2048N256};
use dsa::private::{DSAPrivateKey,DSAPrivKey};
use dsa::public::{DSAPublicKey,DSAPubKey};
use dsa::rfc6979::KIterator;
macro_rules! run_rfc6979_test {
($hash: ty, $val: ident, $public: ident, $private: ident,
($hash: ty, $ntype: ident, $val: ident, $params: ident, $public: ident, $private: ident,
k $k: expr,
r $r: expr,
s $s: expr) => ({
let mut digest = <$hash>::default();
digest.process(&$val);
let h1 = digest.fixed_result().as_slice().to_vec();
let h1 = <$hash>::digest(&$val);
let rbytes = $r;
let sbytes = $s;
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);
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);
}
assert_eq!($k, k1);
let sig = $private.sign::<$hash>(&$val);
assert_eq!(sig.r, r);
@@ -202,14 +93,14 @@ fn appendix_a21() {
0x86, 0xE2, 0x22, 0x31, 0x70, 0xB4, 0x4E, 0xAA,
0x7D, 0xA5, 0xDD, 0x9F, 0xFC, 0xFB, 0x7F, 0x3B];
//
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 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 = DSAPrivKey::new(params.clone(), x);
let public = DSAPubKey::<L1024N160,U1024>::new(params.clone(), y);
//
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
@@ -217,7 +108,7 @@ fn appendix_a21() {
// k = 7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B
// r = 2E1A0C2562B2912CAAF89186FB0F42001585DA55
// s = 29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5
run_rfc6979_test!(Sha1, sample, public, private,
run_rfc6979_test!(Sha1, U192, sample, params, public, private,
k vec![0x7B, 0xDB, 0x6B, 0x0F, 0xF7, 0x56, 0xE1, 0xBB,
0x5D, 0x53, 0x58, 0x3E, 0xF9, 0x79, 0x08, 0x2F,
0x9A, 0xD5, 0xBD, 0x5B],
@@ -231,7 +122,7 @@ fn appendix_a21() {
// k = 562097C06782D60C3037BA7BE104774344687649
// r = 4BC3B686AEA70145856814A6F1BB53346F02101E
// s = 410697B92295D994D21EDD2F4ADA85566F6F94C1
run_rfc6979_test!(Sha224, sample, public, private,
run_rfc6979_test!(Sha224, U192, sample, params, public, private,
k vec![0x56, 0x20, 0x97, 0xC0, 0x67, 0x82, 0xD6, 0x0C,
0x30, 0x37, 0xBA, 0x7B, 0xE1, 0x04, 0x77, 0x43,
0x44, 0x68, 0x76, 0x49],
@@ -245,7 +136,7 @@ fn appendix_a21() {
// k = 519BA0546D0C39202A7D34D7DFA5E760B318BCFB
// r = 81F2F5850BE5BC123C43F71A3033E9384611C545
// s = 4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89
run_rfc6979_test!(Sha256, sample, public, private,
run_rfc6979_test!(Sha256, U192, sample, params, public, private,
k vec![0x51, 0x9B, 0xA0, 0x54, 0x6D, 0x0C, 0x39, 0x20,
0x2A, 0x7D, 0x34, 0xD7, 0xDF, 0xA5, 0xE7, 0x60,
0xB3, 0x18, 0xBC, 0xFB],
@@ -259,7 +150,7 @@ fn appendix_a21() {
// k = 95897CD7BBB944AA932DBC579C1C09EB6FCFC595
// r = 07F2108557EE0E3921BC1774F1CA9B410B4CE65A
// s = 54DF70456C86FAC10FAB47C1949AB83F2C6F7595
run_rfc6979_test!(Sha384, sample, public, private,
run_rfc6979_test!(Sha384, U192, sample, params, public, private,
k vec![0x95, 0x89, 0x7C, 0xD7, 0xBB, 0xB9, 0x44, 0xAA,
0x93, 0x2D, 0xBC, 0x57, 0x9C, 0x1C, 0x09, 0xEB,
0x6F, 0xCF, 0xC5, 0x95],
@@ -273,7 +164,7 @@ fn appendix_a21() {
// k = 09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B
// r = 16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B
// s = 02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C
run_rfc6979_test!(Sha512, sample, public, private,
run_rfc6979_test!(Sha512, U192, sample, params, public, private,
k vec![0x09, 0xEC, 0xE7, 0xCA, 0x27, 0xD0, 0xF5, 0xA4,
0xDD, 0x4E, 0x55, 0x6C, 0x9D, 0xF1, 0xD2, 0x1D,
0x28, 0x10, 0x4F, 0x8B],
@@ -287,7 +178,7 @@ fn appendix_a21() {
// k = 5C842DF4F9E344EE09F056838B42C7A17F4A6433
// r = 42AB2052FD43E123F0607F115052A67DCD9C5C77
// s = 183916B0230D45B9931491D4C6B0BD2FB4AAF088
run_rfc6979_test!(Sha1, test, public, private,
run_rfc6979_test!(Sha1, U192, test, params, public, private,
k vec![0x5C, 0x84, 0x2D, 0xF4, 0xF9, 0xE3, 0x44, 0xEE,
0x09, 0xF0, 0x56, 0x83, 0x8B, 0x42, 0xC7, 0xA1,
0x7F, 0x4A, 0x64, 0x33],
@@ -301,7 +192,7 @@ fn appendix_a21() {
// k = 4598B8EFC1A53BC8AECD58D1ABBB0C0C71E67297
// r = 6868E9964E36C1689F6037F91F28D5F2C30610F2
// s = 49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F
run_rfc6979_test!(Sha224, test, public, private,
run_rfc6979_test!(Sha224, U192, test, params, public, private,
k vec![0x45, 0x98, 0xB8, 0xEF, 0xC1, 0xA5, 0x3B, 0xC8,
0xAE, 0xCD, 0x58, 0xD1, 0xAB, 0xBB, 0x0C, 0x0C,
0x71, 0xE6, 0x72, 0x97],
@@ -315,7 +206,7 @@ fn appendix_a21() {
// k = 5A67592E8128E03A417B0484410FB72C0B630E1A
// r = 22518C127299B0F6FDC9872B282B9E70D0790812
// s = 6837EC18F150D55DE95B5E29BE7AF5D01E4FE160
run_rfc6979_test!(Sha256, test, public, private,
run_rfc6979_test!(Sha256, U192, test, params, public, private,
k vec![0x5A, 0x67, 0x59, 0x2E, 0x81, 0x28, 0xE0, 0x3A,
0x41, 0x7B, 0x04, 0x84, 0x41, 0x0F, 0xB7, 0x2C,
0x0B, 0x63, 0x0E, 0x1A],
@@ -329,7 +220,7 @@ fn appendix_a21() {
// k = 220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89
// r = 854CF929B58D73C3CBFDC421E8D5430CD6DB5E66
// s = 91D0E0F53E22F898D158380676A871A157CDA622
run_rfc6979_test!(Sha384, test, public, private,
run_rfc6979_test!(Sha384, U192, test, params, public, private,
k vec![0x22, 0x01, 0x56, 0xB7, 0x61, 0xF6, 0xCA, 0x5E,
0x6C, 0x9F, 0x1B, 0x9C, 0xF9, 0xC2, 0x4B, 0xE2,
0x5F, 0x98, 0xCD, 0x89],
@@ -343,7 +234,7 @@ fn appendix_a21() {
// k = 65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C
// r = 8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0
// s = 7C670C7AD72B6C050C109E1790008097125433E8
run_rfc6979_test!(Sha512, test, public, private,
run_rfc6979_test!(Sha512, U192, test, params, public, private,
k vec![0x65, 0xD2, 0xC2, 0xEE, 0xB1, 0x75, 0xE3, 0x70,
0xF2, 0x8C, 0x75, 0xBF, 0xCD, 0xC0, 0x28, 0xD2,
0x2C, 0x7D, 0xBE, 0x9C],
@@ -462,14 +353,14 @@ fn appendix_a22() {
0xD4,0xA0,0x98,0x63,0x15,0xDA,0x8E,0xEC,
0x65,0x61,0xC9,0x38,0x99,0x6B,0xEA,0xDF];
//
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 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 = DSAPrivKey::<L2048N256,U256>::new(params.clone(), x);
let public = DSAPubKey::<L2048N256,U2048>::new(params.clone(), y);
//
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
@@ -477,7 +368,7 @@ fn appendix_a22() {
// k = 888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E
// r = 3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A
// s = D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF
run_rfc6979_test!(Sha1, sample, public, private,
run_rfc6979_test!(Sha1, U256, sample, params, 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,
@@ -494,7 +385,7 @@ fn appendix_a22() {
// k = BC372967702082E1AA4FCE892209F71AE4AD25A6DFD869334E6F153BD0C4D806
// r = DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C
// s = A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC
run_rfc6979_test!(Sha224, sample, public, private,
run_rfc6979_test!(Sha224, U256, sample, params, 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,
@@ -511,7 +402,7 @@ fn appendix_a22() {
// k = 8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52
// r = EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809
// s = 7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53
run_rfc6979_test!(Sha256, sample, public, private,
run_rfc6979_test!(Sha256, U256, sample, params, 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,
@@ -528,7 +419,7 @@ fn appendix_a22() {
// k = C345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920
// r = B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B
// s = 19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B
run_rfc6979_test!(Sha384, sample, public, private,
run_rfc6979_test!(Sha384, U256, sample, params, 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,
@@ -545,7 +436,7 @@ fn appendix_a22() {
// k = 5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC
// r = 2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E
// s = D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351
run_rfc6979_test!(Sha512, sample, public, private,
run_rfc6979_test!(Sha512, U256, sample, params, 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,
@@ -562,7 +453,7 @@ fn appendix_a22() {
// k = 6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F
// r = C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0
// s = 414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA
run_rfc6979_test!(Sha1, test, public, private,
run_rfc6979_test!(Sha1, U256, test, params, 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,
@@ -579,7 +470,7 @@ fn appendix_a22() {
// k = 06BD4C05ED74719106223BE33F2D95DA6B3B541DAD7BFBD7AC508213B6DA6670
// r = 272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3
// s = E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806
run_rfc6979_test!(Sha224, test, public, private,
run_rfc6979_test!(Sha224, U256, test, params, 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,
@@ -596,7 +487,7 @@ fn appendix_a22() {
// k = 1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7
// r = 8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0
// s = 7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E
run_rfc6979_test!(Sha256, test, public, private,
run_rfc6979_test!(Sha256, U256, test, params, 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,
@@ -613,7 +504,7 @@ fn appendix_a22() {
// k = 206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C
// r = 239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE
// s = 6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961
run_rfc6979_test!(Sha384, test, public, private,
run_rfc6979_test!(Sha384, U256, test, params, 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,
@@ -630,7 +521,7 @@ fn appendix_a22() {
// k = AFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA
// r = 89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307
// s = C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1
run_rfc6979_test!(Sha512, test, public, private,
run_rfc6979_test!(Sha512, U256, test, params, 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,

440
src/ecdsa/curve.rs Normal file
View File

@@ -0,0 +1,440 @@
use cryptonum::signed::{I192,I256,I384,I576};
use cryptonum::unsigned::{Decoder};
use cryptonum::unsigned::{U192,U256,U384,U576};
#[allow(non_snake_case)]
pub trait EllipticCurve {
type Unsigned : Clone;
type Signed : Clone;
fn size() -> usize;
fn p() -> Self::Unsigned;
fn n() -> Self::Unsigned;
fn SEED() -> Self::Unsigned;
fn c() -> Self::Unsigned;
fn a() -> Self::Unsigned;
fn b() -> Self::Unsigned;
fn Gx() -> Self::Signed;
fn Gy() -> Self::Signed;
}
pub enum P192 {}
impl EllipticCurve for P192 {
type Unsigned = U192;
type Signed = I192;
fn 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]))
}
}
pub enum P224 {}
impl EllipticCurve for P224 {
type Unsigned = U256;
type Signed = I256;
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
]))
}
}
pub enum P256 {}
impl EllipticCurve for P256 {
type Signed = I256;
type Unsigned = U256;
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
]))
}
}
pub enum P384 {}
impl EllipticCurve for P384 {
type Signed = I384;
type Unsigned = U384;
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
]))
}
}
pub enum P521 {}
impl EllipticCurve for P521 {
type Signed = I576;
type Unsigned = U576;
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
]))
}
}

View File

@@ -1,443 +0,0 @@
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 ]
};

View File

@@ -1,187 +0,0 @@
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,61 +1,54 @@
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
// }
// }
// }
//}
//
//
pub mod curve;
pub mod point;
pub mod private;
pub 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;
use self::curve::{EllipticCurve,P192,P224,P256,P384,P521};
use self::point::{ECCPoint,Point};
pub use self::private::{ECCPrivateKey,ECCPrivate};
pub use self::public::{ECCPublicKey,ECDSAPublic,ECCPubKey};
pub use self::public::{ECDSADecodeErr,ECDSAEncodeErr};
pub trait ECDSAKeyPair<Public,Private> {
fn generate<G: Rng>(g: &mut G) -> (Public, Private);
}
macro_rules! generate_impl {
($curve: ident, $un: ident, $si: ident) => {
impl ECDSAKeyPair<ECCPubKey<$curve>,ECCPrivate<$curve>> for $curve {
fn generate<G: Rng>(rng: &mut G) -> (ECCPubKey<$curve>, ECCPrivate<$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 = ECCPubKey::<$curve>::new(public_point);
let private = ECCPrivate::<$curve>::new(proposed_d);
return (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);

View File

@@ -1,227 +1,328 @@
use cryptonum::{SCN,UCN};
use ecdsa::curves::EllipticCurve;
use cryptonum::signed::*;
use cryptonum::unsigned::*;
use ecdsa::curve::*;
#[derive(Clone,Debug,PartialEq)]
pub struct ECPoint {
pub curve: &'static EllipticCurve,
pub value: ECPointValue
pub trait ECCPoint : Sized {
type Curve: EllipticCurve;
type Scale;
fn default() -> Self;
fn negate(&self) -> Self;
fn double(&self) -> Self;
fn add(&self, other: &Self) -> Self;
fn scale(&self, amt: &Self::Scale) -> Self;
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)
pub struct Point<T: EllipticCurve>
{
pub x: T::Signed,
pub y: T::Signed
}
impl ECPoint {
pub fn new(ec: &'static EllipticCurve, x: SCN, y: SCN) -> ECPoint {
ECPoint {
curve: ec,
value: ECPointValue::Point(x, y)
}
}
pub fn zero(ec: &'static EllipticCurve) -> ECPoint {
ECPoint { curve: ec, value: ECPointValue::Infinity }
}
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 }
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 get_x(&self) -> SCN {
match self.value {
ECPointValue::Infinity =>
SCN::zero(),
ECPointValue::Point(ref x, _) =>
x.clone()
}
}
impl ECCPoint for Point<$curve> {
type Curve = $curve;
type Scale = $base;
pub fn get_y(&self) -> SCN {
match self.value {
ECPointValue::Infinity =>
SCN::zero(),
ECPointValue::Point(_, ref y) =>
y.clone()
}
}
fn default() -> Point<$curve>
{
Point {
x: $curve::Gx(),
y: $curve::Gy()
}
}
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());
fn negate(&self) -> Point<$curve>
{
let mut newy = $base::new(false, $curve::p());
newy -= &self.y;
Point{ x: self.x.clone(), y: newy }
}
fn double(&self) -> Point<$curve>
{
let up = $curve::p();
let bigp = $s2::new(false, $u2::from(&up));
// lambda = (3 * xp ^ 2 + a) / 2 yp
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 * &lambda;
let xr_right = x << 1;
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)));
// xr = lambda^2 - 2 xp
let mut xr = lambda.square();
let mut xr_right = $s2::from(&self.x);
xr_right <<= 1;
xr -= xr_right;
assert!(!xr.is_negative());
xr %= &up;
xr %= &bigp;
let x = $base::from(xr);
// yr = lambda (xp - xr) - yp
let xdiff = x - &xr;
let xdiff = $base::from(&self.x - &x);
let mut yr = &lambda * &xdiff;
yr -= y;
assert!(!yr.is_negative());
yr %= up;
yr -= $s2::from(&self.y);
let y = $base::from(&yr % &bigp);
//
ECPoint {
curve: self.curve,
value: ECPointValue::Point(xr, yr)
}
Point{ x, y }
}
}
}
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);
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);
let mut xr = &s * &s;
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 }
}
}
}
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) }
}
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);
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 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);
let test = d.testbit(bit as usize);
if test {
Q = Q.add(&self);
}
mask >>= 1;
bit -= 1;
}
q
if d.is_negative() {
Q.negate()
} else {
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);
// }
// }
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); }
}
}
}
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);

View File

@@ -1,93 +1,173 @@
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;
use cryptonum::signed::*;
use cryptonum::unsigned::*;
use digest::{BlockInput,Digest,Input,FixedOutput,Reset};
use dsa::rfc6979::{DSASignature,KIterator,bits2int};
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
use ecdsa::point::{ECCPoint,Point};
use hmac::{Hmac,Mac};
#[derive(Clone,Debug,PartialEq)]
pub struct ECDSAPrivate {
pub(crate) curve: &'static EllipticCurve,
pub(crate) d: UCN
pub struct ECCPrivate<Curve: EllipticCurve> {
d: Curve::Unsigned
}
impl ECDSAPrivate {
pub fn new(c: &'static EllipticCurve, d: &UCN)
-> ECDSAPrivate
{
ECDSAPrivate {
curve: c,
d: d.clone()
}
}
pub trait ECCPrivateKey {
type Unsigned;
pub fn sign<Hash>(&self, m: &[u8]) -> DSASignature
fn new(d: Self::Unsigned) -> Self;
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<Self::Unsigned>
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.
//
// 1. H(m) is transformed into an integer modulo q using the bits2int
// transform and an extra modular reduction:
//
// h = bits2int(H(m)) mod q
//
// As was noted in the description of bits2octets, the extra
// modular reduction is no more than a conditional subtraction.
//
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;
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac;
}
// 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
// of the remainder of this document will revolve around the
// 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::<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: 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 = 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;
}
// 4. The value s (modulo q) is computed:
//
// s = (h+x*r)/k mod q
//
// The pair (r, s) is the signature.
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;
macro_rules! generate_privates
{
($curve: ident, $base: ident, $sig: ident, $dbl: ident, $quad: ident) => {
impl ECCPrivateKey for ECCPrivate<$curve>
{
type Unsigned = $base;
fn new(d: $base) -> ECCPrivate<$curve>
{
ECCPrivate{ d }
}
assert!(!r.is_negative());
assert!(!s.is_negative());
return DSASignature{ r: r.value, s: s.value };
fn sign<Hash>(&self, m: &[u8]) -> DSASignature<$base>
where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac
{
// This algorithm is per RFC 6979, which has a nice, relatively
// straightforward description of how to do DSA signing.
//
// 1. H(m) is transformed into an integer modulo q using the bits2int
// transform and an extra modular reduction:
//
// h = bits2int(H(m)) mod q
//
// As was noted in the description of bits2octets, the extra
// modular reduction is no more than a conditional subtraction.
//
let h1 = <Hash>::digest(m);
let size = <$curve>::size();
let h0: $base = bits2int(&h1, size);
let n = <$curve>::n();
let h = h0 % &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
// of the remainder of this document will revolve around the
// 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::<Hash,$base>::new(&h1, size, &n, &self.d) {
// 3. A value r (modulo q) is computed from k and the key
// parameters:
// * For DSA ...
// * For ECDSA ...
//
// 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() {
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 };
}
}
panic!("The world is broken; couldn't find a k in sign().");
}
}
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 sha2::{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 = ECCPrivate::<$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,62 +1,237 @@
use digest::{BlockInput,FixedOutput,Input};
use digest::generic_array::ArrayLength;
use cryptonum::signed::*;
use cryptonum::unsigned::*;
use digest::{BlockInput,Digest,Input,FixedOutput,Reset};
use dsa::rfc6979::DSASignature;
use ecdsa::curves::EllipticCurve;
use ecdsa::math::{ECCPoint,bits2int,point_add_two_muls};
use hmac::Hmac;
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
use ecdsa::point::{ECCPoint,Point};
use hmac::{Hmac,Mac};
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,FromASN1,ToASN1};
use std::cmp::min;
#[allow(non_snake_case)]
#[derive(Clone,Debug,PartialEq)]
pub struct ECDSAPublic {
pub(crate) curve: &'static EllipticCurve,
pub(crate) Q: ECCPoint
pub struct ECCPubKey<Curve: EllipticCurve> {
q: Point<Curve>
}
impl ECDSAPublic {
pub fn new(curve: &'static EllipticCurve, point: &ECCPoint)
-> ECDSAPublic
{
ECDSAPublic {
curve: curve,
Q: point.clone()
}
}
pub enum ECDSAPublic {
ECCPublicP192(ECCPubKey<P192>),
ECCPublicP224(ECCPubKey<P224>),
ECCPublicP256(ECCPubKey<P256>),
ECCPublicP384(ECCPubKey<P384>),
ECCPublicP521(ECCPubKey<P521>),
}
pub fn verify<Hash>(&self, m: &[u8], sig: &DSASignature) -> bool
pub trait ECCPublicKey {
type Curve : EllipticCurve;
type Unsigned;
fn new(d: Point<Self::Curve>) -> Self;
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<Self::Unsigned>) -> bool
where
Hash: Clone + BlockInput + Input + FixedOutput + Default,
Hmac<Hash>: Clone,
Hash::BlockSize: ArrayLength<u8>
{
let n = &self.curve.n;
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac;
}
if &sig.r > n {
return false;
}
if &sig.s > n {
return false;
}
pub enum ECDSAEncodeErr {
ASN1EncodeErr(ASN1EncodeErr),
XValueNegative, YValueNegative
}
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;
}
(xx.value % n) == sig.r
impl From<ASN1EncodeErr> for ECDSAEncodeErr {
fn from(x: ASN1EncodeErr) -> ECDSAEncodeErr {
ECDSAEncodeErr::ASN1EncodeErr(x)
}
}
#[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 for ECCPubKey<$curve>
{
type Curve = $curve;
type Unsigned = $un;
fn new(q: Point<$curve>) -> ECCPubKey<$curve>
{
ECCPubKey{ q }
}
fn verify<Hash>(&self, m: &[u8], sig: &DSASignature<Self::Unsigned>) -> bool
where
Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset,
Hmac<Hash>: Mac
{
let n = <$curve>::n();
if sig.r.is_zero() || (sig.r >= n) {
return false;
}
if sig.s.is_zero() || (sig.s >= n) {
return false;
}
// e = the leftmost min(N, outlen) bits of Hash(M').
let mut digest_bytes = <Hash>::digest(m).to_vec();
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
}
}
}
impl ToASN1 for ECCPubKey<$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 ECCPubKey<$curve> {
type Error = ECDSADecodeErr;
fn from_asn1(bs: &[ASN1Block]) -> Result<(ECCPubKey<$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 = ECCPubKey::<$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 sha2::{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 = ECCPubKey::<$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);

View File

@@ -9,7 +9,9 @@
//! 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 byteorder;
extern crate chrono;
extern crate cryptonum;
extern crate digest;
extern crate hmac;
extern crate num;
@@ -19,28 +21,24 @@ extern crate quickcheck;
extern crate rand;
extern crate sha1;
extern crate sha2;
#[macro_use]
extern crate simple_asn1;
/// 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.
/// The `rsa` module provides bare-bones support for RSA signing, verification,
/// encryption, decryption, and key generation.
pub mod rsa;
/// 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.
/// 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.
pub mod dsa;
/// 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.
/// The `ecdsa` module provides bare-bones support for ECDSA signing,
/// verification, and key generation.
pub mod ecdsa;
/// The `x509` module supports parsing and generating x.509 certificates, as
/// used by TLS and others.
pub mod x509;
#[cfg(test)]
mod testing;
#[cfg(test)]
mod test {
}
mod utils;

View File

@@ -1,123 +1,9 @@
use cryptonum::{BarrettUCN,UCN};
use rand::Rng;
use num::bigint::BigUint;
use rsa::errors::RSAError;
use simple_asn1::{ASN1Block,ASN1DecodeErr};
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")
}
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);
}
}
}
// 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> {
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);
@@ -125,39 +11,38 @@ pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec<u8> {
assert!(keylen > (tlen + 3));
let mut padding = Vec::new();
padding.resize(keylen - tlen - 3, 0xFF);
let mut result = vec![0x00, 0x01];
let mut result = vec![0x00,0x01];
result.append(&mut padding);
result.push(0x00);
result.append(&mut idhash);
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()
}
#[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) );
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))
}
}

View File

@@ -1,16 +1,5 @@
use simple_asn1::ASN1DecodeErr;
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)
}
}
use rand;
#[derive(Debug)]
pub enum RSAError {
@@ -19,12 +8,12 @@ pub enum RSAError {
DecryptionError,
DecryptHashMismatch,
InvalidKey,
RandomGenError(io::Error),
RandomGenError(rand::Error),
ASN1DecodeErr(ASN1DecodeErr)
}
impl From<io::Error> for RSAError {
fn from(e: io::Error) -> RSAError {
impl From<rand::Error> for RSAError {
fn from(e: rand::Error) -> RSAError {
RSAError::RandomGenError(e)
}
}

View File

@@ -1,208 +0,0 @@
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,109 +1,184 @@
//! 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.
//!
mod core;
mod errors;
#[cfg(test)]
mod gold_tests;
mod oaep;
mod public;
mod private;
mod public;
mod signing_hashes;
pub use self::public::RSAPublic;
pub use self::private::RSAPrivate;
pub use self::errors::RSAError;
pub use self::signing_hashes::{SigningHash,
SIGNING_HASH_NULL, SIGNING_HASH_SHA1,
SIGNING_HASH_SHA224, SIGNING_HASH_SHA256,
SIGNING_HASH_SHA384, SIGNING_HASH_SHA512};
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,
RSA512Private, RSA1024Private, RSA2048Private,
RSA3072Private, RSA4096Private, RSA8192Private,
RSA15360Private};
pub use self::public::{RSAPublic, RSAPublicKey,
RSA512Public, RSA1024Public, RSA2048Public,
RSA3072Public, RSA4096Public, RSA8192Public,
RSA15360Public};
use cryptonum::UCN;
use rand::{OsRng,Rng};
use self::core::{ACCEPTABLE_KEY_SIZES,generate_pq};
use self::errors::*;
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;
use std::ops::Sub;
#[derive(Clone,Debug)]
pub struct RSAKeyPair {
pub public: RSAPublic,
pub private: RSAPrivate
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()
}
}
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.
///
/// 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)
}
/// 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>
{
let e = UCN::from(65537 as u32);
for &(length, _) in ACCEPTABLE_KEY_SIZES.iter() {
if length == len_bits {
let (p, q) = generate_pq(rng, &e, len_bits);
let n = &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
})
}
macro_rules! generate_rsa_pair
{
($pair: ident, $pub: ident, $priv: ident, $uint: ident, $half: ident, $iterations: expr) => {
pub struct $pair {
pub public: $pub,
pub private: $priv
}
Err(RSAKeyGenError::InvalidKeySize(len_bits))
}
impl $pair {
pub fn new(pu: $pub, pr: $priv) -> $pair {
$pair {
public: pu,
private: pr
}
}
pub fn generate<G>(rng: &mut G) -> $pair
where G: RngCore
{
loop {
let ebase = 65537u32;
let e = $uint::from(ebase);
let (p, q) = $pair::generate_pq(rng, &$half::from(ebase));
let one = $half::from(1u32);
let pminus1 = &p - &one;
let qminus1 = &q - &one;
let phi = pminus1 * qminus1;
let n = &p * &q;
if let Some(d) = e.modinv(&phi) {
let public = $pub::new(n.clone(), e);
let private = $priv::new(n, d);
return $pair::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);
}
}
}
}
}
}
generate_rsa_pair!(RSA512KeyPair, RSA512Public, RSA512Private, U512, U256, 7);
generate_rsa_pair!(RSA1024KeyPair, RSA1024Public, RSA1024Private, U1024, U512, 7);
generate_rsa_pair!(RSA2048KeyPair, RSA2048Public, RSA2048Private, U2048, U1024, 4);
generate_rsa_pair!(RSA3072KeyPair, RSA3072Public, RSA3072Private, U3072, U1536, 3);
generate_rsa_pair!(RSA4096KeyPair, RSA4096Public, RSA4096Private, U4096, U2048, 3);
generate_rsa_pair!(RSA8192KeyPair, RSA8192Public, RSA8192Private, U8192, U4096, 3);
generate_rsa_pair!(RSA15360KeyPair, RSA15360Public, RSA15360Private, U15360, U7680, 3);
#[cfg(test)]
mod tests {
mod generation {
use quickcheck::{Arbitrary,Gen};
use rsa::core::{ep,dp,sp1,vp1};
use std::fmt;
use super::*;
const TEST_KEY_SIZES: [usize; 2] = [512, 1024];
impl Clone for RSA512KeyPair {
fn clone(&self) -> RSA512KeyPair {
RSA512KeyPair{
public: RSA512Public {
n: self.public.n.clone(),
nu: self.public.nu.clone(),
e: self.public.e.clone(),
},
private: RSA512Private {
nu: self.private.nu.clone(),
d: self.private.d.clone()
}
}
}
}
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()
impl fmt::Debug for RSA512KeyPair {
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 RSA512KeyPair {
fn arbitrary<G: Gen>(g: &mut G) -> RSA512KeyPair {
RSA512KeyPair::generate(g)
}
}
quickcheck! {
#[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
fn generate_and_sign(keypair: RSA512KeyPair, msg: Vec<u8>) -> bool {
let sig = keypair.private.sign(&SIGNING_HASH_SHA256, &msg);
keypair.public.verify(&SIGNING_HASH_SHA256, &msg, &sig)
}
}
}

View File

@@ -1,44 +1,43 @@
use cryptonum::UCN;
use digest::{FixedOutput,Input};
use byteorder::{BigEndian,ByteOrder};
use digest::{Digest,FixedOutput};
use std::marker::PhantomData;
/// 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
/// 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: Default + Digest + FixedOutput> {
pub label: String,
phantom: PhantomData<H>
}
impl<H: Clone + Input + FixedOutput> OAEPParams<H> {
pub fn new(hash: H, label: String)
impl<H: Default + Digest + FixedOutput> OAEPParams<H> {
pub fn new(label: String)
-> OAEPParams<H>
{
OAEPParams { hash: hash, label: label }
OAEPParams { label: label, phantom: PhantomData }
}
pub fn hash_len(&self) -> usize {
self.hash.clone().fixed_result().as_slice().len()
H::default().fixed_result().as_slice().len()
}
pub fn hash(&self, input: &[u8]) -> Vec<u8> {
let mut digest = self.hash.clone();
digest.process(input);
digest.fixed_result().as_slice().to_vec()
H::digest(input).as_slice().to_vec()
}
pub fn mgf1(&self, input: &[u8], len: usize) -> Vec<u8> {
let mut res = Vec::with_capacity(len);
let mut counter = UCN::from(0u64);
let one = UCN::from(1u64);
let mut counter = 0u32;
while res.len() < len {
let c = counter.to_bytes(4);
let mut digest = self.hash.clone();
digest.process(input);
digest.process(&c);
let mut buffer = [0; 4];
BigEndian::write_u32(&mut buffer, counter);
let mut digest = H::default();
digest.input(input);
digest.input(&buffer);
let chunk = digest.fixed_result();
res.extend_from_slice(chunk.as_slice());
counter = counter + &one;
counter = counter + 1;
}
res.truncate(len);

View File

@@ -1,149 +1,274 @@
use cryptonum::{BarrettUCN,UCN};
use digest::{FixedOutput,Input};
use rsa::core::{ACCEPTABLE_KEY_SIZES,dp,pkcs1_pad,sp1,xor_vecs};
use cryptonum::unsigned::*;
use digest::{Digest,FixedOutput};
use rsa::core::{drop0s,pkcs1_pad,xor_vecs};
use rsa::errors::RSAError;
use rsa::oaep::OAEPParams;
use rsa::signing_hashes::SigningHash;
use std::fmt;
#[derive(Clone)]
pub struct RSAPrivate {
pub(crate) byte_len: usize,
pub(crate) n: UCN,
pub(crate) nu: BarrettUCN,
pub(crate) d: UCN
pub trait RSAPrivateKey<N> {
/// Generate a new private key using the given modulus and private
/// exponent. You probably don't want to use this function directly
/// unless you're writing your own key generation routine or key
/// parsing library.
fn new(n: N, d: N) -> Self;
/// Sign the given message with the given private key.
fn sign(&self, signhash: &SigningHash, msg: &[u8]) -> Vec<u8>;
/// Decrypt the provided message using the given OAEP parameters. As
/// mentioned in the comment for encryption, RSA decryption is really,
/// really slow. So if your plaintext is larger than about half the
/// bit size of the key, it's almost certainly a better idea to generate
/// a fresh symmetric encryption key, encrypt only the key with RSA, and
/// then encrypt the message with that key.
fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where H: Default + Digest + FixedOutput;
}
#[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()
}
pub enum RSAPrivate {
Key512(RSA512Private),
Key1024(RSA1024Private),
Key2048(RSA2048Private),
Key3072(RSA3072Private),
Key4096(RSA4096Private),
Key8192(RSA8192Private),
Key15360(RSA15360Private)
}
#[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)
}
}
macro_rules! generate_rsa_private
{
($rsa: ident, $num: ident, $bar: ident, $size: expr) => {
pub struct $rsa {
pub(crate) nu: $bar,
pub(crate) d: $num
}
#[cfg(test)]
impl Eq for RSAPrivate {}
impl RSAPrivateKey<$num> for $rsa {
fn new(n: $num, d: $num) -> $rsa {
let nu = $bar::new(n.clone());
$rsa { nu: nu, d: d }
}
#[cfg(not(test))]
impl fmt::Debug for RSAPrivate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("RSAPrivateKey<PRIVATE>")
}
}
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();
sig
}
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();
fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where H: Default + Digest + FixedOutput
{
let mut res = Vec::new();
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()
};
for chunk in msg.chunks($size/8) {
let mut dchunk = self.oaep_decrypt(oaep, chunk)?;
res.append(&mut dchunk);
}
Ok(res)
}
}
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
}
impl $rsa {
fn sp1(&self, m: &$num) -> $num {
m.modexp(&self.d, &self.nu)
}
/// 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();
fn dp(&self, c: &$num) -> $num {
c.modexp(&self.d, &self.nu)
}
for chunk in msg.chunks(self.byte_len) {
let mut dchunk = self.oaep_decrypt(oaep, chunk)?;
res.append(&mut dchunk);
}
fn oaep_decrypt<H>(&self, oaep: &OAEPParams<H>, c: &[u8])
-> Result<Vec<u8>,RSAError>
where
H: Default + Digest + FixedOutput
{
let byte_len = $size / 8;
// Step 1b
if c.len() != byte_len {
return Err(RSAError::DecryptionError);
}
// Step 1c
if byte_len < ((2 * oaep.hash_len()) + 2) {
return Err(RSAError::DecryptHashMismatch);
}
// Step 2a
let c_ip = $num::from_bytes(&c);
// Step 2b
let m_ip = self.dp(&c_ip);
// Step 2c
let em = m_ip.to_bytes();
// Step 3a
let l_hash = oaep.hash(oaep.label.as_bytes());
// Step 3b
let (y, rest) = em.split_at(1);
let (masked_seed, masked_db) = rest.split_at(oaep.hash_len());
// Step 3c
let seed_mask = oaep.mgf1(masked_db, oaep.hash_len());
// 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);
// Step 3f
let db = xor_vecs(&masked_db.to_vec(), &db_mask);
// Step 3g
let (l_hash2, ps_o_m) = db.split_at(oaep.hash_len());
let o_m = drop0s(ps_o_m);
let (o, m) = o_m.split_at(1);
// Checks!
if o != [1] {
return Err(RSAError::DecryptionError);
}
if l_hash != l_hash2 {
return Err(RSAError::DecryptionError);
}
if y != [0] {
return Err(RSAError::DecryptionError);
}
Ok(res)
}
fn oaep_decrypt<H: Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, c: &[u8])
-> Result<Vec<u8>,RSAError>
{
// Step 1b
if c.len() != self.byte_len {
return Err(RSAError::DecryptionError);
Ok(m.to_vec())
}
}
// Step 1c
if self.byte_len < ((2 * oaep.hash_len()) + 2) {
return Err(RSAError::DecryptHashMismatch);
}
// Step 2a
let c_ip = UCN::from_bytes(&c.to_vec());
// Step 2b
let m_ip = dp(&self.nu, &self.d, &c_ip);
// Step 2c
let em = &m_ip.to_bytes(self.byte_len);
// Step 3a
let l_hash = oaep.hash(oaep.label.as_bytes());
// Step 3b
let (y, rest) = em.split_at(1);
let (masked_seed, masked_db) = rest.split_at(oaep.hash_len());
// Step 3c
let seed_mask = oaep.mgf1(masked_db, oaep.hash_len());
// Step 3d
let seed = xor_vecs(&masked_seed.to_vec(), &seed_mask);
// Step 3e
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
let (l_hash2, ps_o_m) = db.split_at(oaep.hash_len());
let o_m = drop0s(ps_o_m);
let (o, m) = o_m.split_at(1);
// Checks!
if o != [1] {
return Err(RSAError::DecryptionError);
}
if l_hash != l_hash2 {
return Err(RSAError::DecryptionError);
}
if y != [0] {
return Err(RSAError::DecryptionError);
}
Ok(m.to_vec())
}
}
fn drop0s(a: &[u8]) -> &[u8] {
let mut idx = 0;
generate_rsa_private!(RSA512Private, U512, BarrettU512, 512);
generate_rsa_private!(RSA1024Private, U1024, BarrettU1024, 1024);
generate_rsa_private!(RSA2048Private, U2048, BarrettU2048, 2048);
generate_rsa_private!(RSA3072Private, U3072, BarrettU3072, 3072);
generate_rsa_private!(RSA4096Private, U4096, BarrettU4096, 4096);
generate_rsa_private!(RSA8192Private, U8192, BarrettU8192, 8192);
generate_rsa_private!(RSA15360Private, U15360, BarrettU15360, 15360);
while (idx < a.len()) && (a[idx] == 0) {
idx = idx + 1;
}
#[cfg(test)]
macro_rules! sign_test_body {
($mod: ident, $rsa: 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();
&a[idx..]
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 = $rsa{ nu: $bar::from_components(k, n.clone(), nu), d: d };
let sig = privkey.sign(sighash, &mbytes);
assert_eq!(*sbytes, sig);
});
};
}
#[cfg(test)]
macro_rules! decrypt_test_body {
($mod: ident, $rsa: 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 = $rsa{ 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, $rsa: 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 sha2::{Sha224,Sha256,Sha384,Sha512};
#[test]
fn sign() {
sign_test_body!($mod, $rsa, $num, $bar, $num64, $size);
}
#[test]
fn decrypt() {
decrypt_test_body!($mod, $rsa, $num, $bar, $num64, $size);
}
}
};
(ignore $mod: ident, $rsa: 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 sha2::{Sha224,Sha256,Sha384,Sha512};
#[ignore]
#[test]
fn sign() {
sign_test_body!($mod, $rsa, $num, $bar, $num64, $size);
}
#[ignore]
#[test]
fn decrypt() {
decrypt_test_body!($mod, $rsa, $num, $bar, $num64, $size);
}
}
}
}
generate_tests!(RSA512, RSA512Private, U512, BarrettU512, U576, 512);
generate_tests!(RSA1024, RSA1024Private, U1024, BarrettU1024, U1088, 1024);
generate_tests!(RSA2048, RSA2048Private, U2048, BarrettU2048, U2112, 2048);
generate_tests!(RSA3072, RSA3072Private, U3072, BarrettU3072, U3136, 3072);
generate_tests!(RSA4096, RSA4096Private, U4096, BarrettU4096, U4160, 4096);
generate_tests!(ignore RSA8192, RSA8192Private, U8192, BarrettU8192, U8256, 8192);
generate_tests!(ignore RSA15360, RSA15360Private, U15360, BarrettU15360, U15424, 15360);

View File

@@ -1,124 +1,520 @@
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 cryptonum::unsigned::*;
use digest::{Digest,FixedOutput};
use rand::Rng;
use rand::rngs::OsRng;
use rsa::core::{decode_biguint,pkcs1_pad,xor_vecs};
use rsa::errors::RSAError;
use rsa::oaep::OAEPParams;
use rsa::signing_hashes::SigningHash;
use simple_asn1::{ASN1Block,ASN1DecodeErr,ASN1EncodeErr,
ASN1Class,FromASN1,ToASN1};
#[cfg(test)]
use std::fmt;
use utils::TranslateNums;
#[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
pub trait RSAPublicKey<N> {
/// 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.
fn new(n: N, e: N) -> Self;
/// 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.
fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool;
/// 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.
///
/// 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.
fn encrypt_rng<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where
G: Rng,
H: Default + Digest + FixedOutput;
/// 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.
fn encrypt<H>(&self,oaep:&OAEPParams<H>,msg:&[u8])
-> Result<Vec<u8>,RSAError>
where
H: Default + Digest + FixedOutput
{
let mut g = OsRng::new()?;
self.encrypt_rng(&mut g, oaep, msg)
}
}
pub enum RSAPublic {
Key512(RSA512Public),
Key1024(RSA1024Public),
Key2048(RSA2048Public),
Key3072(RSA3072Public),
Key4096(RSA4096Public),
Key8192(RSA8192Public),
Key15360(RSA15360Public)
}
impl RSAPublic {
/// 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()")
}
/// 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_)
}
/// Encrypt the given data with the public key and parameters, returning
/// the encrypted blob or an error encountered during encryption.
///
/// 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>
pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool
{
let mut g = OsRng::new()?;
self.encrypt_with_rng(&mut g, oaep, msg)
}
/// 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);
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)
}
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)
}
Ok(res)
}
fn oaep_encrypt<G: Rng,H:Clone + Input + FixedOutput>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
{
// Step 1b
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 = self.byte_len - msg.len() - (2 * oaep.hash_len()) - 2;
let mut ps = Vec::new();
ps.resize(num0s, 0);
// Step 2c
let mut db = Vec::new();
db.append(&mut lhash);
db.append(&mut ps);
db.push(1);
db.extend_from_slice(msg);
// Step 2d
let seed : Vec<u8> = g.gen_iter().take(oaep.hash_len()).collect();
// Step 2e
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
let seed_mask = oaep.mgf1(&masked_db, oaep.hash_len());
// Step 2h
let mut masked_seed = xor_vecs(&seed, &seed_mask);
// Step 2i
let mut em = Vec::new();
em.push(0);
em.append(&mut masked_seed);
em.append(&mut masked_db);
// Step 3a
let m_i = UCN::from_bytes(&em);
// Step 3b
let c_i = ep(&self.nu, &self.e, &m_i);
// Step 3c
let c = c_i.to_bytes(self.byte_len);
Ok(c)
}
}
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 = RSA512Public::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 = RSA1024Public::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 = RSA2048Public::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 = RSA3072Public::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 = RSA4096Public::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 = RSA8192Public::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 = RSA15360Public::new(n2, e2);
Ok((RSAPublic::Key15360(res), rest))
}
_ =>
Err(RSAError::InvalidKey)
}
}
Some(_) =>
Err(RSAError::InvalidKey)
}
}
}
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)
}
}
}
macro_rules! generate_rsa_public
{
($rsa: ident, $num: ident, $bar: ident, $var: ident, $size: expr) => {
#[derive(PartialEq)]
pub struct $rsa {
pub(crate) n: $num,
pub(crate) nu: $bar,
pub(crate) e: $num
}
impl RSAPublicKey<$num> for $rsa {
fn new(n: $num, e: $num) -> $rsa {
let nu = $bar::new(n.clone());
$rsa { n: n, nu: nu, e: e }
}
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_
}
fn encrypt_rng<G,H>(&self,g: &mut G,oaep: &OAEPParams<H>,msg: &[u8])
-> Result<Vec<u8>,RSAError>
where
G: Rng,
H: Default + Digest + FixedOutput
{
let byte_len = $size / 8;
let mut res = Vec::new();
if 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 newchunk = self.oaep_encrypt(g, oaep, chunk)?;
res.append(&mut newchunk);
}
Ok(res)
}
}
impl $rsa {
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: Default + Digest + FixedOutput
{
let byte_len = $size / 8;
// Step 1b
if m.len() > (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 mut ps = Vec::new();
ps.resize(num0s, 0);
// Step 2c
let mut db = Vec::new();
db.append(&mut lhash);
db.append(&mut ps);
db.push(1);
db.extend_from_slice(m);
// 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());
// Step 2e
let db_mask = oaep.mgf1(&seed, byte_len - oaep.hash_len() - 1);
// Step 2f
let mut masked_db = xor_vecs(&db, &db_mask);
// Step 2g
let seed_mask = oaep.mgf1(&masked_db, oaep.hash_len());
// Step 2h
let mut masked_seed = xor_vecs(&seed, &seed_mask);
// Step 2i
let mut em = Vec::new();
em.push(0);
em.append(&mut masked_seed);
em.append(&mut masked_db);
// Step 3a
let m_i = $num::from_bytes(&em);
// Step 3b
let c_i = self.ep(&m_i);
// Step 3c
let c = c_i.to_bytes();
Ok(c)
}
}
impl FromASN1 for $rsa {
type Error = RSAError;
fn from_asn1(bs: &[ASN1Block])
-> Result<($rsa,&[ASN1Block]),RSAError>
{
let (core, rest) = RSAPublic::from_asn1(bs)?;
match core {
RSAPublic::$var(x) => Ok((x, rest)),
_ => Err(RSAError::InvalidKey)
}
}
}
impl ToASN1 for $rsa {
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 $rsa {
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!(RSA512Public, U512, BarrettU512, Key512, 512);
generate_rsa_public!(RSA1024Public, U1024, BarrettU1024, Key1024, 1024);
generate_rsa_public!(RSA2048Public, U2048, BarrettU2048, Key2048, 2048);
generate_rsa_public!(RSA3072Public, U3072, BarrettU3072, Key3072, 3072);
generate_rsa_public!(RSA4096Public, U4096, BarrettU4096, Key4096, 4096);
generate_rsa_public!(RSA8192Public, U8192, BarrettU8192, Key8192, 8192);
generate_rsa_public!(RSA15360Public, U15360, BarrettU15360, Key15360, 15360);
#[cfg(test)]
macro_rules! new_test_body {
($mod: ident, $rsa: ident, $priv: 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 = $rsa::new(n.clone(), e.clone());
let pubkey1 = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
assert_eq!(pubkey1, pubkey2);
});
};
}
#[cfg(test)]
macro_rules! encode_test_body {
($mod: ident, $rsa: ident, $priv: 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 = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
let asn1 = pubkey.to_asn1().unwrap();
let (pubkey2, _) = $rsa::from_asn1(&asn1).unwrap();
assert_eq!(pubkey, pubkey2);
});
};
}
#[cfg(test)]
macro_rules! verify_test_body {
($mod: ident, $rsa: ident, $priv: 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 = $rsa{ 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, $rsa: ident, $priv: 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 = $rsa{ n: n.clone(), nu: nu.clone(), e: e };
let privkey = $priv{ 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, $rsa: ident, $priv: 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 sha2::{Sha224,Sha256,Sha384,Sha512};
#[test]
fn new() { new_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
#[test]
fn encode() { encode_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
#[test]
fn verify() { verify_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
#[test]
fn encrypt() { encrypt_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
}
};
(ignore $mod: ident, $rsa: ident, $priv: 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 sha2::{Sha224,Sha256,Sha384,Sha512};
#[ignore]
#[test]
fn new() { new_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
#[ignore]
#[test]
fn encode() { encode_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
#[ignore]
#[test]
fn verify() { verify_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
#[ignore]
#[test]
fn encrypt() { encrypt_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); }
}
};
}
generate_tests!(RSA512, RSA512Public, RSA512Private, U512, BarrettU512, U576, 512);
generate_tests!(RSA1024, RSA1024Public, RSA1024Private, U1024, BarrettU1024, U1088, 1024);
generate_tests!(RSA2048, RSA2048Public, RSA2048Private, U2048, BarrettU2048, U2112, 2048);
generate_tests!(RSA3072, RSA3072Public, RSA3072Private, U3072, BarrettU3072, U3136, 3072);
generate_tests!(RSA4096, RSA4096Public, RSA4096Private, U4096, BarrettU4096, U4160, 4096);
generate_tests!(ignore RSA8192, RSA8192Public, RSA8192Private, U8192, BarrettU8192, U8256, 8192);
generate_tests!(ignore RSA15360, RSA15360Public, RSA15360Private, U15360, BarrettU15360, U15424, 15360);

View File

@@ -1,4 +1,4 @@
use digest::{FixedOutput,Input};
use digest::Digest;
use sha1::Sha1;
use sha2::{Sha224,Sha256,Sha384,Sha512};
use std::fmt;
@@ -46,9 +46,7 @@ pub static SIGNING_HASH_SHA1: SigningHash = SigningHash {
};
fn runsha1(i: &[u8]) -> Vec<u8> {
let mut d = Sha1::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
Sha1::digest(i).as_slice().to_vec()
}
/// Sign a hash based on SHA2-224. This is the first reasonable choice
@@ -63,9 +61,7 @@ pub static SIGNING_HASH_SHA224: SigningHash = SigningHash {
};
fn runsha224(i: &[u8]) -> Vec<u8> {
let mut d = Sha224::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
Sha224::digest(i).as_slice().to_vec()
}
/// Sign a hash based on SHA2-256. The first one I'd recommend!
@@ -78,9 +74,7 @@ pub static SIGNING_HASH_SHA256: SigningHash = SigningHash {
};
fn runsha256(i: &[u8]) -> Vec<u8> {
let mut d = Sha256::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
Sha256::digest(i).as_slice().to_vec()
}
/// Sign a hash based on SHA2-384. Approximately 50% better than
@@ -94,9 +88,7 @@ pub static SIGNING_HASH_SHA384: SigningHash = SigningHash {
};
fn runsha384(i: &[u8]) -> Vec<u8> {
let mut d = Sha384::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
Sha384::digest(i).as_slice().to_vec()
}
/// Sign a hash based on SHA2-512. At this point, you're getting a bit
@@ -111,9 +103,7 @@ pub static SIGNING_HASH_SHA512: SigningHash = SigningHash {
};
fn runsha512(i: &[u8]) -> Vec<u8> {
let mut d = Sha512::default();
d.process(i);
d.fixed_result().as_slice().to_vec()
Sha512::digest(i).as_slice().to_vec()
}

View File

@@ -1,9 +1,13 @@
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());
@@ -11,7 +15,7 @@ fn next_value_set(line: &str) -> (String, bool, Vec<u8>)
let key = items.next().unwrap();
let valbits = items.next().unwrap();
let neg = valbits.contains('-');
let valbitsnoneg = valbits.trim_left_matches("-");
let valbitsnoneg = valbits.trim_start_matches("-");
let mut nibble_iter = valbitsnoneg.chars().rev();
let mut val = Vec::new();
@@ -49,32 +53,7 @@ fn next_test_case(contents: &mut Lines, lines: usize) ->
Some(res)
}
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)
pub fn run_test<F>(fname: String, i: usize, f: F)
where F: Fn(HashMap<String,(bool,Vec<u8>)>)
{
let mut file = File::open(fname).unwrap();

57
src/utils.rs Normal file
View File

@@ -0,0 +1,57 @@
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);

377
src/x509/algident.rs Normal file
View File

@@ -0,0 +1,377 @@
use num::BigUint;
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
use x509::error::X509ParseError;
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum HashAlgorithm { SHA1, SHA224, SHA256, SHA384, SHA512 }
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum PublicKeyInfo { RSA, DSA, ECDSA }
#[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
}
}
}
}
}
}

368
src/x509/atv.rs Normal file
View File

@@ -0,0 +1,368 @@
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
use std::ops::Index;
use x509::error::X509ParseError;
use x509::name::X520Name;
#[derive(Clone,Debug)]
pub struct InfoBlock {
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])
}
}
#[derive(Clone,Debug,PartialEq)]
struct AttributeTypeValue {
attrtype: X520Name,
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
}
}
}
}
}

53
src/x509/error.rs Normal file
View File

@@ -0,0 +1,53 @@
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)
}
}

195
src/x509/misc.rs Normal file
View File

@@ -0,0 +1,195 @@
use num::{BigInt,BigUint,One,ToPrimitive,Zero};
use num::bigint::ToBigInt;
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
use x509::error::X509ParseError;
#[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))
}
}
/******************************************************************************/
#[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
}
}
}
}
}

293
src/x509/mod.rs Normal file
View File

@@ -0,0 +1,293 @@
mod algident;
mod atv;
mod error;
mod misc;
mod name;
mod publickey;
mod validity;
use dsa::{DSAPublic,DSAPublicKey};
use ecdsa::{ECDSAPublic,ECCPublicKey};
use rsa::{SIGNING_HASH_SHA1,SIGNING_HASH_SHA224,SIGNING_HASH_SHA256,SIGNING_HASH_SHA384,SIGNING_HASH_SHA512};
use sha1::Sha1;
use sha2::{Sha224,Sha256,Sha384,Sha512};
use simple_asn1::{ASN1Block,FromASN1,der_decode,from_der};
use x509::validity::Validity;
use x509::algident::{AlgorithmIdentifier,HashAlgorithm,PublicKeyInfo,
decode_algorithm_ident};
use x509::atv::InfoBlock;
use x509::error::X509ParseError;
use x509::misc::{X509Serial,X509Version,decode_signature};
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
*
******************************************************************************/
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::ECCPublicP192(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::ECCPublicP224(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::ECCPublicP256(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::ECCPublicP384(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::ECCPublicP521(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());
}
}

136
src/x509/name.rs Normal file
View File

@@ -0,0 +1,136 @@
use num::BigUint;
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
use x509::error::X509ParseError;
#[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);
}
}

328
src/x509/publickey.rs Normal file
View File

@@ -0,0 +1,328 @@
use cryptonum::unsigned::{U3072,U2048,U1024,U256,U192};
use dsa::{DSAPublic,DSAPublicKey,DSAPubKey,DSAParameters};
use dsa::{L3072N256,L2048N256,L2048N224,L1024N160};
use ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPubKey};
use ecdsa::curve::{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;
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 = DSAPubKey::<L3072N256,U3072>::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 = DSAPubKey::<L2048N256,U2048>::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 = DSAPubKey::<L2048N224,U2048>::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 = DSAPubKey::<L1024N160,U1024>::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::ECCPublicP192(k) => (oid!(1,2,840,10045,3,1,1), k.to_asn1_class(c)?),
ECDSAPublic::ECCPublicP224(k) => (oid!(1,3,132,0,33), k.to_asn1_class(c)?),
ECDSAPublic::ECCPublicP256(k) => (oid!(1,2,840,10045,3,1,7), k.to_asn1_class(c)?),
ECDSAPublic::ECCPublicP384(k) => (oid!(1,3,132,0,34), k.to_asn1_class(c)?),
ECDSAPublic::ECCPublicP521(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, _) = ECCPubKey::<P192>::from_asn1(keybls)?;
return Ok(ECDSAPublic::ECCPublicP192(res));
}
if oid == oid!(1,3,132,0,33) {
let (res, _) = ECCPubKey::<P224>::from_asn1(keybls)?;
return Ok(ECDSAPublic::ECCPublicP224(res));
}
if oid == oid!(1,2,840,10045,3,1,7) {
let (res, _) = ECCPubKey::<P256>::from_asn1(keybls)?;
return Ok(ECDSAPublic::ECCPublicP256(res));
}
if oid == oid!(1,3,132,0,34) {
let (res, _) = ECCPubKey::<P384>::from_asn1(keybls)?;
return Ok(ECDSAPublic::ECCPublicP384(res));
}
if oid == oid!(1,3,132,0,35) {
let (res, _) = ECCPubKey::<P521>::from_asn1(keybls)?;
return Ok(ECDSAPublic::ECCPublicP521(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)
}
}

118
src/x509/validity.rs Normal file
View File

@@ -0,0 +1,118 @@
use chrono::{DateTime,Utc};
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
use x509::error::X509ParseError;
#[derive(Clone,Debug,PartialEq)]
pub struct Validity {
not_before: DateTime<Utc>,
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
}
}
}
}

2
test-generator/.gitignore vendored Normal file
View File

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

87
test-generator/DSA.hs Normal file
View File

@@ -0,0 +1,87 @@
{-# 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(..),Test)
import Utils(HashAlg(..),generateHash,showHash)
import Debug.Trace
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 = go,
taskCount = cnt
}
where
go :: Test
go (memory, drg0) =
case generateProbablePrimes sz drg0 sha256 Nothing of
Left _ -> trace "generate primes" $ goAdvance memory drg0
Right (p, q, _, drg1) ->
case generateUnverifiableGenerator p q of
Nothing -> trace "generate g" $ goAdvance memory drg1
Just g ->
let params = Params p g q
in case generateKeyPairWithParams params drg1 of
Left _ -> trace "generate key" $ 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 _ ->
trace "sign failure" $ 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

@@ -0,0 +1,50 @@
{-# 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

@@ -0,0 +1,193 @@
{-# 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(..))
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 = go,
taskCount = 1000
}
where
go (memory0, drg) =
let (scalar, drg') = withDRG drg (scalarGenerate curve)
point = pointBaseMul curve scalar
dbl = pointNegate curve point
in case (point, dbl) of
(PointO, _) -> go (memory0, drg')
(_, PointO) -> go (memory0, drg')
(Point basex basey, Point dblx dbly) ->
let res = Map.fromList [("x", showX basex), ("y", showX basey),
("a", showX dblx), ("b", showX dbly)]
in (res, scalar, (memory0, drg'))
doubleTest :: String -> Curve -> Task
doubleTest name curve = Task {
taskName = name ++ " point doubling",
taskFile = "../testdata/ecc/double/" ++ name ++ ".test",
taskTest = go,
taskCount = 1000
}
where
go (memory0, drg) =
let (scalar, drg') = withDRG drg (scalarGenerate curve)
point = pointBaseMul curve scalar
dbl = pointDouble curve point
in case (point, dbl) of
(PointO, _) -> go (memory0, drg')
(_, PointO) -> go (memory0, drg')
(Point basex basey, Point dblx dbly) ->
let res = Map.fromList [("x", showX basex), ("y", showX basey),
("a", showX dblx), ("b", showX dbly)]
in (res, scalar, (memory0, drg'))
addTest :: String -> Curve -> Task
addTest name curve = Task {
taskName = name ++ " point addition",
taskFile = "../testdata/ecc/add/" ++ name ++ ".test",
taskTest = go,
taskCount = 1000
}
where
go (memory0, drg0) =
let (scalar1, drg1) = withDRG drg0 (scalarGenerate curve)
(scalar2, drg2) = withDRG drg1 (scalarGenerate curve)
point1 = pointBaseMul curve scalar1
point2 = pointBaseMul curve scalar2
pointr = pointAdd curve point1 point2
in case (point1, point2, pointr) of
(Point x1 y1, Point x2 y2, Point xr yr) ->
let res = Map.fromList [("x", showX x1), ("y", showX y1),
("u", showX x2), ("v", showX y2),
("a", showX xr), ("b", showX yr)]
in (res, scalar1, (memory0, drg2))
_ ->
go (memory0, drg2)
scaleTest :: String -> Curve -> Task
scaleTest name curve = Task {
taskName = name ++ " point scaling",
taskFile = "../testdata/ecc/scale/" ++ name ++ ".test",
taskTest = go,
taskCount = 1000
}
where
go (memory0, drg0) =
let (scalar0, drg1) = withDRG drg0 (scalarGenerate curve)
(scalar1, drg2) = withDRG drg1 (scalarGenerate curve)
(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 = 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 = 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

43
test-generator/Main.hs Normal file
View File

@@ -0,0 +1,43 @@
{-# 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 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)
replicateM_ executors (spawnExecutor tasks done)
replicateM_ executors (void $ readChan done)

166
test-generator/Math.hs Normal file
View File

@@ -0,0 +1,166 @@
{-# 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'''

113
test-generator/RFC6979.hs Normal file
View File

@@ -0,0 +1,113 @@
{-# 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(..))
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 = 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]

126
test-generator/RSA.hs Normal file
View File

@@ -0,0 +1,126 @@
{-# 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(..))
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 = 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 = 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)

51
test-generator/Task.hs Normal file
View File

@@ -0,0 +1,51 @@
{-# LANGUAGE PackageImports #-}
module Task(
Test,
Task(..),
runTask
)
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 -> (Map.Map String String, Integer, Database)
data Task = Task {
taskName :: String,
taskFile :: FilePath,
taskTest :: Test,
taskCount :: Int
}
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 let (output, key, acc@(db',gen')) = runner db
before = Map.findWithDefault [] "RESULT" db'
if length (filter (== key) before) >= 10
then writer hndl pg runner acc x
else do forM_ (Map.toList output) $ \ (outkey, val) ->
hPutStrLn hndl (outkey ++ ": " ++ val)
tick pg
return (Map.insert "RESULT" (key : before) db', gen')

35
test-generator/Utils.hs Normal file
View File

@@ -0,0 +1,35 @@
{-# 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"

34
test-generator/gcd.hs Normal file
View File

@@ -0,0 +1,34 @@
import Numeric
data Set = Set { r :: Integer, s :: Integer, t :: Integer }
step :: Set -> Set -> Set
step old new = Set r' s' t'
where
quotient = r old `div` r new
r' = r old - (r new * quotient)
s' = s old - (s new * quotient)
t' = t old - (t new * quotient)
run :: Integer -> Integer -> IO Set
run self rhs = go (Set self 1 0) (Set rhs 0 1)
where
go old new | r new == 0 =
do putStrLn "------------------------------"
putStrLn ("res_r: " ++ showX (r old))
putStrLn ("res_s: " ++ showX (s old))
putStrLn ("res_t: " ++ showX (t old))
return old
| otherwise =
do putStrLn "------------------------------"
putStrLn ("old_r: " ++ showX (r old))
putStrLn ("old_s: " ++ showX (s old))
putStrLn ("old_t: " ++ showX (t old))
putStrLn ("new_r: " ++ showX (r new))
putStrLn ("new_s: " ++ showX (s new))
putStrLn ("new_t: " ++ showX (t new))
go new (step old new)
showX :: Integer -> String
showX x | x < 0 = "-" ++ showX (abs x)
| otherwise = showHex x ""

View File

@@ -0,0 +1,28 @@
cabal-version: >=1.10
-- Initial package description 'test-generator.cabal' generated by 'cabal
-- init'. For further documentation, see
-- http://haskell.org/cabal/users-guide/
name: test-generator
version: 0.1.0.0
synopsis: Test generation helper
-- description:
homepage: http://github.com/acw
-- bug-reports:
license: ISC
license-file: ../LICENSE
author: Adam Wick
maintainer: awick@uhsure.com
-- copyright:
category: Testing
build-type: Simple
extra-source-files: CHANGELOG.md
executable gen-tests
main-is: Main.hs
other-modules: Database, DSA, ECDSATesting, 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: .
default-language: Haskell2010
ghc-options: -Wall -O2 -threaded -rtsopts -with-rtsopts=-N

3609
testdata/dsa/signL1024N160.test vendored Normal file

File diff suppressed because it is too large Load Diff

909
testdata/dsa/signL2048N224.test vendored Normal file
View File

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

459
testdata/dsa/signL2048N256.test vendored Normal file
View File

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

234
testdata/dsa/signL3072N256.test vendored Normal file
View File

@@ -0,0 +1,234 @@
g: 49e6930d809a1bee01a02f9610d983d22fd44c0b1f6a2493d801c2bd1dbb604a0e962c4716e102f9acbe0ad7e23a051b9fdb60126574e62c287b35d4531500ca3b7e29797abcf2ab583f7fbf934f3f8fcf0e908910de4932cec237384629ce7f088d40128d55dbe83f25491d6cfbef103ac0e129f941d278db2998f7a7bf7f9aa21abff054dfb9af5602325957c5584c46c812638f3e71820e5f7eb88bae8207fdd62498408fe300e591156a38634d64eaf6d696dd52a44ef451af1593c65788ff8105e7665f6ae68c8f2c011ea964bd839dacddd5857fbb9209c2926b275a5bb7f3be960b28f842e78a600370e957ea1ec83bb5ac2d3e9fd58fae0275f794b76ff8715e67e70c63abb53e2939945ff35e23292226993210fa3f4aa1e512dd9a9ca245a7552149e1128e99b4f30bd4f48f181ccb33169f599787e27ff31cd04d5dbdd64e0187f89b821efbe11b3d330ab420f0fd7c44fded5837eebddbc818670d686f64f99321be8942dc6ce3b12bbffad3cf52f7205c4a99e65b5bac86c14a
h: 100
m: 72c62618547db4fdcc9325ffcc1a3ce1cec5fd9142053fa19f81d0fffdc2cd8ff21dbc41a44a6e36eaef7a7457ad268ab7d1f888b479310a526bba75a82461ba1734326d043e97b7d4b22340ab592b4546e02b2ae695fa74238859d855
p: c4c30de34f5303d4dd1e318d8a3be4298f176aa8108554fe1a1a0498def92fff2ceb40ec45c0d5d1397cf24ba1aa910cdac68072a2bae7f793bb991744b84a578c9bfad192ce2fa4db813c90ebe0ad1ac44023795876b4d8969097b9b0caa81a65e404e4b5636daf204fdf63be249066fdc4bf6af7883e17e3b33d6bbe3b9f62b520d9b357afa25022da9f4f3ea3fdd5278c915a0ed2b8947acb17e98ea83990c6886de1af20a42af1503604a2c7a8fc60167d3401a3935b3a5372a885f33002c3bf280fe558f46ad133111a12f706dffdf313547bce8f9834d091216e64620099acf82c97e42f67d65afd7d68ea36bc4680a3ef6cb5c08df10de7e6d2b75c011c3684a64f93fde539e3c11789342d7a7008e0a82102e1e6f625f4501ac253b4969c1cc3ee4929ef8756c58e512a2e8de70a21fdc8443e4ca29a7a05c2ee8cce39000e9a0a7f8d84a6ec48ae2088667d9c02b89304c3e2a51886f36d70b5b0cc495a12157cc6faadbb576dbf169ed793e57a40ea017b3a8d1a2baea86834fe3b
q: 93fd71f343eb63dfec7bd52546ebe25673cbbc94524d9caed3bed7d75cf98313
r: 413a490c44d018d26ba8a917c9566be316abc904fcf354c04de6715513db477d
s: 75d30b6411c4bf3482312b9c52a52aa838f1e6d5551f92363cdb3f69d2bc66b
x: 357c61bb275e61e191abed4ddaa37c6dc4f0afb9f00db99359d05d087a9de725
y: 3b5bb87c8f72459d71e3733ccb196f718b964a7dedc34791c29578a6d6a94941325b210e1dc8b071cddd428c2097a43c9d51cb10f4f2fa216cd4c695e2dbc1865bc143a6d3bbe747aec9f7738507a7d0851d482467723fc6f04d521b5e057e254aee4a4bf557a8d036695a945ec0197ba01d2080272a58a3c67bed7ab28cbeaae836b54e39156642e07b6d4c169798a8b1cd2fcf2e2121f1a835f7a55ff3c69c9d93c4091a8ddc25b6996f8b0247e574d65f42c954e62397d9df72ac3dc42240331c398fda9b6e685ad306aca2c8f18b280c58f9eeb70c38d89a476ae143d759b40f0c07cefed451d9e417c6a37fa5e0dfb7e549e5191cac63142de9a292cf753c7b400049fc8b0990b4d8b242bb6584966f1b34b543df6f2699354826a959d6a6e9cb02b7d402a71a17c178215175c2e426bb3c563848a6d35059cb077151c83d144886fe790c524fc95a670578712fb0a3d36b6d6310a7cc7d260b6cf520b15af3bd94222b0fa08fc8e1921cab8a2754e83dcc303578c187361eb1dc7588b8
g: 5aa403d7788597ea2bbe63a17d69c6ed0a9a9a571a4df72244abb9002c7a3f7bb0afe5a14f3281b639ed331cac11048d60a4d4117a015e21d2a3fcc5d2c0570499527fc3ef1bf9790639d55a17d31bfdebd6075b09154fe64e5928c68b3aba6ee10599dc45985016b77ce00c0a3248e0d57293dde97c03838de71c7971e8642c94913b16ff51096c24553b8da426d969d8c8fc2d99845b1952b406e46b19cf411fb558f8ac25d357d913c9e828e497a07e074f11f6a1860443edee7349c7a6417298b03b859e207367566ad49f40f0f0b4e4b5791061da9c28ad6765ca55454f2db058e0ce98ed5bb3e539b1bdea7a57c19d72e5e752770dce049483da079563b3aec0a75424e641bab2ba2deda8f86ceecb1ec26e962917c6e1461592af99707cea6c46395b2d110508acbd3d39f9e386e5f374d672670ab50815574ffe6d5c20c5f08c7f7955664d603b08165f58e817448945d1014a177d4058c33c368583f8c82c55197ce1f5e9e9c8640d86caa97c1de73fdabae3f9f9f1be2613f2c0d4
h: 100
m: 5e710084410ddd74c90d018900f7001dc3f103da35a239416fef6d607b10509bd623e58d86cc96e72d6279f817a839d888dbfe8fd012d6292f
p: c7bc869fd2c584ffd7c8c93e6072f4dd2e32ea2bbad9e99608c510f2a9956bcd61d418b9a37e9388af66d2f5780d328ee301fb4361856c7ac6aad1d1b8baef0c8c113ea7dfc0f52a079d874419b5226a55dc7509cb0e66f02efb503d6eb43cde8610783b564ba1ad1306c8c96d6c2f40fd8ed10298fbb5531920c3394921d8ac3f5576f0403e1f59ebdf074c3fbd4f3b730e246b55577e97ea705e5a39327688609694f35f0af79a2542462cd1ae4c02319c31b264b1d2f7b00271f4b246266a532adb513bcf18f21bea3a48365791fff11c9d50d00e2c1fc91a7e084a4e7725c0b2cecc01c2c56b9a438fd81629b6cea9d799072e5cdc6d76d69a5949f6495d6dd5d2d2ace98cba2b369f495a4005eb892890eb8e0a7883e031e7991fe9217a9364bd8a1e9563236e3f9e3acbc1683e9cc882ad9082893a1ab84ed618ca0caec00df0143e8aacf9b8a15ee1daff8b2861e4693fe24a996ed02260a229cd9f840b404f9b733bfcbf39d9d5eda6b853401d8b6d9f445766355a6a166fef281f5b
q: bff801fbd536e6a98417b4ddc95475b057c130ef429746e699314195a8149c4f
r: 17a1e5fa55e4cec816f26f373670dffb595ae3ec1aed98577a57adc141af68df
s: 7bef6a5af8cadeacdb1cadc04f5d14a385c842a4e68c42690da492ff90e72b8e
x: 797b3494b2ecaa3c50e73e6277c4d210161c8c412c33e10f3fd9e40bbca75d26
y: 9411c4322f0ef3ad8749137dbba75a2a61039a5505fd5dc6e48269a986ef5eb9bef783e2e1371ae047f69cef854e828bfef4065d80bd8d4059ee312d33538261131e9f2fd74efb4ebfd0039113b1464c45278708010f015a56debd171e39c0abfa0851b54e7ae3597d43efbd755a0ada48b5afe8b5a58077573bbd8c2ee534844f167df810d7111268bbe57d2fc8ce3b095e41a45893401f1388eba9601e444f503647ca2194335b6ce4db4fd49d5b09c89529ae46d793882934d22cd20704be20f725a87a3ef485fb8b07cfc8bd2c637353e71a6d1d76c69098bc0f1152c2bcb9e47466dba385e8c0ed4eaadd5fa2452897c172f3a9f5d4b298bfc1836ec2bf609dae39b8a60f4f143c1497575038b21674fe86ab1b253fbe689a180d7d78dc941a503af4d404f4dd6aca90854e9c801f848dfedddd480edbaf1c0436dafd1b54cff84f68e7667afcc24235d39e2cf27aea758d068a80ae95946e148f9fa2e4d5cfe32a6caa918bf102a2f87614194aba7d305bdbf5ed3bb8753b5e76cf37de
g: a04c7eaffe0785ea3d39a553a2f3b587a3621bab9d57e0851f80e6e1856861f0d52ce801a4fb74f0c70719914e74298c49ca782182c5e692b5b834b01f6f478acb9e82f9fb0d4e484a030516bde61b472f766be8e7ee3dd9116c151a5340714b0cec3a5ee97b35d291aca3e0dad582cb76921053205d318537360b12d4724f934ac150003d0868b5729604974dbed08cbb3353641211f36a6f4c060d304fc670180cd15e951516b117d7a2848da41650cd66e59086a2351c0ad91f3c815c240d212ad06beb57a36299781096fa8e39186aaa6402b35a380c14f2bf6cfc2ddd78be2ca2d1dd727c14252d58c7085c412dd3596859b8c57ad1788913c3371618c12bee8e2c7c4694bb930fcec749470ce260530d701c42ff662727709f16efd4571f998e05f587ed757784ac5e3a87d631d08d853a317d5fb5a095b1c71cb998ea5dee72de0776d17c34168b3e3771ef9b8d6314f8a5fcdf77d50dafb7293dbbcc5c9bd538b2d1052f2b6182232b245a21f0d4d36b476887621d8d2f95899c3988
h: 100
m: 8ace8c6ec04b9a1f02de5843fe58329584c841686e7909ed153ce78f3f9ba2ae60e7a5efa84d6c111c7c68bf12910e
p: cb8384ca68625ddfa6eb56f82c546e784a6b7e67138b99822205925b5e293df684ba9f8d81eb9e9fe6a08018a035408265824bb0c685fbe688c0a16ae8017e07245defb51652ee9e80ffdf847fde3b4b8cfaf6df253ab6dfec187ac616c459fcc3bd53f0b88f2a37acc8b32fe9f5efbd6de0a866d261315bec005431fc6d94c004c69c71317f4444136308d8a998d276694d7a6718aed4b345457ff92406f00359a96afc5a017c54564d0ca8a9d1d1396ea948c1af2cdf775d4cbb02ceb60379af5f90935ba3ae858d0a0ec382494fed50202b7e19350073e181874157e2df1c652c100232c5c509011a4f0aa3c1761113dad93fc051ee064573484385efb9c3011238e57907921c92201ff6588f7134beb5175fce89f7891f576a571fc4eaa244e418f858f25de8c99fb906ad6b8839d8c4beb5c3f4394fba1f35ada9c9babe6419809be6093fab0f42fb1d2d4cf82d563f7c128e90fe4bddccc6fbf94299d2ea6173badb6dd7f1ab786582b528dbd03633fc83fadfe3874b2ea597b67bfdb3
q: 8a17ccf94b115396dbdd6183a9b08e02c89415749da720c9c09319aef45e9521
r: 6301c9bdf8ee8ffb4c8e8c86064c2b0f45797f1a9f68b0715219112e9e4667e5
s: 8532948e6e54466883a59d7792d5a7937e9f3be961947df48e7c3ec1c3ea064e
x: 3ec4747e545c0fbf8711bec311f02ab9ff2c1037799550e93a64fde643f2ce1f
y: c2f690b036cba7d9a7e930bb92b4da8daa9aa7f8325c5870b5bdfe3d1a54a446edad969c3cca59a3a09b458ef857d676cdc09b0941958ec5ea3e3e2756b2fac5a33fc01d7c42d9151f8cbe30e54f43957f895cf55c4f7d1cece263af58e5a76e4f4b89c7f15133b8dde960ba5b45d5d049386041a8fd31d321655813d09dc389ea72248b99e273d0bdab3e83bc04a71883546b86a25fdd12ea5346d2ba7577a438a1d2cbce202382e2eda65a783a9fdf374714de202fbd66ec736147e481748c9512ed91642558574d503cc40c42fd5207f4f1f50d958f05bcecf92bba7698317749f95507ccce1d4d5558907dbcab2c03ee7330fb89e0083935d0a5ca2872f383ed211c6e9c12919580edd15ae1c5213995cf0cc53242f61632f023021106ac8e683b485950e2b4e8d3a5a4c20f7af6558db7404273659bbdcd17059cbb54ba8751f2fd6138698ae8f78f6b96ecf82a833dfa29ba2ca1110809bf9dd948b294e764da465d441773c9bbbf99bd37512df4b208608a25e97dda2ebe58139d93b7
g: 92000ea70ab4041fe58717a88d93ee93fecb90fef03740de69b2bf4b320f2ff405b79b1c0d588fff1669b616b728c55711dbe484f4403784b8f8a193af4db2befbbcba0818459e6fb7f022bc233a8ddbf1f885d030d385218a3a1d670b5f52cc7afda10d74b718b3a73d3d3de129bad7647daf2b72bad3f683e4ac57c75cc25f779d615a8562564705ff03cb188119c4779e4eb3a46c9a50543fe5170084a53a659b02c7ae65397353dc34e271d345ab3fff2d3ae8a018f95a51919b0510ead4cf28c55e8c629aadba454a5363ac5f82d49da2cb0a091c5c58d24ed86da571d1f815a83036b7510046f83bad20a49382b4ba016b4742146a284e173d07f8042f911bc2e5d910e5b15b09802856809b1e0908064e794acd0f66698b97e956fe8eb874af8bb96e70eaed6388e27b9c9897fece0bf4db80d6838bc4be2e3882ff45e66e9836fa647cafa1249b81bedef8fb94fb38d78bc8cce70b00ce087c8c5dee5d1d35ebe4ba56a933b548483b9d56e83e68f55f9ba3f7fb026a442547e15116
h: 100
m: a9354c66dce761985ca6ba3c7e161ea4c01b8edfd94950a7cd7f9360e05935446dc2cdfadb43659879f4fc05173abc895cbb0c24fc01f1bd659745fd37384b2fb75d76f9879d741e25d6e4cbf178c7c9ced99f4ce8e66702b2242a8de1d96de0d4fa5bab2a87cd901c910a59c706872288ae1988eaf21e7db14c6cf3cdcefe45b8fa2df167b50ca7baa7a1fe107d8518f7add1c5683eccb8ccdbddf5ff5ed99131f5ce68313d53
p: b5fad4366a5725718b918c6612afb4964f80eb3126e868c4f37a841295b2fa4c3f7726f87f6094f55a47155d7b1d6fdbc85a20bc8fa6fef9a2563a35d1bfd144138968b472efd48e072e3160626b66597f2e05688a4cfc04f44d0b594a528ba9f5791ffeb3adeb791189db358eef8b7b521f69a9f4497cd4cedceb1d45eeee308f8bb2ed3b8ca4a3e90d8ad62cbb4ee84e2e5b0f14c262f5bc93a559feacaf6e9106929acbbd86241d45438c556f5d607ff753eb8592c94e514ddd17a84ac9f40869c05cd0a2f1e6e3eb367f1c492ce9a5e4cd4ae55345640580ce0fc05bffb8e963168de905479412d6c1eda8ac81f71f6eb9511e2b90003144d5793af2137fda67d6e8487a797450a6c149c82d9a4830c176e264649d58fa7ca3b3605040d302c5db56d4bb58f452821934bd7ce689491c86bbd61088d7da967e07f13a657748998a67fc06845940498411b494babbfd9b6b6407520082666b92f876917c407ded2528db098bd98a8f4fe56bdd2bfda2d32f699d01933b90c16965d6b1e059
q: d2ce16aebd336e053f4a481b29fd561b965c393d9f8236d7ee9f984f73cb9a8d
r: c54cecac1a88615f90097266a876532209ec4d6080f256cb49d87a2a5ffbb8d2
s: 579e099e9277fb696ae585ff22b0885c4c866696eefaa7fe1866fae338e2a0a7
x: 63eaf858c516680439dc271cf65cbe7c931960704effe05a2e03d8d4996231e0
y: 95a5f0e09cc67d063e8786f2d9f79a5fc09072d5a29137327e6c33d1f256d3ca1a79d035b7fac3f410b234df0d44700fc723d03523747b6ba0c6a790ca880bc7caa921a8d4edcf4f2004cccf80311d75dd0f0cc701819d1636423969b4d2ccb3f4106cb2ad132c55ce4f2f230b060c955466621b414dcf0f7a6b0cb40dff6b9239b87781fe67c48d422d481f13f1f875e98702bc4e97a45e34caf4a4e24a1b51b97cc73b23d0f5e20ea6d25398c52cf513d0cca9f2cfd68c492f91e8bf9611e49aa48ff79f5f566e3698b46814af329944112dfc2a8fea3c51471d93184366e8a0a192bed3ad7d5e574524f1ddc3dd749458f98065bbf354fcf8912e81fd45ac2d791d17ab9e60ed2536039e2cc00edbec444ccd7bc94f7b2251784387d88e6ba6ee1c840129772385a4a12e540f58463b87507aa44d9aa1c6cf0439cc90c32f0aa0d10c493653de7d123bfd3e7a0aea7b47fd5f62838ebdf6e7a733971337da2dbb5a96c72ee3882c88eed74e2d613eb84d7aefb414f6b0d51ad70a1bdc614c
g: 94c5e4141aa62747576d8f77dfda28549b1d32b2385c3ef674aa0704fac7d7467bb66f0c1013782268993fec56c75ae1bcdb398f602dafce94bfc7a5a9b4ea6cb78e7a6bbfa7d9c735d709daa60389d4023ad5554863ae3c034071652a029b188c9ff605a0dcf00f82b63b90dc8af111bf92555415db91dce5752f03cb36f7926ba358c99c9a32612bec0712da6050eb7a27e7dd2d50f4ec9d0b12a64668525ad8214500cc88ec10d4a5d68a7440408edfc1732c0d6fa7c107d1f5bb259f3598f562b45b780e6a3389e9a173902994ad8c5b1641b2fa30d5a1a1c53f3b82ca2786ff21f63148093a8717ff879e580d963ebb5020b6a160c9731c3387108d3bbee2a3925dc3dd9ae0fa97c3e51bca20666c0e2dfd48901298bd46c11f9f9854cb599814a9ee5865653ebd29650d9aadc1469a222bea446aef443317e13681bffe506c023e474ab0910d6bf25a75d050878d6ba1f49814fe848619eae7583a54567c3f6ba0309783d48b4d653bb45b74e28389bfa36d563efaae36a67e18117bbe
h: 180
m: 4e7ae07569250b
p: c91120e215cf1263c2ca59975fcea94f1e118b6de0abc8c988f706b277900bb42cb2d96c9bb6a9519d25f5529e20d5b360a0acde1fdcc3b33ce2492d3661c3aab81cee079dd40bdbfa0dfcf867019cd1e03ef01f51850ea19de0f667c37ea7f9cba2f6c68598a11645eb3d34a7e6a52a36b6161a375ef3b21d3cc82ab44e45e9c76511b52a9c8f97ea435a9abb8e459799cb3371f3ca7b58faa1e1668f0cc1289d63d567faff48c569e252c200b978259e06d9b8b37f9d2b21cd606c8fe48778d11044c1831c80fa678e8f608e179b3456a78b678a047b74a03ffaa171c1c165d3e9436fdfde14e505b0967e5c18974354d9b86bd81e40f571c603801fb78bffa52a86a3fa5a09d80ad19d4d9c87be1d3348a8f6ddd1b1920cc84f2b46749d21693738a6e80abc6a5cd16eda93738ef3bf57c45612765b6392b12d78685e6b4a893ff0f27ed6528d8cecec92acae2a930e4ad04b5c48e1c70948aaedc1bdcc7c2afc58d0016d7515c746a0c502573958aa1812b3161d54e3db4fdd6960faa465
q: ae4783fe9115a7aa65f1533d8411425eae2898f9c970f6721f52bb59c2ef6827
r: 222f31f6086a4a81af34dc37a373c2b603493c76996a129d49502f64cac4bf25
s: 968de9546a45c6c633fb23db37ec2290755fb97a2bcce21bd19a9d7bff744488
x: 67749c7c078a2d33b5d62d9be1c4544e265a8a33097b5db480a4508fd0d5dbe1
y: 3359b5d22ede90ca85f596419f6e75cf4f3f1a0bd80d8f65cd7721c0e2866c9ca39067d737ffbdbe9c6cd827548710aa1807321aa6a65a600b23cb5ff25b86dd8550421ad20b2602ab036264f97be5ed88c9a0a1c7755bb41ed0e7472306392806e51d8b2ba50d335a01921c38ddecaca7af7c2f3f4e44a9a83dbca4eb81495026f2ac11322e07cab76ca67f880de83c2e9f5e628e275f7b40e114034e36efa6af3461f24227d0de0e2d9fdc709aea990f274fb8823ba3dfb18a3fd3d37892c65b1df9b85834391c35a484927a02bef25c483af48cacd6addb303957816772c764dc649b8202a81a8450c8ad50a68c748a01c9884fcb47fd51f497367ea7ab28eedfa171ff11b3c65a9292bfcd1d4904f3b25fef4ce75343f16eb764ce83b7fede384c3e4828bd71f905bcf4f45660bef76abdff80d649c2117728d098272fe9c965546563ae0089f5a1d49cd28adb2812049b44d521ce697294cf6a7a30d197e172d410110bda15bf5d204486c72d51ff97af4311ebe1f83af2370700ba7fb3
g: 40316306b4a213e51f1e2dde8724751c3fa1555ef68f900a0f3fdd4586a93b94652ff55023262aa204770ebac035cb9a10f22ea9d1f2fdaf8bf4149e17bb74b8c9861761b77c5e51519169d62a8cdea3adbc41df8b5fb18b7b46364cb85019d4996fac5325ad25d0a38859c88339dd4d23a3b992ee436ebc886670aba858e83c18e75264e77bdfdc8f10e8aa21e738cccf23984526e3de20ccbb2521a756e3ab94a9c795182df8daded27b060cfff738f6b356e9f7a7a297bc5a1d984b26451d3bf0e09469eac2bd8c8b37dc64c749b0bd26e1383c7ba5001f2abb2ecf0961b26cfc6191ef987adc6d3ae0812ebf255ae82b8872de45374f475d05c620f39575441b1d73071f0dacdbce5b9894d31f3561a6c0813c7994a2b98c61da75d3d946b23f47962cc79927cf47443a3ce61305437813c6749e8abd9e2a97d39a58b4b50cd9227dbeac3b11ca0764c0b8e34fe0cb2783d10106839930a13c05db4a7438d63be894ef6345f70ea1adbf46ee65c25f0ae858f7692b949183737034a45a30
h: 180
m: 0d013565871e6a07b5ea23dae74b7ef8af4835c080914022653911
p: 8a0b6e292cfe764c78a9449ff2b88778f41c09d777de23ddd13adf162d3d84e48b400c4487f1ca82e4e51e401a4d22fae911bd943bf216f59f00aaf8e94e87eeb5bc2a73333fd8bd49e0da0b3a19e0cc8bc5239c07f89168c8b8363c7cba2a8a090155682e788236009ada70d5d8285edd9a467df5bb014931dc6fa405c9b3332a666bcfebc395a082c113e75dcf5e28ad523d6b12709acfed7e62036a3f8d0fa6c433ee563745a900888f68631df2a362561b3140be33ad256c297162c1d6f28141a479e52bcc0fdaf0f53db9c7a1d013d6d0b7f0c6f02cbf977a2f2afbbf90ee3e65e199704e2d71498e0546346e77946d6bcdea28c5a3275069a18f1ec8d0785c3939831aa212503f9fa5d4d8f065c7b41b94bb13c6e2e1e75930148ce22b029b620c976e1f38b1ef6da08b3c1f2ab37f6f96f86494512f268c39bb33e68a049d19c9a0ba93b4dae8b270e13a99f5bdfa93321580074b422adcf95bfc648d14d7f55bfb341acd0d0f3f36ef5fdc7e5c3b499ef365a4ac6de80e43147b40b9
q: c55a6e8de86e0208693baa4cc38ae83c7d004a12a1a0b87e83ab430f4e29e2db
r: b949252f11cc02c38a3fc1218930db9ad7a24097fa8e9b42b44f1d09ea9f5220
s: 6d22c65f65ed864a1f232501100c99a331760c14566670784ebfc5bff3053955
x: e243660b0cbff5d84422bbbfabed9dcbd2e6970a999997890be51c01a4c128
y: 4f8096c18bc3ed8971b3514305200348a12d95c05e1487ebd7fca567adf70f0237fc19117363b051ee0e80f5e63f8fe0d90613c88750bb032e97c9487a00210b31106da93937807258411660a580eb2ff2c01ebf4c7ff36c5f70bdfecb2570e55ea6b8f6d9dd1c7ea752f1b492759a9eeabe8e3fe9385467f6820b5d0ac93dceb1e634dc1ab7621492c9b6f23a0258dcb44c0158de736b50a9e5034f3c984364da9a2abd451598ab5818de60aaed6fa7eb102e1f2c2623f8af70fa3559bf67933bf59137ba259af1ec00ed4b8d8f354a8b4fb048e7942db7a53f4830f456804cfc77caaf071ce727f4f61d540116f97cd06d1fc1d6cc222faa0310afce507fbcd963264efed234d70ed4198e7493e67ac2388fd0e969c0309131326b506fb75caa58584bb5533502a41c0516cb63a086124d5df1b530b5de36e1cc6f0f9386b9dc1597ea00601e2a3cc3457d1ac3b7d4e593d7575ae69cd0a664a8ae1c2f3ee128abe12ade38083917c77d6427fb3cf8fc2bf1d16e562f440f65d26a229f7ad2
g: 819ed31af9b43aade213a15f57f9c2a23693b6cdfedd17b1fbda475ebcc5666c8473645d62fb3a1d67b6966ca4a85588dc31c278e5898b76b27e48467161c9ef25615a1d5e1308af93af4fd4c9b6698adf65b587ee162ffe669f56d4fa511b896c2c91afe619259920ce02ab157599826723e259fcc1b158a053fac35bf2e8a899634e2d345aaa8dd268605ce8c9fa8de22355abb9d6c197999d67b31317d9f57fdce6e2ae77ffec26db0516ab2c5d8af752fa912b7c5e6631a8abdf0191871e5ef1035812c5ac3cf1e83c45ce9a57269eba8cff000cdd466ea95d50b0531eeb30684c7030b1d230fc3b53b1551095d305df5ddf65034a6052e4c7096b2f87968755c8da2a270901886139506c3165bc56cc070263d79becc30e27bd1f47250cd1463aa011af79309a8c007441f6292b6788f372510740c9da9631a0fefc393a2a1bc45f28b239eae4c82b97c1d785705bda235a2d95cdd28af794c411eee1f95d0fce855c00ec21139b45362fd69388267614458ee32ed0126dd427d42e23c5
h: e0
m: 5544165755e744ff748e3277d1017ce1f92996010a3e4c48b772041fcfe2ea5b70ef8c997df7a27c404babcf9c5bbdfe052caca08cbaa6f62d1a5fb7e1cf45faedc948ef620303daa8a534327851c6f6a17438fbbcd30fa22faaab7787d2fa4a3f2e7303ef96fb68c9fe685893d3ab32ab37eb9eee19a29e85cae582bbad1dfc50b98e4b2adfee9b3516062ecf9c2d07041370502486eeaaaccb7b50c0ef4420ba7b707a
p: e068fd7533926bf7df46106569173bb5a42aee40a5c996ad9b01ab529639b55c28e4dcf4fb9c0edb81335002a4e4111b1347f5fdb55def3077d459ac5317b60731eb56f97c035bd162af260910f37bec47437ecdaeb845dd185b91cb46b5c4022865ea31ebbe8b3272b762c1895881ac487e5c5d9ab90b6282059a1e981ea3f4097c4b8a8e8d17f26d73c1fcb779c9f67ad4aa75238b65d3d736a420e40a3309fd509a5fb47574ec667f663894cda29e9c50c5c4efc0d94e5f3a952ba874cc62da4a43223b54a3ccd253798e437340de9335b92741b73210d0dd3a2b41d15a41dc9b06c931340f7eae5b232832d9b7b4c67151ad8abe3869182784997c3f421cec561da7fe4de6e1debd0ccd12ad8ae1d03c580aea0e2b1b1a77f5f5572523a9c4afd99ff1b1ff6866677fe0187c5493c206c4d89fba7196bc68889cc71542940adf707fd91589cfbc207ea8a32e8e6caec2f761fd6712056a69aa2d454d2fc814844a85a3c6e43074a1ffd294c0fcfeae0ce48bdcf6794bb949fd0740ef7e63
q: 9613456933bbc547883efa93dc8c50b3528e31bee6ad0832f0aaf81393890203
r: 84084f214704c50fb35041dd1632546382496b1093d644544b781175e88c565
s: 7bde6c2d6f6d81946ffbc8d3121087683891fe829adb6743066ad236a633bbc2
x: 5f76f382983be91fa3cd87e20ea4f2a64ea5fd3a8b7e336321d3ab028c99a1dd
y: e72024d9babfdbb885f4c2e656c67a8c07749814476fe432db1c808576362b1fbc70bca3d3098f1c347c28882031a5b80a54096652e65f43eb9a9b1169c4af54a5671281c95572da0609d67648b752c9cb57cd7f10a40279b39af7480e596e4c425c12f5ecf8e33c0f7c1106dbc58f9bf8a3c8e81901c9ff97bffa5f6a3fc6940b0d468d160b973586bf1a107baf29adc132b9e7bf5c9f2bdc3d3cb5254bdcb09169bbc03d0a94f6bec6c9b2b6b881ad9354ca1cd6d235e11801396953e3fe21ce41a6c03ed4000484ed17e9f367df50bb65e31d03f77008e403ce27db5f3934abf69c9d8d34b74e473c81cfb50c881dc9762b0a87160885829b50694a87d398f0be11d1b44d75fdb7d2919a4f7f26cba7928ca5fd2607cf453ec7e2edae117dec51dc948045f992a899aaabfbf80d0b3dce08e63b16a136ba0928f087ec42b75cb57114b1970491071ce30c8119a6ea7855df1b23d005f98ff175b5d54b950d694df17878d8ee676d4acaea7b0869332c8790fca1cb9cf7766eb65c27dd0aa
g: 53d837de9316555dfa4f027dd2a56b4527ba164b94fce67689c554144dadc559b14c372356cbbc5f01d356a64a2da4138d04bed902d71220a131bdcd7c2c867ceca64c87e662f8f841f6a5040850dc4fcef2baca890728e762af6e81eb119e173a2a92bb7e2f467d669cf0522011bfd0afa25472c20241bc23bf0c7e9a7590e494aa7e1fe08dc616150b9f8202ce70b7b7c1e13bac8dbfca147f8d90765a21ecb9f141d9f70862f40af3c8edfc0afcfd3c3810c97e62ac4b4e99b0de795ee56f75749d4a4d1dc6afd23b1fbfd7528df5afd04155cc21c4b54a5386e3a98703601e1a9ed7c0c6fe8af8d54bb5cf9777e38af474266b179004d750344c8eaf0be6a1490290a26f4a9d1a144fd7841ed131d080b85446a35b3d93b4b0f092314818682a9f21ac15eaf65e7106620dd8038497a7e2f3df9b01c5b835e55ac4336a57adbef25251f95c487812b877a5453df587e58cf7f59e815e5e622b1e38fb808256547304b63e9548b5f03e8be4650203d64b68ae901a06c8d9c809147eaac90c
h: 100
m: 3a2c384980d3903dedfeb912cb73b0739652cf428805630143e3d5d8d093961ac6dde83a3ef46445fae7908028d3e16d0a4c0a449e016303511372e07a7451f0785e231fefbfd57797010f931a912425d13651cfc3da031705f61c4f11007ab2914c6eb30944e276801622c35d0570cb9162fbc65d12d6bf7257080192b04a54abe8412a3688c42a4cff79fff3e2532b12a6907b2b41521256918d05a8cfa28550cfce159ff8ded87be56204cfa39262db6c5aa6e30f13
p: a635c59a578456f0dc86a56b4bba959acc84476b72b5be1bb7814da6ef36396152078e6703db6af604fdb82468367838a26b2c9f9a8accfa8a8741b4166af0122382ac3bd474a8c62fce402af6898bc6c247559cbac578ff1e8caa1c96cb78804b182540f5973e4a6c6431dce82c7e6dd0390395b148ebbbe9b37dc1178c5eb8b4f10e17de4985714a23086dfee81c6424f88f24af94306f44561afa96c50e25505f942ad5ece4734d6b09cfdd4eec18e347800adaf839a87959a380e0b9b13f45ea598aa3684c813ce318729ccaa13257723b8c95565489d6f86af12c5153ab5272a98c42d6643b67a31ce64e1c358874f7793584ca059290a5d8af8aec5e480b730bb29e8750161edf88ad463baad3287327528cef517abe7e023a18a11d986aa0cd112a68fed6a4ca4ec3fb9b72461f101fa35132ac9300058bc136b7fcbf30831825e86977b81757da26b232ef4890ffd94297cef5f794e3129716226d804e23bdecdd0a9f878442c5bd38bdf97ac8b1e391845ec230732db657fd41f4f9
q: ae55f5cf13dceb13dd19cb6043b004e61d28cce9eb4b0d385ba5de3c3b18470f
r: 7191370e8a88cae5f03903829eb53867fb52dce11de751fde0d77e5f803230e7
s: 18e066762501f9e77d08b8ee6a182560f1e42202193739871a4680752f6da3b2
x: 914a809b0742631a6fc2f088abe6fe4d411e901f6c439dc3d174ffb6e71269dc
y: 4324dd5fc8ffb6087d4025b71d829548511598ba004fd0de676b322f7b612d1fbb1c48d5c392aeedfa54ea27d838d0d4ddc9a26ca48a5ad00c7fb21ecd5d61f7fa545c69b7224904929bedb71aa8adb13f05070a01f45b0d20bea9a425edace730aef05c51b6f3ffa029d44eec79d9e7fd30f15b9961fc7ad94355791a9c3c6bc0f31098f367b1eec256b094a567f2861c6a5049cf3bd6d7c9a8d81022f93273edfd660b53b5789410997327f5c1ceefb8e1cb8159c34026fbb38953b10e8ff9458cc79b2111e44d510b230b8251a6b3e0514b74815ee7fce3e24f6f1b28177f9e552b0b1a99e74ff936292021051cf441b23245493e0117f045d87dd697ff75adf1d75de3cc4853e1ae487d436062d533b157a6c1829c104e2f6ce6b045b6c1d1f4d83710b611da9411156934c896b55168c28d6ac80c943a397e5c2745ac32feaadce6b93fe1c3121146bd1dd7604897eaf41e8a2619816e37f2e22b520b00b6fd9a24420f47443fa5f14b0d620fd3920e6eb64a15b95d15851abc8b63b811
g: fcc8fc2cf59a7693585f1c39a01051ccca7d435842af80f0b0808142774473b8bee527a5ff3f858543deb2af4715388e319d9a36257d8496564fe749745b44f62939c358a6724d62b36bf0be8e5e264b0ed0c06e36a37a4af8908214c4983210b5421587601b04c7ef51291d4cdf4e939dc4b37b575712de8ded5be001bff2027bee49067c0e8247661130e34661c934d919709c6d7521c203a43fe4362ec0c479fa54279435206387450f655353b8139129ccd83da1b6b61279017b39e4c1b1a8db59f7facb682a4e6d642cff38a5477ff6be559aae9652523f12eb057f0519f958d501a62c3f8aefb7eb69cdf68cb217b5fbd5fe32e1e006240a2ad953ef454a234fb41ac75f7d7974620beeca05b3e51b901d2a6281f6a90c4ac4c60647bad3ac2152e813cd4b0f830ca36adbf65dca3483b95d7f05630838f99de52301649424b449ea05efcdf2aede13206f95a1290b2fd61907655d9025d0fa0b46d66d49e92aa09d8887abcda6d68a4c44e53b3fba72f81732a8fa7b3a589b3ee4790a
h: 100
m:
p: fee8d17b45d621340a534a162c58fcc0f397d4baa515ae56acc00c0d09211511e63e40c1e26fece6aa85dbe5ad57721c78801087668609dd3d2eb8de079d860eeb6d6064e0b536a609cc4d951374f1df5c1d98d934d2de51dc818ab1d8f19f8c97fcdb63cdee3878c25bed6f51a658458bf4024f8c26d234eecb3c3254328f1b5fb6419613ee530a4dade1e99f98f15028c837c1a19d30e367308145ccc71e54c35060d02f5c11605782ffcfaa0f210b7d1998defa6b448ba76401e827e50c7edd3433d5f95212b61ac75fc77461977b87368688bcfcc2889fe1c033fdd682858d8b34a64d04a138c30adb6dfe5387281eda06429604178d8d8c661342f35ea77e08716687503b2525c5ff390513d56093f5543be751e0d2de7ca9aaeb694adcfbff52d6a87f8d79bab579df3ec9b4dc51fd0312bf63ef4756c4b093214c5a64a4067a018685472cb37e81334ff9530dcd628a44ecde999f8f4e99408978d3b52839a04ce9110c6c3c11d5c2d79a38e00caea2a74aba044293cdae470c348f6b
q: db744f628d60ef586c449d07f004b05df98ed06774cac1ede88f8c9609b34c67
r: 27e44e643e960065b0f65c260987aaa22c91e92ac2c9f33db998d5f22bee7a2f
s: 56801987b9b68bb3ce55b3e0a62b4fda25589f2e69e609fcf6abd9c28355f79b
x: 3c38768ab71d691e0c26326ccab8b89cfdad211d0a7fde425b1993efaa64cb55
y: 3e3429567c42211b12193c53e926ada2b4521b4dd02992e5c4702065d5ae6b14f2a7c9b9554f96ba3e7001dad6a9e5aa2ceb90597a57d40cd67d09af9e482e9465bb614d0fb7d49d1e3095414caa7ad67101badf5bbecbbe20935ba242759919a4c5bd8fdae8c724a839019fb6acb58ee6ee6493cdd38690ead6f0a59c442bb387f08f62f7ddf70b64554f83541aa888dd78b5759a00b0380a2200cb6c95bbe4b43d44186f0beb6e98aef8db4a53164e83fa022ba1fbdd4ca6007c34a0b5ddf24d04e0d321b7be6731f8c4c28c18e56362b30f70a3a916e41b48be47005acdaa6d8d546f6bed9c554ad76bc9f1b517afa8d31ca4d2029aaafb795cf9e8dbe7322556e678e90c09b41e4a8c1533c1c4e568bb2478ec7b248beed68281179f9f0a60bf0f4868b63fc371ad666e6738bcb9dec5b82026171833d2d6842bce9e5214e436e2d8316e65a0ad24a30e38aafa1de7afcacbe0dec155cbe64d612218d22ce2a2633671714f7d1d7f0d715650e6a663d6595b0156ccdca935d93132b6bff
g: 212235e323636f061874040e52cf5c500b80e27c4dcf90784807114f7045cffbc83b425a5a31f11b30c56fa602109893e074af52f1236468aa0430e953009069ebbb48ede64365a8d4cae6b2857084a6e7fb59541e39bb39ecdb0bb1e9ad02ec4d89ff999e78eaa4f1bda133a730346c5e4676d7e16346ccb7b607c63ab3b9f320ad00e0b0f0faf6e6d75f1f441fcb038c546a329e13d1b68d5cae27c6359ac607112857c4ea367095b7de4ab39501c0900a9dd00e8cb64ab20d193465efa8cd5eb641128fe8daa83e29880c7cf504b07b14ad80aa9e044ed28a38d990bd2f18b4042da4c97528bf02a1fdd9086e44dfdb179651ab49bd0a6e68cafdb2be1af7f0de5de23e2049bcff30d9928ca70eb0896f5dc0b6192b9841f76029f1c56bbea86c0c213c7f7dbf7d42f795d2256715158e2c4054e5075ba908fcff6fd92ee5570765303e1931bdd878146bda1c34dacac43a2a357437947cdfcccdc2bbcce5337d5b4fa483b6c01ac9b389886b99efbeaf145979626fcfcbe5b4a6d9326d13
h: e0
m: cba4fd1d7a0d57561b27022803560168562f6997bcb1ae596496e79916ac13dcd044bb78e6f9e9f0f0b24c4fe30acd7ba3a78e29428d3baf5fe2ee569c9aea5e34e0169bbb2a274308ac78e06048bfede129497c1926edc90e55783d5fe4f0c11087ea64bb6225a5570fecb13acb75c47e0593e9c1e1cbe36ebe6b444791976349139b7f2c912c311748a742b6eca7edb400e5b3f8bef1ab31313303e9cf14
p: c0753b107ed449541d42eab7ae1e1550b4e87750ba7a45ee6e6a00764633dd34028c2619930a25e764be4a8dfc5f485ef52d9dee840a5e4767f4e3606e8437e310d08c76e28877fa9cc548097903d04a0b165b2d27bdc9b4cc9db0d179733ce45bee7b6497c9eaf6a56fb95431f4248570ed3d278eabc85c058193a39bf9800fa6a881aecdaea45b32070153062e4166c6bb34e44499f1054b72c928f2f91edde4a908fa75b501f3647d71df17b4aeb8668dc4bddb1cf25a52ed2611fc3b0f2cf0c96effe48e5de4dda75b62d5fd772ceeb52913d70af52a625c341169e2600472cc46f6c336e3c02885b96f46b4e77ee8b4f5c16df35109bf120531cb70157d820a36945c63028602ae5434dafac2e8374ff0832a65e185faeaa516705eaa0c93db88ec3712c627d7de880cf91a25776af02eefe1f331715ed66531186f14df58b58578af5e44a5b1065ba1e39d801afe4c373678b4bd7114f981c5159bb1e22474eb43386565d4014e155b310f3f09c3f8ce31557a2307af2c3917dbf8b457
q: eadeb843ff31d95daae4a01d376742120a1bd1c4f0c27639ba9d9de1ae9fb615
r: 148ebc9c6f1e88b32f11c207026d7cc2e84a838a75b0b906a816c332d55a574b
s: adbfbf68c9bfcd93813bc0452102ac6074b5c18a90d33bef438290d332b3c847
x: 65394f78cf7ef53ab7cef2277456d177f194b3468c61a2300fc92508369e1174
y: 3e440d6f5a06aa3eea13f9f27013f58b60a7d11cfede48c212f5f626ee33650556ac47946e6778d5b6c826c062ee48da167d08e835da58d085849b77ffe732bc91f0926a7fbe0fd02c76c6c539304b36019563e41a049b7165a43e73cba7b9e536755fd35bd85ce18a51206d72d75d485c2915aa7ad9c3aefe7892693e3e2ab2969f6cb31ba11b1726e8fa4f00b3b35254c2a2d4848f4b7ed1e52b0aa786016404346e4a764b9c56a261f5f9321a9e87d1a9b5221b44917002ed222f596ce56e9163598fa3baef48e7556f6c78a5c6f31979d90de4b12be3e23225c6478695768246dbcc12b9ad3dc7aea89878ed5938195d3c87179b0da01dc99786527ebee362c56d5622ec8c129d43878bfc226f3034dcfe5415ad1a01de156bd2fc1ace834e25ef7f4ae4a02bf4bb168eaa8ce8fd0fa555c5a93bfc17c038e2592359b4522ce15b03dc9bb0c460e714ef07db4e328ff82a2bc6bf52c0b7897eb1e1182452b008f459dcd8e3fffe716ff91653c33f5d7fc8e470ec6f079e94088d4186a612
g: 37937d8c7b7ff9b5e80b1bd910cf886325e697c029fac389d883d3559852d8c925a92b006b6e2e834847ef9b9b9f5e577e9731ca4b137cb51710fc52e1200fe24a2f25e9cb50f54bc1e7da264d44480b8064145c70f94e4e00958b3cb66e5ccf30e4fc10073a5e5bf19d43a39f911d78bbd43be6e854dac0fba93adb7e6f0e2fc65d938062fd0db42472e0fd013b361f6f3694c26c876f0e11e291299af026fc964336ce4e4e1708ae928f3312f8353f11df0c258ad605b1e084212ed7d58380f48a7595c490c722879661dcacd15439034382a158adbee93bafbc2584e2ffe9b8d55d92efbd3444e751e51a2cda5260d14141a2c5cfcc15e21739cf730dcd6b850fb523dc82a318b961a4f4e6d5c14f7e0a17417e5ab3e8c3b33fc1ff43d0695b4abeafd3d7f6bf03f7a9f4ba291464dcaa88e5e418c0102cdb17bcb03aa93aeb5d9ed231d12e99f27e5a6f0ad3fee43f2bb034aeeb4421ac22d2dbf3a5e93843cf9770d9a15e17c2b00fc2ef2891d2173b149137601efa0bc85a477fd2885c
h: 180
m: b4dda139569a44b5a179c2e5457bee1c65b0894c8bd3f3e336cfd61f22842a0b33228bc953ad110d9f471398802be2ad509993c6
p: d1975e9d4fea417fe2415982f42e9fc5827fdc851bca21f5fb890414e70fd082745433c713bc925548e8fae09f7d4c02330aa572ccac10bc60e7dfca034f3a1bb6a257de6d21ced88fb804fe2e6c98f62c407c893c56f7b87d2ee7e7438684b115f1d35f887249b0ab922b20a454e9410afe74fdb696b53a57eb038c341d5a1ea72e7a9e7b8d7ffa633981da6f86517c3a9498dc4d1e73df8a86c3647f7028a65a44230297465c563da84e5cb22ca990d1f52a0232eb948a9b9f98d27434e4e1559f377e0f2f33640eeeaf9f8276e729585f93fe749f7563b87e00a9725e75cfbda5c48651a09af950b2a67c0f481708baf71d1e2d61250df8b2e11a8b0d7892a93a91ac47022feeb641a0401256831a810d699f187ff2a9c564e28fff200b25d56e9d65bcca39a4957b67c1050b74c1c38a34800acab0007bd508aaec5496290cdf313b3b15e258ba0e852cf08e11bfa88f38d297c2b5001dd6807ef81d77a796af530fd9e8ecadd3b24d356bff4f20d81cdffc7f2e7b615416c3923ce1b85d
q: aac8b1f5a8f8f55410f312d6d2441b33c806e948be692f008ba7c21f4ff1e59b
r: 2b7e93a7e1123cb62bbede1c006d605ca4cb326482ed5610eefc3c09c018c799
s: 224237bfb5aa7a899c010bdc9bd3c995579785dd71dec357279b68ed9cf25fc7
x: 2367d7a1e5bb1090299898f1a93afbc7685fb9c9c6b6427c881b1f972be8e8a8
y: 5638ec10d489552fab7db5ab3e3632c1b474f2e34fe51e44de75c24320f7b88ea9f55a661a742005e2ccde5f274f4f5acfc68a45c1fdae90931ac7598b63fd3a222ba622f3e5d4143cfbcca3e764cdb3b52da099b66f414abef8516c3a7dfc440746c98102e1a31cbd8899e3aaa37b4b36ca42495468232d52441e0bf9d4f9531e985e116ea96bd1e0d05f80bb4604e8fea11544eb97e3f04f0c4b60cf0b7388310c1012a4db38e33045b7aff192ad25d2848ca7b787fc2e7059c6ae788095f2a186821de66ac1fe39827d6cfd4d2789198465570683f19099e3e1f3bf7096da9ac000a09ee739d299b418946b25f634d1ba6b53bc7761fe7587b02feff561ee481661d010b3d9e87998ca843a77c0459aec5d3768d462d5a499ffd98ebcfc7c112c417c7b64c22731467d56a5e7a7661b40fa5c954655121822b4b1fa3febc10e413e19c0599fd744a56254b7754d433555a49b8fffb5b80717c0b5049f0afb1c842e70a4e82bc8dae38017e3f456c5eb4b0820de0778468cbeaa782515abe6
g: 938a31e11b17fc5272ed65f5403b595e025137b510daec1038fd679f2e1c120244fb8007ca83f5d43af98cd88598e08e761e622febf417c452445da1ce0cf56442ac45ca500775b4f3c0cfbebacd9233f346c7477d86ee6f6ebe6fdc923b1e707a1b3a59e1c8e0c07dd36710012e79b93ddc219dc7f58aa4bd525e8853fca761a234e4badb5d8f001c119d5c5addb2cbdd4b0f89747faa6a5c1ea601eef695eb014ec7bbcc5ec71f8779ab5c31c1b7b0d381fac3699d7d38f7353f5e1188ab837cfdea4733242ec8fc86e372a2029818979caecd1f5d8d0798490ceb92199283a426d77e53e0c8ff4ce66d4a571b93186ea11a18f9d1db9143d057ce1d31effc82a84f706ed6b5563e8b55e41aba68f895fe743123f8e0b0fb7b2100957e25ad4974c4e03b6241dc2dc64166e507185cd01b7dade03d9452bbf9c58888fa3d3665f08f1e98538c6c2b648edeb1501e143eae11e2e0dfc164df0203eaab408cffa7b68c7f3dbd50716348afc688ade5673a1e30f7053484a1429b7349789a0336
h: 200
m: a6e57e358ee95fd5d1dd95650b1f20b6c0ac4b83ef07f213a7de4bb79aab5faebec0a609979a8d84f5c039ee08ce65f17b61ed5397fec71f440c2ee689b474425b94e695c90253e0810574a39991b664eb6390090882e372714842477de0d56fd333039a1a223549487c2c6e36662c2631ab0c80f2a79d0672
p: bbed6cc8f36354c59cbb3e073d68cb53304f7249326a3620012fd3bc32b416ae5d64f5e50e855df4de20536ab04175c30bc62ad07836365ac5c526c7945c9d52672cdca2750ba6d23173afaab5333f7d33120d836d843466ba0b529a43a010c4a3ebb10ff3d0d0e92635a7d94238689ab014aee50ecb8f5cc363da56f8f7d34a234cbec4ec7757245a982d2f2c09ec261bd45d511c500453579aad2efbef88aa0ba371aec852ae7cb766692416b25447beb97d8db8cca769bbe28d1adefe07be66b9b75d8aeba471cb6c32765f6e39425b273460fcbfe3f49f05dc64e9d7a69c28bc70525e8d5acf32096e693c41899b6234a333804551c278080185495a2372dee0995c583c762e131fb8f544a21846d04a260d0f2fcad9c85dbd30b48e32032bbbe11cb34c642163532c466953e4864d8768c2e8c2ee31144d0a9e69cba4b3d98ba5ef53682462786fe8a5bc43225a3342b87813c41e8a08dd65f896885f00928854bb0e068b805a71620c3d9c854dae4c8fb441760c628432e921b67dcb43
q: a39300e431619be4b8c2aaab03ae649a81c1bb8554f3c4c2c9200ba7194fd19d
r: 2cc389248e2c4bd59c57770a43f469c9eae30eb6c4744ec388de95712d58b5ca
s: 1bb7aac3abff58f138f9668f112c687d34f31c618992bceec68d022fdd9a3919
x: 7a9723c452867d5fe06947fa97f6850c74e991d4a8beaa6557700b459e298f4
y: 4ae5605095b89cfce482636d4e0fd2b07e2838fca7e2bbd5f496c4ca3c71ab1f06eca457bb8e7f4a9992451018aec6d0e24d007814b5a8bd8b5ee968285b55e287668793a8ff9a9eb9ba00eda018d29561c5b61fbe3278f91efafde86b81d402a6590f84cc6f0f90afe725e59fcb173e1eeaa5b24ca09ec0754bd438fb9fe1264d040a9e2582645807e9df4462bf069652778cd30db041399407dbd89e5dc0fb4359efd345daf8a1d1093ab137ba8d8fbce2badacd3bb3be438ddc3c45c4920e7e5a2703a40f284b7c2663be21faae3083a23ff4abd381ec93f16c82bc30cc9495c036679ab295eb7c7ff01b0020aad0c08569d4f94b8abaa70ae10097111e901e30c019f921bf2da5ad188c4659b57260b82f60fc7043242bfa9c5749e756bff41474126925652d84a4b18a50c28598b5d8c8efd0ed12c387ef9bbc0b580d5cfe3443267bddc1ddebeacd7b7a456d3b2a84f47bf528adbe825f5fbbda9cf06007f30aa5acd8027c47c76cca10dd9dde68104710559ad3324d6cf046d3416ecc
g: 564a9966353c55b57c6a42e5b17c35ea70ebe40baa9a71b1de5d72858d5154574d5b4959eec96dd8d3d1498fbf8857b7a31831db381943bde2b05b2d9ee565d9f388130da4d5e20e62c4ecde304b19672dd93bf8bc105d6e46bebb8a3d538709baa235e338ad47450f3a437cc89710a0e759694f65d74fa578fd9c6041ee5078d72dc5d40d868ced67ccf06f01f74faceda056c609a2112ce1e43b6181ce353db008fe783e8d3b4331640ba6c7a6769e917d3bfb3e97167e66bc9e4bcf576193970e93f83c817635810bdb98f544ed82114d8bfc52c85797306b799e40c1ab181d9c6c64dd1305e9a786bee62f83babdb4ea006d953f6b2a17edf8e455549b27ad05374c5ca5905a335d85ecb601701c529e0fd63f4e51ed6bcca4672e8effc886984975517ef28dda6ebe964170469cac61f83c3c8da31b9e867eedd0ba64106995027ae1b4365cec6f49239c0e522e88723a2e4d2ed13433beb155aa806c6793c16c12d232464fa954e1e72e241a17d460435c23be7d4f60e9345d008490ab
h: 100
m: a71b2929af46e7543e
p: ac858a709f5ee49f31263b09d9aabfbe89fa3ef7cda33afb3d8be3c53365d60a842d4ad3ebc6a8d0a2d02b51685df0249ba269e0f0f6655b5071417b282c9312d045d7362a9cbf34f308e939945db31b89c9365e704b1a3d9f14779a090e3746e6544f0b5ebc2d91b2d0f5e7e6c22a5cbdb8e92c13243891da666b7061f3a3a3c11ca48d698e8c8e00eafdb8e7ac98727429cffdebf73cc25ee6809c48578027ae2f9895b619650db9e043f83dfbe3bd2058673c9093c58ba5b4221f6bc3c52d6eb3c5a60179badd6d87516861bbf5c779969b639cf229a6386d73a22b39bc00d82b7038472d6985e2485137061dfaf574176ecbce66617b1a9fe9efeabaadd85212ba5429681ce7addfbbdeef49abdf510dfc949c4b75fe6744b1f40163a03ec45dc5a32027dd1ff1cae99eca4887284933119892aa469af527d212d0a54ea1f24f617b8b0760418b06f38f87a77ac70d450d7a7e67cd51aeeccafc8f807cba2b60a666d270486c236a27bdc5dc007b30ab4661ce37989245cb4e8fd2dfa545
q: 9a8c0039f364082e3828d98f62316ea3acff181bdab8b1d8ee8af6117d78d2f3
r: 41815e633fa50a45e2f5e67e72abb0ca5c850996b4d37fd126ae0270fe8986b2
s: 712e672d05e8bce407746bec1e26426de01c02801bcd508eecd0d58fda2f105e
x: 6b09b366c3b2aa81164208ec0e8ed5ebed585725befc895f37ae444fd42dfa04
y: 1d8573838adb591dcbea08d8105459914f575d72ce86a88dc1e443814eab46bab9cdb9ff0cf28b1b2a83b19a4d2805da15d77d101801fcfbb7dfc46c19f61fc4132e3f591006e6282ab5a609ae438b8f53984aa60bde6f127ddc727b999167852b53be146624d67eee9aab3c35e4e8ba112c78113cb1432265eddd51ddb7b66a701d7084c7cb99a1bfa8ae7743eb1b7258a0a5967fa31d5601e8933d96a81e5749a53f6356785cb962d2bcaae3b70a1bacc0348cdf8fd3347b689ea26cedbd8ce05a7c26175acdc66b13b8d3ed81d5baca94c0bf4a9b82e4e5caf07c23aef5d9d3fb3fee2d3e9dc7f31da6983e6a6ff61fd6f9212b2147389534ca768a21054b82e13cd3fb98735de482582a7028ad548808b635a3a7892be503dae2806090b825acca0f1d54df3669aff15e21337d3ccac8b989f3968c2b0763f5e89636e73b0625eb47962d3cfb35720d7df49cfac233b732d2e1075c20965682cf47c976dbec79574d3ed2b1f224fd72a672cdcdb1a55d88ae6e6d8aafa1415fae3d579e60
g: 6c211aab7f67be64dd75828e176eaf1dd9a5c12c464d8e86111bdcc8a9374c6e03a96a49a0afe383be7d5f56eb6f191013a17bb18f32dc2622d6fa5bcc967fe2c80a077344241c31f939e0f3c2134747e0edbda63e5b971ff1a2f084b7da8e45fdcc86b3ec8996fec01dd71b9beb87b622ba9587b3ea1baee8be528e5a6606846d2b0ede32385b8f59807ee09a3f523254fcdf6b3bc370b84b335875959c09bd2e5aef0dcd8bdee573b083553f658f1f766b5c7174b851addc8b8dcdd1f6c3266aadd97e6109c185b84ed2be6a641f40d722602a54781b2a663dce8746777706812478c6e1b996055d16a4e147a32bca50dc7c6e3cb065fb949bbaef072c50982f2afeeca1ad2e9338a80c150726fcefb05f96b8192590820bef40b8fd3ff8d0cd752864964e7e7274d974960d2469c24de432dc1d235350fef28b41dfe828bee7b7773428f48cc7acc5bad92104ede5d5c0c186e19296ec68fe9abd27b6d50e318cd7b65cf2b2617d77e38527a26aa13e52d3dab898a1b1814ba60b7402058b
h: e0
m: 41cff2f02d4ac663b0eda83f2efb939e2ba8c1376e5bcf5e22376a5d8209a6369563d99be3fa9c6634ce6ff0a1f988bf061bdf1b3b7e3fc8f61bebe04c7bb28f5c798ed4858ffa4b65a9297ac8a56ac47e5782fd231a1af7d96e073ae08588a73ebfdd7e8de8d58743f45e18386ca4b3cdd941c94dfb7adc30
p: d8e1faeb2fd188a8a7cde53b8b3b43ca37df1f085c0a31f675d6da92770eac126e02e5fc3837669362850cb89ab4f325c3ec336bb2f3addcbc03b6843ff4d0bd6a8db6acd91b0c6a73aee84ba5ca3b0b7ffcaf97f6748c103f54f32d0ab3fedbb56fc107c2df192510f19a636606dbe95652b4e40b2d9ef4a91d112160f168e4715112c8ff257aa1fd65a325242d1f6bb3d835a88dbc0965e542d8e32ae419029911c76de29cd85f80ed491de2ab24ec3f08fa80cc972179009874d48e3700041a2eef7c146f7f36b922f3e2b1a525dd0a5d5e0fb58d09e9d368740606e8b9cec3c59d69c57d68b084185a879bfa699e4e7ded1e0dd6d01f6e80e456e35e15c2e38809749bf4881d530e738c5b647c186883a2ac90c8d2dae4c9f79cc550dd1f9bca1b32c14fcd2c7805f5178ade716d6f3b7ef3bd12631116353e22ca5c298b485d2fbd5f43ef024668471facce5016fd1590aee5b74e4bcd4fdfe1acbeae7695a9dc92618e3a22d9112d636b4697977053caf5ed0864f8c7889a63f3f621a1
q: baf930264ecde018c65874e7fa04024256b22a84437cff82a2aa7ec4508cc397
r: 8f81fdf43c81e8f64d3b42401c5fd4d0034f3c7cb543690f6e187ff3fc1e3b7c
s: 498e069e14c41fd63647a0456e9950f99ed59f73516edf9cc02ab4c97d98de00
x: a91a1f6880a942d147802a32ca65fbb083835e159eafa577f8a958ad931de3cb
y: 7cdfe454be693a9c8b66e81058e73fcdeb74879fd13c3af7b1026da762d1b85e8997d6ea1d01b9f95896b883e9e9d1457729c953d64c9e55a1a8df4fb2195fadf55f59ae7b5e6f46a4ff35168caaa3076344a65e876c27b90d476bedf23db215282dedb8329d948d62f00004d45579c3017af70afdbae6b90f695d117115238cdafde16cf27f00f94a073d37d89377f7c72b812012ab1a467d981111d7b18d49cbeedfd71ffba34a556634776d879163bd10fdca99cec3bde95e97695432549ce662cb211917c5b129cf757004e2e009a73498ade0408c26ab6ceea31d3a42c1209176fb435729e0cb5e9b60a0a4129e935e9a28bdd296ef8f2366d0feddabec5fc6756c96f25b5c61267ff56b1fb1e76f9d899c0d46f1f4a89500b095752148bea3d7af414e326e4fa0591fdf4b455f489c6b6476c14ff5dc1ebbe6e4a22ff16ef8fe6bc0372c2dfced665942fdf9f1fe5374a5be6782bc7eed8439bc2163765062b97f6c331afc5b4cff28097712f5ea807c1d38dd9d157d583301c28add9a
g: 246aa59573c86300c83ee53d64bf1a7f4cace3ea40db0c309f653e4231c82104a26333c9ab3aa779ef84b607b273f71145cd3a0dbc379625382be8aa61f71c7d205297335e65ee9ced3ab29a00109b0893aa88e4bb1f3767f45cabde0715f4fa531aa952c65098da52b707daedc3c9626db68403c7b5d88d850ca144f4903872de6b6f622c64b144a7465967598b6d25d057e012ae011068a51d387b4f60faf13e79d96e9cd8d38b10ffd9ccd747cd7bd8a442941e3d422a164b6c43b8351a756daeb53522d3941bfcd4f91a397005acb6c84610e9bf13e6a3bf8bddbdfa69e172a635eb30c78e7d5f7c41b337394c449e411ce5d040f2d5dd03675269f66e9e17554e7bac006acad16c15ab34526290fe78ee8b4f221c86426c832f60697e59dd37625598b7ddd7d57efc7120967b39badadf111a7f74427dbff4cbb2cba83a285e370a8f2f0aa2d8b8de7eb94a4b4037e68e8ecba0b0830faf53c4037e9e217518d6787f00b61e882828941366e86fa1d40c5209935723b8b325dfd432bc91
h: 180
m: f8c04b2114f02fe4c8ad7a8f0f50ab2095e3d53fc03c688994e3eb42f70ef8218a9a41be21d7cd52d81ab557d3da2652785232dad130871b
p: 89c2fcb4f23d573ae016f733f5d675f7e04d6961040787f9879ac93e5d77219d9901484434a849445a87e23c6aac47929ebb3f68dfd3431880d92a8358ff428d555cd5194faf3011e0d8a6b4749f85fa0ec44f276ab957eeabee75e6d19fe960c54607a1356a7ebda002066a66e377c3e4b0758b94500c32f38386cdf8df332208e404e51565cac987de26fe7c2dcb2da7b760d91ee7f1136976aba2dff06999850d48148a4a95dd7c5a8f72674529f2f9cfb942e872ebe2deda1dc923c2325741fce62ffd279cae4bc2f82e8730796c7eb038ac17919f73b30ad2318878b08b7e8dd1fb3e7fafe73840b3a0b5848dbe8e4d714a4cddb48ef098c64f557dbd52dce8c47dbd3c3adbfd2b6d1c9a79914ddd9110b57b0add4fed67f5bd23139ef2fc4cc70ca867b007f174f2b3e5ed2ed9436b8720e516cd59afec575b58f6a8393826a9bd240b2f91eb1bc183ad6d3771922f4075cdd48816dbe52a15c1a49b88ca7a75a9db0e852259258445f3a8ebc668f18666182f6ade41d1c29315ed2325
q: f139ec4db606832bcd7225f9cfaebba8de23a2bf0bef7c6e7e6da3c0a67e340f
r: 94c027a53e44370294ac7aeb0026696a5a7594fa5981ebc8cfd4aa2beae182fd
s: a6f97f810c693b98fadaee961171491d478c496975d6a8d6a69e448aa6dc1a25
x: 70de3057cd3914c66ccf91b988a668ae71fcc8dd2cfd5f4ec234608eb8b2cbc
y: 45e6f1b509af74cb0ee5932fb3ed71af98dcd9bd6a6c37374462891d85b3935aacf2e4abf92911cfdb67d7d0aebaa6f03703d6426a3938df67749c4444724c34be608accf82f7839e20860954dd5c5d8417d148f4f3708fa43a8c7d9e63ca4c16c0d46fcc21d8aeee46f71a6f2674513a89c178bcbb7fa700b39f955f015198931cb90e9a3f51137d5f8888caf017a78ad94f3a874260afb5bd0ddd00e8a18ce5f67507c4623ee071685cdea9e84e8b602d96d637e2f3f3f230a6350f19ecedfc38bfa86d5ae1aa9964e8feb16b2828270c8fdd912c9c9b7acbced2f9f5191ebf507bb3b6ae52fc6b1682d26fbe674b05e47f1908abf0a1dc66b350124b6fe871797eafaef7adf7bd5e7a63c5d3df2c815492a94625ffbb9a0985142a8f2e3ab678310aaa5b031c5f2c71df41443d6d5037360381a71bd6d3e7dbc6b8bd2f2aad5ff6da9af039991b34d21e2e1b2eb0066b21ae8042ea6230da9803b34debae1fbff6e6aec96138a19e4f32ea7b55e3a1aed6356a2ad41852f45dc42f5adc232
g: 2439794053fbc1ad5dc947bd900d9055aaf605e4ed189bb186f9e7d287c8e7d4d811be0e7778e86408734edcc04c4250b67a6e525b9257336c0161db48fdaf031a2004115550c78437613a0ca4d6cbb0d23bd4d43e0667ae8f4e4e2bdd1ede22b830a289fe4b0d273919454f22681e12b66007a092549bed122baee5d507d2012bc9fc195a54689e33162f1c4e5de7e73a8cb45ca5f896aaae0db2117371813ae0ba966aa29705806897d0571e808f30f87c4de3d71d0452e120d4844bcf2d1c6a17771103ab3742a4d48a1054b3b1bc4ad607962f8ec818c20501bf17bfea56e8a4892b2825b53f7d60a82ace5c7bbc190724ca303f15896df50ce57d975c602d90a6378e710488942dcfdeb79806ee17211f77c51597719a076c7203270c0afa4aa4cd1f74452d74c74fd1d92577a85bea21c65528e2eff8c875c5e1380f511d47b0e30148bfb3a8ebe212dbfbb44e2081657d2d3e661ac8f63479e90441e0584df9256a7ae832b494d351df7a4254370254eaf0d7f316c6cbc2f4ad621993
h: 100
m: 59852f4236ba78cd9f2e6ddb4d5098e7d50073e550a92993a162546f439604a44b915b9133c8c2de2fa2def32118d7d51ae426f11f391088e082729825a0376e9c3ab24818864c298b7d304b3f6adc4258f19112a37625b23eec8f477f389cf6c89172fd1354fa9a57fc73b6368343829ac918bcffd47aece5507b61156150f22ecacdde4f8b16f8e83ac62c8842ce7a1e87d70b3cc3cd0d41dacf8618e751346605d234ac7989414e4d692b95c7f202bad0c0e332297151eddf7dc416bbd7c2ef841bd2bc3f8fcbf3af3fda107cf8cbc576eff5
p: e82433bbdf1b0342d22306244745c9d76dd07a6e8b291c4ef4b13575e7dc9beca812faa9296adf84c92709218ff59d4d9b03d6f353ffe10bf8bd744c687bbe1fcd50c15495b4007801be38b21b938a7ae7572b2d46d5eda936769dd1eb4e60a080d751a4b73c0cdbace113197916a33ce0a68f194276792eac1def1fe864aff03c54c0676adde24b1027c92ce1b9989fbada83272742e9a40ec035460f48080de3461e779cb8cb7598060d720bc400e8d712cdfada9a1170e7dfcc024d137145ecc84f378bc6a9dacf67fe636f85b758821d826c6ab326b388c99ec9eeed0abad77582f4cad6c68d6e01b5c2514468acba728066c98275efaf123a7fe33bd57211e4c9c6626a54a50c35499b88e6ed217a315541048b7a8d8c0780a8292f471b96ce7d482a7e79bea18cb33ae2acf2f00bd5c486dd61627ad574c7e1f90446537c2b2f60553fdcf570dc87f91d0a6d9ebb644ecac4309fb4b45ec9952b3742ace82a7ce0035163dbc3c378bc9b7b6c8b10affbc58e4de7beec584867e9f3c2d9
q: 9927f153e3357e818ab74f37fef9e8179088f98f3426f086488b960dae77a475
r: 3a8b87dd16bc200c83cc600848704bd5376a27dd3322e0f6d86707dfad1315c7
s: 11d2e1140a88837eea7c8a2ef7b064f1e25068a5911d7ebef19d9df03a54c0ae
x: 1e8e5f046a7dbe29d3e38766a676e48f78ae02c9bf20d3fb937efe9f5ecb7f54
y: bb70a52ae0547271bb4dae20efc3cbc92badca851ed1529fd126da0bdd579e9e06df7133d0f96b1f890e951534096fc59bbc5bb316c6977b776f2d82cc954d57397e14742b0c500960c7d942f116657ecbefe6ea54ec9a07dfdda77d605cdeee0f58b7bb7b3f9d0a681bf1c24b22520895a3a9a2991cf815641fe0c3b01634c7aae4af2668a4a07464fe430fcbbdbe56718e9af97ad6ac88e316ebb778ba4c58788280b0e5d982a9bd9c21f7209480527be2d5aac45a07c8e6080e0e84c804fc52f9eaca35edfea8ba285882141cb2333aa524b22edd9330fc8ff3e256264e1e2f755d85e873ef558c3ccd1cc0aed3ecfe534da328d3095011dffcafb70cc0bdb469a0b485e125f4b9225962ea007cb2b427846235c3cab9e09c600245ff43971a1aff04c6221c630753c3a87cf12d71edd5d33790d2d3a8757aab0254b438ad53db2c3318e62492e00ccbc8fbe6ff287e82d25dc34a50e454d2f04df088a326312e29686ddcf3d4e4396c73aa623a0b785f6d0ae49583d8c5c0c2c7c21b314
g: 90d56047fe0437deb0c3eedde6dd8b8c411cfd53139f5b7aa4c700b0e8c30a54572c039bf76eca66d7f80a9ba1033651611dbde3bbda18d54d8a8875dca65f71766c1b72148101b2d702ef9b5aa1a85c2368b4d3a4c9f90126a1ff47ec9a75efa4c0bfa3355973cc8708457196412151411d3fe12e09a72aa6fdad83f3b1a808289d99977eeac805908981e7c2a38d79b601a1222bb37ca0e9c14284eaa772153cf79ba3221814cc2d7e2f9c51540d7a3b23814fb40a943bb578a0b12ca5f7eb4d810cd7afc051410f630243c5c5b7cc672e778cc4b675bafa90b2de8fe1fd613caca26fc4371cd6153c964afc28f635bc751be35703fd587b36491a006a48824cddfddb9d8ecf329f832377336922b27225bdd7e994d6e2b93c36f889de40cbec8e23832d082c3e3ab2d556a3c18ce8944ea04001472d8673d98ec9c4d2ecad98f853288102c78cec5e28b587cd17c0266773fe826682e3096cde88aadc23b49cd422f9cb8f68fc9ede7a9887ceefc2c8554edd1bb5863d58448cc79ff6a0a4
h: 100
m: 76035b3bd6553ce5c469264452d82458c4526be46ce94416e5dbe4289ce836f6682e4b48f37dfcc4c5cf6086e82a29bf61a9ff8d21a1ed239a7cd9d17ee981e62ca6e3d6cb7ffcba4a47aaad0f884aa1fa8fd9dde2eecc734cfecbcd7b1bf73a72cb47a574485b55037c95f0fd61162526c7921199845133bcb7e25f5918c134e4b37e313780b2c16f5afc225fc1d9a058b5a82a002075778b3622aabc953573b4fd0fce2109c895d2d81d7a1d7f565a9b26bf74dcc6b8ad8624212081e70d4c894bded18da63163ff05cb7792e1cefa8206a4d146b2004dbf095cded6ac3ade513b8978d1e321baf49614688bc52b45d77f4d68b83ae21c7e92c8468f86b3
p: a402f26e8ac3f9a578f910de96aaf4cb6e06bf66121c45d3d365331f0bdaf099e90ca7c09373255204f19d3e747a0de6fdca44b0f7294a850b158bf1a77c5fb934f78c35f525199090bfdbc2e0190523eafd01d3e87595bdff792dee18a857f1103c9c70a3a01874edc124fb3e7adb22202edd48d950e5771cb722d3deb151ca8c37b0d028c26006003f4d2619baba2d92748d104023889d45c4e28a99ef537babc839d153168c2ddc1a98ce7d745c870192bd69f16561b90e5aa1ab3f3d853bb01bdd0c414c980873fc97c04602edb64cc2f97143ecfd98581e839557a1bd1114d5c0af803c274e7a55108c64daf601286b0d728ec9318025dafe80d915a9bb0aa74be28890d01fe835021974c3987b8bcf21e7852cefbbfb0b4f3af0585550ed5007a06d4dfc9b41abe01669810a8e3c1f85c69de39f0fc5111a51494c0377c75c8c9114b8ccfd03701c81f594dc0d5f85807f7ae7e89a536b7f03fa2ef3f3d92c03d32f821a293d1a044841e55d8b969a09905c6876756f3c93f0523b6e11
q: a128342cc13963a072d7e1f8fb48211c64d3fa9a88a196879f827fe2bf5a5e37
r: 7b9b903020b499eb52c02fa2c44a771507f7ee213e18739fe6c2b506257271cb
s: 7a75aa9cb7047b9be0b2bec8eac8b6d51e1c0c335380a526ee67d8f7c40c6336
x: 463d26dfacc068729cdbbd33fdb014ffcef9913f0cd3745125825d59a9e594f7
y: 165f2ee5c2f0a86bc3af3a97e9c83dbe6f8b046285316469736a502d8efa25c046a7ee2b541d18cb8ba68e29afa814180eac1a60f9da2d858167870699a5a648247aaf0d779e90a76d568b236a9df05fda494a68878c4f14fbe3ede875f9746b2f694208c8df9d93737b22589d1b440ed2d02e362465a3d7c573fc947842e7169c3924e586e2ce6cdb6b2496b1e0ca94be95ee98aac15422f141985e310484f71d6861623672c3ec448260b87572cf903202d73dec2c577d2eb5b7ade7f706d16350359cf6d07ff83fb82111050d1f36924299c10b810a0ec2b1f2647b96d28c719a8757ec816a7692e026455b66fc2a9cce27f19a5c69733d21713e38029ba5e6c45a72329a8299897f907626dd3324d3494e00155fbece2be23efdde7dc55b14e945c4758c38f9c00fe5631bc5b5f4ae2b74079b3e9268ad7b816ea5085c423b1cea436dc34800e970095dd888b383de553dc963b0d040093c6fe4c278b28d64ad722c55627a87b5472ec9b4996c9acc91c0a3aeea39a30702e366dd50c658
g: 5764707062116cc99172717ef717efa8005d28030727cd2fcc6688b9a834cb19a767f1628b9b63b3699b812dfc0dcb94c0ada4017922f536194aa6515a7d30982b083fb169e57393bf90b589936e4f187359d34f4f538017b4f4ac76c9fdb1fe2e9f390e4e1c21d6ca55d94e022e84482dbb9d4837dfac458e6be78ec2dbc3f4fdf4936e6c8d14a1100864bd8c57dc5989f77ff6b2912978126f962e58ebfa65a5de631b17474d8532d5d80f417e28e2de5a2b54d88ac0c198132e750a8f77d92933f977b53cd22ff4253692b0beb5d6b8bc8a00c93dfd4d5d770e2474b361bef7f452b2969b483e0753850e0cebe9e4bcd32748bca7e5935eff31736b8965c7403b14ef4f6e0b014466c24ffa48c25af65351f5f8c3094b4c4e52c4c6ce8eb85172c56c8d5ea30e9dd95deaedaba7fae22579958e4d1c1c156e5443b023864ab8685b3fcb1c98094dd36b9b05059b8aaa2304dcc65c2a5ab2e6c0b51978ae1d545b5e72359be8339014976ebde8548fc492002948908212960ca3e40a6ec6a0
h: 180
m: b711f04ac5fd89c910b1c0e582fabd78ca0f57ffcfa42c346a078588689fa371ad03fb4852915160f47d9af4446f720381c5571e8c5e
p: 9c0a94fcece70453cfee19ea72714e33761e57ae6747fdb63db3d76c462abb7928b61f9ae467d7d1d9796d8941b5aa47fbcba4ebdce760272fe644e90788591400ecc65c5e4beda021cf5bd761cf34e9ce0866e7c93dce6344e6c6aa3c50011de5040bd2d03e3af54b0f78fb534bc951d008a4e3accd54a4eb666fe479f6c837d8766b2693185629fff8c88f2c3c2bc7d35597b5ebe7920f3d932471e27f78899ca97f0c8bb25438deb9f3e313d1947dc52758b00c8985557617f411e96a536981054051d39e67b7a38f8f060281d4520efdfef4b832f8ac323bd5a18336e7fe17a648b106b3e5347dc2847d36df0cb63a1c33e2827abf624a925740873419f9440160936ac093eb5c5343d04ef8da6d0653b268a227a819e61deb230b94071057a58f818df4198d580dce76cc5511ef968d636e32892633a0ea4661e6c7d6766166ecb435059e07c102d8969dcda065265f08274326a53755d5d73956a16ff1cc7c6708a8eb2d5b8a15c8405c5cd43b350b036fc624912c446568b4fb435f3f
q: 864af34f127a0053b57efda497bc6716bfb8d994da1673b73e5fa76c5eb43d3f
r: 9d0125693a02f4db4f05fba2cd67a8cde6a09684102be94a433e57d8546a6dd
s: 20700ca03c9fa80b12a6ac38916348f47eb63c2bc2b23c7ce34918b2b2cf876e
x: 22412c573b55b3810506821515830084286ceefa19c7a1d64924e77bc02297a0
y: 49e202074ed99c408f3b1eb8f728be5198208c35816ba0980d062b55f0d3d6e6c88c70d3c3e3525c56e0596bd509f94bad73bc842e1876379facae5223bbd41686628b4472ed8b4f39e3a79263439d6736ce9346c9b94a6f72b18e86acfeb0138b2154f3f1ddc1e40ebcd4aa943d7e70240e778ba63d039258f54b85d7c402f132f069d9d84010454de8e6eef7e5ff9b08c68c8686904119bf2864e21ef7eb9b8587cb6040bed7bafcd7b71e6edec8ac2aed8f0c21718a0441f273e737c38aae2d769f22aab468ef82014c6419a8f9c717b40064c7badcdfb3dd873eddb0ffa29b540d3f27b7612e983ff841116a0c552bfa4db4a8225af7829779440f6224d1a5dc00cfd0ad533d8d10d4cc4e2d7db62f38eabd239a184c68f87072cde722f6999ce50b1b56b411c8068ff10ddbfa43fc64b96862f686ab437e6ca9e6dccce5cf19756b9905d553acc93a6b4693092f1ce1ac174543459a7caf0e8973495168f30e8e1564cd2072dbe250c09c8834e4dea3940c38a63db92334c126946bd648
g: b52366675b30cbc99d71aa6b47f774d84c1913ac563f5b5bbaa1e8eb604fe8b4626a128e90b2e1f47e3b0c6bdfa8ba1a49411c3fe9376101a70696d913487886efeae71b8f0bda37e9740089bc80ef8e77bfb3b9579abe7cce8463eb45cb2b7797a3c8454cc7fb45034e3dbd05a30af54ebb4ba5392eaf7f51ce1f6341b16890fc153a6b0d365dc1f931b5bdcf872b0b1b3223e2a2d8791ee84bef27b4032ede9f3ca89e62fe56d2676ef6a52cd518bd57b3084cafa629577c9bf3efef9f68d770a617c452f72d551cd1e723687b5e9d8e41e3630a6660d507545b82226c3210a6aec46b94bf14286bf078309f13340ba59bde46f6ee3254ac44a199416a12f4a8187524446643f9cf69a8e882d7ab77476b6cb137b653e5cf4f93b33ebf7bd516b87f7d39266d0088758c94d7eda81c9075dfdb8ce7a9bdc6bde60df2939a12fc1a455fac1893098133b209783c6fd1396c8bb2110e23ad7e3c24c42290136978493231de9c552d5b9ee9e53b286765f7240e2b2c16ade943af26f63598ef6c
h: e0
m: cdb6087be618f5cb6816b019752a6c9b1b2a34088844fa94c17ba5e12c87b5e01298e3a91871a207efce74e468e4d6968671a68d16538b9cfd13c150869fa128750a66e4d9adde677be2da3f1886afc15cdff6fca2494a112b1bda966e1c0d71955652c87813ae4314ff6af24a1d5eb4c5faa449e6dd4aeea7a4524017a7d42583891658256f15d29d058fcfb89a501f661c4eb4eb7cee8aae4cae8eadbe3a3ba24f117bfe377dfa1e2957a61e4d81
p: f4b0f3e4b4103c527c690c480004166ddf1bd21c6c8a76af29735525f8f79bd009e8a2116e38352964e440e2a4974a7f84a235d21c263d93766362387ba62f791a6fe230ab31668294f7b3f586196f2dcae2b7d45384cd15651525a27e6d4ff9634f7312a4feb0b3ee70febb01d7a36c676940ab0b6ffe5d8082bdc8ec5c0515e2085233808b834b3817ef5fbfcb95efd8c8f2c9db995f02c94c12a478f0976a8fed28a04f62f867ca5862a43392f9ccf143c3423503edd3f0170b1b2e3533a0cad8efbfd67026e8f53a2c16c6d838fb9c0a5bf182ce06304a1e97607f8d2fb52e02385389a24c9919d6d839f046127bc9b848715396f2d1d2c16592a9437d37ef39bd7d2cc02d5c141605fb187f51dc2c27546aa026334d82158b6c4683453dfea194cf41d909d1236c00b7d06be78827150d4a16602b4a5e47f43d83911e4fc52aefe080b0ec30ffad2b3e61fb25a7621dd3115be40c58c6ed5fb51ee55b14f7a14fa6124097c3f0b01dda122f8e6926cbf56d7aea8f634983fcb0325c5dfb
q: dc7dfe844fef142c9ba751bdcef77a0c0d406cfac2333d94ea57cd4d4f74c9b7
r: aa4bd24ce34f71d6bfe8c5962c418e99d6f001317c02af89d5eb85e150cc3efb
s: 6bdddfce0fb4b45820678f9fc96f671059771aceec106a4a4c040d6796dec18a
x: ad5beaea9d375ac3b2f051e4654eace6e69c274c30ef1e7703be7c24bf2637bd
y: 87e156b6ec44d4b2734e4d7cbaa421cc43bc30d475726ab3f2ac57ce87c7ff3e23b1a19eb3224ade9793bce23de15a4c5c6e7dd21115b9026bcf203438c8ac266137f92b758256f80c6f6f90a30fa8ede207c28f7a7d7206605ede85e3fb3ddc940af10360d2f12f6f134450afcddda5364f20fde312594a594c7e408e5f9497692063b75f29b4685911fa7b2e6dcf716c8c4db8702dd29589654b8751a2183cb7a8f59a079b725d10771d185a9888ef7f87ef8711e02f19cd268922169fdbccc3a35e5f84b8780e829ed1524a8102d90864f62c986552aa49af07fbfd5c003bb6bb27ad5f6af7805cbaa31094c7d8f40933a05b66ab94aa8633f4dcdd3ee6f17927e1d056441986550a909f401d81ba8164b8834aaff1143e6181fe781bed105a236409c9b148d5253dd13f1e944da61fc44b71a2baba102792e5b101fdd09a042e917f4a3d81ae60e6f462ea0f14f892f963443f7eab34ecc7c2214f65f4a4e03565f47a0f23cc7f4e68447db8c21301563ffa884e6b3adcea96a266c29f44
g: d713efad64b087c2cc9b5119f6297c70f61dc1dc532241f83000d04b1d6bca0997d762780fbd77313481bb90565a395aa79e09c7229f2b0d07fae2d08ad69565cdaed4f2fd50137ed6b0766388a7c738b4545f8562c342b09ac6644e3ccfc1995a3f5a214fedd5d6d5e631c728e87b65c9afa5ee20fde8c87962e9fdb30e0b3d974d90fb9418041493581fbadebcc17c4791e9fe928f41dbdc34cf0d30c51fc656d5e1c53732a3830822833aa96d0456f007c480fa747f9cb4f821d64b73314c3b47f333ddbc8b438d79979526e0fec835f33803c36c99586b87c63e91342594f785bb4a495e7af0277c09ed200c9346f825ca62db2063cad829ee1c5ce881310dfcfc6caa8ce70a31cc9fc325a7e2048b226a2fbef1c0088490841e89a2fc8e6686a27c60e4cabef23eb23b721c5d618426d4890038d6ab44ef55d935bbdc0376c4444ac0b85b872e64a3a58f55a44390c7cdc7431f5b53152533b25661fe5df3e634128836d5e6a76ee381445ab73b1096ec9a2b2ea3b02adab1a2df4924a
h: 100
m: 5f86e29f9ef35c4930273fa1b480f5485c8db0229d850549d48f4686df121b9ede620c411f80a355cd942273358321e021c6aa8b11a33d2f62dc506f74f20fc7200ab2ad07236b5dd3d77dac35598fa56169a48287603ad97103b00f8c32f5b455d0350e184a671a7e12d7e97b6de4d589642b9f3df880e0c8c473bc6142b73fe9d4be6c351b0ea024bef4f3dfdb6a6e47b2538f539c46f494846d18670dcddc0f2a9542
p: 9953d548a719f5b6e2d5c40c5402de5753dc86d1aee25f17fbab2658dac058434c0bbcc7fc60e6e436cb568f34af2be3526b388a32e07aca68bf24b0f955f4d92df4d9ff2909ffa251cbbfcb3366d1a912a6ee685eb29a35eba9853cbf509491a5c6377f205f69865a60cb9213a64d04b8dd6f399f5a0471d62077bf15a6d2eeb42f0585a97f7682783357f2822bd2c986b340f8974c53a2b1c18f0dcd6e2148acf58c2a636339fd461ce1d1aa85a14367bda77ede7125e846d93108a9fe4213acf6415165041b5cc0ad4994c812b4c74a079da16e021af1b8356712f32c4d3d1dc46fce33c5f568a8a046ab1b028f528636359616fcdedee98b16e7eebb6ba63e82e4402005c8f5340addb4e494f906730cafd22374f1ad0ab2aec4443b02a7493ed850481647b23b86f05428b1004085574252713682822c0406c86927329ca8294b6a8847724e2a3a6d274ead6608c96954ddd2c153747ebea52ed32ede3629aad22b5bb8258a205261c551f4db7e36169d3379c8a22f18fbb549fb006b95
q: d307be73371985389474519e828f990b87efa7c47e65162b7cd3f26eab91f471
r: 1c2b676da8c57ecdafab5988825e7c274380877bdaab4e5e3d949db999accc75
s: 2bf2af337e4701718c7a3531653b918cf4c11a82944e44f216f54a77295a0c25
x: 2fef5826efb21cf6fdad5e67a56d2c94086bd6556123133d922a9c2d7769db97
y: 799be060154973433a65df1484588e58909db6695768106373d0b7e5b04e191188ed9c199da9732eebe985b092d4f0ca804b305ea19de2b46b2d319e916e96767fb15fe76112d796dcb5aec065ea8ea3c2922b102265672455c1105f338ed4f55593deb39d7150efc230890e74d39f9a55e9138397ee4bee6322aac99d7c29073f16871c988ee0f00fdacaa9e730e72dcb7237e6856b6cfd2d61302481a996443dab8bf3040e29e3ee2e6ba33949289dded2167eb7be933042dbe5a0fa435f14ba703fd8b6b74f9f1e6e3d4fcf56da966c0c48314de97160a901b1f32b00605983e27875ca5d3cfefb5101fd582aa2a05d47f3cfc266eaee5a139842161cf3929d3d884912efc11db2c39f26e1a13bd69ca38d5fb9661cca518f15d3f7b2b710abdf57f9042bb4a8ded22d43d2b66ac9e6156f75f1b442bcfd2b1526bf95e959f8f846a4bc715f6503525406c2a93c287397b59ae820e1abd9771ea50f4e37c8796988a4ef7812232d991257630ccbe59910b4f52c001d6b48dd6836c220d26
g: 50e3684ae9af22039f636f7c47a7ec93aedeb3ae2199c0af0ea0ca0e6977595ea720e4b963d52c68506fa094e812af8b0a6f90b6accd87dcbfbdf857af73c21c680b5ebe349a141a78af969c5534afeb929718b09c1c0d25fc9107778620d8fb7fafa89626487aa36474766ad96bfe353c48c2421384dccc9e1b84ae71b18c1426354315e70ee02d6f2ee6ae33a065dde2d00240c626e6d9a53808af2b7a58e90ce6c5259b78a0c40fb53d6074afee5e29be15e70b2e3c33c753e37a2165e0eebd3c8fd3327186cf81eb9be1d19ef67519d12c1b40df715dcc1d822376180bf2c94b890d24bb80bb2302d5fbe1b175c206a785c9c733d01eb6540a43c3acec325a78f87bbab5c471945be6626c3e6c9f18b8c1bcf2aa771b59cc3130d3fe56b6a327597b724054bca2a9ec247b78aedf960df4dda66afff397f278de2c3ac4e9feed3e43a56d75d5f0a243f9cbc11aaa3b34d274f4e2e71d94f3e9c61957a041b1aa7e34a8c3556d8aa28d66cc590ffcf5b9868b8e58de8fbae3fbbd1218bd17
h: 200
m: 3bf1060d97176213b1879548b06188e007f3b1ce6ff47f262d51cd510d1e3eea893f706f29bb4f2aacf80fe973738a063560cb09528ad4da41c5ba92b72e4752bd983c75b056dfd1e2d5fe8fc712f27dc3fe15dae447be7cf85c82fc674dd087dfefb21c4dacfb33b84650cd74d27d991cd22e48a6f0cb0e521b503d1115eed48500efbc61ea2a8cdb9286a7a9a4f6c4a37d06eced08ba
p: 851533792e81443e6e477e8cf99647cbbcb8a028e871484e8eba49ba7bef8fcf248c126c644b4f0616e3f4ec822749623fe419ecad79af4dcbd16bb6bdbe7cb7694a6b991649edc5bca86c2eb2ef6855b8952326c70c3454b4dbc42429bd50ed9654a4901f1c007e4301170d78192f0e479b554f32b1d5708bfacee94a89c1ad8a522d08923393520412d4a1e47cd8679ae44a6bd5f531310b2898bed1d9490d4035ee4d9980b4b6f8bf23fd2bc4e5833844ac36768004cf977c6b8601a91a14fc782966777f72fa11edc8296d4f52ab4106eeaa00826dbcfe60d1c64863d77e7ed2a244d5ea7654d7c630af2ff367e244356afae88cfbc22d16ee54d7053d33b9f274cfea986270be668ae6c97ef19bc41d4f876a768e24fc9b0e45042868be36e950069f3e3044a1d41bbca352c6978e08ebfcfe3ef07bfc11c43feeb7e95b18692c2b1eea026b90be4c82e981ff8bef9737ed860c5476013c673dddd6c400e2cb68e35d7eb136676955f51598a48ca4971fc8cee90332b52d082cf738f65b
q: b7992e8e0e3bfbf9507b2d9d0882fb5375f5e0e9e753f669ce6344279fad1cdf
r: 18299fa7e2de9ed0b083d53b3d60fde8f53a74aed8a4e9916ef4c731cbfd5aad
s: a0f9fa736c98a106bd0014689bcd2685ec0e03d4952cecda22079070c568ee19
x: b186219e231b37ea1c7dfc17d3ccb9053eb90493fd7d24e7606a272c093ed48d
y: 1ea9ecd257062b07a62f835fe45dcb3713589307acf54c81239e33a8ca016f441047688c37f8839b291cc74ce19760087061153342716c00f61799cd79519ebe1da91c5094d111141a7586e35046f642c890d927eeadcd07c76a426f0c2b2c06946f97b8e7db018985ea13ef1bdde77f806886802c7e0e8b0eee6775c9e9cfe453a183012bc34eba355991c7d439f8b9a881379589ee968979b970264ab4629ff662b64a9d601567714bb27d82c46dda2b46bdf727f7b2f5130e650fb182d2b875bc0c39e726c763e998b5990ebcfa9dc3e60dc7dc1163b029dab939ee6bd89455f96da7fc94cd2c6f9ad187c31d6b6e97f17aaf2ec33b2a5e3d65ba170595d793c36a7d699633f752016d9f2881c73102b05576637dad84053fa750c427d13644883b4b99b412fc811f719aef5cf7766a5baa449c57495cfa3617ff7cb8473ab3e11ff03b5f545b33a831d7636a75512aec1092ed4deb77dd68c60177565ec3888384e97bfc7c65f9e856fee08782a0918c30195f64332f7b6fb5a46f883675
g: 38a1c6f59bac2e9ff7339597b2f6fcf6b7bc6272ca27479b99ef8a2a6ea6064105496edb6963287fdcc9a83d8e70ea1504abb2b505cc9ff6dac7d2e5579d72f7c3522d963b4fae9a5faed229530fa4a1f28ccfc0e1e811067ec91e65fff3a3353a831ab9af34965f5fb3979b43ef89c8d7aacba7c3a304dd6ed4b848c749f68749756ad8fd9fa23eb719f37a007ed9338fdd33e2601f184be60e6ba25fb0b58e9f041a25cb83aa5d86b622ff19e3077a9bff79e9c6063f1eea509e590eb60d779a8a00f3e49cb432c7dfc825bd0c93583f0e1c89e7d1acec0aec83003a928d16b4e18184c5ec0224779e543756f20951b73942e7ff89239136b134b08288e1669c36a676889ce4c2bb4a845f1bf44b6d9968ecea57f559c122aaa2892da42592761f65638da0c6c0ea2afbf78a05b8c42e0c6c40bc2150dc33a020d740ac0534ad50713d0829bdc4f7477c98b35773a958cde84d535b07e4108a5f848b25bd6d0caf383eaab4bbb49741a690bd745205bfb3150b5f6475a936df27ba5b0dc606
h: 100
m: 5bf1847e57ef2e2ca2e7bc0bda2439bb7371c0d638373d1618b0a4659c0fd6f2f525593b4ce336adefb8a8b465d7fa8e836a7142f9e53a4351856c268270a98cf824d1ccfcd1dd89dca9645040ddc989c52db0f6ca6a20e988912df86f28d2e57b53a0920be5bac2db84bf5525df6c2587e4c1ebcecbed27823df5c2635b9ffa635c0f68023df2ddbfac63e73d624c4d21c2a27905bd7248d8da2be324bd364ea8c1c4d3d1b1208dc5895beb52f57b73131ff0bc859d609d3e1cf4e3de15744f669325d18e6671e969d4ea70b7a3fe0b388a7720a722d65257b0c66167e716aeb292000c72925ed7cc801d63e75bd60b
p: bf1d45c2f14defaa83dedd0f963146938158c49880721cab543263454826bec0262a7be17dfb7a412728b1991784c228024b178fadd063a5329ab903823c2e22d4ab66ba73fc267288935c7b3c74b3606a97a010d635bb47ce2a5cf1f08fa0abb3dc97e8e0a2ca1adb0f7d4e408a6f70ca262aabd72a2e6ebc72dfc5a40bc42db54e8b3d258be97aff17cbe9255972adce24127e839d736af6b242b87a37d8dad93cfb70121a26126ccd40984b2c41605d9a6ba5d57be75125d553471110526539e59f938d4e9a58e439a8591626e9c189d16188fb28ec404377052a8251b43e0ea7ecf5c3b792fb02bd50739316d9d3b2234e7c4a914bcd59e09bdf7c67705472207019c384f6e6d3c536380beedde79e8e1b965630061975c54ef3a0228485261279d94e41877b00e31c5f85d8b0f5a185a211703b19b0aa45ed2b51f40f0996d9bf9d741291fdf943218200f8e3a74e6063d0d0cbf6185d752b6ce3b50ba6ed9806d3dcffe4cfd73a748b3443939672c8450683091f4da8938e78fd9fa4e7
q: bf203a4717e98b95fa06af9d41171e2737fb3b19f0b0be58f9ef46a583572c39
r: b8d5d2bde478e7369c6f431037405c6d96afe66c4417ebbe27dbb1074592716b
s: 250d8724c86de34350406a5d5fa0b881242a477066cc3884ea5261efc049f27d
x: 3a5415ab661fef04c90bf52ef2d46f01a89ccf571d936f3290fce5da0655cb8a
y: 3335ebc838937ba51207be4a5cc7ecdf6b7bbf9345ffe9e8dd992caa029635fe21c993b4a6c7f6ca6929f1ef9bef0da067437280071e7d1773e1ea591bc7658a0a88e4bf6ca0ade13ea5f6339ed0eb8f0e8319c0e4c05f40856da8e3c40de2dbff93afa7f50132e3105eddeb33ebef5eba416549b31afe1b4ff9ea9df891790462b94a860371d3c0be772826ca92968c9b7e6f38459d8b101310a9dce49a4ef65e767d0960bee4a9dcece1840260907d0d6e5c9fc6ec2c568a5e0bc13c502dd4847277b022a10ef564464a8f139d4534ef336fab8b7887e88392fa58fb1630e098aba05cd0a909606f14ef93e15279f818054e9090462b6a33ce20383b89c5cc4ba0e5b03d44a3a7df6e99cc555d4731a3ca406ee5b6bb3c4546ba620449bed3a4cd7982962e7cb8f7d552353732206d03e763391afff6421bf285f779d6bb01a6a164c8082503be965657f87a181c1f99d28ec4ced70aca4a89e475e5e9bfb8875a96509aea6ea8bad07cfc709ff37dbb08b5c47888f7604728a9eaaf62ca3d
g: cb1363519f3a5d78a8e24b3001c589c0a52b65ef4c52f67c4eca26eb9d82bd439b6772188f60c322709859ccaacc59c2a503813ea8476359fc7d75b619182ec41cccd3405799ae9f3e13e7b286a6725eb48b45c93c204968cf702912baf988e0259564483032de41b0dbfa662f8b295dd53094f075a37ea41e990eabdc64912d063dfc017abe7faa81303736b848fd9dab8f9abe353572c63a9b67327ae04f025ff6712adbb5a5fcb600309b32a35778d3e0a5834e75f5724a4f380f0153fcb7f8537c8f4bcaa559a5f2962878a73c9dc8f0b859765f6c14f72fa8ba33e1ea0c53da64916ffdb609f747559046f5b7bd2b6b46a6609dda375d4225debf2a6dddd9950bd2445b6f30674496543496eb4bf6df3e8c625a8d86f28a9f711e2195bb62be66c63455a85ae17804cbfcddcbedde633ba1d76d2f716d5fec58e897fc4caa7a67288fdd58c37f528cfc3a1590770342d1f01511d77c517b03c73e1ccd6f97332ff17c6cdada5fba582bb1cb38c09843f2bbe6b0211bd6d8fbdba39d1600
h: e0
m: cad2de0ce06aafa9772686be13718add0f2a7592626d4747942ac1e4794de1ebf19b6ee809fa3256ad420ff27bfec8f9d247949014ce52451844ee43881b877146a8a0527819f2268b4b7840
p: dc87f9966f346756a165953f8e5b69354a1e5796912c647bf0ffdede76181689354e053d09cfd49974ce6ed7b3bfe19601ef0b41b1e88656e31555dbfc7c99ce10dd61b7882349e59c0d23843421f0d4719050b933391b83b9506285536c272f289e74bb1d74e4419ce911286f4b62c70916645b8d12ff06e1af1519f4b627906651d90bd40fe6caf56098491b1eb45d1c5195d673416bedcb13b8f632e0f4e00da5147c4b8f48ae06738ef81d6ee63d5456f3e002ad5fc7968e86d0fbf0112ea34cf602d06691ac69a36d3262dddb5363cd6e493f329f4365a28a0dec7227008eb6a3752d8d5669028a9210933aef75125c516841e322f8acdf64796d2e345a641d5fb3a3e950d1bccfbcb5c7e784d125f728a9af3358c310ed05537e66aa3539b48bdfa9f597fb411e1c52e4e19320184b20477ccf95c0407f717dca500c7eeeedfecf29daf1833e85ed0f31b08b2784c8cf3bb87cd2fc3e19afd44d9bc35e9589e5d4c069502656bbd73bd07e76040fc8beac36a7ea36b9be10c5369180c5
q: b6ec58b0869cccd8c97973ee2e37010b9021abda0cf8c7cf7f3a60d98ec57627
r: 2e68a6610988dce53b6b90a8387221910f700f61039b7a1e7e4ea061bb60ede8
s: 1830e0b0665f20e98104f2aea6f8386aeee00c0eaff4b19b6135a4b0ed44bcad
x: 329f1b3c755a7cf792cccca87c92a72ce54a96fc4cedb19309e42efadff2ae8f
y: 5df5751fb98886f4c34e1bc51e75f5e04337b7cb0d7d4ba3d3a0abad5b9b205977955b0c7515024257ea833815a0afe6c2d01777b550444d3c54ff83d41cb889fd7a148500a29ddf874f4fef747da9ee1c84f2213643a200f81dcc57de3ed9697043261d9cf6ad01154dac9fc9c932c177cc810fa53564f3a157534baa5bd5ce343dcdfc53495826784c8a867feaa95f6c43dda4f8231f9c0c8c232f4966078d6cc65302f84cf85d9f99aa00158ce9fa789d8957b2e4e8cdd174b5310dfb3f560982f398b363d04c885c2a7ca8b80e8e974073217614d1b3fcc247cb78c55081c23067f55d457b85e6b5fe0de3c4f4e7a463022014a002cf517d09671aafef8dca7e3c16b74527b009bb9977be172e85994a3e7eb87a745c82127293ff9f9ee5c9bec5a38f0b3af5e8dcab229e3aeb10f88edee402b7a8fa8f2bed1b57a74d65292d70849a7228ba39affe2708084d432494b05ebbecd0c18599dec6ae1866bde89c59eff898e8c76894b1aced83e323c4926c9ffcfc1e57679da776c1d2bcde
g: 2654c54957d5f231ea51f06c3038414d27208d03178238c4113b92a2f28d0e74a82c4389d2fb4f5f15986a24a71f4fbadeb1158c244c7ecc7f68f252616dc209de7a459703c1cd085e99d48f0b9281d2bea916cc153acf6ef383426b0dc590e289046bcc74e8de8a7d9c050dfcad021ccfb9e00725027ad0c7ba202ac82aa36ab9f1be757aa843e5cf012c8e0fc143be56f0afc1ac109763a175fb9c4253879fd40ce26686dcdfe9c623bba02c4f7f4688cf3b82bfabbff2f9b3b8c4bc142d143a5c8cf634f55015c5c7a87a135c8c0c146c84c8ee721a2e4ade5fb84c935ace7be84dddfa744a6ad9412508325c7f965cd8c61fa48c42e29aff127f3e9cb3ddda3617bfc8f0433aa1cdc67df7b73d0d2154a1915e6eb177446678469e3afeb76b90c0fdbfeff7a1ae9c0f5f37f89d053cc394599f48d39ccda33d424776ad9f97e8369669f3396f0cebc496bbd563925d5838292ac5f1a7a4f2d943800c2ec44cf34139d4779dea375e90479aaab0934b574d5f0bfaa369cd47bda3b39b5e43
h: 200
m: c13052f7a9b02c725b91f804f703b7b7cd91265fa160b8a6a8d4b96b48d3c973c6f1781738bbc72734436327f08d34b04c523aa4d3daec93235ef68ca742
p: d64274f0b853957c3c4f76a4e228fcb99f3ba3bdb3b686f0323aaed4f6635319338feed69697c2c6bba0c853a2fbbe648bafd5e3f0f2fdf12d884b7d648d9c2ccb4d030ad3c9dd8388970bbfd832ffda49688c1f146c32c62a1c1f17ff24f5ff4d0eb553212163da141db6d9cf4e006875959b32c09d9f9111cf6782800fd47878f894fc62244bdaeea6dc27d15226554bd100e115a953c511455f5025937c16c9cc32c5a0038d1c250391e09613669a0e8ec94b6539cc6fd2e94c8c78cc5600e5a07f69012811f971943e84016ad5ece193b9d536de197f40fbfc1547328d59163479231015e8c4c4fa7748e9863d76825a0d26d85fdfc006d3134958da16f93dbc5fd01767abd812422039d3d4dbb0e2d7dba0de764b4a6b7345fe03d7c88d0def649532e7465339ed876dd6a06b4657f308f687237a3d102fa415cb2c3da3d3f545374ffc2db2aaa735a4bc2d377d21de36ea5583348a51c8691249ef2418b9e7bdcf765afce97f420d8156306df909d4783aaec74337e5102b261eddc69f
q: 85866b52ca7abb554cca8e2bd1c7a576360c741619c1c5828543af1854bb091b
r: 17681cfc288a9af204819850a801bdccdca7851c81f15ebd5e2fe8dda998ba26
s: 721971a5d0a5df0de7fc7bfa43a876ab9615472ea9d25a24da23ac3e7442b26a
x: 76313df7999a1daf6addcf77cb5035d85020b88c8b93d144c045d52f9d1723ab
y: c88d58b26f6f5d15d65b8e88e57b52bbb3f4605acd317dccddf0126d07da1728d8db9158ad6414bf05a21e431b5813e71a6136892ea51c31826c08127d0f03005420601ccf8bcf589eb57a4269b3c4c4b02f2b0c0c6c32bcf009138186045b7e4914c1b2e22d2444a2a0e13fcd6d83200ce27357c458082afdd42a969c5fa241da332252203b239f4be10fbc9bb71a2852717b88de58b52b8c3ad45c7095f258673a07438d320d5296574b76dadf014fed7122b32cc2f2cf9de43851f69da26411feb8d1df3c08ffc22a57d0096c712c59c34ecc5b6d6193d4e10fa14f8fffeba770c2528a2927fb5cf14a8ddecb4bf06084d07a08f67c474641748a33303edb7b6e58426d0cb2f1128b18cf62a5e4de47551034cb9fdee1eb6f43a82f47e2544acc0e7a1f4e33b3c87735bd135d04886f9d28ee1da564ea82e41e664b26da5d1099d2437a122c97e2e5f5d587f2934cdd1049cb0afe713d9c11cbca9dd4359a1f2dc45a8afc6587ba660d33a76655f283d9903cf96318ca2281b181a0410282
g: 54752997542fea6994ef20f0e6f4fa5480c9870da25b94a8503de5eb76f80a98c0273d626d92486a1337c2dae36678113cbcc243214a3820c8e89c98e3b2449b5c37947dd250967f0bb0c64c4501fb2668c3be02c2f1ab82689cf0ea023956d2fe2c38e99ab58ecd89dfac66cb92c7f30224bd86e42e1c9ea2c0ea79c5f7950225d802e70e62ea01e568a3f556bf8747dce52c762424b2b6aae25f89bc4c907a8534daca7f8858a8645a5319d22e7f6eec116b93c14ca8bc84d8effc25b3cba545249639ef1f53f10de54c9c91b51083b9f87fa6db438f17e846ee0ca140a3c083bf75f002711b1add956b5017131607d2df847b5ed0430038f32887206796fc8bb8428dfacf462644153d76215935f50010255471c771edd5b27e1db1e30a8212d7836061496df4603b54396da056b74173dad52edba35d8073d1f817b042e39f1fd1bdedb7beadd5cae6c115a3df14b780b15a6a840510f197a482486840ea097238c366382b08b5152678c6d4c853710e90895290e4a0641fd28eb7a91902
h: e0
m: 45f8963daab81ee0dbb33fd39d5c78531aca9254ad306e604df679159616a7b398d316d859b0edef37a440618217636e782cc9b6982f777cff0c1b9ee9c8886b6615fc1feb6e75b328eda66da5c9918889ad2fb1955da0ed1fbb724d8ee072782bcf1dc265c6eff7099eacd6aaf484b87e7439d78e6550eaec0c53fe69
p: 9be72f23b783501416b43f3261e247a91f35c6a29c2f7f06128235541888b955d6f0a85215e4af29f572863b9e0b6121a16f43c8a7e8993067c2ec6128c4cb05ddd271a15445e1a35ccddbb33feccd6b36699866681178a72174b918b85551dccdd708056d2d9494fecb401dd97dbe1b5785578902206487c931706475c27891938593a47b06a1b9ed930437ca26a6255be1a0e69df4390df1803f74049bb544a13756598083674db369f4c1c142f928382aaeb0e22687e79564bdec32db27ad33eaa18e93fb3c2ad27fcd9e191c305584406a985f068ce70c7137a10d2ceb644def0185e37d0357ab3b72af631c67d4695bae8e771a0e83833c32abfaad390218163e3a62e42a1180ddf57a43cef697bf7b53880de1f476337b836e4e1427e33985ad9e75748ffa67d9de615c258bf3bd48249ca57fb3a09df28a3ea087dbdc0d098661fd7d933007cb84618f1d42d4e3fe7b13c6498c882d4d24955ed68eca8dc90b785b3b2de4b217462442aec4a5551b1fcdc4c05f2410371f40206ce4b9
q: c61d00ea045811550ac15b93b7a4d917fee2e7940b2aa6eaae9113cbde6b7179
r: 4437040a80c38c48e0968937ad630a430c0b548008129012a03fce469cbf79c3
s: 1496011167df962f46f1030234387793f7380c4490ebc05004d8732536beb62e
x: f00d7ea6d38ab75ff0abae8ab5344d17283932981a6e840a21f152b2f9e4228
y: 2ff8c0a5fc1bf27e011d01b6710e03dfd86e5459782786db6c22b8862f12d600eae05b09f7294a27e10672897483649d0066fe0734df883153122e0b07b94162f6585f803d9ddc9c4911012e917d14d221259ca3ba10a71214a0b43f5bac72f7230de5e1e2dee30f52a3a6bf1359c6dc9d3747b7d5256479d5688435ca15ed4cacd07b886b9181604d00be4d7e5d60bc03d3cf16369beb611cb1bde5f75a06eadb3cbe56313e0bb56c829cdf1d1e7b9075cbcfd0ff49df4e3ff7345f8b21535823aa3cf639864a8fbbfa06571e56548ae9a2f3543d2e6a49c25accc8021f5d86903744681c70c859d749462f7d49f2b689fb8ee7b17e6c6dc2c765989d6b86489fbec179cf9d1a88f8f1b4a4078fa8576776cdf7eb77febcbe647e10e475eb18b65b310bc1bc0bd787134e21d1fd08549d47df7533e43f239f3f8337610703168b589a09e895c2b4c1c6122708469cdaff8e2fb094a7ed0283f9dc9245c0e178397238c457b00cb60bb59a313726d6c5f002ad4e110d55d20ab08ce0dc558130
g: f88b439c1d5a24d56b7da4dc0cd891d5f585a4eba8c04c9c21647feffb099cc4ae8c592aa07bcfaca724440b638696be6da9c63dea938bc57d217cb5601e2902d7058e3f92f228253cfe612abc2657bf78803b22bd7fe5247b2a7fc6fd63f30044794043fc7f09a4880f8b033234a482434ad118f307da0da05d10b7d09c76d80a7180891013b3ce94880ca0aef7dfb89e7ec7c38f5665bdf7a103aa5ea95d04a7ca851aa6c1bcc6d2d5c818ec43b7f1ea1ff3baae84f9253728705ce0b41e2b6490665f0d1718019a323a36fa647b0f60e54e292d457cfe3e53bbd09587adf566fcc602256023d7c4710c8ccd1076a7bfaf052b48774b3a447d3db1a3eabb3911d045202305c1c22b8a7180969c3b6a25bed606b05e010216243999a3550356e3964106be2d140a11616a3b0e93a030e65e38631def3d731df97d6c82744bd70e28d2790662ab8bd6066ba71cdf06375cbf24db30672c646f2404de8f83a6bac9bfda637d20127d690fdda530f843dc5fbc340a52a9e583381cc3733e1b5d8
h: e0
m: d8e89814a1c2bad79aff1dcb84cb4f47bfdb17a3f51e450aa6af09ec3cfbbf6c83a81c31b710c20cac01bd724a192492754b1d0527db6441c6b63f6ca174311a3b38a9c91af0a3210a85a15e6bd1f3bed8918efb4646f607dff24a02648aa8fc4d31075ffe0e290275c6b48338d33c55f99f5db6ce411721c7c555c3f05929426a
p: 9de469e959e408c0ed9e6a48b8966f8926415df7e6ece9c1ddf8dc5347c42f6aced941c4093db833a5192dd093ba5da0d2c3ecc9e6b86c4e8ee0512132277b82365e3c8648abeeaa4b0d833640b5c8639f41786cd237b5a67a43a6c4edee22527c0f35a84ce742fd48bb7028af4d638b0792de8ff89f41a5bedf02d05e5d604415387d48d26892e6fd64c760353e567ac899fbc70c4fc38006a253459ad1cb01f35fc4ed03201a66f24dd3da3a08eb68f69a320ae9f2a58a502cb2f27ced83e4fed0b820adcf1078055d344a9047c4dcf87b1cb6faf5b236db59b522aa954c1bcb5952f41f2393c898e72ceaf7745715b620a332cd0958cd6e5cb6853eebdf21a8957a69cb9bd90ed2fef1a4e14e23b074d20359b31faf2bf4c0b11aea73124ac73eef14901cea349452742f9fb6b9f5538c72d2c7c91908bfc50afd230630a87a76c392246fae232d664648af44565de85fede34fca9b20d50584ae6195b24e8ef554722cb28e782e6fd5d9dea5f3e072454a636099aaddd021a02ef6ad864b
q: bd64cb7286fb3ab2973b6d62271ae59a9f800784509cc6eeffabb9b5f4d5324b
r: b64e0bb2174fbec119f7fbf72cb4ef5a8c25c420e153fa3d299bb7886ab308c0
s: 3489553457d35b244afe5eb151ee27af3de2d3a665d608bb787a105370ef43d
x: 8073a3ae49cb8c9ed31c9e6e50ebd86d88ef9f3e91cdf3adb55a01d5cc6731b3
y: 70ad82a27171a57eb752fc53b4913e12dbd19d4c0dcc31ccf24b907e65c5f9515e89d8633396166cb44e83c6b4a94ef6a46bb7e4fe49a6c665947a7063c466c697ad598dea75f9ebe92136becc579c84ffce88a1c826574a987850352199f6b337964709ad5373870e158122b7ec919e84388ede9161a5ade3175161849300033c13880d6179a39040a44f6d3c25b0be4ce7c679c3c4cf4ab1b13444cb0ef2ed74fa427b7a0fc0f284180be14ddff22d0acef1cb480818f74cb398be50757ac8582ce70b71309fa355bd6d905c12c2a0a595886e334701d159dc6830d37689c4925a9bbc8d9f5404dc3b4d50919d2c3cee44598a261a9c71fcb8f866749230b381fe781af56412ba6173db3264adf1cd799e2e2bcef84a32f53786a81b099d37b7598564960f81b344cb9eac67794a643b6727b4c5b756fb14d306d8717d03e3f853dfb6146b611bb76252eeee1c31f7d305388077d85e23476f0fe221a52d26f861ed31ffce03fc4c1a4dd08e682cd7284c4e3c53161b1608c824ad47683056

6006
testdata/ecc/add/P192.test vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/ecc/add/P224.test vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/ecc/add/P256.test vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/ecc/add/P384.test vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/ecc/add/P521.test vendored Normal file

File diff suppressed because it is too large Load Diff

8008
testdata/ecc/add_scale2/P192.test vendored Normal file

File diff suppressed because it is too large Load Diff

8008
testdata/ecc/add_scale2/P224.test vendored Normal file

File diff suppressed because it is too large Load Diff

8008
testdata/ecc/add_scale2/P256.test vendored Normal file

File diff suppressed because it is too large Load Diff

8008
testdata/ecc/add_scale2/P384.test vendored Normal file

File diff suppressed because it is too large Load Diff

8008
testdata/ecc/add_scale2/P521.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/double/P192.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/double/P224.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/double/P256.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/double/P384.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/double/P521.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/negate/P192.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/negate/P224.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/negate/P256.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/negate/P384.test vendored Normal file

File diff suppressed because it is too large Load Diff

4004
testdata/ecc/negate/P521.test vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/ecc/scale/P192.test vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/ecc/scale/P224.test vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/ecc/scale/P256.test vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/ecc/scale/P384.test vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/ecc/scale/P521.test vendored Normal file

File diff suppressed because it is too large Load Diff

9009
testdata/ecc/sign/P192.test vendored Normal file

File diff suppressed because it is too large Load Diff

9009
testdata/ecc/sign/P224.test vendored Normal file

File diff suppressed because it is too large Load Diff

9009
testdata/ecc/sign/P256.test vendored Normal file

File diff suppressed because it is too large Load Diff

9009
testdata/ecc/sign/P384.test vendored Normal file

File diff suppressed because it is too large Load Diff

9009
testdata/ecc/sign/P521.test vendored Normal file

File diff suppressed because it is too large Load Diff

7007
testdata/rfc6979/SHA224.test vendored Normal file

File diff suppressed because it is too large Load Diff

7007
testdata/rfc6979/SHA256.test vendored Normal file

File diff suppressed because it is too large Load Diff

7007
testdata/rfc6979/SHA384.test vendored Normal file

File diff suppressed because it is too large Load Diff

7007
testdata/rfc6979/SHA512.test vendored Normal file

File diff suppressed because it is too large Load Diff

1809
testdata/rsa/encrypt1024.test vendored Normal file

File diff suppressed because it is too large Load Diff

54
testdata/rsa/encrypt15360.test vendored Normal file
View File

@@ -0,0 +1,54 @@
c: 3f8ae0d96eac5e0038fad507302138d8fccca791ee4540e5b345a8e6de77b226735c7e4fdf2eeff0998c762af21bd6a258574d44ad971d3a815ba5d06af2731341b1d56a31d8cc8f268d645bade13ab202c15a2c1f10cc5929aeece51d859c1cbf3e653fc9c7b0c0c6444431a21d2e49a9f518134e5808f84ffd82ce173a6da27dd4f9b68dfe6549d3f0bf3e7032cb87137c7221fc0b13db87231d39f9e250a86bd44507ae8022dc3e778cf677e0f38ce5ba5d6abea0f0c90ccaa9eb6a45cae1ac82974ee1f81e25eb3440c1dd9745421245a367e0b19f97ad86b254434408775cf233366f9bb403af17ead5773a62c36b50ebd04b801afae91c99eec2fe59bf500e2bd17b746738a95386edd2dee0ef36de6b831bf02de3cd3f41198483d063d59833e3985d9263d7abc742382a55a12e14dce339f11647dd5ba0807d6b9ffdd20e08c62b0c863f385e346d4325f6713813f4e8a617bda5b5abeff6fc425b823b6df8bcc7ec323f65b6fdf7be04fd0c9dd730f64e19a51336460054c36389c627e8dee2bfcbdc31aef20b9e051b10bc3675b40f64c744e25044dc2505ab1b67c3ea6b1866e76381dbe3874633f1e482ba29dc2dea743385ee831c74f2e3a96e65d4035aeda4f39ea2d1731a7ca2147c30aa9ec9d542db161b41af65232e850b6a60c214e3885df1e395423ffa201778735783d1e36028e51806e7453e5048865724c7973e4bab7cd7bd2b8a482be168b0516fce1e9636c760a8ff36ba21b315ada3355291e2602319e00d6db7aeddec835abf971ea3954fcf5cf623d5004a0feb4f41c021622b122cfa7913cd43dfa0b48eb3060b896d61f5cc6f5c9f439be80b413ab5f9ddae3b9a0e9a25cded6bd130d77ed9596062ba2f722db34122d3a551b607e7cbadaba655b33a537fce67d5beb6eabf0fbd3671ba50cfeab8cd2423f37157fd43f1da2dde422dc2510d66edf206c9e1af5a7abe803e33997ec38d597b76ee2ba087bff7df21dfefbc51634ac11403e469f2e1ef7c83b123a82544575f98c337fbe2903348a6589b1b5a0c24e9b27a79dceef82b3fad17de00b6bbf5aaa936c6483837e5ff1629011b1d36519939b687a8600ff385fa88fe1315787a2baa2195875e62000932093bb15e428cd0816e449387fb505a02bdbb040744c02f80100d75cb0050f3ad89a4281cda3548bd9defc5b3e2ab3dd946aa324099ee7221c163746fd52864b6f5a73ca9a436b11c5570da1ad76e0717a26384893e10fb25a58c782952c01aec8af2ae28d4905ab936519dd8788d3ea02e01c22748df87ae842c02fc621f3bb3bf0262d89eed6f3336bdfff130fa325bed9422d69fdf35ac10e809659930ed4ed31f460f826b75389c9e1e21be412b229ea43809f9970d0952a182c2919100d9e73aa53421b8320d87b6d31584728c39b265d65f0e517daa2c3ff7a731e88ad4dfb6598bf9b45563ba907e756163f742b2bf3e1ded98512f447c689d7dc14c9df332cf986144b393faa884b85a1e61fb832617221f60e0fa4f225e855430549323e2b40fe62644d7c1acdf6fa5e044664e7f39b1f08f6bc3d527c739b169e6239fa4b47c7034a8b27d51f4e5d93e891aaee2a653e3116cd1fe51f1807f47d2ea9e4a8ad04f287df99131f774f53e948635812116b5f4cc1a9d429575451307496bfb7438e4dc5913885be21a702ba6056310aa034a2667eee82fd49c0e7b262522436efd6b1540301a41fcf1248e730fded09fa6a6ce0aae4c840b45218c004b842bce223b86ad7ccc06f117340d165fbdafbc7566fce52aa7aa97731689434c25f63e4825f937ffc54bc21130919b7d8bec5dd4be7149a42ca1946a403fcf47c756d2c2df231f177b13123fb934e445bcfbbf1e509fad3db3e06791e1f6bc41077103f7068d0f974b17f84726cc6b7cf61868d12fa4bed9e233c30fe97d14950b7e333fd4b91f171837e556f76e12d569a54edebd12dd99c759e7b2c9709eaeee6492679d3447aaf9e53c3e7259180beccd601ebb627758b853ec07165d2c507ee2710cc3e9822597d86e3599af9f3b84cc210e951442bb2afcac966260f02da2a4720d32306b11b65cb38f29d74171a2f34e4806a31560eb6f66c1ac56a3102ea470707d0002d84adaca34a16091bd8b9ca16e3f63f3123b69928b53bdad94a5e1df599195bdfa922e91a70b1d4402072d95acd6188d01f6d7b9142b427ccf681e02f49ad33c6c57f016dec3c3b0e6871c1eb9242d15fe1ecb34668a918464c745e8a9add0e8a3d49813370a7b9b69308a8968d9b356e94296f19b1512a86791a59709c63eedcb95ce7058882713a00d032f9e4978a75e4e0a6bbb9d967d9884736ad0942f0541e3aa9d77674f2dce4e9daef49cb49a390fadf0ff0d20497197fba945b328b6c825898be6942d648103a99eeac70ab08130458e91f20e587f8c407364d21ee95b3d94aa6933cb632c8385b4a4a557a25a2e8b45714a81fe7879776608c6fa3b26a91c2fcd0793c1d3a925f18212b04a2cdf6910ac76009863e60a0bbdf3c79b705b92767be221896503675d4e87f57b33bf361e80aa56bcaeb2fb5fde47c7f6af9dfdd751b710f04646be537776044525f92a7cd81c17be3276aa95f2c1f911d2156fab30094548849f42a0c667c503dd8ab9f6fc6502beedca5ff399cc124fdff1ce2ecaa1f601aa8bda0a9a11c0
d: 682714d05d3c43d1175e8667a1126015c8cfc2b63b6b0708af4678c779716e24cf987d70ac1959d1459da6e4d30d5614d61d1798d9cf3fa7c3ebc85467091f72129c69dc7a223dad7a3216743d8ac2d3f2d60d96715b77d1039c20d3bfae7d5286bfdc35650973ff1e3af4bca3e660a79ca84416ec420409657721c1e556d2501994127d6676a64fab01b85036646b84d0abf8fa34d56d3ff6e72447e2b2cacee87518b2cb5e92e3326e9f2647188123ebe849480e93e7cf26ae2cb014f9b8aec7a28e10b7b88df0f10edba51961bdb1e1eef2377a244c6ac665dcf232080c898c9a3fdeab2053cd653a95a84c85e66d66c593e8702b0b7f8b2125a8f2796cc51225ffa9c1f3373dfd31ff8a3b309ea94319b7f700339d82424dc6be2f91db72d965720bb0155a2f9f0ad1dfe6e1ff6016319fc48bc327864585cb59238b67acb742c3907c67d09b8301188099e7f5667d688d8998ae171363ca2904c31a0533bf525bf40f87ac1ef325e3d75bfb8f08b928f86e7cf0fe1fa578e641a81bf23c946f14eaa8da26b893702e2e0e729a7897c74c71dab96cc9c3a5dd3f1c0bc5845fab150d22d0785c5cb2e51069d20200c641edd76e70a9851520d6ada5b98d38536c777f55c10476fc71022812cd523d9c8e9dd8a40b128aff7b490b3390ef8659a0d873194892ae0e7362199428c6c70f9bb4b99b11ea1f728ef2ee3a39cff1f43a4750b75ca2968a11100fbe9de229ac0c35b6f2abbf2458ad24903d3326fb5f3c660d03d735f2c942ace3c495ba232409350622764e1ff24b0100315b6240e7775cbdc4ed918e0fb03d09f1b47dd3e4edc1dab70e370f3aef7f7f4a9f36b7c81bef41ff2d16ac5a00750eb3b67e8addc1ab287df52ffdb6f654f2d11f9eb19ff9b8750cee881dc210cf1a1e15847a7f140c43d57631e81b8889df136495aa21457e2c0bd7d7532348f3a844faf5c08c96f298db0277973797b6b0dac33e0adac589aabfda4ef109c7cc7cd0053f4a40b93b74698927c8b410243f24a162b2393694ba45565874364df5894e480d959a7bbdf71018b6492e14abcd0d3fcb72921cf90eaf31c78f3525b30e91347447ba1aa47dbefac5883916891f5135a3469f3a76b0f83d2138fe98a237b7c85166dddb605b8b189a5284c3223dca83a5a46aa76aff54f0f7abea54e01c50ef7a2d425140fa6b9b047feae02fef9fb942510863f6b11fa6def9be97bd324c564b08de2d2ebac039fb5accacbf5b8ba4847bd226c4424125b9af67142f65da3272eb15549766ffb8757dda2fd8cf691d53771d590f6c6850027c62afa92a38ecf9b89926f266caf93932501d8bbb02d8013359f19bee550f86ba9c45a0a71518941bf29086107ab704161b9de9bbcc9fb8669c530a8f03d14993644f331ce484fb53ea7a6101741136b56f7e0dec97f6483e87c1842ba654d077c3a49c0f542b008bbc2acaaa7d856c8fb494d42eb20591c7c8c8ce550386cb0eba70f55d995bd72db48b641007de2503b3bf327e6fc2826fe7c66b375bc6c2b486ff1b0c5b140e5adef723d0242bce3e8d05f0f039a3fe7c4091f5acfffcf55175b5494d589fa0b907027c40c6c387e80ebb07999c423b57d37b493589c9f3fac1850dfaa0279eb065239399ef2d04a971a7046b080464a2afaf8eda7dd86f79afa8c5046f3f7b874aab6dcdcc5fd69388f8b3215652636d1c3b9e631f1e083ad109fcf0b7fce76ab6118e5fa421259fe95364ec4249f7af640165cd34a9846d7172f45beb5ab098712d3f6f62e1005f3c48568646848f4284fa7742d37ea2c06cbf22d8f19e53279516ad9323aa483423f1321e5a59804e4337a5d3893959f3465df79b9483f6723c62a7dc0c79a41e9b1c16afabfe79e3f64a7f2aba7f136227bc60e41f16803d4ad8e7cb1f5fc6434b278d8f0298ec77a89d407183cb4d4115a4a5acd24c18fc6c18a0fde7b1c12565b420c66df7154ef358ec324c91731225de22d735d17a26de57ca8f0e463b242eba7d1c4ae31d018870d30da0ed553dea13e82e7f69678dc2530ab2f2583a324da34ff8127121ec24648e916b8c64ffff04cf6c20d2b1c9b065c6f494324ac87f3b67daef9913fce10a751ae1a5befb5d74541b18da96adaeaa13400e41bd5494eee734a6e9491136f31811bd4da590a095de223008814a705e779f4d488e902b255290c04107a6070df90f35ee075b796c0bc7ddd052837a964ce7b44525400800e736b136317db57e3800a819da74d636b5259e4e728cb2aea32dfef9f3cef4dc3b3da395c441157aae2265d580d6819c84e749a4a3e1b23a8b1dea9d15ecc450257cca302fec490d9414d603d1b55400e27ebea8aa5af4d44f16a6fc4445723395615f10640dd65da06d144e5cf15ab7bf1d853765e13c6dc108395f8e83d553938c96af94bef7e003f47931afcb0f07a89dfc06e9e7da11ca2e1b7da013cecdc49951be9b15536321a5be4e79f7a5103bf9b05d25acc8102db7e099d9de3ebd7212e931a5e98fc0c34ac30276c08d4ddff7e7b112e20059fd7681851d662ecdf75bfaecf2dd5969afa02ba7b7e5949bc680070aa9ef363fd5284a33dc3e8be743159ae07c6f7e1119628e07d644fa8b6afa988d102f47495b72270c5fb05306e4cce8933e17e66f16abc10d44fa8923e7a0e594278b34d8262277867b6022ab91ba8d444801
e: 0
h: 200
k: f0
l:
m: 35df7bc3e83407e1e7b88bbc49471bfa1d257d024be63033db42b89d505d5d981f03de2d275db2594c1db7645c51eb3da4595efd6e7d0a4adcfa05bbd6ab3f30ba0ac955da381b8d93c7
n: e8fefeaabb2e913e74764371bbff736b0922ea19fd36f7ec57606706736cb3b746dcbdab13859309a46987806fbb02f48081967dfc27ee06767427264db712d53c1b5f6e5930b9406225560a855fc6aa34192b9768e09f37bef61ca92e04ba3dd560a3358f4cb27a5b6303b398d7e9c080356a643ff926d40aa168a8f52bb05dc78d2d97a30f125ef207dbce1331ee2f3954ac068d595c0b804595df582d23634bf44404ca0b2b7f6ad582a11ee368f8250484f76672d7e66699af73a4167d5910827f1eab7e4d42aec42173403c0acc202a1ed0b6005641e08c1f8754d12652b5cab32e1851a466d7a9d46733b72eba1180b8f4fd83870369d8707fb8b7266f8ff735209740acae6320d3ecf06f84a15c717c70e6c950066e08bf5ed969605f89172b5a32e6c88984a29caf8b21bffbb6e45e6db7158f645c620476f8e8bfc1a22e17efc801ca9eb886764c3847b7fb6921ca784b6d5528ebb49cb8f0bfe5d5d0cbced76a14ef23ed070d422170ed2998b1289c7fc926509080bb4db8f410fdf60907a295a4b2911382bd92a2bfe735fcec52b5d23d4de7894b5e237447e0d29b0c9fe12b7619d684f4f856d09fc5712e94f024994ea52bc0044c2f816421fdc4c2b78a1cce09286a0c922f70bccb1b1d0c650264b2e14b3cdfc7032fa496a4c7ff51af9f35eedc5b737dce6bad771ed0a08b70f7da041107419ef1b6cebc03645a8f8ba9b6200b934a783f53076abe8d1fc0d4dee336ceda8af3889d2e50a8f3347a001620a98ad425625883ed8889481cbdb8e66203d461afa2b3ae96e424fef4270d939a6961bdb691a2bb9dfc7027b8c1048d4a5d5fa681fa8962d5ed774058d8b1b0b7a096dd93ea52499675bc4c2b2405648197065a3730e0091bf615851003347a3aa055a7c3c00f7eab27b517324ade9976c448d22584787efbbeb20b525884127d4d223518636b2c596f648c0506b5990e48a5f3d3a9f3028d6de09e69bd080d776410fe66424ff17a3112094219492a9f42915edf1391583a3a0df21873131a4a5ca63a761b53c839d8d4de2d3bdd72ece6b5cbf865852eaba0ce9fcdc3b3bbc650d2407f4d7e91b6816f472faa16668eedfd78a61e640eb94b0c2f8bddb4a1780b194e07d632d708e3788371eedd01b6c8dedb236f2913b9f45378c35eb698d1d4e8f2b97c2a5f74d790ad5b53d9cd03ea6ca158bc9b9c400d83197d67c963568876d227640e1092bac8da9527a303ad30fa0ee2e24ac1c87eacba88ef294aded1a05faa121fae8f9068180b93772f1cd8e83a8fe5262fa5ee00b4c80bcacc6090f4b8616a10cbc5b876ba3a8b1871cf19f769b2c9447f1e186f33a0a45a483990f13de470680884a0bbee6c222ce5069a187df840ee990147ac328b5cb73be337de12959568ff8ffc217b7fb2ffd8d519b4665399bb05a14d39b54333efabd6a253e1a74673b14e442f06383cf1e7dceb9249f1c5a62da2b75c1f71402e8b23a1cad54d21da4ed13de6b59cf7909e6513c2348d323a1fefe26b1aa760f7c666eaa78390131d120c4775eb434cb8e429756c73dc08caea29068611dca69ad01a164b96326544637a9b255dca8beeda3264cc82c6306b717e238cba86a47d2321265d36d01f40b44ea1b675a8ee162f00436da354b93cc95c78cb0df92ae582e177b54245e2cdc5ccb1b37af487d02a984a91fa655dcc629a1d9738d02b7f6ba5f0b64c6af302dc5009a1fb1797ec5d8db9bab22cd124172c990cb6accee33ae90ffee5ec5b684e5e8a357d3ac7ec4f5d5774d5a6d35c04d0c7b42dce9c1d1ad4ce1414043562078881ae37de810144826163544c1473c3177ce960a09beeedc7674b62fb788856ea6d921546482cc071a9253197be3b78a82fb5a48f66c563bad1be37ad33e3afe0692abd875a3e8e7e637e4bb53abf46d99f94331fd10f507b3ef86d8bc80d22c79e90ab2e8567305d040720cb6ff5c96cc7c79c8cd0d340271c3453dabf7107af38426485762b13885caae0cf512e38289e4c049a7a56064f4f0048546d626573f8525c0ac206ac98ec0d7d8996f746ff80395ff73a7dc9514cd2aa989d140c4a4395bb0f111a2d0550609808709cf98a065e96c4cdfafb1090e42e6e07ea8c8650f8ce6cb03755cd680f4b1ad1e3b8181ff3878c584ac24a16bdf5e4d02fa33442645340f1cbeb6c161b62d7e6330a76b69c940778d40ba099b014cf0ef9281768ee8da81ac8d4cb1b4091d98e18f34b0dd6c0b0709ace0d45dd1768663efeefd0e154955b160e8884bd6e7439f3c921368785c2faf271c7cff21b77685409b1540c94255024783a03ce4a2904456f3af6d4eb61d7b2107d2e2a7eaeb54f9aff6623ab9c2a842fffb196a70b03b7f009817141e4a8dc882e0191dc056d6b851c56e923defa6a5fac66b3ff2468497df9780706d8795ee86001124fae742bcdfebbc444573bf9e2cdc720621f76351a13d6e0e062014d63936c2658927073f181e36c02758383c8f08a6b2ae568e9377a2e5830b9f315f5d70a06b55fa0427d31c6aae97e7af091ab46fd80bbc670bc0c5288c42344c90ebb20d3b067e173deddfe0943997bdf07de71a7bd778b18483724f353bc2047c877224c3f7a8b9d8dc7e2a900fb3a11a36e96b28dc284987b8d47affae79ddf6d1b49bcd352ffd19f20390536b7aec9926ce087b3b0879c1e97bd75
u: 119466eaf21166509158a5491f62247a4f60853461eb0c5d7c9a68e2047c9cf57f31d835f3df592893a2c4a2755726e601d6308d4ba52b591629c2b1058a967d7b94f4a8a6f9b06bbd5f28257f99c3c2b28cc5e3a56463b6f3fe225e34ba3af5e26e097c8907e84c7e8cc83e4d4c07a0b6865369f5e33627e7e529c2558a93fba68407c8da8e6dd8ed1f1abef5167a35aa34c43c0975c71c82936a9a3e1e3929777b5896227a46b2fd8db565ac88fe8dd333e32bba8adffaa41bf9770cc459bfd778dfe08fa97fa48d8310c781dfcf4a163d1f1af9a8d1be4fcae0a700163ca2eaa6c351fd8bc404cb89afa590bc15d370dd05f43eb3f9c9d487c66fcc3ec9a826813d21ec74f6b16e981e6cc7b548cdbbad929d57447ad7bfe8069108ed3e1cd5e63345b092ef1f98c5b22eb6c546cf75dbc8f31196564747591dec0ae73e6585f7a9c3dbb4f514cd46c64d816f948212799b6d983a82213b3f6a87f80c5d5366cebef7b23003c2255d1aa4b3b4f1621f067edbe754b15f2ca3c49d757a98305d1f8e4aaa374e6d8b777a3bd95171a9f5ba7a788b42a19deb72cf0e69b1effe918484f51b3600bd4df6e55a6a2fb98268b7ac35f3fe3b90fe8bb2c36a691a725e034c44c06d787c0a300a4d72ea0dbdff23479dff77d2f902b400aa85ee155fa8b29231f625c3d481b4e2214afd7a703e9f33cdc5d307bc5fbec80a609a178b238da01049ede29e53f44c39a23b8143ec50b0de3eef6aa426a608616e807ea2c59de348f5dc315842ca1fb8150b578f1d8da339ac8eddfedfc1a583e57a30ff65e8683bce7dbd2c1adffe1c0d00685c56faef7bd4a67dff060d8b734ab39e78f93f3fb6319ecf0cecfa0a6ce209df8f1458fa734c830a58c45558946bd5c88c637d370e686eb1d7d82f9f73188d8c19885ba12f3b6114a3fbb5a9498a51dab05f65e2547c8fcc38192f86fc88a5db3434856fd082838a1402801bff845dd2da82ba29a787929e35187e393e0e16b3b421b86788a1ae7530a26adadc5b67617714de8d53cd78b2c4fddae34242355bfa5abc75f0722fdf66214bdd08f5d29e10032012d30d2a89089ab7dc6c522d4854f066d97b7c92262a98af42babb6259368364dcda365ce06ad309ea826156b0a28314f01ddd25ea9a1c2b987936b66c4158a24d02eb01b53658fa2c425dd6b45e3731b38b7782f0d39d4d9b77e6f0036b01d45f3fca43f268de3423c4f7258ab5ec48fd0146c2f7c6ccce1856f32ed98fbaf61f6aa944b21ea2b5d7b0b174f22f79c90ef186903737583b4c02d19ac4974ee7e6416b0a2286e1869cae6ea2e89395c689ee4850132f58d510a85599eb7d2964a29b4663e71e8c2416b423b9d5a6f710ac31251cc90d9f62802cff8ddd6c32fb60bd2dbd20cd0705cd2dad2bb4f8047b6b892e343dafeaabbc6eac782d0523faf46ddcd82f2b5a01fedec5becb1718ed0b9c52b4e580bb01ccfae8729e3d504d37e6c619786e30fde9d9519bbdbeb2a08940fc30e4e4f528d24d3508f04dc92d4a9d5a14224d9744c2ec410215aa3f8f69023c4b41b3fa61dfdc00e011a761b5e5c65bec688bf4b1c6e7c3b439dc5c8cb10985babb587757fec93e3f60c4e5e1d7096697ee0e4144056aa4646e1909a76678d0ca3997b84053f85dcc5343e592cf7231d815c047af253e1a8e91a7b02cbab5337b3375bb99399f4a57fa35f6c07b94e1c85cb388259fa5be4fd7e6735572c983f0b0f19294d9d32c691281168936ecd1464450d039a8d5f04af3ac5803010a367294a607687309fe167f3eecbc91cd00a85e507cbc05e4893f1e106008d6bf52a5232af59a9f640a57c6acbe68b53cc6d85ad04743218d07c038515d620512738adcfe61143342c1d7d69282185da9e927391ad9647f2b5c2d3a5f977227796e8d449d8a0d93b2aeda1ad76458969739ea8987854ef011a9d36e9712a88cfe6560fab593c590fa6656fd3d17944dff2439aecc4742b120fb2b3610f40e7d0f471895317e3a1b7c47c2e523d257ec843752a3af8cf5d4d53377bda2fd9ddaee5fe28ee53b3352aad526177efd5e7f4828bb3c3673373418847ee29abd583e938a585436ff604f0871402ce351feb2ef414c2a55e05fd088748f889c6cc348ea6f7c048159371d0ac286c195acfe9f0263002500baae08bfbfca70a30dde549ad6d372893a0386d9e687d3c769fa02628757f4cd9994939539d49fbe4eb91c6bcef5815cfd0baebe8240b7dd9168d39f55042fb7e4fdc8d3d6beaab3abebfc50b65dde75a3afc68814dced2f13ece3f4f900913a803fd13a4406626674da1e6e6401fdde2fe76de4384d697cd0ae2480e5972fa7e06b5d001ab12899af3fae2b21facffbc3da558de2bf9723f2a84f922a83f9ae8a14c221045c9db37e567728ae2b2b799e6d1d2337ba1ebcc69e6f93c356cdd1462db63b384d129d235c022547ba22b2fa08d0be56600931aecf7602e69c3fc4d40c0569068945aff167b6dfbc467ac8a6971974300ab74fe9792a41b232700f25a674d5b2ec5663d80ba3e6d67503dac0cb7785fd700189ae50fba82807362a3e4fcb6e75239bbc097e0dc72cc05b6ad87b02667943725471155f3b6503d235c722f270f9d19c1a0637a8e9863c7ca0b2d637107f11922d4903fe4c704e66631006ab31d5b87c358b93356ae306844490fe2d3ff4f9fea0c
c: 52a87167884ece7a6d073edacd8a53bd926a383f3ec16bd5a19a2d7277e767953a55afea933b5633c7c4765f734958150cd9794a72ed391ceedaa429c321357033539634837051283c75cdd2a07e6b6a9d72030203cd42cfe428b38e9ea38defa4c3f4c9e0f3a00395cf166700bd013800cb40ad7ac81ac9c258955812b784232d651a623ed010c9f0c9c646157aa21a6c22680c192deb3afe4f0ee7a3b28d0411cf1de2d87d2b8a20ab126ed7c627a1ff937f23bbbf60741ddf10267c0249ca99a3149d8a5bd7348e3e70e9156dc89547b975a0d85e000ea41f0926eb424a6ee0a65f7092e0b3bc704f8ab10332bbaaaeb8379fe658778c73a37aa0dd877b64f1049577ef158029294bbe5c6f36b83d42cf137c5425a9ef44f37688d4fffc730077c44da1a5eb97fa00eb8370d33d9d83642d9fa07aa8dc908f5a9fbd40aec89557acf25d3b63e5bd351c63120a6b2ef446c6385f00fb6476bf4da17c900af0d9578680753fa3e18277bb6c94bb0df21ba3c8feeaa119eb7a6b5d388b73db123bd238f0588b4dda62171e2bf15b716f9d468d60075d7dd4804542fd4d08709a3aa9ec528561bda9cfd80ea575a9066140981d19907f7ea1aeabd69a0645c4c43fe2e182cc8c44e87e568367250c8b9c0da250b0bb83a02182b8c79263fc1dd2b99c492f3e9a16bde0c80f4f75c2dcee677dfd9ef26c75554553bb39c8d2354e3d734cb54c0152de4e172e997417c0de35d0f1631783b0d21d6fb4788f1f40083ed7ebc65d226336d1f2453b82b8fc37ec9c90bd41f1a16b0994557206c6ae9d457657a8bf1bf1f449dc3b1ea52d464df529c24594b4c1838fbf7f67c0bba119eb7a559f7cc679292bdf3f21b578a3a8639346468951d6ab70cabbcf0a308fc88806acf752d17eebcea815511543006b5e7d7ba3aa6d62ae34f280be1ffbc82bbcd101d24b4f56d8615be6b126032405e02230b0e34acbeea0ef47e34f44cc5fae9c6c4b6a58814fc82975e7ad289912eae812879ad16ab9ab2a7d2f56636df0b23e9c4becd57a522267d862e56a0f1d36ee5e4ab593e224fc8c4620b16ec1ded7be5c972f921c0026d713154df2fb46d9a202ab2ffb8f459d39074716285ae3fa7504ff8c73be217fb687cbcacb8a4e24665ac815333d77e0cdf89eb01aad0876f96b472d30e099e9b811a0ad20f5c7583ec8214b35b256c122adc1f41ce774129d2a1442a5ea00044decf5b2f56401b165cdc2c9a53366bedbadf455529ab275b84c01788b3384b045b70341ff3f5d7879dae72fe6555a7d868126ac1b0202dd7ceaf0923f421ac0a278ffa79cffa46aca02016228526d0f4b76538000d4bb9d190d22ed281ea01cdefadd15fe69f4941d1e5bb8aa6d4ae6c6b1d8f9dad7105427fe57510ba60eceeb52d32a3d8bd070d95c99fee91f75f0e6a76f4aa558b341c8b453a671e2fe99d7abbcea317314f6dcd3a95149a04fe7af7267dffb45a075711bd2d6c619974fce5395320c96d32badf1a98db6a5ee68e61d2fd29e29565735af259220b26209a2ce71192c813ec06f570533b679cd38164845e64c307be779e9790d6420cefcb116e9c944dc78ecebcf2c37cede2b6018cec82744babb95491df9a45a993b53e1a896463c6a57f9e265aea307841a1c3dc8bcff6024f6bed13000faf05b7f68c7da4ce1529be96106116c3b530067d3e65566b1ed05a727125bafa5180edbda1f31dca68f597f5eb1c0e9dbb3b1df971508df46ec58b422e821583051a3694cd95cc793ab4227ec1e30d7558c8686d7e237247836b816b8b7f15844e54ac002567419c7e5a8538cef4e0720dc77454439b07b7a20dd39a2677a48d2e548afee794e0941384e4a402d3fc4ec893a5ec644522fec9f7021b3aec3f64dbb377971e1108454faad2cbc00e047865875466905589f9aa24f3b3bdad3d2f5141e3df734529c82387caf8cbe43fe015fef1ee46488b355cf94faecf804e7a03cf00734778e3e230d43c61202097ed35d4290ef29556952adeb74aed5d07ffe592229236c8c8a01e424ca25408527d0d48470de08187df99ebe3eb5245e8b48f1dd7f468afd02432a51880c25396b546b22544032691a16951554cfc82931ccbbbdcee5954b39c41cb6bd5ad06cfb39f682cc4f37b053c07b2b56fb973a5caab5a7cc2478949eef26271e410aa7252e71cd48c412ec7891969a8d36708b8a93ddb41e80d8cdce63ff38fbd0eb335baba181e46b26dfd7c559258a0ef3589354f863bd1ee27cf9a2f817a28ca71dc490e5dc4bc4d65844a78fa2f458da5130351c41fc91eb54b0dadfb4281a5056b1095817bbe3665972d55830ee7cdd28e2c964e9e497740fc7a2ae04541cc3cefa222f417219f0196dd65f10052f513697fefaf6279c0208f61ec4b470477ad5551cc9b34c1cf36e48f45308d50ff45ad89dd95723591d16f7437269eb3beb9ce9171f3b0302806d025e4cf4c500bb3de42b29b641c2027f0ee005530ff8326f40d9561daa26a3f268706e778a461b114ad1a1cd5c2108d9d35fc8fa6cf85235c37807c889bf438694780c3696d59abb6c9a0cf08a21b7836428e63628948b418d2eaa6b532f3495a3e25ff779a0c2da48980a7872ca5f2b781ff5b3dba67f1968d201c59d4a7a4aaee701173d93b141a6abe6ffa0a3a91c138926b01a0186d73ca68a5a10e29b39688f83b781
d: 5ba23e0a15cfca0e099a1ffa93153883dc781f9a476ab9f78414cc9d74df928ed68fec6a238281c55e1fb4eaf289c480509e734c7c6370606d602d7b7a9ef8d05ee5e193fa46ded854a4a72a7602063441d3f1b7a553b394da984b925a6d33da1f5ab766d0062421f2894c889fac4efcc28761ecf21754e96ede234c69bf32c7c59265a473bd27d598b7bd7f29744875b9c91c1d86a60d57d02db8b1721acf76403b84667452a7e860b568d216206a92bef5902a5ecb981a29f278d40be1f4abb031ff174ea89b434ff0d47bc5cb5d131c03fc253fe8fb7c3cdc758dbc39bc4e1fd2813018c200c768a2308aa7fc428fa4049d3327552111ef15dd1f83055265e121854e530b0d377110e7b827615b2d99f9e4e7cbfb46fef2d0369140ba767ae4ff3d7f1a34621bb6e13d596028cf9a94d1662e286bdea172c8d15c0c15db0f63d8f3b390804053986f1c33f7598c730e6ea3154169472216881bb796c1a21834fd43daaa1926dc2f97b85c94f66726a030e67f86b8154f14b580b52ae8fca61a9326c561c4747462333b64cc1496507f0a451dc37814f94c5ac3aece8ba39d939b537ac03020c930d9844c340434c706190443d0eb8dd9f830090fcc6ac6a290856aa5da7c3f2e39f44f73cde2555d8037c6daa4f03246f64e293992bbcbccbf63f63082ba5318928551360317a6eb4ea94b97a19cef54ac44ec51d199eb0b5896a8bbebafa5ddd9027cf9ce9fd59e9003424cec16c97124f2fc8c8f34c9140ca58e476dd28d994839064c8b3b1c918cf7e751c9a44dfb17cee36f4daf67c9c50dfdc034c7bc64050f03f8a013f45a62a2d1f9101aa0419afa84ab746ccb99617319f4be339870e78af98996fbb102af4af5c1a0ad31a0df94a89b6669e1a158aa9f2bbe74b41ba03bcee8350dcd523fa1cd66fc751d1f6dc5497a53d5ddc9dc5c0e166bfc75e7cf70752e1e54415f203662317636074840ab2ba13eabc35a17fa9bb9440938837e905e37022e58d5386205746f1b63b1b30e30bc119815743841a0fb6006bd29ae8fe655b59d58969a795a551c512b8253f7b1824b6a060ec16b56e37020921372aeceb720bd133afa7a80bc58cd94db25833c6e006bf07b4a676cb8a6d078aaa8ec748882a5546162a78a00f1a8fb6067a6c942498052edd198f6ba3965a49df0e3ecb8933d8eacfda35a9e387531e72e985a41edd9473f5ca488f8fe34576c3994468c976ee9ba6123428b37e4aa4f5e6a53e85650e28958ecdafad3c8c83915b03d0dc8fa6041f1b898643026a556139297e492f8fbc6a787a2cf13c7be0c483db27262063a71b350d25d672a0dfd9386b0c1bfe1178dc38a37d84cc1553d9d292ca02162792b3ec5a0c7a283a88e6bc9d2293e72bb2e92261e9f2a470a2d107f150c4eb6dc4b0485012adcf82c914845ee2fd0f62d45f830b136637ecebdc9362b16fc2d9a691d425cc341868d64a188f98d8f352367b5e1fe6eedb80d982788f70c01842d60e514e9528d6cfec0d09b272f8d5612e9160b6a87d3c7a1c8fd46832d64614c7ba29acd25219205285c420b9c88349fcf0d51980927ebfd8449b9eb3b78b3676bc42731fe5a156eda52617d1a12e91e78031cdfb62b35ccdbc70c2fd8c8a090051cdf63436d79ddb5ebb37343b117dcb63bd887d9cb45d84b84b42f0617fd045bc352cb742467bc44ecffa1357df94b4b060f672c24cb0a3947a0c5cf31d577f0130ae78d55cf23fb006c4f1ce6ae0d0faecde29b881fa55738e6003edd474a67224d79fd8a50d26a0602ba099a6ba2fcc043a1a0654d3d3e43ba559d03d7a5253449f10c9587fceae6469aa1d2f3ba9870a38ea252dfeb40f7d20bd25c68af3a7d1053a70054a25d346dfd0d4f25974191d1f89c7cccbc14397547410f279471d56975250142092f1bee2595a11f1ced73dd0403c3464d4c45a5db4a9dca3e2965552e22b28316c7d763ab2a4dec8bebf4864c01ca34b8c07045f583c68bf2aefef9b9e0ace270f121f264c2196e7b39dea8c17b6eafe1ca595627c7bab55b2b094bec04bc034fdc7ed93c2790efe6a29395dc03cf72d6e3c8ead5a69f102a94052044f9950706c547d654c4de97c38e9770e1d49f795d116b27638d1a5d9f53ad88a9c5e3320c68fc78ec2c96aa75a66643e526af73069b47a02fe91bd0d5471a70b2fe0999d0d28f87153fa2adb5705e888ae60bc8e90bb56f8ac351b2f719ab673aa5e974529c39dcac22c98bf96f8a32fbc8356ffbbcb7305ea338665e75d28877942da706400333adfcc75b8536380e85b7902f420c7c244e19c091c6f74a2082be123bd3b33c6af28647e80c429aeaf9852a626669c844fac4f6a530e2af59fb4c3265373dde7fd3997a0950ddb340e3b26d206680d45252d74d494ae7b59dfd35ed1791c24105c5e67cf425730f661fcbfe06b43d2a77307b7b3c931d765a54c927d929a60f8aa70fecb60548cc65997631433787ff20b73b15cae329a59f79f1dac8d2c525947b2c0b708f28f6c785de70f0f567c5b458f5bbd94f3a18710cc032a1b8406ae5a35dd6485704b2cd3aee53bdf480541bf8acbf1efbe040b38c42b1c308a9a8855b19a83df2a0ca02d054d01f33d98aec2080382b2928f13f6f5fc2514b1b8352fe9cf11d0efb0a981d25d3215dc959b7e2f8cdc4f0538db6aa1d4ee683751f01d65528234975
e: 0
h: 180
k: f0
l:
m: 11ab9c158e85c2c9ee4c7748853ba0ff107bedaf601c3aa6b4159138e4c08569b2cc0fecbf87f46e
n: c61cf28cade2d43e6c970c35918d39de0aa861a5a50daf3b60f6560ac593820484ead60945afdd9c28e24a41837063abd3d68431489eacdf5fbfa344c0e032ef9f4de943a7481b387c5b12580f4e8d00f8b253512d041632e02105b0698719be685f85974a922781eb2249c6dc833a38d0bbb96695913508b4857c902f86c3cd5d8c94ba3ee58deda50e66a24a99b3ca5754a547423fcb8dd55d55e3aa2193151e716cb7109209665a540af97ad709c39888212c19c1f3bc4960a0da21124e33227aab54ad99682328bfd8614ee57b1c2839b2f91e1bf2d5f4445befb2e855206c1aa961e7adb90579da4b2718edf95c78bc2b795a9822b805cf00a9723636a24333b6ba5aeed0f05ecac6c23fd77c0b05b6915b466665eb391ff5be34adcbc4f2540d0f281a1d82285bfcbecea3a645d8759532af52b2303bf24942db2b68dff542b47a8f0b29c2a4b8b821be4ac5b52ecad9a1e852f86fa8ee71c9d1c7fb49457dc3d199ff3f7e7894801984084fa1572469c584c7ea5f8851ba597727a9d9df289fdb0c5a9e7d77bdd6324745c09e8b8e28e45d1d9f0284fa9ee6d3a419b7af795777c245d9a727379673027a581c6675305f70e61ae2b42ff214b40a42ea13d89abe7bac342511351b6389c8f29ce8a03fa9e40959c627b80af158e170f59d2e14ffb1fd7706ad4b85fa4f7bcc710b50308465c0b82fdd381b48c9e7f868f440b399d9a35e78f166ab1e9c4d170ce48b0723431846ab45bbb97ed632f5fb89e1bd7a1397bf4ee6f666f5e318f8881517701b92c5315720a852e20de3d281cf67781e38b362eab4775b48079b08569b0c2cb99371475f5d8c7bb8e685db620ca7aeecafe661f3afcd9ba89cfd97d2ab2a2d049b369583c7efc9691c01b92358839be4b8021db68bdd6f555f56933c02e7d47f3363d824a496265237854104780181cc7374211b88ca1dc40d3a76b7bb10e2ab1ed899487c23cf6d352bd28bee81e6e2024d1c092596a92fb189d7d0611471cb756541abb917ce2892d8c7e2523007ad3ecede0747077b49da608382312aef123d1cab88fc4af03fe3300605031553a80f5ed0f3aafe18410eb01dcb91d1bafe29da9a07b485144de7e9ea38c265ed2af4f8b96a7b7a829f3822502b0758c1a2d8ab83aa0d9fae7645f722dac94e91926622a8c85dfe82a6dc40a396ac814817e01276dc79a41b367f7729b31027a37cafce97a15abb32a73fbfb0e5657bb1c8ce43de159341bb5ce410a942d6e1c6147a48940b29f1133adf356486b37b7ed4190e39d27443382dd4c1b90a49f2e5582e78f7c8732458790a7802b3adb28102d79171e5c82de91dfe8df59c0ed7717768d5409cd01af99ea06d9f7c1732f085e9204caa580e74aafc52cd05b6d35f5d1a631d07515d8ac2b8b0b6923646b83e723e6f0647adb97fa7ec06190a82e318d014403020effd46459f494d8fe817756bf763f8676ea9ef97b8e234563644444fd9371d6df5a2a64df8942b3a4937efa81216be8d296f94f301f49be587c9bd5eea260ba54915559ada4e96cd3b726de0b67e2b58ec4da614d08ca710b2ee7c231801516f4ceec3ba440517d46a0c7dad96fbed20fbea9e103a3b8d1cbd99594e2be834d08bd133649b622747ac58ebc37454aa95912c00904a06956f77ac4127aac57d8588a8074b9e65e9479608902027422d5c07ae9f5c87753a69d22c0c55fc790fb00e2912a3832d30da195b3218d9d7bb8f9ed710373c184f1eb6776c62f6fb0407a1f414fa3fe4d7b48830c3ade10fa459bef89bd4a4de1758f416def8fef4ca07f6c54a4520d417f8431645d688a686b326625d51ac312b8e1affcf8ce930c60c0a0d23951a47c4be083e92a7a7a80f74ea5315aecdb8512297a4b4398955d765a9288724522fe0856adb1dce2cbf27a5127ec8ac39e3b91e767ebc05b333a9064f5e258ffce2d2e910131447367ec19f0e90902f2ad87b9302f5eacd306d0e6cb6ba66da49b975c59311cf82c38e31aa7940509728db1d2813a65c8144697a6e476a3f7d80abe4e392fcb87c0596c7df3614991125497f11e8f3a6d00f5694637c3583e1aa98c03ff45146196cea5a815e3344c7014918b9698b2e0cb1612e77831200a09bd76e5c2085ba19f361f3ed97524b050e5903ba52ebc6d5ca6fc14916b1590d20c7868ab21d7f161ada826e64fbeb44826a9edf2bf52deca62fea57826e38b4f5184647f0f605f2fd2291143193fe6f814b1e9762069c36bd63e648f79296fb4547ec5ceb13222bdd783ba7a17cc14ea0e9e3659578882ce7d1d6e485f0eb3137b5bbce8b701be8ccdd70cd09b93af7950fe33fa31390eff581e142dcb0c8aa76506f23eee24a4869f87f1f93183dabc205958c3e3de92f616ba4d6d63f478278700e5c9b39dc27d62aa32aeb3707781e6572e0ff9637a80c4b64b9081e333dcdc93122848ee08d0d605d2acf7adf462aacaa3af1970dcc81f5549b646f3e432930f1fda32b8c7e6c675c3a27ffd84a2d1ce9695062ebe0246328a8b5fc4fc9ebd5086d680ff53f6eda4ce1f9bed2d1257634f53d622cef33666dcca383cde5ce9a4fb8c27d857114d2cb3b2dc321e4c8518f199f8c10409aeefe63d54a5aa68a77381422ce02f7f09e84ee91e44ae0e9aa65b36c0bc55a728fb6f7d8acbac9c992593d3aa903b6acd230b370c06fff8bfe01
u: 14acd0d203fa7b0bd651104dc9bc23efaf59527fd9110f8ad495403cb8b6ba63b04a9ef92360239212d6061359e75cbd121161c95b1471b2ce5df97621b63e9fb68f820f0eaa52b9a4232440f11771984ca282691fd145f7495ee8a0f5dfbc78f1a7676447430ef541c183e697c168b0a124ac6536b16426b0d42edad93041506b9d312e4dde4aa3c3390e5547ef342ce1c8e43abc84bd1570e85b231b9209292ce203cbf13fb3bee1b3fc7501c7ec47697e559328829561a10d1c65e4c43b0718539e2bd97f90b26ebb3d97cb69b25f098df4b82bafd35aebf5a8543dd7af5ed1d8b9a5e29d28a8abaca34af6e9bc338004fea0029c1aedb1c0c7df2c0c8ce3f15b5caa283fdef3b60246b30ca8a66e038f8fa3268dd7f9b117afbc6d586eac4058288504ecbd859e8edbec62a35b9e35b20676055e3c3e6db97cb4e1855f402a9d2dd974d7db1e088fe6edf328f275d124b28f92335bf2b088ebf842706a2e96ed2511a0b589165af06742c3241d1b27d5d2ae860002deab65e113edeec31d207a73a2c1f694a126507615b8263f690373daf7459f9c79c6b5dafbb00222df8105b2ddc9dca0307b5dda7541e0a249d9eb0844e63c6cf6fcf2459e629578a81d856944da5d353c398a6bef6b144d7e6b82d67f01393e0cf097fabcfee2cc4f0e6b2d467e8f09ac7f4cfb497ad2969e0295bad1b440642189bf3f889ed30e1b42b1a84930c4242acc2e4059af4781de0f5b456f34e5fb535174bc9209fbe4691609c469378ff4db061e6889cd86bb43c7b4107ed453d751e1f6699cdfc8a835713aef192c945f8ae1e4aef9b77262f05408e17fff1559395fdabe330f15a9bd7eae3035b32010ada673f787000832e9eb61f1d92040850c75fdf47139f4dc4800cfeaf76e32060fc762b404c4cd4efdaaf2f1e8fe17d0b00d0cbcc081c25d9f1e839dabc20904fb5708134bb3cb5bae0649543c746f3885563e13c56e61c708afb22c8fa28bc661621bf7289a908bab9ebfe24bfbce6c3c2271c4fb65ef7c08f683e42dea5865d270a5d9c892ca1337f02b0ca0626ed8cbfb873373f480069dede55eb5566813316c0349ef3b0b1e385b1c5ef439e920dfe13d291368f636c35e53dcc243b27da12ba9755fda48477a6952789f6d4382169c10b4115bb535f98713d826a59732fd400efa232fb44dc4b5b2a6306ff24c1b13c9299a85754fe5a101caa5fe4a176c51bef72caa8264c9c1130180c70fb71deeff9911a635330d74b92a66e7d4f67f4a6b04dc7c5b2c961fbd46e5586afc02bcf625dad8831de1e64a32b2e78f94071636537ad18a3890474bb24563c7fcc45c39f1716e3df6e144575efd3beefa53c54067707e48f116bb8d4987a62d636556a6fd983694297b72b84c95966f2204df4cdd3c470f2196f089ec8ac9546ab2549c8571bf07d35e0e07cf0916fc821241e7bc22ef047e0b0f80e3d702c3d32650434d07e972d7934a164278b4d9c0ae685c1395747a160ca7714f49ed7a4d7256252a62c329fd1d3f6385abfe65ab3f1b881bdb4cbaf217675ec6fef65ca34a7ccee1d9696b1779d84ba571c6fd559004540f8bff824a15170bc749835d09c0bbc534d65c402ecd1968b944e2138c01a44c112dd72f224a1ac32f2cdb2c1d43396d6152ec4f2dacd9baf493ae46543fb36c447c02a85740c808427b31f4d4868925d6389aef0206c5bb9a13ae2927960f755466e9f6d76168fee2abcd94bb8c876bef4d8058d3ef23eb0dce364d79668e75933651f1b754e1d29e4bda070e4b4737242201440dadefe875ab42e540c470d62e97fb01d2b460cbcc57d2b0d73bc863b800bee50737e5d60ade4b9fc0b883aed3fad39e44d82ed439e6c6d423db7f4f7223fe79c34bd79b77f65be7190bd5995820fc50dab27edc0bb038decf95ea8da9554d9f461e996e701250d2e5dc7a8d037c19ef8e7a428934c098dbe8f16f7a165f3e11272478f11dcb26d3473ce7b7589d128b4c099442d579cc25f60277fb686da4b21bfc2bb45300f2a9131b21fcb14046887734d32fbd76acafdbd02a96478b6787a1d76b5b64676152305df59c4148f4f66dac4380ddd611312bba7ac8dabee030c4b2181ce486b5d1d8caa4352dd29c1f935958ee06d8423f3a372acd4185a3c1633a2fb9bc56c9f072a7990b3c0430db7c369e21b1b7d18bc3faebbce4a64c8fb2676cbea862354f28f18be6b8f9df356f14255e6477c5367be6675a570ce0016c2449780346fc1943321bf9009e0b29f69d145e49df2d232f33890fbe569ec84a9191fc33c12146fdb7cbe00f664382da3f29e16da0d87f1da0eaff92cde880f90c6397cde0145e483f21f0b5f25ed4ebcac6d08624577a904067861a6f45ba6860482a41fd4a02aa5fde15113585700fb22eecf87390632bc880cfb21fa182898620f176d0ff0d5599ea8cf245eede615a706991292ca1ce39ef0319a09385ea6dc7698bae72b0a33c9535f1e847b4c5c8080b7d29e4095f8d698b48c0bad9d1503972f649933de979e82b38b7dfded8b487c5229dadaddf3d87095c0694c696892a1fae51545186493df5efc19d81958fbf29b805c1d3642a948c650299ffd4745587dfb0dd05b01a14dc0199c7fb86565ee4ceb777548a983244255c9babb22f30f76e47c95a5969d9bc82461becec41833001464339600624b9515584bf6271f
c: 0b52f77e308d4a31eb9e7eae199422b1aeea92ed11d2bb2bedc398730ea8f8410542db91e05eb91e911ac19ba0b5238124b831ef5183af2735c2533750ca6495b91c8be070396de887e3f25d32148a2803ee08c809c1be65ab40a558815521f097473665668fb8d21c3a32eb6e0e303c31c53b99e226b08160e5991478a043c4e8f763094b3297eb22257ec2575736cc69323ed90266b62db6d49a2c6232aa0762fb19b707bc34df6be2c032cc2df35e5a22a318ccaf3115aa90369fac53d51ae8e151288f6daaecfb67a1beb7a1c59b16b4da16a9dbd1ebd576e8bc77e62a77283b74a68f9721e332f5931dd47fb4b212d0fbb6044298de30a30b32b20804d41f7de94b4e9f11be73ecaf29d4a6914e312330044247310b3caabd221dfee205fc525fa0212a46edf77152c167a7e808f6d6b4c49ade71cccd91c704aff448aa689622ac709b1bf779b3883abfb63b6b2a594de708c2a32a24f334ca856d5b06d1cf45bf78bb2eb7b385638f205bef2dc7285b58270d862d44403537eada0eddc66d217e90139b51828650bb8b1e5aa660005bf97b8394082e541b338402b86418669b67bebc9bc9bb03ec75181249c3dd464d576268d7e4bc9897dec075366c9fba4582f3f31e20682dfdfce8f196f688a81a8c656df71a37817ffcb736f842aeee746319cb702c187fc6ee19757108ef8b88374574c69ec483d6532df4048253e7af6f8abd586c0f567746ba4599f5c9c468c0006a0e3e2db229b4b12a58d40c252abc6016c66beb3da38026ff85c6a4637c53a8e5c7bdb62cd43087784af2f3370e2986202b22f769d2b3c17220aa5d45e78a9f2d51a03bfe5a3cef9407f67ad31c54529e58c38b65da52f900ec669919d6103fffb5589075e9bd28af3737db22b9e073da3b3728bca0cbbecf861836fd854d7260a9e347e8e56abe2f437dcb1eec496e4136c0f1b7dfb110e81d85f8bcd278f828d791ebc9a1906f7c79e621877f4a4d60e437449056998bf52640051ff8427893550ce0ed1968048421843a807df8550397b42ee859c71c65ee1338ba6d7d147d5cf0308b673b6e97e54afa5c5cdc9ef2ad40b6b5ac9851ec15db1fdd9a5b934cc5a3472007c874abfe112effd00195d9ba070c7c98d98ce32f9a324cd1c083fd08c77cf41d4f260ae8ce8320cec6118c77fb0dbe659cfd2eda07f957ecd1da4a2b1ebeee782842dfc9cfae7f9669662426dfa1c74731a6a27aafe131ef20a6475010673eacee6de58f03b48fa7fe94a2fa99473ea337a0a9c6d45cdbf50fdf396d3ec2ba796a251a2b8e04b9ebbaddca4c7fac10315f422fa593807821d70e06169913fdff5215a2e8831adb2b553d9a72570d2733c2e87a56f24d4b0df87f0aea5bdde216aa3721a332f02b9dbd6dc297f1304fff46d71f0ae568f47095bf3d99cc6e426b40f3a75df77c58cdc318f4ce01542408494f9bb3e322523e4956c1e86c7294144ada3ab9bd63dd0b8b9bf677c448b0e1af4a780e0d829fd1d022917a61df65c2ac44790bfa7868e76012ed4292551f9d69bd887642c03679171184497a48ccc18070999a1e25530365587469e2f9c08d4ac1a0f2830a5932348c19e487b7c96ede0f111853baaff8cd0d0d31e59e9d7f5e3aa72b25f8c85f58eb055922e9202df3db45d71bc0be6330b1bab34fef01c0f2a9af9af4d1cc8d9bfb1965c3cd023d10e2e9ec4464724a65328f1c55983d0a1d9e37857146b2bb7d61726ad59af8f00543481f491705ff37be5a5bcc6d818112a315ae569f308965ae76192b5699922d320b5e592936c987aa607d117c45d604a6397244aded0ee1f001fb494cf9650a66f91dd0a060ad5e392e276cbcc7f17181c542151e86c73a070c1e106f24998b6c139572f3d929c0755908570d690d6141e2be88e699ccb7aa9aef172640fc599a41d5f93eddd3e42f82d4a8f2ac0e23436f59b80a0df29ec2d1a54c4be6951a84e6c5a80d7c809094025099cbf31b90f836892e58149a36a7195ae4c6c76bc1c4d5da3622ff1c9f1175528b1df22f6ded12069b9430d239c392a8dcede7790207530a5202f6a6c2edb4ba5f19bda1cf72675263d20607d93f1c2bac069c986faea5a2b72e93246d2d93907f8e1eb5f21cd3b89496df76392fca441ddac9bbf8b877c8dbb2791430da06e1f8ec9f354e8dbac79287c584afa3ee6859f688bfcdff839f9ac84e3e1b888985a5e91f640008de3b351816dc0bf69bf9018948e86801f03198ef86b10b30fe12530d6d54e03fffbf02b1fcfb1b9028193aab37f6d86dc6c15ea78b116a4786a40c8ef913a849c30910c05fc7f500a17f38d53f33b1241693e3a36ac8aefb03eafdfa517af845e026f6d81a3c47ef895b356fe905a53fdbc82dcf7c1246993dd0b2aa9479ba3bc9a4eb2af120a33a2bfa8ffc161b9dfa752f8441778f2080e26153c976f83ffcfce1c1db47523eed680f389eaa9ac9637497e1cac4e190699056dca4842403a2a2de8218c72cdebc501d3d2224e0bb85828e0ded615d11c9c5a90890e695c5f2fbd036f82db8c1beff9522aed101385dd61163ec8b898f1f80babe05dca0cd5f7f5f7584c3fbbc5600cf57cc592475d67a486768acd68d2c1a500c7d3e78533b5a32f28e8e949c1525e73edefdcd35265814e42ec1aa84ccde6cb78d43adff60767159c372e2bba841dc727e053a47761ab145
d: 74e189999170c40995149b64cc31d9e936b4ea60212e8d6d4c5688c3c5df1d19545acb3ff3e9b949f26db69e36ca3b03dce1c3ba6c89eed3a936f55fa3b81b727bfc08e6c38e08433b576078eeefa2e860dc162384048fce3e8aaf8ca8d44a40bb6900c1b4dd5f87fcf5b1c4eac20eeb75a8504dc4d0b7ab18a4c19669e792321d5e6bf5d9eff509a997a2dcb697e25613ca82d5c2d1c005f8afbc9e8ffa3fb076e111088f18eb72a58aa32c70e6c8fc07661eefafac494f45328e09c6aa231401abdd7c02e01af8775fde6eee5a849976ca9140fee66dcadfdaa2e91075eec5510cc5209f0866db0f3b6429fa18bdc634c1b6af6b2ed8899fc771e6fd1d1a9bded16c39a17d0ac0bd9a134fbc809ee7ead5f66872cd06bef1b6b6f7ed9e19d6514b42c51b3cb8905855ad41f1ed710d3a8515c66138e2180d36cc6efe815a0a9251c37c78a8a318619fa8d639bced0a91c71cbe006e74344155be33bb84916040c2b8cad4ebfd256efc01deb1252edfcb648e0522d12ed66a4cb56e0c63cd1e855b38698e095cc60efa16215885ecf0247a0ba908f51801aba7ee7e3a58be5130f6e25ffd58e852df9e86becdb3c1ac8525965dea22b231943a5c8f18284646a0f6cee4e68bc78175bce3bd8dc3f241a59e2396c2039e161571208b494576b40b6e9e239d174542f7c5fc246c75efe1a89513f63ad85885cd8be6f06f72f5b452a2b296076126a8fe3e55dca9833e610bf0ada3260684d05fa36c20b7f45c6e868df408f4c1234598ba67d9e7b94315cdde9ce9c39f97365f56c5d232e5bba454e26854033f1f64e56d30a23738d42ddb966176b4aeea3f6273073422062b0fcc57a5d0e1ef85698b75e1ba17aaca165ceb87c18d13bc1a0c2bc06cabbca147598909981ac5c1f79506c759515f75af9ae9f653e1f412a737adb92649bdbb5222a67d049169165c693c668dee326ca9750872b17d0c5f8122f01f30c1cf5b7981ef200626dd78503a7e4f0ef799f164d4d91702ebed3d6a22f036b3ad1e541536a39384a53282ecd3c1c7e4bcc77cd72f408dde0d101cf1c9314da57860a204e6e6b14d380b59fe9e70a664516ad45d9b5d5567b786042e57f54b2224886fd2286238217fa67f2f9b7bd1ff1688c4afe759144b2a302f194df6042fd82e7cc7f2588a16a7eea96f4b05347cb0ff6ae05076710edae6f30ba7a00f5661abf98d6f0c5acc047a916976365be8f6db4f1401f68a0a4e24d22724f998b1c9beedfc0ee5ef806c7c96730d1937e3522d0e6048bc3baaca2870afca604079479771715d5ec7f4ad3dc5c979edb608e3460b97e5b24a0f1f3d6f66f31b2da984f496ae4ac5e378c34ed06e460324ddace423e657a2f5a5be225d2ea0f7b02572806b0791a778bf37451bfceedc1807b52e808c1cb6038b8637793b527a6b1b9316760feb9b49c1a52433a63ce22e30e9124d967b11c481239ff2aebe224d1ca4087cc6b5f0e998db4107a49fee8265c73b443a9403080ed2aaf4d2f5e8ec914ffce0954a7dece34c0805e5b46a76064a7005ac4bb0f3bec643c488e55b13fd81a97e07c9f01ff62f95af3a1e97b957e619c178eab56d3c2b7c554c6b496ee0cf48e5f4b2ccefed4a72c0a73406d8d258905f9558d740cea49f69edc82eb8077dd0be6100094679bd81139b492ae0a66ed8bba4579e2fc768e0862468cf9bce591c12d806e1cf55012491f10feae7384699bf00b9b0bb8153c375f865ef76856f4e5ae5dfa6d59703214e1a4c244f46e6132afa250c7563751638761b22af59be9364146e2d91482f3c5c22a5cfb683007e3e4f3cfa84d4adc07809cd2a1451e71a5757fdf9e2b65add5adfba08e8e9f881fe55a0d30beefe362cbfc7f899b26883bbff56df61fe443f80a5697f667bfb4a896a9089a975b0fac5e0527d8c3aae613b8a06e586470c320cd49e9891f69f0db7238a78745d6a1fb434d2b8c612fffb4a164c446d8ffe79f3d0f5a600a46ba36c982751dd975982f6df092988f5a079707502b89162f44b3499cdfc118c7fb51d0b6357f834bc4b8c2dad5e0e02e77930b3371c8d5dcc993f5c0a9f62a5c3bba87866c0777ba4c5a6f8493c646b3c258ccf5b092a5a935b2fdc8455484259b68f845e12d13c2571ce9b40e6152d956987027099c1dc324e5fa3629195dc9e1b4a5a9b1cb2b770d63a99ec15b7706838b2afebdfed9c2845ceee56cc29d023471fdc402ecf66a2fa4072e13c3f9a55426d975fb96cb301197e14fd0b62000897a2eabdcfbb885aeb33420aef9de256e1b4639f8de09ab74b78fae27ab201e1a62d2d60c173f5da0e5a6aec3ca30fe389616214610599e841621d16430cd29e86a20261bdf8e2a3019d2e599e676fa9b8808eee06bbd5ba1bdd81657a1069c24422d2151bd17145169928484db35ae6b75fa52b836e70d07d32c3ca4b1b183bd97775d7cc23287a6f4dbdbd124119189253c8843f74eb7fff0009008d31adecdf21b0614ec0f2ffce3a6ea91d88b326a3b4730fecd736f49ba9e554f42805042a5a47c110dc00f0b081fd21a460fc49cc5979e51d18820ae4e53c7d768130c2d9b899563928d383e238d4621f036a1300cca082e518b2d93fbf080231a6ec1dae9f3bc7e6be1ea7f72587616739a1c9e36730fd6697acada89e3664c6040f19bd236836c1f98562d5bf03f43af11193579051
e: 0
h: 100
k: f0
l:
m: 5974d012a9617041
n: b4c9fcc18e5a0f1e84d73e5366c4357a6d4cfe6c5de8b7bface295028a9f04fe4e1043408923bd5de109e734018ca8265473f642ec44d9d6119603bcd1c6ef28900857e454919c81ff5cfc4495d86653dc98bc6962bd2fb66c28595e957c2e93f780da59b8b90e9e289ccb69fdfce4783d501de89052896b1a41f7d380e989522819182e88f2729729af85ede82c85ed4e89a0f2dfe9f9d5e11fa1bbfea6c81a8721fde83e5ccbe735a613354136795d602431945f0d80f8577fd50e2dc6146928e124f6dac513cf25797dd90bbe0a0165e79d5e1965aac466439d5e4fde8bfa0db74470b25168cd2cd59e20b058b22913a9040e13bc1c3b2a5007d22be3c521edb03d5b60ad1dfdc127eb4657080214ea772e1d77d89d8d21cf1cb72c5309c11c084a3f17397554887d3968add017bfc86d6f474d3faaa4e4f60a6730ee27bb573c905e85a7ee1f2e5ddc0041da508c8de06746db0fd892f9a4cfa926837ac43bb689dd28f844425791cc83a32b77624b050c2dc782560f5a842003e0bcdbb3987980e17a7d3b4af4a76b31a525de39befa1dac3cbf458f6c57ca93d74b77fe72eb648b59ec313a9e86d2d99c9cc00a7b579e491c82889975214bd6064176361b8f6ca54b4055ecc50e66a80cac517ae7e41e0bda1e6d9cc35ea4585e8cc758dde0f41c582eb4f5aca671dec5c807649a2f3a46ed0e4474f62f9d2dcd00743e73c87e4e7c4a921bd8d7fd8d8f7f47c4cd63f4db842c4b02cb4ce3a3c0468021da721cec2cc5991be6e9e0ae1aa0ce9531f21ec4a89abdaec330233e2d37cea94ce20d10bbda5cb56f38cb9687a012cb78272268e6fbd945c3e89d85b1652fa2900ff6c5610039c49fd80eb1aaef0e85166103bd912c51b91185473ce471b77ee94be4fcadda1be5e47673294ba37aa2950165ac8ca861e6844d329ebaa0313490b8d5cf193ab7026d2c0554bff1dad42e7665c888643a6c5c2f3cba3eb77dd60d8385b178a81ba263d45045106d7cbc67481ac10c442977f5d0b68a6297f3a5b981afc9a050497783dd5116403112277dbb9017f1ae71ea5bbc840bf9b470e5f0b92d410e71a054a39cfd11c641e492688b67eab6ac2bddff1454f8afe91d70b57ae8e1ae0bcfa707865f05abad44a1148964a637f82105c53e4e5d31b7362ff7e1e9d54249f034b697b32836672600ac36c623303cfcdc9f3dd3e2478708c4f9228f32a9f71e19fa76e53ad463f251170f431b90947d8122fcdb2d1fd881fe6905ae916516c59eb25c9e2edfd291420ed7a134ffdcc7b9e201f98e6f4c574cc33af748bdaf83b92f9813c2d07dc37eb57155a5e29d72544a03f1ac2d478c1d31db798dccf51b27c899c794ccfa952b83cf9ccded6210a060361938629bbc270874ea272dea6fcb5279b0a58f23cf55c6ac5f291311b35c97a96e0a103649ebd99f822d81f7bac05f8e69520869b1e9009717510f72a5d75443fde8d97e8470f4d3e760efc5c3c58d598cd811f36ccf48086fd1afd6c3fe11592697e259e50cc603d9debf5c4158b1ab37d87ed4361f56c01f6a104d4309c2102bd9220f0228f8503f9dcb7df7453e66629203b15cceea4effaacfccf138cf2bd108ddb3a54dd8e7b3a85024f1164ac551dfaf5b7110ef2acdf57a7ad56feca13098dff5a489816da8c07b1996dac5f39c59c6f3c35377257d910f916e42d8ee20a017178522993c554ab232d5c050ec26dab6b8d531940939fb37adb5eb17cc3561ddffbccf76abd2714453f1e7be632a48a152b72205539ba977deb07625f66c22a5e5e0edf7cad1ad1804f15ed99c254b74464d27df0cf88929fa06ad36d78202d8813ede0ff37783e061ad36afa4537798d39cfd2310f7aa490ce75413a226c59b91069498dec48dc7f84fa51dc48faa181772fe736fa059526aba24933a195816ebbd100b3eb4d0a451f610536452a52ed37ad75d7f6d17917efbccafb989c38d998a9c9e31df0df12d88acdb405e97f238a5c68e9bdfbd6c5893b7e9587fc2ae16d85b858842f0d265199727316b629456b85dd9961fe4de8d2e5e923b30b79db430e97cdb507d41468e9fd681b12ecdd8b71f573917ebeadd831eb92045b50a312abfcb034e03f2c046013be5d76346e9a8782d2b68f3222ffd9ab76fe13e3026fd8f7869bca7ff5672cf6bbadfa0e164bcdaa07eaf5a8623d2fa9623885d67439da0882656a7bdfca8cca5edf84f6dfcf7c526c135e52839b072fa6416a1a0f0fff23f0921c763222e83377c96e1c5cecd20902b2c88ff91453f0fe80be481dbdcb38e9ccafc963f9e4f242bc0985b390351d5caa69d9952d56ae5c2d9f40b1f05ba6bba52e71d1c362d20f378b0635b2f20f51ff0476d875147683ca82f115ef99725baf0a56a29b885623088d7995d3f09bfc8f99f8e67475117e1c0524db24f71f771f82465cb29bbb85fbfe0dae2e1aac5f355d490cf952d8fcf965a3989ff8c2aec5ef8aaabc76353eae48bd40fbe3bafa7a9a0af8ac80563301ebbc3694e740474dd0162930f6264cb8e102b0681fd56032d4ea8921eb7915503ffee696135aa593aff7965674c40904afbad0f0b8593508fbdf213c1e3261d6f07a6fff1c37cd28f88ec92a0f3c018881c39eccf5399f35d8cda6c5c452f7d6ff3f4753a7e19615c2e9e90fd22e914c92340913714f8d5260157cf0478977b50bafc32802f
u: 16a7ff9c29faf439a5b947361a65e595f843a59cf9235d46d01adac87793dc63905d47ea79f23830e9fa0bd0a0ec3e443c3a90fa848355e280a63eb8590ab2121902f8dec413e9d80f1792ffe8093d334baa2921ac27ae4b5e1f9d4e547083e7c13fa27fb50d20b3a186842896af37de84b5dd6edf86f28ee7dc4e764529e5414dce118100b5d180382ab0a6f577852746f520c440b0ae0ce6dfeed9c1215961fe9c6712456f0b6125b4409a2102aaa5afd878fb6cdb3c6fbe25f83cfb275d91a6e15a31a2cd9b92f5ffde3e086368d0019a260d1790e23941a7b573c0e162f1329628955436e7d54085c88e183d28ab2ecc7bb8d1920522e536c507a217ba6e8ba40f602d68afeab057eda7e95b924af1e773aafd5608eb7f150add60ee20dc7ae1b89b77d929357e72184a77ad5e1a2675fe922dc9fdf1604f7cb3fc9c29156b3fcaea3dafed6f8b9b9c03bbce9287f32bfdddc9ed4f950fe37cee27c0108753e3e13ddbcfe3ff1e404377c31296a9a8c1bf5b01a5730df5a68a57b17d09f912201d14f32c197be7579670bca3a29bf0c48c02792a01c270e98c05eaca8c67ebafcec3bd1f92558bb674200a83babaa46b3954ce103ecae72ecfc82024a90e6fd1dea8e8fd566b28ad580a2977f5015d886f136f02dbaba3dbb1783ef3988f6c6b3c0c78996baa38cac0aba0879ff791fadaa2cf9be60e4f9fde9ede57e30e8e3a41947b1c76db2800c0897ab143e3d6b2a7efa14bde0db360f562acf1a6d26e5dc42f70f378b6c3351d466f9ae8eed1bfcc830683ea05be24155e5117ffc9e4e98de5a0072010d0b86bce733afcdf823173b747ff04e28ce6d6221e8ec8493c9935212841714a92364ea9c347c2198ce4fbfb5137d943393eada2921500575bd694b79b17dc25e969b0e6e678cd029c43e8bc6af7efc38c12deb61e4775f9f158077c3648b27898d8203e3591a74d4a0604d32520a27cdcae8afd278bfd7abe1837d5cb453077b15279d5f8066528a2272f00c9d4edaf2c6b40d3e4c9adf661c3a9e0362ab4d9cf028dc4f41b57a0f312829a2ca6eb8ee03d0ba46879a8b2abecd15eea5e18fea0db9a708522e1ffca4e3a4b491817f72f4352723f556c264829c33f5335fa15bff592754b0398b084071197425abf803828f90d154f21bb94747acb221bf00978600056fa8d412840b56cfed9760659b7c3e746560ff9fd9a0fe8b0e65fdff8364a7b981ed07885ab1396514006822294e468cc423023d2a651e8a4c76820faafd5283bea66a63fa345b89d62834f090a10c0619589ba29b09572b71ea4212b862510de840b88ecfa38cde41100155402155108a077f646b55c4c49a294ead9f0d7e07c4540a2be08b518ecc84d8a4fff1be888e73d0f2fe7b6150f761c1995cafc77496d0df30bfbb08aa851981c610cabb486d4afda41ed448cce13238da85cedea63a2941e527cf545db2213854f69737958d7fc043c2079b619af69f7569cc013de28b974c77946375dc8204d0ed94fc16601ee5a79b2f0816c41bdd873daf4163a2d93336032b2c9de660ebabed6f0cdc10a65b94b6a24fe0c2e714f5a121f72c962ea9850fb8375855d862556b9d99a85ead384b71c3ad89392ab09157c4db1529df2325ee57e202ab19b918833974c2a091454a0cd788ab1d2b871cc0e4d5f1fb9867567a16c2c8f7f8e39eedf107f7e7c047bee54194d7191351ca683769e51aa7af524a93f90624d1da241933a81ceb6208d3b932013a1e0edecc883ee719b907dd2d644de0a3dc964fbefc7665e707d316b87d9ff80d417086b7e10d93e8129a3e8fad2317c87328fe089bfebd343eb560ed5537019deb03f4811765a727d43e9294dc84714b98b2355df5a43876dedc1c19c0c8e13a455a87d7fe2971168e0a1bedec462c189ed7b533e9109d3371a14ae6c9be257bd1a3059ec30e76991a4814d9f07558c92a317ab29bd10a9a12728bf87e5e65b6c3a4b07daa6dc89996b034fdf4f6b69e96c43ec489ab3ba59957a4bcddc4ae15e08cb6a53f0344c50e7d54daa2f05c4606612db4caf9ed3ac4e89d4db9bd6a15e3802776f205e38e1b0dcacdb9820bd5b17d966faa47caebf4821092ccb3a1b8bf7217e2c4e97fab8585779ed61dcaf012e13e0e1ceb9a79645db82a217cb976ae45023e356ba7f3ff23cf0a849fbe8787f7ef8c3b128857236f26fbdd17f2557bb859a2fe3ed6f778f6d8db0aada3160d10f64b9a1b9f68a973585b4fcc0c45c5169700554106b01ef69315cea5280ff54702d7daad1375abb07e963dd8586e9f935f9ddf1d2bb6a071ec38bde0c23fd182cb119fbd8f6e2b08a8575e175d532fb6ea0821ddb0899f7a6911d3727cb07095ca2ef8d2f27eb9ffc38afd2f8e9ed578a974845fa6f7052f84253b9add46bc92a0806ce4bac3e470cf4425b767a5cdd590e1366410fd74513f3b6e90ce771b541d717c7be883a8634c93d0b73c4da95e05447a2df6d29debdadfa2ffb8cfcbe92a45463926894ff33bad78cf7b1119277b4214e5a051785caaff8904d5ad1decbae3302ca8c7c2660aa94d099427262523cb43f0fe743946933b5c3a97440a2dd6b6e7a2920b67fbecacb10e9a52933abcb6aa17f7db9eb47bc13a654d62a40c111e9133e1ac1636c52567bcaa1b32ede0c55444717f7b1e3756dc24100433d787436b219b23a54cb2796d
c: 3f1efda959ec198689c12f39155bd7c5c9b1b9d18ba2df28c048729bd15d2ec3d9f78b35e29df5710ce19ed73938abc11306f583cb4a0d938e3d60e4e150cef095b32d4b4670bd79d8ceeb2ed82a8cc5b84118895ecd898e0cc098c9acbbebd422fd49f4e6d0f27af21827c973e29397f61976955454346ec9602b9bd2f23f551bdf6a29f9b86c2169226b04e1d5944807990c85aa5771254c2c63ffc19bf4c0e2afc71d275e02bc3acedd1583af1140d2d0ee195e16f5a4d5572b40ac3e7c03a55ed30a7e63b573285ab493d1004fae897557bf7c0bb90ae621dbce1dd94c2369b3bf8b9eb57baa8d4aaee0b910967568c5804c0d31a2ecf71be9dfdaf28b8effd49587914c700b9f4618b29ac90df3a7b7e1e988916f4ce6560143704af1ae6ed032736d31f0e4f1d7485112410c840544b7531beba6eec1f091c90bc208e00883fd278a19ce9dde87bf17385b710e738d5b005db867868a2f9045705a461aa3f7f493727189a53f78c8a2253a8ee44854b9469dde3e26bceb856277a8b7f63f2d485a94e76dcdc6d96c7312a38a2cfaa606150fd5b61ae10137f76ecf6ccc223cc37811394e5cec12c2ced47ad172f7a876db577e3d8b869fa86b044e1781e8afb5c4a57149e65006353bfc5b83d8eea78376a686f73b4c8d4f05c0c53cce97d8081cfe417a355f2eae1b990d33834179453794c10f3a57756bbcb4b5682cd5fd6534dcef0ff535c9adc44fd2f9a2aa0cd293dba02554b8c913d1364e9cf4cfdb8f4d51ef688facac9820ed590b2eb2a0cfc6d390d572b7ee4b706e5ea582f0e7bb83037d9fe1f734ff4baa77df68424f9c27656fb9ddaad3169de18cbb243d36051cbf2a3f1fd2d50a17d82ef64d413890ce21251f421785fde4a27ed21b57b9d49eb30c6999d595f7a62f479e1060aca3d1390376cd7d2db1874edb76af1fcd2ca7b6abef16e27f0d7e16e180d218ac8828a824fa9932764eec5a6045beba4f431eb494c08ef9cfb9655290492ca442f6278b7d2fb49adf79a438201b582f5ba375695e86d5ca3a1fcd2d0db6f757b5dc550073b364fa568ac87ab0ad92c3b1fa51fd03d50f54e8b6effefec59152df9dc5a1ddc423118a6dc07eea6bf6afa975d1c3d2effbf15da29bcf389ad7e178f62192ac207e626be4854cf9bae68abd22dc356caef4d8b36b4b1be5c4130906f6451bb5a33769f3ef0dd7e0c85b45ba52f270b763a3261bda667ecf854e3e0ea9f0388867a990626eee3f27341f7caf2c7e2df3d18ed0e2d7570e7dfd16f5e290d57de7d25903d8b2b1c95ca6c0202134ca622d40498a6bcc606bbd556d945131a55421539b2721cbfe260a693f41a8aff8f48dd723bbfad5a2f1bf780a286a281b72c1642c908b3e17ed8e6fca6ebb44120258cb8fafd9def2b7a5e4f816c58e2a009df4db34681aec8d965bf54c6397cab0f864410e8bf5b0bec9767fc0d594ecf2902b6381fc500efb7b3c19071702659076cf542513fd926f4cd126073d2dc05add1c7fcf27e57d5dc93bca7c93fd4d9767d5e5e61d81a8811fb9603171c75b224f23e064d03ddb47fb01d975351fbf16e76ef1543a9b042d77e03754c9467af6138460541246d1a87c17885662e0cc2e77dc6eff1eda9e7373d444645339ec817048e46e7b89194cb469b6db49469713acdb500a773689e92d690c56a2c1b53a747bb9cc4158f634c8da7a15846f774a958b5d718567b6d8a14d21d6abfc2582481e30d435eddc0de588071e359ed2adda4ef0b4ce0e0548ed88dfe6bf5b8fea959ecaec60f9a41c44c96f2aebc54e2dce4e071bd187f70b236061733243579afc4b009a7f46fca7b4893f1ca11de5c282263d0a6b37bcf499c2893fcf65e76f86fb3cfdc46846a0056aaffb2528276a0244e279471b27b747f016986c82ac16cc5bfd82be0a10d4d3b1c62860ef0598e1efdbc0d79527c98fbe52bf32ddab03eb14b6f283dbb49ce129c4fe9650b244458a1d95327e1b2c378c38d6f539112025c42de83b02b07d359a25d0d0aa7835928adb92caeb9df288b388930c1ab3e21e4e048a56a397d8831ebc2e2784416c0cabeb15dd20340b49d6413b3922b24302463f19e7869a217320f3d1a36a0d2388e58d3a862a4b16d8321137f4ca8580c63e30d5b23cf43845c1ed8a8926a2b8fe84a2af51e0fd49a7e69e9e91e69c190e7f426ccd39057e717583afa50bc7cee3f8b8a0679687ac499e840a7326b1431069e2a8a7fac27bb7c636c7e936349ba4c2f5ae1d0f89a47f64bb6fdeac87f90f1a4df017efd7de57ee98048837bcbe06c17e09e6ede8ebd76866031a2cea00deef94b2ea76a565d1d62a361d19ea686325cd9668152d69a10e93a2a800d7a7ed669fc0e658e19615983a8f2350e31b9f0de212ab84d53380cc574403c3aaad6ada9bf26a9d18ed58bb0c5e461dfa6789b06185cf7b425b67197a94fb1d77c3c8c0e0a0fc3936a234246da628a4734d88101c1dfc951988cc2da39ffd6b883f37f8c9a4e72e5185af0af6788e186c18da397dc411139ceeb778eee934c22077afedce56816b0932fc405bfb8af70fc1e4a24d795fabb322cb217063bf9a1eb7c303c7ce71c87fc20113e59453a4b2b12a43313445b64b82102220638176485260a0f069fa431b5131fb29f6f5227402d190d238e86f1aeff31a09f00d074d0de40d4835c684701dc20b08
d: d747717e397e54d4d55c2799234ba2947630ac79f63b7b3791963768dfa61b7f675ff22f63b59f29ade24d4f8fc4a54f5b8d680e0e2b1c11e7819be1528863272c18a031c25c0d1537f5b5c3d2b18b1f5e1fb8b5c690b0c238ca42e92d143c88c8c3a2d515b9198a7473695b33381b8af716e8ca0de51e73c580f8c8c0a3e569459cc835d9c090c3f41334159a58accee3f5ff7cc569781ff7407381823077f4cee5bd07febd0ef51b4e265bb1cd03fcdaab25ecfea022b641db5fa0e6223d22257b0737dda0aedc9a511b7b660c814fc3e053a0e951ef6ef1de87f49eea2bcec9432db4655a78f40b9c84b4775059df933d463c4dc72302665178c5f7831d7a9bb6244a02148f322f440a24c59233397bb63f95a39cabf6ee00f0bda073d06bd93d68b21baddbaf71c11f2f0e7ac7409895aa5895a9f526430f621afb3f866b3e8205e87f663499e280dcd4e76ad348f6cfb0ed6d5e7fe3c27142bb8b3b54a706d230b36798fbb5eb10944160e113cfaaa9c85d255b330b10ec0e0cf276a6644f658540d3bc4397bc3edbabc8bb7909f39ce25c0e0401e2b79d8af152f93f947a8039163218e6d254858506da24a30589ca877142b4b8b9990a8f18bf854897f46045a41132f7f386773773d184dd339573da06cb7938baf0212b69df3c4d190f5d90da041d79da51a91739351b85d218d159ba1c36562b9396bdac1442edbc884706cc23f000f3d6e060f1b42027d509302c83db4b18c10b85921a6380617aecc683d9947eabeecf73146e0ab13685302435769593f89112e0df8ced809114d98d89e995745fa2681627547cc93e49c23857689b3d36555e7149f4de3daa38d27d420bd378dc39f377bf91c61367f6ba7b31981cbb699c3d176f3fb94bd3c507283e4c2d576b6cdbc91562f8fcdcc8054cd4491836816028fa1f3700b4a44bbc325f9e29e881f3ea7d1696e4494cff6df70517be6e78a57b9d5994f91b4cf984317408c35b1d7a87be8701dabbe34abec7e6b16ad11ce95c18d33d69be0bde621d50188821d0e71b83230dd4dd61d60f0122f9fff720afe620eed7dcb8e18d1d696a1a5469c51d42dd2017b0323fea5406c1ae011ad7510f5971ba7ce6c5f4650087684201b7c407f0269530d6fe76f683437963227159b8469d92c8fba6fd1ab2dd148b8062bfe469beedc272bc1694ef80bb9e220b500ac1065aac40836f969c1ee41e9f2252464f3abde2a9b7b2039025cb20f9d8376634aa6d658fb6392b5e8446ea144169f3adaa9586a0d2d828b52cb58d7acfa1f49fd0208b627295ac238153c121c0bd29e323fcf35f08127f1f4375363764d6e54b640faed385bf9e8026198d49b711e7bdb9c15d500ef060cedd52878f6bf3ea0854b6b393b4faa03bbe6f73e5e41dc6c88193c15c20346dd2b2827d2eef47a752a5571a993bb9b09bd38f8c54cd831c4a2be1cade7edeaa1287f47a8ecbec50848669cbe081a251421be6629ca8c90cf6dd5d05be4855aae791cf1b31dab1a1acf588cfc4876a2d7aac1152ab84caab1ccd65b56612c3e42e48d2933d0ea274da764ca7ce4bbc7be397d9d580bb09f85b7d0365ba3153b44955fa78d6b9e357b20e2447b50eff9e04ef9121a8b405d797368dd5b53cb81b53bb0545f06ab39f7080475072b461ae3bfb61855c46411297913667b9de7a12a959158dfd1c468f95e48623eff255cee8e09946c7c0052f40be5a48a9cb5ad0076585d668b338e588ee57ce2892347a33fe3f2834b9d692dd4cd1f31d1e7aad8bfa68f87d929feb2899e24445e5deb03a1757e1b24c625af4274502e0fe1eae51f7cb9a18b11bec45e14ceceb0f2ff6076fc49da5fd8ed473293fc03936288c3dd2ad79f156a8047272cf64e5b3e7b9df2fdf05c5fcc1c20524717527e7334c58bc46c8a004488fc1ed9aa1971e875afb99295b419a8d2886e4c30796bbbe9daaa38e50f72d202712380917a9321cc3330b04c5d7260f5499d8a730f45372834fb452a58c1b0d4cf1c2fd5f2ec3a7a33b4745568c62173b7f0a137b8cc06cba12860a34c74d82fb8004c3f5359f850527826466084041c09b040946c0cc2a09f0832c17bf5e50ce0be74ab77a93fe4fd414b67f3caf9f1132ad7503d8de87c03b16de0131f7a7cb637e6c2fe2b7054f7e4228b2a6450290541549e24fd8b81aac1f169f067a12923e42402e2e2d5b2a43ae8670bea84fb292b0c599fec4793201f6ca6b5262f1fb3871b3a6c203dd9d452d354214d7b05543c15961923603a293509c41134ba88cf185a3bab676ed2fdaf5309d2ba5b4487d05bc7676323ef1fd48f344c2abfd4a6102a7bfbc0973fd8d8e3968aeca47c9b7f4004687a26d7207202a03484981fc9ed84096199e25b74439f28ec82a8ac9e6c285e59992cce041fab5e45c9590a9661fc0e060064f9d2206e58f7c6105d1eb8bd0fcafc77a217f4c1ae351222fd2cd19aba5c0aa3af359f6ccdce10f3168022935393196166fa60b19b86d5d1948e5d04c842ba3ea9d860b884c8ac93062d6eb4ae29a604880272696fb18134ee078a8c3e52579f87e5ba51b1873f1d371b2e7e687174a61d5b0b6500aef9b0d67b21945938b7b8c9efe93d52ad15bc6379c6f442cf080eb25a5e33b2e85722ce1bea82a77834e7bf58d7b3f376c398d7af4a56e298e343036edb178e385d39e0bd8afd01da62ea9
e: 1
h: 100
k: f0
l: 7439346b5450783f74614e6f38653a304e277c3c44656a5f327b312925447c6b2c4c3f34565472687c42315c655a356941675073382d597d3a583d247955556b415245466124484a417e67756559616f72253376324f5d795f647539264a432d595d4a
m: ac324bfe4f4522ce95bc3c7114d790455742804762ae2d5ca2536e8ab8cccbe350f0cf199f9ebfb697bfddcc5faa18d92c9f3e4fc82ff4a5af5ffa1b5d9ad77c588808d5447d21908b5d00b8c3ec685c57c124ddb61a7e81d82b9d63eda3621af7
n: e3cd8ad0d991d42ea259493dd2c4544a1304bb3d250883396aacbb63b823e4259c0d08f780506e931f177323ec8a6886b86b9dcdd012d31b5a721cfee91542d5f5bb51f1585affd4e69fe3672a02745a03c84f409a40dbe91fac1f870a089671d2d4e2fa5f60261bc077f5ad5de684332a8eab46e2077984b0f6ad194716e640e84a757ba7d5ea604349ee6518e6a45c298516027361b2260aa206817fca027c3f097f92ba45fa4e0832999f5c6b1033d81ee330c8f8df088ac1ff1342c4954066c3115d365f999ca7584e4a0f9745d0960f7d746d19efaf521ef130c7318145de21690fd3c045a24a061a2d4d7068d2d380c33427dc4a578d34ae544e81b1d5ed3449b53e886cd1df70102c6016fc344677348d4f7a9aa7a4c42f1d7e2aa4e3b59a797030f09029b875fd13032c7dbc8671f22fe5f40ec8353220772a07e4bb153e2907d58938c09d3f437922a96eaaeaf6aa66b78ea227d6e28456dc1be0198265f6270990fd5bbb7a5f206b47eeced8e100e58b7cfd06681bf887e8cd2fe6f573665c9c0887541d5babc14a0b1181c04a6d2d14acf9b85d94fcdcb778098397a01e83c53c42cf439d3369c567006e3bd5f9f2a2126216718de6bbcd08efdc2470f77eab1a843f4062aa2941739b583190d77207f3ea28dbc00feb035b687957cbf3e544da4517f6b066ea59b70c7b3c9e5ede4997ee15d92bfe425324dec5f33bf070358da80a3796594632c8637d0625b435a276e0b1a7f3c15645783aa46bb4e808e585b3a742cbba65cb673345d31ddff3e076d6371f045dde92b9fb68d393525379e72bbc24f8c39add189f87a2f4f43504a0f2216f3565b755c7791c90a10ea960b785ed332bafb7efafa3521bbc2994578b4c4f5b45ea0e6733a187a14894b087758cba5d6c70f9a7107bb14665577f05be6ad1a410bba1210ec6eb3a3738cdc8fc9e4775ea18e653a51a553e5df94c798c7123defa317ebbdfb7dde113e1fbe16dbac377807c998a16b1518faa0c17737948346a84f1ea0c19b773a74320b83841e8608acb1c66932e1518400c601b645b2b7037c1531c2e10e8288952b53ddf10b27608c196d0d6b70b9e0993d7e8aa775bd610a072a0c8ec4fd683372a9e72d5bd25135eb950ca289ed8fe21f3b39bc15b0f686b8f3ee9c391b0a95f13883b68d7670f3e1b3229278d07a6ad47c70d9b19c289403ad7a08c237b5780e953321a35b952276ff23bb39fb91571e5f09a1d6b1e70ba2c2315a393580e94da0944c4c40caf962d4c907f7b2c0d619cdbc67f47ffd1b67e8044437b7753b0ba1149b490779da89c46f5ca54475b32f5980f326ea736e4a68a5982a4c76aac3ad1174b46567c0a4770af04ceff89db392af155caf742ba8e0b04347bf1b7410d13e4c9375d21537f907c0722360117720bc01c620fa89bd43fb3559e84801c1cb0d7020b8b0b810714847341a992d89a482b8645eb5f6e7478c35431f9a20910819d0fc948b523af3dd024cc9335a6bb075cb9d8db72d424d324f9bcaa633d8cb6fef7b42e38678ca11dcebdcc9e29e2b0aa7f99ad09a183e98531fd92070a8b5d874066d4ed1508194e552ae5209f2abf254199e848705c786593a6b5a936a1784823b509c0fabce621cdc8881d92b4218eb1a8312bd161fb4303faf371b946d2ca7c40300d73bbd1c946e60167ca9e257a544ee1a626388264f3e0f4ca245d952891c4d0e39839a1067e51c705dc2f575147a03e6cfe1f2fd6773956e0d34a33d282003e8148ee775be2b635bbb3a090bba247cc8ce30833fc7238f05c78c0cca25b15e9d124c229fcd5773d18db741884438d836b7654c8bef0c00f3f84cec10bda2820d14e89e769126ce5fc324bc62e34f268fafd87055e2131279f2f201cfbef58c77cdcf8683bb17c5e4e4d762eec67e64aaeb217ba73184d475c4473c239afdd77059b83063a2311aabbdfdfeba0b91fd4fc051e629ee464a6259b578c53d1fc51ad487de099d1e9f91f5876816ddce6b89aa8872915fc10e2fcecaf4daede65e6e0f85b057523bee752ccfe406afab0c4b0114eb4f9b19999a4aacd0a3be414f8f9717262e0f0e7d84fbf042ce00ed2c5acaa39c320cb1e7143d42e05bf001463665e357787301ef947eb2c1835014d3b727c836c31b0bc472c753c165e261f253b33ee90f24d318f3cc7aa41ac5f2c69407cd0627c483b0e33d6d4e664b6553c80112697b29d9bbdf49723ed83fe2199d6d88b0c1babe85acb6c23fb41dbb4f7cef6ce9e9dcf4751609fd99e98ccd0cacf73527444ddf509fecc81811cbad3918c637121db87e3a32e50aec190076375ddf5840b870311f205bea73ca6f133decf873797325e0bf9c2258d50f3a69a512f1023de23726bed2e3f53fcee5b5a74410d56764bfe4e3b7cdfe62d0a399208bd0622dc611806ee9e862c07fa6185e16c2ff07927b2e069b82c116381e97d3d6dd7e059e721398f57f7d20c31a572870b20314c6ae50f14bcce8946f62cc3b7cc3a34c1bf75c784c6d8cd35f8ff62cea82a4c4c50fe0f379519596cdee658138f1770ba388e0332a7018ebfc146cbf91f8e3032d89c3ee99a27b373d37f9866582a215d1d34bbafbd0cf7c987fb66f0653b4cc0dba692e8e81093b6fae8d909aa5e79c5c605e3150d06eb30bbbfda55df0fb30f4fe6d3aa882a4c63c2722b45d7255425428ee5b5
u: 11faff296358e1df047abc02b35061c0c4e7955cf2914fab2bbd6aa84f72c1bb854201046485bf449dc0a46736088c3b38a1373a65b26c436992d8ffbb1aede110a8dbac635acb4172ed56780dff6c2f6b568a77b2c2179e69d0d31b04499a0f6a5f480b0217a5859c504d354a1ea31105e20d6ba93a722223e72eda87f577df2deb0df23d3e789c98c90f5325fd5584548652eb43cc33bdb36f025ae8c8ab58988bfd8550504601b395499792ca479a27912fa105ce15d32569875ce71e99aa754b59f93a66c22042125796aa502d680352d37daf044e585b4b95ce8f7a3cb25fd54b21a998ecaffc0895416ba7caa03a96d2013619fad8246d8af3cf31903db485588ca70d27f44a809344f4cc7c31f75013ec2debbe71d0f465b0178a4f83681ca941101db47ca04c6de0efafd4885c4ba5f82810208414ba671c314b0660515c129cfb656f08490dc912a1ea3aeae864dab368465e789219fe2c0ac8d6afc8e84b54cacc9c45f17317e6ebfcf5150758fdb2a84d6e503759f2f428e0420d5ef01660c30ebecfa41d39985c4a20236a0e43fbdbaac36725f3d24700036f3cd0fc85db65049c86468d3ced0849ede0d6434f1629543d72c2188efc260986f2c4ad230e70ebab09f334f512c16bd06a2a8a00abe4c44e190b2efd913eb338175d187771cc4d6e4feceb6f5ffb360127b7f59836ac0fee443b5489231017db1a16ae4c4d3c01f833d1c13ef60b5644bc09bf81f84572098f902077d6c2a4296c633cb0d6052872d5e0d1b603d6939f702d5c526ef5ed69322b966fde1eadd45a968e628d3686ef1ba59f4ada3b8b6934323ba2450083a86ff26b13ef70b2495cf65cb90de576c9ffe92177975d4300a646ff65e5756681dbadfe3cdced13fc82a3431ade01e3b69c87fd2eea88f941e9e69dc8cb81a5bb859b773f5408f05d33fb03c85c6f84a6a7c8be5abd6a55ca94947b9bae14be636b53d19c72a4b29fdeaca3b71c54f8f4d7cdb6be907be76f4b60dc3388a1692feb42be51b1ad6a9230423cae2a7a30bdf7f556a51b231aaf471990e52166a630b10cae8de397d3a0d005ed5db0153c80fcf159df6719f1f365073a7e143f7530f4191b1a4a701243b6cf67b3ecc9f3c1c9f014df240e763624ec4b2997ba069d1159cc115f5a84f5a8abc356a5426642b9171bc15e5e53417617f9eb298a5689f053906e7d04e42f9498becc0b4d9206f5f9ef641b7760cd234fc9da4d17ac08ffc2d9c9b4a1599aa88c9557b1d0f00776fad393e6ac6a15745e647724efaa4479ed96a7ef80b9c336dfe6f642730daffdca004c7e7a340502a8d5e18f4c00c92a68760e8fbb4d00be957ce51dc26d446a139d76b535fdbfe3e7a663d9609178d3924ae6e3bdae7ba612eb0ebeeba1d9b55a92a9058d93d3d79bb732cad8680f8934c1af9f4b1c8168834d97cfa6b50dfb0f9bc0bbd11010e86b18ef6c25a638f6d193d992f9864fee87cf543ba098e9af8b15252402dfc0ce9598e26373645987aa55158287f29055feb396222911917e8cb2d0f58c7c3853d0cc816f043481d0c01da3c8804e2bef21ba97670c7d8da20ed96e129c8436f0ea83e174848526ad78b5dd5704b123192f34b7c5e8f2a4c81b0eecbfa4d12d195502ae25b7bec58d776e5dfd60c7ba57ab35bf1973ff884accd8be8e49cb93b8cbe8497df7639b33474a5ca3383a986133c97b9914a3836b422fbba6eb9202a62e857a3ea2c8f5f4ef9dba7229afe36529299f4d4a782b6855c6c0f1d0fbc13f656bd0f112c0b8f9f59ab53b02600f6c70226870c33fd04a8dac8d07e49d62f96fcecae25f4cc08ede30274c703050c6f8834105a44883ca7f9906f5918f38a68ff93cf6f39d560f1454da27d0b942ba9fa51203e937dd967db43d1aab8b9fd3090ca8571b968222782bdee71222024e316cad47e9d1ce6077b4de32b84f453bc479f7c256640dac96a789d7b034b51ff6d51277a7b2ec00752d25ee0a7a4748d398014c44af991110e7ea5f0dcb042918b17878447c5938780fcbd3f313fcd71f2db7713b818a1150173e2cf4691dc27c885d584a737f732ca7ae836310dc2e07328c5c2fee8e502ba851db4ca2c30a41132ae74f0894be25a80ab3dd4138e83147e1b79bf09c8b6297d12a2e96162aefb103891d4daac0d7f88600b66edaa5c4ac73e742747ea5aefacb59f678564fca4fa781cf842fd7bf1aee79356a19dc9c7dc49446f22d3150ed3ffb4e21e516da6e087ad54123af48360881cab2e546b5113ce42e118eb9059351d9d89bc77a7a5911a91eb9cb504ca10ff61587cac6f6316a86c78c7555597c1f944ba15848a092d8fd3b71731b0d324465569f39740cc1869d10ccd0e82031498503bff2044d8d71f19597221bad8dc95dcd4129183192420c0239475ab82b451c11046b65ad18af66f5f248e50c23a9828cd86c8d6270c3f0d8feab93173c40901d7d87ae452b6d17ec884e38af7423b0027b7444837429c8120faa85b667a51ec704f56ff4c2dc9196d6ab14e2087c44105dd6f2f7adc8794199c36941a67982975893da6cddbea5057d41f80de081f57f73c8f6381c9a218667709347aa740a4ebf642b2867a5502967929689bcceded0cf6539f1f72b7c3ea90165f4f44d59d02c86b66a983cef2d5e56b3074d72b4ad1f457e81a3b18a561181aa402f2c9818bbb4440
c: 99d1308cc0ec1e990df74489436ef215623ef27c2e435093ec22c5fb7169776a2c404dc7e3b0fc9b69c1afe8a32f9defd4957187db52b09bfe51f6f693760ce9df17592f864ea151553b20088f889794252a65f3d3381ab0afb6074d21dc41dc8ecb6ebacec4d649ca1b7000f7277dd26605a0c9b4f9aec4be80c33128b5f76f57cfc23aea1ea1a4bbf966430194523c9a83d8263f3fb3b4d87858d6a4f177c52c31bdd73ab9e24ed797e0470efcd5da955dae4020734c8e998424246270d895b7321c4ba9a43a5d6359d4c4794fa5e02974bb022588f5f0be4185873d67d953aa5db1e77ea11c19745359af43961a060b7b9e193f538a75a026d33c702bba11b29fbffe06e32a5520525bdce7fa5d766afaa790fed73bf1d8c7d66cfe9d408822f0ac9a15d745ee612152a860804a37edf2ea179e5f8584a81f038dd5904977b206937904bfd55e257b30fc950d49f3a9ea3f35848d70e45a4db5a62ae2be99c2926bb3a1534ddb9e991bf2ca59c88a68ecfe687091ba35ca63c5236bfc3866dd954da056329324ec8bd9fb774c8419420c7a2e4262bda8e5cecad9f63fe3484b2328b20e681bfdf8950660b87dfa015e540307fdadca65028aae32ddd8b637797d3eea103a7f63634ab40ae692393951e02a242d7e563d1afcbf9859c8750a5ae29b665282d2be9e31cd77746de4d4e3665de19d80186e4fbac45456a94957711df4fc191abcc771f75c25d787e3750cbaa05c60d8af24da92bf0bb711279595ef914a412dac3e80e3aa5eddd54d2d8cd0de11e48f239058276c147a1900b442144fecdecc0ddc08e9a8fe5058826e92509cc4541528065191804d247f4788067b3e3ccb879f429dafdf82f422d753a5cbb021d0d7df2a0d5940ef05fc7f8f419436a82781dc006b079431b2e72338650b9851a98e3804f64a5aaa51ccb792624cdc1067f5de0f7cfc052d8d3f9c98014183e61f653c34471fd8e1a195c400aa0c79732e8e69d6bdc6a06d47a98c578b6ac4c99693d0d14c1dc1447dcb0282001b667642b07250926aa69862a780a4e0ae30b07a6ba507015eacca9ad6b1b72589d09c2a9bd0bb98910b35f1815882a593e77ea52156286d658b52300b6673c8c921e0f6f7a1570fcdaeff6024663f8c10416357aa8032b1bc53bfe503d235915307868e3b0c4acbcd361406d17c55c1d684f44d0bbc9fa670f9b68fa6287296ddd33f552a0dfba103d2ecf0455a563a5a133a84d0b34eb68e36b71a225f9f7c40b12ed809d685b4c1306cf74f99beb44313d7cabe75b25d142dccf187a350cc77f1fe94c003e804582e60b676440bbdc57e76eb238ca5e000c8b5fd9177e6a5328664d870d39347edebcb18f975564460d5b96c5ecfcf5a0adcffd676d566fdd17e9e602882b27e36e1a6468dab43a86a5aae6af2734609eba754efbd3289106a17349953c3d5e54958221bb969787954d8ccc3c4415421f0357d0c88a064b3f2caa74edeb59dcfe729e7b113820e70a8db954f1a8e742103a3c80c93143f921a334454ff150c0a6cc457196ddf7aed6609edfcd417dac81bcd25b71f86de768c265becd65c128d6e2f579d3086624e3a7b6b0b1f66e7a1fa66217a5632abb747b2a1c4db1a98c0ab60fb3a5d108653963019048396c7baf6fc1300cf802722db60d33331919c037d22d02821ff9f3f88986d23647d6a9cd24ae8d58a0060be0c139056f40c757d146d6dabb3732a254690079bb4ed8080da95541f78d5f3987e024ea033c1a62ab1cfa693ea750c76960b2dc53b35f8312e39b86faaacabbf4b9ae356f1ff3ad0a39583ea002b5911dac8a481ec393e4ebcea3c52ddfd80f282d01184fd298eed07213373e2734dfad6b75549fa4b0339d7665393c7ef34f28c9284919ea03fab042b1c82153760445f7bae9bfe3268117aac42eb93b832940cf0c54fc4fb321d2fdd20978ddc0015ea446776fec8e9795a6b2d0d1dfa7aee478fb0201409b232598aa1587cad1ff2ec1faad5da6523c3fae37746043c5091cf0c13d99474a2ca10aac1628f7cb08f492d4464ba99c789b0db6db549c44759c6e032524033dd142e550d186ced02fdd699260ce491120b4e5802e1acc9f2e10970d6da1b74883dd3f6eebdfb770634da0b8909fc6f12d820989e55b0347193128e6e366702849fad78e92e5bd6e18ba582fcd68ea38fddbf3836e4325356e23ac9f48914ba114636432cf594908dd4ccfa8389c1f1f80f7f128089c5aa3fd06828ea9f7a378ae40f3b6c3bf9886c56591c8498b00ce2129194d7028e9bb6bbe27786ba1f7f605d9b798bd4892f385c3eafe98d0620b3e041a0e2f44771eb1dc389f9604b2549ff9f3c5dd7f038d368b63aca94c3076e784a1fda444be9e021980640821cb5106d82dd01ef4d525ed119f3cdd436384e44f591aece5ccc4c898a3f1c0d30d632fe3193c72e9cfc67966d9252e70b77ff6e39ae78dc9e59dace96fcc282a34ab45f0d249b9a4c459b95fbe1efe101ad10a2eb95d7ad8584e77a8509779ede19ff578182140baa674eb3fb8b08e956b83181afd56b18b7ede4bbabe07e970f1f06dfc1ddeb94e6a80fef014c8f4cfbb3b1f00e0ca70357d656f2f4e86bd2a246dcaff96c16ca68da35a7f4841ec698741a06008f886e59915dcf6f4362a814675b5bce2cef7ab811c6512b57fce4e45d891329bf7dce37592a
d: 1ede88dcf1ddf9ec35b108e55f0f19d860da23442493d1b851f1bdf8b42457977e9eee9510bfb2c739a116f21f73d79be219abcf3f6dd19cdcc06b6819c3f49a8cd0364af5544ed480e7805d7b5ed73c3b37e9476ce2777a5dce05fbc41df0bdac2f707d439ecfd4371bee99cf40acc1045f5eb300ef796c7f51a0042290ea4265ca89c6d6752e7d99471cb0cf52dec0dcae716027cc71431fd2dd2ac947215397c21ae63c032e00cc0d8a944c015d9a1856ca6cdef69dc958a3e94492b6b7397fe3b561a69384cfaa629584f678c089a6d1dce8b37fab348d9820ff07d4d2ca0b90bf6b278058e9d544b64e597e0b85ec69f9b51349072ce0eea9d9f4169c5823011e5514e7efb194c097ae69f7de60780b3ca3857d4e4eb267c639069ed34f7dfa3d65ffd02ac8ca6239999b1eace36f741fd027203a0fc9432687eae718258ce94a4c3a2f86e1bcc14e29bc4dc40d0923f11ca2c85ef03ca5fde5ec31756a378193df68709498e93b00afaadfd5ec4421f19c1c32ae4b238a24cfbd4b0115b6173bc00572b39ef133c939a9e40e86a71e37a056a8c913292a6d98ce41dafbcd03183fd86cf9b53eec715323122def38572c8f3f6d8fbdce47ad4b776a379a40a96b6d5ab720873fabe1b65c4bfb6ab4e91d5b5f0da22679370500d5fc4e70c4a6f1090a09eeb1246cb5931657d3d7e61bbb06696c6e24bc9548914dd966e541f5b506d8c32d2af14b0a8ff3a4ddcd663bb11c0f53e92841db386a09d2a52798c421c921c31d46fa84fa79f004d2af403ae9b62a187cf7443f6b9c7a4132cc7eb817ebe6b87d91053b700ba229e2f64fcf9d7c45ee546bc19def06baebc30d0890c30e8d66bcc93b49bf1795a96b6238027a3a81ce8260765536d5d86a1ca60ac296aa57d091f83ca7e0ba6ce695ec58cce689a9c0191738d5e73f07d15ceade3e1d717e0795c3566353347c4b7a2601ab02b7f99b08501357182f6ff4408557b61d78c074e05068468ad660b43bc98d6813001b46f7fb79e06d024c9293bc5290906a0ee1b7a3592d34cf5fedd53ffd8dddfd1c6548600b0f566910263ccb25cb9b16828b72588a626dbe16f1f46bd88757a795a62bfb345432a36517ee4a3cdd245c2342592834b48030c9e9adcca97cc678d9af4c61bc387b09d30046f50a3e1dc7c97474d4334dc791f8a1847a4ca210f592bc1d5fb34235ae58c278d5f7ede20677bc4fb1e84ba82c11a4eac0b245cbcf6a5efe6fa99853a559109d761940f9df9c77012eaffbecdc393e6c4378b3299cc9b58551aa1ddd7ba0c45eb648a6d2167abf537d0117bf96adfd4e385b79374fa12d575c154620f251ce2ff1078b6bd4200dc4db08ea44f97a1121747786bfe8f86ece93f08af8c0943a06ad09c6b97a228840b34ca6566bcc113b38e84edd99c92929a411a1b32d58063627dfaa27d6ec535beccd42b1e6cad681d48b42d8b76564b5f94dc52f938a11d68256971f1d44c0efdb8cc740a8376c96d2d41bef65149860f3d80006e40444c75174fe79a01bf55f06004bba7aef72abfd2ee7f1e16b5d587cc9b4c50a903d754edf4783f38940c00db97db14306b18df49b37950d778d6a1155bd8517e998f4a39aabf9fc18b1c64fac04e0b14e426bbdaae2a210f7d4d9c802e612ddf882598a7ac2f520899a9c50b118082de33cdc2a265704895d42e951a050a49f2fc6c969dab1e8597c8b4f255db7533e6ae34ec626c21cdeaef505183b8e74b4b86f155435b1b679c8f57e955b5b50afdb49f0f21a69de82f927a99bdc04f5c4979e673e84ecf9da7448c11ecc5b96baa4b5b836563637f50052047ae5f18b623db3d4d8c9a8e02cdf2e9ca3024be3871ee3b11dac7f191849727c3d0f5540e1ffc64419c44ae1f1bdc579745cb819e8fd612996e435a01848a2ae0373b13e860a307b2bf7a6c08b725f8dcde495a60cbfb783efe09127530ab32d25b22a1da2b2743cc9b6598bc95fe61c3b447309bf395c4fdd65ca614a7c8a1e6a77609ccfa400b001f36f58bf96a05601062b17972721f528c451951d7d7ebe57520c9ee63b6e2cbeb9e0241b29e0cb84d415474e1c4179283b73d399d5e2bc1e719f0c1a39de4446d3716a649417798877afc55a85f62d541ab57fcdb609fb45248a0c895c1d6ed7445495cfdd5a316316515d87a8e3582989740ba6599c860202bbb758a94da3597c4b9c6560a8399256d404a8c6ffb7fdeaa029893cc953070a4848237ef9085852f441a5b9fc47805b40fd27487ea270c536769284f2574087f962600bb34030681844acc1ae2dd38393f429ba5173e4e61964de469f9211e37528f564fbf7be213431767a1b90ba302db5c4157bdbdc6ce0bc3f269b7fb0964caf79f2bf285535ff7e19352563ca59c84bd45e1dee2ab3b97338f9d38358a86ed05f47c0bf1bcaa3b9326f2bf30a99904c3b1b179808a766456588a7a5faaab51e36d8caad8df0845a5dd1996024182cae89a76774a75b3468ed3caefc84a8699ecf658ea5a45cb01850e9135352103e86fdcd81c45ac9794f1ac28f845b6259889f361a073d9b5be2d70eaf1b566640d85af99db5ca972849bfb00eeae937335beaf9d91b87dfc53ef0313cf3bc808824e484f221265c64ab9fe803f2e28a588ab919fcdb2524f07c1b1e341c46e6bedcbe99f3289800d5548ceb59afba040d987fe14c9575
e: 0
h: e0
k: f0
l:
m: b15c6b0d56b5c04dc52f2d3e100c986d3305213b0f1b25daaddbaa6a9ed29f6c15d4db741e8075c0d3158aa306ef37c0a3363a068ad6cc4407a00f181023c85f61a1204d176b62a2089dd0256dcd719f37b1902ffae4711ade034539fe00ba6c6764b0a8a67b39c4fc449028e82f2ee65059716629ea356241fbe6331ebac0e1
n: ca7d7eb1548dd80864fc9b709cb9058bff245cb61fece48faf7e729906197666652bb7d86bbd29b65ea8dee683e81862d8a83d1be24df8d7ce877292f3e1b9169c37bb9dcd80f706efe21ad3b0e25ea0b82ea58f29050e99d28dff6130db0c4376b05aedbbcb19928ff441d83ab070c8e9e5afdc52c654ea02420a09c06e33479e24d5bb48f3088d6ef0c0e36e3f71d61e104c37e36b8413661b8b67f6d3264614cc55cb71e12675a99b92e4929b4403f1c6b9f6a8549347c7f80df38bf5e726b19948ba3a31be89ad80093672e2f195a5d87b776366bdaae692e2f291b0612237437da09a716b15594253c36c02e55359a70a3303ec4834119def5c5e9d634efaad4c2199129792db70ba19b77156f29c23af4e89b832f04fb3259c0a5910619b09cc3240930a59c30b0b0a097cdc83d0546f504d157a181e9e3104c6e9811472dd3590c1ce78ec07c3cf3069f6d6063b36dd8d41d9f7de1081d207b0733e138c622bf1744064468fbe3fc470d4cb58e3482c6e886ffc412129d9f8ee432460a10a1df5baf0520931b3a77bdd66d605a0c179226b49745a5a633b66767f7b1c28ddb9197603e5ebe05f87755690141fd4b5063cb9f110ebae74443ce60925db77e1c45e8d80bc8b4ac57c9c7463833bbc59bd22e22cc4c9b03f7fe188ad5346e031c0816c89deec2bb58a13d483f6aa8bbd1a02d47ced4ca83dd512204d9b0fe1f178ac55d67d256556baf8a6c69da3cf239ff55a1d94d9421ea6f0dce367724d6d0a4ea6b5bed13b92905521eb364c129b46358c1916285c9e8d486ed6497aa52e6b7685ea890504578fa50b223c525f50dfbcda45ce655da4f3be5a34ae279a79e7a3f944c0608cb2170b2a54539fd8c368563266a693255313038ad9ab65876f1ccc6ede67139e1f730799bd17fb40adcf54a3ee22fbd2513a29a39d02e6bd612e2317100f72df3ebd8df6edb0dcddb77f2429961f9893914bd50f2fbf7882de6321d8a22997ef2a1372239499c8bc6c23c640b33d6e0c248fa955039ee961edadd131ba860931a565820135a8c64ab694061baed88c809ca5548b79596f318c766ec8e239239bf0efd85a6638435c9b47cb3ff97b7627e7c90dc0b19a6f3bd05f59bf713d2d2b801cd5571ad1e9b08dd9255639b4703e93b93ca69a8ea6d63d08e383602badb3bec93cb4c880d3fb7feced5d3bfc82b19de343e3040330449041b4ddf787a0e30f7672c95f0bcd65259755d0f76fdc89da0ef49daef12ebaaa79364dceb13381b1aa93976c58e8c8d98c3bd68cbf8981275f54968fa12901975fd683152522e34bbbcd68c5b68121e36cbd854a58a41b3795027415e029bcd1b28865b36c926a11498977ec8019bade640d4065401627e50805ea6e172987caab09769d4b4c5f259651adb8544682be579d56025f0b64439be519e3a21918a10346a0908123f00fe21384c0db4626ab0656611cb0f3ee31ee6968646672090d740472634630a475888e7394169cb0c01e4c8dca25ca879e2d17cb5cb340fc3018afe9917c3f2615de61d5c44d7200cecff627c5e95e2ff90e5d099779e100cd7e59b75a3e00aed0a8025952bbafe8fae09f258853d4230e9bca0d8ad75e8f85b85cb085b9dd092e9934df80b9a41e446c6c72d17af7d99a6a66ad69a82b6f8b6fc5e21651a8b43ff02d60c12b471728fbe37db44a7c05c225711e7c970aaff9d90376f30ab63c5a5c44ec2c285bde54dba8600954c3f02654fef48633e0932b53bc70dcf3086f1ed369126f38f4f79236af01b27f0599372f7ddd9b573f13f4dcf9eb349a9613ab3e789814a98dd48cbe4cf9c34c794fc5e3ee47ce3e8b89ae096fce89d3709a06f65e1770cb1b05dffa8f4e514812f250942fb80688fb556aec2c02ce3e8bebaac68b510ef6f02d03c2d1b59001300835655a1b1a5dc608b61d0c71abfa4ce94ddc5fb77e0d15b6937e678727e2965e6be75c6a36fdf098ba917eb1dcece67be402215d3a00376f5d8c2e3f70f961146fea47511c82dd7b8e0953d4df1c77adcdc5a0ddf7a45a35f5529d2b15f6827f956f22c7a71e2d67a5b8370ff7e404fe6da9b74eedaad4897e94a9f683fa6333d74304a46ea4e1ca779a3a062a37179d1cf1470f9504528dd931846a37998a49503ce75d269df7a466e18de511983bbbb4afb697d150e99db117e883e928489b758a89f9aff6207905b9b6ada685953d146849bd2758f4931f92e1c14e1c60ce2febdf96ea79346de3428f8ca828916ac5a6218e8198711cce5f0164c3cab6557230ee06b741f7b4b4edc21f9422668a7eae2e46ec14c9a54a5594e1770041427012a9a36ca2ada441a0a5bb2dfa95da564fdbd94583ea8039057967ad6bead1541b760eccfb6693829c43076df047c25da34f69514a90a1834e080addd038dfeecc68ce41839ee673507c93f50945fa6c2839bee69d29d1b6269b5b541c06b27ee932e7189b200d03c28eb4590d6f890e0ec8eb7b4606b8c581e3f43d6a3c0b4c8960605bdea7c79d37a9a03b547631df607587a040eff327965987f1ace283cb79c401890c0c8c9852a51989c81395436fe11137a7a0c4fc49078121f28c3d5bb24a90183e4b9f48fbfa4e8cee4b2a7cd242bf609f5ffc432e0762c5cbee29fe1d14addadfa5adf57addb07dc2024b403d08a1ba6b61a83e57393d6cb918fe90724ffa104895
u: 143a67406a0891b5b48536f2742ae38e9fd55ed9ea36d7b69bc0cd16299301a686af0d3fe06e81b83338d81276e36d16918698a743c2ae0cc3ca8c4df85fa342ab8ec229ab4af6d8d2c30330c657906d15543b90df4cc3bde9ac4a3af4b7b87308c443b50961ec77e27fb3cd5e279d12cf83a2e702d739f12e52ef50ebbb4f176d981e97e0d18de063cf4dc08e28f3fb91f418bb543586badcf5c692503ecf99036a1d854454d930bca8a73450bf23141201dc0ea93efd24a2f885eea68efce57fa842e3dbe456a5381b02e163a0808bb3620ab6d160d4c9d42e8bbdf0ebae72409f1f897d43245a26b7bf534c8a52e076bdceb4e5cea7f13c4f48bd85bc88503d06e4f241245d070f1db46d494b146c094884a2e8a8329acb48390dc53532d5417d45318f98a64234fb94e7d31754bd32ff6dce59d192afa36a3ee813d76ecafbf0b8ba058301bbb038ed962cae87af9ac4db1228f4426366a003d7e1b2c7afbb110b1f5426e0a15ce9d266231e658d2442b08431395433374d524d8b1ee4ba87002b99070d2518c79f75b9aac5b3832a251d5398a9133554703580fd117841795745101a5fa13fe32dadfd2ddd4eb723d8f2d24054c371489af93824ab2f2844a7ab47ab07039ac511cc88b54739770d51c1452eb1ec883defb9c6c28f3ee794e11ea2937658a71abbe9454b33f7e450fca9c2edde42aaff0191f4943e5cbd793e77be6a7ccf0fba6207a18d0d7aa32563d7ee37fce1548dea5840a4bed6633f448e090e84964626dc164821a95afc835297a454e4b35c22a1e27219a04ebfe429a5f63ab91f7d8237c67395bddd11303665fa3a0b0e21ddc6d86db5a200c796dfbe4f0594739729ca3dbf4d1ef5beb113665599e5287c1c9f69cfe0c1745824a6ab5fab1dd973770001a8764fba086f0caaa053b613693818e92e86731e303aca0955e215f5eae0622f245f8bf10edad03848c0e2955bfb5752d0025eedf6b5df3e1b6b1f05c793172457f789610b9de18683f4de4e6fe4c9f126d8de1acf8a383acdd34e8d994a16cb975e2a721cf3a1db0eab2bdd499e5a2f5145919b1e90340ea249d678721a2ffd59d52e4eaf2e68a96f42eff4ed20f058f727079486034cc02a00ecce409075236e0ed3dcce5b0f52cbb7b60afbee47ca53de9c19de5439589f9a95f735afc6ffd1ce8484aff9d8fa80c7b25b501e5daffbdca98552ccf8411b19ceffc7688e81af6254e64311f4efa7e188ca4156a03a69d0a3ddcb0fd690214f5156461267064189c3b2cca274d3aed9b91224096e5c8f70ecc1a43b088d5c0655540d191ddee0c5996f0a73ccdfef257c8a8001d6fce54b1361a6f022b3c112ce40bb59921cfece89dc908ab069dc43b40f8fb5076e9be04b64f180a8195163e729c6ad83442aa4d5611ffb546d1fd016c067177d913c580e5b29422cd5be612217a85697f8d8c7cda5e09f20a0e4e9e4f00c9333328db03e1b7c62875a2d11c082fcb6dd3b74118884e6b73b17510fd6ef70b86645bc66aef8c3948c6ee2d3711e3cf5a98bea42bf3bf72361ff7d886b1dbc3a06d2064ca593ac9fa0e534874bc7f3f6a692beed9b0298770c99feb068c2295db2020bb1f8a421cb49f4c0ca39f923004ba37bb7ee65e9be9b76f82e109a3c7f3ee6f92cc08488b392262db5e971bb38822783d863c162748ddd6d3ba5f9449e91a4ed17f884849bb6ee352d2b8b954d5612401adbf333062db26c74a62262ea7dfeecfa3f8910fb2088416f5dcec169ba3e075a5f0bc40ec5ee09ed272833c933cf913ebd8d3979d40ca2bb14f47022e66dd732f4db6b5ca74b7842ea6033c1c70d62828b0f0351e93a95b119af95e0fe09825ad1ccefb4b8920eea1c0e902f70622c78e7e93a5b9b50ea4a0ca6b1428102318f4a988ea4e518428e4c99a93e61f52c9caf7ececb45c78f9fc6ad0d75930c18defc8b27f1e272aa794046269a607a07592b966e6b30bab701fd7091208aebee110f1c1e662779c91327a69231c0b6c95be6839b4ae9ef9508f46d3f83a6119c3328b3a06426be24c8941df0ffc487fac7d98f2915a73f60466d3341c998a70cd9ef1b2a14530e731b2db24ba8df03d22753fe91f58e65b0d123d913c92123c37d48422f6fe62e38594602acc66b0f1dfaf58d2725829eb50792d91ed2eea7212b4473a763cad64aa4c0c613b1dfeb1bb92331bfe9628237450c43c9ec6da4f179b0bf4be479029e47991c3004bd8669490666ad9030688d3523ce79723d67328932f08d21c9802e63a013aa566ec63ca4981e5d5d366df58181818bce968e503c24a90abdab709f398017d2bc43ff01a2b59f585a5c4a46e3ae99d30b32ee944d915c5522bd45c1a3f246c49951a53c391bd8f925d36518a0ccdf6903e07502e8c38c0d4fcf305e474a29601f776e43ee357a57078264b518860bbeaaa84ea4c79a9a5308f99f892a947ec121ba4a107e3ba222d364287973c9b1c3f24f807c8b5af5bed2f1b8d7955e2b4fbf326945bfcc93b7136e6a2bfc7aee46424952687a5f847c424ddbaa7f5bcf42aee68f7194c5b93132b9f3b7f451474e520f3f3368eb32c0b4a993cf315d4b26e6e8409bcb68de276bf0e3ac68ac3d2cb1d2fc65ed142ef05b7022ed546fc5a27a6207682f73ef75cd93b76cc2d6ef9d7cab570ae054a5361a44e98c64f7076421355a4484f7f78ce
c: 45320808f1f93f46a6c9cb869592ca6d605d4897c26fcc76eb4d86889c52ff9d18b859ea2d16aeecf3654c446f54818b008dcdf29cc7d77c20b4dc68a9a085328bc99cc216ce8482490793ce3bf91066797200f64af640c02e00652c2826182fd1f21d1bd7e88e2969ee4568b4285def3b622455267538080ba8c0f7265c910474081159bb65e3fd5f6854f2b028de7c51560798c20c049a256f011e056011e643177927dad51222d3b897eedc99f2e53d11984d417b435182e33260332234aa19c8b8b85fdb6a82fa955d95d55504272f7e42432ca0f09ee33e0f30488dc03603653e5fb6e45e57856c9c3d46eca6969edc25423b4dfc6689157171f8ccf7b41bf637870d2121be28146834f894c5681a87c9e60a3f057569afc654dc264b7a97dc3ccdba80198a54c83cacc18373b603e29b7097ea26e05c7ff82d257e875ad119fe469691280cf71fe51c2d336e3d03de6666a1d513fc76be0daa84420b4c7259e4e42076e63317ab9bdd0cb5bd2be9c70e38c8e6d7344c3774838d2058516fe232add9f00648594f63ee3d50babc17074a530e0ce3c35903156d9bba7294ad824c9df2330b52667a4d2eb1617ab079d06ae9ec9784a9fe3a0bf8c8ffc751f15f5ed101a1a8a732ed49e93631ff9112641264a5b6657fba9c7b419bba12d50dcfd4fae927e29bf990e9ab50e5f08560d27083850dedd97d1ce5b2cba07e43ec3e1ea569ca0fe0f1ff20eddc454b608221625be310f3bd214f44f8012670d2896165075154022388de3e27370bc2e3d3adfefd71106892840fce19e7f43d86ba17e7f3430682455f9d933cc2b71985f1ee2d2991dcdb433f7dcaf95439b7358def763a4f2f76e9ff1e4fbe9bf4a17467aa4d0e5cc35897f60a0b25f7ab70d942ffa6bff2a7e722273a1fb8a162d5c6b670749544873909488709c939ea7b9c0dee0ba8e9eb2704dc8415bfd124f76991aebdab8a0f4060735fb2624c4b085b2d3978f5cbca74997644ef9f171b8077b2fa628d844a98d18ad2d4fbe03e8f864d868b489780dcf43310836dee2b8c00a2e5dab90eb397ea08c94bd8d4779c8ce3e783a14fef2f1f4ad8bbdbd2964f69cd5e8441f1849f290b8a5cee88c8012d2f14f483c7f3f67bd17b7c90cf7eba81ff5094ff219703388a713dacf0cbd53b48afac1c824d72bb6e8a22345966e538ddef22fae306541377310e13eb4380824e7b7e2c1345fe86d188dcdb4af5412aadc6244902fe768b2e998e838d039691f44bc1360cb7db121db133d5801a3b48b93725c7fe4f1bcaef5d112299c19d44949a77ffd284651826cb3ff7ae3a29d0ae43344ae72a7b358718619787fd944e034256c4092e98c23aff3aca21ddde7d702d9bb9ace929e4efc5b049aaaa3cb9ee9c869e3473a5c520981c5e95d9715c16bffa6fadf306fa563d8ead8bf5c2afe2a48cd0eb8a3b62d810d0539144ad51792c892e59ebc291b53f71826381c193de8c55681ab90f7e776faa3a72c3b0c6178a5c9849a05c4210a335c5607ab50598ea6292a2b7d758a40cae2df95d94a9345244db53c33bc5fe5330c8c9f3278f6571106cb0ea23929fac970adda39ac1d1497c7b34bb3d20e6d4a4aa1a230bf28b99ed1142ec96a7ae4da8e2b00f338e12814f536a67e363bc5219610a74f42cab9e8a61cb83fb4fedc399feb347cc3a46dd9bec07408a22684cb67f113884df76167293e7c536d19f62a4cbbdf89052d181843a374063c6db08702af003072752569d5b9f6dede9a699b4bbad98393990f420c69b98235b0b37fb96427da44ab9b068029f3ca4c8ce05f95856868f45ce71aa0180bca3088dbd9cca45b872fb213a9fc1967f3ad95e59a612c05e1f31d66cdd602c1cc8a238a6b4bad84947b7880bf0e040940ef65e1dc36b831374efef0d1beee41e086027ca388fd60c065813a91292680e40d8d9959728b7e78766bfce1bb1081432a9603629da103d787802d30ac852e59a0c7a595f0709ffc43600e42b397143b8d90747ded8dc53ce490a7906f3acd122d8f517ce35dc2ad037ea384b8cf01926a6589cdbf22cb9068d3f4e098f498e0f9e5ea9143d9eacca452cc99d7f1ecfb77dd1c9059bd398c9932b0b599e9bbba08e52857574c32f353c108576a78aa6532174a506fa6ecb1c9f6a4ba1c83081a79e88dcc83eb865630b77f809018673a07706fb8d8224ac68a44993e1a86a44dd2fd7975d147bc678e437afe2c8431774f43a8e73d67d28838c2703622310a93c3bdbc6319d0d703008f558ccef63be374a9e995c779f4b78164475f0da22cb46311b255a316dfb411a8d30a79d85c5e9e88778f8bf3897f2cb26b964ec2472769dd71a820a405870018b4f28da3762bbd8f6c50a3006d899a9c167bce61b6892b170d39b879b0fb7a88007339477005d081890beb15923b34eb74f8336ff171448bc85adc12e95419741e941314f3a9cf9564f47d4bb52d98b117012a782e53682863c8195032839c8523350247cdcb0b919ea2198f6eef9b12496342bd472e211cdeab4061ea084ac8616b46aea2084507d0467be39d47e6c6eaf6386d3cd4795793312ee06ad8a1a1a2f010302231e6e2a3fad5e312d244715395d1c56793dc79a81e41756a4f6d87b7848d4e81e7f93068325debbed738655a4b09303b8ed4b70bbc3106c954acdcd615ee355372e0cbdd277d0a54a87bc
d: 7d242fceb8161f1aaf68caa8e31381491f3a64bdce63a0aa92358497c912a7f6d85923089cc2378aae5161875117fcdde04c334e53598dd74ea9af373095c73857ff80d0087f24dc67ec3bf562e12c8cfcbc0e5381c37390b8099c97f34d15ac71a89a1a12211d42a7a81e67c98ba35b606d0f73899c3573bef62e6ec298f8a91818b10079f57977507e30ca6e42e5ed4fea6dd579653dfb08e1895b07389f7639c062f65a5999cf57f6c07ebc0131b477436829048fdc40f833d929b6e952df66c8d00021549b565ed3e915e200ac7d3022bcbf5d307d620f248ae08d4fa115720eb2bc8e380aaf5f77721b2edc642e53414be2de8b9c9a06875c707c39f68e5faf7de2450d8047a8b4470c4b106f4dc54e50eb86a9f730e5e9a4bf7a4c4d2b2e60d588bc6747ff6c6bb27b76b59a23135d32c63d7e57616e25567690f8c2ab8565bfe32da42adf22b64081aaf71578bdf527167d7735f115135241835097d1bc9c337d213c131ce9f2df666d61b480f6fe1d371c768c2755315b1ffbfe765626407c8b05bc3d49eb88d81752ec86d5c7a88df34621be2676698a5632eab2fce3be5a29ceb5394a7cd5f5bea3f26341920e116117f76a6eacd2293bff0699106629ff24dc425cf894b8bac614cb6cb25c97dcc5b82d6b275f3af718d095e0e23b6fd732f4224dc41abd0ad06f7d3fe00c4c92a116f2cd587e8ed8692b96d11cef3300a1570713cd7ccc087ca7f018e170ee100a53be85e02b8d8bcc58f6e75f9bf795f68632e2261ca25f014aa43d18d19c736d29161810abf01c4f86850bd79cf5a51f2ad336c101d6c114013094b44cb6094d5cefed50f7f772d9e3c0df26117bf9a7e047563a518f7f0fa6cdf1af2f9cda6337988bc5ce476dae042d365419ec59249a28afc98f57807e07693f610ffd1cb12c61f1affec566f1ac609385cf8a94b6553426349cc3062e8aaf11c7623d6dfc02a662b8fc505f25d0233637034ee5d8e34367f1aec0a2668df7b675fed5976c48eba567f38b9ad5a07d1222a97c50776beab59e191973b6f886052808cea1d38636b42aa6ff65d15f810f24fab30634417065422d2f31ad353d05edf9a1b7c373692f778da364492b597901a1c570f5164117eae052cc9ca42af2946d6f6acf6cf6c653eeaf42fedf37c500d20800c4a4456ee55d549ae5c1dfeb516abfe649965182929535ae8dee2180de5a944635bd7baafbbd3830a44a00543c3ff18eb17086741178cd3906c1f6866a694d536b3971d393f6e05a9f35ae9e13414268508079128791c9a2e790aca9c46c66f951565718a815e25c500f1f6b519b06b564d4098b9b4cd5602c18cca92b14e6a1d63e0306fbcd614361f35bed90fc97c7a3da5ec058bffb3f78c2561da5da0425f0714b6ec4f34d12978e0a47c28e39ca49372e566a82f19169a55c039cec4eaf4cd6f5b3d0a72b6d8a7a6d410ff25f7c96fac299561df37ebef05e351495be1ee47984c1185754a0420183d2109367fc5051eae2b7ca181fdb896cc085162439dfc80b27189d7ac6b4b5200a118cb4c9dcea83c4a11024fc2aefb1b8bb215dd511c40518877310daf486aaf50bcc65a1e9e1112efa732be680618fc322dcbfa8c0b9e4a1e3f84019238e7a9d89a8b271bef35fffb4212a9c7317e773235ed2aecc8fdd1681625af76d55857223973f29b6ec5fc1349cfcfae0881728a9de921f34d9d5f1d02cf18c94bc56c5ff75ddb97300c24d3017443ef05aca5b34bff53c87d3f68b62bc24415f7295c1047328c7bf144dfb7e8deda5e8fadd9d23e4c83ce259a08196901dcf4674c372540cae8c59f6a0cd9eb63613bae574ba4a7fe144b4eabdd5dc860104ff5316f2096bcb5f649bcf4d4c0f9b39727a99b1c9433639306bfe85d1128200b64969ad5e6b473a1516eeda4c1a16d25b954bcaf509845446bad9815dfdb90d28ff83a79e38ad21b87eb70b4c1ca5f7cba7c1208f0a29938a5f36c9fd7013a85939cd3c37a3521197ec5b66c2f20476ab6f2ce362e43d26e74a11eb1971d04ea65de3670e01cc490a7315a8297d308f327ec1ef901b757b069e937fdd3cfd1f6f26df713d671e6c717a9dfb2f466b0f42cb08899cfd64a47db08f1899d76a4b9e69096258537259334202e91b57f9414f309d25c9b42010bcfb66aebb0d56375589148dba78a419456dc912e5e219b2cfd8c6f08cd40bf03905bbbd55916c4ae574746e0a534affb0cb8def37111c481c72b482316b57f0d21106ef43d901fc3c95ad66795513cc0b22d9a0317ce32fa8576ecc38df9cf6d753d5ff54a65ab6c1ab5d45c8a1108f1e494933bfc3c1fd2c940087eeaf40967c5007b253b2e492005b8d8737b07e8f821dd658f3481355079e0a2dfedebd9b3f233f4b75346263375788f01b841d07a2cebb68f99b4720b0897a4c8263dfcbe1fa326eea265a1c6e62a2dc3e8334eb07fddc42c40aa2977d0b2c7e6a8529cc015f652cf9f2f8bdc4424383a89639e6a2c3c6d4f884ce47b9b365000becca256c55342bff0c7207287c39c65d924eda3ca525cb477d7fc6a356ae12cc27116c548d7b2e89553bde43609d18a36ad493a9fbb6db9a97659a6d31469af55376e7920ea8a8017b350bec07e6a4f12f5ebbf5d4f8244f21442a34bb53785c46284966a6577aff8797e375246dacf654ef0e51fb78fb823940d6102dfd5b01
e: 1
h: 200
k: f0
l: 286441575e473835353a314a672369397c734f6f24655949487934292a3b6a5838663f397452356f5e553e22237d78286f6f66384f66536f717d644c7a253c676433394166253a406e553b3f27356b6e4a68204222724835207071633a5c302d633c70667c476d705569475834693660
m: c6b7d79a22423dd15c977198f95ee48de52bfc446b3c8f8ce48aead4b5f8f57775c65a
n: bf2a6864c583ffc4211a2f1a2e97e67d0ca2a9a2313383a298afb62ed6f2f64e7506c3533d58bb7dc2f1f3daec9a52120d29f23e377e423d6474b41da4af7a9cc95a3d3834b247e3879ca2a60b914b91731048d7f61cbed4178017e0af20d63425fb14e9a60f271b5edb81730e9dae019f2b30658ad429016c31de8accf4b7c03a70bc9d5b9b3f8ddf8c4b3c9ba7484f77ff209776c5efbf4f5a8ed4e2a0bed82ed248d097e5dd77d775ce1386fcae3999a0bceba813010b10d1f4441ee75dd7be7572eb781f332df8af9f707962c529e7950d1ab553b5b06d11ecdd3687409b29bc134e174c90294e1a252dbfdcfabab7ffb55d5a08c74960c85227691e6fd3429da2cdfa3f11715840babfd7b0d1a61d8cae70def69235f2f58cb2dd1d76591f290469bf94550f1f834e20c7426516259823400d64c3f5325de6d7997521bd560a827e6a790a1aa582ecd85d0b16e6909b1433d24d60ae359020032f11ab5a55140fdb455b4f79bf32371271663a3b18540aad2cc665bcf63ae2971af335629d9836958046ab19e9fc6ae22bad9df04f3ba5096487129b4a751427bf8f914bcf6c62b86f9a45e89f28266862eaa51efa1d425c6704d2e3acfda946790d48849ba2cd48ed1a835d7774fcdaade3d2042f45c98ab7726ecd35df751bd72d64f9c8c1d3a53984aefe45c627027bef3d999b169bdec8e01a0942a5ff8bed9f0d0ae5d3f63d69461b369a38f521cfe2ca3ee766947cc232aea30da08bed7576aff8f47470fb435a5b104e879e295fa95b381e645946f9c104aec9b75285cc8b12341c014d22ab205cebba351fde682a3c02a24b7bd65cf3787b18c4124a8854211f79650aa1e91b05a18101e09ba81a35da8eec85ff51d4cb6570d8519118480cb4af56ef5568a275a9171339976ea32e423b1c6b5980341df146a58fa56a61fa9eb80d1af0ddf1575fe8a792c9ab3aaedfca2e855036a00588a0edb3a26251e1ea5010dba2a2360880edd68c2c8a60dc3e53f765a175a27f6827bcf7cefe863a369bc859c46d4832f09bf3ffc38afab9229be0518c12581cbedec68ab41e53cb3106502ddee478c41e22ed759d1b60dd5f7b93992882f82d29cfe00723d60e21d708dc8f52172a51d20e0b6a26b1fbdd01594138c3936f9db9edb647db4185bf6453298923b389c66c1ffeced55705a6e84c93d8c4f0fe4c79894de498c91048bff848472ffc48f1c8696d13d971cbca15b8a4f84be58da05bec16047cb4c33ed0ade73a9cad507a6e7418f9a90ca631a22b670f9d861d1d0a286a9389962b49b3346020cc064dc7eda90febde9ad4b498144a3bab0986945ee7377cec7e50da9772605bbe374bdb47259a171426a428fec8e4442f8ea248d6fedf05680f8a3539c588d2b789c02122ccd5725c71c4c96025beb7f44ace7ce0f8fe39869e8e869fbb101490e72e332b60a32ecb4fa74fb3430b3e6f2a5faacbf0edd3c71801b5673da1b7315c56a720f54912265171a462c7392cf78a5626e29c4a323e4720bcec8b67d4f2a323b7b540bd46d81caafa0c88ff22a9fa052509bcebbefea14d4e70994be11fb0a48ca186be0db0c0be7dae1a4e6adeb96beeaa2261cf07f734358abc5e3cf0494128c37ecbf65ce0dc67f494818a3de269f25b5f8d08a25a5ea63149f4a0fcfdf08d95a6ba69e9b90f8c3696061dafdbd17df894d61462aba44c379b6824dfc340bb23af8be5344bed968d918f2c4a9885a7d2f492b2f5eedc6b258e5bd2dfaa6bfe10ccc9f29cc52bdea47c883b2b809f8da4d1fc187955ec0b8ae32ad2f7b804b29b8811333e5d230a52e36c5b4cb5b52bbc13783464c94eef78513397f8f019874bb42e3a2facb92f577e9b821a67e5fccea4c5e30b2f09b8f3ec685288b861c324ef145e7058ebcf6a086efba86b287b5bba3804990254e9c45568d85043d950f5c4bf0408befb9e866acd0793e8f05c140cae73393c4e3517770b28d6fcc4dd2ed61713907b7b8f6d6b9d381f15ab1d394a27998e3bce70c3b77eedfd9809513dec8a4f7b46cedac20278ebb70b24f5e350bb0e047e52e2f21a5349c95311caadfa5ca7e8ceb92ba85175605ad2080fcc38a2b341a1e414afd6829e9db7af6d1fe06044b59364e81c8384077cf5a9f6f9889624dd5a7a5d98da45b4549bad584be7266c2c8c53e07b08a38687efe9ff9a3af9d6aa445987715f04ea4ffb6fa7235f7d1b945e43b282967bffec446950518f23d3c789bc22a302f16b1feff64ac1e66465d478fb3659d2b98ee43a62ca57927c97db67e78694bb36e1af386c088d3a7b7b9d736acfaad0edd29e04ff6277b3fcb59cc8c93567f833f6749833b8f949a81aeb765860135ff842e641c2cc4aaf44070a307ba17b195d22dce683ab582bdc47111dd90b4824aeda69b87b27eb29698855c7b2eed47947ebf751d498aa4db3566956ba0f41b057800b7e516becfe58e3d2da0208db0814bcad1dea857f92f9f78d8a9f322239c10fb746055fb5a3f94ac3dd55d0b6745fddf66e4ba3b98acc4365ca06e025441df4893a7811b1bdf66d0823c61a761693a596f7314fe4d34c33ea5e26038fbaf678f26db37131ebf5e01315ccc34472a276f59941e820efde70077fcf54a405529124542e4ab4e9d24fda583aa313555b0f1eb1c3cfd1ab64bb429d5de11c2fda883056353c07d95b20117ec82533
u: 156d2b5c9e2ccdd5f169cc8333e94d301f299180af6daa8a3442b729122a3230ed91c8afd226f57fdf0c7165040e8f176208201146943572ba2eb7bc405dd640abddfbccb871126b029ba71f12cb4c4a4a2dce96debb9db368d8b52422884d1657f39328d7ac0642257734747532a349d7db9ec445bf073d25b1aa36edd6ca216c4a62417303e31c22059e930d4fee0b4c2fbe04f3894b7d731e2b2d83d07bd8504306140899ed7200b96aad4281d62183ebd10daf66d492ad6540b810d5975f6876489411fbc250acabcbe343b6d3f8658f11fa3b1baecfeac08e09cae78a49a1da27a091c2aa2762e80b8618f380e23c57ac1749639f76963d39eaa4f04b0dfc1470b10933319313779aad2b119cabbbe761f1798e9122cad9ac0c7201d8a979942d82c5df9e47e5d3a6ffe061761f138b717381419fd4f263e0c30025372708c27147391a3f49dbef960072af54009ddd276b7f4a9ee8ecf093826758ac2b9f197d1dc52941c06bf92cf561e2f2239466d8549d865b7999f3fed749675e2d7cdf325803ec1806a3bed6c0a1ae9a9885015c81fe0836d8ee57ff8c6dab364fff9c26afb7ca9deb6deadb36c8ab71d317ac8c1216eb26718665109708d185030280426c9d9b4e6d0ea3eea93d8d031814f52bc73d4c179e9a93f6294324743bb30007dc602aa33c354c2720154fdb3b8840e2fa65f8f439360ac7d4d058b3daa063831ba86d941bb98e2b1034b9395d41fdf5f37f55922166ef9a3e7794a610f6675a8e5bcfb3f6c07a2a2eadf69e50a873c75046f6fefa3d054b2a61f271fe20a20841debc4692d5920eff9a1bbb5345be9728b18bc976aad38470a10656d0ee26c8907cee9f808efb32153388e4755564146f7f0916c5485b488a432c97d32ca2c2537160ef1695ce126540490258cbaf1372d72adc6f351ae404555127fab7015c8698d5501769588852645b7c7bbc225ce8cbaf9f43b2a478b5ee3b32bd966910bd03f2e90399f61c636e7e2a09dc5d1b5d2ae02f31484f1f150ecd417af51fa0d601cc711734af0c07bfa097f3c774c30ea551bbdb9c9fb62e416fd50bf734b94797742f57e73504efe1daa4027a090a31d41ecd27c4b8d54e506c4b8b454b5981573719e1a61bbfde4e5e10113702d17c4a952db76b8c6bbbbf5cfef2d17abc6754bb295e47c719aab731be37e46b931b6305eba043e1f27f5dcea3bd1342eb5255e582f20832e6e0cab05e80520ab76ca53d5cadeeffc99933d6598b129a1d798eec3e45ffde349480a2b92f6d6384e59fb65a3a73fb8dbc5d8ac92efb0bbb27f65743128ba6d2a9d855dfecedaccbccbedd58fca4e823a6fa7048ddcad1776b3d4946190b12d45208dd68ff67979c52afe5d836c5f913821af095ef10ae732377803ef827307aa02d5b0e8355cb7e0d34965f37ebc6238e799d634c0b11450d82379c8a336de041073b8d0c712333731ada41e96fbbf5a8cf324fc298e97cf2616a732f3f0017864e460bdf46242056c44219e2cec3a4f00db168f9fa4288ddd88b8d96060edfb94d7fc735514d0478b36410cb8cad49a60bdac6d3ef63e07eddb520182ecd4dca88ff6a2b16e72b860123ae8564e234c3da60ccddf49d31f87a208bd44d56c772d8d0899303e5e48f59fa4e5e3a8399b972045d9bcc770f325ac917736ccb832f7a74935c7d0d47a220f300e477382128275b57f85dc83a13666597bb361e37819ea35e4b36768ffe9c8a7cd08bc328dbc0fed1b1daa1376ce5c0fe44a08d0451b8f1025fa2c7c484fc5d0f524b36217f45a08d06cdaca2a34c6437fd128007c0196347a29e54d0b01e59cc57c8a6c8d059a66af3ce725a4344956f6e948dac86107b2dbf3d603b27ca6155a47066f11824536090bbd2afd38768640b04bbb2e172aab371b887f93cda823efa9985c788a77d1b374bbafabc429d53165debf7e54d768cd2e61df0ae5a8c75818ae2b70e7103ebe64f6b91b2ec96699f8c13d233ad33091e66d0bb10ea2e12cd3e4079a1e7ac4692ca9f51f2773f3f47b3553b151860fac26739fdfed826f8e45770241ad823f19be215ed7e995a46eca3c843339c3290db14e7b009e9be72ad81fab469a163ef16f1869567d884c66ab8fa4cc4c3a12efd0b2c260786b4cd9d7f4b97a591dbb7677c2109f0bc74184d21d6ca3f8989f8b0151668bc435c3c45f9f45e371ee32e3a098aaf03b8534c9a66451156a13c2159bbb2a20074542db1093622c3e4d0cc29573ebb38c44e2470cc2acd1564d15b7dad92049b80b5c7cd8aeba3fada6fd6fbc3e61049475e3b0f8dcdd5d21b12f2f9a14ef2ff9fb5c6123117b150cd670be3c8fcfd5948a27f1cd75ebcd4e8fab24c2d707ced206ac6d7ba1453ca6ead76e310bc05cece5e5f313862411704d11ae3951f3ab211902f349689ba3576185946f89f0ee74cd9e189ebbb99a15395a9ed33a51e8766bb10a2408089aa09b97e381f1a32397162374edad5bea4625442b7518d7c525da15bb229cb3b14077eecdf26a29d9d46b31d2c5d06a5d2f657e7264956475e1f1241f41cb7cf8f097eaa3b9a9ed5f889f3145e336dbad45ef3c70e29660738b65676cb5bc7b18427d3de98c8743cc865c8fcef41b816d04b16a93a9dda042b7cc7a95393e33062379e42551143e61702d9dd3025b77bf01b737e2119bf7cb527128dbe8af7c0e7df5bf7241

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