diff --git a/Cargo.toml b/Cargo.toml index 97028a1..98f8e4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,10 +2,3 @@ resolver = "2" members = ["rust-arkworks", "rust-k256", "javascript"] - -[patch.crates-io] -ark-ec = { git = "https://github.com/FindoraNetwork/ark-algebra" } -ark-ff = { git = "https://github.com/FindoraNetwork/ark-algebra" } -ark-serialize = { git = "https://github.com/FindoraNetwork/ark-algebra" } -ark-algebra-test-templates = { git = "https://github.com/FindoraNetwork/ark-algebra" } -ark-std = { git = "https://github.com/FindoraNetwork/ark-std" } diff --git a/rust-arkworks/Cargo.toml b/rust-arkworks/Cargo.toml index 1dc7a90..9b1d046 100644 --- a/rust-arkworks/Cargo.toml +++ b/rust-arkworks/Cargo.toml @@ -11,12 +11,11 @@ keywords = ["nullifier", "zero-knowledge", "ECDSA", "PLUME"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ark-ec = "~0.3.0" -ark-ff = "~0.3.0" -ark-std = "~0.3.0" -ark-serialize = "~0.3.0" -ark-serialize-derive = "~0.3.0" -secp256k1 = { git = "https://github.com/geometryresearch/ark-secp256k1.git", version = "0.1.0" } +ark-ec = "~0.5.0" +ark-ff = "~0.5.0" +ark-std = "~0.5.0" +ark-serialize = "~0.5.0" +ark-serialize-derive = "~0.5.0" rand_core = { version = "0.6", default-features = false, features = [ "getrandom", ] } @@ -24,11 +23,15 @@ rand = "0.8.4" tiny-keccak = { version = "2.0.2", features = ["shake"] } sha2 = "0.10.2" elliptic-curve = { version = "0.12.2", features = ["arithmetic"] } -k256 = { version = "0.11.3", features = [ - "arithmetic", - "hash2curve", - "expose-field", - "sha2", -] } generic-array = { version = "0.14", default-features = false } hex = "0.4.3" + +# #standinDependencies +## the curve internalization +ark-ff-macros = "~0.5.0" +## field hasher fix +arrayvec = { version = "0.7", default-features = false } + +[dev-dependencies] +num-bigint = "*" +num-traits = "*" \ No newline at end of file diff --git a/rust-arkworks/README.MD b/rust-arkworks/README.MD index 51d111c..ff91c89 100644 --- a/rust-arkworks/README.MD +++ b/rust-arkworks/README.MD @@ -1,3 +1 @@ -https://github.com/plume-sig/zk-nullifier-sig/blob/main/README.md -# HAZMAT -Please note that until `v0.1.0` this is very much a preview crate which lets you have some preliminary feel of the structure and the reference implementation approach. \ No newline at end of file +https://github.com/plume-sig/zk-nullifier-sig/blob/main/README.md \ No newline at end of file diff --git a/rust-arkworks/src/error.rs b/rust-arkworks/src/error.rs deleted file mode 100644 index 151cad8..0000000 --- a/rust-arkworks/src/error.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Legacy definitions for errors which will be gone with arkworks upgrade to `>=0.4.0`. -// `use ark_ec::hashing::HashToCurveError;` - -// use thiserror::Error; - -// /// This is an error that could occur when running a cryptograhic primitive -// #[derive(Error, Debug, PartialEq)] -// pub enum CryptoError { -// #[error("Cannot hash to curve")] -// CannotHashToCurve, - -// #[error("Cannot encode a point not on the curve")] -// PointNotOnCurve, -// } - -// Let's outline what errors will be in `~0.4.0` -/// It's an interim `enum` between legacy definition of the errors and prospective which will be relying on [`ark_ec::hashing::HashToCurveError`]. -#[derive(Debug, Clone)] -pub enum HashToCurveError { - /// Mimics the `ark_ec::hashing::HashToCurveError` enum - UnsupportedCurveError(String), - /// Mimics the `ark_ec::hashing::HashToCurveError` enum - MapToCurveError(String), - /* let's add two more items to absorb everything - in `crate::hash_to_curve` which is - subject to deprecation */ - /// Absorbs any legacy error in [`mod@crate::hash_to_curve`]. They will be deprecated with upgrade to `~0.4.0`. - Legacy, - /// A special case for a reference function. It will be moved to <./examples> with the upgrade to `~0.4.0`. - ReferenceTryAndIncrement, -} diff --git a/rust-arkworks/src/fixed_hasher/expander.rs b/rust-arkworks/src/fixed_hasher/expander.rs new file mode 100644 index 0000000..3d32d1a --- /dev/null +++ b/rust-arkworks/src/fixed_hasher/expander.rs @@ -0,0 +1,135 @@ +// The below implementation is a rework of https://github.com/armfazh/h2c-rust-ref +// With some optimisations + +use core::marker::PhantomData; + +use ark_std::vec::*; + +use arrayvec::ArrayVec; +use sha2::digest::{ExtendableOutput, FixedOutputReset, Update}; + +pub trait Expander { + fn expand(&self, msg: &[u8], length: usize) -> Vec; +} +const MAX_DST_LENGTH: usize = 255; + +const LONG_DST_PREFIX: &[u8; 17] = b"H2C-OVERSIZE-DST-"; + +/// Implements section [5.3.3](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-5.3.3) +/// "Using DSTs longer than 255 bytes" of the +/// [IRTF CFRG hash-to-curve draft #16](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-5.3.3). +pub struct DST(arrayvec::ArrayVec); + +impl DST { + pub fn new_xmd(dst: &[u8]) -> DST { + let array = if dst.len() > MAX_DST_LENGTH { + let mut long = H::default(); + long.update(&LONG_DST_PREFIX[..]); + long.update(&dst); + ArrayVec::try_from(long.finalize_fixed().as_ref()).unwrap() + } else { + ArrayVec::try_from(dst).unwrap() + }; + DST(array) + } + + #[allow(dead_code)] + pub fn new_xof(dst: &[u8], k: usize) -> DST { + let array = if dst.len() > MAX_DST_LENGTH { + let mut long = H::default(); + long.update(&LONG_DST_PREFIX[..]); + long.update(&dst); + + let mut new_dst = [0u8; MAX_DST_LENGTH]; + let new_dst = &mut new_dst[0..((2 * k + 7) >> 3)]; + long.finalize_xof_into(new_dst); + ArrayVec::try_from(&*new_dst).unwrap() + } else { + ArrayVec::try_from(dst).unwrap() + }; + DST(array) + } + + pub fn update(&self, h: &mut H) { + h.update(self.0.as_ref()); + // I2OSP(len,1) https://www.rfc-editor.org/rfc/rfc8017.txt + h.update(&[self.0.len() as u8]); + } +} + +#[allow(dead_code)] +pub(super) struct ExpanderXof { + pub(super) xofer: PhantomData, + pub(super) dst: Vec, + pub(super) k: usize, +} + +impl Expander for ExpanderXof { + fn expand(&self, msg: &[u8], n: usize) -> Vec { + let mut xofer = H::default(); + xofer.update(msg); + + // I2OSP(len,2) https://www.rfc-editor.org/rfc/rfc8017.txt + let lib_str = (n as u16).to_be_bytes(); + xofer.update(&lib_str); + + DST::new_xof::(self.dst.as_ref(), self.k).update(&mut xofer); + xofer.finalize_boxed(n).into_vec() + } +} + +pub(super) struct ExpanderXmd { + pub(super) hasher: PhantomData, + pub(super) dst: Vec, + pub(super) block_size: usize, +} + +static Z_PAD: [u8; 256] = [0u8; 256]; + +impl Expander for ExpanderXmd { + fn expand(&self, msg: &[u8], n: usize) -> Vec { + use sha2::digest::typenum::Unsigned; + // output size of the hash function, e.g. 32 bytes = 256 bits for sha2::Sha256 + let b_len = H::OutputSize::to_usize(); + let ell = (n + (b_len - 1)) / b_len; + assert!( + ell <= 255, + "The ratio of desired output to the output size of hash function is too large!" + ); + + let dst_prime = DST::new_xmd::(self.dst.as_ref()); + // Represent `len_in_bytes` as a 2-byte array. + // As per I2OSP method outlined in https://tools.ietf.org/pdf/rfc8017.pdf, + // The program should abort if integer that we're trying to convert is too large. + assert!(n < (1 << 16), "Length should be smaller than 2^16"); + let lib_str: [u8; 2] = (n as u16).to_be_bytes(); + + let mut hasher = H::default(); + hasher.update(&Z_PAD[0..self.block_size]); + hasher.update(msg); + hasher.update(&lib_str); + hasher.update(&[0u8]); + dst_prime.update(&mut hasher); + let b0 = hasher.finalize_fixed_reset(); + + hasher.update(&b0); + hasher.update(&[1u8]); + dst_prime.update(&mut hasher); + let mut bi = hasher.finalize_fixed_reset(); + + let mut uniform_bytes: Vec = Vec::with_capacity(n); + uniform_bytes.extend_from_slice(&bi); + for i in 2..=ell { + // update the hasher with xor of b_0 and b_i elements + for (l, r) in b0.iter().zip(bi.iter()) { + hasher.update(&[*l ^ *r]); + } + hasher.update(&[i as u8]); + dst_prime.update(&mut hasher); + bi = hasher.finalize_fixed_reset(); + uniform_bytes.extend_from_slice(&bi); + } + uniform_bytes.truncate(n); + uniform_bytes + } +} diff --git a/rust-arkworks/src/fixed_hasher/mod.rs b/rust-arkworks/src/fixed_hasher/mod.rs new file mode 100644 index 0000000..0a1b398 --- /dev/null +++ b/rust-arkworks/src/fixed_hasher/mod.rs @@ -0,0 +1,62 @@ +mod expander; +use ark_ff::{field_hashers::HashToField, Field, PrimeField}; +use core::marker::PhantomData; +use expander::{Expander, ExpanderXmd}; +use sha2::digest::{core_api::BlockSizeUser, FixedOutputReset}; + +pub struct FixedFieldHasher { + expander: ExpanderXmd, + len_per_base_elem: usize, +} + +impl + HashToField for FixedFieldHasher +{ + fn new(dst: &[u8]) -> Self { + // The final output of `hash_to_field` will be an array of field + // elements from F::BaseField, each of size `len_per_elem`. + let len_per_base_elem = get_len_per_elem::(); + + let expander = ExpanderXmd { + hasher: PhantomData, + dst: dst.to_vec(), + block_size: H::block_size(), + }; + + FixedFieldHasher { + expander, + len_per_base_elem, + } + } + + fn hash_to_field(&self, message: &[u8]) -> [F; N] { + let m = F::extension_degree() as usize; + + // The user requests `N` of elements of F_p^m to output per input msg, + // each field element comprising `m` BasePrimeField elements. + let len_in_bytes = N * m * self.len_per_base_elem; + let uniform_bytes = self.expander.expand(message, len_in_bytes); + + let cb = |i| { + let base_prime_field_elem = |j| { + let elm_offset = self.len_per_base_elem * (j + i * m); + F::BasePrimeField::from_be_bytes_mod_order( + &uniform_bytes[elm_offset..][..self.len_per_base_elem], + ) + }; + F::from_base_prime_field_elems((0..m).map(base_prime_field_elem)).unwrap() + }; + ark_std::array::from_fn::(cb) + } +} + +const fn get_len_per_elem() -> usize { + // ceil(log(p)) + let base_field_size_in_bits = F::BasePrimeField::MODULUS_BIT_SIZE as usize; + // ceil(log(p)) + security_parameter + let base_field_size_with_security_padding_in_bits = base_field_size_in_bits + SEC_PARAM; + // ceil( (ceil(log(p)) + security_parameter) / 8) + let bytes_per_base_field_elem = + ((base_field_size_with_security_padding_in_bits + 7) / 8) as u64; + bytes_per_base_field_elem as usize +} diff --git a/rust-arkworks/src/hash_to_curve.rs b/rust-arkworks/src/hash_to_curve.rs deleted file mode 100644 index 8b19697..0000000 --- a/rust-arkworks/src/hash_to_curve.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::error::HashToCurveError; -use ark_ec::short_weierstrass_jacobian::GroupAffine; -use ark_ec::{AffineCurve, ProjectiveCurve}; -use ark_ff::FromBytes; -use elliptic_curve::hash2curve::{ExpandMsgXmd, GroupDigest}; -use elliptic_curve::sec1::ToEncodedPoint; -// TODO why not ark libs for these? oO -use k256::{sha2::Sha256, AffinePoint, ProjectivePoint, Secp256k1}; -use secp256k1::Sec1EncodePoint; -use tiny_keccak::{Hasher, Shake, Xof}; - -pub fn hash_to_curve( - msg: &[u8], - pk: &GroupAffine

, -) -> Result, HashToCurveError> { - let b = hex::decode(&pk.to_encoded_point(true)).expect(super::EXPECT_MSG_DECODE); - let x = [msg, b.as_slice()]; - let x = x.concat().clone(); - let x = x.as_slice(); - - let pt: ProjectivePoint = Secp256k1::hash_from_bytes::>( - &[x], - b"QUUX-V01-CS02-with-secp256k1_XMD:SHA-256_SSWU_RO_", - ) - .map_err(|_| HashToCurveError::Legacy)?; - - let pt_affine = pt.to_affine(); - - k256_affine_to_arkworks_secp256k1_affine::

(pt_affine) -} - -pub fn k256_affine_to_arkworks_secp256k1_affine( - k_pt: AffinePoint, -) -> Result, HashToCurveError> { - let encoded_pt = k_pt.to_encoded_point(false); - - let num_field_bytes = 40; - - // extract k_pt.x - let k_pt_x_bytes = encoded_pt.x().ok_or(HashToCurveError::Legacy)?; - - // pad x bytes - let mut k_pt_x_bytes_vec = vec![0u8; num_field_bytes]; - for (i, _) in k_pt_x_bytes.clone().iter().enumerate() { - let _ = std::mem::replace( - &mut k_pt_x_bytes_vec[i], - k_pt_x_bytes[k_pt_x_bytes.len() - 1 - i], - ); - } - let reader = std::io::BufReader::new(k_pt_x_bytes_vec.as_slice()); - let g_x = P::BaseField::read(reader).map_err(|_| HashToCurveError::Legacy)?; - - // extract k_pt.y - let k_pt_y_bytes = encoded_pt.y().ok_or(HashToCurveError::Legacy)?; - - // pad y bytes - let mut k_pt_y_bytes_vec = vec![0u8; num_field_bytes]; - for (i, _) in k_pt_y_bytes.clone().iter().enumerate() { - let _ = std::mem::replace( - &mut k_pt_y_bytes_vec[i], - k_pt_y_bytes[k_pt_y_bytes.len() - 1 - i], - ); - } - - let reader = std::io::BufReader::new(k_pt_y_bytes_vec.as_slice()); - let g_y = P::BaseField::read(reader).map_err(|_| HashToCurveError::Legacy)?; - - Ok(GroupAffine::

::new(g_x, g_y, false)) -} - -/// Kobi's hash_to_curve function, here for reference only -pub fn _try_and_increment(msg: &[u8]) -> Result { - for nonce in 0u8..=255 { - let mut h = Shake::v128(); - h.update(&[nonce]); - h.update(msg.as_ref()); - let output_size = C::zero().serialized_size(); - let mut output = vec![0u8; output_size]; - h.squeeze(&mut output); - - if let Some(p) = C::Affine::from_random_bytes(&output) { - return Ok(p); - } - } - - Err(HashToCurveError::ReferenceTryAndIncrement) -} diff --git a/rust-arkworks/src/lib.rs b/rust-arkworks/src/lib.rs index 2497515..4483ab3 100644 --- a/rust-arkworks/src/lib.rs +++ b/rust-arkworks/src/lib.rs @@ -1,34 +1,74 @@ -/// This crate provides the PLUME signature scheme. +//! This crate provides the PLUME signature scheme. +//! +//! See for more information. +//! +//! Find the crate to use with RustCrypto as `plume_rustcrypto`. +//! +//! # Examples +//! ```rust +//! use plume_arkworks::{PlumeSignature, PlumeVersion, SWCurveConfig}; +//! use rand_core::OsRng; +//! +//! # fn main() { +//! let message_the = b"ZK nullifier signature"; +//! let sk = PlumeSignature::keygen(&mut OsRng); +//! +//! let sig = PlumeSignature::sign( +//! &mut OsRng, (&sk.0, &sk.1), message_the.as_slice(), PlumeVersion::V1 +//! ); +//! +//! assert!( +//! sig.unwrap() +//! .verify_non_zk( +//! &plume_arkworks::Parameters{ +//! g_point: plume_arkworks::secp256k1::Config::GENERATOR +//! }, +//! &sk.0, +//! message_the, +//! PlumeVersion::V1 +//! ).unwrap() +//! ); +//! # } +//! ``` + +/// Stand-in solution until [the default hasher issue](https://github.com/arkworks-rs/algebra/issues/849) is fixed. +pub mod fixed_hasher; // #standinDependencies +/// Stand-in solution until [the curve hashing support](https://github.com/arkworks-rs/algebra/pull/863) is merged. +pub mod secp256k1; // #standinDependencies + +/* /// Re-exports `SWCurveConfig` type from `models::short_weierstrass` of the `ark_ec` crate, +/// and `hashing` items. /// -/// See for more information. -/// -/// Find RustCrypto crate as `plume_rustcrypto`. - -pub use crate::error::HashToCurveError; -use crate::hash_to_curve::hash_to_curve; - -/// Re-exports the `GroupAffine` and `SWModelParameters` types from the `ark_ec` crate. +/// `HashToCurve` is the trait needed for hashing to the curve. +/// `HashToCurveError` is the error type to process a `Result`. /// -/// `GroupAffine` represents an affine point on a short Weierstrass elliptic curve. -/// `SWModelParameters` contains the parameters defining a short Weierstrass curve. -pub use ark_ec::{models::SWModelParameters, short_weierstrass_jacobian::GroupAffine}; -/// Re-exports the `Rng` trait from the `rand` crate in `ark_std`. +/// `SWCurveConfig` contains the parameters defining a short Weierstrass curve. */ +pub use ark_ec::{ + hashing::{HashToCurve, HashToCurveError}, + models::short_weierstrass::SWCurveConfig, +}; +use ark_ec::{short_weierstrass, AffineRepr, CurveGroup}; +/// Re-exports the `Rng` trait from `rand` crate in `ark_std`. /// /// `Rng` provides methods for generating random values. pub use ark_std::rand::Rng; -use ark_ec::{AffineCurve, ProjectiveCurve}; -use ark_ff::PrimeField; -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write}; -use ark_std::UniformRand; -use secp256k1::sec1::Sec1EncodePoint; -use sha2::digest::Output; -use sha2::{Digest, Sha256}; +use ark_ff::{BigInteger, PrimeField}; -mod error; -mod hash_to_curve; +/// Re-exports the `CanonicalDeserialize` and `CanonicalSerialize` traits from `ark_serialize` crate. +/// +/// These traits provide methods for serializing and deserializing data in a canonical format. +pub use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::UniformRand; +use fixed_hasher::FixedFieldHasher; +use sha2::{digest::Output, Digest, Sha256}; +use std::ops::Mul; -const EXPECT_MSG_DECODE: &str = "the value decoded have been generated by a function which is improbable to output a malformed hexstring (still a place for refactoring)"; +/// Re-exports the `Affine` and `Fr` types from `secp256k1` module. +/// +/// `Affine` represents an affine point on `secp256k1` elliptic curve. +/// `Fr` represents an element of the scalar field of the secp256k1 elliptic curve. +pub use secp256k1::{Affine, Fr}; /// An `enum` representing the variant of the PLUME protocol. pub enum PlumeVersion { @@ -38,54 +78,72 @@ pub enum PlumeVersion { /// Converts an affine point on the curve to the byte representation. /// -/// Serializes the affine point to its SEC1 encoding and returns the raw bytes. -pub fn affine_to_bytes(point: &GroupAffine

) -> Vec { - hex::decode(point.to_encoded_point(true)) - .expect(EXPECT_MSG_DECODE) - .to_vec() +/// Serializes the affine point to its SEC1 compressed encoding and returns the raw bytes. +/// +/// Note that the identity element is coded with the `Vec` of single zero byte. +pub fn affine_to_bytes(point: &Affine) -> Vec { + if point.is_zero() { + return [0].into(); + } + let mut compressed_bytes = Vec::new(); + point.serialize_compressed(&mut compressed_bytes).expect("it's actually infallible here because the `BaseField` is a proper `Fp` (no flags on serialization)"); + compressed_bytes.reverse(); + compressed_bytes[0] = if point + .y() + .expect("zero check have been done above") + .into_bigint() + .is_odd() + { + 3 + } else { + 2 + }; + compressed_bytes } -fn compute_h<'a, C: ProjectiveCurve, Fq: PrimeField, P: SWModelParameters>( - pk: &GroupAffine

, - message: &'a [u8], -) -> Result, HashToCurveError> { - //let pk_affine_bytes_vec = affine_to_bytes::

(pk); - //let m_pk = [message, pk_affine_bytes_vec.as_slice()].concat(); - //hash_to_curve::try_and_increment::(m_pk.as_slice()) - hash_to_curve::(message, pk) +fn hash_to_curve(message: &[u8], pk: &Affine) -> Result { + ark_ec::hashing::map_to_curve_hasher::MapToCurveBasedHasher::< + ark_ec::short_weierstrass::Projective, + FixedFieldHasher, + ark_ec::hashing::curve_maps::wb::WBMap, + >::new(b"QUUX-V01-CS02-with-secp256k1_XMD:SHA-256_SSWU_RO_")? + .hash( + [message, affine_to_bytes(pk).as_slice()] + .concat() + .as_slice(), + ) } -fn compute_c_v1( - g_point: &GroupAffine

, - pk: &GroupAffine

, - hashed_to_curve: &GroupAffine

, - nullifier: &GroupAffine

, - r_point: &GroupAffine

, - hashed_to_curve_r: &GroupAffine

, +fn compute_c_v1( + pk: &secp256k1::Affine, + hashed_to_curve: &secp256k1::Affine, + nullifier: &secp256k1::Affine, + r_point: &secp256k1::Affine, + hashed_to_curve_r: &secp256k1::Affine, ) -> Output { - // Compute c = sha512([g, pk, h, nul, g^r, z]) + // Compute c = sha256([g, pk, h, nul, g^r, z]) let c_preimage_vec = [ - affine_to_bytes::

(g_point), - affine_to_bytes::

(pk), - affine_to_bytes::

(hashed_to_curve), - affine_to_bytes::

(nullifier), - affine_to_bytes::

(r_point), - affine_to_bytes::

(hashed_to_curve_r), + affine_to_bytes(&secp256k1::Config::GENERATOR), + affine_to_bytes(pk), + affine_to_bytes(hashed_to_curve), + affine_to_bytes(nullifier), + affine_to_bytes(r_point), + affine_to_bytes(hashed_to_curve_r), ] .concat(); Sha256::digest(c_preimage_vec.as_slice()) } -fn compute_c_v2( - nullifier: &GroupAffine

, - r_point: &GroupAffine

, - hashed_to_curve_r: &GroupAffine

, +fn compute_c_v2( + nullifier: &secp256k1::Affine, + r_point: &secp256k1::Affine, + hashed_to_curve_r: &secp256k1::Affine, ) -> Output { - // Compute c = sha512([nul, g^r, z]) - let nul_bytes = affine_to_bytes::

(nullifier); - let g_r_bytes = affine_to_bytes::

(r_point); - let z_bytes = affine_to_bytes::

(hashed_to_curve_r); + // Compute c = sha256([nul, g^r, z]) + let nul_bytes = affine_to_bytes(nullifier); + let g_r_bytes = affine_to_bytes(r_point); + let z_bytes = affine_to_bytes(hashed_to_curve_r); let c_preimage_vec = [nul_bytes, g_r_bytes, z_bytes].concat(); @@ -100,9 +158,9 @@ fn compute_c_v2( ark_serialize_derive::CanonicalSerialize, ark_serialize_derive::CanonicalDeserialize, )] -pub struct Parameters { +pub struct Parameters { /// The generator point for the SW model parameters. - pub g_point: GroupAffine

, + pub g_point: short_weierstrass::Affine

, } /// A struct containing the PLUME signature data @@ -112,15 +170,15 @@ pub struct Parameters { ark_serialize_derive::CanonicalSerialize, ark_serialize_derive::CanonicalDeserialize, )] -pub struct PlumeSignature { +pub struct PlumeSignature { /// The hash-to-curve output multiplied by the random `r`. - pub hashed_to_curve_r: GroupAffine

, + pub hashed_to_curve_r: Affine, /// The randomness `r` represented as the curve point. - pub r_point: GroupAffine

, - pub s: P::ScalarField, - pub c: P::ScalarField, + pub r_point: Affine, + pub s: Fr, + pub c: Fr, /// The nullifier. - pub nullifier: GroupAffine

, + pub nullifier: Affine, } // These aliases should be gone in #88 . If they won't TODO pay attention to the warning about `trait` boundaries being not checked for aliases @@ -129,34 +187,29 @@ pub struct PlumeSignature { /// A type alias for a byte slice reference, used for representing the message. pub type Message<'a> = &'a [u8]; /// The public key. -pub type PublicKey = GroupAffine

