Compare commits
129 Commits
explicit_s
...
sha
| Author | SHA1 | Date | |
|---|---|---|---|
| 82bb499be3 | |||
| 20c65b93bf | |||
| 7c45f898ab | |||
| c675aaa5f6 | |||
| 6d4c9c4f50 | |||
| a34d8dc88b | |||
| b59653de57 | |||
| 3eee154fe1 | |||
| 0b4d84b038 | |||
| 54687cb602 | |||
| 1bac2010b1 | |||
| 818b006521 | |||
| bae1c93c54 | |||
| ef3174f224 | |||
| 89c8705779 | |||
| 080c8f18e2 | |||
| 060b82b351 | |||
| ba2ceee725 | |||
| 4d2e43620a | |||
| c5850b4d01 | |||
| a19c1ee124 | |||
| 2145fb47fa | |||
| 2912c72a07 | |||
| 23a79300c8 | |||
| 0e6664f232 | |||
| 4ce8797da2 | |||
| 7f2b509640 | |||
| b0885722a8 | |||
| 83cdd8ef4c | |||
| 2f395721bc | |||
| 2b63dfa376 | |||
| fc09ff48a2 | |||
| c9f418feff | |||
| ac380d08af | |||
| 25746af626 | |||
| 16cf6172ce | |||
| d2bdbd37fe | |||
| e6e3789127 | |||
| 8bca480e47 | |||
| b42902e6ab | |||
| 44618c2e2f | |||
| 4c03ab6648 | |||
| 1b2d7db1e0 | |||
| 9cf0b587b2 | |||
| d459850c54 | |||
| 6c61e1c56c | |||
| aaa8dc3497 | |||
| ad484877cf | |||
| 1eba2d1709 | |||
| 29872fa47a | |||
| 031b4be14e | |||
| 8c87f945a1 | |||
| 6d2c803f2b | |||
| 8a7e604fbd | |||
| cfc06c3b56 | |||
| 40a5793089 | |||
| 026b321f7c | |||
| 887c90202a | |||
| 6613f85ff3 | |||
| 22b4fcbd94 | |||
| e4f67f0918 | |||
| 68ddc7096b | |||
| 54c5244bc5 | |||
| 06d3391748 | |||
| 3a0d08d572 | |||
| 1d1ca3d817 | |||
| 69cef498f2 | |||
| 47fae77a4f | |||
| 06400cc7a5 | |||
| 3a6ae61707 | |||
| 5a69795fdf | |||
| 40254014d3 | |||
| 9d2e56ad06 | |||
| 95c3dc94df | |||
| cc83b239cc | |||
| b3276ce2f6 | |||
| 91d595ee4b | |||
| f1f39f8b5f | |||
| 038db66c2f | |||
| bf13f4a1e6 | |||
| 15ec3c5c9b | |||
| 8d8351e833 | |||
| 4559b80d2f | |||
| 293a93c6d4 | |||
| a3b0ef8d98 | |||
| 9ce976bb6e | |||
| 94defc4e77 | |||
| a426ca3901 | |||
| 3716dba87c | |||
| a390a7bb53 | |||
| 71cb38ca30 | |||
| 322701ad6c | |||
| 8a771c05a4 | |||
| a8174ac47e | |||
| 00b944e30a | |||
| 63bfda9073 | |||
| 4529562cb8 | |||
| 4af5446e80 | |||
| 04b4c79f7a | |||
| 89deea0337 | |||
| f60a492a0b | |||
| c5e9d4be25 | |||
| f4e47154c2 | |||
| cdcfd9a3a3 | |||
| f3494d8524 | |||
| eb82edea7e | |||
| 62cb276888 | |||
| 160618cdd7 | |||
| 9d87916cc5 | |||
| ef54ed4cda | |||
| 43b73139cd | |||
| b30fe6a75f | |||
| 011ebc0c99 | |||
| a6def22bd1 | |||
| c49cd29c43 | |||
| 65d7b7e93f | |||
| b93286fe60 | |||
| 5a5b48569b | |||
| b5afa8fdf9 | |||
| 26eb05ceeb | |||
| fee68cca18 | |||
| 11c951d29b | |||
| 72a5c4568e | |||
| eae2ea49a9 | |||
| 69596c83ec | |||
| bebb5b2861 | |||
| a5f0179d77 | |||
| 041f824caf | |||
| f088f0f9a5 |
13
.gitignore
vendored
13
.gitignore
vendored
@@ -11,3 +11,16 @@ Cargo.lock
|
||||
|
||||
# And these are just annoying
|
||||
.DS_Store
|
||||
.vscode
|
||||
|
||||
# Ignore testing files
|
||||
**/*.o
|
||||
**/*.hi
|
||||
**/gen
|
||||
**/.cabal-sandbox
|
||||
**/cabal.sandbox.config
|
||||
FlameGraph
|
||||
*.user_stacks
|
||||
**/.ghc.environment.*
|
||||
|
||||
test.ed25519
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "cryptonum"]
|
||||
path = cryptonum
|
||||
url = https://github.com/acw/cryptonum.git
|
||||
@@ -1,3 +1,9 @@
|
||||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
matrix:
|
||||
allow_failures:
|
||||
- nightly
|
||||
fast_finish: true
|
||||
|
||||
22
Cargo.toml
22
Cargo.toml
@@ -9,19 +9,23 @@ license-file = "LICENSE"
|
||||
repository = "https://github.com/acw/simple_crypto"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "^1.2.1"
|
||||
digest = "^0.7.1"
|
||||
num = "^0.1.39"
|
||||
rand = "^0.3"
|
||||
sha-1 = "^0.7.0"
|
||||
sha2 = "^0.7.0"
|
||||
simple_asn1 = "^0.1.0"
|
||||
base64 = "^0.10.1"
|
||||
byteorder = "^1.3.1"
|
||||
chrono = "^0.4.6"
|
||||
cryptonum = { path = "cryptonum" }
|
||||
num = "^0.2.0"
|
||||
rand = "^0.6.5"
|
||||
simple_asn1 = "^0.2.0"
|
||||
|
||||
[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
|
||||
|
||||
11
TECHNICAL_DEBT
Normal file
11
TECHNICAL_DEBT
Normal file
@@ -0,0 +1,11 @@
|
||||
- Add negative test cases (RSA, DSA, ECDSA)
|
||||
- Make Point::double_scalar_mult() not truly awful
|
||||
- Use std::Default instead of the bespoke default() in Point?
|
||||
- Run rustfmt on this stuff
|
||||
- Run clippy on this stuff
|
||||
- De-macro. Surely some of this stuff could be turned into trait invocations?
|
||||
- Test cases for key generation
|
||||
- Better, timing-resistant ECC point math
|
||||
- Make the x.509 library not terrible
|
||||
- Ability to generate a SSH public key line / file
|
||||
- Extend SSH examples with public key reading/writing
|
||||
1
cryptonum
Submodule
1
cryptonum
Submodule
Submodule cryptonum added at 666378b14b
@@ -1,70 +0,0 @@
|
||||
macro_rules! define_arithmetic {
|
||||
($type: ident, $asncl: ident, $asnfn: ident,
|
||||
$cl: ident, $clfn: ident,
|
||||
$self: ident, $o: ident, $body: block) =>
|
||||
{
|
||||
build_assign_operator!($type, $asncl, $asnfn, $self, $o, $body);
|
||||
derive_arithmetic_operators!($type, $cl, $clfn, $asncl, $asnfn);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! build_assign_operator {
|
||||
($type: ident, $asncl: ident, $asnfn: ident, $self: ident,
|
||||
$o: ident, $body: block) =>
|
||||
{
|
||||
impl<'a> $asncl<&'a $type> for $type {
|
||||
fn $asnfn(&mut $self, $o: &$type) $body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
macro_rules! derive_barrett
|
||||
{
|
||||
($type: ident, $barrett: ident, $count: expr) => {
|
||||
impl CryptoNumFastMod for $type {
|
||||
type BarrettMu = $barrett;
|
||||
|
||||
fn barrett_mu(&self) -> Option<$barrett> {
|
||||
// Step #0: Don't divide by 0.
|
||||
if self.is_zero() {
|
||||
return None
|
||||
}
|
||||
// Step #1: Compute k.
|
||||
let mut k = $count;
|
||||
while self.contents[k - 1] == 0 { k -= 1 };
|
||||
// Step #2: The algorithm below only works if x has at most 2k
|
||||
// digits, so if k*2 < count, abort this whole process.
|
||||
if (k * 2) < $count {
|
||||
return None
|
||||
}
|
||||
// Step #2: Compute floor(b^2k / m), where m is this value.
|
||||
let mut widebody_b2k = [0; ($count * 2) + 1];
|
||||
let mut widebody_self = [0; ($count * 2) + 1];
|
||||
let mut quotient = [0; ($count * 2) + 1];
|
||||
let mut remainder = [0; ($count * 2) + 1];
|
||||
widebody_b2k[$count * 2] = 1;
|
||||
for i in 0..k {
|
||||
widebody_self[i] = self.contents[i];
|
||||
}
|
||||
generic_div(&widebody_b2k, &widebody_self,
|
||||
&mut quotient, &mut remainder);
|
||||
let mut result = [0; $count + 1];
|
||||
for (idx, val) in quotient.iter().enumerate() {
|
||||
if idx < ($count + 1) {
|
||||
result[idx] = *val;
|
||||
} else {
|
||||
if quotient[idx] != 0 {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some($barrett{k: k, progenitor: self.clone(), contents: result})
|
||||
}
|
||||
|
||||
fn fastmod(&self, mu: &$barrett) -> $type {
|
||||
// This algorithm is from our friends at the Handbook of
|
||||
// Applied Cryptography, Chapter 14, Algorithm 14.42.
|
||||
// Step #0:
|
||||
// Expand x so that it has the same size as the Barrett
|
||||
// value.
|
||||
let mut x = [0; $count + 1];
|
||||
for i in 0..$count {
|
||||
x[i] = self.contents[i];
|
||||
}
|
||||
// Step #1:
|
||||
// q1 <- floor(x / b^(k-1))
|
||||
let mut q1 = x.clone();
|
||||
generic_shr(&mut q1, &x, 64 * (mu.k - 1));
|
||||
// q2 <- q1 * mu
|
||||
let q2 = expanding_mul(&q1, &mu.contents);
|
||||
// q3 <- floor(q2 / b^(k+1))
|
||||
let mut q3big = q2.clone();
|
||||
generic_shr(&mut q3big, &q2, 64 * (mu.k + 1));
|
||||
let mut q3 = [0; $count + 1];
|
||||
for (idx, val) in q3big.iter().enumerate() {
|
||||
if idx <= $count {
|
||||
q3[idx] = *val;
|
||||
} else {
|
||||
assert_eq!(*val, 0);
|
||||
}
|
||||
}
|
||||
// Step #2:
|
||||
// r1 <- x mod b^(k+1)
|
||||
let mut r1 = x.clone();
|
||||
for i in mu.k..($count+1) {
|
||||
r1[i] = 0;
|
||||
}
|
||||
// r2 <- q3 * m mod b^(k+1)
|
||||
let mut moddedm = [0; $count + 1];
|
||||
for i in 0..mu.k {
|
||||
moddedm[i] = mu.progenitor.contents[i];
|
||||
}
|
||||
let mut r2 = q3.clone();
|
||||
generic_mul(&mut r2, &q3, &moddedm);
|
||||
// r <- r1 - r2
|
||||
let mut r = r1.clone();
|
||||
generic_sub(&mut r, &r2);
|
||||
let is_negative = !ge(&r1, &r2);
|
||||
// Step #3:
|
||||
// if r < 0 then r <- r + b^(k + 1)
|
||||
if is_negative {
|
||||
let mut bk1 = [0; $count + 1];
|
||||
bk1[mu.k] = 1;
|
||||
generic_add(&mut r, &bk1);
|
||||
}
|
||||
// Step #4:
|
||||
// while r >= m do: r <- r - m.
|
||||
while ge(&r, &moddedm) {
|
||||
generic_sub(&mut r, &moddedm);
|
||||
}
|
||||
// Step #5:
|
||||
// return r
|
||||
let mut retval = [0; $count];
|
||||
for i in 0..$count {
|
||||
retval[i] = r[i];
|
||||
}
|
||||
assert_eq!(r[$count], 0);
|
||||
$type{ contents: retval }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
macro_rules! generate_unsigned_conversions
|
||||
{
|
||||
($type: ident, $count: expr) => {
|
||||
generate_unsigned_primtype_conversions!($type, u8, $count);
|
||||
generate_unsigned_primtype_conversions!($type, u16, $count);
|
||||
generate_unsigned_primtype_conversions!($type, u32, $count);
|
||||
generate_unsigned_primtype_conversions!($type, u64, $count);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_signed_conversions
|
||||
{
|
||||
($type: ident, $base: ident) => {
|
||||
generate_signed_primtype_conversions!($type, $base, i8, u8);
|
||||
generate_signed_primtype_conversions!($type, $base, i16, u16);
|
||||
generate_signed_primtype_conversions!($type, $base, i32, u32);
|
||||
generate_signed_primtype_conversions!($type, $base, i64, u64);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_unsigned_primtype_conversions
|
||||
{
|
||||
($type: ident, $base: ty, $count: expr) => {
|
||||
generate_from!($type, $base, x, {
|
||||
let mut res = $type{ contents: [0; $count] };
|
||||
res.contents[0] = x as u64;
|
||||
res
|
||||
});
|
||||
generate_into!($type, $base, self, {
|
||||
self.contents[0] as $base
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_signed_primtype_conversions
|
||||
{
|
||||
($type: ident, $untype: ident, $base: ident, $unbase: ident) => {
|
||||
generate_from!($type, $unbase, x, {
|
||||
$type{ negative: false, value: $untype::from(x) }
|
||||
});
|
||||
generate_into!($type, $unbase, self, {
|
||||
self.value.contents[0] as $unbase
|
||||
});
|
||||
generate_from!($type, $base, x, {
|
||||
let neg = x < 0;
|
||||
$type{negative: neg, value: $untype::from(x.abs() as $unbase)}
|
||||
});
|
||||
generate_into!($type, $base, self, {
|
||||
if self.negative {
|
||||
let start = self.value.contents[0] as $unbase;
|
||||
let mask = ($unbase::max_value() - 1) >> 1;
|
||||
let res = (start & mask) as $base;
|
||||
-res
|
||||
} else {
|
||||
self.value.contents[0] as $base
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_from
|
||||
{
|
||||
($type: ident, $base: ty, $x: ident, $body: block) => {
|
||||
impl From<$base> for $type {
|
||||
fn from($x: $base) -> $type $body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_into
|
||||
{
|
||||
($type: ident, $base: ty, $self: ident, $body: block) => {
|
||||
impl Into<$base> for $type {
|
||||
fn into($self) -> $base $body
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,332 +0,0 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_cmp(a: &[u64], b: &[u64]) -> Ordering {
|
||||
let mut i = a.len() - 1;
|
||||
|
||||
assert!(a.len() == b.len());
|
||||
loop {
|
||||
match a[i].cmp(&b[i]) {
|
||||
Ordering::Equal if i == 0 =>
|
||||
return Ordering::Equal,
|
||||
Ordering::Equal =>
|
||||
i -= 1,
|
||||
res =>
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn le(a: &[u64], b: &[u64]) -> bool {
|
||||
generic_cmp(a, b) != Ordering::Greater
|
||||
}
|
||||
|
||||
pub fn ge(a: &[u64], b: &[u64]) -> bool {
|
||||
generic_cmp(a, b) != Ordering::Less
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_bitand(a: &mut [u64], b: &[u64]) {
|
||||
let mut i = 0;
|
||||
|
||||
assert!(a.len() == b.len());
|
||||
while i < a.len() {
|
||||
a[i] &= b[i];
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_bitor(a: &mut [u64], b: &[u64]) {
|
||||
let mut i = 0;
|
||||
|
||||
assert!(a.len() == b.len());
|
||||
while i < a.len() {
|
||||
a[i] |= b[i];
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_bitxor(a: &mut [u64], b: &[u64]) {
|
||||
let mut i = 0;
|
||||
|
||||
assert!(a.len() == b.len());
|
||||
while i < a.len() {
|
||||
a[i] ^= b[i];
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_not(a: &mut [u64]) {
|
||||
for x in a.iter_mut() {
|
||||
*x = !*x;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_shl(a: &mut [u64], orig: &[u64], amount: usize) {
|
||||
let digits = amount / 64;
|
||||
let bits = amount % 64;
|
||||
|
||||
assert!(a.len() == orig.len());
|
||||
for i in 0..a.len() {
|
||||
if i < digits {
|
||||
a[i] = 0;
|
||||
} else {
|
||||
let origidx = i - digits;
|
||||
let prev = if origidx == 0 { 0 } else { orig[origidx - 1] };
|
||||
let (carry,_) = if bits == 0 { (0, false) }
|
||||
else { prev.overflowing_shr(64 - bits as u32) };
|
||||
a[i] = (orig[origidx] << bits) | carry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_shr(a: &mut [u64], orig: &[u64], amount: usize) {
|
||||
let digits = amount / 64;
|
||||
let bits = amount % 64;
|
||||
|
||||
assert!(a.len() == orig.len());
|
||||
for i in 0..a.len() {
|
||||
let oldidx = i + digits;
|
||||
let caridx = i + digits + 1;
|
||||
let old = if oldidx >= a.len() { 0 } else { orig[oldidx] };
|
||||
let carry = if caridx >= a.len() { 0 } else { orig[caridx] };
|
||||
let cb = if bits == 0 { 0 } else { carry << (64 - bits) };
|
||||
a[i] = (old >> bits) | cb;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_add(a: &mut [u64], b: &[u64]) {
|
||||
let mut carry = 0;
|
||||
|
||||
assert!(a.len() == b.len());
|
||||
for i in 0..a.len() {
|
||||
let x = a[i] as u128;
|
||||
let y = b[i] as u128;
|
||||
let total = x + y + carry;
|
||||
a[i] = total as u64;
|
||||
carry = total >> 64;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_sub(a: &mut [u64], b: &[u64]) {
|
||||
let mut negated_rhs = b.to_vec();
|
||||
generic_not(&mut negated_rhs);
|
||||
let mut one = Vec::with_capacity(a.len());
|
||||
one.resize(a.len(), 0);
|
||||
one[0] = 1;
|
||||
generic_add(&mut negated_rhs, &one);
|
||||
generic_add(a, &negated_rhs);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_mul(a: &mut [u64], orig: &[u64], b: &[u64]) {
|
||||
assert!(a.len() == orig.len());
|
||||
assert!(a.len() == b.len());
|
||||
assert!(a == orig);
|
||||
|
||||
// Build the output table. This is a little bit awkward because we don't
|
||||
// know how big we're running, but hopefully the compiler is smart enough
|
||||
// to work all this out.
|
||||
let mut table = Vec::with_capacity(a.len());
|
||||
for _ in 0..a.len() {
|
||||
let mut row = Vec::with_capacity(a.len());
|
||||
row.resize(a.len(), 0);
|
||||
table.push(row);
|
||||
}
|
||||
// This uses "simple" grade school techniques to work things out. But,
|
||||
// for reference, consider two 4 digit numbers:
|
||||
//
|
||||
// l0c3 l0c2 l0c1 l0c0 [orig]
|
||||
// x l1c3 l1c2 l1c1 l1c0 [b]
|
||||
// ------------------------------------------------------------
|
||||
// (l0c3*l1c0) (l0c2*l1c0) (l0c1*l1c0) (l0c0*l1c0)
|
||||
// (l0c2*l1c1) (l0c1*l1c1) (l0c0*l1c1)
|
||||
// (l0c1*l1c2) (l0c0*l1c2)
|
||||
// (l0c0*l1c3)
|
||||
// ------------------------------------------------------------
|
||||
// AAAAA BBBBB CCCCC DDDDD
|
||||
for line in 0..a.len() {
|
||||
let maxcol = a.len() - line;
|
||||
for col in 0..maxcol {
|
||||
let left = orig[col] as u128;
|
||||
let right = b[line] as u128;
|
||||
table[line][col + line] = left * right;
|
||||
}
|
||||
}
|
||||
// ripple the carry across each line, ensuring that each entry in the
|
||||
// table is 64-bits
|
||||
for line in 0..a.len() {
|
||||
let mut carry = 0;
|
||||
for col in 0..a.len() {
|
||||
table[line][col] = table[line][col] + carry;
|
||||
carry = table[line][col] >> 64;
|
||||
table[line][col] &= 0xFFFFFFFFFFFFFFFF;
|
||||
}
|
||||
}
|
||||
// now do the final addition across the lines, rippling the carry as
|
||||
// normal
|
||||
let mut carry = 0;
|
||||
for col in 0..a.len() {
|
||||
let mut total = carry;
|
||||
for line in 0..a.len() {
|
||||
total += table[line][col];
|
||||
}
|
||||
a[col] = total as u64;
|
||||
carry = total >> 64;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn expanding_mul(a: &[u64], b: &[u64]) -> Vec<u64> {
|
||||
assert!(a.len() == b.len());
|
||||
// The maximum size of an n x n digit multiplication is 2n digits, so
|
||||
// here's our output array.
|
||||
let mut result = Vec::with_capacity(a.len() * 2);
|
||||
result.resize(a.len() * 2, 0);
|
||||
|
||||
for (base_idx, digit) in b.iter().enumerate() {
|
||||
let mut myrow = Vec::with_capacity(a.len() * 2);
|
||||
let mut carry = 0;
|
||||
|
||||
myrow.resize(a.len() * 2, 0);
|
||||
for (col_idx, digit2) in a.iter().enumerate() {
|
||||
let left = *digit2 as u128;
|
||||
let right = *digit as u128;
|
||||
let combo = (left * right) + carry;
|
||||
|
||||
myrow[base_idx + col_idx] = combo as u64;
|
||||
carry = combo >> 64;
|
||||
}
|
||||
generic_add(&mut result, &myrow);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_div(inx: &[u64], iny: &[u64],
|
||||
outq: &mut [u64], outr: &mut [u64])
|
||||
{
|
||||
assert!(inx.len() == inx.len());
|
||||
assert!(inx.len() == iny.len());
|
||||
assert!(inx.len() == outq.len());
|
||||
assert!(inx.len() == outr.len());
|
||||
// This algorithm is from the Handbook of Applied Cryptography, Chapter 14,
|
||||
// algorithm 14.20. It has a couple assumptions about the inputs, namely that
|
||||
// n >= t >= 1 and y[t] != 0, where n and t refer to the number of digits in
|
||||
// the numbers. Which means that if we used the inputs unmodified, we can't
|
||||
// divide by single-digit numbers.
|
||||
//
|
||||
// To deal with this, we multiply inx and iny by 2^64, so that we push out
|
||||
// t by one.
|
||||
//
|
||||
// In addition, this algorithm starts to go badly when y[t] is very small
|
||||
// and x[n] is very large. Really, really badly. This can be fixed by
|
||||
// insuring that the top bit is set in y[t], which we can achieve by
|
||||
// shifting everyone over a maxiumum of 63 bits.
|
||||
//
|
||||
// What this means is, just for safety, we add a 0 at the beginning and
|
||||
// end of each number.
|
||||
let mut y = iny.to_vec();
|
||||
let mut x = inx.to_vec();
|
||||
y.insert(0,0); y.push(0);
|
||||
x.insert(0,0); x.push(0);
|
||||
// 0. Compute 'n' and 't'
|
||||
let n = x.len() - 1;
|
||||
let mut t = y.len() - 1;
|
||||
while (t > 0) && (y[t] == 0) { t -= 1 }
|
||||
assert!(y[t] != 0); // this is where division by zero will fire
|
||||
// 0.5. Figure out a shift we can do such that the high bit of y[t] is
|
||||
// set, and then shift x and y left by that much.
|
||||
let additional_shift: usize = y[t].leading_zeros() as usize;
|
||||
let origx = x.clone();
|
||||
let origy = y.clone();
|
||||
generic_shl(&mut x, &origx, additional_shift);
|
||||
generic_shl(&mut y, &origy, additional_shift);
|
||||
// 1. For j from 0 to (n - 1) do: q_j <- 0
|
||||
let mut q = Vec::with_capacity(y.len());
|
||||
q.resize(y.len(), 0);
|
||||
for qj in q.iter_mut() { *qj = 0 }
|
||||
// 2. While (x >= yb^(n-t)) do the following:
|
||||
// q_(n-t) <- q_(n-t) + 1
|
||||
// x <- x - yb^(n-t)
|
||||
let mut ybnt = y.clone();
|
||||
generic_shl(&mut ybnt, &y, 64 * (n - t));
|
||||
while ge(&x, &ybnt) {
|
||||
q[n-t] = q[n-t] + 1;
|
||||
generic_sub(&mut x, &ybnt);
|
||||
}
|
||||
// 3. For i from n down to (t + 1) do the following:
|
||||
let mut i = n;
|
||||
while i >= (t + 1) {
|
||||
// 3.1. if x_i = y_t, then set q_(i-t-1) <- b - 1; otherwise set
|
||||
// q_(i-t-1) <- floor((x_i * b + x_(i-1)) / y_t).
|
||||
if x[i] == y[t] {
|
||||
q[i-t-1] = 0xFFFFFFFFFFFFFFFF;
|
||||
} else {
|
||||
let top = ((x[i] as u128) << 64) + (x[i-1] as u128);
|
||||
let bot = y[t] as u128;
|
||||
let solution = top / bot;
|
||||
q[i-t-1] = solution as u64;
|
||||
}
|
||||
// 3.2. While (q_(i-t-1)(y_t * b + y_(t-1)) > x_i(b2) + x_(i-1)b +
|
||||
// x_(i-2)) do:
|
||||
// q_(i - t - 1) <- q_(i - t 1) - 1.
|
||||
loop {
|
||||
let mut left = Vec::with_capacity(x.len());
|
||||
left.resize(x.len(), 0);
|
||||
left[0] = q[i - t - 1];
|
||||
let mut leftright = Vec::with_capacity(x.len());
|
||||
leftright.resize(x.len(), 0);
|
||||
leftright[0] = y[t-1];
|
||||
|
||||
let copy = left.clone();
|
||||
generic_mul(&mut left, ©, &leftright);
|
||||
let mut right = Vec::with_capacity(x.len());
|
||||
right.resize(x.len(), 0);
|
||||
right[0] = x[i-2];
|
||||
right[1] = x[i-1];
|
||||
right[2] = x[i];
|
||||
|
||||
if le(&left, &right) {
|
||||
break
|
||||
}
|
||||
|
||||
q[i - t - 1] -= 1;
|
||||
}
|
||||
// 3.3. x <- x - q_(i - t - 1) * y * b^(i-t-1)
|
||||
let mut right = Vec::with_capacity(y.len());
|
||||
right.resize(y.len(), 0);
|
||||
right[i - t - 1] = q[i - t - 1];
|
||||
let rightclone = right.clone();
|
||||
generic_mul(&mut right, &rightclone, &y);
|
||||
let wentnegative = generic_cmp(&x, &right) == Ordering::Less;
|
||||
generic_sub(&mut x, &right);
|
||||
// 3.4. if x < 0 then set x <- x + yb^(i-t-1) and
|
||||
// q_(i-t-1) <- q_(i-t-1) - 1
|
||||
if wentnegative {
|
||||
let mut ybit1 = y.to_vec();
|
||||
generic_shl(&mut ybit1, &y, 64 * (i - t - 1));
|
||||
generic_add(&mut x, &ybit1);
|
||||
q[i - t - 1] -= 1;
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
// 4. r <- x
|
||||
let finalx = x.clone();
|
||||
generic_shr(&mut x, &finalx, additional_shift);
|
||||
for i in 0..outr.len() {
|
||||
outr[i] = x[i + 1]; // note that for the remainder, we're dividing by
|
||||
// our normalization value.
|
||||
}
|
||||
// 5. return (q,r)
|
||||
for i in 0..outq.len() {
|
||||
outq[i] = q[i];
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
//! # Simple-Crypto CryptoNum
|
||||
//!
|
||||
//! This module is designed to provide large, fixed-width number support for
|
||||
//! the rest of the Simple-Crypto libraries. Feel free to use it other places,
|
||||
//! of course, but that's its origin.
|
||||
//!
|
||||
//! 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.
|
||||
//!
|
||||
#[macro_use]
|
||||
mod arithmetic_traits;
|
||||
#[macro_use]
|
||||
mod barrett;
|
||||
#[macro_use]
|
||||
mod conversions;
|
||||
mod core;
|
||||
#[macro_use]
|
||||
mod modops;
|
||||
#[macro_use]
|
||||
mod primes;
|
||||
#[macro_use]
|
||||
mod signed;
|
||||
#[macro_use]
|
||||
mod unsigned;
|
||||
mod traits;
|
||||
|
||||
use cryptonum::core::*;
|
||||
use num::{BigUint,BigInt};
|
||||
use rand::Rng;
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{Debug,Error,Formatter};
|
||||
use std::ops::*;
|
||||
pub use self::traits::*;
|
||||
use self::primes::SMALL_PRIMES;
|
||||
|
||||
construct_unsigned!(U512, BarretMu512, u512, 8);
|
||||
construct_unsigned!(U1024, BarretMu1024, u1024, 16);
|
||||
construct_unsigned!(U2048, BarretMu2048, u2048, 32);
|
||||
construct_unsigned!(U3072, BarretMu3072, u3072, 48);
|
||||
construct_unsigned!(U4096, BarretMu4096, u4096, 64);
|
||||
construct_unsigned!(U7680, BarretMu7680, u7680, 120);
|
||||
construct_unsigned!(U8192, BarretMu8192, u8192, 128);
|
||||
construct_unsigned!(U15360, BarretMu15360, u15360, 240);
|
||||
|
||||
construct_signed!(I512, U512, i512);
|
||||
construct_signed!(I1024, U1024, i1024);
|
||||
construct_signed!(I2048, U2048, i2048);
|
||||
construct_signed!(I3072, U3072, i3072);
|
||||
construct_signed!(I4096, U4096, i4096);
|
||||
construct_signed!(I7680, U7680, i7680);
|
||||
construct_signed!(I8192, U8192, i8192);
|
||||
construct_signed!(I15360, U15360, i15360);
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
macro_rules! derive_modulo_operations
|
||||
{
|
||||
($type: ident) => {
|
||||
impl CryptoNumModOps for $type {
|
||||
fn modinv(&self, _b: &Self) -> Self {
|
||||
panic!("modinv");
|
||||
}
|
||||
fn modexp(&self, _a: &Self, _b: &Self) -> Self {
|
||||
panic!("modexp");
|
||||
}
|
||||
fn modsq(&self, _v: &Self) -> Self {
|
||||
panic!("modsq");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
pub 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];
|
||||
|
||||
macro_rules! derive_prime_operations
|
||||
{
|
||||
($type: ident, $count: expr) => {
|
||||
impl $type {
|
||||
fn miller_rabin<G: Rng>(&self, g: &mut G, iters: usize)
|
||||
-> bool
|
||||
{
|
||||
let nm1 = self - $type::from(1 as u8);
|
||||
// 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 < ($count * 64));
|
||||
}
|
||||
// WitnessLoop: repeat k times
|
||||
'WitnessLoop: for _k in 0..iters {
|
||||
// pick a random integer a in the range [2, n - 2]
|
||||
let a = $type::random_in_range(g, &$type::from(2 as u8), &nm1);
|
||||
// x <- a^d mod n
|
||||
let mut x = a.modexp(&d, &self);
|
||||
// if x = 1 or x = n - 1 then
|
||||
if (&x == &$type::from(1 as u8)) || (&x == &nm1) {
|
||||
// continue WitnessLoop
|
||||
continue 'WitnessLoop;
|
||||
}
|
||||
// repeat r - 1 times:
|
||||
for _i in 0..r {
|
||||
// x <- x^2 mod n
|
||||
x = x.modexp(&$type::from(2 as u8), &self);
|
||||
// if x = 1 then
|
||||
if &x == &$type::from(1 as u8) {
|
||||
// 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, min: &$type, max: &$type)
|
||||
-> $type
|
||||
{
|
||||
loop {
|
||||
let candidate = $type::random_number(rng);
|
||||
if (&candidate >= min) && (&candidate < max) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn random_number<G: Rng>(rng: &mut G) -> $type {
|
||||
let mut components = [0; $count];
|
||||
for i in 0..$count {
|
||||
components[i] = rng.gen();
|
||||
}
|
||||
$type{ contents: components }
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoNumPrimes for $type {
|
||||
fn probably_prime<G: Rng>(&self, g: &mut G, iters: usize) -> bool {
|
||||
for tester in SMALL_PRIMES.iter() {
|
||||
let testvalue = $type::from(*tester);
|
||||
if (self % testvalue).is_zero() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.miller_rabin(g, iters)
|
||||
}
|
||||
fn generate_prime<G: Rng>(_g: &mut G, _iters: usize, _e: &Self, _min: &Self) -> Self {
|
||||
panic!("generate_prime");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
macro_rules! construct_signed {
|
||||
($type: ident, $base: ident, $modname: ident) => {
|
||||
#[derive(Clone,PartialEq,Eq)]
|
||||
pub struct $type {
|
||||
negative: bool,
|
||||
value: $base
|
||||
}
|
||||
|
||||
impl Debug for $type {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(),Error> {
|
||||
if self.negative {
|
||||
f.write_str("-")?;
|
||||
} else {
|
||||
f.write_str("+")?;
|
||||
}
|
||||
self.value.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<&'a $type> for $type {
|
||||
fn eq(&self, other: &&$type) -> bool {
|
||||
(self.negative == other.negative) &&
|
||||
(self.value == other.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for $type {
|
||||
fn partial_cmp(&self, other: &$type) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for $type {
|
||||
fn cmp(&self, other: &$type) -> Ordering {
|
||||
match (self.negative, other.negative) {
|
||||
(true, true) =>
|
||||
self.value.cmp(&other.value).reverse(),
|
||||
(true, false) => Ordering::Greater,
|
||||
(false, true) => Ordering::Less,
|
||||
(false, false) =>
|
||||
self.value.cmp(&other.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoNumBase for $type {
|
||||
fn zero() -> $type {
|
||||
$type{ negative: false, value: $base::zero() }
|
||||
}
|
||||
fn max_value() -> $type {
|
||||
$type{ negative: false, value: $base::max_value() }
|
||||
}
|
||||
fn is_zero(&self) -> bool {
|
||||
self.value.is_zero()
|
||||
}
|
||||
fn is_odd(&self) -> bool {
|
||||
self.value.is_odd()
|
||||
}
|
||||
fn is_even(&self) -> bool {
|
||||
self.value.is_even()
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoNumFastMod for $type {
|
||||
type BarrettMu = <$base as CryptoNumFastMod>::BarrettMu;
|
||||
|
||||
fn barrett_mu(&self) -> Option<Self::BarrettMu> {
|
||||
if self.negative {
|
||||
None
|
||||
} else {
|
||||
self.value.barrett_mu()
|
||||
}
|
||||
}
|
||||
|
||||
fn fastmod(&self, mu: &Self::BarrettMu) -> $type {
|
||||
let res = self.value.fastmod(mu);
|
||||
$type{ negative: self.negative, value: res }
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoNumSigned for $type {
|
||||
type Unsigned = $base;
|
||||
|
||||
fn new(v: $base) -> $type {
|
||||
$type{ negative: false, value: v.clone() }
|
||||
}
|
||||
fn abs(&self) -> $base {
|
||||
self.value.clone()
|
||||
}
|
||||
fn is_positive(&self) -> bool {
|
||||
!self.negative
|
||||
}
|
||||
fn is_negative(&self) -> bool {
|
||||
self.negative
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for $type {
|
||||
type Output = $type;
|
||||
|
||||
fn neg(self) -> $type {
|
||||
(&self).neg()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Neg for &'a $type {
|
||||
type Output = $type;
|
||||
|
||||
fn neg(self) -> $type {
|
||||
if self.value.is_zero() {
|
||||
$type{ negative: false, value: self.value.clone() }
|
||||
} else {
|
||||
$type{ negative: !self.negative, value: self.value.clone() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_arithmetic!($type,AddAssign,add_assign,Add,add,self,other,{
|
||||
let signs_match = self.negative == other.negative;
|
||||
let ordering = self.value.cmp(&other.value);
|
||||
|
||||
match (signs_match, ordering) {
|
||||
(true, _) =>
|
||||
// if the signs are the same, we maintain the sign and
|
||||
// just increase the magnitude
|
||||
self.value.add_assign(&other.value),
|
||||
(false, Ordering::Equal) => {
|
||||
// if the signs are different and the numbers are equal,
|
||||
// we just set this to zero. However, we actually do the
|
||||
// subtraction to make the timing roughly similar.
|
||||
self.negative = false;
|
||||
self.value.sub_assign(&other.value)
|
||||
}
|
||||
(false, Ordering::Less) => {
|
||||
// if the signs are different and the first one is less
|
||||
// than the second, then we flip the sign and subtract.
|
||||
self.negative = !self.negative;
|
||||
let mut other_copy = other.value.clone();
|
||||
other_copy.sub_assign(&self.value);
|
||||
self.value = other_copy;
|
||||
}
|
||||
(false, Ordering::Greater) => {
|
||||
// if the signs are different and the first one is
|
||||
// greater than the second, then we leave the sign and
|
||||
// subtract.
|
||||
self.value.sub_assign(&other.value)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
define_arithmetic!($type,SubAssign,sub_assign,Sub,sub,self,other,{
|
||||
// this is a bit inefficient, but a heck of a lot easier.
|
||||
let mut other2 = other.clone();
|
||||
other2.negative = !other2.negative;
|
||||
self.add_assign(&other2)
|
||||
});
|
||||
|
||||
define_arithmetic!($type,MulAssign,mul_assign,Mul,mul,self,other,{
|
||||
self.negative = self.negative ^ other.negative;
|
||||
self.value.mul_assign(&other.value);
|
||||
});
|
||||
|
||||
define_arithmetic!($type,DivAssign,div_assign,Div,div,self,other,{
|
||||
self.negative = self.negative ^ other.negative;
|
||||
self.value.div_assign(&other.value);
|
||||
});
|
||||
|
||||
define_arithmetic!($type,RemAssign,rem_assign,Rem,rem,self,other,{
|
||||
self.value.rem_assign(&other.value);
|
||||
});
|
||||
|
||||
generate_signed_conversions!($type, $base);
|
||||
|
||||
#[cfg(test)]
|
||||
mod $modname {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use super::*;
|
||||
|
||||
impl Arbitrary for $type {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> $type {
|
||||
let value = $base::arbitrary(g);
|
||||
if value.is_zero() {
|
||||
$type{ negative: false, value: value }
|
||||
} else {
|
||||
$type{ negative: g.gen_weighted_bool(2), value: value }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn double_negation(x: $type) -> bool {
|
||||
(- (- &x)) == &x
|
||||
}
|
||||
fn add_identity(x: $type) -> bool {
|
||||
(&x + $type::zero()) == &x
|
||||
}
|
||||
fn add_commutivity(x: $type, y: $type) -> bool {
|
||||
(&x + &y) == (&y + &x)
|
||||
}
|
||||
fn add_associativity(a: $type, b: $type, c: $type) -> bool {
|
||||
// we shift these to get away from rollover
|
||||
let x = $type{ negative: a.negative, value: a.value >> 2 };
|
||||
let y = $type{ negative: b.negative, value: b.value >> 2 };
|
||||
let z = $type{ negative: c.negative, value: c.value >> 2 };
|
||||
(&x + (&y + &z)) == ((&x + &y) + &z)
|
||||
}
|
||||
fn sub_is_add_negation(x: $type, y: $type) -> bool {
|
||||
(&x - &y) == (&x + (- &y))
|
||||
}
|
||||
fn sub_destroys(x: $type) -> bool {
|
||||
(&x - &x) == $type::zero()
|
||||
}
|
||||
fn mul_identity(x: $type) -> bool {
|
||||
(&x * $type::from(1)) == &x
|
||||
}
|
||||
fn mul_commutivity(x: $type, y: $type) -> bool {
|
||||
(&x * &y) == (&y * &x)
|
||||
}
|
||||
fn mul_associativity(a: $type, b: $type, c: $type) -> bool {
|
||||
// we shift these to get away from rollover
|
||||
let s = (a.value.bit_size() / 2) - 2;
|
||||
let x = $type{ negative: a.negative, value: a.value >> s };
|
||||
let y = $type{ negative: b.negative, value: b.value >> s };
|
||||
let z = $type{ negative: c.negative, value: c.value >> s };
|
||||
(&x * (&y * &z)) == ((&x * &y) * &z)
|
||||
}
|
||||
#[ignore]
|
||||
fn div_identity(a: $type) -> bool {
|
||||
&a / $type::from(1) == a
|
||||
}
|
||||
fn div_self_is_one(a: $type) -> bool {
|
||||
(&a / &a) == $type::from(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
use rand::Rng;
|
||||
|
||||
pub trait CryptoNumBase {
|
||||
/// Generate the zero value for this type.
|
||||
fn zero() -> Self;
|
||||
/// Generate the maximum possible value for this type.
|
||||
fn max_value() -> Self;
|
||||
/// Test if the number is zero.
|
||||
fn is_zero(&self) -> bool;
|
||||
/// Test if the number is odd (a.k.a., the low bit is set)
|
||||
fn is_odd(&self) -> bool;
|
||||
/// Test if the number is even (a.k.a., the low bit is clear)
|
||||
fn is_even(&self) -> bool;
|
||||
}
|
||||
|
||||
pub trait CryptoNumSerialization {
|
||||
/// The number of bits used when this number is serialized.
|
||||
fn bit_size(&self) -> usize;
|
||||
/// The number of bytes used when this number is serialized.
|
||||
fn byte_size(&self) -> usize;
|
||||
/// Convert a number to a series of bytes, in standard order (most to
|
||||
/// least significant)
|
||||
fn to_bytes(&self) -> Vec<u8>;
|
||||
/// Convert a series of bytes into the number. The size of the given slice
|
||||
/// must be greater than or equal to the size of the number, and must be
|
||||
/// a multiple of 8 bytes long. Unused bytes should be ignored.
|
||||
fn from_bytes(&[u8]) -> Self;
|
||||
}
|
||||
|
||||
pub trait CryptoNumFastMod {
|
||||
/// A related type that can hold the constant required for Barrett
|
||||
/// reduction.
|
||||
type BarrettMu;
|
||||
|
||||
/// Compute the Barett constant mu, using this as a modulus, which we can
|
||||
/// use later to perform faster mod operations.
|
||||
fn barrett_mu(&self) -> Option<Self::BarrettMu>;
|
||||
/// Faster modulo through the use of the Barrett constant, above.
|
||||
fn fastmod(&self, &Self::BarrettMu) -> Self;
|
||||
}
|
||||
|
||||
pub trait CryptoNumSigned {
|
||||
/// The unsigned type that this type is related to.
|
||||
type Unsigned;
|
||||
|
||||
/// Generate a new signed number based on the given unsigned number.
|
||||
fn new(x: Self::Unsigned) -> Self;
|
||||
/// Get the absolute value of the signed number, turning it back into an
|
||||
/// unsigned number.
|
||||
fn abs(&self) -> Self::Unsigned;
|
||||
/// Test if the number is negative.
|
||||
fn is_negative(&self) -> bool;
|
||||
/// Test if the number is positive.
|
||||
fn is_positive(&self) -> bool;
|
||||
}
|
||||
|
||||
pub trait CryptoNumModOps: Sized
|
||||
{
|
||||
/// Compute the modular inverse of the number.
|
||||
fn modinv(&self, b: &Self) -> Self;
|
||||
/// Raise the number to the power of the first value, mod the second.
|
||||
fn modexp(&self, a: &Self, b: &Self) -> Self;
|
||||
/// Square the number, mod the given value.
|
||||
fn modsq(&self, v: &Self) -> Self;
|
||||
}
|
||||
|
||||
pub trait CryptoNumPrimes
|
||||
{
|
||||
/// Determine if the given number is probably prime using a quick spot
|
||||
/// check and Miller-Rabin, using the given random number generator
|
||||
/// and number of iterations.
|
||||
fn probably_prime<G: Rng>(&self, g: &mut G, iters: usize) -> bool;
|
||||
/// Generate a prime using the given random number generator, using
|
||||
/// the given number of rounds to determine if the number is probably
|
||||
/// prime. The other two numbers are a number for which the generator
|
||||
/// should have a GCD of 1, and the minimum value for the number.
|
||||
fn generate_prime<G: Rng>(g: &mut G, iters: usize, e: &Self, min: &Self)
|
||||
-> Self;
|
||||
}
|
||||
@@ -1,685 +0,0 @@
|
||||
macro_rules! construct_unsigned {
|
||||
($type: ident, $barrett: ident, $modname: ident, $count: expr) => {
|
||||
#[derive(Clone)]
|
||||
pub struct $type {
|
||||
contents: [u64; $count]
|
||||
}
|
||||
|
||||
pub struct $barrett {
|
||||
k: usize,
|
||||
progenitor: $type,
|
||||
contents: [u64; $count + 1]
|
||||
}
|
||||
|
||||
impl PartialEq for $type {
|
||||
fn eq(&self, other: &$type) -> bool {
|
||||
for i in 0..$count {
|
||||
if self.contents[i] != other.contents[i] {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for $type {}
|
||||
|
||||
impl Debug for $type {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(),Error> {
|
||||
f.write_str("CryptoNum{{ ")?;
|
||||
f.debug_list().entries(self.contents.iter()).finish()?;
|
||||
f.write_str(" }}")
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for $barrett {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(),Error> {
|
||||
f.write_str("BarrettMu{{ ")?;
|
||||
f.write_fmt(format_args!("k = {}, ", self.k))?;
|
||||
f.write_fmt(format_args!("progen = {:?}, ",self.progenitor))?;
|
||||
f.write_str("contents: ")?;
|
||||
f.debug_list().entries(self.contents.iter()).finish()?;
|
||||
f.write_str(" }}")
|
||||
}
|
||||
}
|
||||
|
||||
generate_unsigned_conversions!($type, $count);
|
||||
|
||||
impl PartialOrd for $type {
|
||||
fn partial_cmp(&self, other: &$type) -> Option<Ordering> {
|
||||
Some(generic_cmp(&self.contents, &other.contents))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for $type {
|
||||
fn cmp(&self, other: &$type) -> Ordering {
|
||||
generic_cmp(&self.contents, &other.contents)
|
||||
}
|
||||
}
|
||||
|
||||
impl Not for $type {
|
||||
type Output = $type;
|
||||
|
||||
fn not(self) -> $type {
|
||||
let mut output = self.clone();
|
||||
generic_not(&mut output.contents);
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Not for &'a $type {
|
||||
type Output = $type;
|
||||
|
||||
fn not(self) -> $type {
|
||||
let mut output = self.clone();
|
||||
generic_not(&mut output.contents);
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
define_arithmetic!($type,BitOrAssign,bitor_assign,BitOr,bitor,self,other,{
|
||||
generic_bitor(&mut self.contents, &other.contents);
|
||||
});
|
||||
define_arithmetic!($type,BitAndAssign,bitand_assign,BitAnd,bitand,self,other,{
|
||||
generic_bitand(&mut self.contents, &other.contents);
|
||||
});
|
||||
define_arithmetic!($type,BitXorAssign,bitxor_assign,BitXor,bitxor,self,other,{
|
||||
generic_bitxor(&mut self.contents, &other.contents);
|
||||
});
|
||||
define_arithmetic!($type,AddAssign,add_assign,Add,add,self,other,{
|
||||
generic_add(&mut self.contents, &other.contents);
|
||||
});
|
||||
define_arithmetic!($type,SubAssign,sub_assign,Sub,sub,self,other,{
|
||||
generic_sub(&mut self.contents, &other.contents);
|
||||
});
|
||||
define_arithmetic!($type,MulAssign,mul_assign,Mul,mul,self,other,{
|
||||
let copy = self.contents.clone();
|
||||
generic_mul(&mut self.contents, ©, &other.contents);
|
||||
});
|
||||
define_arithmetic!($type,DivAssign,div_assign,Div,div,self,other,{
|
||||
let mut dead = [0; $count];
|
||||
let copy = self.contents.clone();
|
||||
generic_div(©, &other.contents,
|
||||
&mut self.contents, &mut dead);
|
||||
});
|
||||
define_arithmetic!($type,RemAssign,rem_assign,Rem,rem,self,other,{
|
||||
let mut dead = [0; $count];
|
||||
let copy = self.contents.clone();
|
||||
generic_div(©, &other.contents,
|
||||
&mut dead, &mut self.contents);
|
||||
});
|
||||
|
||||
shifts!($type, usize);
|
||||
shifts!($type, u64);
|
||||
shifts!($type, i64);
|
||||
shifts!($type, u32);
|
||||
shifts!($type, i32);
|
||||
shifts!($type, u16);
|
||||
shifts!($type, i16);
|
||||
shifts!($type, u8);
|
||||
shifts!($type, i8);
|
||||
|
||||
impl CryptoNumBase for $type {
|
||||
fn zero() -> $type {
|
||||
$type { contents: [0; $count] }
|
||||
}
|
||||
|
||||
fn max_value() -> $type {
|
||||
$type { contents: [0xFFFFFFFFFFFFFFFF; $count] }
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
for x in self.contents.iter() {
|
||||
if *x != 0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn is_odd(&self) -> bool {
|
||||
(self.contents[0] & 1) == 1
|
||||
}
|
||||
|
||||
fn is_even(&self) -> bool {
|
||||
(self.contents[0] & 1) == 0
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoNumSerialization for $type {
|
||||
fn bit_size(&self) -> usize {
|
||||
$count * 64
|
||||
}
|
||||
|
||||
fn byte_size(&self) -> usize {
|
||||
$count * 8
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut res = Vec::with_capacity($count * 8);
|
||||
for x in self.contents.iter() {
|
||||
res.push( (x >> 56) as u8 );
|
||||
res.push( (x >> 48) as u8 );
|
||||
res.push( (x >> 40) as u8 );
|
||||
res.push( (x >> 32) as u8 );
|
||||
res.push( (x >> 24) as u8 );
|
||||
res.push( (x >> 16) as u8 );
|
||||
res.push( (x >> 8) as u8 );
|
||||
res.push( (x >> 0) as u8 );
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn from_bytes(x: &[u8]) -> $type {
|
||||
let mut res = $type::zero();
|
||||
let mut i = 0;
|
||||
|
||||
assert!(x.len() >= ($count * 8));
|
||||
for chunk in x.chunks(8) {
|
||||
assert!(chunk.len() == 8);
|
||||
res.contents[i] = ((chunk[0] as u64) << 56) |
|
||||
((chunk[1] as u64) << 48) |
|
||||
((chunk[2] as u64) << 40) |
|
||||
((chunk[3] as u64) << 32) |
|
||||
((chunk[4] as u64) << 24) |
|
||||
((chunk[5] as u64) << 16) |
|
||||
((chunk[6] as u64) << 8) |
|
||||
((chunk[7] as u64) << 0);
|
||||
i += 1;
|
||||
}
|
||||
assert!(i == $count);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
derive_barrett!($type, $barrett, $count);
|
||||
derive_modulo_operations!($type);
|
||||
derive_prime_operations!($type, $count);
|
||||
|
||||
impl Into<BigInt> for $type {
|
||||
fn into(self) -> BigInt {
|
||||
panic!("into bigint")
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<BigUint> for $type {
|
||||
fn into(self) -> BigUint {
|
||||
panic!("into big uint")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BigInt> for $type {
|
||||
fn from(_x: BigInt) -> Self {
|
||||
panic!("from bigint")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BigUint> for $type {
|
||||
fn from(_x: BigUint) -> Self {
|
||||
panic!("from biguint")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod $modname {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use super::*;
|
||||
|
||||
impl Arbitrary for $type {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> $type {
|
||||
let mut res = [0; $count];
|
||||
|
||||
for i in 0..$count {
|
||||
res[i] = g.next_u64();
|
||||
}
|
||||
$type{ contents: res }
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_builders() {
|
||||
let mut buffer = [0; $count];
|
||||
assert_eq!($type{ contents: buffer }, $type::from(0 as u8));
|
||||
buffer[0] = 0x7F;
|
||||
assert_eq!($type{ contents: buffer }, $type::from(0x7F as u8));
|
||||
buffer[0] = 0x7F7F;
|
||||
assert_eq!($type{ contents: buffer }, $type::from(0x7F7F as u16));
|
||||
buffer[0] = 0xCA5CADE5;
|
||||
assert_eq!($type{ contents: buffer },
|
||||
$type::from(0xCA5CADE5 as u32));
|
||||
assert_eq!($type{ contents: buffer },
|
||||
$type::from(0xCA5CADE5 as u32));
|
||||
buffer[0] = 0xFFFFFFFFFFFFFFFF;
|
||||
assert_eq!($type{ contents: buffer },
|
||||
$type::from(0xFFFFFFFFFFFFFFFF as u64));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max() {
|
||||
let max64: u64 = $type::from(u64::max_value()).into();
|
||||
assert_eq!(max64, u64::max_value());
|
||||
let max64v: u64 = $type::max_value().into();
|
||||
assert_eq!(max64v, u64::max_value());
|
||||
assert_eq!($type::max_value() + $type::from(1 as u8), $type::zero());
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn builder_u8_upgrade_u16(x: u8) -> bool {
|
||||
$type::from(x) == $type::from(x as u16)
|
||||
}
|
||||
fn builder_u16_upgrade_u32(x: u16) -> bool {
|
||||
$type::from(x) == $type::from(x as u32)
|
||||
}
|
||||
fn builder_u32_upgrade_u64(x: u32) -> bool {
|
||||
$type::from(x) == $type::from(x as u64)
|
||||
}
|
||||
fn builder_u8_roundtrips(x: u8) -> bool {
|
||||
let thereback: u8 = $type::from(x).into();
|
||||
x == thereback
|
||||
}
|
||||
fn builder_u16_roundtrips(x: u16) -> bool {
|
||||
let thereback: u16 = $type::from(x).into();
|
||||
x == thereback
|
||||
}
|
||||
fn builder_u32_roundtrips(x: u32) -> bool {
|
||||
let thereback: u32 = $type::from(x).into();
|
||||
x == thereback
|
||||
}
|
||||
fn builder_u64_roundtrips(x: u64) -> bool {
|
||||
let thereback: u64 = $type::from(x).into();
|
||||
x == thereback
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn partial_ord64_works(x: u64, y: u64) -> bool {
|
||||
let xbig = $type::from(x);
|
||||
let ybig = $type::from(y);
|
||||
xbig.partial_cmp(&ybig) == x.partial_cmp(&y)
|
||||
}
|
||||
fn ord64_works(x: u64, y: u64) -> bool {
|
||||
let xbig = $type::from(x);
|
||||
let ybig = $type::from(y);
|
||||
xbig.cmp(&ybig) == x.cmp(&y)
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn and_annulment(x: $type) -> bool {
|
||||
(x & $type::zero()) == $type::zero()
|
||||
}
|
||||
fn or_annulment(x: $type) -> bool {
|
||||
(x | $type::max_value()) == $type::max_value()
|
||||
}
|
||||
fn and_identity(x: $type) -> bool {
|
||||
(&x & $type::max_value()) == x
|
||||
}
|
||||
fn or_identity(x: $type) -> bool {
|
||||
(&x | $type::zero()) == x
|
||||
}
|
||||
fn and_idempotent(x: $type) -> bool {
|
||||
(&x & &x) == x
|
||||
}
|
||||
fn or_idempotent(x: $type) -> bool {
|
||||
(&x | &x) == x
|
||||
}
|
||||
fn and_complement(x: $type) -> bool {
|
||||
(&x & &x) == x
|
||||
}
|
||||
fn or_complement(x: $type) -> bool {
|
||||
(&x | !&x) == $type::max_value()
|
||||
}
|
||||
fn and_commutative(x: $type, y: $type) -> bool {
|
||||
(&x & &y) == (&y & &x)
|
||||
}
|
||||
fn or_commutative(x: $type, y: $type) -> bool {
|
||||
(&x | &y) == (&y | &x)
|
||||
}
|
||||
fn double_negation(x: $type) -> bool {
|
||||
!!&x == x
|
||||
}
|
||||
fn or_distributive(a: $type, b: $type, c: $type) -> bool {
|
||||
(&a & (&b | &c)) == ((&a & &b) | (&a & &c))
|
||||
}
|
||||
fn and_distributive(a: $type, b: $type, c: $type) -> bool {
|
||||
(&a | (&b & &c)) == ((&a | &b) & (&a | &c))
|
||||
}
|
||||
fn or_absorption(a: $type, b: $type) -> bool {
|
||||
(&a | (&a & &b)) == a
|
||||
}
|
||||
fn and_absorption(a: $type, b: $type) -> bool {
|
||||
(&a & (&a | &b)) == a
|
||||
}
|
||||
fn or_associative(a: $type, b: $type, c: $type) -> bool {
|
||||
(&a | (&b | &c)) == ((&a | &b) | &c)
|
||||
}
|
||||
fn and_associative(a: $type, b: $type, c: $type) -> bool {
|
||||
(&a & (&b & &c)) == ((&a & &b) & &c)
|
||||
}
|
||||
fn xor_as_defined(a: $type, b: $type) -> bool {
|
||||
(&a ^ &b) == ((&a | &b) & !(&a & &b))
|
||||
}
|
||||
fn small_or_check(x: u64, y: u64) -> bool {
|
||||
let x512 = $type::from(x);
|
||||
let y512 = $type::from(y);
|
||||
let z512 = x512 | y512;
|
||||
let res: u64 = z512.into();
|
||||
res == (x | y)
|
||||
}
|
||||
fn small_and_check(x: u64, y: u64) -> bool {
|
||||
let x512 = $type::from(x);
|
||||
let y512 = $type::from(y);
|
||||
let z512 = x512 & y512;
|
||||
let res: u64 = z512.into();
|
||||
res == (x & y)
|
||||
}
|
||||
fn small_xor_check(x: u64, y: u64) -> bool {
|
||||
let x512 = $type::from(x);
|
||||
let y512 = $type::from(y);
|
||||
let z512 = x512 ^ y512;
|
||||
let res: u64 = z512.into();
|
||||
res == (x ^ y)
|
||||
}
|
||||
fn small_neg_check(x: u64) -> bool {
|
||||
let x512 = $type::from(x);
|
||||
let z512 = !x512;
|
||||
let res: u64 = z512.into();
|
||||
res == !x
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shl_tests() {
|
||||
let ones = [1; $count];
|
||||
assert_eq!($type{ contents: ones.clone() } << 0,
|
||||
$type{ contents: ones.clone() });
|
||||
let mut notones = [0; $count];
|
||||
for i in 0..$count {
|
||||
notones[i] = (i + 1) as u64;
|
||||
}
|
||||
assert_eq!($type{ contents: notones.clone() } << 0,
|
||||
$type{ contents: notones.clone() });
|
||||
assert_eq!($type{ contents: ones.clone() } << ($count * 64),
|
||||
$type::zero());
|
||||
assert_eq!($type::from(2 as u8) << 1, $type::from(4 as u8));
|
||||
let mut buffer = [0; $count];
|
||||
buffer[1] = 1;
|
||||
assert_eq!($type::from(1 as u8) << 64,
|
||||
$type{ contents: buffer.clone() });
|
||||
buffer[0] = 0xFFFFFFFFFFFFFFFE;
|
||||
assert_eq!($type::from(0xFFFFFFFFFFFFFFFF as u64) << 1,
|
||||
$type{ contents: buffer.clone() });
|
||||
buffer[0] = 0;
|
||||
buffer[1] = 4;
|
||||
assert_eq!($type::from(1 as u8) << 66,
|
||||
$type{ contents: buffer.clone() });
|
||||
assert_eq!($type::from(1 as u8) << 1, $type::from(2 as u8));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shr_tests() {
|
||||
let ones = [1; $count];
|
||||
assert_eq!($type{ contents: ones.clone() } >> 0,
|
||||
$type{ contents: ones.clone() });
|
||||
let mut notones = [0; $count];
|
||||
for i in 0..$count {
|
||||
notones[i] = (i + 1) as u64;
|
||||
}
|
||||
assert_eq!($type{ contents: ones.clone() } >> 0,
|
||||
$type{ contents: ones.clone() });
|
||||
assert_eq!($type{ contents: ones.clone() } >> ($count * 64),
|
||||
$type::zero());
|
||||
assert_eq!($type::from(2 as u8) >> 1,
|
||||
$type::from(1 as u8));
|
||||
let mut oneleft = [0; $count];
|
||||
oneleft[1] = 1;
|
||||
assert_eq!($type{ contents: oneleft.clone() } >> 1,
|
||||
$type::from(0x8000000000000000 as u64));
|
||||
assert_eq!($type{ contents: oneleft.clone() } >> 64,
|
||||
$type::from(1 as u64));
|
||||
oneleft[1] = 4;
|
||||
assert_eq!($type{ contents: oneleft.clone() } >> 66,
|
||||
$type::from(1 as u64));
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn shift_mask_equivr(x: $type, in_shift: usize) -> bool {
|
||||
let shift = in_shift % ($count * 64);
|
||||
let mask = $type::max_value() << shift;
|
||||
let masked_x = &x & mask;
|
||||
let shift_maskr = (x >> shift) << shift;
|
||||
shift_maskr == masked_x
|
||||
}
|
||||
fn shift_mask_equivl(x: $type, in_shift: usize) -> bool {
|
||||
let shift = in_shift % ($count * 64);
|
||||
let mask = $type::max_value() >> shift;
|
||||
let masked_x = &x & mask;
|
||||
let shift_maskl = (x << shift) >> shift;
|
||||
shift_maskl == masked_x
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_tests() {
|
||||
let ones = [1; $count];
|
||||
let twos = [2; $count];
|
||||
assert_eq!($type{ contents: ones.clone() } +
|
||||
$type{ contents: ones.clone() },
|
||||
$type{ contents: twos.clone() });
|
||||
let mut buffer = [0; $count];
|
||||
buffer[1] = 1;
|
||||
assert_eq!($type::from(1 as u64) +
|
||||
$type::from(0xFFFFFFFFFFFFFFFF as u64),
|
||||
$type{ contents: buffer.clone() });
|
||||
let mut high = [0; $count];
|
||||
high[$count - 1] = 0xFFFFFFFFFFFFFFFF;
|
||||
buffer[1] = 0;
|
||||
buffer[$count - 1] = 1;
|
||||
assert_eq!($type{ contents: buffer } + $type{ contents: high },
|
||||
$type{ contents: [0; $count] });
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn add_symmetry(a: $type, b: $type) -> bool {
|
||||
(&a + &b) == (&b + &a)
|
||||
}
|
||||
fn add_commutivity(a: $type, b: $type, c: $type) -> bool {
|
||||
(&a + (&b + &c)) == ((&a + &b) + &c)
|
||||
}
|
||||
fn add_identity(a: $type) -> bool {
|
||||
(&a + $type::zero()) == a
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_tests() {
|
||||
let ones = [1; $count];
|
||||
assert_eq!($type{ contents: ones.clone() } -
|
||||
$type{ contents: ones.clone() },
|
||||
$type::zero());
|
||||
let mut buffer = [0; $count];
|
||||
buffer[1] = 1;
|
||||
assert_eq!($type{contents:buffer.clone()} - $type::from(1 as u8),
|
||||
$type::from(0xFFFFFFFFFFFFFFFF as u64));
|
||||
assert_eq!($type::zero() - $type::from(1 as u8),
|
||||
$type::max_value());
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn sub_destroys(a: $type) -> bool {
|
||||
(&a - &a) == $type::zero()
|
||||
}
|
||||
fn sub_add_ident(a: $type, b: $type) -> bool {
|
||||
((&a - &b) + &b) == a
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mul_tests() {
|
||||
assert_eq!($type::from(1 as u8) * $type::from(1 as u8),
|
||||
$type::from(1 as u8));
|
||||
assert_eq!($type::from(1 as u8) * $type::from(0 as u8),
|
||||
$type::from(0 as u8));
|
||||
assert_eq!($type::from(1 as u8) * $type::from(2 as u8),
|
||||
$type::from(2 as u8));
|
||||
let mut temp = $type::zero();
|
||||
temp.contents[0] = 1;
|
||||
temp.contents[1] = 0xFFFFFFFFFFFFFFFE;
|
||||
assert_eq!($type::from(0xFFFFFFFFFFFFFFFF as u64) *
|
||||
$type::from(0xFFFFFFFFFFFFFFFF as u64),
|
||||
temp);
|
||||
let effs = $type{ contents: [0xFFFFFFFFFFFFFFFF; $count] };
|
||||
assert_eq!($type::from(1 as u8) * &effs, effs);
|
||||
temp = effs.clone();
|
||||
temp.contents[0] = temp.contents[0] - 1;
|
||||
assert_eq!($type::from(2 as u8) * &effs, temp);
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn mul_symmetry(a: $type, b: $type) -> bool {
|
||||
(&a * &b) == (&b * &a)
|
||||
}
|
||||
fn mul_commutivity(a: $type, b: $type, c: $type) -> bool {
|
||||
(&a * (&b * &c)) == ((&a * &b) * &c)
|
||||
}
|
||||
fn mul_identity(a: $type) -> bool {
|
||||
(&a * $type::from(1 as u8)) == a
|
||||
}
|
||||
fn mul_zero(a: $type) -> bool {
|
||||
(&a * $type::zero()) == $type::zero()
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn addmul_distribution(a: $type, b: $type, c: $type) -> bool {
|
||||
(&a * (&b + &c)) == ((&a * &b) + (&a * &c))
|
||||
}
|
||||
fn submul_distribution(a: $type, b: $type, c: $type) -> bool {
|
||||
(&a * (&b - &c)) == ((&a * &b) - (&a * &c))
|
||||
}
|
||||
fn mul2shift1_equiv(a: $type) -> bool {
|
||||
(&a << 1) == (&a * $type::from(2 as u8))
|
||||
}
|
||||
fn mul16shift4_equiv(a: $type) -> bool {
|
||||
(&a << 4) == (&a * $type::from(16 as u8))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn div_tests() {
|
||||
assert_eq!($type::from(2 as u8) / $type::from(2 as u8),
|
||||
$type::from(1 as u8));
|
||||
assert_eq!($type::from(2 as u8) / $type::from(1 as u8),
|
||||
$type::from(2 as u8));
|
||||
assert_eq!($type::from(4 as u8) / $type::from(3 as u8),
|
||||
$type::from(1 as u8));
|
||||
assert_eq!($type::from(4 as u8) / $type::from(5 as u8),
|
||||
$type::from(0 as u8));
|
||||
assert_eq!($type::from(4 as u8) / $type::from(4 as u8),
|
||||
$type::from(1 as u8));
|
||||
let mut temp1 = $type::zero();
|
||||
let mut temp2 = $type::zero();
|
||||
temp1.contents[$count - 1] = 4;
|
||||
temp2.contents[$count - 1] = 4;
|
||||
assert_eq!(&temp1 / temp2, $type::from(1 as u8));
|
||||
assert_eq!(&temp1 / $type::from(1 as u8), temp1);
|
||||
temp1.contents[$count - 1] = u64::max_value();
|
||||
assert_eq!(&temp1 / $type::from(1 as u8), temp1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn div0_fails() {
|
||||
$type::from(0xabcd as u16) / $type::zero();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mod_tests() {
|
||||
assert_eq!($type::from(4 as u16) % $type::from(5 as u16),
|
||||
$type::from(4 as u16));
|
||||
assert_eq!($type::from(5 as u16) % $type::from(4 as u16),
|
||||
$type::from(1 as u16));
|
||||
let fives = $type{ contents: [5; $count] };
|
||||
let fours = $type{ contents: [4; $count] };
|
||||
let ones = $type{ contents: [1; $count] };
|
||||
assert_eq!(fives % fours, ones);
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
#[ignore]
|
||||
fn div_identity(a: $type) -> bool {
|
||||
&a / $type::from(1 as u16) == a
|
||||
}
|
||||
fn div_self_is_one(a: $type) -> bool {
|
||||
if a == $type::zero() {
|
||||
return true;
|
||||
}
|
||||
&a / &a == $type::from(1 as u16)
|
||||
}
|
||||
fn euclid_is_alive(a: $type, b: $type) -> bool {
|
||||
let q = &a / &b;
|
||||
let r = &a % &b;
|
||||
a == ((b * q) + r)
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn serialization_inverts(a: $type) -> bool {
|
||||
let bytes = a.to_bytes();
|
||||
let b = $type::from_bytes(&bytes);
|
||||
a == b
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn fastmod_works(a: $type, b: $type) -> bool {
|
||||
assert!(b != $type::zero());
|
||||
match b.barrett_mu() {
|
||||
None =>
|
||||
true,
|
||||
Some(barrett) => {
|
||||
a.fastmod(&barrett) == (&a % &b)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! shifts {
|
||||
($type: ident, $shtype: ty) => {
|
||||
shifts!($type, $shtype, ShlAssign, shl_assign, Shl, shl, generic_shl);
|
||||
shifts!($type, $shtype, ShrAssign, shr_assign, Shr, shr, generic_shr);
|
||||
};
|
||||
|
||||
($type: ident, $shtype: ty, $asncl: ident, $asnfn: ident,
|
||||
$cl: ident, $fn: ident, $impl: ident) => {
|
||||
impl $asncl<$shtype> for $type {
|
||||
fn $asnfn(&mut self, amount: $shtype) {
|
||||
let copy = self.contents.clone();
|
||||
$impl(&mut self.contents, ©, amount as usize);
|
||||
}
|
||||
}
|
||||
|
||||
impl $cl<$shtype> for $type {
|
||||
type Output = $type;
|
||||
|
||||
fn $fn(self, rhs: $shtype) -> $type {
|
||||
let mut res = self.clone();
|
||||
$impl(&mut res.contents, &self.contents, rhs as usize);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> $cl<$shtype> for &'a $type {
|
||||
type Output = $type;
|
||||
|
||||
fn $fn(self, rhs: $shtype) -> $type {
|
||||
let mut res = self.clone();
|
||||
$impl(&mut res.contents, &self.contents, rhs as usize);
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/dsa/errors.rs
Normal file
20
src/dsa/errors.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use simple_asn1::ASN1DecodeErr;
|
||||
use rand;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DSAError {
|
||||
RandomGenError(rand::Error),
|
||||
ASN1DecodeErr(ASN1DecodeErr)
|
||||
}
|
||||
|
||||
impl From<rand::Error> for DSAError {
|
||||
fn from(e: rand::Error) -> DSAError {
|
||||
DSAError::RandomGenError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ASN1DecodeErr> for DSAError {
|
||||
fn from(e: ASN1DecodeErr) -> DSAError {
|
||||
DSAError::ASN1DecodeErr(e)
|
||||
}
|
||||
}
|
||||
118
src/dsa/mod.rs
Normal file
118
src/dsa/mod.rs
Normal file
@@ -0,0 +1,118 @@
|
||||
//! If you want to use this module to generate keys, which you really
|
||||
//! really shouldn't, there are two ways to do so, depending on whether
|
||||
//! you've previously agreed on a set of DSA parameters for this key
|
||||
//! pair. If you haven't, you can generate the parameters using a good
|
||||
//! random number generator.
|
||||
//!
|
||||
//! ```rust
|
||||
//! use simple_crypto::dsa::{DSAKeyPair,DSAParameters,L2048N256};
|
||||
//! use simple_crypto::sha::SHA224;
|
||||
//!
|
||||
//! // Generate a set of DSA parameters, assuming you don't have
|
||||
//! // them already
|
||||
//! let mut rng = rand::rngs::OsRng::new().unwrap();
|
||||
//! let params = L2048N256::generate(&mut rng);
|
||||
//!
|
||||
//! // Given those parameters, you can generate a key pair like so:
|
||||
//! let kp = DSAKeyPair::<L2048N256>::generate(¶ms, &mut rng);
|
||||
//! // Keeping in mind that you can re-use the parameters across multiple
|
||||
//! // keys, and that their secrecy isn't paramout for the security of the
|
||||
//! // algorithm.
|
||||
//!
|
||||
//! // Now that you have this key pair, you can sign and verify messages
|
||||
//! // using it. For example, to sign the vector [0,1,2,3,4] with SHA224
|
||||
//! // and then verify that signature, we would write:
|
||||
//! let msg = vec![0,1,2,3,4];
|
||||
//! let sig = kp.private.sign::<SHA224>(&msg);
|
||||
//! assert!( kp.public.verify::<SHA224>(&msg, &sig) );
|
||||
//! ```
|
||||
|
||||
|
||||
mod errors;
|
||||
mod params;
|
||||
mod private;
|
||||
mod public;
|
||||
/// Support for RFC6979 signing, which provides a secure way to generate
|
||||
/// signatures without the use of a random number generator. This is used
|
||||
/// in DSA signing as well as in ECDSA signing, but appears here because
|
||||
/// ... well, because it was written for DSA first, both historically
|
||||
/// (I think) and by me.
|
||||
pub mod rfc6979;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use self::params::*;
|
||||
pub use self::private::*;
|
||||
pub use self::public::*;
|
||||
|
||||
use cryptonum::unsigned::*;
|
||||
use rand::Rng;
|
||||
use rand::distributions::Standard;
|
||||
use super::KeyPair;
|
||||
|
||||
/// A DSA key pair, for use in signing and signature verification. Note
|
||||
/// that you probably shouldn't be using DSA any more; ECDSA or ED25519
|
||||
/// are probably better options.
|
||||
///
|
||||
/// DSA key pairs are parameterized by their DSA parameters, so that
|
||||
/// you can't accidentally use them in the wrong place.
|
||||
pub struct DSAKeyPair<P: DSAParameters>
|
||||
{
|
||||
pub private: DSAPrivateKey<P>,
|
||||
pub public: DSAPublicKey<P>
|
||||
}
|
||||
|
||||
impl<P: DSAParameters> KeyPair for DSAKeyPair<P>
|
||||
{
|
||||
type Private = DSAPrivateKey<P>;
|
||||
type Public = DSAPublicKey<P>;
|
||||
|
||||
fn new(public: DSAPublicKey<P>, private: DSAPrivateKey<P>) -> DSAKeyPair<P>
|
||||
{
|
||||
DSAKeyPair{ private, public }
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_dsa_pair {
|
||||
($ptype: ident, $ltype: ident, $ntype: ident, $nbig: ident) => {
|
||||
impl DSAKeyPair<$ptype>
|
||||
{
|
||||
/// Generate a DSA key pair using the given parameters and random
|
||||
/// number generator. Please make sure that the RNG you're using
|
||||
/// is suitable for key generators (look for the term "cryptographic"
|
||||
/// or "crypto strong" in its documentation, or see if it matches
|
||||
/// any of the NIST-suggested RNG algorithms).
|
||||
pub fn generate<G: Rng>(params: &$ptype, rng: &mut G) -> Self
|
||||
{
|
||||
// 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 + 64) / 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(¶ms.q);
|
||||
let x = $ntype::from( (&c % (&qbig - &one)) + &one );
|
||||
// 7. y = g^x mod p
|
||||
let y = params.g.modexp(&$ltype::from(&x), ¶ms.p);
|
||||
// 8. Return SUCCESS, x, and y.
|
||||
let private = DSAPrivateKey::<$ptype>::new(params.clone(), x);
|
||||
let public = DSAPublicKey::<$ptype>::new(params.clone(), y);
|
||||
DSAKeyPair { private, public }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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);
|
||||
225
src/dsa/params.rs
Normal file
225
src/dsa/params.rs
Normal file
@@ -0,0 +1,225 @@
|
||||
use cryptonum::unsigned::{CryptoNum,Decoder,Encoder,ModExp,PrimeGen};
|
||||
use cryptonum::unsigned::{U192,U256,U1024,U2048,U3072};
|
||||
use sha::{Hash,SHA256};
|
||||
use simple_asn1::{ToASN1,ASN1Block,ASN1Class,ASN1EncodeErr};
|
||||
use rand::Rng;
|
||||
use utils::TranslateNums;
|
||||
|
||||
/// A trait that describes what a set of DSA parameters must support in
|
||||
/// order to be used by the rest of the system.
|
||||
pub trait DSAParameters : ToASN1
|
||||
{
|
||||
/// The fixed-width, unsigned type of values in L.
|
||||
type L;
|
||||
/// The fixed-width, unsigned type of values in N.
|
||||
type N;
|
||||
|
||||
/// Given a `p`, `g`, and `q`, generate a new structure that includes
|
||||
/// this information. Optionally, do any cross-checks needed.
|
||||
fn new(p: Self::L, g: Self::L, q: Self::N) -> Self;
|
||||
/// Generate a new set of DSA parameters given the provided random
|
||||
/// number generator. Just as with key generation, this should be a
|
||||
/// cryptographically-strong random number generator. If it's not,
|
||||
/// you may be writing compromisable code.
|
||||
fn generate<G: Rng>(rng: &mut G) -> Self;
|
||||
/// Return the size of values of N in bits.
|
||||
fn n_size() -> usize;
|
||||
/// Return the size of values of L in bits.
|
||||
fn l_size() -> usize;
|
||||
/// Return the size of `q` in this particular instance of the parameters.
|
||||
/// (Should be the same as `n_size()`, and the default implementation
|
||||
/// simply uses `n_size(), but included for convenience)
|
||||
fn n_bits(&self) -> usize {
|
||||
Self::n_size()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_parameters {
|
||||
($name: ident, $ltype: ident, $ntype: ident, $l: expr, $n: expr) => {
|
||||
/// DSA parameters to the given L and N, with the values given in bits.
|
||||
#[derive(Clone,PartialEq)]
|
||||
pub struct $name {
|
||||
pub p: $ltype,
|
||||
pub g: $ltype,
|
||||
pub q: $ntype
|
||||
}
|
||||
|
||||
impl ToASN1 for $name {
|
||||
type Error = ASN1EncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||
{
|
||||
let p = ASN1Block::Integer(c, 0, self.p.to_num());
|
||||
let q = ASN1Block::Integer(c, 0, self.q.to_num());
|
||||
let g = ASN1Block::Integer(c, 0, self.g.to_num());
|
||||
Ok(vec![ASN1Block::Sequence(c, 0, vec![p, q, g])])
|
||||
}
|
||||
}
|
||||
|
||||
impl DSAParameters for $name
|
||||
{
|
||||
type L = $ltype;
|
||||
type N = $ntype;
|
||||
|
||||
fn new(p: $ltype, g: $ltype, q: $ntype) -> $name
|
||||
{
|
||||
$name{ p: p, g: g, q: q }
|
||||
}
|
||||
|
||||
fn generate<G: Rng>(rng: &mut G) -> $name
|
||||
{
|
||||
let (p, q, _, _) = $name::generate_primes(rng);
|
||||
let g = $name::generate_g(rng, &p, &q);
|
||||
$name{ p: p, g: g, q: q }
|
||||
}
|
||||
|
||||
fn l_size() -> usize {
|
||||
$l
|
||||
}
|
||||
|
||||
fn n_size() -> usize {
|
||||
$n
|
||||
}
|
||||
}
|
||||
|
||||
impl $name
|
||||
{
|
||||
pub fn generate_primes<G: Rng>(rng: &mut G) -> ($ltype,$ntype,U256,usize)
|
||||
{
|
||||
// This is A.1.1.2 from FIPS 186-4, with seedlen hardcoded to 256
|
||||
// (since that's guaranteed to be >= N), and with the hash
|
||||
// hardcoded as SHA-256.
|
||||
#[allow(non_snake_case)]
|
||||
let L = $ltype::bit_length();
|
||||
#[allow(non_snake_case)]
|
||||
let N = $ntype::bit_length();
|
||||
let seedlen = 256;
|
||||
let outlen = 256;
|
||||
//
|
||||
// 1. Check that the (L,N) pair is in the list of acceptable
|
||||
// (L,N) pairs (see Section 4.2). If the pair is not in the
|
||||
// list, then return INVALID.
|
||||
// [This is always true.]
|
||||
//
|
||||
// 2. If (seedlen < N), then return INVALID.
|
||||
// [This is always true.]
|
||||
//
|
||||
// 3. n = L/outlen – 1.
|
||||
let n = ((L + 255) / 256) - 1;
|
||||
// 4. b = L – 1 – (n ∗ outlen).
|
||||
let b = L - 1 - (n * outlen);
|
||||
loop {
|
||||
// 5. Get an arbitrary sequence of seedlen bits as the
|
||||
// domain_parameter_seed.
|
||||
let domain_parameter_seed: U256 = rng.gen();
|
||||
// 6. U = Hash (domain_parameter_seed) mod 2^(N–1).
|
||||
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^(N–1) + U + 1 – (U mod 2).
|
||||
let highbit = $ntype::from(1u64) << (N - 1);
|
||||
let lowbit = $ntype::from(1u64);
|
||||
let q = U | highbit | lowbit;
|
||||
// 8. Test whether or not q is prime as specified in Appendix C.3.
|
||||
let q_is_prime = q.probably_prime(rng, 40);
|
||||
// 9. If q is not a prime, then go to step 5.
|
||||
if !q_is_prime {
|
||||
continue;
|
||||
}
|
||||
// 10. offset = 1.
|
||||
let mut offset = 1;
|
||||
// 11. For counter = 0 to (4L – 1) do
|
||||
for counter in 0..(4*L)-1 {
|
||||
// 11.1 For j = 0 to n do
|
||||
// Vj = Hash ((domain_parameter_seed + offset + j) mod 2^seedlen).
|
||||
#[allow(non_snake_case)]
|
||||
let mut V = Vec::new();
|
||||
for j in 0..n {
|
||||
let val = &domain_parameter_seed + U256::from(offset + j);
|
||||
let bytes = hash(&val, 32);
|
||||
assert_eq!(seedlen, bytes.len() * 8);
|
||||
V.push(bytes);
|
||||
}
|
||||
// 11.2 W = V_0 + ( V_1 ∗ 2^outlen) + ... + ( V_(n–1) ∗ 2^(n –1) ∗ outlen) + ((V_n mod 2^b) ∗ 2^(n ∗ outlen).
|
||||
#[allow(non_snake_case)]
|
||||
let mut W = $ltype::zero();
|
||||
for (idx, val) in V.iter().enumerate() {
|
||||
if idx < n {
|
||||
let mut base = val.clone();
|
||||
let baselen = base.len();
|
||||
base.resize(baselen + (idx * (outlen / 8)), 0);
|
||||
W += $ltype::from_bytes(&base);
|
||||
} else {
|
||||
let base = $ltype::from_bytes(val);
|
||||
let twob = $ltype::from(1u64) << b;
|
||||
let val = base % twob;
|
||||
W += val << (n * outlen);
|
||||
}
|
||||
}
|
||||
// 11.3 X = W + 2^(L – 1).
|
||||
// Comment: 0 ≤ W < 2 L – 1 ; hence, 2 L – 1 ≤ X < 2 L .
|
||||
#[allow(non_snake_case)]
|
||||
let mut X = $ltype::from(1u64) << (L - 1);
|
||||
X += W;
|
||||
// 11.4 c = X mod 2q.
|
||||
let c = &X % ($ltype::from(&q) << 1);
|
||||
// 11.5 p = X – ( c – 1).
|
||||
// Comment: p ≡ 1 ( mod 2 q) .
|
||||
let p = &X - (c - $ltype::from(1u64));
|
||||
// 11.6 If ( p < 2L – 1), then go to step 11.9.
|
||||
if p >= $ltype::from((2*L) - 1) {
|
||||
// 11.7 Test whether or not p is prime as specified in Appendix C .3.
|
||||
if p.probably_prime(rng, 40) {
|
||||
// 11.8 If p is determined to be prime, then return VALID and the values of p , q and (optionally) the values of domain_parameter_seed and counter .
|
||||
return (p, q, domain_parameter_seed, counter);
|
||||
}
|
||||
}
|
||||
// 11.9 offset = offset + n + 1.
|
||||
offset = offset + n + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_g<G: Rng>(rng: &mut G, p: &$ltype, q: &$ntype) -> $ltype
|
||||
{
|
||||
let bigq = $ltype::from(q);
|
||||
let p_minus_1 = p - $ltype::from(1u64);
|
||||
// This is A.2.1 (Unverifiable Generation of g) from FIPS 186-4.
|
||||
// 1. e = (p – 1) / q.
|
||||
let e = (p - $ltype::from(1u64)) / bigq;
|
||||
loop {
|
||||
// 2. Set h = any integer satisfying 1 < h < ( p – 1), such that
|
||||
// h differs from any value previously tried. Note that h could
|
||||
// be obtained from a random number generator or from a counter
|
||||
// that changes after each use.
|
||||
let h = rng.gen_range($ltype::from(2u64), &p_minus_1);
|
||||
// 3. g = h^e mod p.
|
||||
let g = h.modexp(&e, p);
|
||||
// 4. If ( g = 1), then go to step 2.
|
||||
if g != $ltype::from(1u64) {
|
||||
// 5. Return g
|
||||
return g;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
generate_parameters!(L1024N160, U1024, U192, 1024, 160);
|
||||
generate_parameters!(L2048N224, U2048, U256, 2048, 224);
|
||||
generate_parameters!(L2048N256, U2048, U256, 2048, 256);
|
||||
generate_parameters!(L3072N256, U3072, U256, 3072, 256);
|
||||
|
||||
fn hash<T>(x: &T, len: usize) -> Vec<u8>
|
||||
where T: Encoder
|
||||
{
|
||||
let mut base = x.to_bytes();
|
||||
let bytelen = len / 8;
|
||||
while base.len() < bytelen {
|
||||
base.insert(0,0);
|
||||
}
|
||||
SHA256::hash(&base)
|
||||
}
|
||||
159
src/dsa/private.rs
Normal file
159
src/dsa/private.rs
Normal file
@@ -0,0 +1,159 @@
|
||||
use cryptonum::unsigned::*;
|
||||
use cryptonum::signed::ModInv;
|
||||
use dsa::params::*;
|
||||
use dsa::rfc6979::*;
|
||||
use sha::Hash;
|
||||
|
||||
/// A DSA private key, parameterized by its DSA parameters (so that you don't
|
||||
/// accidentally pass the wrong key to the wrong routine).
|
||||
pub struct DSAPrivateKey<Params: DSAParameters>
|
||||
{
|
||||
pub(crate) params: Params,
|
||||
pub(crate) x: Params::N
|
||||
}
|
||||
|
||||
/// A generic DSA private key enum, which masks which kind of DSA key (1024,
|
||||
/// 2048 with the small `n`, 2048 with the normal `n`, or 3072) you're using.
|
||||
pub enum DSAPrivate {
|
||||
DSA1024Private(DSAPrivateKey<L1024N160>),
|
||||
DSA2048SmallPrivate(DSAPrivateKey<L2048N224>),
|
||||
DSA2048Private(DSAPrivateKey<L2048N256>),
|
||||
DSA3072Private(DSAPrivateKey<L3072N256>)
|
||||
}
|
||||
|
||||
macro_rules! privkey_impls {
|
||||
($ptype: ident, $ltype: ident, $ntype: ident, $big: ident, $bigger: ident, $biggest: ident) => {
|
||||
impl DSAPrivateKey<$ptype>
|
||||
{
|
||||
pub fn new(params: $ptype, x: $ntype) -> DSAPrivateKey<$ptype>
|
||||
{
|
||||
DSAPrivateKey{ params, x }
|
||||
}
|
||||
|
||||
pub fn sign<H: Hash + Clone>(&self, m: &[u8]) -> DSASignature<$ntype>
|
||||
{
|
||||
// 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 = <H>::hash(m);
|
||||
let n = $ptype::n_size();
|
||||
let h0: $ntype = bits2int(&h1, $ptype::n_size());
|
||||
let q = &self.params.q;
|
||||
let h = h0 % q;
|
||||
|
||||
// 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::<H,$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 sha::{SHA224,SHA256,SHA384,SHA512};
|
||||
|
||||
#[test]
|
||||
fn verify() {
|
||||
let fname = format!("testdata/dsa/sign{}.test", stringify!($params));
|
||||
run_test(fname.to_string(), 9, |case| {
|
||||
let (neg0, pbytes) = case.get("p").unwrap();
|
||||
let (neg1, qbytes) = case.get("q").unwrap();
|
||||
let (neg2, gbytes) = case.get("g").unwrap();
|
||||
let (neg3, _bytes) = case.get("y").unwrap();
|
||||
let (neg4, xbytes) = case.get("x").unwrap();
|
||||
let (neg5, mbytes) = case.get("m").unwrap();
|
||||
let (neg6, hbytes) = case.get("h").unwrap();
|
||||
let (neg7, rbytes) = case.get("r").unwrap();
|
||||
let (neg8, sbytes) = case.get("s").unwrap();
|
||||
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 &&
|
||||
!neg5 && !neg6 && !neg7 && !neg8);
|
||||
let p = $lt::from_bytes(pbytes);
|
||||
let q = $nt::from_bytes(qbytes);
|
||||
let g = $lt::from_bytes(gbytes);
|
||||
let x = $nt::from_bytes(xbytes);
|
||||
//let y = $lt::from_bytes(ybytes);
|
||||
let h = usize::from($nt::from_bytes(hbytes));
|
||||
let r = $nt::from_bytes(rbytes);
|
||||
let s = $nt::from_bytes(sbytes);
|
||||
|
||||
let params = $params::new(p,g,q);
|
||||
let private = DSAPrivateKey::<$params>::new(params, x);
|
||||
let sig = match h {
|
||||
224 => private.sign::<SHA224>(mbytes),
|
||||
256 => private.sign::<SHA256>(mbytes),
|
||||
384 => private.sign::<SHA384>(mbytes),
|
||||
512 => private.sign::<SHA512>(mbytes),
|
||||
_ => panic!("Unexpected hash {}", h)
|
||||
};
|
||||
assert_eq!(r, sig.r);
|
||||
assert_eq!(s, sig.s);
|
||||
});
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
generate_tests!( (DSA1024N160, L1024N160, U1024, U192),
|
||||
(DSA2048N224, L2048N224, U2048, U256),
|
||||
(DSA2048N256, L2048N256, U2048, U256),
|
||||
(DSA3072N256, L3072N256, U3072, U256)
|
||||
);
|
||||
145
src/dsa/public.rs
Normal file
145
src/dsa/public.rs
Normal file
@@ -0,0 +1,145 @@
|
||||
use cryptonum::unsigned::*;
|
||||
use cryptonum::signed::ModInv;
|
||||
use dsa::params::*;
|
||||
use dsa::rfc6979::DSASignature;
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,ToASN1};
|
||||
use sha::Hash;
|
||||
use std::cmp::min;
|
||||
use utils::TranslateNums;
|
||||
|
||||
/// A DSA public key, parameterized by its DSA parameters (so that you don't
|
||||
/// accidentally pass the wrong thing to the wrong function).
|
||||
pub struct DSAPublicKey<Params: DSAParameters> {
|
||||
pub(crate) params: Params,
|
||||
pub(crate) y: Params::L
|
||||
}
|
||||
|
||||
/// An enumeration that hides exactly which parameters you're using. Use at
|
||||
/// your own risk, as the types won't save you.
|
||||
pub enum DSAPublic {
|
||||
DSAPublicL1024N160(DSAPublicKey<L1024N160>),
|
||||
DSAPublicL2048N224(DSAPublicKey<L2048N224>),
|
||||
DSAPublicL2048N256(DSAPublicKey<L2048N256>),
|
||||
DSAPublicL3072N256(DSAPublicKey<L3072N256>)
|
||||
}
|
||||
|
||||
macro_rules! pubkey_impls {
|
||||
($ptype: ident, $ltype: ident, $ntype: ident, $dbl: ident, $bdbl: ident) => {
|
||||
impl DSAPublicKey<$ptype>
|
||||
{
|
||||
pub fn new(params: $ptype, y: $ltype) -> DSAPublicKey<$ptype>
|
||||
{
|
||||
DSAPublicKey{ params, y }
|
||||
}
|
||||
|
||||
pub fn verify<H: Hash>(&self, m: &[u8], sig: &DSASignature<$ntype>) -> bool
|
||||
{
|
||||
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 = <H>::hash(m);
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
impl ToASN1 for DSAPublicKey<$ptype> {
|
||||
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])
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pubkey_impls!(L1024N160, U1024, U192, U384, U2048);
|
||||
pubkey_impls!(L2048N224, U2048, U256, U512, U4096);
|
||||
pubkey_impls!(L2048N256, U2048, U256, U512, U4096);
|
||||
pubkey_impls!(L3072N256, U3072, U256, U512, U6144);
|
||||
|
||||
macro_rules! generate_tests {
|
||||
( $( ($mod: ident, $params: ident, $lt: ident, $nt: ident) ),* ) => {
|
||||
$(
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod $mod {
|
||||
use cryptonum::unsigned::Decoder;
|
||||
use super::*;
|
||||
use testing::run_test;
|
||||
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||
|
||||
#[test]
|
||||
fn verify() {
|
||||
let fname = format!("testdata/dsa/sign{}.test", stringify!($params));
|
||||
run_test(fname.to_string(), 9, |case| {
|
||||
let (neg0, pbytes) = case.get("p").unwrap();
|
||||
let (neg1, qbytes) = case.get("q").unwrap();
|
||||
let (neg2, gbytes) = case.get("g").unwrap();
|
||||
let (neg3, ybytes) = case.get("y").unwrap();
|
||||
let (neg4, _bytes) = case.get("x").unwrap();
|
||||
let (neg5, mbytes) = case.get("m").unwrap();
|
||||
let (neg6, hbytes) = case.get("h").unwrap();
|
||||
let (neg7, rbytes) = case.get("r").unwrap();
|
||||
let (neg8, sbytes) = case.get("s").unwrap();
|
||||
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 &&
|
||||
!neg5 && !neg6 && !neg7 && !neg8);
|
||||
let p = $lt::from_bytes(pbytes);
|
||||
let q = $nt::from_bytes(qbytes);
|
||||
let g = $lt::from_bytes(gbytes);
|
||||
//let x = $lt::from_bytes(xbytes);
|
||||
let y = $lt::from_bytes(ybytes);
|
||||
let h = usize::from($nt::from_bytes(hbytes));
|
||||
let r = $nt::from_bytes(rbytes);
|
||||
let s = $nt::from_bytes(sbytes);
|
||||
|
||||
let params = $params::new(p,g,q);
|
||||
let public = DSAPublicKey::<$params>::new(params, y);
|
||||
let sig = DSASignature::<$nt>::new(r, s);
|
||||
match h {
|
||||
224 => assert!(public.verify::<SHA224>(mbytes, &sig)),
|
||||
256 => assert!(public.verify::<SHA256>(mbytes, &sig)),
|
||||
384 => assert!(public.verify::<SHA384>(mbytes, &sig)),
|
||||
512 => assert!(public.verify::<SHA512>(mbytes, &sig)),
|
||||
_ => panic!("Unexpected hash {}", h)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
generate_tests!( (DSA1024N160, L1024N160, U1024, U192),
|
||||
(DSA2048N224, L2048N224, U2048, U256),
|
||||
(DSA2048N256, L2048N256, U2048, U256),
|
||||
(DSA3072N256, L3072N256, U3072, U256)
|
||||
);
|
||||
417
src/dsa/rfc6979.rs
Normal file
417
src/dsa/rfc6979.rs
Normal file
@@ -0,0 +1,417 @@
|
||||
use cryptonum::unsigned::{CryptoNum,Decoder,Encoder};
|
||||
use hmac::HMAC;
|
||||
use sha::Hash;
|
||||
use num::BigInt;
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr};
|
||||
use simple_asn1::{FromASN1,ToASN1};
|
||||
use utils::TranslateNums;
|
||||
use std::ops::{Shr,Sub};
|
||||
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub struct DSASignature<N>
|
||||
{
|
||||
pub r: N,
|
||||
pub s: N
|
||||
}
|
||||
|
||||
impl<N> DSASignature<N>
|
||||
{
|
||||
pub fn new(r: N, s: N) -> DSASignature<N>
|
||||
{
|
||||
DSASignature{ r, s }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub struct KIterator<H,N>
|
||||
where
|
||||
H: Hash + Clone,
|
||||
N: Clone + Decoder + Encoder + PartialOrd + Shr<usize,Output=N>,
|
||||
{
|
||||
hmac_k: HMAC<H>,
|
||||
V: Vec<u8>,
|
||||
q: N,
|
||||
qlen: usize
|
||||
}
|
||||
|
||||
impl<H,N> KIterator<H,N>
|
||||
where
|
||||
H: Hash + Clone,
|
||||
N: Clone + Decoder + Encoder + PartialOrd + Shr<usize,Output=N> + Sub<Output=N>,
|
||||
{
|
||||
pub fn new(h1: &[u8], qlen: usize, q: &N, x: &N) -> KIterator<H,N>
|
||||
{
|
||||
// Given the input message m, the following process is applied:
|
||||
//
|
||||
// a. Process m through the hash function H, yielding:
|
||||
//
|
||||
// h1 = H(m)
|
||||
//
|
||||
// (h1 is a sequence of hlen bits).
|
||||
//
|
||||
let hlen = h1.len();
|
||||
// b. Set:
|
||||
//
|
||||
// V = 0x01 0x01 0x01 ... 0x01
|
||||
//
|
||||
// such that the length of V, in bits, is equal to 8*ceil(hlen/8).
|
||||
// For instance, on an octet-based system, if H is SHA-256, then
|
||||
// V is set to a sequence of 32 octets of value 1. Note that in
|
||||
// this step and all subsequent steps, we use the same H function
|
||||
// as the one used in step 'a' to process the input message; this
|
||||
// choice will be discussed in more detail in Section 3.6.
|
||||
//
|
||||
#[allow(non_snake_case)]
|
||||
let mut V = Vec::new();
|
||||
V.resize(hlen, 0x01);
|
||||
// c. Set:
|
||||
//
|
||||
// K = 0x00 0x00 0x00 ... 0x00
|
||||
//
|
||||
// such that the length of K, in bits, is equal to 8*ceil(hlen/8).
|
||||
#[allow(non_snake_case)]
|
||||
let mut K = Vec::new();
|
||||
K.resize(hlen, 0x00);
|
||||
// d. Set:
|
||||
//
|
||||
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1))
|
||||
//
|
||||
// where '||' denotes concatenation. In other words, we compute
|
||||
// HMAC with key K, over the concatenation of the following, in
|
||||
// order: the current value of V, a sequence of eight bits of value
|
||||
// 0, the encoding of the (EC)DSA private key x, and the hashed
|
||||
// message (possibly truncated and extended as specified by the
|
||||
// bits2octets transform). The HMAC result is the new value of K.
|
||||
// Note that the private key x is in the [1, q-1] range, hence a
|
||||
// proper input for int2octets, yielding rlen bits of output, i.e.,
|
||||
// an integral number of octets (rlen is a multiple of 8).
|
||||
let xbytes = int2octets(x, qlen);
|
||||
let h1bytes = bits2octets(h1, q, qlen);
|
||||
let mut input = Vec::new();
|
||||
input.extend_from_slice(&V);
|
||||
input.push(0x00);
|
||||
input.extend_from_slice(&xbytes);
|
||||
input.extend_from_slice(&h1bytes);
|
||||
K = HMAC::<H>::hmac(&K, &input);
|
||||
// e. Set:
|
||||
//
|
||||
// V = HMAC_K(V)
|
||||
V = HMAC::<H>::hmac(&K, &V);
|
||||
// f. Set:
|
||||
//
|
||||
// K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1))
|
||||
//
|
||||
// Note that the "internal octet" is 0x01 this time.
|
||||
input = Vec::new();
|
||||
input.extend_from_slice(&V);
|
||||
input.push(0x01);
|
||||
input.extend_from_slice(&xbytes);
|
||||
input.extend_from_slice(&h1bytes);
|
||||
K = HMAC::<H>::hmac(&K, &input);
|
||||
// g. Set:
|
||||
//
|
||||
// V = HMAC_K(V)
|
||||
V = HMAC::<H>::hmac(&K, &V);
|
||||
// h is for later ...
|
||||
KIterator {
|
||||
hmac_k: HMAC::<H>::new(&K),
|
||||
V: V,
|
||||
q: q.clone(),
|
||||
qlen: qlen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<H,N> Iterator for KIterator<H,N>
|
||||
where
|
||||
H: Hash + Clone,
|
||||
N: Clone + CryptoNum + Decoder + Encoder + PartialOrd + Shr<usize,Output=N>,
|
||||
{
|
||||
type Item = N;
|
||||
|
||||
fn next(&mut self) -> Option<N>
|
||||
{
|
||||
loop {
|
||||
// h. Apply the following algorithm until a proper value is found
|
||||
// for k:
|
||||
//
|
||||
// 1. Set T to the empty sequence. The length of T (in bits) is
|
||||
// denoted tlen; thus, at that point, tlen = 0.
|
||||
let mut t = Vec::new();
|
||||
//
|
||||
// 2. While tlen < qlen, do the following:
|
||||
//
|
||||
// V = HMAC_K(V)
|
||||
// T = T || V
|
||||
let target = (self.qlen + 7) / 8;
|
||||
while t.len() < target {
|
||||
self.V = runhmac(&self.hmac_k, &self.V);
|
||||
t.extend_from_slice(&self.V);
|
||||
}
|
||||
//
|
||||
// 3. Compute:
|
||||
//
|
||||
// k = bits2int(T)
|
||||
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
|
||||
// that is not 0; see Section 3.4), then the generation of k
|
||||
// is finished. The obtained value of k is used in DSA or
|
||||
// ECDSA. Otherwise, compute:
|
||||
//
|
||||
// K = HMAC_K(V || 0x00)
|
||||
let mut input = self.V.clone();
|
||||
input.push(0x00);
|
||||
#[allow(non_snake_case)]
|
||||
let K = runhmac(&self.hmac_k, &input);
|
||||
// V = HMAC_K(V)
|
||||
self.hmac_k = HMAC::<H>::new(&K);
|
||||
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) {
|
||||
return Some(resk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bits2int<X>(x: &[u8], qlen: usize) -> X
|
||||
where
|
||||
X: Decoder + Shr<usize,Output=X>
|
||||
{
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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>(x: &X, qlen_bits: usize) -> Vec<u8>
|
||||
where X: Encoder
|
||||
{
|
||||
let qlen_bytes = (qlen_bits + 7) / 8;
|
||||
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: Hash + Clone>(base: &HMAC<H>, m: &[u8]) -> Vec<u8>
|
||||
{
|
||||
let mut runner = base.clone();
|
||||
runner.update(&m);
|
||||
runner.finalize()
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub enum DSADecodeError {
|
||||
ASN1Error(ASN1DecodeErr),
|
||||
NoSignatureFound,
|
||||
InvalidRValue,
|
||||
InvalidSValue
|
||||
}
|
||||
|
||||
impl From<ASN1DecodeErr> for DSADecodeError {
|
||||
fn from(a: ASN1DecodeErr) -> DSADecodeError {
|
||||
DSADecodeError::ASN1Error(a)
|
||||
}
|
||||
}
|
||||
|
||||
impl<N> FromASN1 for DSASignature<N>
|
||||
where N: TranslateNums<BigInt>
|
||||
{
|
||||
type Error = DSADecodeError;
|
||||
|
||||
fn from_asn1(v: &[ASN1Block])
|
||||
-> Result<(DSASignature<N>,&[ASN1Block]),DSADecodeError>
|
||||
{
|
||||
match v.split_first() {
|
||||
Some((&ASN1Block::Sequence(_,_,ref info), rest))
|
||||
if info.len() == 2 =>
|
||||
{
|
||||
match (&info[0], &info[1]) {
|
||||
(&ASN1Block::Integer(_,_,ref rint),
|
||||
&ASN1Block::Integer(_,_,ref sint)) => {
|
||||
let r = N::from_num(rint).ok_or(DSADecodeError::InvalidRValue)?;
|
||||
let s = N::from_num(sint).ok_or(DSADecodeError::InvalidSValue)?;
|
||||
Ok((DSASignature{ r, s }, rest))
|
||||
}
|
||||
_ => Err(DSADecodeError::NoSignatureFound)
|
||||
}
|
||||
}
|
||||
_ => Err(DSADecodeError::NoSignatureFound)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, 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 cryptonum::unsigned::U192;
|
||||
use sha::{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,
|
||||
0x0D, 0x99, 0xF8, 0xA5, 0xEF];
|
||||
const XBYTES: [u8; 21] = [0x00, 0x9A, 0x4D, 0x67, 0x92, 0x29, 0x5A, 0x7F,
|
||||
0x73, 0x0F, 0xC3, 0xF2, 0xB4, 0x9C, 0xBC, 0x0F,
|
||||
0x62, 0xE8, 0x62, 0x27, 0x2F];
|
||||
const H1: [u8; 32] = [0xAF, 0x2B, 0xDB, 0xE1, 0xAA, 0x9B, 0x6E, 0xC1,
|
||||
0xE2, 0xAD, 0xE1, 0xD6, 0x94, 0xF4, 0x1F, 0xC7,
|
||||
0x1A, 0x83, 0x1D, 0x02, 0x68, 0xE9, 0x89, 0x15,
|
||||
0x62, 0x11, 0x3D, 0x8A, 0x62, 0xAD, 0xD1, 0xBF];
|
||||
|
||||
#[test]
|
||||
fn int2octets_example() {
|
||||
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,
|
||||
0x62, 0xE8, 0x62, 0x27, 0x2F];
|
||||
assert_eq!(octets, target);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bits2octets_example() {
|
||||
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,
|
||||
0x2B, 0x3A, 0x20, 0x42, 0x24];
|
||||
assert_eq!(octets, target);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn k_gen_example() {
|
||||
let q = U192::from_bytes(&QBYTES);
|
||||
let x = U192::from_bytes(&XBYTES);
|
||||
let mut iter = KIterator::<SHA256,U192>::new(&H1, 163, &q, &x);
|
||||
match iter.next() {
|
||||
None =>
|
||||
assert!(false),
|
||||
Some(x) => {
|
||||
let target = vec![0x02, 0x3A, 0xF4, 0x07, 0x4C, 0x90, 0xA0,
|
||||
0x2B, 0x3F, 0xE6, 0x1D, 0x28, 0x6D, 0x5C,
|
||||
0x87, 0xF4, 0x25, 0xE6, 0xBD, 0xD8, 0x1B];
|
||||
let x2 = U192::from_bytes(&target);
|
||||
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");
|
||||
|
||||
}
|
||||
535
src/dsa/tests.rs
Normal file
535
src/dsa/tests.rs
Normal file
@@ -0,0 +1,535 @@
|
||||
use cryptonum::unsigned::*;
|
||||
use sha::{Hash,SHA1,SHA224,SHA256,SHA384,SHA512};
|
||||
use simple_asn1::{der_decode,der_encode};
|
||||
use dsa::params::{DSAParameters,L1024N160,L2048N256};
|
||||
use dsa::private::DSAPrivateKey;
|
||||
use dsa::public::DSAPublicKey;
|
||||
use dsa::rfc6979::KIterator;
|
||||
|
||||
macro_rules! run_rfc6979_test {
|
||||
($hash: ty, $ntype: ident, $val: ident, $params: ident, $public: ident, $private: ident,
|
||||
k $k: expr,
|
||||
r $r: expr,
|
||||
s $s: expr) => ({
|
||||
let h1 = <$hash>::hash(&$val);
|
||||
let rbytes = $r;
|
||||
let sbytes = $s;
|
||||
let r = $ntype::from_bytes(&rbytes);
|
||||
let s = $ntype::from_bytes(&sbytes);
|
||||
let mut iter = KIterator::<$hash,$ntype>::new(&h1, $params.n_bits(), &$params.q, &$private.x);
|
||||
let mut k1 = iter.next().unwrap().to_bytes().to_vec();
|
||||
while k1.len() > $k.len() {
|
||||
assert_eq!(k1[0], 0);
|
||||
k1.remove(0);
|
||||
}
|
||||
assert_eq!($k, k1);
|
||||
let sig = $private.sign::<$hash>(&$val);
|
||||
assert_eq!(sig.r, r);
|
||||
assert_eq!(sig.s, s);
|
||||
assert!($public.verify::<$hash>(&$val, &sig));
|
||||
let blocks = der_encode(&sig).unwrap();
|
||||
let sig2 = der_decode(&blocks).unwrap();
|
||||
assert_eq!(sig, sig2);
|
||||
})
|
||||
}
|
||||
|
||||
// these appendix_* tests are out of RFC6979
|
||||
#[test]
|
||||
fn appendix_a21() {
|
||||
let pbytes = vec![0x86, 0xF5, 0xCA, 0x03, 0xDC, 0xFE, 0xB2, 0x25,
|
||||
0x06, 0x3F, 0xF8, 0x30, 0xA0, 0xC7, 0x69, 0xB9,
|
||||
0xDD, 0x9D, 0x61, 0x53, 0xAD, 0x91, 0xD7, 0xCE,
|
||||
0x27, 0xF7, 0x87, 0xC4, 0x32, 0x78, 0xB4, 0x47,
|
||||
0xE6, 0x53, 0x3B, 0x86, 0xB1, 0x8B, 0xED, 0x6E,
|
||||
0x8A, 0x48, 0xB7, 0x84, 0xA1, 0x4C, 0x25, 0x2C,
|
||||
0x5B, 0xE0, 0xDB, 0xF6, 0x0B, 0x86, 0xD6, 0x38,
|
||||
0x5B, 0xD2, 0xF1, 0x2F, 0xB7, 0x63, 0xED, 0x88,
|
||||
0x73, 0xAB, 0xFD, 0x3F, 0x5B, 0xA2, 0xE0, 0xA8,
|
||||
0xC0, 0xA5, 0x90, 0x82, 0xEA, 0xC0, 0x56, 0x93,
|
||||
0x5E, 0x52, 0x9D, 0xAF, 0x7C, 0x61, 0x04, 0x67,
|
||||
0x89, 0x9C, 0x77, 0xAD, 0xED, 0xFC, 0x84, 0x6C,
|
||||
0x88, 0x18, 0x70, 0xB7, 0xB1, 0x9B, 0x2B, 0x58,
|
||||
0xF9, 0xBE, 0x05, 0x21, 0xA1, 0x70, 0x02, 0xE3,
|
||||
0xBD, 0xD6, 0xB8, 0x66, 0x85, 0xEE, 0x90, 0xB3,
|
||||
0xD9, 0xA1, 0xB0, 0x2B, 0x78, 0x2B, 0x17, 0x79];
|
||||
let qbytes = vec![0x99, 0x6F, 0x96, 0x7F, 0x6C, 0x8E, 0x38, 0x8D,
|
||||
0x9E, 0x28, 0xD0, 0x1E, 0x20, 0x5F, 0xBA, 0x95,
|
||||
0x7A, 0x56, 0x98, 0xB1];
|
||||
let gbytes = vec![0x07, 0xB0, 0xF9, 0x25, 0x46, 0x15, 0x0B, 0x62,
|
||||
0x51, 0x4B, 0xB7, 0x71, 0xE2, 0xA0, 0xC0, 0xCE,
|
||||
0x38, 0x7F, 0x03, 0xBD, 0xA6, 0xC5, 0x6B, 0x50,
|
||||
0x52, 0x09, 0xFF, 0x25, 0xFD, 0x3C, 0x13, 0x3D,
|
||||
0x89, 0xBB, 0xCD, 0x97, 0xE9, 0x04, 0xE0, 0x91,
|
||||
0x14, 0xD9, 0xA7, 0xDE, 0xFD, 0xEA, 0xDF, 0xC9,
|
||||
0x07, 0x8E, 0xA5, 0x44, 0xD2, 0xE4, 0x01, 0xAE,
|
||||
0xEC, 0xC4, 0x0B, 0xB9, 0xFB, 0xBF, 0x78, 0xFD,
|
||||
0x87, 0x99, 0x5A, 0x10, 0xA1, 0xC2, 0x7C, 0xB7,
|
||||
0x78, 0x9B, 0x59, 0x4B, 0xA7, 0xEF, 0xB5, 0xC4,
|
||||
0x32, 0x6A, 0x9F, 0xE5, 0x9A, 0x07, 0x0E, 0x13,
|
||||
0x6D, 0xB7, 0x71, 0x75, 0x46, 0x4A, 0xDC, 0xA4,
|
||||
0x17, 0xBE, 0x5D, 0xCE, 0x2F, 0x40, 0xD1, 0x0A,
|
||||
0x46, 0xA3, 0xA3, 0x94, 0x3F, 0x26, 0xAB, 0x7F,
|
||||
0xD9, 0xC0, 0x39, 0x8F, 0xF8, 0xC7, 0x6E, 0xE0,
|
||||
0xA5, 0x68, 0x26, 0xA8, 0xA8, 0x8F, 0x1D, 0xBD];
|
||||
let xbytes = vec![0x41, 0x16, 0x02, 0xCB, 0x19, 0xA6, 0xCC, 0xC3,
|
||||
0x44, 0x94, 0xD7, 0x9D, 0x98, 0xEF, 0x1E, 0x7E,
|
||||
0xD5, 0xAF, 0x25, 0xF7];
|
||||
let ybytes = vec![0x5D, 0xF5, 0xE0, 0x1D, 0xED, 0x31, 0xD0, 0x29,
|
||||
0x7E, 0x27, 0x4E, 0x16, 0x91, 0xC1, 0x92, 0xFE,
|
||||
0x58, 0x68, 0xFE, 0xF9, 0xE1, 0x9A, 0x84, 0x77,
|
||||
0x64, 0x54, 0xB1, 0x00, 0xCF, 0x16, 0xF6, 0x53,
|
||||
0x92, 0x19, 0x5A, 0x38, 0xB9, 0x05, 0x23, 0xE2,
|
||||
0x54, 0x2E, 0xE6, 0x18, 0x71, 0xC0, 0x44, 0x0C,
|
||||
0xB8, 0x7C, 0x32, 0x2F, 0xC4, 0xB4, 0xD2, 0xEC,
|
||||
0x5E, 0x1E, 0x7E, 0xC7, 0x66, 0xE1, 0xBE, 0x8D,
|
||||
0x4C, 0xE9, 0x35, 0x43, 0x7D, 0xC1, 0x1C, 0x3C,
|
||||
0x8F, 0xD4, 0x26, 0x33, 0x89, 0x33, 0xEB, 0xFE,
|
||||
0x73, 0x9C, 0xB3, 0x46, 0x5F, 0x4D, 0x36, 0x68,
|
||||
0xC5, 0xE4, 0x73, 0x50, 0x82, 0x53, 0xB1, 0xE6,
|
||||
0x82, 0xF6, 0x5C, 0xBD, 0xC4, 0xFA, 0xE9, 0x3C,
|
||||
0x2E, 0xA2, 0x12, 0x39, 0x0E, 0x54, 0x90, 0x5A,
|
||||
0x86, 0xE2, 0x22, 0x31, 0x70, 0xB4, 0x4E, 0xAA,
|
||||
0x7D, 0xA5, 0xDD, 0x9F, 0xFC, 0xFB, 0x7F, 0x3B];
|
||||
//
|
||||
let p = U1024::from_bytes(&pbytes);
|
||||
let q = U192::from_bytes(&qbytes);
|
||||
let g = U1024::from_bytes(&gbytes);
|
||||
let params = L1024N160::new(p, g, q);
|
||||
let x = U192::from_bytes(&xbytes);
|
||||
let y = U1024::from_bytes(&ybytes);
|
||||
let private = DSAPrivateKey::<L1024N160>::new(params.clone(), x);
|
||||
let public = DSAPublicKey::<L1024N160>::new(params.clone(), y);
|
||||
//
|
||||
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
|
||||
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
|
||||
// With SHA-1, message = "sample":
|
||||
// k = 7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B
|
||||
// r = 2E1A0C2562B2912CAAF89186FB0F42001585DA55
|
||||
// s = 29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5
|
||||
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],
|
||||
r vec![0x2E, 0x1A, 0x0C, 0x25, 0x62, 0xB2, 0x91, 0x2C,
|
||||
0xAA, 0xF8, 0x91, 0x86, 0xFB, 0x0F, 0x42, 0x00,
|
||||
0x15, 0x85, 0xDA, 0x55],
|
||||
s vec![0x29, 0xEF, 0xB6, 0xB0, 0xAF, 0xF2, 0xD7, 0xA6,
|
||||
0x8E, 0xB7, 0x0C, 0xA3, 0x13, 0x02, 0x22, 0x53,
|
||||
0xB9, 0xA8, 0x8D, 0xF5]);
|
||||
// With SHA-224, message = "sample":
|
||||
// k = 562097C06782D60C3037BA7BE104774344687649
|
||||
// r = 4BC3B686AEA70145856814A6F1BB53346F02101E
|
||||
// s = 410697B92295D994D21EDD2F4ADA85566F6F94C1
|
||||
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],
|
||||
r vec![0x4B, 0xC3, 0xB6, 0x86, 0xAE, 0xA7, 0x01, 0x45,
|
||||
0x85, 0x68, 0x14, 0xA6, 0xF1, 0xBB, 0x53, 0x34,
|
||||
0x6F, 0x02, 0x10, 0x1E],
|
||||
s vec![0x41, 0x06, 0x97, 0xB9, 0x22, 0x95, 0xD9, 0x94,
|
||||
0xD2, 0x1E, 0xDD, 0x2F, 0x4A, 0xDA, 0x85, 0x56,
|
||||
0x6F, 0x6F, 0x94, 0xC1]);
|
||||
// With SHA-256, message = "sample":
|
||||
// k = 519BA0546D0C39202A7D34D7DFA5E760B318BCFB
|
||||
// r = 81F2F5850BE5BC123C43F71A3033E9384611C545
|
||||
// s = 4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89
|
||||
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],
|
||||
r vec![0x81, 0xF2, 0xF5, 0x85, 0x0B, 0xE5, 0xBC, 0x12,
|
||||
0x3C, 0x43, 0xF7, 0x1A, 0x30, 0x33, 0xE9, 0x38,
|
||||
0x46, 0x11, 0xC5, 0x45],
|
||||
s vec![0x4C, 0xDD, 0x91, 0x4B, 0x65, 0xEB, 0x6C, 0x66,
|
||||
0xA8, 0xAA, 0xAD, 0x27, 0x29, 0x9B, 0xEE, 0x6B,
|
||||
0x03, 0x5F, 0x5E, 0x89]);
|
||||
// With SHA-384, message = "sample":
|
||||
// k = 95897CD7BBB944AA932DBC579C1C09EB6FCFC595
|
||||
// r = 07F2108557EE0E3921BC1774F1CA9B410B4CE65A
|
||||
// s = 54DF70456C86FAC10FAB47C1949AB83F2C6F7595
|
||||
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],
|
||||
r vec![0x07, 0xF2, 0x10, 0x85, 0x57, 0xEE, 0x0E, 0x39,
|
||||
0x21, 0xBC, 0x17, 0x74, 0xF1, 0xCA, 0x9B, 0x41,
|
||||
0x0B, 0x4C, 0xE6, 0x5A],
|
||||
s vec![0x54, 0xDF, 0x70, 0x45, 0x6C, 0x86, 0xFA, 0xC1,
|
||||
0x0F, 0xAB, 0x47, 0xC1, 0x94, 0x9A, 0xB8, 0x3F,
|
||||
0x2C, 0x6F, 0x75, 0x95]);
|
||||
// With SHA-512, message = "sample":
|
||||
// k = 09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B
|
||||
// r = 16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B
|
||||
// s = 02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C
|
||||
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],
|
||||
r vec![0x16, 0xC3, 0x49, 0x1F, 0x9B, 0x8C, 0x3F, 0xBB,
|
||||
0xDD, 0x5E, 0x7A, 0x7B, 0x66, 0x70, 0x57, 0xF0,
|
||||
0xD8, 0xEE, 0x8E, 0x1B],
|
||||
s vec![0x02, 0xC3, 0x6A, 0x12, 0x7A, 0x7B, 0x89, 0xED,
|
||||
0xBB, 0x72, 0xE4, 0xFF, 0xBC, 0x71, 0xDA, 0xBC,
|
||||
0x7D, 0x4F, 0xC6, 0x9C]);
|
||||
// With SHA-1, message = "test":
|
||||
// k = 5C842DF4F9E344EE09F056838B42C7A17F4A6433
|
||||
// r = 42AB2052FD43E123F0607F115052A67DCD9C5C77
|
||||
// s = 183916B0230D45B9931491D4C6B0BD2FB4AAF088
|
||||
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],
|
||||
r vec![0x42, 0xAB, 0x20, 0x52, 0xFD, 0x43, 0xE1, 0x23,
|
||||
0xF0, 0x60, 0x7F, 0x11, 0x50, 0x52, 0xA6, 0x7D,
|
||||
0xCD, 0x9C, 0x5C, 0x77],
|
||||
s vec![0x18, 0x39, 0x16, 0xB0, 0x23, 0x0D, 0x45, 0xB9,
|
||||
0x93, 0x14, 0x91, 0xD4, 0xC6, 0xB0, 0xBD, 0x2F,
|
||||
0xB4, 0xAA, 0xF0, 0x88]);
|
||||
// With SHA-224, message = "test":
|
||||
// k = 4598B8EFC1A53BC8AECD58D1ABBB0C0C71E67297
|
||||
// r = 6868E9964E36C1689F6037F91F28D5F2C30610F2
|
||||
// s = 49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F
|
||||
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],
|
||||
r vec![0x68, 0x68, 0xE9, 0x96, 0x4E, 0x36, 0xC1, 0x68,
|
||||
0x9F, 0x60, 0x37, 0xF9, 0x1F, 0x28, 0xD5, 0xF2,
|
||||
0xC3, 0x06, 0x10, 0xF2],
|
||||
s vec![0x49, 0xCE, 0xC3, 0xAC, 0xDC, 0x83, 0x01, 0x8C,
|
||||
0x5B, 0xD2, 0x67, 0x4E, 0xCA, 0xAD, 0x35, 0xB8,
|
||||
0xCD, 0x22, 0x94, 0x0F]);
|
||||
// With SHA-256, message = "test":
|
||||
// k = 5A67592E8128E03A417B0484410FB72C0B630E1A
|
||||
// r = 22518C127299B0F6FDC9872B282B9E70D0790812
|
||||
// s = 6837EC18F150D55DE95B5E29BE7AF5D01E4FE160
|
||||
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],
|
||||
r vec![0x22, 0x51, 0x8C, 0x12, 0x72, 0x99, 0xB0, 0xF6,
|
||||
0xFD, 0xC9, 0x87, 0x2B, 0x28, 0x2B, 0x9E, 0x70,
|
||||
0xD0, 0x79, 0x08, 0x12],
|
||||
s vec![0x68, 0x37, 0xEC, 0x18, 0xF1, 0x50, 0xD5, 0x5D,
|
||||
0xE9, 0x5B, 0x5E, 0x29, 0xBE, 0x7A, 0xF5, 0xD0,
|
||||
0x1E, 0x4F, 0xE1, 0x60]);
|
||||
// With SHA-384, message = "test":
|
||||
// k = 220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89
|
||||
// r = 854CF929B58D73C3CBFDC421E8D5430CD6DB5E66
|
||||
// s = 91D0E0F53E22F898D158380676A871A157CDA622
|
||||
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],
|
||||
r vec![0x85, 0x4C, 0xF9, 0x29, 0xB5, 0x8D, 0x73, 0xC3,
|
||||
0xCB, 0xFD, 0xC4, 0x21, 0xE8, 0xD5, 0x43, 0x0C,
|
||||
0xD6, 0xDB, 0x5E, 0x66],
|
||||
s vec![0x91, 0xD0, 0xE0, 0xF5, 0x3E, 0x22, 0xF8, 0x98,
|
||||
0xD1, 0x58, 0x38, 0x06, 0x76, 0xA8, 0x71, 0xA1,
|
||||
0x57, 0xCD, 0xA6, 0x22]);
|
||||
// With SHA-512, message = "test":
|
||||
// k = 65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C
|
||||
// r = 8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0
|
||||
// s = 7C670C7AD72B6C050C109E1790008097125433E8
|
||||
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],
|
||||
r vec![0x8E, 0xA4, 0x7E, 0x47, 0x5B, 0xA8, 0xAC, 0x6F,
|
||||
0x2D, 0x82, 0x1D, 0xA3, 0xBD, 0x21, 0x2D, 0x11,
|
||||
0xA3, 0xDE, 0xB9, 0xA0],
|
||||
s vec![0x7C, 0x67, 0x0C, 0x7A, 0xD7, 0x2B, 0x6C, 0x05,
|
||||
0x0C, 0x10, 0x9E, 0x17, 0x90, 0x00, 0x80, 0x97,
|
||||
0x12, 0x54, 0x33, 0xE8]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn appendix_a22() {
|
||||
let pbytes = vec![0x9D,0xB6,0xFB,0x59,0x51,0xB6,0x6B,0xB6,
|
||||
0xFE,0x1E,0x14,0x0F,0x1D,0x2C,0xE5,0x50,
|
||||
0x23,0x74,0x16,0x1F,0xD6,0x53,0x8D,0xF1,
|
||||
0x64,0x82,0x18,0x64,0x2F,0x0B,0x5C,0x48,
|
||||
0xC8,0xF7,0xA4,0x1A,0xAD,0xFA,0x18,0x73,
|
||||
0x24,0xB8,0x76,0x74,0xFA,0x18,0x22,0xB0,
|
||||
0x0F,0x1E,0xCF,0x81,0x36,0x94,0x3D,0x7C,
|
||||
0x55,0x75,0x72,0x64,0xE5,0xA1,0xA4,0x4F,
|
||||
0xFE,0x01,0x2E,0x99,0x36,0xE0,0x0C,0x1D,
|
||||
0x3E,0x93,0x10,0xB0,0x1C,0x7D,0x17,0x98,
|
||||
0x05,0xD3,0x05,0x8B,0x2A,0x9F,0x4B,0xB6,
|
||||
0xF9,0x71,0x6B,0xFE,0x61,0x17,0xC6,0xB5,
|
||||
0xB3,0xCC,0x4D,0x9B,0xE3,0x41,0x10,0x4A,
|
||||
0xD4,0xA8,0x0A,0xD6,0xC9,0x4E,0x00,0x5F,
|
||||
0x4B,0x99,0x3E,0x14,0xF0,0x91,0xEB,0x51,
|
||||
0x74,0x3B,0xF3,0x30,0x50,0xC3,0x8D,0xE2,
|
||||
0x35,0x56,0x7E,0x1B,0x34,0xC3,0xD6,0xA5,
|
||||
0xC0,0xCE,0xAA,0x1A,0x0F,0x36,0x82,0x13,
|
||||
0xC3,0xD1,0x98,0x43,0xD0,0xB4,0xB0,0x9D,
|
||||
0xCB,0x9F,0xC7,0x2D,0x39,0xC8,0xDE,0x41,
|
||||
0xF1,0xBF,0x14,0xD4,0xBB,0x45,0x63,0xCA,
|
||||
0x28,0x37,0x16,0x21,0xCA,0xD3,0x32,0x4B,
|
||||
0x6A,0x2D,0x39,0x21,0x45,0xBE,0xBF,0xAC,
|
||||
0x74,0x88,0x05,0x23,0x6F,0x5C,0xA2,0xFE,
|
||||
0x92,0xB8,0x71,0xCD,0x8F,0x9C,0x36,0xD3,
|
||||
0x29,0x2B,0x55,0x09,0xCA,0x8C,0xAA,0x77,
|
||||
0xA2,0xAD,0xFC,0x7B,0xFD,0x77,0xDD,0xA6,
|
||||
0xF7,0x11,0x25,0xA7,0x45,0x6F,0xEA,0x15,
|
||||
0x3E,0x43,0x32,0x56,0xA2,0x26,0x1C,0x6A,
|
||||
0x06,0xED,0x36,0x93,0x79,0x7E,0x79,0x95,
|
||||
0xFA,0xD5,0xAA,0xBB,0xCF,0xBE,0x3E,0xDA,
|
||||
0x27,0x41,0xE3,0x75,0x40,0x4A,0xE2,0x5B];
|
||||
let qbytes = vec![0xF2,0xC3,0x11,0x93,0x74,0xCE,0x76,0xC9,
|
||||
0x35,0x69,0x90,0xB4,0x65,0x37,0x4A,0x17,
|
||||
0xF2,0x3F,0x9E,0xD3,0x50,0x89,0xBD,0x96,
|
||||
0x9F,0x61,0xC6,0xDD,0xE9,0x99,0x8C,0x1F];
|
||||
let gbytes = vec![0x5C,0x7F,0xF6,0xB0,0x6F,0x8F,0x14,0x3F,
|
||||
0xE8,0x28,0x84,0x33,0x49,0x3E,0x47,0x69,
|
||||
0xC4,0xD9,0x88,0xAC,0xE5,0xBE,0x25,0xA0,
|
||||
0xE2,0x48,0x09,0x67,0x07,0x16,0xC6,0x13,
|
||||
0xD7,0xB0,0xCE,0xE6,0x93,0x2F,0x8F,0xAA,
|
||||
0x7C,0x44,0xD2,0xCB,0x24,0x52,0x3D,0xA5,
|
||||
0x3F,0xBE,0x4F,0x6E,0xC3,0x59,0x58,0x92,
|
||||
0xD1,0xAA,0x58,0xC4,0x32,0x8A,0x06,0xC4,
|
||||
0x6A,0x15,0x66,0x2E,0x7E,0xAA,0x70,0x3A,
|
||||
0x1D,0xEC,0xF8,0xBB,0xB2,0xD0,0x5D,0xBE,
|
||||
0x2E,0xB9,0x56,0xC1,0x42,0xA3,0x38,0x66,
|
||||
0x1D,0x10,0x46,0x1C,0x0D,0x13,0x54,0x72,
|
||||
0x08,0x50,0x57,0xF3,0x49,0x43,0x09,0xFF,
|
||||
0xA7,0x3C,0x61,0x1F,0x78,0xB3,0x2A,0xDB,
|
||||
0xB5,0x74,0x0C,0x36,0x1C,0x9F,0x35,0xBE,
|
||||
0x90,0x99,0x7D,0xB2,0x01,0x4E,0x2E,0xF5,
|
||||
0xAA,0x61,0x78,0x2F,0x52,0xAB,0xEB,0x8B,
|
||||
0xD6,0x43,0x2C,0x4D,0xD0,0x97,0xBC,0x54,
|
||||
0x23,0xB2,0x85,0xDA,0xFB,0x60,0xDC,0x36,
|
||||
0x4E,0x81,0x61,0xF4,0xA2,0xA3,0x5A,0xCA,
|
||||
0x3A,0x10,0xB1,0xC4,0xD2,0x03,0xCC,0x76,
|
||||
0xA4,0x70,0xA3,0x3A,0xFD,0xCB,0xDD,0x92,
|
||||
0x95,0x98,0x59,0xAB,0xD8,0xB5,0x6E,0x17,
|
||||
0x25,0x25,0x2D,0x78,0xEA,0xC6,0x6E,0x71,
|
||||
0xBA,0x9A,0xE3,0xF1,0xDD,0x24,0x87,0x19,
|
||||
0x98,0x74,0x39,0x3C,0xD4,0xD8,0x32,0x18,
|
||||
0x68,0x00,0x65,0x47,0x60,0xE1,0xE3,0x4C,
|
||||
0x09,0xE4,0xD1,0x55,0x17,0x9F,0x9E,0xC0,
|
||||
0xDC,0x44,0x73,0xF9,0x96,0xBD,0xCE,0x6E,
|
||||
0xED,0x1C,0xAB,0xED,0x8B,0x6F,0x11,0x6F,
|
||||
0x7A,0xD9,0xCF,0x50,0x5D,0xF0,0xF9,0x98,
|
||||
0xE3,0x4A,0xB2,0x75,0x14,0xB0,0xFF,0xE7];
|
||||
let xbytes = vec![0x69,0xC7,0x54,0x8C,0x21,0xD0,0xDF,0xEA,
|
||||
0x6B,0x9A,0x51,0xC9,0xEA,0xD4,0xE2,0x7C,
|
||||
0x33,0xD3,0xB3,0xF1,0x80,0x31,0x6E,0x5B,
|
||||
0xCA,0xB9,0x2C,0x93,0x3F,0x0E,0x4D,0xBC];
|
||||
let ybytes = vec![0x66,0x70,0x98,0xC6,0x54,0x42,0x6C,0x78,
|
||||
0xD7,0xF8,0x20,0x1E,0xAC,0x6C,0x20,0x3E,
|
||||
0xF0,0x30,0xD4,0x36,0x05,0x03,0x2C,0x2F,
|
||||
0x1F,0xA9,0x37,0xE5,0x23,0x7D,0xBD,0x94,
|
||||
0x9F,0x34,0xA0,0xA2,0x56,0x4F,0xE1,0x26,
|
||||
0xDC,0x8B,0x71,0x5C,0x51,0x41,0x80,0x2C,
|
||||
0xE0,0x97,0x9C,0x82,0x46,0x46,0x3C,0x40,
|
||||
0xE6,0xB6,0xBD,0xAA,0x25,0x13,0xFA,0x61,
|
||||
0x17,0x28,0x71,0x6C,0x2E,0x4F,0xD5,0x3B,
|
||||
0xC9,0x5B,0x89,0xE6,0x99,0x49,0xD9,0x65,
|
||||
0x12,0xE8,0x73,0xB9,0xC8,0xF8,0xDF,0xD4,
|
||||
0x99,0xCC,0x31,0x28,0x82,0x56,0x1A,0xDE,
|
||||
0xCB,0x31,0xF6,0x58,0xE9,0x34,0xC0,0xC1,
|
||||
0x97,0xF2,0xC4,0xD9,0x6B,0x05,0xCB,0xAD,
|
||||
0x67,0x38,0x1E,0x7B,0x76,0x88,0x91,0xE4,
|
||||
0xDA,0x38,0x43,0xD2,0x4D,0x94,0xCD,0xFB,
|
||||
0x51,0x26,0xE9,0xB8,0xBF,0x21,0xE8,0x35,
|
||||
0x8E,0xE0,0xE0,0xA3,0x0E,0xF1,0x3F,0xD6,
|
||||
0xA6,0x64,0xC0,0xDC,0xE3,0x73,0x1F,0x7F,
|
||||
0xB4,0x9A,0x48,0x45,0xA4,0xFD,0x82,0x54,
|
||||
0x68,0x79,0x72,0xA2,0xD3,0x82,0x59,0x9C,
|
||||
0x9B,0xAC,0x4E,0x0E,0xD7,0x99,0x81,0x93,
|
||||
0x07,0x89,0x13,0x03,0x25,0x58,0x13,0x49,
|
||||
0x76,0x41,0x0B,0x89,0xD2,0xC1,0x71,0xD1,
|
||||
0x23,0xAC,0x35,0xFD,0x97,0x72,0x19,0x59,
|
||||
0x7A,0xA7,0xD1,0x5C,0x1A,0x9A,0x42,0x8E,
|
||||
0x59,0x19,0x4F,0x75,0xC7,0x21,0xEB,0xCB,
|
||||
0xCF,0xAE,0x44,0x69,0x6A,0x49,0x9A,0xFA,
|
||||
0x74,0xE0,0x42,0x99,0xF1,0x32,0x02,0x66,
|
||||
0x01,0x63,0x8C,0xB8,0x7A,0xB7,0x91,0x90,
|
||||
0xD4,0xA0,0x98,0x63,0x15,0xDA,0x8E,0xEC,
|
||||
0x65,0x61,0xC9,0x38,0x99,0x6B,0xEA,0xDF];
|
||||
//
|
||||
let p = U2048::from_bytes(&pbytes);
|
||||
let q = U256::from_bytes(&qbytes);
|
||||
let g = U2048::from_bytes(&gbytes);
|
||||
let params = L2048N256::new(p, g, q);
|
||||
let x = U256::from_bytes(&xbytes);
|
||||
let y = U2048::from_bytes(&ybytes);
|
||||
let private = DSAPrivateKey::<L2048N256>::new(params.clone(), x);
|
||||
let public = DSAPublicKey::<L2048N256>::new(params.clone(), y);
|
||||
//
|
||||
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
|
||||
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
|
||||
// With SHA-1, message = "sample":
|
||||
// k = 888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E
|
||||
// r = 3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A
|
||||
// s = D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF
|
||||
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,
|
||||
0x5C,0xA1,0x62,0x30,0xF9,0xCB,0xD5,0x3E],
|
||||
r vec![0x3A,0x1B,0x2D,0xBD,0x74,0x89,0xD6,0xED,
|
||||
0x7E,0x60,0x8F,0xD0,0x36,0xC8,0x3A,0xF3,
|
||||
0x96,0xE2,0x90,0xDB,0xD6,0x02,0x40,0x8E,
|
||||
0x86,0x77,0xDA,0xAB,0xD6,0xE7,0x44,0x5A],
|
||||
s vec![0xD2,0x6F,0xCB,0xA1,0x9F,0xA3,0xE3,0x05,
|
||||
0x8F,0xFC,0x02,0xCA,0x15,0x96,0xCD,0xBB,
|
||||
0x6E,0x0D,0x20,0xCB,0x37,0xB0,0x60,0x54,
|
||||
0xF7,0xE3,0x6D,0xED,0x0C,0xDB,0xBC,0xCF]);
|
||||
// With SHA-224, message = "sample":
|
||||
// k = BC372967702082E1AA4FCE892209F71AE4AD25A6DFD869334E6F153BD0C4D806
|
||||
// r = DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C
|
||||
// s = A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC
|
||||
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,
|
||||
0x4E,0x6F,0x15,0x3B,0xD0,0xC4,0xD8,0x06],
|
||||
r vec![0xDC,0x9F,0x4D,0xEA,0xDA,0x8D,0x8F,0xF5,
|
||||
0x88,0xE9,0x8F,0xED,0x0A,0xB6,0x90,0xFF,
|
||||
0xCE,0x85,0x8D,0xC8,0xC7,0x93,0x76,0x45,
|
||||
0x0E,0xB6,0xB7,0x6C,0x24,0x53,0x7E,0x2C],
|
||||
s vec![0xA6,0x5A,0x9C,0x3B,0xC7,0xBA,0xBE,0x28,
|
||||
0x6B,0x19,0x5D,0x5D,0xA6,0x86,0x16,0xDA,
|
||||
0x8D,0x47,0xFA,0x00,0x97,0xF3,0x6D,0xD1,
|
||||
0x9F,0x51,0x73,0x27,0xDC,0x84,0x8C,0xEC]);
|
||||
// With SHA-256, message = "sample":
|
||||
// k = 8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52
|
||||
// r = EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809
|
||||
// s = 7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53
|
||||
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,
|
||||
0xAF,0x43,0x33,0x56,0x9D,0x59,0x7C,0x52],
|
||||
r vec![0xEA,0xCE,0x8B,0xDB,0xBE,0x35,0x3C,0x43,
|
||||
0x2A,0x79,0x5D,0x9E,0xC5,0x56,0xC6,0xD0,
|
||||
0x21,0xF7,0xA0,0x3F,0x42,0xC3,0x6E,0x9B,
|
||||
0xC8,0x7E,0x4A,0xC7,0x93,0x2C,0xC8,0x09],
|
||||
s vec![0x70,0x81,0xE1,0x75,0x45,0x5F,0x92,0x47,
|
||||
0xB8,0x12,0xB7,0x45,0x83,0xE9,0xE9,0x4F,
|
||||
0x9E,0xA7,0x9B,0xD6,0x40,0xDC,0x96,0x25,
|
||||
0x33,0xB0,0x68,0x07,0x93,0xA3,0x8D,0x53]);
|
||||
// With SHA-384, message = "sample":
|
||||
// k = C345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920
|
||||
// r = B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B
|
||||
// s = 19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B
|
||||
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,
|
||||
0x83,0xE3,0x90,0x68,0xEC,0x56,0x49,0x20],
|
||||
r vec![0xB2,0xDA,0x94,0x5E,0x91,0x85,0x88,0x34,
|
||||
0xFD,0x9B,0xF6,0x16,0xEB,0xAC,0x15,0x1E,
|
||||
0xDB,0xC4,0xB4,0x5D,0x27,0xD0,0xDD,0x4A,
|
||||
0x7F,0x6A,0x22,0x73,0x9F,0x45,0xC0,0x0B],
|
||||
s vec![0x19,0x04,0x8B,0x63,0xD9,0xFD,0x6B,0xCA,
|
||||
0x1D,0x9B,0xAE,0x36,0x64,0xE1,0xBC,0xB9,
|
||||
0x7F,0x72,0x76,0xC3,0x06,0x13,0x09,0x69,
|
||||
0xF6,0x3F,0x38,0xFA,0x83,0x19,0x02,0x1B]);
|
||||
// With SHA-512, message = "sample":
|
||||
// k = 5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC
|
||||
// r = 2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E
|
||||
// s = D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351
|
||||
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,
|
||||
0x95,0xC8,0x9E,0xD0,0x37,0x46,0x68,0xFC],
|
||||
r vec![0x20,0x16,0xED,0x09,0x2D,0xC5,0xFB,0x66,
|
||||
0x9B,0x8E,0xFB,0x3D,0x1F,0x31,0xA9,0x1E,
|
||||
0xEC,0xB1,0x99,0x87,0x9B,0xE0,0xCF,0x78,
|
||||
0xF0,0x2B,0xA0,0x62,0xCB,0x4C,0x94,0x2E],
|
||||
s vec![0xD0,0xC7,0x6F,0x84,0xB5,0xF0,0x91,0xE1,
|
||||
0x41,0x57,0x2A,0x63,0x9A,0x4F,0xB8,0xC2,
|
||||
0x30,0x80,0x7E,0xEA,0x7D,0x55,0xC8,0xA1,
|
||||
0x54,0xA2,0x24,0x40,0x0A,0xFF,0x23,0x51]);
|
||||
// With SHA-1, message = "test":
|
||||
// k = 6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F
|
||||
// r = C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0
|
||||
// s = 414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA
|
||||
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,
|
||||
0x76,0xBE,0x64,0x1C,0xCB,0x24,0xBA,0x4F],
|
||||
r vec![0xC1,0x82,0x70,0xA9,0x3C,0xFC,0x60,0x63,
|
||||
0xF5,0x7A,0x4D,0xFA,0x86,0x02,0x4F,0x70,
|
||||
0x0D,0x98,0x0E,0x4C,0xF4,0xE2,0xCB,0x65,
|
||||
0xA5,0x04,0x39,0x72,0x73,0xD9,0x8E,0xA0],
|
||||
s vec![0x41,0x4F,0x22,0xE5,0xF3,0x1A,0x8B,0x6D,
|
||||
0x33,0x29,0x5C,0x75,0x39,0xC1,0xC1,0xBA,
|
||||
0x3A,0x61,0x60,0xD7,0xD6,0x8D,0x50,0xAC,
|
||||
0x0D,0x3A,0x5B,0xEA,0xC2,0x88,0x4F,0xAA]);
|
||||
// With SHA-224, message = "test":
|
||||
// k = 06BD4C05ED74719106223BE33F2D95DA6B3B541DAD7BFBD7AC508213B6DA6670
|
||||
// r = 272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3
|
||||
// s = E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806
|
||||
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,
|
||||
0xAC,0x50,0x82,0x13,0xB6,0xDA,0x66,0x70],
|
||||
r vec![0x27,0x2A,0xBA,0x31,0x57,0x2F,0x6C,0xC5,
|
||||
0x5E,0x30,0xBF,0x61,0x6B,0x7A,0x26,0x53,
|
||||
0x12,0x01,0x8D,0xD3,0x25,0xBE,0x03,0x1B,
|
||||
0xE0,0xCC,0x82,0xAA,0x17,0x87,0x0E,0xA3],
|
||||
s vec![0xE9,0xCC,0x28,0x6A,0x52,0xCC,0xE2,0x01,
|
||||
0x58,0x67,0x22,0xD3,0x6D,0x1E,0x91,0x7E,
|
||||
0xB9,0x6A,0x4E,0xBD,0xB4,0x79,0x32,0xF9,
|
||||
0x57,0x6A,0xC6,0x45,0xB3,0xA6,0x08,0x06]);
|
||||
// With SHA-256, message = "test":
|
||||
// k = 1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7
|
||||
// r = 8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0
|
||||
// s = 7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E
|
||||
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,
|
||||
0xDF,0xB4,0x47,0x9A,0xAC,0x8D,0xEA,0xD7],
|
||||
r vec![0x81,0x90,0x01,0x2A,0x19,0x69,0xF9,0x95,
|
||||
0x7D,0x56,0xFC,0xCA,0xAD,0x22,0x31,0x86,
|
||||
0xF4,0x23,0x39,0x8D,0x58,0xEF,0x5B,0x3C,
|
||||
0xEF,0xD5,0xA4,0x14,0x6A,0x44,0x76,0xF0],
|
||||
s vec![0x74,0x52,0xA5,0x3F,0x70,0x75,0xD4,0x17,
|
||||
0xB4,0xB0,0x13,0xB2,0x78,0xD1,0xBB,0x8B,
|
||||
0xBD,0x21,0x86,0x3F,0x5E,0x7B,0x1C,0xEE,
|
||||
0x67,0x9C,0xF2,0x18,0x8E,0x1A,0xB1,0x9E]);
|
||||
// With SHA-384, message = "test":
|
||||
// k = 206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C
|
||||
// r = 239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE
|
||||
// s = 6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961
|
||||
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,
|
||||
0x5B,0x64,0xCA,0xD3,0x9C,0xF9,0xF9,0x1C],
|
||||
r vec![0x23,0x9E,0x66,0xDD,0xBE,0x8F,0x8C,0x23,
|
||||
0x0A,0x3D,0x07,0x1D,0x60,0x1B,0x6F,0xFB,
|
||||
0xDF,0xB5,0x90,0x1F,0x94,0xD4,0x44,0xC6,
|
||||
0xAF,0x56,0xF7,0x32,0xBE,0xB9,0x54,0xBE],
|
||||
s vec![0x6B,0xD7,0x37,0x51,0x3D,0x5E,0x72,0xFE,
|
||||
0x85,0xD1,0xC7,0x50,0xE0,0xF7,0x39,0x21,
|
||||
0xFE,0x29,0x9B,0x94,0x5A,0xAD,0x1C,0x80,
|
||||
0x2F,0x15,0xC2,0x6A,0x43,0xD3,0x49,0x61]);
|
||||
// With SHA-512, message = "test":
|
||||
// k = AFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA
|
||||
// r = 89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307
|
||||
// s = C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1
|
||||
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,
|
||||
0xC5,0x5B,0xE1,0x0B,0x56,0x8A,0xA0,0xAA],
|
||||
r vec![0x89,0xEC,0x4B,0xB1,0x40,0x0E,0xCC,0xFF,
|
||||
0x8E,0x7D,0x9A,0xA5,0x15,0xCD,0x1D,0xE7,
|
||||
0x80,0x3F,0x2D,0xAF,0xF0,0x96,0x93,0xEE,
|
||||
0x7F,0xD1,0x35,0x3E,0x90,0xA6,0x83,0x07],
|
||||
s vec![0xC9,0xF0,0xBD,0xAB,0xCC,0x0D,0x88,0x0B,
|
||||
0xB1,0x37,0xA9,0x94,0xCC,0x7F,0x39,0x80,
|
||||
0xCE,0x91,0xCC,0x10,0xFA,0xF5,0x29,0xFC,
|
||||
0x46,0x56,0x5B,0x15,0xCE,0xA8,0x54,0xE1]);
|
||||
}
|
||||
498
src/ecdsa/curve.rs
Normal file
498
src/ecdsa/curve.rs
Normal file
@@ -0,0 +1,498 @@
|
||||
use cryptonum::signed::{I192,I256,I384,I576};
|
||||
use cryptonum::unsigned::{Decoder};
|
||||
use cryptonum::unsigned::{U192,U256,U384,U576};
|
||||
use ecdsa::point::Point;
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// Elliptic curves must implement this trait in order to work with the rest
|
||||
/// of the ECDSA system. I've included instances for the core NIST curves
|
||||
/// used in most systems, but this could be extended without issues.
|
||||
/// (Eventually the curves defined here should actually be extended in
|
||||
/// interesting ways to make the math faster, but we haven't gotten there
|
||||
/// yet.)
|
||||
#[allow(non_snake_case)]
|
||||
pub trait EllipticCurve {
|
||||
/// The unsigned numeric type that fits constants for this curve.
|
||||
type Unsigned : Clone;
|
||||
/// The signed numeric type that fits constants for this curve.
|
||||
type Signed : Clone + Debug + PartialEq;
|
||||
/// The type of a point on the curve
|
||||
type Point;
|
||||
|
||||
/// The size of the curve in bits.
|
||||
fn size() -> usize;
|
||||
/// The `p` value for the curve.
|
||||
fn p() -> Self::Unsigned;
|
||||
/// The `p` value for the curve.
|
||||
fn n() -> Self::Unsigned;
|
||||
/// The seed value for the curve.
|
||||
fn SEED() -> Self::Unsigned;
|
||||
/// The `c` value for the curve.
|
||||
fn c() -> Self::Unsigned;
|
||||
/// The `a` value for the curve.
|
||||
fn a() -> Self::Unsigned;
|
||||
/// The `b` value for the curve.
|
||||
fn b() -> Self::Unsigned;
|
||||
/// The `x` coordinate of the base point for the curve.
|
||||
fn Gx() -> Self::Signed;
|
||||
/// The `y` coordinate of the base point for the curve.
|
||||
fn Gy() -> Self::Signed;
|
||||
/// Generate a point for the curve given the provided values.
|
||||
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point;
|
||||
}
|
||||
|
||||
/// NIST curve P-192 (FIPS 186-4, page 101-102), a.k.a. secp192r1 from RFC5480
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub struct P192 {}
|
||||
|
||||
impl EllipticCurve for P192 {
|
||||
type Unsigned = U192;
|
||||
type Signed = I192;
|
||||
type Point = Point<P192>;
|
||||
|
||||
fn size() -> usize {
|
||||
192
|
||||
}
|
||||
|
||||
fn p() -> U192 {
|
||||
U192::from([0xffffffffffffffff, 0xfffffffffffffffe, 0xffffffffffffffff])
|
||||
}
|
||||
|
||||
fn n() -> U192 {
|
||||
U192::from([0x146bc9b1b4d22831, 0xffffffff99def836, 0xffffffffffffffff])
|
||||
}
|
||||
|
||||
fn SEED() -> U192 {
|
||||
U192::from([0xd38020eae12196d5, 0xc8422f64ed579528, 0x3045ae6f])
|
||||
}
|
||||
|
||||
fn c() -> U192 {
|
||||
U192::from([0x5f3d6fe2c745de65, 0x542dcd5fb078b6ef, 0x3099d2bbbfcb2538])
|
||||
}
|
||||
|
||||
fn a() -> U192 {
|
||||
U192::from([0xfffffffffffffffc, 0xfffffffffffffffe, 0xffffffffffffffff])
|
||||
}
|
||||
|
||||
fn b() -> U192 {
|
||||
U192::from([0xfeb8deecc146b9b1, 0x0fa7e9ab72243049, 0x64210519e59c80e7])
|
||||
}
|
||||
|
||||
fn Gx() -> I192 {
|
||||
I192::from(U192::from([0xf4ff0afd82ff1012, 0x7cbf20eb43a18800, 0x188da80eb03090f6]))
|
||||
}
|
||||
|
||||
fn Gy() -> I192 {
|
||||
I192::from(U192::from([0x73f977a11e794811, 0x631011ed6b24cdd5, 0x07192b95ffc8da78]))
|
||||
}
|
||||
|
||||
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
|
||||
Point::<P192>{ x: I192::from(x), y: I192::from(y) }
|
||||
}
|
||||
}
|
||||
|
||||
/// NIST curve P-224 (FIPS 186-4, page 102), a.k.a. secp224r1 from RFC5480
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub struct P224 {}
|
||||
|
||||
impl EllipticCurve for P224 {
|
||||
type Unsigned = U256;
|
||||
type Signed = I256;
|
||||
type Point = Point<P224>;
|
||||
|
||||
fn size() -> usize {
|
||||
224
|
||||
}
|
||||
|
||||
fn p() -> U256 {
|
||||
U256::from_bytes(&[
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01
|
||||
])
|
||||
}
|
||||
|
||||
fn n() -> U256 {
|
||||
U256::from_bytes(&[
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
|
||||
0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
|
||||
0x5c, 0x5c, 0x2a, 0x3d
|
||||
])
|
||||
}
|
||||
|
||||
fn SEED() -> U256 {
|
||||
U256::from_bytes(&[
|
||||
0xbd, 0x71, 0x34, 0x47, 0x99, 0xd5, 0xc7, 0xfc,
|
||||
0xdc, 0x45, 0xb5, 0x9f, 0xa3, 0xb9, 0xab, 0x8f,
|
||||
0x6a, 0x94, 0x8b, 0xc5
|
||||
])
|
||||
}
|
||||
|
||||
fn c() -> U256 {
|
||||
U256::from_bytes(&[
|
||||
0x5b, 0x05, 0x6c, 0x7e, 0x11, 0xdd, 0x68, 0xf4,
|
||||
0x04, 0x69, 0xee, 0x7f, 0x3c, 0x7a, 0x7d, 0x74,
|
||||
0xf7, 0xd1, 0x21, 0x11, 0x65, 0x06, 0xd0, 0x31,
|
||||
0x21, 0x82, 0x91, 0xfb
|
||||
])
|
||||
}
|
||||
|
||||
fn a() -> U256 {
|
||||
U256::from_bytes(&[
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfe
|
||||
])
|
||||
}
|
||||
|
||||
fn b() -> U256 {
|
||||
U256::from_bytes(&[
|
||||
0xb4, 0x05, 0x0a, 0x85, 0x0c, 0x04, 0xb3, 0xab,
|
||||
0xf5, 0x41, 0x32, 0x56, 0x50, 0x44, 0xb0, 0xb7,
|
||||
0xd7, 0xbf, 0xd8, 0xba, 0x27, 0x0b, 0x39, 0x43,
|
||||
0x23, 0x55, 0xff, 0xb4
|
||||
])
|
||||
}
|
||||
|
||||
fn Gx() -> I256 {
|
||||
I256::from(U256::from_bytes(&[
|
||||
0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f,
|
||||
0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3,
|
||||
0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6,
|
||||
0x11, 0x5c, 0x1d, 0x21
|
||||
]))
|
||||
}
|
||||
|
||||
fn Gy() -> I256 {
|
||||
I256::from(U256::from_bytes(&[
|
||||
0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb,
|
||||
0x4c, 0x22, 0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0,
|
||||
0x5a, 0x07, 0x47, 0x64, 0x44, 0xd5, 0x81, 0x99,
|
||||
0x85, 0x00, 0x7e, 0x34
|
||||
]))
|
||||
}
|
||||
|
||||
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
|
||||
Point::<P224>{ x: I256::from(x), y: I256::from(y) }
|
||||
}
|
||||
}
|
||||
|
||||
/// NIST curve P-256 (FIPS 186-4, page 102-103), a.k.a. secp256r1 from RFC5480
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub struct P256 {}
|
||||
|
||||
impl EllipticCurve for P256 {
|
||||
type Signed = I256;
|
||||
type Unsigned = U256;
|
||||
type Point = Point<P256>;
|
||||
|
||||
fn size() -> usize {
|
||||
256
|
||||
}
|
||||
|
||||
fn p() -> U256 {
|
||||
U256::from_bytes(&[
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
])
|
||||
}
|
||||
|
||||
fn n() -> U256 {
|
||||
U256::from_bytes(&[
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84,
|
||||
0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51
|
||||
])
|
||||
}
|
||||
|
||||
fn SEED() -> U256 {
|
||||
U256::from_bytes(&[
|
||||
0xc4, 0x9d, 0x36, 0x08, 0x86, 0xe7, 0x04, 0x93,
|
||||
0x6a, 0x66, 0x78, 0xe1, 0x13, 0x9d, 0x26, 0xb7,
|
||||
0x81, 0x9f, 0x7e, 0x90
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
fn c() -> U256 {
|
||||
U256::from_bytes(&[
|
||||
0x7e, 0xfb, 0xa1, 0x66, 0x29, 0x85, 0xbe, 0x94,
|
||||
0x03, 0xcb, 0x05, 0x5c, 0x75, 0xd4, 0xf7, 0xe0,
|
||||
0xce, 0x8d, 0x84, 0xa9, 0xc5, 0x11, 0x4a, 0xbc,
|
||||
0xaf, 0x31, 0x77, 0x68, 0x01, 0x04, 0xfa, 0x0d
|
||||
])
|
||||
}
|
||||
|
||||
fn a() -> U256 {
|
||||
U256::from_bytes(&[
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc
|
||||
])
|
||||
}
|
||||
|
||||
fn b() -> U256 {
|
||||
U256::from_bytes(&[
|
||||
0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7,
|
||||
0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc,
|
||||
0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53, 0xb0, 0xf6,
|
||||
0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b
|
||||
])
|
||||
}
|
||||
|
||||
fn Gx() -> I256 {
|
||||
I256::from(U256::from_bytes(&[
|
||||
0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47,
|
||||
0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2,
|
||||
0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0,
|
||||
0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96
|
||||
]))
|
||||
}
|
||||
|
||||
fn Gy() -> I256 {
|
||||
I256::from(U256::from_bytes(&[
|
||||
0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b,
|
||||
0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16,
|
||||
0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce,
|
||||
0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5
|
||||
]))
|
||||
}
|
||||
|
||||
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
|
||||
Point::<P256>{ x: I256::from(x), y: I256::from(y) }
|
||||
}
|
||||
}
|
||||
|
||||
/// NIST curve P-384 (FIPS 186-4, page 103-104), a.k.a. secp384r1 from RFC5480
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub struct P384 {}
|
||||
|
||||
impl EllipticCurve for P384 {
|
||||
type Signed = I384;
|
||||
type Unsigned = U384;
|
||||
type Point = Point<P384>;
|
||||
|
||||
fn size() -> usize {
|
||||
384
|
||||
}
|
||||
|
||||
fn p() -> U384 {
|
||||
U384::from_bytes(&[
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
|
||||
])
|
||||
}
|
||||
|
||||
fn n() -> U384 {
|
||||
U384::from_bytes(&[
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf,
|
||||
0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a,
|
||||
0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x73
|
||||
])
|
||||
}
|
||||
|
||||
fn SEED() -> U384 {
|
||||
U384::from_bytes(&[
|
||||
0xa3, 0x35, 0x92, 0x6a, 0xa3, 0x19, 0xa2, 0x7a,
|
||||
0x1d, 0x00, 0x89, 0x6a, 0x67, 0x73, 0xa4, 0x82,
|
||||
0x7a, 0xcd, 0xac, 0x73
|
||||
])
|
||||
}
|
||||
|
||||
fn c() -> U384 {
|
||||
U384::from_bytes(&[
|
||||
0x79, 0xd1, 0xe6, 0x55, 0xf8, 0x68, 0xf0, 0x2f,
|
||||
0xff, 0x48, 0xdc, 0xde, 0xe1, 0x41, 0x51, 0xdd,
|
||||
0xb8, 0x06, 0x43, 0xc1, 0x40, 0x6d, 0x0c, 0xa1,
|
||||
0x0d, 0xfe, 0x6f, 0xc5, 0x20, 0x09, 0x54, 0x0a,
|
||||
0x49, 0x5e, 0x80, 0x42, 0xea, 0x5f, 0x74, 0x4f,
|
||||
0x6e, 0x18, 0x46, 0x67, 0xcc, 0x72, 0x24, 0x83
|
||||
])
|
||||
}
|
||||
|
||||
fn a() -> U384 {
|
||||
U384::from_bytes(&[
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfc
|
||||
])
|
||||
}
|
||||
|
||||
fn b() -> U384 {
|
||||
U384::from_bytes(&[
|
||||
0xb3, 0x31, 0x2f, 0xa7, 0xe2, 0x3e, 0xe7, 0xe4,
|
||||
0x98, 0x8e, 0x05, 0x6b, 0xe3, 0xf8, 0x2d, 0x19,
|
||||
0x18, 0x1d, 0x9c, 0x6e, 0xfe, 0x81, 0x41, 0x12,
|
||||
0x03, 0x14, 0x08, 0x8f, 0x50, 0x13, 0x87, 0x5a,
|
||||
0xc6, 0x56, 0x39, 0x8d, 0x8a, 0x2e, 0xd1, 0x9d,
|
||||
0x2a, 0x85, 0xc8, 0xed, 0xd3, 0xec, 0x2a, 0xef
|
||||
])
|
||||
}
|
||||
|
||||
fn Gx() -> I384 {
|
||||
I384::from(U384::from_bytes(&[
|
||||
0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37,
|
||||
0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74,
|
||||
0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98,
|
||||
0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38,
|
||||
0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c,
|
||||
0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7
|
||||
]))
|
||||
}
|
||||
|
||||
fn Gy() -> I384 {
|
||||
I384::from(U384::from_bytes(&[
|
||||
0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f,
|
||||
0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29,
|
||||
0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c,
|
||||
0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0,
|
||||
0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d,
|
||||
0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f
|
||||
]))
|
||||
}
|
||||
|
||||
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
|
||||
Point::<P384>{ x: I384::from(x), y: I384::from(y) }
|
||||
}
|
||||
}
|
||||
|
||||
/// NIST curve P-521 (FIPS 186-4, page 104), a.k.a. secp521r1 from RFC5480
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub struct P521 {}
|
||||
|
||||
impl EllipticCurve for P521 {
|
||||
type Signed = I576;
|
||||
type Unsigned = U576;
|
||||
type Point = Point<P521>;
|
||||
|
||||
fn size() -> usize {
|
||||
521
|
||||
}
|
||||
|
||||
fn p() -> U576 {
|
||||
U576::from_bytes(&[
|
||||
0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff
|
||||
])
|
||||
}
|
||||
|
||||
fn n() -> U576 {
|
||||
U576::from_bytes(&[
|
||||
0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfa, 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f,
|
||||
0x96, 0x6b, 0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09,
|
||||
0xa5, 0xd0, 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c,
|
||||
0x47, 0xae, 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38,
|
||||
0x64, 0x09
|
||||
])
|
||||
}
|
||||
|
||||
fn SEED() -> U576 {
|
||||
U576::from_bytes(&[
|
||||
0xd0, 0x9e, 0x88, 0x00, 0x29, 0x1c, 0xb8, 0x53,
|
||||
0x96, 0xcc, 0x67, 0x17, 0x39, 0x32, 0x84, 0xaa,
|
||||
0xa0, 0xda, 0x64, 0xba
|
||||
])
|
||||
}
|
||||
|
||||
fn c() -> U576 {
|
||||
U576::from_bytes(&[
|
||||
0xb4, 0x8b, 0xfa, 0x5f, 0x42, 0x0a, 0x34, 0x94,
|
||||
0x95, 0x39, 0xd2, 0xbd, 0xfc, 0x26, 0x4e, 0xee,
|
||||
0xeb, 0x07, 0x76, 0x88, 0xe4, 0x4f, 0xbf, 0x0a,
|
||||
0xd8, 0xf6, 0xd0, 0xed, 0xb3, 0x7b, 0xd6, 0xb5,
|
||||
0x33, 0x28, 0x10, 0x00, 0x51, 0x8e, 0x19, 0xf1,
|
||||
0xb9, 0xff, 0xbe, 0x0f, 0xe9, 0xed, 0x8a, 0x3c,
|
||||
0x22, 0x00, 0xb8, 0xf8, 0x75, 0xe5, 0x23, 0x86,
|
||||
0x8c, 0x70, 0xc1, 0xe5, 0xbf, 0x55, 0xba, 0xd6,
|
||||
0x37
|
||||
])
|
||||
}
|
||||
|
||||
fn a() -> U576 {
|
||||
U576::from_bytes(&[
|
||||
0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfc
|
||||
])
|
||||
}
|
||||
|
||||
fn b() -> U576 {
|
||||
U576::from_bytes(&[
|
||||
0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c, 0x9a,
|
||||
0x1f, 0x92, 0x9a, 0x21, 0xa0, 0xb6, 0x85, 0x40,
|
||||
0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3, 0x15,
|
||||
0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1, 0x09,
|
||||
0xe1, 0x56, 0x19, 0x39, 0x51, 0xec, 0x7e, 0x93,
|
||||
0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1, 0xbf,
|
||||
0x07, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c, 0x34,
|
||||
0xf1, 0xef, 0x45, 0x1f, 0xd4, 0x6b, 0x50, 0x3f,
|
||||
0x00
|
||||
])
|
||||
}
|
||||
|
||||
fn Gx() -> I576 {
|
||||
I576::from(U576::from_bytes(&[
|
||||
0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04,
|
||||
0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95,
|
||||
0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f,
|
||||
0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d,
|
||||
0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7,
|
||||
0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff,
|
||||
0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a,
|
||||
0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5,
|
||||
0xbd, 0x66
|
||||
]))
|
||||
}
|
||||
|
||||
fn Gy() -> I576 {
|
||||
I576::from(U576::from_bytes(&[
|
||||
0x01, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b,
|
||||
0xc0, 0x04, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d,
|
||||
0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b,
|
||||
0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e,
|
||||
0x66, 0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4,
|
||||
0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad,
|
||||
0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72,
|
||||
0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1,
|
||||
0x66, 0x50
|
||||
]))
|
||||
}
|
||||
|
||||
fn new_point(x: Self::Unsigned, y: Self::Unsigned) -> Self::Point {
|
||||
Point::<P521>{ x: I576::from(x), y: I576::from(y) }
|
||||
}
|
||||
}
|
||||
121
src/ecdsa/mod.rs
Normal file
121
src/ecdsa/mod.rs
Normal file
@@ -0,0 +1,121 @@
|
||||
//! The generation and use of ECDSA keys is pretty straightforward, compared
|
||||
//! to DSA and RSA. You should be able to find what you want to do in the
|
||||
//! following code snippet, as an example:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use simple_crypto::ecdsa::{ECDSAKeyPair,P384};
|
||||
//! use simple_crypto::sha::SHA256;
|
||||
//!
|
||||
//! // Generate a new ECDSA key for curve P384 (this is a good choice, by
|
||||
//! // the way, if you're wondering which curve to use).
|
||||
//! let mut rng = rand::rngs::OsRng::new().unwrap();
|
||||
//! let kp = ECDSAKeyPair::<P384>::generate(&mut rng);
|
||||
//!
|
||||
//! // Now that you have this key pair, you can sign and verify messages
|
||||
//! // using it. For example, to sign the vector [0,1,2,3,4] with SHA256
|
||||
//! // and then verify that signature, we would write:
|
||||
//! let msg = vec![0,1,2,3,4];
|
||||
//! let sig = kp.private.sign::<SHA256>(&msg);
|
||||
//! assert!( kp.public.verify::<SHA256>(&msg, &sig) );
|
||||
//! ```
|
||||
|
||||
mod curve;
|
||||
pub(crate) mod point;
|
||||
mod private;
|
||||
mod public;
|
||||
|
||||
use cryptonum::signed::{I192,I256,I384,I576};
|
||||
use cryptonum::unsigned::{CryptoNum,Decoder};
|
||||
use cryptonum::unsigned::{U192,U256,U384,U576};
|
||||
use rand::Rng;
|
||||
use rand::distributions::Standard;
|
||||
pub use self::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
||||
use self::point::{ECCPoint,Point};
|
||||
pub use self::private::{ECDSAPrivate,ECCPrivateKey};
|
||||
pub use self::public::{ECDSAPublic,ECCPublicKey};
|
||||
pub use self::public::{ECDSADecodeErr,ECDSAEncodeErr};
|
||||
use super::KeyPair;
|
||||
|
||||
/// An ECDSA key pair for the given curve.
|
||||
pub struct ECDSAKeyPair<Curve: EllipticCurve> {
|
||||
pub public: ECCPublicKey<Curve>,
|
||||
pub private: ECCPrivateKey<Curve>
|
||||
}
|
||||
|
||||
/// A generic ECDSA key pair that implements one of our known curves, for cases
|
||||
/// when you're not sure which one you're going to have.
|
||||
pub enum ECDSAPair {
|
||||
P192(ECCPublicKey<P192>,ECCPrivateKey<P192>),
|
||||
P224(ECCPublicKey<P224>,ECCPrivateKey<P224>),
|
||||
P256(ECCPublicKey<P256>,ECCPrivateKey<P256>),
|
||||
P384(ECCPublicKey<P384>,ECCPrivateKey<P384>),
|
||||
P521(ECCPublicKey<P521>,ECCPrivateKey<P521>),
|
||||
}
|
||||
|
||||
impl KeyPair for ECDSAPair {
|
||||
type Public = ECDSAPublic;
|
||||
type Private = ECDSAPrivate;
|
||||
|
||||
fn new(pu: ECDSAPublic, pr: ECDSAPrivate) -> ECDSAPair
|
||||
{
|
||||
match (pu, pr) {
|
||||
(ECDSAPublic::P192(pbl),ECDSAPrivate::P192(prv)) => ECDSAPair::P192(pbl,prv),
|
||||
(ECDSAPublic::P224(pbl),ECDSAPrivate::P224(prv)) => ECDSAPair::P224(pbl,prv),
|
||||
(ECDSAPublic::P256(pbl),ECDSAPrivate::P256(prv)) => ECDSAPair::P256(pbl,prv),
|
||||
(ECDSAPublic::P384(pbl),ECDSAPrivate::P384(prv)) => ECDSAPair::P384(pbl,prv),
|
||||
(ECDSAPublic::P521(pbl),ECDSAPrivate::P521(prv)) => ECDSAPair::P521(pbl,prv),
|
||||
_ =>
|
||||
panic!("Non-matching public/private pairs in ECDSAPair::new()")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_impl {
|
||||
($curve: ident, $un: ident, $si: ident) => {
|
||||
impl KeyPair for ECDSAKeyPair<$curve> {
|
||||
type Public = ECCPublicKey<$curve>;
|
||||
type Private = ECCPrivateKey<$curve>;
|
||||
|
||||
fn new(public: ECCPublicKey<$curve>, private: ECCPrivateKey<$curve>) -> ECDSAKeyPair<$curve>
|
||||
{
|
||||
ECDSAKeyPair{ public, private }
|
||||
}
|
||||
}
|
||||
|
||||
impl ECDSAKeyPair<$curve> {
|
||||
/// Generate a fresh ECDSA key pair for this curve, given the
|
||||
/// provided random number generator. THIS MUST BE A CRYPTO
|
||||
/// STRONG RNG. If it's not, then you're going to generate weak
|
||||
/// keys and the crypto gremlins will get you.
|
||||
pub fn generate<G: Rng>(rng: &mut G) -> ECDSAKeyPair<$curve>
|
||||
{
|
||||
loop {
|
||||
let size = ($curve::size() + 7) / 8;
|
||||
let random_bytes: Vec<u8> = rng.sample_iter(&Standard).take(size).collect();
|
||||
let proposed_d = $un::from_bytes(&random_bytes);
|
||||
|
||||
if proposed_d.is_zero() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if proposed_d >= $curve::n() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let d = $si::from(&proposed_d);
|
||||
let public_point = Point::<$curve>::default().scale(&d);
|
||||
let public = ECCPublicKey::<$curve>::new(public_point);
|
||||
let private = ECCPrivateKey::<$curve>::new(proposed_d);
|
||||
|
||||
return ECDSAKeyPair{ public, private };
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
generate_impl!(P192, U192, I192);
|
||||
generate_impl!(P224, U256, I256);
|
||||
generate_impl!(P256, U256, I256);
|
||||
generate_impl!(P384, U384, I384);
|
||||
generate_impl!(P521, U576, I576);
|
||||
329
src/ecdsa/point.rs
Normal file
329
src/ecdsa/point.rs
Normal file
@@ -0,0 +1,329 @@
|
||||
use cryptonum::signed::*;
|
||||
use cryptonum::unsigned::*;
|
||||
use ecdsa::curve::*;
|
||||
|
||||
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(Debug,PartialEq)]
|
||||
pub struct Point<T: EllipticCurve>
|
||||
{
|
||||
pub x: T::Signed,
|
||||
pub y: T::Signed
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ECCPoint for Point<$curve> {
|
||||
type Curve = $curve;
|
||||
type Scale = $base;
|
||||
|
||||
fn default() -> Point<$curve>
|
||||
{
|
||||
Point {
|
||||
x: $curve::Gx(),
|
||||
y: $curve::Gy()
|
||||
}
|
||||
}
|
||||
|
||||
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 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;
|
||||
xr %= &bigp;
|
||||
let x = $base::from(xr);
|
||||
// yr = lambda (xp - xr) - yp
|
||||
let xdiff = $base::from(&self.x - &x);
|
||||
let mut yr = &lambda * &xdiff;
|
||||
yr -= $s2::from(&self.y);
|
||||
let y = $base::from(&yr % &bigp);
|
||||
//
|
||||
Point{ x, y }
|
||||
}
|
||||
|
||||
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 -= $s2::from(&self.x);
|
||||
xr -= $s2::from(&other.x);
|
||||
let bigsignedp = $s2::from(&signedp);
|
||||
xr %= &bigsignedp;
|
||||
let mut yr = $s2::from(&self.x);
|
||||
yr -= &xr;
|
||||
yr *= $s2::from(&s);
|
||||
yr -= $s2::from(&self.y);
|
||||
yr %= &bigsignedp;
|
||||
Point{ x: $base::from(xr), y: $base::from(yr) }
|
||||
}
|
||||
|
||||
fn scale(&self, d: &$base) -> Point<$curve>
|
||||
{
|
||||
assert!(!d.is_zero());
|
||||
#[allow(non_snake_case)]
|
||||
let mut Q: Point<$curve> = self.clone();
|
||||
let mut bit = ($base::bit_length() - 1) as isize;
|
||||
|
||||
// Skip down until we hit a set bit
|
||||
while !d.testbit(bit as usize) {
|
||||
bit -= 1;
|
||||
}
|
||||
// drop one
|
||||
bit -= 1;
|
||||
// do the double and add algorithm
|
||||
while bit >= 0 {
|
||||
Q = Q.double();
|
||||
|
||||
let test = d.testbit(bit as usize);
|
||||
if test {
|
||||
Q = Q.add(&self);
|
||||
}
|
||||
|
||||
bit -= 1;
|
||||
}
|
||||
|
||||
if d.is_negative() {
|
||||
Q.negate()
|
||||
} else {
|
||||
Q
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
point_impl!(P192, I192, I384, U384, I448, U448);
|
||||
point_impl!(P224, I256, I512, U512, I576, U576);
|
||||
point_impl!(P256, I256, I512, U512, I576, U576);
|
||||
point_impl!(P384, I384, I768, U768, I832, U832);
|
||||
point_impl!(P521, I576, I1152, U1152, I1216, U1216);
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! negate_test_body
|
||||
{
|
||||
($curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
|
||||
let fname = build_test_path("ecc/negate",stringify!($curve));
|
||||
run_test(fname.to_string(), 4, |case| {
|
||||
let (negx, xbytes) = case.get("x").unwrap();
|
||||
let (negy, ybytes) = case.get("y").unwrap();
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
|
||||
let x = $stype::new(*negx, $utype::from_bytes(xbytes));
|
||||
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
|
||||
let a = $stype::new(*nega, $utype::from_bytes(abytes));
|
||||
let b = $stype::new(*negb, $utype::from_bytes(bbytes));
|
||||
let point = Point::<$curve>{ x, y };
|
||||
let dbl = point.negate();
|
||||
assert_eq!(a, dbl.x, "x equivalence");
|
||||
assert_eq!(b, dbl.y, "y equivalence");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! double_test_body
|
||||
{
|
||||
($curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
|
||||
let fname = build_test_path("ecc/double",stringify!($curve));
|
||||
run_test(fname.to_string(), 4, |case| {
|
||||
let (negx, xbytes) = case.get("x").unwrap();
|
||||
let (negy, ybytes) = case.get("y").unwrap();
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
|
||||
let x = $stype::new(*negx, $utype::from_bytes(xbytes));
|
||||
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
|
||||
let a = $stype::new(*nega, $utype::from_bytes(abytes));
|
||||
let b = $stype::new(*negb, $utype::from_bytes(bbytes));
|
||||
let point = Point::<$curve>{ x, y };
|
||||
let dbl = point.double();
|
||||
assert_eq!(a, dbl.x, "x equivalence");
|
||||
assert_eq!(b, dbl.y, "y equivalence");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! add_test_body
|
||||
{
|
||||
($curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
|
||||
let fname = build_test_path("ecc/add",stringify!($curve));
|
||||
run_test(fname.to_string(), 6, move |case| {
|
||||
let (negx, xbytes) = case.get("x").unwrap();
|
||||
let (negy, ybytes) = case.get("y").unwrap();
|
||||
let (negu, ubytes) = case.get("u").unwrap();
|
||||
let (negv, vbytes) = case.get("v").unwrap();
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
|
||||
let x = $stype::new(*negx, $utype::from_bytes(xbytes));
|
||||
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
|
||||
let u = $stype::new(*negu, $utype::from_bytes(ubytes));
|
||||
let v = $stype::new(*negv, $utype::from_bytes(vbytes));
|
||||
let a = $stype::new(*nega, $utype::from_bytes(abytes));
|
||||
let b = $stype::new(*negb, $utype::from_bytes(bbytes));
|
||||
let point1 = Point::<$curve>{ x: x, y: y };
|
||||
let point2 = Point::<$curve>{ x: u, y: v };
|
||||
let res = point1.add(&point2);
|
||||
assert_eq!(a, res.x, "x equivalence");
|
||||
assert_eq!(b, res.y, "y equivalence");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! scale_test_body
|
||||
{
|
||||
($curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
|
||||
let fname = build_test_path("ecc/scale",stringify!($curve));
|
||||
run_test(fname.to_string(), 5, |case| {
|
||||
let (negx, xbytes) = case.get("x").unwrap();
|
||||
let (negy, ybytes) = case.get("y").unwrap();
|
||||
let (negk, kbytes) = case.get("k").unwrap();
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
|
||||
let x = $stype::new(*negx, $utype::from_bytes(xbytes));
|
||||
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
|
||||
let k = $stype::new(*negk, $utype::from_bytes(kbytes));
|
||||
let a = $stype::new(*nega, $utype::from_bytes(abytes));
|
||||
let b = $stype::new(*negb, $utype::from_bytes(bbytes));
|
||||
let point = Point::<$curve>{ x: x, y: y };
|
||||
let res = point.scale(&k);
|
||||
assert_eq!(a, res.x, "x equivalence");
|
||||
assert_eq!(b, res.y, "y equivalence");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! add_scale2_test_body
|
||||
{
|
||||
($curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
|
||||
let fname = build_test_path("ecc/add_scale2",stringify!($curve));
|
||||
run_test(fname.to_string(), 8, |case| {
|
||||
let (negx, xbytes) = case.get("x").unwrap();
|
||||
let (negy, ybytes) = case.get("y").unwrap();
|
||||
let (negp, pbytes) = case.get("p").unwrap();
|
||||
let (negq, qbytes) = case.get("q").unwrap();
|
||||
let (negn, nbytes) = case.get("n").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negr, rbytes) = case.get("r").unwrap();
|
||||
let (negs, sbytes) = case.get("s").unwrap();
|
||||
|
||||
let x = $stype::new(*negx, $utype::from_bytes(xbytes));
|
||||
let y = $stype::new(*negy, $utype::from_bytes(ybytes));
|
||||
let p = $stype::new(*negp, $utype::from_bytes(pbytes));
|
||||
let q = $stype::new(*negq, $utype::from_bytes(qbytes));
|
||||
let n = $stype::new(*negn, $utype::from_bytes(nbytes));
|
||||
let m = $stype::new(*negm, $utype::from_bytes(mbytes));
|
||||
let r = $stype::new(*negr, $utype::from_bytes(rbytes));
|
||||
let s = $stype::new(*negs, $utype::from_bytes(sbytes));
|
||||
let p1 = Point::<$curve>{ x: x, y: y };
|
||||
let p2 = Point::<$curve>{ x: p, y: q };
|
||||
let res = Point::<$curve>::double_scalar_mult(&n, &p1, &m, &p2);
|
||||
assert_eq!(r, res.x, "x equivalence");
|
||||
assert_eq!(s, res.y, "y equivalence");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! point_tests
|
||||
{
|
||||
($curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
|
||||
#[cfg(test)]
|
||||
mod $lcurve {
|
||||
use super::*;
|
||||
use testing::*;
|
||||
|
||||
#[test]
|
||||
fn negate() { negate_test_body!($curve, $lcurve, $stype, $utype); }
|
||||
#[test]
|
||||
fn double() { double_test_body!($curve, $lcurve, $stype, $utype); }
|
||||
#[test]
|
||||
fn add() { add_test_body!($curve, $lcurve, $stype, $utype); }
|
||||
#[test]
|
||||
fn scale() { scale_test_body!($curve, $lcurve, $stype, $utype); }
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn add_scale2() { add_scale2_test_body!($curve, $lcurve, $stype, $utype); }
|
||||
}
|
||||
};
|
||||
(ignore_expensive $curve: ident, $lcurve: ident, $stype: ident, $utype: ident) => {
|
||||
#[cfg(test)]
|
||||
mod $lcurve {
|
||||
use super::*;
|
||||
use testing::*;
|
||||
|
||||
#[test]
|
||||
fn negate() { negate_test_body!($curve, $lcurve, $stype, $utype); }
|
||||
#[test]
|
||||
fn double() { double_test_body!($curve, $lcurve, $stype, $utype); }
|
||||
#[test]
|
||||
fn add() { add_test_body!($curve, $lcurve, $stype, $utype); }
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn scale() { scale_test_body!($curve, $lcurve, $stype, $utype); }
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn add_scale2() { add_scale2_test_body!($curve, $lcurve, $stype, $utype); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
179
src/ecdsa/private.rs
Normal file
179
src/ecdsa/private.rs
Normal file
@@ -0,0 +1,179 @@
|
||||
use cryptonum::signed::*;
|
||||
use cryptonum::unsigned::*;
|
||||
use dsa::rfc6979::{DSASignature,KIterator,bits2int};
|
||||
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
||||
use ecdsa::point::{ECCPoint,Point};
|
||||
use sha::Hash;
|
||||
use std::fmt;
|
||||
|
||||
/// A private key for the given curve.
|
||||
#[derive(PartialEq)]
|
||||
pub struct ECCPrivateKey<Curve: EllipticCurve> {
|
||||
pub(crate) d: Curve::Unsigned
|
||||
}
|
||||
|
||||
impl<Curve: EllipticCurve> fmt::Debug for ECCPrivateKey<Curve> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error>
|
||||
{
|
||||
f.write_str("<ECCPrivateKey>")
|
||||
}
|
||||
}
|
||||
|
||||
/// A generic private key.
|
||||
pub enum ECDSAPrivate {
|
||||
P192(ECCPrivateKey<P192>),
|
||||
P224(ECCPrivateKey<P224>),
|
||||
P256(ECCPrivateKey<P256>),
|
||||
P384(ECCPrivateKey<P384>),
|
||||
P521(ECCPrivateKey<P521>),
|
||||
}
|
||||
|
||||
macro_rules! generate_privates
|
||||
{
|
||||
($curve: ident, $base: ident, $sig: ident, $dbl: ident, $quad: ident) => {
|
||||
impl ECCPrivateKey<$curve>
|
||||
{
|
||||
/// Generate a new private key using the given private scalar.
|
||||
pub fn new(d: $base) -> ECCPrivateKey<$curve>
|
||||
{
|
||||
ECCPrivateKey{ d }
|
||||
}
|
||||
|
||||
/// Sign the given message with the current key, using the hash provided
|
||||
/// in the type.
|
||||
pub fn sign<H: Hash + Clone>(&self, m: &[u8]) -> DSASignature<$base>
|
||||
{
|
||||
// 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 = <H>::hash(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::<H,$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 % ∋
|
||||
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().");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generate_privates!(P192, U192, I192, U384, U768);
|
||||
generate_privates!(P224, U256, I256, U512, U1024);
|
||||
generate_privates!(P256, U256, I256, U512, U1024);
|
||||
generate_privates!(P384, U384, I384, U768, U1536);
|
||||
generate_privates!(P521, U576, I576, U1152, U2304);
|
||||
|
||||
/************* TESTING ********************************************************/
|
||||
|
||||
#[cfg(test)]
|
||||
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||
#[cfg(test)]
|
||||
use testing::*;
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! sign_test_body
|
||||
{
|
||||
($name: ident, $curve: ident, $base: ident) => {
|
||||
let fname = build_test_path("ecc/sign",stringify!($curve));
|
||||
run_test(fname.to_string(), 9, |case| {
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
let (negk, _bytes) = case.get("k").unwrap();
|
||||
let (negx, xbytes) = case.get("x").unwrap();
|
||||
let (negy, ybytes) = case.get("y").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negh, hbytes) = case.get("h").unwrap();
|
||||
let (negr, rbytes) = case.get("r").unwrap();
|
||||
let (negs, sbytes) = case.get("s").unwrap();
|
||||
|
||||
assert!(!negd && !negk && !negx && !negy &&
|
||||
!negm && !negh && !negr && !negs);
|
||||
let d = $base::from_bytes(dbytes);
|
||||
let _ = $base::from_bytes(xbytes);
|
||||
let _ = $base::from_bytes(ybytes);
|
||||
let h = $base::from_bytes(hbytes);
|
||||
let r = $base::from_bytes(rbytes);
|
||||
let s = $base::from_bytes(sbytes);
|
||||
|
||||
let private = ECCPrivateKey::<$curve>::new(d);
|
||||
let sig = match usize::from(h) {
|
||||
224 => private.sign::<SHA224>(mbytes),
|
||||
256 => private.sign::<SHA256>(mbytes),
|
||||
384 => private.sign::<SHA384>(mbytes),
|
||||
512 => private.sign::<SHA512>(mbytes),
|
||||
x => panic!("Unknown hash algorithm {}", x)
|
||||
};
|
||||
assert_eq!(r, sig.r, "r signature check");
|
||||
assert_eq!(s, sig.s, "s signature check");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_tests {
|
||||
($name: ident, $curve: ident, $base: ident) => {
|
||||
#[test]
|
||||
fn $name() {
|
||||
sign_test_body!($name, $curve, $base);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $curve: ident, $base: ident) => {
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn $name() {
|
||||
sign_test_body!($name, $curve, $base);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
generate_tests!(p192_sign, P192, U192);
|
||||
generate_tests!(ignore p224_sign, P224, U256);
|
||||
generate_tests!(ignore p256_sign, P256, U256);
|
||||
generate_tests!(ignore p384_sign, P384, U384);
|
||||
generate_tests!(ignore p521_sign, P521, U576);
|
||||
230
src/ecdsa/public.rs
Normal file
230
src/ecdsa/public.rs
Normal file
@@ -0,0 +1,230 @@
|
||||
use cryptonum::signed::*;
|
||||
use cryptonum::unsigned::*;
|
||||
use dsa::rfc6979::DSASignature;
|
||||
use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521};
|
||||
use ecdsa::point::{ECCPoint,Point};
|
||||
use sha::Hash;
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,FromASN1,ToASN1};
|
||||
use std::cmp::min;
|
||||
|
||||
/// An ECDSA public key for the given curve.
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub struct ECCPublicKey<Curve: EllipticCurve> {
|
||||
pub(crate) q: Point<Curve>
|
||||
}
|
||||
|
||||
/// A generic ECDSA public key, when you're not sure which curve you're
|
||||
/// going to get.
|
||||
pub enum ECDSAPublic {
|
||||
P192(ECCPublicKey<P192>),
|
||||
P224(ECCPublicKey<P224>),
|
||||
P256(ECCPublicKey<P256>),
|
||||
P384(ECCPublicKey<P384>),
|
||||
P521(ECCPublicKey<P521>),
|
||||
}
|
||||
|
||||
/// An error that can occur when encoding an ECDSA public key as an ASN.1
|
||||
/// object.
|
||||
pub enum ECDSAEncodeErr {
|
||||
ASN1EncodeErr(ASN1EncodeErr),
|
||||
XValueNegative, YValueNegative
|
||||
}
|
||||
|
||||
impl From<ASN1EncodeErr> for ECDSAEncodeErr {
|
||||
fn from(x: ASN1EncodeErr) -> ECDSAEncodeErr {
|
||||
ECDSAEncodeErr::ASN1EncodeErr(x)
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that can occur when decoding an ECDSA public key from an
|
||||
/// ASN.1 blob.
|
||||
#[derive(Debug)]
|
||||
pub enum ECDSADecodeErr {
|
||||
ASN1DecodeErr(ASN1DecodeErr),
|
||||
NoKeyFound,
|
||||
InvalidKeyFormat,
|
||||
InvalidKeyBlockSize
|
||||
}
|
||||
|
||||
impl From<ASN1DecodeErr> for ECDSADecodeErr {
|
||||
fn from(x: ASN1DecodeErr) -> ECDSADecodeErr {
|
||||
ECDSADecodeErr::ASN1DecodeErr(x)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! public_impl {
|
||||
($curve: ident, $un: ident, $si: ident) => {
|
||||
impl ECCPublicKey<$curve>
|
||||
{
|
||||
/// Generate a new public key object from the given public point.
|
||||
pub fn new(q: Point<$curve>) -> ECCPublicKey<$curve>
|
||||
{
|
||||
ECCPublicKey{ q }
|
||||
}
|
||||
|
||||
/// Returns true if the given message matches the given signature,
|
||||
/// assuming the provided hash function.
|
||||
pub fn verify<H: Hash>(&self, m: &[u8], sig: &DSASignature<$un>) -> bool
|
||||
{
|
||||
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 = <H>::hash(m);
|
||||
let len = min(digest_bytes.len(), $curve::size() / 8);
|
||||
digest_bytes.truncate(len);
|
||||
|
||||
if let Some(c) = sig.s.modinv(&n) {
|
||||
let e = $un::from_bytes(&digest_bytes);
|
||||
let u1 = e.modmul(&c, &n);
|
||||
let u2 = sig.r.modmul(&c, &n);
|
||||
let g = Point::<$curve>::default();
|
||||
let u1i = $si::from(u1);
|
||||
let u2i = $si::from(u2);
|
||||
let point = Point::<$curve>::double_scalar_mult(&u1i, &g, &u2i, &self.q);
|
||||
!point.x.is_negative() && (sig.r == $un::from(point.x))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToASN1 for ECCPublicKey<$curve> {
|
||||
type Error = ECDSAEncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class) -> Result<Vec<ASN1Block>,ECDSAEncodeErr>
|
||||
{
|
||||
if self.q.x.is_negative() {
|
||||
return Err(ECDSAEncodeErr::XValueNegative);
|
||||
}
|
||||
if self.q.y.is_negative() {
|
||||
return Err(ECDSAEncodeErr::YValueNegative);
|
||||
}
|
||||
|
||||
let xval = $un::from(&self.q.x);
|
||||
let yval = $un::from(&self.q.y);
|
||||
let mut xbytes = xval.to_bytes();
|
||||
let mut ybytes = yval.to_bytes();
|
||||
let goalsize = ($curve::size() + 7) / 8;
|
||||
let mut target = Vec::with_capacity(1 + (goalsize * 2));
|
||||
|
||||
while xbytes.len() > goalsize { xbytes.remove(0); };
|
||||
while xbytes.len() < goalsize { xbytes.insert(0,0) };
|
||||
while ybytes.len() > goalsize { ybytes.remove(0); };
|
||||
while ybytes.len() < goalsize { ybytes.insert(0,0) };
|
||||
|
||||
target.push(4);
|
||||
target.append(&mut xbytes);
|
||||
target.append(&mut ybytes);
|
||||
|
||||
let result = ASN1Block::BitString(c, 0, target.len() * 8, target);
|
||||
Ok(vec![result])
|
||||
}
|
||||
}
|
||||
|
||||
impl FromASN1 for ECCPublicKey<$curve> {
|
||||
type Error = ECDSADecodeErr;
|
||||
|
||||
fn from_asn1(bs: &[ASN1Block]) -> Result<(ECCPublicKey<$curve>,&[ASN1Block]),ECDSADecodeErr>
|
||||
{
|
||||
let (x, rest) = bs.split_first().ok_or(ECDSADecodeErr::NoKeyFound)?;
|
||||
if let ASN1Block::BitString(_, _, _, target) = x {
|
||||
let (hdr, xy_bstr) = target.split_first().ok_or(ECDSADecodeErr::InvalidKeyFormat)?;
|
||||
if *hdr != 4 {
|
||||
return Err(ECDSADecodeErr::InvalidKeyFormat);
|
||||
}
|
||||
let goalsize = ($curve::size() + 7) / 8;
|
||||
if xy_bstr.len() != (2 * goalsize) {
|
||||
return Err(ECDSADecodeErr::InvalidKeyBlockSize);
|
||||
}
|
||||
let (xbstr, ybstr) = xy_bstr.split_at(goalsize);
|
||||
let x = $un::from_bytes(xbstr);
|
||||
let y = $un::from_bytes(ybstr);
|
||||
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
|
||||
let res = ECCPublicKey::<$curve>::new(point);
|
||||
Ok((res, rest))
|
||||
} else {
|
||||
Err(ECDSADecodeErr::InvalidKeyFormat)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public_impl!(P192, U192, I192);
|
||||
public_impl!(P224, U256, I256);
|
||||
public_impl!(P256, U256, I256);
|
||||
public_impl!(P384, U384, I384);
|
||||
public_impl!(P521, U576, I576);
|
||||
|
||||
#[cfg(test)]
|
||||
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||
#[cfg(test)]
|
||||
use testing::*;
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! verify_test_body
|
||||
{
|
||||
($name: ident, $curve: ident, $un: ident, $si: ident) => {
|
||||
let fname = build_test_path("ecc/sign",stringify!($curve));
|
||||
run_test(fname.to_string(), 9, |case| {
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
let (negk, _bytes) = case.get("k").unwrap();
|
||||
let (negx, xbytes) = case.get("x").unwrap();
|
||||
let (negy, ybytes) = case.get("y").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negh, hbytes) = case.get("h").unwrap();
|
||||
let (negr, rbytes) = case.get("r").unwrap();
|
||||
let (negs, sbytes) = case.get("s").unwrap();
|
||||
|
||||
assert!(!negd && !negk && !negx && !negy &&
|
||||
!negm && !negh && !negr && !negs);
|
||||
let _ = $un::from_bytes(dbytes);
|
||||
let x = $un::from_bytes(xbytes);
|
||||
let y = $un::from_bytes(ybytes);
|
||||
let h = $un::from_bytes(hbytes);
|
||||
let r = $un::from_bytes(rbytes);
|
||||
let s = $un::from_bytes(sbytes);
|
||||
|
||||
let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) };
|
||||
let public = ECCPublicKey::<$curve>::new(point);
|
||||
let sig = DSASignature::new(r, s);
|
||||
match usize::from(h) {
|
||||
224 => assert!(public.verify::<SHA224>(mbytes, &sig)),
|
||||
256 => assert!(public.verify::<SHA256>(mbytes, &sig)),
|
||||
384 => assert!(public.verify::<SHA384>(mbytes, &sig)),
|
||||
512 => assert!(public.verify::<SHA512>(mbytes, &sig)),
|
||||
x => panic!("Unknown hash algorithm {}", x)
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! test_impl {
|
||||
($name: ident, $curve: ident, $un: ident, $si: ident) => {
|
||||
#[test]
|
||||
fn $name() {
|
||||
verify_test_body!($name, $curve, $un, $si);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $curve: ident, $un: ident, $si: ident) => {
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn $name() {
|
||||
verify_test_body!($name, $curve, $un, $si);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test_impl!(p192,P192,U192,I192);
|
||||
test_impl!(p224,P224,U256,I256);
|
||||
test_impl!(ignore p256,P256,U256,I256);
|
||||
test_impl!(ignore p384,P384,U384,I384);
|
||||
test_impl!(ignore p521,P521,U576,I576);
|
||||
1500
src/ed25519/constants.rs
Normal file
1500
src/ed25519/constants.rs
Normal file
File diff suppressed because it is too large
Load Diff
1090
src/ed25519/fe.rs
Normal file
1090
src/ed25519/fe.rs
Normal file
File diff suppressed because it is too large
Load Diff
33
src/ed25519/loads.rs
Normal file
33
src/ed25519/loads.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
#[cfg(test)]
|
||||
use cryptonum::unsigned::{Decoder,U192};
|
||||
#[cfg(test)]
|
||||
use testing::run_test;
|
||||
|
||||
pub fn load3(x: &[u8]) -> u64
|
||||
{
|
||||
(x[0] as u64) | ((x[1] as u64) << 8) | ((x[2] as u64) << 16)
|
||||
}
|
||||
|
||||
pub fn load4(x: &[u8]) -> u64
|
||||
{
|
||||
(x[0] as u64) | ((x[1] as u64) << 8) |
|
||||
((x[2] as u64) << 16) | ((x[3] as u64) << 24)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn loads() {
|
||||
let fname = "testdata/ed25519/load.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negx, xbytes) = case.get("x").unwrap();
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
|
||||
assert!(!negx && !nega && !negb);
|
||||
let res3 = u64::from(U192::from_bytes(abytes));
|
||||
let res4 = u64::from(U192::from_bytes(bbytes));
|
||||
assert_eq!(res3, load3(&xbytes), "load3");
|
||||
assert_eq!(res4, load4(&xbytes), "load4");
|
||||
});
|
||||
}
|
||||
|
||||
267
src/ed25519/mod.rs
Normal file
267
src/ed25519/mod.rs
Normal file
@@ -0,0 +1,267 @@
|
||||
//! The generation and use of ED25519 keys is the most straightforward
|
||||
//! of all the asymmetric crypto schemes, because you basically get no
|
||||
//! choices. There's just one key size, and you're going to use the
|
||||
//! built-in hash (which is a good one, if you were worried). So if
|
||||
//! you're not sure, this is a pretty good choice.
|
||||
//!
|
||||
//! ```rust
|
||||
//! use simple_crypto::ed25519::ED25519KeyPair;
|
||||
//!
|
||||
//! // Generate a new ED25519 key
|
||||
//! let mut rng = rand::rngs::OsRng::new().unwrap();
|
||||
//! let kp = ED25519KeyPair::generate(&mut rng);
|
||||
//!
|
||||
//! // Now that you have this key pair, you can sign and verify messages
|
||||
//! // using it. For example, to sign the vector [0,1,2,3,4] and then
|
||||
//! // verify that signature, we would write:
|
||||
//! let msg = vec![0,1,2,3,4];
|
||||
//! let sig = kp.private.sign(&msg);
|
||||
//! assert!( kp.public.verify(&msg, &sig) );
|
||||
//! ```
|
||||
|
||||
mod constants;
|
||||
mod fe;
|
||||
mod loads;
|
||||
mod point;
|
||||
mod scalars;
|
||||
|
||||
use rand::Rng;
|
||||
use sha::{Hash,SHA512};
|
||||
use self::scalars::{curve25519_scalar_mask,x25519_sc_muladd,x25519_sc_reduce};
|
||||
use self::point::{Point,Point2};
|
||||
#[cfg(test)]
|
||||
use testing::run_test;
|
||||
#[cfg(test)]
|
||||
use std::collections::HashMap;
|
||||
use super::KeyPair;
|
||||
|
||||
/// An ED25519 key pair
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub struct ED25519KeyPair
|
||||
{
|
||||
pub public: ED25519Public,
|
||||
pub private: ED25519Private
|
||||
}
|
||||
|
||||
impl KeyPair for ED25519KeyPair
|
||||
{
|
||||
type Public = ED25519Public;
|
||||
type Private = ED25519Private;
|
||||
|
||||
fn new(pbl: ED25519Public, prv: ED25519Private) -> ED25519KeyPair
|
||||
{
|
||||
ED25519KeyPair {
|
||||
public: pbl,
|
||||
private: prv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ED25519KeyPair
|
||||
{
|
||||
/// Generate a random ED25519 key pair, using the given random number
|
||||
/// generator. You really need to use a good, cryptographically-strong
|
||||
/// RNG if you want good keys.
|
||||
pub fn generate<G: Rng>(rng: &mut G) -> ED25519KeyPair
|
||||
{
|
||||
let mut seed = [0; 32];
|
||||
rng.fill_bytes(&mut seed);
|
||||
let private = ED25519Private::from_seed(&seed);
|
||||
let public = ED25519Public::from(&private);
|
||||
ED25519KeyPair::new(public, private)
|
||||
}
|
||||
|
||||
/// Generate the ED25519 key pair defined by the given seed value.
|
||||
/// This should be a block of 32 bytes.
|
||||
pub fn from_seed(seed: &[u8]) -> ED25519KeyPair
|
||||
{
|
||||
let private = ED25519Private::from_seed(seed);
|
||||
let public = ED25519Public::from(&private);
|
||||
ED25519KeyPair{ public, private }
|
||||
}
|
||||
}
|
||||
|
||||
/// An ED25519 private key.
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub struct ED25519Private
|
||||
{
|
||||
seed: [u8; 32],
|
||||
private: [u8; 32],
|
||||
prefix: [u8; 32],
|
||||
public: [u8; 32]
|
||||
}
|
||||
|
||||
impl ED25519Private {
|
||||
/// Generate the ED25519 private key defined by the given 32 byte seed
|
||||
/// value.
|
||||
pub fn from_seed(seed: &[u8]) -> ED25519Private {
|
||||
let mut result = ED25519Private {
|
||||
seed: [0; 32],
|
||||
private: [0; 32],
|
||||
prefix: [0; 32],
|
||||
public: [0; 32]
|
||||
};
|
||||
result.seed.copy_from_slice(seed);
|
||||
let mut expanded = SHA512::hash(seed);
|
||||
let (private, prefix) = expanded.split_at_mut(32);
|
||||
result.private.copy_from_slice(private);
|
||||
result.prefix.copy_from_slice(prefix);
|
||||
curve25519_scalar_mask(&mut result.private);
|
||||
let a = Point::scalarmult_base(&result.private);
|
||||
result.public.copy_from_slice(&a.encode());
|
||||
result
|
||||
}
|
||||
|
||||
/// Sign the given message, returning the signature. Unlike most other
|
||||
/// public/private schemes, you don't get a choice on the hash used to
|
||||
/// compute this signature. (On the bright side, it's SHA2-512.)
|
||||
pub fn sign(&self, msg: &[u8]) -> Vec<u8>
|
||||
{
|
||||
let mut signature_s = [0u8; 32];
|
||||
|
||||
let mut ctx = SHA512::new();
|
||||
ctx.update(&self.prefix);
|
||||
ctx.update(&msg);
|
||||
let nonce = digest_scalar(&ctx.finalize());
|
||||
let r = Point::scalarmult_base(&nonce);
|
||||
let signature_r = r.encode();
|
||||
let hram_digest = eddsa_digest(&signature_r, &self.public, &msg);
|
||||
let hram = digest_scalar(&hram_digest);
|
||||
x25519_sc_muladd(&mut signature_s, &hram, &self.private, &nonce);
|
||||
let mut result = Vec::with_capacity(64);
|
||||
result.extend_from_slice(&signature_r);
|
||||
result.extend_from_slice(&signature_s);
|
||||
result
|
||||
}
|
||||
|
||||
/// Covert the given private key into its byte representation. This is
|
||||
/// guaranteed to be exactly 32 bytes.
|
||||
pub fn to_bytes(&self) -> Vec<u8>
|
||||
{
|
||||
self.seed.to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
/// An ED25519 Public key
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub struct ED25519Public
|
||||
{
|
||||
bytes: [u8; 32],
|
||||
point: Point
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ED25519Private> for ED25519Public
|
||||
{
|
||||
fn from(x: &ED25519Private) -> ED25519Public
|
||||
{
|
||||
ED25519Public::new(&x.public).expect("Broke converting private ED25519 to public. (?!)")
|
||||
}
|
||||
}
|
||||
|
||||
/// The kinds of errors you can get when you try to generate a public key from,
|
||||
/// for example, an unknown block of bytes.
|
||||
#[derive(Debug)]
|
||||
pub enum ED25519PublicImportError
|
||||
{
|
||||
WrongNumberOfBytes(usize),
|
||||
InvalidPublicPoint
|
||||
}
|
||||
|
||||
impl ED25519Public {
|
||||
/// Generate an ED25519 public key given the provided (32 byte) bytes. This
|
||||
/// can return errors if the value isn't a reasonable representation of an
|
||||
/// ED25519 point.
|
||||
pub fn new(bytes: &[u8]) -> Result<ED25519Public,ED25519PublicImportError>
|
||||
{
|
||||
if bytes.len() != 32 {
|
||||
return Err(ED25519PublicImportError::WrongNumberOfBytes(bytes.len()));
|
||||
}
|
||||
match Point::from_bytes(&bytes) {
|
||||
None =>
|
||||
Err(ED25519PublicImportError::InvalidPublicPoint),
|
||||
Some(a) => {
|
||||
let mut res = ED25519Public{ bytes: [0; 32], point: a };
|
||||
res.bytes.copy_from_slice(&bytes);
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify that the given signature matches the given message.
|
||||
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool
|
||||
{
|
||||
assert_eq!(sig.len(), 64);
|
||||
|
||||
let signature_r = &sig[..32];
|
||||
let signature_s = &sig[32..];
|
||||
|
||||
if signature_s[31] & 0b11100000 != 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let ainv = self.point.invert();
|
||||
let h_digest = eddsa_digest(signature_r, &self.bytes, msg);
|
||||
let h = digest_scalar(&h_digest);
|
||||
let r = Point2::double_scalarmult_vartime(&h, &ainv, &signature_s);
|
||||
let r_check = r.encode();
|
||||
signature_r.to_vec() == r_check
|
||||
}
|
||||
|
||||
/// Turn the ED25519 into its byte representation. This will always be a
|
||||
/// 32 byte block.
|
||||
pub fn to_bytes(&self) -> Vec<u8>
|
||||
{
|
||||
self.bytes.to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
fn eddsa_digest(signature_r: &[u8], public_key: &[u8], msg: &[u8]) -> Vec<u8>
|
||||
{
|
||||
let mut ctx = SHA512::new();
|
||||
ctx.update(signature_r);
|
||||
ctx.update(public_key);
|
||||
ctx.update(msg);
|
||||
ctx.finalize()
|
||||
}
|
||||
|
||||
fn digest_scalar(digest: &[u8]) -> Vec<u8> {
|
||||
assert_eq!(digest.len(), 512/8);
|
||||
let mut copy = [0; 512/8];
|
||||
copy.copy_from_slice(digest);
|
||||
x25519_sc_reduce(&mut copy);
|
||||
copy[..32].to_vec()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn run_signing_testcase(case: HashMap<String,(bool,Vec<u8>)>)
|
||||
{
|
||||
let (negr, rbytes) = case.get("r").unwrap();
|
||||
let (negu, ubytes) = case.get("u").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negs, sbytes) = case.get("s").unwrap();
|
||||
|
||||
assert!(!negr && !negu && !negm && !negs);
|
||||
let keypair = ED25519KeyPair::from_seed(rbytes);
|
||||
assert_eq!(ubytes, &keypair.public.bytes.to_vec());
|
||||
let mut privpub = Vec::new();
|
||||
privpub.append(&mut rbytes.clone());
|
||||
privpub.append(&mut ubytes.clone());
|
||||
let sig = keypair.private.sign(&mbytes);
|
||||
assert_eq!(sig.len(), sbytes.len());
|
||||
assert!(sig.iter().eq(sbytes.iter()));
|
||||
assert!(keypair.public.verify(&mbytes, &sig));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn rfc8072() {
|
||||
let fname = "testdata/ed25519/rfc8032.test";
|
||||
run_test(fname.to_string(), 4, run_signing_testcase);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn signing() {
|
||||
let fname = "testdata/ed25519/sign.test";
|
||||
run_test(fname.to_string(), 4, run_signing_testcase);
|
||||
}
|
||||
733
src/ed25519/point.rs
Normal file
733
src/ed25519/point.rs
Normal file
@@ -0,0 +1,733 @@
|
||||
#[cfg(test)]
|
||||
use testing::run_test;
|
||||
|
||||
use ed25519::fe::*;
|
||||
use ed25519::constants::*;
|
||||
use std::ops::*;
|
||||
|
||||
// This is ge_p3 in the original source code
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct Point {
|
||||
pub x: FieldElement,
|
||||
pub y: FieldElement,
|
||||
pub z: FieldElement,
|
||||
pub t: FieldElement
|
||||
}
|
||||
|
||||
impl Point {
|
||||
fn zero() -> Point
|
||||
{
|
||||
Point {
|
||||
x: FieldElement::zero(),
|
||||
y: FieldElement::one(),
|
||||
z: FieldElement::one(),
|
||||
t: FieldElement::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn load_test_value(xs: &[u8]) -> Point {
|
||||
assert!(xs.len() == 160);
|
||||
Point {
|
||||
x: test_from_bytes(&xs[0..40]),
|
||||
y: test_from_bytes(&xs[40..80]),
|
||||
z: test_from_bytes(&xs[80..120]),
|
||||
t: test_from_bytes(&xs[120..])
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert 32 bytes into an ED25519 point. This routine is not
|
||||
/// statically timed, so don't use it if that's important to you.
|
||||
pub fn from_bytes(s: &[u8]) -> Option<Point>
|
||||
{
|
||||
let hy = FieldElement::from_bytes(s);
|
||||
let hz = FieldElement::one();
|
||||
let mut u = hy.square();
|
||||
let mut v = &u * &D;
|
||||
u = &u - &hz; /* u = y^2-1 */
|
||||
v += &hz;
|
||||
|
||||
let mut v3 = v.square();
|
||||
v3 *= &v; /* v3 = v^3 */
|
||||
let mut hx = v3.square();
|
||||
hx *= &v;
|
||||
hx *= &u; /* x = uv^7 */
|
||||
hx = hx.pow22523(); /* x = (uv^7)^((q-5)/8) */
|
||||
hx *= &v3;
|
||||
hx *= &u; /* x = uv^3(uv^7)^((q-5)/8) */
|
||||
|
||||
let mut vxx = hx.square();
|
||||
vxx *= &v;
|
||||
let mut check = &vxx - &u; /* vx^2-u */
|
||||
if check.isnonzero() {
|
||||
check = &vxx + &u;
|
||||
if check.isnonzero() {
|
||||
return None;
|
||||
}
|
||||
hx *= &SQRTM1;
|
||||
}
|
||||
|
||||
if hx.isnegative() != ((s[31] >> 7) == 1) {
|
||||
hx = -&hx;
|
||||
}
|
||||
|
||||
let ht = &hx * &hy;
|
||||
return Some(Point{ x: hx, y: hy, z: hz, t: ht });
|
||||
}
|
||||
|
||||
pub fn encode(&self) -> Vec<u8>
|
||||
{
|
||||
into_encoded_point(&self.x, &self.y, &self.z)
|
||||
}
|
||||
|
||||
pub fn invert(&self) -> Point
|
||||
{
|
||||
Point {
|
||||
x: -&self.x,
|
||||
y: self.y.clone(),
|
||||
z: self.z.clone(),
|
||||
t: -&self.t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const D: FieldElement = FieldElement {
|
||||
value: [-10913610, 13857413, -15372611, 6949391, 114729,
|
||||
-8787816, -6275908, -3247719, -18696448, -12055116]
|
||||
};
|
||||
|
||||
const SQRTM1: FieldElement = FieldElement {
|
||||
value: [-32595792, -7943725, 9377950, 3500415, 12389472,
|
||||
-272473, -25146209, -2005654, 326686, 11406482]
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn from_bytes_vartime() {
|
||||
let fname = "testdata/ed25519/fbv.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
|
||||
assert!(!nega && !negb && !negc);
|
||||
let target = Point::load_test_value(&cbytes);
|
||||
let mine = Point::from_bytes(&abytes);
|
||||
if bbytes.len() < cbytes.len() {
|
||||
assert!(mine.is_none());
|
||||
} else {
|
||||
assert_eq!(target, mine.unwrap());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub struct Point2 {
|
||||
pub x: FieldElement,
|
||||
pub y: FieldElement,
|
||||
pub z: FieldElement,
|
||||
}
|
||||
|
||||
impl Point2 {
|
||||
pub fn zero() -> Point2
|
||||
{
|
||||
Point2 {
|
||||
x: FieldElement::zero(),
|
||||
y: FieldElement::one(),
|
||||
z: FieldElement::one()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn load_test_value(xs: &[u8]) -> Point2 {
|
||||
assert!(xs.len() == 120);
|
||||
Point2 {
|
||||
x: test_from_bytes(&xs[0..40]),
|
||||
y: test_from_bytes(&xs[40..80]),
|
||||
z: test_from_bytes(&xs[80..120]),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode(&self) -> Vec<u8>
|
||||
{
|
||||
into_encoded_point(&self.x, &self.y, &self.z)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Point> for Point2 {
|
||||
fn from(p: &Point) -> Point2 {
|
||||
Point2 {
|
||||
x: p.x.clone(),
|
||||
y: p.y.clone(),
|
||||
z: p.z.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub struct PointP1P1 {
|
||||
x: FieldElement,
|
||||
y: FieldElement,
|
||||
z: FieldElement,
|
||||
t: FieldElement
|
||||
}
|
||||
|
||||
impl PointP1P1 {
|
||||
#[cfg(test)]
|
||||
fn load_test_value(xs: &[u8]) -> PointP1P1 {
|
||||
assert!(xs.len() == 160);
|
||||
PointP1P1 {
|
||||
x: test_from_bytes(&xs[0..40]),
|
||||
y: test_from_bytes(&xs[40..80]),
|
||||
z: test_from_bytes(&xs[80..120]),
|
||||
t: test_from_bytes(&xs[120..])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug,PartialEq)]
|
||||
struct Cached {
|
||||
yplusx: FieldElement,
|
||||
yminusx: FieldElement,
|
||||
z: FieldElement,
|
||||
t2d: FieldElement
|
||||
}
|
||||
|
||||
impl Cached
|
||||
{
|
||||
fn new() -> Cached
|
||||
{
|
||||
Cached {
|
||||
yplusx: FieldElement::new(),
|
||||
yminusx: FieldElement::new(),
|
||||
z: FieldElement::new(),
|
||||
t2d: FieldElement::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn load_test_value(xs: &[u8]) -> Cached {
|
||||
assert!(xs.len() == 160);
|
||||
Cached {
|
||||
yplusx: test_from_bytes(&xs[0..40]),
|
||||
yminusx: test_from_bytes(&xs[40..80]),
|
||||
z: test_from_bytes(&xs[80..120]),
|
||||
t2d: test_from_bytes(&xs[120..])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const D2: FieldElement = FieldElement {
|
||||
value: [-21827239, -5839606, -30745221, 13898782, 229458,
|
||||
15978800, -12551817, -6495438, 29715968, 9444199]
|
||||
};
|
||||
|
||||
impl<'a> From<&'a Point> for Cached
|
||||
{
|
||||
fn from(p: &Point) -> Cached
|
||||
{
|
||||
Cached {
|
||||
yplusx: &p.y + &p.x,
|
||||
yminusx: &p.y - &p.x,
|
||||
z: p.z.clone(),
|
||||
t2d: &p.t * &D2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a PointP1P1> for Point2
|
||||
{
|
||||
fn from(p: &PointP1P1) -> Point2
|
||||
{
|
||||
Point2 {
|
||||
x: &p.x * &p.t,
|
||||
y: &p.y * &p.z,
|
||||
z: &p.z * &p.t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a PointP1P1> for Point
|
||||
{
|
||||
fn from(p: &PointP1P1) -> Point
|
||||
{
|
||||
Point {
|
||||
x: &p.x * &p.t,
|
||||
y: &p.y * &p.z,
|
||||
z: &p.z * &p.t,
|
||||
t: &p.x * &p.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn conversion() {
|
||||
let fname = "testdata/ed25519/conversion.test";
|
||||
run_test(fname.to_string(), 6, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
let (negt, tbytes) = case.get("t").unwrap();
|
||||
let (nego, obytes) = case.get("o").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
|
||||
let a = Point::load_test_value(&abytes);
|
||||
let c = Cached::load_test_value(&cbytes);
|
||||
let t = Point2::load_test_value(&tbytes);
|
||||
let o = PointP1P1::load_test_value(&obytes);
|
||||
let d = Point2::load_test_value(&dbytes);
|
||||
let b = Point::load_test_value(&bbytes);
|
||||
|
||||
assert!(!nega && !negc && !negt && !nego && !negd && !negb);
|
||||
|
||||
let myc = Cached::from(&a);
|
||||
assert_eq!(myc, c);
|
||||
|
||||
let myt = Point2::from(&a);
|
||||
assert_eq!(myt, t);
|
||||
|
||||
let myo = a.double();
|
||||
assert_eq!(myo, o);
|
||||
|
||||
let myd = Point2::from(&o);
|
||||
assert_eq!(myd, d);
|
||||
|
||||
let myb = Point::from(&o);
|
||||
assert_eq!(myb, b);
|
||||
});
|
||||
}
|
||||
|
||||
/* r = 2 * p */
|
||||
impl Point2 {
|
||||
fn double(&self) -> PointP1P1
|
||||
{
|
||||
let x0 = self.x.square();
|
||||
let z0 = self.y.square();
|
||||
let t0 = self.z.sq2();
|
||||
let y0 = &self.x + &self.y;
|
||||
let ry = &z0 + &x0;
|
||||
let rz = &z0 - &x0;
|
||||
let rx = &y0.square() - &ry;
|
||||
let rt = &t0 - &rz;
|
||||
PointP1P1 { x: rx, y: ry, z: rz, t: rt }
|
||||
}
|
||||
}
|
||||
|
||||
/* r = 2 * p */
|
||||
impl Point {
|
||||
fn double(&self) -> PointP1P1
|
||||
{
|
||||
Point2::from(self).double()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn double() {
|
||||
let fname = "testdata/ed25519/pt_double.test";
|
||||
run_test(fname.to_string(), 4, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
|
||||
assert!(!nega && !negb && !negc && !negd);
|
||||
let a = Point::load_test_value(abytes);
|
||||
let b = PointP1P1::load_test_value(bbytes);
|
||||
let c = Point2::load_test_value(cbytes);
|
||||
let d = PointP1P1::load_test_value(dbytes);
|
||||
|
||||
let myb = a.double();
|
||||
assert_eq!(myb, b);
|
||||
let myd = c.double();
|
||||
assert_eq!(myd, d);
|
||||
});
|
||||
}
|
||||
|
||||
impl<'a,'b> Add<&'a Precomp> for &'b Point
|
||||
{
|
||||
type Output = PointP1P1;
|
||||
|
||||
fn add(self, q: &Precomp) -> PointP1P1
|
||||
{
|
||||
let mut rx;
|
||||
let mut ry;
|
||||
let mut rz;
|
||||
let mut rt;
|
||||
|
||||
rx = &self.y + &self.x;
|
||||
ry = &self.y - &self.x;
|
||||
rz = &rx * &q.yplusx;
|
||||
ry *= &q.yminusx;
|
||||
rt = &q.xy2d * &self.t;
|
||||
let t0 = &self.z + &self.z;
|
||||
rx = &rz - &ry;
|
||||
ry += &rz;
|
||||
rz = &t0 + &rt;
|
||||
rt = &t0 - &rt;
|
||||
|
||||
PointP1P1 { x: rx, y: ry, z: rz, t: rt }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'b> Sub<&'a Precomp> for &'b Point
|
||||
{
|
||||
type Output = PointP1P1;
|
||||
|
||||
/* r = p - q */
|
||||
fn sub(self, q: &Precomp) -> PointP1P1
|
||||
{
|
||||
let mut rx = &self.y + &self.x;
|
||||
let mut ry = &self.y - &self.x;
|
||||
let mut rz = &rx * &q.yminusx;
|
||||
ry *= &q.yplusx;
|
||||
let mut rt = &q.xy2d * &self.t;
|
||||
let t0 = &self.z + &self.z;
|
||||
rx = &rz - &ry;
|
||||
ry += &rz;
|
||||
rz = &t0 - &rt;
|
||||
rt += &t0;
|
||||
PointP1P1{ x: rx, y: ry, z: rz, t: rt }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn maddsub() {
|
||||
let fname = "testdata/ed25519/maddsub.test";
|
||||
run_test(fname.to_string(), 4, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
|
||||
assert!(!nega && !negb && !negc && !negd);
|
||||
let a = Point::load_test_value(abytes);
|
||||
let b = PointP1P1::load_test_value(bbytes);
|
||||
let c = Precomp::load_test_value(cbytes);
|
||||
let d = PointP1P1::load_test_value(dbytes);
|
||||
|
||||
let myb = &a + &c;
|
||||
assert_eq!(myb, b);
|
||||
let myd = &a - &c;
|
||||
assert_eq!(myd, d);
|
||||
});
|
||||
}
|
||||
|
||||
impl<'a,'b> Add<&'a Cached> for &'b Point
|
||||
{
|
||||
type Output = PointP1P1;
|
||||
|
||||
fn add(self, q: &Cached) -> PointP1P1
|
||||
{
|
||||
let mut rx;
|
||||
let mut ry;
|
||||
let mut rz;
|
||||
let mut rt;
|
||||
|
||||
rx = &self.y + &self.x;
|
||||
ry = &self.y - &self.x;
|
||||
rz = &rx * &q.yplusx;
|
||||
ry *= &q.yminusx;
|
||||
rt = &q.t2d * &self.t;
|
||||
rx = &self.z * &q.z;
|
||||
let t0 = &rx + ℞
|
||||
rx = &rz - &ry;
|
||||
ry += &rz;
|
||||
rz = &t0 + &rt;
|
||||
rt = &t0 - &rt;
|
||||
|
||||
PointP1P1{ x: rx, y: ry, z: rz, t: rt }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'b> Sub<&'a Cached> for &'b Point
|
||||
{
|
||||
type Output = PointP1P1;
|
||||
|
||||
fn sub(self, q: &Cached) -> PointP1P1
|
||||
{
|
||||
let mut rx;
|
||||
let mut ry;
|
||||
let mut rz;
|
||||
let mut rt;
|
||||
|
||||
rx = &self.y + &self.x;
|
||||
ry = &self.y - &self.x;
|
||||
rz = &rx * &q.yminusx;
|
||||
ry *= &q.yplusx;
|
||||
rt = &q.t2d * &self.t;
|
||||
rx = &self.z * &q.z;
|
||||
let t0 = &rx + ℞
|
||||
rx = &rz - &ry;
|
||||
ry += &rz;
|
||||
rz = &t0 - &rt;
|
||||
rt += &t0;
|
||||
|
||||
PointP1P1{ x: rx, y: ry, z: rz, t: rt }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn addsub() {
|
||||
let fname = "testdata/ed25519/ptaddsub.test";
|
||||
run_test(fname.to_string(), 4, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
|
||||
assert!(!nega && !negb && !negc && !negd);
|
||||
let a = Point::load_test_value(abytes);
|
||||
let b = PointP1P1::load_test_value(bbytes);
|
||||
let c = Cached::load_test_value(cbytes);
|
||||
let d = PointP1P1::load_test_value(dbytes);
|
||||
|
||||
let myb = &a + &c;
|
||||
assert_eq!(myb, b);
|
||||
let myd = &a - &c;
|
||||
assert_eq!(myd, d);
|
||||
});
|
||||
}
|
||||
|
||||
impl Point {
|
||||
/* h = a * B
|
||||
* where a = a[0]+256*a[1]+...+256^31 a[31]
|
||||
* B is the Ed25519 base point (x,4/5) with x positive.
|
||||
*
|
||||
* Preconditions:
|
||||
* a[31] <= 127 */
|
||||
pub fn scalarmult_base(a: &[u8]) -> Point
|
||||
{
|
||||
let mut e: [i8; 64] = [0; 64];
|
||||
for i in 0..32 {
|
||||
e[2 * i + 0] = ((a[i] >> 0) & 15) as i8;
|
||||
e[2 * i + 1] = ((a[i] >> 4) & 15) as i8;
|
||||
}
|
||||
/* each e[i] is between 0 and 15 */
|
||||
/* e[63] is between 0 and 7 */
|
||||
|
||||
let mut carry = 0;
|
||||
for i in 0..63 {
|
||||
e[i] += carry;
|
||||
carry = e[i] + 8;
|
||||
carry >>= 4;
|
||||
e[i] -= carry << 4;
|
||||
}
|
||||
e[63] += carry;
|
||||
/* each e[i] is between -8 and 8 */
|
||||
|
||||
let mut r;
|
||||
let mut t;
|
||||
|
||||
let mut h = Point::zero();
|
||||
for i in &[1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63] {
|
||||
t = Precomp::table_select(*i / 2, e[*i as usize]);
|
||||
r = &h + &t;
|
||||
h = Point::from(&r);
|
||||
}
|
||||
|
||||
r = h.double();
|
||||
let mut s = Point2::from(&r);
|
||||
r = s.double();
|
||||
s = Point2::from(&r);
|
||||
r = s.double();
|
||||
s = Point2::from(&r);
|
||||
r = s.double();
|
||||
h = Point::from(&r);
|
||||
|
||||
for i in &[0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62] {
|
||||
t = Precomp::table_select(*i / 2, e[*i as usize]);
|
||||
r = &h + &t;
|
||||
h = Point::from(&r);
|
||||
}
|
||||
|
||||
h
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn scalarmult_base() {
|
||||
let fname = "testdata/ed25519/scalar_mult.test";
|
||||
run_test(fname.to_string(), 2, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
|
||||
assert!(!nega && !negb);
|
||||
let b = Point::load_test_value(bbytes);
|
||||
let mine = Point::scalarmult_base(&abytes);
|
||||
assert_eq!(mine, b);
|
||||
});
|
||||
}
|
||||
|
||||
fn slide(r: &mut [i8], a: &[u8])
|
||||
{
|
||||
for i in 0..256 {
|
||||
r[i] = (1 & (a[i >> 3] >> (i & 7))) as i8;
|
||||
}
|
||||
|
||||
for i in 0..256 {
|
||||
if r[i] != 0 {
|
||||
let mut b = 1;
|
||||
while (b <= 6) && ((i + b) < 256) {
|
||||
if r[i + b] != 0 {
|
||||
if r[i] + (r[i + b] << b) <= 15 {
|
||||
r[i] += r[i + b] << b;
|
||||
r[i + b] = 0;
|
||||
} else if r[i] - (r[i + b] << b) >= -15 {
|
||||
r[i] -= r[i + b] << b;
|
||||
for k in (i+b)..256 {
|
||||
if r[k] == 0 {
|
||||
r[k] = 1;
|
||||
break;
|
||||
}
|
||||
r[k] = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
b += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn helper_slide() {
|
||||
let fname = "testdata/ed25519/slide.test";
|
||||
run_test(fname.to_string(), 2, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
|
||||
assert!(!nega && !negb);
|
||||
let mut mine = [0; 256];
|
||||
slide(&mut mine, &abytes);
|
||||
for i in 0..256 {
|
||||
assert_eq!(mine[i], bbytes[i] as i8);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
impl Point2
|
||||
{
|
||||
/* r = a * A + b * B
|
||||
* where a = a[0]+256*a[1]+...+256^31 a[31].
|
||||
* and b = b[0]+256*b[1]+...+256^31 b[31].
|
||||
* B is the Ed25519 base point (x,4/5) with x positive. */
|
||||
#[allow(non_snake_case)]
|
||||
pub fn double_scalarmult_vartime(a: &[u8], A: &Point, b: &[u8]) -> Point2
|
||||
{
|
||||
let mut aslide: [i8; 256] = [0; 256];
|
||||
let mut bslide: [i8; 256] = [0; 256];
|
||||
#[allow(non_snake_case)]
|
||||
let mut Ai: [Cached; 8] = [Cached::new(), Cached::new(), Cached::new(), Cached::new(),
|
||||
Cached::new(), Cached::new(), Cached::new(), Cached::new()];
|
||||
#[allow(non_snake_case)]
|
||||
|
||||
slide(&mut aslide, &a);
|
||||
slide(&mut bslide, &b);
|
||||
|
||||
Ai[0] = Cached::from(A);
|
||||
let mut t = A.double();
|
||||
let A2 = Point::from(&t);
|
||||
t = &A2 + &Ai[0];
|
||||
let mut u = Point::from(&t);
|
||||
Ai[1] = Cached::from(&u);
|
||||
t = &A2 + &Ai[1];
|
||||
u = Point::from(&t);
|
||||
Ai[2] = Cached::from(&u);
|
||||
t = &A2 + &Ai[2];
|
||||
u = Point::from(&t);
|
||||
Ai[3] = Cached::from(&u);
|
||||
t = &A2 + &Ai[3];
|
||||
u = Point::from(&t);
|
||||
Ai[4] = Cached::from(&u);
|
||||
t = &A2 + &Ai[4];
|
||||
u = Point::from(&t);
|
||||
Ai[5] = Cached::from(&u);
|
||||
t = &A2 + &Ai[5];
|
||||
u = Point::from(&t);
|
||||
Ai[6] = Cached::from(&u);
|
||||
t = &A2 + &Ai[6];
|
||||
u = Point::from(&t);
|
||||
Ai[7] = Cached::from(&u);
|
||||
|
||||
let mut r = Point2::zero();
|
||||
|
||||
let mut i: i32 = 255;
|
||||
loop {
|
||||
if (aslide[i as usize] != 0) || (bslide[i as usize] != 0) {
|
||||
break;
|
||||
}
|
||||
i -= 1;
|
||||
if i < 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while i >= 0 {
|
||||
t = r.double();
|
||||
|
||||
if aslide[i as usize] > 0 {
|
||||
u = Point::from(&t);
|
||||
let idx = (aslide[i as usize] / 2) as usize;
|
||||
t = &u + &Ai[idx]
|
||||
} else if aslide[i as usize] < 0 {
|
||||
u = Point::from(&t);
|
||||
let idx = ((-aslide[i as usize]) / 2) as usize;
|
||||
t = &u - &Ai[idx];
|
||||
}
|
||||
|
||||
if bslide[i as usize] > 0 {
|
||||
u = Point::from(&t);
|
||||
let idx = (bslide[i as usize] / 2) as usize;
|
||||
t = &u + &BI[idx];
|
||||
} else if bslide[i as usize] < 0 {
|
||||
u = Point::from(&t);
|
||||
let idx = ((-bslide[i as usize]) / 2) as usize;
|
||||
t = &u - &BI[idx];
|
||||
}
|
||||
|
||||
r = Point2::from(&t);
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn double_scalarmult() {
|
||||
let fname = "testdata/ed25519/scalar_mult_gen.test";
|
||||
run_test(fname.to_string(), 4, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
|
||||
assert!(!nega && !negb && !negc && !negd);
|
||||
let b = Point::load_test_value(bbytes);
|
||||
let d = Point2::load_test_value(dbytes);
|
||||
let mine = Point2::double_scalarmult_vartime(&abytes, &b, &cbytes);
|
||||
assert_eq!(mine, d);
|
||||
});
|
||||
}
|
||||
|
||||
fn into_encoded_point(x: &FieldElement, y: &FieldElement, z: &FieldElement) -> Vec<u8>
|
||||
{
|
||||
let recip = z.invert();
|
||||
let x_over_z = x * &recip;
|
||||
let y_over_z = y * &recip;
|
||||
let mut bytes = y_over_z.to_bytes();
|
||||
let sign_bit = if x_over_z.isnegative() { 1 } else { 0 };
|
||||
// The preceding computations must execute in constant time, but this
|
||||
// doesn't need to.
|
||||
bytes[31] ^= sign_bit << 7;
|
||||
bytes
|
||||
}
|
||||
3363
src/ed25519/rfc8032.txt
Normal file
3363
src/ed25519/rfc8032.txt
Normal file
File diff suppressed because it is too large
Load Diff
881
src/ed25519/scalars.rs
Normal file
881
src/ed25519/scalars.rs
Normal file
@@ -0,0 +1,881 @@
|
||||
use ed25519::loads::{load3,load4};
|
||||
#[cfg(test)]
|
||||
use testing::run_test;
|
||||
|
||||
/* The set of scalars is \Z/l
|
||||
* where l = 2^252 + 27742317777372353535851937790883648493. */
|
||||
|
||||
/* Input:
|
||||
* s[0]+256*s[1]+...+256^63*s[63] = s
|
||||
*
|
||||
* Output:
|
||||
* s[0]+256*s[1]+...+256^31*s[31] = s mod l
|
||||
* where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
* Overwrites s in place. */
|
||||
pub fn x25519_sc_reduce(s: &mut [u8])
|
||||
{
|
||||
let mut s0 : i64 = 2097151 & load3(s) as i64;
|
||||
let mut s1 : i64 = 2097151 & (load4(&s[2..]) >> 5) as i64;
|
||||
let mut s2 : i64 = 2097151 & (load3(&s[5..]) >> 2) as i64;
|
||||
let mut s3 : i64 = 2097151 & (load4(&s[7..]) >> 7) as i64;
|
||||
let mut s4 : i64 = 2097151 & (load4(&s[10..]) >> 4) as i64;
|
||||
let mut s5 : i64 = 2097151 & (load3(&s[13..]) >> 1) as i64;
|
||||
let mut s6 : i64 = 2097151 & (load4(&s[15..]) >> 6) as i64;
|
||||
let mut s7 : i64 = 2097151 & (load3(&s[18..]) >> 3) as i64;
|
||||
let mut s8 : i64 = 2097151 & load3(&s[21..]) as i64;
|
||||
let mut s9 : i64 = 2097151 & (load4(&s[23..]) >> 5) as i64;
|
||||
let mut s10 : i64 = 2097151 & (load3(&s[26..]) >> 2) as i64;
|
||||
let mut s11 : i64 = 2097151 & (load4(&s[28..]) >> 7) as i64;
|
||||
let mut s12 : i64 = 2097151 & (load4(&s[31..]) >> 4) as i64;
|
||||
let mut s13 : i64 = 2097151 & (load3(&s[34..]) >> 1) as i64;
|
||||
let mut s14 : i64 = 2097151 & (load4(&s[36..]) >> 6) as i64;
|
||||
let mut s15 : i64 = 2097151 & (load3(&s[39..]) >> 3) as i64;
|
||||
let mut s16 : i64 = 2097151 & load3(&s[42..]) as i64;
|
||||
let mut s17 : i64 = 2097151 & (load4(&s[44..]) >> 5) as i64;
|
||||
let s18 : i64 = 2097151 & (load3(&s[47..]) >> 2) as i64;
|
||||
let s19 : i64 = 2097151 & (load4(&s[49..]) >> 7) as i64;
|
||||
let s20 : i64 = 2097151 & (load4(&s[52..]) >> 4) as i64;
|
||||
let s21 : i64 = 2097151 & (load3(&s[55..]) >> 1) as i64;
|
||||
let s22 : i64 = 2097151 & (load4(&s[57..]) >> 6) as i64;
|
||||
let s23 : i64 = (load4(&s[60..]) >> 3) as i64 as i64;
|
||||
let mut carry0 : i64;
|
||||
let mut carry1 : i64;
|
||||
let mut carry2 : i64;
|
||||
let mut carry3 : i64;
|
||||
let mut carry4 : i64;
|
||||
let mut carry5 : i64;
|
||||
let mut carry6 : i64;
|
||||
let mut carry7 : i64;
|
||||
let mut carry8 : i64;
|
||||
let mut carry9 : i64;
|
||||
let mut carry10 : i64;
|
||||
let mut carry11 : i64;
|
||||
let carry12 : i64;
|
||||
let carry13 : i64;
|
||||
let carry14 : i64;
|
||||
let carry15 : i64;
|
||||
let carry16 : i64;
|
||||
|
||||
s11 += s23 * 666643;
|
||||
s12 += s23 * 470296;
|
||||
s13 += s23 * 654183;
|
||||
s14 -= s23 * 997805;
|
||||
s15 += s23 * 136657;
|
||||
s16 -= s23 * 683901;
|
||||
//s23 = 0;
|
||||
|
||||
s10 += s22 * 666643;
|
||||
s11 += s22 * 470296;
|
||||
s12 += s22 * 654183;
|
||||
s13 -= s22 * 997805;
|
||||
s14 += s22 * 136657;
|
||||
s15 -= s22 * 683901;
|
||||
//s22 = 0;
|
||||
|
||||
s9 += s21 * 666643;
|
||||
s10 += s21 * 470296;
|
||||
s11 += s21 * 654183;
|
||||
s12 -= s21 * 997805;
|
||||
s13 += s21 * 136657;
|
||||
s14 -= s21 * 683901;
|
||||
//s21 = 0;
|
||||
|
||||
s8 += s20 * 666643;
|
||||
s9 += s20 * 470296;
|
||||
s10 += s20 * 654183;
|
||||
s11 -= s20 * 997805;
|
||||
s12 += s20 * 136657;
|
||||
s13 -= s20 * 683901;
|
||||
//s20 = 0;
|
||||
|
||||
s7 += s19 * 666643;
|
||||
s8 += s19 * 470296;
|
||||
s9 += s19 * 654183;
|
||||
s10 -= s19 * 997805;
|
||||
s11 += s19 * 136657;
|
||||
s12 -= s19 * 683901;
|
||||
//s19 = 0;
|
||||
|
||||
s6 += s18 * 666643;
|
||||
s7 += s18 * 470296;
|
||||
s8 += s18 * 654183;
|
||||
s9 -= s18 * 997805;
|
||||
s10 += s18 * 136657;
|
||||
s11 -= s18 * 683901;
|
||||
//s18 = 0;
|
||||
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= carry16 << 21;
|
||||
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= carry15 << 21;
|
||||
|
||||
s5 += s17 * 666643;
|
||||
s6 += s17 * 470296;
|
||||
s7 += s17 * 654183;
|
||||
s8 -= s17 * 997805;
|
||||
s9 += s17 * 136657;
|
||||
s10 -= s17 * 683901;
|
||||
//s17 = 0;
|
||||
|
||||
s4 += s16 * 666643;
|
||||
s5 += s16 * 470296;
|
||||
s6 += s16 * 654183;
|
||||
s7 -= s16 * 997805;
|
||||
s8 += s16 * 136657;
|
||||
s9 -= s16 * 683901;
|
||||
//s16 = 0;
|
||||
|
||||
s3 += s15 * 666643;
|
||||
s4 += s15 * 470296;
|
||||
s5 += s15 * 654183;
|
||||
s6 -= s15 * 997805;
|
||||
s7 += s15 * 136657;
|
||||
s8 -= s15 * 683901;
|
||||
//s15 = 0;
|
||||
|
||||
s2 += s14 * 666643;
|
||||
s3 += s14 * 470296;
|
||||
s4 += s14 * 654183;
|
||||
s5 -= s14 * 997805;
|
||||
s6 += s14 * 136657;
|
||||
s7 -= s14 * 683901;
|
||||
//s14 = 0;
|
||||
|
||||
s1 += s13 * 666643;
|
||||
s2 += s13 * 470296;
|
||||
s3 += s13 * 654183;
|
||||
s4 -= s13 * 997805;
|
||||
s5 += s13 * 136657;
|
||||
s6 -= s13 * 683901;
|
||||
//s13 = 0;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry11 = s11 >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
//s12 = 0;
|
||||
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
|
||||
s[0] = (s0 >> 0) as u8;
|
||||
s[1] = (s0 >> 8) as u8;
|
||||
s[2] = ((s0 >> 16) | (s1 << 5)) as u8;
|
||||
s[3] = (s1 >> 3) as u8;
|
||||
s[4] = (s1 >> 11) as u8;
|
||||
s[5] = ((s1 >> 19) | (s2 << 2)) as u8;
|
||||
s[6] = (s2 >> 6) as u8;
|
||||
s[7] = ((s2 >> 14) | (s3 << 7)) as u8;
|
||||
s[8] = (s3 >> 1) as u8;
|
||||
s[9] = (s3 >> 9) as u8;
|
||||
s[10] = ((s3 >> 17) | (s4 << 4)) as u8;
|
||||
s[11] = (s4 >> 4) as u8;
|
||||
s[12] = (s4 >> 12) as u8;
|
||||
s[13] = ((s4 >> 20) | (s5 << 1)) as u8;
|
||||
s[14] = (s5 >> 7) as u8;
|
||||
s[15] = ((s5 >> 15) | (s6 << 6)) as u8;
|
||||
s[16] = (s6 >> 2) as u8;
|
||||
s[17] = (s6 >> 10) as u8;
|
||||
s[18] = ((s6 >> 18) | (s7 << 3)) as u8;
|
||||
s[19] = (s7 >> 5) as u8;
|
||||
s[20] = (s7 >> 13) as u8;
|
||||
s[21] = (s8 >> 0) as u8;
|
||||
s[22] = (s8 >> 8) as u8;
|
||||
s[23] = ((s8 >> 16) | (s9 << 5)) as u8;
|
||||
s[24] = (s9 >> 3) as u8;
|
||||
s[25] = (s9 >> 11) as u8;
|
||||
s[26] = ((s9 >> 19) | (s10 << 2)) as u8;
|
||||
s[27] = (s10 >> 6) as u8;
|
||||
s[28] = ((s10 >> 14) | (s11 << 7)) as u8;
|
||||
s[29] = (s11 >> 1) as u8;
|
||||
s[30] = (s11 >> 9) as u8;
|
||||
s[31] = (s11 >> 17) as u8;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn reduce() {
|
||||
let fname = "testdata/ed25519/reduce.test";
|
||||
run_test(fname.to_string(), 2, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
|
||||
assert!(!nega && !negb);
|
||||
assert_eq!(abytes.len(), 64);
|
||||
assert_eq!(bbytes.len(), 32);
|
||||
let mut copy = abytes.clone();
|
||||
x25519_sc_reduce(&mut copy);
|
||||
assert_eq!(©[0..32], &bbytes[0..]);
|
||||
});
|
||||
}
|
||||
|
||||
/* Input:
|
||||
* a[0]+256*a[1]+...+256^31*a[31] = a
|
||||
* b[0]+256*b[1]+...+256^31*b[31] = b
|
||||
* c[0]+256*c[1]+...+256^31*c[31] = c
|
||||
*
|
||||
* Output:
|
||||
* s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
|
||||
* where l = 2^252 + 27742317777372353535851937790883648493. */
|
||||
pub fn x25519_sc_muladd(s: &mut [u8], a: &[u8], b: &[u8], c: &[u8])
|
||||
{
|
||||
let a0 : i64 = 2097151 & load3(a) as i64;
|
||||
let a1 : i64 = 2097151 & (load4(&a[2..]) >> 5) as i64;
|
||||
let a2 : i64 = 2097151 & (load3(&a[5..]) >> 2) as i64;
|
||||
let a3 : i64 = 2097151 & (load4(&a[7..]) >> 7) as i64;
|
||||
let a4 : i64 = 2097151 & (load4(&a[10..]) >> 4) as i64;
|
||||
let a5 : i64 = 2097151 & (load3(&a[13..]) >> 1) as i64;
|
||||
let a6 : i64 = 2097151 & (load4(&a[15..]) >> 6) as i64;
|
||||
let a7 : i64 = 2097151 & (load3(&a[18..]) >> 3) as i64;
|
||||
let a8 : i64 = 2097151 & load3(&a[21..]) as i64;
|
||||
let a9 : i64 = 2097151 & (load4(&a[23..]) >> 5) as i64;
|
||||
let a10 : i64 = 2097151 & (load3(&a[26..]) >> 2) as i64;
|
||||
let a11 : i64 = (load4(&a[28..]) >> 7) as i64;
|
||||
let b0 : i64 = 2097151 & load3(b) as i64;
|
||||
let b1 : i64 = 2097151 & (load4(&b[2..]) >> 5) as i64;
|
||||
let b2 : i64 = 2097151 & (load3(&b[5..]) >> 2) as i64;
|
||||
let b3 : i64 = 2097151 & (load4(&b[7..]) >> 7) as i64;
|
||||
let b4 : i64 = 2097151 & (load4(&b[10..]) >> 4) as i64;
|
||||
let b5 : i64 = 2097151 & (load3(&b[13..]) >> 1) as i64;
|
||||
let b6 : i64 = 2097151 & (load4(&b[15..]) >> 6) as i64;
|
||||
let b7 : i64 = 2097151 & (load3(&b[18..]) >> 3) as i64;
|
||||
let b8 : i64 = 2097151 & load3(&b[21..]) as i64;
|
||||
let b9 : i64 = 2097151 & (load4(&b[23..]) >> 5) as i64;
|
||||
let b10 : i64 = 2097151 & (load3(&b[26..]) >> 2) as i64;
|
||||
let b11 : i64 = (load4(&b[28..]) >> 7) as i64;
|
||||
let c0 : i64 = 2097151 & load3(c) as i64;
|
||||
let c1 : i64 = 2097151 & (load4(&c[2..]) >> 5) as i64;
|
||||
let c2 : i64 = 2097151 & (load3(&c[5..]) >> 2) as i64;
|
||||
let c3 : i64 = 2097151 & (load4(&c[7..]) >> 7) as i64;
|
||||
let c4 : i64 = 2097151 & (load4(&c[10..]) >> 4) as i64;
|
||||
let c5 : i64 = 2097151 & (load3(&c[13..]) >> 1) as i64;
|
||||
let c6 : i64 = 2097151 & (load4(&c[15..]) >> 6) as i64;
|
||||
let c7 : i64 = 2097151 & (load3(&c[18..]) >> 3) as i64;
|
||||
let c8 : i64 = 2097151 & load3(&c[21..]) as i64;
|
||||
let c9 : i64 = 2097151 & (load4(&c[23..]) >> 5) as i64;
|
||||
let c10 : i64 = 2097151 & (load3(&c[26..]) >> 2) as i64;
|
||||
let c11 : i64 = (load4(&c[28..]) >> 7) as i64;
|
||||
let mut s0 : i64;
|
||||
let mut s1 : i64;
|
||||
let mut s2 : i64;
|
||||
let mut s3 : i64;
|
||||
let mut s4 : i64;
|
||||
let mut s5 : i64;
|
||||
let mut s6 : i64;
|
||||
let mut s7 : i64;
|
||||
let mut s8 : i64;
|
||||
let mut s9 : i64;
|
||||
let mut s10 : i64;
|
||||
let mut s11 : i64;
|
||||
let mut s12 : i64;
|
||||
let mut s13 : i64;
|
||||
let mut s14 : i64;
|
||||
let mut s15 : i64;
|
||||
let mut s16 : i64;
|
||||
let mut s17 : i64;
|
||||
let mut s18 : i64;
|
||||
let mut s19 : i64;
|
||||
let mut s20 : i64;
|
||||
let mut s21 : i64;
|
||||
let mut s22 : i64;
|
||||
let mut s23 : i64;
|
||||
let mut carry0 : i64;
|
||||
let mut carry1 : i64;
|
||||
let mut carry2 : i64;
|
||||
let mut carry3 : i64;
|
||||
let mut carry4 : i64;
|
||||
let mut carry5 : i64;
|
||||
let mut carry6 : i64;
|
||||
let mut carry7 : i64;
|
||||
let mut carry8 : i64;
|
||||
let mut carry9 : i64;
|
||||
let mut carry10 : i64;
|
||||
let mut carry11 : i64;
|
||||
let mut carry12 : i64;
|
||||
let mut carry13 : i64;
|
||||
let mut carry14 : i64;
|
||||
let mut carry15 : i64;
|
||||
let mut carry16 : i64;
|
||||
let carry17 : i64;
|
||||
let carry18 : i64;
|
||||
let carry19 : i64;
|
||||
let carry20 : i64;
|
||||
let carry21 : i64;
|
||||
let carry22 : i64;
|
||||
|
||||
s0 = c0 + a0 * b0;
|
||||
s1 = c1 + a0 * b1 + a1 * b0;
|
||||
s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0;
|
||||
s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
|
||||
s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
|
||||
s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
|
||||
s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
|
||||
s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 +
|
||||
a6 * b1 + a7 * b0;
|
||||
s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 +
|
||||
a6 * b2 + a7 * b1 + a8 * b0;
|
||||
s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 +
|
||||
a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
|
||||
s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 +
|
||||
a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
|
||||
s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 +
|
||||
a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
|
||||
s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 +
|
||||
a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
|
||||
s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 +
|
||||
a9 * b4 + a10 * b3 + a11 * b2;
|
||||
s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 +
|
||||
a10 * b4 + a11 * b3;
|
||||
s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 +
|
||||
a11 * b4;
|
||||
s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
|
||||
s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
|
||||
s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
|
||||
s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
|
||||
s20 = a9 * b11 + a10 * b10 + a11 * b9;
|
||||
s21 = a10 * b11 + a11 * b10;
|
||||
s22 = a11 * b11;
|
||||
s23 = 0;
|
||||
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= carry16 << 21;
|
||||
carry18 = (s18 + (1 << 20)) >> 21;
|
||||
s19 += carry18;
|
||||
s18 -= carry18 << 21;
|
||||
carry20 = (s20 + (1 << 20)) >> 21;
|
||||
s21 += carry20;
|
||||
s20 -= carry20 << 21;
|
||||
carry22 = (s22 + (1 << 20)) >> 21;
|
||||
s23 += carry22;
|
||||
s22 -= carry22 << 21;
|
||||
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= carry15 << 21;
|
||||
carry17 = (s17 + (1 << 20)) >> 21;
|
||||
s18 += carry17;
|
||||
s17 -= carry17 << 21;
|
||||
carry19 = (s19 + (1 << 20)) >> 21;
|
||||
s20 += carry19;
|
||||
s19 -= carry19 << 21;
|
||||
carry21 = (s21 + (1 << 20)) >> 21;
|
||||
s22 += carry21;
|
||||
s21 -= carry21 << 21;
|
||||
|
||||
s11 += s23 * 666643;
|
||||
s12 += s23 * 470296;
|
||||
s13 += s23 * 654183;
|
||||
s14 -= s23 * 997805;
|
||||
s15 += s23 * 136657;
|
||||
s16 -= s23 * 683901;
|
||||
//s23 = 0;
|
||||
|
||||
s10 += s22 * 666643;
|
||||
s11 += s22 * 470296;
|
||||
s12 += s22 * 654183;
|
||||
s13 -= s22 * 997805;
|
||||
s14 += s22 * 136657;
|
||||
s15 -= s22 * 683901;
|
||||
//s22 = 0;
|
||||
|
||||
s9 += s21 * 666643;
|
||||
s10 += s21 * 470296;
|
||||
s11 += s21 * 654183;
|
||||
s12 -= s21 * 997805;
|
||||
s13 += s21 * 136657;
|
||||
s14 -= s21 * 683901;
|
||||
//s21 = 0;
|
||||
|
||||
s8 += s20 * 666643;
|
||||
s9 += s20 * 470296;
|
||||
s10 += s20 * 654183;
|
||||
s11 -= s20 * 997805;
|
||||
s12 += s20 * 136657;
|
||||
s13 -= s20 * 683901;
|
||||
//s20 = 0;
|
||||
|
||||
s7 += s19 * 666643;
|
||||
s8 += s19 * 470296;
|
||||
s9 += s19 * 654183;
|
||||
s10 -= s19 * 997805;
|
||||
s11 += s19 * 136657;
|
||||
s12 -= s19 * 683901;
|
||||
//s19 = 0;
|
||||
|
||||
s6 += s18 * 666643;
|
||||
s7 += s18 * 470296;
|
||||
s8 += s18 * 654183;
|
||||
s9 -= s18 * 997805;
|
||||
s10 += s18 * 136657;
|
||||
s11 -= s18 * 683901;
|
||||
//s18 = 0;
|
||||
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= carry16 << 21;
|
||||
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= carry15 << 21;
|
||||
|
||||
s5 += s17 * 666643;
|
||||
s6 += s17 * 470296;
|
||||
s7 += s17 * 654183;
|
||||
s8 -= s17 * 997805;
|
||||
s9 += s17 * 136657;
|
||||
s10 -= s17 * 683901;
|
||||
//s17 = 0;
|
||||
|
||||
s4 += s16 * 666643;
|
||||
s5 += s16 * 470296;
|
||||
s6 += s16 * 654183;
|
||||
s7 -= s16 * 997805;
|
||||
s8 += s16 * 136657;
|
||||
s9 -= s16 * 683901;
|
||||
//s16 = 0;
|
||||
|
||||
s3 += s15 * 666643;
|
||||
s4 += s15 * 470296;
|
||||
s5 += s15 * 654183;
|
||||
s6 -= s15 * 997805;
|
||||
s7 += s15 * 136657;
|
||||
s8 -= s15 * 683901;
|
||||
//s15 = 0;
|
||||
|
||||
s2 += s14 * 666643;
|
||||
s3 += s14 * 470296;
|
||||
s4 += s14 * 654183;
|
||||
s5 -= s14 * 997805;
|
||||
s6 += s14 * 136657;
|
||||
s7 -= s14 * 683901;
|
||||
//s14 = 0;
|
||||
|
||||
s1 += s13 * 666643;
|
||||
s2 += s13 * 470296;
|
||||
s3 += s13 * 654183;
|
||||
s4 -= s13 * 997805;
|
||||
s5 += s13 * 136657;
|
||||
s6 -= s13 * 683901;
|
||||
//s13 = 0;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry11 = s11 >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
//s12 = 0;
|
||||
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
|
||||
s[0] = (s0 >> 0) as u8;
|
||||
s[1] = (s0 >> 8) as u8;
|
||||
s[2] = ((s0 >> 16) | (s1 << 5)) as u8;
|
||||
s[3] = (s1 >> 3) as u8;
|
||||
s[4] = (s1 >> 11) as u8;
|
||||
s[5] = ((s1 >> 19) | (s2 << 2)) as u8;
|
||||
s[6] = (s2 >> 6) as u8;
|
||||
s[7] = ((s2 >> 14) | (s3 << 7)) as u8;
|
||||
s[8] = (s3 >> 1) as u8;
|
||||
s[9] = (s3 >> 9) as u8;
|
||||
s[10] = ((s3 >> 17) | (s4 << 4)) as u8;
|
||||
s[11] = (s4 >> 4) as u8;
|
||||
s[12] = (s4 >> 12) as u8;
|
||||
s[13] = ((s4 >> 20) | (s5 << 1)) as u8;
|
||||
s[14] = (s5 >> 7) as u8;
|
||||
s[15] = ((s5 >> 15) | (s6 << 6)) as u8;
|
||||
s[16] = (s6 >> 2) as u8;
|
||||
s[17] = (s6 >> 10) as u8;
|
||||
s[18] = ((s6 >> 18) | (s7 << 3)) as u8;
|
||||
s[19] = (s7 >> 5) as u8;
|
||||
s[20] = (s7 >> 13) as u8;
|
||||
s[21] = (s8 >> 0) as u8;
|
||||
s[22] = (s8 >> 8) as u8;
|
||||
s[23] = ((s8 >> 16) | (s9 << 5)) as u8;
|
||||
s[24] = (s9 >> 3) as u8;
|
||||
s[25] = (s9 >> 11) as u8;
|
||||
s[26] = ((s9 >> 19) | (s10 << 2)) as u8;
|
||||
s[27] = (s10 >> 6) as u8;
|
||||
s[28] = ((s10 >> 14) | (s11 << 7)) as u8;
|
||||
s[29] = (s11 >> 1) as u8;
|
||||
s[30] = (s11 >> 9) as u8;
|
||||
s[31] = (s11 >> 17) as u8;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn muladd() {
|
||||
let fname = "testdata/ed25519/muladd.test";
|
||||
run_test(fname.to_string(), 4, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
|
||||
assert!(!nega && !negb && !negc && !negd);
|
||||
let mut mine = [0; 32];
|
||||
x25519_sc_muladd(&mut mine, abytes, bbytes, cbytes);
|
||||
for i in 0..32 {
|
||||
assert_eq!(&mine[i], &dbytes[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn curve25519_scalar_mask(a: &mut [u8])
|
||||
{
|
||||
assert_eq!(a.len(), 32);
|
||||
a[0] &= 248;
|
||||
a[31] &= 127;
|
||||
a[31] |= 64;
|
||||
}
|
||||
|
||||
196
src/hmac.rs
Normal file
196
src/hmac.rs
Normal file
@@ -0,0 +1,196 @@
|
||||
//! This module implements the Keyed-Hash Message Authentication Code, or HMAC,
|
||||
//! as defined by NIST 198-1. Now, you might have questions, like:
|
||||
//! * *Where did the 'K' go in the acronym?* I don't know. Maybe we should
|
||||
//! always be saying Keyed-HMAC? It's a mystery.
|
||||
//! * *What is this good for?* I do know the answer to that! HMACs are
|
||||
//! useful when you want to extend the ability of a hash to tell you if
|
||||
//! a message has been modified with the ability to determine if the
|
||||
//! person that sent it had hold of a key. It's thus a version of the
|
||||
//! message signing capability used in asymmetric crypto (`DSA`, `RSA`,
|
||||
//! `ECDSA`, and `ED25519`, as implemented in this crate), but with a
|
||||
//! symmetric key, instead.
|
||||
//!
|
||||
//! Because HMAC can be used with a variety of hash functions, this module
|
||||
//! implements it as a generic structure that takes the associated hash as
|
||||
//! a type argument. This should provide a reasonable level of flexibility,
|
||||
//! while allowing the type system from preventing us from making any number
|
||||
//! of really annoying mistakes. You can specify which of the hash functions
|
||||
//! you want to use by using your standard turbofish:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use simple_crypto::hmac::HMAC;
|
||||
//! use simple_crypto::sha::SHA256;
|
||||
//!
|
||||
//! let key = [0,1,2,3,4]; // very secure
|
||||
//! let msg = [5,6,7,8];
|
||||
//! let hmac = HMAC::<SHA256>::hmac(&key, &msg);
|
||||
//! ```
|
||||
//!
|
||||
//! Much like with `SHAKE128` and `SHAKE256` the interface for HMAC is
|
||||
//! similar to, but not quite, the interface for `Hash`. We thus try to
|
||||
//! copy as much of the standard `Hash` interface as we can, but extend
|
||||
//! `new` with a key, rename `hash` to `hmac`, and extend `hmac` with a
|
||||
//! key as well. This provides a similar ability to use HMACs both in an
|
||||
//! incremental mode as well as just do it all at once, as follows:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use simple_crypto::hmac::HMAC;
|
||||
//! use simple_crypto::sha::SHA256;
|
||||
//!
|
||||
//! let key = [0,1,2,3,4]; // like my suitcase
|
||||
//! let msg = [5,6,7,8];
|
||||
//!
|
||||
//! // Compute the HMAC incrementally
|
||||
//! let mut hmacinc = HMAC::<SHA256>::new(&key);
|
||||
//! hmacinc.update(&[5,6]);
|
||||
//! hmacinc.update(&[7,8]);
|
||||
//! let hmac_incremental = hmacinc.finalize();
|
||||
//!
|
||||
//! // Compute the HMAC all at once
|
||||
//! let hmac_once = HMAC::<SHA256>::hmac(&key, &msg);
|
||||
//!
|
||||
//! // ... which should be the same thing
|
||||
//! assert_eq!(hmac_incremental, hmac_once);
|
||||
//! ```
|
||||
|
||||
/// The HMAC structure, parameterized by its hash function.
|
||||
///
|
||||
/// Much like with `SHAKE128` and `SHAKE256` the interface for HMAC is
|
||||
/// similar to, but not quite, the interface for `Hash`. We thus try to
|
||||
/// copy as much of the standard `Hash` interface as we can, but extend
|
||||
/// `new` with a key, rename `hash` to `hmac`, and extend `hmac` with a
|
||||
/// key as well. This provides a similar ability to use HMACs both in an
|
||||
/// incremental mode as well as just do it all at once, as follows:
|
||||
///
|
||||
/// ```rust
|
||||
/// use simple_crypto::hmac::HMAC;
|
||||
/// use simple_crypto::sha::SHA256;
|
||||
///
|
||||
/// let key = [0,1,2,3,4]; // like my suitcase
|
||||
/// let msg = [5,6,7,8];
|
||||
///
|
||||
/// // Compute the HMAC incrementally
|
||||
/// let mut hmacinc = HMAC::<SHA256>::new(&key);
|
||||
/// hmacinc.update(&[5,6]);
|
||||
/// hmacinc.update(&[7,8]);
|
||||
/// let hmac_incremental = hmacinc.finalize();
|
||||
///
|
||||
/// // Compute the HMAC all at once
|
||||
/// let hmac_once = HMAC::<SHA256>::hmac(&key, &msg);
|
||||
///
|
||||
/// // ... which should be the same thing
|
||||
/// assert_eq!(hmac_incremental, hmac_once);
|
||||
/// ```
|
||||
use super::Hash;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct HMAC<H: Hash + Clone> {
|
||||
ipad_hash: H,
|
||||
opad_hash: H,
|
||||
result: Option<Vec<u8>>
|
||||
}
|
||||
|
||||
impl<H: Hash + Clone> HMAC<H> {
|
||||
/// Generate a new HMAC construction for the provide underlying hash
|
||||
/// function, and prep it to start taking input via the `update`
|
||||
/// method.
|
||||
pub fn new(inkey: &[u8]) -> Self {
|
||||
let hash_blocklen_bytes = H::block_size() / 8;
|
||||
|
||||
// If the input key is longer than the hash block length, then we
|
||||
// immediately hash it down to be the block length. Otherwise, we
|
||||
// leave it be.
|
||||
let mut key = if inkey.len() > hash_blocklen_bytes { H::hash(inkey) }
|
||||
else { inkey.to_vec() };
|
||||
// It may now be too small, or have started too small, in which case
|
||||
// we pad it out with zeros.
|
||||
key.resize(hash_blocklen_bytes, 0);
|
||||
// Generate the inner and outer key pad from this key.
|
||||
let o_key_pad: Vec<u8> = key.iter().map(|x| *x ^ 0x5c).collect();
|
||||
let i_key_pad: Vec<u8> = key.iter().map(|x| *x ^ 0x36).collect();
|
||||
// Now we can start the hashes; obviously we'll have to wait
|
||||
// until we get the rest of the message to complete them.
|
||||
let mut ipad_hash = H::new();
|
||||
ipad_hash.update(&i_key_pad);
|
||||
let mut opad_hash = H::new();
|
||||
opad_hash.update(&o_key_pad);
|
||||
let result = None;
|
||||
HMAC { ipad_hash, opad_hash, result }
|
||||
}
|
||||
|
||||
/// Add more data as part of the HMAC computation. This can be called
|
||||
/// zero or more times over the lifetime of the HMAC structure. That
|
||||
/// being said, once you call `finalize`, this structure is done, and
|
||||
/// it will ignore further calls to `update`.
|
||||
pub fn update(&mut self, buffer: &[u8])
|
||||
{
|
||||
if self.result.is_none() {
|
||||
self.ipad_hash.update(&buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/// Provide the final HMAC value for the bitrstream as read. This shifts
|
||||
/// this structure into a final mode, in which it will ignore any more
|
||||
/// data provided to it from `update`. You can, however, call `finalize`
|
||||
/// more than once; the HMAC structure caches the return value and will
|
||||
/// return it as many times as you like.
|
||||
pub fn finalize(&mut self) -> Vec<u8>
|
||||
{
|
||||
if let Some(ref res) = self.result {
|
||||
res.clone()
|
||||
} else {
|
||||
self.opad_hash.update(&self.ipad_hash.finalize());
|
||||
let res = self.opad_hash.finalize();
|
||||
self.result = Some(res.clone());
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
/// A useful method for those situations in which you have only one block
|
||||
/// of data to generate an HMAC for. Runs `new`, `update`, and `finalize`
|
||||
/// for you, in order.
|
||||
pub fn hmac(key: &[u8], val: &[u8]) -> Vec<u8>
|
||||
{
|
||||
let mut h = Self::new(key);
|
||||
h.update(val);
|
||||
h.finalize()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use sha::{SHA1,SHA224,SHA256,SHA384,SHA512};
|
||||
#[cfg(test)]
|
||||
use testing::run_test;
|
||||
#[cfg(test)]
|
||||
use cryptonum::unsigned::{Decoder,U192};
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn nist_vectors() {
|
||||
let fname = "testdata/sha/hmac.test";
|
||||
run_test(fname.to_string(), 6, |case| {
|
||||
let (negh, hbytes) = case.get("h").unwrap();
|
||||
let (negr, rbytes) = case.get("r").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negk, kbytes) = case.get("k").unwrap();
|
||||
let (negl, lbytes) = case.get("l").unwrap();
|
||||
let (negt, tbytes) = case.get("t").unwrap();
|
||||
|
||||
assert!(!negh && !negr && !negm && !negk && !negl && !negt);
|
||||
let l = usize::from(U192::from_bytes(lbytes));
|
||||
let h = usize::from(U192::from_bytes(hbytes));
|
||||
assert_eq!(l, kbytes.len());
|
||||
let mut res = match h {
|
||||
160 => HMAC::<SHA1>::hmac(&kbytes, &mbytes),
|
||||
224 => HMAC::<SHA224>::hmac(&kbytes, &mbytes),
|
||||
256 => HMAC::<SHA256>::hmac(&kbytes, &mbytes),
|
||||
384 => HMAC::<SHA384>::hmac(&kbytes, &mbytes),
|
||||
512 => HMAC::<SHA512>::hmac(&kbytes, &mbytes),
|
||||
_ => panic!("Weird hash size in HMAC test file")
|
||||
};
|
||||
let t = usize::from(U192::from_bytes(tbytes));
|
||||
res.resize(t, 0);
|
||||
assert_eq!(rbytes, &res);
|
||||
});
|
||||
}
|
||||
|
||||
92
src/lib.rs
92
src/lib.rs
@@ -1,4 +1,3 @@
|
||||
#![feature(i128_type)]
|
||||
//! # Simple Crypto: A quaint little crypto library for rust.
|
||||
//!
|
||||
//! This is the simple_crypto library. Its goal is to provide straightforward
|
||||
@@ -10,31 +9,92 @@
|
||||
//! that a new user should use, along with documentation regarding how and
|
||||
//! when they should use it, and examples. For now, it mostly just fowards
|
||||
//! off to more detailed modules. Help requested!
|
||||
|
||||
extern crate base64;
|
||||
extern crate byteorder;
|
||||
extern crate digest;
|
||||
extern crate chrono;
|
||||
extern crate cryptonum;
|
||||
extern crate num;
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
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 at fixed,
|
||||
/// cryptographically-relevant sizes.
|
||||
pub mod cryptonum;
|
||||
/// The RSA module performs the basic operations for RSA, and should
|
||||
/// be used directly only if you're fairly confident about what you're
|
||||
/// doing.
|
||||
/// The `rsa` module provides bare-bones support for RSA signing, verification,
|
||||
/// encryption, decryption, and key generation.
|
||||
pub mod rsa;
|
||||
/// The `dsa` module provides bare-bones support for DSA signing, verification,
|
||||
/// and key generation. You shouldn't need to use these if you're building a
|
||||
/// new system, but might need to use them to interact with legacy systems or
|
||||
/// protocols.
|
||||
pub mod dsa;
|
||||
/// The `ecdsa` module provides bare-bones support for ECDSA signing,
|
||||
/// verification, and key generation.
|
||||
pub mod ecdsa;
|
||||
/// The `ed25519` provides signing and verification using ED25519.
|
||||
pub mod ed25519;
|
||||
/// The `ssh` module provides support for parsing OpenSSH-formatted SSH keys,
|
||||
/// both public and private.
|
||||
pub mod ssh;
|
||||
/// The `shake` module provides support for SHAKE128 and SHAKE256, two
|
||||
/// variable-length hash functions that derive from the same core hash
|
||||
/// as SHA3.
|
||||
pub mod shake;
|
||||
/// The `hmac` module provides support for keyed-hash message authentication,
|
||||
/// or HMAC, based on any of the hash functions defined in this module.
|
||||
pub mod hmac;
|
||||
/// The `x509` module supports parsing and generating x.509 certificates, as
|
||||
/// used by TLS and others.
|
||||
pub mod x509;
|
||||
/// An implementation of the SHA family of hashes, including the relatively
|
||||
/// weak SHA1 and a bunch of hashes you should use, like the SHA2 and SHA3
|
||||
/// hashes.
|
||||
pub mod sha;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
/// A generic trait for defining what a key pair looks like. This is useful
|
||||
/// in a couple places in which we want to define code regardless of the
|
||||
/// kind of key it is, but is unlikely to be hugely useful to users of the
|
||||
/// library.
|
||||
pub trait KeyPair {
|
||||
/// The type of the public key of this pair.
|
||||
type Public;
|
||||
/// The type of the private key of this pair.
|
||||
type Private;
|
||||
|
||||
#[test]
|
||||
fn testing_works() {
|
||||
assert!(true);
|
||||
/// Generate a key pair given the provided public and private keys.
|
||||
fn new(pbl: Self::Public, prv: Self::Private) -> Self;
|
||||
}
|
||||
|
||||
/// A generic trait for defining a hash function.
|
||||
pub trait Hash: Sized
|
||||
{
|
||||
/// Generate a fresh instance of this hash function, set to the
|
||||
/// appropriate initial state.
|
||||
fn new() -> Self;
|
||||
/// Update the hash function with some more data for it to chew on.
|
||||
/// Nom nom nom. If you give it more information after calling
|
||||
/// `finalize`, the implementation is welcome to do anything it
|
||||
/// wants; mostly they will just ignore additional data, but
|
||||
/// maybe just don't do that.
|
||||
fn update(&mut self, data: &[u8]);
|
||||
/// Finalize the hash function, returning the hash value.
|
||||
fn finalize(&mut self) -> Vec<u8>;
|
||||
/// Return the block size of the underlying hash function, in
|
||||
/// bits. This is mostly useful internally to this crate.
|
||||
fn block_size() -> usize;
|
||||
|
||||
/// This is a convenience routine that runs new(), update(), and
|
||||
/// finalize() on a piece of data all at once. Because that's
|
||||
/// mostly what people want to do.
|
||||
fn hash(data: &[u8]) -> Vec<u8>
|
||||
{
|
||||
let mut x = Self::new();
|
||||
x.update(&data);
|
||||
x.finalize()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod testing;
|
||||
mod utils;
|
||||
|
||||
@@ -1,10 +1,25 @@
|
||||
use cryptonum::{CryptoNumModOps};
|
||||
use num::BigUint;
|
||||
use cryptonum::unsigned::*;
|
||||
use num::bigint::BigUint;
|
||||
use rsa::errors::RSAError;
|
||||
use simple_asn1::{ASN1DecodeErr,ASN1Block};
|
||||
use simple_asn1::{ASN1Block,ASN1DecodeErr};
|
||||
|
||||
// encoding PKCS1 stuff
|
||||
pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec<u8> {
|
||||
/// A valid key size for RSA keys, basically, and a (slightly annoying)
|
||||
/// trait that is used to tie these types to their Barrett value types.
|
||||
pub trait RSAMode {
|
||||
type Barrett;
|
||||
}
|
||||
|
||||
impl RSAMode for U512 { type Barrett = BarrettU512; }
|
||||
impl RSAMode for U1024 { type Barrett = BarrettU1024; }
|
||||
impl RSAMode for U2048 { type Barrett = BarrettU2048; }
|
||||
impl RSAMode for U3072 { type Barrett = BarrettU3072; }
|
||||
impl RSAMode for U4096 { type Barrett = BarrettU4096; }
|
||||
impl RSAMode for U8192 { type Barrett = BarrettU8192; }
|
||||
impl RSAMode for U15360 { type Barrett = BarrettU15360; }
|
||||
|
||||
|
||||
pub fn 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);
|
||||
@@ -12,26 +27,25 @@ 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
|
||||
}
|
||||
|
||||
// the RSA encryption function
|
||||
pub fn ep<U: CryptoNumModOps>(n: &U, e: &U, m: &U) -> U {
|
||||
m.modexp(e, n)
|
||||
pub fn drop0s(a: &[u8]) -> &[u8] {
|
||||
let mut idx = 0;
|
||||
|
||||
while (idx < a.len()) && (a[idx] == 0) {
|
||||
idx = idx + 1;
|
||||
}
|
||||
|
||||
&a[idx..]
|
||||
}
|
||||
|
||||
// the RSA decryption function
|
||||
pub fn dp<U: CryptoNumModOps>(n: &U, d: &U, c: &U) -> U {
|
||||
c.modexp(d, n)
|
||||
}
|
||||
|
||||
// the RSA signature generation function
|
||||
pub fn sp1<U: CryptoNumModOps>(n: &U, d: &U, m: &U) -> U {
|
||||
m.modexp(d, n)
|
||||
pub fn xor_vecs(a: &Vec<u8>, b: &Vec<u8>) -> Vec<u8> {
|
||||
a.iter().zip(b.iter()).map(|(a,b)| a^b).collect()
|
||||
}
|
||||
|
||||
pub fn decode_biguint(b: &ASN1Block) -> Result<BigUint,RSAError> {
|
||||
@@ -48,12 +62,3 @@ pub fn decode_biguint(b: &ASN1Block) -> Result<BigUint,RSAError> {
|
||||
}
|
||||
|
||||
|
||||
// the RSA signature verification function
|
||||
pub fn vp1<U: CryptoNumModOps>(n: &U, e: &U, s: &U) -> U {
|
||||
s.modexp(e, n)
|
||||
}
|
||||
|
||||
pub fn xor_vecs(a: &Vec<u8>, b: &Vec<u8>) -> Vec<u8> {
|
||||
a.iter().zip(b.iter()).map(|(a,b)| a^b).collect()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
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 simple_asn1::ASN1DecodeErr;
|
||||
use rand;
|
||||
|
||||
/// A bunch of errors that you can get generating, reading, or
|
||||
/// writing RSA keys.
|
||||
#[derive(Debug)]
|
||||
pub enum RSAError {
|
||||
BadMessageSize,
|
||||
@@ -19,13 +10,12 @@ pub enum RSAError {
|
||||
DecryptionError,
|
||||
DecryptHashMismatch,
|
||||
InvalidKey,
|
||||
KeySizeMismatch,
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
523
src/rsa/mod.rs
523
src/rsa/mod.rs
@@ -1,10 +1,54 @@
|
||||
//! # An implementation of RSA.
|
||||
//! A simple RSA library.
|
||||
//!
|
||||
//! This module is designed to provide implementations of the core routines
|
||||
//! used for asymmetric cryptography using RSA. It probably provides a bit
|
||||
//! more flexibility than beginners should play with, and definitely includes
|
||||
//! some capabilities largely targeted at legacy systems. New users should
|
||||
//! probably stick with the stuff in the root of this crate.
|
||||
//! This library performs all the standard bits and pieces that you'd expect
|
||||
//! from an RSA library, and does so using only Rust. It's a bit slow at the
|
||||
//! moment, but it gets the job done.
|
||||
//!
|
||||
//! Key generation is supported, using either the native `OsRng` or a random
|
||||
//! number generator of your choice. Obviously, you should be careful to use
|
||||
//! a cryptographically-sound random number generator sufficient for the
|
||||
//! security level you're going for.
|
||||
//!
|
||||
//! Signing and verification are via standard PKCS1 padding, but can be
|
||||
//! adjusted based on the exact hash you want. This library also supports
|
||||
//! somewhat arbitrary signing mechanisms used by your weirder network
|
||||
//! protocols. (I'm looking at you, Tor.)
|
||||
//!
|
||||
//! Encryption and decryption are via the OAEP mechanism, as described in
|
||||
//! NIST documents.
|
||||
//!
|
||||
//! The following is an example of generating an RSA2048 key pair, then using
|
||||
//! it to sign, verify, encrypt, and decrypt some data.
|
||||
//!
|
||||
//! ```rust
|
||||
//! extern crate cryptonum;
|
||||
//!
|
||||
//! use simple_crypto::rsa::RSAKeyPair;
|
||||
//! use simple_crypto::rsa::SIGNING_HASH_SHA256;
|
||||
//! use simple_crypto::rsa::OAEPParams;
|
||||
//! use simple_crypto::sha::SHA256;
|
||||
//! use cryptonum::unsigned::U2048;
|
||||
//!
|
||||
//! // Generate a new RSA with key size 2048. (This is an acceptable but
|
||||
//! // not great key size, but is a nice compromise given that this little
|
||||
//! // example runs as part of the test suite.)
|
||||
//! let mut rng = rand::rngs::OsRng::new().unwrap();
|
||||
//! let kp = RSAKeyPair::<U2048>::generate(&mut rng);
|
||||
//!
|
||||
//! // Now that you have this key pair, you can sign and verify messages
|
||||
//! // using it. For example, to sign the vector [0,1,2,3,4] with SHA256
|
||||
//! // and then verify that signature, we would write:
|
||||
//! let msg = vec![0,1,2,3,4];
|
||||
//! let sig = kp.private.sign(&SIGNING_HASH_SHA256, &msg);
|
||||
//! assert!( kp.public.verify(&SIGNING_HASH_SHA256, &msg, &sig) );
|
||||
//!
|
||||
//! // We can also use RSA public keys to encrypt data, which can then be
|
||||
//! // decrypted by the private key.
|
||||
//! let params = OAEPParams::<SHA256>::new(String::from("example!"));
|
||||
//! let cipher = kp.public.encrypt(¶ms, &msg).expect("Encryption error");
|
||||
//! let msg2 = kp.private.decrypt(¶ms, &cipher).expect("Decryption error");
|
||||
//! assert_eq!(msg, msg2);
|
||||
//! ```
|
||||
mod core;
|
||||
mod errors;
|
||||
mod oaep;
|
||||
@@ -12,217 +56,284 @@ mod private;
|
||||
mod public;
|
||||
mod signing_hashes;
|
||||
|
||||
use cryptonum::*;
|
||||
use rand::{OsRng,Rng};
|
||||
use std::cmp::PartialOrd;
|
||||
use std::ops::*;
|
||||
|
||||
pub use self::errors::{RSAKeyGenError,RSAError};
|
||||
pub use self::oaep::{OAEPParams};
|
||||
pub use self::private::RSAPrivateKey;
|
||||
pub use self::public::RSAPublicKey;
|
||||
pub use self::core::RSAMode;
|
||||
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};
|
||||
pub use self::public::{RSAPublic, RSAPublicKey};
|
||||
use cryptonum::signed::{EGCD,ModInv};
|
||||
use cryptonum::unsigned::{CryptoNum,PrimeGen};
|
||||
use cryptonum::unsigned::{U256,U512,U1024,U1536,U2048,U3072,U4096,U7680,U8192,U15360};
|
||||
use rand::RngCore;
|
||||
#[cfg(test)]
|
||||
use std::fmt;
|
||||
use std::ops::Sub;
|
||||
use super::KeyPair;
|
||||
|
||||
/// An RSA public and private key.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct RSAKeyPair<Size>
|
||||
fn diff<T>(a: &T, b: &T) -> T
|
||||
where
|
||||
Size: CryptoNumBase + CryptoNumSerialization
|
||||
{
|
||||
pub private: RSAPrivateKey<Size>,
|
||||
pub public: RSAPublicKey<Size>
|
||||
}
|
||||
|
||||
impl<T> RSAKeyPair<T>
|
||||
where
|
||||
T: Clone + Sized + PartialOrd + From<u64>,
|
||||
T: CryptoNumBase + CryptoNumModOps + CryptoNumPrimes + CryptoNumSerialization,
|
||||
T: Sub<Output=T> + Mul<Output=T> + Shl<usize,Output=T>
|
||||
{
|
||||
/// Generates a fresh RSA key pair. 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() -> Result<RSAKeyPair<T>,RSAKeyGenError> {
|
||||
let mut rng = OsRng::new()?;
|
||||
RSAKeyPair::<T>::generate_w_rng(&mut rng)
|
||||
}
|
||||
|
||||
/// 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)
|
||||
-> Result<RSAKeyPair<T>,RSAKeyGenError>
|
||||
{
|
||||
let e = T::from(65537);
|
||||
let len_bits = e.bit_size();
|
||||
match generate_pq(rng, &e) {
|
||||
None =>
|
||||
return Err(RSAKeyGenError::InvalidKeySize(len_bits)),
|
||||
Some((p, q)) => {
|
||||
let n = p.clone() * q.clone();
|
||||
let phi = (p - T::from(1)) * (q - T::from(1));
|
||||
let d = e.modinv(&phi);
|
||||
let public_key = RSAPublicKey::new(n.clone(), e);
|
||||
let private_key = RSAPrivateKey::new(n, d);
|
||||
return Ok(RSAKeyPair{ private: private_key, public: public_key })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_pq<'a,G,T>(rng: &mut G, e: &T) -> Option<(T,T)>
|
||||
where
|
||||
G: Rng,
|
||||
T: Clone + PartialOrd + Shl<usize,Output=T> + Sub<Output=T> + From<u64>,
|
||||
T: CryptoNumBase + CryptoNumPrimes + CryptoNumSerialization
|
||||
{
|
||||
let bitlen = T::zero().bit_size();
|
||||
let mindiff = T::from(1) << ((bitlen/2)-101);
|
||||
let minval = T::from(6074001000) << ((mindiff.bit_size()/2) - 33);
|
||||
let p = T::generate_prime(rng, 7, e, &minval);
|
||||
|
||||
loop {
|
||||
let q = T::generate_prime(rng, 7, e, &minval);
|
||||
|
||||
if diff(p.clone(), q.clone()) >= mindiff {
|
||||
return Some((p, q));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn diff<T: PartialOrd + Sub<Output=T>>(a: T, b: T) -> T
|
||||
T: Clone + PartialOrd,
|
||||
T: Sub<T,Output=T>
|
||||
{
|
||||
if a > b {
|
||||
a - b
|
||||
a.clone() - b.clone()
|
||||
} else {
|
||||
b - a
|
||||
b.clone() - a.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// An RSA key pair containing keys of the given size; keeping them in the
|
||||
/// type means you'll never forget which one you have.
|
||||
///
|
||||
/// As an aside:
|
||||
/// * `U512` should only be used for testing
|
||||
/// * `U1024` should only be used to support old protocols or devices
|
||||
/// * `U2048` is probably your bare minimum
|
||||
/// * `U3072` is a very reasonable choice
|
||||
/// * **`U4096` is what you should use**
|
||||
/// * `U8192` is starting to get a bit silly (and slow)
|
||||
/// * `U15360` is for when you're using encryption to heat your house or server room
|
||||
pub struct RSAKeyPair<R: RSAMode> {
|
||||
pub public: RSAPublicKey<R>,
|
||||
pub private: RSAPrivateKey<R>
|
||||
}
|
||||
|
||||
/// A generic RSA key pair that is agnostic about its key size. It's not
|
||||
/// totally clear why this is useful, at this point.
|
||||
#[derive(PartialEq)]
|
||||
pub enum RSAPair {
|
||||
R512(RSAPublicKey<U512>, RSAPrivateKey<U512>),
|
||||
R1024(RSAPublicKey<U1024>, RSAPrivateKey<U1024>),
|
||||
R2048(RSAPublicKey<U2048>, RSAPrivateKey<U2048>),
|
||||
R3072(RSAPublicKey<U3072>, RSAPrivateKey<U3072>),
|
||||
R4096(RSAPublicKey<U4096>, RSAPrivateKey<U4096>),
|
||||
R8192(RSAPublicKey<U8192>, RSAPrivateKey<U8192>),
|
||||
R15360(RSAPublicKey<U15360>, RSAPrivateKey<U15360>),
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use rsa::core::{dp,ep,sp1,vp1};
|
||||
use sha2::Sha224;
|
||||
use simple_asn1::{der_decode,der_encode};
|
||||
use super::*;
|
||||
|
||||
impl Arbitrary for RSAKeyPair<U512> {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> RSAKeyPair<U512> {
|
||||
RSAKeyPair::generate_w_rng(g).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
// Core primitive checks
|
||||
quickcheck! {
|
||||
fn ep_dp_inversion(kp: RSAKeyPair<U512>, m: U512) -> bool {
|
||||
let realm = &m % &kp.public.n;
|
||||
let ciphertext = ep(&kp.public.n, &kp.public.e, &realm);
|
||||
let mprime = dp(&kp.private.n, &kp.private.d, &ciphertext);
|
||||
mprime == m
|
||||
}
|
||||
fn sp_vp_inversion(kp: RSAKeyPair<U512>, m: U512) -> bool {
|
||||
let realm = &m % &kp.public.n;
|
||||
let sig = sp1(&kp.private.n, &kp.private.d, &realm);
|
||||
let mprime = vp1(&kp.public.n, &kp.public.e, &sig);
|
||||
mprime == m
|
||||
}
|
||||
}
|
||||
|
||||
// Public key serialization
|
||||
quickcheck! {
|
||||
fn asn1_encoding_inverts(kp: RSAKeyPair<U512>) -> bool {
|
||||
let bytes = der_encode(&kp.public).unwrap();
|
||||
let pubkey: RSAPublicKey<U512> = der_decode(&bytes).unwrap();
|
||||
(pubkey.n == kp.public.n) && (pubkey.e == kp.public.e)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
struct Message {
|
||||
m: Vec<u8>
|
||||
}
|
||||
|
||||
impl Arbitrary for Message {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> Message {
|
||||
let len = 1 + (g.gen::<u8>() % 3);
|
||||
let mut storage = Vec::new();
|
||||
for _ in 0..len {
|
||||
storage.push(g.gen::<u8>());
|
||||
}
|
||||
Message{ m: storage }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
struct KeyPairAndSigHash<T>
|
||||
where
|
||||
T: CryptoNumSerialization + CryptoNumBase
|
||||
impl fmt::Debug for RSAPair {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
|
||||
{
|
||||
kp: RSAKeyPair<T>,
|
||||
sh: &'static SigningHash
|
||||
}
|
||||
|
||||
impl<T> Arbitrary for KeyPairAndSigHash<T>
|
||||
where
|
||||
T: Clone + Sized + PartialOrd + From<u64>,
|
||||
T: CryptoNumBase + CryptoNumModOps,
|
||||
T: CryptoNumPrimes + CryptoNumSerialization,
|
||||
T: Sub<Output=T> + Mul<Output=T> + Shl<usize,Output=T>,
|
||||
RSAKeyPair<T>: Arbitrary
|
||||
{
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> KeyPairAndSigHash<T> {
|
||||
let kp = RSAKeyPair::generate_w_rng(g).unwrap();
|
||||
let size = kp.public.n.bit_size();
|
||||
let mut hashes = vec![&SIGNING_HASH_SHA1];
|
||||
|
||||
if size >= 1024 {
|
||||
hashes.push(&SIGNING_HASH_SHA224);
|
||||
}
|
||||
|
||||
if size >= 2048 {
|
||||
hashes.push(&SIGNING_HASH_SHA256);
|
||||
}
|
||||
|
||||
if size >= 4096 {
|
||||
hashes.push(&SIGNING_HASH_SHA384);
|
||||
hashes.push(&SIGNING_HASH_SHA512);
|
||||
}
|
||||
|
||||
let hash = g.choose(&hashes).unwrap().clone();
|
||||
KeyPairAndSigHash{ kp: kp, sh: hash }
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn sign_verifies(kpsh: KeyPairAndSigHash<U512>, m: Message) -> bool {
|
||||
let sig = kpsh.kp.private.sign(kpsh.sh, &m.m);
|
||||
kpsh.kp.public.verify(kpsh.sh, &m.m, &sig)
|
||||
}
|
||||
|
||||
fn enc_dec_roundtrips(kp: RSAKeyPair<U512>, m: Message) -> bool {
|
||||
let oaep = OAEPParams {
|
||||
hash: Sha224::default(),
|
||||
label: "test".to_string()
|
||||
};
|
||||
let c = kp.public.encrypt(&oaep, &m.m).unwrap();
|
||||
let mp = kp.private.decrypt(&oaep, &c).unwrap();
|
||||
|
||||
mp == m.m
|
||||
match self {
|
||||
RSAPair::R512(_,_) => f.write_str("512-bit RSA key pair"),
|
||||
RSAPair::R1024(_,_) => f.write_str("1024-bit RSA key pair"),
|
||||
RSAPair::R2048(_,_) => f.write_str("2048-bit RSA key pair"),
|
||||
RSAPair::R3072(_,_) => f.write_str("3072-bit RSA key pair"),
|
||||
RSAPair::R4096(_,_) => f.write_str("4096-bit RSA key pair"),
|
||||
RSAPair::R8192(_,_) => f.write_str("8192-bit RSA key pair"),
|
||||
RSAPair::R15360(_,_) => f.write_str("15360-bit RSA key pair"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyPair for RSAPair {
|
||||
type Public = RSAPublic;
|
||||
type Private = RSAPrivate;
|
||||
|
||||
fn new(pu: RSAPublic, pr: RSAPrivate) -> RSAPair
|
||||
{
|
||||
match (pu, pr) {
|
||||
(RSAPublic::Key512(pbl), RSAPrivate::Key512(prv)) =>
|
||||
RSAPair::R512(pbl, prv),
|
||||
(RSAPublic::Key1024(pbl), RSAPrivate::Key1024(prv)) =>
|
||||
RSAPair::R1024(pbl, prv),
|
||||
(RSAPublic::Key2048(pbl), RSAPrivate::Key2048(prv)) =>
|
||||
RSAPair::R2048(pbl, prv),
|
||||
(RSAPublic::Key3072(pbl), RSAPrivate::Key3072(prv)) =>
|
||||
RSAPair::R3072(pbl, prv),
|
||||
(RSAPublic::Key4096(pbl), RSAPrivate::Key4096(prv)) =>
|
||||
RSAPair::R4096(pbl, prv),
|
||||
(RSAPublic::Key8192(pbl), RSAPrivate::Key8192(prv)) =>
|
||||
RSAPair::R8192(pbl, prv),
|
||||
(RSAPublic::Key15360(pbl), RSAPrivate::Key15360(prv)) =>
|
||||
RSAPair::R15360(pbl, prv),
|
||||
_ =>
|
||||
panic!("Unmatched public/private arguments to RSAPair::new()")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RSAPair {
|
||||
pub fn sign(&self, signhash: &SigningHash, msg: &[u8]) -> Vec<u8>
|
||||
{
|
||||
match self {
|
||||
RSAPair::R512(_,prv) => prv.sign(signhash, msg),
|
||||
RSAPair::R1024(_,prv) => prv.sign(signhash, msg),
|
||||
RSAPair::R2048(_,prv) => prv.sign(signhash, msg),
|
||||
RSAPair::R3072(_,prv) => prv.sign(signhash, msg),
|
||||
RSAPair::R4096(_,prv) => prv.sign(signhash, msg),
|
||||
RSAPair::R8192(_,prv) => prv.sign(signhash, msg),
|
||||
RSAPair::R15360(_,prv) => prv.sign(signhash, msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool
|
||||
{
|
||||
match self {
|
||||
RSAPair::R512(pbl,_) => pbl.verify(signhash, msg, sig),
|
||||
RSAPair::R1024(pbl,_) => pbl.verify(signhash, msg, sig),
|
||||
RSAPair::R2048(pbl,_) => pbl.verify(signhash, msg, sig),
|
||||
RSAPair::R3072(pbl,_) => pbl.verify(signhash, msg, sig),
|
||||
RSAPair::R4096(pbl,_) => pbl.verify(signhash, msg, sig),
|
||||
RSAPair::R8192(pbl,_) => pbl.verify(signhash, msg, sig),
|
||||
RSAPair::R15360(pbl,_) => pbl.verify(signhash, msg, sig),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn public(&self) -> RSAPublic
|
||||
{
|
||||
match self {
|
||||
&RSAPair::R512(ref pbl,_) => RSAPublic::Key512(pbl.clone()),
|
||||
&RSAPair::R1024(ref pbl,_) => RSAPublic::Key1024(pbl.clone()),
|
||||
&RSAPair::R2048(ref pbl,_) => RSAPublic::Key2048(pbl.clone()),
|
||||
&RSAPair::R3072(ref pbl,_) => RSAPublic::Key3072(pbl.clone()),
|
||||
&RSAPair::R4096(ref pbl,_) => RSAPublic::Key4096(pbl.clone()),
|
||||
&RSAPair::R8192(ref pbl,_) => RSAPublic::Key8192(pbl.clone()),
|
||||
&RSAPair::R15360(ref pbl,_) => RSAPublic::Key15360(pbl.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn private(&self) -> RSAPrivate
|
||||
{
|
||||
match self {
|
||||
&RSAPair::R512(_,ref prv) => RSAPrivate::Key512(prv.clone()),
|
||||
&RSAPair::R1024(_,ref prv) => RSAPrivate::Key1024(prv.clone()),
|
||||
&RSAPair::R2048(_,ref prv) => RSAPrivate::Key2048(prv.clone()),
|
||||
&RSAPair::R3072(_,ref prv) => RSAPrivate::Key3072(prv.clone()),
|
||||
&RSAPair::R4096(_,ref prv) => RSAPrivate::Key4096(prv.clone()),
|
||||
&RSAPair::R8192(_,ref prv) => RSAPrivate::Key8192(prv.clone()),
|
||||
&RSAPair::R15360(_,ref prv) => RSAPrivate::Key15360(prv.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_rsa_pair
|
||||
{
|
||||
($uint: ident, $half: ident, $iterations: expr) => {
|
||||
impl KeyPair for RSAKeyPair<$uint> {
|
||||
type Public = RSAPublicKey<$uint>;
|
||||
type Private = RSAPrivateKey<$uint>;
|
||||
|
||||
fn new(pu: RSAPublicKey<$uint>, pr: RSAPrivateKey<$uint>) -> RSAKeyPair<$uint> {
|
||||
RSAKeyPair {
|
||||
public: pu,
|
||||
private: pr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RSAKeyPair<$uint> {
|
||||
pub fn generate<G>(rng: &mut G) -> RSAKeyPair<$uint>
|
||||
where G: RngCore
|
||||
{
|
||||
loop {
|
||||
let ebase = 65537u32;
|
||||
let e = $uint::from(ebase);
|
||||
let (p, q) = RSAKeyPair::<$uint>::generate_pq(rng, &$half::from(ebase));
|
||||
let one = $half::from(1u32);
|
||||
let pminus1 = &p - &one;
|
||||
let qminus1 = &q - &one;
|
||||
let phi = pminus1 * qminus1;
|
||||
let n = &p * &q;
|
||||
if let Some(d) = e.modinv(&phi) {
|
||||
let public = RSAPublicKey::<$uint>::new(n.clone(), e);
|
||||
let private = RSAPrivateKey::<$uint>::new(n, d);
|
||||
return RSAKeyPair::<$uint>::new(public, private);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_pq<G>(rng: &mut G, e: &$half) -> ($half, $half)
|
||||
where G: RngCore
|
||||
{
|
||||
let sqrt2_32 = 6074001000u64;
|
||||
let half_bitlen = $half::bit_length();
|
||||
let minval = $half::from(sqrt2_32) << (half_bitlen - 33);
|
||||
let mindiff = $half::from(1u64) << (half_bitlen - 101);
|
||||
let p = $half::random_primef(rng, $iterations, |x| {
|
||||
if (x >= minval) && x.gcd_is_one(e) {
|
||||
Some(x)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
loop {
|
||||
let q = $half::random_primef(rng, $iterations, |x| {
|
||||
if (x >= minval) && x.gcd_is_one(e) {
|
||||
Some(x)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
if diff(&p, &q) >= mindiff {
|
||||
return (p, q);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generate_rsa_pair!(U512, U256, 7);
|
||||
generate_rsa_pair!(U1024, U512, 7);
|
||||
generate_rsa_pair!(U2048, U1024, 4);
|
||||
generate_rsa_pair!(U3072, U1536, 3);
|
||||
generate_rsa_pair!(U4096, U2048, 3);
|
||||
generate_rsa_pair!(U8192, U4096, 3);
|
||||
generate_rsa_pair!(U15360, U7680, 3);
|
||||
|
||||
#[cfg(test)]
|
||||
mod generation {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use std::fmt;
|
||||
use super::*;
|
||||
|
||||
impl Clone for RSAKeyPair<U512> {
|
||||
fn clone(&self) -> RSAKeyPair<U512> {
|
||||
RSAKeyPair {
|
||||
public: RSAPublicKey {
|
||||
n: self.public.n.clone(),
|
||||
nu: self.public.nu.clone(),
|
||||
e: self.public.e.clone(),
|
||||
},
|
||||
private: RSAPrivateKey {
|
||||
nu: self.private.nu.clone(),
|
||||
d: self.private.d.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for RSAKeyPair<U512> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("RSA512KeyPair")
|
||||
.field("n", &self.public.n)
|
||||
.field("e", &self.public.e)
|
||||
.field("d", &self.private.d)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for RSAKeyPair<U512> {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> RSAKeyPair<U512> {
|
||||
RSAKeyPair::<U512>::generate(g)
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn generate_and_sign(keypair: RSAKeyPair<U512>, msg: Vec<u8>) -> bool {
|
||||
let sig = keypair.private.sign(&SIGNING_HASH_SHA256, &msg);
|
||||
keypair.public.verify(&SIGNING_HASH_SHA256, &msg, &sig)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +1,43 @@
|
||||
use byteorder::{BigEndian,ByteOrder};
|
||||
use digest::{FixedOutput,Input};
|
||||
use sha::Hash;
|
||||
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),
|
||||
/// 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
|
||||
pub struct OAEPParams<H: Hash> {
|
||||
pub label: String,
|
||||
phantom: PhantomData<H>
|
||||
}
|
||||
|
||||
impl<H: Clone + Input + FixedOutput> OAEPParams<H> {
|
||||
pub fn new(hash: H, label: String)
|
||||
impl<H: Hash> 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::hash(&[]).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::hash(input)
|
||||
}
|
||||
|
||||
pub fn mgf1(&self, input: &[u8], len: usize) -> Vec<u8> {
|
||||
let mut res = Vec::with_capacity(len);
|
||||
let mut counter: u32 = 0;
|
||||
let mut counter = 0u32;
|
||||
|
||||
while res.len() < len {
|
||||
let mut c: [u8; 4] = [0; 4];
|
||||
BigEndian::write_u32(&mut c, counter);
|
||||
let mut digest = self.hash.clone();
|
||||
digest.process(input);
|
||||
digest.process(&c);
|
||||
let chunk = digest.fixed_result();
|
||||
let mut buffer = [0; 4];
|
||||
BigEndian::write_u32(&mut buffer, counter);
|
||||
let mut digest = H::new();
|
||||
digest.update(input);
|
||||
digest.update(&buffer);
|
||||
let chunk = digest.finalize();
|
||||
res.extend_from_slice(chunk.as_slice());
|
||||
counter += 1;
|
||||
counter = counter + 1;
|
||||
}
|
||||
|
||||
res.truncate(len);
|
||||
|
||||
@@ -1,117 +1,269 @@
|
||||
use cryptonum::{CryptoNumBase,CryptoNumModOps,CryptoNumSerialization};
|
||||
use digest::{FixedOutput,Input};
|
||||
use rsa::core::{dp,sp1,pkcs1_pad,xor_vecs};
|
||||
use rsa::oaep::{OAEPParams};
|
||||
use rsa::errors::{RSAError};
|
||||
use cryptonum::unsigned::*;
|
||||
use rsa::core::{RSAMode,drop0s,pkcs1_pad,xor_vecs};
|
||||
use rsa::errors::RSAError;
|
||||
use rsa::oaep::OAEPParams;
|
||||
use rsa::signing_hashes::SigningHash;
|
||||
use sha::Hash;
|
||||
|
||||
/// A RSA private key. As with public keys, I've left the size as a
|
||||
/// parameter: 2048-4096 is standard practice, 512-1024 is weak, and
|
||||
/// >4096 is going to be slow.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct RSAPrivateKey<Size>
|
||||
where
|
||||
Size: CryptoNumBase + CryptoNumSerialization
|
||||
/// An RSA private key. Useful for signing messages and decrypting encrypted
|
||||
/// content.
|
||||
#[derive(Clone,PartialEq)]
|
||||
pub struct RSAPrivateKey<R: RSAMode>
|
||||
{
|
||||
pub(crate) n: Size,
|
||||
pub(crate) d: Size
|
||||
pub(crate) nu: R::Barrett,
|
||||
pub(crate) d: R
|
||||
}
|
||||
|
||||
impl<U> RSAPrivateKey<U>
|
||||
where
|
||||
U: CryptoNumBase + CryptoNumModOps + CryptoNumSerialization
|
||||
/// A generic RSA private key which is agnostic to its key size.
|
||||
#[derive(Clone,PartialEq)]
|
||||
pub enum RSAPrivate {
|
||||
Key512(RSAPrivateKey<U512>),
|
||||
Key1024(RSAPrivateKey<U1024>),
|
||||
Key2048(RSAPrivateKey<U2048>),
|
||||
Key3072(RSAPrivateKey<U3072>),
|
||||
Key4096(RSAPrivateKey<U4096>),
|
||||
Key8192(RSAPrivateKey<U8192>),
|
||||
Key15360(RSAPrivateKey<U15360>)
|
||||
}
|
||||
|
||||
macro_rules! generate_rsa_private
|
||||
{
|
||||
/// Generate a private key, using the given `n` and `d` parameters
|
||||
/// gathered from some other source. The length should be given in
|
||||
/// bits.
|
||||
pub fn new(n: U, d: U) -> RSAPrivateKey<U> {
|
||||
RSAPrivateKey {
|
||||
n: n,
|
||||
d: d
|
||||
}
|
||||
}
|
||||
($num: ident, $bar: ident, $size: expr) => {
|
||||
impl RSAPrivateKey<$num> {
|
||||
/// Generate a new private key with the given modulus and private
|
||||
/// number (`d`). This operation actually does a bit of computation
|
||||
/// under the hood, in order to speed up future ones, so you might
|
||||
/// want to strongly consider sharing rather than multiple
|
||||
/// instantiation. But you do you.
|
||||
pub fn new(n: $num, d: $num) -> RSAPrivateKey<$num> {
|
||||
let nu = $bar::new(n.clone());
|
||||
RSAPrivateKey{ nu: nu, d: d }
|
||||
}
|
||||
|
||||
/// 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.d.byte_size());
|
||||
let m = U::from_bytes(&em);
|
||||
let s = sp1(&self.n, &self.d, &m);
|
||||
let sig = s.to_bytes();
|
||||
sig
|
||||
}
|
||||
/// Sign the given message with the given SigningHash, returning
|
||||
/// the signature. This uses a deterministic PKCS1 method for
|
||||
/// signing messages, so no RNG required.
|
||||
pub fn sign(&self, signhash: &SigningHash, msg: &[u8])
|
||||
-> Vec<u8>
|
||||
{
|
||||
let hash = (signhash.run)(msg);
|
||||
let em = pkcs1_pad(&signhash.ident, &hash, $size/8);
|
||||
let m = $num::from_bytes(&em);
|
||||
let s = self.sp1(&m);
|
||||
let sig = s.to_bytes();
|
||||
sig
|
||||
}
|
||||
|
||||
/// 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();
|
||||
let byte_len = self.d.byte_size();
|
||||
/// Decrypted the provided encrypted blob using the given
|
||||
/// parameters. This does standard RSA OAEP decryption, which is
|
||||
/// rather slow. If you have a choice, you should probably do
|
||||
/// something clever, like only use this encryption/decryption
|
||||
/// method to encrypt/decrypt a shared symmetric key, like an
|
||||
/// AES key. That way, you only do this operation (which is
|
||||
/// SO SLOW) for a relatively small amount of data.
|
||||
pub fn decrypt<H: Hash>(&self, oaep: &OAEPParams<H>, msg: &[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
{
|
||||
let mut res = Vec::new();
|
||||
|
||||
for chunk in msg.chunks(byte_len) {
|
||||
let mut dchunk = self.oaep_decrypt(oaep, chunk)?;
|
||||
res.append(&mut dchunk);
|
||||
}
|
||||
for chunk in msg.chunks($size/8) {
|
||||
let mut dchunk = self.oaep_decrypt(oaep, chunk)?;
|
||||
res.append(&mut dchunk);
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn oaep_decrypt<H: Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, c: &[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
{
|
||||
let byte_len = self.d.byte_size();
|
||||
// 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 = U::from_bytes(&c);
|
||||
// Step 2b
|
||||
let m_ip = dp(&self.n, &self.d, &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);
|
||||
}
|
||||
fn sp1(&self, m: &$num) -> $num {
|
||||
m.modexp(&self.d, &self.nu)
|
||||
}
|
||||
|
||||
Ok(m.to_vec())
|
||||
fn dp(&self, c: &$num) -> $num {
|
||||
c.modexp(&self.d, &self.nu)
|
||||
}
|
||||
|
||||
fn oaep_decrypt<H: Hash>(&self, oaep: &OAEPParams<H>, c: &[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
{
|
||||
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(m.to_vec())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn drop0s(a: &[u8]) -> &[u8] {
|
||||
let mut idx = 0;
|
||||
generate_rsa_private!(U512, BarrettU512, 512);
|
||||
generate_rsa_private!(U1024, BarrettU1024, 1024);
|
||||
generate_rsa_private!(U2048, BarrettU2048, 2048);
|
||||
generate_rsa_private!(U3072, BarrettU3072, 3072);
|
||||
generate_rsa_private!(U4096, BarrettU4096, 4096);
|
||||
generate_rsa_private!(U8192, BarrettU8192, 8192);
|
||||
generate_rsa_private!(U15360, BarrettU15360, 15360);
|
||||
|
||||
while (idx < a.len()) && (a[idx] == 0) {
|
||||
idx = idx + 1;
|
||||
}
|
||||
#[cfg(test)]
|
||||
macro_rules! sign_test_body {
|
||||
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||
let fname = format!("testdata/rsa/sign{}.test", $size);
|
||||
run_test(fname.to_string(), 7, |case| {
|
||||
let (neg0, dbytes) = case.get("d").unwrap();
|
||||
let (neg1, nbytes) = case.get("n").unwrap();
|
||||
let (neg2, hbytes) = case.get("h").unwrap();
|
||||
let (neg3, mbytes) = case.get("m").unwrap();
|
||||
let (neg4, sbytes) = case.get("s").unwrap();
|
||||
let (neg5, ubytes) = case.get("u").unwrap();
|
||||
let (neg6, kbytes) = case.get("k").unwrap();
|
||||
|
||||
&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 = RSAPrivateKey{ 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, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||
let fname = format!("testdata/rsa/encrypt{}.test", $size);
|
||||
run_test(fname.to_string(), 9, |case| {
|
||||
let (neg0, nbytes) = case.get("n").unwrap();
|
||||
let (neg1, hbytes) = case.get("h").unwrap();
|
||||
let (neg2, mbytes) = case.get("m").unwrap();
|
||||
let (neg3, _bytes) = case.get("e").unwrap();
|
||||
let (neg4, ubytes) = case.get("u").unwrap();
|
||||
let (neg5, kbytes) = case.get("k").unwrap();
|
||||
let (neg6, dbytes) = case.get("d").unwrap();
|
||||
let (neg7, lbytes) = case.get("l").unwrap();
|
||||
let (neg8, cbytes) = case.get("c").unwrap();
|
||||
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5 && !neg6 && !neg7 && !neg8);
|
||||
let n = $num::from_bytes(nbytes);
|
||||
let n64 = $num64::from(&n);
|
||||
let nu = $num64::from_bytes(ubytes);
|
||||
let bigk = $num::from_bytes(kbytes);
|
||||
let k = usize::from(bigk);
|
||||
let d = $num::from_bytes(dbytes);
|
||||
let nu = $bar::from_components(k, n64, nu);
|
||||
let privkey = RSAPrivateKey{ nu: nu, d: d };
|
||||
let lstr = String::from_utf8(lbytes.clone()).unwrap();
|
||||
let message = match usize::from($num::from_bytes(hbytes)) {
|
||||
224 => privkey.decrypt(&OAEPParams::<SHA224>::new(lstr), &cbytes),
|
||||
256 => privkey.decrypt(&OAEPParams::<SHA256>::new(lstr), &cbytes),
|
||||
384 => privkey.decrypt(&OAEPParams::<SHA384>::new(lstr), &cbytes),
|
||||
512 => privkey.decrypt(&OAEPParams::<SHA512>::new(lstr), &cbytes),
|
||||
x => panic!("Unknown hash number: {}", x)
|
||||
};
|
||||
assert!(message.is_ok());
|
||||
assert_eq!(mbytes, &message.unwrap());
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! generate_tests {
|
||||
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod $mod {
|
||||
use cryptonum::unsigned::Decoder;
|
||||
use super::*;
|
||||
use testing::run_test;
|
||||
use rsa::signing_hashes::*;
|
||||
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||
|
||||
#[test]
|
||||
fn sign() {
|
||||
sign_test_body!($mod, $num, $bar, $num64, $size);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decrypt() {
|
||||
decrypt_test_body!($mod, $num, $bar, $num64, $size);
|
||||
}
|
||||
}
|
||||
};
|
||||
(ignore $mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod $mod {
|
||||
use cryptonum::unsigned::Decoder;
|
||||
use super::*;
|
||||
use testing::run_test;
|
||||
use rsa::signing_hashes::*;
|
||||
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn sign() {
|
||||
sign_test_body!($mod, $num, $bar, $num64, $size);
|
||||
}
|
||||
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn decrypt() {
|
||||
decrypt_test_body!($mod, $num, $bar, $num64, $size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generate_tests!( RSA512, U512, BarrettU512, U576, 512);
|
||||
generate_tests!( RSA1024, U1024, BarrettU1024, U1088, 1024);
|
||||
generate_tests!( RSA2048, U2048, BarrettU2048, U2112, 2048);
|
||||
generate_tests!( RSA3072, U3072, BarrettU3072, U3136, 3072);
|
||||
generate_tests!( RSA4096, U4096, BarrettU4096, U4160, 4096);
|
||||
generate_tests!(ignore RSA8192, U8192, BarrettU8192, U8256, 8192);
|
||||
generate_tests!(ignore RSA15360, U15360, BarrettU15360, U15424, 15360);
|
||||
@@ -1,147 +1,61 @@
|
||||
use cryptonum::{CryptoNumBase,CryptoNumModOps,CryptoNumSerialization};
|
||||
use digest::{FixedOutput,Input};
|
||||
use num::{BigInt,BigUint};
|
||||
use rand::{OsRng,Rng};
|
||||
use rsa::core::{ep,vp1,pkcs1_pad,xor_vecs,decode_biguint};
|
||||
use rsa::oaep::{OAEPParams};
|
||||
use rsa::errors::{RSAError};
|
||||
use cryptonum::unsigned::*;
|
||||
use rand::Rng;
|
||||
use rand::rngs::OsRng;
|
||||
use rsa::core::{RSAMode,decode_biguint,pkcs1_pad,xor_vecs};
|
||||
use rsa::errors::RSAError;
|
||||
use rsa::oaep::OAEPParams;
|
||||
use rsa::signing_hashes::SigningHash;
|
||||
use simple_asn1::{FromASN1,ToASN1,ASN1DecodeErr,ASN1EncodeErr};
|
||||
use simple_asn1::{ASN1Block,ASN1Class};
|
||||
use sha::Hash;
|
||||
use simple_asn1::{ASN1Block,ASN1DecodeErr,ASN1EncodeErr,
|
||||
ASN1Class,FromASN1,ToASN1};
|
||||
#[cfg(test)]
|
||||
use std::fmt;
|
||||
use utils::TranslateNums;
|
||||
|
||||
/// An RSA public key with the given modulus size. I've left the size as a
|
||||
/// parameter, instead of hardcoding particular values. That being said,
|
||||
/// you almost certainly want one of `U2048`, `U3072`, or `U4096` if you're
|
||||
/// being pretty standard; `U512` or `U1024` if you're interfacing with
|
||||
/// legacy code or want to build intentionally weak systems; or `U7680`,
|
||||
/// `U8192`, or `U15360` if you like things running very slowly.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct RSAPublicKey<Size>
|
||||
where
|
||||
Size: CryptoNumBase + CryptoNumSerialization
|
||||
{
|
||||
pub(crate) n: Size,
|
||||
pub(crate) e: Size
|
||||
/// An RSA public key. Useful for verifying signatures or encrypting data to
|
||||
/// send to the private key holder.
|
||||
#[derive(Clone,PartialEq)]
|
||||
pub struct RSAPublicKey<R: RSAMode> {
|
||||
pub(crate) n: R,
|
||||
pub(crate) nu: R::Barrett,
|
||||
pub(crate) e: R
|
||||
}
|
||||
|
||||
impl<U> RSAPublicKey<U>
|
||||
where
|
||||
U: CryptoNumBase + CryptoNumModOps + CryptoNumSerialization
|
||||
{
|
||||
/// Create a new RSA public key from the given components, which you found
|
||||
/// via some other mechanism.
|
||||
pub fn new(n: U, e: U) -> RSAPublicKey<U> {
|
||||
RSAPublicKey{ n: n, e: e }
|
||||
}
|
||||
/// A generic private key that is agnostic to the key size.
|
||||
#[derive(Clone,PartialEq)]
|
||||
pub enum RSAPublic {
|
||||
Key512( RSAPublicKey<U512>),
|
||||
Key1024( RSAPublicKey<U1024>),
|
||||
Key2048( RSAPublicKey<U2048>),
|
||||
Key3072( RSAPublicKey<U3072>),
|
||||
Key4096( RSAPublicKey<U4096>),
|
||||
Key8192( RSAPublicKey<U8192>),
|
||||
Key15360(RSAPublicKey<U15360>)
|
||||
}
|
||||
|
||||
/// Verify the signature for a given message, using the given signing hash,
|
||||
/// return true iff the signature validates.
|
||||
pub fn verify(&self, sighash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool
|
||||
impl RSAPublic {
|
||||
/// Verify that the given signature is for the given message, passing
|
||||
/// in the same signing arguments used to sign the message in the
|
||||
/// first place.
|
||||
pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool
|
||||
{
|
||||
let hash = (sighash.run)(msg);
|
||||
let s = U::from_bytes(sig);
|
||||
let m = vp1(&self.n, &self.e, &s);
|
||||
let em = s.to_bytes();
|
||||
let em_ = pkcs1_pad(&sighash.ident, &hash, m.byte_size());
|
||||
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>
|
||||
{
|
||||
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
|
||||
{
|
||||
let mylen = self.e.byte_size();
|
||||
|
||||
if mylen <= ((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(mylen - (2 * oaep.hash_len()) - 2) {
|
||||
let mut newchunk = self.oaep_encrypt(g, oaep, chunk)?;
|
||||
res.append(&mut newchunk)
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn oaep_encrypt<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
where
|
||||
G: Rng, H:Clone + Input + FixedOutput
|
||||
{
|
||||
let mylen = self.e.byte_size();
|
||||
|
||||
// Step 1b
|
||||
if msg.len() > (mylen - (2 * oaep.hash_len()) - 2) {
|
||||
return Err(RSAError::BadMessageSize)
|
||||
}
|
||||
// Step 2a
|
||||
let mut lhash = oaep.hash(oaep.label.as_bytes());
|
||||
// Step 2b
|
||||
let num0s = mylen - 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, mylen - 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 = U::from_bytes(&em);
|
||||
// Step 3b
|
||||
let c_i = ep(&self.n, &self.e, &m_i);
|
||||
// Step 3c
|
||||
let c = c_i.to_bytes();
|
||||
Ok(c)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromASN1 for RSAPublicKey<T>
|
||||
where
|
||||
T: CryptoNumBase + CryptoNumSerialization,
|
||||
T: From<BigUint>
|
||||
{
|
||||
impl FromASN1 for RSAPublic {
|
||||
type Error = RSAError;
|
||||
|
||||
fn from_asn1(bs: &[ASN1Block])
|
||||
-> Result<(RSAPublicKey<T>,&[ASN1Block]),RSAError>
|
||||
-> Result<(RSAPublic,&[ASN1Block]),RSAError>
|
||||
{
|
||||
match bs.split_first() {
|
||||
None =>
|
||||
@@ -149,26 +63,60 @@ impl<T> FromASN1 for RSAPublicKey<T>
|
||||
Some((&ASN1Block::Sequence(_, _, ref items), rest))
|
||||
if items.len() == 2 =>
|
||||
{
|
||||
let numn = decode_biguint(&items[0])?;
|
||||
let nume = decode_biguint(&items[1])?;
|
||||
let nsize = numn.bits();
|
||||
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;
|
||||
}
|
||||
rsa_size /= 8;
|
||||
|
||||
if rsa_size != (T::zero()).bit_size() {
|
||||
return Err(RSAError::KeySizeMismatch);
|
||||
match rsa_size {
|
||||
512 => {
|
||||
let n2 = U512::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||
let e2 = U512::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||
let res = RSAPublicKey::<U512>::new(n2, e2);
|
||||
Ok((RSAPublic::Key512(res), rest))
|
||||
}
|
||||
1024 => {
|
||||
let n2 = U1024::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||
let e2 = U1024::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||
let res = RSAPublicKey::<U1024>::new(n2, e2);
|
||||
Ok((RSAPublic::Key1024(res), rest))
|
||||
}
|
||||
2048 => {
|
||||
let n2 = U2048::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||
let e2 = U2048::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||
let res = RSAPublicKey::<U2048>::new(n2, e2);
|
||||
Ok((RSAPublic::Key2048(res), rest))
|
||||
}
|
||||
3072 => {
|
||||
let n2 = U3072::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||
let e2 = U3072::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||
let res = RSAPublicKey::<U3072>::new(n2, e2);
|
||||
Ok((RSAPublic::Key3072(res), rest))
|
||||
}
|
||||
4096 => {
|
||||
let n2 = U4096::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||
let e2 = U4096::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||
let res = RSAPublicKey::<U4096>::new(n2, e2);
|
||||
Ok((RSAPublic::Key4096(res), rest))
|
||||
}
|
||||
8192 => {
|
||||
let n2 = U8192::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||
let e2 = U8192::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||
let res = RSAPublicKey::<U8192>::new(n2, e2);
|
||||
Ok((RSAPublic::Key8192(res), rest))
|
||||
}
|
||||
15360 => {
|
||||
let n2 = U15360::from_num(&n).ok_or(RSAError::InvalidKey)?;
|
||||
let e2 = U15360::from_num(&e).ok_or(RSAError::InvalidKey)?;
|
||||
let res = RSAPublicKey::<U15360>::new(n2, e2);
|
||||
Ok((RSAPublic::Key15360(res), rest))
|
||||
}
|
||||
_ =>
|
||||
Err(RSAError::InvalidKey)
|
||||
}
|
||||
|
||||
let n = T::from(numn);
|
||||
let e = T::from(nume);
|
||||
|
||||
let res = RSAPublicKey{ n: n, e: e };
|
||||
|
||||
Ok((res, rest))
|
||||
}
|
||||
Some(_) =>
|
||||
Err(RSAError::InvalidKey)
|
||||
@@ -176,21 +124,403 @@ impl<T> FromASN1 for RSAPublicKey<T>
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ToASN1 for RSAPublicKey<T>
|
||||
where
|
||||
T: Clone + Into<BigInt>,
|
||||
T: CryptoNumBase + CryptoNumSerialization
|
||||
{
|
||||
impl ToASN1 for RSAPublic {
|
||||
type Error = ASN1EncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
-> Result<Vec<ASN1Block>,Self::Error>
|
||||
{
|
||||
let enc_n = ASN1Block::Integer(c, 0, self.n.clone().into());
|
||||
let enc_e = ASN1Block::Integer(c, 0, self.e.clone().into());
|
||||
let seq = ASN1Block::Sequence(c, 0, vec![enc_n, enc_e]);
|
||||
Ok(vec![seq])
|
||||
match self {
|
||||
RSAPublic::Key512(x) => x.to_asn1_class(c),
|
||||
RSAPublic::Key1024(x) => x.to_asn1_class(c),
|
||||
RSAPublic::Key2048(x) => x.to_asn1_class(c),
|
||||
RSAPublic::Key3072(x) => x.to_asn1_class(c),
|
||||
RSAPublic::Key4096(x) => x.to_asn1_class(c),
|
||||
RSAPublic::Key8192(x) => x.to_asn1_class(c),
|
||||
RSAPublic::Key15360(x) => x.to_asn1_class(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl fmt::Debug for RSAPublic {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
RSAPublic::Key512(x) => write!(fmt, "RSA:{:?}", x),
|
||||
RSAPublic::Key1024(x) => write!(fmt, "RSA:{:?}", x),
|
||||
RSAPublic::Key2048(x) => write!(fmt, "RSA:{:?}", x),
|
||||
RSAPublic::Key3072(x) => write!(fmt, "RSA:{:?}", x),
|
||||
RSAPublic::Key4096(x) => write!(fmt, "RSA:{:?}", x),
|
||||
RSAPublic::Key8192(x) => write!(fmt, "RSA:{:?}", x),
|
||||
RSAPublic::Key15360(x) => write!(fmt, "RSA:{:?}", x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_rsa_public
|
||||
{
|
||||
($num: ident, $bar: ident, $var: ident, $size: expr) => {
|
||||
impl RSAPublicKey<$num> {
|
||||
/// Generate a new public key pair for the given modulus and
|
||||
/// exponent. You should probably not call this directly unless
|
||||
/// you're writing a key generation function or writing your own
|
||||
/// public key parser.
|
||||
pub fn new(n: $num, e: $num) -> RSAPublicKey<$num> {
|
||||
let nu = $bar::new(n.clone());
|
||||
RSAPublicKey{ n: n, nu: nu, e: e }
|
||||
}
|
||||
|
||||
/// Verify that the provided signature is valid; that the private
|
||||
/// key associated with this public key sent exactly this message.
|
||||
/// The hash used here must exactly match the hash used to sign
|
||||
/// the message, including its ASN.1 metadata.
|
||||
pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8])
|
||||
-> bool
|
||||
{
|
||||
let hash: Vec<u8> = (signhash.run)(msg);
|
||||
let s = $num::from_bytes(&sig);
|
||||
let m = self.vp1(&s);
|
||||
let em = m.to_bytes();
|
||||
let em_ = pkcs1_pad(signhash.ident, &hash, $size/8);
|
||||
em == em_
|
||||
}
|
||||
|
||||
/// Encrypt the message with a hash function, given the appropriate
|
||||
/// label. Please note that RSA encryption is not particularly fast,
|
||||
/// and decryption is very slow indeed. Thus, most crypto systems that
|
||||
/// need asymmetric encryption should generate a symmetric key, encrypt
|
||||
/// that key with RSA encryption, and then encrypt the actual message
|
||||
/// with that symmetric key.
|
||||
///
|
||||
/// In this variant of the function, we use an explicit random number
|
||||
/// generator, just in case you have one you really like. It better be
|
||||
/// cryptographically strong, though, as some of the padding protections
|
||||
/// are relying on it.
|
||||
pub fn encrypt_rng<G,H>(&self,g: &mut G,oaep: &OAEPParams<H>,msg: &[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
where
|
||||
G: Rng,
|
||||
H: Hash
|
||||
{
|
||||
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)
|
||||
}
|
||||
|
||||
/// Encrypt the message with a hash function, given the appropriate
|
||||
/// label. Please note that RSA encryption is not particularly fast,
|
||||
/// and decryption is very slow indeed. Thus, most crypto systems that
|
||||
/// need asymmetric encryption should generate a symmetric key, encrypt
|
||||
/// that key with RSA encryption, and then encrypt the actual message
|
||||
/// with that symmetric key.
|
||||
///
|
||||
/// This variant will just use the system RNG for its randomness.
|
||||
pub fn encrypt<H: Hash>(&self,oaep:&OAEPParams<H>,msg:&[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
{
|
||||
let mut g = OsRng::new()?;
|
||||
self.encrypt_rng(&mut g, oaep, msg)
|
||||
}
|
||||
|
||||
fn vp1(&self, s: &$num) -> $num {
|
||||
s.modexp(&self.e, &self.nu)
|
||||
}
|
||||
|
||||
fn ep(&self, m: &$num) -> $num {
|
||||
m.modexp(&self.e, &self.nu)
|
||||
}
|
||||
|
||||
fn oaep_encrypt<G,H>(&self,g: &mut G,oaep: &OAEPParams<H>,m: &[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
where
|
||||
G: Rng,
|
||||
H: Hash
|
||||
{
|
||||
let byte_len = $size / 8;
|
||||
// Step 1b
|
||||
if m.len() > (byte_len - (2 * oaep.hash_len()) - 2) {
|
||||
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 RSAPublicKey<$num> {
|
||||
type Error = RSAError;
|
||||
|
||||
fn from_asn1(bs: &[ASN1Block])
|
||||
-> Result<(RSAPublicKey<$num>,&[ASN1Block]),RSAError>
|
||||
{
|
||||
let (core, rest) = RSAPublic::from_asn1(bs)?;
|
||||
|
||||
match core {
|
||||
RSAPublic::$var(x) => Ok((x, rest)),
|
||||
_ => Err(RSAError::InvalidKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToASN1 for RSAPublicKey<$num> {
|
||||
type Error = ASN1EncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
-> Result<Vec<ASN1Block>,Self::Error>
|
||||
{
|
||||
let n = self.n.to_num();
|
||||
let e = self.e.to_num();
|
||||
let enc_n = ASN1Block::Integer(c, 0, n);
|
||||
let enc_e = ASN1Block::Integer(c, 0, e);
|
||||
let seq = ASN1Block::Sequence(c, 0, vec![enc_n, enc_e]);
|
||||
Ok(vec![seq])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl fmt::Debug for RSAPublicKey<$num> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct(stringify!($rsa))
|
||||
.field("n", &self.n)
|
||||
.field("nu", &self.nu)
|
||||
.field("e", &self.e)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generate_rsa_public!(U512, BarrettU512, Key512, 512);
|
||||
generate_rsa_public!(U1024, BarrettU1024, Key1024, 1024);
|
||||
generate_rsa_public!(U2048, BarrettU2048, Key2048, 2048);
|
||||
generate_rsa_public!(U3072, BarrettU3072, Key3072, 3072);
|
||||
generate_rsa_public!(U4096, BarrettU4096, Key4096, 4096);
|
||||
generate_rsa_public!(U8192, BarrettU8192, Key8192, 8192);
|
||||
generate_rsa_public!(U15360, BarrettU15360, Key15360, 15360);
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! new_test_body {
|
||||
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||
let fname = format!("testdata/rsa/sign{}.test", $size);
|
||||
run_test(fname.to_string(), 7, |case| {
|
||||
let (neg0, nbytes) = case.get("n").unwrap();
|
||||
let (neg1, ubytes) = case.get("u").unwrap();
|
||||
let (neg2, kbytes) = case.get("k").unwrap();
|
||||
|
||||
assert!(!neg0&&!neg1&&!neg2);
|
||||
let n = $num::from_bytes(nbytes);
|
||||
let n64 = $num64::from(&n);
|
||||
let nu = $num64::from_bytes(ubytes);
|
||||
let bigk = $num::from_bytes(kbytes);
|
||||
let k = usize::from(bigk);
|
||||
let e = $num::from(65537u64);
|
||||
let pubkey2 = RSAPublicKey::<$num>::new(n.clone(), e.clone());
|
||||
let pubkey1 = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
||||
assert_eq!(pubkey1, pubkey2);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! encode_test_body {
|
||||
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||
let fname = format!("testdata/rsa/sign{}.test", $size);
|
||||
run_test(fname.to_string(), 7, |case| {
|
||||
let (neg0, nbytes) = case.get("n").unwrap();
|
||||
let (neg1, ubytes) = case.get("u").unwrap();
|
||||
let (neg2, kbytes) = case.get("k").unwrap();
|
||||
|
||||
assert!(!neg0&&!neg1&&!neg2);
|
||||
let n = $num::from_bytes(nbytes);
|
||||
let n64 = $num64::from(&n);
|
||||
let nu = $num64::from_bytes(ubytes);
|
||||
let bigk = $num::from_bytes(kbytes);
|
||||
let k = usize::from(bigk);
|
||||
let e = $num::from(65537u64);
|
||||
let pubkey = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
||||
let asn1 = pubkey.to_asn1().unwrap();
|
||||
let (pubkey2, _) = RSAPublicKey::from_asn1(&asn1).unwrap();
|
||||
assert_eq!(pubkey, pubkey2);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! verify_test_body {
|
||||
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||
let fname = format!("testdata/rsa/sign{}.test", $size);
|
||||
run_test(fname.to_string(), 7, |case| {
|
||||
let (neg0, nbytes) = case.get("n").unwrap();
|
||||
let (neg1, hbytes) = case.get("h").unwrap();
|
||||
let (neg2, mbytes) = case.get("m").unwrap();
|
||||
let (neg3, sbytes) = case.get("s").unwrap();
|
||||
let (neg4, ubytes) = case.get("u").unwrap();
|
||||
let (neg5, kbytes) = case.get("k").unwrap();
|
||||
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5);
|
||||
let n = $num::from_bytes(nbytes);
|
||||
let n64 = $num64::from(&n);
|
||||
let nu = $num64::from_bytes(ubytes);
|
||||
let bigk = $num::from_bytes(kbytes);
|
||||
let k = usize::from(bigk);
|
||||
let e = $num::from(65537u64);
|
||||
let pubkey = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
|
||||
let hashnum = u64::from($num::from_bytes(hbytes));
|
||||
let sighash = match hashnum {
|
||||
160 => &SIGNING_HASH_SHA1,
|
||||
224 => &SIGNING_HASH_SHA224,
|
||||
256 => &SIGNING_HASH_SHA256,
|
||||
384 => &SIGNING_HASH_SHA384,
|
||||
512 => &SIGNING_HASH_SHA512,
|
||||
_ => panic!("Bad signing hash: {}", hashnum)
|
||||
};
|
||||
assert!(pubkey.verify(sighash, &mbytes, &sbytes));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! encrypt_test_body {
|
||||
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||
let fname = format!("testdata/rsa/encrypt{}.test", $size);
|
||||
run_test(fname.to_string(), 9, |case| {
|
||||
let (neg0, nbytes) = case.get("n").unwrap();
|
||||
let (neg1, hbytes) = case.get("h").unwrap();
|
||||
let (neg2, mbytes) = case.get("m").unwrap();
|
||||
let (neg3, _bytes) = case.get("e").unwrap();
|
||||
let (neg4, ubytes) = case.get("u").unwrap();
|
||||
let (neg5, kbytes) = case.get("k").unwrap();
|
||||
let (neg6, dbytes) = case.get("d").unwrap();
|
||||
let (neg7, lbytes) = case.get("l").unwrap();
|
||||
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5 && !neg6 && !neg7);
|
||||
let n = $num::from_bytes(nbytes);
|
||||
let n64 = $num64::from(&n);
|
||||
let nu = $num64::from_bytes(ubytes);
|
||||
let bigk = $num::from_bytes(kbytes);
|
||||
let k = usize::from(bigk);
|
||||
let e = $num::from(65537u64);
|
||||
let d = $num::from_bytes(dbytes);
|
||||
let nu = $bar::from_components(k, n64, nu);
|
||||
let pubkey = RSAPublicKey{ n: n.clone(), nu: nu.clone(), e: e };
|
||||
let privkey = RSAPrivateKey{ nu: nu, d: d };
|
||||
let lstr = String::from_utf8(lbytes.clone()).unwrap();
|
||||
let cipher = match usize::from($num::from_bytes(hbytes)) {
|
||||
224 => pubkey.encrypt(&OAEPParams::<SHA224>::new(lstr.clone()), mbytes),
|
||||
256 => pubkey.encrypt(&OAEPParams::<SHA256>::new(lstr.clone()), mbytes),
|
||||
384 => pubkey.encrypt(&OAEPParams::<SHA384>::new(lstr.clone()), mbytes),
|
||||
512 => pubkey.encrypt(&OAEPParams::<SHA512>::new(lstr.clone()), mbytes),
|
||||
x => panic!("Unknown hash number: {}", x)
|
||||
};
|
||||
assert!(cipher.is_ok());
|
||||
let message = match usize::from($num::from_bytes(hbytes)) {
|
||||
224 => privkey.decrypt(&OAEPParams::<SHA224>::new(lstr), &cipher.unwrap()),
|
||||
256 => privkey.decrypt(&OAEPParams::<SHA256>::new(lstr), &cipher.unwrap()),
|
||||
384 => privkey.decrypt(&OAEPParams::<SHA384>::new(lstr), &cipher.unwrap()),
|
||||
512 => privkey.decrypt(&OAEPParams::<SHA512>::new(lstr), &cipher.unwrap()),
|
||||
x => panic!("Unknown hash number: {}", x)
|
||||
};
|
||||
assert!(message.is_ok());
|
||||
assert_eq!(mbytes, &message.unwrap());
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! generate_tests {
|
||||
($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod $mod {
|
||||
use cryptonum::unsigned::Decoder;
|
||||
use super::*;
|
||||
use testing::run_test;
|
||||
use rsa::private::*;
|
||||
use rsa::signing_hashes::*;
|
||||
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||
|
||||
#[test]
|
||||
fn new() { new_test_body!($mod, $num, $bar, $num64, $size); }
|
||||
#[test]
|
||||
fn encode() { encode_test_body!($mod, $num, $bar, $num64, $size); }
|
||||
#[test]
|
||||
fn verify() { verify_test_body!($mod, $num, $bar, $num64, $size); }
|
||||
#[test]
|
||||
fn encrypt() { encrypt_test_body!($mod, $num, $bar, $num64, $size); }
|
||||
}
|
||||
};
|
||||
(ignore $mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod $mod {
|
||||
use cryptonum::unsigned::Decoder;
|
||||
use super::*;
|
||||
use testing::run_test;
|
||||
use rsa::private::*;
|
||||
use rsa::signing_hashes::*;
|
||||
use sha::{SHA224,SHA256,SHA384,SHA512};
|
||||
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn new() { new_test_body!($mod, $num, $bar, $num64, $size); }
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn encode() { encode_test_body!($mod, $num, $bar, $num64, $size); }
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn verify() { verify_test_body!($mod, $num, $bar, $num64, $size); }
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn encrypt() { encrypt_test_body!($mod, $num, $bar, $num64, $size); }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
generate_tests!( RSA512, U512, BarrettU512, U576, 512);
|
||||
generate_tests!( RSA1024, U1024, BarrettU1024, U1088, 1024);
|
||||
generate_tests!( RSA2048, U2048, BarrettU2048, U2112, 2048);
|
||||
generate_tests!( RSA3072, U3072, BarrettU3072, U3136, 3072);
|
||||
generate_tests!( RSA4096, U4096, BarrettU4096, U4160, 4096);
|
||||
generate_tests!(ignore RSA8192, U8192, BarrettU8192, U8256, 8192);
|
||||
generate_tests!(ignore RSA15360, U15360, BarrettU15360, U15424, 15360);
|
||||
@@ -1,6 +1,4 @@
|
||||
use digest::{FixedOutput,Input};
|
||||
use sha1::Sha1;
|
||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||
use sha::{Hash,SHA1,SHA224,SHA256,SHA384,SHA512};
|
||||
use std::fmt;
|
||||
|
||||
/// A hash that can be used to sign a message.
|
||||
@@ -28,13 +26,9 @@ impl fmt::Debug for SigningHash {
|
||||
pub static SIGNING_HASH_NULL: SigningHash = SigningHash {
|
||||
name: "NULL",
|
||||
ident: &[],
|
||||
run: nohash
|
||||
run: |x| { x.to_vec() }
|
||||
};
|
||||
|
||||
fn nohash(i: &[u8]) -> Vec<u8> {
|
||||
i.to_vec()
|
||||
}
|
||||
|
||||
/// Sign a hash based on SHA1. You shouldn't use this unless you're using
|
||||
/// very small keys, and this is the only one available to you. Even then,
|
||||
/// why are you using such small keys?!
|
||||
@@ -42,15 +36,9 @@ pub static SIGNING_HASH_SHA1: SigningHash = SigningHash {
|
||||
name: "SHA1",
|
||||
ident: &[0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,
|
||||
0x02,0x1a,0x05,0x00,0x04,0x14],
|
||||
run: runsha1
|
||||
run: |x| { SHA1::hash(x) }
|
||||
};
|
||||
|
||||
fn runsha1(i: &[u8]) -> Vec<u8> {
|
||||
let mut d = Sha1::default();
|
||||
d.process(i);
|
||||
d.fixed_result().as_slice().to_vec()
|
||||
}
|
||||
|
||||
/// Sign a hash based on SHA2-224. This is the first reasonable choice
|
||||
/// we've come across, and is useful when you have smaller RSA key sizes.
|
||||
/// I wouldn't recommend it, though.
|
||||
@@ -59,30 +47,18 @@ pub static SIGNING_HASH_SHA224: SigningHash = SigningHash {
|
||||
ident: &[0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||
0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,
|
||||
0x1c],
|
||||
run: runsha224
|
||||
run: |x| { SHA224::hash(x) }
|
||||
};
|
||||
|
||||
fn runsha224(i: &[u8]) -> Vec<u8> {
|
||||
let mut d = Sha224::default();
|
||||
d.process(i);
|
||||
d.fixed_result().as_slice().to_vec()
|
||||
}
|
||||
|
||||
/// Sign a hash based on SHA2-256. The first one I'd recommend!
|
||||
pub static SIGNING_HASH_SHA256: SigningHash = SigningHash {
|
||||
name: "SHA256",
|
||||
ident: &[0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||
0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,
|
||||
0x20],
|
||||
run: runsha256
|
||||
run: |x| { SHA256::hash(x) }
|
||||
};
|
||||
|
||||
fn runsha256(i: &[u8]) -> Vec<u8> {
|
||||
let mut d = Sha256::default();
|
||||
d.process(i);
|
||||
d.fixed_result().as_slice().to_vec()
|
||||
}
|
||||
|
||||
/// Sign a hash based on SHA2-384. Approximately 50% better than
|
||||
/// SHA-256.
|
||||
pub static SIGNING_HASH_SHA384: SigningHash = SigningHash {
|
||||
@@ -90,15 +66,9 @@ pub static SIGNING_HASH_SHA384: SigningHash = SigningHash {
|
||||
ident: &[0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||
0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,
|
||||
0x30],
|
||||
run: runsha384
|
||||
run: |x| { SHA384::hash(x) }
|
||||
};
|
||||
|
||||
fn runsha384(i: &[u8]) -> Vec<u8> {
|
||||
let mut d = Sha384::default();
|
||||
d.process(i);
|
||||
d.fixed_result().as_slice().to_vec()
|
||||
}
|
||||
|
||||
/// Sign a hash based on SHA2-512. At this point, you're getting a bit
|
||||
/// silly. But if you want to through 8kbit RSA keys with a 512 bit SHA2
|
||||
/// signing hash, we're totally behind you.
|
||||
@@ -107,13 +77,5 @@ pub static SIGNING_HASH_SHA512: SigningHash = SigningHash {
|
||||
ident: &[0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||
0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,
|
||||
0x40],
|
||||
run: runsha512
|
||||
run: |x| { SHA512::hash(x) }
|
||||
};
|
||||
|
||||
fn runsha512(i: &[u8]) -> Vec<u8> {
|
||||
let mut d = Sha512::default();
|
||||
d.process(i);
|
||||
d.fixed_result().as_slice().to_vec()
|
||||
}
|
||||
|
||||
|
||||
|
||||
64
src/sha/mod.rs
Normal file
64
src/sha/mod.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
//! The SHA family of hash functions, as defined by NIST; specifically, from
|
||||
//! NIST 180-4 (for SHA1 and SHA2) and NIST 202 (for SHA3).
|
||||
//!
|
||||
//! These hash functions are used through their instantiation of the `Hash`
|
||||
//! trait, located in the parent `simple_crypto` module and re-exported
|
||||
//! here for convenience. Thus, you're not going to see a lot of functions
|
||||
//! or macros, here, just the type declarations.
|
||||
//!
|
||||
//! To use SHA2-384, as an example, you could run the following code:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use simple_crypto::sha::{Hash,SHA384};
|
||||
//!
|
||||
//! let empty: [u8; 0] = [0; 0];
|
||||
//! let mut digest_incremental = SHA384::new();
|
||||
//! digest_incremental.update(&empty);
|
||||
//! digest_incremental.update(&empty);
|
||||
//! digest_incremental.update(&empty);
|
||||
//! let result = digest_incremental.finalize();
|
||||
//!
|
||||
//! assert_eq!(result, vec![0x38,0xb0,0x60,0xa7,0x51,0xac,0x96,0x38,
|
||||
//! 0x4c,0xd9,0x32,0x7e,0xb1,0xb1,0xe3,0x6a,
|
||||
//! 0x21,0xfd,0xb7,0x11,0x14,0xbe,0x07,0x43,
|
||||
//! 0x4c,0x0c,0xc7,0xbf,0x63,0xf6,0xe1,0xda,
|
||||
//! 0x27,0x4e,0xde,0xbf,0xe7,0x6f,0x65,0xfb,
|
||||
//! 0xd5,0x1a,0xd2,0xf1,0x48,0x98,0xb9,0x5b]);
|
||||
//! ```
|
||||
//!
|
||||
//! For other hashes, just substitute the appropriate hash structure for
|
||||
//! `SHA384`. The `Hash` trait also includes a do-it-all-at-once built-in
|
||||
//! function for those cases when you just have a single blob of data
|
||||
//! you want to hash, rather than an incremental set of data:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use simple_crypto::sha::{Hash,SHA3_256};
|
||||
//!
|
||||
//! let empty: [u8; 0] = [0; 0];
|
||||
//! let result = SHA3_256::hash(&empty);
|
||||
//!
|
||||
//! assert_eq!(result, vec![0xa7,0xff,0xc6,0xf8,0xbf,0x1e,0xd7,0x66,
|
||||
//! 0x51,0xc1,0x47,0x56,0xa0,0x61,0xd6,0x62,
|
||||
//! 0xf5,0x80,0xff,0x4d,0xe4,0x3b,0x49,0xfa,
|
||||
//! 0x82,0xd8,0x0a,0x4b,0x80,0xf8,0x43,0x4a]);
|
||||
//! ```
|
||||
//!
|
||||
//! In general, you should not use SHA1 for anything but supporting legacy
|
||||
//! systems. We recommend either SHA2 or SHA3 at their 256-, 384-, or 512-bit
|
||||
//! sizes. NIST claims (in FIPS 202, page 23-24) that SHA2 and SHA3 are
|
||||
//! approximately equivalent in terms of security for collision, preimate,
|
||||
//! and second preimage attacks, but that SHA3 improves upon SHA2 against
|
||||
//! length-extension and other attacks. On the other hand, SHA2 has been
|
||||
//! banged on for a little longer, and there's some claims that it's more
|
||||
//! resistant to quantum attacks. So ... make your own decisions.
|
||||
#[macro_use]
|
||||
mod shared;
|
||||
mod sha1;
|
||||
mod sha2;
|
||||
mod sha3;
|
||||
|
||||
pub use super::Hash;
|
||||
pub use self::sha1::SHA1;
|
||||
pub use self::sha2::{SHA224,SHA256,SHA384,SHA512};
|
||||
pub use self::sha3::{SHA3_224,SHA3_256,SHA3_384,SHA3_512};
|
||||
pub(crate) use self::sha3::Keccak;
|
||||
306
src/sha/sha1.rs
Normal file
306
src/sha/sha1.rs
Normal file
@@ -0,0 +1,306 @@
|
||||
use byteorder::{BigEndian,WriteBytesExt};
|
||||
use super::super::Hash;
|
||||
use sha::shared::calculate_k;
|
||||
|
||||
/// The SHA1 hash. Don't use this except to support legacy systems.
|
||||
///
|
||||
/// To use, you can run it in incremental mode -- by calling new(),
|
||||
/// update() zero or more times, and then finalize() -- or you can
|
||||
/// just invoke the hash directly. For example:
|
||||
///
|
||||
/// ```rust
|
||||
/// use simple_crypto::sha::{Hash,SHA1};
|
||||
///
|
||||
/// let empty = [0; 0];
|
||||
/// // Do the hash using the incremental API
|
||||
/// let mut hashf = SHA1::new();
|
||||
/// hashf.update(&empty);
|
||||
/// let result_incremental = hashf.finalize();
|
||||
/// // Do the hash using the direct API
|
||||
/// let result_direct = SHA1::hash(&empty);
|
||||
/// // ... and they should be the same
|
||||
/// assert_eq!(result_incremental,result_direct);
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct SHA1 {
|
||||
state: [u32; 5],
|
||||
buffer: Vec<u8>,
|
||||
done: bool,
|
||||
l: usize
|
||||
}
|
||||
|
||||
macro_rules! sha1_step {
|
||||
($op: ident, $out: ident, $ins: expr, $k: expr, $w: ident) => {
|
||||
let $out = {
|
||||
let [a,b,c,d,e] = $ins;
|
||||
let ap = a.rotate_left(5) + $op!(b,c,d) + e + $k + $w;
|
||||
let bp = a;
|
||||
let cp = b.rotate_left(30);
|
||||
let dp = c;
|
||||
let ep = d;
|
||||
[ap, bp, cp, dp, ep]
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
impl SHA1 {
|
||||
fn process(&mut self, w00: u32, w01: u32, w02: u32, w03: u32,
|
||||
w04: u32, w05: u32, w06: u32, w07: u32,
|
||||
w08: u32, w09: u32, w10: u32, w11: u32,
|
||||
w12: u32, w13: u32, w14: u32, w15: u32)
|
||||
{
|
||||
let w16 = (w13 ^ w08 ^ w02 ^ w00).rotate_left(1);
|
||||
let w17 = (w14 ^ w09 ^ w03 ^ w01).rotate_left(1);
|
||||
let w18 = (w15 ^ w10 ^ w04 ^ w02).rotate_left(1);
|
||||
let w19 = (w16 ^ w11 ^ w05 ^ w03).rotate_left(1);
|
||||
let w20 = (w17 ^ w12 ^ w06 ^ w04).rotate_left(1);
|
||||
let w21 = (w18 ^ w13 ^ w07 ^ w05).rotate_left(1);
|
||||
let w22 = (w19 ^ w14 ^ w08 ^ w06).rotate_left(1);
|
||||
let w23 = (w20 ^ w15 ^ w09 ^ w07).rotate_left(1);
|
||||
let w24 = (w21 ^ w16 ^ w10 ^ w08).rotate_left(1);
|
||||
let w25 = (w22 ^ w17 ^ w11 ^ w09).rotate_left(1);
|
||||
let w26 = (w23 ^ w18 ^ w12 ^ w10).rotate_left(1);
|
||||
let w27 = (w24 ^ w19 ^ w13 ^ w11).rotate_left(1);
|
||||
let w28 = (w25 ^ w20 ^ w14 ^ w12).rotate_left(1);
|
||||
let w29 = (w26 ^ w21 ^ w15 ^ w13).rotate_left(1);
|
||||
let w30 = (w27 ^ w22 ^ w16 ^ w14).rotate_left(1);
|
||||
let w31 = (w28 ^ w23 ^ w17 ^ w15).rotate_left(1);
|
||||
let w32 = (w29 ^ w24 ^ w18 ^ w16).rotate_left(1);
|
||||
let w33 = (w30 ^ w25 ^ w19 ^ w17).rotate_left(1);
|
||||
let w34 = (w31 ^ w26 ^ w20 ^ w18).rotate_left(1);
|
||||
let w35 = (w32 ^ w27 ^ w21 ^ w19).rotate_left(1);
|
||||
let w36 = (w33 ^ w28 ^ w22 ^ w20).rotate_left(1);
|
||||
let w37 = (w34 ^ w29 ^ w23 ^ w21).rotate_left(1);
|
||||
let w38 = (w35 ^ w30 ^ w24 ^ w22).rotate_left(1);
|
||||
let w39 = (w36 ^ w31 ^ w25 ^ w23).rotate_left(1);
|
||||
let w40 = (w37 ^ w32 ^ w26 ^ w24).rotate_left(1);
|
||||
let w41 = (w38 ^ w33 ^ w27 ^ w25).rotate_left(1);
|
||||
let w42 = (w39 ^ w34 ^ w28 ^ w26).rotate_left(1);
|
||||
let w43 = (w40 ^ w35 ^ w29 ^ w27).rotate_left(1);
|
||||
let w44 = (w41 ^ w36 ^ w30 ^ w28).rotate_left(1);
|
||||
let w45 = (w42 ^ w37 ^ w31 ^ w29).rotate_left(1);
|
||||
let w46 = (w43 ^ w38 ^ w32 ^ w30).rotate_left(1);
|
||||
let w47 = (w44 ^ w39 ^ w33 ^ w31).rotate_left(1);
|
||||
let w48 = (w45 ^ w40 ^ w34 ^ w32).rotate_left(1);
|
||||
let w49 = (w46 ^ w41 ^ w35 ^ w33).rotate_left(1);
|
||||
let w50 = (w47 ^ w42 ^ w36 ^ w34).rotate_left(1);
|
||||
let w51 = (w48 ^ w43 ^ w37 ^ w35).rotate_left(1);
|
||||
let w52 = (w49 ^ w44 ^ w38 ^ w36).rotate_left(1);
|
||||
let w53 = (w50 ^ w45 ^ w39 ^ w37).rotate_left(1);
|
||||
let w54 = (w51 ^ w46 ^ w40 ^ w38).rotate_left(1);
|
||||
let w55 = (w52 ^ w47 ^ w41 ^ w39).rotate_left(1);
|
||||
let w56 = (w53 ^ w48 ^ w42 ^ w40).rotate_left(1);
|
||||
let w57 = (w54 ^ w49 ^ w43 ^ w41).rotate_left(1);
|
||||
let w58 = (w55 ^ w50 ^ w44 ^ w42).rotate_left(1);
|
||||
let w59 = (w56 ^ w51 ^ w45 ^ w43).rotate_left(1);
|
||||
let w60 = (w57 ^ w52 ^ w46 ^ w44).rotate_left(1);
|
||||
let w61 = (w58 ^ w53 ^ w47 ^ w45).rotate_left(1);
|
||||
let w62 = (w59 ^ w54 ^ w48 ^ w46).rotate_left(1);
|
||||
let w63 = (w60 ^ w55 ^ w49 ^ w47).rotate_left(1);
|
||||
let w64 = (w61 ^ w56 ^ w50 ^ w48).rotate_left(1);
|
||||
let w65 = (w62 ^ w57 ^ w51 ^ w49).rotate_left(1);
|
||||
let w66 = (w63 ^ w58 ^ w52 ^ w50).rotate_left(1);
|
||||
let w67 = (w64 ^ w59 ^ w53 ^ w51).rotate_left(1);
|
||||
let w68 = (w65 ^ w60 ^ w54 ^ w52).rotate_left(1);
|
||||
let w69 = (w66 ^ w61 ^ w55 ^ w53).rotate_left(1);
|
||||
let w70 = (w67 ^ w62 ^ w56 ^ w54).rotate_left(1);
|
||||
let w71 = (w68 ^ w63 ^ w57 ^ w55).rotate_left(1);
|
||||
let w72 = (w69 ^ w64 ^ w58 ^ w56).rotate_left(1);
|
||||
let w73 = (w70 ^ w65 ^ w59 ^ w57).rotate_left(1);
|
||||
let w74 = (w71 ^ w66 ^ w60 ^ w58).rotate_left(1);
|
||||
let w75 = (w72 ^ w67 ^ w61 ^ w59).rotate_left(1);
|
||||
let w76 = (w73 ^ w68 ^ w62 ^ w60).rotate_left(1);
|
||||
let w77 = (w74 ^ w69 ^ w63 ^ w61).rotate_left(1);
|
||||
let w78 = (w75 ^ w70 ^ w64 ^ w62).rotate_left(1);
|
||||
let w79 = (w76 ^ w71 ^ w65 ^ w63).rotate_left(1);
|
||||
sha1_step!(ch, s01, self.state, 0x5a827999, w00);
|
||||
sha1_step!(ch, s02, s01, 0x5a827999, w01);
|
||||
sha1_step!(ch, s03, s02, 0x5a827999, w02);
|
||||
sha1_step!(ch, s04, s03, 0x5a827999, w03);
|
||||
sha1_step!(ch, s05, s04, 0x5a827999, w04);
|
||||
sha1_step!(ch, s06, s05, 0x5a827999, w05);
|
||||
sha1_step!(ch, s07, s06, 0x5a827999, w06);
|
||||
sha1_step!(ch, s08, s07, 0x5a827999, w07);
|
||||
sha1_step!(ch, s09, s08, 0x5a827999, w08);
|
||||
sha1_step!(ch, s10, s09, 0x5a827999, w09);
|
||||
sha1_step!(ch, s11, s10, 0x5a827999, w10);
|
||||
sha1_step!(ch, s12, s11, 0x5a827999, w11);
|
||||
sha1_step!(ch, s13, s12, 0x5a827999, w12);
|
||||
sha1_step!(ch, s14, s13, 0x5a827999, w13);
|
||||
sha1_step!(ch, s15, s14, 0x5a827999, w14);
|
||||
sha1_step!(ch, s16, s15, 0x5a827999, w15);
|
||||
sha1_step!(ch, s17, s16, 0x5a827999, w16);
|
||||
sha1_step!(ch, s18, s17, 0x5a827999, w17);
|
||||
sha1_step!(ch, s19, s18, 0x5a827999, w18);
|
||||
sha1_step!(ch, s20, s19, 0x5a827999, w19);
|
||||
sha1_step!(parity, s21, s20, 0x6ed9eba1, w20);
|
||||
sha1_step!(parity, s22, s21, 0x6ed9eba1, w21);
|
||||
sha1_step!(parity, s23, s22, 0x6ed9eba1, w22);
|
||||
sha1_step!(parity, s24, s23, 0x6ed9eba1, w23);
|
||||
sha1_step!(parity, s25, s24, 0x6ed9eba1, w24);
|
||||
sha1_step!(parity, s26, s25, 0x6ed9eba1, w25);
|
||||
sha1_step!(parity, s27, s26, 0x6ed9eba1, w26);
|
||||
sha1_step!(parity, s28, s27, 0x6ed9eba1, w27);
|
||||
sha1_step!(parity, s29, s28, 0x6ed9eba1, w28);
|
||||
sha1_step!(parity, s30, s29, 0x6ed9eba1, w29);
|
||||
sha1_step!(parity, s31, s30, 0x6ed9eba1, w30);
|
||||
sha1_step!(parity, s32, s31, 0x6ed9eba1, w31);
|
||||
sha1_step!(parity, s33, s32, 0x6ed9eba1, w32);
|
||||
sha1_step!(parity, s34, s33, 0x6ed9eba1, w33);
|
||||
sha1_step!(parity, s35, s34, 0x6ed9eba1, w34);
|
||||
sha1_step!(parity, s36, s35, 0x6ed9eba1, w35);
|
||||
sha1_step!(parity, s37, s36, 0x6ed9eba1, w36);
|
||||
sha1_step!(parity, s38, s37, 0x6ed9eba1, w37);
|
||||
sha1_step!(parity, s39, s38, 0x6ed9eba1, w38);
|
||||
sha1_step!(parity, s40, s39, 0x6ed9eba1, w39);
|
||||
sha1_step!(maj, s41, s40, 0x8f1bbcdc, w40);
|
||||
sha1_step!(maj, s42, s41, 0x8f1bbcdc, w41);
|
||||
sha1_step!(maj, s43, s42, 0x8f1bbcdc, w42);
|
||||
sha1_step!(maj, s44, s43, 0x8f1bbcdc, w43);
|
||||
sha1_step!(maj, s45, s44, 0x8f1bbcdc, w44);
|
||||
sha1_step!(maj, s46, s45, 0x8f1bbcdc, w45);
|
||||
sha1_step!(maj, s47, s46, 0x8f1bbcdc, w46);
|
||||
sha1_step!(maj, s48, s47, 0x8f1bbcdc, w47);
|
||||
sha1_step!(maj, s49, s48, 0x8f1bbcdc, w48);
|
||||
sha1_step!(maj, s50, s49, 0x8f1bbcdc, w49);
|
||||
sha1_step!(maj, s51, s50, 0x8f1bbcdc, w50);
|
||||
sha1_step!(maj, s52, s51, 0x8f1bbcdc, w51);
|
||||
sha1_step!(maj, s53, s52, 0x8f1bbcdc, w52);
|
||||
sha1_step!(maj, s54, s53, 0x8f1bbcdc, w53);
|
||||
sha1_step!(maj, s55, s54, 0x8f1bbcdc, w54);
|
||||
sha1_step!(maj, s56, s55, 0x8f1bbcdc, w55);
|
||||
sha1_step!(maj, s57, s56, 0x8f1bbcdc, w56);
|
||||
sha1_step!(maj, s58, s57, 0x8f1bbcdc, w57);
|
||||
sha1_step!(maj, s59, s58, 0x8f1bbcdc, w58);
|
||||
sha1_step!(maj, s60, s59, 0x8f1bbcdc, w59);
|
||||
sha1_step!(parity, s61, s60, 0xca62c1d6, w60);
|
||||
sha1_step!(parity, s62, s61, 0xca62c1d6, w61);
|
||||
sha1_step!(parity, s63, s62, 0xca62c1d6, w62);
|
||||
sha1_step!(parity, s64, s63, 0xca62c1d6, w63);
|
||||
sha1_step!(parity, s65, s64, 0xca62c1d6, w64);
|
||||
sha1_step!(parity, s66, s65, 0xca62c1d6, w65);
|
||||
sha1_step!(parity, s67, s66, 0xca62c1d6, w66);
|
||||
sha1_step!(parity, s68, s67, 0xca62c1d6, w67);
|
||||
sha1_step!(parity, s69, s68, 0xca62c1d6, w68);
|
||||
sha1_step!(parity, s70, s69, 0xca62c1d6, w69);
|
||||
sha1_step!(parity, s71, s70, 0xca62c1d6, w70);
|
||||
sha1_step!(parity, s72, s71, 0xca62c1d6, w71);
|
||||
sha1_step!(parity, s73, s72, 0xca62c1d6, w72);
|
||||
sha1_step!(parity, s74, s73, 0xca62c1d6, w73);
|
||||
sha1_step!(parity, s75, s74, 0xca62c1d6, w74);
|
||||
sha1_step!(parity, s76, s75, 0xca62c1d6, w75);
|
||||
sha1_step!(parity, s77, s76, 0xca62c1d6, w76);
|
||||
sha1_step!(parity, s78, s77, 0xca62c1d6, w77);
|
||||
sha1_step!(parity, s79, s78, 0xca62c1d6, w78);
|
||||
sha1_step!(parity, s80, s79, 0xca62c1d6, w79);
|
||||
self.state[0] += s80[0];
|
||||
self.state[1] += s80[1];
|
||||
self.state[2] += s80[2];
|
||||
self.state[3] += s80[3];
|
||||
self.state[4] += s80[4];
|
||||
}
|
||||
|
||||
fn finish(&mut self)
|
||||
{
|
||||
let bitlen = self.l * 8;
|
||||
let k = calculate_k(448, 512, bitlen);
|
||||
// INVARIANT: k is necessarily > 0, and (k + 1) is a multiple of 8
|
||||
let bytes_to_add = (k + 1) / 8;
|
||||
let mut padvec = Vec::with_capacity(bytes_to_add + 8);
|
||||
padvec.push(0x80); // Set the high bit, since the first bit after the data
|
||||
// should be set
|
||||
padvec.resize(bytes_to_add, 0);
|
||||
padvec.write_u64::<BigEndian>(bitlen as u64).expect("Broken writing value to pre-allocated Vec?");
|
||||
self.update(&padvec);
|
||||
self.done = true;
|
||||
assert_eq!(self.buffer.len(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for SHA1
|
||||
{
|
||||
fn new() -> SHA1
|
||||
{
|
||||
SHA1 {
|
||||
state: [ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 ],
|
||||
buffer: Vec::with_capacity(64),
|
||||
done: false,
|
||||
l: 0
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, block: &[u8])
|
||||
{
|
||||
if !self.done {
|
||||
let mut offset = 0;
|
||||
|
||||
self.l += block.len();
|
||||
|
||||
if self.buffer.len() + block.len() < 64 {
|
||||
self.buffer.extend_from_slice(block);
|
||||
return;
|
||||
}
|
||||
|
||||
if self.buffer.len() > 0 {
|
||||
// We must be able to build up a 64 byte chunk, at this point, otherwise
|
||||
// the math above would've been wrong.
|
||||
while self.buffer.len() < 64 {
|
||||
self.buffer.push(block[offset]);
|
||||
offset += 1;
|
||||
}
|
||||
process_u32_block!(self.buffer, 0, self);
|
||||
// Reset the buffer now, we're done with that nonsense for the moment
|
||||
self.buffer.resize(0,0);
|
||||
}
|
||||
|
||||
while (offset + 64) <= block.len() {
|
||||
process_u32_block!(block, offset, self);
|
||||
offset += 64;
|
||||
}
|
||||
|
||||
if offset < block.len() {
|
||||
self.buffer.extend_from_slice(&block[offset..]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn finalize(&mut self) -> Vec<u8>
|
||||
{
|
||||
if !self.done {
|
||||
self.finish();
|
||||
}
|
||||
|
||||
let mut output = Vec::with_capacity(20);
|
||||
output.write_u32::<BigEndian>(self.state[0]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state[1]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state[2]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state[3]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state[4]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output
|
||||
}
|
||||
|
||||
fn block_size() -> usize
|
||||
{
|
||||
512
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use testing::run_test;
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn nist() {
|
||||
let fname = "testdata/sha/nist_sha1.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negl, lbytes) = case.get("l").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
|
||||
assert!(!negl && !negm && !negd);
|
||||
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||
let digest = SHA1::hash(&msg);
|
||||
assert_eq!(dbytes, &digest);
|
||||
});
|
||||
}
|
||||
|
||||
842
src/sha/sha2.rs
Normal file
842
src/sha/sha2.rs
Normal file
@@ -0,0 +1,842 @@
|
||||
use byteorder::{BigEndian,ByteOrder,WriteBytesExt};
|
||||
use sha::shared::calculate_k;
|
||||
use super::super::Hash;
|
||||
|
||||
/// The SHA2-224 hash.
|
||||
///
|
||||
/// To use, you can run it in incremental mode -- by calling new(),
|
||||
/// update() zero or more times, and then finalize() -- or you can
|
||||
/// just invoke the hash directly. For example:
|
||||
///
|
||||
/// ```rust
|
||||
/// use simple_crypto::sha::{Hash,SHA224};
|
||||
///
|
||||
/// let empty = [0; 0];
|
||||
/// // Do the hash using the incremental API
|
||||
/// let mut hashf = SHA224::new();
|
||||
/// hashf.update(&empty);
|
||||
/// let result_incremental = hashf.finalize();
|
||||
/// // Do the hash using the direct API
|
||||
/// let result_direct = SHA224::hash(&empty);
|
||||
/// // ... and they should be the same
|
||||
/// assert_eq!(result_incremental,result_direct);
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct SHA224 {
|
||||
state: SHA256State
|
||||
}
|
||||
|
||||
impl Hash for SHA224 {
|
||||
fn new() -> Self
|
||||
{
|
||||
let state = SHA256State::new([0xc1059ed8,0x367cd507,0x3070dd17,0xf70e5939,
|
||||
0xffc00b31,0x68581511,0x64f98fa7,0xbefa4fa4]);
|
||||
SHA224{ state }
|
||||
}
|
||||
|
||||
fn update(&mut self, data: &[u8])
|
||||
{
|
||||
self.state.update(data);
|
||||
}
|
||||
|
||||
fn finalize(&mut self) -> Vec<u8>
|
||||
{
|
||||
if !self.state.done {
|
||||
self.state.finish();
|
||||
}
|
||||
|
||||
let mut output = Vec::with_capacity(28);
|
||||
output.write_u32::<BigEndian>(self.state.state[0]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state.state[1]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state.state[2]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state.state[3]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state.state[4]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state.state[5]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state.state[6]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output
|
||||
}
|
||||
|
||||
fn block_size() -> usize
|
||||
{
|
||||
512
|
||||
}
|
||||
}
|
||||
|
||||
/// The SHA2-256 hash. [GOOD]
|
||||
///
|
||||
/// To use, you can run it in incremental mode -- by calling new(),
|
||||
/// update() zero or more times, and then finalize() -- or you can
|
||||
/// just invoke the hash directly. For example:
|
||||
///
|
||||
/// ```rust
|
||||
/// use simple_crypto::sha::{Hash,SHA256};
|
||||
///
|
||||
/// let empty = [0; 0];
|
||||
/// // Do the hash using the incremental API
|
||||
/// let mut hashf = SHA256::new();
|
||||
/// hashf.update(&empty);
|
||||
/// let result_incremental = hashf.finalize();
|
||||
/// // Do the hash using the direct API
|
||||
/// let result_direct = SHA256::hash(&empty);
|
||||
/// // ... and they should be the same
|
||||
/// assert_eq!(result_incremental,result_direct);
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct SHA256 {
|
||||
state: SHA256State
|
||||
}
|
||||
|
||||
impl Hash for SHA256 {
|
||||
fn new() -> Self
|
||||
{
|
||||
let state = SHA256State::new([0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,
|
||||
0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19]);
|
||||
SHA256{ state }
|
||||
}
|
||||
|
||||
fn update(&mut self, data: &[u8])
|
||||
{
|
||||
self.state.update(data);
|
||||
}
|
||||
|
||||
fn finalize(&mut self) -> Vec<u8>
|
||||
{
|
||||
if !self.state.done {
|
||||
self.state.finish();
|
||||
}
|
||||
|
||||
let mut output = Vec::with_capacity(28);
|
||||
output.write_u32::<BigEndian>(self.state.state[0]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state.state[1]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state.state[2]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state.state[3]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state.state[4]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state.state[5]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state.state[6]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u32::<BigEndian>(self.state.state[7]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output
|
||||
}
|
||||
|
||||
fn block_size() -> usize
|
||||
{
|
||||
512
|
||||
}
|
||||
}
|
||||
|
||||
/// The SHA2-384 hash. [BETTER]
|
||||
///
|
||||
/// To use, you can run it in incremental mode -- by calling new(),
|
||||
/// update() zero or more times, and then finalize() -- or you can
|
||||
/// just invoke the hash directly. For example:
|
||||
///
|
||||
/// ```rust
|
||||
/// use simple_crypto::sha::{Hash,SHA384};
|
||||
///
|
||||
/// let empty = [0; 0];
|
||||
/// // Do the hash using the incremental API
|
||||
/// let mut hashf = SHA384::new();
|
||||
/// hashf.update(&empty);
|
||||
/// let result_incremental = hashf.finalize();
|
||||
/// // Do the hash using the direct API
|
||||
/// let result_direct = SHA384::hash(&empty);
|
||||
/// // ... and they should be the same
|
||||
/// assert_eq!(result_incremental,result_direct);
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct SHA384 {
|
||||
state: SHA512State
|
||||
}
|
||||
|
||||
impl Hash for SHA384 {
|
||||
fn new() -> Self
|
||||
{
|
||||
let state = SHA512State::new([0xcbbb9d5dc1059ed8,0x629a292a367cd507,
|
||||
0x9159015a3070dd17,0x152fecd8f70e5939,
|
||||
0x67332667ffc00b31,0x8eb44a8768581511,
|
||||
0xdb0c2e0d64f98fa7,0x47b5481dbefa4fa4]);
|
||||
SHA384{ state }
|
||||
}
|
||||
|
||||
fn update(&mut self, data: &[u8])
|
||||
{
|
||||
self.state.update(data);
|
||||
}
|
||||
|
||||
fn finalize(&mut self) -> Vec<u8>
|
||||
{
|
||||
if !self.state.done {
|
||||
self.state.finish();
|
||||
}
|
||||
|
||||
let mut output = Vec::with_capacity(64);
|
||||
output.write_u64::<BigEndian>(self.state.state[0]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u64::<BigEndian>(self.state.state[1]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u64::<BigEndian>(self.state.state[2]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u64::<BigEndian>(self.state.state[3]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u64::<BigEndian>(self.state.state[4]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u64::<BigEndian>(self.state.state[5]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output
|
||||
}
|
||||
|
||||
fn block_size() -> usize
|
||||
{
|
||||
1024
|
||||
}
|
||||
}
|
||||
|
||||
/// The SHA2-512 hash. [BEST]
|
||||
///
|
||||
/// To use, you can run it in incremental mode -- by calling new(),
|
||||
/// update() zero or more times, and then finalize() -- or you can
|
||||
/// just invoke the hash directly. For example:
|
||||
///
|
||||
/// ```rust
|
||||
/// use simple_crypto::sha::{Hash,SHA512};
|
||||
///
|
||||
/// let empty = [0; 0];
|
||||
/// // Do the hash using the incremental API
|
||||
/// let mut hashf = SHA512::new();
|
||||
/// hashf.update(&empty);
|
||||
/// let result_incremental = hashf.finalize();
|
||||
/// // Do the hash using the direct API
|
||||
/// let result_direct = SHA512::hash(&empty);
|
||||
/// // ... and they should be the same
|
||||
/// assert_eq!(result_incremental,result_direct);
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct SHA512 {
|
||||
state: SHA512State
|
||||
}
|
||||
|
||||
impl Hash for SHA512 {
|
||||
fn new() -> Self
|
||||
{
|
||||
let state = SHA512State::new([0x6a09e667f3bcc908,0xbb67ae8584caa73b,
|
||||
0x3c6ef372fe94f82b,0xa54ff53a5f1d36f1,
|
||||
0x510e527fade682d1,0x9b05688c2b3e6c1f,
|
||||
0x1f83d9abfb41bd6b,0x5be0cd19137e2179]);
|
||||
SHA512{ state }
|
||||
}
|
||||
|
||||
fn update(&mut self, data: &[u8])
|
||||
{
|
||||
self.state.update(data);
|
||||
}
|
||||
|
||||
fn finalize(&mut self) -> Vec<u8>
|
||||
{
|
||||
if !self.state.done {
|
||||
self.state.finish();
|
||||
}
|
||||
|
||||
let mut output = Vec::with_capacity(64);
|
||||
output.write_u64::<BigEndian>(self.state.state[0]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u64::<BigEndian>(self.state.state[1]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u64::<BigEndian>(self.state.state[2]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u64::<BigEndian>(self.state.state[3]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u64::<BigEndian>(self.state.state[4]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u64::<BigEndian>(self.state.state[5]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u64::<BigEndian>(self.state.state[6]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output.write_u64::<BigEndian>(self.state.state[7]).expect("Broken writing value to pre-allocated Vec?");
|
||||
output
|
||||
}
|
||||
|
||||
fn block_size() -> usize
|
||||
{
|
||||
1024
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! bsig256_0 {
|
||||
($x: ident) => {
|
||||
$x.rotate_right(2) ^ $x.rotate_right(13) ^ $x.rotate_right(22)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! bsig256_1 {
|
||||
($x: ident) => {
|
||||
$x.rotate_right(6) ^ $x.rotate_right(11) ^ $x.rotate_right(25)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! lsig256_0 {
|
||||
($x: ident) => {
|
||||
$x.rotate_right(7) ^ $x.rotate_right(18) ^ ($x >> 3)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! lsig256_1 {
|
||||
($x: ident) => {
|
||||
$x.rotate_right(17) ^ $x.rotate_right(19) ^ ($x >> 10)
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct SHA256State {
|
||||
state: [u32; 8],
|
||||
buffer: Vec<u8>,
|
||||
done: bool,
|
||||
l: usize
|
||||
}
|
||||
|
||||
impl SHA256State {
|
||||
fn new(values: [u32; 8]) -> Self {
|
||||
SHA256State {
|
||||
state: values,
|
||||
buffer: Vec::with_capacity(64),
|
||||
done: false,
|
||||
l: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn process(&mut self, w00: u32, w01: u32, w02: u32, w03: u32,
|
||||
w04: u32, w05: u32, w06: u32, w07: u32,
|
||||
w08: u32, w09: u32, w10: u32, w11: u32,
|
||||
w12: u32, w13: u32, w14: u32, w15: u32)
|
||||
{
|
||||
let w16 = lsig256_1!(w14) + w09 + lsig256_0!(w01) + w00;
|
||||
let w17 = lsig256_1!(w15) + w10 + lsig256_0!(w02) + w01;
|
||||
let w18 = lsig256_1!(w16) + w11 + lsig256_0!(w03) + w02;
|
||||
let w19 = lsig256_1!(w17) + w12 + lsig256_0!(w04) + w03;
|
||||
let w20 = lsig256_1!(w18) + w13 + lsig256_0!(w05) + w04;
|
||||
let w21 = lsig256_1!(w19) + w14 + lsig256_0!(w06) + w05;
|
||||
let w22 = lsig256_1!(w20) + w15 + lsig256_0!(w07) + w06;
|
||||
let w23 = lsig256_1!(w21) + w16 + lsig256_0!(w08) + w07;
|
||||
let w24 = lsig256_1!(w22) + w17 + lsig256_0!(w09) + w08;
|
||||
let w25 = lsig256_1!(w23) + w18 + lsig256_0!(w10) + w09;
|
||||
let w26 = lsig256_1!(w24) + w19 + lsig256_0!(w11) + w10;
|
||||
let w27 = lsig256_1!(w25) + w20 + lsig256_0!(w12) + w11;
|
||||
let w28 = lsig256_1!(w26) + w21 + lsig256_0!(w13) + w12;
|
||||
let w29 = lsig256_1!(w27) + w22 + lsig256_0!(w14) + w13;
|
||||
let w30 = lsig256_1!(w28) + w23 + lsig256_0!(w15) + w14;
|
||||
let w31 = lsig256_1!(w29) + w24 + lsig256_0!(w16) + w15;
|
||||
let w32 = lsig256_1!(w30) + w25 + lsig256_0!(w17) + w16;
|
||||
let w33 = lsig256_1!(w31) + w26 + lsig256_0!(w18) + w17;
|
||||
let w34 = lsig256_1!(w32) + w27 + lsig256_0!(w19) + w18;
|
||||
let w35 = lsig256_1!(w33) + w28 + lsig256_0!(w20) + w19;
|
||||
let w36 = lsig256_1!(w34) + w29 + lsig256_0!(w21) + w20;
|
||||
let w37 = lsig256_1!(w35) + w30 + lsig256_0!(w22) + w21;
|
||||
let w38 = lsig256_1!(w36) + w31 + lsig256_0!(w23) + w22;
|
||||
let w39 = lsig256_1!(w37) + w32 + lsig256_0!(w24) + w23;
|
||||
let w40 = lsig256_1!(w38) + w33 + lsig256_0!(w25) + w24;
|
||||
let w41 = lsig256_1!(w39) + w34 + lsig256_0!(w26) + w25;
|
||||
let w42 = lsig256_1!(w40) + w35 + lsig256_0!(w27) + w26;
|
||||
let w43 = lsig256_1!(w41) + w36 + lsig256_0!(w28) + w27;
|
||||
let w44 = lsig256_1!(w42) + w37 + lsig256_0!(w29) + w28;
|
||||
let w45 = lsig256_1!(w43) + w38 + lsig256_0!(w30) + w29;
|
||||
let w46 = lsig256_1!(w44) + w39 + lsig256_0!(w31) + w30;
|
||||
let w47 = lsig256_1!(w45) + w40 + lsig256_0!(w32) + w31;
|
||||
let w48 = lsig256_1!(w46) + w41 + lsig256_0!(w33) + w32;
|
||||
let w49 = lsig256_1!(w47) + w42 + lsig256_0!(w34) + w33;
|
||||
let w50 = lsig256_1!(w48) + w43 + lsig256_0!(w35) + w34;
|
||||
let w51 = lsig256_1!(w49) + w44 + lsig256_0!(w36) + w35;
|
||||
let w52 = lsig256_1!(w50) + w45 + lsig256_0!(w37) + w36;
|
||||
let w53 = lsig256_1!(w51) + w46 + lsig256_0!(w38) + w37;
|
||||
let w54 = lsig256_1!(w52) + w47 + lsig256_0!(w39) + w38;
|
||||
let w55 = lsig256_1!(w53) + w48 + lsig256_0!(w40) + w39;
|
||||
let w56 = lsig256_1!(w54) + w49 + lsig256_0!(w41) + w40;
|
||||
let w57 = lsig256_1!(w55) + w50 + lsig256_0!(w42) + w41;
|
||||
let w58 = lsig256_1!(w56) + w51 + lsig256_0!(w43) + w42;
|
||||
let w59 = lsig256_1!(w57) + w52 + lsig256_0!(w44) + w43;
|
||||
let w60 = lsig256_1!(w58) + w53 + lsig256_0!(w45) + w44;
|
||||
let w61 = lsig256_1!(w59) + w54 + lsig256_0!(w46) + w45;
|
||||
let w62 = lsig256_1!(w60) + w55 + lsig256_0!(w47) + w46;
|
||||
let w63 = lsig256_1!(w61) + w56 + lsig256_0!(w48) + w47;
|
||||
let s01 = step256(self.state,0x428a2f98,w00);
|
||||
let s02 = step256(s01,0x71374491,w01);
|
||||
let s03 = step256(s02,0xb5c0fbcf,w02);
|
||||
let s04 = step256(s03,0xe9b5dba5,w03);
|
||||
let s05 = step256(s04,0x3956c25b,w04);
|
||||
let s06 = step256(s05,0x59f111f1,w05);
|
||||
let s07 = step256(s06,0x923f82a4,w06);
|
||||
let s08 = step256(s07,0xab1c5ed5,w07);
|
||||
let s09 = step256(s08,0xd807aa98,w08);
|
||||
let s10 = step256(s09,0x12835b01,w09);
|
||||
let s11 = step256(s10,0x243185be,w10);
|
||||
let s12 = step256(s11,0x550c7dc3,w11);
|
||||
let s13 = step256(s12,0x72be5d74,w12);
|
||||
let s14 = step256(s13,0x80deb1fe,w13);
|
||||
let s15 = step256(s14,0x9bdc06a7,w14);
|
||||
let s16 = step256(s15,0xc19bf174,w15);
|
||||
let s17 = step256(s16,0xe49b69c1,w16);
|
||||
let s18 = step256(s17,0xefbe4786,w17);
|
||||
let s19 = step256(s18,0x0fc19dc6,w18);
|
||||
let s20 = step256(s19,0x240ca1cc,w19);
|
||||
let s21 = step256(s20,0x2de92c6f,w20);
|
||||
let s22 = step256(s21,0x4a7484aa,w21);
|
||||
let s23 = step256(s22,0x5cb0a9dc,w22);
|
||||
let s24 = step256(s23,0x76f988da,w23);
|
||||
let s25 = step256(s24,0x983e5152,w24);
|
||||
let s26 = step256(s25,0xa831c66d,w25);
|
||||
let s27 = step256(s26,0xb00327c8,w26);
|
||||
let s28 = step256(s27,0xbf597fc7,w27);
|
||||
let s29 = step256(s28,0xc6e00bf3,w28);
|
||||
let s30 = step256(s29,0xd5a79147,w29);
|
||||
let s31 = step256(s30,0x06ca6351,w30);
|
||||
let s32 = step256(s31,0x14292967,w31);
|
||||
let s33 = step256(s32,0x27b70a85,w32);
|
||||
let s34 = step256(s33,0x2e1b2138,w33);
|
||||
let s35 = step256(s34,0x4d2c6dfc,w34);
|
||||
let s36 = step256(s35,0x53380d13,w35);
|
||||
let s37 = step256(s36,0x650a7354,w36);
|
||||
let s38 = step256(s37,0x766a0abb,w37);
|
||||
let s39 = step256(s38,0x81c2c92e,w38);
|
||||
let s40 = step256(s39,0x92722c85,w39);
|
||||
let s41 = step256(s40,0xa2bfe8a1,w40);
|
||||
let s42 = step256(s41,0xa81a664b,w41);
|
||||
let s43 = step256(s42,0xc24b8b70,w42);
|
||||
let s44 = step256(s43,0xc76c51a3,w43);
|
||||
let s45 = step256(s44,0xd192e819,w44);
|
||||
let s46 = step256(s45,0xd6990624,w45);
|
||||
let s47 = step256(s46,0xf40e3585,w46);
|
||||
let s48 = step256(s47,0x106aa070,w47);
|
||||
let s49 = step256(s48,0x19a4c116,w48);
|
||||
let s50 = step256(s49,0x1e376c08,w49);
|
||||
let s51 = step256(s50,0x2748774c,w50);
|
||||
let s52 = step256(s51,0x34b0bcb5,w51);
|
||||
let s53 = step256(s52,0x391c0cb3,w52);
|
||||
let s54 = step256(s53,0x4ed8aa4a,w53);
|
||||
let s55 = step256(s54,0x5b9cca4f,w54);
|
||||
let s56 = step256(s55,0x682e6ff3,w55);
|
||||
let s57 = step256(s56,0x748f82ee,w56);
|
||||
let s58 = step256(s57,0x78a5636f,w57);
|
||||
let s59 = step256(s58,0x84c87814,w58);
|
||||
let s60 = step256(s59,0x8cc70208,w59);
|
||||
let s61 = step256(s60,0x90befffa,w60);
|
||||
let s62 = step256(s61,0xa4506ceb,w61);
|
||||
let s63 = step256(s62,0xbef9a3f7,w62);
|
||||
let s64 = step256(s63,0xc67178f2,w63);
|
||||
self.state[0] += s64[0];
|
||||
self.state[1] += s64[1];
|
||||
self.state[2] += s64[2];
|
||||
self.state[3] += s64[3];
|
||||
self.state[4] += s64[4];
|
||||
self.state[5] += s64[5];
|
||||
self.state[6] += s64[6];
|
||||
self.state[7] += s64[7];
|
||||
}
|
||||
|
||||
fn update(&mut self, block: &[u8]) {
|
||||
if !self.done {
|
||||
let mut offset = 0;
|
||||
|
||||
self.l += block.len();
|
||||
|
||||
if self.buffer.len() + block.len() < 64 {
|
||||
self.buffer.extend_from_slice(block);
|
||||
return;
|
||||
}
|
||||
|
||||
if self.buffer.len() > 0 {
|
||||
// We must be able to build up a 64 byte chunk, at this point, otherwise
|
||||
// the math above would've been wrong.
|
||||
while self.buffer.len() < 64 {
|
||||
self.buffer.push(block[offset]);
|
||||
offset += 1;
|
||||
}
|
||||
process_u32_block!(self.buffer, 0, self);
|
||||
// Reset the buffer now, we're done with that nonsense for the moment
|
||||
self.buffer.resize(0,0);
|
||||
}
|
||||
|
||||
while (offset + 64) <= block.len() {
|
||||
process_u32_block!(block, offset, self);
|
||||
offset += 64;
|
||||
}
|
||||
|
||||
if offset < block.len() {
|
||||
self.buffer.extend_from_slice(&block[offset..]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn finish(&mut self) {
|
||||
let bitlen = self.l * 8;
|
||||
let k = calculate_k(448, 512, bitlen);
|
||||
// INVARIANT: k is necessarily > 0, and (k + 1) is a multiple of 8
|
||||
let bytes_to_add = (k + 1) / 8;
|
||||
let mut padvec = Vec::with_capacity(bytes_to_add + 8);
|
||||
padvec.push(0x80); // Set the high bit, since the first bit after the data
|
||||
// should be set
|
||||
padvec.resize(bytes_to_add, 0);
|
||||
padvec.write_u64::<BigEndian>(bitlen as u64).expect("Broken writing value to pre-allocated Vec?");
|
||||
self.update(&padvec);
|
||||
self.done = true;
|
||||
assert_eq!(self.buffer.len(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn step256(state0: [u32; 8], k: u32, w: u32) -> [u32; 8]
|
||||
{
|
||||
let [a,b,c,d,e,f,g,h] = state0;
|
||||
let t1 = h + bsig256_1!(e) + ch!(e,f,g) + k + w;
|
||||
let t2 = bsig256_0!(a) + maj!(a,b,c);
|
||||
let hp = g;
|
||||
let gp = f;
|
||||
let fp = e;
|
||||
let ep = d + t1;
|
||||
let dp = c;
|
||||
let cp = b;
|
||||
let bp = a;
|
||||
let ap = t1 + t2;
|
||||
[ap,bp,cp,dp,ep,fp,gp,hp]
|
||||
}
|
||||
|
||||
macro_rules! bsig512_0 {
|
||||
($x: ident) => {
|
||||
$x.rotate_right(28) ^ $x.rotate_right(34) ^ $x.rotate_right(39)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! bsig512_1 {
|
||||
($x: ident) => {
|
||||
$x.rotate_right(14) ^ $x.rotate_right(18) ^ $x.rotate_right(41)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! lsig512_0 {
|
||||
($x: ident) => {
|
||||
$x.rotate_right(1) ^ $x.rotate_right(8) ^ ($x >> 7)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! lsig512_1 {
|
||||
($x: ident) => {
|
||||
$x.rotate_right(19) ^ $x.rotate_right(61) ^ ($x >> 6)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! process_u64_block {
|
||||
($buf: expr, $off: expr, $self: ident) => {{
|
||||
let w00 = BigEndian::read_u64(&$buf[$off+0..]);
|
||||
let w01 = BigEndian::read_u64(&$buf[$off+8..]);
|
||||
let w02 = BigEndian::read_u64(&$buf[$off+16..]);
|
||||
let w03 = BigEndian::read_u64(&$buf[$off+24..]);
|
||||
let w04 = BigEndian::read_u64(&$buf[$off+32..]);
|
||||
let w05 = BigEndian::read_u64(&$buf[$off+40..]);
|
||||
let w06 = BigEndian::read_u64(&$buf[$off+48..]);
|
||||
let w07 = BigEndian::read_u64(&$buf[$off+56..]);
|
||||
let w08 = BigEndian::read_u64(&$buf[$off+64..]);
|
||||
let w09 = BigEndian::read_u64(&$buf[$off+72..]);
|
||||
let w10 = BigEndian::read_u64(&$buf[$off+80..]);
|
||||
let w11 = BigEndian::read_u64(&$buf[$off+88..]);
|
||||
let w12 = BigEndian::read_u64(&$buf[$off+96..]);
|
||||
let w13 = BigEndian::read_u64(&$buf[$off+104..]);
|
||||
let w14 = BigEndian::read_u64(&$buf[$off+112..]);
|
||||
let w15 = BigEndian::read_u64(&$buf[$off+120..]);
|
||||
$self.process(w00, w01, w02, w03, w04, w05, w06, w07,
|
||||
w08, w09, w10, w11, w12, w13, w14, w15);
|
||||
}};
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct SHA512State {
|
||||
state: [u64; 8],
|
||||
buffer: Vec<u8>,
|
||||
done: bool,
|
||||
l: usize
|
||||
}
|
||||
|
||||
impl SHA512State {
|
||||
fn new(values: [u64; 8]) -> Self {
|
||||
SHA512State {
|
||||
state: values,
|
||||
buffer: Vec::with_capacity(128),
|
||||
done: false,
|
||||
l: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn process(&mut self, w00: u64, w01: u64, w02: u64, w03: u64,
|
||||
w04: u64, w05: u64, w06: u64, w07: u64,
|
||||
w08: u64, w09: u64, w10: u64, w11: u64,
|
||||
w12: u64, w13: u64, w14: u64, w15: u64)
|
||||
{
|
||||
let w16 = lsig512_1!(w14) + w09 + lsig512_0!(w01) + w00;
|
||||
let w17 = lsig512_1!(w15) + w10 + lsig512_0!(w02) + w01;
|
||||
let w18 = lsig512_1!(w16) + w11 + lsig512_0!(w03) + w02;
|
||||
let w19 = lsig512_1!(w17) + w12 + lsig512_0!(w04) + w03;
|
||||
let w20 = lsig512_1!(w18) + w13 + lsig512_0!(w05) + w04;
|
||||
let w21 = lsig512_1!(w19) + w14 + lsig512_0!(w06) + w05;
|
||||
let w22 = lsig512_1!(w20) + w15 + lsig512_0!(w07) + w06;
|
||||
let w23 = lsig512_1!(w21) + w16 + lsig512_0!(w08) + w07;
|
||||
let w24 = lsig512_1!(w22) + w17 + lsig512_0!(w09) + w08;
|
||||
let w25 = lsig512_1!(w23) + w18 + lsig512_0!(w10) + w09;
|
||||
let w26 = lsig512_1!(w24) + w19 + lsig512_0!(w11) + w10;
|
||||
let w27 = lsig512_1!(w25) + w20 + lsig512_0!(w12) + w11;
|
||||
let w28 = lsig512_1!(w26) + w21 + lsig512_0!(w13) + w12;
|
||||
let w29 = lsig512_1!(w27) + w22 + lsig512_0!(w14) + w13;
|
||||
let w30 = lsig512_1!(w28) + w23 + lsig512_0!(w15) + w14;
|
||||
let w31 = lsig512_1!(w29) + w24 + lsig512_0!(w16) + w15;
|
||||
let w32 = lsig512_1!(w30) + w25 + lsig512_0!(w17) + w16;
|
||||
let w33 = lsig512_1!(w31) + w26 + lsig512_0!(w18) + w17;
|
||||
let w34 = lsig512_1!(w32) + w27 + lsig512_0!(w19) + w18;
|
||||
let w35 = lsig512_1!(w33) + w28 + lsig512_0!(w20) + w19;
|
||||
let w36 = lsig512_1!(w34) + w29 + lsig512_0!(w21) + w20;
|
||||
let w37 = lsig512_1!(w35) + w30 + lsig512_0!(w22) + w21;
|
||||
let w38 = lsig512_1!(w36) + w31 + lsig512_0!(w23) + w22;
|
||||
let w39 = lsig512_1!(w37) + w32 + lsig512_0!(w24) + w23;
|
||||
let w40 = lsig512_1!(w38) + w33 + lsig512_0!(w25) + w24;
|
||||
let w41 = lsig512_1!(w39) + w34 + lsig512_0!(w26) + w25;
|
||||
let w42 = lsig512_1!(w40) + w35 + lsig512_0!(w27) + w26;
|
||||
let w43 = lsig512_1!(w41) + w36 + lsig512_0!(w28) + w27;
|
||||
let w44 = lsig512_1!(w42) + w37 + lsig512_0!(w29) + w28;
|
||||
let w45 = lsig512_1!(w43) + w38 + lsig512_0!(w30) + w29;
|
||||
let w46 = lsig512_1!(w44) + w39 + lsig512_0!(w31) + w30;
|
||||
let w47 = lsig512_1!(w45) + w40 + lsig512_0!(w32) + w31;
|
||||
let w48 = lsig512_1!(w46) + w41 + lsig512_0!(w33) + w32;
|
||||
let w49 = lsig512_1!(w47) + w42 + lsig512_0!(w34) + w33;
|
||||
let w50 = lsig512_1!(w48) + w43 + lsig512_0!(w35) + w34;
|
||||
let w51 = lsig512_1!(w49) + w44 + lsig512_0!(w36) + w35;
|
||||
let w52 = lsig512_1!(w50) + w45 + lsig512_0!(w37) + w36;
|
||||
let w53 = lsig512_1!(w51) + w46 + lsig512_0!(w38) + w37;
|
||||
let w54 = lsig512_1!(w52) + w47 + lsig512_0!(w39) + w38;
|
||||
let w55 = lsig512_1!(w53) + w48 + lsig512_0!(w40) + w39;
|
||||
let w56 = lsig512_1!(w54) + w49 + lsig512_0!(w41) + w40;
|
||||
let w57 = lsig512_1!(w55) + w50 + lsig512_0!(w42) + w41;
|
||||
let w58 = lsig512_1!(w56) + w51 + lsig512_0!(w43) + w42;
|
||||
let w59 = lsig512_1!(w57) + w52 + lsig512_0!(w44) + w43;
|
||||
let w60 = lsig512_1!(w58) + w53 + lsig512_0!(w45) + w44;
|
||||
let w61 = lsig512_1!(w59) + w54 + lsig512_0!(w46) + w45;
|
||||
let w62 = lsig512_1!(w60) + w55 + lsig512_0!(w47) + w46;
|
||||
let w63 = lsig512_1!(w61) + w56 + lsig512_0!(w48) + w47;
|
||||
let w64 = lsig512_1!(w62) + w57 + lsig512_0!(w49) + w48;
|
||||
let w65 = lsig512_1!(w63) + w58 + lsig512_0!(w50) + w49;
|
||||
let w66 = lsig512_1!(w64) + w59 + lsig512_0!(w51) + w50;
|
||||
let w67 = lsig512_1!(w65) + w60 + lsig512_0!(w52) + w51;
|
||||
let w68 = lsig512_1!(w66) + w61 + lsig512_0!(w53) + w52;
|
||||
let w69 = lsig512_1!(w67) + w62 + lsig512_0!(w54) + w53;
|
||||
let w70 = lsig512_1!(w68) + w63 + lsig512_0!(w55) + w54;
|
||||
let w71 = lsig512_1!(w69) + w64 + lsig512_0!(w56) + w55;
|
||||
let w72 = lsig512_1!(w70) + w65 + lsig512_0!(w57) + w56;
|
||||
let w73 = lsig512_1!(w71) + w66 + lsig512_0!(w58) + w57;
|
||||
let w74 = lsig512_1!(w72) + w67 + lsig512_0!(w59) + w58;
|
||||
let w75 = lsig512_1!(w73) + w68 + lsig512_0!(w60) + w59;
|
||||
let w76 = lsig512_1!(w74) + w69 + lsig512_0!(w61) + w60;
|
||||
let w77 = lsig512_1!(w75) + w70 + lsig512_0!(w62) + w61;
|
||||
let w78 = lsig512_1!(w76) + w71 + lsig512_0!(w63) + w62;
|
||||
let w79 = lsig512_1!(w77) + w72 + lsig512_0!(w64) + w63;
|
||||
let s01 = step512(self.state,0x428a2f98d728ae22,w00);
|
||||
let s02 = step512(s01,0x7137449123ef65cd,w01);
|
||||
let s03 = step512(s02,0xb5c0fbcfec4d3b2f,w02);
|
||||
let s04 = step512(s03,0xe9b5dba58189dbbc,w03);
|
||||
let s05 = step512(s04,0x3956c25bf348b538,w04);
|
||||
let s06 = step512(s05,0x59f111f1b605d019,w05);
|
||||
let s07 = step512(s06,0x923f82a4af194f9b,w06);
|
||||
let s08 = step512(s07,0xab1c5ed5da6d8118,w07);
|
||||
let s09 = step512(s08,0xd807aa98a3030242,w08);
|
||||
let s10 = step512(s09,0x12835b0145706fbe,w09);
|
||||
let s11 = step512(s10,0x243185be4ee4b28c,w10);
|
||||
let s12 = step512(s11,0x550c7dc3d5ffb4e2,w11);
|
||||
let s13 = step512(s12,0x72be5d74f27b896f,w12);
|
||||
let s14 = step512(s13,0x80deb1fe3b1696b1,w13);
|
||||
let s15 = step512(s14,0x9bdc06a725c71235,w14);
|
||||
let s16 = step512(s15,0xc19bf174cf692694,w15);
|
||||
let s17 = step512(s16,0xe49b69c19ef14ad2,w16);
|
||||
let s18 = step512(s17,0xefbe4786384f25e3,w17);
|
||||
let s19 = step512(s18,0x0fc19dc68b8cd5b5,w18);
|
||||
let s20 = step512(s19,0x240ca1cc77ac9c65,w19);
|
||||
let s21 = step512(s20,0x2de92c6f592b0275,w20);
|
||||
let s22 = step512(s21,0x4a7484aa6ea6e483,w21);
|
||||
let s23 = step512(s22,0x5cb0a9dcbd41fbd4,w22);
|
||||
let s24 = step512(s23,0x76f988da831153b5,w23);
|
||||
let s25 = step512(s24,0x983e5152ee66dfab,w24);
|
||||
let s26 = step512(s25,0xa831c66d2db43210,w25);
|
||||
let s27 = step512(s26,0xb00327c898fb213f,w26);
|
||||
let s28 = step512(s27,0xbf597fc7beef0ee4,w27);
|
||||
let s29 = step512(s28,0xc6e00bf33da88fc2,w28);
|
||||
let s30 = step512(s29,0xd5a79147930aa725,w29);
|
||||
let s31 = step512(s30,0x06ca6351e003826f,w30);
|
||||
let s32 = step512(s31,0x142929670a0e6e70,w31);
|
||||
let s33 = step512(s32,0x27b70a8546d22ffc,w32);
|
||||
let s34 = step512(s33,0x2e1b21385c26c926,w33);
|
||||
let s35 = step512(s34,0x4d2c6dfc5ac42aed,w34);
|
||||
let s36 = step512(s35,0x53380d139d95b3df,w35);
|
||||
let s37 = step512(s36,0x650a73548baf63de,w36);
|
||||
let s38 = step512(s37,0x766a0abb3c77b2a8,w37);
|
||||
let s39 = step512(s38,0x81c2c92e47edaee6,w38);
|
||||
let s40 = step512(s39,0x92722c851482353b,w39);
|
||||
let s41 = step512(s40,0xa2bfe8a14cf10364,w40);
|
||||
let s42 = step512(s41,0xa81a664bbc423001,w41);
|
||||
let s43 = step512(s42,0xc24b8b70d0f89791,w42);
|
||||
let s44 = step512(s43,0xc76c51a30654be30,w43);
|
||||
let s45 = step512(s44,0xd192e819d6ef5218,w44);
|
||||
let s46 = step512(s45,0xd69906245565a910,w45);
|
||||
let s47 = step512(s46,0xf40e35855771202a,w46);
|
||||
let s48 = step512(s47,0x106aa07032bbd1b8,w47);
|
||||
let s49 = step512(s48,0x19a4c116b8d2d0c8,w48);
|
||||
let s50 = step512(s49,0x1e376c085141ab53,w49);
|
||||
let s51 = step512(s50,0x2748774cdf8eeb99,w50);
|
||||
let s52 = step512(s51,0x34b0bcb5e19b48a8,w51);
|
||||
let s53 = step512(s52,0x391c0cb3c5c95a63,w52);
|
||||
let s54 = step512(s53,0x4ed8aa4ae3418acb,w53);
|
||||
let s55 = step512(s54,0x5b9cca4f7763e373,w54);
|
||||
let s56 = step512(s55,0x682e6ff3d6b2b8a3,w55);
|
||||
let s57 = step512(s56,0x748f82ee5defb2fc,w56);
|
||||
let s58 = step512(s57,0x78a5636f43172f60,w57);
|
||||
let s59 = step512(s58,0x84c87814a1f0ab72,w58);
|
||||
let s60 = step512(s59,0x8cc702081a6439ec,w59);
|
||||
let s61 = step512(s60,0x90befffa23631e28,w60);
|
||||
let s62 = step512(s61,0xa4506cebde82bde9,w61);
|
||||
let s63 = step512(s62,0xbef9a3f7b2c67915,w62);
|
||||
let s64 = step512(s63,0xc67178f2e372532b,w63);
|
||||
let s65 = step512(s64,0xca273eceea26619c,w64);
|
||||
let s66 = step512(s65,0xd186b8c721c0c207,w65);
|
||||
let s67 = step512(s66,0xeada7dd6cde0eb1e,w66);
|
||||
let s68 = step512(s67,0xf57d4f7fee6ed178,w67);
|
||||
let s69 = step512(s68,0x06f067aa72176fba,w68);
|
||||
let s70 = step512(s69,0x0a637dc5a2c898a6,w69);
|
||||
let s71 = step512(s70,0x113f9804bef90dae,w70);
|
||||
let s72 = step512(s71,0x1b710b35131c471b,w71);
|
||||
let s73 = step512(s72,0x28db77f523047d84,w72);
|
||||
let s74 = step512(s73,0x32caab7b40c72493,w73);
|
||||
let s75 = step512(s74,0x3c9ebe0a15c9bebc,w74);
|
||||
let s76 = step512(s75,0x431d67c49c100d4c,w75);
|
||||
let s77 = step512(s76,0x4cc5d4becb3e42b6,w76);
|
||||
let s78 = step512(s77,0x597f299cfc657e2a,w77);
|
||||
let s79 = step512(s78,0x5fcb6fab3ad6faec,w78);
|
||||
let s80 = step512(s79,0x6c44198c4a475817,w79);
|
||||
self.state[0] += s80[0];
|
||||
self.state[1] += s80[1];
|
||||
self.state[2] += s80[2];
|
||||
self.state[3] += s80[3];
|
||||
self.state[4] += s80[4];
|
||||
self.state[5] += s80[5];
|
||||
self.state[6] += s80[6];
|
||||
self.state[7] += s80[7];
|
||||
}
|
||||
|
||||
fn update(&mut self, block: &[u8]) {
|
||||
if !self.done {
|
||||
let mut offset = 0;
|
||||
|
||||
self.l += block.len();
|
||||
|
||||
if self.buffer.len() + block.len() < 128 {
|
||||
self.buffer.extend_from_slice(block);
|
||||
return;
|
||||
}
|
||||
|
||||
if self.buffer.len() > 0 {
|
||||
// We must be able to build up a 128 byte chunk, at this point, otherwise
|
||||
// the math above would've been wrong.
|
||||
while self.buffer.len() < 128 {
|
||||
self.buffer.push(block[offset]);
|
||||
offset += 1;
|
||||
}
|
||||
process_u64_block!(self.buffer, 0, self);
|
||||
// Reset the buffer now, we're done with that nonsense for the moment
|
||||
self.buffer.resize(0,0);
|
||||
}
|
||||
|
||||
while (offset + 128) <= block.len() {
|
||||
process_u64_block!(block, offset, self);
|
||||
offset += 128;
|
||||
}
|
||||
|
||||
if offset < block.len() {
|
||||
self.buffer.extend_from_slice(&block[offset..]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn finish(&mut self) {
|
||||
let bitlen = self.l * 8;
|
||||
let k = calculate_k(896, 1024, bitlen);
|
||||
// INVARIANT: k is necessarily > 0, and (k + 1) is a multiple of 8
|
||||
let bytes_to_add = (k + 1) / 8;
|
||||
let mut padvec = Vec::with_capacity(bytes_to_add + 16);
|
||||
padvec.push(0x80); // Set the high bit, since the first bit after the data
|
||||
// should be set
|
||||
padvec.resize(bytes_to_add, 0);
|
||||
padvec.write_u128::<BigEndian>(bitlen as u128).expect("Broken writing value to pre-allocated Vec?");
|
||||
self.update(&padvec);
|
||||
self.done = true;
|
||||
assert_eq!(self.buffer.len(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn step512(state0: [u64; 8], k: u64, w: u64) -> [u64; 8]
|
||||
{
|
||||
let [a,b,c,d,e,f,g,h] = state0;
|
||||
let t1 = h + bsig512_1!(e) + ch!(e,f,g) + k + w;
|
||||
let t2 = bsig512_0!(a) + maj!(a,b,c);
|
||||
let hp = g;
|
||||
let gp = f;
|
||||
let fp = e;
|
||||
let ep = d + t1;
|
||||
let dp = c;
|
||||
let cp = b;
|
||||
let bp = a;
|
||||
let ap = t1 + t2;
|
||||
[ap,bp,cp,dp,ep,fp,gp,hp]
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use testing::run_test;
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn nist_sha224() {
|
||||
let fname = "testdata/sha/nist_sha224.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negl, lbytes) = case.get("l").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
|
||||
assert!(!negl && !negm && !negd);
|
||||
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||
let digest = SHA224::hash(&msg);
|
||||
assert_eq!(dbytes, &digest);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn nist_sha256() {
|
||||
let fname = "testdata/sha/nist_sha256.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negl, lbytes) = case.get("l").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
|
||||
assert!(!negl && !negm && !negd);
|
||||
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||
let digest = SHA256::hash(&msg);
|
||||
assert_eq!(dbytes, &digest);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn nist_sha384() {
|
||||
let fname = "testdata/sha/nist_sha384.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negl, lbytes) = case.get("l").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
|
||||
assert!(!negl && !negm && !negd);
|
||||
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||
let digest = SHA384::hash(&msg);
|
||||
assert_eq!(dbytes, &digest);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn nist_sha512() {
|
||||
let fname = "testdata/sha/nist_sha512.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negl, lbytes) = case.get("l").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
|
||||
assert!(!negl && !negm && !negd);
|
||||
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||
let digest = SHA512::hash(&msg);
|
||||
assert_eq!(dbytes, &digest);
|
||||
});
|
||||
}
|
||||
610
src/sha/sha3.rs
Normal file
610
src/sha/sha3.rs
Normal file
@@ -0,0 +1,610 @@
|
||||
use super::super::Hash;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Keccak {
|
||||
rate_in_bytes: usize,
|
||||
rate_in_longs: usize,
|
||||
buffer: Vec<u8>,
|
||||
state: [u64; 25], // This is Keccak-f[1600]
|
||||
output: Option<Vec<u8>>
|
||||
}
|
||||
|
||||
const KECCAK_ROUND_CONSTANTS: [u64; 24] =
|
||||
[ 0x0000000000000001u64, 0x0000000000008082u64,
|
||||
0x800000000000808au64, 0x8000000080008000u64,
|
||||
0x000000000000808bu64, 0x0000000080000001u64,
|
||||
0x8000000080008081u64, 0x8000000000008009u64,
|
||||
0x000000000000008au64, 0x0000000000000088u64,
|
||||
0x0000000080008009u64, 0x000000008000000au64,
|
||||
0x000000008000808bu64, 0x800000000000008bu64,
|
||||
0x8000000000008089u64, 0x8000000000008003u64,
|
||||
0x8000000000008002u64, 0x8000000000000080u64,
|
||||
0x000000000000800au64, 0x800000008000000au64,
|
||||
0x8000000080008081u64, 0x8000000000008080u64,
|
||||
0x0000000080000001u64, 0x8000000080008008u64,
|
||||
];
|
||||
|
||||
macro_rules! absorb {
|
||||
($self: ident, $block: expr, $sidx: expr) => {{
|
||||
let mut i = 0;
|
||||
let mut off = 0;
|
||||
|
||||
while i < $self.rate_in_longs {
|
||||
let word = ($block[$sidx+off+0] as u64) << 00 |
|
||||
($block[$sidx+off+1] as u64) << 08 |
|
||||
($block[$sidx+off+2] as u64) << 16 |
|
||||
($block[$sidx+off+3] as u64) << 24 |
|
||||
($block[$sidx+off+4] as u64) << 32 |
|
||||
($block[$sidx+off+5] as u64) << 40 |
|
||||
($block[$sidx+off+6] as u64) << 48 |
|
||||
($block[$sidx+off+7] as u64) << 56;
|
||||
$self.state[i] ^= word;
|
||||
off += 8;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
$self.permute();
|
||||
}};
|
||||
}
|
||||
|
||||
impl Keccak {
|
||||
pub fn new(rate: usize) -> Self
|
||||
{
|
||||
assert_eq!(rate % 64, 0);
|
||||
Keccak {
|
||||
rate_in_bytes: rate / 8,
|
||||
rate_in_longs: rate / 64,
|
||||
buffer: Vec::with_capacity(rate),
|
||||
state: [0; 25],
|
||||
output: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn permute(&mut self)
|
||||
{
|
||||
// This is a translation of the very easy-to-read implementation in BouncyCastle
|
||||
for i in 0..24 {
|
||||
// Theta!
|
||||
let c0 = self.state[0] ^ self.state[5] ^ self.state[10] ^ self.state[15] ^ self.state[20];
|
||||
let c1 = self.state[1] ^ self.state[6] ^ self.state[11] ^ self.state[16] ^ self.state[21];
|
||||
let c2 = self.state[2] ^ self.state[7] ^ self.state[12] ^ self.state[17] ^ self.state[22];
|
||||
let c3 = self.state[3] ^ self.state[8] ^ self.state[13] ^ self.state[18] ^ self.state[23];
|
||||
let c4 = self.state[4] ^ self.state[9] ^ self.state[14] ^ self.state[19] ^ self.state[24];
|
||||
let d0 = c0.rotate_left(1) ^ c3;
|
||||
let d1 = c1.rotate_left(1) ^ c4;
|
||||
let d2 = c2.rotate_left(1) ^ c0;
|
||||
let d3 = c3.rotate_left(1) ^ c1;
|
||||
let d4 = c4.rotate_left(1) ^ c2;
|
||||
self.state[0] ^= d1; self.state[5] ^= d1; self.state[10] ^= d1; self.state[15] ^= d1; self.state[20] ^= d1;
|
||||
self.state[1] ^= d2; self.state[6] ^= d2; self.state[11] ^= d2; self.state[16] ^= d2; self.state[21] ^= d2;
|
||||
self.state[2] ^= d3; self.state[7] ^= d3; self.state[12] ^= d3; self.state[17] ^= d3; self.state[22] ^= d3;
|
||||
self.state[3] ^= d4; self.state[8] ^= d4; self.state[13] ^= d4; self.state[18] ^= d4; self.state[23] ^= d4;
|
||||
self.state[4] ^= d0; self.state[9] ^= d0; self.state[14] ^= d0; self.state[19] ^= d0; self.state[24] ^= d0;
|
||||
// Rho & Pi!
|
||||
let t1 = self.state[01].rotate_left(1);
|
||||
self.state[01] = self.state[06].rotate_left(44);
|
||||
self.state[06] = self.state[09].rotate_left(20);
|
||||
self.state[09] = self.state[22].rotate_left(61);
|
||||
self.state[22] = self.state[14].rotate_left(39);
|
||||
self.state[14] = self.state[20].rotate_left(18);
|
||||
self.state[20] = self.state[02].rotate_left(62);
|
||||
self.state[02] = self.state[12].rotate_left(43);
|
||||
self.state[12] = self.state[13].rotate_left(25);
|
||||
self.state[13] = self.state[19].rotate_left(8);
|
||||
self.state[19] = self.state[23].rotate_left(56);
|
||||
self.state[23] = self.state[15].rotate_left(41);
|
||||
self.state[15] = self.state[04].rotate_left(27);
|
||||
self.state[04] = self.state[24].rotate_left(14);
|
||||
self.state[24] = self.state[21].rotate_left(2);
|
||||
self.state[21] = self.state[08].rotate_left(55);
|
||||
self.state[08] = self.state[16].rotate_left(45);
|
||||
self.state[16] = self.state[05].rotate_left(36);
|
||||
self.state[05] = self.state[03].rotate_left(28);
|
||||
self.state[03] = self.state[18].rotate_left(21);
|
||||
self.state[18] = self.state[17].rotate_left(15);
|
||||
self.state[17] = self.state[11].rotate_left(10);
|
||||
self.state[11] = self.state[07].rotate_left(6);
|
||||
self.state[07] = self.state[10].rotate_left(3);
|
||||
self.state[10] = t1;
|
||||
// Chi!
|
||||
let t2 = self.state[00] ^ (!self.state[01] & self.state[02]);
|
||||
let t3 = self.state[01] ^ (!self.state[02] & self.state[03]);
|
||||
self.state[02] ^= !self.state[03] & self.state[04];
|
||||
self.state[03] ^= !self.state[04] & self.state[00];
|
||||
self.state[04] ^= !self.state[00] & self.state[01];
|
||||
self.state[00] = t2;
|
||||
self.state[01] = t3;
|
||||
|
||||
let t4 = self.state[05] ^ (!self.state[06] & self.state[07]);
|
||||
let t5 = self.state[06] ^ (!self.state[07] & self.state[08]);
|
||||
self.state[07] ^= !self.state[08] & self.state[09];
|
||||
self.state[08] ^= !self.state[09] & self.state[05];
|
||||
self.state[09] ^= !self.state[05] & self.state[06];
|
||||
self.state[05] = t4;
|
||||
self.state[06] = t5;
|
||||
|
||||
let t6 = self.state[10] ^ (!self.state[11] & self.state[12]);
|
||||
let t7 = self.state[11] ^ (!self.state[12] & self.state[13]);
|
||||
self.state[12] ^= !self.state[13] & self.state[14];
|
||||
self.state[13] ^= !self.state[14] & self.state[10];
|
||||
self.state[14] ^= !self.state[10] & self.state[11];
|
||||
self.state[10] = t6;
|
||||
self.state[11] = t7;
|
||||
|
||||
let t8 = self.state[15] ^ (!self.state[16] & self.state[17]);
|
||||
let t9 = self.state[16] ^ (!self.state[17] & self.state[18]);
|
||||
self.state[17] ^= !self.state[18] & self.state[19];
|
||||
self.state[18] ^= !self.state[19] & self.state[15];
|
||||
self.state[19] ^= !self.state[15] & self.state[16];
|
||||
self.state[15] = t8;
|
||||
self.state[16] = t9;
|
||||
|
||||
let ta = self.state[20] ^ (!self.state[21] & self.state[22]);
|
||||
let tb = self.state[21] ^ (!self.state[22] & self.state[23]);
|
||||
self.state[22] ^= !self.state[23] & self.state[24];
|
||||
self.state[23] ^= !self.state[24] & self.state[20];
|
||||
self.state[24] ^= !self.state[20] & self.state[21];
|
||||
self.state[20] = ta;
|
||||
self.state[21] = tb;
|
||||
|
||||
// iota
|
||||
self.state[00] ^= KECCAK_ROUND_CONSTANTS[i];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process(&mut self, bytes: &[u8])
|
||||
{
|
||||
if self.output.is_none() {
|
||||
let mut offset = 0;
|
||||
|
||||
if self.buffer.len() + bytes.len() < self.rate_in_bytes {
|
||||
self.buffer.extend_from_slice(bytes);
|
||||
return;
|
||||
}
|
||||
|
||||
if self.buffer.len() > 0 {
|
||||
// We must be able to build up a chunk at our absorbtion rate, at this
|
||||
// point, otherwise the math above would've been wrong.
|
||||
while self.buffer.len() < self.rate_in_bytes {
|
||||
self.buffer.push(bytes[offset]);
|
||||
offset += 1;
|
||||
}
|
||||
absorb!(self, self.buffer, 0);
|
||||
// Reset the buffer now, we're done with that nonsense for the moment
|
||||
self.buffer.resize(0,0);
|
||||
}
|
||||
|
||||
while (offset + self.rate_in_bytes) <= bytes.len() {
|
||||
absorb!(self, bytes, offset);
|
||||
offset += self.rate_in_bytes;
|
||||
}
|
||||
|
||||
if offset < bytes.len() {
|
||||
self.buffer.extend_from_slice(&bytes[offset..]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tag_and_pad(&mut self, tag_byte: u8)
|
||||
{
|
||||
if self.output.is_none() {
|
||||
assert!(self.buffer.len() < self.rate_in_bytes);
|
||||
// what we need to do here is tag on a final 01, to tag that as SHA3,
|
||||
// and then pad it out, with an 0x80 at the end.
|
||||
self.buffer.push(tag_byte);
|
||||
self.buffer.resize(self.rate_in_bytes, 0);
|
||||
self.buffer[self.rate_in_bytes-1] |= 0x80;
|
||||
absorb!(self, self.buffer, 0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn squeeze(&mut self, output_len: usize) -> Vec<u8>
|
||||
{
|
||||
if let Some(ref result) = self.output {
|
||||
result.clone()
|
||||
} else {
|
||||
let mut res = Vec::new();
|
||||
|
||||
while res.len() < output_len {
|
||||
for i in 0..self.rate_in_longs {
|
||||
res.push( (self.state[i] >> 00) as u8 );
|
||||
res.push( (self.state[i] >> 08) as u8 );
|
||||
res.push( (self.state[i] >> 16) as u8 );
|
||||
res.push( (self.state[i] >> 24) as u8 );
|
||||
res.push( (self.state[i] >> 32) as u8 );
|
||||
res.push( (self.state[i] >> 40) as u8 );
|
||||
res.push( (self.state[i] >> 48) as u8 );
|
||||
res.push( (self.state[i] >> 56) as u8 );
|
||||
}
|
||||
self.permute();
|
||||
}
|
||||
|
||||
res.resize(output_len, 0);
|
||||
self.output = Some(res.clone());
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The SHA3-224 hash.
|
||||
///
|
||||
/// To use, you can run it in incremental mode -- by calling new(),
|
||||
/// update() zero or more times, and then finalize() -- or you can
|
||||
/// just invoke the hash directly. For example:
|
||||
///
|
||||
/// ```rust
|
||||
/// use simple_crypto::sha::{Hash,SHA3_224};
|
||||
///
|
||||
/// let empty = [0; 0];
|
||||
/// // Do the hash using the incremental API
|
||||
/// let mut hashf = SHA3_224::new();
|
||||
/// hashf.update(&empty);
|
||||
/// let result_incremental = hashf.finalize();
|
||||
/// // Do the hash using the direct API
|
||||
/// let result_direct = SHA3_224::hash(&empty);
|
||||
/// // ... and they should be the same
|
||||
/// assert_eq!(result_incremental,result_direct);
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct SHA3_224 {
|
||||
state: Keccak
|
||||
}
|
||||
|
||||
impl Hash for SHA3_224 {
|
||||
fn new() -> Self
|
||||
{
|
||||
SHA3_224{ state: Keccak::new(1600 - 448) }
|
||||
}
|
||||
|
||||
fn update(&mut self, buffer: &[u8])
|
||||
{
|
||||
self.state.process(&buffer);
|
||||
}
|
||||
|
||||
fn finalize(&mut self) -> Vec<u8>
|
||||
{
|
||||
self.state.tag_and_pad(0x06);
|
||||
self.state.squeeze(224 / 8)
|
||||
}
|
||||
|
||||
fn block_size() -> usize
|
||||
{
|
||||
1152
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod sha224 {
|
||||
use super::*;
|
||||
use testing::run_test;
|
||||
|
||||
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-224_Msg0.pdf
|
||||
#[test]
|
||||
fn nist_empty_example() {
|
||||
let empty = [0; 0];
|
||||
let hashres = [0x6B,0x4E,0x03,0x42,0x36,0x67,0xDB,0xB7,0x3B,0x6E,0x15,
|
||||
0x45,0x4F,0x0E,0xB1,0xAB,0xD4,0x59,0x7F,0x9A,0x1B,0x07,
|
||||
0x8E,0x3F,0x5B,0x5A,0x6B,0xC7];
|
||||
let mine = SHA3_224::hash(&empty);
|
||||
assert_eq!(hashres.to_vec(), mine);
|
||||
}
|
||||
|
||||
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-224_1600.pdf
|
||||
#[test]
|
||||
fn nist_1600_example() {
|
||||
let example = [0xA3; 200];
|
||||
let hashres = [0x93,0x76,0x81,0x6A,0xBA,0x50,0x3F,0x72,
|
||||
0xF9,0x6C,0xE7,0xEB,0x65,0xAC,0x09,0x5D,
|
||||
0xEE,0xE3,0xBE,0x4B,0xF9,0xBB,0xC2,0xA1,
|
||||
0xCB,0x7E,0x11,0xE0];
|
||||
let mine = SHA3_224::hash(&example);
|
||||
assert_eq!(hashres.to_vec(), mine);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn nist_test_vectors() {
|
||||
let fname = "testdata/sha/nist_sha3_224.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negl, lbytes) = case.get("l").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
|
||||
assert!(!negl && !negm && !negd);
|
||||
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||
let digest = SHA3_224::hash(&msg);
|
||||
assert_eq!(dbytes, &digest);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// The SHA3-256 hash. [GOOD]
|
||||
///
|
||||
/// To use, you can run it in incremental mode -- by calling new(),
|
||||
/// update() zero or more times, and then finalize() -- or you can
|
||||
/// just invoke the hash directly. For example:
|
||||
///
|
||||
/// ```rust
|
||||
/// use simple_crypto::sha::{Hash,SHA3_256};
|
||||
///
|
||||
/// let empty = [0; 0];
|
||||
/// // Do the hash using the incremental API
|
||||
/// let mut hashf = SHA3_256::new();
|
||||
/// hashf.update(&empty);
|
||||
/// let result_incremental = hashf.finalize();
|
||||
/// // Do the hash using the direct API
|
||||
/// let result_direct = SHA3_256::hash(&empty);
|
||||
/// // ... and they should be the same
|
||||
/// assert_eq!(result_incremental,result_direct);
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct SHA3_256 {
|
||||
state: Keccak
|
||||
}
|
||||
|
||||
impl Hash for SHA3_256 {
|
||||
fn new() -> Self
|
||||
{
|
||||
SHA3_256{ state: Keccak::new(1600 - 512) }
|
||||
}
|
||||
|
||||
fn update(&mut self, buffer: &[u8])
|
||||
{
|
||||
self.state.process(&buffer);
|
||||
}
|
||||
|
||||
fn finalize(&mut self) -> Vec<u8>
|
||||
{
|
||||
self.state.tag_and_pad(0x06);
|
||||
self.state.squeeze(256 / 8)
|
||||
}
|
||||
|
||||
fn block_size() -> usize
|
||||
{
|
||||
1088
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod sha256 {
|
||||
use super::*;
|
||||
use testing::run_test;
|
||||
|
||||
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-256.pdf
|
||||
#[test]
|
||||
fn nist_empty_example() {
|
||||
let empty = [0; 0];
|
||||
let hashres = [0xA7,0xFF,0xC6,0xF8,0xBF,0x1E,0xD7,0x66,
|
||||
0x51,0xC1,0x47,0x56,0xA0,0x61,0xD6,0x62,
|
||||
0xF5,0x80,0xFF,0x4D,0xE4,0x3B,0x49,0xFA,
|
||||
0x82,0xD8,0x0A,0x4B,0x80,0xF8,0x43,0x4A];
|
||||
let mine = SHA3_256::hash(&empty);
|
||||
assert_eq!(hashres.to_vec(), mine);
|
||||
}
|
||||
|
||||
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-256_1600.pdf
|
||||
#[test]
|
||||
fn nist_1600_example() {
|
||||
let example = [0xA3; 200];
|
||||
let hashres = [0x79,0xF3,0x8A,0xDE,0xC5,0xC2,0x03,0x07,
|
||||
0xA9,0x8E,0xF7,0x6E,0x83,0x24,0xAF,0xBF,
|
||||
0xD4,0x6C,0xFD,0x81,0xB2,0x2E,0x39,0x73,
|
||||
0xC6,0x5F,0xA1,0xBD,0x9D,0xE3,0x17,0x87];
|
||||
let mine = SHA3_256::hash(&example);
|
||||
assert_eq!(hashres.to_vec(), mine);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn nist_test_vectors() {
|
||||
let fname = "testdata/sha/nist_sha3_256.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negl, lbytes) = case.get("l").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
|
||||
assert!(!negl && !negm && !negd);
|
||||
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||
let digest = SHA3_256::hash(&msg);
|
||||
assert_eq!(dbytes, &digest);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// The SHA3-384 hash. [BETTER]
|
||||
///
|
||||
/// To use, you can run it in incremental mode -- by calling new(),
|
||||
/// update() zero or more times, and then finalize() -- or you can
|
||||
/// just invoke the hash directly. For example:
|
||||
///
|
||||
/// ```rust
|
||||
/// use simple_crypto::sha::{Hash,SHA3_384};
|
||||
///
|
||||
/// let empty = [0; 0];
|
||||
/// // Do the hash using the incremental API
|
||||
/// let mut hashf = SHA3_384::new();
|
||||
/// hashf.update(&empty);
|
||||
/// let result_incremental = hashf.finalize();
|
||||
/// // Do the hash using the direct API
|
||||
/// let result_direct = SHA3_384::hash(&empty);
|
||||
/// // ... and they should be the same
|
||||
/// assert_eq!(result_incremental,result_direct);
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct SHA3_384 {
|
||||
state: Keccak
|
||||
}
|
||||
|
||||
impl Hash for SHA3_384 {
|
||||
fn new() -> Self
|
||||
{
|
||||
SHA3_384{ state: Keccak::new(1600 - 768) }
|
||||
}
|
||||
|
||||
fn update(&mut self, buffer: &[u8])
|
||||
{
|
||||
self.state.process(&buffer);
|
||||
}
|
||||
|
||||
fn finalize(&mut self) -> Vec<u8>
|
||||
{
|
||||
self.state.tag_and_pad(0x06);
|
||||
self.state.squeeze(384 / 8)
|
||||
}
|
||||
|
||||
fn block_size() -> usize
|
||||
{
|
||||
832
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod sha384 {
|
||||
use super::*;
|
||||
use testing::run_test;
|
||||
|
||||
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-384_Msg0.pdf
|
||||
#[test]
|
||||
fn nist_empty_example() {
|
||||
let empty = [0; 0];
|
||||
let hashres = [0x0C,0x63,0xA7,0x5B,0x84,0x5E,0x4F,0x7D,
|
||||
0x01,0x10,0x7D,0x85,0x2E,0x4C,0x24,0x85,
|
||||
0xC5,0x1A,0x50,0xAA,0xAA,0x94,0xFC,0x61,
|
||||
0x99,0x5E,0x71,0xBB,0xEE,0x98,0x3A,0x2A,
|
||||
0xC3,0x71,0x38,0x31,0x26,0x4A,0xDB,0x47,
|
||||
0xFB,0x6B,0xD1,0xE0,0x58,0xD5,0xF0,0x04];
|
||||
let mine = SHA3_384::hash(&empty);
|
||||
assert_eq!(hashres.to_vec(), mine);
|
||||
}
|
||||
|
||||
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-384_1600.pdf
|
||||
#[test]
|
||||
fn nist_1600_example() {
|
||||
let example = [0xA3; 200];
|
||||
let hashres = [0x18,0x81,0xDE,0x2C,0xA7,0xE4,0x1E,0xF9,
|
||||
0x5D,0xC4,0x73,0x2B,0x8F,0x5F,0x00,0x2B,
|
||||
0x18,0x9C,0xC1,0xE4,0x2B,0x74,0x16,0x8E,
|
||||
0xD1,0x73,0x26,0x49,0xCE,0x1D,0xBC,0xDD,
|
||||
0x76,0x19,0x7A,0x31,0xFD,0x55,0xEE,0x98,
|
||||
0x9F,0x2D,0x70,0x50,0xDD,0x47,0x3E,0x8F];
|
||||
let mine = SHA3_384::hash(&example);
|
||||
assert_eq!(hashres.to_vec(), mine);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn nist_test_vectors() {
|
||||
let fname = "testdata/sha/nist_sha3_384.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negl, lbytes) = case.get("l").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
|
||||
assert!(!negl && !negm && !negd);
|
||||
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||
let digest = SHA3_384::hash(&msg);
|
||||
assert_eq!(dbytes, &digest);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// The SHA3-512 hash. [BEST]
|
||||
///
|
||||
/// To use, you can run it in incremental mode -- by calling new(),
|
||||
/// update() zero or more times, and then finalize() -- or you can
|
||||
/// just invoke the hash directly. For example:
|
||||
///
|
||||
/// ```rust
|
||||
/// use simple_crypto::sha::{Hash,SHA3_512};
|
||||
///
|
||||
/// let empty = [0; 0];
|
||||
/// // Do the hash using the incremental API
|
||||
/// let mut hashf = SHA3_512::new();
|
||||
/// hashf.update(&empty);
|
||||
/// let result_incremental = hashf.finalize();
|
||||
/// // Do the hash using the direct API
|
||||
/// let result_direct = SHA3_512::hash(&empty);
|
||||
/// // ... and they should be the same
|
||||
/// assert_eq!(result_incremental,result_direct);
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct SHA3_512 {
|
||||
state: Keccak
|
||||
}
|
||||
|
||||
impl Hash for SHA3_512 {
|
||||
fn new() -> Self
|
||||
{
|
||||
SHA3_512{ state: Keccak::new(1600 - 1024) }
|
||||
}
|
||||
|
||||
fn update(&mut self, buffer: &[u8])
|
||||
{
|
||||
self.state.process(&buffer);
|
||||
}
|
||||
|
||||
fn finalize(&mut self) -> Vec<u8>
|
||||
{
|
||||
self.state.tag_and_pad(0x06);
|
||||
self.state.squeeze(512 / 8)
|
||||
}
|
||||
|
||||
fn block_size() -> usize
|
||||
{
|
||||
576
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod sha512 {
|
||||
use super::*;
|
||||
use testing::run_test;
|
||||
|
||||
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-512_Msg0.pdf
|
||||
#[test]
|
||||
fn nist_empty_example() {
|
||||
let empty = [0; 0];
|
||||
let hashres = [0xA6,0x9F,0x73,0xCC,0xA2,0x3A,0x9A,0xC5,
|
||||
0xC8,0xB5,0x67,0xDC,0x18,0x5A,0x75,0x6E,
|
||||
0x97,0xC9,0x82,0x16,0x4F,0xE2,0x58,0x59,
|
||||
0xE0,0xD1,0xDC,0xC1,0x47,0x5C,0x80,0xA6,
|
||||
0x15,0xB2,0x12,0x3A,0xF1,0xF5,0xF9,0x4C,
|
||||
0x11,0xE3,0xE9,0x40,0x2C,0x3A,0xC5,0x58,
|
||||
0xF5,0x00,0x19,0x9D,0x95,0xB6,0xD3,0xE3,
|
||||
0x01,0x75,0x85,0x86,0x28,0x1D,0xCD,0x26];
|
||||
let mine = SHA3_512::hash(&empty);
|
||||
assert_eq!(hashres.to_vec(), mine);
|
||||
}
|
||||
|
||||
// see https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-512_1600.pdf
|
||||
#[test]
|
||||
fn nist_1600_example() {
|
||||
let example = [0xA3; 200];
|
||||
let hashres = [0xE7,0x6D,0xFA,0xD2,0x20,0x84,0xA8,0xB1,
|
||||
0x46,0x7F,0xCF,0x2F,0xFA,0x58,0x36,0x1B,
|
||||
0xEC,0x76,0x28,0xED,0xF5,0xF3,0xFD,0xC0,
|
||||
0xE4,0x80,0x5D,0xC4,0x8C,0xAE,0xEC,0xA8,
|
||||
0x1B,0x7C,0x13,0xC3,0x0A,0xDF,0x52,0xA3,
|
||||
0x65,0x95,0x84,0x73,0x9A,0x2D,0xF4,0x6B,
|
||||
0xE5,0x89,0xC5,0x1C,0xA1,0xA4,0xA8,0x41,
|
||||
0x6D,0xF6,0x54,0x5A,0x1C,0xE8,0xBA,0x00];
|
||||
let mine = SHA3_512::hash(&example);
|
||||
assert_eq!(hashres.to_vec(), mine);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn nist_test_vectors() {
|
||||
let fname = "testdata/sha/nist_sha3_512.test";
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (negl, lbytes) = case.get("l").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
|
||||
assert!(!negl && !negm && !negd);
|
||||
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||
let digest = SHA3_512::hash(&msg);
|
||||
assert_eq!(dbytes, &digest);
|
||||
});
|
||||
}
|
||||
}
|
||||
101
src/sha/shared.rs
Normal file
101
src/sha/shared.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
macro_rules! ch {
|
||||
($x: expr, $y: expr, $z: expr) => {{
|
||||
let xval = $x;
|
||||
(xval & $y) ^ (!xval & $z)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! parity {
|
||||
($x: expr, $y: expr, $z: expr) => {
|
||||
$x ^ $y ^ $z
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! maj {
|
||||
($x: expr, $y: expr, $z: expr) => {{
|
||||
/* the original function is (x & y) ^ (x & z) ^ (y & z).
|
||||
if you fire off truth tables, this is equivalent to
|
||||
(x & y) | (x & z) | (y & z)
|
||||
which you can then use distribution on:
|
||||
(x & (y | z)) | (y & z)
|
||||
which saves one operation */
|
||||
let yval = $y;
|
||||
let zval = $z;
|
||||
($x & (yval | zval)) | (yval & zval)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! process_u32_block {
|
||||
($buf: expr, $off: expr, $self: ident) => {{
|
||||
let w00 = ($buf[$off+0] as u32) << 24 | ($buf[$off+1] as u32) << 16 |
|
||||
($buf[$off+2] as u32) << 8 | ($buf[$off+3] as u32);
|
||||
let w01 = ($buf[$off+4] as u32) << 24 | ($buf[$off+5] as u32) << 16 |
|
||||
($buf[$off+6] as u32) << 8 | ($buf[$off+7] as u32);
|
||||
let w02 = ($buf[$off+8] as u32) << 24 | ($buf[$off+9] as u32) << 16 |
|
||||
($buf[$off+10] as u32) << 8 | ($buf[$off+11] as u32);
|
||||
let w03 = ($buf[$off+12] as u32) << 24 | ($buf[$off+13] as u32) << 16 |
|
||||
($buf[$off+14] as u32) << 8 | ($buf[$off+15] as u32);
|
||||
let w04 = ($buf[$off+16] as u32) << 24 | ($buf[$off+17] as u32) << 16 |
|
||||
($buf[$off+18] as u32) << 8 | ($buf[$off+19] as u32);
|
||||
let w05 = ($buf[$off+20] as u32) << 24 | ($buf[$off+21] as u32) << 16 |
|
||||
($buf[$off+22] as u32) << 8 | ($buf[$off+23] as u32);
|
||||
let w06 = ($buf[$off+24] as u32) << 24 | ($buf[$off+25] as u32) << 16 |
|
||||
($buf[$off+26] as u32) << 8 | ($buf[$off+27] as u32);
|
||||
let w07 = ($buf[$off+28] as u32) << 24 | ($buf[$off+29] as u32) << 16 |
|
||||
($buf[$off+30] as u32) << 8 | ($buf[$off+31] as u32);
|
||||
let w08 = ($buf[$off+32] as u32) << 24 | ($buf[$off+33] as u32) << 16 |
|
||||
($buf[$off+34] as u32) << 8 | ($buf[$off+35] as u32);
|
||||
let w09 = ($buf[$off+36] as u32) << 24 | ($buf[$off+37] as u32) << 16 |
|
||||
($buf[$off+38] as u32) << 8 | ($buf[$off+39] as u32);
|
||||
let w10 = ($buf[$off+40] as u32) << 24 | ($buf[$off+41] as u32) << 16 |
|
||||
($buf[$off+42] as u32) << 8 | ($buf[$off+43] as u32);
|
||||
let w11 = ($buf[$off+44] as u32) << 24 | ($buf[$off+45] as u32) << 16 |
|
||||
($buf[$off+46] as u32) << 8 | ($buf[$off+47] as u32);
|
||||
let w12 = ($buf[$off+48] as u32) << 24 | ($buf[$off+49] as u32) << 16 |
|
||||
($buf[$off+50] as u32) << 8 | ($buf[$off+51] as u32);
|
||||
let w13 = ($buf[$off+52] as u32) << 24 | ($buf[$off+53] as u32) << 16 |
|
||||
($buf[$off+54] as u32) << 8 | ($buf[$off+55] as u32);
|
||||
let w14 = ($buf[$off+56] as u32) << 24 | ($buf[$off+57] as u32) << 16 |
|
||||
($buf[$off+58] as u32) << 8 | ($buf[$off+59] as u32);
|
||||
let w15 = ($buf[$off+60] as u32) << 24 | ($buf[$off+61] as u32) << 16 |
|
||||
($buf[$off+62] as u32) << 8 | ($buf[$off+63] as u32);
|
||||
$self.process(w00, w01, w02, w03, w04, w05, w06, w07,
|
||||
w08, w09, w10, w11, w12, w13, w14, w15);
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Calculate the value `k` used in the padding for all the hashes, solving the
|
||||
// equation (l + 1 + k) mod b = a.
|
||||
pub fn calculate_k(a: usize, b: usize, l: usize) -> usize
|
||||
{
|
||||
(a - (l + 1)) % b
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
quickcheck!
|
||||
{
|
||||
fn maj_rewrite_ok(x: u64, y: u64, z: u64) -> bool
|
||||
{
|
||||
let orig = (x & y) ^ (x & z) ^ (y & z);
|
||||
maj!(x, y, z) == orig
|
||||
}
|
||||
|
||||
// Note, these two laws hold because we hash with bytes as the atomic size,
|
||||
// not bits. If we hashed true bit streams, we'd be in trouble.
|
||||
fn sha1_k_plus_1_multiple_of_8(lbytes: usize) -> bool
|
||||
{
|
||||
let l = lbytes * 8;
|
||||
(calculate_k(448,512,l) + 1) % 8 == 0
|
||||
}
|
||||
|
||||
// Note, these two laws hold because we hash with bytes as the atomic size,
|
||||
// not bits. If we hashed true bit streams, we'd be in trouble.
|
||||
fn sha2_k_plus_1_multiple_of_8(lbytes: usize) -> bool
|
||||
{
|
||||
let l = lbytes * 8;
|
||||
(calculate_k(896,1024,l) + 1) % 8 == 0
|
||||
}
|
||||
}
|
||||
|
||||
215
src/shake.rs
Normal file
215
src/shake.rs
Normal file
@@ -0,0 +1,215 @@
|
||||
//! This module implements the SHAKE family of variable-length hash functions,
|
||||
//! which NIST also referes to as Extendable-Output Functions (XOFs). They are
|
||||
//! based on the same underlying hashing mechanism used in SHA3, but can be
|
||||
//! tuned to output a variety of different hash lengths. One trick is that the
|
||||
//! security of the hash is the minimum of the defined bit size (128 for
|
||||
//! SHAKE128, or 256 for SHAKE256) and the output hash length, so if you use
|
||||
//! shorter hashes you lose some amount of collision protection.
|
||||
//!
|
||||
//! Because the output is variable length, these don't quite fit into the
|
||||
//! normal `Hash` trait. Instead, they implement the same basic functions,
|
||||
//! but with `hash` and `finalize` functions extended with an additional
|
||||
//! output length function. Usage is thus in the analagous way to normal
|
||||
//! hashing:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use simple_crypto::shake::SHAKE128;
|
||||
//!
|
||||
//! // Use SHAKE incrementally
|
||||
//! let empty = [0; 0];
|
||||
//! let mut shakef = SHAKE128::new();
|
||||
//! shakef.update(&empty);
|
||||
//! let result_inc = shakef.finalize(384);
|
||||
//! // Use SHAKE directly
|
||||
//! let result_dir = SHAKE128::hash(&empty, 384);
|
||||
//! // ... and the answers should be the same.
|
||||
//! assert_eq!(result_inc, result_dir);
|
||||
//! ```
|
||||
use sha::Keccak;
|
||||
|
||||
/// The SHAKE128 variable-length hash.
|
||||
///
|
||||
/// This generates a variable-length hash value, although it's not necessarily as
|
||||
/// strong as a hash of the same value. My understanding (which is admittedly
|
||||
/// limited; I've never seen these used) is that this is more for convenience
|
||||
/// when you want to fit into particularly-sized regions. The 128 is the
|
||||
/// approximate maximum bit strength of the hash in bits; the true strength is
|
||||
/// the minimum of the length of the output hash and 128.
|
||||
///
|
||||
/// `SHAKE128` does not implement `Hash`, because it is finalized differently,
|
||||
/// but we've kept something of the flavor of the `Hash` interface for
|
||||
/// familiarity.
|
||||
///
|
||||
/// Like the SHA3 variants, this can be used incrementally or directly, as per
|
||||
/// usual:
|
||||
///
|
||||
/// ```rust
|
||||
/// use simple_crypto::shake::SHAKE128;
|
||||
///
|
||||
/// // Use SHAKE incrementally
|
||||
/// let empty = [0; 0];
|
||||
/// let mut shakef = SHAKE128::new();
|
||||
/// shakef.update(&empty);
|
||||
/// let result_inc = shakef.finalize(384);
|
||||
/// // Use SHAKE directly
|
||||
/// let result_dir = SHAKE128::hash(&empty, 384);
|
||||
/// // ... and the answers should be the same.
|
||||
/// assert_eq!(result_inc, result_dir);
|
||||
/// ```
|
||||
pub struct SHAKE128 {
|
||||
state: Keccak
|
||||
}
|
||||
|
||||
impl SHAKE128 {
|
||||
/// Create a fresh, new SHAKE128 instance for incremental use.
|
||||
pub fn new() -> Self
|
||||
{
|
||||
SHAKE128{
|
||||
state: Keccak::new(1600 - 256)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add more data into the hash function for processing.
|
||||
pub fn update(&mut self, buffer: &[u8])
|
||||
{
|
||||
self.state.process(&buffer);
|
||||
}
|
||||
|
||||
/// Generate the final hash. Because this is a variable-length hash,
|
||||
/// you will need to provide the output size in bits. Note that this
|
||||
/// output size *must* be a multiple of 8, and that the security
|
||||
/// strength of the whole hash is approximately the minimum of this
|
||||
/// length and 128 bits.
|
||||
pub fn finalize(&mut self, outsize: usize) -> Vec<u8>
|
||||
{
|
||||
assert_eq!(outsize % 8, 0);
|
||||
self.state.tag_and_pad(0x1F);
|
||||
self.state.squeeze(outsize / 8)
|
||||
}
|
||||
|
||||
/// Directly generate the SHAKE128 hash of the given buffer, returning
|
||||
/// a hash value of the given size (in bits). Presently, the output
|
||||
/// size *must* be a multiple of 8, although this may change in the
|
||||
/// future.
|
||||
pub fn hash(buffer: &[u8], outsize: usize) -> Vec<u8>
|
||||
{
|
||||
let mut x = Self::new();
|
||||
x.update(&buffer);
|
||||
x.finalize(outsize)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use testing::run_test;
|
||||
#[cfg(test)]
|
||||
use cryptonum::unsigned::{Decoder,U192};
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn shake128() {
|
||||
let fname = "testdata/sha/shake128.test";
|
||||
run_test(fname.to_string(), 4, |case| {
|
||||
let (negl, lbytes) = case.get("l").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
let (nego, obytes) = case.get("o").unwrap();
|
||||
|
||||
assert!(!negl && !negm && !negd && !nego);
|
||||
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||
let osize = usize::from(U192::from_bytes(obytes));
|
||||
let digest = SHAKE128::hash(&msg, osize);;
|
||||
assert_eq!(dbytes, &digest);
|
||||
});
|
||||
}
|
||||
|
||||
/// The SHAKE256 variable-length hash.
|
||||
///
|
||||
/// This generates a variable-length hash value, although it's not necessarily as
|
||||
/// strong as a hash of the same value. My understanding (which is admittedly
|
||||
/// limited; I've never seen these used) is that this is more for convenience
|
||||
/// when you want to fit into particularly-sized regions. The 256 is the
|
||||
/// approximate maximum bit strength of the hash in bits; the true strength is
|
||||
/// the minimum of the length of the output hash and 256.
|
||||
///
|
||||
/// `SHAKE256` does not implement `Hash`, because it is finalized differently,
|
||||
/// but we've kept something of the flavor of the `Hash` interface for
|
||||
/// familiarity.
|
||||
///
|
||||
/// Like the SHA3 variants, this can be used incrementally or directly, as per
|
||||
/// usual:
|
||||
///
|
||||
/// ```rust
|
||||
/// use simple_crypto::shake::SHAKE256;
|
||||
///
|
||||
/// // Use SHAKE incrementally
|
||||
/// let empty = [0; 0];
|
||||
/// let mut shakef = SHAKE256::new();
|
||||
/// shakef.update(&empty);
|
||||
/// let result_inc = shakef.finalize(384);
|
||||
/// // Use SHAKE directly
|
||||
/// let result_dir = SHAKE256::hash(&empty, 384);
|
||||
/// // ... and the answers should be the same.
|
||||
/// assert_eq!(result_inc, result_dir);
|
||||
/// ```
|
||||
pub struct SHAKE256 {
|
||||
state: Keccak
|
||||
}
|
||||
|
||||
impl SHAKE256 {
|
||||
/// Create a fresh, new SHAKE256 instance for incremental use.
|
||||
pub fn new() -> Self
|
||||
{
|
||||
SHAKE256{
|
||||
state: Keccak::new(1600 - 512)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add more data into the hash function for processing.
|
||||
pub fn update(&mut self, buffer: &[u8])
|
||||
{
|
||||
self.state.process(&buffer);
|
||||
}
|
||||
|
||||
/// Generate the final hash. Because this is a variable-length hash,
|
||||
/// you will need to provide the output size in bits. Note that this
|
||||
/// output size *must* be a multiple of 8, and that the security
|
||||
/// strength of the whole hash is approximately the minimum of this
|
||||
/// length and 256 bits.
|
||||
pub fn finalize(&mut self, outsize: usize) -> Vec<u8>
|
||||
{
|
||||
assert_eq!(outsize % 8, 0);
|
||||
self.state.tag_and_pad(0x1F);
|
||||
self.state.squeeze(outsize / 8)
|
||||
}
|
||||
|
||||
/// Directly generate the SHAKE256 hash of the given buffer, returning
|
||||
/// a hash value of the given size (in bits). Presently, the output
|
||||
/// size *must* be a multiple of 8, although this may change in the
|
||||
/// future.
|
||||
pub fn hash(buffer: &[u8], outsize: usize) -> Vec<u8>
|
||||
{
|
||||
let mut x = Self::new();
|
||||
x.update(&buffer);
|
||||
x.finalize(outsize)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn shake256() {
|
||||
let fname = "testdata/sha/shake256.test";
|
||||
run_test(fname.to_string(), 4, |case| {
|
||||
let (negl, lbytes) = case.get("l").unwrap();
|
||||
let (negm, mbytes) = case.get("m").unwrap();
|
||||
let (negd, dbytes) = case.get("d").unwrap();
|
||||
let (nego, obytes) = case.get("o").unwrap();
|
||||
|
||||
assert!(!negl && !negm && !negd && !nego);
|
||||
let msg = if lbytes[0] == 0 { Vec::new() } else { mbytes.clone() };
|
||||
let osize = usize::from(U192::from_bytes(obytes));
|
||||
let digest = SHAKE256::hash(&msg, osize);;
|
||||
assert_eq!(dbytes, &digest);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
75
src/ssh/dsa.rs
Normal file
75
src/ssh/dsa.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
use cryptonum::unsigned::*;
|
||||
use dsa::{DSAKeyPair,DSAParameters,DSAPublicKey,DSAPrivateKey,L1024N160};
|
||||
use std::io::{Read,Write};
|
||||
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||
use ssh::frame::*;
|
||||
use ssh::SSHKey;
|
||||
|
||||
impl SSHKey for DSAKeyPair<L1024N160> {
|
||||
fn valid_keytype(s: &str) -> bool {
|
||||
(s == "ssh-dss") || (s == "dss")
|
||||
}
|
||||
|
||||
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>
|
||||
{
|
||||
let pubkey_type = parse_openssh_string(inp)?;
|
||||
if !Self::valid_keytype(&pubkey_type) {
|
||||
return Err(SSHKeyParseError::UnknownKeyType(pubkey_type));
|
||||
}
|
||||
let pubp = parse_openssh_number(inp)?;
|
||||
let pubq = parse_openssh_number(inp)?;
|
||||
let pubg = parse_openssh_number(inp)?;
|
||||
let pubparams = L1024N160::new(pubp, pubg, pubq);
|
||||
let puby: U1024 = parse_openssh_number(inp)?;
|
||||
for _ in inp.bytes() { return Err(SSHKeyParseError::UnknownTrailingData); }
|
||||
Ok(DSAPublicKey::<L1024N160>::new(pubparams.clone(), puby.clone()))
|
||||
}
|
||||
|
||||
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>
|
||||
{
|
||||
let check1 = parse_openssh_u32(inp)?;
|
||||
let check2 = parse_openssh_u32(inp)?;
|
||||
if check1 != check2 {
|
||||
return Err(SSHKeyParseError::PrivateKeyCorruption);
|
||||
}
|
||||
let privkey_type = parse_openssh_string(inp)?;
|
||||
if !Self::valid_keytype(&privkey_type) {
|
||||
return Err(SSHKeyParseError::InconsistentKeyTypes("ssh-dss".to_string(), privkey_type));
|
||||
}
|
||||
let privp = parse_openssh_number(inp)?;
|
||||
let privq = parse_openssh_number(inp)?;
|
||||
let privg = parse_openssh_number(inp)?;
|
||||
let privparams = L1024N160::new(privp, privg, privq);
|
||||
let _ = parse_openssh_buffer(inp)?; // a copy of y we don't need
|
||||
let privx = parse_openssh_number(inp)?;
|
||||
|
||||
let privkey = DSAPrivateKey::<L1024N160>::new(privparams, privx);
|
||||
let comment = parse_openssh_string(inp)?;
|
||||
for (idx,byte) in inp.bytes().enumerate() {
|
||||
if ((idx+1) as u8) != byte? {
|
||||
return Err(SSHKeyParseError::InvalidPadding);
|
||||
}
|
||||
}
|
||||
|
||||
Ok((privkey,comment))
|
||||
}
|
||||
|
||||
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
render_openssh_string(out, "ssh-dss")?;
|
||||
render_openssh_number(out, &self.public.params.p)?;
|
||||
render_openssh_number(out, &self.public.params.q)?;
|
||||
render_openssh_number(out, &self.public.params.g)?;
|
||||
render_openssh_number(out, &self.public.y)
|
||||
}
|
||||
|
||||
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
render_openssh_string(out, "ssh-dss")?;
|
||||
render_openssh_number(out, &self.private.params.p)?;
|
||||
render_openssh_number(out, &self.private.params.q)?;
|
||||
render_openssh_number(out, &self.private.params.g)?;
|
||||
render_openssh_number(out, &self.public.y)?;
|
||||
render_openssh_number(out, &self.private.x)
|
||||
}
|
||||
}
|
||||
171
src/ssh/ecdsa.rs
Normal file
171
src/ssh/ecdsa.rs
Normal file
@@ -0,0 +1,171 @@
|
||||
use cryptonum::unsigned::*;
|
||||
use ecdsa::{ECDSAPair,ECDSAPublic,ECCPublicKey,ECDSAPrivate,ECCPrivateKey};
|
||||
use ecdsa::{EllipticCurve,P256,P384,P521};
|
||||
use std::io::{Read,Write};
|
||||
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||
use ssh::frame::*;
|
||||
use ssh::SSHKey;
|
||||
|
||||
impl SSHKey for ECDSAPair {
|
||||
fn valid_keytype(s: &str) -> bool {
|
||||
(s == "ssh-ecdsa") || (s == "ecdsa") || (s == "ecdsa-sha2-nistp256") ||
|
||||
(s == "ecdsa-sha2-nistp384") || (s == "ecdsa-sha2-nistp521")
|
||||
}
|
||||
|
||||
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>
|
||||
{
|
||||
let pubkey_type = parse_openssh_string(inp)?;
|
||||
if !Self::valid_keytype(&pubkey_type) {
|
||||
return Err(SSHKeyParseError::UnknownKeyType(pubkey_type));
|
||||
}
|
||||
// this peaks a little under the cover a bit (it'd be nice to pretend
|
||||
// that we didn't know the number format was the same as the buffer
|
||||
// one), but we need to infer what kind of key this is, and this appears
|
||||
// to be the easiest / fastest way.
|
||||
let curve = parse_openssh_string(inp)?;
|
||||
match curve.as_ref() {
|
||||
"nistp256" => {
|
||||
let val = parse_openssh_buffer(inp)?;
|
||||
if val[0] != 4 || val.len() != 65 {
|
||||
return Err(SSHKeyParseError::InvalidECPointCompression);
|
||||
}
|
||||
let x = U256::from_bytes(&val[1..33]);
|
||||
let y = U256::from_bytes(&val[33..]);
|
||||
let p = P256::new_point(x, y);
|
||||
let pbl = ECCPublicKey::<P256>::new(p);
|
||||
Ok(ECDSAPublic::P256(pbl))
|
||||
}
|
||||
"nistp384" => {
|
||||
let val = parse_openssh_buffer(inp)?;
|
||||
if val[0] != 4 || val.len() != 97 {
|
||||
return Err(SSHKeyParseError::InvalidECPointCompression);
|
||||
}
|
||||
let x = U384::from_bytes(&val[1..49]);
|
||||
let y = U384::from_bytes(&val[49..]);
|
||||
let p = P384::new_point(x, y);
|
||||
let pbl = ECCPublicKey::<P384>::new(p);
|
||||
Ok(ECDSAPublic::P384(pbl))
|
||||
}
|
||||
"nistp521" => {
|
||||
let val = parse_openssh_buffer(inp)?;
|
||||
if val[0] != 4 || val.len() != 133 {
|
||||
return Err(SSHKeyParseError::InvalidECPointCompression);
|
||||
}
|
||||
let x = U576::from_bytes(&val[1..67]);
|
||||
let y = U576::from_bytes(&val[67..]);
|
||||
let p = P521::new_point(x, y);
|
||||
let pbl = ECCPublicKey::<P521>::new(p);
|
||||
Ok(ECDSAPublic::P521(pbl))
|
||||
}
|
||||
_ => {
|
||||
return Err(SSHKeyParseError::UnknownECDSACurve(curve))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>
|
||||
{
|
||||
let check1 = parse_openssh_u32(inp)?;
|
||||
let check2 = parse_openssh_u32(inp)?;
|
||||
if check1 != check2 {
|
||||
return Err(SSHKeyParseError::PrivateKeyCorruption);
|
||||
}
|
||||
let res = match ECDSAPair::parse_ssh_public_info(inp)? {
|
||||
ECDSAPublic::P192(_) => return Err(SSHKeyParseError::PrivateKeyCorruption),
|
||||
ECDSAPublic::P224(_) => return Err(SSHKeyParseError::PrivateKeyCorruption),
|
||||
ECDSAPublic::P256(_) => {
|
||||
let mut dbytes = parse_openssh_buffer(inp)?;
|
||||
while dbytes[0] == 0 { dbytes.remove(0); }
|
||||
assert!(dbytes.len() <= 32);
|
||||
let d = U256::from_bytes(&dbytes);
|
||||
ECDSAPrivate::P256(ECCPrivateKey::<P256>::new(d))
|
||||
}
|
||||
ECDSAPublic::P384(_) => {
|
||||
let mut dbytes = parse_openssh_buffer(inp)?;
|
||||
while dbytes[0] == 0 { dbytes.remove(0); }
|
||||
assert!(dbytes.len() <= 48);
|
||||
let d = U384::from_bytes(&dbytes);
|
||||
ECDSAPrivate::P384(ECCPrivateKey::<P384>::new(d))
|
||||
}
|
||||
ECDSAPublic::P521(_) => {
|
||||
let mut dbytes = parse_openssh_buffer(inp)?;
|
||||
while dbytes[0] == 0 { dbytes.remove(0); }
|
||||
assert!(dbytes.len() <= 66);
|
||||
let d = U576::from_bytes(&dbytes);
|
||||
ECDSAPrivate::P521(ECCPrivateKey::<P521>::new(d))
|
||||
}
|
||||
};
|
||||
let comment = parse_openssh_string(inp)?;
|
||||
for (idx,byte) in inp.bytes().enumerate() {
|
||||
if ((idx+1) as u8) != byte? {
|
||||
return Err(SSHKeyParseError::InvalidPadding);
|
||||
}
|
||||
}
|
||||
|
||||
Ok((res, comment))
|
||||
}
|
||||
|
||||
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
render_openssh_string(out, "ssh-ecdsa")?;
|
||||
match self {
|
||||
ECDSAPair::P192(_,_) =>
|
||||
return Err(SSHKeyRenderError::IllegalECDSAKeyType("P192".to_string())),
|
||||
ECDSAPair::P224(_,_) =>
|
||||
return Err(SSHKeyRenderError::IllegalECDSAKeyType("P224".to_string())),
|
||||
ECDSAPair::P256(pu,_) => {
|
||||
render_openssh_string(out, "nistp256")?;
|
||||
let mut vec = Vec::with_capacity(66);
|
||||
vec.write(&[4u8])?;
|
||||
render_number(256, &mut vec, &U256::from(pu.q.x.clone()))?;
|
||||
render_number(256, &mut vec, &U256::from(pu.q.y.clone()))?;
|
||||
render_openssh_buffer(out, &vec)?;
|
||||
}
|
||||
ECDSAPair::P384(pu,_) => {
|
||||
render_openssh_string(out, "nistp384")?;
|
||||
let mut vec = Vec::with_capacity(66);
|
||||
vec.write(&[4u8])?;
|
||||
render_number(384, &mut vec, &U384::from(pu.q.x.clone()))?;
|
||||
render_number(384, &mut vec, &U384::from(pu.q.y.clone()))?;
|
||||
render_openssh_buffer(out, &vec)?;
|
||||
}
|
||||
ECDSAPair::P521(pu,_) => {
|
||||
render_openssh_string(out, "nistp521")?;
|
||||
let mut vec = Vec::with_capacity(66);
|
||||
vec.write(&[4u8])?;
|
||||
render_number(521, &mut vec, &U576::from(pu.q.x.clone()))?;
|
||||
render_number(521, &mut vec, &U576::from(pu.q.y.clone()))?;
|
||||
render_openssh_buffer(out, &vec)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
self.render_ssh_public_info(out)?;
|
||||
match self {
|
||||
ECDSAPair::P192(_,_) =>
|
||||
return Err(SSHKeyRenderError::IllegalECDSAKeyType("P192".to_string())),
|
||||
ECDSAPair::P224(_,_) =>
|
||||
return Err(SSHKeyRenderError::IllegalECDSAKeyType("P224".to_string())),
|
||||
ECDSAPair::P256(_,pr) => { render_openssh_u32(out, 256/8)?; render_number(256, out, &pr.d)?; }
|
||||
ECDSAPair::P384(_,pr) => { render_openssh_u32(out, 384/8)?; render_number(384, out, &pr.d)?; }
|
||||
ECDSAPair::P521(_,pr) => { render_openssh_u32(out, 528/8)?; render_number(521, out, &pr.d)?; }
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn render_number<O,N>(bitlen: usize, out: &mut O, val: &N) -> Result<(),SSHKeyRenderError>
|
||||
where
|
||||
O: Write,
|
||||
N: Encoder
|
||||
{
|
||||
let mut outvec = Vec::new();
|
||||
outvec.write(&val.to_bytes())?;
|
||||
while outvec.len() < ((bitlen + 7) / 8) { outvec.insert(0,0); }
|
||||
while outvec.len() > ((bitlen + 7) / 8) { outvec.remove(0); }
|
||||
out.write(&outvec)?;
|
||||
Ok(())
|
||||
}
|
||||
58
src/ssh/ed25519.rs
Normal file
58
src/ssh/ed25519.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use ed25519::{ED25519KeyPair,ED25519Private,ED25519Public};
|
||||
use std::io::{Read,Write};
|
||||
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||
use ssh::frame::*;
|
||||
use ssh::SSHKey;
|
||||
|
||||
impl SSHKey for ED25519KeyPair {
|
||||
fn valid_keytype(s: &str) -> bool {
|
||||
(s == "ssh-ed25519")
|
||||
}
|
||||
|
||||
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>
|
||||
{
|
||||
let pubkey_type = parse_openssh_string(inp)?;
|
||||
if !Self::valid_keytype(&pubkey_type) {
|
||||
return Err(SSHKeyParseError::UnknownKeyType(pubkey_type));
|
||||
}
|
||||
let pubkey_bytes = parse_openssh_buffer(inp)?;
|
||||
Ok(ED25519Public::new(&pubkey_bytes)?)
|
||||
}
|
||||
|
||||
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>
|
||||
{
|
||||
let check1 = parse_openssh_u32(inp)?;
|
||||
let check2 = parse_openssh_u32(inp)?;
|
||||
if check1 != check2 {
|
||||
return Err(SSHKeyParseError::PrivateKeyCorruption);
|
||||
}
|
||||
let public = ED25519KeyPair::parse_ssh_public_info(inp)?;
|
||||
let private_bytes = parse_openssh_buffer(inp)?;
|
||||
let private = ED25519Private::from_seed(&private_bytes[0..32]);
|
||||
let comment = parse_openssh_string(inp)?;
|
||||
for (idx,byte) in inp.bytes().enumerate() {
|
||||
if ((idx+1) as u8) != byte? {
|
||||
return Err(SSHKeyParseError::InvalidPadding);
|
||||
}
|
||||
}
|
||||
assert_eq!(public, ED25519Public::from(&private));
|
||||
|
||||
Ok((private, comment))
|
||||
}
|
||||
|
||||
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
render_openssh_string(out, "ssh-ed25519")?;
|
||||
render_openssh_buffer(out, &self.public.to_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
self.render_ssh_public_info(out)?;
|
||||
let mut private_bytes = self.private.to_bytes();
|
||||
private_bytes.append(&mut self.public.to_bytes());
|
||||
render_openssh_buffer(out, &private_bytes)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
68
src/ssh/errors.rs
Normal file
68
src/ssh/errors.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
use base64::DecodeError;
|
||||
use ed25519::ED25519PublicImportError;
|
||||
use std::io;
|
||||
|
||||
/// A whole pile of errors that you can get when parsing an SSH key from
|
||||
/// disk or memory.
|
||||
#[derive(Debug)]
|
||||
pub enum SSHKeyParseError
|
||||
{
|
||||
DecodeError(DecodeError),
|
||||
IOError(io::Error),
|
||||
NoBeginBannerFound, NoEndBannerFound,
|
||||
NoOpenSSHMagicHeader,
|
||||
UnknownKeyCipher(String),
|
||||
UnknownKDF(String), UnexpectedKDFOptions,
|
||||
InvalidNumberOfKeys(u32),
|
||||
UnknownTrailingData,
|
||||
UnknownKeyType(String),
|
||||
InvalidPublicKeyMaterial,
|
||||
PrivateKeyCorruption,
|
||||
InconsistentKeyTypes(String,String),
|
||||
InconsistentPublicKeyValue,
|
||||
InvalidPrivateKeyValue,
|
||||
InvalidPadding,
|
||||
InvalidPublicKeyType,
|
||||
BrokenPublicKeyLine,
|
||||
UnknownECDSACurve(String),
|
||||
InvalidECPointCompression
|
||||
}
|
||||
|
||||
impl From<DecodeError> for SSHKeyParseError {
|
||||
fn from(e: DecodeError) -> SSHKeyParseError {
|
||||
SSHKeyParseError::DecodeError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for SSHKeyParseError {
|
||||
fn from(e: io::Error) -> SSHKeyParseError {
|
||||
SSHKeyParseError::IOError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ED25519PublicImportError> for SSHKeyParseError {
|
||||
fn from(e: ED25519PublicImportError) -> SSHKeyParseError {
|
||||
match e {
|
||||
ED25519PublicImportError::WrongNumberOfBytes(_) =>
|
||||
SSHKeyParseError::InvalidPublicKeyMaterial,
|
||||
ED25519PublicImportError::InvalidPublicPoint =>
|
||||
SSHKeyParseError::InvalidPublicKeyMaterial,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A much smaller set of errors you can get when rendering an SSH key into
|
||||
/// a file or memory block.
|
||||
#[derive(Debug)]
|
||||
pub enum SSHKeyRenderError {
|
||||
IOError(io::Error),
|
||||
StringTooLong,
|
||||
BufferTooLarge,
|
||||
IllegalECDSAKeyType(String)
|
||||
}
|
||||
|
||||
impl From<io::Error> for SSHKeyRenderError {
|
||||
fn from(e: io::Error) -> SSHKeyRenderError {
|
||||
SSHKeyRenderError::IOError(e)
|
||||
}
|
||||
}
|
||||
320
src/ssh/frame.rs
Normal file
320
src/ssh/frame.rs
Normal file
@@ -0,0 +1,320 @@
|
||||
use base64::{decode,encode};
|
||||
use byteorder::{BigEndian,ReadBytesExt,WriteBytesExt};
|
||||
use cryptonum::unsigned::{Decoder,Encoder};
|
||||
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||
#[cfg(test)]
|
||||
use std::io::Cursor;
|
||||
#[cfg(test)]
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::io::Write;
|
||||
use std::iter::Iterator;
|
||||
|
||||
const OPENER: &'static str = "-----BEGIN OPENSSH PRIVATE KEY-----";
|
||||
const CLOSER: &'static str = "-----END OPENSSH PRIVATE KEY-----";
|
||||
|
||||
/// Given a string defining an ASCII SSH key blob (one that starts with
|
||||
/// "--BEGIN..."), decode the body of the blob and return it as binary
|
||||
/// data.
|
||||
pub fn parse_ssh_private_key_data(s: &str) -> Result<Vec<u8>,SSHKeyParseError>
|
||||
{
|
||||
if s.starts_with(OPENER) {
|
||||
if let Some(endidx) = s.find(CLOSER) {
|
||||
let b64str: String = s[OPENER.len()..endidx].chars().filter(|x| !x.is_whitespace()).collect();
|
||||
let bytes = decode(&b64str)?;
|
||||
Ok(bytes)
|
||||
} else {
|
||||
Err(SSHKeyParseError::NoEndBannerFound)
|
||||
}
|
||||
} else {
|
||||
Err(SSHKeyParseError::NoBeginBannerFound)
|
||||
}
|
||||
}
|
||||
|
||||
/// Once you've figured out the binary data you want to produce for an SSH key
|
||||
/// blob, use this routine to render it into its ASCII encoding.
|
||||
pub fn render_ssh_private_key_data(bytes: &[u8]) -> String
|
||||
{
|
||||
let mut bytestr = encode(bytes);
|
||||
let mut output = String::new();
|
||||
|
||||
output.push_str(OPENER);
|
||||
#[cfg(target_os="windows")]
|
||||
output.push_str("\r");
|
||||
output.push_str("\n");
|
||||
while bytestr.len() > 70 {
|
||||
let rest = bytestr.split_off(70);
|
||||
output.push_str(&bytestr);
|
||||
#[cfg(target_os="windows")]
|
||||
output.push_str("\r");
|
||||
output.push_str("\n");
|
||||
bytestr = rest;
|
||||
}
|
||||
output.push_str(&bytestr);
|
||||
#[cfg(target_os="windows")]
|
||||
output.push_str("\r");
|
||||
output.push_str("\n");
|
||||
output.push_str(CLOSER);
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const OPENSSH_MAGIC_HEADER: &'static str = "openssh-key-v1\0";
|
||||
const OPENSSH_MAGIC_HEADER_LEN: usize = 15;
|
||||
|
||||
/// Parse the magic header in an SSH key file.
|
||||
pub fn parse_openssh_header<R: Read>(input: &mut R) -> Result<(),SSHKeyParseError>
|
||||
{
|
||||
let mut limited_input_header = input.take(OPENSSH_MAGIC_HEADER_LEN as u64);
|
||||
let mut header: [u8; OPENSSH_MAGIC_HEADER_LEN] = [0; OPENSSH_MAGIC_HEADER_LEN];
|
||||
|
||||
assert_eq!(OPENSSH_MAGIC_HEADER.len(), OPENSSH_MAGIC_HEADER_LEN);
|
||||
limited_input_header.read_exact(&mut header)?;
|
||||
|
||||
for (left, right) in OPENSSH_MAGIC_HEADER.bytes().zip(header.iter()) {
|
||||
if left != *right {
|
||||
return Err(SSHKeyParseError::NoOpenSSHMagicHeader)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Render the magic header in an SSH key file.
|
||||
pub fn render_openssh_header<O: Write>(output: &mut O) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
Ok(output.write_all(OPENSSH_MAGIC_HEADER.as_bytes())?)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Parse an unsigned u32 from the SSH key stream. (This does the appropriate
|
||||
/// conversion from network order to native order.)
|
||||
pub fn parse_openssh_u32<I: Read>(input: &mut I) -> Result<u32,SSHKeyParseError>
|
||||
{
|
||||
let mut limited_input_header = input.take(4);
|
||||
let res = limited_input_header.read_u32::<BigEndian>()?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Render an unsigned u32 from the SSH key stream. (This does the appropriate
|
||||
/// conversion from network order to native order.)
|
||||
pub fn render_openssh_u32<O: Write>(output: &mut O, val: u32) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
Ok(output.write_u32::<BigEndian>(val)?)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Parse a string from the SSH key stream. This does some validation to ensure
|
||||
/// that the data being read is actually in a form that Rust will recognize as
|
||||
/// being a valid string.
|
||||
pub fn parse_openssh_string<I: Read>(input: &mut I) -> Result<String,SSHKeyParseError>
|
||||
{
|
||||
let length = parse_openssh_u32(input)?;
|
||||
let mut limited_input = input.take(length as u64);
|
||||
let mut result = String::new();
|
||||
limited_input.read_to_string(&mut result)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Render a string into the SSH key stream.
|
||||
pub fn render_openssh_string<O: Write>(output: &mut O, v: &str) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
let vbytes: Vec<u8> = v.bytes().collect();
|
||||
let len = vbytes.len();
|
||||
|
||||
if len > 0xFFFFFFFF {
|
||||
return Err(SSHKeyRenderError::StringTooLong);
|
||||
}
|
||||
|
||||
render_openssh_u32(output, vbytes.len() as u32)?;
|
||||
output.write_all(&vbytes)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Read a buffer from the SSH key stream.
|
||||
pub fn parse_openssh_buffer<I: Read>(input: &mut I) -> Result<Vec<u8>,SSHKeyParseError>
|
||||
{
|
||||
let length = parse_openssh_u32(input)?;
|
||||
let mut limited_input = input.take(length as u64);
|
||||
let mut res = Vec::with_capacity(length as usize);
|
||||
limited_input.read_to_end(&mut res)?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Render a buffer into the SSH key stream.
|
||||
pub fn render_openssh_buffer<O: Write>(output: &mut O, b: &[u8]) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
if b.len() > 0xFFFFFFFF {
|
||||
return Err(SSHKeyRenderError::BufferTooLarge);
|
||||
}
|
||||
|
||||
render_openssh_u32(output, b.len() as u32)?;
|
||||
if b.len() > 0 {
|
||||
output.write_all(b)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Parse a fixed-width number from the SSH key stream and return it.
|
||||
pub fn parse_openssh_number<I,D>(input: &mut I) -> Result<D,SSHKeyParseError>
|
||||
where
|
||||
I: Read,
|
||||
D: Decoder
|
||||
{
|
||||
let mut buffer = parse_openssh_buffer(input)?;
|
||||
while buffer[0] == 0 { buffer.remove(0); }
|
||||
Ok(D::from_bytes(&buffer))
|
||||
}
|
||||
|
||||
/// Render a fixed-width number into the SSH key stream.
|
||||
pub fn render_openssh_number<O,D>(output: &mut O, n: &D) -> Result<(),SSHKeyRenderError>
|
||||
where
|
||||
O: Write,
|
||||
D: Encoder
|
||||
{
|
||||
let bytes = n.to_bytes();
|
||||
render_openssh_buffer(output, &bytes)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#[cfg(test)]
|
||||
use cryptonum::unsigned::{U192,U1024,U2048,U4096};
|
||||
|
||||
#[cfg(test)]
|
||||
quickcheck! {
|
||||
fn bytes_roundtrip(x: Vec<u8>) -> bool {
|
||||
let rendered = render_ssh_private_key_data(&x);
|
||||
let returned = parse_ssh_private_key_data(&rendered).unwrap();
|
||||
returned == x
|
||||
}
|
||||
|
||||
fn blocks_formatted(x: Vec<u8>) -> bool {
|
||||
let rendered = render_ssh_private_key_data(&x);
|
||||
let mut is_ok = true;
|
||||
|
||||
for line in rendered.lines() {
|
||||
let clean_line: String = line.chars().filter(|x| *x != '\r').collect();
|
||||
is_ok &= clean_line.len() <= 70;
|
||||
}
|
||||
|
||||
is_ok
|
||||
}
|
||||
|
||||
fn u32s_roundtrip_rp(x: u32) -> bool {
|
||||
let mut buffer = vec![];
|
||||
render_openssh_u32(&mut buffer, x).unwrap();
|
||||
let mut cursor = Cursor::new(buffer);
|
||||
let check = parse_openssh_u32(&mut cursor).unwrap();
|
||||
x == check
|
||||
}
|
||||
|
||||
fn u32s_roundtrip_pr(a: u8, b: u8, c: u8, d: u8) -> bool {
|
||||
let block = [a,b,c,d];
|
||||
let mut cursor = Cursor::new(block);
|
||||
let base = parse_openssh_u32(&mut cursor).unwrap();
|
||||
let mut rendered = vec![];
|
||||
render_openssh_u32(&mut rendered, base).unwrap();
|
||||
(block[0] == rendered[0]) &&
|
||||
(block[1] == rendered[1]) &&
|
||||
(block[2] == rendered[2]) &&
|
||||
(block[3] == rendered[3])
|
||||
}
|
||||
|
||||
fn string_roundtrip(s: String) -> bool {
|
||||
let mut buffer = vec![];
|
||||
render_openssh_string(&mut buffer, &s).unwrap();
|
||||
let mut cursor = Cursor::new(buffer);
|
||||
let check = parse_openssh_string(&mut cursor).unwrap();
|
||||
s == check
|
||||
}
|
||||
|
||||
fn buffer(os: Vec<u8>) -> bool {
|
||||
let mut buffer = vec![];
|
||||
render_openssh_buffer(&mut buffer, &os).unwrap();
|
||||
let mut cursor = Cursor::new(buffer);
|
||||
let check = parse_openssh_buffer(&mut cursor).unwrap();
|
||||
os == check
|
||||
}
|
||||
|
||||
fn u192(x: U192) -> bool {
|
||||
let mut buffer = vec![];
|
||||
render_openssh_number(&mut buffer, &x).unwrap();
|
||||
let mut cursor = Cursor::new(buffer);
|
||||
let check: U192 = parse_openssh_number(&mut cursor).unwrap();
|
||||
check == x
|
||||
}
|
||||
|
||||
fn u1024(x: U1024) -> bool {
|
||||
let mut buffer = vec![];
|
||||
render_openssh_number(&mut buffer, &x).unwrap();
|
||||
let mut cursor = Cursor::new(buffer);
|
||||
let check: U1024 = parse_openssh_number(&mut cursor).unwrap();
|
||||
check == x
|
||||
}
|
||||
|
||||
fn u2048(x: U2048) -> bool {
|
||||
let mut buffer = vec![];
|
||||
render_openssh_number(&mut buffer, &x).unwrap();
|
||||
let mut cursor = Cursor::new(buffer);
|
||||
let check: U2048 = parse_openssh_number(&mut cursor).unwrap();
|
||||
check == x
|
||||
}
|
||||
|
||||
fn u4096(x: U4096) -> bool {
|
||||
let mut buffer = vec![];
|
||||
render_openssh_number(&mut buffer, &x).unwrap();
|
||||
let mut cursor = Cursor::new(buffer);
|
||||
let check: U4096 = parse_openssh_number(&mut cursor).unwrap();
|
||||
check == x
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn pregenerated_reencode() {
|
||||
let test_files = ["dsa1024-1", "dsa1024-2", "dsa1024-3",
|
||||
"ecdsa256-1", "ecdsa256-2", "ecdsa256-3",
|
||||
"ecdsa384-1", "ecdsa384-2", "ecdsa384-3",
|
||||
"ecdsa521-1", "ecdsa521-2", "ecdsa521-3",
|
||||
"ed25519-1", "ed25519-2", "ed25519-3",
|
||||
"rsa1024-1", "rsa1024-2", "rsa1024-3",
|
||||
"rsa2048-1", "rsa2048-2", "rsa2048-3",
|
||||
"rsa3072-1", "rsa3072-2", "rsa3072-3",
|
||||
"rsa4096-1", "rsa4096-2", "rsa4096-3",
|
||||
"rsa8192-1", "rsa8192-2", "rsa8192-3" ];
|
||||
|
||||
for file in test_files.iter() {
|
||||
let path = format!("testdata/ssh/{}",file);
|
||||
let mut fd = File::open(path).unwrap();
|
||||
let mut contents = String::new();
|
||||
fd.read_to_string(&mut contents).unwrap();
|
||||
let parsed = parse_ssh_private_key_data(&contents).unwrap();
|
||||
let rendered = render_ssh_private_key_data(&parsed);
|
||||
// we remove white space in this to avoid a couple issues with files
|
||||
// generated in Windows or not, as well as trailing white space that
|
||||
// doesn't really matter.
|
||||
let cleaned_orig: String = contents.chars().filter(|x| !x.is_whitespace()).collect();
|
||||
let cleaned_rend: String = rendered.chars().filter(|x| !x.is_whitespace()).collect();
|
||||
assert_eq!(cleaned_orig, cleaned_rend);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn header_roundtrips() {
|
||||
let mut vec = Vec::new();
|
||||
assert!(render_openssh_header(&mut vec).is_ok());
|
||||
let mut cursor = Cursor::new(vec);
|
||||
assert!(parse_openssh_header(&mut cursor).is_ok());
|
||||
}
|
||||
428
src/ssh/mod.rs
Normal file
428
src/ssh/mod.rs
Normal file
@@ -0,0 +1,428 @@
|
||||
//! Most of the routines you want are exported from this module as functions,
|
||||
//! not as structs, macros, enums, or what have you. In particular, you
|
||||
//! probably want the `decode` or `encode` functions, or one of the functions
|
||||
//! that `load`s data from disk or `write`s it. Here's some example code
|
||||
//! to get you started, using a generated ED25519 key for fun:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use simple_crypto::ed25519::ED25519KeyPair;
|
||||
//! use simple_crypto::ssh::*;
|
||||
//!
|
||||
//! // Generate a new ED25519 key
|
||||
//! let mut rng = rand::rngs::OsRng::new().unwrap();
|
||||
//! let kp = ED25519KeyPair::generate(&mut rng);
|
||||
//!
|
||||
//! // Now that we have it, we can encode it as a handy ASCII string in memory,
|
||||
//! // using a totally fake email address for fun:
|
||||
//! let ascii_rep = encode_ssh(&kp, "fake@email.addr").expect("Encode failure!");
|
||||
//!
|
||||
//! // As usual, we should be able to decode anything we encode, and the
|
||||
//! // keys should match:
|
||||
//! let (kp2, addr2) = decode_ssh(&ascii_rep).expect("Decode failure!");
|
||||
//! assert_eq!(kp, kp2);
|
||||
//! assert_eq!(&addr2, "fake@email.addr");
|
||||
//!
|
||||
//! // If you want to write this to a file, you can just do so directly:
|
||||
//! write_ssh_keyfile("test.ed25519", &kp, "fake@email.addr").expect("write error");
|
||||
//! // And then load it back:
|
||||
//! let (kp3, addr3) = load_ssh_keyfile("test.ed25519").expect("load error");
|
||||
//! // And, of course, it should be the same.
|
||||
//! assert_eq!(kp, kp3);
|
||||
//! assert_eq!(addr2, addr3);
|
||||
//! ```
|
||||
mod dsa;
|
||||
mod ecdsa;
|
||||
mod ed25519;
|
||||
mod errors;
|
||||
pub mod frame;
|
||||
mod rsa;
|
||||
|
||||
pub use self::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||
|
||||
use base64::decode;
|
||||
use self::frame::*;
|
||||
use std::fs::File;
|
||||
use std::io::{Cursor,Read,Write};
|
||||
use std::path::Path;
|
||||
use super::KeyPair;
|
||||
|
||||
/// A trait defining keys that can be parsed / rendered by this library. Note
|
||||
/// that you probably don't want to use these routines directly; they're mostly
|
||||
/// used by the internal functions. Perhaps the only reason to use them is to
|
||||
/// implement them, because you've got another kind of key you want to parse that
|
||||
/// isn't already part of the library. (In that case, though ... maybe send a
|
||||
/// patch?)
|
||||
pub trait SSHKey: Sized + KeyPair {
|
||||
/// Return true if the given string is a valid key type identifier for this
|
||||
/// key type. (i.e., "ssh-ed25519" is the identifier for ED25519, and "dss"
|
||||
/// and "ssh-dss" are both valid identifiers for DSA keys.)
|
||||
fn valid_keytype(s: &str) -> bool;
|
||||
|
||||
/// Parse the public blob info within an SSH blob. I strongly recommend
|
||||
/// using the functions in `ssh::frame` for this.
|
||||
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>;
|
||||
/// Parse the private blob info within an SSH blob. I strongly recommend
|
||||
/// using the functions in `ssh::frame` for this.
|
||||
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>;
|
||||
|
||||
/// Render the public blob info within an SSH blob. I strongly recommend
|
||||
/// using the functions in `ssh::frame` for this.
|
||||
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>;
|
||||
/// Render the private blob info within an SSH blob. I strongly recommend
|
||||
/// using the functions in `ssh::frame` for this.
|
||||
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>;
|
||||
}
|
||||
|
||||
/// Decode a string containing a private key into the appropriate key type and
|
||||
/// the comment associated with it, usually an email address or similar.
|
||||
pub fn decode_ssh<KP: SSHKey>(x: &str) -> Result<(KP, String),SSHKeyParseError>
|
||||
{
|
||||
let bytes = parse_ssh_private_key_data(x)?;
|
||||
let data_size = bytes.len() as u64;
|
||||
let mut byte_cursor = Cursor::new(bytes);
|
||||
|
||||
parse_openssh_header(&mut byte_cursor)?;
|
||||
let ciphername = parse_openssh_string(&mut byte_cursor)?;
|
||||
if ciphername != "none" {
|
||||
return Err(SSHKeyParseError::UnknownKeyCipher(ciphername));
|
||||
}
|
||||
let kdfname = parse_openssh_string(&mut byte_cursor)?;
|
||||
if kdfname != "none" {
|
||||
return Err(SSHKeyParseError::UnknownKeyCipher(kdfname));
|
||||
}
|
||||
let kdfoptions = parse_openssh_buffer(&mut byte_cursor)?;
|
||||
if kdfoptions.len() > 0 {
|
||||
return Err(SSHKeyParseError::UnexpectedKDFOptions);
|
||||
}
|
||||
let numkeys = parse_openssh_u32(&mut byte_cursor)?;
|
||||
if numkeys != 1 {
|
||||
return Err(SSHKeyParseError::InvalidNumberOfKeys(numkeys));
|
||||
}
|
||||
let pubkey0 = parse_openssh_buffer(&mut byte_cursor)?;
|
||||
let privkeys = parse_openssh_buffer(&mut byte_cursor)?;
|
||||
if byte_cursor.position() < data_size {
|
||||
return Err(SSHKeyParseError::UnknownTrailingData);
|
||||
}
|
||||
|
||||
let mut pubcursor = Cursor::new(pubkey0);
|
||||
let public = KP::parse_ssh_public_info(&mut pubcursor)?;
|
||||
let mut privcursor = Cursor::new(privkeys);
|
||||
let (private, comment) = KP::parse_ssh_private_info(&mut privcursor)?;
|
||||
|
||||
Ok((KP::new(public, private), comment))
|
||||
}
|
||||
|
||||
/// Decode a string containing a public key into an appropriate key type and
|
||||
/// the comment associated with it, usually an email address or similar.
|
||||
pub fn decode_ssh_pubkey<KP: SSHKey>(s: &str) -> Result<(KP::Public, String),SSHKeyParseError>
|
||||
{
|
||||
let mut splitter = s.split_whitespace();
|
||||
|
||||
match (splitter.next(), splitter.next(), splitter.next(), splitter.next()) {
|
||||
(Some(keytype), Some(keymaterial), Some(comment), None) => {
|
||||
if !KP::valid_keytype(keytype) {
|
||||
return Err(SSHKeyParseError::InvalidPublicKeyType);
|
||||
}
|
||||
|
||||
let bytes = decode(keymaterial)?;
|
||||
let mut byte_cursor = Cursor::new(bytes);
|
||||
let key = KP::parse_ssh_public_info(&mut byte_cursor)?;
|
||||
|
||||
Ok((key, comment.to_string()))
|
||||
}
|
||||
_ =>
|
||||
Err(SSHKeyParseError::BrokenPublicKeyLine)
|
||||
}
|
||||
}
|
||||
|
||||
/// Load an SSH private key file, returning the appropriate key type and the
|
||||
/// comment associated with it.
|
||||
pub fn load_ssh_keyfile<KP,P>(path: P) -> Result<(KP, String),SSHKeyParseError>
|
||||
where
|
||||
KP: SSHKey,
|
||||
P: AsRef<Path>
|
||||
{
|
||||
let mut file = File::open(path)?;
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)?;
|
||||
decode_ssh(&contents)
|
||||
}
|
||||
|
||||
/// Load all the public keys from a file into memory.
|
||||
pub fn load_ssh_pubkeys<KP,P>(path: P) -> Result<Vec<(KP::Public, String)>,SSHKeyParseError>
|
||||
where
|
||||
KP: SSHKey,
|
||||
P: AsRef<Path>
|
||||
{
|
||||
let mut file = File::open(path)?;
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)?;
|
||||
let mut result = Vec::new();
|
||||
|
||||
for line in contents.lines() {
|
||||
result.push( decode_ssh_pubkey::<KP>(line)? );
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Encode a supported key into its ASCII SSH format, with the given comment.
|
||||
pub fn encode_ssh<KP: SSHKey>(x: &KP, comment: &str) -> Result<String,SSHKeyRenderError>
|
||||
{
|
||||
let mut pubkeybin = Vec::with_capacity(8192);
|
||||
let mut privkeybin = Vec::with_capacity(8192);
|
||||
let mut binary = Vec::with_capacity(16384);
|
||||
|
||||
// create the public key bits
|
||||
x.render_ssh_public_info(&mut pubkeybin)?;
|
||||
// create the private key bits
|
||||
render_openssh_u32(&mut privkeybin, 0xDEADBEEF)?; // FIXME: Any reason for this to be random?
|
||||
render_openssh_u32(&mut privkeybin, 0xDEADBEEF)?; // ditto
|
||||
x.render_ssh_private_info(&mut privkeybin)?;
|
||||
render_openssh_string(&mut privkeybin, comment)?;
|
||||
// add some padding (not quite sure why)
|
||||
let mut i = comment.len();
|
||||
while (i % 16) != 0 {
|
||||
privkeybin.write(&[(i - comment.len() + 1) as u8])?;
|
||||
i += 1;
|
||||
}
|
||||
// render a bunch of the framing stuff
|
||||
render_openssh_header(&mut binary)?;
|
||||
render_openssh_string(&mut binary, "none")?; // ciphername
|
||||
render_openssh_string(&mut binary, "none")?; // kdfname
|
||||
render_openssh_buffer(&mut binary, &[])?; // kdfoptions
|
||||
render_openssh_u32(&mut binary, 1)?; // numkeys
|
||||
render_openssh_buffer(&mut binary, &pubkeybin)?;
|
||||
render_openssh_buffer(&mut binary, &privkeybin)?;
|
||||
Ok(render_ssh_private_key_data(&binary))
|
||||
}
|
||||
|
||||
/// Encode a supported key into the given file, with the given comment.
|
||||
pub fn write_ssh_keyfile<KP,P>(path: P, x: &KP, comment: &str) -> Result<(),SSHKeyRenderError>
|
||||
where
|
||||
KP: SSHKey,
|
||||
P: AsRef<Path>
|
||||
{
|
||||
let mut file = File::create(path)?;
|
||||
let contents = encode_ssh(x, comment)?;
|
||||
let bytes = contents.into_bytes();
|
||||
file.write_all(&bytes)?;
|
||||
file.sync_all()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use dsa::{DSAKeyPair,DSAPublicKey,L1024N160};
|
||||
#[cfg(test)]
|
||||
use ecdsa::ECDSAPair;
|
||||
#[cfg(test)]
|
||||
use ed25519::ED25519KeyPair;
|
||||
#[cfg(test)]
|
||||
use rsa::{RSAPair,RSAPublic,SIGNING_HASH_SHA256};
|
||||
#[cfg(test)]
|
||||
use sha::SHA256;
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn dsa_examples() {
|
||||
let test_files = ["dsa1024-1", "dsa1024-2", "dsa1024-3"];
|
||||
|
||||
for file in test_files.iter() {
|
||||
let path = format!("testdata/ssh/{}",file);
|
||||
let mkeypair = load_ssh_keyfile(path);
|
||||
match mkeypair {
|
||||
Err(e) => assert!(false, format!("reading error: {:?}", e)),
|
||||
Ok((keypair, comment)) => {
|
||||
let buffer = [0,1,2,3,4,6,2];
|
||||
let _ : DSAKeyPair<L1024N160> = keypair;
|
||||
let sig = keypair.private.sign::<SHA256>(&buffer);
|
||||
assert!(keypair.public.verify::<SHA256>(&buffer, &sig));
|
||||
let buffer2 = [0,1,2,3,4,6,5];
|
||||
assert!(!keypair.public.verify::<SHA256>(&buffer2, &sig));
|
||||
match encode_ssh(&keypair, &comment) {
|
||||
Err(e2) => assert!(false, format!("render error: {:?}", e2)),
|
||||
Ok(encodedstr) => {
|
||||
match decode_ssh(&encodedstr) {
|
||||
Err(e3) => assert!(false, format!("reparse error: {:?}", e3)),
|
||||
Ok((keypair2,comment2)) => {
|
||||
let _ : DSAKeyPair<L1024N160> = keypair2;
|
||||
assert_eq!(keypair.public.params.p,keypair2.public.params.p,"failed to reparse key pair (p)");
|
||||
assert_eq!(keypair.public.params.q,keypair2.public.params.q,"failed to reparse key pair (q)");
|
||||
assert_eq!(keypair.public.params.g,keypair2.public.params.g,"failed to reparse key pair (g)");
|
||||
assert_eq!(keypair.private.params.p,keypair2.private.params.p,"failed to reparse key pair (p)");
|
||||
assert_eq!(keypair.private.params.q,keypair2.private.params.q,"failed to reparse key pair (q)");
|
||||
assert_eq!(keypair.private.params.g,keypair2.private.params.g,"failed to reparse key pair (g)");
|
||||
assert_eq!(keypair.public.y,keypair2.public.y,"failed to reparse key pair (y)");
|
||||
assert_eq!(keypair.private.x,keypair2.private.x,"failed to reparse key pair (x)");
|
||||
assert_eq!(comment,comment2,"failed to reparse comment");
|
||||
let ppath = format!("testdata/ssh/{}.pub",file);
|
||||
match load_ssh_pubkeys::<DSAKeyPair<L1024N160>,String>(ppath) {
|
||||
Err(e4) => assert!(false, format!("pubkey error: {:?}", e4)),
|
||||
Ok(pubkeys) => {
|
||||
let _ : Vec<(DSAPublicKey<L1024N160>,String)> = pubkeys;
|
||||
for (pubkey, comment3) in pubkeys {
|
||||
assert_eq!(pubkey.params.p, keypair.public.params.p, "public key check (p)");
|
||||
assert_eq!(pubkey.params.q, keypair.public.params.q, "public key check (q)");
|
||||
assert_eq!(pubkey.params.g, keypair.public.params.g, "public key check (g)");
|
||||
assert_eq!(pubkey.y, keypair.public.y, "public key check (y)");
|
||||
assert_eq!(comment, comment3, "public key check comment")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn rsa_examples() {
|
||||
let test_files = ["rsa1024-1", "rsa1024-2", "rsa1024-3",
|
||||
"rsa2048-1", "rsa2048-2", "rsa2048-3",
|
||||
"rsa3072-1", "rsa3072-2", "rsa3072-3",
|
||||
"rsa4096-1", "rsa4096-2", "rsa4096-3",
|
||||
"rsa8192-1", "rsa8192-2", "rsa8192-3"];
|
||||
|
||||
for file in test_files.iter() {
|
||||
let path = format!("testdata/ssh/{}",file);
|
||||
let mkeypair = load_ssh_keyfile::<RSAPair,String>(path);
|
||||
match mkeypair {
|
||||
Err(e) => assert!(false, format!("reading error: {:?}", e)),
|
||||
Ok((keypair, comment)) => {
|
||||
let buffer = [0,1,2,3,4,6,2];
|
||||
let sig = keypair.sign(&SIGNING_HASH_SHA256, &buffer);
|
||||
assert!(keypair.verify(&SIGNING_HASH_SHA256, &buffer, &sig));
|
||||
match encode_ssh(&keypair, &comment) {
|
||||
Err(e2) => assert!(false, format!("render error: {:?}", e2)),
|
||||
Ok(encodedstr) => {
|
||||
match decode_ssh(&encodedstr) {
|
||||
Err(e3) => assert!(false, format!("reparse error: {:?}", e3)),
|
||||
Ok((keypair2,comment2)) => {
|
||||
assert_eq!(keypair,keypair2,"failed to reparse key pair");
|
||||
assert_eq!(comment,comment2,"failed to reparse comment");
|
||||
let ppath = format!("testdata/ssh/{}.pub",file);
|
||||
match load_ssh_pubkeys::<RSAPair,String>(ppath) {
|
||||
Err(e4) => assert!(false, format!("pubkey error: {:?}", e4)),
|
||||
Ok(pubkeys) => {
|
||||
let _ : Vec<(RSAPublic,String)> = pubkeys;
|
||||
for (pubkey, comment3) in pubkeys {
|
||||
assert_eq!(pubkey, keypair.public(), "public key check");
|
||||
assert_eq!(comment, comment3, "public key check comment");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn ecdsa_examples() {
|
||||
let test_files = ["ecdsa256-1", "ecdsa256-2", "ecdsa256-3",
|
||||
"ecdsa384-1", "ecdsa384-2", "ecdsa384-3",
|
||||
"ecdsa521-1", "ecdsa521-2", "ecdsa521-3"];
|
||||
|
||||
for file in test_files.iter() {
|
||||
let path = format!("testdata/ssh/{}",file);
|
||||
match load_ssh_keyfile::<ECDSAPair,String>(path) {
|
||||
Err(e) =>
|
||||
assert!(false, "SSH ECDSA parse error: {:?}", e),
|
||||
Ok((keypair,comment)) => {
|
||||
// first see if this roundtrips
|
||||
let buffer = vec![0,1,2,4,5,6,9];
|
||||
match keypair {
|
||||
ECDSAPair::P192(_,_) =>
|
||||
assert!(false, "Somehow got a P192 in read test"),
|
||||
ECDSAPair::P224(_,_) =>
|
||||
assert!(false, "Somehow got a P224 in read test"),
|
||||
ECDSAPair::P256(ref pu, ref pr) => {
|
||||
let sig = pr.sign::<SHA256>(&buffer);
|
||||
assert!(pu.verify::<SHA256>(&buffer, &sig));
|
||||
}
|
||||
ECDSAPair::P384(ref pu, ref pr) => {
|
||||
let sig = pr.sign::<SHA256>(&buffer);
|
||||
assert!(pu.verify::<SHA256>(&buffer, &sig));
|
||||
}
|
||||
ECDSAPair::P521(ref pu, ref pr) => {
|
||||
let sig = pr.sign::<SHA256>(&buffer);
|
||||
assert!(pu.verify::<SHA256>(&buffer, &sig));
|
||||
}
|
||||
}
|
||||
// encode this, parse it again
|
||||
match encode_ssh(&keypair, &comment) {
|
||||
Err(e) =>
|
||||
assert!(false, "SSH ECDSA encoding error: {:?}", e),
|
||||
Ok(coded) => {
|
||||
match (decode_ssh(&coded), keypair) {
|
||||
(Err(e), _) =>
|
||||
assert!(false, "SSSH ECDSA redecoding error: {:?}", e),
|
||||
(Ok((ECDSAPair::P256(pu2, pr2), comment2)), ECDSAPair::P256(pu,pr)) => {
|
||||
assert_eq!(pu, pu2, "public key mismatch");
|
||||
assert_eq!(pr, pr2, "public key mismatch");
|
||||
assert_eq!(comment, comment2, "comment mismatch");
|
||||
}
|
||||
(Ok((ECDSAPair::P384(pu2, pr2), comment2)), ECDSAPair::P384(pu,pr)) => {
|
||||
assert_eq!(pu, pu2, "public key mismatch");
|
||||
assert_eq!(pr, pr2, "public key mismatch");
|
||||
assert_eq!(comment, comment2, "comment mismatch");
|
||||
}
|
||||
(Ok((ECDSAPair::P521(pu2, pr2), comment2)), ECDSAPair::P521(pu,pr)) => {
|
||||
assert_eq!(pu, pu2, "public key mismatch");
|
||||
assert_eq!(pr, pr2, "public key mismatch");
|
||||
assert_eq!(comment, comment2, "comment mismatch");
|
||||
}
|
||||
_ =>
|
||||
assert!(false, "Failed to accurately re-parse key")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn ed25519_examples() {
|
||||
let test_files = ["ed25519-1", "ed25519-2", "ed25519-3"];
|
||||
|
||||
for file in test_files.iter() {
|
||||
let path = format!("testdata/ssh/{}",file);
|
||||
match load_ssh_keyfile::<ED25519KeyPair,String>(path) {
|
||||
Err(e) =>
|
||||
assert!(false, "SSH ED25519 parse error: {:?}", e),
|
||||
Ok((keypair,comment)) => {
|
||||
// first see if this roundtrips
|
||||
let buffer = vec![0,1,2,4,5,6,9];
|
||||
let sig = keypair.private.sign(&buffer);
|
||||
assert!(keypair.public.verify(&buffer, &sig));
|
||||
match encode_ssh(&keypair, &comment) {
|
||||
Err(e) =>
|
||||
assert!(false, "SSH ED25519 encoding error: {:?}", e),
|
||||
Ok(coded) => {
|
||||
match decode_ssh(&coded) {
|
||||
Err(e) =>
|
||||
assert!(false, "SSSH ECDSA redecoding error: {:?}", e),
|
||||
Ok((keypair2, comment2)) => {
|
||||
let _ : ED25519KeyPair = keypair2;
|
||||
assert_eq!(keypair.public, keypair2.public, "public key mismatch");
|
||||
assert_eq!(keypair.private, keypair2.private, "public key mismatch");
|
||||
assert_eq!(comment, comment2, "comment mismatch");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
201
src/ssh/rsa.rs
Normal file
201
src/ssh/rsa.rs
Normal file
@@ -0,0 +1,201 @@
|
||||
use cryptonum::unsigned::*;
|
||||
use rsa::{RSAPair,RSAPublic,RSAPublicKey,RSAPrivate,RSAPrivateKey};
|
||||
use std::io::{Read,Write};
|
||||
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||
use ssh::frame::*;
|
||||
use ssh::SSHKey;
|
||||
|
||||
impl SSHKey for RSAPair {
|
||||
fn valid_keytype(s: &str) -> bool {
|
||||
(s == "ssh-rsa") || (s == "rsa")
|
||||
}
|
||||
|
||||
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>
|
||||
{
|
||||
let pubkey_type = parse_openssh_string(inp)?;
|
||||
if !Self::valid_keytype(&pubkey_type) {
|
||||
return Err(SSHKeyParseError::UnknownKeyType(pubkey_type));
|
||||
}
|
||||
// this peaks a little under the cover a bit (it'd be nice to pretend
|
||||
// that we didn't know the number format was the same as the buffer
|
||||
// one), but we need to infer what kind of key this is, and this appears
|
||||
// to be the easiest / fastest way.
|
||||
let mut ebuf = parse_openssh_buffer(inp)?;
|
||||
let mut nbuf = parse_openssh_buffer(inp)?;
|
||||
|
||||
while ebuf[0] == 0 { ebuf.remove(0); }
|
||||
while nbuf[0] == 0 { nbuf.remove(0); }
|
||||
|
||||
if nbuf.len() > (8192 / 8) {
|
||||
let e = U15360::from_bytes(&ebuf);
|
||||
let n = U15360::from_bytes(&nbuf);
|
||||
Ok(RSAPublic::Key15360(RSAPublicKey::<U15360>::new(n, e)))
|
||||
} else if nbuf.len() > (4096 / 8) {
|
||||
let e = U8192::from_bytes(&ebuf);
|
||||
let n = U8192::from_bytes(&nbuf);
|
||||
Ok(RSAPublic::Key8192(RSAPublicKey::<U8192>::new(n, e)))
|
||||
} else if nbuf.len() > (3072 / 8) {
|
||||
let e = U4096::from_bytes(&ebuf);
|
||||
let n = U4096::from_bytes(&nbuf);
|
||||
Ok(RSAPublic::Key4096(RSAPublicKey::<U4096>::new(n, e)))
|
||||
} else if nbuf.len() > (2048 / 8) {
|
||||
let e = U3072::from_bytes(&ebuf);
|
||||
let n = U3072::from_bytes(&nbuf);
|
||||
Ok(RSAPublic::Key3072(RSAPublicKey::<U3072>::new(n, e)))
|
||||
} else if nbuf.len() > (1024 / 8) {
|
||||
let e = U2048::from_bytes(&ebuf);
|
||||
let n = U2048::from_bytes(&nbuf);
|
||||
Ok(RSAPublic::Key2048(RSAPublicKey::<U2048>::new(n, e)))
|
||||
} else if nbuf.len() > (512 / 8) {
|
||||
let e = U1024::from_bytes(&ebuf);
|
||||
let n = U1024::from_bytes(&nbuf);
|
||||
Ok(RSAPublic::Key1024(RSAPublicKey::<U1024>::new(n, e)))
|
||||
} else {
|
||||
let e = U512::from_bytes(&ebuf);
|
||||
let n = U512::from_bytes(&nbuf);
|
||||
Ok(RSAPublic::Key512(RSAPublicKey::<U512>::new(n, e)))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>
|
||||
{
|
||||
let check1 = parse_openssh_u32(inp)?;
|
||||
let check2 = parse_openssh_u32(inp)?;
|
||||
if check1 != check2 {
|
||||
return Err(SSHKeyParseError::PrivateKeyCorruption);
|
||||
}
|
||||
let privkey_type = parse_openssh_string(inp)?;
|
||||
if !Self::valid_keytype(&privkey_type) {
|
||||
return Err(SSHKeyParseError::InconsistentKeyTypes("ssh-rsa".to_string(), privkey_type));
|
||||
}
|
||||
|
||||
// See the comment in the public key section.
|
||||
let mut nbuf = parse_openssh_buffer(inp)?;
|
||||
let _ebuf = parse_openssh_buffer(inp)?;
|
||||
let mut dbuf = parse_openssh_buffer(inp)?;
|
||||
let _iqmp = parse_openssh_buffer(inp)?;
|
||||
let _pbuf = parse_openssh_buffer(inp)?;
|
||||
let _qbuf = parse_openssh_buffer(inp)?;
|
||||
let comment = parse_openssh_string(inp)?;
|
||||
for (idx,byte) in inp.bytes().enumerate() {
|
||||
if ((idx+1) as u8) != byte? {
|
||||
return Err(SSHKeyParseError::InvalidPadding);
|
||||
}
|
||||
}
|
||||
|
||||
while dbuf[0] == 0 { dbuf.remove(0); }
|
||||
while nbuf[0] == 0 { nbuf.remove(0); }
|
||||
|
||||
if nbuf.len() > (8192 / 8) {
|
||||
let d = U15360::from_bytes(&dbuf);
|
||||
let n = U15360::from_bytes(&nbuf);
|
||||
Ok((RSAPrivate::Key15360(RSAPrivateKey::<U15360>::new(n, d)), comment))
|
||||
} else if nbuf.len() > (4096 / 8) {
|
||||
let d = U8192::from_bytes(&dbuf);
|
||||
let n = U8192::from_bytes(&nbuf);
|
||||
Ok((RSAPrivate::Key8192(RSAPrivateKey::<U8192>::new(n, d)), comment))
|
||||
} else if nbuf.len() > (3072 / 8) {
|
||||
let d = U4096::from_bytes(&dbuf);
|
||||
let n = U4096::from_bytes(&nbuf);
|
||||
Ok((RSAPrivate::Key4096(RSAPrivateKey::<U4096>::new(n, d)), comment))
|
||||
} else if nbuf.len() > (2048 / 8) {
|
||||
let d = U3072::from_bytes(&dbuf);
|
||||
let n = U3072::from_bytes(&nbuf);
|
||||
Ok((RSAPrivate::Key3072(RSAPrivateKey::<U3072>::new(n, d)), comment))
|
||||
} else if nbuf.len() > (1024 / 8) {
|
||||
let d = U2048::from_bytes(&dbuf);
|
||||
let n = U2048::from_bytes(&nbuf);
|
||||
Ok((RSAPrivate::Key2048(RSAPrivateKey::<U2048>::new(n, d)), comment))
|
||||
} else if nbuf.len() > (512 / 8) {
|
||||
let d = U1024::from_bytes(&dbuf);
|
||||
let n = U1024::from_bytes(&nbuf);
|
||||
Ok((RSAPrivate::Key1024(RSAPrivateKey::<U1024>::new(n, d)), comment))
|
||||
} else {
|
||||
let d = U512::from_bytes(&dbuf);
|
||||
let n = U512::from_bytes(&nbuf);
|
||||
Ok((RSAPrivate::Key512(RSAPrivateKey::<U512>::new(n, d)), comment))
|
||||
}
|
||||
}
|
||||
|
||||
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
render_openssh_string(out, "ssh-rsa")?;
|
||||
match self {
|
||||
RSAPair::R512(pbl,_) => {
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
}
|
||||
RSAPair::R1024(pbl,_) => {
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
}
|
||||
RSAPair::R2048(pbl,_) => {
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
}
|
||||
RSAPair::R3072(pbl,_) => {
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
}
|
||||
RSAPair::R4096(pbl,_) => {
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
}
|
||||
RSAPair::R8192(pbl,_) => {
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
}
|
||||
RSAPair::R15360(pbl,_) => {
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
render_openssh_string(out, "ssh-rsa")?;
|
||||
match self {
|
||||
RSAPair::R512(pbl,prv) => {
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &prv.d)?;
|
||||
}
|
||||
RSAPair::R1024(pbl,prv) => {
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &prv.d)?;
|
||||
}
|
||||
RSAPair::R2048(pbl,prv) => {
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &prv.d)?;
|
||||
}
|
||||
RSAPair::R3072(pbl,prv) => {
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &prv.d)?;
|
||||
}
|
||||
RSAPair::R4096(pbl,prv) => {
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &prv.d)?;
|
||||
}
|
||||
RSAPair::R8192(pbl,prv) => {
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &prv.d)?;
|
||||
}
|
||||
RSAPair::R15360(pbl,prv) => {
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &prv.d)?;
|
||||
}
|
||||
}
|
||||
/* iqmp */ render_openssh_buffer(out, &vec![])?;
|
||||
/* p */ render_openssh_buffer(out, &vec![])?;
|
||||
/* q */ render_openssh_buffer(out, &vec![])?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
67
src/testing.rs
Normal file
67
src/testing.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
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());
|
||||
let mut items = line.split(": ");
|
||||
let key = items.next().unwrap();
|
||||
let valbits = items.next().unwrap();
|
||||
let neg = valbits.contains('-');
|
||||
let valbitsnoneg = valbits.trim_start_matches("-");
|
||||
|
||||
let mut nibble_iter = valbitsnoneg.chars().rev();
|
||||
let mut val = Vec::new();
|
||||
|
||||
while let Some(c1) = nibble_iter.next() {
|
||||
match nibble_iter.next() {
|
||||
None => {
|
||||
val.push( c1.to_digit(16).expect(&format!("Unexpected character: |{}|", c1)) as u8 );
|
||||
}
|
||||
Some(c2) => {
|
||||
let b1 = c1.to_digit(16).expect(&format!("Unexpected character: |{}|", c1)) as u8;
|
||||
let b2 = c2.to_digit(16).expect(&format!("Unexpected character: |{}|", c2)) as u8;
|
||||
val.push( (b2 << 4) | b1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
val.reverse();
|
||||
|
||||
(key.to_string(), neg, val)
|
||||
}
|
||||
|
||||
fn next_test_case(contents: &mut Lines, lines: usize) ->
|
||||
Option<HashMap<String,(bool,Vec<u8>)>>
|
||||
{
|
||||
let mut res = HashMap::new();
|
||||
let mut count = 0;
|
||||
|
||||
while count < lines {
|
||||
let line = contents.next()?;
|
||||
let (key, neg, val) = next_value_set(line);
|
||||
res.insert(key, (neg,val));
|
||||
count += 1;
|
||||
}
|
||||
|
||||
Some(res)
|
||||
}
|
||||
|
||||
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();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
let mut iter = contents.lines();
|
||||
|
||||
while let Some(scase) = next_test_case(&mut iter, i) {
|
||||
f(scase);
|
||||
}
|
||||
}
|
||||
57
src/utils.rs
Normal file
57
src/utils.rs
Normal 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);
|
||||
393
src/x509/algident.rs
Normal file
393
src/x509/algident.rs
Normal file
@@ -0,0 +1,393 @@
|
||||
use num::BigUint;
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
|
||||
use x509::error::X509ParseError;
|
||||
|
||||
/// A supported x509 hash algorithm
|
||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||
pub enum HashAlgorithm { SHA1, SHA224, SHA256, SHA384, SHA512 }
|
||||
|
||||
/// A supported x509 asymmetric crypto algorithm
|
||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||
pub enum PublicKeyInfo { RSA, DSA, ECDSA }
|
||||
|
||||
/// The algorithm used, either in a certificate or as part of the signing
|
||||
/// process. We only actually support a subset of the possible values,
|
||||
/// here, although we try to catch them all.
|
||||
///
|
||||
/// Specifically, this library supports:
|
||||
///
|
||||
/// | | *RSA* | *DSA* | *ECDSA* |
|
||||
/// |----------|-------|-------|---------|
|
||||
/// | *SHA1* | X | X | X |
|
||||
/// | *SHA224* | X | X | X |
|
||||
/// | *SHA256* | X | X | X |
|
||||
/// | *SHA384* | X | | X |
|
||||
/// | *SHA512* | X | | X |
|
||||
///
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct AlgorithmIdentifier {
|
||||
pub hash: HashAlgorithm,
|
||||
pub algo: PublicKeyInfo
|
||||
}
|
||||
|
||||
impl FromASN1 for AlgorithmIdentifier {
|
||||
type Error = X509ParseError;
|
||||
|
||||
fn from_asn1(v: &[ASN1Block])
|
||||
-> Result<(AlgorithmIdentifier,&[ASN1Block]),X509ParseError>
|
||||
{
|
||||
match v.split_first() {
|
||||
None =>
|
||||
Err(X509ParseError::NotEnoughData),
|
||||
Some((x, rest)) => {
|
||||
let v = decode_algorithm_ident(&x)?;
|
||||
Ok((v, rest))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_algorithm_ident(x: &ASN1Block)
|
||||
-> Result<AlgorithmIdentifier,X509ParseError>
|
||||
{
|
||||
// AlgorithmIdentifier ::= SEQUENCE {
|
||||
// algorithm OBJECT IDENTIFIER,
|
||||
// parameters ANY DEFINED BY algorithm OPTIONAL }
|
||||
match x {
|
||||
&ASN1Block::Sequence(_, _, ref v) if v.len() >= 1 => {
|
||||
match v[0] {
|
||||
ASN1Block::ObjectIdentifier(_, _, ref oid) => {
|
||||
if oid == oid!(1,2,840,113549,1,1,5) {
|
||||
return Ok(AlgorithmIdentifier {
|
||||
hash: HashAlgorithm::SHA1,
|
||||
algo: PublicKeyInfo::RSA
|
||||
});
|
||||
}
|
||||
if oid == oid!(1,2,840,113549,1,1,11) {
|
||||
return Ok(AlgorithmIdentifier {
|
||||
hash: HashAlgorithm::SHA256,
|
||||
algo: PublicKeyInfo::RSA
|
||||
});
|
||||
}
|
||||
if oid == oid!(1,2,840,113549,1,1,12) {
|
||||
return Ok(AlgorithmIdentifier {
|
||||
hash: HashAlgorithm::SHA384,
|
||||
algo: PublicKeyInfo::RSA
|
||||
});
|
||||
}
|
||||
if oid == oid!(1,2,840,113549,1,1,13) {
|
||||
return Ok(AlgorithmIdentifier {
|
||||
hash: HashAlgorithm::SHA512,
|
||||
algo: PublicKeyInfo::RSA
|
||||
});
|
||||
}
|
||||
if oid == oid!(1,2,840,113549,1,1,14) {
|
||||
return Ok(AlgorithmIdentifier {
|
||||
hash: HashAlgorithm::SHA224,
|
||||
algo: PublicKeyInfo::RSA
|
||||
});
|
||||
}
|
||||
if oid == oid!(1,2,840,10040,4,3) {
|
||||
return Ok(AlgorithmIdentifier {
|
||||
hash: HashAlgorithm::SHA1,
|
||||
algo: PublicKeyInfo::DSA
|
||||
});
|
||||
}
|
||||
if oid == oid!(1,2,840,10045,4,1) {
|
||||
return Ok(AlgorithmIdentifier {
|
||||
hash: HashAlgorithm::SHA1,
|
||||
algo: PublicKeyInfo::ECDSA
|
||||
});
|
||||
}
|
||||
if oid == oid!(1,2,840,10045,4,3,1) {
|
||||
return Ok(AlgorithmIdentifier {
|
||||
hash: HashAlgorithm::SHA224,
|
||||
algo: PublicKeyInfo::ECDSA
|
||||
});
|
||||
}
|
||||
if oid == oid!(1,2,840,10045,4,3,2) {
|
||||
return Ok(AlgorithmIdentifier {
|
||||
hash: HashAlgorithm::SHA256,
|
||||
algo: PublicKeyInfo::ECDSA
|
||||
});
|
||||
}
|
||||
if oid == oid!(1,2,840,10045,4,3,3) {
|
||||
return Ok(AlgorithmIdentifier {
|
||||
hash: HashAlgorithm::SHA384,
|
||||
algo: PublicKeyInfo::ECDSA
|
||||
});
|
||||
}
|
||||
if oid == oid!(1,2,840,10045,4,3,4) {
|
||||
return Ok(AlgorithmIdentifier {
|
||||
hash: HashAlgorithm::SHA512,
|
||||
algo: PublicKeyInfo::ECDSA
|
||||
});
|
||||
}
|
||||
// if oid == oid!(2,16,840,1,101,3,4,2,1) {
|
||||
// return Ok(AlgorithmIdentifier {
|
||||
// hash: HashAlgorithm::SHA256,
|
||||
// algo: PublicKeyInfo::RSAPSS
|
||||
// });
|
||||
// }
|
||||
// if oid == oid!(2,16,840,1,101,3,4,2,2) {
|
||||
// return Ok(AlgorithmIdentifier {
|
||||
// hash: HashAlgorithm::SHA384,
|
||||
// algo: PublicKeyInfo::RSAPSS
|
||||
// });
|
||||
// }
|
||||
// if oid == oid!(2,16,840,1,101,3,4,2,3) {
|
||||
// return Ok(AlgorithmIdentifier {
|
||||
// hash: HashAlgorithm::SHA512,
|
||||
// algo: PublicKeyInfo::RSAPSS
|
||||
// });
|
||||
// }
|
||||
// if oid == oid!(2,16,840,1,101,3,4,2,4) {
|
||||
// return Ok(AlgorithmIdentifier {
|
||||
// hash: HashAlgorithm::SHA224,
|
||||
// algo: PublicKeyInfo::RSAPSS
|
||||
// });
|
||||
// }
|
||||
if oid == oid!(2,16,840,1,101,3,4,3,1) {
|
||||
return Ok(AlgorithmIdentifier {
|
||||
hash: HashAlgorithm::SHA224,
|
||||
algo: PublicKeyInfo::DSA
|
||||
});
|
||||
}
|
||||
if oid == oid!(2,16,840,1,101,3,4,3,2) {
|
||||
return Ok(AlgorithmIdentifier {
|
||||
hash: HashAlgorithm::SHA256,
|
||||
algo: PublicKeyInfo::DSA
|
||||
});
|
||||
}
|
||||
Err(X509ParseError::UnknownAlgorithm)
|
||||
}
|
||||
_ =>
|
||||
Err(X509ParseError::UnknownAlgorithm)
|
||||
}
|
||||
}
|
||||
_ =>
|
||||
Err(X509ParseError::IllFormedAlgoInfo)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub enum SigAlgEncodeError {
|
||||
ASN1Error(ASN1EncodeErr),
|
||||
InvalidDSAValue, InvalidHash
|
||||
}
|
||||
|
||||
impl From<ASN1EncodeErr> for SigAlgEncodeError {
|
||||
fn from(e: ASN1EncodeErr) -> SigAlgEncodeError {
|
||||
SigAlgEncodeError::ASN1Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl ToASN1 for AlgorithmIdentifier {
|
||||
type Error = SigAlgEncodeError;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
-> Result<Vec<ASN1Block>,SigAlgEncodeError>
|
||||
{
|
||||
let block = encode_algorithm_ident(c, self)?;
|
||||
Ok(vec![block])
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_algorithm_ident(c: ASN1Class, x: &AlgorithmIdentifier)
|
||||
-> Result<ASN1Block,SigAlgEncodeError>
|
||||
{
|
||||
match x.algo {
|
||||
PublicKeyInfo::RSA => {
|
||||
match x.hash {
|
||||
HashAlgorithm::SHA1 => {
|
||||
let o = oid!(1,2,840,113549,1,1,5);
|
||||
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||
}
|
||||
HashAlgorithm::SHA224 => {
|
||||
let o = oid!(1,2,840,113549,1,1,14);
|
||||
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||
}
|
||||
HashAlgorithm::SHA256 => {
|
||||
let o = oid!(1,2,840,113549,1,1,11);
|
||||
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||
}
|
||||
HashAlgorithm::SHA384 => {
|
||||
let o = oid!(1,2,840,113549,1,1,12);
|
||||
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||
}
|
||||
HashAlgorithm::SHA512 => {
|
||||
let o = oid!(1,2,840,113549,1,1,13);
|
||||
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||
}
|
||||
}
|
||||
}
|
||||
PublicKeyInfo::DSA => {
|
||||
match x.hash {
|
||||
HashAlgorithm::SHA1 => {
|
||||
let o = oid!(1,2,840,10040,4,3);
|
||||
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||
}
|
||||
HashAlgorithm::SHA224 => {
|
||||
let o = oid!(2,16,840,1,101,3,4,3,1);
|
||||
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||
}
|
||||
HashAlgorithm::SHA256 => {
|
||||
let o = oid!(2,16,840,1,101,3,4,3,2);
|
||||
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||
}
|
||||
_ =>
|
||||
Err(SigAlgEncodeError::InvalidHash),
|
||||
}
|
||||
}
|
||||
PublicKeyInfo::ECDSA=> {
|
||||
match x.hash {
|
||||
HashAlgorithm::SHA1 => {
|
||||
let o = oid!(1,2,840,10045,4,1);
|
||||
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||
}
|
||||
HashAlgorithm::SHA224 => {
|
||||
let o = oid!(1,2,840,10045,4,3,1);
|
||||
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||
}
|
||||
HashAlgorithm::SHA256 => {
|
||||
let o = oid!(1,2,840,10045,4,3,2);
|
||||
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||
}
|
||||
HashAlgorithm::SHA384 => {
|
||||
let o = oid!(1,2,840,10045,4,3,3);
|
||||
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||
}
|
||||
HashAlgorithm::SHA512 => {
|
||||
let o = oid!(1,2,840,10045,4,3,4);
|
||||
let obj = ASN1Block::ObjectIdentifier(c, 0, o);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![obj]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use rand::prelude::SliceRandom;
|
||||
use super::*;
|
||||
|
||||
const RSA1: AlgorithmIdentifier =
|
||||
AlgorithmIdentifier{
|
||||
hash: HashAlgorithm::SHA1,
|
||||
algo: PublicKeyInfo::RSA
|
||||
};
|
||||
|
||||
const RSA224: AlgorithmIdentifier =
|
||||
AlgorithmIdentifier{
|
||||
hash: HashAlgorithm::SHA224,
|
||||
algo: PublicKeyInfo::RSA
|
||||
};
|
||||
|
||||
const RSA256: AlgorithmIdentifier =
|
||||
AlgorithmIdentifier{
|
||||
hash: HashAlgorithm::SHA256,
|
||||
algo: PublicKeyInfo::RSA
|
||||
};
|
||||
|
||||
const RSA384: AlgorithmIdentifier =
|
||||
AlgorithmIdentifier{
|
||||
hash: HashAlgorithm::SHA384,
|
||||
algo: PublicKeyInfo::RSA
|
||||
};
|
||||
|
||||
const RSA512: AlgorithmIdentifier =
|
||||
AlgorithmIdentifier{
|
||||
hash: HashAlgorithm::SHA512,
|
||||
algo: PublicKeyInfo::RSA
|
||||
};
|
||||
|
||||
const DSA1: AlgorithmIdentifier =
|
||||
AlgorithmIdentifier{
|
||||
hash: HashAlgorithm::SHA1,
|
||||
algo: PublicKeyInfo::DSA
|
||||
};
|
||||
|
||||
const DSA224: AlgorithmIdentifier =
|
||||
AlgorithmIdentifier{
|
||||
hash: HashAlgorithm::SHA224,
|
||||
algo: PublicKeyInfo::DSA
|
||||
};
|
||||
|
||||
const DSA256: AlgorithmIdentifier =
|
||||
AlgorithmIdentifier{
|
||||
hash: HashAlgorithm::SHA256,
|
||||
algo: PublicKeyInfo::DSA
|
||||
};
|
||||
|
||||
const EC1: AlgorithmIdentifier =
|
||||
AlgorithmIdentifier{
|
||||
hash: HashAlgorithm::SHA1,
|
||||
algo: PublicKeyInfo::ECDSA
|
||||
};
|
||||
|
||||
const EC224: AlgorithmIdentifier =
|
||||
AlgorithmIdentifier{
|
||||
hash: HashAlgorithm::SHA224,
|
||||
algo: PublicKeyInfo::ECDSA
|
||||
};
|
||||
|
||||
const EC256: AlgorithmIdentifier =
|
||||
AlgorithmIdentifier{
|
||||
hash: HashAlgorithm::SHA256,
|
||||
algo: PublicKeyInfo::ECDSA
|
||||
};
|
||||
|
||||
const EC384: AlgorithmIdentifier =
|
||||
AlgorithmIdentifier{
|
||||
hash: HashAlgorithm::SHA384,
|
||||
algo: PublicKeyInfo::ECDSA
|
||||
};
|
||||
|
||||
const EC512: AlgorithmIdentifier =
|
||||
AlgorithmIdentifier{
|
||||
hash: HashAlgorithm::SHA512,
|
||||
algo: PublicKeyInfo::ECDSA
|
||||
};
|
||||
|
||||
impl Arbitrary for AlgorithmIdentifier {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> AlgorithmIdentifier {
|
||||
let opts = [RSA1, RSA224, RSA256, RSA384, RSA512,
|
||||
DSA1, DSA224, DSA256,
|
||||
EC1, EC224, EC256, EC384, EC512];
|
||||
opts.choose(g).unwrap().clone()
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck!{
|
||||
fn algident_roundtrips(v: AlgorithmIdentifier) -> bool {
|
||||
match encode_algorithm_ident(ASN1Class::Universal, &v) {
|
||||
Err(_) =>
|
||||
false,
|
||||
Ok(block) => {
|
||||
match decode_algorithm_ident(&block) {
|
||||
Err(_) =>
|
||||
false,
|
||||
Ok(v2) =>
|
||||
v == v2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
370
src/x509/atv.rs
Normal file
370
src/x509/atv.rs
Normal file
@@ -0,0 +1,370 @@
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
||||
use std::ops::Index;
|
||||
use x509::error::X509ParseError;
|
||||
pub use x509::name::X520Name;
|
||||
|
||||
/// All of the various bits of information that are encoded within an x.509
|
||||
/// certificate.
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct InfoBlock {
|
||||
pub fields: Vec<AttributeTypeValue>
|
||||
}
|
||||
|
||||
const EMPTY_STRING: &'static str = "";
|
||||
|
||||
impl Index<X520Name> for InfoBlock {
|
||||
type Output = str;
|
||||
|
||||
fn index(&self, name: X520Name) -> &str {
|
||||
for atv in self.fields.iter() {
|
||||
if name == atv.attrtype {
|
||||
return &atv.value;
|
||||
}
|
||||
}
|
||||
&EMPTY_STRING
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for InfoBlock {
|
||||
fn eq(&self, other: &InfoBlock) -> bool {
|
||||
for x in self.fields.iter() {
|
||||
if !other.fields.contains(x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for x in other.fields.iter() {
|
||||
if !self.fields.contains(x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_info_block(x: &ASN1Block)
|
||||
-> Result<InfoBlock,X509ParseError>
|
||||
{
|
||||
// Name ::= CHOICE { -- only one possibility for now --
|
||||
// rdnSequence RDNSequence }
|
||||
//
|
||||
// RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
|
||||
//
|
||||
// RelativeDistinguishedName ::=
|
||||
// SET SIZE (1..MAX) OF AttributeTypeAndValue
|
||||
match x {
|
||||
&ASN1Block::Sequence(_, _, ref items) => {
|
||||
let mut atvs = Vec::new();
|
||||
|
||||
for set in items.iter() {
|
||||
match set {
|
||||
&ASN1Block::Set(_, _, ref setitems) => {
|
||||
for atv in setitems.iter() {
|
||||
let v = decode_attribute_type_value(atv)?;
|
||||
atvs.push(v);
|
||||
}
|
||||
}
|
||||
_ =>
|
||||
return Err(X509ParseError::IllFormedInfoBlock)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(InfoBlock{ fields: atvs })
|
||||
}
|
||||
_ =>
|
||||
Err(X509ParseError::IllFormedInfoBlock)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromASN1 for InfoBlock {
|
||||
type Error = X509ParseError;
|
||||
|
||||
fn from_asn1(v: &[ASN1Block])
|
||||
-> Result<(InfoBlock,&[ASN1Block]),X509ParseError>
|
||||
{
|
||||
match v.split_first() {
|
||||
None =>
|
||||
Err(X509ParseError::NotEnoughData),
|
||||
Some((x, rest)) => {
|
||||
let v = decode_info_block(&x)?;
|
||||
Ok((v, rest))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_info_block(c: ASN1Class, b: &InfoBlock)
|
||||
-> Result<ASN1Block,ASN1EncodeErr>
|
||||
{
|
||||
let mut encoded_fields = Vec::with_capacity(b.fields.len());
|
||||
|
||||
for fld in b.fields.iter() {
|
||||
let val = encode_attribute_type_value(c, fld)?;
|
||||
encoded_fields.push(val);
|
||||
}
|
||||
|
||||
let set = ASN1Block::Set(c, 0, encoded_fields);
|
||||
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![set]))
|
||||
}
|
||||
|
||||
impl ToASN1 for InfoBlock {
|
||||
type Error = ASN1EncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||
{
|
||||
let block = encode_info_block(c, self)?;
|
||||
Ok(vec![block])
|
||||
}
|
||||
}
|
||||
|
||||
/// An attribute within an x.509 key and its associated string value.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct AttributeTypeValue {
|
||||
pub attrtype: X520Name,
|
||||
pub value: String
|
||||
}
|
||||
|
||||
fn decode_attribute_type_value(x: &ASN1Block)
|
||||
-> Result<AttributeTypeValue,X509ParseError>
|
||||
{
|
||||
// AttributeTypeAndValue ::= SEQUENCE {
|
||||
// type AttributeType,
|
||||
// value AttributeValue }
|
||||
match x {
|
||||
&ASN1Block::Sequence(_, _, ref xs) => {
|
||||
let (name, rest) = X520Name::from_asn1(xs)?;
|
||||
match rest.first() {
|
||||
None => Err(X509ParseError::NotEnoughData),
|
||||
Some(ref x) => {
|
||||
let atvstr = get_atv_string(name, x)?;
|
||||
Ok(AttributeTypeValue{
|
||||
attrtype: name,
|
||||
value: atvstr
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
_ =>
|
||||
Err(X509ParseError::IllFormedAttrTypeValue)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromASN1 for AttributeTypeValue {
|
||||
type Error = X509ParseError;
|
||||
|
||||
fn from_asn1(v: &[ASN1Block])
|
||||
-> Result<(AttributeTypeValue,&[ASN1Block]),X509ParseError>
|
||||
{
|
||||
match v.split_first() {
|
||||
None =>
|
||||
Err(X509ParseError::NotEnoughData),
|
||||
Some((x, rest)) => {
|
||||
let v = decode_attribute_type_value(&x)?;
|
||||
Ok((v, rest))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_attribute_type_value(c: ASN1Class, x: &AttributeTypeValue)
|
||||
-> Result<ASN1Block,ASN1EncodeErr>
|
||||
{
|
||||
let mut resvec = x.attrtype.to_asn1_class(c)?;
|
||||
let value = match x.attrtype {
|
||||
X520Name::CountryName =>
|
||||
ASN1Block::PrintableString(c,0,x.value.clone()),
|
||||
X520Name::SerialNumber =>
|
||||
ASN1Block::PrintableString(c,0,x.value.clone()),
|
||||
X520Name::DomainComponent =>
|
||||
ASN1Block::IA5String(c,0,x.value.clone()),
|
||||
X520Name::EmailAddress =>
|
||||
ASN1Block::IA5String(c,0,x.value.clone()),
|
||||
_ =>
|
||||
ASN1Block::UTF8String(c,0,x.value.clone())
|
||||
};
|
||||
resvec.push(value);
|
||||
Ok(ASN1Block::Sequence(c, 0, resvec))
|
||||
}
|
||||
|
||||
impl ToASN1 for AttributeTypeValue {
|
||||
type Error = ASN1EncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||
{
|
||||
let block = encode_attribute_type_value(c, self)?;
|
||||
Ok(vec![block])
|
||||
}
|
||||
}
|
||||
|
||||
fn get_atv_string(n: X520Name, x: &ASN1Block)
|
||||
-> Result<String,X509ParseError>
|
||||
{
|
||||
match n {
|
||||
X520Name::CountryName => {
|
||||
let res = get_printable_val(x)?;
|
||||
if res.len() != 2 {
|
||||
return Err(X509ParseError::IllegalStringValue);
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
X520Name::SerialNumber => get_printable_val(x),
|
||||
X520Name::DomainComponent => get_ia5_val(x),
|
||||
X520Name::EmailAddress => get_ia5_val(x),
|
||||
_ => get_string_val(x),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_string_val(a: &ASN1Block) -> Result<String,X509ParseError>
|
||||
{
|
||||
match a {
|
||||
&ASN1Block::TeletexString(_,_,ref v) => Ok(v.clone()),
|
||||
&ASN1Block::PrintableString(_,_,ref v) => Ok(v.clone()),
|
||||
&ASN1Block::UniversalString(_,_,ref v) => Ok(v.clone()),
|
||||
&ASN1Block::UTF8String(_,_,ref v) => Ok(v.clone()),
|
||||
&ASN1Block::BMPString(_,_,ref v) => Ok(v.clone()),
|
||||
_ =>
|
||||
Err(X509ParseError::IllegalStringValue)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_printable_val(a: &ASN1Block) -> Result<String,X509ParseError>
|
||||
{
|
||||
match a {
|
||||
&ASN1Block::PrintableString(_,_,ref v) => Ok(v.clone()),
|
||||
_ =>
|
||||
Err(X509ParseError::IllegalStringValue)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ia5_val(a: &ASN1Block) -> Result<String,X509ParseError>
|
||||
{
|
||||
match a {
|
||||
&ASN1Block::IA5String(_,_,ref v) => Ok(v.clone()),
|
||||
_ =>
|
||||
Err(X509ParseError::IllegalStringValue)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use rand::Rng;
|
||||
use rand::prelude::SliceRandom;
|
||||
use std::iter::FromIterator;
|
||||
use super::*;
|
||||
|
||||
impl Arbitrary for X520Name {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> X520Name {
|
||||
let names = vec![X520Name::Name,
|
||||
X520Name::Surname,
|
||||
X520Name::GivenName,
|
||||
X520Name::Initials,
|
||||
X520Name::GenerationQualifier,
|
||||
X520Name::CommonName,
|
||||
X520Name::LocalityName,
|
||||
X520Name::StateOrProvinceName,
|
||||
X520Name::OrganizationName,
|
||||
X520Name::OrganizationalUnit,
|
||||
X520Name::Title,
|
||||
X520Name::DNQualifier,
|
||||
X520Name::CountryName,
|
||||
X520Name::SerialNumber,
|
||||
X520Name::Pseudonym,
|
||||
X520Name::DomainComponent,
|
||||
X520Name::EmailAddress];
|
||||
names.choose(g).unwrap().clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for AttributeTypeValue {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> AttributeTypeValue {
|
||||
let name = X520Name::arbitrary(g);
|
||||
let val = match name {
|
||||
X520Name::CountryName => {
|
||||
let mut base = gen_printable(g);
|
||||
base.push('U');
|
||||
base.push('S');
|
||||
base.truncate(2);
|
||||
base
|
||||
}
|
||||
X520Name::SerialNumber => gen_printable(g),
|
||||
X520Name::DomainComponent => gen_ia5(g),
|
||||
X520Name::EmailAddress => gen_ia5(g),
|
||||
_ => gen_utf8(g)
|
||||
};
|
||||
AttributeTypeValue{ attrtype: name, value: val }
|
||||
}
|
||||
}
|
||||
|
||||
const PRINTABLE_CHARS: &'static str =
|
||||
"ABCDEFGHIJKLMOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'()+,-./:=? ";
|
||||
|
||||
fn gen_printable<G: Gen>(g: &mut G) -> String {
|
||||
let count = g.gen_range(0, 384);
|
||||
let mut items = Vec::with_capacity(count);
|
||||
|
||||
for _ in 0..count {
|
||||
let v = PRINTABLE_CHARS.as_bytes().choose(g).unwrap();
|
||||
items.push(*v as char);
|
||||
}
|
||||
String::from_iter(items.iter())
|
||||
}
|
||||
|
||||
fn gen_ia5<G: Gen>(g: &mut G) -> String {
|
||||
let count = g.gen_range(0, 384);
|
||||
let mut items = Vec::with_capacity(count);
|
||||
|
||||
for _ in 0..count {
|
||||
items.push(g.gen::<u8>() as char);
|
||||
}
|
||||
String::from_iter(items.iter())
|
||||
}
|
||||
|
||||
fn gen_utf8<G: Gen>(g: &mut G) -> String {
|
||||
String::arbitrary(g)
|
||||
}
|
||||
|
||||
impl Arbitrary for InfoBlock {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> InfoBlock {
|
||||
let count = g.gen_range(0,12);
|
||||
let mut items = Vec::with_capacity(count);
|
||||
let mut names = Vec::with_capacity(count);
|
||||
|
||||
while items.len() < count {
|
||||
let atv = AttributeTypeValue::arbitrary(g);
|
||||
if !names.contains(&atv.attrtype) {
|
||||
names.push(atv.attrtype);
|
||||
items.push(atv);
|
||||
}
|
||||
}
|
||||
|
||||
InfoBlock{ fields: items }
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn attrtypeval_roundtrips(v: AttributeTypeValue) -> bool {
|
||||
match encode_attribute_type_value(ASN1Class::Universal, &v) {
|
||||
Err(_) => false,
|
||||
Ok(bstr) =>
|
||||
match decode_attribute_type_value(&bstr) {
|
||||
Err(_) => false,
|
||||
Ok(v2) => v == v2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn infoblock_roundtrips(v: InfoBlock) -> bool {
|
||||
match encode_info_block(ASN1Class::Universal, &v) {
|
||||
Err(_) => false,
|
||||
Ok(bstr) =>
|
||||
match decode_info_block(&bstr) {
|
||||
Err(_) => false,
|
||||
Ok(v2) => v == v2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/x509/error.rs
Normal file
53
src/x509/error.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
197
src/x509/misc.rs
Normal file
197
src/x509/misc.rs
Normal file
@@ -0,0 +1,197 @@
|
||||
use num::{BigInt,BigUint,One,ToPrimitive,Zero};
|
||||
use num::bigint::ToBigInt;
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
||||
use x509::error::X509ParseError;
|
||||
|
||||
/// Which version of x.509 certificate this is.
|
||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||
pub enum X509Version { V1, V2, V3 }
|
||||
|
||||
fn decode_version(bs: &[ASN1Block])
|
||||
-> Result<(X509Version,&[ASN1Block]),X509ParseError>
|
||||
{
|
||||
match bs.split_first() {
|
||||
Some((&ASN1Block::Integer(_, _, ref v), rest)) => {
|
||||
match v.to_u8() {
|
||||
Some(0) => Ok((X509Version::V1, rest)),
|
||||
Some(1) => Ok((X509Version::V2, rest)),
|
||||
Some(2) => Ok((X509Version::V3, rest)),
|
||||
_ => Ok((X509Version::V1, &bs))
|
||||
}
|
||||
}
|
||||
_ =>
|
||||
Err(X509ParseError::NotEnoughData)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromASN1 for X509Version {
|
||||
type Error = X509ParseError;
|
||||
|
||||
fn from_asn1(v: &[ASN1Block])
|
||||
-> Result<(X509Version,&[ASN1Block]),X509ParseError>
|
||||
{
|
||||
decode_version(v)
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_version(c: ASN1Class, v: X509Version) -> Vec<ASN1Block> {
|
||||
match v {
|
||||
X509Version::V1 => {
|
||||
let zero: BigInt = Zero::zero();
|
||||
let block = ASN1Block::Integer(c, 0, zero);
|
||||
vec![block]
|
||||
}
|
||||
X509Version::V2 => {
|
||||
let one: BigInt = One::one();
|
||||
let block = ASN1Block::Integer(c, 0, one);
|
||||
vec![block]
|
||||
}
|
||||
X509Version::V3 => {
|
||||
let two: BigInt = BigInt::from(2 as u64);
|
||||
let block = ASN1Block::Integer(c, 0, two);
|
||||
vec![block]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToASN1 for X509Version {
|
||||
type Error = ASN1EncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||
{
|
||||
Ok(encode_version(c, *self))
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/// The serial number for this certificate.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct X509Serial {
|
||||
num: BigUint
|
||||
}
|
||||
|
||||
fn decode_serial(x: &ASN1Block)
|
||||
-> Result<X509Serial,X509ParseError>
|
||||
{
|
||||
match x {
|
||||
&ASN1Block::Integer(_, _, ref v) => {
|
||||
match v.to_biguint() {
|
||||
None =>
|
||||
Err(X509ParseError::IllFormedSerialNumber),
|
||||
Some(n) =>
|
||||
Ok(X509Serial{ num: n })
|
||||
}
|
||||
}
|
||||
_ =>
|
||||
Err(X509ParseError::NoSerialNumber)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromASN1 for X509Serial {
|
||||
type Error = X509ParseError;
|
||||
|
||||
fn from_asn1(v: &[ASN1Block])
|
||||
-> Result<(X509Serial,&[ASN1Block]),X509ParseError>
|
||||
{
|
||||
match v.split_first() {
|
||||
None =>
|
||||
Err(X509ParseError::NoSerialNumber),
|
||||
Some((x, rest)) => {
|
||||
let v = decode_serial(x)?;
|
||||
Ok((v, rest))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SerialEncodeErr { ASN1Error(ASN1EncodeErr), InvalidSerialNumber }
|
||||
|
||||
impl From<ASN1EncodeErr> for SerialEncodeErr {
|
||||
fn from(e: ASN1EncodeErr) -> SerialEncodeErr {
|
||||
SerialEncodeErr::ASN1Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_serial(c: ASN1Class, serial: &X509Serial)
|
||||
-> Result<ASN1Block,SerialEncodeErr>
|
||||
{
|
||||
match serial.num.to_bigint() {
|
||||
None =>
|
||||
Err(SerialEncodeErr::InvalidSerialNumber),
|
||||
Some(n) =>
|
||||
Ok(ASN1Block::Integer(c, 0, n))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToASN1 for X509Serial {
|
||||
type Error = SerialEncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
-> Result<Vec<ASN1Block>,SerialEncodeErr>
|
||||
{
|
||||
let v = encode_serial(c, self)?;
|
||||
Ok(vec![v])
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_signature(x: &ASN1Block)
|
||||
-> Result<Vec<u8>,X509ParseError>
|
||||
{
|
||||
match x {
|
||||
&ASN1Block::BitString(_, _, size, ref sig) if size % 8 == 0 => {
|
||||
Ok(sig.to_vec())
|
||||
}
|
||||
_ =>
|
||||
Err(X509ParseError::SignatureNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use rand::Rng;
|
||||
use rand::distributions::Uniform;
|
||||
use super::*;
|
||||
|
||||
fn check_version_roundtrip(v: X509Version) {
|
||||
let blocks = encode_version(ASN1Class::Universal, v);
|
||||
match decode_version(&blocks) {
|
||||
Err(_) =>
|
||||
assert!(false),
|
||||
Ok((v2,_)) =>
|
||||
assert_eq!(v, v2)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn versions_roundtrip() {
|
||||
check_version_roundtrip(X509Version::V1);
|
||||
check_version_roundtrip(X509Version::V2);
|
||||
check_version_roundtrip(X509Version::V3);
|
||||
}
|
||||
|
||||
impl Arbitrary for X509Serial {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> X509Serial {
|
||||
let count = g.gen_range(0,16);
|
||||
let dist = Uniform::new_inclusive(0,255);
|
||||
let bits = g.sample_iter(&dist).take(count).collect();
|
||||
let val = BigUint::new(bits);
|
||||
X509Serial{ num: val }
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn serial_roundtrips(s: X509Serial) -> bool {
|
||||
match encode_serial(ASN1Class::Universal, &s) {
|
||||
Err(_) => false,
|
||||
Ok(block) =>
|
||||
match decode_serial(&block) {
|
||||
Err(_) => false,
|
||||
Ok(s2) => s == s2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
295
src/x509/mod.rs
Normal file
295
src/x509/mod.rs
Normal file
@@ -0,0 +1,295 @@
|
||||
mod algident;
|
||||
mod atv;
|
||||
mod error;
|
||||
mod misc;
|
||||
mod name;
|
||||
mod publickey;
|
||||
mod validity;
|
||||
|
||||
use dsa::DSAPublic;
|
||||
use ecdsa::ECDSAPublic;
|
||||
use rsa::{SIGNING_HASH_SHA1,SIGNING_HASH_SHA224,SIGNING_HASH_SHA256,SIGNING_HASH_SHA384,SIGNING_HASH_SHA512};
|
||||
use sha::{SHA1,SHA224,SHA256,SHA384,SHA512};
|
||||
use simple_asn1::{ASN1Block,FromASN1,der_decode,from_der};
|
||||
pub use x509::validity::Validity;
|
||||
pub use x509::algident::{AlgorithmIdentifier,HashAlgorithm,PublicKeyInfo};
|
||||
use x509::algident::{decode_algorithm_ident};
|
||||
pub use x509::atv::InfoBlock;
|
||||
use x509::error::X509ParseError;
|
||||
pub use x509::misc::{X509Serial,X509Version};
|
||||
use x509::misc::{decode_signature};
|
||||
pub use x509::publickey::X509PublicKey;
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* The actual certificate data type and methods
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/// The type of an X.509 certificate.
|
||||
pub struct GenericCertificate {
|
||||
pub version: X509Version,
|
||||
pub serial: X509Serial,
|
||||
pub signature_alg: AlgorithmIdentifier,
|
||||
pub issuer: InfoBlock,
|
||||
pub subject: InfoBlock,
|
||||
pub validity: Validity,
|
||||
pub subject_key: X509PublicKey,
|
||||
pub extensions: Vec<()>
|
||||
}
|
||||
|
||||
fn decode_certificate(x: &ASN1Block)
|
||||
-> Result<GenericCertificate,X509ParseError>
|
||||
{
|
||||
//
|
||||
// TBSCertificate ::= SEQUENCE {
|
||||
// version [0] Version DEFAULT v1,
|
||||
// serialNumber CertificateSerialNumber,
|
||||
// signature AlgorithmIdentifier,
|
||||
// issuer Name,
|
||||
// validity Validity,
|
||||
// subject Name,
|
||||
// subjectPublicKeyInfo SubjectPublicKeyInfo,
|
||||
// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
|
||||
// -- If present, version MUST be v2 or v3
|
||||
// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
|
||||
// -- If present, version MUST be v2 or v3
|
||||
// extensions [3] Extensions OPTIONAL
|
||||
// -- If present, version MUST be v3 -- }
|
||||
//
|
||||
match x {
|
||||
&ASN1Block::Sequence(_, _, ref b0) => {
|
||||
let (version, b1) = X509Version::from_asn1(b0)?;
|
||||
let (serial, b2) = X509Serial::from_asn1(b1)?;
|
||||
let (ident, b3) = AlgorithmIdentifier::from_asn1(b2)?;
|
||||
let (issuer, b4) = InfoBlock::from_asn1(b3)?;
|
||||
let (validity, b5) = Validity::from_asn1(b4)?;
|
||||
let (subject, b6) = InfoBlock::from_asn1(b5)?;
|
||||
let (subkey, _ ) = X509PublicKey::from_asn1(b6)?;
|
||||
Ok(GenericCertificate {
|
||||
version: version,
|
||||
serial: serial,
|
||||
signature_alg: ident,
|
||||
issuer: issuer,
|
||||
subject: subject,
|
||||
validity: validity,
|
||||
subject_key: subkey,
|
||||
extensions: vec![]
|
||||
})
|
||||
}
|
||||
_ =>
|
||||
Err(X509ParseError::IllFormedCertificateInfo)
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* X.509 parsing routines
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/// Parse an X.590 certificate in memory into a generic certificate that can
|
||||
/// be used by a program.
|
||||
pub fn parse_x509(buffer: &[u8]) -> Result<GenericCertificate,X509ParseError> {
|
||||
let blocks = from_der(&buffer[..])?;
|
||||
match blocks.first() {
|
||||
None =>
|
||||
Err(X509ParseError::NotEnoughData),
|
||||
Some(&ASN1Block::Sequence(_, _, ref x)) => {
|
||||
let cert = decode_certificate(&x[0])?;
|
||||
let cert_block_start = x[0].offset();
|
||||
let cert_block_end = x[1].offset();
|
||||
let cert_block = &buffer[cert_block_start..cert_block_end];
|
||||
let alginfo = decode_algorithm_ident(&x[1])?;
|
||||
let sig = decode_signature(&x[2])?;
|
||||
check_signature(&alginfo, &cert.subject_key, cert_block, sig)?;
|
||||
Ok(cert)
|
||||
}
|
||||
Some(_) =>
|
||||
Err(X509ParseError::IllFormedEverything)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_signature(alg: &AlgorithmIdentifier,
|
||||
key: &X509PublicKey,
|
||||
block: &[u8],
|
||||
sig: Vec<u8>)
|
||||
-> Result<(),X509ParseError>
|
||||
{
|
||||
match (alg.algo, key) {
|
||||
(PublicKeyInfo::RSA, &X509PublicKey::RSA(ref key)) => {
|
||||
let sighash = match alg.hash {
|
||||
HashAlgorithm::SHA1 => &SIGNING_HASH_SHA1,
|
||||
HashAlgorithm::SHA224 => &SIGNING_HASH_SHA224,
|
||||
HashAlgorithm::SHA256 => &SIGNING_HASH_SHA256,
|
||||
HashAlgorithm::SHA384 => &SIGNING_HASH_SHA384,
|
||||
HashAlgorithm::SHA512 => &SIGNING_HASH_SHA512,
|
||||
};
|
||||
|
||||
if !key.verify(sighash, block, &sig) {
|
||||
return Err(X509ParseError::RSASignatureWrong);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL1024N160(ref key))) => {
|
||||
let dsa_sig = der_decode(&sig)?;
|
||||
match alg.hash {
|
||||
HashAlgorithm::SHA1
|
||||
if key.verify::<SHA1>(block, &dsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA224
|
||||
if key.verify::<SHA224>(block, &dsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &dsa_sig) =>
|
||||
Ok(()),
|
||||
_ =>
|
||||
Err(X509ParseError::InvalidSignatureHash)
|
||||
}
|
||||
}
|
||||
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL2048N224(ref key))) => {
|
||||
let dsa_sig = der_decode(&sig)?;
|
||||
match alg.hash {
|
||||
HashAlgorithm::SHA1
|
||||
if key.verify::<SHA1>(block, &dsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA224
|
||||
if key.verify::<SHA224>(block, &dsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &dsa_sig) =>
|
||||
Ok(()),
|
||||
_ =>
|
||||
Err(X509ParseError::InvalidSignatureHash)
|
||||
}
|
||||
}
|
||||
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL2048N256(ref key))) => {
|
||||
let dsa_sig = der_decode(&sig)?;
|
||||
match alg.hash {
|
||||
HashAlgorithm::SHA1
|
||||
if key.verify::<SHA1>(block, &dsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA224
|
||||
if key.verify::<SHA224>(block, &dsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &dsa_sig) =>
|
||||
Ok(()),
|
||||
_ =>
|
||||
Err(X509ParseError::InvalidSignatureHash)
|
||||
}
|
||||
}
|
||||
(PublicKeyInfo::DSA, &X509PublicKey::DSA(DSAPublic::DSAPublicL3072N256(ref key))) => {
|
||||
let dsa_sig = der_decode(&sig)?;
|
||||
match alg.hash {
|
||||
HashAlgorithm::SHA1
|
||||
if key.verify::<SHA1>(block, &dsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA224
|
||||
if key.verify::<SHA224>(block, &dsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &dsa_sig) =>
|
||||
Ok(()),
|
||||
_ =>
|
||||
Err(X509ParseError::InvalidSignatureHash)
|
||||
}
|
||||
}
|
||||
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P192(ref key))) => {
|
||||
let ecdsa_sig = der_decode(&sig)?;
|
||||
match alg.hash {
|
||||
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA224 if key.verify::<SHA224>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
|
||||
_ =>
|
||||
Err(X509ParseError::InvalidSignatureHash)
|
||||
}
|
||||
}
|
||||
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P224(ref key))) => {
|
||||
let ecdsa_sig = der_decode(&sig)?;
|
||||
match alg.hash {
|
||||
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA224 if key.verify::<SHA224>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
|
||||
_ =>
|
||||
Err(X509ParseError::InvalidSignatureHash)
|
||||
}
|
||||
}
|
||||
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P256(ref key))) => {
|
||||
let ecdsa_sig = der_decode(&sig)?;
|
||||
match alg.hash {
|
||||
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA224 if key.verify::<SHA224>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
|
||||
_ =>
|
||||
Err(X509ParseError::InvalidSignatureHash)
|
||||
}
|
||||
}
|
||||
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P384(ref key))) => {
|
||||
let ecdsa_sig = der_decode(&sig)?;
|
||||
match alg.hash {
|
||||
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA224 if key.verify::<SHA224>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
|
||||
_ =>
|
||||
Err(X509ParseError::InvalidSignatureHash)
|
||||
}
|
||||
}
|
||||
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ECDSAPublic::P521(ref key))) => {
|
||||
let ecdsa_sig = der_decode(&sig)?;
|
||||
match alg.hash {
|
||||
HashAlgorithm::SHA1 if key.verify::<SHA1>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA224 if key.verify::<SHA224>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA256 if key.verify::<SHA256>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA384 if key.verify::<SHA384>(block, &ecdsa_sig) => Ok(()),
|
||||
HashAlgorithm::SHA512 if key.verify::<SHA512>(block, &ecdsa_sig) => Ok(()),
|
||||
_ =>
|
||||
Err(X509ParseError::InvalidSignatureHash)
|
||||
}
|
||||
}
|
||||
_ =>
|
||||
Err(X509ParseError::InvalidSignatureData)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Testing is for winners!
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use super::*;
|
||||
|
||||
fn can_parse(f: &str) -> Result<GenericCertificate,X509ParseError> {
|
||||
let mut fd = File::open(f).unwrap();
|
||||
let mut buffer = Vec::new();
|
||||
let _amt = fd.read_to_end(&mut buffer);
|
||||
parse_x509(&buffer)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rsa_tests() {
|
||||
assert!(can_parse("testdata/x509/rsa2048-1.der").is_ok());
|
||||
assert!(can_parse("testdata/x509/rsa2048-2.der").is_ok());
|
||||
assert!(can_parse("testdata/x509/rsa4096-1.der").is_ok());
|
||||
assert!(can_parse("testdata/x509/rsa4096-2.der").is_ok());
|
||||
assert!(can_parse("testdata/x509/rsa4096-3.der").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dsa_tests() {
|
||||
assert!(can_parse("testdata/x509/dsa2048-1.der").is_ok());
|
||||
assert!(can_parse("testdata/x509/dsa2048-2.der").is_ok());
|
||||
assert!(can_parse("testdata/x509/dsa3072-1.der").is_ok());
|
||||
assert!(can_parse("testdata/x509/dsa3072-2.der").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ecc_tests() {
|
||||
assert!(can_parse("testdata/x509/ec384-1.der").is_ok());
|
||||
assert!(can_parse("testdata/x509/ec384-2.der").is_ok());
|
||||
assert!(can_parse("testdata/x509/ec384-3.der").is_ok());
|
||||
}
|
||||
}
|
||||
138
src/x509/name.rs
Normal file
138
src/x509/name.rs
Normal file
@@ -0,0 +1,138 @@
|
||||
use num::BigUint;
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
|
||||
use x509::error::X509ParseError;
|
||||
|
||||
/// One of the various attributes that can be encoded within an x.509 name. To
|
||||
/// see one of these paired with its value, consider `AttributeTypeValue`.
|
||||
#[derive(Copy,Clone,Debug,Eq,Hash,PartialEq)]
|
||||
pub enum X520Name {
|
||||
Name, Surname, GivenName, Initials, GenerationQualifier, CommonName,
|
||||
LocalityName, StateOrProvinceName, OrganizationName, OrganizationalUnit,
|
||||
Title, DNQualifier, CountryName, SerialNumber, Pseudonym, DomainComponent,
|
||||
EmailAddress
|
||||
}
|
||||
|
||||
impl FromASN1 for X520Name {
|
||||
type Error = X509ParseError;
|
||||
|
||||
fn from_asn1(v: &[ASN1Block])
|
||||
-> Result<(X520Name,&[ASN1Block]),X509ParseError>
|
||||
{
|
||||
match v.split_first() {
|
||||
None =>
|
||||
Err(X509ParseError::NotEnoughData),
|
||||
Some((x,rest)) => {
|
||||
let name = decode_name(&x)?;
|
||||
Ok((name,rest))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_name(val: &ASN1Block)
|
||||
-> Result<X520Name,X509ParseError>
|
||||
{
|
||||
match val {
|
||||
&ASN1Block::ObjectIdentifier(_, _, ref oid) => {
|
||||
if oid == oid!(2,5,4,41) {return Ok(X520Name::Name) }
|
||||
if oid == oid!(2,5,4,4) {return Ok(X520Name::Surname) }
|
||||
if oid == oid!(2,5,4,42) {return Ok(X520Name::GivenName) }
|
||||
if oid == oid!(2,5,4,43) {return Ok(X520Name::Initials) }
|
||||
if oid == oid!(2,5,4,44) {return Ok(X520Name::GenerationQualifier)}
|
||||
if oid == oid!(2,5,4,3) {return Ok(X520Name::CommonName) }
|
||||
if oid == oid!(2,5,4,7) {return Ok(X520Name::LocalityName) }
|
||||
if oid == oid!(2,5,4,8) {return Ok(X520Name::StateOrProvinceName)}
|
||||
if oid == oid!(2,5,4,10) {return Ok(X520Name::OrganizationName) }
|
||||
if oid == oid!(2,5,4,11) {return Ok(X520Name::OrganizationalUnit) }
|
||||
if oid == oid!(2,5,4,12) {return Ok(X520Name::Title) }
|
||||
if oid == oid!(2,5,4,46) {return Ok(X520Name::DNQualifier) }
|
||||
if oid == oid!(2,5,4,6) {return Ok(X520Name::CountryName) }
|
||||
if oid == oid!(2,5,4,5) {return Ok(X520Name::SerialNumber) }
|
||||
if oid == oid!(2,5,4,65) {return Ok(X520Name::Pseudonym) }
|
||||
if oid == oid!(0,9,2342,19200300,100,1,25) {
|
||||
return Ok(X520Name::DomainComponent);
|
||||
}
|
||||
if oid == oid!(1,2,840,113549,1,9,1) {
|
||||
return Ok(X520Name::EmailAddress);
|
||||
}
|
||||
Err(X509ParseError::IllFormedName)
|
||||
}
|
||||
_ =>
|
||||
Err(X509ParseError::IllFormedName)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToASN1 for X520Name {
|
||||
type Error = ASN1EncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||
{
|
||||
let block = encode_name(c, *self);
|
||||
Ok(vec![block])
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_name(class: ASN1Class, name: X520Name)
|
||||
-> ASN1Block
|
||||
{
|
||||
let oid = match name {
|
||||
X520Name::Name => oid!(2,5,4,41),
|
||||
X520Name::Surname => oid!(2,5,4,4),
|
||||
X520Name::GivenName => oid!(2,5,4,42),
|
||||
X520Name::Initials => oid!(2,5,4,43),
|
||||
X520Name::GenerationQualifier => oid!(2,5,4,44),
|
||||
X520Name::CommonName => oid!(2,5,4,3),
|
||||
X520Name::LocalityName => oid!(2,5,4,7),
|
||||
X520Name::StateOrProvinceName => oid!(2,5,4,8),
|
||||
X520Name::OrganizationName => oid!(2,5,4,10),
|
||||
X520Name::OrganizationalUnit => oid!(2,5,4,11),
|
||||
X520Name::Title => oid!(2,5,4,12),
|
||||
X520Name::DNQualifier => oid!(2,5,4,46),
|
||||
X520Name::CountryName => oid!(2,5,4,6),
|
||||
X520Name::SerialNumber => oid!(2,5,4,5),
|
||||
X520Name::Pseudonym => oid!(2,5,4,65),
|
||||
X520Name::DomainComponent => oid!(0,9,2342,19200300,100,1,25),
|
||||
X520Name::EmailAddress => oid!(1,2,840,113549,1,9,1)
|
||||
};
|
||||
|
||||
ASN1Block::ObjectIdentifier(class, 0, oid)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn encdec_test(n: X520Name) {
|
||||
let block = encode_name(ASN1Class::Universal, n);
|
||||
let vec = vec![block];
|
||||
match X520Name::from_asn1(&vec) {
|
||||
Err(_) =>
|
||||
assert!(false),
|
||||
Ok((m, _)) =>
|
||||
assert_eq!(n,m)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn name_encoding_roundtrips() {
|
||||
encdec_test(X520Name::Name);
|
||||
encdec_test(X520Name::Surname);
|
||||
encdec_test(X520Name::GivenName);
|
||||
encdec_test(X520Name::Initials);
|
||||
encdec_test(X520Name::GenerationQualifier);
|
||||
encdec_test(X520Name::CommonName);
|
||||
encdec_test(X520Name::LocalityName);
|
||||
encdec_test(X520Name::StateOrProvinceName);
|
||||
encdec_test(X520Name::OrganizationName);
|
||||
encdec_test(X520Name::OrganizationalUnit);
|
||||
encdec_test(X520Name::Title);
|
||||
encdec_test(X520Name::DNQualifier);
|
||||
encdec_test(X520Name::CountryName);
|
||||
encdec_test(X520Name::SerialNumber);
|
||||
encdec_test(X520Name::Pseudonym);
|
||||
encdec_test(X520Name::DomainComponent);
|
||||
encdec_test(X520Name::EmailAddress);
|
||||
}
|
||||
}
|
||||
|
||||
330
src/x509/publickey.rs
Normal file
330
src/x509/publickey.rs
Normal file
@@ -0,0 +1,330 @@
|
||||
use cryptonum::unsigned::{U3072,U2048,U1024,U256,U192};
|
||||
use dsa::{DSAPublic,DSAPublicKey,DSAParameters};
|
||||
use dsa::{L3072N256,L2048N256,L2048N224,L1024N160};
|
||||
use ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPublicKey};
|
||||
use ecdsa::{P192,P224,P256,P384,P521};
|
||||
use num::BigUint;
|
||||
use rsa::RSAPublic;
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1,
|
||||
der_decode,der_encode,from_der};
|
||||
use utils::TranslateNums;
|
||||
use x509::error::X509ParseError;
|
||||
|
||||
/// A general type that includes all the supported public key types that we
|
||||
/// could read in an x.509 certificate.
|
||||
pub enum X509PublicKey {
|
||||
DSA(DSAPublic),
|
||||
RSA(RSAPublic),
|
||||
ECDSA(ECDSAPublic)
|
||||
}
|
||||
|
||||
impl From<X509PublicKey> for Option<DSAPublic> {
|
||||
fn from(x: X509PublicKey) -> Option<DSAPublic> {
|
||||
match x {
|
||||
X509PublicKey::DSA(x) => Some(x),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<X509PublicKey> for Option<RSAPublic> {
|
||||
fn from(x: X509PublicKey) -> Option<RSAPublic> {
|
||||
match x {
|
||||
X509PublicKey::RSA(x) => Some(x),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<X509PublicKey> for Option<ECDSAPublic> {
|
||||
fn from(x: X509PublicKey) -> Option<ECDSAPublic> {
|
||||
match x {
|
||||
X509PublicKey::ECDSA(x) => Some(x),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum X509EncodeErr {
|
||||
ASN1EncodeErr(ASN1EncodeErr),
|
||||
ECDSAEncodeErr(ECDSAEncodeErr)
|
||||
}
|
||||
|
||||
impl From<ASN1EncodeErr> for X509EncodeErr {
|
||||
fn from(x: ASN1EncodeErr) -> X509EncodeErr {
|
||||
X509EncodeErr::ASN1EncodeErr(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ECDSAEncodeErr> for X509EncodeErr {
|
||||
fn from(x: ECDSAEncodeErr) -> X509EncodeErr {
|
||||
X509EncodeErr::ECDSAEncodeErr(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToASN1 for X509PublicKey {
|
||||
type Error = X509EncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class) -> Result<Vec<ASN1Block>,X509EncodeErr> {
|
||||
let block = match self {
|
||||
X509PublicKey::RSA(x) => encode_rsa_key(c, x)?,
|
||||
X509PublicKey::DSA(x) => encode_dsa_key(c, x)?,
|
||||
X509PublicKey::ECDSA(x) => encode_ecdsa_key(c, x)?,
|
||||
};
|
||||
Ok(vec![block])
|
||||
}
|
||||
}
|
||||
|
||||
impl FromASN1 for X509PublicKey {
|
||||
type Error = X509ParseError;
|
||||
|
||||
fn from_asn1(v: &[ASN1Block]) -> Result<(X509PublicKey, &[ASN1Block]), Self::Error>
|
||||
{
|
||||
let (block, rest) = v.split_first().ok_or(X509ParseError::NotEnoughData)?;
|
||||
|
||||
// SubjectPublicKeyInfo ::= SEQUENCE {
|
||||
// algorithm AlgorithmIdentifier,
|
||||
// subjectPublicKey BIT STRING }
|
||||
if let &ASN1Block::Sequence(_, _, ref info) = block {
|
||||
let (id, malginfo) = strip_algident(&info[0])?;
|
||||
|
||||
if id == oid!(1,2,840,113549,1,1,1) {
|
||||
let key = decode_rsa_key(&info[1])?;
|
||||
return Ok((X509PublicKey::RSA(key), rest));
|
||||
}
|
||||
|
||||
if id == oid!(1,2,840,10040,4,1) {
|
||||
if let Some(alginfo) = malginfo {
|
||||
let key = decode_dsa_key(alginfo, &info[1])?;
|
||||
return Ok((X509PublicKey::DSA(key), rest));
|
||||
}
|
||||
}
|
||||
|
||||
if id == oid!(1,2,840,10045,2,1) {
|
||||
if let Some(alginfo) = malginfo {
|
||||
let key = decode_ecdsa_key(alginfo, &info[1..])?;
|
||||
return Ok((X509PublicKey::ECDSA(key), rest));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(X509ParseError::IllFormedKey)
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// RSA Public Key encoding / decoding
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
fn encode_rsa_key(c: ASN1Class, x: &RSAPublic) -> Result<ASN1Block,ASN1EncodeErr>
|
||||
{
|
||||
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,113549,1,1,1));
|
||||
let bstr = der_encode(x)?;
|
||||
let objkey = ASN1Block::BitString(c, 0, bstr.len() * 8, bstr);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![objoid, objkey]))
|
||||
}
|
||||
|
||||
fn decode_rsa_key(x: &ASN1Block) -> Result<RSAPublic,X509ParseError>
|
||||
{
|
||||
if let &ASN1Block::BitString(_, _, _, ref bstr) = x {
|
||||
der_decode(bstr).map_err(|x| X509ParseError::RSAError(x))
|
||||
} else {
|
||||
Err(X509ParseError::NotEnoughData)
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// DSA Public Key encoding / decoding
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
fn encode_dsa_key(c: ASN1Class, x: &DSAPublic) -> Result<ASN1Block,ASN1EncodeErr>
|
||||
{
|
||||
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,10040,4,1));
|
||||
let (mut objparams, bstr) = match x {
|
||||
DSAPublic::DSAPublicL1024N160(x) => (x.params.to_asn1_class(c)?, der_encode(x)?),
|
||||
DSAPublic::DSAPublicL2048N224(x) => (x.params.to_asn1_class(c)?, der_encode(x)?),
|
||||
DSAPublic::DSAPublicL2048N256(x) => (x.params.to_asn1_class(c)?, der_encode(x)?),
|
||||
DSAPublic::DSAPublicL3072N256(x) => (x.params.to_asn1_class(c)?, der_encode(x)?)
|
||||
};
|
||||
objparams.insert(0, objoid);
|
||||
let headinfo = ASN1Block::Sequence(c, 0, objparams);
|
||||
let objkey = ASN1Block::BitString(c, 0, bstr.len() * 8, bstr);
|
||||
Ok(ASN1Block::Sequence(c, 0, vec![headinfo, objkey]))
|
||||
}
|
||||
|
||||
fn decode_dsa_key(info: ASN1Block, key: &ASN1Block) -> Result<DSAPublic,X509ParseError>
|
||||
{
|
||||
if let ASN1Block::Sequence(_, _, pqg) = info {
|
||||
if pqg.len() != 3 { return Err(X509ParseError::InvalidDSAInfo); }
|
||||
|
||||
let puint = decode_biguint(&pqg[0])?;
|
||||
let guint = decode_biguint(&pqg[1])?;
|
||||
let quint = decode_biguint(&pqg[2])?;
|
||||
|
||||
if puint.bits() > 2048 {
|
||||
let p = U3072::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||
let q = U3072::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||
let g = U256::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||
let params = L3072N256::new(p, q, g);
|
||||
|
||||
if let ASN1Block::BitString(_, _, _, ybstr) = key {
|
||||
let blocks = from_der(ybstr)?;
|
||||
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
||||
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||
let y = U3072::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||
let key = DSAPublicKey::<L3072N256>::new(params, y);
|
||||
let reskey = DSAPublic::DSAPublicL3072N256(key);
|
||||
return Ok(reskey);
|
||||
}
|
||||
}
|
||||
|
||||
return Err(X509ParseError::InvalidDSAKey)
|
||||
}
|
||||
|
||||
if puint.bits() > 1024 {
|
||||
if guint.bits() > 224 {
|
||||
let p = U2048::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||
let q = U2048::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||
let g = U256::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||
let params = L2048N256::new(p, q, g);
|
||||
|
||||
if let ASN1Block::BitString(_, _, _, ybstr) = key {
|
||||
let blocks = from_der(ybstr)?;
|
||||
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
||||
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||
let y = U2048::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||
let key = DSAPublicKey::<L2048N256>::new(params, y);
|
||||
let reskey = DSAPublic::DSAPublicL2048N256(key);
|
||||
return Ok(reskey);
|
||||
}
|
||||
}
|
||||
|
||||
return Err(X509ParseError::InvalidDSAKey)
|
||||
} else {
|
||||
let p = U2048::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||
let q = U2048::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||
let g = U256::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||
let params = L2048N224::new(p, q, g);
|
||||
|
||||
if let ASN1Block::BitString(_, _, _, ybstr) = key {
|
||||
let blocks = from_der(ybstr)?;
|
||||
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
||||
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||
let y = U2048::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||
let key = DSAPublicKey::<L2048N224>::new(params, y);
|
||||
let reskey = DSAPublic::DSAPublicL2048N224(key);
|
||||
return Ok(reskey);
|
||||
}
|
||||
}
|
||||
|
||||
return Err(X509ParseError::InvalidDSAKey)
|
||||
}
|
||||
}
|
||||
|
||||
let p = U1024::from_num(&puint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||
let q = U1024::from_num(&quint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||
let g = U192::from_num(&guint).ok_or(X509ParseError::InvalidDSAInfo)?;
|
||||
let params = L1024N160::new(p, q, g);
|
||||
|
||||
if let ASN1Block::BitString(_, _, _, ybstr) = key {
|
||||
let blocks = from_der(ybstr)?;
|
||||
let (iblk,_) = blocks.split_first().ok_or(X509ParseError::InvalidDSAKey)?;
|
||||
if let ASN1Block::Integer(_,_,ynum) = iblk {
|
||||
let y = U1024::from_num(ynum).ok_or(X509ParseError::InvalidDSAKey)?;
|
||||
let key = DSAPublicKey::<L1024N160>::new(params, y);
|
||||
let reskey = DSAPublic::DSAPublicL1024N160(key);
|
||||
return Ok(reskey);
|
||||
}
|
||||
}
|
||||
|
||||
return Err(X509ParseError::InvalidDSAKey)
|
||||
}
|
||||
|
||||
Err(X509ParseError::InvalidDSAInfo)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// ECDSA Public Key encoding
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
fn encode_ecdsa_key(c: ASN1Class, x: &ECDSAPublic) -> Result<ASN1Block,ECDSAEncodeErr>
|
||||
{
|
||||
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,10045,2,1));
|
||||
let (base_curve_oid, mut keyvec) = match x {
|
||||
ECDSAPublic::P192(k) => (oid!(1,2,840,10045,3,1,1), k.to_asn1_class(c)?),
|
||||
ECDSAPublic::P224(k) => (oid!(1,3,132,0,33), k.to_asn1_class(c)?),
|
||||
ECDSAPublic::P256(k) => (oid!(1,2,840,10045,3,1,7), k.to_asn1_class(c)?),
|
||||
ECDSAPublic::P384(k) => (oid!(1,3,132,0,34), k.to_asn1_class(c)?),
|
||||
ECDSAPublic::P521(k) => (oid!(1,3,132,0,35), k.to_asn1_class(c)?),
|
||||
};
|
||||
let curve_oid = ASN1Block::ObjectIdentifier(c, 0, base_curve_oid);
|
||||
let header = ASN1Block::Sequence(c, 0, vec![objoid, curve_oid]);
|
||||
keyvec.insert(0, header);
|
||||
Ok(ASN1Block::Sequence(c, 0, keyvec))
|
||||
}
|
||||
|
||||
fn decode_ecdsa_key(info: ASN1Block, keybls: &[ASN1Block]) -> Result<ECDSAPublic,X509ParseError>
|
||||
{
|
||||
if let ASN1Block::ObjectIdentifier(_, _, oid) = info {
|
||||
if oid == oid!(1,2,840,10045,3,1,1) {
|
||||
let (res, _) = ECCPublicKey::<P192>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::P192(res));
|
||||
}
|
||||
|
||||
if oid == oid!(1,3,132,0,33) {
|
||||
let (res, _) = ECCPublicKey::<P224>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::P224(res));
|
||||
}
|
||||
|
||||
if oid == oid!(1,2,840,10045,3,1,7) {
|
||||
let (res, _) = ECCPublicKey::<P256>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::P256(res));
|
||||
}
|
||||
|
||||
if oid == oid!(1,3,132,0,34) {
|
||||
let (res, _) = ECCPublicKey::<P384>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::P384(res));
|
||||
}
|
||||
|
||||
if oid == oid!(1,3,132,0,35) {
|
||||
let (res, _) = ECCPublicKey::<P521>::from_asn1(keybls)?;
|
||||
return Ok(ECDSAPublic::P521(res));
|
||||
}
|
||||
}
|
||||
|
||||
Err(X509ParseError::UnknownEllipticCurve)
|
||||
}
|
||||
|
||||
fn strip_algident(block: &ASN1Block)
|
||||
-> Result<(OID, Option<ASN1Block>),X509ParseError>
|
||||
{
|
||||
match block {
|
||||
&ASN1Block::ObjectIdentifier(_, _, ref oid) => {
|
||||
Ok((oid.clone(), None))
|
||||
}
|
||||
&ASN1Block::Sequence(_, _, ref items) => {
|
||||
let (oid, _) = strip_algident(&items[0])?;
|
||||
Ok((oid, Some(items[1].clone())))
|
||||
}
|
||||
_ => Err(X509ParseError::IllFormedAlgoInfo)
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_biguint(b: &ASN1Block) -> Result<BigUint,X509ParseError> {
|
||||
match b {
|
||||
&ASN1Block::Integer(_, _, ref v) => {
|
||||
match v.to_biguint() {
|
||||
Some(sn) => Ok(sn),
|
||||
_ => Err(X509ParseError::InvalidDSAInfo)
|
||||
}
|
||||
}
|
||||
_ =>
|
||||
Err(X509ParseError::InvalidDSAInfo)
|
||||
}
|
||||
}
|
||||
119
src/x509/validity.rs
Normal file
119
src/x509/validity.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
use chrono::{DateTime,Utc};
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,ToASN1};
|
||||
use x509::error::X509ParseError;
|
||||
|
||||
/// The range of dates in which this certificate is valid.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct Validity {
|
||||
pub not_before: DateTime<Utc>,
|
||||
pub not_after: DateTime<Utc>
|
||||
}
|
||||
|
||||
fn decode_validity_data(bs: &ASN1Block) -> Result<Validity,X509ParseError> {
|
||||
// Validity ::= SEQUENCE {
|
||||
// notBefore Time,
|
||||
// notAfter Time }
|
||||
match bs {
|
||||
&ASN1Block::Sequence(_, _, ref valxs) => {
|
||||
if valxs.len() != 2 {
|
||||
return Err(X509ParseError::IllFormedValidity);
|
||||
}
|
||||
let nb = get_time(&valxs[0])?;
|
||||
let na = get_time(&valxs[1])?;
|
||||
Ok(Validity{ not_before: nb, not_after: na })
|
||||
}
|
||||
_ =>
|
||||
Err(X509ParseError::IllFormedValidity)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromASN1 for Validity {
|
||||
type Error = X509ParseError;
|
||||
|
||||
fn from_asn1(v: &[ASN1Block])
|
||||
-> Result<(Validity,&[ASN1Block]),X509ParseError>
|
||||
{
|
||||
match v.split_first() {
|
||||
None =>
|
||||
Err(X509ParseError::NotEnoughData),
|
||||
Some((x, rest)) => {
|
||||
let v = decode_validity_data(&x)?;
|
||||
Ok((v, rest))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_validity_data(c: ASN1Class, v: &Validity) -> ASN1Block {
|
||||
let mut vs = Vec::with_capacity(2);
|
||||
vs.push(ASN1Block::GeneralizedTime(c, 0, v.not_before));
|
||||
vs.push(ASN1Block::GeneralizedTime(c, 0, v.not_after));
|
||||
ASN1Block::Sequence(c, 0, vs)
|
||||
}
|
||||
|
||||
impl ToASN1 for Validity {
|
||||
type Error = ASN1EncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||
{
|
||||
let block = encode_validity_data(c, self);
|
||||
Ok(vec![block])
|
||||
}
|
||||
}
|
||||
|
||||
fn get_time(b: &ASN1Block) -> Result<DateTime<Utc>, X509ParseError> {
|
||||
match b {
|
||||
&ASN1Block::UTCTime(_, _, v) => Ok(v.clone()),
|
||||
&ASN1Block::GeneralizedTime(_, _, v) => Ok(v.clone()),
|
||||
_ =>
|
||||
Err(X509ParseError::IllFormedValidity)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use chrono::TimeZone;
|
||||
use chrono::offset::LocalResult;
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use rand::Rng;
|
||||
use super::*;
|
||||
|
||||
fn arbitrary_date<G: Gen>(g: &mut G) -> DateTime<Utc> {
|
||||
loop {
|
||||
let y = g.gen_range(1900,3000);
|
||||
let mo = g.gen_range(0,12);
|
||||
let d = g.gen_range(0,31);
|
||||
let h = g.gen_range(0,24);
|
||||
let mi = g.gen_range(0,60);
|
||||
let s = g.gen_range(0,60);
|
||||
match Utc.ymd_opt(y,mo,d).and_hms_opt(h,mi,s) {
|
||||
LocalResult::None =>
|
||||
continue,
|
||||
LocalResult::Single(x) =>
|
||||
return x,
|
||||
LocalResult::Ambiguous(x,_) =>
|
||||
return x
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for Validity {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> Validity {
|
||||
Validity {
|
||||
not_before: arbitrary_date(g),
|
||||
not_after: arbitrary_date(g)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn validity_roundtrips(v: Validity) -> bool {
|
||||
let bstr = encode_validity_data(ASN1Class::Universal, &v);
|
||||
match decode_validity_data(&bstr) {
|
||||
Err(_) => false,
|
||||
Ok(v2) => v == v2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
test-generator/.gitignore
vendored
Normal file
2
test-generator/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
dist/
|
||||
dist-newstyle/
|
||||
84
test-generator/DSA.hs
Normal file
84
test-generator/DSA.hs
Normal file
@@ -0,0 +1,84 @@
|
||||
{-# LANGUAGE PackageImports #-}
|
||||
module DSA(dsaTasks)
|
||||
where
|
||||
|
||||
import Codec.Crypto.DSA.Pure
|
||||
import Crypto.Hash(Digest, SHA256, hash)
|
||||
import "cryptonite" Crypto.Random(DRG(..),getRandomBytes,withDRG)
|
||||
import Data.ByteArray(convert)
|
||||
import qualified Data.ByteString as BS
|
||||
import Data.ByteString.Lazy(ByteString)
|
||||
import qualified Data.ByteString.Lazy as BSL
|
||||
import qualified Data.Map.Strict as Map
|
||||
import Math(showX,showBin)
|
||||
import Task(Task(..),liftTest)
|
||||
import Utils(HashAlg(..),generateHash,showHash)
|
||||
|
||||
dsaSizes :: [(ParameterSizes, Int)]
|
||||
dsaSizes = [(L1024_N160, 400),
|
||||
(L2048_N224, 100),
|
||||
(L2048_N256, 50),
|
||||
(L3072_N256, 25)]
|
||||
|
||||
dsaTasks :: [Task]
|
||||
dsaTasks = concatMap generateTask dsaSizes
|
||||
|
||||
generateTask :: (ParameterSizes, Int) -> [Task]
|
||||
generateTask (s, c) = [signTest s c]
|
||||
|
||||
showParam :: ParameterSizes -> String
|
||||
showParam L1024_N160 = "L1024N160"
|
||||
showParam L2048_N224 = "L2048N224"
|
||||
showParam L2048_N256 = "L2048N256"
|
||||
showParam L3072_N256 = "L3072N256"
|
||||
|
||||
signTest :: ParameterSizes -> Int -> Task
|
||||
signTest sz cnt = Task {
|
||||
taskName = "DSA " ++ show sz ++ " signing",
|
||||
taskFile = "../testdata/dsa/sign" ++ showParam sz ++ ".test",
|
||||
taskTest = liftTest go,
|
||||
taskCount = cnt
|
||||
}
|
||||
where
|
||||
go (memory, drg0) =
|
||||
case generateProbablePrimes sz drg0 sha256 Nothing of
|
||||
Left _ -> goAdvance memory drg0
|
||||
Right (p, q, _, drg1) ->
|
||||
case generateUnverifiableGenerator p q of
|
||||
Nothing -> goAdvance memory drg1
|
||||
Just g ->
|
||||
let params = Params p g q
|
||||
in case generateKeyPairWithParams params drg1 of
|
||||
Left _ -> goAdvance memory drg1
|
||||
Right (pub, priv, drg2) ->
|
||||
let (msg, drg3) = withDRG drg2 $ getRandomBytes =<< ((fromIntegral . BS.head) `fmap` getRandomBytes 1)
|
||||
(hashf, drg4) = withDRG drg3 generateHash
|
||||
in case signMessage' (translateHash hashf) kViaRFC6979 drg4 priv (BSL.fromStrict msg) of
|
||||
Left _ ->
|
||||
go (memory, drg4)
|
||||
Right (sig, drg5) ->
|
||||
let res = Map.fromList [("p", showX p),
|
||||
("q", showX q),
|
||||
("g", showX g),
|
||||
("y", showX (public_y pub)),
|
||||
("x", showX (private_x priv)),
|
||||
("m", showBin msg),
|
||||
("h", showHash hashf),
|
||||
("r", showX (sign_r sig)),
|
||||
("s", showX (sign_s sig))]
|
||||
in (res, p, (memory, drg5))
|
||||
--
|
||||
goAdvance memory drg0 =
|
||||
let (bstr, drg1) = randomBytesGenerate 37 drg0
|
||||
in BS.null bstr `seq` go (memory, drg1)
|
||||
--
|
||||
translateHash Sha224 = Codec.Crypto.DSA.Pure.SHA224
|
||||
translateHash Sha256 = Codec.Crypto.DSA.Pure.SHA256
|
||||
translateHash Sha384 = Codec.Crypto.DSA.Pure.SHA384
|
||||
translateHash Sha512 = Codec.Crypto.DSA.Pure.SHA512
|
||||
|
||||
sha256 :: ByteString -> ByteString
|
||||
sha256 = BSL.fromStrict . convert' . hash . BSL.toStrict
|
||||
where
|
||||
convert' :: Digest SHA256 -> BS.ByteString
|
||||
convert' = convert
|
||||
50
test-generator/Database.hs
Normal file
50
test-generator/Database.hs
Normal 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
|
||||
193
test-generator/ECDSATesting.hs
Normal file
193
test-generator/ECDSATesting.hs
Normal 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(..),liftTest)
|
||||
import Utils(HashAlg(..),generateHash,runHash,showHash)
|
||||
|
||||
curves :: [(String, Curve)]
|
||||
curves = [("P192", getCurveByName SEC_p192r1),
|
||||
("P224", getCurveByName SEC_p224r1),
|
||||
("P256", getCurveByName SEC_p256r1),
|
||||
("P384", getCurveByName SEC_p384r1),
|
||||
("P521", getCurveByName SEC_p521r1)]
|
||||
|
||||
negateTest :: String -> Curve -> Task
|
||||
negateTest name curve = Task {
|
||||
taskName = name ++ " point negation",
|
||||
taskFile = "../testdata/ecc/negate/" ++ name ++ ".test",
|
||||
taskTest = liftTest go,
|
||||
taskCount = 1000
|
||||
}
|
||||
where
|
||||
go (memory0, drg) =
|
||||
let (scalar, drg') = withDRG drg (scalarGenerate curve)
|
||||
point = pointBaseMul curve scalar
|
||||
dbl = pointNegate curve point
|
||||
in case (point, dbl) of
|
||||
(PointO, _) -> go (memory0, drg')
|
||||
(_, PointO) -> go (memory0, drg')
|
||||
(Point basex basey, Point dblx dbly) ->
|
||||
let res = Map.fromList [("x", showX basex), ("y", showX basey),
|
||||
("a", showX dblx), ("b", showX dbly)]
|
||||
in (res, scalar, (memory0, drg'))
|
||||
|
||||
doubleTest :: String -> Curve -> Task
|
||||
doubleTest name curve = Task {
|
||||
taskName = name ++ " point doubling",
|
||||
taskFile = "../testdata/ecc/double/" ++ name ++ ".test",
|
||||
taskTest = liftTest go,
|
||||
taskCount = 1000
|
||||
}
|
||||
where
|
||||
go (memory0, drg) =
|
||||
let (scalar, drg') = withDRG drg (scalarGenerate curve)
|
||||
point = pointBaseMul curve scalar
|
||||
dbl = pointDouble curve point
|
||||
in case (point, dbl) of
|
||||
(PointO, _) -> go (memory0, drg')
|
||||
(_, PointO) -> go (memory0, drg')
|
||||
(Point basex basey, Point dblx dbly) ->
|
||||
let res = Map.fromList [("x", showX basex), ("y", showX basey),
|
||||
("a", showX dblx), ("b", showX dbly)]
|
||||
in (res, scalar, (memory0, drg'))
|
||||
|
||||
addTest :: String -> Curve -> Task
|
||||
addTest name curve = Task {
|
||||
taskName = name ++ " point addition",
|
||||
taskFile = "../testdata/ecc/add/" ++ name ++ ".test",
|
||||
taskTest = liftTest go,
|
||||
taskCount = 1000
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
let (scalar1, drg1) = withDRG drg0 (scalarGenerate curve)
|
||||
(scalar2, drg2) = withDRG drg1 (scalarGenerate curve)
|
||||
point1 = pointBaseMul curve scalar1
|
||||
point2 = pointBaseMul curve scalar2
|
||||
pointr = pointAdd curve point1 point2
|
||||
in case (point1, point2, pointr) of
|
||||
(Point x1 y1, Point x2 y2, Point xr yr) ->
|
||||
let res = Map.fromList [("x", showX x1), ("y", showX y1),
|
||||
("u", showX x2), ("v", showX y2),
|
||||
("a", showX xr), ("b", showX yr)]
|
||||
in (res, scalar1, (memory0, drg2))
|
||||
_ ->
|
||||
go (memory0, drg2)
|
||||
|
||||
scaleTest :: String -> Curve -> Task
|
||||
scaleTest name curve = Task {
|
||||
taskName = name ++ " point scaling",
|
||||
taskFile = "../testdata/ecc/scale/" ++ name ++ ".test",
|
||||
taskTest = liftTest go,
|
||||
taskCount = 1000
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
let (scalar0, drg1) = withDRG drg0 (scalarGenerate curve)
|
||||
(scalar1, drg2) = withDRG drg1 (scalarGenerate curve)
|
||||
(negbs, drg3) = randomBytesGenerate 1 drg2
|
||||
[negbyte] = S.unpack negbs
|
||||
k = if odd negbyte then scalar1 else -scalar1
|
||||
point = pointBaseMul curve scalar0
|
||||
respnt = pointMul curve k point
|
||||
in case (point, respnt) of
|
||||
(PointO, _) -> go (memory0, drg3)
|
||||
(_, PointO) -> go (memory0, drg3)
|
||||
(Point basex basey, Point resx resy) ->
|
||||
let res = Map.fromList [("x", showX basex), ("y", showX basey),
|
||||
("k", showX k),
|
||||
("a", showX resx), ("b", showX resy)]
|
||||
in (res, scalar0, (memory0, drg3))
|
||||
|
||||
addScaleTest :: String -> Curve -> Task
|
||||
addScaleTest name curve = Task {
|
||||
taskName = name ++ " point addition of two scalings",
|
||||
taskFile = "../testdata/ecc/add_scale2/" ++ name ++ ".test",
|
||||
taskTest = liftTest go,
|
||||
taskCount = 1000
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
let (scalar1, drg1) = withDRG drg0 (scalarGenerate curve)
|
||||
(scalar2, drg2) = withDRG drg1 (scalarGenerate curve)
|
||||
(n, drg3) = withDRG drg2 (scalarGenerate curve)
|
||||
(m, drg4) = withDRG drg3 (scalarGenerate curve)
|
||||
point1 = pointBaseMul curve scalar1
|
||||
point2 = pointBaseMul curve scalar2
|
||||
pointr = pointAddTwoMuls curve n point1 m point2
|
||||
in case (point1, point2, pointr) of
|
||||
(Point x1 y1, Point x2 y2, Point xr yr) ->
|
||||
let res = Map.fromList [("x", showX x1), ("y", showX y1),
|
||||
("p", showX x2), ("q", showX y2),
|
||||
("n", showX n), ("m", showX m),
|
||||
("r", showX xr), ("s", showX yr)]
|
||||
in (res, scalar1, (memory0, drg4))
|
||||
_ ->
|
||||
go (memory0, drg4)
|
||||
|
||||
|
||||
signTest :: String -> Curve -> Task
|
||||
signTest name curve = Task {
|
||||
taskName = name ++ " curve signing",
|
||||
taskFile = "../testdata/ecc/sign/" ++ name ++ ".test",
|
||||
taskTest = liftTest go,
|
||||
taskCount = 1000
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
let ((pub, priv), drg1) = withDRG drg0 (generate curve)
|
||||
(msg, drg2) = withDRG drg1 $ do x <- generateBetween 0 256
|
||||
getRandomBytes (fromIntegral x)
|
||||
(hash, drg3) = withDRG drg2 generateHash
|
||||
n = ecc_n (common_curve curve)
|
||||
PrivateKey _ d = priv
|
||||
kStream = generateKStream hash msg d n (curveSizeBits curve)
|
||||
findGoodK stream =
|
||||
case stream of
|
||||
[] ->
|
||||
go (memory0, drg3)
|
||||
(k : restks) ->
|
||||
case signWith' k priv hash msg of
|
||||
Nothing ->
|
||||
findGoodK restks
|
||||
Just sig ->
|
||||
let PublicKey _ (Point x y) = pub
|
||||
res = Map.fromList [("d", showX d), ("k", showX k),
|
||||
("x", showX x), ("y", showX y),
|
||||
("m", showBin msg), ("h", showHash hash),
|
||||
("n", showBin (runHash hash msg)),
|
||||
("r", showX (sign_r sig)),
|
||||
("s", showX (sign_s sig))]
|
||||
in (res, d, (memory0, drg3))
|
||||
in findGoodK kStream
|
||||
|
||||
signWith' :: Integer -> PrivateKey -> HashAlg -> S.ByteString -> Maybe Signature
|
||||
signWith' k priv Sha224 msg = signWith k priv SHA224 msg
|
||||
signWith' k priv Sha256 msg = signWith k priv SHA256 msg
|
||||
signWith' k priv Sha384 msg = signWith k priv SHA384 msg
|
||||
signWith' k priv Sha512 msg = signWith k priv SHA512 msg
|
||||
|
||||
generateTasks :: (String, Curve) -> [Task]
|
||||
generateTasks (name, curve) = [negateTest name curve,
|
||||
doubleTest name curve,
|
||||
addTest name curve,
|
||||
scaleTest name curve,
|
||||
addScaleTest name curve,
|
||||
signTest name curve]
|
||||
|
||||
ecdsaTasks :: [Task]
|
||||
ecdsaTasks = concatMap generateTasks curves
|
||||
735
test-generator/ED25519.hs
Normal file
735
test-generator/ED25519.hs
Normal file
@@ -0,0 +1,735 @@
|
||||
{-# LANGUAGE PackageImports #-}
|
||||
module ED25519(ed25519Tasks)
|
||||
where
|
||||
|
||||
import Control.Monad(unless)
|
||||
import Crypto.Error(CryptoFailable(CryptoPassed))
|
||||
import "crypto-api" Crypto.Random(SystemRandom)
|
||||
import "cryptonite" Crypto.Random(getRandomBytes,withDRG)
|
||||
import Crypto.PubKey.Ed25519
|
||||
import Data.ByteArray(convert)
|
||||
import Data.ByteString(ByteString,pack,useAsCString)
|
||||
import qualified Data.ByteString as BS
|
||||
import Data.Int(Int32)
|
||||
import qualified Data.Map.Strict as Map
|
||||
import Data.Word(Word8,Word32,Word64)
|
||||
import ED25519.PrecompPoints
|
||||
import Foreign.C.Types(CChar)
|
||||
import Foreign.Marshal.Alloc(alloca)
|
||||
import Foreign.Marshal.Array(allocaArray,peekArray,pokeArray)
|
||||
import Foreign.Ptr(Ptr,castPtr)
|
||||
import Foreign.Storable(Storable(..))
|
||||
import Math(showX,showBin)
|
||||
import Task(Task(..))
|
||||
|
||||
cTEST_COUNT :: Int
|
||||
cTEST_COUNT = 1000
|
||||
|
||||
ed25519Tasks :: [Task]
|
||||
ed25519Tasks = [ loadTests, byteTests, addsubTests, mulTests,
|
||||
squaringTests, inversionTests, negateTests,
|
||||
cmovTests, isTests, square2Tests,
|
||||
pow22523Tests, fbvTests, conversionTests,
|
||||
ptDoubleTests, maddsubTests, ptAddSubTests,
|
||||
scalarMultBaseTests, slideTests, scalarMultTests,
|
||||
reduceTests, muladdTests, pubPrivTests,
|
||||
signTest ]
|
||||
|
||||
loadTests :: Task
|
||||
loadTests = Task {
|
||||
taskName = "ed25519 byte loading",
|
||||
taskFile = "../testdata/ed25519/load.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
do let (bytes, drg1) = withDRG drg0 (getRandomBytes 4)
|
||||
res3 <- useAsCString bytes (\ptr -> load_3 ptr)
|
||||
res4 <- useAsCString bytes (\ptr -> load_4 ptr)
|
||||
let res = Map.fromList [("x", showBin bytes), ("a", showX res3), ("b", showX res4)]
|
||||
return (res, fromIntegral res4, (memory0, drg1))
|
||||
|
||||
byteTests :: Task
|
||||
byteTests = Task {
|
||||
taskName = "ed25519 byte / element conversion",
|
||||
taskFile = "../testdata/ed25519/bytes.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomPackedBytes drg0 $ \ ptra drg1 ->
|
||||
alloca $ \ ptrc ->
|
||||
allocaArray 32 $ \ rptr ->
|
||||
do clearSpace ptrc
|
||||
pokeArray (rptr :: Ptr Word8) (replicate 32 0)
|
||||
fe_frombytes ptrc ptra
|
||||
b <- convertFE ptrc
|
||||
fe_tobytes (castPtr rptr) ptrc
|
||||
start <- peek ptra
|
||||
end <- peek (castPtr rptr)
|
||||
unless (start == end) $
|
||||
fail "field element tobytes/frombytes doesn't round trip"
|
||||
bytes' <- pack `fmap` peekArray 32 (castPtr ptra :: Ptr Word8)
|
||||
let res = Map.fromList [("a", showBin bytes'),
|
||||
("b", showBin b)]
|
||||
return (res, toNumber b, (memory0, drg1))
|
||||
|
||||
addsubTests :: Task
|
||||
addsubTests = Task {
|
||||
taskName = "ed25519 addition/subtraction tests",
|
||||
taskFile = "../testdata/ed25519/addsub.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomElement drg0 $ \ ptrel1 drg1 ->
|
||||
randomElement drg1 $ \ ptrel2 drg2 ->
|
||||
alloca $ \ ptrc ->
|
||||
alloca $ \ ptrd ->
|
||||
do fe_add ptrc ptrel1 ptrel2
|
||||
fe_sub ptrd ptrel1 ptrel2
|
||||
[a, b, c, d] <- mapM convertFE [ptrel1, ptrel2, ptrc, ptrd]
|
||||
let res = Map.fromList [("a", showBin a),
|
||||
("b", showBin b),
|
||||
("c", showBin c),
|
||||
("d", showBin d)]
|
||||
return (res, toNumber c, (memory0, drg2))
|
||||
|
||||
mulTests :: Task
|
||||
mulTests = Task {
|
||||
taskName = "ed25519 multiplication tests",
|
||||
taskFile = "../testdata/ed25519/mul.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomElement drg0 $ \ ptrel1 drg1 ->
|
||||
randomElement drg1 $ \ ptrel2 drg2 ->
|
||||
alloca $ \ ptrc ->
|
||||
do fe_mul ptrc ptrel1 ptrel2
|
||||
[a, b, c] <- mapM convertFE [ptrel1, ptrel2, ptrc]
|
||||
let res = Map.fromList [("a", showBin a),
|
||||
("b", showBin b),
|
||||
("c", showBin c)]
|
||||
return (res, toNumber c, (memory0, drg2))
|
||||
|
||||
squaringTests :: Task
|
||||
squaringTests = Task {
|
||||
taskName = "ed25519 squaring tests",
|
||||
taskFile = "../testdata/ed25519/square.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomElement drg0 $ \ ptrel drg1 ->
|
||||
alloca $ \ ptrc ->
|
||||
do fe_square ptrc ptrel
|
||||
[a, c] <- mapM convertFE [ptrel, ptrc]
|
||||
let res = Map.fromList [("a", showBin a),
|
||||
("c", showBin c)]
|
||||
return (res, toNumber c, (memory0, drg1))
|
||||
|
||||
inversionTests :: Task
|
||||
inversionTests = Task {
|
||||
taskName = "ed25519 inversion tests",
|
||||
taskFile = "../testdata/ed25519/invert.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomElement drg0 $ \ ptrel drg1 ->
|
||||
alloca $ \ ptrc ->
|
||||
do fe_invert ptrc ptrel
|
||||
a <- convertFE ptrel
|
||||
c <- convertFE ptrc
|
||||
let res = Map.fromList [("a", showBin a),
|
||||
("c", showBin c)]
|
||||
return (res, toNumber a, (memory0, drg1))
|
||||
|
||||
negateTests :: Task
|
||||
negateTests = Task {
|
||||
taskName = "ed25519 negation tests",
|
||||
taskFile = "../testdata/ed25519/negate.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomElement drg0 $ \ ptrel drg1 ->
|
||||
alloca $ \ ptrc ->
|
||||
do fe_negate ptrc ptrel
|
||||
a <- convertFE ptrel
|
||||
c <- convertFE ptrc
|
||||
let res = Map.fromList [("a", showBin a),
|
||||
("c", showBin c)]
|
||||
return (res, toNumber a, (memory0, drg1))
|
||||
|
||||
cmovTests :: Task
|
||||
cmovTests = Task {
|
||||
taskName = "ed25519 conditional mov tests",
|
||||
taskFile = "../testdata/ed25519/cmov.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomElement drg0 $ \ aelptr drg1 ->
|
||||
do let (bbytes, drg2) = withDRG drg1 (getRandomBytes 1)
|
||||
b = even (BS.head bbytes)
|
||||
bvalLib = if b then 0 else 1
|
||||
bvalOut = if b then 0 else 0xFFFFFF :: Word32
|
||||
alloca $ \ celptr ->
|
||||
do clearSpace celptr
|
||||
fe_cmov celptr aelptr bvalLib
|
||||
a <- convertFE aelptr
|
||||
c <- convertFE celptr
|
||||
let res = Map.fromList [("a", showBin a),
|
||||
("b", showX bvalOut),
|
||||
("c", showBin c)]
|
||||
return (res, toNumber a, (memory0, drg2))
|
||||
|
||||
isTests :: Task
|
||||
isTests = Task {
|
||||
taskName = "ed25519 predicate tests",
|
||||
taskFile = "../testdata/ed25519/istests.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomElement drg0 $ \ aptr drg1 ->
|
||||
do a <- convertFE aptr
|
||||
z <- fe_isnonzero aptr
|
||||
n <- fe_isnegative aptr
|
||||
let res = Map.fromList [("a", showBin a),
|
||||
("z", showX (if z == 0 then 0 :: Word32 else 0xFFFFFF)),
|
||||
("n", showX (if n == 0 then 0 :: Word32 else 0xFFFFFF))]
|
||||
return (res, toNumber a, (memory0, drg1))
|
||||
|
||||
square2Tests :: Task
|
||||
square2Tests = Task {
|
||||
taskName = "ed25519 square2 tests",
|
||||
taskFile = "../testdata/ed25519/square2.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomElement drg0 $ \ aptr drg1 ->
|
||||
alloca $ \ cptr ->
|
||||
do clearSpace cptr
|
||||
fe_square2 cptr aptr
|
||||
a <- convertFE aptr
|
||||
c <- convertFE cptr
|
||||
let res = Map.fromList [("a", showBin a), ("c", showBin c)]
|
||||
return (res, toNumber a, (memory0, drg1))
|
||||
|
||||
pow22523Tests :: Task
|
||||
pow22523Tests = Task {
|
||||
taskName = "ed25519 pow22523 tests",
|
||||
taskFile = "../testdata/ed25519/pow22523.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomElement drg0 $ \ aptr drg1 ->
|
||||
alloca $ \ cptr ->
|
||||
do clearSpace cptr
|
||||
fe_pow22523 cptr aptr
|
||||
a <- convertFE aptr
|
||||
c <- convertFE cptr
|
||||
let res = Map.fromList [("a", showBin a), ("c", showBin c)]
|
||||
return (res, toNumber a, (memory0, drg1))
|
||||
|
||||
fbvTests :: Task
|
||||
fbvTests = Task {
|
||||
taskName = "ed25519 from bytes (vartime) tests",
|
||||
taskFile = "../testdata/ed25519/fbv.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
do let (abytes, drg1) = withDRG drg0 (getRandomBytes 32)
|
||||
useAsCString abytes $ \ aptr ->
|
||||
do let aptr' = castPtr aptr :: Ptr PackedBytes
|
||||
curve25519_scalar_mask aptr'
|
||||
alloca $ \ dest ->
|
||||
do clearSpace dest
|
||||
ok <- point_frombytes dest aptr'
|
||||
a <- pack `fmap` peekArray 32 (castPtr aptr)
|
||||
c <- pack `fmap` peekArray (4 * 10 * 4) (castPtr dest)
|
||||
let c' | ok = c
|
||||
| otherwise = BS.empty
|
||||
let res = Map.fromList [("a", showBin a),
|
||||
("b", showBin c'),
|
||||
("c", showBin c)]
|
||||
return (res, if ok then (toNumber abytes) else 0, (memory0, drg1))
|
||||
|
||||
conversionTests :: Task
|
||||
conversionTests = Task {
|
||||
taskName = "ed25519 point form conversion tests",
|
||||
taskFile = "../testdata/ed25519/conversion.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomPoint3 drg0 $ \ ptr3 drg' ->
|
||||
alloca $ \ ptrCached ->
|
||||
alloca $ \ ptr2 ->
|
||||
alloca $ \ ptrP1P1 ->
|
||||
alloca $ \ ptr2' ->
|
||||
alloca $ \ ptr3' ->
|
||||
do clearSpace ptrCached
|
||||
clearSpace ptr2
|
||||
clearSpace ptrP1P1
|
||||
clearSpace ptr2'
|
||||
clearSpace ptr3'
|
||||
p3_to_cached ptrCached ptr3
|
||||
ge_p3_to_p2 ptr2 ptr3
|
||||
ge_p3_dbl ptrP1P1 ptr3
|
||||
p1p1_to_p2 ptr2' ptrP1P1
|
||||
p1p1_to_p3 ptr3' ptrP1P1
|
||||
a <- convertPoint ptr3
|
||||
c <- convertPoint ptrCached
|
||||
t <- convertPoint ptr2
|
||||
o <- convertPoint ptrP1P1
|
||||
d <- convertPoint ptr2'
|
||||
b <- convertPoint ptr3'
|
||||
let res = Map.fromList [("a", showBin a), ("c", showBin c),
|
||||
("t", showBin t), ("o", showBin o),
|
||||
("d", showBin d), ("b", showBin b)]
|
||||
return (res, toNumber a, (memory0, drg'))
|
||||
|
||||
ptDoubleTests :: Task
|
||||
ptDoubleTests = Task {
|
||||
taskName = "ed25519 point doubling tests",
|
||||
taskFile = "../testdata/ed25519/pt_double.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomPoint3 drg0 $ \ ptra drg1 ->
|
||||
randomPoint2 drg1 $ \ ptrc drg2 ->
|
||||
alloca $ \ ptrb ->
|
||||
alloca $ \ ptrd ->
|
||||
do clearSpace ptrb
|
||||
clearSpace ptrd
|
||||
ge_p3_dbl ptrb ptra
|
||||
ge_p2_dbl ptrd ptrc
|
||||
a <- convertPoint ptra
|
||||
b <- convertPoint ptrb
|
||||
c <- convertPoint ptrc
|
||||
d <- convertPoint ptrd
|
||||
let res = Map.fromList [("a", showBin a), ("b", showBin b),
|
||||
("c", showBin c), ("d", showBin d)]
|
||||
return (res, toNumber a, (memory0, drg2))
|
||||
|
||||
maddsubTests :: Task
|
||||
maddsubTests = Task {
|
||||
taskName = "ed25519 point madd/msub tests",
|
||||
taskFile = "../testdata/ed25519/maddsub.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomPoint3 drg0 $ \ ptra drg1 ->
|
||||
randomPointPrecomp drg1 $ \ ptrc drg2 ->
|
||||
alloca $ \ ptrb ->
|
||||
alloca $ \ ptrd ->
|
||||
do clearSpace ptrb
|
||||
clearSpace ptrd
|
||||
ge_madd ptrb ptra ptrc
|
||||
ge_msub ptrd ptra ptrc
|
||||
a <- convertPoint ptra
|
||||
b <- convertPoint ptrb
|
||||
c <- convertPoint ptrc
|
||||
d <- convertPoint ptrd
|
||||
let res = Map.fromList [("a", showBin a), ("b", showBin b),
|
||||
("c", showBin c), ("d", showBin d)]
|
||||
return (res, toNumber a, (memory0, drg2))
|
||||
|
||||
ptAddSubTests :: Task
|
||||
ptAddSubTests = Task {
|
||||
taskName = "ed25519 point add/sub tests",
|
||||
taskFile = "../testdata/ed25519/ptaddsub.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomPoint3 drg0 $ \ ptra drg1 ->
|
||||
randomPointCached drg1 $ \ ptrc drg2 ->
|
||||
alloca $ \ ptrb ->
|
||||
alloca $ \ ptrd ->
|
||||
do clearSpace ptrb
|
||||
clearSpace ptrd
|
||||
ge_add ptrb ptra ptrc
|
||||
ge_sub ptrd ptra ptrc
|
||||
a <- convertPoint ptra
|
||||
b <- convertPoint ptrb
|
||||
c <- convertPoint ptrc
|
||||
d <- convertPoint ptrd
|
||||
let res = Map.fromList [("a", showBin a), ("b", showBin b),
|
||||
("c", showBin c), ("d", showBin d)]
|
||||
return (res, toNumber a, (memory0, drg2))
|
||||
|
||||
scalarMultBaseTests :: Task
|
||||
scalarMultBaseTests = Task {
|
||||
taskName = "ed25519 point add/sub tests",
|
||||
taskFile = "../testdata/ed25519/scalar_mult.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomPackedBytes drg0 $ \ ptra drg1 ->
|
||||
alloca $ \ ptrb ->
|
||||
do clearSpace ptrb
|
||||
x25519_ge_scalarmult_base ptrb ptra
|
||||
PB abytes <- peek ptra
|
||||
let a = pack abytes
|
||||
b <- convertPoint ptrb
|
||||
let res = Map.fromList [("a", showBin a), ("b", showBin b)]
|
||||
return (res, toNumber a, (memory0, drg1))
|
||||
|
||||
slideTests :: Task
|
||||
slideTests = Task {
|
||||
taskName = "ed25519 slide helper function tests",
|
||||
taskFile = "../testdata/ed25519/slide.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomPackedBytes drg0 $ \ ptra drg1 ->
|
||||
allocaArray 256 $ \ ptrb ->
|
||||
do pokeArray ptrb (replicate 256 0)
|
||||
slide ptrb ptra
|
||||
a <- pack `fmap` peekArray 32 (castPtr ptra)
|
||||
b <- pack `fmap` peekArray 356 ptrb
|
||||
let res = Map.fromList [("a", showBin a), ("b", showBin b)]
|
||||
return (res, toNumber a, (memory0, drg1))
|
||||
|
||||
scalarMultTests :: Task
|
||||
scalarMultTests = Task {
|
||||
taskName = "ed25519 point general scalar multiplication tests",
|
||||
taskFile = "../testdata/ed25519/scalar_mult_gen.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomPackedBytes drg0 $ \ ptra drg1 ->
|
||||
randomPoint3 drg1 $ \ ptrb drg2 ->
|
||||
randomPackedBytes drg2 $ \ ptrc drg3 ->
|
||||
alloca $ \ ptrd ->
|
||||
do clearSpace ptrd
|
||||
ge_double_scalarmult_vartime ptrd ptra ptrb ptrc
|
||||
PB abytes <- peek ptra
|
||||
let a = pack abytes
|
||||
b <- convertPoint ptrb
|
||||
PB cbytes <- peek ptrc
|
||||
let c = pack cbytes
|
||||
d <- convertPoint ptrd
|
||||
let res = Map.fromList [("a", showBin a), ("b", showBin b),
|
||||
("c", showBin c), ("d", showBin d)]
|
||||
return (res, toNumber a, (memory0, drg3))
|
||||
|
||||
reduceTests :: Task
|
||||
reduceTests = Task {
|
||||
taskName = "ed25519 reduce tests",
|
||||
taskFile = "../testdata/ed25519/reduce.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
do let (a, drg1) = withDRG drg0 (getRandomBytes 64)
|
||||
allocaArray 64 $ \ target ->
|
||||
do pokeArray target (BS.unpack a)
|
||||
sc_reduce target
|
||||
b <- pack `fmap` peekArray 32 target
|
||||
let res = Map.fromList [("a", showBin a), ("b", showBin b)]
|
||||
return (res, toNumber a, (memory0, drg1))
|
||||
|
||||
muladdTests :: Task
|
||||
muladdTests = Task {
|
||||
taskName = "ed25519 multiplication+addition tests",
|
||||
taskFile = "../testdata/ed25519/muladd.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomPackedBytes drg0 $ \ ptra drg1 ->
|
||||
randomPackedBytes drg1 $ \ ptrb drg2 ->
|
||||
randomPackedBytes drg2 $ \ ptrc drg3 ->
|
||||
alloca $ \ ptrd ->
|
||||
do clearSpace ptrd
|
||||
sc_muladd ptrd ptra ptrb ptrc
|
||||
a <- repackBytes ptra
|
||||
b <- repackBytes ptrb
|
||||
c <- repackBytes ptrc
|
||||
d <- repackBytes ptrd
|
||||
let res = Map.fromList [("a", showBin a), ("b", showBin b),
|
||||
("c", showBin c), ("d", showBin d)]
|
||||
return (res, toNumber a, (memory0, drg3))
|
||||
|
||||
pubPrivTests :: Task
|
||||
pubPrivTests = Task {
|
||||
taskName = "ed25519 private -> public conversion tests",
|
||||
taskFile = "../testdata/ed25519/pubfrompriv.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
randomPackedBytes drg0 $ \ ptra drg1 ->
|
||||
alloca $ \ ptrb ->
|
||||
do clearSpace ptrb
|
||||
public_from_private ptrb ptra
|
||||
a <- repackBytes ptra
|
||||
b <- repackBytes ptrb
|
||||
let res = Map.fromList [("a", showBin a), ("b", showBin b)]
|
||||
return (res, toNumber a, (memory0, drg1))
|
||||
|
||||
signTest :: Task
|
||||
signTest = Task {
|
||||
taskName = "ed25519 signing tests",
|
||||
taskFile = "../testdata/ed25519/sign.test",
|
||||
taskTest = go,
|
||||
taskCount = cTEST_COUNT
|
||||
}
|
||||
where
|
||||
go (memory0, drg0) =
|
||||
let (priv, drg1) = withDRG drg0 generateSecretKey
|
||||
(msg, drg2) = withDRG drg1 $ getRandomBytes =<< ((fromIntegral . BS.head) `fmap` getRandomBytes 1)
|
||||
pub = toPublic priv
|
||||
privBytes = convert priv
|
||||
pubBytes = convert pub
|
||||
sig = convert (sign priv pub msg)
|
||||
res = Map.fromList [("u", showBin pubBytes), ("r", showBin privBytes),
|
||||
("m", showBin msg), ("s", showBin sig)]
|
||||
in return (res, toNumber privBytes, (memory0, drg2))
|
||||
|
||||
|
||||
data PackedBytes = PB [Word8]
|
||||
deriving (Eq)
|
||||
|
||||
instance Storable PackedBytes where
|
||||
sizeOf _ = 32
|
||||
alignment _ = 8
|
||||
peek p = PB `fmap` peekArray 32 (castPtr p)
|
||||
poke p (PB v) = pokeArray (castPtr p) v
|
||||
|
||||
randomPackedBytes :: SystemRandom -> (Ptr PackedBytes -> SystemRandom -> IO a) -> IO a
|
||||
randomPackedBytes drg action =
|
||||
do let (bytes, drg') = withDRG drg (getRandomBytes 32)
|
||||
useAsCString bytes $ \ ptr ->
|
||||
do let ptr' = castPtr ptr :: Ptr PackedBytes
|
||||
curve25519_scalar_mask ptr'
|
||||
action ptr' drg'
|
||||
|
||||
repackBytes :: Ptr PackedBytes -> IO ByteString
|
||||
repackBytes ptr =
|
||||
do PB xs <- peek ptr
|
||||
return (pack xs)
|
||||
|
||||
data Element = FE [Int32]
|
||||
|
||||
instance Storable Element where
|
||||
sizeOf _ = 10 * sizeOf (undefined :: Int32)
|
||||
alignment _ = 8
|
||||
peek p = FE `fmap` peekArray 10 (castPtr p)
|
||||
poke p (FE v) = pokeArray (castPtr p) v
|
||||
|
||||
randomElement :: SystemRandom -> (Ptr Element -> SystemRandom -> IO a) -> IO a
|
||||
randomElement drg action =
|
||||
randomPackedBytes drg $ \ ptrpb drg' -> alloca $ \ ptrel ->
|
||||
do clearSpace ptrel
|
||||
fe_frombytes ptrel ptrpb
|
||||
action ptrel drg'
|
||||
|
||||
data Point3 = P3 [Element]
|
||||
|
||||
instance Storable Point3 where
|
||||
sizeOf _ = 4 * sizeOf (undefined :: Element)
|
||||
alignment _ = 8
|
||||
peek p = P3 `fmap` peekArray 4 (castPtr p)
|
||||
poke p (P3 v) = pokeArray (castPtr p) v
|
||||
|
||||
randomPoint3 :: SystemRandom -> (Ptr Point3 -> SystemRandom -> IO a) -> IO a
|
||||
randomPoint3 drg0 action = allocaArray (4 * 10) (go drg0)
|
||||
where
|
||||
go drg dest =
|
||||
do mres <- randomPackedBytes drg $ \ aptr drg' ->
|
||||
do clearSpace dest
|
||||
worked <- point_frombytes dest aptr
|
||||
if worked
|
||||
then Right `fmap` action (castPtr dest) drg'
|
||||
else return (Left drg')
|
||||
case mres of
|
||||
Right x -> return x
|
||||
Left drg' -> go drg' dest
|
||||
|
||||
data PointCached = PC [Element]
|
||||
|
||||
instance Storable PointCached where
|
||||
sizeOf _ = 4 * sizeOf (undefined :: Element)
|
||||
alignment _ = 8
|
||||
peek p = PC `fmap` peekArray 4 (castPtr p)
|
||||
poke p (PC v) = pokeArray (castPtr p) v
|
||||
|
||||
randomPointCached :: SystemRandom -> (Ptr PointCached -> SystemRandom -> IO a) -> IO a
|
||||
randomPointCached drg action =
|
||||
randomPoint3 drg $ \ ptr drg' ->
|
||||
allocaArray (4 * 10) $ \ dest ->
|
||||
do pokeArray (castPtr dest :: Ptr Int32) (replicate (4 * 10) 0)
|
||||
p3_to_cached dest ptr
|
||||
action (castPtr dest) drg'
|
||||
|
||||
data Point2 = P2 [Element]
|
||||
|
||||
instance Storable Point2 where
|
||||
sizeOf _ = 3 * sizeOf (undefined :: Element)
|
||||
alignment _ = 8
|
||||
peek p = P2 `fmap` peekArray 3 (castPtr p)
|
||||
poke p (P2 v) = pokeArray (castPtr p) v
|
||||
|
||||
randomPoint2 :: SystemRandom -> (Ptr Point2 -> SystemRandom -> IO a) -> IO a
|
||||
randomPoint2 drg action =
|
||||
randomPoint3 drg $ \ ptr3 drg' ->
|
||||
allocaArray (3 * 10) $ \ dest ->
|
||||
do pokeArray (castPtr dest :: Ptr Int32) (replicate (3 * 10) 0)
|
||||
ge_p3_to_p2 dest ptr3
|
||||
action (castPtr dest) drg'
|
||||
|
||||
data PointP1P1 = P1P1 [Element]
|
||||
|
||||
instance Storable PointP1P1 where
|
||||
sizeOf _ = 4 * sizeOf (undefined :: Element)
|
||||
alignment _ = 8
|
||||
peek p = P1P1 `fmap` peekArray 4 (castPtr p)
|
||||
poke p (P1P1 v) = pokeArray (castPtr p) v
|
||||
|
||||
_randomPointP1P1 :: SystemRandom -> (Ptr PointP1P1 -> SystemRandom -> IO a) -> IO a
|
||||
_randomPointP1P1 drg action =
|
||||
randomPoint3 drg $ \ ptr3 drg' ->
|
||||
allocaArray (4 * 10) $ \ dest ->
|
||||
do pokeArray (castPtr dest :: Ptr Int32) (replicate (4 * 10) 0)
|
||||
ge_p3_dbl dest ptr3
|
||||
action (castPtr dest) drg'
|
||||
|
||||
data PointPrecomp = PP [Element]
|
||||
|
||||
instance Storable PointPrecomp where
|
||||
sizeOf _ = 4 * sizeOf (undefined :: Element)
|
||||
alignment _ = 8
|
||||
peek p = PP `fmap` peekArray 4 (castPtr p)
|
||||
poke p (PP v) = pokeArray (castPtr p) v
|
||||
|
||||
randomPointPrecomp :: SystemRandom -> (Ptr PointPrecomp -> SystemRandom -> IO a) -> IO a
|
||||
randomPointPrecomp drg action =
|
||||
do let ([a,b,c,d], drg') = withDRG drg (BS.unpack `fmap` getRandomBytes 4)
|
||||
mix = fromIntegral a + fromIntegral b + fromIntegral c + fromIntegral d
|
||||
idx = mix `mod` (length precompPoints)
|
||||
val = PP (map FE (precompPoints !! idx))
|
||||
alloca $ \ ptr ->
|
||||
do poke ptr val
|
||||
action ptr drg'
|
||||
|
||||
clearSpace :: Storable a => Ptr a -> IO ()
|
||||
clearSpace x = meh x undefined
|
||||
where
|
||||
meh :: Storable a => Ptr a -> a -> IO ()
|
||||
meh p v = pokeArray (castPtr p) (replicate (sizeOf v) (0 :: Word8))
|
||||
|
||||
convertFE :: Ptr Element -> IO ByteString
|
||||
convertFE feptr = pack `fmap` peekArray 40 (castPtr feptr :: Ptr Word8)
|
||||
|
||||
convertPoint :: Storable a => Ptr a -> IO ByteString
|
||||
convertPoint x = meh x undefined
|
||||
where
|
||||
meh :: Storable a => Ptr a -> a -> IO ByteString
|
||||
meh p v = pack `fmap` peekArray (sizeOf v) (castPtr p)
|
||||
|
||||
toNumber :: ByteString -> Integer
|
||||
toNumber = BS.foldr (\ x a -> fromIntegral x + a) 0
|
||||
|
||||
foreign import ccall unsafe "load_3"
|
||||
load_3 :: Ptr CChar -> IO Word64
|
||||
foreign import ccall unsafe "load_4"
|
||||
load_4 :: Ptr CChar -> IO Word64
|
||||
foreign import ccall unsafe "GFp_curve25519_scalar_mask"
|
||||
curve25519_scalar_mask :: Ptr PackedBytes -> IO ()
|
||||
foreign import ccall unsafe "fe_frombytes"
|
||||
fe_frombytes :: Ptr Element -> Ptr PackedBytes -> IO ()
|
||||
foreign import ccall unsafe "GFp_fe_tobytes"
|
||||
fe_tobytes :: Ptr PackedBytes -> Ptr Element -> IO ()
|
||||
foreign import ccall unsafe "fe_add"
|
||||
fe_add :: Ptr Element -> Ptr Element -> Ptr Element -> IO ()
|
||||
foreign import ccall unsafe "fe_sub"
|
||||
fe_sub :: Ptr Element -> Ptr Element -> Ptr Element -> IO ()
|
||||
foreign import ccall unsafe "GFp_fe_mul"
|
||||
fe_mul :: Ptr Element -> Ptr Element -> Ptr Element -> IO ()
|
||||
foreign import ccall unsafe "fe_sq"
|
||||
fe_square :: Ptr Element -> Ptr Element -> IO ()
|
||||
foreign import ccall unsafe "GFp_fe_invert"
|
||||
fe_invert :: Ptr Element -> Ptr Element -> IO ()
|
||||
foreign import ccall unsafe "fe_neg"
|
||||
fe_negate :: Ptr Element -> Ptr Element -> IO ()
|
||||
foreign import ccall unsafe "fe_cmov"
|
||||
fe_cmov :: Ptr Element -> Ptr Element -> Word32 -> IO ()
|
||||
foreign import ccall unsafe "fe_isnonzero"
|
||||
fe_isnonzero :: Ptr Element -> IO Int32
|
||||
foreign import ccall unsafe "GFp_fe_isnegative"
|
||||
fe_isnegative :: Ptr Element -> IO Word8
|
||||
foreign import ccall unsafe "fe_sq2"
|
||||
fe_square2 :: Ptr Element -> Ptr Element -> IO ()
|
||||
foreign import ccall unsafe "fe_pow22523"
|
||||
fe_pow22523 :: Ptr Element -> Ptr Element -> IO ()
|
||||
foreign import ccall unsafe "GFp_x25519_ge_frombytes_vartime"
|
||||
point_frombytes :: Ptr Point3 -> Ptr PackedBytes -> IO Bool
|
||||
foreign import ccall unsafe "x25519_ge_p3_to_cached"
|
||||
p3_to_cached :: Ptr PointCached -> Ptr Point3 -> IO ()
|
||||
foreign import ccall unsafe "x25519_ge_p1p1_to_p2"
|
||||
p1p1_to_p2 :: Ptr Point2 -> Ptr PointP1P1 -> IO ()
|
||||
foreign import ccall unsafe "x25519_ge_p1p1_to_p3"
|
||||
p1p1_to_p3 :: Ptr Point3 -> Ptr PointP1P1 -> IO ()
|
||||
foreign import ccall unsafe "ge_p2_dbl"
|
||||
ge_p2_dbl :: Ptr PointP1P1 -> Ptr Point2 -> IO ()
|
||||
foreign import ccall unsafe "ge_p3_dbl"
|
||||
ge_p3_dbl :: Ptr PointP1P1 -> Ptr Point3 -> IO ()
|
||||
foreign import ccall unsafe "ge_p3_to_p2"
|
||||
ge_p3_to_p2 :: Ptr Point2 -> Ptr Point3 -> IO ()
|
||||
foreign import ccall unsafe "ge_madd"
|
||||
ge_madd :: Ptr PointP1P1 -> Ptr Point3 -> Ptr PointPrecomp -> IO ()
|
||||
foreign import ccall unsafe "ge_msub"
|
||||
ge_msub :: Ptr PointP1P1 -> Ptr Point3 -> Ptr PointPrecomp -> IO ()
|
||||
foreign import ccall unsafe "x25519_ge_add"
|
||||
ge_add :: Ptr PointP1P1 -> Ptr Point3 -> Ptr PointCached -> IO ()
|
||||
foreign import ccall unsafe "x25519_ge_sub"
|
||||
ge_sub :: Ptr PointP1P1 -> Ptr Point3 -> Ptr PointCached -> IO ()
|
||||
foreign import ccall unsafe "GFp_x25519_ge_scalarmult_base"
|
||||
x25519_ge_scalarmult_base :: Ptr Point3 -> Ptr PackedBytes -> IO ()
|
||||
foreign import ccall unsafe "slide"
|
||||
slide :: Ptr Word8 -> Ptr PackedBytes -> IO ()
|
||||
foreign import ccall unsafe "GFp_ge_double_scalarmult_vartime"
|
||||
ge_double_scalarmult_vartime :: Ptr Point2 -> Ptr PackedBytes -> Ptr Point3 -> Ptr PackedBytes -> IO ()
|
||||
foreign import ccall unsafe "GFp_x25519_sc_reduce"
|
||||
sc_reduce :: Ptr Word8 -> IO ()
|
||||
foreign import ccall unsafe "GFp_x25519_sc_muladd"
|
||||
sc_muladd :: Ptr PackedBytes -> Ptr PackedBytes -> Ptr PackedBytes -> Ptr PackedBytes -> IO ()
|
||||
foreign import ccall unsafe "GFp_x25519_public_from_private"
|
||||
public_from_private :: Ptr PackedBytes -> Ptr PackedBytes -> IO ()
|
||||
2120
test-generator/ED25519/PrecompPoints.hs
Normal file
2120
test-generator/ED25519/PrecompPoints.hs
Normal file
File diff suppressed because it is too large
Load Diff
44
test-generator/Main.hs
Normal file
44
test-generator/Main.hs
Normal file
@@ -0,0 +1,44 @@
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE PackageImports #-}
|
||||
import Control.Concurrent(forkIO)
|
||||
import Control.Concurrent.Chan(Chan,newChan,readChan,writeChan)
|
||||
import Control.Concurrent.MVar(MVar,newMVar,modifyMVar)
|
||||
import Control.Exception(SomeException,catch)
|
||||
import Control.Monad(replicateM_,void)
|
||||
import "crypto-api" Crypto.Random(CryptoRandomGen(..),SystemRandom)
|
||||
import DSA(dsaTasks)
|
||||
import ECDSATesting(ecdsaTasks)
|
||||
import ED25519(ed25519Tasks)
|
||||
import GHC.Conc(getNumCapabilities)
|
||||
import RFC6979(rfcTasks)
|
||||
import RSA(rsaTasks)
|
||||
import System.Console.AsciiProgress
|
||||
import Task(Task, runTask)
|
||||
|
||||
taskExecutor :: MVar [Task] -> Chan () -> SystemRandom -> IO SystemRandom
|
||||
taskExecutor taskList done gen =
|
||||
do mnext <- modifyMVar taskList (\case
|
||||
[] -> return ([], Nothing)
|
||||
(x:xs) -> return (xs, Just x))
|
||||
case mnext of
|
||||
Nothing -> do writeChan done ()
|
||||
return gen
|
||||
Just x -> do gen' <- runTask gen x
|
||||
taskExecutor taskList done gen'
|
||||
|
||||
spawnExecutor :: MVar [Task] -> Chan () -> IO ()
|
||||
spawnExecutor tasks done =
|
||||
do gen <- newGenIO
|
||||
void (forkIO (catch (void (taskExecutor tasks done gen)) handler))
|
||||
where
|
||||
handler :: SomeException -> IO ()
|
||||
handler e = putStrLn ("ERROR: " ++ show e)
|
||||
|
||||
main :: IO ()
|
||||
main = displayConsoleRegions $
|
||||
do
|
||||
executors <- getNumCapabilities
|
||||
done <- newChan
|
||||
tasks <- newMVar (dsaTasks ++ ecdsaTasks ++ rfcTasks ++ rsaTasks ++ ed25519Tasks)
|
||||
replicateM_ executors (spawnExecutor tasks done)
|
||||
replicateM_ executors (void $ readChan done)
|
||||
166
test-generator/Math.hs
Normal file
166
test-generator/Math.hs
Normal 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
113
test-generator/RFC6979.hs
Normal 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(..),liftTest)
|
||||
import Utils(HashAlg(..), runHash)
|
||||
|
||||
|
||||
runHMAC :: HashAlg -> S.ByteString -> S.ByteString -> S.ByteString
|
||||
runHMAC Sha224 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA224))
|
||||
runHMAC Sha256 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA256))
|
||||
runHMAC Sha384 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA384))
|
||||
runHMAC Sha512 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA512))
|
||||
|
||||
generateKStream :: HashAlg -> S.ByteString -> Integer -> Integer -> Int -> [Integer]
|
||||
generateKStream alg m x q qlen = nextK bigK2 bigV2
|
||||
where
|
||||
h1 = runHash alg m
|
||||
bigV0 = S.replicate (S.length h1) 0x01
|
||||
bigK0 = S.replicate (S.length h1) 0x00
|
||||
seed1 = S.concat [bigV0, S.singleton 0x00, int2octets qlen x, bits2octets qlen q h1]
|
||||
bigK1 = runHMAC alg bigK0 seed1
|
||||
bigV1 = runHMAC alg bigK1 bigV0
|
||||
seed2 = S.concat [bigV1, S.singleton 0x01, int2octets qlen x, bits2octets qlen q h1]
|
||||
bigK2 = runHMAC alg bigK1 seed2
|
||||
bigV2 = runHMAC alg bigK2 bigV1
|
||||
--
|
||||
nextK bigK bigV =
|
||||
let (bigV', bigT) = buildT bigK bigV S.empty
|
||||
k = bits2int qlen bigT
|
||||
bigK' = runHMAC alg bigK (bigV' `S.append` S.singleton 0)
|
||||
bigV'' = runHMAC alg bigK' bigV'
|
||||
in if k < q then (k : nextK bigK' bigV'') else nextK bigK' bigV''
|
||||
buildT bigK bigV bigT
|
||||
| S.length bigT * 8 >= qlen = (bigV, bigT)
|
||||
| otherwise =
|
||||
let bigV' = runHMAC alg bigK bigV
|
||||
in buildT bigK bigV' (bigT `S.append` bigV')
|
||||
|
||||
bits2int :: Int -> S.ByteString -> Integer
|
||||
bits2int qlen bstr = reduce (go bstr 0)
|
||||
where
|
||||
reduce x =
|
||||
let vlen = S.length bstr * 8
|
||||
in if vlen > qlen
|
||||
then x `shiftR` (vlen - qlen)
|
||||
else x
|
||||
--
|
||||
go x acc =
|
||||
case S.uncons x of
|
||||
Nothing -> acc
|
||||
Just (v, rest) ->
|
||||
go rest ((acc `shiftL` 8) + fromIntegral v)
|
||||
|
||||
int2octets :: Int -> Integer -> S.ByteString
|
||||
int2octets lenBits x =
|
||||
S.pack (pad (rlen `div` 8) (reverse (go x)))
|
||||
where
|
||||
rlen = 8 * ((lenBits + 7) `div` 8)
|
||||
pad target ls
|
||||
| length ls > target = drop (length ls - target) ls
|
||||
| length ls < target = pad target (0 : ls)
|
||||
| otherwise = ls
|
||||
--
|
||||
go 0 = []
|
||||
go v = (fromIntegral (v .&. 0xFF)) : go (v `shiftR` 8)
|
||||
|
||||
bits2octets :: Int -> Integer -> S.ByteString -> S.ByteString
|
||||
bits2octets qlen q bstr =
|
||||
let z1 = bits2int qlen bstr
|
||||
z2 = if z1 > q then z1 - q else z1
|
||||
in int2octets qlen z2
|
||||
|
||||
rfc6979Test :: HashAlg -> Task
|
||||
rfc6979Test alg = Task {
|
||||
taskName = name ++ " RFC 6979 deterministic k-generation",
|
||||
taskFile = "../testdata/rfc6979/" ++ name ++ ".test",
|
||||
taskTest = liftTest go,
|
||||
taskCount = 1000
|
||||
}
|
||||
where
|
||||
name = map toUpper (show alg)
|
||||
go (memory0, drg0) =
|
||||
let (qlen, drg1) = withDRG drg0 $ generateBetween 160 521
|
||||
(key, drg2) = withDRG drg1 $ generateBetween 1 ((2 ^ qlen) - 1)
|
||||
(q, drg3) = withDRG drg2 $ generateBetween 1 ((2 ^ qlen) - 1)
|
||||
(dataSize, drg4) = withDRG drg3 $ generateBetween 1 1024
|
||||
(msg, drg5) = withDRG drg4 $ getRandomBytes (fromIntegral dataSize)
|
||||
h1 = runHash alg msg
|
||||
ks = generateKStream alg msg key q (fromIntegral qlen)
|
||||
res = Map.fromList [("q", showX q), ("l", showX qlen),
|
||||
("x", showX key), ("h", showBin h1),
|
||||
("k", showX (ks !! 0)),
|
||||
("y", showX (ks !! 1)),
|
||||
("z", showX (ks !! 2))]
|
||||
in (res, qlen, (memory0, drg5))
|
||||
|
||||
rfcTasks :: [Task]
|
||||
rfcTasks = [rfc6979Test Sha224, rfc6979Test Sha256,
|
||||
rfc6979Test Sha384, rfc6979Test Sha512]
|
||||
126
test-generator/RSA.hs
Normal file
126
test-generator/RSA.hs
Normal 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(..),liftTest)
|
||||
import Utils(HashAlg(..),generateHash,showHash)
|
||||
|
||||
rsaSizes :: [(Int, Int)]
|
||||
rsaSizes = [(512, 400),
|
||||
(1024, 200),
|
||||
(2048, 100),
|
||||
(3072, 50),
|
||||
(4096, 50),
|
||||
(8192, 10),
|
||||
(15360, 5)]
|
||||
|
||||
rsaTasks :: [Task]
|
||||
rsaTasks = concatMap generateTask rsaSizes
|
||||
|
||||
generateTask :: (Int, Int) -> [Task]
|
||||
generateTask (s, c) = [signTest s c, encryptTest s c]
|
||||
|
||||
signTest :: Int -> Int -> Task
|
||||
signTest sz cnt = Task {
|
||||
taskName = "RSA " ++ show sz ++ " signing",
|
||||
taskFile = "../testdata/rsa/sign" ++ show sz ++ ".test",
|
||||
taskTest = liftTest go,
|
||||
taskCount = cnt
|
||||
}
|
||||
where
|
||||
go db = withDRG' db go2
|
||||
--
|
||||
go2 :: MonadRandom m => m (Map String String, Integer)
|
||||
go2 = do (public, private) <- generate (sz `div` 8) 65537
|
||||
let d = private_d private
|
||||
let n = public_n public
|
||||
msg <- getRandomBytes =<< ((fromIntegral . BS.head) `fmap` getRandomBytes 1)
|
||||
hash <- generateHash
|
||||
case signWith hash private msg of
|
||||
Left _ -> go2
|
||||
Right sig -> return $ (Map.fromList [("d", showX d),
|
||||
("n", showX n),
|
||||
("k", showX (computeK n)),
|
||||
("u", showX (barrett n)),
|
||||
("h", showHash hash),
|
||||
("m", showBin msg),
|
||||
("s", showBin sig)], n)
|
||||
|
||||
withDRG' :: Database -> MonadPseudoRandom SystemRandom (Map String String, Integer) ->
|
||||
(Map String String, Integer, Database)
|
||||
withDRG' (memory, drg) action =
|
||||
let ((res, n), drg') = withDRG drg action
|
||||
in (res, n, (memory, drg'))
|
||||
|
||||
signWith :: HashAlg -> PrivateKey -> BS.ByteString -> Either Error BS.ByteString
|
||||
signWith Sha224 = sign Nothing (Just SHA224)
|
||||
signWith Sha256 = sign Nothing (Just SHA256)
|
||||
signWith Sha384 = sign Nothing (Just SHA384)
|
||||
signWith Sha512 = sign Nothing (Just SHA512)
|
||||
|
||||
encryptTest :: Int -> Int -> Task
|
||||
encryptTest sz cnt = Task {
|
||||
taskName = "RSA " ++ show sz ++ " encryption",
|
||||
taskFile = "../testdata/rsa/encrypt" ++ show sz ++ ".test",
|
||||
taskTest = liftTest go,
|
||||
taskCount = cnt
|
||||
}
|
||||
where
|
||||
go db = withDRG' db go2
|
||||
go2 = do (public, private) <- generate (sz `div` 8) 65537
|
||||
let d = private_d private
|
||||
let n = public_n public
|
||||
msg <- getRandomBytes =<< ((fromIntegral . BS.head) `fmap` getRandomBytes 1)
|
||||
hash <- generateHash
|
||||
label <- do len <- BS.head `fmap` getRandomBytes 1
|
||||
if odd len
|
||||
then return Nothing
|
||||
else Just `fmap` genASCII (len `div` 2)
|
||||
let labelbstr = fromMaybe BS.empty (BSC.pack `fmap` label)
|
||||
labelAlive = if isJust label then 1 else (0 :: Integer)
|
||||
res <- encryptWith hash (BSC.pack `fmap` label) public msg
|
||||
case res of
|
||||
Left _ -> go2
|
||||
Right cipher ->
|
||||
return $ (Map.fromList [("d", showX d),
|
||||
("n", showX n),
|
||||
("k", showX (computeK n)),
|
||||
("u", showX (barrett n)),
|
||||
("h", showHash hash),
|
||||
("m", showBin msg),
|
||||
("l", showBin labelbstr),
|
||||
("e", showX labelAlive),
|
||||
("c", showBin cipher)], n)
|
||||
|
||||
genASCII :: MonadRandom m => Word8 -> m String
|
||||
genASCII 0 = return ""
|
||||
genASCII x =
|
||||
do v <- (BS.head `fmap` getRandomBytes 1)
|
||||
let c = chr (fromIntegral v)
|
||||
if (v < 128) && isPrint c
|
||||
then (c :) `fmap` genASCII (x - 1)
|
||||
else genASCII x
|
||||
|
||||
encryptWith :: MonadRandom m =>
|
||||
HashAlg -> Maybe BS.ByteString -> PublicKey -> BS.ByteString ->
|
||||
m (Either Error BS.ByteString)
|
||||
encryptWith Sha224 mlabel = encrypt (OAEPParams SHA224 (mgf1 SHA224) mlabel)
|
||||
encryptWith Sha256 mlabel = encrypt (OAEPParams SHA256 (mgf1 SHA256) mlabel)
|
||||
encryptWith Sha384 mlabel = encrypt (OAEPParams SHA384 (mgf1 SHA384) mlabel)
|
||||
encryptWith Sha512 mlabel = encrypt (OAEPParams SHA512 (mgf1 SHA512) mlabel)
|
||||
56
test-generator/Task.hs
Normal file
56
test-generator/Task.hs
Normal file
@@ -0,0 +1,56 @@
|
||||
{-# LANGUAGE PackageImports #-}
|
||||
module Task(
|
||||
Test,
|
||||
Task(..),
|
||||
runTask,
|
||||
liftTest
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Monad(foldM, forM_)
|
||||
import "crypto-api" Crypto.Random(SystemRandom)
|
||||
import qualified Data.Map.Strict as Map
|
||||
import Database
|
||||
import System.Console.AsciiProgress
|
||||
import System.Directory(createDirectoryIfMissing,doesFileExist)
|
||||
import System.FilePath(takeDirectory)
|
||||
import System.IO(Handle,IOMode(..),hPutStrLn,withFile)
|
||||
|
||||
type Test = Database -> IO (Map.Map String String, Integer, Database)
|
||||
|
||||
data Task = Task {
|
||||
taskName :: String,
|
||||
taskFile :: FilePath,
|
||||
taskTest :: Test,
|
||||
taskCount :: Int
|
||||
}
|
||||
|
||||
liftTest :: (Database -> (Map.Map String String, Integer, Database)) ->
|
||||
(Database -> IO (Map.Map String String, Integer, Database))
|
||||
liftTest f db = return (f db)
|
||||
|
||||
runTask :: SystemRandom -> Task -> IO SystemRandom
|
||||
runTask gen task =
|
||||
do createDirectoryIfMissing True (takeDirectory (taskFile task))
|
||||
alreadyDone <- doesFileExist (taskFile task)
|
||||
if alreadyDone
|
||||
then return gen
|
||||
else withFile (taskFile task) WriteMode $ \ hndl ->
|
||||
do pg <- newProgressBar def{ pgOnCompletion = Just ("Finished " ++ taskName task),
|
||||
pgFormat = taskName task ++ " " ++ pgFormat def,
|
||||
pgTotal = fromIntegral (taskCount task) }
|
||||
let initval = emptyDatabase gen
|
||||
(_, gen') <- foldM (writer hndl pg (taskTest task)) initval [0..taskCount task]
|
||||
return gen'
|
||||
where
|
||||
writer :: Handle -> ProgressBar -> Test -> Database -> Int -> IO Database
|
||||
writer hndl pg runner db x =
|
||||
do (output, key, acc@(db',gen')) <- runner db
|
||||
let before = Map.findWithDefault [] "RESULT" db'
|
||||
if length (filter (== key) before) >= 10
|
||||
then writer hndl pg runner acc x
|
||||
else do forM_ (Map.toList output) $ \ (outkey, val) ->
|
||||
hPutStrLn hndl (outkey ++ ": " ++ val)
|
||||
tick pg
|
||||
return (Map.insert "RESULT" (key : before) db', gen')
|
||||
|
||||
35
test-generator/Utils.hs
Normal file
35
test-generator/Utils.hs
Normal 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"
|
||||
96
test-generator/cbits/GFp/aes.h
Normal file
96
test-generator/cbits/GFp/aes.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/* ====================================================================
|
||||
* Copyright (c) 2002-2006 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ==================================================================== */
|
||||
|
||||
#ifndef OPENSSL_HEADER_AES_H
|
||||
#define OPENSSL_HEADER_AES_H
|
||||
|
||||
#include <GFp/base.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Raw AES functions. */
|
||||
|
||||
|
||||
#define AES_ENCRYPT 1
|
||||
#define AES_DECRYPT 0
|
||||
|
||||
/* AES_MAXNR is the maximum number of AES rounds. */
|
||||
#define AES_MAXNR 14
|
||||
|
||||
#define AES_BLOCK_SIZE 16
|
||||
|
||||
/* aes_key_st should be an opaque type, but EVP requires that the size be
|
||||
* known. */
|
||||
struct aes_key_st {
|
||||
uint32_t rd_key[4 * (AES_MAXNR + 1)];
|
||||
unsigned rounds;
|
||||
};
|
||||
typedef struct aes_key_st AES_KEY;
|
||||
|
||||
/* GFp_AES_set_encrypt_key configures |aeskey| to encrypt with the |bits|-bit
|
||||
* key, |key|.
|
||||
*
|
||||
* WARNING: unlike other OpenSSL functions, this returns zero on success and a
|
||||
* negative number on error. */
|
||||
OPENSSL_EXPORT int GFp_AES_set_encrypt_key(const uint8_t *key, unsigned bits,
|
||||
AES_KEY *aeskey);
|
||||
|
||||
/* AES_encrypt encrypts a single block from |in| to |out| with |key|. The |in|
|
||||
* and |out| pointers may overlap. */
|
||||
OPENSSL_EXPORT void GFp_AES_encrypt(const uint8_t *in, uint8_t *out,
|
||||
const AES_KEY *key);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern C */
|
||||
#endif
|
||||
|
||||
#endif /* OPENSSL_HEADER_AES_H */
|
||||
123
test-generator/cbits/GFp/arm_arch.h
Normal file
123
test-generator/cbits/GFp/arm_arch.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This product includes cryptographic software written by Eric Young
|
||||
* (eay@cryptsoft.com). This product includes software written by Tim
|
||||
* Hudson (tjh@cryptsoft.com). */
|
||||
|
||||
#ifndef OPENSSL_HEADER_ARM_ARCH_H
|
||||
#define OPENSSL_HEADER_ARM_ARCH_H
|
||||
|
||||
#if !defined(__ARM_ARCH__)
|
||||
# if defined(__CC_ARM)
|
||||
# define __ARM_ARCH__ __TARGET_ARCH_ARM
|
||||
# if defined(__BIG_ENDIAN)
|
||||
# define __ARMEB__
|
||||
# else
|
||||
# define __ARMEL__
|
||||
# endif
|
||||
# elif defined(__GNUC__)
|
||||
# if defined(__aarch64__)
|
||||
# define __ARM_ARCH__ 8
|
||||
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
# define __ARMEB__
|
||||
# else
|
||||
# define __ARMEL__
|
||||
# endif
|
||||
/* Why doesn't gcc define __ARM_ARCH__? Instead it defines
|
||||
* bunch of below macros. See all_architectires[] table in
|
||||
* gcc/config/arm/arm.c. On a side note it defines
|
||||
* __ARMEL__/__ARMEB__ for little-/big-endian. */
|
||||
# elif defined(__ARM_ARCH)
|
||||
# define __ARM_ARCH__ __ARM_ARCH
|
||||
# elif defined(__ARM_ARCH_8A__)
|
||||
# define __ARM_ARCH__ 8
|
||||
# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
|
||||
defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__) || \
|
||||
defined(__ARM_ARCH_7EM__)
|
||||
# define __ARM_ARCH__ 7
|
||||
# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
|
||||
defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__) || \
|
||||
defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__) || \
|
||||
defined(__ARM_ARCH_6T2__)
|
||||
# define __ARM_ARCH__ 6
|
||||
# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \
|
||||
defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__) || \
|
||||
defined(__ARM_ARCH_5TEJ__)
|
||||
# define __ARM_ARCH__ 5
|
||||
# elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
|
||||
# define __ARM_ARCH__ 4
|
||||
# else
|
||||
# error "unsupported ARM architecture"
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Even when building for 32-bit ARM, support for aarch64 crypto instructions
|
||||
* will be included. */
|
||||
#if !defined(__ARM_MAX_ARCH__)
|
||||
#define __ARM_MAX_ARCH__ 8
|
||||
#endif
|
||||
|
||||
/* ARMV7_NEON is true when a NEON unit is present in the current CPU. */
|
||||
#define ARMV7_NEON (1 << 0)
|
||||
|
||||
/* ARMV8_AES indicates support for hardware AES instructions. */
|
||||
#define ARMV8_AES (1 << 2)
|
||||
|
||||
/* ARMV8_SHA1 indicates support for hardware SHA-1 instructions. */
|
||||
#define ARMV8_SHA1 (1 << 3)
|
||||
|
||||
/* ARMV8_SHA256 indicates support for hardware SHA-256 instructions. */
|
||||
#define ARMV8_SHA256 (1 << 4)
|
||||
|
||||
/* ARMV8_PMULL indicates support for carryless multiplication. */
|
||||
#define ARMV8_PMULL (1 << 5)
|
||||
|
||||
|
||||
#endif /* OPENSSL_HEADER_ARM_ARCH_H */
|
||||
122
test-generator/cbits/GFp/base.h
Normal file
122
test-generator/cbits/GFp/base.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This product includes cryptographic software written by Eric Young
|
||||
* (eay@cryptsoft.com). This product includes software written by Tim
|
||||
* Hudson (tjh@cryptsoft.com). */
|
||||
|
||||
#ifndef OPENSSL_HEADER_BASE_H
|
||||
#define OPENSSL_HEADER_BASE_H
|
||||
|
||||
|
||||
/* This file should be the first included by all BoringSSL headers. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64)
|
||||
#define OPENSSL_64_BIT
|
||||
#define OPENSSL_X86_64
|
||||
#elif defined(__x86) || defined(__i386) || defined(__i386__) || defined(_M_IX86)
|
||||
#define OPENSSL_32_BIT
|
||||
#define OPENSSL_X86
|
||||
#elif defined(__aarch64__)
|
||||
#define OPENSSL_64_BIT
|
||||
#define OPENSSL_AARCH64
|
||||
#elif defined(__arm) || defined(__arm__) || defined(_M_ARM)
|
||||
#define OPENSSL_32_BIT
|
||||
#define OPENSSL_ARM
|
||||
#elif (defined(__PPC64__) || defined(__powerpc64__)) && defined(_LITTLE_ENDIAN)
|
||||
#define OPENSSL_64_BIT
|
||||
#define OPENSSL_PPC64LE
|
||||
#elif defined(__mips__) && !defined(__LP64__)
|
||||
#define OPENSSL_32_BIT
|
||||
#define OPENSSL_MIPS
|
||||
#elif defined(__mips__) && defined(__LP64__)
|
||||
#define OPENSSL_64_BIT
|
||||
#define OPENSSL_MIPS64
|
||||
#elif defined(__pnacl__)
|
||||
#define OPENSSL_32_BIT
|
||||
#define OPENSSL_PNACL
|
||||
#elif defined(__myriad2__)
|
||||
#define OPENSSL_32_BIT
|
||||
#else
|
||||
#error "Unknown target CPU"
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define OPENSSL_APPLE
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define OPENSSL_WINDOWS
|
||||
#endif
|
||||
|
||||
#define OPENSSL_IS_BORINGSSL
|
||||
#define OPENSSL_IS_RING
|
||||
#define OPENSSL_VERSION_NUMBER 0x10002000
|
||||
|
||||
/* *ring* doesn't support the `BORINGSSL_SHARED_LIBRARY` configuration, so
|
||||
* the default (usually "hidden") visibility is always used, even for exported
|
||||
* items. */
|
||||
#define OPENSSL_EXPORT
|
||||
|
||||
typedef struct bignum_st BIGNUM;
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern C */
|
||||
#endif
|
||||
|
||||
#endif /* OPENSSL_HEADER_BASE_H */
|
||||
256
test-generator/cbits/GFp/bn.h
Normal file
256
test-generator/cbits/GFp/bn.h
Normal file
@@ -0,0 +1,256 @@
|
||||
/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.]
|
||||
*/
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This product includes cryptographic software written by Eric Young
|
||||
* (eay@cryptsoft.com). This product includes software written by Tim
|
||||
* Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
*/
|
||||
/* ====================================================================
|
||||
* Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
|
||||
*
|
||||
* Portions of the attached software ("Contribution") are developed by
|
||||
* SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
|
||||
*
|
||||
* The Contribution is licensed pursuant to the Eric Young open source
|
||||
* license provided above.
|
||||
*
|
||||
* The binary polynomial arithmetic software is originally written by
|
||||
* Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
|
||||
* Laboratories. */
|
||||
|
||||
#ifndef OPENSSL_HEADER_BN_H
|
||||
#define OPENSSL_HEADER_BN_H
|
||||
|
||||
#include <GFp/base.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* BN provides support for working with arbitrary sized integers. For example,
|
||||
* although the largest integer supported by the compiler might be 64 bits, BN
|
||||
* will allow you to work with numbers until you run out of memory. */
|
||||
|
||||
|
||||
/* BN_ULONG is the native word size when working with big integers.
|
||||
*
|
||||
* Note: on some platforms, inttypes.h does not define print format macros in
|
||||
* C++ unless |__STDC_FORMAT_MACROS| defined. As this is a public header, bn.h
|
||||
* does not define |__STDC_FORMAT_MACROS| itself. C++ source files which use the
|
||||
* FMT macros must define it externally. */
|
||||
#if defined(OPENSSL_64_BIT)
|
||||
#define BN_ULONG uint64_t
|
||||
#define BN_BITS2 64
|
||||
#elif defined(OPENSSL_32_BIT)
|
||||
#define BN_ULONG uint32_t
|
||||
#define BN_BITS2 32
|
||||
#else
|
||||
#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT"
|
||||
#endif
|
||||
|
||||
|
||||
/* Allocation and freeing. */
|
||||
|
||||
/* GFp_BN_init initialises a stack allocated |BIGNUM|. */
|
||||
OPENSSL_EXPORT void GFp_BN_init(BIGNUM *bn);
|
||||
|
||||
/* GFp_BN_free frees the data referenced by |bn| and, if |bn| was originally
|
||||
* allocated on the heap, frees |bn| also. */
|
||||
OPENSSL_EXPORT void GFp_BN_free(BIGNUM *bn);
|
||||
|
||||
/* GFp_BN_copy sets |dest| equal to |src| and returns one on success or zero on
|
||||
* failure. */
|
||||
OPENSSL_EXPORT int GFp_BN_copy(BIGNUM *dest, const BIGNUM *src);
|
||||
|
||||
|
||||
/* Basic functions. */
|
||||
|
||||
/* GFp_BN_zero sets |bn| to zero. */
|
||||
OPENSSL_EXPORT void GFp_BN_zero(BIGNUM *bn);
|
||||
|
||||
|
||||
/* Internal functions.
|
||||
*
|
||||
* These functions are useful for code that is doing low-level manipulations of
|
||||
* BIGNUM values. However, be sure that no other function in this file does
|
||||
* what you want before turning to these. */
|
||||
|
||||
/* bn_correct_top decrements |bn->top| until |bn->d[top-1]| is non-zero or
|
||||
* until |top| is zero. */
|
||||
OPENSSL_EXPORT void GFp_bn_correct_top(BIGNUM *bn);
|
||||
|
||||
/* bn_wexpand ensures that |bn| has at least |words| works of space without
|
||||
* altering its value. It returns one on success and zero on allocation
|
||||
* failure. */
|
||||
OPENSSL_EXPORT int GFp_bn_wexpand(BIGNUM *bn, size_t words);
|
||||
|
||||
|
||||
/* Simple arithmetic */
|
||||
|
||||
/* GFp_BN_mul_no_alias sets |r| = |a| * |b|, where |r| must not be the same pointer
|
||||
* as |a| or |b|. Returns one on success and zero otherwise. */
|
||||
OPENSSL_EXPORT int GFp_BN_mul_no_alias(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
|
||||
|
||||
|
||||
/* Comparison functions */
|
||||
|
||||
/* GFp_BN_is_odd returns one if |bn| is odd and zero otherwise. */
|
||||
OPENSSL_EXPORT int GFp_BN_is_odd(const BIGNUM *bn);
|
||||
|
||||
|
||||
/* Bitwise operations. */
|
||||
|
||||
/* GFp_BN_is_bit_set returns the value of the |n|th, least-significant bit in
|
||||
* |a|, or zero if the bit doesn't exist. */
|
||||
OPENSSL_EXPORT int GFp_BN_is_bit_set(const BIGNUM *a, int n);
|
||||
|
||||
|
||||
/* Modulo arithmetic. */
|
||||
|
||||
/* GFp_BN_mod_mul_mont set |r| equal to |a| * |b|, in the Montgomery domain.
|
||||
* Both |a| and |b| must already be in the Montgomery domain (by
|
||||
* |GFp_BN_to_mont|). In particular, |a| and |b| are assumed to be in the range
|
||||
* [0, n), where |n| is the Montgomery modulus. It returns one on success or
|
||||
* zero on error. */
|
||||
OPENSSL_EXPORT int GFp_BN_mod_mul_mont(
|
||||
BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *n,
|
||||
const BN_ULONG n0[/*BN_MONT_CTX_N0_LIMBS*/]);
|
||||
|
||||
/* GFp_BN_reduce_montgomery returns |a % n| in constant-ish time using
|
||||
* Montgomery reduction. |a| is assumed to be in the range [0, n**2), where |n|
|
||||
* is the Montgomery modulus. It returns one on success or zero on error. */
|
||||
int GFp_BN_reduce_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *n,
|
||||
const BN_ULONG n0[/*BN_MONT_CTX_N0_LIMBS*/]);
|
||||
|
||||
|
||||
/* Exponentiation. */
|
||||
|
||||
OPENSSL_EXPORT int GFp_BN_mod_exp_mont_consttime(
|
||||
BIGNUM *rr, const BIGNUM *a_mont, const BIGNUM *p, size_t p_bits,
|
||||
const BIGNUM *one_mont, const BIGNUM *n,
|
||||
const BN_ULONG n0[/*BN_MONT_CTX_N0_LIMBS*/]);
|
||||
|
||||
|
||||
/* Private functions */
|
||||
|
||||
/* Keep in sync with `BIGNUM` in `ring::rsa::bigint`. */
|
||||
struct bignum_st {
|
||||
BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks in little-endian
|
||||
order. */
|
||||
int top; /* Index of last used element in |d|, plus one. */
|
||||
int dmax; /* Size of |d|, in words. */
|
||||
int flags; /* bitmask of BN_FLG_* values */
|
||||
};
|
||||
|
||||
#define BN_FLG_MALLOCED 0x01
|
||||
#define BN_FLG_STATIC_DATA 0x02
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern C */
|
||||
#endif
|
||||
|
||||
#endif /* OPENSSL_HEADER_BN_H */
|
||||
189
test-generator/cbits/GFp/cpu.h
Normal file
189
test-generator/cbits/GFp/cpu.h
Normal file
@@ -0,0 +1,189 @@
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.]
|
||||
*
|
||||
* This product includes cryptographic software written by Eric Young
|
||||
* (eay@cryptsoft.com). This product includes software written by Tim
|
||||
* Hudson (tjh@cryptsoft.com). */
|
||||
|
||||
#ifndef OPENSSL_HEADER_CPU_H
|
||||
#define OPENSSL_HEADER_CPU_H
|
||||
|
||||
#include <GFp/base.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Runtime CPU feature support */
|
||||
|
||||
|
||||
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
|
||||
/* GFp_ia32cap_P contains the Intel CPUID bits when running on an x86 or
|
||||
* x86-64 system.
|
||||
*
|
||||
* Index 0:
|
||||
* EDX for CPUID where EAX = 1
|
||||
* Bit 20 is always zero
|
||||
* Bit 28 is adjusted to reflect whether the data cache is shared between
|
||||
* multiple logical cores
|
||||
* Bit 30 is used to indicate an Intel CPU
|
||||
* Index 1:
|
||||
* ECX for CPUID where EAX = 1
|
||||
* Bit 11 is used to indicate AMD XOP support, not SDBG
|
||||
* Index 2:
|
||||
* EBX for CPUID where EAX = 7
|
||||
* Index 3 is set to zero.
|
||||
*
|
||||
* Note: the CPUID bits are pre-adjusted for the OSXSAVE bit and the YMM and XMM
|
||||
* bits in XCR0, so it is not necessary to check those. */
|
||||
extern uint32_t GFp_ia32cap_P[4];
|
||||
#endif
|
||||
|
||||
#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
|
||||
|
||||
#if defined(OPENSSL_APPLE)
|
||||
/* iOS builds use the static ARM configuration. */
|
||||
#define OPENSSL_STATIC_ARMCAP
|
||||
|
||||
#if defined(OPENSSL_AARCH64)
|
||||
#define OPENSSL_STATIC_ARMCAP_AES
|
||||
#define OPENSSL_STATIC_ARMCAP_SHA1
|
||||
#define OPENSSL_STATIC_ARMCAP_SHA256
|
||||
#define OPENSSL_STATIC_ARMCAP_PMULL
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(OPENSSL_STATIC_ARMCAP)
|
||||
|
||||
/* GFp_is_NEON_capable_at_runtime returns true if the current CPU has a NEON
|
||||
* unit. Note that |OPENSSL_armcap_P| also exists and contains the same
|
||||
* information in a form that's easier for assembly to use. */
|
||||
OPENSSL_EXPORT uint8_t GFp_is_NEON_capable_at_runtime(void);
|
||||
|
||||
/* GFp_is_NEON_capable returns true if the current CPU has a NEON unit. If
|
||||
* this is known statically then it returns one immediately. */
|
||||
static inline int GFp_is_NEON_capable(void) {
|
||||
/* On 32-bit ARM, one CPU is known to have a broken NEON unit which is known
|
||||
* to fail with on some hand-written NEON assembly. Assume that non-Android
|
||||
* applications will not use that buggy CPU but still support Android users
|
||||
* that do, even when the compiler is instructed to freely emit NEON code.
|
||||
* See https://crbug.com/341598 and https://crbug.com/606629. */
|
||||
#if defined(__ARM_NEON__) && (!defined(OPENSSL_ARM) || !defined(__ANDROID__))
|
||||
return 1;
|
||||
#else
|
||||
return GFp_is_NEON_capable_at_runtime();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(OPENSSL_ARM)
|
||||
/* GFp_has_broken_NEON returns one if the current CPU is known to have a
|
||||
* broken NEON unit. See https://crbug.com/341598. */
|
||||
OPENSSL_EXPORT int GFp_has_broken_NEON(void);
|
||||
#endif
|
||||
|
||||
/* GFp_is_ARMv8_AES_capable returns true if the current CPU supports the
|
||||
* ARMv8 AES instruction. */
|
||||
int GFp_is_ARMv8_AES_capable(void);
|
||||
|
||||
/* GFp_is_ARMv8_PMULL_capable returns true if the current CPU supports the
|
||||
* ARMv8 PMULL instruction. */
|
||||
int GFp_is_ARMv8_PMULL_capable(void);
|
||||
|
||||
#else
|
||||
|
||||
static inline int GFp_is_NEON_capable(void) {
|
||||
#if defined(OPENSSL_STATIC_ARMCAP_NEON) || defined(__ARM_NEON__)
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int GFp_is_ARMv8_AES_capable(void) {
|
||||
#if defined(OPENSSL_STATIC_ARMCAP_AES)
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int GFp_is_ARMv8_PMULL_capable(void) {
|
||||
#if defined(OPENSSL_STATIC_ARMCAP_PMULL)
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* OPENSSL_STATIC_ARMCAP */
|
||||
#endif /* OPENSSL_ARM || OPENSSL_AARCH64 */
|
||||
|
||||
#if defined(OPENSSL_PPC64LE)
|
||||
|
||||
/* CRYPTO_is_PPC64LE_vcrypto_capable returns true iff the current CPU supports
|
||||
* the Vector.AES category of instructions. */
|
||||
int CRYPTO_is_PPC64LE_vcrypto_capable(void);
|
||||
|
||||
#endif /* OPENSSL_PPC64LE */
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern C */
|
||||
#endif
|
||||
|
||||
#endif /* OPENSSL_HEADER_CPU_H */
|
||||
93
test-generator/cbits/GFp/mem.h
Normal file
93
test-generator/cbits/GFp/mem.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#ifndef OPENSSL_HEADER_MEM_H
|
||||
#define OPENSSL_HEADER_MEM_H
|
||||
|
||||
#include <GFp/base.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Memory and string functions, see also buf.h.
|
||||
*
|
||||
* OpenSSL has, historically, had a complex set of malloc debugging options.
|
||||
* However, that was written in a time before Valgrind and ASAN. Since we now
|
||||
* have those tools, the OpenSSL allocation functions are simply macros around
|
||||
* the standard memory functions. */
|
||||
|
||||
|
||||
#define OPENSSL_malloc malloc
|
||||
#define OPENSSL_realloc realloc
|
||||
#define OPENSSL_free free
|
||||
|
||||
/* GFp_memcmp returns zero iff the |len| bytes at |a| and |b| are equal. It
|
||||
* takes an amount of time dependent on |len|, but independent of the contents
|
||||
* of |a| and |b|. Unlike memcmp, it cannot be used to put elements into a
|
||||
* defined order as the return value when a != b is undefined, other than to be
|
||||
* non-zero. */
|
||||
OPENSSL_EXPORT int GFp_memcmp(const void *a, const void *b, size_t len);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern C */
|
||||
#endif
|
||||
|
||||
#endif /* OPENSSL_HEADER_MEM_H */
|
||||
75
test-generator/cbits/GFp/type_check.h
Normal file
75
test-generator/cbits/GFp/type_check.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#ifndef OPENSSL_HEADER_TYPE_CHECK_H
|
||||
#define OPENSSL_HEADER_TYPE_CHECK_H
|
||||
|
||||
#include <GFp/base.h>
|
||||
|
||||
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
#define OPENSSL_COMPILE_ASSERT(cond, msg) _Static_assert(cond, #msg)
|
||||
#elif defined(__GNUC__)
|
||||
#define OPENSSL_COMPILE_ASSERT(cond, msg) \
|
||||
typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)] \
|
||||
__attribute__((unused))
|
||||
#else
|
||||
#define OPENSSL_COMPILE_ASSERT(cond, msg) \
|
||||
typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)]
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* OPENSSL_HEADER_TYPE_CHECK_H */
|
||||
2133
test-generator/cbits/asm/x25519-asm-arm.S
Normal file
2133
test-generator/cbits/asm/x25519-asm-arm.S
Normal file
File diff suppressed because it is too large
Load Diff
1921
test-generator/cbits/asm/x25519-asm-x86_64.S
Normal file
1921
test-generator/cbits/asm/x25519-asm-x86_64.S
Normal file
File diff suppressed because it is too large
Load Diff
4726
test-generator/cbits/curve25519.c
Normal file
4726
test-generator/cbits/curve25519.c
Normal file
File diff suppressed because it is too large
Load Diff
109
test-generator/cbits/internal.h
Normal file
109
test-generator/cbits/internal.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/* Copyright (c) 2015, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#ifndef OPENSSL_HEADER_CURVE25519_INTERNAL_H
|
||||
#define OPENSSL_HEADER_CURVE25519_INTERNAL_H
|
||||
|
||||
#include <GFp/base.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(OPENSSL_X86_64) && !defined(OPENSSL_SMALL) && \
|
||||
!defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_ASM)
|
||||
/* This isn't compatible with Windows because the asm code makes use of the red
|
||||
* zone, which Windows doesn't support. */
|
||||
#define BORINGSSL_X25519_X86_64
|
||||
|
||||
void GFp_x25519_x86_64(uint8_t out[32], const uint8_t scalar[32],
|
||||
const uint8_t point[32]);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
|
||||
#define BORINGSSL_X25519_NEON
|
||||
|
||||
/* x25519_NEON is defined in asm/x25519-arm.S. */
|
||||
void GFp_x25519_NEON(uint8_t out[32], const uint8_t scalar[32],
|
||||
const uint8_t point[32]);
|
||||
#endif
|
||||
|
||||
/* fe means field element. Here the field is \Z/(2^255-19). An element t,
|
||||
* entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
|
||||
* t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
|
||||
* context.
|
||||
*
|
||||
* Keep in sync with `Elem` and `ELEM_LIMBS` in curve25519/ops.rs. */
|
||||
typedef int32_t fe[10];
|
||||
|
||||
/* ge means group element.
|
||||
|
||||
* Here the group is the set of pairs (x,y) of field elements (see fe.h)
|
||||
* satisfying -x^2 + y^2 = 1 + d x^2y^2
|
||||
* where d = -121665/121666.
|
||||
*
|
||||
* Representations:
|
||||
* ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
|
||||
* ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
|
||||
* ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
|
||||
* ge_precomp (Duif): (y+x,y-x,2dxy)
|
||||
*/
|
||||
|
||||
/* Keep in sync with `Point` in curve25519/ops.rs. */
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
} ge_p2;
|
||||
|
||||
|
||||
/* Keep in sync with `ExtPoint` in curve25519/ops.rs. */
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
fe T;
|
||||
} ge_p3;
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
fe T;
|
||||
} ge_p1p1;
|
||||
|
||||
typedef struct {
|
||||
fe yplusx;
|
||||
fe yminusx;
|
||||
fe xy2d;
|
||||
} ge_precomp;
|
||||
|
||||
typedef struct {
|
||||
fe YplusX;
|
||||
fe YminusX;
|
||||
fe Z;
|
||||
fe T2d;
|
||||
} ge_cached;
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern C */
|
||||
#endif
|
||||
|
||||
#endif /* OPENSSL_HEADER_CURVE25519_INTERNAL_H */
|
||||
361
test-generator/cbits/internal2.h
Normal file
361
test-generator/cbits/internal2.h
Normal file
@@ -0,0 +1,361 @@
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.]
|
||||
*/
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This product includes cryptographic software written by Eric Young
|
||||
* (eay@cryptsoft.com). This product includes software written by Tim
|
||||
* Hudson (tjh@cryptsoft.com). */
|
||||
|
||||
#ifndef OPENSSL_HEADER_CRYPTO_INTERNAL_H
|
||||
#define OPENSSL_HEADER_CRYPTO_INTERNAL_H
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(__clang__) || defined(_MSC_VER)
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <GFp/base.h>
|
||||
#include <GFp/type_check.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push, 3)
|
||||
#include <intrin.h>
|
||||
#pragma warning(pop)
|
||||
#if !defined(__cplusplus)
|
||||
#define alignas(x) __declspec(align(x))
|
||||
#define alignof __alignof
|
||||
#endif
|
||||
#elif !defined(__clang__) && defined(__GNUC__) && __GNUC__ == 4 && \
|
||||
__GNUC_MINOR__ <= 6
|
||||
#define alignas(x) __attribute__((aligned (x)))
|
||||
#define alignof __alignof__
|
||||
#else
|
||||
#include <stdalign.h>
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM) || \
|
||||
defined(OPENSSL_AARCH64) || defined(OPENSSL_PPC64LE)
|
||||
/* OPENSSL_cpuid_setup initializes the platform-specific feature cache. */
|
||||
void GFp_cpuid_setup(void);
|
||||
#endif
|
||||
|
||||
#define OPENSSL_LITTLE_ENDIAN 1
|
||||
#define OPENSSL_BIG_ENDIAN 2
|
||||
|
||||
#if defined(OPENSSL_X86_64) || defined(OPENSSL_X86) || \
|
||||
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
|
||||
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
#define OPENSSL_ENDIAN OPENSSL_LITTLE_ENDIAN
|
||||
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
|
||||
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define OPENSSL_ENDIAN OPENSSL_BIG_ENDIAN
|
||||
#else
|
||||
#error "Cannot determine endianness"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define bswap_u32(x) __builtin_bswap32(x)
|
||||
#define bswap_u64(x) __builtin_bswap64(x)
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma intrinsic(_byteswap_ulong, _byteswap_uint64)
|
||||
#define bswap_u32(x) _byteswap_ulong(x)
|
||||
#define bswap_u64(x) _byteswap_uint64(x)
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(_MSC_VER) && defined(OPENSSL_64_BIT)
|
||||
typedef __int128_t int128_t;
|
||||
typedef __uint128_t uint128_t;
|
||||
#endif
|
||||
|
||||
|
||||
/* Constant-time utility functions.
|
||||
*
|
||||
* The following methods return a bitmask of all ones (0xff...f) for true and 0
|
||||
* for false. This is useful for choosing a value based on the result of a
|
||||
* conditional in constant time. */
|
||||
|
||||
/* constant_time_msb returns the given value with the MSB copied to all the
|
||||
* other bits. */
|
||||
static inline unsigned int constant_time_msb_unsigned(unsigned int a) {
|
||||
return (unsigned int)((int)(a) >> (sizeof(int) * 8 - 1));
|
||||
}
|
||||
|
||||
OPENSSL_COMPILE_ASSERT(sizeof(ptrdiff_t) == sizeof(size_t),
|
||||
ptrdiff_t_and_size_t_are_different_sizes);
|
||||
|
||||
static inline size_t constant_time_msb_size_t(size_t a) {
|
||||
return (size_t)((ptrdiff_t)(a) >> (sizeof(ptrdiff_t) * 8 - 1));
|
||||
}
|
||||
|
||||
|
||||
/* constant_time_is_zero returns 0xff..f if a == 0 and 0 otherwise. */
|
||||
static inline unsigned int constant_time_is_zero_unsigned(unsigned int a) {
|
||||
/* Here is an SMT-LIB verification of this formula:
|
||||
*
|
||||
* (define-fun is_zero ((a (_ BitVec 32))) (_ BitVec 32)
|
||||
* (bvand (bvnot a) (bvsub a #x00000001))
|
||||
* )
|
||||
*
|
||||
* (declare-fun a () (_ BitVec 32))
|
||||
*
|
||||
* (assert (not (= (= #x00000001 (bvlshr (is_zero a) #x0000001f)) (= a #x00000000))))
|
||||
* (check-sat)
|
||||
* (get-model)
|
||||
*/
|
||||
return constant_time_msb_unsigned(~a & (a - 1));
|
||||
}
|
||||
|
||||
/* constant_time_is_zero_size_t is like |constant_time_is_zero_unsigned| but
|
||||
* operates on |size_t|. */
|
||||
static inline size_t constant_time_is_zero_size_t(size_t a) {
|
||||
return constant_time_msb_size_t(~a & (a - 1));
|
||||
}
|
||||
|
||||
static inline size_t constant_time_is_nonzero_size_t(size_t a) {
|
||||
return constant_time_is_zero_size_t(constant_time_is_zero_size_t(a));
|
||||
}
|
||||
|
||||
/* constant_time_eq_int returns 0xff..f if a == b and 0 otherwise. */
|
||||
static inline unsigned int constant_time_eq_int(int a, int b) {
|
||||
return constant_time_is_zero_unsigned((unsigned)(a) ^ (unsigned)(b));
|
||||
}
|
||||
|
||||
/* constant_time_eq_size_t acts like |constant_time_eq_int| but operates on
|
||||
* |size_t|. */
|
||||
static inline size_t constant_time_eq_size_t(size_t a, size_t b) {
|
||||
return constant_time_is_zero_size_t(a ^ b);
|
||||
}
|
||||
|
||||
/* constant_time_select_size_t returns (mask & a) | (~mask & b). When |mask| is
|
||||
* all 1s or all 0s (as returned by the methods above), the select methods
|
||||
* return either |a| (if |mask| is nonzero) or |b| (if |mask| is zero). it is
|
||||
* derived from BoringSSL's |constant_time_select|. */
|
||||
static inline size_t constant_time_select_size_t(size_t mask, size_t a,
|
||||
size_t b) {
|
||||
return (mask & a) | (~mask & b);
|
||||
}
|
||||
|
||||
/* from_be_u32_ptr returns the 32-bit big-endian-encoded value at |data|. */
|
||||
static inline uint32_t from_be_u32_ptr(const uint8_t *data) {
|
||||
#if defined(__clang__) || defined(_MSC_VER)
|
||||
/* XXX: Unlike GCC, Clang doesn't optimize compliant access to unaligned data
|
||||
* well. See https://llvm.org/bugs/show_bug.cgi?id=20605,
|
||||
* https://llvm.org/bugs/show_bug.cgi?id=17603,
|
||||
* http://blog.regehr.org/archives/702, and
|
||||
* http://blog.regehr.org/archives/1055. MSVC seems to have similar problems.
|
||||
*/
|
||||
uint32_t value;
|
||||
memcpy(&value, data, sizeof(value));
|
||||
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
|
||||
value = bswap_u32(value);
|
||||
#endif
|
||||
return value;
|
||||
#else
|
||||
return ((uint32_t)data[0] << 24) |
|
||||
((uint32_t)data[1] << 16) |
|
||||
((uint32_t)data[2] << 8) |
|
||||
((uint32_t)data[3]);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* from_be_u64_ptr returns the 64-bit big-endian-encoded value at |data|. */
|
||||
static inline uint64_t from_be_u64_ptr(const uint8_t *data) {
|
||||
#if defined(__clang__) || defined(_MSC_VER)
|
||||
/* XXX: Unlike GCC, Clang doesn't optimize compliant access to unaligned data
|
||||
* well. See https://llvm.org/bugs/show_bug.cgi?id=20605,
|
||||
* https://llvm.org/bugs/show_bug.cgi?id=17603,
|
||||
* http://blog.regehr.org/archives/702, and
|
||||
* http://blog.regehr.org/archives/1055. MSVC seems to have similar problems.
|
||||
*/
|
||||
uint64_t value;
|
||||
memcpy(&value, data, sizeof(value));
|
||||
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
|
||||
value = bswap_u64(value);
|
||||
#endif
|
||||
return value;
|
||||
#else
|
||||
return ((uint64_t)data[0] << 56) |
|
||||
((uint64_t)data[1] << 48) |
|
||||
((uint64_t)data[2] << 40) |
|
||||
((uint64_t)data[3] << 32) |
|
||||
((uint64_t)data[4] << 24) |
|
||||
((uint64_t)data[5] << 16) |
|
||||
((uint64_t)data[6] << 8) |
|
||||
((uint64_t)data[7]);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* to_be_u32_ptr writes the value |x| to the location |out| in big-endian
|
||||
order. */
|
||||
static inline void to_be_u32_ptr(uint8_t *out, uint32_t value) {
|
||||
#if defined(__clang__) || defined(_MSC_VER)
|
||||
/* XXX: Unlike GCC, Clang doesn't optimize compliant access to unaligned data
|
||||
* well. See https://llvm.org/bugs/show_bug.cgi?id=20605,
|
||||
* https://llvm.org/bugs/show_bug.cgi?id=17603,
|
||||
* http://blog.regehr.org/archives/702, and
|
||||
* http://blog.regehr.org/archives/1055. MSVC seems to have similar problems.
|
||||
*/
|
||||
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
|
||||
value = bswap_u32(value);
|
||||
#endif
|
||||
memcpy(out, &value, sizeof(value));
|
||||
#else
|
||||
out[0] = (uint8_t)(value >> 24);
|
||||
out[1] = (uint8_t)(value >> 16);
|
||||
out[2] = (uint8_t)(value >> 8);
|
||||
out[3] = (uint8_t)value;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* to_be_u64_ptr writes the value |value| to the location |out| in big-endian
|
||||
order. */
|
||||
static inline void to_be_u64_ptr(uint8_t *out, uint64_t value) {
|
||||
#if defined(__clang__) || defined(_MSC_VER)
|
||||
/* XXX: Unlike GCC, Clang doesn't optimize compliant access to unaligned data
|
||||
* well. See https://llvm.org/bugs/show_bug.cgi?id=20605,
|
||||
* https://llvm.org/bugs/show_bug.cgi?id=17603,
|
||||
* http://blog.regehr.org/archives/702, and
|
||||
* http://blog.regehr.org/archives/1055. MSVC seems to have similar problems.
|
||||
*/
|
||||
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
|
||||
value = bswap_u64(value);
|
||||
#endif
|
||||
memcpy(out, &value, sizeof(value));
|
||||
#else
|
||||
out[0] = (uint8_t)(value >> 56);
|
||||
out[1] = (uint8_t)(value >> 48);
|
||||
out[2] = (uint8_t)(value >> 40);
|
||||
out[3] = (uint8_t)(value >> 32);
|
||||
out[4] = (uint8_t)(value >> 24);
|
||||
out[5] = (uint8_t)(value >> 16);
|
||||
out[6] = (uint8_t)(value >> 8);
|
||||
out[7] = (uint8_t)value;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* from_be_u64 returns the native representation of the 64-bit
|
||||
* big-endian-encoded value |x|. */
|
||||
static inline uint64_t from_be_u64(uint64_t x) {
|
||||
#if OPENSSL_ENDIAN != OPENSSL_BIG_ENDIAN
|
||||
x = bswap_u64(x);
|
||||
#endif
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern C */
|
||||
#endif
|
||||
|
||||
#endif /* OPENSSL_HEADER_CRYPTO_INTERNAL_H */
|
||||
1921
test-generator/cbits/x25519-asm-x86_64.S
Normal file
1921
test-generator/cbits/x25519-asm-x86_64.S
Normal file
File diff suppressed because it is too large
Load Diff
244
test-generator/cbits/x25519-x86_64.c
Normal file
244
test-generator/cbits/x25519-x86_64.c
Normal file
@@ -0,0 +1,244 @@
|
||||
/* Copyright (c) 2015, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
/* This code is mostly taken from the ref10 version of Ed25519 in SUPERCOP
|
||||
* 20141124 (http://bench.cr.yp.to/supercop.html). That code is released as
|
||||
* public domain but this file has the ISC license just to keep licencing
|
||||
* simple.
|
||||
*
|
||||
* The field functions are shared by Ed25519 and X25519 where possible. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
#if defined(BORINGSSL_X25519_X86_64)
|
||||
|
||||
typedef struct { uint64_t v[5]; } fe25519;
|
||||
|
||||
/* These functions are defined in asm/x25519-x86_64.S */
|
||||
void GFp_x25519_x86_64_work_cswap(fe25519 *, uint64_t);
|
||||
void GFp_x25519_x86_64_mul(fe25519 *out, const fe25519 *a, const fe25519 *b);
|
||||
void GFp_x25519_x86_64_square(fe25519 *out, const fe25519 *a);
|
||||
void GFp_x25519_x86_64_freeze(fe25519 *);
|
||||
void GFp_x25519_x86_64_ladderstep(fe25519 *work);
|
||||
|
||||
static void fe25519_setint(fe25519 *r, unsigned v) {
|
||||
r->v[0] = v;
|
||||
r->v[1] = 0;
|
||||
r->v[2] = 0;
|
||||
r->v[3] = 0;
|
||||
r->v[4] = 0;
|
||||
}
|
||||
|
||||
/* Assumes input x being reduced below 2^255 */
|
||||
static void fe25519_pack(unsigned char r[32], const fe25519 *x) {
|
||||
fe25519 t;
|
||||
t = *x;
|
||||
GFp_x25519_x86_64_freeze(&t);
|
||||
|
||||
r[0] = (uint8_t)(t.v[0] & 0xff);
|
||||
r[1] = (uint8_t)((t.v[0] >> 8) & 0xff);
|
||||
r[2] = (uint8_t)((t.v[0] >> 16) & 0xff);
|
||||
r[3] = (uint8_t)((t.v[0] >> 24) & 0xff);
|
||||
r[4] = (uint8_t)((t.v[0] >> 32) & 0xff);
|
||||
r[5] = (uint8_t)((t.v[0] >> 40) & 0xff);
|
||||
r[6] = (uint8_t)((t.v[0] >> 48));
|
||||
|
||||
r[6] ^= (uint8_t)((t.v[1] << 3) & 0xf8);
|
||||
r[7] = (uint8_t)((t.v[1] >> 5) & 0xff);
|
||||
r[8] = (uint8_t)((t.v[1] >> 13) & 0xff);
|
||||
r[9] = (uint8_t)((t.v[1] >> 21) & 0xff);
|
||||
r[10] = (uint8_t)((t.v[1] >> 29) & 0xff);
|
||||
r[11] = (uint8_t)((t.v[1] >> 37) & 0xff);
|
||||
r[12] = (uint8_t)((t.v[1] >> 45));
|
||||
|
||||
r[12] ^= (uint8_t)((t.v[2] << 6) & 0xc0);
|
||||
r[13] = (uint8_t)((t.v[2] >> 2) & 0xff);
|
||||
r[14] = (uint8_t)((t.v[2] >> 10) & 0xff);
|
||||
r[15] = (uint8_t)((t.v[2] >> 18) & 0xff);
|
||||
r[16] = (uint8_t)((t.v[2] >> 26) & 0xff);
|
||||
r[17] = (uint8_t)((t.v[2] >> 34) & 0xff);
|
||||
r[18] = (uint8_t)((t.v[2] >> 42) & 0xff);
|
||||
r[19] = (uint8_t)((t.v[2] >> 50));
|
||||
|
||||
r[19] ^= (uint8_t)((t.v[3] << 1) & 0xfe);
|
||||
r[20] = (uint8_t)((t.v[3] >> 7) & 0xff);
|
||||
r[21] = (uint8_t)((t.v[3] >> 15) & 0xff);
|
||||
r[22] = (uint8_t)((t.v[3] >> 23) & 0xff);
|
||||
r[23] = (uint8_t)((t.v[3] >> 31) & 0xff);
|
||||
r[24] = (uint8_t)((t.v[3] >> 39) & 0xff);
|
||||
r[25] = (uint8_t)((t.v[3] >> 47));
|
||||
|
||||
r[25] ^= (uint8_t)((t.v[4] << 4) & 0xf0);
|
||||
r[26] = (uint8_t)((t.v[4] >> 4) & 0xff);
|
||||
r[27] = (uint8_t)((t.v[4] >> 12) & 0xff);
|
||||
r[28] = (uint8_t)((t.v[4] >> 20) & 0xff);
|
||||
r[29] = (uint8_t)((t.v[4] >> 28) & 0xff);
|
||||
r[30] = (uint8_t)((t.v[4] >> 36) & 0xff);
|
||||
r[31] = (uint8_t)((t.v[4] >> 44));
|
||||
}
|
||||
|
||||
static void fe25519_unpack(fe25519 *r, const uint8_t x[32]) {
|
||||
r->v[0] = x[0];
|
||||
r->v[0] += (uint64_t)x[1] << 8;
|
||||
r->v[0] += (uint64_t)x[2] << 16;
|
||||
r->v[0] += (uint64_t)x[3] << 24;
|
||||
r->v[0] += (uint64_t)x[4] << 32;
|
||||
r->v[0] += (uint64_t)x[5] << 40;
|
||||
r->v[0] += ((uint64_t)x[6] & 7) << 48;
|
||||
|
||||
r->v[1] = x[6] >> 3;
|
||||
r->v[1] += (uint64_t)x[7] << 5;
|
||||
r->v[1] += (uint64_t)x[8] << 13;
|
||||
r->v[1] += (uint64_t)x[9] << 21;
|
||||
r->v[1] += (uint64_t)x[10] << 29;
|
||||
r->v[1] += (uint64_t)x[11] << 37;
|
||||
r->v[1] += ((uint64_t)x[12] & 63) << 45;
|
||||
|
||||
r->v[2] = x[12] >> 6;
|
||||
r->v[2] += (uint64_t)x[13] << 2;
|
||||
r->v[2] += (uint64_t)x[14] << 10;
|
||||
r->v[2] += (uint64_t)x[15] << 18;
|
||||
r->v[2] += (uint64_t)x[16] << 26;
|
||||
r->v[2] += (uint64_t)x[17] << 34;
|
||||
r->v[2] += (uint64_t)x[18] << 42;
|
||||
r->v[2] += ((uint64_t)x[19] & 1) << 50;
|
||||
|
||||
r->v[3] = x[19] >> 1;
|
||||
r->v[3] += (uint64_t)x[20] << 7;
|
||||
r->v[3] += (uint64_t)x[21] << 15;
|
||||
r->v[3] += (uint64_t)x[22] << 23;
|
||||
r->v[3] += (uint64_t)x[23] << 31;
|
||||
r->v[3] += (uint64_t)x[24] << 39;
|
||||
r->v[3] += ((uint64_t)x[25] & 15) << 47;
|
||||
|
||||
r->v[4] = x[25] >> 4;
|
||||
r->v[4] += (uint64_t)x[26] << 4;
|
||||
r->v[4] += (uint64_t)x[27] << 12;
|
||||
r->v[4] += (uint64_t)x[28] << 20;
|
||||
r->v[4] += (uint64_t)x[29] << 28;
|
||||
r->v[4] += (uint64_t)x[30] << 36;
|
||||
r->v[4] += ((uint64_t)x[31] & 127) << 44;
|
||||
}
|
||||
|
||||
static void fe25519_invert(fe25519 *r, const fe25519 *x) {
|
||||
fe25519 z2;
|
||||
fe25519 z9;
|
||||
fe25519 z11;
|
||||
fe25519 z2_5_0;
|
||||
fe25519 z2_10_0;
|
||||
fe25519 z2_20_0;
|
||||
fe25519 z2_50_0;
|
||||
fe25519 z2_100_0;
|
||||
fe25519 t;
|
||||
int i;
|
||||
|
||||
/* 2 */ GFp_x25519_x86_64_square(&z2, x);
|
||||
/* 4 */ GFp_x25519_x86_64_square(&t, &z2);
|
||||
/* 8 */ GFp_x25519_x86_64_square(&t, &t);
|
||||
/* 9 */ GFp_x25519_x86_64_mul(&z9, &t, x);
|
||||
/* 11 */ GFp_x25519_x86_64_mul(&z11, &z9, &z2);
|
||||
/* 22 */ GFp_x25519_x86_64_square(&t, &z11);
|
||||
/* 2^5 - 2^0 = 31 */ GFp_x25519_x86_64_mul(&z2_5_0, &t, &z9);
|
||||
|
||||
/* 2^6 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_5_0);
|
||||
/* 2^20 - 2^10 */ for (i = 1; i < 5; i++) { GFp_x25519_x86_64_square(&t, &t); }
|
||||
/* 2^10 - 2^0 */ GFp_x25519_x86_64_mul(&z2_10_0, &t, &z2_5_0);
|
||||
|
||||
/* 2^11 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_10_0);
|
||||
/* 2^20 - 2^10 */ for (i = 1; i < 10; i++) { GFp_x25519_x86_64_square(&t, &t); }
|
||||
/* 2^20 - 2^0 */ GFp_x25519_x86_64_mul(&z2_20_0, &t, &z2_10_0);
|
||||
|
||||
/* 2^21 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_20_0);
|
||||
/* 2^40 - 2^20 */ for (i = 1; i < 20; i++) { GFp_x25519_x86_64_square(&t, &t); }
|
||||
/* 2^40 - 2^0 */ GFp_x25519_x86_64_mul(&t, &t, &z2_20_0);
|
||||
|
||||
/* 2^41 - 2^1 */ GFp_x25519_x86_64_square(&t, &t);
|
||||
/* 2^50 - 2^10 */ for (i = 1; i < 10; i++) { GFp_x25519_x86_64_square(&t, &t); }
|
||||
/* 2^50 - 2^0 */ GFp_x25519_x86_64_mul(&z2_50_0, &t, &z2_10_0);
|
||||
|
||||
/* 2^51 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_50_0);
|
||||
/* 2^100 - 2^50 */ for (i = 1; i < 50; i++) { GFp_x25519_x86_64_square(&t, &t); }
|
||||
/* 2^100 - 2^0 */ GFp_x25519_x86_64_mul(&z2_100_0, &t, &z2_50_0);
|
||||
|
||||
/* 2^101 - 2^1 */ GFp_x25519_x86_64_square(&t, &z2_100_0);
|
||||
/* 2^200 - 2^100 */ for (i = 1; i < 100; i++) {
|
||||
GFp_x25519_x86_64_square(&t, &t);
|
||||
}
|
||||
/* 2^200 - 2^0 */ GFp_x25519_x86_64_mul(&t, &t, &z2_100_0);
|
||||
|
||||
/* 2^201 - 2^1 */ GFp_x25519_x86_64_square(&t, &t);
|
||||
/* 2^250 - 2^50 */ for (i = 1; i < 50; i++) { GFp_x25519_x86_64_square(&t, &t); }
|
||||
/* 2^250 - 2^0 */ GFp_x25519_x86_64_mul(&t, &t, &z2_50_0);
|
||||
|
||||
/* 2^251 - 2^1 */ GFp_x25519_x86_64_square(&t, &t);
|
||||
/* 2^252 - 2^2 */ GFp_x25519_x86_64_square(&t, &t);
|
||||
/* 2^253 - 2^3 */ GFp_x25519_x86_64_square(&t, &t);
|
||||
|
||||
/* 2^254 - 2^4 */ GFp_x25519_x86_64_square(&t, &t);
|
||||
|
||||
/* 2^255 - 2^5 */ GFp_x25519_x86_64_square(&t, &t);
|
||||
/* 2^255 - 21 */ GFp_x25519_x86_64_mul(r, &t, &z11);
|
||||
}
|
||||
|
||||
static void mladder(fe25519 *xr, fe25519 *zr, const uint8_t s[32]) {
|
||||
fe25519 work[5];
|
||||
|
||||
work[0] = *xr;
|
||||
fe25519_setint(work + 1, 1);
|
||||
fe25519_setint(work + 2, 0);
|
||||
work[3] = *xr;
|
||||
fe25519_setint(work + 4, 1);
|
||||
|
||||
int i, j;
|
||||
uint8_t prevbit = 0;
|
||||
|
||||
j = 6;
|
||||
for (i = 31; i >= 0; i--) {
|
||||
while (j >= 0) {
|
||||
const uint8_t bit = 1 & (s[i] >> j);
|
||||
const uint64_t swap = bit ^ prevbit;
|
||||
prevbit = bit;
|
||||
GFp_x25519_x86_64_work_cswap(work + 1, swap);
|
||||
GFp_x25519_x86_64_ladderstep(work);
|
||||
j -= 1;
|
||||
}
|
||||
j = 7;
|
||||
}
|
||||
|
||||
*xr = work[1];
|
||||
*zr = work[2];
|
||||
}
|
||||
|
||||
void GFp_x25519_x86_64(uint8_t out[32], const uint8_t scalar[32],
|
||||
const uint8_t point[32]) {
|
||||
uint8_t e[32];
|
||||
memcpy(e, scalar, sizeof(e));
|
||||
|
||||
e[0] &= 248;
|
||||
e[31] &= 127;
|
||||
e[31] |= 64;
|
||||
|
||||
fe25519 t;
|
||||
fe25519 z;
|
||||
fe25519_unpack(&t, point);
|
||||
mladder(&t, &z, e);
|
||||
fe25519_invert(&z, &z);
|
||||
GFp_x25519_x86_64_mul(&t, &t, &z);
|
||||
fe25519_pack(out, &t);
|
||||
}
|
||||
|
||||
#endif /* BORINGSSL_X25519_X86_64 */
|
||||
34
test-generator/gcd.hs
Normal file
34
test-generator/gcd.hs
Normal file
@@ -0,0 +1,34 @@
|
||||
import Numeric
|
||||
|
||||
data Set = Set { r :: Integer, s :: Integer, t :: Integer }
|
||||
|
||||
step :: Set -> Set -> Set
|
||||
step old new = Set r' s' t'
|
||||
where
|
||||
quotient = r old `div` r new
|
||||
r' = r old - (r new * quotient)
|
||||
s' = s old - (s new * quotient)
|
||||
t' = t old - (t new * quotient)
|
||||
|
||||
run :: Integer -> Integer -> IO Set
|
||||
run self rhs = go (Set self 1 0) (Set rhs 0 1)
|
||||
where
|
||||
go old new | r new == 0 =
|
||||
do putStrLn "------------------------------"
|
||||
putStrLn ("res_r: " ++ showX (r old))
|
||||
putStrLn ("res_s: " ++ showX (s old))
|
||||
putStrLn ("res_t: " ++ showX (t old))
|
||||
return old
|
||||
| otherwise =
|
||||
do putStrLn "------------------------------"
|
||||
putStrLn ("old_r: " ++ showX (r old))
|
||||
putStrLn ("old_s: " ++ showX (s old))
|
||||
putStrLn ("old_t: " ++ showX (t old))
|
||||
putStrLn ("new_r: " ++ showX (r new))
|
||||
putStrLn ("new_s: " ++ showX (s new))
|
||||
putStrLn ("new_t: " ++ showX (t new))
|
||||
go new (step old new)
|
||||
|
||||
showX :: Integer -> String
|
||||
showX x | x < 0 = "-" ++ showX (abs x)
|
||||
| otherwise = showHex x ""
|
||||
32
test-generator/test-generator.cabal
Normal file
32
test-generator/test-generator.cabal
Normal file
@@ -0,0 +1,32 @@
|
||||
cabal-version: >=1.10
|
||||
-- Initial package description 'test-generator.cabal' generated by 'cabal
|
||||
-- init'. For further documentation, see
|
||||
-- http://haskell.org/cabal/users-guide/
|
||||
|
||||
name: test-generator
|
||||
version: 0.1.0.0
|
||||
synopsis: Test generation helper
|
||||
-- description:
|
||||
homepage: http://github.com/acw
|
||||
-- bug-reports:
|
||||
license: ISC
|
||||
license-file: ../LICENSE
|
||||
author: Adam Wick
|
||||
maintainer: awick@uhsure.com
|
||||
-- copyright:
|
||||
category: Testing
|
||||
build-type: Simple
|
||||
extra-source-files: CHANGELOG.md
|
||||
|
||||
executable gen-tests
|
||||
main-is: Main.hs
|
||||
other-modules: Database, DSA, ECDSATesting, ED25519, ED25519.PrecompPoints, Math, RFC6979, RSA, Task, Utils
|
||||
-- other-extensions:
|
||||
build-depends: base >=4.11 && < 4.14, ascii-progress, bytestring, containers, crypto-api, cryptonite, directory, DSA, filepath, integer-gmp, memory, random
|
||||
hs-source-dirs: .
|
||||
c-sources: cbits/curve25519.c cbits/x25519-x86_64.c cbits/x25519-asm-x86_64.S
|
||||
include-dirs: cbits
|
||||
default-language: Haskell2010
|
||||
ghc-options: -Wall -O2 -threaded -rtsopts -with-rtsopts=-N
|
||||
if os(Windows) || !arch(x86_64)
|
||||
buildable: False
|
||||
3609
testdata/dsa/signL1024N160.test
vendored
Normal file
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
909
testdata/dsa/signL2048N224.test
vendored
Normal 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
459
testdata/dsa/signL2048N256.test
vendored
Normal 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
234
testdata/dsa/signL3072N256.test
vendored
Normal 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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user