diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml new file mode 100644 index 0000000..d3ed68f --- /dev/null +++ b/.github/workflows/clippy.yml @@ -0,0 +1,11 @@ +name: Clippy check +on: [push, pull_request] +jobs: + clippy_check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: rustup component add clippy + - uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/src/lib.rs b/src/lib.rs index c687c1c..e5c0074 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ +// BabyJubJub elliptic curve implementation in Rust. // For LICENSE check https://github.com/arnaucube/babyjubjub-rs -extern crate rand; -#[macro_use] extern crate ff; +extern crate rand; use ff::*; use poseidon_rs::Poseidon; @@ -16,14 +16,12 @@ extern crate num_bigint; extern crate num_traits; extern crate rand6; -use rand6::Rng; // use blake2::{Blake2b, Digest}; #[cfg(feature = "default")] extern crate blake_hash; // compatible version with Blake used at circomlib #[cfg(feature = "default")] -#[macro_use] use blake_hash::Digest; #[cfg(feature = "aarch64")] @@ -43,9 +41,9 @@ extern crate lazy_static; lazy_static! { static ref D: Fr = Fr::from_str("168696").unwrap(); - static ref D_big: BigInt = BigInt::parse_bytes(b"168696", 10).unwrap(); + static ref D_BIG: BigInt = BigInt::parse_bytes(b"168696", 10).unwrap(); static ref A: Fr = Fr::from_str("168700").unwrap(); - static ref A_big: BigInt = BigInt::parse_bytes(b"168700", 10).unwrap(); + static ref A_BIG: BigInt = BigInt::parse_bytes(b"168700", 10).unwrap(); pub static ref Q: BigInt = BigInt::parse_bytes( b"21888242871839275222246405745257275088548364400416034343698204186575808495617",10 ) @@ -72,7 +70,7 @@ lazy_static! { ) .unwrap() >> 3; - static ref poseidon: poseidon_rs::Poseidon = Poseidon::new(); + static ref POSEIDON: poseidon_rs::Poseidon = Poseidon::new(); } #[derive(Clone, Debug)] @@ -97,11 +95,10 @@ impl PointProjective { let mut y = self.y; y.mul_assign(&zinv); - Point { - x: x.clone(), - y: y.clone(), - } + Point { x, y } } + + #[allow(clippy::many_single_char_names)] pub fn add(&self, q: &PointProjective) -> PointProjective { // add-2008-bbjlp https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#doubling-dbl-2008-bbjlp let mut a = self.z; @@ -112,7 +109,7 @@ impl PointProjective { c.mul_assign(&q.x); let mut d = self.y; d.mul_assign(&q.y); - let mut e = D.clone(); + let mut e = *D; e.mul_assign(&c); e.mul_assign(&d); let mut f = b; @@ -130,7 +127,7 @@ impl PointProjective { let mut x3 = a; x3.mul_assign(&f); x3.mul_assign(&aux); - let mut ac = A.clone(); + let mut ac = *A; ac.mul_assign(&c); let mut dac = d; dac.sub_assign(&ac); @@ -141,9 +138,9 @@ impl PointProjective { z3.mul_assign(&g); PointProjective { - x: x3.clone(), - y: y3.clone(), - z: z3.clone(), + x: x3, + y: y3, + z: z3, } } } @@ -157,8 +154,8 @@ pub struct Point { impl Point { pub fn projective(&self) -> PointProjective { PointProjective { - x: self.x.clone(), - y: self.y.clone(), + x: self.x, + y: self.y, z: Fr::one(), } } @@ -188,8 +185,8 @@ impl Point { let (_, y_bytes) = y_big.to_bytes_le(); let len = min(y_bytes.len(), r.len()); r[..len].copy_from_slice(&y_bytes[..len]); - if &x_big > &(&Q.clone() >> 1) { - r[31] = r[31] | 0x80; + if x_big > (&Q.clone() >> 1) { + r[31] |= 0x80; } r } @@ -202,17 +199,17 @@ impl Point { } } -pub fn test_bit(b: &Vec, i: usize) -> bool { - return b[i / 8] & (1 << (i % 8)) != 0; +pub fn test_bit(b: &[u8], i: usize) -> bool { + b[i / 8] & (1 << (i % 8)) != 0 } pub fn decompress_point(bb: [u8; 32]) -> Result { // https://tools.ietf.org/html/rfc8032#section-5.2.3 let mut sign: bool = false; - let mut b = bb.clone(); + let mut b = bb; if b[31] & 0x80 != 0x00 { sign = true; - b[31] = b[31] & 0x7F; + b[31] &= 0x7F; } let y: BigInt = BigInt::from_bytes_le(Sign::Plus, &b[..]); if y >= Q.clone() { @@ -223,7 +220,7 @@ pub fn decompress_point(bb: [u8; 32]) -> Result { // x^2 = (1 - y^2) / (a - d * y^2) (mod p) let den = utils::modinv( &utils::modulus( - &(&A_big.clone() - utils::modulus(&(&D_big.clone() * (&y * &y)), &Q)), + &(&A_BIG.clone() - utils::modulus(&(&D_BIG.clone() * (&y * &y)), &Q)), &Q, ), &Q, @@ -231,8 +228,8 @@ pub fn decompress_point(bb: [u8; 32]) -> Result { let mut x: BigInt = utils::modulus(&((one - utils::modulus(&(&y * &y), &Q)) * den), &Q); x = utils::modsqrt(&x, &Q)?; - if sign && !(&x > &(&Q.clone() >> 1)) || (!sign && (&x > &(&Q.clone() >> 1))) { - x = x * -1.to_bigint().unwrap(); + if sign && (x <= (&Q.clone() >> 1)) || (!sign && (x > (&Q.clone() >> 1))) { + x *= -(1.to_bigint().unwrap()); } x = utils::modulus(&x, &Q); let x_fr: Fr = Fr::from_str(&x.to_string()).unwrap(); @@ -241,7 +238,7 @@ pub fn decompress_point(bb: [u8; 32]) -> Result { } #[cfg(feature = "default")] -fn blh(b: &Vec) -> Vec { +fn blh(b: &[u8]) -> Vec { let hash = blake_hash::Blake512::digest(&b); hash.to_vec() } @@ -279,11 +276,8 @@ pub fn decompress_signature(b: &[u8; 64]) -> Result { let s: BigInt = BigInt::from_bytes_le(Sign::Plus, &b[32..]); let r_b8 = decompress_point(r_b8_bytes); match r_b8 { - Result::Err(err) => return Err(err.to_string()), - Result::Ok(res) => Ok(Signature { - r_b8: res.clone(), - s: s, - }), + Result::Err(err) => Err(err), + Result::Ok(res) => Ok(Signature { r_b8: res, s }), } } @@ -308,21 +302,19 @@ impl PrivateKey { // let mut h = hasher.finalize(); // compatible with circomlib implementation - let mut hash: Vec = blh(&self.key.to_vec()); + let hash: Vec = blh(&self.key.to_vec()); let mut h: Vec = hash[..32].to_vec(); - h[0] = h[0] & 0xF8; - h[31] = h[31] & 0x7F; - h[31] = h[31] | 0x40; + h[0] &= 0xF8; + h[31] &= 0x7F; + h[31] |= 0x40; let sk = BigInt::from_bytes_le(Sign::Plus, &h[..]); sk >> 3 } pub fn public(&self) -> Point { - // https://tools.ietf.org/html/rfc8032#section-5.1.5 - let pk = B8.mul_scalar(&self.scalar_key()); - pk.clone() + B8.mul_scalar(&self.scalar_key()) } pub fn sign(&self, msg: BigInt) -> Result { @@ -346,24 +338,22 @@ impl PrivateKey { let r_hashed: Vec = blh(&r_bytes); let mut r = BigInt::from_bytes_le(Sign::Plus, &r_hashed[..]); r = utils::modulus(&r, &SUBORDER); - let r8: Point = B8.mul_scalar(&r); + let r_b8: Point = B8.mul_scalar(&r); let a = &self.public(); - let hm_input = vec![r8.x.clone(), r8.y.clone(), a.x.clone(), a.y.clone(), msg_fr]; - let hm = poseidon.hash(hm_input)?; + let hm_input = vec![r_b8.x, r_b8.y, a.x, a.y, msg_fr]; + let hm = POSEIDON.hash(hm_input)?; let mut s = &self.scalar_key() << 3; let hm_b = BigInt::parse_bytes(to_hex(&hm).as_bytes(), 16).unwrap(); s = hm_b * s; s = r + s; - s = s % &SUBORDER.clone(); + s %= &SUBORDER.clone(); - Ok(Signature { - r_b8: r8.clone(), - s: s, - }) + Ok(Signature { r_b8, s }) } + #[allow(clippy::many_single_char_names)] pub fn sign_schnorr(&self, m: BigInt) -> Result<(Point, BigInt), String> { // random r let mut rng = rand6::thread_rng(); @@ -388,8 +378,8 @@ pub fn schnorr_hash(pk: &Point, msg: BigInt, c: &Point) -> Result bool { return false; } let msg_fr: Fr = Fr::from_str(&msg.to_string()).unwrap(); - let hm_input = vec![ - sig.r_b8.x.clone(), - sig.r_b8.y.clone(), - pk.x.clone(), - pk.y.clone(), - msg_fr, - ]; - let hm = match poseidon.hash(hm_input) { + let hm_input = vec![sig.r_b8.x, sig.r_b8.y, pk.x, pk.y, msg_fr]; + let hm = match POSEIDON.hash(hm_input) { Result::Err(_) => return false, Result::Ok(hm) => hm, }; @@ -443,6 +427,7 @@ pub fn verify(pk: Point, sig: Signature, msg: BigInt) -> bool { mod tests { use super::*; extern crate rustc_hex; + use rand6::Rng; use rustc_hex::{FromHex, ToHex}; #[test] @@ -720,7 +705,7 @@ mod tests { .unwrap(); // test blake compatible with circomlib implementation - let mut h: Vec = blh(&sk_raw_bytes); + let h: Vec = blh(&sk_raw_bytes); assert_eq!(h.to_hex(), "c992db23d6290c70ffcc02f7abeb00b9d00fa8b43e55d7949c28ba6be7545d3253882a61bd004a236ef1cdba01b27ba0aedfb08eefdbfb7c19657c880b43ddf1"); // test private key diff --git a/src/utils.rs b/src/utils.rs index 3763040..776be66 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,6 @@ +// BabyJubJub elliptic curve implementation in Rust. +// For LICENSE check https://github.com/arnaucube/babyjubjub-rs + extern crate num; extern crate num_bigint; extern crate num_traits; @@ -106,6 +109,7 @@ pub fn concatenate_arrays(x: &[T], y: &[T]) -> Vec { x.iter().chain(y).cloned().collect() } +#[allow(clippy::many_single_char_names)] pub fn modsqrt(a: &BigInt, q: &BigInt) -> Result { // Tonelli-Shanks Algorithm (https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm) // @@ -115,11 +119,7 @@ pub fn modsqrt(a: &BigInt, q: &BigInt) -> Result { let zero: BigInt = Zero::zero(); let one: BigInt = One::one(); - if legendre_symbol(&a, q) != 1 { - return Err("not a mod p square".to_string()); - } else if a == &zero { - return Err("not a mod p square".to_string()); - } else if q == &2.to_bigint().unwrap() { + if legendre_symbol(&a, q) != 1 || a == &zero || q == &2.to_bigint().unwrap() { return Err("not a mod p square".to_string()); } else if q % 4.to_bigint().unwrap() == 3.to_bigint().unwrap() { let r = a.modpow(&((q + one) / 4), &q); @@ -129,8 +129,8 @@ pub fn modsqrt(a: &BigInt, q: &BigInt) -> Result { let mut s = q - &one; let mut e: BigInt = Zero::zero(); while &s % 2 == zero { - s = s >> 1; - e = e + &one; + s >>= 1; + e += &one; } let mut n: BigInt = 2.to_bigint().unwrap(); @@ -146,13 +146,13 @@ pub fn modsqrt(a: &BigInt, q: &BigInt) -> Result { loop { let mut t = b.clone(); let mut m: BigInt = Zero::zero(); - while &t != &one { + while t != one { t = modulus(&(&t * &t), q); - m = m + &one; + m += &one; } if m == zero { - return Ok(y.clone()); + return Ok(y); } t = g.modpow(&(2.to_bigint().unwrap().modpow(&(&r - &m - 1), q)), q); @@ -164,6 +164,7 @@ pub fn modsqrt(a: &BigInt, q: &BigInt) -> Result { } #[allow(dead_code)] +#[allow(clippy::many_single_char_names)] pub fn modsqrt_v2(a: &BigInt, q: &BigInt) -> Result { // Tonelli-Shanks Algorithm (https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm) // @@ -171,11 +172,7 @@ pub fn modsqrt_v2(a: &BigInt, q: &BigInt) -> Result { let zero: BigInt = Zero::zero(); let one: BigInt = One::one(); - if legendre_symbol(&a, q) != 1 { - return Err("not a mod p square".to_string()); - } else if a == &zero { - return Err("not a mod p square".to_string()); - } else if q == &2.to_bigint().unwrap() { + if legendre_symbol(&a, q) != 1 || a == &zero || q == &2.to_bigint().unwrap() { return Err("not a mod p square".to_string()); } else if q % 4.to_bigint().unwrap() == 3.to_bigint().unwrap() { let r = a.modpow(&((q + one) / 4), &q); @@ -185,8 +182,8 @@ pub fn modsqrt_v2(a: &BigInt, q: &BigInt) -> Result { let mut p = q - &one; let mut s: BigInt = Zero::zero(); while &p % 2.to_bigint().unwrap() == zero { - s = s + &one; - p = p >> 1; + s += &one; + p >>= 1; } let mut z: BigInt = One::one(); @@ -199,15 +196,15 @@ pub fn modsqrt_v2(a: &BigInt, q: &BigInt) -> Result { let mut t = a.modpow(&p, q); let mut m = s; - while &t != &one { + while t != one { let mut i: BigInt = One::one(); let mut e: BigInt = 2.to_bigint().unwrap(); while i < m { if t.modpow(&e, q) == one { break; } - e = e * 2.to_bigint().unwrap(); - i = i + &one; + e *= 2.to_bigint().unwrap(); + i += &one; } let b = c.modpow(&(2.to_bigint().unwrap().modpow(&(&m - &i - 1), q)), q); @@ -216,14 +213,14 @@ pub fn modsqrt_v2(a: &BigInt, q: &BigInt) -> Result { c = modulus(&(&b * &b), q); m = i.clone(); } - return Ok(x); + Ok(x) } pub fn legendre_symbol(a: &BigInt, q: &BigInt) -> i32 { // returns 1 if has a square root modulo q let one: BigInt = One::one(); let ls: BigInt = a.modpow(&((q - &one) >> 1), &q); - if &(ls) == &(q - one) { + if ls == q - one { return -1; } 1