Compare commits
66 Commits
ssh
...
variable_c
| Author | SHA1 | Date | |
|---|---|---|---|
| bdf7f81b20 | |||
| dde1092f49 | |||
| 6fabbe6af1 | |||
| f83b8a3fe5 | |||
| 61f4a009a0 | |||
| 1d67b4c775 | |||
| 81ccf3e06b | |||
| 219641da5e | |||
| f0f4891abe | |||
| 3d767c3e13 | |||
| a2b4baa087 | |||
| 213c75ad51 | |||
| 29a14b39e6 | |||
| c34629aa47 | |||
| b01c59a094 | |||
| fa04efa5fe | |||
| bd0ddd848b | |||
| 9c60a3bc3e | |||
| 7c28727f73 | |||
| c9092ffe6a | |||
| 296bb6ad90 | |||
| d9df506920 | |||
| 2eacea8ff9 | |||
| 153d88237f | |||
| 5758b6e22b | |||
| baa70a6ce6 | |||
| b5a5cbdd98 | |||
| 4985426e74 | |||
| c45235473a | |||
| b1c659087d | |||
| 0d08f53d70 | |||
| 109e23789a | |||
| 551ebeac3b | |||
| 017392ff6c | |||
| d98baa1381 | |||
| 330dabe017 | |||
| 675f8adc7e | |||
| 5868553c74 | |||
| ceb1e9eb58 | |||
| 3cd37a881d | |||
| 2f16a45784 | |||
| f06f83583f | |||
| ae6a33f4b8 | |||
| 8a4693d30d | |||
| 20592a3d65 | |||
| acda294bac | |||
| c4409d9c25 | |||
| ec0f0dc597 | |||
| 80f57b9f22 | |||
| fa33de88db | |||
| b92b47d971 | |||
| a4e65fa35f | |||
| 30bff2a22f | |||
| 185881df91 | |||
| 824718eafc | |||
| bfdede4241 | |||
| d6c59b5037 | |||
| fd9254a322 | |||
| f9b25ab03a | |||
| d53cdb6c97 | |||
| a595eb349d | |||
| 03765c2ff6 | |||
| edd7c7fee3 | |||
| 6b9783c69a | |||
| 9c4ea7ae26 | |||
| 7a8bb7b4fd |
14
.gitignore
vendored
14
.gitignore
vendored
@@ -11,3 +11,17 @@ Cargo.lock
|
|||||||
|
|
||||||
# And these are just annoying
|
# And these are just annoying
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# And some Haskell stuff, because I can't shake it!
|
||||||
|
**/cabal.sandbox.config
|
||||||
|
**/.cabal-sandbox
|
||||||
|
|
||||||
|
# Test generation leavings
|
||||||
|
**/*.hi
|
||||||
|
**/*.o
|
||||||
|
**/gen
|
||||||
|
**/*.class
|
||||||
|
**/*.jar
|
||||||
|
|
||||||
|
# And I started playing with IDEs, so ...
|
||||||
|
.vscode
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
language: rust
|
language: rust
|
||||||
rust:
|
rust:
|
||||||
|
- stable
|
||||||
|
- beta
|
||||||
- nightly
|
- nightly
|
||||||
|
script:
|
||||||
|
- cargo build --verbose
|
||||||
|
- travis_wait 25 cargo test --verbose
|
||||||
|
|||||||
@@ -9,7 +9,14 @@ license-file = "LICENSE"
|
|||||||
repository = "https://github.com/acw/simple_crypto"
|
repository = "https://github.com/acw/simple_crypto"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
base64 = "^0.9.1"
|
||||||
|
digest = "^0.7.1"
|
||||||
|
hmac = "^0.5.0"
|
||||||
|
num = "^0.1.42"
|
||||||
rand = "^0.3"
|
rand = "^0.3"
|
||||||
|
sha-1 = "^0.7.0"
|
||||||
|
sha2 = "^0.7.0"
|
||||||
|
simple_asn1 = "^0.1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
quickcheck = "^0.4.1"
|
quickcheck = "^0.4.1"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
126
src/cryptonum/complete_arith.rs
Normal file
126
src/cryptonum/complete_arith.rs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
macro_rules! derive_arithmetic_operators
|
||||||
|
{
|
||||||
|
($type: ident, $cl: ident, $fn: ident, $asncl: ident, $asnfn: ident) => {
|
||||||
|
impl $asncl for $type {
|
||||||
|
fn $asnfn(&mut self, other: $type) {
|
||||||
|
self.$asnfn(&other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $cl for $type {
|
||||||
|
type Output = $type;
|
||||||
|
|
||||||
|
fn $fn(self, other: $type) -> $type {
|
||||||
|
let mut res = self.clone();
|
||||||
|
res.$asnfn(&other);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> $cl<&'a $type> for $type {
|
||||||
|
type Output = $type;
|
||||||
|
|
||||||
|
fn $fn(self, other: &$type) -> $type {
|
||||||
|
let mut res = self.clone();
|
||||||
|
res.$asnfn(other);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> $cl<$type> for &'a $type {
|
||||||
|
type Output = $type;
|
||||||
|
|
||||||
|
fn $fn(self, other: $type) -> $type {
|
||||||
|
let mut res = self.clone();
|
||||||
|
res.$asnfn(&other);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a,'b> $cl<&'a $type> for &'b $type {
|
||||||
|
type Output = $type;
|
||||||
|
|
||||||
|
fn $fn(self, other: &$type) -> $type {
|
||||||
|
let mut res = self.clone();
|
||||||
|
res.$asnfn(other);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! derive_shift_operators
|
||||||
|
{
|
||||||
|
($type: ident, $asncl: ident, $cl: ident,
|
||||||
|
$asnfn: ident, $fn: ident,
|
||||||
|
$base: ident) =>
|
||||||
|
{
|
||||||
|
impl $asncl<$base> for $type {
|
||||||
|
fn $asnfn(&mut self, rhs: $base) {
|
||||||
|
self.$asnfn(rhs as u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
derive_shifts_from_shift_assign!($type, $asncl, $cl,
|
||||||
|
$asnfn, $fn,
|
||||||
|
$base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! derive_shifts_from_shift_assign
|
||||||
|
{
|
||||||
|
($type: ident, $asncl: ident, $cl: ident,
|
||||||
|
$asnfn: ident, $fn: ident,
|
||||||
|
$base: ident) =>
|
||||||
|
{
|
||||||
|
impl $cl<$base> for $type {
|
||||||
|
type Output = $type;
|
||||||
|
|
||||||
|
fn $fn(self, rhs: $base) -> $type {
|
||||||
|
let mut copy = self.clone();
|
||||||
|
copy.$asnfn(rhs as u64);
|
||||||
|
copy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> $cl<$base> for &'a $type {
|
||||||
|
type Output = $type;
|
||||||
|
|
||||||
|
fn $fn(self, rhs: $base) -> $type {
|
||||||
|
let mut copy = self.clone();
|
||||||
|
copy.$asnfn(rhs as u64);
|
||||||
|
copy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! derive_signed_shift_operators
|
||||||
|
{
|
||||||
|
($type: ident, $base: ident, $signed_base: ident) => {
|
||||||
|
impl ShlAssign<$signed_base> for $type {
|
||||||
|
fn shl_assign(&mut self, rhs: $signed_base) {
|
||||||
|
if rhs < 0 {
|
||||||
|
self.shr_assign(-rhs);
|
||||||
|
} else {
|
||||||
|
self.shl_assign(rhs as $base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShrAssign<$signed_base> for $type {
|
||||||
|
fn shr_assign(&mut self, rhs: $signed_base) {
|
||||||
|
if rhs < 0 {
|
||||||
|
self.shl_assign(-rhs);
|
||||||
|
} else {
|
||||||
|
self.shr_assign(rhs as $base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
derive_shifts_from_shift_assign!($type, ShlAssign, Shl,
|
||||||
|
shl_assign, shl, $signed_base);
|
||||||
|
derive_shifts_from_shift_assign!($type, ShrAssign, Shr,
|
||||||
|
shr_assign, shr, $signed_base);
|
||||||
|
}
|
||||||
|
}
|
||||||
85
src/cryptonum/conversions.rs
Normal file
85
src/cryptonum/conversions.rs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
macro_rules! define_from
|
||||||
|
{
|
||||||
|
($type: ident, $base: ident) => {
|
||||||
|
impl From<$base> for $type {
|
||||||
|
fn from(x: $base) -> $type {
|
||||||
|
if x == 0 {
|
||||||
|
UCN{ contents: Vec::new() }
|
||||||
|
} else {
|
||||||
|
UCN{ contents: vec![x as u64] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! define_signed_from
|
||||||
|
{
|
||||||
|
($type: ident, $base: ident, $uns: ident) => {
|
||||||
|
impl From<$uns> for $type {
|
||||||
|
fn from(x: $uns) -> $type {
|
||||||
|
SCN{ negative: false, value: UCN::from(x) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$base> for $type {
|
||||||
|
fn from(x: $base) -> $type {
|
||||||
|
let neg = x < 0;
|
||||||
|
let absx = x.abs();
|
||||||
|
SCN{ negative: neg, value: UCN::from(absx as $uns) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! define_into
|
||||||
|
{
|
||||||
|
($type: ident, $base: ident) => {
|
||||||
|
impl<'a> From<&'a $type> for $base {
|
||||||
|
fn from(x: &$type) -> $base {
|
||||||
|
if x.contents.is_empty() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
x.contents[0] as $base
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$type> for $base {
|
||||||
|
fn from(x: $type) -> $base {
|
||||||
|
$base::from(&x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! define_signed_into
|
||||||
|
{
|
||||||
|
($type: ident, $base: ident, $uns: ident) => {
|
||||||
|
impl<'a> From<&'a $type> for $uns {
|
||||||
|
fn from(x: &$type) -> $uns {
|
||||||
|
let res: $uns = $uns::from(&x.value);
|
||||||
|
if x.negative { 0-res } else { res }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a $type> for $base {
|
||||||
|
fn from(x: &$type) -> $base {
|
||||||
|
let res: $uns = $uns::from(&x.value);
|
||||||
|
if x.negative { (0-res) as $base } else { res as $base }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$type> for $uns {
|
||||||
|
fn from(x: $type) -> $uns {
|
||||||
|
$uns::from(&x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$type> for $base {
|
||||||
|
fn from(x: $type) -> $base {
|
||||||
|
$base::from(&x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,71 +0,0 @@
|
|||||||
use cryptonum::signed::Signed;
|
|
||||||
use cryptonum::traits::*;
|
|
||||||
use std::ops::*;
|
|
||||||
|
|
||||||
pub fn modinv<'a,T>(e: &T, phi: &T) -> T
|
|
||||||
where
|
|
||||||
T: Clone + CryptoNumBase + Ord,
|
|
||||||
T: AddAssign + SubAssign + MulAssign + DivAssign,
|
|
||||||
T: Add<Output=T> + Sub<Output=T> + Mul<Output=T> + Div<Output=T>,
|
|
||||||
&'a T: Sub<Output=T>,
|
|
||||||
T: 'a
|
|
||||||
{
|
|
||||||
let (_, mut x, _) = extended_euclidean(e, phi);
|
|
||||||
let int_phi = Signed::<T>::new(phi.clone());
|
|
||||||
while x.is_negative() {
|
|
||||||
x += &int_phi;
|
|
||||||
}
|
|
||||||
x.abs()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn modexp<T>(b: &T, e: &T, m: &T) -> T
|
|
||||||
{
|
|
||||||
panic!("modexp")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extended_euclidean<T>(a: &T, b: &T) -> (Signed<T>, Signed<T>, Signed<T>)
|
|
||||||
where
|
|
||||||
T: Clone + CryptoNumBase + Div + Mul + Sub
|
|
||||||
{
|
|
||||||
let posinta = Signed::<T>::new(a.clone());
|
|
||||||
let posintb = Signed::<T>::new(b.clone());
|
|
||||||
let (mut d, mut x, mut y) = egcd(&posinta, &posintb);
|
|
||||||
|
|
||||||
if d.is_negative() {
|
|
||||||
d.negate();
|
|
||||||
x.negate();
|
|
||||||
y.negate();
|
|
||||||
}
|
|
||||||
|
|
||||||
(d, x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn egcd<T>(a: &Signed<T>, b: &Signed<T>) -> (Signed<T>,Signed<T>,Signed<T>)
|
|
||||||
where
|
|
||||||
T: Clone + CryptoNumBase + Div + Mul + Sub
|
|
||||||
{
|
|
||||||
let mut s = Signed::<T>::zero();
|
|
||||||
let mut old_s = Signed::<T>::from_u8(1);
|
|
||||||
let mut t = Signed::<T>::from_u8(1);
|
|
||||||
let mut old_t = Signed::<T>::zero();
|
|
||||||
let mut r = b.clone();
|
|
||||||
let mut old_r = a.clone();
|
|
||||||
|
|
||||||
while !r.is_zero() {
|
|
||||||
let quotient = old_r.clone() / r.clone();
|
|
||||||
|
|
||||||
let prov_r = r.clone();
|
|
||||||
let prov_s = s.clone();
|
|
||||||
let prov_t = t.clone();
|
|
||||||
|
|
||||||
r = old_r - (r * "ient);
|
|
||||||
s = old_s - (s * "ient);
|
|
||||||
t = old_t - (t * "ient);
|
|
||||||
|
|
||||||
old_r = prov_r;
|
|
||||||
old_s = prov_s;
|
|
||||||
old_t = prov_t;
|
|
||||||
}
|
|
||||||
|
|
||||||
(old_r, old_s, old_t)
|
|
||||||
}
|
|
||||||
187
src/cryptonum/gold_tests.rs
Normal file
187
src/cryptonum/gold_tests.rs
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
use cryptonum::unsigned::BarrettUCN;
|
||||||
|
use testing::{make_signed,make_unsigned,run_test};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unsigned_sum_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/unsigned_add.tests", 3, |scase| {
|
||||||
|
let case = make_unsigned(scase);
|
||||||
|
let x = case.get("x").unwrap();
|
||||||
|
let y = case.get("y").unwrap();
|
||||||
|
let z = case.get("z").unwrap();
|
||||||
|
let res = x + y;
|
||||||
|
assert_eq!(res, *z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn signed_sum_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/signed_add.tests", 3, |bcase| {
|
||||||
|
let case = make_signed(bcase);
|
||||||
|
let x = case.get("x").unwrap();
|
||||||
|
let y = case.get("y").unwrap();
|
||||||
|
let z = case.get("z").unwrap();
|
||||||
|
assert_eq!(x + y, *z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unsigned_sub_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/unsigned_sub.tests", 3, |scase| {
|
||||||
|
let case = make_unsigned(scase);
|
||||||
|
let x = case.get("x").unwrap();
|
||||||
|
let y = case.get("y").unwrap();
|
||||||
|
let z = case.get("z").unwrap();
|
||||||
|
assert_eq!(x - y, *z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn signed_sub_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/signed_sub.tests", 3, |bcase| {
|
||||||
|
let case = make_signed(bcase);
|
||||||
|
let x = case.get("x").unwrap();
|
||||||
|
let y = case.get("y").unwrap();
|
||||||
|
let z = case.get("z").unwrap();
|
||||||
|
assert_eq!(x - y, *z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unsigned_mul_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/unsigned_mul.tests", 3, |scase| {
|
||||||
|
let case = make_unsigned(scase);
|
||||||
|
let x = case.get("x").unwrap();
|
||||||
|
let y = case.get("y").unwrap();
|
||||||
|
let z = case.get("z").unwrap();
|
||||||
|
assert_eq!(x * y, *z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn signed_mul_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/signed_mul.tests", 3, |bcase| {
|
||||||
|
let case = make_signed(bcase);
|
||||||
|
let x = case.get("x").unwrap();
|
||||||
|
let y = case.get("y").unwrap();
|
||||||
|
let z = case.get("z").unwrap();
|
||||||
|
assert_eq!(x * y, *z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unsigned_div_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/unsigned_div.tests", 3, |scase| {
|
||||||
|
let case = make_unsigned(scase);
|
||||||
|
let x = case.get("x").unwrap();
|
||||||
|
let y = case.get("y").unwrap();
|
||||||
|
let z = case.get("z").unwrap();
|
||||||
|
assert_eq!(x / y, *z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn signed_div_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/signed_div.tests", 3, |bcase| {
|
||||||
|
let case = make_signed(bcase);
|
||||||
|
let x = case.get("x").unwrap();
|
||||||
|
let y = case.get("y").unwrap();
|
||||||
|
let z = case.get("z").unwrap();
|
||||||
|
assert_eq!(x / y, *z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unsigned_mod_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/unsigned_mod.tests", 3, |scase| {
|
||||||
|
let case = make_unsigned(scase);
|
||||||
|
let x = case.get("x").unwrap();
|
||||||
|
let y = case.get("y").unwrap();
|
||||||
|
let z = case.get("z").unwrap();
|
||||||
|
assert_eq!(x % y, *z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn signed_mod_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/signed_mod.tests", 3, |bcase| {
|
||||||
|
let case = make_signed(bcase);
|
||||||
|
let x = case.get("x").unwrap();
|
||||||
|
let y = case.get("y").unwrap();
|
||||||
|
let z = case.get("z").unwrap();
|
||||||
|
assert_eq!(x % y, *z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn modular_exponentiation_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/modexp.tests", 4, |scase| {
|
||||||
|
let case = make_unsigned(scase);
|
||||||
|
let a = case.get("a").unwrap();
|
||||||
|
let b = case.get("b").unwrap();
|
||||||
|
let m = case.get("m").unwrap();
|
||||||
|
let z = case.get("z").unwrap();
|
||||||
|
assert_eq!(a.modexp(&b, &m), *z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fast_modular_exponentiation_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/fastmodexp.tests", 6, |scase| {
|
||||||
|
let case = make_unsigned(scase);
|
||||||
|
let a = case.get("a").unwrap();
|
||||||
|
let b = case.get("b").unwrap();
|
||||||
|
let kbig = case.get("k").unwrap();
|
||||||
|
let k = usize::from(kbig);
|
||||||
|
let m = case.get("m").unwrap();
|
||||||
|
let u = case.get("u").unwrap();
|
||||||
|
let z = case.get("z").unwrap();
|
||||||
|
let mu = BarrettUCN{ k: k, u: u.clone(), m: m.clone() };
|
||||||
|
assert_eq!(a.fastmodexp(&b, &mu), *z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn barrett_reduction_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/barrett.tests", 5, |scase| {
|
||||||
|
let case = make_unsigned(scase);
|
||||||
|
let kbig = case.get("k").unwrap();
|
||||||
|
let m = case.get("m").unwrap();
|
||||||
|
let r = case.get("r").unwrap();
|
||||||
|
let u = case.get("u").unwrap();
|
||||||
|
let v = case.get("v").unwrap();
|
||||||
|
let k = usize::from(kbig);
|
||||||
|
let barrett = m.barrett_u();
|
||||||
|
let result = v.reduce(&barrett);
|
||||||
|
assert_eq!(barrett.k, k);
|
||||||
|
assert_eq!(&barrett.u, u);
|
||||||
|
assert_eq!(&barrett.m, m);
|
||||||
|
assert_eq!(&result, r);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn modular_inverse_test()
|
||||||
|
{
|
||||||
|
run_test("tests/math/modinv.tests", 3, |scase| {
|
||||||
|
let case = make_unsigned(scase);
|
||||||
|
let a = case.get("x").unwrap();
|
||||||
|
let m = case.get("y").unwrap();
|
||||||
|
let r = case.get("z").unwrap();
|
||||||
|
let result = a.modinv(m);
|
||||||
|
assert_eq!(r, &result);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,18 +1,13 @@
|
|||||||
//! # 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.
|
|
||||||
mod core;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod builder;
|
mod conversions;
|
||||||
//mod extended_math;
|
#[macro_use]
|
||||||
// mod primes;
|
mod complete_arith;
|
||||||
|
mod primes;
|
||||||
mod signed;
|
mod signed;
|
||||||
mod traits;
|
|
||||||
mod unsigned;
|
mod unsigned;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod gold_tests;
|
||||||
|
|
||||||
// pub use self::extended_math::{modexp,modinv,extended_euclidean,egcd};
|
pub use self::signed::SCN;
|
||||||
// pub use self::primes::{probably_prime};
|
pub use self::unsigned::{BarrettUCN,UCN};
|
||||||
pub use self::signed::{Signed};
|
pub use self::primes::*;
|
||||||
pub use self::unsigned::{U512,U1024,U2048,U3072,U4096,U7680,U8192,U15360};
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
use cryptonum::extended_math::modexp;
|
use cryptonum::unsigned::UCN;
|
||||||
use cryptonum::traits::*;
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::ops::*;
|
|
||||||
|
|
||||||
static SMALL_PRIMES: [u64; 310] = [
|
static SMALL_PRIMES: [u32; 310] = [
|
||||||
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
|
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
|
||||||
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
|
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
|
||||||
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
|
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
|
||||||
@@ -37,29 +35,47 @@ static SMALL_PRIMES: [u64; 310] = [
|
|||||||
1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053];
|
1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053];
|
||||||
|
|
||||||
|
|
||||||
pub fn probably_prime<G,T>(x: &T, g: &mut G, iters: usize) -> bool
|
impl UCN {
|
||||||
|
pub fn generate_prime<F,G>(rng: &mut G,
|
||||||
|
bitlen: usize,
|
||||||
|
iterations: usize,
|
||||||
|
check_value: F)
|
||||||
|
-> UCN
|
||||||
where
|
where
|
||||||
G: Rng,
|
G: Rng,
|
||||||
T: Clone + PartialOrd + Rem + Sub,
|
F: Fn(UCN) -> Option<UCN>
|
||||||
T: CryptoNumBase + CryptoNumSerialization,
|
{
|
||||||
{
|
let one = UCN::from(1 as u8);
|
||||||
|
|
||||||
|
assert!((bitlen % 64) == 0);
|
||||||
|
loop {
|
||||||
|
let base = random_number(rng, bitlen);
|
||||||
|
let candidate = base | &one;
|
||||||
|
|
||||||
|
if let Some(proposed) = check_value(candidate) {
|
||||||
|
if proposed.probably_prime(rng, bitlen, iterations) {
|
||||||
|
return proposed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn probably_prime<G: Rng>(&self, g: &mut G, size: usize, iters: usize)
|
||||||
|
-> bool
|
||||||
|
{
|
||||||
for tester in SMALL_PRIMES.iter() {
|
for tester in SMALL_PRIMES.iter() {
|
||||||
if (x % T::from_u64(*tester)) == T::zero() {
|
if (self % UCN::from(*tester)).is_zero() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
miller_rabin(g, x, iters)
|
miller_rabin(g, &self, size, iters)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn miller_rabin<G,T>(g: &mut G, n: T, iters: usize) -> bool
|
fn miller_rabin<G: Rng>(g: &mut G, n: &UCN, size: usize, iters: usize) -> bool {
|
||||||
where
|
let one = UCN::from(1 as u8);
|
||||||
G: Rng,
|
let two = UCN::from(2 as u8);
|
||||||
T: Clone + PartialEq + PartialOrd + Sub,
|
let nm1 = n - &one;
|
||||||
T: CryptoNumBase + CryptoNumSerialization,
|
|
||||||
{
|
|
||||||
let one = T::from_u8(1);
|
|
||||||
let two = T::from_u8(2);
|
|
||||||
let nm1 = n - one;
|
|
||||||
// Quoth Wikipedia:
|
// Quoth Wikipedia:
|
||||||
// write n - 1 as 2^r*d with d odd by factoring powers of 2 from n - 1
|
// 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 d = nm1.clone();
|
||||||
@@ -67,14 +83,14 @@ fn miller_rabin<G,T>(g: &mut G, n: T, iters: usize) -> bool
|
|||||||
while d.is_even() {
|
while d.is_even() {
|
||||||
d >>= 1;
|
d >>= 1;
|
||||||
r += 1;
|
r += 1;
|
||||||
assert!(r < n.bit_size());
|
assert!(r < n.bits());
|
||||||
}
|
}
|
||||||
// WitnessLoop: repeat k times
|
// WitnessLoop: repeat k times
|
||||||
'WitnessLoop: for _k in 0..iters {
|
'WitnessLoop: for _k in 0..iters {
|
||||||
// pick a random integer a in the range [2, n - 2]
|
// pick a random integer a in the range [2, n - 2]
|
||||||
let a = random_in_range(g, &two, &nm1);
|
let a = random_in_range(g, size, &two, &nm1);
|
||||||
// x <- a^d mod n
|
// x <- a^d mod n
|
||||||
let mut x = modexp(&a, &d, &n);
|
let mut x = a.modexp(&d, &n);
|
||||||
// if x = 1 or x = n - 1 then
|
// if x = 1 or x = n - 1 then
|
||||||
if (&x == &one) || (&x == &nm1) {
|
if (&x == &one) || (&x == &nm1) {
|
||||||
// continue WitnessLoop
|
// continue WitnessLoop
|
||||||
@@ -83,7 +99,7 @@ fn miller_rabin<G,T>(g: &mut G, n: T, iters: usize) -> bool
|
|||||||
// repeat r - 1 times:
|
// repeat r - 1 times:
|
||||||
for _i in 0..r {
|
for _i in 0..r {
|
||||||
// x <- x^2 mod n
|
// x <- x^2 mod n
|
||||||
x = modexp(&x, &two, &n);
|
x = x.modexp(&two, &n);
|
||||||
// if x = 1 then
|
// if x = 1 then
|
||||||
if &x == &one {
|
if &x == &one {
|
||||||
// return composite
|
// return composite
|
||||||
@@ -102,14 +118,11 @@ fn miller_rabin<G,T>(g: &mut G, n: T, iters: usize) -> bool
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_in_range<G,T>(rng: &mut G, min: &T, max: &T) -> T
|
fn random_in_range<G: Rng>(rng: &mut G, bitlen: usize, min: &UCN, max: &UCN)
|
||||||
where
|
-> UCN
|
||||||
G: Rng,
|
|
||||||
T: CryptoNumSerialization + PartialOrd
|
|
||||||
{
|
{
|
||||||
assert_eq!(min.byte_size(), max.byte_size());
|
|
||||||
loop {
|
loop {
|
||||||
let candidate = random_number(rng, min.byte_size());
|
let candidate = random_number(rng, bitlen);
|
||||||
|
|
||||||
if (&candidate >= min) && (&candidate < max) {
|
if (&candidate >= min) && (&candidate < max) {
|
||||||
return candidate;
|
return candidate;
|
||||||
@@ -117,13 +130,10 @@ fn random_in_range<G,T>(rng: &mut G, min: &T, max: &T) -> T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_number<G,T>(rng: &mut G, bytelen: usize) -> T
|
fn random_number<G: Rng>(rng: &mut G, bitlen: usize) -> UCN {
|
||||||
where
|
assert!(bitlen % 64 == 0);
|
||||||
G: Rng,
|
let wordlen = bitlen / 64;
|
||||||
T: CryptoNumSerialization
|
let components = rng.gen_iter().take(wordlen).collect();
|
||||||
{
|
UCN{ contents: components }
|
||||||
let components: Vec<u8> = rng.gen_iter().take(bytelen).collect();
|
|
||||||
T::from_bytes(&components)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,431 +1,406 @@
|
|||||||
use cryptonum::traits::*;
|
use cryptonum::unsigned::{BarrettUCN,UCN,divmod};
|
||||||
|
use num::BigInt;
|
||||||
|
use num::bigint::Sign;
|
||||||
|
use std::fmt;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt::{Debug,Error,Formatter};
|
use std::fmt::Write;
|
||||||
use std::ops::*;
|
use std::ops::*;
|
||||||
|
|
||||||
pub struct Signed<T: Sized> {
|
/// In case you were wondering, it stands for "Signed Crypto Num".
|
||||||
positive: bool,
|
#[derive(Clone,Debug,PartialEq,Eq)]
|
||||||
value: T
|
pub struct SCN {
|
||||||
|
pub(crate) negative: bool,
|
||||||
|
pub(crate) value: UCN
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Signed<T> {
|
impl SCN {
|
||||||
pub fn new(v: T) -> Signed<T> {
|
pub fn zero() -> SCN {
|
||||||
Signed{ positive: true, value: v }
|
SCN{ negative: false, value: UCN::zero() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn abs(&self) -> T
|
pub fn is_zero(&self) -> bool {
|
||||||
where T: Clone
|
|
||||||
{
|
|
||||||
self.value.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_positive(&self) -> bool
|
|
||||||
where T: CryptoNumBase
|
|
||||||
{
|
|
||||||
self.positive && !self.value.is_zero()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_negative(&self) -> bool
|
|
||||||
where T: CryptoNumBase
|
|
||||||
{
|
|
||||||
!self.positive && !self.value.is_zero()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn negate(&mut self)
|
|
||||||
{
|
|
||||||
self.positive = !self.positive;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: CryptoNumBase> CryptoNumBase for Signed<T> {
|
|
||||||
fn zero() -> Signed<T> {
|
|
||||||
Signed{ positive: true, value: T::zero() }
|
|
||||||
}
|
|
||||||
fn max_value() -> Signed<T> {
|
|
||||||
Signed{ positive: true, value: T::max_value() }
|
|
||||||
}
|
|
||||||
fn is_zero(&self) -> bool {
|
|
||||||
self.value.is_zero()
|
self.value.is_zero()
|
||||||
}
|
}
|
||||||
fn is_odd(&self) -> bool {
|
|
||||||
self.value.is_odd()
|
|
||||||
}
|
|
||||||
fn is_even(&self) -> bool {
|
|
||||||
self.value.is_even()
|
|
||||||
}
|
|
||||||
fn from_u8(x: u8) -> Signed<T> {
|
|
||||||
Signed{ positive: true, value: T::from_u8(x) }
|
|
||||||
}
|
|
||||||
fn to_u8(&self) -> u8 {
|
|
||||||
self.value.to_u8()
|
|
||||||
}
|
|
||||||
fn from_u16(x: u16) -> Signed<T> {
|
|
||||||
Signed{ positive: true, value: T::from_u16(x) }
|
|
||||||
}
|
|
||||||
fn to_u16(&self) -> u16 {
|
|
||||||
self.value.to_u16()
|
|
||||||
}
|
|
||||||
fn from_u32(x: u32) -> Signed<T> {
|
|
||||||
Signed{ positive: true, value: T::from_u32(x) }
|
|
||||||
}
|
|
||||||
fn to_u32(&self) -> u32 {
|
|
||||||
self.value.to_u32()
|
|
||||||
}
|
|
||||||
fn from_u64(x: u64) -> Signed<T> {
|
|
||||||
Signed{ positive: true, value: T::from_u64(x) }
|
|
||||||
}
|
|
||||||
fn to_u64(&self) -> u64 {
|
|
||||||
self.value.to_u64()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: CryptoNumFastMod> CryptoNumFastMod for Signed<T> {
|
pub fn is_negative(&self) -> bool {
|
||||||
type BarrettMu = T::BarrettMu;
|
self.negative
|
||||||
|
}
|
||||||
|
|
||||||
fn barrett_mu(&self) -> Option<T::BarrettMu> {
|
pub fn from_str(x: &str) -> SCN {
|
||||||
if self.positive {
|
if x.get(0..1) == Some("-") {
|
||||||
self.value.barrett_mu()
|
SCN{ negative: true, value: UCN::from_str(&x[1..]) }
|
||||||
} else {
|
} else {
|
||||||
None
|
SCN{ negative: false, value: UCN::from_str(x) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fastmod(&self, mu: &T::BarrettMu) -> Signed<T> {
|
fn cleanup(&mut self) {
|
||||||
Signed{ positive: self.positive, value: self.value.fastmod(&mu) }
|
if self.value.is_zero() {
|
||||||
|
self.negative = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn egcd(self, b: SCN) -> (SCN, SCN, SCN) {
|
||||||
|
let mut s = SCN::zero();
|
||||||
|
let mut old_s = SCN::from(1 as u8);
|
||||||
|
let mut t = SCN::from(1 as u8);
|
||||||
|
let mut old_t = SCN::zero();
|
||||||
|
let mut r = b;
|
||||||
|
let mut old_r = self;
|
||||||
|
|
||||||
|
while !r.is_zero() {
|
||||||
|
let quotient = old_r.clone() / r.clone();
|
||||||
|
|
||||||
|
let prov_r = r.clone();
|
||||||
|
let prov_s = s.clone();
|
||||||
|
let prov_t = t.clone();
|
||||||
|
|
||||||
|
r = old_r - (r * "ient);
|
||||||
|
s = old_s - (s * "ient);
|
||||||
|
t = old_t - (t * "ient);
|
||||||
|
|
||||||
|
old_r = prov_r;
|
||||||
|
old_s = prov_s;
|
||||||
|
old_t = prov_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
(old_r, old_s, old_t)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reduce(&self, m: &BarrettUCN) -> SCN {
|
||||||
|
println!("signed reduce");
|
||||||
|
SCN{ negative: false, value: self.value.reduce(m) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn divmod(&self, x: &SCN, m: &BarrettUCN) -> SCN {
|
||||||
|
println!("STEP1");
|
||||||
|
let xmod = x.reduce(m);
|
||||||
|
println!("STEP2");
|
||||||
|
assert!(!xmod.negative);
|
||||||
|
println!("STEP3");
|
||||||
|
let i = xmod.value.modinv(&m.m);
|
||||||
|
println!("STEP4");
|
||||||
|
let si = SCN::from(i);
|
||||||
|
println!("STEP5");
|
||||||
|
let yi = self * si;
|
||||||
|
println!("STEP6: {:X}", yi);
|
||||||
|
println!(" mod {:X}", m.m);
|
||||||
|
let res = yi.reduce(m);
|
||||||
|
println!("STEP7");
|
||||||
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> Clone for Signed<T> {
|
impl fmt::UpperHex for SCN {
|
||||||
fn clone(&self) -> Signed<T> {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(),fmt::Error> {
|
||||||
Signed{ positive: self.positive, value: self.value.clone() }
|
if self.negative {
|
||||||
|
fmt.write_char('-')?;
|
||||||
|
}
|
||||||
|
self.value.fmt(fmt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a,T: PartialEq> PartialEq<&'a Signed<T>> for Signed<T> {
|
//------------------------------------------------------------------------------
|
||||||
fn eq(&self, other: &&Signed<T>) -> bool {
|
//
|
||||||
(self.positive == other.positive) && (self.value == other.value)
|
// Conversions to/from crypto nums.
|
||||||
|
//
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
define_signed_from!(SCN, i8, u8);
|
||||||
|
define_signed_from!(SCN, i16, u16);
|
||||||
|
define_signed_from!(SCN, i32, u32);
|
||||||
|
define_signed_from!(SCN, i64, u64);
|
||||||
|
define_signed_into!(SCN, i8, u8);
|
||||||
|
define_signed_into!(SCN, i16, u16);
|
||||||
|
define_signed_into!(SCN, i32, u32);
|
||||||
|
define_signed_into!(SCN, i64, u64);
|
||||||
|
|
||||||
|
impl From<UCN> for SCN {
|
||||||
|
fn from(x: UCN) -> SCN {
|
||||||
|
SCN{ negative: false, value: x }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a,T: PartialEq> PartialEq<Signed<T>> for &'a Signed<T> {
|
impl Into<UCN> for SCN {
|
||||||
fn eq(&self, other: &Signed<T>) -> bool {
|
fn into(self) -> UCN {
|
||||||
(self.positive == other.positive) && (self.value == other.value)
|
self.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: PartialEq> PartialEq for Signed<T> {
|
impl From<SCN> for BigInt {
|
||||||
fn eq(&self, other: &Signed<T>) -> bool {
|
fn from(x: SCN) -> BigInt {
|
||||||
(self.positive == other.positive) && (self.value == other.value)
|
let sign = if x.is_negative() { Sign::Minus } else { Sign::Plus };
|
||||||
|
let numbytes = x.value.contents.len() * 8;
|
||||||
|
let bytes = x.value.to_bytes(numbytes);
|
||||||
|
BigInt::from_bytes_be(sign, &bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Eq> Eq for Signed<T> {}
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Comparisons
|
||||||
|
//
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
impl<T: Debug> Debug for Signed<T> {
|
impl PartialOrd for SCN {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
fn partial_cmp(&self, other: &SCN) -> Option<Ordering> {
|
||||||
if self.positive {
|
|
||||||
f.write_str("+")?;
|
|
||||||
} else {
|
|
||||||
f.write_str("-")?;
|
|
||||||
}
|
|
||||||
self.value.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Ord> Ord for Signed<T> {
|
|
||||||
fn cmp(&self, other: &Signed<T>) -> Ordering {
|
|
||||||
match (self.positive, other.positive) {
|
|
||||||
(true, true) => self.value.cmp(&other.value),
|
|
||||||
(true, false) => Ordering::Greater,
|
|
||||||
(false, true) => Ordering::Less,
|
|
||||||
(false, false) =>
|
|
||||||
self.value.cmp(&other.value).reverse()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Ord> PartialOrd for Signed<T> {
|
|
||||||
fn partial_cmp(&self, other: &Signed<T>) -> Option<Ordering>{
|
|
||||||
Some(self.cmp(other))
|
Some(self.cmp(other))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
impl Ord for SCN {
|
||||||
|
fn cmp(&self, other: &SCN) -> Ordering {
|
||||||
impl<T: Clone> Neg for Signed<T> {
|
match (self.negative, other.negative) {
|
||||||
type Output = Signed<T>;
|
(false, false) => self.value.cmp(&other.value),
|
||||||
|
(false, true) => Ordering::Greater,
|
||||||
fn neg(self) -> Signed<T> {
|
(true, false) => Ordering::Less,
|
||||||
Signed {
|
(true, true) => self.value.cmp(&other.value).reverse()
|
||||||
positive: !self.positive,
|
|
||||||
value: self.value.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a,T: Clone> Neg for &'a Signed<T> {
|
|
||||||
type Output = Signed<T>;
|
|
||||||
|
|
||||||
fn neg(self) -> Signed<T> {
|
|
||||||
Signed {
|
|
||||||
positive: !self.positive,
|
|
||||||
value: self.value.clone()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
impl<T> AddAssign for Signed<T>
|
// Shifts
|
||||||
where
|
//
|
||||||
T: Clone + Ord,
|
|
||||||
T: AddAssign + SubAssign,
|
|
||||||
{
|
|
||||||
fn add_assign(&mut self, other: Signed<T>) {
|
|
||||||
match (self.positive, other.positive, self.value.cmp(&other.value)) {
|
|
||||||
// if the signs are the same, we maintain the sign and just increase
|
|
||||||
// the magnitude
|
|
||||||
(x, y, _) if x == y =>
|
|
||||||
self.value.add_assign(other.value),
|
|
||||||
// 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.
|
|
||||||
(_, _, Ordering::Equal) => {
|
|
||||||
self.positive = true;
|
|
||||||
self.value.sub_assign(other.value);
|
|
||||||
}
|
|
||||||
// if the signs are different and the first one is less than the
|
|
||||||
// second, then we flip the sign and subtract.
|
|
||||||
(_, _, Ordering::Less) => {
|
|
||||||
self.positive = !self.positive;
|
|
||||||
let temp = self.value.clone();
|
|
||||||
self.value = other.value.clone();
|
|
||||||
self.value.sub_assign(temp);
|
|
||||||
}
|
|
||||||
// if the signs are different and the first one is greater than the
|
|
||||||
// second, then we leave the sign and subtract.
|
|
||||||
(_, _, Ordering::Greater) => {
|
|
||||||
self.value.sub_assign(other.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a,T> AddAssign<&'a Signed<T>> for Signed<T>
|
|
||||||
where
|
|
||||||
T: Clone + Ord,
|
|
||||||
T: AddAssign + SubAssign,
|
|
||||||
T: AddAssign<&'a T> + SubAssign<&'a T>
|
|
||||||
{
|
|
||||||
fn add_assign(&mut self, other: &'a Signed<T>) {
|
|
||||||
match (self.positive, other.positive, self.value.cmp(&other.value)) {
|
|
||||||
// if the signs are the same, we maintain the sign and just increase
|
|
||||||
// the magnitude
|
|
||||||
(x, y, _) if x == y =>
|
|
||||||
self.value.add_assign(&other.value),
|
|
||||||
// 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.
|
|
||||||
(_, _, Ordering::Equal) => {
|
|
||||||
self.positive = true;
|
|
||||||
self.value.sub_assign(&other.value);
|
|
||||||
}
|
|
||||||
// if the signs are different and the first one is less than the
|
|
||||||
// second, then we flip the sign and subtract.
|
|
||||||
(_, _, Ordering::Less) => {
|
|
||||||
self.positive = !self.positive;
|
|
||||||
let temp = self.value.clone();
|
|
||||||
self.value = other.value.clone();
|
|
||||||
self.value.sub_assign(temp);
|
|
||||||
}
|
|
||||||
// if the signs are different and the first one is greater than the
|
|
||||||
// second, then we leave the sign and subtract.
|
|
||||||
(_, _, Ordering::Greater) => {
|
|
||||||
self.value.sub_assign(&other.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
math_operator!(Add,add,add_assign);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
impl<T> SubAssign for Signed<T>
|
impl ShlAssign<u64> for SCN {
|
||||||
where
|
fn shl_assign(&mut self, rhs: u64) {
|
||||||
T: Clone + Ord,
|
self.value <<= rhs;
|
||||||
T: AddAssign + SubAssign,
|
|
||||||
{
|
|
||||||
fn sub_assign(&mut self, other: Signed<T>) {
|
|
||||||
let mut other2 = other.clone();
|
|
||||||
other2.positive = !other.positive;
|
|
||||||
self.add_assign(other2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a,T> SubAssign<&'a Signed<T>> for Signed<T>
|
impl Shl<u64> for SCN {
|
||||||
where
|
type Output = SCN;
|
||||||
T: Clone + Ord,
|
|
||||||
T: AddAssign + SubAssign,
|
fn shl(self, rhs: u64) -> SCN {
|
||||||
T: AddAssign<&'a T> + SubAssign<&'a T>
|
let mut copy = self.clone();
|
||||||
{
|
copy.shl_assign(rhs);
|
||||||
fn sub_assign(&mut self, other: &'a Signed<T>) {
|
copy
|
||||||
let mut other2 = other.clone();
|
|
||||||
other2.positive = !other.positive;
|
|
||||||
self.add_assign(other2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
math_operator!(Sub,sub,sub_assign);
|
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, usize);
|
||||||
|
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u32);
|
||||||
|
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u16);
|
||||||
|
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u8);
|
||||||
|
|
||||||
|
impl ShrAssign<u64> for SCN {
|
||||||
|
fn shr_assign(&mut self, rhs: u64) {
|
||||||
|
self.value >>= rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shr<u64> for SCN {
|
||||||
|
type Output = SCN;
|
||||||
|
|
||||||
|
fn shr(self, rhs: u64) -> SCN {
|
||||||
|
let mut copy = self.clone();
|
||||||
|
copy.shr_assign(rhs);
|
||||||
|
copy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, usize);
|
||||||
|
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u32);
|
||||||
|
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u16);
|
||||||
|
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u8);
|
||||||
|
|
||||||
|
derive_signed_shift_operators!(SCN, usize, isize);
|
||||||
|
derive_signed_shift_operators!(SCN, u64, i64);
|
||||||
|
derive_signed_shift_operators!(SCN, u32, i32);
|
||||||
|
derive_signed_shift_operators!(SCN, u16, i16);
|
||||||
|
derive_signed_shift_operators!(SCN, u8, i8);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
impl<T> MulAssign for Signed<T>
|
// Arithmetic
|
||||||
where
|
//
|
||||||
T: MulAssign
|
|
||||||
{
|
|
||||||
fn mul_assign(&mut self, other: Signed<T>) {
|
|
||||||
self.positive = !(self.positive ^ other.positive);
|
|
||||||
self.value *= other.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a,T> MulAssign<&'a Signed<T>> for Signed<T>
|
|
||||||
where
|
|
||||||
T: MulAssign + MulAssign<&'a T>
|
|
||||||
{
|
|
||||||
fn mul_assign(&mut self, other: &'a Signed<T>) {
|
|
||||||
self.positive = !(self.positive ^ other.positive);
|
|
||||||
self.value *= &other.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
math_operator!(Mul,mul,mul_assign);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
impl<T> DivAssign for Signed<T>
|
impl Neg for SCN {
|
||||||
where
|
type Output = SCN;
|
||||||
T: DivAssign
|
|
||||||
{
|
fn neg(self) -> SCN {
|
||||||
fn div_assign(&mut self, other: Signed<T>) {
|
if self.is_zero() {
|
||||||
self.positive = !(self.positive ^ other.positive);
|
self
|
||||||
self.value /= other.value;
|
} else {
|
||||||
|
SCN{ negative: !self.negative, value: self.value }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a,T> DivAssign<&'a Signed<T>> for Signed<T>
|
impl<'a> Neg for &'a SCN {
|
||||||
where
|
type Output = SCN;
|
||||||
T: DivAssign + DivAssign<&'a T>
|
|
||||||
{
|
fn neg(self) -> SCN {
|
||||||
fn div_assign(&mut self, other: &'a Signed<T>) {
|
if self.is_zero() {
|
||||||
self.positive = !(self.positive ^ other.positive);
|
self.clone()
|
||||||
self.value /= &other.value;
|
} else {
|
||||||
|
SCN{ negative: !self.negative, value: self.value.clone() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
math_operator!(Div,div,div_assign);
|
impl<'a> AddAssign<&'a SCN> for SCN {
|
||||||
|
fn add_assign(&mut self, rhs: &SCN) {
|
||||||
|
if self.negative == rhs.negative {
|
||||||
|
self.value.add_assign(&rhs.value);
|
||||||
|
} else {
|
||||||
|
if self.value >= rhs.value {
|
||||||
|
self.value.sub_assign(&rhs.value);
|
||||||
|
} else {
|
||||||
|
self.negative = !self.negative;
|
||||||
|
self.value = &rhs.value - &self.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SubAssign<&'a SCN> for SCN {
|
||||||
|
fn sub_assign(&mut self, rhs: &SCN) {
|
||||||
|
let flipped = SCN{ negative: !rhs.negative, value: rhs.value.clone() };
|
||||||
|
self.add_assign(&flipped);
|
||||||
|
self.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> MulAssign<&'a SCN> for SCN {
|
||||||
|
fn mul_assign(&mut self, rhs: &SCN) {
|
||||||
|
self.negative ^= rhs.negative;
|
||||||
|
self.value.mul_assign(&rhs.value);
|
||||||
|
self.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DivAssign<&'a SCN> for SCN {
|
||||||
|
fn div_assign(&mut self, rhs: &SCN) {
|
||||||
|
self.negative ^= rhs.negative;
|
||||||
|
// rounding makes me grumpy
|
||||||
|
let mut remainder = Vec::new();
|
||||||
|
let copy = self.value.contents.clone();
|
||||||
|
divmod(&mut self.value.contents, &mut remainder,
|
||||||
|
©, &rhs.value.contents);
|
||||||
|
if self.negative && !remainder.is_empty() {
|
||||||
|
let one = UCN{ contents: vec![1] };
|
||||||
|
self.sub_assign(SCN{ negative: false, value: one});
|
||||||
|
}
|
||||||
|
self.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> RemAssign<&'a SCN> for SCN {
|
||||||
|
fn rem_assign(&mut self, rhs: &SCN) {
|
||||||
|
let base = &self.value % &rhs.value;
|
||||||
|
|
||||||
|
if self.negative == rhs.negative {
|
||||||
|
self.value = base;
|
||||||
|
} else {
|
||||||
|
self.negative = rhs.negative;
|
||||||
|
self.value = &rhs.value - &base;
|
||||||
|
}
|
||||||
|
self.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
derive_arithmetic_operators!(SCN, Add, add, AddAssign, add_assign);
|
||||||
|
derive_arithmetic_operators!(SCN, Sub, sub, SubAssign, sub_assign);
|
||||||
|
derive_arithmetic_operators!(SCN, Mul, mul, MulAssign, mul_assign);
|
||||||
|
derive_arithmetic_operators!(SCN, Div, div, DivAssign, div_assign);
|
||||||
|
derive_arithmetic_operators!(SCN, Rem, rem, RemAssign, rem_assign);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Tests!
|
||||||
|
//
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod test {
|
||||||
use cryptonum::unsigned::U512;
|
|
||||||
use quickcheck::{Arbitrary,Gen};
|
use quickcheck::{Arbitrary,Gen};
|
||||||
use std::cmp::{max,min};
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl<T: Arbitrary + CryptoNumBase> Arbitrary for Signed<T> {
|
impl Arbitrary for SCN {
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Signed<T> {
|
fn arbitrary<G: Gen>(g: &mut G) -> SCN {
|
||||||
let value = T::arbitrary(g);
|
let neg = (g.next_u32() & 1) == 1;
|
||||||
if value.is_zero() {
|
SCN{ negative: neg, value: UCN::arbitrary(g) }
|
||||||
Signed {
|
|
||||||
positive: true,
|
|
||||||
value: value
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Signed {
|
|
||||||
positive: g.gen_weighted_bool(2),
|
|
||||||
value: value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn one() -> SCN {
|
||||||
|
SCN{ negative: false, value: UCN::from(1 as u8) }
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn double_negation(x: Signed<U512>) -> bool {
|
fn additive_identity(x: SCN) -> bool {
|
||||||
&x == (- (- &x))
|
(&x + &SCN::zero()) == x
|
||||||
}
|
}
|
||||||
|
fn subtractive_identity(x: SCN) -> bool {
|
||||||
|
(&x - &SCN::zero()) == x
|
||||||
|
}
|
||||||
|
fn multiplicative_identity(x: SCN) -> bool {
|
||||||
|
(&x * &one()) == x
|
||||||
|
}
|
||||||
|
fn division_identity(x: SCN) -> bool {
|
||||||
|
let result = &x / &one();
|
||||||
|
result == x
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
fn additive_destructor(x: SCN) -> bool {
|
||||||
fn add_associates(x: Signed<U512>, y: Signed<U512>, z: Signed<U512>)
|
(&x + (- &x)) == SCN::zero()
|
||||||
-> bool
|
|
||||||
{
|
|
||||||
let mut a = x.clone();
|
|
||||||
let mut b = y.clone();
|
|
||||||
let mut c = z.clone();
|
|
||||||
|
|
||||||
// we shift these right because rollover makes for weird behavior
|
|
||||||
a.value >>= 2;
|
|
||||||
b.value >>= 2;
|
|
||||||
c.value >>= 2;
|
|
||||||
|
|
||||||
(&a + (&b + &c)) == ((&a + &b) + &c)
|
|
||||||
}
|
}
|
||||||
fn add_commutes(x: Signed<U512>, y: Signed<U512>) -> bool {
|
fn subtractive_destructor(x: SCN) -> bool {
|
||||||
(&x + &y) == (&y + &x)
|
(&x - &x) == SCN::zero()
|
||||||
}
|
}
|
||||||
fn add_identity(x: Signed<U512>) -> bool {
|
fn multiplicative_destructor(x: SCN) -> bool {
|
||||||
let zero = Signed{ positive: true, value: U512::zero() };
|
(x * SCN::zero()) == SCN::zero()
|
||||||
(&x + &zero) == &x
|
|
||||||
}
|
}
|
||||||
|
fn division_deastructor(x: SCN) -> bool {
|
||||||
|
(&x / &x) == one()
|
||||||
|
}
|
||||||
|
fn remainder_destructor(x: SCN) -> bool {
|
||||||
|
(&x % &x) == SCN::zero()
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
fn addition_commutes(a: SCN, b: SCN) -> bool {
|
||||||
fn sub_is_add_negation(x: Signed<U512>, y: Signed<U512>) -> bool {
|
(&a + &b) == (&b + &a)
|
||||||
(&x - &y) == (&x + (- &y))
|
|
||||||
}
|
}
|
||||||
|
fn multiplication_commutes(a: SCN, b: SCN) -> bool {
|
||||||
|
(&a * &b) == (&b * &a)
|
||||||
}
|
}
|
||||||
|
fn addition_associates(a: SCN, b: SCN, c: SCN) -> bool {
|
||||||
quickcheck! {
|
((&a + &b) + &c) == (&a + (&b + &c))
|
||||||
fn mul_associates(x: Signed<U512>, y: Signed<U512>, z: Signed<U512>)
|
|
||||||
-> bool
|
|
||||||
{
|
|
||||||
let mut a = x.clone();
|
|
||||||
let mut b = y.clone();
|
|
||||||
let mut c = z.clone();
|
|
||||||
|
|
||||||
// we shift these right because rollover makes for weird behavior
|
|
||||||
a.value >>= 258;
|
|
||||||
b.value >>= 258;
|
|
||||||
c.value >>= 258;
|
|
||||||
|
|
||||||
(&a * (&b * &c)) == ((&a * &b) * &c)
|
|
||||||
}
|
}
|
||||||
fn mul_commutes(x: Signed<U512>, y: Signed<U512>) -> bool {
|
fn multiplication_associates(a: SCN, b: SCN, c: SCN) -> bool {
|
||||||
(&x * &y) == (&y * &x)
|
((&a * &b) * &c) == (&a * (&b * &c))
|
||||||
}
|
}
|
||||||
fn mul_identity(x: Signed<U512>) -> bool {
|
fn distribution_works(a: SCN, b: SCN, c: SCN) -> bool {
|
||||||
let one = Signed{ positive: true, value: U512::from_u8(1) };
|
|
||||||
(&x * &one) == &x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
quickcheck! {
|
|
||||||
fn add_mul_distribution(x:Signed<U512>,y:Signed<U512>,z:Signed<U512>)
|
|
||||||
-> bool
|
|
||||||
{
|
|
||||||
let mut a = x.clone();
|
|
||||||
let mut b = y.clone();
|
|
||||||
let mut c = z.clone();
|
|
||||||
|
|
||||||
// we shift these right because rollover makes for weird behavior
|
|
||||||
a.value >>= 258;
|
|
||||||
b.value >>= 258;
|
|
||||||
c.value >>= 258;
|
|
||||||
|
|
||||||
(&a * (&b + &c)) == ((&a * &b) + (&a * &c))
|
(&a * (&b + &c)) == ((&a * &b) + (&a * &c))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn negation_works(a: SCN) -> bool {
|
||||||
|
(- &a) == (&a * &SCN{ negative: true, value: UCN::from(1 as u8) })
|
||||||
|
}
|
||||||
|
fn double_negation_works(a: SCN) -> bool {
|
||||||
|
(- (- &a)) == a
|
||||||
|
}
|
||||||
|
fn negation_commutes(a: SCN, b: SCN) -> bool {
|
||||||
|
((- &a) * &b) == (&a * (- &b))
|
||||||
|
}
|
||||||
|
fn negation_cancels(a: SCN, b: SCN) -> bool {
|
||||||
|
((- &a) * (- &b)) == (&a * &b)
|
||||||
|
}
|
||||||
|
fn negation_distributes(a: SCN, b: SCN) -> bool {
|
||||||
|
(- (&a + &b)) == ((- &a) + (- &b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn egcd_works(a: SCN, b: SCN) -> bool {
|
||||||
|
let (d, x, y) = a.clone().egcd(b.clone());
|
||||||
|
((a * x) + (b * y)) == d
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
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;
|
|
||||||
/// Translate a `u8` to this type. This must be safe.
|
|
||||||
fn from_u8(x: u8) -> Self;
|
|
||||||
/// Convert this back into a `u8`. This is the equivalent of masking off
|
|
||||||
/// the lowest 8 bits and then casting to a `u8`.
|
|
||||||
fn to_u8(&self) -> u8;
|
|
||||||
/// Translate a `u16` to this type. This must be safe.
|
|
||||||
fn from_u16(x: u16) -> Self;
|
|
||||||
/// Convert this back into a `u16`. This is the equivalent of masking off
|
|
||||||
/// the lowest 16 bits and then casting to a `u16`.
|
|
||||||
fn to_u16(&self) -> u16;
|
|
||||||
/// Translate a `u32` to this type. This must be safe.
|
|
||||||
fn from_u32(x: u32) -> Self;
|
|
||||||
/// Convert this back into a `u32`. This is the equivalent of masking off
|
|
||||||
/// the lowest 32 bits and then casting to a `u32`.
|
|
||||||
fn to_u32(&self) -> u32;
|
|
||||||
/// Translate a `u64` to this type. This must be safe.
|
|
||||||
fn from_u64(x: u64) -> Self;
|
|
||||||
/// Convert this back into a `u64`. This is the equivalent of masking off
|
|
||||||
/// the lowest 64 bits and then casting to a `u64`.
|
|
||||||
fn to_u64(&self) -> u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
28
src/dsa/errors.rs
Normal file
28
src/dsa/errors.rs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
use simple_asn1::ASN1DecodeErr;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum DSAError {
|
||||||
|
ASN1DecodeErr(ASN1DecodeErr),
|
||||||
|
InvalidParamSize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ASN1DecodeErr> for DSAError {
|
||||||
|
fn from(e: ASN1DecodeErr) -> DSAError {
|
||||||
|
DSAError::ASN1DecodeErr(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum DSAGenError {
|
||||||
|
RngFailure(io::Error),
|
||||||
|
InvalidSeedLength, InvalidPrimeLength, TooManyGenAttempts
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for DSAGenError {
|
||||||
|
fn from(e: io::Error) -> DSAGenError {
|
||||||
|
DSAGenError::RngFailure(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
585
src/dsa/generation.rs
Normal file
585
src/dsa/generation.rs
Normal file
@@ -0,0 +1,585 @@
|
|||||||
|
use cryptonum::{BarrettUCN,UCN};
|
||||||
|
use digest::{FixedOutput,Input};
|
||||||
|
use dsa::errors::DSAGenError;
|
||||||
|
use dsa::parameters::{DSAParameterSize,n_bits,l_bits};
|
||||||
|
use rand::Rng;
|
||||||
|
use sha2::Sha256;
|
||||||
|
use std::ops::{Add,Div,Rem,Sub};
|
||||||
|
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct DSAGenEvidence {
|
||||||
|
pub first_seed: UCN,
|
||||||
|
pub p_seed: UCN,
|
||||||
|
pub q_seed: UCN,
|
||||||
|
pub pgen_counter: usize,
|
||||||
|
pub qgen_counter: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_domain_parameter_seed(ev: &DSAGenEvidence) -> Vec<u8> {
|
||||||
|
let mut output = Vec::new();
|
||||||
|
let fssize = (ev.first_seed.bits() + 7) / 8;
|
||||||
|
output.append(&mut ev.first_seed.to_bytes(fssize));
|
||||||
|
let psize = (ev.p_seed.bits() + 7) / 8;
|
||||||
|
output.append(&mut ev.p_seed.to_bytes(psize));
|
||||||
|
let qsize = (ev.q_seed.bits() + 7) / 8;
|
||||||
|
output.append(&mut ev.q_seed.to_bytes(qsize));
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_provable_primes<G: Rng>(rng: &mut G,
|
||||||
|
firstseed: &UCN,
|
||||||
|
ps: DSAParameterSize)
|
||||||
|
-> Result<(UCN, UCN, DSAGenEvidence),DSAGenError>
|
||||||
|
{
|
||||||
|
let one: UCN = UCN::from(1u64);
|
||||||
|
let two: UCN = UCN::from(2u64);
|
||||||
|
let three: UCN = UCN::from(3u64);
|
||||||
|
// See Page 38 of FIPS 186-4!
|
||||||
|
let n = n_bits(ps);
|
||||||
|
let l = l_bits(ps);
|
||||||
|
// 1. Check that the (L, N) pair is in the list of acceptable (L, N) pairs
|
||||||
|
// (see Section 4.2). If the pair is not in the list, return FAILURE.
|
||||||
|
//
|
||||||
|
// Done because sum types are cool.
|
||||||
|
//
|
||||||
|
// 2. Using N as the length and firstseed as the input_seed, use the random
|
||||||
|
// prime generation routine in Appendix C.6 to obtain q, qseed and
|
||||||
|
// qgen_counter. If FAILURE is returned, then return FAILURE.
|
||||||
|
let (q, qseed, qgen_counter) = shawe_taylor(rng, n, &firstseed)?;
|
||||||
|
// 3. Using ceiling(L / 2 + 1) as the length and qseed as the input_seed,
|
||||||
|
// use the random prime generation routine in Appendix C.6 to obtain
|
||||||
|
// p0, pseed, and pgen_counter. If FAILURE is returned, then return
|
||||||
|
// FAILURE.
|
||||||
|
//
|
||||||
|
// NOTE: The ceiling isn't required. All of the values of L divide
|
||||||
|
// evenly by 2, so it's just l / 2 + 1. I'm not sure why the
|
||||||
|
// spec mentions it, frankly.
|
||||||
|
let (p0, mut pseed, mut pgen_counter) = shawe_taylor(rng, l/2 + 1, &qseed)?;
|
||||||
|
// 4. iterations = ceiling(L / outlen) - 1.
|
||||||
|
let iterations = ceildiv(&l, &256) - 1;
|
||||||
|
// 5. old_counter = pgen_counter.
|
||||||
|
let old_counter = pgen_counter;
|
||||||
|
// 6. x = 0.
|
||||||
|
let mut x_bytes = Vec::new();
|
||||||
|
// 7. For i = 0 to iterations fo
|
||||||
|
// x + x + (Hash(pseed + i) * 2^(i * outlen).
|
||||||
|
// NOTE: WE run this backwards, much like we do in shawe_taylor()
|
||||||
|
let mut i: i64 = iterations as i64;
|
||||||
|
while i >= 0 {
|
||||||
|
let bigi = UCN::from(i as u64);
|
||||||
|
let prime_i = &pseed + &bigi;
|
||||||
|
let mut hash_i = hash(&prime_i, l);
|
||||||
|
x_bytes.append(&mut hash_i);
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
let x = UCN::from_bytes(&x_bytes);
|
||||||
|
// 8. pseed = pseed + iterations + 1.
|
||||||
|
pseed = &pseed + UCN::from(iterations) + &one;
|
||||||
|
// 9. x = 2^(L-1) + (x mod 2^(L-1));
|
||||||
|
let twol1: UCN = &one << (l - 1);
|
||||||
|
// 10. t = ceiling(x / (2 * q * p_0))
|
||||||
|
let twoqp0 = &two * &q * &p0;
|
||||||
|
let mut t = ceildiv(&x, &twoqp0);
|
||||||
|
loop {
|
||||||
|
// 11. If (2tqp_0 + 1) > 2^L, then t = ceiling(2^(L-1)/2qp0).
|
||||||
|
let twotqp0p1 = (&t * &twoqp0) + &one;
|
||||||
|
let twol = &one << l;
|
||||||
|
if &twotqp0p1 > &twol {
|
||||||
|
t = ceildiv(&twol1, &twoqp0);
|
||||||
|
}
|
||||||
|
// 12. p = 2tqp_0 + 1
|
||||||
|
let p = twotqp0p1;
|
||||||
|
// 13. pgen_counter = pgen_counter + 1
|
||||||
|
pgen_counter = &pgen_counter + 1;
|
||||||
|
// 14. a = 0
|
||||||
|
let mut a_bytes = Vec::new();
|
||||||
|
// 15. For i = 0 to iterations do
|
||||||
|
// a = a + (Hash(pseed + i) * 2^(i*outlen).
|
||||||
|
i = iterations as i64;
|
||||||
|
while i >= 0 {
|
||||||
|
let bigi = UCN::from(i as u64);
|
||||||
|
let prime_i = &pseed + &bigi;
|
||||||
|
let mut hash_i = hash(&prime_i, l);
|
||||||
|
a_bytes.append(&mut hash_i);
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
let mut a = UCN::from_bytes(&a_bytes);
|
||||||
|
// 16. pseed = pseed + iterations + 1.
|
||||||
|
pseed = &pseed + UCN::from(iterations) + &one;
|
||||||
|
// 17. a = 2 + (a mod (p - 3))
|
||||||
|
let pm3 = &p - &three;
|
||||||
|
let amodpm3 = &a % &pm3;
|
||||||
|
a = &two + &amodpm3;
|
||||||
|
// 18. z = a^(2tq) mod p.
|
||||||
|
let twotq = &two * &t * &q;
|
||||||
|
let z = a.modexp(&twotq, &p);
|
||||||
|
// 19. If ((1 = GCD(z-1,p)) and (1 = z^p0 mod p)), then return SUCCESS
|
||||||
|
// and the values of p, q, and (optionally) pseed, qseed, pgen_counter,
|
||||||
|
// and qgen_counter.
|
||||||
|
let zm1 = &z - &one;
|
||||||
|
if (&one == &zm1.gcd(&p)) && (&one == &z.modexp(&p0, &p)) {
|
||||||
|
let evidence = DSAGenEvidence {
|
||||||
|
first_seed: firstseed.clone(),
|
||||||
|
p_seed: pseed,
|
||||||
|
q_seed: qseed,
|
||||||
|
pgen_counter: pgen_counter,
|
||||||
|
qgen_counter: qgen_counter
|
||||||
|
};
|
||||||
|
return Ok((p, q, evidence));
|
||||||
|
}
|
||||||
|
// 20. If (pgen_counter > (4L + old_counter)), then return FAILURE.
|
||||||
|
if pgen_counter > ((4 * l) + old_counter) {
|
||||||
|
return Err(DSAGenError::TooManyGenAttempts);
|
||||||
|
}
|
||||||
|
// 21. t = t + 1
|
||||||
|
t = &t + &one;
|
||||||
|
// 22. Go to step 11.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate_provable_primes<G: Rng>(rng: &mut G,
|
||||||
|
p: &UCN, q: &UCN,
|
||||||
|
ev: &DSAGenEvidence)
|
||||||
|
-> bool
|
||||||
|
{
|
||||||
|
let one = UCN::from(1u64);
|
||||||
|
// This is from Page 40 of 186-4, section A.1.2.2.
|
||||||
|
// 1. L = len(p);
|
||||||
|
let l = ((p.bits() + 255) / 256) * 256;
|
||||||
|
// 2. N = len(q);
|
||||||
|
let n = ((q.bits() + 15) / 16) * 16;
|
||||||
|
// 3. Check that the (L, N) pair is in the list of acceptable (L, N) pairs.
|
||||||
|
// If the pair is not in the list, then return failure.
|
||||||
|
let params = match (l, n) {
|
||||||
|
(1024, 160) => DSAParameterSize::L1024N160,
|
||||||
|
(2048, 224) => DSAParameterSize::L2048N224,
|
||||||
|
(2048, 256) => DSAParameterSize::L2048N256,
|
||||||
|
(3072, 256) => DSAParameterSize::L3072N256,
|
||||||
|
_ => return false
|
||||||
|
};
|
||||||
|
// 4. If (firstseed < 2^(n-1), then return FAILURE.
|
||||||
|
let twon1 = &one << (n - 1);
|
||||||
|
if &ev.first_seed < &twon1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 5. If (2^n <= q), then return FAILURE.
|
||||||
|
let twon = &one << n;
|
||||||
|
if &twon <= q {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 6. If (2^l <= p), then return FAILURE.
|
||||||
|
let twol = &one << l;
|
||||||
|
if &twol <= p {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 7. If ((p - 1) mod q /= 0), then return FAILURE.
|
||||||
|
let pm1 = p - &one;
|
||||||
|
if !pm1.rem(q).is_zero() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 8. Using L, N and firstseed, perform the constructive prime generation
|
||||||
|
// procedure in Appendix A.1.2.1.2 to obtain p_val, q_val, pseed_val,
|
||||||
|
// qseed_val, pgen_counter_val, and qgen_counter_val. If FAILURE is
|
||||||
|
// returned, or if (q_val ≠ q) or (qseed_val ≠ qseed) or
|
||||||
|
// (qgen_counter_val ≠ qgen_counter) or (p_val ≠ p) or (pseed_val ≠
|
||||||
|
// pseed) or (pgen_counter_val ≠ pgen_counter), then return FAILURE.
|
||||||
|
match generate_provable_primes(rng, &ev.first_seed, params) {
|
||||||
|
Err(_) => false,
|
||||||
|
Ok((p_val, q_val, ev2)) => {
|
||||||
|
// 9. Return SUCCESS
|
||||||
|
(&q_val == q) && (&p_val == p) && (ev == &ev2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_verifiable_generator(p: &UCN, pu: &BarrettUCN,
|
||||||
|
q: &UCN,
|
||||||
|
ev: &DSAGenEvidence,
|
||||||
|
index: u8)
|
||||||
|
-> Result<UCN,DSAGenError>
|
||||||
|
{
|
||||||
|
// See FIPS 186-4, Section A.2.3: Verifiable Canonical Generatio of the
|
||||||
|
// Generator g
|
||||||
|
let one = UCN::from(1u64);
|
||||||
|
let two = UCN::from(2u64);
|
||||||
|
// 1. If (index is incorrect), then return INVALID.
|
||||||
|
// NOTE: Can't happen, because types.
|
||||||
|
// 2. N = len(q)
|
||||||
|
let _n = q.bits();
|
||||||
|
// 3. e = (p - 1)/q.
|
||||||
|
let e = (p - &one) / q;
|
||||||
|
// 4. count = 0.
|
||||||
|
let mut count: u16 = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// 5. count = count + 1;
|
||||||
|
count = count + 1;
|
||||||
|
// 6. if (count = 0), then return INVALID.
|
||||||
|
if count == 0 {
|
||||||
|
return Err(DSAGenError::TooManyGenAttempts);
|
||||||
|
}
|
||||||
|
// 7. U = domain_parameter_seed || "ggen" || index || count
|
||||||
|
// Comment: "ggen" is the bit string 0x6767656E.
|
||||||
|
let mut u = get_domain_parameter_seed(&ev);
|
||||||
|
u.push(0x67); u.push(0x67); u.push(0x65); u.push(0x6E);
|
||||||
|
u.push(index);
|
||||||
|
u.push((count >> 8) as u8); u.push((count & 0xFF) as u8);
|
||||||
|
// 8. W = hash(U)
|
||||||
|
let mut dgst = Sha256::default();
|
||||||
|
dgst.process(&u);
|
||||||
|
let w = UCN::from_bytes(dgst.fixed_result().as_slice());
|
||||||
|
// 9. g = W^e mod p
|
||||||
|
let g = w.fastmodexp(&e, &pu);
|
||||||
|
// 10. if (g < 2), then go to step 5.
|
||||||
|
if &g >= &two {
|
||||||
|
// 11. Return VALID and the value of g.
|
||||||
|
return Ok(g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify_generator(p: &UCN, q: &UCN, ev: &DSAGenEvidence,
|
||||||
|
index: u8, g: &UCN)
|
||||||
|
-> bool
|
||||||
|
{
|
||||||
|
// FIPS 186.4, Section A.2.4!
|
||||||
|
let one = UCN::from(1u64);
|
||||||
|
let two = UCN::from(2u64);
|
||||||
|
// 1. If (index is incorrect), then return INVALID.
|
||||||
|
// NOTE: Not sure how this can be invalid.
|
||||||
|
// 2. Verify that 2 <= g <= (p - 1). If not true, return INVALID.
|
||||||
|
if g < &two {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if g >= p {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 3. If (g^q /= 1 mod p), then return INVALID.
|
||||||
|
if g.modexp(q, p) != one {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 4. N = len(q)
|
||||||
|
// let n = ((q.bits() + 15) / 15) * 15;
|
||||||
|
// 5. e = (p - 1) / q
|
||||||
|
let e = (p - &one) / q;
|
||||||
|
// 6. count = 0
|
||||||
|
let mut count: u16 = 0;
|
||||||
|
loop {
|
||||||
|
// 7. count = count + 1
|
||||||
|
count = count + 1;
|
||||||
|
// 8. if (count == 0), then return INVALID
|
||||||
|
if count == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 9. U = domain_parameter_seed || "ggen" || index || count.
|
||||||
|
let mut u = get_domain_parameter_seed(&ev);
|
||||||
|
u.push(0x67); u.push(0x67); u.push(0x65); u.push(0x6E);
|
||||||
|
u.push(index);
|
||||||
|
u.push((count >> 8) as u8); u.push((count & 0xFF) as u8);
|
||||||
|
// 10. W = Hash(U)
|
||||||
|
let mut dgst = Sha256::default();
|
||||||
|
dgst.process(&u);
|
||||||
|
let w = UCN::from_bytes(dgst.fixed_result().as_slice());
|
||||||
|
// 11. computed_g = W^e mod p
|
||||||
|
let computed_g = w.modexp(&e, &p);
|
||||||
|
// 12. if (computed_g < 2), then go to step 7.
|
||||||
|
if &computed_g < &two {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 13. if (computed_g == g), then return VALID, else return INVALID
|
||||||
|
return &computed_g == g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_input_seed<G: Rng>(rng: &mut G,
|
||||||
|
size: DSAParameterSize,
|
||||||
|
seedlen: usize)
|
||||||
|
-> Result<UCN,DSAGenError>
|
||||||
|
{
|
||||||
|
let mut firstseed = UCN::from(0u64);
|
||||||
|
let one = UCN::from(1u64);
|
||||||
|
let n = n_bits(size);
|
||||||
|
|
||||||
|
// 3. If (seedlen < N), then return FAILURE
|
||||||
|
if seedlen < n {
|
||||||
|
return Err(DSAGenError::InvalidSeedLength)
|
||||||
|
}
|
||||||
|
// 4. While firstseed < 2^(n-1) ...
|
||||||
|
let twonm1 = one << (n - 1);
|
||||||
|
while &firstseed < &twonm1 {
|
||||||
|
// Get an arbitrary sequence of seedlen bits as firstseed.
|
||||||
|
let bytes: Vec<u8> = rng.gen_iter().take(seedlen / 8).collect();
|
||||||
|
firstseed = UCN::from_bytes(&bytes);
|
||||||
|
}
|
||||||
|
// 5. Return SUCCESS and the value of firstseed
|
||||||
|
Ok(firstseed)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appendix C.6: Shawe-Taylor Random_Prime Routine. Also referenced in 186-4
|
||||||
|
// as ST_Random_Prime, so when you see that in a bit, understand that it's a
|
||||||
|
// recursive call.
|
||||||
|
fn shawe_taylor<G: Rng>(rng: &mut G, length: usize, input_seed: &UCN)
|
||||||
|
-> Result<(UCN,UCN,usize),DSAGenError>
|
||||||
|
{
|
||||||
|
// 1. If (length < 2), then return (FAILURE, 0, 0 {, 0}).
|
||||||
|
if length < 2 {
|
||||||
|
return Err(DSAGenError::InvalidPrimeLength);
|
||||||
|
}
|
||||||
|
// 2. If (length ≥ 33), then go to step 14.
|
||||||
|
if length >= 33 {
|
||||||
|
shawe_taylor_large(rng, length, input_seed)
|
||||||
|
} else {
|
||||||
|
shawe_taylor_small(length, input_seed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shawe_taylor_small(length: usize, input_seed: &UCN)
|
||||||
|
-> Result<(UCN,UCN,usize),DSAGenError>
|
||||||
|
{
|
||||||
|
let one = UCN::from(1u64);
|
||||||
|
let two = UCN::from(2u64);
|
||||||
|
// 3. prime_seed = input_seed.
|
||||||
|
let mut prime_seed: UCN = input_seed.clone();
|
||||||
|
// 4. prime_gen_counter = 0
|
||||||
|
let mut prime_gen_counter = 0;
|
||||||
|
loop {
|
||||||
|
// 5. c = Hash(prime_seed) ⊕ Hash(prime_seed + 1).
|
||||||
|
let cbs = xorvecs(hash(&prime_seed, length),
|
||||||
|
hash(&(&prime_seed + &one), length));
|
||||||
|
let mut c = UCN::from_bytes(&cbs);
|
||||||
|
// 6. c = 2^(length – 1) + (c mod 2^(length – 1))
|
||||||
|
let twolm1: UCN = &one << (length - 1);
|
||||||
|
c = &twolm1 + (c % &twolm1);
|
||||||
|
// 7. c = (2 ∗ floor(c / 2)) + 1.
|
||||||
|
c = ((c >> 1) << 1) + &one;
|
||||||
|
// 8. prime_gen_counter = prime_gen_counter + 1.
|
||||||
|
prime_gen_counter = prime_gen_counter + 1;
|
||||||
|
// 9. prime_seed = prime_seed + 2.
|
||||||
|
prime_seed = prime_seed + &two;
|
||||||
|
// 10. Perform a deterministic primality test on c. For example, since
|
||||||
|
// c is small, its primality can be tested by trial division. See
|
||||||
|
// Appendix C.7.
|
||||||
|
let c_is_prime = prime_test(&c);
|
||||||
|
// 11. If (c is a prime number), then
|
||||||
|
if c_is_prime {
|
||||||
|
// 11.1 prime = c.
|
||||||
|
let prime = c;
|
||||||
|
// 11.2 Return (SUCCESS, prime, prime_seed {, prime_gen_counter}).
|
||||||
|
return Ok((prime, prime_seed.clone(), prime_gen_counter))
|
||||||
|
}
|
||||||
|
// 12. If (prime_gen_counter > (4 ∗ length)), then
|
||||||
|
// return (FAILURE, 0, 0 {, 0}).
|
||||||
|
if prime_gen_counter > (4 * length) {
|
||||||
|
return Err(DSAGenError::TooManyGenAttempts);
|
||||||
|
}
|
||||||
|
// 13. Go to step 5.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shawe_taylor_large<G: Rng>(rng: &mut G, length: usize, input_seed: &UCN)
|
||||||
|
-> Result<(UCN,UCN,usize),DSAGenError>
|
||||||
|
{
|
||||||
|
let one = UCN::from(1u64);
|
||||||
|
let two = UCN::from(2u64);
|
||||||
|
let three = UCN::from(3u64);
|
||||||
|
// 14. (status, c0, prime_seed, prime_gen_counter) =
|
||||||
|
// (ST_Random_Prime ((ceiling(length / 2) + 1), input_seed).
|
||||||
|
let len2: usize = ceildiv(&length, &2);
|
||||||
|
let (c0, mut prime_seed, mut prime_gen_counter) =
|
||||||
|
shawe_taylor( rng, len2 + 1, input_seed )?;
|
||||||
|
// 15. If FAILURE is returned, return (FAILURE, 0, 0 {, 0}).
|
||||||
|
// 16. iterations = ceiling(length / outlen) – 1.
|
||||||
|
let outlen = 256; // the size of the hash function output in bits
|
||||||
|
let iterations = ceildiv(&length, &outlen) - 1;
|
||||||
|
// 17. old_counter = prime_gen_counter.
|
||||||
|
let old_counter = prime_gen_counter;
|
||||||
|
// 18. x = 0.
|
||||||
|
let mut x_bytes = Vec::new();
|
||||||
|
// 19. For i = 0 to iterations do
|
||||||
|
// x = x + (Hash(prime_seed + i) ∗ 2^(i * outlen)).
|
||||||
|
//
|
||||||
|
// We're going to actually run this backwards. What this computation
|
||||||
|
// does is essentially built up a large vector of hashes, one per
|
||||||
|
// iteration, shifting them bast each other via the 2^(i * outlen)
|
||||||
|
// term. So we'll just do this directly.
|
||||||
|
let mut i: i64 = iterations as i64;
|
||||||
|
while i >= 0 {
|
||||||
|
let bigi = UCN::from(i as u64);
|
||||||
|
let prime_i = &prime_seed + &bigi;
|
||||||
|
let mut hash_i = hash(&prime_i, length);
|
||||||
|
x_bytes.append(&mut hash_i);
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
let mut x = UCN::from_bytes(&x_bytes);
|
||||||
|
// 20. prime_seed = prime_seed + iterations + 1.
|
||||||
|
prime_seed = &prime_seed + UCN::from(iterations) + &one;
|
||||||
|
// 21. x = 2^(length – 1) + (x mod 2^(length – 1)).
|
||||||
|
let twolm1 = &one << (length - 1);
|
||||||
|
x = &twolm1 + (&x % &twolm1);
|
||||||
|
// 22. t = ceiling(x / (2c0)).
|
||||||
|
let twoc0 = &two * &c0;
|
||||||
|
let mut t: UCN = ceildiv(&x, &twoc0);
|
||||||
|
loop {
|
||||||
|
// 23. If (2tc0 + 1 > 2^length), then
|
||||||
|
// t = ceiling(2^(length – 1) / (2c0)).
|
||||||
|
let twotc0 = &t * &twoc0;
|
||||||
|
if (&twotc0 + &one) > (&one << length) {
|
||||||
|
t = ceildiv(&twolm1, &twoc0);
|
||||||
|
}
|
||||||
|
// 24. c = 2tc0 + 1.
|
||||||
|
let c = &twotc0 + &one;
|
||||||
|
|
||||||
|
// 25. prime_gen_counter = prime_gen_counter + 1.
|
||||||
|
prime_gen_counter = prime_gen_counter + 1;
|
||||||
|
// 26. a = 0.
|
||||||
|
let mut a_bytes = Vec::new();
|
||||||
|
// 27. For i = 0 to iterations do
|
||||||
|
// a = a + (Hash(prime_seed + i) ∗ 2 i * outlen).
|
||||||
|
//
|
||||||
|
// As with the last time we did this, we're going to do this more
|
||||||
|
// constructively
|
||||||
|
i = iterations as i64;
|
||||||
|
while i >= 0 {
|
||||||
|
let bigi = UCN::from(i as u64);
|
||||||
|
let prime_i = &prime_seed + &bigi;
|
||||||
|
let mut hash_i = hash(&prime_i, length);
|
||||||
|
a_bytes.append(&mut hash_i);
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
let mut a = UCN::from_bytes(&a_bytes);
|
||||||
|
// 28. prime_seed = prime_seed + iterations + 1.
|
||||||
|
prime_seed = &prime_seed + UCN::from(iterations) + &one;
|
||||||
|
// 29. a = 2 + (a mod (c – 3)).
|
||||||
|
a = &two + (a % (&c - &three));
|
||||||
|
// 30. z = a^2t mod c.
|
||||||
|
let z: UCN = a.modexp(&(&two * &t), &c);
|
||||||
|
// 31. If ((1 = GCD(z – 1, c)) and (1 = z^c_0 mod c)), then
|
||||||
|
let gcd_ok = &one == &c.gcd(&(&z - &one));
|
||||||
|
let modexp_ok = &one == &z.modexp(&c0, &c);
|
||||||
|
if gcd_ok && modexp_ok {
|
||||||
|
// 31.1 prime = c.
|
||||||
|
let prime = c;
|
||||||
|
// 31.2 Return (SUCCESS, prime, prime_seed {, prime_gen_counter}).
|
||||||
|
return Ok((prime, prime_seed, prime_gen_counter));
|
||||||
|
}
|
||||||
|
// 32. If (prime_gen_counter ≥ ((4 ∗ length) + old_counter)), then
|
||||||
|
// return (FAILURE, 0, 0 {, 0}).
|
||||||
|
let limit = (4 * length) + old_counter;
|
||||||
|
if prime_gen_counter >= limit {
|
||||||
|
return Err(DSAGenError::TooManyGenAttempts)
|
||||||
|
}
|
||||||
|
// 33. t = t + 1.
|
||||||
|
t = t + &one;
|
||||||
|
// 34. Go to step 23.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ceildiv<T>(a: &T, b: &T) -> T
|
||||||
|
where T: Add<Output=T>,
|
||||||
|
T: Sub<Output=T>,
|
||||||
|
T: Div<Output=T>,
|
||||||
|
T: From<usize>,
|
||||||
|
T: Clone
|
||||||
|
{
|
||||||
|
let aclone: T = a.clone();
|
||||||
|
let bclone: T = b.clone();
|
||||||
|
let one: T = T::from(1 as usize);
|
||||||
|
let x: T = (aclone + bclone.clone()) - one;
|
||||||
|
let res = x / bclone;
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prime_test(x: &UCN) -> bool {
|
||||||
|
let two = UCN::from(2 as u64);
|
||||||
|
let three = UCN::from(3 as u64);
|
||||||
|
let five = UCN::from(5 as u64);
|
||||||
|
|
||||||
|
if x.is_even() {
|
||||||
|
if x == &two {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if x.is_multiple_of(&three) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if x.is_multiple_of(&five) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut divisor = UCN::from(7 as u32);
|
||||||
|
let sqrtx = isqrt(&x);
|
||||||
|
while &divisor < &sqrtx {
|
||||||
|
if x.is_multiple_of(&divisor) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
divisor = next_divisor(divisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isqrt(x: &UCN) -> UCN {
|
||||||
|
let mut num = x.clone();
|
||||||
|
let mut res = UCN::from(0u64);
|
||||||
|
let one = UCN::from(1u64);
|
||||||
|
let mut bit = one << num.bits();
|
||||||
|
|
||||||
|
while &bit > &num {
|
||||||
|
bit >>= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
while !bit.is_zero() {
|
||||||
|
if num >= (&res + &bit) {
|
||||||
|
num = &num - (&res + &bit);
|
||||||
|
res = (&res >> 1) + &bit;
|
||||||
|
} else {
|
||||||
|
res >>= 1;
|
||||||
|
}
|
||||||
|
bit >>= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_divisor(input: UCN) -> UCN {
|
||||||
|
let two = UCN::from(2 as u64);
|
||||||
|
let three = UCN::from(3 as u64);
|
||||||
|
let five = UCN::from(5 as u64);
|
||||||
|
let mut x = input;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
x = &x + &two;
|
||||||
|
|
||||||
|
if x.is_multiple_of(&three) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if x.is_multiple_of(&five) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash(x: &UCN, len: usize) -> Vec<u8> {
|
||||||
|
let bytelen = len / 8;
|
||||||
|
let base = x.to_bytes(bytelen);
|
||||||
|
let mut dgst = Sha256::default();
|
||||||
|
dgst.process(&base);
|
||||||
|
dgst.fixed_result().as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn xorvecs(a: Vec<u8>, b: Vec<u8>) -> Vec<u8> {
|
||||||
|
assert!(a.len() == b.len());
|
||||||
|
let mut c = Vec::with_capacity(a.len());
|
||||||
|
|
||||||
|
for (a,b) in a.iter().zip(b.iter()) {
|
||||||
|
c.push(a ^ b);
|
||||||
|
}
|
||||||
|
c
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
646
src/dsa/gold_tests.rs
Normal file
646
src/dsa/gold_tests.rs
Normal file
@@ -0,0 +1,646 @@
|
|||||||
|
use cryptonum::UCN;
|
||||||
|
use digest::{FixedOutput,Input};
|
||||||
|
use dsa::generation::*;
|
||||||
|
use dsa::rfc6979::*;
|
||||||
|
use dsa::parameters::*;
|
||||||
|
use dsa::private::DSAPrivate;
|
||||||
|
use dsa::public::DSAPublic;
|
||||||
|
use rand::{OsRng,Rng};
|
||||||
|
use sha1::Sha1;
|
||||||
|
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||||
|
use simple_asn1::{der_decode,der_encode};
|
||||||
|
use testing::run_test;
|
||||||
|
|
||||||
|
const NUM_TESTS: u32 = 2;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn pqg_generation_checks() {
|
||||||
|
let mut rng = OsRng::new().unwrap();
|
||||||
|
let params = DSAParameterSize::L1024N160;
|
||||||
|
|
||||||
|
for _ in 0..NUM_TESTS {
|
||||||
|
let seed = get_input_seed(&mut rng,params,n_bits(params)).unwrap();
|
||||||
|
let (p, q, ev) =
|
||||||
|
generate_provable_primes(&mut rng, &seed, params).unwrap();
|
||||||
|
assert!(validate_provable_primes(&mut rng, &p, &q, &ev));
|
||||||
|
let index = rng.gen::<u8>();
|
||||||
|
let pu = p.barrett_u();
|
||||||
|
let g = generate_verifiable_generator(&p, &pu, &q, &ev, index).unwrap();
|
||||||
|
assert!(verify_generator(&p, &q, &ev, index, &g));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dsa_verification_tests()
|
||||||
|
{
|
||||||
|
run_test("tests/dsa/signature.test", 9, |case| {
|
||||||
|
let (neg0, pbytes) = case.get("p").unwrap();
|
||||||
|
let (neg1, gbytes) = case.get("g").unwrap();
|
||||||
|
let (neg2, qbytes) = case.get("q").unwrap();
|
||||||
|
let (neg4, ybytes) = case.get("y").unwrap();
|
||||||
|
let (neg5, hbytes) = case.get("h").unwrap();
|
||||||
|
let (neg6, msg) = case.get("m").unwrap();
|
||||||
|
let (neg7, rbytes) = case.get("r").unwrap();
|
||||||
|
let (neg8, sbytes) = case.get("s").unwrap();
|
||||||
|
|
||||||
|
assert!(!neg0 & !neg1 & !neg2 & !neg4 &
|
||||||
|
!neg5 & !neg6 & !neg7 & !neg8);
|
||||||
|
|
||||||
|
let p = UCN::from_bytes(pbytes);
|
||||||
|
let g = UCN::from_bytes(gbytes);
|
||||||
|
let q = UCN::from_bytes(qbytes);
|
||||||
|
let params = DSAParameters::new(p, g, q).unwrap();
|
||||||
|
let y = UCN::from_bytes(ybytes);
|
||||||
|
let public = DSAPublic::new(¶ms, y);
|
||||||
|
let r = UCN::from_bytes(rbytes);
|
||||||
|
let s = UCN::from_bytes(sbytes);
|
||||||
|
let sig = DSASignature{ r: r, s: s };
|
||||||
|
|
||||||
|
match usize::from(UCN::from_bytes(hbytes)) {
|
||||||
|
0x1 => assert!(public.verify::<Sha1>(msg, &sig)),
|
||||||
|
0x224 => assert!(public.verify::<Sha224>(msg, &sig)),
|
||||||
|
0x256 => assert!(public.verify::<Sha256>(msg, &sig)),
|
||||||
|
0x384 => assert!(public.verify::<Sha384>(msg, &sig)),
|
||||||
|
0x512 => assert!(public.verify::<Sha512>(msg, &sig)),
|
||||||
|
v => panic!("Bad hash size {}!", v)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn dsa_signing_tests()
|
||||||
|
{
|
||||||
|
run_test("tests/dsa/signature.test", 9, |case| {
|
||||||
|
let (neg0, pbytes) = case.get("p").unwrap();
|
||||||
|
let (neg1, gbytes) = case.get("g").unwrap();
|
||||||
|
let (neg2, qbytes) = case.get("q").unwrap();
|
||||||
|
let (neg3, xbytes) = case.get("x").unwrap();
|
||||||
|
let (neg4, ybytes) = case.get("y").unwrap();
|
||||||
|
let (neg5, hbytes) = case.get("h").unwrap();
|
||||||
|
let (neg6, msg) = case.get("m").unwrap();
|
||||||
|
|
||||||
|
|
||||||
|
assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4 & !neg5 & !neg6);
|
||||||
|
|
||||||
|
let p = UCN::from_bytes(pbytes);
|
||||||
|
let g = UCN::from_bytes(gbytes);
|
||||||
|
let q = UCN::from_bytes(qbytes);
|
||||||
|
let params = DSAParameters::new(p, g, q).unwrap();
|
||||||
|
let y = UCN::from_bytes(ybytes);
|
||||||
|
let public = DSAPublic::new(¶ms, y);
|
||||||
|
let x = UCN::from_bytes(xbytes);
|
||||||
|
let private = DSAPrivate::new(¶ms, x);
|
||||||
|
let hash_size = usize::from(UCN::from_bytes(hbytes));
|
||||||
|
|
||||||
|
let sig = match hash_size {
|
||||||
|
0x1 => private.sign::<Sha1>(msg),
|
||||||
|
0x224 => private.sign::<Sha224>(msg),
|
||||||
|
0x256 => private.sign::<Sha256>(msg),
|
||||||
|
0x384 => private.sign::<Sha384>(msg),
|
||||||
|
0x512 => private.sign::<Sha512>(msg),
|
||||||
|
v => panic!("Bad hash size {}!", v)
|
||||||
|
};
|
||||||
|
|
||||||
|
match usize::from(UCN::from_bytes(hbytes)) {
|
||||||
|
0x1 => assert!(public.verify::<Sha1>(msg, &sig)),
|
||||||
|
0x224 => assert!(public.verify::<Sha224>(msg, &sig)),
|
||||||
|
0x256 => assert!(public.verify::<Sha256>(msg, &sig)),
|
||||||
|
0x384 => assert!(public.verify::<Sha384>(msg, &sig)),
|
||||||
|
0x512 => assert!(public.verify::<Sha512>(msg, &sig)),
|
||||||
|
v => panic!("Bad hash size {}!", v)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! run_rfc6979_test {
|
||||||
|
($hash: ty, $val: ident, $public: ident, $private: ident,
|
||||||
|
k $k: expr,
|
||||||
|
r $r: expr,
|
||||||
|
s $s: expr) => ({
|
||||||
|
let mut digest = <$hash>::default();
|
||||||
|
digest.process(&$val);
|
||||||
|
let h1 = digest.fixed_result().as_slice().to_vec();
|
||||||
|
let rbytes = $r;
|
||||||
|
let sbytes = $s;
|
||||||
|
let r = UCN::from_bytes(&rbytes);
|
||||||
|
let s = UCN::from_bytes(&sbytes);
|
||||||
|
let mut iter = KIterator::<$hash>::new(&h1,
|
||||||
|
n_bits($public.params.size),
|
||||||
|
&$public.params.q,
|
||||||
|
&$private.x);
|
||||||
|
let next = iter.next().unwrap();
|
||||||
|
let size = (next.bits() + 7) / 8;
|
||||||
|
let k1 = next.to_bytes(size);
|
||||||
|
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 = UCN::from_bytes(&pbytes);
|
||||||
|
let q = UCN::from_bytes(&qbytes);
|
||||||
|
let g = UCN::from_bytes(&gbytes);
|
||||||
|
let params = DSAParameters::new(p, g, q).unwrap();
|
||||||
|
let x = UCN::from_bytes(&xbytes);
|
||||||
|
let y = UCN::from_bytes(&ybytes);
|
||||||
|
let private = DSAPrivate::new(¶ms, x);
|
||||||
|
let public = DSAPublic::new(¶ms, 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, sample, public, private,
|
||||||
|
k vec![0x7B, 0xDB, 0x6B, 0x0F, 0xF7, 0x56, 0xE1, 0xBB,
|
||||||
|
0x5D, 0x53, 0x58, 0x3E, 0xF9, 0x79, 0x08, 0x2F,
|
||||||
|
0x9A, 0xD5, 0xBD, 0x5B],
|
||||||
|
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, sample, public, private,
|
||||||
|
k vec![0x56, 0x20, 0x97, 0xC0, 0x67, 0x82, 0xD6, 0x0C,
|
||||||
|
0x30, 0x37, 0xBA, 0x7B, 0xE1, 0x04, 0x77, 0x43,
|
||||||
|
0x44, 0x68, 0x76, 0x49],
|
||||||
|
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, sample, public, private,
|
||||||
|
k vec![0x51, 0x9B, 0xA0, 0x54, 0x6D, 0x0C, 0x39, 0x20,
|
||||||
|
0x2A, 0x7D, 0x34, 0xD7, 0xDF, 0xA5, 0xE7, 0x60,
|
||||||
|
0xB3, 0x18, 0xBC, 0xFB],
|
||||||
|
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, sample, public, private,
|
||||||
|
k vec![0x95, 0x89, 0x7C, 0xD7, 0xBB, 0xB9, 0x44, 0xAA,
|
||||||
|
0x93, 0x2D, 0xBC, 0x57, 0x9C, 0x1C, 0x09, 0xEB,
|
||||||
|
0x6F, 0xCF, 0xC5, 0x95],
|
||||||
|
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, sample, public, private,
|
||||||
|
k vec![0x09, 0xEC, 0xE7, 0xCA, 0x27, 0xD0, 0xF5, 0xA4,
|
||||||
|
0xDD, 0x4E, 0x55, 0x6C, 0x9D, 0xF1, 0xD2, 0x1D,
|
||||||
|
0x28, 0x10, 0x4F, 0x8B],
|
||||||
|
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, test, public, private,
|
||||||
|
k vec![0x5C, 0x84, 0x2D, 0xF4, 0xF9, 0xE3, 0x44, 0xEE,
|
||||||
|
0x09, 0xF0, 0x56, 0x83, 0x8B, 0x42, 0xC7, 0xA1,
|
||||||
|
0x7F, 0x4A, 0x64, 0x33],
|
||||||
|
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, test, public, private,
|
||||||
|
k vec![0x45, 0x98, 0xB8, 0xEF, 0xC1, 0xA5, 0x3B, 0xC8,
|
||||||
|
0xAE, 0xCD, 0x58, 0xD1, 0xAB, 0xBB, 0x0C, 0x0C,
|
||||||
|
0x71, 0xE6, 0x72, 0x97],
|
||||||
|
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, test, public, private,
|
||||||
|
k vec![0x5A, 0x67, 0x59, 0x2E, 0x81, 0x28, 0xE0, 0x3A,
|
||||||
|
0x41, 0x7B, 0x04, 0x84, 0x41, 0x0F, 0xB7, 0x2C,
|
||||||
|
0x0B, 0x63, 0x0E, 0x1A],
|
||||||
|
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, test, public, private,
|
||||||
|
k vec![0x22, 0x01, 0x56, 0xB7, 0x61, 0xF6, 0xCA, 0x5E,
|
||||||
|
0x6C, 0x9F, 0x1B, 0x9C, 0xF9, 0xC2, 0x4B, 0xE2,
|
||||||
|
0x5F, 0x98, 0xCD, 0x89],
|
||||||
|
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, test, public, private,
|
||||||
|
k vec![0x65, 0xD2, 0xC2, 0xEE, 0xB1, 0x75, 0xE3, 0x70,
|
||||||
|
0xF2, 0x8C, 0x75, 0xBF, 0xCD, 0xC0, 0x28, 0xD2,
|
||||||
|
0x2C, 0x7D, 0xBE, 0x9C],
|
||||||
|
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 = UCN::from_bytes(&pbytes);
|
||||||
|
let q = UCN::from_bytes(&qbytes);
|
||||||
|
let g = UCN::from_bytes(&gbytes);
|
||||||
|
let params = DSAParameters::new(p, g, q).unwrap();
|
||||||
|
let x = UCN::from_bytes(&xbytes);
|
||||||
|
let y = UCN::from_bytes(&ybytes);
|
||||||
|
let private = DSAPrivate::new(¶ms, x);
|
||||||
|
let public = DSAPublic::new(¶ms, 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, sample, public, private,
|
||||||
|
k vec![0x88,0x8F,0xA6,0xF7,0x73,0x8A,0x41,0xBD,
|
||||||
|
0xC9,0x84,0x64,0x66,0xAB,0xDB,0x81,0x74,
|
||||||
|
0xC0,0x33,0x82,0x50,0xAE,0x50,0xCE,0x95,
|
||||||
|
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, sample, public, private,
|
||||||
|
k vec![0xBC,0x37,0x29,0x67,0x70,0x20,0x82,0xE1,
|
||||||
|
0xAA,0x4F,0xCE,0x89,0x22,0x09,0xF7,0x1A,
|
||||||
|
0xE4,0xAD,0x25,0xA6,0xDF,0xD8,0x69,0x33,
|
||||||
|
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, sample, public, private,
|
||||||
|
k vec![0x89,0x26,0xA2,0x7C,0x40,0x48,0x42,0x16,
|
||||||
|
0xF0,0x52,0xF4,0x42,0x7C,0xFD,0x56,0x47,
|
||||||
|
0x33,0x8B,0x7B,0x39,0x39,0xBC,0x65,0x73,
|
||||||
|
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, sample, public, private,
|
||||||
|
k vec![0xC3,0x45,0xD5,0xAB,0x3D,0xA0,0xA5,0xBC,
|
||||||
|
0xB7,0xEC,0x8F,0x8F,0xB7,0xA7,0xE9,0x60,
|
||||||
|
0x69,0xE0,0x3B,0x20,0x63,0x71,0xEF,0x7D,
|
||||||
|
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, sample, public, private,
|
||||||
|
k vec![0x5A,0x12,0x99,0x44,0x31,0x78,0x54,0x85,
|
||||||
|
0xB3,0xF5,0xF0,0x67,0x22,0x15,0x17,0x79,
|
||||||
|
0x1B,0x85,0xA5,0x97,0xB7,0xA9,0x43,0x69,
|
||||||
|
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, test, public, private,
|
||||||
|
k vec![0x6E,0xEA,0x48,0x6F,0x9D,0x41,0xA0,0x37,
|
||||||
|
0xB2,0xC6,0x40,0xBC,0x56,0x45,0x69,0x4F,
|
||||||
|
0xF8,0xFF,0x4B,0x98,0xD0,0x66,0xA2,0x5F,
|
||||||
|
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, test, public, private,
|
||||||
|
k vec![0x06,0xBD,0x4C,0x05,0xED,0x74,0x71,0x91,
|
||||||
|
0x06,0x22,0x3B,0xE3,0x3F,0x2D,0x95,0xDA,
|
||||||
|
0x6B,0x3B,0x54,0x1D,0xAD,0x7B,0xFB,0xD7,
|
||||||
|
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, test, public, private,
|
||||||
|
k vec![0x1D,0x6C,0xE6,0xDD,0xA1,0xC5,0xD3,0x73,
|
||||||
|
0x07,0x83,0x9C,0xD0,0x3A,0xB0,0xA5,0xCB,
|
||||||
|
0xB1,0x8E,0x60,0xD8,0x00,0x93,0x7D,0x67,
|
||||||
|
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, test, public, private,
|
||||||
|
k vec![0x20,0x6E,0x61,0xF7,0x3D,0xBE,0x1B,0x2D,
|
||||||
|
0xC8,0xBE,0x73,0x6B,0x22,0xB0,0x79,0xE9,
|
||||||
|
0xDA,0xCD,0x97,0x4D,0xB0,0x0E,0xEB,0xBC,
|
||||||
|
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, test, public, private,
|
||||||
|
k vec![0xAF,0xF1,0x65,0x1E,0x4C,0xD6,0x03,0x6D,
|
||||||
|
0x57,0xAA,0x8B,0x2A,0x05,0xCC,0xF1,0xA9,
|
||||||
|
0xD5,0xA4,0x01,0x66,0x34,0x0E,0xCB,0xBD,
|
||||||
|
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]);
|
||||||
|
}
|
||||||
77
src/dsa/mod.rs
Normal file
77
src/dsa/mod.rs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
mod errors;
|
||||||
|
mod generation;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod gold_tests;
|
||||||
|
mod parameters;
|
||||||
|
mod public;
|
||||||
|
mod private;
|
||||||
|
pub(crate) mod rfc6979;
|
||||||
|
|
||||||
|
pub use self::public::DSAPublic;
|
||||||
|
pub use self::private::DSAPrivate;
|
||||||
|
pub use self::rfc6979::DSASignature;
|
||||||
|
|
||||||
|
use cryptonum::UCN;
|
||||||
|
use rand::{OsRng,Rng};
|
||||||
|
use self::errors::*;
|
||||||
|
use self::parameters::*;
|
||||||
|
|
||||||
|
/// A DSA key pair
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct DSAKeyPair {
|
||||||
|
pub private: DSAPrivate,
|
||||||
|
pub public: DSAPublic
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DSAKeyPair {
|
||||||
|
pub fn generate(size: DSAParameterSize)
|
||||||
|
-> Result<DSAKeyPair,DSAGenError>
|
||||||
|
{
|
||||||
|
let mut rng = OsRng::new()?;
|
||||||
|
DSAKeyPair::generate_rng(&mut rng, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_rng<G: Rng>(rng: &mut G, size: DSAParameterSize)
|
||||||
|
-> Result<DSAKeyPair,DSAGenError>
|
||||||
|
{
|
||||||
|
let params = DSAParameters::generate_w_rng(rng, size)?;
|
||||||
|
DSAKeyPair::generate_w_params_rng(rng, ¶ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_w_params(params: &DSAParameters)
|
||||||
|
-> Result<DSAKeyPair,DSAGenError>
|
||||||
|
{
|
||||||
|
let mut rng = OsRng::new()?;
|
||||||
|
DSAKeyPair::generate_w_params_rng(&mut rng, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_w_params_rng<G: Rng>(rng: &mut G, params: &DSAParameters)
|
||||||
|
-> Result<DSAKeyPair,DSAGenError>
|
||||||
|
{
|
||||||
|
// 1. N = len(q); L = len(p);
|
||||||
|
let n = n_bits(params.size);
|
||||||
|
// 2. If the (L,N) pair is invalid, then return an ERROR indicator,
|
||||||
|
// Invalid_x, and Invalid_y.
|
||||||
|
// 3. requested_security_strength = the security strength associated
|
||||||
|
// with the (L, N) pair; see SP 800-57.
|
||||||
|
// 4. Obtain a string of N+64 returned_bits from an RBG with a security
|
||||||
|
// strength of requested_security_strength or more. If an ERROR
|
||||||
|
// indication is returned, then return an ERROR indication,
|
||||||
|
// Invalid_x, and Invalid_y.
|
||||||
|
let returned_bits: Vec<u8> = rng.gen_iter().take(n + 8).collect();
|
||||||
|
// 5. Convert returned_bits to the (non-negative) integer c.
|
||||||
|
let c = UCN::from_bytes(&returned_bits);
|
||||||
|
// 6. x = (c mod (q-1)) + 1.
|
||||||
|
let one = UCN::from(1 as u64);
|
||||||
|
let x = (&c % (¶ms.q - &one)) + &one;
|
||||||
|
// 7. y = g^x mod p
|
||||||
|
let y = params.g.fastmodexp(&x, ¶ms.pu);
|
||||||
|
// 8. Return SUCCESS, x, and y.
|
||||||
|
let private = DSAPrivate { params: params.clone(), x: x };
|
||||||
|
let public = DSAPublic { params: params.clone(), y: y };
|
||||||
|
Ok(DSAKeyPair {
|
||||||
|
private: private,
|
||||||
|
public: public
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
119
src/dsa/parameters.rs
Normal file
119
src/dsa/parameters.rs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
use cryptonum::{BarrettUCN,UCN};
|
||||||
|
use dsa::errors::*;
|
||||||
|
use dsa::generation::{DSAGenEvidence,verify_generator,
|
||||||
|
get_input_seed,generate_provable_primes,
|
||||||
|
generate_verifiable_generator,
|
||||||
|
validate_provable_primes};
|
||||||
|
use rand::{OsRng,Rng};
|
||||||
|
|
||||||
|
/// These are the legal lengths for L and N when using DSA; essentially,
|
||||||
|
/// the bit sizes available for the algorithms.
|
||||||
|
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||||
|
pub enum DSAParameterSize { L1024N160, L2048N224, L2048N256, L3072N256 }
|
||||||
|
|
||||||
|
pub fn n_bits(ps: DSAParameterSize) -> usize {
|
||||||
|
match ps {
|
||||||
|
DSAParameterSize::L1024N160 => 160,
|
||||||
|
DSAParameterSize::L2048N224 => 224,
|
||||||
|
DSAParameterSize::L2048N256 => 256,
|
||||||
|
DSAParameterSize::L3072N256 => 256,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn l_bits(ps: DSAParameterSize) -> usize {
|
||||||
|
match ps {
|
||||||
|
DSAParameterSize::L1024N160 => 1024,
|
||||||
|
DSAParameterSize::L2048N224 => 2048,
|
||||||
|
DSAParameterSize::L2048N256 => 2048,
|
||||||
|
DSAParameterSize::L3072N256 => 3072,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A set of DSA parameters, which are shared across both the public and private
|
||||||
|
/// keys.
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct DSAParameters {
|
||||||
|
pub size: DSAParameterSize,
|
||||||
|
pub p: UCN,
|
||||||
|
pub g: UCN,
|
||||||
|
pub q: UCN,
|
||||||
|
pub pu: BarrettUCN,
|
||||||
|
pub qu: BarrettUCN
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DSAParameters {
|
||||||
|
/// Generate a new set of DSA parameters, from a certificate file or some
|
||||||
|
/// other source. This will try to find an appropriate size based on the
|
||||||
|
/// size of the values provided, but will fail (returning
|
||||||
|
/// `DSAError::InvalidParamSize`) if it can't find a reasonable one.
|
||||||
|
pub fn new(p: UCN, g: UCN, q: UCN)
|
||||||
|
-> Result<DSAParameters,DSAError>
|
||||||
|
{
|
||||||
|
let l = ((p.bits() + 255) / 256) * 256;
|
||||||
|
let n = ((q.bits() + 15) / 16) * 16;
|
||||||
|
let size = match (l, n) {
|
||||||
|
(1024, 160) => DSAParameterSize::L1024N160,
|
||||||
|
(2048, 224) => DSAParameterSize::L2048N224,
|
||||||
|
(2048, 256) => DSAParameterSize::L2048N256,
|
||||||
|
(3072, 256) => DSAParameterSize::L3072N256,
|
||||||
|
_ => return Err(DSAError::InvalidParamSize)
|
||||||
|
};
|
||||||
|
let pu = p.barrett_u();
|
||||||
|
let qu = q.barrett_u();
|
||||||
|
Ok(DSAParameters{ size: size, p: p, g: g, q: q, pu: pu, qu: qu })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a new set of DSA parameters for use. You probably shouldn't be
|
||||||
|
/// doing this. This is equivalent to calling `generate_w_rng` with
|
||||||
|
/// `OsRng`, which is supposed to be cryptographically sound.
|
||||||
|
pub fn generate(ps: DSAParameterSize)
|
||||||
|
-> Result<DSAParameters,DSAGenError>
|
||||||
|
{
|
||||||
|
let mut rng = OsRng::new()?;
|
||||||
|
DSAParameters::generate_w_rng(&mut rng, ps)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a new set of DSA parameters for use, using the given entropy
|
||||||
|
/// source. I would normally include a note here about making sure to use
|
||||||
|
/// a good one, but if you're using DSA you've already given up a little
|
||||||
|
/// bit of the high ground, there.
|
||||||
|
pub fn generate_w_rng<G: Rng>(rng: &mut G, ps: DSAParameterSize)
|
||||||
|
-> Result<DSAParameters,DSAGenError>
|
||||||
|
{
|
||||||
|
let firstseed = get_input_seed(rng, ps, n_bits(ps))?;
|
||||||
|
let (p, q, ev) = generate_provable_primes(rng, &firstseed, ps)?;
|
||||||
|
DSAParameters::generate_g(ps, p, q, ev, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Using the given p and q values and an index, create a new DSAParameters
|
||||||
|
/// by creating a new generator g that works with p and q.
|
||||||
|
fn generate_g(ps: DSAParameterSize,
|
||||||
|
p: UCN, q: UCN,
|
||||||
|
ev: DSAGenEvidence,
|
||||||
|
idx: u8)
|
||||||
|
-> Result<DSAParameters, DSAGenError>
|
||||||
|
{
|
||||||
|
let pu = p.barrett_u();
|
||||||
|
let qu = q.barrett_u();
|
||||||
|
let g = generate_verifiable_generator(&p, &pu, &q, &ev, idx)?;
|
||||||
|
Ok(DSAParameters{ size: ps, p: p, q: q, g: g, pu: pu, qu: qu })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given the provided evidence, validate that the domain parameters
|
||||||
|
/// were appropriately constructed.
|
||||||
|
pub fn verify(&self, ev: &DSAGenEvidence, idx: u8) -> bool {
|
||||||
|
let mut rng = OsRng::new().unwrap();
|
||||||
|
self.verify_w_rng(&mut rng, ev, idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given the set of inputs you used to generate your system, verify that
|
||||||
|
/// everything makes sense.
|
||||||
|
pub fn verify_w_rng<G: Rng>(&self, r: &mut G, ev: &DSAGenEvidence, idx: u8)
|
||||||
|
-> bool
|
||||||
|
{
|
||||||
|
validate_provable_primes(r, &self.p, &self.q, ev) &&
|
||||||
|
verify_generator(&self.p, &self.q, ev, idx, &self.g)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
89
src/dsa/private.rs
Normal file
89
src/dsa/private.rs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
use cryptonum::UCN;
|
||||||
|
use digest::{BlockInput,FixedOutput,Input};
|
||||||
|
use digest::generic_array::ArrayLength;
|
||||||
|
use dsa::parameters::{DSAParameters,n_bits};
|
||||||
|
use dsa::rfc6979::{DSASignature,KIterator,bits2int};
|
||||||
|
use hmac::Hmac;
|
||||||
|
use std::ops::Rem;
|
||||||
|
|
||||||
|
/// A DSA private key.
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct DSAPrivate {
|
||||||
|
pub params: DSAParameters,
|
||||||
|
pub(crate) x: UCN
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DSAPrivate {
|
||||||
|
pub fn new(params: &DSAParameters, x: UCN) -> DSAPrivate {
|
||||||
|
DSAPrivate {
|
||||||
|
params: params.clone(),
|
||||||
|
x: x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sign<Hash>(&self, m: &[u8]) -> DSASignature
|
||||||
|
where
|
||||||
|
Hash: Clone + BlockInput + Input + FixedOutput + Default,
|
||||||
|
Hmac<Hash>: Clone,
|
||||||
|
Hash::BlockSize: ArrayLength<u8>
|
||||||
|
{
|
||||||
|
// This algorithm is per RFC 6979, which has a nice, relatively
|
||||||
|
// straightforward description of how to do DSA signing.
|
||||||
|
//
|
||||||
|
// 1. H(m) is transformed into an integer modulo q using the bits2int
|
||||||
|
// transform and an extra modular reduction:
|
||||||
|
//
|
||||||
|
// h = bits2int(H(m)) mod q
|
||||||
|
//
|
||||||
|
// As was noted in the description of bits2octets, the extra
|
||||||
|
// modular reduction is no more than a conditional subtraction.
|
||||||
|
//
|
||||||
|
let mut digest = <Hash>::default();
|
||||||
|
digest.process(m);
|
||||||
|
let n = n_bits(self.params.size);
|
||||||
|
let h1: Vec<u8> = digest.fixed_result()
|
||||||
|
.as_slice()
|
||||||
|
.iter()
|
||||||
|
.map(|x| *x)
|
||||||
|
.collect();
|
||||||
|
let h0 = bits2int(&h1, n);
|
||||||
|
let h = h0.reduce(&self.params.qu);
|
||||||
|
|
||||||
|
// 2. A random value modulo q, dubbed k, is generated. That value
|
||||||
|
// shall not be 0; hence, it lies in the [1, q-1] range. Most
|
||||||
|
// of the remainder of this document will revolve around the
|
||||||
|
// process used to generate k. In plain DSA or ECDSA, k should
|
||||||
|
// be selected through a random selection that chooses a value
|
||||||
|
// among the q-1 possible values with uniform probability.
|
||||||
|
for k in KIterator::<Hash>::new(&h1, n, &self.params.q, &self.x) {
|
||||||
|
// 3. A value r (modulo q) is computed from k and the key
|
||||||
|
// parameters:
|
||||||
|
// * For DSA:
|
||||||
|
// r = g^k mod p mod q
|
||||||
|
//
|
||||||
|
// (The exponentiation is performed modulo p, yielding a
|
||||||
|
// number between 0 and p-1, which is then further reduced
|
||||||
|
// modulo q.)
|
||||||
|
// * For ECDSA ...
|
||||||
|
//
|
||||||
|
// If r turns out to be zero, a new k should be selected and r
|
||||||
|
// computed again (this is an utterly improbable occurrence).
|
||||||
|
let r = self.params.g.fastmodexp(&k, &self.params.pu)
|
||||||
|
.rem(&self.params.q);
|
||||||
|
if r.is_zero() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 4. The value s (modulo q) is computed:
|
||||||
|
//
|
||||||
|
// s = (h+x*r)/k mod q
|
||||||
|
//
|
||||||
|
// The pair (r, s) is the signature.
|
||||||
|
let kinv = k.modinv(&self.params.q);
|
||||||
|
let s = ((&h + (&self.x * &r)) * &kinv).rem(&self.params.q);
|
||||||
|
return DSASignature{ r: r, s: s };
|
||||||
|
}
|
||||||
|
panic!("The world is broken; couldn't find a k in sign().");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
72
src/dsa/public.rs
Normal file
72
src/dsa/public.rs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
use cryptonum::{SCN,UCN};
|
||||||
|
use digest::{FixedOutput,Input};
|
||||||
|
use dsa::parameters::{DSAParameters,n_bits};
|
||||||
|
use dsa::rfc6979::DSASignature;
|
||||||
|
use num::BigInt;
|
||||||
|
use simple_asn1::{ASN1Block,ToASN1,ASN1EncodeErr,ASN1Class};
|
||||||
|
use std::cmp::min;
|
||||||
|
use std::ops::Rem;
|
||||||
|
|
||||||
|
/// A DSA key pair
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct DSAPublic {
|
||||||
|
pub params: DSAParameters,
|
||||||
|
pub y: UCN
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DSAPublic {
|
||||||
|
pub fn new(params: &DSAParameters, y: UCN) -> DSAPublic {
|
||||||
|
DSAPublic {
|
||||||
|
params: params.clone(),
|
||||||
|
y: y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify<Hash>(&self, m: &[u8], sig: &DSASignature) -> bool
|
||||||
|
where Hash: Clone + Default + Input + FixedOutput
|
||||||
|
{
|
||||||
|
if sig.r >= self.params.q {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if sig.s >= self.params.q {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// w = (s')^-1 mod q;
|
||||||
|
let w = sig.s.modinv(&self.params.q);
|
||||||
|
// z = the leftmost min(N, outlen) bits of Hash(M').
|
||||||
|
let mut digest = <Hash>::default();
|
||||||
|
digest.process(m);
|
||||||
|
let z = { let mut bytes: Vec<u8> = digest.fixed_result()
|
||||||
|
.as_slice()
|
||||||
|
.iter()
|
||||||
|
.map(|x| *x)
|
||||||
|
.collect();
|
||||||
|
let n = n_bits(self.params.size) / 8;
|
||||||
|
let len = min(n, bytes.len());
|
||||||
|
bytes.truncate(len);
|
||||||
|
UCN::from_bytes(&bytes) };
|
||||||
|
// u1 = (zw) mod q
|
||||||
|
let u1 = (&z * &w).reduce(&self.params.qu);
|
||||||
|
// u2 = (rw) mod q
|
||||||
|
let u2 = (&sig.r * &w).reduce(&self.params.qu);
|
||||||
|
// v = (((g)^u1(y)^u2) mod p) mod q
|
||||||
|
let v_1 = self.params.g.fastmodexp(&u1, &self.params.pu);
|
||||||
|
let v_2 = self.y.fastmodexp(&u2, &self.params.pu);
|
||||||
|
let v = (&v_1 * &v_2).reduce(&self.params.pu)
|
||||||
|
.rem(&self.params.q);
|
||||||
|
// if v = r, then the signature is verified
|
||||||
|
v == sig.r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToASN1 for DSAPublic {
|
||||||
|
type Error = ASN1EncodeErr;
|
||||||
|
|
||||||
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
|
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||||
|
{
|
||||||
|
let inty = SCN::from(self.y.clone());
|
||||||
|
let yblock = ASN1Block::Integer(c, 0, BigInt::from(inty));
|
||||||
|
Ok(vec![yblock])
|
||||||
|
}
|
||||||
|
}
|
||||||
324
src/dsa/rfc6979.rs
Normal file
324
src/dsa/rfc6979.rs
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
use cryptonum::UCN;
|
||||||
|
use digest::{BlockInput,FixedOutput,Input};
|
||||||
|
use digest::generic_array::ArrayLength;
|
||||||
|
use hmac::{Hmac,Mac};
|
||||||
|
use num::{BigInt,Signed};
|
||||||
|
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,
|
||||||
|
FromASN1, ToASN1};
|
||||||
|
use std::clone::Clone;
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub struct KIterator<H>
|
||||||
|
where
|
||||||
|
H: Clone + BlockInput + Input + FixedOutput + Default,
|
||||||
|
H::BlockSize : ArrayLength<u8>
|
||||||
|
{
|
||||||
|
hmac_k: Hmac<H>,
|
||||||
|
V: Vec<u8>,
|
||||||
|
q: UCN,
|
||||||
|
qlen: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H> KIterator<H>
|
||||||
|
where
|
||||||
|
H: Clone + BlockInput + Input + FixedOutput + Default,
|
||||||
|
Hmac<H>: Clone,
|
||||||
|
H::BlockSize : ArrayLength<u8>
|
||||||
|
{
|
||||||
|
pub fn new(h1: &[u8], qlen: usize, q: &UCN, x: &UCN) -> KIterator<H>
|
||||||
|
{
|
||||||
|
// 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(&K, &input);
|
||||||
|
// e. Set:
|
||||||
|
//
|
||||||
|
// V = HMAC_K(V)
|
||||||
|
V = 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(&K, &input);
|
||||||
|
// g. Set:
|
||||||
|
//
|
||||||
|
// V = HMAC_K(V)
|
||||||
|
V = hmac(&K, &V);
|
||||||
|
// h is for later ...
|
||||||
|
KIterator {
|
||||||
|
hmac_k: Hmac::<H>::new(&K).unwrap(),
|
||||||
|
V: V,
|
||||||
|
q: q.clone(),
|
||||||
|
qlen: qlen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H> Iterator for KIterator<H>
|
||||||
|
where
|
||||||
|
H: Clone + BlockInput + Input + FixedOutput + Default,
|
||||||
|
Hmac<H>: Clone,
|
||||||
|
H::BlockSize : ArrayLength<u8>
|
||||||
|
{
|
||||||
|
type Item = UCN;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<UCN> {
|
||||||
|
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 = 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).unwrap();
|
||||||
|
self.V = runhmac(&self.hmac_k, &self.V);
|
||||||
|
//
|
||||||
|
// and loop (try to generate a new T, and so on).
|
||||||
|
//
|
||||||
|
if !resk.is_zero() && (&resk < &self.q) {
|
||||||
|
return Some(resk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bits2int(x: &[u8], qlen: usize) -> UCN {
|
||||||
|
let mut value = UCN::from_bytes(x);
|
||||||
|
let vlen = x.len() * 8;
|
||||||
|
|
||||||
|
if vlen > qlen {
|
||||||
|
value >>= vlen - qlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bits2octets(x: &[u8], q: &UCN, qlen: usize) -> Vec<u8> {
|
||||||
|
let z1 = bits2int(x, qlen);
|
||||||
|
let res = if &z1 > q { z1 - q } else { z1 };
|
||||||
|
int2octets(&res, qlen)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn int2octets(x: &UCN, qlen_bits: usize) -> Vec<u8> {
|
||||||
|
let qlen_bytes = (qlen_bits + 7) / 8;
|
||||||
|
x.to_bytes(qlen_bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn runhmac<H>(base: &Hmac<H>, m: &[u8]) -> Vec<u8>
|
||||||
|
where
|
||||||
|
H: Clone + BlockInput + Input + FixedOutput + Default,
|
||||||
|
Hmac<H>: Clone,
|
||||||
|
H::BlockSize : ArrayLength<u8>
|
||||||
|
{
|
||||||
|
let mut runner = base.clone();
|
||||||
|
runner.input(&m);
|
||||||
|
runner.result().code().as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hmac<H>(k: &[u8], m: &[u8]) -> Vec<u8>
|
||||||
|
where
|
||||||
|
H: Clone + BlockInput + Input + FixedOutput + Default,
|
||||||
|
Hmac<H>: Clone,
|
||||||
|
H::BlockSize : ArrayLength<u8>
|
||||||
|
{
|
||||||
|
let mut runner = Hmac::<H>::new(&k).unwrap();
|
||||||
|
runner.input(&m);
|
||||||
|
runner.result().code().as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A DSA Signature
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct DSASignature {
|
||||||
|
pub r: UCN,
|
||||||
|
pub s: UCN
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub enum DSADecodeError {
|
||||||
|
ASN1Error(ASN1DecodeErr),
|
||||||
|
NoSignatureFound,
|
||||||
|
NegativeSigValues
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ASN1DecodeErr> for DSADecodeError {
|
||||||
|
fn from(a: ASN1DecodeErr) -> DSADecodeError {
|
||||||
|
DSADecodeError::ASN1Error(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromASN1 for DSASignature {
|
||||||
|
type Error = DSADecodeError;
|
||||||
|
|
||||||
|
fn from_asn1(v: &[ASN1Block])
|
||||||
|
-> Result<(DSASignature,&[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)) => {
|
||||||
|
if rint.is_negative() || sint.is_negative() {
|
||||||
|
return Err(DSADecodeError::NegativeSigValues)
|
||||||
|
}
|
||||||
|
let r = UCN::from(rint);
|
||||||
|
let s = UCN::from(sint);
|
||||||
|
Ok((DSASignature{ r: r, s: s }, rest))
|
||||||
|
}
|
||||||
|
_ => Err(DSADecodeError::NoSignatureFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(DSADecodeError::NoSignatureFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToASN1 for DSASignature {
|
||||||
|
type Error = ASN1EncodeErr;
|
||||||
|
|
||||||
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
|
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||||
|
{
|
||||||
|
let rb = ASN1Block::Integer(c, 0, BigInt::from(self.r.clone()));
|
||||||
|
let sb = ASN1Block::Integer(c, 0, BigInt::from(self.s.clone()));
|
||||||
|
Ok(vec![ASN1Block::Sequence(c, 0, vec![rb,sb])])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use sha2::Sha256;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
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 = UCN::from_bytes(&XBYTES);
|
||||||
|
let octets = int2octets(&x, 163);
|
||||||
|
let target = vec![0x00, 0x9A, 0x4D, 0x67, 0x92, 0x29, 0x5A, 0x7F,
|
||||||
|
0x73, 0x0F, 0xC3, 0xF2, 0xB4, 0x9C, 0xBC, 0x0F,
|
||||||
|
0x62, 0xE8, 0x62, 0x27, 0x2F];
|
||||||
|
assert_eq!(octets, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bits2octets_example() {
|
||||||
|
let q = UCN::from_bytes(&QBYTES);
|
||||||
|
let octets = bits2octets(&H1, &q, 163);
|
||||||
|
let target = vec![0x01, 0x79, 0x5E, 0xDF, 0x0D, 0x54, 0xDB, 0x76,
|
||||||
|
0x0F, 0x15, 0x6D, 0x0D, 0xAC, 0x04, 0xC0, 0x32,
|
||||||
|
0x2B, 0x3A, 0x20, 0x42, 0x24];
|
||||||
|
assert_eq!(octets, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn k_gen_example() {
|
||||||
|
let q = UCN::from_bytes(&QBYTES);
|
||||||
|
let x = UCN::from_bytes(&XBYTES);
|
||||||
|
let mut iter = KIterator::<Sha256>::new(&H1, 163, &q, &x);
|
||||||
|
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 = UCN::from_bytes(&target);
|
||||||
|
assert_eq!(x, x2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
443
src/ecdsa/curves.rs
Normal file
443
src/ecdsa/curves.rs
Normal file
@@ -0,0 +1,443 @@
|
|||||||
|
use cryptonum::{BarrettUCN,SCN,UCN};
|
||||||
|
use ecdsa::point::ECPoint;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
pub struct EllipticCurve {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub p: [u8; 66],
|
||||||
|
pub n: [u8; 66],
|
||||||
|
pub seed: [u8; 66],
|
||||||
|
pub c: [u8; 66],
|
||||||
|
pub a: [u8; 66],
|
||||||
|
pub b: [u8; 66],
|
||||||
|
pub gx: [u8; 66],
|
||||||
|
pub gy: [u8; 66]
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for EllipticCurve {
|
||||||
|
fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for EllipticCurve {
|
||||||
|
fn eq(&self, other: &EllipticCurve) -> bool {
|
||||||
|
self.name == other.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EllipticCurve {
|
||||||
|
pub fn get_p(&self) -> UCN {
|
||||||
|
UCN::from_bytes(&self.p)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_pu(&self) -> BarrettUCN {
|
||||||
|
self.get_p().barrett_uk(self.get_p().contents.len() + 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_n(&self) -> UCN {
|
||||||
|
UCN::from_bytes(&self.n)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_seed(&self) -> UCN {
|
||||||
|
UCN::from_bytes(&self.seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_c(&self) -> UCN {
|
||||||
|
UCN::from_bytes(&self.c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_a(&self) -> UCN {
|
||||||
|
UCN::from_bytes(&self.a)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_b(&self) -> UCN {
|
||||||
|
UCN::from_bytes(&self.b)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default(&'static self) -> ECPoint {
|
||||||
|
let x = SCN::from(UCN::from_bytes(&self.gx));
|
||||||
|
let y = SCN::from(UCN::from_bytes(&self.gy));
|
||||||
|
ECPoint::new(self, x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const NIST_P192: EllipticCurve = EllipticCurve {
|
||||||
|
name: "secp192r1",
|
||||||
|
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff ],
|
||||||
|
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99, 0xde,
|
||||||
|
0xf8, 0x36, 0x14, 0x6b, 0xc9, 0xb1, 0xb4, 0xd2,
|
||||||
|
0x28, 0x31 ],
|
||||||
|
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x45,
|
||||||
|
0xae, 0x6f, 0xc8, 0x42, 0x2f, 0x64, 0xed, 0x57,
|
||||||
|
0x95, 0x28, 0xd3, 0x81, 0x20, 0xea, 0xe1, 0x21,
|
||||||
|
0x96, 0xd5 ],
|
||||||
|
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x30, 0x99, 0xd2, 0xbb, 0xbf, 0xcb,
|
||||||
|
0x25, 0x38, 0x54, 0x2d, 0xcd, 0x5f, 0xb0, 0x78,
|
||||||
|
0xb6, 0xef, 0x5f, 0x3d, 0x6f, 0xe2, 0xc7, 0x45,
|
||||||
|
0xde, 0x65 ],
|
||||||
|
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xfc ],
|
||||||
|
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x64, 0x21, 0x05, 0x19, 0xe5, 0x9c,
|
||||||
|
0x80, 0xe7, 0x0f, 0xa7, 0xe9, 0xab, 0x72, 0x24,
|
||||||
|
0x30, 0x49, 0xfe, 0xb8, 0xde, 0xec, 0xc1, 0x46,
|
||||||
|
0xb9, 0xb1 ],
|
||||||
|
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x18, 0x8d, 0xa8, 0x0e, 0xb0, 0x30,
|
||||||
|
0x90, 0xf6, 0x7c, 0xbf, 0x20, 0xeb, 0x43, 0xa1,
|
||||||
|
0x88, 0x00, 0xf4, 0xff, 0x0a, 0xfd, 0x82, 0xff,
|
||||||
|
0x10, 0x12 ],
|
||||||
|
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x07, 0x19, 0x2b, 0x95, 0xff, 0xc8,
|
||||||
|
0xda, 0x78, 0x63, 0x10, 0x11, 0xed, 0x6b, 0x24,
|
||||||
|
0xcd, 0xd5, 0x73, 0xf9, 0x77, 0xa1, 0x1e, 0x79,
|
||||||
|
0x48, 0x11 ]
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const NIST_P224: EllipticCurve = EllipticCurve {
|
||||||
|
name: "secp224r1",
|
||||||
|
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x01],
|
||||||
|
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, 0xe0, 0xb8,
|
||||||
|
0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, 0x5c, 0x5c,
|
||||||
|
0x2a, 0x3d],
|
||||||
|
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x71,
|
||||||
|
0x34, 0x47, 0x99, 0xd5, 0xc7, 0xfc, 0xdc, 0x45,
|
||||||
|
0xb5, 0x9f, 0xa3, 0xb9, 0xab, 0x8f, 0x6a, 0x94,
|
||||||
|
0x8b, 0xc5],
|
||||||
|
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x05,
|
||||||
|
0x6c, 0x7e, 0x11, 0xdd, 0x68, 0xf4, 0x04, 0x69,
|
||||||
|
0xee, 0x7f, 0x3c, 0x7a, 0x7d, 0x74, 0xf7, 0xd1,
|
||||||
|
0x21, 0x11, 0x65, 0x06, 0xd0, 0x31, 0x21, 0x82,
|
||||||
|
0x91, 0xfb],
|
||||||
|
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xfe],
|
||||||
|
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x05,
|
||||||
|
0x0a, 0x85, 0x0c, 0x04, 0xb3, 0xab, 0xf5, 0x41,
|
||||||
|
0x32, 0x56, 0x50, 0x44, 0xb0, 0xb7, 0xd7, 0xbf,
|
||||||
|
0xd8, 0xba, 0x27, 0x0b, 0x39, 0x43, 0x23, 0x55,
|
||||||
|
0xff, 0xb4],
|
||||||
|
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x0e,
|
||||||
|
0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, 0x32, 0x13,
|
||||||
|
0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3, 0x56, 0xc2,
|
||||||
|
0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, 0x11, 0x5c,
|
||||||
|
0x1d, 0x21],
|
||||||
|
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x37,
|
||||||
|
0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22,
|
||||||
|
0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07,
|
||||||
|
0x47, 0x64, 0x44, 0xd5, 0x81, 0x99, 0x85, 0x00,
|
||||||
|
0x7e, 0x34]
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const NIST_P256: EllipticCurve = EllipticCurve {
|
||||||
|
name: "secp256r1",
|
||||||
|
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||||
|
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff],
|
||||||
|
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17,
|
||||||
|
0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63,
|
||||||
|
0x25, 0x51],
|
||||||
|
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x9d,
|
||||||
|
0x36, 0x08, 0x86, 0xe7, 0x04, 0x93, 0x6a, 0x66,
|
||||||
|
0x78, 0xe1, 0x13, 0x9d, 0x26, 0xb7, 0x81, 0x9f,
|
||||||
|
0x7e, 0x90],
|
||||||
|
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x7e, 0xfb, 0xa1, 0x66, 0x29, 0x85,
|
||||||
|
0xbe, 0x94, 0x03, 0xcb, 0x05, 0x5c, 0x75, 0xd4,
|
||||||
|
0xf7, 0xe0, 0xce, 0x8d, 0x84, 0xa9, 0xc5, 0x11,
|
||||||
|
0x4a, 0xbc, 0xaf, 0x31, 0x77, 0x68, 0x01, 0x04,
|
||||||
|
0xfa, 0x0d],
|
||||||
|
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||||
|
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xfc],
|
||||||
|
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a,
|
||||||
|
0x93, 0xe7, 0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98,
|
||||||
|
0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
|
||||||
|
0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2,
|
||||||
|
0x60, 0x4b],
|
||||||
|
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c,
|
||||||
|
0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4,
|
||||||
|
0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb,
|
||||||
|
0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98,
|
||||||
|
0xc2, 0x96],
|
||||||
|
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a,
|
||||||
|
0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f,
|
||||||
|
0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31,
|
||||||
|
0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf,
|
||||||
|
0x51, 0xf5]
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const NIST_P384: EllipticCurve = EllipticCurve {
|
||||||
|
name: "secp384r1",
|
||||||
|
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||||
|
0xff, 0xff],
|
||||||
|
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37,
|
||||||
|
0x2d, 0xdf, 0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0,
|
||||||
|
0xa7, 0x7a, 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5,
|
||||||
|
0x29, 0x73],
|
||||||
|
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x35,
|
||||||
|
0x92, 0x6a, 0xa3, 0x19, 0xa2, 0x7a, 0x1d, 0x00,
|
||||||
|
0x89, 0x6a, 0x67, 0x73, 0xa4, 0x82, 0x7a, 0xcd,
|
||||||
|
0xac, 0x73],
|
||||||
|
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x79, 0xd1, 0xe6, 0x55, 0xf8, 0x68,
|
||||||
|
0xf0, 0x2f, 0xff, 0x48, 0xdc, 0xde, 0xe1, 0x41,
|
||||||
|
0x51, 0xdd, 0xb8, 0x06, 0x43, 0xc1, 0x40, 0x6d,
|
||||||
|
0x0c, 0xa1, 0x0d, 0xfe, 0x6f, 0xc5, 0x20, 0x09,
|
||||||
|
0x54, 0x0a, 0x49, 0x5e, 0x80, 0x42, 0xea, 0x5f,
|
||||||
|
0x74, 0x4f, 0x6e, 0x18, 0x46, 0x67, 0xcc, 0x72,
|
||||||
|
0x24, 0x83],
|
||||||
|
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||||
|
0xff, 0xfc],
|
||||||
|
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xb3, 0x31, 0x2f, 0xa7, 0xe2, 0x3e,
|
||||||
|
0xe7, 0xe4, 0x98, 0x8e, 0x05, 0x6b, 0xe3, 0xf8,
|
||||||
|
0x2d, 0x19, 0x18, 0x1d, 0x9c, 0x6e, 0xfe, 0x81,
|
||||||
|
0x41, 0x12, 0x03, 0x14, 0x08, 0x8f, 0x50, 0x13,
|
||||||
|
0x87, 0x5a, 0xc6, 0x56, 0x39, 0x8d, 0x8a, 0x2e,
|
||||||
|
0xd1, 0x9d, 0x2a, 0x85, 0xc8, 0xed, 0xd3, 0xec,
|
||||||
|
0x2a, 0xef],
|
||||||
|
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b,
|
||||||
|
0x05, 0x37, 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20,
|
||||||
|
0xad, 0x74, 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7,
|
||||||
|
0x9b, 0x98, 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54,
|
||||||
|
0x2a, 0x38, 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55,
|
||||||
|
0x29, 0x6c, 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76,
|
||||||
|
0x0a, 0xb7],
|
||||||
|
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26,
|
||||||
|
0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92,
|
||||||
|
0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a,
|
||||||
|
0x14, 0x7c, 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0,
|
||||||
|
0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e,
|
||||||
|
0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea,
|
||||||
|
0x0e, 0x5f]
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const NIST_P521: EllipticCurve = EllipticCurve {
|
||||||
|
name: "secp521r1",
|
||||||
|
p: [ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff ],
|
||||||
|
n: [ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xfa, 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f,
|
||||||
|
0x96, 0x6b, 0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09,
|
||||||
|
0xa5, 0xd0, 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c,
|
||||||
|
0x47, 0xae, 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38,
|
||||||
|
0x64, 0x09 ],
|
||||||
|
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x9e,
|
||||||
|
0x88, 0x00, 0x29, 0x1c, 0xb8, 0x53, 0x96, 0xcc,
|
||||||
|
0x67, 0x17, 0x39, 0x32, 0x84, 0xaa, 0xa0, 0xda,
|
||||||
|
0x64, 0xba ],
|
||||||
|
c: [ 0x00, 0xb4, 0x8b, 0xfa, 0x5f, 0x42, 0x0a, 0x34,
|
||||||
|
0x94, 0x95, 0x39, 0xd2, 0xbd, 0xfc, 0x26, 0x4e,
|
||||||
|
0xee, 0xeb, 0x07, 0x76, 0x88, 0xe4, 0x4f, 0xbf,
|
||||||
|
0x0a, 0xd8, 0xf6, 0xd0, 0xed, 0xb3, 0x7b, 0xd6,
|
||||||
|
0xb5, 0x33, 0x28, 0x10, 0x00, 0x51, 0x8e, 0x19,
|
||||||
|
0xf1, 0xb9, 0xff, 0xbe, 0x0f, 0xe9, 0xed, 0x8a,
|
||||||
|
0x3c, 0x22, 0x00, 0xb8, 0xf8, 0x75, 0xe5, 0x23,
|
||||||
|
0x86, 0x8c, 0x70, 0xc1, 0xe5, 0xbf, 0x55, 0xba,
|
||||||
|
0xd6, 0x37 ],
|
||||||
|
a: [ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xfc ],
|
||||||
|
b: [ 0x00, 0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c,
|
||||||
|
0x9a, 0x1f, 0x92, 0x9a, 0x21, 0xa0, 0xb6, 0x85,
|
||||||
|
0x40, 0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3,
|
||||||
|
0x15, 0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1,
|
||||||
|
0x09, 0xe1, 0x56, 0x19, 0x39, 0x51, 0xec, 0x7e,
|
||||||
|
0x93, 0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1,
|
||||||
|
0xbf, 0x07, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c,
|
||||||
|
0x34, 0xf1, 0xef, 0x45, 0x1f, 0xd4, 0x6b, 0x50,
|
||||||
|
0x3f, 0x00 ],
|
||||||
|
gx: [ 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04,
|
||||||
|
0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95,
|
||||||
|
0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f,
|
||||||
|
0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d,
|
||||||
|
0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7,
|
||||||
|
0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff,
|
||||||
|
0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a,
|
||||||
|
0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5,
|
||||||
|
0xbd, 0x66 ],
|
||||||
|
gy: [ 0x00, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b,
|
||||||
|
0xc0, 0x04, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d,
|
||||||
|
0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b,
|
||||||
|
0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e,
|
||||||
|
0x66, 0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4,
|
||||||
|
0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad,
|
||||||
|
0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72,
|
||||||
|
0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1,
|
||||||
|
0x66, 0x50 ]
|
||||||
|
};
|
||||||
187
src/ecdsa/gold_tests.rs
Normal file
187
src/ecdsa/gold_tests.rs
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
use cryptonum::{SCN,UCN};
|
||||||
|
//use dsa::rfc6979::*;
|
||||||
|
use ecdsa::curves::*;
|
||||||
|
use ecdsa::point::ECPoint;
|
||||||
|
//use ecdsa::private::ECDSAPrivate;
|
||||||
|
//use ecdsa::public::ECDSAPublic;
|
||||||
|
//use sha1::Sha1;
|
||||||
|
//use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||||
|
use testing::run_test;
|
||||||
|
|
||||||
|
fn get_curve(cbytes: &[u8]) -> &'static EllipticCurve {
|
||||||
|
match usize::from(UCN::from_bytes(cbytes)) {
|
||||||
|
0x192 => &NIST_P192,
|
||||||
|
0x224 => &NIST_P224,
|
||||||
|
0x256 => &NIST_P256,
|
||||||
|
0x384 => &NIST_P384,
|
||||||
|
0x521 => &NIST_P521,
|
||||||
|
x => panic!("Unacceptable curve identifier {}", x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn point_negate()
|
||||||
|
{
|
||||||
|
run_test("tests/ecdsa/ec_negate.test", 5, |case| {
|
||||||
|
let (neg0, abytes) = case.get("a").unwrap();
|
||||||
|
let (neg1, bbytes) = case.get("b").unwrap();
|
||||||
|
let (neg2, cbytes) = case.get("c").unwrap();
|
||||||
|
let (neg3, xbytes) = case.get("x").unwrap();
|
||||||
|
let (neg4, ybytes) = case.get("y").unwrap();
|
||||||
|
|
||||||
|
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4);
|
||||||
|
let curve = get_curve(&cbytes);
|
||||||
|
let x = SCN::from(UCN::from_bytes(xbytes));
|
||||||
|
let y = SCN::from(UCN::from_bytes(ybytes));
|
||||||
|
let orig = ECPoint::new(curve, x, y);
|
||||||
|
let a = SCN::from(UCN::from_bytes(abytes));
|
||||||
|
let b = SCN::from(UCN::from_bytes(bbytes));
|
||||||
|
let inverted = ECPoint::new(curve, a, b);
|
||||||
|
assert_eq!(inverted, orig.negate());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn point_double()
|
||||||
|
{
|
||||||
|
run_test("tests/ecdsa/ec_dble.test", 5, |case| {
|
||||||
|
println!("START");
|
||||||
|
let (neg0, abytes) = case.get("a").unwrap();
|
||||||
|
let (neg1, bbytes) = case.get("b").unwrap();
|
||||||
|
let (neg2, cbytes) = case.get("c").unwrap();
|
||||||
|
let (neg3, xbytes) = case.get("x").unwrap();
|
||||||
|
let (neg4, ybytes) = case.get("y").unwrap();
|
||||||
|
|
||||||
|
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4);
|
||||||
|
println!("SEC1");
|
||||||
|
let curve = get_curve(&cbytes);
|
||||||
|
println!("SEC2");
|
||||||
|
let x = SCN::from(UCN::from_bytes(xbytes));
|
||||||
|
let y = SCN::from(UCN::from_bytes(ybytes));
|
||||||
|
let orig = ECPoint::new(curve, x, y);
|
||||||
|
println!("SEC3");
|
||||||
|
let a = SCN::from(UCN::from_bytes(abytes));
|
||||||
|
let b = SCN::from(UCN::from_bytes(bbytes));
|
||||||
|
let doubled = ECPoint::new(curve, a, b);
|
||||||
|
println!("SEC4");
|
||||||
|
assert_eq!(doubled, orig.double());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn point_add()
|
||||||
|
{
|
||||||
|
run_test("tests/ecdsa/ec_add.test", 7, |case| {
|
||||||
|
let (neg0, abytes) = case.get("a").unwrap();
|
||||||
|
let (neg1, bbytes) = case.get("b").unwrap();
|
||||||
|
let (neg2, qbytes) = case.get("q").unwrap();
|
||||||
|
let (neg3, rbytes) = case.get("r").unwrap();
|
||||||
|
let (neg4, cbytes) = case.get("c").unwrap();
|
||||||
|
let (neg5, xbytes) = case.get("x").unwrap();
|
||||||
|
let (neg6, ybytes) = case.get("y").unwrap();
|
||||||
|
|
||||||
|
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5 && !neg6);
|
||||||
|
let curve = get_curve(&cbytes);
|
||||||
|
let x = SCN::from(UCN::from_bytes(xbytes));
|
||||||
|
let y = SCN::from(UCN::from_bytes(ybytes));
|
||||||
|
let p1 = ECPoint::new(curve, x, y);
|
||||||
|
let q = SCN::from(UCN::from_bytes(qbytes));
|
||||||
|
let r = SCN::from(UCN::from_bytes(rbytes));
|
||||||
|
let p2 = ECPoint::new(curve, q, r);
|
||||||
|
let a = SCN::from(UCN::from_bytes(abytes));
|
||||||
|
let b = SCN::from(UCN::from_bytes(bbytes));
|
||||||
|
let result = ECPoint::new(curve, a, b);
|
||||||
|
assert_eq!(result, p1.add(&p2));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn point_scale()
|
||||||
|
{
|
||||||
|
run_test("tests/ecdsa/ec_mul.test", 6, |case| {
|
||||||
|
let (neg0, abytes) = case.get("a").unwrap();
|
||||||
|
let (neg1, bbytes) = case.get("b").unwrap();
|
||||||
|
let (neg2, kbytes) = case.get("k").unwrap();
|
||||||
|
let (neg3, cbytes) = case.get("c").unwrap();
|
||||||
|
let (neg4, xbytes) = case.get("x").unwrap();
|
||||||
|
let (neg5, ybytes) = case.get("y").unwrap();
|
||||||
|
|
||||||
|
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5);
|
||||||
|
let curve = get_curve(&cbytes);
|
||||||
|
let x = SCN::from(UCN::from_bytes(xbytes));
|
||||||
|
let y = SCN::from(UCN::from_bytes(ybytes));
|
||||||
|
let base = ECPoint::new(curve, x, y);
|
||||||
|
let k = UCN::from_bytes(kbytes);
|
||||||
|
let a = SCN::from(UCN::from_bytes(abytes));
|
||||||
|
let b = SCN::from(UCN::from_bytes(bbytes));
|
||||||
|
let result = ECPoint::new(curve, a, b);
|
||||||
|
assert_eq!(result, base.scale(&k));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//#[test]
|
||||||
|
//fn verification_tests()
|
||||||
|
//{
|
||||||
|
// run_test("tests/ecdsa/signature.test", 8, |case| {
|
||||||
|
// let (neg0, cbytes) = case.get("c").unwrap();
|
||||||
|
// let (negx, xbytes) = case.get("x").unwrap();
|
||||||
|
// let (negy, ybytes) = case.get("y").unwrap();
|
||||||
|
// let (neg1, hbytes) = case.get("h").unwrap();
|
||||||
|
// let (neg2, msg) = case.get("m").unwrap();
|
||||||
|
// let (neg3, rbytes) = case.get("r").unwrap();
|
||||||
|
// let (neg4, sbytes) = case.get("s").unwrap();
|
||||||
|
//
|
||||||
|
// assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4);
|
||||||
|
// let curve = get_curve(cbytes);
|
||||||
|
// let ux = UCN::from_bytes(xbytes);
|
||||||
|
// let uy = UCN::from_bytes(ybytes);
|
||||||
|
// let x = SCN{ negative: *negx, value: ux };
|
||||||
|
// let y = SCN{ negative: *negy, value: uy };
|
||||||
|
// let point = ECCPoint::new(&curve, x, y);
|
||||||
|
// let public = ECDSAPublic::new(&curve, &point);
|
||||||
|
// let r = UCN::from_bytes(rbytes);
|
||||||
|
// let s = UCN::from_bytes(sbytes);
|
||||||
|
// println!("r: {:X}", r);
|
||||||
|
// let sig = DSASignature{ r: r, s: s };
|
||||||
|
//
|
||||||
|
// match usize::from(UCN::from_bytes(hbytes)) {
|
||||||
|
// 0x1 => assert!(public.verify::<Sha1>(msg, &sig)),
|
||||||
|
// 0x224 => assert!(public.verify::<Sha224>(msg, &sig)),
|
||||||
|
// 0x256 => assert!(public.verify::<Sha256>(msg, &sig)),
|
||||||
|
// 0x384 => assert!(public.verify::<Sha384>(msg, &sig)),
|
||||||
|
// 0x512 => assert!(public.verify::<Sha512>(msg, &sig)),
|
||||||
|
// v => panic!("Bad hash size {}!", v)
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//#[test]
|
||||||
|
//fn signing_tests()
|
||||||
|
//{
|
||||||
|
// run_test("tests/ecdsa/signature.test", 8, |case| {
|
||||||
|
// let (neg0, cbytes) = case.get("c").unwrap();
|
||||||
|
// let (neg1, dbytes) = case.get("d").unwrap();
|
||||||
|
// let (neg2, hbytes) = case.get("h").unwrap();
|
||||||
|
// let (neg3, msg) = case.get("m").unwrap();
|
||||||
|
// let (neg4, rbytes) = case.get("r").unwrap();
|
||||||
|
// let (neg5, sbytes) = case.get("s").unwrap();
|
||||||
|
//
|
||||||
|
// assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4 & !neg5);
|
||||||
|
// let curve = get_curve(cbytes);
|
||||||
|
// let d = UCN::from_bytes(dbytes);
|
||||||
|
// let private = ECDSAPrivate::new(&curve, &d);
|
||||||
|
// let r = UCN::from_bytes(rbytes);
|
||||||
|
// let s = UCN::from_bytes(sbytes);
|
||||||
|
// let sig = DSASignature{ r: r, s: s };
|
||||||
|
//
|
||||||
|
// match usize::from(UCN::from_bytes(hbytes)) {
|
||||||
|
// 0x1 => assert_eq!(sig, private.sign::<Sha1>(msg)),
|
||||||
|
// 0x224 => assert_eq!(sig, private.sign::<Sha224>(msg)),
|
||||||
|
// 0x256 => assert_eq!(sig, private.sign::<Sha256>(msg)),
|
||||||
|
// 0x384 => assert_eq!(sig, private.sign::<Sha384>(msg)),
|
||||||
|
// 0x512 => assert_eq!(sig, private.sign::<Sha512>(msg)),
|
||||||
|
// v => panic!("Bad hash size {}!", v)
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
//}
|
||||||
61
src/ecdsa/mod.rs
Normal file
61
src/ecdsa/mod.rs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
mod curves;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod gold_tests;
|
||||||
|
mod point;
|
||||||
|
//mod private;
|
||||||
|
//mod public;
|
||||||
|
//
|
||||||
|
//pub use self::private::ECDSAPrivate;
|
||||||
|
//pub use self::public::ECDSAPublic;
|
||||||
|
pub use self::curves::{NIST_P192,NIST_P224,NIST_P256,NIST_P384,NIST_P521};
|
||||||
|
//
|
||||||
|
//use cryptonum::UCN;
|
||||||
|
//use rand::{Rng,OsRng};
|
||||||
|
//use self::curves::EllipticCurve;
|
||||||
|
//use self::math::ECCPoint;
|
||||||
|
//
|
||||||
|
//#[derive(Clone,Debug,PartialEq)]
|
||||||
|
//pub struct ECDSAKeyPair {
|
||||||
|
// pub private: ECDSAPrivate,
|
||||||
|
// pub public: ECDSAPublic
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//impl ECDSAKeyPair {
|
||||||
|
// pub fn generate(params: &'static EllipticCurve)
|
||||||
|
// -> ECDSAKeyPair
|
||||||
|
// {
|
||||||
|
// let mut rng = OsRng::new().unwrap();
|
||||||
|
// ECDSAKeyPair::generate_w_rng(&mut rng, params)
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn generate_w_rng<G: Rng>(rng: &mut G, params: &'static EllipticCurve)
|
||||||
|
// -> ECDSAKeyPair
|
||||||
|
// {
|
||||||
|
// let one = UCN::from(1u64);
|
||||||
|
// #[allow(non_snake_case)]
|
||||||
|
// let N = params.n.bits();
|
||||||
|
// let bits_to_generate = N + 64;
|
||||||
|
// let bytes_to_generate = (bits_to_generate + 7) / 8;
|
||||||
|
// let bits: Vec<u8> = rng.gen_iter().take(bytes_to_generate).collect();
|
||||||
|
// let bits_generated = bytes_to_generate * 8;
|
||||||
|
// let mut c = UCN::from_bytes(&bits);
|
||||||
|
// c >>= bits_generated - bits_to_generate;
|
||||||
|
// let nm1 = ¶ms.n - &one;
|
||||||
|
// let d = (c % &nm1) + &one;
|
||||||
|
// #[allow(non_snake_case)]
|
||||||
|
// let Q = ECCPoint::default(params).scale(&d);
|
||||||
|
// ECDSAKeyPair {
|
||||||
|
// private: ECDSAPrivate {
|
||||||
|
// curve: params,
|
||||||
|
// d: d
|
||||||
|
// },
|
||||||
|
// public: ECDSAPublic {
|
||||||
|
// curve: params,
|
||||||
|
// Q: Q
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
227
src/ecdsa/point.rs
Normal file
227
src/ecdsa/point.rs
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
use cryptonum::{SCN,UCN};
|
||||||
|
use ecdsa::curves::EllipticCurve;
|
||||||
|
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct ECPoint {
|
||||||
|
pub curve: &'static EllipticCurve,
|
||||||
|
pub value: ECPointValue
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub enum ECPointValue {
|
||||||
|
Infinity,
|
||||||
|
Point(SCN, SCN)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ECPoint {
|
||||||
|
pub fn new(ec: &'static EllipticCurve, x: SCN, y: SCN) -> ECPoint {
|
||||||
|
ECPoint {
|
||||||
|
curve: ec,
|
||||||
|
value: ECPointValue::Point(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn zero(ec: &'static EllipticCurve) -> ECPoint {
|
||||||
|
ECPoint { curve: ec, value: ECPointValue::Infinity }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn negate(&self) -> ECPoint {
|
||||||
|
match self.value {
|
||||||
|
ECPointValue::Infinity =>
|
||||||
|
self.clone(),
|
||||||
|
ECPointValue::Point(ref x, ref y) => {
|
||||||
|
let newy = SCN::from(self.curve.get_p()) - y;
|
||||||
|
let newv = ECPointValue::Point(x.clone(), newy);
|
||||||
|
ECPoint{ curve: self.curve, value: newv }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_x(&self) -> SCN {
|
||||||
|
match self.value {
|
||||||
|
ECPointValue::Infinity =>
|
||||||
|
SCN::zero(),
|
||||||
|
ECPointValue::Point(ref x, _) =>
|
||||||
|
x.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_y(&self) -> SCN {
|
||||||
|
match self.value {
|
||||||
|
ECPointValue::Infinity =>
|
||||||
|
SCN::zero(),
|
||||||
|
ECPointValue::Point(_, ref y) =>
|
||||||
|
y.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn double(&self) -> ECPoint {
|
||||||
|
match self.value {
|
||||||
|
ECPointValue::Infinity =>
|
||||||
|
self.clone(),
|
||||||
|
ECPointValue::Point(ref x, ref y) => {
|
||||||
|
let ua = SCN::from(self.curve.get_a());
|
||||||
|
let up = SCN::from(self.curve.get_p());
|
||||||
|
// lambda = (3 * xp ^ 2 + a) / 2 yp
|
||||||
|
let mut lambda = x * x;
|
||||||
|
lambda *= SCN::from(3);
|
||||||
|
lambda += &ua;
|
||||||
|
let twoy = y << 1;
|
||||||
|
lambda = lambda.divmod(&twoy, &self.curve.get_pu());
|
||||||
|
// xr = lambda ^ 2 - 2 xp
|
||||||
|
let mut xr = &lambda * λ
|
||||||
|
let xr_right = x << 1;
|
||||||
|
xr -= xr_right;
|
||||||
|
assert!(!xr.is_negative());
|
||||||
|
xr %= &up;
|
||||||
|
// yr = lambda (xp - xr) - yp
|
||||||
|
let xdiff = x - &xr;
|
||||||
|
let mut yr = &lambda * &xdiff;
|
||||||
|
yr -= y;
|
||||||
|
assert!(!yr.is_negative());
|
||||||
|
yr %= up;
|
||||||
|
//
|
||||||
|
ECPoint {
|
||||||
|
curve: self.curve,
|
||||||
|
value: ECPointValue::Point(xr, yr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(&self, other: &ECPoint) -> ECPoint {
|
||||||
|
assert_eq!(self.curve, other.curve);
|
||||||
|
match (&self.value, &other.value) {
|
||||||
|
(ECPointValue::Infinity, ECPointValue::Infinity) =>
|
||||||
|
self.clone(),
|
||||||
|
(ECPointValue::Infinity, _) =>
|
||||||
|
other.clone(),
|
||||||
|
(_, ECPointValue::Infinity) =>
|
||||||
|
self.clone(),
|
||||||
|
(ECPointValue::Point(ref sx, ref sy),
|
||||||
|
ECPointValue::Point(ref ox, ref oy)) => {
|
||||||
|
let xdiff = sx - ox;
|
||||||
|
let ydiff = sy - oy;
|
||||||
|
let pu = self.curve.get_pu();
|
||||||
|
let s = ydiff.divmod(&xdiff, &pu);
|
||||||
|
let mut xr = &s * &s;
|
||||||
|
xr -= sx;
|
||||||
|
xr -= ox;
|
||||||
|
xr = xr.reduce(&pu);
|
||||||
|
let mut yr = sx - &xr;
|
||||||
|
yr *= &s;
|
||||||
|
yr -= sy;
|
||||||
|
yr = yr.reduce(&pu);
|
||||||
|
let val = ECPointValue::Point(xr, yr);
|
||||||
|
ECPoint{ curve: self.curve, value: val }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale(&self, d: &UCN) -> ECPoint {
|
||||||
|
match self.value {
|
||||||
|
ECPointValue::Infinity =>
|
||||||
|
self.clone(),
|
||||||
|
ECPointValue::Point(_, _) => {
|
||||||
|
if d.is_zero() {
|
||||||
|
return ECPoint::zero(self.curve);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut q = self.clone();
|
||||||
|
let i = d.bits() - 2;
|
||||||
|
let mut mask = UCN::from(1u64) << i;
|
||||||
|
|
||||||
|
while !mask.is_zero() {
|
||||||
|
q = q.double();
|
||||||
|
|
||||||
|
let test = d & &mask;
|
||||||
|
if !test.is_zero() {
|
||||||
|
q = q.add(&self);
|
||||||
|
}
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
q
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// pub fn bits2int(x: &[u8], qlen: usize) -> UCN {
|
||||||
|
// let mut value = UCN::from_bytes(x);
|
||||||
|
// let vlen = x.len() * 8;
|
||||||
|
//
|
||||||
|
// if vlen > qlen {
|
||||||
|
// value >>= vlen - qlen;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// value
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn point_add_two_muls(k1: &UCN, p1: &ECCPoint, k2: &UCN, p2: &ECCPoint)
|
||||||
|
// -> ECCPoint
|
||||||
|
// {
|
||||||
|
// panic!("point_add_two_muls()")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// #[cfg(test)]
|
||||||
|
// mod tests {
|
||||||
|
// use super::*;
|
||||||
|
//
|
||||||
|
// #[test]
|
||||||
|
// fn p256_double() {
|
||||||
|
// let xbytes = vec![0x7c, 0xf2, 0x7b, 0x18, 0x8d, 0x03, 0x4f, 0x7e,
|
||||||
|
// 0x8a, 0x52, 0x38, 0x03, 0x04, 0xb5, 0x1a, 0xc3,
|
||||||
|
// 0xc0, 0x89, 0x69, 0xe2, 0x77, 0xf2, 0x1b, 0x35,
|
||||||
|
// 0xa6, 0x0b, 0x48, 0xfc, 0x47, 0x66, 0x99, 0x78];
|
||||||
|
// let ybytes = vec![0x07, 0x77, 0x55, 0x10, 0xdb, 0x8e, 0xd0, 0x40,
|
||||||
|
// 0x29, 0x3d, 0x9a, 0xc6, 0x9f, 0x74, 0x30, 0xdb,
|
||||||
|
// 0xba, 0x7d, 0xad, 0xe6, 0x3c, 0xe9, 0x82, 0x29,
|
||||||
|
// 0x9e, 0x04, 0xb7, 0x9d, 0x22, 0x78, 0x73, 0xd1];
|
||||||
|
// let x = SCN::from(UCN::from_bytes(&xbytes));
|
||||||
|
// let y = SCN::from(UCN::from_bytes(&ybytes));
|
||||||
|
// let base = ECCPoint::default(&EllipticCurve::p256());
|
||||||
|
// let res = base.double();
|
||||||
|
// let goal = ECCPoint{ curve: base.curve,
|
||||||
|
// value: ECCPointValue::Point(x,y) };
|
||||||
|
// assert_eq!(res, goal);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// #[test]
|
||||||
|
// fn p256_add() {
|
||||||
|
// let xbytes = vec![0x5e, 0xcb, 0xe4, 0xd1, 0xa6, 0x33, 0x0a, 0x44,
|
||||||
|
// 0xc8, 0xf7, 0xef, 0x95, 0x1d, 0x4b, 0xf1, 0x65,
|
||||||
|
// 0xe6, 0xc6, 0xb7, 0x21, 0xef, 0xad, 0xa9, 0x85,
|
||||||
|
// 0xfb, 0x41, 0x66, 0x1b, 0xc6, 0xe7, 0xfd, 0x6c];
|
||||||
|
// let ybytes = vec![0x87, 0x34, 0x64, 0x0c, 0x49, 0x98, 0xff, 0x7e,
|
||||||
|
// 0x37, 0x4b, 0x06, 0xce, 0x1a, 0x64, 0xa2, 0xec,
|
||||||
|
// 0xd8, 0x2a, 0xb0, 0x36, 0x38, 0x4f, 0xb8, 0x3d,
|
||||||
|
// 0x9a, 0x79, 0xb1, 0x27, 0xa2, 0x7d, 0x50, 0x32];
|
||||||
|
// let x = SCN::from(UCN::from_bytes(&xbytes));
|
||||||
|
// let y = SCN::from(UCN::from_bytes(&ybytes));
|
||||||
|
// let base = ECCPoint::default(&EllipticCurve::p256());
|
||||||
|
// let res = base.add(&base.double());
|
||||||
|
// let goal = ECCPoint{ curve: base.curve,
|
||||||
|
// value: ECCPointValue::Point(x,y) };
|
||||||
|
// assert_eq!(res, goal);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// #[test]
|
||||||
|
// fn p256_scale() {
|
||||||
|
// let xbytes = vec![0xea, 0x68, 0xd7, 0xb6, 0xfe, 0xdf, 0x0b, 0x71,
|
||||||
|
// 0x87, 0x89, 0x38, 0xd5, 0x1d, 0x71, 0xf8, 0x72,
|
||||||
|
// 0x9e, 0x0a, 0xcb, 0x8c, 0x2c, 0x6d, 0xf8, 0xb3,
|
||||||
|
// 0xd7, 0x9e, 0x8a, 0x4b, 0x90, 0x94, 0x9e, 0xe0];
|
||||||
|
// let ybytes = vec![0x2a, 0x27, 0x44, 0xc9, 0x72, 0xc9, 0xfc, 0xe7,
|
||||||
|
// 0x87, 0x01, 0x4a, 0x96, 0x4a, 0x8e, 0xa0, 0xc8,
|
||||||
|
// 0x4d, 0x71, 0x4f, 0xea, 0xa4, 0xde, 0x82, 0x3f,
|
||||||
|
// 0xe8, 0x5a, 0x22, 0x4a, 0x4d, 0xd0, 0x48, 0xfa];
|
||||||
|
// let x = SCN::from(UCN::from_bytes(&xbytes));
|
||||||
|
// let y = SCN::from(UCN::from_bytes(&ybytes));
|
||||||
|
// let base = ECCPoint::default(&EllipticCurve::p256());
|
||||||
|
// let res = base.scale(&UCN::from(9 as u64));
|
||||||
|
// let goal = ECCPoint{ curve: base.curve,
|
||||||
|
// value: ECCPointValue::Point(x,y) };
|
||||||
|
// assert_eq!(res, goal);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
93
src/ecdsa/private.rs
Normal file
93
src/ecdsa/private.rs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
use cryptonum::{SCN,UCN};
|
||||||
|
use digest::{BlockInput,FixedOutput,Input};
|
||||||
|
use digest::generic_array::ArrayLength;
|
||||||
|
use dsa::rfc6979::{DSASignature,KIterator};
|
||||||
|
use ecdsa::curves::EllipticCurve;
|
||||||
|
use ecdsa::math::{ECCPoint,bits2int};
|
||||||
|
use hmac::Hmac;
|
||||||
|
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct ECDSAPrivate {
|
||||||
|
pub(crate) curve: &'static EllipticCurve,
|
||||||
|
pub(crate) d: UCN
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ECDSAPrivate {
|
||||||
|
pub fn new(c: &'static EllipticCurve, d: &UCN)
|
||||||
|
-> ECDSAPrivate
|
||||||
|
{
|
||||||
|
ECDSAPrivate {
|
||||||
|
curve: c,
|
||||||
|
d: d.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sign<Hash>(&self, m: &[u8]) -> DSASignature
|
||||||
|
where
|
||||||
|
Hash: Clone + BlockInput + Input + FixedOutput + Default,
|
||||||
|
Hmac<Hash>: Clone,
|
||||||
|
Hash::BlockSize: ArrayLength<u8>
|
||||||
|
{
|
||||||
|
// This algorithm is per RFC 6979, which has a nice, relatively
|
||||||
|
// straightforward description of how to do DSA signing.
|
||||||
|
//
|
||||||
|
// 1. H(m) is transformed into an integer modulo q using the bits2int
|
||||||
|
// transform and an extra modular reduction:
|
||||||
|
//
|
||||||
|
// h = bits2int(H(m)) mod q
|
||||||
|
//
|
||||||
|
// As was noted in the description of bits2octets, the extra
|
||||||
|
// modular reduction is no more than a conditional subtraction.
|
||||||
|
//
|
||||||
|
let mut digest = <Hash>::default();
|
||||||
|
digest.process(m);
|
||||||
|
let n = self.curve.p.bits();
|
||||||
|
let h1: Vec<u8> = digest.fixed_result()
|
||||||
|
.as_slice()
|
||||||
|
.iter()
|
||||||
|
.map(|x| *x)
|
||||||
|
.collect();
|
||||||
|
let h0 = bits2int(&h1, n);
|
||||||
|
let h = h0 % &self.curve.n;
|
||||||
|
|
||||||
|
// 2. A random value modulo q, dubbed k, is generated. That value
|
||||||
|
// shall not be 0; hence, it lies in the [1, q-1] range. Most
|
||||||
|
// of the remainder of this document will revolve around the
|
||||||
|
// process used to generate k. In plain DSA or ECDSA, k should
|
||||||
|
// be selected through a random selection that chooses a value
|
||||||
|
// among the q-1 possible values with uniform probability.
|
||||||
|
for k in KIterator::<Hash>::new(&h1, n, &self.curve.n, &self.curve.b) {
|
||||||
|
// 3. A value r (modulo q) is computed from k and the key
|
||||||
|
// parameters:
|
||||||
|
// * For DSA ...
|
||||||
|
// * For ECDSA: the point kG is computed; its X coordinate (a
|
||||||
|
// member of the field over which E is defined) is converted
|
||||||
|
// to an integer, which is reduced modulo q, yielding r.
|
||||||
|
//
|
||||||
|
// If r turns out to be zero, a new k should be selected and r
|
||||||
|
// computed again (this is an utterly improbable occurrence).
|
||||||
|
let g = ECCPoint::default(self.curve);
|
||||||
|
let kg = g.scale(&k);
|
||||||
|
let ni = SCN::from(self.curve.n.clone());
|
||||||
|
let r = &kg.get_x() % ∋
|
||||||
|
if r.is_zero() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 4. The value s (modulo q) is computed:
|
||||||
|
//
|
||||||
|
// s = (h+x*r)/k mod q
|
||||||
|
//
|
||||||
|
// The pair (r, s) is the signature.
|
||||||
|
let kinv = SCN::from(k.modinv(&ni.value));
|
||||||
|
let s = ((SCN::from(h.clone()) + (&kg.get_x() * &r)) * &kinv) % ∋
|
||||||
|
if s.is_zero() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(!r.is_negative());
|
||||||
|
assert!(!s.is_negative());
|
||||||
|
return DSASignature{ r: r.value, s: s.value };
|
||||||
|
}
|
||||||
|
panic!("The world is broken; couldn't find a k in sign().");
|
||||||
|
}
|
||||||
|
}
|
||||||
62
src/ecdsa/public.rs
Normal file
62
src/ecdsa/public.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
use digest::{BlockInput,FixedOutput,Input};
|
||||||
|
use digest::generic_array::ArrayLength;
|
||||||
|
use dsa::rfc6979::DSASignature;
|
||||||
|
use ecdsa::curves::EllipticCurve;
|
||||||
|
use ecdsa::math::{ECCPoint,bits2int,point_add_two_muls};
|
||||||
|
use hmac::Hmac;
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct ECDSAPublic {
|
||||||
|
pub(crate) curve: &'static EllipticCurve,
|
||||||
|
pub(crate) Q: ECCPoint
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ECDSAPublic {
|
||||||
|
pub fn new(curve: &'static EllipticCurve, point: &ECCPoint)
|
||||||
|
-> ECDSAPublic
|
||||||
|
{
|
||||||
|
ECDSAPublic {
|
||||||
|
curve: curve,
|
||||||
|
Q: point.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify<Hash>(&self, m: &[u8], sig: &DSASignature) -> bool
|
||||||
|
where
|
||||||
|
Hash: Clone + BlockInput + Input + FixedOutput + Default,
|
||||||
|
Hmac<Hash>: Clone,
|
||||||
|
Hash::BlockSize: ArrayLength<u8>
|
||||||
|
{
|
||||||
|
let n = &self.curve.n;
|
||||||
|
|
||||||
|
if &sig.r > n {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if &sig.s > n {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let c = sig.s.modinv(&n);
|
||||||
|
|
||||||
|
let mut digest = <Hash>::default();
|
||||||
|
digest.process(m);
|
||||||
|
let h1: Vec<u8> = digest.fixed_result()
|
||||||
|
.as_slice()
|
||||||
|
.iter()
|
||||||
|
.map(|x| *x)
|
||||||
|
.collect();
|
||||||
|
let h0 = bits2int(&h1, self.curve.p.bits()) % n;
|
||||||
|
let u1 = (&h0 * &c) % n;
|
||||||
|
let u2 = (&sig.r * &c) % n;
|
||||||
|
let x = point_add_two_muls(&u1, &ECCPoint::default(&self.curve),
|
||||||
|
&u2, &self.Q);
|
||||||
|
let xx = x.get_x();
|
||||||
|
|
||||||
|
if xx.is_negative() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
(xx.value % n) == sig.r
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/lib.rs
32
src/lib.rs
@@ -1,4 +1,3 @@
|
|||||||
#![feature(i128_type)]
|
|
||||||
//! # Simple Crypto: A quaint little crypto library for rust.
|
//! # Simple Crypto: A quaint little crypto library for rust.
|
||||||
//!
|
//!
|
||||||
//! This is the simple_crypto library. Its goal is to provide straightforward
|
//! This is the simple_crypto library. Its goal is to provide straightforward
|
||||||
@@ -11,20 +10,37 @@
|
|||||||
//! when they should use it, and examples. For now, it mostly just fowards
|
//! when they should use it, and examples. For now, it mostly just fowards
|
||||||
//! off to more detailed modules. Help requested!
|
//! off to more detailed modules. Help requested!
|
||||||
|
|
||||||
|
extern crate digest;
|
||||||
|
extern crate hmac;
|
||||||
|
extern crate num;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate quickcheck;
|
extern crate quickcheck;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
extern crate sha1;
|
||||||
|
extern crate sha2;
|
||||||
|
extern crate simple_asn1;
|
||||||
|
|
||||||
/// The cryptonum module provides support for large numbers at fixed,
|
/// The `cryptonum` module provides support for large numbers for use in various
|
||||||
/// cryptographically-relevant sizes.
|
/// cryptographically-relevant algorithms.
|
||||||
pub mod cryptonum;
|
pub mod cryptonum;
|
||||||
|
/// The `rsa` module provides support for RSA-related core algorithms, including
|
||||||
|
/// signing / verification and encryption / decryption. You can also generate
|
||||||
|
/// key material there.
|
||||||
|
pub mod rsa;
|
||||||
|
/// The `dsa` module provides support for DSA-related signing and verification
|
||||||
|
/// algorithms, as well as key generation. That being said: don't use this,
|
||||||
|
/// unless you've got a legacy application or system that you're trying to
|
||||||
|
/// interact with. DSA is almost always the wrong choice.
|
||||||
|
pub mod dsa;
|
||||||
|
/// The 'ecdsa' module provides support for ECDSA-related signing and
|
||||||
|
/// verification algorithms, as well as key generation. This and RSA should be
|
||||||
|
/// your go-to choice for asymmetric crypto.
|
||||||
|
pub mod ecdsa;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod testing;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn testing_works() {
|
|
||||||
assert!(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
163
src/rsa/core.rs
Normal file
163
src/rsa/core.rs
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
use cryptonum::{BarrettUCN,UCN};
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
pub static ACCEPTABLE_KEY_SIZES: [(usize,usize); 8] =
|
||||||
|
[(512, 7),
|
||||||
|
(1024, 7),
|
||||||
|
(2048, 4),
|
||||||
|
(3072, 3),
|
||||||
|
(4096, 3),
|
||||||
|
(7680, 3),
|
||||||
|
(8192, 3),
|
||||||
|
(15360, 3)];
|
||||||
|
|
||||||
|
fn iterations_for_size(l: usize) -> usize {
|
||||||
|
for &(m, i) in ACCEPTABLE_KEY_SIZES.iter() {
|
||||||
|
if m == l {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("Bad key size, can't get M-R iterations")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_pq<G: Rng>(rng: &mut G, e: &UCN, bitlen: usize) -> (UCN, UCN) {
|
||||||
|
let iterations = iterations_for_size(bitlen);
|
||||||
|
let sqrt2 = UCN::from(6074001000 as u64);
|
||||||
|
let topbit = UCN::from(1 as u64) << ((bitlen / 2) - 1);
|
||||||
|
let minval = sqrt2 << ((bitlen / 2) - 33);
|
||||||
|
let mindiff = UCN::from(1 as u64) << ((bitlen / 2) - 101);
|
||||||
|
let validate = |inval| {
|
||||||
|
let x = &inval | &topbit;
|
||||||
|
if x < minval {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
if !gcd_is_one(&e, &x) {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
Some(x)
|
||||||
|
};
|
||||||
|
|
||||||
|
let p = UCN::generate_prime(rng, bitlen / 2, iterations, validate);
|
||||||
|
loop {
|
||||||
|
let q = UCN::generate_prime(rng, bitlen / 2, iterations, validate);
|
||||||
|
|
||||||
|
if diff(&p, &q) >= mindiff {
|
||||||
|
return (p, q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn diff(a: &UCN, b: &UCN) -> UCN {
|
||||||
|
if a > b {
|
||||||
|
a - b
|
||||||
|
} else {
|
||||||
|
b - a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gcd_is_one(a: &UCN, b: &UCN) -> bool {
|
||||||
|
let mut u = a.clone();
|
||||||
|
let mut v = b.clone();
|
||||||
|
|
||||||
|
if u.is_zero() {
|
||||||
|
return v == UCN::from(1 as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.is_zero() {
|
||||||
|
return u == UCN::from(1 as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.is_even() && v.is_even() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while u.is_even() {
|
||||||
|
u >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
while v.is_even() {
|
||||||
|
v >>= 1;
|
||||||
|
}
|
||||||
|
// u and v guaranteed to be odd right now.
|
||||||
|
if u > v {
|
||||||
|
// make sure that v > u, so that our subtraction works
|
||||||
|
// out.
|
||||||
|
let t = u;
|
||||||
|
u = v;
|
||||||
|
v = t;
|
||||||
|
}
|
||||||
|
v = v - &u;
|
||||||
|
|
||||||
|
if v.is_zero() {
|
||||||
|
return u == UCN::from(1 as u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// the RSA encryption function
|
||||||
|
pub fn ep(nu: &BarrettUCN, e: &UCN, m: &UCN) -> UCN {
|
||||||
|
m.fastmodexp(e, nu)
|
||||||
|
}
|
||||||
|
|
||||||
|
// the RSA decryption function
|
||||||
|
pub fn dp(nu: &BarrettUCN, d: &UCN, c: &UCN) -> UCN {
|
||||||
|
c.fastmodexp(d, nu)
|
||||||
|
}
|
||||||
|
|
||||||
|
// the RSA signature generation function
|
||||||
|
pub fn sp1(nu: &BarrettUCN, d: &UCN, m: &UCN) -> UCN {
|
||||||
|
m.fastmodexp(d, nu)
|
||||||
|
}
|
||||||
|
|
||||||
|
// the RSA signature verification function
|
||||||
|
pub fn vp1(nu: &BarrettUCN, e: &UCN, s: &UCN) -> UCN {
|
||||||
|
s.fastmodexp(e, nu)
|
||||||
|
}
|
||||||
|
|
||||||
|
// encoding PKCS1 stuff
|
||||||
|
pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec<u8> {
|
||||||
|
let mut idhash = Vec::new();
|
||||||
|
idhash.extend_from_slice(ident);
|
||||||
|
idhash.extend_from_slice(hash);
|
||||||
|
let tlen = idhash.len();
|
||||||
|
assert!(keylen > (tlen + 3));
|
||||||
|
let mut padding = Vec::new();
|
||||||
|
padding.resize(keylen - tlen - 3, 0xFF);
|
||||||
|
let mut result = vec![0x00, 0x01];
|
||||||
|
result.append(&mut padding);
|
||||||
|
result.push(0x00);
|
||||||
|
result.append(&mut idhash);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn xor_vecs(a: &Vec<u8>, b: &Vec<u8>) -> Vec<u8> {
|
||||||
|
a.iter().zip(b.iter()).map(|(a,b)| a^b).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use rand::OsRng;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn can_get_p_and_q() {
|
||||||
|
let mut rng = OsRng::new().unwrap();
|
||||||
|
let e = UCN::from(65537 as u64);
|
||||||
|
|
||||||
|
for &(size, _) in ACCEPTABLE_KEY_SIZES.iter().take(3) {
|
||||||
|
let (p,q) = generate_pq(&mut rng, &e, size);
|
||||||
|
let minval = UCN::from(1 as u8) << ((size / 2) - 1);
|
||||||
|
assert!(p > minval);
|
||||||
|
assert!(q > minval);
|
||||||
|
assert!(p != q);
|
||||||
|
assert!(p.is_odd());
|
||||||
|
assert!(q.is_odd());
|
||||||
|
let phi = (p - UCN::from(1 as u64)) * (q - UCN::from(1 as u64));
|
||||||
|
let d = e.modinv(&phi);
|
||||||
|
assert_eq!( (&e * &d) % phi, UCN::from(1 as u64) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/rsa/errors.rs
Normal file
38
src/rsa/errors.rs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum RSAError {
|
||||||
|
BadMessageSize,
|
||||||
|
KeyTooSmallForHash,
|
||||||
|
DecryptionError,
|
||||||
|
DecryptHashMismatch,
|
||||||
|
InvalidKey,
|
||||||
|
RandomGenError(io::Error),
|
||||||
|
ASN1DecodeErr(ASN1DecodeErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for RSAError {
|
||||||
|
fn from(e: io::Error) -> RSAError {
|
||||||
|
RSAError::RandomGenError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ASN1DecodeErr> for RSAError {
|
||||||
|
fn from(e: ASN1DecodeErr) -> RSAError {
|
||||||
|
RSAError::ASN1DecodeErr(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
208
src/rsa/gold_tests.rs
Normal file
208
src/rsa/gold_tests.rs
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
use rsa::*;
|
||||||
|
use rsa::oaep::OAEPParams;
|
||||||
|
use sha1::Sha1;
|
||||||
|
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||||
|
use testing::run_test;
|
||||||
|
|
||||||
|
fn get_signing_hash(s: usize) -> &'static SigningHash {
|
||||||
|
match s {
|
||||||
|
0x1 => &SIGNING_HASH_SHA1,
|
||||||
|
0x224 => &SIGNING_HASH_SHA224,
|
||||||
|
0x256 => &SIGNING_HASH_SHA256,
|
||||||
|
0x384 => &SIGNING_HASH_SHA384,
|
||||||
|
0x512 => &SIGNING_HASH_SHA512,
|
||||||
|
_ => panic!("Unacceptable hash")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn rsa_signing_tests()
|
||||||
|
{
|
||||||
|
run_test("tests/rsa/signature.test", 7, |case| {
|
||||||
|
let (neg0, dbytes) = case.get("d").unwrap();
|
||||||
|
let (neg1, nbytes) = case.get("n").unwrap();
|
||||||
|
let (neg2, hbytes) = case.get("h").unwrap();
|
||||||
|
let (neg3, kbytes) = case.get("k").unwrap();
|
||||||
|
let (neg4, msg) = case.get("m").unwrap();
|
||||||
|
let (neg5, sig) = case.get("s").unwrap();
|
||||||
|
|
||||||
|
assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4 & !neg5);
|
||||||
|
let hash = get_signing_hash(usize::from(UCN::from_bytes(hbytes)));
|
||||||
|
let size = usize::from(UCN::from_bytes(kbytes));
|
||||||
|
let key = RSAPrivate::new(UCN::from_bytes(nbytes),
|
||||||
|
UCN::from_bytes(dbytes));
|
||||||
|
|
||||||
|
assert!(size % 8 == 0);
|
||||||
|
assert_eq!(key.byte_len * 8, size);
|
||||||
|
let sig2 = key.sign(hash, &msg);
|
||||||
|
assert_eq!(*sig, sig2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rsa_verification_tests()
|
||||||
|
{
|
||||||
|
run_test("tests/rsa/signature.test", 7, |case| {
|
||||||
|
let (neg1, nbytes) = case.get("n").unwrap();
|
||||||
|
let (neg2, hbytes) = case.get("h").unwrap();
|
||||||
|
let (neg3, kbytes) = case.get("k").unwrap();
|
||||||
|
let (neg4, msg) = case.get("m").unwrap();
|
||||||
|
let (neg5, sig) = case.get("s").unwrap();
|
||||||
|
|
||||||
|
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5);
|
||||||
|
let hash = get_signing_hash(usize::from(UCN::from_bytes(hbytes)));
|
||||||
|
let size = usize::from(UCN::from_bytes(kbytes));
|
||||||
|
let key = RSAPublic::new(UCN::from_bytes(nbytes),
|
||||||
|
UCN::from(65537u64));
|
||||||
|
|
||||||
|
assert_eq!(key.byte_len * 8, size);
|
||||||
|
assert!(key.verify(hash, &msg, sig));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rsa_decryption_tests()
|
||||||
|
{
|
||||||
|
run_test("tests/rsa/encryption.test", 6, |case| {
|
||||||
|
let (neg1, dbytes) = case.get("d").unwrap();
|
||||||
|
let (neg2, nbytes) = case.get("n").unwrap();
|
||||||
|
let (neg3, hbytes) = case.get("h").unwrap();
|
||||||
|
let (neg4, lbytes) = case.get("l").unwrap();
|
||||||
|
let (neg5, msg) = case.get("m").unwrap();
|
||||||
|
let (neg6, cphtxt) = case.get("c").unwrap();
|
||||||
|
|
||||||
|
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5 & !neg6);
|
||||||
|
let label = String::from_utf8(lbytes.clone()).unwrap();
|
||||||
|
let key = RSAPrivate::new(UCN::from_bytes(nbytes),
|
||||||
|
UCN::from_bytes(dbytes));
|
||||||
|
let wrapped = match usize::from(UCN::from_bytes(hbytes)) {
|
||||||
|
0x1 => key.decrypt(&OAEPParams::new(Sha1::default(), label),cphtxt),
|
||||||
|
0x224 => key.decrypt(&OAEPParams::new(Sha224::default(),label),cphtxt),
|
||||||
|
0x256 => key.decrypt(&OAEPParams::new(Sha256::default(),label),cphtxt),
|
||||||
|
0x384 => key.decrypt(&OAEPParams::new(Sha384::default(),label),cphtxt),
|
||||||
|
0x512 => key.decrypt(&OAEPParams::new(Sha512::default(),label),cphtxt),
|
||||||
|
_ => panic!("Unacceptable hash")
|
||||||
|
};
|
||||||
|
let mymsg = wrapped.unwrap();
|
||||||
|
assert_eq!(msg, &mymsg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn rsa_long_decryption_tests()
|
||||||
|
{
|
||||||
|
run_test("tests/rsa/encryption.ext.test", 6, |case| {
|
||||||
|
let (neg1, dbytes) = case.get("d").unwrap();
|
||||||
|
let (neg2, nbytes) = case.get("n").unwrap();
|
||||||
|
let (neg3, hbytes) = case.get("h").unwrap();
|
||||||
|
let (neg4, lbytes) = case.get("l").unwrap();
|
||||||
|
let (neg5, msg) = case.get("m").unwrap();
|
||||||
|
let (neg6, cphtxt) = case.get("c").unwrap();
|
||||||
|
|
||||||
|
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5 & !neg6);
|
||||||
|
let label = String::from_utf8(lbytes.clone()).unwrap();
|
||||||
|
let key = RSAPrivate::new(UCN::from_bytes(nbytes),
|
||||||
|
UCN::from_bytes(dbytes));
|
||||||
|
let wrapped = match usize::from(UCN::from_bytes(hbytes)) {
|
||||||
|
0x1 => key.decrypt(&OAEPParams::new(Sha1::default(), label),cphtxt),
|
||||||
|
0x224 => key.decrypt(&OAEPParams::new(Sha224::default(),label),cphtxt),
|
||||||
|
0x256 => key.decrypt(&OAEPParams::new(Sha256::default(),label),cphtxt),
|
||||||
|
0x384 => key.decrypt(&OAEPParams::new(Sha384::default(),label),cphtxt),
|
||||||
|
0x512 => key.decrypt(&OAEPParams::new(Sha512::default(),label),cphtxt),
|
||||||
|
_ => panic!("Unacceptable hash")
|
||||||
|
};
|
||||||
|
let mymsg = wrapped.unwrap();
|
||||||
|
assert_eq!(msg, &mymsg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rsa_encryption_tests()
|
||||||
|
{
|
||||||
|
run_test("tests/rsa/encryption.test", 6, |case| {
|
||||||
|
let (neg1, dbytes) = case.get("d").unwrap();
|
||||||
|
let (neg2, nbytes) = case.get("n").unwrap();
|
||||||
|
let (neg3, hbytes) = case.get("h").unwrap();
|
||||||
|
let (neg4, lbytes) = case.get("l").unwrap();
|
||||||
|
let (neg5, msg) = case.get("m").unwrap();
|
||||||
|
|
||||||
|
// This one's a little tricky, because there's randomness in the
|
||||||
|
// encryption phase. So we can't just encrypt and see if we get the
|
||||||
|
// same value. Instead, we just use this as a test vector to round
|
||||||
|
// trip, and trust that the decryption test above makes sure we're
|
||||||
|
// not going off into la la land.
|
||||||
|
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5);
|
||||||
|
let label = String::from_utf8(lbytes.clone()).unwrap();
|
||||||
|
let private = RSAPrivate::new(UCN::from_bytes(nbytes),
|
||||||
|
UCN::from_bytes(dbytes));
|
||||||
|
let public = RSAPublic::new(UCN::from_bytes(nbytes),
|
||||||
|
UCN::from(65537u64));
|
||||||
|
let wrappedc = match usize::from(UCN::from_bytes(hbytes)) {
|
||||||
|
0x1 => public.encrypt(&OAEPParams::new(Sha1::default(), label.clone()), &msg),
|
||||||
|
0x224 => public.encrypt(&OAEPParams::new(Sha224::default(),label.clone()), &msg),
|
||||||
|
0x256 => public.encrypt(&OAEPParams::new(Sha256::default(),label.clone()), &msg),
|
||||||
|
0x384 => public.encrypt(&OAEPParams::new(Sha384::default(),label.clone()), &msg),
|
||||||
|
0x512 => public.encrypt(&OAEPParams::new(Sha512::default(),label.clone()), &msg),
|
||||||
|
_ => panic!("Unacceptable hash")
|
||||||
|
};
|
||||||
|
let ciphertext = wrappedc.unwrap();
|
||||||
|
let wrappedm = match usize::from(UCN::from_bytes(hbytes)) {
|
||||||
|
0x1 => private.decrypt(&OAEPParams::new(Sha1::default(), label), &ciphertext),
|
||||||
|
0x224 => private.decrypt(&OAEPParams::new(Sha224::default(),label), &ciphertext),
|
||||||
|
0x256 => private.decrypt(&OAEPParams::new(Sha256::default(),label), &ciphertext),
|
||||||
|
0x384 => private.decrypt(&OAEPParams::new(Sha384::default(),label), &ciphertext),
|
||||||
|
0x512 => private.decrypt(&OAEPParams::new(Sha512::default(),label), &ciphertext),
|
||||||
|
_ => panic!("Unacceptable hash")
|
||||||
|
};
|
||||||
|
let message = wrappedm.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(msg, &message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn rsa_long_encryption_tests()
|
||||||
|
{
|
||||||
|
run_test("tests/rsa/encryption.ext.test", 6, |case| {
|
||||||
|
let (neg1, dbytes) = case.get("d").unwrap();
|
||||||
|
let (neg2, nbytes) = case.get("n").unwrap();
|
||||||
|
let (neg3, hbytes) = case.get("h").unwrap();
|
||||||
|
let (neg4, lbytes) = case.get("l").unwrap();
|
||||||
|
let (neg5, msg) = case.get("m").unwrap();
|
||||||
|
|
||||||
|
// This one's a little tricky, because there's randomness in the
|
||||||
|
// encryption phase. So we can't just encrypt and see if we get the
|
||||||
|
// same value. Instead, we just use this as a test vector to round
|
||||||
|
// trip, and trust that the decryption test above makes sure we're
|
||||||
|
// not going off into la la land.
|
||||||
|
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5);
|
||||||
|
let label = String::from_utf8(lbytes.clone()).unwrap();
|
||||||
|
let private = RSAPrivate::new(UCN::from_bytes(nbytes),
|
||||||
|
UCN::from_bytes(dbytes));
|
||||||
|
let public = RSAPublic::new(UCN::from_bytes(nbytes),
|
||||||
|
UCN::from(65537u64));
|
||||||
|
let wrappedc = match usize::from(UCN::from_bytes(hbytes)) {
|
||||||
|
0x1 => public.encrypt(&OAEPParams::new(Sha1::default(), label.clone()), &msg),
|
||||||
|
0x224 => public.encrypt(&OAEPParams::new(Sha224::default(),label.clone()), &msg),
|
||||||
|
0x256 => public.encrypt(&OAEPParams::new(Sha256::default(),label.clone()), &msg),
|
||||||
|
0x384 => public.encrypt(&OAEPParams::new(Sha384::default(),label.clone()), &msg),
|
||||||
|
0x512 => public.encrypt(&OAEPParams::new(Sha512::default(),label.clone()), &msg),
|
||||||
|
_ => panic!("Unacceptable hash")
|
||||||
|
};
|
||||||
|
let ciphertext = wrappedc.unwrap();
|
||||||
|
let wrappedm = match usize::from(UCN::from_bytes(hbytes)) {
|
||||||
|
0x1 => private.decrypt(&OAEPParams::new(Sha1::default(), label), &ciphertext),
|
||||||
|
0x224 => private.decrypt(&OAEPParams::new(Sha224::default(),label), &ciphertext),
|
||||||
|
0x256 => private.decrypt(&OAEPParams::new(Sha256::default(),label), &ciphertext),
|
||||||
|
0x384 => private.decrypt(&OAEPParams::new(Sha384::default(),label), &ciphertext),
|
||||||
|
0x512 => private.decrypt(&OAEPParams::new(Sha512::default(),label), &ciphertext),
|
||||||
|
_ => panic!("Unacceptable hash")
|
||||||
|
};
|
||||||
|
let message = wrappedm.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(msg, &message);
|
||||||
|
});
|
||||||
|
}
|
||||||
109
src/rsa/mod.rs
Normal file
109
src/rsa/mod.rs
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
mod core;
|
||||||
|
mod errors;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod gold_tests;
|
||||||
|
mod oaep;
|
||||||
|
mod public;
|
||||||
|
mod private;
|
||||||
|
mod signing_hashes;
|
||||||
|
|
||||||
|
pub use self::public::RSAPublic;
|
||||||
|
pub use self::private::RSAPrivate;
|
||||||
|
pub use self::signing_hashes::{SigningHash,
|
||||||
|
SIGNING_HASH_NULL, SIGNING_HASH_SHA1,
|
||||||
|
SIGNING_HASH_SHA224, SIGNING_HASH_SHA256,
|
||||||
|
SIGNING_HASH_SHA384, SIGNING_HASH_SHA512};
|
||||||
|
|
||||||
|
use cryptonum::UCN;
|
||||||
|
use rand::{OsRng,Rng};
|
||||||
|
use self::core::{ACCEPTABLE_KEY_SIZES,generate_pq};
|
||||||
|
use self::errors::*;
|
||||||
|
|
||||||
|
#[derive(Clone,Debug)]
|
||||||
|
pub struct RSAKeyPair {
|
||||||
|
pub public: RSAPublic,
|
||||||
|
pub private: RSAPrivate
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RSAKeyPair {
|
||||||
|
/// Generates a fresh RSA key pair of the given bit size. Valid bit sizes
|
||||||
|
/// are 512, 1024, 2048, 3072, 4096, 7680, 8192, and 15360. If you
|
||||||
|
/// actually want to protect data, use a value greater than or equal to
|
||||||
|
/// 2048. If you don't want to spend all day waiting for RSA computations
|
||||||
|
/// to finish, choose a value less than or equal to 4096.
|
||||||
|
///
|
||||||
|
/// This routine will use `OsRng` for entropy. If you want to use your
|
||||||
|
/// own random number generator, use `generate_w_rng`.
|
||||||
|
pub fn generate(len_bits: usize) -> Result<RSAKeyPair,RSAKeyGenError> {
|
||||||
|
let mut rng = OsRng::new()?;
|
||||||
|
RSAKeyPair::generate_w_rng(&mut rng, len_bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a fresh RSA key pair of the given bit size. Valid bit sizes
|
||||||
|
/// are 512, 1024, 2048, 3072, 4096, 7680, 8192, and 15360. If you
|
||||||
|
/// actually want to protect data, use a value greater than or equal to
|
||||||
|
/// 2048. If you don't want to spend all day waiting for RSA computations
|
||||||
|
/// to finish, choose a value less than or equal to 4096.
|
||||||
|
///
|
||||||
|
/// If you provide your own random number generator that is not `OsRng`,
|
||||||
|
/// you should know what you're doing, and be using a cryptographically-
|
||||||
|
/// strong RNG of your own choosing. We've warned you. Use a good one.
|
||||||
|
/// So now it's on you.
|
||||||
|
pub fn generate_w_rng<G: Rng>(rng: &mut G, len_bits: usize)
|
||||||
|
-> Result<RSAKeyPair,RSAKeyGenError>
|
||||||
|
{
|
||||||
|
let e = UCN::from(65537 as u32);
|
||||||
|
|
||||||
|
for &(length, _) in ACCEPTABLE_KEY_SIZES.iter() {
|
||||||
|
if length == len_bits {
|
||||||
|
let (p, q) = generate_pq(rng, &e, len_bits);
|
||||||
|
let n = &p * &q;
|
||||||
|
let one = UCN::from(1 as u8);
|
||||||
|
let phi = (p - &one) * (q - &one);
|
||||||
|
let d = e.modinv(&phi);
|
||||||
|
let public_key = RSAPublic::new(n.clone(), e);
|
||||||
|
let private_key = RSAPrivate::new(n, d);
|
||||||
|
return Ok(RSAKeyPair{
|
||||||
|
private: private_key,
|
||||||
|
public: public_key
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(RSAKeyGenError::InvalidKeySize(len_bits))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use quickcheck::{Arbitrary,Gen};
|
||||||
|
use rsa::core::{ep,dp,sp1,vp1};
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const TEST_KEY_SIZES: [usize; 2] = [512, 1024];
|
||||||
|
|
||||||
|
impl Arbitrary for RSAKeyPair {
|
||||||
|
fn arbitrary<G: Gen>(g: &mut G) -> RSAKeyPair {
|
||||||
|
let size = g.choose(&TEST_KEY_SIZES).unwrap();
|
||||||
|
RSAKeyPair::generate_w_rng(g, *size).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
#[ignore]
|
||||||
|
fn rsa_ep_dp_inversion(kp: RSAKeyPair, n: UCN) -> bool {
|
||||||
|
let m = n.reduce(&kp.public.nu);
|
||||||
|
let ciphertext = ep(&kp.public.nu, &kp.public.e, &m);
|
||||||
|
let mprime = dp(&kp.private.nu, &kp.private.d, &ciphertext);
|
||||||
|
mprime == m
|
||||||
|
}
|
||||||
|
#[ignore]
|
||||||
|
fn rsa_sp_vp_inversion(kp: RSAKeyPair, n: UCN) -> bool {
|
||||||
|
let m = n.reduce(&kp.public.nu);
|
||||||
|
let sig = sp1(&kp.private.nu, &kp.private.d, &m);
|
||||||
|
let mprime = vp1(&kp.public.nu, &kp.public.e, &sig);
|
||||||
|
mprime == m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/rsa/oaep.rs
Normal file
47
src/rsa/oaep.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
use cryptonum::UCN;
|
||||||
|
use digest::{FixedOutput,Input};
|
||||||
|
|
||||||
|
/// Parameters for OAEP encryption and decryption: a hash function to use as part of the message
|
||||||
|
/// generation function (MGF1, if you're curious), and any labels you want to include as part of
|
||||||
|
/// the encryption.
|
||||||
|
pub struct OAEPParams<H: Clone + Input + FixedOutput> {
|
||||||
|
pub hash: H,
|
||||||
|
pub label: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H: Clone + Input + FixedOutput> OAEPParams<H> {
|
||||||
|
pub fn new(hash: H, label: String)
|
||||||
|
-> OAEPParams<H>
|
||||||
|
{
|
||||||
|
OAEPParams { hash: hash, label: label }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash_len(&self) -> usize {
|
||||||
|
self.hash.clone().fixed_result().as_slice().len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash(&self, input: &[u8]) -> Vec<u8> {
|
||||||
|
let mut digest = self.hash.clone();
|
||||||
|
digest.process(input);
|
||||||
|
digest.fixed_result().as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mgf1(&self, input: &[u8], len: usize) -> Vec<u8> {
|
||||||
|
let mut res = Vec::with_capacity(len);
|
||||||
|
let mut counter = UCN::from(0u64);
|
||||||
|
let one = UCN::from(1u64);
|
||||||
|
|
||||||
|
while res.len() < len {
|
||||||
|
let c = counter.to_bytes(4);
|
||||||
|
let mut digest = self.hash.clone();
|
||||||
|
digest.process(input);
|
||||||
|
digest.process(&c);
|
||||||
|
let chunk = digest.fixed_result();
|
||||||
|
res.extend_from_slice(chunk.as_slice());
|
||||||
|
counter = counter + &one;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.truncate(len);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
149
src/rsa/private.rs
Normal file
149
src/rsa/private.rs
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
use cryptonum::{BarrettUCN,UCN};
|
||||||
|
use digest::{FixedOutput,Input};
|
||||||
|
use rsa::core::{ACCEPTABLE_KEY_SIZES,dp,pkcs1_pad,sp1,xor_vecs};
|
||||||
|
use rsa::errors::RSAError;
|
||||||
|
use rsa::oaep::OAEPParams;
|
||||||
|
use rsa::signing_hashes::SigningHash;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct RSAPrivate {
|
||||||
|
pub(crate) byte_len: usize,
|
||||||
|
pub(crate) n: UCN,
|
||||||
|
pub(crate) nu: BarrettUCN,
|
||||||
|
pub(crate) d: UCN
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl fmt::Debug for RSAPrivate {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
f.debug_struct("RSAPrivate")
|
||||||
|
.field("byte_len", &self.byte_len)
|
||||||
|
.field("n", &self.n)
|
||||||
|
.field("nu", &self.nu)
|
||||||
|
.field("d", &self.d)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl PartialEq for RSAPrivate {
|
||||||
|
fn eq(&self, rhs: &RSAPrivate) -> bool {
|
||||||
|
(self.byte_len == rhs.byte_len) &&
|
||||||
|
(self.n == rhs.n) &&
|
||||||
|
(self.nu == rhs.nu) &&
|
||||||
|
(self.d == rhs.d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl Eq for RSAPrivate {}
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
impl fmt::Debug for RSAPrivate {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
f.write_str("RSAPrivateKey<PRIVATE>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RSAPrivate {
|
||||||
|
/// Create a new RSA public key from the given components, which you found
|
||||||
|
/// via some other mechanism.
|
||||||
|
pub fn new(n: UCN, d: UCN) -> RSAPrivate {
|
||||||
|
let len = n.bits();
|
||||||
|
|
||||||
|
for &(valid_bits, _) in ACCEPTABLE_KEY_SIZES.iter() {
|
||||||
|
if valid_bits >= len {
|
||||||
|
return RSAPrivate {
|
||||||
|
byte_len: valid_bits / 8,
|
||||||
|
n: n.clone(),
|
||||||
|
nu: n.barrett_u(),
|
||||||
|
d: d.clone()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("Invalid RSA key size in new()")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign a message using the given hash.
|
||||||
|
pub fn sign(&self, sighash: &SigningHash, msg: &[u8]) -> Vec<u8> {
|
||||||
|
let hash = (sighash.run)(msg);
|
||||||
|
let em = pkcs1_pad(&sighash.ident, &hash, self.byte_len);
|
||||||
|
let m = UCN::from_bytes(&em);
|
||||||
|
let s = sp1(&self.nu, &self.d, &m);
|
||||||
|
let sig = s.to_bytes(self.byte_len);
|
||||||
|
sig
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decrypt a message with the given parameters.
|
||||||
|
pub fn decrypt<H: Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, msg: &[u8])
|
||||||
|
-> Result<Vec<u8>,RSAError>
|
||||||
|
{
|
||||||
|
let mut res = Vec::new();
|
||||||
|
|
||||||
|
for chunk in msg.chunks(self.byte_len) {
|
||||||
|
let mut dchunk = self.oaep_decrypt(oaep, chunk)?;
|
||||||
|
res.append(&mut dchunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn oaep_decrypt<H: Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, c: &[u8])
|
||||||
|
-> Result<Vec<u8>,RSAError>
|
||||||
|
{
|
||||||
|
// Step 1b
|
||||||
|
if c.len() != self.byte_len {
|
||||||
|
return Err(RSAError::DecryptionError);
|
||||||
|
}
|
||||||
|
// Step 1c
|
||||||
|
if self.byte_len < ((2 * oaep.hash_len()) + 2) {
|
||||||
|
return Err(RSAError::DecryptHashMismatch);
|
||||||
|
}
|
||||||
|
// Step 2a
|
||||||
|
let c_ip = UCN::from_bytes(&c.to_vec());
|
||||||
|
// Step 2b
|
||||||
|
let m_ip = dp(&self.nu, &self.d, &c_ip);
|
||||||
|
// Step 2c
|
||||||
|
let em = &m_ip.to_bytes(self.byte_len);
|
||||||
|
// Step 3a
|
||||||
|
let l_hash = oaep.hash(oaep.label.as_bytes());
|
||||||
|
// Step 3b
|
||||||
|
let (y, rest) = em.split_at(1);
|
||||||
|
let (masked_seed, masked_db) = rest.split_at(oaep.hash_len());
|
||||||
|
// Step 3c
|
||||||
|
let seed_mask = oaep.mgf1(masked_db, oaep.hash_len());
|
||||||
|
// Step 3d
|
||||||
|
let seed = xor_vecs(&masked_seed.to_vec(), &seed_mask);
|
||||||
|
// Step 3e
|
||||||
|
let db_mask = oaep.mgf1(&seed, self.byte_len - oaep.hash_len() - 1);
|
||||||
|
// Step 3f
|
||||||
|
let db = xor_vecs(&masked_db.to_vec(), &db_mask);
|
||||||
|
// Step 3g
|
||||||
|
let (l_hash2, ps_o_m) = db.split_at(oaep.hash_len());
|
||||||
|
let o_m = drop0s(ps_o_m);
|
||||||
|
let (o, m) = o_m.split_at(1);
|
||||||
|
// Checks!
|
||||||
|
if o != [1] {
|
||||||
|
return Err(RSAError::DecryptionError);
|
||||||
|
}
|
||||||
|
if l_hash != l_hash2 {
|
||||||
|
return Err(RSAError::DecryptionError);
|
||||||
|
}
|
||||||
|
if y != [0] {
|
||||||
|
return Err(RSAError::DecryptionError);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(m.to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drop0s(a: &[u8]) -> &[u8] {
|
||||||
|
let mut idx = 0;
|
||||||
|
|
||||||
|
while (idx < a.len()) && (a[idx] == 0) {
|
||||||
|
idx = idx + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&a[idx..]
|
||||||
|
}
|
||||||
124
src/rsa/public.rs
Normal file
124
src/rsa/public.rs
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
use cryptonum::{BarrettUCN,UCN};
|
||||||
|
use digest::{FixedOutput,Input};
|
||||||
|
use rand::{OsRng,Rng};
|
||||||
|
use rsa::core::{ACCEPTABLE_KEY_SIZES,ep,pkcs1_pad,vp1,xor_vecs};
|
||||||
|
use rsa::errors::RSAError;
|
||||||
|
use rsa::oaep::OAEPParams;
|
||||||
|
use rsa::signing_hashes::SigningHash;
|
||||||
|
|
||||||
|
#[derive(Clone,Debug,PartialEq,Eq)]
|
||||||
|
pub struct RSAPublic {
|
||||||
|
pub(crate) byte_len: usize,
|
||||||
|
pub(crate) n: UCN,
|
||||||
|
pub(crate) nu: BarrettUCN,
|
||||||
|
pub(crate) e: UCN
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RSAPublic {
|
||||||
|
/// Create a new RSA public key from the given components, which you found
|
||||||
|
/// via some other mechanism.
|
||||||
|
pub fn new(n: UCN, e: UCN) -> RSAPublic {
|
||||||
|
let len = n.bits();
|
||||||
|
|
||||||
|
for &(valid_bits, _) in ACCEPTABLE_KEY_SIZES.iter() {
|
||||||
|
if valid_bits >= len {
|
||||||
|
return RSAPublic{
|
||||||
|
byte_len: valid_bits / 8,
|
||||||
|
n: n.clone(),
|
||||||
|
nu: n.barrett_u(),
|
||||||
|
e: e.clone()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("Invalid RSA key size in new()")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify the signature for a given message, using the given signing hash,
|
||||||
|
/// returning true iff the signature validates.
|
||||||
|
pub fn verify(&self, shash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool {
|
||||||
|
let hash = (shash.run)(msg);
|
||||||
|
let s = UCN::from_bytes(&sig);
|
||||||
|
let m = vp1(&self.nu, &self.e, &s);
|
||||||
|
let em = m.to_bytes(self.byte_len);
|
||||||
|
let em_ = pkcs1_pad(&shash.ident, &hash, self.byte_len);
|
||||||
|
(em == em_)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encrypt the given data with the public key and parameters, returning
|
||||||
|
/// the encrypted blob or an error encountered during encryption.
|
||||||
|
///
|
||||||
|
/// OAEP encoding is used for this process, which requires a random number
|
||||||
|
/// generator. This version of the function uses `OsRng`. If you want to
|
||||||
|
/// use your own RNG, use `encrypt_w_rng`.
|
||||||
|
pub fn encrypt<H:Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, msg: &[u8])
|
||||||
|
-> Result<Vec<u8>,RSAError>
|
||||||
|
{
|
||||||
|
let mut g = OsRng::new()?;
|
||||||
|
self.encrypt_with_rng(&mut g, oaep, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encrypt the given data with the public key and parameters, returning
|
||||||
|
/// the encrypted blob or an error encountered during encryption. This
|
||||||
|
/// version also allows you to provide your own RNG, if you really feel
|
||||||
|
/// like shooting yourself in the foot.
|
||||||
|
pub fn encrypt_with_rng<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
|
||||||
|
-> Result<Vec<u8>,RSAError>
|
||||||
|
where G: Rng, H: Clone + Input + FixedOutput
|
||||||
|
{
|
||||||
|
if self.byte_len <= ((2 * oaep.hash_len()) + 2) {
|
||||||
|
return Err(RSAError::KeyTooSmallForHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut res = Vec::new();
|
||||||
|
|
||||||
|
for chunk in msg.chunks(self.byte_len - (2 * oaep.hash_len()) - 2) {
|
||||||
|
let mut newchunk = self.oaep_encrypt(g, oaep, chunk)?;
|
||||||
|
res.append(&mut newchunk)
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn oaep_encrypt<G: Rng,H:Clone + Input + FixedOutput>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
|
||||||
|
-> Result<Vec<u8>,RSAError>
|
||||||
|
{
|
||||||
|
// Step 1b
|
||||||
|
if msg.len() > (self.byte_len - (2 * oaep.hash_len()) - 2) {
|
||||||
|
return Err(RSAError::BadMessageSize)
|
||||||
|
}
|
||||||
|
// Step 2a
|
||||||
|
let mut lhash = oaep.hash(oaep.label.as_bytes());
|
||||||
|
// Step 2b
|
||||||
|
let num0s = self.byte_len - msg.len() - (2 * oaep.hash_len()) - 2;
|
||||||
|
let mut ps = Vec::new();
|
||||||
|
ps.resize(num0s, 0);
|
||||||
|
// Step 2c
|
||||||
|
let mut db = Vec::new();
|
||||||
|
db.append(&mut lhash);
|
||||||
|
db.append(&mut ps);
|
||||||
|
db.push(1);
|
||||||
|
db.extend_from_slice(msg);
|
||||||
|
// Step 2d
|
||||||
|
let seed : Vec<u8> = g.gen_iter().take(oaep.hash_len()).collect();
|
||||||
|
// Step 2e
|
||||||
|
let db_mask = oaep.mgf1(&seed, self.byte_len - oaep.hash_len() - 1);
|
||||||
|
// Step 2f
|
||||||
|
let mut masked_db = xor_vecs(&db, &db_mask);
|
||||||
|
// Step 2g
|
||||||
|
let seed_mask = oaep.mgf1(&masked_db, oaep.hash_len());
|
||||||
|
// Step 2h
|
||||||
|
let mut masked_seed = xor_vecs(&seed, &seed_mask);
|
||||||
|
// Step 2i
|
||||||
|
let mut em = Vec::new();
|
||||||
|
em.push(0);
|
||||||
|
em.append(&mut masked_seed);
|
||||||
|
em.append(&mut masked_db);
|
||||||
|
// Step 3a
|
||||||
|
let m_i = UCN::from_bytes(&em);
|
||||||
|
// Step 3b
|
||||||
|
let c_i = ep(&self.nu, &self.e, &m_i);
|
||||||
|
// Step 3c
|
||||||
|
let c = c_i.to_bytes(self.byte_len);
|
||||||
|
Ok(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
119
src/rsa/signing_hashes.rs
Normal file
119
src/rsa/signing_hashes.rs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
use digest::{FixedOutput,Input};
|
||||||
|
use sha1::Sha1;
|
||||||
|
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// A hash that can be used to sign a message.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SigningHash {
|
||||||
|
/// The name of this hash (only used for display purposes)
|
||||||
|
pub name: &'static str,
|
||||||
|
/// The approved identity string for the hash.
|
||||||
|
pub ident: &'static [u8],
|
||||||
|
/// The hash
|
||||||
|
pub run: fn(&[u8]) -> Vec<u8>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for SigningHash {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The "null" signing hash. This signing hash has no identity, and will
|
||||||
|
/// simply pass the data through unhashed. You really should know what
|
||||||
|
/// you're doing if you use this, and probably using a somewhat strange
|
||||||
|
/// signing protocol. There's no good reason to use this in new code
|
||||||
|
/// for a new protocol or system.
|
||||||
|
pub static SIGNING_HASH_NULL: SigningHash = SigningHash {
|
||||||
|
name: "NULL",
|
||||||
|
ident: &[],
|
||||||
|
run: nohash
|
||||||
|
};
|
||||||
|
|
||||||
|
fn nohash(i: &[u8]) -> Vec<u8> {
|
||||||
|
i.to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign a hash based on SHA1. You shouldn't use this unless you're using
|
||||||
|
/// very small keys, and this is the only one available to you. Even then,
|
||||||
|
/// why are you using such small keys?!
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
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.
|
||||||
|
pub static SIGNING_HASH_SHA224: SigningHash = SigningHash {
|
||||||
|
name: "SHA224",
|
||||||
|
ident: &[0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||||
|
0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,
|
||||||
|
0x1c],
|
||||||
|
run: runsha224
|
||||||
|
};
|
||||||
|
|
||||||
|
fn runsha224(i: &[u8]) -> Vec<u8> {
|
||||||
|
let mut d = Sha224::default();
|
||||||
|
d.process(i);
|
||||||
|
d.fixed_result().as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign a hash based on SHA2-256. The first one I'd recommend!
|
||||||
|
pub static SIGNING_HASH_SHA256: SigningHash = SigningHash {
|
||||||
|
name: "SHA256",
|
||||||
|
ident: &[0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||||
|
0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,
|
||||||
|
0x20],
|
||||||
|
run: runsha256
|
||||||
|
};
|
||||||
|
|
||||||
|
fn runsha256(i: &[u8]) -> Vec<u8> {
|
||||||
|
let mut d = Sha256::default();
|
||||||
|
d.process(i);
|
||||||
|
d.fixed_result().as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign a hash based on SHA2-384. Approximately 50% better than
|
||||||
|
/// SHA-256.
|
||||||
|
pub static SIGNING_HASH_SHA384: SigningHash = SigningHash {
|
||||||
|
name: "SHA384",
|
||||||
|
ident: &[0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||||
|
0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,
|
||||||
|
0x30],
|
||||||
|
run: runsha384
|
||||||
|
};
|
||||||
|
|
||||||
|
fn runsha384(i: &[u8]) -> Vec<u8> {
|
||||||
|
let mut d = Sha384::default();
|
||||||
|
d.process(i);
|
||||||
|
d.fixed_result().as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign a hash based on SHA2-512. At this point, you're getting a bit
|
||||||
|
/// silly. But if you want to through 8kbit RSA keys with a 512 bit SHA2
|
||||||
|
/// signing hash, we're totally behind you.
|
||||||
|
pub static SIGNING_HASH_SHA512: SigningHash = SigningHash {
|
||||||
|
name: "SHA512",
|
||||||
|
ident: &[0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||||
|
0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,
|
||||||
|
0x40],
|
||||||
|
run: runsha512
|
||||||
|
};
|
||||||
|
|
||||||
|
fn runsha512(i: &[u8]) -> Vec<u8> {
|
||||||
|
let mut d = Sha512::default();
|
||||||
|
d.process(i);
|
||||||
|
d.fixed_result().as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
88
src/testing.rs
Normal file
88
src/testing.rs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
use cryptonum::{SCN,UCN};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::str::Lines;
|
||||||
|
|
||||||
|
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_left_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).unwrap() as u8 );
|
||||||
|
}
|
||||||
|
Some(c2) => {
|
||||||
|
let b1 = c1.to_digit(16).unwrap() as u8;
|
||||||
|
let b2 = c2.to_digit(16).unwrap() 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 make_signed(m: HashMap<String,(bool,Vec<u8>)>) -> HashMap<String,SCN>
|
||||||
|
{
|
||||||
|
let mut res: HashMap<String,SCN> = HashMap::new();
|
||||||
|
|
||||||
|
for (key, (neg, bval)) in m.iter() {
|
||||||
|
let base = UCN::from_bytes(bval);
|
||||||
|
let val = SCN{ negative: *neg, value: base };
|
||||||
|
res.insert(key.clone(), val);
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_unsigned(m: HashMap<String,(bool,Vec<u8>)>) -> HashMap<String,UCN>
|
||||||
|
{
|
||||||
|
let mut res: HashMap<String,UCN> = HashMap::new();
|
||||||
|
|
||||||
|
for (key, (neg, bval)) in m.iter() {
|
||||||
|
assert!(!neg);
|
||||||
|
res.insert(key.clone(), UCN::from_bytes(bval));
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_test<F>(fname: &'static str, i: usize, f: F)
|
||||||
|
where F: Fn(HashMap<String,(bool,Vec<u8>)>)
|
||||||
|
{
|
||||||
|
let mut file = File::open(fname).unwrap();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
225
tests/dsa/Generator.java
Normal file
225
tests/dsa/Generator.java
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
// Just because I always forget Java compilation:
|
||||||
|
// javac Generator.java -cp bcprov-ext-jdk15on-159.jar
|
||||||
|
// java -cp "bcprov-ext-jdk15on-159.jar:." Generator
|
||||||
|
// Also, go here:
|
||||||
|
// https://www.bouncycastle.org/latest_releases.html
|
||||||
|
//
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.InterruptedException;
|
||||||
|
import java.lang.Math;
|
||||||
|
import java.lang.Thread;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||||
|
import org.bouncycastle.crypto.Digest;
|
||||||
|
import org.bouncycastle.crypto.digests.SHA1Digest;
|
||||||
|
import org.bouncycastle.crypto.digests.SHA224Digest;
|
||||||
|
import org.bouncycastle.crypto.digests.SHA256Digest;
|
||||||
|
import org.bouncycastle.crypto.digests.SHA384Digest;
|
||||||
|
import org.bouncycastle.crypto.digests.SHA512Digest;
|
||||||
|
import org.bouncycastle.crypto.generators.DSAKeyPairGenerator;
|
||||||
|
import org.bouncycastle.crypto.generators.DSAParametersGenerator;
|
||||||
|
import org.bouncycastle.crypto.params.DSAKeyGenerationParameters;
|
||||||
|
import org.bouncycastle.crypto.params.DSAParameterGenerationParameters;
|
||||||
|
import org.bouncycastle.crypto.params.DSAParameters;
|
||||||
|
import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
|
||||||
|
import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
|
||||||
|
import org.bouncycastle.crypto.signers.DSASigner;
|
||||||
|
import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
|
||||||
|
|
||||||
|
class Generator {
|
||||||
|
private FileWriter out;
|
||||||
|
private SecureRandom rng;
|
||||||
|
|
||||||
|
final static int NUM_THREADS = 4;
|
||||||
|
|
||||||
|
public Generator(SecureRandom r, FileWriter o) {
|
||||||
|
rng = r;
|
||||||
|
out = o;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runTests(int lsize, int nsize, int count)
|
||||||
|
throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
Thread threads[] = new Thread[NUM_THREADS];
|
||||||
|
|
||||||
|
System.out.print("Generating L" + lsize + "N" + nsize + " tests ");
|
||||||
|
for(int i = 0; i < NUM_THREADS; i++) {
|
||||||
|
Runner runner = new Runner(lsize, nsize, count / NUM_THREADS, this);
|
||||||
|
Thread runThread = new Thread(runner);
|
||||||
|
runThread.start();
|
||||||
|
threads[i] = runThread;
|
||||||
|
}
|
||||||
|
for(Thread thread : threads) {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
System.out.println(" done.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void output(DSAParameters params,
|
||||||
|
AsymmetricCipherKeyPair kp,
|
||||||
|
int digestsize,
|
||||||
|
byte[] message,
|
||||||
|
BigInteger[] rs)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic();
|
||||||
|
DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate();
|
||||||
|
out.write("p: " + params.getP().toString(16) + "\n");
|
||||||
|
out.write("q: " + params.getQ().toString(16) + "\n");
|
||||||
|
out.write("g: " + params.getG().toString(16) + "\n");
|
||||||
|
out.write("x: " + priv.getX().toString(16) + "\n");
|
||||||
|
out.write("y: " + pub.getY().toString(16) + "\n");
|
||||||
|
out.write("h: " + digestsize + "\n");
|
||||||
|
out.write("m: " + asHex(message) + "\n");
|
||||||
|
out.write("r: " + rs[0].toString(16) + "\n");
|
||||||
|
out.write("s: " + rs[1].toString(16) + "\n");
|
||||||
|
out.flush();
|
||||||
|
System.out.print(".");
|
||||||
|
System.out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Digest appropriateDigest(int nsize)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
switch(nsize) {
|
||||||
|
case 1: return new SHA1Digest();
|
||||||
|
case 160: return new SHA1Digest();
|
||||||
|
case 224: return new SHA224Digest();
|
||||||
|
case 256: return new SHA256Digest();
|
||||||
|
case 384: return new SHA384Digest();
|
||||||
|
case 512: return new SHA512Digest();
|
||||||
|
default:
|
||||||
|
throw new IOException("Bad digest size!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int randomDigestSize()
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
switch(getRandomChoice(5)) {
|
||||||
|
case 0: return 1;
|
||||||
|
case 1: return 224;
|
||||||
|
case 2: return 256;
|
||||||
|
case 3: return 384;
|
||||||
|
case 4: return 512;
|
||||||
|
default:
|
||||||
|
throw new IOException("The world broke.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getRandomChoice(int modulus) {
|
||||||
|
byte randoms[] = new byte[2];
|
||||||
|
rng.nextBytes(randoms);
|
||||||
|
int random = ((int)randoms[0] << 8) + ((int)randoms[1]);
|
||||||
|
return (Math.abs(random) % modulus);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String asHex(byte[] data) {
|
||||||
|
String result = "";
|
||||||
|
|
||||||
|
for(byte value : data) {
|
||||||
|
result = result + String.format("%02x", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
SecureRandom rng = new SecureRandom();
|
||||||
|
FileWriter outfile = new FileWriter("signature.test", false);
|
||||||
|
Generator gen = new Generator(rng, outfile);
|
||||||
|
|
||||||
|
gen.runTests(1024, 160, 500);
|
||||||
|
gen.runTests(2048, 224, 500);
|
||||||
|
gen.runTests(2048, 256, 250);
|
||||||
|
gen.runTests(3072, 256, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Runner implements Runnable {
|
||||||
|
private int lsize;
|
||||||
|
private int nsize;
|
||||||
|
private int count;
|
||||||
|
private Generator parent;
|
||||||
|
|
||||||
|
public Runner(int lsize, int nsize, int count, Generator parent)
|
||||||
|
{
|
||||||
|
this.lsize = lsize;
|
||||||
|
this.nsize = nsize;
|
||||||
|
this.count = count;
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
for(int i = 0; i < count; i++) {
|
||||||
|
runTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DSAParameters getParameters()
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
DSAParameterGenerationParameters genparams =
|
||||||
|
new DSAParameterGenerationParameters(lsize, nsize, 80, rng);
|
||||||
|
DSAParametersGenerator gen =
|
||||||
|
new DSAParametersGenerator(parent.appropriateDigest(nsize));
|
||||||
|
gen.init(genparams);
|
||||||
|
return gen.generateParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AsymmetricCipherKeyPair getKeyPair(DSAParameters params)
|
||||||
|
{
|
||||||
|
DSAKeyGenerationParameters dsakeygenparams =
|
||||||
|
new DSAKeyGenerationParameters(rng, params);
|
||||||
|
DSAKeyPairGenerator keygen = new DSAKeyPairGenerator();
|
||||||
|
keygen.init(dsakeygenparams);
|
||||||
|
return keygen.generateKeyPair();
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getMessage()
|
||||||
|
{
|
||||||
|
int msgsize = getRandomChoice(1024);
|
||||||
|
byte message[] = new byte[msgsize];
|
||||||
|
rng.nextBytes(message);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] runHash(byte[] msg, int digestsize)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
Digest digestfn = appropriateDigest(digestsize);
|
||||||
|
digestfn.update(msg, 0, msg.length);
|
||||||
|
byte result[] = new byte[digestfn.getDigestSize()];
|
||||||
|
digestfn.doFinal(result, 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runTest()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
DSAParameters params = getParameters();
|
||||||
|
AsymmetricCipherKeyPair kp = getKeyPair(params);
|
||||||
|
DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic();
|
||||||
|
DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate();
|
||||||
|
|
||||||
|
byte message[] = getMessage();
|
||||||
|
int digestsize = randomDigestSize();
|
||||||
|
byte hash[] = runHash(message, digestsize);
|
||||||
|
|
||||||
|
Digest msgdigest = appropriateDigest(digestsize);
|
||||||
|
HMacDSAKCalculator kgen = new HMacDSAKCalculator(msgdigest);
|
||||||
|
DSASigner signer = new DSASigner(kgen);
|
||||||
|
signer.init(true, priv);
|
||||||
|
BigInteger rs[] = signer.generateSignature(hash);
|
||||||
|
parent.output(params, kp, digestsize, message, rs);
|
||||||
|
} catch(IOException exc) {
|
||||||
|
System.out.println("EXCEPTION!");
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12132
tests/dsa/signature.test
Normal file
12132
tests/dsa/signature.test
Normal file
File diff suppressed because it is too large
Load Diff
318
tests/ecdsa/Generator.java
Normal file
318
tests/ecdsa/Generator.java
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
// Just because I always forget Java compilation:
|
||||||
|
// javac Generator.java -cp bcprov-ext-jdk15on-159.jar
|
||||||
|
// java -cp "bcprov-ext-jdk15on-159.jar:." Generator
|
||||||
|
// Also, go here:
|
||||||
|
// https://www.bouncycastle.org/latest_releases.html
|
||||||
|
//
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.InterruptedException;
|
||||||
|
import java.lang.Math;
|
||||||
|
import java.lang.Thread;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import org.bouncycastle.asn1.nist.NISTNamedCurves;
|
||||||
|
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||||
|
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||||
|
import org.bouncycastle.crypto.Digest;
|
||||||
|
import org.bouncycastle.crypto.digests.SHA1Digest;
|
||||||
|
import org.bouncycastle.crypto.digests.SHA224Digest;
|
||||||
|
import org.bouncycastle.crypto.digests.SHA256Digest;
|
||||||
|
import org.bouncycastle.crypto.digests.SHA384Digest;
|
||||||
|
import org.bouncycastle.crypto.digests.SHA512Digest;
|
||||||
|
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
|
||||||
|
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||||
|
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
|
||||||
|
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||||
|
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||||
|
import org.bouncycastle.crypto.signers.ECDSASigner;
|
||||||
|
import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
|
||||||
|
import org.bouncycastle.math.ec.ECAlgorithms;
|
||||||
|
import org.bouncycastle.math.ec.ECPoint;
|
||||||
|
|
||||||
|
class Generator {
|
||||||
|
final static int COUNT = 500;
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
new Generator().run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Generator() { }
|
||||||
|
|
||||||
|
public void run()
|
||||||
|
throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
OutFiles outfiles = new OutFiles();
|
||||||
|
String[] curves = { "P-192", "P-224", "P-256", "P-384", "P-521" };
|
||||||
|
ArrayList<Thread> threads = new ArrayList<Thread>();
|
||||||
|
|
||||||
|
System.out.print("Generating: ");
|
||||||
|
for(String curve : curves) {
|
||||||
|
X9ECParameters params = NISTNamedCurves.getByName(curve);
|
||||||
|
ECDomainParameters dp = new ECDomainParameters(params.getCurve(),
|
||||||
|
params.getG(),
|
||||||
|
params.getN());
|
||||||
|
Runner runner = new Runner(outfiles, dp);
|
||||||
|
Thread thread = new Thread(runner);
|
||||||
|
thread.start();
|
||||||
|
threads.add(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Thread thread: threads) {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
System.out.println(" done.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OutFiles {
|
||||||
|
public FileWriter negate;
|
||||||
|
public FileWriter dble;
|
||||||
|
public FileWriter add;
|
||||||
|
public FileWriter mul;
|
||||||
|
public FileWriter add2mul;
|
||||||
|
public FileWriter sig;
|
||||||
|
|
||||||
|
public OutFiles()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
negate = new FileWriter("ec_negate.test", false);
|
||||||
|
dble = new FileWriter("ec_dble.test", false);
|
||||||
|
add = new FileWriter("ec_add.test", false);
|
||||||
|
mul = new FileWriter("ec_mul.test", false);
|
||||||
|
add2mul = new FileWriter("ec_add2mul.test", false);
|
||||||
|
sig = new FileWriter("signature.test", false);
|
||||||
|
} catch(IOException e) {
|
||||||
|
System.out.println("Blech: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void dump(FileWriter file, Map<String,String> x) {
|
||||||
|
try {
|
||||||
|
for(Map.Entry<String,String> entry : x.entrySet()) {
|
||||||
|
file.write(entry.getKey());
|
||||||
|
file.write(": ");
|
||||||
|
file.write(entry.getValue());
|
||||||
|
file.write("\n");
|
||||||
|
file.flush();
|
||||||
|
|
||||||
|
if(file == negate) { System.out.print("N"); };
|
||||||
|
if(file == dble) { System.out.print("D"); };
|
||||||
|
if(file == add) { System.out.print("A"); };
|
||||||
|
if(file == mul) { System.out.print("M"); };
|
||||||
|
if(file == add2mul) { System.out.print("2"); };
|
||||||
|
if(file == sig) { System.out.print("S"); };
|
||||||
|
System.out.flush();
|
||||||
|
}
|
||||||
|
} catch(IOException e) {
|
||||||
|
System.out.println("Argh: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Runner implements Runnable {
|
||||||
|
private OutFiles outfiles;
|
||||||
|
private SecureRandom rng;
|
||||||
|
private ECDomainParameters ecparams;
|
||||||
|
private BigInteger two;
|
||||||
|
|
||||||
|
public Runner(OutFiles outfiles, ECDomainParameters params) {
|
||||||
|
this.outfiles = outfiles;
|
||||||
|
this.ecparams = params;
|
||||||
|
this.rng = new SecureRandom();
|
||||||
|
this.two = BigInteger.valueOf(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
for(int i = 0; i < COUNT; i++) { generateNegateTests(); }
|
||||||
|
for(int i = 0; i < COUNT; i++) { generateDoubleTests(); }
|
||||||
|
for(int i = 0; i < COUNT; i++) { generateAddTests(); }
|
||||||
|
for(int i = 0; i < COUNT; i++) { generateMulTests(); }
|
||||||
|
for(int i = 0; i < COUNT; i++) { generateAdd2MulTests(); }
|
||||||
|
for(int i = 0; i < COUNT; i++) { generateSignatureTests(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateNegateTests() {
|
||||||
|
ECPoint p = getPoint();
|
||||||
|
ECPoint n = p.negate().normalize();
|
||||||
|
HashMap<String,String> m = new HashMap<String,String>();
|
||||||
|
|
||||||
|
m.put("c", Integer.toString(ecparams.getN().bitLength()));
|
||||||
|
m.put("x", p.getAffineXCoord().toBigInteger().toString(16));
|
||||||
|
m.put("y", p.getAffineYCoord().toBigInteger().toString(16));
|
||||||
|
m.put("a", n.getAffineXCoord().toBigInteger().toString(16));
|
||||||
|
m.put("b", n.getAffineYCoord().toBigInteger().toString(16));
|
||||||
|
outfiles.dump(outfiles.negate, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateDoubleTests() {
|
||||||
|
ECPoint p = getPoint();
|
||||||
|
ECPoint n = p.twice().normalize();
|
||||||
|
HashMap<String,String> m = new HashMap<String,String>();
|
||||||
|
|
||||||
|
m.put("c", Integer.toString(ecparams.getN().bitLength()));
|
||||||
|
m.put("x", p.getAffineXCoord().toBigInteger().toString(16));
|
||||||
|
m.put("y", p.getAffineYCoord().toBigInteger().toString(16));
|
||||||
|
m.put("a", n.getAffineXCoord().toBigInteger().toString(16));
|
||||||
|
m.put("b", n.getAffineYCoord().toBigInteger().toString(16));
|
||||||
|
outfiles.dump(outfiles.dble, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateAddTests() {
|
||||||
|
ECPoint p1 = getPoint();
|
||||||
|
ECPoint p2 = getPoint();
|
||||||
|
ECPoint q = p1.add(p2).normalize();
|
||||||
|
HashMap<String,String> m = new HashMap<String,String>();
|
||||||
|
|
||||||
|
m.put("c", Integer.toString(ecparams.getN().bitLength()));
|
||||||
|
m.put("x", p1.getAffineXCoord().toBigInteger().toString(16));
|
||||||
|
m.put("y", p1.getAffineYCoord().toBigInteger().toString(16));
|
||||||
|
m.put("q", p2.getAffineXCoord().toBigInteger().toString(16));
|
||||||
|
m.put("r", p2.getAffineYCoord().toBigInteger().toString(16));
|
||||||
|
m.put("a", q.getAffineXCoord().toBigInteger().toString(16));
|
||||||
|
m.put("b", q.getAffineYCoord().toBigInteger().toString(16));
|
||||||
|
outfiles.dump(outfiles.add, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateMulTests() {
|
||||||
|
ECPoint p = getPoint();
|
||||||
|
BigInteger k = getConstant();
|
||||||
|
ECPoint q = p.multiply(k).normalize();
|
||||||
|
HashMap<String,String> m = new HashMap<String,String>();
|
||||||
|
|
||||||
|
m.put("c", Integer.toString(ecparams.getN().bitLength()));
|
||||||
|
m.put("x", p.getAffineXCoord().toBigInteger().toString(16));
|
||||||
|
m.put("y", p.getAffineYCoord().toBigInteger().toString(16));
|
||||||
|
m.put("k", k.toString(16));
|
||||||
|
m.put("a", q.getAffineXCoord().toBigInteger().toString(16));
|
||||||
|
m.put("b", q.getAffineYCoord().toBigInteger().toString(16));
|
||||||
|
outfiles.dump(outfiles.mul, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateAdd2MulTests() {
|
||||||
|
ECPoint p = getPoint();
|
||||||
|
BigInteger a = getConstant();
|
||||||
|
ECPoint q = getPoint();
|
||||||
|
BigInteger b = getConstant();
|
||||||
|
ECPoint r = ECAlgorithms.sumOfTwoMultiplies(p,a,q,b).normalize();
|
||||||
|
HashMap<String,String> m = new HashMap<String,String>();
|
||||||
|
|
||||||
|
m.put("c", Integer.toString(ecparams.getN().bitLength()));
|
||||||
|
m.put("x", p.getAffineXCoord().toBigInteger().toString(16));
|
||||||
|
m.put("y", p.getAffineYCoord().toBigInteger().toString(16));
|
||||||
|
m.put("a", a.toString(16));
|
||||||
|
m.put("q", q.getAffineXCoord().toBigInteger().toString(16));
|
||||||
|
m.put("r", q.getAffineYCoord().toBigInteger().toString(16));
|
||||||
|
m.put("b", b.toString(16));
|
||||||
|
m.put("s", r.getAffineXCoord().toBigInteger().toString(16));
|
||||||
|
m.put("t", r.getAffineYCoord().toBigInteger().toString(16));
|
||||||
|
outfiles.dump(outfiles.add2mul, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateSignatureTests() {
|
||||||
|
AsymmetricCipherKeyPair kp = getKeyPair();
|
||||||
|
ECPublicKeyParameters pub = (ECPublicKeyParameters)kp.getPublic();
|
||||||
|
ECPrivateKeyParameters priv = (ECPrivateKeyParameters)kp.getPrivate();
|
||||||
|
byte message[] = getMessage();
|
||||||
|
int digestsize = getDigestSize();
|
||||||
|
byte hash[] = runHash(message, digestsize);
|
||||||
|
Digest msgdigest = getHash(digestsize);
|
||||||
|
HMacDSAKCalculator kgen = new HMacDSAKCalculator(msgdigest);
|
||||||
|
ECDSASigner signer = new ECDSASigner(kgen);
|
||||||
|
signer.init(true, priv);
|
||||||
|
BigInteger rs[] = signer.generateSignature(hash);
|
||||||
|
HashMap<String,String> m = new HashMap<String,String>();
|
||||||
|
|
||||||
|
m.put("c", Integer.toString(ecparams.getN().bitLength()));
|
||||||
|
m.put("x", pub.getQ().getAffineXCoord().toBigInteger().toString(16));
|
||||||
|
m.put("y", pub.getQ().getAffineYCoord().toBigInteger().toString(16));
|
||||||
|
m.put("d", priv.getD().toString(16));
|
||||||
|
m.put("h", Integer.toString(digestsize));
|
||||||
|
m.put("m", asHex(message));
|
||||||
|
m.put("r", rs[0].toString(16));
|
||||||
|
m.put("s", rs[1].toString(16));
|
||||||
|
outfiles.dump(outfiles.sig, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] runHash(byte[] msg, int size) {
|
||||||
|
Digest digestfn = getHash(size);
|
||||||
|
digestfn.update(msg, 0, msg.length);
|
||||||
|
byte result[] = new byte[digestfn.getDigestSize()];
|
||||||
|
digestfn.doFinal(result, 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AsymmetricCipherKeyPair getKeyPair() {
|
||||||
|
ECKeyGenerationParameters params =
|
||||||
|
new ECKeyGenerationParameters(ecparams, rng);
|
||||||
|
ECKeyPairGenerator keygen = new ECKeyPairGenerator();
|
||||||
|
keygen.init(params);
|
||||||
|
return keygen.generateKeyPair();
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getMessage() {
|
||||||
|
int msgsize = rng.nextInt(1024);
|
||||||
|
byte message[] = new byte[msgsize];
|
||||||
|
rng.nextBytes(message);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ECPoint getPoint() {
|
||||||
|
BigInteger k = getConstant();
|
||||||
|
return ecparams.getG().multiply(k).normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigInteger getConstant() {
|
||||||
|
BigInteger n = ecparams.getN();
|
||||||
|
int nBitLength = n.bitLength();
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
BigInteger d = new BigInteger(nBitLength, rng);
|
||||||
|
|
||||||
|
if(d.compareTo(two) < 0 || (d.compareTo(n) >= 0)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getDigestSize() {
|
||||||
|
switch(rng.nextInt(5)) {
|
||||||
|
case 0: return 1;
|
||||||
|
case 1: return 224;
|
||||||
|
case 2: return 256;
|
||||||
|
case 3: return 384;
|
||||||
|
case 4: return 512;
|
||||||
|
default:
|
||||||
|
return 999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Digest getHash(int nsize) {
|
||||||
|
switch(nsize) {
|
||||||
|
case 1: return new SHA1Digest();
|
||||||
|
case 224: return new SHA1Digest();
|
||||||
|
case 256: return new SHA1Digest();
|
||||||
|
case 384: return new SHA1Digest();
|
||||||
|
case 512: return new SHA1Digest();
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String asHex(byte[] data) {
|
||||||
|
String result = "";
|
||||||
|
for(byte value : data) {
|
||||||
|
result = result + String.format("%02x", value);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
17500
tests/ecdsa/ec_add.test
Normal file
17500
tests/ecdsa/ec_add.test
Normal file
File diff suppressed because it is too large
Load Diff
22500
tests/ecdsa/ec_add2mul.test
Normal file
22500
tests/ecdsa/ec_add2mul.test
Normal file
File diff suppressed because it is too large
Load Diff
12500
tests/ecdsa/ec_dble.test
Normal file
12500
tests/ecdsa/ec_dble.test
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/ecdsa/ec_mul.test
Normal file
15000
tests/ecdsa/ec_mul.test
Normal file
File diff suppressed because it is too large
Load Diff
12500
tests/ecdsa/ec_negate.test
Normal file
12500
tests/ecdsa/ec_negate.test
Normal file
File diff suppressed because it is too large
Load Diff
20000
tests/ecdsa/signature.test
Normal file
20000
tests/ecdsa/signature.test
Normal file
File diff suppressed because it is too large
Load Diff
216
tests/math/GenerateMathTests.hs
Normal file
216
tests/math/GenerateMathTests.hs
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
import Control.Monad
|
||||||
|
import Data.Bits
|
||||||
|
import Data.List
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
import GHC.Integer.GMP.Internals
|
||||||
|
import Numeric
|
||||||
|
import System.IO
|
||||||
|
import System.Random
|
||||||
|
import Debug.Trace
|
||||||
|
|
||||||
|
type Generator a = StdGen -> a -> (Maybe [(String, Integer)], a, StdGen)
|
||||||
|
|
||||||
|
iterations :: Int
|
||||||
|
iterations = 5000
|
||||||
|
|
||||||
|
maxSize :: Int
|
||||||
|
maxSize = 8
|
||||||
|
|
||||||
|
randomVal :: (Integer -> Bool) -> StdGen -> (Integer, StdGen)
|
||||||
|
randomVal filter g =
|
||||||
|
let (mySize, g') = randomR (1, maxSize) g
|
||||||
|
(possible, g'') = go g' mySize
|
||||||
|
in if filter possible
|
||||||
|
then (possible, g'')
|
||||||
|
else randomVal filter g''
|
||||||
|
where
|
||||||
|
go rng 0 = (0, rng)
|
||||||
|
go rng i =
|
||||||
|
let (other, rng') = go rng (i - 1)
|
||||||
|
(self, rng'') = random rng'
|
||||||
|
in ((other `shiftL` 64) + self, rng'')
|
||||||
|
|
||||||
|
buildBasicGenerator :: (Integer -> Bool) ->
|
||||||
|
(Integer -> Integer -> Maybe Integer) ->
|
||||||
|
Generator ()
|
||||||
|
buildBasicGenerator filter f g () =
|
||||||
|
let (x, g') = randomVal filter g
|
||||||
|
(y, g'') = randomVal filter g'
|
||||||
|
in case f x y of
|
||||||
|
Nothing ->
|
||||||
|
(Nothing, (), g'')
|
||||||
|
Just z ->
|
||||||
|
(Just [("x", x), ("y", y), ("z", z)], (), g'')
|
||||||
|
|
||||||
|
buildBasicLimitingGenerator :: (Integer -> Bool) ->
|
||||||
|
(Integer -> Integer -> Maybe Integer) ->
|
||||||
|
Generator (Map.Map Integer Int)
|
||||||
|
buildBasicLimitingGenerator filter f g m =
|
||||||
|
let (x, g') = randomVal filter g
|
||||||
|
(y, g'') = randomVal filter g'
|
||||||
|
in case f x y of
|
||||||
|
Nothing -> (Nothing, m, g'')
|
||||||
|
Just z ->
|
||||||
|
case Map.lookup z m of
|
||||||
|
Nothing ->
|
||||||
|
(Just [("x",x),("y",y),("z",z)], Map.insert z 1 m, g'')
|
||||||
|
Just c | c >= 100 ->
|
||||||
|
(Nothing, m, g'')
|
||||||
|
Just c ->
|
||||||
|
(Just [("x",x),("y",y),("z",z)], Map.insert z (c + 1) m, g'')
|
||||||
|
|
||||||
|
buildBasicAccGenerator :: (Integer -> Bool) ->
|
||||||
|
(Integer -> Integer -> a -> Maybe (Integer, a)) ->
|
||||||
|
Generator a
|
||||||
|
buildBasicAccGenerator filter f g acc =
|
||||||
|
let (x, g') = randomVal filter g
|
||||||
|
(y, g'') = randomVal filter g'
|
||||||
|
in case f x y acc of
|
||||||
|
Nothing ->
|
||||||
|
(Nothing, acc, g'')
|
||||||
|
Just (z, acc') ->
|
||||||
|
(Just [("x", x), ("y", y), ("z", z)], acc', g'')
|
||||||
|
|
||||||
|
runGenerator :: forall a. StdGen -> String -> a -> Generator a -> IO StdGen
|
||||||
|
runGenerator g filename initVal generator =
|
||||||
|
withFile (filename ++ ".tests") WriteMode $ \ hndl ->
|
||||||
|
do putStrLn ("Generating " ++ filename ++ ".tests")
|
||||||
|
go hndl g initVal iterations
|
||||||
|
where
|
||||||
|
go :: Handle -> StdGen -> a -> Int -> IO StdGen
|
||||||
|
go _ g _ 0 = return g
|
||||||
|
go hndl g acc iterations =
|
||||||
|
case generator g acc of
|
||||||
|
(Nothing, acc', g') ->
|
||||||
|
go hndl g' acc' iterations
|
||||||
|
(Just res, acc', g') ->
|
||||||
|
do let sorted = sort res
|
||||||
|
forM_ sorted $ \ (key, val) ->
|
||||||
|
do let neg = if val < 0 then "-" else ""
|
||||||
|
val' = abs val
|
||||||
|
hPutStrLn hndl (key ++ ": " ++ neg ++ showHex val' "")
|
||||||
|
go hndl g' acc' (iterations - 1)
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main =
|
||||||
|
do g0 <- newStdGen
|
||||||
|
g1 <- runGenerator g0 "unsigned_add" () $
|
||||||
|
buildBasicGenerator (>= 0) $ \ a b -> Just (a + b)
|
||||||
|
g2 <- runGenerator g1 "signed_add" () $
|
||||||
|
buildBasicGenerator (const True) $ \ a b -> Just (a + b)
|
||||||
|
g3 <- runGenerator g2 "unsigned_sub" () $
|
||||||
|
buildBasicGenerator (>= 0) $ \ a b ->
|
||||||
|
if a >= b then Just (a - b) else Nothing
|
||||||
|
g4 <- runGenerator g3 "signed_sub" () $
|
||||||
|
buildBasicGenerator (const True) $ \ a b -> Just (a - b)
|
||||||
|
g5 <- runGenerator g4 "unsigned_mul" () $
|
||||||
|
buildBasicGenerator (>= 0) $ \ a b -> Just (a * b)
|
||||||
|
g6 <- runGenerator g5 "signed_mul" () $
|
||||||
|
buildBasicGenerator (const True) $ \ a b -> Just (a * b)
|
||||||
|
g7 <- runGenerator g6 "unsigned_div" Map.empty $
|
||||||
|
buildBasicLimitingGenerator (>= 0) $ \ a b ->
|
||||||
|
if b == 0 then Nothing else Just (a `div` b)
|
||||||
|
g8 <- runGenerator g7 "signed_div" Map.empty $
|
||||||
|
buildBasicLimitingGenerator (const True) $ \ a b ->
|
||||||
|
if b == 0 then Nothing else Just (a `div` b)
|
||||||
|
g7 <- runGenerator g6 "unsigned_mod" 0 $
|
||||||
|
buildBasicAccGenerator (>= 0) $ \ a b i ->
|
||||||
|
case a `mod` b of
|
||||||
|
_ | b == 0 -> Nothing
|
||||||
|
x | (a == x) && (i == 100) -> Nothing
|
||||||
|
x | a == x -> Just (x, i + 1)
|
||||||
|
x -> Just (x, i)
|
||||||
|
g8 <- runGenerator g7 "signed_mod" 0 $
|
||||||
|
buildBasicAccGenerator (const True) $ \ a b i ->
|
||||||
|
case a `mod` b of
|
||||||
|
_ | b == 0 -> Nothing
|
||||||
|
x | (a == x) && (i == 100) -> Nothing
|
||||||
|
x | a == x -> Just (x, i + 1)
|
||||||
|
x -> Just (x, i)
|
||||||
|
g9 <- runGenerator g8 "modexp" () $ \ g () ->
|
||||||
|
let (a, g') = randomVal (>= 0) g
|
||||||
|
(b, g'') = randomVal (>= 0) g'
|
||||||
|
(m, g''') = randomVal (>= 0) g''
|
||||||
|
z = powModInteger a b m
|
||||||
|
res = [("a",a),("b",b),("m",m),("z",z)]
|
||||||
|
in if m == 0
|
||||||
|
then (Nothing, (), g''')
|
||||||
|
else (Just res, (), g''')
|
||||||
|
g10<- runGenerator g9 "barrett" () $ \ g () ->
|
||||||
|
let (m, g') = randomVal (>= 0) g
|
||||||
|
(v, g'') = randomVal (>= 0) g'
|
||||||
|
barrett = barrett_u m
|
||||||
|
vk = computeK v
|
||||||
|
in if vk > (2 * (bk barrett))
|
||||||
|
then (Nothing, (), g'')
|
||||||
|
else let me = reduce v barrett
|
||||||
|
standard = v `mod` m
|
||||||
|
res = [("m", m), ("v", v), ("r", me),
|
||||||
|
("u", bu barrett), ("k", fromIntegral (bk barrett))]
|
||||||
|
in if me /= standard
|
||||||
|
then error "Barrett broken"
|
||||||
|
else (Just res, (), g'')
|
||||||
|
g11<- runGenerator g10 "fastmodexp" () $ \ g () ->
|
||||||
|
let (a, g') = randomVal (>= 0) g
|
||||||
|
(b, g'') = randomVal (>= 0) g'
|
||||||
|
(m, g''') = randomVal (>= 0) g'
|
||||||
|
z = powModInteger a b m
|
||||||
|
barrett = barrett_u m
|
||||||
|
ak = computeK a
|
||||||
|
in if ak > bk barrett
|
||||||
|
then (Nothing, (), g''')
|
||||||
|
else let res = [("a", a), ("b", b), ("z", z),
|
||||||
|
("m", m), ("u", bu barrett),
|
||||||
|
("k", fromIntegral (bk barrett))]
|
||||||
|
in (Just res, (), g''')
|
||||||
|
_ <- runGenerator g11 "modinv" Map.empty $
|
||||||
|
buildBasicLimitingGenerator (>= 0) $ \ a b ->
|
||||||
|
let res == recipModInteger a b
|
||||||
|
if b == 0 then Nothing else Just (recipModInteger a b)
|
||||||
|
return ()
|
||||||
|
|
||||||
|
-- Implement Barrett reduction using incredibly simplistic implementations, to
|
||||||
|
-- be sure we got it right.
|
||||||
|
--
|
||||||
|
b :: Integer
|
||||||
|
b = 2 ^ 64
|
||||||
|
|
||||||
|
computeK :: Integer -> Int
|
||||||
|
computeK v = go 0 1
|
||||||
|
where
|
||||||
|
go k acc
|
||||||
|
| v < acc = k
|
||||||
|
| otherwise = go (k + 1) (acc * b)
|
||||||
|
|
||||||
|
data Barrett = Barrett { bm :: Integer, bu :: Integer, bk :: Int }
|
||||||
|
deriving (Show)
|
||||||
|
|
||||||
|
barrett_u :: Integer -> Barrett
|
||||||
|
barrett_u x = Barrett {
|
||||||
|
bm = x,
|
||||||
|
bu = (b ^ (2 * k)) `div` x,
|
||||||
|
bk = k
|
||||||
|
}
|
||||||
|
where k = computeK x
|
||||||
|
|
||||||
|
reduce :: Integer -> Barrett -> Integer
|
||||||
|
reduce x barrett = result
|
||||||
|
where
|
||||||
|
k = bk barrett
|
||||||
|
u = bu barrett
|
||||||
|
m = bm barrett
|
||||||
|
--
|
||||||
|
q1 = x `div` (b ^ (k - 1))
|
||||||
|
q2 = q1 * u
|
||||||
|
q3 = q2 `div` (b ^ (k + 1))
|
||||||
|
r1 = x `mod` (b ^ (k + 1))
|
||||||
|
r2 = (q3 * m) `mod` (b ^ (k + 1))
|
||||||
|
r = r1 - r2
|
||||||
|
r' = if r < 0 then r + (b ^ (k + 1)) else r
|
||||||
|
result = minimize r' m
|
||||||
|
|
||||||
|
minimize :: Integer -> Integer -> Integer
|
||||||
|
minimize r m | r < 0 = error "BLECH"
|
||||||
|
| r >= m = minimize (r - m) m
|
||||||
|
| otherwise = r
|
||||||
25000
tests/math/barrett.tests
Normal file
25000
tests/math/barrett.tests
Normal file
File diff suppressed because it is too large
Load Diff
30000
tests/math/fastmodexp.tests
Normal file
30000
tests/math/fastmodexp.tests
Normal file
File diff suppressed because it is too large
Load Diff
20000
tests/math/modexp.tests
Normal file
20000
tests/math/modexp.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/modinv.tests
Normal file
15000
tests/math/modinv.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_add.tests
Normal file
15000
tests/math/signed_add.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_div.tests
Normal file
15000
tests/math/signed_div.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_mod.tests
Normal file
15000
tests/math/signed_mod.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_mul.tests
Normal file
15000
tests/math/signed_mul.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_sub.tests
Normal file
15000
tests/math/signed_sub.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_add.tests
Normal file
15000
tests/math/unsigned_add.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_div.tests
Normal file
15000
tests/math/unsigned_div.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_mod.tests
Normal file
15000
tests/math/unsigned_mod.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_mul.tests
Normal file
15000
tests/math/unsigned_mul.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_sub.tests
Normal file
15000
tests/math/unsigned_sub.tests
Normal file
File diff suppressed because it is too large
Load Diff
214
tests/rsa/GenerateRSATests.hs
Normal file
214
tests/rsa/GenerateRSATests.hs
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
import Control.Monad
|
||||||
|
import Codec.Crypto.RSA.Pure
|
||||||
|
import Control.Concurrent
|
||||||
|
import Crypto.Random.DRBG
|
||||||
|
import Data.Bits
|
||||||
|
import qualified Data.ByteString as BS
|
||||||
|
import qualified Data.ByteString.Char8 as BSC
|
||||||
|
import qualified Data.ByteString.Lazy as BSL
|
||||||
|
import Data.Char
|
||||||
|
import Data.List
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
import GHC.Integer.GMP.Internals
|
||||||
|
import Numeric
|
||||||
|
import System.IO
|
||||||
|
import System.ProgressBar
|
||||||
|
import System.Random
|
||||||
|
import Debug.Trace
|
||||||
|
|
||||||
|
keySizes :: [Int]
|
||||||
|
keySizes = [512,1024,2048,3072,4096,7680,8192,15360]
|
||||||
|
|
||||||
|
keyIterations :: [Int]
|
||||||
|
keyIterations = replicate 500 512 ++
|
||||||
|
replicate 500 1024 ++
|
||||||
|
replicate 250 2048 ++
|
||||||
|
replicate 125 3072 ++
|
||||||
|
replicate 50 4096 ++
|
||||||
|
replicate 5 7680 ++
|
||||||
|
replicate 2 8192 ++
|
||||||
|
replicate 1 15360
|
||||||
|
|
||||||
|
randomByteString :: CryptoRandomGen g => g -> (BS.ByteString, g)
|
||||||
|
randomByteString g =
|
||||||
|
let Right (bs, g') = genBytes 2 g
|
||||||
|
[h,l] = BS.unpack bs
|
||||||
|
x = (fromIntegral h `shiftL` 8) + (fromIntegral l)
|
||||||
|
Right (res, g'') = genBytes (x `mod` 1024) g'
|
||||||
|
in (res, g'')
|
||||||
|
|
||||||
|
randomLabel :: CryptoRandomGen g => g -> (BS.ByteString, g)
|
||||||
|
randomLabel g =
|
||||||
|
let Right (ls, g') = genBytes 1 g
|
||||||
|
[l8] = BS.unpack ls
|
||||||
|
(letters, g'') = go g' (l8 `mod` 24)
|
||||||
|
in (BSC.pack letters, g'')
|
||||||
|
where
|
||||||
|
goodChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++
|
||||||
|
"abcdefghijklmnopqrstuvwxyz" ++
|
||||||
|
"0123456789 .,/?'\";:[{]}\\|-_=+" ++
|
||||||
|
"`~!@#$%^&*()"
|
||||||
|
lenGoods = fromIntegral (length goodChars)
|
||||||
|
--
|
||||||
|
go g 0 = ("", g)
|
||||||
|
go g x =
|
||||||
|
let Right (bs, g') = genBytes 1 g
|
||||||
|
[x] = BS.unpack bs
|
||||||
|
idx = fromIntegral (x `mod` lenGoods)
|
||||||
|
(rest, g'') = go g' (x - 1)
|
||||||
|
in ((goodChars !! idx) : rest, g'')
|
||||||
|
|
||||||
|
randomHash :: CryptoRandomGen g => g -> ((HashInfo, String), g)
|
||||||
|
randomHash g =
|
||||||
|
randomElement g [(hashSHA1, "1"),
|
||||||
|
(hashSHA224, "224"),
|
||||||
|
(hashSHA256, "256"),
|
||||||
|
(hashSHA384, "384"),
|
||||||
|
(hashSHA512, "512")]
|
||||||
|
|
||||||
|
showBinary :: BS.ByteString -> String
|
||||||
|
showBinary v = go v
|
||||||
|
where
|
||||||
|
go bstr =
|
||||||
|
case BS.uncons bstr of
|
||||||
|
Nothing ->
|
||||||
|
""
|
||||||
|
Just (x, rest) ->
|
||||||
|
let high = showHex (x `shiftR` 4) ""
|
||||||
|
low = showHex (x .&. 0xF) ""
|
||||||
|
in high ++ low ++ go rest
|
||||||
|
|
||||||
|
dump :: Handle -> [(String,String)] -> IO ()
|
||||||
|
dump hndl = mapM_ writeItem
|
||||||
|
where
|
||||||
|
writeItem (name, value) =
|
||||||
|
do hPutStr hndl name
|
||||||
|
hPutStr hndl ": "
|
||||||
|
hPutStrLn hndl value
|
||||||
|
|
||||||
|
mkProgress x y = Progress (fromIntegral x) (fromIntegral y)
|
||||||
|
|
||||||
|
runSignatureGenerator :: Chan Int -> Chan [(String,String)] -> IO ()
|
||||||
|
runSignatureGenerator inputs outputs =
|
||||||
|
do rng0 :: GenBuffered SystemRandom <- newGenIO
|
||||||
|
go Nothing rng0
|
||||||
|
where
|
||||||
|
go Nothing rng0 =
|
||||||
|
do keySize <- readChan inputs
|
||||||
|
go (Just keySize) rng0
|
||||||
|
go (Just keySize) g0 =
|
||||||
|
do unless (keySize `elem` keySizes) $
|
||||||
|
fail ("Bad key size: " ++ show keySize)
|
||||||
|
let Right (public, private, g1) = generateKeyPair g0 keySize
|
||||||
|
unless (private_d private `shiftR` keySize == 0) $
|
||||||
|
fail ("Bad private key size.")
|
||||||
|
unless (public_n public `shiftR` keySize == 0) $
|
||||||
|
fail ("Bad private key size.")
|
||||||
|
let (message, g2) = randomByteString g1
|
||||||
|
let ((hash, hashname), g3) = randomHash g2
|
||||||
|
case rsassa_pkcs1_v1_5_sign hash private (BSL.fromStrict message) of
|
||||||
|
Left _ ->
|
||||||
|
go (Just keySize) g3
|
||||||
|
Right sig ->
|
||||||
|
case rsassa_pkcs1_v1_5_verify hash public (BSL.fromStrict message) sig of
|
||||||
|
Left err ->
|
||||||
|
fail ("RSA Verification error: " ++ show err)
|
||||||
|
Right False ->
|
||||||
|
fail ("RSA verification failed?!")
|
||||||
|
Right True ->
|
||||||
|
do writeChan outputs [("d", showHex (private_d private) ""),
|
||||||
|
("n", showHex (public_n public) ""),
|
||||||
|
("h", hashname),
|
||||||
|
("k", showHex keySize ""),
|
||||||
|
("l", showHex (BS.length message) ""),
|
||||||
|
("m", showBinary message),
|
||||||
|
("s", showBinary (BSL.toStrict sig))]
|
||||||
|
go Nothing g3
|
||||||
|
|
||||||
|
runEncryptionGenerator :: Chan Int -> Chan [(String,String)] -> IO ()
|
||||||
|
runEncryptionGenerator inputs outputs =
|
||||||
|
do rng0 :: GenBuffered SystemRandom <- newGenIO
|
||||||
|
go Nothing rng0
|
||||||
|
where
|
||||||
|
go Nothing rng0 =
|
||||||
|
do keySize <- readChan inputs
|
||||||
|
go (Just keySize) rng0
|
||||||
|
go (Just keySize) g0 =
|
||||||
|
do unless (keySize `elem` keySizes) $
|
||||||
|
fail ("Bad key size: " ++ show keySize)
|
||||||
|
let Right (public, private, g1) = generateKeyPair g0 keySize
|
||||||
|
let (message, g2) = randomByteString g1
|
||||||
|
let (label, g3) = randomLabel g2
|
||||||
|
let ((hashinfo, hashname), g4) = randomHash g3
|
||||||
|
let hash = hashFunction hashinfo
|
||||||
|
let mgf1 = generateMGF1 hash
|
||||||
|
let msg = BSL.fromStrict message
|
||||||
|
lbl = BSL.fromStrict label
|
||||||
|
case encryptOAEP g4 hash mgf1 lbl public msg of
|
||||||
|
Left _ ->
|
||||||
|
go (Just keySize) g4
|
||||||
|
Right (c, g5) ->
|
||||||
|
do writeChan outputs [("d", showHex (private_d private) ""),
|
||||||
|
("n", showHex (public_n public) ""),
|
||||||
|
("h", hashname),
|
||||||
|
("l", showBinary label),
|
||||||
|
("m", showBinary message),
|
||||||
|
("c", showBinary (BSL.toStrict c))]
|
||||||
|
go Nothing g5
|
||||||
|
|
||||||
|
writeData :: Chan [(String,String)] -> Int -> (Progress -> IO ()) ->
|
||||||
|
Handle ->
|
||||||
|
IO ()
|
||||||
|
writeData outputChan countInt progressBar hndl = go 0
|
||||||
|
where
|
||||||
|
count = fromIntegral countInt
|
||||||
|
go x | x == count = return ()
|
||||||
|
| otherwise = do output <- readChan outputChan
|
||||||
|
dump hndl output
|
||||||
|
hFlush hndl
|
||||||
|
progressBar (Progress (x + 1) count)
|
||||||
|
go (x + 1)
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main =
|
||||||
|
do sizeChan <- newChan
|
||||||
|
outputChan <- newChan
|
||||||
|
let count = length keyIterations
|
||||||
|
numThreads <- getNumCapabilities
|
||||||
|
--
|
||||||
|
unless (all (`elem` keySizes) keyIterations) $
|
||||||
|
fail "System setup failure."
|
||||||
|
--
|
||||||
|
sigthrs <- replicateM numThreads $
|
||||||
|
forkIO $ runSignatureGenerator sizeChan outputChan
|
||||||
|
let bar = autoProgressBar (msg "Generating signature tests") percentage 60
|
||||||
|
writeList2Chan sizeChan keyIterations
|
||||||
|
g1 <- withFile "signature.test" WriteMode $
|
||||||
|
writeData outputChan count bar
|
||||||
|
mapM_ killThread sigthrs
|
||||||
|
--
|
||||||
|
encthrs <- replicateM numThreads $
|
||||||
|
forkIO $ runEncryptionGenerator sizeChan outputChan
|
||||||
|
let bar = autoProgressBar (msg "Generating encryption tests") percentage 60
|
||||||
|
writeList2Chan sizeChan (take 1000 keyIterations)
|
||||||
|
g2 <- withFile "encryption.test" WriteMode $
|
||||||
|
writeData outputChan 1000 bar
|
||||||
|
mapM_ killThread encthrs
|
||||||
|
--
|
||||||
|
replicateM_ numThreads $
|
||||||
|
void $ forkIO $ runEncryptionGenerator sizeChan outputChan
|
||||||
|
let bar = autoProgressBar (msg "Generating encryption tests") percentage 60
|
||||||
|
writeList2Chan sizeChan (drop 1000 keyIterations)
|
||||||
|
let i = length keyIterations - 1
|
||||||
|
g2 <- withFile "encryption.ext.test" WriteMode $
|
||||||
|
writeData outputChan (count - 1000) bar
|
||||||
|
--
|
||||||
|
return ()
|
||||||
|
|
||||||
|
randomElement :: CryptoRandomGen g => g -> [a] -> (a, g)
|
||||||
|
randomElement g xs =
|
||||||
|
let Right (bs, g') = genBytes 1 g
|
||||||
|
x = BS.head bs
|
||||||
|
idx = fromIntegral x `mod` length xs
|
||||||
|
in (xs !! idx, g')
|
||||||
2598
tests/rsa/encryption.ext.test
Normal file
2598
tests/rsa/encryption.ext.test
Normal file
File diff suppressed because it is too large
Load Diff
6000
tests/rsa/encryption.test
Normal file
6000
tests/rsa/encryption.test
Normal file
File diff suppressed because one or more lines are too long
10031
tests/rsa/signature.test
Normal file
10031
tests/rsa/signature.test
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user