; +pub type PublicKey = Affine; /// The scalar field element representing the secret key. -pub type SecretKeyMaterial = P::ScalarField; +pub type SecretKeyMaterial = Fr; -impl PlumeSignature

{ +impl PlumeSignature { /// Generate the public key and a private key. - /// # HAZMAT - /// No measures yet taken for the [`SecretKeyMaterial`] protection - pub fn keygen(pp: &Parameters

, rng: &mut impl Rng) -> (PublicKey

, SecretKeyMaterial

) { - let secret_key = SecretKeyMaterial::

::rand(rng); - let public_key = pp.g_point.mul(secret_key).into(); - (public_key, secret_key) + pub fn keygen(rng: &mut impl Rng) -> (PublicKey, SecretKeyMaterial) { + let secret_key = SecretKeyMaterial::rand(rng); + let public_key = secp256k1::Config::GENERATOR * secret_key; + (public_key.into_affine(), secret_key) } /// Sign a message using the specified `r` value - fn sign_with_r( - pp: &Parameters

, - keypair: (&PublicKey

, &SecretKeyMaterial

), + pub fn sign_with_r( + keypair: (&PublicKey, &SecretKeyMaterial), message: Message, - r_scalar: P::ScalarField, + r_scalar: Fr, version: PlumeVersion, ) -> Result { - let g_point = pp.g_point; - let r_point = g_point.mul(r_scalar).into_affine(); + let r_point = secp256k1::Config::GENERATOR.mul(r_scalar).into_affine(); // Compute h = htc([m, pk]) - let hashed_to_curve = - compute_h::(&keypair.0, &message)?; + let hashed_to_curve: secp256k1::Affine = hash_to_curve(message, keypair.0)?; // Compute z = h^r let hashed_to_curve_r = hashed_to_curve.mul(r_scalar).into_affine(); @@ -164,10 +217,9 @@ impl PlumeSignature

{ // Compute nul = h^sk let nullifier = hashed_to_curve.mul(*keypair.1).into_affine(); - // Compute c = sha512([g, pk, h, nul, g^r, z]) + // Compute c = sha256([g, pk, h, nul, g^r, z]) let c = match version { - PlumeVersion::V1 => compute_c_v1::

( - &g_point, + PlumeVersion::V1 => compute_c_v1( keypair.0, &hashed_to_curve, &nullifier, @@ -176,12 +228,12 @@ impl PlumeSignature

{ ), PlumeVersion::V2 => compute_c_v2(&nullifier, &r_point, &hashed_to_curve_r), }; - let c_scalar = P::ScalarField::from_be_bytes_mod_order(c.as_ref()); + let c_scalar = secp256k1::Fr::from_be_bytes_mod_order(c.as_ref()); // Compute s = r + sk ⋅ c - let sk_c = keypair.1.into_repr().into() * c_scalar.into_repr().into(); - let s = r_scalar.into_repr().into() + sk_c; + let sk_c = keypair.1 * &c_scalar; + let s = r_scalar + sk_c; - let s_scalar = P::ScalarField::from(s); + let s_scalar = secp256k1::Fr::from(s); let signature = PlumeSignature { hashed_to_curve_r, @@ -194,17 +246,16 @@ impl PlumeSignature

{ } /// Sign a message. - fn sign( - pp: &Parameters

, + pub fn sign( rng: &mut impl Rng, - keypair: (&PublicKey

, &SecretKeyMaterial

), + keypair: (&PublicKey, &SecretKeyMaterial), message: Message, version: PlumeVersion, ) -> Result { // Pick a random r from Fp - let r_scalar = P::ScalarField::rand(rng); + let r_scalar = secp256k1::Fr::rand(rng); - Self::sign_with_r(pp, keypair, message, r_scalar, version) + Self::sign_with_r(keypair, message, r_scalar, version) } /// Verifies a PLUME signature. @@ -217,23 +268,20 @@ impl PlumeSignature

{ /// - Confirm c = c' /// /// Rejects if any check fails. - fn verify_non_zk( + pub fn verify_non_zk( self, - pp: &Parameters

, - pk: &PublicKey

, + pp: &Parameters, + pk: &PublicKey, message: Message, version: PlumeVersion, ) -> Result { // Compute h = htc([m, pk]) - let hashed_to_curve = - compute_h::(pk, message)?; + let hashed_to_curve = hash_to_curve(message, pk)?; - // TODO [replace SHA-512](https://github.com/plume-sig/zk-nullifier-sig/issues/39#issuecomment-1732497672) - // Compute c' = sha512([g, pk, h, nul, g^r, z]) for v1 - // c' = sha512([nul, g^r, z]) for v2 + // Compute c' = sha256([g, pk, h, nul, g^r, z]) for v1 + // c' = sha256([nul, g^r, z]) for v2 let c = match version { - PlumeVersion::V1 => compute_c_v1::

( - &pp.g_point, + PlumeVersion::V1 => compute_c_v1( pk, &hashed_to_curve, &self.nullifier, @@ -244,7 +292,7 @@ impl PlumeSignature

{ compute_c_v2(&self.nullifier, &self.r_point, &self.hashed_to_curve_r) } }; - let c_scalar = P::ScalarField::from_be_bytes_mod_order(c.as_ref()); + let c_scalar = secp256k1::Fr::from_be_bytes_mod_order(c.as_ref()); // Reject if g^s ⋅ pk^{-c} != g^r let g_s = pp.g_point.mul(self.s); diff --git a/rust-arkworks/src/secp256k1/curves/mod.rs b/rust-arkworks/src/secp256k1/curves/mod.rs new file mode 100644 index 0000000..101111f --- /dev/null +++ b/rust-arkworks/src/secp256k1/curves/mod.rs @@ -0,0 +1,113 @@ +use super::{fq::Fq, fr::Fr}; +use ark_ec::{ + hashing::curve_maps::{ + swu::SWUConfig, + wb::{IsogenyMap, WBConfig}, + }, + models::CurveConfig, + short_weierstrass::{self as sw, SWCurveConfig}, +}; +use ark_ff::{AdditiveGroup, Field, MontFp, Zero}; + +#[derive(Copy, Clone, Default, PartialEq, Eq)] +pub struct Secp256k1Parameters; + +pub type Affine = sw::Affine; +// pub type Projective = sw::Projective; + +// pub type BaseField = Fq; +// pub type ScalarField = Fr; + +#[derive(Copy, Clone, Default, PartialEq, Eq)] +pub struct Config; +impl CurveConfig for Config { + type BaseField = Fq; + type ScalarField = Fr; + + /// COFACTOR = 1 + const COFACTOR: &'static [u64] = &[0x1]; + + /// COFACTOR_INV = COFACTOR^{-1} mod r = 1 + #[rustfmt::skip] + const COFACTOR_INV: Fr = Fr::ONE; +} +impl SWCurveConfig for Config { + /// COEFF_A = 0 + const COEFF_A: Fq = Fq::ZERO; + + /// COEFF_B = 7 + const COEFF_B: Fq = MontFp!("7"); + + /// GENERATOR = (G_GENERATOR_X, G_GENERATOR_Y) + const GENERATOR: Affine = Affine::new_unchecked(G_GENERATOR_X, G_GENERATOR_Y); + + #[inline(always)] + fn mul_by_a(_: Self::BaseField) -> Self::BaseField { + Self::BaseField::zero() + } +} + +/// G_GENERATOR_X = +/// 55066263022277343669578718895168534326250603453777594175500187360389116729240 +pub const G_GENERATOR_X: Fq = + MontFp!("55066263022277343669578718895168534326250603453777594175500187360389116729240"); + +/// G_GENERATOR_Y = +/// 32670510020758816978083085130507043184471273380659243275938904335757337482424 +pub const G_GENERATOR_Y: Fq = + MontFp!("32670510020758816978083085130507043184471273380659243275938904335757337482424"); + +/// `secp256k1_XMD:SHA-256_SSWU_RO_` isogenous curve +pub struct ConfigIsogenous {} +impl CurveConfig for ConfigIsogenous { + type BaseField = ::BaseField; + type ScalarField = ::ScalarField; + + const COFACTOR: &'static [u64] = Config::COFACTOR; + const COFACTOR_INV: Self::ScalarField = Config::COFACTOR_INV; +} +type TheIsoCurveAffine = sw::Affine; +impl SWCurveConfig for ConfigIsogenous { + const COEFF_A: Self::BaseField = + MontFp!("0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533"); + const COEFF_B: Self::BaseField = MontFp!("1771"); + const GENERATOR: TheIsoCurveAffine = TheIsoCurveAffine::new_unchecked( + MontFp!("75295888890003590383366995344834012177557063699577440394299653383124903397514"), + MontFp!("82553647407850972504999846303729620951309077682374043495922869307182479212755"), + ); +} +impl SWUConfig for ConfigIsogenous { + const ZETA: Self::BaseField = MontFp!("-11"); +} + +// Parameters from the [IETF draft v16, section E.3](https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-suites-for-secp256k1). +impl WBConfig for Config { + type IsogenousCurve = ConfigIsogenous; + + const ISOGENY_MAP: IsogenyMap<'static, Self::IsogenousCurve, Self> = IsogenyMap { + x_map_numerator: &[ + MontFp!("0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa8c7"), + MontFp!("0x7d3d4c80bc321d5b9f315cea7fd44c5d595d2fc0bf63b92dfff1044f17c6581"), + MontFp!("0x534c328d23f234e6e2a413deca25caece4506144037c40314ecbd0b53d9dd262"), + MontFp!("0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa88c"), + ], + x_map_denominator: &[ + MontFp!("0xd35771193d94918a9ca34ccbb7b640dd86cd409542f8487d9fe6b745781eb49b"), + MontFp!("0xedadc6f64383dc1df7c4b2d51b54225406d36b641f5e41bbc52a56612a8c6d14"), + MontFp!("1"), + MontFp!("0"), + ], + y_map_numerator: &[ + MontFp!("0x4bda12f684bda12f684bda12f684bda12f684bda12f684bda12f684b8e38e23c"), + MontFp!("0xc75e0c32d5cb7c0fa9d0a54b12a0a6d5647ab046d686da6fdffc90fc201d71a3"), + MontFp!("0x29a6194691f91a73715209ef6512e576722830a201be2018a765e85a9ecee931"), + MontFp!("0x2f684bda12f684bda12f684bda12f684bda12f684bda12f684bda12f38e38d84"), + ], + y_map_denominator: &[ + MontFp!("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff93b"), + MontFp!("0x7a06534bb8bdb49fd5e9e6632722c2989467c1bfc8e8d978dfb425d2685c2573"), + MontFp!("0x6484aa716545ca2cf3a70c3fa8fe337e0a3d21162f0d6299a7bf8192bfd2a76f"), + MontFp!("1"), + ], + }; +} diff --git a/rust-arkworks/src/secp256k1/fields/fq.rs b/rust-arkworks/src/secp256k1/fields/fq.rs new file mode 100644 index 0000000..bfd0e2f --- /dev/null +++ b/rust-arkworks/src/secp256k1/fields/fq.rs @@ -0,0 +1,87 @@ +use ark_ff::{ + // biginteger::BigInteger320 as BigInteger, + fields::{* /* MontConfig */}, +}; +use ark_ff_macros::MontConfig; +/* + ~~Supported BigInteger sizes:~~ + ~~256, 320, 384, 448, 768, 832~~ +*/ + +#[derive(MontConfig)] +#[modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663"] +#[generator = "3"] +#[small_subgroup_base = "3"] +#[small_subgroup_power = "1"] +pub struct FqConfig; +pub type Fq = Fp256>; + +// pub struct FqParameters; + +/* impl Fp320Parameters for FqParameters {} + +impl FftParameters for FqParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 1; + + const TWO_ADIC_ROOT_OF_UNITY: Self::BigInt = BigInteger::new([ + 0xfffffffefffffc2f, 0xfffffffefffffc2e, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000000000000000, + ]); +} + +impl FpParameters for FqParameters { + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger::new([ + 0xfffffffefffffc2f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000000000000000, + ]); + + const MODULUS_BITS: u32 = 256; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + /// The number of bits that must be shaved from the beginning of + /// the representation when randomly sampling. + const REPR_SHAVE_BITS: u32 = 64; + + /// Let `M` be the power of 2^64 nearest to `Self::MODULUS_BITS`. Then + /// `R = M % Self::MODULUS`. + /// R = M % MODULUS + #[rustfmt::skip] + const R: BigInteger = BigInteger::new([ + 0x0000000000000000, 0x00000001000003d1, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + ]); + + /// R2 = R * R % MODULUS + #[rustfmt::skip] + const R2: BigInteger = BigInteger::new([ + 0x0000000000000000, 0x0000000000000000, 0x000007a2000e90a1, 0x0000000000000001, 0x0000000000000000, + ]); + + /// INV = -MODULUS^{-1} mod 2^64 + const INV: u64 = 15580212934572586289; + + /// A multiplicative generator of the field, in Montgomery form (g * R % modulus). + /// `Self::GENERATOR` is an element having multiplicative order + /// `Self::MODULUS - 1`. In other words, the generator is the lowest value such that + /// MultiplicativeOrder(generator, p) = p - 1 where p is the modulus. + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger::new([ + 0x0000000000000000, 0x0000000300000b73, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + ]); + + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger::new([ + 0xffffffff7ffffe17, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff, 0x0000000000000000, + ]); + + #[rustfmt::skip] + const T: BigInteger = BigInteger::new([ + 0xffffffff7ffffe17, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff, 0x0000000000000000, + ]); + + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger::new([ + 0xffffffffbfffff0b, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffffffffffffff, 0x0000000000000000, + ]); +} */ diff --git a/rust-arkworks/src/secp256k1/fields/fr.rs b/rust-arkworks/src/secp256k1/fields/fr.rs new file mode 100644 index 0000000..f3864c1 --- /dev/null +++ b/rust-arkworks/src/secp256k1/fields/fr.rs @@ -0,0 +1,94 @@ +use ark_ff::{ + // biginteger::BigInteger320 as BigInteger, + fields::{ + // FftParameters, + // Fp320, + // Fp320Parameters, + // FpParameters, + Fp256, + MontBackend, + MontConfig, + }, +}; +/* + ~~Supported BigInteger sizes:~~ + ~~256, 320, 384, 448, 768, 832~~ +*/ + +#[derive(MontConfig)] +#[modulus = "115792089237316195423570985008687907852837564279074904382605163141518161494337"] +#[generator = "7"] +#[small_subgroup_base = "3"] +#[small_subgroup_power = "1"] +pub struct FrConfig; +pub type Fr = Fp256>; + +// pub struct FrParameters; + +// impl Fp320Parameters for FrParameters {} + +// impl FftParameters for FrParameters { +// type BigInt = BigInteger; + +// const TWO_ADICITY: u32 = 6; + +// const TWO_ADIC_ROOT_OF_UNITY: Self::BigInt = BigInteger::new([ +// 0x0112cb0f605a214a, 0x92225daffb794500, 0x7e42003a6ccb6212, 0x55980b07bc222114, 0x0000000000000000, +// ]); +// } + +// impl FpParameters for FrParameters { +// #[rustfmt::skip] +// const MODULUS: BigInteger = BigInteger::new([ +// 0xbfd25e8cd0364141, 0xbaaedce6af48a03b, 0xfffffffffffffffe, 0xffffffffffffffff, 0x0000000000000000, +// ]); + +// const MODULUS_BITS: u32 = 256; + +// const CAPACITY: u32 = Self::MODULUS_BITS - 1; + +// /// The number of bits that must be shaved from the beginning of +// /// the representation when randomly sampling. +// const REPR_SHAVE_BITS: u32 = 64; + +// /// Let `M` be the power of 2^64 nearest to `Self::MODULUS_BITS`. Then +// /// `R = M % Self::MODULUS`. +// /// R = M % MODULUS +// #[rustfmt::skip] +// const R: BigInteger = BigInteger::new([ +// 0x0000000000000000, 0x402da1732fc9bebf, 0x4551231950b75fc4, 0x0000000000000001, 0x0000000000000000, +// ]); + +// /// R2 = R * R % MODULUS +// #[rustfmt::skip] +// const R2: BigInteger = BigInteger::new([ +// 0x1e004f504dfd7f79, 0x08fcf59774a052ea, 0x27c4120fc94e1653, 0x3c1a6191e5702644, 0x0000000000000000, +// ]); + +// /// INV = -MODULUS^{-1} mod 2^64 +// const INV: u64 = 5408259542528602431; + +// /// A multiplicative generator of the field, in Montgomery form (g * R % modulus). +// /// `Self::GENERATOR` is an element having multiplicative order +// /// `Self::MODULUS - 1`. In other words, the generator is the lowest value such that +// /// MultiplicativeOrder(generator, p) = p - 1 where p is the modulus. +// #[rustfmt::skip] +// const GENERATOR: BigInteger = BigInteger::new([ +// 0x0000000000000000, 0xc13f6a264e843739, 0xe537f5b135039e5d, 0x0000000000000008, 0x0000000000000000, +// ]); + +// #[rustfmt::skip] +// const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger::new([ +// 0xdfe92f46681b20a0, 0x5d576e7357a4501d, 0xffffffffffffffff, 0x7fffffffffffffff, 0x0000000000000000, +// ]); + +// #[rustfmt::skip] +// const T: BigInteger = BigInteger::new([ +// 0xeeff497a3340d905, 0xfaeabb739abd2280, 0xffffffffffffffff, 0x03ffffffffffffff, 0x0000000000000000, +// ]); + +// #[rustfmt::skip] +// const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger::new([ +// 0x777fa4bd19a06c82, 0xfd755db9cd5e9140, 0xffffffffffffffff, 0x01ffffffffffffff, 0x0000000000000000, +// ]); +// } diff --git a/rust-arkworks/src/secp256k1/fields/mod.rs b/rust-arkworks/src/secp256k1/fields/mod.rs new file mode 100644 index 0000000..a426322 --- /dev/null +++ b/rust-arkworks/src/secp256k1/fields/mod.rs @@ -0,0 +1,4 @@ +pub mod fq; +pub mod fr; +pub use self::fr::*; +// pub use self::fq::*; diff --git a/rust-arkworks/src/secp256k1/mod.rs b/rust-arkworks/src/secp256k1/mod.rs new file mode 100644 index 0000000..65a6c70 --- /dev/null +++ b/rust-arkworks/src/secp256k1/mod.rs @@ -0,0 +1,21 @@ +#![deny( + warnings, + unused, + // future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![allow(rustdoc::bare_urls)] +#![forbid(unsafe_code)] + +pub mod curves; +pub use curves::*; + +pub mod fields; +pub use fields::*; + +// pub mod sec1; +// pub use sec1::*; + +// pub mod test_vectors; +mod tests; diff --git a/rust-arkworks/src/secp256k1/tests.rs b/rust-arkworks/src/secp256k1/tests.rs new file mode 100644 index 0000000..2bdf60e --- /dev/null +++ b/rust-arkworks/src/secp256k1/tests.rs @@ -0,0 +1,157 @@ +#![allow(unused_imports)] +use ark_ec::hashing::HashToCurve; +use ark_ec::AffineRepr; +use ark_ff::field_hashers::HashToField; +use ark_ff::BigInt; +// use crate::test_vectors; +// use crate::sec1::Sec1EncodePoint; +// use crate::fields::{Fr, Fq}; +// use crate::curves::*; +use ark_std::{io::BufReader, rand::Rng, string::String, test_rng, vec::Vec}; +// use ark_algebra_test_templates::{ +// fields::*, +// curves::*, +// msm::test_var_base_msm, +// groups::group_test, +// }; +// use ark_ec::{AffineCurve, ProjectiveCurve}; +use ark_ff::{ + biginteger::BigInteger320, + vec, + BigInteger, + PrimeField, + // ToBytes, + // FromBytes, + ToConstraintField, +}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::string::ToString; +use hex::ToHex; +use sha2::Sha256; + +use crate::fixed_hasher::FixedFieldHasher; +use crate::secp256k1; + +// #[test] +// fn test_fr() { +// let mut rng = test_rng(); +// for _ in 0..5 { +// let a: Fr = rng.gen(); + +// sqrt_field_test(a); +// fft_field_test::(); +// primefield_test::(); + +// let b: Fr = rng.gen(); +// field_test::(a, b); +// } +// } + +// #[test] +// fn test_fq() { +// let mut rng = test_rng(); +// for _ in 0..5 { +// let a: Fq = rng.gen(); + +// sqrt_field_test(a); +// fft_field_test::(); +// primefield_test::(); +// let b: Fq = rng.gen(); +// field_test::(a, b); +// } +// } + +// #[test] +// fn test_secp256k1_curve() { +// let mut rng = ark_std::test_rng(); +// let a: Projective = rng.gen(); +// let b: Projective = rng.gen(); +// group_test(a, b); + +// curve_tests::(); + +// test_var_base_msm::(); + +// // Fails in arkworks 0.3.0 but the next version should have a fix +// sw_tests::(); + +// test_var_base_msm::(); +// } + +#[test] +fn test_secp256k1_generator() { + let generator = super::Affine::generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_h2c() { + /* suite = secp256k1_XMD:SHA-256_SSWU_RO_ + dst = QUUX-V01-CS02-with-secp256k1_XMD:SHA-256_SSWU_RO_ + + msg = + P.x = c1cae290e291aee617ebaef1be6d73861479c48b841eaba9b7b5852ddfeb1346 + C1CAE290E291AEE617EBAEF1BE6D73861479C48B841EABA9B7B5852DDFEB1346 + P.y = 64fa678e07ae116126f08b022a94af6de15985c996c3a91b64c406a960e51067 + 64FA678E07AE116126F08B022A94AF6DE15985C996C3A91B64C406A960E51067 + u[0] = 6b0f9910dd2ba71c78f2ee9f04d73b5f4c5f7fc773a701abea1e57 + 3cab002fb3 + u[1] = 1ae6c212e08fe1a5937f6202f929a2cc8ef4ee5b9782db68b0d579 + 9fd8f09e16 + Q0.x = 74519ef88b32b425a095e4ebcc84d81b64e9e2c2675340a720bb1a + 1857b99f1e + Q0.y = c174fa322ab7c192e11748beed45b508e9fdb1ce046dee9c2cd3a2 + a86b410936 + Q1.x = 44548adb1b399263ded3510554d28b4bead34b8cf9a37b4bd0bd2b + a4db87ae63 + Q1.y = 96eb8e2faf05e368efe5957c6167001760233e6dd2487516b46ae7 + 25c4cce0c6 */ + use std::str::FromStr; + + // assert_eq!( + // ExpanderXmd::expand([]), + // hex::decode("68a985b87eb6b46952128911f2a4412bbc302a9d759667f87f7a21d803f07235") + // ); + + let dst = b"QUUX-V01-CS02-with-secp256k1_XMD:SHA-256_SSWU_RO_"; + + let defhasher: FixedFieldHasher = + as HashToField>::new(dst); + let u: [secp256k1::fq::Fq; 2] = defhasher.hash_to_field::<2>(&[]); + println!("{}", u[0]); + assert_eq!( + u[0], + secp256k1::fq::Fq::new( + BigInt::from_str( + "48425033926223359121679389614872723077618800904285921194876400224709273202611" + ) + .unwrap() + ), + ); + + assert_eq!( + ark_ec::hashing::map_to_curve_hasher::MapToCurveBasedHasher::< + ark_ec::short_weierstrass::Projective, + FixedFieldHasher, + ark_ec::hashing::curve_maps::wb::WBMap, + >::new(dst) + .unwrap() + .hash(&[]) + .unwrap(), + secp256k1::Affine::new( + secp256k1::fq::Fq::new( + BigInt::from_str( + "87654846584422849836571930156466438379984710599888121545025567473301233275718" + ) + .unwrap() + ), + secp256k1::fq::Fq::new( + BigInt::from_str( + "45673711333516174500892987253036094404176536844955599116957274814081860440167" + ) + .unwrap() + ), + ) + ); +} diff --git a/rust-arkworks/src/tests.rs b/rust-arkworks/src/tests.rs index d6b7eef..4780498 100644 --- a/rust-arkworks/src/tests.rs +++ b/rust-arkworks/src/tests.rs @@ -1,46 +1,27 @@ -use crate::hash_to_curve::{hash_to_curve, k256_affine_to_arkworks_secp256k1_affine}; -use crate::{PlumeSignature, PlumeVersion}; -use ark_ec::models::short_weierstrass_jacobian::GroupAffine; -use ark_ec::{AffineCurve, ProjectiveCurve}; -use ark_ff::biginteger; -use ark_ff::bytes::{FromBytes, ToBytes}; +mod test_vectors; + +use crate::secp256k1::{Affine, Config}; +use crate::{secp256k1, PlumeSignature, PlumeVersion}; +use ark_ec::AffineRepr; use ark_std::rand; -use k256::{ProjectivePoint, Scalar}; use rand::{prelude::ThreadRng, thread_rng}; -use secp256k1::curves::Affine; -use secp256k1::curves::Secp256k1Parameters; -use secp256k1::fields::Fq; -type Parameters = crate::Parameters; +use crate::secp256k1::fq::Fq; +use ark_ec::CurveGroup; +use ark_ff::PrimeField; +use ark_ff::{BigInt, BigInteger}; +use std::ops::Mul; + +type Parameters = crate::Parameters; fn test_template() -> (ThreadRng, Affine) { let rng = thread_rng(); - let g = Affine::prime_subgroup_generator(); + let g = Affine::generator(); (rng, g) } -#[test] -pub fn test_k256_affine_to_arkworks_secp256k1_affine() { - for i in 1..50 { - let i_u64 = i as u64; - let k256_scalar = Scalar::from(i_u64); - let ark_scalar = Fq::from(i_u64); - - // Compute g^i_u64 - let k256_pt = ProjectivePoint::GENERATOR.to_affine() * k256_scalar; - let ark_pt = Affine::prime_subgroup_generator().mul(ark_scalar); - - // Convert k256_pt to an arkworks point - let converted_pt = - k256_affine_to_arkworks_secp256k1_affine::(k256_pt.to_affine()); - - // The points should match - assert_eq!(ark_pt.into_affine(), converted_pt.unwrap()); - } -} - -fn hex_to_fr(hex: &str) -> secp256k1::fields::Fr { +fn hex_to_fr(hex: &str) -> crate::secp256k1::Fr { let num_field_bits = 320; let mut sk_bytes_vec = vec![0u8; num_field_bits]; let mut sk_bytes = hex::decode(hex).unwrap(); @@ -51,12 +32,11 @@ fn hex_to_fr(hex: &str) -> secp256k1::fields::Fr { let _ = std::mem::replace(&mut sk_bytes_vec[i], sk_bytes[i]); } - secp256k1::fields::Fr::read(sk_bytes_vec.as_slice()).unwrap() + crate::secp256k1::Fr::from_le_bytes_mod_order(sk_bytes_vec.as_slice()) } -fn coord_to_hex(coord: biginteger::BigInteger320) -> String { - let mut coord_bytes = vec![]; - let _ = coord.write(&mut coord_bytes); +fn coord_to_hex(coord: Fq) -> String { + let mut coord_bytes = coord.into_bigint().to_bytes_le(); coord_bytes.reverse(); String::from(hex::encode(coord_bytes)) @@ -79,7 +59,7 @@ pub fn test_keygen() { let (mut rng, g) = test_template(); let pp = Parameters { g_point: g }; - let (pk, sk) = PlumeSignature::keygen(&pp, &mut rng); + let (pk, sk) = PlumeSignature::keygen(&mut rng); let expected_pk = g.mul(sk); assert_eq!(pk, expected_pk); @@ -91,10 +71,9 @@ pub fn test_sign_and_verify() { let pp = Parameters { g_point: g }; let message = b"Message"; - let keypair = PlumeSignature::keygen(&pp, &mut rng); + let keypair = PlumeSignature::keygen(&mut rng); let sig = PlumeSignature::sign( - &pp, &mut rng, (&keypair.0, &keypair.1), message, @@ -106,7 +85,6 @@ pub fn test_sign_and_verify() { assert!(is_valid.unwrap()); let sig = PlumeSignature::sign( - &pp, &mut rng, (&keypair.0, &keypair.1), message, @@ -118,16 +96,15 @@ pub fn test_sign_and_verify() { assert!(is_valid.unwrap()); } -pub fn compute_h() -> GroupAffine { +pub fn hash_to_curve_with_testvalues() -> Affine { let msg = hardcoded_msg(); let message = msg.as_bytes(); let sk = hex_to_fr(&hardcoded_sk()); let (_, g) = test_template(); - let pk_projective = g.mul(sk); - let pk = GroupAffine::::from(pk_projective); + let pk_projective = g * sk; - hash_to_curve::(message, &pk).unwrap() + super::hash_to_curve(message, &pk_projective.into_affine()).unwrap() } #[test] @@ -137,121 +114,135 @@ pub fn test_against_zk_nullifier_sig_pk() { let (_, g) = test_template(); let pk_projective = g.mul(sk); - let pk = GroupAffine::::from(pk_projective); + let pk = Affine::from(pk_projective); assert_eq!( coord_to_hex(pk.x.into()), - "00000000000000000cec028ee08d09e02672a68310814354f9eabfff0de6dacc1cd3a774496076ae" + "0cec028ee08d09e02672a68310814354f9eabfff0de6dacc1cd3a774496076ae" ); assert_eq!( coord_to_hex(pk.y.into()), - "0000000000000000eff471fba0409897b6a48e8801ad12f95d0009b753cf8f51c128bf6b0bd27fbd" + "eff471fba0409897b6a48e8801ad12f95d0009b753cf8f51c128bf6b0bd27fbd" ); } #[test] pub fn test_against_zk_nullifier_sig_g_r() { // Test g^r using the hardcoded r - let r = secp256k1::fields::Fr::from(hex_to_fr(&hardcoded_r())); + let r = crate::secp256k1::Fr::from(hex_to_fr(&hardcoded_r())); let (_, g) = test_template(); let g_r_projective = g.mul(r); - let g_r = GroupAffine::::from(g_r_projective); + let g_r = Affine::from(g_r_projective); assert_eq!( coord_to_hex(g_r.x.into()), - "00000000000000009d8ca4350e7e2ad27abc6d2a281365818076662962a28429590e2dc736fe9804" + "9d8ca4350e7e2ad27abc6d2a281365818076662962a28429590e2dc736fe9804" ); assert_eq!( coord_to_hex(g_r.y.into()), - "0000000000000000ff08c30b8afd4e854623c835d9c3aac6bcebe45112472d9b9054816a7670c5a1" + "ff08c30b8afd4e854623c835d9c3aac6bcebe45112472d9b9054816a7670c5a1" ); } -//TODO: add test vectors for hash_to_curve #[test] pub fn test_against_zk_nullifier_sig_h() { - let h = compute_h(); + let h = hash_to_curve_with_testvalues(); assert_eq!( coord_to_hex(h.x.into()), - "0000000000000000bcac2d0e12679f23c218889395abcdc01f2affbc49c54d1136a2190db0800b65" + "bcac2d0e12679f23c218889395abcdc01f2affbc49c54d1136a2190db0800b65" ); assert_eq!( coord_to_hex(h.y.into()), - "00000000000000003bcfb339c974c0e757d348081f90a123b0a91a53e32b3752145d87f0cd70966e" + "3bcfb339c974c0e757d348081f90a123b0a91a53e32b3752145d87f0cd70966e" ); } #[test] pub fn test_against_zk_nullifier_sig_h_r() { - let h = compute_h(); + let h = hash_to_curve_with_testvalues(); // Test h^r using the hardcoded r - let r = secp256k1::fields::Fr::from(hex_to_fr(&hardcoded_r())); - let h_r_projective = h.mul(r); - let h_r = GroupAffine::::from(h_r_projective); + let r = crate::secp256k1::Fr::from(hex_to_fr(&hardcoded_r())); + let h_r_projective = h * r; + let h_r = Affine::from(h_r_projective); assert_eq!( coord_to_hex(h_r.x.into()), - "00000000000000006d017c6f63c59fa7a5b1e9a654e27d2869579f4d152131db270558fccd27b97c" + "6d017c6f63c59fa7a5b1e9a654e27d2869579f4d152131db270558fccd27b97c" ); assert_eq!( coord_to_hex(h_r.y.into()), - "0000000000000000586c43fb5c99818c564a8f80a88a65f83e3f44d3c6caf5a1a4e290b777ac56ed" + "586c43fb5c99818c564a8f80a88a65f83e3f44d3c6caf5a1a4e290b777ac56ed" ); } #[test] pub fn test_against_zk_nullifier_sig_h_sk() { - let h = compute_h(); + let h = hash_to_curve_with_testvalues(); let sk = hex_to_fr(&hardcoded_sk()); // Test h^r using the hardcoded sk - let h_sk_projective = h.mul(sk); - let h_sk = GroupAffine::::from(h_sk_projective); + let h_sk_projective = h * sk; + let h_sk = h_sk_projective.into_affine(); assert_eq!( coord_to_hex(h_sk.x.into()), - "000000000000000057bc3ed28172ef8adde4b9e0c2cce745fcc5a66473a45c1e626f1d0c67e55830" + "57bc3ed28172ef8adde4b9e0c2cce745fcc5a66473a45c1e626f1d0c67e55830" ); assert_eq!( coord_to_hex(h_sk.y.into()), - "00000000000000006a2f41488d58f33ae46edd2188e111609f9f3ae67ea38fa891d6087fe59ecb73" + "6a2f41488d58f33ae46edd2188e111609f9f3ae67ea38fa891d6087fe59ecb73" ); } #[test] pub fn test_against_zk_nullifier_sig_c_and_s() { - let r = secp256k1::fields::Fr::from(hex_to_fr(&hardcoded_r())); + let r = crate::secp256k1::Fr::from(hex_to_fr(&hardcoded_r())); let message = hardcoded_msg(); let message = message.as_bytes(); let sk = hex_to_fr(&hardcoded_sk()); let (_, g) = test_template(); let pp = Parameters { g_point: g }; - let pk_projective = g.mul(sk); - let pk = GroupAffine::::from(pk_projective); + let pk_projective = g * sk; + let pk = Affine::from(pk_projective); let keypair = (pk, sk); - let sig = - PlumeSignature::sign_with_r(&pp, (&keypair.0, &keypair.1), message, r, PlumeVersion::V1) - .unwrap(); + let sig = PlumeSignature::sign_with_r((&keypair.0, &keypair.1), message, r, PlumeVersion::V1) + .unwrap(); assert_eq!( - coord_to_hex(sig.c.into()), - "0000000000000000c6a7fc2c926ddbaf20731a479fb6566f2daa5514baae5223fe3b32edbce83254" + sig.c.into_bigint(), + BigInt!("0xc6a7fc2c926ddbaf20731a479fb6566f2daa5514baae5223fe3b32edbce83254") ); assert_eq!( - coord_to_hex(sig.s.into()), - "0000000000000000e69f027d84cb6fe5f761e333d12e975fb190d163e8ea132d7de0bd6079ba28ca" + sig.s.into_bigint(), + BigInt!("0xe69f027d84cb6fe5f761e333d12e975fb190d163e8ea132d7de0bd6079ba28ca") ); - let sig = - PlumeSignature::sign_with_r(&pp, (&keypair.0, &keypair.1), message, r, PlumeVersion::V2) - .unwrap(); - + let sig = PlumeSignature::sign_with_r((&keypair.0, &keypair.1), message, r, PlumeVersion::V2) + .unwrap(); + assert_eq!( - coord_to_hex(sig.c.into()), - "00000000000000003dbfb717705010d4f44a70720c95e74b475bd3a783ab0b9e8a6b3b363434eb96" + sig.c.into_bigint(), + BigInt!("0x3dbfb717705010d4f44a70720c95e74b475bd3a783ab0b9e8a6b3b363434eb96") ); assert_eq!( - coord_to_hex(sig.s.into()), - "0000000000000000528e8fbb6452f82200797b1a73b2947a92524bd611085a920f1177cb8098136b" + sig.s.into_bigint(), + BigInt!("0x528e8fbb6452f82200797b1a73b2947a92524bd611085a920f1177cb8098136b") ); } + +#[test] +fn test_point_sec1_encoding() { + let vectors = test_vectors::encoding_test_vectors(); + + let generator = secp256k1::Affine::generator(); + + for vector in vectors { + let k = vector.0; + let point = (generator * secp256k1::Fr::from(k)).into_affine(); + + assert_eq!( + super::affine_to_bytes(&point), + hex::decode(vector.1.as_bytes()).unwrap() + ); + } +} diff --git a/rust-arkworks/src/tests/test_vectors.rs b/rust-arkworks/src/tests/test_vectors.rs new file mode 100644 index 0000000..8a1226e --- /dev/null +++ b/rust-arkworks/src/tests/test_vectors.rs @@ -0,0 +1,504 @@ +pub fn encoding_test_vectors() -> Vec<(u64, String, String)> { + vec![ + ( + 0u64, + String::from("00"), + String::from("00"), + ), + ( + 1u64, + String::from("0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"), + String::from("0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"), + ), + ( + 2u64, + String::from("02C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5"), + String::from("04C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE51AE168FEA63DC339A3C58419466CEAEEF7F632653266D0E1236431A950CFE52A"), + ), + ( + 3u64, + String::from("02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9"), + String::from("04F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9388F7B0F632DE8140FE337E62A37F3566500A99934C2231B6CB9FD7584B8E672"), + ), + ( + 4u64, + String::from("02E493DBF1C10D80F3581E4904930B1404CC6C13900EE0758474FA94ABE8C4CD13"), + String::from("04E493DBF1C10D80F3581E4904930B1404CC6C13900EE0758474FA94ABE8C4CD1351ED993EA0D455B75642E2098EA51448D967AE33BFBDFE40CFE97BDC47739922"), + ), + ( + 5u64, + String::from("022F8BDE4D1A07209355B4A7250A5C5128E88B84BDDC619AB7CBA8D569B240EFE4"), + String::from("042F8BDE4D1A07209355B4A7250A5C5128E88B84BDDC619AB7CBA8D569B240EFE4D8AC222636E5E3D6D4DBA9DDA6C9C426F788271BAB0D6840DCA87D3AA6AC62D6"), + ), + ( + 6u64, + String::from("03FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A1460297556"), + String::from("04FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A1460297556AE12777AACFBB620F3BE96017F45C560DE80F0F6518FE4A03C870C36B075F297"), + ), + ( + 7u64, + String::from("025CBDF0646E5DB4EAA398F365F2EA7A0E3D419B7E0330E39CE92BDDEDCAC4F9BC"), + String::from("045CBDF0646E5DB4EAA398F365F2EA7A0E3D419B7E0330E39CE92BDDEDCAC4F9BC6AEBCA40BA255960A3178D6D861A54DBA813D0B813FDE7B5A5082628087264DA"), + ), + ( + 8u64, + String::from("022F01E5E15CCA351DAFF3843FB70F3C2F0A1BDD05E5AF888A67784EF3E10A2A01"), + String::from("042F01E5E15CCA351DAFF3843FB70F3C2F0A1BDD05E5AF888A67784EF3E10A2A015C4DA8A741539949293D082A132D13B4C2E213D6BA5B7617B5DA2CB76CBDE904"), + ), + ( + 9u64, + String::from("03ACD484E2F0C7F65309AD178A9F559ABDE09796974C57E714C35F110DFC27CCBE"), + String::from("04ACD484E2F0C7F65309AD178A9F559ABDE09796974C57E714C35F110DFC27CCBECC338921B0A7D9FD64380971763B61E9ADD888A4375F8E0F05CC262AC64F9C37"), + ), + ( + 10u64, + String::from("03A0434D9E47F3C86235477C7B1AE6AE5D3442D49B1943C2B752A68E2A47E247C7"), + String::from("04A0434D9E47F3C86235477C7B1AE6AE5D3442D49B1943C2B752A68E2A47E247C7893ABA425419BC27A3B6C7E693A24C696F794C2ED877A1593CBEE53B037368D7"), + ), + ( + 11u64, + String::from("03774AE7F858A9411E5EF4246B70C65AAC5649980BE5C17891BBEC17895DA008CB"), + String::from("04774AE7F858A9411E5EF4246B70C65AAC5649980BE5C17891BBEC17895DA008CBD984A032EB6B5E190243DD56D7B7B365372DB1E2DFF9D6A8301D74C9C953C61B"), + ), + ( + 12u64, + String::from("03D01115D548E7561B15C38F004D734633687CF4419620095BC5B0F47070AFE85A"), + String::from("04D01115D548E7561B15C38F004D734633687CF4419620095BC5B0F47070AFE85AA9F34FFDC815E0D7A8B64537E17BD81579238C5DD9A86D526B051B13F4062327"), + ), + ( + 13u64, + String::from("03F28773C2D975288BC7D1D205C3748651B075FBC6610E58CDDEEDDF8F19405AA8"), + String::from("04F28773C2D975288BC7D1D205C3748651B075FBC6610E58CDDEEDDF8F19405AA80AB0902E8D880A89758212EB65CDAF473A1A06DA521FA91F29B5CB52DB03ED81"), + ), + ( + 14u64, + String::from("03499FDF9E895E719CFD64E67F07D38E3226AA7B63678949E6E49B241A60E823E4"), + String::from("04499FDF9E895E719CFD64E67F07D38E3226AA7B63678949E6E49B241A60E823E4CAC2F6C4B54E855190F044E4A7B3D464464279C27A3F95BCC65F40D403A13F5B"), + ), + ( + 15u64, + String::from("02D7924D4F7D43EA965A465AE3095FF41131E5946F3C85F79E44ADBCF8E27E080E"), + String::from("04D7924D4F7D43EA965A465AE3095FF41131E5946F3C85F79E44ADBCF8E27E080E581E2872A86C72A683842EC228CC6DEFEA40AF2BD896D3A5C504DC9FF6A26B58"), + ), + ( + 16u64, + String::from("03E60FCE93B59E9EC53011AABC21C23E97B2A31369B87A5AE9C44EE89E2A6DEC0A"), + String::from("04E60FCE93B59E9EC53011AABC21C23E97B2A31369B87A5AE9C44EE89E2A6DEC0AF7E3507399E595929DB99F34F57937101296891E44D23F0BE1F32CCE69616821"), + ), + ( + 17u64, + String::from("03DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34"), + String::from("04DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A344211AB0694635168E997B0EAD2A93DAECED1F4A04A95C0F6CFB199F69E56EB77"), + ), + ( + 18u64, + String::from("025601570CB47F238D2B0286DB4A990FA0F3BA28D1A319F5E7CF55C2A2444DA7CC"), + String::from("045601570CB47F238D2B0286DB4A990FA0F3BA28D1A319F5E7CF55C2A2444DA7CCC136C1DC0CBEB930E9E298043589351D81D8E0BC736AE2A1F5192E5E8B061D58"), + ), + ( + 19u64, + String::from("022B4EA0A797A443D293EF5CFF444F4979F06ACFEBD7E86D277475656138385B6C"), + String::from("042B4EA0A797A443D293EF5CFF444F4979F06ACFEBD7E86D277475656138385B6C85E89BC037945D93B343083B5A1C86131A01F60C50269763B570C854E5C09B7A"), + ), + ( + 20u64, + String::from("024CE119C96E2FA357200B559B2F7DD5A5F02D5290AFF74B03F3E471B273211C97"), + String::from("044CE119C96E2FA357200B559B2F7DD5A5F02D5290AFF74B03F3E471B273211C9712BA26DCB10EC1625DA61FA10A844C676162948271D96967450288EE9233DC3A"), + ), + ( + 21u64, + String::from("02352BBF4A4CDD12564F93FA332CE333301D9AD40271F8107181340AEF25BE59D5"), + String::from("04352BBF4A4CDD12564F93FA332CE333301D9AD40271F8107181340AEF25BE59D5321EB4075348F534D59C18259DDA3E1F4A1B3B2E71B1039C67BD3D8BCF81998C"), + ), + ( + 22u64, + String::from("03421F5FC9A21065445C96FDB91C0C1E2F2431741C72713B4B99DDCB316F31E9FC"), + String::from("04421F5FC9A21065445C96FDB91C0C1E2F2431741C72713B4B99DDCB316F31E9FC2B90F16D11DABDB616F6DB7E225D1E14743034B37B223115DB20717AD1CD6781"), + ), + ( + 23u64, + String::from("032FA2104D6B38D11B0230010559879124E42AB8DFEFF5FF29DC9CDADD4ECACC3F"), + String::from("042FA2104D6B38D11B0230010559879124E42AB8DFEFF5FF29DC9CDADD4ECACC3F02DE1068295DD865B64569335BD5DD80181D70ECFC882648423BA76B532B7D67"), + ), + ( + 24u64, + String::from("03FE72C435413D33D48AC09C9161BA8B09683215439D62B7940502BDA8B202E6CE"), + String::from("04FE72C435413D33D48AC09C9161BA8B09683215439D62B7940502BDA8B202E6CE6851DE067FF24A68D3AB47E09D72998101DC88E36B4A9D22978ED2FBCF58C5BF"), + ), + ( + 25u64, + String::from("029248279B09B4D68DAB21A9B066EDDA83263C3D84E09572E269CA0CD7F5453714"), + String::from("049248279B09B4D68DAB21A9B066EDDA83263C3D84E09572E269CA0CD7F545371473016F7BF234AADE5D1AA71BDEA2B1FF3FC0DE2A887912FFE54A32CE97CB3402"), + ), + ( + 26u64, + String::from("026687CDB5B650D558F40CBDEFC8E40997C03FE1B2ABB840885E5CAD81710C4C8A"), + String::from("046687CDB5B650D558F40CBDEFC8E40997C03FE1B2ABB840885E5CAD81710C4C8A3FD502B3111178B11A1FA873825C72000EF8E529F033F272B32E83B25C83AD64"), + ), + ( + 27u64, + String::from("03DAED4F2BE3A8BF278E70132FB0BEB7522F570E144BF615C07E996D443DEE8729"), + String::from("04DAED4F2BE3A8BF278E70132FB0BEB7522F570E144BF615C07E996D443DEE8729A69DCE4A7D6C98E8D4A1ACA87EF8D7003F83C230F3AFA726AB40E52290BE1C55"), + ), + ( + 28u64, + String::from("0255EB67D7B7238A70A7FA6F64D5DC3C826B31536DA6EB344DC39A66F904F97968"), + String::from("0455EB67D7B7238A70A7FA6F64D5DC3C826B31536DA6EB344DC39A66F904F979687D916A47B2B581400B1E718BF404258540973BCE1C95052DD0689F2F493BE3C8"), + ), + ( + 29u64, + String::from("02C44D12C7065D812E8ACF28D7CBB19F9011ECD9E9FDF281B0E6A3B5E87D22E7DB"), + String::from("04C44D12C7065D812E8ACF28D7CBB19F9011ECD9E9FDF281B0E6A3B5E87D22E7DB2119A460CE326CDC76C45926C982FDAC0E106E861EDF61C5A039063F0E0E6482"), + ), + ( + 30u64, + String::from("036D2B085E9E382ED10B69FC311A03F8641CCFFF21574DE0927513A49D9A688A00"), + String::from("046D2B085E9E382ED10B69FC311A03F8641CCFFF21574DE0927513A49D9A688A00ACB82EB93309AD1CC739DDFA33604A83776238AA0BD5FF248DBAC47A17F388FB"), + ), + ( + 31u64, + String::from("026A245BF6DC698504C89A20CFDED60853152B695336C28063B61C65CBD269E6B4"), + String::from("046A245BF6DC698504C89A20CFDED60853152B695336C28063B61C65CBD269E6B4E022CF42C2BD4A708B3F5126F16A24AD8B33BA48D0423B6EFD5E6348100D8A82"), + ), + ( + 32u64, + String::from("03D30199D74FB5A22D47B6E054E2F378CEDACFFCB89904A61D75D0DBD407143E65"), + String::from("04D30199D74FB5A22D47B6E054E2F378CEDACFFCB89904A61D75D0DBD407143E6595038D9D0AE3D5C3B3D6DEC9E98380651F760CC364ED819605B3FF1F24106AB9"), + ), + ( + 33u64, + String::from("021697FFA6FD9DE627C077E3D2FE541084CE13300B0BEC1146F95AE57F0D0BD6A5"), + String::from("041697FFA6FD9DE627C077E3D2FE541084CE13300B0BEC1146F95AE57F0D0BD6A5B9C398F186806F5D27561506E4557433A2CF15009E498AE7ADEE9D63D01B2396"), + ), + ( + 34u64, + String::from("031BE68A5A028F2601D0E80D468C344BA331D611B96C358B6032E8B4DA0547FC11"), + String::from("041BE68A5A028F2601D0E80D468C344BA331D611B96C358B6032E8B4DA0547FC11BEBC47511ADE7308B3CA6265F9400779C076329C75146BC6FF1822F5D1F30E79"), + ), + ( + 35u64, + String::from("03605BDB019981718B986D0F07E834CB0D9DEB8360FFB7F61DF982345EF27A7479"), + String::from("04605BDB019981718B986D0F07E834CB0D9DEB8360FFB7F61DF982345EF27A747902972D2DE4F8D20681A78D93EC96FE23C26BFAE84FB14DB43B01E1E9056B8C49"), + ), + ( + 36u64, + String::from("02E0392CFA338AAF2F0B56C563E3E5E67A5D5FEFE3388F85D90C899DA20F0198F9"), + String::from("04E0392CFA338AAF2F0B56C563E3E5E67A5D5FEFE3388F85D90C899DA20F0198F976D458642A2C93ADEE7A347A5E4681F9BB5B10F4BD8AA51EDFD6E3F50E7DA3AC"), + ), + ( + 37u64, + String::from("0362D14DAB4150BF497402FDC45A215E10DCB01C354959B10CFE31C7E9D87FF33D"), + String::from("0462D14DAB4150BF497402FDC45A215E10DCB01C354959B10CFE31C7E9D87FF33D80FC06BD8CC5B01098088A1950EED0DB01AA132967AB472235F5642483B25EAF"), + ), + ( + 38u64, + String::from("02B699A30E6E184CDFA88AC16C7D80BFFD38E2E1FC705821EA69CD5FDF1691FFF7"), + String::from("04B699A30E6E184CDFA88AC16C7D80BFFD38E2E1FC705821EA69CD5FDF1691FFF7D505700C51D860CE5A096EE637EBED3BD9D7268126C76A16B745BC318A51AB04"), + ), + ( + 39u64, + String::from("0280C60AD0040F27DADE5B4B06C408E56B2C50E9F56B9B8B425E555C2F86308B6F"), + String::from("0480C60AD0040F27DADE5B4B06C408E56B2C50E9F56B9B8B425E555C2F86308B6F1C38303F1CC5C30F26E66BAD7FE72F70A65EED4CBE7024EB1AA01F56430BD57A"), + ), + ( + 40u64, + String::from("0391DE2F6BB67B11139F0E21203041BF080EACF59A33D99CD9F1929141BB0B4D0B"), + String::from("0491DE2F6BB67B11139F0E21203041BF080EACF59A33D99CD9F1929141BB0B4D0BEB9EF6C031EED31DE34E7A1009F8725155B03158202A9D3E9A9A2E83124A7899"), + ), + ( + 41u64, + String::from("037A9375AD6167AD54AA74C6348CC54D344CC5DC9487D847049D5EABB0FA03C8FB"), + String::from("047A9375AD6167AD54AA74C6348CC54D344CC5DC9487D847049D5EABB0FA03C8FB0D0E3FA9ECA8726909559E0D79269046BDC59EA10C70CE2B02D499EC224DC7F7"), + ), + ( + 42u64, + String::from("02FE8D1EB1BCB3432B1DB5833FF5F2226D9CB5E65CEE430558C18ED3A3C86CE1AF"), + String::from("04FE8D1EB1BCB3432B1DB5833FF5F2226D9CB5E65CEE430558C18ED3A3C86CE1AF07B158F244CD0DE2134AC7C1D371CFFBFAE4DB40801A2572E531C573CDA9B5B4"), + ), + ( + 43u64, + String::from("03D528ECD9B696B54C907A9ED045447A79BB408EC39B68DF504BB51F459BC3FFC9"), + String::from("04D528ECD9B696B54C907A9ED045447A79BB408EC39B68DF504BB51F459BC3FFC9EECF41253136E5F99966F21881FD656EBC4345405C520DBC063465B521409933"), + ), + ( + 44u64, + String::from("025D045857332D5B9E541514731622AF8D60C180165D971A61E06B70A9B3834765"), + String::from("045D045857332D5B9E541514731622AF8D60C180165D971A61E06B70A9B3834765DB2BA972802D45FD2DECBAB8D098A8C2A1D1F34761C6CF261879A7CABF06FB68"), + ), + ( + 45u64, + String::from("02049370A4B5F43412EA25F514E8ECDAD05266115E4A7ECB1387231808F8B45963"), + String::from("04049370A4B5F43412EA25F514E8ECDAD05266115E4A7ECB1387231808F8B45963758F3F41AFD6ED428B3081B0512FD62A54C3F3AFBB5B6764B653052A12949C9A"), + ), + ( + 46u64, + String::from("03F8B0B03D44112259F903B3D100E3950D980FDDE9C7E85701C16BAEDC90235717"), + String::from("04F8B0B03D44112259F903B3D100E3950D980FDDE9C7E85701C16BAEDC90235717BD8E9DC301D9ADC96BE1883B362F123BD0A986928AC79972517AB5C246242203"), + ), + ( + 47u64, + String::from("0277F230936EE88CBBD73DF930D64702EF881D811E0E1498E2F1C13EB1FC345D74"), + String::from("0477F230936EE88CBBD73DF930D64702EF881D811E0E1498E2F1C13EB1FC345D74958EF42A7886B6400A08266E9BA1B37896C95330D97077CBBE8EB3C7671C60D6"), + ), + ( + 48u64, + String::from("026ECA335D9645307DB441656EF4E65B4BFC579B27452BEBC19BD870AA1118E5C3"), + String::from("046ECA335D9645307DB441656EF4E65B4BFC579B27452BEBC19BD870AA1118E5C3D50123B57A7A0710592F579074B875A03A496A3A3BF8EC34498A2F7805A08668"), + ), + ( + 49u64, + String::from("03F2DAC991CC4CE4B9EA44887E5C7C0BCE58C80074AB9D4DBAEB28531B7739F530"), + String::from("04F2DAC991CC4CE4B9EA44887E5C7C0BCE58C80074AB9D4DBAEB28531B7739F530E0DEDC9B3B2F8DAD4DA1F32DEC2531DF9EB5FBEB0598E4FD1A117DBA703A3C37"), + ), + ( + 50u64, + String::from("0229757774CC6F3BE1D5F1774AEFA8F02E50BC64404230E7A67E8FDE79BD559A9A"), + String::from("0429757774CC6F3BE1D5F1774AEFA8F02E50BC64404230E7A67E8FDE79BD559A9AC39D07337DDC9268A0EBA45A7A41876D151B423EAC4033B550BD28C17C470134"), + ), + ( + 51u64, + String::from("02463B3D9F662621FB1B4BE8FBBE2520125A216CDFC9DAE3DEBCBA4850C690D45B"), + String::from("04463B3D9F662621FB1B4BE8FBBE2520125A216CDFC9DAE3DEBCBA4850C690D45B5ED430D78C296C3543114306DD8622D7C622E27C970A1DE31CB377B01AF7307E"), + ), + ( + 52u64, + String::from("032B22EFDA32491A9E0294339CA3DA761F7D36CFC8814C1B29CA731921025FF695"), + String::from("042B22EFDA32491A9E0294339CA3DA761F7D36CFC8814C1B29CA731921025FF6957ED520327080A9FA4C16662FC134FADCC7048846D46ADE0030B83FD19ADC87CD"), + ), + ( + 53u64, + String::from("02F16F804244E46E2A09232D4AFF3B59976B98FAC14328A2D1A32496B49998F247"), + String::from("04F16F804244E46E2A09232D4AFF3B59976B98FAC14328A2D1A32496B49998F247CEDABD9B82203F7E13D206FCDF4E33D92A6C53C26E5CCE26D6579962C4E31DF6"), + ), + ( + 54u64, + String::from("034FDCB8FA639CEE441C8331FD47A2E5FF3447BE24500CA7A5249971067C1D506B"), + String::from("044FDCB8FA639CEE441C8331FD47A2E5FF3447BE24500CA7A5249971067C1D506B25A5208B674BFD4CAE4D91EB555010AA422CC82409D5079690F3743D00FDAEFB"), + ), + ( + 55u64, + String::from("02CAF754272DC84563B0352B7A14311AF55D245315ACE27C65369E15F7151D41D1"), + String::from("04CAF754272DC84563B0352B7A14311AF55D245315ACE27C65369E15F7151D41D1CB474660EF35F5F2A41B643FA5E460575F4FA9B7962232A5C32F908318A04476"), + ), + ( + 56u64, + String::from("02BCE74DE6D5F98DC027740C2BBFF05B6AAFE5FD8D103F827E48894A2BD3460117"), + String::from("04BCE74DE6D5F98DC027740C2BBFF05B6AAFE5FD8D103F827E48894A2BD34601175BEA1FA17A41B115525A3E7DBF0D8D5A4F7CE5C6FC73A6F4F216512417C9F6B4"), + ), + ( + 57u64, + String::from("022600CA4B282CB986F85D0F1709979D8B44A09C07CB86D7C124497BC86F082120"), + String::from("042600CA4B282CB986F85D0F1709979D8B44A09C07CB86D7C124497BC86F0821204119B88753C15BD6A693B03FCDDBB45D5AC6BE74AB5F0EF44B0BE9475A7E4B40"), + ), + ( + 58u64, + String::from("0245562F033698FACA1540CBC9BF962CF4764C1EF4094EE4B6742B761C49B46D3B"), + String::from("0445562F033698FACA1540CBC9BF962CF4764C1EF4094EE4B6742B761C49B46D3B9403D11A2B419EDAACF931BFBD9C32A264558508362BC5FC99025EC62B034E02"), + ), + ( + 59u64, + String::from("037635CA72D7E8432C338EC53CD12220BC01C48685E24F7DC8C602A7746998E435"), + String::from("047635CA72D7E8432C338EC53CD12220BC01C48685E24F7DC8C602A7746998E435091B649609489D613D1D5E590F78E6D74ECFC061D57048BAD9E76F302C5B9C61"), + ), + ( + 60u64, + String::from("0301257E93A78A5B7D8FE0CF28FF1D8822350C778AC8A30E57D2ACFC4D5FB8C192"), + String::from("0401257E93A78A5B7D8FE0CF28FF1D8822350C778AC8A30E57D2ACFC4D5FB8C1921124EC11C77D356E042DAD154E1116EDA7CC69244F295166B54E3D341904A1A7"), + ), + ( + 61u64, + String::from("03754E3239F325570CDBBF4A87DEEE8A66B7F2B33479D468FBC1A50743BF56CC18"), + String::from("04754E3239F325570CDBBF4A87DEEE8A66B7F2B33479D468FBC1A50743BF56CC180673FB86E5BDA30FB3CD0ED304EA49A023EE33D0197A695D0C5D98093C536683"), + ), + ( + 62u64, + String::from("03108443B948D1553584A271333F7FBD043C4D66A91706EDECBF07F6894C04F299"), + String::from("04108443B948D1553584A271333F7FBD043C4D66A91706EDECBF07F6894C04F2994E7B5DABA34FBCF9F055520D4DB8C49FD60282D32ADFCA555B04403DB9581A9F"), + ), + ( + 63u64, + String::from("03E3E6BD1071A1E96AFF57859C82D570F0330800661D1C952F9FE2694691D9B9E8"), + String::from("04E3E6BD1071A1E96AFF57859C82D570F0330800661D1C952F9FE2694691D9B9E859C9E0BBA394E76F40C0AA58379A3CB6A5A2283993E90C4167002AF4920E37F5"), + ), + ( + 64u64, + String::from("03BF23C1542D16EAB70B1051EAF832823CFC4C6F1DCDBAFD81E37918E6F874EF8B"), + String::from("04BF23C1542D16EAB70B1051EAF832823CFC4C6F1DCDBAFD81E37918E6F874EF8B5CB3866FC33003737AD928A0BA5392E4C522FC54811E2F784DC37EFE66831D9F"), + ), + ( + 65u64, + String::from("03186B483D056A033826AE73D88F732985C4CCB1F32BA35F4B4CC47FDCF04AA6EB"), + String::from("04186B483D056A033826AE73D88F732985C4CCB1F32BA35F4B4CC47FDCF04AA6EB3B952D32C67CF77E2E17446E204180AB21FB8090895138B4A4A797F86E80888B"), + ), + ( + 66u64, + String::from("03079264C4B4BFCD7FE3A7B7B92B6C439F3A5B3ABCD29189BF7B54D781FF03D722"), + String::from("04079264C4B4BFCD7FE3A7B7B92B6C439F3A5B3ABCD29189BF7B54D781FF03D7226F6F0E0784EADA9F92999EE9C438D47EAA2C8068F1845197E3071C74B063C5E1"), + ), + ( + 67u64, + String::from("03DF9D70A6B9876CE544C98561F4BE4F725442E6D2B737D9C91A8321724CE0963F"), + String::from("04DF9D70A6B9876CE544C98561F4BE4F725442E6D2B737D9C91A8321724CE0963F55EB2DAFD84D6CCD5F862B785DC39D4AB157222720EF9DA217B8C45CF2BA2417"), + ), + ( + 68u64, + String::from("0270E6B44A2AC6083AB673BACB5CB7CA554B795B416E702C1C980BB7B87C78B8E9"), + String::from("0470E6B44A2AC6083AB673BACB5CB7CA554B795B416E702C1C980BB7B87C78B8E949BA3203048E06D84173867AB5324BE40A0D0E6436DA16754FF98B2AAE170CF8"), + ), + ( + 69u64, + String::from("025EDD5CC23C51E87A497CA815D5DCE0F8AB52554F849ED8995DE64C5F34CE7143"), + String::from("045EDD5CC23C51E87A497CA815D5DCE0F8AB52554F849ED8995DE64C5F34CE7143EFAE9C8DBC14130661E8CEC030C89AD0C13C66C0D17A2905CDC706AB7399A868"), + ), + ( + 70u64, + String::from("03C00BE8830995D1E44F1420DD3B90D3441FB66F6861C84A35F959C495A3BE5440"), + String::from("04C00BE8830995D1E44F1420DD3B90D3441FB66F6861C84A35F959C495A3BE5440ECF9665E6EBA45720DE652A340600C7356EFE24D228BFE6EA2043E7791C51BB7"), + ), + ( + 71u64, + String::from("02290798C2B6476830DA12FE02287E9E777AA3FBA1C355B17A722D362F84614FBA"), + String::from("04290798C2B6476830DA12FE02287E9E777AA3FBA1C355B17A722D362F84614FBAE38DA76DCD440621988D00BCF79AF25D5B29C094DB2A23146D003AFD41943E7A"), + ), + ( + 72u64, + String::from("03A8F2C94E19D9D829ECB4B17F84F42D8C1E988D693DF4A1FB659032865FF5154C"), + String::from("04A8F2C94E19D9D829ECB4B17F84F42D8C1E988D693DF4A1FB659032865FF5154C3F1D72D253A01DFC462E21F336A8971DFAD3DA15D691EFA4F9DDC14E86BE1EBF"), + ), + ( + 73u64, + String::from("02AF3C423A95D9F5B3054754EFA150AC39CD29552FE360257362DFDECEF4053B45"), + String::from("04AF3C423A95D9F5B3054754EFA150AC39CD29552FE360257362DFDECEF4053B45F98A3FD831EB2B749A93B0E6F35CFB40C8CD5AA667A15581BC2FEDED498FD9C6"), + ), + ( + 74u64, + String::from("032773840FCF4E9E459C052CEBBFBB7E9DFD6B072C4FBB8D476E37B93C5C478840"), + String::from("042773840FCF4E9E459C052CEBBFBB7E9DFD6B072C4FBB8D476E37B93C5C478840CC26479830E1037074EAA876AA416CF59AFD48BBC2A2CFB49D3A95324E543C49"), + ), + ( + 75u64, + String::from("02766DBB24D134E745CCCAA28C99BF274906BB66B26DCF98DF8D2FED50D884249A"), + String::from("04766DBB24D134E745CCCAA28C99BF274906BB66B26DCF98DF8D2FED50D884249A744B1152EACBE5E38DCC887980DA38B897584A65FA06CEDD2C924F97CBAC5996"), + ), + ( + 76u64, + String::from("0296516A8F65774275278D0D7420A88DF0AC44BD64C7BAE07C3FE397C5B3300B23"), + String::from("0496516A8F65774275278D0D7420A88DF0AC44BD64C7BAE07C3FE397C5B3300B23BDACD9A05FB9FB73108C0A99D567FBA9B2F75AB36207E1557F6BF255F1337FF0"), + ), + ( + 77u64, + String::from("0259DBF46F8C94759BA21277C33784F41645F7B44F6C596A58CE92E666191ABE3E"), + String::from("0459DBF46F8C94759BA21277C33784F41645F7B44F6C596A58CE92E666191ABE3EC534AD44175FBC300F4EA6CE648309A042CE739A7919798CD85E216C4A307F6E"), + ), + ( + 78u64, + String::from("032DDF7BBCFE114E807EFE354DB9F95FE70E7E555BD9114950BB3D3D987058C8AE"), + String::from("042DDF7BBCFE114E807EFE354DB9F95FE70E7E555BD9114950BB3D3D987058C8AEEC93E49C88FC85652E754603B426BC0D90F3408491C470B4EB13F199399F4EC9"), + ), + ( + 79u64, + String::from("03F13ADA95103C4537305E691E74E9A4A8DD647E711A95E73CB62DC6018CFD87B8"), + String::from("04F13ADA95103C4537305E691E74E9A4A8DD647E711A95E73CB62DC6018CFD87B8E13817B44EE14DE663BF4BC808341F326949E21A6A75C2570778419BDAF5733D"), + ), + ( + 80u64, + String::from("03E9623BBEF1BF90EC0D7C744ED34659F010E6E638637161270ECD31E14F87F62E"), + String::from("04E9623BBEF1BF90EC0D7C744ED34659F010E6E638637161270ECD31E14F87F62E38A9743B4BC299E9E0FE953A8EDAA929FE6043C9DD68844E53013EAFA44EE737"), + ), + ( + 81u64, + String::from("027754B4FA0E8ACED06D4167A2C59CCA4CDA1869C06EBADFB6488550015A88522C"), + String::from("047754B4FA0E8ACED06D4167A2C59CCA4CDA1869C06EBADFB6488550015A88522C30E93E864E669D82224B967C3020B8FA8D1E4E350B6CBCC537A48B57841163A2"), + ), + ( + 82u64, + String::from("03E35BC6BB1B05B2130A37C28E771C6CB4BE89B397B454C8B59E594FECC13B59DF"), + String::from("04E35BC6BB1B05B2130A37C28E771C6CB4BE89B397B454C8B59E594FECC13B59DF21868874CC2CB5A79C4D07D56A198DEC358EB4E66A331B76C128B757CDD92ACB"), + ), + ( + 83u64, + String::from("02948DCADF5990E048AA3874D46ABEF9D701858F95DE8041D2A6828C99E2262519"), + String::from("04948DCADF5990E048AA3874D46ABEF9D701858F95DE8041D2A6828C99E2262519E491A42537F6E597D5D28A3224B1BC25DF9154EFBD2EF1D2CBBA2CAE5347D57E"), + ), + ( + 84u64, + String::from("0287C01E27D84DA2DBD3330A7F05A58614A1ECDBABDCFCCD39E5626BAAF6812379"), + String::from("0487C01E27D84DA2DBD3330A7F05A58614A1ECDBABDCFCCD39E5626BAAF681237990E9991A7304206A64EF68644823BE8A420E76859E59E54E0E5EC95EE2A1ECEE"), + ), + ( + 85u64, + String::from("037962414450C76C1689C7B48F8202EC37FB224CF5AC0BFA1570328A8A3D7C77AB"), + String::from("047962414450C76C1689C7B48F8202EC37FB224CF5AC0BFA1570328A8A3D7C77AB100B610EC4FFB4760D5C1FC133EF6F6B12507A051F04AC5760AFA5B29DB83437"), + ), + ( + 86u64, + String::from("02497C83C39C76E56D070FB906BCED44099DE2D0E222575F22E4749682DE46EEAC"), + String::from("04497C83C39C76E56D070FB906BCED44099DE2D0E222575F22E4749682DE46EEAC9807DA341A297EE84653A557449FF8B27AE69493FDA866F8A7ED795B923B9722"), + ), + ( + 87u64, + String::from("033514087834964B54B15B160644D915485A16977225B8847BB0DD085137EC47CA"), + String::from("043514087834964B54B15B160644D915485A16977225B8847BB0DD085137EC47CAEF0AFBB2056205448E1652C48E8127FC6039E77C15C2378B7E7D15A0DE293311"), + ), + ( + 88u64, + String::from("02A8AF384E794930E63D81D3E1EF66CDAB16D1CFDA1B054DA5F7086353A80C44FE"), + String::from("04A8AF384E794930E63D81D3E1EF66CDAB16D1CFDA1B054DA5F7086353A80C44FEA24D6D07EDE1CEDECB32648C493AF7DEAF9915F0377906F1E3AB823D6581CC28"), + ), + ( + 89u64, + String::from("02D3CC30AD6B483E4BC79CE2C9DD8BC54993E947EB8DF787B442943D3F7B527EAF"), + String::from("04D3CC30AD6B483E4BC79CE2C9DD8BC54993E947EB8DF787B442943D3F7B527EAF8B378A22D827278D89C5E9BE8F9508AE3C2AD46290358630AFB34DB04EEDE0A4"), + ), + ( + 90u64, + String::from("03EB49FD9F510469F4FE540E4B0664410F216CBBC90D97AED62AF2E606110CC919"), + String::from("04EB49FD9F510469F4FE540E4B0664410F216CBBC90D97AED62AF2E606110CC9196E638DF7A9105BBC34DB14F93706891D5D6406CBFCD76E174C481324A6C8912B"), + ), + ( + 91u64, + String::from("031624D84780732860CE1C78FCBFEFE08B2B29823DB913F6493975BA0FF4847610"), + String::from("041624D84780732860CE1C78FCBFEFE08B2B29823DB913F6493975BA0FF484761068651CF9B6DA903E0914448C6CD9D4CA896878F5282BE4C8CC06E2A404078575"), + ), + ( + 92u64, + String::from("03DE1D35CBC6308CC5B435DB84A21605A7D3A6172D6511C68BF6639D49C8704818"), + String::from("04DE1D35CBC6308CC5B435DB84A21605A7D3A6172D6511C68BF6639D49C8704818D03CE0B8EF7AA8AA2AAF43C6B4E4EBF1823AC662E052FA2775D5E1F0201F1DED"), + ), + ( + 93u64, + String::from("03733CE80DA955A8A26902C95633E62A985192474B5AF207DA6DF7B4FD5FC61CD4"), + String::from("04733CE80DA955A8A26902C95633E62A985192474B5AF207DA6DF7B4FD5FC61CD4F5435A2BD2BADF7D485A4D8B8DB9FCCE3E1EF8E0201E4578C54673BC1DC5EA1D"), + ), + ( + 94u64, + String::from("0284DF2E6E5E84CDFF24120CA18648961AC134BCD7D6F35919BF6DCD5710E682F2"), + String::from("0484DF2E6E5E84CDFF24120CA18648961AC134BCD7D6F35919BF6DCD5710E682F21D1D201C7C29525CC5339C7D978E3B748935E6D57F30002A79B16D545167625E"), + ), + ( + 95u64, + String::from("0315D9441254945064CF1A1C33BBD3B49F8966C5092171E699EF258DFAB81C045C"), + String::from("0415D9441254945064CF1A1C33BBD3B49F8966C5092171E699EF258DFAB81C045CD56EB30B69463E7234F5137B73B84177434800BACEBFC685FC37BBE9EFE4070D"), + ), + ( + 96u64, + String::from("033F0E80E574456D8F8FA64E044B2EB72EA22EB53FE1EFE3A443933ACA7F8CB0E3"), + String::from("043F0E80E574456D8F8FA64E044B2EB72EA22EB53FE1EFE3A443933ACA7F8CB0E3CB66D7D7296CBC91E90B9C08485D01B39501253AA65B53A4CB0289E2EA5F404F"), + ), + ( + 97u64, + String::from("03A1D0FCF2EC9DE675B612136E5CE70D271C21417C9D2B8AAAAC138599D0717940"), + String::from("04A1D0FCF2EC9DE675B612136E5CE70D271C21417C9D2B8AAAAC138599D0717940EDD77F50BCB5A3CAB2E90737309667F2641462A54070F3D519212D39C197A629"), + ), + ( + 98u64, + String::from("024752F8548620831139BF1C39D65F194D191110FD2E9122ABD637AB63EF91E5B4"), + String::from("044752F8548620831139BF1C39D65F194D191110FD2E9122ABD637AB63EF91E5B4C80F1D852659B4186EC19E9CE26AE4BDB6F36B14FBF54AD1654F3EE5C9E6C1C2"), + ), + ( + 99u64, + String::from("02E22FBE15C0AF8CCC5780C0735F84DBE9A790BADEE8245C06C7CA37331CB36980"), + String::from("04E22FBE15C0AF8CCC5780C0735F84DBE9A790BADEE8245C06C7CA37331CB369800A855BABAD5CD60C88B430A69F53A1A7A38289154964799BE43D06D77D31DA06"), + ), + ] +} diff --git a/rust-k256/src/lib.rs b/rust-k256/src/lib.rs index f0e66dc..c4eb146 100644 --- a/rust-k256/src/lib.rs +++ b/rust-k256/src/lib.rs @@ -5,7 +5,7 @@ //! //! See for more information. //! -// Find `arkworks-rs` crate as `plume_arkworks`. +//! Find the crate to use with `arkworks-rs` crate as `plume_arkworks`. // //! # Examples //! If you want more control or to be more generic on traits `use` [`PlumeSigner`] from [`randomizedsigner`]