Skip to content
This repository has been archived by the owner on Jun 8, 2020. It is now read-only.

Commit

Permalink
Merge pull request #118 from jovfer/feature/rc_0_4_2
Browse files Browse the repository at this point in the history
RC 0.4.2
  • Loading branch information
Vyacheslav authored Jul 23, 2018
2 parents 870e7be + 5f3d18b commit d04d8f4
Show file tree
Hide file tree
Showing 24 changed files with 4,478 additions and 2,433 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
0.4.2
- BLS: verification optimization
- Rust API enhancements (add more Clone derives for structures)
- CL: update link-secrets logic - allow to use multiply link-secrets as non-schema attributes

Note:
This version of Indy Crypto can process artifacts from previous one.
But in reason of multiply link-secrets support older versions can't consume CL output of 0.4.2.

0.4.1
- Bugfix: correct format of KeyCorrectness proof JSON representation

Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ If you haven't done so already, please visit the main resource for all things "I

# Indy Crypto

This is the shared crypto libirary for [Hyperledger Indy](https://www.hyperledger.org/projects) components.
This is the shared crypto library for [Hyperledger Indy](https://www.hyperledger.org/projects) components.

[Hyperledger Indy](https://www.hyperledger.org/projects) provides a distributed-ledger-based foundation for [self-sovereign identity](https://sovrin.org).

Expand Down Expand Up @@ -34,6 +34,10 @@ us on [Jira's Rocket.Chat](chat.hyperledger.org) at #indy-sdk to discuss.
cd libindy-crypto
cargo test
```
**Note:**
By default `cargo build` produce debug artifacts with a large amount of run-time checks.
It's good for development, but this build can be in 100+ times slower for some math calculation.
If you would like to analyse CPU performance of libindy-crypto for your use case, you have to use release artifacts (`cargo build --release`).

### Windows build dependency
System OpenSSL library is required.
Expand Down
4 changes: 2 additions & 2 deletions libindy-crypto/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[package]
name = "indy-crypto"
version = "0.4.1"
version = "0.4.2"
authors = ["Artemkaaas <[email protected]>"]
description = "This is the shared crypto libirary for Hyperledger Indy components."
description = "This is the shared crypto library for Hyperledger Indy components."
license = "MIT/Apache-2.0"

[lib]
Expand Down
8 changes: 6 additions & 2 deletions libindy-crypto/debian/changelog
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
libindy-crypto (0.4.1) unstable; urgency=medium

[ Indy Crypto ]
* Anoncreds API refactoring for better revocation support
* Bugfix: correct format of KeyCorrectness proof JSON representation
* BLS: verification optimization
* Rust API enhancements (add more Clone derives for structures)
* CL: update link-secrets logic - allow to use multiply link-secrets as non-schema attributes
Note:
This version of Indy Crypto can process artifacts from previous one.
But in reason of multiply link-secrets support older versions can't consume CL output of 0.4.2.

-- Hyperledger <[email protected]> Tue, 12 Sep 2017 19:19:00 +0300
Binary file modified libindy-crypto/docs/AnonCred.pdf
Binary file not shown.
23 changes: 14 additions & 9 deletions libindy-crypto/src/bls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl SignKey {
}

/// BLS verification key.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct VerKey {
point: PointG2,
bytes: Vec<u8>
Expand Down Expand Up @@ -379,18 +379,23 @@ impl Bls {
/// assert!(valid)
/// ```
pub fn verify_multi_sig(multi_sig: &MultiSignature, message: &[u8], ver_keys: &[&VerKey], gen: &Generator) -> Result<bool, IndyCryptoError> {
let mut multi_sig_e_list: Vec<Pair> = Vec::new();
// Since each signer (identified by a Verkey) has signed the same message, the public keys
// can be added together to form the aggregated verkey
let mut aggregated_verkey = PointG2::new_inf()?;
for ver_key in ver_keys {
let h = Bls::_hash(message)?;
multi_sig_e_list.push(Pair::pair(&h, &ver_key.point)?);
aggregated_verkey = aggregated_verkey.add(&ver_key.point)?;
}

let mut multi_sig_e = multi_sig_e_list.get(0).ok_or(IndyCryptoError::InvalidStructure(format!("Element not found")))?.clone();
for e in multi_sig_e_list[1..].to_vec() {
multi_sig_e = multi_sig_e.mul(&e)?;
}
// TODO: Add a new method that takes a message and an aggregated verkey and expose using
// the C API. Verifiers can thus cache the aggregated verkey and avoid several EC point additions.
// The code below should be moved to such method.

let msg_hash = Bls::_hash(message)?;

let lhs = Pair::pair(&multi_sig.point, &gen.point)?;
let rhs = Pair::pair(&msg_hash, &aggregated_verkey)?;

Ok(Pair::pair(&multi_sig.point, &gen.point)?.eq(&multi_sig_e))
Ok(lhs.eq(&rhs))
}

fn _hash(message: &[u8]) -> Result<PointG1, IndyCryptoError> {
Expand Down
214 changes: 202 additions & 12 deletions libindy-crypto/src/bn/openssl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,28 @@ impl BigNumber {
}
}

pub fn is_safe_prime(&self, ctx: Option<&mut BigNumberContext>) -> Result<bool, IndyCryptoError> {

match ctx {
Some(c) => {
// according to https://eprint.iacr.org/2003/186.pdf
// a safe prime is congruent to 2 mod 3

// a safe prime satisfies (p-1)/2 is prime. Since a
// prime is odd, We just need to divide by 2
Ok(
self.modulus(&BigNumber::from_u32(3)?, Some(c))? == BigNumber::from_u32(2)? &&
self.is_prime(Some(c))? &&
self.rshift1()?.is_prime(Some(c))?
)
},
None => {
let mut context = BigNumber::new_context()?;
self.is_safe_prime(Some(&mut context))
}
}
}

pub fn rand(size: usize) -> Result<BigNumber, IndyCryptoError> {
let mut bn = BigNumber::new()?;
BigNumRef::rand(&mut bn.openssl_bn, size as i32, MSB_MAYBE_ZERO, false)?;
Expand Down Expand Up @@ -249,14 +271,23 @@ impl BigNumber {
}

pub fn mod_exp(&self, a: &BigNumber, b: &BigNumber, ctx: Option<&mut BigNumberContext>) -> Result<BigNumber, IndyCryptoError> {
let mut bn = BigNumber::new()?;
match ctx {
Some(context) => BigNumRef::mod_exp(&mut bn.openssl_bn, &self.openssl_bn, &a.openssl_bn, &b.openssl_bn, &mut context.openssl_bn_context)?,
Some(context) => self._mod_exp(a, b, context),
None => {
let mut ctx = BigNumber::new_context()?;
BigNumRef::mod_exp(&mut bn.openssl_bn, &self.openssl_bn, &a.openssl_bn, &b.openssl_bn, &mut ctx.openssl_bn_context)?;
self._mod_exp(a, b, &mut ctx)
}
}
}

fn _mod_exp(&self, a: &BigNumber, b: &BigNumber, ctx: &mut BigNumberContext) -> Result<BigNumber, IndyCryptoError> {
let mut bn = BigNumber::new()?;

if a.openssl_bn.is_negative() {
BigNumRef::mod_exp(&mut bn.openssl_bn, &self.inverse(b, Some(ctx))?.openssl_bn, &a.set_negative(false)?.openssl_bn, &b.openssl_bn, &mut ctx.openssl_bn_context)?;
} else {
BigNumRef::mod_exp(&mut bn.openssl_bn, &self.openssl_bn, &a.openssl_bn, &b.openssl_bn, &mut ctx.openssl_bn_context)?;
};
Ok(bn)
}

Expand Down Expand Up @@ -296,16 +327,78 @@ impl BigNumber {
Ok(bn)
}

pub fn mod_div(&self, b: &BigNumber, p: &BigNumber) -> Result<BigNumber, IndyCryptoError> {
//(a* (1/b mod p) mod p)
pub fn set_negative(&self, negative: bool) -> Result<BigNumber, IndyCryptoError> {
let mut bn = BigNum::from_slice(&self.openssl_bn.to_vec())?;
bn.set_negative(negative);
Ok(BigNumber {
openssl_bn: bn
})
}

let mut context = BigNumber::new_context()?;
pub fn is_negative(&self) -> bool {
self.openssl_bn.is_negative()
}

let res = b
.inverse(p, Some(&mut context))?
.mul(&self, Some(&mut context))?
.modulus(&p, Some(&mut context))?;
Ok(res)
pub fn increment(&self) -> Result<BigNumber, IndyCryptoError> {
let mut bn = BigNum::from_slice(&self.openssl_bn.to_vec())?;
bn.add_word(1)?;
Ok(BigNumber {
openssl_bn: bn
})
}

pub fn decrement(&self) -> Result<BigNumber, IndyCryptoError> {
let mut bn = BigNum::from_slice(&self.openssl_bn.to_vec())?;
bn.sub_word(1)?;
Ok(BigNumber {
openssl_bn: bn
})
}

pub fn lshift1(&self) -> Result<BigNumber, IndyCryptoError> {
let mut bn = BigNumber::new()?;
BigNumRef::lshift1(&mut bn.openssl_bn, &self.openssl_bn)?;
Ok(bn)
}

pub fn rshift1(&self) -> Result<BigNumber, IndyCryptoError> {
let mut bn = BigNumber::new()?;
BigNumRef::rshift1(&mut bn.openssl_bn, &self.openssl_bn)?;
Ok(bn)
}

pub fn rshift(&self, n: i32) -> Result<BigNumber, IndyCryptoError> {
let mut bn = BigNumber::new()?;
BigNumRef::rshift(&mut bn.openssl_bn, &self.openssl_bn, n)?;
Ok(bn)
}

pub fn mod_div(&self, b: &BigNumber, p: &BigNumber, ctx: Option<&mut BigNumberContext>) -> Result<BigNumber, IndyCryptoError> {
//(a * (1/b mod p) mod p)
match ctx {
Some(mut context) => self._mod_div(b, p, &mut context),
None => {
let mut context = BigNumber::new_context()?;
self._mod_div(b, p, &mut context)
}
}
}

///(a * (1/b mod p) mod p)
fn _mod_div(&self, b: &BigNumber, p: &BigNumber, ctx: &mut BigNumberContext)-> Result<BigNumber, IndyCryptoError> {
let mut bn = BigNumber::new()?;
BigNumRef::mod_mul(&mut bn.openssl_bn, &self.openssl_bn,
&b.inverse(p, Some(ctx))?.openssl_bn,
&p.openssl_bn, &mut ctx.openssl_bn_context)?;
Ok(bn)
}

pub fn random_qr(n: &BigNumber) -> Result<BigNumber, IndyCryptoError> {
let qr = n
.rand_range()?
.sqr(None)?
.modulus(&n, None)?;
Ok(qr)
}

pub fn clone(&self) -> Result<BigNumber, IndyCryptoError> {
Expand All @@ -327,7 +420,7 @@ impl BigNumber {

impl Ord for BigNumber {
fn cmp(&self, other: &BigNumber) -> Ordering {
self.openssl_bn.ucmp(&other.openssl_bn)
self.openssl_bn.cmp(&other.openssl_bn)
}
}

Expand Down Expand Up @@ -382,6 +475,12 @@ impl From<ErrorStack> for IndyCryptoError {
}
}

impl Default for BigNumber {
fn default() -> BigNumber {
BigNumber::from_u32(0).unwrap()
}
}

// Constants that are used throughout the code, so avoiding recomputation.
lazy_static! {
pub static ref BIGNUMBER_1: BigNumber = BigNumber::from_u32(1).unwrap();
Expand All @@ -407,6 +506,97 @@ mod tests {
assert!(end > random_prime);
}

#[test]
fn is_prime_works() {
let primes:Vec<u64> = vec![2, 23, 31, 42885908609, 24473809133, 47055833459];
for pr in primes {
let num = BigNumber::from_dec(&pr.to_string()).unwrap();
assert!(num.is_prime(None).unwrap());
}
let num = BigNumber::from_dec("36").unwrap();
assert!(!num.is_prime(None).unwrap());

let mut n128 = BigNumber::new().unwrap();
BigNumRef::generate_prime(&mut n128.openssl_bn, 128, false, None, None).unwrap();
assert!(n128.is_prime(None).unwrap());
let mut n256 = BigNumber::new().unwrap();
BigNumRef::generate_prime(&mut n256.openssl_bn, 256, false, None, None).unwrap();
assert!(n256.is_prime(None).unwrap());

let vec1 = vec![9, 252, 51, 8, 129]; // big endian representation of 42885908609
let v1 = BigNumber::from_bytes(&vec1).unwrap();
assert!(v1.is_prime(None).unwrap());
let vec2 = vec![129, 8, 51, 252, 9]; // little endian representation of 42885908609
let v2 = BigNumber::from_bytes(&vec2).unwrap();
assert!(!v2.is_prime(None).unwrap());
let vec3 = vec![1, 153, 25]; // big endian representation of 104729
let v3 = BigNumber::from_bytes(&vec3).unwrap();
assert!(v3.is_prime(None).unwrap());
}

#[test]
fn test_modular_exponentiation() {
let base = BigNumber::from_dec("12714671911903680502393098440562958150461307840092575886187217264492970515611166458444182780904860535776274190597528985988632488194981204988199325501696648896748368401254829974173258613724800116424602180755019588176641580062215499750550535543002990347313784260314641340394494547935943176226649412526659864646068220114536172189443925908781755710141006387091748541976715633668919725277837668568166444731358541327097786024076841158424402136565558677098853060675674958695935207345864359540948421232816012865873346545455513695413921957708811080877422273777355768568166638843699798663264533662595755767287970642902713301649").unwrap();
let exp = BigNumber::from_dec("13991423645225256679625502829143442357836305738777175327623021076136862973228390317258480888217725740262243618881809894688804251512223982403225288178492105393953431042196371492402144120299046493467608097411259757604892535967240041988260332063962457178993277482991886508015739613530825229685281072180891075265116698114782553748364913010741387964956740720544998915158970813171997488129859542399633104746793770216517872705889857552727967921847493285577238").unwrap();
let modulus = BigNumber::from_dec("991272771610724400277702356109350334773782112020672787325464582894874455338156617087078683660308327009158085342465983713825070967004447592080649030930737560915527173820649490032274245863850782844569456999473516497618489127293328524608584652323593452247534656999363158875176879817952982494174728640545484193154314433925648566686738628413929222467005197087738850212963801663981588243042912430590088435419451359859770426041670326127890520192033283832465411962274045956439947646966560440910244870464709982605844468449227905039953511431640780483761563845223213570597106855699997837768334871601402132694515676785338799407204529154456178837013845488372635042715003769626150545960460800980936426723680755798495767188398126674428244764038147226578038085253616108968402209263400729503458144370189359160926796812468410806201905992347006546335038212090539118675048292666041345556742530041533878341459110515497642054583635133581316796089099043782055893003258788369004899742992039315008110063759802733045648131896557338576682560236591353394201381103042167106112201578883917022695113857967398885475101031596068885337186646296664517159150904935112836318654117577507707562065113238913343761942585545093919444150946120523831367132144754209388110483749").unwrap();
let n = base.mod_exp(&exp, &modulus, None).unwrap();
assert_eq!(n, BigNumber::from_dec("156669382818249607878298589043381544147555658222157929549484054385620519150887267126359684884641035264854247223281407349108771361611707714806192334779156374961296686821846487267487447347213829476609283133961216115764596907219173912888367998704856300105745961091899745329082513615681466199188236178266479183520370119131067362815102553237342546358580424556049196548520326206809677290296313839918774603549816182657993044271509706055893922152644469350618465711055733369291523796837304622919600074130968607301641438272377350795631212741686475924538423333008944556761300787668873766797549942827958501053262330421256183088509761636226277739400954175538503984519144969688787730088704522060486181427528150632576628856946041322195818246199503927686629821338146828603690778689292695518745939007886131151503766930229761608131819298276772877945842806872426029069949874062579870088710097070526608376602732627661781899595747063793310401032556802468649888104062151213860356554306295111191704764944574687548637446778783560586599000631975868701382113259027374431129732911012887214749014288413818636520182416636289308770657630129067046301651835893708731812616847614495049523221056260334965662875649480493232265453415256612460815802528012166114764216881").unwrap());

let base = BigNumber::from_u32(6).unwrap();
let exp = BigNumber::from_u32(5).unwrap().set_negative(true).unwrap();
let modulus = BigNumber::from_u32(13).unwrap();
assert_eq!(BigNumber::from_u32(7).unwrap(), base.mod_exp(&exp, &modulus, None).unwrap());
}

#[test]
#[ignore]
fn is_safe_prime_works() {
let prime1 = BigNumber::generate_safe_prime(256).unwrap();
let prime2 = BigNumber::generate_safe_prime(1024).unwrap();
assert!(prime1.is_safe_prime(None).unwrap());
assert!(prime2.is_safe_prime(None).unwrap());
}

#[test]
#[ignore] //TODO Expensive test, only run to generate public params
fn is_safe_prime_works_for_large_prime() {
let prime = BigNumber::generate_safe_prime(4096).unwrap();
assert!(prime.is_safe_prime(None).unwrap());
}

#[test]
fn decrement_works() {
let num = BigNumber::from_u32(1000).unwrap();
assert_eq!(num.decrement().unwrap(), num.sub(&BIGNUMBER_1).unwrap());
}

#[test]
fn increment_works() {
let num = BigNumber::from_u32(1000).unwrap();
assert_eq!(num.increment().unwrap(), num.add(&BIGNUMBER_1).unwrap());
}

#[test]
fn rshift1_works() {
let num = BigNumber::from_u32(1000).unwrap();
assert_eq!(num.rshift1().unwrap(), BigNumber::from_u32(500).unwrap());
}

#[test]
fn rshift_works() {
let num = BigNumber::from_u32(1024).unwrap();
assert_eq!(num.rshift(1).unwrap(), BigNumber::from_u32(512).unwrap());
assert_eq!(num.rshift(2).unwrap(), BigNumber::from_u32(256).unwrap());
assert_eq!(num.rshift(3).unwrap(), BigNumber::from_u32(128).unwrap());
assert_eq!(num.rshift(4).unwrap(), BigNumber::from_u32(64).unwrap());
}

#[test]
fn lshift1_works() {
let num = BigNumber::from_u32(1000).unwrap();
assert_eq!(num.lshift1().unwrap(), BigNumber::from_u32(2000).unwrap());
}

#[cfg(feature = "serialization")]
#[derive(Serialize, Deserialize)]
struct Test {
Expand Down
1 change: 0 additions & 1 deletion libindy-crypto/src/cl/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pub const ITERATION: usize = 4;
Dmitry Khovratovich, suggests to use same size as LARGE_MVECT
FIXME sync the paper and remove this comment
*/
pub const LARGE_M1_TILDE: usize = LARGE_MVECT;
pub const LARGE_NONCE: usize = 80;
pub const LARGE_ALPHATILDE: usize = 2787;

Expand Down
Loading

0 comments on commit d04d8f4

Please sign in to comment.