diff --git a/.cargo/config.toml b/.cargo/config.toml index 2f8739ee..205816c9 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -20,3 +20,6 @@ rustflags = [ "-Wunused-qualifications", "-Wclippy::unwrap_used", ] + +[target.wasm32-unknown-unknown] +rustflags = ['--cfg', 'getrandom_backend="wasm_js"'] diff --git a/Cargo.toml b/Cargo.toml index 6c5be8a5..fd3794eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ "ark-bdk-wallet", "e2e-tests", "ark-sample", - "ark-rust-secp256k1-zkp", + "ark-rust-secp256k1", "ark-dlc-sample", "ark-rs", ] diff --git a/ark-client/Cargo.toml b/ark-client/Cargo.toml index 492212d9..f8ce26df 100644 --- a/ark-client/Cargo.toml +++ b/ark-client/Cargo.toml @@ -16,12 +16,12 @@ bech32 = "0.11" bitcoin = { version = "0.32.4", features = ["rand"] } futures = "0.3.31" jiff = "0.2.1" +musig = { package = "ark-secp256k1", path = "../ark-rust-secp256k1", features = ["serde"] } prost = "0.13.3" prost-types = "0.13.3" rand = "0.8" tokio = { version = "1.41.0", features = ["sync"] } tracing = "0.1.37" -zkp = { package = "ark-secp256k1-zkp", version = "0.10.0", path = "../ark-rust-secp256k1-zkp", features = ["serde", "rand-std"] } [target.'cfg(not(all(target_arch = "wasm32", target_os = "unknown")))'.dependencies] ark-grpc = { path = "../ark-grpc", version = "0.5.9" } diff --git a/ark-core/Cargo.toml b/ark-core/Cargo.toml index 227ff7eb..631b5ddb 100644 --- a/ark-core/Cargo.toml +++ b/ark-core/Cargo.toml @@ -8,9 +8,10 @@ description = "Core types and utilities for Ark" [dependencies] bech32 = "0.11" bitcoin = { version = "0.32.4", features = ["base64", "rand"] } +musig = { package = "ark-secp256k1", path = "../ark-rust-secp256k1", features = ["serde", "rand"] } rand = "0.8" tracing = "0.1.37" -zkp = { package = "ark-secp256k1-zkp", version = "0.10.0", path = "../ark-rust-secp256k1-zkp", features = ["serde", "rand-std"] } [target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies] getrandom = { version = "0.2", features = ["wasm-bindgen", "js"] } +getrandom2 = { package = "getrandom", version = "0.3.1", features = ["wasm_js"] } diff --git a/ark-core/src/conversions.rs b/ark-core/src/conversions.rs index 84bd71bf..58cd7596 100644 --- a/ark-core/src/conversions.rs +++ b/ark-core/src/conversions.rs @@ -1,10 +1,10 @@ use bitcoin::secp256k1::PublicKey; use bitcoin::XOnlyPublicKey; -pub fn to_zkp_pk(pk: PublicKey) -> zkp::PublicKey { - zkp::PublicKey::from_slice(&pk.serialize()).expect("valid conversion") +pub fn to_musig_pk(pk: PublicKey) -> musig::PublicKey { + musig::PublicKey::from_slice(&pk.serialize()).expect("valid conversion") } -pub fn from_zkp_xonly(pk: zkp::XOnlyPublicKey) -> XOnlyPublicKey { +pub fn from_musig_xonly(pk: musig::XOnlyPublicKey) -> XOnlyPublicKey { XOnlyPublicKey::from_slice(&pk.serialize()).expect("valid conversion") } diff --git a/ark-core/src/round.rs b/ark-core/src/round.rs index ecf73992..14bd6347 100644 --- a/ark-core/src/round.rs +++ b/ark-core/src/round.rs @@ -1,5 +1,5 @@ -use crate::conversions::from_zkp_xonly; -use crate::conversions::to_zkp_pk; +use crate::conversions::from_musig_xonly; +use crate::conversions::to_musig_pk; use crate::forfeit_fee::compute_forfeit_min_relay_fee; use crate::internal_node::VtxoTreeInternalNodeScript; use crate::server::TxTree; @@ -30,17 +30,11 @@ use bitcoin::Transaction; use bitcoin::TxIn; use bitcoin::TxOut; use bitcoin::XOnlyPublicKey; +use musig::musig; use rand::CryptoRng; use rand::Rng; use std::collections::BTreeMap; use std::collections::HashMap; -use zkp::MusigAggNonce; -use zkp::MusigKeyAggCache; -use zkp::MusigPartialSignature; -use zkp::MusigPubNonce; -use zkp::MusigSecNonce; -use zkp::MusigSession; -use zkp::MusigSessionId; /// The cosigner PKs that sign a VTXO TX input are included in the `unknown` key-value map field of /// that input in the VTXO PSBT. Since the `unknown` field can be used for any purpose, we know that @@ -119,14 +113,14 @@ impl VtxoInput { /// copied. We use the [`Option`] to move it into the [`NonceTree`] during nonce generation, and out /// of the [`NonceTree`] when signing the VTXO tree. #[allow(clippy::type_complexity)] -pub struct NonceTree(Vec, MusigPubNonce)>>>); +pub struct NonceTree(Vec, musig::PublicNonce)>>>); impl NonceTree { /// Take ownership of the [`MusigSecNonce`] at level `i` and branch `j` in the tree. /// /// The caller must take ownership because the [`MusigSecNonce`] ensures that it can only be /// used once, to avoid nonce reuse. - pub fn take_sk(&mut self, i: usize, j: usize) -> Option { + pub fn take_sk(&mut self, i: usize, j: usize) -> Option { self.0 .get_mut(i) .and_then(|level| { @@ -156,11 +150,11 @@ impl NonceTree { /// A public nonce per shared internal (non-leaf) node in the VTXO tree. #[derive(Debug)] -pub struct PubNonceTree(Vec>>); +pub struct PubNonceTree(Vec>>); impl PubNonceTree { /// Get the [`MusigPubNonce`] at level `i` and branch `j` in the tree. - pub fn get(&self, i: usize, j: usize) -> Option { + pub fn get(&self, i: usize, j: usize) -> Option { self.0 .get(i) .and_then(|level| level.get(j)) @@ -169,13 +163,13 @@ impl PubNonceTree { } /// Get the underlying matrix of [`MusigPubNonce`]s. - pub fn into_inner(self) -> Vec>> { + pub fn into_inner(self) -> Vec>> { self.0 } } -impl From>>> for PubNonceTree { - fn from(value: Vec>>) -> Self { +impl From>>> for PubNonceTree { + fn from(value: Vec>>) -> Self { Self(value) } } @@ -190,7 +184,7 @@ pub fn generate_nonce_tree( where R: Rng + CryptoRng, { - let secp_zkp = zkp::Secp256k1::new(); + let secp_musig = ::musig::Secp256k1::new(); let nonce_tree = unsigned_vtxo_tree .levels @@ -207,7 +201,10 @@ where return Ok(None); } - let session_id = MusigSessionId::new(rng); + // TODO: We would like to use our own RNG here, but this library is using a + // different version of `rand`. I think it's not worth the hassle at this stage, + // particularly because this duplicated dependency will go away anyway. + let session_id = musig::SessionSecretRand::new(); let extra_rand = rng.gen(); let msg = virtual_tx_sighash(node, unsigned_vtxo_tree, i, round_tx)?; @@ -215,20 +212,21 @@ where let key_agg_cache = { let cosigner_pks = cosigner_pks .iter() - .map(|pk| to_zkp_pk(*pk)) + .map(|pk| to_musig_pk(*pk)) .collect::>(); - MusigKeyAggCache::new(&secp_zkp, &cosigner_pks) + musig::KeyAggCache::new( + &secp_musig, + &cosigner_pks.iter().collect::>(), + ) }; - let (nonce, pub_nonce) = key_agg_cache - .nonce_gen( - &secp_zkp, - session_id, - to_zkp_pk(own_cosigner_pk), - msg, - extra_rand, - ) - .map_err(Error::crypto)?; + let (nonce, pub_nonce) = key_agg_cache.nonce_gen( + &secp_musig, + session_id, + to_musig_pk(own_cosigner_pk), + msg, + extra_rand, + ); Ok(Some((Some(nonce), pub_nonce))) }) @@ -248,7 +246,7 @@ fn virtual_tx_sighash( level: usize, // The round transaction, in case it is the parent VTXO. round_tx: &Psbt, -) -> Result { +) -> Result<::musig::Message, Error> { let tx = &node.tx.unsigned_tx; // We expect a single input to a VTXO. @@ -277,17 +275,17 @@ fn virtual_tx_sighash( let tap_sighash = SighashCache::new(tx) .taproot_key_spend_signature_hash(VTXO_INPUT_INDEX, &prevouts, TapSighashType::Default) .map_err(Error::crypto)?; - let msg = zkp::Message::from_digest(tap_sighash.to_raw_hash().to_byte_array()); + let msg = ::musig::Message::from_digest(tap_sighash.to_raw_hash().to_byte_array()); Ok(msg) } /// A Musig partial signature per shared internal (non-leaf) node in the VTXO tree. -pub struct PartialSigTree(Vec>>); +pub struct PartialSigTree(Vec>>); impl PartialSigTree { /// Get the underlying matrix of [`MusigPartialSignature`]s. - pub fn into_inner(self) -> Vec>> { + pub fn into_inner(self) -> Vec>> { self.0 } } @@ -309,13 +307,13 @@ pub fn sign_vtxo_tree( let internal_node_script = VtxoTreeInternalNodeScript::new(vtxo_tree_expiry, server_pk); let secp = Secp256k1::new(); - let secp_zkp = zkp::Secp256k1::new(); + let secp_musig = ::musig::Secp256k1::new(); let own_cosigner_kp = - zkp::Keypair::from_seckey_slice(&secp_zkp, &own_cosigner_kp.secret_bytes()) + ::musig::Keypair::from_seckey_slice(&secp_musig, &own_cosigner_kp.secret_bytes()) .expect("valid keypair"); - let mut partial_sig_tree: Vec>> = Vec::new(); + let mut partial_sig_tree: Vec>> = Vec::new(); for (i, level) in vtxo_tree.levels.iter().enumerate() { let mut sigs_level = Vec::new(); for (j, node) in level.nodes.iter().enumerate() { @@ -332,19 +330,21 @@ pub fn sign_vtxo_tree( let mut key_agg_cache = { let cosigner_pks = cosigner_pks .iter() - .map(|pk| to_zkp_pk(*pk)) + .map(|pk| to_musig_pk(*pk)) .collect::>(); - MusigKeyAggCache::new(&secp_zkp, &cosigner_pks) + musig::KeyAggCache::new(&secp_musig, &cosigner_pks.iter().collect::>()) }; let sweep_tap_tree = internal_node_script - .sweep_spend_leaf(&secp, from_zkp_xonly(key_agg_cache.agg_pk())); + .sweep_spend_leaf(&secp, from_musig_xonly(key_agg_cache.agg_pk())); - let tweak = zkp::SecretKey::from_slice(sweep_tap_tree.tap_tweak().as_byte_array()) - .expect("valid conversion"); + let tweak = ::musig::Scalar::from( + ::musig::SecretKey::from_slice(sweep_tap_tree.tap_tweak().as_byte_array()) + .expect("valid conversion"), + ); key_agg_cache - .pubkey_xonly_tweak_add(&secp_zkp, tweak) + .pubkey_xonly_tweak_add(&secp_musig, &tweak) .map_err(Error::crypto)?; let agg_pub_nonce = aggregate_pub_nonce_tree @@ -352,7 +352,7 @@ pub fn sign_vtxo_tree( .ok_or_else(|| Error::crypto(format!("missing pub nonce {i}, {j}")))?; // Equivalent to parsing the individual `MusigAggNonce` from a slice. - let agg_nonce = MusigAggNonce::new(&secp_zkp, &[agg_pub_nonce]); + let agg_nonce = musig::AggregatedNonce::new(&secp_musig, &[&agg_pub_nonce]); let msg = virtual_tx_sighash(node, vtxo_tree, i, round_tx)?; @@ -360,9 +360,8 @@ pub fn sign_vtxo_tree( .take_sk(i, j) .ok_or(Error::crypto("missing nonce {i}, {j}"))?; - let sig = MusigSession::new(&secp_zkp, &key_agg_cache, agg_nonce, msg) - .partial_sign(&secp_zkp, nonce_sk, &own_cosigner_kp, &key_agg_cache) - .map_err(Error::crypto)?; + let sig = musig::Session::new(&secp_musig, &key_agg_cache, agg_nonce, msg) + .partial_sign(&secp_musig, nonce_sk, &own_cosigner_kp, &key_agg_cache); sigs_level.push(Some(sig)); } diff --git a/ark-core/src/server.rs b/ark-core/src/server.rs index 3447176d..f8d70379 100644 --- a/ark-core/src/server.rs +++ b/ark-core/src/server.rs @@ -8,6 +8,7 @@ use bitcoin::OutPoint; use bitcoin::Psbt; use bitcoin::ScriptBuf; use bitcoin::Txid; +use musig::musig; use std::collections::HashMap; #[derive(Clone, Debug)] @@ -207,7 +208,7 @@ pub struct RoundSigningEvent { #[derive(Debug, Clone)] pub struct RoundSigningNoncesGeneratedEvent { pub id: String, - pub tree_nonces: Vec>>, + pub tree_nonces: Vec>>, } #[derive(Debug, Clone)] diff --git a/ark-dlc-sample/Cargo.toml b/ark-dlc-sample/Cargo.toml index e6ac64cc..cdb3a7f5 100644 --- a/ark-dlc-sample/Cargo.toml +++ b/ark-dlc-sample/Cargo.toml @@ -10,9 +10,10 @@ ark-grpc = { path = "../ark-grpc" } bitcoin = { version = "0.32" } esplora-client = { version = "0.10", features = ["async-https"] } futures = "0.3" +musig = { package = "ark-secp256k1", path = "../ark-rust-secp256k1" } rand = "0.8" regex = "1" tokio = { version = "1", features = ["macros", "rt-multi-thread"] } tracing = "0.1" tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt", "ansi", "env-filter", "time", "tracing-log", "json"] } -zkp = { package = "ark-secp256k1-zkp", version = "0.10.0", path = "../ark-rust-secp256k1-zkp" } +zkp = { package = "secp256k1-zkp", git = "https://github.com/sanket1729/rust-secp256k1-zkp", rev = "60e631c24588a0c9e271badd61959294848c665d", features = ["rand-std"] } diff --git a/ark-dlc-sample/src/main.rs b/ark-dlc-sample/src/main.rs index 0f053517..8d36a7b4 100644 --- a/ark-dlc-sample/src/main.rs +++ b/ark-dlc-sample/src/main.rs @@ -4,8 +4,6 @@ use anyhow::Context; use anyhow::Result; use ark_core::boarding_output::list_boarding_outpoints; use ark_core::boarding_output::BoardingOutpoints; -use ark_core::conversions::from_zkp_xonly; -use ark_core::conversions::to_zkp_pk; use ark_core::redeem; use ark_core::redeem::build_redeem_transaction; use ark_core::redeem::sign_redeem_transaction; @@ -50,11 +48,11 @@ use std::collections::HashMap; use std::process::Command; use std::time::Duration; use tokio::task::block_in_place; -use zkp::musig; -use zkp::new_musig_nonce_pair; -use zkp::MusigAggNonce; -use zkp::MusigSession; -use zkp::MusigSessionId; +use zkp::musig::new_musig_nonce_pair; +use zkp::musig::MusigAggNonce; +use zkp::musig::MusigKeyAggCache; +use zkp::musig::MusigSession; +use zkp::musig::MusigSessionId; #[tokio::main] async fn main() -> Result<()> { @@ -113,7 +111,7 @@ async fn main() -> Result<()> { // Using Musig2, the server is not even aware that this is a shared VTXO. let musig_key_agg_cache = - musig::MusigKeyAggCache::new(&zkp, &[to_zkp_pk(alice_pk), to_zkp_pk(bob_pk)]); + MusigKeyAggCache::new(&zkp, &[to_zkp_pk(alice_pk), to_zkp_pk(bob_pk)]); let shared_pk = musig_key_agg_cache.agg_pk(); let shared_pk = from_zkp_xonly(shared_pk); @@ -283,7 +281,7 @@ async fn main() -> Result<()> { // Complete the adaptor signature, producing a valid signature for this CET. - let sig = musig::adapt(adaptor_sig, adaptor, musig_nonce_parity); + let sig = zkp::musig::adapt(adaptor_sig, adaptor, musig_nonce_parity); let sig = schnorr::Signature::from_slice(sig.as_ref()).expect("valid sig"); input_sig.signature = sig; @@ -433,7 +431,7 @@ fn sign_cet_redeem_tx( mut cet_redeem_psbt: Psbt, alice_kp: &Keypair, bob_kp: &Keypair, - musig_key_agg_cache: &musig::MusigKeyAggCache, + musig_key_agg_cache: &MusigKeyAggCache, adaptor_pk: zkp::PublicKey, dlc_vtxo_input: &redeem::VtxoInput, ) -> Result<(Psbt, zkp::Parity)> { @@ -823,7 +821,7 @@ pub struct SpendStatus { } impl EsploraClient { - pub fn new(url: &str) -> Result { + fn new(url: &str) -> Result { let builder = esplora_client::Builder::new(url); let esplora_client = builder.build_async()?; @@ -895,7 +893,7 @@ impl EsploraClient { } } -pub async fn faucet_fund(address: &bitcoin::Address, amount: Amount) -> Result { +async fn faucet_fund(address: &bitcoin::Address, amount: Amount) -> Result { let res = Command::new("nigiri") .args(["faucet", &address.to_string(), &amount.to_btc().to_string()]) .output()?; @@ -942,7 +940,15 @@ pub async fn faucet_fund(address: &bitcoin::Address, amount: Amount) -> Result zkp::PublicKey { + zkp::PublicKey::from_slice(&pk.serialize()).expect("valid conversion") +} + +pub fn from_zkp_xonly(pk: zkp::XOnlyPublicKey) -> XOnlyPublicKey { + XOnlyPublicKey::from_slice(&pk.serialize()).expect("valid conversion") +} + +fn init_tracing() { tracing_subscriber::fmt() .with_env_filter( "debug,\ diff --git a/ark-grpc/Cargo.toml b/ark-grpc/Cargo.toml index b622a6d0..f0db12f6 100644 --- a/ark-grpc/Cargo.toml +++ b/ark-grpc/Cargo.toml @@ -15,10 +15,10 @@ base64 = { version = "0.22", default-features = false } bitcoin = { version = "0.32", default-features = false } futures = { version = "0.3", default-features = false } log = "0.4" +musig = { package = "ark-secp256k1", path = "../ark-rust-secp256k1", features = ["serde"] } prost = { version = "0.13", default-features = false } prost-types = { version = "0.13", default-features = false } tonic = { version = "0.12", default-features = false, features = ["tls-native-roots", "transport", "codegen", "prost"] } -zkp = { package = "ark-secp256k1-zkp", version = "0.10.0", path = "../ark-rust-secp256k1-zkp", features = ["serde"] } [target.'cfg(genproto)'.build-dependencies] tonic-build = { version = "0.12" } diff --git a/ark-grpc/src/client.rs b/ark-grpc/src/client.rs index 2cddb58d..6dcd4a7a 100644 --- a/ark-grpc/src/client.rs +++ b/ark-grpc/src/client.rs @@ -50,6 +50,7 @@ use bitcoin::Txid; use futures::Stream; use futures::StreamExt; use futures::TryStreamExt; +use musig::musig; use std::collections::HashMap; use std::str::FromStr; @@ -257,7 +258,7 @@ impl Client { &self, round_id: &str, cosigner_pubkey: PublicKey, - pub_nonce_tree: Vec>>, + pub_nonce_tree: Vec>>, ) -> Result<(), Error> { let mut client = self.inner_ark_client()?; @@ -279,7 +280,7 @@ impl Client { &self, round_id: &str, cosigner_pk: PublicKey, - partial_sig_tree: Vec>>, + partial_sig_tree: Vec>>, ) -> Result<(), Error> { let mut client = self.inner_ark_client()?; diff --git a/ark-grpc/src/tree.rs b/ark-grpc/src/tree.rs index ecce21b3..a98a0829 100644 --- a/ark-grpc/src/tree.rs +++ b/ark-grpc/src/tree.rs @@ -1,23 +1,22 @@ use crate::Error; use bitcoin::hex::FromHex; +use musig::musig; use std::io; use std::io::Cursor; use std::io::Read; use std::io::Write; -use zkp::MusigPartialSignature; -use zkp::MusigPubNonce; pub trait ToBytes { fn to_bytes(&self) -> Vec; } -impl ToBytes for MusigPubNonce { +impl ToBytes for musig::PublicNonce { fn to_bytes(&self) -> Vec { self.serialize().to_vec() } } -impl ToBytes for MusigPartialSignature { +impl ToBytes for musig::PartialSignature { fn to_bytes(&self) -> Vec { self.serialize().to_vec() } @@ -29,12 +28,12 @@ pub trait FromCursor { Self: Sized; } -impl FromCursor for MusigPubNonce { +impl FromCursor for musig::PublicNonce { fn from_cursor(cursor: &mut Cursor<&Vec>) -> Result { let mut buffer = [0u8; 66]; cursor.read_exact(&mut buffer).map_err(Error::conversion)?; - MusigPubNonce::from_slice(&buffer).map_err(Error::conversion) + musig::PublicNonce::from_byte_array(&buffer).map_err(Error::conversion) } } @@ -119,21 +118,21 @@ mod tests { use super::*; use bitcoin::hex::DisplayHex; use bitcoin::hex::FromHex; - use zkp::MusigPubNonce; - use zkp::MusigSecNonce; #[test] fn nonce_tree_round_trip() { let a_bytes = Vec::from_hex("03a2ca7605303774152c9af458c9abdfa5636a8028e7bb91d4e2e6b69b60a7961e02e7d8f8d98e1b8452bec2b8132a49b97b8d3a5e8a71ce6d1b1b5a58d9263ac8dd").unwrap(); + let a_bytes: [u8; 66] = a_bytes.try_into().unwrap(); let b_bytes = Vec::from_hex("021a9d01ba9ef321b512f1368ff426bb8e9a7edf4ae5f0e65691a08eef604acfc7026fc797f4f8a81af2f44aee6084a34227c16656eececa41d550fc1f0f6fe765fd").unwrap(); + let b_bytes: [u8; 66] = b_bytes.try_into().unwrap(); let a = ( - MusigSecNonce::dangerous_from_bytes([1u8; 132]), - MusigPubNonce::from_slice(&a_bytes).unwrap(), + musig::SecretNonce::dangerous_from_bytes([1u8; 132]), + musig::PublicNonce::from_byte_array(&a_bytes).unwrap(), ); let b = ( - MusigSecNonce::dangerous_from_bytes([2u8; 132]), - MusigPubNonce::from_slice(&b_bytes).unwrap(), + musig::SecretNonce::dangerous_from_bytes([2u8; 132]), + musig::PublicNonce::from_byte_array(&b_bytes).unwrap(), ); let nonce_tree = vec![vec![Some(a.1)], vec![None, Some(b.1)]]; @@ -143,8 +142,11 @@ mod tests { let deserialized = decode_tree(serialized).unwrap(); let pub_nonce_tree = vec![ - vec![Some(MusigPubNonce::from_slice(&a_bytes).unwrap())], - vec![None, Some(MusigPubNonce::from_slice(&b_bytes).unwrap())], + vec![Some(musig::PublicNonce::from_byte_array(&a_bytes).unwrap())], + vec![ + None, + Some(musig::PublicNonce::from_byte_array(&b_bytes).unwrap()), + ], ]; assert_eq!(pub_nonce_tree, deserialized); diff --git a/ark-rust-secp256k1-zkp/.dprintrc.json b/ark-rust-secp256k1-zkp/.dprintrc.json deleted file mode 100644 index 7077da71..00000000 --- a/ark-rust-secp256k1-zkp/.dprintrc.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "https://dprint.dev/schemas/v0.json", - "projectType": "openSource", - "incremental": true, - "includes": ["**/*.{rs,md}"], - "excludes": [ - "secp256k1-zkp-sys/build.rs", - "secp256k1-zkp-sys/depend/**" - ], - "plugins": [ - "https://plugins.dprint.dev/rustfmt-0.3.0.wasm", - "https://plugins.dprint.dev/markdown-0.4.3.wasm" - ] -} diff --git a/ark-rust-secp256k1-zkp/CHANGELOG.md b/ark-rust-secp256k1-zkp/CHANGELOG.md deleted file mode 100644 index b59b6c30..00000000 --- a/ark-rust-secp256k1-zkp/CHANGELOG.md +++ /dev/null @@ -1,70 +0,0 @@ -# 0.10.0 - 2024-01-02 - -- update `secp256k1` to 0.28.0 -- update `secp256k1-sys` to 0.9.0 -- update `hashes` to 0.13.0 -- rename `bitcoin_hashes` feature to `hashes` -- bump MSRV to 1.56.1 - -# 0.9.2 - 2023-07-18 - -- Impl `Ord` for `RangeProof`, `SurjectionProof` and `PedersenCommitment` - -# 0.9.1 - 2023-06-09 - -- Add `Hash` derive to `Tweak` - -# 0.9.0 - 2023-06-08 - -- Rename `use-serde` to `serde` and `use-rand` to `rand` -- Remove unused `unstable` feature -- Add `PartialOrd`, `Ord` and `Hash` back to `Tweak` - -# 0.8.0 - 2023-04-13 - -- Increment MSRV to 1.48.0 -- Increment `secp256k1` dependency to 0.27.0 -- Update upstream to 1d256089004a19bdbead7c5676e52c8e07b09fce - -# 0.7.0 - 2022-09-27 - -- Increment MSRV to 1.41.1 and edition to 2018 -- ffi: fix signature of whitelist_sign -- Update secp256k1 to 0.24.0 and update deprecated functions -- Fix RangeProof and SurjectionProof from_str - -# 0.6.0 - 2022-03-28 - -- Update secp256k1 to 0.22.1 -- Updates upstream to 725d895fc54cf82da1c2a9c69048656405da556d -- Comment out WASM build - -# 0.5.0 - 2021-10-22 - -- Encrypt ECDSA adaptor signatures in release builds. Previously encryption returned just zero bytes. -- Add support for "whitelist" ring signatures of libsecp256k1-zkp. -- Rename `secp256k1_zkp::bitcoin_hashes` module to `secp256k1_zkp::hashes`. -- Rename feature `hashes` to `bitcoin_hashes` to align with `rust-secp256k1`. -- Implement `serde::{Serialize, Deserialize}` for `EcdsaAdaptorSignature`. - -# 0.4.0 - 2021-05-04 - -- Changed several zkp APIs to use `Tweak` type instead of `SecretKey` type to allow modelling of zero tweaks. -- Introduce `Generator::new_unblinded` and `PedersenCommitment::new_unblinded` APIs - -# 0.3.0 - 2021-04-19 - -- Add ECDSA adaptor signatures - -# 0.2.1 - 2021-04-13 - -- Fix bug in Pedersen Commitment deserialization. - -# 0.2.0 - 2021-01-06 - -- Completely replaced with https://github.com/comit-network/rust-secp256k1-zkp/ which has - bindings for generators, pedersen commitments and range proofs - -# 0.1.0 - 2019-06-03 - -- Initial release with bindings to Schnorr signatures diff --git a/ark-rust-secp256k1-zkp/Cargo.toml b/ark-rust-secp256k1-zkp/Cargo.toml deleted file mode 100644 index 4e2d0250..00000000 --- a/ark-rust-secp256k1-zkp/Cargo.toml +++ /dev/null @@ -1,48 +0,0 @@ -[package] -name = "ark-secp256k1-zkp" -version = "0.10.0" -authors = [ "Dawid Ciężarkiewicz ", - "Andrew Poelstra ", - "Lucas Soriano ", - "Thomas Eizinger " ] -license = "CC0-1.0" -homepage = "https://github.com/ElementsProject/rust-secp256k1-zkp/" -repository = "https://github.com/ElementsProject/rust-secp256k1-zkp/" -description = "Rust bindings for the `libsecp256k1-zkp` library." -keywords = [ "crypto", "ECDSA", "secp256k1-zkp", "libsecp256k1-zkp", "elements" ] -readme = "README.md" -autoexamples = false # Remove when edition 2018 https://github.com/rust-lang/cargo/issues/5330 -edition = "2018" - -# Should make docs.rs show all functions, even those behind non-default features -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[features] -default = ["std"] -std = ["secp256k1-zkp-sys/std", "secp256k1/std"] -rand-std = ["actual-rand/std", "secp256k1/rand-std"] -recovery = ["secp256k1-zkp-sys/recovery", "secp256k1/recovery"] -lowmemory = ["secp256k1-zkp-sys/lowmemory", "secp256k1/lowmemory"] -global-context = ["std", "rand-std", "secp256k1/global-context"] -hashes = ["secp256k1/hashes"] -serde = ["actual-serde", "secp256k1/serde"] -rand = ["actual-rand", "secp256k1/rand"] - -[dependencies] -actual-serde = { package = "serde", version = "1.0", default-features = false, optional = true } -actual-rand = { package = "rand", version = "0.8", default-features = false, optional = true } -secp256k1 = "0.28.0" -secp256k1-zkp-sys = { package = "ark-secp256k1-zkp-sys", version = "0.9.1", default-features = false, path = "./ark-secp256k1-zkp-sys" } -internals = { package = "bitcoin-private", version = "0.1.0" } - -[dev-dependencies] -serde_test = "1.0" - -[target.wasm32-unknown-unknown.dev-dependencies] -wasm-bindgen-test = "0.3" -getrandom = { version = "0.2", features = ["js"] } - -[lib] -crate-type = ["cdylib", "rlib"] diff --git a/ark-rust-secp256k1-zkp/Makefile b/ark-rust-secp256k1-zkp/Makefile deleted file mode 100644 index ba171527..00000000 --- a/ark-rust-secp256k1-zkp/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -test: - cargo test --features "global-context" - -build: - cargo build - diff --git a/ark-rust-secp256k1-zkp/README.md b/ark-rust-secp256k1-zkp/README.md deleted file mode 100644 index f743b5a5..00000000 --- a/ark-rust-secp256k1-zkp/README.md +++ /dev/null @@ -1,24 +0,0 @@ -![Continuous integration](https://github.com/ElementsProject/rust-secp256k1-zkp/workflows/Continuous%20integration/badge.svg) - -# rust-secp256k1-zkp - -`rust-secp256k1-zkp` is a wrapper around [libsecp256k1-zkp](https://github.com/ElementsProject/secp256k1-zkp) that also -re-exports all bindings from [`rust-secp256k1`](https://github.com/rust-bitcoin/rust-secp256k1). -As such, all of its types - `SecretKey`, `Context`, etc - are interoperable with the ones defined in `rust-secp256k1`. - -In addition to everything from `rust-secp256k1`, this library adds type-safe Rust bindings for the following modules: - -- generators -- range proofs -- pedersen commitments -- adaptor signatures - -# Contributing - -Contributions to this library are welcome. A few guidelines: - -- Any breaking changes must have an accompanied entry in CHANGELOG.md -- No new dependencies, please. -- No crypto should be implemented in Rust, with the possible exception of hash functions. Cryptographic contributions should be directed upstream to libsecp256k1. -- This library should always compile with any combination of features on **Rust 1.41.1**. - diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/CHANGELOG.md b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/CHANGELOG.md deleted file mode 100644 index f35f31ae..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/CHANGELOG.md +++ /dev/null @@ -1,12 +0,0 @@ -# 0.9.1 - 2023-01-03 - -- Many changes; restart CHANGELOG. - -# 0.2.0 - 2021-01-06 - -- Completely replaced with https://github.com/comit-network/rust-secp256k1-zkp/ which has - bindings for generators, pedersen commitments and range proofs - -# 0.1.0 - 2019-06-03 - -- Initial release with bindings to Schnorr signatures diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/Cargo.toml b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/Cargo.toml deleted file mode 100644 index 3750f1cc..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "ark-secp256k1-zkp-sys" -version = "0.9.1" -authors = [ "Dawid Ciężarkiewicz ", - "Andrew Poelstra ", - "Steven Roose ", - "Lucas Soriano ", - "Thomas Eizinger " ] -license = "CC0-1.0" -homepage = "https://github.com/ElementsProject/rust-secp256k1-zkp/" -repository = "https://github.com/ElementsProject/rust-secp256k1-zkp/" -description = "FFI for `libsecp256k1-zkp` library." -keywords = [ "secp256k1", "libsecp256k1-zkp", "ffi" ] -readme = "README.md" -build = "build.rs" -links = "rustsecp256k1zkp_v0_8_0" -edition = "2015" - -# Should make docs.rs show all functions, even those behind non-default features -[package.metadata.docs.rs] -features = [ "recovery", "lowmemory" ] - -[build-dependencies] -cc = "1.0.28" - -[dependencies] -secp256k1-sys = "0.9.0" - -[features] -default = ["std"] -recovery = ["secp256k1-sys/recovery"] -lowmemory = ["secp256k1-sys/lowmemory"] -std = [] diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/README.md b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/README.md deleted file mode 100644 index c6551cc2..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# secp256k1-zkp-sys - -This crate provides Rust definitions for the FFI structures and methods. - -## Vendoring - -The default build process is to build using the vendored libsecp256k1-zkp sources in -the depend folder. These sources are prefixed with a special -rust-secp256k1-zkp-sys-specific prefix `rustsecp256k1zkp_v1_2_3_`. - -This prefix ensures that no symbol collision can happen: - -- when a Rust project has two different versions of rust-secp256k1-zkp in its - depepdency tree, or -- when rust-secp256k1-zkp is used for building a static library in a context where - existing libsecp256k1-zkp symbols are already linked. - -To update the vendored sources, use the `vendor-libsecp.sh` script: - -``` -$ ./vendor-libsecp.sh -``` - -Where `` is the git revision of libsecp256k1 to checkout. If you do not -specify a revision, the script will simply clone the repo and use whatever -revision the default branch is pointing to. - -## Linking to external symbols - -For the more exotic use cases, this crate can be used with existing libsecp256k1-zkp -symbols by using the `external-symbols` feature. How to setup rustc to link -against those existing symbols is left as an exercise to the reader. - -## Minimum Supported Rust Version - -This library should always compile with any combination of features on **Rust 1.56.1**. diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/build.rs b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/build.rs deleted file mode 100644 index 6d6a39af..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/build.rs +++ /dev/null @@ -1,82 +0,0 @@ -#![allow(warnings)] -// Bitcoin secp256k1 bindings -// Written in 2015 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! # Build script - -// Coding conventions -#![deny(non_upper_case_globals)] -#![deny(non_camel_case_types)] -#![deny(non_snake_case)] -#![deny(unused_mut)] -#![warn(missing_docs)] - -extern crate cc; - -use std::env; - -fn main() { - if cfg!(feature = "external-symbols") { - println!("cargo:rustc-link-lib=static=secp256k1zkp"); - return; - } - - // Actual build - let mut base_config = cc::Build::new(); - base_config - .include("depend/secp256k1/") - .include("depend/secp256k1/include") - .include("depend/secp256k1/src") - .flag_if_supported("-Wno-unused-function") // some ecmult stuff is defined but not used upstream - .define("SECP256K1_BUILD", Some("")) - .define("ENABLE_MODULE_SURJECTIONPROOF", Some("1")) - .define("ENABLE_MODULE_GENERATOR", Some("1")) - .define("ENABLE_MODULE_RANGEPROOF", Some("1")) - .define("ENABLE_MODULE_ECDSA_ADAPTOR", Some("1")) - .define("ENABLE_MODULE_WHITELIST", Some("1")) - .define("ENABLE_MODULE_EXTRAKEYS", Some("1")) - .define("ENABLE_MODULE_MUSIG", Some("1")) - .define("ENABLE_MODULE_SCHNORRSIG", Some("1")) - .define("ECMULT_GEN_PREC_BITS", Some("4")) - // TODO these three should be changed to use libgmp, at least until secp PR 290 is merged - .define("USE_NUM_NONE", Some("1")) - .define("USE_FIELD_INV_BUILTIN", Some("1")) - .define("USE_SCALAR_INV_BUILTIN", Some("1")); - - if cfg!(feature = "lowmemory") { - base_config.define("ECMULT_WINDOW_SIZE", Some("4")); // A low-enough value to consume neglible memory - } else { - base_config.define("ECMULT_WINDOW_SIZE", Some("15")); // This is the default in the configure file (`auto`) - } - base_config.define("USE_EXTERNAL_DEFAULT_CALLBACKS", Some("1")); - - if let Ok(target_endian) = env::var("CARGO_CFG_TARGET_ENDIAN") { - if target_endian == "big" { - base_config.define("WORDS_BIGENDIAN", Some("1")); - } - } - - // Header files. WASM only. - if env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "wasm32" { - base_config.include("wasm-sysroot"); - } - - // secp256k1 - base_config - .file("depend/secp256k1/contrib/lax_der_parsing.c") - .file("depend/secp256k1/src/secp256k1.c") - .file("depend/secp256k1/src/precomputed_ecmult_gen.c") - .file("depend/secp256k1/src/precomputed_ecmult.c") - .compile("libsecp256k1zkp.a"); -} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1.h.patch b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1.h.patch deleted file mode 100644 index a22f8cfd..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1.h.patch +++ /dev/null @@ -1,22 +0,0 @@ -226,228d225 -< SECP256K1_API secp256k1_context* secp256k1_context_create( -< unsigned int flags -< ) SECP256K1_WARN_UNUSED_RESULT; -231,233d227 -< SECP256K1_API secp256k1_context* secp256k1_context_clone( -< const secp256k1_context* ctx -< ) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; -248,250d241 -< SECP256K1_API void secp256k1_context_destroy( -< secp256k1_context* ctx -< ) SECP256K1_ARG_NONNULL(1); -327,330d317 -< SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space* secp256k1_scratch_space_create( -< const secp256k1_context* ctx, -< size_t size -< ) SECP256K1_ARG_NONNULL(1); -338,341d324 -< SECP256K1_API void secp256k1_scratch_space_destroy( -< const secp256k1_context* ctx, -< secp256k1_scratch_space* scratch -< ) SECP256K1_ARG_NONNULL(1); diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/.cirrus.yml b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/.cirrus.yml deleted file mode 100644 index 48c9be8c..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/.cirrus.yml +++ /dev/null @@ -1,325 +0,0 @@ -env: - ### compiler options - HOST: - # Specific warnings can be disabled with -Wno-error=foo. - # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual. - WERROR_CFLAGS: -Werror -pedantic-errors - MAKEFLAGS: -j4 - BUILD: check - ### secp256k1 config - ECMULTWINDOW: auto - ECMULTGENPRECISION: auto - ASM: no - WIDEMUL: auto - WITH_VALGRIND: yes - EXTRAFLAGS: - ### secp256k1 modules - ECDH: no - RECOVERY: no - SCHNORRSIG: no - ECDSA_S2C: no - GENERATOR: no - RANGEPROOF: no - WHITELIST: no - MUSIG: no - ECDSAADAPTOR: no - BPPP: no - ### test options - SECP256K1_TEST_ITERS: - BENCH: yes - SECP256K1_BENCH_ITERS: 2 - CTIMETEST: yes - # Compile and run the tests - EXAMPLES: yes - -cat_logs_snippet: &CAT_LOGS - always: - cat_tests_log_script: - - cat tests.log || true - cat_exhaustive_tests_log_script: - - cat exhaustive_tests.log || true - cat_valgrind_ctime_test_log_script: - - cat valgrind_ctime_test.log || true - cat_bench_log_script: - - cat bench.log || true - on_failure: - cat_config_log_script: - - cat config.log || true - cat_test_env_script: - - cat test_env.log || true - cat_ci_env_script: - - env - -merge_base_script_snippet: &MERGE_BASE - merge_base_script: - - if [ "$CIRRUS_PR" = "" ]; then exit 0; fi - - git fetch $CIRRUS_REPO_CLONE_URL $CIRRUS_BASE_BRANCH - - git config --global user.email "ci@ci.ci" - - git config --global user.name "ci" - - git merge FETCH_HEAD # Merge base to detect silent merge conflicts - -linux_container_snippet: &LINUX_CONTAINER - container: - dockerfile: ci/linux-debian.Dockerfile - # Reduce number of CPUs to be able to do more builds in parallel. - cpu: 1 - # Gives us more CPUs for free if they're available. - greedy: true - # More than enough for our scripts. - memory: 1G - -task: - name: "x86_64: Linux (Debian stable)" - << : *LINUX_CONTAINER - matrix: &ENV_MATRIX - - env: {WIDEMUL: int64, RECOVERY: yes} - - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes} - - env: {WIDEMUL: int128} - - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes} - - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes} - - env: {WIDEMUL: int128, ASM: x86_64} - - env: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes} - - env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no} - - env: {CPPFLAGS: -DDETERMINISTIC} - - env: {CFLAGS: -O0, CTIMETEST: no} - - env: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } - - env: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 } - matrix: - - env: - CC: gcc - - env: - CC: clang - << : *MERGE_BASE - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "i686: Linux (Debian stable)" - << : *LINUX_CONTAINER - env: - HOST: i686-linux-gnu - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - EXPERIMENTAL: yes - ECDSA_S2C: yes - RANGEPROOF: yes - WHITELIST: yes - GENERATOR: yes - MUSIG: yes - ECDSAADAPTOR: yes - BPPP: yes - matrix: - - env: - CC: i686-linux-gnu-gcc - - env: - CC: clang --target=i686-pc-linux-gnu -isystem /usr/i686-linux-gnu/include - << : *MERGE_BASE - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "arm64: macOS Ventura" - macos_instance: - image: ghcr.io/cirruslabs/macos-ventura-base:latest - # tasks with valgrind enabled take about 90 minutes - timeout_in: 120m - env: - HOMEBREW_NO_AUTO_UPDATE: 1 - HOMEBREW_NO_INSTALL_CLEANUP: 1 - # Cirrus gives us a fixed number of 4 virtual CPUs. Not that we even have that many jobs at the moment... - MAKEFLAGS: -j5 - matrix: - << : *ENV_MATRIX - env: - ASM: no - WITH_VALGRIND: no - CTIMETEST: no - matrix: - - env: - CC: gcc - - env: - CC: clang - brew_script: - - brew install automake libtool gcc - << : *MERGE_BASE - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "s390x (big-endian): Linux (Debian stable, QEMU)" - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: qemu-s390x - SECP256K1_TEST_ITERS: 16 - HOST: s390x-linux-gnu - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - EXPERIMENTAL: yes - ECDSA_S2C: yes - RANGEPROOF: yes - WHITELIST: yes - GENERATOR: yes - MUSIG: yes - ECDSAADAPTOR: yes - BPPP: yes - CTIMETEST: no - << : *MERGE_BASE - test_script: - # https://sourceware.org/bugzilla/show_bug.cgi?id=27008 - - rm /etc/ld.so.cache - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "ARM32: Linux (Debian stable, QEMU)" - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: qemu-arm - SECP256K1_TEST_ITERS: 16 - HOST: arm-linux-gnueabihf - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - CTIMETEST: no - matrix: - - env: {} - - env: {EXPERIMENTAL: yes, ASM: arm} - << : *MERGE_BASE - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "ARM64: Linux (Debian stable, QEMU)" - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: qemu-aarch64 - SECP256K1_TEST_ITERS: 16 - HOST: aarch64-linux-gnu - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - CTIMETEST: no - << : *MERGE_BASE - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "ppc64le: Linux (Debian stable, QEMU)" - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: qemu-ppc64le - SECP256K1_TEST_ITERS: 16 - HOST: powerpc64le-linux-gnu - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - CTIMETEST: no - << : *MERGE_BASE - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)" - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: wine64-stable - SECP256K1_TEST_ITERS: 16 - HOST: x86_64-w64-mingw32 - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - CTIMETEST: no - << : *MERGE_BASE - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -# Sanitizers -task: - timeout_in: 120m - << : *LINUX_CONTAINER - env: - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - EXPERIMENTAL: yes - ECDSA_S2C: yes - RANGEPROOF: yes - WHITELIST: yes - GENERATOR: yes - MUSIG: yes - ECDSAADAPTOR: yes - BPPP: yes - CTIMETEST: no - matrix: - - name: "Valgrind (memcheck)" - container: - cpu: 2 - env: - # The `--error-exitcode` is required to make the test fail if valgrind found errors, otherwise it'll return 0 (https://www.valgrind.org/docs/manual/manual-core.html) - WRAPPER_CMD: "valgrind --error-exitcode=42" - SECP256K1_TEST_ITERS: 2 - - name: "UBSan, ASan, LSan" - container: - memory: 2G - env: - CFLAGS: "-fsanitize=undefined,address -g" - UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1" - ASAN_OPTIONS: "strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1" - LSAN_OPTIONS: "use_unaligned=1" - SECP256K1_TEST_ITERS: 32 - # Try to cover many configurations with just a tiny matrix. - matrix: - - env: - ASM: auto - - env: - ASM: no - ECMULTGENPRECISION: 2 - ECMULTWINDOW: 2 - matrix: - - env: - CC: clang - - env: - HOST: i686-linux-gnu - CC: i686-linux-gnu-gcc - << : *MERGE_BASE - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "C++ -fpermissive" - << : *LINUX_CONTAINER - env: - # ./configure correctly errors out when given CC=g++. - # We hack around this by passing CC=g++ only to make. - CC: gcc - MAKEFLAGS: -j4 CC=g++ CFLAGS=-fpermissive\ -g - WERROR_CFLAGS: - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - << : *MERGE_BASE - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "sage prover" - << : *LINUX_CONTAINER - test_script: - - cd sage - - sage prove_group_implementations.sage diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/ci/cirrus.sh b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/ci/cirrus.sh deleted file mode 100755 index 14c8dbe9..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/ci/cirrus.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/sh - -set -e -set -x - -export LC_ALL=C - -env >> test_env.log - -$CC -v || true -valgrind --version || true - -./autogen.sh - -./configure \ - --enable-experimental="$EXPERIMENTAL" \ - --with-test-override-wide-multiply="$WIDEMUL" --with-asm="$ASM" \ - --with-ecmult-window="$ECMULTWINDOW" \ - --with-ecmult-gen-precision="$ECMULTGENPRECISION" \ - --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \ - --enable-module-ecdsa-s2c="$ECDSA_S2C" \ - --enable-module-bppp="$BPPP" \ - --enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \ - --enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \ - --enable-module-schnorrsig="$SCHNORRSIG" \ - --enable-examples="$EXAMPLES" \ - --with-valgrind="$WITH_VALGRIND" \ - --host="$HOST" $EXTRAFLAGS - -# We have set "-j" in MAKEFLAGS. -make - -# Print information about binaries so that we can see that the architecture is correct -file *tests* || true -file bench* || true -file .libs/* || true - -# This tells `make check` to wrap test invocations. -export LOG_COMPILER="$WRAPPER_CMD" - -make "$BUILD" - -if [ "$BENCH" = "yes" ] -then - # Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool - EXEC='./libtool --mode=execute' - if [ -n "$WRAPPER_CMD" ] - then - EXEC="$EXEC $WRAPPER_CMD" - fi - { - $EXEC ./bench_ecmult - $EXEC ./bench_internal - $EXEC ./bench - if [ "$BPPP" = "yes" ] - then - $EXEC ./bench_bppp - fi - } >> bench.log 2>&1 -fi - -if [ "$CTIMETEST" = "yes" ] -then - ./libtool --mode=execute valgrind --error-exitcode=42 ./valgrind_ctime_test > valgrind_ctime_test.log 2>&1 -fi - -# Rebuild precomputed files (if not cross-compiling). -if [ -z "$HOST" ] -then - make clean-precomp - make precomp -fi - -# Check that no repo files have been modified by the build. -# (This fails for example if the precomp files need to be updated in the repo.) -git diff --exit-code diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/ci/linux-debian.Dockerfile b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/ci/linux-debian.Dockerfile deleted file mode 100644 index 5cccbb55..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/ci/linux-debian.Dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -FROM debian:stable - -RUN dpkg --add-architecture i386 -RUN dpkg --add-architecture s390x -RUN dpkg --add-architecture armhf -RUN dpkg --add-architecture arm64 -RUN dpkg --add-architecture ppc64el -RUN apt-get update - -# dkpg-dev: to make pkg-config work in cross-builds -# llvm: for llvm-symbolizer, which is used by clang's UBSan for symbolized stack traces -RUN apt-get install --no-install-recommends --no-upgrade -y \ - git ca-certificates \ - make automake libtool pkg-config dpkg-dev valgrind qemu-user \ - gcc clang llvm libc6-dbg \ - g++ \ - gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan6:i386 \ - gcc-s390x-linux-gnu libc6-dev-s390x-cross libc6-dbg:s390x \ - gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \ - gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 \ - gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \ - wine gcc-mingw-w64-x86-64 \ - sagemath - -# Run a dummy command in wine to make it set up configuration -RUN wine64-stable xcopy || true diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/configure.ac b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/configure.ac deleted file mode 100644 index c168694c..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/configure.ac +++ /dev/null @@ -1,573 +0,0 @@ -AC_PREREQ([2.60]) - -# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of -# the API. All changes in experimental modules are treated as -# backwards-compatible and therefore at most increase the minor version. -define(_PKG_VERSION_MAJOR, 0) -define(_PKG_VERSION_MINOR, 1) -define(_PKG_VERSION_BUILD, 0) -define(_PKG_VERSION_IS_RELEASE, false) - -# The library version is based on libtool versioning of the ABI. The set of -# rules for updating the version can be found here: -# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html -# All changes in experimental modules are treated as if they don't affect the -# interface and therefore only increase the revision. -define(_LIB_VERSION_CURRENT, 0) -define(_LIB_VERSION_REVISION, 0) -define(_LIB_VERSION_AGE, 0) - -AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_BUILD)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-pre]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1]) - -AC_CONFIG_AUX_DIR([build-aux]) -AC_CONFIG_MACRO_DIR([build-aux/m4]) -AC_CANONICAL_HOST -AH_TOP([#ifndef LIBSECP256K1_CONFIG_H]) -AH_TOP([#define LIBSECP256K1_CONFIG_H]) -AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/]) - -# Require Automake 1.11.2 for AM_PROG_AR -AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects]) - -# Make the compilation flags quiet unless V=1 is used. -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - -AC_PROG_CC -if test x"$ac_cv_prog_cc_c89" = x"no"; then - AC_MSG_ERROR([c89 compiler support required]) -fi -AM_PROG_AS -AM_PROG_AR - -LT_INIT([win32-dll]) - -build_windows=no - -case $host_os in - *darwin*) - if test x$cross_compiling != xyes; then - AC_CHECK_PROG([BREW], brew, brew) - if test x$BREW = xbrew; then - # These Homebrew packages may be keg-only, meaning that they won't be found - # in expected paths because they may conflict with system files. Ask - # Homebrew where each one is located, then adjust paths accordingly. - if $BREW list --versions valgrind >/dev/null; then - valgrind_prefix=$($BREW --prefix valgrind 2>/dev/null) - VALGRIND_CPPFLAGS="-I$valgrind_prefix/include" - fi - else - AC_CHECK_PROG([PORT], port, port) - # If homebrew isn't installed and macports is, add the macports default paths - # as a last resort. - if test x$PORT = xport; then - CPPFLAGS="$CPPFLAGS -isystem /opt/local/include" - LDFLAGS="$LDFLAGS -L/opt/local/lib" - fi - fi - fi - ;; - cygwin*|mingw*) - build_windows=yes - ;; -esac - -# Try if some desirable compiler flags are supported and append them to SECP_CFLAGS. -# -# These are our own flags, so we append them to our own SECP_CFLAGS variable (instead of CFLAGS) as -# recommended in the automake manual (Section "Flag Variables Ordering"). CFLAGS belongs to the user -# and we are not supposed to touch it. In the Makefile, we will need to ensure that SECP_CFLAGS -# is prepended to CFLAGS when invoking the compiler so that the user always has the last word (flag). -# -# Another advantage of not touching CFLAGS is that the contents of CFLAGS will be picked up by -# libtool for compiling helper executables. For example, when compiling for Windows, libtool will -# generate entire wrapper executables (instead of simple wrapper scripts as on Unix) to ensure -# proper operation of uninstalled programs linked by libtool against the uninstalled shared library. -# These executables are compiled from C source file for which our flags may not be appropriate, -# e.g., -std=c89 flag has lead to undesirable warnings in the past. -# -# TODO We should analogously not touch CPPFLAGS and LDFLAGS but currently there are no issues. -AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [ - # Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will - # not error out if it gets unknown warning flags and the checks here will always succeed - # no matter if clang knows the flag or not. - SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS" - SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS) - - SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic. - SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic. - SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers - SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall. - SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions. - SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95 - SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0 - SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only - SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0 - - CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS" -]) -SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS) - -### -### Define config arguments -### - -# In dev mode, we enable all binaries and modules by default but individual options can still be overridden explicitly. -# Check for dev mode first because SECP_SET_DEFAULT needs enable_dev_mode set. -AC_ARG_ENABLE(dev_mode, [], [], - [enable_dev_mode=no]) - -AC_ARG_ENABLE(benchmark, - AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]), [], - [SECP_SET_DEFAULT([enable_benchmark], [yes], [yes])]) - -AC_ARG_ENABLE(coverage, - AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]), [], - [SECP_SET_DEFAULT([enable_coverage], [no], [no])]) - -AC_ARG_ENABLE(tests, - AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [], - [SECP_SET_DEFAULT([enable_tests], [yes], [yes])]) - -AC_ARG_ENABLE(experimental, - AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [], - [SECP_SET_DEFAULT([enable_experimental], [no], [yes])]) - -AC_ARG_ENABLE(exhaustive_tests, - AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]), [], - [SECP_SET_DEFAULT([enable_exhaustive_tests], [yes], [yes])]) - -AC_ARG_ENABLE(examples, - AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [], - [SECP_SET_DEFAULT([enable_examples], [no], [yes])]) - -AC_ARG_ENABLE(module_bppp, - AS_HELP_STRING([--enable-module-bppp],[enable Bulletproofs++ module (experimental)]), - [], - [SECP_SET_DEFAULT([enable_module_bppp], [no], [yes])]) - -AC_ARG_ENABLE(module_ecdh, - AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=no]]), [], - [SECP_SET_DEFAULT([enable_module_ecdh], [no], [yes])]) - -AC_ARG_ENABLE(module_musig, - AS_HELP_STRING([--enable-module-musig],[enable MuSig module (experimental)]), - [], - [SECP_SET_DEFAULT([enable_module_musig], [no], [yes])]) - -AC_ARG_ENABLE(module_recovery, - AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [], - [SECP_SET_DEFAULT([enable_module_recovery], [no], [yes])]) - -AC_ARG_ENABLE(module_generator, - AS_HELP_STRING([--enable-module-generator],[enable NUMS generator module [default=no]]), - [], - [SECP_SET_DEFAULT([enable_module_generator], [no], [yes])]) - -AC_ARG_ENABLE(module_rangeproof, - AS_HELP_STRING([--enable-module-rangeproof],[enable Pedersen / zero-knowledge range proofs module [default=no]]), - [], - [SECP_SET_DEFAULT([enable_module_rangeproof], [no], [yes])]) - -AC_ARG_ENABLE(module_whitelist, - AS_HELP_STRING([--enable-module-whitelist],[enable key whitelisting module [default=no]]), - [], - [SECP_SET_DEFAULT([enable_module_whitelist], [no], [yes])]) - -AC_ARG_ENABLE(module_extrakeys, - AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=no]]), [], - [SECP_SET_DEFAULT([enable_module_extrakeys], [no], [yes])]) - -AC_ARG_ENABLE(module_schnorrsig, - AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=no]]), [], - [SECP_SET_DEFAULT([enable_module_schnorrsig], [no], [yes])]) - -AC_ARG_ENABLE(module_ecdsa_s2c, - AS_HELP_STRING([--enable-module-ecdsa-s2c],[enable ECDSA sign-to-contract module [default=no]]), - [], - [SECP_SET_DEFAULT([enable_module_ecdsa_s2c], [no], [yes])]) - -AC_ARG_ENABLE(module_ecdsa-adaptor, - AS_HELP_STRING([--enable-module-ecdsa-adaptor],[enable ECDSA adaptor module [default=no]]), - [], - [SECP_SET_DEFAULT([enable_module_ecdsa_adaptor], [no], [yes])]) - -AC_ARG_ENABLE(external_default_callbacks, - AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [], - [SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])]) - -AC_ARG_ENABLE(module_surjectionproof, - AS_HELP_STRING([--enable-module-surjectionproof],[enable surjection proof module [default=no]]), - [], - [SECP_SET_DEFAULT([enable_module_surjectionproof], [no], [yes])]) - -AC_ARG_ENABLE(reduced_surjection_proof_size, - AS_HELP_STRING([--enable-reduced-surjection-proof-size],[use reduced surjection proof size (disabling parsing and verification) [default=no]]), - [], - [SECP_SET_DEFAULT([use_reduced_surjection_proof_size], [no], [no])]) - -# Test-only override of the (autodetected by the C code) "widemul" setting. -# Legal values are int64 (for [u]int64_t), int128 (for [unsigned] __int128), and auto (the default). -AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto]) - -AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto], -[assembly optimizations to use (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto]) - -AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto], -[window size for ecmult precomputation for verification, specified as integer in range [2..24].] -[Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.] -[The table will store 2^(SIZE-1) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.] -[A window size larger than 15 will require you delete the prebuilt precomputed_ecmult.c file so that it can be rebuilt.] -[For very large window sizes, use "make -j 1" to reduce memory use during compilation.] -["auto" is a reasonable setting for desktop machines (currently 15). [default=auto]] -)], -[req_ecmult_window=$withval], [req_ecmult_window=auto]) - -AC_ARG_WITH([ecmult-gen-precision], [AS_HELP_STRING([--with-ecmult-gen-precision=2|4|8|auto], -[Precision bits to tune the precomputed table size for signing.] -[The size of the table is 32kB for 2 bits, 64kB for 4 bits, 512kB for 8 bits of precision.] -[A larger table size usually results in possible faster signing.] -["auto" is a reasonable setting for desktop machines (currently 4). [default=auto]] -)], -[req_ecmult_gen_precision=$withval], [req_ecmult_gen_precision=auto]) - -AC_ARG_WITH([valgrind], [AS_HELP_STRING([--with-valgrind=yes|no|auto], -[Build with extra checks for running inside Valgrind [default=auto]] -)], -[req_valgrind=$withval], [req_valgrind=auto]) - -### -### Handle config options (except for modules) -### - -if test x"$req_valgrind" = x"no"; then - enable_valgrind=no -else - SECP_VALGRIND_CHECK - if test x"$has_valgrind" != x"yes"; then - if test x"$req_valgrind" = x"yes"; then - AC_MSG_ERROR([Valgrind support explicitly requested but valgrind/memcheck.h header not available]) - fi - enable_valgrind=no - else - enable_valgrind=yes - fi -fi -AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"]) - -if test x"$enable_coverage" = x"yes"; then - AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code]) - SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS" - LDFLAGS="--coverage $LDFLAGS" -else - # Most likely the CFLAGS already contain -O2 because that is autoconf's default. - # We still add it here because passing it twice is not an issue, and handling - # this case would just add unnecessary complexity (see #896). - SECP_CFLAGS="-O2 $SECP_CFLAGS" -fi - -AC_MSG_CHECKING([for __builtin_popcount]) -AC_LINK_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_popcount(0);}]])], - [ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_POPCOUNT,1,[Define this symbol if __builtin_popcount is available]) ], - [ AC_MSG_RESULT([no]) - ]) - -AC_MSG_CHECKING([for __builtin_clzll]) -AC_LINK_IFELSE([AC_LANG_SOURCE([[void myfunc() { __builtin_clzll(1);}]])], - [ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_CLZLL,1,[Define this symbol if __builtin_clzll is available]) ], - [ AC_MSG_RESULT([no]) - ]) - -if test x"$req_asm" = x"auto"; then - SECP_64BIT_ASM_CHECK - if test x"$has_64bit_asm" = x"yes"; then - set_asm=x86_64 - fi - if test x"$set_asm" = x; then - set_asm=no - fi -else - set_asm=$req_asm - case $set_asm in - x86_64) - SECP_64BIT_ASM_CHECK - if test x"$has_64bit_asm" != x"yes"; then - AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) - fi - ;; - arm) - ;; - no) - ;; - *) - AC_MSG_ERROR([invalid assembly optimization selection]) - ;; - esac -fi - -# Select assembly optimization -enable_external_asm=no - -case $set_asm in -x86_64) - AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations]) - ;; -arm) - enable_external_asm=yes - ;; -no) - ;; -*) - AC_MSG_ERROR([invalid assembly optimizations]) - ;; -esac - -if test x"$enable_external_asm" = x"yes"; then - AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used]) -fi - - -# Select wide multiplication implementation -case $set_widemul in -int128) - AC_DEFINE(USE_FORCE_WIDEMUL_INT128, 1, [Define this symbol to force the use of the (unsigned) __int128 based wide multiplication implementation]) - ;; -int64) - AC_DEFINE(USE_FORCE_WIDEMUL_INT64, 1, [Define this symbol to force the use of the (u)int64_t based wide multiplication implementation]) - ;; -auto) - ;; -*) - AC_MSG_ERROR([invalid wide multiplication implementation]) - ;; -esac - -# Set ecmult window size -if test x"$req_ecmult_window" = x"auto"; then - set_ecmult_window=15 -else - set_ecmult_window=$req_ecmult_window -fi - -error_window_size=['window size for ecmult precomputation not an integer in range [2..24] or "auto"'] -case $set_ecmult_window in -''|*[[!0-9]]*) - # no valid integer - AC_MSG_ERROR($error_window_size) - ;; -*) - if test "$set_ecmult_window" -lt 2 -o "$set_ecmult_window" -gt 24 ; then - # not in range - AC_MSG_ERROR($error_window_size) - fi - AC_DEFINE_UNQUOTED(ECMULT_WINDOW_SIZE, $set_ecmult_window, [Set window size for ecmult precomputation]) - ;; -esac - -# Set ecmult gen precision -if test x"$req_ecmult_gen_precision" = x"auto"; then - set_ecmult_gen_precision=4 -else - set_ecmult_gen_precision=$req_ecmult_gen_precision -fi - -case $set_ecmult_gen_precision in -2|4|8) - AC_DEFINE_UNQUOTED(ECMULT_GEN_PREC_BITS, $set_ecmult_gen_precision, [Set ecmult gen precision bits]) - ;; -*) - AC_MSG_ERROR(['ecmult gen precision not 2, 4, 8 or "auto"']) - ;; -esac - -if test x"$enable_valgrind" = x"yes"; then - SECP_INCLUDES="$SECP_INCLUDES $VALGRIND_CPPFLAGS" -fi - -# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI) -SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS" - -### -### Handle module options -### - -# Besides testing whether modules are enabled, the following code also enables -# module dependencies. The order of the tests matters: the dependency must be -# tested first. - -if test x"$enable_module_ecdh" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module]) -fi - -if test x"$enable_module_musig" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_MUSIG, 1, [Define this symbol to enable the MuSig module]) - enable_module_schnorrsig=yes -fi - -if test x"$enable_module_recovery" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module]) -fi - -if test x"$enable_module_whitelist" = x"yes"; then - enable_module_rangeproof=yes - AC_DEFINE(ENABLE_MODULE_WHITELIST, 1, [Define this symbol to enable the key whitelisting module]) -fi - -if test x"$enable_module_surjectionproof" = x"yes"; then - enable_module_rangeproof=yes - AC_DEFINE(ENABLE_MODULE_SURJECTIONPROOF, 1, [Define this symbol to enable the surjection proof module]) -fi - -if test x"$enable_module_rangeproof" = x"yes"; then - enable_module_generator=yes - AC_DEFINE(ENABLE_MODULE_RANGEPROOF, 1, [Define this symbol to enable the Pedersen / zero knowledge range proof module]) -fi - -if test x"$enable_module_bppp" = x"yes"; then - enable_module_generator=yes - AC_DEFINE(ENABLE_MODULE_BPPP, 1, [Define this symbol to enable the Bulletproofs++ module]) -fi - -if test x"$enable_module_generator" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_GENERATOR, 1, [Define this symbol to enable the NUMS generator module]) -fi - -if test x"$enable_module_schnorrsig" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_SCHNORRSIG, 1, [Define this symbol to enable the schnorrsig module]) - enable_module_extrakeys=yes -fi - -if test x"$enable_module_extrakeys" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_EXTRAKEYS, 1, [Define this symbol to enable the extrakeys module]) -fi - -if test x"$enable_module_ecdsa_s2c" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_ECDSA_S2C, 1, [Define this symbol to enable the ECDSA sign-to-contract module]) -fi - -if test x"$enable_external_default_callbacks" = x"yes"; then - AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used]) -fi - -if test x"$use_reduced_surjection_proof_size" = x"yes"; then - AC_DEFINE(USE_REDUCED_SURJECTION_PROOF_SIZE, 1, [Define this symbol to reduce SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS to 16, disabling parsing and verification]) -fi - -if test x"$enable_module_ecdsa_adaptor" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_ECDSA_ADAPTOR, 1, [Define this symbol to enable the ECDSA adaptor module]) -fi - -### -### Check for --enable-experimental if necessary -### - -if test x"$enable_experimental" = x"yes"; then - AC_MSG_NOTICE([******]) - AC_MSG_NOTICE([WARNING: experimental build]) - AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.]) - AC_MSG_NOTICE([******]) -else - # The order of the following tests matters. If the user enables a dependent - # module (which automatically enables the module dependencies) we want to - # print an error for the dependent module, not the module dependency. Hence, - # we first test dependent modules. - if test x"$enable_module_bppp" = x"yes"; then - AC_MSG_ERROR([Bulletproofs++ module is experimental. Use --enable-experimental to allow.]) - fi - if test x"$enable_module_whitelist" = x"yes"; then - AC_MSG_ERROR([Key whitelisting module is experimental. Use --enable-experimental to allow.]) - fi - if test x"$enable_module_surjectionproof" = x"yes"; then - AC_MSG_ERROR([Surjection proof module is experimental. Use --enable-experimental to allow.]) - fi - if test x"$enable_module_rangeproof" = x"yes"; then - AC_MSG_ERROR([Range proof module is experimental. Use --enable-experimental to allow.]) - fi - if test x"$enable_module_generator" = x"yes"; then - AC_MSG_ERROR([NUMS generator module is experimental. Use --enable-experimental to allow.]) - fi - if test x"$enable_module_musig" = x"yes"; then - AC_MSG_ERROR([MuSig module is experimental. Use --enable-experimental to allow.]) - fi - if test x"$enable_module_ecdsa_s2c" = x"yes"; then - AC_MSG_ERROR([ECDSA sign-to-contract module module is experimental. Use --enable-experimental to allow.]) - fi - if test x"$enable_module_ecdsa_adaptor" = x"yes"; then - AC_MSG_ERROR([ecdsa adaptor signatures module is experimental. Use --enable-experimental to allow.]) - fi - if test x"$set_asm" = x"arm"; then - AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.]) - fi -fi - -### -### Generate output -### - -AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) -AC_CONFIG_FILES([Makefile libsecp256k1.pc]) -AC_SUBST(SECP_INCLUDES) -AC_SUBST(SECP_LIBS) -AC_SUBST(SECP_TEST_LIBS) -AC_SUBST(SECP_TEST_INCLUDES) -AC_SUBST(SECP_CFLAGS) -AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) -AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"]) -AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"]) -AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"]) -AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_BPPP], [test x"$enable_module_bppp" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_GENERATOR], [test x"$enable_module_generator" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_RANGEPROOF], [test x"$enable_module_rangeproof" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_WHITELIST], [test x"$enable_module_whitelist" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_ECDSA_S2C], [test x"$enable_module_ecdsa_s2c" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_ECDSA_ADAPTOR], [test x"$enable_module_ecdsa_adaptor" = x"yes"]) -AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"]) -AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"]) -AM_CONDITIONAL([ENABLE_MODULE_SURJECTIONPROOF], [test x"$enable_module_surjectionproof" = x"yes"]) -AM_CONDITIONAL([USE_REDUCED_SURJECTION_PROOF_SIZE], [test x"$use_reduced_surjection_proof_size" = x"yes"]) -AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"]) -AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT) -AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION) -AC_SUBST(LIB_VERSION_AGE, _LIB_VERSION_AGE) - -AC_OUTPUT - -echo -echo "Build Options:" -echo " with external callbacks = $enable_external_default_callbacks" -echo " with benchmarks = $enable_benchmark" -echo " with tests = $enable_tests" -echo " with coverage = $enable_coverage" -echo " with examples = $enable_examples" -echo " module ecdh = $enable_module_ecdh" -echo " module recovery = $enable_module_recovery" -echo " module extrakeys = $enable_module_extrakeys" -echo " module schnorrsig = $enable_module_schnorrsig" -echo " module generator = $enable_module_generator" -echo " module rangeproof = $enable_module_rangeproof" -echo " module surjectionproof = $enable_module_surjectionproof" -echo " module whitelist = $enable_module_whitelist" -echo " module musig = $enable_module_musig" -echo " module ecdsa-s2c = $enable_module_ecdsa_s2c" -echo " module ecdsa-adaptor = $enable_module_ecdsa_adaptor" -echo " module bppp = $enable_module_bppp" -echo -echo " asm = $set_asm" -echo " ecmult window size = $set_ecmult_window" -echo " ecmult gen prec. bits = $set_ecmult_gen_precision" -# Hide test-only options unless they're used. -if test x"$set_widemul" != xauto; then -echo " wide multiplication = $set_widemul" -fi -echo -echo " valgrind = $enable_valgrind" -echo " CC = $CC" -echo " CPPFLAGS = $CPPFLAGS" -echo " SECP_CFLAGS = $SECP_CFLAGS" -echo " CFLAGS = $CFLAGS" -echo " LDFLAGS = $LDFLAGS" diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/sync-upstream.sh b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/sync-upstream.sh deleted file mode 100755 index f4ccc449..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/sync-upstream.sh +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env bash - -set -eou pipefail - -help() { - echo "$0 range [end]" - echo " merges every merge commit present in upstream and missing locally." - echo " If the optional [end] commit is provided, only merges up to [end]." - echo - echo "$0 select ... " - echo " merges every selected merge commit" - echo - echo "This tool creates a branch and a script that can be executed to create the" - echo "PR automatically. The script requires the github-cli tool (aka gh)." - echo "" - echo "Tip: \`git log --oneline upstream/master --merges\` shows merge commits." - exit 1 -} - -if [ "$#" -lt 1 ]; then - help -fi - -REMOTE=upstream -REMOTE_BRANCH="$REMOTE/master" -# Makes sure you have a remote "upstream" that is up-to-date -setup() { - ret=0 - git fetch "$REMOTE" &> /dev/null || ret="$?" - if [ ${ret} == 0 ]; then - return - fi - echo "Adding remote \"$REMOTE\" with URL git@github.com:bitcoin-core/secp256k1.git. Continue with y" - read -r yn - case $yn in - [Yy]* ) ;; - * ) exit 1;; - esac - git remote add "$REMOTE" git@github.com:bitcoin-core/secp256k1.git &> /dev/null - git fetch "$REMOTE" &> /dev/null -} - -range() { - RANGESTART_COMMIT=$(git merge-base "$REMOTE_BRANCH" master) - RANGEEND_COMMIT=$(git rev-parse "$REMOTE_BRANCH") - if [ "$#" = 1 ]; then - RANGEEND_COMMIT=$1 - fi - - COMMITS=$(git --no-pager log --oneline --merges "$RANGESTART_COMMIT".."$RANGEEND_COMMIT") - COMMITS=$(echo "$COMMITS" | tac | awk '{ print $1 }' ORS=' ') - echo "Merging $COMMITS. Continue with y" - read -r yn - case $yn in - [Yy]* ) ;; - * ) exit 1;; - esac -} - -case $1 in - range) - shift - setup - range "$@" - REPRODUCE_COMMAND="$0 range $RANGEEND_COMMIT" - ;; - select) - shift - setup - COMMITS=$* - REPRODUCE_COMMAND="$0 select $@" - ;; - help) - help - ;; - *) - help -esac - -TITLE="Upstream PRs" -BODY="" -for COMMIT in $COMMITS -do - PRNUM=$(git log -1 "$COMMIT" --pretty=format:%s | sed s/'Merge \(bitcoin-core\/secp256k1\)\?#\([0-9]*\).*'/'\2'/) - TITLE="$TITLE $PRNUM," - BODY=$(printf "%s\n%s" "$BODY" "$(git log -1 "$COMMIT" --pretty=format:%s | sed s/'Merge \(bitcoin-core\/secp256k1\)\?#\([0-9]*\)'/'[bitcoin-core\/secp256k1#\2]'/)") -done -# Remove trailing "," -TITLE=${TITLE%?} - -BODY=$(printf "%s\n\n%s" "$BODY" "This PR can be recreated with \`$REPRODUCE_COMMAND\`.") - -echo "-----------------------------------" -echo "$TITLE" -echo "-----------------------------------" -echo "$BODY" -echo "-----------------------------------" -# Create branch from PR commit and create PR -git checkout master -git pull -git checkout -b temp-merge-"$PRNUM" - -# Escape single quote -# ' -> '\'' -quote() { - local quoted=${1//\'/\'\\\'\'} - printf "%s" "$quoted" -} -TITLE=$(quote "$TITLE") -BODY=$(quote "$BODY") - -BASEDIR=$(dirname "$0") -FNAME="$BASEDIR/gh-pr-create.sh" -cat < "$FNAME" -#!/bin/sh -gh pr create -t '$TITLE' -b '$BODY' --web -# Remove temporary branch -git checkout master -git branch -D temp-merge-"$PRNUM" -EOT -chmod +x "$FNAME" -echo Run "$FNAME" after solving the merge conflicts - -git merge --no-edit -m "Merge commits '$COMMITS' into temp-merge-$PRNUM" $COMMITS diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/doc/CHANGELOG.md b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/doc/CHANGELOG.md deleted file mode 100644 index 3c4c2e45..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/doc/CHANGELOG.md +++ /dev/null @@ -1,12 +0,0 @@ -# Changelog - -This file is currently only a template for future use. - -Each change falls into one of the following categories: Added, Changed, Deprecated, Removed, Fixed or Security. - -## [Unreleased] - -## [MAJOR.MINOR.PATCH] - YYYY-MM-DD - -### Added/Changed/Deprecated/Removed/Fixed/Security -- [Title with link to Pull Request](https://link-to-pr) diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/doc/musig-spec.mediawiki b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/doc/musig-spec.mediawiki deleted file mode 100644 index 017a0c3e..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/doc/musig-spec.mediawiki +++ /dev/null @@ -1 +0,0 @@ -This document was moved to [https://github.com/jonasnick/bips/blob/musig2/bip-musig2.mediawiki https://github.com/jonasnick/bips/blob/musig2/bip-musig2.mediawiki]. \ No newline at end of file diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/doc/release-process.md b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/doc/release-process.md deleted file mode 100644 index a35b8a9d..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/doc/release-process.md +++ /dev/null @@ -1,14 +0,0 @@ -# Release Process - -1. Open PR to master that - 1. adds release notes to `doc/CHANGELOG.md` and - 2. if this is **not** a patch release, updates `_PKG_VERSION_{MAJOR,MINOR}` and `_LIB_VERSIONS_*` in `configure.ac` -2. After the PR is merged, - * if this is **not** a patch release, create a release branch with name `MAJOR.MINOR`. - Make sure that the branch contains the right commits. - Create commit on the release branch that sets `_PKG_VERSION_IS_RELEASE` in `configure.ac` to `true`. - * if this **is** a patch release, open a pull request with the bugfixes to the `MAJOR.MINOR` branch. - Also include the release note commit bump `_PKG_VERSION_BUILD` and `_LIB_VERSIONS_*` in `configure.ac`. -4. Tag the commit with `git tag -s vMAJOR.MINOR.PATCH`. -5. Push branch and tag with `git push origin --tags`. -6. Create a new GitHub release with a link to the corresponding entry in `doc/CHANGELOG.md`. diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/musig.c b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/musig.c deleted file mode 100644 index b901669f..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/musig.c +++ /dev/null @@ -1,212 +0,0 @@ -/************************************************************************* - * Written in 2018 by Jonas Nick * - * To the extent possible under law, the author(s) have dedicated all * - * copyright and related and neighboring rights to the software in this * - * file to the public domain worldwide. This software is distributed * - * without any warranty. For the CC0 Public Domain Dedication, see * - * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * - *************************************************************************/ - -/** This file demonstrates how to use the MuSig module to create a - * 3-of-3 multisignature. Additionally, see the documentation in - * include/rustsecp256k1zkp_v0_8_0_musig.h and src/modules/musig/musig.md. - */ - -#include -#include -#include -#include -#include - -#include "random.h" - -struct signer_secrets { - rustsecp256k1zkp_v0_8_0_keypair keypair; - rustsecp256k1zkp_v0_8_0_musig_secnonce secnonce; -}; - -struct signer { - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_musig_pubnonce pubnonce; - rustsecp256k1zkp_v0_8_0_musig_partial_sig partial_sig; -}; - - /* Number of public keys involved in creating the aggregate signature */ -#define N_SIGNERS 3 -/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */ -int create_keypair(const rustsecp256k1zkp_v0_8_0_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) { - unsigned char seckey[32]; - while (1) { - if (!fill_random(seckey, sizeof(seckey))) { - printf("Failed to generate randomness\n"); - return 1; - } - if (rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &signer_secrets->keypair, seckey)) { - break; - } - } - if (!rustsecp256k1zkp_v0_8_0_keypair_pub(ctx, &signer->pubkey, &signer_secrets->keypair)) { - return 0; - } - return 1; -} - -/* Tweak the pubkey corresponding to the provided keyagg cache, update the cache - * and return the tweaked aggregate pk. */ -int tweak(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_xonly_pubkey *agg_pk, rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *cache) { - rustsecp256k1zkp_v0_8_0_pubkey output_pk; - unsigned char plain_tweak[32] = "this could be a BIP32 tweak...."; - unsigned char xonly_tweak[32] = "this could be a taproot tweak.."; - - - /* Plain tweaking which, for example, allows deriving multiple child - * public keys from a single aggregate key using BIP32 */ - if (!rustsecp256k1zkp_v0_8_0_musig_pubkey_ec_tweak_add(ctx, NULL, cache, plain_tweak)) { - return 0; - } - /* Note that we did not provided an output_pk argument, because the - * resulting pk is also saved in the cache and so if one is just interested - * in signing the output_pk argument is unnecessary. On the other hand, if - * one is not interested in signing, the same output_pk can be obtained by - * calling `rustsecp256k1zkp_v0_8_0_musig_pubkey_get` right after key aggregation to get - * the full pubkey and then call `rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add`. */ - - /* Xonly tweaking which, for example, allows creating taproot commitments */ - if (!rustsecp256k1zkp_v0_8_0_musig_pubkey_xonly_tweak_add(ctx, &output_pk, cache, xonly_tweak)) { - return 0; - } - /* Note that if we wouldn't care about signing, we can arrive at the same - * output_pk by providing the untweaked public key to - * `rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add` (after converting it to an xonly pubkey - * if necessary with `rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey`). */ - - /* Now we convert the output_pk to an xonly pubkey to allow to later verify - * the Schnorr signature against it. For this purpose we can ignore the - * `pk_parity` output argument; we would need it if we would have to open - * the taproot commitment. */ - if (!rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(ctx, agg_pk, NULL, &output_pk)) { - return 0; - } - return 1; -} - -/* Sign a message hash with the given key pairs and store the result in sig */ -int sign(const rustsecp256k1zkp_v0_8_0_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *cache, const unsigned char *msg32, unsigned char *sig64) { - int i; - const rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonces[N_SIGNERS]; - const rustsecp256k1zkp_v0_8_0_musig_partial_sig *partial_sigs[N_SIGNERS]; - /* The same for all signers */ - rustsecp256k1zkp_v0_8_0_musig_session session; - - for (i = 0; i < N_SIGNERS; i++) { - unsigned char seckey[32]; - unsigned char session_id[32]; - /* Create random session ID. It is absolutely necessary that the session ID - * is unique for every call of rustsecp256k1zkp_v0_8_0_musig_nonce_gen. Otherwise - * it's trivial for an attacker to extract the secret key! */ - if (!fill_random(session_id, sizeof(session_id))) { - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) { - return 0; - } - /* Initialize session and create secret nonce for signing and public - * nonce to send to the other signers. */ - if (!rustsecp256k1zkp_v0_8_0_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_id, seckey, &signer[i].pubkey, msg32, NULL, NULL)) { - return 0; - } - pubnonces[i] = &signer[i].pubnonce; - } - /* Communication round 1: A production system would exchange public nonces - * here before moving on. */ - for (i = 0; i < N_SIGNERS; i++) { - rustsecp256k1zkp_v0_8_0_musig_aggnonce agg_pubnonce; - - /* Create aggregate nonce and initialize the session */ - if (!rustsecp256k1zkp_v0_8_0_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, N_SIGNERS)) { - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_musig_nonce_process(ctx, &session, &agg_pubnonce, msg32, cache, NULL)) { - return 0; - } - /* partial_sign will clear the secnonce by setting it to 0. That's because - * you must _never_ reuse the secnonce (or use the same session_id to - * create a secnonce). If you do, you effectively reuse the nonce and - * leak the secret key. */ - if (!rustsecp256k1zkp_v0_8_0_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, cache, &session)) { - return 0; - } - partial_sigs[i] = &signer[i].partial_sig; - } - /* Communication round 2: A production system would exchange - * partial signatures here before moving on. */ - for (i = 0; i < N_SIGNERS; i++) { - /* To check whether signing was successful, it suffices to either verify - * the aggregate signature with the aggregate public key using - * rustsecp256k1zkp_v0_8_0_schnorrsig_verify, or verify all partial signatures of all - * signers individually. Verifying the aggregate signature is cheaper but - * verifying the individual partial signatures has the advantage that it - * can be used to determine which of the partial signatures are invalid - * (if any), i.e., which of the partial signatures cause the aggregate - * signature to be invalid and thus the protocol run to fail. It's also - * fine to first verify the aggregate sig, and only verify the individual - * sigs if it does not work. - */ - if (!rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(ctx, &signer[i].partial_sig, &signer[i].pubnonce, &signer[i].pubkey, cache, &session)) { - return 0; - } - } - return rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(ctx, sig64, &session, partial_sigs, N_SIGNERS); -} - - int main(void) { - rustsecp256k1zkp_v0_8_0_context* ctx; - int i; - struct signer_secrets signer_secrets[N_SIGNERS]; - struct signer signers[N_SIGNERS]; - const rustsecp256k1zkp_v0_8_0_pubkey *pubkeys_ptr[N_SIGNERS]; - rustsecp256k1zkp_v0_8_0_xonly_pubkey agg_pk; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache cache; - unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!"; - unsigned char sig[64]; - - /* Create a context for signing and verification */ - ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - printf("Creating key pairs......"); - for (i = 0; i < N_SIGNERS; i++) { - if (!create_keypair(ctx, &signer_secrets[i], &signers[i])) { - printf("FAILED\n"); - return 1; - } - pubkeys_ptr[i] = &signers[i].pubkey; - } - printf("ok\n"); - printf("Combining public keys..."); - /* If you just want to aggregate and not sign the cache can be NULL */ - if (!rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(ctx, NULL, &agg_pk, &cache, pubkeys_ptr, N_SIGNERS)) { - printf("FAILED\n"); - return 1; - } - printf("ok\n"); - printf("Tweaking................"); - /* Optionally tweak the aggregate key */ - if (!tweak(ctx, &agg_pk, &cache)) { - printf("FAILED\n"); - return 1; - } - printf("ok\n"); - printf("Signing message........."); - if (!sign(ctx, signer_secrets, signers, &cache, msg, sig)) { - printf("FAILED\n"); - return 1; - } - printf("ok\n"); - printf("Verifying signature....."); - if (!rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig, msg, 32, &agg_pk)) { - printf("FAILED\n"); - return 1; - } - printf("ok\n"); - rustsecp256k1zkp_v0_8_0_context_destroy(ctx); - return 0; -} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_bppp.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_bppp.h deleted file mode 100644 index ede04ae3..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_bppp.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef _SECP256K1_BPPP_ -# define _SECP256K1_BPPP_ - -#include "secp256k1.h" - -# ifdef __cplusplus -extern "C" { -# endif - -#include - -/** Opaque structure representing a large number of NUMS generators */ -typedef struct rustsecp256k1zkp_v0_8_0_bppp_generators rustsecp256k1zkp_v0_8_0_bppp_generators; - -/** Allocates and initializes a list of NUMS generators. - * Returns a list of generators, or calls the error callback if the allocation fails. - * Args: ctx: pointer to a context object - * n: number of NUMS generators to produce. - * - * TODO: In a followup range-proof PR, this is would still require 16 + 8 = 24 NUMS - * points. We will later use G = H0(required for compatibility with pedersen_commitment DS) - * in a separate commit to make review easier. - */ -SECP256K1_API rustsecp256k1zkp_v0_8_0_bppp_generators *rustsecp256k1zkp_v0_8_0_bppp_generators_create( - const rustsecp256k1zkp_v0_8_0_context* ctx, - size_t n -) SECP256K1_ARG_NONNULL(1); - -/** Allocates a list of generators from a static array - * Returns a list of generators or NULL in case of failure. - * Args: ctx: pointer to a context object - * In: data: data that came from `rustsecp256k1zkp_v0_8_0_bppp_generators_serialize` - * data_len: the length of the `data` buffer - */ -SECP256K1_API rustsecp256k1zkp_v0_8_0_bppp_generators* rustsecp256k1zkp_v0_8_0_bppp_generators_parse( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const unsigned char* data, - size_t data_len -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - -/** Serializes a list of generators to an array - * Returns 1 on success, 0 if the provided array was not large enough - * Args: ctx: pointer to a context object - * gen: pointer to the generator set to be serialized - * Out: data: pointer to buffer into which the generators will be serialized - * In/Out: data_len: the length of the `data` buffer. Should be at least - * k = 33 * num_gens. Will be set to k on successful return - * - * TODO: For ease of review, this setting G = H0 is not included in this commit. We will - * add it in the follow-up rangeproof PR. - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_bppp_generators_serialize( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_bppp_generators* gen, - unsigned char* data, - size_t *data_len -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Destroys a list of NUMS generators, freeing allocated memory - * Args: ctx: pointer to a context object - * gen: pointer to the generator set to be destroyed - * (can be NULL, in which case this function is a no-op) - */ -SECP256K1_API void rustsecp256k1zkp_v0_8_0_bppp_generators_destroy( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_bppp_generators* gen -) SECP256K1_ARG_NONNULL(1); - -# ifdef __cplusplus -} -# endif - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_ecdsa_adaptor.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_ecdsa_adaptor.h deleted file mode 100644 index d836bf6f..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_ecdsa_adaptor.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef SECP256K1_ECDSA_ADAPTOR_H -#define SECP256K1_ECDSA_ADAPTOR_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** This module implements single signer ECDSA adaptor signatures following - * "One-Time Verifiably Encrypted Signatures A.K.A. Adaptor Signatures" by - * Lloyd Fournier - * (https://lists.linuxfoundation.org/pipermail/lightning-dev/2019-November/002316.html - * and https://github.com/LLFourn/one-time-VES/blob/master/main.pdf). - * - * WARNING! DANGER AHEAD! - * As mentioned in Lloyd Fournier's paper, the adaptor signature leaks the - * Elliptic-curve Diffie–Hellman (ECDH) key between the signing key and the - * encryption key. This is not a problem for ECDSA adaptor signatures - * themselves, but may result in a complete loss of security when they are - * composed with other schemes. More specifically, let us refer to the - * signer's public key as X = x*G, and to the encryption key as Y = y*G. - * Given X, Y and the adaptor signature, it is trivial to compute Y^x = X^y. - * - * A defense is to not reuse the signing key of ECDSA adaptor signatures in - * protocols that rely on the hardness of the CDH problem, e.g., Diffie-Hellman - * key exchange and ElGamal encryption. In general, it is a well-established - * cryptographic practice to seperate keys for different purposes whenever - * possible. - */ - -/** A pointer to a function to deterministically generate a nonce. - * - * Same as rustsecp256k1zkp_v0_8_0_nonce_function_hardened with the exception of using the - * compressed 33-byte encoding for the pubkey argument. - * - * Returns: 1 if a nonce was successfully generated. 0 will cause signing to - * return an error. - * Out: nonce32: pointer to a 32-byte array to be filled by the function - * In: msg32: the 32-byte message hash being verified - * key32: pointer to a 32-byte secret key - * pk33: the 33-byte serialized pubkey corresponding to key32 - * algo: pointer to an array describing the signature algorithm - * algolen: the length of the algo array - * data: arbitrary data pointer that is passed through - * - * Except for test cases, this function should compute some cryptographic hash of - * the message, the key, the pubkey, the algorithm description, and data. - */ -typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function_hardened_ecdsa_adaptor)( - unsigned char *nonce32, - const unsigned char *msg32, - const unsigned char *key32, - const unsigned char *pk33, - const unsigned char *algo, - size_t algolen, - void *data -); - -/** A modified BIP-340 nonce generation function. If a data pointer is passed, it is - * assumed to be a pointer to 32 bytes of auxiliary random data as defined in BIP-340. - * The hash will be tagged with algo after removing all terminating null bytes. - */ -SECP256K1_API extern const rustsecp256k1zkp_v0_8_0_nonce_function_hardened_ecdsa_adaptor rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor; - -/** Encrypted Signing - * - * Creates an adaptor signature, which includes a proof to verify the adaptor - * signature. - * WARNING: Make sure you have read and understood the WARNING at the top of - * this file and applied the suggested countermeasures. - * - * Returns: 1 on success, 0 on failure - * Args: ctx: a secp256k1 context object, initialized for signing - * Out: adaptor_sig162: pointer to 162 byte to store the returned signature - * In: seckey32: pointer to 32 byte secret key that will be used for - * signing - * enckey: pointer to the encryption public key - * msg32: pointer to the 32-byte message hash to sign - * noncefp: pointer to a nonce generation function. If NULL, - * rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor is used - * ndata: pointer to arbitrary data used by the nonce generation - * function (can be NULL). If it is non-NULL and - * rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor is used, then - * ndata must be a pointer to 32-byte auxiliary randomness - * as per BIP-340. - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *adaptor_sig162, - unsigned char *seckey32, - const rustsecp256k1zkp_v0_8_0_pubkey *enckey, - const unsigned char *msg32, - rustsecp256k1zkp_v0_8_0_nonce_function_hardened_ecdsa_adaptor noncefp, - void *ndata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -/** Encryption Verification - * - * Verifies that the adaptor decryption key can be extracted from the adaptor signature - * and the completed ECDSA signature. - * - * Returns: 1 on success, 0 on failure - * Args: ctx: a secp256k1 context object, initialized for verification - * In: adaptor_sig162: pointer to 162-byte signature to verify - * pubkey: pointer to the public key corresponding to the secret key - * used for signing - * msg32: pointer to the 32-byte message hash being verified - * enckey: pointer to the adaptor encryption public key - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const unsigned char *adaptor_sig162, - const rustsecp256k1zkp_v0_8_0_pubkey *pubkey, - const unsigned char *msg32, - const rustsecp256k1zkp_v0_8_0_pubkey *enckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -/** Signature Decryption - * - * Derives an ECDSA signature from an adaptor signature and an adaptor decryption key. - * - * Returns: 1 on success, 0 on failure - * Args: ctx: a secp256k1 context object - * Out: sig: pointer to the ECDSA signature to create - * In: deckey32: pointer to 32-byte decryption secret key for the adaptor - * encryption public key - * adaptor_sig162: pointer to 162-byte adaptor sig - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_signature *sig, - const unsigned char *deckey32, - const unsigned char *adaptor_sig162 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Decryption Key Recovery - * - * Extracts the adaptor decryption key from the complete signature and the adaptor - * signature. - * - * Returns: 1 on success, 0 on failure - * Args: ctx: a secp256k1 context object, initialized for signing - * Out: deckey32: pointer to 32-byte adaptor decryption key for the adaptor - * encryption public key - * In: sig: pointer to ECDSA signature to recover the adaptor decryption - * key from - * adaptor_sig162: pointer to adaptor signature to recover the adaptor - * decryption key from - * enckey: pointer to the adaptor encryption public key - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *deckey32, - const rustsecp256k1zkp_v0_8_0_ecdsa_signature *sig, - const unsigned char *adaptor_sig162, - const rustsecp256k1zkp_v0_8_0_pubkey *enckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_ECDSA_ADAPTOR_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_ecdsa_s2c.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_ecdsa_s2c.h deleted file mode 100644 index 08d51f23..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_ecdsa_s2c.h +++ /dev/null @@ -1,234 +0,0 @@ -#ifndef SECP256K1_ECDSA_S2C_H -#define SECP256K1_ECDSA_S2C_H - -#include "secp256k1.h" - -/** This module implements the sign-to-contract scheme for ECDSA signatures, as - * well as the "ECDSA Anti-Exfil Protocol" that is based on sign-to-contract - * and is specified further down. The sign-to-contract scheme allows creating a - * signature that also commits to some data. This works by offsetting the public - * nonce point of the signature R by hash(R, data)*G where G is the secp256k1 - * group generator. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** Data structure that holds a sign-to-contract ("s2c") opening information. - * Sign-to-contract allows a signer to commit to some data as part of a signature. It - * can be used as an Out-argument in certain signing functions. - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. It is - * however guaranteed to be 64 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage, transmission, or - * comparison, use rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_serialize and rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_parse. - */ -typedef struct { - unsigned char data[64]; -} rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening; - -/** Parse a sign-to-contract opening. - * - * Returns: 1 if the opening could be parsed - * 0 if the opening could not be parsed - * Args: ctx: a secp256k1 context object. - * Out: opening: pointer to an opening object. If 1 is returned, it is set to a - * parsed version of input. If not, its value is unspecified. - * In: input33: pointer to 33-byte array with a serialized opening - * - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_parse( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* opening, - const unsigned char* input33 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize a sign-to-contract opening into a byte sequence. - * - * Returns: 1 if the opening was successfully serialized. - * 0 if the opening could not be serialized - * Args: ctx: a secp256k1 context object - * Out: output33: pointer to a 33-byte array to place the serialized opening in - * In: opening: a pointer to an initialized `rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening` - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_serialize( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char* output33, - const rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* opening -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Same as rustsecp256k1zkp_v0_8_0_ecdsa_sign, but s2c_data32 is committed to inside the nonce - * - * Returns: 1: signature created - * 0: the nonce generation function failed, or the private key was invalid. - * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) - * s2c_opening: if non-NULL, pointer to an rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening structure to populate - * In: msg32: the 32-byte message hash being signed (cannot be NULL) - * seckey: pointer to a 32-byte secret key (cannot be NULL) - * s2c_data32: pointer to a 32-byte data to commit to in the nonce (cannot be NULL) - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, - rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* s2c_opening, - const unsigned char* msg32, - const unsigned char* seckey, - const unsigned char* s2c_data32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); - -/** Verify a sign-to-contract commitment. - * - * Returns: 1: the signature contains a commitment to data32 (though it does - * not necessarily need to be a valid siganture!) - * 0: incorrect opening - * Args: ctx: a secp256k1 context object, initialized for verification. - * In: sig: the signature containing the sign-to-contract commitment (cannot be NULL) - * data32: the 32-byte data that was committed to (cannot be NULL) - * opening: pointer to the opening created during signing (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_ecdsa_signature *sig, - const unsigned char *data32, - const rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening *opening -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - - -/** ECDSA Anti-Exfil Protocol - * - * The ecdsa_anti_exfil_* functions can be used to prevent a signing device from - * exfiltrating the secret signing keys through biased signature nonces. The general - * idea is that a host provides additional randomness to the signing device client - * and the client commits to the randomness in the nonce using sign-to-contract. - * - * The following scheme is described by Stepan Snigirev here: - * https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-February/017655.html - * and by Pieter Wuille (as "Scheme 6") here: - * https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-March/017667.html - * - * In order to ensure the host cannot trick the signing device into revealing its - * keys, or the signing device to bias the nonce despite the host's contributions, - * the host and client must engage in a commit-reveal protocol as follows: - * 1. The host draws randomness `rho` and computes a sha256 commitment to it using - * `rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_host_commit`. It sends this to the signing device. - * 2. The signing device computes a public nonce `R` using the host's commitment - * as auxiliary randomness, using `rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_signer_commit`. - * The signing device sends the resulting `R` to the host as a s2c_opening. - * - * If, at any point from this step onward, the hardware device fails, it is - * okay to restart the protocol using **exactly the same `rho`** and checking - * that the hardware device proposes **exactly the same** `R`. Otherwise, the - * hardware device may be selectively aborting and thereby biasing the set of - * nonces that are used in actual signatures. - * - * It takes many (>100) such aborts before there is a plausible attack, given - * current knowledge in 2020. However such aborts accumulate even across a total - * replacement of all relevant devices (but not across replacement of the actual - * signing keys with new independently random ones). - * - * In case the hardware device cannot be made to sign with the given `rho`, `R` - * pair, wallet authors should alert the user and present a very scary message - * implying that if this happens more than even a few times, say 20 or more times - * EVER, they should change hardware vendors and perhaps sweep their coins. - * - * 3. The host replies with `rho` generated in step 1. - * 4. The device signs with `rustsecp256k1zkp_v0_8_0_anti_exfil_sign`, using `rho` as `host_data32`, - * and sends the signature to the host. - * 5. The host verifies that the signature's public nonce matches the opening from - * step 2 and its original randomness `rho`, using `rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify`. - * - * Rationale: - * - The reason for having a host commitment is to allow the signing device to - * deterministically derive a unique nonce even if the host restarts the protocol - * using the same message and keys. Otherwise the signer might reuse the original - * nonce in two iterations of the protocol with different `rho`, which leaks the - * the secret key. - * - The signer does not need to check that the host commitment matches the host's - * claimed `rho`. Instead it re-derives the commitment (and its original `R`) from - * the provided `rho`. If this differs from the original commitment, the result - * will be an invalid `s2c_opening`, but since `R` was unique there is no risk to - * the signer's secret keys. Because of this, the signing device does not need to - * maintain any state about the progress of the protocol. - */ - -/** Create the initial host commitment to `rho`. Part of the ECDSA Anti-Exfil Protocol. - * - * Returns 1 on success, 0 on failure. - * Args: ctx: pointer to a context object (cannot be NULL) - * Out: rand_commitment32: pointer to 32-byte array to store the returned commitment (cannot be NULL) - * In: rand32: the 32-byte randomness to commit to (cannot be NULL). It must come from - * a cryptographically secure RNG. As per the protocol, this value must not - * be revealed to the client until after the host has received the client - * commitment. - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_host_commit( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char* rand_commitment32, - const unsigned char* rand32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Compute signer's original nonce. Part of the ECDSA Anti-Exfil Protocol. - * - * Returns 1 on success, 0 on failure. - * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * Out: s2c_opening: pointer to an s2c_opening where the signer's public nonce will be - * placed. (cannot be NULL) - * In: msg32: the 32-byte message hash to be signed (cannot be NULL) - * seckey32: the 32-byte secret key used for signing (cannot be NULL) - * rand_commitment32: the 32-byte randomness commitment from the host (cannot be NULL) - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_signer_commit( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* s2c_opening, - const unsigned char* msg32, - const unsigned char* seckey32, - const unsigned char* rand_commitment32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -/** Same as rustsecp256k1zkp_v0_8_0_ecdsa_sign, but commits to host randomness in the nonce. Part of the - * ECDSA Anti-Exfil Protocol. - * - * Returns: 1: signature created - * 0: the nonce generation function failed, or the private key was invalid. - * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) - * In: msg32: the 32-byte message hash being signed (cannot be NULL) - * seckey: pointer to a 32-byte secret key (cannot be NULL) - * host_data32: pointer to 32-byte host-provided randomness (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_anti_exfil_sign( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, - const unsigned char* msg32, - const unsigned char* seckey, - const unsigned char* host_data32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -/** Verify a signature was correctly constructed using the ECDSA Anti-Exfil Protocol. - * - * Returns: 1: the signature is valid and contains a commitment to host_data32 - * 0: incorrect opening - * Args: ctx: a secp256k1 context object, initialized for verification. - * In: sig: the signature produced by the signer (cannot be NULL) - * msghash32: the 32-byte message hash being verified (cannot be NULL) - * pubkey: pointer to the signer's public key (cannot be NULL) - * host_data32: the 32-byte data provided by the host (cannot be NULL) - * opening: the s2c opening provided by the signer (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_ecdsa_signature *sig, - const unsigned char *msg32, - const rustsecp256k1zkp_v0_8_0_pubkey *pubkey, - const unsigned char *host_data32, - const rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening *opening -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_ECDSA_S2C_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_generator.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_generator.h deleted file mode 100644 index e0f72bc7..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_generator.h +++ /dev/null @@ -1,241 +0,0 @@ -#ifndef _SECP256K1_GENERATOR_ -# define _SECP256K1_GENERATOR_ - -#include "secp256k1.h" - -# ifdef __cplusplus -extern "C" { -# endif - -#include - -/** Opaque data structure that stores a base point - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. It is - * however guaranteed to be 64 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage, transmission, or - * comparison, use rustsecp256k1zkp_v0_8_0_generator_serialize and rustsecp256k1zkp_v0_8_0_generator_parse. - */ -typedef struct { - unsigned char data[64]; -} rustsecp256k1zkp_v0_8_0_generator; - -/** - * Static constant generator 'h' maintained for historical reasons. - */ -SECP256K1_API extern const rustsecp256k1zkp_v0_8_0_generator *rustsecp256k1zkp_v0_8_0_generator_h; - -/** Parse a 33-byte generator byte sequence into a generator object. - * - * Returns: 1 if input contains a valid generator. - * Args: ctx: a secp256k1 context object. - * Out: gen: pointer to the output generator object - * In: input: pointer to a 33-byte serialized generator - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_generator_parse( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_generator* gen, - const unsigned char *input -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize a 33-byte generator into a serialized byte sequence. - * - * Returns: 1 always. - * Args: ctx: a secp256k1 context object. - * Out: output: a pointer to a 33-byte byte array - * In: gen: a pointer to a generator - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_generator_serialize( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *output, - const rustsecp256k1zkp_v0_8_0_generator* gen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Generate a generator for the curve. - * - * Returns: 0 in the highly unlikely case the seed is not acceptable, - * 1 otherwise. - * Args: ctx: a secp256k1 context object - * Out: gen: a generator object - * In: seed32: a 32-byte seed - * - * If successful a valid generator will be placed in gen. The produced - * generators are distributed uniformly over the curve, and will not have a - * known discrete logarithm with respect to any other generator produced, - * or to the base generator G. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_generator_generate( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_generator* gen, - const unsigned char *seed32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Generate a blinded generator for the curve. - * - * Returns: 0 in the highly unlikely case the seed is not acceptable or when - * blind is out of range. 1 otherwise. - * Args: ctx: a secp256k1 context object, initialized for signing - * Out: gen: a generator object - * In: seed32: a 32-byte seed - * blind32: a 32-byte secret value to blind the generator with. - * - * The result is equivalent to first calling rustsecp256k1zkp_v0_8_0_generator_generate, - * converting the result to a public key, calling rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add, - * and then converting back to generator form. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_generator_generate_blinded( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_generator* gen, - const unsigned char *seed32, - const unsigned char *blind32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Opaque data structure that stores a Pedersen commitment - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. It is - * however guaranteed to be 64 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage, transmission, or - * comparison, use rustsecp256k1zkp_v0_8_0_pedersen_commitment_serialize and - * rustsecp256k1zkp_v0_8_0_pedersen_commitment_parse. - */ -typedef struct { - unsigned char data[64]; -} rustsecp256k1zkp_v0_8_0_pedersen_commitment; - -/** Parse a 33-byte commitment into a commitment object. - * - * Returns: 1 if input contains a valid commitment. - * Args: ctx: a secp256k1 context object. - * Out: commit: pointer to the output commitment object - * In: input: pointer to a 33-byte serialized commitment key - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_pedersen_commitment_parse( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pedersen_commitment* commit, - const unsigned char *input -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize a commitment object into a serialized byte sequence. - * - * Returns: 1 always. - * Args: ctx: a secp256k1 context object. - * Out: output: a pointer to a 33-byte byte array - * In: commit: a pointer to a rustsecp256k1zkp_v0_8_0_pedersen_commitment containing an - * initialized commitment - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_pedersen_commitment_serialize( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *output, - const rustsecp256k1zkp_v0_8_0_pedersen_commitment* commit -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Generate a pedersen commitment. - * Returns 1: Commitment successfully created. - * 0: Error. The blinding factor is larger than the group order - * (probability for random 32 byte number < 2^-127) or results in the - * point at infinity. Retry with a different factor. - * In: ctx: pointer to a context object, initialized for signing and Pedersen commitment (cannot be NULL) - * blind: pointer to a 32-byte blinding factor (cannot be NULL) - * value: unsigned 64-bit integer value to commit to. - * gen: additional generator 'h' - * Out: commit: pointer to the commitment (cannot be NULL) - * - * Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_pedersen_commit( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pedersen_commitment *commit, - const unsigned char *blind, - uint64_t value, - const rustsecp256k1zkp_v0_8_0_generator *gen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); - -/** Computes the sum of multiple positive and negative blinding factors. - * Returns 1: Sum successfully computed. - * 0: Error. A blinding factor is larger than the group order - * (probability for random 32 byte number < 2^-127). Retry with - * different factors. - * In: ctx: pointer to a context object (cannot be NULL) - * blinds: pointer to pointers to 32-byte character arrays for blinding factors. (cannot be NULL) - * n: number of factors pointed to by blinds. - * npositive: how many of the initial factors should be treated with a positive sign. - * Out: blind_out: pointer to a 32-byte array for the sum (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_pedersen_blind_sum( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *blind_out, - const unsigned char * const *blinds, - size_t n, - size_t npositive -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Verify a tally of pedersen commitments - * Returns 1: commitments successfully sum to zero. - * 0: Commitments do not sum to zero or other error. - * In: ctx: pointer to a context object (cannot be NULL) - * commits: pointer to array of pointers to the commitments. (cannot be NULL if pcnt is non-zero) - * pcnt: number of commitments pointed to by commits. - * ncommits: pointer to array of pointers to the negative commitments. (cannot be NULL if ncnt is non-zero) - * ncnt: number of commitments pointed to by ncommits. - * - * This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) == 0. - * - * A pedersen commitment is xG + vA where G and A are generators for the secp256k1 group and x is a blinding factor, - * while v is the committed value. For a collection of commitments to sum to zero, for each distinct generator - * A all blinding factors and all values must sum to zero. - * - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_pedersen_verify_tally( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_pedersen_commitment * const* commits, - size_t pcnt, - const rustsecp256k1zkp_v0_8_0_pedersen_commitment * const* ncommits, - size_t ncnt -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); - -/** Sets the final Pedersen blinding factor correctly when the generators themselves - * have blinding factors. - * - * Consider a generator of the form A' = A + rG, where A is the "real" generator - * but A' is the generator provided to verifiers. Then a Pedersen commitment - * P = vA' + r'G really has the form vA + (vr + r')G. To get all these (vr + r') - * to sum to zero for multiple commitments, we take three arrays consisting of - * the `v`s, `r`s, and `r'`s, respectively called `value`s, `generator_blind`s - * and `blinding_factor`s, and sum them. - * - * The function then subtracts the sum of all (vr + r') from the last element - * of the `blinding_factor` array, setting the total sum to zero. - * - * Returns 1: Blinding factor successfully computed. - * 0: Error. A blinding_factor or generator_blind are larger than the group - * order (probability for random 32 byte number < 2^-127). Retry with - * different values. - * - * In: ctx: pointer to a context object - * value: array of asset values, `v` in the above paragraph. - * May not be NULL unless `n_total` is 0. - * generator_blind: array of asset blinding factors, `r` in the above paragraph - * May not be NULL unless `n_total` is 0. - * n_total: Total size of the above arrays - * n_inputs: How many of the initial array elements represent commitments that - * will be negated in the final sum - * In/Out: blinding_factor: array of commitment blinding factors, `r'` in the above paragraph - * May not be NULL unless `n_total` is 0. - * the last value will be modified to get the total sum to zero. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_pedersen_blind_generator_blind_sum( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const uint64_t *value, - const unsigned char* const* generator_blind, - unsigned char* const* blinding_factor, - size_t n_total, - size_t n_inputs -); - -# ifdef __cplusplus -} -# endif - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_musig.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_musig.h deleted file mode 100644 index 9b3e3938..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_musig.h +++ /dev/null @@ -1,602 +0,0 @@ -#ifndef SECP256K1_MUSIG_H -#define SECP256K1_MUSIG_H - -#include "secp256k1_extrakeys.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/** This module implements BIP MuSig2 v1.0.0-rc.3, a multi-signature scheme - * compatible with BIP-340 ("Schnorr"). You can find an example demonstrating - * the musig module in examples/musig.c. - * - * The module also supports BIP-341 ("Taproot") public key tweaking and adaptor - * signatures as described in - * https://github.com/ElementsProject/scriptless-scripts/pull/24. - * - * It is recommended to read the documentation in this include file carefully. - * Further notes on API usage can be found in src/modules/musig/musig.md - * - * Since the first version of MuSig is essentially replaced by MuSig2, we use - * MuSig, musig and MuSig2 synonymously unless noted otherwise. - */ - -/** Opaque data structures - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. If you - * need to convert to a format suitable for storage, transmission, or - * comparison, use the corresponding serialization and parsing functions. - */ - -/** Opaque data structure that caches information about public key aggregation. - * - * Guaranteed to be 197 bytes in size. It can be safely copied/moved. No - * serialization and parsing functions (yet). - */ -typedef struct { - unsigned char data[197]; -} rustsecp256k1zkp_v0_8_0_musig_keyagg_cache; - -/** Opaque data structure that holds a signer's _secret_ nonce. - * - * Guaranteed to be 132 bytes in size. - * - * WARNING: This structure MUST NOT be copied or read or written to directly. A - * signer who is online throughout the whole process and can keep this - * structure in memory can use the provided API functions for a safe standard - * workflow. See - * https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/ for - * more details about the risks associated with serializing or deserializing - * this structure. - * - * We repeat, copying this data structure can result in nonce reuse which will - * leak the secret signing key. - */ -typedef struct { - unsigned char data[132]; -} rustsecp256k1zkp_v0_8_0_musig_secnonce; - -/** Opaque data structure that holds a signer's public nonce. -* -* Guaranteed to be 132 bytes in size. It can be safely copied/moved. Serialized -* and parsed with `musig_pubnonce_serialize` and `musig_pubnonce_parse`. -*/ -typedef struct { - unsigned char data[132]; -} rustsecp256k1zkp_v0_8_0_musig_pubnonce; - -/** Opaque data structure that holds an aggregate public nonce. - * - * Guaranteed to be 132 bytes in size. It can be safely copied/moved. - * Serialized and parsed with `musig_aggnonce_serialize` and - * `musig_aggnonce_parse`. - */ -typedef struct { - unsigned char data[132]; -} rustsecp256k1zkp_v0_8_0_musig_aggnonce; - -/** Opaque data structure that holds a MuSig session. - * - * This structure is not required to be kept secret for the signing protocol to - * be secure. Guaranteed to be 133 bytes in size. It can be safely - * copied/moved. No serialization and parsing functions (yet). - */ -typedef struct { - unsigned char data[133]; -} rustsecp256k1zkp_v0_8_0_musig_session; - -/** Opaque data structure that holds a partial MuSig signature. - * - * Guaranteed to be 36 bytes in size. Serialized and parsed with - * `musig_partial_sig_serialize` and `musig_partial_sig_parse`. - */ -typedef struct { - unsigned char data[36]; -} rustsecp256k1zkp_v0_8_0_musig_partial_sig; - -/** Parse a signer's public nonce. - * - * Returns: 1 when the nonce could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: nonce: pointer to a nonce object - * In: in66: pointer to the 66-byte nonce to be parsed - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_musig_pubnonce* nonce, - const unsigned char *in66 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize a signer's public nonce - * - * Returns: 1 when the nonce could be serialized, 0 otherwise - * Args: ctx: a secp256k1 context object - * Out: out66: pointer to a 66-byte array to store the serialized nonce - * In: nonce: pointer to the nonce - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_musig_pubnonce_serialize( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *out66, - const rustsecp256k1zkp_v0_8_0_musig_pubnonce* nonce -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Parse an aggregate public nonce. - * - * Returns: 1 when the nonce could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: nonce: pointer to a nonce object - * In: in66: pointer to the 66-byte nonce to be parsed - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_musig_aggnonce_parse( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_musig_aggnonce* nonce, - const unsigned char *in66 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize an aggregate public nonce - * - * Returns: 1 when the nonce could be serialized, 0 otherwise - * Args: ctx: a secp256k1 context object - * Out: out66: pointer to a 66-byte array to store the serialized nonce - * In: nonce: pointer to the nonce - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_musig_aggnonce_serialize( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *out66, - const rustsecp256k1zkp_v0_8_0_musig_aggnonce* nonce -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize a MuSig partial signature - * - * Returns: 1 when the signature could be serialized, 0 otherwise - * Args: ctx: a secp256k1 context object - * Out: out32: pointer to a 32-byte array to store the serialized signature - * In: sig: pointer to the signature - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_musig_partial_sig_serialize( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *out32, - const rustsecp256k1zkp_v0_8_0_musig_partial_sig* sig -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Parse a MuSig partial signature. - * - * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: pointer to a signature object - * In: in32: pointer to the 32-byte signature to be parsed - * - * After the call, sig will always be initialized. If parsing failed or the - * encoded numbers are out of range, signature verification with it is - * guaranteed to fail for every message and public key. - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_musig_partial_sig_parse( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_musig_partial_sig* sig, - const unsigned char *in32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Computes an aggregate public key and uses it to initialize a keyagg_cache - * - * Different orders of `pubkeys` result in different `agg_pk`s. - * - * Before aggregating, the pubkeys can be sorted with `rustsecp256k1zkp_v0_8_0_pubkey_sort` - * which ensures the same `agg_pk` result for the same multiset of pubkeys. - * This is useful to do before `pubkey_agg`, such that the order of pubkeys - * does not affect the aggregate public key. - * - * Returns: 0 if the arguments are invalid, 1 otherwise - * Args: ctx: pointer to a context object initialized for verification - * scratch: should be NULL because it is not yet implemented. If it - * was implemented then the scratch space would be used to - * compute the aggregate pubkey by multiexponentiation. - * Generally, the larger the scratch space, the faster this - * function. However, the returns of providing a larger - * scratch space are diminishing. If NULL, an inefficient - * algorithm is used. - * Out: agg_pk: the MuSig-aggregated x-only public key. If you do not need it, - * this arg can be NULL. - * keyagg_cache: if non-NULL, pointer to a musig_keyagg_cache struct that - * is required for signing (or observing the signing session - * and verifying partial signatures). - * In: pubkeys: input array of pointers to public keys to aggregate. The order - * is important; a different order will result in a different - * aggregate public key. - * n_pubkeys: length of pubkeys array. Must be greater than 0. - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_musig_pubkey_agg( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_scratch_space *scratch, - rustsecp256k1zkp_v0_8_0_xonly_pubkey *agg_pk, - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, - const rustsecp256k1zkp_v0_8_0_pubkey * const* pubkeys, - size_t n_pubkeys -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(5); - -/** Obtain the aggregate public key from a keyagg_cache. - * - * This is only useful if you need the non-xonly public key, in particular for - * plain (non-xonly) tweaking or batch-verifying multiple key aggregations - * (not implemented). - * - * Returns: 0 if the arguments are invalid, 1 otherwise - * Args: ctx: pointer to a context object - * Out: agg_pk: the MuSig-aggregated public key. - * In: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by - * `musig_pubkey_agg` - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_musig_pubkey_get( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *agg_pk, - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Apply plain "EC" tweaking to a public key in a given keyagg_cache by - * adding the generator multiplied with `tweak32` to it. This is useful for - * deriving child keys from an aggregate public key via BIP32. - * - * The tweaking method is the same as `rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add`. So after - * the following pseudocode buf and buf2 have identical contents (absent - * earlier failures). - * - * rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(..., keyagg_cache, pubkeys, ...) - * rustsecp256k1zkp_v0_8_0_musig_pubkey_get(..., agg_pk, keyagg_cache) - * rustsecp256k1zkp_v0_8_0_musig_pubkey_ec_tweak_add(..., output_pk, tweak32, keyagg_cache) - * rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(..., buf, output_pk) - * rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(..., agg_pk, tweak32) - * rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(..., buf2, agg_pk) - * - * This function is required if you want to _sign_ for a tweaked aggregate key. - * On the other hand, if you are only computing a public key, but not intending - * to create a signature for it, you can just use - * `rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add`. - * - * Returns: 0 if the arguments are invalid or the resulting public key would be - * invalid (only when the tweak is the negation of the corresponding - * secret key). 1 otherwise. - * Args: ctx: pointer to a context object initialized for verification - * Out: output_pubkey: pointer to a public key to store the result. Will be set - * to an invalid value if this function returns 0. If you - * do not need it, this arg can be NULL. - * In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by - * `musig_pubkey_agg` - * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid - * according to `rustsecp256k1zkp_v0_8_0_ec_seckey_verify`, this function - * returns 0. For uniformly random 32-byte arrays the - * chance of being invalid is negligible (around 1 in - * 2^128). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_musig_pubkey_ec_tweak_add( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *output_pubkey, - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Apply x-only tweaking to a public key in a given keyagg_cache by adding the - * generator multiplied with `tweak32` to it. This is useful for creating - * Taproot outputs. - * - * The tweaking method is the same as `rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add`. So in - * the following pseudocode xonly_pubkey_tweak_add_check (absent earlier - * failures) returns 1. - * - * rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(..., agg_pk, keyagg_cache, pubkeys, ...) - * rustsecp256k1zkp_v0_8_0_musig_pubkey_xonly_tweak_add(..., output_pk, tweak32, keyagg_cache) - * rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(..., buf, output_pk) - * rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(..., buf, ..., agg_pk, tweak32) - * - * This function is required if you want to _sign_ for a tweaked aggregate key. - * On the other hand, if you are only computing a public key, but not intending - * to create a signature for it, you can just use - * `rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add`. - * - * Returns: 0 if the arguments are invalid or the resulting public key would be - * invalid (only when the tweak is the negation of the corresponding - * secret key). 1 otherwise. - * Args: ctx: pointer to a context object initialized for verification - * Out: output_pubkey: pointer to a public key to store the result. Will be set - * to an invalid value if this function returns 0. If you - * do not need it, this arg can be NULL. - * In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by - * `musig_pubkey_agg` - * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid - * according to rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this function - * returns 0. For uniformly random 32-byte arrays the - * chance of being invalid is negligible (around 1 in - * 2^128). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_musig_pubkey_xonly_tweak_add( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *output_pubkey, - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Starts a signing session by generating a nonce - * - * This function outputs a secret nonce that will be required for signing and a - * corresponding public nonce that is intended to be sent to other signers. - * - * MuSig differs from regular Schnorr signing in that implementers _must_ take - * special care to not reuse a nonce. This can be ensured by following these rules: - * - * 1. Each call to this function must have a UNIQUE session_id32 that must NOT BE - * REUSED in subsequent calls to this function. - * If you do not provide a seckey, session_id32 _must_ be UNIFORMLY RANDOM - * AND KEPT SECRET (even from other signers). If you do provide a seckey, - * session_id32 can instead be a counter (that must never repeat!). However, - * it is recommended to always choose session_id32 uniformly at random. - * 2. If you already know the seckey, message or aggregate public key - * cache, they can be optionally provided to derive the nonce and increase - * misuse-resistance. The extra_input32 argument can be used to provide - * additional data that does not repeat in normal scenarios, such as the - * current time. - * 3. Avoid copying (or serializing) the secnonce. This reduces the possibility - * that it is used more than once for signing. - * - * Remember that nonce reuse will leak the secret key! - * Note that using the same seckey for multiple MuSig sessions is fine. - * - * Returns: 0 if the arguments are invalid and 1 otherwise - * Args: ctx: pointer to a context object, initialized for signing - * Out: secnonce: pointer to a structure to store the secret nonce - * pubnonce: pointer to a structure to store the public nonce - * In: session_id32: a 32-byte session_id32 as explained above. Must be unique to this - * call to rustsecp256k1zkp_v0_8_0_musig_nonce_gen and must be uniformly random - * unless you really know what you are doing. - * seckey: the 32-byte secret key that will later be used for signing, if - * already known (can be NULL) - * pubkey: public key of the signer creating the nonce. The secnonce - * output of this function cannot be used to sign for any - * other public key. - * msg32: the 32-byte message that will later be signed, if already known - * (can be NULL) - * keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate - * (and potentially tweaked) public key if already known - * (can be NULL) - * extra_input32: an optional 32-byte array that is input to the nonce - * derivation function (can be NULL) - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_musig_nonce_gen( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_musig_secnonce *secnonce, - rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonce, - const unsigned char *session_id32, - const unsigned char *seckey, - const rustsecp256k1zkp_v0_8_0_pubkey *pubkey, - const unsigned char *msg32, - const rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, - const unsigned char *extra_input32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6); - -/** Aggregates the nonces of all signers into a single nonce - * - * This can be done by an untrusted party to reduce the communication - * between signers. Instead of everyone sending nonces to everyone else, there - * can be one party receiving all nonces, aggregating the nonces with this - * function and then sending only the aggregate nonce back to the signers. - * - * Returns: 0 if the arguments are invalid, 1 otherwise - * Args: ctx: pointer to a context object - * Out: aggnonce: pointer to an aggregate public nonce object for - * musig_nonce_process - * In: pubnonces: array of pointers to public nonces sent by the - * signers - * n_pubnonces: number of elements in the pubnonces array. Must be - * greater than 0. - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_musig_nonce_agg( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_musig_aggnonce *aggnonce, - const rustsecp256k1zkp_v0_8_0_musig_pubnonce * const* pubnonces, - size_t n_pubnonces -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Takes the public nonces of all signers and computes a session that is - * required for signing and verification of partial signatures. - * - * If the adaptor argument is non-NULL, then the output of - * musig_partial_sig_agg will be a pre-signature which is not a valid Schnorr - * signature. In order to create a valid signature, the pre-signature and the - * secret adaptor must be provided to `musig_adapt`. - * - * Returns: 0 if the arguments are invalid or if some signer sent invalid - * pubnonces, 1 otherwise - * Args: ctx: pointer to a context object, initialized for verification - * Out: session: pointer to a struct to store the session - * In: aggnonce: pointer to an aggregate public nonce object that is the - * output of musig_nonce_agg - * msg32: the 32-byte message to sign - * keyagg_cache: pointer to the keyagg_cache that was used to create the - * aggregate (and potentially tweaked) pubkey - * adaptor: optional pointer to an adaptor point encoded as a public - * key if this signing session is part of an adaptor - * signature protocol (can be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_musig_nonce_process( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_musig_session *session, - const rustsecp256k1zkp_v0_8_0_musig_aggnonce *aggnonce, - const unsigned char *msg32, - const rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, - const rustsecp256k1zkp_v0_8_0_pubkey *adaptor -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -/** Produces a partial signature - * - * This function overwrites the given secnonce with zeros and will abort if given a - * secnonce that is all zeros. This is a best effort attempt to protect against nonce - * reuse. However, this is of course easily defeated if the secnonce has been - * copied (or serialized). Remember that nonce reuse will leak the secret key! - * - * For signing to succeed, the secnonce provided to this function must have - * been generated for the provided keypair. This means that when signing for a - * keypair consisting of a seckey and pubkey, the secnonce must have been - * created by calling musig_nonce_gen with that pubkey. Otherwise, the - * illegal_callback is called. - * - * Returns: 0 if the arguments are invalid or the provided secnonce has already - * been used for signing, 1 otherwise - * Args: ctx: pointer to a context object - * Out: partial_sig: pointer to struct to store the partial signature - * In/Out: secnonce: pointer to the secnonce struct created in - * musig_nonce_gen that has been never used in a - * partial_sign call before and has been created for the - * keypair - * In: keypair: pointer to keypair to sign the message with - * keyagg_cache: pointer to the keyagg_cache that was output when the - * aggregate public key for this session - * session: pointer to the session that was created with - * musig_nonce_process - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_musig_partial_sign( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_musig_partial_sig *partial_sig, - rustsecp256k1zkp_v0_8_0_musig_secnonce *secnonce, - const rustsecp256k1zkp_v0_8_0_keypair *keypair, - const rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, - const rustsecp256k1zkp_v0_8_0_musig_session *session -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); - -/** Verifies an individual signer's partial signature - * - * The signature is verified for a specific signing session. In order to avoid - * accidentally verifying a signature from a different or non-existing signing - * session, you must ensure the following: - * 1. The `keyagg_cache` argument is identical to the one used to create the - * `session` with `musig_nonce_process`. - * 2. The `pubkey` argument must be identical to the one sent by the signer - * before aggregating it with `musig_pubkey_agg` to create the - * `keyagg_cache`. - * 3. The `pubnonce` argument must be identical to the one sent by the signer - * before aggregating it with `musig_nonce_agg` and using the result to - * create the `session` with `musig_nonce_process`. - * - * This function is essential when using protocols with adaptor signatures. - * However, it is not essential for regular MuSig sessions, in the sense that if any - * partial signature does not verify, the full signature will not verify either, so the - * problem will be caught. But this function allows determining the specific party - * who produced an invalid signature. - * - * Returns: 0 if the arguments are invalid or the partial signature does not - * verify, 1 otherwise - * Args ctx: pointer to a context object, initialized for verification - * In: partial_sig: pointer to partial signature to verify, sent by - * the signer associated with `pubnonce` and `pubkey` - * pubnonce: public nonce of the signer in the signing session - * pubkey: public key of the signer in the signing session - * keyagg_cache: pointer to the keyagg_cache that was output when the - * aggregate public key for this signing session - * session: pointer to the session that was created with - * `musig_nonce_process` - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_musig_partial_sig *partial_sig, - const rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonce, - const rustsecp256k1zkp_v0_8_0_pubkey *pubkey, - const rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, - const rustsecp256k1zkp_v0_8_0_musig_session *session -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); - -/** Aggregates partial signatures - * - * Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean - * the resulting signature verifies). - * Args: ctx: pointer to a context object - * Out: sig64: complete (but possibly invalid) Schnorr signature - * In: session: pointer to the session that was created with - * musig_nonce_process - * partial_sigs: array of pointers to partial signatures to aggregate - * n_sigs: number of elements in the partial_sigs array. Must be - * greater than 0. - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *sig64, - const rustsecp256k1zkp_v0_8_0_musig_session *session, - const rustsecp256k1zkp_v0_8_0_musig_partial_sig * const* partial_sigs, - size_t n_sigs -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Extracts the nonce_parity bit from a session - * - * This is used for adaptor signatures. - * - * Returns: 0 if the arguments are invalid, 1 otherwise - * Args: ctx: pointer to a context object - * Out: nonce_parity: pointer to an integer that indicates the parity - * of the aggregate public nonce. Used for adaptor - * signatures. - * In: session: pointer to the session that was created with - * musig_nonce_process - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_musig_nonce_parity( - const rustsecp256k1zkp_v0_8_0_context* ctx, - int *nonce_parity, - const rustsecp256k1zkp_v0_8_0_musig_session *session -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Creates a signature from a pre-signature and an adaptor. - * - * If the sec_adaptor32 argument is incorrect, the output signature will be - * invalid. This function does not verify the signature. - * - * Returns: 0 if the arguments are invalid, or pre_sig64 or sec_adaptor32 contain - * invalid (overflowing) values. 1 otherwise (which does NOT mean the - * signature or the adaptor are valid!) - * Args: ctx: pointer to a context object - * Out: sig64: 64-byte signature. This pointer may point to the same - * memory area as `pre_sig`. - * In: pre_sig64: 64-byte pre-signature - * sec_adaptor32: 32-byte secret adaptor to add to the pre-signature - * nonce_parity: the output of `musig_nonce_parity` called with the - * session used for producing the pre-signature - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_musig_adapt( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *sig64, - const unsigned char *pre_sig64, - const unsigned char *sec_adaptor32, - int nonce_parity -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Extracts a secret adaptor from a MuSig pre-signature and corresponding - * signature - * - * This function will not fail unless given grossly invalid data; if it is - * merely given signatures that do not verify, the returned value will be - * nonsense. It is therefore important that all data be verified at earlier - * steps of any protocol that uses this function. In particular, this includes - * verifying all partial signatures that were aggregated into pre_sig64. - * - * Returns: 0 if the arguments are NULL, or sig64 or pre_sig64 contain - * grossly invalid (overflowing) values. 1 otherwise (which does NOT - * mean the signatures or the adaptor are valid!) - * Args: ctx: pointer to a context object - * Out:sec_adaptor32: 32-byte secret adaptor - * In: sig64: complete, valid 64-byte signature - * pre_sig64: the pre-signature corresponding to sig64, i.e., the - * aggregate of partial signatures without the secret - * adaptor - * nonce_parity: the output of `musig_nonce_parity` called with the - * session used for producing sig64 - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_musig_extract_adaptor( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *sec_adaptor32, - const unsigned char *sig64, - const unsigned char *pre_sig64, - int nonce_parity -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_rangeproof.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_rangeproof.h deleted file mode 100644 index bfaf5320..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_rangeproof.h +++ /dev/null @@ -1,182 +0,0 @@ -#ifndef _SECP256K1_RANGEPROOF_ -# define _SECP256K1_RANGEPROOF_ - -#include "secp256k1.h" -#include "secp256k1_generator.h" - -# ifdef __cplusplus -extern "C" { -# endif - -#include - -/** Length of a message that can be embedded into a maximally-sized rangeproof - * - * It is not be possible to fit a message of this size into a non-maximally-sized - * rangeproof, but it is guaranteed that any embeddable message can fit into an - * array of this size. This constant is intended to be used for memory allocations - * and sanity checks. - */ -#define SECP256K1_RANGEPROOF_MAX_MESSAGE_LEN 3968 - -/** Verify a proof that a committed value is within a range. - * Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs. - * 0: Proof failed or other error. - * In: ctx: pointer to a context object, initialized for range-proof and commitment (cannot be NULL) - * commit: the commitment being proved. (cannot be NULL) - * proof: pointer to character array with the proof. (cannot be NULL) - * plen: length of proof in bytes. - * extra_commit: additional data covered in rangeproof signature - * extra_commit_len: length of extra_commit byte array (0 if NULL) - * gen: additional generator 'h' - * Out: min_value: pointer to a unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL) - * max_value: pointer to a unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_rangeproof_verify( - const rustsecp256k1zkp_v0_8_0_context* ctx, - uint64_t *min_value, - uint64_t *max_value, - const rustsecp256k1zkp_v0_8_0_pedersen_commitment *commit, - const unsigned char *proof, - size_t plen, - const unsigned char *extra_commit, - size_t extra_commit_len, - const rustsecp256k1zkp_v0_8_0_generator* gen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(9); - -/** Verify a range proof proof and rewind the proof to recover information sent by its author. - * Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs, and the value and blinding were recovered. - * 0: Proof failed, rewind failed, or other error. - * In: ctx: pointer to a context object, initialized for range-proof and Pedersen commitment (cannot be NULL) - * commit: the commitment being proved. (cannot be NULL) - * proof: pointer to character array with the proof. (cannot be NULL) - * plen: length of proof in bytes. - * nonce: 32-byte secret nonce used by the prover (cannot be NULL) - * extra_commit: additional data covered in rangeproof signature - * extra_commit_len: length of extra_commit byte array (0 if NULL) - * gen: additional generator 'h' - * In/Out: blind_out: storage for the 32-byte blinding factor used for the commitment - * value_out: pointer to an unsigned int64 which has the exact value of the commitment. - * message_out: pointer to a 4096 byte character array to receive message data from the proof author. - * outlen: length of message data written to message_out. This is generally not equal to the - * msg_len used by the signer. However, for all i with msg_len <= i < outlen, it is - * guaranteed that message_out[i] == 0. - * min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL) - * max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_rangeproof_rewind( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *blind_out, - uint64_t *value_out, - unsigned char *message_out, - size_t *outlen, - const unsigned char *nonce, - uint64_t *min_value, - uint64_t *max_value, - const rustsecp256k1zkp_v0_8_0_pedersen_commitment *commit, - const unsigned char *proof, - size_t plen, - const unsigned char *extra_commit, - size_t extra_commit_len, - const rustsecp256k1zkp_v0_8_0_generator *gen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(9) SECP256K1_ARG_NONNULL(10) SECP256K1_ARG_NONNULL(14); - -/** Author a proof that a committed value is within a range. - * Returns 1: Proof successfully created. - * 0: Error - * In: ctx: pointer to a context object, initialized for range-proof, signing, and Pedersen commitment (cannot be NULL) - * proof: pointer to array to receive the proof, can be up to 5134 bytes. (cannot be NULL) - * min_value: constructs a proof where the verifer can tell the minimum value is at least the specified amount. - * commit: the commitment being proved. - * blind: 32-byte blinding factor used by commit. The blinding factor may be all-zeros as long as min_bits is set to 3 or greater. - * This is a side-effect of the underlying crypto, not a deliberate API choice, but it may be useful when balancing CT transactions. - * nonce: 32-byte secret nonce used to initialize the proof (value can be reverse-engineered out of the proof if this secret is known.) - * exp: Base-10 exponent. Digits below above will be made public, but the proof will be made smaller. Allowed range is -1 to 18. - * (-1 is a special case that makes the value public. 0 is the most private.) - * min_bits: Number of bits of the value to keep private. (0 = auto/minimal, - 64). - * value: Actual value of the commitment. - * message: pointer to a byte array of data to be embedded in the rangeproof that can be recovered by rewinding the proof - * msg_len: size of the message to be embedded in the rangeproof - * extra_commit: additional data to be covered in rangeproof signature - * extra_commit_len: length of extra_commit byte array (0 if NULL) - * gen: additional generator 'h' - * In/out: plen: point to an integer with the size of the proof buffer and the size of the constructed proof. - * - * If min_value or exp is non-zero then the value must be on the range [0, 2^63) to prevent the proof range from spanning past 2^64. - * - * If exp is -1 the value is revealed by the proof (e.g. it proves that the proof is a blinding of a specific value, without revealing the blinding key.) - * - * This can randomly fail with probability around one in 2^100. If this happens, buy a lottery ticket and retry with a different nonce or blinding. - * - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_rangeproof_sign( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *proof, - size_t *plen, - uint64_t min_value, - const rustsecp256k1zkp_v0_8_0_pedersen_commitment *commit, - const unsigned char *blind, - const unsigned char *nonce, - int exp, - int min_bits, - uint64_t value, - const unsigned char *message, - size_t msg_len, - const unsigned char *extra_commit, - size_t extra_commit_len, - const rustsecp256k1zkp_v0_8_0_generator *gen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(15); - -/** Extract some basic information from a range-proof. - * Returns 1: Information successfully extracted. - * 0: Decode failed. - * In: ctx: pointer to a context object - * proof: pointer to character array with the proof. - * plen: length of proof in bytes. - * Out: exp: Exponent used in the proof (-1 means the value isn't private). - * mantissa: Number of bits covered by the proof. - * min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL) - * max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_rangeproof_info( - const rustsecp256k1zkp_v0_8_0_context* ctx, - int *exp, - int *mantissa, - uint64_t *min_value, - uint64_t *max_value, - const unsigned char *proof, - size_t plen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -/** Returns an upper bound on the size of a rangeproof with the given parameters - * - * An actual rangeproof may be smaller, for example if the actual value - * is less than both the provided `max_value` and 2^`min_bits`, or if - * the `exp` parameter to `rustsecp256k1zkp_v0_8_0_rangeproof_sign` is set such that - * the proven range is compressed. In particular this function will always - * overestimate the size of single-value proofs. Also, if `min_value` - * is set to 0 in the proof, the result will usually, but not always, - * be 8 bytes smaller than if a nonzero value had been passed. - * - * The goal of this function is to provide a useful upper bound for - * memory allocation or fee estimation purposes, without requiring - * too many parameters be fixed in advance. - * - * To obtain the size of largest possible proof, set `max_value` to - * `UINT64_MAX` (and `min_bits` to any valid value such as 0). - * - * In: ctx: pointer to a context object - * max_value: the maximum value that might be passed for `value` for the proof. - * min_bits: the value that will be passed as `min_bits` for the proof. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT size_t rustsecp256k1zkp_v0_8_0_rangeproof_max_size( - const rustsecp256k1zkp_v0_8_0_context* ctx, - uint64_t max_value, - int min_bits -) SECP256K1_ARG_NONNULL(1); - -# ifdef __cplusplus -} -# endif - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_surjectionproof.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_surjectionproof.h deleted file mode 100644 index 2e3fa34c..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_surjectionproof.h +++ /dev/null @@ -1,270 +0,0 @@ -#ifndef _SECP256K1_SURJECTIONPROOF_ -#define _SECP256K1_SURJECTIONPROOF_ - -#include "secp256k1.h" -#include "secp256k1_rangeproof.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Maximum number of inputs that may be given in a surjection proof */ -#define SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS 256 - -/** Maximum number of inputs that may be used in a surjection proof */ -#define SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS 256 - -/** Number of bytes a serialized surjection proof requires given the - * number of inputs and the number of used inputs. - */ -#define SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(n_inputs, n_used_inputs) \ - (2 + (n_inputs + 7)/8 + 32 * (1 + (n_used_inputs))) - -/** Maximum number of bytes a serialized surjection proof requires. */ -#define SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX \ - SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS) - -/** Opaque data structure that holds a parsed surjection proof - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. Nor is - * it guaranteed to have any particular size, nor that identical proofs - * will have identical representation. (That is, memcmp may return nonzero - * even for identical proofs.) - * - * To obtain these properties, instead use rustsecp256k1zkp_v0_8_0_surjectionproof_parse - * and rustsecp256k1zkp_v0_8_0_surjectionproof_serialize to encode/decode proofs into a - * well-defined format. - * - * The representation is exposed to allow creation of these objects on the - * stack; please *do not* use these internals directly. - */ -typedef struct { -#ifdef VERIFY - /** Mark whether this proof has gone through `rustsecp256k1zkp_v0_8_0_surjectionproof_initialize` */ - int initialized; -#endif - /** Total number of input asset tags */ - size_t n_inputs; - /** Bitmap of which input tags are used in the surjection proof */ - unsigned char used_inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS / 8]; - /** Borromean signature: e0, scalars */ - unsigned char data[32 * (1 + SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS)]; -} rustsecp256k1zkp_v0_8_0_surjectionproof; - -#ifndef USE_REDUCED_SURJECTION_PROOF_SIZE -/** Parse a surjection proof - * - * Returns: 1 when the proof could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: proof: a pointer to a proof object - * In: input: a pointer to the array to parse - * inputlen: length of the array pointed to by input - * - * The proof must consist of: - * - A 2-byte little-endian total input count `n` - * - A ceil(n/8)-byte bitmap indicating which inputs are used. - * - A big-endian 32-byte borromean signature e0 value - * - `m` big-endian 32-byte borromean signature s values, where `m` - * is the number of set bits in the bitmap - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_surjectionproof_parse( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_surjectionproof *proof, - const unsigned char *input, - size_t inputlen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -#endif - -/** Serialize a surjection proof - * - * Returns: 1 if enough space was available to serialize, 0 otherwise - * Args: ctx: a secp256k1 context object - * Out: output: a pointer to an array to store the serialization - * In/Out: outputlen: a pointer to an integer which is initially set to the - * size of output, and is overwritten with the written - * size. - * In: proof: a pointer to an initialized proof object - * - * See rustsecp256k1zkp_v0_8_0_surjectionproof_parse for details about the encoding. - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_surjectionproof_serialize( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *output, - size_t *outputlen, - const rustsecp256k1zkp_v0_8_0_surjectionproof *proof -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Data structure that holds a fixed asset tag. - * - * This data type is *not* opaque. It will always be 32 bytes of whatever - * data the API user wants to use as an asset tag. Its contents have no - * semantic meaning to libsecp whatsoever. - */ -typedef struct { - unsigned char data[32]; -} rustsecp256k1zkp_v0_8_0_fixed_asset_tag; - -/** Returns the total number of inputs a proof expects to be over. - * - * Returns: the number of inputs for the given proof - * In: ctx: pointer to a context object - * proof: a pointer to a proof object - */ -SECP256K1_API size_t rustsecp256k1zkp_v0_8_0_surjectionproof_n_total_inputs( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_surjectionproof* proof -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - -/** Returns the actual number of inputs that a proof uses - * - * Returns: the number of inputs for the given proof - * In: ctx: pointer to a context object - * proof: a pointer to a proof object - */ -SECP256K1_API size_t rustsecp256k1zkp_v0_8_0_surjectionproof_n_used_inputs( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_surjectionproof* proof -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - -/** Returns the total size this proof would take, in bytes, when serialized - * - * Returns: the total size - * In: ctx: pointer to a context object - * proof: a pointer to a proof object - */ -SECP256K1_API size_t rustsecp256k1zkp_v0_8_0_surjectionproof_serialized_size( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_surjectionproof* proof -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - -/** Surjection proof initialization function; decides on inputs to use - * To be used to initialize stack-allocated rustsecp256k1zkp_v0_8_0_surjectionproof struct - * Returns 0: inputs could not be selected - * n: inputs were selected after n iterations of random selection - * - * In: ctx: pointer to a context object - * fixed_input_tags: fixed input tags `A_i` for all inputs. (If the fixed tag is not known, - * e.g. in a coinjoin with others' inputs, an ephemeral tag can be given; - * this won't match the output tag but might be used in the anonymity set.) - * n_input_tags: the number of entries in the fixed_input_tags array - * n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set - * Must be <= SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS - * fixed_output_tag: fixed output tag - * max_n_iterations: the maximum number of iterations to do before giving up. Because the - * maximum number of inputs (SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) is - * limited to 256 the probability of giving up is smaller than - * (255/256)^(n_input_tags_to_use*max_n_iterations). - * - * random_seed32: a random seed to be used for input selection - * Out: proof: The proof whose bitvector will be initialized. In case of failure, - * the state of the proof is undefined. - * input_index: The index of the actual input that is secretly mapped to the output - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_surjectionproof_initialize( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_surjectionproof* proof, - size_t *input_index, - const rustsecp256k1zkp_v0_8_0_fixed_asset_tag* fixed_input_tags, - const size_t n_input_tags, - const size_t n_input_tags_to_use, - const rustsecp256k1zkp_v0_8_0_fixed_asset_tag* fixed_output_tag, - const size_t n_max_iterations, - const unsigned char *random_seed32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(7); - - -/** Surjection proof allocation and initialization function; decides on inputs to use - * Returns 0: inputs could not be selected, or malloc failure - * n: inputs were selected after n iterations of random selection - * - * In: ctx: pointer to a context object - * proof_out_p: a pointer to a pointer to `rustsecp256k1zkp_v0_8_0_surjectionproof*`. - * the newly-allocated struct pointer will be saved here. - * fixed_input_tags: fixed input tags `A_i` for all inputs. (If the fixed tag is not known, - * e.g. in a coinjoin with others' inputs, an ephemeral tag can be given; - * this won't match the output tag but might be used in the anonymity set.) - * n_input_tags: the number of entries in the fixed_input_tags array - * n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set - * fixed_output_tag: fixed output tag - * max_n_iterations: the maximum number of iterations to do before giving up. Because the - * maximum number of inputs (SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) is - * limited to 256 the probability of giving up is smaller than - * (255/256)^(n_input_tags_to_use*max_n_iterations). - * - * random_seed32: a random seed to be used for input selection - * Out: proof_out_p: The pointer to newly-allocated proof whose bitvector will be initialized. - * In case of failure, the pointer will be NULL. - * input_index: The index of the actual input that is secretly mapped to the output - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_surjectionproof_allocate_initialized( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_surjectionproof** proof_out_p, - size_t *input_index, - const rustsecp256k1zkp_v0_8_0_fixed_asset_tag* fixed_input_tags, - const size_t n_input_tags, - const size_t n_input_tags_to_use, - const rustsecp256k1zkp_v0_8_0_fixed_asset_tag* fixed_output_tag, - const size_t n_max_iterations, - const unsigned char *random_seed32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(7); - -/** Surjection proof destroy function - * deallocates the struct that was allocated with rustsecp256k1zkp_v0_8_0_surjectionproof_allocate_initialized - * - * In: proof: pointer to rustsecp256k1zkp_v0_8_0_surjectionproof struct - */ -SECP256K1_API void rustsecp256k1zkp_v0_8_0_surjectionproof_destroy( - rustsecp256k1zkp_v0_8_0_surjectionproof* proof -) SECP256K1_ARG_NONNULL(1); - -/** Surjection proof generation function - * Returns 0: proof could not be created - * 1: proof was successfully created - * - * In: ctx: pointer to a context object, initialized for signing and verification - * ephemeral_input_tags: the ephemeral asset tag of all inputs - * n_ephemeral_input_tags: the number of entries in the ephemeral_input_tags array - * ephemeral_output_tag: the ephemeral asset tag of the output - * input_index: the index of the input that actually maps to the output - * input_blinding_key: the blinding key of the input - * output_blinding_key: the blinding key of the output - * In/Out: proof: The produced surjection proof. Must have already gone through `rustsecp256k1zkp_v0_8_0_surjectionproof_initialize` - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_surjectionproof_generate( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_surjectionproof* proof, - const rustsecp256k1zkp_v0_8_0_generator* ephemeral_input_tags, - size_t n_ephemeral_input_tags, - const rustsecp256k1zkp_v0_8_0_generator* ephemeral_output_tag, - size_t input_index, - const unsigned char *input_blinding_key, - const unsigned char *output_blinding_key -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8); - - -#ifndef USE_REDUCED_SURJECTION_PROOF_SIZE -/** Surjection proof verification function - * Returns 0: proof was invalid - * 1: proof was valid - * - * In: ctx: pointer to a context object, initialized for signing and verification - * proof: proof to be verified - * ephemeral_input_tags: the ephemeral asset tag of all inputs - * n_ephemeral_input_tags: the number of entries in the ephemeral_input_tags array - * ephemeral_output_tag: the ephemeral asset tag of the output - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_surjectionproof_verify( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_surjectionproof* proof, - const rustsecp256k1zkp_v0_8_0_generator* ephemeral_input_tags, - size_t n_ephemeral_input_tags, - const rustsecp256k1zkp_v0_8_0_generator* ephemeral_output_tag -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_whitelist.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_whitelist.h deleted file mode 100644 index 2031cb31..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_whitelist.h +++ /dev/null @@ -1,148 +0,0 @@ -/********************************************************************** - * Copyright (c) 2016 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_WHITELIST_ -#define _SECP256K1_WHITELIST_ - -#include "secp256k1.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define SECP256K1_WHITELIST_MAX_N_KEYS 255 - -/** Opaque data structure that holds a parsed whitelist proof - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. Nor is - * it guaranteed to have any particular size, nor that identical signatures - * will have identical representation. (That is, memcmp may return nonzero - * even for identical signatures.) - * - * To obtain these properties, instead use rustsecp256k1zkp_v0_8_0_whitelist_signature_parse - * and rustsecp256k1zkp_v0_8_0_whitelist_signature_serialize to encode/decode signatures - * into a well-defined format. - * - * The representation is exposed to allow creation of these objects on the - * stack; please *do not* use these internals directly. To learn the number - * of keys for a signature, use `rustsecp256k1zkp_v0_8_0_whitelist_signature_n_keys`. - */ -typedef struct { - size_t n_keys; - /* e0, scalars */ - unsigned char data[32 * (1 + SECP256K1_WHITELIST_MAX_N_KEYS)]; -} rustsecp256k1zkp_v0_8_0_whitelist_signature; - -/** Parse a whitelist signature - * - * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input: a pointer to the array to parse - * input_len: the length of the above array - * - * The signature must consist of a 1-byte n_keys value, followed by a 32-byte - * big endian e0 value, followed by n_keys many 32-byte big endian s values. - * If n_keys falls outside of [0..SECP256K1_WHITELIST_MAX_N_KEYS] the encoding - * is invalid. - * - * The total length of the input array must therefore be 33 + 32 * n_keys. - * If the length `input_len` does not match this value, parsing will fail. - * - * After the call, sig will always be initialized. If parsing failed or any - * scalar values overflow or are zero, the resulting sig value is guaranteed - * to fail validation for any set of keys. - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_whitelist_signature_parse( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_whitelist_signature *sig, - const unsigned char *input, - size_t input_len -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Returns the number of keys a signature expects to have. - * - * Returns: the number of keys for the given signature - * In: sig: a pointer to a signature object - */ -SECP256K1_API size_t rustsecp256k1zkp_v0_8_0_whitelist_signature_n_keys( - const rustsecp256k1zkp_v0_8_0_whitelist_signature *sig -) SECP256K1_ARG_NONNULL(1); - -/** Serialize a whitelist signature - * - * Returns: 1 - * Args: ctx: a secp256k1 context object - * Out: output64: a pointer to an array to store the serialization - * In/Out: output_len: length of the above array, updated with the actual serialized length - * In: sig: a pointer to an initialized signature object - * - * See rustsecp256k1zkp_v0_8_0_whitelist_signature_parse for details about the encoding. - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_whitelist_signature_serialize( - const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *output, - size_t *output_len, - const rustsecp256k1zkp_v0_8_0_whitelist_signature *sig -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Compute a whitelist signature - * Returns 1: signature was successfully created - * 0: signature was not successfully created - * In: ctx: pointer to a context object, initialized for signing and verification - * online_pubkeys: list of all online pubkeys - * offline_pubkeys: list of all offline pubkeys - * n_keys: the number of entries in each of the above two arrays - * sub_pubkey: the key to be whitelisted - * online_seckey: the secret key to the signer's online pubkey - * summed_seckey: the secret key to the sum of (whitelisted key, signer's offline pubkey) - * index: the signer's index in the lists of keys - * Out: sig: The produced signature. - * - * The signatures are of the list of all passed pubkeys in the order - * ( whitelist, online_1, offline_1, online_2, offline_2, ... ) - * The verification key list consists of - * online_i + H(offline_i + whitelist)(offline_i + whitelist) - * for each public key pair (offline_i, offline_i). Here H means sha256 of the - * compressed serialization of the key. - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_whitelist_sign( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_whitelist_signature *sig, - const rustsecp256k1zkp_v0_8_0_pubkey *online_pubkeys, - const rustsecp256k1zkp_v0_8_0_pubkey *offline_pubkeys, - const size_t n_keys, - const rustsecp256k1zkp_v0_8_0_pubkey *sub_pubkey, - const unsigned char *online_seckey, - const unsigned char *summed_seckeyx, - const size_t index -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8); - -/** Verify a whitelist signature - * Returns 1: signature is valid - * 0: signature is not valid - * In: ctx: pointer to a context object, initialized for signing and verification - * sig: the signature to be verified - * online_pubkeys: list of all online pubkeys - * offline_pubkeys: list of all offline pubkeys - * n_keys: the number of entries in each of the above two arrays - * sub_pubkey: the key to be whitelisted - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_whitelist_verify( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_whitelist_signature *sig, - const rustsecp256k1zkp_v0_8_0_pubkey *online_pubkeys, - const rustsecp256k1zkp_v0_8_0_pubkey *offline_pubkeys, - const size_t n_keys, - const rustsecp256k1zkp_v0_8_0_pubkey *sub_pubkey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/gen_exhaustive_groups.sage b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/gen_exhaustive_groups.sage deleted file mode 100644 index 682e487e..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/gen_exhaustive_groups.sage +++ /dev/null @@ -1,124 +0,0 @@ -load("rustsecp256k1zkp_v0_8_0_params.sage") - -orders_done = set() -results = {} -first = True -for b in range(1, P): - # There are only 6 curves (up to isomorphism) of the form y^2=x^3+B. Stop once we have tried all. - if len(orders_done) == 6: - break - - E = EllipticCurve(F, [0, b]) - print("Analyzing curve y^2 = x^3 + %i" % b) - n = E.order() - # Skip curves with an order we've already tried - if n in orders_done: - print("- Isomorphic to earlier curve") - continue - orders_done.add(n) - # Skip curves isomorphic to the real secp256k1 - if n.is_pseudoprime(): - print(" - Isomorphic to secp256k1") - continue - - print("- Finding subgroups") - - # Find what prime subgroups exist - for f, _ in n.factor(): - print("- Analyzing subgroup of order %i" % f) - # Skip subgroups of order >1000 - if f < 4 or f > 1000: - print(" - Bad size") - continue - - # Iterate over X coordinates until we find one that is on the curve, has order f, - # and for which curve isomorphism exists that maps it to X coordinate 1. - for x in range(1, P): - # Skip X coordinates not on the curve, and construct the full point otherwise. - if not E.is_x_coord(x): - continue - G = E.lift_x(F(x)) - - print(" - Analyzing (multiples of) point with X=%i" % x) - - # Skip points whose order is not a multiple of f. Project the point to have - # order f otherwise. - if (G.order() % f): - print(" - Bad order") - continue - G = G * (G.order() // f) - - # Find lambda for endomorphism. Skip if none can be found. - lam = None - for l in Integers(f)(1).nth_root(3, all=True): - if int(l)*G == E(BETA*G[0], G[1]): - lam = int(l) - break - if lam is None: - print(" - No endomorphism for this subgroup") - break - - # Now look for an isomorphism of the curve that gives this point an X - # coordinate equal to 1. - # If (x,y) is on y^2 = x^3 + b, then (a^2*x, a^3*y) is on y^2 = x^3 + a^6*b. - # So look for m=a^2=1/x. - m = F(1)/G[0] - if not m.is_square(): - print(" - No curve isomorphism maps it to a point with X=1") - continue - a = m.sqrt() - rb = a^6*b - RE = EllipticCurve(F, [0, rb]) - - # Use as generator twice the image of G under the above isormorphism. - # This means that generator*(1/2 mod f) will have X coordinate 1. - RG = RE(1, a^3*G[1]) * 2 - # And even Y coordinate. - if int(RG[1]) % 2: - RG = -RG - assert(RG.order() == f) - assert(lam*RG == RE(BETA*RG[0], RG[1])) - - # We have found curve RE:y^2=x^3+rb with generator RG of order f. Remember it - results[f] = {"b": rb, "G": RG, "lambda": lam} - print(" - Found solution") - break - - print("") - -print("") -print("") -print("/* To be put in src/group_impl.h: */") -first = True -for f in sorted(results.keys()): - b = results[f]["b"] - G = results[f]["G"] - print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f)) - first = False - print("static const rustsecp256k1zkp_v0_8_0_ge rustsecp256k1zkp_v0_8_0_ge_const_g = SECP256K1_GE_CONST(") - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) - print(");") - print("static const rustsecp256k1zkp_v0_8_0_fe rustsecp256k1zkp_v0_8_0_fe_const_b = SECP256K1_FE_CONST(") - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) - print(");") -print("# else") -print("# error No known generator for the specified exhaustive test group order.") -print("# endif") - -print("") -print("") -print("/* To be put in src/scalar_impl.h: */") -first = True -for f in sorted(results.keys()): - lam = results[f]["lambda"] - print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f)) - first = False - print("# define EXHAUSTIVE_TEST_LAMBDA %i" % lam) -print("# else") -print("# error No known lambda for the specified exhaustive test group order.") -print("# endif") -print("") diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/shallue_van_de_woestijne.sage b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/shallue_van_de_woestijne.sage deleted file mode 100644 index 1cc97b65..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/shallue_van_de_woestijne.sage +++ /dev/null @@ -1,51 +0,0 @@ - -### http://www.di.ens.fr/~fouque/pub/latincrypt12.pdf - -# Parameters for secp256k1 -p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F -a = 0 -b = 7 -F = FiniteField (p) -C = EllipticCurve ([F(a), F(b)]) - -def svdw(t): - sqrt_neg_3 = F(-3).nth_root(2) - - ## Compute candidate x values - w = sqrt_neg_3 * t / (1 + b + t^2) - x = [ F(0), F(0), F(0) ] - x[0] = (-1 + sqrt_neg_3) / 2 - t * w - x[1] = -1 - x[0] - x[2] = 1 + 1 / w^2 - - print - print "On %2d" % t - print " x1 %064x" % x[0] - print " x2 %064x" % x[1] - print " x3 %064x" % x[2] - - ## Select which to use - alph = jacobi_symbol(x[0]^3 + b, p) - beta = jacobi_symbol(x[1]^3 + b, p) - if alph == 1 and beta == 1: - i = 0 - elif alph == 1 and beta == -1: - i = 0 - elif alph == -1 and beta == 1: - i = 1 - elif alph == -1 and beta == -1: - i = 2 - else: - print "Help! I don't understand Python!" - - ## Expand to full point - sign = 1 - 2 * (int(F(t)) % 2) - ret_x = x[i] - ret_y = sign * F(x[i]^3 + b).nth_root(2) - return C.point((ret_x, ret_y)) - - -## main -for i in range(1, 11): - res = svdw(i) - print "Result: %064x %064x" % res.xy() diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/assumptions.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/assumptions.h deleted file mode 100644 index 083c8059..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/assumptions.h +++ /dev/null @@ -1,80 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ASSUMPTIONS_H -#define SECP256K1_ASSUMPTIONS_H - -#include - -#include "util.h" - -/* This library, like most software, relies on a number of compiler implementation defined (but not undefined) - behaviours. Although the behaviours we require are essentially universal we test them specifically here to - reduce the odds of experiencing an unwelcome surprise. -*/ - -struct rustsecp256k1zkp_v0_8_0_assumption_checker { - /* This uses a trick to implement a static assertion in C89: a type with an array of negative size is not - allowed. */ - int dummy_array[( - /* Bytes are 8 bits. */ - (CHAR_BIT == 8) && - - /* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32 - without signed overflow, which would be undefined behaviour. */ - (UINT_MAX <= UINT32_MAX) && - - /* Conversions from unsigned to signed outside of the bounds of the signed type are - implementation-defined. Verify that they function as reinterpreting the lower - bits of the input in two's complement notation. Do this for conversions: - - from uint(N)_t to int(N)_t with negative result - - from uint(2N)_t to int(N)_t with negative result - - from int(2N)_t to int(N)_t with negative result - - from int(2N)_t to int(N)_t with positive result */ - - /* To int8_t. */ - ((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55) && - ((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33) && - ((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF) && - ((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34) && - - /* To int16_t. */ - ((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322) && - ((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C) && - ((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4) && - ((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678) && - - /* To int32_t. */ - ((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B) && - ((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE) && - ((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8) && - ((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789) && - - /* To int64_t. */ - ((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL) && -#if defined(SECP256K1_WIDEMUL_INT128) - ((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL) && - (((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL) && - (((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL) && - - /* To int128_t. */ - ((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL)) && -#endif - - /* Right shift on negative signed values is implementation defined. Verify that it - acts as a right shift in two's complement with sign extension (i.e duplicating - the top bit into newly added bits). */ - ((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA) && - ((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A) && - ((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48) && - ((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL) && -#if defined(SECP256K1_WIDEMUL_INT128) - ((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)) && -#endif - 1) * 2 - 1]; -}; - -#endif /* SECP256K1_ASSUMPTIONS_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/basic-config.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/basic-config.h deleted file mode 100644 index 6f7693cb..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/basic-config.h +++ /dev/null @@ -1,17 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_BASIC_CONFIG_H -#define SECP256K1_BASIC_CONFIG_H - -#ifdef USE_BASIC_CONFIG - -#define ECMULT_WINDOW_SIZE 15 -#define ECMULT_GEN_PREC_BITS 4 - -#endif /* USE_BASIC_CONFIG */ - -#endif /* SECP256K1_BASIC_CONFIG_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_bppp.c b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_bppp.c deleted file mode 100644 index b696bfb5..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_bppp.c +++ /dev/null @@ -1,38 +0,0 @@ -/********************************************************************** - * Copyright (c) 2020 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#include - -#include "include/secp256k1_bppp.h" -#include "util.h" -#include "bench.h" - -typedef struct { - rustsecp256k1zkp_v0_8_0_context* ctx; -} bench_bppp_data; - -static void bench_bppp_setup(void* arg) { - (void) arg; -} - -static void bench_bppp(void* arg, int iters) { - bench_bppp_data *data = (bench_bppp_data*)arg; - - (void) data; - (void) iters; -} - -int main(void) { - bench_bppp_data data; - int iters = get_iters(32); - - data.ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - run_benchmark("bppp_verify_bit", bench_bppp, bench_bppp_setup, NULL, &data, 10, iters); - - rustsecp256k1zkp_v0_8_0_context_destroy(data.ctx); - return 0; -} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_generator.c b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_generator.c deleted file mode 100644 index a2c2dc83..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_generator.c +++ /dev/null @@ -1,60 +0,0 @@ -/********************************************************************** - * Copyright (c) 2016 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#include -#include - -#include "include/secp256k1_generator.h" -#include "util.h" -#include "bench.h" - -typedef struct { - rustsecp256k1zkp_v0_8_0_context* ctx; - unsigned char key[32]; - unsigned char blind[32]; -} bench_generator_t; - -static void bench_generator_setup(void* arg) { - bench_generator_t *data = (bench_generator_t*)arg; - memset(data->key, 0x31, 32); - memset(data->blind, 0x13, 32); -} - -static void bench_generator_generate(void* arg, int iters) { - int i; - bench_generator_t *data = (bench_generator_t*)arg; - - for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_generator gen; - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate(data->ctx, &gen, data->key)); - data->key[i & 31]++; - } -} - -static void bench_generator_generate_blinded(void* arg, int iters) { - int i; - bench_generator_t *data = (bench_generator_t*)arg; - - for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_generator gen; - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(data->ctx, &gen, data->key, data->blind)); - data->key[1 + (i & 30)]++; - data->blind[1 + (i & 30)]++; - } -} - -int main(void) { - bench_generator_t data; - int iters = get_iters(20000); - - data.ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - run_benchmark("generator_generate", bench_generator_generate, bench_generator_setup, NULL, &data, 10, iters); - run_benchmark("generator_generate_blinded", bench_generator_generate_blinded, bench_generator_setup, NULL, &data, 10, iters); - - rustsecp256k1zkp_v0_8_0_context_destroy(data.ctx); - return 0; -} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_rangeproof.c b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_rangeproof.c deleted file mode 100644 index fd38dc36..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_rangeproof.c +++ /dev/null @@ -1,65 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014, 2015 Pieter Wuille, Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#include - -#include "include/secp256k1_rangeproof.h" -#include "util.h" -#include "bench.h" - -typedef struct { - rustsecp256k1zkp_v0_8_0_context* ctx; - rustsecp256k1zkp_v0_8_0_pedersen_commitment commit; - unsigned char proof[5134]; - unsigned char blind[32]; - size_t len; - int min_bits; - uint64_t v; -} bench_rangeproof_t; - -static void bench_rangeproof_setup(void* arg) { - int i; - uint64_t minv; - uint64_t maxv; - bench_rangeproof_t *data = (bench_rangeproof_t*)arg; - - data->v = 0; - for (i = 0; i < 32; i++) data->blind[i] = i + 1; - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(data->ctx, &data->commit, data->blind, data->v, rustsecp256k1zkp_v0_8_0_generator_h)); - data->len = 5134; - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(data->ctx, data->proof, &data->len, 0, &data->commit, data->blind, (const unsigned char*)&data->commit, 0, data->min_bits, data->v, NULL, 0, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(data->ctx, &minv, &maxv, &data->commit, data->proof, data->len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); -} - -static void bench_rangeproof(void* arg, int iters) { - int i; - bench_rangeproof_t *data = (bench_rangeproof_t*)arg; - - for (i = 0; i < iters/data->min_bits; i++) { - int j; - uint64_t minv; - uint64_t maxv; - j = rustsecp256k1zkp_v0_8_0_rangeproof_verify(data->ctx, &minv, &maxv, &data->commit, data->proof, data->len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h); - for (j = 0; j < 4; j++) { - data->proof[j + 2 + 32 *((data->min_bits + 1) >> 1) - 4] = (i >> 8)&255; - } - } -} - -int main(void) { - bench_rangeproof_t data; - int iters; - - data.ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - data.min_bits = 32; - iters = data.min_bits*get_iters(32); - - run_benchmark("rangeproof_verify_bit", bench_rangeproof, bench_rangeproof_setup, NULL, &data, 10, iters); - - rustsecp256k1zkp_v0_8_0_context_destroy(data.ctx); - return 0; -} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_whitelist.c b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_whitelist.c deleted file mode 100644 index e729c1a7..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_whitelist.c +++ /dev/null @@ -1,107 +0,0 @@ -/********************************************************************** - * Copyright (c) 2017 Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ -#include - -#include "include/secp256k1.h" - -#include "include/secp256k1_whitelist.h" -#include "util.h" -#include "bench.h" -#include "hash_impl.h" -#include "scalar_impl.h" -#include "testrand_impl.h" - -#define MAX_N_KEYS 30 - -typedef struct { - rustsecp256k1zkp_v0_8_0_context* ctx; - unsigned char online_seckey[MAX_N_KEYS][32]; - unsigned char summed_seckey[MAX_N_KEYS][32]; - rustsecp256k1zkp_v0_8_0_pubkey online_pubkeys[MAX_N_KEYS]; - rustsecp256k1zkp_v0_8_0_pubkey offline_pubkeys[MAX_N_KEYS]; - unsigned char csub[32]; - rustsecp256k1zkp_v0_8_0_pubkey sub_pubkey; - rustsecp256k1zkp_v0_8_0_whitelist_signature sig; - size_t n_keys; -} bench_data; - -static void bench_whitelist(void* arg, int iters) { - bench_data* data = (bench_data*)arg; - int i; - for (i = 0; i < iters; i++) { - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_verify(data->ctx, &data->sig, data->online_pubkeys, data->offline_pubkeys, data->n_keys, &data->sub_pubkey) == 1); - } -} - -static void bench_whitelist_setup(void* arg) { - bench_data* data = (bench_data*)arg; - int i = 0; - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_sign(data->ctx, &data->sig, data->online_pubkeys, data->offline_pubkeys, data->n_keys, &data->sub_pubkey, data->online_seckey[i], data->summed_seckey[i], i)); -} - -static void run_test(bench_data* data, int iters) { - char str[32]; - sprintf(str, "whitelist_%i", (int)data->n_keys); - run_benchmark(str, bench_whitelist, bench_whitelist_setup, NULL, data, 100, iters); -} - -void random_scalar_order(rustsecp256k1zkp_v0_8_0_scalar *num) { - do { - unsigned char b32[32]; - int overflow = 0; - rustsecp256k1zkp_v0_8_0_testrand256(b32); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(num, b32, &overflow); - if (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(num)) { - continue; - } - break; - } while(1); -} - -int main(void) { - bench_data data; - size_t i; - size_t n_keys = 30; - rustsecp256k1zkp_v0_8_0_scalar ssub; - int iters = get_iters(5); - - data.ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - /* Start with subkey */ - random_scalar_order(&ssub); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(data.csub, &ssub); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(data.ctx, data.csub) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(data.ctx, &data.sub_pubkey, data.csub) == 1); - /* Then offline and online whitelist keys */ - for (i = 0; i < n_keys; i++) { - rustsecp256k1zkp_v0_8_0_scalar son, soff; - - /* Create two keys */ - random_scalar_order(&son); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(data.online_seckey[i], &son); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(data.ctx, data.online_seckey[i]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(data.ctx, &data.online_pubkeys[i], data.online_seckey[i]) == 1); - - random_scalar_order(&soff); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(data.summed_seckey[i], &soff); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(data.ctx, data.summed_seckey[i]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(data.ctx, &data.offline_pubkeys[i], data.summed_seckey[i]) == 1); - - /* Make summed_seckey correspond to the sum of offline_pubkey and sub_pubkey */ - rustsecp256k1zkp_v0_8_0_scalar_add(&soff, &soff, &ssub); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(data.summed_seckey[i], &soff); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(data.ctx, data.summed_seckey[i]) == 1); - } - - /* Run test */ - for (i = 1; i <= n_keys; ++i) { - data.n_keys = i; - run_test(&data, iters); - } - - rustsecp256k1zkp_v0_8_0_context_destroy(data.ctx); - return(0); -} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/eccommit.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/eccommit.h deleted file mode 100644 index 68b184db..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/eccommit.h +++ /dev/null @@ -1,28 +0,0 @@ -/********************************************************************** - * Copyright (c) 2020 The libsecp256k1-zkp Developers * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_ECCOMMIT_H -#define SECP256K1_ECCOMMIT_H - -/** Helper function to add a 32-byte value to a scalar */ -static int rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add_helper(rustsecp256k1zkp_v0_8_0_scalar *sec, const unsigned char *tweak); -/** Helper function to add a 32-byte value, times G, to an EC point */ -static int rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add_helper(const rustsecp256k1zkp_v0_8_0_ecmult_context* ecmult_ctx, rustsecp256k1zkp_v0_8_0_ge *p, const unsigned char *tweak); - -/** Serializes elem as a 33 byte array. This is non-constant time with respect to - * whether pubp is the point at infinity. Thus, you may need to declassify - * pubp->infinity before calling this function. */ -static int rustsecp256k1zkp_v0_8_0_ec_commit_pubkey_serialize_const(rustsecp256k1zkp_v0_8_0_ge *pubp, unsigned char *buf33); -/** Compute an ec commitment tweak as hash(pubkey, data). */ -static int rustsecp256k1zkp_v0_8_0_ec_commit_tweak(unsigned char *tweak32, rustsecp256k1zkp_v0_8_0_ge* pubp, rustsecp256k1zkp_v0_8_0_sha256* sha, const unsigned char *data, size_t data_size); -/** Compute an ec commitment as pubkey + hash(pubkey, data)*G. */ -static int rustsecp256k1zkp_v0_8_0_ec_commit(const rustsecp256k1zkp_v0_8_0_ecmult_context* ecmult_ctx, rustsecp256k1zkp_v0_8_0_ge* commitp, const rustsecp256k1zkp_v0_8_0_ge* pubp, rustsecp256k1zkp_v0_8_0_sha256* sha, const unsigned char *data, size_t data_size); -/** Compute a secret key commitment as seckey + hash(pubkey, data). */ -static int rustsecp256k1zkp_v0_8_0_ec_commit_seckey(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context* ecmult_gen_ctx, rustsecp256k1zkp_v0_8_0_scalar* seckey, rustsecp256k1zkp_v0_8_0_ge* pubp, rustsecp256k1zkp_v0_8_0_sha256* sha, const unsigned char *data, size_t data_size); -/** Verify an ec commitment as pubkey + hash(pubkey, data)*G ?= commitment. */ -static int rustsecp256k1zkp_v0_8_0_ec_commit_verify(const rustsecp256k1zkp_v0_8_0_ecmult_context* ecmult_ctx, const rustsecp256k1zkp_v0_8_0_ge* commitp, const rustsecp256k1zkp_v0_8_0_ge* pubp, rustsecp256k1zkp_v0_8_0_sha256* sha, const unsigned char *data, size_t data_size); - -#endif /* SECP256K1_ECCOMMIT_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/eccommit_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/eccommit_impl.h deleted file mode 100644 index 8d88b419..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/eccommit_impl.h +++ /dev/null @@ -1,73 +0,0 @@ -/********************************************************************** - * Copyright (c) 2020 The libsecp256k1 Developers * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#include - -#include "eckey.h" -#include "hash.h" - -/* from secp256k1.c */ -static int rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add_helper(rustsecp256k1zkp_v0_8_0_scalar *sec, const unsigned char *tweak); -static int rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add_helper(rustsecp256k1zkp_v0_8_0_ge *pubp, const unsigned char *tweak); - -static int rustsecp256k1zkp_v0_8_0_ec_commit_pubkey_serialize_const(rustsecp256k1zkp_v0_8_0_ge *pubp, unsigned char *buf33) { - if (rustsecp256k1zkp_v0_8_0_ge_is_infinity(pubp)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_fe_normalize(&pubp->x); - rustsecp256k1zkp_v0_8_0_fe_normalize(&pubp->y); - rustsecp256k1zkp_v0_8_0_fe_get_b32(&buf33[1], &pubp->x); - buf33[0] = rustsecp256k1zkp_v0_8_0_fe_is_odd(&pubp->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN; - return 1; -} - -/* Compute an ec commitment tweak as hash(pubp, data). */ -static int rustsecp256k1zkp_v0_8_0_ec_commit_tweak(unsigned char *tweak32, rustsecp256k1zkp_v0_8_0_ge* pubp, rustsecp256k1zkp_v0_8_0_sha256* sha, const unsigned char *data, size_t data_size) -{ - unsigned char rbuf[33]; - - if (!rustsecp256k1zkp_v0_8_0_ec_commit_pubkey_serialize_const(pubp, rbuf)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_sha256_write(sha, rbuf, sizeof(rbuf)); - rustsecp256k1zkp_v0_8_0_sha256_write(sha, data, data_size); - rustsecp256k1zkp_v0_8_0_sha256_finalize(sha, tweak32); - return 1; -} - -/* Compute an ec commitment as pubp + hash(pubp, data)*G. */ -static int rustsecp256k1zkp_v0_8_0_ec_commit(rustsecp256k1zkp_v0_8_0_ge* commitp, const rustsecp256k1zkp_v0_8_0_ge* pubp, rustsecp256k1zkp_v0_8_0_sha256* sha, const unsigned char *data, size_t data_size) { - unsigned char tweak[32]; - - *commitp = *pubp; - return rustsecp256k1zkp_v0_8_0_ec_commit_tweak(tweak, commitp, sha, data, data_size) - && rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add_helper(commitp, tweak); -} - -/* Compute the seckey of an ec commitment from the original secret key of the pubkey as seckey + - * hash(pubp, data). */ -static int rustsecp256k1zkp_v0_8_0_ec_commit_seckey(rustsecp256k1zkp_v0_8_0_scalar* seckey, rustsecp256k1zkp_v0_8_0_ge* pubp, rustsecp256k1zkp_v0_8_0_sha256* sha, const unsigned char *data, size_t data_size) { - unsigned char tweak[32]; - return rustsecp256k1zkp_v0_8_0_ec_commit_tweak(tweak, pubp, sha, data, data_size) - && rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add_helper(seckey, tweak); -} - -/* Verify an ec commitment as pubp + hash(pubp, data)*G ?= commitment. */ -static int rustsecp256k1zkp_v0_8_0_ec_commit_verify(const rustsecp256k1zkp_v0_8_0_ge* commitp, const rustsecp256k1zkp_v0_8_0_ge* pubp, rustsecp256k1zkp_v0_8_0_sha256* sha, const unsigned char *data, size_t data_size) { - rustsecp256k1zkp_v0_8_0_gej pj; - rustsecp256k1zkp_v0_8_0_ge p; - - if (!rustsecp256k1zkp_v0_8_0_ec_commit(&p, pubp, sha, data, data_size)) { - return 0; - } - - /* Return p == commitp */ - rustsecp256k1zkp_v0_8_0_ge_neg(&p, &p); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&pj, &p); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&pj, &pj, commitp, NULL); - return rustsecp256k1zkp_v0_8_0_gej_is_infinity(&pj); -} - diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecdsa.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecdsa.h deleted file mode 100644 index 50eefda8..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecdsa.h +++ /dev/null @@ -1,21 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECDSA_H -#define SECP256K1_ECDSA_H - -#include - -#include "scalar.h" -#include "group.h" -#include "ecmult.h" - -static int rustsecp256k1zkp_v0_8_0_ecdsa_sig_parse(rustsecp256k1zkp_v0_8_0_scalar *r, rustsecp256k1zkp_v0_8_0_scalar *s, const unsigned char *sig, size_t size); -static int rustsecp256k1zkp_v0_8_0_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *s); -static int rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(const rustsecp256k1zkp_v0_8_0_scalar* r, const rustsecp256k1zkp_v0_8_0_scalar* s, const rustsecp256k1zkp_v0_8_0_ge *pubkey, const rustsecp256k1zkp_v0_8_0_scalar *message); -static int rustsecp256k1zkp_v0_8_0_ecdsa_sig_sign(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context *ctx, rustsecp256k1zkp_v0_8_0_scalar* r, rustsecp256k1zkp_v0_8_0_scalar* s, const rustsecp256k1zkp_v0_8_0_scalar *seckey, const rustsecp256k1zkp_v0_8_0_scalar *message, const rustsecp256k1zkp_v0_8_0_scalar *nonce, int *recid); - -#endif /* SECP256K1_ECDSA_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/eckey.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/eckey.h deleted file mode 100644 index cc18fe9e..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/eckey.h +++ /dev/null @@ -1,25 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECKEY_H -#define SECP256K1_ECKEY_H - -#include - -#include "group.h" -#include "scalar.h" -#include "ecmult.h" -#include "ecmult_gen.h" - -static int rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(rustsecp256k1zkp_v0_8_0_ge *elem, const unsigned char *pub, size_t size); -static int rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(rustsecp256k1zkp_v0_8_0_ge *elem, unsigned char *pub, size_t *size, int compressed); - -static int rustsecp256k1zkp_v0_8_0_eckey_privkey_tweak_add(rustsecp256k1zkp_v0_8_0_scalar *key, const rustsecp256k1zkp_v0_8_0_scalar *tweak); -static int rustsecp256k1zkp_v0_8_0_eckey_pubkey_tweak_add(rustsecp256k1zkp_v0_8_0_ge *key, const rustsecp256k1zkp_v0_8_0_scalar *tweak); -static int rustsecp256k1zkp_v0_8_0_eckey_privkey_tweak_mul(rustsecp256k1zkp_v0_8_0_scalar *key, const rustsecp256k1zkp_v0_8_0_scalar *tweak); -static int rustsecp256k1zkp_v0_8_0_eckey_pubkey_tweak_mul(rustsecp256k1zkp_v0_8_0_ge *key, const rustsecp256k1zkp_v0_8_0_scalar *tweak); - -#endif /* SECP256K1_ECKEY_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/eckey_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/eckey_impl.h deleted file mode 100644 index 91ec7a12..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/eckey_impl.h +++ /dev/null @@ -1,96 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECKEY_IMPL_H -#define SECP256K1_ECKEY_IMPL_H - -#include "eckey.h" - -#include "scalar.h" -#include "field.h" -#include "group.h" -#include "ecmult_gen.h" - -static int rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(rustsecp256k1zkp_v0_8_0_ge *elem, const unsigned char *pub, size_t size) { - if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) { - rustsecp256k1zkp_v0_8_0_fe x; - return rustsecp256k1zkp_v0_8_0_fe_set_b32(&x, pub+1) && rustsecp256k1zkp_v0_8_0_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD); - } else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { - rustsecp256k1zkp_v0_8_0_fe x, y; - if (!rustsecp256k1zkp_v0_8_0_fe_set_b32(&x, pub+1) || !rustsecp256k1zkp_v0_8_0_fe_set_b32(&y, pub+33)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_ge_set_xy(elem, &x, &y); - if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) && - rustsecp256k1zkp_v0_8_0_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { - return 0; - } - return rustsecp256k1zkp_v0_8_0_ge_is_valid_var(elem); - } else { - return 0; - } -} - -static int rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(rustsecp256k1zkp_v0_8_0_ge *elem, unsigned char *pub, size_t *size, int compressed) { - if (rustsecp256k1zkp_v0_8_0_ge_is_infinity(elem)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&elem->x); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&elem->y); - rustsecp256k1zkp_v0_8_0_fe_get_b32(&pub[1], &elem->x); - if (compressed) { - *size = 33; - pub[0] = rustsecp256k1zkp_v0_8_0_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN; - } else { - *size = 65; - pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED; - rustsecp256k1zkp_v0_8_0_fe_get_b32(&pub[33], &elem->y); - } - return 1; -} - -static int rustsecp256k1zkp_v0_8_0_eckey_privkey_tweak_add(rustsecp256k1zkp_v0_8_0_scalar *key, const rustsecp256k1zkp_v0_8_0_scalar *tweak) { - rustsecp256k1zkp_v0_8_0_scalar_add(key, key, tweak); - return !rustsecp256k1zkp_v0_8_0_scalar_is_zero(key); -} - -static int rustsecp256k1zkp_v0_8_0_eckey_pubkey_tweak_add(rustsecp256k1zkp_v0_8_0_ge *key, const rustsecp256k1zkp_v0_8_0_scalar *tweak) { - rustsecp256k1zkp_v0_8_0_gej pt; - rustsecp256k1zkp_v0_8_0_scalar one; - rustsecp256k1zkp_v0_8_0_gej_set_ge(&pt, key); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&one, 1); - rustsecp256k1zkp_v0_8_0_ecmult(&pt, &pt, &one, tweak); - - if (rustsecp256k1zkp_v0_8_0_gej_is_infinity(&pt)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_ge_set_gej(key, &pt); - return 1; -} - -static int rustsecp256k1zkp_v0_8_0_eckey_privkey_tweak_mul(rustsecp256k1zkp_v0_8_0_scalar *key, const rustsecp256k1zkp_v0_8_0_scalar *tweak) { - int ret; - ret = !rustsecp256k1zkp_v0_8_0_scalar_is_zero(tweak); - - rustsecp256k1zkp_v0_8_0_scalar_mul(key, key, tweak); - return ret; -} - -static int rustsecp256k1zkp_v0_8_0_eckey_pubkey_tweak_mul(rustsecp256k1zkp_v0_8_0_ge *key, const rustsecp256k1zkp_v0_8_0_scalar *tweak) { - rustsecp256k1zkp_v0_8_0_scalar zero; - rustsecp256k1zkp_v0_8_0_gej pt; - if (rustsecp256k1zkp_v0_8_0_scalar_is_zero(tweak)) { - return 0; - } - - rustsecp256k1zkp_v0_8_0_scalar_set_int(&zero, 0); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&pt, key); - rustsecp256k1zkp_v0_8_0_ecmult(&pt, &pt, tweak, &zero); - rustsecp256k1zkp_v0_8_0_ge_set_gej(key, &pt); - return 1; -} - -#endif /* SECP256K1_ECKEY_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_compute_table_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_compute_table_impl.h deleted file mode 100644 index 46fee9e5..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_compute_table_impl.h +++ /dev/null @@ -1,49 +0,0 @@ -/***************************************************************************************************** - * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php. * - *****************************************************************************************************/ - -#ifndef SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H -#define SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H - -#include "ecmult_compute_table.h" -#include "group_impl.h" -#include "field_impl.h" -#include "ecmult.h" -#include "util.h" - -static void rustsecp256k1zkp_v0_8_0_ecmult_compute_table(rustsecp256k1zkp_v0_8_0_ge_storage* table, int window_g, const rustsecp256k1zkp_v0_8_0_gej* gen) { - rustsecp256k1zkp_v0_8_0_gej gj; - rustsecp256k1zkp_v0_8_0_ge ge, dgen; - int j; - - gj = *gen; - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&ge, &gj); - rustsecp256k1zkp_v0_8_0_ge_to_storage(&table[0], &ge); - - rustsecp256k1zkp_v0_8_0_gej_double_var(&gj, gen, NULL); - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&dgen, &gj); - - for (j = 1; j < ECMULT_TABLE_SIZE(window_g); ++j) { - rustsecp256k1zkp_v0_8_0_gej_set_ge(&gj, &ge); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&gj, &gj, &dgen, NULL); - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&ge, &gj); - rustsecp256k1zkp_v0_8_0_ge_to_storage(&table[j], &ge); - } -} - -/* Like rustsecp256k1zkp_v0_8_0_ecmult_compute_table, but one for both gen and gen*2^128. */ -static void rustsecp256k1zkp_v0_8_0_ecmult_compute_two_tables(rustsecp256k1zkp_v0_8_0_ge_storage* table, rustsecp256k1zkp_v0_8_0_ge_storage* table_128, int window_g, const rustsecp256k1zkp_v0_8_0_ge* gen) { - rustsecp256k1zkp_v0_8_0_gej gj; - int i; - - rustsecp256k1zkp_v0_8_0_gej_set_ge(&gj, gen); - rustsecp256k1zkp_v0_8_0_ecmult_compute_table(table, window_g, &gj); - for (i = 0; i < 128; ++i) { - rustsecp256k1zkp_v0_8_0_gej_double_var(&gj, &gj, NULL); - } - rustsecp256k1zkp_v0_8_0_ecmult_compute_table(table_128, window_g, &gj); -} - -#endif /* SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_const.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_const.h deleted file mode 100644 index 5202c956..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_const.h +++ /dev/null @@ -1,21 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECMULT_CONST_H -#define SECP256K1_ECMULT_CONST_H - -#include "scalar.h" -#include "group.h" - -/** - * Multiply: R = q*A (in constant-time) - * Here `bits` should be set to the maximum bitlength of the _absolute value_ of `q`, plus - * one because we internally sometimes add 2 to the number during the WNAF conversion. - * A must not be infinity. - */ -static void rustsecp256k1zkp_v0_8_0_ecmult_const(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_ge *a, const rustsecp256k1zkp_v0_8_0_scalar *q, int bits); - -#endif /* SECP256K1_ECMULT_CONST_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_const_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_const_impl.h deleted file mode 100644 index 7e7ad75b..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_const_impl.h +++ /dev/null @@ -1,231 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECMULT_CONST_IMPL_H -#define SECP256K1_ECMULT_CONST_IMPL_H - -#include "scalar.h" -#include "group.h" -#include "ecmult_const.h" -#include "ecmult_impl.h" - -/** Fill a table 'pre' with precomputed odd multiples of a. - * - * The resulting point set is brought to a single constant Z denominator, stores the X and Y - * coordinates as ge_storage points in pre, and stores the global Z in globalz. - * It only operates on tables sized for WINDOW_A wnaf multiples. - */ -static void rustsecp256k1zkp_v0_8_0_ecmult_odd_multiples_table_globalz_windowa(rustsecp256k1zkp_v0_8_0_ge *pre, rustsecp256k1zkp_v0_8_0_fe *globalz, const rustsecp256k1zkp_v0_8_0_gej *a) { - rustsecp256k1zkp_v0_8_0_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)]; - - rustsecp256k1zkp_v0_8_0_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr, globalz, a); - rustsecp256k1zkp_v0_8_0_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr); -} - -/* This is like `ECMULT_TABLE_GET_GE` but is constant time */ -#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \ - int m = 0; \ - /* Extract the sign-bit for a constant time absolute-value. */ \ - int mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \ - int abs_n = ((n) + mask) ^ mask; \ - int idx_n = abs_n >> 1; \ - rustsecp256k1zkp_v0_8_0_fe neg_y; \ - VERIFY_CHECK(((n) & 1) == 1); \ - VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ - VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ - VERIFY_SETUP(rustsecp256k1zkp_v0_8_0_fe_clear(&(r)->x)); \ - VERIFY_SETUP(rustsecp256k1zkp_v0_8_0_fe_clear(&(r)->y)); \ - /* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one \ - * or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \ - (r)->x = (pre)[m].x; \ - (r)->y = (pre)[m].y; \ - for (m = 1; m < ECMULT_TABLE_SIZE(w); m++) { \ - /* This loop is used to avoid secret data in array indices. See - * the comment in ecmult_gen_impl.h for rationale. */ \ - rustsecp256k1zkp_v0_8_0_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \ - rustsecp256k1zkp_v0_8_0_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \ - } \ - (r)->infinity = 0; \ - rustsecp256k1zkp_v0_8_0_fe_negate(&neg_y, &(r)->y, 1); \ - rustsecp256k1zkp_v0_8_0_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \ -} while(0) - -/** Convert a number to WNAF notation. - * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. - * It has the following guarantees: - * - each wnaf[i] an odd integer between -(1 << w) and (1 << w) - * - each wnaf[i] is nonzero - * - the number of words set is always WNAF_SIZE(w) + 1 - * - * Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar - * Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.) - * CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlag Berlin Heidelberg 2003 - * - * Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335 - */ -static int rustsecp256k1zkp_v0_8_0_wnaf_const(int *wnaf, const rustsecp256k1zkp_v0_8_0_scalar *scalar, int w, int size) { - int global_sign; - int skew; - int word = 0; - - /* 1 2 3 */ - int u_last; - int u; - - int flip; - rustsecp256k1zkp_v0_8_0_scalar s = *scalar; - - VERIFY_CHECK(w > 0); - VERIFY_CHECK(size > 0); - - /* Note that we cannot handle even numbers by negating them to be odd, as is - * done in other implementations, since if our scalars were specified to have - * width < 256 for performance reasons, their negations would have width 256 - * and we'd lose any performance benefit. Instead, we use a variation of a - * technique from Section 4.2 of the Okeya/Tagaki paper, which is to add 1 to the - * number we are encoding when it is even, returning a skew value indicating - * this, and having the caller compensate after doing the multiplication. - * - * In fact, we _do_ want to negate numbers to minimize their bit-lengths (and in - * particular, to ensure that the outputs from the endomorphism-split fit into - * 128 bits). If we negate, the parity of our number flips, affecting whether - * we want to add to the scalar to ensure that it's odd. */ - flip = rustsecp256k1zkp_v0_8_0_scalar_is_high(&s); - skew = flip ^ rustsecp256k1zkp_v0_8_0_scalar_is_even(&s); - rustsecp256k1zkp_v0_8_0_scalar_cadd_bit(&s, 0, skew); - global_sign = rustsecp256k1zkp_v0_8_0_scalar_cond_negate(&s, flip); - - /* 4 */ - u_last = rustsecp256k1zkp_v0_8_0_scalar_shr_int(&s, w); - do { - int even; - - /* 4.1 4.4 */ - u = rustsecp256k1zkp_v0_8_0_scalar_shr_int(&s, w); - /* 4.2 */ - even = ((u & 1) == 0); - /* In contrast to the original algorithm, u_last is always > 0 and - * therefore we do not need to check its sign. In particular, it's easy - * to see that u_last is never < 0 because u is never < 0. Moreover, - * u_last is never = 0 because u is never even after a loop - * iteration. The same holds analogously for the initial value of - * u_last (in the first loop iteration). */ - VERIFY_CHECK(u_last > 0); - VERIFY_CHECK((u_last & 1) == 1); - u += even; - u_last -= even * (1 << w); - - /* 4.3, adapted for global sign change */ - wnaf[word++] = u_last * global_sign; - - u_last = u; - } while (word * w < size); - wnaf[word] = u * global_sign; - - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_scalar_is_zero(&s)); - VERIFY_CHECK(word == WNAF_SIZE_BITS(size, w)); - return skew; -} - -static void rustsecp256k1zkp_v0_8_0_ecmult_const(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_ge *a, const rustsecp256k1zkp_v0_8_0_scalar *scalar, int size) { - rustsecp256k1zkp_v0_8_0_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; - rustsecp256k1zkp_v0_8_0_ge tmpa; - rustsecp256k1zkp_v0_8_0_fe Z; - - int skew_1; - rustsecp256k1zkp_v0_8_0_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; - int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; - int skew_lam; - rustsecp256k1zkp_v0_8_0_scalar q_1, q_lam; - int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; - - int i; - - /* build wnaf representation for q. */ - int rsize = size; - if (size > 128) { - rsize = 128; - /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ - rustsecp256k1zkp_v0_8_0_scalar_split_lambda(&q_1, &q_lam, scalar); - skew_1 = rustsecp256k1zkp_v0_8_0_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128); - skew_lam = rustsecp256k1zkp_v0_8_0_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128); - } else - { - skew_1 = rustsecp256k1zkp_v0_8_0_wnaf_const(wnaf_1, scalar, WINDOW_A - 1, size); - skew_lam = 0; - } - - /* Calculate odd multiples of a. - * All multiples are brought to the same Z 'denominator', which is stored - * in Z. Due to secp256k1' isomorphism we can do all operations pretending - * that the Z coordinate was 1, use affine addition formulae, and correct - * the Z coordinate of the result once at the end. - */ - VERIFY_CHECK(!a->infinity); - rustsecp256k1zkp_v0_8_0_gej_set_ge(r, a); - rustsecp256k1zkp_v0_8_0_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r); - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&pre_a[i].y); - } - if (size > 128) { - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - rustsecp256k1zkp_v0_8_0_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); - } - - } - - /* first loop iteration (separated out so we can directly set r, rather - * than having it start at infinity, get doubled several times, then have - * its new value added to it) */ - i = wnaf_1[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)]; - VERIFY_CHECK(i != 0); - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); - rustsecp256k1zkp_v0_8_0_gej_set_ge(r, &tmpa); - if (size > 128) { - i = wnaf_lam[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)]; - VERIFY_CHECK(i != 0); - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A); - rustsecp256k1zkp_v0_8_0_gej_add_ge(r, r, &tmpa); - } - /* remaining loop iterations */ - for (i = WNAF_SIZE_BITS(rsize, WINDOW_A - 1) - 1; i >= 0; i--) { - int n; - int j; - for (j = 0; j < WINDOW_A - 1; ++j) { - rustsecp256k1zkp_v0_8_0_gej_double(r, r); - } - - n = wnaf_1[i]; - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); - VERIFY_CHECK(n != 0); - rustsecp256k1zkp_v0_8_0_gej_add_ge(r, r, &tmpa); - if (size > 128) { - n = wnaf_lam[i]; - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); - VERIFY_CHECK(n != 0); - rustsecp256k1zkp_v0_8_0_gej_add_ge(r, r, &tmpa); - } - } - - { - /* Correct for wNAF skew */ - rustsecp256k1zkp_v0_8_0_gej tmpj; - - rustsecp256k1zkp_v0_8_0_ge_neg(&tmpa, &pre_a[0]); - rustsecp256k1zkp_v0_8_0_gej_add_ge(&tmpj, r, &tmpa); - rustsecp256k1zkp_v0_8_0_gej_cmov(r, &tmpj, skew_1); - - if (size > 128) { - rustsecp256k1zkp_v0_8_0_ge_neg(&tmpa, &pre_a_lam[0]); - rustsecp256k1zkp_v0_8_0_gej_add_ge(&tmpj, r, &tmpa); - rustsecp256k1zkp_v0_8_0_gej_cmov(r, &tmpj, skew_lam); - } - } - - rustsecp256k1zkp_v0_8_0_fe_mul(&r->z, &r->z, &Z); -} - -#endif /* SECP256K1_ECMULT_CONST_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_gen.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_gen.h deleted file mode 100644 index d8f5cd7a..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_gen.h +++ /dev/null @@ -1,36 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECMULT_GEN_H -#define SECP256K1_ECMULT_GEN_H - -#include "scalar.h" -#include "group.h" - -#if ECMULT_GEN_PREC_BITS != 2 && ECMULT_GEN_PREC_BITS != 4 && ECMULT_GEN_PREC_BITS != 8 -# error "Set ECMULT_GEN_PREC_BITS to 2, 4 or 8." -#endif -#define ECMULT_GEN_PREC_G(bits) (1 << bits) -#define ECMULT_GEN_PREC_N(bits) (256 / bits) - -typedef struct { - /* Whether the context has been built. */ - int built; - - /* Blinding values used when computing (n-b)G + bG. */ - rustsecp256k1zkp_v0_8_0_scalar blind; /* -b */ - rustsecp256k1zkp_v0_8_0_gej initial; /* bG */ -} rustsecp256k1zkp_v0_8_0_ecmult_gen_context; - -static void rustsecp256k1zkp_v0_8_0_ecmult_gen_context_build(rustsecp256k1zkp_v0_8_0_ecmult_gen_context* ctx); -static void rustsecp256k1zkp_v0_8_0_ecmult_gen_context_clear(rustsecp256k1zkp_v0_8_0_ecmult_gen_context* ctx); - -/** Multiply with the generator: R = a*G */ -static void rustsecp256k1zkp_v0_8_0_ecmult_gen(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context* ctx, rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_scalar *a); - -static void rustsecp256k1zkp_v0_8_0_ecmult_gen_blind(rustsecp256k1zkp_v0_8_0_ecmult_gen_context *ctx, const unsigned char *seed32); - -#endif /* SECP256K1_ECMULT_GEN_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_gen_compute_table_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_gen_compute_table_impl.h deleted file mode 100644 index a21d2060..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_gen_compute_table_impl.h +++ /dev/null @@ -1,81 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H -#define SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H - -#include "ecmult_gen_compute_table.h" -#include "group_impl.h" -#include "field_impl.h" -#include "ecmult_gen.h" -#include "util.h" - -static void rustsecp256k1zkp_v0_8_0_ecmult_gen_compute_table(rustsecp256k1zkp_v0_8_0_ge_storage* table, const rustsecp256k1zkp_v0_8_0_ge* gen, int bits) { - int g = ECMULT_GEN_PREC_G(bits); - int n = ECMULT_GEN_PREC_N(bits); - - rustsecp256k1zkp_v0_8_0_ge* prec = checked_malloc(&default_error_callback, n * g * sizeof(*prec)); - rustsecp256k1zkp_v0_8_0_gej gj; - rustsecp256k1zkp_v0_8_0_gej nums_gej; - int i, j; - - /* get the generator */ - rustsecp256k1zkp_v0_8_0_gej_set_ge(&gj, gen); - - /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ - { - static const unsigned char nums_b32[33] = "The scalar for this x is unknown"; - rustsecp256k1zkp_v0_8_0_fe nums_x; - rustsecp256k1zkp_v0_8_0_ge nums_ge; - int r; - r = rustsecp256k1zkp_v0_8_0_fe_set_b32(&nums_x, nums_b32); - (void)r; - VERIFY_CHECK(r); - r = rustsecp256k1zkp_v0_8_0_ge_set_xo_var(&nums_ge, &nums_x, 0); - (void)r; - VERIFY_CHECK(r); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&nums_gej, &nums_ge); - /* Add G to make the bits in x uniformly distributed. */ - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&nums_gej, &nums_gej, gen, NULL); - } - - /* compute prec. */ - { - rustsecp256k1zkp_v0_8_0_gej gbase; - rustsecp256k1zkp_v0_8_0_gej numsbase; - rustsecp256k1zkp_v0_8_0_gej* precj = checked_malloc(&default_error_callback, n * g * sizeof(*precj)); /* Jacobian versions of prec. */ - gbase = gj; /* PREC_G^j * G */ - numsbase = nums_gej; /* 2^j * nums. */ - for (j = 0; j < n; j++) { - /* Set precj[j*PREC_G .. j*PREC_G+(PREC_G-1)] to (numsbase, numsbase + gbase, ..., numsbase + (PREC_G-1)*gbase). */ - precj[j*g] = numsbase; - for (i = 1; i < g; i++) { - rustsecp256k1zkp_v0_8_0_gej_add_var(&precj[j*g + i], &precj[j*g + i - 1], &gbase, NULL); - } - /* Multiply gbase by PREC_G. */ - for (i = 0; i < bits; i++) { - rustsecp256k1zkp_v0_8_0_gej_double_var(&gbase, &gbase, NULL); - } - /* Multiply numbase by 2. */ - rustsecp256k1zkp_v0_8_0_gej_double_var(&numsbase, &numsbase, NULL); - if (j == n - 2) { - /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ - rustsecp256k1zkp_v0_8_0_gej_neg(&numsbase, &numsbase); - rustsecp256k1zkp_v0_8_0_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); - } - } - rustsecp256k1zkp_v0_8_0_ge_set_all_gej_var(prec, precj, n * g); - free(precj); - } - for (j = 0; j < n; j++) { - for (i = 0; i < g; i++) { - rustsecp256k1zkp_v0_8_0_ge_to_storage(&table[j*g + i], &prec[j*g + i]); - } - } - free(prec); -} - -#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_gen_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_gen_impl.h deleted file mode 100644 index 324d300c..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_gen_impl.h +++ /dev/null @@ -1,132 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_ECMULT_GEN_IMPL_H -#define SECP256K1_ECMULT_GEN_IMPL_H - -#include "util.h" -#include "scalar.h" -#include "group.h" -#include "ecmult_gen.h" -#include "hash_impl.h" -#include "precomputed_ecmult_gen.h" - -static void rustsecp256k1zkp_v0_8_0_ecmult_gen_context_build(rustsecp256k1zkp_v0_8_0_ecmult_gen_context *ctx) { - rustsecp256k1zkp_v0_8_0_ecmult_gen_blind(ctx, NULL); - ctx->built = 1; -} - -static int rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context* ctx) { - return ctx->built; -} - -static void rustsecp256k1zkp_v0_8_0_ecmult_gen_context_clear(rustsecp256k1zkp_v0_8_0_ecmult_gen_context *ctx) { - ctx->built = 0; - rustsecp256k1zkp_v0_8_0_scalar_clear(&ctx->blind); - rustsecp256k1zkp_v0_8_0_gej_clear(&ctx->initial); -} - -/* For accelerating the computation of a*G: - * To harden against timing attacks, use the following mechanism: - * * Break up the multiplicand into groups of PREC_BITS bits, called n_0, n_1, n_2, ..., n_(PREC_N-1). - * * Compute sum(n_i * (PREC_G)^i * G + U_i, i=0 ... PREC_N-1), where: - * * U_i = U * 2^i, for i=0 ... PREC_N-2 - * * U_i = U * (1-2^(PREC_N-1)), for i=PREC_N-1 - * where U is a point with no known corresponding scalar. Note that sum(U_i, i=0 ... PREC_N-1) = 0. - * For each i, and each of the PREC_G possible values of n_i, (n_i * (PREC_G)^i * G + U_i) is - * precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0 ... PREC_N-1). - * None of the resulting prec group elements have a known scalar, and neither do any of - * the intermediate sums while computing a*G. - * The prec values are stored in rustsecp256k1zkp_v0_8_0_ecmult_gen_prec_table[i][n_i] = n_i * (PREC_G)^i * G + U_i. - */ -static void rustsecp256k1zkp_v0_8_0_ecmult_gen(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context *ctx, rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_scalar *gn) { - int bits = ECMULT_GEN_PREC_BITS; - int g = ECMULT_GEN_PREC_G(bits); - int n = ECMULT_GEN_PREC_N(bits); - - rustsecp256k1zkp_v0_8_0_ge add; - rustsecp256k1zkp_v0_8_0_ge_storage adds; - rustsecp256k1zkp_v0_8_0_scalar gnb; - int i, j, n_i; - - memset(&adds, 0, sizeof(adds)); - *r = ctx->initial; - /* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */ - rustsecp256k1zkp_v0_8_0_scalar_add(&gnb, gn, &ctx->blind); - add.infinity = 0; - for (i = 0; i < n; i++) { - n_i = rustsecp256k1zkp_v0_8_0_scalar_get_bits(&gnb, i * bits, bits); - for (j = 0; j < g; j++) { - /** This uses a conditional move to avoid any secret data in array indexes. - * _Any_ use of secret indexes has been demonstrated to result in timing - * sidechannels, even when the cache-line access patterns are uniform. - * See also: - * "A word of warning", CHES 2013 Rump Session, by Daniel J. Bernstein and Peter Schwabe - * (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and - * "Cache Attacks and Countermeasures: the Case of AES", RSA 2006, - * by Dag Arne Osvik, Adi Shamir, and Eran Tromer - * (https://www.tau.ac.il/~tromer/papers/cache.pdf) - */ - rustsecp256k1zkp_v0_8_0_ge_storage_cmov(&adds, &rustsecp256k1zkp_v0_8_0_ecmult_gen_prec_table[i][j], j == n_i); - } - rustsecp256k1zkp_v0_8_0_ge_from_storage(&add, &adds); - rustsecp256k1zkp_v0_8_0_gej_add_ge(r, r, &add); - } - n_i = 0; - rustsecp256k1zkp_v0_8_0_ge_clear(&add); - rustsecp256k1zkp_v0_8_0_scalar_clear(&gnb); -} - -/* Setup blinding values for rustsecp256k1zkp_v0_8_0_ecmult_gen. */ -static void rustsecp256k1zkp_v0_8_0_ecmult_gen_blind(rustsecp256k1zkp_v0_8_0_ecmult_gen_context *ctx, const unsigned char *seed32) { - rustsecp256k1zkp_v0_8_0_scalar b; - rustsecp256k1zkp_v0_8_0_gej gb; - rustsecp256k1zkp_v0_8_0_fe s; - unsigned char nonce32[32]; - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256 rng; - int overflow; - unsigned char keydata[64] = {0}; - if (seed32 == NULL) { - /* When seed is NULL, reset the initial point and blinding value. */ - rustsecp256k1zkp_v0_8_0_gej_set_ge(&ctx->initial, &rustsecp256k1zkp_v0_8_0_ge_const_g); - rustsecp256k1zkp_v0_8_0_gej_neg(&ctx->initial, &ctx->initial); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&ctx->blind, 1); - } - /* The prior blinding value (if not reset) is chained forward by including it in the hash. */ - rustsecp256k1zkp_v0_8_0_scalar_get_b32(nonce32, &ctx->blind); - /** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data, - * and guards against weak or adversarial seeds. This is a simpler and safer interface than - * asking the caller for blinding values directly and expecting them to retry on failure. - */ - memcpy(keydata, nonce32, 32); - if (seed32 != NULL) { - memcpy(keydata + 32, seed32, 32); - } - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32); - memset(keydata, 0, sizeof(keydata)); - /* Accept unobservably small non-uniformity. */ - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); - overflow = !rustsecp256k1zkp_v0_8_0_fe_set_b32(&s, nonce32); - overflow |= rustsecp256k1zkp_v0_8_0_fe_is_zero(&s); - rustsecp256k1zkp_v0_8_0_fe_cmov(&s, &rustsecp256k1zkp_v0_8_0_fe_one, overflow); - /* Randomize the projection to defend against multiplier sidechannels. */ - rustsecp256k1zkp_v0_8_0_gej_rescale(&ctx->initial, &s); - rustsecp256k1zkp_v0_8_0_fe_clear(&s); - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&b, nonce32, NULL); - /* A blinding value of 0 works, but would undermine the projection hardening. */ - rustsecp256k1zkp_v0_8_0_scalar_cmov(&b, &rustsecp256k1zkp_v0_8_0_scalar_one, rustsecp256k1zkp_v0_8_0_scalar_is_zero(&b)); - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_finalize(&rng); - memset(nonce32, 0, 32); - rustsecp256k1zkp_v0_8_0_ecmult_gen(ctx, &gb, &b); - rustsecp256k1zkp_v0_8_0_scalar_negate(&b, &b); - ctx->blind = b; - ctx->initial = gb; - rustsecp256k1zkp_v0_8_0_scalar_clear(&b); - rustsecp256k1zkp_v0_8_0_gej_clear(&gb); -} - -#endif /* SECP256K1_ECMULT_GEN_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_impl.h deleted file mode 100644 index a5565d78..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_impl.h +++ /dev/null @@ -1,859 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra, Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php. * - ******************************************************************************/ - -#ifndef SECP256K1_ECMULT_IMPL_H -#define SECP256K1_ECMULT_IMPL_H - -#include -#include - -#include "util.h" -#include "group.h" -#include "scalar.h" -#include "ecmult.h" -#include "precomputed_ecmult.h" - -#if defined(EXHAUSTIVE_TEST_ORDER) -/* We need to lower these values for exhaustive tests because - * the tables cannot have infinities in them (this breaks the - * affine-isomorphism stuff which tracks z-ratios) */ -# if EXHAUSTIVE_TEST_ORDER > 128 -# define WINDOW_A 5 -# elif EXHAUSTIVE_TEST_ORDER > 8 -# define WINDOW_A 4 -# else -# define WINDOW_A 2 -# endif -#else -/* optimal for 128-bit and 256-bit exponents. */ -# define WINDOW_A 5 -/** Larger values for ECMULT_WINDOW_SIZE result in possibly better - * performance at the cost of an exponentially larger precomputed - * table. The exact table size is - * (1 << (WINDOW_G - 2)) * sizeof(rustsecp256k1zkp_v0_8_0_ge_storage) bytes, - * where sizeof(rustsecp256k1zkp_v0_8_0_ge_storage) is typically 64 bytes but can - * be larger due to platform-specific padding and alignment. - * Two tables of this size are used (due to the endomorphism - * optimization). - */ -#endif - -#define WNAF_BITS 128 -#define WNAF_SIZE_BITS(bits, w) (((bits) + (w) - 1) / (w)) -#define WNAF_SIZE(w) WNAF_SIZE_BITS(WNAF_BITS, w) - -/* The number of objects allocated on the scratch space for ecmult_multi algorithms */ -#define PIPPENGER_SCRATCH_OBJECTS 6 -#define STRAUSS_SCRATCH_OBJECTS 5 - -#define PIPPENGER_MAX_BUCKET_WINDOW 12 - -/* Minimum number of points for which pippenger_wnaf is faster than strauss wnaf */ -#define ECMULT_PIPPENGER_THRESHOLD 88 - -#define ECMULT_MAX_POINTS_PER_BATCH 5000000 - -/** Fill a table 'pre_a' with precomputed odd multiples of a. - * pre_a will contain [1*a,3*a,...,(2*n-1)*a], so it needs space for n group elements. - * zr needs space for n field elements. - * - * Although pre_a is an array of _ge rather than _gej, it actually represents elements - * in Jacobian coordinates with their z coordinates omitted. The omitted z-coordinates - * can be recovered using z and zr. Using the notation z(b) to represent the omitted - * z coordinate of b: - * - z(pre_a[n-1]) = 'z' - * - z(pre_a[i-1]) = z(pre_a[i]) / zr[i] for n > i > 0 - * - * Lastly the zr[0] value, which isn't used above, is set so that: - * - a.z = z(pre_a[0]) / zr[0] - */ -static void rustsecp256k1zkp_v0_8_0_ecmult_odd_multiples_table(int n, rustsecp256k1zkp_v0_8_0_ge *pre_a, rustsecp256k1zkp_v0_8_0_fe *zr, rustsecp256k1zkp_v0_8_0_fe *z, const rustsecp256k1zkp_v0_8_0_gej *a) { - rustsecp256k1zkp_v0_8_0_gej d, ai; - rustsecp256k1zkp_v0_8_0_ge d_ge; - int i; - - VERIFY_CHECK(!a->infinity); - - rustsecp256k1zkp_v0_8_0_gej_double_var(&d, a, NULL); - - /* - * Perform the additions using an isomorphic curve Y^2 = X^3 + 7*C^6 where C := d.z. - * The isomorphism, phi, maps a secp256k1 point (x, y) to the point (x*C^2, y*C^3) on the other curve. - * In Jacobian coordinates phi maps (x, y, z) to (x*C^2, y*C^3, z) or, equivalently to (x, y, z/C). - * - * phi(x, y, z) = (x*C^2, y*C^3, z) = (x, y, z/C) - * d_ge := phi(d) = (d.x, d.y, 1) - * ai := phi(a) = (a.x*C^2, a.y*C^3, a.z) - * - * The group addition functions work correctly on these isomorphic curves. - * In particular phi(d) is easy to represent in affine coordinates under this isomorphism. - * This lets us use the faster rustsecp256k1zkp_v0_8_0_gej_add_ge_var group addition function that we wouldn't be able to use otherwise. - */ - rustsecp256k1zkp_v0_8_0_ge_set_xy(&d_ge, &d.x, &d.y); - rustsecp256k1zkp_v0_8_0_ge_set_gej_zinv(&pre_a[0], a, &d.z); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&ai, &pre_a[0]); - ai.z = a->z; - - /* pre_a[0] is the point (a.x*C^2, a.y*C^3, a.z*C) which is equvalent to a. - * Set zr[0] to C, which is the ratio between the omitted z(pre_a[0]) value and a.z. - */ - zr[0] = d.z; - - for (i = 1; i < n; i++) { - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&ai, &ai, &d_ge, &zr[i]); - rustsecp256k1zkp_v0_8_0_ge_set_xy(&pre_a[i], &ai.x, &ai.y); - } - - /* Multiply the last z-coordinate by C to undo the isomorphism. - * Since the z-coordinates of the pre_a values are implied by the zr array of z-coordinate ratios, - * undoing the isomorphism here undoes the isomorphism for all pre_a values. - */ - rustsecp256k1zkp_v0_8_0_fe_mul(z, &ai.z, &d.z); -} - -#define SECP256K1_ECMULT_TABLE_VERIFY(n,w) \ - VERIFY_CHECK(((n) & 1) == 1); \ - VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ - VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_ecmult_table_get_ge(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_ge *pre, int n, int w) { - SECP256K1_ECMULT_TABLE_VERIFY(n,w) - if (n > 0) { - *r = pre[(n-1)/2]; - } else { - *r = pre[(-n-1)/2]; - rustsecp256k1zkp_v0_8_0_fe_negate(&(r->y), &(r->y), 1); - } -} - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_ecmult_table_get_ge_lambda(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_ge *pre, const rustsecp256k1zkp_v0_8_0_fe *x, int n, int w) { - SECP256K1_ECMULT_TABLE_VERIFY(n,w) - if (n > 0) { - rustsecp256k1zkp_v0_8_0_ge_set_xy(r, &x[(n-1)/2], &pre[(n-1)/2].y); - } else { - rustsecp256k1zkp_v0_8_0_ge_set_xy(r, &x[(-n-1)/2], &pre[(-n-1)/2].y); - rustsecp256k1zkp_v0_8_0_fe_negate(&(r->y), &(r->y), 1); - } -} - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_ecmult_table_get_ge_storage(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_ge_storage *pre, int n, int w) { - SECP256K1_ECMULT_TABLE_VERIFY(n,w) - if (n > 0) { - rustsecp256k1zkp_v0_8_0_ge_from_storage(r, &pre[(n-1)/2]); - } else { - rustsecp256k1zkp_v0_8_0_ge_from_storage(r, &pre[(-n-1)/2]); - rustsecp256k1zkp_v0_8_0_fe_negate(&(r->y), &(r->y), 1); - } -} - -/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits), - * with the following guarantees: - * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1) - * - two non-zero entries in wnaf are separated by at least w-1 zeroes. - * - the number of set values in wnaf is returned. This number is at most 256, and at most one more - * than the number of bits in the (absolute value) of the input. - */ -static int rustsecp256k1zkp_v0_8_0_ecmult_wnaf(int *wnaf, int len, const rustsecp256k1zkp_v0_8_0_scalar *a, int w) { - rustsecp256k1zkp_v0_8_0_scalar s; - int last_set_bit = -1; - int bit = 0; - int sign = 1; - int carry = 0; - - VERIFY_CHECK(wnaf != NULL); - VERIFY_CHECK(0 <= len && len <= 256); - VERIFY_CHECK(a != NULL); - VERIFY_CHECK(2 <= w && w <= 31); - - memset(wnaf, 0, len * sizeof(wnaf[0])); - - s = *a; - if (rustsecp256k1zkp_v0_8_0_scalar_get_bits(&s, 255, 1)) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&s, &s); - sign = -1; - } - - while (bit < len) { - int now; - int word; - if (rustsecp256k1zkp_v0_8_0_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) { - bit++; - continue; - } - - now = w; - if (now > len - bit) { - now = len - bit; - } - - word = rustsecp256k1zkp_v0_8_0_scalar_get_bits_var(&s, bit, now) + carry; - - carry = (word >> (w-1)) & 1; - word -= carry << w; - - wnaf[bit] = sign * word; - last_set_bit = bit; - - bit += now; - } -#ifdef VERIFY - CHECK(carry == 0); - while (bit < 256) { - CHECK(rustsecp256k1zkp_v0_8_0_scalar_get_bits(&s, bit++, 1) == 0); - } -#endif - return last_set_bit + 1; -} - -struct rustsecp256k1zkp_v0_8_0_strauss_point_state { - int wnaf_na_1[129]; - int wnaf_na_lam[129]; - int bits_na_1; - int bits_na_lam; -}; - -struct rustsecp256k1zkp_v0_8_0_strauss_state { - /* aux is used to hold z-ratios, and then used to hold pre_a[i].x * BETA values. */ - rustsecp256k1zkp_v0_8_0_fe* aux; - rustsecp256k1zkp_v0_8_0_ge* pre_a; - struct rustsecp256k1zkp_v0_8_0_strauss_point_state* ps; -}; - -static void rustsecp256k1zkp_v0_8_0_ecmult_strauss_wnaf(const struct rustsecp256k1zkp_v0_8_0_strauss_state *state, rustsecp256k1zkp_v0_8_0_gej *r, size_t num, const rustsecp256k1zkp_v0_8_0_gej *a, const rustsecp256k1zkp_v0_8_0_scalar *na, const rustsecp256k1zkp_v0_8_0_scalar *ng) { - rustsecp256k1zkp_v0_8_0_ge tmpa; - rustsecp256k1zkp_v0_8_0_fe Z; - /* Split G factors. */ - rustsecp256k1zkp_v0_8_0_scalar ng_1, ng_128; - int wnaf_ng_1[129]; - int bits_ng_1 = 0; - int wnaf_ng_128[129]; - int bits_ng_128 = 0; - int i; - int bits = 0; - size_t np; - size_t no = 0; - - rustsecp256k1zkp_v0_8_0_fe_set_int(&Z, 1); - for (np = 0; np < num; ++np) { - rustsecp256k1zkp_v0_8_0_gej tmp; - rustsecp256k1zkp_v0_8_0_scalar na_1, na_lam; - if (rustsecp256k1zkp_v0_8_0_scalar_is_zero(&na[np]) || rustsecp256k1zkp_v0_8_0_gej_is_infinity(&a[np])) { - continue; - } - /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ - rustsecp256k1zkp_v0_8_0_scalar_split_lambda(&na_1, &na_lam, &na[np]); - - /* build wnaf representation for na_1 and na_lam. */ - state->ps[no].bits_na_1 = rustsecp256k1zkp_v0_8_0_ecmult_wnaf(state->ps[no].wnaf_na_1, 129, &na_1, WINDOW_A); - state->ps[no].bits_na_lam = rustsecp256k1zkp_v0_8_0_ecmult_wnaf(state->ps[no].wnaf_na_lam, 129, &na_lam, WINDOW_A); - VERIFY_CHECK(state->ps[no].bits_na_1 <= 129); - VERIFY_CHECK(state->ps[no].bits_na_lam <= 129); - if (state->ps[no].bits_na_1 > bits) { - bits = state->ps[no].bits_na_1; - } - if (state->ps[no].bits_na_lam > bits) { - bits = state->ps[no].bits_na_lam; - } - - /* Calculate odd multiples of a. - * All multiples are brought to the same Z 'denominator', which is stored - * in Z. Due to secp256k1' isomorphism we can do all operations pretending - * that the Z coordinate was 1, use affine addition formulae, and correct - * the Z coordinate of the result once at the end. - * The exception is the precomputed G table points, which are actually - * affine. Compared to the base used for other points, they have a Z ratio - * of 1/Z, so we can use rustsecp256k1zkp_v0_8_0_gej_add_zinv_var, which uses the same - * isomorphism to efficiently add with a known Z inverse. - */ - tmp = a[np]; - if (no) { -#ifdef VERIFY - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&Z); -#endif - rustsecp256k1zkp_v0_8_0_gej_rescale(&tmp, &Z); - } - rustsecp256k1zkp_v0_8_0_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &Z, &tmp); - if (no) rustsecp256k1zkp_v0_8_0_fe_mul(state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &(a[np].z)); - - ++no; - } - - /* Bring them to the same Z denominator. */ - rustsecp256k1zkp_v0_8_0_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux); - - for (np = 0; np < no; ++np) { - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - rustsecp256k1zkp_v0_8_0_fe_mul(&state->aux[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i].x, &rustsecp256k1zkp_v0_8_0_const_beta); - } - } - - if (ng) { - /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ - rustsecp256k1zkp_v0_8_0_scalar_split_128(&ng_1, &ng_128, ng); - - /* Build wnaf representation for ng_1 and ng_128 */ - bits_ng_1 = rustsecp256k1zkp_v0_8_0_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G); - bits_ng_128 = rustsecp256k1zkp_v0_8_0_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G); - if (bits_ng_1 > bits) { - bits = bits_ng_1; - } - if (bits_ng_128 > bits) { - bits = bits_ng_128; - } - } - - rustsecp256k1zkp_v0_8_0_gej_set_infinity(r); - - for (i = bits - 1; i >= 0; i--) { - int n; - rustsecp256k1zkp_v0_8_0_gej_double_var(r, r, NULL); - for (np = 0; np < no; ++np) { - if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) { - rustsecp256k1zkp_v0_8_0_ecmult_table_get_ge(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(r, r, &tmpa, NULL); - } - if (i < state->ps[np].bits_na_lam && (n = state->ps[np].wnaf_na_lam[i])) { - rustsecp256k1zkp_v0_8_0_ecmult_table_get_ge_lambda(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(r, r, &tmpa, NULL); - } - } - if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { - rustsecp256k1zkp_v0_8_0_ecmult_table_get_ge_storage(&tmpa, rustsecp256k1zkp_v0_8_0_pre_g, n, WINDOW_G); - rustsecp256k1zkp_v0_8_0_gej_add_zinv_var(r, r, &tmpa, &Z); - } - if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { - rustsecp256k1zkp_v0_8_0_ecmult_table_get_ge_storage(&tmpa, rustsecp256k1zkp_v0_8_0_pre_g_128, n, WINDOW_G); - rustsecp256k1zkp_v0_8_0_gej_add_zinv_var(r, r, &tmpa, &Z); - } - } - - if (!r->infinity) { - rustsecp256k1zkp_v0_8_0_fe_mul(&r->z, &r->z, &Z); - } -} - -static void rustsecp256k1zkp_v0_8_0_ecmult(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a, const rustsecp256k1zkp_v0_8_0_scalar *na, const rustsecp256k1zkp_v0_8_0_scalar *ng) { - rustsecp256k1zkp_v0_8_0_fe aux[ECMULT_TABLE_SIZE(WINDOW_A)]; - rustsecp256k1zkp_v0_8_0_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; - struct rustsecp256k1zkp_v0_8_0_strauss_point_state ps[1]; - struct rustsecp256k1zkp_v0_8_0_strauss_state state; - - state.aux = aux; - state.pre_a = pre_a; - state.ps = ps; - rustsecp256k1zkp_v0_8_0_ecmult_strauss_wnaf(&state, r, 1, a, na, ng); -} - -static size_t rustsecp256k1zkp_v0_8_0_strauss_scratch_size(size_t n_points) { - static const size_t point_size = (sizeof(rustsecp256k1zkp_v0_8_0_ge) + sizeof(rustsecp256k1zkp_v0_8_0_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct rustsecp256k1zkp_v0_8_0_strauss_point_state) + sizeof(rustsecp256k1zkp_v0_8_0_gej) + sizeof(rustsecp256k1zkp_v0_8_0_scalar); - return n_points*point_size; -} - -static int rustsecp256k1zkp_v0_8_0_ecmult_strauss_batch(const rustsecp256k1zkp_v0_8_0_callback* error_callback, rustsecp256k1zkp_v0_8_0_scratch *scratch, rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_scalar *inp_g_sc, rustsecp256k1zkp_v0_8_0_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { - rustsecp256k1zkp_v0_8_0_gej* points; - rustsecp256k1zkp_v0_8_0_scalar* scalars; - struct rustsecp256k1zkp_v0_8_0_strauss_state state; - size_t i; - const size_t scratch_checkpoint = rustsecp256k1zkp_v0_8_0_scratch_checkpoint(error_callback, scratch); - - rustsecp256k1zkp_v0_8_0_gej_set_infinity(r); - if (inp_g_sc == NULL && n_points == 0) { - return 1; - } - - /* We allocate STRAUSS_SCRATCH_OBJECTS objects on the scratch space. If these - * allocations change, make sure to update the STRAUSS_SCRATCH_OBJECTS - * constant and strauss_scratch_size accordingly. */ - points = (rustsecp256k1zkp_v0_8_0_gej*)rustsecp256k1zkp_v0_8_0_scratch_alloc(error_callback, scratch, n_points * sizeof(rustsecp256k1zkp_v0_8_0_gej)); - scalars = (rustsecp256k1zkp_v0_8_0_scalar*)rustsecp256k1zkp_v0_8_0_scratch_alloc(error_callback, scratch, n_points * sizeof(rustsecp256k1zkp_v0_8_0_scalar)); - state.aux = (rustsecp256k1zkp_v0_8_0_fe*)rustsecp256k1zkp_v0_8_0_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(rustsecp256k1zkp_v0_8_0_fe)); - state.pre_a = (rustsecp256k1zkp_v0_8_0_ge*)rustsecp256k1zkp_v0_8_0_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(rustsecp256k1zkp_v0_8_0_ge)); - state.ps = (struct rustsecp256k1zkp_v0_8_0_strauss_point_state*)rustsecp256k1zkp_v0_8_0_scratch_alloc(error_callback, scratch, n_points * sizeof(struct rustsecp256k1zkp_v0_8_0_strauss_point_state)); - - if (points == NULL || scalars == NULL || state.aux == NULL || state.pre_a == NULL || state.ps == NULL) { - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); - return 0; - } - - for (i = 0; i < n_points; i++) { - rustsecp256k1zkp_v0_8_0_ge point; - if (!cb(&scalars[i], &point, i+cb_offset, cbdata)) { - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); - return 0; - } - rustsecp256k1zkp_v0_8_0_gej_set_ge(&points[i], &point); - } - rustsecp256k1zkp_v0_8_0_ecmult_strauss_wnaf(&state, r, n_points, points, scalars, inp_g_sc); - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); - return 1; -} - -/* Wrapper for rustsecp256k1zkp_v0_8_0_ecmult_multi_func interface */ -static int rustsecp256k1zkp_v0_8_0_ecmult_strauss_batch_single(const rustsecp256k1zkp_v0_8_0_callback* error_callback, rustsecp256k1zkp_v0_8_0_scratch *scratch, rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_scalar *inp_g_sc, rustsecp256k1zkp_v0_8_0_ecmult_multi_callback cb, void *cbdata, size_t n) { - return rustsecp256k1zkp_v0_8_0_ecmult_strauss_batch(error_callback, scratch, r, inp_g_sc, cb, cbdata, n, 0); -} - -static size_t rustsecp256k1zkp_v0_8_0_strauss_max_points(const rustsecp256k1zkp_v0_8_0_callback* error_callback, rustsecp256k1zkp_v0_8_0_scratch *scratch) { - return rustsecp256k1zkp_v0_8_0_scratch_max_allocation(error_callback, scratch, STRAUSS_SCRATCH_OBJECTS) / rustsecp256k1zkp_v0_8_0_strauss_scratch_size(1); -} - -/** Convert a number to WNAF notation. - * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. - * It has the following guarantees: - * - each wnaf[i] is either 0 or an odd integer between -(1 << w) and (1 << w) - * - the number of words set is always WNAF_SIZE(w) - * - the returned skew is 0 or 1 - */ -static int rustsecp256k1zkp_v0_8_0_wnaf_fixed(int *wnaf, const rustsecp256k1zkp_v0_8_0_scalar *s, int w) { - int skew = 0; - int pos; - int max_pos; - int last_w; - const rustsecp256k1zkp_v0_8_0_scalar *work = s; - - if (rustsecp256k1zkp_v0_8_0_scalar_is_zero(s)) { - for (pos = 0; pos < WNAF_SIZE(w); pos++) { - wnaf[pos] = 0; - } - return 0; - } - - if (rustsecp256k1zkp_v0_8_0_scalar_is_even(s)) { - skew = 1; - } - - wnaf[0] = rustsecp256k1zkp_v0_8_0_scalar_get_bits_var(work, 0, w) + skew; - /* Compute last window size. Relevant when window size doesn't divide the - * number of bits in the scalar */ - last_w = WNAF_BITS - (WNAF_SIZE(w) - 1) * w; - - /* Store the position of the first nonzero word in max_pos to allow - * skipping leading zeros when calculating the wnaf. */ - for (pos = WNAF_SIZE(w) - 1; pos > 0; pos--) { - int val = rustsecp256k1zkp_v0_8_0_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w); - if(val != 0) { - break; - } - wnaf[pos] = 0; - } - max_pos = pos; - pos = 1; - - while (pos <= max_pos) { - int val = rustsecp256k1zkp_v0_8_0_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w); - if ((val & 1) == 0) { - wnaf[pos - 1] -= (1 << w); - wnaf[pos] = (val + 1); - } else { - wnaf[pos] = val; - } - /* Set a coefficient to zero if it is 1 or -1 and the proceeding digit - * is strictly negative or strictly positive respectively. Only change - * coefficients at previous positions because above code assumes that - * wnaf[pos - 1] is odd. - */ - if (pos >= 2 && ((wnaf[pos - 1] == 1 && wnaf[pos - 2] < 0) || (wnaf[pos - 1] == -1 && wnaf[pos - 2] > 0))) { - if (wnaf[pos - 1] == 1) { - wnaf[pos - 2] += 1 << w; - } else { - wnaf[pos - 2] -= 1 << w; - } - wnaf[pos - 1] = 0; - } - ++pos; - } - - return skew; -} - -struct rustsecp256k1zkp_v0_8_0_pippenger_point_state { - int skew_na; - size_t input_pos; -}; - -struct rustsecp256k1zkp_v0_8_0_pippenger_state { - int *wnaf_na; - struct rustsecp256k1zkp_v0_8_0_pippenger_point_state* ps; -}; - -/* - * pippenger_wnaf computes the result of a multi-point multiplication as - * follows: The scalars are brought into wnaf with n_wnaf elements each. Then - * for every i < n_wnaf, first each point is added to a "bucket" corresponding - * to the point's wnaf[i]. Second, the buckets are added together such that - * r += 1*bucket[0] + 3*bucket[1] + 5*bucket[2] + ... - */ -static int rustsecp256k1zkp_v0_8_0_ecmult_pippenger_wnaf(rustsecp256k1zkp_v0_8_0_gej *buckets, int bucket_window, struct rustsecp256k1zkp_v0_8_0_pippenger_state *state, rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_scalar *sc, const rustsecp256k1zkp_v0_8_0_ge *pt, size_t num) { - size_t n_wnaf = WNAF_SIZE(bucket_window+1); - size_t np; - size_t no = 0; - int i; - int j; - - for (np = 0; np < num; ++np) { - if (rustsecp256k1zkp_v0_8_0_scalar_is_zero(&sc[np]) || rustsecp256k1zkp_v0_8_0_ge_is_infinity(&pt[np])) { - continue; - } - state->ps[no].input_pos = np; - state->ps[no].skew_na = rustsecp256k1zkp_v0_8_0_wnaf_fixed(&state->wnaf_na[no*n_wnaf], &sc[np], bucket_window+1); - no++; - } - rustsecp256k1zkp_v0_8_0_gej_set_infinity(r); - - if (no == 0) { - return 1; - } - - for (i = n_wnaf - 1; i >= 0; i--) { - rustsecp256k1zkp_v0_8_0_gej running_sum; - - for(j = 0; j < ECMULT_TABLE_SIZE(bucket_window+2); j++) { - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&buckets[j]); - } - - for (np = 0; np < no; ++np) { - int n = state->wnaf_na[np*n_wnaf + i]; - struct rustsecp256k1zkp_v0_8_0_pippenger_point_state point_state = state->ps[np]; - rustsecp256k1zkp_v0_8_0_ge tmp; - int idx; - - if (i == 0) { - /* correct for wnaf skew */ - int skew = point_state.skew_na; - if (skew) { - rustsecp256k1zkp_v0_8_0_ge_neg(&tmp, &pt[point_state.input_pos]); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&buckets[0], &buckets[0], &tmp, NULL); - } - } - if (n > 0) { - idx = (n - 1)/2; - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&buckets[idx], &buckets[idx], &pt[point_state.input_pos], NULL); - } else if (n < 0) { - idx = -(n + 1)/2; - rustsecp256k1zkp_v0_8_0_ge_neg(&tmp, &pt[point_state.input_pos]); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&buckets[idx], &buckets[idx], &tmp, NULL); - } - } - - for(j = 0; j < bucket_window; j++) { - rustsecp256k1zkp_v0_8_0_gej_double_var(r, r, NULL); - } - - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&running_sum); - /* Accumulate the sum: bucket[0] + 3*bucket[1] + 5*bucket[2] + 7*bucket[3] + ... - * = bucket[0] + bucket[1] + bucket[2] + bucket[3] + ... - * + 2 * (bucket[1] + 2*bucket[2] + 3*bucket[3] + ...) - * using an intermediate running sum: - * running_sum = bucket[0] + bucket[1] + bucket[2] + ... - * - * The doubling is done implicitly by deferring the final window doubling (of 'r'). - */ - for(j = ECMULT_TABLE_SIZE(bucket_window+2) - 1; j > 0; j--) { - rustsecp256k1zkp_v0_8_0_gej_add_var(&running_sum, &running_sum, &buckets[j], NULL); - rustsecp256k1zkp_v0_8_0_gej_add_var(r, r, &running_sum, NULL); - } - - rustsecp256k1zkp_v0_8_0_gej_add_var(&running_sum, &running_sum, &buckets[0], NULL); - rustsecp256k1zkp_v0_8_0_gej_double_var(r, r, NULL); - rustsecp256k1zkp_v0_8_0_gej_add_var(r, r, &running_sum, NULL); - } - return 1; -} - -/** - * Returns optimal bucket_window (number of bits of a scalar represented by a - * set of buckets) for a given number of points. - */ -static int rustsecp256k1zkp_v0_8_0_pippenger_bucket_window(size_t n) { - if (n <= 1) { - return 1; - } else if (n <= 4) { - return 2; - } else if (n <= 20) { - return 3; - } else if (n <= 57) { - return 4; - } else if (n <= 136) { - return 5; - } else if (n <= 235) { - return 6; - } else if (n <= 1260) { - return 7; - } else if (n <= 4420) { - return 9; - } else if (n <= 7880) { - return 10; - } else if (n <= 16050) { - return 11; - } else { - return PIPPENGER_MAX_BUCKET_WINDOW; - } -} - -/** - * Returns the maximum optimal number of points for a bucket_window. - */ -static size_t rustsecp256k1zkp_v0_8_0_pippenger_bucket_window_inv(int bucket_window) { - switch(bucket_window) { - case 1: return 1; - case 2: return 4; - case 3: return 20; - case 4: return 57; - case 5: return 136; - case 6: return 235; - case 7: return 1260; - case 8: return 1260; - case 9: return 4420; - case 10: return 7880; - case 11: return 16050; - case PIPPENGER_MAX_BUCKET_WINDOW: return SIZE_MAX; - } - return 0; -} - - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_ecmult_endo_split(rustsecp256k1zkp_v0_8_0_scalar *s1, rustsecp256k1zkp_v0_8_0_scalar *s2, rustsecp256k1zkp_v0_8_0_ge *p1, rustsecp256k1zkp_v0_8_0_ge *p2) { - rustsecp256k1zkp_v0_8_0_scalar tmp = *s1; - rustsecp256k1zkp_v0_8_0_scalar_split_lambda(s1, s2, &tmp); - rustsecp256k1zkp_v0_8_0_ge_mul_lambda(p2, p1); - - if (rustsecp256k1zkp_v0_8_0_scalar_is_high(s1)) { - rustsecp256k1zkp_v0_8_0_scalar_negate(s1, s1); - rustsecp256k1zkp_v0_8_0_ge_neg(p1, p1); - } - if (rustsecp256k1zkp_v0_8_0_scalar_is_high(s2)) { - rustsecp256k1zkp_v0_8_0_scalar_negate(s2, s2); - rustsecp256k1zkp_v0_8_0_ge_neg(p2, p2); - } -} - -/** - * Returns the scratch size required for a given number of points (excluding - * base point G) without considering alignment. - */ -static size_t rustsecp256k1zkp_v0_8_0_pippenger_scratch_size(size_t n_points, int bucket_window) { - size_t entries = 2*n_points + 2; - size_t entry_size = sizeof(rustsecp256k1zkp_v0_8_0_ge) + sizeof(rustsecp256k1zkp_v0_8_0_scalar) + sizeof(struct rustsecp256k1zkp_v0_8_0_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); - return (sizeof(rustsecp256k1zkp_v0_8_0_gej) << bucket_window) + sizeof(struct rustsecp256k1zkp_v0_8_0_pippenger_state) + entries * entry_size; -} - -static int rustsecp256k1zkp_v0_8_0_ecmult_pippenger_batch(const rustsecp256k1zkp_v0_8_0_callback* error_callback, rustsecp256k1zkp_v0_8_0_scratch *scratch, rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_scalar *inp_g_sc, rustsecp256k1zkp_v0_8_0_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { - const size_t scratch_checkpoint = rustsecp256k1zkp_v0_8_0_scratch_checkpoint(error_callback, scratch); - /* Use 2(n+1) with the endomorphism, when calculating batch - * sizes. The reason for +1 is that we add the G scalar to the list of - * other scalars. */ - size_t entries = 2*n_points + 2; - rustsecp256k1zkp_v0_8_0_ge *points; - rustsecp256k1zkp_v0_8_0_scalar *scalars; - rustsecp256k1zkp_v0_8_0_gej *buckets; - struct rustsecp256k1zkp_v0_8_0_pippenger_state *state_space; - size_t idx = 0; - size_t point_idx = 0; - int i, j; - int bucket_window; - - rustsecp256k1zkp_v0_8_0_gej_set_infinity(r); - if (inp_g_sc == NULL && n_points == 0) { - return 1; - } - bucket_window = rustsecp256k1zkp_v0_8_0_pippenger_bucket_window(n_points); - - /* We allocate PIPPENGER_SCRATCH_OBJECTS objects on the scratch space. If - * these allocations change, make sure to update the - * PIPPENGER_SCRATCH_OBJECTS constant and pippenger_scratch_size - * accordingly. */ - points = (rustsecp256k1zkp_v0_8_0_ge *) rustsecp256k1zkp_v0_8_0_scratch_alloc(error_callback, scratch, entries * sizeof(*points)); - scalars = (rustsecp256k1zkp_v0_8_0_scalar *) rustsecp256k1zkp_v0_8_0_scratch_alloc(error_callback, scratch, entries * sizeof(*scalars)); - state_space = (struct rustsecp256k1zkp_v0_8_0_pippenger_state *) rustsecp256k1zkp_v0_8_0_scratch_alloc(error_callback, scratch, sizeof(*state_space)); - if (points == NULL || scalars == NULL || state_space == NULL) { - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); - return 0; - } - state_space->ps = (struct rustsecp256k1zkp_v0_8_0_pippenger_point_state *) rustsecp256k1zkp_v0_8_0_scratch_alloc(error_callback, scratch, entries * sizeof(*state_space->ps)); - state_space->wnaf_na = (int *) rustsecp256k1zkp_v0_8_0_scratch_alloc(error_callback, scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int)); - buckets = (rustsecp256k1zkp_v0_8_0_gej *) rustsecp256k1zkp_v0_8_0_scratch_alloc(error_callback, scratch, (1<ps == NULL || state_space->wnaf_na == NULL || buckets == NULL) { - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); - return 0; - } - - if (inp_g_sc != NULL) { - scalars[0] = *inp_g_sc; - points[0] = rustsecp256k1zkp_v0_8_0_ge_const_g; - idx++; - rustsecp256k1zkp_v0_8_0_ecmult_endo_split(&scalars[0], &scalars[1], &points[0], &points[1]); - idx++; - } - - while (point_idx < n_points) { - if (!cb(&scalars[idx], &points[idx], point_idx + cb_offset, cbdata)) { - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); - return 0; - } - idx++; - rustsecp256k1zkp_v0_8_0_ecmult_endo_split(&scalars[idx - 1], &scalars[idx], &points[idx - 1], &points[idx]); - idx++; - point_idx++; - } - - rustsecp256k1zkp_v0_8_0_ecmult_pippenger_wnaf(buckets, bucket_window, state_space, r, scalars, points, idx); - - /* Clear data */ - for(i = 0; (size_t)i < idx; i++) { - rustsecp256k1zkp_v0_8_0_scalar_clear(&scalars[i]); - state_space->ps[i].skew_na = 0; - for(j = 0; j < WNAF_SIZE(bucket_window+1); j++) { - state_space->wnaf_na[i * WNAF_SIZE(bucket_window+1) + j] = 0; - } - } - for(i = 0; i < 1< max_alloc) { - break; - } - space_for_points = max_alloc - space_overhead; - - n_points = space_for_points/entry_size; - n_points = n_points > max_points ? max_points : n_points; - if (n_points > res) { - res = n_points; - } - if (n_points < max_points) { - /* A larger bucket_window may support even more points. But if we - * would choose that then the caller couldn't safely use any number - * smaller than what this function returns */ - break; - } - } - return res; -} - -/* Computes ecmult_multi by simply multiplying and adding each point. Does not - * require a scratch space */ -static int rustsecp256k1zkp_v0_8_0_ecmult_multi_simple_var(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_scalar *inp_g_sc, rustsecp256k1zkp_v0_8_0_ecmult_multi_callback cb, void *cbdata, size_t n_points) { - size_t point_idx; - rustsecp256k1zkp_v0_8_0_scalar szero; - rustsecp256k1zkp_v0_8_0_gej tmpj; - - rustsecp256k1zkp_v0_8_0_scalar_set_int(&szero, 0); - rustsecp256k1zkp_v0_8_0_gej_set_infinity(r); - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&tmpj); - /* r = inp_g_sc*G */ - rustsecp256k1zkp_v0_8_0_ecmult(r, &tmpj, &szero, inp_g_sc); - for (point_idx = 0; point_idx < n_points; point_idx++) { - rustsecp256k1zkp_v0_8_0_ge point; - rustsecp256k1zkp_v0_8_0_gej pointj; - rustsecp256k1zkp_v0_8_0_scalar scalar; - if (!cb(&scalar, &point, point_idx, cbdata)) { - return 0; - } - /* r += scalar*point */ - rustsecp256k1zkp_v0_8_0_gej_set_ge(&pointj, &point); - rustsecp256k1zkp_v0_8_0_ecmult(&tmpj, &pointj, &scalar, NULL); - rustsecp256k1zkp_v0_8_0_gej_add_var(r, r, &tmpj, NULL); - } - return 1; -} - -/* Compute the number of batches and the batch size given the maximum batch size and the - * total number of points */ -static int rustsecp256k1zkp_v0_8_0_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n_batch_points, size_t max_n_batch_points, size_t n) { - if (max_n_batch_points == 0) { - return 0; - } - if (max_n_batch_points > ECMULT_MAX_POINTS_PER_BATCH) { - max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH; - } - if (n == 0) { - *n_batches = 0; - *n_batch_points = 0; - return 1; - } - /* Compute ceil(n/max_n_batch_points) and ceil(n/n_batches) */ - *n_batches = 1 + (n - 1) / max_n_batch_points; - *n_batch_points = 1 + (n - 1) / *n_batches; - return 1; -} - -typedef int (*rustsecp256k1zkp_v0_8_0_ecmult_multi_func)(const rustsecp256k1zkp_v0_8_0_callback* error_callback, rustsecp256k1zkp_v0_8_0_scratch*, rustsecp256k1zkp_v0_8_0_gej*, const rustsecp256k1zkp_v0_8_0_scalar*, rustsecp256k1zkp_v0_8_0_ecmult_multi_callback cb, void*, size_t); -static int rustsecp256k1zkp_v0_8_0_ecmult_multi_var(const rustsecp256k1zkp_v0_8_0_callback* error_callback, rustsecp256k1zkp_v0_8_0_scratch *scratch, rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_scalar *inp_g_sc, rustsecp256k1zkp_v0_8_0_ecmult_multi_callback cb, void *cbdata, size_t n) { - size_t i; - - int (*f)(const rustsecp256k1zkp_v0_8_0_callback* error_callback, rustsecp256k1zkp_v0_8_0_scratch*, rustsecp256k1zkp_v0_8_0_gej*, const rustsecp256k1zkp_v0_8_0_scalar*, rustsecp256k1zkp_v0_8_0_ecmult_multi_callback cb, void*, size_t, size_t); - size_t n_batches; - size_t n_batch_points; - - rustsecp256k1zkp_v0_8_0_gej_set_infinity(r); - if (inp_g_sc == NULL && n == 0) { - return 1; - } else if (n == 0) { - rustsecp256k1zkp_v0_8_0_scalar szero; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&szero, 0); - rustsecp256k1zkp_v0_8_0_ecmult(r, r, &szero, inp_g_sc); - return 1; - } - if (scratch == NULL) { - return rustsecp256k1zkp_v0_8_0_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); - } - - /* Compute the batch sizes for Pippenger's algorithm given a scratch space. If it's greater than - * a threshold use Pippenger's algorithm. Otherwise use Strauss' algorithm. - * As a first step check if there's enough space for Pippenger's algo (which requires less space - * than Strauss' algo) and if not, use the simple algorithm. */ - if (!rustsecp256k1zkp_v0_8_0_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, rustsecp256k1zkp_v0_8_0_pippenger_max_points(error_callback, scratch), n)) { - return rustsecp256k1zkp_v0_8_0_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); - } - if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) { - f = rustsecp256k1zkp_v0_8_0_ecmult_pippenger_batch; - } else { - if (!rustsecp256k1zkp_v0_8_0_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, rustsecp256k1zkp_v0_8_0_strauss_max_points(error_callback, scratch), n)) { - return rustsecp256k1zkp_v0_8_0_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); - } - f = rustsecp256k1zkp_v0_8_0_ecmult_strauss_batch; - } - for(i = 0; i < n_batches; i++) { - size_t nbp = n < n_batch_points ? n : n_batch_points; - size_t offset = n_batch_points*i; - rustsecp256k1zkp_v0_8_0_gej tmp; - if (!f(error_callback, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_gej_add_var(r, r, &tmp, NULL); - n -= nbp; - } - return 1; -} - -#endif /* SECP256K1_ECMULT_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field.h deleted file mode 100644 index 0717afdd..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field.h +++ /dev/null @@ -1,145 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_FIELD_H -#define SECP256K1_FIELD_H - -/** Field element module. - * - * Field elements can be represented in several ways, but code accessing - * it (and implementations) need to take certain properties into account: - * - Each field element can be normalized or not. - * - Each field element has a magnitude, which represents how far away - * its representation is away from normalization. Normalized elements - * always have a magnitude of 0 or 1, but a magnitude of 1 doesn't - * imply normality. - */ - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#include "util.h" - -#if defined(SECP256K1_WIDEMUL_INT128) -#include "field_5x52.h" -#elif defined(SECP256K1_WIDEMUL_INT64) -#include "field_10x26.h" -#else -#error "Please select wide multiplication implementation" -#endif - -static const rustsecp256k1zkp_v0_8_0_fe rustsecp256k1zkp_v0_8_0_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); -static const rustsecp256k1zkp_v0_8_0_fe rustsecp256k1zkp_v0_8_0_const_beta = SECP256K1_FE_CONST( - 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, - 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul -); - -/** Normalize a field element. This brings the field element to a canonical representation, reduces - * its magnitude to 1, and reduces it modulo field size `p`. - */ -static void rustsecp256k1zkp_v0_8_0_fe_normalize(rustsecp256k1zkp_v0_8_0_fe *r); - -/** Weakly normalize a field element: reduce its magnitude to 1, but don't fully normalize. */ -static void rustsecp256k1zkp_v0_8_0_fe_normalize_weak(rustsecp256k1zkp_v0_8_0_fe *r); - -/** Normalize a field element, without constant-time guarantee. */ -static void rustsecp256k1zkp_v0_8_0_fe_normalize_var(rustsecp256k1zkp_v0_8_0_fe *r); - -/** Verify whether a field element represents zero i.e. would normalize to a zero value. */ -static int rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(const rustsecp256k1zkp_v0_8_0_fe *r); - -/** Verify whether a field element represents zero i.e. would normalize to a zero value, - * without constant-time guarantee. */ -static int rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(const rustsecp256k1zkp_v0_8_0_fe *r); - -/** Set a field element equal to a small (not greater than 0x7FFF), non-negative integer. - * Resulting field element is normalized; it has magnitude 0 if a == 0, and magnitude 1 otherwise. - */ -static void rustsecp256k1zkp_v0_8_0_fe_set_int(rustsecp256k1zkp_v0_8_0_fe *r, int a); - -/** Sets a field element equal to zero, initializing all fields. */ -static void rustsecp256k1zkp_v0_8_0_fe_clear(rustsecp256k1zkp_v0_8_0_fe *a); - -/** Verify whether a field element is zero. Requires the input to be normalized. */ -static int rustsecp256k1zkp_v0_8_0_fe_is_zero(const rustsecp256k1zkp_v0_8_0_fe *a); - -/** Check the "oddness" of a field element. Requires the input to be normalized. */ -static int rustsecp256k1zkp_v0_8_0_fe_is_odd(const rustsecp256k1zkp_v0_8_0_fe *a); - -/** Compare two field elements. Requires magnitude-1 inputs. */ -static int rustsecp256k1zkp_v0_8_0_fe_equal(const rustsecp256k1zkp_v0_8_0_fe *a, const rustsecp256k1zkp_v0_8_0_fe *b); - -/** Same as rustsecp256k1zkp_v0_8_0_fe_equal, but may be variable time. */ -static int rustsecp256k1zkp_v0_8_0_fe_equal_var(const rustsecp256k1zkp_v0_8_0_fe *a, const rustsecp256k1zkp_v0_8_0_fe *b); - -/** Compare two field elements. Requires both inputs to be normalized */ -static int rustsecp256k1zkp_v0_8_0_fe_cmp_var(const rustsecp256k1zkp_v0_8_0_fe *a, const rustsecp256k1zkp_v0_8_0_fe *b); - -/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */ -static int rustsecp256k1zkp_v0_8_0_fe_set_b32(rustsecp256k1zkp_v0_8_0_fe *r, const unsigned char *a); - -/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void rustsecp256k1zkp_v0_8_0_fe_get_b32(unsigned char *r, const rustsecp256k1zkp_v0_8_0_fe *a); - -/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input - * as an argument. The magnitude of the output is one higher. */ -static void rustsecp256k1zkp_v0_8_0_fe_negate(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a, int m); - -/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that - * small integer. */ -static void rustsecp256k1zkp_v0_8_0_fe_mul_int(rustsecp256k1zkp_v0_8_0_fe *r, int a); - -/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ -static void rustsecp256k1zkp_v0_8_0_fe_add(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a); - -/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8. - * The output magnitude is 1 (but not guaranteed to be normalized). */ -static void rustsecp256k1zkp_v0_8_0_fe_mul(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a, const rustsecp256k1zkp_v0_8_0_fe * SECP256K1_RESTRICT b); - -/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. - * The output magnitude is 1 (but not guaranteed to be normalized). */ -static void rustsecp256k1zkp_v0_8_0_fe_sqr(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a); - -/** If a has a square root, it is computed in r and 1 is returned. If a does not - * have a square root, the root of its negation is computed and 0 is returned. - * The input's magnitude can be at most 8. The output magnitude is 1 (but not - * guaranteed to be normalized). The result in r will always be a square - * itself. */ -static int rustsecp256k1zkp_v0_8_0_fe_sqrt(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a); - -/** Checks whether a field element is a quadratic residue. */ -static int rustsecp256k1zkp_v0_8_0_fe_is_quad_var(const rustsecp256k1zkp_v0_8_0_fe *a); - -/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be - * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ -static void rustsecp256k1zkp_v0_8_0_fe_inv(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a); - -/** Potentially faster version of rustsecp256k1zkp_v0_8_0_fe_inv, without constant-time guarantee. */ -static void rustsecp256k1zkp_v0_8_0_fe_inv_var(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a); - -/** Convert a field element to the storage type. */ -static void rustsecp256k1zkp_v0_8_0_fe_to_storage(rustsecp256k1zkp_v0_8_0_fe_storage *r, const rustsecp256k1zkp_v0_8_0_fe *a); - -/** Convert a field element back from the storage type. */ -static void rustsecp256k1zkp_v0_8_0_fe_from_storage(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe_storage *a); - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ -static void rustsecp256k1zkp_v0_8_0_fe_storage_cmov(rustsecp256k1zkp_v0_8_0_fe_storage *r, const rustsecp256k1zkp_v0_8_0_fe_storage *a, int flag); - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ -static void rustsecp256k1zkp_v0_8_0_fe_cmov(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a, int flag); - -/** Halves the value of a field element modulo the field prime. Constant-time. - * For an input magnitude 'm', the output magnitude is set to 'floor(m/2) + 1'. - * The output is not guaranteed to be normalized, regardless of the input. */ -static void rustsecp256k1zkp_v0_8_0_fe_half(rustsecp256k1zkp_v0_8_0_fe *r); - -/** Sets each limb of 'r' to its upper bound at magnitude 'm'. The output will also have its - * magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */ -static void rustsecp256k1zkp_v0_8_0_fe_get_bounds(rustsecp256k1zkp_v0_8_0_fe *r, int m); - -#endif /* SECP256K1_FIELD_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_5x52_asm_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_5x52_asm_impl.h deleted file mode 100644 index 74c8e597..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_5x52_asm_impl.h +++ /dev/null @@ -1,502 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -/** - * Changelog: - * - March 2013, Diederik Huys: original version - * - November 2014, Pieter Wuille: updated to use Peter Dettman's parallel multiplication algorithm - * - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly - */ - -#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H -#define SECP256K1_FIELD_INNER5X52_IMPL_H - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { -/** - * Registers: rdx:rax = multiplication accumulator - * r9:r8 = c - * r15:rcx = d - * r10-r14 = a0-a4 - * rbx = b - * rdi = r - * rsi = a / t? - */ - uint64_t tmp1, tmp2, tmp3; -__asm__ __volatile__( - "movq 0(%%rsi),%%r10\n" - "movq 8(%%rsi),%%r11\n" - "movq 16(%%rsi),%%r12\n" - "movq 24(%%rsi),%%r13\n" - "movq 32(%%rsi),%%r14\n" - - /* d += a3 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r13\n" - "movq %%rax,%%rcx\n" - "movq %%rdx,%%r15\n" - /* d += a2 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a1 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d = a0 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c = a4 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r14\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += (c & M) * R */ - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* t3 (tmp1) = d & M */ - "movq %%rcx,%%rsi\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rsi\n" - "movq %%rsi,%q1\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* d += a4 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a2 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a1 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a0 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += c * R */ - "movq %%r8,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* t4 = d & M (%%rsi) */ - "movq %%rcx,%%rsi\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* tx = t4 >> 48 (tmp3) */ - "movq %%rsi,%%rax\n" - "shrq $48,%%rax\n" - "movq %%rax,%q3\n" - /* t4 &= (M >> 4) (tmp2) */ - "movq $0xffffffffffff,%%rax\n" - "andq %%rax,%%rsi\n" - "movq %%rsi,%q2\n" - /* c = a0 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r10\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += a4 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a2 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a1 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* u0 = d & M (%%rsi) */ - "movq %%rcx,%%rsi\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* u0 = (u0 << 4) | tx (%%rsi) */ - "shlq $4,%%rsi\n" - "movq %q3,%%rax\n" - "orq %%rax,%%rsi\n" - /* c += u0 * (R >> 4) */ - "movq $0x1000003d1,%%rax\n" - "mulq %%rsi\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[0] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,0(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += a1 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* c += a0 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d += a4 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a2 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c += (d & M) * R */ - "movq %%rcx,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* r[1] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,8(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += a2 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* c += a1 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* c += a0 * b2 (last use of %%r10 = a0) */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* fetch t3 (%%r10, overwrites a0), t4 (%%rsi) */ - "movq %q2,%%rsi\n" - "movq %q1,%%r10\n" - /* d += a4 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c += (d & M) * R */ - "movq %%rcx,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 (%%rcx only) */ - "shrdq $52,%%r15,%%rcx\n" - /* r[2] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,16(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += t3 */ - "addq %%r10,%%r8\n" - /* c += d * R */ - "movq %%rcx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[3] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,24(%%rdi)\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* c += t4 (%%r8 only) */ - "addq %%rsi,%%r8\n" - /* r[4] = c */ - "movq %%r8,32(%%rdi)\n" -: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) -: "b"(b), "D"(r) -: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" -); -} - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_sqr_inner(uint64_t *r, const uint64_t *a) { -/** - * Registers: rdx:rax = multiplication accumulator - * r9:r8 = c - * rcx:rbx = d - * r10-r14 = a0-a4 - * r15 = M (0xfffffffffffff) - * rdi = r - * rsi = a / t? - */ - uint64_t tmp1, tmp2, tmp3; -__asm__ __volatile__( - "movq 0(%%rsi),%%r10\n" - "movq 8(%%rsi),%%r11\n" - "movq 16(%%rsi),%%r12\n" - "movq 24(%%rsi),%%r13\n" - "movq 32(%%rsi),%%r14\n" - "movq $0xfffffffffffff,%%r15\n" - - /* d = (a0*2) * a3 */ - "leaq (%%r10,%%r10,1),%%rax\n" - "mulq %%r13\n" - "movq %%rax,%%rbx\n" - "movq %%rdx,%%rcx\n" - /* d += (a1*2) * a2 */ - "leaq (%%r11,%%r11,1),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c = a4 * a4 */ - "movq %%r14,%%rax\n" - "mulq %%r14\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += (c & M) * R */ - "andq %%r15,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* t3 (tmp1) = d & M */ - "movq %%rbx,%%rsi\n" - "andq %%r15,%%rsi\n" - "movq %%rsi,%q1\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* a4 *= 2 */ - "addq %%r14,%%r14\n" - /* d += a0 * a4 */ - "movq %%r10,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d+= (a1*2) * a3 */ - "leaq (%%r11,%%r11,1),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += a2 * a2 */ - "movq %%r12,%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += c * R */ - "movq %%r8,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* t4 = d & M (%%rsi) */ - "movq %%rbx,%%rsi\n" - "andq %%r15,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* tx = t4 >> 48 (tmp3) */ - "movq %%rsi,%%rax\n" - "shrq $48,%%rax\n" - "movq %%rax,%q3\n" - /* t4 &= (M >> 4) (tmp2) */ - "movq $0xffffffffffff,%%rax\n" - "andq %%rax,%%rsi\n" - "movq %%rsi,%q2\n" - /* c = a0 * a0 */ - "movq %%r10,%%rax\n" - "mulq %%r10\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += a1 * a4 */ - "movq %%r11,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += (a2*2) * a3 */ - "leaq (%%r12,%%r12,1),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* u0 = d & M (%%rsi) */ - "movq %%rbx,%%rsi\n" - "andq %%r15,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* u0 = (u0 << 4) | tx (%%rsi) */ - "shlq $4,%%rsi\n" - "movq %q3,%%rax\n" - "orq %%rax,%%rsi\n" - /* c += u0 * (R >> 4) */ - "movq $0x1000003d1,%%rax\n" - "mulq %%rsi\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[0] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,0(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* a0 *= 2 */ - "addq %%r10,%%r10\n" - /* c += a0 * a1 */ - "movq %%r10,%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d += a2 * a4 */ - "movq %%r12,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += a3 * a3 */ - "movq %%r13,%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c += (d & M) * R */ - "movq %%rbx,%%rax\n" - "andq %%r15,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* r[1] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,8(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += a0 * a2 (last use of %%r10) */ - "movq %%r10,%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* fetch t3 (%%r10, overwrites a0),t4 (%%rsi) */ - "movq %q2,%%rsi\n" - "movq %q1,%%r10\n" - /* c += a1 * a1 */ - "movq %%r11,%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d += a3 * a4 */ - "movq %%r13,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c += (d & M) * R */ - "movq %%rbx,%%rax\n" - "andq %%r15,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 (%%rbx only) */ - "shrdq $52,%%rcx,%%rbx\n" - /* r[2] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,16(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += t3 */ - "addq %%r10,%%r8\n" - /* c += d * R */ - "movq %%rbx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[3] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,24(%%rdi)\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* c += t4 (%%r8 only) */ - "addq %%rsi,%%r8\n" - /* r[4] = c */ - "movq %%r8,32(%%rdi)\n" -: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) -: "D"(r) -: "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" -); -} - -#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_5x52_int128_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_5x52_int128_impl.h deleted file mode 100644 index 8f8588ac..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_5x52_int128_impl.h +++ /dev/null @@ -1,278 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H -#define SECP256K1_FIELD_INNER5X52_IMPL_H - -#include - -#ifdef VERIFY -#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) -#else -#define VERIFY_BITS(x, n) do { } while(0) -#endif - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { - uint128_t c, d; - uint64_t t3, t4, tx, u0; - uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; - const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; - - VERIFY_BITS(a[0], 56); - VERIFY_BITS(a[1], 56); - VERIFY_BITS(a[2], 56); - VERIFY_BITS(a[3], 56); - VERIFY_BITS(a[4], 52); - VERIFY_BITS(b[0], 56); - VERIFY_BITS(b[1], 56); - VERIFY_BITS(b[2], 56); - VERIFY_BITS(b[3], 56); - VERIFY_BITS(b[4], 52); - VERIFY_CHECK(r != b); - VERIFY_CHECK(a != b); - - /* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. - * for 0 <= x <= 4, px is a shorthand for sum(a[i]*b[x-i], i=0..x). - * for 4 <= x <= 8, px is a shorthand for sum(a[i]*b[x-i], i=(x-4)..4) - * Note that [x 0 0 0 0 0] = [x*R]. - */ - - d = (uint128_t)a0 * b[3] - + (uint128_t)a1 * b[2] - + (uint128_t)a2 * b[1] - + (uint128_t)a3 * b[0]; - VERIFY_BITS(d, 114); - /* [d 0 0 0] = [p3 0 0 0] */ - c = (uint128_t)a4 * b[4]; - VERIFY_BITS(c, 112); - /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - d += (uint128_t)R * (uint64_t)c; c >>= 64; - VERIFY_BITS(d, 115); - VERIFY_BITS(c, 48); - /* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - t3 = d & M; d >>= 52; - VERIFY_BITS(t3, 52); - VERIFY_BITS(d, 63); - /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - - d += (uint128_t)a0 * b[4] - + (uint128_t)a1 * b[3] - + (uint128_t)a2 * b[2] - + (uint128_t)a3 * b[1] - + (uint128_t)a4 * b[0]; - VERIFY_BITS(d, 115); - /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - d += (uint128_t)(R << 12) * (uint64_t)c; - VERIFY_BITS(d, 116); - /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - t4 = d & M; d >>= 52; - VERIFY_BITS(t4, 52); - VERIFY_BITS(d, 64); - /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - tx = (t4 >> 48); t4 &= (M >> 4); - VERIFY_BITS(tx, 4); - VERIFY_BITS(t4, 48); - /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - - c = (uint128_t)a0 * b[0]; - VERIFY_BITS(c, 112); - /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ - d += (uint128_t)a1 * b[4] - + (uint128_t)a2 * b[3] - + (uint128_t)a3 * b[2] - + (uint128_t)a4 * b[1]; - VERIFY_BITS(d, 115); - /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = d & M; d >>= 52; - VERIFY_BITS(u0, 52); - VERIFY_BITS(d, 63); - /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = (u0 << 4) | tx; - VERIFY_BITS(u0, 56); - /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - c += (uint128_t)u0 * (R >> 4); - VERIFY_BITS(c, 115); - /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - r[0] = c & M; c >>= 52; - VERIFY_BITS(r[0], 52); - VERIFY_BITS(c, 61); - /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ - - c += (uint128_t)a0 * b[1] - + (uint128_t)a1 * b[0]; - VERIFY_BITS(c, 114); - /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ - d += (uint128_t)a2 * b[4] - + (uint128_t)a3 * b[3] - + (uint128_t)a4 * b[2]; - VERIFY_BITS(d, 114); - /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - c += (d & M) * R; d >>= 52; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 62); - /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - r[1] = c & M; c >>= 52; - VERIFY_BITS(r[1], 52); - VERIFY_BITS(c, 63); - /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - - c += (uint128_t)a0 * b[2] - + (uint128_t)a1 * b[1] - + (uint128_t)a2 * b[0]; - VERIFY_BITS(c, 114); - /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint128_t)a3 * b[4] - + (uint128_t)a4 * b[3]; - VERIFY_BITS(d, 114); - /* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += (uint128_t)R * (uint64_t)d; d >>= 64; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 50); - /* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - r[2] = c & M; c >>= 52; - VERIFY_BITS(r[2], 52); - VERIFY_BITS(c, 63); - /* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += (uint128_t)(R << 12) * (uint64_t)d + t3; - VERIFY_BITS(c, 100); - /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[3] = c & M; c >>= 52; - VERIFY_BITS(r[3], 52); - VERIFY_BITS(c, 48); - /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += t4; - VERIFY_BITS(c, 49); - /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[4] = c; - VERIFY_BITS(r[4], 49); - /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ -} - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_sqr_inner(uint64_t *r, const uint64_t *a) { - uint128_t c, d; - uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; - int64_t t3, t4, tx, u0; - const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; - - VERIFY_BITS(a[0], 56); - VERIFY_BITS(a[1], 56); - VERIFY_BITS(a[2], 56); - VERIFY_BITS(a[3], 56); - VERIFY_BITS(a[4], 52); - - /** [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. - * px is a shorthand for sum(a[i]*a[x-i], i=0..x). - * Note that [x 0 0 0 0 0] = [x*R]. - */ - - d = (uint128_t)(a0*2) * a3 - + (uint128_t)(a1*2) * a2; - VERIFY_BITS(d, 114); - /* [d 0 0 0] = [p3 0 0 0] */ - c = (uint128_t)a4 * a4; - VERIFY_BITS(c, 112); - /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - d += (uint128_t)R * (uint64_t)c; c >>= 64; - VERIFY_BITS(d, 115); - VERIFY_BITS(c, 48); - /* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - t3 = d & M; d >>= 52; - VERIFY_BITS(t3, 52); - VERIFY_BITS(d, 63); - /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - - a4 *= 2; - d += (uint128_t)a0 * a4 - + (uint128_t)(a1*2) * a3 - + (uint128_t)a2 * a2; - VERIFY_BITS(d, 115); - /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - d += (uint128_t)(R << 12) * (uint64_t)c; - VERIFY_BITS(d, 116); - /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - t4 = d & M; d >>= 52; - VERIFY_BITS(t4, 52); - VERIFY_BITS(d, 64); - /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - tx = (t4 >> 48); t4 &= (M >> 4); - VERIFY_BITS(tx, 4); - VERIFY_BITS(t4, 48); - /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - - c = (uint128_t)a0 * a0; - VERIFY_BITS(c, 112); - /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ - d += (uint128_t)a1 * a4 - + (uint128_t)(a2*2) * a3; - VERIFY_BITS(d, 114); - /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = d & M; d >>= 52; - VERIFY_BITS(u0, 52); - VERIFY_BITS(d, 62); - /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = (u0 << 4) | tx; - VERIFY_BITS(u0, 56); - /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - c += (uint128_t)u0 * (R >> 4); - VERIFY_BITS(c, 113); - /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - r[0] = c & M; c >>= 52; - VERIFY_BITS(r[0], 52); - VERIFY_BITS(c, 61); - /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ - - a0 *= 2; - c += (uint128_t)a0 * a1; - VERIFY_BITS(c, 114); - /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ - d += (uint128_t)a2 * a4 - + (uint128_t)a3 * a3; - VERIFY_BITS(d, 114); - /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - c += (d & M) * R; d >>= 52; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 62); - /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - r[1] = c & M; c >>= 52; - VERIFY_BITS(r[1], 52); - VERIFY_BITS(c, 63); - /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - - c += (uint128_t)a0 * a2 - + (uint128_t)a1 * a1; - VERIFY_BITS(c, 114); - /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint128_t)a3 * a4; - VERIFY_BITS(d, 114); - /* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += (uint128_t)R * (uint64_t)d; d >>= 64; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 50); - /* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[2] = c & M; c >>= 52; - VERIFY_BITS(r[2], 52); - VERIFY_BITS(c, 63); - /* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - c += (uint128_t)(R << 12) * (uint64_t)d + t3; - VERIFY_BITS(c, 100); - /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[3] = c & M; c >>= 52; - VERIFY_BITS(r[3], 52); - VERIFY_BITS(c, 48); - /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += t4; - VERIFY_BITS(c, 49); - /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[4] = c; - VERIFY_BITS(r[4], 49); - /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ -} - -#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_impl.h deleted file mode 100644 index 4d5c2279..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_impl.h +++ /dev/null @@ -1,143 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_FIELD_IMPL_H -#define SECP256K1_FIELD_IMPL_H - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#include "util.h" - -#if defined(SECP256K1_WIDEMUL_INT128) -#include "field_5x52_impl.h" -#elif defined(SECP256K1_WIDEMUL_INT64) -#include "field_10x26_impl.h" -#else -#error "Please select wide multiplication implementation" -#endif - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_fe_equal(const rustsecp256k1zkp_v0_8_0_fe *a, const rustsecp256k1zkp_v0_8_0_fe *b) { - rustsecp256k1zkp_v0_8_0_fe na; - rustsecp256k1zkp_v0_8_0_fe_negate(&na, a, 1); - rustsecp256k1zkp_v0_8_0_fe_add(&na, b); - return rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(&na); -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_fe_equal_var(const rustsecp256k1zkp_v0_8_0_fe *a, const rustsecp256k1zkp_v0_8_0_fe *b) { - rustsecp256k1zkp_v0_8_0_fe na; - rustsecp256k1zkp_v0_8_0_fe_negate(&na, a, 1); - rustsecp256k1zkp_v0_8_0_fe_add(&na, b); - return rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(&na); -} - -static int rustsecp256k1zkp_v0_8_0_fe_sqrt(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a) { - /** Given that p is congruent to 3 mod 4, we can compute the square root of - * a mod p as the (p+1)/4'th power of a. - * - * As (p+1)/4 is an even number, it will have the same result for a and for - * (-a). Only one of these two numbers actually has a square root however, - * so we test at the end by squaring and comparing to the input. - * Also because (p+1)/4 is an even number, the computed square root is - * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). - */ - rustsecp256k1zkp_v0_8_0_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; - int j; - - VERIFY_CHECK(r != a); - - /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in - * { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: - * 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] - */ - - rustsecp256k1zkp_v0_8_0_fe_sqr(&x2, a); - rustsecp256k1zkp_v0_8_0_fe_mul(&x2, &x2, a); - - rustsecp256k1zkp_v0_8_0_fe_sqr(&x3, &x2); - rustsecp256k1zkp_v0_8_0_fe_mul(&x3, &x3, a); - - x6 = x3; - for (j=0; j<3; j++) { - rustsecp256k1zkp_v0_8_0_fe_sqr(&x6, &x6); - } - rustsecp256k1zkp_v0_8_0_fe_mul(&x6, &x6, &x3); - - x9 = x6; - for (j=0; j<3; j++) { - rustsecp256k1zkp_v0_8_0_fe_sqr(&x9, &x9); - } - rustsecp256k1zkp_v0_8_0_fe_mul(&x9, &x9, &x3); - - x11 = x9; - for (j=0; j<2; j++) { - rustsecp256k1zkp_v0_8_0_fe_sqr(&x11, &x11); - } - rustsecp256k1zkp_v0_8_0_fe_mul(&x11, &x11, &x2); - - x22 = x11; - for (j=0; j<11; j++) { - rustsecp256k1zkp_v0_8_0_fe_sqr(&x22, &x22); - } - rustsecp256k1zkp_v0_8_0_fe_mul(&x22, &x22, &x11); - - x44 = x22; - for (j=0; j<22; j++) { - rustsecp256k1zkp_v0_8_0_fe_sqr(&x44, &x44); - } - rustsecp256k1zkp_v0_8_0_fe_mul(&x44, &x44, &x22); - - x88 = x44; - for (j=0; j<44; j++) { - rustsecp256k1zkp_v0_8_0_fe_sqr(&x88, &x88); - } - rustsecp256k1zkp_v0_8_0_fe_mul(&x88, &x88, &x44); - - x176 = x88; - for (j=0; j<88; j++) { - rustsecp256k1zkp_v0_8_0_fe_sqr(&x176, &x176); - } - rustsecp256k1zkp_v0_8_0_fe_mul(&x176, &x176, &x88); - - x220 = x176; - for (j=0; j<44; j++) { - rustsecp256k1zkp_v0_8_0_fe_sqr(&x220, &x220); - } - rustsecp256k1zkp_v0_8_0_fe_mul(&x220, &x220, &x44); - - x223 = x220; - for (j=0; j<3; j++) { - rustsecp256k1zkp_v0_8_0_fe_sqr(&x223, &x223); - } - rustsecp256k1zkp_v0_8_0_fe_mul(&x223, &x223, &x3); - - /* The final result is then assembled using a sliding window over the blocks. */ - - t1 = x223; - for (j=0; j<23; j++) { - rustsecp256k1zkp_v0_8_0_fe_sqr(&t1, &t1); - } - rustsecp256k1zkp_v0_8_0_fe_mul(&t1, &t1, &x22); - for (j=0; j<6; j++) { - rustsecp256k1zkp_v0_8_0_fe_sqr(&t1, &t1); - } - rustsecp256k1zkp_v0_8_0_fe_mul(&t1, &t1, &x2); - rustsecp256k1zkp_v0_8_0_fe_sqr(&t1, &t1); - rustsecp256k1zkp_v0_8_0_fe_sqr(r, &t1); - - /* Check that a square root was actually calculated */ - - rustsecp256k1zkp_v0_8_0_fe_sqr(&t1, r); - return rustsecp256k1zkp_v0_8_0_fe_equal(&t1, a); -} - -static int rustsecp256k1zkp_v0_8_0_fe_is_quad_var(const rustsecp256k1zkp_v0_8_0_fe *a) { - rustsecp256k1zkp_v0_8_0_fe r; - return rustsecp256k1zkp_v0_8_0_fe_sqrt(&r, a); -} - -#endif /* SECP256K1_FIELD_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/group.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/group.h deleted file mode 100644 index f4e78e7f..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/group.h +++ /dev/null @@ -1,173 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_GROUP_H -#define SECP256K1_GROUP_H - -#include "field.h" - -/** A group element in affine coordinates on the secp256k1 curve, - * or occasionally on an isomorphic curve of the form y^2 = x^3 + 7*t^6. - * Note: For exhaustive test mode, secp256k1 is replaced by a small subgroup of a different curve. - */ -typedef struct { - rustsecp256k1zkp_v0_8_0_fe x; - rustsecp256k1zkp_v0_8_0_fe y; - int infinity; /* whether this represents the point at infinity */ -} rustsecp256k1zkp_v0_8_0_ge; - -#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0} -#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} - -/** A group element of the secp256k1 curve, in jacobian coordinates. - * Note: For exhastive test mode, sepc256k1 is replaced by a small subgroup of a different curve. - */ -typedef struct { - rustsecp256k1zkp_v0_8_0_fe x; /* actual X: x/z^2 */ - rustsecp256k1zkp_v0_8_0_fe y; /* actual Y: y/z^3 */ - rustsecp256k1zkp_v0_8_0_fe z; - int infinity; /* whether this represents the point at infinity */ -} rustsecp256k1zkp_v0_8_0_gej; - -#define SECP256K1_GEJ_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), 0} -#define SECP256K1_GEJ_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} - -typedef struct { - rustsecp256k1zkp_v0_8_0_fe_storage x; - rustsecp256k1zkp_v0_8_0_fe_storage y; -} rustsecp256k1zkp_v0_8_0_ge_storage; - -#define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))} - -#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) - -/** Set a group element equal to the point with given X and Y coordinates */ -static void rustsecp256k1zkp_v0_8_0_ge_set_xy(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_fe *x, const rustsecp256k1zkp_v0_8_0_fe *y); - -/** Set a group element (affine) equal to the point with the given X coordinate - * and a Y coordinate that is a quadratic residue modulo p. The return value - * is true iff a coordinate with the given X coordinate exists. - */ -static int rustsecp256k1zkp_v0_8_0_ge_set_xquad(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_fe *x); - -/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness - * for Y. Return value indicates whether the result is valid. */ -static int rustsecp256k1zkp_v0_8_0_ge_set_xo_var(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_fe *x, int odd); - -/** Check whether a group element is the point at infinity. */ -static int rustsecp256k1zkp_v0_8_0_ge_is_infinity(const rustsecp256k1zkp_v0_8_0_ge *a); - -/** Check whether a group element is valid (i.e., on the curve). */ -static int rustsecp256k1zkp_v0_8_0_ge_is_valid_var(const rustsecp256k1zkp_v0_8_0_ge *a); - -/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ -static void rustsecp256k1zkp_v0_8_0_ge_neg(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_ge *a); - -/** Set a group element equal to another which is given in jacobian coordinates. Constant time. */ -static void rustsecp256k1zkp_v0_8_0_ge_set_gej(rustsecp256k1zkp_v0_8_0_ge *r, rustsecp256k1zkp_v0_8_0_gej *a); - -/** Set a group element equal to another which is given in jacobian coordinates. */ -static void rustsecp256k1zkp_v0_8_0_ge_set_gej_var(rustsecp256k1zkp_v0_8_0_ge *r, rustsecp256k1zkp_v0_8_0_gej *a); - -/** Set a batch of group elements equal to the inputs given in jacobian coordinates */ -static void rustsecp256k1zkp_v0_8_0_ge_set_all_gej_var(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_gej *a, size_t len); - -/** Bring a batch of inputs to the same global z "denominator", based on ratios between - * (omitted) z coordinates of adjacent elements. - * - * Although the elements a[i] are _ge rather than _gej, they actually represent elements - * in Jacobian coordinates with their z coordinates omitted. - * - * Using the notation z(b) to represent the omitted z coordinate of b, the array zr of - * z coordinate ratios must satisfy zr[i] == z(a[i]) / z(a[i-1]) for 0 < 'i' < len. - * The zr[0] value is unused. - * - * This function adjusts the coordinates of 'a' in place so that for all 'i', z(a[i]) == z(a[len-1]). - * In other words, the initial value of z(a[len-1]) becomes the global z "denominator". Only the - * a[i].x and a[i].y coordinates are explicitly modified; the adjustment of the omitted z coordinate is - * implicit. - * - * The coordinates of the final element a[len-1] are not changed. - */ -static void rustsecp256k1zkp_v0_8_0_ge_table_set_globalz(size_t len, rustsecp256k1zkp_v0_8_0_ge *a, const rustsecp256k1zkp_v0_8_0_fe *zr); - -/** Set a group element (affine) equal to the point at infinity. */ -static void rustsecp256k1zkp_v0_8_0_ge_set_infinity(rustsecp256k1zkp_v0_8_0_ge *r); - -/** Set a group element (jacobian) equal to the point at infinity. */ -static void rustsecp256k1zkp_v0_8_0_gej_set_infinity(rustsecp256k1zkp_v0_8_0_gej *r); - -/** Set a group element (jacobian) equal to another which is given in affine coordinates. */ -static void rustsecp256k1zkp_v0_8_0_gej_set_ge(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_ge *a); - -/** Compare the X coordinate of a group element (jacobian). */ -static int rustsecp256k1zkp_v0_8_0_gej_eq_x_var(const rustsecp256k1zkp_v0_8_0_fe *x, const rustsecp256k1zkp_v0_8_0_gej *a); - -/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ -static void rustsecp256k1zkp_v0_8_0_gej_neg(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a); - -/** Check whether a group element is the point at infinity. */ -static int rustsecp256k1zkp_v0_8_0_gej_is_infinity(const rustsecp256k1zkp_v0_8_0_gej *a); - -/** Check whether a group element's y coordinate is a quadratic residue. */ -static int rustsecp256k1zkp_v0_8_0_gej_has_quad_y_var(const rustsecp256k1zkp_v0_8_0_gej *a); - -/** Set r equal to the double of a. Constant time. */ -static void rustsecp256k1zkp_v0_8_0_gej_double(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a); - -/** Set r equal to the double of a. If rzr is not-NULL this sets *rzr such that r->z == a->z * *rzr (where infinity means an implicit z = 0). */ -static void rustsecp256k1zkp_v0_8_0_gej_double_var(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a, rustsecp256k1zkp_v0_8_0_fe *rzr); - -/** Set r equal to the sum of a and b. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */ -static void rustsecp256k1zkp_v0_8_0_gej_add_var(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a, const rustsecp256k1zkp_v0_8_0_gej *b, rustsecp256k1zkp_v0_8_0_fe *rzr); - -/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */ -static void rustsecp256k1zkp_v0_8_0_gej_add_ge(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a, const rustsecp256k1zkp_v0_8_0_ge *b); - -/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient - than rustsecp256k1zkp_v0_8_0_gej_add_var. It is identical to rustsecp256k1zkp_v0_8_0_gej_add_ge but without constant-time - guarantee, and b is allowed to be infinity. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */ -static void rustsecp256k1zkp_v0_8_0_gej_add_ge_var(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a, const rustsecp256k1zkp_v0_8_0_ge *b, rustsecp256k1zkp_v0_8_0_fe *rzr); - -/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */ -static void rustsecp256k1zkp_v0_8_0_gej_add_zinv_var(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a, const rustsecp256k1zkp_v0_8_0_ge *b, const rustsecp256k1zkp_v0_8_0_fe *bzinv); - -/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */ -static void rustsecp256k1zkp_v0_8_0_ge_mul_lambda(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_ge *a); - -/** Clear a rustsecp256k1zkp_v0_8_0_gej to prevent leaking sensitive information. */ -static void rustsecp256k1zkp_v0_8_0_gej_clear(rustsecp256k1zkp_v0_8_0_gej *r); - -/** Clear a rustsecp256k1zkp_v0_8_0_ge to prevent leaking sensitive information. */ -static void rustsecp256k1zkp_v0_8_0_ge_clear(rustsecp256k1zkp_v0_8_0_ge *r); - -/** Convert a group element to the storage type. */ -static void rustsecp256k1zkp_v0_8_0_ge_to_storage(rustsecp256k1zkp_v0_8_0_ge_storage *r, const rustsecp256k1zkp_v0_8_0_ge *a); - -/** Convert a group element back from the storage type. */ -static void rustsecp256k1zkp_v0_8_0_ge_from_storage(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_ge_storage *a); - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ -static void rustsecp256k1zkp_v0_8_0_gej_cmov(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a, int flag); - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ -static void rustsecp256k1zkp_v0_8_0_ge_storage_cmov(rustsecp256k1zkp_v0_8_0_ge_storage *r, const rustsecp256k1zkp_v0_8_0_ge_storage *a, int flag); - -/** Rescale a jacobian point by b which must be non-zero. Constant-time. */ -static void rustsecp256k1zkp_v0_8_0_gej_rescale(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_fe *b); - -/** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve. - * - * In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the - * group, and this function returns always true. - * - * When compiling in exhaustive test mode, a slightly different curve equation is used, leading to a group with a - * (very) small subgroup, and that subgroup is what is used for all cryptographic operations. In that mode, this - * function checks whether a point that is on the curve is in fact also in that subgroup. - */ -static int rustsecp256k1zkp_v0_8_0_ge_is_in_correct_subgroup(const rustsecp256k1zkp_v0_8_0_ge* ge); - -#endif /* SECP256K1_GROUP_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/group_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/group_impl.h deleted file mode 100644 index 9becd35b..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/group_impl.h +++ /dev/null @@ -1,693 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_GROUP_IMPL_H -#define SECP256K1_GROUP_IMPL_H - -#include "field.h" -#include "group.h" - -#define SECP256K1_G_ORDER_13 SECP256K1_GE_CONST(\ - 0xc3459c3d, 0x35326167, 0xcd86cce8, 0x07a2417f,\ - 0x5b8bd567, 0xde8538ee, 0x0d507b0c, 0xd128f5bb,\ - 0x8e467fec, 0xcd30000a, 0x6cc1184e, 0x25d382c2,\ - 0xa2f4494e, 0x2fbe9abc, 0x8b64abac, 0xd005fb24\ -) -#define SECP256K1_G_ORDER_199 SECP256K1_GE_CONST(\ - 0x226e653f, 0xc8df7744, 0x9bacbf12, 0x7d1dcbf9,\ - 0x87f05b2a, 0xe7edbd28, 0x1f564575, 0xc48dcf18,\ - 0xa13872c2, 0xe933bb17, 0x5d9ffd5b, 0xb5b6e10c,\ - 0x57fe3c00, 0xbaaaa15a, 0xe003ec3e, 0x9c269bae\ -) -/** Generator for secp256k1, value 'g' defined in - * "Standards for Efficient Cryptography" (SEC2) 2.7.1. - */ -#define SECP256K1_G SECP256K1_GE_CONST(\ - 0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL,\ - 0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL,\ - 0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL,\ - 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL\ -) -/* These exhaustive group test orders and generators are chosen such that: - * - The field size is equal to that of secp256k1, so field code is the same. - * - The curve equation is of the form y^2=x^3+B for some constant B. - * - The subgroup has a generator 2*P, where P.x=1. - * - The subgroup has size less than 1000 to permit exhaustive testing. - * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y). - * - * These parameters are generated using sage/gen_exhaustive_groups.sage. - */ -#if defined(EXHAUSTIVE_TEST_ORDER) -# if EXHAUSTIVE_TEST_ORDER == 13 -static const rustsecp256k1zkp_v0_8_0_ge rustsecp256k1zkp_v0_8_0_ge_const_g = SECP256K1_G_ORDER_13; - -static const rustsecp256k1zkp_v0_8_0_fe rustsecp256k1zkp_v0_8_0_fe_const_b = SECP256K1_FE_CONST( - 0x3d3486b2, 0x159a9ca5, 0xc75638be, 0xb23a69bc, - 0x946a45ab, 0x24801247, 0xb4ed2b8e, 0x26b6a417 -); -# elif EXHAUSTIVE_TEST_ORDER == 199 -static const rustsecp256k1zkp_v0_8_0_ge rustsecp256k1zkp_v0_8_0_ge_const_g = SECP256K1_G_ORDER_199; - -static const rustsecp256k1zkp_v0_8_0_fe rustsecp256k1zkp_v0_8_0_fe_const_b = SECP256K1_FE_CONST( - 0x2cca28fa, 0xfc614b80, 0x2a3db42b, 0x00ba00b1, - 0xbea8d943, 0xdace9ab2, 0x9536daea, 0x0074defb -); -# else -# error No known generator for the specified exhaustive test group order. -# endif -#else -static const rustsecp256k1zkp_v0_8_0_ge rustsecp256k1zkp_v0_8_0_ge_const_g = SECP256K1_G; - -static const rustsecp256k1zkp_v0_8_0_fe rustsecp256k1zkp_v0_8_0_fe_const_b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 7); -#endif - -static void rustsecp256k1zkp_v0_8_0_ge_set_gej_zinv(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_gej *a, const rustsecp256k1zkp_v0_8_0_fe *zi) { - rustsecp256k1zkp_v0_8_0_fe zi2; - rustsecp256k1zkp_v0_8_0_fe zi3; - VERIFY_CHECK(!a->infinity); - rustsecp256k1zkp_v0_8_0_fe_sqr(&zi2, zi); - rustsecp256k1zkp_v0_8_0_fe_mul(&zi3, &zi2, zi); - rustsecp256k1zkp_v0_8_0_fe_mul(&r->x, &a->x, &zi2); - rustsecp256k1zkp_v0_8_0_fe_mul(&r->y, &a->y, &zi3); - r->infinity = a->infinity; -} - -static void rustsecp256k1zkp_v0_8_0_ge_set_xy(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_fe *x, const rustsecp256k1zkp_v0_8_0_fe *y) { - r->infinity = 0; - r->x = *x; - r->y = *y; -} - -static int rustsecp256k1zkp_v0_8_0_ge_is_infinity(const rustsecp256k1zkp_v0_8_0_ge *a) { - return a->infinity; -} - -static void rustsecp256k1zkp_v0_8_0_ge_neg(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_ge *a) { - *r = *a; - rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&r->y); - rustsecp256k1zkp_v0_8_0_fe_negate(&r->y, &r->y, 1); -} - -static void rustsecp256k1zkp_v0_8_0_ge_set_gej(rustsecp256k1zkp_v0_8_0_ge *r, rustsecp256k1zkp_v0_8_0_gej *a) { - rustsecp256k1zkp_v0_8_0_fe z2, z3; - r->infinity = a->infinity; - rustsecp256k1zkp_v0_8_0_fe_inv(&a->z, &a->z); - rustsecp256k1zkp_v0_8_0_fe_sqr(&z2, &a->z); - rustsecp256k1zkp_v0_8_0_fe_mul(&z3, &a->z, &z2); - rustsecp256k1zkp_v0_8_0_fe_mul(&a->x, &a->x, &z2); - rustsecp256k1zkp_v0_8_0_fe_mul(&a->y, &a->y, &z3); - rustsecp256k1zkp_v0_8_0_fe_set_int(&a->z, 1); - r->x = a->x; - r->y = a->y; -} - -static void rustsecp256k1zkp_v0_8_0_ge_set_gej_var(rustsecp256k1zkp_v0_8_0_ge *r, rustsecp256k1zkp_v0_8_0_gej *a) { - rustsecp256k1zkp_v0_8_0_fe z2, z3; - if (a->infinity) { - rustsecp256k1zkp_v0_8_0_ge_set_infinity(r); - return; - } - rustsecp256k1zkp_v0_8_0_fe_inv_var(&a->z, &a->z); - rustsecp256k1zkp_v0_8_0_fe_sqr(&z2, &a->z); - rustsecp256k1zkp_v0_8_0_fe_mul(&z3, &a->z, &z2); - rustsecp256k1zkp_v0_8_0_fe_mul(&a->x, &a->x, &z2); - rustsecp256k1zkp_v0_8_0_fe_mul(&a->y, &a->y, &z3); - rustsecp256k1zkp_v0_8_0_fe_set_int(&a->z, 1); - rustsecp256k1zkp_v0_8_0_ge_set_xy(r, &a->x, &a->y); -} - -static void rustsecp256k1zkp_v0_8_0_ge_set_all_gej_var(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_gej *a, size_t len) { - rustsecp256k1zkp_v0_8_0_fe u; - size_t i; - size_t last_i = SIZE_MAX; - - for (i = 0; i < len; i++) { - if (a[i].infinity) { - rustsecp256k1zkp_v0_8_0_ge_set_infinity(&r[i]); - } else { - /* Use destination's x coordinates as scratch space */ - if (last_i == SIZE_MAX) { - r[i].x = a[i].z; - } else { - rustsecp256k1zkp_v0_8_0_fe_mul(&r[i].x, &r[last_i].x, &a[i].z); - } - last_i = i; - } - } - if (last_i == SIZE_MAX) { - return; - } - rustsecp256k1zkp_v0_8_0_fe_inv_var(&u, &r[last_i].x); - - i = last_i; - while (i > 0) { - i--; - if (!a[i].infinity) { - rustsecp256k1zkp_v0_8_0_fe_mul(&r[last_i].x, &r[i].x, &u); - rustsecp256k1zkp_v0_8_0_fe_mul(&u, &u, &a[last_i].z); - last_i = i; - } - } - VERIFY_CHECK(!a[last_i].infinity); - r[last_i].x = u; - - for (i = 0; i < len; i++) { - if (!a[i].infinity) { - rustsecp256k1zkp_v0_8_0_ge_set_gej_zinv(&r[i], &a[i], &r[i].x); - } - } -} - -static void rustsecp256k1zkp_v0_8_0_ge_table_set_globalz(size_t len, rustsecp256k1zkp_v0_8_0_ge *a, const rustsecp256k1zkp_v0_8_0_fe *zr) { - size_t i = len - 1; - rustsecp256k1zkp_v0_8_0_fe zs; - - if (len > 0) { - /* Ensure all y values are in weak normal form for fast negation of points */ - rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&a[i].y); - zs = zr[i]; - - /* Work our way backwards, using the z-ratios to scale the x/y values. */ - while (i > 0) { - rustsecp256k1zkp_v0_8_0_gej tmpa; - if (i != len - 1) { - rustsecp256k1zkp_v0_8_0_fe_mul(&zs, &zs, &zr[i]); - } - i--; - tmpa.x = a[i].x; - tmpa.y = a[i].y; - tmpa.infinity = 0; - rustsecp256k1zkp_v0_8_0_ge_set_gej_zinv(&a[i], &tmpa, &zs); - } - } -} - -static void rustsecp256k1zkp_v0_8_0_gej_set_infinity(rustsecp256k1zkp_v0_8_0_gej *r) { - r->infinity = 1; - rustsecp256k1zkp_v0_8_0_fe_clear(&r->x); - rustsecp256k1zkp_v0_8_0_fe_clear(&r->y); - rustsecp256k1zkp_v0_8_0_fe_clear(&r->z); -} - -static void rustsecp256k1zkp_v0_8_0_ge_set_infinity(rustsecp256k1zkp_v0_8_0_ge *r) { - r->infinity = 1; - rustsecp256k1zkp_v0_8_0_fe_clear(&r->x); - rustsecp256k1zkp_v0_8_0_fe_clear(&r->y); -} - -static void rustsecp256k1zkp_v0_8_0_gej_clear(rustsecp256k1zkp_v0_8_0_gej *r) { - r->infinity = 0; - rustsecp256k1zkp_v0_8_0_fe_clear(&r->x); - rustsecp256k1zkp_v0_8_0_fe_clear(&r->y); - rustsecp256k1zkp_v0_8_0_fe_clear(&r->z); -} - -static void rustsecp256k1zkp_v0_8_0_ge_clear(rustsecp256k1zkp_v0_8_0_ge *r) { - r->infinity = 0; - rustsecp256k1zkp_v0_8_0_fe_clear(&r->x); - rustsecp256k1zkp_v0_8_0_fe_clear(&r->y); -} - -static int rustsecp256k1zkp_v0_8_0_ge_set_xquad(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_fe *x) { - rustsecp256k1zkp_v0_8_0_fe x2, x3; - r->x = *x; - rustsecp256k1zkp_v0_8_0_fe_sqr(&x2, x); - rustsecp256k1zkp_v0_8_0_fe_mul(&x3, x, &x2); - r->infinity = 0; - rustsecp256k1zkp_v0_8_0_fe_add(&x3, &rustsecp256k1zkp_v0_8_0_fe_const_b); - return rustsecp256k1zkp_v0_8_0_fe_sqrt(&r->y, &x3); -} - -static int rustsecp256k1zkp_v0_8_0_ge_set_xo_var(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_fe *x, int odd) { - if (!rustsecp256k1zkp_v0_8_0_ge_set_xquad(r, x)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&r->y); - if (rustsecp256k1zkp_v0_8_0_fe_is_odd(&r->y) != odd) { - rustsecp256k1zkp_v0_8_0_fe_negate(&r->y, &r->y, 1); - } - return 1; - -} - -static void rustsecp256k1zkp_v0_8_0_gej_set_ge(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_ge *a) { - r->infinity = a->infinity; - r->x = a->x; - r->y = a->y; - rustsecp256k1zkp_v0_8_0_fe_set_int(&r->z, 1); -} - -static int rustsecp256k1zkp_v0_8_0_gej_eq_x_var(const rustsecp256k1zkp_v0_8_0_fe *x, const rustsecp256k1zkp_v0_8_0_gej *a) { - rustsecp256k1zkp_v0_8_0_fe r, r2; - VERIFY_CHECK(!a->infinity); - rustsecp256k1zkp_v0_8_0_fe_sqr(&r, &a->z); rustsecp256k1zkp_v0_8_0_fe_mul(&r, &r, x); - r2 = a->x; rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&r2); - return rustsecp256k1zkp_v0_8_0_fe_equal_var(&r, &r2); -} - -static void rustsecp256k1zkp_v0_8_0_gej_neg(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a) { - r->infinity = a->infinity; - r->x = a->x; - r->y = a->y; - r->z = a->z; - rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&r->y); - rustsecp256k1zkp_v0_8_0_fe_negate(&r->y, &r->y, 1); -} - -static int rustsecp256k1zkp_v0_8_0_gej_is_infinity(const rustsecp256k1zkp_v0_8_0_gej *a) { - return a->infinity; -} - -static int rustsecp256k1zkp_v0_8_0_ge_is_valid_var(const rustsecp256k1zkp_v0_8_0_ge *a) { - rustsecp256k1zkp_v0_8_0_fe y2, x3; - if (a->infinity) { - return 0; - } - /* y^2 = x^3 + 7 */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&y2, &a->y); - rustsecp256k1zkp_v0_8_0_fe_sqr(&x3, &a->x); rustsecp256k1zkp_v0_8_0_fe_mul(&x3, &x3, &a->x); - rustsecp256k1zkp_v0_8_0_fe_add(&x3, &rustsecp256k1zkp_v0_8_0_fe_const_b); - rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&x3); - return rustsecp256k1zkp_v0_8_0_fe_equal_var(&y2, &x3); -} - -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_gej_double(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a) { - /* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */ - rustsecp256k1zkp_v0_8_0_fe l, s, t; - - r->infinity = a->infinity; - - /* Formula used: - * L = (3/2) * X1^2 - * S = Y1^2 - * T = -X1*S - * X3 = L^2 + 2*T - * Y3 = -(L*(X3 + T) + S^2) - * Z3 = Y1*Z1 - */ - - rustsecp256k1zkp_v0_8_0_fe_mul(&r->z, &a->z, &a->y); /* Z3 = Y1*Z1 (1) */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&s, &a->y); /* S = Y1^2 (1) */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&l, &a->x); /* L = X1^2 (1) */ - rustsecp256k1zkp_v0_8_0_fe_mul_int(&l, 3); /* L = 3*X1^2 (3) */ - rustsecp256k1zkp_v0_8_0_fe_half(&l); /* L = 3/2*X1^2 (2) */ - rustsecp256k1zkp_v0_8_0_fe_negate(&t, &s, 1); /* T = -S (2) */ - rustsecp256k1zkp_v0_8_0_fe_mul(&t, &t, &a->x); /* T = -X1*S (1) */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&r->x, &l); /* X3 = L^2 (1) */ - rustsecp256k1zkp_v0_8_0_fe_add(&r->x, &t); /* X3 = L^2 + T (2) */ - rustsecp256k1zkp_v0_8_0_fe_add(&r->x, &t); /* X3 = L^2 + 2*T (3) */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&s, &s); /* S' = S^2 (1) */ - rustsecp256k1zkp_v0_8_0_fe_add(&t, &r->x); /* T' = X3 + T (4) */ - rustsecp256k1zkp_v0_8_0_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */ - rustsecp256k1zkp_v0_8_0_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */ - rustsecp256k1zkp_v0_8_0_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */ -} - -static void rustsecp256k1zkp_v0_8_0_gej_double_var(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a, rustsecp256k1zkp_v0_8_0_fe *rzr) { - /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, - * Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have - * y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. - * - * Having said this, if this function receives a point on a sextic twist, e.g. by - * a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6, - * since -6 does have a cube root mod p. For this point, this function will not set - * the infinity flag even though the point doubles to infinity, and the result - * point will be gibberish (z = 0 but infinity = 0). - */ - if (a->infinity) { - rustsecp256k1zkp_v0_8_0_gej_set_infinity(r); - if (rzr != NULL) { - rustsecp256k1zkp_v0_8_0_fe_set_int(rzr, 1); - } - return; - } - - if (rzr != NULL) { - *rzr = a->y; - rustsecp256k1zkp_v0_8_0_fe_normalize_weak(rzr); - } - - rustsecp256k1zkp_v0_8_0_gej_double(r, a); -} - -static void rustsecp256k1zkp_v0_8_0_gej_add_var(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a, const rustsecp256k1zkp_v0_8_0_gej *b, rustsecp256k1zkp_v0_8_0_fe *rzr) { - /* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */ - rustsecp256k1zkp_v0_8_0_fe z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; - - if (a->infinity) { - VERIFY_CHECK(rzr == NULL); - *r = *b; - return; - } - - if (b->infinity) { - if (rzr != NULL) { - rustsecp256k1zkp_v0_8_0_fe_set_int(rzr, 1); - } - *r = *a; - return; - } - - r->infinity = 0; - rustsecp256k1zkp_v0_8_0_fe_sqr(&z22, &b->z); - rustsecp256k1zkp_v0_8_0_fe_sqr(&z12, &a->z); - rustsecp256k1zkp_v0_8_0_fe_mul(&u1, &a->x, &z22); - rustsecp256k1zkp_v0_8_0_fe_mul(&u2, &b->x, &z12); - rustsecp256k1zkp_v0_8_0_fe_mul(&s1, &a->y, &z22); rustsecp256k1zkp_v0_8_0_fe_mul(&s1, &s1, &b->z); - rustsecp256k1zkp_v0_8_0_fe_mul(&s2, &b->y, &z12); rustsecp256k1zkp_v0_8_0_fe_mul(&s2, &s2, &a->z); - rustsecp256k1zkp_v0_8_0_fe_negate(&h, &u1, 1); rustsecp256k1zkp_v0_8_0_fe_add(&h, &u2); - rustsecp256k1zkp_v0_8_0_fe_negate(&i, &s1, 1); rustsecp256k1zkp_v0_8_0_fe_add(&i, &s2); - if (rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(&h)) { - if (rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(&i)) { - rustsecp256k1zkp_v0_8_0_gej_double_var(r, a, rzr); - } else { - if (rzr != NULL) { - rustsecp256k1zkp_v0_8_0_fe_set_int(rzr, 0); - } - rustsecp256k1zkp_v0_8_0_gej_set_infinity(r); - } - return; - } - rustsecp256k1zkp_v0_8_0_fe_sqr(&i2, &i); - rustsecp256k1zkp_v0_8_0_fe_sqr(&h2, &h); - rustsecp256k1zkp_v0_8_0_fe_mul(&h3, &h, &h2); - rustsecp256k1zkp_v0_8_0_fe_mul(&h, &h, &b->z); - if (rzr != NULL) { - *rzr = h; - } - rustsecp256k1zkp_v0_8_0_fe_mul(&r->z, &a->z, &h); - rustsecp256k1zkp_v0_8_0_fe_mul(&t, &u1, &h2); - r->x = t; rustsecp256k1zkp_v0_8_0_fe_mul_int(&r->x, 2); rustsecp256k1zkp_v0_8_0_fe_add(&r->x, &h3); rustsecp256k1zkp_v0_8_0_fe_negate(&r->x, &r->x, 3); rustsecp256k1zkp_v0_8_0_fe_add(&r->x, &i2); - rustsecp256k1zkp_v0_8_0_fe_negate(&r->y, &r->x, 5); rustsecp256k1zkp_v0_8_0_fe_add(&r->y, &t); rustsecp256k1zkp_v0_8_0_fe_mul(&r->y, &r->y, &i); - rustsecp256k1zkp_v0_8_0_fe_mul(&h3, &h3, &s1); rustsecp256k1zkp_v0_8_0_fe_negate(&h3, &h3, 1); - rustsecp256k1zkp_v0_8_0_fe_add(&r->y, &h3); -} - -static void rustsecp256k1zkp_v0_8_0_gej_add_ge_var(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a, const rustsecp256k1zkp_v0_8_0_ge *b, rustsecp256k1zkp_v0_8_0_fe *rzr) { - /* 8 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ - rustsecp256k1zkp_v0_8_0_fe z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; - if (a->infinity) { - VERIFY_CHECK(rzr == NULL); - rustsecp256k1zkp_v0_8_0_gej_set_ge(r, b); - return; - } - if (b->infinity) { - if (rzr != NULL) { - rustsecp256k1zkp_v0_8_0_fe_set_int(rzr, 1); - } - *r = *a; - return; - } - r->infinity = 0; - - rustsecp256k1zkp_v0_8_0_fe_sqr(&z12, &a->z); - u1 = a->x; rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&u1); - rustsecp256k1zkp_v0_8_0_fe_mul(&u2, &b->x, &z12); - s1 = a->y; rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&s1); - rustsecp256k1zkp_v0_8_0_fe_mul(&s2, &b->y, &z12); rustsecp256k1zkp_v0_8_0_fe_mul(&s2, &s2, &a->z); - rustsecp256k1zkp_v0_8_0_fe_negate(&h, &u1, 1); rustsecp256k1zkp_v0_8_0_fe_add(&h, &u2); - rustsecp256k1zkp_v0_8_0_fe_negate(&i, &s1, 1); rustsecp256k1zkp_v0_8_0_fe_add(&i, &s2); - if (rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(&h)) { - if (rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(&i)) { - rustsecp256k1zkp_v0_8_0_gej_double_var(r, a, rzr); - } else { - if (rzr != NULL) { - rustsecp256k1zkp_v0_8_0_fe_set_int(rzr, 0); - } - rustsecp256k1zkp_v0_8_0_gej_set_infinity(r); - } - return; - } - rustsecp256k1zkp_v0_8_0_fe_sqr(&i2, &i); - rustsecp256k1zkp_v0_8_0_fe_sqr(&h2, &h); - rustsecp256k1zkp_v0_8_0_fe_mul(&h3, &h, &h2); - if (rzr != NULL) { - *rzr = h; - } - rustsecp256k1zkp_v0_8_0_fe_mul(&r->z, &a->z, &h); - rustsecp256k1zkp_v0_8_0_fe_mul(&t, &u1, &h2); - r->x = t; rustsecp256k1zkp_v0_8_0_fe_mul_int(&r->x, 2); rustsecp256k1zkp_v0_8_0_fe_add(&r->x, &h3); rustsecp256k1zkp_v0_8_0_fe_negate(&r->x, &r->x, 3); rustsecp256k1zkp_v0_8_0_fe_add(&r->x, &i2); - rustsecp256k1zkp_v0_8_0_fe_negate(&r->y, &r->x, 5); rustsecp256k1zkp_v0_8_0_fe_add(&r->y, &t); rustsecp256k1zkp_v0_8_0_fe_mul(&r->y, &r->y, &i); - rustsecp256k1zkp_v0_8_0_fe_mul(&h3, &h3, &s1); rustsecp256k1zkp_v0_8_0_fe_negate(&h3, &h3, 1); - rustsecp256k1zkp_v0_8_0_fe_add(&r->y, &h3); -} - -static void rustsecp256k1zkp_v0_8_0_gej_add_zinv_var(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a, const rustsecp256k1zkp_v0_8_0_ge *b, const rustsecp256k1zkp_v0_8_0_fe *bzinv) { - /* 9 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ - rustsecp256k1zkp_v0_8_0_fe az, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; - - if (b->infinity) { - *r = *a; - return; - } - if (a->infinity) { - rustsecp256k1zkp_v0_8_0_fe bzinv2, bzinv3; - r->infinity = b->infinity; - rustsecp256k1zkp_v0_8_0_fe_sqr(&bzinv2, bzinv); - rustsecp256k1zkp_v0_8_0_fe_mul(&bzinv3, &bzinv2, bzinv); - rustsecp256k1zkp_v0_8_0_fe_mul(&r->x, &b->x, &bzinv2); - rustsecp256k1zkp_v0_8_0_fe_mul(&r->y, &b->y, &bzinv3); - rustsecp256k1zkp_v0_8_0_fe_set_int(&r->z, 1); - return; - } - r->infinity = 0; - - /** We need to calculate (rx,ry,rz) = (ax,ay,az) + (bx,by,1/bzinv). Due to - * secp256k1's isomorphism we can multiply the Z coordinates on both sides - * by bzinv, and get: (rx,ry,rz*bzinv) = (ax,ay,az*bzinv) + (bx,by,1). - * This means that (rx,ry,rz) can be calculated as - * (ax,ay,az*bzinv) + (bx,by,1), when not applying the bzinv factor to rz. - * The variable az below holds the modified Z coordinate for a, which is used - * for the computation of rx and ry, but not for rz. - */ - rustsecp256k1zkp_v0_8_0_fe_mul(&az, &a->z, bzinv); - - rustsecp256k1zkp_v0_8_0_fe_sqr(&z12, &az); - u1 = a->x; rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&u1); - rustsecp256k1zkp_v0_8_0_fe_mul(&u2, &b->x, &z12); - s1 = a->y; rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&s1); - rustsecp256k1zkp_v0_8_0_fe_mul(&s2, &b->y, &z12); rustsecp256k1zkp_v0_8_0_fe_mul(&s2, &s2, &az); - rustsecp256k1zkp_v0_8_0_fe_negate(&h, &u1, 1); rustsecp256k1zkp_v0_8_0_fe_add(&h, &u2); - rustsecp256k1zkp_v0_8_0_fe_negate(&i, &s1, 1); rustsecp256k1zkp_v0_8_0_fe_add(&i, &s2); - if (rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(&h)) { - if (rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(&i)) { - rustsecp256k1zkp_v0_8_0_gej_double_var(r, a, NULL); - } else { - rustsecp256k1zkp_v0_8_0_gej_set_infinity(r); - } - return; - } - rustsecp256k1zkp_v0_8_0_fe_sqr(&i2, &i); - rustsecp256k1zkp_v0_8_0_fe_sqr(&h2, &h); - rustsecp256k1zkp_v0_8_0_fe_mul(&h3, &h, &h2); - r->z = a->z; rustsecp256k1zkp_v0_8_0_fe_mul(&r->z, &r->z, &h); - rustsecp256k1zkp_v0_8_0_fe_mul(&t, &u1, &h2); - r->x = t; rustsecp256k1zkp_v0_8_0_fe_mul_int(&r->x, 2); rustsecp256k1zkp_v0_8_0_fe_add(&r->x, &h3); rustsecp256k1zkp_v0_8_0_fe_negate(&r->x, &r->x, 3); rustsecp256k1zkp_v0_8_0_fe_add(&r->x, &i2); - rustsecp256k1zkp_v0_8_0_fe_negate(&r->y, &r->x, 5); rustsecp256k1zkp_v0_8_0_fe_add(&r->y, &t); rustsecp256k1zkp_v0_8_0_fe_mul(&r->y, &r->y, &i); - rustsecp256k1zkp_v0_8_0_fe_mul(&h3, &h3, &s1); rustsecp256k1zkp_v0_8_0_fe_negate(&h3, &h3, 1); - rustsecp256k1zkp_v0_8_0_fe_add(&r->y, &h3); -} - - -static void rustsecp256k1zkp_v0_8_0_gej_add_ge(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a, const rustsecp256k1zkp_v0_8_0_ge *b) { - /* Operations: 7 mul, 5 sqr, 24 add/cmov/half/mul_int/negate/normalize_weak/normalizes_to_zero */ - rustsecp256k1zkp_v0_8_0_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; - rustsecp256k1zkp_v0_8_0_fe m_alt, rr_alt; - int infinity, degenerate; - VERIFY_CHECK(!b->infinity); - VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); - - /** In: - * Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks. - * In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002. - * we find as solution for a unified addition/doubling formula: - * lambda = ((x1 + x2)^2 - x1 * x2 + a) / (y1 + y2), with a = 0 for secp256k1's curve equation. - * x3 = lambda^2 - (x1 + x2) - * 2*y3 = lambda * (x1 + x2 - 2 * x3) - (y1 + y2). - * - * Substituting x_i = Xi / Zi^2 and yi = Yi / Zi^3, for i=1,2,3, gives: - * U1 = X1*Z2^2, U2 = X2*Z1^2 - * S1 = Y1*Z2^3, S2 = Y2*Z1^3 - * Z = Z1*Z2 - * T = U1+U2 - * M = S1+S2 - * Q = -T*M^2 - * R = T^2-U1*U2 - * X3 = R^2+Q - * Y3 = -(R*(2*X3+Q)+M^4)/2 - * Z3 = M*Z - * (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.) - * - * This formula has the benefit of being the same for both addition - * of distinct points and doubling. However, it breaks down in the - * case that either point is infinity, or that y1 = -y2. We handle - * these cases in the following ways: - * - * - If b is infinity we simply bail by means of a VERIFY_CHECK. - * - * - If a is infinity, we detect this, and at the end of the - * computation replace the result (which will be meaningless, - * but we compute to be constant-time) with b.x : b.y : 1. - * - * - If a = -b, we have y1 = -y2, which is a degenerate case. - * But here the answer is infinity, so we simply set the - * infinity flag of the result, overriding the computed values - * without even needing to cmov. - * - * - If y1 = -y2 but x1 != x2, which does occur thanks to certain - * properties of our curve (specifically, 1 has nontrivial cube - * roots in our field, and the curve equation has no x coefficient) - * then the answer is not infinity but also not given by the above - * equation. In this case, we cmov in place an alternate expression - * for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these - * expressions for lambda are defined, they are equal, and can be - * obtained from each other by multiplication by (y1 + y2)/(y1 + y2) - * then substitution of x^3 + 7 for y^2 (using the curve equation). - * For all pairs of nonzero points (a, b) at least one is defined, - * so this covers everything. - */ - - rustsecp256k1zkp_v0_8_0_fe_sqr(&zz, &a->z); /* z = Z1^2 */ - u1 = a->x; rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */ - rustsecp256k1zkp_v0_8_0_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ - s1 = a->y; rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */ - rustsecp256k1zkp_v0_8_0_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */ - rustsecp256k1zkp_v0_8_0_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ - t = u1; rustsecp256k1zkp_v0_8_0_fe_add(&t, &u2); /* t = T = U1+U2 (2) */ - m = s1; rustsecp256k1zkp_v0_8_0_fe_add(&m, &s2); /* m = M = S1+S2 (2) */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&rr, &t); /* rr = T^2 (1) */ - rustsecp256k1zkp_v0_8_0_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */ - rustsecp256k1zkp_v0_8_0_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */ - /** If lambda = R/M = 0/0 we have a problem (except in the "trivial" - * case that Z = z1z2 = 0, and this is special-cased later on). */ - degenerate = rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(&m) & - rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(&rr); - /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. - * This means either x1 == beta*x2 or beta*x1 == x2, where beta is - * a nontrivial cube root of one. In either case, an alternate - * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2), - * so we set R/M equal to this. */ - rr_alt = s1; - rustsecp256k1zkp_v0_8_0_fe_mul_int(&rr_alt, 2); /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */ - rustsecp256k1zkp_v0_8_0_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 */ - - rustsecp256k1zkp_v0_8_0_fe_cmov(&rr_alt, &rr, !degenerate); - rustsecp256k1zkp_v0_8_0_fe_cmov(&m_alt, &m, !degenerate); - /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0. - * From here on out Ralt and Malt represent the numerator - * and denominator of lambda; R and M represent the explicit - * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */ - rustsecp256k1zkp_v0_8_0_fe_negate(&q, &t, 2); /* q = -T (3) */ - rustsecp256k1zkp_v0_8_0_fe_mul(&q, &q, &n); /* q = Q = -T*Malt^2 (1) */ - /* These two lines use the observation that either M == Malt or M == 0, - * so M^3 * Malt is either Malt^4 (which is computed by squaring), or - * zero (which is "computed" by cmov). So the cost is one squaring - * versus two multiplications. */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&n, &n); - rustsecp256k1zkp_v0_8_0_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ - rustsecp256k1zkp_v0_8_0_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */ - infinity = rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(&r->z) & ~a->infinity; - rustsecp256k1zkp_v0_8_0_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */ - r->x = t; /* r->x = X3 = Ralt^2 + Q (2) */ - rustsecp256k1zkp_v0_8_0_fe_mul_int(&t, 2); /* t = 2*X3 (4) */ - rustsecp256k1zkp_v0_8_0_fe_add(&t, &q); /* t = 2*X3 + Q (5) */ - rustsecp256k1zkp_v0_8_0_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*X3 + Q) (1) */ - rustsecp256k1zkp_v0_8_0_fe_add(&t, &n); /* t = Ralt*(2*X3 + Q) + M^3*Malt (3) */ - rustsecp256k1zkp_v0_8_0_fe_negate(&r->y, &t, 3); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (4) */ - rustsecp256k1zkp_v0_8_0_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 (3) */ - - /** In case a->infinity == 1, replace r with (b->x, b->y, 1). */ - rustsecp256k1zkp_v0_8_0_fe_cmov(&r->x, &b->x, a->infinity); - rustsecp256k1zkp_v0_8_0_fe_cmov(&r->y, &b->y, a->infinity); - rustsecp256k1zkp_v0_8_0_fe_cmov(&r->z, &rustsecp256k1zkp_v0_8_0_fe_one, a->infinity); - r->infinity = infinity; -} - -static void rustsecp256k1zkp_v0_8_0_gej_rescale(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_fe *s) { - /* Operations: 4 mul, 1 sqr */ - rustsecp256k1zkp_v0_8_0_fe zz; - VERIFY_CHECK(!rustsecp256k1zkp_v0_8_0_fe_is_zero(s)); - rustsecp256k1zkp_v0_8_0_fe_sqr(&zz, s); - rustsecp256k1zkp_v0_8_0_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&r->y, &r->y, &zz); - rustsecp256k1zkp_v0_8_0_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&r->z, &r->z, s); /* r->z *= s */ -} - -static void rustsecp256k1zkp_v0_8_0_ge_to_storage(rustsecp256k1zkp_v0_8_0_ge_storage *r, const rustsecp256k1zkp_v0_8_0_ge *a) { - rustsecp256k1zkp_v0_8_0_fe x, y; - VERIFY_CHECK(!a->infinity); - x = a->x; - rustsecp256k1zkp_v0_8_0_fe_normalize(&x); - y = a->y; - rustsecp256k1zkp_v0_8_0_fe_normalize(&y); - rustsecp256k1zkp_v0_8_0_fe_to_storage(&r->x, &x); - rustsecp256k1zkp_v0_8_0_fe_to_storage(&r->y, &y); -} - -static void rustsecp256k1zkp_v0_8_0_ge_from_storage(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_ge_storage *a) { - rustsecp256k1zkp_v0_8_0_fe_from_storage(&r->x, &a->x); - rustsecp256k1zkp_v0_8_0_fe_from_storage(&r->y, &a->y); - r->infinity = 0; -} - -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_gej_cmov(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a, int flag) { - rustsecp256k1zkp_v0_8_0_fe_cmov(&r->x, &a->x, flag); - rustsecp256k1zkp_v0_8_0_fe_cmov(&r->y, &a->y, flag); - rustsecp256k1zkp_v0_8_0_fe_cmov(&r->z, &a->z, flag); - - r->infinity ^= (r->infinity ^ a->infinity) & flag; -} - -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_ge_storage_cmov(rustsecp256k1zkp_v0_8_0_ge_storage *r, const rustsecp256k1zkp_v0_8_0_ge_storage *a, int flag) { - rustsecp256k1zkp_v0_8_0_fe_storage_cmov(&r->x, &a->x, flag); - rustsecp256k1zkp_v0_8_0_fe_storage_cmov(&r->y, &a->y, flag); -} - -static void rustsecp256k1zkp_v0_8_0_ge_mul_lambda(rustsecp256k1zkp_v0_8_0_ge *r, const rustsecp256k1zkp_v0_8_0_ge *a) { - *r = *a; - rustsecp256k1zkp_v0_8_0_fe_mul(&r->x, &r->x, &rustsecp256k1zkp_v0_8_0_const_beta); -} - -static int rustsecp256k1zkp_v0_8_0_gej_has_quad_y_var(const rustsecp256k1zkp_v0_8_0_gej *a) { - rustsecp256k1zkp_v0_8_0_fe yz; - - if (a->infinity) { - return 0; - } - - /* We rely on the fact that the Jacobi symbol of 1 / a->z^3 is the same as - * that of a->z. Thus a->y / a->z^3 is a quadratic residue iff a->y * a->z - is */ - rustsecp256k1zkp_v0_8_0_fe_mul(&yz, &a->y, &a->z); - return rustsecp256k1zkp_v0_8_0_fe_is_quad_var(&yz); -} - -static int rustsecp256k1zkp_v0_8_0_ge_is_in_correct_subgroup(const rustsecp256k1zkp_v0_8_0_ge* ge) { -#ifdef EXHAUSTIVE_TEST_ORDER - rustsecp256k1zkp_v0_8_0_gej out; - int i; - - /* A very simple EC multiplication ladder that avoids a dependency on ecmult. */ - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&out); - for (i = 0; i < 32; ++i) { - rustsecp256k1zkp_v0_8_0_gej_double_var(&out, &out, NULL); - if ((((uint32_t)EXHAUSTIVE_TEST_ORDER) >> (31 - i)) & 1) { - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&out, &out, ge, NULL); - } - } - return rustsecp256k1zkp_v0_8_0_gej_is_infinity(&out); -#else - (void)ge; - /* The real secp256k1 group has cofactor 1, so the subgroup is the entire curve. */ - return 1; -#endif -} - -#endif /* SECP256K1_GROUP_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/hash.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/hash.h deleted file mode 100644 index ef21b5b3..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/hash.h +++ /dev/null @@ -1,41 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_HASH_H -#define SECP256K1_HASH_H - -#include -#include - -typedef struct { - uint32_t s[8]; - unsigned char buf[64]; - uint64_t bytes; -} rustsecp256k1zkp_v0_8_0_sha256; - -static void rustsecp256k1zkp_v0_8_0_sha256_initialize(rustsecp256k1zkp_v0_8_0_sha256 *hash); -static void rustsecp256k1zkp_v0_8_0_sha256_write(rustsecp256k1zkp_v0_8_0_sha256 *hash, const unsigned char *data, size_t size); -static void rustsecp256k1zkp_v0_8_0_sha256_finalize(rustsecp256k1zkp_v0_8_0_sha256 *hash, unsigned char *out32); - -typedef struct { - rustsecp256k1zkp_v0_8_0_sha256 inner, outer; -} rustsecp256k1zkp_v0_8_0_hmac_sha256; - -static void rustsecp256k1zkp_v0_8_0_hmac_sha256_initialize(rustsecp256k1zkp_v0_8_0_hmac_sha256 *hash, const unsigned char *key, size_t size); -static void rustsecp256k1zkp_v0_8_0_hmac_sha256_write(rustsecp256k1zkp_v0_8_0_hmac_sha256 *hash, const unsigned char *data, size_t size); -static void rustsecp256k1zkp_v0_8_0_hmac_sha256_finalize(rustsecp256k1zkp_v0_8_0_hmac_sha256 *hash, unsigned char *out32); - -typedef struct { - unsigned char v[32]; - unsigned char k[32]; - int retry; -} rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256; - -static void rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_initialize(rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen); -static void rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen); -static void rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_finalize(rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256 *rng); - -#endif /* SECP256K1_HASH_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modinv64_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modinv64_impl.h deleted file mode 100644 index d012a6cb..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modinv64_impl.h +++ /dev/null @@ -1,593 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Peter Dettman * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODINV64_IMPL_H -#define SECP256K1_MODINV64_IMPL_H - -#include "modinv64.h" - -#include "util.h" - -/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and - * modular inversion" by Daniel J. Bernstein and Bo-Yin Yang. - * - * For an explanation of the algorithm, see doc/safegcd_implementation.md. This file contains an - * implementation for N=62, using 62-bit signed limbs represented as int64_t. - */ - -#ifdef VERIFY -/* Helper function to compute the absolute value of an int64_t. - * (we don't use abs/labs/llabs as it depends on the int sizes). */ -static int64_t rustsecp256k1zkp_v0_8_0_modinv64_abs(int64_t v) { - VERIFY_CHECK(v > INT64_MIN); - if (v < 0) return -v; - return v; -} - -static const rustsecp256k1zkp_v0_8_0_modinv64_signed62 SECP256K1_SIGNED62_ONE = {{1}}; - -/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^62). */ -static void rustsecp256k1zkp_v0_8_0_modinv64_mul_62(rustsecp256k1zkp_v0_8_0_modinv64_signed62 *r, const rustsecp256k1zkp_v0_8_0_modinv64_signed62 *a, int alen, int64_t factor) { - const int64_t M62 = (int64_t)(UINT64_MAX >> 2); - int128_t c = 0; - int i; - for (i = 0; i < 4; ++i) { - if (i < alen) c += (int128_t)a->v[i] * factor; - r->v[i] = (int64_t)c & M62; c >>= 62; - } - if (4 < alen) c += (int128_t)a->v[4] * factor; - VERIFY_CHECK(c == (int64_t)c); - r->v[4] = (int64_t)c; -} - -/* Return -1 for ab*factor. A has alen limbs; b has 5. */ -static int rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(const rustsecp256k1zkp_v0_8_0_modinv64_signed62 *a, int alen, const rustsecp256k1zkp_v0_8_0_modinv64_signed62 *b, int64_t factor) { - int i; - rustsecp256k1zkp_v0_8_0_modinv64_signed62 am, bm; - rustsecp256k1zkp_v0_8_0_modinv64_mul_62(&am, a, alen, 1); /* Normalize all but the top limb of a. */ - rustsecp256k1zkp_v0_8_0_modinv64_mul_62(&bm, b, 5, factor); - for (i = 0; i < 4; ++i) { - /* Verify that all but the top limb of a and b are normalized. */ - VERIFY_CHECK(am.v[i] >> 62 == 0); - VERIFY_CHECK(bm.v[i] >> 62 == 0); - } - for (i = 4; i >= 0; --i) { - if (am.v[i] < bm.v[i]) return -1; - if (am.v[i] > bm.v[i]) return 1; - } - return 0; -} -#endif - -/* Take as input a signed62 number in range (-2*modulus,modulus), and add a multiple of the modulus - * to it to bring it to range [0,modulus). If sign < 0, the input will also be negated in the - * process. The input must have limbs in range (-2^62,2^62). The output will have limbs in range - * [0,2^62). */ -static void rustsecp256k1zkp_v0_8_0_modinv64_normalize_62(rustsecp256k1zkp_v0_8_0_modinv64_signed62 *r, int64_t sign, const rustsecp256k1zkp_v0_8_0_modinv64_modinfo *modinfo) { - const int64_t M62 = (int64_t)(UINT64_MAX >> 2); - int64_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4]; - int64_t cond_add, cond_negate; - -#ifdef VERIFY - /* Verify that all limbs are in range (-2^62,2^62). */ - int i; - for (i = 0; i < 5; ++i) { - VERIFY_CHECK(r->v[i] >= -M62); - VERIFY_CHECK(r->v[i] <= M62); - } - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, -2) > 0); /* r > -2*modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */ -#endif - - /* In a first step, add the modulus if the input is negative, and then negate if requested. - * This brings r from range (-2*modulus,modulus) to range (-modulus,modulus). As all input - * limbs are in range (-2^62,2^62), this cannot overflow an int64_t. Note that the right - * shifts below are signed sign-extending shifts (see assumptions.h for tests that that is - * indeed the behavior of the right shift operator). */ - cond_add = r4 >> 63; - r0 += modinfo->modulus.v[0] & cond_add; - r1 += modinfo->modulus.v[1] & cond_add; - r2 += modinfo->modulus.v[2] & cond_add; - r3 += modinfo->modulus.v[3] & cond_add; - r4 += modinfo->modulus.v[4] & cond_add; - cond_negate = sign >> 63; - r0 = (r0 ^ cond_negate) - cond_negate; - r1 = (r1 ^ cond_negate) - cond_negate; - r2 = (r2 ^ cond_negate) - cond_negate; - r3 = (r3 ^ cond_negate) - cond_negate; - r4 = (r4 ^ cond_negate) - cond_negate; - /* Propagate the top bits, to bring limbs back to range (-2^62,2^62). */ - r1 += r0 >> 62; r0 &= M62; - r2 += r1 >> 62; r1 &= M62; - r3 += r2 >> 62; r2 &= M62; - r4 += r3 >> 62; r3 &= M62; - - /* In a second step add the modulus again if the result is still negative, bringing - * r to range [0,modulus). */ - cond_add = r4 >> 63; - r0 += modinfo->modulus.v[0] & cond_add; - r1 += modinfo->modulus.v[1] & cond_add; - r2 += modinfo->modulus.v[2] & cond_add; - r3 += modinfo->modulus.v[3] & cond_add; - r4 += modinfo->modulus.v[4] & cond_add; - /* And propagate again. */ - r1 += r0 >> 62; r0 &= M62; - r2 += r1 >> 62; r1 &= M62; - r3 += r2 >> 62; r2 &= M62; - r4 += r3 >> 62; r3 &= M62; - - r->v[0] = r0; - r->v[1] = r1; - r->v[2] = r2; - r->v[3] = r3; - r->v[4] = r4; - -#ifdef VERIFY - VERIFY_CHECK(r0 >> 62 == 0); - VERIFY_CHECK(r1 >> 62 == 0); - VERIFY_CHECK(r2 >> 62 == 0); - VERIFY_CHECK(r3 >> 62 == 0); - VERIFY_CHECK(r4 >> 62 == 0); - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 0) >= 0); /* r >= 0 */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */ -#endif -} - -/* Data type for transition matrices (see section 3 of explanation). - * - * t = [ u v ] - * [ q r ] - */ -typedef struct { - int64_t u, v, q, r; -} rustsecp256k1zkp_v0_8_0_modinv64_trans2x2; - -/* Compute the transition matrix and eta for 59 divsteps (where zeta=-(delta+1/2)). - * Note that the transformation matrix is scaled by 2^62 and not 2^59. - * - * Input: zeta: initial zeta - * f0: bottom limb of initial f - * g0: bottom limb of initial g - * Output: t: transition matrix - * Return: final zeta - * - * Implements the divsteps_n_matrix function from the explanation. - */ -static int64_t rustsecp256k1zkp_v0_8_0_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_t g0, rustsecp256k1zkp_v0_8_0_modinv64_trans2x2 *t) { - /* u,v,q,r are the elements of the transformation matrix being built up, - * starting with the identity matrix times 8 (because the caller expects - * a result scaled by 2^62). Semantically they are signed integers - * in range [-2^62,2^62], but here represented as unsigned mod 2^64. This - * permits left shifting (which is UB for negative numbers). The range - * being inside [-2^63,2^63) means that casting to signed works correctly. - */ - uint64_t u = 8, v = 0, q = 0, r = 8; - uint64_t c1, c2, f = f0, g = g0, x, y, z; - int i; - - for (i = 3; i < 62; ++i) { - VERIFY_CHECK((f & 1) == 1); /* f must always be odd */ - VERIFY_CHECK((u * f0 + v * g0) == f << i); - VERIFY_CHECK((q * f0 + r * g0) == g << i); - /* Compute conditional masks for (zeta < 0) and for (g & 1). */ - c1 = zeta >> 63; - c2 = -(g & 1); - /* Compute x,y,z, conditionally negated versions of f,u,v. */ - x = (f ^ c1) - c1; - y = (u ^ c1) - c1; - z = (v ^ c1) - c1; - /* Conditionally add x,y,z to g,q,r. */ - g += x & c2; - q += y & c2; - r += z & c2; - /* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */ - c1 &= c2; - /* Conditionally change zeta into -zeta-2 or zeta-1. */ - zeta = (zeta ^ c1) - 1; - /* Conditionally add g,q,r to f,u,v. */ - f += g & c1; - u += q & c1; - v += r & c1; - /* Shifts */ - g >>= 1; - u <<= 1; - v <<= 1; - /* Bounds on zeta that follow from the bounds on iteration count (max 10*59 divsteps). */ - VERIFY_CHECK(zeta >= -591 && zeta <= 591); - } - /* Return data in t and return value. */ - t->u = (int64_t)u; - t->v = (int64_t)v; - t->q = (int64_t)q; - t->r = (int64_t)r; - /* The determinant of t must be a power of two. This guarantees that multiplication with t - * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which - * will be divided out again). As each divstep's individual matrix has determinant 2, the - * aggregate of 59 of them will have determinant 2^59. Multiplying with the initial - * 8*identity (which has determinant 2^6) means the overall outputs has determinant - * 2^65. */ - VERIFY_CHECK((int128_t)t->u * t->r - (int128_t)t->v * t->q == ((int128_t)1) << 65); - return zeta; -} - -/* Compute the transition matrix and eta for 62 divsteps (variable time, eta=-delta). - * - * Input: eta: initial eta - * f0: bottom limb of initial f - * g0: bottom limb of initial g - * Output: t: transition matrix - * Return: final eta - * - * Implements the divsteps_n_matrix_var function from the explanation. - */ -static int64_t rustsecp256k1zkp_v0_8_0_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, rustsecp256k1zkp_v0_8_0_modinv64_trans2x2 *t) { - /* Transformation matrix; see comments in rustsecp256k1zkp_v0_8_0_modinv64_divsteps_62. */ - uint64_t u = 1, v = 0, q = 0, r = 1; - uint64_t f = f0, g = g0, m; - uint32_t w; - int i = 62, limit, zeros; - - for (;;) { - /* Use a sentinel bit to count zeros only up to i. */ - zeros = rustsecp256k1zkp_v0_8_0_ctz64_var(g | (UINT64_MAX << i)); - /* Perform zeros divsteps at once; they all just divide g by two. */ - g >>= zeros; - u <<= zeros; - v <<= zeros; - eta -= zeros; - i -= zeros; - /* We're done once we've done 62 divsteps. */ - if (i == 0) break; - VERIFY_CHECK((f & 1) == 1); - VERIFY_CHECK((g & 1) == 1); - VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i)); - VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i)); - /* Bounds on eta that follow from the bounds on iteration count (max 12*62 divsteps). */ - VERIFY_CHECK(eta >= -745 && eta <= 745); - /* If eta is negative, negate it and replace f,g with g,-f. */ - if (eta < 0) { - uint64_t tmp; - eta = -eta; - tmp = f; f = g; g = -tmp; - tmp = u; u = q; q = -tmp; - tmp = v; v = r; r = -tmp; - /* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled - * out (as we'd be done before that point), and no more than eta+1 can be done as its - * will flip again once that happens. */ - limit = ((int)eta + 1) > i ? i : ((int)eta + 1); - VERIFY_CHECK(limit > 0 && limit <= 62); - /* m is a mask for the bottom min(limit, 6) bits. */ - m = (UINT64_MAX >> (64 - limit)) & 63U; - /* Find what multiple of f must be added to g to cancel its bottom min(limit, 6) - * bits. */ - w = (f * g * (f * f - 2)) & m; - } else { - /* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as - * eta tends to be smaller here. */ - limit = ((int)eta + 1) > i ? i : ((int)eta + 1); - VERIFY_CHECK(limit > 0 && limit <= 62); - /* m is a mask for the bottom min(limit, 4) bits. */ - m = (UINT64_MAX >> (64 - limit)) & 15U; - /* Find what multiple of f must be added to g to cancel its bottom min(limit, 4) - * bits. */ - w = f + (((f + 1) & 4) << 1); - w = (-w * g) & m; - } - g += f * w; - q += u * w; - r += v * w; - VERIFY_CHECK((g & m) == 0); - } - /* Return data in t and return value. */ - t->u = (int64_t)u; - t->v = (int64_t)v; - t->q = (int64_t)q; - t->r = (int64_t)r; - /* The determinant of t must be a power of two. This guarantees that multiplication with t - * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which - * will be divided out again). As each divstep's individual matrix has determinant 2, the - * aggregate of 62 of them will have determinant 2^62. */ - VERIFY_CHECK((int128_t)t->u * t->r - (int128_t)t->v * t->q == ((int128_t)1) << 62); - return eta; -} - -/* Compute (t/2^62) * [d, e] mod modulus, where t is a transition matrix scaled by 2^62. - * - * On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range - * (-2^62,2^62). - * - * This implements the update_de function from the explanation. - */ -static void rustsecp256k1zkp_v0_8_0_modinv64_update_de_62(rustsecp256k1zkp_v0_8_0_modinv64_signed62 *d, rustsecp256k1zkp_v0_8_0_modinv64_signed62 *e, const rustsecp256k1zkp_v0_8_0_modinv64_trans2x2 *t, const rustsecp256k1zkp_v0_8_0_modinv64_modinfo* modinfo) { - const int64_t M62 = (int64_t)(UINT64_MAX >> 2); - const int64_t d0 = d->v[0], d1 = d->v[1], d2 = d->v[2], d3 = d->v[3], d4 = d->v[4]; - const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4]; - const int64_t u = t->u, v = t->v, q = t->q, r = t->r; - int64_t md, me, sd, se; - int128_t cd, ce; -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ - VERIFY_CHECK((rustsecp256k1zkp_v0_8_0_modinv64_abs(u) + rustsecp256k1zkp_v0_8_0_modinv64_abs(v)) >= 0); /* |u|+|v| doesn't overflow */ - VERIFY_CHECK((rustsecp256k1zkp_v0_8_0_modinv64_abs(q) + rustsecp256k1zkp_v0_8_0_modinv64_abs(r)) >= 0); /* |q|+|r| doesn't overflow */ - VERIFY_CHECK((rustsecp256k1zkp_v0_8_0_modinv64_abs(u) + rustsecp256k1zkp_v0_8_0_modinv64_abs(v)) <= M62 + 1); /* |u|+|v| <= 2^62 */ - VERIFY_CHECK((rustsecp256k1zkp_v0_8_0_modinv64_abs(q) + rustsecp256k1zkp_v0_8_0_modinv64_abs(r)) <= M62 + 1); /* |q|+|r| <= 2^62 */ -#endif - /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ - sd = d4 >> 63; - se = e4 >> 63; - md = (u & sd) + (v & se); - me = (q & sd) + (r & se); - /* Begin computing t*[d,e]. */ - cd = (int128_t)u * d0 + (int128_t)v * e0; - ce = (int128_t)q * d0 + (int128_t)r * e0; - /* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */ - md -= (modinfo->modulus_inv62 * (uint64_t)cd + md) & M62; - me -= (modinfo->modulus_inv62 * (uint64_t)ce + me) & M62; - /* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */ - cd += (int128_t)modinfo->modulus.v[0] * md; - ce += (int128_t)modinfo->modulus.v[0] * me; - /* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */ - VERIFY_CHECK(((int64_t)cd & M62) == 0); cd >>= 62; - VERIFY_CHECK(((int64_t)ce & M62) == 0); ce >>= 62; - /* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */ - cd += (int128_t)u * d1 + (int128_t)v * e1; - ce += (int128_t)q * d1 + (int128_t)r * e1; - if (modinfo->modulus.v[1]) { /* Optimize for the case where limb of modulus is zero. */ - cd += (int128_t)modinfo->modulus.v[1] * md; - ce += (int128_t)modinfo->modulus.v[1] * me; - } - d->v[0] = (int64_t)cd & M62; cd >>= 62; - e->v[0] = (int64_t)ce & M62; ce >>= 62; - /* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */ - cd += (int128_t)u * d2 + (int128_t)v * e2; - ce += (int128_t)q * d2 + (int128_t)r * e2; - if (modinfo->modulus.v[2]) { /* Optimize for the case where limb of modulus is zero. */ - cd += (int128_t)modinfo->modulus.v[2] * md; - ce += (int128_t)modinfo->modulus.v[2] * me; - } - d->v[1] = (int64_t)cd & M62; cd >>= 62; - e->v[1] = (int64_t)ce & M62; ce >>= 62; - /* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */ - cd += (int128_t)u * d3 + (int128_t)v * e3; - ce += (int128_t)q * d3 + (int128_t)r * e3; - if (modinfo->modulus.v[3]) { /* Optimize for the case where limb of modulus is zero. */ - cd += (int128_t)modinfo->modulus.v[3] * md; - ce += (int128_t)modinfo->modulus.v[3] * me; - } - d->v[2] = (int64_t)cd & M62; cd >>= 62; - e->v[2] = (int64_t)ce & M62; ce >>= 62; - /* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */ - cd += (int128_t)u * d4 + (int128_t)v * e4; - ce += (int128_t)q * d4 + (int128_t)r * e4; - cd += (int128_t)modinfo->modulus.v[4] * md; - ce += (int128_t)modinfo->modulus.v[4] * me; - d->v[3] = (int64_t)cd & M62; cd >>= 62; - e->v[3] = (int64_t)ce & M62; ce >>= 62; - /* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */ - d->v[4] = (int64_t)cd; - e->v[4] = (int64_t)ce; -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ -#endif -} - -/* Compute (t/2^62) * [f, g], where t is a transition matrix scaled by 2^62. - * - * This implements the update_fg function from the explanation. - */ -static void rustsecp256k1zkp_v0_8_0_modinv64_update_fg_62(rustsecp256k1zkp_v0_8_0_modinv64_signed62 *f, rustsecp256k1zkp_v0_8_0_modinv64_signed62 *g, const rustsecp256k1zkp_v0_8_0_modinv64_trans2x2 *t) { - const int64_t M62 = (int64_t)(UINT64_MAX >> 2); - const int64_t f0 = f->v[0], f1 = f->v[1], f2 = f->v[2], f3 = f->v[3], f4 = f->v[4]; - const int64_t g0 = g->v[0], g1 = g->v[1], g2 = g->v[2], g3 = g->v[3], g4 = g->v[4]; - const int64_t u = t->u, v = t->v, q = t->q, r = t->r; - int128_t cf, cg; - /* Start computing t*[f,g]. */ - cf = (int128_t)u * f0 + (int128_t)v * g0; - cg = (int128_t)q * f0 + (int128_t)r * g0; - /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ - VERIFY_CHECK(((int64_t)cf & M62) == 0); cf >>= 62; - VERIFY_CHECK(((int64_t)cg & M62) == 0); cg >>= 62; - /* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */ - cf += (int128_t)u * f1 + (int128_t)v * g1; - cg += (int128_t)q * f1 + (int128_t)r * g1; - f->v[0] = (int64_t)cf & M62; cf >>= 62; - g->v[0] = (int64_t)cg & M62; cg >>= 62; - /* Compute limb 2 of t*[f,g], and store it as output limb 1. */ - cf += (int128_t)u * f2 + (int128_t)v * g2; - cg += (int128_t)q * f2 + (int128_t)r * g2; - f->v[1] = (int64_t)cf & M62; cf >>= 62; - g->v[1] = (int64_t)cg & M62; cg >>= 62; - /* Compute limb 3 of t*[f,g], and store it as output limb 2. */ - cf += (int128_t)u * f3 + (int128_t)v * g3; - cg += (int128_t)q * f3 + (int128_t)r * g3; - f->v[2] = (int64_t)cf & M62; cf >>= 62; - g->v[2] = (int64_t)cg & M62; cg >>= 62; - /* Compute limb 4 of t*[f,g], and store it as output limb 3. */ - cf += (int128_t)u * f4 + (int128_t)v * g4; - cg += (int128_t)q * f4 + (int128_t)r * g4; - f->v[3] = (int64_t)cf & M62; cf >>= 62; - g->v[3] = (int64_t)cg & M62; cg >>= 62; - /* What remains is limb 5 of t*[f,g]; store it as output limb 4. */ - f->v[4] = (int64_t)cf; - g->v[4] = (int64_t)cg; -} - -/* Compute (t/2^62) * [f, g], where t is a transition matrix for 62 divsteps. - * - * Version that operates on a variable number of limbs in f and g. - * - * This implements the update_fg function from the explanation. - */ -static void rustsecp256k1zkp_v0_8_0_modinv64_update_fg_62_var(int len, rustsecp256k1zkp_v0_8_0_modinv64_signed62 *f, rustsecp256k1zkp_v0_8_0_modinv64_signed62 *g, const rustsecp256k1zkp_v0_8_0_modinv64_trans2x2 *t) { - const int64_t M62 = (int64_t)(UINT64_MAX >> 2); - const int64_t u = t->u, v = t->v, q = t->q, r = t->r; - int64_t fi, gi; - int128_t cf, cg; - int i; - VERIFY_CHECK(len > 0); - /* Start computing t*[f,g]. */ - fi = f->v[0]; - gi = g->v[0]; - cf = (int128_t)u * fi + (int128_t)v * gi; - cg = (int128_t)q * fi + (int128_t)r * gi; - /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ - VERIFY_CHECK(((int64_t)cf & M62) == 0); cf >>= 62; - VERIFY_CHECK(((int64_t)cg & M62) == 0); cg >>= 62; - /* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting - * down by 62 bits). */ - for (i = 1; i < len; ++i) { - fi = f->v[i]; - gi = g->v[i]; - cf += (int128_t)u * fi + (int128_t)v * gi; - cg += (int128_t)q * fi + (int128_t)r * gi; - f->v[i - 1] = (int64_t)cf & M62; cf >>= 62; - g->v[i - 1] = (int64_t)cg & M62; cg >>= 62; - } - /* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */ - f->v[len - 1] = (int64_t)cf; - g->v[len - 1] = (int64_t)cg; -} - -/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */ -static void rustsecp256k1zkp_v0_8_0_modinv64(rustsecp256k1zkp_v0_8_0_modinv64_signed62 *x, const rustsecp256k1zkp_v0_8_0_modinv64_modinfo *modinfo) { - /* Start with d=0, e=1, f=modulus, g=x, zeta=-1. */ - rustsecp256k1zkp_v0_8_0_modinv64_signed62 d = {{0, 0, 0, 0, 0}}; - rustsecp256k1zkp_v0_8_0_modinv64_signed62 e = {{1, 0, 0, 0, 0}}; - rustsecp256k1zkp_v0_8_0_modinv64_signed62 f = modinfo->modulus; - rustsecp256k1zkp_v0_8_0_modinv64_signed62 g = *x; - int i; - int64_t zeta = -1; /* zeta = -(delta+1/2); delta starts at 1/2. */ - - /* Do 10 iterations of 59 divsteps each = 590 divsteps. This suffices for 256-bit inputs. */ - for (i = 0; i < 10; ++i) { - /* Compute transition matrix and new zeta after 59 divsteps. */ - rustsecp256k1zkp_v0_8_0_modinv64_trans2x2 t; - zeta = rustsecp256k1zkp_v0_8_0_modinv64_divsteps_59(zeta, f.v[0], g.v[0], &t); - /* Update d,e using that transition matrix. */ - rustsecp256k1zkp_v0_8_0_modinv64_update_de_62(&d, &e, &t, modinfo); - /* Update f,g using that transition matrix. */ -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif - rustsecp256k1zkp_v0_8_0_modinv64_update_fg_62(&f, &g, &t); -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif - } - - /* At this point sufficient iterations have been performed that g must have reached 0 - * and (if g was not originally 0) f must now equal +/- GCD of the initial f, g - * values i.e. +/- 1, and d now contains +/- the modular inverse. */ -#ifdef VERIFY - /* g == 0 */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&g, 5, &SECP256K1_SIGNED62_ONE, 0) == 0); - /* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, -1) == 0 || - rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, 1) == 0 || - (rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && - rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && - (rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) == 0 || - rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) == 0))); -#endif - - /* Optionally negate d, normalize to [0,modulus), and return it. */ - rustsecp256k1zkp_v0_8_0_modinv64_normalize_62(&d, f.v[4], modinfo); - *x = d; -} - -/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (variable time). */ -static void rustsecp256k1zkp_v0_8_0_modinv64_var(rustsecp256k1zkp_v0_8_0_modinv64_signed62 *x, const rustsecp256k1zkp_v0_8_0_modinv64_modinfo *modinfo) { - /* Start with d=0, e=1, f=modulus, g=x, eta=-1. */ - rustsecp256k1zkp_v0_8_0_modinv64_signed62 d = {{0, 0, 0, 0, 0}}; - rustsecp256k1zkp_v0_8_0_modinv64_signed62 e = {{1, 0, 0, 0, 0}}; - rustsecp256k1zkp_v0_8_0_modinv64_signed62 f = modinfo->modulus; - rustsecp256k1zkp_v0_8_0_modinv64_signed62 g = *x; -#ifdef VERIFY - int i = 0; -#endif - int j, len = 5; - int64_t eta = -1; /* eta = -delta; delta is initially 1 */ - int64_t cond, fn, gn; - - /* Do iterations of 62 divsteps each until g=0. */ - while (1) { - /* Compute transition matrix and new eta after 62 divsteps. */ - rustsecp256k1zkp_v0_8_0_modinv64_trans2x2 t; - eta = rustsecp256k1zkp_v0_8_0_modinv64_divsteps_62_var(eta, f.v[0], g.v[0], &t); - /* Update d,e using that transition matrix. */ - rustsecp256k1zkp_v0_8_0_modinv64_update_de_62(&d, &e, &t, modinfo); - /* Update f,g using that transition matrix. */ -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif - rustsecp256k1zkp_v0_8_0_modinv64_update_fg_62_var(len, &f, &g, &t); - /* If the bottom limb of g is zero, there is a chance that g=0. */ - if (g.v[0] == 0) { - cond = 0; - /* Check if the other limbs are also 0. */ - for (j = 1; j < len; ++j) { - cond |= g.v[j]; - } - /* If so, we're done. */ - if (cond == 0) break; - } - - /* Determine if len>1 and limb (len-1) of both f and g is 0 or -1. */ - fn = f.v[len - 1]; - gn = g.v[len - 1]; - cond = ((int64_t)len - 2) >> 63; - cond |= fn ^ (fn >> 63); - cond |= gn ^ (gn >> 63); - /* If so, reduce length, propagating the sign of f and g's top limb into the one below. */ - if (cond == 0) { - f.v[len - 2] |= (uint64_t)fn << 62; - g.v[len - 2] |= (uint64_t)gn << 62; - --len; - } -#ifdef VERIFY - VERIFY_CHECK(++i < 12); /* We should never need more than 12*62 = 744 divsteps */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif - } - - /* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of - * the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */ -#ifdef VERIFY - /* g == 0 */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&g, len, &SECP256K1_SIGNED62_ONE, 0) == 0); - /* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, -1) == 0 || - rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, 1) == 0 || - (rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && - rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && - (rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) == 0 || - rustsecp256k1zkp_v0_8_0_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) == 0))); -#endif - - /* Optionally negate d, normalize to [0,modulus), and return it. */ - rustsecp256k1zkp_v0_8_0_modinv64_normalize_62(&d, f.v[len - 1], modinfo); - *x = d; -} - -#endif /* SECP256K1_MODINV64_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/Makefile.am.include b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/Makefile.am.include deleted file mode 100644 index e6693a9e..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/Makefile.am.include +++ /dev/null @@ -1,13 +0,0 @@ -include_HEADERS += include/rustsecp256k1zkp_v0_8_0_bppp.h -noinst_HEADERS += src/modules/bppp/bppp_util.h -noinst_HEADERS += src/modules/bppp/main_impl.h -noinst_HEADERS += src/modules/bppp/bppp_transcript_impl.h -noinst_HEADERS += src/modules/bppp/bppp_norm_product_impl.h -noinst_HEADERS += src/modules/bppp/tests_impl.h - -if USE_BENCHMARK -noinst_PROGRAMS += bench_bppp -bench_bppp_SOURCES = src/bench_bppp.c -bench_bppp_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_bppp_LDFLAGS = -static -endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/bppp_norm_product_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/bppp_norm_product_impl.h deleted file mode 100644 index c2aa466b..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/bppp_norm_product_impl.h +++ /dev/null @@ -1,559 +0,0 @@ -/********************************************************************** - * Copyright (c) 2020 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_MODULE_BPPP_PP_NORM_PRODUCT_ -#define _SECP256K1_MODULE_BPPP_PP_NORM_PRODUCT_ - -#include "group.h" -#include "scalar.h" -#include "ecmult.h" -#include "ecmult_gen.h" -#include "hash.h" - -#include "modules/bppp/main.h" -#include "modules/bppp/bppp_util.h" -#include "modules/bppp/bppp_transcript_impl.h" - -/* Computes the inner product of two vectors of scalars - * with elements starting from offset a and offset b - * skipping elements according to specified step. - * Returns: Sum_{i=0..len-1}(a[offset_a + i*step] * b[offset_b + i*step]) */ -static int rustsecp256k1zkp_v0_8_0_scalar_inner_product( - rustsecp256k1zkp_v0_8_0_scalar* res, - const rustsecp256k1zkp_v0_8_0_scalar* a_vec, - const size_t a_offset, - const rustsecp256k1zkp_v0_8_0_scalar* b_vec, - const size_t b_offset, - const size_t step, - const size_t len -) { - size_t i; - rustsecp256k1zkp_v0_8_0_scalar_set_int(res, 0); - for (i = 0; i < len; i++) { - rustsecp256k1zkp_v0_8_0_scalar term; - rustsecp256k1zkp_v0_8_0_scalar_mul(&term, &a_vec[a_offset + step*i], &b_vec[b_offset + step*i]); - rustsecp256k1zkp_v0_8_0_scalar_add(res, res, &term); - } - return 1; -} - -/* Computes the q-weighted inner product of two vectors of scalars - * for elements starting from offset a and offset b respectively with the - * given step. - * Returns: Sum_{i=0..len-1}(a[offset_a + step*i] * b[offset_b2 + step*i]*q^(i+1)) */ -static int rustsecp256k1zkp_v0_8_0_weighted_scalar_inner_product( - rustsecp256k1zkp_v0_8_0_scalar* res, - const rustsecp256k1zkp_v0_8_0_scalar* a_vec, - const size_t a_offset, - const rustsecp256k1zkp_v0_8_0_scalar* b_vec, - const size_t b_offset, - const size_t step, - const size_t len, - const rustsecp256k1zkp_v0_8_0_scalar* q -) { - rustsecp256k1zkp_v0_8_0_scalar q_pow; - size_t i; - rustsecp256k1zkp_v0_8_0_scalar_set_int(res, 0); - q_pow = *q; - for (i = 0; i < len; i++) { - rustsecp256k1zkp_v0_8_0_scalar term; - rustsecp256k1zkp_v0_8_0_scalar_mul(&term, &a_vec[a_offset + step*i], &b_vec[b_offset + step*i]); - rustsecp256k1zkp_v0_8_0_scalar_mul(&term, &term, &q_pow); - rustsecp256k1zkp_v0_8_0_scalar_mul(&q_pow, &q_pow, q); - rustsecp256k1zkp_v0_8_0_scalar_add(res, res, &term); - } - return 1; -} - -/* Compute the powers of r as r, r^2, r^4 ... r^(2^(n-1)) */ -static void rustsecp256k1zkp_v0_8_0_bppp_powers_of_r(rustsecp256k1zkp_v0_8_0_scalar *powers, const rustsecp256k1zkp_v0_8_0_scalar *r, size_t n) { - size_t i; - if (n == 0) { - return; - } - powers[0] = *r; - for (i = 1; i < n; i++) { - rustsecp256k1zkp_v0_8_0_scalar_sqr(&powers[i], &powers[i - 1]); - } -} - -typedef struct ecmult_bp_commit_cb_data { - const rustsecp256k1zkp_v0_8_0_scalar *n; - const rustsecp256k1zkp_v0_8_0_ge *g; - const rustsecp256k1zkp_v0_8_0_scalar *l; - size_t g_len; -} ecmult_bp_commit_cb_data; - -static int ecmult_bp_commit_cb(rustsecp256k1zkp_v0_8_0_scalar *sc, rustsecp256k1zkp_v0_8_0_ge *pt, size_t idx, void *cbdata) { - ecmult_bp_commit_cb_data *data = (ecmult_bp_commit_cb_data*) cbdata; - *pt = data->g[idx]; - if (idx < data->g_len) { - *sc = data->n[idx]; - } else { - *sc = data->l[idx - data->g_len]; - } - return 1; -} - -/* Create a commitment `commit` = vG + n_vec*G_vec + l_vec*H_vec where - v = |n_vec*n_vec|_q + . |w|_q denotes q-weighted norm of w and - denotes inner product of l and r. -*/ -static int rustsecp256k1zkp_v0_8_0_bppp_commit( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_scratch_space* scratch, - rustsecp256k1zkp_v0_8_0_ge* commit, - const rustsecp256k1zkp_v0_8_0_bppp_generators* g_vec, - const rustsecp256k1zkp_v0_8_0_scalar* n_vec, - size_t n_vec_len, - const rustsecp256k1zkp_v0_8_0_scalar* l_vec, - size_t l_vec_len, - const rustsecp256k1zkp_v0_8_0_scalar* c_vec, - size_t c_vec_len, - const rustsecp256k1zkp_v0_8_0_scalar* q -) { - rustsecp256k1zkp_v0_8_0_scalar v, l_c; - /* First n_vec_len generators are Gs, rest are Hs*/ - VERIFY_CHECK(g_vec->n == (n_vec_len + l_vec_len)); - VERIFY_CHECK(l_vec_len == c_vec_len); - - /* It is possible to extend to support n_vec and c_vec to not be power of - two. For the initial iterations of the code, we stick to powers of two for simplicity.*/ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_is_power_of_two(n_vec_len)); - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_is_power_of_two(c_vec_len)); - - /* Compute v = n_vec*n_vec*q + l_vec*c_vec */ - rustsecp256k1zkp_v0_8_0_weighted_scalar_inner_product(&v, n_vec, 0 /*a offset */, n_vec, 0 /*b offset*/, 1 /*step*/, n_vec_len, q); - rustsecp256k1zkp_v0_8_0_scalar_inner_product(&l_c, l_vec, 0 /*a offset */, c_vec, 0 /*b offset*/, 1 /*step*/, l_vec_len); - rustsecp256k1zkp_v0_8_0_scalar_add(&v, &v, &l_c); - - { - ecmult_bp_commit_cb_data data; - rustsecp256k1zkp_v0_8_0_gej commitj; - data.g = g_vec->gens; - data.n = n_vec; - data.l = l_vec; - data.g_len = n_vec_len; - - if (!rustsecp256k1zkp_v0_8_0_ecmult_multi_var(&ctx->error_callback, scratch, &commitj, &v, ecmult_bp_commit_cb, (void*) &data, n_vec_len + l_vec_len)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(commit, &commitj); - } - return 1; -} - -typedef struct ecmult_x_cb_data { - const rustsecp256k1zkp_v0_8_0_scalar *n; - const rustsecp256k1zkp_v0_8_0_ge *g; - const rustsecp256k1zkp_v0_8_0_scalar *l; - const rustsecp256k1zkp_v0_8_0_scalar *r; - const rustsecp256k1zkp_v0_8_0_scalar *r_inv; - size_t G_GENS_LEN; /* Figure out initialization syntax so that this can also be const */ - size_t n_len; -} ecmult_x_cb_data; - -static int ecmult_x_cb(rustsecp256k1zkp_v0_8_0_scalar *sc, rustsecp256k1zkp_v0_8_0_ge *pt, size_t idx, void *cbdata) { - ecmult_x_cb_data *data = (ecmult_x_cb_data*) cbdata; - if (idx < data->n_len) { - if (idx % 2 == 0) { - rustsecp256k1zkp_v0_8_0_scalar_mul(sc, &data->n[idx + 1], data->r); - *pt = data->g[idx]; - } else { - rustsecp256k1zkp_v0_8_0_scalar_mul(sc, &data->n[idx - 1], data->r_inv); - *pt = data->g[idx]; - } - } else { - idx -= data->n_len; - if (idx % 2 == 0) { - *sc = data->l[idx + 1]; - *pt = data->g[data->G_GENS_LEN + idx]; - } else { - *sc = data->l[idx - 1]; - *pt = data->g[data->G_GENS_LEN + idx]; - } - } - return 1; -} - -typedef struct ecmult_r_cb_data { - const rustsecp256k1zkp_v0_8_0_scalar *n1; - const rustsecp256k1zkp_v0_8_0_ge *g1; - const rustsecp256k1zkp_v0_8_0_scalar *l1; - size_t G_GENS_LEN; - size_t n_len; -} ecmult_r_cb_data; - -static int ecmult_r_cb(rustsecp256k1zkp_v0_8_0_scalar *sc, rustsecp256k1zkp_v0_8_0_ge *pt, size_t idx, void *cbdata) { - ecmult_r_cb_data *data = (ecmult_r_cb_data*) cbdata; - if (idx < data->n_len) { - *sc = data->n1[2*idx + 1]; - *pt = data->g1[2*idx + 1]; - } else { - idx -= data->n_len; - *sc = data->l1[2*idx + 1]; - *pt = data->g1[data->G_GENS_LEN + 2*idx + 1]; - } - return 1; -} - -/* Recursively compute the norm argument proof satisfying the relation - * _q + = v for some commitment - * C = v*G + + . _q is the weighted inner - * product of x with itself, where the weights are the first n powers of q. - * _q = q*x_1^2 + q^2*x_2^2 + q^3*x_3^2 + ... + q^n*x_n^2. - * The API computes q as square of the r challenge (`r^2`). - * - * The norm argument is not zero knowledge and does not operate on any secret data. - * Thus the following code uses variable time operations while computing the proof. - * This function also modifies the values of n_vec, l_vec, c_vec and g_vec. The caller - * is expected to copy these values if they need to be preserved. - * - * Assumptions: This function is intended to be used in conjunction with the - * some parent protocol. To use this norm protocol in a standalone manner, the user - * should add the commitment, generators and initial public data to the transcript hash. -*/ -static int rustsecp256k1zkp_v0_8_0_bppp_rangeproof_norm_product_prove( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_scratch_space* scratch, - unsigned char* proof, - size_t *proof_len, - rustsecp256k1zkp_v0_8_0_sha256* transcript, /* Transcript hash of the parent protocol */ - const rustsecp256k1zkp_v0_8_0_scalar* r, - rustsecp256k1zkp_v0_8_0_ge* g_vec, - size_t g_vec_len, - rustsecp256k1zkp_v0_8_0_scalar* n_vec, - size_t n_vec_len, - rustsecp256k1zkp_v0_8_0_scalar* l_vec, - size_t l_vec_len, - rustsecp256k1zkp_v0_8_0_scalar* c_vec, - size_t c_vec_len -) { - rustsecp256k1zkp_v0_8_0_scalar q_f, r_f = *r; - size_t proof_idx = 0; - ecmult_x_cb_data x_cb_data; - ecmult_r_cb_data r_cb_data; - size_t g_len = n_vec_len, h_len = l_vec_len; - const size_t G_GENS_LEN = g_len; - size_t log_g_len, log_h_len; - size_t num_rounds; - - VERIFY_CHECK(g_len > 0 && h_len > 0); - log_g_len = rustsecp256k1zkp_v0_8_0_bppp_log2(g_len); - log_h_len = rustsecp256k1zkp_v0_8_0_bppp_log2(h_len); - num_rounds = log_g_len > log_h_len ? log_g_len : log_h_len; - /* Check proof sizes.*/ - VERIFY_CHECK(*proof_len >= 65 * num_rounds + 64); - VERIFY_CHECK(g_vec_len == (n_vec_len + l_vec_len) && l_vec_len == c_vec_len); - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_is_power_of_two(n_vec_len) && rustsecp256k1zkp_v0_8_0_is_power_of_two(c_vec_len)); - - x_cb_data.n = n_vec; - x_cb_data.g = g_vec; - x_cb_data.l = l_vec; - x_cb_data.G_GENS_LEN = G_GENS_LEN; - - r_cb_data.n1 = n_vec; - r_cb_data.g1 = g_vec; - r_cb_data.l1 = l_vec; - r_cb_data.G_GENS_LEN = G_GENS_LEN; - rustsecp256k1zkp_v0_8_0_scalar_sqr(&q_f, &r_f); - - - while (g_len > 1 || h_len > 1) { - size_t i, num_points; - rustsecp256k1zkp_v0_8_0_scalar q_sq, r_inv, c0_l1, c1_l0, x_v, c1_l1, r_v; - rustsecp256k1zkp_v0_8_0_gej rj, xj; - rustsecp256k1zkp_v0_8_0_ge r_ge, x_ge; - rustsecp256k1zkp_v0_8_0_scalar e; - - rustsecp256k1zkp_v0_8_0_scalar_inverse_var(&r_inv, &r_f); - rustsecp256k1zkp_v0_8_0_scalar_sqr(&q_sq, &q_f); - - /* Compute the X commitment X = WIP(r_inv*n0,n1)_q2 * g + r + */ - rustsecp256k1zkp_v0_8_0_scalar_inner_product(&c0_l1, c_vec, 0, l_vec, 1, 2, h_len/2); - rustsecp256k1zkp_v0_8_0_scalar_inner_product(&c1_l0, c_vec, 1, l_vec, 0, 2, h_len/2); - rustsecp256k1zkp_v0_8_0_weighted_scalar_inner_product(&x_v, n_vec, 0, n_vec, 1, 2, g_len/2, &q_sq); - rustsecp256k1zkp_v0_8_0_scalar_mul(&x_v, &x_v, &r_inv); - rustsecp256k1zkp_v0_8_0_scalar_add(&x_v, &x_v, &x_v); - rustsecp256k1zkp_v0_8_0_scalar_add(&x_v, &x_v, &c0_l1); - rustsecp256k1zkp_v0_8_0_scalar_add(&x_v, &x_v, &c1_l0); - - x_cb_data.r = &r_f; - x_cb_data.r_inv = &r_inv; - x_cb_data.n_len = g_len >= 2 ? g_len : 0; - num_points = x_cb_data.n_len + (h_len >= 2 ? h_len : 0); - - if (!rustsecp256k1zkp_v0_8_0_ecmult_multi_var(&ctx->error_callback, scratch, &xj, &x_v, ecmult_x_cb, (void*)&x_cb_data, num_points)) { - return 0; - } - - rustsecp256k1zkp_v0_8_0_weighted_scalar_inner_product(&r_v, n_vec, 1, n_vec, 1, 2, g_len/2, &q_sq); - rustsecp256k1zkp_v0_8_0_scalar_inner_product(&c1_l1, c_vec, 1, l_vec, 1, 2, h_len/2); - rustsecp256k1zkp_v0_8_0_scalar_add(&r_v, &r_v, &c1_l1); - - r_cb_data.n_len = g_len/2; - num_points = r_cb_data.n_len + h_len/2; - if (!rustsecp256k1zkp_v0_8_0_ecmult_multi_var(&ctx->error_callback, scratch, &rj, &r_v, ecmult_r_cb, (void*)&r_cb_data, num_points)) { - return 0; - } - - /* We only fail here because we cannot serialize points at infinity. */ - if (rustsecp256k1zkp_v0_8_0_gej_is_infinity(&xj) || rustsecp256k1zkp_v0_8_0_gej_is_infinity(&rj)) { - return 0; - } - - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&x_ge, &xj); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&x_ge.x); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&x_ge.y); - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&r_ge, &rj); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&r_ge.x); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&r_ge.y); - rustsecp256k1zkp_v0_8_0_bppp_serialize_points(&proof[proof_idx], &x_ge, &r_ge); - proof_idx += 65; - - /* Obtain challenge e for the the next round */ - rustsecp256k1zkp_v0_8_0_sha256_write(transcript, &proof[proof_idx - 65], 65); - rustsecp256k1zkp_v0_8_0_bppp_challenge_scalar(&e, transcript, 0); - - if (g_len > 1) { - for (i = 0; i < g_len; i = i + 2) { - rustsecp256k1zkp_v0_8_0_scalar nl, nr; - rustsecp256k1zkp_v0_8_0_gej gl, gr; - rustsecp256k1zkp_v0_8_0_scalar_mul(&nl, &n_vec[i], &r_inv); - rustsecp256k1zkp_v0_8_0_scalar_mul(&nr, &n_vec[i + 1], &e); - rustsecp256k1zkp_v0_8_0_scalar_add(&n_vec[i/2], &nl, &nr); - - rustsecp256k1zkp_v0_8_0_gej_set_ge(&gl, &g_vec[i]); - rustsecp256k1zkp_v0_8_0_ecmult(&gl, &gl, &r_f, NULL); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&gr, &g_vec[i + 1]); - rustsecp256k1zkp_v0_8_0_ecmult(&gr, &gr, &e, NULL); - rustsecp256k1zkp_v0_8_0_gej_add_var(&gl, &gl, &gr, NULL); - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&g_vec[i/2], &gl); - } - } - - if (h_len > 1) { - for (i = 0; i < h_len; i = i + 2) { - rustsecp256k1zkp_v0_8_0_scalar temp1; - rustsecp256k1zkp_v0_8_0_gej grj; - rustsecp256k1zkp_v0_8_0_scalar_mul(&temp1, &c_vec[i + 1], &e); - rustsecp256k1zkp_v0_8_0_scalar_add(&c_vec[i/2], &c_vec[i], &temp1); - - rustsecp256k1zkp_v0_8_0_scalar_mul(&temp1, &l_vec[i + 1], &e); - rustsecp256k1zkp_v0_8_0_scalar_add(&l_vec[i/2], &l_vec[i], &temp1); - - rustsecp256k1zkp_v0_8_0_gej_set_ge(&grj, &g_vec[G_GENS_LEN + i + 1]); - rustsecp256k1zkp_v0_8_0_ecmult(&grj, &grj, &e, NULL); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&grj, &grj, &g_vec[G_GENS_LEN + i], NULL); - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&g_vec[G_GENS_LEN + i/2], &grj); - } - } - g_len = g_len / 2; - h_len = h_len / 2; - r_f = q_f; - q_f = q_sq; - } - - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&proof[proof_idx], &n_vec[0]); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&proof[proof_idx + 32], &l_vec[0]); - proof_idx += 64; - *proof_len = proof_idx; - return 1; -} - -typedef struct ec_mult_verify_cb_data1 { - const unsigned char *proof; - const rustsecp256k1zkp_v0_8_0_ge *commit; - const rustsecp256k1zkp_v0_8_0_scalar *challenges; -} ec_mult_verify_cb_data1; - -static int ec_mult_verify_cb1(rustsecp256k1zkp_v0_8_0_scalar *sc, rustsecp256k1zkp_v0_8_0_ge *pt, size_t idx, void *cbdata) { - ec_mult_verify_cb_data1 *data = (ec_mult_verify_cb_data1*) cbdata; - if (idx == 0) { - *pt = *data->commit; - rustsecp256k1zkp_v0_8_0_scalar_set_int(sc, 1); - return 1; - } - idx -= 1; - if (idx % 2 == 0) { - unsigned char pk_buf[33]; - idx /= 2; - *sc = data->challenges[idx]; - pk_buf[0] = 2 | (data->proof[65*idx] >> 1); - memcpy(&pk_buf[1], &data->proof[65*idx + 1], 32); - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(pt, pk_buf, sizeof(pk_buf))) { - return 0; - } - } else { - unsigned char pk_buf[33]; - rustsecp256k1zkp_v0_8_0_scalar neg_one; - idx /= 2; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&neg_one, 1); - rustsecp256k1zkp_v0_8_0_scalar_negate(&neg_one, &neg_one); - *sc = data->challenges[idx]; - rustsecp256k1zkp_v0_8_0_scalar_sqr(sc, sc); - rustsecp256k1zkp_v0_8_0_scalar_add(sc, sc, &neg_one); - pk_buf[0] = 2 | data->proof[65*idx]; - memcpy(&pk_buf[1], &data->proof[65*idx + 33], 32); - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(pt, pk_buf, sizeof(pk_buf))) { - return 0; - } - } - return 1; -} - -typedef struct ec_mult_verify_cb_data2 { - const rustsecp256k1zkp_v0_8_0_scalar *s_g; - const rustsecp256k1zkp_v0_8_0_scalar *s_h; - const rustsecp256k1zkp_v0_8_0_ge *g_vec; - size_t g_vec_len; -} ec_mult_verify_cb_data2; - -static int ec_mult_verify_cb2(rustsecp256k1zkp_v0_8_0_scalar *sc, rustsecp256k1zkp_v0_8_0_ge *pt, size_t idx, void *cbdata) { - ec_mult_verify_cb_data2 *data = (ec_mult_verify_cb_data2*) cbdata; - if (idx < data->g_vec_len) { - *sc = data->s_g[idx]; - } else { - *sc = data->s_h[idx - data->g_vec_len]; - } - *pt = data->g_vec[idx]; - return 1; -} - -/* Verify the proof. This function modifies the generators, c_vec and the challenge r. The - caller should make sure to back them up if they need to be reused. -*/ -static int rustsecp256k1zkp_v0_8_0_bppp_rangeproof_norm_product_verify( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_scratch_space* scratch, - const unsigned char* proof, - size_t proof_len, - rustsecp256k1zkp_v0_8_0_sha256* transcript, - const rustsecp256k1zkp_v0_8_0_scalar* r, - const rustsecp256k1zkp_v0_8_0_bppp_generators* g_vec, - size_t g_len, - const rustsecp256k1zkp_v0_8_0_scalar* c_vec, - size_t c_vec_len, - const rustsecp256k1zkp_v0_8_0_ge* commit -) { - rustsecp256k1zkp_v0_8_0_scalar r_f, q_f, v, n, l, r_inv, h_c; - rustsecp256k1zkp_v0_8_0_scalar *es, *s_g, *s_h, *r_inv_pows; - rustsecp256k1zkp_v0_8_0_gej res1, res2; - size_t i = 0, scratch_checkpoint; - int overflow; - size_t log_g_len, log_h_len; - size_t n_rounds; - size_t h_len = c_vec_len; - - if (g_len == 0 || c_vec_len == 0) { - return 0; - } - log_g_len = rustsecp256k1zkp_v0_8_0_bppp_log2(g_len); - log_h_len = rustsecp256k1zkp_v0_8_0_bppp_log2(c_vec_len); - n_rounds = log_g_len > log_h_len ? log_g_len : log_h_len; - - if (g_vec->n != (h_len + g_len) || (proof_len != 65 * n_rounds + 64)) { - return 0; - } - - if (!rustsecp256k1zkp_v0_8_0_is_power_of_two(g_len) || !rustsecp256k1zkp_v0_8_0_is_power_of_two(h_len)) { - return 0; - } - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&n, &proof[n_rounds*65], &overflow); /* n */ - if (overflow) return 0; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&l, &proof[n_rounds*65 + 32], &overflow); /* l */ - if (overflow) return 0; - if (rustsecp256k1zkp_v0_8_0_scalar_is_zero(r)) return 0; - - /* Collect the challenges in a new vector */ - scratch_checkpoint = rustsecp256k1zkp_v0_8_0_scratch_checkpoint(&ctx->error_callback, scratch); - es = (rustsecp256k1zkp_v0_8_0_scalar*)rustsecp256k1zkp_v0_8_0_scratch_alloc(&ctx->error_callback, scratch, n_rounds * sizeof(rustsecp256k1zkp_v0_8_0_scalar)); - s_g = (rustsecp256k1zkp_v0_8_0_scalar*)rustsecp256k1zkp_v0_8_0_scratch_alloc(&ctx->error_callback, scratch, g_len * sizeof(rustsecp256k1zkp_v0_8_0_scalar)); - s_h = (rustsecp256k1zkp_v0_8_0_scalar*)rustsecp256k1zkp_v0_8_0_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(rustsecp256k1zkp_v0_8_0_scalar)); - r_inv_pows = (rustsecp256k1zkp_v0_8_0_scalar*)rustsecp256k1zkp_v0_8_0_scratch_alloc(&ctx->error_callback, scratch, log_g_len * sizeof(rustsecp256k1zkp_v0_8_0_scalar)); - if (es == NULL || s_g == NULL || s_h == NULL || r_inv_pows == NULL) { - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); - return 0; - } - - /* Compute powers of r_inv. Later used in g_factor computations*/ - rustsecp256k1zkp_v0_8_0_scalar_inverse_var(&r_inv, r); - rustsecp256k1zkp_v0_8_0_bppp_powers_of_r(r_inv_pows, &r_inv, log_g_len); - - /* Compute r_f = r^(2^log_g_len) */ - r_f = *r; - for (i = 0; i < log_g_len; i++) { - rustsecp256k1zkp_v0_8_0_scalar_sqr(&r_f, &r_f); - } - - for (i = 0; i < n_rounds; i++) { - rustsecp256k1zkp_v0_8_0_scalar e; - rustsecp256k1zkp_v0_8_0_sha256_write(transcript, &proof[i * 65], 65); - rustsecp256k1zkp_v0_8_0_bppp_challenge_scalar(&e, transcript, 0); - es[i] = e; - } - /* s_g[0] = n * \prod_{j=0}^{log_g_len - 1} r^(2^j) - * = n * r^(2^log_g_len - 1) - * = n * r_f * r_inv */ - rustsecp256k1zkp_v0_8_0_scalar_mul(&s_g[0], &n, &r_f); - rustsecp256k1zkp_v0_8_0_scalar_mul(&s_g[0], &s_g[0], &r_inv); - for (i = 1; i < g_len; i++) { - size_t log_i = rustsecp256k1zkp_v0_8_0_bppp_log2(i); - size_t nearest_pow_of_two = (size_t)1 << log_i; - /* This combines the two multiplications of challenges and r_invs in a - * single loop. - * s_g[i] = s_g[i - nearest_pow_of_two] - * * e[log_i] * r_inv^(2^log_i) */ - rustsecp256k1zkp_v0_8_0_scalar_mul(&s_g[i], &s_g[i - nearest_pow_of_two], &es[log_i]); - rustsecp256k1zkp_v0_8_0_scalar_mul(&s_g[i], &s_g[i], &r_inv_pows[log_i]); - } - s_h[0] = l; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&h_c, 0); - for (i = 1; i < h_len; i++) { - size_t log_i = rustsecp256k1zkp_v0_8_0_bppp_log2(i); - size_t nearest_pow_of_two = (size_t)1 << log_i; - rustsecp256k1zkp_v0_8_0_scalar_mul(&s_h[i], &s_h[i - nearest_pow_of_two], &es[log_i]); - } - rustsecp256k1zkp_v0_8_0_scalar_inner_product(&h_c, c_vec, 0 /* a_offset */ , s_h, 0 /* b_offset */, 1 /* step */, h_len); - /* Compute v = n*n*q_f + l*h_c where q_f = r_f^2 */ - rustsecp256k1zkp_v0_8_0_scalar_sqr(&q_f, &r_f); - rustsecp256k1zkp_v0_8_0_scalar_mul(&v, &n, &n); - rustsecp256k1zkp_v0_8_0_scalar_mul(&v, &v, &q_f); - rustsecp256k1zkp_v0_8_0_scalar_add(&v, &v, &h_c); - - { - ec_mult_verify_cb_data1 data; - data.proof = proof; - data.commit = commit; - data.challenges = es; - - if (!rustsecp256k1zkp_v0_8_0_ecmult_multi_var(&ctx->error_callback, scratch, &res1, NULL, ec_mult_verify_cb1, &data, 2*n_rounds + 1)) { - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); - return 0; - } - } - { - ec_mult_verify_cb_data2 data; - data.g_vec = g_vec->gens; - data.g_vec_len = g_len; - data.s_g = s_g; - data.s_h = s_h; - - if (!rustsecp256k1zkp_v0_8_0_ecmult_multi_var(&ctx->error_callback, scratch, &res2, &v, ec_mult_verify_cb2, &data, g_len + h_len)) { - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); - return 0; - } - } - - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); - - /* res1 and res2 should be equal. Could not find a simpler way to compare them */ - rustsecp256k1zkp_v0_8_0_gej_neg(&res1, &res1); - rustsecp256k1zkp_v0_8_0_gej_add_var(&res1, &res1, &res2, NULL); - return rustsecp256k1zkp_v0_8_0_gej_is_infinity(&res1); -} -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/bppp_transcript_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/bppp_transcript_impl.h deleted file mode 100644 index f277f848..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/bppp_transcript_impl.h +++ /dev/null @@ -1,40 +0,0 @@ -/********************************************************************** - * Copyright (c) 2022 Sanket Kanjalkar * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ -#ifndef _SECP256K1_MODULE_BPPP_PP_TRANSCRIPT_IMPL_ -#define _SECP256K1_MODULE_BPPP_PP_TRANSCRIPT_IMPL_ - -#include "group.h" -#include "scalar.h" -#include "bppp_util.h" - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("Bulletproofs_pp/v0/commitment")||SHA256("Bulletproofs_pp/v0/commitment"). - */ -static void rustsecp256k1zkp_v0_8_0_bppp_sha256_tagged_commitment_init(rustsecp256k1zkp_v0_8_0_sha256 *sha) { - rustsecp256k1zkp_v0_8_0_sha256_initialize(sha); - sha->s[0] = 0x52fc8185ul; - sha->s[1] = 0x0e7debf0ul; - sha->s[2] = 0xb0967270ul; - sha->s[3] = 0x6f5abfe1ul; - sha->s[4] = 0x822bdec0ul; - sha->s[5] = 0x36db8beful; - sha->s[6] = 0x03d9e1f1ul; - sha->s[7] = 0x8a5cef6ful; - - sha->bytes = 64; -} - -/* Obtain a challenge scalar from the current transcript.*/ -static void rustsecp256k1zkp_v0_8_0_bppp_challenge_scalar(rustsecp256k1zkp_v0_8_0_scalar* ch, const rustsecp256k1zkp_v0_8_0_sha256 *transcript, uint64_t idx) { - unsigned char buf[32]; - rustsecp256k1zkp_v0_8_0_sha256 sha = *transcript; - rustsecp256k1zkp_v0_8_0_bppp_le64(buf, idx); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, buf, 8); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, buf); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(ch, buf, NULL); -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/bppp_util.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/bppp_util.h deleted file mode 100644 index 40851331..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/bppp_util.h +++ /dev/null @@ -1,57 +0,0 @@ -/********************************************************************** - * Copyright (c) 2020 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_MODULE_BPPP_UTIL_ -#define _SECP256K1_MODULE_BPPP_UTIL_ - -#include "field.h" -#include "group.h" -#include "hash.h" -#include "eckey.h" - -/* Outputs a pair of points, amortizing the parity byte between them - * Assumes both points' coordinates have been normalized. - */ -static void rustsecp256k1zkp_v0_8_0_bppp_serialize_points(unsigned char *output, const rustsecp256k1zkp_v0_8_0_ge *lpt, const rustsecp256k1zkp_v0_8_0_ge *rpt) { - output[0] = (rustsecp256k1zkp_v0_8_0_fe_is_odd(&lpt->y) << 1) + rustsecp256k1zkp_v0_8_0_fe_is_odd(&rpt->y); - rustsecp256k1zkp_v0_8_0_fe_get_b32(&output[1], &lpt->x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(&output[33], &rpt->x); -} - -/* Outputs a serialized point in compressed form. Returns 0 at point at infinity. -*/ -static int rustsecp256k1zkp_v0_8_0_bppp_serialize_pt(unsigned char *output, rustsecp256k1zkp_v0_8_0_ge *lpt) { - size_t size; - return rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(lpt, output, &size, 1 /*compressed*/); -} - -/* little-endian encodes a uint64 */ -static void rustsecp256k1zkp_v0_8_0_bppp_le64(unsigned char *output, const uint64_t n) { - output[0] = n; - output[1] = n >> 8; - output[2] = n >> 16; - output[3] = n >> 24; - output[4] = n >> 32; - output[5] = n >> 40; - output[6] = n >> 48; - output[7] = n >> 56; -} - -/* Check if n is power of two*/ -static int rustsecp256k1zkp_v0_8_0_is_power_of_two(size_t n) { - return n > 0 && (n & (n - 1)) == 0; -} - -/* Compute the log2 of n. n must NOT be 0. If n is not a power of two, it - * returns the largest `k` such that 2^k <= n. Assumes 0 < n < 2^64. In - * Bulletproofs, this is bounded by len of input vectors which can be safely - * assumed to be less than 2^64. -*/ -static size_t rustsecp256k1zkp_v0_8_0_bppp_log2(size_t n) { - return 64 - 1 - rustsecp256k1zkp_v0_8_0_clz64_var((uint64_t)n); -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/main.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/main.h deleted file mode 100644 index 4bef634d..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/main.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef SECP256K1_MODULE_BPPP_MAIN_H -#define SECP256K1_MODULE_BPPP_MAIN_H - -/* this type must be completed before any of the modules/bppp includes */ -struct rustsecp256k1zkp_v0_8_0_bppp_generators { - size_t n; - /* n total generators; includes both G_i and H_i */ - /* For BP++, the generators are G_i from [0..(n - 8)] and the last 8 values - are generators are for H_i */ - rustsecp256k1zkp_v0_8_0_ge* gens; -}; - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/main_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/main_impl.h deleted file mode 100644 index 441c5a82..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/main_impl.h +++ /dev/null @@ -1,115 +0,0 @@ -/********************************************************************** - * Copyright (c) 2020 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_MODULE_BPPP_MAIN_ -#define _SECP256K1_MODULE_BPPP_MAIN_ - -#include "include/secp256k1_bppp.h" -#include "include/secp256k1_generator.h" -#include "modules/generator/main_impl.h" /* for generator_{load, save} */ -#include "hash.h" -#include "util.h" -#include "modules/bppp/main.h" -#include "modules/bppp/bppp_norm_product_impl.h" - -rustsecp256k1zkp_v0_8_0_bppp_generators *rustsecp256k1zkp_v0_8_0_bppp_generators_create(const rustsecp256k1zkp_v0_8_0_context *ctx, size_t n) { - rustsecp256k1zkp_v0_8_0_bppp_generators *ret; - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256 rng; - unsigned char seed[64]; - size_t i; - - VERIFY_CHECK(ctx != NULL); - - ret = (rustsecp256k1zkp_v0_8_0_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret)); - if (ret == NULL) { - return NULL; - } - ret->gens = (rustsecp256k1zkp_v0_8_0_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens)); - if (ret->gens == NULL) { - free(ret); - return NULL; - } - ret->n = n; - - rustsecp256k1zkp_v0_8_0_fe_get_b32(&seed[0], &rustsecp256k1zkp_v0_8_0_ge_const_g.x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(&seed[32], &rustsecp256k1zkp_v0_8_0_ge_const_g.y); - - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_initialize(&rng, seed, 64); - for (i = 0; i < n; i++) { - rustsecp256k1zkp_v0_8_0_generator gen; - unsigned char tmp[32] = { 0 }; - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(&rng, tmp, 32); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate(ctx, &gen, tmp)); - rustsecp256k1zkp_v0_8_0_generator_load(&ret->gens[i], &gen); - } - - return ret; -} - -rustsecp256k1zkp_v0_8_0_bppp_generators* rustsecp256k1zkp_v0_8_0_bppp_generators_parse(const rustsecp256k1zkp_v0_8_0_context* ctx, const unsigned char* data, size_t data_len) { - size_t n = data_len / 33; - rustsecp256k1zkp_v0_8_0_bppp_generators* ret; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(data != NULL); - - if (data_len % 33 != 0) { - return NULL; - } - - ret = (rustsecp256k1zkp_v0_8_0_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret)); - if (ret == NULL) { - return NULL; - } - ret->n = n; - ret->gens = (rustsecp256k1zkp_v0_8_0_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens)); - if (ret->gens == NULL) { - free(ret); - return NULL; - } - - while (n--) { - rustsecp256k1zkp_v0_8_0_generator gen; - if (!rustsecp256k1zkp_v0_8_0_generator_parse(ctx, &gen, &data[33 * n])) { - free(ret->gens); - free(ret); - return NULL; - } - rustsecp256k1zkp_v0_8_0_generator_load(&ret->gens[n], &gen); - } - return ret; -} - -int rustsecp256k1zkp_v0_8_0_bppp_generators_serialize(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_bppp_generators* gens, unsigned char* data, size_t *data_len) { - size_t i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(gens != NULL); - ARG_CHECK(data != NULL); - ARG_CHECK(data_len != NULL); - ARG_CHECK(*data_len >= 33 * gens->n); - - memset(data, 0, *data_len); - for (i = 0; i < gens->n; i++) { - rustsecp256k1zkp_v0_8_0_generator gen; - rustsecp256k1zkp_v0_8_0_generator_save(&gen, &gens->gens[i]); - rustsecp256k1zkp_v0_8_0_generator_serialize(ctx, &data[33 * i], &gen); - } - - *data_len = 33 * gens->n; - return 1; -} - -void rustsecp256k1zkp_v0_8_0_bppp_generators_destroy(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_bppp_generators *gens) { - VERIFY_CHECK(ctx != NULL); - (void) ctx; - if (gens != NULL) { - free(gens->gens); - free(gens); - } -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/test_vectors/verify.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/test_vectors/verify.h deleted file mode 100644 index 1213dc7a..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/test_vectors/verify.h +++ /dev/null @@ -1,65 +0,0 @@ -static const unsigned char verify_vector_gens[264] = { 0x03, 0xAF, 0x2C, 0x40, 0xAD, 0x03, 0xCD, 0xC5, 0x76, 0x8C, 0x07, 0x1E, 0x58, 0xD6, 0x8C, 0x73, 0x45, 0xBA, 0xEB, 0xB5, 0x3F, 0x40, 0xFA, 0x8B, 0xBF, 0x73, 0x6E, 0x7B, 0x4A, 0x54, 0x06, 0xED, 0x32, 0x03, 0xCC, 0x11, 0x19, 0x22, 0x2C, 0xA1, 0x0A, 0x45, 0x23, 0xAF, 0x9B, 0x40, 0x0D, 0xA4, 0x5E, 0x06, 0x24, 0xF4, 0x5F, 0x07, 0x89, 0x88, 0xCD, 0x71, 0xAE, 0x77, 0xC1, 0xF5, 0x87, 0x4E, 0xFC, 0xA5, 0x03, 0xDE, 0x61, 0xB1, 0x8F, 0x2C, 0xAC, 0x18, 0xF5, 0xE4, 0x06, 0x8F, 0x65, 0x55, 0xA1, 0x30, 0x5E, 0xF5, 0xF4, 0x84, 0xED, 0x6B, 0xDD, 0xC2, 0xCC, 0xE8, 0x51, 0x38, 0xB8, 0xA5, 0x4C, 0x43, 0xBD, 0x02, 0xA5, 0xF9, 0x8C, 0x1F, 0x82, 0x2D, 0xC6, 0xF3, 0x0F, 0x53, 0xDB, 0x74, 0x77, 0xC7, 0x91, 0x04, 0xB0, 0xB1, 0xA6, 0x17, 0xB2, 0x91, 0xF4, 0x8B, 0x93, 0x3E, 0xBB, 0x73, 0x15, 0x3E, 0x5A, 0xD1, 0x02, 0x44, 0xF5, 0xC6, 0x4E, 0x77, 0x60, 0x81, 0x83, 0xFF, 0xC2, 0x8E, 0x06, 0xFE, 0x67, 0x0C, 0x9A, 0x4B, 0xF2, 0x34, 0xB9, 0xEA, 0xE9, 0x37, 0xDA, 0x30, 0xE2, 0x32, 0x27, 0xF3, 0x88, 0x5F, 0x2A, 0x02, 0x1D, 0x49, 0x5D, 0x04, 0xED, 0x61, 0x95, 0x37, 0xDD, 0x95, 0xB1, 0x4F, 0x64, 0x0E, 0x1E, 0xFB, 0x47, 0x9F, 0xA7, 0xD7, 0xE0, 0x7A, 0xB1, 0x02, 0x81, 0x95, 0xD1, 0xA5, 0x7E, 0xB2, 0x74, 0x8F, 0x03, 0x26, 0xA5, 0xEC, 0xE9, 0x71, 0x46, 0x37, 0xAC, 0x3D, 0x74, 0x84, 0x26, 0xCB, 0x7C, 0xE8, 0xFE, 0x4E, 0xB0, 0x6D, 0x70, 0x3D, 0x00, 0x10, 0x1A, 0x3A, 0x5B, 0xB8, 0xAA, 0x29, 0x59, 0x93, 0x15, 0x03, 0xE1, 0xA5, 0x39, 0x44, 0x75, 0x16, 0x28, 0x5F, 0xBA, 0x69, 0xA2, 0x4A, 0x2A, 0xC3, 0x5B, 0x63, 0x1F, 0x40, 0x10, 0x36, 0xF9, 0x4C, 0xD2, 0x76, 0x0F, 0xCF, 0x7F, 0x50, 0x30, 0x6E, 0x2B, 0x1D }; -static const unsigned char verify_vector_0_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 }; -static const size_t verify_vector_0_n_vec_len = 1; -static const unsigned char verify_vector_0_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; -static rustsecp256k1zkp_v0_8_0_scalar verify_vector_0_c_vec[1]; -static const unsigned char verify_vector_0_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A }; -static const unsigned char verify_vector_0_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E }; -static const int verify_vector_0_result = 1; -static const unsigned char verify_vector_1_commit33[33] = { 0x02, 0x6C, 0x09, 0xD7, 0x06, 0x2D, 0x1C, 0x07, 0x0A, 0x64, 0x34, 0x82, 0xF6, 0x46, 0x03, 0xEB, 0x24, 0x3E, 0x54, 0x0F, 0xDA, 0xAF, 0x3A, 0x69, 0x5F, 0x86, 0xB6, 0xD2, 0xC2, 0x06, 0xE9, 0x49, 0xC7 }; -static const size_t verify_vector_1_n_vec_len = 1; -static const unsigned char verify_vector_1_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; -static rustsecp256k1zkp_v0_8_0_scalar verify_vector_1_c_vec[1]; -static const unsigned char verify_vector_1_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A }; -static const unsigned char verify_vector_1_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E }; -static const int verify_vector_1_result = 0; -static const unsigned char verify_vector_2_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 }; -static const size_t verify_vector_2_n_vec_len = 1; -static const unsigned char verify_vector_2_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; -static rustsecp256k1zkp_v0_8_0_scalar verify_vector_2_c_vec[1]; -static const unsigned char verify_vector_2_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A }; -static const unsigned char verify_vector_2_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }; -static const int verify_vector_2_result = 0; -static const unsigned char verify_vector_3_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 }; -static const size_t verify_vector_3_n_vec_len = 1; -static const unsigned char verify_vector_3_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; -static rustsecp256k1zkp_v0_8_0_scalar verify_vector_3_c_vec[1]; -static const unsigned char verify_vector_3_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A }; -static const unsigned char verify_vector_3_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }; -static const int verify_vector_3_result = 0; -static const unsigned char verify_vector_4_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 }; -static const size_t verify_vector_4_n_vec_len = 1; -static const unsigned char verify_vector_4_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; -static rustsecp256k1zkp_v0_8_0_scalar verify_vector_4_c_vec[1]; -static const unsigned char verify_vector_4_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A }; -static const unsigned char verify_vector_4_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41 }; -static const int verify_vector_4_result = 0; -static const unsigned char verify_vector_5_commit33[33] = { 0x03, 0x83, 0x6A, 0xD4, 0x2D, 0xD2, 0x02, 0x49, 0xC8, 0x6E, 0x53, 0x22, 0x53, 0x24, 0xDA, 0x52, 0x08, 0xC0, 0x62, 0x4C, 0xCB, 0xB3, 0x13, 0xD7, 0x14, 0x59, 0x68, 0x47, 0x56, 0x00, 0xC0, 0x8D, 0xBA }; -static const size_t verify_vector_5_n_vec_len = 2; -static const unsigned char verify_vector_5_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; -static rustsecp256k1zkp_v0_8_0_scalar verify_vector_5_c_vec[1]; -static const unsigned char verify_vector_5_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x36 }; -static const unsigned char verify_vector_5_proof[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x4C, 0xB9, 0xD4, 0x34, 0xA2, 0xD6, 0xD5, 0x4C, 0x0F, 0x2E, 0x2C, 0xE3, 0x82, 0x17, 0x48, 0x63, 0xE0, 0xAE, 0x6B, 0xD7, 0x64, 0x9D, 0x43, 0x2B, 0x6E, 0x6E, 0x1C, 0x62, 0x55, 0x4B, 0xC5, 0x73, 0x3D, 0x74, 0x7B, 0x78, 0x43, 0xF4, 0x8B, 0x7C, 0x84, 0x10, 0x00, 0x8B, 0x12, 0xAF, 0xA4, 0xF1, 0xF4, 0x01, 0x96, 0x21, 0x8B, 0xE9, 0x05, 0x01, 0xF8, 0x23, 0x7A, 0x8F, 0x66, 0xC9, 0xDE, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E }; -static const int verify_vector_5_result = 0; -static const unsigned char verify_vector_6_commit33[33] = { 0x03, 0xCF, 0x7F, 0x08, 0xF5, 0x8A, 0x06, 0x74, 0x5C, 0xDB, 0xCE, 0xC6, 0x51, 0xF3, 0xE5, 0xE4, 0xDC, 0xAD, 0xF4, 0x40, 0x3C, 0xFA, 0xE6, 0x78, 0xBE, 0x49, 0x2D, 0x90, 0xC8, 0xD0, 0x16, 0x3D, 0x78 }; -static const size_t verify_vector_6_n_vec_len = 2; -static const unsigned char verify_vector_6_c_vec32[4][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x30 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D } }; -static rustsecp256k1zkp_v0_8_0_scalar verify_vector_6_c_vec[4]; -static const unsigned char verify_vector_6_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A }; -static const unsigned char verify_vector_6_proof[] = { 0x00, 0xD2, 0xEC, 0xE2, 0x53, 0x97, 0x28, 0x68, 0x22, 0x59, 0x34, 0xEF, 0xE4, 0x7B, 0x87, 0x4D, 0xE9, 0x57, 0xD5, 0xB7, 0xC7, 0x72, 0xF4, 0xC9, 0xEA, 0x66, 0x14, 0x59, 0xE1, 0xA9, 0xD5, 0xB2, 0x10, 0xDF, 0xE2, 0xFF, 0xF5, 0xA4, 0x38, 0x6B, 0xFE, 0x36, 0x89, 0xE4, 0x9D, 0x90, 0x9F, 0x71, 0x19, 0xE6, 0xA3, 0x1E, 0xAA, 0xAA, 0x4E, 0xFE, 0xC2, 0xD3, 0x37, 0xBB, 0xDE, 0xDB, 0x46, 0x43, 0xC2, 0x01, 0x42, 0x5F, 0xFC, 0xC6, 0x25, 0xA0, 0xB4, 0xF0, 0x76, 0x99, 0xF4, 0x7C, 0xE9, 0x83, 0x82, 0xED, 0x7C, 0x95, 0xBA, 0xD0, 0xE6, 0x5B, 0x88, 0xFD, 0x38, 0xEA, 0x23, 0x54, 0xD4, 0xBD, 0xD4, 0x37, 0xB8, 0x2B, 0x49, 0xAF, 0x81, 0xFD, 0xBE, 0x88, 0xB2, 0xE5, 0x3F, 0xF4, 0x30, 0x52, 0x00, 0x63, 0x9D, 0xAE, 0x82, 0x44, 0xE9, 0x62, 0x87, 0x2A, 0x23, 0x89, 0x10, 0xE4, 0x9A, 0x64, 0x9F, 0x71, 0xD9, 0x32, 0x57, 0x3B, 0xCB, 0xAC, 0x30, 0xAE, 0x71, 0x61, 0xE9, 0x50, 0x1F, 0xCB, 0x49, 0x9C, 0x52, 0xBA, 0x0C, 0xC4, 0x00, 0x58, 0x73, 0x63, 0xD3, 0x42, 0xDE, 0x42, 0x5E, 0xC5, 0x97, 0xE5, 0xDA, 0x88, 0x76, 0x49, 0x6C, 0x8B, 0x92, 0x99, 0xEE, 0xD0, 0xA9, 0xEB, 0x6E, 0xCA, 0xE1, 0x93, 0x81, 0x56, 0x2E, 0xCA, 0xF3, 0x8E, 0xF0, 0x04, 0xD2, 0x96, 0xD8, 0xDB, 0xEE, 0xEE, 0x1C, 0x44 }; -static const int verify_vector_6_result = 1; -static const unsigned char verify_vector_7_commit33[33] = { 0x02, 0x7A, 0xAA, 0xB2, 0x7E, 0xA5, 0x5B, 0x77, 0x08, 0xE5, 0x43, 0xB6, 0x22, 0x7F, 0xC9, 0xAC, 0x53, 0x10, 0x32, 0x61, 0x7B, 0x7D, 0xAC, 0xB1, 0xB6, 0xF6, 0xAC, 0xDE, 0x63, 0x79, 0x82, 0x9C, 0x24 }; -static const size_t verify_vector_7_n_vec_len = 4; -static const unsigned char verify_vector_7_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; -static rustsecp256k1zkp_v0_8_0_scalar verify_vector_7_c_vec[1]; -static const unsigned char verify_vector_7_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 }; -static const unsigned char verify_vector_7_proof[] = { 0x00, 0xBC, 0x4C, 0x42, 0x67, 0x71, 0x69, 0x52, 0x6A, 0x65, 0xFE, 0xA0, 0xCB, 0x3F, 0x58, 0x8B, 0x48, 0x48, 0x6E, 0x59, 0xFC, 0x55, 0x51, 0x10, 0xB9, 0xBF, 0x6A, 0x7D, 0xBF, 0x32, 0x34, 0x4E, 0x7D, 0xBA, 0xD5, 0xCB, 0xCC, 0x19, 0xED, 0xAA, 0x9F, 0x8D, 0x93, 0x26, 0x5E, 0x3F, 0x3E, 0xAA, 0xDF, 0x0B, 0x1C, 0xB3, 0xDC, 0x37, 0xB6, 0xDB, 0xAE, 0x43, 0x63, 0x92, 0xB5, 0xFF, 0x0D, 0x1C, 0x77, 0x02, 0x7E, 0x2B, 0xB8, 0x87, 0x85, 0x81, 0x13, 0x70, 0x1F, 0x03, 0x65, 0x7D, 0xD8, 0x91, 0x83, 0xE5, 0x7E, 0x8B, 0x9E, 0x6F, 0x1C, 0x08, 0x9C, 0x9C, 0x5F, 0xA4, 0x12, 0x5F, 0xD3, 0xEE, 0xE2, 0x74, 0x7A, 0x2C, 0x58, 0x3A, 0x29, 0x4F, 0x64, 0x10, 0xE7, 0x89, 0xBF, 0xB2, 0xE5, 0xD9, 0xD5, 0xC5, 0x62, 0x83, 0x0C, 0xA8, 0xDD, 0x1E, 0x24, 0x6D, 0xD1, 0x58, 0x8D, 0x80, 0x74, 0xF3, 0xD9, 0x3A, 0x68, 0x7B, 0xF5, 0x12, 0xC6, 0xC2, 0x3F, 0x71, 0x47, 0xDF, 0xCF, 0xC8, 0xE2, 0xC4, 0x59, 0xDF, 0x4F, 0xEC, 0x86, 0xE9, 0xF9, 0x31, 0x94, 0x6A, 0x5F, 0xD9, 0x1E, 0x6B, 0x09, 0xCD, 0xCF, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E }; -static const int verify_vector_7_result = 1; -static const unsigned char verify_vector_8_commit33[33] = { 0x02, 0x2D, 0x4F, 0xF9, 0xB7, 0x15, 0x22, 0xBC, 0xB0, 0x8B, 0xF8, 0xBA, 0x31, 0x0A, 0x80, 0x76, 0x7A, 0xE9, 0xA9, 0x83, 0x00, 0xBC, 0x5A, 0x01, 0xCC, 0xE9, 0x00, 0x83, 0x56, 0xEA, 0x77, 0xEB, 0x75 }; -static const size_t verify_vector_8_n_vec_len = 4; -static const unsigned char verify_vector_8_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } }; -static rustsecp256k1zkp_v0_8_0_scalar verify_vector_8_c_vec[1]; -static const unsigned char verify_vector_8_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 }; -static const unsigned char verify_vector_8_proof[] = { 0x00, 0xBC, 0x4C, 0x42, 0x67, 0x71, 0x69, 0x52, 0x6A, 0x65, 0xFE, 0xA0, 0xCB, 0x3F, 0x58, 0x8B, 0x48, 0x48, 0x6E, 0x59, 0xFC, 0x55, 0x51, 0x10, 0xB9, 0xBF, 0x6A, 0x7D, 0xBF, 0x32, 0x34, 0x4E, 0x7D, 0xBA, 0xD5, 0xCB, 0xCC, 0x19, 0xED, 0xAA, 0x9F, 0x8D, 0x93, 0x26, 0x5E, 0x3F, 0x3E, 0xAA, 0xDF, 0x0B, 0x1C, 0xB3, 0xDC, 0x37, 0xB6, 0xDB, 0xAE, 0x43, 0x63, 0x92, 0xB5, 0xFF, 0x0D, 0x1C, 0x77, 0x02, 0x7E, 0x2B, 0xB8, 0x87, 0x85, 0x81, 0x13, 0x70, 0x1F, 0x03, 0x65, 0x7D, 0xD8, 0x91, 0x83, 0xE5, 0x7E, 0x8B, 0x9E, 0x6F, 0x1C, 0x08, 0x9C, 0x9C, 0x5F, 0xA4, 0x12, 0x5F, 0xD3, 0xEE, 0xE2, 0x74, 0x7A, 0x2C, 0x58, 0x3A, 0x29, 0x4F, 0x64, 0x10, 0xE7, 0x89, 0xBF, 0xB2, 0xE5, 0xD9, 0xD5, 0xC5, 0x62, 0x83, 0x0C, 0xA8, 0xDD, 0x1E, 0x24, 0x6D, 0xD1, 0x58, 0x8D, 0x80, 0x74, 0xF3, 0xD9, 0x3A, 0x68, 0x7B, 0xF5, 0x12, 0xC6, 0xC2, 0x3F, 0x71, 0x47, 0xDF, 0xCF, 0xC8, 0xE2, 0xC4, 0x59, 0xDF, 0x4F, 0xEC, 0x86, 0xE9, 0xF9, 0x31, 0x94, 0x6A, 0x5F, 0xD9, 0x1E, 0x6B, 0x09, 0xCD, 0xCF, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E }; -static const int verify_vector_8_result = 0; - diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/tests_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/tests_impl.h deleted file mode 100644 index 30a7a4f1..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/bppp/tests_impl.h +++ /dev/null @@ -1,584 +0,0 @@ -/********************************************************************** - * Copyright (c) 2020 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_MODULE_BPPP_TEST_ -#define _SECP256K1_MODULE_BPPP_TEST_ - -#include - -#include "include/secp256k1_bppp.h" -#include "bppp_norm_product_impl.h" -#include "bppp_util.h" -#include "bppp_transcript_impl.h" -#include "test_vectors/verify.h" - -static void test_bppp_generators_api(void) { - /* The BP generator API requires no precomp */ - rustsecp256k1zkp_v0_8_0_context *none = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); - - rustsecp256k1zkp_v0_8_0_bppp_generators *gens; - rustsecp256k1zkp_v0_8_0_bppp_generators *gens_orig; - unsigned char gens_ser[330]; - size_t len = sizeof(gens_ser); - - int32_t ecount = 0; - - rustsecp256k1zkp_v0_8_0_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - - /* Create */ - gens = rustsecp256k1zkp_v0_8_0_bppp_generators_create(none, 10); - CHECK(gens != NULL && ecount == 0); - gens_orig = gens; /* Preserve for round-trip test */ - - /* Serialize */ - ecount = 0; - CHECK(!rustsecp256k1zkp_v0_8_0_bppp_generators_serialize(none, NULL, gens_ser, &len)); - CHECK(ecount == 1); - CHECK(!rustsecp256k1zkp_v0_8_0_bppp_generators_serialize(none, gens, NULL, &len)); - CHECK(ecount == 2); - CHECK(!rustsecp256k1zkp_v0_8_0_bppp_generators_serialize(none, gens, gens_ser, NULL)); - CHECK(ecount == 3); - len = 0; - CHECK(!rustsecp256k1zkp_v0_8_0_bppp_generators_serialize(none, gens, gens_ser, &len)); - CHECK(ecount == 4); - len = sizeof(gens_ser) - 1; - CHECK(!rustsecp256k1zkp_v0_8_0_bppp_generators_serialize(none, gens, gens_ser, &len)); - CHECK(ecount == 5); - len = sizeof(gens_ser); - { - /* Output buffer can be greater than minimum needed */ - unsigned char gens_ser_tmp[331]; - size_t len_tmp = sizeof(gens_ser_tmp); - CHECK(rustsecp256k1zkp_v0_8_0_bppp_generators_serialize(none, gens, gens_ser_tmp, &len_tmp)); - CHECK(len_tmp == sizeof(gens_ser_tmp) - 1); - CHECK(ecount == 5); - } - - /* Parse */ - CHECK(rustsecp256k1zkp_v0_8_0_bppp_generators_serialize(none, gens, gens_ser, &len)); - ecount = 0; - gens = rustsecp256k1zkp_v0_8_0_bppp_generators_parse(none, NULL, sizeof(gens_ser)); - CHECK(gens == NULL && ecount == 1); - /* Not a multiple of 33 */ - gens = rustsecp256k1zkp_v0_8_0_bppp_generators_parse(none, gens_ser, sizeof(gens_ser) - 1); - CHECK(gens == NULL && ecount == 1); - gens = rustsecp256k1zkp_v0_8_0_bppp_generators_parse(none, gens_ser, sizeof(gens_ser)); - CHECK(gens != NULL && ecount == 1); - /* Not valid generators */ - memset(gens_ser, 1, sizeof(gens_ser)); - CHECK(rustsecp256k1zkp_v0_8_0_bppp_generators_parse(none, gens_ser, sizeof(gens_ser)) == NULL); - CHECK(ecount == 1); - - /* Check that round-trip succeeded */ - CHECK(gens->n == gens_orig->n); - for (len = 0; len < gens->n; len++) { - ge_equals_ge(&gens->gens[len], &gens_orig->gens[len]); - } - - /* Destroy (we allow destroying a NULL context, it's just a noop. like free().) */ - ecount = 0; - rustsecp256k1zkp_v0_8_0_bppp_generators_destroy(none, NULL); - rustsecp256k1zkp_v0_8_0_bppp_generators_destroy(none, gens); - rustsecp256k1zkp_v0_8_0_bppp_generators_destroy(none, gens_orig); - CHECK(ecount == 0); - - rustsecp256k1zkp_v0_8_0_context_destroy(none); -} - -static void test_bppp_generators_fixed(void) { - rustsecp256k1zkp_v0_8_0_bppp_generators *gens = rustsecp256k1zkp_v0_8_0_bppp_generators_create(ctx, 3); - unsigned char gens_ser[330]; - const unsigned char fixed_first_3[99] = { - 0x0b, - 0xb3, 0x4d, 0x5f, 0xa6, 0xb8, 0xf3, 0xd1, 0x38, - 0x49, 0xce, 0x51, 0x91, 0xb7, 0xf6, 0x76, 0x18, - 0xfe, 0x5b, 0xd1, 0x2a, 0x88, 0xb2, 0x0e, 0xac, - 0x33, 0x89, 0x45, 0x66, 0x7f, 0xb3, 0x30, 0x56, - 0x0a, - 0x62, 0x86, 0x15, 0x16, 0x92, 0x42, 0x10, 0x9e, - 0x9e, 0x64, 0xd4, 0xcb, 0x28, 0x81, 0x60, 0x9c, - 0x24, 0xb9, 0x89, 0x51, 0x2a, 0xd9, 0x01, 0xae, - 0xff, 0x75, 0x64, 0x9c, 0x37, 0x5d, 0xbd, 0x79, - 0x0a, - 0xed, 0xe0, 0x6e, 0x07, 0x5e, 0x79, 0xd0, 0xf7, - 0x7b, 0x03, 0x3e, 0xb9, 0xa9, 0x21, 0xa4, 0x5b, - 0x99, 0xf3, 0x9b, 0xee, 0xfe, 0xa0, 0x37, 0xa2, - 0x1f, 0xe9, 0xd7, 0x4f, 0x95, 0x8b, 0x10, 0xe2, - }; - size_t len; - - len = 99; - CHECK(rustsecp256k1zkp_v0_8_0_bppp_generators_serialize(ctx, gens, gens_ser, &len)); - CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0); - - len = sizeof(gens_ser); - CHECK(rustsecp256k1zkp_v0_8_0_bppp_generators_serialize(ctx, gens, gens_ser, &len)); - CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0); - - rustsecp256k1zkp_v0_8_0_bppp_generators_destroy(ctx, gens); -} - -static void test_bppp_tagged_hash(void) { - unsigned char tag_data[29] = "Bulletproofs_pp/v0/commitment"; - rustsecp256k1zkp_v0_8_0_sha256 sha; - rustsecp256k1zkp_v0_8_0_sha256 sha_cached; - unsigned char output[32]; - unsigned char output_cached[32]; - rustsecp256k1zkp_v0_8_0_scalar s; - - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, tag_data, sizeof(tag_data)); - rustsecp256k1zkp_v0_8_0_bppp_sha256_tagged_commitment_init(&sha_cached); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, output); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha_cached, output_cached); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(output, output_cached, 32) == 0); - - { - unsigned char expected[32] = { 0x21, 0x2F, 0xB6, 0x4F, 0x9D, 0x8C, 0x3B, 0xC5, - 0xF6, 0x91, 0x15, 0xEE, 0x74, 0xF5, 0x12, 0x67, - 0x8A, 0x41, 0xC6, 0x85, 0x1A, 0x79, 0x14, 0xFC, - 0x48, 0x15, 0xC7, 0x2D, 0xF8, 0x63, 0x8F, 0x1B }; - rustsecp256k1zkp_v0_8_0_bppp_sha256_tagged_commitment_init(&sha); - rustsecp256k1zkp_v0_8_0_bppp_challenge_scalar(&s, &sha, 0); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(output, &s); - CHECK(memcmp(output, expected, sizeof(output)) == 0); - } - - { - unsigned char tmp[3] = {0, 1, 2}; - unsigned char expected[32] = { 0x8D, 0xAA, 0xB7, 0x7E, 0x3C, 0x6A, 0x9E, 0xEC, - 0x72, 0x7E, 0x3E, 0xB7, 0x10, 0x03, 0xF0, 0xE9, - 0x69, 0x4D, 0xAA, 0x96, 0xCE, 0x98, 0xBB, 0x39, - 0x1C, 0x2F, 0x7C, 0x2E, 0x1C, 0x17, 0x78, 0x6D }; - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, tmp, sizeof(tmp)); - rustsecp256k1zkp_v0_8_0_bppp_challenge_scalar(&s, &sha, 0); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(output, &s); - CHECK(memcmp(output, expected, sizeof(output)) == 0); - } -} - -void test_log_exp(void) { - CHECK(rustsecp256k1zkp_v0_8_0_is_power_of_two(0) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_is_power_of_two(1) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_is_power_of_two(2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_is_power_of_two(64) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_is_power_of_two(63) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_is_power_of_two(256) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_bppp_log2(1) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_bppp_log2(2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_bppp_log2(255) == 7); - CHECK(rustsecp256k1zkp_v0_8_0_bppp_log2(256) == 8); - CHECK(rustsecp256k1zkp_v0_8_0_bppp_log2(257) == 8); -} - -void test_norm_util_helpers(void) { - rustsecp256k1zkp_v0_8_0_scalar a_vec[4], b_vec[4], r_pows[4], res, res2, q, r; - int i; - /* a = {1, 2, 3, 4} b = {5, 6, 7, 8}, q = 4, r = 2 */ - for (i = 0; i < 4; i++) { - rustsecp256k1zkp_v0_8_0_scalar_set_int(&a_vec[i], i + 1); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&b_vec[i], i + 5); - } - rustsecp256k1zkp_v0_8_0_scalar_set_int(&q, 4); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&r, 2); - rustsecp256k1zkp_v0_8_0_scalar_inner_product(&res, a_vec, 0, b_vec, 0, 1, 4); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&res2, 70); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&res2, &res) == 1); - - rustsecp256k1zkp_v0_8_0_scalar_inner_product(&res, a_vec, 0, b_vec, 1, 2, 2); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&res2, 30); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&res2, &res) == 1); - - rustsecp256k1zkp_v0_8_0_scalar_inner_product(&res, a_vec, 1, b_vec, 0, 2, 2); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&res2, 38); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&res2, &res) == 1); - - rustsecp256k1zkp_v0_8_0_scalar_inner_product(&res, a_vec, 1, b_vec, 1, 2, 2); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&res2, 44); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&res2, &res) == 1); - - rustsecp256k1zkp_v0_8_0_weighted_scalar_inner_product(&res, a_vec, 0, a_vec, 0, 1, 4, &q); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&res2, 4740); /*i*i*4^(i+1) */ - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&res2, &res) == 1); - - rustsecp256k1zkp_v0_8_0_bppp_powers_of_r(r_pows, &r, 4); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&res, 2); CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&res, &r_pows[0])); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&res, 4); CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&res, &r_pows[1])); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&res, 16); CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&res, &r_pows[2])); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&res, 256); CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&res, &r_pows[3])); -} - -static void rustsecp256k1zkp_v0_8_0_norm_arg_commit_initial_data( - rustsecp256k1zkp_v0_8_0_sha256* transcript, - const rustsecp256k1zkp_v0_8_0_scalar* r, - const rustsecp256k1zkp_v0_8_0_bppp_generators* gens_vec, - size_t g_len, /* Same as n_vec_len, g_len + c_vec_len = gens->n */ - const rustsecp256k1zkp_v0_8_0_scalar* c_vec, - size_t c_vec_len, - const rustsecp256k1zkp_v0_8_0_ge* commit -) { - /* Commit to the initial public values */ - unsigned char ser_commit[33], ser_scalar[32], ser_le64[8]; - size_t i; - rustsecp256k1zkp_v0_8_0_ge comm = *commit; - rustsecp256k1zkp_v0_8_0_bppp_sha256_tagged_commitment_init(transcript); - rustsecp256k1zkp_v0_8_0_fe_normalize(&comm.x); - rustsecp256k1zkp_v0_8_0_fe_normalize(&comm.y); - CHECK(rustsecp256k1zkp_v0_8_0_ge_is_infinity(&comm) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_bppp_serialize_pt(&ser_commit[0], &comm)); - rustsecp256k1zkp_v0_8_0_sha256_write(transcript, ser_commit, 33); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(ser_scalar, r); - rustsecp256k1zkp_v0_8_0_sha256_write(transcript, ser_scalar, 32); - rustsecp256k1zkp_v0_8_0_bppp_le64(ser_le64, g_len); - rustsecp256k1zkp_v0_8_0_sha256_write(transcript, ser_le64, 8); - rustsecp256k1zkp_v0_8_0_bppp_le64(ser_le64, gens_vec->n); - rustsecp256k1zkp_v0_8_0_sha256_write(transcript, ser_le64, 8); - for (i = 0; i < gens_vec->n; i++) { - rustsecp256k1zkp_v0_8_0_fe_normalize(&gens_vec->gens[i].x); - rustsecp256k1zkp_v0_8_0_fe_normalize(&gens_vec->gens[i].y); - CHECK(rustsecp256k1zkp_v0_8_0_bppp_serialize_pt(&ser_commit[0], &gens_vec->gens[i])); - rustsecp256k1zkp_v0_8_0_sha256_write(transcript, ser_commit, 33); - } - rustsecp256k1zkp_v0_8_0_bppp_le64(ser_le64, c_vec_len); - rustsecp256k1zkp_v0_8_0_sha256_write(transcript, ser_le64, 8); - for (i = 0; i < c_vec_len; i++) { - rustsecp256k1zkp_v0_8_0_scalar_get_b32(ser_scalar, &c_vec[i]); - rustsecp256k1zkp_v0_8_0_sha256_write(transcript, ser_scalar, 32); - } -} - -static void copy_vectors_into_scratch(rustsecp256k1zkp_v0_8_0_scratch_space* scratch, - rustsecp256k1zkp_v0_8_0_scalar **ns, - rustsecp256k1zkp_v0_8_0_scalar **ls, - rustsecp256k1zkp_v0_8_0_scalar **cs, - rustsecp256k1zkp_v0_8_0_ge **gs, - const rustsecp256k1zkp_v0_8_0_scalar *n_vec, - const rustsecp256k1zkp_v0_8_0_scalar *l_vec, - const rustsecp256k1zkp_v0_8_0_scalar *c_vec, - const rustsecp256k1zkp_v0_8_0_ge *gens_vec, - size_t g_len, - size_t h_len) { - *ns = (rustsecp256k1zkp_v0_8_0_scalar*)rustsecp256k1zkp_v0_8_0_scratch_alloc(&ctx->error_callback, scratch, g_len * sizeof(rustsecp256k1zkp_v0_8_0_scalar)); - *ls = (rustsecp256k1zkp_v0_8_0_scalar*)rustsecp256k1zkp_v0_8_0_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(rustsecp256k1zkp_v0_8_0_scalar)); - *cs = (rustsecp256k1zkp_v0_8_0_scalar*)rustsecp256k1zkp_v0_8_0_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(rustsecp256k1zkp_v0_8_0_scalar)); - *gs = (rustsecp256k1zkp_v0_8_0_ge*)rustsecp256k1zkp_v0_8_0_scratch_alloc(&ctx->error_callback, scratch, (g_len + h_len) * sizeof(rustsecp256k1zkp_v0_8_0_ge)); - CHECK(ns != NULL && ls != NULL && cs != NULL && gs != NULL); - memcpy(*ns, n_vec, g_len * sizeof(rustsecp256k1zkp_v0_8_0_scalar)); - memcpy(*ls, l_vec, h_len * sizeof(rustsecp256k1zkp_v0_8_0_scalar)); - memcpy(*cs, c_vec, h_len * sizeof(rustsecp256k1zkp_v0_8_0_scalar)); - memcpy(*gs, gens_vec, (g_len + h_len) * sizeof(rustsecp256k1zkp_v0_8_0_ge)); -} - -/* A complete norm argument. In contrast to rustsecp256k1zkp_v0_8_0_bppp_rangeproof_norm_product_prove, this is meant - to be used as a standalone norm argument. - This is a simple wrapper around rustsecp256k1zkp_v0_8_0_bppp_rangeproof_norm_product_prove - that also commits to the initial public values used in the protocol. In this case, these public - values are commitment. -*/ -static int rustsecp256k1zkp_v0_8_0_norm_arg_prove( - rustsecp256k1zkp_v0_8_0_scratch_space* scratch, - unsigned char* proof, - size_t *proof_len, - const rustsecp256k1zkp_v0_8_0_scalar* r, - const rustsecp256k1zkp_v0_8_0_bppp_generators* gens_vec, - const rustsecp256k1zkp_v0_8_0_scalar* n_vec, - size_t n_vec_len, - const rustsecp256k1zkp_v0_8_0_scalar* l_vec, - size_t l_vec_len, - const rustsecp256k1zkp_v0_8_0_scalar* c_vec, - size_t c_vec_len, - const rustsecp256k1zkp_v0_8_0_ge* commit -) { - rustsecp256k1zkp_v0_8_0_scalar *ns, *ls, *cs; - rustsecp256k1zkp_v0_8_0_ge *gs, comm = *commit; - size_t scratch_checkpoint; - size_t g_len = n_vec_len, h_len = l_vec_len; - int res; - rustsecp256k1zkp_v0_8_0_sha256 transcript; - - scratch_checkpoint = rustsecp256k1zkp_v0_8_0_scratch_checkpoint(&ctx->error_callback, scratch); - - copy_vectors_into_scratch(scratch, &ns, &ls, &cs, &gs, n_vec, l_vec, c_vec, gens_vec->gens, g_len, h_len); - - /* Commit to the initial public values */ - rustsecp256k1zkp_v0_8_0_norm_arg_commit_initial_data(&transcript, r, gens_vec, g_len, c_vec, c_vec_len, &comm); - - res = rustsecp256k1zkp_v0_8_0_bppp_rangeproof_norm_product_prove( - ctx, - scratch, - proof, - proof_len, - &transcript, /* Transcript hash of the parent protocol */ - r, - gs, - gens_vec->n, - ns, - n_vec_len, - ls, - l_vec_len, - cs, - c_vec_len - ); - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); - return res; -} - -/* Verify the proof */ -static int rustsecp256k1zkp_v0_8_0_norm_arg_verify( - rustsecp256k1zkp_v0_8_0_scratch_space* scratch, - const unsigned char* proof, - size_t proof_len, - const rustsecp256k1zkp_v0_8_0_scalar* r, - const rustsecp256k1zkp_v0_8_0_bppp_generators* gens_vec, - size_t g_len, - const rustsecp256k1zkp_v0_8_0_scalar* c_vec, - size_t c_vec_len, - const rustsecp256k1zkp_v0_8_0_ge* commit -) { - rustsecp256k1zkp_v0_8_0_ge comm = *commit; - int res; - rustsecp256k1zkp_v0_8_0_sha256 transcript; - - /* Commit to the initial public values */ - rustsecp256k1zkp_v0_8_0_norm_arg_commit_initial_data(&transcript, r, gens_vec, g_len, c_vec, c_vec_len, &comm); - - res = rustsecp256k1zkp_v0_8_0_bppp_rangeproof_norm_product_verify( - ctx, - scratch, - proof, - proof_len, - &transcript, - r, - gens_vec, - g_len, - c_vec, - c_vec_len, - commit - ); - return res; -} - -void norm_arg_zero(void) { - rustsecp256k1zkp_v0_8_0_scalar n_vec[64], l_vec[64], c_vec[64]; - rustsecp256k1zkp_v0_8_0_scalar r, q; - rustsecp256k1zkp_v0_8_0_ge commit; - size_t i; - rustsecp256k1zkp_v0_8_0_scratch *scratch = rustsecp256k1zkp_v0_8_0_scratch_space_create(ctx, 1000*10); /* shouldn't need much */ - unsigned char proof[1000]; - rustsecp256k1zkp_v0_8_0_sha256 transcript; - - random_scalar_order(&r); - rustsecp256k1zkp_v0_8_0_scalar_sqr(&q, &r); - - /* l is zero vector and n is zero vectors of length 1 each. */ - { - size_t plen = sizeof(proof); - unsigned int n_vec_len = 1; - unsigned int c_vec_len = 1; - rustsecp256k1zkp_v0_8_0_bppp_generators *gens = rustsecp256k1zkp_v0_8_0_bppp_generators_create(ctx, n_vec_len + c_vec_len); - - rustsecp256k1zkp_v0_8_0_scalar_set_int(&n_vec[0], 0); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&l_vec[0], 0); - random_scalar_order(&c_vec[0]); - - rustsecp256k1zkp_v0_8_0_sha256_initialize(&transcript); /* No challenges used in n = 1, l = 1, but we set transcript as a good practice*/ - CHECK(rustsecp256k1zkp_v0_8_0_bppp_commit(ctx, scratch, &commit, gens, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &q)); - { - rustsecp256k1zkp_v0_8_0_scalar *ns, *ls, *cs; - rustsecp256k1zkp_v0_8_0_ge *gs; - size_t scratch_checkpoint = rustsecp256k1zkp_v0_8_0_scratch_checkpoint(&ctx->error_callback, scratch); - copy_vectors_into_scratch(scratch, &ns, &ls, &cs, &gs, n_vec, l_vec, c_vec, gens->gens, n_vec_len, c_vec_len); - CHECK(rustsecp256k1zkp_v0_8_0_bppp_rangeproof_norm_product_prove(ctx, scratch, proof, &plen, &transcript, &r, gs, gens->n, ns, n_vec_len, ls, c_vec_len, cs, c_vec_len)); - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); - } - rustsecp256k1zkp_v0_8_0_sha256_initialize(&transcript); - CHECK(rustsecp256k1zkp_v0_8_0_bppp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &r, gens, c_vec_len, c_vec, c_vec_len, &commit)); - - rustsecp256k1zkp_v0_8_0_bppp_generators_destroy(ctx, gens); - } - - /* l is the zero vector and longer than n. This results in one of the - * internal commitments X or R to be the point at infinity. */ - { - unsigned int n_vec_len = 1; - unsigned int c_vec_len = 2; - rustsecp256k1zkp_v0_8_0_bppp_generators *gs = rustsecp256k1zkp_v0_8_0_bppp_generators_create(ctx, n_vec_len + c_vec_len); - size_t plen = sizeof(proof); - for (i = 0; i < n_vec_len; i++) { - random_scalar_order(&n_vec[i]); - } - for (i = 0; i < c_vec_len; i++) { - rustsecp256k1zkp_v0_8_0_scalar_set_int(&l_vec[i], 0); - random_scalar_order(&c_vec[i]); - } - CHECK(rustsecp256k1zkp_v0_8_0_bppp_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &q)); - CHECK(!rustsecp256k1zkp_v0_8_0_norm_arg_prove(scratch, proof, &plen, &r, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &commit)); - rustsecp256k1zkp_v0_8_0_bppp_generators_destroy(ctx, gs); - } - - /* Verify vectors of length 0 */ - { - unsigned int n_vec_len = 1; - unsigned int c_vec_len = 1; - rustsecp256k1zkp_v0_8_0_bppp_generators *gs = rustsecp256k1zkp_v0_8_0_bppp_generators_create(ctx, n_vec_len + c_vec_len); - size_t plen = sizeof(proof); - random_scalar_order(&n_vec[0]); - random_scalar_order(&c_vec[0]); - random_scalar_order(&l_vec[0]); - CHECK(rustsecp256k1zkp_v0_8_0_bppp_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &q)); - CHECK(rustsecp256k1zkp_v0_8_0_norm_arg_prove(scratch, proof, &plen, &r, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &commit)); - CHECK(rustsecp256k1zkp_v0_8_0_norm_arg_verify(scratch, proof, plen, &r, gs, n_vec_len, c_vec, c_vec_len, &commit)); - CHECK(!rustsecp256k1zkp_v0_8_0_norm_arg_verify(scratch, proof, plen, &r, gs, 0, c_vec, c_vec_len, &commit)); - CHECK(!rustsecp256k1zkp_v0_8_0_norm_arg_verify(scratch, proof, plen, &r, gs, n_vec_len, c_vec, 0, &commit)); - - rustsecp256k1zkp_v0_8_0_bppp_generators_destroy(ctx, gs); - } - - rustsecp256k1zkp_v0_8_0_scratch_space_destroy(ctx, scratch); -} - -void norm_arg_test(unsigned int n, unsigned int m) { - rustsecp256k1zkp_v0_8_0_scalar n_vec[64], l_vec[64], c_vec[64]; - rustsecp256k1zkp_v0_8_0_scalar r, q; - rustsecp256k1zkp_v0_8_0_ge commit; - size_t i, plen; - int res; - rustsecp256k1zkp_v0_8_0_bppp_generators *gs = rustsecp256k1zkp_v0_8_0_bppp_generators_create(ctx, n + m); - rustsecp256k1zkp_v0_8_0_scratch *scratch = rustsecp256k1zkp_v0_8_0_scratch_space_create(ctx, 1000*1000); /* shouldn't need much */ - unsigned char proof[1000]; - plen = 1000; - random_scalar_order(&r); - rustsecp256k1zkp_v0_8_0_scalar_sqr(&q, &r); - - for (i = 0; i < n; i++) { - random_scalar_order(&n_vec[i]); - } - - for (i = 0; i < m; i++) { - random_scalar_order(&l_vec[i]); - random_scalar_order(&c_vec[i]); - } - - res = rustsecp256k1zkp_v0_8_0_bppp_commit(ctx, scratch, &commit, gs, n_vec, n, l_vec, m, c_vec, m, &q); - CHECK(res == 1); - res = rustsecp256k1zkp_v0_8_0_norm_arg_prove(scratch, proof, &plen, &r, gs, n_vec, n, l_vec, m, c_vec, m, &commit); - CHECK(res == 1); - - res = rustsecp256k1zkp_v0_8_0_norm_arg_verify(scratch, proof, plen, &r, gs, n, c_vec, m, &commit); - CHECK(res == 1); - - /* Changing any of last two scalars should break the proof */ - proof[plen - 1] ^= 1; - res = rustsecp256k1zkp_v0_8_0_norm_arg_verify(scratch, proof, plen, &r, gs, n, c_vec, m, &commit); - CHECK(res == 0); - proof[plen - 1 - 32] ^= 1; - res = rustsecp256k1zkp_v0_8_0_norm_arg_verify(scratch, proof, plen, &r, gs, n, c_vec, m, &commit); - CHECK(res == 0); - - rustsecp256k1zkp_v0_8_0_scratch_space_destroy(ctx, scratch); - rustsecp256k1zkp_v0_8_0_bppp_generators_destroy(ctx, gs); -} - -/* Parses generators from points compressed as pubkeys */ -rustsecp256k1zkp_v0_8_0_bppp_generators* bppp_generators_parse_regular(const unsigned char* data, size_t data_len) { - size_t n = data_len / 33; - rustsecp256k1zkp_v0_8_0_bppp_generators* ret; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(data != NULL); - - if (data_len % 33 != 0) { - return NULL; - } - - ret = (rustsecp256k1zkp_v0_8_0_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret)); - if (ret == NULL) { - return NULL; - } - ret->n = n; - ret->gens = (rustsecp256k1zkp_v0_8_0_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens)); - if (ret->gens == NULL) { - free(ret); - return NULL; - } - - while (n--) { - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&ret->gens[n], &data[33 * n], 33)) { - free(ret->gens); - free(ret); - return NULL; - } - } - return ret; -} - -int norm_arg_verify_vectors_helper(rustsecp256k1zkp_v0_8_0_scratch *scratch, const unsigned char *gens, const unsigned char *proof, size_t plen, const unsigned char *r32, size_t n_vec_len, const unsigned char c_vec32[][32], rustsecp256k1zkp_v0_8_0_scalar *c_vec, size_t c_vec_len, const unsigned char *commit33) { - rustsecp256k1zkp_v0_8_0_sha256 transcript; - rustsecp256k1zkp_v0_8_0_bppp_generators *gs = bppp_generators_parse_regular(gens, 33*(n_vec_len + c_vec_len)); - rustsecp256k1zkp_v0_8_0_scalar r; - rustsecp256k1zkp_v0_8_0_ge commit; - int overflow; - int i; - int ret; - - CHECK(gs != NULL); - rustsecp256k1zkp_v0_8_0_sha256_initialize(&transcript); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&r, r32, &overflow); - CHECK(!overflow); - - for (i = 0; i < (int)c_vec_len; i++) { - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&c_vec[i], c_vec32[i], &overflow); - CHECK(!overflow); - } - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&commit, commit33, 33)); - ret = rustsecp256k1zkp_v0_8_0_bppp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &r, gs, n_vec_len, c_vec, c_vec_len, &commit); - - rustsecp256k1zkp_v0_8_0_bppp_generators_destroy(ctx, gs); - return ret; -} - -#define IDX_TO_TEST(i) (norm_arg_verify_vectors_helper(scratch, verify_vector_gens, verify_vector_##i##_proof, sizeof(verify_vector_##i##_proof), verify_vector_##i##_r32, verify_vector_##i##_n_vec_len, verify_vector_##i##_c_vec32, verify_vector_##i##_c_vec, sizeof(verify_vector_##i##_c_vec)/sizeof(rustsecp256k1zkp_v0_8_0_scalar), verify_vector_##i##_commit33) == verify_vector_##i##_result) - -void norm_arg_verify_vectors(void) { - rustsecp256k1zkp_v0_8_0_scratch *scratch = rustsecp256k1zkp_v0_8_0_scratch_space_create(ctx, 1000*1000); /* shouldn't need much */ - size_t alloc = scratch->alloc_size; - - CHECK(IDX_TO_TEST(0)); - CHECK(IDX_TO_TEST(1)); - CHECK(IDX_TO_TEST(2)); - CHECK(IDX_TO_TEST(3)); - CHECK(IDX_TO_TEST(4)); - CHECK(IDX_TO_TEST(5)); - CHECK(IDX_TO_TEST(6)); - CHECK(IDX_TO_TEST(7)); - CHECK(IDX_TO_TEST(8)); - - CHECK(alloc == scratch->alloc_size); - rustsecp256k1zkp_v0_8_0_scratch_space_destroy(ctx, scratch); -} -#undef IDX_TO_TEST - -void run_bppp_tests(void) { - test_log_exp(); - test_norm_util_helpers(); - test_bppp_generators_api(); - test_bppp_generators_fixed(); - test_bppp_tagged_hash(); - - norm_arg_zero(); - norm_arg_test(1, 1); - norm_arg_test(1, 64); - norm_arg_test(64, 1); - norm_arg_test(32, 32); - norm_arg_test(32, 64); - norm_arg_test(64, 32); - norm_arg_test(64, 64); - norm_arg_verify_vectors(); -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdh/main_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdh/main_impl.h deleted file mode 100644 index ebee763f..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdh/main_impl.h +++ /dev/null @@ -1,71 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_ECDH_MAIN_H -#define SECP256K1_MODULE_ECDH_MAIN_H - -#include "../../../include/secp256k1_ecdh.h" -#include "../../ecmult_const_impl.h" - -static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) { - unsigned char version = (y32[31] & 0x01) | 0x02; - rustsecp256k1zkp_v0_8_0_sha256 sha; - (void)data; - - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, &version, 1); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, x32, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, output); - - return 1; -} - -const rustsecp256k1zkp_v0_8_0_ecdh_hash_function rustsecp256k1zkp_v0_8_0_ecdh_hash_function_sha256 = ecdh_hash_function_sha256; -const rustsecp256k1zkp_v0_8_0_ecdh_hash_function rustsecp256k1zkp_v0_8_0_ecdh_hash_function_default = ecdh_hash_function_sha256; - -int rustsecp256k1zkp_v0_8_0_ecdh(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *output, const rustsecp256k1zkp_v0_8_0_pubkey *point, const unsigned char *scalar, rustsecp256k1zkp_v0_8_0_ecdh_hash_function hashfp, void *data) { - int ret = 0; - int overflow = 0; - rustsecp256k1zkp_v0_8_0_gej res; - rustsecp256k1zkp_v0_8_0_ge pt; - rustsecp256k1zkp_v0_8_0_scalar s; - unsigned char x[32]; - unsigned char y[32]; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output != NULL); - ARG_CHECK(point != NULL); - ARG_CHECK(scalar != NULL); - - if (hashfp == NULL) { - hashfp = rustsecp256k1zkp_v0_8_0_ecdh_hash_function_default; - } - - rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &pt, point); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&s, scalar, &overflow); - - overflow |= rustsecp256k1zkp_v0_8_0_scalar_is_zero(&s); - rustsecp256k1zkp_v0_8_0_scalar_cmov(&s, &rustsecp256k1zkp_v0_8_0_scalar_one, overflow); - - rustsecp256k1zkp_v0_8_0_ecmult_const(&res, &pt, &s, 256); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&pt, &res); - - /* Compute a hash of the point */ - rustsecp256k1zkp_v0_8_0_fe_normalize(&pt.x); - rustsecp256k1zkp_v0_8_0_fe_normalize(&pt.y); - rustsecp256k1zkp_v0_8_0_fe_get_b32(x, &pt.x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(y, &pt.y); - - ret = hashfp(output, x, y, data); - - memset(x, 0, 32); - memset(y, 0, 32); - rustsecp256k1zkp_v0_8_0_scalar_clear(&s); - - return !!ret & !overflow; -} - -#endif /* SECP256K1_MODULE_ECDH_MAIN_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdh/tests_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdh/tests_impl.h deleted file mode 100644 index 75f8ebae..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdh/tests_impl.h +++ /dev/null @@ -1,165 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_ECDH_TESTS_H -#define SECP256K1_MODULE_ECDH_TESTS_H - -int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { - (void)output; - (void)x; - (void)y; - (void)data; - return 0; -} - -int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { - (void)data; - /* Save x and y as uncompressed public key */ - output[0] = 0x04; - memcpy(output + 1, x, 32); - memcpy(output + 33, y, 32); - return 1; -} - -void test_ecdh_api(void) { - /* Setup context that just counts errors */ - rustsecp256k1zkp_v0_8_0_context *tctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN); - rustsecp256k1zkp_v0_8_0_pubkey point; - unsigned char res[32]; - unsigned char s_one[32] = { 0 }; - int32_t ecount = 0; - s_one[31] = 1; - - rustsecp256k1zkp_v0_8_0_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(tctx, &point, s_one) == 1); - - /* Check all NULLs are detected */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(tctx, NULL, &point, s_one, NULL, NULL) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(tctx, res, NULL, s_one, NULL, NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(tctx, res, &point, NULL, NULL, NULL) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1); - CHECK(ecount == 3); - - /* Cleanup */ - rustsecp256k1zkp_v0_8_0_context_destroy(tctx); -} - -void test_ecdh_generator_basepoint(void) { - unsigned char s_one[32] = { 0 }; - rustsecp256k1zkp_v0_8_0_pubkey point[2]; - int i; - - s_one[31] = 1; - /* Check against pubkey creation when the basepoint is the generator */ - for (i = 0; i < 2 * count; ++i) { - rustsecp256k1zkp_v0_8_0_sha256 sha; - unsigned char s_b32[32]; - unsigned char output_ecdh[65]; - unsigned char output_ser[32]; - unsigned char point_ser[65]; - size_t point_ser_len = sizeof(point_ser); - rustsecp256k1zkp_v0_8_0_scalar s; - - random_scalar_order(&s); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(s_b32, &s); - - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &point[0], s_one) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &point[1], s_b32) == 1); - - /* compute using ECDH function with custom hash function */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(ctx, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1); - /* compute "explicitly" */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1); - /* compare */ - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(output_ecdh, point_ser, 65) == 0); - - /* compute using ECDH function with default hash function */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(ctx, output_ecdh, &point[0], s_b32, NULL, NULL) == 1); - /* compute "explicitly" */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, point_ser, point_ser_len); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, output_ser); - /* compare */ - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(output_ecdh, output_ser, 32) == 0); - } -} - -void test_bad_scalar(void) { - unsigned char s_zero[32] = { 0 }; - unsigned char s_overflow[32] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, - 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 - }; - unsigned char s_rand[32] = { 0 }; - unsigned char output[32]; - rustsecp256k1zkp_v0_8_0_scalar rand; - rustsecp256k1zkp_v0_8_0_pubkey point; - - /* Create random point */ - random_scalar_order(&rand); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(s_rand, &rand); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &point, s_rand) == 1); - - /* Try to multiply it by bad values */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(ctx, output, &point, s_zero, NULL, NULL) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 0); - /* ...and a good one */ - s_overflow[31] -= 1; - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 1); - - /* Hash function failure results in ecdh failure */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0); -} - -/** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */ -void test_result_basepoint(void) { - rustsecp256k1zkp_v0_8_0_pubkey point; - rustsecp256k1zkp_v0_8_0_scalar rand; - unsigned char s[32]; - unsigned char s_inv[32]; - unsigned char out[32]; - unsigned char out_inv[32]; - unsigned char out_base[32]; - int i; - - unsigned char s_one[32] = { 0 }; - s_one[31] = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &point, s_one) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(ctx, out_base, &point, s_one, NULL, NULL) == 1); - - for (i = 0; i < 2 * count; i++) { - random_scalar_order(&rand); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(s, &rand); - rustsecp256k1zkp_v0_8_0_scalar_inverse(&rand, &rand); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(s_inv, &rand); - - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &point, s) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(ctx, out, &point, s_inv, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(out, out_base, 32) == 0); - - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &point, s_inv) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(ctx, out_inv, &point, s, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(out_inv, out_base, 32) == 0); - } -} - -void run_ecdh_tests(void) { - test_ecdh_api(); - test_ecdh_generator_basepoint(); - test_bad_scalar(); - test_result_basepoint(); -} - -#endif /* SECP256K1_MODULE_ECDH_TESTS_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_adaptor/Makefile.am.include b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_adaptor/Makefile.am.include deleted file mode 100644 index cbdacc21..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_adaptor/Makefile.am.include +++ /dev/null @@ -1,4 +0,0 @@ -include_HEADERS += include/rustsecp256k1zkp_v0_8_0_ecdsa_adaptor.h -noinst_HEADERS += src/modules/ecdsa_adaptor/main_impl.h -noinst_HEADERS += src/modules/ecdsa_adaptor/dleq_impl.h -noinst_HEADERS += src/modules/ecdsa_adaptor/tests_impl.h diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_adaptor/dleq_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_adaptor/dleq_impl.h deleted file mode 100644 index 222207f9..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_adaptor/dleq_impl.h +++ /dev/null @@ -1,158 +0,0 @@ -#ifndef SECP256K1_DLEQ_IMPL_H -#define SECP256K1_DLEQ_IMPL_H - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("DLEQ")||SHA256("DLEQ"). */ -static void rustsecp256k1zkp_v0_8_0_nonce_function_dleq_sha256_tagged(rustsecp256k1zkp_v0_8_0_sha256 *sha) { - rustsecp256k1zkp_v0_8_0_sha256_initialize(sha); - sha->s[0] = 0x8cc4beacul; - sha->s[1] = 0x2e011f3ful; - sha->s[2] = 0x355c75fbul; - sha->s[3] = 0x3ba6a2c5ul; - sha->s[4] = 0xe96f3aeful; - sha->s[5] = 0x180530fdul; - sha->s[6] = 0x94582499ul; - sha->s[7] = 0x577fd564ul; - - sha->bytes = 64; -} - -/* algo argument for nonce_function_ecdsa_adaptor to derive the nonce using a tagged hash function. */ -static const unsigned char dleq_algo[4] = "DLEQ"; - -static int rustsecp256k1zkp_v0_8_0_dleq_hash_point(rustsecp256k1zkp_v0_8_0_sha256 *sha, rustsecp256k1zkp_v0_8_0_ge *p) { - unsigned char buf[33]; - size_t size = 33; - - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(p, buf, &size, 1)) { - return 0; - } - - rustsecp256k1zkp_v0_8_0_sha256_write(sha, buf, size); - return 1; -} - -static int rustsecp256k1zkp_v0_8_0_dleq_nonce(rustsecp256k1zkp_v0_8_0_scalar *k, const unsigned char *sk32, const unsigned char *gen2_33, const unsigned char *p1_33, const unsigned char *p2_33, rustsecp256k1zkp_v0_8_0_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) { - rustsecp256k1zkp_v0_8_0_sha256 sha; - unsigned char buf[32]; - unsigned char nonce[32]; - size_t size = 33; - - if (noncefp == NULL) { - noncefp = rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor; - } - - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, p1_33, size); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, p2_33, size); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, buf); - - if (!noncefp(nonce, buf, sk32, gen2_33, dleq_algo, sizeof(dleq_algo), ndata)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_scalar_set_b32(k, nonce, NULL); - if (rustsecp256k1zkp_v0_8_0_scalar_is_zero(k)) { - return 0; - } - - return 1; -} - -/* Generates a challenge as defined in the DLC Specification at - * https://github.com/discreetlogcontracts/dlcspecs */ -static void rustsecp256k1zkp_v0_8_0_dleq_challenge(rustsecp256k1zkp_v0_8_0_scalar *e, rustsecp256k1zkp_v0_8_0_ge *gen2, rustsecp256k1zkp_v0_8_0_ge *r1, rustsecp256k1zkp_v0_8_0_ge *r2, rustsecp256k1zkp_v0_8_0_ge *p1, rustsecp256k1zkp_v0_8_0_ge *p2) { - unsigned char buf[32]; - rustsecp256k1zkp_v0_8_0_sha256 sha; - - rustsecp256k1zkp_v0_8_0_nonce_function_dleq_sha256_tagged(&sha); - rustsecp256k1zkp_v0_8_0_dleq_hash_point(&sha, p1); - rustsecp256k1zkp_v0_8_0_dleq_hash_point(&sha, gen2); - rustsecp256k1zkp_v0_8_0_dleq_hash_point(&sha, p2); - rustsecp256k1zkp_v0_8_0_dleq_hash_point(&sha, r1); - rustsecp256k1zkp_v0_8_0_dleq_hash_point(&sha, r2); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, buf); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(e, buf, NULL); -} - -/* P1 = x*G, P2 = x*Y */ -static void rustsecp256k1zkp_v0_8_0_dleq_pair(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context *ecmult_gen_ctx, rustsecp256k1zkp_v0_8_0_ge *p1, rustsecp256k1zkp_v0_8_0_ge *p2, const rustsecp256k1zkp_v0_8_0_scalar *sk, const rustsecp256k1zkp_v0_8_0_ge *gen2) { - rustsecp256k1zkp_v0_8_0_gej p1j, p2j; - - rustsecp256k1zkp_v0_8_0_ecmult_gen(ecmult_gen_ctx, &p1j, sk); - rustsecp256k1zkp_v0_8_0_ge_set_gej(p1, &p1j); - rustsecp256k1zkp_v0_8_0_ecmult_const(&p2j, gen2, sk, 256); - rustsecp256k1zkp_v0_8_0_ge_set_gej(p2, &p2j); -} - -/* Generates a proof that the discrete logarithm of P1 to the secp256k1 base G is the - * same as the discrete logarithm of P2 to the base Y */ -static int rustsecp256k1zkp_v0_8_0_dleq_prove(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_scalar *s, rustsecp256k1zkp_v0_8_0_scalar *e, const rustsecp256k1zkp_v0_8_0_scalar *sk, rustsecp256k1zkp_v0_8_0_ge *gen2, rustsecp256k1zkp_v0_8_0_ge *p1, rustsecp256k1zkp_v0_8_0_ge *p2, rustsecp256k1zkp_v0_8_0_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) { - rustsecp256k1zkp_v0_8_0_ge r1, r2; - rustsecp256k1zkp_v0_8_0_scalar k = { 0 }; - unsigned char sk32[32]; - unsigned char gen2_33[33]; - unsigned char p1_33[33]; - unsigned char p2_33[33]; - int ret = 1; - size_t pubkey_size = 33; - - rustsecp256k1zkp_v0_8_0_scalar_get_b32(sk32, sk); - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(gen2, gen2_33, &pubkey_size, 1)) { - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(p1, p1_33, &pubkey_size, 1)) { - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(p2, p2_33, &pubkey_size, 1)) { - return 0; - } - - ret &= rustsecp256k1zkp_v0_8_0_dleq_nonce(&k, sk32, gen2_33, p1_33, p2_33, noncefp, ndata); - /* R1 = k*G, R2 = k*Y */ - rustsecp256k1zkp_v0_8_0_dleq_pair(&ctx->ecmult_gen_ctx, &r1, &r2, &k, gen2); - /* We declassify the non-secret values r1 and r2 to allow using them as - * branch points. */ - rustsecp256k1zkp_v0_8_0_declassify(ctx, &r1, sizeof(r1)); - rustsecp256k1zkp_v0_8_0_declassify(ctx, &r2, sizeof(r2)); - - /* e = tagged hash(p1, gen2, p2, r1, r2) */ - /* s = k + e * sk */ - rustsecp256k1zkp_v0_8_0_dleq_challenge(e, gen2, &r1, &r2, p1, p2); - rustsecp256k1zkp_v0_8_0_scalar_mul(s, e, sk); - rustsecp256k1zkp_v0_8_0_scalar_add(s, s, &k); - - rustsecp256k1zkp_v0_8_0_scalar_clear(&k); - return ret; -} - -static int rustsecp256k1zkp_v0_8_0_dleq_verify(const rustsecp256k1zkp_v0_8_0_scalar *s, const rustsecp256k1zkp_v0_8_0_scalar *e, rustsecp256k1zkp_v0_8_0_ge *p1, rustsecp256k1zkp_v0_8_0_ge *gen2, rustsecp256k1zkp_v0_8_0_ge *p2) { - rustsecp256k1zkp_v0_8_0_scalar e_neg; - rustsecp256k1zkp_v0_8_0_scalar e_expected; - rustsecp256k1zkp_v0_8_0_gej gen2j; - rustsecp256k1zkp_v0_8_0_gej p1j, p2j; - rustsecp256k1zkp_v0_8_0_gej r1j, r2j; - rustsecp256k1zkp_v0_8_0_ge r1, r2; - rustsecp256k1zkp_v0_8_0_gej tmpj; - - rustsecp256k1zkp_v0_8_0_gej_set_ge(&p1j, p1); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&p2j, p2); - - rustsecp256k1zkp_v0_8_0_scalar_negate(&e_neg, e); - /* R1 = s*G - e*P1 */ - rustsecp256k1zkp_v0_8_0_ecmult(&r1j, &p1j, &e_neg, s); - /* R2 = s*gen2 - e*P2 */ - rustsecp256k1zkp_v0_8_0_ecmult(&tmpj, &p2j, &e_neg, &rustsecp256k1zkp_v0_8_0_scalar_zero); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&gen2j, gen2); - rustsecp256k1zkp_v0_8_0_ecmult(&r2j, &gen2j, s, &rustsecp256k1zkp_v0_8_0_scalar_zero); - rustsecp256k1zkp_v0_8_0_gej_add_var(&r2j, &r2j, &tmpj, NULL); - - rustsecp256k1zkp_v0_8_0_ge_set_gej(&r1, &r1j); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&r2, &r2j); - rustsecp256k1zkp_v0_8_0_dleq_challenge(&e_expected, gen2, &r1, &r2, p1, p2); - - rustsecp256k1zkp_v0_8_0_scalar_add(&e_expected, &e_expected, &e_neg); - return rustsecp256k1zkp_v0_8_0_scalar_is_zero(&e_expected); -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_adaptor/main_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_adaptor/main_impl.h deleted file mode 100644 index 177d9e5c..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_adaptor/main_impl.h +++ /dev/null @@ -1,375 +0,0 @@ -/********************************************************************** - * Copyright (c) 2020-2021 Jonas Nick, Jesse Posner * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_ECDSA_ADAPTOR_MAIN_H -#define SECP256K1_MODULE_ECDSA_ADAPTOR_MAIN_H - -#include "../../../include/secp256k1_ecdsa_adaptor.h" -#include "dleq_impl.h" - -/* (R, R', s', dleq_proof) */ -static int rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_serialize(unsigned char *adaptor_sig162, rustsecp256k1zkp_v0_8_0_ge *r, rustsecp256k1zkp_v0_8_0_ge *rp, const rustsecp256k1zkp_v0_8_0_scalar *sp, const rustsecp256k1zkp_v0_8_0_scalar *dleq_proof_e, const rustsecp256k1zkp_v0_8_0_scalar *dleq_proof_s) { - size_t size = 33; - - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(r, adaptor_sig162, &size, 1)) { - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(rp, &adaptor_sig162[33], &size, 1)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&adaptor_sig162[66], sp); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&adaptor_sig162[98], dleq_proof_e); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&adaptor_sig162[130], dleq_proof_s); - - return 1; -} - -static int rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(rustsecp256k1zkp_v0_8_0_ge *r, rustsecp256k1zkp_v0_8_0_scalar *sigr, rustsecp256k1zkp_v0_8_0_ge *rp, rustsecp256k1zkp_v0_8_0_scalar *sp, rustsecp256k1zkp_v0_8_0_scalar *dleq_proof_e, rustsecp256k1zkp_v0_8_0_scalar *dleq_proof_s, const unsigned char *adaptor_sig162) { - /* If r is deserialized, require that a sigr is provided to receive - * the X-coordinate */ - VERIFY_CHECK((r == NULL) || (r != NULL && sigr != NULL)); - if (r != NULL) { - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(r, &adaptor_sig162[0], 33)) { - return 0; - } - } - if (sigr != NULL) { - rustsecp256k1zkp_v0_8_0_scalar_set_b32(sigr, &adaptor_sig162[1], NULL); - if (rustsecp256k1zkp_v0_8_0_scalar_is_zero(sigr)) { - return 0; - } - } - if (rp != NULL) { - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(rp, &adaptor_sig162[33], 33)) { - return 0; - } - } - if (sp != NULL) { - if (!rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(sp, &adaptor_sig162[66])) { - return 0; - } - } - if (dleq_proof_e != NULL) { - rustsecp256k1zkp_v0_8_0_scalar_set_b32(dleq_proof_e, &adaptor_sig162[98], NULL); - } - if (dleq_proof_s != NULL) { - int overflow; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(dleq_proof_s, &adaptor_sig162[130], &overflow); - if (overflow) { - return 0; - } - } - return 1; -} - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("ECDSAadaptor/non")||SHA256("ECDSAadaptor/non"). */ -static void rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor_sha256_tagged(rustsecp256k1zkp_v0_8_0_sha256 *sha) { - rustsecp256k1zkp_v0_8_0_sha256_initialize(sha); - sha->s[0] = 0x791dae43ul; - sha->s[1] = 0xe52d3b44ul; - sha->s[2] = 0x37f9edeaul; - sha->s[3] = 0x9bfd2ab1ul; - sha->s[4] = 0xcfb0f44dul; - sha->s[5] = 0xccf1d880ul; - sha->s[6] = 0xd18f2c13ul; - sha->s[7] = 0xa37b9024ul; - - sha->bytes = 64; -} - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("ECDSAadaptor/aux")||SHA256("ECDSAadaptor/aux"). */ -static void rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor_sha256_tagged_aux(rustsecp256k1zkp_v0_8_0_sha256 *sha) { - rustsecp256k1zkp_v0_8_0_sha256_initialize(sha); - sha->s[0] = 0xd14c7bd9ul; - sha->s[1] = 0x095d35e6ul; - sha->s[2] = 0xb8490a88ul; - sha->s[3] = 0xfb00ef74ul; - sha->s[4] = 0x0baa488ful; - sha->s[5] = 0x69366693ul; - sha->s[6] = 0x1c81c5baul; - sha->s[7] = 0xc33b296aul; - - sha->bytes = 64; -} - -/* algo argument for nonce_function_ecdsa_adaptor to derive the nonce using a tagged hash function. */ -static const unsigned char ecdsa_adaptor_algo[16] = "ECDSAadaptor/non"; - -/* Modified BIP-340 nonce function */ -static int nonce_function_ecdsa_adaptor(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *pk33, const unsigned char *algo, size_t algolen, void *data) { - rustsecp256k1zkp_v0_8_0_sha256 sha; - unsigned char masked_key[32]; - int i; - - if (algo == NULL) { - return 0; - } - - if (data != NULL) { - rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor_sha256_tagged_aux(&sha); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, data, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, masked_key); - for (i = 0; i < 32; i++) { - masked_key[i] ^= key32[i]; - } - } - - /* Tag the hash with algo which is important to avoid nonce reuse across - * algorithims. An optimized tagging implementation is used if the default - * tag is provided. */ - if (algolen == sizeof(ecdsa_adaptor_algo) - && rustsecp256k1zkp_v0_8_0_memcmp_var(algo, ecdsa_adaptor_algo, algolen) == 0) { - rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor_sha256_tagged(&sha); - } else if (algolen == sizeof(dleq_algo) - && rustsecp256k1zkp_v0_8_0_memcmp_var(algo, dleq_algo, algolen) == 0) { - rustsecp256k1zkp_v0_8_0_nonce_function_dleq_sha256_tagged(&sha); - } else { - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, algo, algolen); - } - - /* Hash (masked-)key||pk||msg using the tagged hash as per BIP-340 */ - if (data != NULL) { - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, masked_key, 32); - } else { - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, key32, 32); - } - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, pk33, 33); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, msg32, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, nonce32); - return 1; -} - -const rustsecp256k1zkp_v0_8_0_nonce_function_hardened_ecdsa_adaptor rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor = nonce_function_ecdsa_adaptor; - -int rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *adaptor_sig162, unsigned char *seckey32, const rustsecp256k1zkp_v0_8_0_pubkey *enckey, const unsigned char *msg32, rustsecp256k1zkp_v0_8_0_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) { - rustsecp256k1zkp_v0_8_0_scalar k; - rustsecp256k1zkp_v0_8_0_gej rj, rpj; - rustsecp256k1zkp_v0_8_0_ge r, rp; - rustsecp256k1zkp_v0_8_0_ge enckey_ge; - rustsecp256k1zkp_v0_8_0_scalar dleq_proof_s; - rustsecp256k1zkp_v0_8_0_scalar dleq_proof_e; - rustsecp256k1zkp_v0_8_0_scalar sk; - rustsecp256k1zkp_v0_8_0_scalar msg; - rustsecp256k1zkp_v0_8_0_scalar sp; - rustsecp256k1zkp_v0_8_0_scalar sigr; - rustsecp256k1zkp_v0_8_0_scalar n; - unsigned char nonce32[32] = { 0 }; - unsigned char buf33[33]; - size_t size = 33; - int ret = 1; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(adaptor_sig162 != NULL); - ARG_CHECK(seckey32 != NULL); - ARG_CHECK(enckey != NULL); - ARG_CHECK(msg32 != NULL); - - rustsecp256k1zkp_v0_8_0_scalar_clear(&dleq_proof_e); - rustsecp256k1zkp_v0_8_0_scalar_clear(&dleq_proof_s); - - if (noncefp == NULL) { - noncefp = rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor; - } - - ret &= rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &enckey_ge, enckey); - ret &= rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&enckey_ge, buf33, &size, 1); - ret &= !!noncefp(nonce32, msg32, seckey32, buf33, ecdsa_adaptor_algo, sizeof(ecdsa_adaptor_algo), ndata); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&k, nonce32, NULL); - ret &= !rustsecp256k1zkp_v0_8_0_scalar_is_zero(&k); - rustsecp256k1zkp_v0_8_0_scalar_cmov(&k, &rustsecp256k1zkp_v0_8_0_scalar_one, !ret); - - /* R' := k*G */ - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &rpj, &k); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&rp, &rpj); - /* R = k*Y; */ - rustsecp256k1zkp_v0_8_0_ecmult_const(&rj, &enckey_ge, &k, 256); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&r, &rj); - /* We declassify the non-secret values rp and r to allow using them - * as branch points. */ - rustsecp256k1zkp_v0_8_0_declassify(ctx, &rp, sizeof(rp)); - rustsecp256k1zkp_v0_8_0_declassify(ctx, &r, sizeof(r)); - - /* dleq_proof = DLEQ_prove(k, (R', Y, R)) */ - ret &= rustsecp256k1zkp_v0_8_0_dleq_prove(ctx, &dleq_proof_s, &dleq_proof_e, &k, &enckey_ge, &rp, &r, noncefp, ndata); - - ret &= rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&sk, seckey32); - rustsecp256k1zkp_v0_8_0_scalar_cmov(&sk, &rustsecp256k1zkp_v0_8_0_scalar_one, !ret); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&msg, msg32, NULL); - rustsecp256k1zkp_v0_8_0_fe_normalize(&r.x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(buf33, &r.x); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&sigr, buf33, NULL); - ret &= !rustsecp256k1zkp_v0_8_0_scalar_is_zero(&sigr); - /* s' = k⁻¹(m + R.x * x) */ - rustsecp256k1zkp_v0_8_0_scalar_mul(&n, &sigr, &sk); - rustsecp256k1zkp_v0_8_0_scalar_add(&n, &n, &msg); - rustsecp256k1zkp_v0_8_0_scalar_inverse(&sp, &k); - rustsecp256k1zkp_v0_8_0_scalar_mul(&sp, &sp, &n); - ret &= !rustsecp256k1zkp_v0_8_0_scalar_is_zero(&sp); - - /* return (R, R', s', dleq_proof) */ - ret &= rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_serialize(adaptor_sig162, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s); - - rustsecp256k1zkp_v0_8_0_memczero(adaptor_sig162, 162, !ret); - rustsecp256k1zkp_v0_8_0_scalar_clear(&n); - rustsecp256k1zkp_v0_8_0_scalar_clear(&k); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sk); - - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(const rustsecp256k1zkp_v0_8_0_context* ctx, const unsigned char *adaptor_sig162, const rustsecp256k1zkp_v0_8_0_pubkey *pubkey, const unsigned char *msg32, const rustsecp256k1zkp_v0_8_0_pubkey *enckey) { - rustsecp256k1zkp_v0_8_0_scalar dleq_proof_s, dleq_proof_e; - rustsecp256k1zkp_v0_8_0_scalar msg; - rustsecp256k1zkp_v0_8_0_ge pubkey_ge; - rustsecp256k1zkp_v0_8_0_ge r, rp; - rustsecp256k1zkp_v0_8_0_scalar sp; - rustsecp256k1zkp_v0_8_0_scalar sigr; - rustsecp256k1zkp_v0_8_0_ge enckey_ge; - rustsecp256k1zkp_v0_8_0_gej derived_rp; - rustsecp256k1zkp_v0_8_0_scalar sn, u1, u2; - rustsecp256k1zkp_v0_8_0_gej pubkeyj; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(adaptor_sig162 != NULL); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(enckey != NULL); - - if (!rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig162)) { - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &enckey_ge, enckey)) { - return 0; - } - /* DLEQ_verify((R', Y, R), dleq_proof) */ - if(!rustsecp256k1zkp_v0_8_0_dleq_verify(&dleq_proof_s, &dleq_proof_e, &rp, &enckey_ge, &r)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&msg, msg32, NULL); - if (!rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &pubkey_ge, pubkey)) { - return 0; - } - - /* return R' == s'⁻¹(m * G + R.x * X) */ - rustsecp256k1zkp_v0_8_0_scalar_inverse_var(&sn, &sp); - rustsecp256k1zkp_v0_8_0_scalar_mul(&u1, &sn, &msg); - rustsecp256k1zkp_v0_8_0_scalar_mul(&u2, &sn, &sigr); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&pubkeyj, &pubkey_ge); - rustsecp256k1zkp_v0_8_0_ecmult(&derived_rp, &pubkeyj, &u2, &u1); - if (rustsecp256k1zkp_v0_8_0_gej_is_infinity(&derived_rp)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_gej_neg(&derived_rp, &derived_rp); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&derived_rp, &derived_rp, &rp, NULL); - return rustsecp256k1zkp_v0_8_0_gej_is_infinity(&derived_rp); -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_signature *sig, const unsigned char *deckey32, const unsigned char *adaptor_sig162) { - rustsecp256k1zkp_v0_8_0_scalar deckey; - rustsecp256k1zkp_v0_8_0_scalar sp; - rustsecp256k1zkp_v0_8_0_scalar s; - rustsecp256k1zkp_v0_8_0_scalar sigr; - int overflow; - int high; - int ret = 1; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(deckey32 != NULL); - ARG_CHECK(adaptor_sig162 != NULL); - - rustsecp256k1zkp_v0_8_0_scalar_clear(&sp); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&deckey, deckey32, &overflow); - ret &= !overflow; - ret &= rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(NULL, &sigr, NULL, &sp, NULL, NULL, adaptor_sig162); - ret &= !rustsecp256k1zkp_v0_8_0_scalar_is_zero(&deckey); - rustsecp256k1zkp_v0_8_0_scalar_inverse(&s, &deckey); - /* s = s' * y⁻¹ */ - rustsecp256k1zkp_v0_8_0_scalar_mul(&s, &s, &sp); - high = rustsecp256k1zkp_v0_8_0_scalar_is_high(&s); - rustsecp256k1zkp_v0_8_0_scalar_cond_negate(&s, high); - rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(sig, &sigr, &s); - - rustsecp256k1zkp_v0_8_0_memczero(&sig->data[0], 64, !ret); - rustsecp256k1zkp_v0_8_0_scalar_clear(&deckey); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sp); - rustsecp256k1zkp_v0_8_0_scalar_clear(&s); - - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *deckey32, const rustsecp256k1zkp_v0_8_0_ecdsa_signature *sig, const unsigned char *adaptor_sig162, const rustsecp256k1zkp_v0_8_0_pubkey *enckey) { - rustsecp256k1zkp_v0_8_0_scalar sp, adaptor_sigr; - rustsecp256k1zkp_v0_8_0_scalar s, r; - rustsecp256k1zkp_v0_8_0_scalar deckey; - rustsecp256k1zkp_v0_8_0_ge enckey_expected_ge; - rustsecp256k1zkp_v0_8_0_gej enckey_expected_gej; - unsigned char enckey33[33]; - unsigned char enckey_expected33[33]; - size_t size = 33; - int ret = 1; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(deckey32 != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(adaptor_sig162 != NULL); - ARG_CHECK(enckey != NULL); - - if (!rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(NULL, &adaptor_sigr, NULL, &sp, NULL, NULL, adaptor_sig162)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &r, &s, sig); - /* Check that we're not looking at some unrelated signature */ - ret &= rustsecp256k1zkp_v0_8_0_scalar_eq(&adaptor_sigr, &r); - /* y = s⁻¹ * s' */ - ret &= !rustsecp256k1zkp_v0_8_0_scalar_is_zero(&s); - rustsecp256k1zkp_v0_8_0_scalar_inverse(&deckey, &s); - rustsecp256k1zkp_v0_8_0_scalar_mul(&deckey, &deckey, &sp); - - /* Deal with ECDSA malleability */ - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &enckey_expected_gej, &deckey); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&enckey_expected_ge, &enckey_expected_gej); - /* We declassify non-secret enckey_expected_ge to allow using it as a - * branch point. */ - rustsecp256k1zkp_v0_8_0_declassify(ctx, &enckey_expected_ge, sizeof(enckey_expected_ge)); - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&enckey_expected_ge, enckey_expected33, &size, SECP256K1_EC_COMPRESSED)) { - /* Unreachable from tests (and other VERIFY builds) and therefore this - * branch should be ignored in test coverage analysis. - * - * Proof: - * eckey_pubkey_serialize fails <=> deckey = 0 - * deckey = 0 <=> s^-1 = 0 or sp = 0 - * case 1: s^-1 = 0 impossible by the definition of multiplicative - * inverse and because the scalar_inverse implementation - * VERIFY_CHECKs that the inputs are valid scalars. - * case 2: sp = 0 impossible because ecdsa_adaptor_sig_deserialize would have already failed - */ - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, enckey33, &size, enckey, SECP256K1_EC_COMPRESSED)) { - return 0; - } - if (rustsecp256k1zkp_v0_8_0_memcmp_var(&enckey_expected33[1], &enckey33[1], 32) != 0) { - return 0; - } - if (enckey_expected33[0] != enckey33[0]) { - /* try Y_implied == -Y */ - rustsecp256k1zkp_v0_8_0_scalar_negate(&deckey, &deckey); - } - rustsecp256k1zkp_v0_8_0_scalar_get_b32(deckey32, &deckey); - - rustsecp256k1zkp_v0_8_0_scalar_clear(&deckey); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sp); - rustsecp256k1zkp_v0_8_0_scalar_clear(&s); - - return ret; -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_adaptor/tests_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_adaptor/tests_impl.h deleted file mode 100644 index 21a842fd..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_adaptor/tests_impl.h +++ /dev/null @@ -1,1219 +0,0 @@ -#ifndef SECP256K1_MODULE_ECDSA_ADAPTOR_TESTS_H -#define SECP256K1_MODULE_ECDSA_ADAPTOR_TESTS_H - -#include "../../../include/secp256k1_ecdsa_adaptor.h" - -void rand_scalar(rustsecp256k1zkp_v0_8_0_scalar *scalar) { - unsigned char buf32[32]; - rustsecp256k1zkp_v0_8_0_testrand256(buf32); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(scalar, buf32, NULL); -} - -void rand_point(rustsecp256k1zkp_v0_8_0_ge *point) { - rustsecp256k1zkp_v0_8_0_scalar x; - rustsecp256k1zkp_v0_8_0_gej pointj; - rand_scalar(&x); - - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &pointj, &x); - rustsecp256k1zkp_v0_8_0_ge_set_gej(point, &pointj); -} - -void dleq_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) { - rustsecp256k1zkp_v0_8_0_scalar k1, k2; - - CHECK(rustsecp256k1zkp_v0_8_0_dleq_nonce(&k1, args[0], args[1], args[2], args[3], NULL, args[4]) == 1); - rustsecp256k1zkp_v0_8_0_testrand_flip(args[n_flip], n_bytes); - CHECK(rustsecp256k1zkp_v0_8_0_dleq_nonce(&k2, args[0], args[1], args[2], args[3], NULL, args[4]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&k1, &k2) == 0); -} - -void dleq_tests(void) { - rustsecp256k1zkp_v0_8_0_scalar s, e, sk, k; - rustsecp256k1zkp_v0_8_0_ge gen2, p1, p2; - unsigned char *args[5]; - unsigned char sk32[32]; - unsigned char gen2_33[33]; - unsigned char p1_33[33]; - unsigned char p2_33[33]; - unsigned char aux_rand[32]; - int i; - size_t pubkey_size = 33; - - rand_point(&gen2); - rand_scalar(&sk); - rustsecp256k1zkp_v0_8_0_dleq_pair(&ctx->ecmult_gen_ctx, &p1, &p2, &sk, &gen2); - CHECK(rustsecp256k1zkp_v0_8_0_dleq_prove(ctx, &s, &e, &sk, &gen2, &p1, &p2, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_dleq_verify(&s, &e, &p1, &gen2, &p2) == 1); - - { - rustsecp256k1zkp_v0_8_0_scalar tmp; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&tmp, 1); - CHECK(rustsecp256k1zkp_v0_8_0_dleq_verify(&tmp, &e, &p1, &gen2, &p2) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_dleq_verify(&s, &tmp, &p1, &gen2, &p2) == 0); - } - { - rustsecp256k1zkp_v0_8_0_ge p_tmp; - rand_point(&p_tmp); - CHECK(rustsecp256k1zkp_v0_8_0_dleq_verify(&s, &e, &p_tmp, &gen2, &p2) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_dleq_verify(&s, &e, &p1, &p_tmp, &p2) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_dleq_verify(&s, &e, &p1, &gen2, &p_tmp) == 0); - } - { - rustsecp256k1zkp_v0_8_0_ge p_inf; - rustsecp256k1zkp_v0_8_0_ge_set_infinity(&p_inf); - CHECK(rustsecp256k1zkp_v0_8_0_dleq_prove(ctx, &s, &e, &sk, &p_inf, &p1, &p2, NULL, NULL) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_dleq_prove(ctx, &s, &e, &sk, &gen2, &p_inf, &p2, NULL, NULL) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_dleq_prove(ctx, &s, &e, &sk, &gen2, &p1, &p_inf, NULL, NULL) == 0); - } - - /* Nonce tests */ - rustsecp256k1zkp_v0_8_0_scalar_get_b32(sk32, &sk); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&gen2, gen2_33, &pubkey_size, 1)); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&p1, p1_33, &pubkey_size, 1)); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&p2, p2_33, &pubkey_size, 1)); - CHECK(rustsecp256k1zkp_v0_8_0_dleq_nonce(&k, sk32, gen2_33, p1_33, p2_33, NULL, NULL) == 1); - - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(sk32, sizeof(sk32)); - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(gen2_33, sizeof(gen2_33)); - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(p1_33, sizeof(p1_33)); - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(p2_33, sizeof(p2_33)); - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(aux_rand, sizeof(aux_rand)); - - /* Check that a bitflip in an argument results in different nonces. */ - args[0] = sk32; - args[1] = gen2_33; - args[2] = p1_33; - args[3] = p2_33; - args[4] = aux_rand; - for (i = 0; i < count; i++) { - dleq_nonce_bitflip(args, 0, sizeof(sk32)); - dleq_nonce_bitflip(args, 1, sizeof(gen2_33)); - dleq_nonce_bitflip(args, 2, sizeof(p1_33)); - /* Flip p2 */ - dleq_nonce_bitflip(args, 3, sizeof(p2_33)); - /* Flip p2 again */ - dleq_nonce_bitflip(args, 3, sizeof(p2_33)); - dleq_nonce_bitflip(args, 4, sizeof(aux_rand)); - } - - /* NULL aux_rand argument is allowed. */ - CHECK(rustsecp256k1zkp_v0_8_0_dleq_nonce(&k, sk32, gen2_33, p1_33, p2_33, NULL, NULL) == 1); -} - -void rand_flip_bit(unsigned char *array, size_t n) { - array[rustsecp256k1zkp_v0_8_0_testrand_int(n)] ^= 1 << rustsecp256k1zkp_v0_8_0_testrand_int(8); -} - -/* Helper function for test_ecdsa_adaptor_spec_vectors - * Checks that the adaptor signature is valid for the public and encryption keys. */ -void test_ecdsa_adaptor_spec_vectors_check_verify(const unsigned char *adaptor_sig162, const unsigned char *msg32, const unsigned char *pubkey33, const unsigned char *encryption_key33, int expected) { - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_ge pubkey_ge; - rustsecp256k1zkp_v0_8_0_pubkey encryption_key; - rustsecp256k1zkp_v0_8_0_ge encryption_key_ge; - - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&encryption_key_ge, encryption_key33, 33) == 1); - rustsecp256k1zkp_v0_8_0_pubkey_save(&encryption_key, &encryption_key_ge); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&pubkey_ge, pubkey33, 33) == 1); - rustsecp256k1zkp_v0_8_0_pubkey_save(&pubkey, &pubkey_ge); - - CHECK(expected == rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(ctx, adaptor_sig162, &pubkey, msg32, &encryption_key)); -} - -/* Helper function for test_ecdsa_adaptor_spec_vectors - * Checks that the signature can be decrypted from the adaptor signature and the decryption key. */ -void test_ecdsa_adaptor_spec_vectors_check_decrypt(const unsigned char *adaptor_sig162, const unsigned char *decryption_key32, const unsigned char *signature64, int expected) { - unsigned char signature[64]; - rustsecp256k1zkp_v0_8_0_ecdsa_signature s; - - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(ctx, &s, decryption_key32, adaptor_sig162) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact(ctx, signature, &s) == 1); - - CHECK(expected == !(rustsecp256k1zkp_v0_8_0_memcmp_var(signature, signature64, 64))); -} - -/* Helper function for test_ecdsa_adaptor_spec_vectors - * Checks that the decryption key can be recovered from the adaptor signature, encryption key, and the signature. */ -void test_ecdsa_adaptor_spec_vectors_check_recover(const unsigned char *adaptor_sig162, const unsigned char *encryption_key33, const unsigned char *decryption_key32, const unsigned char *signature64, int expected) { - unsigned char deckey32[32] = { 0 }; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig; - rustsecp256k1zkp_v0_8_0_pubkey encryption_key; - rustsecp256k1zkp_v0_8_0_ge encryption_key_ge; - - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&encryption_key_ge, encryption_key33, 33) == 1); - rustsecp256k1zkp_v0_8_0_pubkey_save(&encryption_key, &encryption_key_ge); - - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact(ctx, &sig, signature64) == 1); - CHECK(expected == rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(ctx, deckey32, &sig, adaptor_sig162, &encryption_key)); - if (decryption_key32 != NULL) { - CHECK(expected == !(rustsecp256k1zkp_v0_8_0_memcmp_var(deckey32, decryption_key32, 32))); - } -} - -/* Helper function for test_ecdsa_adaptor_spec_vectors - * Checks deserialization and serialization. */ -void test_ecdsa_adaptor_spec_vectors_check_serialization(const unsigned char *adaptor_sig162, int expected) { - unsigned char buf[162]; - rustsecp256k1zkp_v0_8_0_scalar dleq_proof_s, dleq_proof_e; - rustsecp256k1zkp_v0_8_0_ge r, rp; - rustsecp256k1zkp_v0_8_0_scalar sp; - rustsecp256k1zkp_v0_8_0_scalar sigr; - - CHECK(expected == rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig162)); - if (expected == 1) { - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_serialize(buf, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(buf, adaptor_sig162, 162) == 0); - } -} - -/* Test vectors according to ECDSA adaptor signature spec. See - * https://github.com/discreetlogcontracts/dlcspecs/blob/596a177375932a47306f07e7385f398f52519a83/test/ecdsa_adaptor.json. */ -void test_ecdsa_adaptor_spec_vectors(void) { - { - /* Test vector 0 */ - /* kind: verification test */ - /* plain valid adaptor signature */ - const unsigned char adaptor_sig[162] = { - 0x03, 0x42, 0x4d, 0x14, 0xa5, 0x47, 0x1c, 0x04, - 0x8a, 0xb8, 0x7b, 0x3b, 0x83, 0xf6, 0x08, 0x5d, - 0x12, 0x5d, 0x58, 0x64, 0x24, 0x9a, 0xe4, 0x29, - 0x7a, 0x57, 0xc8, 0x4e, 0x74, 0x71, 0x0b, 0xb6, - 0x73, 0x02, 0x23, 0xf3, 0x25, 0x04, 0x2f, 0xce, - 0x53, 0x5d, 0x04, 0x0f, 0xee, 0x52, 0xec, 0x13, - 0x23, 0x1b, 0xf7, 0x09, 0xcc, 0xd8, 0x42, 0x33, - 0xc6, 0x94, 0x4b, 0x90, 0x31, 0x7e, 0x62, 0x52, - 0x8b, 0x25, 0x27, 0xdf, 0xf9, 0xd6, 0x59, 0xa9, - 0x6d, 0xb4, 0xc9, 0x9f, 0x97, 0x50, 0x16, 0x83, - 0x08, 0x63, 0x3c, 0x18, 0x67, 0xb7, 0x0f, 0x3a, - 0x18, 0xfb, 0x0f, 0x45, 0x39, 0xa1, 0xae, 0xce, - 0xdc, 0xd1, 0xfc, 0x01, 0x48, 0xfc, 0x22, 0xf3, - 0x6b, 0x63, 0x03, 0x08, 0x3e, 0xce, 0x3f, 0x87, - 0x2b, 0x18, 0xe3, 0x5d, 0x36, 0x8b, 0x39, 0x58, - 0xef, 0xe5, 0xfb, 0x08, 0x1f, 0x77, 0x16, 0x73, - 0x6c, 0xcb, 0x59, 0x8d, 0x26, 0x9a, 0xa3, 0x08, - 0x4d, 0x57, 0xe1, 0x85, 0x5e, 0x1e, 0xa9, 0xa4, - 0x5e, 0xfc, 0x10, 0x46, 0x3b, 0xbf, 0x32, 0xae, - 0x37, 0x80, 0x29, 0xf5, 0x76, 0x3c, 0xeb, 0x40, - 0x17, 0x3f - }; - const unsigned char message_hash[32] = { - 0x81, 0x31, 0xe6, 0xf4, 0xb4, 0x57, 0x54, 0xf2, - 0xc9, 0x0b, 0xd0, 0x66, 0x88, 0xce, 0xea, 0xbc, - 0x0c, 0x45, 0x05, 0x54, 0x60, 0x72, 0x99, 0x28, - 0xb4, 0xee, 0xcf, 0x11, 0x02, 0x6a, 0x9e, 0x2d - }; - const unsigned char pubkey[33] = { - 0x03, 0x5b, 0xe5, 0xe9, 0x47, 0x82, 0x09, 0x67, - 0x4a, 0x96, 0xe6, 0x0f, 0x1f, 0x03, 0x7f, 0x61, - 0x76, 0x54, 0x0f, 0xd0, 0x01, 0xfa, 0x1d, 0x64, - 0x69, 0x47, 0x70, 0xc5, 0x6a, 0x77, 0x09, 0xc4, - 0x2c - }; - const unsigned char encryption_key[33] = { - 0x02, 0xc2, 0x66, 0x2c, 0x97, 0x48, 0x8b, 0x07, - 0xb6, 0xe8, 0x19, 0x12, 0x4b, 0x89, 0x89, 0x84, - 0x92, 0x06, 0x33, 0x4a, 0x4c, 0x2f, 0xbd, 0xf6, - 0x91, 0xf7, 0xb3, 0x4d, 0x2b, 0x16, 0xe9, 0xc2, - 0x93 - }; - const unsigned char decryption_key[32] = { - 0x0b, 0x2a, 0xba, 0x63, 0xb8, 0x85, 0xa0, 0xf0, - 0xe9, 0x6f, 0xa0, 0xf3, 0x03, 0x92, 0x0c, 0x7f, - 0xb7, 0x43, 0x1d, 0xdf, 0xa9, 0x43, 0x76, 0xad, - 0x94, 0xd9, 0x69, 0xfb, 0xf4, 0x10, 0x9d, 0xc8 - }; - const unsigned char signature[64] = { - 0x42, 0x4d, 0x14, 0xa5, 0x47, 0x1c, 0x04, 0x8a, - 0xb8, 0x7b, 0x3b, 0x83, 0xf6, 0x08, 0x5d, 0x12, - 0x5d, 0x58, 0x64, 0x24, 0x9a, 0xe4, 0x29, 0x7a, - 0x57, 0xc8, 0x4e, 0x74, 0x71, 0x0b, 0xb6, 0x73, - 0x29, 0xe8, 0x0e, 0x0e, 0xe6, 0x0e, 0x57, 0xaf, - 0x3e, 0x62, 0x5b, 0xba, 0xe1, 0x67, 0x2b, 0x1e, - 0xca, 0xa5, 0x8e, 0xff, 0xe6, 0x13, 0x42, 0x6b, - 0x02, 0x4f, 0xa1, 0x62, 0x1d, 0x90, 0x33, 0x94 - }; - test_ecdsa_adaptor_spec_vectors_check_verify(adaptor_sig, message_hash, pubkey, encryption_key, 1); - test_ecdsa_adaptor_spec_vectors_check_decrypt(adaptor_sig, decryption_key, signature, 1); - test_ecdsa_adaptor_spec_vectors_check_recover(adaptor_sig, encryption_key, decryption_key, signature, 1); - } - { - /* Test vector 1 */ - /* verification test */ - /* the decrypted signature is high so it must be negated first - * AND the extracted decryption key must be negated */ - const unsigned char adaptor_sig[162] = { - 0x03, 0x60, 0x35, 0xc8, 0x98, 0x60, 0xec, 0x62, - 0xad, 0x15, 0x3f, 0x69, 0xb5, 0xb3, 0x07, 0x7b, - 0xcd, 0x08, 0xfb, 0xb0, 0xd2, 0x8d, 0xc7, 0xf7, - 0xf6, 0xdf, 0x4a, 0x05, 0xcc, 0xa3, 0x54, 0x55, - 0xbe, 0x03, 0x70, 0x43, 0xb6, 0x3c, 0x56, 0xf6, - 0x31, 0x7d, 0x99, 0x28, 0xe8, 0xf9, 0x10, 0x07, - 0x33, 0x57, 0x48, 0xc4, 0x98, 0x24, 0x22, 0x0d, - 0xb1, 0x4a, 0xd1, 0x0d, 0x80, 0xa5, 0xd0, 0x0a, - 0x96, 0x54, 0xaf, 0x09, 0x96, 0xc1, 0x82, 0x4c, - 0x64, 0xc9, 0x0b, 0x95, 0x1b, 0xb2, 0x73, 0x4a, - 0xae, 0xcf, 0x78, 0xd4, 0xb3, 0x61, 0x31, 0xa4, - 0x72, 0x38, 0xc3, 0xfa, 0x2b, 0xa2, 0x5e, 0x2c, - 0xed, 0x54, 0x25, 0x5b, 0x06, 0xdf, 0x69, 0x6d, - 0xe1, 0x48, 0x3c, 0x37, 0x67, 0x24, 0x2a, 0x37, - 0x28, 0x82, 0x6e, 0x05, 0xf7, 0x9e, 0x39, 0x81, - 0xe1, 0x25, 0x53, 0x35, 0x5b, 0xba, 0x8a, 0x01, - 0x31, 0xcd, 0x37, 0x0e, 0x63, 0xe3, 0xda, 0x73, - 0x10, 0x6f, 0x63, 0x85, 0x76, 0xa5, 0xaa, 0xb0, - 0xea, 0x6d, 0x45, 0xc0, 0x42, 0x57, 0x4c, 0x0c, - 0x8d, 0x0b, 0x14, 0xb8, 0xc7, 0xc0, 0x1c, 0xfe, - 0x90, 0x72 - }; - const unsigned char message_hash[32] = { - 0x81, 0x31, 0xe6, 0xf4, 0xb4, 0x57, 0x54, 0xf2, - 0xc9, 0x0b, 0xd0, 0x66, 0x88, 0xce, 0xea, 0xbc, - 0x0c, 0x45, 0x05, 0x54, 0x60, 0x72, 0x99, 0x28, - 0xb4, 0xee, 0xcf, 0x11, 0x02, 0x6a, 0x9e, 0x2d - }; - const unsigned char pubkey[33] = { - 0x03, 0x5b, 0xe5, 0xe9, 0x47, 0x82, 0x09, 0x67, - 0x4a, 0x96, 0xe6, 0x0f, 0x1f, 0x03, 0x7f, 0x61, - 0x76, 0x54, 0x0f, 0xd0, 0x01, 0xfa, 0x1d, 0x64, - 0x69, 0x47, 0x70, 0xc5, 0x6a, 0x77, 0x09, 0xc4, - 0x2c - }; - const unsigned char encryption_key[33] = { - 0x02, 0x4e, 0xee, 0x18, 0xbe, 0x9a, 0x5a, 0x52, - 0x24, 0x00, 0x0f, 0x91, 0x6c, 0x80, 0xb3, 0x93, - 0x44, 0x79, 0x89, 0xe7, 0x19, 0x4b, 0xc0, 0xb0, - 0xf1, 0xad, 0x7a, 0x03, 0x36, 0x97, 0x02, 0xbb, - 0x51 - }; - const unsigned char decryption_key[32] = { - 0xdb, 0x2d, 0xeb, 0xdd, 0xb0, 0x02, 0x47, 0x3a, - 0x00, 0x1d, 0xd7, 0x0b, 0x06, 0xf6, 0xc9, 0x7b, - 0xdc, 0xd1, 0xc4, 0x6b, 0xa1, 0x00, 0x12, 0x37, - 0xfe, 0x0e, 0xe1, 0xae, 0xff, 0xb2, 0xb6, 0xc4 - }; - const unsigned char signature[64] = { - 0x60, 0x35, 0xc8, 0x98, 0x60, 0xec, 0x62, 0xad, - 0x15, 0x3f, 0x69, 0xb5, 0xb3, 0x07, 0x7b, 0xcd, - 0x08, 0xfb, 0xb0, 0xd2, 0x8d, 0xc7, 0xf7, 0xf6, - 0xdf, 0x4a, 0x05, 0xcc, 0xa3, 0x54, 0x55, 0xbe, - 0x4c, 0xea, 0xcf, 0x92, 0x15, 0x46, 0xc0, 0x3d, - 0xd1, 0xbe, 0x59, 0x67, 0x23, 0xad, 0x1e, 0x76, - 0x91, 0xbd, 0xac, 0x73, 0xd8, 0x8c, 0xc3, 0x6c, - 0x42, 0x1c, 0x5e, 0x7f, 0x08, 0x38, 0x43, 0x05 - }; - test_ecdsa_adaptor_spec_vectors_check_verify(adaptor_sig, message_hash, pubkey, encryption_key, 1); - test_ecdsa_adaptor_spec_vectors_check_decrypt(adaptor_sig, decryption_key, signature, 1); - test_ecdsa_adaptor_spec_vectors_check_recover(adaptor_sig, encryption_key, decryption_key, signature, 1); - } - { - /* Test vector 2 */ - /* verification test */ - /* proof is wrong */ - const unsigned char adaptor_sig[162] = { - 0x03, 0xf9, 0x4d, 0xca, 0x20, 0x6d, 0x75, 0x82, - 0xc0, 0x15, 0xfb, 0x9b, 0xff, 0xe4, 0xe4, 0x3b, - 0x14, 0x59, 0x1b, 0x30, 0xef, 0x7d, 0x2b, 0x46, - 0x4d, 0x10, 0x3e, 0xc5, 0xe1, 0x16, 0x59, 0x5d, - 0xba, 0x03, 0x12, 0x7f, 0x8a, 0xc3, 0x53, 0x3d, - 0x24, 0x92, 0x80, 0x33, 0x24, 0x74, 0x33, 0x90, - 0x00, 0x92, 0x2e, 0xb6, 0xa5, 0x8e, 0x3b, 0x9b, - 0xf4, 0xfc, 0x7e, 0x01, 0xe4, 0xb4, 0xdf, 0x2b, - 0x7a, 0x41, 0x00, 0xa1, 0xe0, 0x89, 0xf1, 0x6e, - 0x5d, 0x70, 0xbb, 0x89, 0xf9, 0x61, 0x51, 0x6f, - 0x1d, 0xe0, 0x68, 0x4c, 0xc7, 0x9d, 0xb9, 0x78, - 0x49, 0x5d, 0xf2, 0xf3, 0x99, 0xb0, 0xd0, 0x1e, - 0xd7, 0x24, 0x0f, 0xa6, 0xe3, 0x25, 0x2a, 0xed, - 0xb5, 0x8b, 0xdc, 0x6b, 0x58, 0x77, 0xb0, 0xc6, - 0x02, 0x62, 0x8a, 0x23, 0x5d, 0xd1, 0xcc, 0xae, - 0xbd, 0xdd, 0xcb, 0xe9, 0x61, 0x98, 0xc0, 0xc2, - 0x1b, 0xea, 0xd7, 0xb0, 0x5f, 0x42, 0x3b, 0x67, - 0x3d, 0x14, 0xd2, 0x06, 0xfa, 0x15, 0x07, 0xb2, - 0xdb, 0xe2, 0x72, 0x2a, 0xf7, 0x92, 0xb8, 0xc2, - 0x66, 0xfc, 0x25, 0xa2, 0xd9, 0x01, 0xd7, 0xe2, - 0xc3, 0x35 - }; - const unsigned char message_hash[32] = { - 0x81, 0x31, 0xe6, 0xf4, 0xb4, 0x57, 0x54, 0xf2, - 0xc9, 0x0b, 0xd0, 0x66, 0x88, 0xce, 0xea, 0xbc, - 0x0c, 0x45, 0x05, 0x54, 0x60, 0x72, 0x99, 0x28, - 0xb4, 0xee, 0xcf, 0x11, 0x02, 0x6a, 0x9e, 0x2d - }; - const unsigned char pubkey[33] = { - 0x03, 0x5b, 0xe5, 0xe9, 0x47, 0x82, 0x09, 0x67, - 0x4a, 0x96, 0xe6, 0x0f, 0x1f, 0x03, 0x7f, 0x61, - 0x76, 0x54, 0x0f, 0xd0, 0x01, 0xfa, 0x1d, 0x64, - 0x69, 0x47, 0x70, 0xc5, 0x6a, 0x77, 0x09, 0xc4, - 0x2c - }; - const unsigned char encryption_key[33] = { - 0x02, 0x14, 0xcc, 0xb7, 0x56, 0x24, 0x9a, 0xd6, - 0xe7, 0x33, 0xc8, 0x02, 0x85, 0xea, 0x7a, 0xc2, - 0xee, 0x12, 0xff, 0xeb, 0xbc, 0xee, 0x4e, 0x55, - 0x6e, 0x68, 0x10, 0x79, 0x3a, 0x60, 0xc4, 0x5a, - 0xd4 - }; - const unsigned char decryption_key[32] = { - 0x1d, 0xfc, 0xfc, 0x08, 0x80, 0xe7, 0x25, 0x09, - 0x76, 0x8a, 0xb4, 0x6f, 0x25, 0x45, 0xb3, 0x31, - 0x68, 0xb8, 0xb8, 0xdf, 0x8e, 0x4f, 0x5f, 0xeb, - 0x50, 0x59, 0xaa, 0x37, 0x50, 0xee, 0x59, 0xd0 - }; - const unsigned char signature[64] = { - 0x42, 0x4d, 0x14, 0xa5, 0x47, 0x1c, 0x04, 0x8a, - 0xb8, 0x7b, 0x3b, 0x83, 0xf6, 0x08, 0x5d, 0x12, - 0x5d, 0x58, 0x64, 0x24, 0x9a, 0xe4, 0x29, 0x7a, - 0x57, 0xc8, 0x4e, 0x74, 0x71, 0x0b, 0xb6, 0x73, - 0x29, 0xe8, 0x0e, 0x0e, 0xe6, 0x0e, 0x57, 0xaf, - 0x3e, 0x62, 0x5b, 0xba, 0xe1, 0x67, 0x2b, 0x1e, - 0xca, 0xa5, 0x8e, 0xff, 0xe6, 0x13, 0x42, 0x6b, - 0x02, 0x4f, 0xa1, 0x62, 0x1d, 0x90, 0x33, 0x94 - }; - test_ecdsa_adaptor_spec_vectors_check_verify(adaptor_sig, message_hash, pubkey, encryption_key, 0); - test_ecdsa_adaptor_spec_vectors_check_decrypt(adaptor_sig, decryption_key, signature, 0); - test_ecdsa_adaptor_spec_vectors_check_recover(adaptor_sig, encryption_key, decryption_key, signature, 0); - } - { - /* Test vector 3 */ - /* recovery test */ - /* plain recovery */ - const unsigned char adaptor_sig[162] = { - 0x03, 0xf2, 0xdb, 0x6e, 0x9e, 0xd3, 0x30, 0x92, - 0xcc, 0x0b, 0x89, 0x8f, 0xd6, 0xb2, 0x82, 0xe9, - 0x9b, 0xda, 0xec, 0xcb, 0x3d, 0xe8, 0x5c, 0x2d, - 0x25, 0x12, 0xd8, 0xd5, 0x07, 0xf9, 0xab, 0xab, - 0x29, 0x02, 0x10, 0xc0, 0x1b, 0x5b, 0xed, 0x70, - 0x94, 0xa1, 0x26, 0x64, 0xae, 0xaa, 0xb3, 0x40, - 0x2d, 0x87, 0x09, 0xa8, 0xf3, 0x62, 0xb1, 0x40, - 0x32, 0x8d, 0x1b, 0x36, 0xdd, 0x7c, 0xb4, 0x20, - 0xd0, 0x2f, 0xb6, 0x6b, 0x12, 0x30, 0xd6, 0x1c, - 0x16, 0xd0, 0xcd, 0x0a, 0x2a, 0x02, 0x24, 0x6d, - 0x5a, 0xc7, 0x84, 0x8d, 0xcd, 0x6f, 0x04, 0xfe, - 0x62, 0x70, 0x53, 0xcd, 0x3c, 0x70, 0x15, 0xa7, - 0xd4, 0xaa, 0x6a, 0xc2, 0xb0, 0x43, 0x47, 0x34, - 0x8b, 0xd6, 0x7d, 0xa4, 0x3b, 0xe8, 0x72, 0x25, - 0x15, 0xd9, 0x9a, 0x79, 0x85, 0xfb, 0xfa, 0x66, - 0xf0, 0x36, 0x5c, 0x70, 0x1d, 0xe7, 0x6f, 0xf0, - 0x40, 0x0d, 0xff, 0xdc, 0x9f, 0xa8, 0x4d, 0xdd, - 0xf4, 0x13, 0xa7, 0x29, 0x82, 0x3b, 0x16, 0xaf, - 0x60, 0xaa, 0x63, 0x61, 0xbc, 0x32, 0xe7, 0xcf, - 0xd6, 0x70, 0x1e, 0x32, 0x95, 0x7c, 0x72, 0xac, - 0xe6, 0x7b - }; - const unsigned char encryption_key[33] = { - 0x02, 0x7e, 0xe4, 0xf8, 0x99, 0xbc, 0x9c, 0x5f, - 0x2b, 0x62, 0x6f, 0xa1, 0xa9, 0xb3, 0x7c, 0xe2, - 0x91, 0xc0, 0x38, 0x8b, 0x52, 0x27, 0xe9, 0x0b, - 0x0f, 0xd8, 0xf4, 0xfa, 0x57, 0x61, 0x64, 0xed, - 0xe7 - }; - const unsigned char decryption_key[32] = { - 0x9c, 0xf3, 0xea, 0x9b, 0xe5, 0x94, 0x36, 0x6b, - 0x78, 0xc4, 0x57, 0x16, 0x29, 0x08, 0xaf, 0x3c, - 0x2e, 0xa1, 0x77, 0x05, 0x81, 0x77, 0xe9, 0xc6, - 0xbf, 0x99, 0x04, 0x79, 0x27, 0x77, 0x3a, 0x06 - }; - const unsigned char signature[64] = { - 0xf2, 0xdb, 0x6e, 0x9e, 0xd3, 0x30, 0x92, 0xcc, - 0x0b, 0x89, 0x8f, 0xd6, 0xb2, 0x82, 0xe9, 0x9b, - 0xda, 0xec, 0xcb, 0x3d, 0xe8, 0x5c, 0x2d, 0x25, - 0x12, 0xd8, 0xd5, 0x07, 0xf9, 0xab, 0xab, 0x29, - 0x21, 0x81, 0x1f, 0xe7, 0xb5, 0x3b, 0xec, 0xf3, - 0xb7, 0xaf, 0xfa, 0x94, 0x42, 0xab, 0xaa, 0x93, - 0xc0, 0xab, 0x8a, 0x8e, 0x45, 0xcd, 0x7e, 0xe2, - 0xea, 0x8d, 0x25, 0x8b, 0xfc, 0x25, 0xd4, 0x64 - }; - test_ecdsa_adaptor_spec_vectors_check_decrypt(adaptor_sig, decryption_key, signature, 1); - test_ecdsa_adaptor_spec_vectors_check_recover(adaptor_sig, encryption_key, decryption_key, signature, 1); - } - { - /* Test vector 4 */ - /* recovery test */ - /* the R value of the signature does not match */ - const unsigned char adaptor_sig[162] = { - 0x03, 0xaa, 0x86, 0xd7, 0x80, 0x59, 0xa9, 0x10, - 0x59, 0xc2, 0x9e, 0xc1, 0xa7, 0x57, 0xc4, 0xdc, - 0x02, 0x9f, 0xf6, 0x36, 0xa1, 0xe6, 0xc1, 0x14, - 0x2f, 0xef, 0xe1, 0xe9, 0xd7, 0x33, 0x96, 0x17, - 0xc0, 0x03, 0xa8, 0x15, 0x3e, 0x50, 0xc0, 0xc8, - 0x57, 0x4a, 0x38, 0xd3, 0x89, 0xe6, 0x1b, 0xbb, - 0x0b, 0x58, 0x15, 0x16, 0x9e, 0x06, 0x09, 0x24, - 0xe4, 0xb5, 0xf2, 0xe7, 0x8f, 0xf1, 0x3a, 0xa7, - 0xad, 0x85, 0x8e, 0x0c, 0x27, 0xc4, 0xb9, 0xee, - 0xd9, 0xd6, 0x05, 0x21, 0xb3, 0xf5, 0x4f, 0xf8, - 0x3c, 0xa4, 0x77, 0x4b, 0xe5, 0xfb, 0x3a, 0x68, - 0x0f, 0x82, 0x0a, 0x35, 0xe8, 0x84, 0x0f, 0x4a, - 0xaf, 0x2d, 0xe8, 0x8e, 0x7c, 0x5c, 0xff, 0x38, - 0xa3, 0x7b, 0x78, 0x72, 0x59, 0x04, 0xef, 0x97, - 0xbb, 0x82, 0x34, 0x13, 0x28, 0xd5, 0x59, 0x87, - 0x01, 0x9b, 0xd3, 0x8a, 0xe1, 0x74, 0x5e, 0x3e, - 0xfe, 0x0f, 0x8e, 0xa8, 0xbd, 0xfe, 0xde, 0x0d, - 0x37, 0x8f, 0xc1, 0xf9, 0x6e, 0x94, 0x4a, 0x75, - 0x05, 0x24, 0x9f, 0x41, 0xe9, 0x37, 0x81, 0x50, - 0x9e, 0xe0, 0xba, 0xde, 0x77, 0x29, 0x0d, 0x39, - 0xcd, 0x12 - }; - const unsigned char encryption_key[33] = { - 0x03, 0x51, 0x76, 0xd2, 0x41, 0x29, 0x74, 0x1b, - 0x0f, 0xca, 0xa5, 0xfd, 0x67, 0x50, 0x72, 0x7c, - 0xe3, 0x08, 0x60, 0x44, 0x7e, 0x0a, 0x92, 0xc9, - 0xeb, 0xeb, 0xde, 0xb7, 0xc3, 0xf9, 0x39, 0x95, - 0xed - }; - const unsigned char signature[64] = { - 0xf7, 0xf7, 0xfe, 0x6b, 0xd0, 0x56, 0xfc, 0x4a, - 0xbd, 0x70, 0xd3, 0x35, 0xf7, 0x2d, 0x0a, 0xa1, - 0xe8, 0x40, 0x6b, 0xba, 0x68, 0xf3, 0xe5, 0x79, - 0xe4, 0x78, 0x94, 0x75, 0x32, 0x35, 0x64, 0xa4, - 0x52, 0xc4, 0x61, 0x76, 0xc7, 0xfb, 0x40, 0xaa, - 0x37, 0xd5, 0x65, 0x13, 0x41, 0xf5, 0x56, 0x97, - 0xda, 0xb2, 0x7d, 0x84, 0xa2, 0x13, 0xb3, 0x0c, - 0x93, 0x01, 0x1a, 0x77, 0x90, 0xba, 0xce, 0x8c - }; - test_ecdsa_adaptor_spec_vectors_check_recover(adaptor_sig, encryption_key, NULL, signature, 0); - } - { - /* Test vector 5 */ - /* recovery test */ - /* recovery from high s signature */ - const unsigned char adaptor_sig[162] = { - 0x03, 0x2c, 0x63, 0x7c, 0xd7, 0x97, 0xdd, 0x8c, - 0x2c, 0xe2, 0x61, 0x90, 0x7e, 0xd4, 0x3e, 0x82, - 0xd6, 0xd1, 0xa4, 0x8c, 0xba, 0xbb, 0xbe, 0xce, - 0x80, 0x11, 0x33, 0xdd, 0x8d, 0x70, 0xa0, 0x1b, - 0x14, 0x03, 0xeb, 0x61, 0x5a, 0x3e, 0x59, 0xb1, - 0xcb, 0xbf, 0x4f, 0x87, 0xac, 0xaf, 0x64, 0x5b, - 0xe1, 0xed, 0xa3, 0x2a, 0x06, 0x66, 0x11, 0xf3, - 0x5d, 0xd5, 0x55, 0x78, 0x02, 0x80, 0x2b, 0x14, - 0xb1, 0x9c, 0x81, 0xc0, 0x4c, 0x3f, 0xef, 0xac, - 0x57, 0x83, 0xb2, 0x07, 0x7b, 0xd4, 0x3f, 0xa0, - 0xa3, 0x9a, 0xb8, 0xa6, 0x4d, 0x4d, 0x78, 0x33, - 0x2a, 0x5d, 0x62, 0x1e, 0xa2, 0x3e, 0xca, 0x46, - 0xbc, 0x01, 0x10, 0x11, 0xab, 0x82, 0xdd, 0xa6, - 0xde, 0xb8, 0x56, 0x99, 0xf5, 0x08, 0x74, 0x4d, - 0x70, 0xd4, 0x13, 0x4b, 0xea, 0x03, 0xf7, 0x84, - 0xd2, 0x85, 0xb5, 0xc6, 0xc1, 0x5a, 0x56, 0xe4, - 0xe1, 0xfa, 0xb4, 0xbc, 0x35, 0x6a, 0xbb, 0xde, - 0xbb, 0x3b, 0x8f, 0xe1, 0xe5, 0x5e, 0x6d, 0xd6, - 0xd2, 0xa9, 0xea, 0x45, 0x7e, 0x91, 0xb2, 0xe6, - 0x64, 0x2f, 0xae, 0x69, 0xf9, 0xdb, 0xb5, 0x25, - 0x88, 0x54 - }; - const unsigned char encryption_key[33] = { - 0x02, 0x04, 0x25, 0x37, 0xe9, 0x13, 0xad, 0x74, - 0xc4, 0xbb, 0xd8, 0xda, 0x96, 0x07, 0xad, 0x3b, - 0x9c, 0xb2, 0x97, 0xd0, 0x8e, 0x01, 0x4a, 0xfc, - 0x51, 0x13, 0x30, 0x83, 0xf1, 0xbd, 0x68, 0x7a, - 0x62 - }; - const unsigned char decryption_key[32] = { - 0x32, 0x47, 0x19, 0xb5, 0x1f, 0xf2, 0x47, 0x4c, - 0x94, 0x38, 0xeb, 0x76, 0x49, 0x4b, 0x0d, 0xc0, - 0xbc, 0xce, 0xeb, 0x52, 0x9f, 0x0a, 0x54, 0x28, - 0xfd, 0x19, 0x8a, 0xd8, 0xf8, 0x86, 0xe9, 0x9c - }; - const unsigned char signature[64] = { - 0x2c, 0x63, 0x7c, 0xd7, 0x97, 0xdd, 0x8c, 0x2c, - 0xe2, 0x61, 0x90, 0x7e, 0xd4, 0x3e, 0x82, 0xd6, - 0xd1, 0xa4, 0x8c, 0xba, 0xbb, 0xbe, 0xce, 0x80, - 0x11, 0x33, 0xdd, 0x8d, 0x70, 0xa0, 0x1b, 0x14, - 0xb5, 0xf2, 0x43, 0x21, 0xf5, 0x50, 0xb7, 0xb9, - 0xdd, 0x06, 0xee, 0x4f, 0xcf, 0xd8, 0x2b, 0xda, - 0xd8, 0xb1, 0x42, 0xff, 0x93, 0xa7, 0x90, 0xcc, - 0x4d, 0x9f, 0x79, 0x62, 0xb3, 0x8c, 0x6a, 0x3b - }; - test_ecdsa_adaptor_spec_vectors_check_decrypt(adaptor_sig, decryption_key, signature, 0); - test_ecdsa_adaptor_spec_vectors_check_recover(adaptor_sig, encryption_key, decryption_key, signature, 1); - } - { - /* Test vector 6 */ - /* serialization test */ - const unsigned char adaptor_sig[162] = { - 0x03, 0xe6, 0xd5, 0x1d, 0xa7, 0xbc, 0x2b, 0xf2, - 0x4c, 0xf9, 0xdf, 0xd9, 0xac, 0xc6, 0xc4, 0xf0, - 0xa3, 0xe7, 0x4d, 0x8a, 0x62, 0x73, 0xee, 0x5a, - 0x57, 0x3e, 0xd6, 0x81, 0x8e, 0x30, 0x95, 0xb6, - 0x09, 0x03, 0xf3, 0x3b, 0xc9, 0x8f, 0x9d, 0x2e, - 0xa3, 0x51, 0x1f, 0x2e, 0x24, 0xf3, 0x35, 0x85, - 0x57, 0xc8, 0x15, 0xab, 0xd7, 0x71, 0x3c, 0x93, - 0x18, 0xaf, 0x9f, 0x4d, 0xfa, 0xb4, 0x44, 0x18, - 0x98, 0xec, 0xd6, 0x19, 0xac, 0xb1, 0xcb, 0x75, - 0xc1, 0xa5, 0x94, 0x6f, 0xba, 0xf7, 0x16, 0xd2, - 0x27, 0x19, 0x9a, 0x64, 0x79, 0xa6, 0x78, 0xd1, - 0x0a, 0x6d, 0x95, 0x51, 0x2d, 0x67, 0x4f, 0xb7, - 0x70, 0x3d, 0x85, 0xb5, 0x89, 0x80, 0xb8, 0xe6, - 0xc5, 0x4b, 0xd2, 0x06, 0x16, 0xbd, 0xb9, 0x46, - 0x1d, 0xcc, 0xd8, 0xee, 0xbb, 0x7d, 0x7e, 0x7c, - 0x83, 0xa9, 0x14, 0x52, 0xcc, 0x20, 0xed, 0xf5, - 0x3b, 0xe5, 0xb0, 0xfe, 0x0d, 0xb4, 0x4d, 0xdd, - 0xaa, 0xaf, 0xbe, 0x73, 0x76, 0x78, 0xc6, 0x84, - 0xb6, 0xe8, 0x9b, 0x9b, 0x4b, 0x67, 0x9b, 0x18, - 0x55, 0xaa, 0x6e, 0xd6, 0x44, 0x49, 0x8b, 0x89, - 0xc9, 0x18 - }; - test_ecdsa_adaptor_spec_vectors_check_serialization(adaptor_sig, 1); - } - { - /* Test vector 7 */ - /* serialization test */ - /* R can be above curve order */ - const unsigned char adaptor_sig[162] = { - 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, - 0x2c, 0x03, 0xf3, 0x3b, 0xc9, 0x8f, 0x9d, 0x2e, - 0xa3, 0x51, 0x1f, 0x2e, 0x24, 0xf3, 0x35, 0x85, - 0x57, 0xc8, 0x15, 0xab, 0xd7, 0x71, 0x3c, 0x93, - 0x18, 0xaf, 0x9f, 0x4d, 0xfa, 0xb4, 0x44, 0x18, - 0x98, 0xec, 0xd6, 0x19, 0xac, 0xb1, 0xcb, 0x75, - 0xc1, 0xa5, 0x94, 0x6f, 0xba, 0xf7, 0x16, 0xd2, - 0x27, 0x19, 0x9a, 0x64, 0x79, 0xa6, 0x78, 0xd1, - 0x0a, 0x6d, 0x95, 0x51, 0x2d, 0x67, 0x4f, 0xb7, - 0x70, 0x3d, 0x85, 0xb5, 0x89, 0x80, 0xb8, 0xe6, - 0xc5, 0x4b, 0xd2, 0x06, 0x16, 0xbd, 0xb9, 0x46, - 0x1d, 0xcc, 0xd8, 0xee, 0xbb, 0x7d, 0x7e, 0x7c, - 0x83, 0xa9, 0x14, 0x52, 0xcc, 0x20, 0xed, 0xf5, - 0x3b, 0xe5, 0xb0, 0xfe, 0x0d, 0xb4, 0x4d, 0xdd, - 0xaa, 0xaf, 0xbe, 0x73, 0x76, 0x78, 0xc6, 0x84, - 0xb6, 0xe8, 0x9b, 0x9b, 0x4b, 0x67, 0x9b, 0x18, - 0x55, 0xaa, 0x6e, 0xd6, 0x44, 0x49, 0x8b, 0x89, - 0xc9, 0x18 - }; - test_ecdsa_adaptor_spec_vectors_check_serialization(adaptor_sig, 1); - } - { - /* Test vector 8 */ - /* serialization test */ - /* R_a can be above curve order */ - const unsigned char adaptor_sig[162] = { - 0x03, 0xe6, 0xd5, 0x1d, 0xa7, 0xbc, 0x2b, 0xf2, - 0x4c, 0xf9, 0xdf, 0xd9, 0xac, 0xc6, 0xc4, 0xf0, - 0xa3, 0xe7, 0x4d, 0x8a, 0x62, 0x73, 0xee, 0x5a, - 0x57, 0x3e, 0xd6, 0x81, 0x8e, 0x30, 0x95, 0xb6, - 0x09, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xfc, 0x2c, 0xd6, 0x19, 0xac, 0xb1, 0xcb, 0x75, - 0xc1, 0xa5, 0x94, 0x6f, 0xba, 0xf7, 0x16, 0xd2, - 0x27, 0x19, 0x9a, 0x64, 0x79, 0xa6, 0x78, 0xd1, - 0x0a, 0x6d, 0x95, 0x51, 0x2d, 0x67, 0x4f, 0xb7, - 0x70, 0x3d, 0x85, 0xb5, 0x89, 0x80, 0xb8, 0xe6, - 0xc5, 0x4b, 0xd2, 0x06, 0x16, 0xbd, 0xb9, 0x46, - 0x1d, 0xcc, 0xd8, 0xee, 0xbb, 0x7d, 0x7e, 0x7c, - 0x83, 0xa9, 0x14, 0x52, 0xcc, 0x20, 0xed, 0xf5, - 0x3b, 0xe5, 0xb0, 0xfe, 0x0d, 0xb4, 0x4d, 0xdd, - 0xaa, 0xaf, 0xbe, 0x73, 0x76, 0x78, 0xc6, 0x84, - 0xb6, 0xe8, 0x9b, 0x9b, 0x4b, 0x67, 0x9b, 0x18, - 0x55, 0xaa, 0x6e, 0xd6, 0x44, 0x49, 0x8b, 0x89, - 0xc9, 0x18 - }; - test_ecdsa_adaptor_spec_vectors_check_serialization(adaptor_sig, 1); - } - { - /* Test vector 9 */ - /* serialization test */ - /* s_a cannot be zero */ - const unsigned char adaptor_sig[162] = { - 0x03, 0xe6, 0xd5, 0x1d, 0xa7, 0xbc, 0x2b, 0xf2, - 0x4c, 0xf9, 0xdf, 0xd9, 0xac, 0xc6, 0xc4, 0xf0, - 0xa3, 0xe7, 0x4d, 0x8a, 0x62, 0x73, 0xee, 0x5a, - 0x57, 0x3e, 0xd6, 0x81, 0x8e, 0x30, 0x95, 0xb6, - 0x09, 0x03, 0xf3, 0x3b, 0xc9, 0x8f, 0x9d, 0x2e, - 0xa3, 0x51, 0x1f, 0x2e, 0x24, 0xf3, 0x35, 0x85, - 0x57, 0xc8, 0x15, 0xab, 0xd7, 0x71, 0x3c, 0x93, - 0x18, 0xaf, 0x9f, 0x4d, 0xfa, 0xb4, 0x44, 0x18, - 0x98, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x85, 0xb5, 0x89, 0x80, 0xb8, 0xe6, - 0xc5, 0x4b, 0xd2, 0x06, 0x16, 0xbd, 0xb9, 0x46, - 0x1d, 0xcc, 0xd8, 0xee, 0xbb, 0x7d, 0x7e, 0x7c, - 0x83, 0xa9, 0x14, 0x52, 0xcc, 0x20, 0xed, 0xf5, - 0x3b, 0xe5, 0xb0, 0xfe, 0x0d, 0xb4, 0x4d, 0xdd, - 0xaa, 0xaf, 0xbe, 0x73, 0x76, 0x78, 0xc6, 0x84, - 0xb6, 0xe8, 0x9b, 0x9b, 0x4b, 0x67, 0x9b, 0x18, - 0x55, 0xaa, 0x6e, 0xd6, 0x44, 0x49, 0x8b, 0x89, - 0xc9, 0x18 - }; - test_ecdsa_adaptor_spec_vectors_check_serialization(adaptor_sig, 0); - } - { - /* Test vector 10 */ - /* serialization test */ - /* s_a too high */ - const unsigned char adaptor_sig[162] = { - 0x03, 0xe6, 0xd5, 0x1d, 0xa7, 0xbc, 0x2b, 0xf2, - 0x4c, 0xf9, 0xdf, 0xd9, 0xac, 0xc6, 0xc4, 0xf0, - 0xa3, 0xe7, 0x4d, 0x8a, 0x62, 0x73, 0xee, 0x5a, - 0x57, 0x3e, 0xd6, 0x81, 0x8e, 0x30, 0x95, 0xb6, - 0x09, 0x03, 0xf3, 0x3b, 0xc9, 0x8f, 0x9d, 0x2e, - 0xa3, 0x51, 0x1f, 0x2e, 0x24, 0xf3, 0x35, 0x85, - 0x57, 0xc8, 0x15, 0xab, 0xd7, 0x71, 0x3c, 0x93, - 0x18, 0xaf, 0x9f, 0x4d, 0xfa, 0xb4, 0x44, 0x18, - 0x98, 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, - 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, - 0x41, 0x41, 0x85, 0xb5, 0x89, 0x80, 0xb8, 0xe6, - 0xc5, 0x4b, 0xd2, 0x06, 0x16, 0xbd, 0xb9, 0x46, - 0x1d, 0xcc, 0xd8, 0xee, 0xbb, 0x7d, 0x7e, 0x7c, - 0x83, 0xa9, 0x14, 0x52, 0xcc, 0x20, 0xed, 0xf5, - 0x3b, 0xe5, 0xb0, 0xfe, 0x0d, 0xb4, 0x4d, 0xdd, - 0xaa, 0xaf, 0xbe, 0x73, 0x76, 0x78, 0xc6, 0x84, - 0xb6, 0xe8, 0x9b, 0x9b, 0x4b, 0x67, 0x9b, 0x18, - 0x55, 0xaa, 0x6e, 0xd6, 0x44, 0x49, 0x8b, 0x89, - 0xc9, 0x18 - }; - test_ecdsa_adaptor_spec_vectors_check_serialization(adaptor_sig, 0); - } -} - -/* Nonce function that returns constant 0 */ -static int ecdsa_adaptor_nonce_function_failing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *encryption_key33, const unsigned char *algo, size_t algolen, void *data) { - (void) msg32; - (void) key32; - (void) encryption_key33; - (void) algo; - (void) algolen; - (void) data; - (void) nonce32; - return 0; -} - -/* Nonce function that sets nonce to 0 */ -static int ecdsa_adaptor_nonce_function_0(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *encryption_key33, const unsigned char *algo, size_t algolen, void *data) { - (void) msg32; - (void) key32; - (void) encryption_key33; - (void) algo; - (void) algolen; - (void) data; - - memset(nonce32, 0, 32); - return 1; -} - -/* Nonce function that sets nonce to 0xFF...0xFF */ -static int ecdsa_adaptor_nonce_function_overflowing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *encryption_key33, const unsigned char *algo, size_t algolen, void *data) { - (void) msg32; - (void) key32; - (void) encryption_key33; - (void) algo; - (void) algolen; - (void) data; - - memset(nonce32, 0xFF, 32); - return 1; -} - -/* Checks that a bit flip in the n_flip-th argument (that has n_bytes many - * bytes) changes the hash function - */ -void nonce_function_ecdsa_adaptor_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t algolen) { - unsigned char nonces[2][32]; - CHECK(nonce_function_ecdsa_adaptor(nonces[0], args[0], args[1], args[2], args[3], algolen, args[4]) == 1); - rustsecp256k1zkp_v0_8_0_testrand_flip(args[n_flip], n_bytes); - CHECK(nonce_function_ecdsa_adaptor(nonces[1], args[0], args[1], args[2], args[3], algolen, args[4]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(nonces[0], nonces[1], 32) != 0); -} - -/* Tests for the equality of two sha256 structs. This function only produces a - * correct result if an integer multiple of 64 many bytes have been written - * into the hash functions. */ -void ecdsa_adaptor_test_sha256_eq(const rustsecp256k1zkp_v0_8_0_sha256 *sha1, const rustsecp256k1zkp_v0_8_0_sha256 *sha2) { - /* Is buffer fully consumed? */ - CHECK((sha1->bytes & 0x3F) == 0); - - CHECK(sha1->bytes == sha2->bytes); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0); -} - -void run_nonce_function_ecdsa_adaptor_tests(void) { - unsigned char tag[16] = "ECDSAadaptor/non"; - unsigned char aux_tag[16] = "ECDSAadaptor/aux"; - unsigned char algo[16] = "ECDSAadaptor/non"; - size_t algolen = sizeof(algo); - unsigned char dleq_tag[4] = "DLEQ"; - rustsecp256k1zkp_v0_8_0_sha256 sha; - rustsecp256k1zkp_v0_8_0_sha256 sha_optimized; - unsigned char nonce[32]; - unsigned char msg[32]; - unsigned char key[32]; - unsigned char pk[33]; - unsigned char aux_rand[32]; - unsigned char *args[5]; - int i; - - /* Check that hash initialized by - * rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor_sha256_tagged has the expected - * state. */ - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, tag, sizeof(tag)); - rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor_sha256_tagged(&sha_optimized); - ecdsa_adaptor_test_sha256_eq(&sha, &sha_optimized); - - /* Check that hash initialized by - * rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor_sha256_tagged_aux has the expected - * state. */ - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, aux_tag, sizeof(aux_tag)); - rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor_sha256_tagged_aux(&sha_optimized); - ecdsa_adaptor_test_sha256_eq(&sha, &sha_optimized); - - /* Check that hash initialized by - * rustsecp256k1zkp_v0_8_0_nonce_function_dleq_sha256_tagged_aux has the expected - * state. */ - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, dleq_tag, sizeof(dleq_tag)); - rustsecp256k1zkp_v0_8_0_nonce_function_dleq_sha256_tagged(&sha_optimized); - ecdsa_adaptor_test_sha256_eq(&sha, &sha_optimized); - - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(msg, sizeof(msg)); - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(key, sizeof(key)); - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(pk, sizeof(pk)); - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(aux_rand, sizeof(aux_rand)); - - /* Check that a bitflip in an argument results in different nonces. */ - args[0] = msg; - args[1] = key; - args[2] = pk; - args[3] = algo; - args[4] = aux_rand; - for (i = 0; i < count; i++) { - nonce_function_ecdsa_adaptor_bitflip(args, 0, sizeof(msg), algolen); - nonce_function_ecdsa_adaptor_bitflip(args, 1, sizeof(key), algolen); - nonce_function_ecdsa_adaptor_bitflip(args, 2, sizeof(pk), algolen); - /* Flip algo special case "ECDSAadaptor/non" */ - nonce_function_ecdsa_adaptor_bitflip(args, 3, sizeof(algo), algolen); - /* Flip algo again */ - nonce_function_ecdsa_adaptor_bitflip(args, 3, sizeof(algo), algolen); - nonce_function_ecdsa_adaptor_bitflip(args, 4, sizeof(aux_rand), algolen); - } - - /* NULL algo is disallowed */ - CHECK(nonce_function_ecdsa_adaptor(nonce, msg, key, pk, NULL, 0, NULL) == 0); - /* Empty algo is fine */ - memset(algo, 0x00, algolen); - CHECK(nonce_function_ecdsa_adaptor(nonce, msg, key, pk, algo, algolen, NULL) == 1); - /* Other algo is fine */ - memset(algo, 0xFF, algolen); - CHECK(nonce_function_ecdsa_adaptor(nonce, msg, key, pk, algo, algolen, NULL) == 1); - /* dleq algo is fine */ - CHECK(nonce_function_ecdsa_adaptor(nonce, msg, key, pk, dleq_algo, sizeof(dleq_algo), NULL) == 1); - - /* Different algolen gives different nonce */ - for (i = 0; i < count; i++) { - unsigned char nonce2[32]; - uint32_t offset = rustsecp256k1zkp_v0_8_0_testrand_int(algolen - 1); - size_t algolen_tmp = (algolen + offset) % algolen; - - CHECK(nonce_function_ecdsa_adaptor(nonce2, msg, key, pk, algo, algolen_tmp, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(nonce, nonce2, 32) != 0); - } - - /* NULL aux_rand argument is allowed. */ - CHECK(nonce_function_ecdsa_adaptor(nonce, msg, key, pk, algo, algolen, NULL) == 1); -} - -void test_ecdsa_adaptor_api(void) { - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_pubkey enckey; - rustsecp256k1zkp_v0_8_0_pubkey zero_pk; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig; - unsigned char sk[32]; - unsigned char msg[32]; - unsigned char asig[162]; - unsigned char deckey[32]; - - /** setup **/ - rustsecp256k1zkp_v0_8_0_context *none = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); - rustsecp256k1zkp_v0_8_0_context *sign = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN); - rustsecp256k1zkp_v0_8_0_context *vrfy = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *both = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *sttc = rustsecp256k1zkp_v0_8_0_context_clone(rustsecp256k1zkp_v0_8_0_context_no_precomp); - int ecount; - - rustsecp256k1zkp_v0_8_0_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); - - rustsecp256k1zkp_v0_8_0_testrand256(sk); - rustsecp256k1zkp_v0_8_0_testrand256(msg); - rustsecp256k1zkp_v0_8_0_testrand256(deckey); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &enckey, deckey) == 1); - memset(&zero_pk, 0, sizeof(zero_pk)); - - /** main test body **/ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(none, asig, sk, &enckey, msg, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(vrfy, asig, sk, &enckey, msg, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(sign, asig, sk, &enckey, msg, NULL, NULL) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(sttc, asig, sk, &enckey, msg, NULL, NULL) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(sign, NULL, sk, &enckey, msg, NULL, NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(sign, asig, sk, &enckey, NULL, NULL, NULL) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(sign, asig, NULL, &enckey, msg, NULL, NULL) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(sign, asig, sk, NULL, msg, NULL, NULL) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(sign, asig, sk, &zero_pk, msg, NULL, NULL) == 0); - CHECK(ecount == 6); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(sign, asig, sk, &enckey, msg, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(none, asig, &pubkey, msg, &enckey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(sign, asig, &pubkey, msg, &enckey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(vrfy, asig, &pubkey, msg, &enckey) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(vrfy, NULL, &pubkey, msg, &enckey) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(vrfy, asig, &pubkey, NULL, &enckey) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(vrfy, asig, &pubkey, msg, NULL) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(vrfy, asig, NULL, msg, &enckey) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(vrfy, asig, &zero_pk, msg, &enckey) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(vrfy, asig, &pubkey, msg, &zero_pk) == 0); - CHECK(ecount == 6); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(none, &sig, deckey, asig) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(sign, &sig, deckey, asig) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(vrfy, &sig, deckey, asig) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(both, &sig, deckey, asig) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(both, NULL, deckey, asig) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(both, &sig, NULL, asig) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(both, &sig, deckey, NULL) == 0); - CHECK(ecount == 3); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(both, &sig, deckey, asig) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(none, deckey, &sig, asig, &enckey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(vrfy, deckey, &sig, asig, &enckey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(sign, deckey, &sig, asig, &enckey) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(sttc, deckey, &sig, asig, &enckey) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(sign, NULL, &sig, asig, &enckey) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(sign, deckey, NULL, asig, &enckey) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(sign, deckey, &sig, NULL, &enckey) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(sign, deckey, &sig, asig, NULL) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(sign, deckey, &sig, asig, &zero_pk) == 0); - CHECK(ecount == 6); - - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(vrfy); - rustsecp256k1zkp_v0_8_0_context_destroy(both); - rustsecp256k1zkp_v0_8_0_context_destroy(sttc); -} - -void adaptor_tests(void) { - unsigned char seckey[32]; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - unsigned char msg[32]; - unsigned char deckey[32]; - rustsecp256k1zkp_v0_8_0_pubkey enckey; - unsigned char adaptor_sig[162]; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig; - unsigned char zeros162[162] = { 0 }; - unsigned char zeros64[64] = { 0 }; - unsigned char big[32]; - - rustsecp256k1zkp_v0_8_0_testrand256(seckey); - rustsecp256k1zkp_v0_8_0_testrand256(msg); - rustsecp256k1zkp_v0_8_0_testrand256(deckey); - - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, seckey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &enckey, deckey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(ctx, adaptor_sig, seckey, &enckey, msg, NULL, NULL) == 1); - - { - /* Test overflowing seckey */ - memset(big, 0xFF, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(ctx, adaptor_sig, big, &enckey, msg, NULL, NULL) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(adaptor_sig, zeros162, sizeof(adaptor_sig)) == 0); - - /* Test different nonce functions */ - memset(adaptor_sig, 1, sizeof(adaptor_sig)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(ctx, adaptor_sig, seckey, &enckey, msg, ecdsa_adaptor_nonce_function_failing, NULL) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(adaptor_sig, zeros162, sizeof(adaptor_sig)) == 0); - memset(&adaptor_sig, 1, sizeof(adaptor_sig)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(ctx, adaptor_sig, seckey, &enckey, msg, ecdsa_adaptor_nonce_function_0, NULL) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(adaptor_sig, zeros162, sizeof(adaptor_sig)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(ctx, adaptor_sig, seckey, &enckey, msg, ecdsa_adaptor_nonce_function_overflowing, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(adaptor_sig, zeros162, sizeof(adaptor_sig)) != 0); - } - { - /* Test adaptor_sig_serialize roundtrip */ - rustsecp256k1zkp_v0_8_0_ge r, rp; - rustsecp256k1zkp_v0_8_0_scalar sigr; - rustsecp256k1zkp_v0_8_0_scalar sp; - rustsecp256k1zkp_v0_8_0_scalar dleq_proof_s, dleq_proof_e; - rustsecp256k1zkp_v0_8_0_ge p_inf; - unsigned char adaptor_sig_tmp[162]; - - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_serialize(adaptor_sig_tmp, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)) == 0); - - /* Test adaptor_sig_serialize points at infinity */ - rustsecp256k1zkp_v0_8_0_ge_set_infinity(&p_inf); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_serialize(adaptor_sig_tmp, &p_inf, &rp, &sp, &dleq_proof_e, &dleq_proof_s) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_serialize(adaptor_sig_tmp, &r, &p_inf, &sp, &dleq_proof_e, &dleq_proof_s) == 0); - } - { - /* Test adaptor_sig_deserialize */ - rustsecp256k1zkp_v0_8_0_ge r, rp; - rustsecp256k1zkp_v0_8_0_scalar sigr; - rustsecp256k1zkp_v0_8_0_scalar sp; - rustsecp256k1zkp_v0_8_0_scalar dleq_proof_s, dleq_proof_e; - unsigned char adaptor_sig_tmp[162]; - - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig) == 1); - - /* r */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(&r, &sigr, NULL, NULL, NULL, NULL, adaptor_sig) == 1); - memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); - memset(&adaptor_sig_tmp[0], 0xFF, 33); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(&r, &sigr, NULL, NULL, NULL, NULL, adaptor_sig_tmp) == 0); - - /* sigr */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(NULL, &sigr, NULL, NULL, NULL, NULL, adaptor_sig) == 1); - memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); - memset(&adaptor_sig_tmp[1], 0xFF, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(NULL, &sigr, NULL, NULL, NULL, NULL, adaptor_sig_tmp) == 1); - memset(&adaptor_sig_tmp[1], 0, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(NULL, &sigr, NULL, NULL, NULL, NULL, adaptor_sig_tmp) == 0); - - /* rp */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(NULL, NULL, &rp, NULL, NULL, NULL, adaptor_sig) == 1); - memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); - memset(&adaptor_sig_tmp[33], 0xFF, 33); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(NULL, NULL, &rp, NULL, NULL, NULL, adaptor_sig_tmp) == 0); - - /* sp */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(NULL, NULL, NULL, &sp, NULL, NULL, adaptor_sig) == 1); - memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); - memset(&adaptor_sig_tmp[66], 0xFF, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(NULL, NULL, NULL, &sp, NULL, NULL, adaptor_sig_tmp) == 0); - - /* dleq_proof_e */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(NULL, NULL, NULL, NULL, &dleq_proof_e, NULL, adaptor_sig) == 1); - memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); - memset(&adaptor_sig_tmp[98], 0xFF, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(NULL, NULL, NULL, NULL, &dleq_proof_e, NULL, adaptor_sig_tmp) == 1); - - /* dleq_proof_s */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(NULL, NULL, NULL, NULL, NULL, &dleq_proof_s, adaptor_sig) == 1); - memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); - memset(&adaptor_sig_tmp[130], 0xFF, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(NULL, NULL, NULL, NULL, NULL, &dleq_proof_s, adaptor_sig_tmp) == 0); - } - - /* Test adaptor_sig_verify */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(ctx, adaptor_sig, &pubkey, msg, &enckey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(ctx, adaptor_sig, &enckey, msg, &enckey) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(ctx, adaptor_sig, &pubkey, msg, &pubkey) == 0); - { - /* Test failed adaptor sig deserialization */ - unsigned char adaptor_sig_tmp[162]; - memset(&adaptor_sig_tmp, 0xFF, 162); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(ctx, adaptor_sig_tmp, &pubkey, msg, &enckey) == 0); - } - { - /* Test that any flipped bit in the adaptor signature will make - * verification fail */ - unsigned char adaptor_sig_tmp[162]; - memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); - rand_flip_bit(&adaptor_sig_tmp[1], sizeof(adaptor_sig_tmp) - 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(ctx, adaptor_sig_tmp, &pubkey, msg, &enckey) == 0); - } - { - unsigned char msg_tmp[32]; - memcpy(msg_tmp, msg, sizeof(msg_tmp)); - rand_flip_bit(msg_tmp, sizeof(msg_tmp)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(ctx, adaptor_sig, &pubkey, msg_tmp, &enckey) == 0); - } - { - /* Verification must check that the derived R' is not equal to the point at - * infinity before negating it. R' is derived as follows: - * - * R' == s'⁻¹(m * G + R.x * X) - * - * When the base point, G, is multiplied by the subgroup order, q, the - * result is the point at infinity, 0: - * - * q * G = 0 - * - * Thus, if we set s' equal to R.x, m equal to (q - 1) * R.x, and X equal to - * G, then our derived R' will be 0: - * - * R' = R.x⁻¹((q - 1 * R.x) * G + R.x * G) = q * G = 0 */ - - /* t := q - 1 */ - const unsigned char target[32] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, - 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40 - }; - unsigned char seckey_tmp[32] = { 0 }; - unsigned char msg_tmp[32]; - unsigned char adaptor_sig_tmp[162]; - rustsecp256k1zkp_v0_8_0_pubkey pubkey_tmp; - rustsecp256k1zkp_v0_8_0_scalar sigr, t, m; - - /* m := t * sigr */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_sig_deserialize(NULL, &sigr, NULL, NULL, NULL, NULL, adaptor_sig) == 1); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&t, target, NULL); - rustsecp256k1zkp_v0_8_0_scalar_mul(&m, &t, &sigr); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(msg_tmp, &m); - - /* X := G */ - seckey_tmp[31] = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey_tmp, seckey_tmp) == 1); - - /* sp := sigr */ - memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); - memcpy(&adaptor_sig_tmp[66], &adaptor_sig_tmp[1], 32); - - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(ctx, adaptor_sig_tmp, &pubkey_tmp, msg_tmp, &enckey) == 0); - } - - /* Test decryption */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(ctx, &sig, deckey, adaptor_sig) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1); - - { - /* Test overflowing decryption key */ - rustsecp256k1zkp_v0_8_0_ecdsa_signature s; - memset(big, 0xFF, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(ctx, &s, big, adaptor_sig) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&s.data[0], zeros64, sizeof(&s.data[0])) == 0); - } - { - /* Test key recover */ - unsigned char decryption_key_tmp[32]; - unsigned char adaptor_sig_tmp[162]; - - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(ctx, decryption_key_tmp, &sig, adaptor_sig, &enckey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(deckey, decryption_key_tmp, sizeof(deckey)) == 0); - - /* Test failed sp deserialization */ - memcpy(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)); - memset(&adaptor_sig_tmp[66], 0xFF, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(ctx, decryption_key_tmp, &sig, adaptor_sig_tmp, &enckey) == 0); - } -} - -void multi_hop_lock_tests(void) { - unsigned char seckey_a[32]; - unsigned char seckey_b[32]; - unsigned char pop[32]; - unsigned char tx_ab[32]; - unsigned char tx_bc[32]; - unsigned char buf[32]; - unsigned char asig_ab[162]; - unsigned char asig_bc[162]; - rustsecp256k1zkp_v0_8_0_pubkey pubkey_pop; - rustsecp256k1zkp_v0_8_0_pubkey pubkey_a, pubkey_b; - rustsecp256k1zkp_v0_8_0_pubkey l, r; - rustsecp256k1zkp_v0_8_0_ge l_ge, r_ge; - rustsecp256k1zkp_v0_8_0_scalar t1, t2, tp; - rustsecp256k1zkp_v0_8_0_scalar deckey; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig_ab, sig_bc; - - rustsecp256k1zkp_v0_8_0_testrand256(seckey_a); - rustsecp256k1zkp_v0_8_0_testrand256(seckey_b); - - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey_a, seckey_a)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey_b, seckey_b)); - - /* Carol setup */ - /* Proof of payment */ - rustsecp256k1zkp_v0_8_0_testrand256(pop); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey_pop, pop)); - - /* Alice setup */ - rustsecp256k1zkp_v0_8_0_testrand256(tx_ab); - rand_scalar(&t1); - rand_scalar(&t2); - rustsecp256k1zkp_v0_8_0_scalar_add(&tp, &t1, &t2); - /* Left lock */ - rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &l_ge, &pubkey_pop); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_tweak_add(&l_ge, &t1)); - rustsecp256k1zkp_v0_8_0_pubkey_save(&l, &l_ge); - /* Right lock */ - rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &r_ge, &pubkey_pop); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_tweak_add(&r_ge, &tp)); - rustsecp256k1zkp_v0_8_0_pubkey_save(&r, &r_ge); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(ctx, asig_ab, seckey_a, &l, tx_ab, NULL, NULL)); - - /* Bob setup */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(ctx, asig_ab, &pubkey_a, tx_ab, &l)); - rustsecp256k1zkp_v0_8_0_testrand256(tx_bc); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(ctx, asig_bc, seckey_b, &r, tx_bc, NULL, NULL)); - - /* Carol decrypt */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify(ctx, asig_bc, &pubkey_b, tx_bc, &r)); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&deckey, pop, NULL); - rustsecp256k1zkp_v0_8_0_scalar_add(&deckey, &deckey, &tp); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(buf, &deckey); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(ctx, &sig_bc, buf, asig_bc)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig_bc, tx_bc, &pubkey_b)); - - /* Bob recover and decrypt */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(ctx, buf, &sig_bc, asig_bc, &r)); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&deckey, buf, NULL); - rustsecp256k1zkp_v0_8_0_scalar_negate(&t2, &t2); - rustsecp256k1zkp_v0_8_0_scalar_add(&deckey, &deckey, &t2); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(buf, &deckey); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(ctx, &sig_ab, buf, asig_ab)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig_ab, tx_ab, &pubkey_a)); - - /* Alice recover and derive proof of payment */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(ctx, buf, &sig_ab, asig_ab, &l)); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&deckey, buf, NULL); - rustsecp256k1zkp_v0_8_0_scalar_negate(&t1, &t1); - rustsecp256k1zkp_v0_8_0_scalar_add(&deckey, &deckey, &t1); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(buf, &deckey); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(buf, pop, 32) == 0); -} - -void run_ecdsa_adaptor_tests(void) { - int i; - run_nonce_function_ecdsa_adaptor_tests(); - - test_ecdsa_adaptor_api(); - test_ecdsa_adaptor_spec_vectors(); - for (i = 0; i < count; i++) { - dleq_tests(); - } - for (i = 0; i < count; i++) { - adaptor_tests(); - } - for (i = 0; i < count; i++) { - multi_hop_lock_tests(); - } -} - -#endif /* SECP256K1_MODULE_ECDSA_ADAPTOR_TESTS_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_s2c/Makefile.am.include b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_s2c/Makefile.am.include deleted file mode 100644 index 33d620d8..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_s2c/Makefile.am.include +++ /dev/null @@ -1,3 +0,0 @@ -include_HEADERS += include/rustsecp256k1zkp_v0_8_0_ecdsa_s2c.h -noinst_HEADERS += src/modules/ecdsa_s2c/main_impl.h -noinst_HEADERS += src/modules/ecdsa_s2c/tests_impl.h diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_s2c/main_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_s2c/main_impl.h deleted file mode 100644 index a26862d2..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_s2c/main_impl.h +++ /dev/null @@ -1,197 +0,0 @@ -/********************************************************************** - * Copyright (c) 2019-2020 Marko Bencun, Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_ECDSA_S2C_MAIN_H -#define SECP256K1_MODULE_ECDSA_S2C_MAIN_H - -#include "../../../include/secp256k1.h" -#include "../../../include/secp256k1_ecdsa_s2c.h" - -static void rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_save(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* opening, rustsecp256k1zkp_v0_8_0_ge* ge) { - rustsecp256k1zkp_v0_8_0_pubkey_save((rustsecp256k1zkp_v0_8_0_pubkey*) opening, ge); -} - -static int rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ge* ge, const rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* opening) { - return rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, ge, (const rustsecp256k1zkp_v0_8_0_pubkey*) opening); -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_parse(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* opening, const unsigned char* input33) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(opening != NULL); - ARG_CHECK(input33 != NULL); - return rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, (rustsecp256k1zkp_v0_8_0_pubkey*) opening, input33, 33); -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_serialize(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char* output33, const rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* opening) { - size_t out_len = 33; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output33 != NULL); - ARG_CHECK(opening != NULL); - return rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, output33, &out_len, (const rustsecp256k1zkp_v0_8_0_pubkey*) opening, SECP256K1_EC_COMPRESSED); -} - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("s2c/ecdsa/point")||SHA256("s2c/ecdsa/point"). */ -static void rustsecp256k1zkp_v0_8_0_s2c_ecdsa_point_sha256_tagged(rustsecp256k1zkp_v0_8_0_sha256 *sha) { - rustsecp256k1zkp_v0_8_0_sha256_initialize(sha); - sha->s[0] = 0xa9b21c7bul; - sha->s[1] = 0x358c3e3eul; - sha->s[2] = 0x0b6863d1ul; - sha->s[3] = 0xc62b2035ul; - sha->s[4] = 0xb44b40ceul; - sha->s[5] = 0x254a8912ul; - sha->s[6] = 0x0f85d0d4ul; - sha->s[7] = 0x8a5bf91cul; - - sha->bytes = 64; -} - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("s2c/ecdsa/data")||SHA256("s2c/ecdsa/data"). */ -static void rustsecp256k1zkp_v0_8_0_s2c_ecdsa_data_sha256_tagged(rustsecp256k1zkp_v0_8_0_sha256 *sha) { - rustsecp256k1zkp_v0_8_0_sha256_initialize(sha); - sha->s[0] = 0xfeefd675ul; - sha->s[1] = 0x73166c99ul; - sha->s[2] = 0xe2309cb8ul; - sha->s[3] = 0x6d458113ul; - sha->s[4] = 0x01d3a512ul; - sha->s[5] = 0x00e18112ul; - sha->s[6] = 0x37ee0874ul; - sha->s[7] = 0x421fc55ful; - - sha->bytes = 64; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_signature* signature, rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* s2c_opening, const unsigned char - *msg32, const unsigned char *seckey, const unsigned char* s2c_data32) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - int ret; - unsigned char ndata[32]; - rustsecp256k1zkp_v0_8_0_sha256 s2c_sha; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(signature != NULL); - ARG_CHECK(seckey != NULL); - ARG_CHECK(s2c_data32 != NULL); - - /* Provide `s2c_data32` to the nonce function as additional data to - * derive the nonce. It is first hashed because it should be possible - * to derive nonces even if only a SHA256 commitment to the data is - * known. This is important in the ECDSA anti-exfil protocol. */ - rustsecp256k1zkp_v0_8_0_s2c_ecdsa_data_sha256_tagged(&s2c_sha); - rustsecp256k1zkp_v0_8_0_sha256_write(&s2c_sha, s2c_data32, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&s2c_sha, ndata); - - rustsecp256k1zkp_v0_8_0_s2c_ecdsa_point_sha256_tagged(&s2c_sha); - ret = rustsecp256k1zkp_v0_8_0_ecdsa_sign_inner(ctx, &r, &s, NULL, &s2c_sha, s2c_opening, s2c_data32, msg32, seckey, NULL, ndata); - rustsecp256k1zkp_v0_8_0_scalar_cmov(&r, &rustsecp256k1zkp_v0_8_0_scalar_zero, !ret); - rustsecp256k1zkp_v0_8_0_scalar_cmov(&s, &rustsecp256k1zkp_v0_8_0_scalar_zero, !ret); - rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(signature, &r, &s); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, const unsigned char* data32, const rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* opening) { - rustsecp256k1zkp_v0_8_0_ge commitment_ge; - rustsecp256k1zkp_v0_8_0_ge original_pubnonce_ge; - unsigned char x_bytes[32]; - rustsecp256k1zkp_v0_8_0_scalar sigr, sigs, x_scalar; - rustsecp256k1zkp_v0_8_0_sha256 s2c_sha; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(data32 != NULL); - ARG_CHECK(opening != NULL); - - if (!rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_load(ctx, &original_pubnonce_ge, opening)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_s2c_ecdsa_point_sha256_tagged(&s2c_sha); - if (!rustsecp256k1zkp_v0_8_0_ec_commit(&commitment_ge, &original_pubnonce_ge, &s2c_sha, data32, 32)) { - return 0; - } - - /* Check that sig_r == commitment_x (mod n) - * sig_r is the x coordinate of R represented by a scalar. - * commitment_x is the x coordinate of the commitment (field element). - * - * Note that we are only checking the x-coordinate -- this is because the y-coordinate - * is not part of the ECDSA signature (and therefore not part of the commitment!) - */ - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &sigr, &sigs, sig); - - rustsecp256k1zkp_v0_8_0_fe_normalize(&commitment_ge.x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(x_bytes, &commitment_ge.x); - /* Do not check overflow; overflowing a scalar does not affect whether - * or not the R value is a cryptographic commitment, only whether it - * is a valid R value for an ECDSA signature. If users care about that - * they should use `ecdsa_verify` or `anti_exfil_host_verify`. In other - * words, this check would be (at best) unnecessary, and (at worst) - * insufficient. */ - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&x_scalar, x_bytes, NULL); - return rustsecp256k1zkp_v0_8_0_scalar_eq(&sigr, &x_scalar); -} - -/*** anti-exfil ***/ -int rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_host_commit(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char* rand_commitment32, const unsigned char* rand32) { - rustsecp256k1zkp_v0_8_0_sha256 sha; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(rand_commitment32 != NULL); - ARG_CHECK(rand32 != NULL); - - rustsecp256k1zkp_v0_8_0_s2c_ecdsa_data_sha256_tagged(&sha); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, rand32, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, rand_commitment32); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_signer_commit(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* opening, const unsigned char* msg32, const unsigned char* seckey32, const unsigned char* rand_commitment32) { - unsigned char nonce32[32]; - rustsecp256k1zkp_v0_8_0_scalar k; - rustsecp256k1zkp_v0_8_0_gej rj; - rustsecp256k1zkp_v0_8_0_ge r; - unsigned int count = 0; - int is_nonce_valid = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(opening != NULL); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(seckey32 != NULL); - ARG_CHECK(rand_commitment32 != NULL); - - memset(nonce32, 0, 32); - while (!is_nonce_valid) { - /* cast to void* removes const qualifier, but rustsecp256k1zkp_v0_8_0_nonce_function_default does not modify it */ - if (!rustsecp256k1zkp_v0_8_0_nonce_function_default(nonce32, msg32, seckey32, NULL, (void*)rand_commitment32, count)) { - rustsecp256k1zkp_v0_8_0_callback_call(&ctx->error_callback, "(cryptographically unreachable) generated bad nonce"); - } - is_nonce_valid = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&k, nonce32); - /* The nonce is still secret here, but it being invalid is is less likely than 1:2^255. */ - rustsecp256k1zkp_v0_8_0_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid)); - count++; - } - - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&r, &rj); - rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_save(opening, &r); - memset(nonce32, 0, 32); - rustsecp256k1zkp_v0_8_0_scalar_clear(&k); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_anti_exfil_sign(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, const unsigned char* msg32, const unsigned char* seckey, const unsigned char* host_data32) { - return rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(ctx, sig, NULL, msg32, seckey, host_data32); -} - -int rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_ecdsa_signature *sig, const unsigned char *msg32, const rustsecp256k1zkp_v0_8_0_pubkey *pubkey, const unsigned char *host_data32, const rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening *opening) { - return rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(ctx, sig, host_data32, opening) && - rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, sig, msg32, pubkey); -} - -#endif /* SECP256K1_ECDSA_S2C_MAIN_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_s2c/tests_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_s2c/tests_impl.h deleted file mode 100644 index b97e63e5..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdsa_s2c/tests_impl.h +++ /dev/null @@ -1,415 +0,0 @@ -/********************************************************************** - * Copyright (c) 2019-2020 Marko Bencun, Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_ECDSA_S2C_TESTS_H -#define SECP256K1_MODULE_ECDSA_S2C_TESTS_H - -#include "../../../include/secp256k1_ecdsa_s2c.h" - -static void test_ecdsa_s2c_tagged_hash(void) { - unsigned char tag_data[14] = "s2c/ecdsa/data"; - unsigned char tag_point[15] = "s2c/ecdsa/point"; - rustsecp256k1zkp_v0_8_0_sha256 sha; - rustsecp256k1zkp_v0_8_0_sha256 sha_optimized; - unsigned char output[32]; - unsigned char output_optimized[32]; - - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, tag_data, sizeof(tag_data)); - rustsecp256k1zkp_v0_8_0_s2c_ecdsa_data_sha256_tagged(&sha_optimized); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, output); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha_optimized, output_optimized); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(output, output_optimized, 32) == 0); - - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, tag_point, sizeof(tag_point)); - rustsecp256k1zkp_v0_8_0_s2c_ecdsa_point_sha256_tagged(&sha_optimized); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, output); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha_optimized, output_optimized); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(output, output_optimized, 32) == 0); -} - -void run_s2c_opening_test(void) { - int i = 0; - unsigned char output[33]; - rustsecp256k1zkp_v0_8_0_context *none = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); - - unsigned char input[33] = { - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02 - }; - rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening opening; - int32_t ecount = 0; - - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - - /* First parsing, then serializing works */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_parse(none, &opening, input) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_serialize(none, output, &opening) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_parse(none, &opening, input) == 1); - CHECK(ecount == 0); - - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_parse(none, NULL, input) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_parse(none, &opening, NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_parse(none, &opening, input) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_serialize(none, NULL, &opening) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_serialize(none, output, NULL) == 0); - - CHECK(ecount == 4); - /* Invalid pubkey makes parsing fail */ - input[0] = 0; /* bad oddness bit */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_parse(none, &opening, input) == 0); - input[0] = 2; - input[31] = 1; /* point not on the curve */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_parse(none, &opening, input) == 0); - CHECK(ecount == 4); /* neither of the above are API errors */ - - /* Try parsing and serializing a bunch of openings */ - for (i = 0; i < count; i++) { - /* This is expected to fail in about 50% of iterations because the - * points' x-coordinates are uniformly random */ - if (rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_parse(none, &opening, input) == 1) { - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_serialize(none, output, &opening) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(output, input, sizeof(output)) == 0); - } - rustsecp256k1zkp_v0_8_0_testrand256(&input[1]); - /* Set pubkey oddness tag to first bit of input[1] */ - input[0] = (input[1] & 1) + 2; - } - - rustsecp256k1zkp_v0_8_0_context_destroy(none); -} - -static void test_ecdsa_s2c_api(void) { - rustsecp256k1zkp_v0_8_0_context *none = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); - rustsecp256k1zkp_v0_8_0_context *sign = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN); - rustsecp256k1zkp_v0_8_0_context *vrfy = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *both = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *sttc = rustsecp256k1zkp_v0_8_0_context_clone(rustsecp256k1zkp_v0_8_0_context_no_precomp); - - rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening s2c_opening; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig; - const unsigned char msg[32] = "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm"; - const unsigned char sec[32] = "ssssssssssssssssssssssssssssssss"; - const unsigned char s2c_data[32] = "dddddddddddddddddddddddddddddddd"; - const unsigned char hostrand[32] = "hrhrhrhrhrhrhrhrhrhrhrhrhrhrhrhr"; - unsigned char hostrand_commitment[32]; - rustsecp256k1zkp_v0_8_0_pubkey pk; - - int32_t ecount; - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pk, sec)); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(both, NULL, &s2c_opening, msg, sec, s2c_data) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(both, &sig, NULL, msg, sec, s2c_data) == 1); - CHECK(ecount == 1); /* NULL opening is not an API error */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(both, &sig, &s2c_opening, NULL, sec, s2c_data) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(both, &sig, &s2c_opening, msg, NULL, s2c_data) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(both, &sig, &s2c_opening, msg, sec, NULL) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(none, &sig, &s2c_opening, msg, sec, s2c_data) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(vrfy, &sig, &s2c_opening, msg, sec, s2c_data) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(sign, &sig, &s2c_opening, msg, sec, s2c_data) == 1); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(sttc, &sig, &s2c_opening, msg, sec, s2c_data) == 0); - CHECK(ecount == 5); - - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg, &pk) == 1); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(both, NULL, s2c_data, &s2c_opening) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(both, &sig, NULL, &s2c_opening) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(both, &sig, s2c_data, NULL) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(none, &sig, s2c_data, &s2c_opening) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(sign, &sig, s2c_data, &s2c_opening) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(vrfy, &sig, s2c_data, &s2c_opening) == 1); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(vrfy, &sig, sec, &s2c_opening) == 0); - CHECK(ecount == 3); /* wrong data is not an API error */ - - /* Signing with NULL s2c_opening gives the same result */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(sign, &sig, NULL, msg, sec, s2c_data) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(vrfy, &sig, s2c_data, &s2c_opening) == 1); - - /* anti-exfil */ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_host_commit(none, NULL, hostrand) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_host_commit(none, hostrand_commitment, NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_host_commit(none, hostrand_commitment, hostrand) == 1); - CHECK(ecount == 2); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_signer_commit(both, NULL, msg, sec, hostrand_commitment) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_signer_commit(both, &s2c_opening, NULL, sec, hostrand_commitment) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_signer_commit(both, &s2c_opening, msg, NULL, hostrand_commitment) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_signer_commit(both, &s2c_opening, msg, sec, NULL) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_signer_commit(none, &s2c_opening, msg, sec, hostrand_commitment) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_signer_commit(vrfy, &s2c_opening, msg, sec, hostrand_commitment) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_signer_commit(sign, &s2c_opening, msg, sec, hostrand_commitment) == 1); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_signer_commit(sttc, &s2c_opening, msg, sec, hostrand_commitment) == 0); - CHECK(ecount == 5); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_sign(both, NULL, msg, sec, hostrand) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_sign(both, &sig, NULL, sec, hostrand) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_sign(both, &sig, msg, NULL, hostrand) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_sign(both, &sig, msg, sec, NULL) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_sign(none, &sig, msg, sec, hostrand) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_sign(vrfy, &sig, msg, sec, hostrand) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_sign(both, &sig, msg, sec, hostrand) == 1); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_sign(sttc, &sig, msg, sec, hostrand) == 0); - CHECK(ecount == 5); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(both, NULL, msg, &pk, hostrand, &s2c_opening) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(both, &sig, NULL, &pk, hostrand, &s2c_opening) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(both, &sig, msg, NULL, hostrand, &s2c_opening) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(both, &sig, msg, &pk, NULL, &s2c_opening) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(both, &sig, msg, &pk, hostrand, NULL) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(none, &sig, msg, &pk, hostrand, &s2c_opening) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(sign, &sig, msg, &pk, hostrand, &s2c_opening) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(vrfy, &sig, msg, &pk, hostrand, &s2c_opening) == 1); - CHECK(ecount == 5); - - rustsecp256k1zkp_v0_8_0_context_destroy(both); - rustsecp256k1zkp_v0_8_0_context_destroy(vrfy); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sttc); -} - -/* When using sign-to-contract commitments, the nonce function is fixed, so we can use fixtures to test. */ -typedef struct { - /* Data to commit to */ - unsigned char s2c_data[32]; - /* Original nonce */ - unsigned char expected_s2c_opening[33]; - /* Original nonce (anti-exfil protocol, which mixes in host randomness) */ - unsigned char expected_s2c_exfil_opening[33]; -} ecdsa_s2c_test; - -static ecdsa_s2c_test ecdsa_s2c_tests[] = { - { - "\x1b\xf6\xfb\x42\xf4\x1e\xb8\x76\xc4\xd7\xaa\x0d\x67\x24\x2b\x00\xba\xab\x99\xdc\x20\x84\x49\x3e\x4e\x63\x27\x7f\xa1\xf7\x7f\x22", - "\x03\xf0\x30\xde\xf3\x18\x8c\x0f\x56\xfc\xea\x87\x43\x5b\x30\x76\x43\xf4\x5d\xaf\xe2\x2c\xbc\x82\xfd\x56\x03\x4f\xae\x97\x41\x7d\x3a", - "\x02\xdf\x63\x75\x5d\x1f\x32\x92\xbf\xfe\xd8\x29\x86\xb1\x06\x49\x7c\x93\xb1\xf8\xbd\xc0\x45\x4b\x6b\x0b\x0a\x47\x79\xc0\xef\x71\x88", - }, - { - "\x35\x19\x9a\x8f\xbf\x84\xad\x6e\xf6\x9a\x18\x4c\x1b\x19\x28\x5b\xef\xbe\x06\xe6\x0b\x62\x64\xe6\xd3\x73\x89\x3f\x68\x55\xe2\x4a", - "\x03\x90\x17\x17\xce\x7c\x74\x84\xa2\xce\x1b\x7d\xc7\x40\x3b\x14\xe0\x35\x49\x71\x39\x3e\xc0\x92\xa7\xf3\xe0\xc8\xe4\xe2\xd2\x63\x9d", - "\x02\xc0\x4a\xc7\xf7\x71\xe8\xeb\xdb\xf3\x15\xff\x5e\x58\xb7\xfe\x95\x16\x10\x21\x03\x50\x00\x66\x17\x2c\x4f\xac\x5b\x20\xf9\xe0\xea", - }, -}; - -static void test_ecdsa_s2c_fixed_vectors(void) { - const unsigned char privkey[32] = { - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - }; - const unsigned char message[32] = { - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - }; - size_t i; - - for (i = 0; i < sizeof(ecdsa_s2c_tests) / sizeof(ecdsa_s2c_tests[0]); i++) { - rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening s2c_opening; - unsigned char opening_ser[33]; - const ecdsa_s2c_test *test = &ecdsa_s2c_tests[i]; - rustsecp256k1zkp_v0_8_0_ecdsa_signature signature; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, message, privkey, test->s2c_data) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_serialize(ctx, opening_ser, &s2c_opening) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(test->expected_s2c_opening, opening_ser, sizeof(opening_ser)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(ctx, &signature, test->s2c_data, &s2c_opening) == 1); - } -} - -static void test_ecdsa_s2c_sign_verify(void) { - unsigned char privkey[32]; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - unsigned char message[32]; - unsigned char noncedata[32]; - unsigned char s2c_data[32]; - unsigned char s2c_data2[32]; - rustsecp256k1zkp_v0_8_0_ecdsa_signature signature; - rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening s2c_opening; - - /* Generate a random key, message, noncedata and s2c_data. */ - { - rustsecp256k1zkp_v0_8_0_scalar key; - random_scalar_order_test(&key); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(privkey, &key); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, privkey) == 1); - - rustsecp256k1zkp_v0_8_0_testrand256_test(message); - rustsecp256k1zkp_v0_8_0_testrand256_test(noncedata); - rustsecp256k1zkp_v0_8_0_testrand256_test(s2c_data); - rustsecp256k1zkp_v0_8_0_testrand256_test(s2c_data2); - } - - { /* invalid privkeys */ - unsigned char zero_privkey[32] = {0}; - unsigned char overflow_privkey[32] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(ctx, &signature, NULL, message, zero_privkey, s2c_data) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(ctx, &signature, NULL, message, overflow_privkey, s2c_data) == 0); - } - /* Check that the sign-to-contract signature is valid, with s2c_data. Also check the commitment. */ - { - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, message, privkey, s2c_data) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature, message, &pubkey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(ctx, &signature, s2c_data, &s2c_opening) == 1); - } - /* Check that an invalid commitment does not verify */ - { - unsigned char sigbytes[64]; - size_t i; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, message, privkey, s2c_data) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature, message, &pubkey) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact(ctx, sigbytes, &signature) == 1); - for(i = 0; i < 32; i++) { - /* change one byte */ - sigbytes[i] = (((int)sigbytes[i]) + 1) % 256; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact(ctx, &signature, sigbytes) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(ctx, &signature, s2c_data, &s2c_opening) == 0); - /* revert */ - sigbytes[i] = (((int)sigbytes[i]) + 255) % 256; - } - } -} - -static void test_ecdsa_anti_exfil_signer_commit(void) { - size_t i; - unsigned char privkey[32] = { - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - }; - unsigned char message[32] = { - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - }; - /* Check that original pubnonce is derived from s2c_data */ - for (i = 0; i < sizeof(ecdsa_s2c_tests) / sizeof(ecdsa_s2c_tests[0]); i++) { - rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening s2c_opening; - unsigned char buf[33]; - const ecdsa_s2c_test *test = &ecdsa_s2c_tests[i]; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_signer_commit(ctx, &s2c_opening, message, privkey, test->s2c_data) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_serialize(ctx, buf, &s2c_opening) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(test->expected_s2c_exfil_opening, buf, sizeof(buf)) == 0); - } -} - -/* This tests the full ECDSA Anti-Exfil Protocol */ -static void test_ecdsa_anti_exfil(void) { - unsigned char signer_privkey[32]; - unsigned char host_msg[32]; - unsigned char host_commitment[32]; - unsigned char host_nonce_contribution[32]; - rustsecp256k1zkp_v0_8_0_pubkey signer_pubkey; - rustsecp256k1zkp_v0_8_0_ecdsa_signature signature; - rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening s2c_opening; - - /* Generate a random key, message. */ - { - rustsecp256k1zkp_v0_8_0_scalar key; - random_scalar_order_test(&key); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(signer_privkey, &key); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &signer_pubkey, signer_privkey) == 1); - rustsecp256k1zkp_v0_8_0_testrand256_test(host_msg); - rustsecp256k1zkp_v0_8_0_testrand256_test(host_nonce_contribution); - } - - /* Protocol step 1. */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_host_commit(ctx, host_commitment, host_nonce_contribution) == 1); - /* Protocol step 2. */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_signer_commit(ctx, &s2c_opening, host_msg, signer_privkey, host_commitment) == 1); - /* Protocol step 3: host_nonce_contribution send to signer to be used in step 4. */ - /* Protocol step 4. */ - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_sign(ctx, &signature, host_msg, signer_privkey, host_nonce_contribution) == 1); - /* Protocol step 5. */ - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(ctx, &signature, host_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 1); - /* Protocol step 5 (explicitly) */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(ctx, &signature, host_nonce_contribution, &s2c_opening) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature, host_msg, &signer_pubkey) == 1); - - { /* host_verify: commitment does not match */ - unsigned char sigbytes[64]; - size_t i; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact(ctx, sigbytes, &signature) == 1); - for(i = 0; i < 32; i++) { - /* change one byte */ - sigbytes[i] += 1; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact(ctx, &signature, sigbytes) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_verify_commit(ctx, &signature, host_nonce_contribution, &s2c_opening) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(ctx, &signature, host_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 0); - /* revert */ - sigbytes[i] -= 1; - } - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact(ctx, &signature, sigbytes) == 1); - } - { /* host_verify: message does not match */ - unsigned char bad_msg[32]; - rustsecp256k1zkp_v0_8_0_testrand256_test(bad_msg); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(ctx, &signature, host_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(ctx, &signature, bad_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 0); - } - { /* s2c_sign: host provided data that didn't match commitment */ - rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening orig_opening = s2c_opening; - unsigned char bad_nonce_contribution[32] = { 1, 2, 3, 4 }; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, host_msg, signer_privkey, bad_nonce_contribution) == 1); - /* good signature but the opening (original public nonce does not match the original */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature, host_msg, &signer_pubkey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(ctx, &signature, host_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_anti_exfil_host_verify(ctx, &signature, host_msg, &signer_pubkey, bad_nonce_contribution, &s2c_opening) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&s2c_opening, &orig_opening, sizeof(s2c_opening)) != 0); - } -} - -static void run_ecdsa_s2c_tests(void) { - run_s2c_opening_test(); - test_ecdsa_s2c_tagged_hash(); - test_ecdsa_s2c_api(); - test_ecdsa_s2c_fixed_vectors(); - test_ecdsa_s2c_sign_verify(); - - test_ecdsa_anti_exfil_signer_commit(); - test_ecdsa_anti_exfil(); -} - -#endif /* SECP256K1_MODULE_ECDSA_S2C_TESTS_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/hsort.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/hsort.h deleted file mode 100644 index 69efdfa2..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/hsort.h +++ /dev/null @@ -1,22 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2021 Russell O'Connor, Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_HSORT_H_ -#define SECP256K1_HSORT_H_ - -#include -#include - -/* In-place, iterative heapsort with an interface matching glibc's qsort_r. This - * is preferred over standard library implementations because they generally - * make no guarantee about being fast for malicious inputs. - * - * See the qsort_r manpage for a description of the interface. - */ -static void rustsecp256k1zkp_v0_8_0_hsort(void *ptr, size_t count, size_t size, - int (*cmp)(const void *, const void *, void *), - void *cmp_data); -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/hsort_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/hsort_impl.h deleted file mode 100644 index fcd59be4..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/hsort_impl.h +++ /dev/null @@ -1,116 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2021 Russell O'Connor, Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_HSORT_IMPL_H_ -#define SECP256K1_HSORT_IMPL_H_ - -#include "hsort.h" - -/* An array is a heap when, for all non-zero indexes i, the element at index i - * compares as less than or equal to the element at index parent(i) = (i-1)/2. - */ - -static SECP256K1_INLINE size_t child1(size_t i) { - VERIFY_CHECK(i <= (SIZE_MAX - 1)/2); - return 2*i + 1; -} - -static SECP256K1_INLINE size_t child2(size_t i) { - VERIFY_CHECK(i <= SIZE_MAX/2 - 1); - return child1(i)+1; -} - -static SECP256K1_INLINE void heap_swap64(unsigned char *a, size_t i, size_t j, size_t stride) { - unsigned char tmp[64]; - VERIFY_CHECK(stride <= 64); - memcpy(tmp, a + i*stride, stride); - memmove(a + i*stride, a + j*stride, stride); - memcpy(a + j*stride, tmp, stride); -} - -static SECP256K1_INLINE void heap_swap(unsigned char *a, size_t i, size_t j, size_t stride) { - while (64 < stride) { - heap_swap64(a + (stride - 64), i, j, 64); - stride -= 64; - } - heap_swap64(a, i, j, stride); -} - -static SECP256K1_INLINE void heap_down(unsigned char *a, size_t i, size_t heap_size, size_t stride, - int (*cmp)(const void *, const void *, void *), void *cmp_data) { - while (i < heap_size/2) { - VERIFY_CHECK(i <= SIZE_MAX/2 - 1); - /* Proof: - * i < heap_size/2 - * i + 1 <= heap_size/2 - * 2*i + 2 <= heap_size <= SIZE_MAX - * 2*i <= SIZE_MAX - 2 - */ - - VERIFY_CHECK(child1(i) < heap_size); - /* Proof: - * i < heap_size/2 - * i + 1 <= heap_size/2 - * 2*i + 2 <= heap_size - * 2*i + 1 < heap_size - * child1(i) < heap_size - */ - - /* Let [x] be notation for the contents at a[x*stride]. - * - * If [child1(i)] > [i] and [child2(i)] > [i], - * swap [i] with the larger child to ensure the new parent is larger - * than both children. When [child1(i)] == [child2(i)], swap [i] with - * [child2(i)]. - * Else if [child1(i)] > [i], swap [i] with [child1(i)]. - * Else if [child2(i)] > [i], swap [i] with [child2(i)]. - */ - if (child2(i) < heap_size - && 0 <= cmp(a + child2(i)*stride, a + child1(i)*stride, cmp_data)) { - if (0 < cmp(a + child2(i)*stride, a + i*stride, cmp_data)) { - heap_swap(a, i, child2(i), stride); - i = child2(i); - } else { - /* At this point we have [child2(i)] >= [child1(i)] and we have - * [child2(i)] <= [i], and thus [child1(i)] <= [i] which means - * that the next comparison can be skipped. */ - return; - } - } else if (0 < cmp(a + child1(i)*stride, a + i*stride, cmp_data)) { - heap_swap(a, i, child1(i), stride); - i = child1(i); - } else { - return; - } - } - /* heap_size/2 <= i - * heap_size/2 < i + 1 - * heap_size < 2*i + 2 - * heap_size <= 2*i + 1 - * heap_size <= child1(i) - * Thus child1(i) and child2(i) are now out of bounds and we are at a leaf. - */ -} - -/* In-place heap sort. */ -static void rustsecp256k1zkp_v0_8_0_hsort(void *ptr, size_t count, size_t size, - int (*cmp)(const void *, const void *, void *), - void *cmp_data ) { - size_t i; - - for(i = count/2; 0 < i; --i) { - heap_down(ptr, i-1, count, size, cmp, cmp_data); - } - for(i = count; 1 < i; --i) { - /* Extract the largest value from the heap */ - heap_swap(ptr, 0, i-1, size); - - /* Repair the heap condition */ - heap_down(ptr, 0, i-1, size, cmp, cmp_data); - } -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/main_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/main_impl.h deleted file mode 100644 index 8e55c581..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/main_impl.h +++ /dev/null @@ -1,334 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_EXTRAKEYS_MAIN_H -#define SECP256K1_MODULE_EXTRAKEYS_MAIN_H - -#include "../../../include/secp256k1.h" -#include "../../../include/secp256k1_extrakeys.h" -#include "hsort_impl.h" - -static SECP256K1_INLINE int rustsecp256k1zkp_v0_8_0_xonly_pubkey_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ge *ge, const rustsecp256k1zkp_v0_8_0_xonly_pubkey *pubkey) { - return rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, ge, (const rustsecp256k1zkp_v0_8_0_pubkey *) pubkey); -} - -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_xonly_pubkey_save(rustsecp256k1zkp_v0_8_0_xonly_pubkey *pubkey, rustsecp256k1zkp_v0_8_0_ge *ge) { - rustsecp256k1zkp_v0_8_0_pubkey_save((rustsecp256k1zkp_v0_8_0_pubkey *) pubkey, ge); -} - -int rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_xonly_pubkey *pubkey, const unsigned char *input32) { - rustsecp256k1zkp_v0_8_0_ge pk; - rustsecp256k1zkp_v0_8_0_fe x; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - memset(pubkey, 0, sizeof(*pubkey)); - ARG_CHECK(input32 != NULL); - - if (!rustsecp256k1zkp_v0_8_0_fe_set_b32(&x, input32)) { - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_ge_set_xo_var(&pk, &x, 0)) { - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_ge_is_in_correct_subgroup(&pk)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_xonly_pubkey_save(pubkey, &pk); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *output32, const rustsecp256k1zkp_v0_8_0_xonly_pubkey *pubkey) { - rustsecp256k1zkp_v0_8_0_ge pk; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output32 != NULL); - memset(output32, 0, 32); - ARG_CHECK(pubkey != NULL); - - if (!rustsecp256k1zkp_v0_8_0_xonly_pubkey_load(ctx, &pk, pubkey)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_fe_get_b32(output32, &pk.x); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_xonly_pubkey_cmp(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_xonly_pubkey* pk0, const rustsecp256k1zkp_v0_8_0_xonly_pubkey* pk1) { - unsigned char out[2][32]; - const rustsecp256k1zkp_v0_8_0_xonly_pubkey* pk[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - pk[0] = pk0; pk[1] = pk1; - for (i = 0; i < 2; i++) { - /* If the public key is NULL or invalid, xonly_pubkey_serialize will - * call the illegal_callback and return 0. In that case we will - * serialize the key as all zeros which is less than any valid public - * key. This results in consistent comparisons even if NULL or invalid - * pubkeys are involved and prevents edge cases such as sorting - * algorithms that use this function and do not terminate as a - * result. */ - if (!rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, out[i], pk[i])) { - /* Note that xonly_pubkey_serialize should already set the output to - * zero in that case, but it's not guaranteed by the API, we can't - * test it and writing a VERIFY_CHECK is more complex than - * explicitly memsetting (again). */ - memset(out[i], 0, sizeof(out[i])); - } - } - return rustsecp256k1zkp_v0_8_0_memcmp_var(out[0], out[1], sizeof(out[1])); -} - -/** Keeps a group element as is if it has an even Y and otherwise negates it. - * y_parity is set to 0 in the former case and to 1 in the latter case. - * Requires that the coordinates of r are normalized. */ -static int rustsecp256k1zkp_v0_8_0_extrakeys_ge_even_y(rustsecp256k1zkp_v0_8_0_ge *r) { - int y_parity = 0; - VERIFY_CHECK(!rustsecp256k1zkp_v0_8_0_ge_is_infinity(r)); - - if (rustsecp256k1zkp_v0_8_0_fe_is_odd(&r->y)) { - rustsecp256k1zkp_v0_8_0_fe_negate(&r->y, &r->y, 1); - y_parity = 1; - } - return y_parity; -} - -int rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_xonly_pubkey *xonly_pubkey, int *pk_parity, const rustsecp256k1zkp_v0_8_0_pubkey *pubkey) { - rustsecp256k1zkp_v0_8_0_ge pk; - int tmp; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(xonly_pubkey != NULL); - ARG_CHECK(pubkey != NULL); - - if (!rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &pk, pubkey)) { - return 0; - } - tmp = rustsecp256k1zkp_v0_8_0_extrakeys_ge_even_y(&pk); - if (pk_parity != NULL) { - *pk_parity = tmp; - } - rustsecp256k1zkp_v0_8_0_xonly_pubkey_save(xonly_pubkey, &pk); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *output_pubkey, const rustsecp256k1zkp_v0_8_0_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_ge pk; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output_pubkey != NULL); - memset(output_pubkey, 0, sizeof(*output_pubkey)); - ARG_CHECK(internal_pubkey != NULL); - ARG_CHECK(tweak32 != NULL); - - if (!rustsecp256k1zkp_v0_8_0_xonly_pubkey_load(ctx, &pk, internal_pubkey) - || !rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add_helper(&pk, tweak32)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_pubkey_save(output_pubkey, &pk); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(const rustsecp256k1zkp_v0_8_0_context* ctx, const unsigned char *tweaked_pubkey32, int tweaked_pk_parity, const rustsecp256k1zkp_v0_8_0_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_ge pk; - unsigned char pk_expected32[32]; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(internal_pubkey != NULL); - ARG_CHECK(tweaked_pubkey32 != NULL); - ARG_CHECK(tweak32 != NULL); - - if (!rustsecp256k1zkp_v0_8_0_xonly_pubkey_load(ctx, &pk, internal_pubkey) - || !rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add_helper(&pk, tweak32)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&pk.x); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&pk.y); - rustsecp256k1zkp_v0_8_0_fe_get_b32(pk_expected32, &pk.x); - - return rustsecp256k1zkp_v0_8_0_memcmp_var(&pk_expected32, tweaked_pubkey32, 32) == 0 - && rustsecp256k1zkp_v0_8_0_fe_is_odd(&pk.y) == tweaked_pk_parity; -} - -static void rustsecp256k1zkp_v0_8_0_keypair_save(rustsecp256k1zkp_v0_8_0_keypair *keypair, const rustsecp256k1zkp_v0_8_0_scalar *sk, rustsecp256k1zkp_v0_8_0_ge *pk) { - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&keypair->data[0], sk); - rustsecp256k1zkp_v0_8_0_pubkey_save((rustsecp256k1zkp_v0_8_0_pubkey *)&keypair->data[32], pk); -} - - -static int rustsecp256k1zkp_v0_8_0_keypair_seckey_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_scalar *sk, const rustsecp256k1zkp_v0_8_0_keypair *keypair) { - int ret; - - ret = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(sk, &keypair->data[0]); - /* We can declassify ret here because sk is only zero if a keypair function - * failed (which zeroes the keypair) and its return value is ignored. */ - rustsecp256k1zkp_v0_8_0_declassify(ctx, &ret, sizeof(ret)); - ARG_CHECK(ret); - return ret; -} - -/* Load a keypair into pk and sk (if non-NULL). This function declassifies pk - * and ARG_CHECKs that the keypair is not invalid. It always initializes sk and - * pk with dummy values. */ -static int rustsecp256k1zkp_v0_8_0_keypair_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_scalar *sk, rustsecp256k1zkp_v0_8_0_ge *pk, const rustsecp256k1zkp_v0_8_0_keypair *keypair) { - int ret; - const rustsecp256k1zkp_v0_8_0_pubkey *pubkey = (const rustsecp256k1zkp_v0_8_0_pubkey *)&keypair->data[32]; - - /* Need to declassify the pubkey because pubkey_load ARG_CHECKs if it's - * invalid. */ - rustsecp256k1zkp_v0_8_0_declassify(ctx, pubkey, sizeof(*pubkey)); - ret = rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, pk, pubkey); - if (sk != NULL) { - ret = ret && rustsecp256k1zkp_v0_8_0_keypair_seckey_load(ctx, sk, keypair); - } - if (!ret) { - *pk = rustsecp256k1zkp_v0_8_0_ge_const_g; - if (sk != NULL) { - *sk = rustsecp256k1zkp_v0_8_0_scalar_one; - } - } - return ret; -} - -int rustsecp256k1zkp_v0_8_0_keypair_create(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_keypair *keypair, const unsigned char *seckey32) { - rustsecp256k1zkp_v0_8_0_scalar sk; - rustsecp256k1zkp_v0_8_0_ge pk; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(keypair != NULL); - memset(keypair, 0, sizeof(*keypair)); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(seckey32 != NULL); - - ret = rustsecp256k1zkp_v0_8_0_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &sk, &pk, seckey32); - rustsecp256k1zkp_v0_8_0_keypair_save(keypair, &sk, &pk); - rustsecp256k1zkp_v0_8_0_memczero(keypair, sizeof(*keypair), !ret); - - rustsecp256k1zkp_v0_8_0_scalar_clear(&sk); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_keypair_sec(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *seckey, const rustsecp256k1zkp_v0_8_0_keypair *keypair) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - memset(seckey, 0, 32); - ARG_CHECK(keypair != NULL); - - memcpy(seckey, &keypair->data[0], 32); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_keypair_pub(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *pubkey, const rustsecp256k1zkp_v0_8_0_keypair *keypair) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - memset(pubkey, 0, sizeof(*pubkey)); - ARG_CHECK(keypair != NULL); - - memcpy(pubkey->data, &keypair->data[32], sizeof(*pubkey)); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_xonly_pubkey *pubkey, int *pk_parity, const rustsecp256k1zkp_v0_8_0_keypair *keypair) { - rustsecp256k1zkp_v0_8_0_ge pk; - int tmp; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - memset(pubkey, 0, sizeof(*pubkey)); - ARG_CHECK(keypair != NULL); - - if (!rustsecp256k1zkp_v0_8_0_keypair_load(ctx, NULL, &pk, keypair)) { - return 0; - } - tmp = rustsecp256k1zkp_v0_8_0_extrakeys_ge_even_y(&pk); - if (pk_parity != NULL) { - *pk_parity = tmp; - } - rustsecp256k1zkp_v0_8_0_xonly_pubkey_save(pubkey, &pk); - - return 1; -} - -int rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_keypair *keypair, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_ge pk; - rustsecp256k1zkp_v0_8_0_scalar sk; - int y_parity; - int ret; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(keypair != NULL); - ARG_CHECK(tweak32 != NULL); - - ret = rustsecp256k1zkp_v0_8_0_keypair_load(ctx, &sk, &pk, keypair); - memset(keypair, 0, sizeof(*keypair)); - - y_parity = rustsecp256k1zkp_v0_8_0_extrakeys_ge_even_y(&pk); - if (y_parity == 1) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&sk, &sk); - } - - ret &= rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add_helper(&sk, tweak32); - ret &= rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add_helper(&pk, tweak32); - - rustsecp256k1zkp_v0_8_0_declassify(ctx, &ret, sizeof(ret)); - if (ret) { - rustsecp256k1zkp_v0_8_0_keypair_save(keypair, &sk, &pk); - } - - rustsecp256k1zkp_v0_8_0_scalar_clear(&sk); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_pubkey_cmp(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_pubkey* pk0, const rustsecp256k1zkp_v0_8_0_pubkey* pk1) { - unsigned char out[2][33]; - const rustsecp256k1zkp_v0_8_0_pubkey* pk[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - pk[0] = pk0; pk[1] = pk1; - for (i = 0; i < 2; i++) { - size_t outputlen = sizeof(out[i]); - /* If the public key is NULL or invalid, pubkey_serialize will - * call the illegal_callback and return 0. In that case we will - * serialize the key as all zeros which is less than any valid public - * key. This results in consistent comparisons even if NULL or invalid - * pubkeys are involved and prevents edge cases such as sorting - * algorithms that use this function and do not terminate as a - * result. */ - if (!rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, out[i], &outputlen, pk[i], SECP256K1_EC_COMPRESSED)) { - /* Note that pubkey_serialize should already set the output to - * zero in that case, but it's not guaranteed by the API, we can't - * test it and writing a VERIFY_CHECK is more complex than - * explicitly memsetting (again). */ - memset(out[i], 0, sizeof(out[i])); - } - } - return rustsecp256k1zkp_v0_8_0_memcmp_var(out[0], out[1], sizeof(out[1])); -} - -/* This struct wraps a const context pointer to satisfy the rustsecp256k1zkp_v0_8_0_hsort api - * which expects a non-const cmp_data pointer. */ -typedef struct { - const rustsecp256k1zkp_v0_8_0_context *ctx; -} rustsecp256k1zkp_v0_8_0_pubkey_sort_cmp_data; - -static int rustsecp256k1zkp_v0_8_0_pubkey_sort_cmp(const void* pk1, const void* pk2, void *cmp_data) { - return rustsecp256k1zkp_v0_8_0_pubkey_cmp(((rustsecp256k1zkp_v0_8_0_pubkey_sort_cmp_data*)cmp_data)->ctx, - *(rustsecp256k1zkp_v0_8_0_pubkey **)pk1, - *(rustsecp256k1zkp_v0_8_0_pubkey **)pk2); -} - -int rustsecp256k1zkp_v0_8_0_pubkey_sort(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_pubkey **pubkeys, size_t n_pubkeys) { - rustsecp256k1zkp_v0_8_0_pubkey_sort_cmp_data cmp_data; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkeys != NULL); - - cmp_data.ctx = ctx; - rustsecp256k1zkp_v0_8_0_hsort(pubkeys, n_pubkeys, sizeof(*pubkeys), rustsecp256k1zkp_v0_8_0_pubkey_sort_cmp, &cmp_data); - return 1; -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h deleted file mode 100644 index 70477758..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h +++ /dev/null @@ -1,68 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H -#define SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H - -#include "src/modules/extrakeys/main_impl.h" -#include "../../../include/secp256k1_extrakeys.h" - -static void test_exhaustive_extrakeys(const rustsecp256k1zkp_v0_8_0_context *ctx, const rustsecp256k1zkp_v0_8_0_ge* group) { - rustsecp256k1zkp_v0_8_0_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1]; - rustsecp256k1zkp_v0_8_0_pubkey pubkey[EXHAUSTIVE_TEST_ORDER - 1]; - rustsecp256k1zkp_v0_8_0_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1]; - int parities[EXHAUSTIVE_TEST_ORDER - 1]; - unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32]; - int i; - - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { - rustsecp256k1zkp_v0_8_0_fe fe; - rustsecp256k1zkp_v0_8_0_scalar scalar_i; - unsigned char buf[33]; - int parity; - - rustsecp256k1zkp_v0_8_0_scalar_set_int(&scalar_i, i); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(buf, &scalar_i); - - /* Construct pubkey and keypair. */ - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair[i - 1], buf)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey[i - 1], buf)); - - /* Construct serialized xonly_pubkey from keypair. */ - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parities[i - 1], &keypair[i - 1])); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1])); - - /* Parse the xonly_pubkey back and verify it matches the previously serialized value. */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(ctx, &xonly_pubkey[i - 1], xonly_pubkey_bytes[i - 1])); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1])); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0); - - /* Construct the xonly_pubkey from the pubkey, and verify it matches the same. */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(ctx, &xonly_pubkey[i - 1], &parity, &pubkey[i - 1])); - CHECK(parity == parities[i - 1]); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1])); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0); - - /* Compare the xonly_pubkey bytes against the precomputed group. */ - rustsecp256k1zkp_v0_8_0_fe_set_b32(&fe, xonly_pubkey_bytes[i - 1]); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&fe, &group[i].x)); - - /* Check the parity against the precomputed group. */ - fe = group[i].y; - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&fe); - CHECK(rustsecp256k1zkp_v0_8_0_fe_is_odd(&fe) == parities[i - 1]); - - /* Verify that the higher half is identical to the lower half mirrored. */ - if (i > EXHAUSTIVE_TEST_ORDER / 2) { - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(xonly_pubkey_bytes[i - 1], xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - i - 1], 32) == 0); - CHECK(parities[i - 1] == 1 - parities[EXHAUSTIVE_TEST_ORDER - i - 1]); - } - } - - /* TODO: keypair/xonly_pubkey tweak tests */ -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/tests_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/tests_impl.h deleted file mode 100644 index 4c591f91..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/tests_impl.h +++ /dev/null @@ -1,829 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_H -#define SECP256K1_MODULE_EXTRAKEYS_TESTS_H - -#include "../../../include/secp256k1_extrakeys.h" - -static rustsecp256k1zkp_v0_8_0_context* api_test_context(int flags, int *ecount) { - rustsecp256k1zkp_v0_8_0_context *ctx0 = rustsecp256k1zkp_v0_8_0_context_create(flags); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(ctx0, counting_illegal_callback_fn, ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount); - return ctx0; -} - -void test_xonly_pubkey(void) { - rustsecp256k1zkp_v0_8_0_pubkey pk; - rustsecp256k1zkp_v0_8_0_xonly_pubkey xonly_pk, xonly_pk_tmp; - rustsecp256k1zkp_v0_8_0_ge pk1; - rustsecp256k1zkp_v0_8_0_ge pk2; - rustsecp256k1zkp_v0_8_0_fe y; - unsigned char sk[32]; - unsigned char xy_sk[32]; - unsigned char buf32[32]; - unsigned char ones32[32]; - unsigned char zeros64[64] = { 0 }; - int pk_parity; - int i; - - int ecount; - rustsecp256k1zkp_v0_8_0_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); - rustsecp256k1zkp_v0_8_0_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount); - rustsecp256k1zkp_v0_8_0_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); - - rustsecp256k1zkp_v0_8_0_testrand256(sk); - memset(ones32, 0xFF, 32); - rustsecp256k1zkp_v0_8_0_testrand256(xy_sk); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(sign, &pk, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1); - - /* Test xonly_pubkey_from_pubkey */ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(sign, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(verify, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(none, NULL, &pk_parity, &pk) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, NULL) == 0); - CHECK(ecount == 2); - memset(&pk, 0, sizeof(pk)); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 0); - CHECK(ecount == 3); - - /* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */ - memset(sk, 0, sizeof(sk)); - sk[0] = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pk, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pk, &xonly_pk, sizeof(pk)) == 0); - CHECK(pk_parity == 0); - - /* Choose a secret key such that pubkey and xonly_pubkey are each others - * negation. */ - sk[0] = 2; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pk, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&xonly_pk, &pk, sizeof(xonly_pk)) != 0); - CHECK(pk_parity == 1); - rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &pk1, &pk); - rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &pk2, (rustsecp256k1zkp_v0_8_0_pubkey *) &xonly_pk); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal(&pk1.x, &pk2.x) == 1); - rustsecp256k1zkp_v0_8_0_fe_negate(&y, &pk2.y, 1); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal(&pk1.y, &y) == 1); - - /* Test xonly_pubkey_serialize and xonly_pubkey_parse */ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(none, NULL, &xonly_pk) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(none, buf32, NULL) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(buf32, zeros64, 32) == 0); - CHECK(ecount == 2); - { - /* A pubkey filled with 0s will fail to serialize due to pubkey_load - * special casing. */ - rustsecp256k1zkp_v0_8_0_xonly_pubkey pk_tmp; - memset(&pk_tmp, 0, sizeof(pk_tmp)); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(none, buf32, &pk_tmp) == 0); - } - /* pubkey_load called illegal callback */ - CHECK(ecount == 3); - - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(none, buf32, &xonly_pk) == 1); - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(none, NULL, buf32) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(none, &xonly_pk, NULL) == 0); - CHECK(ecount == 2); - - /* Serialization and parse roundtrip */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(ctx, &xonly_pk_tmp, buf32) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0); - - /* Test parsing invalid field elements */ - memset(&xonly_pk, 1, sizeof(xonly_pk)); - /* Overflowing field element */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(none, &xonly_pk, ones32) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); - memset(&xonly_pk, 1, sizeof(xonly_pk)); - /* There's no point with x-coordinate 0 on secp256k1 */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(none, &xonly_pk, zeros64) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); - /* If a random 32-byte string can not be parsed with ec_pubkey_parse - * (because interpreted as X coordinate it does not correspond to a point on - * the curve) then xonly_pubkey_parse should fail as well. */ - for (i = 0; i < count; i++) { - unsigned char rand33[33]; - rustsecp256k1zkp_v0_8_0_testrand256(&rand33[1]); - rand33[0] = SECP256K1_TAG_PUBKEY_EVEN; - if (!rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pk, rand33, 33)) { - memset(&xonly_pk, 1, sizeof(xonly_pk)); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); - } else { - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 1); - } - } - CHECK(ecount == 2); - - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(verify); -} - -void test_xonly_pubkey_comparison(void) { - unsigned char pk1_ser[32] = { - 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, - 0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23 - }; - const unsigned char pk2_ser[32] = { - 0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d, - 0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c - }; - rustsecp256k1zkp_v0_8_0_xonly_pubkey pk1; - rustsecp256k1zkp_v0_8_0_xonly_pubkey pk2; - int ecount = 0; - rustsecp256k1zkp_v0_8_0_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); - - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(none, &pk1, pk1_ser) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(none, &pk2, pk2_ser) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_cmp(none, NULL, &pk2) < 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_cmp(none, &pk1, NULL) > 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_cmp(none, &pk1, &pk2) < 0); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_cmp(none, &pk2, &pk1) > 0); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_cmp(none, &pk1, &pk1) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_cmp(none, &pk2, &pk2) == 0); - CHECK(ecount == 2); - memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_cmp(none, &pk1, &pk2) < 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_cmp(none, &pk1, &pk1) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_cmp(none, &pk2, &pk1) > 0); - CHECK(ecount == 6); - - rustsecp256k1zkp_v0_8_0_context_destroy(none); -} - -void test_xonly_pubkey_tweak(void) { - unsigned char zeros64[64] = { 0 }; - unsigned char overflows[32]; - unsigned char sk[32]; - rustsecp256k1zkp_v0_8_0_pubkey internal_pk; - rustsecp256k1zkp_v0_8_0_xonly_pubkey internal_xonly_pk; - rustsecp256k1zkp_v0_8_0_pubkey output_pk; - int pk_parity; - unsigned char tweak[32]; - int i; - - int ecount; - rustsecp256k1zkp_v0_8_0_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); - rustsecp256k1zkp_v0_8_0_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount); - rustsecp256k1zkp_v0_8_0_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); - - memset(overflows, 0xff, sizeof(overflows)); - rustsecp256k1zkp_v0_8_0_testrand256(tweak); - rustsecp256k1zkp_v0_8_0_testrand256(sk); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &internal_pk, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(none, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(sign, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(verify, NULL, &internal_xonly_pk, tweak) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(verify, &output_pk, NULL, tweak) == 0); - CHECK(ecount == 2); - /* NULL internal_xonly_pk zeroes the output_pk */ - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, NULL) == 0); - CHECK(ecount == 3); - /* NULL tweak zeroes the output_pk */ - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); - - /* Invalid tweak zeroes the output_pk */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, overflows) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); - - /* A zero tweak is fine */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, zeros64) == 1); - - /* Fails if the resulting key was infinity */ - for (i = 0; i < count; i++) { - rustsecp256k1zkp_v0_8_0_scalar scalar_tweak; - /* Because sk may be negated before adding, we need to try with tweak = - * sk as well as tweak = -sk. */ - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&scalar_tweak, sk, NULL); - rustsecp256k1zkp_v0_8_0_scalar_negate(&scalar_tweak, &scalar_tweak); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(tweak, &scalar_tweak); - CHECK((rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, sk) == 0) - || (rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); - } - - /* Invalid pk with a valid tweak */ - memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk)); - rustsecp256k1zkp_v0_8_0_testrand256(tweak); - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); - - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(verify); -} - -void test_xonly_pubkey_tweak_check(void) { - unsigned char zeros64[64] = { 0 }; - unsigned char overflows[32]; - unsigned char sk[32]; - rustsecp256k1zkp_v0_8_0_pubkey internal_pk; - rustsecp256k1zkp_v0_8_0_xonly_pubkey internal_xonly_pk; - rustsecp256k1zkp_v0_8_0_pubkey output_pk; - rustsecp256k1zkp_v0_8_0_xonly_pubkey output_xonly_pk; - unsigned char output_pk32[32]; - unsigned char buf32[32]; - int pk_parity; - unsigned char tweak[32]; - - int ecount; - rustsecp256k1zkp_v0_8_0_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); - rustsecp256k1zkp_v0_8_0_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount); - rustsecp256k1zkp_v0_8_0_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); - - memset(overflows, 0xff, sizeof(overflows)); - rustsecp256k1zkp_v0_8_0_testrand256(tweak); - rustsecp256k1zkp_v0_8_0_testrand256(sk); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &internal_pk, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(verify, &output_xonly_pk, &pk_parity, &output_pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, buf32, &output_xonly_pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(none, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(sign, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(verify, NULL, pk_parity, &internal_xonly_pk, tweak) == 0); - CHECK(ecount == 1); - /* invalid pk_parity value */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(verify, buf32, 2, &internal_xonly_pk, tweak) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, NULL, tweak) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, NULL) == 0); - CHECK(ecount == 3); - - memset(tweak, 1, sizeof(tweak)); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(ctx, &internal_xonly_pk, NULL, &internal_pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(ctx, &output_xonly_pk, &pk_parity, &output_pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, output_pk32, &output_xonly_pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1); - - /* Wrong pk_parity */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(ctx, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0); - /* Wrong public key */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, buf32, &internal_xonly_pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 0); - - /* Overflowing tweak not allowed */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, overflows) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); - CHECK(ecount == 3); - - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(verify); -} - -/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1 - * additional pubkeys by calling tweak_add. Then verifies every tweak starting - * from the last pubkey. */ -#define N_PUBKEYS 32 -void test_xonly_pubkey_tweak_recursive(void) { - unsigned char sk[32]; - rustsecp256k1zkp_v0_8_0_pubkey pk[N_PUBKEYS]; - unsigned char pk_serialized[32]; - unsigned char tweak[N_PUBKEYS - 1][32]; - int i; - - rustsecp256k1zkp_v0_8_0_testrand256(sk); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pk[0], sk) == 1); - /* Add tweaks */ - for (i = 0; i < N_PUBKEYS - 1; i++) { - rustsecp256k1zkp_v0_8_0_xonly_pubkey xonly_pk; - memset(tweak[i], i + 1, sizeof(tweak[i])); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(ctx, &pk[i + 1], &xonly_pk, tweak[i]) == 1); - } - - /* Verify tweaks */ - for (i = N_PUBKEYS - 1; i > 0; i--) { - rustsecp256k1zkp_v0_8_0_xonly_pubkey xonly_pk; - int pk_parity; - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk[i]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, pk_serialized, &xonly_pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i - 1]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(ctx, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1); - } -} -#undef N_PUBKEYS - -void test_keypair(void) { - unsigned char sk[32]; - unsigned char sk_tmp[32]; - unsigned char zeros96[96] = { 0 }; - unsigned char overflows[32]; - rustsecp256k1zkp_v0_8_0_keypair keypair; - rustsecp256k1zkp_v0_8_0_pubkey pk, pk_tmp; - rustsecp256k1zkp_v0_8_0_xonly_pubkey xonly_pk, xonly_pk_tmp; - int pk_parity, pk_parity_tmp; - int ecount; - rustsecp256k1zkp_v0_8_0_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); - rustsecp256k1zkp_v0_8_0_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount); - rustsecp256k1zkp_v0_8_0_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); - rustsecp256k1zkp_v0_8_0_context *sttc = rustsecp256k1zkp_v0_8_0_context_clone(rustsecp256k1zkp_v0_8_0_context_no_precomp); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); - - CHECK(sizeof(zeros96) == sizeof(keypair)); - memset(overflows, 0xFF, sizeof(overflows)); - - /* Test keypair_create */ - ecount = 0; - rustsecp256k1zkp_v0_8_0_testrand256(sk); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(none, &keypair, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(verify, &keypair, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(sign, NULL, sk) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(sign, &keypair, NULL) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(sign, &keypair, sk) == 1); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(sttc, &keypair, sk) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); - CHECK(ecount == 3); - - /* Invalid secret key */ - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(sign, &keypair, zeros96) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(sign, &keypair, overflows) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); - - /* Test keypair_pub */ - ecount = 0; - rustsecp256k1zkp_v0_8_0_testrand256(sk); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_pub(none, &pk, &keypair) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_pub(none, NULL, &keypair) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_pub(none, &pk, NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); - - /* Using an invalid keypair is fine for keypair_pub */ - memset(&keypair, 0, sizeof(keypair)); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_pub(none, &pk, &keypair) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); - - /* keypair holds the same pubkey as pubkey_create */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(sign, &pk, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(sign, &keypair, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_pub(none, &pk_tmp, &keypair) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0); - - /** Test keypair_xonly_pub **/ - ecount = 0; - rustsecp256k1zkp_v0_8_0_testrand256(sk); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(none, NULL, &pk_parity, &keypair) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(none, &xonly_pk, NULL, &keypair) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(none, &xonly_pk, &pk_parity, NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); - /* Using an invalid keypair will set the xonly_pk to 0 (first reset - * xonly_pk). */ - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1); - memset(&keypair, 0, sizeof(keypair)); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); - CHECK(ecount == 3); - - /** keypair holds the same xonly pubkey as pubkey_create **/ - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(sign, &pk, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(sign, &keypair, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(none, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0); - CHECK(pk_parity == pk_parity_tmp); - - /* Test keypair_seckey */ - ecount = 0; - rustsecp256k1zkp_v0_8_0_testrand256(sk); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_sec(none, sk_tmp, &keypair) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_sec(none, NULL, &keypair) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_sec(none, sk_tmp, NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); - - /* keypair returns the same seckey it got */ - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(sign, &keypair, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_sec(none, sk_tmp, &keypair) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(sk, sk_tmp, sizeof(sk_tmp)) == 0); - - - /* Using an invalid keypair is fine for keypair_seckey */ - memset(&keypair, 0, sizeof(keypair)); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_sec(none, sk_tmp, &keypair) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); - - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(verify); - rustsecp256k1zkp_v0_8_0_context_destroy(sttc); -} - -void test_keypair_add(void) { - unsigned char sk[32]; - rustsecp256k1zkp_v0_8_0_keypair keypair; - unsigned char overflows[32]; - unsigned char zeros96[96] = { 0 }; - unsigned char tweak[32]; - int i; - int ecount = 0; - rustsecp256k1zkp_v0_8_0_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); - rustsecp256k1zkp_v0_8_0_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount); - rustsecp256k1zkp_v0_8_0_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); - - CHECK(sizeof(zeros96) == sizeof(keypair)); - rustsecp256k1zkp_v0_8_0_testrand256(sk); - rustsecp256k1zkp_v0_8_0_testrand256(tweak); - memset(overflows, 0xFF, 32); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, sk) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(none, &keypair, tweak) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(sign, &keypair, tweak) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(verify, &keypair, tweak) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(verify, NULL, tweak) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(verify, &keypair, NULL) == 0); - CHECK(ecount == 2); - /* This does not set the keypair to zeroes */ - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0); - - /* Invalid tweak zeroes the keypair */ - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(ctx, &keypair, overflows) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); - - /* A zero tweak is fine */ - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(ctx, &keypair, zeros96) == 1); - - /* Fails if the resulting keypair was (sk=0, pk=infinity) */ - for (i = 0; i < count; i++) { - rustsecp256k1zkp_v0_8_0_scalar scalar_tweak; - rustsecp256k1zkp_v0_8_0_keypair keypair_tmp; - rustsecp256k1zkp_v0_8_0_testrand256(sk); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, sk) == 1); - memcpy(&keypair_tmp, &keypair, sizeof(keypair)); - /* Because sk may be negated before adding, we need to try with tweak = - * sk as well as tweak = -sk. */ - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&scalar_tweak, sk, NULL); - rustsecp256k1zkp_v0_8_0_scalar_negate(&scalar_tweak, &scalar_tweak); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(tweak, &scalar_tweak); - CHECK((rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(ctx, &keypair, sk) == 0) - || (rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(ctx, &keypair_tmp, tweak) == 0)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0 - || rustsecp256k1zkp_v0_8_0_memcmp_var(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0); - } - - /* Invalid keypair with a valid tweak */ - memset(&keypair, 0, sizeof(keypair)); - rustsecp256k1zkp_v0_8_0_testrand256(tweak); - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); - /* Only seckey part of keypair invalid */ - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, sk) == 1); - memset(&keypair, 0, 32); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0); - CHECK(ecount == 2); - /* Only pubkey part of keypair invalid */ - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, sk) == 1); - memset(&keypair.data[32], 0, 64); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0); - CHECK(ecount == 3); - - /* Check that the keypair_tweak_add implementation is correct */ - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, sk) == 1); - for (i = 0; i < count; i++) { - rustsecp256k1zkp_v0_8_0_xonly_pubkey internal_pk; - rustsecp256k1zkp_v0_8_0_xonly_pubkey output_pk; - rustsecp256k1zkp_v0_8_0_pubkey output_pk_xy; - rustsecp256k1zkp_v0_8_0_pubkey output_pk_expected; - unsigned char pk32[32]; - unsigned char sk32[32]; - int pk_parity; - - rustsecp256k1zkp_v0_8_0_testrand256(tweak); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(ctx, &output_pk, &pk_parity, &keypair) == 1); - - /* Check that it passes xonly_pubkey_tweak_add_check */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, pk32, &output_pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(ctx, pk32, pk_parity, &internal_pk, tweak) == 1); - - /* Check that the resulting pubkey matches xonly_pubkey_tweak_add */ - CHECK(rustsecp256k1zkp_v0_8_0_keypair_pub(ctx, &output_pk_xy, &keypair) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add(ctx, &output_pk_expected, &internal_pk, tweak) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); - - /* Check that the secret key in the keypair is tweaked correctly */ - CHECK(rustsecp256k1zkp_v0_8_0_keypair_sec(none, sk32, &keypair) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &output_pk_expected, sk32) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); - } - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(verify); -} - -static void test_hsort_is_sorted(int *ints, size_t n) { - size_t i; - for (i = 1; i < n; i++) { - CHECK(ints[i-1] <= ints[i]); - } -} - -static int test_hsort_cmp(const void *i1, const void *i2, void *counter) { - *(size_t*)counter += 1; - return *(int*)i1 - *(int*)i2; -} - -#define NUM 64 -void test_hsort(void) { - int ints[NUM] = { 0 }; - size_t counter = 0; - int i, j; - - rustsecp256k1zkp_v0_8_0_hsort(ints, 0, sizeof(ints[0]), test_hsort_cmp, &counter); - CHECK(counter == 0); - rustsecp256k1zkp_v0_8_0_hsort(ints, 1, sizeof(ints[0]), test_hsort_cmp, &counter); - CHECK(counter == 0); - rustsecp256k1zkp_v0_8_0_hsort(ints, NUM, sizeof(ints[0]), test_hsort_cmp, &counter); - CHECK(counter > 0); - test_hsort_is_sorted(ints, NUM); - - /* Test hsort with length n array and random elements in - * [-interval/2, interval/2] */ - for (i = 0; i < count; i++) { - int n = rustsecp256k1zkp_v0_8_0_testrand_int(NUM); - int interval = rustsecp256k1zkp_v0_8_0_testrand_int(64); - for (j = 0; j < n; j++) { - ints[j] = rustsecp256k1zkp_v0_8_0_testrand_int(interval) - interval/2; - } - rustsecp256k1zkp_v0_8_0_hsort(ints, n, sizeof(ints[0]), test_hsort_cmp, &counter); - test_hsort_is_sorted(ints, n); - } -} -#undef NUM - -void test_pubkey_comparison(void) { - unsigned char pk1_ser[33] = { - 0x02, - 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, - 0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23 - }; - const unsigned char pk2_ser[33] = { - 0x03, - 0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d, - 0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c - }; - rustsecp256k1zkp_v0_8_0_pubkey pk1; - rustsecp256k1zkp_v0_8_0_pubkey pk2; - int ecount = 0; - rustsecp256k1zkp_v0_8_0_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); - - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(none, &pk1, pk1_ser, sizeof(pk1_ser)) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(none, &pk2, pk2_ser, sizeof(pk2_ser)) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_cmp(none, NULL, &pk2) < 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_cmp(none, &pk1, NULL) > 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_cmp(none, &pk1, &pk2) < 0); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_cmp(none, &pk2, &pk1) > 0); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_cmp(none, &pk1, &pk1) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_cmp(none, &pk2, &pk2) == 0); - CHECK(ecount == 2); - memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */ - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_cmp(none, &pk1, &pk2) < 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_cmp(none, &pk1, &pk1) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_cmp(none, &pk2, &pk1) > 0); - CHECK(ecount == 6); - - rustsecp256k1zkp_v0_8_0_context_destroy(none); -} - -void test_sort_helper(rustsecp256k1zkp_v0_8_0_pubkey *pk, size_t *pk_order, size_t n_pk) { - size_t i; - const rustsecp256k1zkp_v0_8_0_pubkey *pk_test[5]; - - for (i = 0; i < n_pk; i++) { - pk_test[i] = &pk[pk_order[i]]; - } - rustsecp256k1zkp_v0_8_0_pubkey_sort(ctx, pk_test, n_pk); - for (i = 0; i < n_pk; i++) { - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(pk_test[i], &pk[i], sizeof(*pk_test[i])) == 0); - } -} - -void permute(size_t *arr, size_t n) { - size_t i; - for (i = n - 1; i >= 1; i--) { - size_t tmp, j; - j = rustsecp256k1zkp_v0_8_0_testrand_int(i + 1); - tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; - } -} - -void rand_pk(rustsecp256k1zkp_v0_8_0_pubkey *pk) { - unsigned char seckey[32]; - rustsecp256k1zkp_v0_8_0_keypair keypair; - rustsecp256k1zkp_v0_8_0_testrand256(seckey); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, seckey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_pub(ctx, pk, &keypair) == 1); -} - -void test_sort_api(void) { - int ecount = 0; - rustsecp256k1zkp_v0_8_0_pubkey pks[2]; - const rustsecp256k1zkp_v0_8_0_pubkey *pks_ptr[2]; - rustsecp256k1zkp_v0_8_0_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); - - pks_ptr[0] = &pks[0]; - pks_ptr[1] = &pks[1]; - - rand_pk(&pks[0]); - rand_pk(&pks[1]); - - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_sort(none, pks_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_sort(none, NULL, 2) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_sort(none, pks_ptr, 0) == 1); - /* Test illegal public keys */ - memset(&pks[0], 0, sizeof(pks[0])); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_sort(none, pks_ptr, 2) == 1); - CHECK(ecount == 2); - memset(&pks[1], 0, sizeof(pks[1])); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_sort(none, pks_ptr, 2) == 1); - CHECK(ecount > 2); - - rustsecp256k1zkp_v0_8_0_context_destroy(none); -} - -void test_sort(void) { - rustsecp256k1zkp_v0_8_0_pubkey pk[5]; - unsigned char pk_ser[5][33] = { - { 0x02, 0x08 }, - { 0x02, 0x0b }, - { 0x02, 0x0c }, - { 0x03, 0x05 }, - { 0x03, 0x0a }, - }; - int i; - size_t pk_order[5] = { 0, 1, 2, 3, 4 }; - - for (i = 0; i < 5; i++) { - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pk[i], pk_ser[i], sizeof(pk_ser[i]))); - } - - permute(pk_order, 1); - test_sort_helper(pk, pk_order, 1); - permute(pk_order, 2); - test_sort_helper(pk, pk_order, 2); - permute(pk_order, 3); - test_sort_helper(pk, pk_order, 3); - for (i = 0; i < count; i++) { - permute(pk_order, 4); - test_sort_helper(pk, pk_order, 4); - } - for (i = 0; i < count; i++) { - permute(pk_order, 5); - test_sort_helper(pk, pk_order, 5); - } - /* Check that sorting also works for random pubkeys */ - for (i = 0; i < count; i++) { - int j; - const rustsecp256k1zkp_v0_8_0_pubkey *pk_ptr[5]; - for (j = 0; j < 5; j++) { - rand_pk(&pk[j]); - pk_ptr[j] = &pk[j]; - } - rustsecp256k1zkp_v0_8_0_pubkey_sort(ctx, pk_ptr, 5); - for (j = 1; j < 5; j++) { - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_sort_cmp(&pk_ptr[j - 1], &pk_ptr[j], ctx) <= 0); - } - } -} - -/* Test vectors from BIP-MuSig2 */ -void test_sort_vectors(void) { - enum { N_PUBKEYS = 6 }; - unsigned char pk_ser[N_PUBKEYS][33] = { - { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, - 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, - 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 }, - { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, - 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, - 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, - { 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, - 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, - 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }, - { 0x02, 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, 0x15, 0xC2, - 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, 0x14, 0x93, 0x16, 0xC3, 0x51, - 0x8C, 0xE7, 0xB7, 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 }, - { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, - 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, - 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xFF }, - { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, - 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, - 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 } - }; - rustsecp256k1zkp_v0_8_0_pubkey pubkeys[N_PUBKEYS]; - rustsecp256k1zkp_v0_8_0_pubkey *sorted[N_PUBKEYS]; - const rustsecp256k1zkp_v0_8_0_pubkey *pks_ptr[N_PUBKEYS]; - int i; - - sorted[0] = &pubkeys[3]; - sorted[1] = &pubkeys[0]; - sorted[2] = &pubkeys[0]; - sorted[3] = &pubkeys[4]; - sorted[4] = &pubkeys[1]; - sorted[5] = &pubkeys[2]; - - for (i = 0; i < N_PUBKEYS; i++) { - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkeys[i], pk_ser[i], sizeof(pk_ser[i]))); - pks_ptr[i] = &pubkeys[i]; - } - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_sort(ctx, pks_ptr, N_PUBKEYS) == 1); - for (i = 0; i < N_PUBKEYS; i++) { - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(pks_ptr[i], sorted[i], sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) == 0); - } -} - -void run_extrakeys_tests(void) { - /* xonly key test cases */ - test_xonly_pubkey(); - test_xonly_pubkey_tweak(); - test_xonly_pubkey_tweak_check(); - test_xonly_pubkey_tweak_recursive(); - test_xonly_pubkey_comparison(); - - /* keypair tests */ - test_keypair(); - test_keypair_add(); - - test_hsort(); - test_pubkey_comparison(); - test_sort_api(); - test_sort(); - test_sort_vectors(); -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/Makefile.am.include b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/Makefile.am.include deleted file mode 100644 index 25d1c85d..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/Makefile.am.include +++ /dev/null @@ -1,11 +0,0 @@ -include_HEADERS += include/rustsecp256k1zkp_v0_8_0_generator.h -noinst_HEADERS += src/modules/generator/pedersen.h -noinst_HEADERS += src/modules/generator/pedersen_impl.h -noinst_HEADERS += src/modules/generator/main_impl.h -noinst_HEADERS += src/modules/generator/tests_impl.h -if USE_BENCHMARK -noinst_PROGRAMS += bench_generator -bench_generator_SOURCES = src/bench_generator.c -bench_generator_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_generator_LDFLAGS = -static -endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/main_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/main_impl.h deleted file mode 100644 index 33df672a..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/main_impl.h +++ /dev/null @@ -1,442 +0,0 @@ -/********************************************************************** - * Copyright (c) 2016 Andrew Poelstra & Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_GENERATOR_MAIN -#define SECP256K1_MODULE_GENERATOR_MAIN - -#include - -#include "../../field.h" -#include "../../group.h" -#include "../../hash.h" -#include "../../scalar.h" - -#include "modules/generator/pedersen_impl.h" - -/** Alternative generator for secp256k1. - * This is the sha256 of 'g' after standard encoding (without compression), - * which happens to be a point on the curve. More precisely, the generator is - * derived by running the following script with the sage mathematics software. - - import hashlib - F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) - G = '0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8' - H = EllipticCurve ([F (0), F (7)]).lift_x(F(int(hashlib.sha256(G.decode('hex')).hexdigest(),16))) - print('%x %x' % H.xy()) - */ -static const rustsecp256k1zkp_v0_8_0_generator rustsecp256k1zkp_v0_8_0_generator_h_internal = {{ - 0x50, 0x92, 0x9b, 0x74, 0xc1, 0xa0, 0x49, 0x54, 0xb7, 0x8b, 0x4b, 0x60, 0x35, 0xe9, 0x7a, 0x5e, - 0x07, 0x8a, 0x5a, 0x0f, 0x28, 0xec, 0x96, 0xd5, 0x47, 0xbf, 0xee, 0x9a, 0xce, 0x80, 0x3a, 0xc0, - 0x31, 0xd3, 0xc6, 0x86, 0x39, 0x73, 0x92, 0x6e, 0x04, 0x9e, 0x63, 0x7c, 0xb1, 0xb5, 0xf4, 0x0a, - 0x36, 0xda, 0xc2, 0x8a, 0xf1, 0x76, 0x69, 0x68, 0xc3, 0x0c, 0x23, 0x13, 0xf3, 0xa3, 0x89, 0x04 -}}; - -const rustsecp256k1zkp_v0_8_0_generator *rustsecp256k1zkp_v0_8_0_generator_h = &rustsecp256k1zkp_v0_8_0_generator_h_internal; - - -static void rustsecp256k1zkp_v0_8_0_generator_load(rustsecp256k1zkp_v0_8_0_ge* ge, const rustsecp256k1zkp_v0_8_0_generator* gen) { - int succeed; - succeed = rustsecp256k1zkp_v0_8_0_fe_set_b32(&ge->x, &gen->data[0]); - VERIFY_CHECK(succeed != 0); - succeed = rustsecp256k1zkp_v0_8_0_fe_set_b32(&ge->y, &gen->data[32]); - VERIFY_CHECK(succeed != 0); - ge->infinity = 0; - (void) succeed; -} - -static void rustsecp256k1zkp_v0_8_0_generator_save(rustsecp256k1zkp_v0_8_0_generator *gen, rustsecp256k1zkp_v0_8_0_ge* ge) { - VERIFY_CHECK(!rustsecp256k1zkp_v0_8_0_ge_is_infinity(ge)); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge->x); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge->y); - rustsecp256k1zkp_v0_8_0_fe_get_b32(&gen->data[0], &ge->x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(&gen->data[32], &ge->y); -} - -int rustsecp256k1zkp_v0_8_0_generator_parse(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_generator* gen, const unsigned char *input) { - rustsecp256k1zkp_v0_8_0_fe x; - rustsecp256k1zkp_v0_8_0_ge ge; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(gen != NULL); - ARG_CHECK(input != NULL); - - if ((input[0] & 0xFE) != 10 || - !rustsecp256k1zkp_v0_8_0_fe_set_b32(&x, &input[1]) || - !rustsecp256k1zkp_v0_8_0_ge_set_xquad(&ge, &x)) { - return 0; - } - if (input[0] & 1) { - rustsecp256k1zkp_v0_8_0_ge_neg(&ge, &ge); - } - rustsecp256k1zkp_v0_8_0_generator_save(gen, &ge); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_generator_serialize(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *output, const rustsecp256k1zkp_v0_8_0_generator* gen) { - rustsecp256k1zkp_v0_8_0_ge ge; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output != NULL); - ARG_CHECK(gen != NULL); - - rustsecp256k1zkp_v0_8_0_generator_load(&ge, gen); - - output[0] = 11 ^ rustsecp256k1zkp_v0_8_0_fe_is_quad_var(&ge.y); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge.x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(&output[1], &ge.x); - return 1; -} - -static void shallue_van_de_woestijne(rustsecp256k1zkp_v0_8_0_ge* ge, const rustsecp256k1zkp_v0_8_0_fe* t) { - /* Implements the algorithm from: - * Indifferentiable Hashing to Barreto-Naehrig Curves - * Pierre-Alain Fouque and Mehdi Tibouchi - * Latincrypt 2012 - */ - - /* Basic algorithm: - - c = sqrt(-3) - d = (c - 1)/2 - - w = c * t / (1 + b + t^2) [with b = 7] - x1 = d - t*w - x2 = -(x1 + 1) - x3 = 1 + 1/w^2 - - To avoid the 2 divisions, compute the above in numerator/denominator form: - wn = c * t - wd = 1 + 7 + t^2 - x1n = d*wd - t*wn - x1d = wd - x2n = -(x1n + wd) - x2d = wd - x3n = wd^2 + c^2 + t^2 - x3d = (c * t)^2 - - The joint denominator j = wd * c^2 * t^2, and - 1 / x1d = 1/j * c^2 * t^2 - 1 / x2d = x3d = 1/j * wd - */ - - static const rustsecp256k1zkp_v0_8_0_fe c = SECP256K1_FE_CONST(0x0a2d2ba9, 0x3507f1df, 0x233770c2, 0xa797962c, 0xc61f6d15, 0xda14ecd4, 0x7d8d27ae, 0x1cd5f852); - static const rustsecp256k1zkp_v0_8_0_fe d = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40); - static const rustsecp256k1zkp_v0_8_0_fe b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 7); - static const rustsecp256k1zkp_v0_8_0_fe b_plus_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 8); - - rustsecp256k1zkp_v0_8_0_fe wn, wd, x1n, x2n, x3n, x3d, jinv, tmp, x1, x2, x3, alphain, betain, gammain, y1, y2, y3; - int alphaquad, betaquad; - - rustsecp256k1zkp_v0_8_0_fe_mul(&wn, &c, t); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&wd, t); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_add(&wd, &b_plus_one); /* mag 2 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&tmp, t, &wn); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_negate(&tmp, &tmp, 1); /* mag 2 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&x1n, &d, &wd); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_add(&x1n, &tmp); /* mag 3 */ - x2n = x1n; /* mag 3 */ - rustsecp256k1zkp_v0_8_0_fe_add(&x2n, &wd); /* mag 5 */ - rustsecp256k1zkp_v0_8_0_fe_negate(&x2n, &x2n, 5); /* mag 6 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&x3d, &c, t); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&x3d, &x3d); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&x3n, &wd); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_add(&x3n, &x3d); /* mag 2 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&jinv, &x3d, &wd); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_inv(&jinv, &jinv); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&x1, &x1n, &x3d); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&x1, &x1, &jinv); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&x2, &x2n, &x3d); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&x2, &x2, &jinv); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&x3, &x3n, &wd); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&x3, &x3, &jinv); /* mag 1 */ - - rustsecp256k1zkp_v0_8_0_fe_sqr(&alphain, &x1); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&alphain, &alphain, &x1); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_add(&alphain, &b); /* mag 2 */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&betain, &x2); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&betain, &betain, &x2); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_add(&betain, &b); /* mag 2 */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&gammain, &x3); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_mul(&gammain, &gammain, &x3); /* mag 1 */ - rustsecp256k1zkp_v0_8_0_fe_add(&gammain, &b); /* mag 2 */ - - alphaquad = rustsecp256k1zkp_v0_8_0_fe_sqrt(&y1, &alphain); - betaquad = rustsecp256k1zkp_v0_8_0_fe_sqrt(&y2, &betain); - rustsecp256k1zkp_v0_8_0_fe_sqrt(&y3, &gammain); - - rustsecp256k1zkp_v0_8_0_fe_cmov(&x1, &x2, (!alphaquad) & betaquad); - rustsecp256k1zkp_v0_8_0_fe_cmov(&y1, &y2, (!alphaquad) & betaquad); - rustsecp256k1zkp_v0_8_0_fe_cmov(&x1, &x3, (!alphaquad) & !betaquad); - rustsecp256k1zkp_v0_8_0_fe_cmov(&y1, &y3, (!alphaquad) & !betaquad); - - rustsecp256k1zkp_v0_8_0_ge_set_xy(ge, &x1, &y1); - - /* The linked algorithm from the paper uses the Jacobi symbol of t to - * determine the Jacobi symbol of the produced y coordinate. Since the - * rest of the algorithm only uses t^2, we can safely use another criterion - * as long as negation of t results in negation of the y coordinate. Here - * we choose to use t's oddness, as it is faster to determine. */ - rustsecp256k1zkp_v0_8_0_fe_negate(&tmp, &ge->y, 1); - rustsecp256k1zkp_v0_8_0_fe_cmov(&ge->y, &tmp, rustsecp256k1zkp_v0_8_0_fe_is_odd(t)); -} - -static int rustsecp256k1zkp_v0_8_0_generator_generate_internal(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_generator* gen, const unsigned char *key32, const unsigned char *blind32) { - static const unsigned char prefix1[17] = "1st generation: "; - static const unsigned char prefix2[17] = "2nd generation: "; - rustsecp256k1zkp_v0_8_0_fe t = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 4); - rustsecp256k1zkp_v0_8_0_ge add; - rustsecp256k1zkp_v0_8_0_gej accum; - int overflow; - rustsecp256k1zkp_v0_8_0_sha256 sha256; - unsigned char b32[32]; - int ret = 1; - - if (blind32) { - rustsecp256k1zkp_v0_8_0_scalar blind; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&blind, blind32, &overflow); - ret = !overflow; - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &accum, &blind); - } - - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha256); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256, prefix1, 16); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256, key32, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha256, b32); - ret &= rustsecp256k1zkp_v0_8_0_fe_set_b32(&t, b32); - shallue_van_de_woestijne(&add, &t); - if (blind32) { - rustsecp256k1zkp_v0_8_0_gej_add_ge(&accum, &accum, &add); - } else { - rustsecp256k1zkp_v0_8_0_gej_set_ge(&accum, &add); - } - - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha256); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256, prefix2, 16); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256, key32, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha256, b32); - ret &= rustsecp256k1zkp_v0_8_0_fe_set_b32(&t, b32); - shallue_van_de_woestijne(&add, &t); - rustsecp256k1zkp_v0_8_0_gej_add_ge(&accum, &accum, &add); - - rustsecp256k1zkp_v0_8_0_ge_set_gej(&add, &accum); - rustsecp256k1zkp_v0_8_0_generator_save(gen, &add); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_generator_generate(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_generator* gen, const unsigned char *key32) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(gen != NULL); - ARG_CHECK(key32 != NULL); - return rustsecp256k1zkp_v0_8_0_generator_generate_internal(ctx, gen, key32, NULL); -} - -int rustsecp256k1zkp_v0_8_0_generator_generate_blinded(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_generator* gen, const unsigned char *key32, const unsigned char *blind32) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(gen != NULL); - ARG_CHECK(key32 != NULL); - ARG_CHECK(blind32 != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - return rustsecp256k1zkp_v0_8_0_generator_generate_internal(ctx, gen, key32, blind32); -} - -static void rustsecp256k1zkp_v0_8_0_pedersen_commitment_load(rustsecp256k1zkp_v0_8_0_ge* ge, const rustsecp256k1zkp_v0_8_0_pedersen_commitment* commit) { - rustsecp256k1zkp_v0_8_0_fe fe; - rustsecp256k1zkp_v0_8_0_fe_set_b32(&fe, &commit->data[1]); - rustsecp256k1zkp_v0_8_0_ge_set_xquad(ge, &fe); - if (commit->data[0] & 1) { - rustsecp256k1zkp_v0_8_0_ge_neg(ge, ge); - } -} - -static void rustsecp256k1zkp_v0_8_0_pedersen_commitment_save(rustsecp256k1zkp_v0_8_0_pedersen_commitment* commit, rustsecp256k1zkp_v0_8_0_ge* ge) { - rustsecp256k1zkp_v0_8_0_fe_normalize(&ge->x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(&commit->data[1], &ge->x); - commit->data[0] = 9 ^ rustsecp256k1zkp_v0_8_0_fe_is_quad_var(&ge->y); -} - -int rustsecp256k1zkp_v0_8_0_pedersen_commitment_parse(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pedersen_commitment* commit, const unsigned char *input) { - rustsecp256k1zkp_v0_8_0_fe x; - rustsecp256k1zkp_v0_8_0_ge ge; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(commit != NULL); - ARG_CHECK(input != NULL); - (void) ctx; - - if ((input[0] & 0xFE) != 8 || - !rustsecp256k1zkp_v0_8_0_fe_set_b32(&x, &input[1]) || - !rustsecp256k1zkp_v0_8_0_ge_set_xquad(&ge, &x)) { - return 0; - } - if (input[0] & 1) { - rustsecp256k1zkp_v0_8_0_ge_neg(&ge, &ge); - } - rustsecp256k1zkp_v0_8_0_pedersen_commitment_save(commit, &ge); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_pedersen_commitment_serialize(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *output, const rustsecp256k1zkp_v0_8_0_pedersen_commitment* commit) { - rustsecp256k1zkp_v0_8_0_ge ge; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output != NULL); - ARG_CHECK(commit != NULL); - - rustsecp256k1zkp_v0_8_0_pedersen_commitment_load(&ge, commit); - - output[0] = 9 ^ rustsecp256k1zkp_v0_8_0_fe_is_quad_var(&ge.y); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge.x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(&output[1], &ge.x); - return 1; -} - -/* Generates a pedersen commitment: *commit = blind * G + value * G2. The blinding factor is 32 bytes.*/ -int rustsecp256k1zkp_v0_8_0_pedersen_commit(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pedersen_commitment *commit, const unsigned char *blind, uint64_t value, const rustsecp256k1zkp_v0_8_0_generator* gen) { - rustsecp256k1zkp_v0_8_0_ge genp; - rustsecp256k1zkp_v0_8_0_gej rj; - rustsecp256k1zkp_v0_8_0_ge r; - rustsecp256k1zkp_v0_8_0_scalar sec; - int overflow; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(commit != NULL); - ARG_CHECK(blind != NULL); - ARG_CHECK(gen != NULL); - rustsecp256k1zkp_v0_8_0_generator_load(&genp, gen); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&sec, blind, &overflow); - if (!overflow) { - rustsecp256k1zkp_v0_8_0_pedersen_ecmult(&ctx->ecmult_gen_ctx, &rj, &sec, value, &genp); - if (!rustsecp256k1zkp_v0_8_0_gej_is_infinity(&rj)) { - rustsecp256k1zkp_v0_8_0_ge_set_gej(&r, &rj); - rustsecp256k1zkp_v0_8_0_pedersen_commitment_save(commit, &r); - ret = 1; - } - rustsecp256k1zkp_v0_8_0_gej_clear(&rj); - rustsecp256k1zkp_v0_8_0_ge_clear(&r); - } - rustsecp256k1zkp_v0_8_0_scalar_clear(&sec); - return ret; -} - -/** Takes a list of n pointers to 32 byte blinding values, the first negs of which are treated with positive sign and the rest - * negative, then calculates an additional blinding value that adds to zero. - */ -int rustsecp256k1zkp_v0_8_0_pedersen_blind_sum(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *blind_out, const unsigned char * const *blinds, size_t n, size_t npositive) { - rustsecp256k1zkp_v0_8_0_scalar acc; - rustsecp256k1zkp_v0_8_0_scalar x; - size_t i; - int overflow; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(blind_out != NULL); - ARG_CHECK(blinds != NULL); - ARG_CHECK(npositive <= n); - (void) ctx; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&acc, 0); - for (i = 0; i < n; i++) { - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&x, blinds[i], &overflow); - if (overflow) { - return 0; - } - if (i >= npositive) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&x, &x); - } - rustsecp256k1zkp_v0_8_0_scalar_add(&acc, &acc, &x); - } - rustsecp256k1zkp_v0_8_0_scalar_get_b32(blind_out, &acc); - rustsecp256k1zkp_v0_8_0_scalar_clear(&acc); - rustsecp256k1zkp_v0_8_0_scalar_clear(&x); - return 1; -} - -/* Takes two lists of commitments and sums the first set and subtracts the second and verifies that they sum to excess. */ -int rustsecp256k1zkp_v0_8_0_pedersen_verify_tally(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_pedersen_commitment * const* commits, size_t pcnt, const rustsecp256k1zkp_v0_8_0_pedersen_commitment * const* ncommits, size_t ncnt) { - rustsecp256k1zkp_v0_8_0_gej accj; - rustsecp256k1zkp_v0_8_0_ge add; - size_t i; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(!pcnt || (commits != NULL)); - ARG_CHECK(!ncnt || (ncommits != NULL)); - (void) ctx; - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&accj); - for (i = 0; i < ncnt; i++) { - rustsecp256k1zkp_v0_8_0_pedersen_commitment_load(&add, ncommits[i]); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&accj, &accj, &add, NULL); - } - rustsecp256k1zkp_v0_8_0_gej_neg(&accj, &accj); - for (i = 0; i < pcnt; i++) { - rustsecp256k1zkp_v0_8_0_pedersen_commitment_load(&add, commits[i]); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&accj, &accj, &add, NULL); - } - return rustsecp256k1zkp_v0_8_0_gej_is_infinity(&accj); -} - -int rustsecp256k1zkp_v0_8_0_pedersen_blind_generator_blind_sum(const rustsecp256k1zkp_v0_8_0_context* ctx, const uint64_t *value, const unsigned char* const* generator_blind, unsigned char* const* blinding_factor, size_t n_total, size_t n_inputs) { - rustsecp256k1zkp_v0_8_0_scalar sum; - rustsecp256k1zkp_v0_8_0_scalar tmp; - size_t i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(n_total == 0 || value != NULL); - ARG_CHECK(n_total == 0 || generator_blind != NULL); - ARG_CHECK(n_total == 0 || blinding_factor != NULL); - ARG_CHECK(n_total > n_inputs); - (void) ctx; - - if (n_total == 0) { - return 1; - } - - rustsecp256k1zkp_v0_8_0_scalar_set_int(&sum, 0); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&tmp, 0); - - /* Here, n_total > 0. Thus the loop runs at least once. - Thus we may use a do-while loop, which checks the loop - condition only at the end. - - The do-while loop helps GCC prove that the loop runs at least - once and suppresses a -Wmaybe-uninitialized warning. */ - i = 0; - do { - int overflow = 0; - rustsecp256k1zkp_v0_8_0_scalar addend; - rustsecp256k1zkp_v0_8_0_scalar_set_u64(&addend, value[i]); /* s = v */ - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&tmp, generator_blind[i], &overflow); - if (overflow == 1) { - rustsecp256k1zkp_v0_8_0_scalar_clear(&tmp); - rustsecp256k1zkp_v0_8_0_scalar_clear(&addend); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sum); - return 0; - } - rustsecp256k1zkp_v0_8_0_scalar_mul(&addend, &addend, &tmp); /* s = vr */ - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&tmp, blinding_factor[i], &overflow); - if (overflow == 1) { - rustsecp256k1zkp_v0_8_0_scalar_clear(&tmp); - rustsecp256k1zkp_v0_8_0_scalar_clear(&addend); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sum); - return 0; - } - rustsecp256k1zkp_v0_8_0_scalar_add(&addend, &addend, &tmp); /* s = vr + r' */ - rustsecp256k1zkp_v0_8_0_scalar_cond_negate(&addend, i < n_inputs); /* s is negated if it's an input */ - rustsecp256k1zkp_v0_8_0_scalar_add(&sum, &sum, &addend); /* sum += s */ - rustsecp256k1zkp_v0_8_0_scalar_clear(&addend); - - i++; - } while (i < n_total); - - /* Right now tmp has the last pedersen blinding factor. Subtract the sum from it. */ - rustsecp256k1zkp_v0_8_0_scalar_negate(&sum, &sum); - rustsecp256k1zkp_v0_8_0_scalar_add(&tmp, &tmp, &sum); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(blinding_factor[n_total - 1], &tmp); - - rustsecp256k1zkp_v0_8_0_scalar_clear(&tmp); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sum); - return 1; -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/pedersen.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/pedersen.h deleted file mode 100644 index a45b5825..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/pedersen.h +++ /dev/null @@ -1,22 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014, 2015 Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_PEDERSEN_H_ -#define _SECP256K1_PEDERSEN_H_ - -#include "../../ecmult_gen.h" -#include "../../group.h" -#include "../../scalar.h" - -#include - -/** Multiply a small number with the generator: r = gn*G2 */ -static void rustsecp256k1zkp_v0_8_0_pedersen_ecmult_small(rustsecp256k1zkp_v0_8_0_gej *r, uint64_t gn, const rustsecp256k1zkp_v0_8_0_ge* genp); - -/* sec * G + value * G2. */ -static void rustsecp256k1zkp_v0_8_0_pedersen_ecmult(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context *ecmult_gen_ctx, rustsecp256k1zkp_v0_8_0_gej *rj, const rustsecp256k1zkp_v0_8_0_scalar *sec, uint64_t value, const rustsecp256k1zkp_v0_8_0_ge* genp); - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/pedersen_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/pedersen_impl.h deleted file mode 100644 index d37c7a1a..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/pedersen_impl.h +++ /dev/null @@ -1,51 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015 Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php. * - ***********************************************************************/ - -#ifndef _SECP256K1_PEDERSEN_IMPL_H_ -#define _SECP256K1_PEDERSEN_IMPL_H_ - -#include - -#include "../../eckey.h" -#include "../../ecmult_const.h" -#include "../../ecmult_gen.h" -#include "../../group.h" -#include "../../field.h" -#include "../../scalar.h" -#include "../../util.h" - -static void rustsecp256k1zkp_v0_8_0_pedersen_scalar_set_u64(rustsecp256k1zkp_v0_8_0_scalar *sec, uint64_t value) { - unsigned char data[32]; - int i; - for (i = 0; i < 24; i++) { - data[i] = 0; - } - for (; i < 32; i++) { - data[i] = value >> 56; - value <<= 8; - } - rustsecp256k1zkp_v0_8_0_scalar_set_b32(sec, data, NULL); - memset(data, 0, 32); -} - -static void rustsecp256k1zkp_v0_8_0_pedersen_ecmult_small(rustsecp256k1zkp_v0_8_0_gej *r, uint64_t gn, const rustsecp256k1zkp_v0_8_0_ge* genp) { - rustsecp256k1zkp_v0_8_0_scalar s; - rustsecp256k1zkp_v0_8_0_pedersen_scalar_set_u64(&s, gn); - rustsecp256k1zkp_v0_8_0_ecmult_const(r, genp, &s, 64); - rustsecp256k1zkp_v0_8_0_scalar_clear(&s); -} - -/* sec * G + value * G2. */ -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_pedersen_ecmult(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context *ecmult_gen_ctx, rustsecp256k1zkp_v0_8_0_gej *rj, const rustsecp256k1zkp_v0_8_0_scalar *sec, uint64_t value, const rustsecp256k1zkp_v0_8_0_ge* genp) { - rustsecp256k1zkp_v0_8_0_gej vj; - rustsecp256k1zkp_v0_8_0_ecmult_gen(ecmult_gen_ctx, rj, sec); - rustsecp256k1zkp_v0_8_0_pedersen_ecmult_small(&vj, value, genp); - /* FIXME: constant time. */ - rustsecp256k1zkp_v0_8_0_gej_add_var(rj, rj, &vj, NULL); - rustsecp256k1zkp_v0_8_0_gej_clear(&vj); -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/tests_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/tests_impl.h deleted file mode 100644 index 63dcbbeb..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/generator/tests_impl.h +++ /dev/null @@ -1,396 +0,0 @@ -/********************************************************************** - * Copyright (c) 2016 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_GENERATOR_TESTS -#define SECP256K1_MODULE_GENERATOR_TESTS - -#include -#include - -#include "../../group.h" -#include "../../scalar.h" -#include "../../testrand.h" -#include "../../util.h" - -#include "../../../include/secp256k1_generator.h" - -void test_generator_api(void) { - unsigned char key[32]; - unsigned char blind[32]; - unsigned char sergen[33]; - rustsecp256k1zkp_v0_8_0_context *none = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); - rustsecp256k1zkp_v0_8_0_context *sign = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN); - rustsecp256k1zkp_v0_8_0_context *vrfy = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *sttc = rustsecp256k1zkp_v0_8_0_context_clone(rustsecp256k1zkp_v0_8_0_context_no_precomp); - rustsecp256k1zkp_v0_8_0_generator gen; - int32_t ecount = 0; - - rustsecp256k1zkp_v0_8_0_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_testrand256(key); - rustsecp256k1zkp_v0_8_0_testrand256(blind); - - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate(none, &gen, key) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate(none, NULL, key) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate(none, &gen, NULL) == 0); - CHECK(ecount == 2); - - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(sign, &gen, key, blind) == 1); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(vrfy, &gen, key, blind) == 1); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(none, &gen, key, blind) == 1); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(sttc, &gen, key, blind) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(vrfy, NULL, key, blind) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(vrfy, &gen, NULL, blind) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(vrfy, &gen, key, NULL) == 0); - CHECK(ecount == 6); - - CHECK(rustsecp256k1zkp_v0_8_0_generator_serialize(none, sergen, &gen) == 1); - CHECK(ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_generator_serialize(none, NULL, &gen) == 0); - CHECK(ecount == 7); - CHECK(rustsecp256k1zkp_v0_8_0_generator_serialize(none, sergen, NULL) == 0); - CHECK(ecount == 8); - - CHECK(rustsecp256k1zkp_v0_8_0_generator_serialize(none, sergen, &gen) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_generator_parse(none, &gen, sergen) == 1); - CHECK(ecount == 8); - CHECK(rustsecp256k1zkp_v0_8_0_generator_parse(none, NULL, sergen) == 0); - CHECK(ecount == 9); - CHECK(rustsecp256k1zkp_v0_8_0_generator_parse(none, &gen, NULL) == 0); - CHECK(ecount == 10); - - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(vrfy); - rustsecp256k1zkp_v0_8_0_context_destroy(sttc); -} - -void test_shallue_van_de_woestijne(void) { - /* Matches with the output of the shallue_van_de_woestijne.sage SAGE program */ - static const rustsecp256k1zkp_v0_8_0_ge_storage results[32] = { - SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0x0225f529, 0xee75acaf, 0xccfc4560, 0x26c5e46b, 0xf80237a3, 0x3924655a, 0x16f90e88, 0x085ed52a), - SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0xfdda0ad6, 0x118a5350, 0x3303ba9f, 0xd93a1b94, 0x07fdc85c, 0xc6db9aa5, 0xe906f176, 0xf7a12705), - SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0x56716069, 0x6818286b, 0x72f01a3e, 0x5e8caca7, 0x36249160, 0xc7ded69d, 0xd51913c3, 0x03a2fa97), - SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0xa98e9f96, 0x97e7d794, 0x8d0fe5c1, 0xa1735358, 0xc9db6e9f, 0x38212962, 0x2ae6ec3b, 0xfc5d0198), - SECP256K1_GE_STORAGE_CONST(0x531f7239, 0xaebc780e, 0x179fbf8d, 0x412a1b01, 0x511f0abc, 0xe0c46151, 0x8b38db84, 0xcc2467f3, 0x82387d45, 0xec7bd5cc, 0x61fcb9df, 0x41cddd7b, 0x217d8114, 0x3577dc8f, 0x23de356a, 0x7e97704e), - SECP256K1_GE_STORAGE_CONST(0x531f7239, 0xaebc780e, 0x179fbf8d, 0x412a1b01, 0x511f0abc, 0xe0c46151, 0x8b38db84, 0xcc2467f3, 0x7dc782ba, 0x13842a33, 0x9e034620, 0xbe322284, 0xde827eeb, 0xca882370, 0xdc21ca94, 0x81688be1), - SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0x56716069, 0x6818286b, 0x72f01a3e, 0x5e8caca7, 0x36249160, 0xc7ded69d, 0xd51913c3, 0x03a2fa97), - SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0xa98e9f96, 0x97e7d794, 0x8d0fe5c1, 0xa1735358, 0xc9db6e9f, 0x38212962, 0x2ae6ec3b, 0xfc5d0198), - SECP256K1_GE_STORAGE_CONST(0x5e5936b1, 0x81db0b65, 0x8e33a8c6, 0x1aa687dd, 0x31d11e15, 0x85e35664, 0x6b4c2071, 0xcde7e942, 0x88bb5332, 0xa8e05654, 0x78d4f60c, 0x0cd979ec, 0x938558f2, 0xcac11216, 0x7c387a56, 0xe3a6d5f3), - SECP256K1_GE_STORAGE_CONST(0x5e5936b1, 0x81db0b65, 0x8e33a8c6, 0x1aa687dd, 0x31d11e15, 0x85e35664, 0x6b4c2071, 0xcde7e942, 0x7744accd, 0x571fa9ab, 0x872b09f3, 0xf3268613, 0x6c7aa70d, 0x353eede9, 0x83c785a8, 0x1c59263c), - SECP256K1_GE_STORAGE_CONST(0x657d438f, 0xfac34a50, 0x463fd07c, 0x3f09f320, 0x4c98e8ed, 0x6927e330, 0xc0c7735f, 0x76d32f6d, 0x577c2b11, 0xcaca2f6f, 0xd60bcaf0, 0x3e7cebe9, 0x5da6e1f4, 0xbb557f12, 0x2a397331, 0x81df897f), - SECP256K1_GE_STORAGE_CONST(0x657d438f, 0xfac34a50, 0x463fd07c, 0x3f09f320, 0x4c98e8ed, 0x6927e330, 0xc0c7735f, 0x76d32f6d, 0xa883d4ee, 0x3535d090, 0x29f4350f, 0xc1831416, 0xa2591e0b, 0x44aa80ed, 0xd5c68ccd, 0x7e2072b0), - SECP256K1_GE_STORAGE_CONST(0xbe0bc11b, 0x2bc639cb, 0xc28f72a8, 0xd07c21cc, 0xbc06cfa7, 0x4c2ff25e, 0x630c9740, 0x23128eab, 0x6f062fc8, 0x75148197, 0xd10375c3, 0xcc3fadb6, 0x20277e9c, 0x00579c55, 0xeddd7f95, 0xe95604db), - SECP256K1_GE_STORAGE_CONST(0xbe0bc11b, 0x2bc639cb, 0xc28f72a8, 0xd07c21cc, 0xbc06cfa7, 0x4c2ff25e, 0x630c9740, 0x23128eab, 0x90f9d037, 0x8aeb7e68, 0x2efc8a3c, 0x33c05249, 0xdfd88163, 0xffa863aa, 0x12228069, 0x16a9f754), - SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0xfdda0ad6, 0x118a5350, 0x3303ba9f, 0xd93a1b94, 0x07fdc85c, 0xc6db9aa5, 0xe906f176, 0xf7a12705), - SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0x0225f529, 0xee75acaf, 0xccfc4560, 0x26c5e46b, 0xf80237a3, 0x3924655a, 0x16f90e88, 0x085ed52a), - SECP256K1_GE_STORAGE_CONST(0xaee172d4, 0xce7c5010, 0xdb20a88f, 0x469598c1, 0xd7f7926f, 0xabb85cb5, 0x339f1403, 0x87e6b494, 0x38065980, 0x4de81b35, 0x098c7190, 0xe3380f9d, 0x95b2ed6c, 0x6c869e85, 0xc772bc5a, 0x7bc3d9d5), - SECP256K1_GE_STORAGE_CONST(0xaee172d4, 0xce7c5010, 0xdb20a88f, 0x469598c1, 0xd7f7926f, 0xabb85cb5, 0x339f1403, 0x87e6b494, 0xc7f9a67f, 0xb217e4ca, 0xf6738e6f, 0x1cc7f062, 0x6a4d1293, 0x9379617a, 0x388d43a4, 0x843c225a), - SECP256K1_GE_STORAGE_CONST(0xc28f5c28, 0xf5c28f5c, 0x28f5c28f, 0x5c28f5c2, 0x8f5c28f5, 0xc28f5c28, 0xf5c28f5b, 0x6666635a, 0x0c4da840, 0x1b2cf5be, 0x4604e6ec, 0xf92b2780, 0x063a5351, 0xe294bf65, 0xbb2f8b61, 0x00902db7), - SECP256K1_GE_STORAGE_CONST(0xc28f5c28, 0xf5c28f5c, 0x28f5c28f, 0x5c28f5c2, 0x8f5c28f5, 0xc28f5c28, 0xf5c28f5b, 0x6666635a, 0xf3b257bf, 0xe4d30a41, 0xb9fb1913, 0x06d4d87f, 0xf9c5acae, 0x1d6b409a, 0x44d0749d, 0xff6fce78), - SECP256K1_GE_STORAGE_CONST(0xecf56be6, 0x9c8fde26, 0x152832c6, 0xe043b3d5, 0xaf9a723f, 0x789854a0, 0xcb1b810d, 0xe2614ece, 0x66127ae4, 0xe4c17a75, 0x60a727e6, 0xffd2ea7f, 0xaed99088, 0xbec465c6, 0xbde56791, 0x37ed5572), - SECP256K1_GE_STORAGE_CONST(0xecf56be6, 0x9c8fde26, 0x152832c6, 0xe043b3d5, 0xaf9a723f, 0x789854a0, 0xcb1b810d, 0xe2614ece, 0x99ed851b, 0x1b3e858a, 0x9f58d819, 0x002d1580, 0x51266f77, 0x413b9a39, 0x421a986d, 0xc812a6bd), - SECP256K1_GE_STORAGE_CONST(0xba72860f, 0x10fcd142, 0x23f71e3c, 0x228deb9a, 0xc46c5ff5, 0x90b884e5, 0xcc60d51e, 0x0629d16e, 0x67999f31, 0x5a74ada3, 0x526832cf, 0x76b9fec3, 0xa348cc97, 0x33c3aa67, 0x02bd2516, 0x7814f635), - SECP256K1_GE_STORAGE_CONST(0xba72860f, 0x10fcd142, 0x23f71e3c, 0x228deb9a, 0xc46c5ff5, 0x90b884e5, 0xcc60d51e, 0x0629d16e, 0x986660ce, 0xa58b525c, 0xad97cd30, 0x8946013c, 0x5cb73368, 0xcc3c5598, 0xfd42dae8, 0x87eb05fa), - SECP256K1_GE_STORAGE_CONST(0x92ef5657, 0xdba51cc7, 0xf3e1b442, 0xa6a0916b, 0x8ce03079, 0x2ef5657d, 0xba51cc7e, 0xab2beb65, 0x782c65d2, 0x3f1e0eb2, 0x9179a994, 0xe5e8ff80, 0x5a0d50d9, 0xdeeaed90, 0xcec96ca5, 0x973e2ad3), - SECP256K1_GE_STORAGE_CONST(0x92ef5657, 0xdba51cc7, 0xf3e1b442, 0xa6a0916b, 0x8ce03079, 0x2ef5657d, 0xba51cc7e, 0xab2beb65, 0x87d39a2d, 0xc0e1f14d, 0x6e86566b, 0x1a17007f, 0xa5f2af26, 0x2115126f, 0x31369359, 0x68c1d15c), - SECP256K1_GE_STORAGE_CONST(0x9468ad22, 0xf921fc78, 0x8de3f1b0, 0x586c58eb, 0x5e6f0270, 0xe950b602, 0x7ada90d9, 0xd71ae323, 0x922a0c6a, 0x9ccc31d9, 0xc3bf87fd, 0x88381739, 0x35fe393f, 0xa64dfdec, 0x29f2846d, 0x12918d86), - SECP256K1_GE_STORAGE_CONST(0x9468ad22, 0xf921fc78, 0x8de3f1b0, 0x586c58eb, 0x5e6f0270, 0xe950b602, 0x7ada90d9, 0xd71ae323, 0x6dd5f395, 0x6333ce26, 0x3c407802, 0x77c7e8c6, 0xca01c6c0, 0x59b20213, 0xd60d7b91, 0xed6e6ea9), - SECP256K1_GE_STORAGE_CONST(0x76ddc7f5, 0xe029e59e, 0x22b0e54f, 0xa811db94, 0x5a209c4f, 0x5e912ca2, 0x8b4da6a7, 0x4c1e00a2, 0x1e8f516c, 0x91c20437, 0x50f6e24e, 0x8c2cf202, 0xacf68291, 0xbf8b66eb, 0xf7335b62, 0xec2c88fe), - SECP256K1_GE_STORAGE_CONST(0x76ddc7f5, 0xe029e59e, 0x22b0e54f, 0xa811db94, 0x5a209c4f, 0x5e912ca2, 0x8b4da6a7, 0x4c1e00a2, 0xe170ae93, 0x6e3dfbc8, 0xaf091db1, 0x73d30dfd, 0x53097d6e, 0x40749914, 0x08cca49c, 0x13d37331), - SECP256K1_GE_STORAGE_CONST(0xf75763bc, 0x2907e79b, 0x125e33c3, 0x9a027f48, 0x0f8c6409, 0x2153432f, 0x967bc2b1, 0x1d1f5cf0, 0xb4a8edc6, 0x36391b39, 0x9bc219c0, 0x3d033128, 0xdbcd463e, 0xd2506394, 0x061b87a5, 0x9e510235), - SECP256K1_GE_STORAGE_CONST(0xf75763bc, 0x2907e79b, 0x125e33c3, 0x9a027f48, 0x0f8c6409, 0x2153432f, 0x967bc2b1, 0x1d1f5cf0, 0x4b571239, 0xc9c6e4c6, 0x643de63f, 0xc2fcced7, 0x2432b9c1, 0x2daf9c6b, 0xf9e47859, 0x61aef9fa), - }; - - rustsecp256k1zkp_v0_8_0_ge ge; - rustsecp256k1zkp_v0_8_0_fe fe; - rustsecp256k1zkp_v0_8_0_ge_storage ges; - int i, s; - for (i = 1; i <= 16; i++) { - rustsecp256k1zkp_v0_8_0_fe_set_int(&fe, i); - - for (s = 0; s < 2; s++) { - if (s) { - rustsecp256k1zkp_v0_8_0_fe_negate(&fe, &fe, 1); - rustsecp256k1zkp_v0_8_0_fe_normalize(&fe); - } - shallue_van_de_woestijne(&ge, &fe); - rustsecp256k1zkp_v0_8_0_ge_to_storage(&ges, &ge); - - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&ges, &results[i * 2 + s - 2], sizeof(rustsecp256k1zkp_v0_8_0_ge_storage)) == 0); - } - } -} - -void test_generator_generate(void) { - static const rustsecp256k1zkp_v0_8_0_ge_storage results[32] = { - SECP256K1_GE_STORAGE_CONST(0x806cd8ed, 0xd6c153e3, 0x4aa9b9a0, 0x8755c4be, 0x4718b1ef, 0xb26cb93f, 0xfdd99e1b, 0x21f2af8e, 0xc7062208, 0xcc649a03, 0x1bdc1a33, 0x9d01f115, 0x4bcd0dca, 0xfe0b875d, 0x62f35f73, 0x28673006), - SECP256K1_GE_STORAGE_CONST(0xd91b15ec, 0x47a811f4, 0xaa189561, 0xd13f5c4d, 0x4e81f10d, 0xc7dc551f, 0x4fea9b84, 0x610314c4, 0x9b0ada1e, 0xb38efd67, 0x8bff0b6c, 0x7d7315f7, 0xb49b8cc5, 0xa679fad4, 0xc94f9dc6, 0x9da66382), - SECP256K1_GE_STORAGE_CONST(0x11c00de6, 0xf885035e, 0x76051430, 0xa3c38b2a, 0x5f86ab8c, 0xf66dae58, 0x04ea7307, 0x348b19bf, 0xe0858ae7, 0x61dcb1ba, 0xff247e37, 0xd38fcd88, 0xf3bd7911, 0xaa4ed6e0, 0x28d792dd, 0x3ee1ac09), - SECP256K1_GE_STORAGE_CONST(0x986b99eb, 0x3130e7f0, 0xe779f674, 0xb85cb514, 0x46a676bf, 0xb1dfb603, 0x4c4bb639, 0x7c406210, 0xdf900609, 0x8b3ef1e0, 0x30e32fb0, 0xd97a4329, 0xff98aed0, 0xcd278c3f, 0xe6078467, 0xfbd12f35), - SECP256K1_GE_STORAGE_CONST(0xae528146, 0x03fdf91e, 0xc592977e, 0x12461dc7, 0xb9e038f8, 0x048dcb62, 0xea264756, 0xd459ae42, 0x80ef658d, 0x92becb84, 0xdba8e4f9, 0x560d7a72, 0xbaf4c393, 0xfbcf6007, 0x11039f1c, 0x224faaad), - SECP256K1_GE_STORAGE_CONST(0x00df3d91, 0x35975eee, 0x91fab903, 0xe3128e4a, 0xca071dde, 0x270814e5, 0xcbda69ec, 0xcad58f46, 0x11b590aa, 0x92d89969, 0x2dbd932f, 0x08013b8b, 0x45afabc6, 0x43677db2, 0x143e0c0f, 0x5865fb03), - SECP256K1_GE_STORAGE_CONST(0x1168155b, 0x987e9bc8, 0x84c5f3f4, 0x92ebf784, 0xcc8c6735, 0x39d8e5e8, 0xa967115a, 0x2949da9b, 0x0858a470, 0xf403ca97, 0xb1827f6f, 0x544c2c67, 0x08f6cb83, 0xc510c317, 0x96c981ed, 0xb9f61780), - SECP256K1_GE_STORAGE_CONST(0xe8d7c0cf, 0x2bb4194c, 0x97bf2a36, 0xbd115ba0, 0x81a9afe8, 0x7663fa3c, 0x9c3cd253, 0x79fe2571, 0x2028ad04, 0xefa00119, 0x5a25d598, 0x67e79502, 0x49de7c61, 0x4751cd9d, 0x4fb317f6, 0xf76f1110), - SECP256K1_GE_STORAGE_CONST(0x9532c491, 0xa64851dd, 0xcd0d3e5a, 0x93e17267, 0xa10aca95, 0xa23781aa, 0x5087f340, 0xc45fecc3, 0xb691ddc2, 0x3143a7b6, 0x09969302, 0x258affb8, 0x5bbf8666, 0xe1192319, 0xeb174d88, 0x308bd57a), - SECP256K1_GE_STORAGE_CONST(0x6b20b6e2, 0x1ba6cc44, 0x3f2c3a0c, 0x5283ba44, 0xbee43a0a, 0x2799a6cf, 0xbecc0f8a, 0xf8c583ac, 0xf7021e76, 0xd51291a6, 0xf9396215, 0x686f25aa, 0xbec36282, 0x5e11eeea, 0x6e51a6e6, 0xd7d7c006), - SECP256K1_GE_STORAGE_CONST(0xde27e6ff, 0x219b3ab1, 0x2b0a9e4e, 0x51fc6092, 0x96e55af6, 0xc6f717d6, 0x12cd6cce, 0x65d6c8f2, 0x48166884, 0x4dc13fd2, 0xed7a7d81, 0x66a0839a, 0x8a960863, 0xfe0001c1, 0x35d206fd, 0x63b87c09), - SECP256K1_GE_STORAGE_CONST(0x79a96fb8, 0xd88a08d3, 0x055d38d1, 0x3346b0d4, 0x47d838ca, 0xfcc8fa40, 0x6d3a7157, 0xef84e7e3, 0x6bab9c45, 0x2871b51d, 0xb0df2369, 0xe7860e01, 0x2e37ffea, 0x6689fd1a, 0x9c6fe9cf, 0xb940acea), - SECP256K1_GE_STORAGE_CONST(0x06c4d4cb, 0xd32c0ddb, 0x67e988c6, 0x2bdbe6ad, 0xa39b80cc, 0x61afb347, 0x234abe27, 0xa689618c, 0x5b355949, 0xf904fe08, 0x569b2313, 0xe8f19f8d, 0xc5b79e27, 0x70da0832, 0x5fb7a229, 0x238ca6b6), - SECP256K1_GE_STORAGE_CONST(0x7027e566, 0x3e727c28, 0x42aa14e5, 0x52c2d2ec, 0x1d8beaa9, 0x8a22ceab, 0x15ccafc3, 0xb4f06249, 0x9b3dffbc, 0xdbd5e045, 0x6931fd03, 0x8b1c6a9b, 0x4c168c6d, 0xa6553897, 0xfe11ce49, 0xac728139), - SECP256K1_GE_STORAGE_CONST(0xee3520c3, 0x9f2b954d, 0xf8e15547, 0xdaeb6cc8, 0x04c8f3b0, 0x9301f53e, 0xe0c11ea1, 0xeace539d, 0x244ff873, 0x7e060c98, 0xe843c353, 0xcd35d2e4, 0x3cd8b082, 0xcffbc9ae, 0x81eafa70, 0x332f9748), - SECP256K1_GE_STORAGE_CONST(0xdaecd756, 0xf5b706a4, 0xc14e1095, 0x3e2f70df, 0xa81276e7, 0x71806b89, 0x4d8a5502, 0xa0ef4998, 0xbac906c0, 0x948b1d48, 0xe023f439, 0xfd3770b8, 0x837f60cc, 0x40552a51, 0x433d0b79, 0x6610da27), - SECP256K1_GE_STORAGE_CONST(0x55e1ca28, 0x750fe2d0, 0x57f7449b, 0x3f49d999, 0x3b9616dd, 0x5387bc2e, 0x6e6698f8, 0xc4ea49f4, 0xe339e0e9, 0xa4c7fa99, 0xd063e062, 0x6582bce2, 0x33c6b1ee, 0x17a5b47f, 0x6d43ecf8, 0x98b40120), - SECP256K1_GE_STORAGE_CONST(0xdd82cac2, 0x9e0e0135, 0x4964d3bc, 0x27469233, 0xf13bbd5e, 0xd7aff24b, 0x4902fca8, 0x17294b12, 0x561ab1d6, 0xcd9bcb6e, 0x805585cf, 0x3df8714c, 0x1bfa6304, 0x5efbf122, 0x1a3d8fd9, 0x3827764a), - SECP256K1_GE_STORAGE_CONST(0xda5cbfb7, 0x3522e9c7, 0xcb594436, 0x83677038, 0x0eaa64a9, 0x2eca3888, 0x0fe4c9d6, 0xdeb22dbf, 0x4f46de68, 0x0447c780, 0xc54a314b, 0x5389a926, 0xbba8910b, 0x869fc6cd, 0x42ee82e8, 0x5895e42a), - SECP256K1_GE_STORAGE_CONST(0x4e09830e, 0xc8894c58, 0x4e6278de, 0x167a96b0, 0x20d60463, 0xee48f788, 0x4974d66e, 0x871e35e9, 0x21259c4d, 0x332ca932, 0x2e187df9, 0xe7afbc23, 0x9d171ebc, 0x7d9e2560, 0x503f50b1, 0x9fe45834), - SECP256K1_GE_STORAGE_CONST(0xabfff6ca, 0x41dcfd17, 0x03cae629, 0x9d127971, 0xf19ee000, 0x2db332e6, 0x5cc209a3, 0xc21b8f54, 0x65991d60, 0xee54f5cc, 0xddf7a732, 0xa76b0303, 0xb9f519a6, 0x22ea0390, 0x8af23ffa, 0x35ae6632), - SECP256K1_GE_STORAGE_CONST(0xc6c9b92c, 0x91e045a5, 0xa1913277, 0x44d6fce2, 0x11b12c7c, 0x9b3112d6, 0xc61e14a6, 0xd6b1ae12, 0x04ab0396, 0xebdc4c6a, 0xc213cc3e, 0x077a2e80, 0xb4ba7b2b, 0x33907d56, 0x2c98ccf7, 0xb82a2e9f), - SECP256K1_GE_STORAGE_CONST(0x66f6e6d9, 0xc4bb9a5f, 0x99085781, 0x83cb9362, 0x2ea437d8, 0xccd31969, 0xffadca3a, 0xff1d3935, 0x50a5b06e, 0x39e039d7, 0x1dfb2723, 0x18db74e5, 0x5af64da1, 0xdfc34586, 0x6aac3bd0, 0x5792a890), - SECP256K1_GE_STORAGE_CONST(0x58ded03c, 0x98e1a890, 0x63fc7793, 0xe3ecd896, 0x235e75c9, 0x82e7008f, 0xddbf3ca8, 0x5b7e9ecb, 0x34594776, 0x58ab6821, 0xaf43a453, 0xa946fda9, 0x13d24999, 0xccf22df8, 0xd291ef59, 0xb08975c0), - SECP256K1_GE_STORAGE_CONST(0x74557864, 0x4f2b0486, 0xd5beea7c, 0x2d258ccb, 0x78a870e1, 0x848982d8, 0xed3f91a4, 0x9db83a36, 0xd84e940e, 0x1d33c28a, 0x62398ec8, 0xc493aee7, 0x7c2ba722, 0x42dee7ae, 0x3c35c256, 0xad00cf42), - SECP256K1_GE_STORAGE_CONST(0x7fc7963a, 0x16abc8fb, 0x5d61eb61, 0x0fc50a68, 0x754470d2, 0xf43df3be, 0x52228f66, 0x522fe61b, 0x499f9e7f, 0x462c6545, 0x29687af4, 0x9f7c732d, 0x48801ce5, 0x21acd546, 0xc6fb903c, 0x7c265032), - SECP256K1_GE_STORAGE_CONST(0xb2f6257c, 0xc58df82f, 0xb9ba4f36, 0x7ededf03, 0xf8ea10f3, 0x104d7ae6, 0x233b7ac4, 0x725e11de, 0x9c7a32df, 0x4842f33d, 0xaad84f0b, 0x62e88b40, 0x46ddcbde, 0xbbeec6f8, 0x93bfde27, 0x0561dc73), - SECP256K1_GE_STORAGE_CONST(0xe2cdfd27, 0x8a8e22be, 0xabf08b79, 0x1bc6ae38, 0x41d22a9a, 0x9472e266, 0x1a7c6e83, 0xa2f74725, 0x0e26c103, 0xe0dd93b2, 0x3724f3b7, 0x8bb7366e, 0x2c245768, 0xd64f3283, 0xd8316e8a, 0x1383b977), - SECP256K1_GE_STORAGE_CONST(0x757c13e7, 0xe866017e, 0xe6af61d7, 0x161d208a, 0xc438f712, 0x242fcd23, 0x63a10e59, 0xd67e41fb, 0xb550c6a9, 0x4ddb15f3, 0xfeea4bfe, 0xd2faa19f, 0x2aa2fbd3, 0x0c6ae785, 0xe357f365, 0xb30d12e0), - SECP256K1_GE_STORAGE_CONST(0x528d525e, 0xac30095b, 0x5e5f83ca, 0x4d3dea63, 0xeb608f2d, 0x18dd25a7, 0x2529c8e5, 0x1ae5f9f1, 0xfde2860b, 0x492a4106, 0x9f356c05, 0x3ebc045e, 0x4ad08b79, 0x3e264935, 0xf25785a9, 0x8690b5ee), - SECP256K1_GE_STORAGE_CONST(0x150df593, 0x5b6956a0, 0x0cfed843, 0xb9d6ffce, 0x4f790022, 0xea18730f, 0xc495111d, 0x91568e55, 0x6700a2ca, 0x9ff4ed32, 0xc1697312, 0x4eb51ce3, 0x5656344b, 0x65a1e3d5, 0xd6c1f7ce, 0x29233f82), - SECP256K1_GE_STORAGE_CONST(0x38e02eaf, 0x2c8774fd, 0x58b8b373, 0x732457f1, 0x16dbe53b, 0xea5683d9, 0xada20dd7, 0x14ce20a6, 0x6ac5362e, 0xbb425416, 0x8250f43f, 0xa4ee2b63, 0x0406324f, 0x1c876d60, 0xebe5be2c, 0x6eb1515b), - }; - rustsecp256k1zkp_v0_8_0_generator gen; - rustsecp256k1zkp_v0_8_0_ge ge; - rustsecp256k1zkp_v0_8_0_ge_storage ges; - int i; - unsigned char v[32]; - unsigned char s[32] = {0}; - rustsecp256k1zkp_v0_8_0_scalar sc; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&sc, s, NULL); - for (i = 1; i <= 32; i++) { - memset(v, 0, 31); - v[31] = i; - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(ctx, &gen, v, s)); - rustsecp256k1zkp_v0_8_0_generator_load(&ge, &gen); - rustsecp256k1zkp_v0_8_0_ge_to_storage(&ges, &ge); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&ges, &results[i - 1], sizeof(rustsecp256k1zkp_v0_8_0_ge_storage)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate(ctx, &gen, v)); - rustsecp256k1zkp_v0_8_0_generator_load(&ge, &gen); - rustsecp256k1zkp_v0_8_0_ge_to_storage(&ges, &ge); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&ges, &results[i - 1], sizeof(rustsecp256k1zkp_v0_8_0_ge_storage)) == 0); - } - - /* There is no range restriction on the value, but the blinder must be a - * valid scalar. Check that an invalid blinder causes the call to fail - * but not crash. */ - memset(v, 0xff, 32); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate(ctx, &gen, v)); - memset(s, 0xff, 32); - CHECK(!rustsecp256k1zkp_v0_8_0_generator_generate_blinded(ctx, &gen, v, s)); -} - -void test_generator_fixed_vector(void) { - const unsigned char two_g[33] = { - 0x0b, - 0xc6, 0x04, 0x7f, 0x94, 0x41, 0xed, 0x7d, 0x6d, 0x30, 0x45, 0x40, 0x6e, 0x95, 0xc0, 0x7c, 0xd8, - 0x5c, 0x77, 0x8e, 0x4b, 0x8c, 0xef, 0x3c, 0xa7, 0xab, 0xac, 0x09, 0xb9, 0x5c, 0x70, 0x9e, 0xe5 - }; - unsigned char result[33]; - rustsecp256k1zkp_v0_8_0_generator parse; - - CHECK(rustsecp256k1zkp_v0_8_0_generator_parse(ctx, &parse, two_g)); - CHECK(rustsecp256k1zkp_v0_8_0_generator_serialize(ctx, result, &parse)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(two_g, result, 33) == 0); - - result[0] = 0x0a; - CHECK(rustsecp256k1zkp_v0_8_0_generator_parse(ctx, &parse, result)); - result[0] = 0x08; - CHECK(!rustsecp256k1zkp_v0_8_0_generator_parse(ctx, &parse, result)); -} - -static void test_pedersen_api(void) { - rustsecp256k1zkp_v0_8_0_context *none = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); - rustsecp256k1zkp_v0_8_0_context *sign = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN); - rustsecp256k1zkp_v0_8_0_context *vrfy = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *sttc = rustsecp256k1zkp_v0_8_0_context_clone(rustsecp256k1zkp_v0_8_0_context_no_precomp); - rustsecp256k1zkp_v0_8_0_pedersen_commitment commit; - const rustsecp256k1zkp_v0_8_0_pedersen_commitment *commit_ptr = &commit; - unsigned char blind[32]; - unsigned char blind_out[32]; - const unsigned char *blind_ptr = blind; - unsigned char *blind_out_ptr = blind_out; - uint64_t val = rustsecp256k1zkp_v0_8_0_testrand32(); - int32_t ecount = 0; - - rustsecp256k1zkp_v0_8_0_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); - - rustsecp256k1zkp_v0_8_0_testrand256(blind); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(none, &commit, blind, val, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(vrfy, &commit, blind, val, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(sign, &commit, blind, val, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(sttc, &commit, blind, val, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(ecount == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(sign, NULL, blind, val, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(sign, &commit, NULL, val, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(sign, &commit, blind, val, NULL) == 0); - CHECK(ecount == 4); - - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_blind_sum(none, blind_out, &blind_ptr, 1, 1) != 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_blind_sum(none, NULL, &blind_ptr, 1, 1) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_blind_sum(none, blind_out, NULL, 1, 1) == 0); - CHECK(ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 1) == 0); - CHECK(ecount == 7); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 0) != 0); - CHECK(ecount == 7); - - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(sign, &commit, blind, val, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_verify_tally(none, &commit_ptr, 1, &commit_ptr, 1) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_verify_tally(none, NULL, 0, &commit_ptr, 1) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 0) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_verify_tally(none, NULL, 0, NULL, 0) != 0); - CHECK(ecount == 7); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_verify_tally(none, NULL, 1, &commit_ptr, 1) == 0); - CHECK(ecount == 8); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 1) == 0); - CHECK(ecount == 9); - - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 0) != 0); - CHECK(ecount == 9); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 1) == 0); - CHECK(ecount == 10); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 0, 0) == 0); - CHECK(ecount == 11); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_blind_generator_blind_sum(none, NULL, &blind_ptr, &blind_out_ptr, 1, 0) == 0); - CHECK(ecount == 12); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_blind_generator_blind_sum(none, &val, NULL, &blind_out_ptr, 1, 0) == 0); - CHECK(ecount == 13); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, NULL, 1, 0) == 0); - CHECK(ecount == 14); - - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(vrfy); - rustsecp256k1zkp_v0_8_0_context_destroy(sttc); -} - -static void test_pedersen(void) { - rustsecp256k1zkp_v0_8_0_pedersen_commitment commits[19]; - const rustsecp256k1zkp_v0_8_0_pedersen_commitment *cptr[19]; - unsigned char blinds[32*19]; - const unsigned char *bptr[19]; - rustsecp256k1zkp_v0_8_0_scalar s; - uint64_t values[19]; - int64_t totalv; - int i; - int inputs; - int outputs; - int total; - inputs = (rustsecp256k1zkp_v0_8_0_testrand32() & 7) + 1; - outputs = (rustsecp256k1zkp_v0_8_0_testrand32() & 7) + 2; - total = inputs + outputs; - for (i = 0; i < 19; i++) { - cptr[i] = &commits[i]; - bptr[i] = &blinds[i * 32]; - } - totalv = 0; - for (i = 0; i < inputs; i++) { - values[i] = rustsecp256k1zkp_v0_8_0_testrandi64(0, INT64_MAX - totalv); - totalv += values[i]; - } - for (i = 0; i < outputs - 1; i++) { - values[i + inputs] = rustsecp256k1zkp_v0_8_0_testrandi64(0, totalv); - totalv -= values[i + inputs]; - } - values[total - 1] = totalv; - - for (i = 0; i < total - 1; i++) { - random_scalar_order(&s); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&blinds[i * 32], &s); - } - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_blind_sum(ctx, &blinds[(total - 1) * 32], bptr, total - 1, inputs)); - for (i = 0; i < total; i++) { - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], rustsecp256k1zkp_v0_8_0_generator_h)); - } - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs)); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_verify_tally(ctx, &cptr[inputs], outputs, cptr, inputs)); - if (inputs > 0 && values[0] > 0) { - CHECK(!rustsecp256k1zkp_v0_8_0_pedersen_verify_tally(ctx, cptr, inputs - 1, &cptr[inputs], outputs)); - } - random_scalar_order(&s); - for (i = 0; i < 4; i++) { - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&blinds[i * 32], &s); - } - values[0] = INT64_MAX; - values[1] = 0; - values[2] = 1; - for (i = 0; i < 3; i++) { - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], rustsecp256k1zkp_v0_8_0_generator_h)); - } - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1)); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1)); -} - -void test_pedersen_commitment_fixed_vector(void) { - const unsigned char two_g[33] = { - 0x09, - 0xc6, 0x04, 0x7f, 0x94, 0x41, 0xed, 0x7d, 0x6d, 0x30, 0x45, 0x40, 0x6e, 0x95, 0xc0, 0x7c, 0xd8, - 0x5c, 0x77, 0x8e, 0x4b, 0x8c, 0xef, 0x3c, 0xa7, 0xab, 0xac, 0x09, 0xb9, 0x5c, 0x70, 0x9e, 0xe5 - }; - unsigned char result[33]; - rustsecp256k1zkp_v0_8_0_pedersen_commitment parse; - - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commitment_parse(ctx, &parse, two_g)); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commitment_serialize(ctx, result, &parse)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(two_g, result, 33) == 0); - - result[0] = 0x08; - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commitment_parse(ctx, &parse, result)); - result[0] = 0x0c; - CHECK(!rustsecp256k1zkp_v0_8_0_pedersen_commitment_parse(ctx, &parse, result)); -} - - -void run_generator_tests(void) { - int i; - - test_shallue_van_de_woestijne(); - test_generator_fixed_vector(); - test_generator_api(); - test_generator_generate(); - test_pedersen_api(); - test_pedersen_commitment_fixed_vector(); - for (i = 0; i < count / 2 + 1; i++) { - test_pedersen(); - } -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/adaptor_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/adaptor_impl.h deleted file mode 100644 index 93e70531..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/adaptor_impl.h +++ /dev/null @@ -1,101 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2021 Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_MUSIG_ADAPTOR_IMPL_H -#define SECP256K1_MODULE_MUSIG_ADAPTOR_IMPL_H - -#include - -#include "../../../include/secp256k1.h" -#include "../../../include/secp256k1_musig.h" - -#include "session.h" -#include "../../scalar.h" - -int rustsecp256k1zkp_v0_8_0_musig_nonce_parity(const rustsecp256k1zkp_v0_8_0_context* ctx, int *nonce_parity, const rustsecp256k1zkp_v0_8_0_musig_session *session) { - rustsecp256k1zkp_v0_8_0_musig_session_internal session_i; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(nonce_parity != NULL); - ARG_CHECK(session != NULL); - - if (!rustsecp256k1zkp_v0_8_0_musig_session_load(ctx, &session_i, session)) { - return 0; - } - *nonce_parity = session_i.fin_nonce_parity; - return 1; -} - -int rustsecp256k1zkp_v0_8_0_musig_adapt(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *sig64, const unsigned char *pre_sig64, const unsigned char *sec_adaptor32, int nonce_parity) { - rustsecp256k1zkp_v0_8_0_scalar s; - rustsecp256k1zkp_v0_8_0_scalar t; - int overflow; - int ret = 1; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(pre_sig64 != NULL); - ARG_CHECK(sec_adaptor32 != NULL); - ARG_CHECK(nonce_parity == 0 || nonce_parity == 1); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&s, &pre_sig64[32], &overflow); - if (overflow) { - return 0; - } - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&t, sec_adaptor32, &overflow); - ret &= !overflow; - - /* Determine if the secret adaptor should be negated. - * - * The musig_session stores the X-coordinate and the parity of the "final nonce" - * (r + t)*G, where r*G is the aggregate public nonce and t is the secret adaptor. - * - * Since a BIP340 signature requires an x-only public nonce, in the case where - * (r + t)*G has odd Y-coordinate (i.e. nonce_parity == 1), the x-only public nonce - * corresponding to the signature is actually (-r - t)*G. Thus adapting a - * pre-signature requires negating t in this case. - */ - if (nonce_parity) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&t, &t); - } - - rustsecp256k1zkp_v0_8_0_scalar_add(&s, &s, &t); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&sig64[32], &s); - memmove(sig64, pre_sig64, 32); - rustsecp256k1zkp_v0_8_0_scalar_clear(&t); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_musig_extract_adaptor(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *sec_adaptor32, const unsigned char *sig64, const unsigned char *pre_sig64, int nonce_parity) { - rustsecp256k1zkp_v0_8_0_scalar t; - rustsecp256k1zkp_v0_8_0_scalar s; - int overflow; - int ret = 1; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sec_adaptor32 != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(pre_sig64 != NULL); - ARG_CHECK(nonce_parity == 0 || nonce_parity == 1); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&t, &sig64[32], &overflow); - ret &= !overflow; - rustsecp256k1zkp_v0_8_0_scalar_negate(&t, &t); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&s, &pre_sig64[32], &overflow); - if (overflow) { - return 0; - } - rustsecp256k1zkp_v0_8_0_scalar_add(&t, &t, &s); - - if (!nonce_parity) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&t, &t); - } - rustsecp256k1zkp_v0_8_0_scalar_get_b32(sec_adaptor32, &t); - rustsecp256k1zkp_v0_8_0_scalar_clear(&t); - return ret; -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/keyagg.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/keyagg.h deleted file mode 100644 index 79d24eb0..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/keyagg.h +++ /dev/null @@ -1,49 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2021 Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_H -#define SECP256K1_MODULE_MUSIG_KEYAGG_H - -#include "../../../include/secp256k1.h" -#include "../../../include/secp256k1_musig.h" - -#include "../../field.h" -#include "../../group.h" -#include "../../scalar.h" - -typedef struct { - rustsecp256k1zkp_v0_8_0_ge pk; - /* If there is no "second" public key, second_pk is set to the point at - * infinity */ - rustsecp256k1zkp_v0_8_0_ge second_pk; - unsigned char pk_hash[32]; - /* tweak is identical to value tacc[v] in the specification. */ - rustsecp256k1zkp_v0_8_0_scalar tweak; - /* parity_acc corresponds to gacc[v] in the spec. If gacc[v] is -1, - * parity_acc is 1. Otherwise, parity_acc is 0. */ - int parity_acc; -} rustsecp256k1zkp_v0_8_0_keyagg_cache_internal; - -/* Save and load points to and from byte arrays, similar to - * rustsecp256k1zkp_v0_8_0_pubkey_{save,load}. */ -static void rustsecp256k1zkp_v0_8_0_point_save(unsigned char *data, rustsecp256k1zkp_v0_8_0_ge *ge); - -/* In contrast to pubkey_load, point_load does not attempt to check that data - * has been initialized, since it is assumed that this check already happened - * (e.g. by comparing magic bytes) */ -static void rustsecp256k1zkp_v0_8_0_point_load(rustsecp256k1zkp_v0_8_0_ge *ge, const unsigned char *data); - -/* point_save_ext and point_load_ext are identical to point_save and point_load - * except that they allow saving and loading the point at infinity */ -static void rustsecp256k1zkp_v0_8_0_point_save_ext(unsigned char *data, rustsecp256k1zkp_v0_8_0_ge *ge); - -static void rustsecp256k1zkp_v0_8_0_point_load_ext(rustsecp256k1zkp_v0_8_0_ge *ge, const unsigned char *data); - -static int rustsecp256k1zkp_v0_8_0_keyagg_cache_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_keyagg_cache_internal *cache_i, const rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *cache); - -static void rustsecp256k1zkp_v0_8_0_musig_keyaggcoef(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_keyagg_cache_internal *cache_i, rustsecp256k1zkp_v0_8_0_ge *pk); - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/keyagg_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/keyagg_impl.h deleted file mode 100644 index 5ec13263..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/keyagg_impl.h +++ /dev/null @@ -1,331 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2021 Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H -#define SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H - -#include - -#include "keyagg.h" -#include "../../eckey.h" -#include "../../ecmult.h" -#include "../../field.h" -#include "../../group.h" -#include "../../hash.h" -#include "../../util.h" - -static void rustsecp256k1zkp_v0_8_0_point_save(unsigned char *data, rustsecp256k1zkp_v0_8_0_ge *ge) { - if (sizeof(rustsecp256k1zkp_v0_8_0_ge_storage) == 64) { - rustsecp256k1zkp_v0_8_0_ge_storage s; - rustsecp256k1zkp_v0_8_0_ge_to_storage(&s, ge); - memcpy(data, &s, sizeof(s)); - } else { - VERIFY_CHECK(!rustsecp256k1zkp_v0_8_0_ge_is_infinity(ge)); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge->x); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge->y); - rustsecp256k1zkp_v0_8_0_fe_get_b32(data, &ge->x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(data + 32, &ge->y); - } -} - -static void rustsecp256k1zkp_v0_8_0_point_load(rustsecp256k1zkp_v0_8_0_ge *ge, const unsigned char *data) { - if (sizeof(rustsecp256k1zkp_v0_8_0_ge_storage) == 64) { - /* When the rustsecp256k1zkp_v0_8_0_ge_storage type is exactly 64 byte, use its - * representation as conversion is very fast. */ - rustsecp256k1zkp_v0_8_0_ge_storage s; - memcpy(&s, data, sizeof(s)); - rustsecp256k1zkp_v0_8_0_ge_from_storage(ge, &s); - } else { - /* Otherwise, fall back to 32-byte big endian for X and Y. */ - rustsecp256k1zkp_v0_8_0_fe x, y; - rustsecp256k1zkp_v0_8_0_fe_set_b32(&x, data); - rustsecp256k1zkp_v0_8_0_fe_set_b32(&y, data + 32); - rustsecp256k1zkp_v0_8_0_ge_set_xy(ge, &x, &y); - } -} - -static void rustsecp256k1zkp_v0_8_0_point_save_ext(unsigned char *data, rustsecp256k1zkp_v0_8_0_ge *ge) { - if (rustsecp256k1zkp_v0_8_0_ge_is_infinity(ge)) { - memset(data, 0, 64); - } else { - rustsecp256k1zkp_v0_8_0_point_save(data, ge); - } -} - -static void rustsecp256k1zkp_v0_8_0_point_load_ext(rustsecp256k1zkp_v0_8_0_ge *ge, const unsigned char *data) { - unsigned char zeros[64] = { 0 }; - if (rustsecp256k1zkp_v0_8_0_memcmp_var(data, zeros, sizeof(zeros)) == 0) { - rustsecp256k1zkp_v0_8_0_ge_set_infinity(ge); - } else { - rustsecp256k1zkp_v0_8_0_point_load(ge, data); - } -} - -static const unsigned char rustsecp256k1zkp_v0_8_0_musig_keyagg_cache_magic[4] = { 0xf4, 0xad, 0xbb, 0xdf }; - -/* A keyagg cache consists of - * - 4 byte magic set during initialization to allow detecting an uninitialized - * object. - * - 64 byte aggregate (and potentially tweaked) public key - * - 64 byte "second" public key (set to the point at infinity if not present) - * - 32 byte hash of all public keys - * - 1 byte the parity of the internal key (if tweaked, otherwise 0) - * - 32 byte tweak - */ -/* Requires that cache_i->pk is not infinity and cache_i->second_pk_x to be normalized. */ -static void rustsecp256k1zkp_v0_8_0_keyagg_cache_save(rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *cache, rustsecp256k1zkp_v0_8_0_keyagg_cache_internal *cache_i) { - unsigned char *ptr = cache->data; - memcpy(ptr, rustsecp256k1zkp_v0_8_0_musig_keyagg_cache_magic, 4); - ptr += 4; - rustsecp256k1zkp_v0_8_0_point_save(ptr, &cache_i->pk); - ptr += 64; - rustsecp256k1zkp_v0_8_0_point_save_ext(ptr, &cache_i->second_pk); - ptr += 64; - memcpy(ptr, cache_i->pk_hash, 32); - ptr += 32; - *ptr = cache_i->parity_acc; - ptr += 1; - rustsecp256k1zkp_v0_8_0_scalar_get_b32(ptr, &cache_i->tweak); -} - -static int rustsecp256k1zkp_v0_8_0_keyagg_cache_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_keyagg_cache_internal *cache_i, const rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *cache) { - const unsigned char *ptr = cache->data; - ARG_CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(ptr, rustsecp256k1zkp_v0_8_0_musig_keyagg_cache_magic, 4) == 0); - ptr += 4; - rustsecp256k1zkp_v0_8_0_point_load(&cache_i->pk, ptr); - ptr += 64; - rustsecp256k1zkp_v0_8_0_point_load_ext(&cache_i->second_pk, ptr); - ptr += 64; - memcpy(cache_i->pk_hash, ptr, 32); - ptr += 32; - cache_i->parity_acc = *ptr & 1; - ptr += 1; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&cache_i->tweak, ptr, NULL); - return 1; -} - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("KeyAgg list")||SHA256("KeyAgg list"). */ -static void rustsecp256k1zkp_v0_8_0_musig_keyagglist_sha256(rustsecp256k1zkp_v0_8_0_sha256 *sha) { - rustsecp256k1zkp_v0_8_0_sha256_initialize(sha); - - sha->s[0] = 0xb399d5e0ul; - sha->s[1] = 0xc8fff302ul; - sha->s[2] = 0x6badac71ul; - sha->s[3] = 0x07c5b7f1ul; - sha->s[4] = 0x9701e2eful; - sha->s[5] = 0x2a72ecf8ul; - sha->s[6] = 0x201a4c7bul; - sha->s[7] = 0xab148a38ul; - sha->bytes = 64; -} - -/* Computes pk_hash = tagged_hash(pk[0], ..., pk[np-1]) */ -static int rustsecp256k1zkp_v0_8_0_musig_compute_pk_hash(const rustsecp256k1zkp_v0_8_0_context *ctx, unsigned char *pk_hash, const rustsecp256k1zkp_v0_8_0_pubkey * const* pk, size_t np) { - rustsecp256k1zkp_v0_8_0_sha256 sha; - size_t i; - - rustsecp256k1zkp_v0_8_0_musig_keyagglist_sha256(&sha); - for (i = 0; i < np; i++) { - unsigned char ser[33]; - size_t ser_len = sizeof(ser); - if (!rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, ser, &ser_len, pk[i], SECP256K1_EC_COMPRESSED)) { - return 0; - } - VERIFY_CHECK(ser_len == sizeof(ser)); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, ser, sizeof(ser)); - } - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, pk_hash); - return 1; -} - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("KeyAgg coefficient")||SHA256("KeyAgg coefficient"). */ -static void rustsecp256k1zkp_v0_8_0_musig_keyaggcoef_sha256(rustsecp256k1zkp_v0_8_0_sha256 *sha) { - rustsecp256k1zkp_v0_8_0_sha256_initialize(sha); - - sha->s[0] = 0x6ef02c5aul; - sha->s[1] = 0x06a480deul; - sha->s[2] = 0x1f298665ul; - sha->s[3] = 0x1d1134f2ul; - sha->s[4] = 0x56a0b063ul; - sha->s[5] = 0x52da4147ul; - sha->s[6] = 0xf280d9d4ul; - sha->s[7] = 0x4484be15ul; - sha->bytes = 64; -} - -/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and - * otherwise tagged_hash(pk_hash, x) where pk_hash is the hash of public keys. - * second_pk is the point at infinity in case there is no second_pk. Assumes - * that pk is not the point at infinity and that the coordinates of pk and - * second_pk are normalized. */ -static void rustsecp256k1zkp_v0_8_0_musig_keyaggcoef_internal(rustsecp256k1zkp_v0_8_0_scalar *r, const unsigned char *pk_hash, rustsecp256k1zkp_v0_8_0_ge *pk, const rustsecp256k1zkp_v0_8_0_ge *second_pk) { - rustsecp256k1zkp_v0_8_0_sha256 sha; - - if (!rustsecp256k1zkp_v0_8_0_ge_is_infinity(second_pk) - && rustsecp256k1zkp_v0_8_0_fe_equal(&pk->x, &second_pk->x) - && rustsecp256k1zkp_v0_8_0_fe_is_odd(&pk->y) == rustsecp256k1zkp_v0_8_0_fe_is_odd(&second_pk->y)) { - rustsecp256k1zkp_v0_8_0_scalar_set_int(r, 1); - } else { - unsigned char buf[33]; - size_t buflen = sizeof(buf); - int ret; - rustsecp256k1zkp_v0_8_0_musig_keyaggcoef_sha256(&sha); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, pk_hash, 32); - ret = rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(pk, buf, &buflen, 1); - /* Serialization does not fail since the pk is not the point at infinity - * (according to this function's precondition). */ - VERIFY_CHECK(ret && buflen == sizeof(buf)); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, buf, sizeof(buf)); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, buf); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(r, buf, NULL); - } -} - -/* Assumes both field elements x and second_pk_x are normalized. */ -static void rustsecp256k1zkp_v0_8_0_musig_keyaggcoef(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_keyagg_cache_internal *cache_i, rustsecp256k1zkp_v0_8_0_ge *pk) { - rustsecp256k1zkp_v0_8_0_musig_keyaggcoef_internal(r, cache_i->pk_hash, pk, &cache_i->second_pk); -} - -typedef struct { - const rustsecp256k1zkp_v0_8_0_context *ctx; - /* pk_hash is the hash of the public keys */ - unsigned char pk_hash[32]; - const rustsecp256k1zkp_v0_8_0_pubkey * const* pks; - rustsecp256k1zkp_v0_8_0_ge second_pk; -} rustsecp256k1zkp_v0_8_0_musig_pubkey_agg_ecmult_data; - -/* Callback for batch EC multiplication to compute keyaggcoef_0*P0 + keyaggcoef_1*P1 + ... */ -static int rustsecp256k1zkp_v0_8_0_musig_pubkey_agg_callback(rustsecp256k1zkp_v0_8_0_scalar *sc, rustsecp256k1zkp_v0_8_0_ge *pt, size_t idx, void *data) { - rustsecp256k1zkp_v0_8_0_musig_pubkey_agg_ecmult_data *ctx = (rustsecp256k1zkp_v0_8_0_musig_pubkey_agg_ecmult_data *) data; - int ret; - ret = rustsecp256k1zkp_v0_8_0_pubkey_load(ctx->ctx, pt, ctx->pks[idx]); - /* pubkey_load can't fail because the same pks have already been loaded in - * `musig_compute_pk_hash` (and we test this). */ - VERIFY_CHECK(ret); - rustsecp256k1zkp_v0_8_0_musig_keyaggcoef_internal(sc, ctx->pk_hash, pt, &ctx->second_pk); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_scratch_space *scratch, rustsecp256k1zkp_v0_8_0_xonly_pubkey *agg_pk, rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, const rustsecp256k1zkp_v0_8_0_pubkey * const* pubkeys, size_t n_pubkeys) { - rustsecp256k1zkp_v0_8_0_musig_pubkey_agg_ecmult_data ecmult_data; - rustsecp256k1zkp_v0_8_0_gej pkj; - rustsecp256k1zkp_v0_8_0_ge pkp; - size_t i; - (void) scratch; - - VERIFY_CHECK(ctx != NULL); - if (agg_pk != NULL) { - memset(agg_pk, 0, sizeof(*agg_pk)); - } - ARG_CHECK(pubkeys != NULL); - ARG_CHECK(n_pubkeys > 0); - - ecmult_data.ctx = ctx; - ecmult_data.pks = pubkeys; - - rustsecp256k1zkp_v0_8_0_ge_set_infinity(&ecmult_data.second_pk); - for (i = 1; i < n_pubkeys; i++) { - if (rustsecp256k1zkp_v0_8_0_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) { - rustsecp256k1zkp_v0_8_0_ge pk; - if (!rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &pk, pubkeys[i])) { - return 0; - } - ecmult_data.second_pk = pk; - break; - } - } - - if (!rustsecp256k1zkp_v0_8_0_musig_compute_pk_hash(ctx, ecmult_data.pk_hash, pubkeys, n_pubkeys)) { - return 0; - } - /* TODO: actually use optimized ecmult_multi algorithms by providing a - * scratch space */ - if (!rustsecp256k1zkp_v0_8_0_ecmult_multi_var(&ctx->error_callback, NULL, &pkj, NULL, rustsecp256k1zkp_v0_8_0_musig_pubkey_agg_callback, (void *) &ecmult_data, n_pubkeys)) { - /* In order to reach this line with the current implementation of - * ecmult_multi_var one would need to provide a callback that can - * fail. */ - return 0; - } - rustsecp256k1zkp_v0_8_0_ge_set_gej(&pkp, &pkj); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&pkp.y); - /* The resulting public key is infinity with negligible probability */ - VERIFY_CHECK(!rustsecp256k1zkp_v0_8_0_ge_is_infinity(&pkp)); - if (keyagg_cache != NULL) { - rustsecp256k1zkp_v0_8_0_keyagg_cache_internal cache_i = { 0 }; - cache_i.pk = pkp; - cache_i.second_pk = ecmult_data.second_pk; - memcpy(cache_i.pk_hash, ecmult_data.pk_hash, sizeof(cache_i.pk_hash)); - rustsecp256k1zkp_v0_8_0_keyagg_cache_save(keyagg_cache, &cache_i); - } - - rustsecp256k1zkp_v0_8_0_extrakeys_ge_even_y(&pkp); - if (agg_pk != NULL) { - rustsecp256k1zkp_v0_8_0_xonly_pubkey_save(agg_pk, &pkp); - } - return 1; -} - -int rustsecp256k1zkp_v0_8_0_musig_pubkey_get(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *agg_pk, rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache) { - rustsecp256k1zkp_v0_8_0_keyagg_cache_internal cache_i; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(agg_pk != NULL); - memset(agg_pk, 0, sizeof(*agg_pk)); - ARG_CHECK(keyagg_cache != NULL); - - if(!rustsecp256k1zkp_v0_8_0_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_pubkey_save(agg_pk, &cache_i.pk); - return 1; -} - -static int rustsecp256k1zkp_v0_8_0_musig_pubkey_tweak_add_internal(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *output_pubkey, rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32, int xonly) { - rustsecp256k1zkp_v0_8_0_keyagg_cache_internal cache_i; - int overflow = 0; - rustsecp256k1zkp_v0_8_0_scalar tweak; - - VERIFY_CHECK(ctx != NULL); - if (output_pubkey != NULL) { - memset(output_pubkey, 0, sizeof(*output_pubkey)); - } - ARG_CHECK(keyagg_cache != NULL); - ARG_CHECK(tweak32 != NULL); - - if (!rustsecp256k1zkp_v0_8_0_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&tweak, tweak32, &overflow); - if (overflow) { - return 0; - } - if (xonly && rustsecp256k1zkp_v0_8_0_extrakeys_ge_even_y(&cache_i.pk)) { - cache_i.parity_acc ^= 1; - rustsecp256k1zkp_v0_8_0_scalar_negate(&cache_i.tweak, &cache_i.tweak); - } - rustsecp256k1zkp_v0_8_0_scalar_add(&cache_i.tweak, &cache_i.tweak, &tweak); - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_tweak_add(&cache_i.pk, &tweak)) { - return 0; - } - /* eckey_pubkey_tweak_add fails if cache_i.pk is infinity */ - VERIFY_CHECK(!rustsecp256k1zkp_v0_8_0_ge_is_infinity(&cache_i.pk)); - rustsecp256k1zkp_v0_8_0_keyagg_cache_save(keyagg_cache, &cache_i); - if (output_pubkey != NULL) { - rustsecp256k1zkp_v0_8_0_pubkey_save(output_pubkey, &cache_i.pk); - } - return 1; -} - -int rustsecp256k1zkp_v0_8_0_musig_pubkey_ec_tweak_add(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *output_pubkey, rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) { - return rustsecp256k1zkp_v0_8_0_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 0); -} - -int rustsecp256k1zkp_v0_8_0_musig_pubkey_xonly_tweak_add(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *output_pubkey, rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) { - return rustsecp256k1zkp_v0_8_0_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 1); -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/musig.md b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/musig.md deleted file mode 100644 index c44a7911..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/musig.md +++ /dev/null @@ -1,63 +0,0 @@ -Notes on the musig module API -=========================== - -The following sections contain additional notes on the API of the musig module (`include/rustsecp256k1zkp_v0_8_0_musig.h`). -A usage example can be found in `examples/musig.c`. - -# API misuse - -The musig API is designed to be as misuse resistant as possible. -However, the MuSig protocol has some additional failure modes (mainly due to interactivity) that do not appear in single-signing. -While the results can be catastrophic (e.g. leaking of the secret key), it is unfortunately not possible for the musig implementation to rule out all such failure modes. - -Therefore, users of the musig module must take great care to make sure of the following: - -1. A unique nonce per signing session is generated in `rustsecp256k1zkp_v0_8_0_musig_nonce_gen`. - See the corresponding comment in `include/rustsecp256k1zkp_v0_8_0_musig.h` for how to ensure that. -2. The `rustsecp256k1zkp_v0_8_0_musig_secnonce` structure is never copied or serialized. - See also the comment on `rustsecp256k1zkp_v0_8_0_musig_secnonce` in `include/rustsecp256k1zkp_v0_8_0_musig.h`. -3. Opaque data structures are never written to or read from directly. - Instead, only the provided accessor functions are used. -4. If adaptor signatures are used, all partial signatures are verified. - -# Key Aggregation and (Taproot) Tweaking - -Given a set of public keys, the aggregate public key is computed with `rustsecp256k1zkp_v0_8_0_musig_pubkey_agg`. -A (Taproot) tweak can be added to the resulting public key with `rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add` and a plain tweak can be added with `rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add`. - -# Signing - -This is covered by `examples/musig.c`. -Essentially, the protocol proceeds in the following steps: - -1. Generate a keypair with `rustsecp256k1zkp_v0_8_0_keypair_create` and obtain the public key with `rustsecp256k1zkp_v0_8_0_keypair_pub`. -2. Call `rustsecp256k1zkp_v0_8_0_musig_pubkey_agg` with the pubkeys of all participants. -3. Optionally add a (Taproot) tweak with `rustsecp256k1zkp_v0_8_0_musig_pubkey_xonly_tweak_add` and a plain tweak with `rustsecp256k1zkp_v0_8_0_musig_pubkey_ec_tweak_add`. -4. Generate a pair of secret and public nonce with `rustsecp256k1zkp_v0_8_0_musig_nonce_gen` and send the public nonce to the other signers. -5. Someone (not necessarily the signer) aggregates the public nonce with `rustsecp256k1zkp_v0_8_0_musig_nonce_agg` and sends it to the signers. -6. Process the aggregate nonce with `rustsecp256k1zkp_v0_8_0_musig_nonce_process`. -7. Create a partial signature with `rustsecp256k1zkp_v0_8_0_musig_partial_sign`. -8. Verify the partial signatures (optional in some scenarios) with `rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify`. -9. Someone (not necessarily the signer) obtains all partial signatures and aggregates them into the final Schnorr signature using `rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg`. - -The aggregate signature can be verified with `rustsecp256k1zkp_v0_8_0_schnorrsig_verify`. - -Note that steps 1 to 5 can happen before the message to be signed is known to the signers. -Therefore, the communication round to exchange nonces can be viewed as a pre-processing step that is run whenever convenient to the signers. -This disables some of the defense-in-depth measures that may protect against API misuse in some cases. -Similarly, the API supports an alternative protocol flow where generating the aggregate key (steps 1 to 3) is allowed to happen after exchanging nonces (steps 4 to 5). - -# Verification - -A participant who wants to verify the partial signatures, but does not sign itself may do so using the above instructions except that the verifier skips steps 1, 4 and 7. - -# Atomic Swaps - -The signing API supports the production of "adaptor signatures", modified partial signatures -which are offset by an auxiliary secret known to one party. That is, -1. One party generates a (secret) adaptor `t` with corresponding (public) adaptor `T = t*G`. -2. When calling `rustsecp256k1zkp_v0_8_0_musig_nonce_process`, the public adaptor `T` is provided as the `adaptor` argument. -3. The party who is going to extract the secret adaptor `t` later must verify all partial signatures. -4. Due to step 2, the signature output of `rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg` is a pre-signature and not a valid Schnorr signature. All parties involved extract this session's `nonce_parity` with `rustsecp256k1zkp_v0_8_0_musig_nonce_parity`. -5. The party who knows `t` must "adapt" the pre-signature with `t` (and the `nonce_parity` using `rustsecp256k1zkp_v0_8_0_musig_adapt` to complete the signature. -6. Any party who sees both the final signature and the pre-signature (and has the `nonce_parity`) can extract `t` with `rustsecp256k1zkp_v0_8_0_musig_extract_adaptor`. diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/session_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/session_impl.h deleted file mode 100644 index b8b79ac4..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/session_impl.h +++ /dev/null @@ -1,735 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2021 Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_MUSIG_SESSION_IMPL_H -#define SECP256K1_MODULE_MUSIG_SESSION_IMPL_H - -#include - -#include "../../../include/secp256k1.h" -#include "../../../include/secp256k1_extrakeys.h" -#include "../../../include/secp256k1_musig.h" - -#include "keyagg.h" -#include "session.h" -#include "../../eckey.h" -#include "../../hash.h" -#include "../../scalar.h" -#include "../../util.h" - -static const unsigned char rustsecp256k1zkp_v0_8_0_musig_secnonce_magic[4] = { 0x22, 0x0e, 0xdc, 0xf1 }; - -static void rustsecp256k1zkp_v0_8_0_musig_secnonce_save(rustsecp256k1zkp_v0_8_0_musig_secnonce *secnonce, const rustsecp256k1zkp_v0_8_0_scalar *k, rustsecp256k1zkp_v0_8_0_ge *pk) { - memcpy(&secnonce->data[0], rustsecp256k1zkp_v0_8_0_musig_secnonce_magic, 4); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&secnonce->data[4], &k[0]); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&secnonce->data[36], &k[1]); - rustsecp256k1zkp_v0_8_0_point_save(&secnonce->data[68], pk); -} - -static int rustsecp256k1zkp_v0_8_0_musig_secnonce_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_scalar *k, rustsecp256k1zkp_v0_8_0_ge *pk, rustsecp256k1zkp_v0_8_0_musig_secnonce *secnonce) { - int is_zero; - ARG_CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&secnonce->data[0], rustsecp256k1zkp_v0_8_0_musig_secnonce_magic, 4) == 0); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&k[0], &secnonce->data[4], NULL); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&k[1], &secnonce->data[36], NULL); - rustsecp256k1zkp_v0_8_0_point_load(pk, &secnonce->data[68]); - /* We make very sure that the nonce isn't invalidated by checking the values - * in addition to the magic. */ - is_zero = rustsecp256k1zkp_v0_8_0_scalar_is_zero(&k[0]) & rustsecp256k1zkp_v0_8_0_scalar_is_zero(&k[1]); - rustsecp256k1zkp_v0_8_0_declassify(ctx, &is_zero, sizeof(is_zero)); - ARG_CHECK(!is_zero); - return 1; -} - -/* If flag is true, invalidate the secnonce; otherwise leave it. Constant-time. */ -static void rustsecp256k1zkp_v0_8_0_musig_secnonce_invalidate(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_musig_secnonce *secnonce, int flag) { - rustsecp256k1zkp_v0_8_0_memczero(secnonce->data, sizeof(secnonce->data), flag); - /* The flag argument is usually classified. So, the line above makes the - * magic and public key classified. However, we need both to be - * declassified. Note that we don't declassify the entire object, because if - * flag is 0, then k[0] and k[1] have not been zeroed. */ - rustsecp256k1zkp_v0_8_0_declassify(ctx, secnonce->data, sizeof(rustsecp256k1zkp_v0_8_0_musig_secnonce_magic)); - rustsecp256k1zkp_v0_8_0_declassify(ctx, &secnonce->data[68], 64); -} - -static const unsigned char rustsecp256k1zkp_v0_8_0_musig_pubnonce_magic[4] = { 0xf5, 0x7a, 0x3d, 0xa0 }; - -/* Saves two group elements into a pubnonce. Requires that none of the provided - * group elements is infinity. */ -static void rustsecp256k1zkp_v0_8_0_musig_pubnonce_save(rustsecp256k1zkp_v0_8_0_musig_pubnonce* nonce, rustsecp256k1zkp_v0_8_0_ge* ge) { - int i; - memcpy(&nonce->data[0], rustsecp256k1zkp_v0_8_0_musig_pubnonce_magic, 4); - for (i = 0; i < 2; i++) { - rustsecp256k1zkp_v0_8_0_point_save(nonce->data + 4+64*i, &ge[i]); - } -} - -/* Loads two group elements from a pubnonce. Returns 1 unless the nonce wasn't - * properly initialized */ -static int rustsecp256k1zkp_v0_8_0_musig_pubnonce_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ge* ge, const rustsecp256k1zkp_v0_8_0_musig_pubnonce* nonce) { - int i; - - ARG_CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&nonce->data[0], rustsecp256k1zkp_v0_8_0_musig_pubnonce_magic, 4) == 0); - for (i = 0; i < 2; i++) { - rustsecp256k1zkp_v0_8_0_point_load(&ge[i], nonce->data + 4 + 64*i); - } - return 1; -} - -static const unsigned char rustsecp256k1zkp_v0_8_0_musig_aggnonce_magic[4] = { 0xa8, 0xb7, 0xe4, 0x67 }; - -static void rustsecp256k1zkp_v0_8_0_musig_aggnonce_save(rustsecp256k1zkp_v0_8_0_musig_aggnonce* nonce, rustsecp256k1zkp_v0_8_0_ge* ge) { - int i; - memcpy(&nonce->data[0], rustsecp256k1zkp_v0_8_0_musig_aggnonce_magic, 4); - for (i = 0; i < 2; i++) { - rustsecp256k1zkp_v0_8_0_point_save_ext(&nonce->data[4 + 64*i], &ge[i]); - } -} - -static int rustsecp256k1zkp_v0_8_0_musig_aggnonce_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ge* ge, const rustsecp256k1zkp_v0_8_0_musig_aggnonce* nonce) { - int i; - - ARG_CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&nonce->data[0], rustsecp256k1zkp_v0_8_0_musig_aggnonce_magic, 4) == 0); - for (i = 0; i < 2; i++) { - rustsecp256k1zkp_v0_8_0_point_load_ext(&ge[i], &nonce->data[4 + 64*i]); - } - return 1; -} - -static const unsigned char rustsecp256k1zkp_v0_8_0_musig_session_cache_magic[4] = { 0x9d, 0xed, 0xe9, 0x17 }; - -/* A session consists of - * - 4 byte session cache magic - * - 1 byte the parity of the final nonce - * - 32 byte serialized x-only final nonce - * - 32 byte nonce coefficient b - * - 32 byte signature challenge hash e - * - 32 byte scalar s that is added to the partial signatures of the signers - */ -static void rustsecp256k1zkp_v0_8_0_musig_session_save(rustsecp256k1zkp_v0_8_0_musig_session *session, const rustsecp256k1zkp_v0_8_0_musig_session_internal *session_i) { - unsigned char *ptr = session->data; - - memcpy(ptr, rustsecp256k1zkp_v0_8_0_musig_session_cache_magic, 4); - ptr += 4; - *ptr = session_i->fin_nonce_parity; - ptr += 1; - memcpy(ptr, session_i->fin_nonce, 32); - ptr += 32; - rustsecp256k1zkp_v0_8_0_scalar_get_b32(ptr, &session_i->noncecoef); - ptr += 32; - rustsecp256k1zkp_v0_8_0_scalar_get_b32(ptr, &session_i->challenge); - ptr += 32; - rustsecp256k1zkp_v0_8_0_scalar_get_b32(ptr, &session_i->s_part); -} - -static int rustsecp256k1zkp_v0_8_0_musig_session_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_musig_session_internal *session_i, const rustsecp256k1zkp_v0_8_0_musig_session *session) { - const unsigned char *ptr = session->data; - - ARG_CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(ptr, rustsecp256k1zkp_v0_8_0_musig_session_cache_magic, 4) == 0); - ptr += 4; - session_i->fin_nonce_parity = *ptr; - ptr += 1; - memcpy(session_i->fin_nonce, ptr, 32); - ptr += 32; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&session_i->noncecoef, ptr, NULL); - ptr += 32; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&session_i->challenge, ptr, NULL); - ptr += 32; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&session_i->s_part, ptr, NULL); - return 1; -} - -static const unsigned char rustsecp256k1zkp_v0_8_0_musig_partial_sig_magic[4] = { 0xeb, 0xfb, 0x1a, 0x32 }; - -static void rustsecp256k1zkp_v0_8_0_musig_partial_sig_save(rustsecp256k1zkp_v0_8_0_musig_partial_sig* sig, rustsecp256k1zkp_v0_8_0_scalar *s) { - memcpy(&sig->data[0], rustsecp256k1zkp_v0_8_0_musig_partial_sig_magic, 4); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&sig->data[4], s); -} - -static int rustsecp256k1zkp_v0_8_0_musig_partial_sig_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_scalar *s, const rustsecp256k1zkp_v0_8_0_musig_partial_sig* sig) { - int overflow; - - ARG_CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&sig->data[0], rustsecp256k1zkp_v0_8_0_musig_partial_sig_magic, 4) == 0); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(s, &sig->data[4], &overflow); - /* Parsed signatures can not overflow */ - VERIFY_CHECK(!overflow); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_musig_pubnonce_serialize(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *out66, const rustsecp256k1zkp_v0_8_0_musig_pubnonce* nonce) { - rustsecp256k1zkp_v0_8_0_ge ge[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(out66 != NULL); - memset(out66, 0, 66); - ARG_CHECK(nonce != NULL); - - if (!rustsecp256k1zkp_v0_8_0_musig_pubnonce_load(ctx, ge, nonce)) { - return 0; - } - for (i = 0; i < 2; i++) { - int ret; - size_t size = 33; - ret = rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&ge[i], &out66[33*i], &size, 1); - /* serialize must succeed because the point was just loaded */ - VERIFY_CHECK(ret && size == 33); - } - return 1; -} - -int rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_musig_pubnonce* nonce, const unsigned char *in66) { - rustsecp256k1zkp_v0_8_0_ge ge[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(nonce != NULL); - ARG_CHECK(in66 != NULL); - - for (i = 0; i < 2; i++) { - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&ge[i], &in66[33*i], 33)) { - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_ge_is_in_correct_subgroup(&ge[i])) { - return 0; - } - } - rustsecp256k1zkp_v0_8_0_musig_pubnonce_save(nonce, ge); - return 1; -} - -/* Outputs 33 zero bytes if the given group element is the point at infinity and - * otherwise outputs the compressed serialization */ -static void rustsecp256k1zkp_v0_8_0_ge_serialize_ext(unsigned char *out33, rustsecp256k1zkp_v0_8_0_ge* ge) { - if (rustsecp256k1zkp_v0_8_0_ge_is_infinity(ge)) { - memset(out33, 0, 33); - } else { - int ret; - size_t size = 33; - ret = rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(ge, out33, &size, 1); - /* Serialize must succeed because the point is not at infinity */ - VERIFY_CHECK(ret && size == 33); - } -} - -/* Outputs the point at infinity if the given byte array is all zero, otherwise - * attempts to parse compressed point serialization. */ -static int rustsecp256k1zkp_v0_8_0_ge_parse_ext(rustsecp256k1zkp_v0_8_0_ge* ge, const unsigned char *in33) { - unsigned char zeros[33] = { 0 }; - - if (memcmp(in33, zeros, sizeof(zeros)) == 0) { - rustsecp256k1zkp_v0_8_0_ge_set_infinity(ge); - return 1; - } - return rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(ge, in33, 33); -} - -int rustsecp256k1zkp_v0_8_0_musig_aggnonce_serialize(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *out66, const rustsecp256k1zkp_v0_8_0_musig_aggnonce* nonce) { - rustsecp256k1zkp_v0_8_0_ge ge[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(out66 != NULL); - memset(out66, 0, 66); - ARG_CHECK(nonce != NULL); - - if (!rustsecp256k1zkp_v0_8_0_musig_aggnonce_load(ctx, ge, nonce)) { - return 0; - } - for (i = 0; i < 2; i++) { - rustsecp256k1zkp_v0_8_0_ge_serialize_ext(&out66[33*i], &ge[i]); - } - return 1; -} - -int rustsecp256k1zkp_v0_8_0_musig_aggnonce_parse(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_musig_aggnonce* nonce, const unsigned char *in66) { - rustsecp256k1zkp_v0_8_0_ge ge[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(nonce != NULL); - ARG_CHECK(in66 != NULL); - - for (i = 0; i < 2; i++) { - if (!rustsecp256k1zkp_v0_8_0_ge_parse_ext(&ge[i], &in66[33*i])) { - return 0; - } - } - rustsecp256k1zkp_v0_8_0_musig_aggnonce_save(nonce, ge); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_musig_partial_sig_serialize(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *out32, const rustsecp256k1zkp_v0_8_0_musig_partial_sig* sig) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(out32 != NULL); - ARG_CHECK(sig != NULL); - memcpy(out32, &sig->data[4], 32); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_musig_partial_sig_parse(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_musig_partial_sig* sig, const unsigned char *in32) { - rustsecp256k1zkp_v0_8_0_scalar tmp; - int overflow; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(in32 != NULL); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&tmp, in32, &overflow); - if (overflow) { - return 0; - } - rustsecp256k1zkp_v0_8_0_musig_partial_sig_save(sig, &tmp); - return 1; -} - -/* Normalizes the x-coordinate of the given group element. */ -static int rustsecp256k1zkp_v0_8_0_xonly_ge_serialize(unsigned char *output32, rustsecp256k1zkp_v0_8_0_ge *ge) { - if (rustsecp256k1zkp_v0_8_0_ge_is_infinity(ge)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge->x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(output32, &ge->x); - return 1; -} - -/* Write optional inputs into the hash */ -static void rustsecp256k1zkp_v0_8_0_nonce_function_musig_helper(rustsecp256k1zkp_v0_8_0_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) { - unsigned char zero[7] = { 0 }; - /* The spec requires length prefixes to be between 1 and 8 bytes - * (inclusive) */ - VERIFY_CHECK(prefix_size <= 8); - /* Since the length of all input data fits in a byte, we can always pad the - * length prefix with prefix_size - 1 zero bytes. */ - rustsecp256k1zkp_v0_8_0_sha256_write(sha, zero, prefix_size - 1); - if (data != NULL) { - rustsecp256k1zkp_v0_8_0_sha256_write(sha, &len, 1); - rustsecp256k1zkp_v0_8_0_sha256_write(sha, data, len); - } else { - len = 0; - rustsecp256k1zkp_v0_8_0_sha256_write(sha, &len, 1); - } -} - -static void rustsecp256k1zkp_v0_8_0_nonce_function_musig(rustsecp256k1zkp_v0_8_0_scalar *k, const unsigned char *session_id, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) { - rustsecp256k1zkp_v0_8_0_sha256 sha; - unsigned char rand[32]; - unsigned char i; - unsigned char msg_present; - - if (seckey32 != NULL) { - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, (unsigned char*)"MuSig/aux", sizeof("MuSig/aux") - 1); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, session_id, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, rand); - for (i = 0; i < 32; i++) { - rand[i] ^= seckey32[i]; - } - } else { - memcpy(rand, session_id, sizeof(rand)); - } - - /* Subtract one from `sizeof` to avoid hashing the implicit null byte */ - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, (unsigned char*)"MuSig/nonce", sizeof("MuSig/nonce") - 1); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, rand, sizeof(rand)); - rustsecp256k1zkp_v0_8_0_nonce_function_musig_helper(&sha, 1, pk33, 33); - rustsecp256k1zkp_v0_8_0_nonce_function_musig_helper(&sha, 1, agg_pk32, 32); - msg_present = msg32 != NULL; - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, &msg_present, 1); - if (msg_present) { - rustsecp256k1zkp_v0_8_0_nonce_function_musig_helper(&sha, 8, msg32, 32); - } - rustsecp256k1zkp_v0_8_0_nonce_function_musig_helper(&sha, 4, extra_input32, 32); - - for (i = 0; i < 2; i++) { - unsigned char buf[32]; - rustsecp256k1zkp_v0_8_0_sha256 sha_tmp = sha; - rustsecp256k1zkp_v0_8_0_sha256_write(&sha_tmp, &i, 1); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha_tmp, buf); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&k[i], buf, NULL); - } -} - -int rustsecp256k1zkp_v0_8_0_musig_nonce_gen(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_musig_secnonce *secnonce, rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonce, const unsigned char *session_id32, const unsigned char *seckey, const rustsecp256k1zkp_v0_8_0_pubkey *pubkey, const unsigned char *msg32, const rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { - rustsecp256k1zkp_v0_8_0_keyagg_cache_internal cache_i; - rustsecp256k1zkp_v0_8_0_scalar k[2]; - rustsecp256k1zkp_v0_8_0_ge nonce_pt[2]; - int i; - unsigned char pk_ser[33]; - size_t pk_ser_len = sizeof(pk_ser); - unsigned char aggpk_ser[32]; - unsigned char *aggpk_ser_ptr = NULL; - rustsecp256k1zkp_v0_8_0_ge pk; - int pk_serialize_success; - int ret = 1; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secnonce != NULL); - memset(secnonce, 0, sizeof(*secnonce)); - ARG_CHECK(pubnonce != NULL); - memset(pubnonce, 0, sizeof(*pubnonce)); - ARG_CHECK(session_id32 != NULL); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - if (seckey == NULL) { - /* Check in constant time that the session_id is not 0 as a - * defense-in-depth measure that may protect against a faulty RNG. */ - unsigned char acc = 0; - for (i = 0; i < 32; i++) { - acc |= session_id32[i]; - } - ret &= !!acc; - memset(&acc, 0, sizeof(acc)); - } - - /* Check that the seckey is valid to be able to sign for it later. */ - if (seckey != NULL) { - rustsecp256k1zkp_v0_8_0_scalar sk; - ret &= rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&sk, seckey); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sk); - } - - if (keyagg_cache != NULL) { - int ret_tmp; - if (!rustsecp256k1zkp_v0_8_0_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { - return 0; - } - ret_tmp = rustsecp256k1zkp_v0_8_0_xonly_ge_serialize(aggpk_ser, &cache_i.pk); - /* Serialization can not fail because the loaded point can not be infinity. */ - VERIFY_CHECK(ret_tmp); - aggpk_ser_ptr = aggpk_ser; - } - if (!rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &pk, pubkey)) { - return 0; - } - pk_serialize_success = rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&pk, pk_ser, &pk_ser_len, SECP256K1_EC_COMPRESSED); - /* A pubkey cannot be the point at infinity */ - VERIFY_CHECK(pk_serialize_success); - VERIFY_CHECK(pk_ser_len == sizeof(pk_ser)); - - rustsecp256k1zkp_v0_8_0_nonce_function_musig(k, session_id32, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32); - VERIFY_CHECK(!rustsecp256k1zkp_v0_8_0_scalar_is_zero(&k[0])); - VERIFY_CHECK(!rustsecp256k1zkp_v0_8_0_scalar_is_zero(&k[1])); - VERIFY_CHECK(!rustsecp256k1zkp_v0_8_0_scalar_eq(&k[0], &k[1])); - rustsecp256k1zkp_v0_8_0_musig_secnonce_save(secnonce, k, &pk); - rustsecp256k1zkp_v0_8_0_musig_secnonce_invalidate(ctx, secnonce, !ret); - - for (i = 0; i < 2; i++) { - rustsecp256k1zkp_v0_8_0_gej nonce_ptj; - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj, &k[i]); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&nonce_pt[i], &nonce_ptj); - rustsecp256k1zkp_v0_8_0_declassify(ctx, &nonce_pt[i], sizeof(nonce_pt)); - rustsecp256k1zkp_v0_8_0_scalar_clear(&k[i]); - } - /* nonce_pt won't be infinity because k != 0 with overwhelming probability */ - rustsecp256k1zkp_v0_8_0_musig_pubnonce_save(pubnonce, nonce_pt); - return ret; -} - -static int rustsecp256k1zkp_v0_8_0_musig_sum_nonces(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_gej *summed_nonces, const rustsecp256k1zkp_v0_8_0_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { - size_t i; - int j; - - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&summed_nonces[0]); - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&summed_nonces[1]); - - for (i = 0; i < n_pubnonces; i++) { - rustsecp256k1zkp_v0_8_0_ge nonce_pt[2]; - if (!rustsecp256k1zkp_v0_8_0_musig_pubnonce_load(ctx, nonce_pt, pubnonces[i])) { - return 0; - } - for (j = 0; j < 2; j++) { - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&summed_nonces[j], &summed_nonces[j], &nonce_pt[j], NULL); - } - } - return 1; -} - -int rustsecp256k1zkp_v0_8_0_musig_nonce_agg(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_musig_aggnonce *aggnonce, const rustsecp256k1zkp_v0_8_0_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { - rustsecp256k1zkp_v0_8_0_gej aggnonce_ptj[2]; - rustsecp256k1zkp_v0_8_0_ge aggnonce_pt[2]; - int i; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(aggnonce != NULL); - ARG_CHECK(pubnonces != NULL); - ARG_CHECK(n_pubnonces > 0); - - if (!rustsecp256k1zkp_v0_8_0_musig_sum_nonces(ctx, aggnonce_ptj, pubnonces, n_pubnonces)) { - return 0; - } - for (i = 0; i < 2; i++) { - rustsecp256k1zkp_v0_8_0_ge_set_gej(&aggnonce_pt[i], &aggnonce_ptj[i]); - } - rustsecp256k1zkp_v0_8_0_musig_aggnonce_save(aggnonce, aggnonce_pt); - return 1; -} - -/* tagged_hash(aggnonce[0], aggnonce[1], agg_pk, msg) */ -static int rustsecp256k1zkp_v0_8_0_musig_compute_noncehash(unsigned char *noncehash, rustsecp256k1zkp_v0_8_0_ge *aggnonce, const unsigned char *agg_pk32, const unsigned char *msg) { - unsigned char buf[33]; - rustsecp256k1zkp_v0_8_0_sha256 sha; - int i; - - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, (unsigned char*)"MuSig/noncecoef", sizeof("MuSig/noncecoef") - 1); - for (i = 0; i < 2; i++) { - rustsecp256k1zkp_v0_8_0_ge_serialize_ext(buf, &aggnonce[i]); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, buf, sizeof(buf)); - } - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, agg_pk32, 32); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, msg, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, noncehash); - return 1; -} - -static int rustsecp256k1zkp_v0_8_0_musig_nonce_process_internal(int *fin_nonce_parity, unsigned char *fin_nonce, rustsecp256k1zkp_v0_8_0_scalar *b, rustsecp256k1zkp_v0_8_0_gej *aggnoncej, const unsigned char *agg_pk32, const unsigned char *msg) { - unsigned char noncehash[32]; - rustsecp256k1zkp_v0_8_0_ge fin_nonce_pt; - rustsecp256k1zkp_v0_8_0_gej fin_nonce_ptj; - rustsecp256k1zkp_v0_8_0_ge aggnonce[2]; - int ret; - - rustsecp256k1zkp_v0_8_0_ge_set_gej(&aggnonce[0], &aggnoncej[0]); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&aggnonce[1], &aggnoncej[1]); - if (!rustsecp256k1zkp_v0_8_0_musig_compute_noncehash(noncehash, aggnonce, agg_pk32, msg)) { - return 0; - } - /* fin_nonce = aggnonce[0] + b*aggnonce[1] */ - rustsecp256k1zkp_v0_8_0_scalar_set_b32(b, noncehash, NULL); - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&fin_nonce_ptj); - rustsecp256k1zkp_v0_8_0_ecmult(&fin_nonce_ptj, &aggnoncej[1], b, NULL); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&fin_nonce_ptj, &fin_nonce_ptj, &aggnonce[0], NULL); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&fin_nonce_pt, &fin_nonce_ptj); - if (rustsecp256k1zkp_v0_8_0_ge_is_infinity(&fin_nonce_pt)) { - fin_nonce_pt = rustsecp256k1zkp_v0_8_0_ge_const_g; - } - ret = rustsecp256k1zkp_v0_8_0_xonly_ge_serialize(fin_nonce, &fin_nonce_pt); - /* Can't fail since fin_nonce_pt is not infinity */ - VERIFY_CHECK(ret); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&fin_nonce_pt.y); - *fin_nonce_parity = rustsecp256k1zkp_v0_8_0_fe_is_odd(&fin_nonce_pt.y); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_musig_nonce_process(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_musig_session *session, const rustsecp256k1zkp_v0_8_0_musig_aggnonce *aggnonce, const unsigned char *msg32, const rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, const rustsecp256k1zkp_v0_8_0_pubkey *adaptor) { - rustsecp256k1zkp_v0_8_0_keyagg_cache_internal cache_i; - rustsecp256k1zkp_v0_8_0_ge aggnonce_pt[2]; - rustsecp256k1zkp_v0_8_0_gej aggnonce_ptj[2]; - unsigned char fin_nonce[32]; - rustsecp256k1zkp_v0_8_0_musig_session_internal session_i; - unsigned char agg_pk32[32]; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(session != NULL); - ARG_CHECK(aggnonce != NULL); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(keyagg_cache != NULL); - - if (!rustsecp256k1zkp_v0_8_0_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_fe_get_b32(agg_pk32, &cache_i.pk.x); - - if (!rustsecp256k1zkp_v0_8_0_musig_aggnonce_load(ctx, aggnonce_pt, aggnonce)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_gej_set_ge(&aggnonce_ptj[0], &aggnonce_pt[0]); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&aggnonce_ptj[1], &aggnonce_pt[1]); - /* Add public adaptor to nonce */ - if (adaptor != NULL) { - rustsecp256k1zkp_v0_8_0_ge adaptorp; - if (!rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &adaptorp, adaptor)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&aggnonce_ptj[0], &aggnonce_ptj[0], &adaptorp, NULL); - } - if (!rustsecp256k1zkp_v0_8_0_musig_nonce_process_internal(&session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_ptj, agg_pk32, msg32)) { - return 0; - } - - rustsecp256k1zkp_v0_8_0_schnorrsig_challenge(&session_i.challenge, fin_nonce, msg32, 32, agg_pk32); - - /* If there is a tweak then set `challenge` times `tweak` to the `s`-part.*/ - rustsecp256k1zkp_v0_8_0_scalar_set_int(&session_i.s_part, 0); - if (!rustsecp256k1zkp_v0_8_0_scalar_is_zero(&cache_i.tweak)) { - rustsecp256k1zkp_v0_8_0_scalar e_tmp; - rustsecp256k1zkp_v0_8_0_scalar_mul(&e_tmp, &session_i.challenge, &cache_i.tweak); - if (rustsecp256k1zkp_v0_8_0_fe_is_odd(&cache_i.pk.y)) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&e_tmp, &e_tmp); - } - rustsecp256k1zkp_v0_8_0_scalar_add(&session_i.s_part, &session_i.s_part, &e_tmp); - } - memcpy(session_i.fin_nonce, fin_nonce, sizeof(session_i.fin_nonce)); - rustsecp256k1zkp_v0_8_0_musig_session_save(session, &session_i); - return 1; -} - -static void rustsecp256k1zkp_v0_8_0_musig_partial_sign_clear(rustsecp256k1zkp_v0_8_0_scalar *sk, rustsecp256k1zkp_v0_8_0_scalar *k) { - rustsecp256k1zkp_v0_8_0_scalar_clear(sk); - rustsecp256k1zkp_v0_8_0_scalar_clear(&k[0]); - rustsecp256k1zkp_v0_8_0_scalar_clear(&k[1]); -} - -int rustsecp256k1zkp_v0_8_0_musig_partial_sign(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_musig_partial_sig *partial_sig, rustsecp256k1zkp_v0_8_0_musig_secnonce *secnonce, const rustsecp256k1zkp_v0_8_0_keypair *keypair, const rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, const rustsecp256k1zkp_v0_8_0_musig_session *session) { - rustsecp256k1zkp_v0_8_0_scalar sk; - rustsecp256k1zkp_v0_8_0_ge pk, keypair_pk; - rustsecp256k1zkp_v0_8_0_scalar k[2]; - rustsecp256k1zkp_v0_8_0_scalar mu, s; - rustsecp256k1zkp_v0_8_0_keyagg_cache_internal cache_i; - rustsecp256k1zkp_v0_8_0_musig_session_internal session_i; - int ret; - - VERIFY_CHECK(ctx != NULL); - - ARG_CHECK(secnonce != NULL); - /* Fails if the magic doesn't match */ - ret = rustsecp256k1zkp_v0_8_0_musig_secnonce_load(ctx, k, &pk, secnonce); - /* Set nonce to zero to avoid nonce reuse. This will cause subsequent calls - * of this function to fail */ - memset(secnonce, 0, sizeof(*secnonce)); - if (!ret) { - rustsecp256k1zkp_v0_8_0_musig_partial_sign_clear(&sk, k); - return 0; - } - - ARG_CHECK(partial_sig != NULL); - ARG_CHECK(keypair != NULL); - ARG_CHECK(keyagg_cache != NULL); - ARG_CHECK(session != NULL); - - if (!rustsecp256k1zkp_v0_8_0_keypair_load(ctx, &sk, &keypair_pk, keypair)) { - rustsecp256k1zkp_v0_8_0_musig_partial_sign_clear(&sk, k); - return 0; - } - ARG_CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&pk.x, &keypair_pk.x) - && rustsecp256k1zkp_v0_8_0_fe_equal_var(&pk.y, &keypair_pk.y)); - if (!rustsecp256k1zkp_v0_8_0_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { - rustsecp256k1zkp_v0_8_0_musig_partial_sign_clear(&sk, k); - return 0; - } - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&pk.y); - - /* Negate sk if rustsecp256k1zkp_v0_8_0_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc. - * This corresponds to the line "Let d = g⋅gacc⋅d' mod n" in the - * specification. */ - if ((rustsecp256k1zkp_v0_8_0_fe_is_odd(&cache_i.pk.y) - != cache_i.parity_acc)) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&sk, &sk); - } - - /* Multiply KeyAgg coefficient */ - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&pk.x); - /* TODO Cache mu */ - rustsecp256k1zkp_v0_8_0_musig_keyaggcoef(&mu, &cache_i, &pk); - rustsecp256k1zkp_v0_8_0_scalar_mul(&sk, &sk, &mu); - - if (!rustsecp256k1zkp_v0_8_0_musig_session_load(ctx, &session_i, session)) { - rustsecp256k1zkp_v0_8_0_musig_partial_sign_clear(&sk, k); - return 0; - } - - if (session_i.fin_nonce_parity) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&k[0], &k[0]); - rustsecp256k1zkp_v0_8_0_scalar_negate(&k[1], &k[1]); - } - - /* Sign */ - rustsecp256k1zkp_v0_8_0_scalar_mul(&s, &session_i.challenge, &sk); - rustsecp256k1zkp_v0_8_0_scalar_mul(&k[1], &session_i.noncecoef, &k[1]); - rustsecp256k1zkp_v0_8_0_scalar_add(&k[0], &k[0], &k[1]); - rustsecp256k1zkp_v0_8_0_scalar_add(&s, &s, &k[0]); - rustsecp256k1zkp_v0_8_0_musig_partial_sig_save(partial_sig, &s); - rustsecp256k1zkp_v0_8_0_musig_partial_sign_clear(&sk, k); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_musig_partial_sig *partial_sig, const rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonce, const rustsecp256k1zkp_v0_8_0_pubkey *pubkey, const rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, const rustsecp256k1zkp_v0_8_0_musig_session *session) { - rustsecp256k1zkp_v0_8_0_keyagg_cache_internal cache_i; - rustsecp256k1zkp_v0_8_0_musig_session_internal session_i; - rustsecp256k1zkp_v0_8_0_scalar mu, e, s; - rustsecp256k1zkp_v0_8_0_gej pkj; - rustsecp256k1zkp_v0_8_0_ge nonce_pt[2]; - rustsecp256k1zkp_v0_8_0_gej rj; - rustsecp256k1zkp_v0_8_0_gej tmp; - rustsecp256k1zkp_v0_8_0_ge pkp; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(partial_sig != NULL); - ARG_CHECK(pubnonce != NULL); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(keyagg_cache != NULL); - ARG_CHECK(session != NULL); - - if (!rustsecp256k1zkp_v0_8_0_musig_session_load(ctx, &session_i, session)) { - return 0; - } - - /* Compute "effective" nonce rj = aggnonce[0] + b*aggnonce[1] */ - /* TODO: use multiexp to compute -s*G + e*mu*pubkey + aggnonce[0] + b*aggnonce[1] */ - if (!rustsecp256k1zkp_v0_8_0_musig_pubnonce_load(ctx, nonce_pt, pubnonce)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_gej_set_ge(&rj, &nonce_pt[1]); - rustsecp256k1zkp_v0_8_0_ecmult(&rj, &rj, &session_i.noncecoef, NULL); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&rj, &rj, &nonce_pt[0], NULL); - - if (!rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &pkp, pubkey)) { - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { - return 0; - } - /* Multiplying the challenge by the KeyAgg coefficient is equivalent - * to multiplying the signer's public key by the coefficient, except - * much easier to do. */ - rustsecp256k1zkp_v0_8_0_musig_keyaggcoef(&mu, &cache_i, &pkp); - rustsecp256k1zkp_v0_8_0_scalar_mul(&e, &session_i.challenge, &mu); - - /* Negate e if rustsecp256k1zkp_v0_8_0_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc. - * This corresponds to the line "Let g' = g⋅gacc mod n" and the multiplication "g'⋅e" - * in the specification. */ - if (rustsecp256k1zkp_v0_8_0_fe_is_odd(&cache_i.pk.y) - != cache_i.parity_acc) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&e, &e); - } - - if (!rustsecp256k1zkp_v0_8_0_musig_partial_sig_load(ctx, &s, partial_sig)) { - return 0; - } - /* Compute -s*G + e*pkj + rj (e already includes the keyagg coefficient mu) */ - rustsecp256k1zkp_v0_8_0_scalar_negate(&s, &s); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&pkj, &pkp); - rustsecp256k1zkp_v0_8_0_ecmult(&tmp, &pkj, &e, &s); - if (session_i.fin_nonce_parity) { - rustsecp256k1zkp_v0_8_0_gej_neg(&rj, &rj); - } - rustsecp256k1zkp_v0_8_0_gej_add_var(&tmp, &tmp, &rj, NULL); - - return rustsecp256k1zkp_v0_8_0_gej_is_infinity(&tmp); -} - -int rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *sig64, const rustsecp256k1zkp_v0_8_0_musig_session *session, const rustsecp256k1zkp_v0_8_0_musig_partial_sig * const* partial_sigs, size_t n_sigs) { - size_t i; - rustsecp256k1zkp_v0_8_0_musig_session_internal session_i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(session != NULL); - ARG_CHECK(partial_sigs != NULL); - ARG_CHECK(n_sigs > 0); - - if (!rustsecp256k1zkp_v0_8_0_musig_session_load(ctx, &session_i, session)) { - return 0; - } - for (i = 0; i < n_sigs; i++) { - rustsecp256k1zkp_v0_8_0_scalar term; - if (!rustsecp256k1zkp_v0_8_0_musig_partial_sig_load(ctx, &term, partial_sigs[i])) { - return 0; - } - rustsecp256k1zkp_v0_8_0_scalar_add(&session_i.s_part, &session_i.s_part, &term); - } - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&sig64[32], &session_i.s_part); - memcpy(&sig64[0], session_i.fin_nonce, 32); - return 1; -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/tests_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/tests_impl.h deleted file mode 100644 index 8476958b..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/tests_impl.h +++ /dev/null @@ -1,1348 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2018 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_MUSIG_TESTS_IMPL_H -#define SECP256K1_MODULE_MUSIG_TESTS_IMPL_H - -#include -#include - -#include "../../../include/secp256k1.h" -#include "../../../include/secp256k1_extrakeys.h" -#include "../../../include/secp256k1_musig.h" - -#include "session.h" -#include "keyagg.h" -#include "../../scalar.h" -#include "../../scratch.h" -#include "../../field.h" -#include "../../group.h" -#include "../../hash.h" -#include "../../util.h" - -#include "vectors.h" - -static int create_keypair_and_pk(rustsecp256k1zkp_v0_8_0_keypair *keypair, rustsecp256k1zkp_v0_8_0_pubkey *pk, const unsigned char *sk) { - int ret; - rustsecp256k1zkp_v0_8_0_keypair keypair_tmp; - ret = rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair_tmp, sk); - ret &= rustsecp256k1zkp_v0_8_0_keypair_pub(ctx, pk, &keypair_tmp); - if (keypair != NULL) { - *keypair = keypair_tmp; - } - return ret; -} - -/* Just a simple (non-adaptor, non-tweaked) 2-of-2 MuSig aggregate, sign, verify - * test. */ -void musig_simple_test(rustsecp256k1zkp_v0_8_0_scratch_space *scratch) { - unsigned char sk[2][32]; - rustsecp256k1zkp_v0_8_0_keypair keypair[2]; - rustsecp256k1zkp_v0_8_0_musig_pubnonce pubnonce[2]; - const rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonce_ptr[2]; - rustsecp256k1zkp_v0_8_0_musig_aggnonce aggnonce; - unsigned char msg[32]; - rustsecp256k1zkp_v0_8_0_xonly_pubkey agg_pk; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache; - unsigned char session_id[2][32]; - rustsecp256k1zkp_v0_8_0_musig_secnonce secnonce[2]; - rustsecp256k1zkp_v0_8_0_pubkey pk[2]; - const rustsecp256k1zkp_v0_8_0_pubkey *pk_ptr[2]; - rustsecp256k1zkp_v0_8_0_musig_partial_sig partial_sig[2]; - const rustsecp256k1zkp_v0_8_0_musig_partial_sig *partial_sig_ptr[2]; - unsigned char final_sig[64]; - rustsecp256k1zkp_v0_8_0_musig_session session; - int i; - - rustsecp256k1zkp_v0_8_0_testrand256(msg); - for (i = 0; i < 2; i++) { - rustsecp256k1zkp_v0_8_0_testrand256(session_id[i]); - rustsecp256k1zkp_v0_8_0_testrand256(sk[i]); - pk_ptr[i] = &pk[i]; - pubnonce_ptr[i] = &pubnonce[i]; - partial_sig_ptr[i] = &partial_sig[i]; - - CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i])); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(ctx, &secnonce[i], &pubnonce[i], session_id[i], sk[i], &pk[i], NULL, NULL, NULL) == 1); - } - - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(ctx, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(ctx, &session, &aggnonce, msg, &keyagg_cache, NULL) == 1); - - for (i = 0; i < 2; i++) { - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(ctx, &partial_sig[i], &secnonce[i], &keypair[i], &keyagg_cache, &session) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(ctx, &partial_sig[i], &pubnonce[i], &pk[i], &keyagg_cache, &session) == 1); - } - - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(ctx, final_sig, &session, partial_sig_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, final_sig, msg, sizeof(msg), &agg_pk) == 1); -} - -void pubnonce_summing_to_inf(rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonce) { - rustsecp256k1zkp_v0_8_0_ge ge[2]; - int i; - rustsecp256k1zkp_v0_8_0_gej summed_nonces[2]; - const rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonce_ptr[2]; - - ge[0] = rustsecp256k1zkp_v0_8_0_ge_const_g; - ge[1] = rustsecp256k1zkp_v0_8_0_ge_const_g; - - for (i = 0; i < 2; i++) { - rustsecp256k1zkp_v0_8_0_musig_pubnonce_save(&pubnonce[i], ge); - pubnonce_ptr[i] = &pubnonce[i]; - rustsecp256k1zkp_v0_8_0_ge_neg(&ge[0], &ge[0]); - rustsecp256k1zkp_v0_8_0_ge_neg(&ge[1], &ge[1]); - } - - rustsecp256k1zkp_v0_8_0_musig_sum_nonces(ctx, summed_nonces, pubnonce_ptr, 2); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&summed_nonces[0])); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&summed_nonces[1])); -} - -int memcmp_and_randomize(unsigned char *value, const unsigned char *expected, size_t len) { - int ret; - size_t i; - ret = rustsecp256k1zkp_v0_8_0_memcmp_var(value, expected, len); - for (i = 0; i < len; i++) { - value[i] = rustsecp256k1zkp_v0_8_0_testrand_bits(8); - } - return ret; -} - -void musig_api_tests(rustsecp256k1zkp_v0_8_0_scratch_space *scratch) { - rustsecp256k1zkp_v0_8_0_scratch_space *scratch_small; - rustsecp256k1zkp_v0_8_0_musig_partial_sig partial_sig[2]; - const rustsecp256k1zkp_v0_8_0_musig_partial_sig *partial_sig_ptr[2]; - rustsecp256k1zkp_v0_8_0_musig_partial_sig invalid_partial_sig; - const rustsecp256k1zkp_v0_8_0_musig_partial_sig *invalid_partial_sig_ptr[2]; - unsigned char final_sig[64]; - unsigned char pre_sig[64]; - unsigned char buf[32]; - unsigned char sk[2][32]; - rustsecp256k1zkp_v0_8_0_keypair keypair[2]; - rustsecp256k1zkp_v0_8_0_keypair invalid_keypair; - unsigned char max64[64]; - unsigned char zeros132[132] = { 0 }; - unsigned char session_id[2][32]; - rustsecp256k1zkp_v0_8_0_musig_secnonce secnonce[2]; - rustsecp256k1zkp_v0_8_0_musig_secnonce secnonce_tmp; - rustsecp256k1zkp_v0_8_0_musig_secnonce invalid_secnonce; - rustsecp256k1zkp_v0_8_0_musig_pubnonce pubnonce[2]; - const rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonce_ptr[2]; - unsigned char pubnonce_ser[66]; - rustsecp256k1zkp_v0_8_0_musig_pubnonce inf_pubnonce[2]; - const rustsecp256k1zkp_v0_8_0_musig_pubnonce *inf_pubnonce_ptr[2]; - rustsecp256k1zkp_v0_8_0_musig_pubnonce invalid_pubnonce; - const rustsecp256k1zkp_v0_8_0_musig_pubnonce *invalid_pubnonce_ptr[1]; - rustsecp256k1zkp_v0_8_0_musig_aggnonce aggnonce; - unsigned char aggnonce_ser[66]; - unsigned char msg[32]; - rustsecp256k1zkp_v0_8_0_xonly_pubkey agg_pk; - rustsecp256k1zkp_v0_8_0_pubkey full_agg_pk; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache invalid_keyagg_cache; - rustsecp256k1zkp_v0_8_0_musig_session session; - rustsecp256k1zkp_v0_8_0_musig_session invalid_session; - rustsecp256k1zkp_v0_8_0_pubkey pk[2]; - const rustsecp256k1zkp_v0_8_0_pubkey *pk_ptr[2]; - rustsecp256k1zkp_v0_8_0_pubkey invalid_pk; - const rustsecp256k1zkp_v0_8_0_pubkey *invalid_pk_ptr2[2]; - const rustsecp256k1zkp_v0_8_0_pubkey *invalid_pk_ptr3[3]; - unsigned char tweak[32]; - int nonce_parity; - unsigned char sec_adaptor[32]; - unsigned char sec_adaptor1[32]; - rustsecp256k1zkp_v0_8_0_pubkey adaptor; - int i; - - /** setup **/ - rustsecp256k1zkp_v0_8_0_context *none = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); - rustsecp256k1zkp_v0_8_0_context *sign = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN); - rustsecp256k1zkp_v0_8_0_context *vrfy = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *sttc = rustsecp256k1zkp_v0_8_0_context_clone(rustsecp256k1zkp_v0_8_0_context_no_precomp); - int ecount; - - rustsecp256k1zkp_v0_8_0_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); - - memset(max64, 0xff, sizeof(max64)); - memset(&invalid_keypair, 0, sizeof(invalid_keypair)); - memset(&invalid_pk, 0, sizeof(invalid_pk)); - memset(&invalid_secnonce, 0, sizeof(invalid_secnonce)); - memset(&invalid_partial_sig, 0, sizeof(invalid_partial_sig)); - pubnonce_summing_to_inf(inf_pubnonce); - /* Simulate structs being uninitialized by setting it to 0s. We don't want - * to produce undefined behavior by actually providing uninitialized - * structs. */ - memset(&invalid_keyagg_cache, 0, sizeof(invalid_keyagg_cache)); - memset(&invalid_pk, 0, sizeof(invalid_pk)); - memset(&invalid_pubnonce, 0, sizeof(invalid_pubnonce)); - memset(&invalid_session, 0, sizeof(invalid_session)); - - rustsecp256k1zkp_v0_8_0_testrand256(sec_adaptor); - rustsecp256k1zkp_v0_8_0_testrand256(msg); - rustsecp256k1zkp_v0_8_0_testrand256(tweak); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &adaptor, sec_adaptor) == 1); - for (i = 0; i < 2; i++) { - pk_ptr[i] = &pk[i]; - invalid_pk_ptr2[i] = &invalid_pk; - invalid_pk_ptr3[i] = &pk[i]; - pubnonce_ptr[i] = &pubnonce[i]; - inf_pubnonce_ptr[i] = &inf_pubnonce[i]; - partial_sig_ptr[i] = &partial_sig[i]; - invalid_partial_sig_ptr[i] = &partial_sig[i]; - rustsecp256k1zkp_v0_8_0_testrand256(session_id[i]); - rustsecp256k1zkp_v0_8_0_testrand256(sk[i]); - CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i])); - } - invalid_pubnonce_ptr[0] = &invalid_pubnonce; - invalid_partial_sig_ptr[0] = &invalid_partial_sig; - /* invalid_pk_ptr3 has two valid, one invalid pk, which is important to test - * musig_pubkey_agg */ - invalid_pk_ptr3[2] = &invalid_pk; - - /** main test body **/ - - /** Key aggregation **/ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(none, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(sign, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); - /* pubkey_agg does not require a scratch space */ - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(vrfy, NULL, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); - /* A small scratch space works too, but will result in using an ineffecient algorithm */ - scratch_small = rustsecp256k1zkp_v0_8_0_scratch_space_create(ctx, 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(vrfy, scratch_small, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); - rustsecp256k1zkp_v0_8_0_scratch_space_destroy(ctx, scratch_small); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(vrfy, scratch, NULL, &keyagg_cache, pk_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(vrfy, scratch, &agg_pk, NULL, pk_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, NULL, 2) == 0); - CHECK(ecount == 1); - CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, invalid_pk_ptr2, 2) == 0); - CHECK(ecount == 2); - CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, invalid_pk_ptr3, 3) == 0); - CHECK(ecount == 3); - CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, pk_ptr, 0) == 0); - CHECK(ecount == 4); - CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, NULL, 0) == 0); - CHECK(ecount == 5); - CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(none, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(sign, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); - - /* pubkey_get */ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_get(none, &full_agg_pk, &keyagg_cache) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_get(none, NULL, &keyagg_cache) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_get(none, &full_agg_pk, NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&full_agg_pk, zeros132, sizeof(full_agg_pk)) == 0); - - /** Tweaking **/ - { - int (*tweak_func[2]) (const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *output_pubkey, rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32); - tweak_func[0] = rustsecp256k1zkp_v0_8_0_musig_pubkey_ec_tweak_add; - tweak_func[1] = rustsecp256k1zkp_v0_8_0_musig_pubkey_xonly_tweak_add; - for (i = 0; i < 2; i++) { - rustsecp256k1zkp_v0_8_0_pubkey tmp_output_pk; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache tmp_keyagg_cache = keyagg_cache; - ecount = 0; - CHECK((*tweak_func[i])(ctx, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); - /* Reset keyagg_cache */ - tmp_keyagg_cache = keyagg_cache; - CHECK((*tweak_func[i])(none, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); - tmp_keyagg_cache = keyagg_cache; - CHECK((*tweak_func[i])(sign, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); - tmp_keyagg_cache = keyagg_cache; - CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); - tmp_keyagg_cache = keyagg_cache; - CHECK((*tweak_func[i])(vrfy, NULL, &tmp_keyagg_cache, tweak) == 1); - tmp_keyagg_cache = keyagg_cache; - CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, NULL, tweak) == 0); - CHECK(ecount == 1); - CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); - tmp_keyagg_cache = keyagg_cache; - CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, &tmp_keyagg_cache, NULL) == 0); - CHECK(ecount == 2); - CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); - tmp_keyagg_cache = keyagg_cache; - CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, &tmp_keyagg_cache, max64) == 0); - CHECK(ecount == 2); - CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); - tmp_keyagg_cache = keyagg_cache; - /* Uninitialized keyagg_cache */ - CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, &invalid_keyagg_cache, tweak) == 0); - CHECK(ecount == 3); - CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); - } - } - - /** Session creation **/ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(none, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(vrfy, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sttc, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, NULL, &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[0], NULL, session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], NULL, sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); - CHECK(ecount == 4); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - /* no seckey and session_id is 0 */ - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], zeros132, NULL, &pk[0], msg, &keyagg_cache, max64) == 0); - CHECK(ecount == 4); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - /* session_id 0 is fine when a seckey is provided */ - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], zeros132, sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], NULL, &pk[0], msg, &keyagg_cache, max64) == 1); - CHECK(ecount == 4); - /* invalid seckey */ - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], max64, &pk[0], msg, &keyagg_cache, max64) == 0); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], NULL, msg, &keyagg_cache, max64) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &invalid_pk, msg, &keyagg_cache, max64) == 0); - CHECK(ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], NULL, &keyagg_cache, max64) == 1); - CHECK(ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, NULL, max64) == 1); - CHECK(ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &invalid_keyagg_cache, max64) == 0); - CHECK(ecount == 7); - CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, NULL) == 1); - CHECK(ecount == 7); - - /* Every in-argument except session_id and pubkey can be NULL */ - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], NULL, &pk[0], NULL, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(sign, &secnonce[1], &pubnonce[1], session_id[1], sk[1], &pk[1], NULL, NULL, NULL) == 1); - - /** Serialize and parse public nonces **/ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_serialize(none, NULL, &pubnonce[0]) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_serialize(none, pubnonce_ser, NULL) == 0); - CHECK(ecount == 2); - CHECK(memcmp_and_randomize(pubnonce_ser, zeros132, sizeof(pubnonce_ser)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_serialize(none, pubnonce_ser, &invalid_pubnonce) == 0); - CHECK(ecount == 3); - CHECK(memcmp_and_randomize(pubnonce_ser, zeros132, sizeof(pubnonce_ser)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_serialize(none, pubnonce_ser, &pubnonce[0]) == 1); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse(none, &pubnonce[0], pubnonce_ser) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse(none, NULL, pubnonce_ser) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse(none, &pubnonce[0], NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse(none, &pubnonce[0], zeros132) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse(none, &pubnonce[0], pubnonce_ser) == 1); - - { - /* Check that serialize and parse results in the same value */ - rustsecp256k1zkp_v0_8_0_musig_pubnonce tmp; - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_serialize(none, pubnonce_ser, &pubnonce[0]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse(none, &tmp, pubnonce_ser) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&tmp, &pubnonce[0], sizeof(tmp)) == 0); - } - - /** Receive nonces and aggregate **/ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_agg(none, &aggnonce, pubnonce_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_agg(none, NULL, pubnonce_ptr, 2) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_agg(none, &aggnonce, NULL, 2) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_agg(none, &aggnonce, pubnonce_ptr, 0) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_agg(none, &aggnonce, invalid_pubnonce_ptr, 1) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_agg(none, &aggnonce, inf_pubnonce_ptr, 2) == 1); - { - /* Check that the aggnonce encodes two points at infinity */ - rustsecp256k1zkp_v0_8_0_ge aggnonce_pt[2]; - rustsecp256k1zkp_v0_8_0_musig_aggnonce_load(ctx, aggnonce_pt, &aggnonce); - for (i = 0; i < 2; i++) { - rustsecp256k1zkp_v0_8_0_ge_is_infinity(&aggnonce_pt[i]); - } - } - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_agg(none, &aggnonce, pubnonce_ptr, 2) == 1); - - /** Serialize and parse aggregate nonces **/ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_serialize(none, aggnonce_ser, &aggnonce) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_serialize(none, NULL, &aggnonce) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_serialize(none, aggnonce_ser, NULL) == 0); - CHECK(ecount == 2); - CHECK(memcmp_and_randomize(aggnonce_ser, zeros132, sizeof(aggnonce_ser)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_serialize(none, aggnonce_ser, (rustsecp256k1zkp_v0_8_0_musig_aggnonce*) &invalid_pubnonce) == 0); - CHECK(ecount == 3); - CHECK(memcmp_and_randomize(aggnonce_ser, zeros132, sizeof(aggnonce_ser)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_serialize(none, aggnonce_ser, &aggnonce) == 1); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_parse(none, &aggnonce, aggnonce_ser) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_parse(none, NULL, aggnonce_ser) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_parse(none, &aggnonce, NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_parse(none, &aggnonce, zeros132) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_parse(none, &aggnonce, aggnonce_ser) == 1); - - { - /* Check that serialize and parse results in the same value */ - rustsecp256k1zkp_v0_8_0_musig_aggnonce tmp; - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_serialize(none, aggnonce_ser, &aggnonce) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_parse(none, &tmp, aggnonce_ser) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&tmp, &aggnonce, sizeof(tmp)) == 0); - } - - /** Process nonces **/ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(none, &session, &aggnonce, msg, &keyagg_cache, &adaptor) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(sign, &session, &aggnonce, msg, &keyagg_cache, &adaptor) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(vrfy, NULL, &aggnonce, msg, &keyagg_cache, &adaptor) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(vrfy, &session, NULL, msg, &keyagg_cache, &adaptor) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(vrfy, &session, (rustsecp256k1zkp_v0_8_0_musig_aggnonce*) &invalid_pubnonce, msg, &keyagg_cache, &adaptor) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(vrfy, &session, &aggnonce, NULL, &keyagg_cache, &adaptor) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(vrfy, &session, &aggnonce, msg, NULL, &adaptor) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(vrfy, &session, &aggnonce, msg, &invalid_keyagg_cache, &adaptor) == 0); - CHECK(ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(vrfy, &session, &aggnonce, msg, &keyagg_cache, NULL) == 1); - CHECK(ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(vrfy, &session, &aggnonce, msg, &keyagg_cache, (rustsecp256k1zkp_v0_8_0_pubkey *)&invalid_pk) == 0); - CHECK(ecount == 7); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(vrfy, &session, &aggnonce, msg, &keyagg_cache, &adaptor) == 1); - - ecount = 0; - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 1); - /* The secnonce is set to 0 and subsequent signing attempts fail */ - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&secnonce_tmp, zeros132, sizeof(secnonce_tmp)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 1); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(none, NULL, &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 2); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(none, &partial_sig[0], NULL, &keypair[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(none, &partial_sig[0], &invalid_secnonce, &keypair[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, NULL, &keyagg_cache, &session) == 0); - CHECK(ecount == 5); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &invalid_keypair, &keyagg_cache, &session) == 0); - CHECK(ecount == 6); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - { - unsigned char sk_tmp[32]; - rustsecp256k1zkp_v0_8_0_keypair keypair_tmp; - rustsecp256k1zkp_v0_8_0_testrand256(sk_tmp); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair_tmp, sk_tmp)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair_tmp, &keyagg_cache, &session) == 0); - CHECK(ecount == 7); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - } - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], NULL, &session) == 0); - CHECK(ecount == 8); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &invalid_keyagg_cache, &session) == 0); - CHECK(ecount == 9); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, NULL) == 0); - CHECK(ecount == 10); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &invalid_session) == 0); - CHECK(ecount == 11); - memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(none, &partial_sig[0], &secnonce[0], &keypair[0], &keyagg_cache, &session) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(none, &partial_sig[1], &secnonce[1], &keypair[1], &keyagg_cache, &session) == 1); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_serialize(none, buf, &partial_sig[0]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_serialize(none, NULL, &partial_sig[0]) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_serialize(none, buf, NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_parse(none, &partial_sig[0], buf) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_parse(none, NULL, buf) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_parse(none, &partial_sig[0], max64) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_parse(none, &partial_sig[0], NULL) == 0); - CHECK(ecount == 4); - - { - /* Check that serialize and parse results in the same value */ - rustsecp256k1zkp_v0_8_0_musig_partial_sig tmp; - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_serialize(none, buf, &partial_sig[0]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_parse(none, &tmp, buf) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&tmp, &partial_sig[0], sizeof(tmp)) == 0); - } - - /** Partial signature verification */ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(none, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(sign, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(vrfy, &partial_sig[1], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(vrfy, NULL, &pubnonce[0], &pk[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(vrfy, &invalid_partial_sig, &pubnonce[0], &pk[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(vrfy, &partial_sig[0], NULL, &pk[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(vrfy, &partial_sig[0], &invalid_pubnonce, &pk[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], NULL, &keyagg_cache, &session) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], &invalid_pk, &keyagg_cache, &session) == 0); - CHECK(ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], &pk[0], NULL, &session) == 0); - CHECK(ecount == 7); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], &pk[0], &invalid_keyagg_cache, &session) == 0); - CHECK(ecount == 8); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, NULL) == 0); - CHECK(ecount == 9); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &invalid_session) == 0); - CHECK(ecount == 10); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(vrfy, &partial_sig[1], &pubnonce[1], &pk[1], &keyagg_cache, &session) == 1); - - /** Signature aggregation and verification */ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(none, pre_sig, &session, partial_sig_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(none, NULL, &session, partial_sig_ptr, 2) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(none, pre_sig, NULL, partial_sig_ptr, 2) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(none, pre_sig, &invalid_session, partial_sig_ptr, 2) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(none, pre_sig, &session, NULL, 2) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(none, pre_sig, &session, invalid_partial_sig_ptr, 2) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(none, pre_sig, &session, partial_sig_ptr, 0) == 0); - CHECK(ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(none, pre_sig, &session, partial_sig_ptr, 1) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(none, pre_sig, &session, partial_sig_ptr, 2) == 1); - - /** Adaptor signature verification */ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_parity(none, &nonce_parity, &session) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_parity(none, NULL, &session) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_parity(none, &nonce_parity, NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_parity(none, &nonce_parity, &invalid_session) == 0); - CHECK(ecount == 3); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_adapt(none, final_sig, pre_sig, sec_adaptor, nonce_parity) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_adapt(none, NULL, pre_sig, sec_adaptor, 0) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_adapt(none, final_sig, NULL, sec_adaptor, 0) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_musig_adapt(none, final_sig, max64, sec_adaptor, 0) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_musig_adapt(none, final_sig, pre_sig, NULL, 0) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_musig_adapt(none, final_sig, pre_sig, max64, 0) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_musig_adapt(none, final_sig, pre_sig, sec_adaptor, 2) == 0); - CHECK(ecount == 4); - /* sig and pre_sig argument point to the same location */ - memcpy(final_sig, pre_sig, sizeof(final_sig)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_adapt(none, final_sig, final_sig, sec_adaptor, nonce_parity) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(vrfy, final_sig, msg, sizeof(msg), &agg_pk) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_adapt(none, final_sig, pre_sig, sec_adaptor, nonce_parity) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(vrfy, final_sig, msg, sizeof(msg), &agg_pk) == 1); - - /** Secret adaptor can be extracted from signature */ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_musig_extract_adaptor(none, sec_adaptor1, final_sig, pre_sig, nonce_parity) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(sec_adaptor, sec_adaptor1, 32) == 0); - /* wrong nonce parity */ - CHECK(rustsecp256k1zkp_v0_8_0_musig_extract_adaptor(none, sec_adaptor1, final_sig, pre_sig, !nonce_parity) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(sec_adaptor, sec_adaptor1, 32) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_musig_extract_adaptor(none, NULL, final_sig, pre_sig, 0) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_extract_adaptor(none, sec_adaptor1, NULL, pre_sig, 0) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_musig_extract_adaptor(none, sec_adaptor1, max64, pre_sig, 0) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_musig_extract_adaptor(none, sec_adaptor1, final_sig, NULL, 0) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_musig_extract_adaptor(none, sec_adaptor1, final_sig, max64, 0) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_musig_extract_adaptor(none, sec_adaptor1, final_sig, pre_sig, 2) == 0); - CHECK(ecount == 4); - - /** cleanup **/ - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(vrfy); - rustsecp256k1zkp_v0_8_0_context_destroy(sttc); -} - -void musig_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) { - rustsecp256k1zkp_v0_8_0_scalar k1[2], k2[2]; - - rustsecp256k1zkp_v0_8_0_nonce_function_musig(k1, args[0], args[1], args[2], args[3], args[4], args[5]); - rustsecp256k1zkp_v0_8_0_testrand_flip(args[n_flip], n_bytes); - rustsecp256k1zkp_v0_8_0_nonce_function_musig(k2, args[0], args[1], args[2], args[3], args[4], args[5]); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&k1[0], &k2[0]) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&k1[1], &k2[1]) == 0); -} - -void musig_nonce_test(void) { - unsigned char *args[6]; - unsigned char session_id[32]; - unsigned char sk[32]; - unsigned char pk[33]; - unsigned char msg[32]; - unsigned char agg_pk[32]; - unsigned char extra_input[32]; - int i, j; - rustsecp256k1zkp_v0_8_0_scalar k[6][2]; - - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(session_id, sizeof(session_id)); - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(sk, sizeof(sk)); - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(pk, sizeof(pk)); - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(msg, sizeof(msg)); - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(agg_pk, sizeof(agg_pk)); - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(extra_input, sizeof(extra_input)); - - /* Check that a bitflip in an argument results in different nonces. */ - args[0] = session_id; - args[1] = msg; - args[2] = sk; - args[3] = pk; - args[4] = agg_pk; - args[5] = extra_input; - for (i = 0; i < count; i++) { - musig_nonce_bitflip(args, 0, sizeof(session_id)); - musig_nonce_bitflip(args, 1, sizeof(msg)); - musig_nonce_bitflip(args, 2, sizeof(sk)); - musig_nonce_bitflip(args, 3, sizeof(pk)); - musig_nonce_bitflip(args, 4, sizeof(agg_pk)); - musig_nonce_bitflip(args, 5, sizeof(extra_input)); - } - /* Check that if any argument is NULL, a different nonce is produced than if - * any other argument is NULL. */ - memcpy(msg, session_id, sizeof(msg)); - memcpy(sk, session_id, sizeof(sk)); - memcpy(pk, session_id, sizeof(session_id)); - memcpy(agg_pk, session_id, sizeof(agg_pk)); - memcpy(extra_input, session_id, sizeof(extra_input)); - rustsecp256k1zkp_v0_8_0_nonce_function_musig(k[0], args[0], args[1], args[2], args[3], args[4], args[5]); - rustsecp256k1zkp_v0_8_0_nonce_function_musig(k[1], args[0], NULL, args[2], args[3], args[4], args[5]); - rustsecp256k1zkp_v0_8_0_nonce_function_musig(k[2], args[0], args[1], NULL, args[3], args[4], args[5]); - rustsecp256k1zkp_v0_8_0_nonce_function_musig(k[3], args[0], args[1], args[2], NULL, args[4], args[5]); - rustsecp256k1zkp_v0_8_0_nonce_function_musig(k[4], args[0], args[1], args[2], args[3], NULL, args[5]); - rustsecp256k1zkp_v0_8_0_nonce_function_musig(k[5], args[0], args[1], args[2], args[3], args[4], NULL); - for (i = 0; i < 6; i++) { - CHECK(!rustsecp256k1zkp_v0_8_0_scalar_eq(&k[i][0], &k[i][1])); - for (j = i+1; j < 6; j++) { - CHECK(!rustsecp256k1zkp_v0_8_0_scalar_eq(&k[i][0], &k[j][0])); - CHECK(!rustsecp256k1zkp_v0_8_0_scalar_eq(&k[i][1], &k[j][1])); - } - } -} - -void scriptless_atomic_swap(rustsecp256k1zkp_v0_8_0_scratch_space *scratch) { - /* Throughout this test "a" and "b" refer to two hypothetical blockchains, - * while the indices 0 and 1 refer to the two signers. Here signer 0 is - * sending a-coins to signer 1, while signer 1 is sending b-coins to signer - * 0. Signer 0 produces the adaptor signatures. */ - unsigned char pre_sig_a[64]; - unsigned char final_sig_a[64]; - unsigned char pre_sig_b[64]; - unsigned char final_sig_b[64]; - rustsecp256k1zkp_v0_8_0_musig_partial_sig partial_sig_a[2]; - const rustsecp256k1zkp_v0_8_0_musig_partial_sig *partial_sig_a_ptr[2]; - rustsecp256k1zkp_v0_8_0_musig_partial_sig partial_sig_b[2]; - const rustsecp256k1zkp_v0_8_0_musig_partial_sig *partial_sig_b_ptr[2]; - unsigned char sec_adaptor[32]; - unsigned char sec_adaptor_extracted[32]; - rustsecp256k1zkp_v0_8_0_pubkey pub_adaptor; - unsigned char sk_a[2][32]; - unsigned char sk_b[2][32]; - rustsecp256k1zkp_v0_8_0_keypair keypair_a[2]; - rustsecp256k1zkp_v0_8_0_keypair keypair_b[2]; - rustsecp256k1zkp_v0_8_0_pubkey pk_a[2]; - const rustsecp256k1zkp_v0_8_0_pubkey *pk_a_ptr[2]; - rustsecp256k1zkp_v0_8_0_pubkey pk_b[2]; - const rustsecp256k1zkp_v0_8_0_pubkey *pk_b_ptr[2]; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache_a; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache_b; - rustsecp256k1zkp_v0_8_0_xonly_pubkey agg_pk_a; - rustsecp256k1zkp_v0_8_0_xonly_pubkey agg_pk_b; - rustsecp256k1zkp_v0_8_0_musig_secnonce secnonce_a[2]; - rustsecp256k1zkp_v0_8_0_musig_secnonce secnonce_b[2]; - rustsecp256k1zkp_v0_8_0_musig_pubnonce pubnonce_a[2]; - rustsecp256k1zkp_v0_8_0_musig_pubnonce pubnonce_b[2]; - const rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonce_ptr_a[2]; - const rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonce_ptr_b[2]; - rustsecp256k1zkp_v0_8_0_musig_aggnonce aggnonce_a; - rustsecp256k1zkp_v0_8_0_musig_aggnonce aggnonce_b; - rustsecp256k1zkp_v0_8_0_musig_session session_a, session_b; - int nonce_parity_a; - int nonce_parity_b; - unsigned char seed_a[2][32] = { "a0", "a1" }; - unsigned char seed_b[2][32] = { "b0", "b1" }; - const unsigned char msg32_a[32] = "this is the message blockchain a"; - const unsigned char msg32_b[32] = "this is the message blockchain b"; - int i; - - /* Step 1: key setup */ - for (i = 0; i < 2; i++) { - pk_a_ptr[i] = &pk_a[i]; - pk_b_ptr[i] = &pk_b[i]; - pubnonce_ptr_a[i] = &pubnonce_a[i]; - pubnonce_ptr_b[i] = &pubnonce_b[i]; - partial_sig_a_ptr[i] = &partial_sig_a[i]; - partial_sig_b_ptr[i] = &partial_sig_b[i]; - - rustsecp256k1zkp_v0_8_0_testrand256(sk_a[i]); - rustsecp256k1zkp_v0_8_0_testrand256(sk_b[i]); - CHECK(create_keypair_and_pk(&keypair_a[i], &pk_a[i], sk_a[i]) == 1); - CHECK(create_keypair_and_pk(&keypair_b[i], &pk_b[i], sk_b[i]) == 1); - } - rustsecp256k1zkp_v0_8_0_testrand256(sec_adaptor); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pub_adaptor, sec_adaptor) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(ctx, scratch, &agg_pk_a, &keyagg_cache_a, pk_a_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(ctx, scratch, &agg_pk_b, &keyagg_cache_b, pk_b_ptr, 2) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(ctx, &secnonce_a[0], &pubnonce_a[0], seed_a[0], sk_a[0], &pk_a[0], NULL, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(ctx, &secnonce_a[1], &pubnonce_a[1], seed_a[1], sk_a[1], &pk_a[1], NULL, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(ctx, &secnonce_b[0], &pubnonce_b[0], seed_b[0], sk_b[0], &pk_b[0], NULL, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(ctx, &secnonce_b[1], &pubnonce_b[1], seed_b[1], sk_b[1], &pk_b[1], NULL, NULL, NULL) == 1); - - /* Step 2: Exchange nonces */ - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_agg(ctx, &aggnonce_a, pubnonce_ptr_a, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(ctx, &session_a, &aggnonce_a, msg32_a, &keyagg_cache_a, &pub_adaptor) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_parity(ctx, &nonce_parity_a, &session_a) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_agg(ctx, &aggnonce_b, pubnonce_ptr_b, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(ctx, &session_b, &aggnonce_b, msg32_b, &keyagg_cache_b, &pub_adaptor) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_parity(ctx, &nonce_parity_b, &session_b) == 1); - - /* Step 3: Signer 0 produces partial signatures for both chains. */ - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(ctx, &partial_sig_a[0], &secnonce_a[0], &keypair_a[0], &keyagg_cache_a, &session_a) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(ctx, &partial_sig_b[0], &secnonce_b[0], &keypair_b[0], &keyagg_cache_b, &session_b) == 1); - - /* Step 4: Signer 1 receives partial signatures, verifies them and creates a - * partial signature to send B-coins to signer 0. */ - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(ctx, &partial_sig_a[0], &pubnonce_a[0], &pk_a[0], &keyagg_cache_a, &session_a) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(ctx, &partial_sig_b[0], &pubnonce_b[0], &pk_b[0], &keyagg_cache_b, &session_b) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(ctx, &partial_sig_b[1], &secnonce_b[1], &keypair_b[1], &keyagg_cache_b, &session_b) == 1); - - /* Step 5: Signer 0 aggregates its own partial signature with the partial - * signature from signer 1 and adapts it. This results in a complete - * signature which is broadcasted by signer 0 to take B-coins. */ - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(ctx, pre_sig_b, &session_b, partial_sig_b_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_adapt(ctx, final_sig_b, pre_sig_b, sec_adaptor, nonce_parity_b) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, final_sig_b, msg32_b, sizeof(msg32_b), &agg_pk_b) == 1); - - /* Step 6: Signer 1 signs, extracts adaptor from the published signature, - * and adapts the signature to take A-coins. */ - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(ctx, &partial_sig_a[1], &secnonce_a[1], &keypair_a[1], &keyagg_cache_a, &session_a) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(ctx, pre_sig_a, &session_a, partial_sig_a_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_extract_adaptor(ctx, sec_adaptor_extracted, final_sig_b, pre_sig_b, nonce_parity_b) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(sec_adaptor_extracted, sec_adaptor, sizeof(sec_adaptor)) == 0); /* in real life we couldn't check this, of course */ - CHECK(rustsecp256k1zkp_v0_8_0_musig_adapt(ctx, final_sig_a, pre_sig_a, sec_adaptor_extracted, nonce_parity_a) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, final_sig_a, msg32_a, sizeof(msg32_a), &agg_pk_a) == 1); -} - -void sha256_tag_test_internal(rustsecp256k1zkp_v0_8_0_sha256 *sha_tagged, unsigned char *tag, size_t taglen) { - rustsecp256k1zkp_v0_8_0_sha256 sha; - unsigned char buf[32]; - unsigned char buf2[32]; - size_t i; - - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, tag, taglen); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, buf); - /* buf = SHA256(tag) */ - - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, buf, 32); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, buf, 32); - /* Is buffer fully consumed? */ - CHECK((sha.bytes & 0x3F) == 0); - - /* Compare with tagged SHA */ - for (i = 0; i < 8; i++) { - CHECK(sha_tagged->s[i] == sha.s[i]); - } - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, buf, 32); - rustsecp256k1zkp_v0_8_0_sha256_write(sha_tagged, buf, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, buf); - rustsecp256k1zkp_v0_8_0_sha256_finalize(sha_tagged, buf2); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(buf, buf2, 32) == 0); -} - -/* Checks that the initialized tagged hashes initialized have the expected - * state. */ -void sha256_tag_test(void) { - rustsecp256k1zkp_v0_8_0_sha256 sha_tagged; - { - char tag[11] = "KeyAgg list"; - rustsecp256k1zkp_v0_8_0_musig_keyagglist_sha256(&sha_tagged); - sha256_tag_test_internal(&sha_tagged, (unsigned char*)tag, sizeof(tag)); - } - { - char tag[18] = "KeyAgg coefficient"; - rustsecp256k1zkp_v0_8_0_musig_keyaggcoef_sha256(&sha_tagged); - sha256_tag_test_internal(&sha_tagged, (unsigned char*)tag, sizeof(tag)); - } -} - -/* Attempts to create a signature for the aggregate public key using given secret - * keys and keyagg_cache. */ -void musig_tweak_test_helper(const rustsecp256k1zkp_v0_8_0_xonly_pubkey* agg_pk, const unsigned char *sk0, const unsigned char *sk1, rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache) { - rustsecp256k1zkp_v0_8_0_pubkey pk[2]; - unsigned char session_id[2][32]; - unsigned char msg[32]; - rustsecp256k1zkp_v0_8_0_musig_secnonce secnonce[2]; - rustsecp256k1zkp_v0_8_0_musig_pubnonce pubnonce[2]; - const rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonce_ptr[2]; - rustsecp256k1zkp_v0_8_0_musig_aggnonce aggnonce; - rustsecp256k1zkp_v0_8_0_keypair keypair[2]; - rustsecp256k1zkp_v0_8_0_musig_session session; - rustsecp256k1zkp_v0_8_0_musig_partial_sig partial_sig[2]; - const rustsecp256k1zkp_v0_8_0_musig_partial_sig *partial_sig_ptr[2]; - unsigned char final_sig[64]; - int i; - - for (i = 0; i < 2; i++) { - pubnonce_ptr[i] = &pubnonce[i]; - partial_sig_ptr[i] = &partial_sig[i]; - - rustsecp256k1zkp_v0_8_0_testrand256(session_id[i]); - } - CHECK(create_keypair_and_pk(&keypair[0], &pk[0], sk0) == 1); - CHECK(create_keypair_and_pk(&keypair[1], &pk[1], sk1) == 1); - rustsecp256k1zkp_v0_8_0_testrand256(msg); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(ctx, &secnonce[0], &pubnonce[0], session_id[0], sk0, &pk[0], NULL, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(ctx, &secnonce[1], &pubnonce[1], session_id[1], sk1, &pk[1], NULL, NULL, NULL) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(ctx, &session, &aggnonce, msg, keyagg_cache, NULL) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(ctx, &partial_sig[0], &secnonce[0], &keypair[0], keyagg_cache, &session) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(ctx, &partial_sig[1], &secnonce[1], &keypair[1], keyagg_cache, &session) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(ctx, &partial_sig[0], &pubnonce[0], &pk[0], keyagg_cache, &session) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(ctx, &partial_sig[1], &pubnonce[1], &pk[1], keyagg_cache, &session) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(ctx, final_sig, &session, partial_sig_ptr, 2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, final_sig, msg, sizeof(msg), agg_pk) == 1); -} - -/* Create aggregate public key P[0], tweak multiple times (using xonly and - * plain tweaking) and test signing. */ -void musig_tweak_test(rustsecp256k1zkp_v0_8_0_scratch_space *scratch) { - unsigned char sk[2][32]; - rustsecp256k1zkp_v0_8_0_pubkey pk[2]; - const rustsecp256k1zkp_v0_8_0_pubkey *pk_ptr[2]; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache; - enum { N_TWEAKS = 8 }; - rustsecp256k1zkp_v0_8_0_pubkey P[N_TWEAKS + 1]; - rustsecp256k1zkp_v0_8_0_xonly_pubkey P_xonly[N_TWEAKS + 1]; - int i; - - /* Key Setup */ - for (i = 0; i < 2; i++) { - pk_ptr[i] = &pk[i]; - rustsecp256k1zkp_v0_8_0_testrand256(sk[i]); - CHECK(create_keypair_and_pk(NULL, &pk[i], sk[i]) == 1); - } - /* Compute P0 = keyagg(pk0, pk1) and test signing for it */ - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(ctx, scratch, &P_xonly[0], &keyagg_cache, pk_ptr, 2) == 1); - musig_tweak_test_helper(&P_xonly[0], sk[0], sk[1], &keyagg_cache); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_get(ctx, &P[0], &keyagg_cache)); - - /* Compute Pi = f(Pj) + tweaki*G where where j = i-1 and try signing for - * that key. If xonly is set to true, the function f is normalizes the input - * point to have an even X-coordinate ("xonly-tweaking"). - * Otherwise, the function f is the identity function. */ - for (i = 1; i <= N_TWEAKS; i++) { - unsigned char tweak[32]; - int P_parity; - int xonly = rustsecp256k1zkp_v0_8_0_testrand_bits(1); - - rustsecp256k1zkp_v0_8_0_testrand256(tweak); - if (xonly) { - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_xonly_tweak_add(ctx, &P[i], &keyagg_cache, tweak) == 1); - } else { - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_ec_tweak_add(ctx, &P[i], &keyagg_cache, tweak) == 1); - } - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(ctx, &P_xonly[i], &P_parity, &P[i])); - /* Check that musig_pubkey_tweak_add produces same result as - * xonly_pubkey_tweak_add or ec_pubkey_tweak_add. */ - if (xonly) { - unsigned char P_serialized[32]; - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, P_serialized, &P_xonly[i])); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(ctx, P_serialized, P_parity, &P_xonly[i-1], tweak) == 1); - } else { - rustsecp256k1zkp_v0_8_0_pubkey tmp_key = P[i-1]; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(ctx, &tmp_key, tweak)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&tmp_key, &P[i], sizeof(tmp_key)) == 0); - } - /* Test signing for P[i] */ - musig_tweak_test_helper(&P_xonly[i], sk[0], sk[1], &keyagg_cache); - } -} - -int musig_vectors_keyagg_and_tweak(enum MUSIG_ERROR *error, - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache, - unsigned char *agg_pk_ser, - const unsigned char pubkeys33[][33], - const unsigned char tweaks32[][32], - size_t key_indices_len, - const size_t *key_indices, - size_t tweak_indices_len, - const size_t *tweak_indices, - const int *is_xonly) { - rustsecp256k1zkp_v0_8_0_pubkey pubkeys[MUSIG_VECTORS_MAX_PUBKEYS]; - const rustsecp256k1zkp_v0_8_0_pubkey *pk_ptr[MUSIG_VECTORS_MAX_PUBKEYS]; - int i; - rustsecp256k1zkp_v0_8_0_pubkey agg_pk; - rustsecp256k1zkp_v0_8_0_xonly_pubkey agg_pk_xonly; - - for (i = 0; i < (int)key_indices_len; i++) { - if (!rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkeys[i], pubkeys33[key_indices[i]], 33)) { - *error = MUSIG_PUBKEY; - return 0; - } - pk_ptr[i] = &pubkeys[i]; - } - if (!rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(ctx, NULL, NULL, keyagg_cache, pk_ptr, key_indices_len)) { - *error = MUSIG_OTHER; - return 0; - } - - for (i = 0; i < (int)tweak_indices_len; i++) { - if (is_xonly[i]) { - if (!rustsecp256k1zkp_v0_8_0_musig_pubkey_xonly_tweak_add(ctx, NULL, keyagg_cache, tweaks32[tweak_indices[i]])) { - *error = MUSIG_TWEAK; - return 0; - } - } else { - if (!rustsecp256k1zkp_v0_8_0_musig_pubkey_ec_tweak_add(ctx, NULL, keyagg_cache, tweaks32[tweak_indices[i]])) { - *error = MUSIG_TWEAK; - return 0; - } - } - } - if (!rustsecp256k1zkp_v0_8_0_musig_pubkey_get(ctx, &agg_pk, keyagg_cache)) { - *error = MUSIG_OTHER; - return 0; - } - - if (!rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey(ctx, &agg_pk_xonly, NULL, &agg_pk)) { - *error = MUSIG_OTHER; - return 0; - } - - if (agg_pk_ser != NULL) { - if (!rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, agg_pk_ser, &agg_pk_xonly)) { - *error = MUSIG_OTHER; - return 0; - } - } - - return 1; -} - -void musig_test_vectors_keyagg(void) { - size_t i; - const struct musig_key_agg_vector *vector = &musig_key_agg_vector; - - for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { - const struct musig_key_agg_valid_test_case *c = &vector->valid_case[i]; - enum MUSIG_ERROR error; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache; - unsigned char agg_pk[32]; - - CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, 0, NULL, NULL)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(agg_pk, c->expected, sizeof(agg_pk)) == 0); - } - - for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { - const struct musig_key_agg_error_test_case *c = &vector->error_case[i]; - enum MUSIG_ERROR error; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache; - - CHECK(!musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); - CHECK(c->error == error); - } -} - -void musig_test_vectors_noncegen(void) { - size_t i; - const struct musig_nonce_gen_vector *vector = &musig_nonce_gen_vector; - - for (i = 0; i < sizeof(vector->test_case)/sizeof(vector->test_case[0]); i++) { - const struct musig_nonce_gen_test_case *c = &vector->test_case[i]; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache *keyagg_cache_ptr = NULL; - rustsecp256k1zkp_v0_8_0_musig_secnonce secnonce; - rustsecp256k1zkp_v0_8_0_musig_pubnonce pubnonce; - const unsigned char *sk = NULL; - const unsigned char *msg = NULL; - const unsigned char *extra_in = NULL; - rustsecp256k1zkp_v0_8_0_pubkey pk; - unsigned char pubnonce66[66]; - - if (c->has_sk) { - sk = c->sk; - } - if (c->has_aggpk) { - /* Create keyagg_cache from aggpk */ - rustsecp256k1zkp_v0_8_0_keyagg_cache_internal cache_i; - rustsecp256k1zkp_v0_8_0_xonly_pubkey aggpk; - memset(&cache_i, 0, sizeof(cache_i)); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(ctx, &aggpk, c->aggpk)); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_load(ctx, &cache_i.pk, &aggpk)); - rustsecp256k1zkp_v0_8_0_keyagg_cache_save(&keyagg_cache, &cache_i); - keyagg_cache_ptr = &keyagg_cache; - } - if (c->has_msg) { - msg = c->msg; - } - if (c->has_extra_in) { - extra_in = c->extra_in; - } - - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pk, c->pk, sizeof(c->pk))); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_gen(ctx, &secnonce, &pubnonce, c->rand_, sk, &pk, msg, keyagg_cache_ptr, extra_in) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&secnonce.data[4], c->expected_secnonce, 2*32) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&secnonce.data[4+2*32], &pk, sizeof(pk)) == 0); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_serialize(ctx, pubnonce66, &pubnonce) == 1); - CHECK(sizeof(c->expected_pubnonce) == sizeof(pubnonce66)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(pubnonce66, c->expected_pubnonce, sizeof(pubnonce66)) == 0); - } -} - - -void musig_test_vectors_nonceagg(void) { - size_t i; - int j; - const struct musig_nonce_agg_vector *vector = &musig_nonce_agg_vector; - - for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { - const struct musig_nonce_agg_test_case *c = &vector->valid_case[i]; - rustsecp256k1zkp_v0_8_0_musig_pubnonce pubnonce[2]; - const rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonce_ptr[2]; - rustsecp256k1zkp_v0_8_0_musig_aggnonce aggnonce; - unsigned char aggnonce66[66]; - - for (j = 0; j < 2; j++) { - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse(ctx, &pubnonce[j], vector->pnonces[c->pnonce_indices[j]]) == 1); - pubnonce_ptr[j] = &pubnonce[j]; - } - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 2)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_serialize(ctx, aggnonce66, &aggnonce)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(aggnonce66, c->expected, 33) == 0); - } - for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { - const struct musig_nonce_agg_test_case *c = &vector->error_case[i]; - rustsecp256k1zkp_v0_8_0_musig_pubnonce pubnonce[2]; - for (j = 0; j < 2; j++) { - int expected = c->invalid_nonce_idx != j; - CHECK(expected == rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse(ctx, &pubnonce[j], vector->pnonces[c->pnonce_indices[j]])); - } - } -} - -void musig_test_set_secnonce(rustsecp256k1zkp_v0_8_0_musig_secnonce *secnonce, const unsigned char *secnonce64, const rustsecp256k1zkp_v0_8_0_pubkey *pubkey) { - rustsecp256k1zkp_v0_8_0_ge pk; - rustsecp256k1zkp_v0_8_0_scalar k[2]; - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&k[0], &secnonce64[0], NULL); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&k[1], &secnonce64[32], NULL); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &pk, pubkey)); - rustsecp256k1zkp_v0_8_0_musig_secnonce_save(secnonce, k, &pk); -} - -void musig_test_vectors_signverify(void) { - size_t i; - const struct musig_sign_verify_vector *vector = &musig_sign_verify_vector; - - for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { - const struct musig_valid_case *c = &vector->valid_case[i]; - enum MUSIG_ERROR error; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_musig_pubnonce pubnonce; - rustsecp256k1zkp_v0_8_0_musig_aggnonce aggnonce; - rustsecp256k1zkp_v0_8_0_musig_session session; - rustsecp256k1zkp_v0_8_0_musig_partial_sig partial_sig; - rustsecp256k1zkp_v0_8_0_musig_secnonce secnonce; - rustsecp256k1zkp_v0_8_0_keypair keypair; - unsigned char partial_sig32[32]; - - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, vector->sk)); - CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_parse(ctx, &aggnonce, vector->aggnonces[c->aggnonce_index])); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(ctx, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache, NULL)); - - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); - musig_test_set_secnonce(&secnonce, vector->secnonces[0], &pubkey); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_serialize(ctx, partial_sig32, &partial_sig)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(partial_sig32, c->expected, sizeof(partial_sig32)) == 0); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse(ctx, &pubnonce, vector->pubnonces[0])); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(ctx, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session)); - } - for (i = 0; i < sizeof(vector->sign_error_case)/sizeof(vector->sign_error_case[0]); i++) { - const struct musig_sign_error_case *c = &vector->sign_error_case[i]; - enum MUSIG_ERROR error; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_musig_aggnonce aggnonce; - rustsecp256k1zkp_v0_8_0_musig_session session; - rustsecp256k1zkp_v0_8_0_musig_partial_sig partial_sig; - rustsecp256k1zkp_v0_8_0_musig_secnonce secnonce; - rustsecp256k1zkp_v0_8_0_keypair keypair; - int expected; - - if (i == 0) { - /* Skip this vector since the implementation does not error out when - * the signing key does not belong to any pubkey. */ - continue; - } - expected = c->error != MUSIG_PUBKEY; - CHECK(expected == musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); - CHECK(expected || c->error == error); - if (!expected) { - continue; - } - - expected = c->error != MUSIG_AGGNONCE; - CHECK(expected == rustsecp256k1zkp_v0_8_0_musig_aggnonce_parse(ctx, &aggnonce, vector->aggnonces[c->aggnonce_index])); - if (!expected) { - continue; - } - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(ctx, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache, NULL)); - - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); - musig_test_set_secnonce(&secnonce, vector->secnonces[c->secnonce_index], &pubkey); - { - /* In the last test vector we sign with an invalid secnonce, which - * triggers an illegal_callback. Hence, we need to use a custom - * context that does not abort in this case. */ - rustsecp256k1zkp_v0_8_0_context *ctx_tmp = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); - int32_t ecount = 0; - rustsecp256k1zkp_v0_8_0_context_set_error_callback(ctx_tmp, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(ctx_tmp, counting_illegal_callback_fn, &ecount); - expected = c->error != MUSIG_SECNONCE; - CHECK(expected == rustsecp256k1zkp_v0_8_0_musig_partial_sign(ctx_tmp, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); - CHECK((!expected) == ecount); - rustsecp256k1zkp_v0_8_0_context_destroy(ctx_tmp); - } - } - for (i = 0; i < sizeof(vector->verify_fail_case)/sizeof(vector->verify_fail_case[0]); i++) { - const struct musig_verify_fail_error_case *c = &vector->verify_fail_case[i]; - enum MUSIG_ERROR error; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache; - rustsecp256k1zkp_v0_8_0_musig_aggnonce aggnonce; - rustsecp256k1zkp_v0_8_0_musig_session session; - rustsecp256k1zkp_v0_8_0_musig_partial_sig partial_sig; - enum { NUM_PUBNONCES = 3 }; - rustsecp256k1zkp_v0_8_0_musig_pubnonce pubnonce[NUM_PUBNONCES]; - const rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonce_ptr[NUM_PUBNONCES]; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - int expected; - size_t j; - - CHECK(NUM_PUBNONCES <= c->nonce_indices_len); - for (j = 0; j < c->nonce_indices_len; j++) { - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse(ctx, &pubnonce[j], vector->pubnonces[c->nonce_indices[j]])); - pubnonce_ptr[j] = &pubnonce[j]; - } - - CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, c->nonce_indices_len) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(ctx, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache, NULL)); - - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, vector->pubkeys[c->signer_index], sizeof(vector->pubkeys[0]))); - - expected = c->error != MUSIG_SIG; - CHECK(expected == rustsecp256k1zkp_v0_8_0_musig_partial_sig_parse(ctx, &partial_sig, c->sig)); - if (!expected) { - continue; - } - expected = c->error != MUSIG_SIG_VERIFY; - CHECK(expected == rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(ctx, &partial_sig, pubnonce, &pubkey, &keyagg_cache, &session)); - } - for (i = 0; i < sizeof(vector->verify_error_case)/sizeof(vector->verify_error_case[0]); i++) { - const struct musig_verify_fail_error_case *c = &vector->verify_error_case[i]; - enum MUSIG_ERROR error; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache; - rustsecp256k1zkp_v0_8_0_musig_pubnonce pubnonce; - int expected; - - expected = c->error != MUSIG_PUBKEY; - CHECK(expected == musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); - CHECK(expected || c->error == error); - if (!expected) { - continue; - } - expected = c->error != MUSIG_PUBNONCE; - CHECK(expected == rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse(ctx, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]])); - } -} - -void musig_test_vectors_tweak(void) { - size_t i; - const struct musig_tweak_vector *vector = &musig_tweak_vector; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_musig_aggnonce aggnonce; - rustsecp256k1zkp_v0_8_0_musig_secnonce secnonce; - - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_parse(ctx, &aggnonce, vector->aggnonce)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); - - for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { - const struct musig_tweak_case *c = &vector->valid_case[i]; - enum MUSIG_ERROR error; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache; - rustsecp256k1zkp_v0_8_0_musig_pubnonce pubnonce; - rustsecp256k1zkp_v0_8_0_musig_session session; - rustsecp256k1zkp_v0_8_0_musig_partial_sig partial_sig; - rustsecp256k1zkp_v0_8_0_keypair keypair; - unsigned char partial_sig32[32]; - - musig_test_set_secnonce(&secnonce, vector->secnonce, &pubkey); - - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, vector->sk)); - CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(ctx, &session, &aggnonce, vector->msg, &keyagg_cache, NULL)); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_serialize(ctx, partial_sig32, &partial_sig)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(partial_sig32, c->expected, sizeof(partial_sig32)) == 0); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse(ctx, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]])); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify(ctx, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session)); - } - for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { - const struct musig_tweak_case *c = &vector->error_case[i]; - enum MUSIG_ERROR error; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache; - CHECK(!musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); - CHECK(error == MUSIG_TWEAK); - } -} - -void musig_test_vectors_sigagg(void) { - size_t i, j; - const struct musig_sig_agg_vector *vector = &musig_sig_agg_vector; - - for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { - const struct musig_sig_agg_case *c = &vector->valid_case[i]; - enum MUSIG_ERROR error; - unsigned char final_sig[64]; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache keyagg_cache; - unsigned char agg_pk32[32]; - rustsecp256k1zkp_v0_8_0_xonly_pubkey agg_pk; - rustsecp256k1zkp_v0_8_0_musig_aggnonce aggnonce; - rustsecp256k1zkp_v0_8_0_musig_session session; - rustsecp256k1zkp_v0_8_0_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; - const rustsecp256k1zkp_v0_8_0_musig_partial_sig *partial_sig_ptr[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; - - CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk32, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_aggnonce_parse(ctx, &aggnonce, c->aggnonce)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(ctx, &session, &aggnonce, vector->msg, &keyagg_cache, NULL)); - for (j = 0; j < c->psig_indices_len; j++) { - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_parse(ctx, &partial_sig[j], vector->psigs[c->psig_indices[j]])); - partial_sig_ptr[j] = &partial_sig[j]; - } - - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(ctx, final_sig, &session, partial_sig_ptr, c->psig_indices_len) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(final_sig, c->expected, sizeof(final_sig)) == 0); - - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(ctx, &agg_pk, agg_pk32)); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, final_sig, vector->msg, sizeof(vector->msg), &agg_pk) == 1); - } - for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { - const struct musig_sig_agg_case *c = &vector->error_case[i]; - rustsecp256k1zkp_v0_8_0_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; - for (j = 0; j < c->psig_indices_len; j++) { - int expected = c->invalid_sig_idx != (int)j; - CHECK(expected == rustsecp256k1zkp_v0_8_0_musig_partial_sig_parse(ctx, &partial_sig[j], vector->psigs[c->psig_indices[j]])); - } - } -} - -void run_musig_tests(void) { - int i; - rustsecp256k1zkp_v0_8_0_scratch_space *scratch = rustsecp256k1zkp_v0_8_0_scratch_space_create(ctx, 1024 * 1024); - - for (i = 0; i < count; i++) { - musig_simple_test(scratch); - } - musig_api_tests(scratch); - musig_nonce_test(); - for (i = 0; i < count; i++) { - /* Run multiple times to ensure that pk and nonce have different y - * parities */ - scriptless_atomic_swap(scratch); - musig_tweak_test(scratch); - } - sha256_tag_test(); - musig_test_vectors_keyagg(); - musig_test_vectors_noncegen(); - musig_test_vectors_nonceagg(); - musig_test_vectors_signverify(); - musig_test_vectors_tweak(); - musig_test_vectors_sigagg(); - - rustsecp256k1zkp_v0_8_0_scratch_space_destroy(ctx, scratch); -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/Makefile.am.include b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/Makefile.am.include deleted file mode 100644 index 88892505..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/Makefile.am.include +++ /dev/null @@ -1,13 +0,0 @@ -include_HEADERS += include/rustsecp256k1zkp_v0_8_0_rangeproof.h -noinst_HEADERS += src/modules/rangeproof/main_impl.h -noinst_HEADERS += src/modules/rangeproof/borromean.h -noinst_HEADERS += src/modules/rangeproof/borromean_impl.h -noinst_HEADERS += src/modules/rangeproof/rangeproof.h -noinst_HEADERS += src/modules/rangeproof/rangeproof_impl.h -noinst_HEADERS += src/modules/rangeproof/tests_impl.h -if USE_BENCHMARK -noinst_PROGRAMS += bench_rangeproof -bench_rangeproof_SOURCES = src/bench_rangeproof.c -bench_rangeproof_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_rangeproof_LDFLAGS = -static -endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/borromean.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/borromean.h deleted file mode 100644 index df17168d..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/borromean.h +++ /dev/null @@ -1,24 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014, 2015 Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - - -#ifndef _SECP256K1_BORROMEAN_H_ -#define _SECP256K1_BORROMEAN_H_ - -#include "../../scalar.h" -#include "../../field.h" -#include "../../group.h" -#include "../../ecmult.h" -#include "../../ecmult_gen.h" - -int rustsecp256k1zkp_v0_8_0_borromean_verify(rustsecp256k1zkp_v0_8_0_scalar *evalues, const unsigned char *e0, const rustsecp256k1zkp_v0_8_0_scalar *s, - const rustsecp256k1zkp_v0_8_0_gej *pubs, const size_t *rsizes, size_t nrings, const unsigned char *m, size_t mlen); - -int rustsecp256k1zkp_v0_8_0_borromean_sign(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context *ecmult_gen_ctx, - unsigned char *e0, rustsecp256k1zkp_v0_8_0_scalar *s, const rustsecp256k1zkp_v0_8_0_gej *pubs, const rustsecp256k1zkp_v0_8_0_scalar *k, const rustsecp256k1zkp_v0_8_0_scalar *sec, - const size_t *rsizes, const size_t *secidx, size_t nrings, const unsigned char *m, size_t mlen); - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/borromean_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/borromean_impl.h deleted file mode 100644 index 1217646c..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/borromean_impl.h +++ /dev/null @@ -1,202 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014, 2015 Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - - -#ifndef _SECP256K1_BORROMEAN_IMPL_H_ -#define _SECP256K1_BORROMEAN_IMPL_H_ - -#include "../../scalar.h" -#include "../../field.h" -#include "../../group.h" -#include "../../hash.h" -#include "../../eckey.h" -#include "../../ecmult.h" -#include "../../ecmult_gen.h" -#include "borromean.h" - -#include -#include - -#if defined(SECP256K1_BIG_ENDIAN) -#define BE32(x) (x) -#elif defined(SECP256K1_LITTLE_ENDIAN) -#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) -#endif - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_borromean_hash(unsigned char *hash, const unsigned char *m, size_t mlen, const unsigned char *e, size_t elen, - size_t ridx, size_t eidx) { - uint32_t ring; - uint32_t epos; - rustsecp256k1zkp_v0_8_0_sha256 sha256_en; - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha256_en); - ring = BE32((uint32_t)ridx); - epos = BE32((uint32_t)eidx); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_en, e, elen); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_en, m, mlen); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_en, (unsigned char*)&ring, 4); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_en, (unsigned char*)&epos, 4); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha256_en, hash); -} - -/** "Borromean" ring signature. - * Verifies nrings concurrent ring signatures all sharing a challenge value. - * Signature is one s value per pubkey and a hash. - * Verification equation: - * | m = H(P_{0..}||message) (Message must contain pubkeys or a pubkey commitment) - * | For each ring i: - * | | en = to_scalar(H(e0||m||i||0)) - * | | For each pubkey j: - * | | | r = s_i_j G + en * P_i_j - * | | | e = H(r||m||i||j) - * | | | en = to_scalar(e) - * | | r_i = r - * | return e_0 ==== H(r_{0..i}||m) - */ -int rustsecp256k1zkp_v0_8_0_borromean_verify(rustsecp256k1zkp_v0_8_0_scalar *evalues, const unsigned char *e0, - const rustsecp256k1zkp_v0_8_0_scalar *s, const rustsecp256k1zkp_v0_8_0_gej *pubs, const size_t *rsizes, size_t nrings, const unsigned char *m, size_t mlen) { - rustsecp256k1zkp_v0_8_0_gej rgej; - rustsecp256k1zkp_v0_8_0_ge rge; - rustsecp256k1zkp_v0_8_0_scalar ens; - rustsecp256k1zkp_v0_8_0_sha256 sha256_e0; - unsigned char tmp[33]; - size_t i; - size_t j; - size_t count; - size_t size; - int overflow; - VERIFY_CHECK(e0 != NULL); - VERIFY_CHECK(s != NULL); - VERIFY_CHECK(pubs != NULL); - VERIFY_CHECK(rsizes != NULL); - VERIFY_CHECK(nrings > 0); - VERIFY_CHECK(m != NULL); - count = 0; - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha256_e0); - for (i = 0; i < nrings; i++) { - VERIFY_CHECK(INT_MAX - count > rsizes[i]); - rustsecp256k1zkp_v0_8_0_borromean_hash(tmp, m, mlen, e0, 32, i, 0); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&ens, tmp, &overflow); - for (j = 0; j < rsizes[i]; j++) { - if (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(&s[count]) || rustsecp256k1zkp_v0_8_0_scalar_is_zero(&ens) || rustsecp256k1zkp_v0_8_0_gej_is_infinity(&pubs[count])) { - return 0; - } - if (evalues) { - /*If requested, save the challenges for proof rewind.*/ - evalues[count] = ens; - } - rustsecp256k1zkp_v0_8_0_ecmult(&rgej, &pubs[count], &ens, &s[count]); - if (rustsecp256k1zkp_v0_8_0_gej_is_infinity(&rgej)) { - return 0; - } - /* OPT: loop can be hoisted and split to use batch inversion across all the rings; this would make it much faster. */ - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&rge, &rgej); - rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&rge, tmp, &size, 1); - if (j != rsizes[i] - 1) { - rustsecp256k1zkp_v0_8_0_borromean_hash(tmp, m, mlen, tmp, 33, i, j + 1); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&ens, tmp, &overflow); - } else { - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_e0, tmp, size); - } - count++; - } - } - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_e0, m, mlen); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha256_e0, tmp); - return rustsecp256k1zkp_v0_8_0_memcmp_var(e0, tmp, 32) == 0; -} - -int rustsecp256k1zkp_v0_8_0_borromean_sign(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context *ecmult_gen_ctx, - unsigned char *e0, rustsecp256k1zkp_v0_8_0_scalar *s, const rustsecp256k1zkp_v0_8_0_gej *pubs, const rustsecp256k1zkp_v0_8_0_scalar *k, const rustsecp256k1zkp_v0_8_0_scalar *sec, - const size_t *rsizes, const size_t *secidx, size_t nrings, const unsigned char *m, size_t mlen) { - rustsecp256k1zkp_v0_8_0_gej rgej; - rustsecp256k1zkp_v0_8_0_ge rge; - rustsecp256k1zkp_v0_8_0_scalar ens; - rustsecp256k1zkp_v0_8_0_sha256 sha256_e0; - unsigned char tmp[33]; - size_t i; - size_t j; - size_t count; - size_t size; - int overflow; - VERIFY_CHECK(ecmult_gen_ctx != NULL); - VERIFY_CHECK(e0 != NULL); - VERIFY_CHECK(s != NULL); - VERIFY_CHECK(pubs != NULL); - VERIFY_CHECK(k != NULL); - VERIFY_CHECK(sec != NULL); - VERIFY_CHECK(rsizes != NULL); - VERIFY_CHECK(secidx != NULL); - VERIFY_CHECK(nrings > 0); - VERIFY_CHECK(m != NULL); - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha256_e0); - count = 0; - for (i = 0; i < nrings; i++) { - VERIFY_CHECK(INT_MAX - count > rsizes[i]); - rustsecp256k1zkp_v0_8_0_ecmult_gen(ecmult_gen_ctx, &rgej, &k[i]); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&rge, &rgej); - if (rustsecp256k1zkp_v0_8_0_gej_is_infinity(&rgej)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&rge, tmp, &size, 1); - for (j = secidx[i] + 1; j < rsizes[i]; j++) { - rustsecp256k1zkp_v0_8_0_borromean_hash(tmp, m, mlen, tmp, 33, i, j); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&ens, tmp, &overflow); - if (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(&ens)) { - return 0; - } - /** The signing algorithm as a whole is not memory uniform so there is likely a cache sidechannel that - * leaks which members are non-forgeries. That the forgeries themselves are variable time may leave - * an additional privacy impacting timing side-channel, but not a key loss one. - */ - rustsecp256k1zkp_v0_8_0_ecmult(&rgej, &pubs[count + j], &ens, &s[count + j]); - if (rustsecp256k1zkp_v0_8_0_gej_is_infinity(&rgej)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&rge, &rgej); - rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&rge, tmp, &size, 1); - } - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_e0, tmp, size); - count += rsizes[i]; - } - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_e0, m, mlen); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha256_e0, e0); - count = 0; - for (i = 0; i < nrings; i++) { - VERIFY_CHECK(INT_MAX - count > rsizes[i]); - rustsecp256k1zkp_v0_8_0_borromean_hash(tmp, m, mlen, e0, 32, i, 0); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&ens, tmp, &overflow); - if (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(&ens)) { - return 0; - } - for (j = 0; j < secidx[i]; j++) { - rustsecp256k1zkp_v0_8_0_ecmult(&rgej, &pubs[count + j], &ens, &s[count + j]); - if (rustsecp256k1zkp_v0_8_0_gej_is_infinity(&rgej)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&rge, &rgej); - rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&rge, tmp, &size, 1); - rustsecp256k1zkp_v0_8_0_borromean_hash(tmp, m, mlen, tmp, 33, i, j + 1); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&ens, tmp, &overflow); - if (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(&ens)) { - return 0; - } - } - rustsecp256k1zkp_v0_8_0_scalar_mul(&s[count + j], &ens, &sec[i]); - rustsecp256k1zkp_v0_8_0_scalar_negate(&s[count + j], &s[count + j]); - rustsecp256k1zkp_v0_8_0_scalar_add(&s[count + j], &s[count + j], &k[i]); - if (rustsecp256k1zkp_v0_8_0_scalar_is_zero(&s[count + j])) { - return 0; - } - count += rsizes[i]; - } - rustsecp256k1zkp_v0_8_0_scalar_clear(&ens); - rustsecp256k1zkp_v0_8_0_ge_clear(&rge); - rustsecp256k1zkp_v0_8_0_gej_clear(&rgej); - memset(tmp, 0, 33); - return 1; -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/main_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/main_impl.h deleted file mode 100644 index c9de5cd4..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/main_impl.h +++ /dev/null @@ -1,103 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014-2015 Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_RANGEPROOF_MAIN -#define SECP256K1_MODULE_RANGEPROOF_MAIN - -#include "../../group.h" - -#include "modules/generator/main_impl.h" -#include "modules/rangeproof/borromean_impl.h" -#include "modules/rangeproof/rangeproof_impl.h" - -int rustsecp256k1zkp_v0_8_0_rangeproof_info(const rustsecp256k1zkp_v0_8_0_context* ctx, int *exp, int *mantissa, - uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, size_t plen) { - size_t offset; - uint64_t scale; - ARG_CHECK(exp != NULL); - ARG_CHECK(mantissa != NULL); - ARG_CHECK(min_value != NULL); - ARG_CHECK(max_value != NULL); - ARG_CHECK(proof != NULL); - offset = 0; - scale = 1; - (void)ctx; - return rustsecp256k1zkp_v0_8_0_rangeproof_getheader_impl(&offset, exp, mantissa, &scale, min_value, max_value, proof, plen); -} - -int rustsecp256k1zkp_v0_8_0_rangeproof_rewind(const rustsecp256k1zkp_v0_8_0_context* ctx, - unsigned char *blind_out, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce, - uint64_t *min_value, uint64_t *max_value, - const rustsecp256k1zkp_v0_8_0_pedersen_commitment *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const rustsecp256k1zkp_v0_8_0_generator* gen) { - rustsecp256k1zkp_v0_8_0_ge commitp; - rustsecp256k1zkp_v0_8_0_ge genp; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(commit != NULL); - ARG_CHECK(proof != NULL); - ARG_CHECK(min_value != NULL); - ARG_CHECK(max_value != NULL); - ARG_CHECK(message_out != NULL || outlen == NULL); - ARG_CHECK(nonce != NULL); - ARG_CHECK(extra_commit != NULL || extra_commit_len == 0); - ARG_CHECK(gen != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - rustsecp256k1zkp_v0_8_0_pedersen_commitment_load(&commitp, commit); - rustsecp256k1zkp_v0_8_0_generator_load(&genp, gen); - return rustsecp256k1zkp_v0_8_0_rangeproof_verify_impl(&ctx->ecmult_gen_ctx, - blind_out, value_out, message_out, outlen, nonce, min_value, max_value, &commitp, proof, plen, extra_commit, extra_commit_len, &genp); -} - -int rustsecp256k1zkp_v0_8_0_rangeproof_verify(const rustsecp256k1zkp_v0_8_0_context* ctx, uint64_t *min_value, uint64_t *max_value, - const rustsecp256k1zkp_v0_8_0_pedersen_commitment *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const rustsecp256k1zkp_v0_8_0_generator* gen) { - rustsecp256k1zkp_v0_8_0_ge commitp; - rustsecp256k1zkp_v0_8_0_ge genp; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(commit != NULL); - ARG_CHECK(proof != NULL); - ARG_CHECK(min_value != NULL); - ARG_CHECK(max_value != NULL); - ARG_CHECK(extra_commit != NULL || extra_commit_len == 0); - ARG_CHECK(gen != NULL); - rustsecp256k1zkp_v0_8_0_pedersen_commitment_load(&commitp, commit); - rustsecp256k1zkp_v0_8_0_generator_load(&genp, gen); - return rustsecp256k1zkp_v0_8_0_rangeproof_verify_impl(NULL, - NULL, NULL, NULL, NULL, NULL, min_value, max_value, &commitp, proof, plen, extra_commit, extra_commit_len, &genp); -} - -int rustsecp256k1zkp_v0_8_0_rangeproof_sign(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *proof, size_t *plen, uint64_t min_value, - const rustsecp256k1zkp_v0_8_0_pedersen_commitment *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value, - const unsigned char *message, size_t msg_len, const unsigned char *extra_commit, size_t extra_commit_len, const rustsecp256k1zkp_v0_8_0_generator* gen){ - rustsecp256k1zkp_v0_8_0_ge commitp; - rustsecp256k1zkp_v0_8_0_ge genp; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(proof != NULL); - ARG_CHECK(plen != NULL); - ARG_CHECK(commit != NULL); - ARG_CHECK(blind != NULL); - ARG_CHECK(nonce != NULL); - ARG_CHECK(message != NULL || msg_len == 0); - ARG_CHECK(extra_commit != NULL || extra_commit_len == 0); - ARG_CHECK(gen != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - rustsecp256k1zkp_v0_8_0_pedersen_commitment_load(&commitp, commit); - rustsecp256k1zkp_v0_8_0_generator_load(&genp, gen); - return rustsecp256k1zkp_v0_8_0_rangeproof_sign_impl(&ctx->ecmult_gen_ctx, - proof, plen, min_value, &commitp, blind, nonce, exp, min_bits, value, message, msg_len, extra_commit, extra_commit_len, &genp); -} - -size_t rustsecp256k1zkp_v0_8_0_rangeproof_max_size(const rustsecp256k1zkp_v0_8_0_context* ctx, uint64_t max_value, int min_bits) { - const int val_mantissa = max_value > 0 ? 64 - rustsecp256k1zkp_v0_8_0_clz64_var(max_value) : 1; - const int mantissa = min_bits > val_mantissa ? min_bits : val_mantissa; - const size_t rings = (mantissa + 1) / 2; - const size_t npubs = rings * 4 - 2 * (mantissa % 2); - - VERIFY_CHECK(ctx != NULL); - (void) ctx; - - return 10 + 32 * (npubs + rings - 1) + 32 + ((rings - 1 + 7) / 8); -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/rangeproof.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/rangeproof.h deleted file mode 100644 index 9f25442f..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/rangeproof.h +++ /dev/null @@ -1,20 +0,0 @@ -/********************************************************************** - * Copyright (c) 2015 Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_RANGEPROOF_H_ -#define _SECP256K1_RANGEPROOF_H_ - -#include "../../scalar.h" -#include "../../group.h" -#include "../../ecmult.h" -#include "../../ecmult_gen.h" - -static int rustsecp256k1zkp_v0_8_0_rangeproof_verify_impl(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context* ecmult_gen_ctx, - unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce, - uint64_t *min_value, uint64_t *max_value, const rustsecp256k1zkp_v0_8_0_ge *commit, const unsigned char *proof, size_t plen, - const unsigned char *extra_commit, size_t extra_commit_len, const rustsecp256k1zkp_v0_8_0_ge* genp); - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/rangeproof_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/rangeproof_impl.h deleted file mode 100644 index 5589e128..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/rangeproof_impl.h +++ /dev/null @@ -1,682 +0,0 @@ -/********************************************************************** - * Copyright (c) 2015 Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_RANGEPROOF_IMPL_H_ -#define _SECP256K1_RANGEPROOF_IMPL_H_ - -#include "../../eckey.h" -#include "../../scalar.h" -#include "../../group.h" -#include "../../hash_impl.h" -#include "../../util.h" - -#include "modules/generator/pedersen.h" -#include "modules/rangeproof/borromean.h" -#include "modules/rangeproof/rangeproof.h" - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_rangeproof_pub_expand(rustsecp256k1zkp_v0_8_0_gej *pubs, - int exp, size_t *rsizes, size_t rings, const rustsecp256k1zkp_v0_8_0_ge* genp) { - rustsecp256k1zkp_v0_8_0_gej base; - size_t i; - size_t j; - size_t npub; - VERIFY_CHECK(exp < 19); - if (exp < 0) { - exp = 0; - } - rustsecp256k1zkp_v0_8_0_gej_set_ge(&base, genp); - rustsecp256k1zkp_v0_8_0_gej_neg(&base, &base); - while (exp--) { - /* Multiplication by 10 */ - rustsecp256k1zkp_v0_8_0_gej tmp; - rustsecp256k1zkp_v0_8_0_gej_double_var(&tmp, &base, NULL); - rustsecp256k1zkp_v0_8_0_gej_double_var(&base, &tmp, NULL); - rustsecp256k1zkp_v0_8_0_gej_double_var(&base, &base, NULL); - rustsecp256k1zkp_v0_8_0_gej_add_var(&base, &base, &tmp, NULL); - } - npub = 0; - for (i = 0; i < rings; i++) { - for (j = 1; j < rsizes[i]; j++) { - rustsecp256k1zkp_v0_8_0_gej_add_var(&pubs[npub + j], &pubs[npub + j - 1], &base, NULL); - } - if (i < rings - 1) { - rustsecp256k1zkp_v0_8_0_gej_double_var(&base, &base, NULL); - rustsecp256k1zkp_v0_8_0_gej_double_var(&base, &base, NULL); - } - npub += rsizes[i]; - } -} - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_rangeproof_serialize_point(unsigned char* data, const rustsecp256k1zkp_v0_8_0_ge *point) { - rustsecp256k1zkp_v0_8_0_fe pointx; - pointx = point->x; - rustsecp256k1zkp_v0_8_0_fe_normalize(&pointx); - data[0] = !rustsecp256k1zkp_v0_8_0_fe_is_quad_var(&point->y); - rustsecp256k1zkp_v0_8_0_fe_get_b32(data + 1, &pointx); -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_rangeproof_genrand(rustsecp256k1zkp_v0_8_0_scalar *sec, rustsecp256k1zkp_v0_8_0_scalar *s, unsigned char *message, - size_t *rsizes, size_t rings, const unsigned char *nonce, const rustsecp256k1zkp_v0_8_0_ge *commit, const unsigned char *proof, size_t len, const rustsecp256k1zkp_v0_8_0_ge* genp) { - unsigned char tmp[32]; - unsigned char rngseed[32 + 33 + 33 + 10]; - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256 rng; - rustsecp256k1zkp_v0_8_0_scalar acc; - int overflow; - int ret; - size_t i; - size_t j; - int b; - size_t npub; - VERIFY_CHECK(len <= 10); - memcpy(rngseed, nonce, 32); - rustsecp256k1zkp_v0_8_0_rangeproof_serialize_point(rngseed + 32, commit); - rustsecp256k1zkp_v0_8_0_rangeproof_serialize_point(rngseed + 32 + 33, genp); - memcpy(rngseed + 33 + 33 + 32, proof, len); - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_initialize(&rng, rngseed, 32 + 33 + 33 + len); - rustsecp256k1zkp_v0_8_0_scalar_clear(&acc); - npub = 0; - ret = 1; - for (i = 0; i < rings; i++) { - if (i < rings - 1) { - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(&rng, tmp, 32); - do { - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(&rng, tmp, 32); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&sec[i], tmp, &overflow); - } while (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(&sec[i])); - rustsecp256k1zkp_v0_8_0_scalar_add(&acc, &acc, &sec[i]); - } else { - rustsecp256k1zkp_v0_8_0_scalar_negate(&acc, &acc); - sec[i] = acc; - } - for (j = 0; j < rsizes[i]; j++) { - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(&rng, tmp, 32); - if (message) { - for (b = 0; b < 32; b++) { - tmp[b] ^= message[(i * 4 + j) * 32 + b]; - message[(i * 4 + j) * 32 + b] = tmp[b]; - } - } - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&s[npub], tmp, &overflow); - ret &= !(overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(&s[npub])); - npub++; - } - } - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_finalize(&rng); - rustsecp256k1zkp_v0_8_0_scalar_clear(&acc); - memset(tmp, 0, 32); - return ret; -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_range_proveparams(uint64_t *v, size_t *rings, size_t *rsizes, size_t *npub, size_t *secidx, uint64_t *min_value, - int *mantissa, uint64_t *scale, int *exp, int *min_bits, uint64_t value) { - size_t i; - *rings = 1; - rsizes[0] = 1; - secidx[0] = 0; - *scale = 1; - *mantissa = 0; - *npub = 0; - if (*min_value == UINT64_MAX) { - /* If the minimum value is the maximal representable value, then we cannot code a range. */ - *exp = -1; - } - if (*exp >= 0) { - int max_bits; - uint64_t v2; - if ((*min_value && value > INT64_MAX) || (value && *min_value >= INT64_MAX)) { - /* If either value or min_value is >= 2^63-1 then the other must by zero to avoid overflowing the proven range. */ - return 0; - } - max_bits = *min_value ? rustsecp256k1zkp_v0_8_0_clz64_var(*min_value) : 64; - if (*min_bits > max_bits) { - *min_bits = max_bits; - } - if (*min_bits > 61 || value > INT64_MAX) { - /** Ten is not a power of two, so dividing by ten and then representing in base-2 times ten - * expands the representable range. The verifier requires the proven range is within 0..2**64. - * For very large numbers (all over 2**63) we must change our exponent to compensate. - * Rather than handling it precisely, this just disables use of the exponent for big values. - */ - *exp = 0; - } - /* Mask off the least significant digits, as requested. */ - *v = value - *min_value; - /* If the user has asked for more bits of proof then there is room for in the exponent, reduce the exponent. */ - v2 = *min_bits ? (UINT64_MAX>>(64-*min_bits)) : 0; - for (i = 0; (int) i < *exp && (v2 <= UINT64_MAX / 10); i++) { - *v /= 10; - v2 *= 10; - } - *exp = i; - v2 = *v; - for (i = 0; (int) i < *exp; i++) { - v2 *= 10; - *scale *= 10; - } - /* If the masked number isn't precise, compute the public offset. */ - *min_value = value - v2; - /* How many bits do we need to represent our value? */ - *mantissa = *v ? 64 - rustsecp256k1zkp_v0_8_0_clz64_var(*v) : 1; - if (*min_bits > *mantissa) { - /* If the user asked for more precision, give it to them. */ - *mantissa = *min_bits; - } - /* Digits in radix-4, except for the last digit if our mantissa length is odd. */ - *rings = (*mantissa + 1) >> 1; - for (i = 0; i < *rings; i++) { - rsizes[i] = ((i < *rings - 1) | (!(*mantissa&1))) ? 4 : 2; - *npub += rsizes[i]; - secidx[i] = (*v >> (i*2)) & 3; - } - VERIFY_CHECK(*mantissa>0); - VERIFY_CHECK((*v & ~(UINT64_MAX>>(64-*mantissa))) == 0); /* Did this get all the bits? */ - } else { - /* A proof for an exact value. */ - *exp = 0; - *min_value = value; - *v = 0; - *npub = 2; - } - VERIFY_CHECK(*v * *scale + *min_value == value); - VERIFY_CHECK(*rings > 0); - VERIFY_CHECK(*rings <= 32); - VERIFY_CHECK(*npub <= 128); - return 1; -} - -/* strawman interface, writes proof in proof, a buffer of plen, proves with respect to min_value the range for commit which has the provided blinding factor and value. */ -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_rangeproof_sign_impl(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context* ecmult_gen_ctx, - unsigned char *proof, size_t *plen, uint64_t min_value, - const rustsecp256k1zkp_v0_8_0_ge *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value, - const unsigned char *message, size_t msg_len, const unsigned char *extra_commit, size_t extra_commit_len, const rustsecp256k1zkp_v0_8_0_ge* genp){ - rustsecp256k1zkp_v0_8_0_gej pubs[128]; /* Candidate digits for our proof, most inferred. */ - rustsecp256k1zkp_v0_8_0_scalar s[128]; /* Signatures in our proof, most forged. */ - rustsecp256k1zkp_v0_8_0_scalar sec[32]; /* Blinding factors for the correct digits. */ - rustsecp256k1zkp_v0_8_0_scalar k[32]; /* Nonces for our non-forged signatures. */ - rustsecp256k1zkp_v0_8_0_scalar stmp; - rustsecp256k1zkp_v0_8_0_sha256 sha256_m; - unsigned char prep[4096]; - unsigned char tmp[33]; - unsigned char *signs; /* Location of sign flags in the proof. */ - uint64_t v; - uint64_t scale; /* scale = 10^exp. */ - int mantissa; /* Number of bits proven in the blinded value. */ - size_t rings; /* How many digits will our proof cover. */ - size_t rsizes[32]; /* How many possible values there are for each place. */ - size_t secidx[32]; /* Which digit is the correct one. */ - size_t len; /* Number of bytes used so far. */ - size_t i; - int overflow; - size_t npub; - len = 0; - if (*plen < 65 || min_value > value || min_bits > 64 || min_bits < 0 || exp < -1 || exp > 18) { - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_range_proveparams(&v, &rings, rsizes, &npub, secidx, &min_value, &mantissa, &scale, &exp, &min_bits, value)) { - return 0; - } - proof[len] = (rsizes[0] > 1 ? (64 | exp) : 0) | (min_value ? 32 : 0); - len++; - if (rsizes[0] > 1) { - VERIFY_CHECK(mantissa > 0 && mantissa <= 64); - proof[len] = mantissa - 1; - len++; - } - if (min_value) { - for (i = 0; i < 8; i++) { - proof[len + i] = (min_value >> ((7-i) * 8)) & 255; - } - len += 8; - } - /* Do we have enough room in the proof for the message? Each ring gives us 128 bytes, but the - * final ring is used to encode the blinding factor and the value, so we can't use that. (Well, - * technically there are 64 bytes available if we avoided the other data, but this is difficult - * because it's not always in the same place. */ - if (msg_len > 0 && msg_len > 128 * (rings - 1)) { - return 0; - } - /* Do we have enough room for the proof? */ - if (*plen - len < 32 * (npub + rings - 1) + 32 + ((rings+6) >> 3)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha256_m); - rustsecp256k1zkp_v0_8_0_rangeproof_serialize_point(tmp, commit); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_m, tmp, 33); - rustsecp256k1zkp_v0_8_0_rangeproof_serialize_point(tmp, genp); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_m, tmp, 33); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_m, proof, len); - - memset(prep, 0, 4096); - if (message != NULL) { - memcpy(prep, message, msg_len); - } - /* Note, the data corresponding to the blinding factors must be zero. */ - if (rsizes[rings - 1] > 1) { - size_t idx; - /* Value encoding sidechannel. */ - idx = rsizes[rings - 1] - 1; - idx -= secidx[rings - 1] == idx; - idx = ((rings - 1) * 4 + idx) * 32; - for (i = 0; i < 8; i++) { - prep[8 + i + idx] = prep[16 + i + idx] = prep[24 + i + idx] = (v >> (56 - i * 8)) & 255; - prep[i + idx] = 0; - } - prep[idx] = 128; - } - if (!rustsecp256k1zkp_v0_8_0_rangeproof_genrand(sec, s, prep, rsizes, rings, nonce, commit, proof, len, genp)) { - return 0; - } - memset(prep, 0, 4096); - for (i = 0; i < rings; i++) { - /* Sign will overwrite the non-forged signature, move that random value into the nonce. */ - k[i] = s[i * 4 + secidx[i]]; - rustsecp256k1zkp_v0_8_0_scalar_clear(&s[i * 4 + secidx[i]]); - } - /** Genrand returns the last blinding factor as -sum(rest), - * adding in the blinding factor for our commitment, results in the blinding factor for - * the commitment to the last digit that the verifier can compute for itself by subtracting - * all the digits in the proof from the commitment. This lets the prover skip sending the - * blinded value for one digit. - */ - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&stmp, blind, &overflow); - rustsecp256k1zkp_v0_8_0_scalar_add(&sec[rings - 1], &sec[rings - 1], &stmp); - if (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(&sec[rings - 1])) { - return 0; - } - signs = &proof[len]; - /* We need one sign bit for each blinded value we send. */ - for (i = 0; i < (rings + 6) >> 3; i++) { - signs[i] = 0; - len++; - } - npub = 0; - for (i = 0; i < rings; i++) { - /*OPT: Use the precomputed gen2 basis?*/ - rustsecp256k1zkp_v0_8_0_pedersen_ecmult(ecmult_gen_ctx, &pubs[npub], &sec[i], ((uint64_t)secidx[i] * scale) << (i*2), genp); - if (rustsecp256k1zkp_v0_8_0_gej_is_infinity(&pubs[npub])) { - return 0; - } - if (i < rings - 1) { - unsigned char tmpc[33]; - rustsecp256k1zkp_v0_8_0_ge c; - unsigned char quadness; - /*OPT: split loop and batch invert.*/ - /*OPT: do not compute full pubs[npub] in ge form; we only need x */ - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&c, &pubs[npub]); - rustsecp256k1zkp_v0_8_0_rangeproof_serialize_point(tmpc, &c); - quadness = tmpc[0]; - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_m, tmpc, 33); - signs[i>>3] |= quadness << (i&7); - memcpy(&proof[len], tmpc + 1, 32); - len += 32; - } - npub += rsizes[i]; - } - rustsecp256k1zkp_v0_8_0_rangeproof_pub_expand(pubs, exp, rsizes, rings, genp); - if (extra_commit != NULL) { - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_m, extra_commit, extra_commit_len); - } - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha256_m, tmp); - if (!rustsecp256k1zkp_v0_8_0_borromean_sign(ecmult_gen_ctx, &proof[len], s, pubs, k, sec, rsizes, secidx, rings, tmp, 32)) { - return 0; - } - len += 32; - for (i = 0; i < npub; i++) { - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&proof[len],&s[i]); - len += 32; - } - VERIFY_CHECK(len <= *plen); - *plen = len; - memset(prep, 0, 4096); - return 1; -} - -/* Computes blinding factor x given k, s, and the challenge e. */ -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_rangeproof_recover_x(rustsecp256k1zkp_v0_8_0_scalar *x, const rustsecp256k1zkp_v0_8_0_scalar *k, const rustsecp256k1zkp_v0_8_0_scalar *e, - const rustsecp256k1zkp_v0_8_0_scalar *s) { - rustsecp256k1zkp_v0_8_0_scalar stmp; - rustsecp256k1zkp_v0_8_0_scalar_negate(x, s); - rustsecp256k1zkp_v0_8_0_scalar_add(x, x, k); - rustsecp256k1zkp_v0_8_0_scalar_inverse(&stmp, e); - rustsecp256k1zkp_v0_8_0_scalar_mul(x, x, &stmp); -} - -/* Computes ring's nonce given the blinding factor x, the challenge e, and the signature s. */ -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_rangeproof_recover_k(rustsecp256k1zkp_v0_8_0_scalar *k, const rustsecp256k1zkp_v0_8_0_scalar *x, const rustsecp256k1zkp_v0_8_0_scalar *e, - const rustsecp256k1zkp_v0_8_0_scalar *s) { - rustsecp256k1zkp_v0_8_0_scalar stmp; - rustsecp256k1zkp_v0_8_0_scalar_mul(&stmp, x, e); - rustsecp256k1zkp_v0_8_0_scalar_add(k, s, &stmp); -} - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_rangeproof_ch32xor(unsigned char *x, const unsigned char *y) { - int i; - for (i = 0; i < 32; i++) { - x[i] ^= y[i]; - } -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_rangeproof_rewind_inner(rustsecp256k1zkp_v0_8_0_scalar *blind, uint64_t *v, - unsigned char *m, size_t *mlen, rustsecp256k1zkp_v0_8_0_scalar *ev, rustsecp256k1zkp_v0_8_0_scalar *s, - size_t *rsizes, size_t rings, const unsigned char *nonce, const rustsecp256k1zkp_v0_8_0_ge *commit, const unsigned char *proof, size_t len, const rustsecp256k1zkp_v0_8_0_ge *genp) { - rustsecp256k1zkp_v0_8_0_scalar s_orig[128]; - rustsecp256k1zkp_v0_8_0_scalar sec[32]; - rustsecp256k1zkp_v0_8_0_scalar stmp; - unsigned char prep[4096]; - unsigned char tmp[32]; - uint64_t value = 0; - size_t offset; - size_t i; - size_t j; - int b; - size_t skip1; - size_t skip2; - size_t npub; - npub = ((rings - 1) << 2) + rsizes[rings-1]; - VERIFY_CHECK(npub <= 128); - VERIFY_CHECK(npub >= 1); - memset(prep, 0, 4096); - /* Reconstruct the provers random values. */ - rustsecp256k1zkp_v0_8_0_rangeproof_genrand(sec, s_orig, prep, rsizes, rings, nonce, commit, proof, len, genp); - *v = UINT64_MAX; - rustsecp256k1zkp_v0_8_0_scalar_clear(blind); - if (rings == 1 && rsizes[0] == 1) { - /* With only a single proof, we can only recover the blinding factor. */ - rustsecp256k1zkp_v0_8_0_rangeproof_recover_x(blind, &s_orig[0], &ev[0], &s[0]); - if (v) { - *v = 0; - } - if (mlen) { - *mlen = 0; - } - return 1; - } - npub = (rings - 1) << 2; - for (j = 0; j < 2; j++) { - size_t idx; - /* Look for a value encoding in the last ring. */ - idx = npub + rsizes[rings - 1] - 1 - j; - rustsecp256k1zkp_v0_8_0_scalar_get_b32(tmp, &s[idx]); - rustsecp256k1zkp_v0_8_0_rangeproof_ch32xor(tmp, &prep[idx * 32]); - if ((tmp[0] & 128) && (rustsecp256k1zkp_v0_8_0_memcmp_var(&tmp[16], &tmp[24], 8) == 0) && (rustsecp256k1zkp_v0_8_0_memcmp_var(&tmp[8], &tmp[16], 8) == 0)) { - value = 0; - for (i = 0; i < 8; i++) { - value = (value << 8) + tmp[24 + i]; - } - if (v) { - *v = value; - } - memcpy(&prep[idx * 32], tmp, 32); - break; - } - } - if (j > 1) { - /* Couldn't extract a value. */ - if (mlen) { - *mlen = 0; - } - return 0; - } - skip1 = rsizes[rings - 1] - 1 - j; - skip2 = ((value >> ((rings - 1) << 1)) & 3); - if (skip1 == skip2) { - /*Value is in wrong position.*/ - if (mlen) { - *mlen = 0; - } - return 0; - } - skip1 += (rings - 1) << 2; - skip2 += (rings - 1) << 2; - /* Like in the rsize[] == 1 case, Having figured out which s is the one which was not forged, we can recover the blinding factor. */ - rustsecp256k1zkp_v0_8_0_rangeproof_recover_x(&stmp, &s_orig[skip2], &ev[skip2], &s[skip2]); - rustsecp256k1zkp_v0_8_0_scalar_negate(&sec[rings - 1], &sec[rings - 1]); - rustsecp256k1zkp_v0_8_0_scalar_add(blind, &stmp, &sec[rings - 1]); - if (!m || !mlen || *mlen == 0) { - if (mlen) { - *mlen = 0; - } - /* FIXME: cleanup in early out/failure cases. */ - return 1; - } - offset = 0; - npub = 0; - for (i = 0; i < rings; i++) { - size_t idx; - idx = (value >> (i << 1)) & 3; - for (j = 0; j < rsizes[i]; j++) { - if (npub == skip1 || npub == skip2) { - npub++; - continue; - } - if (idx == j) { - /** For the non-forged signatures the signature is calculated instead of random, instead we recover the prover's nonces. - * this could just as well recover the blinding factors and messages could be put there as is done for recovering the - * blinding factor in the last ring, but it takes an inversion to recover x so it's faster to put the message data in k. - */ - rustsecp256k1zkp_v0_8_0_rangeproof_recover_k(&stmp, &sec[i], &ev[npub], &s[npub]); - } else { - stmp = s[npub]; - } - rustsecp256k1zkp_v0_8_0_scalar_get_b32(tmp, &stmp); - rustsecp256k1zkp_v0_8_0_rangeproof_ch32xor(tmp, &prep[npub * 32]); - for (b = 0; b < 32 && offset < *mlen; b++) { - m[offset] = tmp[b]; - offset++; - } - npub++; - } - } - *mlen = offset; - memset(prep, 0, 4096); - for (i = 0; i < 128; i++) { - rustsecp256k1zkp_v0_8_0_scalar_clear(&s_orig[i]); - } - for (i = 0; i < 32; i++) { - rustsecp256k1zkp_v0_8_0_scalar_clear(&sec[i]); - } - rustsecp256k1zkp_v0_8_0_scalar_clear(&stmp); - return 1; -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_rangeproof_getheader_impl(size_t *offset, int *exp, int *mantissa, uint64_t *scale, - uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, size_t plen) { - int i; - int has_nz_range; - int has_min; - if (plen < 65 || ((proof[*offset] & 128) != 0)) { - return 0; - } - has_nz_range = proof[*offset] & 64; - has_min = proof[*offset] & 32; - *exp = -1; - *mantissa = 0; - if (has_nz_range) { - *exp = proof[*offset] & 31; - *offset += 1; - if (*exp > 18) { - return 0; - } - *mantissa = proof[*offset] + 1; - if (*mantissa > 64) { - return 0; - } - *max_value = UINT64_MAX>>(64-*mantissa); - } else { - *max_value = 0; - } - *offset += 1; - *scale = 1; - for (i = 0; i < *exp; i++) { - if (*max_value > UINT64_MAX / 10) { - return 0; - } - *max_value *= 10; - *scale *= 10; - } - *min_value = 0; - if (has_min) { - if(plen - *offset < 8) { - return 0; - } - /*FIXME: Compact minvalue encoding?*/ - for (i = 0; i < 8; i++) { - *min_value = (*min_value << 8) | proof[*offset + i]; - } - *offset += 8; - } - if (*max_value > UINT64_MAX - *min_value) { - return 0; - } - *max_value += *min_value; - return 1; -} - -/* Verifies range proof (len plen) for commit, the min/max values proven are put in the min/max arguments; returns 0 on failure 1 on success.*/ -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_rangeproof_verify_impl(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context* ecmult_gen_ctx, - unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce, - uint64_t *min_value, uint64_t *max_value, const rustsecp256k1zkp_v0_8_0_ge *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const rustsecp256k1zkp_v0_8_0_ge* genp) { - rustsecp256k1zkp_v0_8_0_gej accj; - rustsecp256k1zkp_v0_8_0_gej pubs[128]; - rustsecp256k1zkp_v0_8_0_ge c; - rustsecp256k1zkp_v0_8_0_scalar s[128]; - rustsecp256k1zkp_v0_8_0_scalar evalues[128]; /* Challenges, only used during proof rewind. */ - rustsecp256k1zkp_v0_8_0_sha256 sha256_m; - size_t rsizes[32]; - int ret; - size_t i; - int exp; - int mantissa; - size_t offset; - size_t rings; - int overflow; - size_t npub; - int offset_post_header; - uint64_t scale; - unsigned char signs[31]; - unsigned char m[33]; - const unsigned char *e0; - offset = 0; - if (!rustsecp256k1zkp_v0_8_0_rangeproof_getheader_impl(&offset, &exp, &mantissa, &scale, min_value, max_value, proof, plen)) { - return 0; - } - offset_post_header = offset; - rings = 1; - rsizes[0] = 1; - npub = 1; - if (mantissa != 0) { - rings = (mantissa >> 1); - for (i = 0; i < rings; i++) { - rsizes[i] = 4; - } - npub = (mantissa >> 1) << 2; - if (mantissa & 1) { - rsizes[rings] = 2; - npub += rsizes[rings]; - rings++; - } - } - VERIFY_CHECK(rings <= 32); - if (plen - offset < 32 * (npub + rings - 1) + 32 + ((rings+6) >> 3)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha256_m); - rustsecp256k1zkp_v0_8_0_rangeproof_serialize_point(m, commit); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_m, m, 33); - rustsecp256k1zkp_v0_8_0_rangeproof_serialize_point(m, genp); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_m, m, 33); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_m, proof, offset); - for(i = 0; i < rings - 1; i++) { - signs[i] = (proof[offset + ( i>> 3)] & (1 << (i & 7))) != 0; - } - offset += (rings + 6) >> 3; - if ((rings - 1) & 7) { - /* Number of coded blinded points is not a multiple of 8, force extra sign bits to 0 to reject mutation. */ - if ((proof[offset - 1] >> ((rings - 1) & 7)) != 0) { - return 0; - } - } - npub = 0; - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&accj); - if (*min_value) { - rustsecp256k1zkp_v0_8_0_pedersen_ecmult_small(&accj, *min_value, genp); - } - for(i = 0; i < rings - 1; i++) { - rustsecp256k1zkp_v0_8_0_fe fe; - if (!rustsecp256k1zkp_v0_8_0_fe_set_b32(&fe, &proof[offset]) || - !rustsecp256k1zkp_v0_8_0_ge_set_xquad(&c, &fe)) { - return 0; - } - if (signs[i]) { - rustsecp256k1zkp_v0_8_0_ge_neg(&c, &c); - } - /* Not using rustsecp256k1zkp_v0_8_0_rangeproof_serialize_point as we almost have it - * serialized form already. */ - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_m, &signs[i], 1); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_m, &proof[offset], 32); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&pubs[npub], &c); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&accj, &accj, &c, NULL); - offset += 32; - npub += rsizes[i]; - } - rustsecp256k1zkp_v0_8_0_gej_neg(&accj, &accj); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&pubs[npub], &accj, commit, NULL); - if (rustsecp256k1zkp_v0_8_0_gej_is_infinity(&pubs[npub])) { - return 0; - } - rustsecp256k1zkp_v0_8_0_rangeproof_pub_expand(pubs, exp, rsizes, rings, genp); - npub += rsizes[rings - 1]; - e0 = &proof[offset]; - offset += 32; - for (i = 0; i < npub; i++) { - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&s[i], &proof[offset], &overflow); - if (overflow) { - return 0; - } - offset += 32; - } - if (offset != plen) { - /*Extra data found, reject.*/ - return 0; - } - if (extra_commit != NULL) { - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_m, extra_commit, extra_commit_len); - } - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha256_m, m); - ret = rustsecp256k1zkp_v0_8_0_borromean_verify(nonce ? evalues : NULL, e0, s, pubs, rsizes, rings, m, 32); - if (ret && nonce) { - /* Given the nonce, try rewinding the witness to recover its initial state. */ - rustsecp256k1zkp_v0_8_0_scalar blind; - uint64_t vv; - if (!ecmult_gen_ctx) { - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_rangeproof_rewind_inner(&blind, &vv, message_out, outlen, evalues, s, rsizes, rings, nonce, commit, proof, offset_post_header, genp)) { - return 0; - } - /* Unwind apparently successful, see if the commitment can be reconstructed. */ - /* FIXME: should check vv is in the mantissa's range. */ - vv = (vv * scale) + *min_value; - rustsecp256k1zkp_v0_8_0_pedersen_ecmult(ecmult_gen_ctx, &accj, &blind, vv, genp); - if (rustsecp256k1zkp_v0_8_0_gej_is_infinity(&accj)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_gej_neg(&accj, &accj); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&accj, &accj, commit, NULL); - if (!rustsecp256k1zkp_v0_8_0_gej_is_infinity(&accj)) { - return 0; - } - if (blindout) { - rustsecp256k1zkp_v0_8_0_scalar_get_b32(blindout, &blind); - } - if (value_out) { - *value_out = vv; - } - } - return ret; -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/tests_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/tests_impl.h deleted file mode 100644 index d97113d4..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/rangeproof/tests_impl.h +++ /dev/null @@ -1,1425 +0,0 @@ -/********************************************************************** - * Copyright (c) 2015 Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_RANGEPROOF_TESTS -#define SECP256K1_MODULE_RANGEPROOF_TESTS - -#include - -#include "../../group.h" -#include "../../scalar.h" -#include "../../testrand.h" -#include "../../util.h" - -#include "../../../include/secp256k1_rangeproof.h" - -static void test_rangeproof_api(const rustsecp256k1zkp_v0_8_0_context *none, const rustsecp256k1zkp_v0_8_0_context *sign, const rustsecp256k1zkp_v0_8_0_context *vrfy, const rustsecp256k1zkp_v0_8_0_context *both, const rustsecp256k1zkp_v0_8_0_context *sttc, const int32_t *ecount) { - unsigned char proof[5134]; - unsigned char blind[32]; - rustsecp256k1zkp_v0_8_0_pedersen_commitment commit; - uint64_t vmin = rustsecp256k1zkp_v0_8_0_testrand32(); - uint64_t val = vmin + rustsecp256k1zkp_v0_8_0_testrand32(); - size_t len = sizeof(proof); - /* we'll switch to dylan thomas for this one */ - const unsigned char message[68] = "My tears are like the quiet drift / Of petals from some magic rose;"; - size_t mlen = sizeof(message); - const unsigned char ext_commit[72] = "And all my grief flows from the rift / Of unremembered skies and snows."; - size_t ext_commit_len = sizeof(ext_commit); - - rustsecp256k1zkp_v0_8_0_testrand256(blind); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(ctx, &commit, blind, val, rustsecp256k1zkp_v0_8_0_generator_h)); - - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(none, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(sign, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(vrfy, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(*ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(sttc, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(both, NULL, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(both, proof, NULL, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(both, proof, &len, vmin, NULL, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(both, proof, &len, vmin, &commit, NULL, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(both, proof, &len, vmin, &commit, blind, NULL, 0, 0, val, message, mlen, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, vmin - 1, message, mlen, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, mlen, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 7); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(*ecount == 7); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 8); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(*ecount == 8); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, 0, NULL) == 0); - CHECK(*ecount == 9); - - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - { - int exp; - int mantissa; - uint64_t min_value; - uint64_t max_value; - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, proof, len) != 0); - CHECK(exp == 0); - CHECK(((uint64_t) 1 << mantissa) > val - vmin); - CHECK(((uint64_t) 1 << (mantissa - 1)) <= val - vmin); - CHECK(min_value == vmin); - CHECK(max_value >= val); - - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_info(none, NULL, &mantissa, &min_value, &max_value, proof, len) == 0); - CHECK(*ecount == 10); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_info(none, &exp, NULL, &min_value, &max_value, proof, len) == 0); - CHECK(*ecount == 11); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_info(none, &exp, &mantissa, NULL, &max_value, proof, len) == 0); - CHECK(*ecount == 12); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_info(none, &exp, &mantissa, &min_value, NULL, proof, len) == 0); - CHECK(*ecount == 13); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, NULL, len) == 0); - CHECK(*ecount == 14); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, proof, 0) == 0); - CHECK(*ecount == 14); - } - { - uint64_t min_value; - uint64_t max_value; - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(none, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(sign, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(*ecount == 14); - - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(vrfy, NULL, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 15); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(vrfy, &min_value, NULL, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 16); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(vrfy, &min_value, &max_value, NULL, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 17); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(vrfy, &min_value, &max_value, &commit, NULL, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 18); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, 0, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 18); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 19); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 19); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL) == 0); - CHECK(*ecount == 20); - } - { - unsigned char blind_out[32]; - unsigned char message_out[68]; - uint64_t value_out; - uint64_t min_value; - uint64_t max_value; - size_t message_len = sizeof(message_out); - - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(none, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(*ecount == 20); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(sign, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(vrfy, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(*ecount == 20); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(both, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(*ecount == 20); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(sttc, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 21); - - CHECK(min_value == vmin); - CHECK(max_value >= val); - CHECK(value_out == val); - CHECK(message_len == sizeof(message_out)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(message, message_out, sizeof(message_out)) == 0); - - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(both, NULL, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(*ecount == 21); /* blindout may be NULL */ - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(both, blind_out, NULL, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(*ecount == 21); /* valueout may be NULL */ - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(both, blind_out, &value_out, NULL, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 22); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(*ecount == 22); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, NULL, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 23); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, NULL, &max_value, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 24); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, NULL, &commit, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 25); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, NULL, proof, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 26); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, NULL, len, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 27); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, 0, ext_commit, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 27); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, ext_commit_len, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 28); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h) == 0); - CHECK(*ecount == 28); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL) == 0); - CHECK(*ecount == 29); - } - - /* This constant is hardcoded in these tests and elsewhere, so we - * consider it to be part of the API and test it here. */ - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_max_size(none, 0, 64) == 5134); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_max_size(none, UINT64_MAX, 0) == 5134); -} - -static void test_api(void) { - rustsecp256k1zkp_v0_8_0_context *none = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); - rustsecp256k1zkp_v0_8_0_context *sign = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN); - rustsecp256k1zkp_v0_8_0_context *vrfy = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *both = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *sttc = rustsecp256k1zkp_v0_8_0_context_clone(rustsecp256k1zkp_v0_8_0_context_no_precomp); - int32_t ecount; - int i; - - rustsecp256k1zkp_v0_8_0_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); - - for (i = 0; i < count; i++) { - ecount = 0; - test_rangeproof_api(none, sign, vrfy, both, sttc, &ecount); - } - - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(vrfy); - rustsecp256k1zkp_v0_8_0_context_destroy(both); - rustsecp256k1zkp_v0_8_0_context_destroy(sttc); -} - -static void test_borromean(void) { - unsigned char e0[32]; - rustsecp256k1zkp_v0_8_0_scalar s[64]; - rustsecp256k1zkp_v0_8_0_gej pubs[64]; - rustsecp256k1zkp_v0_8_0_scalar k[8]; - rustsecp256k1zkp_v0_8_0_scalar sec[8]; - rustsecp256k1zkp_v0_8_0_ge ge; - rustsecp256k1zkp_v0_8_0_scalar one; - unsigned char m[32]; - size_t rsizes[8]; - size_t secidx[8]; - size_t nrings; - size_t i; - size_t j; - int c; - rustsecp256k1zkp_v0_8_0_testrand256_test(m); - nrings = 1 + (rustsecp256k1zkp_v0_8_0_testrand32()&7); - c = 0; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&one, 1); - if (rustsecp256k1zkp_v0_8_0_testrand32()&1) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&one, &one); - } - for (i = 0; i < nrings; i++) { - rsizes[i] = 1 + (rustsecp256k1zkp_v0_8_0_testrand32()&7); - secidx[i] = rustsecp256k1zkp_v0_8_0_testrand32() % rsizes[i]; - random_scalar_order(&sec[i]); - random_scalar_order(&k[i]); - if(rustsecp256k1zkp_v0_8_0_testrand32()&7) { - sec[i] = one; - } - if(rustsecp256k1zkp_v0_8_0_testrand32()&7) { - k[i] = one; - } - for (j = 0; j < rsizes[i]; j++) { - random_scalar_order(&s[c + j]); - if(rustsecp256k1zkp_v0_8_0_testrand32()&7) { - s[i] = one; - } - if (j == secidx[i]) { - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &pubs[c + j], &sec[i]); - } else { - random_group_element_test(&ge); - random_group_element_jacobian_test(&pubs[c + j],&ge); - } - } - c += rsizes[i]; - } - CHECK(rustsecp256k1zkp_v0_8_0_borromean_sign(&ctx->ecmult_gen_ctx, e0, s, pubs, k, sec, rsizes, secidx, nrings, m, 32)); - CHECK(rustsecp256k1zkp_v0_8_0_borromean_verify(NULL, e0, s, pubs, rsizes, nrings, m, 32)); - i = rustsecp256k1zkp_v0_8_0_testrand32() % c; - rustsecp256k1zkp_v0_8_0_scalar_negate(&s[i],&s[i]); - CHECK(!rustsecp256k1zkp_v0_8_0_borromean_verify(NULL, e0, s, pubs, rsizes, nrings, m, 32)); - rustsecp256k1zkp_v0_8_0_scalar_negate(&s[i],&s[i]); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&one, 1); - for(j = 0; j < 4; j++) { - i = rustsecp256k1zkp_v0_8_0_testrand32() % c; - if (rustsecp256k1zkp_v0_8_0_testrand32() & 1) { - rustsecp256k1zkp_v0_8_0_gej_double_var(&pubs[i],&pubs[i], NULL); - } else { - rustsecp256k1zkp_v0_8_0_scalar_add(&s[i],&s[i],&one); - } - CHECK(!rustsecp256k1zkp_v0_8_0_borromean_verify(NULL, e0, s, pubs, rsizes, nrings, m, 32)); - } -} - -static void test_rangeproof(void) { - const uint64_t testvs[11] = {0, 1, 5, 11, 65535, 65537, INT32_MAX, UINT32_MAX, INT64_MAX - 1, INT64_MAX, UINT64_MAX}; - rustsecp256k1zkp_v0_8_0_pedersen_commitment commit; - rustsecp256k1zkp_v0_8_0_pedersen_commitment commit2; - unsigned char proof[5134 + 1]; /* One additional byte to test if trailing bytes are rejected */ - unsigned char blind[32]; - unsigned char blindout[32]; - unsigned char message[4096]; - size_t mlen; - uint64_t v; - uint64_t vout; - uint64_t vmin; - uint64_t minv; - uint64_t maxv; - size_t len; - size_t i; - size_t j; - size_t k; - /* Short message is a Simone de Beauvoir quote */ - const unsigned char message_short[120] = "When I see my own likeness in the depths of someone else's consciousness, I always experience a moment of panic."; - /* Long message is 0xA5 with a bunch of this quote in the middle */ - unsigned char message_long[3968]; - memset(message_long, 0xa5, sizeof(message_long)); - for (i = 1200; i < 3600; i += 120) { - memcpy(&message_long[i], message_short, sizeof(message_short)); - } - - rustsecp256k1zkp_v0_8_0_testrand256(blind); - for (i = 0; i < 11; i++) { - v = testvs[i]; - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(ctx, &commit, blind, v, rustsecp256k1zkp_v0_8_0_generator_h)); - for (vmin = 0; vmin < (i<9 && i > 0 ? 2 : 1); vmin++) { - const unsigned char *input_message = NULL; - size_t input_message_len = 0; - /* vmin is always either 0 or 1; if it is 1, then we have no room for a message. - * If it's 0, we use "minimum encoding" and only have room for a small message when - * `testvs[i]` is >= 4; for a large message when it's >= 2^32. */ - if (vmin == 0 && i > 2) { - input_message = message_short; - input_message_len = sizeof(message_short); - } - if (vmin == 0 && i > 7) { - input_message = message_long; - input_message_len = sizeof(message_long); - } - len = 5134; - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, 0, 0, v, input_message, input_message_len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(len <= 5134); - CHECK(len <= rustsecp256k1zkp_v0_8_0_rangeproof_max_size(ctx, v, 0)); - mlen = 4096; - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - if (input_message != NULL) { - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(message, input_message, input_message_len) == 0); - } - for (j = input_message_len; j < mlen; j++) { - CHECK(message[j] == 0); - } - CHECK(mlen <= 4096); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(blindout, blind, 32) == 0); - CHECK(vout == v); - CHECK(minv <= v); - CHECK(maxv >= v); - len = 5134; - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, -1, 64, v, NULL, 0, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(len <= 73); - CHECK(len <= rustsecp256k1zkp_v0_8_0_rangeproof_max_size(ctx, v, 0)); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(blindout, blind, 32) == 0); - CHECK(vout == v); - CHECK(minv == v); - CHECK(maxv == v); - - /* Check with a committed message */ - len = 5134; - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, -1, 64, v, NULL, 0, message_short, sizeof(message_short), rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(len <= 73); - CHECK(len <= rustsecp256k1zkp_v0_8_0_rangeproof_max_size(ctx, v, 0)); - CHECK(!rustsecp256k1zkp_v0_8_0_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(!rustsecp256k1zkp_v0_8_0_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, message_long, sizeof(message_long), rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, message_short, sizeof(message_short), rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(blindout, blind, 32) == 0); - CHECK(vout == v); - CHECK(minv == v); - CHECK(maxv == v); - } - } - rustsecp256k1zkp_v0_8_0_testrand256(blind); - v = INT64_MAX - 1; - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(ctx, &commit, blind, v, rustsecp256k1zkp_v0_8_0_generator_h)); - for (i = 0; i < 19; i++) { - len = 5134; - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, i, 0, v, NULL, 0, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(len <= rustsecp256k1zkp_v0_8_0_rangeproof_max_size(ctx, v, 0)); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(len <= 5134); - CHECK(minv <= v); - CHECK(maxv >= v); - /* Make sure it fails when validating with a committed message */ - CHECK(!rustsecp256k1zkp_v0_8_0_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, message_short, sizeof(message_short), rustsecp256k1zkp_v0_8_0_generator_h)); - } - rustsecp256k1zkp_v0_8_0_testrand256(blind); - { - /*Malleability test.*/ - v = rustsecp256k1zkp_v0_8_0_testrandi64(0, 255); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(ctx, &commit, blind, v, rustsecp256k1zkp_v0_8_0_generator_h)); - len = 5134; - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, 0, 3, v, NULL, 0, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(len <= 5134); - CHECK(len <= rustsecp256k1zkp_v0_8_0_rangeproof_max_size(ctx, v, 3)); - /* Test if trailing bytes are rejected. */ - proof[len] = v; - CHECK(!rustsecp256k1zkp_v0_8_0_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len + 1, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - for (i = 0; i < len*8; i++) { - proof[i >> 3] ^= 1 << (i & 7); - CHECK(!rustsecp256k1zkp_v0_8_0_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - proof[i >> 3] ^= 1 << (i & 7); - } - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(minv <= v); - CHECK(maxv >= v); - } - memcpy(&commit2, &commit, sizeof(commit)); - for (i = 0; i < (size_t) count; i++) { - int exp; - int min_bits; - v = rustsecp256k1zkp_v0_8_0_testrandi64(0, UINT64_MAX >> (rustsecp256k1zkp_v0_8_0_testrand32()&63)); - vmin = 0; - if ((v < INT64_MAX) && (rustsecp256k1zkp_v0_8_0_testrand32()&1)) { - vmin = rustsecp256k1zkp_v0_8_0_testrandi64(0, v); - } - rustsecp256k1zkp_v0_8_0_testrand256(blind); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(ctx, &commit, blind, v, rustsecp256k1zkp_v0_8_0_generator_h)); - len = 5134; - exp = (int)rustsecp256k1zkp_v0_8_0_testrandi64(0,18)-(int)rustsecp256k1zkp_v0_8_0_testrandi64(0,18); - if (exp < 0) { - exp = -exp; - } - min_bits = (int)rustsecp256k1zkp_v0_8_0_testrandi64(0,64)-(int)rustsecp256k1zkp_v0_8_0_testrandi64(0,64); - if (min_bits < 0) { - min_bits = -min_bits; - } - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, exp, min_bits, v, NULL, 0, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(len <= 5134); - CHECK(len <= rustsecp256k1zkp_v0_8_0_rangeproof_max_size(ctx, v, min_bits)); - mlen = 4096; - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - for (j = 0; j < mlen; j++) { - CHECK(message[j] == 0); - } - CHECK(mlen <= 4096); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(blindout, blind, 32) == 0); - - CHECK(minv <= v); - CHECK(maxv >= v); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - memcpy(&commit2, &commit, sizeof(commit)); - } - for (j = 0; j < 3; j++) { - for (i = 0; i < 96; i++) { - rustsecp256k1zkp_v0_8_0_testrand256(&proof[i * 32]); - } - for (k = 0; k < 128; k += 3) { - len = k; - CHECK(!rustsecp256k1zkp_v0_8_0_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - } - len = rustsecp256k1zkp_v0_8_0_testrandi64(0, 3072); - CHECK(!rustsecp256k1zkp_v0_8_0_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - } -} - -static void test_rangeproof_null_blinder(void) { - unsigned char proof[5134]; - const unsigned char blind[32] = { 0 }; - const uint64_t v = 1111; - uint64_t minv, maxv; - rustsecp256k1zkp_v0_8_0_pedersen_commitment commit; - size_t len; - - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(ctx, &commit, blind, v, rustsecp256k1zkp_v0_8_0_generator_h)); - - /* Try a 32-bit proof; should work */ - len = 5134; - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(ctx, proof, &len, 1, &commit, blind, commit.data, 0, 32, v, NULL, 0, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(minv == 1); - CHECK(maxv == 1ULL << 32); - - /* Try a 3-bit proof; should work */ - len = 5134; - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(ctx, proof, &len, v - 1, &commit, blind, commit.data, 0, 3, v, NULL, 0, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(minv == 1110); - CHECK(maxv == 1117); - - /* But a 2-bits will not because then it does not have any subcommitments (which rerandomize - * the blinding factors that get passed into the borromean logic ... passing 0s will fail) */ - len = 5134; - CHECK(!rustsecp256k1zkp_v0_8_0_rangeproof_sign(ctx, proof, &len, v - 1, &commit, blind, commit.data, 0, 2, v, NULL, 0, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - - /* Rewinding with 3-bits works */ - { - uint64_t value_out; - unsigned char msg[128]; - unsigned char msg_out[128]; - unsigned char blind_out[32]; - size_t msg_len = sizeof(msg); - - len = 1000; - rustsecp256k1zkp_v0_8_0_testrand256(msg); - rustsecp256k1zkp_v0_8_0_testrand256(&msg[32]); - rustsecp256k1zkp_v0_8_0_testrand256(&msg[64]); - rustsecp256k1zkp_v0_8_0_testrand256(&msg[96]); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, 0, 3, v, msg, sizeof(msg), NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind(ctx, blind_out, &value_out, msg_out, &msg_len, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(blind, blind_out, sizeof(blind)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(msg, msg_out, sizeof(msg)) == 0); - CHECK(value_out == v); - CHECK(minv == v); - CHECK(maxv == v + 7); - } -} - -static void test_single_value_proof(uint64_t val) { - unsigned char proof[5000]; - rustsecp256k1zkp_v0_8_0_pedersen_commitment commit; - unsigned char blind[32]; - unsigned char blind_out[32]; - unsigned char nonce[32]; - const unsigned char message[1] = " "; /* no message will fit into a single-value proof */ - unsigned char message_out[sizeof(proof)] = { 0 }; - size_t plen = sizeof(proof); - uint64_t min_val_out = 0; - uint64_t max_val_out = 0; - - uint64_t val_out = 0; - size_t m_len_out = 0; - - rustsecp256k1zkp_v0_8_0_testrand256(blind); - rustsecp256k1zkp_v0_8_0_testrand256(nonce); - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(ctx, &commit, blind, val, rustsecp256k1zkp_v0_8_0_generator_h)); - - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign( - ctx, - proof, &plen, - val, /* min_val */ - &commit, blind, nonce, - -1, /* exp: -1 is magic value to indicate a single-value proof */ - 0, /* min_bits */ - val, /* val */ - message, sizeof(message), /* Will cause this to fail */ - NULL, 0, - rustsecp256k1zkp_v0_8_0_generator_h - ) == 0); - - plen = sizeof(proof); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign( - ctx, - proof, &plen, - val, /* min_val */ - &commit, blind, nonce, - -1, /* exp: -1 is magic value to indicate a single-value proof */ - 0, /* min_bits */ - val, /* val */ - NULL, 0, - NULL, 0, - rustsecp256k1zkp_v0_8_0_generator_h - ) == 1); - CHECK(plen <= rustsecp256k1zkp_v0_8_0_rangeproof_max_size(ctx, val, 0)); - - /* Different proof sizes are unfortunate but is caused by `min_value` of - * zero being special-cased and encoded more efficiently. */ - if (val == 0) { - CHECK(plen == 65); - } else { - CHECK(plen == 73); - } - - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify( - ctx, - &min_val_out, &max_val_out, - &commit, - proof, plen, - NULL, 0, - rustsecp256k1zkp_v0_8_0_generator_h - ) == 1); - CHECK(min_val_out == val); - CHECK(max_val_out == val); - - memset(message_out, 0, sizeof(message_out)); - m_len_out = sizeof(message_out); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind( - ctx, - blind_out, &val_out, - message_out, &m_len_out, - nonce, - &min_val_out, &max_val_out, - &commit, - proof, plen, - NULL, 0, - rustsecp256k1zkp_v0_8_0_generator_h - )); - CHECK(val_out == val); - CHECK(min_val_out == val); - CHECK(max_val_out == val); - CHECK(m_len_out == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(blind, blind_out, 32) == 0); - for (m_len_out = 0; m_len_out < sizeof(message_out); m_len_out++) { - CHECK(message_out[m_len_out] == 0); - } -} - -#define MAX_N_GENS 30 -static void test_multiple_generators(void) { - const size_t n_inputs = (rustsecp256k1zkp_v0_8_0_testrand32() % (MAX_N_GENS / 2)) + 1; - const size_t n_outputs = (rustsecp256k1zkp_v0_8_0_testrand32() % (MAX_N_GENS / 2)) + 1; - const size_t n_generators = n_inputs + n_outputs; - unsigned char *generator_blind[MAX_N_GENS]; - unsigned char *pedersen_blind[MAX_N_GENS]; - rustsecp256k1zkp_v0_8_0_generator generator[MAX_N_GENS]; - rustsecp256k1zkp_v0_8_0_pedersen_commitment commit[MAX_N_GENS]; - const rustsecp256k1zkp_v0_8_0_pedersen_commitment *commit_ptr[MAX_N_GENS]; - size_t i; - int64_t total_value; - uint64_t value[MAX_N_GENS]; - - rustsecp256k1zkp_v0_8_0_scalar s; - - unsigned char generator_seed[32]; - random_scalar_order(&s); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(generator_seed, &s); - /* Create all the needed generators */ - for (i = 0; i < n_generators; i++) { - generator_blind[i] = (unsigned char*) malloc(32); - pedersen_blind[i] = (unsigned char*) malloc(32); - - random_scalar_order(&s); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(generator_blind[i], &s); - random_scalar_order(&s); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(pedersen_blind[i], &s); - - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(ctx, &generator[i], generator_seed, generator_blind[i])); - - commit_ptr[i] = &commit[i]; - } - - /* Compute all the values -- can be positive or negative */ - total_value = 0; - for (i = 0; i < n_outputs; i++) { - value[n_inputs + i] = rustsecp256k1zkp_v0_8_0_testrandi64(0, INT64_MAX - total_value); - total_value += value[n_inputs + i]; - } - for (i = 0; i < n_inputs - 1; i++) { - value[i] = rustsecp256k1zkp_v0_8_0_testrandi64(0, total_value); - total_value -= value[i]; - } - value[i] = total_value; - - /* Correct for blinding factors and do the commitments */ - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_blind_generator_blind_sum(ctx, value, (const unsigned char * const *) generator_blind, pedersen_blind, n_generators, n_inputs)); - for (i = 0; i < n_generators; i++) { - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(ctx, &commit[i], pedersen_blind[i], value[i], &generator[i])); - } - - /* Verify */ - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_verify_tally(ctx, &commit_ptr[0], n_inputs, &commit_ptr[n_inputs], n_outputs)); - - /* Cleanup */ - for (i = 0; i < n_generators; i++) { - free(generator_blind[i]); - free(pedersen_blind[i]); - } -} - -void test_rangeproof_fixed_vectors(void) { - size_t i; - unsigned char blind[32]; - uint64_t value; - uint64_t min_value; - uint64_t max_value; - rustsecp256k1zkp_v0_8_0_pedersen_commitment pc; - unsigned char message[4000] = {0}; - size_t m_len = sizeof(message); - - /* Vector 1: no message */ -{ - static const unsigned char vector_1[] = { - 0x62, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x02, 0x2a, 0x5c, 0x42, 0x0e, 0x1d, - 0x51, 0xe1, 0xb7, 0xf3, 0x69, 0x04, 0xb5, 0xbb, 0x9b, 0x41, 0x66, 0x14, 0xf3, 0x64, 0x42, 0x26, - 0xe3, 0xa7, 0x6a, 0x06, 0xbb, 0xa8, 0x5a, 0x49, 0x6f, 0x19, 0x76, 0xfb, 0xe5, 0x75, 0x77, 0x88, - 0xab, 0xa9, 0x66, 0x44, 0x80, 0xea, 0x29, 0x95, 0x7f, 0xdf, 0x72, 0x4a, 0xaf, 0x02, 0xbe, 0xdd, - 0x5d, 0x15, 0xd8, 0xae, 0xff, 0x74, 0xc9, 0x8c, 0x1a, 0x67, 0x0e, 0xb2, 0x57, 0x22, 0x99, 0xc3, - 0x21, 0x46, 0x6f, 0x15, 0x58, 0x0e, 0xdb, 0xe6, 0x6e, 0xc4, 0x0d, 0xfe, 0x6f, 0x04, 0x6b, 0x0d, - 0x18, 0x3d, 0x78, 0x40, 0x98, 0x56, 0x4e, 0xe4, 0x4a, 0x74, 0x90, 0xa7, 0xac, 0x9c, 0x16, 0xe0, - 0x3e, 0x81, 0xaf, 0x0f, 0xe3, 0x4f, 0x34, 0x99, 0x52, 0xf7, 0xa7, 0xf6, 0xd3, 0x83, 0xa0, 0x17, - 0x4b, 0x2d, 0xa7, 0xd4, 0xfd, 0xf7, 0x84, 0x45, 0xc4, 0x11, 0x71, 0x3d, 0x4a, 0x22, 0x34, 0x09, - 0x9c, 0xa7, 0xe5, 0xc8, 0xba, 0x04, 0xbf, 0xfd, 0x25, 0x11, 0x7d, 0xa4, 0x43, 0x45, 0xc7, 0x62, - 0x9e, 0x7b, 0x80, 0xf6, 0x09, 0xbb, 0x1b, 0x2e, 0xf3, 0xcd, 0x23, 0xe0, 0xed, 0x81, 0x43, 0x42, - 0xbe, 0xc4, 0x9f, 0x58, 0x8a, 0x0d, 0x66, 0x79, 0x09, 0x70, 0x11, 0x68, 0x3d, 0x87, 0x38, 0x1c, - 0x3c, 0x85, 0x52, 0x5b, 0x62, 0xf7, 0x3e, 0x7e, 0x87, 0xa2, 0x99, 0x24, 0xd0, 0x7d, 0x18, 0x63, - 0x56, 0x48, 0xa4, 0x3a, 0xfe, 0x65, 0xfa, 0xa4, 0xd0, 0x67, 0xaa, 0x98, 0x65, 0x4d, 0xe4, 0x22, - 0x75, 0x45, 0x52, 0xe8, 0x41, 0xc7, 0xed, 0x38, 0xeb, 0xf5, 0x02, 0x90, 0xc9, 0x45, 0xa3, 0xb0, - 0x4d, 0x03, 0xd7, 0xab, 0x43, 0xe4, 0x21, 0xfc, 0x83, 0xd6, 0x12, 0x1d, 0x76, 0xb1, 0x3c, 0x67, - 0x63, 0x1f, 0x52, 0x9d, 0xc3, 0x23, 0x5c, 0x4e, 0xa6, 0x8d, 0x01, 0x4a, 0xba, 0x9a, 0xf4, 0x16, - 0x5b, 0x67, 0xc8, 0xe1, 0xd2, 0x42, 0x6d, 0xdf, 0xcd, 0x08, 0x6a, 0x73, 0x41, 0x6a, 0xc2, 0x84, - 0xc6, 0x31, 0xbe, 0x57, 0xcb, 0x0e, 0xde, 0xbf, 0x71, 0xd5, 0x8a, 0xf7, 0x24, 0xb2, 0xa7, 0x89, - 0x96, 0x62, 0x4f, 0xd9, 0xf7, 0xc3, 0xde, 0x4c, 0xab, 0x13, 0x72, 0xb4, 0xb3, 0x35, 0x04, 0x82, - 0xa8, 0x75, 0x1d, 0xde, 0x46, 0xa8, 0x0d, 0xb8, 0x23, 0x44, 0x00, 0x44, 0xfa, 0x53, 0x6c, 0x2d, - 0xce, 0xd3, 0xa6, 0x80, 0xa1, 0x20, 0xca, 0xd1, 0x63, 0xbb, 0xbe, 0x39, 0x5f, 0x9d, 0x27, 0x69, - 0xb3, 0x33, 0x1f, 0xdb, 0xda, 0x67, 0x05, 0x37, 0xbe, 0x65, 0xe9, 0x7e, 0xa9, 0xc3, 0xff, 0x37, - 0x8a, 0xb4, 0x2d, 0xfe, 0xf2, 0x16, 0x85, 0xc7, 0x0f, 0xd9, 0xbe, 0x14, 0xd1, 0x80, 0x14, 0x9f, - 0x58, 0x56, 0x98, 0x41, 0xf6, 0x26, 0xf7, 0xa2, 0x71, 0x66, 0xb4, 0x7a, 0x9c, 0x12, 0x73, 0xd3, - 0xdf, 0x77, 0x2b, 0x49, 0xe5, 0xca, 0x50, 0x57, 0x44, 0x6e, 0x3f, 0x58, 0x56, 0xbc, 0x21, 0x70, - 0x4f, 0xc6, 0xaa, 0x12, 0xff, 0x7c, 0xa7, 0x3d, 0xed, 0x46, 0xc1, 0x40, 0xe6, 0x58, 0x09, 0x2a, - 0xda, 0xb3, 0x76, 0xab, 0x44, 0xb5, 0x4e, 0xb3, 0x12, 0xe0, 0x26, 0x8a, 0x52, 0xac, 0x49, 0x1d, - 0xe7, 0x06, 0x53, 0x3a, 0x01, 0x35, 0x21, 0x2e, 0x86, 0x48, 0xc5, 0x75, 0xc1, 0xa2, 0x7d, 0x22, - 0x53, 0xf6, 0x3f, 0x41, 0xc5, 0xb3, 0x08, 0x7d, 0xa3, 0x67, 0xc0, 0xbb, 0xb6, 0x8d, 0xf0, 0xd3, - 0x01, 0x72, 0xd3, 0x63, 0x82, 0x01, 0x1a, 0xe7, 0x1d, 0x22, 0xfa, 0x95, 0x33, 0xf6, 0xf2, 0xde, - 0xa2, 0x53, 0x86, 0x55, 0x5a, 0xb4, 0x2e, 0x75, 0x75, 0xc6, 0xd5, 0x93, 0x9c, 0x57, 0xa9, 0x1f, - 0xb9, 0x3e, 0xe8, 0x1c, 0xbf, 0xac, 0x1c, 0x54, 0x6f, 0xf5, 0xab, 0x41, 0xee, 0xb3, 0x0e, 0xd0, - 0x76, 0xc4, 0x1a, 0x45, 0xcd, 0xf1, 0xd6, 0xcc, 0xb0, 0x83, 0x70, 0x73, 0xbc, 0x88, 0x74, 0xa0, - 0x5b, 0xe7, 0x98, 0x10, 0x36, 0xbf, 0xec, 0x23, 0x1c, 0xc2, 0xb5, 0xba, 0x4b, 0x9d, 0x7f, 0x8c, - 0x8a, 0xe2, 0xda, 0x18, 0xdd, 0xab, 0x27, 0x8a, 0x15, 0xeb, 0xb0, 0xd4, 0x3a, 0x8b, 0x77, 0x00, - 0xc7, 0xbb, 0xcc, 0xfa, 0xba, 0xa4, 0x6a, 0x17, 0x5c, 0xf8, 0x51, 0x5d, 0x8d, 0x16, 0xcd, 0xa7, - 0x0e, 0x71, 0x97, 0x98, 0x78, 0x5a, 0x41, 0xb3, 0xf0, 0x1f, 0x87, 0x2d, 0x65, 0xcd, 0x29, 0x49, - 0xd2, 0x87, 0x2c, 0x91, 0xa9, 0x5f, 0xcc, 0xa9, 0xd8, 0xbb, 0x53, 0x18, 0xe7, 0xd6, 0xec, 0x65, - 0xa6, 0x45, 0xf6, 0xce, 0xcf, 0x48, 0xf6, 0x1e, 0x3d, 0xd2, 0xcf, 0xcb, 0x3a, 0xcd, 0xbb, 0x92, - 0x29, 0x24, 0x16, 0x7f, 0x8a, 0xa8, 0x5c, 0x0c, 0x45, 0x71, 0x33 - }; - static const unsigned char commit_1[] = { - 0x08, - 0xf5, 0x1e, 0x0d, 0xc5, 0x86, 0x78, 0x51, 0xa9, 0x00, 0x00, 0xef, 0x4d, 0xe2, 0x94, 0x60, 0x89, - 0x83, 0x04, 0xb4, 0x0e, 0x90, 0x10, 0x05, 0x1c, 0x7f, 0xd7, 0x33, 0x92, 0x1f, 0xe7, 0x74, 0x59 - }; - static const unsigned char blind_1[] = { - 0x98, 0x44, 0xfc, 0x7a, 0x64, 0xa9, 0xca, 0xdf, 0xf3, 0x2f, 0x9f, 0x02, 0xba, 0x46, 0xc7, 0xd9, - 0x77, 0x47, 0xa4, 0xd3, 0x53, 0x17, 0xc6, 0x44, 0x30, 0x73, 0x84, 0xeb, 0x1f, 0xbe, 0xa1, 0xfb - }; - - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commitment_parse(ctx, &pc, commit_1)); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify( - ctx, - &min_value, &max_value, - &pc, - vector_1, sizeof(vector_1), - NULL, 0, - rustsecp256k1zkp_v0_8_0_generator_h - )); - CHECK(min_value == 86); - CHECK(max_value == 25586); - - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind( - ctx, - blind, &value, - message, &m_len, - pc.data, - &min_value, &max_value, - &pc, - vector_1, sizeof(vector_1), - NULL, 0, - rustsecp256k1zkp_v0_8_0_generator_h - )); - - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(blind, blind_1, 32) == 0); - CHECK(value == 86); - CHECK(min_value == 86); - CHECK(max_value == 25586); - CHECK(m_len == 448); /* length of the sidechannel in the proof */ - for (i = 0; i < m_len; i++) { - /* No message encoded in this vector */ - CHECK(message[i] == 0); - } -} - - /* Vector 2: embedded message */ -{ - static const unsigned char vector_2[] = { - 0x40, 0x03, 0x00, 0x90, 0x1a, 0x61, 0x64, 0xbb, 0x85, 0x1a, 0x78, 0x35, 0x1e, 0xe0, 0xd5, 0x96, - 0x71, 0x0f, 0x18, 0x8e, 0xf3, 0x33, 0xf0, 0x75, 0xfe, 0xd6, 0xc6, 0x11, 0x6b, 0x42, 0x89, 0xea, - 0xa2, 0x0c, 0x89, 0x25, 0x37, 0x81, 0x10, 0xf9, 0xf0, 0x9b, 0xda, 0x68, 0x2a, 0xd9, 0x2e, 0x0c, - 0x45, 0x17, 0x54, 0x6d, 0x02, 0xd2, 0x21, 0x5d, 0xbc, 0x10, 0xf8, 0x8f, 0xf1, 0x92, 0x40, 0xa9, - 0xc7, 0x24, 0x00, 0x1b, 0xc8, 0x75, 0x0f, 0xf6, 0x8f, 0x93, 0x8b, 0x78, 0x62, 0x73, 0x3c, 0x86, - 0x4b, 0x61, 0x7c, 0x0f, 0xc6, 0x41, 0xc9, 0xb3, 0xc1, 0x30, 0x7f, 0xd4, 0xee, 0x9f, 0x37, 0x08, - 0x9b, 0x64, 0x23, 0xd5, 0xe6, 0x1a, 0x03, 0x54, 0x74, 0x9b, 0x0b, 0xae, 0x6f, 0x2b, 0x1e, 0xf5, - 0x40, 0x44, 0xaa, 0x12, 0xe8, 0xbd, 0xe0, 0xa6, 0x85, 0x89, 0xf1, 0xa9, 0xd0, 0x3f, 0x2e, 0xc6, - 0x1f, 0x11, 0xf5, 0x44, 0x69, 0x99, 0x31, 0x10, 0x2e, 0x64, 0xc6, 0x44, 0xdb, 0x47, 0x06, 0x6d, - 0xd5, 0xf2, 0x8d, 0x19, 0x00, 0x39, 0xb8, 0xca, 0xda, 0x5c, 0x1d, 0x83, 0xbd, 0xa3, 0x6d, 0xbf, - 0x97, 0xdd, 0x83, 0x86, 0xc9, 0x56, 0xe2, 0xbb, 0x37, 0x4b, 0x2d, 0xb5, 0x9d, 0xf2, 0x7a, 0x6a, - 0x25, 0x47, 0xfa, 0x03, 0x05, 0xc5, 0xda, 0x73, 0xe1, 0x96, 0x15, 0x21, 0x23, 0xe5, 0xef, 0x55, - 0x36, 0xdd, 0xf1, 0xb1, 0x3f, 0x33, 0x1a, 0x91, 0x6c, 0x73, 0x64, 0xd3, 0x88, 0xe7, 0xc6, 0xc9, - 0x04, 0x29, 0xae, 0x55, 0x27, 0xa0, 0x80, 0x60, 0xaf, 0x0c, 0x09, 0x2f, 0xc8, 0x1b, 0xe6, 0x16, - 0x9e, 0xed, 0x29, 0xc7, 0x93, 0xce, 0xc7, 0x0d, 0xdf, 0x1f, 0x28, 0xba, 0xf3, 0x38, 0xc3, 0xaa, - 0x99, 0xd9, 0x21, 0x41, 0xb8, 0x10, 0xa5, 0x48, 0x37, 0xec, 0x60, 0xda, 0x64, 0x5a, 0x73, 0x55, - 0xd7, 0xff, 0x23, 0xfa, 0xf6, 0xc6, 0xf4, 0xe2, 0xca, 0x99, 0x2f, 0x30, 0x36, 0x48, 0x73, 0x8b, - 0x57, 0xa6, 0x62, 0x12, 0xa3, 0xe7, 0x5c, 0xa8, 0xd1, 0xe6, 0x85, 0x05, 0x59, 0xfe, 0x2b, 0x44, - 0xe4, 0x73, 0x1c, 0xc3, 0x56, 0x32, 0x07, 0x65, 0x4a, 0x58, 0xaf, 0x2b, 0x3f, 0x36, 0xca, 0xb4, - 0x1d, 0x5c, 0x2a, 0x46, 0x1f, 0xf7, 0x63, 0x59, 0x4f, 0x2b, 0xd0, 0xf6, 0xfc, 0xcf, 0x04, 0x09, - 0xb7, 0x65, 0x1b - }; - static const unsigned char commit_2[] = { - 0x09, - 0x25, 0xa4, 0xbd, 0xc4, 0x57, 0x69, 0xeb, 0x4f, 0x34, 0x0f, 0xea, 0xb8, 0xe4, 0x72, 0x04, 0x54, - 0x06, 0xe5, 0xd6, 0x85, 0x15, 0x42, 0xea, 0x6e, 0x1d, 0x11, 0x11, 0x9c, 0x56, 0xf8, 0x10, 0x45 - }; - static const unsigned char blind_2[] = { - 0xdc, 0x79, 0x07, 0x89, 0x2d, 0xc4, 0xe3, 0x76, 0xf9, 0x13, 0x38, 0xd6, 0x4b, 0x46, 0xed, 0x9d, - 0x9b, 0xf6, 0x70, 0x3d, 0x04, 0xcf, 0x96, 0x8c, 0xfd, 0xb5, 0xff, 0x0a, 0x06, 0xc7, 0x08, 0x8b - }; - static const unsigned char message_2[] = "When I see my own likeness in the depths of someone else's consciousness, I always experience a moment of panic."; - - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commitment_parse(ctx, &pc, commit_2)); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify( - ctx, - &min_value, &max_value, - &pc, - vector_2, sizeof(vector_2), - NULL, 0, - rustsecp256k1zkp_v0_8_0_generator_h - )); - CHECK(min_value == 0); - CHECK(max_value == 15); - - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind( - ctx, - blind, &value, - message, &m_len, - pc.data, - &min_value, &max_value, - &pc, - vector_2, sizeof(vector_2), - NULL, 0, - rustsecp256k1zkp_v0_8_0_generator_h - )); - - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(blind, blind_2, 32) == 0); - CHECK(value == 11); - CHECK(min_value == 0); - CHECK(max_value == 15); - CHECK(m_len == 192); /* length of the sidechannel in the proof */ - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(message, message_2, sizeof(message_2)) == 0); - for (i = sizeof(message_2); i < m_len; i++) { - CHECK(message[i] == 0); - } -} - - /* Vector 3: single-value proof of UINT64_MAX */ -{ - static const unsigned char vector_3[] = { - 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0x7d, 0x0b, 0x79, 0x0e, 0xaf, 0x41, - 0xa5, 0x8e, 0x9b, 0x0c, 0x5b, 0xa3, 0xee, 0x7d, 0xfd, 0x3d, 0x6b, 0xf3, 0xac, 0x04, 0x8a, 0x43, - 0x75, 0xb0, 0xb7, 0x0e, 0x92, 0xd7, 0xdf, 0xf0, 0x76, 0xc4, 0xa5, 0xb6, 0x2f, 0xf1, 0xb5, 0xfb, - 0xb4, 0xb6, 0x29, 0xea, 0x34, 0x9b, 0x16, 0x30, 0x0d, 0x06, 0xf1, 0xb4, 0x3f, 0x0d, 0x73, 0x59, - 0x75, 0xbf, 0x5d, 0x19, 0x59, 0xef, 0x11, 0xf0, 0xbf - }; - static const unsigned char commit_3[] = { - 0x08, - 0xc7, 0xea, 0x40, 0x7d, 0x26, 0x38, 0xa2, 0x99, 0xb9, 0x40, 0x22, 0x78, 0x17, 0x57, 0x65, 0xb3, - 0x36, 0x82, 0x18, 0x42, 0xc5, 0x57, 0x04, 0x5e, 0x58, 0x5e, 0xf6, 0x40, 0x8b, 0x24, 0x73, 0x10 - }; - static const unsigned char nonce_3[] = { - 0x84, 0x50, 0x94, 0x69, 0xa3, 0x4b, 0x6c, 0x62, 0x1a, 0xc7, 0xe2, 0x0e, 0x07, 0x9a, 0x6f, 0x85, - 0x5f, 0x26, 0x50, 0xcd, 0x88, 0x5a, 0x9f, 0xaa, 0x23, 0x5e, 0x0a, 0xe0, 0x7e, 0xc5, 0xe9, 0xf1 - }; - static const unsigned char blind_3[] = { - 0x68, 0x89, 0x47, 0x8c, 0x77, 0xec, 0xcc, 0x2b, 0x65, 0x01, 0x78, 0x6b, 0x06, 0x8b, 0x38, 0x94, - 0xc0, 0x6b, 0x9b, 0x4c, 0x02, 0xa6, 0xc8, 0xf6, 0xc0, 0x34, 0xea, 0x35, 0x57, 0xf4, 0xe1, 0x37 - }; - - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commitment_parse(ctx, &pc, commit_3)); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify( - ctx, - &min_value, &max_value, - &pc, - vector_3, sizeof(vector_3), - NULL, 0, - rustsecp256k1zkp_v0_8_0_generator_h - )); - CHECK(min_value == UINT64_MAX); - CHECK(max_value == UINT64_MAX); - - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind( - ctx, - blind, &value, - message, &m_len, - nonce_3, - &min_value, &max_value, - &pc, - vector_3, sizeof(vector_3), - NULL, 0, - rustsecp256k1zkp_v0_8_0_generator_h - )); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(blind, blind_3, 32) == 0); - CHECK(value == UINT64_MAX); - CHECK(min_value == UINT64_MAX); - CHECK(max_value == UINT64_MAX); - CHECK(m_len == 0); -} -} - -static void print_vector_helper(unsigned char *buf, size_t buf_len) { - size_t j; - printf(" "); - for (j = 0; j < buf_len; j++) { - printf("0x%02x", buf[j]); - if (j == buf_len-1) { - printf(",\n"); - } else if ((j+1) % 16 != 0) { - printf(", "); - } else { - printf(",\n"); - printf(" "); - } - } - printf("};\n"); -} - -static void print_vector(int i, unsigned char *proof, size_t p_len, rustsecp256k1zkp_v0_8_0_pedersen_commitment *commit) { - unsigned char commit_output[33]; - - printf("unsigned char vector_%d[] = {\n", i); - print_vector_helper(proof, p_len); - - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commitment_serialize(ctx, commit_output, commit)); - printf("unsigned char commit_%d[] = {\n", i); - print_vector_helper(commit_output, sizeof(commit_output)); -} - - -/* Use same nonce and blinding value for all "reproducible" test vectors */ -static unsigned char vector_blind[] = { - 0x48, 0x26, 0xad, 0x41, 0x37, 0x4c, 0x25, 0x62, 0x52, 0x14, 0x78, 0x82, 0x89, 0x9c, 0x86, 0x27, - 0xa1, 0x19, 0xf6, 0xe1, 0xfa, 0x44, 0xe4, 0x29, 0x08, 0xa7, 0xb3, 0x45, 0xad, 0x35, 0xb2, 0xd9, -}; -static unsigned char vector_nonce[] = { - 0xc8, 0x5c, 0x7e, 0x6c, 0xa1, 0xfa, 0x11, 0x35, 0xc7, 0x45, 0x24, 0x8a, 0xb5, 0x28, 0x6d, 0x1a, - 0x88, 0x00, 0xff, 0xca, 0x96, 0x0f, 0xc7, 0x77, 0xa5, 0x96, 0x7a, 0x5e, 0xf8, 0x88, 0x2d, 0xd4, -}; - -/* Maximum length of a message that can be embedded into a rangeproof */ -void test_rangeproof_fixed_vectors_reproducible_helper(unsigned char *vector, size_t vector_len, unsigned char *commit, uint64_t *value_r, uint64_t *min_value_r, uint64_t *max_value_r, unsigned char *message_r, size_t *m_len_r) { - rustsecp256k1zkp_v0_8_0_pedersen_commitment pc; - unsigned char blind_r[32]; - - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commitment_parse(ctx, &pc, commit)); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_verify( - ctx, - min_value_r, max_value_r, - &pc, - vector, vector_len, - NULL, 0, - rustsecp256k1zkp_v0_8_0_generator_h - )); - - *m_len_r = SECP256K1_RANGEPROOF_MAX_MESSAGE_LEN; - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_rewind( - ctx, - blind_r, value_r, - message_r, m_len_r, - vector_nonce, - min_value_r, max_value_r, - &pc, - vector, vector_len, - NULL, 0, - rustsecp256k1zkp_v0_8_0_generator_h - )); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(blind_r, vector_blind, sizeof(vector_blind)) == 0); -} - -void test_rangeproof_fixed_vectors_reproducible(void) { - uint64_t value_r; - uint64_t min_value_r; - uint64_t max_value_r; - unsigned char message[SECP256K1_RANGEPROOF_MAX_MESSAGE_LEN], message_r[SECP256K1_RANGEPROOF_MAX_MESSAGE_LEN]; - size_t m_len_r; - memset(message, 0xFF, sizeof(message)); - - /* Test maximum values for value, min_bits, m_len and exp */ - { - uint64_t value = UINT64_MAX; - uint64_t min_value = 0; - size_t m_len = sizeof(message); /* maximum message length */ - - int min_bits = 64; - int exp = 18; - unsigned char proof[5126]; - size_t p_len = sizeof(proof); - rustsecp256k1zkp_v0_8_0_pedersen_commitment pc; - - unsigned char vector_0[] = { - 0x40, 0x3f, 0xd1, 0x77, 0x65, 0x05, 0x87, 0x88, 0xd0, 0x3d, 0xb2, 0x24, 0x60, 0x7a, 0x08, 0x76, - 0xf8, 0x9f, 0x5a, 0x00, 0x73, 0x32, 0x6b, 0x5b, 0x0b, 0x59, 0xda, 0xa0, 0x6d, 0x2b, 0x66, 0xb8, - 0xfa, 0xa4, 0x8c, 0xf9, 0x78, 0x5e, 0xe3, 0xc7, 0x30, 0xea, 0xb4, 0x31, 0x77, 0x3a, 0xe4, 0xe3, - 0xf0, 0x76, 0x15, 0x21, 0x07, 0xb3, 0x6e, 0x84, 0x36, 0xdb, 0x45, 0xe6, 0x2b, 0x14, 0x50, 0xf3, - 0x53, 0x5d, 0x79, 0xf8, 0x6d, 0xc4, 0x99, 0x36, 0xa4, 0x7c, 0xc1, 0x14, 0x90, 0x99, 0xa8, 0x4b, - 0xf0, 0x01, 0x9f, 0xe7, 0xd4, 0xf9, 0xf1, 0x74, 0xb0, 0x7f, 0xf5, 0x90, 0x8d, 0x27, 0x9e, 0x61, - 0x9e, 0xc5, 0xd0, 0xa6, 0x32, 0xe8, 0x64, 0x4a, 0x02, 0x8b, 0xbf, 0xf7, 0xb8, 0x31, 0xa3, 0x4d, - 0x99, 0xbe, 0x12, 0x77, 0x4b, 0x07, 0x4a, 0xef, 0x75, 0xb4, 0xb3, 0x6e, 0x96, 0x95, 0xff, 0xe9, - 0xf7, 0xfc, 0x27, 0x17, 0x62, 0xfa, 0x99, 0xed, 0x00, 0x3c, 0xdd, 0xaa, 0xae, 0x9e, 0x80, 0xc1, - 0x29, 0x73, 0x4d, 0xfc, 0x41, 0xe6, 0xb4, 0x21, 0xe2, 0x62, 0x78, 0xf5, 0x46, 0xef, 0xcd, 0xcf, - 0x15, 0x2a, 0x05, 0x80, 0xb9, 0x95, 0xaa, 0xa5, 0xe9, 0x69, 0x5f, 0xfd, 0x58, 0x12, 0x00, 0x51, - 0xc4, 0x8f, 0xa2, 0xce, 0x03, 0x7f, 0x16, 0x19, 0xb1, 0x77, 0xc2, 0x98, 0xbe, 0xaa, 0x18, 0x6a, - 0x80, 0x0b, 0x4a, 0x81, 0x85, 0xc0, 0xc2, 0x62, 0xb3, 0xec, 0xae, 0xe7, 0x95, 0xbf, 0xd3, 0xe0, - 0xcd, 0xa3, 0xdd, 0x02, 0x70, 0x98, 0x6c, 0xf3, 0x4b, 0x43, 0xec, 0x8d, 0x07, 0xf4, 0x3e, 0xb0, - 0x00, 0x7c, 0xb7, 0x1a, 0x85, 0x9a, 0x94, 0xe8, 0x57, 0xc9, 0x7e, 0x24, 0xb4, 0x7a, 0x84, 0x17, - 0x08, 0xe6, 0xae, 0x91, 0x14, 0xcb, 0x94, 0xf3, 0xe9, 0x13, 0x25, 0x35, 0x54, 0xbf, 0x22, 0xe9, - 0xab, 0x8e, 0xa4, 0xa1, 0x18, 0x78, 0x6c, 0xee, 0x13, 0x26, 0xfc, 0x79, 0xf1, 0xe5, 0x51, 0x1e, - 0x0c, 0xac, 0xa5, 0xef, 0x0d, 0xee, 0xe8, 0x5f, 0x93, 0xa4, 0x88, 0x4a, 0x32, 0x95, 0x8a, 0x61, - 0x76, 0xd8, 0xac, 0x2d, 0x36, 0x9a, 0x6b, 0xa4, 0x7c, 0x30, 0xa3, 0x09, 0x38, 0xbb, 0xbc, 0x51, - 0x1a, 0x10, 0xae, 0x9e, 0x18, 0x9f, 0xd8, 0xc8, 0xce, 0xfa, 0x63, 0xab, 0x28, 0xc9, 0x76, 0x28, - 0x32, 0x61, 0x39, 0x83, 0x99, 0x0a, 0x41, 0xc0, 0x55, 0x1c, 0x65, 0x6c, 0xcf, 0xc3, 0x72, 0x47, - 0xe7, 0xb1, 0x99, 0xb5, 0x04, 0x44, 0xb9, 0xde, 0x4b, 0x83, 0x37, 0x66, 0xb2, 0xee, 0x9f, 0x07, - 0xf1, 0x4f, 0x4d, 0x59, 0xee, 0x37, 0x79, 0x47, 0x0e, 0x31, 0x70, 0x3a, 0xfa, 0xe0, 0xa1, 0xef, - 0xa2, 0x1f, 0xeb, 0xe8, 0xd7, 0x4f, 0xcb, 0xc2, 0xce, 0xdc, 0x82, 0xa6, 0x36, 0xed, 0x1d, 0xdd, - 0xa6, 0x40, 0x10, 0x38, 0x4f, 0x28, 0x90, 0xc3, 0xe3, 0xb6, 0xa4, 0x74, 0xbb, 0x56, 0x23, 0x01, - 0x3a, 0xb6, 0xb1, 0xad, 0x94, 0x4b, 0x52, 0x42, 0x0a, 0x9d, 0xd6, 0x89, 0xdd, 0xa7, 0x0f, 0x66, - 0xdb, 0x4e, 0x5b, 0xa4, 0xc2, 0x11, 0xd7, 0xd5, 0xf7, 0x0a, 0xf1, 0xc8, 0x35, 0x16, 0xc0, 0x7d, - 0x29, 0x5d, 0x5c, 0x62, 0x6b, 0xe0, 0x1b, 0x74, 0x8d, 0x14, 0x9e, 0x08, 0xb6, 0x18, 0x0d, 0x2b, - 0x3a, 0xfb, 0x22, 0x9e, 0xd6, 0x77, 0x05, 0x1b, 0xd4, 0x5d, 0x25, 0x27, 0x97, 0x40, 0x93, 0x58, - 0x35, 0xad, 0xc5, 0x19, 0x96, 0x62, 0xbb, 0x10, 0x2d, 0x4e, 0x24, 0x62, 0xc0, 0x1a, 0xe6, 0x12, - 0x84, 0xac, 0x1b, 0x5e, 0x25, 0xa9, 0xc7, 0x5d, 0xa0, 0x34, 0x85, 0x70, 0xf1, 0x08, 0xd8, 0xf9, - 0x1c, 0x1b, 0x71, 0xcc, 0x72, 0xec, 0xce, 0x30, 0x91, 0x67, 0xac, 0xe5, 0x4e, 0x51, 0xa6, 0x47, - 0x74, 0x09, 0x19, 0xee, 0x9d, 0x2d, 0x3f, 0xf2, 0x49, 0x5a, 0xf0, 0x6c, 0x8f, 0xe9, 0x1f, 0x10, - 0xcc, 0x32, 0x2f, 0x8d, 0x3e, 0xfa, 0xba, 0x0c, 0x37, 0x51, 0xe2, 0x3e, 0xcc, 0xdd, 0x81, 0xd5, - 0xef, 0xef, 0x56, 0x3a, 0xd2, 0x96, 0x10, 0xfb, 0x19, 0xce, 0x90, 0xbf, 0x82, 0x11, 0xf6, 0xe6, - 0x28, 0x7e, 0x4d, 0x16, 0x61, 0x87, 0xdd, 0xc5, 0x61, 0x5d, 0x85, 0xa9, 0x02, 0xea, 0xdf, 0x7a, - 0x2c, 0x92, 0xdd, 0xc3, 0xa3, 0xc9, 0xec, 0xd9, 0xc0, 0x54, 0xbd, 0xf2, 0x77, 0x00, 0x5e, 0x18, - 0x8c, 0x0a, 0x63, 0xdf, 0x8f, 0xf9, 0x1e, 0x45, 0x1c, 0xd1, 0xf7, 0x11, 0x1e, 0xbd, 0x20, 0x30, - 0x1c, 0x27, 0x45, 0xfe, 0xb7, 0xe6, 0x93, 0xae, 0x2a, 0xc1, 0xdc, 0xe2, 0xf6, 0xd1, 0x54, 0x42, - 0xa3, 0x26, 0x79, 0xd6, 0xb3, 0x5c, 0xb0, 0xd2, 0x97, 0x3e, 0xc0, 0x0e, 0xce, 0xf4, 0x82, 0x42, - 0x99, 0x49, 0xb7, 0xad, 0x33, 0xd6, 0x67, 0x81, 0xaf, 0x40, 0xa2, 0xbd, 0x71, 0x7e, 0x82, 0x66, - 0x8d, 0x97, 0x3b, 0x9d, 0x30, 0xe8, 0x4b, 0x4d, 0xcd, 0xf0, 0x1e, 0xfb, 0x33, 0xbd, 0xcd, 0xb2, - 0xca, 0x7e, 0x5d, 0xa2, 0xe5, 0x6a, 0xa1, 0xc0, 0xbd, 0xae, 0x8c, 0x65, 0x93, 0x9d, 0x53, 0x6f, - 0x8d, 0xce, 0x4f, 0xc2, 0xb1, 0x54, 0x7d, 0x7a, 0x59, 0x08, 0xc0, 0xaa, 0xfc, 0x12, 0xa9, 0x41, - 0x9b, 0x11, 0x3c, 0x24, 0x3a, 0x89, 0x8f, 0x2f, 0x5a, 0x49, 0x44, 0x64, 0x83, 0x17, 0xbe, 0xa2, - 0xff, 0x6f, 0xcb, 0x65, 0x04, 0x6f, 0x75, 0x4c, 0x5d, 0x15, 0x06, 0x7b, 0x3b, 0x3e, 0xc1, 0xed, - 0xcb, 0xdc, 0xde, 0x04, 0x03, 0x30, 0x74, 0xc2, 0x6b, 0x50, 0x53, 0x6b, 0x8c, 0xcd, 0x1b, 0xe7, - 0xd5, 0xf8, 0x42, 0xe5, 0x07, 0x16, 0xc3, 0x70, 0x83, 0x49, 0x25, 0xa4, 0x1e, 0x61, 0xa8, 0xc4, - 0x13, 0x82, 0xfe, 0x56, 0xd7, 0x04, 0xbe, 0x4d, 0x59, 0x05, 0xb8, 0x35, 0xcc, 0xd2, 0xaf, 0x40, - 0x24, 0xf3, 0xbc, 0x48, 0x58, 0x0e, 0x01, 0xe6, 0x47, 0x19, 0x9d, 0xb6, 0xe3, 0x6f, 0x17, 0x5e, - 0xab, 0x6c, 0xa3, 0x5a, 0x9a, 0xdd, 0x95, 0x2a, 0x18, 0x22, 0x42, 0x36, 0x07, 0xa0, 0x47, 0xb1, - 0x2e, 0x8f, 0xc8, 0x78, 0xcc, 0x7d, 0x16, 0x61, 0x5f, 0x34, 0x66, 0xee, 0x01, 0x17, 0x60, 0xa3, - 0x3f, 0x4d, 0xb1, 0xcc, 0xcc, 0x13, 0x99, 0x51, 0x3e, 0x78, 0x69, 0x7b, 0x83, 0x49, 0x5f, 0xf3, - 0x89, 0xa9, 0x9e, 0x24, 0x18, 0x08, 0x4d, 0xdb, 0x8a, 0xb1, 0xd8, 0xd7, 0xae, 0x30, 0x82, 0x4d, - 0x3d, 0x4f, 0xce, 0xbe, 0x17, 0xe5, 0x47, 0x5d, 0xa6, 0x03, 0x8c, 0xae, 0xe7, 0xa2, 0x63, 0xf3, - 0xe8, 0x88, 0x21, 0xf4, 0xfd, 0xa9, 0x32, 0x15, 0x93, 0x0c, 0xbe, 0x61, 0xe8, 0x35, 0x6c, 0xb5, - 0xc9, 0xa9, 0xec, 0x1c, 0x7f, 0x34, 0x5b, 0xb0, 0x80, 0x6d, 0x0a, 0x52, 0x87, 0x74, 0x12, 0x90, - 0x3a, 0xf7, 0x40, 0x41, 0xe1, 0x62, 0xa5, 0xb7, 0xf0, 0x5d, 0x45, 0x3e, 0x55, 0x1a, 0x30, 0xec, - 0x5d, 0x52, 0x00, 0x76, 0x38, 0x10, 0x0d, 0xf0, 0x2f, 0x7f, 0xf2, 0x3e, 0x34, 0x1f, 0x1a, 0xd9, - 0xf8, 0xb9, 0x86, 0xf9, 0xdc, 0x05, 0xe0, 0xcf, 0x28, 0x49, 0xfd, 0x21, 0x64, 0xf6, 0xa1, 0xc4, - 0xf7, 0xce, 0x91, 0xb2, 0x15, 0xdf, 0x82, 0x39, 0x30, 0x60, 0xf3, 0xd1, 0xa6, 0x18, 0xc4, 0x3b, - 0xf7, 0xd2, 0x64, 0xe8, 0xab, 0x67, 0x23, 0xb8, 0x2c, 0x57, 0x84, 0x17, 0xc0, 0x2c, 0x21, 0xfc, - 0x55, 0x8b, 0xb6, 0x06, 0xbf, 0x79, 0x7e, 0x29, 0x5a, 0xfb, 0x5c, 0xa5, 0x5a, 0xe4, 0x46, 0xac, - 0x16, 0x8e, 0xf4, 0x03, 0xb7, 0xbb, 0xb0, 0x7b, 0xbf, 0xd3, 0x84, 0xbe, 0xb5, 0x6a, 0xc8, 0x28, - 0xe8, 0x2c, 0x2d, 0x0b, 0x7d, 0x0a, 0x65, 0xd3, 0xee, 0x54, 0x8c, 0xbf, 0xd9, 0xda, 0x84, 0x21, - 0x80, 0x07, 0x68, 0x09, 0x75, 0xbd, 0xa8, 0xd0, 0xbf, 0xa0, 0xf3, 0xc7, 0xc5, 0xb5, 0xf2, 0xf8, - 0xf1, 0x74, 0x6e, 0x7d, 0xad, 0x80, 0xbd, 0x87, 0xe9, 0x83, 0x2e, 0xda, 0x61, 0x28, 0x03, 0x74, - 0xe5, 0x45, 0x74, 0x0d, 0x1f, 0x47, 0x46, 0x10, 0x7f, 0xef, 0x12, 0x9f, 0x78, 0xec, 0x03, 0xed, - 0x22, 0x86, 0x6f, 0x1a, 0x31, 0x14, 0xf4, 0x3a, 0x7f, 0xef, 0x98, 0x3e, 0x64, 0x86, 0xb9, 0x0e, - 0x5b, 0x0d, 0x55, 0xba, 0xcc, 0x6d, 0x04, 0xc7, 0x9c, 0x1e, 0xd4, 0xf7, 0xf0, 0x60, 0x6d, 0x54, - 0x75, 0x70, 0x3b, 0x99, 0xd3, 0x01, 0x9f, 0x34, 0x44, 0x98, 0xab, 0xd1, 0x6b, 0xc8, 0xaa, 0xfd, - 0xd9, 0x5a, 0xd3, 0xee, 0x5d, 0x2c, 0x54, 0x38, 0x06, 0x1f, 0x93, 0xb3, 0x5c, 0x87, 0x10, 0x5e, - 0xcb, 0xcd, 0xd3, 0x4a, 0x89, 0xd2, 0x0d, 0xac, 0xeb, 0x42, 0x67, 0x2b, 0xd1, 0x75, 0x12, 0x58, - 0xdd, 0x19, 0xe3, 0x21, 0x33, 0x75, 0xf6, 0x51, 0x25, 0xeb, 0xa6, 0x43, 0x44, 0x82, 0x64, 0xae, - 0xb8, 0x97, 0x01, 0xff, 0x17, 0x8f, 0xce, 0x96, 0xc8, 0xc3, 0x86, 0xa0, 0x05, 0xb2, 0x2c, 0x33, - 0x01, 0x27, 0x25, 0x84, 0x83, 0x85, 0x33, 0xe2, 0xd0, 0xc5, 0x65, 0x89, 0x85, 0x45, 0x81, 0x3f, - 0x2d, 0xb4, 0xb1, 0x8b, 0x1d, 0x04, 0x5d, 0x4c, 0xd8, 0x46, 0x8a, 0x04, 0x3a, 0x3b, 0xa7, 0x76, - 0x47, 0x5e, 0xcc, 0xc0, 0x16, 0xb2, 0x3a, 0x38, 0x9a, 0x6a, 0x50, 0x3a, 0x8b, 0x82, 0xb7, 0x6b, - 0xf2, 0x60, 0x53, 0x4e, 0xdf, 0x8a, 0x02, 0x9f, 0xc6, 0x27, 0x4f, 0xf5, 0x2a, 0xf1, 0xf1, 0x2f, - 0x4a, 0xaa, 0xc7, 0x94, 0xc0, 0xdc, 0xdb, 0x8c, 0x41, 0xd9, 0x16, 0x13, 0xa2, 0xae, 0x37, 0x2a, - 0x7e, 0x26, 0x6f, 0xdf, 0x46, 0x07, 0x74, 0x88, 0x62, 0xab, 0x28, 0x64, 0x12, 0x7c, 0xca, 0xd5, - 0xbb, 0x6f, 0x7f, 0x3b, 0x44, 0x99, 0x20, 0x93, 0x9a, 0xa0, 0xac, 0x17, 0xed, 0x82, 0xf9, 0x43, - 0xc2, 0x98, 0x6b, 0xcf, 0x54, 0x91, 0xfe, 0x3c, 0x9e, 0xfa, 0x7b, 0x57, 0x38, 0xe2, 0x64, 0x58, - 0x9c, 0xe0, 0x41, 0x95, 0x8a, 0xa0, 0xa3, 0x3d, 0x7b, 0x3e, 0x99, 0xea, 0xc7, 0xec, 0x82, 0xc8, - 0xa8, 0xae, 0xbd, 0xf9, 0x5c, 0x7e, 0xa2, 0x20, 0x78, 0xce, 0x4a, 0x6c, 0x74, 0x2a, 0xe7, 0x31, - 0xdb, 0xc1, 0x02, 0x49, 0x4b, 0x83, 0x0b, 0x0e, 0x7e, 0xeb, 0x69, 0x59, 0xf9, 0x3c, 0x13, 0x47, - 0xaf, 0xbd, 0x58, 0xec, 0x7f, 0xae, 0x7e, 0x4b, 0xf3, 0x3d, 0x18, 0xbf, 0xb0, 0x79, 0x92, 0x59, - 0x9e, 0x5f, 0x03, 0x30, 0x15, 0xba, 0xec, 0xd1, 0xaf, 0x2e, 0xf7, 0x88, 0xde, 0x50, 0xae, 0x9e, - 0x59, 0x14, 0xf3, 0xa5, 0x78, 0x25, 0xd7, 0xd9, 0x1a, 0x33, 0x81, 0x29, 0x8b, 0x93, 0xf6, 0xfa, - 0x90, 0x3d, 0x13, 0xaa, 0x0d, 0xa7, 0x8e, 0x79, 0xc0, 0x36, 0x45, 0x29, 0xa5, 0xf1, 0xfe, 0x92, - 0x1b, 0x57, 0x42, 0x58, 0xe0, 0x85, 0x15, 0xa2, 0xc9, 0xb1, 0x50, 0x08, 0x6a, 0x02, 0x46, 0xc6, - 0x1d, 0xd0, 0xf0, 0xb4, 0x5a, 0xcc, 0xd5, 0x54, 0x9d, 0xab, 0x13, 0x47, 0x9f, 0x82, 0x60, 0x9b, - 0x11, 0x64, 0x35, 0xfa, 0xef, 0x89, 0xb4, 0x87, 0x43, 0x48, 0x6e, 0x78, 0x64, 0x01, 0xbe, 0x09, - 0xd1, 0xd0, 0x40, 0xdf, 0x77, 0x6b, 0xee, 0x92, 0xc5, 0xff, 0x77, 0xcf, 0x20, 0x95, 0x36, 0x78, - 0x35, 0x1f, 0x1e, 0xaf, 0x4b, 0xa7, 0x66, 0x71, 0x9d, 0x5e, 0xb7, 0xd9, 0x70, 0x6e, 0xaa, 0x35, - 0x49, 0x3c, 0x9a, 0x23, 0x53, 0xaf, 0x3e, 0x9d, 0x60, 0x72, 0xb5, 0x27, 0x33, 0x80, 0x33, 0xd2, - 0x11, 0x4b, 0xff, 0xfb, 0x53, 0xab, 0x14, 0x4c, 0xe4, 0xe7, 0xbc, 0x2f, 0x5c, 0xd8, 0xbf, 0x81, - 0x5c, 0xf7, 0x4d, 0x5d, 0xb8, 0x84, 0x62, 0xf3, 0xd2, 0x0a, 0x53, 0x66, 0xd3, 0x13, 0xff, 0xb0, - 0xeb, 0x4b, 0x1f, 0x10, 0x1d, 0xa9, 0xba, 0x5c, 0xad, 0xe2, 0x52, 0x91, 0xae, 0xbe, 0x5d, 0x05, - 0x54, 0x6d, 0x72, 0x1e, 0xc1, 0x14, 0xb5, 0x9b, 0x22, 0x3f, 0x78, 0x73, 0x5e, 0x99, 0x50, 0xde, - 0xa8, 0x41, 0x31, 0xd0, 0x44, 0xf3, 0x2f, 0x31, 0xd9, 0x0b, 0x72, 0x1a, 0xd3, 0x70, 0xbe, 0x84, - 0xfc, 0xe1, 0xed, 0x15, 0xb9, 0xe9, 0x69, 0xe2, 0xbe, 0x50, 0xa2, 0xda, 0x4e, 0x7a, 0x83, 0xc5, - 0x56, 0xea, 0xaf, 0x2c, 0xc9, 0x8f, 0xcc, 0x83, 0x1a, 0xa5, 0x0e, 0x74, 0xaa, 0x64, 0x96, 0xb5, - 0x5a, 0x4a, 0x72, 0xad, 0x86, 0x5a, 0xb8, 0x5a, 0x04, 0x0d, 0x68, 0x21, 0x63, 0x23, 0x7b, 0x17, - 0x9d, 0xfd, 0x1b, 0x3f, 0xac, 0x80, 0x98, 0x97, 0xb5, 0xd4, 0xb7, 0x08, 0x50, 0xf4, 0x18, 0xf9, - 0x16, 0xb1, 0x57, 0xfa, 0xff, 0xa8, 0x02, 0x6e, 0x62, 0x7b, 0x15, 0x8d, 0xc0, 0x17, 0xdd, 0xa3, - 0x45, 0x98, 0x5a, 0xa0, 0xda, 0xe2, 0xd1, 0x17, 0x91, 0x3d, 0xda, 0x18, 0x16, 0x19, 0x3a, 0xfb, - 0xfd, 0x44, 0x72, 0x03, 0x97, 0x72, 0x1d, 0xbf, 0x11, 0xca, 0x95, 0x05, 0x6a, 0x9e, 0x41, 0x3d, - 0x85, 0xb4, 0xd9, 0xb3, 0x88, 0xd4, 0xd9, 0xfb, 0x1c, 0xd2, 0x35, 0x31, 0x12, 0xcc, 0xf3, 0x03, - 0x50, 0x8a, 0xfb, 0x0e, 0x72, 0xeb, 0x86, 0x65, 0xd5, 0x96, 0x0f, 0x53, 0x1e, 0x13, 0x99, 0x91, - 0xa7, 0x70, 0xab, 0x4c, 0xa6, 0x1a, 0xb7, 0x0d, 0x71, 0x0e, 0xb6, 0x17, 0x85, 0xdf, 0x9b, 0x74, - 0x19, 0x4a, 0xc7, 0x55, 0x0e, 0xe9, 0x22, 0x6b, 0x8e, 0xa8, 0x5e, 0x45, 0xc4, 0x0f, 0x36, 0xbb, - 0x21, 0xda, 0x97, 0xcf, 0xed, 0x41, 0xb5, 0x00, 0x26, 0xb1, 0x70, 0x43, 0x5c, 0x60, 0x59, 0x23, - 0x19, 0xc5, 0xdb, 0x49, 0xef, 0xdd, 0x5d, 0x19, 0x5f, 0x58, 0xaa, 0x20, 0xd9, 0x09, 0x17, 0x09, - 0xc7, 0x5f, 0xb9, 0x65, 0x8f, 0x0a, 0xe8, 0x4d, 0x7d, 0x60, 0x88, 0x7a, 0x53, 0x9e, 0xf1, 0x25, - 0xcd, 0xa1, 0x3e, 0xc6, 0xc5, 0x86, 0xf2, 0xee, 0x60, 0x0f, 0x11, 0x3e, 0xe3, 0x90, 0x4d, 0xff, - 0x49, 0x0b, 0x2f, 0x85, 0x7f, 0x18, 0x53, 0x4e, 0xe2, 0x5c, 0x06, 0x61, 0x51, 0x08, 0xca, 0x55, - 0x80, 0x83, 0xa4, 0x80, 0x05, 0x26, 0xe7, 0x29, 0xdb, 0xab, 0x94, 0x66, 0xe9, 0xbf, 0xf8, 0xd2, - 0x79, 0x71, 0x61, 0x05, 0x33, 0xc8, 0x6b, 0x5c, 0x62, 0x01, 0x7f, 0x82, 0xef, 0x5f, 0xa3, 0xf6, - 0x29, 0x86, 0xb6, 0x0a, 0xa5, 0xed, 0x3a, 0xae, 0x34, 0x12, 0xba, 0xb0, 0x80, 0xd4, 0x53, 0x79, - 0x57, 0x7d, 0xa2, 0x38, 0xfd, 0x39, 0xc1, 0xaf, 0x07, 0x8d, 0x23, 0x6b, 0xcd, 0x97, 0xe0, 0xf6, - 0x83, 0x74, 0x7c, 0x3c, 0x95, 0xdb, 0xb1, 0xf0, 0xf7, 0x9e, 0xe9, 0xe4, 0x68, 0x67, 0x18, 0x0e, - 0x00, 0x12, 0x70, 0x79, 0xc2, 0xfe, 0xde, 0x00, 0x12, 0x87, 0x00, 0xd3, 0x8a, 0xc5, 0x1b, 0xb4, - 0xd7, 0x46, 0x1d, 0x73, 0x5c, 0x51, 0x93, 0x19, 0x83, 0x1b, 0x28, 0xb9, 0x70, 0x87, 0x20, 0x34, - 0xb6, 0x7e, 0xb9, 0x1f, 0x9d, 0x15, 0xdb, 0xd7, 0xfb, 0x30, 0x92, 0xe8, 0x21, 0x6c, 0x5c, 0xdb, - 0xaf, 0x5c, 0xd5, 0xa5, 0x76, 0x4b, 0x5f, 0xc3, 0xa8, 0x73, 0x9a, 0x42, 0x04, 0x21, 0xf1, 0x49, - 0xbc, 0x47, 0xa0, 0xa7, 0x4a, 0xda, 0x16, 0x34, 0xcd, 0x62, 0xe1, 0xe0, 0x9a, 0x35, 0xf2, 0xf9, - 0xb2, 0x3c, 0xcf, 0xa6, 0x4f, 0xd7, 0x23, 0xc2, 0xd2, 0xa5, 0x5a, 0xf9, 0xfd, 0x7d, 0x25, 0x84, - 0xda, 0xda, 0x66, 0xb9, 0x99, 0x7f, 0xec, 0xfc, 0x82, 0x7c, 0xea, 0x6b, 0x23, 0x89, 0x6e, 0xab, - 0xe9, 0x43, 0xcb, 0x88, 0xcd, 0x18, 0x6e, 0xae, 0x2d, 0xf5, 0xc7, 0xe3, 0x92, 0x55, 0x0b, 0xc0, - 0x4d, 0xc8, 0xee, 0x4b, 0x7e, 0xfe, 0x84, 0x8c, 0x32, 0x33, 0xc8, 0xf1, 0xfb, 0xd8, 0x11, 0x22, - 0xd9, 0x0d, 0x2b, 0x16, 0x19, 0xba, 0x65, 0xe4, 0x99, 0x26, 0x7b, 0xa7, 0x04, 0x11, 0xfc, 0xb8, - 0x05, 0x48, 0x36, 0x43, 0x82, 0x14, 0xb7, 0x31, 0x50, 0xfd, 0x38, 0x89, 0xc1, 0x36, 0xa1, 0xd5, - 0x8e, 0x52, 0x76, 0x99, 0xc8, 0x38, 0x49, 0xb4, 0x94, 0x02, 0x96, 0x35, 0x8c, 0xc1, 0x9c, 0x7c, - 0x2b, 0xbe, 0x73, 0x62, 0x0a, 0xd3, 0x57, 0x3d, 0xdb, 0x81, 0x14, 0x7c, 0xd0, 0x4a, 0xe5, 0x2f, - 0x63, 0xbd, 0xac, 0xcf, 0x83, 0x10, 0xfd, 0x06, 0x54, 0xc0, 0x5c, 0xba, 0x96, 0x72, 0x0b, 0xcf, - 0x0a, 0x74, 0xe2, 0xbf, 0xbc, 0x1c, 0xc6, 0xd8, 0x9e, 0x7f, 0x5f, 0xbb, 0x00, 0xfe, 0x2a, 0xbd, - 0x36, 0x02, 0x56, 0x5b, 0xa2, 0x30, 0x75, 0x44, 0x62, 0xf8, 0x22, 0x24, 0x14, 0x04, 0x30, 0x26, - 0xe5, 0xb4, 0x06, 0x3d, 0xfe, 0x5c, 0x3a, 0xc7, 0xd8, 0x1d, 0x1b, 0xc9, 0x99, 0xbb, 0xa5, 0x2c, - 0x92, 0x3b, 0xaa, 0x92, 0xf2, 0x12, 0x59, 0xc1, 0xd7, 0xec, 0xae, 0x89, 0x45, 0xfb, 0xe6, 0x15, - 0xa7, 0xe8, 0xad, 0x26, 0xf9, 0xb3, 0xe0, 0xd5, 0x57, 0xab, 0x4c, 0xab, 0xda, 0xe0, 0xc2, 0x9d, - 0xb1, 0x12, 0x6f, 0xc9, 0x84, 0x2b, 0x66, 0x89, 0x05, 0x37, 0x2a, 0x6b, 0x8d, 0xe8, 0x21, 0xa4, - 0xbb, 0x28, 0xc4, 0xb4, 0xa6, 0x93, 0xc2, 0xc9, 0x54, 0x39, 0x38, 0x84, 0xae, 0x70, 0x9b, 0xcf, - 0xc5, 0xc5, 0x3c, 0x56, 0x21, 0xb4, 0x95, 0xb0, 0xa7, 0x2a, 0x30, 0xd8, 0xcb, 0x18, 0x22, 0x31, - 0x59, 0x01, 0x62, 0x43, 0xe2, 0x65, 0xb9, 0xf3, 0xc6, 0x5c, 0x9c, 0xe1, 0xea, 0x48, 0x6f, 0x10, - 0xc2, 0x27, 0x3a, 0xd6, 0xd1, 0x15, 0xeb, 0x7f, 0xc9, 0x2b, 0x21, 0x25, 0xae, 0x91, 0x34, 0xd0, - 0x6b, 0xfe, 0xe3, 0x79, 0x52, 0xb9, 0xb2, 0x17, 0xd6, 0x6b, 0xf0, 0xfa, 0x3f, 0x15, 0xb5, 0x74, - 0x10, 0xf9, 0xd9, 0xb0, 0xc5, 0xdb, 0x72, 0x1a, 0x76, 0xeb, 0x41, 0x6f, 0xb5, 0x9b, 0x8d, 0xb9, - 0x8f, 0x75, 0x6d, 0xc8, 0x25, 0xfa, 0xee, 0xdb, 0x1c, 0x3c, 0x01, 0x80, 0x38, 0x5b, 0x83, 0x01, - 0xc0, 0x02, 0xa1, 0x1c, 0x71, 0xef, 0xbc, 0x58, 0xa5, 0xf6, 0x49, 0xb7, 0xef, 0x9c, 0xa7, 0x7d, - 0x39, 0xcc, 0x2a, 0x0b, 0xdb, 0x78, 0xb7, 0x5d, 0x22, 0x36, 0xb1, 0x36, 0x72, 0x56, 0x62, 0x19, - 0xf1, 0x5c, 0x0a, 0x63, 0x02, 0x6a, 0x59, 0x8e, 0x24, 0xb6, 0x32, 0x21, 0x11, 0x96, 0xd2, 0x8c, - 0xf1, 0xaf, 0x84, 0x3f, 0xf5, 0x98, 0x0d, 0x22, 0x14, 0x15, 0xda, 0x9f, 0x44, 0x0b, 0x08, 0x33, - 0x13, 0x11, 0x53, 0x78, 0xe1, 0xf1, 0x4b, 0x40, 0x1c, 0x43, 0x73, 0x5d, 0x86, 0x06, 0xe1, 0x02, - 0x79, 0x3f, 0x68, 0x00, 0xb7, 0xb0, 0xcb, 0x3b, 0x2e, 0x12, 0x4e, 0x81, 0x77, 0x2a, 0xc5, 0x74, - 0xc4, 0xd9, 0xa0, 0x1e, 0xa3, 0x74, 0x17, 0x61, 0x15, 0xaf, 0xa7, 0xb4, 0x25, 0x61, 0x85, 0x60, - 0x70, 0x85, 0xfb, 0x43, 0xb9, 0x43, 0x4f, 0x87, 0x44, 0x1a, 0x7b, 0xee, 0x68, 0xbb, 0x74, 0x99, - 0xff, 0x81, 0x22, 0xb4, 0x8d, 0x94, 0xf0, 0x4a, 0x3e, 0x28, 0xf5, 0xbd, 0x5c, 0xa1, 0x7f, 0x5c, - 0xea, 0xe6, 0xba, 0xf2, 0x5d, 0x85, 0xf2, 0xed, 0xd7, 0xfd, 0x93, 0xf0, 0xbb, 0xba, 0x86, 0x23, - 0xb5, 0xee, 0xb5, 0x5b, 0xd9, 0x91, 0xbf, 0xdc, 0xe3, 0xdc, 0xbe, 0x82, 0x92, 0xce, 0xb4, 0x0f, - 0xbf, 0xf1, 0x80, 0x0f, 0xe8, 0xc3, 0x04, 0x49, 0x3e, 0x95, 0x72, 0xf8, 0x36, 0x44, 0xce, 0xf4, - 0x3a, 0x6a, 0xeb, 0xdd, 0x88, 0x28, 0x8d, 0xf3, 0x04, 0x65, 0xd8, 0xfd, 0x9d, 0xb1, 0x22, 0xbd, - 0x44, 0xe7, 0xcf, 0x0f, 0x2f, 0xfc, 0xb6, 0xd6, 0x60, 0x7a, 0x6e, 0x6a, 0x93, 0x83, 0xf1, 0x86, - 0xf4, 0xf1, 0x23, 0xb2, 0xfd, 0x4a, 0xb6, 0xcf, 0x97, 0x70, 0xae, 0xa9, 0x44, 0x94, 0x7a, 0x4e, - 0xf9, 0x1e, 0xf8, 0xdc, 0x1f, 0xf0, 0x06, 0x16, 0xdf, 0x69, 0xde, 0x70, 0xea, 0x64, 0x98, 0xe6, - 0x1f, 0x9f, 0x3a, 0xcf, 0xf6, 0xb6, 0x10, 0xb1, 0x3c, 0xd1, 0x76, 0x67, 0x6c, 0xaf, 0x3c, 0x0a, - 0xc3, 0x46, 0x31, 0x89, 0xf7, 0x7a, 0x0f, 0x9b, 0x7d, 0xd8, 0x9a, 0x81, 0x57, 0x0c, 0x37, 0xda, - 0xf7, 0xc3, 0xe5, 0x4b, 0x14, 0xe9, 0x0e, 0x8c, 0x27, 0xdc, 0x68, 0xdb, 0xd8, 0xdb, 0x8b, 0xee, - 0x4e, 0x9f, 0x93, 0x18, 0x4c, 0x75, 0xec, 0x41, 0x6f, 0xbe, 0x89, 0xe3, 0x77, 0x64, 0xbd, 0x22, - 0xa1, 0x0a, 0x16, 0x93, 0xbc, 0x7a, 0xec, 0x6e, 0x3c, 0x2d, 0x97, 0x4a, 0xb1, 0x7d, 0xb6, 0xfc, - 0x01, 0x8b, 0x87, 0x2b, 0x60, 0xe4, 0x53, 0xde, 0x72, 0xef, 0xa5, 0xdf, 0xeb, 0x2d, 0x3c, 0x01, - 0xdc, 0xfd, 0xd8, 0x3b, 0x2a, 0x16, 0x74, 0x1b, 0x26, 0x40, 0x5c, 0x4d, 0x11, 0x7f, 0xa8, 0x3f, - 0xc9, 0xe8, 0x8f, 0x6b, 0xe4, 0x96, 0x3f, 0x2b, 0x4e, 0xfa, 0x1f, 0xa5, 0x73, 0x85, 0xbb, 0xe5, - 0x6f, 0xd7, 0x0c, 0xf4, 0x46, 0x81, 0xfd, 0x0d, 0x0f, 0x70, 0x3c, 0x51, 0x46, 0x47, 0x5d, 0x37, - 0x02, 0x94, 0x52, 0x44, 0x4b, 0xac, 0x30, 0xc3, 0x72, 0xd1, 0x50, 0x5e, 0x29, 0xa2, 0x4a, 0xfb, - 0xbe, 0x8e, 0x60, 0x16, 0xb0, 0xb1, 0x82, 0xd8, 0x29, 0xf5, 0x3c, 0x72, 0x3c, 0x79, 0x9d, 0xa8, - 0x64, 0x15, 0x57, 0x7a, 0x10, 0x0f, 0xb4, 0xc0, 0x02, 0xdb, 0xc6, 0x6c, 0x37, 0xa1, 0xf3, 0x52, - 0x5c, 0xb5, 0xcd, 0x42, 0xf1, 0x43, 0x31, 0xfe, 0x0b, 0xaa, 0xcb, 0xd5, 0x0a, 0xf4, 0x69, 0x64, - 0xf5, 0x98, 0x41, 0x53, 0xed, 0x04, 0x27, 0x56, 0x4a, 0xe9, 0x4c, 0x96, 0x64, 0x29, 0xff, 0xe2, - 0xe1, 0x79, 0xf5, 0x78, 0x69, 0x43, 0xe6, 0x4e, 0x4e, 0xa8, 0x8a, 0x50, 0x15, 0x37, 0x44, 0x73, - 0x41, 0xe8, 0x21, 0xe4, 0x0a, 0x2e, 0x43, 0x2d, 0x4b, 0xd1, 0xfe, 0xf5, 0xc5, 0x30, 0x31, 0x39, - 0xfa, 0x53, 0x7a, 0x3c, 0xd5, 0x63, 0x7a, 0x5c, 0xff, 0x18, 0xf8, 0x79, 0x84, 0x73, 0x84, 0x55, - 0x61, 0x17, 0x2f, 0xad, 0x34, 0xd3, 0xf2, 0xf3, 0x2b, 0xe6, 0xe3, 0xc2, 0x0e, 0x2b, 0x28, 0xc4, - 0x92, 0xd0, 0xd3, 0x14, 0x06, 0x58, 0xbb, 0x2f, 0xdf, 0xe6, 0x3d, 0x0d, 0x6b, 0x71, 0x40, 0xc2, - 0xbf, 0x6b, 0x41, 0xae, 0x85, 0x39, 0x1c, 0xdf, 0x02, 0xf3, 0x6e, 0x85, 0x15, 0x1d, 0xb8, 0xe4, - 0xbe, 0x32, 0x77, 0x70, 0x22, 0x5b, 0xe7, 0x03, 0xd6, 0x1c, 0xab, 0x90, 0x9b, 0x0d, 0x03, 0x40, - 0x0f, 0x3d, 0x82, 0x9b, 0xb8, 0x32, 0x03, 0x99, 0xee, 0xe4, 0xa9, 0x63, 0x35, 0xec, 0xe2, 0x29, - 0xb3, 0xda, 0x4c, 0x3c, 0x4c, 0x6b, 0x4f, 0x67, 0x0a, 0x8e, 0x35, 0xe2, 0xe5, 0x3d, 0x97, 0xe6, - 0xec, 0xb2, 0x99, 0xa2, 0x7d, 0x1c, 0xf0, 0xb0, 0x6d, 0xc7, 0x14, 0xe6, 0xb1, 0x77, 0x75, 0x2d, - 0x73, 0x0e, 0xa6, 0x3b, 0x4b, 0x90, 0xac, 0xe4, 0x34, 0x60, 0x6d, 0x03, 0xba, 0xb2, 0xb4, 0xb8, - 0x11, 0xe1, 0x1c, 0xb2, 0x27, 0xbb, 0x39, 0x61, 0x47, 0x53, 0x3e, 0xb0, 0x5b, 0x0d, 0x5a, 0xc9, - 0x36, 0xd5, 0xd3, 0x99, 0xa8, 0xdb, 0x74, 0x32, 0x5b, 0x05, 0x95, 0x0d, 0x2f, 0x19, 0xa7, 0x99, - 0x2e, 0x57, 0x19, 0xde, 0x4b, 0xb9, 0x08, 0x57, 0xdc, 0x37, 0x15, 0x7d, 0x1f, 0xe5, 0x12, 0x33, - 0x91, 0xa1, 0xdd, 0xe3, 0x30, 0x2b, 0x84, 0x4c, 0xe9, 0xbd, 0x0c, 0x8b, 0x6d, 0xe4, 0x75, 0x12, - 0x41, 0x98, 0x4b, 0xab, 0x25, 0xda, 0x4b, 0xc0, 0x92, 0xb1, 0x4a, 0x32, 0x06, 0x5a, 0xac, 0x93, - 0xf2, 0x6f, 0x01, 0x4d, 0xc1, 0xac, 0xf2, 0x37, 0x8b, 0x4e, 0x03, 0xbb, 0xd0, 0x06, 0x4f, 0xfa, - 0x7d, 0xb5, 0xdc, 0x1e, 0xf3, 0x2d, 0x05, 0x29, 0x1b, 0x7e, 0x6e, 0x0e, 0x26, 0x3c, 0x11, 0x5c, - 0xaf, 0x97, 0x55, 0x5a, 0xc9, 0x4f, 0x75, 0xb5, 0x24, 0x72, 0xa7, 0x07, 0x0b, 0x02, 0xd9, 0xa2, - 0xa3, 0xb0, 0xde, 0x30, 0x22, 0xfc, 0x54, 0x14, 0xfa, 0x7b, 0x19, 0x58, 0x19, 0x59, 0x9f, 0x7d, - 0x8a, 0x63, 0xd7, 0x27, 0x66, 0xe0, 0x52, 0x05, 0x3d, 0x4e, 0x14, 0xad, 0xf5, 0xaa, 0xc5, 0x79, - 0x1a, 0x02, 0x78, 0x03, 0x2c, 0xe4, 0x86, 0x14, 0x51, 0xbc, 0xc7, 0x31, 0x58, 0x04, 0x39, 0xe9, - 0xac, 0xae, 0xaf, 0x74, 0x97, 0xef, 0x9a, 0x5a, 0x97, 0x7c, 0xf5, 0xcd, 0xa1, 0x19, 0xd6, 0x31, - 0xc2, 0x0b, 0x5e, 0x66, 0x9a, 0x7f, 0x96, 0x09, 0x59, 0xc5, 0x17, 0x5c, 0x39, 0x66, 0xa7, 0x29, - 0x31, 0xb9, 0x6d, 0xad, 0x4e, 0xc1, 0x90, 0xb9, 0x94, 0x02, 0xc3, 0xe0, 0x69, 0xb8, 0x44, 0x6b, - 0xa3, 0xa6, 0xab, 0x7e, 0xfe, 0xfa, 0x8f, 0x89, 0x60, 0xf5, 0x7e, 0x68, 0x62, 0xcf, 0x58, 0xa2, - 0x96, 0xca, 0xe5, 0x36, 0x23, 0xd9, 0x88, 0x6e, 0x8b, 0x17, 0x7e, 0xf3, 0xe5, 0xd7, 0x63, 0xb0, - 0x96, 0x82, 0x18, 0xf3, 0x10, 0x13, 0x09, 0xce, 0x7b, 0xe3, 0xd8, 0xb6, 0x5b, 0x6f, 0x0e, 0x13, - 0x1b, 0xd3, 0x49, 0x57, 0x8b, 0xa1, 0xf8, 0xbd, 0xda, 0xed, 0x0d, 0x9c, 0x6c, 0x32, 0x61, 0x03, - 0xdd, 0x39, 0x63, 0x9c, 0x6f, 0xe3, 0xe5, 0xc1, 0xd6, 0xdb, 0x26, 0x1d, 0xa2, 0x60, 0x7e, 0x7b, - 0xb2, 0x51, 0x80, 0x8f, 0x78, 0x89, 0x43, 0xaa, 0x9d, 0x76, 0xef, 0x1e, 0xdb, 0xd0, 0x51, 0xb4, - 0x8e, 0xed, 0x14, 0x42, 0xfb, 0x63, 0x5d, 0x21, 0x99, 0x30, 0x99, 0x05, 0x53, 0x25, 0xe8, 0xec, - 0xe7, 0xf1, 0x40, 0x8c, 0xba, 0xb6, 0x6a, 0xe0, 0xc7, 0x73, 0x68, 0x6c, 0x15, 0x4b, 0x42, 0xe3, - 0xda, 0x97, 0x0e, 0x40, 0xc5, 0xff, 0x98, 0x2b, 0xf2, 0x19, 0xca, 0x3d, 0x49, 0x72, 0x7a, 0x96, - 0xd5, 0x16, 0xd4, 0x2a, 0xf4, 0x5d, 0x1d, 0xd2, 0x1d, 0x22, 0x60, 0xe0, 0x18, 0xf7, 0x38, 0x04, - 0x01, 0x94, 0x45, 0xb2, 0x5f, 0xc0, 0x10, 0xce, 0x65, 0x62, 0x33, 0x61, 0x6d, 0x65, 0x15, 0x7d, - 0x39, 0xc0, 0xcf, 0xcb, 0x4c, 0xa2, 0x23, 0x1c, 0xa8, 0x42, 0x46, 0x99, 0x81, 0xdc, 0x28, 0xad, - 0xd6, 0xcc, 0x92, 0xdd, 0x06, 0x58, 0x02, 0x0c, 0xe1, 0x67, 0xf2, 0x4f, 0x7a, 0xe3, 0xde, 0xb9, - 0x65, 0x81, 0xb4, 0x59, 0x13, 0xfc, 0xa4, 0x12, 0x13, 0x41, 0x9f, 0xd2, 0xe2, 0x9e, 0xea, 0x87, - 0x6a, 0x95, 0xba, 0xae, 0x27, 0x4d, 0x12, 0xc4, 0x58, 0x2a, 0x4c, 0x18, 0x68, 0x6b, 0x3b, 0xd6, - 0xfa, 0xc5, 0x47, 0x0c, 0xfe, 0x40, 0x66, 0x5b, 0x0e, 0xe9, 0xe9, 0x01, 0x4f, 0x1c, 0x48, 0x52, - 0x19, 0xc8, 0x9d, 0xa3, 0xbe, 0x81, 0x04, 0xa1, 0xd8, 0x4e, 0x6f, 0x6e, 0x80, 0xcd, 0xf7, 0x38, - 0x63, 0x16, 0x1f, 0x27, 0x4e, 0x5e, 0x4a, 0xcb, 0xc8, 0x15, 0x62, 0x15, 0x9e, 0x4e, 0xbc, 0xfc, - 0xa3, 0x26, 0x85, 0x54, 0xe0, 0x56, 0xb9, 0xef, 0xc0, 0x6c, 0x42, 0x87, 0x35, 0x9a, 0x28, 0xc1, - 0x90, 0x2c, 0xa2, 0xc6, 0xbe, 0x9e, 0xbb, 0x11, 0x1b, 0x88, 0xa7, 0xea, 0x03, 0x82, 0x8b, 0xf5, - 0xb5, 0x72, 0x76, 0xb8, 0x30, 0x2d, 0x07, 0xb3, 0x2f, 0x35, 0x48, 0xf5, 0xc5, 0x6c, 0xd3, 0x30, - 0x98, 0x55, 0xe1, 0x68, 0x0d, 0x47, 0xcf, 0xbe, 0x29, 0x8f, 0xcf, 0x48, 0x7b, 0x79, 0x2d, 0xd8, - 0xbf, 0x52, 0xce, 0x1d, 0xdc, 0xb2, 0x22, 0xe6, 0x86, 0x30, 0x98, 0x50, 0xf4, 0x56, 0x53, 0x49, - 0x38, 0x5f, 0x6d, 0xce, 0xe9, 0x35, 0x2f, 0xcf, 0x44, 0x8a, 0x96, 0xe5, 0x0a, 0xd8, 0x62, 0x64, - 0x1b, 0xfe, 0x38, 0x83, 0x36, 0x60, 0xd4, 0x31, 0xa4, 0x63, 0x4a, 0xd7, 0xa0, 0x9b, 0x1a, 0xca, - 0x84, 0xaa, 0x30, 0xba, 0xea, 0xcc, 0x48, 0xb2, 0xb0, 0x51, 0xc5, 0x0e, 0xd6, 0x3b, 0x1b, 0xab, - 0x20, 0x4a, 0xd0, 0xd9, 0xc8, 0xf3, 0x19, 0x63, 0x07, 0x10, 0x7c, 0xcd, 0xa6, 0x5a, 0xa5, 0xcd, - 0x3b, 0x8e, 0x09, 0x7f, 0xf0, 0x54, 0xba, 0xc8, 0x2a, 0xbb, 0x1d, 0x0d, 0x76, 0xdd, 0xb1, 0x47, - 0xed, 0xb9, 0x41, 0x25, 0x43, 0x97, 0x2d, 0x27, 0xc0, 0x89, 0x81, 0x69, 0xfb, 0x02, 0x21, 0xd3, - 0xc6, 0x59, 0x65, 0x11, 0x42, 0xbc, 0x88, 0x98, 0xa0, 0x0a, 0xa1, 0xdc, 0xb1, 0xb7, 0x03, 0xc1, - 0x64, 0x8f, 0x95, 0xb3, 0x37, 0x67, 0x87, 0x5f, 0xe5, 0xf1, 0x93, 0x27, 0xe7, 0x12, 0x62, 0x5e, - 0x87, 0x52, 0x4b, 0x44, 0x5f, 0xe5, 0x45, 0x58, 0xc0, 0xfb, 0x06, 0xbc, 0x8a, 0xe0, 0xd4, 0xe5, - 0x9f, 0xf3, 0x2c, 0x20, 0x30, 0x64, 0xfe, 0x46, 0xf5, 0xf3, 0xda, 0x53, 0x42, 0x8f, 0x99, 0x7d, - 0xfb, 0x47, 0xb7, 0x4a, 0xbe, 0x66, 0xf6, 0xe1, 0x2e, 0x62, 0x87, 0x26, 0xce, 0x02, 0x9a, 0xe2, - 0xeb, 0xca, 0x64, 0xc4, 0xaa, 0x0d, 0xbc, 0x9b, 0x1e, 0x32, 0xc3, 0xf8, 0xec, 0xaf, 0x1b, 0xdb, - 0xff, 0x0c, 0x71, 0x69, 0xc6, 0xb2, 0xc0, 0x3a, 0x66, 0xee, 0xd2, 0xc9, 0x16, 0x4d, 0xaf, 0x24, - 0xfa, 0x65, 0x18, 0x75, 0xfb, 0x45, 0x25, 0xa6, 0x26, 0xfb, 0x66, 0x2a, 0x15, 0x9c, 0x85, 0xf4, - 0xda, 0x1d, 0x4f, 0x3b, 0xe2, 0x4d, 0x23, 0xeb, 0x8c, 0x57, 0xb1, 0xb5, 0x4c, 0x90, 0x23, 0x7f, - 0x01, 0xfa, 0x06, 0x9d, 0x35, 0x4c, 0x6a, 0xb5, 0x79, 0xb9, 0x00, 0x17, 0x46, 0x46, 0x54, 0x45, - 0x60, 0xed, 0xe8, 0x86, 0xc3, 0xde, 0x65, 0xdf, 0x5b, 0x40, 0x97, 0xcd, 0x77, 0x25, 0x41, 0xcd, - 0xf2, 0x89, 0xbf, 0xfe, 0x55, 0xa1, 0xf9, 0xf5, 0x7a, 0x18, 0x2d, 0x6c, 0xec, 0x28, 0xed, 0xd1, - 0x44, 0xa1, 0x98, 0x77, 0x73, 0x6f, 0xc0, 0x4c, 0x7f, 0x05, 0xc0, 0x9c, 0x19, 0xed, 0x90, 0x3c, - 0x56, 0xb6, 0xf4, 0x86, 0x2f, 0x60, 0xb3, 0x1b, 0x95, 0x58, 0x26, 0x40, 0xc2, 0xc0, 0xda, 0x24, - 0x26, 0xcb, 0x06, 0x26, 0x53, 0x30, 0x12, 0x35, 0x0b, 0xe5, 0x39, 0x80, 0x3a, 0xf7, 0xd5, 0xae, - 0xb8, 0xcb, 0xea, 0xf6, 0x4c, 0x3d, 0x81, 0xb4, 0x1f, 0x97, 0x88, 0x2c, 0x9f, 0x9c, 0x70, 0x70, - 0xd5, 0x34, 0xe8, 0x65, 0xb7, 0xdb, 0xb3, 0x33, 0x26, 0xcf, 0x95, 0xa3, 0x31, 0x6a, 0x90, 0x9f, - 0xde, 0xd3, 0x17, 0x8a, 0x24, 0xdc, 0xe1, 0x57, 0xb8, 0x28, 0x70, 0x79, 0x52, 0xd7, 0x9d, 0x6b, - 0x99, 0xbb, 0xf7, 0x14, 0x5e, 0xc0, 0x05, 0xff, 0xbc, 0x82, 0xc2, 0x20, 0x57, 0x6c, 0xbe, 0xbe, - 0x71, 0xf7, 0xdb, 0x24, 0xc3, 0x33, 0xe6, 0x26, 0x50, 0x9a, 0xfc, 0xd6, 0x35, 0xb7, 0x42, 0xc4, - 0x63, 0x22, 0x3d, 0x4c, 0x52, 0x1b, 0xf3, 0x6a, 0x38, 0x5c, 0x9b, 0xf5, 0x9b, 0xfb, 0x5f, 0x0b, - 0x37, 0x9a, 0xf2, 0x25, 0xd3, 0xd9, 0xa7, 0xc5, 0x02, 0x0f, 0x86, 0xaa, 0xee, 0x71, 0x49, 0xa2, - 0x22, 0xc2, 0x9d, 0x92, 0xc2, 0x3e, 0x8f, 0x26, 0x7f, 0x5c, 0x23, 0x62, 0xe4, 0xb5, 0xf5, 0x9e, - 0xea, 0x2f, 0xbc, 0xe8, 0x4b, 0x4d, 0xd1, 0xbd, 0x2e, 0x39, 0x04, 0x56, 0xfc, 0x0f, 0xd3, 0xd6, - 0x10, 0x16, 0xe5, 0x02, 0x11, 0x5c, 0xbc, 0x66, 0x90, 0xf1, 0xb7, 0xf6, 0x4f, 0x56, 0x0f, 0x87, - 0x2c, 0xa8, 0xb6, 0xa9, 0x30, 0xf6, 0x17, 0x1b, 0xda, 0x2c, 0x2a, 0x75, 0x09, 0xcc, 0x32, 0xe2, - 0x77, 0xc8, 0xd8, 0x98, 0x7b, 0xd4, 0x8a, 0x73, 0xda, 0xe2, 0x76, 0x78, 0x04, 0x82, 0xab, 0x11, - 0x71, 0xe3, 0x73, 0x79, 0x5e, 0xdb, 0x86, 0x79, 0x52, 0x1d, 0x28, 0xc1, 0x87, 0xa8, 0x2f, 0xca, - 0xbc, 0xb9, 0xba, 0x58, 0x4e, 0xb3, 0x89, 0x4d, 0x74, 0x88, 0x37, 0x36, 0xbb, 0x1d, 0x1d, 0xe8, - 0xc9, 0xd4, 0xe8, 0xa4, 0x31, 0x17, 0x56, 0xf4, 0x72, 0xc0, 0x00, 0x58, 0x1c, 0x76, 0xab, 0x2d, - 0x75, 0xe6, 0x90, 0x85, 0xbf, 0xdc, 0x57, 0x2f, 0xbe, 0xb1, 0xa9, 0x3c, 0xd1, 0xf6, 0x58, 0x80, - 0xcf, 0x43, 0x60, 0xb4, 0x1b, 0x82, 0x02, 0x90, 0x3c, 0xad, 0xfc, 0xef, 0xc4, 0xce, 0x9a, 0xec, - 0xea, 0x26, 0x57, 0xb9, 0x7e, 0xf7, 0x69, 0xa3, 0x06, 0x52, 0xc2, 0x51, 0x83, 0x8f, 0xf4, 0x0d, - 0xb7, 0xa3, 0xfc, 0xae, 0x29, 0x81, 0xcc, 0xdc, 0xbb, 0x2d, 0xed, 0x38, 0xf4, 0x40, 0x7a, 0x16, - 0x56, 0x11, 0x7f, 0x33, 0x50, 0x44, 0xc0, 0xb9, 0x77, 0x66, 0x6b, 0xce, 0x18, 0xd6, 0xdf, 0x39, - 0x9e, 0xa6, 0xa1, 0xbd, 0xed, 0x0e, 0xd7, 0x14, 0xe1, 0xb9, 0x6a, 0x51, 0x4b, 0x5c, 0x00, 0xdc, - 0xd7, 0xdb, 0x76, 0x69, 0xef, 0xfa, 0x2e, 0xcf, 0x4f, 0xa8, 0x2e, 0x59, 0x26, 0xa0, 0x55, 0x7e, - 0x9b, 0x55, 0xfc, 0x7c, 0x32, 0xff, 0xbf, 0x08, 0x90, 0xb5, 0x7a, 0x4f, 0xf2, 0x26, 0x05, 0x85, - 0xf6, 0x56, 0x7b, 0x56, 0x41, 0xdc, 0x95, 0xcf, 0x03, 0x45, 0xef, 0x78, 0x34, 0x30, 0x61, 0x9a, - 0x44, 0x8f, 0xbc, 0xb5, 0x5c, 0xf4, 0x64, 0x2c, 0x13, 0x21, 0x3c, 0xa5, 0x1b, 0xe7, 0x9c, 0x60, - 0x9b, 0x49, 0xe1, 0x34, 0x8a, 0xef, 0x72, 0xa7, 0xa9, 0x71, 0x6f, 0x32, 0x52, 0x64, 0x0a, 0xa0, - 0x4a, 0xf3, 0xa2, 0xee, 0x16, 0x1a, 0xbe, 0x93, 0x0a, 0xa2, 0xd8, 0xb0, 0x82, 0x3b, 0x4d, 0x7d, - 0x24, 0xe2, 0x09, 0xef, 0x6b, 0xdd, 0x92, 0x00, 0x6f, 0x76, 0xd1, 0x41, 0xde, 0xdb, 0xab, 0x6c, - 0x39, 0x4d, 0x26, 0x54, 0xb4, 0x56, 0xce, 0x4c, 0x19, 0x95, 0x2a, 0x51, 0xa9, 0xf1, 0xad, 0x58, - 0xf8, 0x6d, 0xeb, 0x32, 0xc2, 0x30, 0x03, 0x15, 0x0e, 0x9d, 0x76, 0x74, 0x5d, 0xe0, 0x62, 0xd9, - 0xc3, 0x83, 0xe4, 0xd5, 0x33, 0x1d, 0x7b, 0xfe, 0x6f, 0x16, 0x5c, 0xaf, 0x34, 0xe9, 0x2c, 0x20, - 0xca, 0x99, 0xac, 0x57, 0x47, 0x81, 0x0d, 0x57, 0x65, 0x33, 0x1a, 0x5b, 0x0c, 0xaa, 0x13, 0x00, - 0xf9, 0x3d, 0x02, 0x2c, 0xc1, 0x23, 0x7d, 0x55, 0x47, 0xdb, 0x8b, 0xcb, 0x50, 0xc1, 0xd2, 0x95, - 0xff, 0x0b, 0x8a, 0xb3, 0x38, 0x43, 0x51, 0xe1, 0x3b, 0x3b, 0xc3, 0x4b, 0x5e, 0xc9, 0xac, 0x0f, - 0xb3, 0x81, 0x32, 0xf1, 0x2e, 0xa2, 0x51, 0xea, 0xb2, 0x85, 0x1a, 0x48, 0xee, 0x35, 0xa0, 0x86, - 0x05, 0x14, 0x05, 0xc3, 0xf5, 0xe2, 0xa1, 0xdf, 0x47, 0xb0, 0xe2, 0x04, 0x21, 0x85, 0xbd, 0x0b, - 0x00, 0x98, 0xe4, 0xdb, 0xe1, 0x7a, 0xf7, 0xfd, 0x7a, 0x92, 0x45, 0x15, 0x57, 0xd7, 0xcf, 0x18, - 0xb7, 0xa3, 0xf2, 0xd5, 0xcf, 0x18, 0x7a, 0xe5, 0xa4, 0x4b, 0x0c, 0xe1, 0x66, 0xd9, 0x1b, 0x3f, - 0x60, 0x47, 0x90, 0xd1, 0xe9, 0xb8, 0xf5, 0xa8, 0x36, 0x1f, 0xab, 0x7d, 0x85, 0x9a, 0x57, 0xc6, - 0xdb, 0x9c, 0xf8, 0x90, 0xbf, 0xc7, 0xb7, 0xf5, 0xa3, 0x1d, 0x69, 0x6d, 0xe8, 0xda, 0x3d, 0xa6, - 0xaa, 0x38, 0x55, 0x30, 0x9d, 0x7a, 0xc0, 0x6d, 0x42, 0xeb, 0xc6, 0x97, 0xf3, 0x84, 0xa1, 0x0a, - 0x4c, 0x78, 0xc3, 0xdb, 0x9f, 0x29, 0x85, 0x08, 0x4d, 0x8f, 0xbe, 0x8e, 0xba, 0x68, 0x1a, 0x97, - 0x74, 0xa7, 0xd2, 0xec, 0xb9, 0x8b, 0xbf, 0x8c, 0xd7, 0xb6, 0x2e, 0x3d, 0x3b, 0x7d, 0xf8, 0x84, - 0x2b, 0x30, 0xe6, 0x40, 0x13, 0x53, 0xbe, 0x47, 0xd9, 0x14, 0x16, 0xdf, 0x05, 0xeb, 0xa3, 0x6c, - 0x74, 0xd4, 0xba, 0x8d, 0xf5, 0x80, 0xab, 0xc8, 0x40, 0x3c, 0xd5, 0x00, 0x47, 0x86, 0x66, 0x73, - 0x6b, 0x36, 0xc5, 0xa2, 0x81, 0x92, 0xd8, 0xfd, 0xde, 0x61, 0x34, 0xc3, 0x34, 0xaa, 0x1a, 0x40, - 0x3c, 0x95, 0x8f, 0x75, 0x2f, 0xc6, 0x22, 0xbb, 0x45, 0xfa, 0x68, 0x10, 0xd7, 0x22, 0x09, 0x59, - 0x36, 0x25, 0x45, 0x06, 0x9b, 0xa2, 0x33, 0xf9, 0x34, 0x63, 0xe2, 0x2b, 0x18, 0xa7, 0xbe, 0x25, - 0xf2, 0xe6, 0x9d, 0x99, 0x97, 0xb1, 0x0d, 0x64, 0x3a, 0x53, 0xcb, 0xe5, 0x73, 0xc6, 0x47, 0x3c, - 0x76, 0x87, 0xae, 0x74, 0x1f, 0x4f, 0x84, 0x2e, 0x4f, 0x10, 0xda, 0x4e, 0x32, 0x40, 0x71, 0xc4, - 0xd9, 0xac, 0x85, 0x4c, 0x6e, 0x10, 0x37, 0x66, 0xcd, 0x49, 0x83, 0x20, 0xa7, 0xe7, 0x47, 0x70, - 0xaf, 0x38, 0x6c, 0x95, 0x32, 0x6e, 0x7f, 0x21, 0x9e, 0x2b, 0xbd, 0x09, 0x6a, 0xe0, 0xd9, 0xdf, - 0x27, 0x1e, 0x41, 0x0b, 0x1a, 0xc3, 0x6c, 0x83, 0x9f, 0x1a, 0x57, 0x5e, 0x94, 0x72, 0xc5, 0x8d, - 0x9f, 0x61, 0xe4, 0x47, 0x56, 0xb1, 0x80, 0x32, 0x3c, 0x23, 0x4c, 0x21, 0x0d, 0xdd, 0x4e, 0x5f, - 0x61, 0x8a, 0xcf, 0xee, 0x59, 0x87, 0x36, 0xe4, 0x0a, 0x24, 0x7c, 0x03, 0xda, 0x64, 0x76, 0x3c, - 0x80, 0x04, 0x3c, 0x89, 0x91, 0x9e, 0x56, 0xba, 0x66, 0x98, 0xb2, 0xfc, 0x8d, 0x81, 0xdf, 0xf4, - 0x3c, 0x0c, 0x0c, 0x03, 0xee, 0xd9, 0xb4, 0xb0, 0x0a, 0xcf, 0x6d, 0x0b, 0xf6, 0xe7, 0xa6, 0x21, - 0x1c, 0xe7, 0x9f, 0xa5, 0x74, 0xea, 0x18, 0x3f, 0xf7, 0x2c, 0x3c, 0x09, 0x53, 0xd6, 0xcc, 0x71, - 0xd7, 0x07, 0x9d, 0x3d, 0x59, 0xb4, 0xec, 0x86, 0xe9, 0x8b, 0xa0, 0x14, 0x99, 0xf8, 0xa6, 0x9b, - 0x59, 0xe2, 0x6e, 0x73, 0x78, 0xe0, 0xf3, 0xcb, 0xce, 0x06, 0xd0, 0x1b, 0x70, 0xd8, 0x15, 0xc2, - 0xbf, 0x04, 0xe8, 0xcb, 0x31, 0x1d, 0x04, 0x9f, 0x9d, 0xf2, 0xa1, 0x60, 0x1f, 0x63, 0x49, 0x64, - 0x56, 0x3e, 0xa1, 0x64, 0xf2, 0xb0, 0xaa, 0xdc, 0x5f, 0xa3, 0x3b, 0x8d, 0x16, 0x07, 0xa1, 0xf3, - 0xec, 0xc5, 0x7f, 0xe2, 0x1c, 0xeb, 0xb7, 0x81, 0xd3, 0xdf, 0x5f, 0xee, 0xa0, 0xe1, 0x82, 0x25, - 0x7a, 0xe2, 0x3f, 0xce, 0x3b, 0x89, 0x1f, 0xbe, 0x73, 0x9e, 0xe4, 0x46, 0x11, 0x39, 0xfc, 0x6b, - 0xe6, 0x99, 0xd6, 0x98, 0x9f, 0x8f, 0x19, 0x41, 0x90, 0x5d, 0xf1, 0x85, 0x94, 0xe7, 0x13, 0x91, - 0xe3, 0x01, 0xfd, 0x41, 0x29, 0x1d, 0xcb, 0x11, 0x13, 0xcd, 0x4c, 0x92, 0x6c, 0x15, 0x7c, 0xd1, - 0xbc, 0x50, 0x68, 0x4c, 0x46, 0xe3, 0x0f, 0x25, 0xd5, 0x6c, 0x3b, 0x53, 0x0b, 0x2f, 0x1d, 0xd2, - 0x52, 0xca, 0x97, 0x29, 0x5c, 0xdf, 0x24, 0xa8, 0xc6, 0xbe, 0xd1, 0xc1, 0x14, 0x20, 0x24, 0x4f, - 0xfa, 0xd4, 0xe5, 0xb0, 0x93, 0x45, 0xe1, 0xc9, 0xf2, 0xbe, 0x0d, 0xc2, 0xd1, 0x4c, 0xab, 0x2f, - 0x85, 0xc1, 0x0b, 0x51, 0x40, 0x7c, 0xdf, 0x7f, 0x74, 0xa1, 0x3d, 0xb8, 0x4d, 0x4f, 0x26, 0x24, - 0x11, 0x61, 0x64, 0xd3, 0x0e, 0x5b, 0x29, 0x87, 0x05, 0xfe, 0xb9, 0x78, 0xde, 0xad, 0xf9, 0xe8, - 0xc4, 0x47, 0x4d, 0xfb, 0xa8, 0x54, 0x99, 0x50, 0x1d, 0xe7, 0xaf, 0x1a, 0x12, 0x20, 0x8d, 0xcd, - 0xde, 0x8e, 0xf8, 0x26, 0x65, 0x8b, - }; - unsigned char commit_0[] = { - 0x09, 0x9e, 0x56, 0x8d, 0x5b, 0x9d, 0x2a, 0xd6, 0x1f, 0xe0, 0x81, 0x21, 0xcc, 0x15, 0xb3, 0x66, - 0x6d, 0xb4, 0xbb, 0xac, 0xdd, 0x28, 0x08, 0xab, 0x21, 0x6e, 0x35, 0xac, 0xa7, 0xe0, 0x0a, 0xa8, - 0xef, - }; - - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(ctx, &pc, vector_blind, value, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(ctx, proof, &p_len, min_value, &pc, vector_blind, vector_nonce, exp, min_bits, value, message, m_len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(p_len <= rustsecp256k1zkp_v0_8_0_rangeproof_max_size(ctx, value, min_bits)); - CHECK(p_len == sizeof(proof)); - /* Uncomment the next line to print the test vector */ - /* print_vector(0, proof, p_len, &pc); */ - CHECK(p_len == sizeof(vector_0)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(proof, vector_0, p_len) == 0); - - test_rangeproof_fixed_vectors_reproducible_helper(vector_0, sizeof(vector_0), commit_0, &value_r, &min_value_r, &max_value_r, message_r, &m_len_r); - CHECK(value_r == value); - CHECK(m_len_r == m_len); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(message_r, message, m_len_r) == 0); - CHECK(min_value_r == min_value); - CHECK(max_value_r == UINT64_MAX); - memset(message_r, 0, sizeof(message_r)); - } - - /* Test min_bits = 3 */ - { - uint64_t value = 13; - size_t m_len = 128; /* maximum message length with min_bits = 3 */ - - uint64_t min_value = 1; - int min_bits = 3; - int exp = 1; - unsigned char proof[267]; - size_t p_len = sizeof(proof); - rustsecp256k1zkp_v0_8_0_pedersen_commitment pc; - - unsigned char vector_1[] = { - 0x61, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0xcb, 0xdc, 0xbe, 0x42, 0xe6, - 0x44, 0x1e, 0xc4, 0x63, 0x9d, 0xb1, 0x93, 0x7b, 0x49, 0xdc, 0xd5, 0x6e, 0x55, 0xdd, 0x3b, 0x1e, - 0x41, 0x1c, 0x0e, 0xd7, 0x47, 0xd7, 0xf0, 0x26, 0xf7, 0xe4, 0x36, 0xbd, 0x51, 0xb9, 0x77, 0x90, - 0x33, 0xdd, 0x64, 0xe7, 0x47, 0x38, 0x49, 0x29, 0x12, 0xa8, 0x12, 0x79, 0xbc, 0x62, 0xea, 0xf9, - 0xb5, 0x51, 0x8f, 0x51, 0xea, 0x28, 0x5d, 0x30, 0x9f, 0x30, 0xd5, 0x93, 0x31, 0x56, 0x61, 0x01, - 0xd7, 0x7f, 0xa4, 0xec, 0xfc, 0xe5, 0x83, 0x52, 0x5a, 0xe0, 0x80, 0x76, 0x40, 0xb8, 0x8d, 0x67, - 0x23, 0x46, 0x8c, 0xb8, 0x74, 0x2a, 0x20, 0x12, 0x86, 0x4d, 0xd8, 0x8c, 0x23, 0x73, 0x2f, 0xbe, - 0x99, 0xa5, 0xd5, 0x8c, 0x11, 0xc7, 0xb2, 0xf9, 0xd3, 0x7c, 0x88, 0x16, 0x4d, 0x21, 0x80, 0x10, - 0x70, 0xfc, 0x1f, 0x9b, 0x0b, 0x5e, 0xbe, 0xe3, 0x65, 0xe2, 0x4f, 0xbd, 0x1d, 0xb0, 0x64, 0x0a, - 0xc5, 0xe0, 0x94, 0x8b, 0x49, 0xf7, 0xc4, 0x88, 0x5e, 0xc0, 0x2d, 0xbb, 0x98, 0x60, 0x5f, 0xd2, - 0x7a, 0x9a, 0xff, 0x9e, 0x1c, 0x1f, 0x45, 0x34, 0x08, 0x96, 0xa9, 0xd3, 0xa5, 0x4d, 0x95, 0x9c, - 0x1f, 0xe6, 0xe5, 0xdc, 0x32, 0xbb, 0x18, 0x4a, 0x76, 0x22, 0xe9, 0x75, 0x1f, 0x45, 0x6b, 0x81, - 0x70, 0x4a, 0xc8, 0x00, 0x72, 0x7a, 0xc8, 0xee, 0xed, 0xc5, 0x19, 0x8f, 0xec, 0x7b, 0x4b, 0xfd, - 0x7f, 0xc8, 0x51, 0xda, 0x28, 0x0e, 0x95, 0xd3, 0xc6, 0xc1, 0x29, 0x28, 0x3f, 0xd8, 0x3d, 0x41, - 0xde, 0xdf, 0xfc, 0x2b, 0x71, 0x3a, 0xdb, 0x78, 0xa4, 0x0e, 0x50, 0xb8, 0xf9, 0xae, 0xdb, 0x7b, - 0xb1, 0x31, 0x81, 0xc2, 0xf2, 0xb5, 0x01, 0x64, 0x8e, 0x86, 0xe2, 0x8b, 0x67, 0x13, 0xec, 0x7e, - 0xf5, 0xad, 0x9d, 0x57, 0x2b, 0x5d, 0x0c, 0x94, 0xa9, 0x89, 0x92, - }; - unsigned char commit_1[] = { - 0x09, 0xe5, 0xb3, 0x27, 0x82, 0x88, 0xeb, 0x21, 0xcd, 0xb2, 0x56, 0x37, 0x61, 0x84, 0xce, 0xc1, - 0x66, 0x16, 0x2e, 0x44, 0xc8, 0x65, 0x8e, 0xe6, 0x3a, 0x1a, 0x57, 0x2c, 0xb9, 0x6c, 0x07, 0x85, - 0xf0, - }; - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(ctx, &pc, vector_blind, value, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(ctx, proof, &p_len, min_value, &pc, vector_blind, vector_nonce, exp, min_bits, value, message, m_len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(p_len <= rustsecp256k1zkp_v0_8_0_rangeproof_max_size(ctx, value, min_bits)); - CHECK(p_len == sizeof(proof)); - /* Uncomment the next line to print the test vector */ - /* print_vector(1, proof, p_len, &pc); */ - CHECK(p_len == sizeof(vector_1)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(proof, vector_1, p_len) == 0); - - test_rangeproof_fixed_vectors_reproducible_helper(vector_1, sizeof(vector_1), commit_1, &value_r, &min_value_r, &max_value_r, message_r, &m_len_r); - CHECK(value_r == value); - CHECK(m_len_r == m_len); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(message_r, message, m_len_r) == 0); - CHECK(min_value_r == 3); - CHECK(max_value_r == 73); - memset(message_r, 0, sizeof(message_r)); - } - - /* Test large min_value */ - { - uint64_t value = INT64_MAX; - size_t m_len = 0; /* maximum message length with min_bits = 3 */ - - /* Uncomment this to recreate test vector */ - uint64_t min_value = INT64_MAX-1; - int min_bits = 1; - int exp = 0; - unsigned char proof[106]; - size_t p_len = sizeof(proof); - rustsecp256k1zkp_v0_8_0_pedersen_commitment pc; - - unsigned char vector_2[] = { - 0x60, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x81, 0xd8, 0x21, 0x12, 0x4d, 0xa4, - 0x84, 0xdd, 0x2c, 0xd1, 0x04, 0xe7, 0x08, 0x9a, 0xd3, 0x6f, 0xa5, 0xd8, 0xfc, 0x52, 0x4c, 0xba, - 0xf0, 0x83, 0xeb, 0x76, 0x9f, 0x1c, 0x03, 0xe3, 0xcf, 0x23, 0x1e, 0x40, 0x18, 0xc6, 0x6d, 0xf9, - 0x25, 0x56, 0x80, 0x3c, 0x83, 0xdd, 0x58, 0x36, 0x43, 0xe3, 0x56, 0xa0, 0xb7, 0xf0, 0x0e, 0xf9, - 0xe2, 0x8b, 0x82, 0x5a, 0x77, 0xa7, 0xbe, 0x36, 0x98, 0x10, 0x99, 0x2e, 0xaa, 0x21, 0x24, 0xe6, - 0x78, 0xa8, 0xcc, 0xc7, 0x06, 0x1c, 0x06, 0xb0, 0x03, 0x87, 0x86, 0x89, 0xce, 0x85, 0x88, 0xea, - 0xa1, 0x9d, 0x4d, 0xfd, 0x8d, 0x65, 0xbd, 0xa9, 0xd0, 0x0f, - }; - unsigned char commit_2[] = { - 0x09, 0x2a, 0x74, 0xa1, 0x9c, 0xee, 0xcb, 0x6a, 0xd1, 0xa7, 0x97, 0xbe, 0x97, 0xe7, 0xb6, 0x37, - 0x90, 0x96, 0xc2, 0x5a, 0xe5, 0xfc, 0xed, 0x91, 0xff, 0x4c, 0x67, 0x07, 0x96, 0x1d, 0x2a, 0xb3, - 0x70, - }; - - CHECK(rustsecp256k1zkp_v0_8_0_pedersen_commit(ctx, &pc, vector_blind, value, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(rustsecp256k1zkp_v0_8_0_rangeproof_sign(ctx, proof, &p_len, min_value, &pc, vector_blind, vector_nonce, exp, min_bits, value, message, m_len, NULL, 0, rustsecp256k1zkp_v0_8_0_generator_h)); - CHECK(p_len <= rustsecp256k1zkp_v0_8_0_rangeproof_max_size(ctx, value, min_bits)); - CHECK(p_len == sizeof(proof)); - /* Uncomment the next line to print the test vector */ - /* print_vector(2, proof, p_len, &pc); */ - CHECK(p_len == sizeof(vector_2)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(proof, vector_2, p_len) == 0); - - test_rangeproof_fixed_vectors_reproducible_helper(vector_2, sizeof(vector_2), commit_2, &value_r, &min_value_r, &max_value_r, message_r, &m_len_r); - CHECK(value_r == value); - CHECK(m_len_r == m_len); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(message_r, message, m_len_r) == 0); - CHECK(min_value_r == INT64_MAX-1); - CHECK(max_value_r == INT64_MAX); - memset(message_r, 0, sizeof(message_r)); - } -} - -void run_rangeproof_tests(void) { - int i; - test_api(); - - test_single_value_proof(0); - test_single_value_proof(12345678); - test_single_value_proof(UINT64_MAX); - - test_rangeproof_fixed_vectors(); - test_rangeproof_fixed_vectors_reproducible(); - for (i = 0; i < count / 2 + 1; i++) { - test_borromean(); - } - test_rangeproof(); - test_rangeproof_null_blinder(); - test_multiple_generators(); -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/main_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/main_impl.h deleted file mode 100644 index 23e70efa..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/main_impl.h +++ /dev/null @@ -1,159 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H -#define SECP256K1_MODULE_RECOVERY_MAIN_H - -#include "../../../include/secp256k1_recovery.h" - -static void rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_scalar* r, rustsecp256k1zkp_v0_8_0_scalar* s, int* recid, const rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature* sig) { - (void)ctx; - if (sizeof(rustsecp256k1zkp_v0_8_0_scalar) == 32) { - /* When the rustsecp256k1zkp_v0_8_0_scalar type is exactly 32 byte, use its - * representation inside rustsecp256k1zkp_v0_8_0_ecdsa_signature, as conversion is very fast. - * Note that rustsecp256k1zkp_v0_8_0_ecdsa_signature_save must use the same representation. */ - memcpy(r, &sig->data[0], 32); - memcpy(s, &sig->data[32], 32); - } else { - rustsecp256k1zkp_v0_8_0_scalar_set_b32(r, &sig->data[0], NULL); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(s, &sig->data[32], NULL); - } - *recid = sig->data[64]; -} - -static void rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_save(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature* sig, const rustsecp256k1zkp_v0_8_0_scalar* r, const rustsecp256k1zkp_v0_8_0_scalar* s, int recid) { - if (sizeof(rustsecp256k1zkp_v0_8_0_scalar) == 32) { - memcpy(&sig->data[0], r, 32); - memcpy(&sig->data[32], s, 32); - } else { - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&sig->data[0], r); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&sig->data[32], s); - } - sig->data[64] = recid; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - int ret = 1; - int overflow = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(input64 != NULL); - ARG_CHECK(recid >= 0 && recid <= 3); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&r, &input64[0], &overflow); - ret &= !overflow; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&s, &input64[32], &overflow); - ret &= !overflow; - if (ret) { - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_save(sig, &r, &s, recid); - } else { - memset(sig, 0, sizeof(*sig)); - } - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_serialize_compact(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *output64, int *recid, const rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature* sig) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output64 != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(recid != NULL); - - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&output64[0], &r); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&output64[32], &s); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_convert(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, const rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature* sigin) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - int recid; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(sigin != NULL); - - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin); - rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(sig, &r, &s); - return 1; -} - -static int rustsecp256k1zkp_v0_8_0_ecdsa_sig_recover(const rustsecp256k1zkp_v0_8_0_scalar *sigr, const rustsecp256k1zkp_v0_8_0_scalar* sigs, rustsecp256k1zkp_v0_8_0_ge *pubkey, const rustsecp256k1zkp_v0_8_0_scalar *message, int recid) { - unsigned char brx[32]; - rustsecp256k1zkp_v0_8_0_fe fx; - rustsecp256k1zkp_v0_8_0_ge x; - rustsecp256k1zkp_v0_8_0_gej xj; - rustsecp256k1zkp_v0_8_0_scalar rn, u1, u2; - rustsecp256k1zkp_v0_8_0_gej qj; - int r; - - if (rustsecp256k1zkp_v0_8_0_scalar_is_zero(sigr) || rustsecp256k1zkp_v0_8_0_scalar_is_zero(sigs)) { - return 0; - } - - rustsecp256k1zkp_v0_8_0_scalar_get_b32(brx, sigr); - r = rustsecp256k1zkp_v0_8_0_fe_set_b32(&fx, brx); - (void)r; - VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */ - if (recid & 2) { - if (rustsecp256k1zkp_v0_8_0_fe_cmp_var(&fx, &rustsecp256k1zkp_v0_8_0_ecdsa_const_p_minus_order) >= 0) { - return 0; - } - rustsecp256k1zkp_v0_8_0_fe_add(&fx, &rustsecp256k1zkp_v0_8_0_ecdsa_const_order_as_fe); - } - if (!rustsecp256k1zkp_v0_8_0_ge_set_xo_var(&x, &fx, recid & 1)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_gej_set_ge(&xj, &x); - rustsecp256k1zkp_v0_8_0_scalar_inverse_var(&rn, sigr); - rustsecp256k1zkp_v0_8_0_scalar_mul(&u1, &rn, message); - rustsecp256k1zkp_v0_8_0_scalar_negate(&u1, &u1); - rustsecp256k1zkp_v0_8_0_scalar_mul(&u2, &rn, sigs); - rustsecp256k1zkp_v0_8_0_ecmult(&qj, &xj, &u2, &u1); - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(pubkey, &qj); - return !rustsecp256k1zkp_v0_8_0_gej_is_infinity(&qj); -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, rustsecp256k1zkp_v0_8_0_nonce_function noncefp, const void* noncedata) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - int ret, recid; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msghash32 != NULL); - ARG_CHECK(signature != NULL); - ARG_CHECK(seckey != NULL); - - ret = rustsecp256k1zkp_v0_8_0_ecdsa_sign_inner(ctx, &r, &s, &recid, NULL, NULL, NULL, msghash32, seckey, noncefp, noncedata); - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_save(signature, &r, &s, recid); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_recover(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *pubkey, const rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature *signature, const unsigned char *msghash32) { - rustsecp256k1zkp_v0_8_0_ge q; - rustsecp256k1zkp_v0_8_0_scalar r, s; - rustsecp256k1zkp_v0_8_0_scalar m; - int recid; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(msghash32 != NULL); - ARG_CHECK(signature != NULL); - ARG_CHECK(pubkey != NULL); - - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature); - VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */ - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&m, msghash32, NULL); - if (rustsecp256k1zkp_v0_8_0_ecdsa_sig_recover(&r, &s, &q, &m, recid)) { - rustsecp256k1zkp_v0_8_0_pubkey_save(pubkey, &q); - return 1; - } else { - memset(pubkey, 0, sizeof(*pubkey)); - return 0; - } -} - -#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/tests_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/tests_impl.h deleted file mode 100644 index ada80225..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/tests_impl.h +++ /dev/null @@ -1,399 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H -#define SECP256K1_MODULE_RECOVERY_TESTS_H - -static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { - (void) msg32; - (void) key32; - (void) algo16; - (void) data; - - /* On the first run, return 0 to force a second run */ - if (counter == 0) { - memset(nonce32, 0, 32); - return 1; - } - /* On the second run, return an overflow to force a third run */ - if (counter == 1) { - memset(nonce32, 0xff, 32); - return 1; - } - /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */ - memset(nonce32, 1, 32); - return rustsecp256k1zkp_v0_8_0_testrand_bits(1); -} - -void test_ecdsa_recovery_api(void) { - /* Setup contexts that just count errors */ - rustsecp256k1zkp_v0_8_0_context *none = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); - rustsecp256k1zkp_v0_8_0_context *sign = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN); - rustsecp256k1zkp_v0_8_0_context *vrfy = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *both = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *sttc = rustsecp256k1zkp_v0_8_0_context_clone(rustsecp256k1zkp_v0_8_0_context_no_precomp); - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_pubkey recpubkey; - rustsecp256k1zkp_v0_8_0_ecdsa_signature normal_sig; - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature recsig; - unsigned char privkey[32] = { 1 }; - unsigned char message[32] = { 2 }; - int32_t ecount = 0; - int recid = 0; - unsigned char sig[74]; - unsigned char zero_privkey[32] = { 0 }; - unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - rustsecp256k1zkp_v0_8_0_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); - - /* Construct and verify corresponding public key. */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, privkey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, privkey) == 1); - - /* Check bad contexts and NULLs for signing */ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(sttc, &recsig, message, privkey, NULL, NULL) == 0); - CHECK(ecount == 4); - /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */ - rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL); - CHECK(ecount == 4); - /* These will all fail, but not in ARG_CHECK way */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0); - /* This one will succeed. */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 4); - - /* Check signing with a goofy nonce function */ - - /* Check bad contexts and NULLs for recovery */ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(none, &recpubkey, &recsig, message) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(sign, &recpubkey, &recsig, message) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(both, &recpubkey, &recsig, message) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(both, NULL, &recsig, message) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(both, &recpubkey, NULL, message) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0); - CHECK(ecount == 3); - - /* Check NULLs for conversion */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1); - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1); - - /* Check NULLs for de/serialization */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0); - CHECK(ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0); - CHECK(ecount == 7); - /* overflow in signature will fail but not affect ecount */ - memcpy(sig, over_privkey, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0); - CHECK(ecount == 7); - - /* cleanup */ - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(vrfy); - rustsecp256k1zkp_v0_8_0_context_destroy(both); - rustsecp256k1zkp_v0_8_0_context_destroy(sttc); -} - -void test_ecdsa_recovery_end_to_end(void) { - unsigned char extra[32] = {0x00}; - unsigned char privkey[32]; - unsigned char message[32]; - rustsecp256k1zkp_v0_8_0_ecdsa_signature signature[5]; - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature rsignature[5]; - unsigned char sig[74]; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_pubkey recpubkey; - int recid = 0; - - /* Generate a random key and message. */ - { - rustsecp256k1zkp_v0_8_0_scalar msg, key; - random_scalar_order_test(&msg); - random_scalar_order_test(&key); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(privkey, &key); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(message, &msg); - } - - /* Construct and verify corresponding public key. */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, privkey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, privkey) == 1); - - /* Serialize/parse compact and verify/recover. */ - extra[0] = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1); - extra[31] = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1); - extra[31] = 0; - extra[0] = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&signature[4], &signature[0], 64) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); - memset(&rsignature[4], 0, sizeof(rsignature[4])); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); - /* Parse compact (with recovery id) and recover. */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) == 0); - /* Serialize/destroy/parse signature and verify again. */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); - sig[rustsecp256k1zkp_v0_8_0_testrand_bits(6)] += 1 + rustsecp256k1zkp_v0_8_0_testrand_int(255); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0); - /* Recover again */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 || - rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) != 0); -} - -/* Tests several edge cases. */ -void test_ecdsa_recovery_edge_cases(void) { - const unsigned char msg32[32] = { - 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', - 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', - 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', - 's', 's', 'a', 'g', 'e', '.', '.', '.' - }; - const unsigned char sig64[64] = { - /* Generated by signing the above message with nonce 'This is the nonce we will use...' - * and secret key 0 (which is not valid), resulting in recid 1. */ - 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, - 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, - 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, - 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, - 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, - 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, - 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, - 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 - }; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ - const unsigned char sigb64[64] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - }; - rustsecp256k1zkp_v0_8_0_pubkey pubkeyb; - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature rsig; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig; - int recid; - - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0)); - CHECK(!rustsecp256k1zkp_v0_8_0_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2)); - CHECK(!rustsecp256k1zkp_v0_8_0_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3)); - CHECK(!rustsecp256k1zkp_v0_8_0_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); - - for (recid = 0; recid < 4; recid++) { - int i; - int recid2; - /* (4,4) encoded in DER. */ - unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; - unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01}; - unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00}; - unsigned char sigbderalt1[39] = { - 0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, - }; - unsigned char sigbderalt2[39] = { - 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - }; - unsigned char sigbderalt3[40] = { - 0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, - }; - unsigned char sigbderalt4[40] = { - 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - }; - /* (order + r,4) encoded in DER. */ - unsigned char sigbderlong[40] = { - 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, - 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, - 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 - }; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); - for (recid2 = 0; recid2 < 4; recid2++) { - rustsecp256k1zkp_v0_8_0_pubkey pubkey2b; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1); - /* Verifying with (order + r,4) should always fail. */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); - } - /* DER parsing tests. */ - /* Zero length r/s. */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); - /* Leading zeros. */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); - sigbderalt3[4] = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); - sigbderalt4[7] = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); - /* Damage signature. */ - sigbder[7]++; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); - sigbder[7]--; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0); - for(i = 0; i < 8; i++) { - int c; - unsigned char orig = sigbder[i]; - /*Try every single-byte change.*/ - for (c = 0; c < 256; c++) { - if (c == orig ) { - continue; - } - sigbder[i] = c; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); - } - sigbder[i] = orig; - } - } - - /* Test r/s equal to zero */ - { - /* (1,1) encoded in DER. */ - unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; - unsigned char sigc64[64] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - }; - rustsecp256k1zkp_v0_8_0_pubkey pubkeyc; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1); - sigcder[4] = 0; - sigc64[31] = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); - sigcder[4] = 1; - sigcder[7] = 0; - sigc64[31] = 1; - sigc64[63] = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); - } -} - -void run_recovery_tests(void) { - int i; - for (i = 0; i < count; i++) { - test_ecdsa_recovery_api(); - } - for (i = 0; i < 64*count; i++) { - test_ecdsa_recovery_end_to_end(); - } - test_ecdsa_recovery_edge_cases(); -} - -#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/main_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/main_impl.h deleted file mode 100644 index 20059687..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/main_impl.h +++ /dev/null @@ -1,267 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_MODULE_SCHNORRSIG_MAIN_H -#define SECP256K1_MODULE_SCHNORRSIG_MAIN_H - -#include "../../../include/secp256k1.h" -#include "../../../include/secp256k1_schnorrsig.h" -#include "../../hash.h" - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("BIP0340/nonce")||SHA256("BIP0340/nonce"). */ -static void rustsecp256k1zkp_v0_8_0_nonce_function_bip340_sha256_tagged(rustsecp256k1zkp_v0_8_0_sha256 *sha) { - rustsecp256k1zkp_v0_8_0_sha256_initialize(sha); - sha->s[0] = 0x46615b35ul; - sha->s[1] = 0xf4bfbff7ul; - sha->s[2] = 0x9f8dc671ul; - sha->s[3] = 0x83627ab3ul; - sha->s[4] = 0x60217180ul; - sha->s[5] = 0x57358661ul; - sha->s[6] = 0x21a29e54ul; - sha->s[7] = 0x68b07b4cul; - - sha->bytes = 64; -} - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("BIP0340/aux")||SHA256("BIP0340/aux"). */ -static void rustsecp256k1zkp_v0_8_0_nonce_function_bip340_sha256_tagged_aux(rustsecp256k1zkp_v0_8_0_sha256 *sha) { - rustsecp256k1zkp_v0_8_0_sha256_initialize(sha); - sha->s[0] = 0x24dd3219ul; - sha->s[1] = 0x4eba7e70ul; - sha->s[2] = 0xca0fabb9ul; - sha->s[3] = 0x0fa3166dul; - sha->s[4] = 0x3afbe4b1ul; - sha->s[5] = 0x4c44df97ul; - sha->s[6] = 0x4aac2739ul; - sha->s[7] = 0x249e850aul; - - sha->bytes = 64; -} - -/* algo argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340 - * by using the correct tagged hash function. */ -static const unsigned char bip340_algo[13] = "BIP0340/nonce"; - -static const unsigned char schnorrsig_extraparams_magic[4] = SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC; - -static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { - rustsecp256k1zkp_v0_8_0_sha256 sha; - unsigned char masked_key[32]; - int i; - - if (algo == NULL) { - return 0; - } - - if (data != NULL) { - rustsecp256k1zkp_v0_8_0_nonce_function_bip340_sha256_tagged_aux(&sha); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, data, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, masked_key); - for (i = 0; i < 32; i++) { - masked_key[i] ^= key32[i]; - } - } else { - /* Precomputed TaggedHash("BIP0340/aux", 0x0000...00); */ - static const unsigned char ZERO_MASK[32] = { - 84, 241, 105, 207, 201, 226, 229, 114, - 116, 128, 68, 31, 144, 186, 37, 196, - 136, 244, 97, 199, 11, 94, 165, 220, - 170, 247, 175, 105, 39, 10, 165, 20 - }; - for (i = 0; i < 32; i++) { - masked_key[i] = key32[i] ^ ZERO_MASK[i]; - } - } - - /* Tag the hash with algo which is important to avoid nonce reuse across - * algorithms. If this nonce function is used in BIP-340 signing as defined - * in the spec, an optimized tagging implementation is used. */ - if (algolen == sizeof(bip340_algo) - && rustsecp256k1zkp_v0_8_0_memcmp_var(algo, bip340_algo, algolen) == 0) { - rustsecp256k1zkp_v0_8_0_nonce_function_bip340_sha256_tagged(&sha); - } else { - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, algo, algolen); - } - - /* Hash masked-key||pk||msg using the tagged hash as per the spec */ - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, masked_key, 32); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, xonly_pk32, 32); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, msg, msglen); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, nonce32); - return 1; -} - -const rustsecp256k1zkp_v0_8_0_nonce_function_hardened rustsecp256k1zkp_v0_8_0_nonce_function_bip340 = nonce_function_bip340; - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("BIP0340/challenge")||SHA256("BIP0340/challenge"). */ -static void rustsecp256k1zkp_v0_8_0_schnorrsig_sha256_tagged(rustsecp256k1zkp_v0_8_0_sha256 *sha) { - rustsecp256k1zkp_v0_8_0_sha256_initialize(sha); - sha->s[0] = 0x9cecba11ul; - sha->s[1] = 0x23925381ul; - sha->s[2] = 0x11679112ul; - sha->s[3] = 0xd1627e0ful; - sha->s[4] = 0x97c87550ul; - sha->s[5] = 0x003cc765ul; - sha->s[6] = 0x90f61164ul; - sha->s[7] = 0x33e9b66aul; - sha->bytes = 64; -} - -static void rustsecp256k1zkp_v0_8_0_schnorrsig_challenge(rustsecp256k1zkp_v0_8_0_scalar* e, const unsigned char *r32, const unsigned char *msg, size_t msglen, const unsigned char *pubkey32) -{ - unsigned char buf[32]; - rustsecp256k1zkp_v0_8_0_sha256 sha; - - /* tagged hash(r.x, pk.x, msg) */ - rustsecp256k1zkp_v0_8_0_schnorrsig_sha256_tagged(&sha); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, r32, 32); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, pubkey32, 32); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, msg, msglen); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, buf); - /* Set scalar e to the challenge hash modulo the curve order as per - * BIP340. */ - rustsecp256k1zkp_v0_8_0_scalar_set_b32(e, buf, NULL); -} - -static int rustsecp256k1zkp_v0_8_0_schnorrsig_sign_internal(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const rustsecp256k1zkp_v0_8_0_keypair *keypair, rustsecp256k1zkp_v0_8_0_nonce_function_hardened noncefp, void *ndata) { - rustsecp256k1zkp_v0_8_0_scalar sk; - rustsecp256k1zkp_v0_8_0_scalar e; - rustsecp256k1zkp_v0_8_0_scalar k; - rustsecp256k1zkp_v0_8_0_gej rj; - rustsecp256k1zkp_v0_8_0_ge pk; - rustsecp256k1zkp_v0_8_0_ge r; - unsigned char buf[32] = { 0 }; - unsigned char pk_buf[32]; - unsigned char seckey[32]; - int ret = 1; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(msg != NULL || msglen == 0); - ARG_CHECK(keypair != NULL); - - if (noncefp == NULL) { - noncefp = rustsecp256k1zkp_v0_8_0_nonce_function_bip340; - } - - ret &= rustsecp256k1zkp_v0_8_0_keypair_load(ctx, &sk, &pk, keypair); - /* Because we are signing for a x-only pubkey, the secret key is negated - * before signing if the point corresponding to the secret key does not - * have an even Y. */ - if (rustsecp256k1zkp_v0_8_0_fe_is_odd(&pk.y)) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&sk, &sk); - } - - rustsecp256k1zkp_v0_8_0_scalar_get_b32(seckey, &sk); - rustsecp256k1zkp_v0_8_0_fe_get_b32(pk_buf, &pk.x); - ret &= !!noncefp(buf, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&k, buf, NULL); - ret &= !rustsecp256k1zkp_v0_8_0_scalar_is_zero(&k); - rustsecp256k1zkp_v0_8_0_scalar_cmov(&k, &rustsecp256k1zkp_v0_8_0_scalar_one, !ret); - - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&r, &rj); - - /* We declassify r to allow using it as a branch point. This is fine - * because r is not a secret. */ - rustsecp256k1zkp_v0_8_0_declassify(ctx, &r, sizeof(r)); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&r.y); - if (rustsecp256k1zkp_v0_8_0_fe_is_odd(&r.y)) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&k, &k); - } - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&r.x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(&sig64[0], &r.x); - - rustsecp256k1zkp_v0_8_0_schnorrsig_challenge(&e, &sig64[0], msg, msglen, pk_buf); - rustsecp256k1zkp_v0_8_0_scalar_mul(&e, &e, &sk); - rustsecp256k1zkp_v0_8_0_scalar_add(&e, &e, &k); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&sig64[32], &e); - - rustsecp256k1zkp_v0_8_0_memczero(sig64, 64, !ret); - rustsecp256k1zkp_v0_8_0_scalar_clear(&k); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sk); - memset(seckey, 0, sizeof(seckey)); - - return ret; -} - -int rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *sig64, const unsigned char *msg32, const rustsecp256k1zkp_v0_8_0_keypair *keypair, const unsigned char *aux_rand32) { - /* We cast away const from the passed aux_rand32 argument since we know the default nonce function does not modify it. */ - return rustsecp256k1zkp_v0_8_0_schnorrsig_sign_internal(ctx, sig64, msg32, 32, keypair, rustsecp256k1zkp_v0_8_0_nonce_function_bip340, (unsigned char*)aux_rand32); -} - -int rustsecp256k1zkp_v0_8_0_schnorrsig_sign(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *sig64, const unsigned char *msg32, const rustsecp256k1zkp_v0_8_0_keypair *keypair, const unsigned char *aux_rand32) { - return rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(ctx, sig64, msg32, keypair, aux_rand32); -} - -int rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const rustsecp256k1zkp_v0_8_0_keypair *keypair, rustsecp256k1zkp_v0_8_0_schnorrsig_extraparams *extraparams) { - rustsecp256k1zkp_v0_8_0_nonce_function_hardened noncefp = NULL; - void *ndata = NULL; - VERIFY_CHECK(ctx != NULL); - - if (extraparams != NULL) { - ARG_CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(extraparams->magic, - schnorrsig_extraparams_magic, - sizeof(extraparams->magic)) == 0); - noncefp = extraparams->noncefp; - ndata = extraparams->ndata; - } - return rustsecp256k1zkp_v0_8_0_schnorrsig_sign_internal(ctx, sig64, msg, msglen, keypair, noncefp, ndata); -} - -int rustsecp256k1zkp_v0_8_0_schnorrsig_verify(const rustsecp256k1zkp_v0_8_0_context* ctx, const unsigned char *sig64, const unsigned char *msg, size_t msglen, const rustsecp256k1zkp_v0_8_0_xonly_pubkey *pubkey) { - rustsecp256k1zkp_v0_8_0_scalar s; - rustsecp256k1zkp_v0_8_0_scalar e; - rustsecp256k1zkp_v0_8_0_gej rj; - rustsecp256k1zkp_v0_8_0_ge pk; - rustsecp256k1zkp_v0_8_0_gej pkj; - rustsecp256k1zkp_v0_8_0_fe rx; - rustsecp256k1zkp_v0_8_0_ge r; - unsigned char buf[32]; - int overflow; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(msg != NULL || msglen == 0); - ARG_CHECK(pubkey != NULL); - - if (!rustsecp256k1zkp_v0_8_0_fe_set_b32(&rx, &sig64[0])) { - return 0; - } - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&s, &sig64[32], &overflow); - if (overflow) { - return 0; - } - - if (!rustsecp256k1zkp_v0_8_0_xonly_pubkey_load(ctx, &pk, pubkey)) { - return 0; - } - - /* Compute e. */ - rustsecp256k1zkp_v0_8_0_fe_get_b32(buf, &pk.x); - rustsecp256k1zkp_v0_8_0_schnorrsig_challenge(&e, &sig64[0], msg, msglen, buf); - - /* Compute rj = s*G + (-e)*pkj */ - rustsecp256k1zkp_v0_8_0_scalar_negate(&e, &e); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&pkj, &pk); - rustsecp256k1zkp_v0_8_0_ecmult(&rj, &pkj, &e, &s); - - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&r, &rj); - if (rustsecp256k1zkp_v0_8_0_ge_is_infinity(&r)) { - return 0; - } - - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&r.y); - return !rustsecp256k1zkp_v0_8_0_fe_is_odd(&r.y) && - rustsecp256k1zkp_v0_8_0_fe_equal_var(&rx, &r.x); -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/Makefile.am.include b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/Makefile.am.include deleted file mode 100644 index 26395b05..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/Makefile.am.include +++ /dev/null @@ -1,6 +0,0 @@ -include_HEADERS += include/rustsecp256k1zkp_v0_8_0_surjectionproof.h -noinst_HEADERS += src/modules/surjection/main_impl.h -noinst_HEADERS += src/modules/surjection/surjection.h -noinst_HEADERS += src/modules/surjection/surjection_impl.h -noinst_HEADERS += src/modules/surjection/tests_impl.h - diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/main_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/main_impl.h deleted file mode 100644 index 9d69bdb8..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/main_impl.h +++ /dev/null @@ -1,361 +0,0 @@ -/********************************************************************** - * Copyright (c) 2016 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ -#ifndef SECP256K1_MODULE_SURJECTION_MAIN -#define SECP256K1_MODULE_SURJECTION_MAIN - -#include - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#include "../../../include/secp256k1_rangeproof.h" -#include "../../../include/secp256k1_surjectionproof.h" -#include "../rangeproof/borromean.h" -#include "surjection_impl.h" -#include "../../hash.h" - -#ifdef USE_REDUCED_SURJECTION_PROOF_SIZE -#undef SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS -#define SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS 16 -#endif - -static size_t rustsecp256k1zkp_v0_8_0_count_bits_set(const unsigned char* data, size_t count) { - size_t ret = 0; - size_t i; - for (i = 0; i < count; i++) { -#ifdef HAVE_BUILTIN_POPCOUNT - ret += __builtin_popcount(data[i]); -#else - ret += !!(data[i] & 0x1); - ret += !!(data[i] & 0x2); - ret += !!(data[i] & 0x4); - ret += !!(data[i] & 0x8); - ret += !!(data[i] & 0x10); - ret += !!(data[i] & 0x20); - ret += !!(data[i] & 0x40); - ret += !!(data[i] & 0x80); -#endif - } - return ret; -} - -#ifdef USE_REDUCED_SURJECTION_PROOF_SIZE -static -#endif -int rustsecp256k1zkp_v0_8_0_surjectionproof_parse(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_surjectionproof *proof, const unsigned char *input, size_t inputlen) { - size_t n_inputs; - size_t signature_len; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(proof != NULL); - ARG_CHECK(input != NULL); - (void) ctx; - - if (inputlen < 2) { - return 0; - } - n_inputs = ((size_t) (input[1] << 8)) + input[0]; - if (n_inputs > SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) { - return 0; - } - if (inputlen < 2 + (n_inputs + 7) / 8) { - return 0; - } - - /* Check that the bitvector of used inputs is of the claimed - * length; i.e. the final byte has no "padding bits" set */ - if (n_inputs % 8 != 0) { - const unsigned char padding_mask = (~0U) << (n_inputs % 8); - if ((input[2 + (n_inputs + 7) / 8 - 1] & padding_mask) != 0) { - return 0; - } - } - - signature_len = 32 * (1 + rustsecp256k1zkp_v0_8_0_count_bits_set(&input[2], (n_inputs + 7) / 8)); - if (inputlen != 2 + (n_inputs + 7) / 8 + signature_len) { - return 0; - } - proof->n_inputs = n_inputs; - memcpy(proof->used_inputs, &input[2], (n_inputs + 7) / 8); - memcpy(proof->data, &input[2 + (n_inputs + 7) / 8], signature_len); - - return 1; -} - -int rustsecp256k1zkp_v0_8_0_surjectionproof_serialize(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *output, size_t *outputlen, const rustsecp256k1zkp_v0_8_0_surjectionproof *proof) { - size_t signature_len; - size_t serialized_len; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output != NULL); - ARG_CHECK(outputlen != NULL); - ARG_CHECK(proof != NULL); - (void) ctx; - - signature_len = 32 * (1 + rustsecp256k1zkp_v0_8_0_count_bits_set(proof->used_inputs, (proof->n_inputs + 7) / 8)); - serialized_len = 2 + (proof->n_inputs + 7) / 8 + signature_len; - if (*outputlen < serialized_len) { - return 0; - } - - output[0] = proof->n_inputs % 0x100; - output[1] = proof->n_inputs / 0x100; - memcpy(&output[2], proof->used_inputs, (proof->n_inputs + 7) / 8); - memcpy(&output[2 + (proof->n_inputs + 7) / 8], proof->data, signature_len); - *outputlen = serialized_len; - - return 1; -} - -size_t rustsecp256k1zkp_v0_8_0_surjectionproof_n_total_inputs(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_surjectionproof* proof) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(proof != NULL); - (void) ctx; - return proof->n_inputs; -} - -size_t rustsecp256k1zkp_v0_8_0_surjectionproof_n_used_inputs(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_surjectionproof* proof) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(proof != NULL); - (void) ctx; - return rustsecp256k1zkp_v0_8_0_count_bits_set(proof->used_inputs, (proof->n_inputs + 7) / 8); -} - -size_t rustsecp256k1zkp_v0_8_0_surjectionproof_serialized_size(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_surjectionproof* proof) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(proof != NULL); - return 2 + (proof->n_inputs + 7) / 8 + 32 * (1 + rustsecp256k1zkp_v0_8_0_surjectionproof_n_used_inputs(ctx, proof)); -} - -typedef struct { - unsigned char state[32]; - size_t state_i; -} rustsecp256k1zkp_v0_8_0_surjectionproof_csprng; - -static void rustsecp256k1zkp_v0_8_0_surjectionproof_csprng_init(rustsecp256k1zkp_v0_8_0_surjectionproof_csprng *csprng, const unsigned char* state) { - memcpy(csprng->state, state, 32); - csprng->state_i = 0; -} - -static size_t rustsecp256k1zkp_v0_8_0_surjectionproof_csprng_next(rustsecp256k1zkp_v0_8_0_surjectionproof_csprng *csprng, size_t rand_max) { - /* The number of random bytes to read for each random sample */ - const size_t increment = rand_max > 256 ? 2 : 1; - /* The maximum value expressable by the number of random bytes we read */ - const size_t selection_range = rand_max > 256 ? 0xffff : 0xff; - /* The largest multiple of rand_max that fits within selection_range */ - const size_t limit = ((selection_range + 1) / rand_max) * rand_max; - - while (1) { - size_t val; - if (csprng->state_i + increment >= 32) { - rustsecp256k1zkp_v0_8_0_sha256 sha; - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, csprng->state, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, csprng->state); - csprng->state_i = 0; - } - val = csprng->state[csprng->state_i]; - if (increment > 1) { - val = (val << 8) + csprng->state[csprng->state_i + 1]; - } - csprng->state_i += increment; - /* Accept only values below our limit. Values equal to or above the limit are - * biased because they comprise only a subset of the range (0, rand_max - 1) */ - if (val < limit) { - return val % rand_max; - } - } -} - -int rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_surjectionproof* proof, size_t *input_index, const rustsecp256k1zkp_v0_8_0_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, const rustsecp256k1zkp_v0_8_0_fixed_asset_tag* fixed_output_tag, const size_t n_max_iterations, const unsigned char *random_seed32) { - rustsecp256k1zkp_v0_8_0_surjectionproof_csprng csprng; - size_t n_iterations = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(proof != NULL); - ARG_CHECK(input_index != NULL); - ARG_CHECK(fixed_input_tags != NULL); - ARG_CHECK(fixed_output_tag != NULL); - ARG_CHECK(random_seed32 != NULL); - ARG_CHECK(n_input_tags <= SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS); - ARG_CHECK(n_input_tags_to_use <= SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS); - ARG_CHECK(n_input_tags_to_use <= n_input_tags); - (void) ctx; - - rustsecp256k1zkp_v0_8_0_surjectionproof_csprng_init(&csprng, random_seed32); - memset(proof->data, 0, sizeof(proof->data)); - proof->n_inputs = n_input_tags; - - while (1) { - int has_output_tag = 0; - size_t i; - - /* obtain a random set of indices */ - memset(proof->used_inputs, 0, sizeof(proof->used_inputs)); - for (i = 0; i < n_input_tags_to_use; i++) { - while (1) { - size_t next_input_index; - next_input_index = rustsecp256k1zkp_v0_8_0_surjectionproof_csprng_next(&csprng, n_input_tags); - if (rustsecp256k1zkp_v0_8_0_memcmp_var(&fixed_input_tags[next_input_index], fixed_output_tag, sizeof(*fixed_output_tag)) == 0) { - *input_index = next_input_index; - has_output_tag = 1; - } - - if (!(proof->used_inputs[next_input_index / 8] & (1 << (next_input_index % 8)))) { - proof->used_inputs[next_input_index / 8] |= (1 << (next_input_index % 8)); - break; - } - } - } - - /* Check if we succeeded */ - n_iterations++; - if (has_output_tag) { -#ifdef VERIFY - proof->initialized = 1; -#endif - return n_iterations; - } - if (n_iterations >= n_max_iterations) { -#ifdef VERIFY - proof->initialized = 0; -#endif - return 0; - } - } -} - -int rustsecp256k1zkp_v0_8_0_surjectionproof_generate(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_surjectionproof* proof, const rustsecp256k1zkp_v0_8_0_generator* ephemeral_input_tags, size_t n_ephemeral_input_tags, const rustsecp256k1zkp_v0_8_0_generator* ephemeral_output_tag, size_t input_index, const unsigned char *input_blinding_key, const unsigned char *output_blinding_key) { - rustsecp256k1zkp_v0_8_0_scalar blinding_key; - rustsecp256k1zkp_v0_8_0_scalar tmps; - rustsecp256k1zkp_v0_8_0_scalar nonce; - int overflow = 0; - size_t rsizes[1]; /* array needed for borromean sig API */ - size_t indices[1]; /* array needed for borromean sig API */ - size_t i; - size_t n_total_pubkeys; - size_t n_used_pubkeys; - size_t ring_input_index = 0; - rustsecp256k1zkp_v0_8_0_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS]; - rustsecp256k1zkp_v0_8_0_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS]; - unsigned char msg32[32]; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(proof != NULL); - ARG_CHECK(ephemeral_input_tags != NULL); - ARG_CHECK(ephemeral_output_tag != NULL); - ARG_CHECK(input_blinding_key != NULL); - ARG_CHECK(output_blinding_key != NULL); -#ifdef VERIFY - CHECK(proof->initialized == 1); -#endif - - n_used_pubkeys = rustsecp256k1zkp_v0_8_0_surjectionproof_n_used_inputs(ctx, proof); - /* This must be true if the proof was created with surjectionproof_initialize */ - ARG_CHECK(n_used_pubkeys > 0); - - /* Compute secret key */ - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&tmps, input_blinding_key, &overflow); - if (overflow) { - return 0; - } - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&blinding_key, output_blinding_key, &overflow); - if (overflow) { - return 0; - } - /* If any input tag is equal to an output tag, verification will fail, because our ring - * signature logic would receive a zero-key, which is illegal. This is unfortunate but - * it is deployed on Liquid and cannot be fixed without a hardfork. We should review - * this at the same time that we relax the max-256-inputs rule. */ - for (i = 0; i < n_ephemeral_input_tags; i++) { - if (rustsecp256k1zkp_v0_8_0_memcmp_var(ephemeral_input_tags[i].data, ephemeral_output_tag->data, sizeof(ephemeral_output_tag->data)) == 0) { - return 0; - } - } - rustsecp256k1zkp_v0_8_0_scalar_negate(&tmps, &tmps); - rustsecp256k1zkp_v0_8_0_scalar_add(&blinding_key, &blinding_key, &tmps); - - /* Compute public keys */ - n_total_pubkeys = rustsecp256k1zkp_v0_8_0_surjectionproof_n_total_inputs(ctx, proof); - - if (n_used_pubkeys > n_total_pubkeys || n_total_pubkeys != n_ephemeral_input_tags) { - return 0; - } - - if (rustsecp256k1zkp_v0_8_0_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, ephemeral_input_tags, n_total_pubkeys, proof->used_inputs, ephemeral_output_tag, input_index, &ring_input_index) == 0) { - return 0; - } - - /* Produce signature */ - rsizes[0] = (int) n_used_pubkeys; - indices[0] = (int) ring_input_index; - rustsecp256k1zkp_v0_8_0_surjection_genmessage(msg32, ephemeral_input_tags, n_total_pubkeys, ephemeral_output_tag); - if (rustsecp256k1zkp_v0_8_0_surjection_genrand(borromean_s, n_used_pubkeys, &blinding_key) == 0) { - return 0; - } - /* Borromean sign will overwrite one of the s values we just generated, so use - * it as a nonce instead. This avoids extra random generation and also is an - * homage to the rangeproof code which does this very cleverly to encode messages. */ - nonce = borromean_s[ring_input_index]; - rustsecp256k1zkp_v0_8_0_scalar_clear(&borromean_s[ring_input_index]); - if (rustsecp256k1zkp_v0_8_0_borromean_sign(&ctx->ecmult_gen_ctx, &proof->data[0], borromean_s, ring_pubkeys, &nonce, &blinding_key, rsizes, indices, 1, msg32, 32) == 0) { - return 0; - } - for (i = 0; i < n_used_pubkeys; i++) { - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&proof->data[32 + 32 * i], &borromean_s[i]); - } - return 1; -} - -#ifdef USE_REDUCED_SURJECTION_PROOF_SIZE -static -#endif -int rustsecp256k1zkp_v0_8_0_surjectionproof_verify(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_surjectionproof* proof, const rustsecp256k1zkp_v0_8_0_generator* ephemeral_input_tags, size_t n_ephemeral_input_tags, const rustsecp256k1zkp_v0_8_0_generator* ephemeral_output_tag) { - size_t rsizes[1]; /* array needed for borromean sig API */ - size_t i; - size_t n_total_pubkeys; - size_t n_used_pubkeys; - rustsecp256k1zkp_v0_8_0_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS]; - rustsecp256k1zkp_v0_8_0_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS]; - unsigned char msg32[32]; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(proof != NULL); - ARG_CHECK(ephemeral_input_tags != NULL); - ARG_CHECK(ephemeral_output_tag != NULL); - - /* Compute public keys */ - n_total_pubkeys = rustsecp256k1zkp_v0_8_0_surjectionproof_n_total_inputs(ctx, proof); - n_used_pubkeys = rustsecp256k1zkp_v0_8_0_surjectionproof_n_used_inputs(ctx, proof); - if (n_used_pubkeys == 0 || n_used_pubkeys > n_total_pubkeys || n_total_pubkeys != n_ephemeral_input_tags) { - return 0; - } - - /* Reject proofs with too many used inputs in USE_REDUCED_SURJECTION_PROOF_SIZE mode */ - if (n_used_pubkeys > SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS) { - return 0; - } - - if (rustsecp256k1zkp_v0_8_0_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, ephemeral_input_tags, n_total_pubkeys, proof->used_inputs, ephemeral_output_tag, 0, NULL) == 0) { - return 0; - } - - /* Verify signature */ - rsizes[0] = (int) n_used_pubkeys; - for (i = 0; i < n_used_pubkeys; i++) { - int overflow = 0; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&borromean_s[i], &proof->data[32 + 32 * i], &overflow); - if (overflow == 1) { - return 0; - } - } - rustsecp256k1zkp_v0_8_0_surjection_genmessage(msg32, ephemeral_input_tags, n_total_pubkeys, ephemeral_output_tag); - return rustsecp256k1zkp_v0_8_0_borromean_verify(NULL, &proof->data[0], borromean_s, ring_pubkeys, rsizes, 1, msg32, 32); -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/surjection.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/surjection.h deleted file mode 100644 index 87eb96e6..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/surjection.h +++ /dev/null @@ -1,19 +0,0 @@ -/********************************************************************** - * Copyright (c) 2016 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_SURJECTION_H_ -#define _SECP256K1_SURJECTION_H_ - -#include "../../group.h" -#include "../../scalar.h" - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_surjection_genmessage(unsigned char *msg32, rustsecp256k1zkp_v0_8_0_ge *ephemeral_input_tags, size_t n_input_tags, rustsecp256k1zkp_v0_8_0_ge *ephemeral_output_tag); - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_surjection_genrand(rustsecp256k1zkp_v0_8_0_scalar *s, size_t ns, const rustsecp256k1zkp_v0_8_0_scalar *blinding_key); - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_surjection_compute_public_keys(rustsecp256k1zkp_v0_8_0_gej *pubkeys, size_t n_pubkeys, const rustsecp256k1zkp_v0_8_0_ge *input_tags, size_t n_input_tags, const unsigned char *used_tags, const rustsecp256k1zkp_v0_8_0_ge *output_tag, size_t input_index, size_t *ring_input_index); - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/surjection.md b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/surjection.md deleted file mode 100644 index e7bd4db1..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/surjection.md +++ /dev/null @@ -1,108 +0,0 @@ -Surjection Proof Module -=========================== - -This module implements a scheme by which a given point can be proven to be -equal to one of a set of points, plus a known difference. This is used in -Confidential Assets when reblinding "asset commitments", which are NUMS -points, to prove that the underlying NUMS point does not change during -reblinding. - -Assets are represented, in general, by a 32-byte seed (a hash of some -transaction data) which is hashed to form a NUMS generator, which appears -on the blockchain only in blinded form. We refer to the seed as an -"asset ID" and the blinded generator as an "(ephemeral) asset commitment". -These asset commitments are unique per-output, and their NUMS components -are in general known only to the holder of the output. - -The result is that within a transaction, all outputs are able to have -a new uniformly-random asset commitment which cannot be associated with -any individual input asset id, but verifiers are nonetheless assured that -all assets coming out of a transaction are ones that went in. - -### Terminology - -Assets are identified by a 32-byte "asset ID". In this library these IDs -are used as input to a point-valued hash function `H`. We usually refer -to the hash output as `A`, since this output is the only thing that appears -in the algebra. - -Then transaction outputs have "asset commitments", which are curvepoints -of the form `A + rG`, where `A` is the hash of the asset ID and `r` is -some random "blinding factor". - -### Design Rationale - -Confidential Assets essentially works by replacing the second NUMS generator -`H` in Confidental Transactions with a per-asset unique NUMS generator. This -allows the same verification equation (the sum of all blinded inputs must -equal the sum of all blinded outputs) to imply that quantity of *every* asset -type is preserved in each transaction. - -It turns out that even if outputs are reblinded by the addition of `rG` for -some known `r`, this verification equation has the same meaning, with one -caveat: verifiers must be assured that the reblinding preserves the original -generators (and does not, for example, negate them). - -This assurance is what surjection proofs provide. - -### Limitations - -The naive scheme works as follows: every output asset is shown to have come -from some input asset. However, the proofs scale with the number of input -assets, so for all outputs the total size of all surjection proofs is `O(mn)` -for `m`, `n` the number of inputs and outputs. - -We therefore restrict the number of inputs that each output may have come -from to 3 (well, some fixed number, which is passed into the API), which -provides a weaker form of blinding, but gives `O(n)` scaling. Over many -transactions, the privacy afforded by this increases exponentially. - -### Our Scheme - -Our scheme works as follows. Proofs are generated in two steps, "initialization" -which selects a subset of inputs and "generation" which does the mathematical -part of proof generation. - -Every input has an asset commitment for which we know the blinding key and -underlying asset ID. - -#### Initialization - -The initialization function takes a list of input asset IDs and one output -asset ID. It chooses an input subset of some fixed size repeatedly until it -the output ID appears at least once in its subset. - -It stores a bitmap representing this subset in the proof object and returns -the number of iterations it needed to choose the subset. The reciprocal of -this represents the probability that a uniformly random input-output -mapping would correspond to the actual input-output mapping, and therefore -gives a measure of privacy. (Lower iteration counts are better.) - -It also informs the caller the index of the input whose ID matches the output. - -As the API works on only a single output at a time, the total probability -should be computed by multiplying together the counts for each output. - -#### Generation - -The generation function takes a list of input asset commitments, an output -asset commitment, the input index returned by the initialization step, and -blinding keys for (a) the output commitment, (b) the input commitment. Here -"the input commitment" refers specifically to the input whose index was -chosen during initialization. - -Next, it computes a ring signature over the differences between the output -commitment and every input commitment chosen during initialization. Since -the discrete log of one of these is the difference between the output and -input blinding keys, it is possible to create a ring signature over every -differences will be the blinding factor of the output. We create such a -signature, which completes the proof. - -#### Verification - -Verification takes a surjection proof object, a list of input commitments, -and an output commitment. The proof object contains a ring signature and -a bitmap describing which input commitments to use, and verification -succeeds iff the signature verifies. - - diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/surjection_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/surjection_impl.h deleted file mode 100644 index 39e12fc8..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/surjection_impl.h +++ /dev/null @@ -1,90 +0,0 @@ -/********************************************************************** - * Copyright (c) 2016 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_SURJECTION_IMPL_H_ -#define _SECP256K1_SURJECTION_IMPL_H_ - -#include - -#include "../../eckey.h" -#include "../../group.h" -#include "../../scalar.h" -#include "../../hash.h" - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_surjection_genmessage(unsigned char *msg32, const rustsecp256k1zkp_v0_8_0_generator *ephemeral_input_tags, size_t n_input_tags, const rustsecp256k1zkp_v0_8_0_generator *ephemeral_output_tag) { - /* compute message */ - size_t i; - unsigned char pk_ser[33]; - size_t pk_len = sizeof(pk_ser); - rustsecp256k1zkp_v0_8_0_sha256 sha256_en; - - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha256_en); - for (i = 0; i < n_input_tags; i++) { - pk_ser[0] = 2 + (ephemeral_input_tags[i].data[63] & 1); - memcpy(&pk_ser[1], &ephemeral_input_tags[i].data[0], 32); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_en, pk_ser, pk_len); - } - pk_ser[0] = 2 + (ephemeral_output_tag->data[63] & 1); - memcpy(&pk_ser[1], &ephemeral_output_tag->data[0], 32); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_en, pk_ser, pk_len); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha256_en, msg32); -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_surjection_genrand(rustsecp256k1zkp_v0_8_0_scalar *s, size_t ns, const rustsecp256k1zkp_v0_8_0_scalar *blinding_key) { - size_t i; - unsigned char sec_input[36]; - rustsecp256k1zkp_v0_8_0_sha256 sha256_en; - - /* compute s values */ - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&sec_input[4], blinding_key); - for (i = 0; i < ns; i++) { - int overflow = 0; - sec_input[0] = i; - sec_input[1] = i >> 8; - sec_input[2] = i >> 16; - sec_input[3] = i >> 24; - - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha256_en); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_en, sec_input, 36); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha256_en, sec_input); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&s[i], sec_input, &overflow); - if (overflow == 1) { - memset(sec_input, 0, 32); - return 0; - } - } - memset(sec_input, 0, 32); - return 1; -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_surjection_compute_public_keys(rustsecp256k1zkp_v0_8_0_gej *pubkeys, size_t n_pubkeys, const rustsecp256k1zkp_v0_8_0_generator *input_tags, size_t n_input_tags, const unsigned char *used_tags, const rustsecp256k1zkp_v0_8_0_generator *output_tag, size_t input_index, size_t *ring_input_index) { - size_t i; - size_t j = 0; - for (i = 0; i < n_input_tags; i++) { - if (used_tags[i / 8] & (1 << (i % 8))) { - rustsecp256k1zkp_v0_8_0_ge tmpge; - rustsecp256k1zkp_v0_8_0_generator_load(&tmpge, &input_tags[i]); - rustsecp256k1zkp_v0_8_0_ge_neg(&tmpge, &tmpge); - - VERIFY_CHECK(j < SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS); - VERIFY_CHECK(j < n_pubkeys); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&pubkeys[j], &tmpge); - - rustsecp256k1zkp_v0_8_0_generator_load(&tmpge, output_tag); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&pubkeys[j], &pubkeys[j], &tmpge, NULL); - if (ring_input_index != NULL && input_index == i) { - *ring_input_index = j; - } - j++; - } - } - /* Caller needs to ensure that the number of set bits in used_tags (which we counted in j) equals n_pubkeys. */ - VERIFY_CHECK(j == n_pubkeys); - return 1; -} - - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/tests_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/tests_impl.h deleted file mode 100644 index 796eb305..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/tests_impl.h +++ /dev/null @@ -1,730 +0,0 @@ -/********************************************************************** - * Copyright (c) 2016 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_SURJECTIONPROOF_TESTS -#define SECP256K1_MODULE_SURJECTIONPROOF_TESTS - -#include "../../testrand.h" -#include "../../group.h" -#include "../../../include/secp256k1_generator.h" -#include "../../../include/secp256k1_rangeproof.h" -#include "../../../include/secp256k1_surjectionproof.h" - -static void test_surjectionproof_api(void) { - unsigned char seed[32]; - rustsecp256k1zkp_v0_8_0_context *none = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); - rustsecp256k1zkp_v0_8_0_context *sign = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN); - rustsecp256k1zkp_v0_8_0_context *vrfy = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *both = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *sttc = rustsecp256k1zkp_v0_8_0_context_clone(rustsecp256k1zkp_v0_8_0_context_no_precomp); - rustsecp256k1zkp_v0_8_0_fixed_asset_tag fixed_input_tags[10]; - rustsecp256k1zkp_v0_8_0_fixed_asset_tag fixed_output_tag; - rustsecp256k1zkp_v0_8_0_generator ephemeral_input_tags[10]; - rustsecp256k1zkp_v0_8_0_generator ephemeral_output_tag; - unsigned char input_blinding_key[10][32]; - unsigned char output_blinding_key[32]; - unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX]; - size_t serialized_len; - rustsecp256k1zkp_v0_8_0_surjectionproof proof; - rustsecp256k1zkp_v0_8_0_surjectionproof* proof_on_heap; - size_t n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]); - size_t input_index; - int32_t ecount = 0; - size_t i; - - rustsecp256k1zkp_v0_8_0_testrand256(seed); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); - - - for (i = 0; i < n_inputs; i++) { - rustsecp256k1zkp_v0_8_0_testrand256(input_blinding_key[i]); - rustsecp256k1zkp_v0_8_0_testrand256(fixed_input_tags[i].data); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(ctx, &ephemeral_input_tags[i], fixed_input_tags[i].data, input_blinding_key[i])); - } - rustsecp256k1zkp_v0_8_0_testrand256(output_blinding_key); - memcpy(&fixed_output_tag, &fixed_input_tags[0], sizeof(fixed_input_tags[0])); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(ctx, &ephemeral_output_tag, fixed_output_tag.data, output_blinding_key)); - - /* check allocate_initialized */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, seed) == 0); - CHECK(proof_on_heap == 0); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0); - CHECK(proof_on_heap != 0); - rustsecp256k1zkp_v0_8_0_surjectionproof_destroy(proof_on_heap); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_allocate_initialized(none, NULL, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_allocate_initialized(none, &proof_on_heap, NULL, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); - CHECK(proof_on_heap == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, NULL, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); - CHECK(proof_on_heap == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS + 1, 3, &fixed_input_tags[0], 100, seed) == 0); - CHECK(proof_on_heap == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], 100, seed) != 0); - CHECK(proof_on_heap != 0); - rustsecp256k1zkp_v0_8_0_surjectionproof_destroy(proof_on_heap); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, n_inputs + 1, &fixed_input_tags[0], 100, seed) == 0); - CHECK(proof_on_heap == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 3, NULL, 100, seed) == 0); - CHECK(proof_on_heap == 0); - CHECK(ecount == 6); - CHECK((rustsecp256k1zkp_v0_8_0_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 0, seed) & 1) == 0); - CHECK(proof_on_heap == 0); - CHECK(ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, NULL) == 0); - CHECK(proof_on_heap == 0); - CHECK(ecount == 7); - - /* we are now going to test essentially the same functions, just without heap allocation. - * reset ecount. */ - ecount = 0; - - /* check initialize */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, seed) == 0); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(none, NULL, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(none, &proof, NULL, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(none, &proof, &input_index, NULL, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS + 1, 3, &fixed_input_tags[0], 100, seed) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], 100, seed) != 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs + 1, &fixed_input_tags[0], 100, seed) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, NULL, 100, seed) == 0); - CHECK(ecount == 6); - CHECK((rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 0, seed) & 1) == 0); - CHECK(ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, NULL) == 0); - CHECK(ecount == 7); - - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0); - /* check generate */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(none, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) != 0); - CHECK(ecount == 7); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(vrfy, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) != 0); - CHECK(ecount == 7); - - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(sign, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) != 0); - CHECK(ecount == 7); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(sttc, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); - CHECK(ecount == 8); - - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(both, NULL, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); - CHECK(ecount == 9); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(both, &proof, NULL, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); - CHECK(ecount == 10); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs + 1, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); - CHECK(ecount == 10); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs - 1, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); - CHECK(ecount == 10); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(both, &proof, ephemeral_input_tags, 0, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); - CHECK(ecount == 10); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, NULL, 0, input_blinding_key[0], output_blinding_key) == 0); - CHECK(ecount == 11); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 1, input_blinding_key[0], output_blinding_key) != 0); - CHECK(ecount == 11); /* the above line "succeeds" but generates an invalid proof as the input_index is wrong. it is fairly expensive to detect this. should we? */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, n_inputs + 1, input_blinding_key[0], output_blinding_key) != 0); - CHECK(ecount == 11); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, NULL, output_blinding_key) == 0); - CHECK(ecount == 12); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], NULL) == 0); - CHECK(ecount == 13); - - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) != 0); - /* check verify */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_verify(none, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_verify(sign, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 1); - CHECK(ecount == 13); - - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_verify(vrfy, NULL, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 0); - CHECK(ecount == 14); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_verify(vrfy, &proof, NULL, n_inputs, &ephemeral_output_tag) == 0); - CHECK(ecount == 15); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs - 1, &ephemeral_output_tag) == 0); - CHECK(ecount == 15); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs + 1, &ephemeral_output_tag) == 0); - CHECK(ecount == 15); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs, NULL) == 0); - CHECK(ecount == 16); - - /* Test how surjectionproof_generate fails when the proof was not created - * with surjectionproof_initialize */ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(sign, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 1); - { - rustsecp256k1zkp_v0_8_0_surjectionproof tmp_proof = proof; - tmp_proof.n_inputs = 0; - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(sign, &tmp_proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); - } - CHECK(ecount == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_generate(sign, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 1); - - /* Check serialize */ - ecount = 0; - serialized_len = sizeof(serialized_proof); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_serialize(none, serialized_proof, &serialized_len, &proof) != 0); - CHECK(ecount == 0); - serialized_len = sizeof(serialized_proof); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_serialize(none, NULL, &serialized_len, &proof) == 0); - CHECK(ecount == 1); - serialized_len = sizeof(serialized_proof); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_serialize(none, serialized_proof, NULL, &proof) == 0); - CHECK(ecount == 2); - serialized_len = sizeof(serialized_proof); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_serialize(none, serialized_proof, &serialized_len, NULL) == 0); - CHECK(ecount == 3); - - serialized_len = sizeof(serialized_proof); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_serialize(none, serialized_proof, &serialized_len, &proof) != 0); - /* Check parse */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(none, &proof, serialized_proof, serialized_len) != 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(none, NULL, serialized_proof, serialized_len) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(none, &proof, NULL, serialized_len) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(none, &proof, serialized_proof, 0) == 0); - CHECK(ecount == 5); - - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(vrfy); - rustsecp256k1zkp_v0_8_0_context_destroy(both); - rustsecp256k1zkp_v0_8_0_context_destroy(sttc); -} - -static void test_input_selection(size_t n_inputs) { - unsigned char seed[32]; - size_t i; - size_t result; - size_t input_index; - size_t try_count = n_inputs * 100; - rustsecp256k1zkp_v0_8_0_surjectionproof proof; - rustsecp256k1zkp_v0_8_0_fixed_asset_tag fixed_input_tags[1000]; - const size_t max_n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]) - 1; - - CHECK(n_inputs < max_n_inputs); - rustsecp256k1zkp_v0_8_0_testrand256(seed); - - for (i = 0; i < n_inputs + 1; i++) { - rustsecp256k1zkp_v0_8_0_testrand256(fixed_input_tags[i].data); - } - - /* cannot match output when told to use zero keys */ - result = rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], try_count, seed); - CHECK(result == 0); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_n_used_inputs(ctx, &proof) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_serialized_size(ctx, &proof) == 34 + (n_inputs + 7) / 8); - if (n_inputs > 0) { - /* succeed in 100*n_inputs tries (probability of failure e^-100) */ - result = rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 1, &fixed_input_tags[0], try_count, seed); - CHECK(result > 0); - CHECK(result < n_inputs * 10); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_n_used_inputs(ctx, &proof) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_serialized_size(ctx, &proof) == 66 + (n_inputs + 7) / 8); - CHECK(input_index == 0); - } - - if (n_inputs >= 3) { - /* succeed in 10*n_inputs tries (probability of failure e^-10) */ - result = rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[1], try_count, seed); - CHECK(result > 0); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_n_used_inputs(ctx, &proof) == 3); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_serialized_size(ctx, &proof) == 130 + (n_inputs + 7) / 8); - CHECK(input_index == 1); - - /* fail, key not found */ - result = rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[n_inputs], try_count, seed); - CHECK(result == 0); - - /* succeed on first try when told to use all keys */ - result = rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], try_count, seed); - CHECK(result == 1); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_n_used_inputs(ctx, &proof) == n_inputs); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_serialized_size(ctx, &proof) == 2 + 32 * (n_inputs + 1) + (n_inputs + 7) / 8); - CHECK(input_index == 0); - - /* succeed in less than 64 tries when told to use half keys. (probability of failure 2^-64) */ - result = rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs / 2, &fixed_input_tags[0], 64, seed); - CHECK(result > 0); - CHECK(result < 64); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_n_used_inputs(ctx, &proof) == n_inputs / 2); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_serialized_size(ctx, &proof) == 2 + 32 * (n_inputs / 2 + 1) + (n_inputs + 7) / 8); - CHECK(input_index == 0); - } -} - -/** Runs surjectionproof_initilize multiple times and records the number of times each input was used. - */ -static void test_input_selection_distribution_helper(const rustsecp256k1zkp_v0_8_0_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, size_t *used_inputs) { - rustsecp256k1zkp_v0_8_0_surjectionproof proof; - size_t input_index; - size_t i; - size_t j; - unsigned char seed[32]; - size_t result; - for (i = 0; i < n_input_tags; i++) { - used_inputs[i] = 0; - } - for(j = 0; j < 10000; j++) { - rustsecp256k1zkp_v0_8_0_testrand256(seed); - result = rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_input_tags, n_input_tags_to_use, &fixed_input_tags[0], 64, seed); - CHECK(result > 0); - - for (i = 0; i < n_input_tags; i++) { - if (proof.used_inputs[i / 8] & (1 << (i % 8))) { - used_inputs[i] += 1; - } - } - } -} - -/** Probabilistic test of the distribution of used_inputs after surjectionproof_initialize. - * Each confidence interval assertion fails incorrectly with a probability of 2^-128. - */ -static void test_input_selection_distribution(void) { - size_t i; - size_t n_input_tags_to_use; - const size_t n_inputs = 4; - rustsecp256k1zkp_v0_8_0_fixed_asset_tag fixed_input_tags[4]; - size_t used_inputs[4]; - - for (i = 0; i < n_inputs; i++) { - rustsecp256k1zkp_v0_8_0_testrand256(fixed_input_tags[i].data); - } - - /* If there is one input tag to use, initialize must choose the one equal to fixed_output_tag. */ - n_input_tags_to_use = 1; - test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); - CHECK(used_inputs[0] == 10000); - CHECK(used_inputs[1] == 0); - CHECK(used_inputs[2] == 0); - CHECK(used_inputs[3] == 0); - - n_input_tags_to_use = 2; - /* The input equal to the fixed_output_tag must be included in all used_inputs sets. - * For each fixed_input_tag != fixed_output_tag the probability that it's included - * in the used_inputs set is P(used_input|not fixed_output_tag) = 1/3. - */ - test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); - CHECK(used_inputs[0] == 10000); - CHECK(used_inputs[1] > 2725 && used_inputs[1] < 3961); - CHECK(used_inputs[2] > 2725 && used_inputs[2] < 3961); - CHECK(used_inputs[3] > 2725 && used_inputs[3] < 3961); - - n_input_tags_to_use = 3; - /* P(used_input|not fixed_output_tag) = 2/3 */ - test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); - CHECK(used_inputs[0] == 10000); - CHECK(used_inputs[1] > 6039 && used_inputs[1] < 7275); - CHECK(used_inputs[2] > 6039 && used_inputs[2] < 7275); - CHECK(used_inputs[3] > 6039 && used_inputs[3] < 7275); - - - n_input_tags_to_use = 1; - /* Create second input tag that is equal to the output tag. Therefore, when using only - * one input we have P(used_input|fixed_output_tag) = 1/2 and P(used_input|not fixed_output_tag) = 0 - */ - memcpy(fixed_input_tags[0].data, fixed_input_tags[1].data, 32); - test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); - CHECK(used_inputs[0] > 4345 && used_inputs[0] < 5655); - CHECK(used_inputs[1] > 4345 && used_inputs[1] < 5655); - CHECK(used_inputs[2] == 0); - CHECK(used_inputs[3] == 0); - - n_input_tags_to_use = 2; - /* When choosing 2 inputs in initialization there are 5 possible combinations of - * input indexes {(0, 1), (1, 2), (0, 3), (1, 3), (0, 2)}. Therefore we have - * P(used_input|fixed_output_tag) = 3/5 and P(used_input|not fixed_output_tag) = 2/5. - */ - test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); - CHECK(used_inputs[0] > 5352 && used_inputs[0] < 6637); - CHECK(used_inputs[1] > 5352 && used_inputs[1] < 6637); - CHECK(used_inputs[2] > 3363 && used_inputs[2] < 4648); - CHECK(used_inputs[3] > 3363 && used_inputs[3] < 4648); - - n_input_tags_to_use = 3; - /* There are 4 combinations, each with all inputs except one. Therefore we have - * P(used_input|fixed_output_tag) = 3/4 and P(used_input|not fixed_output_tag) = 3/4. - */ - test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); - CHECK(used_inputs[0] > 6918 && used_inputs[0] < 8053); - CHECK(used_inputs[1] > 6918 && used_inputs[1] < 8053); - CHECK(used_inputs[2] > 6918 && used_inputs[2] < 8053); - CHECK(used_inputs[3] > 6918 && used_inputs[3] < 8053); -} - -static void test_gen_verify(size_t n_inputs, size_t n_used) { - unsigned char seed[32]; - rustsecp256k1zkp_v0_8_0_surjectionproof proof; - unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX]; - unsigned char serialized_proof_trailing[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX + 1]; - size_t serialized_len = SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX; - rustsecp256k1zkp_v0_8_0_fixed_asset_tag fixed_input_tags[1000]; - rustsecp256k1zkp_v0_8_0_generator ephemeral_input_tags[1000]; - unsigned char *input_blinding_key[1000]; - const size_t max_n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]) - 1; - size_t try_count = n_inputs * 100; - size_t key_index; - size_t input_index; - size_t i; - int result; - - /* setup */ - CHECK(n_used <= n_inputs); - CHECK(n_inputs < max_n_inputs); - rustsecp256k1zkp_v0_8_0_testrand256(seed); - - key_index = (((size_t) seed[0] << 8) + seed[1]) % n_inputs; - - for (i = 0; i < n_inputs + 1; i++) { - input_blinding_key[i] = malloc(32); - rustsecp256k1zkp_v0_8_0_testrand256(input_blinding_key[i]); - /* choose random fixed tag, except that for the output one copy from the key_index */ - if (i < n_inputs) { - rustsecp256k1zkp_v0_8_0_testrand256(fixed_input_tags[i].data); - } else { - memcpy(&fixed_input_tags[i], &fixed_input_tags[key_index], sizeof(fixed_input_tags[i])); - } - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(ctx, &ephemeral_input_tags[i], fixed_input_tags[i].data, input_blinding_key[i])); - } - - /* test */ - result = rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_used, &fixed_input_tags[key_index], try_count, seed); - if (n_used == 0) { - CHECK(result == 0); - return; - } - CHECK(result > 0); - CHECK(input_index == key_index); - - result = rustsecp256k1zkp_v0_8_0_surjectionproof_generate(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs], input_index, input_blinding_key[input_index], input_blinding_key[n_inputs]); - CHECK(result == 1); - - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_serialize(ctx, serialized_proof, &serialized_len, &proof)); - CHECK(serialized_len == rustsecp256k1zkp_v0_8_0_surjectionproof_serialized_size(ctx, &proof)); - CHECK(serialized_len == SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(n_inputs, n_used)); - - /* trailing garbage */ - memcpy(&serialized_proof_trailing, &serialized_proof, serialized_len); - serialized_proof_trailing[serialized_len] = seed[0]; - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, serialized_proof_trailing, serialized_len + 1) == 0); - - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, serialized_proof, serialized_len)); - result = rustsecp256k1zkp_v0_8_0_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs]); - CHECK(result == 1); - - /* various fail cases */ - if (n_inputs > 1) { - result = rustsecp256k1zkp_v0_8_0_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs - 1]); - CHECK(result == 0); - - /* number of entries in ephemeral_input_tags array is less than proof.n_inputs */ - n_inputs -= 1; - result = rustsecp256k1zkp_v0_8_0_surjectionproof_generate(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs], input_index, input_blinding_key[input_index], input_blinding_key[n_inputs]); - CHECK(result == 0); - result = rustsecp256k1zkp_v0_8_0_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs - 1]); - CHECK(result == 0); - n_inputs += 1; - } - - for (i = 0; i < n_inputs; i++) { - /* flip bit */ - proof.used_inputs[i / 8] ^= (1 << (i % 8)); - result = rustsecp256k1zkp_v0_8_0_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs]); - CHECK(result == 0); - /* reset the bit */ - proof.used_inputs[i / 8] ^= (1 << (i % 8)); - } - - /* cleanup */ - for (i = 0; i < n_inputs + 1; i++) { - free(input_blinding_key[i]); - } -} - -/* check that a proof with empty n_used_inputs is invalid */ -static void test_no_used_inputs_verify(void) { - rustsecp256k1zkp_v0_8_0_surjectionproof proof; - rustsecp256k1zkp_v0_8_0_fixed_asset_tag fixed_input_tag; - rustsecp256k1zkp_v0_8_0_fixed_asset_tag fixed_output_tag; - rustsecp256k1zkp_v0_8_0_generator ephemeral_input_tags[1]; - size_t n_ephemeral_input_tags = 1; - rustsecp256k1zkp_v0_8_0_generator ephemeral_output_tag; - unsigned char blinding_key[32]; - rustsecp256k1zkp_v0_8_0_ge output; - rustsecp256k1zkp_v0_8_0_sha256 sha256_e0; - int result; - - /* Create proof that doesn't use inputs. rustsecp256k1zkp_v0_8_0_surjectionproof_initialize - * will not work here since it insists on selecting an input that matches the output. */ - proof.n_inputs = 1; - memset(proof.used_inputs, 0, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS / 8); - - /* create different fixed input and output tags */ - rustsecp256k1zkp_v0_8_0_testrand256(fixed_input_tag.data); - rustsecp256k1zkp_v0_8_0_testrand256(fixed_output_tag.data); - - /* blind fixed output tags with random blinding key */ - rustsecp256k1zkp_v0_8_0_testrand256(blinding_key); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(ctx, &ephemeral_input_tags[0], fixed_input_tag.data, blinding_key)); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(ctx, &ephemeral_output_tag, fixed_output_tag.data, blinding_key)); - - /* create "borromean signature" which is just a hash of metadata (pubkeys, etc) in this case */ - rustsecp256k1zkp_v0_8_0_generator_load(&output, &ephemeral_output_tag); - rustsecp256k1zkp_v0_8_0_surjection_genmessage(proof.data, ephemeral_input_tags, 1, &ephemeral_output_tag); - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha256_e0); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256_e0, proof.data, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha256_e0, proof.data); - - result = rustsecp256k1zkp_v0_8_0_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_ephemeral_input_tags, &ephemeral_output_tag); - CHECK(result == 0); -} - -void test_bad_serialize(void) { - rustsecp256k1zkp_v0_8_0_surjectionproof proof; - unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX]; - size_t serialized_len; - - proof.n_inputs = 0; - serialized_len = 2 + 31; - /* e0 is one byte too short */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_serialize(ctx, serialized_proof, &serialized_len, &proof) == 0); -} - -void test_bad_parse(void) { - rustsecp256k1zkp_v0_8_0_surjectionproof proof; - unsigned char serialized_proof0[] = { 0x00 }; - unsigned char serialized_proof1[] = { 0x01, 0x00 }; - unsigned char serialized_proof2[33] = { 0 }; - - /* Missing total input count */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, serialized_proof0, sizeof(serialized_proof0)) == 0); - /* Missing bitmap */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, serialized_proof1, sizeof(serialized_proof1)) == 0); - /* Missing e0 value */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, serialized_proof2, sizeof(serialized_proof2)) == 0); -} - -void test_input_eq_output(void) { - rustsecp256k1zkp_v0_8_0_surjectionproof proof; - rustsecp256k1zkp_v0_8_0_fixed_asset_tag fixed_tag; - rustsecp256k1zkp_v0_8_0_generator ephemeral_tag; - unsigned char blinding_key[32]; - unsigned char entropy[32]; - size_t input_index; - - rustsecp256k1zkp_v0_8_0_testrand256(fixed_tag.data); - rustsecp256k1zkp_v0_8_0_testrand256(blinding_key); - rustsecp256k1zkp_v0_8_0_testrand256(entropy); - - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_initialize(ctx, &proof, &input_index, &fixed_tag, 1, 1, &fixed_tag, 100, entropy) == 1); - CHECK(input_index == 0); - - /* Generation should fail */ - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(ctx, &ephemeral_tag, fixed_tag.data, blinding_key)); - CHECK(!rustsecp256k1zkp_v0_8_0_surjectionproof_generate(ctx, &proof, &ephemeral_tag, 1, &ephemeral_tag, input_index, blinding_key, blinding_key)); - - /* ...even when the blinding key is zero */ - memset(blinding_key, 0, 32); - CHECK(rustsecp256k1zkp_v0_8_0_generator_generate_blinded(ctx, &ephemeral_tag, fixed_tag.data, blinding_key)); - CHECK(!rustsecp256k1zkp_v0_8_0_surjectionproof_generate(ctx, &proof, &ephemeral_tag, 1, &ephemeral_tag, input_index, blinding_key, blinding_key)); -} - -void test_fixed_vectors(void) { - const unsigned char tag0_ser[] = { - 0x0a, - 0x1c, 0xa3, 0xdd, 0x12, 0x48, 0xdd, 0x4d, 0xd0, 0x04, 0x30, 0x47, 0x48, 0x75, 0xf5, 0xf5, 0xff, - 0x2a, 0xd5, 0x0d, 0x1d, 0x86, 0x2b, 0xa4, 0xa4, 0x2f, 0x46, 0xe9, 0xb4, 0x54, 0x21, 0xf0, 0x85 - }; - const unsigned char tag1_ser[] = { - 0x0a, - 0x09, 0x0d, 0x5a, 0xd4, 0xed, 0xae, 0x9c, 0x0c, 0x69, 0x79, 0xf3, 0x8d, 0x22, 0x03, 0x0a, 0x3d, - 0x38, 0xd4, 0x78, 0xe1, 0x03, 0x0d, 0x70, 0x57, 0xd9, 0x9a, 0x23, 0x03, 0xf0, 0x7f, 0xfb, 0xef - }; - const unsigned char tag2_ser[] = { - 0x0a, - 0xfd, 0xed, 0xba, 0x15, 0x20, 0x8a, 0xb2, 0xaf, 0x0b, 0x76, 0x6d, 0xd2, 0x5f, 0xd4, 0x15, 0x11, - 0x90, 0xec, 0xcb, 0x3f, 0xcd, 0x08, 0xb5, 0x35, 0xd9, 0x24, 0x18, 0xb1, 0xd3, 0x47, 0x83, 0x54 - }; - const unsigned char tag3_ser[] = { - 0x0b, - 0x8b, 0x47, 0xca, 0xee, 0x20, 0x52, 0x17, 0xbf, 0xee, 0xcc, 0x84, 0xcd, 0x34, 0x32, 0x6c, 0x36, - 0xf1, 0xd9, 0x3f, 0xe1, 0x6f, 0x77, 0xfe, 0x89, 0x3e, 0x4a, 0xc8, 0x2a, 0x75, 0xfa, 0x2d, 0x36 - }; - const unsigned char tag4_ser[] = { - 0x0b, - 0x3c, 0x5c, 0xf4, 0x61, 0x45, 0xa8, 0x53, 0xc1, 0x64, 0x32, 0x0e, 0x92, 0x68, 0x52, 0xbd, 0x12, - 0xe9, 0x45, 0x31, 0xeb, 0x04, 0x4c, 0xf4, 0xe2, 0x9e, 0x9f, 0x60, 0x26, 0x50, 0xbf, 0xd6, 0x9f - }; - const unsigned char output_tag_ser[] = { - 0x0b, - 0xf7, 0x3c, 0x03, 0xed, 0xae, 0x83, 0xa1, 0xa6, 0x94, 0x8c, 0xe3, 0xb8, 0x54, 0x02, 0xa8, 0xbd, - 0x66, 0xca, 0x28, 0xef, 0x44, 0xf5, 0x3a, 0xcb, 0xc7, 0x5b, 0x16, 0xac, 0xce, 0x29, 0x4b, 0xc6 - }; - - const unsigned char total1_used1[] = { - 0x01, 0x00, 0x01, 0x8e, 0x6b, 0x8d, 0x8b, 0x96, 0x29, 0x10, 0x29, 0xcb, 0xf8, 0x48, 0xd9, 0xc8, - 0x5b, 0x77, 0xdc, 0xdf, 0x16, 0x67, 0x19, 0xfe, 0x8d, 0xee, 0x8f, 0x56, 0x6f, 0x9c, 0xe9, 0xae, - 0xb9, 0xd9, 0x12, 0xb8, 0x95, 0x6c, 0xf1, 0x48, 0x07, 0x7d, 0x49, 0xe4, 0x3e, 0x7f, 0xc1, 0x2c, - 0xe2, 0xe1, 0x94, 0x10, 0xb1, 0xda, 0x86, 0x5f, 0xbc, 0x03, 0x59, 0xe1, 0x09, 0xd2, 0x1b, 0x18, - 0xce, 0x58, 0x15 - }; - const size_t total1_used1_len = sizeof(total1_used1); - - const unsigned char total2_used1[] = { - 0x02, 0x00, 0x01, 0x35, 0x3a, 0x29, 0x4b, 0xe4, 0x99, 0xc6, 0xbf, 0x99, 0x4d, 0x6c, 0xc8, 0x18, - 0x14, 0xad, 0x10, 0x22, 0x3a, 0xb8, 0x1c, 0xb9, 0xc5, 0x77, 0xda, 0xe0, 0x8a, 0x71, 0x2d, 0x0d, - 0x8e, 0x80, 0xf5, 0x8d, 0x74, 0xf9, 0x01, 0x6b, 0x35, 0x88, 0xf4, 0x8e, 0x43, 0xa5, 0x9c, 0x0f, - 0x7e, 0x37, 0x86, 0x77, 0x44, 0x72, 0x7c, 0xaa, 0xff, 0x14, 0x5b, 0x7a, 0x42, 0x41, 0x75, 0xb2, - 0x5e, 0x3d, 0x6c - }; - const size_t total2_used1_len = sizeof(total2_used1); - - const unsigned char total3_used2[] = { - 0x03, 0x00, 0x03, 0xf2, 0x3f, 0xca, 0x49, 0x52, 0x05, 0xaf, 0x81, 0x83, 0x01, 0xd7, 0xf4, 0x92, - 0xc0, 0x50, 0xe3, 0x15, 0xfc, 0x94, 0xc1, 0x27, 0x10, 0xd7, 0x8f, 0x57, 0xb1, 0x23, 0xcf, 0x68, - 0x31, 0xf8, 0xcb, 0x58, 0x3d, 0xca, 0x2f, 0x7a, 0x3b, 0x0b, 0xb6, 0x10, 0x52, 0x94, 0xc8, 0x5f, - 0x0a, 0xf8, 0xca, 0x5d, 0x4c, 0x38, 0x44, 0x92, 0xb3, 0xc7, 0xe4, 0x46, 0x9f, 0x96, 0x64, 0xbd, - 0xd2, 0xda, 0x40, 0xdb, 0x63, 0x76, 0x87, 0x48, 0xdc, 0x55, 0x0b, 0x82, 0x9c, 0xa5, 0x96, 0xbe, - 0xe9, 0x0d, 0xe4, 0x98, 0x80, 0x8e, 0x58, 0x38, 0xdc, 0x13, 0x59, 0x1d, 0x5c, 0x8e, 0xda, 0x90, - 0x4c, 0xa4, 0x91 - }; - const size_t total3_used2_len = sizeof(total3_used2); - - const unsigned char total5_used3[] = { - 0x05, 0x00, 0x15, 0x36, 0x3b, 0x92, 0x97, 0x84, 0x25, 0x75, 0xd6, 0xa6, 0xaf, 0xb7, 0x32, 0x5b, - 0x2c, 0xf8, 0x31, 0xe2, 0x15, 0x3a, 0x9b, 0xb7, 0x20, 0x14, 0xc0, 0x67, 0x96, 0x7d, 0xa9, 0xc4, - 0xa2, 0xb4, 0x22, 0x57, 0x5f, 0xb8, 0x20, 0xf1, 0xe8, 0x82, 0xaf, 0xbc, 0x8a, 0xbc, 0x01, 0xc9, - 0x35, 0xf2, 0x7f, 0x6f, 0x0c, 0x0d, 0xba, 0x87, 0xa4, 0xc3, 0xec, 0x60, 0x54, 0x49, 0x35, 0xeb, - 0x1e, 0x48, 0x2c, 0xdb, 0x63, 0x76, 0x87, 0x48, 0xdc, 0x55, 0x0b, 0x82, 0x9c, 0xa5, 0x96, 0xbe, - 0xe9, 0x0d, 0xe4, 0x98, 0x80, 0x8e, 0x58, 0x38, 0xdc, 0x13, 0x59, 0x1d, 0x5c, 0x8e, 0xda, 0x90, - 0x4c, 0xa4, 0x91, 0x5e, 0x8f, 0xcf, 0x2e, 0xc7, 0x5f, 0xfc, 0xca, 0x42, 0xd8, 0x80, 0xe4, 0x3b, - 0x90, 0xa5, 0xd2, 0x07, 0x7d, 0xd1, 0xc9, 0x5c, 0x69, 0xc2, 0xd7, 0xef, 0x8a, 0xae, 0x0a, 0xee, - 0x9c, 0xf5, 0xb9 - }; - const size_t total5_used3_len = sizeof(total5_used3); - - const unsigned char total5_used5[] = { - 0x05, 0x00, 0x1f, 0xfd, 0xbb, 0xb6, 0xc2, 0x78, 0x82, 0xad, 0xe1, 0x66, 0x6d, 0x20, 0x4d, 0xfe, - 0x6b, 0xd2, 0x0b, 0x21, 0x6e, 0xa8, 0x5b, 0xc8, 0xe4, 0x88, 0x42, 0x11, 0x30, 0x3b, 0x6b, 0x02, - 0xc9, 0x7f, 0x44, 0x1c, 0xee, 0xd8, 0x37, 0x6a, 0xf8, 0xfd, 0xc8, 0x4b, 0x0b, 0xa1, 0x43, 0x1f, - 0x68, 0x77, 0x8d, 0x1b, 0xac, 0x9e, 0xc1, 0xc1, 0xda, 0x60, 0xa8, 0xcf, 0x10, 0x9d, 0x80, 0x07, - 0x90, 0x57, 0xb6, 0xdb, 0x63, 0x76, 0x87, 0x48, 0xdc, 0x55, 0x0b, 0x82, 0x9c, 0xa5, 0x96, 0xbe, - 0xe9, 0x0d, 0xe4, 0x98, 0x80, 0x8e, 0x58, 0x38, 0xdc, 0x13, 0x59, 0x1d, 0x5c, 0x8e, 0xda, 0x90, - 0x4c, 0xa4, 0x91, 0x5e, 0x8f, 0xcf, 0x2e, 0xc7, 0x5f, 0xfc, 0xca, 0x42, 0xd8, 0x80, 0xe4, 0x3b, - 0x90, 0xa5, 0xd2, 0x07, 0x7d, 0xd1, 0xc9, 0x5c, 0x69, 0xc2, 0xd7, 0xef, 0x8a, 0xae, 0x0a, 0xee, - 0x9c, 0xf5, 0xb9, 0x5a, 0xc8, 0x03, 0x8d, 0x4f, 0xe3, 0x1d, 0x79, 0x38, 0x5a, 0xfa, 0xe5, 0xa8, - 0x9d, 0x56, 0x77, 0xb3, 0xf9, 0xa8, 0x70, 0x46, 0x27, 0x26, 0x6c, 0x6e, 0x54, 0xaf, 0xf9, 0xd0, - 0x37, 0xa4, 0x86, 0x68, 0x8f, 0xac, 0x3e, 0x78, 0xaa, 0x3d, 0x83, 0x1a, 0xca, 0x05, 0xfe, 0x10, - 0x95, 0xa4, 0x6a, 0x10, 0xc6, 0x62, 0xf3, 0xf7, 0xf3, 0x4d, 0x0b, 0xd4, 0x94, 0xe5, 0x51, 0x6c, - 0x85, 0xd7, 0xc7 - }; - const size_t total5_used5_len = sizeof(total5_used5); - - unsigned char bad[sizeof(total5_used5) + 32] = { 0 }; - - rustsecp256k1zkp_v0_8_0_generator input_tags[5]; - rustsecp256k1zkp_v0_8_0_generator output_tag; - rustsecp256k1zkp_v0_8_0_surjectionproof proof; - - CHECK(rustsecp256k1zkp_v0_8_0_generator_parse(ctx, &input_tags[0], tag0_ser)); - CHECK(rustsecp256k1zkp_v0_8_0_generator_parse(ctx, &input_tags[1], tag1_ser)); - CHECK(rustsecp256k1zkp_v0_8_0_generator_parse(ctx, &input_tags[2], tag2_ser)); - CHECK(rustsecp256k1zkp_v0_8_0_generator_parse(ctx, &input_tags[3], tag3_ser)); - CHECK(rustsecp256k1zkp_v0_8_0_generator_parse(ctx, &input_tags[4], tag4_ser)); - CHECK(rustsecp256k1zkp_v0_8_0_generator_parse(ctx, &output_tag, output_tag_ser)); - - /* check 1-of-1 */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, total1_used1, total1_used1_len)); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_verify(ctx, &proof, input_tags, 1, &output_tag)); - /* check 1-of-2 */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, total2_used1, total2_used1_len)); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_verify(ctx, &proof, input_tags, 2, &output_tag)); - /* check 2-of-3 */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, total3_used2, total3_used2_len)); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_verify(ctx, &proof, input_tags, 3, &output_tag)); - /* check 3-of-5 */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, total5_used3, total5_used3_len)); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_verify(ctx, &proof, input_tags, 5, &output_tag)); - /* check 5-of-5 */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, total5_used5, total5_used5_len)); - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_verify(ctx, &proof, input_tags, 5, &output_tag)); - - /* check invalid length fails */ - CHECK(!rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, total5_used5, total5_used3_len)); - /* check invalid keys fail */ - CHECK(rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, total1_used1, total1_used1_len)); - CHECK(!rustsecp256k1zkp_v0_8_0_surjectionproof_verify(ctx, &proof, &input_tags[1], 1, &output_tag)); - CHECK(!rustsecp256k1zkp_v0_8_0_surjectionproof_verify(ctx, &proof, input_tags, 1, &input_tags[0])); - - /* Try setting 6 bits on the total5-used-5; check that parsing fails */ - memcpy(bad, total5_used5, total5_used5_len); - bad[2] = 0x3f; /* 0x1f -> 0x3f */ - CHECK(!rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, bad, total5_used5_len)); - /* Correct for the length */ - CHECK(!rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, bad, total5_used5_len + 32)); - /* Alternately just turn off one of the "legit" bits */ - bad[2] = 0x37; /* 0x1f -> 0x37 */ - CHECK(!rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, bad, total5_used5_len)); - - /* Similarly try setting 4 bits on the total5-used-3, with one bit out of range */ - memcpy(bad, total5_used3, total5_used3_len); - bad[2] = 0x35; /* 0x15 -> 0x35 */ - CHECK(!rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, bad, total5_used3_len)); - CHECK(!rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, bad, total5_used3_len + 32)); - bad[2] = 0x34; /* 0x15 -> 0x34 */ - CHECK(!rustsecp256k1zkp_v0_8_0_surjectionproof_parse(ctx, &proof, bad, total5_used3_len)); -} - -void run_surjection_tests(void) { - test_surjectionproof_api(); - test_input_eq_output(); - test_fixed_vectors(); - - test_input_selection(0); - test_input_selection(1); - test_input_selection(5); - test_input_selection(SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS); - - test_input_selection_distribution(); - test_gen_verify(10, 3); - test_gen_verify(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS); - test_no_used_inputs_verify(); - test_bad_serialize(); - test_bad_parse(); -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/Makefile.am.include b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/Makefile.am.include deleted file mode 100644 index 328c1e3d..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/Makefile.am.include +++ /dev/null @@ -1,11 +0,0 @@ -include_HEADERS += include/rustsecp256k1zkp_v0_8_0_whitelist.h -noinst_HEADERS += src/modules/whitelist/whitelist_impl.h -noinst_HEADERS += src/modules/whitelist/main_impl.h -noinst_HEADERS += src/modules/whitelist/tests_impl.h -if USE_BENCHMARK -noinst_PROGRAMS += bench_whitelist -bench_whitelist_SOURCES = src/bench_whitelist.c -bench_whitelist_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES) -bench_whitelist_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_generator_LDFLAGS = -static -endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/main_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/main_impl.h deleted file mode 100644 index eb4f774c..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/main_impl.h +++ /dev/null @@ -1,168 +0,0 @@ -/********************************************************************** - * Copyright (c) 2016 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_WHITELIST_MAIN -#define SECP256K1_MODULE_WHITELIST_MAIN - -#include "../../../include/secp256k1_whitelist.h" -#include "whitelist_impl.h" - -#define MAX_KEYS SECP256K1_WHITELIST_MAX_N_KEYS /* shorter alias */ - -int rustsecp256k1zkp_v0_8_0_whitelist_sign(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_whitelist_signature *sig, const rustsecp256k1zkp_v0_8_0_pubkey *online_pubkeys, const rustsecp256k1zkp_v0_8_0_pubkey *offline_pubkeys, const size_t n_keys, const rustsecp256k1zkp_v0_8_0_pubkey *sub_pubkey, const unsigned char *online_seckey, const unsigned char *summed_seckey, const size_t index) { - rustsecp256k1zkp_v0_8_0_gej pubs[MAX_KEYS]; - rustsecp256k1zkp_v0_8_0_scalar s[MAX_KEYS]; - rustsecp256k1zkp_v0_8_0_scalar sec, non; - unsigned char msg32[32]; - int ret; - - /* Sanity checks */ - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(sig != NULL); - ARG_CHECK(online_pubkeys != NULL); - ARG_CHECK(offline_pubkeys != NULL); - ARG_CHECK(n_keys <= MAX_KEYS); - ARG_CHECK(sub_pubkey != NULL); - ARG_CHECK(online_seckey != NULL); - ARG_CHECK(summed_seckey != NULL); - ARG_CHECK(index < n_keys); - - /* Compute pubkeys: online_pubkey + tweaked(offline_pubkey + address), and message */ - ret = rustsecp256k1zkp_v0_8_0_whitelist_compute_keys_and_message(ctx, msg32, pubs, online_pubkeys, offline_pubkeys, n_keys, sub_pubkey); - - /* Compute signing key: online_seckey + tweaked(summed_seckey) */ - if (ret) { - ret = rustsecp256k1zkp_v0_8_0_whitelist_compute_tweaked_privkey(ctx, &sec, online_seckey, summed_seckey); - } - /* Compute nonce and random s-values */ - if (ret) { - unsigned char seckey32[32]; - unsigned int count = 0; - int overflow = 0; - - rustsecp256k1zkp_v0_8_0_scalar_get_b32(seckey32, &sec); - while (1) { - size_t i; - unsigned char nonce32[32]; - int done; - ret = rustsecp256k1zkp_v0_8_0_nonce_function_default(nonce32, msg32, seckey32, NULL, NULL, count); - if (!ret) { - break; - } - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&non, nonce32, &overflow); - memset(nonce32, 0, 32); - if (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(&non)) { - count++; - continue; - } - done = 1; - for (i = 0; i < n_keys; i++) { - msg32[0] ^= i + 1; - msg32[1] ^= (i + 1) / 0x100; - ret = rustsecp256k1zkp_v0_8_0_nonce_function_default(&sig->data[32 * (i + 1)], msg32, seckey32, NULL, NULL, count); - if (!ret) { - break; - } - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&s[i], &sig->data[32 * (i + 1)], &overflow); - msg32[0] ^= i + 1; - msg32[1] ^= (i + 1) / 0x100; - if (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(&s[i])) { - count++; - done = 0; - break; - } - } - if (done) { - break; - } - } - memset(seckey32, 0, 32); - } - /* Actually sign */ - if (ret) { - sig->n_keys = n_keys; - ret = rustsecp256k1zkp_v0_8_0_borromean_sign(&ctx->ecmult_gen_ctx, &sig->data[0], s, pubs, &non, &sec, &n_keys, &index, 1, msg32, 32); - /* Signing will change s[index], so update in the sig structure */ - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&sig->data[32 * (index + 1)], &s[index]); - } - - rustsecp256k1zkp_v0_8_0_scalar_clear(&non); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sec); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_whitelist_verify(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_whitelist_signature *sig, const rustsecp256k1zkp_v0_8_0_pubkey *online_pubkeys, const rustsecp256k1zkp_v0_8_0_pubkey *offline_pubkeys, const size_t n_keys, const rustsecp256k1zkp_v0_8_0_pubkey *sub_pubkey) { - rustsecp256k1zkp_v0_8_0_scalar s[MAX_KEYS]; - rustsecp256k1zkp_v0_8_0_gej pubs[MAX_KEYS]; - unsigned char msg32[32]; - size_t i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(online_pubkeys != NULL); - ARG_CHECK(offline_pubkeys != NULL); - ARG_CHECK(sub_pubkey != NULL); - - if (sig->n_keys > MAX_KEYS || sig->n_keys != n_keys) { - return 0; - } - for (i = 0; i < sig->n_keys; i++) { - int overflow = 0; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&s[i], &sig->data[32 * (i + 1)], &overflow); - if (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(&s[i])) { - return 0; - } - } - - /* Compute pubkeys: online_pubkey + tweaked(offline_pubkey + address), and message */ - if (!rustsecp256k1zkp_v0_8_0_whitelist_compute_keys_and_message(ctx, msg32, pubs, online_pubkeys, offline_pubkeys, sig->n_keys, sub_pubkey)) { - return 0; - } - /* Do verification */ - return rustsecp256k1zkp_v0_8_0_borromean_verify(NULL, &sig->data[0], s, pubs, &sig->n_keys, 1, msg32, 32); -} - -size_t rustsecp256k1zkp_v0_8_0_whitelist_signature_n_keys(const rustsecp256k1zkp_v0_8_0_whitelist_signature *sig) { - return sig->n_keys; -} - -int rustsecp256k1zkp_v0_8_0_whitelist_signature_parse(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_whitelist_signature *sig, const unsigned char *input, size_t input_len) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(input != NULL); - - if (input_len == 0) { - return 0; - } - - sig->n_keys = input[0]; - if (sig->n_keys > MAX_KEYS || input_len != 1 + 32 * (sig->n_keys + 1)) { - return 0; - } - memcpy(&sig->data[0], &input[1], 32 * (sig->n_keys + 1)); - - return 1; -} - -int rustsecp256k1zkp_v0_8_0_whitelist_signature_serialize(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *output, size_t *output_len, const rustsecp256k1zkp_v0_8_0_whitelist_signature *sig) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output != NULL); - ARG_CHECK(output_len != NULL); - ARG_CHECK(sig != NULL); - - if (*output_len < 1 + 32 * (sig->n_keys + 1)) { - return 0; - } - - output[0] = sig->n_keys; - memcpy(&output[1], &sig->data[0], 32 * (sig->n_keys + 1)); - *output_len = 1 + 32 * (sig->n_keys + 1); - - return 1; -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/tests_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/tests_impl.h deleted file mode 100644 index 4004ab44..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/tests_impl.h +++ /dev/null @@ -1,163 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014-2016 Pieter Wuille, Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_WHITELIST_TESTS -#define SECP256K1_MODULE_WHITELIST_TESTS - -#include "../../../include/secp256k1_whitelist.h" - -void test_whitelist_end_to_end_internal(const unsigned char *summed_seckey, const unsigned char *online_seckey, const rustsecp256k1zkp_v0_8_0_pubkey *online_pubkeys, const rustsecp256k1zkp_v0_8_0_pubkey *offline_pubkeys, const rustsecp256k1zkp_v0_8_0_pubkey *sub_pubkey, const size_t signer_i, const size_t n_keys) { - unsigned char serialized[32 + 4 + 32 * SECP256K1_WHITELIST_MAX_N_KEYS] = {0}; - size_t slen = sizeof(serialized); - rustsecp256k1zkp_v0_8_0_whitelist_signature sig; - rustsecp256k1zkp_v0_8_0_whitelist_signature sig1; - - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_sign(ctx, &sig, online_pubkeys, offline_pubkeys, n_keys, sub_pubkey, online_seckey, summed_seckey, signer_i)); - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_verify(ctx, &sig, online_pubkeys, offline_pubkeys, n_keys, sub_pubkey) == 1); - /* Check that exchanging keys causes a failure */ - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_verify(ctx, &sig, offline_pubkeys, online_pubkeys, n_keys, sub_pubkey) != 1); - /* Serialization round trip */ - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_signature_serialize(ctx, serialized, &slen, &sig) == 1); - CHECK(slen == 33 + 32 * n_keys); - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_signature_parse(ctx, &sig1, serialized, slen) == 1); - /* (Check various bad-length conditions) */ - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_signature_parse(ctx, &sig1, serialized, slen + 32) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_signature_parse(ctx, &sig1, serialized, slen + 1) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_signature_parse(ctx, &sig1, serialized, slen - 1) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_signature_parse(ctx, &sig1, serialized, 0) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_verify(ctx, &sig1, online_pubkeys, offline_pubkeys, n_keys, sub_pubkey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_verify(ctx, &sig1, offline_pubkeys, online_pubkeys, n_keys, sub_pubkey) != 1); - - /* Test n_keys */ - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_signature_n_keys(&sig) == n_keys); - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_signature_n_keys(&sig1) == n_keys); - - /* Test bad number of keys in signature */ - sig.n_keys = n_keys + 1; - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_verify(ctx, &sig, offline_pubkeys, online_pubkeys, n_keys, sub_pubkey) != 1); - sig.n_keys = n_keys; -} - -void test_whitelist_end_to_end(const size_t n_keys, int test_all_keys) { - unsigned char **online_seckey = (unsigned char **) malloc(n_keys * sizeof(*online_seckey)); - unsigned char **summed_seckey = (unsigned char **) malloc(n_keys * sizeof(*summed_seckey)); - rustsecp256k1zkp_v0_8_0_pubkey *online_pubkeys = (rustsecp256k1zkp_v0_8_0_pubkey *) malloc(n_keys * sizeof(*online_pubkeys)); - rustsecp256k1zkp_v0_8_0_pubkey *offline_pubkeys = (rustsecp256k1zkp_v0_8_0_pubkey *) malloc(n_keys * sizeof(*offline_pubkeys)); - - rustsecp256k1zkp_v0_8_0_scalar ssub; - unsigned char csub[32]; - rustsecp256k1zkp_v0_8_0_pubkey sub_pubkey; - - /* Generate random keys */ - size_t i; - /* Start with subkey */ - random_scalar_order_test(&ssub); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(csub, &ssub); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, csub) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &sub_pubkey, csub) == 1); - /* Then offline and online whitelist keys */ - for (i = 0; i < n_keys; i++) { - rustsecp256k1zkp_v0_8_0_scalar son, soff; - - online_seckey[i] = (unsigned char *) malloc(32); - summed_seckey[i] = (unsigned char *) malloc(32); - - /* Create two keys */ - random_scalar_order_test(&son); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(online_seckey[i], &son); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, online_seckey[i]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &online_pubkeys[i], online_seckey[i]) == 1); - - random_scalar_order_test(&soff); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(summed_seckey[i], &soff); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, summed_seckey[i]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &offline_pubkeys[i], summed_seckey[i]) == 1); - - /* Make summed_seckey correspond to the sum of offline_pubkey and sub_pubkey */ - rustsecp256k1zkp_v0_8_0_scalar_add(&soff, &soff, &ssub); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(summed_seckey[i], &soff); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, summed_seckey[i]) == 1); - } - - /* Sign/verify with each one */ - if (test_all_keys) { - for (i = 0; i < n_keys; i++) { - test_whitelist_end_to_end_internal(summed_seckey[i], online_seckey[i], online_pubkeys, offline_pubkeys, &sub_pubkey, i, n_keys); - } - } else { - uint32_t rand_idx = rustsecp256k1zkp_v0_8_0_testrand_int(n_keys-1); - test_whitelist_end_to_end_internal(summed_seckey[0], online_seckey[0], online_pubkeys, offline_pubkeys, &sub_pubkey, 0, n_keys); - test_whitelist_end_to_end_internal(summed_seckey[rand_idx], online_seckey[rand_idx], online_pubkeys, offline_pubkeys, &sub_pubkey, rand_idx, n_keys); - test_whitelist_end_to_end_internal(summed_seckey[n_keys-1], online_seckey[n_keys-1], online_pubkeys, offline_pubkeys, &sub_pubkey, n_keys-1, n_keys); - } - - for (i = 0; i < n_keys; i++) { - free(online_seckey[i]); - free(summed_seckey[i]); - } - free(online_seckey); - free(summed_seckey); - free(online_pubkeys); - free(offline_pubkeys); -} - -void test_whitelist_bad_parse(void) { - rustsecp256k1zkp_v0_8_0_whitelist_signature sig; - - const unsigned char serialized0[] = { 1+32*(0+1) }; - const unsigned char serialized1[] = { - 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 - }; - const unsigned char serialized2[] = { - 0x01, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 - }; - - /* Empty input */ - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_signature_parse(ctx, &sig, serialized0, 0) == 0); - /* Misses one byte of e0 */ - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_signature_parse(ctx, &sig, serialized1, sizeof(serialized1)) == 0); - /* Enough bytes for e0, but there is no s value */ - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_signature_parse(ctx, &sig, serialized2, sizeof(serialized2)) == 0); -} - -void test_whitelist_bad_serialize(void) { - unsigned char serialized[] = { - 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 - }; - size_t serialized_len; - rustsecp256k1zkp_v0_8_0_whitelist_signature sig; - - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_signature_parse(ctx, &sig, serialized, sizeof(serialized)) == 1); - serialized_len = sizeof(serialized) - 1; - /* Output buffer is one byte too short */ - CHECK(rustsecp256k1zkp_v0_8_0_whitelist_signature_serialize(ctx, serialized, &serialized_len, &sig) == 0); -} - -void run_whitelist_tests(void) { - int i; - test_whitelist_bad_parse(); - test_whitelist_bad_serialize(); - for (i = 0; i < count; i++) { - test_whitelist_end_to_end(1, 1); - test_whitelist_end_to_end(10, 1); - test_whitelist_end_to_end(50, 1); - test_whitelist_end_to_end(SECP256K1_WHITELIST_MAX_N_KEYS, 0); - } -} - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/whitelist.md b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/whitelist.md deleted file mode 100644 index 28307f4b..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/whitelist.md +++ /dev/null @@ -1,107 +0,0 @@ -Address Whitelisting Module -=========================== - -This module implements a scheme by which members of some group, having fixed -signing keys, can prove control of an arbitrary other key without associating -their own identity (only that they belong to the group) to the new key. The -application is to patch ring-signature-like behaviour onto systems such as -Bitcoin or PGP which do not directly support this. - -We refer to such delegation as "whitelisting" because we expect it to be used -to build a dynamic whitelist of authorized keys. - -For example, imagine a private sidechain with a fixed membership set but -stronger privacy properties than Bitcoin. When moving coins from this system -to Bitcoin, it is desirable that the destination Bitcoin addresses be provably -in control of some user of the sidechain. This prevents malicious or erroneous -behaviour on the sidechain, which can likely be resolved by its participants, -from translating to theft on the wider Bitcoin network, which is irreversible. - -### Unused Schemes and Design Rationale - -#### Direct Signing - -An obvious scheme for such delegation is to simply have participants sign the -key they want to whitelist. To avoid revealing their specific identity, they -could use a ring signature. The problem with this is that it really only proves -that a participant *signed off* on a key, not that they control it. Thus any -security failure that allows text substitution could be used to subvert this -and redirect coins to an attacker-controlled address. - -#### Signing with Difference-of-Keys - -A less obvious scheme is to have a participant sign an arbitrary message with -the sum of her key `P` and the whitelisted key `W`. Such a signature with the key -`P + W` proves knowledge of either (a) discrete logarithms of both `P` and `W`; -or (b) neither. This makes directly attacking participants' signing schemes much -harder, but allows an attacker to whitelist arbitrary "cancellation" keys by -computing `W` as the difference between an attacker-controlled key and `P`. -Because to spend the funds the attacker must produce a signature with `W`, the -coins will be unspendable until attacker and the legitimate participant owning -`P` cooperate. - -In an important sense, this "cancellation" attack is a good thing: it enables -*offline delegation*. That is, the key `P` does not need to be available at the -time of delegation. Instead, participants could choose `S = P + W`, sign with -this to delegate, and only later compute the discrete logarithm of `W = P - S`. -This allows `P` to be in cold storage or be otherwise inaccessible, improving -the overall system security. - -#### Signing with Tweaked-Difference-of-Keys - -A modification of this scheme, which prevents this "cancellation" attack, is to -instead have participants sign some message with the key `P + H(W)W`, for `H` -some random-oracle hash that maps group elements to scalars. This key, and its -discrete logarithm, cannot be known until after `W` is chosen, so `W` cannot -be selected as the difference between it and `P`. (Note that `P` could still -be some chosen difference; however `P` is a fixed key and must be verified -out-of-band to have come from a legitimate participant anyway.) - -This scheme is almost what we want, but it no longer supports offline -delegation. However, we can get this back by introducing a new key, `P'`, -and signing with the key `P + H(W + P')(W + P')`. This gives us the best -of both worlds: `P'` does not need to be online to delegate, allowing it -to be securely stored and preventing real-time attacks; `P` does need to -be online, but its compromise only allows an attacker to whitelist keys he does -not control alone. - -### Our Scheme - -Our scheme works as follows: each participant `i` chooses two keys, `P_i` and `Q_i`. -We refer to `P_i` as the "online key" and `Q_i` as the "offline key". To whitelist -a key `W`, the participant computes the key `L_j = P_j + H(W + Q_j)(W + Q_j)` for -every participant `j`. Then she will know the discrete logarithm of `L_i` for her -own `i`. - -Next, she signs a message containing every `P_i` and `Q_i` as well as `W` with -a ring signature over all the keys `L_j`. This proves that she knows the discrete -logarithm of some `L_i` (though it is zero-knowledge which one), and therefore -knows: -1. The discrete logarithms of all of `W`, `P_i` and `Q_i`; or -2. The discrete logarithm of `P_i` but of *neither* `W` nor `Q_i`. -In other words, compromise of the online key `P_i` allows an attacker to whitelist -"cancellation keys" for which the attacker alone does not know the discrete logarithm; -to whitelist an attacker-controlled key, he must compromise both `P_i` and `Q_i`. This is difficult -because by design, only the sum `S = W + Q_i` is used when signing; then by choosing -`S` freely, a participant can delegate without the secret key to `Q_i` ever being online. -(Later, when she wants to actually use `W`, she will need to compute its key as the -difference between `S` and `Q_i`; but this can be done offline and much later -and with more expensive security requirements.) - -The message to be signed contains all public keys to prevent a class of attacks -centered around choosing keys to match pre-computed signatures. In our proposed -use case, whitelisted keys already must be computed before they are signed, and -the remaining public keys are verified out-of-band when setting up the system, -so there is no direct benefit to this. We do it only to reduce fragility and -increase safety of unforeseen uses. - -Having to access the offline key `Q_i` to compute the secret to the sum `W + -Q_i` for every authorization is onerous. Instead, if the whitelisted keys are -created using -[BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) -unhardened derivation, the sum can be computed on an online machine. In order -to achieve that, the offline key `Q_j` is set to the negated last hardened -BIP32 derived parent key (typically, the public key corresponding to the xpub). -As a result `W + Q_i = I_L*G` where `I_L` is the public tweak used -to derive `W` and can be easily computed online using the extended public key -and the derivation path. diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/whitelist_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/whitelist_impl.h deleted file mode 100644 index eb81de75..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/whitelist/whitelist_impl.h +++ /dev/null @@ -1,129 +0,0 @@ -/********************************************************************** - * Copyright (c) 2016 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_WHITELIST_IMPL_H_ -#define _SECP256K1_WHITELIST_IMPL_H_ - -static int rustsecp256k1zkp_v0_8_0_whitelist_hash_pubkey(rustsecp256k1zkp_v0_8_0_scalar* output, rustsecp256k1zkp_v0_8_0_gej* pubkey) { - unsigned char h[32]; - unsigned char c[33]; - rustsecp256k1zkp_v0_8_0_sha256 sha; - int overflow = 0; - size_t size = 33; - rustsecp256k1zkp_v0_8_0_ge ge; - - rustsecp256k1zkp_v0_8_0_ge_set_gej(&ge, pubkey); - - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&ge, c, &size, SECP256K1_EC_COMPRESSED)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, c, size); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, h); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(output, h, &overflow); - if (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(output)) { - /* This return path is mathematically impossible to hit */ - rustsecp256k1zkp_v0_8_0_scalar_clear(output); - return 0; - } - return 1; -} - -static int rustsecp256k1zkp_v0_8_0_whitelist_tweak_pubkey(rustsecp256k1zkp_v0_8_0_gej* pub_tweaked) { - rustsecp256k1zkp_v0_8_0_scalar tweak; - rustsecp256k1zkp_v0_8_0_scalar zero; - int ret; - - rustsecp256k1zkp_v0_8_0_scalar_set_int(&zero, 0); - - ret = rustsecp256k1zkp_v0_8_0_whitelist_hash_pubkey(&tweak, pub_tweaked); - if (ret) { - rustsecp256k1zkp_v0_8_0_ecmult(pub_tweaked, pub_tweaked, &tweak, &zero); - } - return ret; -} - -static int rustsecp256k1zkp_v0_8_0_whitelist_compute_tweaked_privkey(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_scalar* skey, const unsigned char *online_key, const unsigned char *summed_key) { - rustsecp256k1zkp_v0_8_0_scalar tweak; - int ret = 1; - int overflow = 0; - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(skey, summed_key, &overflow); - if (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(skey)) { - ret = 0; - } - if (ret) { - rustsecp256k1zkp_v0_8_0_gej pkeyj; - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &pkeyj, skey); - ret = rustsecp256k1zkp_v0_8_0_whitelist_hash_pubkey(&tweak, &pkeyj); - } - if (ret) { - rustsecp256k1zkp_v0_8_0_scalar sonline; - rustsecp256k1zkp_v0_8_0_scalar_mul(skey, skey, &tweak); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&sonline, online_key, &overflow); - if (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(&sonline)) { - ret = 0; - } - rustsecp256k1zkp_v0_8_0_scalar_add(skey, skey, &sonline); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sonline); - rustsecp256k1zkp_v0_8_0_scalar_clear(&tweak); - } - - if (!ret) { - rustsecp256k1zkp_v0_8_0_scalar_clear(skey); - } - return ret; -} - -/* Takes a list of pubkeys and combines them to form the public keys needed - * for the ring signature; also produce a commitment to every one that will - * be our "message". */ -static int rustsecp256k1zkp_v0_8_0_whitelist_compute_keys_and_message(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *msg32, rustsecp256k1zkp_v0_8_0_gej *keys, const rustsecp256k1zkp_v0_8_0_pubkey *online_pubkeys, const rustsecp256k1zkp_v0_8_0_pubkey *offline_pubkeys, const int n_keys, const rustsecp256k1zkp_v0_8_0_pubkey *sub_pubkey) { - unsigned char c[33]; - size_t size = 33; - rustsecp256k1zkp_v0_8_0_sha256 sha; - int i; - rustsecp256k1zkp_v0_8_0_ge subkey_ge; - - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &subkey_ge, sub_pubkey); - - /* commit to sub-key */ - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&subkey_ge, c, &size, SECP256K1_EC_COMPRESSED)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, c, size); - for (i = 0; i < n_keys; i++) { - rustsecp256k1zkp_v0_8_0_ge offline_ge; - rustsecp256k1zkp_v0_8_0_ge online_ge; - rustsecp256k1zkp_v0_8_0_gej tweaked_gej; - - /* commit to fixed keys */ - rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &offline_ge, &offline_pubkeys[i]); - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&offline_ge, c, &size, SECP256K1_EC_COMPRESSED)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, c, size); - rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &online_ge, &online_pubkeys[i]); - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&online_ge, c, &size, SECP256K1_EC_COMPRESSED)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, c, size); - - /* compute tweaked keys */ - rustsecp256k1zkp_v0_8_0_gej_set_ge(&tweaked_gej, &offline_ge); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&tweaked_gej, &tweaked_gej, &subkey_ge, NULL); - rustsecp256k1zkp_v0_8_0_whitelist_tweak_pubkey(&tweaked_gej); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&keys[i], &tweaked_gej, &online_ge, NULL); - } - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, msg32); - return 1; -} - - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precompute_ecmult_gen.c b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precompute_ecmult_gen.c deleted file mode 100644 index 015feb3e..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precompute_ecmult_gen.c +++ /dev/null @@ -1,80 +0,0 @@ -/********************************************************************************* - * Copyright (c) 2013, 2014, 2015, 2021 Thomas Daede, Cory Fields, Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php. * - *********************************************************************************/ - -#include -#include - -#include "../include/secp256k1.h" -#include "assumptions.h" -#include "util.h" -#include "group.h" -#include "ecmult_gen.h" -#include "ecmult_gen_compute_table_impl.h" - -int main(int argc, char **argv) { - const char outfile[] = "src/precomputed_ecmult_gen.c"; - FILE* fp; - int bits; - - (void)argc; - (void)argv; - - fp = fopen(outfile, "w"); - if (fp == NULL) { - fprintf(stderr, "Could not open %s for writing!\n", outfile); - return -1; - } - - fprintf(fp, "/* This file was automatically generated by precompute_ecmult_gen. */\n"); - fprintf(fp, "/* See ecmult_gen_impl.h for details about the contents of this file. */\n"); - fprintf(fp, "#if defined HAVE_CONFIG_H\n"); - fprintf(fp, "# include \"libsecp256k1-config.h\"\n"); - fprintf(fp, "#endif\n"); - fprintf(fp, "#include \"../include/secp256k1.h\"\n"); - fprintf(fp, "#include \"group.h\"\n"); - fprintf(fp, "#include \"ecmult_gen.h\"\n"); - fprintf(fp, "#include \"precomputed_ecmult_gen.h\"\n"); - fprintf(fp, "#ifdef EXHAUSTIVE_TEST_ORDER\n"); - fprintf(fp, "# error Cannot compile precomputed_ecmult_gen.c in exhaustive test mode\n"); - fprintf(fp, "#endif /* EXHAUSTIVE_TEST_ORDER */\n"); - fprintf(fp, "#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)\n"); - fprintf(fp, "const rustsecp256k1zkp_v0_8_0_ge_storage rustsecp256k1zkp_v0_8_0_ecmult_gen_prec_table[ECMULT_GEN_PREC_N(ECMULT_GEN_PREC_BITS)][ECMULT_GEN_PREC_G(ECMULT_GEN_PREC_BITS)] = {\n"); - - for (bits = 2; bits <= 8; bits *= 2) { - int g = ECMULT_GEN_PREC_G(bits); - int n = ECMULT_GEN_PREC_N(bits); - int inner, outer; - - rustsecp256k1zkp_v0_8_0_ge_storage* table = checked_malloc(&default_error_callback, n * g * sizeof(rustsecp256k1zkp_v0_8_0_ge_storage)); - rustsecp256k1zkp_v0_8_0_ecmult_gen_compute_table(table, &rustsecp256k1zkp_v0_8_0_ge_const_g, bits); - - fprintf(fp, "#if ECMULT_GEN_PREC_BITS == %d\n", bits); - for(outer = 0; outer != n; outer++) { - fprintf(fp,"{"); - for(inner = 0; inner != g; inner++) { - fprintf(fp, "S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32 - ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")", - SECP256K1_GE_STORAGE_CONST_GET(table[outer * g + inner])); - if (inner != g - 1) { - fprintf(fp,",\n"); - } - } - if (outer != n - 1) { - fprintf(fp,"},\n"); - } else { - fprintf(fp,"}\n"); - } - } - fprintf(fp, "#endif\n"); - free(table); - } - - fprintf(fp, "};\n"); - fprintf(fp, "#undef S\n"); - fclose(fp); - - return 0; -} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precomputed_ecmult_gen.c b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precomputed_ecmult_gen.c deleted file mode 100644 index 3252e31c..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precomputed_ecmult_gen.c +++ /dev/null @@ -1,9750 +0,0 @@ -/* This file was automatically generated by precompute_ecmult_gen. */ -/* See ecmult_gen_impl.h for details about the contents of this file. */ -#if defined HAVE_CONFIG_H -# include "libsecp256k1-config.h" -#endif -#include "../include/secp256k1.h" -#include "group.h" -#include "ecmult_gen.h" -#include "precomputed_ecmult_gen.h" -#ifdef EXHAUSTIVE_TEST_ORDER -# error Cannot compile precomputed_ecmult_gen.c in exhaustive test mode -#endif /* EXHAUSTIVE_TEST_ORDER */ -#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u) -const rustsecp256k1zkp_v0_8_0_ge_storage rustsecp256k1zkp_v0_8_0_ecmult_gen_prec_table[ECMULT_GEN_PREC_N(ECMULT_GEN_PREC_BITS)][ECMULT_GEN_PREC_G(ECMULT_GEN_PREC_BITS)] = { -#if ECMULT_GEN_PREC_BITS == 2 -{S(3a9ed373,6eed3eec,9aeb5ac0,21b54652,56817b1f,8de6cd0,fbcee548,ba044bb5,7bcc5928,bdc9c023,dfc663b8,9e4f6969,ab751798,8e600ec1,d242010c,45c7974a), -S(e44d7675,c3cb2857,4e133c01,a74f4afc,5ce684f8,4a789711,603f7c4f,50abef58,25bcb62f,fe2e2ce2,196ad86c,a006e20,8c64d21b,b25320a3,b5574b9c,1e1bfb4b), -S(6ada98a4,8118166f,e7082591,d6cda51e,914b60b1,49696270,3350249b,ee8d4770,c234dfad,f3847877,a0a7bcda,112dba85,1cdddf00,84d0c07,df1d1a,a3ec3aeb), -S(a94ae8,63264dfb,b910ea95,4ce9ca7e,4f86f92d,9f3a95d1,ed61552a,7a3f5743,7f53f7f1,6ad2d08f,15e73314,6d80467,41557acf,19556c0f,ed7117ce,37040823)}, -{S(1b8462eb,1ccdf7b2,b8372f2f,cec1f479,ab07c09f,cb26d6c3,965ec73,4d654f81,62f6755,b4a7891d,55de6427,fbc37d33,e4eea418,a2c04392,a3d11807,ccc9025), -S(c3b55f99,9cd9113c,fcb4f29,be00c785,cc70d1c1,f1cfd0ed,593abe8d,260bd2bb,8945790b,5696225a,1c6a1f45,1d6b085e,cde2f332,df068271,f6279877,6d1015aa), -S(a4b41b41,1a255142,ee62144d,96ccfdc,a3cdf5a6,af32bdd8,d1c3d26b,d6aab0b9,3ade7f6a,299ee56c,299fcaad,72a146d2,62db1dcd,2ea1a355,d6e00294,ee34c3), -S(d4af67c6,75f97f30,4a621fe5,343dfa5b,e432d9f1,43758d4d,62df1e09,b79abfe8,d0fea700,2a851a85,33929e5f,1f41d4a9,68b9e520,6c19f3b0,35ce96a5,12b61921)}, -{S(6ae991de,18418b49,160194f,a735eb72,c299b987,1981a4f9,aa717ad2,bcdcf13,7ee8011a,40f384f2,e50add2d,97005173,2787cc7c,89dafb66,301bc94d,24b913f), -S(c28203a6,e0f93259,778bddca,10f994be,67cec8a3,109d0001,d830a8e7,b452794b,18df3a42,ec24b713,2ac4b6ec,dd7605e4,169aa07a,41d7559e,bde808d9,bbfbcb14), -S(4848adb6,b0350cd7,b745b603,cff69deb,8be10519,cc02881c,4b980157,5635aa37,7a814076,187ed7b9,84d0be65,b2f83b90,325441cf,54325183,beb01136,d626ca5c), -S(515d497f,f274da3d,9bb9e4f7,e1b77e8a,af859d52,be7c7e93,f197267,d73ce5ae,da648754,a5ed476,3fad55e1,e93f9687,2d1fe961,b448b9bf,2c42c885,b44678f0)}, -{S(64850a04,76870a44,2cfa57e0,4e4707f7,eccc5e99,12dbcb07,3b457317,717f5686,7c5facd2,91a6defb,a1837cb9,3bcbd0f5,bc37572e,68ccb2a0,c062a155,46656fcc), -S(c3ae412c,a3e5f22b,44863ab1,b5e64719,99078ac0,d5844d9,6a37899f,3e064475,e491d89e,b38b0443,50d96e01,7baceb35,fa0e247,8c982d25,5a2a332c,239e0a54), -S(e72c3804,a774f3db,42348883,297b5035,c9dd3970,7e3bc60d,1e51e41,d7d8e395,e3cb5abb,c3c259ab,2c9e5,fa059c10,fe6f633b,4f99da29,61b9117e,61fbb457), -S(6a7b9de1,8d16a0e2,1b30cb61,3586ebc6,78b60618,e2b45e2d,8c94ad09,36227f74,ac1fb735,266d34,eb995f8f,91cbc339,f63b6e6,bd4c89f0,d7607908,75a4918f)}, -{S(92133195,a4fd0c59,7e0cf65e,8ce1d939,e333f7a8,441523aa,31e339e1,2ae51e8d,556a388,7a7d579e,87de7f49,8c54bf24,2ca4b8a2,8b959e21,ceec4555,b8fabccf), -S(1b3ee78b,df5cbab,a7649125,40852351,602bb558,e4bea533,dbb08eb0,299ae994,9a0c2165,5512777f,fac5ed54,b8e5b4ce,d7a6b17d,643f8c3d,d0173a96,3a4c7aa), -S(6be3de2d,1ceb66ac,1ecd3435,3f241a89,cdaf48f4,a8d5522a,1d6f0083,3c4b2a39,88e10da0,e53b8f5a,ada0db7e,e1ce75c2,8898d5e,156e777f,7acc3ba0,9fee727f), -S(b38c82e4,3e0559db,6732e87a,7cb1e6e6,6164f6f2,258ce060,6d239836,5af9ec0d,9e0f87f4,9d240b33,dc325bd0,49e9fac5,6b7a64e8,57f27ab9,ad765604,2fe47653)}, -{S(ae5fb021,e9256cc0,6236d667,b76b9bdf,304a4683,d2916ffe,489cf019,6b4c5683,e768366b,5c8d36b6,18e45550,d57493e2,41fed17d,12627e37,b29b4b74,d3603696), -S(e4f916f1,a96dc6dd,8867a619,fef6cf67,14ec2642,12d7ba2b,14b5fbda,b584f339,b44855e3,3ddf19b4,31f109b1,daeea11c,340a9ad8,c17b78ea,c9979ecb,791c31fd), -S(4baca037,647377c6,f3146dcc,d732b21d,32449773,f55766d4,de5b239b,2ef89e6a,50b4b046,b9e3cab5,dffdefa,fa305051,7bdb2deb,9bd9fb,9d3cfca0,34a72228), -S(867d7d44,734389e9,71363522,9d4f2c3b,bfc66e57,44a5f01d,1c93c201,9dd3f363,e9b94307,b39ceb65,653f2206,ffc8c858,37654fb5,90eb8d1f,24a9c82e,d8b4d210)}, -{S(782d5c9a,d970322e,deff2e7b,57844184,c589a4da,c042fcf3,86c1a9f8,26c1babb,27bba565,405cb392,64762d97,cbaff552,1bc38b20,56afe313,556542d3,f200eb06), -S(d07eb76,bb6694dd,4d6160e7,4d4a397d,963ea132,f74d0b9,e9f35c06,830940,2b7f902,62c67203,d6f3fc8c,2d435309,7f8e80fa,c2a732a5,dfdf6dee,ab47f017), -S(36afeed4,b7507388,285fc481,beb1de1,bc8e143c,ce7b8e46,7c1e22c0,395fef48,5318e7c9,686171a8,ceefff55,3fc98e41,d9e0d789,a2e880fd,6487c2f5,54816a97), -S(cfc25614,fc96d911,24b3b74,7aed144d,8656693b,a2844934,d2ee61ab,ab794160,fa9e529b,be133fe2,835ec397,b130ff27,187aefdd,df524ed0,9fdd0486,5cf6c014)}, -{S(ebc119d3,8e794efa,85fcbd,5affac35,f73c7428,590ede0f,6365f1ea,87c65b4b,183a9992,3911b1b1,cd9b0fea,3667b6e1,52af7499,8d32beb3,d2ecb91d,af6e8a06), -S(456dfac3,c239290c,336d1b46,e9638bd2,592484bc,f76d011d,104cea57,dd0e5167,62264555,8de68f49,170a8aa4,121aa307,378984a1,76b8affc,241419e6,95500049), -S(71108a04,a50b30f8,29f1420f,b9994ba,384c2ff0,8a581672,e3464bb2,93f0f756,ff6a402c,eb50bb4f,7ae17680,458f53fe,d627b0b,dca24cb1,b033feda,f27cbff4), -S(f8261d8e,ea970b26,fb13ed01,cec553b0,a374b03e,c14763ec,13e68ff9,b219f39,3cee77fb,6e684798,68499e40,fd33fd61,e43ab21d,96a6bf78,35dad6c8,2fea2407)}, -{S(bc4bb9a6,292aa09f,5c66dc9b,667c4642,6b08211f,a9a80f5e,f3f17b,21f275de,5d0e0492,39a862ec,b9649572,6f11bc09,cebd9f29,d9407ab3,1603054d,d9b76b07), -S(ccf3d9af,434d96b9,fd9e12ee,45ea3858,5060b000,896f1de7,a73a12a1,3f635c73,7efe7415,8a3893af,d408b0c,fcd992d9,cff412f0,f77d6a9c,5d5a9235,d14f5e21), -S(18ade473,1ee3019f,ad5621f0,cfc0d6ee,ba69ab38,fdca04ae,fedddf1d,f9cad1ab,1ea6e4d3,63f1cbfb,e9d11c54,c2ab43a4,49e9610f,24b6adf4,446454c9,c3bdccf0), -S(8bc05563,1b13b451,5a99eebd,837e67e9,e80ab8d3,58ee840e,3140ac8e,131cc214,cede3aba,b11b6a91,4ef1ef36,30c12127,bb818ec9,b4d3ad38,a9e68641,a7b799a)}, -{S(c8e595d2,666f4913,1f375b67,81b9113a,d0760e5,9477ca17,8863828b,307488f0,a82cf2a9,d823af13,5c23a04b,bc12dd81,2c352a48,27e19030,8e089d9d,9c316596), -S(d194c03b,ff719a14,6bba239,fc3e1255,7637c9b1,30609ff9,1501942d,348930ee,5e9387d6,4bbc72de,39ca8141,c6c6d526,530e82,47b43161,72717b68,28d1c1c1), -S(cfe58760,54b85d2b,e1220cbc,28ba55f4,51cb3c4b,1ef1d39e,b82e8c25,7538b631,a7616b4a,f3564048,b5cdc6bd,b0250abb,ab1bdd33,a7a15857,31119d26,94ff4bea), -S(190a763e,58315639,578def37,53f4610e,5a802af9,e4873d3e,8c3186c0,e424ac42,b156da85,b8462fa6,83f85c7e,5f718ed7,34a159c2,5b18d092,185ff467,8b8840ed)}, -{S(49e7429b,e0d97bf9,3f17e9a8,53fedb6a,a9bc6edd,8e85f44b,9d2f1469,b2d3b178,ff9e5dfc,2746679e,9826039d,578bac31,c08fbaac,a075214c,73c50f,74568fff), -S(2beda894,682676e6,11bf6a,78cae329,c26b47c6,237d0e52,61a70b9c,36796207,103a18d9,a6785ad0,2129ca1b,96834d9f,f185d49c,edd1c053,96a8c9f4,dd16be16), -S(9602058a,fce0160a,70bd2a32,6cd3eb1b,e5ffbaa8,e05bc2db,fbb9c303,7b449ceb,1fa171c,682393c8,2b237910,2ba5ca8,7efa0543,b8cd65af,de324f14,cc53945b), -S(118d0b52,f418dcd2,b6864967,a49f9d88,809f2468,8bbb6c47,c68f2eb7,bbe7ab31,30ebfb30,ba0bac02,57bf568d,479b7bed,2b1512f9,33aaa040,4966b6fd,5e1678)}, -{S(9a1db7bf,53241ed1,df8d3ea0,f70c0b26,76b43ebc,bcb4622a,9704b0a,3067400a,e3638ad2,95740505,455b2e1e,d495c57a,54ed8e8f,c647a6b9,c69b7dd0,715cef52), -S(b5c353a5,c86b2d4a,9b00804e,f0439259,335d0bde,91dd2bac,a567cd5e,284be39a,5bba9f1e,877d5e0d,21e384d,52de73eb,9aefcaa5,132117d1,2dd984c9,4a0562e1), -S(337a0242,62b9fd60,28f5fcdb,c2305543,385010d6,98fb258a,d5c25b1c,4a765fed,e179c1fb,d671e158,36050d89,48fac97c,57abcae6,79e3be7f,16ed8b98,84dcb013), -S(ecc024ca,640ec936,f7e2320b,58147466,686528ed,579865d0,f61672e8,3e6b0f18,a1335b77,ddb11959,24d40e4c,81270679,270f87e4,158a745c,8d2d810c,ee7024eb)}, -{S(50cd2e16,997d7d45,98bb2d9b,61aceaff,5ad5f38c,8286a0e1,d08055ad,726c7800,dd19c3b,c08b8d97,88f9de1,5941f5fa,6402bbbb,5fdc708b,cfc08844,eb23733b), -S(34d6a7b6,733bf5e9,ae6aad06,5ee0793b,4f5e1ba9,97de99f9,8771ca57,81fb2382,22f8c6f6,dc7203a8,53e64cf1,dbf26d6d,e255f0bf,bddd9508,a759db8f,2c55cbd9), -S(8458b56c,982ccb85,8731c149,e2f38880,3958d6b7,55f38582,b9f4d95b,85d22ee3,b5b8fc5d,2da56779,a5b06b85,b5d07349,9b04cfb1,2d7b26b2,d9a4bf44,3f00cb05), -S(cdbf1327,3388dd49,c163ce36,8d451e3b,51bc7924,173efc08,376cac4d,6f73a84a,d2854757,18fa95a7,1978bb04,5e81095c,f1423d45,e533ba6e,ad91f40f,a6961d2a)}, -{S(4bd266bd,4a730879,cb06d8dc,bd8e5854,c50b6221,d83e0a10,3afcb2a9,a64cca67,a4654a1d,835a51f0,5a877200,1768c549,909212e5,78e3b1d1,df935959,93650863), -S(6666f098,c04d51a2,609c9eb6,596dc668,16735175,1458cd51,59f5bc1e,2c86722c,4ce5faca,45027cb6,85aad7de,e926be69,95b22719,d8d8fb61,260fc9d7,62a9e47b), -S(87b459b0,6e3e2750,31087f45,79e53818,fc200703,59d28147,ad79e39a,488c79ab,2656b94d,d33c0721,b90e981c,b47dda60,166839c0,1c5ca2ee,76979133,824d2488), -S(830acf28,c0a99fcd,f1d3409,ca3066fa,ef8d267a,7ae6ba4,55fceb5,7f76f83c,aa4ec098,51361d43,a339f418,a28de217,a9f464dc,26ceea5a,ae74b4f3,193a58a7)}, -{S(217de5b,a47e8de,cb9d8dc3,dc8fcfd8,203c514b,b9d7bb5e,fb03584b,aa1baaff,c77bddc0,3af15e63,912e51c7,19bd8186,67f999ed,9bd801b8,11bc289b,f12864ed), -S(e5abf144,9c4770fe,b6772067,b18dce01,efab139e,f0a4d73a,eeff868e,6425a7a4,ba62fc47,597dea8d,4bcd1a08,77730314,81ea6990,796a29b5,94bd06d7,d5330188), -S(699e20cd,3b320b24,878b6a98,4c3338d7,45f93ae1,a7aaf363,e20b18e1,8b6d0f56,6602370d,65efc133,83ee1c45,baae4a65,efce9bf8,acb0c3,cfedb5c2,94f36d2), -S(6cf56e78,d6f58bec,32184506,9f26cdbd,7f6ae28,ed310203,dfe410a4,b83449dc,4c24cc91,f78d5c14,690ae276,89a56531,34f89a09,c17e229b,3ab7379c,6da021c8)}, -{S(761cab41,3916a1f5,e131f337,e9023519,6199f789,87ef390b,3f2d8bfa,b0e9bbc6,f10272df,f7e91c40,3565da85,17fd3011,bde7b797,526d3c3,f00fb28e,f26dbd91), -S(ec45cef2,3211527f,220dd3c5,2e4b88be,8f0b0191,d9e73d7d,679fd75d,ae9dc2ae,ac07402f,c7cf8884,8f00e396,42b5e306,7749e10a,441c18b2,646b2fcf,3f76309e), -S(70234e32,61f2e099,a1525a81,9ab7c926,bd672805,ed3562,55369cec,85615e9b,785a6c93,f2673a8f,ccf3b332,35922f9,208dcaee,6932c27c,b8e40b0e,c9b06360), -S(a7c9a0cd,c3692f9a,48ba8307,de80b5d9,80593eef,9e236bf2,49c9693b,c2bb46b,d44258b3,790b9ca2,9636694,6e9ec845,3e3eacf1,a9253092,a7bc92d7,62a03d3c)}, -{S(60b01067,25cf781d,e78ba725,40508697,3f2ff6ec,1511515,6e19384,1fddda7a,624ccf87,f0ec21b9,82efbc4,6d4db878,5d20fb8e,dfe663fc,46660bb7,98c96eb), -S(5d24589d,5ebf326c,9419d539,f06b2291,42c02d0e,44556a3c,772f484,6cb78938,2fb6e6bb,759dbfb7,57257d21,43064225,beeeaf42,4c99b426,aa27d969,d459a5a0), -S(43d4db79,797f6415,93248363,38980bb4,3c90400f,a698ab3a,ba38a4a0,9bb13701,e2bacfbf,b84517da,efb0e137,678ee0b7,bbeefd64,7256628d,7edf46f8,38c65ffd), -S(eb0e5c31,d95f3325,78596f3c,8a027e48,453b5c24,4d0627f3,cffbd413,f8c53db2,29386000,7c3c97da,cc0b5a30,1a7c7c6c,8a1dbfe1,5358c72c,5fa30912,634d4a0b)}, -{S(a707efc4,89165c75,7edcea3c,ce729b44,91f04142,3fc6ea9a,704f52df,c8a0650,f2e7657c,6c618494,c01c5a90,d06b625b,c9416d63,f7b8f809,dda5076f,74fa2c92), -S(b930b8c,a68df36d,80b589ba,72dda82b,502bcee2,cb98a9e9,95c3235b,457ad4c6,7b8fff37,9970f1b4,1a12baae,f7628868,fd3f1003,bd6ea442,46559b40,3a1e8bf6), -S(a6d3233,f7e1001c,eea237bc,d4484744,aa0888b7,a2b44b82,59a542a6,c0d6b552,d2f5772,1c2cbc0,7179d252,3cc0d0e6,94551842,afbb51e4,31a6efb3,9206a70c), -S(c1dd7db5,e5dc3f50,2b08a177,98bb1cfa,afd02252,1bdec7e5,f4653e7b,3303cbaa,558676c3,e25db8,c46bd903,2e9dd122,a981fc50,cbb9e807,157ef35b,5619d3bc)}, -{S(6efd8760,aed4f239,bd97a00,63794c4,ef14acc9,f5b94862,4c7f8b51,3ff35278,74acac29,694c5307,aa221b37,f2ea068a,a269fcd3,c6d85aaf,a8c8eac1,17d7f997), -S(cdd67435,c9fd1182,88f703b1,1fb4e848,9aa2b752,3237a279,ca30a11e,d05de955,149e113c,49db4e2d,bd50dffd,bd53dcf1,a5876825,da059718,e0575d3d,f39476f3), -S(b0fdcf78,9c509ff9,8bb36db8,dbbad047,36bce756,e350373d,ba4d452,8410280d,7c8a7550,91b2cac5,ab71d820,84b335e9,b630cee7,2a277e12,dcb04605,21747c9e), -S(b5ca53ad,77f1569d,ae1c26bf,84ab8e71,98e305fe,e21545e6,f3b2c734,aaa161f2,ec96edd,82ed1d41,cc8423d3,bba6d50,4659de8c,ae5730a9,a0b54fe1,25acdb34)}, -{S(2def7e67,7906cf3f,3677e7b6,1b0a8f8,985fbd9b,23265ea7,18a5c16e,139f0a8,650a89bb,df8c8326,d364fae7,558de827,a529780c,9b7bf8f1,c6925632,7c59c74c), -S(847cecc2,f30f30d3,40ff0276,9167e2db,97b07103,821eecfe,640fe4a1,b3f5a08b,e59c450,3ea1f4db,c4b00c6,e5b912f6,7dafd112,59773c66,d478781,bb343d40), -S(4157664b,4baa043b,9cb959d6,96aa1501,5635bfc8,a20ba704,b6477aaf,a9af9ea5,3e44d11,432b4e5b,97428706,4a787681,522ffe,28eab2f1,15e5bcd6,d42f69ea), -S(675389b6,32431381,bbc0d5eb,20f356aa,31418409,ea9150b,aa7f9c83,41b1124a,999645d2,7a169a1c,de866f4b,ae713070,b9b37c9c,a393567d,8ecd04c5,85b8059d)}, -{S(9705d56f,f75c7d2c,bacc47a4,a6cf8b10,300c688c,fdbd1b1,528f41b9,652d49fa,c53f7f11,896f2edb,fc957dd7,2cc90856,c5df9d86,43e42489,70182843,84201b98), -S(ed362790,55151b78,4e6f5088,e99b7079,d2409203,c08a8791,7644a639,7a8b6199,84affa8c,62a0109c,b003196c,25296d8d,5d3e1904,c1cd10c2,1e73fad1,3a46caa1), -S(21227229,b8deca6f,c30351e1,7607ef99,23cc3f8,9aaaa48,9661487c,7b3bd0e3,a054a47,fcab568b,f8bd4234,a5d7fbec,b11d96e1,aa3ad5b4,88fbb405,a7437f21), -S(59f2227c,32afa124,999ad653,8393e47d,d64c4331,773e09ed,f0517651,3090f07d,1348ffdf,d8adad12,4370f188,cfb47fde,a8297e6f,ea00967,7061bf66,e03b0472)}, -{S(5b27aec1,c644f0a9,ba7f6486,9a960ea6,28343ab,da3feab2,4a2d6add,754866a2,3d1f365c,2aee6c1e,ab2f1879,429b6275,5d1bac85,2998ef25,8a914bfc,ca280b43), -S(27f03daf,a370763a,e2b44480,7b9e6779,9361efcf,cdd7be23,6c493392,f19253fc,eeedf887,cd8f3df0,9d1748c5,62723c56,31956880,cceb0f1f,c118052f,8c44b5ff), -S(d301d8c2,8d7413cf,3298cf95,1f7d6c3a,2e8d86ee,c5e3fbd5,e80e5358,4855e04b,6856d7f1,5e94773a,465cb69c,8b7f8961,a2988f50,fdc179d7,63a92ab5,d94b22a5), -S(8b88670b,72fd02c8,5f973403,5299ad19,484c1367,c8296c73,122d80c7,9bce8407,c98b5a2c,3b0d5c44,32975c0d,32c90794,63ade4fe,92cd4c44,4e8e64ae,7a05c5d4)}, -{S(53512a21,4a659914,82cc157f,da02880f,7c4ff9e6,47a93136,c1e55725,9ce7132f,3ccac75b,13cc40fa,5ab2e017,80f55f2e,b8e6a7e7,22b2e6b1,13a28316,b3c99d3), -S(2a1e20e6,8cfbb77a,ec1f5666,dfc1c85c,c4a07dda,4ead1722,8d7f3633,6771be47,b1f5752b,3f6650ff,261898a7,a8c61f71,48e8f54f,a39e2f4f,8e94ea2f,b332a08a), -S(560d86db,354e5f8e,e8522056,aa9d0f5f,6329fca8,2bf11ba9,fc29505f,7974662d,bfd52860,f42f9d8d,84892fda,b78aa79,9143eee7,26fbc95,b5e17856,53b13878), -S(24c3c40b,df047994,d0416339,e64d6195,276e3779,68869b66,3ecdf186,4703207d,643b0918,c8dce682,50aa3abb,db68f9cf,f8ac64a2,2c7cb77,ef8fd252,36cdf29c)}, -{S(534e9d8,bea140bb,4970b516,c42f2677,dc413f42,9b7c56de,e261f60d,ec68f9d8,e55aff90,1098b0a9,ea377acd,b62dc479,da109514,2654107a,28c68e9f,73b1cba), -S(28ecf7fd,a122550,8301ad75,6028e29e,13da7586,d8b2aaeb,f061e927,dd030db3,bc3e08d3,df4218b,88279f3d,cf75dca7,4a9f567b,75ad0a86,f9379c6e,37661962), -S(851aa3bf,37ee83d0,8318527a,5f4366ee,8ae98d29,de2254d6,2e4428fb,cb5e0f21,423393e3,937816e7,ada1df1c,ebdda887,5e114ab4,23059a35,96668a80,7820754), -S(7e6cf455,9d674d6f,a6263ffa,69cef00e,f69f50e5,4a5d6603,5efb7732,b1aec817,3c6d0cdb,c7ac0623,1c47c044,e28bba2f,105a1730,7cdce1a9,ced324c8,f770cea2)}, -{S(dd7503a2,a3e15e7,39eb9b1f,856d6e33,be4890b2,f40cfea8,1bdf516c,b942731,ca9cd04e,c3789ab4,5088b819,953e08a0,b8adb8b,b2b6f7c8,661a2d3b,83a54c77), -S(9850c031,33d251c2,9f0d64a,f7941f4c,475c6099,e6ba606,9d396ce2,772a5e53,acad3120,b2b5aff9,209bdfce,34d6e5a0,899c9de9,15083064,b84fe57f,2e1c1adb), -S(14194578,53638284,4574721,cb83660,bedd3cff,b68c7023,3f3e6a8e,1d78d797,94d7a10,f4e52fca,c855fbc0,7c977386,b11e179b,db6e6488,67ff3957,28ef2556), -S(c35a90c9,d1f6e5f0,265b7f79,ec47025f,75eda795,27a80f3d,297eb2de,9a85c603,94336bed,d5187e4,5faa0993,875e2421,b7e02eb1,c4dd9e94,b4aab892,3f63f838)}, -{S(c8116b60,1f8d72c6,24957215,46b844f6,bf6bae0b,7575a77,f1f6c6c2,5524fa2b,b7477ca6,de2004df,34882c65,3a46821b,53372f13,ed822cbf,40c20bd9,ddd1d6bd), -S(100f81d7,3b016931,1291696c,c08236f3,6100d4e,10737bd9,2b583d74,1b1903dc,80740c37,a67af622,bcfad64c,38be6968,7e780ad7,318163fe,5d2373a5,b6c90976), -S(17d3e5c8,8a7c9ec5,8a600c2b,c5d0574,491d3c19,6cca5de5,1f812975,e6fd3152,6676bbb0,9ef082b5,f8ebe69b,22c57949,43df3335,2d329621,3238f39,36bc0b9a), -S(f7ccb6af,6dd503e9,a694d721,7e0444a9,6428f277,2cf0e511,cc73bf08,590a5475,817daf4f,3a7106,f23aa303,772a35a4,92d49ce,1d4cf9b5,fde4653d,28ac6cf8)}, -{S(e7ff8d5c,83bd5846,5c967b5,37ac0f36,b9ffe9d2,fc7531e,ef183cb1,7369c066,9a9c3c4b,e482031b,f6dc69fa,843ea90e,de165479,26ba201b,5f05b00a,dbcc30a8), -S(da3b16c5,dd1f95f7,6e54297a,d6be133a,ef0df2f,45f14a55,de978a02,6b8b5fda,6712c26a,cd07740a,70573f13,f42e2b10,edbe32ab,fdb517fa,7a61af6e,aa1c6132), -S(18e515af,fe6c7273,e2acc85b,6dc345c8,f0dce23b,219abd3a,d295f686,4e02ff15,339f848e,f0b1bc1d,fa748290,f25e381e,68cebff2,f3e47caf,ff654909,63fcd515), -S(66bdebee,8c0935ef,32735526,c077cadf,bbc14003,8cbe910e,66107308,8c2edf8b,91ca5bbf,3911b59e,d6c6fe5,2fdd9a94,5ed49883,275b8cac,7fe4c63b,530c7a50)}, -{S(d8f08d18,ece61855,5b06a3b5,ac8e7cf,a6375446,cbc7c8db,ad924f78,69e7f00e,46a91d23,910957eb,db830624,73839954,2cea0570,2f67a09d,d7d19217,646606e), -S(3af65e2b,b700e873,edcf50c7,913e6fb5,534e314f,a2eda897,29fad58f,c7a49b54,dafee0e8,7d70e7b6,fb159def,92a6e5d6,cfd6b8f3,68fdec20,7719e085,94bb8e28), -S(10db17f1,8b009000,660f7dc4,d1a48fba,13926ba,67b71c34,51d2557f,a6f141ca,2f5bcc34,51445a41,d5f574e0,278845d4,805f82ab,ec84bf1c,a39b4bc8,9abdac4c), -S(ab18b6c1,55cb972d,9152c11a,36877a3a,86df3379,181c712f,7242bddf,9fd8f099,b8b8f41b,dcfc9ac0,fc112dbb,63e4cf,72906ad5,1ddaf95c,2a8ecbe5,bae0e229)}, -{S(ca3c008e,cf9efd5f,75cc1035,f9edaa7c,46b17d25,9895b0e3,b3523b6e,eee9daaf,a676aea9,3ce9bb,128ffc34,deb96b0f,72179d28,77406d04,6d0c8b5c,3572f4d2), -S(cf03f3c4,11bf7fe1,46abf004,ecc3583a,25116d55,6c6fff00,71464810,8470f0aa,aa0c0197,d57d72d7,bf336ab3,5527f42e,c7472b8f,8113a9f0,c99f129,4b39e7bf), -S(5d78371e,cb875987,c9e65356,d35240b6,c51e3897,6f884d73,c80dc0d0,839e8b26,76451b48,5c9d7468,77017dd7,412e06b6,2ccfd59d,a1800765,31bae6a5,b2a0bf73), -S(c1df0be6,6001ba2f,2a4ac3a9,466eb526,f37432e0,43688623,8fddcfd1,c1a2bacc,a8b676d5,2b3ecf46,e5849f4c,7c7c46a7,33beff28,d59285a,755509cf,5c629060)}, -{S(8a4e9691,3533875d,b8559500,65c90785,a78233ac,ef24113c,f6ed543a,e6a40024,57d9444,8d091df9,602e6c7f,c3f88934,d45a7c76,18da574b,4d4c15a6,6925bcf4), -S(2afd690,bb940709,ed1a4f85,41658f4d,254edbdb,7a64fff7,c06c904c,47d0cc7,d2177070,3bcdc50c,bc219ac4,62a6fab3,5897b550,d057f9ef,837ac04a,f6233c2f), -S(aad6646,8406b84d,38782e5a,669bddfd,c2279bd7,df486dd7,93e15f82,47bb9cfa,5c0a68b6,2065ebad,f38595e9,5f7a44fe,2bfd7ca8,4ecbaa82,ad39fbd7,b5a1afe5), -S(4a7d2720,1b508d35,a89b6406,68e99cdf,5a400d1c,cb21732b,e51fb44d,61c4cbb,d714cc9,9d59036c,4d82b668,e852cd52,d4d09ba4,f4007346,c7c1bb97,232b0fbd)}, -{S(458f8dbf,9cef8cbc,5d2046c7,42ca6297,e8fc76a,ad22fd3,af4f9a8e,2173d857,57074c8f,14a36b5f,6924517,6e3dc7b6,4d12a08d,8d00565,e70e0ca1,56f29820), -S(970222f4,b79b7b44,bc10c23,1dd6ed2b,2d3412d9,a225fb31,53e8d633,57f2c9a4,5151094a,f28c4b19,6653a42a,dd1f2270,50f0bced,e5e9339a,cea08b7f,e44f9357), -S(5efd117f,645a903,dd4d3f60,72a1f9e0,3c5a91d5,c8042267,1f791747,df32cfa0,770add6c,9b44ecc6,6b7a5fd3,3801ffc3,112bee8a,af0c02c3,fc646347,fb8483f3), -S(ffe6a8da,2abb5280,2d5b9e43,d2d0505f,f564db87,57179c55,30238353,c51c5365,4f1a00f5,4171e1,65d40719,8b913be5,fa84f018,50c40123,9aaa98dd,b303cb71)}, -{S(d2fff4de,9ecfdbd2,dd99ebae,d038415b,19b6c44c,9717926c,9e9a668,3fdfd377,a7e8ef8b,89877e3c,cca566cc,7b7dd537,d157cab,121d1623,b6880567,ac66fa8b), -S(5aaf3141,4ec3d722,75d928a1,c6a528d1,c94ce228,19eb8932,b0da11c,9e4a4574,5d496edf,c3b054ed,5b7fd57c,e731e41b,a538089e,19c11232,2e844b49,918da76b), -S(5798970,da3ee2e,d65e087e,81d9ce60,fb7ee1d4,145af16b,42a4889b,31b68258,8a8fba47,b0b2d716,6324f55b,143b3b14,9af089b0,dc9b9557,40c5df93,3067841d), -S(b482e028,f9cfe926,6d7d4072,c01d30ea,28dfaf9e,268f979d,faaf0b11,4f420d45,eddfa10b,7cba2273,4fa22208,51fc47ba,82721443,19a60d40,624d4e7d,454aff71)}, -{S(b3b5422f,1361ce5c,bf7cc061,3c78aa88,a02683ee,cddeaaf3,f5516cb,291632e0,1790cb50,cc2c760a,c7c2e97c,c44aff29,86c73be5,59a88180,8d036e7a,94347156), -S(34359647,5f3bb33f,eaac445b,5574c7b0,d2fcecf1,50a098d2,445748bd,482b5e0b,7caef8f2,4aa39495,6a36abc7,6704f7f,f7be9b22,6e3a1004,bc3dccc8,3a58cfa5), -S(5000310b,6e81394c,4f91677b,a03c5ca2,5e5c2581,bdaeb320,573febcc,4bd638fa,1c238674,6752ef6,25526d5d,1c80e106,c45a7b83,9ffd9160,bbe6bbe2,8056b532), -S(be843ac0,1b9efaac,adb5c047,49c5990,7441afda,8f33b1ad,20f6335a,5bea9c02,1d14d074,baf0a79,6c165a23,fa9ac432,c46f6576,838625ca,1d73c7f5,327808b0)}, -{S(2e01d33a,c10caa03,ab514f75,46226f67,69a08f01,56017b64,a2436a34,447bfdbe,f5bd77a1,2c61f2ef,60a8c937,cf29e1e6,882b12c0,3e7a7763,f1ea498e,9207836), -S(c8104402,70594c5b,f4e36d2f,ed9e6fb4,2d362b49,5eab7a11,2b1e1c26,aaa20cec,939741b4,db55bca3,53879f72,6362518f,98538a95,77249283,e62b98b6,b3c65c34), -S(408038a2,a79bc8cc,f1fe98f7,d7ddc784,28fd3c71,ed6be435,d76f1390,ed4e3ec0,2dbc7345,f4a358c6,f9690213,1f0418ba,2db1fd01,7e47d8a7,583d30c8,e74027ba), -S(8f0e6b51,50d752a4,86f0edad,a8c21b14,1f7a73c7,2d797233,6a45fc96,8c857683,3cd1fe18,21f1291,7d86b629,ad5aa2ea,46243c8c,398be570,f1959d4a,47b5c3cd)}, -{S(934807e3,60b79e08,d1e28924,2478db59,331c171,6366f421,eda4417b,c0699286,f7f83c26,50e7a77e,2f760e68,7f475858,b2c2d770,195c199d,33a84324,e23f02ef), -S(73c23592,7ae07afa,1cfc030f,a8c874c1,e6d876a4,7414894e,dfd993d1,208ff29d,c2158086,e6dcb078,3a602887,d5d780bc,6e620946,91260289,5244ddc2,f98bb1f5), -S(e588d73a,6eb03f3c,4700380f,17f4c36a,41415cf6,43bd12b3,7e5eedd5,13612e84,3a1cc3ed,22df4c92,96dfa9e3,3faf5035,d084a6f4,fd06c27b,e9bdfefe,bcf1753), -S(7fe24906,485a5638,42ae477b,de90b8a3,1984bf42,7f43660a,f120370d,cf6a3d3d,16bf27da,45038c52,a6051298,26039376,a6fbf802,583ee59a,9752dd09,f30a7ed5)}, -{S(accea070,aa6709bf,efd88be4,bef1d485,a0da83e7,ac9a1eb0,eda8387e,b9fe666b,93fc1c9d,fed8fff9,60ef750e,94dd2342,5fa08c3d,8eda3eee,7f51381,196080e3), -S(412c82e9,f90a302d,f404bf6f,c3581516,b23519aa,2ec26f20,9c80fca3,1f4d0698,31b2bbb8,493e0c15,796d93bb,59cf70d2,7f9c65b4,b3a74969,8612f72e,a42e572b), -S(c0ce0313,52b119b9,795635d8,5e2f5153,a3514d6c,190e2a0c,f9effdf9,bcbdd6ff,b4ef69bd,d4671af5,2be6a4be,1ab4460,71485a7f,6fde10f3,65db8bb0,91eeceb2), -S(b7a23510,abe3c77b,3720006a,9e29c6c,180e40aa,889ea103,ea2387c1,1667aa9a,863f8837,faef7267,d7e36595,a15dd7a4,b2012733,c7347dff,501017f,188ce8b1)}, -{S(a488f83,2bf3e57b,5225f748,754ba2b5,cd9657c7,175198ae,122c3d1c,ee336ef2,4e326d40,648cf269,2db42532,55391fca,5c2b48d7,44a9e39f,bd1293dc,827e9021), -S(bf6227e2,a75c717f,fb3d8d62,361b9212,45bf64e,b19554ed,11040b32,521b9e52,209826fd,41f88c85,f90b4c4b,f90caba0,9cba91aa,687cc502,23bc71cb,7f5459a3), -S(c0ecca8e,90d6979b,54b9e9aa,5a804c8e,106b8b41,a609b85d,1824d079,e2b95f70,1ce95138,2b6eff47,9660cc00,8ed77229,b11158ef,15d97809,a6253439,b88cc4ff), -S(3d4861e1,6069f0f,ddacdb17,595e59df,54a07376,4237b29c,102eba03,230dcb3a,435fa321,90e459cb,137046d7,d316fcff,6fd6c954,a8e2476f,3d38d9e8,263deb51)}, -{S(a473de46,a554667a,368fd573,168dea23,3f81153d,e1b35b26,90da8863,71e6c131,4ba0b462,92aed936,7a2bf9e9,de48a08a,874fd681,aef86a15,58b49e4f,13dbbcec), -S(435ae44e,4f062fae,72ec122d,b7cd5d5a,719c5889,a76ee171,be0e5c61,c5c2d148,d4a6c494,1fafd583,39b59229,b384a5bb,85140ed9,b8cc99b6,38f995b4,2044f380), -S(c170e94b,8fbff40c,159b8fda,ab69093,49e7ce91,1658aa2,896049cc,56b4ee31,19b45604,e602baaa,7085e27a,69d8317f,26ecb345,a558a3e1,5456c1a6,5d89e992), -S(2a043b61,f5e22943,19a38b67,b3bf2f8c,89be156e,641159ad,c94144c9,971af395,17d7c7e1,6c097256,be0cfb11,d9a3cdd7,8bca6a1a,c9514e37,3f59aa5b,c48eeb9c)}, -{S(476d7ba4,35177a71,299267f4,14ef275d,48b434e1,380c1afd,9fac4606,f8e02be0,7f1255fa,57a60447,c14d6574,1d7774b9,695e6d25,1b46912d,d33c77f3,f756edc2), -S(ac4bc955,aae3fa7c,a4ac46a3,84cc2f7f,3cf71f73,b15dd3bc,30513ca2,7da2808a,694ee4e8,6ff945c4,4a5ffd3a,19965ae5,2e15cca9,b51d4795,855eaad7,fc959809), -S(43b4f6e4,25ce5fd6,2c5d6d5,ce33c6c2,df453c6a,9fcb3b15,83faba41,69fee22d,dfda0e64,572ee74f,1fbcc406,7879fbbc,b3896243,70d4bc7a,677eedc0,a3432e4c), -S(e2c0dd25,96da70ee,2569cd83,cea9281e,e37c731c,d0112018,7966da7e,75a9cadd,f87becf8,ed20a606,f8be39ec,2baff52f,60543859,fbbf2b9d,2f8c9933,838b6507)}, -{S(4f62ab4c,b7fb0d13,12620121,9841e932,b0de312d,674cd002,315594e9,81dfb3a1,1145fdd8,c5d16653,a9129b0c,39fcbbd9,5968d22c,ff2127bf,91e89847,35e2834f), -S(ca2ca59e,ad140068,e488658a,836090a8,eba824f0,3c6a81f8,fed13956,865f1be9,f8e286f9,8e9c9003,e4701dfe,83b79be0,d475e320,8cc6fda1,84095f5c,9d0d70b3), -S(eae775d0,8d013499,5ffcba75,33a6dd91,2a07ef45,5a20f49b,8e7b7ed2,75d3c54b,aa4ba756,dd0bd16b,32e86c7e,a520ce1a,bc224d2f,822059e,3df2cd7f,d8d1f855), -S(db566c14,bcae1071,e0bd82a,7a965a72,101d4b5c,29cd7aad,c91e5e99,f4648978,78569150,59ba0432,3afd6a3b,ae5eb503,f920318f,25fc8c45,d1b0fe35,fcbab0e1)}, -{S(110f05a7,489138c6,51e48771,d505c7ce,68bd6e61,67cf4c3,3933441f,a236f263,761652d,178d0d5c,f6189501,d02d7078,2f10f835,27894d79,4f93dff6,e90a3b16), -S(7e0419aa,c31953f4,73ac26a6,80fa9996,7e8f0af6,18ba8a64,de8be81,33f48b6f,b6ef4bd6,5b82a94d,e774eb86,63ad7144,f025fc3e,d8a229cc,af59a816,5c38638f), -S(ec0cc26c,6044567d,609cf31c,c874d9a1,844f61db,37ac4e04,10497e05,c7accec8,20004878,3f7d270e,81144d48,ec839dc1,d1ecdac7,75910eec,b2942619,c8baba8e), -S(942bb265,6d6cf90a,44b1701,76fa9b2b,e366ddbe,fce1a83c,cb3ecb4c,555626cc,e07e2e36,2a835d8e,31601417,fb185a06,14aa4598,6896880b,f1df90e9,aa5c40a7)}, -{S(81f4223,6a39a14e,d2764665,22edb719,f2fb72b2,c571ed67,343e2c57,4fb60e5b,34f10ee5,6c1d5e02,51e8ba8c,9f129391,521f0601,2ebb4549,7377967a,d8347e4b), -S(f983c256,b5c49a86,6bf19c43,50083f4a,7e9cfba8,723d4740,f6909434,3b422fb0,11dd2c7f,16c588c7,d675ddd2,be80e785,50f63fb9,1f1bc016,bc29891b,f5bbd8d5), -S(37fc1499,95a90668,a871c28d,8ed84092,b928fc95,2c459c6d,cde783,28c936ed,e0b07cfb,6fc2442e,4459036d,bcd0117f,c36760ef,2f1046de,17673726,a41316df), -S(4ffc822e,916594f3,fa007cd2,682f0c5d,91b835ac,dbda2ad6,3ac3b73e,5094a175,3ff732fb,57aee90d,ad86ede4,5afa2e18,c95a0a77,d6cd008b,11c95bfc,dc927843)}, -{S(2dc8f27b,b3bdcaa9,2feace80,f2f6212f,8209477e,531e74cb,f497372e,9a2f2263,7feb63a7,96b55bee,ffa180ba,fef47776,fc4fabd4,2ccdcd97,64b4bab3,10350790), -S(c395d4c4,d877c2c8,268621d9,5fbf4f3a,bf839512,c68dc89f,82d6e757,d3938cf7,b37a444,a4e73223,204799c3,df859859,892eae5a,73844d09,9d33eac6,37779a7a), -S(d31454b8,b44e2a30,395674f8,abdc4fb4,6ac242b1,68f0fcd9,c59cbe1d,c8d2b47e,c5a4cbe4,6f8775cd,9482de12,4bcf447a,14e75b52,74f04a5f,c7912457,e31a4d82), -S(c133b76c,a0e74084,b279a464,dd7d5ab5,829e8304,ad8bd982,b2e112a2,9f452272,3bc44411,65b0b601,93bbef51,641b2569,a57aa5c9,6150ffb3,936f00c6,b6434b80)}, -{S(118d5053,fa3ef05c,810cf906,3a410f53,38a9e6bf,513b9a7f,5259112f,f84ad7e4,a371fc9b,c9182528,27d6c842,32e4e44a,9d32eafa,84f1a02d,a86039d1,6309e92), -S(29f11f0d,1457c9ef,7660a6f7,efc42e79,f58ad31c,1df3ee82,33856c30,185a4152,60cc2ceb,5a506326,657219fb,5a8bfcc8,d290f5b,1e05f73a,5f410c10,6ad99bf0), -S(ab757a3a,7af4069e,23493c2f,3978b8af,67d735ea,92382381,727ca6a0,df3082d5,335e418d,1ac2ac71,81a96a7b,7d15c55f,f8c6e342,83aa7f9d,8ae130e,dbe0fd41), -S(37e90fb6,b197550,14d0ea75,1ef33c24,a00d8cf2,5ecd8476,8adabba4,477260f7,90ce4d73,7613beaf,3e884036,5071f104,b88a58a,94c80b4a,1325694,722abbae)}, -{S(568b3e2a,2db4792e,4ef4ee66,14e201f8,a847fdca,38bb003b,adb06d74,1e4f999b,7334b395,61cbcce4,49d83eed,205a4c40,d91d2751,938ba7d0,6ed9e5a5,e1ffea7c), -S(8e37181d,e892fa67,3f26c69c,f6940204,c8f5e5b4,7a027489,ba6f02ac,b87a40ff,9c1a3ad0,bf418dd3,876388af,d45c6ab6,dfa7f7f6,94e991e3,ef0895e,7d7a51c9), -S(cf2e6330,134713f0,cfb27276,9e65e4ae,83d7a3b,84900aaa,3d32d401,55a19673,b8a0a5ca,ebbb17c3,923448a,767804ef,43bb056b,724471f2,5b089b3,ec77e453), -S(ac0df937,d2d65ab2,e6bd28ac,76551b78,bcb1f38d,81f988e9,3fe2b8ed,740ab0b9,f546faf2,120b2e92,6c4f0f18,49cc01eb,834e1406,b5ab4d54,bf3abd22,2b40ec25)}, -{S(7c32fcd7,13305cc7,44fc4ff5,2d315e2d,d4cdf7c0,31b41a64,db6ecbf9,fd4edcbb,7f002bf7,b8e1b8f4,a4a4f2b,1922983e,fb901e13,59cbe934,8a31d91b,7bc86bf4), -S(c72e640,f0401cde,93d85764,224730de,8d46477b,538528b2,53361873,c9f39dfb,571700b2,b5768244,63541839,a1a890bc,dc823e39,a7d137f,9e31e849,583b8fbe), -S(3bf6cfec,83091c9e,1c1deab8,6271526d,9d9afce3,1f052a3a,c8ebd1a9,49005470,35fbff47,bc7d13bb,197e6d7d,50596617,79a06b,e956bfca,667cf070,b80b45de), -S(3416d9d3,6c2c2c6b,77a5d647,500b145c,926cb3e7,1aeb7e83,101dc410,a72bf818,c785a0c4,7408b8b0,30b386cf,9e39f1ef,7bbc4358,f66ddc20,22b1b781,8ca175cc)}, -{S(29d70da5,92094c96,e293c115,42b9dbab,b30df8db,ac98416b,65b0b75b,b3ca446e,a8a5aa3c,c3269596,dd8a9d98,87a3b772,efa1c668,3f8a947f,ff80c662,31c70799), -S(bcaf0322,1e406be9,5df0e9d8,79d82851,2a71aa7a,7a84d8c2,ceb0a6,9d33d827,7a9ecf5c,efb0adf0,c0a2af5b,dc6c2537,b1fdbe0d,be399bf5,6e9d3612,a94f4239), -S(7a24f37d,d6a8c278,cdae5cd1,70be20e5,b9c9c028,ffd3c9fe,4dd3fc18,45a339b2,705f933a,d0dc7a14,7838c060,abba9bc1,7012ccbe,83633551,536e8aba,c8b5ee1b), -S(c35ffef3,aa4a3e9d,93dcaa91,a972172b,785d997e,dee6cf34,e181d217,a3c83d97,122638e5,b7bd05a9,1c5ad0d9,bda96767,6281434,dd0f8a92,561df9bd,96779571)}, -{S(7885bb79,25196ae6,f45b6658,f3c04f5,a3b76cb6,1d60eaf2,45cb35c2,2552267a,9839aae2,b4d9de01,1a119d3a,d269a821,dd88d287,2f031910,a2f3cc22,2e8555a7), -S(b425f805,2659b55e,4b46894e,3498c273,e1869ffb,880e9c50,20bef244,ad471ea7,b0bde647,f6422b6,a8f8fd07,a6f8c73,5b5a17bd,9d6eb57b,34142a18,93825a7e), -S(ccdc5e4c,7593b182,a70c2f97,c358db89,f5b09cf9,de3c5bdf,2a44808e,a84023df,8004b543,df7a516e,faebadfd,c2121101,1ab99b4f,c7a8cdf1,43a56afc,8aa72854), -S(d55f41a9,331ead98,db392478,aea2ce68,ae5c9f84,179caed1,aba5d60f,246f576d,43eed529,61c8bc39,8da97200,92f66f18,69be7dc2,d644f291,98be290d,adabc6a3)}, -{S(422f029,1f51c4df,af233322,7015e4c1,ec8175b1,a8ab6b2f,60a9e291,7242d940,51ae32b0,ed5d39d,e1d61437,d363d59,181a68b6,4e052bc5,9d132da0,9c1f422e), -S(3287920f,f0fc9643,9b0aff00,d6944422,297d3f52,7539f579,98fe3d29,80cc58c4,eaab3473,d562fe1,6cb86453,52228f69,f34efede,6934a587,ce62760d,5fb7869a), -S(a9ce3776,2c703adf,e36d3f6c,7a2b04b9,288bd09e,59bf6fd8,25cb0ac,84bbc641,1e9e8e03,ade9a185,d0680f80,9a9a0468,2338a1bb,4fdc129d,f6a86377,2f9da89), -S(a7480262,bab701d4,11642b23,50934791,8e393f5f,3d55ca2d,fcdf1957,f20c4e04,460875e0,a7afbd6b,ee8491df,d1e80b58,9cba5bd3,a6e4d74e,a4f5bc6c,567460d4)}, -{S(43cf2273,e372157c,2180640,594c144c,93f64fa1,75f28cd2,5e7efebb,14028a93,1f8b092d,4cabc600,33782374,10eafd04,37d6436f,6064932,6f8de6d,94059d4e), -S(e327e5fe,3d20effd,89532c73,eae90c0a,36358e5e,65cff655,b25bd325,8339599f,311932aa,8e4c3f38,cf6ba972,d9872585,14d376,460a1185,6b3a8bbb,ef050996), -S(5fe08c73,62e99994,ea0416e7,d29e1f8e,56e66baa,ef9f3cd8,47732960,c6e545ba,f9373f76,5a340816,cde0db8f,486d6453,531c0ec7,4ddea72e,280d7f42,2fd7ad80), -S(5c32f5a4,74b7f6f0,c019f7d0,a2df5c77,4017dc1a,f93b5c00,bd531eac,32488609,94ca08eb,3d86eb5d,b8f31b4d,9455a6c6,1525a0cf,b388b698,4fb286c7,188d3193)}, -{S(9f10aba7,5a7b9fa0,233bf53c,d819ba2d,919f8acf,9a5e6717,2c93229d,547a40bd,85485295,254a4456,87b065aa,dad21f32,b31735e1,96333fb8,11117a00,d0bf2361), -S(b56da700,114ee476,21540199,e77ba271,e8d578a4,5be263c6,cee2e8ad,fb3a3e48,23ec87c4,236c1299,96ba8d3f,b8cc8af0,b099042c,6623deaf,2abc10cb,c17536fd), -S(a9d94ff7,a5be0ab7,5a8563d6,b061a8a0,7e12690,4870fe3e,39c4ce98,93e96b09,8d1b1b28,a0366d25,a61b617d,9fc10194,72fb3e5e,ff5ce43c,9e1bf1ec,708be6be), -S(fb9fa3f5,381ed2f8,b8f407b2,9991fa07,a6d7a265,4dd2b3b0,cffa3814,10efe8ec,8e9b9167,bf42b7f0,6bb22bb2,3fb40e01,bfbac1a0,dac536ba,b17e7970,803ed9f4)}, -{S(b365ce49,d21ca341,c173b6d7,2238c56b,f080d218,a89e57c6,ce1664f6,5c290a44,e77935dd,75d26531,d4045f72,3b4b5dc4,6608f8b,60f58989,d2ac4002,c304cf04), -S(f512da13,dec07111,2b2cdffe,f72b2b20,aab81bc4,8c3514d2,f6f1360e,ea17e855,3934b35b,87269072,77bb171b,fa2bf260,244b1f6a,13bdba7e,a3e43b8,d86d8abe), -S(3e000708,badfe5fd,d7f708ca,92bd5784,80d0164f,d76bb0bb,4dfaf9eb,e54335a6,713915c9,7c1b1d3a,7111ea47,6c232b85,527ed32b,1e6c4584,cf36e9d8,5abb9d80), -S(c6e97208,17f00aef,4988ea97,8f7a0240,efe4a0ce,203ff10f,4dc77e2b,eb49934,d47cc2d7,f0e499b4,985048fd,fd5f14,83d1f90d,a1abc2ff,340993cb,e7ae03d4)}, -{S(38186a1d,6092b158,554f3f6d,c6de049a,2037577b,2da8db39,163fde30,b19dbf2a,a8cf045,9c7ea28a,415d01f4,47566d54,f986cab5,eb272326,442f32ef,cb6c43c8), -S(ac911a57,1f58a283,517f1ae7,7b2ec8ce,1bbb2d17,3e2dd021,bbaf352e,edca57ad,c9e985f3,f278463b,66851c70,d2a2192,299a3bb1,7ac40661,bff10ea9,29734b3a), -S(9a691204,2f6e8cf2,7189de67,f04d15c5,b80df68e,daa7dc7b,74d08053,e32d4516,a60a7abd,6448fc26,3d49e9fc,32b51f05,1578a8c6,74827059,ddfb9f93,f4621acb), -S(8e6ecfe4,e5b519fc,be7bfc37,5b0738b4,618e5586,dea95ce1,8b870424,55b8d1da,4d459953,53cf5ec3,43b38aed,c3d6bf27,83230fbb,9fc0e147,5cc5ca9,6a341ef8)}, -{S(d8e5f3ba,c152215a,8cf8ca08,40aaad6c,7d001aa0,140bb0b4,dcac726,229ee272,e59390a8,21e8608b,e53fb258,a426dfb6,ca762fd0,9d574f7c,5555cb8d,7174b381), -S(281c15f2,ff06b872,5d0b9a22,2583cbe1,f29c6bd9,7d63db8f,426bbbb7,f36dfd57,ca452a00,fd4afd88,f5369ec0,5b3a99a8,7ebc60cc,db297d6e,ad1479ce,a8c87bf1), -S(69c61933,b91a122a,36087b61,1fb86372,3cfaec6a,5e51b4de,9db83fb5,cc5a1e5c,18b17e6d,74d632da,90946919,2ea6700a,ddfb34f1,f537e5ff,581e04c1,97437d78), -S(e97b38d0,9bc65cb3,421a6ba7,9efeb127,16fc82fd,b539f94c,1c068699,2aab5eb8,43244371,2d899972,a9ebfdab,4ab8a5d3,b7b14b0e,64d82d52,50b9875d,bfc9e1a8)}, -{S(f41bd2b0,e0f49133,747e831c,af4c7a0c,22d2b55f,1cd4ca53,1115d81b,b47754b0,869485d7,26d4687b,c57a9eb6,e90e93a7,bce3b523,998d16c1,297c996a,b68c4fa3), -S(b6161665,b95062e3,aefcc0b5,1220e1d4,dc6945ec,3f73ca4c,47449592,ca977cf9,edea5f23,e6dd49be,7d718fbc,d0368be2,ab3b556c,e1c1de15,1d811c81,44bfd39e), -S(efa245d4,3743d3cd,863a6144,cae9db8a,c7b80e58,4bb31a66,1b670b3e,a17a63b1,ccb90bd2,806117e3,3781f7fd,7ec24d22,b6174aa7,1c8b0f35,bd22e95b,7f5fd96b), -S(ff59688a,fc00c3ce,15e0b2fd,d829725d,28b9d07f,9fb13e7,61ea7f8c,c271914,9779dd1f,aa487c2d,b4c4bb48,3877a848,c329fe68,52c05a8c,7c8d1c51,95a905c6)}, -{S(67c452cb,e71c61c5,8aaf68cc,b1f6208d,5646432b,86774f8f,60081179,6d5337c9,d5f859de,a125aee2,11dcc7cb,b50b4fa3,ef4f9767,7eb94f65,b6a181df,9b938c0a), -S(247c1e17,4a3fcde8,580214e6,b791ad00,59a992d9,84a80f32,640e25ea,3841b18e,1a9f638a,74228a49,e083b3c,c233022f,6943ce4,457199ca,30f230d3,42fb15c4), -S(d36e3977,66121dd6,af8676ea,155f4898,c04ad6f9,d682841a,6811c4c7,2d0a498c,61c0712d,24db9d98,dd6dcdcb,e0a57878,b5cc5a88,d42c50c7,d5f144ce,a937ebf1), -S(b0a52f1f,2cad54b6,658a07a0,dd64c7df,e227aa3f,a32329bd,cf0dba1d,b33de23,c760832f,9be22f9d,c7d17a21,46255338,25ed8afd,1468d03d,d6ae5593,71bfad31)}, -{S(56d09714,cde8f0c,f1956cf,a56bb0aa,b73507c8,bc0399f8,c0fd17de,19e48e9b,d62e1f31,b40ca6ba,71de9059,8a9fb911,6c5f0007,df0c33eb,f50db688,ef0ab90f), -S(a070b352,ecfb2a06,d450cfbf,6800d7ab,6ecd58c4,a5d66c38,a330feb7,739c7dd0,226e8d14,8b074b35,db600e7f,4bbf40f5,c957e5d2,10b757de,3796f2db,1fa4e89f), -S(acf26ed4,9c8d49fc,69d83f06,168a7ead,77a0e16b,89fcd5b9,65da0d65,5dcb7d3f,54894631,5bfd024f,cfff92f2,df2e2ce8,987c385e,6147d783,612a91bb,5411126d), -S(33b944e9,fbcac6bb,4a0a2c95,168180de,fb88eb50,7cbe354,884af02e,dbf5e0c1,a0de73f,8c3646b2,dfeb126b,100a8e6,f5adfd54,2e26b225,d096d760,90f87c62)}, -{S(31095045,658b8c85,ec0c4ddc,7cbce691,d060181d,ffa08855,f3f36722,4c026225,9a8cc527,1c231ce7,aeb6e73b,9acbc16f,4b331b01,4bd457b8,799bad40,547c210c), -S(48472fcc,ddf9b0b3,99ca4d48,254695ba,4beb02da,849833ca,fe68454e,284998c9,a08a0346,83e54fda,d2a1fe63,20b67fb1,b58a4671,b4d08172,b1b6ffc3,c3852499), -S(22cbc8e8,e2d632e7,bbff1662,4b6b971b,ae0b1c12,14c342d6,61fccc2a,af196054,1fae61c2,9843ca1c,6ec5a163,f11c5c7a,1ec4637,4406f32,67a47c4,c111ef3d), -S(5024b68f,89c9eb0,fe4e1517,726f2cef,d270ecf8,182dd81d,20d65a67,8dc81c32,952869d4,4a76c942,ac9c0516,fc16b1d7,a0de7bc7,3fb1a18d,a7253d0b,cbd9019c)}, -{S(da34375c,e38127dc,cc88a823,55d763a7,2dd5d733,d9bac216,7c3e621b,ede529df,13426579,db1353d2,8095e1f2,a007904d,5c04a725,2c621ce4,41157aef,d2e28cf2), -S(ca76f69,937d5d84,659fce11,e1dce556,f450874,5c0e003c,5e474b84,515a7ef5,d2e10042,a71e3e65,d1290d8d,7b5389ea,4156528a,2633ba15,bfe900fa,c5464939), -S(8d7a5378,92f98107,3dcfea0c,9750e22d,e42066a7,ce3b4d16,8b1e56fd,c8a9b93b,ca32aad9,b5d0b83,8eeebde1,8eb7b526,8169b0ae,912539f9,49a1981,d6065703), -S(d58ca70a,51085dee,3d1c06a6,13a5a46d,22d1ba6f,6077df3e,f67b33b9,614869c7,bd212d56,451c1609,93ab9ffe,9371c3b0,76a2c702,d7c12823,ee66a084,ee82fbdb)}, -{S(a80dd274,9cb3c40d,af91b91f,6e8b0850,27fae17,96e416fb,8a172c27,d39e8789,466161e1,e9519ac5,e1b03652,cd1ce6cd,1d7dc696,aa59ab5c,565d822f,af427896), -S(e2313561,865ab364,7118595,e7a10279,4a94ff32,48b7247f,a21d2a3c,906cfc7d,9af6a874,d22254c,f148b479,7d70947d,3065d907,e01f35f2,6f14811c,bb1b36ca), -S(db567947,4a29e5aa,b6cd6cd9,9e92ef97,21eb61db,37b0d0ef,2807624a,e50f1b30,1132a05b,f945f3b4,3bb70fb2,1ef08fe6,c2d4f18,ef2fd356,73f3c430,6ee73ce3), -S(3b4569ea,9feb4458,1c89625,5f39f4d8,3f590d39,c50f3df9,1f061019,c8094e53,97fabe3a,cf3f72b6,c1f01688,690cdac1,c92afe2f,9b1a9138,b9951f97,ddbcdd8f)}, -{S(b3dee3f6,cc08c0ba,5b7ba3b8,50469647,34f7dca1,630e806e,f84157e8,2992c765,d523bf3c,6b004cbd,59db62b2,58395f63,d487d6ce,31799ee1,59ddf96e,d9bae2e8), -S(93c41e9d,ef80a2f6,93cbea0b,c5c111ae,11fd8a86,3940097c,b8753970,e3123733,83a51bb5,849464b3,ee5be4b6,5c5215ed,55e5f157,db8b64bf,aaed7099,497fee0a), -S(6ac20b8b,6c5314e1,72a39c51,a30fdd47,db16215f,e7ed2283,76f74eb3,718ce734,73b0cfa7,ca3836f8,15ef0ddb,d74ca28a,b83093b3,4ae41a94,e92ddfe0,89af26f3), -S(7536c8f8,dc949d7d,c43910a0,8007d6dd,8398f8e3,28ece93d,93b95171,7d2a6479,43e214ad,2c36155b,187973d1,bcdcbbd0,58448490,a1a835ae,2f661084,d8370a10)}, -{S(df9c2e20,68e1e333,f6acc6c3,ba9928eb,e761d4b0,27eaa1de,dae18079,29705021,491f455b,6e937f91,35fe9060,a8c5b6c1,60de5af9,ba90aba4,c060145a,da1b032d), -S(db3f1233,c95cafc0,a5ec4224,2a62e08,745dc259,28b9a938,e6940809,9376dee,94903b4b,2908cd49,95f0883f,1a11d65,880673c4,ef07aa9b,5416de42,8e4ed716), -S(a4eda54e,c923719f,8c4b217e,2c20690c,5986c871,fad99156,8a1f6614,4d48e91a,87736a5f,e71db939,3a673e7a,9bc89091,2ee0c459,5150b88c,792fc2a1,bad3a6b9), -S(ea2475a,ac3db1d8,60263b16,aaff75d5,3c68bd1b,da9123ac,951a8015,30961202,2e723212,716c3573,e58765d7,459070af,45a48555,c176af74,fbf212ab,ff29033e)}, -{S(afdfa934,6f7bcc74,ec473e17,f5048650,11c5251b,bd6c0c70,c25cb561,4b004da8,b16eec26,d575cec6,b8720f94,4ccdddd,78a5c446,a0cf286,fd933f6a,999a4a39), -S(e529f606,84edf5b9,5cd3aba7,233959e9,65639ebd,13c58d6b,c8824fde,3f6e94df,93354f65,e5299a8e,210a94ac,8a871f2a,a7a0a6d7,558fafe0,f67f7c5d,ab304610), -S(83438a3b,47df9b79,baabaeb8,40ea82f4,e7b6aa6c,49802c24,d380fdfa,2f453d0f,25fd4329,e2ac037c,46025db2,16d1d18f,395797ce,613c8c54,beffabd7,eb17eb73), -S(30b3d04f,76e7f7ca,9ddccff1,f904b937,dd972f39,11092f75,9070dd4f,f67cff48,b70176a2,30e72a7e,645c2122,4b9194f0,3c38f18,7020ebed,120df9af,588dbf4f)}, -{S(c8e9e9c6,55d9d7e3,16a16971,f7b7ed06,fa5a2ddb,56288169,ea96c439,6a53e01e,3bf36e6e,8cb2f52d,8a7a155d,1b3e4a17,e06ae0cb,b1dec52a,9b5fbb2,9f0b8a1f), -S(b6b755d8,3e6f1b3,e19a079b,daf2cfe7,22dceea0,2791b200,52ce09a4,d066f196,350f105c,6e52d1b6,da090848,1e338375,7f78a1b3,da3d64f9,eec159cc,ee2c425), -S(713368a8,f3fe29d9,cb8dbff8,6b74b41e,bf2fa4d8,11aced57,47cd800b,afa434cd,2a99e4fc,a4fa0758,8c6ff4ad,968323d,b753d9c4,42b81496,fb0cf028,e9c79173), -S(9e8a9fd0,23b165fc,8d95e7e1,39804c07,aad352cc,18b803d5,b7bf8ae5,5f2fb3,dd7ead28,6afc6105,89e1f4a6,386798e5,97e92401,397f8d50,2ad9802,71a1e81e)}, -{S(9d687619,c1c2c42e,3e466fd0,1ad5a0b8,b459ab12,642d80dc,1081ae1c,a8009f58,34fa7382,687f04f5,1fb15740,c31df8e3,145a0908,ac699527,983a712,23414391), -S(aff756a6,6ea7ea7d,85ba28df,fb25a543,f317f806,f18a4b62,5469ecc9,7e5468aa,b344ad2e,b5cbf601,805017e6,3f8a3d76,99ecfd82,28a9d2be,a7f34436,9e1563d9), -S(d7f37592,cd207f26,80c3e659,ab26a9f3,86270623,bcfd6737,fba2839a,a2ff3f7f,46a52a06,fec906ae,79a81333,39659e09,7ad928d2,4b9495eb,98e89062,d87b0d3e), -S(7fa626bb,98c9f1a,84db146d,584aa1a,3ae75f01,1a86800f,21c2ad77,eb1df5ec,c8a92713,ee8edcdd,3954b267,cd1aed45,929599a3,3d10ab09,5a1703c2,447bc9ef)}, -{S(bede42c9,3086c85,d6793a53,5fcedc15,6202042d,35051eac,a86ee941,aa961d84,e0e7ae8b,a657730c,2fc631ce,82b58bca,1dcd52bf,6f071eb0,cb7b9f7b,24bdeb5b), -S(dbc001ae,137b542,ec96adfa,367531f5,a88b124e,8dda4600,1b14433d,acb50db0,e49c3c9e,abd1e5c3,c5fa8df9,46d7705,e54f594e,d31a5b81,bbc9cf68,d15fd7fa), -S(e199e2ef,a5120572,b844d1bd,76b2b66d,e7f5d2ad,283d4b87,3dda2597,f739733,9926c3f3,88af1ded,eee14bc5,bbf3310,4be655ff,c3ad4798,5b8e4f13,48f3f5c2), -S(19df4eaf,d8bea6e8,edef3a83,415a7a15,a2c3a8a8,95d19651,6c0b0f1,1628f9d9,6e36af6e,9f01cd77,dfa50cc4,a647b222,d6503c57,b4b6cccb,7b9f96bb,d68fb968)}, -{S(998c1a4f,52aa78a,8ab3a94e,66d787b7,145fdaa6,4701c0bc,8bab6933,3ca18ec7,a069228d,355e75be,f50b4682,b210b776,95b997ab,12d87b3a,29e87b1d,289de833), -S(6388dbf6,171559be,2d7e02fa,2bebd597,c373c97f,95d7c4cb,614db1a,9c19a82e,b1d06e7c,83dd9880,a7e1582b,27b3be98,e2953cda,505ecf6e,3ee88bec,713e6035), -S(66f24649,523c8820,798f6e34,a3c0cac1,ebaf194b,c4c32c84,a8ec5a2d,2dedd188,ec6d60de,74e50469,64ab846,1d09335,ae9f657,bb8b6f7a,85e02867,11390425), -S(43784439,5667fc87,d1b4486b,f798d397,e6aa598d,be9f6b21,63fd8218,ea7c8490,dcf33b4c,5738904e,6a4a67b9,a6360ff1,e603fc6c,617a7b6b,17095d56,e6eb2989)}, -{S(8c422f9c,4e2aa24a,6513390,fbcd3531,50b28c5d,40ee8add,8c9d5591,6440cf99,21809c0,2c3f1879,f677997,919d0deb,fd8b2d00,5f249de0,e3df9b4e,8df20524), -S(46f4b7e6,6fc006d3,84e202ce,e1658299,cee653b3,db8672e2,a2e26506,8bfa8b73,d09d2a58,d6c88882,2b2ef6e9,3cd26cc2,4c20f338,50d05e7f,6c937a9c,f8670e7a), -S(a19360c0,66d42f02,541dffe7,fa9aac94,26a4de5a,8a756643,cb812e66,9be21d42,3dd23994,8e869afc,5ca5ca6a,f51fd836,7c612022,d9b78aa2,4a78b8bf,d48a7958), -S(53f1c8b6,f62e094c,3a814741,e2c31259,95fb285c,d8e12d1f,9130c9ce,b1eeb63f,9129139d,42e3c44e,f124685c,fdddddd5,ba9bf1ff,5a61534a,d48503c,b48568b5)}, -{S(3cd27c1f,ece87bf8,10e9c382,a0d7939a,de6f757d,9d0178a4,ea486e2e,241d1216,806192c8,1852c43b,d2439452,b42152e,b0f8a728,50f3af8b,be9670f,fc919897), -S(e00029c9,85a513c0,9eb33ad3,5d0b712f,30bed96a,48eda85c,fc2509b5,99f7b3c0,bc83f8eb,c1bbfb39,981c89f5,7c23912e,780e6cb4,e3a97599,28e51430,a7a205c3), -S(85282c5d,fe004218,1af469d8,8949c331,545e94c2,3a7782a6,4b5b2afd,7e2bc98a,88f0b05d,4032c6d2,8b4140dd,482fdf9a,724181a3,a1ed22a0,ba4b83c,fbd6a61c), -S(8e26c183,26188725,d12e7726,9eb3afcd,121c2b17,6d7678a0,93a496e0,9c4f65ea,a574d95,7e9eb080,5f83e417,f145a708,971e2153,a8ab8462,99d52583,8472e368)}, -{S(7e562c7f,87ba4090,c3147469,78bcb59,722627af,75555e0,ded87772,f67a5ef,433effc5,1a6da4b4,14f793fb,58961db1,fc6681da,2e367f06,331eae98,4c1f31d4), -S(b273ce89,62c52be5,cb23cae,d2b98015,78c7dae3,d10af405,461b4101,c0ff1c43,4ebad439,72b99896,f7f41019,57766925,f145d0ce,59424c8a,6c5cbacc,a3979f16), -S(dc301ce9,26e82026,38b1fe94,7d166507,642a89a1,509fe1c6,5c13af35,9fc34c11,a7230a1,52c96952,a6e5bf42,c4fb504f,12d2577b,40e8b947,53db719b,52ca6b53), -S(4a9fd32c,a97ed57e,83e5c712,5b7a2af7,3fa9ea4e,d96ed369,6aa9f0e3,cbfafda0,4659c8a8,b9d5c6c,cbfcaa9e,eb2cc24a,225de909,faba88c2,132ecf8a,da456ffd)}, -{S(9189ba51,a650f218,5b0e78b2,4fc81b3f,95896526,65bb6ec3,506eff71,71399ad4,981c7770,b6d9fe5e,f55f55b4,4dcd4b29,57ee7078,5cd95d84,d59bbf8,6049a067), -S(8043092c,79a5aa9,c85468f,3e95665b,f7742d3c,78e46529,9fa55525,df768f,5d4df375,eda914f2,49b3755f,365412e8,1f587da9,b444cad0,d3ff87e0,4a7d5f55), -S(c4ceb96c,c733f959,70fc29e1,6abc8ce6,61edb654,6ecda22d,854552ba,3ddca54c,6c1a710a,f15c503e,b2e4ce7b,341256b5,ab3f5a0d,bf1ae1ae,f47d12d4,9c6e3b4a), -S(ef2ffdd3,54249e01,63e49632,c12f236,f71dca92,536ac805,70792598,a46f784f,b121fddc,795491b6,97a1cd12,9964803e,68f60f13,55cee300,5d64f761,3fa1e3d9)}, -{S(b381f721,8381bcba,39ce4649,ded8aeed,43d5548a,b1b09981,a704856a,9b2af576,fd401803,9e993bc,1396a459,8270d4b3,f26f47f1,8babbdc,bfcc30b3,671302bd), -S(9b88c66e,8abab5ea,b4b0e3b8,10bcf0a0,d3987e1c,c53b04cf,9e445f2b,a50b1744,f2f8df3,6fdcb9a8,abe5778e,33fb1912,20b55224,85286f25,3914d175,cf5b85bd), -S(3da8ba80,a6744737,eb75edb4,3bdce32e,f6f1b74b,bc0f7f36,3cc2f342,209a4e52,d61d3a19,bdb8d194,1ee3e2a4,50d7e87,bd00652b,4a52c415,825185b4,a2ad1467), -S(a23779f1,b3716be7,82d4bbb4,3d81677e,d78ed041,c2786f33,49d56666,8bfcec02,33b57d01,c3f38b53,d96ebc7b,2aca2c08,66de0c9d,9764dcb8,dce0c27e,f4217963)}, -{S(e2937985,7de31ced,bca13b56,16a2b853,c1f6c915,8ba5b999,405603bf,eda41ce3,bfff0870,88508486,361a6388,b70638f6,7eacd5fc,a1a1e187,93b2c282,d4d90ec3), -S(42e86050,d6101847,d9aa35b6,45ec7a23,2fd77d5d,c60ad7cd,a10e531c,876187d7,e0a1140,b5e0ab81,79c4a1d9,4e67f6da,ff166fdb,48dd3dd9,4e110519,fdec0563), -S(236ce23b,a13fb252,ee19f08e,9a3948cc,f3edf6b8,9802175b,67d34e91,b82ca1f2,3b569c1b,5c8aae64,b154565,70d7335b,e9f4085a,a2c7e522,96094b93,f9642667), -S(aecaf4d5,282956a7,5831cc6a,a2c09b93,655ab061,1556fba0,8b81bcd,9d9284e5,efdd1e5f,f6c357f0,21d1fe01,d8c6f2fe,c2d0e85e,12b7fab3,6920e684,df21e93a)}, -{S(9eb2f66f,e59abee,bd7c1bd8,dc102027,e94890d6,d24cefe0,e0e3185a,d84567da,123480a6,b2109616,2f5c8bba,4c71ad28,b1ef6d3c,c6b864ab,eec3bfd5,15069b19), -S(e178a416,f501623e,5fb17e46,9d7ae900,1b508178,91f25b5a,83adc565,7556ed18,e0712be6,e78d1a97,452c35a,c19e0459,dd6762a6,9b5ec073,ad1d6ed5,8ba3b369), -S(99243b08,6c3ba8cc,f44cf61e,c7a4ec89,541019e8,65a04ecb,da7e4683,16b5e883,9fb51a9f,4cab9214,d5247350,10a557ca,403fa1c3,b55d722,19557d8b,df2de0c2), -S(c33c61e2,5ceeeb1f,2fa47e22,a93f16ca,123235c2,b7cf9af5,e712e88f,808fb372,a72ded7f,3a362df8,a0992be1,6ab23f52,996f200d,b4981d5c,9cb76712,f0a88274)}, -{S(46481a2d,9c09cf4f,e869ece0,3f065938,e144393b,125191de,a52975d6,f6e0f3f3,74245935,50f81ff0,412a2ccd,f0ec2149,a66a61d0,d63cfd19,74a672f2,ba3dc512), -S(b5d5fb4a,ff2752fb,114a8b1a,c285ad44,5dbcf4aa,fe8f75cb,31bc43a,4298d86f,6f2e10cb,b36e3f26,ca280661,3ac0c052,1fb0781b,214e404,92574c09,8d87e519), -S(308bac42,a25bafbf,93a6ae26,cf99cbc5,1a643215,2cfd927d,7250a964,bc459289,ab38c54b,5725609,3d83bd6c,1dcd4242,e13bd844,c2b7b6c3,b1fdc8e,f7c1abc4), -S(b3c63fe1,67804d24,bf0b00f4,1c4a0175,4886e9c6,a9047439,adf365d6,bca491a7,d0a1a577,da95a3e3,6e2657b9,f9804c8e,93b5e635,6e5fa540,4fe8e3c5,5cf89b2e)}, -{S(5111fd06,525fbe47,3fbd604,6faad331,e715cc48,d2851a8d,70b34c5e,35db531,96ffe690,ff3d3901,d9505f1f,a13c446d,4065ce5e,fabd4ced,59c4f8ca,440d1515), -S(bc12f2be,3b0f27e1,92c9d446,59bec78a,4a592f0e,997be28c,313d93ac,4769fb4a,143f1a68,1f6d69f,66f49543,b131a1f6,c8e3b933,271dd57a,3be9db9d,1f9c31b7), -S(edc09cf5,6730b640,689c052b,989bf0fd,de56d4e4,8079000a,b4e8eff2,23ab61b3,57f21a98,eadedef2,8ff6063d,53bf158b,c38e1c1f,6df2d6e0,5ff7ad18,47c91bea), -S(4ba6c933,962ee6dd,7b7a80fd,4102ead5,d94a224a,4236234a,72afef90,3537c70f,f84264af,c8424c8d,77b4cdc0,37f4fdfc,3b1c7dec,f0fd3da6,f696beb0,98b2840b)}, -{S(6d3b19f9,79986500,2f0fe9f7,67efdd28,73839d01,3b7f4cc0,842b0a85,c1934182,b261bd9c,c90bf00c,3ac67bf3,728ef44e,2aa1b660,6cfd4c41,20d1bab3,aa05efc), -S(b9e6fbd6,bacca67c,d2977ad7,458d006,bea2288f,598904af,6794cd1,dc819231,bfd5bcf,2aeca281,d596798d,482ab975,73b15bfa,db7df642,abdc727e,cf664f1e), -S(f2e3c13c,8e1da25a,3b05272c,fa653ef5,487ea653,6d55bed6,c9ee0e77,85325f90,7bcae36c,67ec60cc,108a8794,cb24a3,b70c5f0d,2d58c813,77dfbd7c,10972256), -S(1317a41e,f4f09481,db342808,63d49b1b,dfb2a11a,f843ddba,29499f1c,69cba337,28aa8ec0,ba9021f,c49e90f5,65c61254,3b2e6e0f,57370374,93fe349e,11ea5eed)}, -{S(5a9ce5ce,5b6c4aeb,88f47c4f,680002a3,d898da92,603c0513,d72ae0c0,239f10ca,c1d25370,ef453f49,7982bdc5,d7062098,1a0dcfe7,d07a0339,eadfc5bc,dd0d7874), -S(575eaa03,caf5e2bd,eea82550,f961b06b,e8c8a25d,a13f912c,856776a9,2c3cd783,732a2a82,da6c4d7c,79f5bef3,9b39831f,f8f79233,f9700346,fabff503,50624616), -S(b70091c1,99c77e1b,756625fc,de51262f,93e236ca,f48d6f79,d5ad6d2c,1c4eddff,d301345f,3d600128,503f3b0a,7ecb44de,f623c9d6,b3ed8cae,d676cabe,695cd53d), -S(338ea0d3,6d5d98fd,b95db010,633555de,c9cae973,720ac4e7,bfddc91b,176103f2,bd9e4e53,e18e541e,8ddb1d24,ffbf38d5,d2529ad3,3c043c07,1fe78847,63be57fb)}, -{S(cf850614,851d0868,16a329fc,f5c1afc,6dfdbbb0,ed9278f1,22de3890,cb693837,b768ddcf,f8dbe818,fcda1d41,1133a9d8,5ba6fa7c,9dc85b1f,23b3174d,69e3f33), -S(e3195ebc,5ee69554,73a626ea,14332378,1da933b0,fb5a1484,da2363d,65cadc7e,d0acda43,e7ff4df9,dd1f46bb,93e8bb3e,ff73644a,e024b5ca,8996a750,91928bd6), -S(5741cbec,60c5375f,6dc383c1,9b0dd4db,1a6a8aed,5658e87b,fef33a14,2e281580,66e9e972,2a6df27b,24500496,ded7638c,a19152d5,7c7adb04,74125ff5,1be6cb5b), -S(7e64bc9b,ea4c6460,b9b1ef71,95a4f4e2,5601d616,11ae689e,cb05b0b1,ade57298,bf43d8b2,65094986,324842b3,23fcb1f6,5d0896ef,1537630f,e42b669b,42758a62)}, -{S(17631e86,523e4d18,51417204,dde16c6a,bb7ded2f,2504bce,6683159,63e9b492,cc3a083e,e4622c59,4d934ecf,2471143f,4af9c4e,481866b4,637104ac,d815c97), -S(69d98c81,2dd5cd4,229eee2d,d82f75a4,986e514d,cd8dd1aa,1bed8447,e5f46fb,7d72fd27,40e91bbc,64a3ca20,243eb038,9cdc46d7,eab75343,8103f4b2,43e9de06), -S(76f7c0d1,c661944,5f0f5beb,568cdeb4,9cd483d,e5bcb737,2de66e73,cab23c2c,540422cd,994b4411,6ed2d068,5dc78193,fb5b5fd6,28e3f432,ee2d221f,8783ef7a), -S(6938d574,f67039b5,eb87fbdb,b759fcdf,4fc2c341,ac5817d6,8ea8277c,d4297574,5a2679bc,83685ca8,d3961d51,1a5ea081,8ae917c9,4606d552,620093eb,f399de53)}, -{S(60ad1b2,a075a3f5,fcf72668,cb48703a,f44c3442,23566340,b0fd682c,ae829ddb,534bb9d8,46bd457d,3574e528,87787f61,743b8cc8,e7b9032c,587992fa,c0ca2818), -S(1d66875f,42d8e75d,5651a635,1db1a820,725a29cf,74e0577d,833bf841,94e9a2d6,803ed33d,2188877a,c2e3d4e6,d78aae19,8d2eeb5e,a9e2c3cc,29cd5214,c20a78be), -S(cf400141,4811b30,70345420,e23ff7fc,bb800b9f,ea2e18cd,84b1b637,7b59ea39,2b8ca9bc,722dee2e,29996865,93178cdf,16503531,e3885322,d42b0ff4,dd091927), -S(ff2612ac,2f9925cb,cd76b975,b23aff70,428062f5,8f64a507,28b3021c,6548495c,e3bc502d,6046782f,8d2cd0f3,f5bd7ea,f661e4d8,5eebb56f,cf2e9d78,535994b3)}, -{S(4839ed9d,4a5e9c82,4c6ab373,b9cce0ee,6d8f19e4,2185c791,89b52aa3,52533187,a1663ed9,7007472,8367faff,33ba90f3,620b6b18,a816ff71,7fe8e97,20304323), -S(ea4b17,5edef6e2,46f8eb69,5bdd5b86,f06231d2,38303d94,c89399b4,af9a4531,aaf021e2,555632b4,da731da2,fb3fa644,2e8c34f7,9ed5a701,d9ff6be6,c3d3e7c7), -S(62def07d,3b90500b,548c2126,5d65f122,edf17b97,9defab64,3e702276,774ba43b,1caa772b,bd3ecd64,c83d903f,ae57a9de,49649abb,5aa7a21,2dc2a904,e97f9ad0), -S(b8cab6cc,e7898d3f,ffabaa1f,8bf0fcb6,fb00239c,27f33ca0,dd893d98,b2784eb0,96841107,cdcc5d3b,5c1c9c7f,39b92ff1,5831e400,73762437,7d062af3,4b0a1db0)}, -{S(63b931af,dd8dd850,d9b2f2fd,480e109,14365299,254ae0a7,b04cbc2a,def6a5a8,dddb17fd,8100129c,27b1122,34587e41,e6b47b01,9ed91775,b217a10b,3030288d), -S(a2a4d3f4,40c5500d,a0cca022,21cea8d5,89410fdd,7782d574,85112d8f,e6ffdd61,adbc7f46,db8b0f29,31dec8a,bdfcf396,96f158be,f6f28d4b,d88e14f5,5ecd7bd7), -S(242766db,7d3aa77a,6daafe42,1fc02bc2,d78bb495,771264fe,4f9ae1d7,837106cd,f9d7f63,7f83f5a0,6dc4cd42,af1aa54c,821f1711,66bb9c02,58ff6448,de3da6ac), -S(c089b764,f873e53f,9fb390b1,d802c7cf,e68f8dab,6f2ba524,4e309027,8ea60dda,7f83e920,b2fb47d1,c7b9aa13,eca044b1,7ab67d0c,94767d39,80aff8a3,1d9effaa)}, -{S(ee609aa5,cfe0de2c,45d1df32,707e4e8,d8c4c572,3acabf20,c95e8d12,9f237cdf,27a1804f,d2ecbe1c,9eb1958,d8b7898e,968c6e5,e798b2b,b86b7a55,f0b00695), -S(16c7fca9,8bc28613,af1133ca,6c3ed5fd,5792858a,73a87773,17c004d9,c88a81b7,7d6d7f8c,4ed838f,7f96a060,32d20e01,b792a729,57d502ef,575e68a6,c55c8b1b), -S(c2c5cfc2,4e16cf88,af21c30a,2e37461f,230a1401,2a970057,f20e87f1,de517cec,6a6c834c,bf6d682f,b1b4779f,1629b1b7,3feac678,38e34a08,74d335d4,9245c37e), -S(1c948040,7673a271,23dd0fd2,85de249a,49c94348,75ec6660,3d0afdb8,9edd4642,2122d99,6781bee8,628b27bc,cdc00293,43e3627a,f14e8e23,4a144b59,3ed887b5)}, -{S(a336ba43,9d7ddf1b,91b05a4f,72083cf5,1f8ff83c,15ac69df,7bcd2d30,c645cead,a99919fc,a5854c02,e7246315,477a6cca,e29005dd,e950c35e,7aef7d4,7e4cacd), -S(211e7055,6cf61cc9,9db2576,20048424,9a5cc104,e818857c,2bcfd86b,35f09d24,f69df2c7,d480cc49,8b605364,e4f64998,a7d26b26,f354dc7d,1780f0a3,324f4bb), -S(781b8f44,86276947,6dc1b3c3,f0935984,6e827615,b22cc0d1,4e92eb46,4420089f,c49a50ef,3ecceb1e,cc6081c3,7acd7449,73b8c2e1,9bdb9802,f55626d9,129bbe09), -S(62161d16,921adaa6,5aa8a7c,b3dd1dab,1e32f9c2,e4ddd119,e5d8a321,3e0f262b,eaae5b60,49d51781,ab479eb8,32153328,fce9b678,3778a06e,581fc028,e5352d8b)}, -{S(9bd360f1,9a65f3d3,757a6d30,74e793fc,8a972315,9dda6f9f,f84bafa9,8b70cfd0,d16b8dd1,5937851d,6382b0e7,f6f858f,862021cf,857f4576,2fce65fe,ef5081ac), -S(820f3f6d,f4747a54,563f4a2c,b1f9a2a3,4454d1ef,c28c4f87,2fa123e2,89a65fea,27a82421,216b7b0f,2cedbe3e,d45d4b1b,c70e47c7,cda3929a,f46d05e6,5b51124b), -S(37e88e66,33965cc1,c313ba45,6762548f,147eb369,debf6661,c8c63749,afca6d30,c2573a88,f797bf94,cb42d82c,c7e1dd5f,67b29517,f41c8950,cd27f77c,f4c4885f), -S(39d0df0e,22fa1770,3ebce0cf,753134bc,5ba82a82,b50886af,ddb4afa3,c67a2df7,3a05b6d7,3fef259d,f900ad7e,23ba9ca3,fa0e8c22,75a98ea7,d60d3ef8,5116bb2b)}, -{S(47686db4,ef418446,4955455b,8aa0cb42,9903b2df,9872087f,74923a43,6a5fa06d,997c2258,ba1958bf,6801fa6c,56a1eeaf,2f4d4f6f,16ee1ec9,389569e3,6abee360), -S(ef85e550,7edfc88c,697e9396,e700cdc9,70a0c65a,cded23ec,97e8fac3,637ff492,7edffbeb,c39d7ff7,90fc479c,704b5717,231b6c17,8a89a032,35b64361,c8f37bed), -S(4790f35d,c4cfc648,cc011693,d4de07b8,341a068d,b89bbdea,b5dc26e2,49673db,52b2c399,97870c54,98427e7c,3a1b1e6b,58151033,ce11d5e2,a07950b4,c0d6a228), -S(b4fe974d,2de71dcd,b6000352,1f2920c3,9c898c81,cbe9953e,41db3462,f298446c,f2f7921e,28e06841,1b7da1e6,81442a6f,e5df27bf,307fc5ad,90268199,eb8dae9d)}, -{S(17d69e5a,f192e0f2,693926e2,adbccce0,8aee8656,5b1838,54cb05f2,d8563ee0,ff0c4e1,bf955a39,f8d14bfc,68094b97,6f1f5429,e04b21eb,9a86e4df,d2e11507), -S(e275d881,a266b218,77523b34,6bd25e69,5ef771a6,b60bc0f9,44b9be13,fcb937f4,50917dec,bfb8c492,97254e5b,32635da0,e16f8a1c,cae44508,546e024d,b91710d9), -S(594e43dc,498fed,9206ecb,8cba88a8,789f34a6,c17700fe,b0b99533,3e18010b,100741ca,9d03b5ca,a094f383,78da3ac5,8d79081a,1015b133,1ce28e1,821eeec6), -S(15f7436d,98885865,3d74e5bc,8210a6d0,73e906f1,25f2f317,63636f8e,4d2a5bad,9b7d4de9,b9379a04,edc9b47a,851385c7,ad8263a4,a0f0735a,d990eb70,dfe860ef)}, -{S(dc728a2f,6062da93,9d72b4ff,2595991c,5eeabdf3,bdc7128d,2fc0f25b,aba482d,297fa2d7,8f62f21,16d3a68,e60bebb0,1bedb0cb,370bc401,30062a3c,f5e57c8b), -S(f842bf23,8f136dd5,db77b46b,7b55974d,dc4f02ae,80d80d4f,7979212f,442f2ee4,fee53360,1c8ae94e,b7fa61c1,5daf3bce,5f8d21db,1b38617c,d9a5d547,58279ae3), -S(5234fb57,d95b1033,21e67c8e,cfdf9983,c7f134f,fb105e6a,c7c11dbd,95a39d85,85abe819,a8a8df4c,c77eb61a,8ac1536,2985c508,f10f3280,e8585c96,f21fdd66), -S(bdcd155c,dee8a06,f8d6449a,f43af493,eba8c6f4,e3dd53a7,a7c880b2,155a04b9,be820a74,41ba1bb7,417901a1,99fc9f22,f5d8604c,42f10c5f,7d423081,505daf20)}, -{S(a00355b4,d41ed117,b9ee9146,de418905,aface350,60c02d8f,d8bf4af5,a20b77a,bdd0dd35,cd5857a1,9b3d0a67,a14b6047,acc7ffeb,70cf4409,633f53d5,bd85395c), -S(3604927b,eb1fa6ac,409d084c,86c8cbae,484e46fb,c9262f02,fc316fe8,ddce379c,5c92529b,1b66b9d2,9b060a9,10ed2da,4637e466,3957349a,83e9ac45,5dc17d53), -S(a681fd19,69da961b,35aca5ef,3a4325e2,12766646,4f63f019,90267865,1fa896c2,f3becaa0,377d0878,462005e4,795bad58,daaae64b,67b7db29,82d2516e,4c72811a), -S(1a87a251,7b770c6,705140f7,cea0bdb4,5abc9a6d,3a0bc0c5,1d801caf,907b635b,c18b4034,f7cddf7,b23673d,b8942ab1,93a698f3,15ef0849,b2c4601d,aca264bb)}, -{S(69ae3d10,523302cc,bcbafd00,1f40f48c,b4f918b9,65190983,24cf0479,f9175e18,e9583688,9ae86eed,ebc7f99c,19af452,7d239906,aa96c92f,2dc91f60,4704909b), -S(18641531,3ec224e9,dbdb0254,f810c2a2,85d477fd,357ec222,1b31617b,7bf51e15,e2900618,7bdc64f5,bb04c80f,7d7ea5af,2adc7d24,57862959,5a598240,219b2faa), -S(c3eaf844,8e1506db,eb0ad332,b26cb2c6,ed2c1d76,36a445b1,b0af2743,122fcf50,f6171ffc,88d5d448,d828a445,d59f7edf,fc37241f,2af04d39,1cdc4d99,8b3b9172), -S(2019838e,f4cc5420,37d97952,ac870d9d,abf443f5,56226166,9ce84839,df69e527,a70ac8e5,e8f76443,fd4765c3,84abb1bc,5ab66333,9c4c555d,8dd840a6,7f87049)}, -{S(90014ea0,f76360c0,aad4ec54,8698e053,1445716d,57e7bd8,9ad0c952,b806ddb7,d039a3d3,717a3b7,68822dfc,94c216df,26249d04,d2995fb9,559fc8a0,53b51fc6), -S(769e1d8f,67248191,113b7ab0,84103fbb,cf4950c8,7b19d6d8,65cafd44,b8bd18a4,8a7d2d69,aaf91be4,d4e86de9,35883b60,8b931f61,67b9e76c,ea43db6d,66952560), -S(a9ae4006,c04ffddb,ecc638c1,e348a014,b179dfeb,b9e8743a,b2d9fde,1a48ced3,30f74acd,4a29811e,718baea3,11d4f5b2,b70d4339,e83550f1,f4ed763c,52907908), -S(13f000d,912ade2f,c6a1c2a1,5dc7f3e6,380df54,44fabc7a,80ee4723,ea27af10,6dcd578c,12d35e33,1e202b81,ec93fd6c,30523f82,a524669,2b7896ef,53db20fc)}, -{S(8cffb25b,9df2cd59,a3d5efd2,bcd2f2f3,f96bd063,14c04246,a5c29083,eb08b219,113d1c14,753ccadb,4b5b8991,86c93f02,13c43711,305e7056,fccb8f5f,8f265714), -S(a3cf6723,3fab81a8,5c04d80a,5118132d,df914239,67a5e486,3f30c792,668fd49a,99274ec7,9a8b0188,a91971fc,631926d1,72923ed8,a91eeaa0,21494bbc,33ac92cf), -S(470e48c9,18310136,80712b3d,9a673795,91a4a7bb,2e25f6c5,59700ec9,b5f87692,3b9a2d0,d9ddcabd,511336aa,f0c1977c,2e09e37b,96664531,48b82476,6c562b8e), -S(eadf65bf,cb609b05,b000aed4,98e344ea,1913d376,c0200c2d,e2747e5e,a24d6900,c42cd81a,756dcd9e,687b42a7,2ad9621b,dfffa3a3,c8b7398a,ea0aabe5,fd737b96)}, -{S(68d83fa5,58a5eeef,8695eb2e,409a1774,61d43b2e,81e2d4f7,efcdce27,25a515f1,679ae994,24e430ae,7cc6d403,afcade07,eede7dcd,3d597717,fe93d1d2,3df076f8), -S(5a55b581,5c824e49,db51f218,913eef58,e8a666c,4191a290,b66ffa0c,abbe6546,8674ef7d,9ea73c1d,3a3915ba,e118c742,fd4d4e88,78adaacd,699963a,5eb9f796), -S(48d7425d,376cb7d9,d32b164e,920cbd7c,e7d174c3,7afc191c,66267221,6ab5489e,d8ffc4e8,29de5c69,dfad7fd2,3353bc49,a6e4fd42,c31a4b8e,16bc0bfa,ce26be4e), -S(ffd5b298,ed5a84f,e58e09bf,8df83308,3ffb4a1e,8c5ac3f6,1e594b03,406565ce,f56678a7,fece6530,6ab4a556,d7bdf41f,353c5470,d2b6293e,a97bc396,d8ee0fcd)}, -{S(3432345c,9df2e165,daddc0ce,9903a17c,2070e055,748a0695,123971ff,440a92d9,3b05179d,dfe73d48,4477c69b,434c05fd,55ad860f,dd286362,ac39cce4,5b7e5c47), -S(abe99ae7,698019bd,66615a5d,7df9c4b,cb498915,a868a48a,25ff29ed,747cff8c,f9b3f71,113c791f,b3353724,a812351d,3988b8ea,3a93821,db26631b,6907ea72), -S(4c493f53,3d4c0b6d,17fac73c,4301a054,75353360,1536da94,bca3b454,767b86c8,8c9743da,8b125a52,20a493d5,2c31440e,e1fb6fc7,dabe35e,7ac97c1c,94c85e0e), -S(2b73a96e,70fdfdd0,ffc601d4,9d78282,f997f73f,eea4ad75,f8c5d753,65db2f2b,994d51eb,c58dcdfe,a5fa01f7,522e5d70,1c21b325,9350b7f6,34c75fa3,1d4ab6c)}, -{S(bd721cf7,30d8cfc2,3bfd5778,67f40847,4fa01225,ddbf427a,c7cb73d0,60046af7,62fdc9aa,b8836c11,89e4cdc0,3d1c6c87,927e36be,2e4d55b5,76b1e6dd,91d7c11a), -S(3c3dfaad,d52f2531,cd835de8,b40a005e,aa2c015c,40366487,962d1363,64f4fa54,a2143a66,a76e30e8,150918d4,1d9eb97d,a69694ae,c426b6c5,5125f88,a22e9ef9), -S(bc075398,462afa25,57c6bb69,b6cc9ae8,75a490e3,e7c65b06,f7d70efa,166534fd,47309e89,1e0c1c68,c6a5532b,b34989d1,658f95fe,7dd7ce94,d2346e0c,15936758), -S(407ef9a4,a92a8471,400e2bdf,7620796a,410c648,e5a12c41,6fbab33e,2119512,60a1d1bd,aa7a7e88,d67b9d50,b20cf09,7888d0d4,5c83a55d,4ae93dda,49befce0)}, -{S(fd8ea149,749825c9,1fb53bc0,329e218c,2b49f62e,a56e7637,730f766f,527b7981,3c4cdba,1c38f4a2,82864b88,a58300bd,d885780,c63ce34f,4c7ba30c,5c55147), -S(e6163d4e,af44e81e,1e32226b,cbd676dd,1e299b6c,249f4fc9,b2706601,ae17f754,4f754176,cfd4ca24,b7c14b79,8149cb8d,40809aae,57a11764,4eb43e6f,22403d84), -S(c23ece67,f8260a8d,4d18b1c4,14ffa33d,d93b5a19,ee0903b4,c4765c03,414a17c6,8b448722,5b20ee7d,fe6cf78f,7220822b,e8afdf97,190511af,ac225a8f,1da22526), -S(3a73ac57,746f5de6,7deb557f,2bd4686a,72c69f2e,b9b2afa5,d8389719,5f955da2,7fb97414,c9738999,51310a0e,85e1e92c,db326de3,a5621318,6ad34638,832112cf)}, -{S(c6188e3e,4da144f1,a71ab806,22998e3a,cc580ae8,28b08c4d,f8ad88f5,5d0723e,d16037fb,b08be935,f89b12a0,810b2574,b7b0f9e2,5039c610,b60267de,1e8895cd), -S(f4eb0af6,b09cbbde,4203443e,2db7cd74,25b3aef1,4bd470,84fc9c6a,7781c45d,84e7dd03,9d221757,d29ef906,efc5124d,7d2833fe,b0d381b2,1d4a1e25,45615bb6), -S(4457652d,9123f6af,79613e87,eb90e62c,e4c7b4a6,3a5b2b2d,b183b23d,bd659f12,c3879b4,c4f249f1,f0cb1a52,874afcc0,46ed7c4f,5b346a63,dd798d0d,9179c3f8), -S(e5aa444c,ba5c8588,33e215c8,a521c552,bd6a449e,a202d2f9,32dbb6e5,4162adf6,111a1695,e7513c72,69e65977,3171da1c,8727b590,32de1df2,1d0ec7ed,67f5c16f)}, -{S(9d12d4d5,8f12e305,f34f165b,c5f000ef,823e4229,6e57a67c,22f3f2ec,bd5c5f7,f8ea4dc4,131d6d1c,d97bb52f,1c03a060,f1ca0af5,71269506,609f92e8,1409dd24), -S(1960c8c4,f9eae197,29769442,a86fb7cb,4a4ee4db,a577001f,13fa0fc6,342ccbed,dec5c3f2,9fa2f71b,992f3aa6,213f5bf5,d7c8a0d9,360c25af,b35f2bb7,776fbb74), -S(d5c94e32,5fad15af,bf295b61,900bb004,51cb568b,ffcd7f2f,c04e0f00,5a596114,e44ccfda,83eca7cf,babf25e5,9be125b0,c04c8130,4f188706,6824ce3a,7409a551), -S(db1b05d,cdd99edd,c6645c81,47aba91b,dcd1ae44,18e4a5dd,94812318,fe9f1e8c,f9818f9a,8b094718,2b88fa1b,689d1495,e94adb67,6e924637,b8dcd799,a1ee3262)}, -{S(7f07a821,c2102e7,c726a07a,892539aa,85e5e3ec,6f79691,37d79611,43b79b75,63411bd5,5ee5f782,e1d2788a,317d8689,6035663b,68b96438,711e74d3,aeb51ef0), -S(37d2f5b7,c66b5439,26e89aa8,f265679e,3b213098,6467fa97,27f365db,ba93c0c2,a1675968,10cf3f94,84455ede,f6ccfdf4,afc726ee,3561c081,8e535f74,cd324cc), -S(d041cfbf,b5f525c9,65fa7741,25b8f9bb,cda162cc,2b1f280c,a41065c0,56474a60,34c757e1,b819fe3d,fd62ba93,801491d,d4c1d05c,b973df22,fc64f23,1cc68550), -S(c640c211,f3004673,a3d8ca66,a18872ba,bbc1dacd,61347d87,78bb4d04,4892ab83,ac305f9,8a267919,68214e95,47d64d2a,c015c740,5619a73a,162287f1,55b1ffb1)}, -{S(760a6682,57ae7b8a,96c5c769,9039a102,cbaa111e,ad076621,88a45a4c,168a482a,ac81a374,c2da5e80,d22db86c,37302c9a,1b154e45,122f9d3f,b5c59b2,bee89a36), -S(5770bac1,871c8262,b4fff00b,a7520d55,d65bb0a4,7c9598db,3fcfee9a,27ff2763,825274f3,44421047,2390a3f3,a7b98de0,ce70bbf8,6d7241ca,a93b5955,24ae94db), -S(9432cd1d,8a62e580,16278ef2,c1ea2703,e628268,3eda8ca5,bd1a718e,6de864d1,5c7e685c,443bff0c,1eac25e2,489d0c15,eeac20be,bbfcb62a,a277938a,21901056), -S(32fa8231,6af1360c,9a58fefd,baf51580,6860463b,7325443d,ee873f40,8d7b8a26,b9879293,6561b733,948a7b6f,535e4699,515a442f,1006eea1,999be950,d2e04295)}, -{S(8f2a3f96,165eb6ed,6e04a3c3,6bc98bbd,8e224687,7e1f5279,4b9457e8,3a098653,cf4e0357,cabc0d24,b1eea14c,1b9bc9dd,e513584d,4d476a02,bfa3305,f9561360), -S(b590c88f,653caf4f,ef1395e4,3438781a,594966e1,fa38d019,c6297350,7cf9e142,b5f13a30,c368d049,7c3dbcf7,f7b07a19,350c5b32,248fb27a,a2a9ba33,5dd18a11), -S(71836bce,72f6b823,8edf858,ea84f2a2,4a0bc6d1,7419d751,e14a4813,bc2668d6,3156f04d,c1b89f36,1e7c878,94b92a87,2c63898f,38cfa4f0,48cac403,ca57fd5a), -S(1996fd72,66c764df,a93b77f5,c158a41d,adf46d38,ada30dca,62919df7,ab256fb,3990ba0,814ff4c3,48822de7,a4e67059,242d4990,78bdf784,28dc6c97,f66ffe48)}, -{S(fec456a8,6cd530b,d0512eec,301e3ef3,d5537be8,974bc23d,60e2efba,71b55ce6,bc77af1b,426e3427,6660dd70,2ee322ac,d1e19d0a,7b1d41a9,8bbe3866,9d087371), -S(9cb7d661,759605b,2237d552,e4967b9a,986fa9bc,8a602343,edcc429b,1b20b0ed,217252c3,1413ebaa,d31cbd1f,d0f6ee4c,4193475d,581806a3,6a864be3,918c9f8), -S(d95a3a88,9c8420d2,fc6b4d65,7f868305,3ba7888d,c946973e,647c6acb,82f4d86d,d7f4973c,bd3ca3c2,fbed8b4b,e78d665d,8140530a,ed5b81e0,c5ca04b2,c8cbb617), -S(8cf3ceaf,7cd77738,d6941ed3,3215ccf,cdaf13dc,910f126e,43356a45,bc9c2822,833e822c,cf90bd9a,dd06b052,dad6b73c,b5ee7678,c1a5e35f,d3e851bb,a9a9a6ce)}, -{S(a258e5e6,e1aac3d,707c5567,a9caae47,1b21224b,87828cbd,537f613a,6cdaaba7,d349347,e8f24cb9,1202c076,6c7247cd,e2eebe9e,62baeed4,aa51191,522c2c07), -S(f654c148,6e9e5a4,2ecd19c6,9b42e27b,94f3c3bb,3407b584,42684229,da0bb67d,cac5b906,d0665fc1,d7efd4f8,d1927f4b,98b9199f,69ce7614,b40ef0fc,dce340a), -S(f30d89a3,a536db35,b040eda1,5189a2b8,166a9e06,4cc92952,386be62,2f43f389,79ace00,4153547e,bbb903be,beceeb9,a916135f,42cb9a29,54817f9d,cb11deb1), -S(3e6e3577,bc22620b,e9a97210,74bb4bea,97379d57,bc1ed61a,33882224,305e4e1f,f634a97a,2e483822,3c4ce4de,50dbe0fc,117ad913,c3dbd75a,69ecaeca,1d413d62)}, -{S(316c28a3,63bf9651,2cd9f688,1bdf7430,dbf7e594,e6a7cff4,bd991c18,d2c0833a,4222087c,65b29e96,7c2562a3,4a491c0f,5ab5db22,2fc30d37,4c1157cb,5bf17741), -S(3384a50c,9f621970,2bfeb9f,5b6259ca,6062004f,b4375f22,22259e2e,ad496236,37afa3b5,23a6c185,3817cb56,e5f87e20,5f57f186,75b66ce2,4c1cb55c,fbe63b3), -S(32082a9a,45f6bd5a,90cf0efc,8c362da6,5f01a679,2c735f2e,a14346b,984279ec,fbfa9371,7ea480f0,a05c9de9,f6a50ed4,5a36b950,fe837c96,b8eda38c,1ad79b9b), -S(d7d044cd,fcf11946,97c63a98,94b56b2d,2b328eb,8fbdb2f7,f919479,2da1f0e4,46da7078,4a495b7b,e839d3c8,10cd7624,5f501685,15661bdb,4e786135,271453c1)}, -{S(3ce0395,6908baa4,1efed22a,3cd2b18b,e14bc3c,a17e8e46,7f757e56,5314f27f,fce17fc7,7d007d1c,25558760,d730019b,22ac9cff,6f4ba689,a1885b2d,5f0d0440), -S(2f5a7352,11a250d2,cb126237,c2c8ebdf,e9d7c628,9a319903,5a1ede18,b585cbe8,e3095320,3f1a2cde,eccb1e9d,5be869eb,f447471,9f7670de,f1b86cdc,fae5da73), -S(e86666e2,980948d,28d2baa4,c4a49d55,fff25b39,55695ac8,11ccd6d8,f882988a,823aa73d,20c0f848,66a8c63b,5631db07,b8a15f5d,90d79e3a,16c4040,a5106987), -S(1b1ce843,955f9c8c,28dac111,5e8a357c,dee3b723,70d1cd36,9d03a3c6,1b7e7342,5f8648e0,4965445d,cc8d6917,db45d7d8,3145d7ec,71f6e117,8e773724,a39e784f)}, -{S(feeaf523,3f208ccc,11478774,bb05c1e1,cc7ee923,32e6f84c,970a0579,aefcd4f2,47f6e6c8,3e5bf7be,5743f776,e607ba73,a83ffbc2,f1c581c5,c0cb1d98,b10be58c), -S(42086c81,d2685972,b69cc8f2,8fb8e949,80417664,76c11dad,1afddef7,773d72fa,b0e1b1f3,79082879,512302b4,1314b3ab,5a3f739e,aa8ac1f3,cb82ebc2,c2f9d13a), -S(5f8dd0eb,57f8a8f9,d1605e28,987aa1dd,bbbd05fe,8ae2aece,48fc6392,3bd6,c7daf790,b90ce9b,a73a3c1f,4b30a508,d41c0d53,f375ca86,b0ba2901,dd9ad482), -S(c92aad54,6d6046c2,4606c934,63391e5,a13be77d,e3eefe17,3b0011bb,129d3ad3,288c9ed0,2db46521,c9249b02,8f262b1f,9e684530,2cba4ae2,506025ad,ca0b8168)}, -{S(e3ee8330,33377c46,d51c8aa0,7919485a,ce3c3969,e533150d,a3e15479,f26c80a6,f757943e,9569814d,1d6bbb71,55294783,500c75d3,7510ac98,18497bb2,9388ca8f), -S(95811875,6d6505a0,89b46ec,648a2297,de391535,d3873b83,a7db485a,1ab8ae01,baa7fd9e,bf67d8a8,c1ac73dd,69bf264f,e0da962b,e26ce223,dd3dd5b9,8154e3a4), -S(1ea76ec,a1955521,2aab3141,173ddc67,8463fc79,2e887297,a713fea9,b6064fc8,c8b34073,8c73318e,d757034e,c947c5b3,ba7baed7,3eea8ea5,2c4d5b37,6186e283), -S(38281ae5,371b347f,bec1e9c7,841cb3d1,5a7ddfa7,684e9e93,e2c12cd1,acf0ee5d,8bf4f92d,92fabcab,c814e790,21ade825,448ffbc8,782ed1c5,60c72149,67fd5cbc)}, -{S(6bd00cc4,657b1902,51f8dd4b,9bec4668,b0c8cfb9,651395f4,8badda1c,a1dbcd3a,84d71092,e37a7401,810b17ec,3e0e4871,27c4847c,afb24d91,241514c7,779c61e5), -S(804cb958,a76c7348,17a62e10,2b1247f,462438e7,b0b3a96b,c202dc5b,c18de9,c775f60e,9e39fb0f,788e4447,fbc40690,ccaef5d4,2e9d7e89,e6ae41b5,8fd2fcb2), -S(d1050190,fb46792b,c29df9c2,5f2b9e48,99125548,336115fb,b7449c74,681c16ae,d677925f,e9448af3,76734c13,af2f7433,a9ab84cf,b7a6c4d5,d6091afa,766d878), -S(b81ee327,adb39987,c8d65543,7b7c771c,9061623c,bf36da42,ecc7c226,4ef708d1,6ec466cb,a3a52bad,a9f3f7a3,6ed90d4a,857a3570,610023a0,94fc5107,df2056ba)}, -{S(725d64c,4128d78d,11b4f7fa,eb9f04fd,9075ac9f,e1129eba,8544c3f6,685ebe04,36eaba03,94b7511,31a9c5f4,292a7307,1862fbb7,c43fee3c,1e5eadb2,7fb65db8), -S(40069204,ebd45314,a4d757ce,5a4020c0,e36f3bd7,fff73d30,60628b53,8d685861,d81134bb,5ebd3d7f,10a90cd,369ec3d6,9cab48c6,f49e5583,d766aae0,4d466d27), -S(901a167d,19e00cc5,14b3b724,759efa64,3eb7a8ce,9466eaf1,b6fab1c8,63b6f9bf,e100d9d1,e1451f09,2b5c1761,1e2d2376,75b1c95a,a71a052c,e7497a63,a9fea105), -S(f0fabd37,39f53d29,801e00e5,304cb5d9,a3553226,fff9ba5e,c8fe1030,26739c1d,cd23a575,ed09eac,f8446c8c,7f311ecc,78acac27,3a0fd6f7,988bdac6,361a4678)}, -{S(8f4e8dd8,20d7e026,ce2fba81,19028ea8,758f99ec,f7bc2f09,d239d60f,24027c9d,81b9197d,7374975d,1bcce80f,1a8a1e84,19a7a656,70a5dc21,49b00aa1,60055743), -S(e8e4ac24,1b8568c4,cec4f08a,9badff38,87c132e2,47add60f,3c39cb7a,8905027c,89c74e18,74737819,6fe1a4b6,3b2893a4,865de0b0,775598f9,33504aa5,ac453a91), -S(e6a8a510,f7316ef1,4e50e9f8,c8843220,c03df75f,e508d820,f3fa0dbb,5e9d0f94,1ecda600,14fc8668,32b1f2f1,b80ccb12,aabcbf94,f74f0a6d,dc6c692a,a20040af), -S(752c8264,bfb10ae3,aebbf561,3f65d191,d2956e3c,a7578e53,2a8b85bc,eb1d294e,1ff5c140,6558073,da1cc7ab,fa80d4c5,d557612e,c990206,6fd895af,11cd493c)}, -{S(9a9a4dfb,615c1e79,c2c19a19,34300742,7329b1f2,b7ae815,8ed8ebf1,5878d02e,39da7ba5,f1b9754b,e6fabbf7,a45b7ea,5cbcea2a,da2cf2bc,82aac66b,468af931), -S(14159eba,90d658df,ff2a3726,9ab60c0a,7540c68f,a77e0339,8caceb5f,6262d656,4497a299,27b365e1,35a77f61,bb6bac74,6918e3c6,79f97021,972c6013,d8109e6), -S(d4d3e7c,2ea5fb74,45160de8,19bec4d9,bc843b9,fc14fa74,6c0cb842,1b02a765,b55606cf,557bdebc,90da9255,f6a38a95,5ebc5998,bf021708,ee0a91a2,147ac684), -S(1acdbd72,130fda7a,122e015c,f3101670,d8090193,828710bd,1ff2b242,5d3ed896,b8cc1086,347ace8d,858ca6bd,56a80125,7d0f4333,b26541f,9865fb44,c5f349d7)}, -{S(93871b45,831fe55e,82338224,aabcb408,26c13f29,64c57fd1,b93711f,4ea53cff,79303c6d,1a8054f9,d66c5524,8ff9cd8e,17b5fdca,f9fa4388,9b0055e2,15c0a54), -S(8319d182,59cb7c75,228d314e,7db1db16,e34c9f62,2bf4e893,f06f86c4,3122dc51,5cccb4e,e295cade,ee396b80,10f6043d,d9141412,b8eb4216,60f9cc63,ee96f6de), -S(1d139778,64726f8b,7713beb7,6066df5d,d5116728,d5688fee,e20fa12f,14f9857d,3fd0294,d9ba6e7c,7a08bd63,d747365e,eadabab7,5ff1ca8a,95174569,c6fbe910), -S(a2c17270,296ad5e1,7ce111c2,899411a6,276efb6f,d6794a7d,212fc3cb,7d9fba31,b0a2e976,582022a3,a2c636c3,2c0909fb,533bbfa,193f8366,e65702c4,e0d8629e)}, -{S(24b75440,39c1351c,ccceacda,d31c758c,206331da,87a277ea,588a4376,82dad76b,854ebb44,a351e732,d900a1de,dbb0a5df,168a311c,4af01dd7,64722531,a3132213), -S(c89cdf5a,c0bae450,ffe0bdc7,f01ec47e,8a036cc9,43e0cd72,245cca5c,308d0087,e54935fb,6eea8620,a8b85fa6,d63d14ea,16c2edca,92fd6adc,7feabc35,91599acb), -S(255e5f4a,2bc33aed,aba2b7ec,b22ec225,30d3bb21,f7a63be4,bd5e2f6d,ad48e927,79cbe440,8da8c79,74bfc4ad,2715e2eb,eec2c950,8a01538,be795d21,c462b208), -S(e1497ffb,ab348f03,ea075d4a,bdc3d5fb,b2b9b413,5dab5190,2d8e1959,2be57e00,e3194cad,50cae1f3,7e713ad2,5bb635fb,74f6cbbe,83782411,65a8dbb6,ccee6faa)}, -{S(b9ed5a31,aaa443eb,99d8afea,7b32b81f,5860946a,5a5e63ae,def2a6bc,25c43f9f,e5bf15af,3e0a5fd5,12a14a6d,e03ce09b,a82b2fac,6fb8e16b,708752df,95f080c6), -S(45b0720c,7c7a16f5,9e07c7a2,b9f79ecc,194c4497,2a076bfe,cd662189,f51b5f4,b8acd754,a68d90f6,928fb515,d51d5c86,b86a832b,1506a251,447430a2,f255bc8f), -S(8a4c2587,cd27e533,7d848f56,43327489,19d3aa88,6d4b944,d4d44689,5cbe1ad,581ce4f3,7471bac8,9e904daf,c42013f4,2451a155,6ba12aad,deb02653,95926838), -S(4cf058d0,f5959eed,87402967,781dbfa4,29df9de1,327633f7,a6b354de,ebde5aaa,9254c0b5,709fa08c,684a59e1,1864a10a,3c4e9359,dd91b39b,15066b2e,e678a1a8)}, -{S(49208997,3351bf26,e5245cf8,afc6a69c,baa24dc8,5565ef5,d39e6a05,8b3cdf17,a4276fd0,1f754f88,11bdd14d,d1ced0d7,8bb7843f,a876e7d6,9531c223,2e9c9b4), -S(7b098cf0,f897637c,cd32c99d,de95acd9,2e05bb47,b16a58cb,d5e97827,734648f9,1d4e7732,2c99b9d1,dd330ef6,e955138a,6d0b606,1948b067,edf1c39b,61ab0505), -S(222b1686,82ca8f4c,b333da8,3a1f3cfb,e19f9e3a,8b597ceb,ceabd65e,720af23d,7278370b,c722a13b,d90164df,41323da4,6cb7b346,3c1428f7,265cbfd5,6d0d8d35), -S(97da8a09,8a3507b2,b5f330b,b405762b,cfd5c631,ed835bb0,842ad75d,a2175c31,5c051aef,a278fcd9,a2e230eb,993fe8da,f0c06306,14a5a6b1,799c0cd4,d3911144)}, -{S(265747dd,9f0d0396,faa54221,4a050192,3de7d376,f13768a1,50daa098,92ca71d7,412f5e39,db7cb201,3d083c20,19ddcb27,2ffd0a0b,89413e81,7718bae2,f1120fab), -S(918a2f6e,863bc4fd,87b5db45,15571d62,50e87c47,fca0914c,2b76d9df,185c0a32,a5551dbd,5c739407,880a5487,8ce218b6,766f0553,78f1a053,179ed3c8,3f362ff6), -S(6da6ff1b,ecb936d0,1ea353c4,ca3f949a,90153ec9,13329206,8b9be293,ae28998e,822ea180,8265bfb2,3fe6c6c4,51f62245,4185a813,e3f61604,c89044e8,555ae0a6), -S(bc0730da,9a06486a,99364ded,b612fb7,ac36cd21,466f7acf,e0be262e,55e0d269,7cffd8a6,13cf43cf,7eca904f,96a9e9dd,8b54dd22,49372095,95483592,64d7b8a0)}, -{S(96f6ae9f,84281919,50583f91,d4b76ec5,3c01dc20,6d06d33a,2560a8fa,11fe5daf,aac32455,acc71276,efed23dc,ab42fb8c,24bd18da,604b913e,bdd1318a,d1bc223), -S(f24cfc1a,9a29848c,f1d996d0,7fdc3ee1,ff14d1a3,a7811f18,e8bdcc47,a7806534,e0e4363d,2a227fc8,2df704b5,316410d3,a671ea2f,34702c0,7208fb27,6c1d12df), -S(1123af94,e86f2def,561f490,94ab160c,996f1955,dc2597f8,fe765c2b,d4793679,39d160a8,caf4b2c4,e4e95087,6e9a3183,55d4da27,9c7e2429,9762065,af62b2c1), -S(f5b8a7e4,6d4b110a,46d12dac,d308dad2,3f7f497d,b5a8a76d,c9577da6,f0943430,835941c3,b12ead86,6ca3f05e,c4b09953,9a8ab640,3e450590,37a990c6,88c1922f)}, -{S(f307f4b,b76a7bcf,1fe75d85,60a4c64,c748b32f,489e30b6,170057ed,225c9e95,fc200ac2,3ba3be6d,aa4d4f86,c89fdc5b,8eb00f8c,ebcf6a41,51411042,ad181fb5), -S(dbcf10f2,e43ae854,85fd600d,ca9ab27d,7ba393d,e6a333c0,7901cfc4,55352569,48d4448d,8ce674df,d254f09,17fdc390,de9aa8ff,29869da7,4c2529cc,dd476fb8), -S(38a07202,a23d26fd,663fa7e1,8e8a02a9,2631011e,57731024,3e717ac3,a0390078,fb6057ac,aa4fabb7,c4e922cb,ab2b7fb1,e4f0b3a7,6be215f7,7de296d3,ed709def), -S(5bd3e7ac,5f8619f,5db77e69,f7416149,b4afa5c7,95d25fbb,fb1da1ad,9e4617e3,9ae709f0,d7278b4e,b66919b,c666d63b,46bc228,8ca956eb,2e20238b,24725d56)}, -{S(35e48872,5074158a,8d2ed392,d178f6e2,e4c43fc9,689b32d,5f374c05,d637a53b,95143742,7bb0105b,5e7f60f2,d95ff164,ff808b7b,c2ad592d,68988e5e,bb5d5679), -S(8619863a,d49d8ab5,6c999e77,4653e1a7,4acb7a63,edb65840,76f3b3ae,903f3579,451500a1,3dac87a8,ace7fe4e,64dc6174,896b5002,67163bea,1d3db275,b8274cc5), -S(afeffbdc,dede5aaf,dc91475c,100918d2,f59039df,b5754f58,a330a469,1855e858,e05eacad,fe537099,35be0173,3d4b4dc6,7674d1a3,7d911d02,ea4f74f,6b63da04), -S(2b697c1a,2d2de701,16536722,945e46c9,21f02fd7,d8e9fd46,8fa9f159,1dec4273,6dd6ad5b,44541355,83b4833f,10de56a1,ed16c5a8,77d593ed,2538b95c,ce8785ef)}, -{S(cce6ccb3,fc1cbcc1,1f40457f,25157d24,6d3fefa2,24c340f1,ebdb3b02,3f02e3cf,9797a15e,ace0c660,eb93b185,7f6de7de,2d1d0f36,8c9a2eeb,a53b2860,b392bf2f), -S(71e75cd4,592214c9,556dc1b7,a7c8c5cf,77ab0249,a6a7ad9a,378e3e5d,d150939d,4e0c9607,c1b2866e,214f38e0,d4759bf3,b38f1f7a,35490b6d,70cf2e65,fde90bc4), -S(dea94d9b,c0222c46,c66012bc,91a3be34,d5df8157,56a9d97d,52c8c4b1,24ed243c,b3df667f,2615a0cf,2e7c0122,63af5067,b47d8cb,d22425f2,1bdba132,5e333588), -S(67bb4796,c88ec279,87e7d4e7,bd2e4e9e,bb1806b,95d3d8b4,e1a5d367,64e6d01,2af04b47,62d5a122,3bd0fd46,49be2b1d,92df5d8a,84ceb205,f2b70f2e,b5679290)}, -{S(86592c40,71b619fd,27e3825,ca585cdd,ea068958,7b59e3bb,b3581075,a3cb8a96,923844bf,2a197b85,b232b973,2922ce0c,a2431dc4,a59d27f0,2ff3b2f4,af7703bf), -S(e82a2871,fbff9467,96109300,26ffb096,d9509b43,6e786697,e85c57b3,389f4fbd,7732b419,f0d682a7,9ab047a7,d4a51685,fcaa3c8c,cd8115bc,4f7514f4,1717c804), -S(9c079fba,32d2288e,a0829fa1,1482dbb,8032397e,c676d744,c7b0ce84,a1c4f539,2b171739,85fa643a,ba7314d3,86f086c0,d4884b63,4062a4c8,3f7f05aa,575936a6), -S(78ea5f31,1d3c1943,e438601e,a885ae8e,efee93e9,26768d82,3e88a71d,9c22d773,953cb0dd,893aed33,9021e63b,277cca61,4d772c7e,a2b8ea3f,bd151b14,5cb144bc)}, -{S(4929a368,f9842917,73f5236f,dd5cbd7f,a8e8dd9f,261cbab,5948ad57,798cbf79,26a2a40b,33630e55,7b376fd8,134a8d48,542c08e8,c2d01a99,586d33c,66d37426), -S(bb4b9ce4,b8dd22bf,2873b2de,f29c494f,621d89e4,aebf3c23,566e0cd4,b4ffd288,d4f81742,4f778966,1274fc8,e8aa5c54,4434fca7,6b73b639,a04aab65,8bb77c2f), -S(6ff70715,17bdc2a4,c0267caa,38ca96ad,8a235744,2a24db87,a07cdec6,c3b022fa,2f16b295,a2db7a6d,321280c3,a53dfcf4,674dc215,38e2a556,75cd37e5,d3ee7362), -S(b5619c5e,edbc92f0,c88a9cad,9955a08b,764dd683,361bb7f2,8c611857,d473c45b,11f6864b,36116181,d2af3f6c,fe738c84,7820ebe1,53f0c82b,14e5c67a,b3a2213e)}, -{S(c7452697,d7691662,ae3b754c,7be11df8,ac70cc8c,e2e80a9b,9638b0f2,a323ecd5,fe84e963,3231caac,63a5c7cc,90cef693,a69ea140,c846e1b3,b96a6fc6,68b43c68), -S(c797ca59,95cda70a,a33093bc,4f7f83c6,1a31ab1e,dbd6f10d,31e0da05,64f41407,ce4a64f9,ae7eef1b,7abfad94,f4a6a7f1,c746268e,9006995e,8f7d311,1b81f85e), -S(288a2e26,8fb8fb28,29bd9d21,4ec5860b,fc1ed577,f40c6184,79a0b921,c2f4b67a,8343d03d,556bfee4,b66ca598,f4fecbcb,aa2723c2,f3c35203,ee12710d,d9ff0b52), -S(7aa02a72,adefd779,fd994c77,697ee142,dd25d168,38c8b8a0,5178b7e7,37f33032,a060f7d4,8e0c2929,864208a7,1668129b,3b3908c3,7e89ba0,e7e55aa6,5e3ed98e)}, -{S(34925d1a,b1c7c081,e945d66d,60ed394e,f474e38a,423562b3,95bc51d4,c4f55321,8ef8dd58,ae1661b5,a7c327ba,ac4105e6,d02d6a30,2263c5f8,62b712fa,b064e562), -S(2bbf19eb,9a6211a,7881c7e0,5483a318,c9d91280,d09e0634,2a54a9f2,b5654be8,3cf7b41,bfab218d,e182cf34,32450abf,88da1e16,fdb79699,ecfeb962,39d422d3), -S(97f1b30a,6ce2dd8e,1d0358fb,45b432fe,be6d9916,34ecc7a4,b7cb4f3c,f1663fb8,c7cba22b,88a5f5c4,498f0f22,cea6830e,1bb44e1c,7f9d9833,60139c2e,97dab7da), -S(b5d0e718,621a0a40,c2adf34a,3e1e64d6,bbad3598,e6944436,f8f87450,575d61ef,2e43eb70,8fb8e2a0,f24a1a12,7a890c07,d79b51d,60e3a281,649afa3c,182d5b77)}, -{S(463080f9,19ecd42f,593dc20a,2d3160cc,74d9592e,446f299d,be5446f4,236a5b17,2a65200d,e1b16975,9d5c75d6,fa6c666,ba45728d,343d6339,48233391,60c14a16), -S(547eef23,516851a2,2f160ec0,781a49f1,1480d07d,2607ab5a,89656c94,2f774b5a,eb6f249d,ee624cae,cbc59f02,63da0fcc,e33a515c,843c3632,661f13e4,39c4f0e4), -S(77f0c9a2,51d48b39,62f92e2a,679fd9cc,f458f17a,edf588be,d4bd6448,47f9306f,355f4827,b10e614b,4590242b,da546e53,dbd419de,1d1a7fa3,208d9350,3496db0c), -S(81e606c1,19b6ef80,418aa008,7ebaf9d3,7adff1ff,a81f739a,172a580b,27c7545c,ddb0404c,e56113c5,93920382,6d2adab2,6590b509,45865406,ce1fd256,6565209a)}, -{S(92d469ed,e0969dd6,7e9d7b31,f0f703e3,97cad53b,e6101b2e,eeb8714d,645eaa9c,24a0a786,916297f4,6a53c7c2,29a3c95,80eec521,355b823,f0488460,39595dd2), -S(e5035341,5c49c24d,f672a74e,4eb2d108,57fa987a,afc50178,ffba8797,5503006f,38522661,fe682984,7b6dda61,9dbbe47b,35c0c9eb,b79b5d2f,2c6ba882,26cb95d4), -S(d0777020,cf6dc469,cf020ce5,e64bc2e4,1e2bf116,4f4e814f,18bbbc4f,f468b0b8,997b2163,c4670401,281ad84b,a914cbe4,e76a5cb1,cb90c1bd,ecdac585,621cb0a6), -S(881abd9c,717f0a2,360de50d,66a9b655,b9459e62,80a985da,e811f2b2,154e307a,beec571,1375031f,354dda5c,b9d8377d,1cb49816,1f4c738d,f6b9d323,f9acacd)}, -{S(ab7d18ba,955fdaaa,b1a0bb25,25844e2a,9d2e204d,ff224588,ae96c41,e690e010,4e0090b1,dcd619c3,10ff5027,9c534612,84ec2467,77b63179,c80724c4,42d00204), -S(1a5982e3,37e3eb50,e679f24e,c3473b4d,1af3dcbe,ac3c7a96,a95f51f9,a9875266,dca6c614,85d55985,1fdc229,56ee59cd,fac74069,6276299b,a199f39c,869e5c9c), -S(bcdf870f,8d5394b4,f1f3446c,a25ec6d,5b4c939,b598e596,814a6dda,a054bb2f,71cfbdd,d1aa7722,892f83e4,ea2dec50,81c4d14e,548a16c4,2818b76d,5721fb7c), -S(cb28eeda,338a5088,db505da,949cddf2,741e071e,378f92f1,dbba270e,9c322c57,d98cba61,cceca53f,7d84d71f,f892b962,6f26e156,841d2dfb,7aaab839,3f515903)} -#endif -#if ECMULT_GEN_PREC_BITS == 4 -{S(3a9ed373,6eed3eec,9aeb5ac0,21b54652,56817b1f,8de6cd0,fbcee548,ba044bb5,7bcc5928,bdc9c023,dfc663b8,9e4f6969,ab751798,8e600ec1,d242010c,45c7974a), -S(e44d7675,c3cb2857,4e133c01,a74f4afc,5ce684f8,4a789711,603f7c4f,50abef58,25bcb62f,fe2e2ce2,196ad86c,a006e20,8c64d21b,b25320a3,b5574b9c,1e1bfb4b), -S(6ada98a4,8118166f,e7082591,d6cda51e,914b60b1,49696270,3350249b,ee8d4770,c234dfad,f3847877,a0a7bcda,112dba85,1cdddf00,84d0c07,df1d1a,a3ec3aeb), -S(a94ae8,63264dfb,b910ea95,4ce9ca7e,4f86f92d,9f3a95d1,ed61552a,7a3f5743,7f53f7f1,6ad2d08f,15e73314,6d80467,41557acf,19556c0f,ed7117ce,37040823), -S(b692c750,d23d3674,c351e3b7,e1a8a87b,14a5df81,852eaf35,209d0ec5,6e22a2cf,b18c4f17,252db89f,838de32f,b3340ea2,bb961a39,54b38c47,f9a8219c,4820a0cb), -S(691fc741,80e75b55,47b375f1,1bf60abe,451d27de,1743a436,5f8e4bac,ad421c09,8eb5fd9d,f3c03240,6cebf370,8125955f,bf2ef703,475d3fd6,1a0291b6,69b52d9d), -S(703b5f14,a7d82473,1196b52f,ae9ca8cb,b245b004,7a9928d7,d0c42f33,391411dc,5ed74eaa,49f276c0,4d61f31b,6da4137c,bde5673d,8e3f815d,efea7951,f88585c), -S(29b8ec47,d241eda1,e51bbb1e,3928444c,3747b4fe,7cecb365,2bbc4587,2f504875,88693238,8562f8bf,f7d72324,62ebc54,6b93a95f,77936b02,eb1cd6a7,d4199bcb), -S(444a07ad,e81916c9,32bdeec2,21c556c4,6b7f6491,e99b479,2cfec82f,4ec17910,2e084c2f,eead5200,77c151b6,eff9375a,713b9d15,5306708d,b3f538e1,8eb18cf), -S(e0dd618b,226ceddc,f560527e,20b4fe58,e5fcf28,39911ea6,c3e8a4a7,e15f9121,a063a157,3377bbbf,1b9a5ebe,afbe11aa,660c1e65,df1392b8,97205858,3c86a3fc), -S(9b99461a,2e8360f2,f2ba0bb8,bcaeb699,159e0652,69d9042a,fa0c4e30,a7b6f30d,3fe7fe04,3cb45303,3d4f5560,7d41cd76,9036a49b,82912350,6d8b9995,254154fd), -S(504da3a9,d9d9c81b,c2065398,4ed28cb1,b5beec9b,6ce5dfb6,cea94e54,fdff044b,cbd40d1e,858133c9,cd20b9e4,ff9fe94,f7cc9579,39e6df49,7a6bd702,797f96cf), -S(ddec0aac,1ebce6aa,ad6300d5,60f0e503,829f0bc6,479641f9,b19d9f6,484376fb,332ff5b1,fc83085e,736736bf,3c265e4c,8f80925e,6f38479d,6563bc34,e5faea1), -S(dc530ceb,b82c246e,41c522f1,d2571d31,4b14edf3,91577a2b,64e42172,b23562c1,563ddd93,857d6529,8b81de24,19e5cede,7a4c5b7,a2fe98f6,9efb8906,6f32a98a), -S(7604d60f,418dd132,78058942,fb2d2153,c0a2bfeb,e83c5011,a451bcb1,58db0773,38be14ae,d9e1c404,63ef92bd,d62c599a,b37625a8,182a3763,4fa2de90,535d50a9), -S(cb896744,77b20829,f5e2bd42,8852c70b,91cbd0af,cadf219,a69727b4,cbec8d7a,5710d17a,20ea0dff,980d3f06,38d8b910,b8940d00,dd4a323f,d777d942,213e1093)}, -{S(1b8462eb,1ccdf7b2,b8372f2f,cec1f479,ab07c09f,cb26d6c3,965ec73,4d654f81,62f6755,b4a7891d,55de6427,fbc37d33,e4eea418,a2c04392,a3d11807,ccc9025), -S(f6fa4c02,1b697e93,ae34145b,481a3ac7,462343dc,6022040f,834dd9d2,c69b5d,5de5e04b,351f9928,b84abaed,d3319e61,ea91fc59,8d6fcac3,401d1ae7,c08943e), -S(cf805a58,d8f9b414,aa73cd0c,e545c9af,3f7d6543,8ae57688,81d30866,e81242d4,f455c617,99a2ca5c,fac3eb6f,23282774,7c9e914e,fce447ad,8fd71ffc,4fc3306b), -S(48dbd9a5,88d1f02d,6eacc5a6,36c0fb4f,de87eb44,11329442,1265b0ff,a72e473,9a206d25,5dc1d916,e3b1e301,cab1bd91,ea29eb7e,979c0b84,608ed770,4af325d0), -S(ceb3637b,28997733,ad6ef0dd,5004e32,9c87981b,e6d811a3,88804884,652780d4,6aed5e97,c0e836b2,73a309fc,5d389779,1f6f0bc9,246921ef,5fa9767f,dacac3f5), -S(8940dca2,52ebefad,61db720b,e709c749,7302b5e1,a4174893,9626910c,43708a18,e1b0d7be,1e36c585,8bc6125f,7fd5c423,5e643f7f,11668026,c1536e9d,f6305efd), -S(aa33c3cb,bb97ccee,5b8f452f,6a615900,392d78f5,b8c1f022,5266b8c,cb3449e0,e9ba50b4,7d3e3279,2253e925,5261f2f8,263c30dc,e613ea9e,737c3b92,8c8e3eef), -S(39f3965d,b455a466,930e5e82,ef214452,ef5c9019,bd805fe9,67fd362d,193a1b2a,8f69a32b,35bd6f1b,c5ada308,f61550b1,534c07b0,1a3465f0,564ed6d,a8f443c1), -S(6725d4a6,a827fef7,a0fb0214,900f526c,e23cc0b4,a6e291d0,ccb96ad9,e77393cd,69f91bac,b09facdd,b55fb70e,68164028,a8cf1bbc,207653c2,d898992f,89244f35), -S(3b71b2f,84d355f4,d246a57e,b235e396,ee236c57,d6ab3a46,f89b5d3c,1a911c1a,7616be06,59e5b42,9f105499,38d17654,c605f81a,e4bdf2b7,b9c1817b,c8db03b3), -S(a346e9c5,d8cc2ce1,1a733026,3136d92c,925f1b22,b27d3037,d9c4b109,9a06ecb6,4a3fd930,54f0cfa,6799e236,add0f928,6e45b77d,cef57797,7dcdac63,485c4f00), -S(8e3c768a,ee07f0aa,3eaa43e3,f6986805,b7829c50,d67861c0,c75ab390,5a6fb794,33d3c292,7a9e9c54,a671788a,fc0ec58d,cc2a0574,a172665e,347690d7,50de0acd), -S(b231176e,d39a928f,76a60397,79643e94,d5e75d17,238487be,f9b38b60,748711c3,3ae1ccae,204fb13d,74705b0b,8a0689eb,aea16e8e,c2f3d5db,177609ec,64027f0d), -S(8afbe02e,161ed971,44075da2,cea389b2,f53562d2,dc771d3f,9405259c,fe4232da,e2c16621,f38a0831,d2839585,9cbceb53,254398ef,b58308cc,bcf3d79,ee0af228), -S(1a263c8,c2c9080b,b0d4d61a,bb5d6b55,e6a7f520,80ef3f36,706e685d,7a527957,3925a458,779c3c25,7b546b99,7399a56c,b3c0b9ca,f6c77f9,c41b708d,f831253e), -S(35d88ae9,b1d3ee59,fe79c24e,de6cad1f,6d822f57,708ee54c,26e7495b,357e92c6,de74f353,d8115188,724c2a32,39b18661,6b8f7951,34aefc75,8e724a30,8be7f31e)}, -{S(6ae991de,18418b49,160194f,a735eb72,c299b987,1981a4f9,aa717ad2,bcdcf13,7ee8011a,40f384f2,e50add2d,97005173,2787cc7c,89dafb66,301bc94d,24b913f), -S(22165bce,e76e1594,5b9041e5,ccdee553,eba60e4f,1ece2d9f,e0ad7440,565f2665,fe8f383b,bae7e284,d1d890bd,569ab7b3,ebe5f1bb,b60ee19e,8e8de65f,88f3ab96), -S(a2600e0e,9265b7d8,fcc46a5,51872122,66ad5334,4ddedbf3,ac8cdf2a,b86f2b8e,d00f90a0,97fe3863,b4854dce,fa5a36e7,3f94015e,f892303f,2e5cb2c7,aefbf15), -S(38758ff9,5cefa7c1,b7a2443a,ba29b65b,aee1fa81,5ed49595,a4ec760f,b995df1d,43bc94bf,dfff3c59,7a6e41c0,52194d41,c1601b91,792f42a,6872ded2,a5e8f4cf), -S(57122897,d98019ae,a6dcbe99,49682895,c95471e8,d53680ac,49927e23,16abfd27,c30cb105,d9edc36c,9e237e93,2edd6bef,3d553d67,fec3a37b,fbe0ef56,a3cb6c), -S(7b7247c7,73470f13,2477c974,7820ce4d,51dde95b,dd14923d,e31dfb13,5a8aacdf,2e7054f4,a33361a7,a4282bb2,7e738884,3a91b211,3f71e160,60fb2235,6b40ffc1), -S(1d3f0661,13c271db,374adce9,ef0c444d,4ffbc1b2,a34b9c91,55986371,52376f68,1a4c07f3,e3752c71,f772c55b,d269f3ae,a9cb40a1,ac8a96b3,7387cd1c,bf22e864), -S(456ada98,2bcfa52a,55018711,6926b843,82754297,9af5c113,8af21e1e,3b625071,a7141c4c,673e441e,f67ccf99,53a7a6a6,3a77432,76261717,21f581b,2893243c), -S(b898efae,8582d8de,b315220c,dc79d2bc,1a221072,300e0971,c4a610f4,7f6b70dc,8da8b020,8d674418,5620db55,fa3cd928,be672c5c,22897030,bb5a5957,37758a8), -S(b732f7e6,9280227d,c1f56e84,7e72989,b834be6b,f04e2e3d,ca8553b5,ded18493,9157298a,5ff6e6e4,d705efcf,7601f33f,76cd2a64,6118103d,98fa000b,8ff9ad99), -S(9601ce19,964403b6,a58d1d51,be876199,d63755ef,91bd657a,fbfac3ef,c85c78d0,df06aeb0,517ae1da,ff3a48bd,7ecceaf5,b10ac9d9,67e7ef4,520593cf,d7502058), -S(a95814ec,11446773,36258a94,56670207,d068d8ae,19ada794,52210f2d,bd67bc5,29d7e4b3,5e5a4300,6297f9c1,f71a6a26,118693ce,fc738fea,ccf1b873,339617b3), -S(d3533330,c6afe33b,ae921c0f,558fe47d,b97e7711,ce98c884,3abe894,320e8926,e1be0b16,72f8ea16,b59a6b9a,20c27621,e63854cb,4efde5d8,d1da8929,4f777383), -S(4f05f649,e8ec9fe9,f675957f,7454a89e,c020feea,217782bb,43bbed43,b0a62881,dde64c2b,255d8518,da7461c6,b160286c,5222baa5,483fd5cf,dade9ae4,96432904), -S(1a06ead0,5ef3dcc1,a9080234,b6158fe5,681cc5ca,acebbbf2,c336ecdf,3505768b,63661e6e,816bad91,1c7bd073,a15b185,c4c7b7b0,ae440dd7,40a54286,3a86721f), -S(e2b163f9,f1b6ad48,e8bea9d3,b199cfe,378fbd2c,8f005cdc,e5959154,b2eca0e7,30759d6c,f55f7f15,a156a705,1f702294,72b9544,ba73fa40,27839cd5,67147083)}, -{S(64850a04,76870a44,2cfa57e0,4e4707f7,eccc5e99,12dbcb07,3b457317,717f5686,7c5facd2,91a6defb,a1837cb9,3bcbd0f5,bc37572e,68ccb2a0,c062a155,46656fcc), -S(4afd2a50,f79b1403,844523a7,e88e0156,f77f7856,8668ac7c,79d2160f,cac27acd,40346549,fb5b8450,165c2a4,c47665be,b1d31f73,1cd758ce,6c8f2b17,37a832d1), -S(f4132840,9cd5ac7d,7a0c92f2,5e39eb57,b8fcfbd5,d535ec00,a281d3d5,1275199b,6b66ce56,99a92cf1,8f635a0,7441f0c1,3561c8d4,cb0075f8,8a1596da,b6da6d29), -S(1a6c66d3,1a54ae12,59b709b4,c70fb434,f3347d11,7921ce06,fd4f0dbe,d211e4f4,b6438fae,74524dbe,2d03e27c,8af409ad,67af8eb6,84760c85,1e81c6af,a4cb004e), -S(3afe6f2e,8b5f1cf4,20ba1dc9,f527c662,a3af94c3,9d0e726e,b7942a2f,c9c1a91d,892cde5,f1420590,ff801f3f,8ec2ace,69f0dd74,31ca7e7,aed14c37,c2c12492), -S(28afcf30,a1f5079d,e6f340bc,9e616ce0,7a89b67d,4e7f0dc0,6f54fe9e,d17f1519,b7cc26ec,9a25b585,33a43369,40b6bdc0,c2462e39,2246a863,e67bdefe,1ae51be1), -S(13980996,af67f2e4,6dc5f389,d0269d1f,39a9341d,5e941e6,b4ff7bdb,ea54cb65,37a37717,d206b584,9eb79193,96ff5af0,449f3164,4c9eb31c,f27d8a,be66c741), -S(b7b75484,8966d79b,aa10ad77,4c447872,dc4c78db,84a58b9b,a112f5ca,77630bab,ca5111f1,55becf6f,1a546463,8a417af3,2c72cfaa,da56f86c,d7654c06,bc8fdff3), -S(b957ab6a,c7d7692,65adf169,492b00eb,4d8a351d,1f189d24,3e66453f,17696dcb,47474297,433f0297,231e0d7f,e51f1846,3af3e463,e071859e,d6b12b05,2191b839), -S(53f2395b,af57e626,f977dead,da52c4a3,f8b98701,f57eb79a,735e73b4,4d4be4b5,1a31bf14,36b5dcfd,5dc24ff2,ab5fc7e1,15940bf,12ae40b3,73859ce,5e26d55b), -S(31f8493d,8a81860a,3762fbdb,5b623358,af37ca99,3ce1bdfd,91f41acf,5d8502ce,1b231e3d,9604e28f,65d06f18,10931210,3a4cfba3,95c6d856,ecc374be,556a296b), -S(77da894f,ef83a273,22138b96,64df3b02,fdb5bf02,4963a103,1000ab37,a821460f,86cdc4bc,3269d02f,d3e97843,fd2c9dfa,c9ad2d99,f7503222,ac4c4da,5394809c), -S(d222a486,cdb8a4a2,8c1030c4,39b512f,f849033f,cc844e08,fcfd8748,1f68430a,2d7d7e4a,281ba28b,75f2d966,1d25a46f,5ded9066,7422a92c,bfcb1f1,797b7e02), -S(e4431b98,21cfaa43,8a8dee6d,b7a19a38,729622c7,67cdc941,789a6b78,c7a2ae4d,770e652e,de9172c3,4f50ed14,bd8f83b0,720ee2f5,8717fc8,a07de08d,5f8ac400), -S(1bb4bf1,1a1fb6b,78093ad1,5fe5408b,f9e1477c,3844e243,a14c37b4,f394254b,d9cf3fa3,25a0ad1e,fef984c5,8cbe25d2,f88f3051,788cbd42,a8f71791,5229e944), -S(a8fc65fe,e4df466b,d6651ce5,7ef030f8,701e364d,f1de5334,92938856,deb74235,b4c7da06,4f7bcc17,b3308c1b,e7924317,fc02c53a,808b47b,d87700ce,1adffc97)}, -{S(92133195,a4fd0c59,7e0cf65e,8ce1d939,e333f7a8,441523aa,31e339e1,2ae51e8d,556a388,7a7d579e,87de7f49,8c54bf24,2ca4b8a2,8b959e21,ceec4555,b8fabccf), -S(1badb614,6a647a09,894f60d1,6544e992,6da742d0,32df02d,ea347ffb,dd52f93b,6927c950,828e5449,bafee29d,e9977bdc,cd6a0185,3d3ef286,d9854f9a,75f5d4ac), -S(dbec52ad,5b8257f8,f41612a2,70047e4a,715853a5,f22091e3,496a238e,cf61379f,1ed383f7,dccbdff5,bebe8f0c,235767dc,ee220fa9,8d1b5ef9,6aba5ad7,87b46252), -S(5d2fc0e9,a5b1a743,131b4b16,88d504d,76422862,942de800,6c6d3611,3443999e,f7f89299,64793634,4156dce3,ca77c2bb,40536f50,60afd3b0,a3b37d3d,869dc11d), -S(761a1b70,83db07d7,340fb1bd,d5309ee0,e9e05bf5,6fc34a53,b6034365,ffd91ac0,82b1fac0,3d382fd0,109e45b5,8a07638b,1ce9ff2b,f45d3cd9,50843b69,43c75c7a), -S(ea397afe,9dcad2b9,4ad000d1,7abc4e5b,739e4132,997a7898,3c6c5c29,ebf7222f,24a87ba3,411ca610,5a696969,f86ab751,2c61e189,5ff4ad18,7193b5ef,7d8d2034), -S(3dc03137,8776b2ba,83a8124e,821de26d,1a52855d,d610eec2,d5c7eec5,9c92e81,b774a839,6ad7b7ad,9e6275eb,2731ad84,271fb8b4,6c3e12df,b74fe942,e6dcd35b), -S(49b98bed,ac9bbbbb,75f4f3fe,310af59b,1ec779cd,41b75982,6a929bcb,d40ada85,c09f3d79,3b143720,dbc1d04a,4d559f35,c650d372,12668736,1d824a9c,b100630e), -S(786555cd,2c6344d5,7f819963,1ee8536a,ba3ed77e,88501a2,20df332e,b41c9aea,f3e046a0,3ea9d39b,31377a11,dcf7c2bb,13ff138f,f021902a,4f927e3f,f48a60c8), -S(413259f7,3ac4366c,1385e7a3,79f54796,4b6295c1,298fdb7e,6046f711,44ee3055,a7a62864,4717b82f,b3fbb73f,fae2318f,985f1923,7df110fb,260434bb,81bfb4dd), -S(64922735,de394c7c,1d42e1ef,d8a19ef6,ef34e69,dc12bce7,c320f748,3993bce2,84bc17d5,5711e228,7e81ccaa,9625c73c,60923b0a,f266b70a,435b1c11,e7d29fff), -S(32d0955a,c57511db,5f27606b,67cdef94,a001bdc2,cc228bf2,951f5426,69d6dd51,7f9bb41c,d62d5863,c2dfecdf,8e3cc9c5,d104abf4,56b9030a,552ed607,73719520), -S(2428069d,b3ff968b,d1559c74,c3f38f17,e725340b,e956e6b6,e6ae3a70,4fe8af4a,1f074994,b487ca2c,9bf222ec,41cb54b1,bac8dd57,50e47f00,59ee74a5,1de0fb4), -S(a7f35a96,ab880ce6,b4e3c5ba,6502af7e,cf00c685,b260fe0c,380ff875,2bcb3e34,7d47fcf3,ed09412b,ed9fc737,212b6289,8b415372,c9338673,a14e7f42,7b4ac9d3), -S(ab624def,ee301beb,96d2626a,88a9adbb,665f9e83,f85640f3,79e4ee7d,c9282b2,4dd486c4,3525c5d4,668c5fb2,7d03c985,df69a344,62187396,ed9b360d,fde32f72), -S(f6b26f3,cb13dfe9,dca461c8,5b480140,df4a0c0e,b1d2f5d7,58de5173,eb4c4746,a5ab6d87,e6852ce6,9965a774,ccb94676,a440d1d0,c8b02f54,21c11bdc,b8406cfa)}, -{S(ae5fb021,e9256cc0,6236d667,b76b9bdf,304a4683,d2916ffe,489cf019,6b4c5683,e768366b,5c8d36b6,18e45550,d57493e2,41fed17d,12627e37,b29b4b74,d3603696), -S(a4e569c7,5d717deb,360a18b9,5bc0fc36,af132603,b74f3e0b,1bca3e31,14c28e64,a70e832c,e3d8d514,84136fba,9f81a2d7,8ab65b93,dc9f9080,1fcf3712,74340130), -S(2e7c85c5,7e68056c,e10ae193,66807434,c048a046,430d2087,92fc9b01,dbe06508,8c3f82a0,b8cb5022,dc7b04aa,6445b06,d251f9ed,bee00246,c33785de,979140eb), -S(fadbb0f0,b4bd864b,73527365,6455cc26,71251519,6c63dec4,41052585,fa86eb52,bcc086d7,54f08f77,1888bef7,4bd3bf9e,35f8498a,aa7cddba,acd63f0f,ef676738), -S(4aa439c5,2a0dd24d,c5f72b14,9a39e991,6dbcd4bc,4619fd34,94012a4d,430a2b0e,5482d41c,7fda4591,4150d653,2173b658,b5a06046,8270fc7c,2ea19d58,7b96e9fd), -S(2e1c9639,537015af,7de6bd50,e2697661,8ac633e5,f1946af5,34bdbc5c,9797aa4f,b6a39518,c607d0d2,94a36682,f4f6493b,c80f1624,792fec2e,e971f080,37dc6dcd), -S(63f28872,6d86ffbe,28a516e4,75f67972,e6266038,3be45c0f,d22e9a6d,d5d240ed,f62ca816,59ac13,10854091,c7851bc0,4d315466,b6187327,3af16f9f,68597dc7), -S(576c051b,2f4d2ace,ca5c067e,290a4d5f,d8f9b6f,19d4652a,449fc1d6,9d4b762d,a2b94a16,903d80d3,f965c43f,b751dc44,690f18fd,bf3e29f7,e21b855a,837664bd), -S(876afd3d,8466f7ea,eed3ee7c,e809528f,c4b392c9,efcc1f9e,753b4dd9,b84722e,e4453b1f,c3fcd636,b2c9bf97,6816b60c,246e254a,67bf2e59,22f835af,103c1107), -S(5a2ca063,6453a00d,b8cd6f60,3434f0d8,8642c119,b6302766,8ee67dc7,c10c9e3b,17be303e,40bdb2d5,9dfe354b,e58a387b,ff64112,3f6a13b2,80876a7,24c4d601), -S(46fbb84c,d08ce9d4,73e3b00,f5ba4cc2,f10fb84b,ea34a8f2,de114c31,8616def2,62410bd7,2ffda863,2400747d,1984d1f7,da285e9c,592729bb,ad9cee72,d266fc78), -S(417f7895,e2bc2999,469ce63b,66cc9bbc,4581b42e,c62171a8,ac32bdd5,23435283,1a5e10ef,826f058a,175fa5d5,21594182,a61a5a07,406e1f00,396935be,f78c9ef8), -S(916866c2,f33c0942,c8f12e54,8771645c,e1581ee8,6f58a90,67ededc6,b70e93b4,c7945f0b,d100c3a4,d624e527,ea9a8d9f,cedc9934,f903955b,aba58be3,c23819b), -S(c3630c36,acc78b38,8c5e8604,8110f113,3638c78b,fad169d9,d25d66fb,728ed4b,5788b6d1,7c74f601,e2bf5d77,eec182ad,1d9b2a89,6da8962,f9887bdb,5a6918e0), -S(64fd5fe6,cf91f11c,970692cd,d2ba6bd3,4d17faa7,77ace6db,d161e63b,93a0ee19,37ce3afe,f75712c3,301e4c97,6456ad79,e09326b2,28b23e10,b033bc53,a6efd060), -S(2ff8f0e0,5d514fe5,766bc683,f82af019,471a173b,b0e2ccb7,53eb45a5,8047041,9a13b872,e26b58d8,68e1db1d,7391afc1,ece8e410,a4bc3f42,dcae2b27,ec9a6e98)}, -{S(782d5c9a,d970322e,deff2e7b,57844184,c589a4da,c042fcf3,86c1a9f8,26c1babb,27bba565,405cb392,64762d97,cbaff552,1bc38b20,56afe313,556542d3,f200eb06), -S(69040dab,81af8b4b,759b852,40c16380,cc2bc3a5,bc8e9e68,7cee93a3,352d8055,e48d161e,b63c619,26c78402,528ad5a7,19a7fef4,4c03b933,37d51bfa,ec497817), -S(d00d4407,f7a1bc4a,57ce72b3,6fba7d8e,ca4f2303,292c2ebf,6940b34f,fd98aafa,ebdee075,32ccf753,1806337b,54a36a53,1641fb80,64d928ac,5a3626bf,e16dba4f), -S(9a3ab165,66f8c8ab,7b3d0d5f,7a3ec7bf,3cb69c0f,31346486,10c552f8,17a4abe2,7eafa760,7fb4cea0,dedcfb1b,1c16ebb9,8904a79e,37395aa3,1ced5c71,fc8c7774), -S(f9028f3f,4f5752a9,9ce55412,876c7067,a199a338,1d707bb9,3d2fc44,b165d000,a7346d7b,6ea796e3,2a19f104,34a7e0d7,b7e90326,81374d05,9b81badb,4dd651da), -S(e7bd1e16,60174f67,13a8db0d,2bf88a45,275a44e2,9a461c1d,cc6dc5c4,fd2b5c0f,9732850b,41082c88,5ab49289,fe11094f,c26bf80d,1b0998c5,1ce63cde,d7bad0fd), -S(d8b88e20,ee8db21e,28bd271b,46d77769,b446994f,5eb35ea8,d0613b29,67f8c1a,8b9905cf,547475e5,838e9191,388b1c64,25fea463,1e4ef825,e84e2226,2888d0b7), -S(3dfae04a,180749e7,e6949aa5,600ebe40,af61d644,ab5446dd,4b3334dd,f9bd7ce,963fb79a,a952447d,e274666f,16c08a2f,d5864825,78b870de,afbd98c6,adf4cca4), -S(4e0f4c4,b4905983,e12cf9cd,7dbcdf18,db9782b7,d4ea7e11,280d1f,7bc01e53,3305aeb,9b5f23af,bf1c759c,14a811a0,1bc3a5aa,19e26176,71690393,f3318bc6), -S(d74e6ecd,72453ee3,f68fc29f,f0de5b36,82c295df,2fc568a9,d68ad747,d4409b77,46dfc1af,819ee0,fd04e0cb,1af0835b,e8f6e53f,1ed28d67,6c0c172b,2e56a74a), -S(d1ef8f37,78dfe4bc,83c48c4f,e9aeb917,34320f2b,a86630e5,28f735d4,fd78fc68,6cc62683,1e417caa,9bdafef9,92c7267a,e7ace1a9,27d225e2,a5000b97,c45007c1), -S(64457682,4f541ec7,d8ba1964,32146322,3d1bd634,5cd09f03,a91aff2e,b9502b15,236ca78e,bec84846,74c43c52,55e2cb76,b41b01da,ded4dede,1a99e1b5,8fe80638), -S(f557af63,f3d8437c,1c48619c,4bad3e7f,d92c6ff6,63b86121,55bba4b7,efbf350c,efe2dfea,62a12ffe,5e4208b8,e5af4f07,13f8de73,824502e6,94b08d34,d1d92e2f), -S(f45ade55,84070898,1d244e7e,a546a34d,85fb1164,5ea86188,43d753d4,2baa1ecb,ec25cb2,6574f472,69a90070,3eff9a68,770ffa2a,7b12efa1,dcd81ce3,56a46978), -S(e3169959,74f4127d,e9002439,582f9790,6047bb58,d4bfdf74,3b6ebea5,b5663d65,cf7afc59,efac3d94,88260d14,a3e252e0,b51345bc,d3e07c1d,b07ec4e,28b6d60e), -S(bc9112f0,137446bd,1a218167,72b6afd7,65b19569,90f8e53a,f8db935c,2a88686b,a74e4d7,1e24d149,1667dced,bd7f58ab,851d685b,1c29e38d,6c9e613d,b65b7864)}, -{S(ebc119d3,8e794efa,85fcbd,5affac35,f73c7428,590ede0f,6365f1ea,87c65b4b,183a9992,3911b1b1,cd9b0fea,3667b6e1,52af7499,8d32beb3,d2ecb91d,af6e8a06), -S(7ce4a044,e4656f8c,687bc693,1c6fcca1,95322643,db41d,8407d880,4d6b6cb0,14fe83fa,eb944cd6,dab9e7b6,279ebde1,6ce1028e,5df74c77,7e6e00dd,55f69465), -S(5226b60e,b344786,bf572e3e,33e5aa14,6ee6feaf,35c3a2b7,22118560,183cadb,cb650e9c,e4f93861,cdb700d,13557323,8a7d7686,e22943f6,433dab6d,96253b10), -S(21c0342b,9a723249,ae7193fe,aa00baf6,beeb376,1f1bb125,7d0d9549,d46b403b,5b2dfee9,4a67c6a4,def4f55,a14af716,ab1be308,ecac6042,f86679a2,1f5114a0), -S(82e97dbf,f1d0d9bc,65797145,7c5aad62,ea75753f,df9d3e15,efcd3ba0,285d3476,7f67ccc2,f0aa795a,890d9a30,6838b9d3,c64c1371,75b0ab05,68622b3c,fdc8d25), -S(6c02ace6,1f479fbf,11059054,d8dc5761,ca0a97a0,22e520c4,8aa2f32,448b7392,4e57f208,ceed832a,3626f347,f8a30956,13a17e57,b0159ca5,33143166,77b91469), -S(8a367826,e40db24e,28fe31c2,fe24151c,8e4702b2,43a99d86,5448d83b,cf49a6f,b2bf6c78,299dc024,2fc66392,cf6c5097,42a05f15,935c835,3944e66b,bbb87c26), -S(c1c3921a,14f64598,11aa70c3,f756e689,82233a48,588bdfb7,84348459,19125af6,6f7109d9,47dabea5,da858a4c,75ba6c3f,162ad404,15e7ab46,7247963e,8f4a1326), -S(ebedcd5a,e0f0005b,2eb70d40,4a1bd4a5,f0537c48,e8f6149c,c042f9a,773c75c5,2b7103da,d29bb9d2,c07def6e,1094fa50,ea70f7c0,4f609b4c,bee0d576,57e506d6), -S(bda6fac6,99e09a50,ee0131c1,efaaec6c,7cde205c,d3b55c83,176d20c7,80678bc2,881c023c,86b948ed,31a5cdff,8f3f985e,cfec9111,627d813f,177afa76,89a16f89), -S(f6d335ac,66fc71a8,319eaa38,3eeb7fb7,41118280,531434f9,cb0b364e,90babd42,b14c40c7,8846262b,e117735a,30a3185b,49f8852d,2e3aa8f3,3dba4806,ea7ff2cb), -S(c5588c4,fcaa5c53,79f910fe,9bfa1224,fd20aacc,f1efdb2d,7ba87c5,3615ddbc,e60ac5b9,fa96e150,57378c1,11f384bc,16fb32a0,a0482f26,603aca30,ed1315fd), -S(db88be26,bbab7b99,f0f20c61,40ac77b0,28afd465,aa4d1294,9011a47b,b1d87f89,e126d612,91ef9a77,e90a8522,ee6e7dfd,fbfbc2a9,90986da5,65919317,dd4ebd1a), -S(1150279e,e9c0323b,b122c2da,6e8b28ed,5e5b02a2,162067ba,67f5aff5,e99214fc,74d876d8,4d00e091,ef0aeaf9,5aefda58,f3da4d52,51b2b28e,cec41a23,4b420401), -S(1bfe1d76,43526f3a,e0799982,69f9679a,9a54f1ee,bdad1f6c,9c8e096b,6e771023,ad94d693,961644ce,a37ee705,e06b4b5b,32c17011,7aba021d,6cf48746,d8637dc0), -S(928b3e6f,a0e6c2c5,896f6eb3,972fe96f,7e446782,50d313d1,54ffd666,2b43a615,50f2d7d5,fa221867,3f18540,f2f7b513,b6b4875b,9ed4a5ba,73de7800,37f842d8)}, -{S(bc4bb9a6,292aa09f,5c66dc9b,667c4642,6b08211f,a9a80f5e,f3f17b,21f275de,5d0e0492,39a862ec,b9649572,6f11bc09,cebd9f29,d9407ab3,1603054d,d9b76b07), -S(bf330f50,a9c015fd,8ff93153,561ecb91,27b84420,62fadf17,3dec27e2,a5f7b0,931f0891,94aefbf5,9c530d74,8ccf5a5d,83f3fb1f,cd9043ee,ebf50994,d8ec1248), -S(33db24e,b1ba1a5,cbe2832e,50d877c8,a4fea4d3,e63d7c71,fe8cf9ea,9fcd1cc5,8b0db6a2,37555121,ec8a2ed0,e8f80dfd,37082a0a,883d3fb7,d7d2dbd4,7c01f6c), -S(eefd96d2,1d6639db,6a7f3a79,26f5bcd6,618e6ae1,70551973,7dfca216,565513d3,d7644dcf,e46715c,1821babf,5ab153bf,a80d20a1,252718b9,b72f299d,21ba7218), -S(48c08093,fc737bb5,70a31154,290f709,3467c915,c4afcf6d,ae372e42,3ed69815,29581f74,659462b1,3951d930,a8912e33,a2928e34,5e3563fe,f88b42d2,28af2f26), -S(68c61ae5,15c1ebb,d395feba,8661a967,162dcbac,5cb13303,9a354c11,ee217267,9db2d6cb,b3880ab,ddf58293,7f76ad7a,70fb1c58,d2eb9a5c,468331b4,55c5ece9), -S(99afe669,baf69344,16b388b8,30b97e80,86886c62,86870e7f,58d6efc,377ded78,a684a9dc,84881a2f,bc340b96,4180a966,d00aa5ce,513693e7,9052795d,74f08f7c), -S(3e893680,b103cb80,e6a4eadc,abdd4eed,6fd53341,d08d6d78,85fde37a,49621bdb,d342db6a,a942396f,76b79de6,a6d48943,2beb59ec,4d1d6399,9244bd1,731a6855), -S(e19eee8c,7206fe64,a217e60,c791c834,de7cecf4,3ae1cf42,b697941b,c556252b,cf79152b,76b0ef1f,abd36175,48701716,32ffe2a1,57b006cc,4fceb313,17be8fd8), -S(50d544c9,b3a10831,e325dbcf,6b13c6ce,a06ba82f,ec3e5b9f,9442101a,a4c64d46,a89b1cfb,169019ac,19785c9b,8fd27f1f,177adcc6,c9b995b3,43b373f5,cd82c9cb), -S(e34ff94c,729ca264,1cd51264,1eea2aa7,ebb5c577,71bd1900,86a02aea,7cc2c1b3,454dd58f,c46f61c,30efbfe8,49c7b2ee,b1a99bbe,6c8a4f6e,c0063a46,a1f63f86), -S(50a5b0a6,919974b8,14c10ffc,8c6233f2,843840a5,834ff5b6,75134ee8,4f40a716,6cbafa57,ec555bd5,2f656a95,3d592aaf,e963d403,40a7540b,644855fa,7c94c3ad), -S(b5f7dfc,438a381d,edfb576,aa62f2e2,12264e1d,8222bea4,f71ba06a,b2b6f0cc,396484f5,3a14cd16,58813612,2fc55f7e,89c4fcab,6d73e5a,fdeffadc,3c9f9b0d), -S(4e2a7b73,1bba01ce,68f4becf,34ab78b4,3c89f711,3214fc8f,ba3e19e6,a449b7f2,aa85874,bca558b2,e674623,3e0ab93d,4ec34eb,6998f0df,3f153126,93739077), -S(3835d447,f4da18c2,1fea247c,9ff3436d,bd60878c,dd347f4c,ca1168f7,ae189ece,df5da21f,f6a6add7,17e53e6a,ff0220d8,9b1e71a1,30339194,81bbec2,40414a1c), -S(82452834,e84617fe,d7d32149,6abdcc54,2af5fa13,8f55faa7,c2245cdc,48c89f06,c01d6da3,96b923c7,290dbd1a,6c16a69d,8a872638,4f6285a,f589a0d0,20e892ac)}, -{S(c8e595d2,666f4913,1f375b67,81b9113a,d0760e5,9477ca17,8863828b,307488f0,a82cf2a9,d823af13,5c23a04b,bc12dd81,2c352a48,27e19030,8e089d9d,9c316596), -S(26da38b,1bfa8363,6be480cb,684ee5c,70957f93,7f9a2d57,3ec75396,bfee49fa,9763277d,f3c228b8,515bd08e,b29dffcc,eac8e3ae,786a9655,5fc1be21,cdd20d47), -S(52063926,34d12242,b2ff32c7,d0a8bb47,fbbd005a,bf7f92ce,78808a5,7b1cbe55,d0cfa8e,49b45823,881819ff,fdbb6d2f,5c65f35f,3572e13b,ff7af252,95efe81e), -S(af61f7dc,8ceb2277,db16412e,dc469b2b,f0e188ac,89c72bcf,20654379,716115f7,524b9b25,925b793a,8bdb8e06,83cdb414,db0f6dfb,e7e06274,d61ef87a,13493b66), -S(39e53a5f,f553d89b,dcbd6688,9eabd7d3,8c5fc6ba,24618d98,88bb6e42,92658f06,ae8439bb,6d32531c,45ac510e,20f1c7d2,b8dc70a6,65c11f2c,cda73603,97c6580c), -S(b687e250,531efb00,f7e12690,659bfe25,429ea2e6,f1dec5eb,74bbd1e4,89a95e31,1033e5b7,9c0adb6d,c0f12ff,afc5d81b,54d7930f,f6190dec,737bbb3e,c4c774ba), -S(4c17f5ec,34cdd368,dbb62f20,c3b86483,24e99e0e,95a7e624,64cabe76,222981a9,1e37e3df,b690b574,a11c9803,f1cb5618,ce4a0331,e17c5cb5,4873ed6d,de217019), -S(bb7c4b21,77b77a9f,8f78c2e6,25bb943e,9d05dbed,abdbe02e,497e5dab,c31dc477,a5f38fb,7ebbe67a,869b90d1,aa4fbaf5,cd7173b0,46cf3c5c,b31a272c,c0693c82), -S(3b18ce78,6688a74a,7256c067,a412aa59,45fbb506,fbf801b8,61734ab6,400744c8,d4f01881,47809cf6,5226529b,acf6e81b,7fdb609e,3eee050d,ec0f3140,2308ae20), -S(b671371e,2f0b770d,af8fb77,6a64948c,1481cba2,afd1a3c1,bd233946,e34c86af,4a58dda7,ee794384,496c539,7ccfaef9,fd75d05,c551e26d,2ac631e0,3d124fec), -S(caa559f1,b0afb30b,d62ede02,a9e28a9d,8bbb437d,e9a8963c,37e25898,428b845c,f73a14ef,2078cc23,92b99742,9dce6a50,5682bdb8,c2b5e587,31786814,9c777411), -S(2676f258,a761c508,5176ceed,a95cf9ea,4d6640df,a2c4abc3,e4954225,c23acf9f,fdc42fdf,b1636050,67786940,3aea320f,8ec1e8fa,b9033c3f,2b919f50,fac0271b), -S(ce17ef68,f6c7b456,4cab6be5,22495389,874f296e,b62d552b,6d621607,192005e9,94fd30c8,71add5fb,5161b468,ab60d254,472339c5,2668437e,7e172ec4,957d00c3), -S(42fca34,df3ec118,417d8d18,4e507f2,91d402aa,32c00b5b,a1dee38e,7fb0cc35,a046e52a,fb7eaf45,bb3205e9,56e0e780,977bff46,ea65633c,cb0cd2b4,a3aeb2aa), -S(99926617,c15dcd0c,95ff4903,ed9d6050,ad0e1982,84a3c9f9,6a24ed55,45641b13,64437785,afc882eb,4a78844d,14d79cc7,cead217a,3cdba8e8,473374e3,4d416b56), -S(3d4751a6,99a8e88c,aff3daf,3ddcebb2,63f0d56e,6d305245,4c16b0c6,f80e0d93,162f562d,32595699,172a5c6,4ba2dd35,11bc5430,f21495d1,2ae9f6a0,638c613a)}, -{S(49e7429b,e0d97bf9,3f17e9a8,53fedb6a,a9bc6edd,8e85f44b,9d2f1469,b2d3b178,ff9e5dfc,2746679e,9826039d,578bac31,c08fbaac,a075214c,73c50f,74568fff), -S(1d1c9798,3eef36d2,75478b94,ecd3e172,a39e49c7,1c79f932,2077f410,e1a9d0ae,5d8d6ec8,aef80d94,3e75ab6f,68408d84,6cf94216,af6e06ef,dd7e9e72,4abcd7b4), -S(60f8ca6d,1d60f524,8d582e8b,ea2fb8a0,dd2ddb3f,49bedc03,5d24973e,aead0b41,7c4e8b11,b0e8b135,bedc60cc,fd540dab,da868d50,78386aca,117bb71e,e108fc51), -S(c6f57fa7,6d2ce583,415e0366,9136b21c,725126e,56187c79,577949d0,797e196c,2772eb6d,94a50849,e58cf22a,eaf1e35d,6e2bf171,f180a44f,42cd8659,41ac2348), -S(3766f2fc,83c96803,e590fb7b,ceb842a0,8cd5602,e57cd00b,5a6e340a,361a7daa,ee3e9d18,da86e137,27560281,8806fc26,199514fb,98c76526,54c85842,649ed048), -S(20de0b0a,6b2200b1,a89499bc,5cf2dad,7dbb6c2,e9805259,21c5e6a7,29c40cff,b680c2e3,33083337,3fefd833,68986b50,d2a28319,9912a092,fbed8b5b,1f22663), -S(d2f06c3a,add7cdb5,ac606876,e4093fad,8c626408,ab6e6dd1,ead7ec93,4e0a1088,990df428,517d791f,ad749267,7666dbe0,6b71436c,5112295e,ab7bfb74,b4cc89fb), -S(c583dce0,f9c32b0,d8c87a9a,dc7dd093,d12037a6,ec162d5e,22ba72ff,beae41e1,d9390ef4,9f7f10fd,7b8641bb,f2ae8388,ed08cc19,3d1e6a13,81d8c198,42025aeb), -S(80f61ba8,a99d2081,f0652a9e,a25b8d23,716d55aa,c9355891,9a4b4d43,1e967f58,b8df023e,56eb796a,e70296b2,b47dea6e,d74ac4b1,99fa132d,c9c464f0,ddac27e2), -S(4ae1535c,dba6c272,6e78dae3,bc651f16,cdf6634f,95584886,899c829e,df12201c,ef66789a,13b7244b,ced52d30,c9af6613,55d66a9a,9efd3a40,703d38bf,c69c7c75), -S(2143bc02,b46d41b8,766db211,61ed21ef,5b0973,b7cebb00,beb89b71,4a6e16d7,7dcb12cb,137dd6e6,96791345,69e25e2d,57cbed88,ce39aff0,3d57ec3b,85160fea), -S(5c0b84bc,ca8945d3,a2356c68,afb8d1e5,d45357b6,b37e5afd,c2b00e6d,1f6c5eab,1608a492,bfb97a7e,746218c5,f673078,c70f5880,de8df87f,8aa5bfb9,89b43ee8), -S(f6cc5210,fa45c072,cb95e88d,ca93b9e3,f7b35e98,13c29976,2ed9364f,8c021e3,ae959f0b,5ce17592,5046e320,f86d9751,a6ec37a3,a773e5ef,c4681ebb,f5aa1baa), -S(d4df71da,5f272934,8653f60,bb02deb6,c314943,f50cc5ec,e4974ace,b5b4d0ac,17caf288,b3286dbe,2e8d0616,df592027,baf3e59f,1e52fe51,9644cf5b,66443c35), -S(44e8227e,177bb9c1,5aab6cd9,d987ef1a,af087d4,bb2672af,1a8d5412,a7d6cb59,4b9b2602,152e1152,92fb191f,2cbbec91,5ecea9e9,ed75121d,5cc7a88,69527cd), -S(97f092f2,75d1ec04,96f6b14c,10a280f7,25c9e4a5,d16afe2a,3f0837b5,422bc5db,12f04418,c131046a,e5c7ed64,f69d6a8f,d3a3d35e,30dd273e,72ff16df,a866822a)}, -{S(9a1db7bf,53241ed1,df8d3ea0,f70c0b26,76b43ebc,bcb4622a,9704b0a,3067400a,e3638ad2,95740505,455b2e1e,d495c57a,54ed8e8f,c647a6b9,c69b7dd0,715cef52), -S(5aa4d7d3,745f341a,c2869a8f,ce1e2a96,e25e49f7,1e5cf140,c0ad884f,47d8ae86,9f03a2ba,989bd4b5,9361448f,abe607ab,210d3887,8da85782,260937f5,9910d8d1), -S(91910df2,7ca6ab42,17ddcf1,d7efbfff,e69eb9cb,24a6648e,3aa7d738,c76290f7,e99691b1,d883491,e79e957b,4c65f975,601aa5a3,b056ebbf,abea6c7c,d7b9ff2f), -S(b5b7792f,99303195,4024caa9,e08bfc16,53f535fe,7bc3e34c,8491864f,74f48799,6cade2ce,595b6714,5d376b7d,7b435a3a,76b15912,6340f6aa,68ae15be,26a159ce), -S(8b54ad71,6c724ad7,e47e5efb,e6b7c93f,8923e7fb,8517ce0e,6f732486,f37ba1af,fb8aa95f,4a6e3522,371cdaf4,461f4d6,8a45481c,da065f7f,a697487e,fb8ea80c), -S(b4896855,b2614337,8c5842ef,b7dfded9,ba6c80fd,2eb154f7,e83c4734,ed7dba2b,30e20644,fd8a9a81,9c622641,b525647e,ae35b892,91410141,1a5df15d,36c4efb1), -S(5bc3cc33,89816b7f,414a473a,2deae3e5,ad3e7803,b7532f36,d2b31598,7c35d6ab,4dfe0f94,86d1ecf9,7de9b0a9,3e437f49,c015b9a7,677aa2a2,74868a4d,512c2ef0), -S(230bee0b,5eaaf145,f18ec782,1e861f12,26cec876,a50ac94a,4a88ed64,4a3f7d34,331778b7,d638cc22,269a7a3e,abd0c393,f7e08d0,dc761da6,25b70b5e,14f18c26), -S(8f55920f,c479e736,3000b33f,ebbb1559,d41a5873,93429368,78a6156a,d476b8bf,94fbaab6,7a49ff13,2435b28e,df7253af,43420841,b721221e,b5606a48,3061e441), -S(d64edeb3,709907c3,761afdea,f9b431fa,7c0d5912,8a603410,39e89346,1561b7fb,d64ce942,eda3a553,82c22d7e,f9b20c61,ba09fb35,4401fdda,c054e891,15134b9d), -S(ab22f920,a97eaefa,25e46069,1123f499,7b3a78e9,af738ad2,266c6c98,4b5fb63e,27f41b98,a05a5599,eb82b0c,37a9a70a,f19df223,5254816f,1b9411b2,52b77d), -S(3a409fc6,f4a19839,c6bd2187,5e2f9b1d,5e10ca36,5711a0b5,67084612,ebe049d6,21006d4e,399d55a1,6a7c136e,b192543b,36e73785,36506555,e9c5fea9,3e5bf265), -S(57305b7,7613e53,635ea239,c9e35edc,1a2a1680,fdf58358,93cb226,c0f11f50,b3316b71,954f5a14,acfe28bc,9e90c27c,715204e5,9db9a74e,a5b5cecd,2f43aef), -S(d5c78499,3727b6d6,18bc7b22,4b1da72b,1cd9122,81e8e58b,cf2dd698,b400cfa2,d1aab246,fc2da7be,de9d90cb,2c438d65,310b4785,ece43715,dd3a1a65,c8abca8a), -S(13a05a02,7191a7f3,eeb453c2,8b76afb5,150bc141,20b90f50,dbd0d218,15453e2e,94ab710a,3736322a,ed6b4443,abcdce44,a8556a3f,85f9d3a3,701dde54,52aa3927), -S(3e6033fe,9fc41a9d,6037d9e7,ef11fdb6,93d1af71,237d3983,2da15f12,aa080ff5,763af526,e9187e31,89955a60,b3914307,99ed7de9,e41b6c,39d8ae8,748af8f7)}, -{S(50cd2e16,997d7d45,98bb2d9b,61aceaff,5ad5f38c,8286a0e1,d08055ad,726c7800,dd19c3b,c08b8d97,88f9de1,5941f5fa,6402bbbb,5fdc708b,cfc08844,eb23733b), -S(4e83070c,e3eba290,c6cd520c,dcb4252b,9098270a,55fd47fd,eedf36da,b1706d47,561a3822,cd94b2a4,1f30bac8,695e05b7,69de8ae7,4241d2ef,f084922d,ccaf09ef), -S(4cb0754e,6863546f,afe0bfa,edc94c15,6d9ac68e,db700281,2a24933c,a0a30401,6cf6ab8e,306e4400,427b7820,52534566,52d2bc98,2510c84e,43b4ec61,3194c402), -S(a3689f89,d4874967,1b205a89,8e6c092a,b0cdbe2d,f1530bf1,99201a3a,6b0e3da5,5a58acbb,e6ad1676,a328e193,30c3297b,81e52e9a,4abfcd4f,7e0bdc2d,543bdf61), -S(79617bb3,c57e2db9,b2978984,2544e9ff,61055023,80faa2c1,9db34d60,b6cc0c8a,e63a05be,be1da5f1,b74450d3,60092dba,29122671,6e07280a,d78a1f17,5daa191), -S(6a474afb,415121c9,38c73c20,27a5fc93,f7e8ea81,d7df1144,a50b1c66,5be0d8cb,5c643389,af9fd383,b7d71966,d251dc20,db8b0d22,8aa94a04,289ee8d8,247877fe), -S(7bbcb86a,ebb40626,ce142507,b8cf0801,2f706862,7a46c76b,fb8eb115,be4163ce,b18769a0,735707da,4b1d7a1c,7690f190,2a3a1f30,67d54f8e,188f8a41,3826ade0), -S(5caeb262,447b4224,19f66418,4899762e,2e2a6b9f,f8aaccae,a29fc3f4,68a1b645,b894f2df,20dec514,2792de69,86a9582f,d6e1e3e0,fd97c5e8,9798624b,9d6e2236), -S(a8ec4087,e144437c,3acf2ab9,3f339415,74e79f9f,cd48bc47,cace25b0,4d4e451b,ef3ce687,12f91e5f,b38ccc98,5c0641f9,d57a6ac2,b72f8814,3e85e128,c7012a4b), -S(724a5b27,5dc8ff8a,e10b34e3,5d05a592,c50904e3,32153a20,78809bc7,5d69ed79,488b7096,f471a9f8,583a9b68,3119a211,6ede4c52,bf817b27,123488d2,9ecb8328), -S(1d1ab819,80b10336,75e10627,b7293cb7,7f31cd83,ad1a043b,ae9aceb4,aa0a7463,cfd42f33,c57814a7,acbb3f08,dd882a4a,c572412c,8502e82f,a3180452,7d2e0151), -S(98b12e59,8166e430,ea43d632,f8a4b981,f3745420,6d1233e6,f9c8756a,47dcf4d2,4f65841a,b8f18241,a46eac62,b875173d,350c78da,6d6af3db,d9fb9bbc,77f33b96), -S(58dab35d,9ec4e48d,6a7e619b,e926ec2c,45f67be3,3d89bde2,38963966,c96b3270,e5d0aaab,6191f65,e6340837,747339b5,acd35b86,823e06af,85eb54c8,7f926564), -S(41dfb55a,cad77bbf,80435b8b,7f2366e3,f41e64f4,74bd9895,dfe86e8b,50abfb83,147a71bb,3809c321,d960ef5d,9f767bde,7873efa5,c590e799,db46d8ba,8c1dd2cd), -S(d739d1a4,72dadc,eb59a120,3b8de564,5d5c1e1c,5ee96ebd,533442e0,de0c8684,610f527d,8cc0ddb6,cb17e24a,51aba4ab,5ab0d8aa,9ebd61c,5d26cf93,30a18293), -S(f887ab66,ed92339e,8fc9d8ea,1af72d3c,6426ba1,a8be283,e2457a97,342dfb4f,94de30b5,4e69b56,fefae855,51fd5a5f,111671f9,c5a733f1,1ef7464d,88d5d66e)}, -{S(4bd266bd,4a730879,cb06d8dc,bd8e5854,c50b6221,d83e0a10,3afcb2a9,a64cca67,a4654a1d,835a51f0,5a877200,1768c549,909212e5,78e3b1d1,df935959,93650863), -S(15fce59,bb77b091,90e5c39b,ae696127,4d51068d,ea51ce52,6c8525e7,b1ee3d1e,b55eb928,92ae639e,da63a4a6,f14fc6f0,ee2450b1,94df32da,9a1004a8,699797a8), -S(d3e5b06e,7648321e,4fe95ed8,e1316474,43996e1e,2cff5283,26783ba9,1906cf7b,2ad6127a,9e45be65,26ccdf8a,460cd441,cebb5689,9f3cfd41,2aae39e,c838b2c5), -S(114032d6,8e474d1b,a9fc40c2,f22f5b1d,6d12b9dd,9cbc286d,38274501,218c54b7,9dd3d787,706a063,c0d81bf,d1cecb6c,b7b5b446,6d7c955d,22cf05e0,822a9ef1), -S(a230cd33,6bb82fca,bee35435,dd0d560f,d286785a,f5425cd9,a4c9abdc,819e58c,57d99f9c,aef9cf3d,fa66dfb8,bedeec77,e21746b4,27e4869,39cdd8af,5a9182d0), -S(593e3646,546aafcb,fc8a293c,6cf0530e,5f1f2639,2f3ac2b0,b136583f,2981e8e,15c4b596,6589f9eb,5fe0d0a4,91e768ad,fc7f5283,875bfcd4,3b698a3b,4f268b43), -S(37729a9c,3ad25a03,e1cb6fbf,ff486df7,d518809f,66099d27,d203dab3,3d33dec5,dfcbd1b3,7905c99,21269ca,283405c5,208ef5eb,e96c0801,f8868631,69ba2c23), -S(46d8c723,f0b889bb,3272389f,ba3ba57e,d30d701f,7f730d0,c7ebc34b,8212cb9d,bc41f981,2017d9e1,1e4e2277,92b6e804,6318776a,d552960f,c751c36,c6d00a2f), -S(fe29d8c8,fd38be9f,c316c2b5,ab74dc69,ffbcc390,1e59df52,66aa345b,6b1408a3,338ea0c3,f80e4400,53858842,936562f2,8b9ea4ea,31540868,11e87150,89e9e304), -S(99ddf18d,cc6505b3,78a4cbb4,f45bea9e,44726ec1,cd51397a,d536dad7,b1b3ca2f,fa8e8ab4,b6071958,c237e5ed,5e0c0962,61825572,3411bcf9,8e923b1f,e748ce4a), -S(14c9fbd4,a0fe77f,1f518efd,13dd7eb0,cb7695f8,219db1be,d4e76fee,813a34dd,991011d6,f67f3e84,a54c2357,9897dff5,f2a58cd7,40bffbf0,a876a611,535f2540), -S(3cc95333,2788684f,bbea85ee,f49a2ae7,51d5e29c,48642a5d,45236bae,a122e5dd,2ed99469,8084af0c,44e7c819,cdeaf311,72f08aa8,ee70644f,ffa2dbbf,bf9c0bd6), -S(9fd0c95e,f60c6831,959f2b44,5a15a366,6463425c,3a64d213,b014edad,bd22e711,8bf7b7d7,50558a66,4481df71,2c14fe8c,9411d8e7,13fa61f0,fcaac1c9,2c1990b7), -S(b23e3552,9d02bd4f,bd847080,a5e9dc69,964b324d,e16af0a8,857f46e0,ad9f32f8,f3b98226,f77e4393,dc35409e,69269fe5,957a3e74,e5e5d7c1,ec11c4b7,3f5ae025), -S(9b674b33,b7bac25e,88896436,b6c80dec,be8cc797,fd34603f,a4007318,415b95ab,50811d7b,bf49c464,de0b274e,2acb4dec,5786043e,6bbded6f,13d0e131,c3b223ea), -S(2cdcffd1,ac351cd5,21216262,9a401b63,2f4f9c64,9fd0e250,2adbd66b,3a0855,54ca3d4b,6043a79a,66cfb5b7,37127ee5,c0a3e0fb,a4214052,6da020b0,c757f73e)}, -{S(217de5b,a47e8de,cb9d8dc3,dc8fcfd8,203c514b,b9d7bb5e,fb03584b,aa1baaff,c77bddc0,3af15e63,912e51c7,19bd8186,67f999ed,9bd801b8,11bc289b,f12864ed), -S(799812b7,d79876fc,7290c3dc,18fc6ea7,1d224373,2e79d17c,9737a47f,29fa8502,4118e843,99b5d024,a82002f2,7e791cf5,badd2e5d,98ae1f30,6d98ea6c,d1d9b4fe), -S(8be7f251,78840efb,df56c470,c4db43dc,54bae1e2,7cab2bfb,c7a6641f,e34f00ad,6db39ad,c7ad2102,90c29073,e48225aa,6d51f27d,d97c0b0f,e241f9fe,dbe1564), -S(bcba249f,59646b10,4f6aba48,1e886117,be0fd815,a6220e4f,f5a08eb6,ac16c612,e8d84c45,88ce9926,99b2d6fe,5ead0615,4b32a372,209e06d0,c3d8c42f,a0e22b86), -S(ae1a61b5,deed4d8a,915b94ca,72aeddbe,2c725ca2,86311610,476d94e0,73fb1415,e1f62c42,efb2da24,47b3b5f0,834617e,e06078f6,78ebf4a3,d38c45c2,f384e1b2), -S(a1e069e7,74cdf680,41c5aea5,39552c4e,bfefd4b6,3869db9e,c5532b09,e8370996,cc1216a0,cea149c1,f19ffcf0,eea82fea,29fa7f3e,b19d5eb,7307904d,a38652da), -S(e6433844,64b7b1ce,bdbbaa01,aea053cb,a36e0cbf,e1c9a652,8c714a45,6b6b66,22f16bb,17b781e4,47fc81d5,1ad5ec9f,c158b069,7c446bdf,52da86ee,6b4ebe8a), -S(accfa38a,10f8d4c2,f8342e29,272f7c54,73d10562,82653714,8b67a26c,5735ab9f,ac0e6829,1043396c,be583305,106514ae,354532ac,5ead4594,dd5a6d4e,332cec1e), -S(d201c17,a1e9efb1,7bc1c655,48c100e2,450614aa,b45b8125,9f2f7e31,4cfc924,4677a168,1eae4650,5c5d6c94,a6984480,43f3793d,ab496ba0,ab86064e,8b48ae23), -S(6612ab47,b35d942a,98427ff,ba59b78b,fe44437e,b87442a7,794e3274,89c3b335,cd540fda,9abe6c72,e298eddb,6d8c5a3e,c0953eff,4a61cc54,22d01ff5,f7329785), -S(35b1b6b9,ce9d1a9,802dd987,745c615b,87a96a83,d1b2465c,cc9f82f0,1c73571d,eee3f5ce,aa7961de,dbb80107,36e6758c,e9cc8b0d,58a6dedf,ecec9f2c,7a73865a), -S(c798e22a,59e65aa5,6647a86e,f9a91e80,98cb97e1,81e07b4d,c3fdd428,dfc3b1b2,45f881a3,1b10db23,ca93210e,22398cf4,81a6a61,6496fb5,ab82b456,7f99a392), -S(39d9dd1,955b77dc,4f4d7436,9d7785a9,c8ebfbc3,d359f15d,8d38d8f3,1097a2d2,64040f85,819c8a31,94dc8ab4,5d794fd0,dadb6826,70de6629,5afaaa1e,c669126d), -S(a9168a3e,d48f2332,48bd4a53,dd37e37b,d24b6284,a2522671,c6494bf5,84738bf1,6ec107ed,6f749a16,27a57227,4d7bcf8f,8ff71417,7d38f6cf,64040ca3,3292bf65), -S(88b92b0f,67c3524c,3d7b04a5,bf539b2a,a244f3de,64867754,bad51192,292a6f3,f65e55f8,f9239573,d77176ae,c976c545,a0e4668f,8c2f2fb6,cb2499ae,94af11ed), -S(6c7ef071,c8f4b0cc,67e66561,38d5354d,fe5c9edc,5cea2eb,a43a5751,317da5ea,40894203,7cf76552,33da385d,43e1bd8f,cb871737,c4b7f044,a44042a3,34d4bb6c)}, -{S(761cab41,3916a1f5,e131f337,e9023519,6199f789,87ef390b,3f2d8bfa,b0e9bbc6,f10272df,f7e91c40,3565da85,17fd3011,bde7b797,526d3c3,f00fb28e,f26dbd91), -S(a6bf4e6,9cb5faaa,8b1308d2,da8e2ada,516b5f18,733156dd,2de04cb9,ab1b0e9c,b84be8fd,2ac4b2f4,2934490d,2c7de2a7,8be093ea,907bab1c,94681e51,3ba7f4e3), -S(4d280f0d,190ce936,11ad117,ad7ca092,d61fc8cf,db1fc752,5788c7d,9cc97535,f20a17ec,c8fdbfb0,2db3b21a,acd35527,25a7aa8c,d20a6e23,bcdeca87,a6fc2112), -S(fc0fecbc,c71d83d7,c888c451,f862474f,2538e8a,800c8a93,f4c30be8,ef98e709,3e809271,356b87ad,87d15888,26b055cd,6ec7e44d,3c9e404c,a27a473a,8cd093cf), -S(c3746b0d,f41e4a85,be3bbe25,c1d64961,f80ed512,8ad3c3d6,2cc5b9f9,b231dabd,382a6d3d,d970f8d4,abe3a72f,58f0cbd5,33dfb21,b92571e0,19a0ed82,55974b77), -S(e5749369,b1e25400,2927cc8d,3b15b5a,dad570b2,cc6ab264,a8af3de5,fcd9a458,38cc0e66,e5b86153,1b8b7aba,c266235b,fd34833f,9b0a18ef,9ac361cb,407d774e), -S(d3463d82,782ece5,999dee44,cca08ccb,1d908f11,7f19d0e1,93f42e86,505470ce,ebb2cfb1,f948fa0,4204c39c,cd3c12fc,6379418,33e9ba07,cd714715,268e8c85), -S(9c88be4,50bee26f,14afddd2,80e247c7,7d07dade,81c55945,4091d1a5,6acc28e1,1a943839,793d91cb,865a3213,4d4ef1cb,927a90a5,e9da30c6,c88d72cb,1fef79), -S(77d8a57e,81ff4149,8703d289,c6d2d6f,209ba69e,99350060,d8e53d5,eb3709a9,6b692bad,ab736bc8,ccc1362c,24f05260,5c3d2b0,23deacf4,641c56f5,c2b79fa3), -S(64ad7f39,a9e7027a,51eaade,8ce6650e,2141e655,b443fe8,f67afbf1,7c970189,a730c9ce,acb21c6b,ba834441,9f417a6d,47ca382a,904e432e,3fc2235c,222acd1b), -S(6f1c3296,67d9cbee,7c44cdf,e5614882,1ab9ca61,1731c1a8,28520698,7f94609,ecd182d9,eed899,f9b8e5f4,71e5805f,ef716180,b8d1499c,82f6186,d09a0338), -S(8116e0e6,75ee5fe6,f0bc86c6,c3830977,a4432546,4d027eba,fa242f13,abe10e55,8cae3d9f,af3e4b04,f9555752,74eb60b,1ccd5f10,8b3e52e6,47871a5a,1671fd), -S(1593b19,7dd26cae,e667733e,d4b564f0,ff212f26,1bd6e81c,61acabe7,37b62f8b,3c9d3e7b,52301084,7a5c2f2a,39cb68d2,b9a88605,a12cfb39,fa790749,7107b746), -S(4bde92f9,1335891a,1f40ff,e4310cb4,10e2b172,27223f80,672b313a,184c9a26,c24904b1,c5d83c4b,31748a87,576880f2,73719ea,4413f945,e8233811,5282347b), -S(e04ce78e,b61966ca,ccaad985,376f23dc,7f4e5c22,7bbba119,a99911cc,b7fe0674,f5e3bee,98daaa6,1f45a2de,6e95e919,68f33ecf,4a71be8c,8fe5d925,92e43989), -S(e30ce87d,35b2a79b,ac96ede0,c3b632e5,506b5b86,22a0c483,c4a6038d,d846d191,d92e324c,c5d9a340,e69050bf,198063b5,e4fddd9c,a3e466b6,9fd00831,3eb13453)}, -{S(60b01067,25cf781d,e78ba725,40508697,3f2ff6ec,1511515,6e19384,1fddda7a,624ccf87,f0ec21b9,82efbc4,6d4db878,5d20fb8e,dfe663fc,46660bb7,98c96eb), -S(3e169750,b508233a,580f67da,55ddf909,a6bdedb7,7a7c8a6a,ca262be3,d6e77a93,d8e9c3e8,733dd591,722f7020,a361b2da,e6a4e71b,7001f1ca,2ac8c89c,1b56fcae), -S(a502b4a5,7f7da399,710ced24,5452f975,314b44c5,2c6c1625,3e4c183c,d53f18b1,814e29d1,67240f5f,2a7a406c,bc0e4980,69def56d,c7e1c16b,2a67a903,59400c37), -S(710d4fa6,d7e2ef8e,373a011d,f28b2a15,88e9810d,c1c74a69,3b3e5de6,4bbba781,c39916e4,231ac0bc,90d1c25f,6768b4a6,cb3efcc9,99b42dc1,27065953,bfb3b307), -S(9735e24d,98430f34,7dba7882,9de4888d,1557f650,ca2ae2a1,48394c36,9b4931ae,9b5e03ff,c52da7a,4119c4e0,c86aadc8,eb3172a5,fc430cb8,ac121fd3,d2949b02), -S(3eac990,f2b5a7b9,7ad3c31b,830576f3,ebe86f15,efc78a0e,ce51e592,190710aa,2e75c1c1,786110a9,785a21c4,d72576b0,9fcddea0,b1828f8b,4a7eb45f,8d0f7081), -S(a797ac71,b5c615ab,52e5341d,5420684a,7ed20dd6,b7cfd205,2ef23b45,7302d01d,32fdc8e5,eee8870e,6bd9ee55,821bf2d5,30798606,85f4c9ce,4534b4e1,525e782a), -S(e9b05915,1e029c34,7c30a260,138378e0,a609051c,33b2da36,3dce9dc4,19b2deb5,5494d79f,9edc31b3,9259c82c,14f6c757,be0159dd,c79a8797,95af6150,484d8683), -S(8ed4c8af,27fa4013,a9d9826e,becd79a1,30cb2014,96e583d2,e2d80eab,573a5eee,4bd35c5,cf78a79c,d5568968,fb1043b,c8cb021f,b5729faf,509a09d8,b82e10c2), -S(14230106,2f11cd2f,b0e8abe,5a76a7c4,2eb3f019,ab8503f3,afa0bab4,487a4928,480dbfeb,2b36a3d3,4cdfd029,dfe3a42d,6297724a,15be840b,ff197fa6,ef5f594a), -S(425fb125,e156d90c,31dea3da,6ce5f3f0,2d1d78d5,9ec17c65,e89c3817,d10df34e,2e2a12cb,d621042,8cc2ce77,df2ec8cc,ec1a8a8a,9a2a2a3d,b537f1b2,13ca871b), -S(b54496c9,57e6e359,88118db8,26be100b,affc546b,511aaa43,6be0f72b,2072d698,4174ec3,ab8c5709,581d797a,831c341b,131d94f4,25715984,7c6b95da,e42d6ac2), -S(edb85684,1b5c164e,eed9b5d5,740972d5,781922c,e9d365c1,24475785,2d4c6602,56eedd35,dbb97163,df4f95d2,dc106a63,114e3f44,1cfb2d74,c57a51f9,87eebfba), -S(de82cea,e7a0a2c0,32db9642,49b47662,201721ea,754aefd5,b304d7cc,ab3ab426,8f533e0,81b88901,ebcd8547,3ade77,776ccbe1,fb1d2ca7,b038c205,be8a915d), -S(7e74f42f,e8d3e772,43d11177,ed249ea7,2e87ec05,cfb5af22,2de3120f,22b8214,2978928f,ca85867e,c9563f6d,5e044fa4,2eb480f0,e2ca86ea,acacb1d6,66bfc426), -S(995857b7,8066f2b1,473eeacc,fadafb7f,36fdc5d9,1ab5fd0b,3ac55be3,91935876,631de25e,51831901,aaa62ca9,391ae54,7dda101f,26ac6fa7,3396f885,3b9fb916)}, -{S(a707efc4,89165c75,7edcea3c,ce729b44,91f04142,3fc6ea9a,704f52df,c8a0650,f2e7657c,6c618494,c01c5a90,d06b625b,c9416d63,f7b8f809,dda5076f,74fa2c92), -S(e670a33e,75e7d765,9dbc17ef,a0466808,3c57e661,975e8197,84ed85c6,838bdc7d,df5e73e7,4a1f7445,d140fc7c,eee1038d,333590d3,6626d5bd,bdf399e,9d9b1843), -S(751a8413,11be980a,5a884850,c9101021,393634c4,862d6806,2b1e6855,2fb42d9b,26a416ba,afadc235,425ce35f,d72e17b8,6d13228a,ac64f30b,5cab853c,1d80a1bf), -S(f044f2af,6d6842d5,946ad6df,43784921,47c45378,721d1e39,ccdbc033,eb0d07f9,68e474b7,e3b1a102,efecbe4a,a20134af,9f3ddcfc,45213188,744f7816,f381f942), -S(24208410,f23c4fd9,42fca91,94b5da3e,de46e511,7b0446f6,e92eae4d,bfadef52,b17efefc,ca0bb9a5,1544f8fc,15474328,84d79be4,bb7cc122,9aa5d66e,450c4849), -S(6aee88ee,18046ce,6399c111,2ed2e9d1,5ae30b0,663b75d6,a20baa10,57a0287f,44155fad,94ff97af,ff36d407,4f0273a5,adaefee4,e2c48bd5,bb1973fb,53d65d20), -S(b112113b,921501f6,208ace14,74cd923e,c4ed6cb1,1b1fbdf1,2786f43,6d2efb0d,d63f1ebb,f305ae31,2b0fe166,23a9cabc,b7c7b76,1e62c8a0,3eb2388b,5635cdb5), -S(74cc4471,707dd64c,bc0688c2,1d15d3e6,863adbcd,3b6a0a08,78556ed0,239ae027,43c03176,1fcf3c22,3a7e70ca,9e27690b,53f8b3d5,a3782461,6d41fdd0,7202ee6b), -S(a23a0d76,d391dadd,23e1654d,a654f0ff,eb8eb983,fb4162c9,a9956c12,fb77d5cb,66e0fc9d,311c830a,3a2229,fc4f82e7,43592058,536a9e7c,722a037f,f87f1363), -S(ea0c9f05,6e39f66b,5ab9f833,5c8e4655,f4ec160c,7accf824,aa1b5dbf,2fc1f8c2,cbffc05d,64ebfc35,7df2966d,a170fd7a,a5861376,f8d7f3ab,6c004671,e0dc812a), -S(ea4ba4c9,2c8b511a,9559c223,abb33c27,22cec491,e48cd519,74b3355f,4e42cb7,4a4db6d6,f426d463,4d6717e3,d3b6ab71,88ba832e,8a18a4e0,4f17a698,bae7a41b), -S(939ad0a1,a64da497,1a6ff2a0,a709c485,30d752ad,a954c8a,f632f969,95561aab,9a763429,5ffe700e,e36d1d65,f53ecbdb,92bca222,e5e2ccb1,55cf3a5f,c751149c), -S(f2548d26,ae82f5d4,38ac89c9,f8a5f974,4632ce26,8fa7f62,9446a19e,2f7c8cf2,7e584e28,b1590b83,31ae2228,81eb28d5,14ac4360,b60aff7c,d5061606,c5cf4014), -S(a4156ded,fa8d19ad,6471653b,42342986,74f4f87e,a9258de7,6ad54fa6,f3b986ef,ec77cd09,b77e2ca,c7b4ad0f,5e05004a,593cef18,6c57145b,3f9510a4,24ca5ab9), -S(12575248,e8aba15d,28a06860,b5a03e0a,942e33b7,e5099128,da2ee781,98333c51,bd3aa2df,cf99aa06,593a3c9a,3d22dee6,bdcbafd4,414a47bc,38916a19,7c2c2025), -S(b4262622,5bb55310,903f5f23,3b0591b9,adb2a909,e09cac82,503ee54a,64372572,997ac9a4,f1a21373,121255ca,9b622dec,2b4e7652,89731f03,37fe5d94,24402685)}, -{S(6efd8760,aed4f239,bd97a00,63794c4,ef14acc9,f5b94862,4c7f8b51,3ff35278,74acac29,694c5307,aa221b37,f2ea068a,a269fcd3,c6d85aaf,a8c8eac1,17d7f997), -S(da759133,159b8d93,d75c9aaf,616d87df,8f7dcebc,a518d4ca,da418b7e,39a264ee,8ad545ae,37548bc6,1702d08f,8de7a2c4,3b3392f2,3b44b186,fe1592e9,2f102577), -S(29bc8d55,faa61a53,643e8a7a,8f8c039c,bb808abb,8ec4a96,b294e4e7,a5a1fd2b,4a170217,7131ba3,275bb1bd,797809ce,cee979a1,d2f161b6,8b632622,2f92100a), -S(c15e640,b71ed510,37d92f02,7de2ffb6,3524e1c,208a6722,aadbffe5,977de2aa,b208b26b,eeeb6d6,1d783e21,35e71c04,1ab78e0f,96315560,d3729c6b,cf69c6f0), -S(9a738ad5,89e86d47,84abc74a,ad4c781f,72ad7fa4,91654392,510ae297,4464c1c0,234423bd,6b770214,7e157d65,e35cab77,62794253,c3e82487,8a4fe726,6105ad55), -S(3692b32a,5be3acc5,3320e434,42c8d1b3,235d0635,49a493e2,e4a33b49,f02f5504,ac61c2ce,38ac1b0e,7b3c5d80,ce988759,18e9ff5d,669f61cb,b285ad07,6d436ee7), -S(dd501ea1,3aaa02ce,619171dd,4270fda,aa164f14,c90302c0,5a3e10c5,bcafaf5f,20ba19c0,8561667b,d24c59a5,a812fb32,972f9231,19a4d42d,48aca05d,9fdfb61e), -S(f7e3ec26,257636ee,74eb2c22,dc9da3d1,4d6cd511,a6c34d18,a59e3d52,b2099502,a2a302d3,50790316,f99cd37,66e61ea4,8b9b3a92,eab54f08,dbd6a061,5f495eb5), -S(281dac89,3afdc45f,4dba86a3,fc5b863a,23f55d97,e49137da,c7a31f64,a0621a04,12f9a757,c8ebf05c,8bf34270,77c6d2fa,852aee99,af3d4ff0,9c6522d7,5becb9b6), -S(8de33df6,91ab87b2,9e36c69,687cc788,dbe100bc,8be07786,892aae4,e44d5834,1a9c323d,65aca9dc,8a11b116,4fb2ad88,b8625f61,72efdcab,88da47e0,7cc74bd1), -S(f2b7d303,6342168d,75c1ab90,c7045095,d8f415cc,96a86154,97425cbd,e4067750,ebd266e0,7a10d930,80241d0a,218eb94d,51596e36,953ae60c,25fff023,25920883), -S(8148dcc3,da9ce438,7edd33f,484f6bc3,6ebf7b2b,5d5c88af,c22542f8,5c943a95,591a62f9,9796dd71,cb18f64a,8e30d6e,9ab8336b,e9c3a684,ecf891c0,3c6e836a), -S(ff688510,eccb5b50,957de634,e4324f21,5cadab7b,93bf0dc5,ce94736e,a93cde8a,37d46d44,e61fc958,6b0da8ac,2023bcf5,75f8a9c7,9d30c993,e3d9a650,764e1ce), -S(eeec9568,1a66969a,e524bd76,580efde7,99302202,16aa7549,d39a98b2,59d717e1,64c4db73,487b23fd,ab74b50e,53fc8d1d,336db703,444b5844,b0d8756b,b84c289c), -S(3b2616e9,b51808ef,430e714b,ceb9a747,aed9e31a,a9caf6c3,d57c1565,cd9b7f88,e6b4bdaa,aa1ea551,4af2705c,47f07417,b2a03bef,2b406760,e86765f7,23cb0438), -S(5f0eef38,c87db43f,6498709d,48c445a1,ac50b40d,f882ecb9,414a56e2,ec927ad0,8197f585,73b0c534,49c04d6a,b0baca10,3c97d9c3,9a61dafd,fc793c5f,df7104af)}, -{S(2def7e67,7906cf3f,3677e7b6,1b0a8f8,985fbd9b,23265ea7,18a5c16e,139f0a8,650a89bb,df8c8326,d364fae7,558de827,a529780c,9b7bf8f1,c6925632,7c59c74c), -S(170634ad,de4863bb,3090218e,543c310e,9bef094e,94003fb7,5f89b076,757f8900,b708e4e9,cdb53954,2bd573f6,eee4774b,ad2cd18a,ab0b0157,dd1d3aa3,aff70dd4), -S(caf1623e,21907368,7d3a686a,7d48f9b9,953fda37,3f68ceee,66b5647c,ba9ac0c8,95ec09e2,533a173e,1773b047,a0702977,3167a96c,c7a2bb42,74ecfd4,9b1b7948), -S(dd21377b,234e31e2,7a42e856,305186d6,33eda53e,5bdfb93b,f83159ab,9cd37bf2,27a40d9d,9bb0437c,c079c24e,e3a8a10b,c54c8af7,6dda2e35,ab61e260,ddf6feaf), -S(5d6d3e69,3865d2b8,4c0061c8,fc85da28,edd6ab37,bb6bc5d,eaef0d,6ed7d0a8,bb15835f,e6074d1d,c05e4840,a22532af,b33a1131,80073cce,17b77822,33dde5ce), -S(3df62006,31fbdf0d,8ae7d924,370927ca,f27587a0,d7bce798,e6556a8c,62f108ed,c4aa6712,405c44e9,389e0a03,952ce263,c073b849,ec66cb7,b9e203e4,12017771), -S(d49653b7,639eeba7,e9d82b1a,61b0e1c5,1363337c,eed06916,47f81c25,b2f71e6b,f1411513,77e6553b,66221284,3f390c4d,ef25b316,e1123b19,a5f77c97,b4559e79), -S(fb4a40b9,77153349,3d316d3f,2688f6ac,32b63e35,6f8fcc17,ca1a9008,b9a90745,d49d6d04,ba60238,5cca34c2,6e5e3ea2,8396a459,c9f54478,f1e93e94,fd3545e4), -S(2b5f9b4,512e7676,82d7f93b,39027d9c,4d2788c4,b587dd66,8e7e2a49,2d1fa3ad,507b76a7,33682d56,6a2773f5,c3cda342,2152e9c4,9c204aa,bd015dc3,9c9469f6), -S(55e1a77,2c3406b7,b300e7de,d35ff44d,76fbb312,7859c80f,841bd730,45c0c006,f7f2b9f4,7c2ec8d,9b476229,ec773a2d,7316b391,8f98d540,e110d196,58cdd0c3), -S(269a6ad,e6e25392,21f59cd,10456fe1,b5e3a756,1e13e578,3cc6b7c6,ef145ac,3827d2be,94cde1f,ded8306a,6619b933,ac2515cb,45cffd75,267caff4,1e76d6ca), -S(e48e1e7,87d48c62,8e85040e,2c836be9,cfb20d10,51a251cc,9e46b589,485a29f8,aee94719,b64713a1,ff2f2402,ec6a19c1,4df12f40,6214c49a,d9b00234,4325730c), -S(7612f9e,691cd23,701a213,79582527,d658be1f,526c220e,da6fc536,b3f7780d,a21538ee,e80268c9,ab6dbe6d,1890c4f2,99aa8dd9,82e9978c,b6ea37ed,53308c10), -S(34761add,2f2dfb4a,6adf1f0,81aff3c5,1faef7cb,bc1a989f,3e23afba,288c11ef,50c8b3b2,9424d319,8d55c10,3976f312,bfa480ee,9e93caf4,b75fa97e,1517d3a1), -S(8e57bcd4,5c8e9789,624ad4b3,8a9d5be8,bcac139e,a0abc310,a1c272b2,35942e69,8daf7fa3,43dd401b,c8aef9d9,c102b577,28535818,3e379de4,5e5ce268,e9f9b548), -S(b9c35f36,2b93a8fd,21c9307,91c659b,270fbe0c,965c8de8,b5b45ff1,e4c8eadb,2e506d1f,a9fdb177,e0a818d,b40d8f67,2b5ef2ab,72f051e,8f6eee9b,fc74b9e8)}, -{S(9705d56f,f75c7d2c,bacc47a4,a6cf8b10,300c688c,fdbd1b1,528f41b9,652d49fa,c53f7f11,896f2edb,fc957dd7,2cc90856,c5df9d86,43e42489,70182843,84201b98), -S(1fb0f8f5,ce10e878,abf40518,116bbc18,ee77a22,f701108e,a8c4f9f,f6562080,8f761286,34089abe,b48bae3b,882019c0,9bcc5386,20fa98dd,4a3710a1,e4e9bb46), -S(4a807b29,3b312ca6,acb43f49,6436b137,36748bc,15c48dcb,7dd35e75,fd2a5668,6115f059,e21f7257,c8888959,d1401db4,c77a0086,34cc2206,e8a8d4ba,1540def8), -S(288ab400,5444930c,15410269,9757d7fe,b8410241,38c45db6,d6a628c8,e0100ad6,bed94f18,78f4b61b,c0b557d3,cecd946a,f9d105d7,a298cb73,fccbddd2,4210cf48), -S(22a7d3c8,85001932,985e9543,1e470770,f664ffd8,e4593aca,7c93a7d0,9fe01b93,65172aa0,9a61749d,d0695269,4a15696a,947c8b37,7ab24041,d76aa7c8,3055290), -S(4470823b,bbf22c97,7602d166,dc895df0,a562a732,f905ea78,416a74a1,eb0f35fd,1b1eeff,736ef902,aff3980c,36b47ce0,c7611f5f,cb83658f,7c5bc15b,c6e35414), -S(bf345a75,c16ba113,a4255ce6,cd485235,d7b71b8c,11fd0d49,1bff369e,240aaaa,8a8b2999,e06ffa8d,89932713,b1bb5c5,6837bf51,aea390ba,9579f2e5,566e7c1e), -S(9ca5d558,2737e890,f9a7dbaf,d921177f,459d791d,21f9993c,481594fe,b9aa7112,808fbe3f,cc3e80d3,f6e2703,f55b32ad,cc1ee8e9,6fdd0250,d7373b15,83918a6), -S(4d3b878d,ac7d1878,a2cb8ef1,29c488f,59f26f1c,d56d5476,7b008e47,eb7a293,ea8ade6,a46ce8f9,4602d631,e0147981,3422eb50,e87cddd6,792a1ee6,2c338f40), -S(2bef9f5c,accfea49,697aac36,24c7db8a,62f03620,109f1cce,fc46af89,25489a69,b39a88a0,d7d59b29,b7773984,53e6eb2f,7b557171,20de3625,a917853a,ed1f8d83), -S(74a0d8dc,415a228f,3bfa9533,e7d4e544,f03551c4,d55b0d2f,fd524d17,835c3132,d3c7c720,c44b1742,49c2d9ad,3e9c5f9c,eb174ba1,bcecab7b,5816cba9,9057b5c3), -S(33b23068,27e030cf,f0673254,ee13b94e,6d7377d5,fb8c9a83,ed50e9eb,4ac6d5f3,b0116426,ca9fc25c,a4f9834d,6d8974da,1571a54e,1f507696,879ecac2,5f23b095), -S(a45a4cb8,24d90134,5ea541f0,6896387a,12711d70,6f07a850,69478780,2e49a474,bb236a74,96161e43,f708abb8,80e3d0a7,a6354a33,cb760bcc,593bc8c8,7c8f433), -S(fba31e01,2f38c223,3750fb25,85c2c33,4fe3afb0,36b17fed,5e8d513d,552dc2b7,d6d8f5c2,745b2c90,d5c201f5,524f2b0d,49020ae2,4eca8e21,b95cebdf,af25e5c6), -S(8a5bf15f,e026e897,190ee896,f79927a8,a8658d05,f9a0f6a6,79ac8971,4ca26fbb,639849f2,41d99df9,d217d702,4e6c5bf2,9e44b7ad,63e0b091,bd235d45,4cb07ebc), -S(43daf5b8,4f1706fa,cdbfab46,e4ee5188,b8697efe,f6d1274a,77af6bf7,b1ae23f7,d2fae1e8,721553b7,e63130aa,76f61e96,a34e60bc,fe7bdb8d,6879a39e,db08d8a0)}, -{S(5b27aec1,c644f0a9,ba7f6486,9a960ea6,28343ab,da3feab2,4a2d6add,754866a2,3d1f365c,2aee6c1e,ab2f1879,429b6275,5d1bac85,2998ef25,8a914bfc,ca280b43), -S(472e2d82,220169b4,e249b18b,ee3d0188,70b91ff8,77fa9f64,9a23ca43,a5aa9271,908226fc,2704e162,c96297f7,6af76d80,32b7845e,9b998466,cd106e37,1a61feb1), -S(e9d0d14b,3cdd4531,f8125e83,dc3ddfda,18d64976,bb4521ae,83a9d9aa,8609b431,e1f950aa,821f586a,91988d6e,e3ca4db1,1574041d,140c64,2ba9a1ad,cd1c52ea), -S(e47190c1,f5fa4910,6160e301,69e8a087,76a9e996,aebef7d8,2b1d7248,7d38ac4d,50abab42,dea32fa5,af0d65cb,3dd950f1,d2e54bda,47d990ee,9fd9cf49,cc552d1b), -S(dd7cc010,b8c93c99,84c19b2,37aa2b6f,1e51c765,7b93bb9e,e4d0ea60,2d6dae8b,9f2773e8,15aa182d,f6ee5e70,8af9e8cc,6ed5f82b,994633b5,545ff889,c5503e5e), -S(6e4656b5,aa8f321d,80a46a7e,721ab22d,f5216f9b,602aa74a,84de050b,a3851d8d,170a272e,f646cd5b,e3c1d9d,14e19601,2f7b140a,136b509e,580c4800,7c0fa08), -S(d0cccf87,813d74c1,e0ef5315,2a2e82a8,9d6729bb,23c8f450,d1e5af64,4b7f6341,b5c903e9,dc51b73b,5cfaed20,b9986f80,b19aed65,d11e624c,53162315,2ab2cb5e), -S(87f7d90e,8f519af2,34262929,c4801bdb,fe472f0e,3eb746a0,cfdde906,1697a540,36b97cec,b6a1766d,b349034e,a980f0d3,cc653b,5ae732f3,e9868d37,1343db0f), -S(feacbc45,43a59a7a,3fe37bdf,5f05885a,a38cc3ae,68e423d9,e90da9df,15569f45,f1aaa0e4,230faf54,c1a394c4,fab80639,184d42bd,62fe74fa,d2b9d8de,2bd13779), -S(db4aad1a,7d5b51f4,be47fe0a,d8b14711,e03e0283,3076470e,7291f310,bb88b65,51b5928e,9e6adc38,be8e5e7f,a93336ea,4ae1f65d,de69b73c,62e04384,fcca96d2), -S(f6a6bd4d,3f763afc,721fd2d9,ed42d34f,df38bc9,4fec069a,8f8aeb76,8b23f74b,d513f993,f97d6fcc,9a7fcd74,458dc00,437fb611,b7e09b9e,a9e85c93,1facecb7), -S(982457c5,6c22522d,e0d10fa0,64a0f8e1,52fe9924,6f20a794,81df8fac,8fc08ab7,2e080dde,a66a3e43,af44f9ee,bbb9962f,16110b33,b0e9d83e,38333aaf,89be29c6), -S(2cd27cb8,d3646f0d,a549cf0e,94e70cbd,c40082df,b4a04456,47579397,e3e12d91,c17377cb,e2ab57d1,1d6c5cbd,c5fef865,440dd8eb,cb5cec53,124872dc,a49409e1), -S(6f34f416,2a190923,8a2b5561,54a056e4,9549d6f1,72929ab4,fb49175,b7da0cb1,2a0ff98f,98422e19,e394f868,7f2eb9d6,dbf7129c,c98df378,31895799,445a5211), -S(3190285d,d898dd64,770729cf,25f59339,eee3971f,16b08450,a87c9916,efb1adca,5423d919,1eb4bf71,fa55c153,161ec8a0,6f5930bc,17ad25f9,39f229d9,8af5382d), -S(3a150c48,d4c56e7e,9d910864,29b43219,9c95881a,d481e0d1,59aaee93,b19ceb72,290d1c34,f241d3b4,f7bcd618,f585578e,7d17a89b,9be52eea,41020f37,e1f521f2)}, -{S(53512a21,4a659914,82cc157f,da02880f,7c4ff9e6,47a93136,c1e55725,9ce7132f,3ccac75b,13cc40fa,5ab2e017,80f55f2e,b8e6a7e7,22b2e6b1,13a28316,b3c99d3), -S(941512ff,9ddbed5,13d60b50,1f3425e5,d210fab7,f30b2ffd,db6bb10d,b102cfa4,ce038b23,257413b9,f3bb957e,43b25747,49fdb5c7,a975667c,72de28a4,46cf4572), -S(cc2210ec,ee7d9560,753ef5c9,1ff9590,230ea13d,8416d73e,47332720,ecc63f9e,cc800501,dadde2a4,152ff67f,9d430ed8,3ae15e7a,e5bb493f,95d41167,327eea9e), -S(384629d5,414c9230,60077a1d,e52fb3ee,ed883b32,46d6f21f,e18285c9,2b1562ab,9aa889f0,f0bb4632,7ff7ffab,beb7eb30,d8730560,edc85521,425d7f6b,372b2272), -S(1ff9dac3,a65aafa9,8693a45,3ac3ee51,915cf4ea,1651a456,b1a03aa0,250e9d97,9245a361,a7831503,be192d77,2f592cb1,f9129287,9ccfc15f,494eb437,9edafcbb), -S(448f1c1,db9f6274,e49511a6,26ad249,e2c0b808,1939a383,609bdabc,dd94ade5,6c142261,2a8a6cf4,1d4bf7ac,8e6e7c87,2dc33b72,a87ef595,e9e0ba72,c68fecb7), -S(c6b5006e,8fabf0c,d3e72c2b,45368021,b6e53820,59fcbca0,3da03181,b72e6eb7,c579f919,cb4bb266,a527a446,80dc9300,629ac1b7,4a5ed005,f5c455ee,bfd5aea7), -S(f4d156ae,da9f6e55,f455080d,35fc507a,bcd2b23f,de6d893b,5ba039db,27493953,7d45e992,a2d4b8cc,41c2849c,34e785b4,8fdb39c2,e715328e,9f7690a7,31bb5e66), -S(bd72705e,9d2a78f5,6d39be16,b1aae55,da527752,c3ada8ad,3f715d37,7e3784e4,5b5f856,7559fc2d,b7088120,9e71be70,db2a4404,e9076084,7f4d7bd4,e2aeb3c7), -S(9c6bce85,191030ff,c60b2b07,c8187f79,249fc982,47508c9f,2797da3,c21c06fb,dd7be1e8,86931a24,925e899b,347a81cd,85eb17bc,b73f9cae,1097935b,462d0937), -S(1a357743,84feeda0,405e9e16,28657462,218f4b2a,7921ed05,dccabcc6,6fe5aeb9,8e44029f,7b28b880,9640e5c6,60131513,e283ef66,983770ce,686aa706,81b1aaa4), -S(d1908dd7,f1b5eaa2,a1f9f066,683db7,b3ce644f,77a839f1,488c90a1,e372f18f,a221de7c,15bf27f4,ff71f3ee,fb068463,79d09aa,3b6e8b82,bbe9eac6,8c00738), -S(b7be7d12,1e964dda,820fb389,2f9e99aa,36e8dc2e,7498ea80,34af4397,ffb82b91,88813b9e,c333a6c4,78b627fa,afe0a657,dcf449ce,3a5adaa5,662a81b0,68b8f5ea), -S(6a66cc8d,27ad7843,ea1a9b74,373e413a,1b3b23a5,fd25a58d,6b75a231,b97538e7,afb5aa7f,f3cbdd2c,a4dc9694,e56141d1,85550285,8dd6c89c,7938be2c,a2856c4), -S(2b1e7d33,b7d1ff91,ac03cd10,f3756e9a,d39d358f,2f63c2fc,e89df693,5e16d3e,d42588b3,d1b1fdee,b860b4aa,d0ded901,bae1bb87,681fc257,e843ab8a,76280692), -S(f7745d72,7b747b4,e9d6e7c7,1242705d,140ed4c4,d43d28cf,a0a8afc5,37ac932c,f640180b,6b8b0eb,c94c8931,2f897e5d,1ecf427d,7c86d2d0,772ed63d,f4cc3444)}, -{S(534e9d8,bea140bb,4970b516,c42f2677,dc413f42,9b7c56de,e261f60d,ec68f9d8,e55aff90,1098b0a9,ea377acd,b62dc479,da109514,2654107a,28c68e9f,73b1cba), -S(f0e363fc,4c8761ad,bf4245e2,b151a7d4,335c9856,bdb9fb2c,1e53fc76,28a9a69b,4629a699,3f8753b8,6d2190f6,505e009f,6fe56739,9dc77507,a1cd4cb8,920b0ced), -S(a28116fc,5e3541e8,8ffe043,160a97ca,b1d6e898,b6a3acf4,d150860e,5bb6a1c2,e43aec5d,22795bcf,7979e260,de7da3fc,46023dfe,8db4851c,165a2fb3,47c204e8), -S(cf6eca04,328af9f8,e461b6e8,9251f94b,3156a63b,d440d6c2,b6dee5c8,7ead5b29,1dcf90f5,9bcd5c0f,362de1f6,1b7a93d0,6ab64659,7f77bf94,b8bed972,9f096f2d), -S(44bcd74b,2cdc4b13,f48e3cbf,b005bf74,bd114fe0,5c2661ad,46642f8,7e952fd3,8873b17b,67848110,fd200c6c,bba0782,34dadccd,70dd83bd,cafbca31,df373440), -S(2dd5eaba,e7cbff44,d2e56df0,14fe3577,efbe6df3,57b870ca,fcf5bfa3,78d35cf3,6922806a,4ed044eb,d711f510,e7c5c846,ce892189,ba4479d3,7ee95a8a,11983756), -S(98294f63,5eac3fdf,f8e07f53,d24e650f,2e470b0,6be9193f,1463f1ba,c37bcf5d,6a03ece,4f397658,f232bde5,71f33a4b,a8058641,e301c99f,e1df978c,74236a47), -S(c68b7c67,36003c06,d29ed03b,2faedf60,5ef705f0,f1172166,b63bdcc5,437bcf0f,a62dfd76,c1df5d72,680eaf7d,51359a63,82ce005d,fac432e0,672f63cb,cc4367aa), -S(10da4eb6,72c088be,d2d4a28e,3e48efb5,f4a456be,b501183a,816615cc,f23b598a,ab798e69,26e55eb,c0435828,a8006356,5cc6ea48,892f748a,a6ed1685,36a3bec7), -S(24363000,a821cc76,4bb2c552,3c37457,9462263e,df791598,cf7ab8f0,89178ea1,c6d07d19,d53ffbdd,f367f46a,6fffd5ac,e2236f63,26fb18cb,3a7d543b,9f193b01), -S(459ff583,3501bc72,13c135c9,be63ef4b,fe99b731,917dd475,b356fd72,21705c8d,9c3ef5e7,4483e1a7,42316df0,9f313a10,17858e7f,ef432763,df139b4c,548aa325), -S(43e3d2c8,44b6ec8b,b5ffc06b,d2a48ad4,39893fc6,a9748cce,e55adc76,d616b503,62efde43,b6525e9d,6de6a7f9,8831e194,9296aeb,7ffe715b,4a064166,c18144f2), -S(8d6eb1ec,5abe1d6,2ecf6a0c,e1283a22,e1259cd9,4ae96c8b,1fa03521,8439f798,9b7e03f,f50082eb,38098a19,c417c4b2,74432e47,79faa37a,2ed5e43f,daaed45), -S(fbaf2899,4a9ebe2f,cbd854ca,d1beddc6,7ea94f73,321f3006,7d75b327,bf25b65f,184a40f0,777c4a8c,6614f8a4,d5ffd514,3215c0ea,9caef82d,c20285e0,4477cd77), -S(c58395d4,623cf0cf,8c7b0abf,686f71f8,6c0b1977,44ddd642,7a1c05f0,1e9f938d,1d8eef66,7d5b8ecd,af794b8f,2bd30b17,966de31d,83ba46e9,73fb4a2b,914b06bd), -S(40c74e1f,f01ae64d,85f958de,6d1faf97,6169b00f,aef64c9f,23c5cdba,5e17d294,b21a6ec2,1b409a69,f8f6987c,1b1705f2,47781843,73ae5695,14b46951,48448e6e)}, -{S(dd7503a2,a3e15e7,39eb9b1f,856d6e33,be4890b2,f40cfea8,1bdf516c,b942731,ca9cd04e,c3789ab4,5088b819,953e08a0,b8adb8b,b2b6f7c8,661a2d3b,83a54c77), -S(a1df11b5,743dccf0,90fba9af,bc699089,bc923e16,96a7841e,5dd338dc,a8aea428,49a697c0,45f6232c,d0d7d5d9,c7e33701,758e6a12,9a9a50d1,f173beb4,5b9b601a), -S(fd7b2a1f,cce0c2de,e11c9f85,c245f43,1b9aed6f,a542d401,4677236f,4381b927,77bc8fa0,5639307c,463fd419,a784dcdd,be1bed1b,be42c315,dcbf9d24,a5c7dc1b), -S(7962833,c1cad761,fc1ecf60,62ab6f9b,b11cf765,2c5c2aa9,e4db18c0,544ec275,7a8bb3e8,209f1876,d3452f6f,40c3cab9,f7166dca,160e0f51,afc35302,75740cc1), -S(bc8ea787,2f386ed9,24197d6f,cde66dad,43b1bc,390ea517,ade69780,beaf444c,12f31c87,9b69c7a3,bed748db,6c0dc465,3a0c1cfa,e4cc7b97,c00abbef,1b86fdeb), -S(eb4a5a9,5957f070,73fd04fb,4f1d9403,ade11ac6,62f2db35,23a3c16e,4a34c040,277d8694,e598912d,7b1266f0,493d9141,febe0f46,bb69eb24,c8be701d,9e8c6f74), -S(391bb04b,b3b924d4,bc548329,64368cbd,7cbc1a79,c3410cf6,63565b9e,e62c5d44,951554f5,fc6b8ff6,40a0aa39,39929e9,41db1056,d05bf87b,ded15a32,f06197f0), -S(4b6a608d,baa71d6a,e20f543,f4a5041c,a06ab5a8,cfe0b331,6a6702b8,46212ea1,f3c31e22,bb3a2f28,bf1f0594,4f798603,107cb301,6bca7ea,a8b863b,5f85954e), -S(a560f348,ba8b5a1e,885158c2,a4e94464,1bbc59f,3fbf4851,3216f4a6,cfbdf8ae,98568f29,eccead17,257e558b,b3835772,5af94f69,42b943a4,36a95824,b92c529), -S(2356a93f,c5cd70f5,f5fde88e,6744efe3,d0d713f0,31f228a5,1cbe2c3a,4baf7107,59adb751,7111910f,9e1a690,139b10d6,f30c311a,4ab6b82e,d1ba7077,3a4994eb), -S(f7fefa64,ad63903e,66705d88,d5df718f,59b7e9e1,f9180d21,647b2a73,6e2f1d6,30b5d8fe,5393f9f3,b68dde98,1adfc77c,cb3953f6,7fbb3445,52fafe72,b9453532), -S(73d5d8d0,95d6c533,60914bcf,5b279c5f,f20145e4,e0ba1ee9,468c2edc,b59ee4e9,56df32f6,dad0b462,487d2b25,79dc14d8,34ef8705,d5efa77f,1f371bb7,641ff145), -S(a1d772f9,4377b24,c98933e8,47dcb51f,7a982940,d205e4e3,c31c2cad,9b90e410,617a72d2,ea1b82b5,775f13fa,1086eb6,2827572f,f6182101,3cfe60d2,7df6aadf), -S(28725dfa,ad66c6af,5f980f25,653ea5d5,116fcc37,be615037,48d71033,ffd322c0,67f3cd88,1ba30b09,3bbc1a25,34826f06,90b149e3,964e313d,e3706f60,31dd6c0a), -S(38573246,ddba2c47,a9d85ac8,c3a13ec8,4133da2a,cf6434ed,98acf5a6,84d89ba,e97fde8e,6b2c1395,a9f242a6,8fa989c9,5dabd2f2,ab830949,4c100a1e,fab317cb), -S(e69ebcca,426dc9cb,474c5f03,5b6e6245,cb18fad5,2d990ad9,6d29ea8b,e032c220,322ac73b,d7c6a5b,89f3926b,82578f6e,a6fc83de,a11da204,e15bad7b,51ab70a7)}, -{S(c8116b60,1f8d72c6,24957215,46b844f6,bf6bae0b,7575a77,f1f6c6c2,5524fa2b,b7477ca6,de2004df,34882c65,3a46821b,53372f13,ed822cbf,40c20bd9,ddd1d6bd), -S(db0d3761,c6b76d0f,4b3f6423,daa1acef,19d01f9d,c6230840,c4ef120,9e4f80e7,2ea359b1,f19e5d6c,e8360c04,12ca60b7,a43939ca,36fc873a,7a80a884,90d3d359), -S(a4539230,a9c0b4ff,65e2a8e6,47490c1e,752706bc,ece59a96,f2581cab,1b430bf2,9c80b433,f87ca7b0,3662b22d,73a99e91,a8c63fa4,9fd3b8b1,b17d669d,aaa9604), -S(a77cbd99,8019c652,7ad38d8,f8be3ce2,dfaeda98,d378cc3b,7f86e291,15a56adf,3d5ef26b,d797de9,6f8a0d9e,d14a5209,ffe8964d,2bb768ce,bc0c3422,85eacf77), -S(2b99d5fa,a416b572,c796d92a,ba9ad7d4,5b020fae,95aee14d,f114489d,cdbff30,4b89c70a,74e07b43,cbf503d8,86954759,9c3862ca,32bf168e,20a913c7,4fdfd266), -S(a007a8e7,a60dd06,6d11f1e7,4912eb12,91908cd9,a3fe6a8f,53393040,f9c6fa52,24b8c6a0,6160c947,61645355,ea365434,323c1d9b,2858f650,5526497b,d148873), -S(7f3f4e9,24fba80b,702f3252,64186077,2879a2e0,cf86c721,cb97c5a,cc1403f0,fa6c055a,4eaa3651,3746385e,c69170f,f3a1ce56,d9c06440,e49bca94,e97220db), -S(70f9b6fb,c3c4a20e,69c75791,2289936,4da614a4,dd49002b,291767cc,304309d0,5becf8f7,3c414163,6aecfb98,161da5a1,ddb08885,545d946e,c4f2f39d,66b15165), -S(ffd34a18,cb7a72a9,19b97602,2110dd29,484b3fbe,84ee3c9,46b370,f710d86c,b03c2cf3,84b6502e,f519c55,b40f0037,cab3e513,2304243b,f8e7117,cb4d4bdf), -S(ef8bb54c,c1fb8d0d,7be9f5c6,85dcc465,9ce9d874,bb1f860d,60bd0954,d751cf7a,79216699,1efe79ee,bd5232c,687af3ee,854c85f0,cc61888e,c2981689,b03060fb), -S(d1cb47ca,c6b4609b,3e7e8f00,76519a77,9d8f4494,baada6bb,43d3a034,5c3e93b5,a8bfd148,a40922ce,1a2a3383,ce323c5,32041c5b,f89917d8,41c79867,d6efdf49), -S(ed2c9d96,38443a38,9a00241e,ce1edea5,4ba0561d,a084d166,9054b486,89bcaf5c,f81239d9,ad7a2fe4,5a9ba8da,9aa306c0,3d22d79c,c80f7953,53c13a90,c81d0505), -S(d7174d31,4126e219,817fa00d,140990dd,43cbebb6,81c45d9f,c5e0dead,d8135ef1,38093e9a,ba7a7223,6a5e8a8,6ad4ee9a,a5cbd614,da2543ea,34021578,8938fcdc), -S(41dbba9a,b52c3f9,98ecc1cd,aea6a093,ce702077,8e5ac6a8,91be5bb5,f73cb8,5ef35b31,829851df,7c3a2304,5777b6e6,89e79e3a,a06c7b73,f3bd47dc,fff8dc99), -S(f9ab0480,d24efbbc,26f1d2f,f09db463,f3d50993,af39d822,85efa32,97c73b6c,40a5a11c,c647b069,4536d4c,e154a58a,db0cbaef,77b24591,bb39020b,ff9c72ee), -S(e59e905e,fe97f343,7bc6ef6f,b8e06ed4,1eeb5666,c3bf72f8,5fcd3fe6,d0f68928,28faea3,4fd42596,c3880cf2,74987c2f,2f228442,5666ebdb,e357d9f5,e8886c4c)}, -{S(e7ff8d5c,83bd5846,5c967b5,37ac0f36,b9ffe9d2,fc7531e,ef183cb1,7369c066,9a9c3c4b,e482031b,f6dc69fa,843ea90e,de165479,26ba201b,5f05b00a,dbcc30a8), -S(92932066,93f2280,8bc088eb,8b50cf83,93c0a33f,5149976d,27b837b1,2e769b6a,7d86f6a,418b04f5,2d01b933,428d1ec3,ce62d349,693d267f,48cb005b,1499aa0d), -S(10e4d4cc,b8efba85,37dcb831,c6badf34,85a3184d,b571fa59,55e3ed98,80fa8e63,270a80d8,ed085ced,f4dcac74,481a75b0,b42775bd,9a844a9e,e2de9be3,92781c96), -S(763ae8ea,212d756,ec3e6a55,9ea9575f,ee67ca83,9e61e61a,99315231,304eb9e8,4e1d3eb9,d1a49677,6d1619af,8acc9b35,c6135fd6,bf82845,5eb55a73,6137d0c0), -S(76ff82ef,27ad0b4c,157d0b24,d89aaed3,ea654fb5,e0492304,ab02b214,81eb7574,701384fe,e57f56cf,62930a9a,e1b5977,8071d8c1,c07746e1,b1b6e94b,1cece9e0), -S(fca9c2e,b84ac3d7,7a32396f,a0a1763f,7483aef7,2b171608,e34bf24f,2c0e3ba5,8678a539,d5b12652,78f2feff,bac321a4,ce2acaa3,d0983d29,27e9e90,1d46dede), -S(a75ffbd9,4ccc3e8c,93a54e06,e4b5fb2f,4410db28,b980283a,51ce071e,83572733,b0151288,ec977854,aaff4ae1,18b65289,ef356df5,1beabbd5,77054a42,da145fb9), -S(178095a7,416460bc,c42fd250,472e6d1e,3db37a73,5bdc0012,e52c4ca8,cf65d4bd,b9c37e8c,a7cce01c,9adeadd5,15759ece,60776e72,992b7c9a,c23b24a1,adde790c), -S(8969a958,1ebfb858,cac5b7f4,88c56e0a,966947d1,adaae934,6db4041f,4f8823a1,5c1ce169,fa336433,1aa72a02,e543cf69,9ebdbfae,2cc00ec0,f83d6f09,8e78fe3d), -S(a7e28d50,eb9a52e9,e18edd59,6b291fce,7024e915,e7ab8119,2cf4642f,7c54d8a8,e35bb3fb,d67ec191,b3a752f0,58428c1e,a92c2c8b,7e84223,363b15ce,28435dbf), -S(7a6542c5,2560ba89,ece8a01d,e9c9acb,e534ea36,48186e75,3bd214d4,cc8826b9,eb9a65b5,e5d3cfef,50f0876c,c9277014,af67ef01,b21fe8f7,13aa8661,f6be4c9d), -S(459ff50,f27af905,a415ed85,26564031,8e3a8b5f,11aa25b8,b0c27cbe,83448bf1,4d86fd56,e083330b,9053b2fc,88cf532d,7672912b,db7c2429,34c8be24,40be22a7), -S(e28b9feb,67173d65,78a8e38d,fdfa8a8,e71bb840,b1d97046,456a7aba,b1bdb4ae,9c8712b5,d2d7e596,d42e088b,801cf20b,7f6dba46,8438032b,c4b25d4,dfc5daf3), -S(3c313413,6261f337,e5b2b81a,6641acf3,4458c82b,524b88ab,844387a8,6acde303,c1948e72,3e2481f5,f0898fed,9c1def3f,8f88f0f1,b58cbc9c,69992a09,4fdf128e), -S(77774800,3a50c6fe,65a5772d,1e01b8be,d8acdfa7,da1cc233,ebe2620d,11b570cf,96522ec4,23bd6dbf,45969c79,15494f6f,bc4a41f8,b99dd400,b7f9b59b,8b45e279), -S(f491ac54,4678dc86,5ce81d7,60465bb3,791c9c38,a7f98016,3de914ab,4f488f23,9e62efde,f5eee54a,ab244604,a3357af2,729e8252,a04f006b,f0d61d7f,5f13437)}, -{S(d8f08d18,ece61855,5b06a3b5,ac8e7cf,a6375446,cbc7c8db,ad924f78,69e7f00e,46a91d23,910957eb,db830624,73839954,2cea0570,2f67a09d,d7d19217,646606e), -S(b1238187,25e216c6,631d4b98,d8d3c743,753529f2,8e02bf80,d1e9119a,f92d8b50,487f7171,60b8993f,a90edd77,3f7c1026,b5961881,895ad804,51b66d8b,d300e0f5), -S(b2ff5766,4b8079c6,3c5651d,e0b2fd47,80d1a18c,60d78c24,b2c57809,9429a552,c7ad3672,6d7e0618,eb506d65,c055a7ff,cba848f4,9b69dcc9,c02a85d1,5dd8ef90), -S(901272b2,bbabc0b6,12dba006,1d4e8ffb,e177c070,43f6ec6,2b437bff,9970685c,ad7c1fae,4b80cd30,c45516ca,e3433e8a,2d3272a5,79e4335c,22e452a1,845326a5), -S(1d5740ed,37452eb5,c645f8e3,cbc4969e,a6f419a,fc0e4662,8b017587,a6871ad0,c7a6436e,b66d164a,685a1b96,3387519f,b4179d38,40f2be68,28c9cd1f,8780bb86), -S(21f0eead,ca362d40,1abae7b9,2edccf19,70bd8c0c,35ffdc2,76820d7c,478ef1d5,d3073714,5d577587,db806eee,b9dc40ee,191f4b68,1c488f64,fee83a32,d1034ef6), -S(bebf44e,4cdbb310,16e0e43f,b183ebd7,263515cc,489fbce1,90cc104b,55225481,f7ace0d5,3dcdb783,e10513cf,2e6c5c63,c60efb67,fa0bc316,de0e571f,d399f519), -S(78f6920,e94f8d53,3dbcd31d,aaec5e94,76919efc,ddff1eea,4e79e1b4,3dfeb4f9,5696bc3c,c8dfd0c,490250c6,4263da19,36454cae,88f653c4,2f9004af,10eba182), -S(4a2d9099,949f854a,e13ef6d8,a0179957,a47fe355,92ed0ab5,b22994da,3e616e20,c922bf45,8feafa64,66e31c20,d99584b6,ab390f2e,5b97009b,5254d229,d2ea57e3), -S(762eb751,35672a8c,26fac373,af7c7396,70b8c0f3,336bc099,aa1f02a,7e804df1,edfa83d0,6cec4971,6cf3d1e7,fd2fcf3b,7e2143ff,8e67a5fa,c24f14da,b3ee01a2), -S(fa4621,897c70c6,8b62619f,c040d058,cc68275f,91b4efb7,b4f902ab,3059b822,8c1c575d,d6066045,9aa7908d,2246e846,103d887d,3b7549fc,b4ab9f6e,e1181a55), -S(6a61b260,3d77f92a,c4df3f3d,30000179,e6f0fa59,a6570233,1ccd0dad,6a146ed0,416c09fe,711b40d3,92723f10,688fbd1f,e30131ec,e8a0a547,9acaa8b2,ae8e335a), -S(8a80bd6d,316dbad9,41c345a2,6f3f7ed1,738934d3,f00efd65,edc54fbe,9d38d48e,82bf1bc2,468b4ffe,11561406,2a2f9ab4,71d40e72,a2f1a40c,8c573013,5a86228), -S(174daec7,77872ecf,46832a7a,ce3c1d5f,47304048,c9cf1248,124c2eca,3438a110,be42dc6f,b61964ad,59083c98,e459ea4,db3298f2,ea8c8379,be76859b,958b6f3c), -S(e11397da,68e78b89,c8f30102,f779e014,f572f9b3,a5d33ccc,b74c2234,ba9d294c,bff23953,fd62c1de,a4dcf767,924e5448,e6529bd3,85a1acdc,3efc0e8d,864fb9cc), -S(9f883f,27e68e8b,201d6ad5,28a04a8a,fce8b706,a4d6f2e4,5d07c4ab,8b0dd96f,965ecfd,1563f640,97f42529,305be630,12f9edcc,82ab67ac,9bee6979,b91ad5f3)}, -{S(ca3c008e,cf9efd5f,75cc1035,f9edaa7c,46b17d25,9895b0e3,b3523b6e,eee9daaf,a676aea9,3ce9bb,128ffc34,deb96b0f,72179d28,77406d04,6d0c8b5c,3572f4d2), -S(59d2d70a,2e90a652,54e06ceb,3793db1b,a78e9b4d,e043a3d,c5773b9e,4c200ea1,80d83c03,5aa47ae,956ded05,cab59b97,4f25c32d,9d6aeca1,32603249,b6d360b3), -S(4d9ba25,f51de6ac,3b63b60f,576354a3,40d89e09,51af3e9f,8d8eba83,c00160e0,218deea,f7a87a13,f7ca36ff,b4f85923,30ed0337,2665c688,e3632048,97dfdcb3), -S(41093dc4,cd6c91ff,67df50f,11031e3c,56d8e078,961e74f3,bf01b010,564e732b,b836ff47,2e29fdb9,c75a4a68,a3277d9d,d4568f0e,43333765,a7246fc1,69d6c074), -S(8a37aecf,7a111e82,21bd8aa4,756974e,adbfc33c,9bd6268b,247270e2,642c8abe,6a9cf7f,d48bd71f,d7f2dbf2,1564737a,2acff559,9aa3da27,925b6140,3e940bfd), -S(7b893836,b2777ef4,2e4a2add,c50bfe33,37f7c75b,f0acdb03,1829e372,129aa8b1,31b64a8e,fe772afc,eb8f631f,b3a4b39,39ca4a47,859a0fc8,59165c5e,d8fc0331), -S(2f493e24,6425e2b0,fa036211,5352d455,8357a2d5,b838ad4,232cf6e4,e4b7dc85,9cc11b9b,5c3a4da1,fdb1a119,aa5a546,47cf86f6,b5bea9f2,a9b6814d,6158fc63), -S(5622f09f,c50ac0eb,2a1fffc6,76604755,9d3a5046,54956aaa,640515e7,91000316,33e375db,350fc408,fff91c09,fd6ec673,4c12f5e4,46348864,b0586d8f,fd1205df), -S(fbe24d9d,29eead5b,72952323,df6e8b87,322d570c,37dd2191,690e9119,8a5b65c9,ca77d605,fa1c71bb,acc38061,f4b04768,e93ccbfd,dd626796,debaf531,6c17e89e), -S(1c324df0,4c5d8f9a,7cf6980f,7239d5dc,94f49053,5ef06925,6341ad0e,5099baaf,97611701,e282fde9,9263c30b,9439c244,b0fc4844,a61c905b,fc03d98,f81d025a), -S(f40508e2,4252b801,f4b34d4e,2941673f,be39a018,2d9e6b4a,e0fe3052,da22d16a,5477f0f3,f55f1571,8e070280,f3e5cc80,af79dc14,9954c40a,8c1aa63c,f1b52686), -S(fcd09f44,ebf12a38,8f12f1ac,1bcb6856,217030a,903dde22,5dd25986,2ada9b71,7d5fc263,6dec7d82,167f40a1,cf00cf9a,fb82a10c,a293c64e,8ff4b616,1f9f9d9a), -S(666675cc,1d4084e5,f4ac65ee,71fef1ea,66fb7b1b,f348d980,b11f711b,fbfa2517,93f65e6d,4038c57c,3e04a0ab,b3b1a45,4050098a,7199635a,ce8c8617,e14c6870), -S(8bacd663,9b1d1f4c,2038c96f,bfabb232,87aa6574,13b3b0ee,5aaac2cd,b8d629fc,50aef7a4,fdbf85bc,e0876914,ed1692f7,7f8854ea,a07022c0,46fe359c,e87284a8), -S(efa17098,da4d08cc,f879897b,ca2b4e3f,e19f1668,4428ae3,94a37f37,cb678d10,c43b0e05,584ee017,80956297,1c7602c8,3784c807,a88b6c51,7f25105e,d16596ae), -S(6c8eb955,497f33f,a1c0f1a9,a4f5017f,3f2613c3,3ab944b3,abee9171,d35f582,9e647007,dd811c9,bc1b907c,e1cc70a4,ae07722d,4dff6f06,d77f5937,9250d8)}, -{S(8a4e9691,3533875d,b8559500,65c90785,a78233ac,ef24113c,f6ed543a,e6a40024,57d9444,8d091df9,602e6c7f,c3f88934,d45a7c76,18da574b,4d4c15a6,6925bcf4), -S(d25026c,edd7663,2a256452,c6585ec2,e8c475f6,247f621c,c4438bde,b4a49ca3,4f8ab8c9,bf340f6d,c38a4830,3e114ac7,9406baaf,583533c3,bf6cc0d3,b529ed36), -S(7bb1335a,3340e2d2,ed2e88b0,5daf002e,6a903241,e142f9d4,e48d585c,a9cff8d3,eb65860e,c2a34d44,1f1677e3,f3cb2bb3,9d0761ee,200dcaac,68f683f8,7066bdc4), -S(809ab901,4a3ca64f,7dac499d,fbe84b51,6566f9b7,f504fd24,681fb9b0,be3a54a7,326d607f,e41037f1,bc1a4d56,4db58169,c637e902,99d52c37,d625862d,faeee076), -S(1fe79a30,e681a701,9c437773,1c99f7ad,b4b6a52e,289baf55,e67bc468,3a20b65f,b4843af,94698c22,ee928995,61418205,a745912f,3b0b11b8,b3a3cf5a,3008aa6d), -S(fb9ae54c,b674e5e9,ccb900f5,53d9cc06,949a6eb,76bcb6d,e7c8cf34,a6352936,3d2ecabc,841d29b0,b81ea46a,7b061c92,103c6036,5e9ce032,286243cb,91000b69), -S(d93164cf,ff3d386c,7d340da2,31479b7b,5167472d,a111e9bc,287be7e0,bbc06ceb,563ac770,b23ac56c,ba093d88,17e1a8a,47c9b607,eb773284,1c8b0c6d,f9cd9a9e), -S(3bc57534,178dcfb7,b80906b3,9db964,7e989039,1e13c2c9,f82d7b63,2a1b3367,5eb2254f,f7547cdd,745ca32f,e3ac49dc,2dadd808,558b7905,71a46132,d0293e09), -S(69c24add,b825c48a,ab10d0d8,36d2f4ff,79535742,f07bcff5,cfd568a2,ce28c8e4,a0465fd2,fd1f7924,e60a96f,472059e2,4df02324,7bc79e7,11f64d8d,a477dc06), -S(76d9304f,8dcde85e,9a331a6a,bc066d5b,72ce9fc3,a3e65614,37c376de,f6aea72c,6a31a164,af370f6d,2ba9729,fd2a7e5f,69d62729,bcecf340,48feb388,541e40d8), -S(f45517e4,13d15400,29e1bf03,aecbeded,9da08531,65a38956,79ca08ef,8d7c8011,7cb4b383,62f330f2,bc54d555,db060911,d7a0383,eda89b65,913cac4d,4098a1d1), -S(2e3b0113,818930dc,f9e6d0cb,d59032b5,e0aa1da8,1cd95f3c,1dfc8520,51135a12,22f9bbbc,e023e03b,d00f1c73,d2aeb9d6,96de61fa,47f5f6fa,31a5f269,b4029c5e), -S(11c85357,5073bac2,51a5f7e1,41aef0b2,8fa240fc,e8045f2a,e6fbe0b1,cf99d9da,ee8a317f,78545477,732e325b,4695f5de,b3bde843,11fb7fde,1a0e1cab,d8bc1c16), -S(f3cef221,8bfdda19,99885c8d,ee2e16a8,b53921e4,6045de20,94775856,9f2c84d8,a95ecfc8,e058dbe2,d57144ad,e65ac41b,b27cf4f,83150b13,f7f80878,81b98480), -S(b537bcd3,3bb129b1,db277096,afa2f42d,d63662cf,849a5c0e,f7438443,fd8d0e4c,76cf0b80,461e8984,bba8d8bb,f926ad96,6a7e9684,f09e4fbd,45657e65,d45ab69c), -S(4ca9dcbd,fc4ccc48,62c1b2ea,cb624698,40c3a0b3,95bbf084,9dfcc410,b89c3718,be50d6f0,845daab8,cb857c24,fa995624,dbf8c938,dbd982a4,85e66d4b,1db2c765)}, -{S(458f8dbf,9cef8cbc,5d2046c7,42ca6297,e8fc76a,ad22fd3,af4f9a8e,2173d857,57074c8f,14a36b5f,6924517,6e3dc7b6,4d12a08d,8d00565,e70e0ca1,56f29820), -S(d4e74c10,91365cde,4cf5168f,f4f523a4,1fe85d27,d50d2b8,76218259,10c3d5a2,ed9fd256,43ca55e9,53a209e7,5fd7e965,7706855f,d47d7053,ca9718dd,a834c691), -S(f992b772,821fc43e,61771037,acd07e54,96f61845,d5915056,5babc86f,11a766d9,8a8806f1,cf24eb13,e7b8cf1c,25d550b7,4aca323b,e3026382,e0dab78b,217a9f98), -S(1e9971ab,68dfe587,fe0f4612,ac8bc090,5c2daef8,616dfa6c,b7505e04,424f74c0,4e9c2118,6214b25e,6bca1e61,57ae70a2,5fcbddd4,7690acd0,e537110f,c08918b5), -S(ff3717b5,f433f50,9a4480c,80e6d115,c41767af,2fe6f0d8,679798dd,cebfa8b6,4e443023,e6bec3dd,f82b217b,d1c0c235,278d6fa7,8209e009,4c716c71,163ef474), -S(4dd0d667,f0d72439,b3d3adec,15bf05e8,129a1218,a8d7c645,307aefdc,616cbb0f,aa592262,93fc13e9,a11bf634,56d81d7f,fc503f33,3a523af5,1b1e9a9a,921a95ce), -S(c5475eac,51e02585,9916ff52,efac5c35,bf9b1b43,bd88e949,8807d772,f9e23b1c,2daa42ef,55198235,e8c4137a,d13bed86,d994fd1c,480ccbea,89c1c545,cc26fb27), -S(588d521f,6f9d2c44,e2ee47db,c05ea3fc,517d1d69,7c66a3a8,a62c72b8,645a6a87,24749bc7,3d997052,3eea9809,66701cd4,db072ff2,d9284255,e4f8c22a,afd75504), -S(d597241f,298a7b8,a1139b92,a8bde9b3,f91ea694,c450c808,e15df89a,feafe70e,5d17b691,ccb6cc27,79337e2c,8906b73,83876759,abf728af,c6889182,bf8301ef), -S(5d2d98db,c2d6a0f0,1cb8e201,516f65da,b43e704,78b0e5d7,deedde32,71614c03,c46181b4,d08d0555,7b031d3d,e5966ba3,6534c010,48875986,93584851,80ae7c53), -S(dceeb9b3,6e8e802d,f2ee9664,b3654b46,741ae546,6031162a,c83bb6da,98bae12,bf6e5152,53aeaf52,8ec5a0e1,de1f156,d64c9123,236178cd,ee9b2c3c,3e2710c2), -S(d4984e63,4d173439,e212d2e,2e8da9d0,d00d14f9,1c1d22ce,c37a537a,f3b0788d,c72c5356,63000ff1,9b17ebd4,be15230b,56528faf,c9622b2b,15e88318,4a5c359f), -S(13ccca15,767ae67,ad5a1b60,36bf0e3,e617d537,adc87238,be522265,b8fb813f,ac7d0ed8,2f30ba14,a4817fa0,9dcac107,3f3abde0,41da268b,c3bc9b61,38df6fce), -S(d891e13d,678ebe25,c129de51,7925ddea,c89ad77,4503bee0,d3be486b,2ed397,9a9b4d6b,62180606,9c6b5d9c,5f14701f,bbc8c436,9d148d40,dac50a58,4e87736b), -S(b6c1f018,2bcc65b2,be194313,9b2d61d4,20dbc415,becf5c44,356b3687,47c215c2,b7bae889,fab9f1a2,6050d82d,b983a6b8,c7edf242,69de609e,d963e0b,9230f79e), -S(853be70f,c6df02bf,271ad18a,6e94e277,53810df4,602276c,c5b0e9d6,2f55e587,bfef4966,5addf7bd,efe505b0,368be840,6fa2bcbf,316be956,53d2dbe8,c3db190c)}, -{S(d2fff4de,9ecfdbd2,dd99ebae,d038415b,19b6c44c,9717926c,9e9a668,3fdfd377,a7e8ef8b,89877e3c,cca566cc,7b7dd537,d157cab,121d1623,b6880567,ac66fa8b), -S(f88cac5b,7ef229e6,1a12c335,1603b853,4911e6e6,644dff0,16924cbe,53aa97f6,e853d434,c1dad0b5,4871e881,21673a90,71182684,12f3362c,e43486ff,61307196), -S(7e61ed71,5dde7b01,f1baabaf,bc1db38a,8074c3eb,ca665c4f,d70cf352,624d3d38,70bb8d04,ab22e016,1c5836dc,f08e2c3c,36ce3f67,f49e0a5b,99e21b5c,c6ed9069), -S(9df9045e,7deba246,11e8fe62,fb323077,dd495d3f,8ebbe4db,384baeeb,aa6b88fc,4d5f0bf9,f5cef832,aec0ae94,f204d1b5,18554378,440675da,8bb2d91a,8fcd5960), -S(5d134cde,d16d21c0,2bf962e,7f12f2d6,4e91586c,8070bfa2,61499edd,e00b2a57,b7b6bc8a,54e118e8,8cbdafc9,325fc6e9,125b46c3,66c85501,33561f0c,49c962be), -S(a565c3cd,2dfe5f28,4c98abad,82bd1a61,76bdbb7a,4ee51f80,29782d13,849f32e0,59ce572a,ff34600d,26ac0c17,4b5b508a,81e1a9f2,7f3ada66,44234439,63ea61a3), -S(8bb4eba,3d2b83f9,d6bdde6f,82253b2a,717cb133,f0a7512a,ddfbd29,c6b271ab,f0a0bcaf,14311a27,da09d57d,ce87ea6c,b2156be9,59982e18,5c92e64b,861f4ed1), -S(8b93bf92,a0f791b0,e60e4a33,8ecc5919,6fcb8f55,b7cd886f,cb71d66e,519333c8,77e26206,945f5dc6,ca3e3075,5834eb21,5c3111c1,4bc0b424,319d7d50,f42dbb8a), -S(b8a91ab4,eab1e465,e9ce0f05,b9cd5cc9,d7bd5ca0,29018129,7a2d2142,a3269d49,35eabe73,94dbc74c,e174be38,81b56b3c,d2ef6a16,4a7f92a3,17034917,239aa67c), -S(26f3e105,9bc8f39a,b56cbfce,cc7f8cfb,ead6cf57,ca4d6d4f,61653fbe,1934e2ba,7a970b03,a86755df,f2465be1,ba1634cb,dfad7486,ed7a8a57,b236ae0a,22993b3), -S(b1775563,68b77fe5,896d8eea,e8631dee,788d6b7d,b5fe84cf,66782308,3c0536c8,ed42a54e,36509460,ecaa422d,fade0836,8d96dfe7,ce4b0af2,fac64b84,a49c4a8), -S(7e8f9d20,9b9ae3e0,d8bcc4cd,8f678d77,b9ddde2,f85b811d,63558dc9,b82b4c2a,317ca8e7,697667a0,1d60345a,acc9eec1,57533739,683a3610,baee81d7,bbb2afe6), -S(ada7a37,a54998fc,ab666fcb,78189cba,f07ac132,d0ddb59e,26a959ed,2281689d,ca658fba,d7ef940e,61e0bd3e,41e04863,cfae0703,f997fe20,b6c4ff96,c1a6d53c), -S(93023c4,ec822347,55893d89,497ebce,c0a884ad,e93a5ee2,23514127,fefbd7e9,cbb91515,e8ce6330,55ab91df,96ec77e8,52a5ce34,f0fe3a08,315c30c8,660ec7c2), -S(f70d11bf,4b476ada,a3329b90,e5673313,2107c27a,da354d4f,53ca0913,117f3efc,38fe645c,7adb5944,cf396af1,3bcf69c9,f952f55a,57274f05,a88e5ba9,51b64064), -S(111c1a35,fab368ad,e90c5384,b0412268,a1a8f8d3,49662a83,4aa7c0d9,830a307c,bc8cf412,238469b5,7a316a27,1fe4ba42,f3fa6a62,efe1e12,54f20f61,8c0eead0)}, -{S(b3b5422f,1361ce5c,bf7cc061,3c78aa88,a02683ee,cddeaaf3,f5516cb,291632e0,1790cb50,cc2c760a,c7c2e97c,c44aff29,86c73be5,59a88180,8d036e7a,94347156), -S(a7087c6e,3cc50e11,5e42e86f,855fc0bb,8a0deae8,4c1f92ba,370152e7,69d7e73f,86a61264,c5ea922b,cf1dd751,b5296539,bc2c41b1,29d3881f,2affabe,51f6d1d3), -S(53ef19db,13d761c4,995bce5a,55365036,def1321f,e0b393b7,41b55b86,8ecc9ba7,7a7d9ef6,61ec075d,19e719ac,56f028bd,403609ef,ccc39881,189673ae,10ec05), -S(9ea51d5,4cec52d8,58f8c082,e4362b84,6a83e0f2,9c99df32,30c9a2d8,e5269818,41305f7f,a9535eae,fe7316d7,6ae49d92,47667649,5776c712,214b8fbd,f0c80cba), -S(9c0db1ac,fa10880f,d4da60e8,a8a7c6e,b4117f37,80394e83,fb591307,14dc6460,55b73b4e,80091775,1e680a18,6df01b67,cf0b38cc,e10bc0f4,dc98e0be,7b5c5a24), -S(9734eb47,f47f2b5,4edad15,791b890f,64794567,df7b4866,b8ccde2f,9890cc38,9bd277e7,7cecded5,9dfa120a,f6bf322a,910e972a,57543940,b74098fb,af5be122), -S(38aceb92,95b480d2,1ab23f0f,c2ffa615,ee4f6903,32aae091,596d0aec,a99e5efd,8a3c1050,4ca2b73e,c5249f9a,6edf0b67,65a8b02,4e8ee2d4,e90dd3a3,a8e3c4b7), -S(bc517f6,658a0f2,ec9bb49b,19573f9b,7c74a37c,c3f40c99,7c31db21,170fb0e8,b0dad7b6,18e1e061,902ad53e,a00d3cd2,e9a7821f,172caac3,3c1fc1ef,fbbd3c65), -S(6726e4bd,5ea071e7,43bdafd2,2fc7153f,49e36504,e8482db4,9d64f995,b8b073db,7cdfdb2a,6a42f050,841631d9,779802c7,3ccb6844,1ad48508,6598f6ac,f91533ab), -S(b586e330,a91d81ed,d9b972e3,d7a33c6a,b01019e5,6f809583,767370f9,2803be7d,8bea5cdc,619dd2b0,185a3242,1fa7dec3,662cda7a,9f1302d4,ffcdd31f,5959628a), -S(6a713584,e0d2fe01,64ab5ec1,f31f2798,fb85518d,7f91d512,d4380e11,3d3fd132,3a864153,4be74fa9,6bceb551,15d2b3f0,59fc61cd,54a046e8,d6216f2c,3cfe61d8), -S(2919d598,7a521f25,5dcdfb55,3e5a707f,696f3aae,47226585,248abd19,39519f38,bef08437,9a346d56,7c800354,e85aa596,6a0e2b03,91efb233,7d4a2df8,9d14e9bc), -S(78bd9c63,35fe26f8,68d85fd2,6ad879de,f582e074,fdf2b20,f6bde782,cced7a14,a5b6404c,cd6059af,2722b328,acc60b6,87759410,161c25c0,6866a6d6,89a26877), -S(fecdabd,1951afa1,406297f6,9ea98463,54e14a30,dec4e3de,8ee107ab,43f7e32c,d3095b1e,5d01e350,2a90289e,c508eab2,ee888bb9,fc72b16a,8625a42e,23ffec30), -S(e97f6e7,5ca07704,dca90e57,aaa27502,e1a1293e,d99e6126,d03c00f,53bad532,e07fe66d,9a2543df,5b618336,f75b0907,83c7d74c,d63d8914,22524339,1f598b91), -S(f7270282,7f520388,5412f3c7,9fdfc9ea,da219679,e78d089c,4c1117ce,d990c5e6,9711ff7b,4223c8b,f9aaed68,f70090b8,1f8163b6,7429ba7b,a59ac7de,ec2412a5)}, -{S(2e01d33a,c10caa03,ab514f75,46226f67,69a08f01,56017b64,a2436a34,447bfdbe,f5bd77a1,2c61f2ef,60a8c937,cf29e1e6,882b12c0,3e7a7763,f1ea498e,9207836), -S(7eab2720,b4dcdc09,8d85ef3,869bb07,9640ab46,2d6b186b,88f92426,ac563a0e,a8a15397,96e48dde,8137ce65,c55c6369,766b5df6,7dd0a6a0,6d4bdcda,a0c4c70c), -S(e6a98f52,eeb51268,91c4c6df,b6ae474,6cbcf21a,7352035e,6bb479d3,25a64de2,61c7b668,e144fb16,e72f06ff,71167211,6f6ec90,4c6ca901,61a71b16,f176e0e), -S(33cca5f8,bde4431e,40c3af09,2242f429,2dcb47ac,8b4954f7,3dd25dda,d572594e,5c23241d,46ad4994,1fc84c2a,9aa42bce,1ee4f3d1,cba680ee,8760cd37,e9924160), -S(e5daf317,a0024ea5,26bc1939,7a54d0e3,ff325e60,3ef6a0db,4ba1b366,e1f65c23,8d70ed47,6895c5ff,ec487a26,b7a3fb0d,73a32e8a,a4a80db0,ca00ac83,4371957e), -S(6131d574,7439ceac,e77bc0d0,b49981a8,4e3033e0,185b63b8,a6ea9dda,cb45e7ef,6e01f69,cbe2af0d,a1826d6c,ab34121d,6ab457fb,770f7450,c366010e,20dbee4a), -S(8a7a6e0c,5deeaa35,f13a9bd1,51c737ba,bbac2fc1,924318e5,8b71bb4a,87ececbe,92fdb178,b2834b39,7dfba6b,69e8ec68,e8db5368,546c54f4,a1ecec8f,e4e0c351), -S(585670f1,f244de6b,fa6c9b23,6f034fc9,47e7075a,59c7ddb7,f744e6d4,af423e9e,d337bcf,822decf2,3ebd7101,6b54dfe0,8dad6082,4a6307cb,f0ed140c,3bb14a59), -S(75a87820,7db72c1d,355cf92e,a74b3b78,fdc5c56b,88c698b3,7eb94e2c,f02d6dbd,88595a5e,e6444a98,3647cd80,cade49cc,92a764d8,f710ba67,63e012d6,b12e5d6f), -S(b6dd4054,943d57ab,3ec4897a,8f755e9b,42c3aec6,7860e182,804490e1,91b342a9,dc70eca6,9f7d62a5,8bdfbd97,dc0e2b83,18d1f890,97e8494d,9632e3db,c6168783), -S(fdd92a7f,566e855c,cc134e03,8b5eed94,39023e36,7985a077,875b150b,1663143,ee7b815b,19e1fea3,fbe2d687,b3611895,48407e6f,b4136865,cb2df984,fccd893a), -S(20734455,8b2ee591,756fa103,2859a08f,9218b547,ca7b67b7,266bf648,25209de6,b389f394,2c3edb68,468dc1e3,73ca3649,ee0f0bc3,78b8da6f,aee8f4c3,90867040), -S(1d29060b,7b0f6884,2ca58992,48e6dc57,f491248e,3851bdd9,80837ee4,a777f4e5,a3ec51c7,888554b4,1b21b6dc,da472271,8e5e70e5,8d7bb22c,b8045fe2,2a9ca251), -S(324ff1e6,4d1ef0bb,e5439a5,a3642ed1,f97b7ad6,dfeb6c7c,9af9400f,f414cca0,9810fef5,762b6517,5bb1469e,9ae69f94,68dbce8b,131a7e,6859461b,25581d94), -S(ee2e5e82,e7106cbf,47093a31,e88fdcca,5e00957c,1020f858,bcaeba82,f21c5b31,d75b0c29,e9360215,7a8d0359,991b5991,8bb17a64,6bc27e9d,4e5d2a27,3d4b43e5), -S(a2b27628,aae04348,72814af1,392c5872,1b787dce,6a78256f,3af5fb33,43fd9fd7,d2ac734b,639aa92e,40362fb6,42bd3de,9272c6de,81cd3c56,c802db25,1e20622e)}, -{S(934807e3,60b79e08,d1e28924,2478db59,331c171,6366f421,eda4417b,c0699286,f7f83c26,50e7a77e,2f760e68,7f475858,b2c2d770,195c199d,33a84324,e23f02ef), -S(73da18c8,9bfd61c,b2b6cf49,f776d53b,ff85de5f,796bd870,efd66099,a97ef7b6,fe5b0c10,1c109bf4,5112ec0c,205c1fdf,6feae62,e907c57a,c4c960be,22dffc8b), -S(19239b6e,d7dfedf2,6b926ff6,72905d85,1b0b39b,a20d0ac9,d24dff81,9aa44b0c,68108879,65ac0e8b,e19a9feb,70980400,fed7d280,a75f1990,65b911d6,39a734ab), -S(e03b6633,7b60f200,38d28ed4,1cbe30d,c84afc0f,1bcbb14d,40b73636,2ac08147,e3dcfe11,5065cd9f,f7ef8225,e9ee3685,fdc1c8e0,66306022,ca5aa599,977db560), -S(7f1744cb,eb8020db,13d21f53,81e7dfdf,b98624ac,ab4bfbb9,1dec9f5a,ef410ec8,fea6fc12,7ea0ebd1,bb3772c9,499bfde8,cec1cc40,e33b2e1f,a4fddf45,d03ce9ee), -S(b1d67d78,979a525,2093be3d,cf10125e,df13734a,eda07905,ad2fce0c,11015bc0,9d6872cf,b685ca9b,42e808c,8f854da,ed0c3939,40ccbd82,49856e84,ca2c9de6), -S(cc9c4e59,fdb57caf,bbdb63b2,f9c8d283,5d332666,96beecc,28d8c28b,2bbd4df6,a8aa77ce,fbdc1413,8d9889e3,55338948,82a8c56a,3c80516d,321d38ae,27c55ae), -S(c0a0db13,6f2dd096,412fec0f,6fb2652f,63346063,559525fc,1da8c67,12e1bc30,3b6257a4,13efda21,623c63f0,d78668d6,93dad095,8653942b,20b8bf3e,ecf8d542), -S(72abfdc9,eb47ad36,86fc6428,42d99247,d6331a5c,113f3f04,b5ada07c,dcf7b706,79cbfce7,65d63523,c7b02011,af3135b3,a67be602,c8e87754,53c45f6e,8538ba70), -S(85670d7,4dbf0d13,4c0ebe98,7f88972f,82fea44f,da5bee6e,8c865ba3,6010e45d,8a7b053e,f8336fb,a9e198c6,b8b7707c,20fa2224,a5d239a,7e40acc3,699d7bdc), -S(21c37875,d3577979,8693da88,85d2e0a0,5faee58d,ea74b21,782ad05c,7108f56a,30f8e75f,6f7caecb,ebf8353f,f06264dd,7b5638f7,fbe48e70,c76b0704,6ac2e3bc), -S(f73ef2db,94358b7a,ee9b7046,8a345c4a,94845bf8,daee156,f5fa9332,c9c2cb5,cdc5fde9,995563fc,612e8e6d,bcd21863,f8e83162,4d3a85b4,9a3d750,665c635), -S(72a27f5e,12944a7e,6406cbce,dd90c43a,bc6c1016,3fc0d325,f3dbac3a,156a2767,e09d85ec,963ebce6,26cd0f2f,16d882fe,488d7bd0,9888a2e5,ff05f570,86206a9f), -S(1e6f7788,61257d8f,ca81902b,394d9815,26f5a703,688c0636,a51853bd,85f05ead,a10cb6b5,e935cb46,cb1239a1,3d08c85,bb387812,9c21af4c,5781c345,f8a3ec5f), -S(ec27394b,44d9f24d,59384965,4c3d3662,a9a45cf9,cfa23557,9320c4bf,1e1dfc17,d28e9133,89c41173,89b8b665,b7ec1f7d,b2cfbb6c,9ff7363f,1f26948,517a12a2), -S(e27482fe,5e305f85,a4ecdc26,22f25c06,ac7f82d6,230b8c8e,4d8bff9a,8a78db10,e426cac3,b02eda3c,1b1f90e8,76f9770,29ed1623,62df1ae6,e68986ac,c346d7d1)}, -{S(accea070,aa6709bf,efd88be4,bef1d485,a0da83e7,ac9a1eb0,eda8387e,b9fe666b,93fc1c9d,fed8fff9,60ef750e,94dd2342,5fa08c3d,8eda3eee,7f51381,196080e3), -S(163e8e65,fb6e7ca8,585fc072,3750bf68,fea588de,5e713e7f,9538dbf1,1524dac8,1217686b,7ff2f144,88d5c121,df15026,b6757b8d,e72b1303,b830f516,4b4cf3c8), -S(7bc1be5d,358d6d0c,a42ebfa3,7d208024,d3b2451d,fa0dd7dd,d6c43159,76483b08,42dbc796,2228db1b,8268dfa0,2725fc82,5814a893,dbabd144,ec5a1cc0,fd8e31c3), -S(6fd5e39c,872cdd15,19df9822,6a0f84b9,a5cce99a,b72d3d54,27e24d24,d8b9655f,7969aad,162d6db9,973d2f9f,a1475ccf,39eddbe1,a205e28f,54594ed0,108136fb), -S(d65d659c,adf25d7d,6ce5fd2b,e8794007,6a4ef262,7284bc70,c4557021,4239e812,c1092daa,39ab1efe,480823f0,6038e5b0,35e1d2cc,1caa879e,1b7d057,8dcdd241), -S(754ebd39,5f6a7a88,b051016c,3631ab36,68733921,b9b95386,d924f6b7,aaac42df,95a20483,80e9a9ad,6b165cce,db441b6d,e439ef5,92802fb7,e314387a,94b2624d), -S(67340806,fe427a46,b9c3939,3dc5c7e6,680f5a3a,275c1008,408a2a11,ec43e2d8,ee7e2b49,b9e508a4,e7a3b6f4,72ec3a51,b4bca79b,897b08fa,e9ba77d2,90a0b4e8), -S(ef822b5a,2746c477,4f4089ef,a33f39e4,2e4e3675,69cb95c9,a6b75148,c0e76e86,9784c76c,6d35e6fc,aeb97de,6daf3401,4e594b81,c862e8f5,cd197e08,3a180888), -S(639bf346,fe9a3915,5a718e2c,c4191bba,4985c628,b5d504e2,de39a421,ae0b0415,d1bb783b,4bd96366,c4e9f82f,e6544bce,df39cbf,592a4aa4,7695182b,b632c443), -S(5de8f2dc,825fdea9,a0fe2aa9,a49b38a8,6f23e639,ee25668e,7445b607,df79ed02,a1a17c29,df23dc19,c013c05a,25094dfe,984591fc,a825aa3,577dae9d,6bb1c513), -S(467a55e3,c7f904b6,308f943c,fbf1c9c6,c8489622,9533bd31,5b008c0c,df5c6e5c,59c10ba7,ddaa2005,a169a884,6f5bdc83,633d260b,762a6bab,2cc8d9bb,401d0ca2), -S(6064e78,170d3667,b0226c1e,628c25bf,3fd01939,132f6fff,bec47896,9cef1880,d74e855,68d86986,f8850360,e74faa47,697a7ba9,9d7cf241,fd131af3,e90b0daf), -S(8dd19520,5cacd63f,7586954d,3f1cf4d2,25303baa,a56bfab4,c25fa9a0,63621dff,e772ecc0,dfa4fc98,9b6ac1e8,4a96e4dd,f1cf84ee,37e0a2c5,126f3dc5,6b8bc142), -S(178ca7d8,807067b9,253ce61a,cf0b49d7,1f973fec,62bbaf65,1af01974,c102ad33,293ae890,98cd4157,db11f6bf,c46414c5,47e152a4,e5276433,6d3a4ab,f9f2c798), -S(49fd915f,42daf79a,648d30de,c913616d,46e89e11,afb9d46f,b18aea34,e4203d2e,c94be4d0,e2ccb36c,c306aad0,940f23d5,20c2a29a,4588a78e,c4a8d792,2d96bf9c), -S(a76cdbb6,1982ae31,8b5d3be4,eb03cefc,8958abbf,578bc99c,5081bb2d,ecca6328,8f0ad9de,7d0a36e1,e27e5bb2,9510734c,509c5f60,c905982f,23865986,784134d7)}, -{S(a488f83,2bf3e57b,5225f748,754ba2b5,cd9657c7,175198ae,122c3d1c,ee336ef2,4e326d40,648cf269,2db42532,55391fca,5c2b48d7,44a9e39f,bd1293dc,827e9021), -S(c2e4a4bb,4cc75a7c,4e5fdae1,3b6910ec,7056bfe4,5c0ab7d1,2146bd69,5a7eaeb3,72b2d74b,6181bedf,4bff36d5,e1162304,65ad711e,c13c099,1dbf2b43,c567a603), -S(9e95d628,c5278b1c,56863ad9,e595739e,8cf36103,75e29168,5a5654ba,562292d5,8abdc7c0,8a472f49,4279be90,6d575b7d,17fbbfe2,47d97022,533fbdd7,1d4ff8e4), -S(76fa079a,2b9a0dc9,3a12d28e,cbede965,e33afdf6,ed28f3c7,c7d5295e,6b26943c,cdd558,61e9b7f6,ba779158,65b37c6,ef665077,9344f7ee,6e8d4b3,ae658c96), -S(a0269bcc,a3d91987,737ae43f,2d1b99d1,18a139b2,5d5b4ba9,cab55c62,66e4cc78,6febb984,7682c796,faf098b7,60c5ab58,b1688f3,49abaf25,3456c3cf,d60fd361), -S(f197660b,f5d0e191,d2a75f95,4230ad48,4e28027,f5e61d49,64f02fd2,b239b18c,cd05cec7,3eecdbd8,fd186f5e,73d121d8,2ae2df03,29bd7e44,408bf7f8,5b3009e9), -S(584dacb5,735c38ab,366ebb74,8ecba797,5be0576b,a52eeec8,c6fc353f,17d783ca,198e2b4,5d1e6ee2,888581c6,5dda9b44,a2441d09,4945deaf,77232861,4d6f0c98), -S(eb6d53e9,4f34c551,9fc21d83,f2092221,457e9697,9e535980,31c5a853,615637e6,b958d521,d74b297f,6e537d1a,9512c5bf,74a3a134,b2354d21,b24b30c3,1eb0e607), -S(d32c2816,b28e0bcf,d477c631,7ca9cea7,51c3d7a2,a4d2aa70,b6ea5568,63581e21,7e42e895,c6cc4eab,c85b2bdf,301e37ed,359ac182,ee1d6843,a3c1c7f7,d253cd0c), -S(bab8ec85,d297ac61,8aeca643,d3e54750,5974d165,4a2031d9,3fe2a865,7efaa8ca,f4544105,4f81f7e9,1a8c773c,369689ff,ee5b286a,ea652d22,7812c8b0,57ffd710), -S(7d75e064,5542097c,d70982b2,92697b2f,c3439a6a,26f1d51a,15766ba0,10c80b5b,9868b21d,2fd0340b,712b2958,ab4925ad,d22eae92,1ca2015,5b578d05,14019501), -S(4885a359,cbdb926b,3d2918e7,a7bfc8a7,ca9c6a8f,870824aa,fc2911c2,be3be588,7cfa2021,bc9eba8,27729709,ba83cd2b,d6c1d68b,2217dd07,c7af1977,35ce7206), -S(52c4990,8a3b1b8b,3eb084f5,33f5f559,e9113d53,8d753027,3b1f9bb5,d0fd03ec,adf0c562,21176de9,b5d54273,97feec53,735f430c,44082b1d,7233ad36,472815bb), -S(b07e4e7d,366026b1,e4487f0c,3a2d6825,909f526d,dfeae840,334fbcb7,b1681beb,26d3eb64,c795a304,f226b341,d49adab8,4b427557,1f683268,140853fb,dbf65459), -S(41d028a6,260d5c21,f3d31771,eb876c10,189c367a,b513b761,2530e974,6ef3b4b1,f8b295c4,a2d2d5cf,1be8fb36,9d2472bf,85263bcd,3a36a42d,705d2555,1a501791), -S(da36f37,ba62c357,1fff8b97,39d77d44,13ff457d,5933e77d,e4dc3d18,7bc601cd,ec0e35b6,6d1ef946,7f59d7bb,534beb75,13f8d2e5,1919d914,f10a7778,4d4abbd1)}, -{S(a473de46,a554667a,368fd573,168dea23,3f81153d,e1b35b26,90da8863,71e6c131,4ba0b462,92aed936,7a2bf9e9,de48a08a,874fd681,aef86a15,58b49e4f,13dbbcec), -S(ec3a1d66,a1f76399,c683837b,7b53e05c,5df3ffbe,325d3d4f,de12cb19,c44a8fc1,73392723,41f63fcc,d994c0af,d1459f82,c5479fc8,1628b8a,34b4d042,e68a23cc), -S(8de418b2,77aa4dcc,11619e6e,f76d6a5d,8ae48448,c6dedccc,f32b7238,b58a2e55,11e44fa8,68811549,8a7cf95b,91eb8c53,7119ef6c,3b9fd2d,37f428ce,94060ea5), -S(eaef8564,efa35058,1ffc48eb,329fe037,60b85bf7,864a433e,70b5e227,9282fd9d,90eeb6b4,c3252fa0,ae0ff9c4,ab2974ec,12cd8b43,8af9a0ad,64b8b3c,e404d35c), -S(6985a408,1a00ef94,ac404379,dbda4471,eb99bb45,69c90da3,241743c1,afa865e6,2485252,3273c205,8321276e,1cc4af69,380642d,3e2ec299,64da2d75,b17f3865), -S(df779625,ea469eae,1463fa21,b088cc70,6ac9d3e0,9c4ad69d,554222b7,7a2bdc0e,56e00902,4defe4e0,5f097ebf,ae0c4782,a93500db,bffdd525,8ab8ecd3,1253f224), -S(1a2d4b3f,29fec403,5b3cb811,147d66bc,70fcc480,4f07bc3,169b592,e4622665,600cc9e2,370d498d,d4db60ee,963c5dab,8da8a23e,8db3cb01,d805ac2a,d77ddb46), -S(2d8e71b5,17971a2e,351221d9,44e82447,e913772,216a4c40,f067087d,4106aa7d,d9284393,ad9a63f1,2e0981d7,aa9107de,21a91a16,ba43a25d,26895b4c,d793d525), -S(b53f44cf,a4f24aa5,a57aadf9,cfc0ee9c,d621d482,3a7046d2,8058f086,cdc91b1,8148f9da,95142591,dc71b505,ee60dab6,a680d0c4,1ddd1fcd,d59aaa3d,dd4a901d), -S(f31db738,2a3f41d8,d4079efb,cff1e3e1,e818b2d4,f83dca09,4a044a73,d64a7452,8eae5b98,cb9e9dd7,2a9332a5,5abb49f8,9bcd4b0a,d8f6913c,e6c1cafe,294ffc87), -S(7ce5ec00,ff2a3001,9eced47,3a891bfd,f2c2a9a1,8fd7e18e,3999ad19,b60d42bd,c514419e,272c3380,a7ce5dc,1883e7cb,2df64c89,5f2a730f,cde2f3c4,945b6ff7), -S(57ea4789,f7e02c29,7a089cff,9ae71fcd,f511cbc,926b9299,25a1e184,c6157c5e,c696731a,51132560,c77afd16,15cd5072,4cf0d136,7c4fa3ca,b19aec05,a8d701fd), -S(5cba3f4e,8aab710d,878697ef,9a1ae299,821960fc,caf88887,9c6f38db,4be1dbe0,336cd748,99412e3f,9ca14d01,2cebcce3,42ee9e97,638cdf3f,df5c0077,8d3e37b6), -S(56b0894,7d551fe1,2e9ab57e,a70d342e,3cb74d74,f549edc3,f7551eef,ca9f9fc0,e7ac85d2,a4baa20c,4e1bab03,7190490b,e3574ad1,f9cbc392,f28f45cf,db4dd2e1), -S(7ca03c7f,ab7f76a5,a258365e,55473083,5a9850af,6c83c311,b487a8c0,4ba87a28,1d144504,193db309,170a3ca7,36b39bf,46d08596,552a2962,6a3c40b0,a8f95e4), -S(5d041b98,b864a305,117791ec,21de3fbb,cbe58a84,8429d291,bad63895,442c9fb,46a179d0,decc9e6c,9b642c1,5fa126be,619872f,17c6273d,30e2ecb1,1d3c0252)}, -{S(476d7ba4,35177a71,299267f4,14ef275d,48b434e1,380c1afd,9fac4606,f8e02be0,7f1255fa,57a60447,c14d6574,1d7774b9,695e6d25,1b46912d,d33c77f3,f756edc2), -S(c68ac953,985c624e,dbbefae0,148f049b,c9de0f23,7b192e7b,e8f13921,dc478295,77efcfbf,a08be5c4,632cae8,c7e9e6a,520ddc19,dbc1271f,ad0070d8,366dfae1), -S(31462a8,ae0be4c9,b3d7a28f,3fe28e1b,994961a5,80cdb3ce,4ced5b5b,20077b77,3137a2d3,5303daf6,441b0ecd,244ee32c,1c87dcf4,27449c65,d3cd9bc2,6189db3a), -S(d78f7afe,6bcb8574,27dd87fd,3869e74a,760045d8,1841a895,f8e78697,189ab251,8e419b36,47160117,af77b5c7,97e6d695,65ac587d,ce16b94f,c11ae91,72b8eca8), -S(827f5436,f983e162,42213577,76403af3,d700ac7e,57e10ee,53985649,19922086,9f64f7aa,ff4c6234,5ef6017f,e027dbd6,26592cc4,f050ff48,ca4c8fc7,5ce87356), -S(6ba0ce5c,6893ee03,629f90e7,841790f0,414410f,8526e56a,b0f74f24,f5c2fefa,25d44a39,961099ef,b341c985,d1f7604f,298838ef,422ccd0a,91195f2,2b48e7d7), -S(2c43c784,bbbcdc5f,34789f99,46a9a5,59be71bd,3fde6f66,b6faf050,99b4dcec,4e5fdc4c,83eed83c,db5b5030,91bdeac6,a70cd8e1,ed187ae4,469b9057,18fa5386), -S(4faafbdb,1806f138,a265e889,db4bfeb7,ab53b2c9,622ed6b4,c6b392d3,1f7ccf07,d1843334,387f73c2,da122ba6,a633fc2,26fa3f70,e42d41a4,561e111e,aed5b357), -S(143b5028,c0bee52f,9dc11734,292d62b,17672d64,559ed0c7,49e02f20,8bf84bfe,887d583f,b7d6c57e,c1c58895,aa99ea4,7ff5406e,fc5e15eb,3d8db3a6,e8cbd4b1), -S(394ff209,a9586a19,396143ec,f8ab1785,a661b80d,8d2d9b28,c66c372b,add96e03,5ce203f6,801bd8b,92a673b5,486f8f03,8bebbcb,bea85bd6,7cab24ea,92a54895), -S(3e2670a7,794a06f4,2928430a,8bce2866,eebb6e38,90fdbc94,6b2c794,d32f0452,31d2e49e,9a6ce422,36bebb25,cb243965,6aa2a1fa,6712f17e,6d5d2b58,ae91c3b8), -S(c4cb5059,31eb4fb6,66fab44b,6e063435,35699e3f,8c3d4957,b971a271,78430a1e,9fb4a0e3,8d46c234,eba2ecc3,8628150f,41cbbde0,734453f7,c65f2444,c52a9565), -S(695d0e52,b32cf29d,2230b84,c1260595,8470dfe0,713aa116,61710c,8ce74e91,f4ade5d1,6d27de08,78d907aa,34b61f91,4135227e,97f0979,f4ff6241,4164ab5), -S(5aed2254,27ae4f7a,92292498,a345b20,49b00c0b,284d55dd,51e6cc82,154a4cbd,6da49cd4,5a48b051,f20987d5,415d58b1,9a4e1744,d83a5ff7,6bd95cec,1c6dbb11), -S(390aa9f6,18e5660,cd158531,7d0e01e5,5e6fb9d2,aa785533,6747eb80,caad2bb,bd7e8ccf,34e718ca,947500ca,a2d7e3e9,3cb0c6f7,d8b7c50c,7aeede81,95d0271a), -S(41ff7ecf,227a0f62,236265b,1bd5649b,96666154,115a2840,c37be05b,776c85d5,fa47dd69,a1d89724,f8801024,dbb52b83,d162f2e8,b8614224,4744afa3,530aa1c5)}, -{S(4f62ab4c,b7fb0d13,12620121,9841e932,b0de312d,674cd002,315594e9,81dfb3a1,1145fdd8,c5d16653,a9129b0c,39fcbbd9,5968d22c,ff2127bf,91e89847,35e2834f), -S(99813c3c,dfbda83c,a798f7df,5ea4f172,3de535e8,2f257577,de67250c,6e11370e,38bdd34b,18bd081c,83307a5c,fea76990,11a50437,ff93fc6d,aa22f9fc,d5021226), -S(75771c9b,9b6e8b88,cedcf4f4,3772b3c2,45f72319,7544d57,c6c920cc,137aad40,d8867e96,7b79997,c0526603,a2a6c201,18d93115,4362d804,1542e3d2,51a8759f), -S(fbc16489,7bebf96b,ca01a281,f2ca36c5,dbe51bd4,1a465b43,3311e163,16bbc85b,7959724,16729f2d,9ade6f1d,97157761,a81baac3,fff31e85,13b9989f,12f72175), -S(2d625707,d2c68919,8ad1b321,d60f6ba0,5e106abd,41bfe029,cbc60bb5,d5e0ddc4,5b3e78b2,a007c909,3722440a,d40c2ea3,6f71717b,c5822eef,322a13ad,614ba310), -S(cf23f492,64ab8e60,afd8c0d3,a8a6e938,fb6a3b06,66b9abed,23b6cb45,d5b33a78,479d121c,571eb9c0,e24c14eb,b3be4816,1363d752,fba522ef,a010ee7c,324be8ca), -S(c2f0f458,e56f387c,a92c2def,f02c3e44,dcc010e8,c2b7917c,751121e1,3e49df7a,d2bdb0a0,f56b97a0,ffd8664,1b34a1f,24ba9123,d089b256,6a50126b,90dfd936), -S(4bbfdb7c,8b393fa4,bdffb5d6,cfdf0721,d17e03d5,ff142b34,a0741039,4c84bed6,c115eef5,b815b3b0,c2f2ec4d,98b6a09c,36d8a320,2f81e777,eeea800c,662441ed), -S(49868964,9201341d,bb24a12d,ac0cd8cb,d973640f,19f13540,dcc9d21,d67a7d76,3bcc0077,5c6c7256,fe0e1d3c,a812ce2a,c16294a9,7b9ac6bb,32f796c1,3a2b50f8), -S(a1e22bff,d0567bc4,f0261a3a,db9c918b,a7d81791,d68e99f7,f8247ab1,1fa7591,9d1c7ff0,db87b176,5e284432,11299012,94ce44eb,31a4d6bb,49fc3cc6,d4735aaa), -S(2ad5fc7b,610a3ddc,e4950765,a86b12,e1f5e0af,89da287f,c930c035,b81fbbd0,9fbb7378,36c20ee5,bd5c081f,5588f57b,4fff0b1c,71a9f334,cff1df26,60085c82), -S(fb4dde8b,40a51684,ee59627,d5adba43,50d2ad89,3b0f4aac,6f7a9900,22b0fa1c,753d7603,674cd3cf,46ef3a5c,e19f0d8c,3be64921,6a581cb8,6dc62674,abfb221), -S(f36e438e,9180c9a7,19679a88,51f96690,6dc096ae,4a86e60a,a2a72bd1,b06ddcfb,3fd68d3b,64d890f4,aa653b0c,5a670273,a53409e9,242f0ccf,fb7ea68c,c91a553b), -S(7ff1d3bb,8de59536,19b5fa0c,9519cecd,fa121bde,ff31a689,65c18c42,d182e4f7,2953d0d,7b0d215d,f75955d2,97a8ce92,4b0f6ce2,726b29c4,2b7a2786,a459c551), -S(9385aa58,1de6a3c5,4b479bc5,8823f699,e65da4df,bfb277d4,b56b76e7,c41ee4f5,95d109c0,5e67ff73,2ef10f46,350a7578,f7aca034,962a573c,707b3977,97af5c72), -S(4f3891ae,e86c16d7,73237e7c,d2db7c7b,7ba260a0,4b85f6dd,91e2443c,bd21c831,a96dbd49,371bb1f4,9ed1dc90,17927def,30810e2e,b938de57,ab5665b,8de5e86f)}, -{S(110f05a7,489138c6,51e48771,d505c7ce,68bd6e61,67cf4c3,3933441f,a236f263,761652d,178d0d5c,f6189501,d02d7078,2f10f835,27894d79,4f93dff6,e90a3b16), -S(928df081,cd85c375,e53e825d,4a250160,a1a893f7,95e0a9b8,5378942d,e206a1f8,1f86b51c,49582064,f21e9673,3786eff1,dab4e713,69273cbb,9dfb3d7c,2d930fa2), -S(ed504706,702b297c,e62c2788,54a29419,e7e0f76d,d6eb602,e0defae2,8f74882b,67f3801f,31e2c8f8,5c3e409b,b104323d,ee41c794,802dbafe,ba832409,4efd3486), -S(d620c03f,dad08f0a,a67287d6,7b68e8ff,57d8fd09,2ecc0731,a236db54,83d897b6,f2a66048,6520abff,aa6cab39,b90c1d3d,89ac4738,fe560114,94117a73,60f30a41), -S(fe57b1d3,b1b33889,148509af,29a3c797,3bc726d2,593b14b,1118580e,6b8fc04e,d69026bd,820418aa,74e6c115,b2bed0b,d4f48cf,f1022367,230679e9,7d878547), -S(1de846e8,8e3bf169,465b4d66,6c0cc230,36c0bf12,b35ac6ca,5dd59935,59c11063,d925394c,c8eac4bc,31a49318,1821560b,bbe38d67,ea0040a9,42a1747,defb69da), -S(7a4dd28e,3ccf40d8,7ab743fb,6011acd3,981e4322,486d38c,6b6bd69c,368e9391,89e0dc28,680ddf3b,1a6ee4f7,b2b5a0a4,c417a9ca,4cdbaaf0,b08b4de2,e2653010), -S(593296c8,840e55ee,f7477ce0,e9d5747b,ce2a24f,e5e518a6,7813da6b,347fbd26,7ea971f6,37522c0,f0bfebab,17fef91b,8216ed49,1a0ec5d6,55f12062,6344c124), -S(b784949b,4228eeb8,b8e9979e,fd7309d0,3e5e3a2e,e658b017,86b664e6,db7afe2d,7f836c1a,3f93744d,e4f0563,456e3f36,56b536c3,1e8e7b39,5c0bc78d,9864910e), -S(2298a36f,6e66645,5ef8ac54,a3564c12,59b2ebcf,3a1dc1c6,8f290f78,fa366974,da9db0a6,26701765,293d39b7,1600c991,effb9ab9,2bf6f95b,a65f6b2e,9c3477b1), -S(253bd683,f5421bc3,4bfeca7b,5b48e6e6,d1db6398,983b451d,6f327288,513516b4,61b02eb9,b3d32555,9692df42,b4ce3267,297aa78b,7ac94afd,c08c3534,3346f8c8), -S(cd328c8f,5aa7ced4,d0b0744,39be20d9,f44924b9,c84fdee2,8363fc9c,1cfc80b3,9b0dcad6,5365b7bb,822c2c73,30105fe1,907e674f,9f11b13d,63385bba,b3278d3f), -S(29c6e1ce,3f8caa9c,d366a0e2,3b86fc16,986c3d12,7c391b2c,aee4ff5b,5c229a7a,dbd8686a,e8f95d99,cd7f133c,3211620a,b02d341d,2a50d04,e27a2430,de9f8371), -S(c2a3ace5,382bdf5d,a5dc3c5,9994d92,88efd495,32a3f0b4,a129cb69,a77fdfc1,d79b9211,55651adf,bacb249a,42ad5059,9bf0eb15,1d8b91a5,f6033c13,73db0480), -S(778c13f2,1cf131b2,86bbe8d6,9c4913bc,a0932939,a79a9446,a8c908e8,bfc396d8,963bd25e,461b56af,990fef90,5af101a3,a96299d9,44ffb8a5,e6c59359,a4d0129c), -S(c65a9cd,15f3b7f4,c0f668e8,53227b2e,4ac01865,37c58514,165b6bac,93e43112,ae0f8b04,1d5dc2d0,7a8688e5,ffc70da8,e7d5b4aa,92faa455,64fe31db,2d24929d)}, -{S(81f4223,6a39a14e,d2764665,22edb719,f2fb72b2,c571ed67,343e2c57,4fb60e5b,34f10ee5,6c1d5e02,51e8ba8c,9f129391,521f0601,2ebb4549,7377967a,d8347e4b), -S(bc6f8e27,8bc0f3f8,6bce4dc9,8ed98476,b4d7427c,3e3f3a79,f488d8bc,3f11313a,5a54bc1d,4b08aefd,53d16afc,79b5065,b637c0e3,d74dd46,62728307,ff6c7611), -S(259905bc,501d58da,72ff446a,315b9f75,89df7c14,4d9cc937,bd962d74,12ac343a,3c233cbc,a1660e91,fd41cce4,674386a5,d949ddff,2477cbb3,737e03f3,3adf25b), -S(5051c982,aa4a5d22,d8c4f57,42130c23,4665bcb3,4cfe0567,dfaf3e4f,a03d9721,9413cf4b,50784ad6,1afd8a6b,8ce23ae4,80480b86,6c08ac48,24379d57,8a4062d0), -S(c0158ef9,e70349fe,2d32c1ed,30c87c8,90de8ceb,46ede75b,2addba8,de2b26b,b462c3ff,b14bd8ba,c167709b,dcae0d46,a908fe55,2789e2ce,c5e43d62,b71aab70), -S(740d9568,b420a2dd,389b3fc8,67065e00,10eb2961,56eb6774,15755b4b,5e277ebd,eec4d9bf,693994b5,13ef673,987ec7f7,2d2c767e,9b41cfd7,858aacc7,edda7aaa), -S(ff333278,480b444e,99b65b7d,926675ec,6b16a64e,dffa2b75,9c5410d6,5fba02ee,1d0f842,e584e31a,480c8202,1824936e,e2f717e3,df72412b,155dd2b3,fb1aeb4b), -S(79b0a263,dd3a2b33,31d1369f,8e94cc7f,aa9b8364,2918f9cd,aad62d9f,7a5cbffb,225dec00,4437c7c2,2055851e,1c4968b3,f699dfc5,846c373a,13bec08f,5cc3890d), -S(2a12e289,7cc085d6,30996a53,cd9b0e64,4dcba64c,7a9c4a5d,c4affde5,42717d25,2b8e848a,43566c29,fc5242e0,4892cf58,1afb0667,9bb15b87,69252962,637e00f2), -S(dbf0d2c6,29bb1f42,10cfd3e7,2d119391,16d23a94,fe0c2828,9140a498,1cdd0749,54594d41,8b87961e,b6486d09,f717471b,13f4d39b,1b82484d,8463a4e7,b28ba974), -S(2a1eeaef,b3478200,de3fea29,c1368d22,ba52fed7,1175ec88,4325833a,e93ec8da,1220e686,97e0347e,d0117f98,ce8929ed,eac74f0b,2fecab82,11bc5eaa,638742ed), -S(8ecd4b9c,beaddc70,f20c09cd,67314d2a,3cf3c115,44cd3508,e74050ed,16e9f34e,52ddfd1,795af7cf,9f083a22,35c15084,87bfbf79,4e3af1f7,2183790e,a27b73c), -S(82ae9584,b592fdba,88ab48c,ceb9ff2e,b95f09be,29ad4700,104bf18e,bbf3e036,ac06c9c9,4d3f79c8,8ab2313f,dd507808,36cfa91b,f65c06d,76b547b1,24067fb0), -S(c3b19b24,35c6c07e,4d3254d2,1e0a30bb,21c2f45f,68a441e6,925c3ffd,72b230a,3bdd5ded,600a0c77,3c620ed1,d9545662,af5f3ec,b3b0763,6022a466,866aec3f), -S(49622f79,9672c94a,26f86edd,22e9e5aa,b8ad1a62,33abddc9,fbbabbb3,3fe276be,c114c6bd,f30f79c4,194100da,847518c4,f5688a3b,70dd60b6,c4f765a1,cd324d6), -S(c07b88f5,cd465622,2fdf8cfc,c7191c4e,a3dd6d18,21adf780,63d62d31,2b9e02d,e601c411,839e2371,8136fd1e,e5adf8b7,c5e59969,35bb152e,955d2ffd,58964059)}, -{S(2dc8f27b,b3bdcaa9,2feace80,f2f6212f,8209477e,531e74cb,f497372e,9a2f2263,7feb63a7,96b55bee,ffa180ba,fef47776,fc4fabd4,2ccdcd97,64b4bab3,10350790), -S(ac8dc04c,1c1b8c7e,abad287f,a1f62206,f307ee19,4ba04fb2,fdc0a908,98a13387,a06c53ed,5fce8db2,a52ccbde,38121da,fea83bcc,96482765,26522b5e,d762b0ae), -S(20c34368,618099a3,d6713278,7f2b5c9f,3aa0d419,40329291,3c97237d,b44c9072,e1d3f30b,8c4f9d31,df2dbcc,435a0bd9,e4ab9342,7df8f04,90c820d7,dd620444), -S(dfa3550d,49bee1f9,304f5bd2,5deb92ce,b1e5d49a,4e3535eb,5b55d429,e133d559,1ddc87e2,b3cad5aa,922391d2,b9bb11bf,a3db93cc,244dcebe,147eaaf7,610caeaf), -S(40510142,20037393,7df28434,48899fe7,2f6469a2,1d77e591,d77d2a16,b3cd9aa8,588afafd,85ed985d,ab38fee9,306ef133,ecb087cd,30ac939a,ff13e1ef,a0b658fa), -S(120068a2,65e77949,5450c83,c6ec07e1,b6825840,ca7a00af,6ecc6d3d,9590e73a,e2eff01b,d4aa986e,dec9248e,f69d747f,65dfa98d,537d5443,c1e7d9be,317d371f), -S(52a1135,9611cb35,6b71c05e,c0376ea4,27c9938f,1191cf3b,dc7d17de,9c29b39d,6299f3f3,2f0bb14b,f1c94b36,88fcc301,cc25c90d,def2f2b8,7b0d0050,193c987f), -S(23000a37,c68fb1f,4ab535a2,db033b76,10f252c5,7de5c03a,47502282,1200ea26,3ac23fb1,f0a42714,829cf914,ffada79f,234e1e5a,dacffd5d,34d3ca52,976c934d), -S(810aaf67,f149fb01,a64e25e6,55888a74,f6eea8b3,c5e96fa0,9fd9c689,3e7543bb,abfe36e6,3418a26e,7a19f2ae,aee72cba,416880a1,770e2bfa,79eeff32,35885e82), -S(cdc0b689,5afbdb4,f1c9521e,280cfbad,7b543619,b8d77c2a,20fdfcc4,66129e45,9d59f91f,bc3894f6,820fda03,ae13748b,572f9a2,d06dc312,4f824831,778d62ff), -S(1bf8e290,19706636,e5d2c34a,39de3f02,331460ed,916c17fe,8e36d097,9a5edcac,e15e619c,f4f096db,1ed1d51,ea5208eb,41625ee,6546f40e,324b754d,e0e202c5), -S(e54a04cd,f5893d80,1a1cc8f6,9dae01e5,34b92457,ab7319a2,4d2b6c2,78f57f76,8103dd9,b4a89691,b079aad5,71267e5a,f601dc04,858f065e,aeed5e92,34dffc0e), -S(711f6808,53d18d8b,911e2342,a301a805,a1c76c2b,b5987775,f5867df,e2325d00,91630ab,cdeca550,a32e9df2,30f02e64,983eeb89,396487d6,4b3c9d59,8350ca01), -S(765b24fb,d42d4d4,a9dec609,48ce7f91,7c3eee70,49a36373,9e44297e,3cced026,56408d2f,d859a211,26d14e77,81302eeb,87371c17,b1f9bf50,9e15f545,c240b79c), -S(b68f07de,6b13a7ce,739a7e9a,1c6a526e,d1df5cda,b7fad149,df46ace,3acc9919,5da1b851,a81fe645,47ef84a8,fe9a39ce,fcdc9abc,a3e95818,b34860f7,f54230bb), -S(d98bcef6,cb3e4a1f,5b9ff8c9,8ef7138d,ba98e80c,200113da,e7508497,54954a96,456c5f23,96fc1c71,79f6b3a3,a82d8bb7,8ab73d62,61b6a098,77527964,5ad80080)}, -{S(118d5053,fa3ef05c,810cf906,3a410f53,38a9e6bf,513b9a7f,5259112f,f84ad7e4,a371fc9b,c9182528,27d6c842,32e4e44a,9d32eafa,84f1a02d,a86039d1,6309e92), -S(ce68cb2b,ec0e3f64,ecab8273,71f248b6,9b25f4db,94ca333d,c8d3595,e6f4db70,a8355f23,f22d8225,7adc9865,55350250,8c0bd086,ad7d8b74,ec3f3ea0,ecc17e88), -S(7834c202,977d96dd,d2897bc0,b2e9b093,6b3bb91,36f78002,85dfba94,cfde7d74,62df13f7,87aecd0f,5f299a98,1b4b6763,82b69aa4,997c8419,1f93eee5,5a8da0e7), -S(5dc11a79,34d41b29,5b384824,89cc2fc6,eae9c348,2baf631,94023e2b,579b750f,bc8719da,924cd9db,901bd524,a5eee1eb,fc161286,508e192c,10f3b786,f167057a), -S(40f1348e,a0032b45,3f2b5339,d687a06,3790503,b4cc7b5e,374828dd,5374566a,b7c04bee,58dd65a2,b5417ed7,236557a9,5d90f89f,2f9be760,408f3806,5ec9c1f3), -S(5bb43572,6cfefc3f,dfcc3a89,3abe627a,3bb9fe92,2dc39256,368b630a,1bbc91c2,4266fcb6,cc3d664e,72943e33,3fc94db2,b76b9b43,1e5956a5,5fcdb36b,27d175a5), -S(c61ca2a7,48faba61,93325019,dde522a4,b4ad7ffa,ffade4ad,84bc46be,390d6833,88fae1ef,1728b211,6a24bf40,7df169b8,5987f26d,75a86b84,37b91bb5,607b4eff), -S(ebb9b8ba,c980a86b,9955a450,493875c1,1bc446f5,ead71ef1,8eeee3a2,ace3a417,77aaae20,a2959de0,8b53b7ad,6434aa02,f3c56dea,877d07b,fdff41e0,aa463b7e), -S(fd3b8946,296987d0,22123898,bffec5ec,b1072fed,c8e66617,a8d1b00b,6bbd9889,54240cbc,7512e6d4,744393a,439e8b4e,9973dc40,34c68b72,df04ddb8,b89e6acb), -S(80aac570,6eb40c4,c6b5cdf8,e25e5740,3aadbc07,f75b190a,444ab53d,4743ca1b,196c7cc8,3ce92b15,ba110e5a,ca1ca0b0,c3205f61,e58c1e4e,fec5e957,72274710), -S(450df283,6de16aa3,3b893d69,39c46224,6ac30dab,941be908,42b3d5c0,714f9670,970c934d,5b242d56,b036b8d9,4b1e8661,45181ae3,cd286bc2,962035a0,fd852a57), -S(64c57089,83eba9da,d7871fb5,64481b9,12612c20,4f2bfaf3,635314c7,3cc9bdb3,7abcce5c,fcfea03f,74665734,13a66116,d6289bad,2209253d,45e77ed4,bae9a738), -S(4692afdc,34fd208c,72726495,7517fe0d,b463d39,6ba454ab,c1b81898,cd7343f8,57b67c27,8a0ab12b,5eb4a55c,933cb45a,d6b5d955,2110762b,61fe79fa,535a783), -S(511415a6,1371abd8,c86d7fbe,4adce11f,f6cdf1bd,330eb95c,7c40ead7,e5fca53e,4adfb29,87b9ac39,baefe7c8,69aa931b,c07fe15e,5a5811b,9add7b77,1d56c8d9), -S(4aee2f4a,ab479df9,b2e1ed5e,19230669,e15d153,22b5472f,c8b138fb,7d542c30,92c8e16,fbea4d0b,114a7d84,292a9643,6839624b,daaebfd3,9d621f3,7f8b141f), -S(8c0bc6ef,25a255c9,3816cea7,599c39d7,acee681,9373b82e,96b81a43,dd267223,8ce9ad90,e893c56c,c0392afa,24109c94,2098b5c1,15468b41,e444568d,9904efa)}, -{S(568b3e2a,2db4792e,4ef4ee66,14e201f8,a847fdca,38bb003b,adb06d74,1e4f999b,7334b395,61cbcce4,49d83eed,205a4c40,d91d2751,938ba7d0,6ed9e5a5,e1ffea7c), -S(ce433da,719f5582,6e69f248,3c3db9db,de45e0ff,fa2cace9,f75cd210,433fadaf,c296f641,5200cb35,cb8e1f23,20b86cc,9b341541,b9256d77,afe302c0,1e2420ea), -S(ea19269e,945625dc,138b9e60,249baee6,8c63bbb7,2b898569,5459629,fcc7ecf1,f5a7bb81,53552b33,86deb8c0,26d88504,f6a85ac1,b9290ef6,f91c0278,2cbb370b), -S(19e8e269,b972af70,c61983cd,cb7446f4,23dc93fb,b0e3d8ba,3fd02476,477e596,3081973d,f2123602,770716d2,6937f31d,f0835148,8c9d1375,d2bfec67,24df9c3a), -S(4968feff,d34e4649,9ca759bc,8e90d374,de9e3199,a13e2b04,28a10df6,15fb7696,2936b2f5,8491cc78,38bdf347,a4ee0b36,db288e5f,9727980,810c6eac,a8d1edf9), -S(d258654b,45fe5366,3552e85,a7da0755,c4598eb,68aa96d4,624875b6,580ea359,52501a5,e7d7d931,417373ff,ce85e0fb,43ef595b,2056729e,b1daecb,91998d1b), -S(b86b0c06,76f64537,f9d38200,66aeadad,4f3b68b4,2b5974e0,9f218d81,a547e04e,52a0e4c2,b827e0b6,894ee674,88a894f7,577cf3f8,fe83ebc,9e103a28,3c054690), -S(9212971d,b38b95f4,e7b9cae1,f1519878,80ca177f,73adcd28,a6d03e8,cefe9a31,9ddd4828,3b079a75,74afcdd0,e7cc4c24,45a4e893,ddc2d2e5,d24c413e,9c676041), -S(42a070d,929191fb,fb691944,a311c931,40740061,2bf33de2,809dceba,ace68f50,5429699e,47e22e59,b6cf8cc7,dbf2c81,23d90d2b,a48f6839,db4dd0c4,7caf4412), -S(895744c5,5b460749,a1e8b784,19e8f6a2,1e53f06a,ae99bb50,df9bd94f,e1a20610,a1ebffc6,da8a497b,bbc52ebc,4de1f196,881d88c1,948b05ca,5b0641e8,c56ab005), -S(c9e8e6a1,414b54f6,c19e9ab4,bd9bfee0,86a3e8ea,7a6b3e58,80cc5988,20fa512f,6878f69a,59a5be7f,3e60c1b2,6e9b9663,9097a6ee,7facc8e0,e242f56,e9a2904a), -S(dbf66722,d309634,872fa8d4,d9ddf8ad,2d198344,41a8515,7521b491,1e9e3473,1823095d,dcf42369,f3ff23,cb3a6ee5,273b8f98,7de2bff9,67dbac10,6b76928f), -S(b133817c,f965b7b2,f5d80c05,b82049b1,464713a7,7cc80d53,1e930434,387ea7d,db03e202,2eec1d26,4cccb613,7679c6e9,e08ef66c,f11378ac,add8985c,88f5e693), -S(e198a2c6,3f0bbde2,f31b8d67,776b8aed,bb86ad58,e2896a67,11b5d5c0,fd3a8d3e,e8df361b,ef77d3d4,4ca4f7d6,c554fc2a,9e2401ba,96769bf1,503b243,8d8306b7), -S(5f3ff8bf,148ec6f7,18aba1fd,8ff0b37c,18e440ee,51beef26,59652c0e,39ab7255,5da559a9,40e22dca,bb4270d9,31acb7b0,2b19d7fa,3495abd6,d5ca7f50,d6281445), -S(1e9ca439,c93cd0b6,d9886234,105fc1b3,178ba0b1,c71742cd,5c043ed5,56045c5,f7d31c2a,1890f586,214371c9,77501788,cf162d88,641a5540,c49ce4,323f3ad8)}, -{S(7c32fcd7,13305cc7,44fc4ff5,2d315e2d,d4cdf7c0,31b41a64,db6ecbf9,fd4edcbb,7f002bf7,b8e1b8f4,a4a4f2b,1922983e,fb901e13,59cbe934,8a31d91b,7bc86bf4), -S(d8aebd7a,db0ece5b,ff422046,6856ea0a,6446862a,4d0a94ef,ac7327a3,acb201ab,6e96ecfa,e9697649,faff155d,cd01bc34,e6c8630,616dd143,1c816c4,9d1168d7), -S(7dd764e9,40746adb,e6dc9e23,f113209c,7fa75c21,7da4cbc0,dbe257f3,cc0e3064,97e244c1,a0c8d68a,fc7a3192,b1f029e8,dbc41d85,8e0b273e,c4eff27,97e63ce0), -S(394a3fb7,320acea1,cf99bdeb,fe686508,15b3b06a,500df196,c05459cb,80b7781a,ec88e635,9615da20,cdb6a16a,245c694,ff550cf,cfaf2939,39103517,653f8986), -S(a394cc44,e64c4b5d,b36b4dad,d0a458ea,9c760e80,342b99f7,5227e22f,6acb0de6,de19b475,9fe10976,e9f38b74,1738b12f,e69df952,26c20d19,5f9135,33458682), -S(1277835b,322b7118,9ea416a4,c9a51518,e3a42d8,419f723b,d2b242ec,f904e26e,ce764cd2,558ffc31,779f610e,b33be553,a80a0dd0,1136132c,6e84b142,e5f5a8b9), -S(7c7527c3,ca6c3b60,18d6af7c,9ad79f0d,461e3d0a,c426e0a8,3bc1610a,80897370,fa7dc6af,7682554b,9c6f4b9,3822bd91,46bdae61,88fd2626,6f13af48,55ab23d6), -S(aa59dd0a,2e342733,a151e156,a82d63c8,9e992530,7bd774d5,d08c327d,27409a89,f14bb267,18ee5ac4,44390439,b8727f1a,f5b62326,fbdfb36e,23ff2f08,3a60e223), -S(733fa3dd,25e41c7c,4e548de1,17572b87,31bcfb22,57f0b822,1be31943,4bc2560c,976fc63c,e29bf97c,499e220b,80bc48d7,1fc07e4f,27afbe03,fb4a610e,e79bf820), -S(d6bf5a3b,ee8b720d,266586cc,70fc5518,a577cb70,44dc30f,210912c9,f1609bdd,bbb5bd29,290cf1b4,28fd9150,db667219,878b1507,121c6fe5,b1730f05,474f98a5), -S(b3a7824b,4da122ce,1120fa6,f5046205,e2989b8d,7c4bc118,d540c91,ab1e4b30,c7e452d5,d23ab126,28301b38,d2286c89,87d402a7,7b5f1fa9,ac033675,4f4461b1), -S(383beab6,dccedb68,d6c461bb,dffd27f7,1dee3acd,2d9bfc78,f9c723db,2df57ee3,913f9d57,286e287c,594a99de,f59ee375,c8d5fa1a,ca9db39d,6397d1f4,ac524650), -S(1de5be5b,6fd264a3,f9445660,995afa2,39587660,9d224d8d,6d02e600,4e7f74c0,f3abf699,af7033f6,cee828e,3bcbdeb8,fcdbba9d,d0f76121,a77f1e9a,cc65c1fd), -S(787be997,f12fb2ed,744bf579,eaf42ead,86d36029,e3063ab0,78e1c932,da1896ed,d652cb82,20ea596,70a51612,71249ce0,62e5c584,bbfc385e,622d7e0a,46a243c6), -S(f5870f7c,4dc65314,8c4ffaea,79154e05,1fcd6769,54939f5e,cc33779,f99634ab,fdb57c99,9d115b59,6d77bf19,e42ea2b7,c0dbf4c1,acccf2c,ef82949a,2895ef3d), -S(721a5aaa,c5bf9886,543b1e42,aff4c222,c6a63847,df9d72bf,7feb57a5,a007e26,94fb4bb8,fb1f945a,d53dd78,82f6a789,ab0dd874,9d1621ce,38bfa0e5,5b50bab6)}, -{S(29d70da5,92094c96,e293c115,42b9dbab,b30df8db,ac98416b,65b0b75b,b3ca446e,a8a5aa3c,c3269596,dd8a9d98,87a3b772,efa1c668,3f8a947f,ff80c662,31c70799), -S(357c14b5,2c0eb735,74f675f9,cd9ba0ea,9d0b5334,d7cd5dc,a8d6cfb1,1359a86e,85ad0fbf,9b2f48f,86fa016d,89824a4d,eed06ad8,3db7340f,986cc8ad,ebe9b5ea), -S(72047bc0,29b36192,b1549087,5e360270,a7fecd3e,1ebe8815,61e7e0e9,2ecc6973,7d1153b9,54ec6a42,3df1157f,fc9d413c,f8c3837b,d4c84bc0,40ee5654,6ec95d2e), -S(a459ac94,974bb47a,8e5d3ba9,169e7327,349ad551,ba8ad12c,fb4e15bc,d4894e91,699eedc9,aeb4bc3d,cdb97dce,2ca019e7,218ab0af,2790bf80,c59ba156,9cbb8c74), -S(e6f35f3,4a17a4a0,a76d997,afd9a480,bf8ef1e4,29441d2f,bd9f9d2d,b3b93bf1,67feedbc,de8e075e,fb80a4d9,2959104e,a990d813,2b0d395c,8e893212,d47a2047), -S(88924114,3997a2ef,1e36bc46,7e7f2fd0,52fb02f9,cd79f4b5,e6ddc9c8,51e26aac,3b1ba5f4,8b0a89ff,a4ce1113,934d11db,26b88e8b,2eae3680,57048db5,e5488936), -S(9ece7680,448a953e,5469839a,12fd31f4,f6d07a2d,434159ab,414bf7dd,60d783e5,2d60b5b2,e6966e5,7969016d,74059dad,c03cc7ae,f7b80825,9a629041,e0cb1b1f), -S(aa98d665,de5df68,9e7d323e,943d411,e98db3fb,51124855,256d0b00,579caf90,ab791e6c,ebca5631,22965594,b52b43c9,5f323834,53b37368,281c895,7d1226e2), -S(306bf517,c30d81fb,1d931b26,49af7c70,87246821,8562e255,42576f53,2ab4e48b,d0d15fa8,1391438a,5416f0e7,1c7b9ca4,512fc802,d4c46a4b,779cb1d5,2842059b), -S(2c8ed21a,fb154f9c,c3e9a6d8,dd047af9,c124e6d2,46da9faa,36a580ce,91b1788c,7dda9e28,6803924c,d8ce710b,d68e0a85,fc2f8678,45258f99,43bbeb2e,f6a7528e), -S(4acfe8f4,6ea97663,56ecb2e1,c3055379,cb4a311e,7e4dfe9f,642fbfb4,18abf5fd,a5d6abd0,d44bc614,ddf25ec4,24526070,100873e7,c4501c65,c3045e24,7478c836), -S(f7b1d348,378a094c,3e8ccc30,3dd8ca52,fcfa019,24c52fd7,32544a40,cf47d783,b92c436a,8c7e7ca6,6dfc1223,c7fad4c3,c65aa955,b8ce913b,45437e54,9dbbd1c7), -S(1ea80a5c,38827511,69cb24f8,64f4c1d,a78f4dd4,6509a73c,381627a1,7862ab8a,126c7a44,5fd6d3a8,f57a3a55,4fbe3f1c,eb9bde07,99afad93,fd7aa6a,11a0dd16), -S(e76aaeb3,9cc18870,6067a0f6,54bc317b,89a72313,2b2bf079,9ee88af0,41597d5e,6d75f6aa,19727219,ea7f6f57,c0a7d801,3b9bf256,d8764219,d261b79b,48ad6108), -S(c6d1b9ac,f9fec422,e89102ae,4fa07021,e6c81049,dd1e66d1,d0903ad9,e072398,2e971363,41b318a4,dfc4e5b9,31a79f35,f90e673c,6bb7aa17,a2ec5f35,def14ff9), -S(d9faf06,ba5bd56b,ee78db82,4db777bc,e57aa5ce,5c4b98ff,8c736164,d4d8b2dc,97af746b,fb890c20,7af10658,38d9b850,2d8d0524,7a5592e2,89f6ffec,a66c5168)}, -{S(7885bb79,25196ae6,f45b6658,f3c04f5,a3b76cb6,1d60eaf2,45cb35c2,2552267a,9839aae2,b4d9de01,1a119d3a,d269a821,dd88d287,2f031910,a2f3cc22,2e8555a7), -S(fac317d2,cb5e27e7,74deba28,d3c2cf69,4364a190,329787bc,e325d80b,150c9fbd,c56d5053,b0a73378,b0d5fbf7,940ac348,abb46107,1b9f0100,c721154a,4d084e7e), -S(9ed46b01,f4e56c79,9b3f582e,2e35434a,25ec32e6,ab497137,6eba881e,7ca96ad4,5e8d2e27,96b8dc65,867f45bb,a623c59b,a365d840,1d9e889c,23d6acd8,d5bfb365), -S(6acaf24d,fce1919f,c8d8743d,7a5b64d3,3010a8e9,cb6340e9,7400d143,53620af4,b767f30a,87b29f8e,308a95b9,6848eb5d,c8bada19,74cee095,8fb75735,86f1d733), -S(1a2f9605,fdb3e5e5,3445c350,4e550312,b36a7dfe,5df0dac2,23aa53e5,dcd7264e,cc4b4a0a,6febc03b,155a755c,187421af,52a7e6eb,2227858b,c56b9feb,4befb45a), -S(4fe527ab,42540438,9d9afa,2a1da83c,968fe9c4,f678256b,d4998bb5,af963a2c,66dea7b,7e0540c4,75799ec3,3987a775,6ae86d43,56a295d0,fe8242cc,27ad7c4), -S(756ee16,fd1019ac,30e50f18,5606d1f5,fa91a7a0,b01329e6,2a949c80,b7590bba,4d190439,98483880,6323163a,6cb23a8b,e47152e5,a5439d24,513d30e0,21511050), -S(63935d2,711ec4d9,f33fb116,ce09ea58,b45b29ab,79614b14,278539b3,4ac44e83,703a7f21,c47d413c,9235fb0,36a7b441,87a90768,2d435953,439f0624,6550944a), -S(fb6bad0b,3503cf55,8a75531e,9e8915df,9a88277b,c766b37c,d9685b58,a91e3fed,483feda,8c214ac0,92ba5274,8b158b62,3a0d541,65fb5b0,7ce07e58,78cb39d4), -S(30c7d349,a9fd4825,82fb09de,f7d638b8,633fca82,b9bbd65c,ef8f6dcf,1c8c05b2,56c76d9d,6df4bd0a,a8030dde,a3839728,71aada1b,61bb34cc,1eda08ee,a14761ae), -S(13faa439,f73bb77d,d2423e1c,9989808f,96d98080,af214cb2,e0cde511,9eba8a14,ef6ed341,7ff03112,ece400db,b274d225,bea30a63,c9a063cc,9a987827,d3e380f0), -S(42112f0d,7628b3bb,7a0e4f0a,eb58d2b,9915f797,10aca7e2,67214532,2ebf502c,a1ad23fa,d76d983d,6cc4a654,95da8d6d,c5372849,d7fdcff1,34e5903a,e8441ce5), -S(d23fef28,114b49b9,77faea5,2bd0e30e,6a9ef11b,c513cb8f,3107e04a,e26a9ceb,5a4cd8b8,b0dbab13,2abc50af,c9d700bb,bc28dc84,3c12060f,612134f4,fe40aea2), -S(463bd8fd,21ba250d,1eee7500,e88aefa8,38211947,fee2be73,d6511300,6d28b5da,20f6f300,e2744ea0,1ed033c4,b5b9e7b6,707c06d4,d97c4771,ad35e305,b11aed86), -S(21795062,e337d1fd,994a7cb9,7407d33d,f40ac1de,4a585c1a,2b3ad400,8e03c4a8,e93a4632,da05b347,8be71e28,c55af8c6,b4b161b8,9f48064f,31755a1c,f6b0ed96), -S(e8f77f4d,272c5dd,f001f939,4b658b96,d58a54aa,bccb9de2,c501211c,6cf9364b,7044feed,21d1dd9f,80705bf3,d68fd160,31c02dc8,5a708f18,1bb7ce91,8655ea61)}, -{S(422f029,1f51c4df,af233322,7015e4c1,ec8175b1,a8ab6b2f,60a9e291,7242d940,51ae32b0,ed5d39d,e1d61437,d363d59,181a68b6,4e052bc5,9d132da0,9c1f422e), -S(f560c762,be8f90f3,b12c1447,4c3a2d37,53634a4d,fef3344,ba8e9a65,1becd50e,49bc8c46,e3207440,76082021,6d203410,fda33028,d3ff4ee3,af065502,ec96609f), -S(edc545ef,2402bc41,c4d7b437,65830ad7,f79128d5,91b4201d,1acb5f90,a7ea6a46,ec758c41,e0ff7bb1,fc28a91c,435c09d9,90338a6b,216504d7,a538691,6af80454), -S(67709f77,e324ec1a,fb57e5fe,43215f07,3cbd3d48,f6cd0bbb,c01f3ae4,1a3c5905,e65102d9,c33abbc4,82f2ed0f,fb156cbc,20210eda,19b5b345,f21150f3,ffb29e79), -S(6b73d1be,a5b5ffb5,438e4cd8,9af6d9c2,bc41a2d6,a9c6b405,ac6fe5d4,6ff920cb,84f7e06,6dc9bde7,782c7636,8aed4a2f,e570e51a,8494864d,88e6c1d0,ed732be9), -S(5aa1e427,64c4f0c8,60423a6d,54cccad7,f6093ba,b6a0e383,9e1e0b63,cd652121,3245d2b0,fe27d590,15cac18a,861d9ed4,a5131871,38faaae,4c01d1d7,759fc9dc), -S(a8460aa6,9cd68695,94288486,1f92a61,e7e924f,1d61b9be,1d31f923,efd803a6,f6bf9b9b,f65a68eb,925f6c63,4d16a6b5,6d92d68f,fb807084,7f09c0d9,d95b852a), -S(fa3b7d59,bcd32e9f,a4cee765,d9b54c1c,65d8cf67,8a88f6e5,3c3192e1,64143cc7,95ed2300,2f55b1c2,21061dc9,bd26f0ed,82c05ee9,4bcf1bad,3bf878e1,3ff33b84), -S(febd5d39,68446d45,fe1daf28,2018c980,f4a5030c,7710edfd,b79daa69,c10f2296,b8c37c65,bc7c42a0,65be333d,1827feba,70eb75f3,5f289e1e,413e2325,5ab9d551), -S(9d696bb4,4dbff608,af3ba93a,e98993e7,4a6d8902,42d406a1,7ae9c609,6bb9b29e,d92c5408,c0ec7131,9efb50d6,18875060,da65855d,8b2d1cc0,9f07f3e8,c0e1d77d), -S(8f4c98cc,21d39520,e837b075,479b8646,2837665a,ac82541d,1bdda842,ca5c2562,3de70692,afbdd878,5a858fe5,51321576,95f464e,cf2c1237,545b1e06,a1cbbe6e), -S(6d31e611,2317acb5,f2ebfc35,a4f66f05,af86ed84,720335ec,535c0f5a,cd14d952,8d22c3d8,32324673,9b20d9b3,7fc73b78,fdaf98a9,6cded077,6e561037,b2a85b1b), -S(dc891a7b,d96f10f,b6d8fe8c,1c749ea0,328ad2e1,353b49a9,8056c5c5,b637df01,475aca0d,c67d1f8f,92f6ffea,20c48300,2b0f7d3f,f5d2526a,cbd8b89f,25ed3eed), -S(c77ede67,1432ef33,73af321d,7d8fc6c0,f254aaa8,37feb14f,34817740,a54cb5b,ec2f427a,cbb9cd4d,96f83c7a,450efa09,6e12917a,122eb466,23c6b63e,dba11010), -S(7334718a,cb39692a,91c140fa,67c21c0c,da368242,aa1d0d2d,7223a0d8,5ce102c3,e3051cf3,4d5e51e3,901449a9,3595fcb4,327c59bc,1e2d92cd,4d4699c2,26ae4e84), -S(23c7e5d2,2b0bab9b,b95fbfe2,e39e6902,5c7bcc89,fad1a0be,1f5da48e,74b3f622,bc5a3ef3,c4679a16,ba09f2ef,4fb202a7,83257a5b,3f95b629,455e4173,9b5b317f)}, -{S(43cf2273,e372157c,2180640,594c144c,93f64fa1,75f28cd2,5e7efebb,14028a93,1f8b092d,4cabc600,33782374,10eafd04,37d6436f,6064932,6f8de6d,94059d4e), -S(83bf8ee2,2a69edf4,74e5b45e,50aa0bdf,4879b4d9,61d4b937,ab18d3,7869fe5e,296e8081,cb72663b,5223c040,a64c7aa5,273fc6ce,70261af9,cb3e071a,79b7c3ac), -S(66b8e44e,c913698e,d68f3b1a,df750442,442a4376,9ebe7859,84e4d233,9f666b1b,b09c7c2f,852bae4d,f90bcaaf,a664c792,ee88ac87,2d2e046d,aa6009b2,2412af94), -S(fea69879,e4eeadf9,275589dd,6339111e,5d29c581,30f22fb7,c6755d5b,2f5840f7,814a6766,65b54689,b3e2d415,4519bc8c,9676cf4e,91b928ef,3586da12,416f546), -S(bd147b40,5c3ca694,ceb4fe83,5f95676c,5428a065,add89f79,ac5859c9,7dc4d5fe,67544f50,a639f7a0,602a5fdf,2d425fb3,edea0cdd,f2cc5f9b,c61189bb,79cfbf58), -S(b3806514,838f93cf,6118c8e,f759cf82,394bab94,e020ca33,7d20c8da,bb61c79d,bf4c1bc7,35c5a806,d682a1fe,239a1027,51a547f1,7d1d87fa,59c9384e,3ca1fe45), -S(bb002b37,60adf886,a89d4ba3,23c17868,83f0f3dd,fd4232f1,28410770,563ba5ea,4aca65b6,68115f32,186773d8,41c061d6,8d4a860c,442b3f8b,c72776b8,3bcd22db), -S(7857b661,420c4251,3db90fad,ab97bfe1,9a1e3f91,5d524f66,86d0cc01,70652ac,75205776,8c2e420c,f255f9b0,df58bf4c,39316f63,612711c1,fc7fe5c0,b4e7ef7), -S(cd386b61,bfbd43e5,109b74f0,5d765ed0,5c4ceac7,85bff4a3,c8386ca9,54fb4553,aeef237e,892a3a1b,84183222,91f9119,64bc7240,2f32da46,47a159dc,4a7d6611), -S(94dcee6d,e36b346d,4dfb5ad6,3f488761,2a5734ae,e251b07d,6f81a3cb,7d255409,3265f73c,af4ef3f0,40919637,4e273be7,c0588085,1940bdc9,9d0ab66c,c488e203), -S(53199671,628f4a30,89e65e28,67489a1c,7f29c9a8,a34fe8a,c144623f,9ef9fc4b,45740e72,3b787de5,1ddf66db,96c91bbd,19954170,62fed0d9,69522916,7b2b10aa), -S(38596053,40ae3e91,d005b3e2,3a998796,195a5c5a,81b24286,458cb7e8,ec905e3d,5484588e,c9dc9485,bce07479,b1dfe9d5,c5007d9b,eb7c372,f52e526f,7627131), -S(594e1bd2,3a5ced9a,98e48bdf,dde40807,b9c2871f,79e1948d,7167b59,9ffecc53,1d7fcd4,bb9bf0ef,e0af9ed9,8da3e36b,2ceb0ea9,e1e3358f,4a590022,f5c530ea), -S(bef8b23f,95e0bdbd,3c0ba1fd,7afb8a58,1f038e23,e3e9eac2,b8848a08,6f23f816,9a234d55,f9c810b1,afff2a1e,b1738d18,4308d19d,11a0e1ec,cc571eaa,b9663c26), -S(632003fc,f53c8833,5542f216,e4020ef5,3eb225a4,be6c0e59,b92ebfe6,52721652,bb4d2dc2,f255b8d2,5c1803b8,88f40d8b,bbe6b2d9,f6754511,8264f809,cbd61844), -S(b7ae730a,e74aa208,9f3266b1,5358369c,4970c009,e6318581,4d541b07,c6c80a96,43a7b349,66b4bd5c,a1e45593,42642d35,ebc969da,544d4cc,65519915,34e80d65)}, -{S(9f10aba7,5a7b9fa0,233bf53c,d819ba2d,919f8acf,9a5e6717,2c93229d,547a40bd,85485295,254a4456,87b065aa,dad21f32,b31735e1,96333fb8,11117a00,d0bf2361), -S(75f8bcf3,831197e8,b9053c1e,5194155e,dae1867d,52f74911,a478085b,52d916b4,90448c24,35180385,a15a335d,a33af722,c9a395a7,16937aa6,b861aee5,b0b9567d), -S(2c05f980,7e24fd5e,87e4562d,65aeee0e,315ebc12,35731606,81e99bc6,be544c8,3a3c9e33,2e78cb5c,8ae90d20,edfc9eb0,3ba0ee07,82a158b9,154999f9,55e89210), -S(c8ff77e3,76a2c4ce,46664e1d,b33f281b,90e34103,500a9a46,83038062,42e59969,1d609bf6,2f6d3e86,c0510de8,4a42a45b,3fdaedd3,77101216,e43c2d86,751d7456), -S(b3205953,aa71cd5c,88ef7e55,3b94c8e3,ec4fd654,b7524c80,51908174,32850864,2c5d67dd,479dcdf3,41db7c5a,e0d03776,f3fe9ece,32dcda0,274a7955,b45edae3), -S(cb903c76,7ad3cd58,66c66429,9e9d07f1,cd35043,66784cd1,af3fc75b,73c4499e,8ef65e96,f1998688,2af0fedd,e0266d80,780ec031,fa47cc38,9e7bd059,eac83ba), -S(1a975b06,9e3f032,7fa9b706,3533fee9,f72c6c11,7ece27e9,cc83934d,a0c5d1e6,2cf46c5b,9f3596d9,5739dae3,a87564f6,13eb944c,5d1b6da5,3be8d76,14ddccf9), -S(d708ccf9,4dd50c89,de00a127,1cbd92bf,29f440b6,401c28fe,699f6f6e,50e0367f,fb173384,e0463978,a15de0ea,2ce146d7,b826f6a2,616d38ab,ae0a3dcf,1e11a1e), -S(11d850b5,4aa10ef7,8959f5dc,4aa9ce13,8ffa25cb,1034a365,234d0f6b,46458146,33162f6,bbb5ce33,af19cdaf,57dc82ec,69291c12,38e8f266,fd0becb0,bab02e8f), -S(7cd60401,be3033a1,85784a4b,adf9dd84,f4bfacc1,952597f0,6730f2d6,924332a2,6efade89,37b517f2,e1a1d41f,d6e6c137,d581d7a3,b55ec632,74ef8b87,1d9dd370), -S(bd82a0d8,34892e4c,974aa93,a64edeb0,9aa2e3b,16785166,c970206b,53ecf157,541cd14b,1fed321d,5a044abe,aa3bba7d,74c3f44b,db3f1fee,b05ddaa2,1f034ac5), -S(6f77bfc3,760934c0,edad8b77,f56d6309,179c8fd5,bbb731dc,42c279d,89f99a44,662854fa,e1da57ea,7e8eeb13,b3bf6744,f28cd210,ed461ede,7883dba7,f7b59d6e), -S(f31d35d4,dd0b2e6f,5b236e98,df56ca98,a5b6db2b,a2a8e0c4,eba41ab3,20cde154,e33e127c,b9c16469,83d71085,ec7ec9aa,12d41302,fa769c61,55af26ef,a7d1785e), -S(c0ea3ba7,be2030c7,790a3d48,7e720893,2e070691,82bd0024,5483be62,7916eab3,f5055e6f,298bb6b8,47e99275,64cb29f6,54d2131,1ff0a3ba,20a89ef5,992c0342), -S(23a696b0,e70e4197,d299abd0,b301b383,3df6f123,80120247,9e8b59a6,10a1fcf3,3af29a3b,ce23b0ce,afd9a25c,f1505958,b85d4f39,318a402d,cc48f98,ea953edf), -S(ac79289d,c14206be,742005e5,f367c4b9,e2b645a1,2c21d30f,ffeac884,e6f888da,27c49ede,7c0b42cf,91de7682,e6f224b,2a19f98f,72f40054,69c3121e,da2c4379)}, -{S(b365ce49,d21ca341,c173b6d7,2238c56b,f080d218,a89e57c6,ce1664f6,5c290a44,e77935dd,75d26531,d4045f72,3b4b5dc4,6608f8b,60f58989,d2ac4002,c304cf04), -S(af35612a,d1230c6b,3a260abb,69cc7099,f7025c1d,2a14d196,1914236e,4d4e1a44,b67d23d0,8737e96e,f629634,44b08f82,822c690a,b3d2838e,46ba259f,bb951b2f), -S(183181ca,37069462,5de3c48f,b8140ce9,84029874,e8189b4e,bcc8d91e,eb8d681d,a1780f41,8e7f00e1,e5ff8147,33a34699,79e6fd38,bfc03491,8acb042e,6ef4d6de), -S(4c1db656,41753e4e,5cf10f66,9a3e4b06,e18b3d0,1b56961d,8c400ae5,9ba239b8,cc57dad5,77b3d6c5,d96109ef,1006e33f,9c888598,c7248f60,5a531800,dd0c957b), -S(f0f61e45,cbe01564,17fdf9e6,db32d3b4,84fa0bbb,4be30aea,95dfc8ea,31529ee8,4b0de888,b71c441a,1c54849c,7e4a8129,d757213e,52b1796e,a5ab02a7,87087757), -S(84e4bc99,7066633c,a3997a55,a3fd3ef1,b4b99302,74349fb3,5da10b39,2f49a022,64512422,1acc41ab,68644fc,73b39a3c,6bcf1268,849bfc5,84aa7c85,4a48efcc), -S(a71007b1,e0747b7b,1b8b4398,232ee970,97f623ec,4924b8af,16ea98d3,6f98102a,91039909,9c42dbe9,1bdd719,d31bd00d,e040752b,cedf9927,77e0863a,96a5a259), -S(2f72cb7f,f0aed6c8,ef75c041,4ebc413c,21705889,de3e33dd,d3057668,4f882553,86450b7c,bfc89e63,ba1a1754,ba42125a,8b41f12,d5a5582f,ad86675a,b05bf998), -S(99f0e44,e11ea919,f16fa130,5ac6e72e,c11ae9dd,e08d3143,2ea9aed0,f902cc77,43f4e6af,ca0605e,749623e4,18027ee9,c64c059e,560d6c80,6219eec7,e475367d), -S(1aff311f,bed263a5,edcebb0f,e149302c,c0cc2b0b,92c69d33,d31c5522,eb9c9a94,8533cdcd,97190439,48d38bb6,845ca07a,9a9485fd,dbd44868,7f06143f,e85f046), -S(4a2dfcd1,4f601607,43273bfa,3702be5c,57f99a6a,29fa7f92,666d5020,6ffc852d,95931301,821cd6fb,63203fbd,a894de3a,57eb75b0,2f273f3d,bf462727,301dd9b4), -S(59c5a0da,480f334,944608fe,a580c302,965d26a0,dcd43b31,3854b302,af6abe35,40e27b3e,932ede7b,40490224,7b937b7f,2938edb0,a11b667f,16a90ed0,2a0309e4), -S(570bc6cf,fec905e1,564906b9,ebdecc13,60abe5a3,61f7c5c8,f03cd2ae,3ef9d125,55bff728,1f73045,82fe61e5,d4a92697,77503b39,9b320c45,ce5bb9bd,35def5c5), -S(bd7dab69,88ece4e3,621efa68,38a24032,ae9721c4,fcd835d8,6283b5f8,f9f02ee4,c7442cc0,95009f1a,193766f6,d050d165,d8cdca90,2ebe6d8f,237fb922,a1b6fb06), -S(a780a23d,eb8459fd,7195ea96,e8fedf8e,8b38edef,e0e0865a,b1d69d85,1d27c65c,f8c94632,a11f7185,9e3c7963,f24904a6,536321d5,f5e4652,3195f854,355de49c), -S(f0ab42b0,bb80f147,7f9fe3ae,f5944100,14a94142,e8312b91,86b0d6fa,3f0243ea,237a6ab6,b5e08f03,a7b58f98,e72227ac,6d3660f5,43da0694,b6821c9d,332724a4)}, -{S(38186a1d,6092b158,554f3f6d,c6de049a,2037577b,2da8db39,163fde30,b19dbf2a,a8cf045,9c7ea28a,415d01f4,47566d54,f986cab5,eb272326,442f32ef,cb6c43c8), -S(aaf937eb,c2084f16,301bdb4e,aa106263,cfe483a7,d0ba1b16,b93d921e,80f03a4d,7e18642e,8be01d91,86366b3c,c94aef09,c02501ea,e084a87a,a94d2d2,f85f84d9), -S(128b8279,ec2731f6,cf2ceed9,fed2cb49,f53d6237,112a84fc,c678189a,8e19867a,fc0dedbb,32524c1a,f44fefc,6b0e6bd2,ba65f23a,54f69986,52953154,41a89489), -S(7c3dac1e,6d89c8b6,e9645ec9,39dc634,a2cf5adb,323be29f,625703b,caeb21e2,a1b87f33,b5bd9351,15f16702,ae411a91,b3e9eb6a,814e678e,b3dd7431,6dff896a), -S(609d5c22,c8c7c1ae,211b4ca2,f709a1ab,75624b91,cb95d2d,6ea6baf3,eacc12c4,65a7b252,f13d08b,4b007967,69e6bee8,edb5cc68,d4ec8c46,527bcf77,535bd7bc), -S(691534e3,2faa9206,5fe7e8a1,8a863d78,afeeb581,97b1f48f,4f090bb6,9d3f9d11,2bfac0b5,35202013,60268e74,2376b901,a027d6f8,f0d91aa6,59341544,118a325b), -S(e6736a7e,e2f3f088,27012faf,3b3d1b7e,ed8dc136,3421e438,8ba70c5b,72eb4eb9,5a9b2651,26652e14,8fa3639,be0b4d5,1ba519c0,1285964e,7aa8a699,45bc71ef), -S(e3f05d6,2aa7b9d9,6e9480a0,a3eefe32,f1f6d45e,2fb1215c,ee5a3fdd,f147b154,47389f33,e03817ef,1051db5b,26efa711,46cf673c,12831163,2ee13576,b8508013), -S(b5041a3f,cf8b742a,dee6540d,e9974cbd,fe527e2f,4842a208,630b9d2,239c0657,4ea01569,fdf5b2e1,7631d2e8,2c2c0bbc,291d69f2,fdeb077f,4ea1df9a,6303ad57), -S(e5463af8,5dc090f9,9ff72771,c1cc3585,dfbf9dfe,329e69b5,fd0ac2ef,3f715ad6,c54085dc,a966fa9a,985d8e46,79335dcd,2d22d470,790f71cc,1d0aeccb,be9c5fad), -S(104b12f7,8fdbd727,2a5716f1,51238362,94261142,48209abe,e4dcbb4c,d7bb0416,ebb07749,12a3ce9a,e20b6696,e485811c,6a15ed53,a1015291,90672c47,e4442c6d), -S(1699a1d8,d04a07fb,32fcecb6,ae89092e,fcaaebd4,fd9c4af7,d79a5eeb,2c18da72,cff1a93d,4ccd9199,9c6259bc,fc975ab3,4992c8e1,8d1cae10,b0c1ce2,83101103), -S(13df43c4,4de2fda2,4b932131,e7c7fc62,896f2747,706ff959,85f98248,4cbc6179,1da341b8,734cec8b,74de0c08,a040ff68,d8d30ef1,dfe1ffe4,72ffc73d,a6a82a74), -S(2e101469,1b7e08f2,d3aa774c,f8f91ae6,e9aea711,fddeccc5,d816e5a3,dd752dfd,cd4e7f49,998ec720,a3ed2e45,8136fbe7,9942011d,da5d7fd4,2c56ed77,29f55b98), -S(b0296b3a,f9e819ac,a7b01bd5,7977ea85,5d2ba87d,24f820f0,c1ad5f84,6b9d10c1,192cc5d1,b6782d9e,e3f444ad,61c0b8d6,9772062e,7b03c615,b1cb7550,a76e1d11), -S(f9a11b59,6e369694,fd62d423,518e355b,a796269b,d2b5a88b,1c8bc812,40fe464f,8c919e60,86160ff7,8d1ce269,4512c16e,75f8a79e,da39df1c,ad104555,6d1543dd)}, -{S(d8e5f3ba,c152215a,8cf8ca08,40aaad6c,7d001aa0,140bb0b4,dcac726,229ee272,e59390a8,21e8608b,e53fb258,a426dfb6,ca762fd0,9d574f7c,5555cb8d,7174b381), -S(c2d7dc95,6c6721e8,6effb64d,5e1c4ec2,ffb13a28,706669fb,ac30f035,9d202663,8cb207fd,63af5339,f9a705f5,79f446cd,1a11c0e4,cde750cb,803b840e,5a4970a5), -S(bb3445f8,d7f47cf9,befd1a73,76dd9c96,f6d76fb5,b6d4b7de,e7f96dc8,c9e8f025,c1fddada,756d03aa,7d92135a,a8dd783d,63920238,1c2f5af4,7e702cbb,97ea783b), -S(1271c587,d72e74bf,286ae688,c022e129,f9a95567,9f74755a,24e85d81,486699eb,1259045a,cb14f2bd,7d5fc85d,d8c58303,9181d367,63e4733a,56172be4,b19c4a40), -S(76274ca3,884de253,ccd8e9fe,b2f7ceb6,1c7b6c49,1a358b42,e64994fb,80808263,d2639e7,539ec38e,b14c7d83,47fc4d10,c2a2d83f,81a1e4ad,1ba8267e,bfdd4dfa), -S(8d80c172,ea0f7e79,d3f2569c,49d49bf8,330cff73,fdce6b14,3a4a349d,e7cec2d8,86dd76ee,63fb3a85,ae315029,3e2d024c,ff1649d3,c823ca63,5a1fd992,975fda33), -S(441e6584,10404939,367bc434,f1c64c42,5b2bd11b,5beeec47,35919f02,4a4626f,3db30e8e,29e6cedb,7bb465eb,92526c4f,4b7d8361,b151ddb1,da878a87,86d83573), -S(10d89274,b0d498f3,d29df723,937c3838,49b4ffd8,b87427bd,a1d142d3,160c2b88,15df3d2d,b11e35fd,a423c709,24e497d9,77941b44,20e3093e,539d3406,e2fcf435), -S(3960dea1,9431a970,6bc4e886,8cbcaaf6,dfb9c87,17e664d0,4ff6eb5,4108f2ce,3cd86dfe,6d967078,9f090213,4661a7f,78e4854d,7e79e519,7283f8c9,a89ce6b3), -S(a1f9b8bf,15de0a59,141449eb,3a52a335,ab881489,7a7ae82f,964d3bff,f1dd38d8,dd563a40,ebbf06d0,84e21a10,dfd117e3,c8806975,53556b4c,2fb51100,6b498d6a), -S(17cbba26,9cf2b92,7d442075,396090da,62a2026f,ce3b3eca,858feb21,76659de2,71f31851,a2561f97,b0ac2495,d72904a0,bdddd83e,83a1dd87,b0db14e6,ff1348b5), -S(10dd7c20,902512d6,6484c830,53063a20,c7474504,3a378949,280a90b9,f8504102,1624bb25,937d3b47,43214401,c8016fff,f770f7ae,7d78d8df,381c2de9,13bc856c), -S(7ecc1dcf,5e9c56cd,43cf311d,5b31d269,50db89c7,2b51b624,745b3c75,eea68899,3ae1b7d,2e8252e6,43b73aa5,6d7c9b62,1f79d1bb,1d2973c,1bc3b150,a17d1ef5), -S(f57d8aa8,ca4c8377,14ca1ac8,e2fa456f,4c94b304,fd0b268,2084ab52,3768827a,2c5bb2ee,e4b509b7,7cadd78,4202c12c,3644ec47,9c599009,581f8b6a,7ef5bc83), -S(74905ca2,7116aec3,b96d16cf,fba3431f,5ccc3cb7,e5747525,124b5b31,bd6fd066,7d26da6c,1268cf67,846954f0,48c7dcb3,3a1244b5,8f0a8026,c3dbc651,68cbe871), -S(4e0b7166,de12f0ff,baeb2464,ba205624,e85b9238,4a3ebbcb,db9c6038,94ef0cef,8a85223,cf784126,3419d777,93fb66d9,19e3428c,5ab844dc,d3d9cc46,7ea95c10)}, -{S(f41bd2b0,e0f49133,747e831c,af4c7a0c,22d2b55f,1cd4ca53,1115d81b,b47754b0,869485d7,26d4687b,c57a9eb6,e90e93a7,bce3b523,998d16c1,297c996a,b68c4fa3), -S(ce2e4f9a,3c32ea4a,2198e61,8d7d88a9,153111cc,fc114a46,cb9b47c,63842146,5c90a793,c4f4b290,240dfc0c,1dc0df9d,a33214d8,3024304a,d49eab61,8c4d64e9), -S(924f51eb,823a89d1,3194305b,45ba1f8c,40a58987,73cb1a5a,a4a4017a,b55af76f,8cfbe8aa,d3b759f6,14c98aea,3b3443ac,46400a2f,5cf741ac,c7f590b3,39f3ea0e), -S(9f985579,fd32d32d,90ec233,c5577a12,b1fc350a,e94b5f08,ccd31cc0,33495f5f,ffae345d,8bae4446,bfd5b6a5,117c0b77,49cab9ff,eabbc8d6,531e0c34,fdaeb328), -S(b4d25ec2,6afed742,2ae7f209,f4201d0,91dfd595,3418bb05,12b1ce25,455ba8e6,8a13f82c,47489b6c,72223047,e8e079e0,165edf0,4c335814,b971a5d8,27d2cab6), -S(7f4ce1f9,acd1d262,6c6da2f9,7dc19ddb,ba3f15c7,7b6c88e6,3b0d4e41,a40a3c7f,750468cd,33a35da7,242142e1,e68128e4,b5210635,c4739aba,910ba9ec,c9c01fcf), -S(67f46710,16d87e34,b2d53d5e,c54f9fa5,f22c283b,a3dc5a17,70fc4a16,1a2be4c4,70503598,1378a67d,16827d9e,c87c591e,afb16fea,6a5ba182,4f6cf6c1,fa92b772), -S(1c30c0ad,43b0a74d,fb199442,b151865,7cf99e26,fca6e2f2,1cb97a6a,53c15893,3728e682,72a4020d,8365b4ca,eb153fe5,162e79c6,ca6a851a,e233a160,400b625d), -S(d92d821,8443e951,ad6ad28d,b7bd7101,756d91a0,cc3deba4,219ee34,ba2f6017,fc3dab7b,ac2436fd,a39a65d4,596dabc2,b65f8f0,c1195a51,5d8f2bd8,4f5530de), -S(3b6264bf,a47de486,3ceccda8,fe6c55a6,ab1d8188,d111b222,4aae150d,c3517ee3,e3f786ce,5adc8660,98965a41,62f4f510,8c1f34d9,2451af03,8f68e5f5,8f6c58d9), -S(c6b7190a,e4d0c14d,b3cba3db,c72fadb9,da9391d4,2eb7ac68,4e1b20fa,d89749ec,f4b7f04a,b1358c35,1b2c622b,aabf3e5f,dc5abd87,ab3cb388,86f73d91,202ce359), -S(c2846da6,a821c506,e022a927,257b8d21,57d82def,196f32a6,78b8cdca,d085779b,d5431c41,4ea1417f,3f4d90cb,c776ee29,9a6a8557,a256b3a2,58a887fa,fb5aa256), -S(7bbe2521,1f987b2,742b6266,d2c598b4,1de04ff,70b689aa,8be97f8c,63829bc8,dfb605ca,3491a434,e53fd0cc,d8bb2188,c6dbb06,cb18a9a5,cfc6844d,400982fb), -S(81a92f34,ce6c4383,a058d74,ac36b44f,f4bad7ad,b6ec6a92,87db84c5,9df3469b,31639fd5,7842ad40,4b204b26,7570a557,91dee70b,ac71630f,90924443,47597c32), -S(9e309152,54a25340,8a533606,d8f8dfb6,9ff93f1a,9d97212e,c261dcf8,ea3d1d7b,ab95d903,ccce7769,cc185c1d,4e24da15,b9c05bc2,7977c754,1b1023d4,39d75d26), -S(f72ff9,92e06721,559e127,28169de4,888efbee,e87542f8,fe0fa971,189baee7,db2e60c0,4678d370,cef335d1,d3e007ec,30dc03c1,f31c02cb,796de00a,f856e440)}, -{S(67c452cb,e71c61c5,8aaf68cc,b1f6208d,5646432b,86774f8f,60081179,6d5337c9,d5f859de,a125aee2,11dcc7cb,b50b4fa3,ef4f9767,7eb94f65,b6a181df,9b938c0a), -S(b068a1a0,e36426fb,2d959715,63faa818,1da81aaf,3ba3654a,f2570e0c,3d373d2e,9d29d11a,9333182b,3202e348,f547a9ac,ed5b6468,83608526,682b10b6,e1ad0f0b), -S(e33d0069,dcc14230,760f13d4,59c4ae5a,8af0383e,e6f37eb3,13a8b7c,587e0c30,aca7fc55,47536053,97b56a7,4d814548,993e11c7,4b89bf1a,b50ecb40,b9cbb5f1), -S(77f40f78,10b06a83,71c1493c,61a816bc,10f3b70d,5fcd025c,54de5036,eb6b2ce4,618187fb,f124b864,d69ae6f6,c9eb674a,eb73a074,b95194df,967b804b,c66d3e56), -S(d0ebe599,772c1450,979c403,25ef498b,69548f62,907bb455,1fba8f0d,c7b076f7,d0ffa315,3b96c94b,cb97af89,2f845295,ccfd1146,d8c682a8,3bb7488c,3fcec2f6), -S(2fe20698,39f33753,819d4b74,f0a036e9,2aefe03f,5b55f504,d3e1af7,eb5cc0eb,27e67641,1aa1a970,fa0fa0df,8a147716,b52ac4be,489194bf,3f192ae0,eceab892), -S(94dfb5be,319f7da5,ef283791,e6375480,1c337607,32f8e66e,bc649943,af99262d,4fedb692,4c6dbe8b,daec8caa,4273f77d,4736b73f,80446c5d,d4116329,5008225), -S(a0147c3d,f958362c,177aea45,908de2f5,afdb005a,89182e95,edd3f4e7,74ee0cf6,c81c0014,b273d2b6,2e7d40f9,d9b169cc,67ebc773,be51d8bc,7f35ff75,f0eeca0c), -S(91fd8598,f0a9c4b2,130310cc,417e7a3a,c1374b1c,2c76e675,f5f1a7df,32b1b96e,f2f277f1,154afaff,774390e2,e87bf67b,a722ee5d,b502a1c6,24042a7c,779d5a45), -S(613b839,a2dc9731,a2ba890a,e8f7c966,ab3c4237,fc14b05,7c561f6e,208c77fb,22b63998,85a758b5,848a318a,5aac49fc,aa14c4f,cb29f020,842280fa,618f235a), -S(653389e1,3b7f87e8,8d22d0de,d8b1de4a,b4902d12,a0c36e76,11ed3d0f,e1efcb86,ba710bfd,95e40d1,a4e8b4c4,cd1ee147,e01ebf1a,74f52483,4fc5148b,65a86e4b), -S(7b5aaf67,bd31c86b,e4877624,85b35fb1,4f6f480f,69aefa91,30e3208a,f9f9997,afdce71,1bf55d3d,4cb01dc9,3870e40a,851a8c7e,a7217607,1d3285f5,c727a9ed), -S(bbed5d70,be29d810,51bd811c,7f237856,7d097da5,cfb2d891,c0bc86da,7d680dec,229ba9e5,ddeaa4cc,498cce34,abea1d19,567e3a6c,878f8fc1,31be7b06,f8550aae), -S(1c4562b2,1dc0d0c,1c4bd826,603d07a2,8b7545f9,29e0cdde,77a1ce23,5d378d1b,b8976266,79671f6e,bd0b43da,9eef06bd,99dff8ee,5092e19,f260f468,ef16ef0), -S(a9edf307,c7fd7446,d71be12c,267a7135,688bf7c6,8f1dd65b,eed8208b,897dc380,9a20e692,9437be50,36a7b701,ad3a6a77,82234965,cadca1bf,4992da4a,24438f9f), -S(3bce25,ad7ebdd3,43645652,954ccfe1,1c5e9597,fa3a9f83,d51ea36f,2b55aae4,cfdbf98b,7f3575f4,4d37ac16,41352d12,bbf7e13a,4315cc04,3e9ab067,b3e41c52)}, -{S(56d09714,cde8f0c,f1956cf,a56bb0aa,b73507c8,bc0399f8,c0fd17de,19e48e9b,d62e1f31,b40ca6ba,71de9059,8a9fb911,6c5f0007,df0c33eb,f50db688,ef0ab90f), -S(8fd887e5,50b3b108,f17bf25a,12187b64,4b173b13,15d5dbb1,c9821c4f,9d05a37d,7b2d3e3b,731d83f,535c0c5f,1df2fe54,b1eb7c02,e43e73e5,42d0efc2,c9175fc1), -S(64331c37,736130c,78f719a7,52603e28,d8a48c9c,33e3676,2ddf079,4647588a,9f214dce,bcf18bea,5aa4823b,e72df87f,634e37e4,6b8e696f,41ac44f9,76834a5d), -S(6bed1320,7626f62b,4e323e92,ffbca06,4b682d74,59192c6f,a3569567,cadca363,8d435e2c,da580046,755f375f,b226ac7f,86d15c33,71114737,fc09b8f1,ff9d311), -S(e1c8c67c,56fba327,fa0b3790,8dde77b,a187df50,e2b0217d,8a151344,4cef208f,7be39f85,450ba36d,b2d46fa,457c68bc,e6c7d140,ac1f6f60,cc95d12a,b3dba197), -S(9e927dc5,427d6859,30da46a8,915934bd,4483374d,263d962c,fa0e9710,6cf285c,cb9b2596,90224417,d65d7bad,f89a946f,df0f7b68,2a28099a,118c146a,598ccf01), -S(fcf97f06,f70b77dd,47ee5661,ca5c5653,5b770d5a,ca61e88,10542124,92fa3748,5df3187,1f5af498,605324c,81dea770,67aa4952,7736a0e6,cd3cd6a6,ad4f185c), -S(f8922d31,8ee1c47f,29a5df4a,66ea44e7,7ac4ecbf,2440c4b9,3815f249,bc5a1b28,9377d8bd,548e7fa3,bfef786d,bca70039,24509e9b,d22e483d,9218fc48,34941d62), -S(6b7de62b,9c928cfa,e9da1197,951c010c,34dfbb7b,b111274f,ed5f4552,20909188,207d06d5,719938a4,f69be3ad,ffe9e83e,17d2e500,7d3dea3e,f34336f8,df3d226a), -S(e948b128,c6217752,8f1d0569,697c656d,92a92b37,34360795,73c9d7ab,61db30b0,7518e35e,1a5e4e2b,64966fbc,1185e7f6,b59766d6,a8fbd37f,36dd9354,14d68af2), -S(9d932075,5fd767b5,87d8cc95,3b2b7d49,4967a9ff,9fe673d3,8b7aa621,3dc4d7ae,80c62686,e574233b,21f8892f,7f8e3cf,4e05c47a,db687e38,4ce2079d,16fd7d36), -S(46eff49d,a6d4dd71,108dff71,e706a9a0,952a8774,efe6eb8,6cd28a90,1b89a8f6,8b26310e,ee49ba70,77f085e7,cb2f82a7,97fa3d50,c96e7148,892f57db,f89e3544), -S(72a59c5d,6286d1fe,c37b7bb0,ff34f67c,4a632530,37a22efe,7dba0305,2cca87eb,a3770634,995ae65d,c48151cb,f2e5efe4,bdb30825,cccb1277,e9728741,ea2832b), -S(1eb0e1c4,8471f8d4,1e34c22d,16bad4f8,2f0cc863,db92d412,8d7487,1f7f2f3d,232f76b7,1cd83c5a,4349358c,a661639a,b4d6a5b6,8eed0f11,a674385,8ce7bf95), -S(d4173198,3c8645f0,ec134630,7c6974f3,1aa396ad,f01a91b4,b618304b,34cad3b9,3825cdf0,bd454a15,ea3d18d6,b07dd5fa,42e1c46f,7fb6a1cc,f1a707e4,74b83550), -S(aa030fd2,52791775,e051f0ee,be7d6902,7da01452,67b4e712,960692f,1d59f72b,fc83d72d,5a0edc4e,c05ecb54,7111a10d,9341df1,b0544177,c2eda0a6,70980ba2)}, -{S(31095045,658b8c85,ec0c4ddc,7cbce691,d060181d,ffa08855,f3f36722,4c026225,9a8cc527,1c231ce7,aeb6e73b,9acbc16f,4b331b01,4bd457b8,799bad40,547c210c), -S(372f6cd,9a7b7907,4f730fa1,8cc1db50,a9747818,99df942f,4f2ceaab,e85c6678,7c9b42a3,81ebd00a,8d4aadaf,2e34daaa,e57f0633,94631677,ee675952,3c72753f), -S(77e7096e,7215e184,cb096b45,54f60fd9,4fc5f7b7,28bba5bf,be2a85b1,1984daf6,4a913cc1,dae55633,9a90de21,746d3e55,7e8db814,c23aa361,be967ccc,cd319643), -S(fd6c827,34bfd6d0,a6130095,d2c38135,e7992c34,6e85d7fc,e5b13410,767620fd,a3996aa6,1e87830e,6d2da97,5bd318f,c44ec9bd,ef552204,f3ecb761,b4541df6), -S(24824f95,be9fea47,be33b438,d855e2c,d0d8982c,2d8a0b0b,d84bba5a,eb8cf0b0,d7e5c1d4,d6c708db,a5b51a46,310bd68b,18b521b,e765fb50,e1d8978c,6460f1a1), -S(d1d2e882,62b62a1b,63ee8e90,31f37d7e,ba90b95a,3b577af4,c0bf5d4a,9cbc65cf,b88f4f9f,62ecbd5a,5165ab8d,92126053,66d719b0,9c5d41c7,539d9991,76d004a8), -S(9118fd29,acf4c565,1ee732d3,c606d374,c4e5306d,90614ae9,d5aab499,4ad300af,8498b6d1,dfa4b247,ddc437e6,cc2f4dbf,d46b4562,3912a2c6,1dea8068,c86d9e54), -S(c303d808,8f33b08b,ea8e2490,d8f4a108,27569644,9a116564,41166838,d6602b9,af7a213f,d6131447,4be0c27c,39abbe1a,3cc45c97,6f28182d,cddd7d86,ef1c26c1), -S(4f09e673,cf4036ca,6b466d49,11b21cb2,421ebd98,f336c6f,9be27aa,7dafa17f,d0b9b5de,d7517f0,f452d744,cc5c7201,f292df97,e70cf642,4879267c,160ccc96), -S(cea44dbe,7286698c,dfb48302,deeb4345,71ccabfd,844411bb,f0d63c70,626c8bfd,2cf9e22e,16dbc1fe,8f159bd0,36ff4496,7eb0d11d,977e181d,a885b200,a552108d), -S(799d8d8e,8297a1ed,5052961d,646c44fa,787ec15f,62c0ea1d,13ba4ac0,3b42dc4a,9ac6c9fd,e28c5dbf,23c76484,6ebae2ef,b4cd7e57,592d6608,9ca6fef6,faf148ef), -S(b7630524,9472c060,168677df,775b6696,97f281b1,3204908f,dbaaa74,b87d555b,5b157540,7c35c69e,9537a1e9,10410d6b,9c6d461b,9a00520,f6850bc8,9628bdcc), -S(9866d83d,7d9fe0b4,8db8c7bd,557326db,c74d757c,d0f063b5,a05eea98,7847758a,f664b109,f96f49f2,b06f3886,4f7c7e99,de8ac6b6,ec08f946,3855bd5b,c74f512a), -S(6b5cf6bd,565f780b,ad85093,3da4f5e7,6a168a5e,bb3c4658,c9ad6945,99ac1d0a,210f9b03,96d9d3c5,f2fd3ba1,a889cbaf,fcfe0bea,af2771fd,c021659b,835e639f), -S(1164bba1,af12b041,55796a4c,d5b17da4,db37470e,782b7875,ed553675,201d72e5,9f5e04a3,3b913c09,56e72111,bd99f2e5,1de13c2b,f496b72d,3b7bf9f3,42572d37), -S(ee09a791,3ddaadbe,13b1b198,a3e4e63b,5cb2f591,475827b8,1f9b81b4,1449dcda,88fafeba,bdd965bd,19bc434,8447f3b7,91de017c,3f89b292,4a6c6f76,839bc6f4)}, -{S(da34375c,e38127dc,cc88a823,55d763a7,2dd5d733,d9bac216,7c3e621b,ede529df,13426579,db1353d2,8095e1f2,a007904d,5c04a725,2c621ce4,41157aef,d2e28cf2), -S(a781c07f,cb52597e,f229d634,b3036507,c297843e,3e784024,d38b0025,72dc3009,e4fa3bcb,511877f0,8369465c,475dfbfd,e0973309,acd09a80,a9d191a4,e21aaa84), -S(d879e837,bb9174e2,19108746,91cbe6a1,9e19efc6,199464d5,2c9ba4f1,d32fa31f,e092c41,35550370,40c786e7,c3d5f72c,6be6988d,441829e3,85b1bfc,f1f00bd3), -S(9fe2fef4,5f1c5e21,110aa61,ee83af2d,2d409120,c6e510d4,dc2945b5,936c8ff4,a1d3701e,26007255,f4b8db48,bc6ef057,a7c146cc,ff50ef2a,e5f8d868,5a684a4b), -S(f2266efb,749fdf5c,dca22eba,8b9d8141,4b8cecf0,1bb25dbb,85f6e3fe,d88e55c4,11acf31c,ad2b4ab6,f3036259,a3b54bdc,6b8100f4,36bfc1ae,a17ba08b,8fdb8bf5), -S(527063af,4e7ebc65,2d45ae2c,e2149c26,f591b12,da157351,bf8b97d9,d998d007,3cdb282,740ff232,d9ac9988,8f0c20dc,96476b79,133af243,eeb01413,54c71ec8), -S(aa067591,c038a16c,2bb18b54,c6357140,731440f2,2b972152,d08726cb,f5654abf,81e8b530,a4997fd9,ff4122b8,b559c6f7,915b3d08,96ecc8f9,dcf01aca,f1f4a61a), -S(7a147e92,6e2b916a,c23e4fa8,d9349aa5,449e65fe,c52f01cd,a7be7863,fa2a1bd4,d13d4e2b,4e64a8c7,824b3051,e277da45,fd947048,ba7f9f09,6e6a6189,f6ae356b), -S(394773be,c4c8587c,a330f243,5ac5057c,f833333c,4693ed63,3d0e780,8d31dfdc,1374bfc8,7b1a7ad2,7c119dbd,cea325b2,c663aa4,18e9f62a,d5cdc878,88c8874e), -S(a1b4edda,14ce5c2c,ed276886,5a3a1519,ff2b56e0,f0e06741,613f7b3b,37d001b9,e462525e,6a1ca74c,be1e0973,139b2f1f,2b1458b7,dacf6f66,cd80ba4,1195516f), -S(a2a20ab,b8cb4a84,9625000d,a2ab6d80,6a2006d7,6994069b,2e50c83e,4aaa183d,3850f9d7,bfe1c1dc,b066f603,8a71f78,352d4cfb,44a7d646,81b86a7d,23b0b468), -S(d66412ac,30ed909,4c282dab,c40624ff,7fc5a593,494a9be2,954d0cd4,961999fd,ad6ad3d1,e3be49b5,402880f4,c67d1546,7b6d01fd,63e4f45f,f87e5901,7b8445a1), -S(ca666365,71fad850,3205e1d3,6c0b0062,9a6347b9,b9ad0a92,10ba208b,57fcd0e8,821d0dee,efc2bf47,4e575d10,83d63505,67235026,e50d9fad,541fb097,2cb196fa), -S(310184cf,7c38bb82,b04a80a7,5c4678a9,985336b0,f60acee2,2a048e87,bfbc6970,4e21334d,6440e46b,a12bc971,31d55598,94ec8648,ab901a94,c757b957,662b41f8), -S(e051316a,62329ec5,add4bf12,4fe30288,dacf5e82,b0977184,7c64bb4a,8c77802e,3358bcbf,94e23384,c9be2d87,79d56ab9,cc0fe4ce,23eb227a,741a3be5,3fdf36ad), -S(1dee1a31,e28d970d,11436760,7861cd75,292cfc9f,533197b6,7ce40e8c,62db266c,7f9c4f61,f534b388,7f00bf73,469601c0,9c6971cf,3ecbded7,63560e1e,ccd0e32b)}, -{S(a80dd274,9cb3c40d,af91b91f,6e8b0850,27fae17,96e416fb,8a172c27,d39e8789,466161e1,e9519ac5,e1b03652,cd1ce6cd,1d7dc696,aa59ab5c,565d822f,af427896), -S(493c8d4a,8a53ccc5,67d531a4,c833a8c2,6ebb3337,9f1f2330,9ffc7a5f,90ad860c,eb52116b,e4f5075e,e391948e,d7970c28,ce156e22,cd3e5820,ed0158a2,1158ea73), -S(42a51205,5158eff9,ed9b2df3,3f17a809,ddea781b,b0cad4f7,5ee9b16d,f03447e0,4b305c2a,987f11c,1700cc3c,b09914b1,cb30379,257c122,cab089da,b0115e93), -S(eeac8ba6,c3397ecb,ad93a0b5,1cbc9108,29aefb53,50a9bb5e,1db9ea58,a33dcab5,e0eaa01a,4596cbfc,76f418c2,6fa382ab,699e8ea6,1b700f76,98f5b913,da774b70), -S(33e903c6,ee45628,db06afde,dace17e8,bf8ff9b2,a4d1e3c2,c43ab4df,693d71a8,a9abf657,94edb2c,80a50e5c,e210f39c,fd37ce86,5eafac01,65191deb,adc9f379), -S(4af6278d,2c4ea624,c4a7c264,5fc4e5c3,85a983e0,1f5c0c2a,bab8c101,8ab36425,4af48c96,64a8e40e,33812cf2,6a4495d9,8bb7bc4d,3455e03c,21ed94f1,e6fcb069), -S(2855cffe,89b73f36,c4851fa3,92ffec8,5b7b4c7d,83998c67,ee8e710a,473c9f72,ecd7c273,c26c1d7,4de7bffa,6bd26a51,cfbf9716,7e9875da,cab2e632,25766e83), -S(1b06d384,d0fb68d6,396314d6,a6f12d91,3853306f,1a904494,24fb2c2e,d73e88e,3de9709c,cfb21234,f8d687a2,e6364caf,74ec05e2,82245cf5,9fe5d37e,e7e3e7b5), -S(cef34326,559a1922,ff354887,54a1bc1b,72d70955,33591c3a,9a2b871d,8845a9a0,aa2a7c74,6a149ceb,b276bc9f,860a96d0,285e9a46,d62b2c15,c9a78701,7cdba153), -S(39e39d53,d9c619be,c9204156,1c8dd8d1,4f5cba0c,94d93295,352c8448,d9ab988c,56c6817c,a33aabed,d8b724,754e8764,72e065fa,357917ab,d9d03199,4c04c3dc), -S(28cf0dcc,2765d3a8,ae99c40f,57d14adc,5d21e730,271f2465,142c5369,80b21878,908d84d6,3774fb34,774931b2,12530d35,8565392c,6ec35541,1cba899b,3fa29e7c), -S(383ae3fc,7967167,ad6dc50d,4af64da0,f5c44be5,4ac33d3,6779a8e4,7ec657d5,11ae57f7,6ef344c1,263974e4,25f27e6c,c68d25af,3c748935,f554e4f,5cc16ba2), -S(9f11beee,fdf9dbbd,c9487b01,869a7b18,c8db78d1,36027914,bf363f,951b1b6f,335899a8,7abd3401,d2ca87f1,ca330c10,c098f7ab,cc2d0206,faa0d8aa,e7726aae), -S(34278948,b6755e7f,2faa3674,f766e6dc,5029c644,55f7ba86,34e45370,a244eac6,f6e04f4a,f27a8768,23de58c9,d2ecfcaa,63a5027e,b6c7cb1b,428a159e,2110537a), -S(44828d6f,29e24d8f,1e1fd7e6,13bec429,27a1fa28,803b1ce8,ac43804a,bc2a4411,4781fc5c,6039f0f5,fba6d3fe,4fa8cc9d,bf9c3ee0,4c42a0f1,8835ecbc,b15a2168), -S(903910a7,1cb1f65c,838f84af,a3167c3d,f396436b,1c76403a,5526344c,ecb0a948,19978bd9,d0563fbe,d9cb07c6,f88e563a,7aa007d2,562feedd,5c8fad6,e555e66a)}, -{S(b3dee3f6,cc08c0ba,5b7ba3b8,50469647,34f7dca1,630e806e,f84157e8,2992c765,d523bf3c,6b004cbd,59db62b2,58395f63,d487d6ce,31799ee1,59ddf96e,d9bae2e8), -S(f5c52e87,8142cf16,d01aa78f,179460fd,7a8d7645,498118a1,a1ec386b,c2860a44,868b7621,a41ca177,84d6b4a4,d5a5ac40,ecced5ea,d8d5bf13,e5bfa29a,5f998c38), -S(26412ec7,e11e9347,d515de0e,98e14920,522610a7,2c090b51,f03bf049,86738df7,11a10543,394f932,19284377,1a2d0741,ebd89e8b,4a0c0dfa,8f8cc5c,db7cc207), -S(8e313452,7bc65ca9,241666a8,bec7c6f9,b92f2f46,c91c3843,e430a22c,4e6a92fb,bf6e2a1f,122f4b35,aadf5b3,c03be0d8,406c0b74,c3e48b1c,85023996,a0eb1214), -S(ed72bb0f,4800c2f4,2db83b49,137af4fd,40d53e5e,d690fe42,b93d8cf4,a603d3da,4dc24219,6e195c7c,c1bd412a,a0982a97,80ed39c7,c1f34181,6540ea3a,e52f0c27), -S(a84809bf,a6592d13,47f1f37c,e7a052be,d4a5e06e,e27c369a,61a74f26,552786ca,7bb26691,5e544c06,cb7aec5,aa61979c,a77bbb52,67dbaa2d,13517b40,3ead93cb), -S(889c0732,6ba150eb,cbe394a5,3bc9eed1,1c6759b0,4f8b82f9,79f24efd,b2469dff,6c9a2c99,7ee4f506,d3150dda,71ff54f0,88d8c904,596fd99d,d2f5017c,9d72fac6), -S(b6f64c81,b5e1ea08,8b712eb1,7a7ba7c4,ff4821e9,3e68c16,7f385e5c,d5e097e5,99286e7b,2c2b49f6,2c2a5d9a,58db244,5e5f4981,b1a7f40b,b0f86004,40e249a7), -S(4b131fc,5d5c5020,48aa2195,c079cb10,8bd101bf,bf4f54db,793bff99,3c2e4a0f,a689fc36,fb782cb5,c9722f4f,8f123ab9,5fc02dd,d1caafd7,eee117e2,e58c6609), -S(8bc5c221,9248c065,b713a126,facbeb63,ef435ce,6759ced7,62e189d8,82adfb92,6663fdc7,32a65abc,8b207cad,dd72ed15,68bdf3bf,c2e84345,9f964f73,fa325216), -S(ad8ca6f2,f29699e7,c4b055c5,bac3738e,d3b390db,21512a70,c3bc452,e231722,fbfd004d,174964ff,273fe355,d76281f,b47fa1be,eae7ec13,6e4cb5ca,5e703b54), -S(12270e16,b82ac7b2,20bee7f9,8c45c6d7,87d14d3c,2e9a2201,67650e2d,c56110b0,390c44c7,4d01351f,78b80029,e84b211d,4cba691,1201864a,d0632466,ee747bad), -S(48cb4d0f,e669f556,5c7e630b,bf435d0c,b0b47511,553301dd,a9bf6e35,b59fb9cd,be02b272,e6fb4e3e,79d6655a,aa37a132,8649b74d,4ab6d733,6cbcd1cb,d02d3f60), -S(558b4a91,b01ae7af,dbe952be,e03987d2,bc64337a,8178c079,f06ee88e,88b4fcc1,1dd61340,ab7dd93a,6b6e169,a4879fbf,75d24270,b0708cc7,51552ca4,f6018052), -S(af5fb90b,d4d48260,9fc8f8b4,34724c8d,162997f2,a6afe68d,97a6bf46,629aee86,ddfea22b,6fd0c331,68a196aa,29c0f0c6,7e828768,15527132,99c37e69,f788c4ad), -S(2ba58b64,b588a995,3872a303,8f478ee7,ae03b805,afa95c54,62920a80,8a12228f,b902f3ef,aa4a081d,1260030d,44d31436,7c5a5b7f,4ccc47c0,1f82035d,af92c39e)}, -{S(df9c2e20,68e1e333,f6acc6c3,ba9928eb,e761d4b0,27eaa1de,dae18079,29705021,491f455b,6e937f91,35fe9060,a8c5b6c1,60de5af9,ba90aba4,c060145a,da1b032d), -S(17cdf19b,1f93cbf4,47e2f77c,6f4adee6,bb62f01,8011e8c9,965eb336,899d4b6b,5d5d7d2b,33222ede,aa07c15d,7f07981b,a7a80c94,d9a4f2fe,7413b4c1,dff20e7b), -S(de7b1e48,3d1e4e54,39a65ab,b74bf705,92a75671,11f83390,78699547,ad798cdd,61087a47,1c37aa33,f538234a,9179e9ee,b4af8e89,7d1f5afb,497ae5ac,8609f8ce), -S(8baae56e,4774ca16,4bb58827,896bb7fd,6dbde044,3e88eb57,aef2cd98,e3968870,7edcb7e0,29411a39,bdc581d3,3a8769da,d0bb62b7,49e2e05e,4b698b73,d77471d), -S(74bcf4a8,18f280ae,6216e44b,fa8c65f5,4de08ee,14f2451e,ab85dbb6,33ecbc27,a72d7c82,19b2307a,3747a6af,e17480bc,12fbadd9,f326a09b,442e5f7c,fa18aa28), -S(8c24276a,5f468d59,d55a0ece,ffd642ca,ad8a7dbf,bd3ca6e9,abda6a3c,3e66c01c,b7463b3b,6fddb0c,cc2b9006,a7af9ba5,346921c1,ccfd24e7,4bb2d09e,9cf78c16), -S(ca4c86a5,438e1b85,aeb79319,95bb4cbb,c2ca6eeb,22eb18c4,449f8050,f8403023,6a86b9d2,d205188e,f6bd4414,1f9948df,7d9bb06a,538d5016,fe310d53,b3a95d18), -S(768b3d99,cf1a2d36,972615c0,b9dd964f,74692061,1d36bbe,892512,5855ae6c,5e821acd,1a49c270,b589b382,159ee4aa,ddf1a163,3f00513a,935f0f05,d4174dc9), -S(f69a77b2,368aa4d3,55639610,d3a4d6b2,72638efd,4ae36772,3868146c,50a81e0c,afc09cea,e975c008,c02827f2,86b4a85a,25e9f5ad,7e26ddf5,fe73f77,edff3141), -S(4d266e6d,8805e372,2ae985c0,3f808e09,4012a97,23cde34b,cc119732,1e3eeb4d,5747f4bb,38eb2a19,74315a74,7fecf1be,2633e3b6,93a6571a,e08bc2d6,8ee984ab), -S(6ccfa6fa,a5bc8629,10cffbd1,c7815328,bbe40716,62b6e66f,3e6db1fe,d796430f,1bb21cdf,c4aeb248,454a6e96,e6399a56,e872effb,ed3c89b6,95d52598,6b801367), -S(2bcac4d9,ad3f7bb,784ff508,3ee24058,871f92c6,db50cefa,3d84707e,8576c271,c2faffb2,f59066f,1ef1e186,3510f9d8,236d9d6c,37a9d5e2,9dc1bd37,1a349074), -S(4ab261a1,8413f27a,328dd402,4dcdc6fc,6d31d071,f479d8c0,f1857f0,2ace11a1,e53ea413,8cd3ff01,21acc725,345ce814,a6739aea,e4600dbb,258df68e,9e3dc4eb), -S(7c276455,398e6e95,45e253a6,b6381d74,1cee69cb,214686be,a81435d1,eb90c86,704bebf6,c434161a,66db20b9,5c859064,a339ffc,35510e49,bc378440,f6794d09), -S(b3a041b7,cf5e1d80,ed040d11,851e5e5,292b7a20,b125f018,979d2853,4e0b2d6,f8f8767,5801504b,98013371,525962f8,d40b44fd,d54862ea,4bd33629,b34deba9), -S(d10e348f,403ae107,5ac0f8af,b81b17a3,aa0d51f9,2cc8d271,2bb2d4f4,cea9a881,5fd767b,30135e1,418ee9b,b83719e0,5f99c3a8,87733c13,695dbdce,c1b26ec0)}, -{S(afdfa934,6f7bcc74,ec473e17,f5048650,11c5251b,bd6c0c70,c25cb561,4b004da8,b16eec26,d575cec6,b8720f94,4ccdddd,78a5c446,a0cf286,fd933f6a,999a4a39), -S(5a4fce51,d54d54ba,b8148e3f,2f8da91a,50c5a4c0,409be13b,723f3ed,7879e1e2,5ae7c52c,f602d6d3,b68f6989,f6e7cb97,484de6f8,d729dbbe,587756b8,cc8b2d1a), -S(53831467,eba14563,3181b826,839812e3,36c1a17d,ffe4bfae,f2baec53,ff428d8e,fa471d8,73ba000c,8d23b0d,6bf79d36,f57a7852,4aa8c52b,227fc42c,400b4fe9), -S(ab384400,3f19fcfc,10055f6,290a0540,cf2242d0,ccab8a4c,40319440,54f0aebb,af368bca,e17e62a,ec0a5544,4d65ecd3,a497306a,eff4a439,92e7d1d8,ed5495ea), -S(ed08f215,50f6510e,e8cb5e09,53ca47a3,9a140441,cd7dc8ac,2c319ca8,cd51c781,39e4c088,589c9851,b78aef9f,33678f7c,ed46d4a,658ccf49,b1c4de72,9fe3b64f), -S(feba0c3d,930d3c71,d2edd2e8,e63e5f67,3f81ea4a,5f8890eb,3fdc6e6e,9c729830,a507a2a8,a0fd3d76,214f59d0,cab63525,54148970,7cd0ae2c,6488efac,7d494d99), -S(f5da1419,be3e268d,b51dea4b,af8867f0,a02a29c9,599266e6,e0e37b,d569d8b,1ecd596,4748be32,44cfe953,6fa9ae30,104b1e6b,8ccd69f4,1e5891e2,242db1c8), -S(eaae3a45,5aa38fed,381ed64f,b6353d0f,2236d267,97f5dc1a,4e7a511,1654be5b,24f1dedd,7f3d9cef,572e7819,b09be2a0,de1f2f4a,6b2314f7,57a81b18,cd1fdd08), -S(a997a9f1,e9fb824d,768fa890,b91ec55f,c851127,5c16eb4a,99577fe4,87d155e5,9cf136a2,c3fd76f8,d4921bba,9d61917,b6ebbfa,f55a4cf5,69665d47,bce7a44c), -S(f20287b,958ffe72,72d443cd,de9fa6f5,f9ab208f,a74c6147,10c44c33,3777f1,ce614f5f,87c3a366,65d7f574,5446d80a,35a8113,1fb4dd2a,aabed948,b9e09931), -S(f9fb85f3,fc4e45a1,6b6eef55,cd8656db,de777390,f20b576,a28110da,e8ce5713,51de9f5a,7b2f0101,cd02e6c7,c98cdf93,a430d62a,1fec4f3e,95bdc3bf,a2212e13), -S(d5fa0933,f13c1f4e,89caeba4,101f44c0,420da5c6,7bfe1ea9,66cf01a5,ef48b1d8,5efc8918,8b9eb65d,faa6e0e9,812407ef,35d8db,76f9e722,ff63bc3c,3afc3b1a), -S(93899e6f,fc291a4b,e986f938,b8b378be,bf4c3d35,f9a1bdd3,ecea5f04,d8f4bada,a19a2983,55cb62fc,43334649,1c89f26d,fbb67bc3,872f7512,9229cb73,d126293e), -S(8fe07488,b5b173c,d530d796,a18eac08,80164c2a,ed787b05,90ac8dce,3bb120d8,829abce1,43ea8009,e4f5f481,125ca6d4,ecff3f32,577cdbf1,c054a23e,67f18b0b), -S(10c3b093,5461407c,369494a7,631eb4a2,365b122e,ce0a6b95,7c1bdbee,387394a4,f09d69ec,925c9a43,57648509,f7db85a9,22f609cd,32b400ce,3a80567,88a74627), -S(cfe48dfc,f5566fbd,7562ed68,576a7911,baef64f0,dc63e158,1a29bf23,3e1a058e,440c6051,19f2a948,b4b6c3a2,7e711cea,c7983d7,f4a2db9,537536db,fdebab76)}, -{S(53d772b6,b18211f7,1478e9d3,3a0c061e,2d232358,44177867,af91508d,e014f22d,b2e85a07,8160d31c,3ca32d9c,ba025904,1bea0368,d9eb13de,8af8f505,73142ed8), -S(b9d6067c,fc26ba4a,1f5bab8e,d5f28ffc,bb6bd6,b61990c4,1b091ec8,2cba973f,532d0ab,7731c02d,91cc7e51,71b625b3,af5a605,d92d02a5,fc4cee4f,afa09ebb), -S(e8a93ceb,3db0a4a3,9a3b768c,700fb504,652161e0,4a1d4d92,df52cd4b,83e65e38,791b967f,22543fea,9ec38e5e,a14a94cc,9d11ea8a,73ca0c13,e022d53b,f8bf1148), -S(ac6130f7,41e1601f,5a92bb75,90a799a8,3e8ad9c,c911ed7b,7dee1bcf,da14f332,97ea5d16,d5c7e368,c7b97c2d,7283cb03,f215f79c,d1d80276,6f9923e0,ce80ce44), -S(ac34d4c1,1d2d4ade,2f044e88,6b57cd45,c1b23550,538059c4,e9855077,4132643c,7191e155,aeb3b578,6b55db41,652e8af2,bac1f933,d6f62723,808c6172,bf0eb0aa), -S(a7c4bafb,f1988992,1ce15754,187d41b9,eb653dd,bc97cf05,ddf449d8,c9ff734c,ccf20733,da4aab6d,81db8d5a,d3f12d1d,9cbc943,8b92165c,e83c5afa,5ee108e3), -S(c04ba857,e758fdb0,29c02712,1671fe33,9b7184b3,50ad952e,9d234681,43f7568d,9ce5d9ca,65f96b76,b4b06f57,f34de7e3,c64a1d21,f07fd6fd,eb7d47e7,bbf4e6c8), -S(8230e7e7,81259e58,e9b74a49,340733dc,252bef7b,5b7dc82,a4e99f0b,2998ba67,9c71921,3b3254d1,f53b4f30,d0a8e665,186e272c,d0e5d316,a7451eb3,2ac8bb3f), -S(720c2f5f,6465d38d,3916939f,8d095657,e547cc5f,849f4a41,30485b1,2d94b5c7,8635961f,5f74d176,e4ae0ec6,e4b3b394,6d5b1766,fcb902fd,9f9bd982,2ad4e4c4), -S(263b45ca,b3547cf1,5eca4381,3d1c402e,5c209d3e,34a288cf,182aa4a3,f04304f,3516b1f3,524bbdcc,fddd94bc,fb86a43a,27a7a78a,fcbbefdd,6692fc21,87364438), -S(4edb7d61,a45ebb51,1fb0c220,6f16fe60,5a202976,9007c3e7,11b94889,a983d0c8,b482fee3,fe824b1a,3251cd2c,3f38ab4f,adad1fee,d398be92,58d2c81d,79b0eb36), -S(f44c286a,b8196e25,87c225f7,2091db05,e47f18b,5b9a0b9,79d2cd3b,15441767,b7aa2018,5925845e,661ad980,a6c215d5,fd7072cb,46010930,ae64089,4c8a0af8), -S(593f9bdd,b246bd1e,19eeaafa,17e348e,5199decc,8e63ef68,ed8bff89,bdffad48,5201d11f,a4ac67db,dd66fbaf,5c2ba20f,8bb1a6b3,18cdfbac,6b257aa8,d30dd316), -S(823b4c96,8be9e125,262d52d9,4aaff240,55def10d,6353a347,e4248de0,7889ecb2,adfafa7a,fb1c60e,e7fb3e2e,73c66063,5a9e97e0,4a38a120,b7a81f17,7d1a6c41), -S(8daef78b,c46e0f5f,858fd74c,68be31bd,3b474d9,6bd74deb,eeba69af,5ef3056a,15db0684,bb6d4e7f,b135a4ab,f4b81d4a,a9fc7e93,c26e3616,b7b938da,25d44a06), -S(2b7616ca,eb608427,5a14eb53,b67a2ee3,b831fb55,6f63e0b2,e01650f6,e6900a0d,915e7dbc,62f8e349,8ffdf22d,d3604d77,bb701137,b6c36543,84cce993,c4613ca4)} -#endif -#if ECMULT_GEN_PREC_BITS == 8 -{S(3a9ed373,6eed3eec,9aeb5ac0,21b54652,56817b1f,8de6cd0,fbcee548,ba044bb5,7bcc5928,bdc9c023,dfc663b8,9e4f6969,ab751798,8e600ec1,d242010c,45c7974a), -S(e44d7675,c3cb2857,4e133c01,a74f4afc,5ce684f8,4a789711,603f7c4f,50abef58,25bcb62f,fe2e2ce2,196ad86c,a006e20,8c64d21b,b25320a3,b5574b9c,1e1bfb4b), -S(6ada98a4,8118166f,e7082591,d6cda51e,914b60b1,49696270,3350249b,ee8d4770,c234dfad,f3847877,a0a7bcda,112dba85,1cdddf00,84d0c07,df1d1a,a3ec3aeb), -S(a94ae8,63264dfb,b910ea95,4ce9ca7e,4f86f92d,9f3a95d1,ed61552a,7a3f5743,7f53f7f1,6ad2d08f,15e73314,6d80467,41557acf,19556c0f,ed7117ce,37040823), -S(b692c750,d23d3674,c351e3b7,e1a8a87b,14a5df81,852eaf35,209d0ec5,6e22a2cf,b18c4f17,252db89f,838de32f,b3340ea2,bb961a39,54b38c47,f9a8219c,4820a0cb), -S(691fc741,80e75b55,47b375f1,1bf60abe,451d27de,1743a436,5f8e4bac,ad421c09,8eb5fd9d,f3c03240,6cebf370,8125955f,bf2ef703,475d3fd6,1a0291b6,69b52d9d), -S(703b5f14,a7d82473,1196b52f,ae9ca8cb,b245b004,7a9928d7,d0c42f33,391411dc,5ed74eaa,49f276c0,4d61f31b,6da4137c,bde5673d,8e3f815d,efea7951,f88585c), -S(29b8ec47,d241eda1,e51bbb1e,3928444c,3747b4fe,7cecb365,2bbc4587,2f504875,88693238,8562f8bf,f7d72324,62ebc54,6b93a95f,77936b02,eb1cd6a7,d4199bcb), -S(444a07ad,e81916c9,32bdeec2,21c556c4,6b7f6491,e99b479,2cfec82f,4ec17910,2e084c2f,eead5200,77c151b6,eff9375a,713b9d15,5306708d,b3f538e1,8eb18cf), -S(e0dd618b,226ceddc,f560527e,20b4fe58,e5fcf28,39911ea6,c3e8a4a7,e15f9121,a063a157,3377bbbf,1b9a5ebe,afbe11aa,660c1e65,df1392b8,97205858,3c86a3fc), -S(9b99461a,2e8360f2,f2ba0bb8,bcaeb699,159e0652,69d9042a,fa0c4e30,a7b6f30d,3fe7fe04,3cb45303,3d4f5560,7d41cd76,9036a49b,82912350,6d8b9995,254154fd), -S(504da3a9,d9d9c81b,c2065398,4ed28cb1,b5beec9b,6ce5dfb6,cea94e54,fdff044b,cbd40d1e,858133c9,cd20b9e4,ff9fe94,f7cc9579,39e6df49,7a6bd702,797f96cf), -S(ddec0aac,1ebce6aa,ad6300d5,60f0e503,829f0bc6,479641f9,b19d9f6,484376fb,332ff5b1,fc83085e,736736bf,3c265e4c,8f80925e,6f38479d,6563bc34,e5faea1), -S(dc530ceb,b82c246e,41c522f1,d2571d31,4b14edf3,91577a2b,64e42172,b23562c1,563ddd93,857d6529,8b81de24,19e5cede,7a4c5b7,a2fe98f6,9efb8906,6f32a98a), -S(7604d60f,418dd132,78058942,fb2d2153,c0a2bfeb,e83c5011,a451bcb1,58db0773,38be14ae,d9e1c404,63ef92bd,d62c599a,b37625a8,182a3763,4fa2de90,535d50a9), -S(cb896744,77b20829,f5e2bd42,8852c70b,91cbd0af,cadf219,a69727b4,cbec8d7a,5710d17a,20ea0dff,980d3f06,38d8b910,b8940d00,dd4a323f,d777d942,213e1093), -S(501915b1,391e083d,e88c795f,8464c846,f699a79e,edb1b963,3e29f71a,9ce4d022,9e1dcc94,17ceb0e,15762f8f,7d0db85f,3bce3ad6,fecbe2c3,567853ef,ccd6d0f9), -S(a63c0b8a,4eb2cb10,1e556904,a7246356,9909055,f45aa4c0,e89c2237,cbffafca,9650b428,12374811,738f4ac3,a2ac0505,396339be,4eeeda8b,c35e6fdd,c51a1e56), -S(a16760e5,c3643d19,da15c034,5feced27,488ccafa,ad5298fa,6ee1070d,a258a761,736a7c7e,69db053,6f541079,158d671d,598efb1c,d75ec804,c7b2b49b,1ad7638a), -S(840693fe,73b96819,bb1b24a9,35d5dc83,f361273c,d0989e76,1edc35ef,50faf90b,4294e19b,49558667,bc6237c6,86c30aba,a2660580,563d465a,fde9875d,74c9a57f), -S(97273c3e,26e12369,1d0ade3,3aa261cd,a45b2d2c,d749af71,a60c0d15,85e18e03,2700c565,dbb08439,fb74317e,60776fca,d0efc1a5,5d0ad87c,18f82f2d,a97caf19), -S(978d68a0,5ce30528,e4db2dae,99f6a245,f69cbd04,3c7171ce,ce2bee57,60e68b9,ffef379c,1515b068,df562f3f,bdadacfb,8aabe5aa,466105d1,97a8febc,1596915b), -S(dfaea7bc,c78d275d,9f6a74fd,21fdec14,bcabfa45,e44070c1,9c44d449,c5d52231,927b810b,c2994b8d,2ed5124d,98e2f5cc,58410607,82b1ed80,d0fae288,8c42d538), -S(ca0b766b,8b8d76fd,ce471a88,18e043d2,604d1ad2,b689cbce,70ceae78,fddf5a27,ddf9e3bc,935ea0bc,22f977ab,98a92414,643140ae,be0448a3,35d6d44a,1bedfc48), -S(11dcc001,3be8d4b7,85e87153,e060d13,57cabb5,34a2c1de,2a4a70cb,9803a031,5b5d46b0,6a96c30c,b1901c12,eaa1c656,3a2f35b1,e9026954,36e087aa,3deb777e), -S(a828121a,18d23262,bce26648,ab44c45d,c5027ae3,f74786b9,598f22b3,c408bf08,37893209,80d7d2de,6074778b,2e8916f0,4043a616,982a9b61,d4089623,31375cab), -S(291ec5eb,e010daff,3ac00825,3452b065,d9f7fcb3,66e125af,22f11358,6263fbaf,4647cba2,45d190d8,2337f217,c278c98c,370120b3,d4e04110,e6df2c54,92d63bb7), -S(44735d48,4c584d70,6afc573e,8ece7670,c79c7b99,99eb0141,4a73905d,34a1cf01,30a27c9f,67b47348,583f1e84,5e7af221,438d4c9f,a1e0cc19,7312ec6b,908d613b), -S(fce8958f,507d5d59,bf0fb944,7be40c23,db2741e6,f89351a7,f29fc642,a60c7d4a,69de744b,9d2ef778,a7280325,bc699cb8,29874d33,bacc1fe7,6264eff,600c815b), -S(171a3251,bc6e72cd,630f8130,d4695e48,e0e649c6,82bdd5b1,b87c7b7c,968cf664,3492ac7,faf2ab56,cfdd5278,9831ea1d,e90ddaa6,b4d6e6e6,fa960bab,2b55a55c), -S(adc566cc,6c9afbe1,41a011fe,e121f0b9,a5dded68,fa9cdf63,45a00fdd,d38d69b3,38db9e85,26ab355b,5ed12b5e,84e795e7,7e2d2c57,24cec516,9cca1946,1d8d9c04), -S(9694e1df,8067defc,de9dd34b,4a4bc91b,653ede57,3139b9f9,4df55858,74f04,f002d8b4,3940cd6b,7cba586e,18f1616e,db907010,230445d1,a96b9eee,b43778fa), -S(8a90adbb,a8c32e,a9149e02,57bd9d24,7da8b0f6,5cd6332c,5803f83e,26a1bdc5,f7f24ef2,aae5a954,db200e45,ae75bdfd,5f4ec6d7,b203459a,7360a9b1,5ae2a9d7), -S(234b3911,f965ef93,5ab16aa2,392d2198,f5df9022,962ceae3,5e73f05e,d7d8f817,a66aa264,a24e1a5c,e9bd5ce6,164cde8,4083c7b9,c354ebbc,caac78c3,f5da2aad), -S(7d22623c,84ed234,5194c248,eb984ad1,28d2d4b,638b687f,730a3693,10f1c4ed,f97e515b,618719be,ea3603ad,7c40e827,59bff425,a8633365,c28c755e,b06769c1), -S(e210b4e3,cf3a2e24,951b0623,a83a8793,11cb942,8d679cbb,16a15718,2e6655eb,f4bfb50,43768438,592e7b75,41bee9c5,f263dc15,59be620,c0dc128b,d5e29339), -S(878c0097,ddb0f977,d75d579e,ca8d0bf1,a887fe50,e33b0c8b,bbaf2874,8875b321,a3401763,39f99298,9335879c,dd43a46e,d21d1387,55be87c9,2f486629,49918020), -S(9a6dee6,4c79975d,2adcccf2,8cbd8bcd,c8bbff9b,2811039d,5a6fc051,9a212503,9c0f3d81,5d56afc8,31de81f2,750cb54,9fd5fc63,b63e2c66,ae88dffa,cd072236), -S(3fa53681,f50925b2,710b66ca,1efa5e8f,b819c5e4,206a591f,d1492a1e,d13279f5,82a5c753,367d57d4,fdad7e9e,8b7ba625,7c50c07,10f93c8,5cb180e1,a459698a), -S(7ce51172,8f94ef7,7924a1fb,fa8b7d1d,411d0e21,65c4a1ec,e105d4a0,909081cb,dbd596d1,bda2f32e,12cdc910,2762f3cd,627cf29b,1b145ca9,dd2037f1,7daa6a86), -S(afbee9e6,d5b0bd25,1dd70bc9,e3b3a013,40116e09,905bb29b,797ba66c,16db5135,8a315473,84275d82,3c5296ed,b56ef5d9,7af96617,dc2e507,c009be9c,f3d3da4), -S(14d13a78,96bd0978,d4a4d4d5,2266afd2,e0f21ea,5c1a693a,9ed4990,81e43974,dc84f2d1,86d91fca,62ef088d,1794715c,c8dcd9fe,efb4aa5c,46800240,886c41dc), -S(7bc1045c,4960054a,fc979961,5cd7faee,5dec92bb,98b4c3d0,9620a488,fd32c35a,b8f420ec,cb5dd9ae,3f075e28,811ec9ca,bd770836,ad40371,66073db5,c1166735), -S(fa24d112,4cf21fd1,bfb06c10,9fa49f10,c3ab248e,3d08f620,4529612b,f7a5328e,c0745547,b64a0068,25ae8f90,82f8565f,ed94865a,d185a364,602e6468,277b3cb9), -S(8758ade8,745d4d18,c8f7ad6a,32fa05e1,c7a08bcf,c7cad42f,7aef474b,de02cff3,7864edbd,2efcbdc3,946dd250,6fdc2ea5,2f1626e0,b7300f8,9ef16420,12ae4853), -S(d2783741,6944bdaa,d212dbd9,40cdc7fc,2847fe5c,a6eabd45,dd6daa9b,9e122693,c7139931,989b4f6d,3acf854d,5aec897,52c69105,2c6d2586,27ef13b7,66e91875), -S(624120d8,420a5afb,64673e4e,b272f7a9,3b7f1f7b,59f4b145,10115691,70a597a2,3e055b16,ce482c12,88bcb9f7,40128b71,e5a441b,4c45056c,dca1466c,6491cad2), -S(96a21be9,a6e8b94c,7ebd4782,809830ac,f2a373fc,6781405f,a320025a,e7bcb4de,772ce6fb,711c2898,dc8446,aaa8cc7b,41608392,6212908b,705ca412,1e2c5e1b), -S(a9e2a4b6,4032f43,46ee1148,46ba487d,9a82f80d,3408b8ea,8434c521,33135ce8,c8537b6e,51846fc3,18898604,192d86a6,36ba3c36,f7ec9aa9,6185e7be,f160b5d3), -S(b43b42e9,381358ce,b8a595c4,77a9caf4,afc6e0db,1f58af55,6dc5bbdf,2cb4449a,556e4e70,cf7d1a16,9249e954,b749619c,dd87aa7c,723176b1,7361966d,2d2b6fa), -S(224cd0fc,393fb763,bfbc3c44,b829f61a,22ae6b98,22622367,2d0890c3,eb9ce9e5,97273eeb,eb71bdb6,5ac5c677,807a533a,f190cd12,e01ccb9a,d617af76,c3bef1ae), -S(6c997b99,b7349b8b,6f399b78,34bcf510,56f070d4,b501f8a3,28ef3a39,7f6019ea,370796ed,ee708852,6ae9ba78,2aac403e,5b57dd21,cc77d0e,1674d6f4,e4ec60e), -S(9c8970cd,125f1c6,1b845a19,a153ef53,594bc62a,3121d43c,e9890888,9c5a7adf,2157717c,55747f64,b8b51feb,9a6c8483,6dc4de7f,40908ff4,4e37d7e9,ef1354b3), -S(eaf2ac12,6894bce4,8862c0de,165c03d6,4c561cb9,d338cb84,17d8811d,55af309d,f9e8f0f3,eeedcb85,67232a8e,cdbcbbfa,1a3b1a67,7a67c129,f07e091d,bb82ca78), -S(8b69c681,7de28f6d,c539687d,28dd6a0,7cf16302,f0cc0f41,a340f6b,2a5669a5,576e108d,b9ae716c,91859b28,25de886,2de16591,eac5cf3d,5a802785,4551f778), -S(aec8ab4d,f8c21840,c3d449f1,cf1100ff,baa91729,a35efbd2,53ad4ca,92af4d19,2350038d,bed217b6,353c31dd,bee52f96,e1706e8b,45350e96,6c55a522,b536ab3d), -S(32b75afb,9fc485f1,744c18ce,8987deb9,51cfd485,26aa491,3dcff45,6b5e394e,c5edbb3e,4b95fb5f,55d24017,86fe65e7,9b8c20f,4e927e2a,caeb2b0a,1aa34ae), -S(a2eba275,e957dcf1,a493b7c8,6ab340d4,647b6951,f8919dd6,ee0274db,a2178016,b89cabbc,ead15406,f57f0763,9cc5e036,45ddc32f,1283c556,ddf94eb8,e0e9cecd), -S(6af5da12,7be295c7,9485e35a,e0a6df36,302bfac3,a20a4325,13e81233,142d4ef9,c7df8582,7682d324,5f7a8d0f,9d17d460,53227aec,28c1de97,23afcf52,96bb8c7b), -S(1c06f8d6,6cebe13e,7cf9ab04,12cbb75a,741a2240,6b89170b,8e11c92b,84d5c9af,cb3b69a2,7a55b2f9,ba3f9ccb,67c50502,c024e8e6,556e7c42,9cea3f58,ad5028a0), -S(a9e3488f,c2dc8af0,a913227e,9ceb31a5,171fcbb9,752d8e82,1249a152,57b655ec,e07fb0fb,d8c6320b,d64645c8,e6785457,652e186d,951e0f92,f91a7ec,171bc993), -S(9d93b099,9bfd6ee3,2919d4d1,88896b80,46f07249,f913d92e,e1c27cf0,40d47277,bac5a0b9,cc9ff8d9,b6274be2,15c49e3a,67131b92,53f7e30f,44d401d7,97f47b30), -S(dd25451c,57c2ab68,542392ca,91e58a50,dd578648,36096c20,bfa8783c,1c359a8,5fcb8e40,32265bec,f5eb02a2,f07980d8,b56fb0fc,de51f140,a1ccf391,b8928602), -S(ca0ffd05,530a0671,fe49d0a2,4a0a0eb5,b19397cd,e8f881eb,542f7919,e793b260,638db61a,bbc020ce,ae9359d,3876f8bf,5ec75498,7f623d89,c3da60e8,f84b6960), -S(117ea7b5,1440731f,403d8485,a300d59e,a571deb2,44dc5bca,20352513,b5d0f691,7e72f426,20ac70e6,2ddd8ee8,edbdaa41,e9e7f46e,c8143f29,95c77289,298ca3f4), -S(c1791bcf,7d2d5477,24c30d4c,d5e8529c,2f03d7a9,711395cf,ddc5ee69,d0745064,30ba86d2,abed8606,1e9d2012,a0079813,26b232eb,34356b08,1afe7de9,3c79eb1), -S(2faa17b5,81123ed2,af8a2393,6b941de2,1cd3d276,4ca47347,5b27703a,f9b4b401,4fab0769,85484ad2,d2352ae2,9a74e90f,7d5d9514,c333443d,8ed54283,c7634ce6), -S(4bc4063e,68d9fed8,185ee402,8b4e1bf6,87c6c73c,c21f6131,799edc8e,83884ccf,3af276b4,24dc5208,7dca3be6,a5e0a133,2c427516,7cddfe4c,ec0710f9,41c62ecd), -S(e0c4a4f9,5fa0f060,b986214,68eb0131,1162accb,ec452a6,2756d36d,8aea45d6,88a49bb7,a66866db,e6905ce6,c15cae3f,2f98de34,7bbdbfda,ab2cd99,fc06297d), -S(6892a64a,e22fa15b,c0e540b2,b75d307d,ccb20675,10ed3d59,702312dc,27882d02,ffda7d9,bac7a8b2,4f83c1b2,11dbc454,8eca5023,30829ea,f5b47a9c,befb451a), -S(def9f462,12aa6e8,3d4578a6,9bece7a0,9e91ec9,28eba3f1,54afac97,d2418785,fba8f869,fbb39c64,8613ce1c,1c36d86d,f326f334,6de2200c,93c8e1f7,bace82e9), -S(32e37792,4336c65f,b112af1a,6978b5de,bc2e2f0a,f6f0b4cd,b6cad6f5,e0d4c177,d3cd48a0,61f45605,e2cfbbe6,9b636cf8,3c8afe36,6e7c8a72,b2cc1b47,a58abd1b), -S(1fd685df,86bfb84e,8bb90216,1a6a0e14,e111667c,aeea586,7f45b6cd,3f411527,be7d8cb4,c3723bfc,f2219442,9e164abd,65258c57,68509e1,a72e3ea5,b13ca966), -S(bc7775ab,a334a06c,c284be77,8e9a8b88,358f3ebd,7fa2a370,2f7700f1,53c93e94,dff3ec2c,84f8c35b,fc869ad,76139913,c25b379,8ddb1e69,4802ac27,602f4a6a), -S(2a3f2aab,10c9e9fb,cecb54c2,c411bd70,38334230,f2286b62,c06db5c2,6b74a6d0,42497e29,37395239,c102a1da,a08580ac,54fb89fa,7f2d2974,8b4f2081,bf15fcef), -S(d5c9be7b,985d769,3d5e7b96,3778daab,49944cf9,8ba2a522,b33d32de,1a7ca3a7,3122fb41,440c3f67,478e116c,1db5b65,2c8d137b,65cb712f,9d235e0e,686ea04), -S(aa772a33,12f19258,b1165378,1376caf9,16c73e3,8b842fa6,3237bf82,63ca771d,95df79b1,ca3951fa,3df74e4e,90db4a4d,b36fd7ee,1758e7c9,9e853faf,959e071e), -S(1faa7b4b,610b3060,166011fb,6eac0337,a8cb6dfa,9e90a8bd,6a84341e,11577791,716cedd4,ce760e78,a2e664ce,baf834ff,725b4296,3e23004a,ef309b5a,662cc36), -S(50a6be45,e41dcf82,659d0690,9aea539c,10fca3da,73a00372,fe9b2db5,46d7fb8a,ffafe7bc,adb82924,6ba72ddb,776b39b6,4a77627c,d36ac0b2,cc73e5ad,84740acd), -S(e27561a,6a206e59,2a8c7747,29d2968b,294378e9,9014f9d1,26eff921,133a1e2b,bc80b28d,573f7502,56da86d3,4118e699,75c671b1,e38b1d9d,1859fb83,681d9931), -S(cd5de182,85de5152,312ddef2,10d36849,a0a638fc,4215e232,13427899,268762f1,f0a0a3ba,b9149edb,c5d6586b,b50471d1,a7db3ec3,cc94ea9c,f9240683,d4ec2c44), -S(9f51022d,30e18985,ae67301b,5db7a3d6,2165335d,e3be70c6,e4f703be,d531199c,43c934d5,39144f1d,43401b71,605b08df,1bcb8bf1,ba3ee1e3,5c591a46,12328552), -S(b014734b,7b204960,adbf1329,129cb3dd,5d9b84a3,6367e643,76df433b,bafc9d2d,56dd6c55,46cef764,574944b2,c9cca7af,7ccb438b,2ffb31c5,7faff8bf,fc21eb09), -S(43f9f9db,bee57d22,e77b51dd,8aae4b30,3849d709,d06353be,8454db01,89b4a34e,f8962178,ae383491,28950190,1a290ed,23ca986a,dd0ea6fd,861f0162,d8032d4c), -S(1ce55c7e,10453890,c9b9171a,bc0d13c6,2ff6b802,1da6c47d,389d0558,c643a8b8,3363feef,920ea3e,b4cdffee,582e91f,7a02bf41,d11afcde,236369c4,4ba76ec9), -S(b45890e8,1ec53e8b,fa7373c9,c0160e69,1d739b3d,538d70be,2c2aea62,b6f2a4ba,70901d9,5e139291,691e17fe,f0d48797,60ec6f61,245f2657,6b9ef283,f81973ec), -S(d8f16bad,a3430da7,9bc7beca,660154b0,28d44348,b73731d8,b2f23229,6188bfe,f7baf0b8,80b60a8f,575b10d1,988aab0b,c29cc9dc,66494727,9c728967,ea24f26e), -S(e74323af,218329de,4aad97b6,c57db6e9,3dfa53ac,784224e2,6b087813,6a74ec3e,42a427c5,e1c72445,881fb359,265f4507,13e933ae,f3b8b10f,b60593b1,c5440236), -S(f5dbabba,6a55736f,b0e2eb38,973882e,ddbcda9b,651a10a,abf0110c,29b6f4f6,74846161,4bd5a349,caad7c3c,46c534e5,3b7e5440,7e3e31c,1247f0ee,4cd181f1), -S(e2d744ce,d24b72c7,c65aac97,b0fece86,77cd7edb,5b2029c6,41a0acf2,8cf72009,1895df09,8d9fab64,b86a701b,efc9c69,ca083ca9,e962c270,bd7af27f,a46d6e75), -S(e4181c43,1c9c9f53,362ecfa6,685d7d28,4b0f09f0,6472a5ef,6f3f77fe,6d24e4e7,d2eb8214,6dc4bf71,dc30e935,c5621b1f,c09819a4,8e572a44,1ea8981d,191f7030), -S(ac36676d,10365635,72c8205e,af547ee7,3e15524b,ab15b489,a0c68f7f,854fcedb,71038dd1,91a1992,e0864fe8,3820eafd,693f05d8,b32df573,817cb314,a24623b9), -S(aad2148d,fd0dd61f,81456435,22d5cdc6,8beeadee,6f60c22a,f23f7183,83f96d88,d7115c62,3d8455f7,955d0772,3f083a7c,341f5bee,64aade0b,426e781,f683b7fd), -S(7e8bd881,b50374f4,10aa55f0,e45991de,737cde63,f03e8077,e29bfd8,55f3316c,244997ad,ebd2ec32,71d9604e,6f9b0bd9,fe330105,acf71224,b203cf83,26b3b1ec), -S(a68beaaf,899a89d3,4c18576d,d9041b36,a1fc14bd,bb8c1588,809494cf,e87ae7f,3ffa0192,3233f77d,f47d8bde,3fd04fc7,f57c2af3,52508343,3f7e810f,4b6330a3), -S(fa9317a6,7e2a74ba,d53ae152,6e3a8a4,d7e8a59c,a1aba4cd,ba46fb23,a1870f05,b9a22792,af785e1c,6b1fd9a3,626ba75e,28583f09,fbd0d3a6,bc9a64dd,23bce82c), -S(2f820b30,6175e982,b1951cef,551a61a4,f9595dcb,35b5f647,fe8dede3,f68e5226,d4f915ed,4f8b3bd,f7e8e0a0,ddd97719,d3e22ff0,8c24c9df,c665d0d9,c4b2e4bd), -S(eaec7330,271b9056,6e98cb0,717741f2,7957ec24,c51f22c7,c25c2cf3,db09cf24,6d6e0108,e103be2e,3f4c8ac1,4a216e40,d8a993d5,5b0e9b89,2219dce6,3e47ae47), -S(2cbcf67c,6e1dd8ea,888c2898,8f636842,ff4b855c,9fb539c9,f3a9a4c,8885c88e,4031a26,c3b13bb6,d0027967,2e1a6e1e,af5d957,e841dfc2,c396c8d0,4e816cb9), -S(9103dd8d,6265d5c6,7f50eb7f,2227977e,53a48e39,a86083ff,965f5d3d,2032a29c,6a1bc02,14930959,ebb9f967,2f9f693a,ff3cc3d8,df65af26,21cba530,425fcb1e), -S(b47cba2,cf3adf57,e6cde1b8,9edb3303,d7c138e1,b59ce4b5,a57a517,aa497285,8d173f6e,af4c0363,7486df13,3fc64826,5aa32348,24f64842,5e36e2ad,226cdc0b), -S(6d59d90,23507028,6f36a203,702fc9c9,c9936b68,b08e5025,9584e385,1410ca5e,ca676e85,cc25987a,4c8e582e,ff1d49f0,5736517f,39e2855a,20cc77f,c40a0860), -S(748fc197,201aae7e,80e01c30,ce77c315,2469403f,a3b85be0,bece627e,93f657a7,6cd7f6ee,73015cc1,28562867,44b1f7dd,33293c72,a54f3e2a,2edd7bc2,6d2aa384), -S(ba8b964e,aa862c8a,9075dbdc,a69d2b90,aeaccf05,27c562c6,f310b3b,adb6486e,6531492a,64203962,4f3ee722,1bfbfd54,c66ec11d,93a66775,c305bc6d,c9a9bda1), -S(7b3a1c20,dd36acca,83f548e0,16907006,4dee8579,1342818c,f1185e89,5f6728f4,1829aa73,168eeec0,897358cc,3c4b8d04,da2b8ed8,1654c1b6,816452a0,943feb0), -S(8e39a814,1cb73d12,a18180c2,50a5c574,4cd0f4ef,42500d3d,a0892da3,bf5d24e3,2496a20b,5e5e3dca,30581c10,cc099093,5ee51283,79b6672e,ffc171c7,3f4fe34f), -S(89bc0ad5,d0b615e6,1510abfa,6ee0856c,d3fb9b33,d53738e1,827f041b,c86547f6,d5bcabf9,f555af1a,2f365910,1af8b19f,a12089e3,21dc2053,8611c3a1,e6f6a904), -S(2350902d,df8c0944,da5ba2a6,c5a9f16a,eb735474,6fbaeba8,4fd5a58d,c2571ab,dd1bf357,ab9ac929,eba9b93b,3f311ddf,2f10aad3,18871982,2ef665f0,36ad3fe7), -S(e53f6624,70227a12,a01f237f,9ac59afc,685276e,440450b4,b8d91e1b,9159a61,a95ee3d,430328e,116128be,c17a74bd,a87b6fe1,3e0adad5,7834ad89,ed597404), -S(dbdc2b2,ecbf18e,58e352cb,aaded3,7324e063,557425f4,a8fb2a50,637f0af2,e5a80b8b,4cb5a7a,af1175b,fd62dbc,ff044f9f,4f03fb89,b768c6d3,72729996), -S(7fa717e6,e78c1641,82b2e,78c2fef9,bda57060,3d0df678,c4716b0a,55f7ca60,59bcdf92,4c9b981e,ad7b30ae,937ef1b7,63b12c69,9fe20e6b,a7c3002a,edf82d34), -S(330a50d2,1a87984c,e657be73,d2570875,75e261ec,ed17d9c8,7150d1e2,6afcaa0f,253f486d,642fcc6e,5d53b79b,8a24bf25,131a1b2a,25b931a4,fb2e6019,34c7df92), -S(762b5213,78d46c16,70251e93,2737c75f,f28e0500,eedd6ae0,62919874,660e865b,efaee12f,3b411bde,7e6e8bf6,3d875a89,68164f6a,ddf102fc,869613f1,e8bbc095), -S(717d699d,f3a985c,8a8a8562,cced0432,4b616e41,e4bd8ebc,43bc1b44,2e2f7b35,cba0f7e4,f4d544e7,6127892f,a5ef8bca,13241760,5be8e7ad,4fdabf66,e8fbe571), -S(124de3d8,54e69390,b6908c5f,c770f602,8439082b,9f9e5e5f,cbf5f822,2193611b,c9b9d896,bb1b5cab,58c10bd9,b6519ed4,a1d3be2a,39ebc4ec,781bd673,351ef376), -S(fcbf142a,a6d9930,33fd9a17,2c7f46b9,63237738,9b76572,2975407,ea8b2440,4366db31,a5acd6e0,a8bb3481,9a654233,e6babe82,bbcb5967,cabca638,e9a19987), -S(82858b62,5d2bbcc1,372e3c38,256b9b1,cf018f3b,3e9d0b70,c17d1ac0,fbf75ca9,e6543ada,7d9a8928,e3a1f6d,b8c15649,379fae57,f99dd8cc,3b096579,8e785840), -S(577b38d2,ffb278de,62ac0df5,ccb6f2c4,e8f40e5d,c5549a7a,4881831e,bfb6b71d,171651e4,7f9eee1c,60ce5d95,9e77b98f,ce651c3,c661d8db,4798372,8ba1c03c), -S(28a83552,9aed0508,34510350,14bef19b,c1f20936,3fbb447,6cf72fb4,26267c45,cf949cce,8b331182,670f5300,29e3df92,57a576f0,e5923a0c,146aecdc,2db60446), -S(621d99c7,abe3982d,889d3b11,6c992a6e,f035ba8d,aeddd4ac,d5d7b04,bbeac79f,2a6b0dc8,a6ede522,b86ecbbd,b057192d,84294e8c,385cdaf7,cc5777d3,607ca69a), -S(8c6395c0,3ecfbba6,82926be8,b6e8d4d6,cf204d50,9f805453,ee40a010,1fab3959,d22e5810,5fde2b81,b82859ca,97a05e7,4c278cfa,b4fac1e4,50e70928,d73b67e2), -S(80ecc87f,b9d4bc15,8e365e31,4518beda,7087f9e,c8086e47,91314d1a,9b37398f,6bfef3c7,8d2e91f0,67075036,385ed8a8,f3a84102,1e44df55,397290ec,68e44812), -S(22cb24d4,e1354314,b1f9bd,c7e37963,3ee08264,ea7fe2fb,2b23ebf9,a35c1438,6e88715d,9d5fe90a,d0940724,b597a55f,386bebee,5eaf32c7,6e95b2c4,d407c808), -S(285cc203,a4eb1e79,1695f8dd,d34a048d,58350aec,4fdc8157,fc1a8427,76b56e19,59cae7e4,435a37d,bd3c3f91,279c7bd6,1cc466d,b1831a53,94f7aadd,4e1e108a), -S(61275052,386f258d,28af0420,d010fa87,c55281bf,59b68b71,698eee9c,824913cb,8532eca9,645479d,9ef72ec3,6d96eb11,418f9619,b0fa95c2,c4c81c86,75a81e76), -S(84d391e4,d946c2f2,b40b5b5e,b6a57463,1adfd4d4,9e034ba1,3a2c862e,68b36c64,f3384ad6,cb7ccfaa,567a2cc8,73c9e509,b4c2de1e,95f7ad30,26be00c1,83ca7419), -S(34e2a77e,cce22a6e,849e1b21,4a6cc570,10e3a0ed,73799e14,51616724,410d854f,cfdd8819,f0af720a,a372b923,fa81eaee,c427f3b2,a29acd3b,ce6710c7,c186d039), -S(bc45065a,b558b2c6,a28b0cf3,8bd26384,f82dbb36,e2029774,561883ed,e6600bf6,22c5a0b8,3dc2bc02,93d7019,b4623b10,aea9d36a,22b04882,954e3daf,e1885b73), -S(4b92a803,94dd5669,c0fa2d3a,c4d1e7ee,8e2954a1,719d37b4,4b02e342,9d183ea8,9218836c,698a5fdb,f95e0e58,8b64ad3e,e3aaef7c,613b47e3,f1464443,a48e3396), -S(acbf0ef8,453addbb,9a4b04dc,3acf662a,d069d5eb,530d7a03,2e6a8708,be241f89,d46405fb,3c8862d0,4e7cc53c,51beead0,dffb3045,a6349fef,6fbbcb9e,cb414036), -S(adbaa36a,4fb531ce,eb084fc,e65f3397,22188967,a947acb5,9f7ea73,52aae5d9,719265f,7e9bf7aa,2d789d96,282e527b,819a252b,7de8915,f44077af,8cc1a8e1), -S(3f5a74c5,98b258ac,b1cb3ace,e55a7a26,78f4613e,b85d784e,1b3c8abd,978619c3,ba16385,ce0487ea,67932ed6,23aaee87,2debdc7a,2bd02ea4,6a681ebf,72ef5df3), -S(6a231807,3d2c0fe0,c89245f6,5dac4052,ce931129,85b83555,c4cdf8a4,f1574135,fe44cf76,f44f3d27,bcb7839f,588fe09e,c6a5aa95,d6ae52b5,8059c7a2,c6afaf71), -S(35555f0f,4fb2677e,dd12f235,2821ef3a,331c78df,3259128f,dcf62f69,85892dd0,101d97af,b1ff1197,3c8336df,bfbc346e,5c5e06e8,f11bd602,aa93f412,2f66c388), -S(d45797ba,61a836d5,13834d,abd3090c,bd139f05,dd67be2d,cd99ea7,66565756,61b0aa,ec1bba4f,6040382f,cb049126,f7e6ba72,9cc4dbe1,f511b792,32204a65), -S(c06dc164,8c07d57b,fa6cb488,1d9c96ea,26cccb68,d40d169,1890ec68,d42d584c,fd4ee4f9,16739643,66ead6cf,fcf31729,bae2263e,c57c14f1,29fc61da,cce93dbd), -S(6826672c,ebb04679,a68958ee,3f64dc3c,69248f3,cfe0f8a8,28b164ab,417a508d,ce38e638,f19b1a66,b5647be4,3ec24f0c,562a8dfa,1b278117,87f9292b,8cba215f), -S(a2d998dd,a82576d1,6933b580,40dcec80,1f12ef10,34ad73d2,de3ee13,7d632abc,e168ae1b,7f288808,efdba59e,cea51299,d65a2c92,76ee7190,3f253384,30ff297), -S(2a9361bf,67b9e8c5,6e8d7b99,ad8b63e9,e10dd96c,1ee1eb35,40244415,270d9ad6,62bd2398,8d35c3a4,dfa31c56,57d099af,e9accd49,cfda6689,a997c862,5e05424c), -S(88ffd75b,7c3e1311,79f885e8,9060a662,460499a5,b2a457cc,47443183,a3015e34,a5a174cb,7b9b9c68,3cfac8cd,4325e0af,90f61241,28a83e23,ce1344c2,532e3a98), -S(2b9baa0c,d7f27a8b,4ada59a2,cd23c80d,94e8ef7e,3bb77d5b,a45b0547,c70abbd5,657251c8,2d564df8,a9fbc5f9,74c7d388,22089c1d,c338805a,33258c8b,db692bbe), -S(1fe51134,d37136d8,f473c5e8,7d316a8a,f0c63155,815e3b6,489f7dd1,91b229fa,f0df503,ee85d7e,b3c03545,dc491cf5,39ef8a3b,68e816c,bf94d126,adfbb343), -S(1a3211b9,9d946e96,bf190bc3,3fa2fcd1,f8cc0646,45599f81,dc7f33d4,3623c41c,ca6892b8,f8452e2f,5a78a463,fb325dcb,913cb17d,1a43ca78,bf2729f9,27a99ca2), -S(a6d7f275,c3600aaa,ae16a1e5,164084a9,6f8313c9,a71961f0,3b6e1a28,e0326e90,528756c8,ae9f109c,3a803d2f,d78dd27a,a66639f2,6b1e2fb,82a683f2,9e2d7993), -S(4acb6c7e,745afc4c,8258f92e,3a706049,a8c4cd51,6462b230,1a824114,e25c4352,3894a647,436c904c,6ef52e8b,6df86e61,4300894c,e0e7f87f,529e96e8,6f20796f), -S(245fd53c,7b9b6698,89ba6bbb,2b6d5603,c423d4c5,76c68a6,9289c1d8,54bbba73,e6a65161,8e8fe90b,36705e0e,82c1728f,49277a2b,6feedd45,d431f349,c759682d), -S(58e89f91,3383bead,5ba5ad57,bcb85f1a,44ef0f2a,4cec383a,7bc4fd92,9d78fae3,56edff42,42716182,9ad3b3c6,339299f2,1b56085d,a051e990,3ed02323,d9ff64b7), -S(e2f35afe,b9e38b16,a29a8452,a17abf93,36a82282,9fd2a726,efc2160e,10e7999e,3a19d922,d2d2b57d,927ae73f,80c7e1e9,40679fd3,fe34b4be,c4c2deea,13d94979), -S(558be465,de2edf0a,d5b7294a,69703376,7a96a366,e7f789af,3b93743f,372f5e1a,9dfd35c1,d1670bf2,e8696fac,9405330,62a90b4d,b4891986,9c8f98f3,6c586880), -S(b49f1db4,206a93ab,9ae73164,6f5364f,7b261d88,3d025764,b2bcbb90,6fecef01,7c81be22,2a77c149,14e48d26,bc81bc9c,2e10886f,2dec7f4c,1e7c42cf,d87c5f12), -S(6cebe305,dbf61912,36e37c34,31029ce7,b0059546,d5984f3f,c6d3b7b8,804d2cad,5e88f74,fb307758,6c7b9c08,ec2697ca,1360bc21,f453688d,edc82cf5,c96f16e8), -S(4e60a6c3,684a0435,99435fd7,7ce52576,aaca0b9a,e2e5ed78,b4f64044,ae89f6f1,668aef77,3c0fd526,e9b7f22d,55baba05,99ead770,442a23d7,fa0bf8e7,75385b2a), -S(d184099,4640c319,9a00608,aa1d3aa5,9527ef7f,46a08f26,3b83fc46,a10c0941,f7f89233,55989992,7b844a71,1f5c866e,3f4c981f,4cf6f190,fcd4846d,1d83d63b), -S(958627b7,214a7133,55521887,fdff08d4,64c66531,3fffa310,c53e74b,89194aeb,93ec45a8,e0aebea8,378b1c30,974bdcd1,4e7b8983,c8138c7a,cc85fe02,6884a91d), -S(7d0932b,5d8cf465,ae6917d7,450e9b59,da57cefe,dfe6665a,4338cdce,71cc6c11,85c5b8fd,757613c8,8ec6b250,3e15c412,4ef2ce44,91b7eaa6,5d512740,4dfaa142), -S(c8ef9918,55874f19,efdd5720,cfd9e164,ae2b1f14,ee745c4,1ec5cc0a,d776cca3,c0b00173,20111e2b,85faf602,cd01a186,8fdf633a,1b0f3017,682e5d65,3ba29671), -S(8a72c61b,eeeebc65,6cd8acd,8449ebe3,6f21dc8,1ba913c7,742247cc,c8c94bf2,98e7b573,2c18d201,c0faa26f,734d25c9,23411751,b03088ad,1ce102e4,5de36e64), -S(cf0c29b2,ce132664,c7bfc440,9d1188c5,33c8f5c5,643291e8,67a2fde1,6c5fa23f,fb317c50,1b3b354b,18a120e9,2a639dd5,629b2125,ebb8785e,2626ff4b,4f538e02), -S(8c9dc0ee,20f7cd08,e9d1db3b,a4569a43,98c3845f,7d02db0a,cf6f7863,111fb016,445b117b,c7b1a779,e0e9fea9,fcc31141,8aee8428,cc8e8e06,fcd265f2,2424cfcf), -S(650c7470,6f2a4225,eee93622,69d261ae,e18117dd,ae23680d,15c77d70,15f373df,6a4fbe02,e1701051,99828d13,84083d60,5555e2c,56e7799c,b2714216,b77f6591), -S(b0b31e86,19d20877,1235a402,94a884b8,1c83bb44,8db973a7,3783267c,8494b32b,8c5dd1fe,31e86a2,c40c1490,179452da,74fd5350,1ae38c1,1e1fff3e,a33f8cef), -S(a156abe8,279dd440,2762a28e,836050d6,7b782022,2036172f,a1a95984,49c15a96,b85356b6,c165788e,3c02549a,1ea50dfe,c557d7ce,4a9052b2,41deec12,eb08ce50), -S(c2919cf9,924df70c,f1f74e42,6f1fe48,1e4aee25,fa00291a,676f924,69002fa2,19067bc8,50deae06,1ca42c6a,3e252abb,d2c7c6cc,f89c3cfc,a6e7f1c3,a6fe1b90), -S(1aa1c198,d4f76755,ea94d005,b300ad47,238fe1fe,87cc1244,8f2a632d,4c922ecc,85e4e4fe,847c1935,f14d155d,a41ee4c3,f146a4f9,d28211a0,374ad6b3,c350dae9), -S(f1e9af6e,45296823,eb5a1d8d,a41c7904,3b8c1166,30213fcb,84e2418a,e161bba4,211963da,8aeed276,f390d6d3,6b958b36,da23f1c,8705461a,312a7687,bcb9f03), -S(47b98d04,1d7e118b,765fb3bf,5d30f5f1,6ffc7b4b,4745c02f,6bb807ea,e15aa092,d1997492,7099df01,f1d64610,700b9439,83970fb5,d7123922,39d790a2,a116d223), -S(2220fd83,794eb1d3,a1f842dd,9f8f849d,43d58385,25d30d79,9b4684b1,4c5406a,74f2715f,a6b77509,d58892fc,78915244,66b2db2,df099a7c,f7eb9e0c,c4d8d3c3), -S(be01ac86,5eef8b4f,e28e15a8,63c22adb,4607c574,c26d7d81,a5b69ab7,265f7bff,675f334,bb9ba742,445aa758,c142798c,bee1cd39,ebb01b65,eb4ca49c,8911da0a), -S(1e35165,2411e2b1,d491972f,61a42c7d,62c12f0e,25441aac,e4770c9f,254ab47a,ce7b801b,910e9fae,c9288272,18557cf4,73b0b8ff,4296ed2d,6e5cae60,f48fe3), -S(1585747c,d984fb1b,b34e0ed5,9c3c6347,159309c9,1524d316,f570d257,b7c3feda,9b501cda,20fc0f1e,a7df5176,bb6da6c4,585baacf,a08fae17,9d52ced9,c1991b55), -S(33fe24f5,4f24ebfa,152a2e59,c2445f19,f1b4bb7c,636a0e64,eea338a6,5f17e9cd,b65667f,f14ae54c,2c272efd,eb2eb1d7,2f9ff4ac,35430488,30283f2,cdbefc29), -S(783538ba,9f685c0c,f85376e7,dadabaee,527eb0b8,73a04007,9d0a8dae,80fc693f,16e846fc,bdb1fd08,4e7d2521,327457b5,93f42350,80b791fc,e91af5ac,8d35bab5), -S(ac1d5e99,bf673475,9c1118fe,44f0a7aa,1989be05,e117d2b0,d9946510,f932eb38,7a81d87f,aba5a37,9dd319e,793c2a23,e079c7e6,6dc272cb,5d787cb8,2ffdd6fe), -S(f65dc8ab,c670e7f8,753246c8,e5273670,d12a4ef7,a3296de7,3bbeb72b,20093771,6a4cf92a,7243fe41,9c6ded92,d51dc607,7c82ed58,60b98aa6,51614266,f9a2b8b1), -S(bb076bae,e9d21b2f,fa004ce5,e361f8cc,773b2d50,cdeb92bc,5ecca796,f10689a1,121a0fda,f6192c07,b2a734de,9d8b8bf4,609d2722,8b0818e0,a488f83,176303ee), -S(4eef5fb,85174419,7659a95a,dbb4d472,d418a8e1,db93ca1d,af6ba2f6,49ee31c7,91c54af5,7b5fa5ce,8e7c3ecc,f90b2e28,33a969e,e3f5bd30,4808e89,f25dbbed), -S(e3473056,711af387,2bb63d59,c92817fc,16c97b7e,33c1173a,df11633e,2984ce45,816407c5,3d1debd3,ade1d781,d46f8b03,2aa5bc05,e3c1bcee,5213fd50,c39b6d17), -S(f2356e97,555be224,cac10a3a,c6061ffb,8a67a77e,1d97f011,f86e7594,2ba2665c,8f5dbff4,a6ad3bba,ca27c595,e2d1eb67,e0f752da,817f2e1,5e27b9f2,d6b955e), -S(1c1682e8,1a4c6d19,dd01945a,34f096cc,1854dfa7,fe42af9a,b523f7fe,cc20b8d2,a610ef90,190b3390,97de87df,10d01c94,4a76610,6d8c7736,87d2b863,621ee297), -S(53b1dc92,d540faa9,c67410a0,901871ee,eb96beb,6809aa96,545b02af,e2cff0da,2132487a,616b4084,c2dddd4b,fba075b7,66607859,4d328d39,55c16060,249b1f23), -S(36623f66,417edc01,c4a43dfc,e97573b3,f14cd858,a6fbb2e2,54ff1df8,21dbde93,88cdd6c0,b3872cf5,9921d376,9eca93f3,d5985f2b,ce62d132,18de4cb7,f6ebc27f), -S(195345f,132c5c5,4f6e1bb8,52f1f76a,a7ca147c,e347b5ac,fada9fc2,f90d3592,2fb7f1d0,23f0fd8e,9ae691aa,3eff2832,4e6b4390,e42d7129,246f14a2,902797e4), -S(ef5badac,2143e60b,adab5ccc,a05f222d,426e0768,44e6edfa,4eba747c,8ccdc909,afdbceb1,62ee5237,f55ba6,71395f2f,e4429a2d,6d0c007a,30caf51,a53b29bf), -S(3c3dbd83,bc2088fa,65a9cc99,95ae0fcd,8a065e1e,9b8bfd2f,7c3a76e9,72305688,336470b4,54fad342,fc51cc10,6a88d82f,6a8ee961,46aeae6e,19e9086e,79325072), -S(1da4f2e4,af97ce25,1fb180e2,c529fe17,c30b318b,53c3b252,53d8feab,21b0a0d0,861cf8ca,7dced920,1e59735d,11d39947,fba5dd1f,dd507a99,a882ba26,6e468ff4), -S(d5bc320c,8618b30f,a9305bad,b6b1ce9a,f5fd055e,843891a0,b0d2fdc1,5fc51f54,cc8ce071,7cda58db,25628843,780d083,625d103c,daddba16,ba751ac4,5e3f281), -S(f5b3f6d2,9939f586,2943067e,361a7333,ef49ca55,70df45ee,e716ac43,cdcc4e16,7e522add,4cf6d92a,8b77292c,b522dcd2,1a456120,4b0abb2b,614351ac,ca1fe517), -S(e27f83a0,f2b76455,1e24d358,d39b946d,63dea7e8,5cee08cd,13762d43,a3b05654,fc5375a,cbc0c518,bf3fc169,3170f204,67ddde21,7db88535,74b6bd8f,4c677f16), -S(196b36ea,4d552f6c,eaa9f749,fb5ea209,92cbce07,f1cea121,9318acbc,7c87ba82,17eed0d5,1f7500af,3f11217b,b703a51a,bde3772d,d4bbbbf,1438af15,334c61c2), -S(cac69e96,84328713,e06a135a,ce0f0fdc,1812eafe,fa499993,980d2895,5804a635,f02fa499,9a54c238,4bef1f2b,89795b76,3d3e526f,aa1081f0,189b4488,1d5828b5), -S(1e1f25b3,d43317e0,623f07f8,3fb09946,6ecf2381,ab348284,8670a30c,2ac734aa,c096a239,3dd1ca24,12eb4637,1d6c3200,a5992f17,3e6203a2,4313f000,62076e8a), -S(77c7da51,12a668c1,666b3c79,966a9299,a033ec4b,976e1fdc,15d62ae,96021cff,6f3f728,9eb1ff33,e80a7c09,134cd880,9860f9d,8805c8de,e194f868,4852abbe), -S(8aa11355,a8c1444c,c1d2cd12,d613e6f,1145e417,d11d9e4f,d13442be,d7e23aec,52533b3b,1024e982,725f77e2,50e785a4,97e253a4,f816eca9,2ff20ffd,7dd733d7), -S(3f504f0b,647cbb41,74adbcdf,2d226689,5871107c,68e12cc9,dc30058,4302b841,22a53436,688d17ff,feac444a,b5ccc64a,f82b802,da8beee2,db623b1e,fcaead50), -S(3f02019c,4692ac29,5fed5e1e,5190269f,92a689c8,adaa9e24,2a1ae01b,d23fd952,704f03b1,c7c03308,70a6dd6f,60fe12a5,cd711511,41ed831d,b6e5194b,e3de6026), -S(d33fd654,d7164cb3,a1a40172,28559c54,25630cbe,e34c6c01,8a8757d9,6eae7980,fbe58168,87bf57ea,b89bd0ca,3effb305,7b8d5369,dd4f90cc,279bb613,49d2faf0), -S(fa3439f4,bb63e36b,48056dec,109e7ec8,51944d8e,d7ac278d,23e21415,7902725a,b427d74b,88806fdd,fbda126b,38ca725b,fa61c855,5118fee3,d4e1f586,e888feb7), -S(f5c58687,a83c7896,3c021e40,e25fb197,82d422ba,7df59a1a,4f56bf83,49b19e2f,6b94698f,3f286993,ad8bf70f,5ab72ab,12059f8f,bc4f7c09,e624854c,3b76624a), -S(18e582ca,88939bf7,16ec8462,91d1ac36,a39319ba,546ba6e3,b224d6e7,3b0b30ae,6d091b7c,69143704,eab7ed7e,deba296c,26688d08,7d36d70c,8540c23f,ba98b8cf), -S(a2ded3a8,b327cef6,84785264,5b9ac68f,8e43f035,fcf00da0,da97e6bc,6d36db68,31b2764,36139115,1852a944,179c86d0,955faa17,da85281f,af02b71d,ea120dfc), -S(da61911,1341a038,fc286fa6,704307a6,11cb4c2f,9f6bb51c,da89901d,cb1e0f2e,30cdc05d,69e3434c,4cf06c35,f852b6cb,e0edc7d0,a9ee2daf,d793d2f2,b2d522ad), -S(9fa4c9d5,103b0cff,2cf01cc0,65c7afcd,b02a0a9,72da4418,63cc30fb,572f2008,401b410e,397b98f7,5948ff7f,babf6c33,9b1e88ac,77455bd,9045e7f,a5489e74), -S(952c5289,fe18f7b0,40f8ab3,17bdb63,fcb610c1,a6b3a4ae,4a98c1b3,2f1af628,66fcb4fd,2d347e9,fe40e378,d3bec17f,94bfeca9,faa84789,98f24294,d3fd905f), -S(5372941d,bedf216d,2d79656d,db0afa6c,8fcff27d,7464cc2b,a53a6bef,ac01f020,79bc84c2,33f106e8,96a1130e,a841b690,ed5e6b7b,f1e1c8aa,d833fa56,5fd4678c), -S(a4d5e6a9,b72da410,ec56d24,c01ae684,fd8e029e,713f9a1e,22c660d3,30bccf99,f08fde87,df365268,226f68a4,52acdf64,23f31856,9435740,9fa06d4,564cdff8), -S(e6dad981,9b3cba07,1465007d,4b4b5343,9d548033,4896c86c,bbede7d,54c0ab97,9e43f1bd,949e54e1,57a4adde,61217640,f798775f,193cef6a,db369c88,3e784d6e), -S(dc666af6,71aa7218,bac55351,ee12b736,8a29a026,19ec4f94,b9de8b80,eb3232a,3786e989,c684d01f,a4b5ff5c,3b0619a2,d39b6543,4ff0dfcf,24b59966,9d7dc874), -S(2e730ff0,401bb59,6dbbf02b,d9fd4d3f,eb3f6f3f,51a2ba53,d77ca83f,a2acd02a,9c508012,5904059f,bffee85b,8fce1438,fd761f52,86f1d798,512c47a2,d96ffce9), -S(9824c6d3,9ae02d8d,3b59290f,99c1d183,1d5bf401,15d6834d,799c0827,853d0090,2062d562,bca410cc,3b5fd22e,497d8078,6bd1a94e,d7734a66,a5a3495,77c406f9), -S(b10e2769,8f6a9e66,65b330e5,4b52093d,caa4f57a,19cc314d,eeb2452e,60f05cff,a9729153,e267d4a0,5859a9ff,3ab88628,47f3c117,d6ae757e,a19246b5,448a20a2), -S(d8817793,68ca0437,c780b0dc,51db1f46,ba5ec6a7,566b3579,e157a421,eaa04c4e,94da7eef,255630a1,820abe8b,7d8bce00,dbe5c467,89a53be7,2698c4ae,925d1576), -S(5151b8af,bd8b69c6,e42db2e1,5876fe3c,2da5c340,e17b52bb,93170bb3,5351bc95,122d0316,55d770a2,4b493484,8fc1777,de9a0f1,a5d9ada7,df678e09,591c30c9), -S(6cd1c141,67feba0e,406e12a,2bd012b1,7dbfd03e,9bacc6c0,6fd6455c,76cc0c5c,131f4150,f7ead6e6,35e93fb2,e672cd73,7f8093a6,c27cdad4,ea4e7c75,5c2ed702), -S(e83f8bfa,b679258f,67bdaa95,5cde03e9,bfe4126,a0eb89e5,abfb072c,cf536043,a9fd9d4e,e5eb9d90,5d8a3665,73d423f5,deb868b1,7433af16,28fda09a,406dea8e), -S(afe4206c,ec19b5a0,77683c63,a4164360,54be1122,db0c0bf6,6e564087,c6ea2670,15db0d5f,75b53b77,52af9b90,288dd9a5,a26f556b,37adadad,adaf558c,587b9e5a), -S(73428153,102d29e6,6f006910,5116c7cc,ca8b93dd,fe1c257e,9e5003df,ff139d47,7fc6eba1,465f201,3d234be,a022ca08,7b981add,a5ebcbb,8704bd26,750303b), -S(424143db,9fefd615,c6a97e1e,c59c3338,f7f4be7a,def4133d,747b7677,b0227e85,f7dce798,10cbb1be,3e1a91f4,9d490b63,aa740517,3a84d96,b37867b,635f68bf), -S(1d2bcb78,17bb2cca,b5c7e058,be33a598,122758cd,92075f20,24a7bd83,7f8dcd80,363fadf,e771b3bc,46aa7a6,cba5191,3b4d04bd,e673615d,8550822d,d351319e), -S(5cfdd130,bb671192,e4edeb41,96008cf7,4ac47279,ea94487,5962bdfe,bb1f4326,9a6cb3e2,925e75b6,264eaaf6,4f56fdd8,c0f4c5d,65cafcec,5d9cb110,5900cc24), -S(52495f7e,1853e084,272d6b77,72dd19f1,4f874952,ea08afa6,6ac16764,9664904d,2bdb6597,99a1822d,9801701c,98646cb,37a1f6f4,cd503720,79c23c4e,872e3d4f), -S(d82e59b1,18786ae4,a6b227df,3f231216,f33d2e1d,b0adf12e,a515c9ce,83ee1bfd,772bb140,7f180791,25d23c04,558cfa84,9f0b716a,c0863361,819623ce,7af2e437), -S(f6dbc260,90822790,e71f8657,22df2bb5,71eb625d,ccc23d3,c61fcba1,b9b96776,c23aa922,ea7ac2fb,c88a860,cfc3d7d6,a8c4f599,59c1c3c8,aadc88e5,aca1a54e), -S(aa7b6845,88c07567,a634b1f8,2425a085,6956955d,e532e905,d6017ca,5ebfdc1e,6ce07cde,1c60de7a,ee80355a,258dae5d,25960af9,be9edd3e,dc234e57,7fba0eab), -S(68065f44,466294b3,ad7e6225,24de08ec,b910693,308f8d73,847827b4,b4318656,c6e68f0f,2e9859f1,a2d9aace,ff9b4c52,4329b8d6,12233991,900d3e23,59804555), -S(c3d14307,5a223701,4ab61635,db180a64,162901b0,cf175010,d55129ac,168b76eb,5bdeba38,2f747cb3,50844858,b161fd5e,3aa8e7d6,873cdcc0,1702d527,9c691172), -S(3a1b6c2b,145a2f30,88e3cd41,6d2a0b8f,60cf8d2b,b3960c40,9637e5d8,a316f514,d724b2e4,c1c2aa15,9b85c32,684fa380,8af93d3b,c6a9d647,bce39a85,2f568fd2), -S(d2520145,c4d27a54,ed6de50b,30fead1c,ec602c4f,a74e3ef6,31f6b88,23e68bef,7cca310f,d966d423,b7285d7d,f4d5a3fd,fb4ad29e,94e69eb6,2a60a9b4,c666be46), -S(d01ff7ec,b4d574f1,56755c8c,fd615a99,83018ab2,35826574,d94cce5a,f78ad3c2,d9d17ed,ea436ffe,fb2f97d3,58485109,3dc64f0f,5bf540ee,c98ceb0a,9cd4743e), -S(5456f76c,a9c7b5c6,42cfcaa,aa0a2dcd,883ecf8a,626786b4,4735e700,fca5111c,6b3e05a8,6ffa85d9,8b9e4eb0,72ff60a0,df87c298,c2da5a31,d2af1c8b,54b91381), -S(14542249,652e33a5,6283676b,223c3055,56196b3e,21e48607,2652f7d8,ce598e9,64e9dc13,6b8020e,d590ff06,8702f99f,91c42596,b7091969,e34f2f5,2e0cb5de), -S(26d85587,4888c76a,96a6dae2,26a6f985,6fb5b9fd,b4ded1f5,a8f843c6,7346f307,d1c71339,d7be6c76,f1a8b0c4,f047ec71,519bcb05,a25ce054,afcfda6e,19971cae), -S(7f8e7eca,e0257e79,ab2c04b6,dc045ca,363c307a,4b04ba70,c5c6272e,23acf215,fe96da11,f16d1171,9f91a666,23cc326c,57d3d453,8639377d,c6b79b63,56ff6ef), -S(4ff72771,ccd75c6,2ac827b4,e800e580,e6e4681,208d64d1,11c93258,2d188154,94e87e31,b2907d44,ee02e947,65ee5da6,f2bfd7b2,9808bfdf,dbd2825d,1b3d6c77), -S(afd475d0,8946f556,81284fd3,fbbf67fe,6989497a,481543c9,1d4f4254,75aa8d94,669a72c9,a8d0918b,a1e787a7,5b505f26,d002b417,f156d888,5ac02ff,bd29a920), -S(f5c11fa1,2912b0ca,e4d680ed,55ea126b,3c260a2e,b8fb10ef,ca21ad7e,65591590,7406281a,a8744da6,eddeeaa9,274c0591,fac0dd0b,3d7c3df7,e0f65c7f,a712680c), -S(ec9b680d,bdfb2a2b,fbd04bf7,cdbe820b,7975563f,6f0f6646,72236c66,17aed40a,851c69e1,99b77fe5,f16c4c2c,4bea6771,1a23afc1,569a8bf3,c91e4133,a8324e53), -S(1f73cd5b,34444b1f,d7287750,c213d5d0,17a8fb49,da9cc3f5,9ee30939,dedf9c0a,792fa236,514d0a6b,218b312c,c5b614dd,cf0a2960,ca13660e,f696d80a,b7faee90), -S(7b0013d7,a6c967ef,e1006cc4,3fb177e7,81cd4021,223ba083,50db6ad9,1e949e06,a2f8fa6d,b6416da5,d0b68bb1,c1ddb47e,8081a063,1422c72d,2bcd7b46,d2576a60), -S(14ee47f5,539c7a7d,acad832,1197c83,7daac6b8,6ba7a828,84cbf45c,ca70391e,7902e477,28ed6a07,80fdc510,c792103c,e4bc215e,390c3894,1a3fe0f9,582f62c), -S(fd75aac4,8e5cf9cd,9e14e7e4,6e980ccc,1a3948f7,41e0ba93,25f6d490,1d15d9dc,b544f9c9,febd77a0,89980585,9ce52db8,e1847db9,dd4a7857,6a8a9210,fb61d2be), -S(93aa7a40,c03e4e7,d605b8b0,3ac2a378,122fee87,9395aafb,4698d35d,8f7f4690,db2859ba,b6d5c89e,2fc4b68,1488ea1d,8d8905f4,a44af57d,3ef9f937,4872013a), -S(20a027b8,79a10933,519a97b1,72d77389,5b8722c4,ddc4603e,40319107,1ed4cbad,4fc480e9,fb55854a,f12077cc,dce038f9,3ec1f3ec,6a37d7fc,ec03b204,8cf9deae), -S(e0e26a0,862f4ca,96084cd9,bacbf501,31da0f20,1f3e4a21,f41f5ff4,853a41ea,e78c00f7,3dc8200,cc43d04f,6105e189,387fb1f1,47f39d71,f562d7b1,19c0f591), -S(fe7f03f7,b6633a8c,e514e801,bd9b3b6b,c4bd7790,69915720,8d49b513,8d5c6be4,74db79fc,180cfda0,c17ab6a7,74d73d28,3c9119b6,d85f3a97,d32389b0,102c052), -S(92b2bff4,c74df07,3cc3a258,fd4fc56,88f1eeda,1908036d,c0606994,92e3fb6e,f92ac36e,f10ac585,3e64a67,5e8e26d,b3cbaa8c,1670ff,ba060f19,bbf04fff), -S(fbfdc0c,41238a0b,ea6e3c4a,b09453c,2afb281a,4cfb5cf7,97f3f473,b02717cc,bce0f212,9d3407fb,c5541dfa,7d266788,72343f8d,748b7b3c,8c0cabd0,78378f85), -S(8dbba484,d9bd416a,f1e18a30,6f42c73a,cc15c5e8,49049c98,612a9d64,f8c99539,670200f4,96e34f9b,50601a49,32200d7,1d79e69,b7889f8d,ca45b13a,cd9cc7e3), -S(44193861,6c2332c3,1d35f82a,b35b515a,1cb3d754,3f83f5c8,63f809f,739448fe,ea559711,904549f4,b2986865,86467205,58420d27,46efa1c3,2ba002a2,64e84219), -S(acbc7bab,6acc8d2d,abf39739,fe9a560,d225d692,9a1f2e93,3a441173,5b766e64,e9f2c663,4104067f,5707f9c4,6a9a7d6,312bf3f5,6a851e0,d52057d,6bc296bd), -S(e3300502,a870f610,5d7b3c68,f26d4ae,bae2b4f1,2a893d74,768a6b8a,c66573af,558f537a,8838b676,121a9d0c,c62d862a,4224348c,1a982c37,6be1a255,a57caae8), -S(fc34afa3,8d658fc4,8d420c47,651057b1,3eec6863,2d3c3a22,bd83580e,3a6f8b82,96a3436d,228bb25a,fc274c5d,7f5da6e6,fcab6b6b,72ee98d3,fc293ef2,ed523154), -S(5e1cddfb,a73e3534,c0409da7,af922c43,7f9dc2fd,6f573ee6,918de501,90e448e,4b1adfe8,406274fd,6c1a3ec0,68568d0c,78132b3d,efe3a9f4,fb23a725,a4f89251), -S(d307c67b,cbcca4dc,89c680ef,9bfb7421,d2283fcf,90a07bfb,95c50cdc,f36deba6,254f92ef,5734f448,24ac8020,89f84bf2,b7e8967a,8afbc2f0,e01bea62,b4a90b73), -S(f4977bc0,e8f81cf,753a2b58,65b512c0,6916b53b,1a0116fc,a5528e2d,aba2f2c0,49fc2c15,8cf226a8,5099bc97,97b2eba9,9516ab90,1e39d462,3adb96f,c44e6c99), -S(e70cf22a,9099028d,96239342,bc94619,e266a53e,6df63d23,fb317879,cc547382,9ee3689e,f7eba3e0,f8715242,5ca1bcbf,fac4d337,ac4afb59,107788d8,6f0f61a7), -S(130fd05c,ea863c62,15aa8789,2d5e293d,3493ad4d,5f526a06,b33c4675,e02393b8,75c9776b,feafd1ea,252aea1e,5f8c8,9224ae3f,39c5ab98,98395468,6f45cb68)}, -{S(1b8462eb,1ccdf7b2,b8372f2f,cec1f479,ab07c09f,cb26d6c3,965ec73,4d654f81,62f6755,b4a7891d,55de6427,fbc37d33,e4eea418,a2c04392,a3d11807,ccc9025), -S(deb66785,6c4683c6,ad7c39e5,deb1b8d9,722ecffb,f431fa34,9dceab3f,698f738e,bae7261c,368ee55b,137b913b,8bfbbd07,de4600fd,7a071287,47c31531,924942f4), -S(75ae3c34,5cc1bc11,46c5f13f,a1144759,d39c4d20,4a8f2f0e,bf3c313f,707d49aa,82a5a9b2,2743788,938a0b76,eeba99dd,f85eb5bd,f7ab8eb5,5f6e5334,a00438de), -S(49bd4e57,c59dc8c,c4cfb0fd,83c5944c,3591eab8,1ae90f87,a8d30725,1904fcf8,66e76d62,610cae77,38976214,20955dd7,95e47715,3bde0ae7,491927df,bf2b1c75), -S(5f3c96aa,a71c774b,754f616c,5eaca0ce,f9d82264,7dfc7c2,ce38ac7c,d7429748,8c72e7a2,b7371046,94ce5e77,521ad47e,2fe5cfd3,10cbcec2,febdd977,9872ace8), -S(43d8f72d,fecd31ae,91eaea66,a7b96a25,2c05c3dd,8d7afd20,d64644c6,cad460fb,d6a28b23,50f5a7c4,cc8233c6,85c87875,9134923,55cd3532,f888fb79,10342509), -S(cae9a205,19cb6e40,ed8c6774,7e7c52fb,5c57f1e1,56ac6f32,9f1538ef,6971e888,959e5c41,344ff293,3387c680,54c03756,1f3b6a97,a75a3119,da25debe,7acbe4c6), -S(5f96d7c7,a8409a4c,d4afd355,1139ee0d,ae63bf99,2580cffe,fd5f7497,2bed3d26,972b40e2,83dce233,190e8961,310d854c,db5d4805,e045b4ea,29414909,592b589), -S(2ed0f7d5,a0281d46,61159e80,3cd6bcd,61b1a37e,16aa6801,bbfe526b,9978bb8a,8a6d62e1,2376a282,e62b21df,238ffbad,a055c342,db073e86,1107ac9f,2f2149e0), -S(167b0b4b,c6a4c17d,9f3a2813,87bb277d,fa30bf1b,f35db9f4,b521cc53,dd479a18,32d48b8c,535a49e0,4c412b05,7e000117,271dbe4,5b7bcaa4,87a857f,b723fb31), -S(358af81a,b1352729,f824fe1b,40eab58b,23298fed,82dcbeec,1ec3ba91,21438fb2,b5bada2b,3906f17a,5f882cb0,460252d9,b11c221c,1d316d79,c21dfa73,174c9cbe), -S(ce544020,abc6a8f5,4d911c49,4d0fe111,bba24b6d,7b5f43c2,7f307c1e,1c2a36ea,2d34bffb,416ce2fa,21db1ce3,b6a97aba,29d7a45,29081849,45df56b9,ebe8351a), -S(6057a2d0,11320781,132b5de2,48ad5fc0,d0b69de4,2587220f,2de808da,e61906d9,df0510ae,96a02157,bccc84db,32204888,277d22e4,76160682,65171c77,4766ab23), -S(4eae969d,c9ca79fe,8f61dfa0,e6f3525b,12a3602d,feda122e,1109e0dd,43ae07c2,7763de53,9abc7599,75f289ec,92866fcc,486b1b47,40ea9761,60aa37f8,f7fc142f), -S(a698bc22,7cbd5730,452aa9af,2cfb600f,425d27ed,716cbe96,603d3280,df046c52,c91312c0,7492188e,bf054f37,e20b68b8,9e135946,7180a505,389da7df,7d45326a), -S(52fdf09,1413d6d3,1f64df21,17d35360,16323b0c,e93c66d,257157e6,2e2f8197,d00868d1,b08ac819,9c4e0215,a0beeab,76a543c2,6e3bd1d1,67709cf7,ce2fa4b8), -S(c19e6f2f,98a0f54f,4f61eaab,7b4477b0,ddbe2577,7e82e836,d8b71e97,9782461b,65855134,75c8676b,210c29d3,89d30beb,dfcfb798,6841fae4,56e7b800,e2193d15), -S(7cf919ab,a90c3572,bd41f673,b63d761f,60f28dca,8b3846bb,dfb13545,1ba52fd2,d474c2b7,d6e83e20,12866c01,21f17fe8,e6b36237,45d162e8,4003f04b,808f82d0), -S(455e9205,4d052a0c,9e0a86ba,83ed7fdb,b2b0c06c,eb05b995,13f6ac0e,75f149fb,12b026df,332040e5,8e2f92ea,be60e016,cc8941e5,d7972217,dba58548,f1079657), -S(e066bfb0,1239eaf6,7599d76d,befab533,9542c16f,6b150dff,c96a0eb2,bb0b1622,a8f1743b,b307f660,6ef6485d,aacd5b36,93354863,1d287b83,11eaf53,77df9ea9), -S(f4844f56,52f6b97,fae41a88,3e433286,a0895daf,4929fa51,8aa5040,da2b79eb,a6c86fa6,5c02cc6d,25b6cd86,473eabb4,95d28ae5,b71061dd,8da877d4,9ada9ecc), -S(111d3003,b086df80,114ca249,993e9a56,43980184,66ddbe4c,adc919b4,d58e60d2,ffada7e9,bf38ffd1,19cb0568,da7c8354,ace0f714,6ba144e7,90b1fe26,5e97f82e), -S(4a556e10,ebe25839,9bc4c3e3,8f4e1c1a,7a1500ce,44c38a1d,94e7b516,18ba3b83,6bd865e0,2d756729,c7560a7e,5422f19b,2f9e5007,f7c31d2f,3ef8cf86,7eb83373), -S(10b0a6b2,dc05613a,c436d0a0,9b082c01,8197ebc4,f106ecae,feb40113,1021a9a,6d6ef39b,33023000,5d68215,aa46ef26,b88d6e9,73b21752,a2bbc055,5c88dd31), -S(a0666545,df775bd2,83a6237d,8b8a7357,7c6bf0f7,5ddae3d6,4e65d3a7,90c69336,e61fd87,f43a927c,a5817c6d,20edc6d6,c69e6667,8765be4c,dd260eee,6a7dd5e4), -S(a593c02b,d899107b,6c71aaac,f7314f36,a594c892,32f5dad6,15601ce2,de916170,52fda077,3ba509f4,a1eea11b,6d11824,83a7c16e,b4227d27,fa844657,cdc21d86), -S(46d914c6,a68981b6,99e46e4c,56a6c482,f9ca55f5,4618cffa,5446e93d,f11495a7,bf913796,9dc92ac3,7d52b941,e6199412,117c49dc,8c05df05,95b7721b,66ed1d30), -S(7882d56f,8e53e827,1d51c0c3,49d2afa6,d632fe6e,344a0e4e,c467ee9d,7399b953,345ace50,4127be13,989c4d7,38f00271,a3ea7d8,720ee6fb,82de9c1e,3873f95e), -S(78c6fc9e,571e02b8,f8bde2f7,9540fef,452fcf4e,2b6e7649,3748f594,aa4d6cb7,e7f5a947,b486be05,ad3b9b02,1834b360,ed8bbc78,6013f58c,dca02885,bc8f36ad), -S(562b2b02,741d8c65,6f457bad,56d7bc25,75ed4ced,46577b52,d8b35deb,e8a7504a,17169453,9746549d,1674a55c,2bea12c2,56074f42,91783f5a,59b92eed,768f4095), -S(81f3c319,ff4e12bf,9b7cadc1,75712278,eb9b9275,87df662e,a72fd92c,7d79232f,eb6ce068,131ac2c1,c31a19ab,9aae0633,ee184235,62065a31,59d978cc,43523b6), -S(8ad3bbb4,dbabc2ea,222d818c,6680c029,b0a11a15,7c175165,69a2729c,c4ba1608,65c3812f,9f645537,fc6cd8a8,94279c10,5eabceb,dcd21eaa,dae4784f,69db467a), -S(19bbdb50,a8ce9bc6,5dfd3006,3508bc23,528b3e3,e0615529,1ec0ff71,6a6b708c,75f8a65d,a25c9020,e1b3e26,929e67dc,9edbe8cb,7ce44e29,a3c2be40,50c3370), -S(8866249d,46d790ae,276930f0,8bfd2047,658cda45,ace08344,5d254413,502369b,41547dc4,2fc37c54,11d65d1c,83df2e5c,31285530,15b51106,155d7549,5e04e711), -S(b18db2b4,15471fbd,38648770,8075b1a,7244af47,5a4099cb,ecfddd0f,18bde801,1a2c7d97,23352c93,373919b,a28bfddc,1af8d2b5,953a7da8,2706027f,e802b77), -S(dcd6a63c,70380948,dff9993e,b163a6b2,54625677,5981c03d,16b7b46c,f0b05bd3,2db2651a,e5adc2ef,f2277b6a,d59fa0e6,d6975fc8,14c0c4c8,192301b4,63fc8969), -S(c66261f0,3bc15a7e,2b7ec26a,9ff9ad3b,ccd7a005,b7f9eb0f,f14dc9ea,64b66a24,975f18c,8eed73e0,c2873945,2fec446e,eeaaf732,c3406add,efbbba5c,8ce72236), -S(1ccedbbb,6705448d,9f5a6271,51bdc2cd,e4f57a4b,ac283514,3de7f244,b3fe2593,d58f089f,588979b,a8dd5e1e,e1f2b1fa,26ed488a,9b7ff553,4d4296ba,c768f3db), -S(fa89b801,ff0cadcf,e45d5e9b,b9d76769,a4a8c293,c4d7dee5,eb3b889,ecacec83,fc82e286,1e786cf5,854d69e8,e3c09ac0,4d584273,27f9691,33cc0087,cf7d3a3), -S(ba9e6bfe,2167dc7c,e2cca3a0,bd90050,6b4c5ed5,a65b6799,38850e1,e983c307,8076fb0e,e4b3bd10,5826a6a4,eaecdc6,198cb674,f62ab20a,dc8495ef,9c69df52), -S(dbffd22c,abad0651,673f6018,a4ec19cb,33e25609,5170c06f,b37aeef6,8a7cf6fa,532a4a76,56c364fc,72e4e3b7,b0bf6fa1,9c7c526f,89cbb49f,8e8ed85e,e85dbb48), -S(470174ee,d0a5ced0,3136015b,581f9e97,bbf2b486,6bc855a4,7f4447ef,c2465628,f6347774,94972ae4,90748fbc,631fa000,5c3c9b2e,60072fd9,fdaade69,ef0f039f), -S(e965ab4c,e7b53fa9,e47a278f,18ec2338,5bc8ac5b,ebd90260,340637c8,31585369,ccd9d755,9b80ff65,ee866c71,44abb0e0,3fa30c1,91bb8593,da54840a,cb2a9d95), -S(f4ed2efb,fbec7f8c,54de593,80958b35,e3e4f3dc,1af445b2,a491b41b,256ecba8,b23b37a,9c4287f1,392eee8d,50d8d406,cab40679,a66e0d40,544aa304,aecb9c2), -S(3d911698,27693d14,3b0d458c,427cd698,eeac19a7,8f64d68e,9cb43c49,5421d915,be75c3e1,fcd657fc,59806fc6,bf1df70d,59e44b4d,6d217c8,417d20ed,f4560432), -S(c4589f51,1ed541c4,c4872619,726e7381,a9566548,4e8f0c16,33cf55a5,61b4f33a,c31f26d2,48c2687c,e119bdcb,1aec287a,2f7e25bb,5b3b1ce5,3af33dd0,9a92508d), -S(b3ac12f6,f45d31,b1d6f44a,7d042406,c04ba3ba,ae68fa43,f8200717,b3fd7c90,d04d1b06,ea0f072c,daef4212,89667b3e,effd1f8c,3b4c4f94,ada534cc,552e6d1f), -S(73ed49b7,9a7ecacf,6dc8ef7e,663111dd,40351718,d3289287,7131f8,53fb3b73,e25b70d1,c9d605ca,571754fd,6b5b0317,c7454773,9f71c39a,9069431c,1c755161), -S(d0cdd56c,984d2f4d,6f5068e9,27801a78,9de020dd,32c70cd6,eefe8dd6,aff910a3,35152fe2,70b7bad4,f0d151cc,6ac69412,5b7dcaa7,c757ac32,3562dd8,45362494), -S(adc7e82f,bf52b914,cb3e3c4f,c1d96ee8,7c1a9b5,3a449587,962aa19b,b03967a0,4883619c,7be39873,9be896b3,b1fd6f9b,c62ca121,198bf71d,85e918e0,7ac115e6), -S(a204d702,1a346020,ab978bd7,78ac1df3,bfffb831,3699c3cb,64a118d4,da7f607b,18a0827,bd9da5f4,35ba7ebb,3c4f198c,3f5c3313,fc6f6e0c,f796e51e,3c2e7d5d), -S(8a6abcb0,2aa24acd,71168ace,c4aa3aea,1485f04b,afffc1f8,7ef9a059,d5996ee0,9979410b,afa6de0d,42852883,e13e84e2,e62db36a,6c2a4967,f8e30a8e,11775e5), -S(144704f7,f1ddfdf3,2e270958,99e0f74d,467b09e1,ef388d1d,954b6817,3cfdc2e2,60e0c043,c4bf6051,e09960ee,d7a156c6,5e66e9d5,c19d8b0b,b8ec9edc,6c3cb3a1), -S(4ba11b29,7cf62910,4d7bf384,d87bd0a3,2315170,61e58d80,600fd7a4,b8e93ef9,fd7b0cc8,5c9de5c2,184fd95b,d04d1d34,4c376f52,e9329f31,98ef2fe6,21fc6ad1), -S(4609bd3a,6d606aad,f372a731,9f88211e,31f8e187,d3d0f7d7,ee418817,13540066,62d5d099,88f99333,e309b519,93c17132,45ff5435,8c29403d,8cec5c58,ef4450d1), -S(66e02b23,5399ad24,6d898a63,6e9f968c,b8abf79a,d976df4d,962219b,ab01997e,80a6f6d2,ee813cd6,bed0685e,d42c926e,d59f3067,59a409d0,3529d474,92acdea0), -S(aa668419,1ce4a14f,450077de,e4588ff4,7565c821,7d7e7628,8a2fabf2,7ac7f1fc,e9c1eaf2,4b00ea7e,34f65672,4db33d21,efadb2d3,7ab90d09,e067a286,a75c200), -S(b4680ca9,f0d4eaf3,36cce2e,aa281eea,c522d87b,ac51995b,6893984b,7351daf4,212a1992,b7af5e9b,3d538c81,193bdd3f,61e24271,fecdec72,f1359bb2,95882590), -S(f682edbe,4cf0c8cd,ca5bbfde,4b1263b1,90a1dd5e,e8ea718d,7f01b892,1f170741,ef891402,e5598b01,295f1e5b,48bc1039,375e920d,550cb552,7bab7160,1ccba576), -S(a40a6aa,b4ac57e9,d3b861e5,2b70d28a,5fa6b9ee,1e1f7776,37397f04,6eacbfdf,12957e43,31a5c6c0,18d0c987,78723fec,e16182ee,480b8cfb,6506ca0f,70603294), -S(53b2aa09,23cf3866,61c0271,7b8302c7,4807fb5f,31641a8,e5c4135f,1e6bf439,d4eed7c9,8b265069,533cbbe5,a6be5182,9d79989a,9df82e71,61c3d45e,f0ff3e06), -S(2644109,54ff1fc9,34ac41a6,5b7cf7f3,d66a0976,999b3a90,bc2c4c0d,de3c4ccb,be2fbecc,c71068c6,4b692e1d,6ecfca5d,14271c40,d6713ca9,323eabde,cc7dc588), -S(2e63233a,4146d344,6ed628f7,a0fd277b,435a9d81,21a2dbdb,43dc38db,69189e91,f0d3d6bc,13ee5049,ff2deee1,a13d1e4,eb8a579b,965a86c4,1a0cad1,8569494b), -S(bf0107ed,190729a4,3e130ff7,5cb99a3c,b13392b8,7fd01e32,ae9ec3e2,a0a93e97,eb2023f5,76a06d93,27cfd3ac,c6ba3d5c,ba3ce673,f84d7666,bd2f3f0a,edb63b9e), -S(c22f151b,c978953a,f3a1fb0a,cd1f7255,b5923e6d,c5aa4c26,53fd2109,3b493171,fd3e46,cf4c66f9,c66c5075,313aa519,538b3df9,f2660554,8b407515,502ae877), -S(b99e5b3e,e44391f4,dc3654a0,86abd389,51c8d8ca,ead1ed8e,ccc1b7e7,5b5a4cf2,74b4fa80,bb4579c8,643299b5,5478ce5e,9566c1d8,98eb10b7,200e8854,6a20eafa), -S(b1734d6a,7d8e19b0,10479c2,49ec6806,9d42ffab,e8265d6,f5fffc06,fc1243fe,bed2333,91c587d3,8710f320,1e74fd1,5816ac9c,2eb70bd2,e182cdf5,986b550b), -S(c6c97574,dae3b2dd,9bd060fa,b0515853,b2043ab0,4e58993e,98aea78a,f5678b19,3127c67f,dcf8cfcc,f4b1ee2b,17abd614,ecda39d2,3baa99b2,53ea3c80,74f9b433), -S(14d32f30,f9268e0d,98452de3,4adadf46,928457cb,423b1d95,a58c9f27,eee95150,ba73964,1ac3088a,2285a4af,c63467f,9efeca29,5ba61418,f6d15a68,1d7b12f3), -S(fb71dc00,dbcacc94,39fc4949,ed18b7be,45cf50dd,8dd68c18,b0855344,fae8395b,789b4500,3add70d0,cffc34e7,5c348033,30965e66,b10e0b7c,eaa21f5b,782ed574), -S(97978bd0,2696dd07,408e4a82,c5e7394e,6379e3d6,314658d6,a37e302d,218c6ea,852fb297,591996a7,f1db1402,5ccbe65,9819dadb,647d28be,5f891bbf,e96d3b57), -S(22d18ae4,56cde12e,451f800,f61edc6c,e05a0fe1,91afbcb0,8dffc101,400ff240,4506e9ae,7b87bc3a,9e9eb106,f3a4bb3b,9adf5144,6389db40,5d6e3e53,22874552), -S(263a0e17,1c1271f5,82ccdb1b,5643b400,94f18e82,e8e2a67a,79ed2cbe,c8d7450c,3cf4ff5c,f9b9a42,74650323,88b5083e,676d0ab,45ab061b,9de8d16e,a5f63e84), -S(1fe94ed9,eb72bdbe,9ab19dd4,abdaf994,7e700451,eae8acd6,ab2a31e1,d97a9ab6,f87b6fcf,e01b375,244b1550,77054488,ed835f5d,3c0d27f1,5f150199,40b3a153), -S(65ab4ff,32bdc4ab,953e8983,11ff56d,2648904c,a6ff30ad,3e013c6,f6b46783,45106115,7e3c8b0f,8d362ab7,2de710b,833cb381,bff4d243,32d6532a,1e76cfd0), -S(eae54dac,dcda8825,45912080,6504fd39,a2237e5b,904c3b62,4c960fb3,ec235cb,790f33b6,6cf0a163,160eec2,4f43c321,31fcbe88,696956bb,8b355eb4,b00093b9), -S(5122f262,72e25078,a9c989a7,cb0bc781,47f0be89,6efc65ab,67369af6,8b1b8f41,612aafd3,a2f791b6,5d62a52a,202c58d2,8979e4d9,a856d589,ec45f514,4b7e80a5), -S(9884b4e6,5bddf06c,c3b0be07,108c4880,f2c9f4d5,58b2781,61e57f29,e257aec5,5d4c8435,c7b7a514,929307a4,ceddaea9,ff551c0d,faa2bcb0,77c68755,4f7b4dd4), -S(4dfcae95,4a4e92a,37dc6d8a,3e503359,4b193f66,6adda287,603499a5,f55f53fc,7aa5ee13,952a1572,bfb85bb1,20e0d2bd,1a3dc28c,b87f01b1,8f817b31,c143d58d), -S(bf8f8ea3,d37eee45,78cfcc3a,6f173097,abc2582,22128787,be7557ce,df4f9a48,8fc5aec7,129e9a05,3c6c4654,4559ba34,f0395264,f01ec35c,1eb11a4c,3fad198a), -S(7d9294a5,f462db4e,5e69ac86,427ab556,818a73c,dbc2133f,f6575f43,312d6c8a,d7bb697e,1498984c,d489469d,f4a4214a,4571406c,35b5e88c,f1d11b48,65fb8b3d), -S(54b0b84,e6ae338b,65d832bf,f820195e,932d4e60,24307c96,a8aa8132,53639c9d,330ee890,4596ceb7,28749302,7c8a0163,cd3a52a5,69d41a75,3c099b50,e92a1289), -S(a3331196,8e97db37,c774e6c1,52d5ff75,8552ce30,80d7b9be,5d34f7fd,1d41726d,644016ad,988a499a,70b31577,dbaa6505,7e50a5ed,1cd4fe0a,db31bb50,c9a7e0a), -S(35e2d742,79bbf8e9,80338f27,fff504d1,640cf5ca,30241d06,d388df5a,5d792652,f88cd405,d779b791,f875ed77,8bc92665,359def46,a903d5fc,8052fed9,9390c0a8), -S(e1d851e9,15812c98,a2d176dc,7443342b,3812052f,c2ae183,c8c3aa0e,662c549d,e225ed92,a1d91ee4,2f191b55,f15c9aca,fc379519,ab0507d2,df2019c2,369ae46b), -S(6e99db31,e3f54cb7,cc6e8640,dfc62b01,471ca8d6,35d788a8,e6d0c79f,8de9efa7,176e8bab,4340883a,8380b53b,1e981376,d7f3535d,41429177,bb3a0187,3cf78d6e), -S(ccb520f3,2c671c00,56cfe1fa,17eab66e,7744b2d7,9b5919b4,47a55ef9,bed0d96b,b8a3016c,fa65d9c8,23671498,46379fe9,2f4e74e9,6487420c,38494701,efd9c809), -S(c5e531d5,49e65f4,254541cc,84bfd39d,2279d7c7,98abefc8,cc2cbc17,2e6ca6,4e1c664b,8bec2ecd,7d56db93,66f6a582,2fc70bb6,70c4d3c1,90b76bd4,9a825995), -S(a132f569,c7cab520,d127fd99,9c06d4e6,4a7fa953,9711e1bd,9eea72f6,78430c7f,a81cbf89,b67534a2,4f5ee9ef,8bf5d134,90f73f78,63b3964a,8a81b5af,e44fe664), -S(59242d2b,9279ac93,4a7c99d7,dba4e033,7ba5b199,29a6fa2c,24766c20,71b3c5b3,8824c16f,71126e9d,6bb56bef,7c5e37c6,760c70db,de4b7dc9,e29afbd0,a8d09b42), -S(a8cb72b3,2435a4b5,5687ed9f,bbdd2860,9e96ddad,dfb7c44,d49f528a,f8ba5f57,e8ea8408,eca95aed,f2a6509f,663956e8,e7ced42d,12900677,c86a4b86,ec0b40e4), -S(58888104,903c52df,fd26b72d,4671642e,c06b2efa,44ebb727,e6ca2d1d,616d12af,387e465c,9559e35a,124d6501,715e295a,3d95668b,35335db8,678e48ab,7fe0ff1d), -S(6cddcea5,a0bb7220,f206cbc3,b6ac999d,47f0d2d,728038fc,3b86fa8,61f4069f,724dc303,13aed0f1,ecee0d8,f696c1ae,d00ccd02,90df311b,8611ae43,3664b31d), -S(283557b9,3698a99d,c64643f3,d302454,841eff33,dc110d24,a00467fa,1d9064cd,715b038e,1147a84,8ad45111,8eeea2d2,66cfdad2,e829932c,fce6872e,a99c2486), -S(3f88dd31,95aa10f8,fba82e6d,9d26cf4f,f2ca855b,75bab7d1,c1305654,ccdc8cd9,99ee6e45,76a0773,a8e0a241,a40b073d,78f98b03,33292f75,650a7eb8,bf55fc88), -S(4f0d20cc,acaa4fdc,972e40d1,90ccfb52,c635c438,353d2fd3,47ea675,ad966fff,ab378bf9,c5560914,e5c423d6,f28ee794,eccd664b,fa78a18e,b8f096e9,c7c68bae), -S(4c4f2110,8d32ad06,d60eccbd,238495e,268d2545,bfc5f17f,cdf7a1ca,37c96639,7edf3b15,346f21ec,b3a271a4,bf70813e,c9a4e4db,169b6f36,1d5d48c3,16d7594b), -S(1ba8777b,218e104e,c0908ea,b9ca48d,9145b8c2,a3a0b6ff,95146883,3077f40e,dd385247,7de05b80,6df645a7,646b1c32,90f78fc9,4eab711b,433c915e,462c52fb), -S(4cda5560,ef56756c,f73fdfbf,3799e8a1,f744f497,bab91815,eddbba86,b404e33e,92e1efd3,eedd500c,f4668d78,f4283cf7,eecd6c6e,979980a2,ac8389c0,779862c6), -S(ffd11b85,884b2330,e21d2077,336fd518,a337a931,15fcf6d5,d843b002,dd225ea2,6ab2c275,4d0e514c,bdbc6e24,f3e2f019,8b73b3ee,d267224a,705e0421,4f449d60), -S(fe4a2c46,15b9b000,d871bc7c,af5e6672,a574a165,e544b8d8,bba978ba,ac80bfca,cd15b01c,1ac4e6b1,25b00112,c04d20fe,3afcd997,541f3955,ad60030e,413cb650), -S(c070d79e,dea4a095,a054e026,1c748411,19b7280f,d5cc922b,c2b092a1,f211257d,f7b93b3a,4fdc7bf6,d90ba7c9,56831153,7948d110,a9cff253,f783f075,6c569e90), -S(7820e29b,8a7615ef,44f0639a,2924958a,4b132f73,9e67d58f,ed93f540,934df025,cbbd3f25,b03c0542,5109d5c7,5a409a18,7c117e73,4ba624,3ae7e085,322df8a2), -S(12b4cc3a,ca603277,32fa5c6d,4ffe02b5,eed489c3,9ea67f67,fac3ad66,a20309c9,9ed214d1,4217b11d,324a1c6b,d6edec3f,6dddbe48,2e238376,d3b74a0c,12de2695), -S(bacc8392,e6770551,38b13942,ce2412cf,6e22f959,9f8bd91b,d4855234,d0972261,91263e47,63785808,6c645df6,9b36a64a,8c6a07ab,fdf28a88,6893cb91,4c5428a0), -S(8bf48d87,419b4741,e461ad8,650f2e5e,c93c1e42,cd75e307,c60e8655,8560d576,c38c0513,88d64e1,cb9f430b,5357ce64,c4aa4379,3494485c,4c23e07,dda82bef), -S(c6217853,f15a6675,aab3b7e5,703ff725,eaf68bf0,60dd45dc,c2c209b5,b6255d22,3b5e1d4a,3b04bc6c,665e4ad1,a3a7587,b53f5fce,6db4aba,bcd01f3a,53b342af), -S(ff04846d,7a1309a2,5bcc043b,3a129275,1c5659da,e1377bff,f0a4f52f,78d57c03,5906a77c,f9c5116e,b2bcfbb2,330f12a0,277b211,7605020b,218af50a,b50a8eb9), -S(9d6031d0,7a4005ca,5badc057,34171110,341aa446,37bd5260,9e3c052c,a7833a3d,c505366e,18f920ee,382b6d0,5c71641a,9164c7a7,685bbdd8,6159d981,6990d5e7), -S(328fc8fb,4cfe884a,d6f8807f,5af7f09b,852cdb4a,8d12d6e9,e0a83e62,ef124cd4,ccb846d5,9e5ebc6a,5f753bcf,91ff3e4e,917afd7b,ef3ec9e0,81c302f7,d0302523), -S(6d15ad00,8a21f27a,50545edf,f6259ffc,50b7b42f,6b66daa8,274ccd4f,9968d758,44cf472a,6a9a5bdb,bebc470d,33936503,2823d19b,62f59c50,880443aa,bac08782), -S(a406569a,df5772a6,e881b5de,48a4240e,680b7e48,6487b3f0,6bc10a62,f930154,5378b0d2,df6a717e,b90a9d48,aa9728bc,5fa45468,c997a990,f51aa988,67bf6d5e), -S(a481763,b51b1851,c99f906e,280e425b,833ed883,14b8f84b,ecf5661a,369d345a,95088d19,330668b6,44bd68cc,a7048e4e,da96fa6a,365c1279,47eca0d6,29fb338e), -S(5600b96a,6e0056a5,12160020,7115b198,8ff3fb06,538d6580,f3ba0b57,a9490fe0,a09d1644,f0d14ad1,73b117ea,cfe1f992,2bec2bb0,a8f92f8e,4588e985,4566f88d), -S(95e9d301,fea78bf6,fdd7210,16c7b890,fdf22b85,54870d4a,520756ec,b8d56414,dc2df8b2,6edf5d4d,faf1291,cf2fa41c,d26090a7,499bf36e,a7c5ffee,bf404236), -S(a154b8fa,adc62ff2,ef26641e,4467cb6f,3506662b,8e452518,1832d6f9,145d00d,2cd50f3c,62a43b4a,9bc0c6d8,72efbcb0,c8407e82,39d69ed,40ad56c9,ae3ca73c), -S(f5f28107,77bc1bb3,10c02f60,88a2252d,ac3c3855,78909551,c4602b84,fbeab69a,c23e586c,731e84c6,5a5a0f19,308fce27,ba3fedbd,3980cad0,389e9ede,c1fe6c6b), -S(64be52da,6082fd6b,9f909950,d8887a73,f614cb5a,8e867fdb,3768a0a4,a958c699,4f6792f6,f65ee798,77ca9ddd,3bd4dbf3,3675f059,6d5cfb85,bbd8070e,6f29031b), -S(26d9c5c4,1803962a,f242b042,2fa73750,12c91a17,b6848ab5,af4e9335,43bc8388,f6703950,633edc7a,482f9651,9b638fb0,337b7bb4,dbe6ad24,6a47294c,7f26896a), -S(c1efc973,50a488e8,467d1fd9,ac679eb2,ba011aea,412d7857,e3d2cc0c,19dd2395,c58649ca,c665691f,2fdfdb68,49ef2ac3,4d0bfdce,3927ff52,7a9e3d41,3d8b57fc), -S(dfcc4a7e,5a0ccc7c,f0f76c4c,fa92f075,791a2b05,92f25384,72256905,c08ad084,de18f9bb,28b017aa,474296e4,8ca2765c,8c4eab13,bb4815f,744694e7,697d1618), -S(a44e0a8f,9591b5ab,a051559b,b64ac3d1,ff8177b3,790103b8,db7e4597,6fa991dc,61c41b5e,30cbc23d,e632808c,76bec591,9ad4f050,251e9355,80d9e14d,7116a878), -S(5f094928,fa4652a3,616fc7c0,25b6e244,37d02298,1b2611c6,51265578,daca0cbf,e6599733,a9d0e424,43d3effd,7993510f,15a5369f,6d4521f5,72a85f9b,db7699cd), -S(f9b59ee6,86af9c75,5bb9a4e0,8b15c93c,a787497,ae30a437,bac76831,6f57a535,77f0686a,2ff851a0,e94f28a2,57f05cb0,fe6cc480,39789850,e3f2c7f8,c03f5836), -S(f81d0108,f446165e,46460e5e,5c89d66f,f2dc8528,f19191e3,e75e5d9b,105c0a82,daaf0ce9,7b104214,942efc9d,ab807966,e321dab,d757649b,c1e294fe,4146a6dc), -S(fdafb234,9f9f169e,aac0d2b1,9fa4e2ee,a60ca31,3c544e39,246732c5,61e6d8b7,2b7038f4,9497fc7e,3e73bc8,dd262dd6,9ddefb45,f2bab8c0,770a5515,a5ab1097), -S(bec0f91,eeba7855,9df639aa,6a46201d,9ce07885,85be6bd6,1594c722,79586935,bff92e25,93b8cb1b,a80bf5ca,da923777,56cc1d41,92011377,4f73d461,8b2ad402), -S(41d616f,b05d2050,6a8303ec,e130c5d8,6d27322c,552a248f,2c0dfcc7,1006fc74,1f121fc3,55b81e7e,43523765,80cc3c41,d50e09fe,18dbc40d,a1c75732,5884c42c), -S(e483af0b,fd8affa,423005f8,3d25933f,d2a0c79a,3d020523,5fbae421,51dc626b,31895405,c1d359cc,9b0e5170,b93773d7,39d32681,de3aa9d6,ee635e9d,28abc9a0), -S(65afd96,3c02dd8c,f09867bf,7eadf306,b9dc6146,5b45e138,e20b0a07,570157c5,1034ac39,8fd3318f,44823b33,a140e57b,db8f9cdd,ace4fd8b,33967abd,304e56bd), -S(71aeec22,61b38f9d,1148bc27,7653b51b,7fe98d61,bb3c33fc,b417653d,fb7ac3b6,8344e611,348f222a,cb3c3e12,6a9dc0db,5375d4fa,c1cef432,6008e601,ba2e8c78), -S(ce4a2466,34fb2994,e0af9fc5,a5e8c612,acc30331,81534c0a,640d5fd9,c9b9d208,ca006505,98096923,9973c2b1,c82c6ff9,848232bb,81851f33,cc773721,a97ad669), -S(2bcbcbee,977d3ba,74c81f1a,b1c6eba1,3cc5e48,fa8d9623,35b8ae4c,84fac6f3,bf89907a,8ec4a9c0,44aa6f40,be9e2bf4,a100a64d,3d046c7a,416c9f8f,151db3fe), -S(a745a5c8,3c8fb696,4552ab95,df609910,46074f8,e7381440,e565464,6fb7480c,9b1494bc,ed6598dd,958ffe63,8fb3c73a,d773407a,372db5d8,3504197b,79f3751b), -S(9e0a17e0,33391d78,d168760c,3a31e3ae,f1cbfea,6e13f848,be89b691,11330dae,29bb981c,388aef6d,60461505,53e81a4b,98464956,a69c9494,efd62227,6e0cb5fa), -S(986ffa05,749bb4f8,3a1a76a9,3b972776,e98f87ff,fc66343e,965345a8,608e4411,daf77d3d,5bf42c92,c51f96ce,e78c1436,50cde8d0,11458939,833387ec,993775c9), -S(62720ce,5863fca0,c4723eeb,9f80600f,9a751974,f3c22c61,4bd8ad01,e92234b,f7f18595,97529732,e497344,b7ebb71c,ce51125,78b0bd68,8f2f6b9e,726f7d3d), -S(e60ece6e,c7745cfe,69a17710,c473fb69,9fd6ba1f,1af4493f,2926684,c9740ed,50d14444,a9092465,93dd08d8,3b8df343,5ff98525,907f04bb,343ac295,d8823836), -S(159be1b0,f7579ff1,ae272047,a1c8a9af,2c38354,1ab19a6c,ef7396fb,4c5351f,2ca76b1,a87755df,61682152,d0379ba9,3054049,1f91f57d,1ee1e081,602aa289), -S(79c9c14d,1997643b,44eb981e,1b89a7ff,a6511b81,9539d1eb,ef5dd46f,4c6fb033,2b9b88c0,3dd3e006,638edeb7,1560343c,1a9dff51,b12c891d,dda7f67d,140f1ec0), -S(610f1c50,8012918f,d60ca30,13369bcf,c4bfd56f,abfe39cb,2206e5dd,59827150,85f62af7,722b89e7,6de3ab17,368615c2,9ce6980,4c397580,d48f6f12,5bfbf022), -S(ee26f4b9,9a2285b4,80bde15d,83dd201c,24dfa7,b8be93a,c7ea3bbb,9e46bd88,129379bd,2daa2b99,906b2643,90eecfd9,78b033a0,fc550fe3,b41e1c9c,97671b1e), -S(b9b51c7f,2bae970f,2acc2d8b,fa88b9b2,15ad5289,b92d1f04,92c44804,7e3ca7cb,c5242210,e779cf4f,1f06e9b4,ec92ae71,9a08805c,a16689fc,15b01ee8,d3585a64), -S(1e7530f,dfa5dbd0,7ecbf05e,4c8fc7f2,a44bd3eb,ddc01d27,d83dd25c,c5d9e136,7857a6f6,6d7027fb,b602d8ff,f63ffe5,bae66c9e,ef23b198,bf65e7e8,3fc66d70), -S(f498545a,1008241b,d815e282,d3fd807d,ec8f331c,83669c34,ba126814,56f22037,998291ad,71473cd5,37ce4f16,7bfef603,c144df31,31769e3b,8f5a89c3,a3274584), -S(cba20c40,5a4297b8,2a6b7756,8512c2e4,26e67465,c420e109,b506a37a,9a177d12,81fc17cc,d2363087,ec9c61cd,7b3bd9d,580e280b,354fff37,b43e2ef8,78c338a2), -S(ad4522e7,87c3436b,3406f8c9,3d7f01ed,92c4d319,11644cbc,41c9e103,e8813041,6dea578b,a468d78d,478f3e6f,6233b227,686fe0f8,19ee352a,cab182a4,ec2307cf), -S(e60c27ec,f8dddf6,27ef1c4,e4f84fef,ec2825a1,c57d8a68,dd1283c8,4bc5547a,a807871f,f74ceef0,f647bed6,fe8c2182,e9581f35,465b9c1e,445806c3,428d98b2), -S(9aa982f,b4fa514e,c8f5e08f,447883f1,e49c720,58b6d1a1,d3c3c12f,acb22a64,20886051,e999d3c,f51206a3,165690cf,9d86367f,cea7491,599ba8c1,36ffb70b), -S(607de32b,6c74e540,55de8743,150e931c,6234d65,991e4630,d3e854d,34ff1469,f58fe81d,4f583242,7e8a481a,8b51bc5e,b379ee2,15888e13,fbc770d1,9421b5f4), -S(f980f137,30c560fb,bb4f6db4,c6de3516,2063a618,e1708e27,2f19b23e,af0f3b03,5b7842b0,3ea2cc6b,4d640ace,f6721fec,afefe70a,3729785b,6c2619d0,5162d5cc), -S(c85ae74c,7fdecb1b,52287522,d3c51a3c,4711711,82d089db,1a01e117,706da488,58f96a54,8b03a13a,d15fa656,e67bdee4,ac1ab1bb,d3b91b97,dd35cedc,96d315be), -S(4bb491bb,c05786fb,ad1d2081,2d23529e,5bdc2846,a344f44e,9b914f30,93cc347a,6cdefe1e,abb3ce02,bd3c4c7c,9b384ec8,701d36cf,643e99d2,5c4163b2,a35cdf04), -S(c1eed40e,ff0e2b5,c58ed098,feaa9ff2,7b9e96d7,ddefc1b2,53aaa2ff,ae450542,eb9b0434,e62e2ff9,10ba0dab,8074c85f,9a3bafd1,e6ed1ddb,e158edaa,3b5bfd51), -S(4bef4127,d6566ba9,33881d05,55fdf018,3c47772c,822dbc63,3e6fa336,d06e1c41,1c163ba4,9bcfdcfe,a99702d2,d9bd19db,bfa67409,f4d3777,531beefb,68ec5e3f), -S(3268e230,6eb8d65b,a528db9e,fbc05d6a,1ff35ec9,d4f0bc57,700610d,c9ea902d,126d5546,12de71f,93be584d,38fdb65e,7deccb12,9a5e4e81,b12746a9,cae2cb2e), -S(c4dbf5f8,7b30af00,ee576ad8,3c20f079,cac5eab0,3faf5df7,4d72d9cb,2226861a,badcd32a,d809ae9,7942bfac,a00be66c,80c6c1b8,4b8c7dfe,2473bb53,5bb4e625), -S(8c919ec9,22d79e15,4f1f63b3,5f04db1a,aac7fd2f,911e75c8,b7918baa,a13914ba,dda36a1e,5ada8eac,4aaa28d,6f0285cd,d0011fd5,c46b0e09,1d8dbb77,8b0deee2), -S(1d8b86c1,70366e16,d3c33bb8,247bbf09,cd04fac2,3d9d3b6b,d0fac9aa,3274efa6,ee9196b8,dd6a3e74,697e8834,5f9575c0,80601ba9,d02b9583,260caf8,e342fd3f), -S(ed400eae,debff33f,922353f2,323788c5,29c933b0,e269c091,3f84986b,6e4c564a,35bb3b89,8427ee01,df168a7d,6be85ae0,71c45003,df37b369,2c52499c,85669874), -S(11e79bc0,1c5472e3,3325e3c0,606b6f46,defbf951,2ffdf9dc,8b59294e,e7c03057,e3a588ea,ad8da56,47d42b0c,f314ee96,dc900c9b,5d7fe6e8,a38298f,84812c5b), -S(24a18d50,18273c95,aac1dec9,6d443b92,b980b7d7,d88ef70a,f4b728f,ee718b82,c7bc851d,3e0200ce,16dcf3a2,15bd5322,d9057c9b,df00fc1c,1b0f63ec,fe231826), -S(8349d4a2,fd0937da,1c85e03,c56f01b6,4c0422f6,bdf90415,d9c4ea7e,2bb5873,1557cc42,fb57f4fd,4de5fde7,e4655cb7,fa42452e,1664b328,425bfab7,63ba891b), -S(515c3896,cdf651aa,99e6099e,2d07f0c9,df039a30,c820c6fd,1665b70e,16fb6e07,2001400b,48447b12,391cd2f7,497e1f57,c948e093,6b981cbb,4a414adb,ac928ca5), -S(91251dd4,5a829e00,4c17cbfc,3238de56,c16e8d37,46536392,d5d05134,3cc12279,21748cf4,95c962cf,d28958cd,306536c1,84f8b822,7cc4dfb3,4a8f370,316cabae), -S(659f2b85,6db07ff8,1f10c48f,356acead,cbeeb169,5022f3aa,1e9920b7,896fe684,b7ef27c4,615ae55a,aa576c7,c92bb571,1dcabcff,1bb05c82,359ec59d,a34f53a3), -S(b82012f0,8c209d40,ad21a839,797cac55,728805c6,f139ad02,893cb9e7,3fd334d,76c80c95,ab38d674,715a6f6e,24978fe,5dbc08f3,530a4a44,904226e4,cbe8a808), -S(e6e4fb7e,8e7a946,62ba3dcf,1802903c,fc2cd961,634311a5,dcceb49d,9277e80b,93dcfc61,127c2afc,76a6e097,9033db34,51a95413,a07bed1e,9548d435,88e68add), -S(1e717f27,98ca7da1,268d6bc9,97c01261,6263a807,3874505f,5fad1adc,a56ade71,3093703b,69edc134,20907623,70572119,ff0e9729,a22689dc,8e421ac3,52f4a3ff), -S(8d6c2b05,ea5b29d4,b02706d2,40a989ae,2c3c8b02,c31cfb88,6453cdf1,c33bbcf3,1e27c8a7,25bba645,48236dff,79370ae6,2949c58d,37eac4af,e5977a93,e5ea9394), -S(ef9d932f,d19aa7df,89e6e21e,542bc530,28937f47,7029ff26,45582736,6f207c46,b45714aa,d344a62c,c9348d78,ed4f0684,7424718,784e8ee3,d9b1f857,4758fd29), -S(34932c61,bdd68dac,7957c957,2d4881fe,9e5933fe,65e6c3d5,6f74f7b0,2bd152e7,fd963edc,eb7607ad,a47f716,a5e8564,797c9862,14a1df3a,c6c3e502,86e75fda), -S(ba182aab,ad4a9b4f,3ee47796,3e8c0233,9b416f42,6b4403bd,6087ef5a,f4ad7a5b,178fc05a,35ada525,943ed04b,fa7b10cf,c69f9edb,63dbc72e,5bf8303f,97626792), -S(a5eb1644,c585ede2,59297d94,4ed41664,a4f95c78,239344f0,e6a66020,467e41c6,b04cc4e9,20e643cf,ba8b8dc1,5e4b76bb,575cf1dc,d05a8016,85211ed1,6a98bd20), -S(59ba1e2b,40959a57,a0b41dc2,f7ef4520,6dce83bd,da582f57,e03338ce,cae060c0,2c92f4af,ee3dfed8,3a910194,e548fa54,d4f07bb8,90386017,7394d707,4a979aaa), -S(3f0ff5c7,dacb5106,782f6527,ca891038,da40fe10,7866e49d,106ce243,3b88c962,3f02265f,4dabeb7d,18618e1d,a97700b9,f416e34b,e93da65d,1969eee5,baeb9dc1), -S(4d767b01,8160b297,3cf4152,110ef381,453dcb5e,30af00d9,5bf79971,6656f41,b2c8dbdf,fae8b792,d3a89c51,fd841fac,108e443d,e50376a0,9b4686a0,e03716eb), -S(b3a13e43,1451f086,c6ada2b5,dc38b059,73e014d2,bdb42157,88046d32,efb7cf74,2a0e4560,4cb507c8,6d6e6,686e9b2,9aece6ae,3fb5d3b,7f5f01ad,a8a65493), -S(cd90b032,a7ecd8c3,f1f2bcba,a523feb1,3790cb6b,1573cb0b,1e468417,e52236de,6ff50c7d,354a3008,7907d056,fdb0a4bd,2c34b649,f0f486b5,a366a60b,7d01043), -S(5d12d03e,cef954b,a35e82d0,918cc576,cc8713d5,e77631ab,ab79a0d0,a428fb04,bdfa4678,77f9a637,7bb86a8c,b36d886c,fe09659e,887ee49b,2018720f,6ee35d89), -S(2dc4f368,62d4ff1a,11246119,81a09c25,ecad53d2,e34fbe1,b708695d,7dfcb380,5aca4c06,e92c9327,8d5e29b2,e7af1e5e,f71ac624,ad1977f8,396dd6cb,b676efef), -S(5f1c640f,aae3885a,af679e2d,a3a73b4d,68c3b64b,e7321aa,ec0e802a,66262d54,704c3b72,eacbda85,f425cb4a,6e6632b3,e65963a8,7b26ed9d,770f3a7,81941c90), -S(8cd7d6fc,522eb467,3a366222,5157ce21,805f7f40,3fc2810a,a7678242,3559f2d1,397ddb0b,d0dfddac,bdf8826a,12666f70,d8ad9fe7,f96f040a,fe55e265,bef932f4), -S(b635c8ed,9b7b1858,86c5f75a,d524e877,c4f2cc11,a3ea63b3,7140b044,fb50e692,6c61f48e,a0cc779d,cf746f4d,7b6dcb6f,ca562bb8,5fe244ed,244e720a,648ac131), -S(e0edc56e,e22db179,fb5203aa,2aedb0f3,9f8cd83e,6a1f7449,e33a317e,97b29dab,d3b29f04,818245cd,eb6b3661,8d6c5e3b,384da6a8,aaa60818,ad56cb95,1ecb59a7), -S(f261ce,b12747ce,1b529cac,1d607525,5d48f813,4d1730,32735be6,72db7df8,6c72a777,69cd260b,b78c912,f0bf461a,4d059704,7c1de47a,23a2421d,ba26caed), -S(b6154355,f2b11b93,b69924b5,b450b026,ae63ba72,777c82b5,99d1d0a0,cab223f0,59fb58be,3295345d,abdeb091,8e93d412,c3c5bb1c,b7527ed4,adae9e72,1b4aca0a), -S(74cc74a5,aa36ad6d,42f82135,908b9414,2842819f,9f7b5c89,d2337ebf,af11751f,df890e41,b3253de2,c594c78,18ff0c7f,6637a8f,fd0e13c9,21a512dc,35fb8022), -S(227bf422,28b51fc7,9d090902,a842e78b,a7138a2c,666459d0,16061c08,d6947e82,1abddc56,c5fe3211,7783b52,68f5629c,7ef2a463,40af1fa6,f4edd22f,c9ac684f), -S(31a79a7c,3f1478bb,88ccf5e1,3a220685,845c390c,378c02ba,ddf099b7,7a2905df,a04ad9ec,4b5693be,7aeaf419,2f5c28ab,6ea03c2e,8db116de,7eb055a0,6c6f4a6e), -S(d1b1f29c,bdf6d9db,3d73f74c,df7dd879,14e00b0d,de6c9733,cf7c497a,a355176e,82c6aa29,4caaf404,a5411644,fdb115c2,3c6525ef,f4dcdc90,53d0eff5,6addb107), -S(57bc432c,9fba6e62,35ace8da,4e44721c,a87b44fd,fcb7bebf,610275b8,49b4031a,a75f94ad,19e9a3a3,a0395f4c,403114ee,aa12553e,e168a80d,6610147a,f5c3152), -S(a7c2839b,1c0b8975,2b85211a,e7532018,ebe5f0d2,fee8f053,e6666a9f,9449ab7e,cd2892ed,2bb40ea7,656492d8,40386e97,86919d81,dba6497f,e6f81e9f,ec8b2160), -S(909c4cfd,e85e5958,9384bd4b,6f780b6b,bde85dcb,fe36d8f9,a3f26a93,4c88ee15,f78b72da,b2531fcf,ea9cd085,c17b4375,4263ede6,8dabbaa8,6ecab23c,9475ecba), -S(cb98a258,98e877fa,3ec0d9b6,a1e6dd7e,477b8f7b,716c97b3,1e48709f,de7a3d15,ba6fb66d,502143bb,cc54472e,df00389c,998c8274,cbe8f997,66c90d67,bcc5fd1b), -S(bf5bc69e,81d7b4aa,e4137ab2,6b701fad,a86c6d1d,fd163e6c,4e57844f,3b55e84b,c87360c7,406eecc5,51697719,4eaa7102,1de0afdb,3198a9c1,9253975f,970df761), -S(2457fbbc,767f4fdb,2b5f6194,ca8cdfb6,fd1da59,19e2314c,d809e2e8,6913424a,910877a2,f7707fc6,7b9d3bd7,6408f162,f04c826c,cda46652,cc54415c,30d77518), -S(625e48ad,44703721,c1934642,d72b6989,94550c74,44589f46,33ea8580,e4c20d5c,ef31188d,c127c8b3,67c6b981,241d8627,5125bbc0,dbf46261,4f9b5fd,a54914f1), -S(3d4f45d0,8a28cb71,aafda05c,50a7f534,5b007f6e,ceeeac7,20cadd68,c04748bf,932ceed2,ae007aa3,469323de,fd7e7dc6,deb77872,85e48e79,bfc21cb9,a7bb8397), -S(49f9290a,55e6c9fd,ffe96742,43198574,d81c5b82,1148e5b4,339d7877,ea070de3,f7e61b91,ce217ba2,bd387b4b,8c01e956,3ff155e1,4c8bf553,7ebd16bf,b48cb0be), -S(feffa5b7,78a277de,ae68ff40,9c00b7d4,d6b78b57,b71ac08,f43a5e92,35ce62ac,b90defad,a94dc21b,ce8e7580,dc79073,b4152c6b,441da59b,d904cf6,76219d8a), -S(7b42826,344499b4,5fe3cb54,b8391820,54166846,7806a48a,6221c88c,b0831099,68c5e981,4889f320,cd2818cd,5443063a,4f85429a,5e335f5c,e4731a59,da2ccefc), -S(a2bb3900,e42c4bf4,91aee9a0,bf73bee9,c73a2245,a94e40eb,2f02a32c,760fd29c,6eea2aaa,ef457edc,357c3b54,547ff6b0,8e12f076,2d8a368d,7a9e65d2,d122b65d), -S(ecbf9e55,3bd020a8,196e0b6e,63e8f568,a60bed0,5fb7dfb7,7af48065,ed4c838b,e2be7677,9e7a57c4,3961af37,aeb7a8f1,80070633,617800ec,a407cb5,3ab63313), -S(9d2ad029,2217200c,e3a22d2,62cbc071,9e5fead,6683ed43,8594250b,44e60b3d,7addb679,81dc9504,8b2d98b8,6a4ea72f,faeb5185,f804514d,cd18888e,77acc88f), -S(8cae4651,91c4432c,9c6abb61,438b06e3,d3277b61,177917bd,8fd024b3,353d413b,5615256e,793c6b8f,d96930f6,96d0aedf,4320104f,fe3c7a3b,c7025232,9a10b1d6), -S(2151ca1a,c8b07208,2f765333,42ef886,4a7c9d95,f23e1074,9fc3ff85,bece3336,3a27fdf0,97569b0,52dce8ba,7f22d2e1,325b06b7,ada607d0,7241ad7c,4282e4d9), -S(f6d4679a,a02e074e,3f0ca3a7,95cf91d6,de2b9cdb,d0bbc86a,8e2d14e5,cb4a8908,eb16065b,ab9cbd11,2f30440a,d4540ce8,eb043035,a653e4c3,c8531375,81965fd5), -S(8f8a299b,ade7c13a,2b6ba6b6,f7aedaaf,c36a31c7,bb9c49a,43778c64,b72be2f7,8371703c,b338cad9,acd6db9d,6a840bc1,4bb65328,793ac715,55743a90,f053cf1b), -S(9310f8b4,73347c50,32840e4d,6cb2eea1,a334dc03,b1ac2364,cc0bcf95,e0bb21ac,134d020d,6c2b528f,6e96a9f6,6feddd58,1f4f0ff5,50673620,cac44f57,de0c36c5), -S(a4dfe64b,5f55c497,ec42842a,d2bce748,18f9ae70,cfa521de,255487f5,6d51685b,20b5c707,d8bca7f1,b5d29b42,c6eeb116,6c96eeb2,4201fcb,352e82c7,663164b1), -S(2b880bf6,9a83cf4d,c6138225,733f51d5,ce5b6a12,95b98bfd,e2929b6a,ee5d3863,c21b7e23,b84dfd91,eadf0b14,9649fc10,872c39c7,13b80b81,1d989673,6492a870), -S(300f1400,fad4b0cc,b20fe64d,d9b50202,1105edec,f0bfb8d7,7a1c9f70,73ce546d,166d9e75,ea9a6b8b,cfea2f18,bdf4110,664ffcc8,be29b91f,80d92907,e322a546), -S(7bf49311,d51f9499,6511d0a,70f65466,aaf6cb24,1666b76a,4e821e03,e47cba37,ef25f85f,6dfefb08,c367eef0,c8433f6,8a775f00,464c4f6d,dc3fcc49,7d6189bd), -S(b20cddfd,6f4c3b4a,d9b9ee4a,353d0ed9,9163cb55,83bb526f,63ed9d53,9359249d,b38097ca,9e0203ad,3214819b,b8f4cf79,afe6ac29,cb33c670,2f3cd462,d635ed12), -S(98296e3,83c9984a,b9c06a3b,2daafeb7,32696ecb,af1fdb8,b1d94df5,9149ff2e,fe25c8d8,a72b6b0,17ce8c63,31c3cf1d,dff0ff98,e2db364e,7ce3e642,d3ff7843), -S(ae3c27b0,e32887e6,568abdc0,711409b2,2030dc6,2bb9a2e9,739b5edb,fe4b1a1b,a8513f4b,57f9dc76,5feec2f0,1d7d3ba1,235387b9,132303f4,54fdbaa1,d04fdd73), -S(e0afc1dc,ead8b23d,5956639,5d312ce6,36716e03,e39f3cef,d2d9a5c9,f959dca9,a3a1e6bb,b7fc2373,76484862,e15d89df,8a617e56,b2d61f18,3b79e7d3,d2fd5223), -S(526bc9c6,798711f5,461862f,817b94a3,d66f30a7,bc2aaae6,1da54b76,69004cf1,542349a9,7ace4d08,1022da51,ca2c412f,7c0cc951,62d0c1ef,22d04191,18643b95), -S(dd2a8d3c,8f8bff64,f5acf9fd,6b0d613e,9b149bf9,7c26fd29,41b0c2be,b5419450,6e88162f,acac6dfd,5174d61d,2aa755a4,cd73c440,4b5a83bf,bb79aedd,b7213cd0), -S(d76bccc2,f4079bb7,dbd605ef,ec78a6d5,f3e8c655,c9b38f07,dbff4013,6d80faeb,8776727f,5caa4d38,ba1a3ea0,4a01ede6,5098e470,914806a5,1889399e,c0daa412), -S(afd6332f,27f0bd9a,ea917732,8bf60bfa,4b80f3b5,82319e26,c0fdb22b,dc4b9faf,9595fb29,a8f6df8e,f0b93ace,8f92bee6,f36edc,60b19d6c,968d4177,6582aa52), -S(fb3a199e,1d5f3237,79afbd79,246c465b,98823ca,2851b64e,79aeb1fd,8f90d920,bfea973f,41bf4aa2,f1cc94ac,58e00da9,e4fe46f4,e1d0bd0d,183b8e84,87a959), -S(c4fd8c80,1ef65e97,614bddd9,ef5aac03,3023f7f,1ebfd7be,27f3c4e1,60b14097,2689b9d4,e244e9c7,64b783af,ce2ec314,8ece5372,76c122d2,2fa5d995,9ed94723), -S(6e171334,b59b4989,e2ae6185,54f6c349,26fa1cb1,e7e8b064,61f8535d,cf8f69bc,8064d981,17637f61,72daa8bb,c4604068,624bb0f4,9555f73b,beea8ac2,77e2b54c), -S(e1509f15,8688d157,973361de,6297142d,237535a7,a6b8f64c,c982393e,ff91d6d9,3087adbe,df20cb0c,488b1f61,f12b7e82,f6a36f8e,34a8c1ab,22d71261,d5c2c40d), -S(1235ab12,23b4d47b,e3e5fc37,6b3986cb,941884a9,37d81e1f,991f3fa6,8e529a25,7dd787bf,f7cbb123,e814eeca,45435af1,e2f32c25,8a7081c6,b66088bb,8e560b44), -S(9d70541b,e7995deb,7c9ae87a,b2f085d7,fb458494,f6c4845d,5c8c013f,a7d4a9d5,b1b6c09f,f12d7ed3,9c1af481,3ad135b4,dd0561c4,5a16d111,9bd696f3,e4cdb757), -S(8649ad0c,d9fe1177,8651ed9e,3c2123f9,8ed3b0df,f0afa4ee,adab9fbc,85680dd4,cbb0f8d8,4bc474da,bd1a0b7c,d397e1f9,d9acd111,5847ea54,9018f290,9594fecf), -S(fbae2b84,7685902f,b1473523,2b13f16a,c03d8366,32294d7a,6e214acf,8f8a4e1f,f3fa3a7e,d6cf4375,1f10050f,35a5252e,3c6a20fc,c3d8ef8c,cd393ba6,413f5fed), -S(635dd021,ef74d3d6,762503f6,924c24a5,32c626d3,75ec0d9,279b0086,bff11281,d2eff50e,b28be98e,192dabc3,8b5a605a,639b665b,17fdfc3e,4f339aa0,33d971e0), -S(99ee1d87,4c97c493,f8942a93,8bfbd578,63f8ddd6,387f716,3fd2a454,fd43bd99,81b96b6f,8d06086c,34407f7f,14e2ea21,2fab454f,131da461,7ca88bdd,4026278e), -S(77447295,aa56c62e,d8722ce0,522c58e5,5356d40f,b657ed65,663499ff,289f757b,f60ac045,15811b93,837a0819,f59d6fa0,c1f709cd,2ab128c6,95716590,43373251), -S(b006dc27,bcf879f,92b86d6b,ca0092a1,d848e98d,de52fb72,80081952,34857183,aba7308a,3686ec32,a0a2eac7,47f69f1d,74f9b7f1,60cdb4f2,f8eba9d6,2a9255), -S(41680159,8de643ad,326c6e46,3bd51cac,8c52020b,feb7ca44,6a9c0820,c02cec4b,ad11cf30,5bf184a0,3965085e,42a95721,6a64d9d7,38d9cd09,1dc3a8bf,2ec3b65d), -S(a4e68433,cb81a8c,148b8b3b,473dba7d,c9a1e44e,8e7d804a,519005ae,5c1b7d9c,89668932,7c597505,cd1f0e06,4273e574,85556724,3d257fcc,e0baa643,b38b15f3), -S(3f9b53e,587b01bf,a04a685b,c7d30db7,4f0d748e,44eff028,19192e28,6bf49016,6b927f7a,910f0057,d19f4604,140c7aae,b81563b9,f4c54ac6,6427e50d,11309e81), -S(6833273e,f2629ed1,d95ced8e,e776bcf4,24bc1a5d,284d54c7,d2c3b634,1ec209d3,25607f55,82f7bf1f,4ab5cc2e,c883ede9,8523b751,9d392230,5d98fa5,41e741b6), -S(c7be699,289a091,3021e2b2,eee75322,8cd18703,cbfa7db3,d1d5f0ad,f6d506fd,e5d016f4,2932d594,ddf556d3,399ffd46,c0b677cb,8fd59340,234c9b7a,349cf213), -S(6ef0d7f6,1803acfe,aa62b4e1,cf238e5f,398f0adf,228629b0,65e7c2c3,fa12e589,628336db,78881419,3026db69,2ed2aba8,ebbeda93,fb4f3903,bb8b2e8e,839eb7), -S(ff83fd15,dca2a55d,2ecfdb97,83ca9595,fac1f440,4b1e96e6,dd3abf90,ac857e69,f061ce87,8640d2dc,5fa4428f,75ff93,14216b92,fc1ffc72,29931d8e,f51c494), -S(f445bc67,47a3b7b0,fe56e4a2,db1aa71d,d042b6a,7b09cfe4,bb28c0f1,bc636587,a79a976b,7c857356,2d6131fb,e8476e13,6b6b0863,b8a464df,8e57da25,fcebedea), -S(37f88df9,22775959,94f77586,72cd5894,71c468f2,e6d3e424,45404b16,ab7b9e76,509ebf24,7f83ca08,71fd94f4,b178310d,4fc62bcb,27b256de,22092893,ff3415e8), -S(fc6ed464,1f548b62,a25062db,6b4c9d18,4d5b4b69,ec9fe4a4,db269646,331f6d12,cd384884,28427b19,4c77395,1373fa66,2ca1c771,2cf7b8a2,51c5049e,5d89bd27), -S(675eaecc,5c441173,b405dcb6,256c95cc,70c6ae38,3ba69053,ac02539f,7b6df001,4c275003,664b1f98,98bde64a,6f1b366a,2856a30f,c39fc84b,b6f2d94d,8435c76d), -S(81d9496b,3d892b9f,c4e0b98a,25c157e5,331d6d19,2a7b27f2,e52d2685,3b633395,4b9714a,e69680,649209da,eaa9734c,c611e98f,9bf19099,6f514022,aa2ef5fe), -S(5c6760d7,dbe3dd8f,26bce0a3,a160c8e0,63de688c,e2227bd6,e890e45e,5205076a,f539524e,a8cb2036,bd6ad2b2,3738222d,fe38823,9f03ef10,dfb9d223,407ba175), -S(6c47b5c2,889c17bb,e9f4c1d4,c930a975,6f74423f,7ae9105e,1dac216f,5aec8d3d,55eb547b,d3d60c79,c585b602,dd0f86cd,7d3895e5,b5bb3d13,a44b90c1,edd6c978), -S(da9ab6b0,4a4d3b27,31130717,aeec1123,b21eec88,ae16d3a5,547c1acf,664a264c,87a44739,396a75a8,1f0c542d,2760a2db,944aa850,f61e2fd2,e44c840a,a222a193), -S(cbfc9815,ae28411f,d7056e72,3a4d3fd3,a026d293,f8741154,d9db4ab6,a0147f41,71ed4ca1,e6702d7c,bdd28e8d,9fd41f6a,3879e88,dde652ef,9c639f13,f183d172), -S(2629d332,e3e1ad22,35420ff8,f94d7775,f2385186,a0559166,2aec35f1,623ede43,8e9cccb7,bd6f76d9,d76f89e6,3d8ff895,306028ba,6bc4ddbd,de26f81b,3eb172d0), -S(47ecfa1d,c1e01ed6,111e7ffe,fb44d552,e7a72e76,228914c7,72a80468,634edfc5,c7f3a761,3cc68070,7a1e9778,b0deec89,fc0cf226,14e16e84,4b661766,e6f6b6b), -S(c9fbd01f,ef8da054,7e5f2fd9,c5bc59c5,3e3f191a,7abc3cf8,df5e7c07,ea2adcbd,ba3c6b49,b5b9fc1e,4f433f14,b1a98e5,e20d2448,7fb234f4,9384e610,2035196a), -S(c179921f,24e2539c,9f90d7a0,37d8bce9,bc2741f9,4d7a78fa,a0212d66,f66a0d96,59b573b,9e9425b6,a0232e87,2d0998f2,b1815f68,a2c1ed5b,7bb5bcb2,b4d737d2), -S(a37a89fa,5001ec92,9a93291e,8506c5f9,b669603f,eb3ee27b,5e487113,1ad82cf5,a208d652,6666e930,964ddde0,737c6af2,900b2f0b,5018d814,904e71e5,8f8a0e86), -S(32323c29,2f98e042,abd15506,423514f5,4ea4070c,da493f93,10d1514c,a1895df6,ef273d5e,56e5ada7,2c872483,10180661,a0fd697b,5aad3faa,4cfd1915,fd749ff)}, -{S(6ae991de,18418b49,160194f,a735eb72,c299b987,1981a4f9,aa717ad2,bcdcf13,7ee8011a,40f384f2,e50add2d,97005173,2787cc7c,89dafb66,301bc94d,24b913f), -S(6fe08b32,ab3b1553,14f229e1,138bb09,a3eb4f6d,6629e4b5,903e122e,7ac2917a,4e4e077e,76ab6d54,97c1fd8a,441772b4,36f350ae,ba1863ea,d1fdd05d,f80e6e78), -S(f5ef51f9,13e10480,9a020bc5,37db3a90,3f3e3410,71bec65b,1cea5343,d43cf884,7ac5f6fc,a749b09e,9dafba18,c16bc969,e3d63971,195b92c0,fa8356ea,3419aba1), -S(2e03f430,51968210,a7dc64b9,612b25e1,cdd167d7,f6e39466,9762ad15,571ad471,f063dbe1,3f537e48,1b249a5,67fbe709,ed80c68d,cf8d4e82,53038d90,e67f1de8), -S(8244571a,ded2fff,1a4c9c1c,f3ea152b,d7852596,3e84b90d,6a3dd929,6e0ad9e5,ab14dd92,be3556b5,63cd396e,d8cb103d,cbacfd7,825faddb,1ebe6e3c,9a2e1180), -S(5fa7cf3,ad236db9,db9df632,e7a172f5,fb5396f3,c4df9bdb,d557a3ac,68a97f46,3339f27a,7a6231d5,3e732557,9ab22f3b,49dc29e3,75e08289,b816e6eb,a3ff3128), -S(5bcc702,f5f4a8dd,3f3dd519,371baa04,85b1284e,8bb539df,d8b89401,7206a943,5426221b,2e3fb26b,858a3f27,3d7b67cd,30b7c2b1,b881c285,cb29515e,59b92e8d), -S(96a96f3,79c8dcc7,f87865e5,9023dc63,95224251,12d98ce9,59b610a6,eb7ef515,bd61d338,c84a70e3,545bd8f0,aa0113e7,93f25c8d,d78ec0b9,d5b98d9e,81e16e82), -S(7e491776,5cfb89ff,edc43a8a,c998da5d,cab4bdcb,3b1d6f58,9def4de0,4b976609,7271e990,b7031b00,a990ae0c,86d893e9,915a84e8,d071a235,95054301,d0874199), -S(f9b8be29,8b5cfcec,62e0777e,d916c7d1,371b4627,9d141280,fb8a2767,1af02c8e,c6bb3293,3e77471a,5157f009,58917cb9,4cf77b81,7dc1b2da,d465dd49,711b552b), -S(9f1889b7,720ab815,e6a026e,67be852,980a9609,9e34d570,e1c2a2c8,55a2f54f,9786d89c,4fc1e09a,3bb81830,92df472b,5c1212f0,4ef05a27,dbe9d0a8,75d5e1f5), -S(fc53a56,52d4c07f,3a4af93a,e88cb4ca,5db66818,ab2c874d,63fe59d5,eaeccd32,bdbd9a97,f57136da,8f8dba2d,f34e5d3e,e1dbf1d5,ef27f,11c2c45b,98ef2d38), -S(96a3ced8,ba47f6dd,48a6b320,d88221a0,a5e36c5a,55938018,2dffd1d,3c3c4d00,ee4272ed,b244f95f,54b68c62,2e3d09,b96c7aac,fe77e9af,600a227e,8ec5299d), -S(5d552446,cb8e1882,2aab5aae,676fb3ad,b44eab09,ce665918,6fa6ef31,6f081e9c,723cc3ea,2bb559d8,da986b40,263f5551,25127091,3dbea220,f79711ca,638f77fe), -S(2bd7f7c4,8be5446,86e5a48a,d663345f,bebf198e,d7a6dcfb,da278054,f86d8e0b,584ba0a4,d2cf2664,e9d99d7d,a513b3a,5c06639,5fbc2edb,9259a51d,aa500e88), -S(1caecfd6,26d39493,a2ae68ff,f7af4b05,2373e9e6,8461d254,f9b6d651,9e92ff6a,cfa0c927,ff9814cd,b2af3cf7,4ab5e514,70d70a66,9fe1f353,b0a92182,86bb183e), -S(31ac3e18,ba88bbe9,21fd4834,f9f63ff7,aae351e1,61874ff4,2f8281e3,cd7cfbe9,61d0002c,110f2a2e,19c1b720,a85798e9,e8be1124,c68854f8,b73d6674,4cccd7a7), -S(19bc479b,1637b2cb,2e700f3a,f06b4361,ba1f5d9,7d1e5099,6bbff88b,6dfdabf7,9a59b4c7,deb3ab08,fa5e9e02,4d8bfc2a,a35b15a4,6cd99a08,9fbb0f3a,8770d0dd), -S(c1915003,caa74b8b,51576d17,de53e4bf,c5cc63bf,9c29f847,4981e180,a71fa0b6,cc93116e,500ceae,f045aad5,d9d7a863,392a3534,694d55bb,1aa69cd3,895c7819), -S(ba105ccb,b1c32d83,a57eeda4,2a9bb748,d36370ad,805ba1d0,647bdc8a,1e84a968,76adb37e,53b8bf0e,368a1a87,9a74b6f1,33116144,47134766,27f2df12,602e6377), -S(892f8edd,23341050,7540f11c,9f0ef107,99099081,dbf9e4eb,9bac01e4,94b8ad05,f0451f12,42bf423d,37afc17,74af91cd,7593062d,f22712a1,dc109b7e,f5b81141), -S(389df091,4b0f71f9,70416ec7,1388a464,c0d3d4e2,2c2e111f,f5bbc5f7,d3618bae,e12e51e7,f27256f2,3e8f8935,677aec3c,7c8f4950,712039cd,afa521f1,a88a1f46), -S(383fc7f,86bc9c65,f831c676,2885ba75,25a72886,5d6e91fb,b3ad1a53,d4e64f3,c58d161c,6a14470a,a7be7467,576a3bd9,67d7c944,ae26cced,74089773,b344b2b9), -S(cc4e9f78,9aa3fd5c,eda60c2a,44a55779,1ef31b72,8687ab18,7012ed4a,616fc628,7aaeb0fe,1a94b6c6,4c033c77,3a1fe878,b9b54559,9af6eb4c,a9e79540,faa7ef34), -S(dcf7dcdd,938028ed,f92c5797,6c3faabb,1f2b155b,59a0389f,fe1735c5,ba658aa2,2a008b2c,29290f2d,b64ba559,3c905c4f,46cdae06,ae2b687f,af0b5b91,5422d5ae), -S(75125b5e,f968db84,df6d0253,5108e0cf,df3dd50c,8ca63618,9521475,c02b26df,f6bb520,f8178541,ed169ecd,42a62d42,57ba7d3d,aeba4ad5,e979c8ec,19cf935b), -S(24f1af66,45831b37,bf80d0e7,e6185dd7,51f09e9e,5a71cf,ed350b8d,2c5834ed,2e04d2f1,b0b5d468,b4cab2dd,f0b18467,f8b78304,2b2f5cb0,49d7920c,695f3551), -S(75024c77,150ccf3f,dc677f59,118b4d6b,8749d514,256c1641,e7f70e36,5d99fcee,d36fe19f,442c7739,cc65d1d8,c7ba5479,57aaf055,38497cb8,dab1ba24,d92bae95), -S(4b0b4d7a,51b5307d,69b366af,9a621e30,258b3a3f,affd9a47,52a4a14e,562fbcf3,dffaa5b0,7133dda3,3586df1e,400412d7,6da55cd2,a978e8df,88e23415,9ca43127), -S(83c377f9,13afe5f5,21bb2550,b0a38343,5956fd13,e62e46e,75e77d96,ca2ae791,db64f4d6,6acf0537,f9d60b6b,28ad8e1a,cd9b414b,8f60968c,62a263b3,c8fe5138), -S(271acbdd,71cf48c5,e5048853,3cd6a1f,a49eb8fa,428f05ba,6d7314cb,d128c387,ccf83cf6,2d001c59,a5e6b531,ff40833,4a2b2421,aa75feed,d9ba7878,67323b6), -S(4d41e719,e003cbf7,f3c26d31,139ae98b,a0a24623,f8b86c94,6edb2bc3,1be3983f,2e052d70,6348b402,40e8da52,3b5b3011,a79451ce,41222416,ef040d76,c64a8caf), -S(2599981e,e5b9ec6d,c5da028,1f5ef995,abc78520,32951d1d,6356009f,f482a96c,9560bc0,aa47102e,1488f45f,90797862,3fd9e54c,7467d600,abfc389c,459e5136), -S(eb82b86d,84989f3,68c8fff5,5f801f88,f351e43c,80f145d,4aa7020f,ff057090,62d44ad5,d42a796a,373724b9,f583d57a,d8c19d6f,36f215cb,1c20ed12,320a60c8), -S(8637f2ae,f77485ab,a2871d48,a4f4296a,c84f6afc,b51cef62,b1f22e6c,4cc4b05c,43ba306c,7d6a184b,774e46c3,94c404da,b2acb796,ba239786,d85b5fcc,2c304436), -S(ee462322,f2f44e1f,96643d7d,bbdfe53f,ad268a49,c9a582b3,828bcd2c,e471c1b9,910ec3fc,b9e4479f,2a6d332e,4f809556,1c69f6ee,812b3097,2812079,ebf87cf7), -S(4dcb9320,6a69600f,6d327bb,624d9ec6,24e6d98b,a758922b,b102d159,e6c1c206,da85a8b3,de7b2e,51ddb90b,99f30c7a,70f1bf23,e2c90b47,eac6fe0f,b0d8f514), -S(a1373c2,d15ac2af,2c496399,1db04165,28c74259,6d9d81bc,8004b80f,a68b1405,b7a13e6b,9255caf3,ca4daf3d,21b5739f,65d1e7c,74330404,24911fdb,4e8815da), -S(fbd0d0eb,5a93c0e7,4627e83d,c483b873,96eace6f,fb75acf,ac743e1d,c7a1aa92,bdc310cc,3f420fda,28012f75,e6db4431,d2032990,d4d09a6e,7fb70fa2,fe1344b2), -S(39d9552e,136794bd,76b864ce,d929f2f3,ed4b1b2a,e15b4c9b,485179c6,1d78a846,1565f88f,f2a5c23f,c2110572,c61ba868,9035cac8,ebbc7e8,367c37a,a22308f3), -S(b92576b2,def0f8cb,e13ec334,93e2af06,f2ebf949,332fd038,689dbe3,70700e57,3d7b8497,523e3901,719145,6e908d62,63f752e8,ad2adbfe,13b6267a,ddc415aa), -S(70806f30,e3a407f2,78d59553,fa3fbf72,d5129209,75e703cb,5080627,f30b3d09,c190bf85,9f43553c,6ccacf0d,e33359f4,87b3c406,ea07d424,981d94cf,9e542976), -S(591c877d,6e4c5d56,95152fb9,b809fb97,41a46e0,446b996c,14d201a7,4705914a,b9dc4a1b,e049f291,5c1e6c13,abf19e36,f6560138,9d7bb630,c853b122,9aa70174), -S(f7f3bc9c,fde746d4,fa47131c,195200ff,53c05c09,af87413d,84e9f7f1,feee671a,70a925f9,5b6477a9,f0a6dfca,b49c214f,c219cdd2,213555aa,ea49419d,33f8334a), -S(9505f06b,3a9fa87e,ae289c2e,f4217b73,edb72175,7aa4d7b3,b681b09e,2f651749,231dc38,d5d63d14,4ba84942,67e1e798,973f632f,8ccc09d8,be747810,851c8962), -S(e33e547a,9987dfb7,ae681cc7,1cbc82da,4f3a3a57,972c2b5,10c09548,6c25c04f,55b7c3af,2b3b2684,6ad280e6,51dd817d,b99b856f,409492ca,4f1bffdf,d3fbb232), -S(7bc182cc,598f9281,74fd434d,9b5c2006,e52e864a,90b0b1bc,1634639a,68e8249,2810d2c3,4bff6211,63b09ebe,e77ec622,ad045f21,f9c103c,99089b2a,f0e8f7ca), -S(83dcd3d4,8a18e1e7,353f9b0,76b7ddbb,ddc371d7,7e3d56c2,3741dc5e,c5686edc,8c297536,c3b02d6c,f059db38,791e08b8,2ed1d82a,8cd03186,d2a0054c,862fb085), -S(d4b08924,b8e71bd9,6ca26c62,9c712e61,dc17a48e,bc07e6bd,116d2898,25aa42c9,c1fdad3,1e85fdcc,2f2a0a63,7308c8a4,ef3b31e,a81fce26,21e98cf8,cda3b25c), -S(1b42a702,16d7cf97,de70f734,37a36d38,10f670f4,6a34f585,f9593c50,c6976,f29bd13b,79a7e65,f4f7f94,53b920f,5c751b6,a067d288,82e62b40,7b9858d5), -S(c61413f0,7bcd6eff,ec818025,f792d8da,3643c869,4bf3d582,9a1813d3,cf38beca,68f603d3,db4d751f,ab0823b7,ed050c40,787b003d,6f6e001a,52e3ff8a,71ac0999), -S(5e90173e,8be185b2,16b0066,aa39a73a,350eeac6,e49b4cf0,546bd57b,50ceb215,455ceebe,31e6c3ae,388624ae,fa2e7a1b,fc0c4950,12c43803,c4eaee31,d17122d8), -S(7d0b2da1,8d6416c3,d47bc493,5e409ff7,6b437874,911347a6,3f8add69,8e25c6d9,da9f27bb,82034ba0,64c54a6c,13609188,584f9014,cfeba572,760b23c1,fcea509d), -S(611b1c17,117e25fb,dd62f458,7daa0258,8d9143de,e2bb133d,34377c3c,28778daf,cf1732c0,6de82698,c2531c96,eba3edbb,23aa6586,372cefc5,bb49831c,4c00df80), -S(b43dde41,96f3bca9,ade881f0,5878d347,812abf24,b1a8bb19,9a4a1d76,2f5e243d,1af78af3,acd73de3,dd2a28ea,50b4940d,284d501c,4d39dc3c,8d9220d9,37aa2e67), -S(ba0cf8a,74235782,f251649c,5f6e53e3,6eff1062,fc51f65a,c2a8c83c,e89f4eaa,58e47b3c,467342bd,4202b54,752ada79,a7356f88,92efe201,201af87e,fccde55c), -S(db06d4e4,ca9b1ce0,6d59cf88,da187b77,5e9568f1,da33b398,c682b8a3,ad9e88c7,418daca8,a8e4d3af,edd2de9b,868ac424,6faec0b8,f0b1edfa,e0e9667c,1f3adc1d), -S(8a46cba2,7263af84,80c9ea35,ce8757b7,9ecd15f5,e938f41,aa7d4abd,5c3ce006,6f28398c,eaa2d168,7e6c8427,730ca15a,19965098,7c7338c5,e40798d9,82fc016), -S(705d7e03,b5f0cea4,3720c73b,d6b4ff3e,26d2f8b,cb2f5ffe,6f5f65af,63e4fcd0,4a41f717,baffb579,b769e3a4,ba976687,4727c132,9a30bd62,61df3d91,1472ef9c), -S(e6ed0125,6af3d738,84d8fa5b,361be34,9e2506f6,88b772ed,eadc5c33,98233012,90c4ee9b,aca8162e,2b58406,83a7de20,fb181b92,da81df99,e612e122,8c8e520c), -S(95cb73bf,29e8d04c,a2bca75a,5925ded6,327e6128,e6db16b2,2847ed49,d3ed169f,b4e84fdf,526e060f,7b3d73f3,f534d669,3537babf,3b1ae0b4,c65dc8d5,11917b77), -S(aad1e800,1abd18dc,4d929c2b,c2d59b8e,23c90d56,7b0af36b,2e4bce1d,ea2ee299,a27daf61,acc02936,835d5742,74c875a2,57796038,de289d27,d97bea15,a9d6be93), -S(969303e0,75cf2eb9,551f93e9,43c5512,71bd1a29,b26feda4,cdb603a5,7e333fd7,a8800641,44578fb4,cf16d1fe,3970df68,708e2a10,79547510,f63ca035,616b2f5), -S(6aa570e3,de1b51a0,67e33350,cfb337de,23ce7af1,be879ccd,2b2a4dcc,db1ae9e,98a5f5d9,79cfde0,30fd1ec8,718d2b74,d33639e1,80d31134,85c607ae,d871f166), -S(4e469241,842ab69a,93bc6844,1b6036,578a22e3,c2902da6,1cfde122,962197f8,cc7ba90c,a290de88,e980f50f,bee59f67,ec227323,1db05d3,f11b4e72,34080cdc), -S(772efb55,d4044423,ddf466cc,925548eb,b2525458,e24bdac5,7edc33f1,2cd64bf,df73e64,818bd4e,c7abd07b,24afa4b9,8be7aee1,d115d936,8f4d0fd4,7f40876b), -S(a594e20e,62db69af,4afdd0f2,5a735906,75446d5a,71574bc2,12bf9f24,cfe879a9,1b2fc870,e5f74b0a,994e1d0c,de8ef9a2,74e6b49e,185f9251,417154a2,4f2163ba), -S(c133d96,a51cba90,3afcbeba,40ea594f,3e39a106,8d0a9898,7df1ebe7,4c38d3e5,5cd8c400,989efe10,295ac89b,8891e0cc,be15247d,61ba04d0,4ea018b4,d0fa51da), -S(3ea10966,fca290dc,b77c85c8,232ab56b,afc1dfdf,78628736,9a696fb8,92e67998,798174a7,b4729cd5,67ed639c,9debebde,1538411,94e99adf,f51c4866,990396af), -S(8f0fb3b9,85565632,8207c0b3,e1528802,310d222a,9246e686,6030f9f3,14472152,4fe2daa,d16d75c3,ea219295,661ff8b6,ad9f73a8,b06ba105,80f7f6e2,6661eca9), -S(fc22c901,b93809ac,21e1a89c,8e02093,92e19fe0,8f83d82a,733dae3e,16236a9c,8db62408,8fc9adc3,39de5f57,5377bb32,e3a1ed8,2731b18f,1ecf4beb,914bd42e), -S(7afb17fe,1a4a5e3a,eba9dc9d,c5e178ac,ab9e76f0,d3efdf96,181b1fdd,eb81544,bfbdba94,c3e5d27a,547db3c4,83a09847,3e5c118b,9fb961b4,e78a40ab,84ab18db), -S(38420ae6,13e0eef0,2cf9c567,b0bc28b0,59035e0f,d5df3fe2,d117eae7,27b7eef1,6e21e249,1c6a6f88,e2c96c1f,76a9238e,82cdd6ca,6e9ab090,56e0c1c6,4ccf808e), -S(6b3e232f,1b22dabe,e22f618e,c1a002f,f6aec9fb,361175b3,fe2d48ce,ee724e8f,2530c6c6,8062ea89,24e6a793,6b1e582b,1e630c0b,fa207505,76a6fc24,5e01a516), -S(8f4f70ae,5fc21122,275f1265,520e68a5,e2fb605c,bc3f17df,4ef48133,1d4d3e24,236bd0c4,ef445db6,9a0bd1f7,7ce38360,137d602c,58f8b70f,395e65b3,8b1f18ec), -S(333fedbc,e4a9064a,cdabf1d6,57d5df7f,86114a67,28bad2c3,29a2bbc0,b7e822da,ca491209,173bac98,fab92935,ca8dba42,2583bca4,b7e62ac0,3f805ee5,5f1301a0), -S(d00cbc99,3a9c2c65,b24bfeeb,f596ac8,c925c51c,e5211f32,74145c16,138708a6,5349ca5f,be59a8c8,4ea300,391efa3f,54b3344b,d708412b,a9e6b0ed,8deb8b04), -S(968af2b6,58020db3,e8297d90,c36911c5,786f1d50,7246b35f,86da1cea,f46efc83,453866b4,f19d5268,3ed07612,57bce4a3,173b2c58,280927dd,ccdcbc47,75cda533), -S(fa0adb79,476bea48,8926e659,c8687e14,b769c88a,3a1c1ba3,f11981c0,6934ff7c,37cf240e,ff3a6514,fd7ba90e,687ad6cf,3152f1f7,6d23b8c2,9bc1198a,bc5176ce), -S(7c4a3b6b,3b9c44f0,4f4aaab0,9604066c,3cddd61,996e259,43757c5,a9832392,36a13d10,9ee60811,aca0b269,d42dcb47,aaa0f7e1,7158fdad,50f07e6b,e11289da), -S(9c4dae1c,c6162f5b,e66bf6b3,53b50a45,d1f400db,aff1dbfa,779a94ef,ce7ae0af,2513117,efac13eb,cff70674,b3a9d27,31db473f,e198c3af,59ee1753,f4be8411), -S(c66c125,a04037f5,dbdc4254,70b16cb2,b6318a14,bcd69f85,44ed7eae,346edf13,288a0477,4c2bf346,115235b0,5f921d9a,566c32dc,67755557,a550690e,42b115e6), -S(42f5a4f7,54d8eb34,62c8da57,9550267a,9d73626f,257d21a0,486c043,58c5cc60,fd89e17d,67a052c6,71af223,2337ebd6,16e13b7b,72480373,3fc3a29c,4ecfd240), -S(725051b,43e3107e,2321405b,4f974469,be69f90c,a961e352,7bb8490f,f8d8c7ac,a143d4c0,46ca1288,97633b98,7a6bd28a,81f035a5,e1f49626,1aaad65a,7f68d1cf), -S(358d4f1a,1b94b0c0,9237f4d3,8d7afc79,f1dc3b1a,fae46a67,1a386ea6,ce6b81ff,b8caefa3,86daa463,93097bcf,526d84e,3666a231,97f3804f,3d976ae4,63fa65e3), -S(749bb6b,e9d272e8,8452ec3f,ec83ca71,c15471c0,608a4326,7355497b,27ffc67a,79d588b3,cc607639,4f410d13,c3cab3f7,e635d10b,44e9b242,583b75a2,62136cc8), -S(e5e8cc0c,a1910688,cdf89e82,da4f7a2d,265f63e3,247e5e3d,39d46fee,b00aeff0,89d4d528,60689061,aaaa4c03,469979ef,4c734119,4181ea99,2398691e,29235eb2), -S(62341395,d066f441,60e08ca7,5a9329f3,7581a8da,fb78ff99,1336faf2,407418ad,63930988,431f129f,5933918,e5d23e7d,8249267a,8f0dfbdd,7945e34f,e9e24959), -S(1a4900e6,95118e4d,9f956e99,2f868c3c,dfe8580c,64776298,13da88ce,fc9f8aa9,53bd8fd4,953510f2,72b67737,5b6179e3,e02e12b8,dcd930c8,de94e400,225aace2), -S(b0303fc5,8c1944e8,a84d9bf3,f2102f50,2bad6105,afbe8a37,b09025ea,6bbcace0,d9a29c66,1af8a54d,7b115f8b,52b834d7,e7c2afe8,c7308d61,4e64aaae,3f0708bb), -S(4b51c846,44955e86,9cdf575b,b8796773,d70ec44e,fee77957,c342d491,aac8ae0d,32480851,7180afa0,2d786a90,172ee8c5,75a5113e,ecbff5ea,444ec3e4,143a8d48), -S(c0d19125,b3fea060,45c1b2b2,4febd77d,e3a59da,4b8a8c0c,910189dc,b38d0228,3bed5e0c,e1a5c537,1d56cead,8c2975e0,f420ad89,f0308ae2,95a0c9e1,fd88d10a), -S(8bc96490,25ecb626,131c81f4,c522427b,7f8c22d0,90fd225,ab8bbc7b,50792500,5d2a60f1,591a151c,f0fb3a68,709e1050,21b9148c,5120a79d,100bd319,aad0479e), -S(4acec462,c6566ae9,c17ee177,61822b5b,5ca04619,30270d8,d5b3d342,5e9daace,82832a6c,ed0fcebb,3f40ba27,6e964981,cc0ccbb7,e2a1bffe,6e10014b,c563b12a), -S(6e7b6406,8e3d11de,ee7ccf55,1cf5a34b,168c3f29,d013a5d6,153fca63,2789ea72,72fb451c,f696060a,a82a14ad,1ae636a7,e0f338b3,8aade7a7,fd2599f5,270b55a5), -S(d24b42a7,40563303,25ec4fe3,11ceb35e,68d6b158,689a7434,4cb65ce8,2fbe5104,b4ac12ff,acc676cb,49d5bf0a,7e0a4167,a2460dc6,1b833e,f26083bc,6c7f9523), -S(5ed0083d,2205815c,576c2207,780d9159,7e985b26,9581da3a,2d60f088,1aaec692,2b7ec860,7d94d1d1,7dc3d67f,caa6f499,e3476f8a,d76ae00e,1a981455,85654267), -S(3a2fd05f,4ef9d7cc,6939dbea,a389521,9b1474f2,6fe8cfd4,a2337771,66ee418,5d04893e,6bfaef9a,ee8b9abc,347f3875,2c8cd5d6,d43da92e,be05777e,1b44e546), -S(a0e5e214,53858d31,7aef7152,aff56438,b425914c,d42dc2a2,61415381,30d13374,8ae28cb9,fee0271b,98fcbdf1,66dc9cb6,f0d2ec0,b1e34161,ab8513f1,597e2b9c), -S(ef690072,4a54168b,eabd6285,8c85ed24,2a4c5b04,c4c419,f3586e2a,3ee2a463,49f17e53,7324d9ec,c7feff8e,2f3e437c,d0b01d79,d92189b7,9b35793b,b367fb28), -S(fe22736e,9be9865b,5c1f61c2,a236bdc4,ce37b650,9312cf44,8b536adf,5017f096,bd67d013,5ac42683,e83239de,93f3b7bd,f1d9da45,a7754bb5,f363f501,c3059e8a), -S(4ac35582,84269d4b,cd98bb27,a708700a,5df4e4e5,8fa93963,f6108432,2e0ba4b,91e43c02,ff39da29,289d4c66,6f58133a,5e7ebdd0,1593c7d0,833bc064,d75b876), -S(1bbfb3c,d5ab0755,96cbd99a,cdec6872,4c30a3ef,92162b30,9df08974,30d378d2,b0d34d68,1907625c,726aa90f,d363ca7a,711518c8,831724ab,bd24f082,9b71a9cb), -S(34417402,cc02a6af,129cd0a,d85f6a46,5367b90,baaef255,22622c04,ffa8e389,664ad84a,dc6e21b9,aa5cfc66,fcec0744,dc0e052,3571b1d7,7bc9bf86,f5233003), -S(5e6773cd,613df09,d818af9,cb13955c,f1159616,dc08482e,2737ef50,f3cc34a4,203fda8a,74f49604,b41226a5,40204452,3619c4fd,1c42c8e,1e4c8543,4ba2593e), -S(21f0fd84,1c01cbfd,9998d5be,f2d19830,6623598b,4c6dccd5,28d4f2b9,b0e0715e,ff00f77b,605f8e47,97ecfdfa,9ec4cde4,a9dc3479,3d571f4e,7f9f8bdf,e80b8707), -S(c1ac43d4,7fbdeb41,85536fd2,37aebc3e,b9faf3db,e2155814,e16f93e9,edfa131a,6785367a,1ead47c8,2d143984,c2de38ef,f3689414,14472eb6,8c1fec2c,2b4216ab), -S(c2fcf122,56b2e49d,36e880ba,16f27ec1,adf9779,82679dd5,4ae962ce,62f29057,580b1989,62da6793,9673a54d,41a45486,a80eae55,2de79bf7,9fb63d79,432ca48e), -S(92455df8,c253c53b,6dd44872,9c2c39ee,8f68b260,bb7511f4,b33a5c65,c756d016,c2258438,3f4d24e2,4bb0394f,b05e6a64,552b9e11,7c1b4ce7,a8c59669,b2244916), -S(7e953554,4a105bc9,77ddb025,8fe7f4d8,63142198,98c07b21,8d4c6696,314fa885,320addf1,d0f0021b,5bd67519,881777e6,2bf762a1,2430b17,2f67edf3,edb7acd4), -S(2d57c338,1abbb97a,bc9bdaf5,6ad542c4,4e3aa5a6,2f2da2a9,8c368eb3,506534e2,bc0e3a81,318ce176,c206eb31,cbffe043,8597eb9a,e2c505bc,2c21ec47,2fadfe51), -S(68ff7b53,b4e3dd0e,a24f4edb,c9fedd72,b904075,8ba87e0f,96cc6a1e,4d1d3e5a,7f3974cc,ad1b83dd,9d29847f,d61fb706,f47b1b19,a2993a6a,f885db9f,ff6a168d), -S(2e340edf,431b9efa,cd54eebf,22a4e79e,9ce9de59,b5e306e3,821ceab6,5b11f576,3a5ed040,679e77f,754ad7c5,5de92610,9c863dec,3fca56ea,85dfe104,af228f0b), -S(aee71663,94e2d18,353824d9,2558046,c15052cf,e3e317ac,baa142a,e503c712,6dd9272f,877f5aa1,88c43f4a,d63ecb63,7bce5836,b0b4efde,f980c2d9,778d7375), -S(cf33b265,604c4e51,40350795,baa4d4d4,baa1b136,1bcf63c5,29d5f7de,3ffab739,113390b3,abebded2,667e169,61da10d3,50a3cb23,e2c2aac0,7e72689e,f933b396), -S(367b235c,b5393994,9a034a1,ad476a0f,a3995777,5f933dfb,4493f518,f8ca0843,e5b1242d,c9341bf5,20e7a524,75587bdf,cd571cf0,bc85b390,aa6e4578,69c4c4ee), -S(b133aef6,30e9ff4f,59ce6ab,299eb6ed,ec1ec4d9,5e4e4c6,f37bae90,e80827cc,a9e4f652,cd9aa9f6,31c42224,ddd8c24a,d6f2c8ef,26102aa3,5585d90a,758cc5df), -S(5cc2d108,17007002,9a3a6158,fea4b6c8,3ebd500c,eda5e63b,55e287c6,36d48dad,dc988502,2c2cf16d,6c54d4cd,c5a8d7be,8396f9f0,e78564bd,7bf1f822,bc13540d), -S(2434c516,40c358ab,961964f,62741de3,373bed5a,1db16197,c79209ee,46838156,3376a3f1,8f4998d1,beb23159,143f505c,dd98a0ad,225e7e3c,cea17dec,7d8867b8), -S(5b115d9,e1997333,7f74ee7b,1ab9b177,5f9334c0,6f3815cb,b987619f,e4fc35f1,29afba83,76be4407,d06a8518,3ad236b9,7b967f2b,1ba1bc6,8bcf3a98,f1d36c18), -S(a4c7426d,8bc73763,a0ed12e9,2086bf9a,3f271e21,ca158feb,d6247cda,400ef88d,7beb9c9a,efd02fd4,57e4824e,1f24c058,ad367ab0,d1dac794,58f93031,8cde173), -S(f08ad354,3be27960,41315205,670378a8,9444f336,b1e62681,d1baeb26,f356ab51,24a5ef2a,21eda2af,4b567efe,3c339bc8,1c651b02,25e4fcff,612cbf8a,f17f3401), -S(9c649e1f,c78c4805,7cad2a42,fc8feb93,b93a5c8,a4e0fe3a,3d9c5931,e2e659c4,469afeb1,bf91db88,e49e4142,207cb5f6,1f601dbc,376a3918,77e2566e,eb5f9ac1), -S(5477d1fc,48669d0f,52a4f666,5b599a3,9671f30b,888a1edd,16c4a3ff,b35b0d7e,7fe541c1,b7859b99,528da7c7,ff50c02b,3698958a,b4e96576,684701a4,10b13e3d), -S(33dac142,9de66b17,60ca63c6,887ab053,f315e77a,42fa8091,42d24834,39792355,6fa0d16d,6213a2c,82026d06,57fa1c7c,8cdaa11e,4a92057e,845525d2,ab9401ad), -S(cb80339a,c6d42daa,cf7c1f6a,90074528,6861340d,a9cbf449,4accf827,15ef15a,3f0135a9,3d3d4fa6,80a4837d,e42c9e12,c28130cb,60b9866f,d5ca9f7,2ec484fa), -S(bd7b0bae,e55f28ae,4882cb87,a98c4fd7,bf2957c2,58cc22a7,9505be2d,5c071933,ae3be725,47e45dff,31f4e5b4,c1bfb425,551dbeb7,4d5ba887,376999bf,cc0dd376), -S(654dd97f,29655a8e,12ffd72a,76ca7a91,ae596e9e,2e2e6d05,48157b93,86ae65c6,a6a721c1,5714573e,8cf00d5e,5cdf8169,e363c5dd,fe6e76c0,c26a3dce,f267f031), -S(346dfb52,da33d501,d55d018,70c7603f,d70785ee,1e3029ed,4295ea6d,19d5523d,8728cf28,d307c488,c0acfc1b,53785bc,cfd84e3c,2340dac8,e84db9e7,6739cbdd), -S(4b22265d,70f13fd6,aac7059c,c7f3c363,7200338,28a20412,2168b772,330d73a9,965982ae,f3d121f1,12b4e1a3,a31ba940,ce702a77,1e743498,5ef4624e,ac13f9aa), -S(2336f680,86bccccc,679bc8d9,1c42bdbb,944300fa,fae9aa51,3a5245ca,5f0fcdbf,b0442c58,74e041e1,acf43400,7547ffd5,fc71d5ac,934fce04,65065e07,9b13d8c), -S(9566b5ab,2ca85589,565a2245,cbc04256,5b26b333,b089878a,393f464b,4405922a,2b6ce7e5,b22b9411,a46a012a,6745dd5,6ba35d7b,3304c686,50eeab44,d245886f), -S(e5722284,b8d280b3,a4ea8413,7cb6d8f5,e7107ed7,c1e46b4c,38adceea,8323d731,83492274,77d6d6e9,f19a2166,4fba0027,7c30529f,5025b6b0,6a10160b,bbf941f6), -S(4efc3d78,d30e4d41,e6d7e04f,d65c7f4d,abf51048,922ea858,ced39ac,ff7ba548,d3f3b5e2,3ab945a3,95ead15c,ea221d86,44bc737a,f894d374,f7379309,1f18f893), -S(268b193e,718e2c07,3cb4205a,c1dea8ac,f12b73da,fc17eaf5,b3dd7f74,f9492e16,6f1e00f7,35e4c6a9,a16b0a5e,5ba280e2,20760b4a,691caa82,d959c412,5fe739b), -S(d31e56df,6a0d1e5a,f6ba93d,63a02d6e,a91a6008,8cc6a7b1,ef6240bb,83ca59ea,3693fa09,ac433b64,424162ae,bff3e0ce,b926c036,37266c07,ab6590e5,b269913e), -S(c5103c0d,6b6995f2,94e1418a,21492951,caeb4adf,edadf140,4481e674,247c54eb,7832f84c,f94d55a5,ee865d46,605e708f,a4ed1879,a1bbea67,d01140,e3aca110), -S(f95cdafa,b5578ef8,6f37e978,476c08c6,6e3167ab,73a802b4,a24d855f,39b7e9be,77ae964e,d8a3b05b,8f8a7005,1cc20b99,71a4d78,74dc40a0,e2cab2a9,c662d445), -S(b4b9e827,faacdf2f,6503b903,171fdef2,7398c819,3776d2ca,7d1b4268,e65afbea,c0143786,244ec5e5,a166996e,194dfb2f,54152030,e1bf2fd5,2d33fc43,7f955ca6), -S(9169df6c,e6c940af,8dd672f4,5babdb0e,332b8082,f06ea004,1555b1bf,d269a328,be066e6c,26a18e22,8de12272,a374d17a,307708c0,f05f5846,3ba9a55d,dcede1d3), -S(4ebeebd7,c1b60e42,d40be032,570beb3c,6671ccf5,b7f1f10a,b094da51,7dfb6971,8b8d6022,5b57789d,c91f02ec,81e25d4d,69d85c88,809f202d,2a998460,95361653), -S(8e96e051,f8d7bee2,30209f26,ebbe1f74,1db4bb35,363dcd1b,bc33ffc2,b7c0869b,ccde36d4,c67f2f29,5241fcd9,a85f2e18,c322def8,dd785c2b,232e1da0,3c9dd27d), -S(61b8b1f1,d92213e1,38673287,79bcd83,7f06b24c,331e5dfd,76d91df4,54d6a42,93b65197,a22442e4,5ee12c2c,345afe10,aaefd03a,ad45dc32,98fcf810,914d0d47), -S(3e94ab30,2d01ac20,9b0e8e4a,d7329066,ab3a32c6,b0d8160d,9e2a7b64,8b625563,85ee61a8,643d08b0,a5eb2f82,7ef70bbb,99ca044c,af4338ba,24774e81,b6fecf4c), -S(dc4ae75d,78831a0d,ac87cab5,7c6fed74,500cf2e4,1fdb8afe,7f95e81e,730b9b5b,5daa7147,1fd50e65,9a9845d2,9535f0eb,55f787c9,ac1b595e,da2fb170,b59f17f7), -S(b56007de,d2b04196,b5398832,df12ec62,7d4b188d,beb5f09e,a3cf87c,c414f252,88d29752,eec1e71f,3c72609d,f5a60e31,f485262,b87d575e,83d9070f,b72c0ae0), -S(5d5389c,741446c,1cb8ddcd,48c67a41,580dcf2e,93257012,97a8b8bc,fd20d4d,e79b258a,57ebb0fb,26f08771,d63cc6b7,6d1cf981,124cb3da,28405aa,9217c698), -S(13037858,1413a8e0,9460dd66,18cc50da,f8e93b44,f0c0245d,58950892,1d61c1ff,5374f786,906892b,77d3cac9,df04a393,f17824b3,8a9a8b47,c5adc73,2a7fa51c), -S(d20a183b,1e003892,f65937ab,a19153a9,5c637bd1,8fb1fa93,4d258555,36e334d,c1a3efc7,c1b2c14c,6176dc68,9ecc273c,fc7250bf,d059ab0,fcb068e2,7cb70741), -S(585aee85,4d5fce99,fa00d575,6922e529,abf77d52,3322bb68,7e7d3cec,b28109b,e7f5ea62,cd4e12e3,c2b43ddd,a1f7638,ebd5a2bc,362b087b,6839b13c,ebfc5cfe), -S(1b20bed,29cc0082,5a6fa7f,d1c8fdbe,13cc853f,f240129f,16df04e9,a04e1f1e,daeb1a97,17f5bf42,4972b4b9,ede42db4,7fd36247,173c0e5,b53a6994,8ab01980), -S(c9a9e323,c531bebd,84548b4f,ffe78967,a08b6399,67788ff0,4953a1e8,8c7febeb,d64b4ed8,eda75c40,66c26902,944d2744,503f6017,b8e80940,55adcc7e,b34306ab), -S(6c551219,2ecadfca,bd79055e,d4e45f98,ab4f3a96,15e3b7ce,138f6266,d0ff245d,56aa876d,efa4593d,d1140d14,19f5465c,8a826859,af6a3eef,e2013c60,330df086), -S(e242ab32,5fc71bde,da7da19,686cb1f7,93f38e81,fbb555be,db874200,8ce81571,c56f2ed3,20f7827,cbe76177,e61486b4,cf15a555,816ca48,3a72867f,f27c4ef9), -S(7ab15e09,4b5af61e,3f5b7397,f89f1711,e3c55005,1202b76e,b351cb1d,91998741,27856f9,a77ad2fb,adfd70c5,7099d4b5,8b162f6b,daa3f3e,59f312d4,d46535af), -S(e55d8d3,77e84b5f,626cc6f6,7d1d0a62,44c72dd3,78206816,35c30d95,f7541cad,e78f840c,f8056853,3824602c,3f7aaacd,2de98757,2edda9ae,37da985b,60e1b690), -S(e9a09a03,9b0a0130,f0b8667c,6d7abca4,b3e5c143,d0126565,1fca6216,c2128771,4207a863,dc05cef4,6bc6bb9c,975485f,7c9f876f,3bce673f,f160d714,bc151e90), -S(e2bfd72f,f1af92f9,33ebd08b,d6b70cb6,c1346895,9a0bed0d,7cdae7e1,65135325,afca8d06,74918152,56a53af,b0dab50,91752e09,b44fdb4,cdce07c4,89b00045), -S(656da8b6,83b95ef1,e20bc36d,e64f4dab,7c1ed8b9,261548e0,93e75d5d,525b1bfe,d12b0be8,d382a555,a71143e1,cd0942ad,9f97e771,90bd6a24,5f473204,5d867bad), -S(e5e3168c,51734cb9,c08d9035,d592b821,a6a479b7,61000156,974a8eea,2f2bb902,63661750,8782dc9c,d4271732,68661c76,d2b8bbfd,9d49c7c3,88df9360,e6ea1fba), -S(6676fa5,dbcbc713,920d915a,13d01972,82457d37,514492,f90798f1,dfbffaa1,3005bd04,4d06ff3e,4f06310b,2927b621,2a82becf,5111a825,dadd6e13,bc3fbb66), -S(4f89f4f,523a53c9,ee9571ec,33bd8768,2f620c7c,8257a844,355d87bb,7f6f0d48,131e3f25,cfc2881d,833bfb59,d917d7ea,af2a7336,ee8944e8,6c4a48d5,10d9254b), -S(9f541512,a0f7a48e,a37bdb58,dfd9e627,e775e862,5b8552df,88e5f595,c68cc80c,a8b36ed1,2ae8c2ec,fbea6d33,6903522d,714ce9,3792759e,678f4643,f880b461), -S(777387eb,9e9c70ba,dc94b9c8,f0fb411,ea6017c4,faec6aff,f6d04105,c031e4cf,6bf663b7,ddfbcb36,f833320f,7098c928,22f9b993,3de32c0b,be60b66d,61f94795), -S(b27524e2,ec594848,fc757dc7,762c6396,9938d53,4f90a0bc,78178192,e9bd94e4,f8c944cb,dfe215c,32886c9d,1149dccf,c05a78da,ab759161,22182569,a5858454), -S(c67fb320,4716820b,37dfc400,cf2e934f,4080c4b3,b092d261,b2bb88a4,5136fa41,a3f61aa1,ccd741c,f36e4b6b,1a05896f,3805089a,26961cae,ffd2f70c,b0b2df3b), -S(f4ec97c8,d8a5af0e,d8d71cf9,5450aef6,66a29847,e395d60,7c17e50,68ea9be4,4376c5ae,10e31637,7b1d3ad4,6d224dca,8a83cdc,4e78a9e1,1286b4d6,2c39495f), -S(101fb524,eac89b59,10337c27,48673b30,e24fe7c4,f9beaf75,69861984,d14243b8,d56cb44,6d9d050b,69b986b5,adc3a710,774698b8,72236af7,d4758d29,dafb1fc0), -S(3baa0ce7,feffb71e,31c935b6,ed2018d1,e2a1a694,963f0878,354d2826,17008749,c010829e,aba91b9c,ea31b88e,aa90fef9,3059bc35,aa2c11d6,4cbbf40d,bed2271), -S(3be18f6d,9c8609d5,8b595b57,1ec6084c,650ef42b,9511e1c8,8c879aa3,ad70c65e,84182bf8,9db24dd2,46eea18,639b98ec,b62f8b93,5ce1df3b,f71d93fd,ee3c031b), -S(4249cb66,d532dcd,406767d2,7af9e7e6,2a7e46d2,4a140a4,b01b155f,5712f3a1,e4b5a468,f71ed053,a060130d,e40662de,fa3a87c8,509dffc7,83c7b2de,93c89817), -S(75688f6a,8599ef01,1c89b06c,132dd184,b4485af6,b3410f20,fc2368a0,1df9fae5,830648be,b36c9c8a,8ccd1096,3f2da3e9,e4f03d0a,75b13325,80601da2,3d572a05), -S(c0b7cfea,412fff9e,92e31b33,7e133041,c81946c5,603a3ec4,3f92fbda,bb56f8b8,63a13e2d,9a06506d,dc65bc20,67afbed0,ef0cf722,e75c17e9,14c0ac03,d50ec0e0), -S(777f64d1,c65275fd,6b266e39,5a0eaf3e,df51bf38,336f6651,1140f475,dfed8bfe,d75139e9,ac863e6a,35b495f7,6ca5c554,21fe88af,24cae574,95456046,503f4286), -S(3e7e7c7c,c7cf5612,f44c42bc,51f3243b,20bf280a,8b75e7ea,e52ce30e,2fd80657,e64e815c,fbb6f263,eeb0a21,8fdff95b,19eb8cad,f3d582b8,8847b7ea,7b9460f3), -S(8795ef69,b029ff93,5e9e0e84,5490ebcf,18728b6d,f25152e8,d315292b,d834cc69,86b984af,49c56711,20630233,f30bc4b5,e460ca18,8e4a86cf,5d5badbc,bfed2e3b), -S(f5b01cfd,59a22134,85fa7eb4,d9a7def6,d16b258f,2bdf581e,e22c28be,9dd8ac3f,95696481,42941826,38a4da0b,57f393d7,65e3a9bf,dab06592,87905d1f,5323109e), -S(9453d039,9e8dfc00,763b254f,905acd5d,60b109db,6830d8a,f062f339,a38f553f,59293f71,ea51b918,334593e9,3dedf34d,9dd0c453,2b5c9b35,edf046d9,5137f38e), -S(40011ac,573a375d,7815fb09,8bfab10,89cfd5fe,7fa87734,c257a9a8,9acbe65f,40f2e596,436bfd24,bd88bf33,1e711828,56478565,93e0250a,d7b87b6b,72b5af13), -S(7e0cdca5,50430cc,404cc9e4,e60bcbdd,6611c175,1cf50670,fe19271a,4db4aedf,812709e0,1e5f03f0,dd94e208,992db41c,4bbe8cdc,fe0f0e0d,bcdcd77b,d95cff63), -S(9c60fd1d,675457f6,4fb43af1,3f25173c,f64833b1,48867172,5e1f76e7,3e3f0da5,11d7e0b9,41c428c6,c0fcd00c,fdc4e252,1084a6f7,ae780845,bafafdd3,30a21e24), -S(7251e853,65bccdd8,a493ef77,f22c347c,964b0827,20c84195,5bd367a0,c2eeb752,8df2d302,e0f90ae1,68e84163,d4081a9,b93d0421,52a45bb0,17635904,8efa67f0), -S(da466345,6e03c943,972bfbb1,5b2cd45c,83fde8b1,e22371ae,8c248431,151a6198,6659dead,d0e6dc6c,15721fa8,c00b1aab,6676fd3f,c5f6a834,9ddb4114,b5c45e18), -S(666b5d13,8d5b8169,256009fd,ab4911db,2ac9ea0c,ea7b707c,60196819,6a2dc816,d7486d1c,d50eb54d,22be8156,caa92197,3614604a,1a5c72a3,836d362a,d0973fe8), -S(48f24f6f,e112c070,21c45eb4,59f5624e,e65de1f,ea3638aa,b8b849e6,175805e4,5d2df55d,bce84e37,1a13d26e,f04f3a99,38a9dc58,c78c6c18,4e72aa8e,2ce03287), -S(3518acd8,23ac4b6f,d50f8691,90d14f76,ba22bdb,8e0c5e49,8949468a,30eb3230,e3c92847,a0fe393e,83e101ec,f1b45ba,763c725b,684811db,d2ae402d,a31a7467), -S(105b1aeb,5c85edd9,ad72a0af,cd04ed48,feb975ec,62ef031d,9b0bc668,795b717e,dfb18689,75b80da7,110cc6c5,c845e9d6,6b8358a6,2382825c,2e6c914f,54b473ff), -S(f156d5c7,f15e5276,a9f673df,590b93e8,348407e7,9f6c096c,73b658a0,a630ee70,9d9bc235,b54fc94a,4d34c33c,fa843c,1c67a074,c679b0da,64b44358,14ab5fd3), -S(eedbc38d,d0da0095,a1df4b97,2add48af,a97f2e92,bce8bf67,5ff3c134,73e5c3ac,116d4b18,5a00d9a6,b858d82a,39192f4a,a4e6f305,b2d695b2,e054557f,b895ae0a), -S(14b54fd2,cf799482,ce31b76f,474055c4,60647893,d6b46894,15676c32,3a413a18,5c700720,c08b7a19,7672fbfc,cc7b5223,6b0664dd,f9fd3df5,aaf66e88,f50824b), -S(ede2af57,9ebec635,d93ccd2,1fa74e69,d8bcb14f,d82ef9a3,570bde8,3f6e7f3,e5b817e2,3af1ee7a,38a3cd2e,41b2cf98,c2d4356f,c40dec19,b899d219,e01f9121), -S(6aeec3f4,90b048a2,cf210738,f14d7324,5ff190ae,72234576,e825f5e9,20641002,acd9b1cb,1fd56468,6da61382,cf9d66e4,1fa00c16,d886c9fe,9aee6d13,d1812054), -S(a0df5ad4,8b909123,e0de90b0,669fcfc6,f0e10d0c,28746ac,a260ce19,a678c8e6,3897d22b,fb2ebbd3,e87d6948,cfbaebee,95adda8d,f0654dac,d409dd51,669c7eb9), -S(d924dce5,a68819c,6e840326,5ec20b56,553d596e,78020430,5ffa6d5,736f5317,fa262ae2,f1be924a,18a41181,f417d16e,9013d50,c56a5eec,47244a3a,fe69122d), -S(98add9e1,45dc7541,4271c971,4d6219e5,436e479b,998a4b6c,36ca3a6c,90645ca9,34997501,ea07f7b4,2aa4b6b0,7387104b,4f20c0c9,dc1dc82a,8c2ba093,900741b1), -S(c42f3e37,2cc9cf46,3d76c4bd,e29481af,dddf3040,340baa94,6bf84220,7f9a70bb,5a1ec58,e4038781,3e9ca00e,9c53358f,7d777fcd,4f18b5f0,dd81b9c2,3bb3a059), -S(e940c5e4,1931a103,a4feef73,7e95a12f,346c3855,7a3a7ff5,dec89ffa,ec1c3ffa,5556a9de,d0a5e7be,5440ab2e,3850f718,438ab153,aae411e9,c31d1012,15705dbb), -S(35b105f5,7ababd24,19f00161,262a6a8d,2738239d,418f8f68,8c57fdc1,c8b3afc4,97e93b99,7664d080,f9236d16,38fb8457,28f812ca,9b0d47d0,545058e5,513b722d), -S(15ddbc98,b22840aa,bf698e42,3eabfb3,8f32af95,2969eb06,c24c9901,8b9428a9,33404fd3,2ef62c0,db440774,7fa7f70f,d681c4d5,e042c48b,1c7918b7,75f13514), -S(a00a5eab,1517bcbf,d377402c,d2721d3c,f493d100,3602e251,8882d426,fa69ebab,68f8d86,2708fcea,4022308c,2e391f76,9cd4e128,495aab01,dcb63473,4334760d), -S(7350c15b,8afddef1,4c173893,bf5892f1,6047769a,278c85cf,20ddcc91,125a632f,3bb33254,e5ab2964,f6f401b5,685ae429,7a33b887,99fc9861,75da7e3a,7abcaf51), -S(7d92d2f0,981424aa,6d651cd3,fc1cf104,2f24e71a,29cf49dc,c4aead32,2771f6df,f4f49d9f,f1905e01,f8de9679,b1bec436,ec0bd68b,b24e8041,89d369e,e1a46e5c), -S(2c10719d,6122c4be,8f1ccdd6,d520211d,aceb2e9d,fbba02d5,6c0fb1a8,5b3a44f4,558fb689,90788971,2e5fdb,7bf12431,3ca1e6a7,e8117d3b,8e53ee5e,b7162eb0), -S(5b271fe6,10767158,ef07e835,54e5cb7c,d39fec5a,defb93ae,122bf5f2,44758a61,d82aae85,70af5248,f1e4b784,26a491a2,d5c33c22,c65165af,de42b288,60f097e0), -S(1c3bfc2b,cac4ef22,9f946221,6f03fbb,b2d27e25,9c2e1cd5,c410db50,74be14f5,f3ee7b94,e8c24dfe,abd78d0d,737b89e,962cca9b,8fd47978,c6573e51,2811b857), -S(d43a0bc4,638e36db,c0068609,b7f761de,44303303,de7189f7,99bf611b,dfa1b233,f8877c1f,6ccb955,6e9b182,379600d6,db4bd0e3,83c76dd,42941e24,bf8fe041), -S(2e4d8eed,3e9d1d99,2f08882b,348fff52,913c9a6c,177bc71c,236d92c7,6634dea3,1e994080,635d8ef7,a6401aad,679ad721,56b81cf8,7959935c,dea463d0,b74e96ca), -S(4cdba5c9,d5fe043b,c99da326,9cd6248f,3ecde544,cf617a5,b8c73e47,cf539c92,2527e4b3,ad0bf862,f94b567a,21020d72,92def1d,8e19211a,35f78ad9,dbf72269), -S(477033f6,5abb16a1,7e4b80da,f81537ea,eb39891,d8a2f0a1,5577b1f,999a6473,c986f8d1,3b17239b,e64224e1,b0316573,18c536d7,b00d6f2e,a462848a,389c47e2), -S(2cd55c4e,e05a9e18,9ae326d8,741db193,eeb4b356,78334c1a,48453f56,4452cb72,d9186792,86ede279,dc4fa812,9bfdc308,b887bed3,1b9b4512,1b15c552,ce4f89d6), -S(c2efc599,bf13c184,7906d679,16182ff9,d98cc345,d306975b,a5285330,75925f94,9e6fcff2,981370d,4f4ee530,ab1ecc8d,4f807572,bbdeb533,6157a096,613f267c), -S(4804058a,88482ff1,bc0c27dd,31f53072,f166b89,abfec728,ac77b832,ce24387,ed62ddb0,9c4ad5e8,473c443d,ee624287,e85398a8,dc08ddb2,8ad5b4f5,4e0b990), -S(6c3264eb,7f4d3f1e,5c0c614c,cd8f77ee,a23f77c8,a22d6679,467269e6,a13353f0,158750fe,28339ea1,ccdd2147,466824e0,9c44df45,21b2b47f,540d4f9d,9b57c2a0), -S(5a2e10de,52c3e589,4f7e9807,cb5d75c6,7b8fb61b,6c161f18,661b7bc7,486f1f5,dc191e64,c33a0aa4,7a771ca8,8aec0c33,8ffde81e,3b8025dd,61314acb,e11b4739), -S(57c4ac9a,c559aeab,da34371d,c0088bce,768cc4d1,6423c8f4,daa3ecba,571e79df,5beef57b,97435345,db22f84a,36b0f1c6,7d42b246,32336304,f1f4cc6b,325f7028), -S(46b350d8,326546e9,93e85952,f4fa1b5e,4ff93d4b,2afaa5a1,5ceb2e66,fcc12665,852b0e65,a3864018,62f9bbb7,f284b4b7,e04ddcf1,dafdc616,5b7d2303,395531db), -S(66556fbc,632cd7fc,e3a8d768,b96de7ab,fcd0a7e4,e3db320b,19e9d971,97326d46,45275512,50aede32,9b6713ef,eada1372,69465b72,cc720404,aaad34b6,fcc5c2b6), -S(24e2b12a,798506aa,68b50881,1c555a5d,80984736,5a4e6f7f,b27c863f,8cbd2bb0,fb9aa79c,d205955d,4e9da24f,4798f930,2933fe7e,1cc01024,c08c9fbd,7fdae7d), -S(fb51fa7e,c8d846f1,fde26c,6c14c479,38059646,aead5a8b,7bbb05e1,a5bc12fb,6ca2fac0,20cf7c16,d360d37f,eea72322,edf5b824,3cc3daa7,f0e91a81,dc2f7aef), -S(4613ed89,ffb65026,f0481095,553fd5af,929a13c8,4013bf28,9005aca4,e8e0dc94,ba837762,a2e6c17,4cd4912f,3662991a,ec910c29,8033122b,63396def,5de2cebd), -S(222473ff,f87dfc87,403467bf,9b0f12f4,2014772a,68457462,401933,f6192499,58aab7bd,8e58d310,1849b3fd,96a2b6db,8eab6ac3,d29f9ddb,d2866980,14774839), -S(5e751a2f,988fab02,b974604,b4177076,81dc7332,a2d268a0,4586f231,300552bd,2d466152,4180a713,f6b40571,29bef9b7,bcbc0372,aefb4b07,8707725a,f31d029f), -S(3c94835,bf940014,e0c589b,3df40cc,a53c20e4,f0aab085,d8a79c26,fdb95b24,4cc1349e,212b1111,50ff06b6,927d701,9387e4d9,4d6bc1c,aa0ba14e,57f97414), -S(9fb3ea60,26b6b1d2,d56e6caf,19fea2d9,a2386ed6,65aceeed,aa66c5dc,f8fb51c2,8f90ecc0,87c300e9,3df10082,a3e461af,88bc0746,41e0a85e,4981988c,c539d096), -S(49c1f091,dc031e1f,a14b5417,3831ad26,438e85fc,407faaad,c634a0c3,8d956cf5,6656b7ba,7a5658dd,a78ae1de,74944332,22c36abc,d7272146,80a64a8f,1135e455), -S(eea69d66,68446656,45231f81,f27dff32,83667f37,4dccc3be,5bf12a42,c446e112,821403bc,f618e100,42c45de2,3262f7f9,b23dfda9,9a5532a7,fc6aef36,868eeefb), -S(c251be6c,5c73933d,90bb741b,e87c8b27,909b9efb,b40c70c2,3b1b5db1,956518b3,68f543dc,872f7f37,b8ece85f,acf3c670,bb2e6f00,7df413b0,5416919b,57aeb60c), -S(b1ef747a,4df39c35,4e67f27f,97b150e8,6e138cdd,70846ca7,3479819d,98cf4cd6,7afefc25,a30d6879,45f2b471,20b50b83,eb58b682,b61dc4bc,72c4e368,4f3c01ac), -S(9cb0d6c5,2094f1e6,ff84549e,32ba4260,a93baf84,cbb9516c,68c25c6,4b67feac,3e8e7ebc,1958e60b,cb4159,16f7c903,d63effeb,4955a11f,cb470ff2,e8935665), -S(d11f3d4d,6b18bc42,1692b7be,40589b49,b909ff2d,5659a058,4bf3af1a,7be76be8,cb42df3b,630010d9,fb48f12,e7ab607d,6fa1f829,1543b68b,5e959478,ffb6a8ba), -S(ff6a9171,de273646,9d0c0b0c,5e7829c9,3aaa1ac7,e63a63a5,fa2788b9,888025fb,335b0b06,411d6e6d,7c6d69e8,4a900f80,5077bc7a,248f2d24,2df2c517,a9bc0cc6), -S(655dd8ac,aa0cc2d4,b9543d3a,1c0baaf2,a76f7b41,caba22e7,47c1976c,deb15707,a726eb12,44c2af81,d6b5abaa,c9c117ac,75f2f6c5,c550915f,e005da5c,efcf746f), -S(4ade0988,d4c2b0c8,e303dc20,88a86aef,b2893fc1,80c410bf,d9467bee,a785e3c7,7c2358bc,74de92a5,18d38766,d13d5d4c,2a0d551f,62996105,bc59024b,147406ce), -S(9430a2f7,6f2bd12f,54d885be,3172f512,5282e84b,ab5c6bf6,7120a6bc,1e070db1,e8087617,943aa433,55684564,53d91a84,4a06fdf4,6a587c14,a2695c54,ccc3894c), -S(72b9e511,c78cc26e,f9498e38,9a15ebde,cad6bb3d,ab08462f,f6f19966,d75ae882,3a8345d9,1a0b1a37,405ea7ec,cc427785,607b84d9,d64adb42,5cda786a,fc68fb33), -S(4615999e,29a4f947,83617d0e,2847ad26,f79bca3,b3cdf3e,6a40e6af,f778fd65,5146f8c6,85b10eb,abf0ee65,145d468e,ed4ce176,705b3ee2,cf8e2f66,d3c739f7), -S(bdcee951,41a500c4,8452f5e1,3833dca2,45f94f83,80ee6574,7197610c,5ccb4558,479b3308,fd9ae072,9f97d0ba,622bfd1f,71c30774,c9be1bc7,b6141278,3e649631), -S(8a52a750,7dfa334a,1e285c5d,8c4d6963,5c3f78a4,79cdde18,d057d0ff,9bed97c,d4f40b1b,dadec733,5c264caf,e8c6d0cc,6f7d40d2,6a5d56d8,6a86b392,97f10477), -S(69387f5e,1d2b3fed,1b033614,25486ad,6ecfd3f6,eb85d8e,fc272adf,6d154915,8a72e294,2be10088,f16b74b7,4327ac02,1aea149,84a25458,55edef5,2e5404db), -S(7a8b4d6,982cdce4,c066b721,ca2730aa,5705a43c,84ce54ec,cd184ea5,53bc1099,f4460a0f,62bacaef,67238243,ee850509,d346752c,4a93f59a,5939daab,a654e215), -S(7a32ba53,a2f6c968,56adb025,10d9036,27e945c7,51108465,c88b42ff,e96442a2,213af901,378b30a2,5272dbf8,9b847fa8,32e3657c,1e5af5f3,d49ddb88,f7c9d701), -S(97388117,9d476881,84a6c968,e96316dd,4933780c,1c5b55ad,78c0de2e,aafaca0c,ab2d23f2,13ec96fc,856e6dd6,c73d10b7,5a0e1c5b,b901ecb3,79dc7544,5dcbc672), -S(500491bb,8e971056,380ba6f1,a02b619e,763aaf4a,bd07f9cf,50f86dba,61833354,ad296ee5,b4c32ef9,728c1924,562c0fac,9360a6d0,16f2651e,16f4c49e,ab35e600), -S(1c9c2015,bd266fdc,fa123aea,45428d07,eebbadb5,2fa10d83,7b4a831b,4ff086f9,73b714a5,71eba339,c58d8449,4637092e,9d44ce29,cf039427,de75b540,97916fe8), -S(5a4361bf,44a082c4,4e87d4c3,4173c910,8a3ece47,ccf3d3de,f933e9c2,fe649df7,184372c2,fe0b659d,57ee278c,f3aaa9f9,c6f3e45f,28c8ffad,54730dea,4df0bc95), -S(f6ed8161,c49f7ac4,931d90f8,fe41a400,367d8ab0,ec23b0c5,74886906,86f11eda,6c24c798,f1d88a2a,e2c7b32b,867e930a,41f425b1,ba59b01b,f971306b,a0b6093f), -S(ba392129,6be5773e,a8b509a,408b556c,deb7953d,a5165db8,d52516d5,36cfcf01,4cf094a4,9c06691,bd11a7d1,864ca452,29e91f2a,60b1cf0d,d9bf1162,901cd89b), -S(eb96dc04,ea36d6a,43823477,d4b6e3d4,a89da427,7d959962,3f31afac,49159203,17ce0e2d,6fdf1ec7,3808ff72,aa9d1fba,5038b698,c3f72214,9db254d0,98b714f0), -S(5ee66f18,669dc60d,a3c7074d,c853c51,21f6c584,bfe5c2d0,949d73a3,24714f52,238d8d46,f4143d4c,e7c74edc,78d1fab0,a42e7593,7c340504,e259dedf,4b462433), -S(71979eda,cc7fa635,91767e7a,57f8a1ff,eed003db,8083c41c,ed252c52,438b1e11,94e75e9d,4f3bf3ce,5ed2e8ef,9056d3ad,bdc9f9d2,4e51edbc,9f2b2bb5,90077c18), -S(7a301d3c,f6f6407d,8e62d5c2,4afb8ddf,744c2bc8,d2d219d2,8d912585,51c23351,3578a307,3dd4766f,319d6a8b,190b8a8c,a85ea7ed,1c54918f,73293b5b,5964652e), -S(8b76e056,31f5ec6e,33cc1267,9b49d9b1,16e8e06e,b3ebf91a,a3f239e9,8b188c42,9f0f4f92,a43cdc9f,f1d5b031,44586266,9b65d7dd,707de8d6,23dd8fa4,62c2d96f), -S(7de9be01,b8ee5708,9fa0dbfd,69757649,4d9d2eae,756bb9a5,f9deedfb,d55a6019,8947c62a,fd4a1e7e,dd70af94,f09aa2ac,aa1c43ac,745cd75f,dd1618fd,49251a4d), -S(d0766e37,769689c2,b55a3839,968e1eca,58824760,716c100a,29746728,4f6254c6,fe00274c,f3274a8a,8c529570,8b122d9c,a226fe8a,843920e8,a17f5468,ee2b0870), -S(61e74942,91821765,e144ef34,37c24dfa,80857029,35fdb2b1,511eebc0,324e9523,a641a75d,8917abc1,fb36b5c3,beaa84d0,b4230817,2337f50d,78b71b52,f4373524), -S(a726ab19,5125f8ec,e8cd1952,2facdfa6,2994c4d0,712251a9,8efd73cc,213773bc,2064d5d0,ee2b5cb4,5567701e,a3015c35,f3718700,af2aee6a,22202325,1fe65afb)}, -{S(64850a04,76870a44,2cfa57e0,4e4707f7,eccc5e99,12dbcb07,3b457317,717f5686,7c5facd2,91a6defb,a1837cb9,3bcbd0f5,bc37572e,68ccb2a0,c062a155,46656fcc), -S(fc479625,fda0067e,a75631e9,c79999b6,dbcaf7b,e1b69d64,a75b08aa,f3ac871b,d550323e,54200c9c,393139aa,b8bf3526,45520bf0,d90f6ed1,5187682a,79515de3), -S(a39b8f47,efba84d7,1b781439,f8c144fc,9b637215,26aa6b68,b55d6a59,137dc291,56c6dc,511a8494,b86f9669,504985ef,e88789b2,83e58916,24b9455b,d656cd39), -S(172d5d5,21edbd11,beb288d3,4ee78e86,a1059bb0,5d781bd6,d9589f23,46eb7833,5251dd9,10553e2,d1476e70,c6d2cfc2,397ea7f1,210e54df,d2f61425,60bfe73f), -S(e5f972b2,d1723e8,8bc6ca8b,ed3ec1a6,fce0e6ec,fb13cb86,efd61e13,24d4c41f,2e072ff7,ea3c48c,8653c0c6,595c2c27,d7953185,4e3e1b6c,8c1e7cd3,bdbf9ca), -S(f586c6c5,44cb108c,edd7cb15,6ea36607,d411d162,730170da,51ba1c39,a1e33241,dd5425c4,3f49fcc3,c92753bd,dbfc4de7,f7ad4511,f8b720fe,b07449d8,8919888e), -S(e324072c,8d3b5516,1c32264c,e2287b41,eb8edab8,356250d,b958c37e,555de216,4bb37975,35b72127,6ef1e62d,82608300,9c04b2b7,24655acb,c2d3a06c,ac55e7cc), -S(1b76872f,cf8f2297,ed95552b,17bba313,5dafb896,7f2a7229,faf4a4af,fd416fa6,8c389799,32b146ef,87aff36e,4d6e1891,a2acf7ab,2f362302,d13e34cd,7a34adaa), -S(797e7051,903abbe1,9735f94e,acdefaec,2f2c8c60,13a6ebb,d06a4234,14820bf2,ffbf5cd4,19e47bda,cf59491e,55d3a3dd,97d35b8c,1b824c79,955ff91c,81269563), -S(e3e22849,a67edc06,10662641,d5975a4,ce59650f,e9ced88d,4865d63f,e0ad948d,551b701f,fadbb47e,ad4ad324,ebb01c12,c5ba2ab3,754c9762,cc840bd5,569897b0), -S(50e49072,aa2ff6ed,2c8705af,1ef1b703,903194f0,2c91c0c6,5fdd46e1,2a01e887,b55bdda1,e98db862,6a283c64,e1e813b2,20e26556,921eb4bb,b72894c9,27be1c7a), -S(d1b0abc1,e1164bc5,277353b9,84856cb9,1c55735d,9d475ae8,8cc743ad,b0462739,cf712d30,edf88915,373be307,e1f7e73a,244a8610,e7c6718d,112cc414,4058bda6), -S(62fecfbb,c1532096,583a588e,cd7b390a,7fae6e93,a675d14b,4bc99ba2,546d5573,ccdd7145,780cfa94,7e4f20e6,1729ec09,6ba6d28c,c2a53ca0,65d060f6,1fd9028a), -S(192e0299,75cab01a,5f5a8428,ca2c283e,1b300925,ceac8290,1e134c8f,97698d79,55f467bd,8d0db18f,cb4c8b72,2784ee99,8127067e,bd1314a4,22c063a,4755b817), -S(eb5a94ca,29e28ddb,11907c63,fbf8fee4,e1677ab7,205c5539,b0b3675b,f5fb9b8,6e9bb010,1fdb591c,c65702b2,cbb16061,cc7b8698,bb693c28,e09e853a,fc00ca), -S(4cff025b,579f9c57,c78bff07,115b7268,39a20ce8,f893e5b7,eeb310a9,c738c67b,d1531ff1,a839c908,97afac4,256b35f8,5bb31903,3e8f8e69,b2a9c13a,ff6be9c2), -S(bb5f423c,77da9a2b,540812b0,1e899dd4,a100bf59,46bd9818,ed4c2e6f,103be9ba,d4851c37,afaf40d6,68de6a6c,3a1d9209,f0fdcd0e,98310455,61210c7f,a1a797dc), -S(86066254,59e38927,b90d60b2,f9594e27,5e509366,f5678d35,133bb9a1,ad4b3262,40900453,bd36c557,10f5c8ac,492186fc,f5caa74d,12c69b2b,c28dad4,9e83e690), -S(81d52fd2,14f2d1dc,c386ab9e,5fdfa5e2,99d57284,7f55917f,4468bec3,812cd638,8b131ad8,2f24d27b,87e73419,bdd9d41d,795b9466,9268a11d,c8b87e01,7665f2fd), -S(7cbb1f2f,47f57e0d,20be44ab,2427feb6,18bc6b82,6e5f4909,51e1927b,bc596ccc,bb587bfa,d416ef29,aa36ff38,1f448f46,fb2fc0d0,a87e5170,8313715f,30cf3d25), -S(3c6e6b89,2e897388,157d3565,95ad59b4,334394ac,b33a3a24,7c455d90,a4dff784,b79d7d85,2b62e00c,c340cb8a,d42b489a,bc372022,75563918,fc9b81b2,a1b58b14), -S(dcad5a44,4c6ed0ba,2206a2ac,92e2f0ea,6c5fdf7f,28dc6bd4,7a6a48b1,d32d7e2c,6300d599,63fb36c8,f0d3109d,161ba1d2,9f718697,6694a11a,63377075,b944ba19), -S(c8515e28,b0f7d1cf,6e3829f,8d0d43d1,cb382299,1f781962,b265b268,c09a0aee,f33e0699,9385890,5520fcd8,f06123bd,3429dbdd,cdad22f5,3e80d951,b620c70b), -S(d1f81565,ebea70fc,6ee132b3,79e11725,4e4f84ad,50e04282,ec23afb0,8e24ab,38bfa250,6628029b,721a11a2,4af41f28,7a4f20d6,87a3c4c3,815deffd,bea92642), -S(79c02a3d,93cbfd75,2dc01fd8,a4d83626,2505eb13,92f4800,965086e1,51cea673,aeb43c57,458510ef,202aa9f2,b904fb34,6350d4cd,ae8faa3,d246feee,8da21571), -S(b476ddcc,6a6f785,b1b8637a,a22b1984,30574567,1bce6b36,ed3738d1,8c1c5f88,e71abebf,e2019b3e,99b27560,d4ea4ef0,6d52d300,14c462b8,1daa5a77,3ba73176), -S(937b753c,2d7cd681,b1e48b4,4236aa73,96968213,b57c5af2,3d48b0d7,cf64523a,2d88bb55,e67d4ef,adbae06f,5f93288,2562b9f5,99b50523,e6e05cec,fb7baccb), -S(7e719005,dc42e572,471177bf,80cf531,d31daba6,f2015664,d46c4df3,ee9840ed,80f9dba9,6a495938,74704313,613e3bba,70ef8e1e,83f2063c,566d2791,d79148aa), -S(70d04693,54db73e3,780a4413,804f7cc6,ca1849f6,158c1b7a,9eded185,8071e826,ff96b0e5,4692693d,774e01d7,5776190e,7caab3d6,72cbc1b6,1623e87d,f0f96936), -S(83bbd70b,f2794adc,7bddc8a,ab107e14,d5cc19a2,eedb59c7,71ba622a,53e2a603,eb92141,5fc3f2d,b96bde24,1d68e314,244c9a0f,42e455f6,3b8c09fa,fe3533b4), -S(8f8ffbca,72942dd0,94b208b1,12ba36bc,c324dcc1,dee4de01,ad8dc8fc,ed4f84a,58fc0a62,a5c20df9,e0de3aaf,3944c907,d7c6db11,4976df5,e38ce452,e1901894), -S(7d5fd589,955a3b87,4bec2638,19faa133,9d03ce58,2a64eb4d,643c42c2,95ab2c7b,deed7974,2d442ed3,d70ac86f,ee47bf20,9a8ec7bc,9d9a98b8,b02ff4e,a857db32), -S(19e47a2,323d5a26,fa5c13a2,78ceca70,e46bf5e8,d9d0e22d,f228c15c,8fe4656b,bb439d24,789f26f8,6e5b25df,b40a9cb9,6b3272b4,d85e4a04,e6651443,e1e41706), -S(75708952,9fdc2d9e,ab85a24d,d06a7c29,252cfa04,f2686d19,9fd04ef4,ecd0d304,c7f53395,8aaaec4,ff6e97a3,19ecf7bd,a53a3034,ab504c6,f02ccb24,2a04475d), -S(30f6959f,468add62,636c1bb2,18c2794d,5eb2d907,3b7449b9,eb5c1f7e,a5c1b016,6fe05738,e8ff7b1a,d8527ea,b8ac47b5,35c61dfb,efda4279,382e8dc2,52893c92), -S(7640da0f,4ddf3448,dd21cab9,257e6f87,304afe2d,fef9d58c,93c2de41,e9a7ddf,f1cb4a24,f553505,a660a219,6baf3485,6e8d21b3,6f661a0,baf2aec6,36805c22), -S(1db0050d,dbcb4f6d,e716dcb9,a3a54079,3a8fae5c,53c630ea,aad1dd66,f195226b,50562f14,6f5c2949,3f9e2efb,d64e2907,f7845673,4b7ddf2f,977e46d8,42cb6bb4), -S(2b5a8ca6,f1d94ed4,d68460c,ebf90aea,7506d3ff,9c71de28,908d05ca,eaf08d0e,6cac6a6e,6b8fe9bf,c733259e,7b4a7715,5a15ca6c,94a42a54,be686849,61a8e064), -S(eac0ed60,87593dbd,3c88510a,c27123af,9fc926e1,4a829f01,9fa24686,1b0f9279,5599829e,ba8e5cd6,253cc3c3,8ddd5a30,7e2e38a8,2da09504,4cde7e55,3dcfafae), -S(495c0e20,51615bf,278ecd84,508ae728,72a7e82f,88cbd992,20f2e370,1d46f9ed,ed5a3c18,27e3474b,c04b6684,bc754cf5,b8014720,145ae8b0,fc24c6f,9297b394), -S(c74debae,32533089,35ad9c23,cc038b95,f3f15965,c46dd3d6,df61b482,ba65cd43,9f82e190,4ab044e8,ad645a7a,b27e0f79,e45bb7d0,9755441e,80d463bc,b25ad4db), -S(c6d4d1bb,4b396ba4,a4393403,ced9a8de,59931eaa,beae1f2d,55c1373,77455ec4,c51f605f,101f038b,913300a8,9ad96bd6,d5e60dcd,d7702ff3,357ee1fc,6ca5b45c), -S(a0f35ff7,dfce08fe,6335cabd,c642c2f7,9a4b6e1a,c95df6a3,b4694bfe,91abd1d0,fdec4844,90ba4281,b78267da,b6dd63c6,ad0ec964,96c42407,32834ebf,b9c822a3), -S(ee231095,46b51ef2,547bcadf,14d57e1a,f4682dae,4611b67c,8d99ee4d,ab912004,dee04daf,3adb4d76,485f8e5f,bf9a2231,5e4bcb96,faf63f67,da257c4,5645d797), -S(77fb6478,1d1ceb38,ed04147b,92e46668,bc47fc0c,73c6e677,a56c9fe8,89772810,ae42f6b7,d26702d7,44c3e867,6750cc7e,224e799b,857b6c68,52936846,6a9c35f4), -S(dd205a7c,9a4901ef,3439a05b,56968951,269c8618,ba1638cf,b9949f98,d84ef11e,8a7da4f9,8a628f46,ca39d902,5e994404,dc6d09ba,8cc2d199,47936454,c024a73c), -S(d4225a81,af1ad205,d1ff1555,cd15df81,d82d75e2,7d8b6a37,a7615c32,ffb932e8,3902c36d,7530add6,a88c6e6e,e426434,b9728690,c6476d33,cdca32a7,eee99fe5), -S(237d87d4,2ab0b9bc,ad29bf03,f754d98e,535a3a2b,6a184929,ce65e18e,17eed134,bd7e8be2,8a125d86,adf47552,aaa6a474,797aa641,94edaf12,56b86a9,5057e480), -S(eb9d15a8,76dff407,4ffe6ce7,c430e797,ffcdd291,34b6f737,b2f07cb3,7f2dc8d,8d975595,aa7790dd,d531e7df,77dac484,948d4ac9,3cd1e4bc,d3b7d9f0,4dcbd431), -S(ab6ffcf,2681db28,7a99226e,3fea18e3,5abec631,898d7038,19c4721a,ae341e5c,a93ae653,4ab9ed9e,e2f50552,cce4ae57,1ab80473,38da0fdd,6a203f18,4c4bed0c), -S(28b7ccc5,53c5665a,1daa0150,102a7eab,8d6db154,b575d2c2,33d2ee1e,6fb2231d,a5eea545,a89579fe,ceb2af8c,e67304c1,f1cf936,91ed7b0,4e461c3f,72863921), -S(db7e3299,5ecaadc1,e94ce255,2c04cafc,c10e3ac0,a88edae4,bcdf941d,6a913b60,8d2cc29c,5a23d74a,76d39caf,fc026a0d,58af12be,9202f250,da8e7b6d,f6a701a4), -S(a030b7c8,169eda5d,ccbe9258,30ce03e0,aa89fca3,654e70ba,f9d9cf08,bb2a95fe,4a16e85,3c8efe30,46443cc0,12646aa6,fa030141,1a0b6f70,dafd1cf0,61ef977d), -S(580150e3,ea63bcfe,13b1202a,b31043b,4d581eb2,86b0d985,116d8b06,3a087325,c4dffb1a,4f7190,9807e070,fbd85774,194d7d2,99f203d6,4470f9a8,b8a3c245), -S(d23c6b7d,4c455c41,edf6a923,33fb1b66,43fb00a7,f5f9e0ff,9d96cbc9,af10e6d0,56a494f3,91b77cf4,3a16f72c,2084c3f4,7332893f,de676cb4,3ae527de,eea4835), -S(91a4fdd,eafdc6fe,5630351c,a1d3270f,3040e70d,7c2ff55b,2af7e256,ba853510,59b05210,6c8d327b,24cad438,891bd72a,1b71ac8a,15c9970,334453a1,a8926055), -S(f297dae9,fce4fd6b,decd1c54,72f86b6e,499a6f01,2468477e,316a689e,62c5d5cf,6a8561c6,6cf1c950,9fd21b39,d27e71b,984ef01e,b8c1fbe0,d14a76f,4153f1f4), -S(c8bce284,4cec327b,83e979c8,1c7bb30d,4f5ec633,d64269fa,8bc33ca5,aa4b72e5,71b4a02,e529b17b,6550455d,e5f6db29,59b59cf3,7fb45e24,ab69098a,a71f6bc6), -S(18650112,b904e937,5074377d,ab19db9,88771616,b47c5e90,93e16eff,8d237969,c464be51,dda23669,ef352ed1,e8eda746,3ee2c9b,f56bc33d,7ef464b5,f96c7b82), -S(58e1d8fd,c85f3d28,829cd90f,f968e826,7ccb6aa0,ec8d7002,d78d77a3,76573d48,b76e4320,40359597,60056ac8,6f953e46,6c335207,6e56422d,28d6dade,f7280826), -S(87ca9444,942ca103,5bd010e8,f89ad6da,7158a16b,f5a7774d,84ad7e2b,91130d27,f14dc3ad,8f102cdd,6e192f9e,604293e8,c80211e4,a6b6e78e,fc8e7343,84352a0e), -S(ae61aef7,e240b692,ecb12ea2,b568158e,8da85c8,1c902d79,db82aa8b,747ddf5f,8fa838ed,7248894,6ae75ef7,b4809546,7bcbf668,9e5bb460,2f711f17,6501d3e7), -S(5a91a937,f5a36f44,4a25053a,2bf2a374,aa6118b4,d7f18ffa,1b641977,d761564d,8d2be259,bc22caee,3d0694ac,b70f4a0e,7b7f8edc,b2418486,9613e0f2,7b2e2fd7), -S(8342a29f,f3739b81,f77918ff,d5a74f20,efd76175,6456eab0,aba2af96,b95b1488,5e1280f,3fe41f14,3da73a56,c11df7cd,69f596df,f98204e6,75ec2601,7f7f25ab), -S(bfd9e9d8,dfaa3fa7,a1bac396,45ae27d7,e0a2d2,aa4022e4,6df8d408,eb06c3c2,5ab07b07,1acf15ab,186836fc,29fea177,2c6ab202,a72bbae1,78c4dd8a,7566d025), -S(ae6c6419,ad0fa0e6,56fba661,834b5f49,2299c610,be8f60b9,815f4775,7ea4d9f2,95e9e9dd,ffc81a1c,112d5f3d,d59a298e,6a3fbdc9,c5fa9c00,37394081,e9f965eb), -S(12212918,77ab7009,96eceb7a,b7ae5b7b,822e92b3,e99e0308,481a9936,c3568143,b40c8be9,16637b33,b428f521,b5c4395,6096dcb4,2504bfcb,5780d42e,984f4474), -S(4cb67c85,5964d298,667173a3,3f3bbfe4,5d2f1e07,72eb26ba,95fa961b,41728597,de8164b5,2af252e0,464eefc5,7a65868b,1e0d16cd,f9c5ee7c,7f13ef2b,1f555cc6), -S(b882a78e,a897c609,29c13dbe,b0d15fa8,3b36d895,9ca15b43,d8c8ebfc,cd2592f0,13a114f0,8bc83d53,103a7327,b92e2289,d18b6cbb,39a9571,16b19c8b,77a714fc), -S(7f77196b,483fa953,39b28b5e,464f42fe,e3ee50fb,3384e401,ae7e5a63,70544479,d66bc424,8370ffcd,445f1aa5,38dcb965,68f51a62,4babede2,3f59ad63,8dfbfe36), -S(d04af491,28f406c0,26c8228b,a270962a,7c45c5eb,51c3cbb6,856c8cf8,d2da8959,c354ae41,f03b906f,74b9c259,5a675bfc,7d6389b7,1c181e6b,1b0bd779,b9e47d71), -S(20f6bd64,cde466fb,e0ff2436,4f9d02a1,d7ad2a92,3bafafc,67a1a154,f1a572df,13dff561,a14d7143,369d74fa,c7872c6e,f57d1e78,b0211f57,ad9a2363,19ee4f4), -S(2ae2e2e9,b53d8788,5889bebb,7cb25669,e75ff2ee,ba305324,a2473937,1826365c,6e52daae,1c2a50af,dc37b1ef,22782d72,7a10f128,225eb816,9b813970,fc14c68), -S(2b50215b,7f3489e,c313d5a,14389c02,1c72b1f9,68ab37ab,d9f4896c,6014808e,50069279,8b2a2226,defcafdc,8a8bdd38,dd7c9a13,f5a2157a,4d0942ba,5453a859), -S(d4bb3a0e,7dd530e4,ae3bcc5f,4001686b,ccdc81d7,6c79c131,288bc2cb,76c72717,9c58063,898cd752,23187ac1,d446c8db,c2918fc4,632c1bb4,2278c0c4,48e97d19), -S(82cec682,b714ec75,6d3348f3,da10fe60,885c790,99822f33,d7811cf8,6077284c,c1f14f0e,670e1bc1,ab604e11,8f3c2827,7c86ecc3,79e97e39,6776594f,b4750f6f), -S(b08b799,5cb8527b,c4c976ac,a6675f03,a82cff9f,309eef60,e78ca418,71486c5a,70df1520,c27367ce,53499421,35fd0daf,ba7df181,f66aff88,b83e12f4,f1b57411), -S(44541703,b3f11462,fc2ffc79,b28237fb,3f6d8611,44c66891,e9cefbd5,7f75cd9,e9b53337,162c5629,eabf13c7,f0433cdf,dc41bd64,9238b810,96d2c8f0,77a5f165), -S(5726f775,b5164bc8,9fa8dd60,267615b8,d5aa1be8,540ce3c9,23271a65,8dfde543,31777af1,58e103b7,db7750cf,37f42dcd,6a155880,7f5d426d,1075d8f5,9a83c9b0), -S(c9993bd,7368efbb,c20b1082,354fcece,b072a3dc,a5fb5e68,73bdc8cb,94ca2b98,3a6b4c46,73d3756b,76d0ad69,701af08b,3f4bd359,3c5ddb40,94eb9c25,776063b6), -S(8b12af05,efe4bafd,bab8b73d,830db99e,c3212e17,bf2f1245,86d821da,82a11b9f,32eb833d,79e92f26,6bfe6840,ecfecdd7,ce000f89,14326697,562372db,66d36ffa), -S(c7986b3a,f4992e69,24363fca,fa8b681c,4cf60003,beecc0ed,af312080,d9329f04,a8a72ac2,f76dddac,faae1172,82965c24,d8710ad5,1a1a5863,5dc2778f,22ca0774), -S(b571af4c,b8fd57c6,2ce4b52e,8a38305e,b3c2b5f7,1cba5931,6dcbe676,3a219f07,4c028e68,9d95d4c6,b974fc05,e7a3a264,b1410fa3,2be80588,32986d4e,fc9976c), -S(412a3d77,6113d30f,fdb4ac2d,1be60a3b,bf93fbde,c837fcd1,d23fe917,811fe6d5,d8dccd67,8856db2d,c698ad2f,269aed7a,3c1255de,590c8208,b8611153,f18faba3), -S(33e955e,9aec13d0,c4b8a61d,455f784a,4d22fd0,f935d7e4,69a88dc5,44c89426,668a62cc,9b903539,a26d8de2,44310f07,d8304b7d,2ec1f4fe,35251b82,220c0cf7), -S(c7cb9ff6,4e7c8dd0,4d05f9dd,a7f106c8,a9841fa7,1cd25eb0,2866a34a,74ddc670,d436d69f,c42c21bd,b64250f,19a15191,bc228b35,37469444,717f4c52,a4e9bfb2), -S(9b6fab7f,f701e6ee,efebb2d9,3c4432e0,826560d9,8aa5b0d6,cbc31c5d,190768e5,f01de8fd,bce677f5,5602113b,90853f6,da7f8029,beba0c02,d20b599d,5646d773), -S(48e25e2a,cfad81b1,315385f,25c958a3,26c425a4,9d75c2b2,1a0233f5,9a830525,83a6accf,d0d149d2,b5dbf766,2bcb0bf8,d725753d,50615657,2a0807fd,882a4d6f), -S(14690774,db72e162,667b9033,be102fb4,f1fd648c,858dfc31,a8b17513,74bc9792,d919061e,6c624203,1f0641f5,bfd7466b,ac55d890,a3b1175,12a4517c,af9a6cc3), -S(941b1555,4838a75e,7762a4d8,fca39187,bfcaa3fc,9869df23,93d6c77a,2b956d18,348db67e,845f7133,aaeecf17,ab75960a,954d0d2b,41ea5e15,be098ff,c4a43d09), -S(487eef1e,77bb13e4,821fc8ab,c9f4448f,672d09fe,5fdefd84,2a9931c,477ae38d,eae4bebb,e06b75c4,b6d37238,faf0237f,5b035c2b,cb084825,93053964,33bc4b53), -S(8896a835,37276df4,40f3be94,41267b4f,4160fbfd,51e3f01a,f675387f,362b0ef4,feb71411,db1429f3,5391993b,e461df0d,c3beba79,4b1b90e,cfdb9338,80e5373e), -S(c6f6f864,baa97e54,69407b28,bdb459db,d1af42b7,19da64db,ba274ab1,58da440b,db83cf5d,feb196dc,5023736,c43c1d46,d6ddba7a,44805f36,69f639e8,f2759a33), -S(c901d3e9,1f590c4d,547b5715,dfb1a61d,f898215c,2be28af4,a4d9d229,7852c00,821c673e,77517338,da3617ec,53213d08,9f695c29,2a5ce31,c60a377,428db6ea), -S(19707c8c,3a276dd0,a54e9cd0,b241f54c,470b508c,ae773fdf,20810696,f9eda3e4,1d8832f7,92db5867,73f1d260,39877814,411f502b,899282ee,ff205495,f04d2119), -S(e197c27f,cb20bca5,6c593eb8,7d677048,5b70596d,4f35c504,acc18bbc,49a54230,85995a28,27b2715f,ce2a682,b727e7a0,4c25f412,407bb99,20cf55a,f756027e), -S(5bcb759b,56bda507,23e45cec,4689f03e,d04ce46,497f2409,1c5a93b,3799ff1d,b068ae2a,47e605f7,f9005545,a563ae91,2f841713,15ee191b,d81e0d58,6d68ee9c), -S(2acdf086,f613c0fe,1299e13c,47568fe4,701f5831,1f515c74,32ebbc0f,cb0c5dd5,2496967f,5f3aa9a,352cac15,d3fe9880,a862925,45a2bb5d,7600c1a3,ccdb6374), -S(268c185f,5d0d2fe3,1c1e2850,b3c80f09,f896134f,5f410524,8edbbd5e,bca357b5,2e81765,ab1c4336,6f782895,35a39076,b8501008,41c574df,d6d25b29,707feff2), -S(b6de69ac,f84f7cf7,48d50a05,dea4faa8,9655ad2c,98846edb,e166e2ef,de4483df,3c377b81,ffa03daf,823a5da,e0d4cb27,77b585be,d5fdb889,62c3a3b8,709ddc9a), -S(bc71d28c,ecd81488,5a76720e,da59deb5,f6d4cdb0,36b2bbb1,2e566d58,2843bd07,501055b,52ddb633,74bbefa0,62ee294f,ced29ac7,4398a634,b629532a,3f50f1da), -S(9091a40c,3a3bb70d,d28cb8c3,ade93,910b783c,40b4a2d4,a48facfe,50c524b7,c1bfb69,3ab9ef96,9eaded97,57ed9621,92344389,e62f6c9e,47c51d8f,b75c1436), -S(46a3e416,8ca5d225,1e01eef9,6cc422f3,da56a59,81fd11df,4ba87e88,ebe6486e,e3630232,96c0efaf,f93b3d4d,2367ea73,3d776180,d98abc44,94d1032f,f49dedef), -S(869daf22,c0978d91,20595281,569f2a43,b3afd058,9e2f29dc,c0644dda,fd26ab6d,58f2ff45,bef8eb75,244e93bc,93d58778,c7a1adc8,c2599c04,635009cd,12f8a6f2), -S(1247ffaa,76f92f50,2e4408b3,2d373f38,79a93634,ced87989,c3f666ef,ffdcb366,8dc9de29,3267dfe5,1966ab2,9462d5c7,d81c205c,536c6eeb,4f2246e1,1848fafb), -S(e25575ff,bf62e7d7,aa64255f,8ad222d7,4ce23ab0,934a3c,cbb80d92,7fd98272,c6c749cc,320892c0,31b3ca54,3920afec,90217d17,5397b6f1,1ea201fe,414c1d24), -S(d02c3fc1,68bba27b,ac38bb2a,4fc7ea99,66e8da54,75f9dd9,fa131fb,d2862057,d24c229e,85b30ff8,80b87f6b,ca145250,f4f72907,ec33f51,94c2f8f4,13a8932), -S(28c4002f,5f1fcfd8,d9e13789,d2527f5b,d2788649,72d5b12c,37dc5c13,b0ab243f,259617c3,7c84d212,2ea7b4c1,33118fb9,9cfdbbcc,db707ec,e99b37ac,12380123), -S(a4d02f63,3f6edcc9,88970f4f,e8b0e639,d07cf277,1a6173d2,1e54594f,65b21770,236c19a0,4bfb2a49,98c776b3,2a2dc4cf,7e91293b,4bdb7d4b,a0ed62a,64683bb), -S(f28f22c1,c3ef5444,fd373435,23e97c40,5d3d19f7,21ee5bd4,53087e95,3d2d006f,fca3f966,a264a422,3e861dee,c5844b99,8f245a11,48301797,db141374,128ae075), -S(7ec145c9,7f1bccdf,ab49ef42,1feaa816,e7a6efeb,ca371e4a,29b7950c,ce8b10e4,a278eb3e,1e9b6d14,52f60e3,5ead3083,114ec862,53101724,442482f6,4fe7f997), -S(66a1296f,f7700439,3305a768,bc9712b9,c6a8b79a,a4211d82,900f39de,3cad406f,968f1ac8,70766942,67d06a0d,655279aa,6110ccf7,7ae73873,4a0f4ced,2848d887), -S(f9e2f7bb,6fb1c6fa,760ded51,d465ef1d,b1207d97,660a360a,34be4dda,c5ccf177,48df22b6,c18fdd1e,213d5a1f,a70084df,2419d324,6811f90f,efc5bf8f,24f25e6), -S(f19fcd39,2cffecc4,4f0a9849,6c0920b2,11ca3208,ab312a84,a87bcee6,f6d5f6e,df36cb00,33f564cf,c2e1397e,5d38e21e,460b019c,9bb86ad8,6d4b9e01,53528261), -S(da3bbf50,f63c674,245af2dd,ad0dbf7,7644d069,bfad635a,f6065c52,f6b4b1f,e6babe9a,281a2a99,92b0f5e2,a1377416,e6d143a6,a2de5cd7,dc91eeb5,b3d0c4f9), -S(d5bb7b31,cf5345b7,8c6c0f9d,bf94bada,3d917dbe,2ba7bbf0,f65b2be5,eada38e1,e8103661,6c69aec4,31c7260c,731a471,e236e453,dd0733f1,8e5d1204,bcfabe61), -S(b1129318,36da4fa4,23ae1331,b1adc768,f1460e0e,22331fc1,4cebcd25,85d40d7c,9f8b7276,27200133,b69adb10,ba95989c,22fbb25b,723dfd60,7d1f4815,293e0856), -S(5bd95654,67d6794b,fae7bae9,df0cc02b,a0dc7ccd,cc5d98dd,5ef33d01,99c10f41,867b8536,363dbb08,234d6be3,d8b25a4a,7caf5044,2546d3ed,8f9d6d95,dd279619), -S(cab5c72e,7561a912,25cb65eb,edefc6b5,2e36caa,5551a749,7ac30cb3,149e6b55,f88e4081,3a6336ff,82cd632d,53590df5,32e3967e,37ea5aa2,bef69000,7c683996), -S(f3198dc6,d55fef1a,9273d311,b0365422,ae4a4c9a,2d2e94aa,1c4d081b,2bf138a2,aa2554e2,8ad481c0,d8376221,d15c3937,13f0553c,97b4f8cd,7b341c5c,72b4123), -S(900f4005,d4af3591,a1f518d8,2cfebf0c,e11f6a0c,8ab82367,337293dd,c823d8e,dd729fa5,d0fadbb8,c294306a,e0e2dcbf,9def32a1,1d58ce37,cd318e85,63cbc99e), -S(10f24db1,481336d3,25716449,c08795f6,efd8e3,f49fd445,cd5dfaaa,58a7ca05,ebdfa0b2,75c6fa7d,79751a4,e66b8a0b,f92852ae,bd108f19,a6feb9e4,9a49d936), -S(4babe89,ec5350a0,2ff673e,2b6fbda9,a1e826f7,ef060396,af08bfcb,8da15719,8415f595,ba1d8e7c,e287fcf5,bf386432,5a5a965a,a5ded5ff,4f9e85cc,8a287228), -S(212b485f,e7f39183,1605bbba,6b32cd0a,e3dbef40,a52d1adc,91362a0b,1fc783df,91a67656,9eabb6ad,dd13a646,c07b5ae0,f93c942d,6be6e96d,3d79ba89,5a1ef56d), -S(4aa0d59b,d8feec6b,507dedcb,eeb3feda,ea98fa96,4cd72734,811a72ca,d1f4fdc5,3d487788,3608eea2,dcb5fce9,dc5d25ab,d9bdfc41,ccdf7391,7cde90ca,ea6fde61), -S(dbad6aa7,b7e547ee,8c97e30,d6653c8b,9bf7c37e,679f8ec9,b74ceb24,2ef65c33,3d39eb67,c276c7c4,24b1e367,e71de6eb,dd32e624,b957cdfa,35081b53,510ffb4a), -S(e0495f52,49e4394c,27d9f2e5,e01c59d2,dcffc868,e4be4ce5,1fb114d9,4607901b,e77ab12d,732e11b8,c32a18c3,9c8931b5,f780f62f,7ce0685f,3d921e96,7d21de3c), -S(aef97af4,f923b5e2,3245ae92,9a0baaab,6c14d1e3,bcfaca45,a7c6dd20,58c6e2cb,83e51238,a46575b9,183635eb,cae26493,25acd694,8c04b911,d05c0e53,dd9c61cb), -S(831ebde4,2fa1913b,f4e036ea,73c22b97,916a61db,73918efe,4f94da72,e714235d,60c29914,c09663f5,e6af5b6f,e3b8da4,80a179ef,70da6c98,8ac12a75,10162124), -S(e4db4221,e7ab4db7,e473572,ec6034b3,96537815,2d1d8bdf,e3ceed44,2f24dd2e,359b878,b5bd2f,53f9a275,384f727b,634894fe,a772d1d2,72568a4a,a4d83d50), -S(2f144d89,972800e9,e0ef550f,da814390,9a106ae5,6b2b9dd,cd0f6855,1d824570,269e925b,ab060ccf,84d4c79f,56a557cc,f476b477,9e73a4b3,872875ee,26388dc2), -S(b3638ed0,d52b3292,f7b953b9,7f6df07d,8d1d5c3d,487261a8,8c25a2af,9a13cbeb,54fa96f6,8f475bd6,5515942d,b8d6f208,99bac252,b042394c,fc73a7a2,adae3113), -S(48c7ecfd,5dc8eb51,7827fddb,2430b600,ccc29edf,906b3db,be5151f2,590e56bf,85e43f35,7d9f46ba,8e5a8903,a75d6d36,bcaaea65,1666b1c9,b7e7dc72,487906d7), -S(963dda96,74cd2b15,84c677c6,dd6d91c0,c968d541,1941f5e5,9a2747bb,4f6a69fd,5ae7f7ad,fb515e1f,7790b789,8d2f801b,b764de6a,f5c33fe9,c54ce712,e4c23a1a), -S(6a3c5404,e22a666b,77396b5e,5827643f,ccf4e3e1,7b8b7c8b,6ad35fc9,ae21b1a2,780c9b96,5220c67c,3c8f8e0d,fe57f1df,67ad445d,4c2f0c41,483d9a32,d558206f), -S(14c13d08,209e5619,df06c33e,ee8289d9,628d4ca6,141fd46a,aab75be7,25a79c15,7acdf79d,b5722728,cceb5416,18c1555,4d833aa2,cba5be7c,5b56ed26,7c323bbf), -S(5c83e244,4ef9d09b,d8d648c4,37af0180,a376173d,4b6a23c9,1791d211,f4ba0973,8a041c51,d8001b77,8cfdab74,ebcea960,414269c8,50e52776,61da8c55,2f06d765), -S(824300c2,d17d63cb,131d489f,63c914d6,75120933,667be49d,e0950587,13cd17cc,94cfb246,f97bf2d6,e9de7b17,fbbe864a,521614e5,1cf6eff0,9f949657,f60c522), -S(691f9af2,1a0e7506,f16acfdf,ef22fb51,fa16e068,86d4ce5a,82bfd069,7fed7406,33d1d8da,91b28358,913089ff,dd0dfe0b,1cf5c3ca,1b4acb43,5223e353,5be8af3), -S(a0014691,2dd02b0,bf8533d7,60cb656a,eaa87ef6,93959f13,df81028c,82025aec,644e45ac,2729f6ee,22388317,a18381db,e1675a35,23ab2820,87afb9d1,48f777f7), -S(7c8f565f,228c2015,f1624956,146fa45c,945f6bea,b69e1b9,bc8401dc,f95d3331,2491f474,81df8eee,6b97f82b,48506dcc,fbdba731,44dc6e9b,29a1606b,22bff452), -S(bae86f26,301c873d,2f5cb288,7b2dad60,161410e4,db4b1a49,6477c58c,4817c582,65eeade1,cdb0ca0,14d50596,6549039c,a0c6e43b,4514de9b,fc222c93,180a7bbd), -S(aecd8a88,4bc42d87,b1c49637,ee23c3a,364c04b7,c16ec871,11c9b447,81116c69,fbe871f6,bc384cea,b894b0e5,837a6da0,98f8ab45,72b82a15,b7e7a058,7d93350a), -S(51388726,2e51e2d8,9c5f4ca4,7a6d2aee,3ec63b6,7ee5515d,4bfbdd82,6318278a,319c5fbb,2cc90ee1,3b3c980,3f2ccdf6,18d9f3f7,d09cde94,12779499,9ca87b3c), -S(29826f1a,27d4f62c,9f891a35,82ede6c7,163bdd5e,22f10325,6eea348d,cc4f5cf8,3f473cd2,9041dc75,6afcedde,34fdd6b2,82e3ebc2,baa2948e,774965a5,6d5c6b5e), -S(2d36c3b8,f293d2c7,80792a15,89895cb5,9b33d8ad,362469af,5777f0e0,225f2941,bf0f3c33,6ab29ad0,1bb693bc,249cad79,63aab00,97beb92f,ff1d4dc1,cf1885ca), -S(b7f1fe36,faf18532,34cbaef9,a45d47fd,26a6cd9d,2cbb6424,7f0757ce,3bc0338f,f86de831,ea68826f,925a8401,5ebffdcc,dad4fbc6,9d32b264,767ab067,c7b1b6b8), -S(d254e76c,41359c6f,521a898b,d55ab42,208b583b,59761c54,e9dbab37,fef84285,d504c24d,7955bf0,2bdfc187,bc8eefc2,42b65db7,43e9439e,3f5204e2,9cec288e), -S(88bdb44c,6999ca3c,8d3e8fa7,61f343e,7a9a5f15,577e514e,809af06b,354b8971,c7cab922,69bb008f,cfb1dd08,b6576959,e0593f76,b5aa45b7,899b305f,e432cc7b), -S(94f19750,6ae279c,772b1c5d,17146012,cf8582b1,973c140b,7aeb0bf9,3cd21ef7,1e9acd37,9e7f2dd5,a6df7a9f,f4b757e3,369aff72,341ba963,fd984259,6c615de), -S(f5b2f65a,16322443,a4ed65d8,7fa21983,25f2d3b5,523cfc11,39f676d0,8953680b,7f6c8197,cd730769,2eb466af,8c63e35b,1d4eb84,fc83d22d,d5d1217d,10e06ee0), -S(58e85669,c5f76dff,9b5f601e,3d1a15d2,c022a5c1,389dc15c,81657f8f,e3eb1be7,4fd07587,429bb7ce,3903f7fc,f3356282,24e17eb3,e256fbb1,32f1fcd1,e1048f05), -S(29bfb3d9,d116ab87,407376b0,f8fc607a,ba8a9da1,803479e8,a7ca8fd8,ce96a822,de56238d,93995238,bc6c4b94,f03823d4,a7b690a5,24d01e06,374ddf4a,2e5589b6), -S(78e32283,983fa295,f6fec0cf,e34ee0fd,83541350,e50d5948,8760279b,dd54cc28,8ce8f6fc,d58a5330,595cb9de,eaa7472d,9cc02c4,c7dad678,74af6,e4a20f34), -S(f70d3534,ef29e626,84b84023,2e69e806,740b20ad,ea957ba4,41cc06ae,cdd4ce39,5cb415c4,7812684f,971026ae,21f8d1dd,377d7c27,a91f8d49,90c96adc,2d570c36), -S(4dffc775,38cad4f1,2e87a8ea,44ea868f,ec9ecb0a,a79d26aa,6db46522,7244f006,7afc7426,9d4a76db,2c243eb5,a89735d7,2d91305c,2d44acae,335fc4ec,7cd5f81c), -S(3fc601db,563c119f,9c3fcc60,1005f3d,63c92315,5bd786,9092cafc,237c6c15,4ce31449,bb975d34,5898d06e,6d2e463f,e8e84835,7bde361e,eca2c999,6982735c), -S(7a74384a,d0423c88,4ca797f5,1d62a152,4064db4,c0b5c925,47739139,5bd9219c,2b9c87e9,53965eb0,d5708dec,58a5d0c7,d698e51b,b6d2d45a,b174c9c3,4eba7f76), -S(76dbd3a0,2ca25871,609eace1,6ae2f814,8b256a09,8cd74d21,ae6b0344,16d542f1,c95914e0,5971f888,61800a05,ac946af0,99e0758d,78cfd058,9347ddd,8000bdec), -S(ed159060,2d63fe28,5b88813d,a6930f49,65dd3290,759b677d,ceb9b213,2340475e,894e82dd,1415a206,f3cbe2b7,3b7043b7,1adff71b,58b74c6b,2297ba54,2e1cccd1), -S(74fc673f,4a41d30b,d3ca4b63,b850d23b,8e1b5f2,6c37fdbf,12a83b9e,9c896ee5,8d341f30,c67403fa,e23b7502,91c35064,ffdde04e,ea52b3aa,3003b169,68f1c95e), -S(78c78ab7,5bf6ae8e,d7836957,e8258a33,b88b9cf3,53feac8,e3a8abe,59307600,95c6d9a1,3c9b637e,35c301d5,78534af5,777dde51,6396b017,6155927f,11db8880), -S(4d694817,ad756fe4,2cc21193,d4e707d8,ec458304,291db1bc,c38dc6c0,52f11194,869b495f,49bda0df,b0b12c00,e19c7cf2,14e457ce,66cc8e6,d93c5db2,7a91e1), -S(ac23df67,801e05c7,d283aa5f,ee2dc366,b02517d3,559123f8,d093de6,a9d61a10,e7e7d4a2,1bd85ae8,c88aa4a1,c5cf91b5,6fc2ec00,f54d6ff7,89e10103,7ceefad1), -S(10c1e9db,43b60e88,379b2ee6,566a53a,3341c12e,8d5d6490,ec5ae5d8,eceb1675,2fa61b2e,26557d26,f496ac8b,aab81dd7,16983978,35abd7e4,4d5b11a8,8d7f3558), -S(55ac4cab,1aa3465b,584aa94d,bdcb9eb9,3cff7159,f8a139a4,2504bb27,bb618854,cbe23bc3,8c553ad8,fc9fa619,b96b5de5,90463240,944d2906,41a14b56,cbb28844), -S(4afd69f4,caedff00,601225ac,9bdb192e,6c17fb45,62a28164,15929e64,249da79d,d08702a1,95f9abfb,47296d6,c24981c5,db62e8f2,96ebabc1,1b4b1612,c9478a55), -S(d70b4279,b68e2135,844a45b1,814f1c74,7eb8a5cd,100a6d8,8b12cc79,bc98c9aa,2728845c,c3e20846,a7088f35,9a08add2,4997be96,1327b54,a26ebb1f,95641efb), -S(ab6bf873,7d0321cb,bd2548e8,b81e8070,ad449761,af21a945,9ce2e17e,bba82bec,49bdc2a4,8bc574a6,9577cc51,91267c5a,85fdf00f,ecc5c538,688dcd86,f9d039d6), -S(2e01933c,1462cfd,b8c6f180,c7d633e,1b684ec9,a3011aff,573ac22a,aabff3da,f7c0c7a3,36e576dd,96b83111,9e3bc370,3b94ff45,d50306cb,4acdf9f7,d8126ec6), -S(9ce6a2c5,cd9dda93,2fd291fd,30e8e846,63720189,4a70fb34,9361bcab,263b4e18,f1d503d,592be1ea,98ec3218,8e61ed8b,c2c94e76,5d42c72d,4fd404a3,83412251), -S(626aa071,a774d04a,bfe7cd21,448392e4,a5a3d2da,a2e53dc0,93fd8cee,78f82bdb,a666518c,7dcbef4f,a0915a66,ce331a4d,46867af4,3966c81d,ad9d2dd2,43d30fa5), -S(a6fd685d,4ceae2b2,e1de2177,dae1ba3c,41822896,22270c76,74118916,1b51ea7a,73c90eef,ee517cf1,4f4afdf3,b0f58c8,b66ff7f8,c59a83f8,49b9153e,e29a5ac9), -S(ffc5a16e,cd27880a,bf5f1931,ba61fd51,57396ea1,1630577e,b5e12eb1,e9fd9826,90abe5e5,e312ce4b,14c6548f,bbe2095c,4e146bf7,c25d4022,c017242e,2b057afa), -S(848ee3ab,8e9bb2e0,745ca530,a6231a00,7a41d685,466bf798,9ef900ca,18407854,e1b0d35d,9f44e0d6,b1c8b148,ae5efecf,320bec28,32aaad80,5e1c7812,993afc41), -S(28d833af,476daeac,27559042,f7e352f3,4aa2f30f,b7ffaef4,26e41e28,d11971fd,d0a0338d,57c2f186,c4faaa78,eb13e931,8f8f6d7e,1472ae68,40668e17,94d31802), -S(40579821,9bc06e48,88b1056e,270b19c2,4ef1278a,d415d3,47c7865f,98bcc237,cc9ce014,f853d620,83e18c0a,2fd36b0e,9eb7d265,b711fd5c,6d3f809c,b86f34d4), -S(98470fbe,636eeb22,7b6d425a,d7077b31,9384ad8b,9327d1e7,139a33a7,cf5765e8,92d4c695,5837771e,9d69826b,1445f09f,bc610387,d23a90a9,773113d1,78d471ba), -S(a9d28158,a84ea778,63c7dd75,5bdc6b60,3d6a0d6a,7cf88e9a,b649fb32,44aac2c0,5d628cd5,38824a6e,25477bea,12962465,dbe281d0,bb7f5db2,78bfca90,e5d812e6), -S(7dea83c9,13fa2478,fb03c1f,459cf002,98adbc39,4dedcea1,c90dc05d,5a56ae02,19306ca3,7f768ad5,9e70ea0d,c811adf1,a1e593eb,42bd8d9e,de0c0673,afc1260e), -S(2ab32555,3df0405e,e5576b5e,9965e488,dfccd677,63b03dfd,ef3255c6,7000ce2b,4fbd0086,10d10040,af8a6e80,a1525d88,d8e44ca2,6a1ca8a7,d6eedd35,c5d26ef4), -S(d59e876,ada6de89,fa87dbdd,43b2db0a,e1c1ed01,cb0a5d3b,5fc5cdec,ea52d069,b7923636,a2c5d928,7722673f,f759ec4d,3dbe9484,b470e14f,e28030e2,f37c3bd0), -S(8a69a111,7bdf0752,13f53f00,1101c594,2d2932ac,789c9b7b,15a57640,c679082d,5ef32f62,103c59,8ce35443,5c26f1f1,9ab21ae4,ee8e4350,60aa910a,99fe1633), -S(1aee31cf,451a516b,24f43cd3,71a1b93a,6a04bb09,74f73855,1120c6a9,d27d4546,f6767dda,c1204f16,e31cab5f,ae5b9357,4a2d8b47,b3dc3229,95c0afcb,c4271d7c), -S(7fcc179a,9a2ab1fb,10f03d6,1e936985,91ac91f2,f49ac834,e583f991,365efa71,c69dda71,c28efe20,3ebdb28d,70d0718a,9da3aa5,255c7c60,6f355961,3841ea7b), -S(bf75127f,46e4e90b,3bb81277,13641056,c75f78eb,3717425d,54df396d,9c021a21,640e202d,c28d9d72,c6d1575e,9d672c57,d64610e9,93983585,10eaba8,61fa86b0), -S(4c1248b6,27e5cbd3,5f93deea,44070e7e,bd5b78d,97f27961,53cb63c0,c18feea6,15e12929,f7b6b8df,bce226f4,6f2c73e,7d473833,18fe05a1,1f8ff01f,5d42dbf3), -S(584bab22,79395635,883c483e,abf11ac9,6e97bdd6,b9a0fffa,f30b9062,37520da6,2e7e69df,570afb7c,a3e594fa,7b23d00a,2f8a7e64,c02cebd7,3fe718ea,458891bc), -S(68ae6eb8,fbb41532,aa8e8801,e7c1334f,571ef1f3,92ad014f,9637bb46,b18ada9,aab3337d,550f07a7,20285869,72781c30,4bcc2d81,ecff0fc9,c27fd09,5c41b1df), -S(21d7d1df,17e3c1f8,65ee8c63,f16b0e60,c074501,334a601e,eaa803bc,2b1db846,b6c847d9,a4992f60,c9dd1898,708be183,41f4999,a5803b4e,7c2a5677,d3def3af), -S(63b70ee3,eac6f6db,36b273f2,2f919be2,6146d19b,bfa217e0,a3389ca1,f131b6fe,38accbc1,28b57d42,ab2ae5ab,21997cb3,5bfb42d0,71059542,6867fe83,14df95d), -S(6981f1e5,ce35b49e,b511612b,22ba76db,5884e2e8,819832d0,1859e993,84d6e8d5,7261f896,810a30d8,53cc24ae,40f3f36f,78826bd2,49141d57,6b9bd900,678e0b79), -S(e30c73e,fcbfb24c,882df876,b878b5db,31f0a78f,2e476d3f,850f6b2c,e1d3d548,5821f7f9,7a2e568c,f0f03bbd,c5e43e2c,ffb1a55a,4d6d4855,49f7b6eb,f9a6817a), -S(e95e8d30,316e97ca,70e8d602,89c5a43d,1c698beb,f40e1ce6,87d0d017,7e922f4a,cb161116,c64f6a66,7fa6500,294fdfe1,f5f27cf8,de2213c8,97c55144,2a70137), -S(f0062921,2603da15,6e315036,ebd10c56,477eb7e7,5239f2d8,a4fec336,9e956c38,4086b08e,a3d16b48,a0cf712f,54a7547d,e732233,69030526,c10ba827,eb85793d), -S(ee8526b6,a932b82a,c4645a4c,c5200e91,ac1a8ca9,eccecd29,1c83cb02,bf69ec6f,d5f40396,4f593b1f,d6b130db,65a45c32,241be6c7,d0faa091,bf8f0d5c,41bc41a2), -S(6209df6f,a66fb907,70c68cf8,81b0494e,7c31ef69,38fab171,cef2156a,740ce435,ed1a499d,5d7712ac,dcc39dd5,512aa71,4af5fb36,f53c789c,7eb53d10,7ab415bb), -S(f1f7899f,7a0cf14f,4ed384e8,e55bd6d,8ef0cfe9,895bea58,ab80715f,7bfb6fb1,679f0e59,705f87f6,b23a008d,69c9e145,c44637e7,69326445,68c9dfd2,631a0e32), -S(ecaabf0f,890fb84,a23e6b2b,11822f6c,62ddefda,7def3d2a,816ea029,2d24d93e,b5450b41,29c8ebcd,f3aa0def,bf091346,6ceab1d,874000cc,527e071b,6e3c420b), -S(42220ae9,3b056efb,66349955,402c6b93,31706ce,c5ac1916,494e523f,10959fa,8272973b,a0c30376,a3ad6d38,f007e1de,c9f74fad,f6621d6c,cccd7f55,f9293477), -S(a5b1cb9d,ffbe6c9e,152304e3,c195ab6,1904fa5b,661b097f,6838e33,fcefb7e4,f933eb70,32b9723f,250b861f,1c2881d4,fa118f20,2f16d0e9,bf41844c,4bb6936e), -S(dc460969,258cbf33,c327b9d3,3927b18b,eeb2f2b6,db477491,fe1b0f8,bfb274ed,383db155,3ec0da85,62038810,653c06f1,f573065,4ec029b6,1eac7f75,85bc7ddb), -S(546afcc3,d5e1002e,f7531c4d,40284782,7690f7aa,a9b7aa65,80070700,9642647d,ea4c5ed6,31cb86c3,c7710671,dc26249,13fed4ef,e2bb56dd,fa4f21f3,478ec442), -S(707533d0,61c5c4ed,387e30d6,69ddc3c1,de0162d5,48c11cd2,8daeeebb,6fd8eeb2,a8f2c219,eeea9182,16a5722d,b9fc3f44,a8cae2c8,8e9632b6,dc9350fa,6d6f08ab), -S(4480b923,babe395f,9b21ded4,d7f3ddc2,b9044ed1,379ff4a1,f417bcb4,ea1a1bcc,14ca822b,e0cffe91,42fb177f,712b5c65,6e650c55,24bbaecf,26450356,c7dfd4e7), -S(484a7a43,c88ccc85,9bd81923,a0faf130,f44e45dc,cc43545a,9f7f18c,184efda9,8b79382,3ab0435d,6422fdcc,8a3272b0,1b326ae3,4ef2992,65693070,45fc2388), -S(df247ee8,1936fb3e,9a4da6f,ad000c85,f7c83171,45097f9,ab4b94f,a2c8e1f9,4955c099,d857520c,633c0b75,731c6286,7b5d43fb,506dfea7,9800ccda,9a4962ab), -S(95a936d7,c83a5b13,e0bf865c,22155aa6,71d8f86a,3c518cfb,58e73ccd,f23a141a,be6ed058,5bee36b8,9f2d8921,58bca498,f87675c1,9342df09,f23d62b,64a6533c), -S(89e0cab0,118c0f6a,58b22a3d,fb66fc48,b19c059b,6b5e2958,6c7f7487,61c65b2,cb77eec3,d806dee7,b11c5552,16dcb2a1,2c00233d,2461887b,6897618d,e8c4b0a8), -S(64ac2ffd,67fe55e9,5d82b26a,a88aafbe,5ecd6b25,12226ef0,e6503aa6,a3fb4ecd,41bdf623,644d265e,be30bc86,13a6f084,a44f1dfd,a6f1ee8e,16d84e4a,fc51d66a), -S(60e0f0fd,99be1c5a,43866b76,a7ea8890,a7077135,43bf4299,e25ff15e,e35d87a6,4ef82895,b158d4ea,d8ed02cb,82e8ecf1,df795d20,b3692951,a431ec81,78479c22), -S(49f0734c,8b89d8fd,2b349b48,2d5b32f3,b7d5e68d,532f76d9,753503ff,de2a3caa,4e1c2858,9b22009a,2b4d143d,94fe44a9,5697540a,48a2fad9,100110c3,ca0b9548), -S(ea29d84f,41a54da5,f0d9f7cb,ad239ff8,91395e85,5cf2c86e,e00257ee,325993f6,a0bd6636,dad5c1d7,8d65e18f,c36b00d0,96d9379f,1e650fb9,cd072b0,224d0f4d), -S(92edd00,f9dd358c,6622bb73,ba4f4760,de3e5727,2cde54bf,a8a6d0c7,bc205f56,eacc8aa9,b85829fe,391ae7b2,a747c122,625b408a,c97f1d46,cd0c8891,eb0d4eda), -S(29811533,8b09ec4,583d1702,5a0b0bf6,b8a322f1,76fc46f2,49430c74,84b7b6ac,f7332c0,3b3c5c4e,bf5bfd9c,1e87d668,8347b315,7f0acc43,591310fc,5792ca4d), -S(b5a4aaf6,8a97958,86540199,cad47d9f,86cc478c,ec43a24a,84722a13,4dd6d20,bafca1a,5c9d99f6,3c986ac5,9e432a49,7c8e5683,331ca708,4326978e,1db66f8a), -S(4e249e10,981f8ee8,b3f0e5e6,c2e67de9,ffc811ee,6d9776b,4cabdaa0,98a8b430,955965e1,7ea5d179,4b293db0,b750a649,429833a2,7c317a24,654806cb,5ab7d709), -S(1d10268d,abf2f72c,2769dad1,dda70fe,879c650c,8ed3b285,8583cddc,cc02ffd7,7d31408e,499940ca,8e88fb4f,1aeadace,fbd288cc,c35699ab,8484be00,1acec27f), -S(3540f96e,fe965c34,dc608016,61bbba18,386b20e2,ccf75f8,a0fd6e62,65b8e62,b0d0399e,35c5c376,7773a848,34cdeb8a,cc7ff651,ab6e2575,1ce81e9f,628bedf2), -S(b1e45c76,35de0135,21274840,8f06efac,4550291,d3151239,f8272640,b7354cfb,aeff7dc0,665692d1,6fe0d607,c996ea0,8134b150,317df1c4,afe97cf9,3630c3ce), -S(9fddcd30,734ef7be,aab9c040,f1ad782f,5a67427d,e457f107,b2935caa,d52ea1fb,5c89b6b,36e26147,38599d97,2f4ceafc,d3dedc7f,79e482d4,478e4cec,b7c4016f), -S(17a4abe3,99579c3d,8504a0fb,427e521d,f6034e48,115dc864,b8ba4385,63d692e6,df5128f7,aea1f8c7,214db822,4738dd89,24e08023,36fcfa9f,d4a49a8e,c09056ca), -S(a7d67392,27d93a67,e7eac9b4,2f1583e5,633c7877,56ba7b01,a983d8b4,d4cd181d,1f10081,e72a50fe,b95b829a,d5c36349,be13e45c,f9722108,8ad78dd0,c7b5d9a9), -S(87b2dfbc,e4301a3e,311d8c9d,23c8bcf4,950f8fb3,8481689f,905d6bc9,be1db1ca,4dc9f93c,c4c25853,93f10a45,31c6cb0c,9607170,49192ea0,9ad09810,3c078463), -S(d2fb6a94,adc47e9a,e68ee0ef,24a1ec07,742f3307,36916c3b,8409de8a,2b546ab,eb44e5d3,970cb849,a797bdbb,438bfd0e,6e6dcd64,83bb11f9,10be2dde,978b7e1), -S(7dd84bf8,c7070b5b,d258da10,e62146b1,b5408b62,d7154cd0,45ca4cd8,81623bc7,cf07575c,a02b6ea3,ef2d4cf2,9ad42689,4b30f1f3,689f6a82,31c63515,6633fa1e), -S(b13fb14f,8fb7bd9d,c2a26c80,aac1ad3a,3d10116f,6ec1a7a6,888bfeba,acefda26,b5314ee,2048c766,af47c814,592c3d42,b143ef88,3470eabb,9629c4c3,5fd70d27), -S(b58f21e4,4061132d,75843ebf,74126a4e,25def37e,1f30759c,1c1d461f,95c29dad,737399d8,b9490cdc,7c0a18ce,3d33d340,c2cf7fbd,78a1564e,1115306b,247feb38), -S(10d3dc81,14156a53,f58cbedf,207026ed,6c74f52c,e62cc0dd,68189a6a,bd577fdc,fc4b7c5b,1f1288aa,698032bb,7b8ba84a,10819479,c616c00b,145f9996,8a4588e9), -S(3890baec,2d7505eb,ab767f3c,8b6ada03,3505a329,791920e5,acd55a6a,ccff5fd,a5ced26c,24fb642c,64d292e,2696aa5f,fbb234b0,3d695e83,50f5b101,6074ef8e), -S(3344cd50,af1eae91,f94eb7b1,168737d,fc8d936a,1fbaa3cf,14e9bac9,9c85dd49,b844c82d,1ef06c70,e7795dba,ae1f1e32,f8ecbe2,6c7d295c,b96433b8,161a0fb5), -S(968d92d4,5b6c2adf,376324ca,2feee09,9715b56b,6038a3c3,c51182b9,a2ecfba2,3e014876,6e32cb,5a1ba838,a5d3c64,f954c3ca,a6d481b4,3c660974,92e39d4c), -S(3f7a1811,751e8bfa,2740371f,27e823aa,c2a23c07,d1f5892b,ac2132b4,c8be745,5d475208,6cad8b6,58cee187,f692309c,4c01f335,c4a561e6,6099ff83,18cbad88), -S(2e5d840d,5e808361,799353bd,a2edef2c,4e686735,f8161382,7f98d94a,a4a4a522,859d0019,a0d7619d,89025f7a,6273d98,25acd521,ecbecb75,195bbac1,6d1124fb), -S(5536c7c2,e29de995,e3ad73d1,6d525d3c,5646a96b,fa931bab,5b96dd,ece62eb7,710b162,6d690586,15e54f97,828f7dc5,527b20a,3273e318,5fe9c64f,86ccc206), -S(d29f9ce6,d0758df,c4025af,7097b53c,163493ba,5e16d5d1,d66414e9,a75fa6a0,af5fd2ab,36975272,bd4eb8f4,83e37b01,9772cabd,fe863c46,53a38906,450cd77), -S(8fda2d0c,79aaee8,fbbf2e24,c9e2a98,e37651f,117df59a,b9c37d62,a4538ca0,dc0fd47,aea5d11f,c64a0aaa,d0a2953a,2762878d,6608d513,8b911d40,e679f238), -S(2e17903f,6b00a556,a3492c2f,cf52ed69,58a53715,950c3cb3,f99ddda7,fec950ae,73c72ce7,6644e080,a0fa570f,32d4bf41,ceb500bc,c328aee2,a9c2b22d,56419e5e), -S(c5ec2ed,9ea6c3fe,5d6021f7,bd475c33,3899edbb,7562d91f,4d0028ff,7a07709,7015d790,a6c3f25e,b9cb4bed,f3bcca04,740daf14,da1d3008,463a8f28,6bcad698), -S(b8deae8b,299a5a56,24dc2931,c9d4b63a,361ba102,c5e4e2d1,fdc17262,e10ea72b,40e8ac66,b37a8bda,5d30e794,977b3d40,d2af7b0c,276ad346,a0c10273,359fe18d), -S(66e4daa2,5442fd81,500071ec,51a2843f,ff19b706,8a8a387c,744f295,6282ca65,16a75c2d,bd9d5317,e2b2094a,a85c95ff,87bf3c9e,39101a0c,1bc743a3,70b09380), -S(237df4c7,cc475cfe,7936c17b,dcbddde8,61f37e34,93e4f3da,40d9466d,eb2c675d,170fa5e6,156a8c60,ced37da4,c929fe15,e6d8c691,ff99850d,bdfa8844,38968873), -S(3290620f,ee694bac,64b4af07,25beb94b,9bbbd0ba,bd9c7340,9129d1e6,d5d8da43,31455278,5f416fd9,5bae000b,9b5eebab,65575fa6,9a3b6ddc,cc2c5163,455438dc), -S(a8eadd35,4d5ecbc0,cde50b55,c7e21304,7a548291,7d979b32,94fc138c,d9dc4cff,94dc973c,962b25e3,9aa324c5,8f1c9349,9190eae3,8c869896,a0e62dfb,222255f0), -S(14cfbcad,83d44db9,4194e0f1,bc7d8650,c3586ea8,a362e1cf,f044d3e3,8a5a3ead,348713af,acdf1749,bf27a162,9baf1992,2aa62412,ca2e84ae,85046366,95acbec), -S(99df52dc,8f8daeab,5bf8a48f,fb8c4368,7f4ea8e2,b7feb3bb,fdd6e1ee,59bcda5f,3c6a421b,d7631546,d3fea7fb,6370e823,999c6a58,c8d4f60a,6362e590,c6114825), -S(4c420d8d,7d734ff8,220d9335,ede52153,4673dcb2,c4af920a,aaa691d4,777e0e61,4ec2028b,811fee0e,8937dc37,9961ef93,d7a04147,72a2a45,1e3f64f6,ec5c37d1), -S(485b4e1b,e755e864,ba0b7505,20ef3fcf,a58e2fe5,5b6f736a,6122ad9c,160a6ad6,56adef3a,b8d325c5,c4b30910,cc7a85a0,5a326195,a39a3681,2838d5c7,e3dce17d), -S(8d698df,4acae452,26ee02c6,18c04d33,4e11ec3,f0ec73b0,6365b46d,2e61e478,bebc1c0d,285eb1c6,bd132d29,5786198b,57650a92,f6eb951,a99bfafe,b06454ad), -S(d0d4db9c,4f9b50c0,dd8612c5,43b9d535,8027c081,cf27986e,cc4326db,16526a12,43bdadb1,b7e56e62,2f10f5d8,169a3198,30523f7,908a679f,1c78bf26,6c699c53), -S(b4aaa39d,50e18cfa,743e307d,8ad30f88,3f8a86d6,9f040d03,de008e10,b66b8060,ebce9bf6,8be9bc73,29e1ce4f,ae1a904b,2e1613a2,a45c8095,ed8e346a,6a1bb53e), -S(28e6c590,5af1bcb,f3a81492,37011af4,2e46ac15,fbe0f2f7,a19ba76f,e7104f98,82ba4bc5,4b20238,12256511,b1335079,b21e97d9,7698ffeb,723605e9,c200fe67), -S(b002b5d4,2a2089b9,fac121e8,eea8e240,2ac5b8dd,77f8fb6f,68b59c2e,f2b45182,7eb16bec,99d2249e,22f89e48,11c51324,99f2b7f,e6df592f,7ebf0fae,36130449), -S(36e9cd9,8d1335ab,90d58af9,83f7736b,e317c3c5,c1f0d702,d43c32cc,916719be,df8a57d0,19c19da2,8fa517fa,749f6cd9,21e19b53,dd97e255,1eae0b93,fa6dcdd9), -S(f89c103a,bccc8040,3684beb0,ea56ba57,b447442f,bf3fe918,b25be9de,9bbb225c,7fb1eec7,855ff2dc,9029e712,ce0b619,a6809a7c,3068acd0,1d275dc4,41a55847), -S(5f164591,cc718471,7f23615c,ac67d055,268bcde1,bad2e211,7e235699,4074767e,99aa6bc3,3979f79c,9765a053,66c82dbe,6c067ae,539065a2,4ae37579,4c5a0eda)}, -{S(92133195,a4fd0c59,7e0cf65e,8ce1d939,e333f7a8,441523aa,31e339e1,2ae51e8d,556a388,7a7d579e,87de7f49,8c54bf24,2ca4b8a2,8b959e21,ceec4555,b8fabccf), -S(e3b58edf,cbd6615a,dde1978a,30160514,80e9a335,1ba66cd2,a4e939d4,f4cce6dc,8d493750,a60f61fa,ed9f680d,fa8ac946,d765ab2,1925675,d535e60,b124b12e), -S(d7dc081e,9409bf1,ae46ffa3,5f9eae76,8a92faf3,4a670d76,487b4334,50c2959a,77737006,f0021115,9c81a55,b58da8f5,5f056493,6d319eb3,9fa1a9f2,9ffe1696), -S(ad4d72d6,768dabac,d7c40d1e,b88d5978,46e2f335,8721b980,f1f4b16c,bdcbd829,151a1ed3,ed7f999c,ab836e2c,665212b6,fa08a716,35ee1061,d650735a,3020f89d), -S(325cc8a0,c03e6d53,acebdc12,265ce043,13d69ef,ae00b17d,84df58e0,a3005759,2effa974,b24c0972,84f2cb82,b48c7460,3268ef06,a117aa4f,66d080bb,20ac77ff), -S(38e08a95,fa799d10,23d33d41,e5f305a7,eed9cf69,5151099e,cab0dd40,861b094,3e2c225c,e2c7d8f4,cd27e9bc,50015cb,3714e4e3,2feea2dc,3d275a24,997b7c08), -S(d477d862,f7572311,73fc315a,35342791,319b0185,4acc9ded,6bc71fbe,ac866aa2,c869f5b1,cb084021,d2379b27,d4e5dd7,5e88ecab,765a1808,4664ee8b,74b23bc8), -S(56a5b347,f304a6e1,13dd27ac,3ad1260e,8e65265c,31a95f8e,6d58a893,d2afed47,43c3a208,c6965fb3,397ad3a5,3d335b11,647af4cc,9ca1f4b3,1dd7cc3d,f11b4b22), -S(7755d5e8,bb6c946e,d5a9bd6c,1d3f1675,b0bfa137,3f69f92b,8f0f64a9,baa72e69,1126edd,f0f0d7d7,18128faf,3a988899,a7e2caaa,901e92b2,312f2658,f24bd0a8), -S(f010342e,3b068db4,79325185,ee3198d4,1cfd61ae,e1f2fc3b,e9552b30,ad5a1767,132b3929,a59718e9,addcd814,99ea1f69,941bb18e,f26b3ac1,50b9324a,eaa58001), -S(1f994727,6e3ef21c,2eee65a4,38fb451e,bc87028d,31ff0769,f9935095,efd3e347,425ebd7d,4d6a6a1a,1b32ecab,7be89b36,1f333206,e1526523,991542d7,b23cdf81), -S(eb0a70b7,ca8a1289,e57b3a86,9f21adeb,1ad77d21,9ab64d0,10716f91,3c5fd2b9,dc03531,46af152d,b78813a,bc402c76,93baece4,e57cf68c,ea05b6b1,ca6be07e), -S(b46e930e,36eba93,11248490,4fe0504,91cac0e8,5caa4d76,f35384d8,24f8637c,8f2e844a,29cb90b5,580b74b5,b16f07bd,87385834,23b61485,e3336286,1817c92d), -S(bdf5b431,db844804,70eb3188,6380085d,76c89d00,7bad9990,f28a4e04,e1bad223,9b71ff3b,8f13cd83,b493c150,67d91f38,6341cba7,5f711276,bf768f3e,229c1e55), -S(a4aec29f,3aba4188,e6c73e04,14e8c538,e482491b,6d1d01e6,9801c580,fdefe920,135980f3,b38cddff,e9f7c0d4,87f1b44c,c83c393e,9fe3f8c5,ef6d7840,85a11013), -S(4664f7d4,58ed1845,33ff308f,6389282e,ee336d05,28dee862,2ad54d31,9d1bd536,d774ea2c,9346db82,edef5940,264d2f47,da810925,ec1492dc,5f3c5887,e0015f58), -S(1732bd76,99c1b718,654ca447,5a9851f0,f46bc444,541239fc,54b9b053,e6cd8d61,db1d259d,15dc772b,608957e3,cf32f7e9,b076ec05,3be1305e,c2b8c9d9,7aedf5fd), -S(8e33f8a1,22c90484,7303d6ab,d80fb29,ff84bb43,eec9ded3,fb643482,82f9d4e8,5d1b2f19,30758a1f,d35d3993,598db1e1,d8514855,c23ab82f,245abb78,77f0eaaa), -S(4d96af74,6c067b61,3dc07f73,7eded3f5,da106daa,8910d37d,f9d8beac,962ea02d,74939d7e,c345a59e,567f8046,bb400efb,54107096,8fa45412,c327e10b,3db50b1), -S(478f6fda,3e82c5f1,d65caf64,f80a8341,54428fa0,90dd3833,c2a58cfa,dce5d32,1cb8ecf6,2f7cd442,8b9b3f6c,b33a42b2,bd7c8a94,26e35886,4e1a73d4,65294226), -S(9f7b432f,c89b4f8c,98966a60,34ac0218,d02cd505,f888dba0,55688463,687164b,9d18be19,871f002a,b4518835,9730000f,15446136,f8803657,51987e10,571e681a), -S(c3d1eeba,d935773a,7f30d379,4e5405bd,6bbb9990,26d3d745,78294c0d,c32a5e2e,8857248c,674c01f,4124bb99,3d5b261,def62594,7facb651,f6bb5385,2f5e5674), -S(40a419f9,180b3e76,dddd489d,eadefab3,b3a53abf,8898e5c1,63221606,d7384ed2,53f5382b,a73b7d00,a5afb12c,9345afbe,9c5e5134,cbfe1d9e,81bf3b59,4dfd6b95), -S(ef7cf180,fac500e4,32a70987,989efd6d,d527ddef,779cd09c,589b7e19,747b5572,7b540c7,c2a008f1,8d5ac610,96743cc1,56e87270,5aa2dba8,ac891ea8,bd6b755d), -S(402422a6,8b33b370,aa5f4d57,3a92aad9,acc9be9,2e304de2,73aba72a,d2a8c4b8,351e81b4,4a250b81,5abd8a73,f23ba0fd,a624970a,59076ed2,99667c52,6f63e7cc), -S(1b101d88,9f802cba,396dffef,4eed336d,24138432,12d21fd1,dfd56765,befab1de,b51691ae,f6589bf9,f1d47e2a,c29b6e95,ba600e4,17e48801,aa8c1c36,fac8dcfa), -S(1e82a9b2,4458de28,97110749,dc63f744,94dbc6e2,1085afbd,15c9317c,e3b0bdb,72ff3c57,cf1c18f,64127651,2959762a,83a77db7,2f7b261a,67b1f64a,bad69db), -S(3e5f2f47,a3b6e9f1,69d67e79,39ddb4a6,3ff4d6b,e85e7855,9eebb19c,ba5dcd88,208bd01e,5ace2579,5ddbf6,b57ea49f,aac3aea0,ab3160c3,62e1436c,c545c7bb), -S(e0aba818,cf81f784,ad2656b8,1576ab4b,91a4d0ef,1145b359,393b2bf7,5e798cb3,52f41c6f,3f49e3d7,8031c7cc,c2d4197f,51d53167,7a2b3034,20f2750d,f85dfef6), -S(115d9e1,1d6ae4e3,7a28e641,4704361c,f6422288,a3044b19,7dcfb54f,e76293dd,81c06f64,28931504,21f74c52,64adc217,9c9839d0,9e2ad42,8680b289,64d7f8b4), -S(b742c7f5,60adf44d,a8ad0f43,30c110df,488fc072,c6029911,bb60196,6098f26b,f683d248,d6ad0724,2d1187ea,109f89e4,b231331d,5867a009,26496d34,e7fc2b7d), -S(d8d686f9,2d5b3e5a,90a6b33b,f6e22fc4,e4dff29c,c8e2abcb,cc03d1d2,89d8ac,817b0c58,8e768884,6570da24,12d4dbae,c1649e4,e87b15f8,fb6ca41a,dc90ef8b), -S(a2792c2d,f53b4f8,c4d8da47,1117e7c2,19891016,14e6f8f3,cd40e74a,1f079bd4,bcd3c49e,fced8a89,c5a22469,8360d91,e55c7752,b3c0b798,ffeea98b,373bbec4), -S(2aa4ede7,9b0e39e2,2108d839,a1a3a280,e69cd9da,3ecfc71a,b3ff89ee,f921feb5,8568355d,eb149d39,8d4ba4f3,bd1a36d4,d7e0320f,8b3d8c6a,c81479d6,702c5841), -S(ab965917,6927e9dc,20ef1e6c,60349cda,947dbe9b,79dd2402,f5fead7c,509c56eb,2cc227d2,68174216,abc20792,12eda585,2a91aa1b,e5e141d2,a510a165,405fd059), -S(4103c008,71a071b7,f628d6cb,123c0c9b,2c91fc19,e52e747c,a35846cc,71a9baa3,8aa4e7d9,ee8493a4,ad092826,1377f4e1,397597b4,f63dee00,cf379bc6,92ba589c), -S(972734a8,6a5fc831,6745ab81,5487dabc,51dc150d,4747ee8c,b96de185,4552d1e8,64341946,6c2ae001,49ea0ee4,9dc92692,9ff80e7a,649bd30b,89030606,319a6fa2), -S(9405e5ea,569e492c,883a5035,ba768b83,79fbd706,bb4171af,b0a7480,7069c796,ebab6dbc,4dc6195c,f0fc9b24,82cf324e,3b00fbf7,c4773677,2f55c2cb,60109c6c), -S(c9152518,b43e2f9e,7565f8f0,322eade9,83c5bddf,dc85a120,8b18c6d4,b53e2cff,33a5001d,26ba5f94,19602e75,a0cd39c,c6cc7648,ab9338c6,a796f68b,250f8bf7), -S(1069e550,becc5618,5bf3b627,9e70db17,5c2b98ec,8796dbc4,ebb393c3,95fc23c,cfcd8ae6,b94cfe4a,b3856627,4896faea,ac4db81f,3137c2f4,d14bcffe,26255ffa), -S(e1d567cc,7a7e3b86,ddfe4143,ddd5ebda,41e731fa,68e84445,3494507d,642aef46,7c6355da,fcf15ddf,8b143c1d,542ac5f3,da67225c,d1eeefba,ed24eb41,698af892), -S(b12d2da5,72556701,4915f7a0,f19d0483,452626f6,d03c4829,9bd2fa9a,633d2ca3,5b3af65c,1ee45b4,51a1be81,db8654e9,62b81470,2f162b9,5b02bd2d,313da49b), -S(b8bf7426,e023d1f8,bbdcf2c8,cf0d1ca,3bc14c46,c25ad34e,30e37538,222aebb2,20311608,cca061d4,7daf2293,ef087cb7,bafdbf51,b6fe17f0,f2c676b5,596120b0), -S(30e2ab2b,4d4416f1,56eae97b,15df3e89,8313bedc,39e224e,2875def3,45ebf7e1,a9a5c2f5,bab83663,463a5ac2,38d34f2d,942f0864,9f013068,d5fb43e4,3aa9cac0), -S(b51a0245,335f2b69,ba346bca,6e262ae,e3bb9483,2c4a76e2,cf1b0a43,24398a06,381aebe5,9c57447e,e48a5615,2b8c1ae2,36e1216a,eab9fcf9,f4608c3b,d5c1bed5), -S(16ff6ff9,ea6268bf,fa04d0d7,697f08c4,1717ce6e,6956c14c,bb1e7088,32ded621,a30c4501,a9791b68,15d4fd1b,9b6c943d,8af81feb,b995457b,34640389,eb312a), -S(75a9b34b,80f56b8f,843fe73f,f0a522b6,b32941cb,a892948,be3a649,ab644ada,55c90f2d,e8ddccf5,a896fedf,bd1676ff,11e537ec,fec1e99c,3d880705,93794d9b), -S(e3d207b,fce3af45,7c93e30e,fa54e879,dc00b005,481775c9,1d2195d8,3c0be4b2,ea97b4fe,989166bc,eb7485d8,50829a7a,ce306586,a34f812c,5f30353,9f46702d), -S(4c133100,4af7bfb,d9b25296,64c16012,aa5d2000,167c5ec0,4560c44d,5f424139,4a68e2be,d1509b05,9839d1bb,1e96e953,cb655fa1,1da92569,8edbd940,5758296d), -S(cf6da6f4,eadc1ed2,c4e5c161,541cd6d7,6c3187e,2ca791b8,2fb20f9c,4f8bcb0b,c9fab960,ef26fed,75259616,ae18156b,3e5c7ab8,73a08a65,cd199de7,f743a492), -S(70348438,bfb71d5c,c0ad51d6,d6dd5b01,1694c9a6,d759ac00,72c1f3f7,8e6064a7,1c825ebe,cdf3f546,c731df,c03a7bfa,8101f864,b8428461,36beb2fa,a1d5a916), -S(505ffdd9,f57bb5fc,1e32c035,6bb7f655,793f3aa8,1d34ae77,68a0fcab,73aff902,7ae3363e,36fdebc4,f5d91f39,cb92dc58,a772741,c0191eb8,ab95575b,ac32bb79), -S(a3f102b7,1312ca94,748f0364,1f3e15b3,bb41d1c8,8bb9ea8d,b51b4c9b,4fdc659a,1b1506f7,ed9bb787,7e65f94f,97b400c9,bdaeb208,5944d4aa,c70906b6,6b8e85f1), -S(21f0e0cc,35288167,6cf5df32,fb7f1d9e,962366d0,ed994a35,5e95d68a,1ae73664,13b8d4ee,c089cfe8,ce0fee41,67f25dd5,bc165cbe,c178e80b,d4d7b57b,b0f26f85), -S(6cdead78,97b40a6f,ab7c0e79,66f930f,ef8a2ea0,f8b8e20d,6c832aa0,6476da10,aee696ac,24106a15,2350a75c,aa45a230,c55e3eba,413e2251,719ed8e4,9bbedce9), -S(ac3d60b1,c5f1d942,17c4165d,45efe2eb,889917c4,8a9e650c,e2528893,ea23d48f,791c1b86,6e072f43,78221fc5,b62c5c97,4a601a97,57f130c,787a3401,8bea3f6d), -S(74b31ac4,5ed0eb87,36380b35,e711c93a,1ada56d3,f4d878b5,ca04033a,2673e0a0,818c0254,b96ed496,29724ffd,cf71501c,f37d57eb,93df690a,4c7fce70,a100fea), -S(b4ede440,f1561150,4e25aaf5,e415030b,3542680f,45697539,6c91c85d,aeaf2be5,92ac0c65,d90063ad,793e78a5,6e94211,392b5a72,f417fc5f,d1763228,4ec2cd5f), -S(b629a62,2434ce88,6f7e340d,d3fdb0f6,b36f06d7,cf4657ac,aa189793,5e46c413,f927a57b,8eb72443,bf2a04c7,65ba56f6,4c9aaaab,f28fce4f,aa1fc964,2b8452bd), -S(2536ca07,e67d4bd1,2a3e0c56,77e0b83b,35f03ef4,392efbb5,9a08106f,5e7468a8,4eec6714,c83fc9a5,5bede8b4,206affe6,68d84316,b88f65c3,a7b1b002,9cb23d94), -S(30a68c11,93764521,b72d251b,dafd608c,eaec6052,89ca2a40,b3bca114,117667f2,4a79cf91,e5938ae2,31516a5,a6198cf1,531c9824,1eff5f2f,519a9038,76c21b6), -S(aaf6b23f,bc200102,ed92dd61,a8a853a0,7298b004,7699d43b,ee706ba2,15daf366,e9a15558,d984695f,fdfdce2f,5add6499,644c1d91,79e910b3,2d8f5cd9,6df9a78a), -S(aba17c14,424f27b7,324bd29f,b3a232c4,670b56bd,71013ea0,14942d40,c55cfdd9,5c0265a1,963f3679,f4bb7e7a,60919df0,860adc26,b0fc502d,830c81b3,d8000999), -S(7dd28211,82eff020,ff58a4f3,393c6fd,516b52a,9f78b823,9ba92f08,6fe30fef,6893b183,1c0402ef,c162c99,87efe669,58e9256a,54cc4048,aefb5ff0,989ed93c), -S(822f080b,76a98334,55635b09,2fee11c0,4abd6018,73b83f82,fa761d68,5fefbaf1,fba007cc,b611b2e7,37ce918a,ff26efcf,92a17d1c,4e90849f,ce058397,4128de69), -S(e47aa72,50e27d84,ab7e2e8c,a566424e,646640f6,c1b458df,3eaacf89,2982253d,e2a109ea,5e1854ea,951edeb0,bb8dec1a,8adb05ef,515b0bcc,40774196,222a0e09), -S(6fb6cc,902df4a,34a517ac,5feb8d78,33607701,1d5522c9,9654dfa5,ab5f4872,6efd6a0b,f55f98d,9a1872ec,8a4102c0,e7272e62,9eb6e10d,de6f5b80,aa4bc44b), -S(2cf349e,34205e69,79ba5a1,83032a05,76b5fb8a,961636cc,4d1e0cc2,82158ce9,b75d36f5,94df0de8,6cfcbcb4,b4ac7b97,fd4b711,b48f132f,961b0642,a123cf1), -S(9cb540d2,f8cc21ca,d4fb1b,7e2529,389f6a2b,ac1a71ca,d73f5152,483017f5,65bb5abd,91d3c759,924314d6,f9925b47,87413c2f,1023a6b7,8a7bb65e,d43a48e5), -S(b008d6d,24acd10e,aa0f129,58045da6,4a858f30,44b47e6a,1caa37c3,3ad7efeb,808a3f6,12773a98,59342b25,e479b2d5,d28a8c1c,b2597f7f,72fa0e9f,8eab294a), -S(24bef8fb,9a3465bc,63868e5a,74293e70,3eac939f,99bc1fe0,8263e324,96a171da,efe5e06,9018bce2,bb92fcf4,29efe63d,1d624acf,d732fd47,f6b82c81,db028f36), -S(338b7660,385e3d4,65d5cf89,12473b94,3d1cc1d6,98a07910,8a3745f5,de300277,6c419d49,f3df4dd4,b87178e4,3bc2e9d4,9a76c1a,262d9d0c,bda141da,78fcad0d), -S(a53c790d,d8756046,8446a40a,cfe6f890,21f64328,8d4bf979,99a5fa9f,51f4bc22,444ecb6d,fe9cf442,d34b643b,94bb73d8,7fd9d5b6,87907c62,68425c57,e43e1158), -S(185852e,f02e1aee,10d6054c,796ec263,a33076db,26a997f7,2ef01fc0,ea6ece3f,1b8ccf90,fc573d34,b0733ffe,f10c1346,2190860a,f3e79c16,863a3fcc,add7394f), -S(5894b2d5,476f40ad,765bc171,2bc9426a,df05dd54,31b0d89e,b164258f,d5ec603a,27bcb2fe,ef2d1ae1,e2024ee4,b62e6d77,9d4930c2,3badf2e3,84241d74,cab8beb4), -S(56f1ebc0,345c7d51,c0e58f2c,5e4414c3,a264da18,73e1e898,e3e7d526,777b77ba,1066de15,7ef9ad2b,a07dff34,7d430525,528812c0,2593c14d,a0d0a7ad,73cd1d93), -S(5a271684,5903bd72,89629f8e,c8b99ded,6e20cbb2,9d20001f,9aaef99b,c6e21ac4,1b32158,4e2273d1,4f9f2fd3,9f5b5813,526577b5,af221538,91feefff,ff1a86eb), -S(7cae9233,8cc38ef9,a84e10e8,2281463e,303f8b0,44eeb9b7,fff51d2f,5ad8c8ba,69855baa,a2516e72,7a516081,821f2f68,988a50aa,eb9aac08,e2cd5e74,f2aed0e0), -S(31659ab6,1bd1376e,e989ced2,7d22ef10,d6e48cee,5ed1563c,646f00ae,5f7049ec,2634891c,bf30a25b,fc710d57,9b0e2795,dc2175d,5c7552dc,c0bc350c,cb240797), -S(e007de0f,96522c6,52f49b68,ac817746,27981ecb,72f70b80,25a4ba,efbb871e,6cb6eff3,dc6c9c4a,424be741,f6769eb,f325f749,b12cd512,d6d82ce1,e142b12f), -S(5c67fa0a,604b6b0c,19997329,aaabb82a,926b595,32e10f64,7c519cd7,139aa06c,7b5e99c2,9c49b426,e1df9233,d0fecd34,ba5e2c75,e6bb2b2f,8397c00,18d77b71), -S(40f1a163,f1046ce2,3d46cafa,30c3f1ce,a0b21da9,5af03f72,e7e8e006,7f070563,efeccb57,6a86a01,4ae4273c,fde8a661,3850ea8b,658aaee9,d3058ae8,9df8fba9), -S(bc34a35b,303f885d,d3d2f32d,81f81b84,fd283478,16d56674,89750253,9abe723e,79e3b04e,e93470a3,5c8848e9,30e3a963,77fc0704,5a0fcf62,f41f5610,1b6cc670), -S(49695da5,ff006373,2e59e24c,6c2b8b57,b081dbc6,8438395,282c555,ae9545d6,197f0bca,b2bae828,669a3505,e1790b60,134eb70a,aa85c7b6,82210c4,f6f2a024), -S(cb73405d,957090b,9eef27db,62657d6a,ec058e08,e9e51513,a63780a7,15c3c77f,80ef26d1,deb10417,a2a430ba,4501a722,8eee85de,c40c863b,a88ac3e4,814fc645), -S(40f1a629,1a37fba5,a9992ce7,a9af16d3,ca57625d,1e72c218,bdb71efa,d6ff819d,fef17320,d4f318f1,e6536f75,c104e7b7,fd5d23c7,efa0ac05,5ab28aa8,9861c05b), -S(adcedea0,47371dd9,95c2d169,e84df39,7b91b051,aef5ca5f,e759afe5,e30fb54a,986f4ab9,dcb46d,676076f5,46ae4f8f,55393422,95d33c0a,d4177ac5,bade6dce), -S(56f92765,41af201c,3e9f428,e7e23b50,7dfc84f5,b36e40ba,41f1f3eb,610d9e0a,c1b9bc04,c9e7412c,c8f6efaf,c4c8ff7a,59b76a40,d2717a5,ac6d9270,12ed62ba), -S(208efb63,23799f9d,a69aae92,d7921ab2,31ba1d9,1b5d17db,f6f061dc,30395e6e,4765abc8,177f4765,810c0fca,a125d72f,aeee8889,637b169,6d843d97,51e0e5c0), -S(271893d6,a36b984,878c40ec,45459e3d,932920f6,257af8a8,a5a11b9e,43a111fb,80ce0758,847df058,1c7d4db,6c62eda1,c41e3b3d,33d6f2ab,2efa949c,36c0fe0a), -S(a6ec4e2f,4937a358,91153a45,254e22a8,dd5b812c,1333500,321a62b5,af4be98e,db55a35e,575d81d1,41da4bcb,12a5813,65c12f37,f8ff0164,feb847e0,e49dd86a), -S(1f5a1cf3,8c4ddaac,d12deac4,efcb280c,6d6cbac3,901fecaa,a64d570e,9ebc68d,12c7fda6,5997f8e2,b4b85d96,9d9ee069,1d084761,25a221e7,cbea891f,6993153b), -S(bf41a276,99dc209f,79c80dcf,a5812086,38c7409d,cbf4b842,21869806,e445303e,d375e246,a1bab103,3a89c999,ab89d82b,7bc50961,ee500c52,4fb6eadb,f4e04104), -S(8375c69c,bb4249be,77bfcb40,8ae97e2c,db6cef39,7e265ec3,85987a60,6b83d8b9,3d6e1864,8f105178,7817858d,791938e3,7b6d8f98,ef9f627a,789574ab,c5bde6c3), -S(4872571a,c44368c0,2d0ebbbd,a82ecdf5,b451d428,f3f9f848,28046f01,19d8c41f,3ac201f4,cbaaa772,c7afd2f,1d942d29,2a0c705,90da811e,789b7aad,ab49a7f), -S(2c24eb5c,124db868,235f333f,c3453e49,5dbe9215,5b6de64e,ffcdaaaa,4be86b86,6f520dcf,35dcea5f,86edd00b,7b7e4903,6e414e2b,f643ece9,e22431ee,9b3a9d29), -S(aa70abed,8c5e973b,a21a038f,37d36ab7,61b0da01,636e9cc1,67cf95e6,78c07330,b4367401,7226b35b,1def07e8,c02b272b,8975ab77,7e8d7c31,10a78db9,94fcac34), -S(ab317750,1b5a627f,45a57b2b,38bff161,aa8869d3,a034a5fe,35289a60,e5056b0d,783adc21,9b1c0173,9977568f,234a3cf,4f05e91c,cf07fee9,71bb55f0,e379ceab), -S(d8ae6ebc,fde52d4d,c482acfc,ef231d62,637f4bde,71c32ad6,8205ab30,9d66c013,f75f1efc,2883bce6,ce06d01,1dd86796,77ef971f,22a1b5ee,1c08a3b0,2ecf9cf8), -S(949dc802,f4d797b3,b5f40cd6,a5b3bbd9,c98e579b,7a4bbc20,2770e4c2,f737c1dc,a1d1dff4,7b86235d,b16a88a4,59596ac6,6634bfcf,ff92736a,7b7aa081,2c10ef89), -S(8b0fa15d,59e05495,47dfd98f,5366571b,91355f8c,c54d78b1,b50ac4bf,ed31e633,4b0215f2,65267379,10855e46,1d8abeb2,71c7baff,170667f1,962c0954,6480baed), -S(98707fae,93b85fb,23f0fc23,c953ed7e,68fdb5d5,c7d29c5c,1b130193,400f3a47,bda56a3a,97c9d049,78bb228f,2aa3b6af,59fbf9a4,b0ea2f29,48304fe7,47a654a9), -S(df34cdd9,cc111a99,66690fc9,a79cd621,66075104,dbc40423,69a817cd,8e94500c,29ef5a11,91ae6c3a,f9b959e2,423523e6,5a32e254,c924a416,a41361f7,df7c4351), -S(c23fd61,b07e8fb6,a528733b,f4ab486a,292901,eb4f6af1,2b940af9,49e80811,a749fc6,7f340cc4,71056f0a,ee59e08b,ecfd98b3,cc978477,1eac93fe,1e2831a8), -S(d8be2fba,6d2970be,cf3fca6d,3f3ce70b,a4eb5e19,61f07223,c60853d0,bdd99e21,b03144b7,7e6161a1,a35a01f5,2474872,6ec44cbb,cff5daa8,53de1524,3d5d7c48), -S(beab3690,382f0fbf,e1ae999b,1c12a04b,f421e94b,ddbe0d78,a287c8f7,9de0a903,91168177,fa3af115,e75a4e5c,b399c136,41793138,4d22a85f,982840a7,89d59082), -S(72b16aa2,6df7b6e,9b6381f6,8f3e153f,da872dd7,16c91f66,d04539d4,bd8182b6,73ff3867,2b5b7008,6db53e27,2d7e2969,c6522666,cb544607,52aa6bd,f6a6a28b), -S(b25f6e67,169d5375,3b3c0e43,a8a1dc67,33ced5b4,95902ebb,4187277f,cb754f9f,88657428,cb2e98d7,8ca80ab3,a52cb043,cc50bda,3e0d477f,b12aa478,dad14016), -S(c5d724e2,1eeff913,fd3bdef5,10c963e,77fe49e0,18890a24,fa2832c3,a8b61905,f06907d3,ac8982cf,63eee75b,b9ba739d,e80b819,32a3e978,a3702a9f,256e9f9c), -S(c2ebd113,ad286a61,fd8bb092,ec4025da,67a1606e,31e023ad,f0f7d8c6,e18b5e61,f5a5e5c,defff7ca,722b9fae,e7182953,3191ccdd,cdee5536,f2ae31a4,48c6918b), -S(d6e1a1,62047343,aec39c67,65f07f2e,d0bd1b14,256370dc,2c90bf11,7b54a82a,75864f87,9f5bc30e,afbcd624,71816e3e,fe9c3aec,ae631dac,e0cc99f9,702f7ddb), -S(bc4fc591,c3869b15,8401713a,e545061b,94675162,8757ff17,a52d200,f6f490fb,8188af48,51cdafbb,a85fc8d5,5129dbaf,53642f19,c0ad555a,8385b0a5,c82860e0), -S(1748e74f,610d6d00,f299527e,9f09b30f,271371d8,7cea2ce5,e092416e,7823bc5,5ab591e7,4cbe7756,9fba9944,b84d8f60,268d4824,f73a05a4,9103817e,5c15960c), -S(cd5827ff,853b6997,b3aed60f,829c5fa1,5a6c8482,f4ab123,eff27af0,3e145f6e,3e7863ce,b6101b67,243b1c22,73824acc,212d9123,882310c,970c6f4,9936cbd9), -S(d61d636d,1d5db74,1cfea51b,59d7b870,4566c733,e8bfd023,a152fe0f,bcbe9c95,fb94fda6,36a9c976,2cd6e1ee,81bf6fbd,a5f033ae,1ff7db06,3c31b045,5674e021), -S(2363f1d0,735814c2,8ae1c637,ba838c00,601cf14,d99dfbbb,a1e0f45c,75c62726,f340d59b,44924783,85235374,729d4773,365943bb,21c78b65,c8d7a8a3,f1de05da), -S(45013f55,3e53c6a9,aba8d265,696ba61f,45e15c9b,b69a578d,57a2559a,cc7441e7,ea2ef736,8dd1868c,34b6a65b,6f451f6b,3342d2d7,f90fa2be,93ccacbd,6e6f5d0d), -S(8fd98d99,6bda42ab,ecc672d2,521921a,4c838e9d,760f0f06,25523dfd,2dad54c9,ce29f650,a59a61a9,5955f9c7,c4e1505d,5d795caa,4cd5f81c,290175d0,4e48cc97), -S(d9af8b8b,3ce2f4b1,70979639,db524cdf,a68797a0,dffeae55,e0bb9e60,9ddacef6,898eecd4,5ad6bf9d,55e2e658,2387fc69,d1acffe6,8603ff56,68a06597,bb0186fc), -S(f3b40480,1e1588bf,fbb524ca,9dae6d88,c96634f5,aa163adf,ccd9fd9b,dc78d8d0,4951b9c9,31a7f009,92c808a0,cd7d6c66,fd6dc868,1836c577,d61b3783,39decd99), -S(feeb0e91,e310b9e1,b8c68885,b6c1c728,31a6c29b,f93a733e,c8c86b43,2f576b27,c43851c8,46c3ba4f,6b84f039,6cd4e20b,3a8d492b,57970b8f,2df52534,ba1fa2a5), -S(8aa75b71,79cd7941,1c45f803,e0e76c01,59972566,b24d7566,3fcd1a17,8a0af8c7,f050d1a6,fc082a7b,6c342cc1,f7221042,373dce2a,2b055638,c49c5900,85b97fed), -S(44e9ea01,b7f3058e,f878a57e,8a9ed638,b6fb5730,aca25b8b,e92ea856,611e3b78,e28955c5,2a5ec160,185a29a2,28b587a6,6ab207ad,70236a25,35d0df67,44b48d7b), -S(7533e418,ad594d1,2cfee794,8894a09a,1e440b6d,335d9019,78416aec,5be9915e,312b4709,605c94fc,1215e513,ec13d2c8,e04cb150,bfed209,e848e247,485b4f5e), -S(682d72b9,e5ac04d8,23d7f275,ced51d52,6f8441bf,2b290c40,1e31e6d2,91392bd9,96a37870,6c3e7c3b,ecb70,dcf3aa02,902bb466,9db00db1,39a5e8da,1cb7e749), -S(79aa4b03,a9cfbe13,b7a9bafb,2e170b87,7dc29832,ae4c33a4,6a4e8957,ad2fff11,403a3f70,b165471b,b120e22d,a78d964a,f40b6712,1535d44f,769ef4ea,ab0827cd), -S(73f36ec8,1fd92ef2,f7a7974e,9bfabd08,2e8af24a,4589336c,9f9d72f4,e903f164,9e351dfe,ae961e77,8f617b33,4faa021e,db206599,84ce85e1,53b3eb24,bf155584), -S(c765b554,2a70148d,ca6cb008,12364451,236cb8b6,f2f389da,8325d283,1385555d,c7010bcc,54c1cdff,8cb53644,59916a7e,90dd5c52,e5ec450e,5bffd621,352f9aca), -S(e3b41ae1,42c61c16,b798aeed,8fd85c8a,1ce8bda4,c7378511,b595b1d2,1ca13278,319a4f8b,b36842cc,b4bca0d1,f30970d1,491f1191,b96bdab8,c460230b,4d79ad87), -S(e12d6ec1,6db77af0,2f6487ad,2e07348f,f09e0db4,61b65a48,51381bbd,c0adc704,8d5eb2d,5dd04fd0,a0a62c1,4dfde904,9345fab1,22b9fa08,d54ba78d,fd362179), -S(222174f1,9fd39456,30239a89,1555950e,c10fa208,fb2699ca,311a383e,a92fbd6a,47681f6e,517eb688,c1c5e6ce,ede55387,d6073d3d,3e838121,1324e7a4,e7a9919d), -S(91686e4d,30b99146,e67f23bc,5d0c2e56,571fbc55,2bde35a3,33360ec2,8664ca33,49792737,7b52d9d3,7fa3f737,898895f2,dc6b5cd,e83c034,8876451d,671134e6), -S(ddd308d,5e6de51f,4618dc3d,5ac91e2f,bf449a6e,3e613d47,5419a018,bc88f5ff,9956918,ba5f5ac8,cc155ab,c617cef3,3173fb42,c3c2ae46,e4ecdbee,9bfd4379), -S(ed320f14,1431b13d,b683a4ec,e2b82554,b32f8c8e,fa626ba8,dc9769ef,f5aec648,90d63300,1b6feaca,db963593,ed87f370,63f58a93,1712d88d,62ea3cbe,1ad502ee), -S(4a6fc424,aa5a3dc8,5e3922ff,bb25593b,a74202bd,c8a3aefb,495bd516,54fdd47d,8f32c810,59df5968,8c96d558,64df667,b1e17252,4f48fd10,801297df,325d0370), -S(409c3ad0,16237b76,e4f61caf,16788c4b,f8b8f994,f82435e1,c808a7f8,e88a0e1d,3a2a5354,b0e8d2d6,4be8004a,287e27c7,ea1d1b8e,d6b7e542,4ffe878,de81dc8f), -S(54cd117,bcb57ddf,67ad286e,fcf49489,5e5351de,95011a8f,2887967c,a2d89b3c,c4967891,b75792b6,ec631929,8ee79bd7,79f499c4,7282805,dd4270ce,672e3c12), -S(f31e127d,fc904fcf,9f38aa19,e3d797d6,83cab4c5,a36be0d7,73e69267,785775ea,1c57ef59,42b1046e,1ae1b2f7,d20f3330,1441baac,eee11a40,905315be,165caa10), -S(a0260e45,b9fb584b,1a82262,cc07a5a9,67dfa2fd,f3e7d748,705d87c8,f46d4b65,8e519cb1,1c634aec,67f682a5,72a93009,a11e91bc,e7182c47,19af78f3,bc171806), -S(f8613bdb,882250c8,8f755bd3,86e31331,8cfb410a,ceffd9cf,7b148ed1,c19b6ddb,aa36adc,3d036a3e,4188eba7,321845bf,26350925,392a9a2a,763e6d5c,da3264b9), -S(9cb8fddc,93df0048,eb5919fd,52e29385,597238f1,d7eae596,583727e7,439c0de7,c9f3d25,5cdeb940,c8cbeed9,92ae5bfe,f9be9d7,d81b32e8,a2948d2d,7014db9d), -S(4543a84d,5dda5cd6,af28086f,ec4b916f,9ba8ddb8,d6c1a4d4,f1e242ef,805cd5c7,5ab700d1,a4a4052,a137778,f5691683,824c6596,44f4b206,4f1f58af,9fbb34be), -S(a33279ff,9fa4e088,13d36e4e,e6be8892,7bc36723,cea3ae92,c059a7b2,cc7392c,b47fd3e,8dd3edd,384f98f2,572d6020,21289abd,b05a0d38,58f0c557,15542fe5), -S(2831c5ae,a01f60f5,55763206,9b0e11b5,e88c01c8,7dc81d6b,c4da8497,f8d34d26,4557f90f,2bed0c05,87bd7ea6,92db50b0,dc12c8ba,a9ffdc0f,972e0e8,9481682f), -S(f8b84c2b,18aeb807,5c001f20,e55fb13c,bff76b0b,fe7defe6,9d985f32,abef4127,46258945,3a074620,df7352ef,cb5efcde,23982c5f,3e706272,52cdfa82,6b2c127e), -S(c47328e2,8dca9f9a,ad9dd5ec,1c9e5038,f362a491,46c39de2,dfc6eaa6,32602264,4e0d731c,834a4a3b,6bd5b3d8,66c1ad,1afb3627,c641fc29,6c1adf2,13d6b313), -S(24980a0,6f177e94,7b00373f,1b7985d9,88d6f715,3647090a,31efc04a,a6fff347,62d80bb6,a4841b41,4d6c8ee,bf626629,2b2a505,15fc158a,7d00d470,63efdc1b), -S(c1c03eaa,ac9c665e,cc4081d,fad9bb3e,a8f38453,c4dd54eb,885d198b,5cb9fae4,ca769550,165fbd81,96af4fd0,82ac3a42,5bf75be1,312f7d05,f5cfa9dd,d20c89ef), -S(14cdaa50,b4ec0bc9,5f609133,4698395a,c204fce2,62fe04ac,5f010826,cefaa818,52008b61,3f289f96,1298c773,2938e44d,2607b5ef,8ceef7fd,8f89566e,5c5d4ff8), -S(9914f9d5,f45c50c5,fc4c11d6,d2aa2751,29880d53,7c0a3618,17577886,abce07a6,a4d71a54,3e5bb9e0,664bc22f,86c146ee,3077764a,fb5a0017,41405ad1,50098d84), -S(5ba84c73,de6b3cd0,df8aff3f,c907de14,b73d21ff,dd0236ee,1eb6e83c,b22cb97d,759c472e,55b3c84c,5a677fcc,19dd56dc,14f88be4,4df9b18d,c0395648,487ec1eb), -S(5f0ebbee,3d20d7b,bdf0681b,ec525604,e95ab69c,166a5ed5,a3b38790,7e2a1c76,2ebf4d70,652ab5ac,a932d68f,7687f284,8be58123,701e6e78,1995a10f,c49a0c32), -S(ac1b8b80,3d168f58,f7498d84,d771ab77,2af1c5dc,fce17fe0,f024409d,5a3735b1,57232c98,5f2b2947,82fa66f3,5cfaa879,36bf2fe5,7cc16e43,3f2ecc1b,508329), -S(ffb18dc7,4644086e,51a6ed2b,b6756b36,69cc9e05,e1599ed7,5678437b,816f8656,3dc8b95e,213dc14f,4ae4576e,80a07ee6,5893720a,62f3d45f,bbdf2946,9febfaec), -S(f80b44bb,1a268d50,66b0aa33,6f0cce05,ac025e05,6bb167cc,c3ee3256,31782edb,10d80583,d4288202,a1c7c543,90373965,bc67191,948c4833,1c629f29,2abf2c02), -S(20131423,d27cc837,a520a922,f5638314,11a73ca1,ce7b5442,c557a341,c0fbbab2,7b6757db,16d6c286,44143884,b76fb2c2,8a2a0811,5cd88e7c,c07b72d3,b91a3967), -S(92343611,cf9abf9d,76291f5,7e00c0c4,868d9f28,50e24c85,3f302c90,4a3fb0fd,1190d25c,b8e776fb,931f47ee,25ebb7ee,7dd032ec,c30bcd5b,d48e1049,6ac9062f), -S(27a0148b,39981959,2ad43fd,bdf913ab,26e98ff2,8bb5d33,d74eef9,c07c49a3,b8322dde,2f0aa07f,c3c95e85,88ffc410,5c18e236,7d71c7ce,e8287e33,80addb88), -S(b336155a,ad266dbb,a52bf3fc,e3b681d0,2f1bd72f,2a3b020e,d1a34e76,62fe00b9,bb997d81,4c915336,117026c8,f0f7baf0,a4a3d63d,13477748,ca4b5228,b32adbf6), -S(27752e08,63b8dc92,c4e63ed4,d2acf880,365ccdd0,f83d3ff7,ed62fa2,a6a4bf9a,a67b60d0,81dca9b4,ccc6a192,4a6f4734,16af822c,c939ae01,dfa88ce3,6d4c851e), -S(c9d2dac6,93e0f9dc,7124c6f,7c256b8f,f99a1436,8ccdd33,6cc9f421,e1b1d474,a3ecf256,9ec4e99b,e04cbcb3,af36851e,44d4f91f,b945e59d,7c76e3f2,288c32d4), -S(ef56ff2d,e27a5853,64a397a8,88204405,680b00a7,6c4943b5,1ad02915,a321be5d,1b2c1be4,5f2f67d0,6cd9851a,9c6f12d5,d4dc7fe3,27031b01,76cebc1e,bf8674df), -S(1abbb10b,d34154f2,d28928e9,6f2719a1,d6674ac8,5c078e2a,bf6167e6,6723d972,7bcbd8e,4c01c5a9,68696956,c4359776,e5ce3cf6,a7faef11,7cb7fb3d,19613de8), -S(e51bf6f7,73d2b22d,4dd57e4d,79bafbd4,94f9d6f8,65baa712,97d8596d,dd5b9c83,e7a565f,d8f0a273,3bb72c84,1d283e0f,d6cd1738,af58f6c2,80a31873,9f70d9a1), -S(f61e0619,2acddda5,309a29e2,43b3f597,5b52914f,5e7ab14b,45047d3,76530c93,60bb1329,705d072a,12cbd305,35ed2f9,b530e967,45e34ede,885ca32b,ff0dcb1e), -S(f91f0469,da8630ab,2134c23a,e892ee57,78327bb5,2b2eeca6,11719330,ff163b8c,c216fc14,88bcc308,e4cc5df9,42b1df51,92c2ab24,e0e6630c,38735932,f941f7b2), -S(c6ce13aa,ecbbdc54,6124e467,e5e8f966,a5cdc609,8e2c77b,37ee82bb,df5da173,eacbe9f4,9e21a930,99b08a1d,1e5e8887,f3cb59f0,b9c79e5a,1e26545f,879893ed), -S(522cdbdf,20b56337,e5062b1d,24c8c347,6335e380,4aede233,daba113f,3a174101,b8be6e5,3dbc2cf0,4373ff88,79a4d847,70255e9a,1c9e46cf,44dc14a5,91f6f659), -S(4fec5311,496a5626,341f22fd,b72d4078,109f6656,347c4a0a,6ffc2757,683f50b5,71235dd1,4aa58ab3,6a5fdbe5,71be3f,c76e68ba,9cc32ff4,95bd2166,b6c88737), -S(ece25d,92d12386,1b8b7a20,79548c7f,71f05bc4,5b37fd63,46f14cd3,8d03cb46,ee6c9e60,d7dd08cb,f3fddf35,547ccecc,5d7c95fb,8de3bebd,f77c529b,317f3b60), -S(b160e499,105c9f7c,5582071c,fcdadffd,bc3be684,74158120,50fe69bb,e090df53,702fb302,77470032,3af31e37,aff2075c,201841b,f8ff4589,fd1faf45,b265e3a3), -S(f578953b,a3e785d0,ff9a0c6a,a4f1c1b0,718024c,c40832b6,fec24024,dc65c23d,46391a1d,9a0eb7cc,40b43b3e,6f234ec4,da5d174c,fc22ac49,13d94c2f,87fae285), -S(43fb3e79,fc0b7a1e,a12e3aa2,78fce929,46f1e368,ec23d157,4ac404c9,347a2468,fb902d9a,1f4fd892,6f622169,b7a9792c,d6cf9071,e0efe86b,cebb9274,be62537e), -S(322b8b20,a86183b1,47e01e7a,1a204e57,b5261b6,3d0cd615,5716c2ba,2b7ab42b,dd36d5e4,82e4ffc7,f16ffba8,dd409cb3,217fb763,35810059,a8bf3534,116dfde1), -S(cc54be01,33ecd8c1,c3bc6031,b8e9d0ef,e5483bf8,23c604f4,464cfb5f,d3bcafb,588f4d9a,561f0951,9fbb5f07,1f0f75c7,530caef3,fda4b815,bdbc39f3,9a93e3b), -S(64ca8dec,26f3a2e0,11929ed,22074fee,f9b9ac00,296ec54b,87fb54b7,184ec668,d1465642,dbea26c1,391cc7ee,4380983b,55a54f6c,6886348,dd394b4f,9fd8056f), -S(3bf7a76d,281c908d,4e9b096a,38b432a,2aac8b63,9fd69561,18dc54f5,8f563cad,2867389,d516089e,d6e21add,199ac238,c239743d,e4355602,14e9e570,c060f268), -S(e3e6ae01,7b23ecfb,acaf4c15,b3068e5e,3c1b7b0e,808dec28,15646d59,3f84b011,88ca8e0d,a307bf72,7aeac25b,49fe536b,213d4815,7d229cbf,3944867a,6d90753b), -S(9569f3ae,b8258e4e,98e2243f,da75fb1,ef74c3b1,58f89f42,8ad3f884,7b40bb6e,751c6fae,979806ba,fb81187c,69cdcafa,e13b4657,1785741f,c10bbd3a,71b8f7ad), -S(f66297ec,a2526513,42662205,286620a9,a2a30926,4023e1f9,98c5ba95,702e3bee,9193d0bb,b677a6ed,68be4f01,8c7c3810,23cd7190,bc7be65a,67e633bf,236262d4), -S(d867329a,1e6f65b1,7b6d1bdd,23c847fd,3cfcde18,e0527696,b282dcee,3944094c,8f31fc4e,43597152,ae9e6749,c16b4873,c678b55e,19375d71,228bba75,39182518), -S(356ac12a,743ae734,81328cd,a8469f86,e0e50107,6bb67e21,e77b2f24,8b4d8bda,585efea5,d6bf41cb,fdff2ae9,9b3c8ed8,cc3d6381,bf5593ed,4efc09c6,f3c4739d), -S(c6d16443,5641ccce,bf033261,510529a9,8d5886af,35248aff,ed516ce0,e8a0cb57,3f9d4a08,cc77b5,32f8ed9,e401fc4d,39f59876,41503c46,42077c9,57bd474e), -S(cd895ed0,d1aae7b8,ede22bea,b3d39045,a3e6ce5e,cd8ac7d8,4b74ba17,ab2a67ee,1e1ad565,2d0eec45,4f9c6801,358b05c0,fa96e34b,796a293a,a2f986b6,a920e6a4), -S(1779a75e,51a56cd0,b433fd5d,5b138c9f,6d42fe24,676daadd,7f0865a5,c58c7d97,ed7e5245,445fc6b9,33032805,b4d6c02a,beb7caa7,b6a4f51d,534f2181,d7a9812c), -S(5c1cd955,73d0ffe4,1d06ef6b,a3aa6f16,f275525e,15e89142,cbd043ad,901bffa9,489f6af9,1798dc67,c71159f,44f4b3cb,b3ba9cca,bd9af2bc,a2fa6e1e,d693c7fe), -S(637d236d,8d9dc670,1d78f88c,acef91be,a05092e,44e2ab08,2f057ce9,ccdf1011,8dd1883d,303dd21b,6de832f4,fab06158,ae9a7043,b6fc026f,88d6981f,46476547), -S(c3c046a6,d0ba702f,72f3e1d3,d7af46e5,5ba2581a,b1efbe36,ed20b96f,326afb97,d9d3d813,88bfbf02,9662d022,ce0fcf38,c5442a6b,426a852a,ac443f4c,c0b940da), -S(f224c5cc,249f2879,92d6ad0f,c9556628,b8565431,b0778364,44521b76,1e220e71,4aa9dfa6,99c5eff1,209ad9d8,9c26df9b,4a7942f8,607d9f86,deacc85d,65637dc6), -S(50c0ce65,6f95aa63,946b66a8,da465882,19b856b8,8f2cd78b,5d85040c,feb19a05,b8529304,9cc46692,b2ee676b,d39b6c7c,d2f465c,f4ededd7,6e7f8655,654c18c), -S(925757f7,d66b084e,61fc08a5,cb96d115,86f94c5a,5979d09c,ca34a07c,44133c5,66691d64,5dc5db51,bec2c2e1,e398fa11,84209850,99ccb6f3,e6467406,256f768), -S(a1a7a197,c8067535,df3ff670,2363c366,988b3630,7b63ddec,a48e5c7,35a5338f,4936dcc1,b186ad2c,7f0bfcb6,7792337f,561a378,e8508206,46e2d8ff,21296856), -S(54ba4a9a,877fe4e6,baed26e7,307ff40a,ee662d57,7a48828f,eacb9bea,cb7b614e,696eb116,b1508f7,547463dc,a93cf778,1a4842f3,d7b120ac,89cb0799,5b06bf15), -S(5af3fea8,2941c9e7,bc3423b3,ffd12df8,2b560441,dc3a2851,9ead7546,898082ac,e33fb5bb,c79b2fab,f1755f54,c56b67f4,c1ed9776,1580cf38,3b603dd1,e6b263b4), -S(f383a835,81e8d9e6,1e9c6d31,8fdfb6db,ffb26137,367885c3,401e1b93,33ad37d6,dc6eb905,bdd1f81d,b27ce843,df578a31,bacbb490,bba9adaf,d0c4cf30,c2e858ef), -S(ea01281b,1aa98a60,5c4a1d9,bae8e45c,a9e67ce0,6eaddab4,4decc473,5a7a51e2,3bb44d94,b07c483d,da7e1f63,eb8dbc9e,4f9e4a59,3ff722bc,816a11a7,ab0c4cd2), -S(e5d489e1,e3d0ddb4,9a1f42a9,e928e2a9,b1a1db09,48a59fc,68452a35,c52fe7e8,90d6cc3d,b30be1da,a8d3742e,bfdff07c,f8bc7c31,a3c4e166,fbd1c3ba,9c6507b2), -S(26133aa9,17fa7770,102a229d,487c56ac,1f531d0d,536043f9,8d25d6b8,ba4bbf0b,57c2eb26,6ce9169f,8b0f0a03,cc9d7b3f,25e1965,91eb66fa,247bb5c4,213ef5f9), -S(447cc951,1e20b173,5cf546e2,809140c1,ad248474,51c101bc,40e0ad44,ce791f12,9031be0f,bdc5de93,5539eb8a,dfbdffbc,b5550e70,613811d,dfc9131e,4550ea6c), -S(76992362,e0ab0d3b,b4ba4552,1197fc18,e355b161,bab8b080,a9b849e6,c32f4ae1,c73b4930,47dad2da,c9eba540,5955da52,94b9a184,fb1dc60f,8cc94d6e,6fb1bec3), -S(e14ce3c5,831c8464,75ea238d,46e8e7d4,ad77f14b,46323bf0,aa48d958,cba69e63,57b2b465,8947875,a26c956e,e8b53d83,2d8a4c10,87170d78,ff751fd,dc82762), -S(76375016,e26cad9c,c194cc1a,fd2a5464,5b5450a3,e93eb3fc,c973db01,d367fad3,f86a87fe,5ad93797,6a96323a,e4261db9,6e176488,3f389165,3aea78a5,a3b3e0ef), -S(99947ad6,27bd282f,60eced69,6a6bc741,e338f2d,b905fb2,85e170e2,9257ef3f,6167d7f0,14605150,2e226f2b,6c8320e,b2338350,9962b6c7,e8945f81,4ce1ea63), -S(a68c11fa,497edb8d,4798408a,f2c0c832,f7f70ac2,45188bd5,df8caaf5,58292b66,1007690,df500ea7,a2e80c7b,78162a27,2b54c93e,1bcaccc7,84218656,8f24f590), -S(559865b4,fb13de16,268fd4d6,f2e4adac,6fbe420d,1c7db6be,cd09cb58,a539edd8,f61bb541,17750264,94d479f,7919c6eb,9198df88,3c195399,f3bbcc5a,5f43b52c), -S(7e88a6ea,d32b58f3,5e76431f,75a0b1c2,848b79e4,8226fe18,60241685,e1e349ab,6b070306,7079d62e,747bb6ea,85d7fdbe,1df8730a,7a62615,28b5b20b,341a5d72), -S(a93b9d40,c0b8cee,3a094e19,a181cbfa,d4ec38ee,f12b3fc8,d8e2fd05,70029b05,8c55292a,a8a4ef7d,4a69ede8,c55dcf57,e0247625,85efa9d0,aa22d6c3,ff070370), -S(26afd318,eff92753,1727fc74,5d3bff1a,9b433c23,475059ed,a6065375,22c0cc49,5f03409f,e8a2e649,7b1deaa2,5c2ad40d,517fc985,2bb306cb,86b0a16e,4448fbd4), -S(c0b61efb,ddac8a75,3f32e885,df07e071,a4250886,4657014d,de4fd9b,aa84be93,c30a6285,e838590b,dff89275,a1f69548,c65d7478,52d57a6a,aef16450,f73569e4), -S(be39b097,6ea0302f,8350a663,1ca366d7,7eb108f,ad8db45c,dd679a5b,68e7657f,4528a809,88d04fa0,b4ddd4f1,10fe8948,ae1f6c37,a13d7a10,81cdb4a3,4b83aa84), -S(267becbc,72ebcef4,95d64c5b,3da4bc2a,3fa2149f,a554bad8,eb20bc47,b43c055e,5c5cf671,4fcc1923,9bba9e52,fc97140c,3037d95f,2aa4b828,2f019854,63e89e38), -S(683e99df,1246557,2b88fac7,914c6b15,a819be55,f7415348,a59aa51a,2f08d99d,e5bf288f,d1a561e6,7b79920a,7cff1563,e22528dc,c0a56996,1e87b84e,98210f18), -S(984d688b,cf2a0f4b,b5972f58,f996d13a,c65ddfd2,35247aac,9c983aa0,ad61bd89,b31672e7,ea2611e0,cd3f9397,3d56b8f1,78ceb2d2,85f15a8c,55a4d514,e8b9296a), -S(a9224213,7882e7a5,5ef1c35d,12a6cea7,c0912746,af66057f,20a9835,5dda38a7,532992e3,630370dc,bb4490c0,76f81e18,b9b20dc1,99b0a557,4c600947,5f05cab), -S(6b6cf051,d4311bc2,6a878a11,f5d755e8,dcfbcec7,ba63180a,6c1a527,90c75f0c,395f012a,fe1f6377,7266f20a,d3f1b47e,552c1e04,fee7cc43,bbc94206,1ade5147), -S(df30d2a,fd1a4145,112b2e25,1943fc1e,3c251d44,f67f583f,793d1f2e,da10e3dd,e6753f83,edcb12f1,e29f688,a555699a,aa361a11,afb94832,32849cb3,33bb66ce), -S(1e09829e,89fe1ef0,54ccb6ac,eb3787b,291ebefb,c4531e5b,765090ad,49e9b4cc,db2bbe7f,57c81824,515191e3,7718c75f,63b6abfc,ea51f397,b4a6cef1,6cb49a58), -S(eae324c0,88d0e213,ea0a5e4d,9fe3cc78,3488bc63,22fc4733,d5a2509a,e9fe9f91,5bd9f44d,bf33e894,7572cd8d,41f7ffe6,47d1e194,b4d27053,4f3da5a2,df55ccde), -S(ea64dfd0,aafda3c,e15d6fd4,d4fd87ca,a050e0e2,9c581b86,dc0ac4d2,9396f1f1,f448858c,36b44a58,fce7d720,b8f577b7,d0888751,2569e473,eba52a94,ffc0b33e), -S(22bdbedf,7b4bbc51,a95efc63,8ddf782c,ef33cccb,b112e866,61e7e47f,4eeb4b3f,5c9703d3,84f23420,3eaf2139,9e2f51ff,c02fda84,570af857,e6d51377,bd837e7d), -S(57f7a357,4787394a,d3577667,99126aac,593d86f,58801919,b1f8ad06,d92f97ad,edcedd28,23618851,ee897866,44846a08,5235a60f,d0e84dc8,7ac22ef8,21cc9bfe), -S(38da2e5a,f6018763,89c3b2de,1101c202,390048ab,5e976c5b,b1d0626e,27b5e684,ad71092d,e3c12d55,496c5fed,739a8007,998bf851,8dcf7937,1e1e5d00,cf05286d), -S(129449ae,79439127,7e336d44,34b40d7f,6e649931,feb5be64,b2e59678,1a9eccb6,b7c99b67,a2e523ed,9b52110f,e5104056,c6410ed7,1c91382,c4e5676a,3f0d568), -S(34d6ee18,c82e63ea,6a795055,4558874,6b93d52b,295b52f4,239cd98d,5250a099,d8a9bccd,2d8e6f2,54c25353,996bccb5,dc2ebc48,ae5e6f55,eb015ace,e111fd9c), -S(d202f4c9,c114ad97,963830d8,1d15018f,ea9fbd1a,37b8b818,3a504b89,5925ff3d,f250110,1abb223e,c3293e06,3dc5d2b9,20b5d0c,ac28ef72,3c3ced74,6ec25def), -S(753d539c,82d24f0f,64fb7e90,fb9553bd,90033df,770d7fb9,aa6255d5,f598f611,340d2ed5,7f4a7d9a,d0f94be0,d7c80fa8,c3d42eac,5536382f,76568caf,ccc86226), -S(a440e28e,e1bb9c91,c03b0664,ffa79f2f,c645433b,59ea44d1,a88c73c6,1536f480,96387729,9824b3a4,d28f1a2,7f8a6f78,60407412,2d06b028,78a31c79,85354247), -S(aa9a9ae3,3ee7de0d,5a1785c1,75bfce5a,2d353344,3c32c5f8,94f7248a,1726a0fe,9063cb03,350e55fb,dec53691,4d1dd16f,34d3631,f7d4a56a,f2c6601e,1eba9482), -S(61b60b17,1d406619,e612c5f0,eeeeee96,a7b02b6b,13333f29,3a67e9bb,996f4dd9,e5093ce6,f9eb8b4,4cc2b835,404ac312,2c62228c,b3f0780c,3d995ffb,f92d1734), -S(7fc18068,b529b15c,86180482,b33b7b7c,12b6cd49,79f46168,58cb6084,c92a8443,49aa8a81,a8d66fe4,b4993097,da735768,a2a64f4d,21993b5f,e6e45f25,7632d775), -S(8ae08ac7,6d8ab6c2,a0eac25a,8bfdd54a,1c383b06,84d99005,5f1cc3fc,ea2ae26c,1b463b39,549f3095,14e22e18,e51c4af6,c3e4f5da,9050b9e7,e1556c2d,9b47c2e1), -S(de680d6b,9e75f2cb,4482e3c6,37b03f25,1873aa93,d4af9641,a3e0efff,d10d10e1,22fde416,c2cbfe77,e27fe7d1,190896e6,64da63c1,f89793d7,1478697d,e5cd9108), -S(6522ca17,8d6fffe3,34a8dc3e,83a7c9e8,566d4d61,aa0de5aa,5623982d,4459f553,cf0033ba,988ca9f4,7afdcff2,abb9a069,62f1622c,2b3744d0,cf7533c7,9e5fd425), -S(bec2be0,2fdd1e26,699cedb6,92c46054,57317b30,3e2ddc2e,bf8c9b12,a55a52e1,f03d1203,e013cac6,5b4fcba9,6ff28834,b6dc8539,d38c8053,4d59b5e3,ec3b45e1), -S(71e3f913,cfda601b,1d9c0d29,82dde7c7,970123a7,a2c9c25c,548995fb,6d28d488,6b30b817,2785c0ee,82eeb3ba,1f3b6f64,95b73a61,990e8532,aec482e,19992f85), -S(901223af,65764264,da7fee9d,fca46c4a,d7ce95f5,1c3d3b59,554853f9,20de36b4,c15ac0c1,69b718c7,9bc06ba8,6bb180e9,f4a45c4,1b09a761,67139e11,c3cf220f), -S(bf0ca457,8cc9c676,e6ccce5d,dd9139ed,ef3e2a92,6d4cb5e1,34db0a96,302ea422,b067b031,4a8cd0d3,427d6e18,6c12d0b7,3eed37a2,b7f197c,e2359dd4,6854456a), -S(8e4ad808,c2fec2de,17595149,4cd176dc,1197c18b,b6d31f18,41501c96,fb96293b,71b0086f,f41aa674,e21802fe,f44ada5d,99b5d7e5,47c60b1a,11c4cbbf,42465e6d), -S(7c682ec,732238ef,d9226ba7,9e3d0a21,d3a23d34,66597af2,4db38989,d06464dd,6a6e89a2,fcc6b55,c9d0562f,2c58819d,b7b59177,fa16eb5b,4f6995bb,64546301), -S(36f96e68,ae6603d3,4da2736e,f76ec4db,645c26c5,cdac2721,29527ac1,9378ae2b,6aee55fd,87741026,362d9c02,1adaf833,1a85623f,d97981d4,d0ef82d0,87e83ed2), -S(3cee56be,a461cbca,53cec614,3453442a,8b7f314a,5a79e004,6ccf2363,7b867ed2,b43ae401,ecd4dd1e,4741fc78,cf1853c2,97352cce,853c50cc,fa4c9699,7b063228), -S(6ebd223,be2b4d8e,6fd3a2e8,cc6d899,9b8f571a,7f5e9905,f45d71b7,7654ba84,9cbcba8,3fce430f,41073a92,a90380e7,73faee19,b2c08150,949708d,f49d23b5), -S(112aada3,f4ae50ea,cfb050b6,52ccb99b,79524b9c,4d7821f4,d67b4fcf,b992e64f,4b4cc764,ecb5698b,328eb0e0,7a242e0e,b69821b2,38231446,964f1f01,b6c59877), -S(54e622ff,ef55ef5a,8bbb46e5,f7a98f9a,4cc577ce,ef87fcc6,40909be4,8b0ae6be,1442f6fb,a55ba6b5,7344b4d5,5555f71b,4e77c10d,442504b1,64f1d948,a38a14fc), -S(247497b8,1e23728,f7dc5d0b,8c450eda,fb6eb9da,7eb90d35,e5939440,8705301f,9a5d529e,f38de912,f5c7f58,56e02285,32c6a6de,702244a8,6bc1990d,6144b46e), -S(720cdf82,bf44e211,b71d6fe7,52ed34b1,c9d7f88e,5c4042aa,b3826812,b45df62a,2a05003e,1b36d9f0,b76e34e7,66feacc6,2ed49573,a3f6414b,f631f32a,9d79817), -S(7b9a28c9,8f5260ba,18db1c61,5656d2ba,3de591b8,90a9cee8,96f60bac,54cba095,8a162ddc,95ca8565,d00530ad,d8d338b4,bd62760e,4f185963,60de82cc,9b543e57), -S(cef8910e,534f2fe1,9228ec86,b903a1fb,e6056a5d,2cf7ddb7,f2dadb23,6e2952e2,deda80a0,305e27b8,e9cec5c3,81015929,202fbbcd,3e84340d,3172e0ed,70666b1e), -S(1203af6d,116f7b3e,4926c3c1,f9002e20,196ab0e0,1c6b2b5f,adb17142,8e2f6ffb,6e7fc524,23e6c744,52d2b6cb,4d659fa6,6e541df5,785cc666,a4779429,7ea3a842), -S(c265725b,f9c43ae8,8ea01292,9d0e3edd,e9bc761c,54316ec3,47adb51a,98eb4590,362a5d1c,9f0ce3b8,9a6c83ac,b30a7e00,ffa5bf70,be1490e3,f1e643ac,3ac65019), -S(5044578f,e3d7c3c5,a70a6a1e,dc6686ef,da027c91,a9bcb7d8,5a14cbff,6e7eb943,18d64743,78e2842,b6704760,d8c68b0f,5caf61d0,37fa4b20,98046c88,8a3e84bc), -S(3d278c7f,c4644246,1b324f0a,f666803e,5e052d5a,80dc0755,9d067d1d,e32acc63,a242e218,d1449f64,20417ab2,41406756,e94d3aa9,f4ea1c40,192015e7,3f3b74f6), -S(e89ac46a,382f58ed,982973b7,6569c95,c23c7ca4,4c893317,ce3c3a0d,934b4c93,f8db1b16,6bca5162,23b6d397,3a7d429,9a99a1f5,1c9e82d9,96e00103,11a9c696), -S(d46d9244,52ed46e3,5868ca93,35c9f14f,158165af,f6a16d0c,f31e90dc,569b8acd,c26880db,bd8c2308,5b2995e5,7a40773d,e692799d,b8680a29,d01fc51d,d92bad21), -S(52b62ffb,6989bfdb,ea671d22,f782c692,aa99daf,f6afb854,a260f6fa,3a5dccd3,75d15e76,a21b03e4,7adf5c27,3953584c,9067450c,343f026f,e0dea126,6d6a4a52), -S(b3db1f2f,9c3e602d,5c32a28e,85079423,3759c3bc,3ebaef4d,485f1e00,817a5f30,cd336cbf,7cff0f29,211b9c6c,3b811eb,1d49dd23,c03d36b1,54b43c71,91dc62db)}, -{S(ae5fb021,e9256cc0,6236d667,b76b9bdf,304a4683,d2916ffe,489cf019,6b4c5683,e768366b,5c8d36b6,18e45550,d57493e2,41fed17d,12627e37,b29b4b74,d3603696), -S(d6f735e7,93f6162d,d540a255,76449ae8,edd46e31,d8f641a6,dda76200,c0d33e4b,7f8721f9,23fecd81,b153eb3c,eb2cc58c,c21f3cce,56a1d750,7f99934c,4ade221c), -S(84254df5,b28af43e,d4aed5f7,4e104d1f,2fb371c0,a2adc7f4,21415ce1,ee836c51,b07204a9,260540d4,8e29fc23,e254f378,a49a2cfe,fa21efa9,a2657342,3be3ffa5), -S(7c329ae8,269aaeee,fc01a25c,d2e9a15e,794c589f,b3ad0c76,d51c8efe,4fed9c87,a31b2006,b54e5b13,1e5f4997,f1eaa866,77aa3073,6f6b808f,249522f6,99373dee), -S(922c5ab9,b3938aec,d8a89bde,ff2a803f,fa6d77bc,d1301d76,3f8aee6f,608c8976,efaad685,6ead7c1d,adeb3f45,988af445,ed6701de,1e063a53,6d8b76c7,64be0ee7), -S(3b3b6d42,b662a8e7,44e218b5,4e8c7ae8,842600d4,dc8ff55b,701ae392,512d2d88,3319f63e,5e72d98e,21b23c40,fba11751,cba6756a,68dbd747,f5ebf054,34f8ea52), -S(7031413,ee20f2a3,c716ba79,39882dd3,74dcd7b3,c4fac819,10b856bf,72edb957,20fdd866,33755d03,5ec21df0,39bd4c33,e4ab4bc3,4adc6e7e,f95c6afb,980daf70), -S(b924bf9c,93d735fa,24f61239,83aa798d,e6745852,cb1202d4,db74ded6,a9ca4d67,c8800807,c30e88ee,6351e5a6,547705b8,e29f87cc,4d7166ea,c719d0e3,3f156cac), -S(d43f2e6d,a0f105eb,e6fa058c,c3e98099,3d878f4c,40791188,80a8c5dd,a775f798,3c681084,a8a466e5,34fe34f0,f533f6bc,7aba722e,37af767d,30519272,4465404), -S(d6fa6f22,5617d2b0,6b35249a,eebdb016,517b7ce8,f2f52051,385ecd1,e987785b,1fb064ba,ee45eb8,b7ee88e5,963e290d,6bca04f5,1edd9623,a94476d9,83d60fba), -S(8584a76f,1b641da2,e3645a14,b9b0beb9,9e43f4d8,40ee16bb,793aaaca,c212f1f2,9d3de317,5cdc70f1,35aa3b81,e8a31154,15a65855,510a1bc7,d980715e,5af76d1e), -S(67f50f74,1508598a,c32fa77,8e7b2ee0,3b24b63d,7a48c12c,5bebfb4f,8af63e2f,f35b00cc,c14cdc2d,a088d8eb,b2b39878,5fa46ed,4ce966c7,8acac1d0,a59430b6), -S(34bac85f,a0bae27,e443336f,c6e6df4d,252e5586,f0dd898a,afdec4c8,8a57239b,756a85d9,71dc0296,8f7124e2,5edd877f,d8554377,4c8dc772,ef22f698,5d741a7a), -S(1d2bf603,120749c8,c802441d,b3021c02,65364a0f,6a162d41,f4dfb347,a425a8f9,4cc35601,ac8bb504,13e3a3ed,9d67a55a,fc5cfb51,d3caa73e,73300b65,9503f351), -S(26b9ca6a,aa72fa3b,68c0c995,52636afb,d0f6e88,e540dfa7,a5955952,af5204ee,b2d6cf87,1e017775,152ec88e,155e7ff2,5c04a631,92df5074,2a5e546b,6e15cd89), -S(7dadd65e,6c658083,e82369a,bfb1745a,fcc94247,54db92f6,3fd00d25,23172d06,655ca6bf,232d8f85,e5d0ed6d,5b4040f3,c34e9589,6be0df98,2c65ac06,ff50d51f), -S(98667128,2950f125,a399c076,d9eff5e3,ab8eb85f,c5a496a8,ae8c740f,cd4853e1,949246a6,b2b17c2f,2ef08455,590d4076,a26c508,6a4043f4,18f2d2d7,2dc42511), -S(efa70ff2,4042d4cc,5215b450,703838fb,d274bec,204df700,72a014b8,33d3bdb3,62fc11bb,bb1a6d7a,b585f05,c5da598a,f59b2148,f31d293f,17280652,c8743380), -S(97ea8025,12bb4141,7a2ba994,8456a498,f66fffb1,69883e3c,970d4c13,834c9f61,87cc181f,6a83fc47,c1ba6e74,38104fe3,1627ca80,6b4efdb3,329c62aa,d5cf9913), -S(1353da1,849ae275,84e55047,e8662ff,2a2361ea,fff847bf,17dd5c8d,52b46942,a380a7c5,2ddb6241,cf7cd12,87cc89d6,96a7b3a9,5a198785,76bc4039,b9a913ba), -S(33329e8f,50855274,5598448a,d07e36d8,85b9eb34,8f67b10b,a8b7d04b,b71edc4,be08cacf,ad6763bf,92864ae,3afebab1,a6b19992,b1f0d9a9,436f42ee,b96c6c90), -S(863827a2,46421930,553387d9,46fc1b4a,7d40549d,dd470f6c,75569887,27fc2747,3fd2c6d0,a9d5a056,95c25ac7,8f7eadca,465176d4,fee49512,72a93d33,5fe7324b), -S(8f2c64ba,637543ac,67a7706f,69ec59da,9528be29,7b1be5e7,ffb4fec0,e16d25af,7cb53924,c47605d0,239add6d,287030e,9e8f33ab,4a36aa56,54f1a729,e3dadca9), -S(8ce26953,8fe8a9dc,ded83d07,717e96a5,c95eeeec,e6af2b92,14ae0811,b315909b,9277f1ea,33861808,36545b6a,f467c0f2,dd96ac04,28ea8a0e,e32db52e,de60207e), -S(44274f51,cab44f1e,3e527e95,e92156fd,1cd2e363,332876d2,d3ce75a8,e96c034d,fc4edd64,5e2fa7fa,3e0a8a60,36af7a5b,80424f09,7203774e,489ad68a,5a0c3b3d), -S(ac9170a2,a320f19e,211c2cae,b827e87,d065a9e3,15e11584,d074c328,b38dff24,5afeef29,a8a03e49,45009c9d,e41d354f,69d8d974,ff0f6b08,d0bdad83,5bb8fb5d), -S(eb21ae48,cc5aad77,7202e145,e7178bac,af1899c4,de96aee6,ef2560e1,a13e898a,5726d1a9,1c897a8,c6594022,e139d2e3,e23047f4,99d107fc,9f3ca9f6,aee95d9b), -S(b6b842c5,bb0ec79c,36c0831c,b87f8eb4,8234618,f5d1b888,678d751d,be61c7de,9dc3deb1,6eee7b4,4f6d29c4,ed170cce,2fc78db1,a5485dd7,85fa6de1,8b9d1838), -S(281f770b,e956f478,26529137,e836d00c,5a5b55c7,4158ff32,79b96ef,7b6f17c7,33e0dd6f,e4610a87,c703f4f1,9a7f2b14,3756ee8f,e3e6fbf1,a36f1d28,88a2a836), -S(3520dd8a,8df2555f,2a404ed2,d2766080,302a38ee,14cad37e,a7c575cc,18334cd8,36000e77,7a789b8b,e3de5ef9,71b345f3,3e08f491,3171df2e,ea41e07a,cddbeb92), -S(4307f2c6,db337087,5e69307f,73fc13bd,eb70f5ba,8651e507,2b58ba8a,5945c07a,198ad388,9d9c5b9d,2e050e69,b8b0ab53,8641f4aa,98204215,5262143f,2e513bbf), -S(3f69e90e,4be15f1b,7a3e0518,d2173143,8fa2d0d5,31617b6b,390cb3bb,6dd3e130,2c2eecb0,fed8c40,a0e158ed,44c94f07,61c5c288,d525f12a,ad927235,cda29dfd), -S(487638fe,525ec3f,fd34fd11,6ea6629d,4c15cf03,fb581c18,2c14e0a5,526e9b99,464c0ab4,eac365db,ba6aa562,2dfab02b,93ddb339,d790f875,f8e98a6b,6dc1677b), -S(9fba06bb,20600712,45795836,ba95a91a,af40c61f,c9c83511,8bc97ea2,1428981a,97930e0b,e2b4fe40,8bb37aaa,afe5b66d,6b8c140a,d4a0b0db,a39abce6,f35bb8bd), -S(fe0b19f0,dd103ec7,cbd3d605,dd1e6230,dd4dfad1,b4dfc2e0,23b8463d,8710a27d,167d8e8b,4595516,1daf03be,99d1dec,383d4c47,247c68c3,8927515b,dd388621), -S(a935d63b,16467a8f,41657e49,2c9f7fb3,c5da37f2,3191955b,7e73882,5bb3d256,7fbcb19,2261cd98,ff7b5087,567c1dc3,635b544c,d9f43d02,8d11a94b,94812623), -S(ad28e247,18f124ca,b1377df9,f3f78fbc,1fd4f8f7,74925d02,2f11f56b,c08bb8f2,e3205a6c,5add373d,4893fd23,84fab0ca,525f87ee,ea5b687a,b1b60550,f090bc1), -S(9fd9c788,2172b1d5,9f2c57b5,746506ea,9483fcf1,5cf51ecc,70fa4a40,841f7e9c,900279b8,566e555a,ad3e1318,dc890ad2,6a0c9e4f,36ee4e01,d3a6b046,7b66f11e), -S(85ab8716,a347ffa4,fa4a9807,6a7a1e4d,8f887dcb,7b758212,5831cee,5fd755cb,ecb83ee,e3ecf915,43460350,39e2097b,ac9f0000,2855ff37,ddbbf6f8,6d2f885), -S(da34dea6,49f6db93,c4edb612,c7872054,d78b9e13,4614502c,e2db2c3f,1445d2a6,d34bd4f3,d65a7b20,79510648,3b41c2ea,5ecab70,5fe961a8,a3844e0e,95b5640), -S(1faf535e,2136c3f0,e5026f42,15ee8d0e,d088dbb9,81ecd469,b5311a1d,c235462e,ac1e6f90,a482e42,c6c4cdf2,d8c33dab,b307c39d,c3745cfa,db24810,94e826c0), -S(d1924ae7,ff945ae6,5c1b41fb,398c257b,cea8bcd1,fe6c6e8f,2bf4118b,c6bc9fbd,33d6d54d,237fdfdc,4536abf4,1bfe6681,173a3b42,5652aa1a,9f605f2,8c2cf834), -S(5e30dd95,dc01b76d,2eb1876a,4d0079e7,4473f4d6,acf88f,4b1a7ade,81ab4a44,5edefb5,959759da,4c39c9b2,8ed669ca,7e96b937,394f8cf9,109d99f2,8ae94e9e), -S(1d1b3ebe,aaf21685,c590efc8,5def9bb8,4b5a6e74,de93b34b,b9b169af,3d1863b6,9c5230b7,c41d8d3b,9512a817,34fd101,9d98856e,b916fc79,2806e377,2a75fc93), -S(b1f84efd,e53a7f4d,4cb66989,876f9521,9922fb16,65dad292,a342ef77,f151a7e,624ba3ee,f1bfd30c,81e905f6,fc9a17a1,1c0cc014,acd9ef0,25620277,3e95e849), -S(88857890,30e21565,c166d64,4b14a4ba,9832f99c,764f34dc,ee2aa79f,60f3b4ba,bddced24,35da5a76,79c207b0,e5713ded,b73cb088,997e2ecd,c9cbfc43,f38bd096), -S(f4b8fdea,a8a4a630,2d59c0a0,b34c2998,a7a72c6e,911cf7be,7adfb44,63d1a213,f78d9aba,e80329e9,f02c4f9e,d1bc524,35114a63,884709a4,99925c8c,d06963f7), -S(7f85e0f3,6a03b7c7,47b9cf89,55aff917,df60dd64,f35e14b0,4e9ba8c1,d647393e,f3b23489,f86e10d9,f9f542f7,49df5ae6,d50f5613,481564f4,b8842869,6e40b72b), -S(b5d3138c,6fee7f5d,68599558,b7f4dad9,948d47af,98abb02e,369fff57,bcb9deda,e0d247f5,2e097751,fd33df86,627cc172,5a26eac5,4a6782e7,7c42cda3,b9262d58), -S(7b13216d,bbb83d60,20b9d45e,5b202538,ff22a2e0,e0358147,22344248,d352f2dd,2eff7c95,77819e9c,aa0a762c,ce70fe9c,f0732917,46a2c8,250b0a86,77563e9c), -S(3a79df59,b1f3ced5,70628491,9aafb365,59c757af,efaddcf2,164dd3f0,73e0b85e,5afd0066,b083d36b,da510974,75d07f24,28ec9d25,5ccf79bf,49e059d,cb637a1e), -S(318610b6,9f525ece,4c7b4c28,14cd0fff,d4729929,56872cbb,3ca350b3,6c0d5aae,8dff9296,62ccc6a3,af202f73,4825ccea,362d64eb,30fc187c,f8db26fb,6ab1ff8b), -S(e411c5bd,ea470bea,188e8e26,f7207bca,4f92c793,ba34c1d2,d1a0ed70,f441d836,d4d40b75,f46aef9a,b17afc53,efdee46b,50217b2c,93058fed,838fb17b,4fc33be1), -S(f363388d,497316bd,bc962af,270c591f,6d5868c9,69a08003,1ca021b2,f218792c,6d29bca1,5716584a,8f13a69d,498ffb53,f37d38ec,d7703e92,d55f2dd7,14b860a), -S(79852af7,34689490,a5e7be06,33f973a4,5f1870c7,aa5912c8,8b121a6,3a6f7aec,ce1bfac3,f472d348,c5186160,e167d840,426a4be3,7a58f56d,ed651eaa,15d14053), -S(353357d8,c93b2dc3,3e091ea4,fdfc99dd,3d235074,1eefd250,70215e03,7ee9f450,85c07a65,6bc1389d,9065abe6,a896d4b7,953aff1d,f918827,dd0b57eb,918e8297), -S(d64e1ec,704e979b,5cd19df,3ea4845d,8161f348,eb9afe89,de1c22ee,6fff6236,6772ac7b,c2224a28,dfad9639,3b9fd942,6f59d6bf,7e4a94d5,4003d24f,6b1cb2f6), -S(4afe8fb,9fff7ac5,3a0a0689,24b5961b,4056f190,27fac3d9,dd493338,180e41ea,efb6bb06,ea3ed1ee,c5e7603b,2cbe1d11,e32a1602,19079b9c,a04f997,8ed42f29), -S(bb42b5e7,a047ca7b,eaa52d7,48c763a,3ccb8ca,38f252db,f131d123,90cefe5c,65f8231e,f9bb6ac,4adcd01e,87b99dc3,b2dd30dc,4163d84,8dc0faab,ae035b87), -S(cc6431cc,e7e4ad45,a0125326,6a8114e8,ac9c6896,56cf6e75,ae8cc4dd,cd810a29,498de8d3,f8194a03,ee8c5db,d1d39826,6e09563f,9d5253c2,a6f5ddbf,cd41dcda), -S(624b81c0,b8f558b6,6b19afbf,76b1b7c2,9ed964a1,b53b6ac,6e58acf3,4c6e4d4c,d8429386,43d28c7f,f0e79a55,801a989b,2c923c36,d84638af,686cc637,2cc3095a), -S(53ad6cd8,b0bd0b5d,2742bd76,65c0d0dc,25234c21,a68fc9fd,da85b2d4,a9efb4d9,d886b54c,9dc40ae,40f57f4d,112da945,46c44b26,8ab08440,d027740,8264d5a), -S(ed7a10a6,9a2a65b7,7f3bfbcf,2d8b2f5,57ce675,5334f13d,615f85b4,7bbaacc4,d9021ae8,e1a0cf99,ba539b6f,52dfa141,ac6d2d48,ff71c1f0,c2cdfba6,845750e6), -S(b07022dc,5d250d6c,1464a03e,538b53f6,72470792,da6bb28a,9eb97664,a9797d9d,6e1dc0e9,2b112d0c,520e3fa3,7e90f7b6,36959a43,15a76833,ad935237,6ce4a96e), -S(f0cc2567,eab35314,d0aa253,681d6319,cb016a81,c6e683b9,51e151a7,98b3ef22,cad6711c,1ae440a4,4f547afe,693d199e,4be0f8d0,6a13e2cd,4127e9fc,c99da815), -S(1a71731f,232ff7a,670c81a5,30b9868f,eb59fde4,6c77a264,7357b84e,51917b2b,1560cb00,13a3bae,23983028,4be74589,ece8016d,8c6a23d2,9b52faa8,e907eebe), -S(b8e1e4c7,461335f9,536fec82,30136f2c,a348baae,bb3a6cda,fc8a3a9,bcf72df4,fe85e36,e956074a,26f56f8e,ca1f4fe2,81b0a682,508ca1c4,d6c3249e,21f48cf4), -S(63eeb2ee,ee187fe0,b80d0c2f,ba2222d,1a763aa4,776b2679,b14bd541,f566bf8,56ead5ac,84ae0964,c728b87c,979557b9,c44c13c7,dfa3b31d,86a7e31,5a920c99), -S(862e7b7f,9bf1cc99,8f0a3cc6,3d873eab,228b3977,8bf3aaba,57ab16f7,32ba9d0c,2d69026e,f29ac9a4,151d9f98,1c4248e3,2c3e4789,72c27811,68fa2c4f,5fce4a28), -S(e0588c62,3f65c421,e12cc7bb,d5842e84,bf46c00b,3ea3c38,9ef98056,6cd1deea,98dc9056,d105607f,569aa79b,6d6b6cd6,1b42f749,4333e255,35c220e3,15f9d939), -S(9a6f0406,7e3743e8,78ba2f1a,4b4aa09e,bb8b5bf5,7058128f,bb0a573b,1c504689,6ad673a6,61c9dc87,15cf81f9,3815b32d,6c47879c,c831c549,5a17749c,80003838), -S(6f4bcc03,ed655fbc,be383009,5fa5a1d3,3d4be203,9380ada7,d53e1ba,248ff68f,91e8f700,44126d04,ac2cb1ca,7650a287,e77b2a9,8cc22e9a,b36b4906,5d03b8c5), -S(66b32a92,23945f66,ba2f7934,43f5e31c,8d0bb858,3fdf9db,6d1861e1,fba5e0ec,74d81838,3c0aa55a,16242a41,3ed5f9e7,6569d041,e668d82d,ff90f6b2,aaa9b9ca), -S(c1acd55e,cc4b6743,3aeb6a4a,6a920dc4,626a4219,d70cec1a,1fa4ad6,87696330,6b14fa02,11b63493,ccaa9c6f,e2c288b5,55a4b851,d6a20682,d7aa7039,6c21b156), -S(2bb86341,deda561c,99dd59b2,dd2392e1,4a5cfbb8,9fd49d9b,a35634dc,3274bc61,3662d431,b4403678,a9d59758,dbb413b4,6b48bccb,f3fc9fba,801fe7fa,8d9da0f7), -S(b94189e1,9fa60eac,7b1eaf49,be80b0f5,511693cb,a0efd3e9,70cc0036,eeaf851b,26ee1cfb,ce3445c3,c217bc5f,5ed12d1c,59367ac1,80b65b91,a52d1d8f,c091c8f5), -S(8cda78cc,fba3d6e7,869ad44d,bb5447cd,718be851,df976c1b,ec65be9d,335ff879,cf2cf6e0,94f20682,505bfc56,8f537acc,b2289003,c87c5cc4,23cfc9a5,f61acf02), -S(eb447748,ca42bb71,71c6183e,6ba0e9,a61360f5,b9b686c9,246295ce,c8dae15e,586d8bb1,4dd7277e,5aefa348,55af5e89,55e56526,df89ba4b,575911e7,59f6cd0d), -S(73beb803,c18a68a3,ee1c945f,6031c646,b08c688,6d5b4999,5641181b,c6ab7b0,5fecd8dd,82e3f515,d7a23cab,26949aee,afb1c1bd,1cdc6853,90f3d081,ffd51157), -S(4c3f9e89,e5cc661a,ed4ac704,f37cac28,42afcf38,2c4d51dc,fcc21761,d87311bf,28547fa6,8c661209,67ba52f1,3a13ce38,33ec41,402cb743,49d82e38,2973f615), -S(3e19b5bc,93c422f0,42a2fccd,1595e7d0,d89a2655,fce95a02,56802460,a3ba5b11,edca8ed3,2758daeb,f2649ad8,80114b84,654c3b72,d7ada177,2b84ea75,ea7079ed), -S(7f4b2fb2,6934a60f,50fb114e,b382e0c3,a432f213,a57124f,6cc23e84,27cfe1fe,d0ac243d,9fa8daa2,90efc550,af03e5c2,59d39ca,de0e8779,d68b5880,c74fc874), -S(daf46145,a53b5aa5,ff26bd5f,e0b1c880,835e04ae,9dc51caa,ab37f168,6e57db0d,6203be50,dc56e59f,adee0012,d1c8f24e,afb8caba,88dbc814,f6c127f9,efbf956c), -S(2b339287,f9760403,6bf7d2a,5dec5ac0,6ed9d23d,c2557b4,f853ecf7,70131ad1,6cfe12b6,fbfad32e,b7b100fb,7abcb7e8,cd990d72,d5e7d10,97ad8a45,bf056c1f), -S(2b42fe3d,6a44b1d6,8077ffd8,d3eb700,96afb615,f70af414,48ba4e88,32791e4f,1a8db3b8,50293439,9d31a512,9272096f,6e913775,ae89656f,da79c425,90ec01aa), -S(36c5c074,76246100,bea82171,713bdf41,3d8ef2b9,5ed50fe0,390a93f7,7756614a,53842c42,37723b9d,24cb4666,9f587f68,fb14601b,f4d7b05f,24f9533,2b6d41ae), -S(6c82d0ad,ccee854e,b8ccf077,4917a92a,4c8f4f1d,da784312,2f317ebf,8e8662bf,be05113c,2fba79a4,14442305,f8773526,3b909e30,95a51853,4f76a666,7be28f3c), -S(5019f59b,48e6cd5b,bb394dcb,3b8798fa,bf13bde6,20916ea3,ee9fb32a,53eb2503,4b2e655e,9a09615,7d64ddba,49d9b337,a84b6b1a,707d8896,93211e51,6829a07), -S(301d16ee,7f980c8f,98056bb0,6ac49906,f2f5f404,f36f4f7a,e1b93d47,6e6640b8,d73660bb,d9bbb41b,8f0cc43d,d203ca79,2f07d10a,a60904e4,8d2e3905,e207ecbd), -S(23078318,53146a67,7e03cade,15e9cb41,d3f516c9,4762abc,8a6d7722,1f5557ba,bd7df729,10f0a43b,74a27c80,5bf3dad4,7751af23,9810d9aa,3f4ebbb5,773732b0), -S(2b91a10c,bc666ed3,e7449d2,bda7793c,d6ddc1e0,59c90e19,b85b80f0,50e2a21f,a9b18e39,5154dce9,d6da961d,dea00c40,c58a9cbb,20d9829e,ed4f246d,e7a4af15), -S(73f25213,23e97715,c726b678,cd8374e2,fa7fa140,ec0f9de4,ca25ca02,277bbb65,8b1ec6ee,85ae17e8,da8f6984,c6d6f2df,fa7d2fd9,440904cb,449c227f,b3bd13f0), -S(b8971801,ac6925f,374a5901,2b19e8f9,f2279479,70d070d2,4e097e04,35b4d196,7329d3f0,23a5d418,68e576f0,39b7ed39,8e0fe209,25f098d9,ffa1c45c,8c805fd4), -S(15a6be8,52035719,da9d99e7,9971035d,bcbcf637,d73a37b0,ed8a0113,7500f8f0,3512f517,b5d07551,2f1e91b5,79ceb942,2b807bd2,6be8c336,c124057c,8f204957), -S(6a814e7,c5267f8,182b46aa,a657ccd7,508a468a,dbd9a8a8,b7ce315,2fc672a5,87013b76,ac1d422c,41c8413e,884feb4,bcb29c4e,4639f65b,1962eec3,25ca0d1b), -S(d5ac8a12,2c4e2e37,4145aa10,d5309658,d5d8dff5,7a246d8f,59a4ffd6,43a48d23,683710d6,6ee30017,a07ad2f9,8c12110d,f794c8b4,d92a89c5,6b509470,ddc737cc), -S(9b2c7eef,f744c46b,6e080539,6abb4dfd,6309458,d65185dd,d72a3c2e,ed301b,866a08de,d9d8598,c90fe692,f195d40e,e7a294bd,13f113be,b32323b9,edb35354), -S(a1d0ca41,dd26772b,303085ea,6514331c,57dbac2d,f7129d3c,94a14b56,64dbd1b1,828b9dae,dba3a32c,e72dce2e,e57cba96,7b3a8001,dcf4694f,4e936cfb,2d195c9a), -S(d775ef1e,c3e03ea0,be8852d5,50d30e2,651f2b6c,1b88cce5,8726d66f,e0f73334,2abd706e,acb8e68b,3a3b096b,4517912c,61fffc4f,8bd6c0af,2ba7affe,f3446c8a), -S(6c4b9a00,8c0cd988,e518536e,6dba0027,60e43d4f,e26e7a00,632db70b,e7701742,79d51a,905d04f5,75067ed4,8b22de92,3c25c98a,f14d2955,dce9021b,9aa9950f), -S(39af331,36455357,e7b4a48e,d74e5b0e,182363c9,aac8ff12,545e7cd4,7af66101,e66eec81,736f055f,7325521f,e349d4e4,3faabfb9,c73f7bf8,7c9a791b,1635f16a), -S(ecd4f3e5,36ec00aa,8b4dcd7a,997cb470,6fc83e55,8635c241,5c03807d,16f6916,479006dc,de668a08,fc4d3bb4,628c8b23,6deaad8e,9f75e99a,93e464db,4bd96a8), -S(d26fe1cf,b13ba752,d76d09d0,1ea6204c,8e90baa3,79ece72b,80e6f7a9,282348b5,db4d5f6b,c63ebd68,44735571,a0f43d81,df9d5661,471a1050,11cf4801,b182d80a), -S(6d00c0ca,7c94bbfb,dcc30c47,1f5622e1,afa13179,8b0fef54,3adb02cb,296faab3,7705f197,bca702e1,3ae1eb4b,ff6d8ad2,80c43085,ae5bc7f7,12fa75a7,aa65e6e4), -S(5a77b624,b3949a1b,16587011,cf9b251f,90428c1b,6f5a371d,f2499c28,92c94982,928036ba,b113a731,65760dc5,70562398,f23d1a53,126ded37,6370178d,37ea3db1), -S(e92f3c46,b854d695,455035b4,fae2d3ff,83ad6f62,5fe9e8f9,fa9f3266,898d063f,9ddd806c,683cdd2b,430677fe,89a7a603,75fa8923,bf72c196,cd0ead02,e1d9fc8f), -S(c9d99f0,47ecc29b,5892fe3a,9a285f23,eb7ea82c,e7ffbe2,2f0596df,14c2f8ef,64c0ead2,269f8833,a7a16d8e,d0c3acc1,56309197,9685467c,f4b47420,1b6e74c8), -S(85359be0,9d8cdce,de34edea,1ae82ecb,51af02ac,8294ac59,868b7972,c114398c,6e6e163,3b8101cd,5d3b4264,26a05f69,3aac26ee,c5da1d7e,75944fcf,710b15ff), -S(a1fb58fd,d1283e1f,86026dfa,4e29ff12,da8d9c7f,d6e75e9,6fb31706,8c9f34ec,9429b8af,a89a0031,ead59b83,a9796219,aa8ecbd0,a7875b79,c9fbdddb,85f1a3bd), -S(8ac4d467,6390b97d,488f7943,5e68c47b,eb7c6cda,f920cfc9,dcd6faa9,593e1185,5cde9d0f,3fd47f0a,65b9d7ad,c415872b,f860e1c4,74471b6,c57d464b,9395ead9), -S(1e1cdc12,96067717,2b3776e1,d61a872d,a65c6a99,33596409,99ac16b8,f836237c,f9fae2b3,49d8e6ca,57911ffa,ba411fc0,f80f45c3,a8ff0bd,ac0d6dfd,1b4fe271), -S(b96841f0,b49538fa,7d14c6c0,2cf08242,d6d21ea7,333ad720,9a0f6156,67f6feb2,fef3827,23554c52,6fc37f41,7baed824,17f163b6,e855af0,51e81cde,bf8a32dd), -S(b42499ab,a8a83591,3be09ac,504c6c47,3214f31e,fbab7573,67936d9e,216fd0f6,a2f6a202,e1a97f1c,cf083e26,c84ee6d,7d57cee2,266246b3,c4b6b56c,5f4d613b), -S(418c2e28,7875dd00,6c5760a1,1c72ec31,f267677,7d27a4f3,fc03cfd6,803d85dd,5e727ed1,a2180e35,4bcfed5b,65eb44d4,f045d3d9,ede9fb67,beba53d3,cf8c9ef7), -S(1aa9e157,cd261a2d,c4a00e7b,d119968f,5bff1084,4cb9c835,62b7218a,3d484fe3,d13b9646,a6f1edb3,777a526f,a48353b4,eb06031e,1a2327cc,99be4b06,836a3bb8), -S(2e865670,19aaaf33,c7833174,333e3f9a,bdd63c7e,d25f0af7,49f2d7f7,a69bf7e7,69da2079,a30f2791,8966aae3,b3b9f8e5,fc150b3e,e71616c7,ca845174,36ee5c24), -S(ef7a8374,943df2f7,5ed67507,df3c1a2f,abe2042f,d66e97f9,4f6e3490,1dba9ce2,6b93d053,481b8395,c77dc3a0,6abb3125,7951ad9d,d9d76190,1e218bee,8bb6b4c7), -S(2d097904,179b400c,165cd596,f57919d2,2d7b0535,8018d528,aad0d3,23583478,9f9a0ecd,6976d6a1,6936816d,95283e18,3e94cfd8,9f384bc8,3573e695,35e15380), -S(35b46f8e,231424a2,314effda,3b610f4,5fcf33cb,799b5db1,6389b880,93ab66eb,5e97fbab,a0b89500,d9dd3e4,2cb68439,ec7eda2d,f1a5d6be,24186be3,212f8648), -S(eaa55e55,c4e410b7,2e599063,f4cc976e,754c43ab,a0df3bae,825a4563,fbd27711,13966980,3ba07091,faaa131,71437472,67a75d15,3f5611db,91d4f27a,80aa6975), -S(310c9ee9,ead99f8b,fe9c711,f93357a,e2639181,176d4a6e,4ac84cb2,2a52d6e8,300e5486,deb90657,dbe417cd,6aae423f,bfb00e5b,b3077fef,b6b8a166,10fbd172), -S(de1383d6,2eb93ae9,81f87d12,7811be58,fc373b38,893f0e7,6a417a82,95b27bef,f86aaacf,8704cab3,f0715f93,3eccc9e8,203396e0,636a55fb,ecf76440,7a2ecbd), -S(f5bfa7a0,28beeef3,1fbd817e,5ef6727d,5b81e76f,179fcae9,f271960a,51eb954f,ec3fc89b,ded5bac4,72d79d7b,19db43fa,ade10bb3,cc43d38c,f38efb3,f9ae9f66), -S(5e67e65,80b858fd,df24ecbe,f0f3100f,4378ffb0,7e382ff,f4761ce9,226d29e7,870a1da5,663f1be1,4cd642fa,d7eae191,d50fc6cc,1146882b,5b6eeec4,f1e80123), -S(68cf070b,60e1778d,7c9a2f66,b6abe3fe,23c2e090,f4c59618,a37eebb8,e7108ea,f09cd61,f52305c8,803a2346,65f76a14,49d2fc53,8a4122cf,8462ec5f,b64652bf), -S(427d23db,3ff49c5f,8e693ed8,d88a9ae6,339105cb,cbe2195b,13f39e46,172abe8e,25f4ab41,24ce76a6,a59cd840,de87daa7,be30fe64,59829f80,2caff723,efab49fd), -S(18c3c0e9,810d5353,7963dea1,820a41ab,3f662b0e,ad0fd5e0,8b07806c,e3bc1110,da91ee74,69e89a86,eb9d4ba5,558d9f77,d3c41201,e0db692b,8f7cb583,da4b41dd), -S(f16661c4,dc6130ec,79c47737,3794193f,7538ca5f,2560ab19,23929a75,ce4a74ca,a225ddd0,d3c3fe76,adb89df3,9987d46e,4b404343,6cb457d6,c3a13583,3b41e05a), -S(e467d2da,4ff404f0,5a1fcab6,631ff889,b8f5809d,64328225,7c228589,cab00ccb,86c1f60,ef5aa2a9,5b262e4c,d539a3cc,6839d704,f20938dd,7b93f958,9f461645), -S(ec69c75,520581c6,4cca16db,acbed064,20df5851,b3b13bcf,299aa02e,4473dc92,7742d8f3,96aeec3c,b27d066a,fb640236,ba38722d,e1ee4d2f,d0c9d810,3dd14d85), -S(21c0f26f,1e5a08e1,3db7581b,86fc8869,f7db1689,c1137223,7305f875,65d3c5db,e799f72e,24aa785e,13de622f,224af49f,ba408dbc,22a935c3,2e3909b1,2da7d775), -S(a49694e1,2feea444,ae028e73,e7c56924,7ae4c7e4,fd7cda34,425aa039,c4c13378,de760a14,58c508ba,f8889c90,35478a55,a8ffdfbb,4ae61802,a364832b,5735b599), -S(1c49af88,e3dfe13c,69e470d5,d8680b17,b2f3094,6e94a5e9,5de05936,d556eb71,3466dec,96cdc49,54957fd0,3bc9376e,7b53b222,ae5f5765,a6645110,c04e8f05), -S(e445bedf,aa503c85,c98cc507,86724a03,d6bda967,ded1752a,3b688844,485c0829,2eb37e04,25589c02,a1531e24,ac1c2df3,497cc81e,3ae51641,cd57db8c,f70f2ae4), -S(1fe3fa90,70496133,c6ebf718,8a076453,91c67d39,6d88f09c,a8244c62,242b494a,35a8b8f1,20503992,20568f9a,c5d0d90d,4a5d1d3c,b9a7c2ea,a17561d8,8d40e61a), -S(658dd6fa,63d1df2d,c9d4045f,c9726e55,2eef2721,90c3c437,29f4a01e,4b775b43,442b482,b77df6c,727f58fb,51331d0c,7604f8c,3da01b77,40f71ba2,f6219bde), -S(57441b8a,6787c3d9,b87b58dc,a66da1e5,32a8e8a,267f8961,fd1fbe3,3859fae0,fb065a85,9675effd,307fba28,226f1276,95f6ee27,389b6959,ea9ef704,ac460e9), -S(432449e2,51582cb8,ac8d232b,901d4796,63198f92,43c1ac42,f66aadfc,a79ece53,d5496156,87c64c16,c2bbf07d,c94e754d,af680ea9,47beb11c,94394c11,a27454af), -S(90db95a2,b17842d5,37c4aeb,42aba933,be6a9cc2,fb23b9,457e35,c2e6a77c,8e10ba44,21a6d262,a4129852,d6f1eab7,2e885bc7,1ccc8b5e,9023e504,2bd751ff), -S(9a7c6aca,93149860,cf4bdb29,fc8dfc1b,84d30bfa,13728f67,ef3bc6b8,1492fdd8,48beecaf,c66ab57f,9e5aa39e,76887725,3ca4a8a9,b464df58,3d86e8a8,f8b126ed), -S(926c02c8,cc70f343,9522fc18,29308f6a,3a1d513b,f632d3a4,cc56f7fd,259de58,229378b2,6e0f48b,de2b0bd9,8364599a,bbd011b9,918e1e55,cd7a0bae,a8cccf2f), -S(264bd086,5bd54674,11b22adc,f02653fb,d483fdac,1682a210,54aa810,9c9cfbb1,75032c4f,a101f117,a042bfbd,5b0fcd3a,3991875a,d3444ca8,5688e3d2,1d2df64d), -S(a2ef67f6,ffacb94b,9f28432,f27bf1b5,ced82580,8c46465a,69e57f01,c070bc1d,2ea53f94,5c1227c7,5eab61e9,a508cbd8,7730d9ae,73831322,80eb90ee,609130e7), -S(940733b7,46fa83a5,4acddd6a,76ed1e31,80daf833,7e014783,93641ce0,3c9a3657,c5a9ddcf,b2202a32,34f736fc,996cb301,9bfea0b0,21988946,8112f5e4,7abe6a11), -S(95e6b0a,eb191afb,10eb0ce8,bcc7c14f,5990a9c,c63da64c,c7bce7ae,1a0d9b48,80698f50,f7ac67c5,4d55911b,cc88d764,83df654e,9873c039,d854d7ae,14a92980), -S(edf7e7dd,e79ad130,1b7c8d7f,ad000004,298a799c,7d08cd94,38b0fecb,cbf5df2c,ae1c98c4,1a7b068,57786d39,169ebf92,ecd60d85,795fe484,707970b5,e7c33fad), -S(f6f75f2b,c0fe2cb7,8be2ef4d,e728e06b,e17f6350,4267de70,1a9dea54,736b804f,11d046f4,efbfef4e,9029f632,e1603dc1,196b710a,32173f07,94dad87c,f8095c84), -S(185ae081,d470ff62,7e73bbdd,3a7fc5d1,df1eb46,733fda26,8e4001ec,fd7b7b94,cf57835c,3a69e46a,5a58ec1a,2c0ff80f,4d8020c4,eef5e1d6,dca1e260,4b2e22de), -S(a93647b6,1342281a,7fa5a92a,48c3379c,4e8fd29d,2113c07a,792e1d75,ec4abde4,b2260a18,e6a05f66,998c3aec,201ea4c1,545ccc98,606d35df,cd671d7e,5b53fc9c), -S(27028628,171d1083,7d713e7,8011a818,81125514,dab8eaf6,846595c,d99cb5e7,99b0fa18,eccaa210,29e5437e,6d561f2c,a5174f49,42ea2f3,b640ceb1,50ceb025), -S(d560c4ed,f442947e,5a99d3,f2f8e519,b61f5243,322aa725,a3a68249,50318281,f403247b,70998349,d5eb3d38,1041616a,ad8697c,6a06643f,8d3b786e,707f12de), -S(b54c07da,a18196e8,33173c51,68d5cf7a,1cde555c,80621501,bfae82bd,2043406e,ee83b25e,300e532c,b09ed563,5b1e1a80,48fcea5c,5b41ed38,97cd2c32,8846b3a7), -S(5e43b2c2,8365005a,fb52b971,ac372448,22ed45b0,9cb6d829,f18fa481,91a5780c,6b3d5dd,951ff60e,4533f783,aab0276f,aab00898,4a4899f4,a31a00fa,a34bc760), -S(3a62aa88,99bf76bc,a23b39dc,d6008d4f,a57e9b1e,3bb69a90,88b77407,49b3ce9e,d83de010,f65c8320,810f7079,8de4f3c9,6e293792,841e7178,d894ff76,135c0951), -S(69ccd9df,9cfe0990,440ff050,7a35ac47,6a0ba786,56c775e2,7677bf59,e5c37594,73a97d37,48f1c24b,6d5c814a,a5829f0c,8589212f,485ffe5d,d86d9868,14bb537a), -S(9b2e9201,51d8b063,95823db7,83e33a7e,e35c092d,265eb440,bcd0a6f9,c9f89c5c,ab125c05,dd565f17,93033058,cc0a0ad1,f6b32ad2,90d129e1,6032c781,ffc2e331), -S(9af6ad84,535f84d9,4d80a592,943c83f8,76360fd4,787ea16,c6f6df4c,b9d92eff,a443e538,895046c2,9cb80270,7777ef63,ee18acb0,fa028a16,d7be8bfa,c0b4e5d0), -S(e7fc44df,cf4eda5e,c982a8a3,1a72d69b,b2b39f83,3dc4e621,bb002fde,2277f4b1,64fa8e8c,f2194013,8caccbe9,8808a47b,bda56376,d9b02ce3,33e36558,365637b4), -S(c820365a,3c6cbff7,273c80b3,f7ae7278,f6f4e282,dca68586,1fd23693,a0dbeaf,adac7864,cca90280,13bb3a68,c3d235d0,dfb3b99f,749b9203,9b03068f,f229310c), -S(3f97b6b9,235afad6,a4cf1eb3,dd3be029,7d67625,ec18972d,62ae4b2,a1b0de3c,a652fa0c,7fc89c54,e11df8e9,7650fae1,7cd51674,dc44be18,26e70b90,12089f2c), -S(74f315a4,d12dba88,1ef5b14,14bea596,ec386f5d,5f6e1dd2,f5e777b,c8c3370f,fc994b03,bd5a0461,9ce52114,4915b7e4,f9380a77,8a15407c,9b8a96d9,e7999c0f), -S(db546b02,795e2435,e8e6ede,3a45fc8a,1cbf311f,d0d9784d,dcd956d4,79d37b40,f16a6c,ab9dfb8f,1374440,86f1e513,79e54030,db4153b2,d2c06602,302ca383), -S(e1ce9f95,c8764028,b707f2bb,ef2b4d0c,88adeb47,f0469924,e2659195,6a53183d,358014fd,987f41cc,8f31856d,25a509f9,d406a68e,82a68fdf,1e1d4afb,99de59d7), -S(38f1e3,e35f77d,76cd5847,9b9b2c92,e90bbb3,d8793cec,509b29cc,c0fe13ed,faaa8e0a,a9a943a2,a5bf0e7f,a2a95079,ead33f72,8e1a3547,e55c6d63,3e908264), -S(143da00,da92138a,609b62da,8e90c19a,44b89be6,3372913,fc8cda65,44740ed7,2d042699,25782d78,8f6d8f4e,7dc63ca,570fb79c,ac2e5691,65a8df5b,38089686), -S(93819e60,23aa61d3,f015f747,d74ff5ce,d3437f2d,9c25d9a4,dd5ee0d,e4bb413b,3496f668,113975c2,4cee563d,5a5fe406,5e68b1d9,afc95e8e,2ebc949b,5779955e), -S(247bdc8f,abbe756b,a35c9f77,2c00836a,51cd8c5a,d2182e56,81f4f79b,2c0fbfd4,39dee166,712fab57,95edba10,8ac84b0,3ac90b43,7e22290f,91f0899,7ac3233), -S(282c681a,c67c8ec0,7c399e8e,a3198c41,a7993d37,b9bc4042,b0226d45,353034ad,8d5fcf2a,d66a9266,788d77f5,5fe4830c,6025c26f,e9468d95,3271d2a5,61634ba0), -S(e0e0229c,b260bfc1,a5979371,5bc7d226,eb9a8989,89edb9cc,5012a2d6,c05657f9,5321fb39,ca241eb2,94c69885,502d8d25,b85e414e,f540b713,e9fdbdde,ec0f50b1), -S(b8e62275,85d52f64,88a76515,e8c62894,7b9b01fa,1a7bcbea,9124dae7,b8a05447,84a564db,e14aa687,4cabdb11,7ccc7e20,706a7a54,c4c23689,4660ea5b,6d0a189), -S(77f3be41,2e08ecdb,b8443431,8e71c69,e6613ec9,bb2ec577,40cf944a,a3e12abe,39b45913,a90e014f,ffae3a15,a3bf44b8,7ac121b9,fadacbe7,19af320b,b9d35124), -S(350833c6,8ceebf3f,b0e5d4a1,749838f8,c60a673b,a7015eac,dd1050f8,eef646c8,ae37f219,cae837b0,bdfd2899,2625868f,3906564a,70ee0b90,92f2b24a,a2631de1), -S(2ee6a70,4c8083c5,3f88dc2a,aa39258f,2833d3f3,600b1a4f,61101e44,bed8d5f,589a8a8a,d8e32dd1,c7e54ad,d2b6952d,62017da2,5e68dda6,aedc696c,77b4dfa6), -S(156af2de,75e81831,2e6eabff,ffb82dc8,b5fc207,4fdd6341,b98597da,b22a6473,dfd13542,36d0407a,e0659ccc,b7eaa304,10bb4afe,4afb4221,4e70909,15d4fb18), -S(396d53f,5a488086,9be37006,e07a4638,496ad4cc,80c7554e,3f4b4939,5ba18d38,a7a6d320,39f05345,f41e2792,77bcefbe,10983280,f56c17bb,943c253d,7c094b0c), -S(15407e62,684b2d9e,4a8f08b2,31010bc,fe42c9e5,f85378f8,904e649,a759c7c0,54ab28eb,1b91562,ad8551f,47f41c96,2516fac3,3af933a0,75c757cc,e381d3dd), -S(80fbd75b,1538f0bb,96f29ebb,3c50682f,de0cd2e,e9615f1a,4b8c1b76,3b2090fa,cc3613a6,8608dc75,97870658,3d478a33,21c3677f,516cf6f0,6fdfc253,3bc0946a), -S(c795f08f,f5458042,f6268079,36fdf08,bda3ab0e,5281fc3c,447df53f,25aecc93,1524dee6,b98b74b6,616509cb,77a2a5da,2871b1cc,78a7b217,3185c187,223b88e5), -S(1c39286d,1aca3eb8,36bd90d4,e46ade42,ba8c0b1e,43523499,ab151e3d,7b331e6b,4f81e790,e66df7af,b4725dac,b506bb73,4c299afd,21dbbfb0,a60055c7,ebf119fb), -S(e778e362,f5f67d32,73c861ab,3cbafbc9,eb03f7c5,e862b5a9,2b7a51fe,26daee5c,1035cc76,9df9e120,7a71a13d,37693edc,19fd6ee9,33fae651,a145cc60,37ccc1dc), -S(d71b5cc5,56ba74aa,a0ab5775,cf0acdee,54e5c48e,5cb08734,6e510e1b,18f9a914,f3c3419e,84b4cf22,31975aac,e31b9b36,9aeb4a3e,e2b2bc6f,feffc3fb,538e8e5), -S(819e3ba3,6f5b1011,64f3e798,764e01af,5838ecd,e6141690,971e562d,a99d0520,da38a00a,838d85cc,f606c440,b941f128,a66b0216,544008b7,a4904094,7d7557c), -S(3c726a07,740912b5,560bca0f,f8d827fc,a9f2b1f7,1596f922,218a95e5,db2c7048,b9e52f48,ee2d0944,3c5c5776,eef02a78,47cdf47c,b83316b2,220fbf00,4b3d72a5), -S(e2b550e7,189f0fcf,a897fe12,245d6912,e6743828,b0ab0d78,9faf3865,d90d1d1,11dbf946,3cefe572,f45a5288,55c2a257,43dbd70c,3db6d012,34821a0b,35ffb115), -S(4cd65ffc,23acbe0d,59471667,44ca1194,f52dfee9,ba532725,508eff79,61130fe9,9af3c41,97fa257d,79fcbe93,145fefb7,96bfb0a0,3914ade3,c1127b41,9e321a28), -S(6fc537e5,4f7bf705,bc4a7a1e,a7cd365e,ec36f190,dd4fc7c1,ec8f5f3c,8dc63c21,d06a12b9,ccf770cc,f8504b97,ae68c61b,1872d500,54db9cfd,76a55c29,58eeff4f), -S(33bdc335,cd76ec99,db66b3f4,d90ad5a7,924f343d,836edcbd,847350a2,10366223,2761ca74,ae8bd215,b74fd37d,9d6527c2,c10406db,fc5932e9,d408c2e0,ef554987), -S(a4ac1b95,e9a8ce4d,da11a1b5,c21401b8,b92d9bc5,f7bbcfda,3b1940cb,cc331dd7,8f630ccf,30f68759,174b4052,8082050,599c29b2,4922c1fc,e4a5952,61c2e239), -S(6f34af2c,86f06702,4f720e5f,89d45fae,f44a8976,2b0bb390,e9a7ee72,fdf07842,785c4f09,d127954d,d6e6dff7,e342bd1f,5540448f,ca390d72,485b2967,b6ef1825), -S(37ef099,8571efbe,bbfc5350,43d0fcf5,758d78cc,3ebf247a,cc7b4f59,480aae80,29a3b2eb,fc41f793,66bbee1a,cc6fffba,76d37631,f10136ea,4a47a18a,d9263c78), -S(3d815c75,6c6d730c,b3d7ca6,de486159,f0035011,851211c8,25bd59f3,624b9056,56e109c3,e6ad3198,48b2e00d,1168806a,f0a22c93,81d8a243,53850c4c,1c486cc1), -S(d3143ac9,845ed52e,961b9fca,faecd1a,ec6e8554,c90357e,ba2317c0,c832730a,f4276188,6db140b,4d9b8b96,1e6555ea,a80dfebc,8d37ddb3,a21e284f,50b1dc73), -S(5b0066c9,221d1b8a,3bf660d3,ef28c3a6,8c611dcf,943824bd,ba4f2a8f,836b03c1,86a24204,f40de381,21be77db,a23a6e3f,5c8ea5eb,7138d218,45d8003,cc8460d8), -S(62461176,e6bc9c4c,77f8636c,3ffcdf24,45ff5c98,935e4b76,1c4e50fe,c00b606d,5431f12e,488bcede,ac9822e9,5797c2c4,5a49167f,6989a6cb,601ed3c2,860c28a3), -S(8efe7f7f,482ab457,4a7e56b7,77a7b5ff,dad6e208,2261b9d6,bfd6c647,c88a757e,ef5e2083,ceaebbb8,aeafa383,d188f30c,7350f484,eec83262,8d9fbabc,522b072f), -S(4dd8e450,5ccb49bc,2ffacdeb,53bad1e0,362df309,5756505b,33eceb64,34ebe715,9f801ac4,243d720c,eab5def4,7a7e6d6e,a051d3b9,783a2b80,aacf087b,b575b58a), -S(3a345a97,85c7db9c,b5661c97,3c739949,c48253c7,bc36ee32,d4d74878,3b0cb734,4bb7a957,d4c8a2c8,e1229e1c,d29af780,ba844bdd,a0251134,5da7fd4d,30223818), -S(d76335f,3e14a6d8,b8d6a87c,7f8d96bf,ee171c24,276feddc,a52f17ec,74cd3ed6,dc2d6c21,590edeb3,a9014b24,fb8a6ffe,e99c0f0b,d8fad1b5,2175f647,d5be53ba), -S(25fb12e6,2e05fa71,57badcc2,ed5c53a0,89a55b1f,4f5b508,f89fee83,b309727d,c73cc2fc,4021d267,7821ac82,f5803218,d4ebb736,6fb22f98,62a98f9d,6e597928), -S(6ec69e2,970df6a6,52e50e1c,2682e39,66e60120,6ac7fd61,12dd1446,47a11783,e9d08d09,1148b329,6a8c7b7,f9e4588,8fdb1179,72e08c56,41908b1d,127b7a87), -S(f72d2f36,35701d5a,a19309f0,12d8c5a3,7ae0784f,699a200a,bca89cad,57b08db6,5081bc4b,16c53997,46f2a35d,e7d59b53,8956b57b,865a99dc,e8bd86b0,259888c8), -S(945fab90,e970531b,766f939a,8c1a5cc3,c43a5c7d,45b96983,ade1d042,13d2e46,d76f827c,1eb775ec,7d5946cc,aab05b62,97173b32,54407669,4bf194c7,c84e612b), -S(fc60b8e4,129df265,9c335842,a099edd6,182acfa5,b74110e7,7880281c,4f582b77,69cc15a6,11c54e60,72db1bc9,9af6d289,f647aa85,95006a83,8b3a91a9,da33557b), -S(a4e41222,f9643671,390a7213,e6d0f5c4,9722d41a,9d0102fd,818f4aa1,6e03f5ec,c1636af0,55a67855,fc6a1827,c9e3e463,88922c7,c769357b,4f4fc4b5,3af2307c), -S(b1749fc4,8c935c8f,f2dbb7a7,2a69524c,83a7d551,88b48ef2,30f0306,a156a002,43efe91d,ee498afb,4f47a4d6,51ce132f,fe1fe875,da143682,c56d936b,dd7dd80f), -S(407b881,6141cf62,b8c87b3c,439290f5,6be1c590,41c847f1,f127c8c,c4b913e0,c3c90c06,afc5bbdd,7c699eca,5ae24594,69735dd9,71bd6b0,e48db6bd,6b77bd8c), -S(b0054fcb,94060a29,f983b713,79ec998e,34e39d5b,c5e0c271,ef48ac4a,e12b3a18,e2b89e84,5aa2f8cd,8ff2d240,72c0491a,81be7ad6,1e8166e5,6619e928,7d37c2fa), -S(4c202cef,fd6b69f2,33efb265,77e327a6,b47e722b,1b8b6477,2372f4fe,7559e5a,1a04446b,e69535eb,3f10d334,38049fbe,e0374b53,54f2f46b,5cc1de16,59c3e726), -S(451ea6f7,c1e9992e,b50c5ee2,90784052,a9974a8a,101da027,753575d5,1f306ef6,ec8cca1e,a21e21b2,cd0fb48e,dd14609f,733b32e5,42cd1c,a1ef2acc,6396cb81), -S(1ae254d6,686a8a2f,135fd775,16de17da,5175a82,aa8599ce,45b1660c,b5f65d78,a2595603,71a24698,626cfd82,7efe6d46,d8c4e31e,1765ca1c,e01ef584,4a5780a8), -S(d358e246,514e986,b0b8a192,53e07db5,5a635c01,85d7f39c,666064ca,cff640ac,d4b34eb9,30620b9f,eb1f94ab,8f88f3c8,8d8a9a5f,4ff35528,df0266f7,d4481c2), -S(fd4af649,5415092b,e61abb8b,ea2827e,3e833f5b,4653a1fe,7e9886bb,ae454b54,9743ed9d,d30ef4ef,31ff9df4,e5d10272,1e5c7609,b539630b,ab555559,88b56965), -S(4286c7fb,d1b785d5,a778f72e,2574bbc4,2912abdd,ebd9f6ba,15bc6c23,c7700cd8,3b0c1d36,2f62cf4d,f5dfdd78,1414fe1a,64a5526,cd36cbed,8e41c740,56525e71), -S(2262acdb,7dce598,ec0b2419,2d761dad,8b413bb2,58444c1c,bebd1693,a1ed597d,c6bde565,87f6e506,4882d86a,6eaf0314,20107b26,9b57dce,e9ba48f4,d9a220ca), -S(b8eba19b,a6057f98,519c319b,cd3566db,8a4a53c2,f3d825fd,9646dae7,13fe7b5c,7bc344ca,fff215eb,cc8f42f6,6b711406,7a00e881,f7e40ae7,253fbba3,bfab8273), -S(d49b8d30,2d8a1c2,ea6e8302,33ec1fe,371cf035,57c2c45f,d0148df3,1a43b11f,6f1052e1,18fd6180,1694b106,8e1d8cea,f72b3e68,ba84d0e8,ad945fb5,156dba1c), -S(56db7750,350da2a5,c6a73239,13f987de,9b4ba04c,9f0c0fa4,67d53abe,129116a3,e4dc5c13,9b72462c,bc5b5200,68d27c73,9599b40,d17c8581,1caa69fe,3a429fa3), -S(1c987244,7d133050,8368960e,7f63a52c,ae56a840,cd19a359,d8e94720,b3f4d54e,9d8d1dab,8efaf90e,f2bbee51,b0e9d369,abc06979,48bdc1d6,efd1c18b,26dd0ec4), -S(e9bfca61,b09d2298,3f1657f1,f303e0ed,f9650830,c3151ccc,eb7cce77,7865568b,6c06c996,48a3a164,a57dadbb,304d9d29,75906d64,89e42292,63d4a86f,b4a82642), -S(52f86eba,9c3ed139,83704865,ad0ec3bb,e54dd2b5,5841fe8b,826da573,213dac7b,59bccd99,a53fb65f,1df73e8f,eb8f4734,67f1d4b2,715745e8,693589b8,d1f24d9c), -S(ac02234a,412dff76,e01f6ff4,a3bab5b5,ff3339a0,4ff3fc70,eac1bdd,f0eb88f3,768d7219,782584c8,e16818a9,f8ce5aa8,18228c2,21a7dfa1,6e9da56a,61227843), -S(c2e5044,2dc773a4,d0c3d1de,d9883be,dcc01c32,c83b2a51,3e946212,8551336c,30063e65,133d1c40,607c2cb1,50f680ac,43195e5a,8ab68add,5ace3977,4242b689), -S(fa02cdca,e19fc987,a7c43acc,77328914,741ac5a0,e150e9bb,cc6aa0ed,9c16287d,ad7e7b78,f566a226,99e27510,2a03ddbb,de7a5e57,58fa52a7,f198dedd,7f27f72b), -S(805110bb,99a2b8ce,a8dfa8fb,e4bfa353,ece63c67,22adb161,9c696d2c,5aa66939,aa0e9a9,df1a2a11,72fbdd30,6ec86d84,e04ec973,79e16505,5273bbda,4fae3c8e), -S(6472c6a5,55be3145,476b3cbc,9f1d5459,be137d1c,c4cf7a11,6d28a722,f1b8960c,d28a0da4,2cc3ce06,fa16e4e4,dab04b2b,eb74d8b7,8b09632,1d02ab86,b92b0afe), -S(a659d5db,dbb45d5c,af7a9893,7f82e6c,c37646f0,34411e20,e361d595,28c4fdd4,d064e26d,ac724089,90947031,27256e35,745ca0c9,696da250,adf2df91,1a3a05a3), -S(882a7c39,56bb7ba3,f3d20df7,d0645bd,b13db6e6,2ba58f31,82ce4efe,2a0846dc,627c82c8,82437a35,1ebc003a,4035af13,63de299a,52924337,a4162a0f,c5bb17b8), -S(5556c236,9f7c003,d5fd2451,8c4be1d0,9b11b2e1,8961522,68e5cdcf,a6282db8,384b8cbf,13d9adbb,7a2fce16,38b71729,aa70d754,37dd7427,8cf98135,bcb0f1ae), -S(f268a877,472c9305,e3c2b193,303c29b0,a6fd2ff0,fb1563eb,ec5d39c0,def431b4,5dd08bbf,c1b8cead,9b45f164,e6323f7,c1bf0b33,bd9ad8e5,c553dfa4,cb42a634), -S(fe3438ef,5cdb0229,2c5d392a,387c38bf,87e453e0,596c5546,aa27940c,7686a90c,5b3baa2f,76647870,95c3453,64f59327,415d6aae,9fce79d5,85222afe,8304b998), -S(51216a9e,54a94c50,f2c2ba07,9548a51c,8345dcf3,b38a7e70,1a3de47c,9d5422fb,1046f888,360c5de2,95d63e16,93463bda,e3714f16,46f74ab7,3b6d68b0,15df71ab), -S(326d2470,700341,9ba6438a,b7ba4498,957e919f,f748590a,130857f6,d46386aa,7e31c242,cc2f3ea7,d5579be1,8e216b8d,9f69e360,c03af079,636bc03d,2090b770), -S(cd5abed8,a071a8c2,4d379611,4d81f490,5e644884,82b2e2b8,3eefbd92,a98947b1,f3d6560f,e10eacaa,9a30cde4,ab852b49,3ef0add2,f6d83db3,5d12b0b6,705292f1), -S(4482b5fa,c39560b7,7550b621,238fd8a9,5252e8f6,25fdc8c8,42382845,8d2e27fa,c1d246d2,145041cb,ef8d3fc3,8b5a1237,fe400256,e4d2588c,ee320733,f6884933), -S(1eb303,74179ee6,76a977a8,76ce0ef9,71ca88b6,615f3729,cab3cefc,6080caa4,a9293fd4,a0a156d5,f8f735cd,a60b9ef2,bc6004b9,efcd12f3,a0f5c16b,5524e421), -S(542685da,a08f407,71cc90b8,bce723cf,d2f6e616,133adcef,7908fbb0,ea29a4e9,df4076d8,44a4d3a1,10126bfa,344fb3a7,79f7455a,a9abc99b,7429eeaa,989b5d44), -S(bf631fa4,5277594b,c425882a,85a361c6,d62c50e,aac20ba7,ebaa596d,d6801a54,69995b4d,f20f336f,44681ef6,6a65b54f,88d43953,6458ee9c,f7657389,94e53bf1), -S(27be809c,5bb70530,ee629628,18a4ea73,540f1e6e,75990926,3269a205,604e7b53,a5bf709a,caba50ab,ad939c56,1abbd0b3,fdafaded,3b82d9af,964727dc,bcba7b3b), -S(40126263,3f3af376,4bdd2a6a,c1c6adb6,fee285fe,1171a29e,af4d71c2,5f03b849,2ffbed36,47815c25,5d5bf7d0,a7f09dfa,8eaf79aa,df9e95ae,57024960,ec98fe8c), -S(a634b11,bf441eff,6ae8eee6,dedba52,6377cb96,e3c36a7b,4ebf02de,42146298,57c555ad,85f0e194,2f9701e9,1227e0f7,42763296,2d0702d9,e81e025c,c411d379), -S(d6130997,fa2259f5,bac49b16,38d224ed,f30786ab,c7321e10,d593b932,27745905,ed5a448b,c2157699,b436efe,6725f8b2,8df8282f,1a588692,41ca7db9,6c66821d), -S(4a313361,bed4a94f,b7d9f1de,a1feaa4d,3d957379,cc24d880,92dc29df,5c503d72,2e4e6930,b8e33e50,d166f862,a4f73520,63470e27,f9d9a3ec,3382d252,e42ee20e), -S(6be34d7b,5aff85f0,e731e6bf,285b2f79,eb241c67,df9aa3aa,c2574e5a,d8b146e6,a9ab3f20,dabd0073,5935255,925676f5,799d14d7,75c896c0,de451057,f0112f5), -S(2e42de88,38560214,228691ae,26a0a26d,fd96cee7,9416439a,e771891,3499898,6ff846c2,72393037,a2d0b2c,da38539f,f8d3a6ae,175fb604,55afab50,8454a419), -S(d65d003a,c979da6d,9e4b077,3ee965a2,f33e512c,5c20a9e7,456fd3d9,fb5b0b6b,fcf12ef7,6fd89385,5ade4bc9,4984d7bc,63406649,d4525f1f,3c9f35a2,6b357f0b), -S(f58d02ec,d136eef,67ec91a2,6fc5097b,74c01db1,911c2685,4941f56c,af6b10b8,14169b8f,aa3a5512,55d3eb4d,25ece18f,d802606d,f1259504,64f79587,518561fa), -S(fd13b1c,d189e832,e3c06cf0,6277474c,3e388979,e0a7e925,1799dc9,a9713b9f,a2838fe5,4a07d539,5392dee5,dc2269c5,9fbb222a,8541f3c0,7fb28cd8,1ac2283f), -S(bdfc6941,424ba1ec,88ecff53,c8da31d1,ee6ac442,c8a1e58f,5171f4fe,b808d41f,a0533200,4e7582cd,a824600c,20864fa9,b8286c7f,2107ff82,9b5c964c,dc4a3531), -S(a390ea29,4096bf15,e953986b,86893c37,e2cd18b3,5a0df983,5be6ba2f,8a5769c3,1b432110,1c37b5b3,147029f7,aec437ab,cbe82b5b,559e9446,a2cd4067,9a9b5b9b), -S(40a61a44,a356f623,968e386e,319bee22,574f2f41,f558cc5c,f8a9b6e2,93db0ea0,745b1083,a9e9e080,365f95ab,31db5c6e,9e38c2f9,62bc4e8e,6a879768,f21998fd), -S(2ab87f5e,83538093,e99e09e,468a0056,5db6e308,2bb072bf,b7f5522a,24977f87,49a22c4d,790450fd,f31f8199,1084676e,7cdafbbb,5656e2d4,bd03621,bf50cf68), -S(656e91bb,156468b,821fc9dd,14c3ee76,ea8016c8,92133d2f,189820a5,81a964c,d8d153b6,870c6ce7,a4db4eb9,bc1f75bf,22f6c3ff,74865118,fabfd336,c7ad73), -S(d2c9e2ed,7cf8c21d,8c078e70,73c8ea8c,88e7169c,abea0a44,5c6c339f,82eca7d2,2db2942f,ee70cb15,56fe1d30,d5bc94a2,3d748e0a,7ce8735f,876e9931,90552a5b), -S(a5301947,cc6e0053,7cbd19ad,db91d854,67ab1bac,1a5e9862,bf46ebe9,a2d14710,c36d3b1,d62195a6,18f5bc12,61680ea8,1000f37,86f3ad28,3f516d16,f45e7cb2), -S(1f61d637,80113793,5cbe0dc5,34042617,932efc37,c3a95ea3,57575ca8,7280269d,24dd91ab,4adfa0ed,9369d30b,70a25b1e,df9b4383,37d83464,7fe064c9,e2ba5de4), -S(14efe93,49750c63,81d61000,4b80c733,204afe5d,223ef3b1,e45bcb6b,177c633,d8e284f0,ee2f4826,9c958271,3caf5364,6361294c,a0aacdd,a9aef70e,8fed2bfc)}, -{S(782d5c9a,d970322e,deff2e7b,57844184,c589a4da,c042fcf3,86c1a9f8,26c1babb,27bba565,405cb392,64762d97,cbaff552,1bc38b20,56afe313,556542d3,f200eb06), -S(1c000fe,9372bdc3,68d4d6df,832c0396,3701cefa,bee1cdc,3965e183,3476f636,1792668,89cb19bf,39633363,98df43b2,9d2eb378,a9a30531,9d33ec1d,a571eeb8), -S(17688e97,d3dd0dff,1f43ced0,af969ed6,d0b53f3b,22c1f1dd,240f4bbb,253770c4,bdab9644,b7047941,f42ce962,4800d25f,54dd194c,6fc74eeb,2e1e9779,3e4890f1), -S(c9e92b0d,e85dde86,8eac6f6d,1eef4b4a,8b25974e,7b77cb,fc210530,b595cdb4,5aa94a9a,7210e6e2,e04dda5c,8250c8af,16bd5081,f2102f6e,a9d09265,8b4c4ac8), -S(c9efbd02,5f6aaad,e30ec696,e5e6739f,ec6e89dd,9bec22ca,cb2a9142,d7bdd284,f32f9e4e,dbaa0a73,135fc5d7,7d2cdcc5,80c357c3,144bfa1f,e05e70e1,c8888744), -S(25cf39cc,ceff3fac,e9ae5cb,e6e6db7a,586f1fb1,8b3c444e,28cb2d19,ba08ef4e,d3b55fe5,3f11624f,f6c25252,4928226d,a82128f2,4649c140,24fb1f17,c9ba9742), -S(262a25d,36253456,cabab430,5be8500b,e2fcf871,1c580d9a,a76202fe,9e97eb39,873e797,bf2adf55,dbb3b0a5,a2480c30,1395cc6e,477f39d3,520e1a1a,6e61440d), -S(3041bc09,6dbe8a9c,9e436f15,bd88954d,b2e1586,5de92c9e,8f8df7f6,456665cc,f17d1d17,e406001e,1aae6cb1,ce4c8889,4a502e40,1a0f7f04,3f8daf4b,a4ed4345), -S(d0fcb1f3,8d32d3c1,5a0d984c,f9eec4de,22e0f400,b93c0343,337f98c1,db2afa4d,de5133d3,f7920fb1,4d34b28e,5058d81e,e9e312a7,17590c98,aa242e98,92f8356d), -S(65f5da86,cd13e857,f41a7016,9e62e05c,628506ef,d1739ea7,5308b75f,510f247c,5e52e176,38b22cfd,8f1f800b,edcf0af2,1efce458,e179da1a,d046e0f9,5afad4b7), -S(a4ae6a21,f07f51e9,cf635714,e0cd35d1,d31fe32f,22d29ffd,16af4bf4,65c859df,41a69d4c,ff1abc12,8831efe6,e410a22d,80790640,5f319692,46fc3bd5,2589c094), -S(d92d5f09,79a47bb2,e995693a,e005c266,54d6260b,85f41806,89407c47,69b2c5fd,1ab29589,87b2e4be,6ed6eaa,fc47a9e7,49349e9d,1eb438c5,735dfb9e,d77f2e8e), -S(f0f136b0,787e1c0a,e43e3c34,66d77cc3,64282ca3,4b686a23,eb30622e,c50644b6,1fe70372,b3047ab5,242190cc,6fbc18a6,4dc0797,d51b2ace,1eb208cd,30625ebd), -S(52cf110,c8a81a1a,f6ecba15,7b6e2748,9fade773,20b22880,ac023ebb,3ba95119,eeb4e114,2762e0d3,42ed393b,c3b01a2b,e7534b34,c7466f91,224519f6,762da31c), -S(dc1f1041,76019cb9,e5ba446,f1601edc,77ff662d,e69a560e,2795243f,e3635bd8,29fff9f1,d8aedf11,5f518298,4b82186c,1c2b8e9c,8d80bf5d,c0a8b0e,9598700c), -S(dac7cde7,dab3d68d,cdecaf9,3b4a1985,ba099d97,eefb84c1,efd5b103,1559bd5a,53940d9e,785b017f,9142dfb4,4157c250,7a8543e2,c52150ee,8ec1910e,caaa36e9), -S(42500318,5ca69e1b,c4413ba8,ed3949c0,bc39ee8d,10b543d,c4035f57,7f46abca,5c187b2c,936e589f,66ecdee7,dbafbd48,b184a1ba,4ee9bf01,f70327f8,7b80f384), -S(1a8728b1,3cf2ef6b,d122df7f,ae11873a,fdc4aaa5,46981212,616f7a35,73fb94bb,3c6e1732,320fa8fb,7bc908a1,93204afa,aa22e138,571bcf1b,b0b31285,2cb76d21), -S(9963b507,f4fdba39,1312782d,35446a4f,a1247315,29a1894e,cfa86138,22206031,1b7feefe,36616571,f904d548,4673322f,4e867016,b60527a0,f0e4ffe5,97b7021d), -S(5f98a8b,93016cee,48a8bac0,6553c0c9,c3f0af5c,4ff969db,237f5669,ae7c4f12,ef144971,69e32124,d0ce4525,c2ad7857,43a62914,ac21c954,a1f0f6c2,4cc2d091), -S(ff4d4fee,875ebc10,fa6db1ab,19941a6f,b934ef14,6b2f7299,cb7ccd74,5c6be029,10b3dcdb,2a753aa7,e2464ce0,b021eabc,3643134b,9acb6f55,955dc471,8a5bf46c), -S(ff159279,11c229ac,f5f0aa9c,67cb98e6,309d16c4,94a95808,91bdc404,e2a1636d,5ae15340,a7e94020,108e0a07,3e775a92,a7eda92c,ceb6af56,cc91ace,e8991e1f), -S(652bcc4e,a1c2f450,10273043,2cdbf01,3e07aa76,7f5d8d00,a48ff9c0,b97d73f3,de96c171,173cfa8e,66174a45,e8899d12,f5ff50e9,481f6310,8293075d,cf5d524b), -S(8d33a9db,ca44ca87,634d52ab,c325f892,14330c84,d6adf84a,3a2e5ab6,ace8089c,6ac0fb1e,2324dfdf,546dfb42,37a523b4,1d8dd5a,81a6c398,2ff14f6b,c68348e0), -S(b7356428,d0f718a5,a999a4b0,cd55332,b812920b,26b5c5a,babf1afb,3c1ef230,60a1a61f,17e4a054,921d9187,30807530,3c0c72f9,1ef469da,743c8a55,cc58f62a), -S(bf32c76c,c733c2dc,85299812,392a2ee6,5b0ce661,93cecfb,ed2ae522,48706aea,961e28d9,a6dfc6e2,3b7a1235,4b9551e5,bd1da617,f8a4d985,467de1dc,bb2b6630), -S(68760c7e,1b0b625c,bfe9533b,fdc4df7,cd0acd04,de4c4e5,cbbda233,4d2394ad,b0ea6bb0,f9c5c9dc,91af54ae,718c3ff7,5bbce1eb,ef353006,3809ab3a,4432978c), -S(abfddef,d56b2944,ba1548f6,dae0e65b,40e19431,b6415380,3558d497,7a373aab,ab40ea01,23588781,882e332c,432177b6,15023347,b76dc121,be5a0a71,f55563f1), -S(73800767,7aa92884,93ace49b,60923a7e,e3adc2de,78c17e28,3ae967f3,72145ad5,fb1552b1,6fa17e4d,1dc2bb35,95b1b1d0,5dc7e48a,ea07fde6,7e6f7c75,f15f5267), -S(50c0bf3c,6e3666c8,a1a69544,90590b43,996e9a75,77c87e0e,5bb8e927,5caa4ec1,d0f80c96,1b75680f,8264fddd,31b52c28,48a769bb,2976d706,b922b46a,277ecc24), -S(879e4cb0,47b3138f,1a5cdd5d,9eab5b47,a9a8b542,83fc488c,f82ab22b,7dbf2f47,5f607d08,bccffc0b,27c2f0f8,f8a80476,52fdc19f,eeb62b02,248447ed,d5743bca), -S(6ebb3735,465dbfcb,32bde807,471e19af,35d5568a,ea6f5286,4a382596,df623bb7,e2801ff0,8e04b574,414d4844,b7b1efe,8741c0f6,4af13080,ef473397,3aa0bdf8), -S(5997354b,9b77dda,f34a9ef8,649904fb,fc8a0223,1e8cf882,7a8309ab,b209f420,d42f55c9,4d8054ad,7dacca4d,8d7553e5,355db690,1df155,5bd07574,25e9580e), -S(41e392d0,456f7aca,f62f8c96,37881d25,8b316bfe,7655ab56,61413f43,4e428f87,20481bd5,36bbd86d,96600911,1da82106,2c55ae0e,b2f12d81,a8b8a1f0,4309af91), -S(5c3514be,60fb6a05,2303b2ff,ccf81ebb,5734ddd9,ff2b485b,429ce68f,3b16ae64,573f787,958b70d6,36565295,b35d9e73,7ee46c3c,d1d1ef0b,e37828bd,eb80e579), -S(de9e95c1,220bcf2c,cc2acf7e,ceab12b8,239f5531,e2c52949,29e30daa,c340ef7,2e20a50c,94476926,ded26edb,72780f78,81f01cf6,bef5b1dd,5051a27f,abc2b181), -S(29922283,6619c2d0,402ff634,ee6fe671,b0afb7ca,cdf4d109,cf98814c,af69adac,ad3f5da2,7b1785c0,b958af5c,7e9e7a85,f6c7002b,3000c25b,f7e82207,fa9ee9d1), -S(82f8b1d4,b50025d,fe960c1c,600eab7,45a25ba0,ee052eae,2f3e56c5,bc236561,97ff7a9a,a3fab00c,54f8bc06,fd59e050,b854f7d0,53dd2df7,1e93d75,60456d29), -S(4b883553,72c3c528,b8edd509,b8eb2b21,92e8504e,da5087a6,d2a3f9ad,256cbeb6,b0ec67df,a34acd1b,a3a68b3f,79962c17,11c0bfbc,3fbed2f3,345cc097,c221aac3), -S(53cfaef7,ff6b8bee,f6264a1f,f4b796b1,a5d3d1e8,471504c8,d6ea5d2a,5362644f,35697dde,1730762a,2692fc5b,1db386bd,1749e07d,a67ef310,47deb9ac,394ab691), -S(c4d4a268,112c2adb,d862b32b,f344af89,4e070db6,2262daf9,244b5c2d,758e1cad,c109c651,2ef251ad,9f9b55b5,10c973e5,dd6b2746,996942ea,7e4de0f7,cd8a18f8), -S(13d63ba,49b043d8,ce6a21a7,929745df,668a2497,5a57895d,704b4f9e,3bbd0aa2,d52dd90d,6e418aa6,afe2037,80870e15,78ce6dfa,c1a73879,490b57e1,c1f06878), -S(4499275a,5e03c1d5,2ee69082,9bd53365,6dc44a6e,6584d2a4,3c27ef78,fa3475a3,4f51bc3f,56fac2ad,3bc36d35,b47bfc56,b3885e3a,9c279c86,83762bff,edc952c3), -S(e526f9ce,24911c8,30311aa,82e8855c,575c9e2c,553f7392,2285fbb6,caee91c3,e56c2c38,28c7432e,20b490e1,3f6c2476,47040253,7b1d851,31690263,a41ced87), -S(723260d9,c31cf302,acafa19d,ac90ded4,18d5945f,e5fe302e,e7fa8e84,b3fb2449,bf7b11aa,b5603f1c,89a8d6d,ecdbc47c,9bc0d229,937cffb0,8e4bb060,d932f6ff), -S(5895fa08,76ae7387,41184045,d088aba1,61be9802,33f8820e,7eb1f9fd,dddbf76e,a4dce1e2,d7a60205,197a8458,d566e8e3,720edaa3,bfc4d946,f798e438,ea3b3c65), -S(c358ae6d,c1565fcb,623c2c2e,a575ad86,388dc893,b9153135,af4e787b,17c64c9,f5a5852e,e3826ec3,e20a0d05,c330338f,f28699e4,ebd749ff,3abfc3de,edb3b97b), -S(efea41f2,599d5357,5314ec4e,7f36b564,1f31802b,ad030d6b,cdf8ef63,4c1491dc,5dd25fd0,45ee4019,c2d22619,e47da1c8,1c4062e0,d6a9bc4d,fb37c6b6,7b9c52ea), -S(8e939129,e1547a83,c73900d5,4adb8bdd,79f98d70,3c9c7689,9a7b3f35,8eada2f4,47b19f53,433c6b75,f8f33cfb,3aa91908,b8acc5a6,a69bb533,711cd84f,f497ca86), -S(e5f3fe2e,ddd45d3c,745baa9,fd812dbc,dad77d5a,aaac44f1,20f92515,53681f79,a450e661,a13cab2d,758eb49f,4e49907c,f9ec8207,bece14e3,e3e80eda,cafcda1b), -S(727ceca1,f1985b59,e3b1abcf,400972e6,87f83e1,ffe30f64,c853c8f6,35f4a3dd,c451b046,44e83ef9,d078367c,3cb44374,ddada9d1,9416ac28,db60a12c,fc526fe9), -S(a98a9e68,da05a375,80c0633e,216d76bf,151a7921,32ecb2a1,c114c001,3fc095b8,26aac75d,f680f14b,ac3cc30c,5c14e782,3b7be308,ff8ec2ed,1551737b,2e213c33), -S(2dc1bed0,a25f6024,3ee2e20b,90158ae7,102b43f2,c781f91,86dc6d8f,768a0ba6,85b6b3d8,509d7c9a,ec12d44e,453456b0,c881212a,3c056d0d,827f5488,f02e581c), -S(90cd9e84,5fc1e7fd,28f28544,8b9459f4,e22be67f,4caeec44,2c96d77,3f6932bf,63c92e01,1cba5199,3311487,7b208922,1cc6a651,b160a049,cd558e90,3ed560e8), -S(7ad554e9,61e1084d,8be77d43,e8aad732,5725a9f8,3ba29da5,6ee8e21c,8d6f15b0,9e13367c,d9b38a18,6b8306e8,714cb709,12619c2b,56953ffa,9c538383,c7b36e3f), -S(e39f4f35,c68f835e,b84acfc5,dd5a9c4a,84263b85,376ee9a7,e72489df,c96fe3e5,3f06c83d,60b5eb27,f6d8ed32,1d38630a,8bf822b0,1eb97f0c,90d2d9ba,c1fe81f1), -S(e732ec5c,6d2c9f2d,17ce26cf,99151e74,31aa7c07,87a9cbf8,65611936,5458124d,51d3e77,e75c44b5,4576bdfe,36cd28c7,9131d0f4,b1cdc356,dad51aa7,253e077a), -S(5cfbff88,130d394b,c0ab5ba4,b79ac89f,f78a2c0,fb3f7f35,bb3b8c60,3eef9596,18aca6d9,58e733bc,12ba085b,bef5173a,6990eab2,59bd6d4e,e3cc7c5c,7bb5516e), -S(69d1998e,3a0be330,a6341161,76adc83b,6d2dc4d1,2b985924,468790b8,25b182c9,5d8435fc,6cb17de7,65b628bd,2609a81c,a4f8d081,337be0d7,89cfd817,583849bb), -S(4fa189e1,1aa8d445,aaac9fe,b8bb0fc3,a615ef8b,5db97120,b231201e,1622d7a1,ae8130c4,164090da,706a5f21,1bd3389c,8a08418b,36c7b248,a9ce1c7d,7f62a175), -S(5b8c0419,17905a9b,7f6683a8,ab52261,bdccab65,9d70db3e,daee62bd,a0647a44,ec7c14a7,ce63910d,4ce729cf,e1c30a22,3c74fb05,eac31e8d,876487f0,cce4bcbd), -S(d8911bb9,9e908660,34a55849,84a7eb49,2f4e2ca1,c1f99d3b,35fe4d58,8813df71,c479c2b3,4d9d5bdc,c82e1f76,c2aff35d,cd71c0a6,fec01808,a0d35ef6,e74631a6), -S(9691f765,417f4841,22baf14e,c65afb44,8337b915,dc85d449,c6101e07,9ec94981,d3f163e1,a69a968a,223e2ba5,145d0dd4,2a8cf4d,baa6d247,4ac5c965,3cdf7049), -S(27299a8f,98275592,39b42976,bbc08787,30025475,79c6eaff,4f959156,61a47ca2,cdbb9fc1,bf25ee54,f5524fe9,c5d70a59,3f849ce6,b9ef2b72,c9d85c57,a0f54974), -S(ba929ab5,abb7da7e,be263049,558e3e68,397811fd,9346890d,ca890f2d,4260a31f,78e7195a,1d6fa4d4,a73d3b25,125b9a70,1346492b,962f3587,7e5b8a40,7b94e610), -S(5d065bee,93ed86be,f4d96ef1,cb1584a3,7723bca0,1c696602,ad27615b,a0eefe84,592a8fed,16b03476,ca7c695f,3e934da7,c9ae43db,6db95bdc,e313ce85,8d6efabc), -S(89c311cc,2cddbba,b5d183af,2d6013ac,f3682f24,7c51a9b6,fda419fc,5620678d,a3c6ff3,9bed892f,5fe084fd,18e7ff3c,4facd6ed,38afc3ba,becbf4e1,67e086da), -S(85d1158b,5ece0b13,97a5d9da,35880f77,fba762cb,58d05c94,ea27a97f,8b84daab,b8cbaf1a,b3f392ab,f70830ad,b7bd69c3,69384f9,4c2f11f1,476ac91d,f171c46c), -S(9905e022,d0d9504f,f9acab48,49be95e6,f95e1c74,f28a8281,7c6e858a,602f65ec,a1552c6e,19467331,f78f6fae,71de8604,504b11f9,66ca5dd9,8788597d,b52b88a2), -S(2cb38e47,c18dda23,10852993,6a668f2e,aa5ddd2,b1acbe2e,8d772c00,18a0b513,6ae910bf,62e0d313,fe326bf1,55e44d88,c85c61f1,35862d96,57237a8b,42310ffc), -S(b98cf874,dc156aeb,f85fe931,af406e75,2e4a7738,bb22db42,5a853949,e152dab8,bfd9ea5f,e8f9fac4,bda888c3,7e37e2e6,73d3262d,8cce54ab,f923fe5b,6afa964), -S(b907808b,678f8eaf,b29d69f4,5f62d8e7,990be642,1f62087e,8002216c,5f75d851,8e01d556,f9ab18ba,711596f5,61294f50,432b429d,5bcf101d,2c7db554,7f2881f9), -S(158c96ad,32e36ffa,1b67a345,a650d15e,e3caa5f8,eb9f391f,f14d04d4,a3299700,f63742a8,a8d39d2f,da081040,748d157,18c9bbc7,f228a768,afabc69a,7897dfd8), -S(cd62d2eb,1ffa09dc,e6d5596e,fd6627f1,a40e1d6,46e58d0a,99fdfda7,1e1d0665,9d0d6f0c,3e02d85,b99b723f,90acfa03,38c1e021,bc8bef01,9fb0deb6,ad41836b), -S(1616a7e,c92bf575,713bf433,e6788774,2ffb6c2f,f9ce2db9,f0df6149,fd7acf66,baf4dcc9,574957eb,aafbc4b9,cf6f913d,198cc26a,d98d9640,364bee25,6c76c22b), -S(e7ef9ff3,6e86908f,8cd68871,838ed08,2873771f,2df1ee9f,a74f8943,f2f46a3e,ed95ed67,65626e66,8cc8860f,b268b28,e9e4784f,4d704af9,3427f645,4f65e081), -S(9d91f868,ddb1beb2,a986d7ab,2e6c8da7,65e2605e,e1cfb07d,f368a30e,239b16eb,55ef3a1a,284bbb2,d73e4fbc,2f92ed35,b332c77a,fb19cc90,ec98d964,dac6f8f9), -S(609af9ec,3804a542,833fc7a5,bffd7bc1,da753dae,2de2e9b8,296b7327,b04da33e,fe876bc1,8fcd4c30,5bee3437,77a27231,c4e1baab,cd0afb37,9469c085,c416c8b7), -S(871a8cce,60560ca5,83896884,9bc3c7d5,3d9dee7d,ba988495,16258f64,23ccce06,2b557be2,d08dd1a6,126c798e,ed1cfe84,340aa979,c38de116,dc01e442,39418023), -S(1475a480,e6da65e5,ff84f5fd,d926f302,6ebada5,6f32c036,c7cc1375,db1df8a4,1e35a8a8,b1c38922,555357d5,69ef412b,dd0338a7,54e58ca8,87d09cd4,7e9fcbee), -S(4e90a94f,cf609448,27b69ac9,7c758057,9aaf77,54e068e9,db68f50f,6d46f68,5a7532b,13f4224,b51542aa,6e94b984,651caf84,37a16c56,1583d227,8099cd22), -S(bf8f311,7c4a9500,8fb70bcc,2442cb8c,bb5be275,f1631dd2,e86edbd6,6e239845,2f8cfd98,1dbed87f,4c51d621,8b308d4,76ee4e60,161509d5,861ff2c0,72a0cfb), -S(ee46cc95,d118b3cb,6c37dd09,31f42988,ed324ceb,9a6cf226,87fdfe13,1bac0cce,4bd94958,867907bb,4823a7dc,9e3deabf,a3ec504f,a4efad0b,146ded5f,3fdc67df), -S(76c7cc03,ca94b2fa,ba2aa8f8,b571d57c,6849461,5aac6385,11e28d0a,4345d4ac,89e964e7,d0c2bdf5,de3be34f,886d6b2,8955cd32,5e92ceb7,b379aed3,b216624f), -S(ee37e6e4,bc5616e,59748645,72e2c350,d43b1f5,fc6c672b,524615fa,e6a5e14f,8b721572,f7fb8c3e,a108c05a,1214ecf0,4443dee3,89fad7e3,86b054f9,1f0c3d5b), -S(e1c7ae02,561bd2f0,1e64844d,ee3df837,eb647df5,db64bae6,96c1312f,d9a0775f,932381c1,1bfe3926,37921d4d,7e1ffc39,8aeb52a5,b113d01e,1b78d0ff,106f4213), -S(6aa0b3e3,98f6f75e,f13994d9,91cdd270,c025c754,67ddc374,9fc530c2,7edbc255,5282fe89,2d97a94a,e4c54bf9,94d9db69,8f629f58,fafcf7a0,e18f85a6,574ecf22), -S(a4c83267,3ea49743,16e3aa95,e5d9ad46,30818d04,58c6783b,5f305e04,71b7e980,10eff981,dff167b0,119286f9,453ec889,a98ab7b9,4acac35e,f8a39745,2df75661), -S(d5b2a546,81726474,55c45c43,a5e900f9,4bdb83e8,8196e3e0,17cbde94,c2f2cfab,d0a76d60,dca26b92,e0a91901,d9b414fb,eb90155c,89ab67c8,351e15e9,da1bc7e7), -S(c7ee2daf,b3d220f,8865a578,6b070507,533d0b2a,3ebf9379,da04c68d,fc5bae5c,ed030df9,e07b915c,ef0dffc3,d2d24cc3,55a0af4c,f6462786,7f322b21,78420cda), -S(1327686a,b3a0cc7e,59a8f6f,c3cfacde,ff6c17d5,9100470b,94f04bec,ba82b09b,1ca32583,151c8774,6a84b527,313c79c9,dee0cb5d,3043f584,6799fd7,abd0d07e), -S(1b245c2a,3e49e7b4,4d35701c,f6b69597,9df760e2,e65df3d2,b16e8a5c,efd065c3,7ded9046,3a7b9073,c30fc599,eb8660b,f3073166,4fd147a7,d5c33903,ec3f046a), -S(d48820d4,c768c172,43727ec1,8b7d4824,ff214bba,1f079eed,828377ee,e386d651,7ccc1a18,5b0018f3,b7911938,21a30185,c18f3586,9d34dddd,4da1f76a,a06ff703), -S(7dcdd09b,ee384bef,55bd4591,82b7560a,aced0ef3,9037a661,317d911,38562054,19b815f7,c2b8370a,e4cbb9a2,facb11ff,b970c050,26ef5aa6,e92713e6,f5cfa3a0), -S(19b26e20,cb023c5d,f474cc3c,12a80528,aaf0150,bd90a19b,9f7578b3,c9624a85,71ef67ed,d954782a,a3fb9bd7,c7b747c9,e9101ab9,2778c401,18c96ddc,d1458273), -S(9dd490d6,f1ae170e,598c17b,3acdd8d6,f50f32fc,9f956bcd,8e2497a1,5af3f29c,e62680d9,4f21d3eb,4ea278d2,66c4bce,ece6c1ab,e6fc068d,ca9d72f1,21bf3903), -S(6f12b9a9,71263232,4c15a533,3726f032,2f634d81,964e0b15,b20dc998,b085998c,34fcccbc,b4177216,24471698,31fe129d,a90ca8d8,d95a62f8,cca5da0b,505d0b3), -S(b011c854,19c89036,77c6023a,bceb8a0e,496c2021,e0448993,87880eed,9f5c2764,afc0603f,aa87d081,5449686,d9ebd182,1f33f675,35d7ab18,5231e8f9,6c5cfd8a), -S(c7ebbba4,5d2c4b92,b71b0e50,3f4c4e99,d9b61fd8,e3bc100,dc3b6b42,53444c10,8c042323,c7a16c9d,32654e6e,240f5c97,901fc2,2f6e0840,de0ad053,7afde378), -S(95d1bb83,27dbe838,bda8e60,7f23f193,f43996bf,5a548270,fd296f9a,7ab93eb0,d15aebdc,f5432a03,3ddbd8e4,42433984,d1726068,634fc49e,ff0dc9be,e843842d), -S(94897726,856037d1,3e009a99,cc799006,388a0eb2,d34541ee,f548ec75,585abb64,7552c109,7343f999,9d97f0a4,ed65910f,f1d7ca9e,542d9b4a,3ecec791,3abc4920), -S(77b0dc2a,158cf2b1,88a98be7,d1b3c1c9,fd9b2c94,a2bdc2f9,c3597e77,e8572823,ff3dee13,5d130bb,c5c12bfd,73f73aae,c510ad84,cc9aee31,f28ba147,e99554f4), -S(47f7ddb,bbba408f,fe233d83,627582bd,a4d8915f,4bb5386e,b0b039e2,ed3706d4,63c6280d,be656fa7,81389b03,1d70ae36,6146f7f6,4fd736a8,8d9edecc,a45d2710), -S(b6561d0d,9673a6b3,4005bf53,20f74c4,acac0fab,d065d10f,8a61d5d5,25145020,dbf3f35a,9bcf58d3,ba3a5534,5229918c,a4461f1,8ae692a8,aeebd8cb,1e66782f), -S(fbff78c9,1c67bd4d,75d62a12,b679a4da,ba352a0c,73ab0d91,96ab06e5,c7e7052c,e2266fba,7e71ecf7,a6862bb5,84b1cc9b,6bef8697,fcba312e,649e836c,fa0fe837), -S(fc7e1250,3b630005,f488c776,9730f43,f5a4848,edaf869b,68bca480,22f85ac7,f8170409,f312edee,fa00b1b9,b62b463a,b7e0ecfc,563bf6f5,543ae7a7,10885247), -S(84f2f115,9fdc3a58,df6a2971,9e2dfd7b,165d1052,4eff49e0,6ee53a9e,6101f30d,50557807,24376a0c,215e44cd,ae1d1dab,619c324f,fcd5e766,89176f71,363d7998), -S(41f89dc6,3cc4169e,e6dd6317,d9aeb671,c5e0f0c4,c29c1621,b9fc1c73,9edb5a14,29d608cf,75a44457,82694ed4,32924d76,79a33233,2e62b4fa,cbad3643,e6ff9e36), -S(2bc495ab,ca4e5879,fa277a14,6c07a2fe,98a07db5,ee5a145a,e042b578,bb4e9c17,87b9ec1a,79d3d68,b822a80e,721238e9,c2a75c2e,aca94cab,2fb731af,f964de60), -S(4b18ea46,1f6468f4,f1f6b709,a00934b4,818032ff,61297f0f,6a4cb057,8cc4cd90,4f491b20,32837a07,171da3d,2acc4191,11eaa82f,db36464e,fa675944,a2c4f986), -S(ecfdc56e,c44009f,1206b7c3,bd3113e3,178e3909,68d6d2f1,cb85ce3b,b951e61b,5085e948,5b4a00bb,9f09efa1,17f83987,6711a043,1c3dd794,611b2c8a,c795229b), -S(6e97a5e4,2e911bba,c5f7ff6e,1c4fa9cb,9d12deac,2c13e8e3,1baa9cd1,3463a8a2,a86f92d4,709c635,f98dcdc2,e93d66cd,a541e49e,aec0ddb0,6b1c90bc,e692ccdb), -S(265226b4,253a201f,bb7db973,5558a4fc,e07c26e4,245e4743,2ab0bb89,e99a804e,51e617ba,10b8b90d,67f565d1,156557af,a967f03b,85400f9,975864c4,f5c2daab), -S(2ad97868,5a488eed,838560e8,b071aa47,565c4bf0,67337584,c20f8cdb,b2534169,8cfd2d8c,4d7bba3a,9d9afcf,2ee1d594,1c3aec8a,8e532e1b,def7e232,b3ae542), -S(457eaad,8c46f083,56a2c593,a65b3d7,74ee3292,bfc812b6,526aff72,8ab2b495,3bc3068b,26008298,5186ef55,7c9c6731,795ff1a7,34657d65,e97dc564,cad5a019), -S(dc83dd36,3ece98e9,636fbabf,96610f56,c74d0518,6ff0658c,e1e96aa2,8a488c7,ffb4642b,9f07e134,a3daae04,a7895645,ac49d6de,7cf95131,a9847514,786b4f76), -S(36962a9d,5731fdd5,379870f2,6562feb8,38f733dc,cbd6726a,41112d3a,c9df3cb4,efa15b5a,bd55c577,82e95c2c,12e54992,d9728e70,31566878,85e19362,8d55af3e), -S(494fa294,b5ac0d72,fc6f7f7,6b7e60d4,f8ec6399,dd1f4465,e57846b7,32210ea8,e0b00b97,71079c11,2a5a6e32,613c5d0e,420d1a5a,3212b52,71d0dbfc,4e6d16a5), -S(4989c175,23783475,36a6fe53,a6f135c,a968484e,f7305e4,f80b6d95,cf41b30,75dd93f7,f04f06b8,88a19ece,4811c5b8,9992825e,9be07f8,c212b660,13cd7017), -S(677e82d2,8b74f3db,73a8230b,98729acd,6b010356,5ba148a5,2438a5c5,436b6fb5,1ad2444d,b7b84e6,c4e2f573,cd2fb644,f3823c6e,81a574dd,bb4777b4,e26ff10), -S(c379002b,e70b8de9,80af55ee,bb05eb6b,ef0beb5a,102e2172,687f85d5,b9984d21,127b0907,fc511741,77cc7f9a,9b36c334,c23d1d72,20267878,391644ad,dbacf331), -S(39b33368,5aa7ef10,fd223b41,3c375334,38d06cf7,5b27ca06,3fd5c8e9,22cca4a7,88aaae58,acc5c41a,807e644f,6cc1bc3f,1f147174,994e0440,ce678f78,d783433c), -S(825be64f,b35ce8ed,85cb6826,79ca7677,5a40bc3c,105828f3,a8b30595,ac3b6b21,976a3b6b,dae0f22a,e33f3d36,7d3fcf21,29f2ac35,e8239df4,553a869f,18650183), -S(47d9d5a8,8bac6136,ecf568dd,ea7ececc,57f26b88,6fdc05d6,4c5b7ae1,113d3a7c,c6863fd7,e05f3e16,c0a47eb,6c2b0581,184b8d8a,550da1e2,370928cf,4d7b2804), -S(bb7576df,abfd677d,6545db2b,69af7d62,20ba17f4,f4ae2881,8ec91a0b,23487df1,b5df0436,9d7227bf,67953da0,ef410f0a,a7cf80c7,4f3c8c89,de6cf1b8,7c65d16), -S(6febeee9,251bea0c,d43eff7a,da9dc5c9,5b86db1e,b0e09bc0,4d34fa4c,4ead4508,df691ae,ac9bda8b,496aa808,949d348,97166b32,3f99c9cd,a851f68c,26a1e39), -S(25fe413a,59744683,ef244175,a8021b6c,62e7c2ef,c6489261,958167e9,10716fb4,8be281f6,2df1bf49,8823c080,69849a84,b1ce138e,2326db32,cccab7e7,8c8a1ab7), -S(1389327f,be427f53,f219b978,4faae37e,8337f5a3,1c377bd3,415596c3,e72bdaf5,fe33fffd,a7bb26f1,34340613,ab692eb3,9a24916f,37b66df3,194ac53d,1f9c1a99), -S(1a3221f,30f9ca00,9e9b3e7,ac40dd45,b7b37b5c,1cff9c34,25cd5375,48f6fa52,7a105b3d,25b763f4,15fc1ff4,b8b3b964,9c1f0317,a6c4fa25,d731a120,562730a3), -S(ece7fa3d,55e6b94,4c6beb50,b6ae339b,69ec8a46,679e11c2,7c703056,4cda225d,68be5c5b,fa975326,e5bd41fe,7187ecd6,b83ba698,ec98a7c8,9c8ff6b,d207d5), -S(9fd0196e,91eba507,74f75e0f,980c4737,ac7ede54,4be0a8e2,c1a852b9,4799d10f,bdf3d80b,fc7ca162,76417e3b,b9caf72a,6e94c84f,c42e8091,d3eefaf1,ea790dfe), -S(db89a9e8,703f23e2,13300b25,f952df32,853691f4,6fa6bade,c7ab775e,21a80fad,504c9ae3,c9a9e7ce,ccad44a,8f97502b,5577db41,510b3e13,8ccfa64c,2fbb0a31), -S(32e762ff,a1b84c7d,c3aff832,a838d555,a9ceea5d,7066ae6a,efbbf96e,5f5c5eeb,ad842a97,ed1f274e,d3bb0460,309ce41b,f7e9cb55,c7bb5d3c,3b2b662,daf4c419), -S(8e7328c9,93fac58c,17d2c9ce,8a3959fb,2c0c8c7f,a4d583a6,c4428f9d,98f5d1ca,b5370e52,815ba519,3fa02e95,d75a7168,e1906ae5,12cbec72,4bcd1a9,b897b8bc), -S(dbb8e270,d516fe0f,470e325c,37707a03,3607ca5f,92c6f2c,97c32f86,1418ecf4,3da4b926,7cab86e1,7bd9442f,f3bf2c41,52aef531,f1d028ed,e801215a,7204fa86), -S(5dd9b4a,bc618666,12cd3344,2d8e068a,fe624850,1cff8c33,87af5881,c3523544,51f5b,a9a010dc,6e5aef1a,138251aa,dd75c5fa,caa222f7,db2d4218,220fbf44), -S(50a74f67,90a95b14,67eaa018,9409ba38,7edc5abb,4f2c408f,5bc6a5cc,6724ecb4,d32f7031,9f9162eb,861255fa,42495a6a,fefc8949,d36150b9,c4d5b066,7b41031e), -S(11721064,55ae2391,2c2e35fd,190ba29,6bf1d580,fc76cfd9,1fcf6a02,e77ac992,158165db,2865,968604f6,3fbd298d,3a079619,a0c161f1,35879f14,5091a41c), -S(570cb8ce,d29b407,f5e4769c,57c42796,b1c0b111,684c5a7b,fe9ecf8a,20b687fe,9826e697,97573a61,26d7cada,c636530,ea747b41,308874b0,a4fa578c,b984814e), -S(5adfd4e9,142a8f6b,1ea6aa3e,14a83fc0,7e1df246,279082e0,36b8e2b7,dcc30637,82314ea,36edc02d,c489c36,c2b0d808,d64167ed,1cb33651,418e3c08,7732c97b), -S(b26f96ee,37d49fc2,e4e76f4d,257197a6,f1c667bb,748fb69c,29d9f033,b94419a9,bcd2178,aafa4409,329d735a,60bf2fb5,60706e87,295c6d7,a7a7e0c9,4b280542), -S(dbbc5fc1,ea84b079,90bd1af4,fd244599,70bff024,835ae3b7,129f6caf,290c4bd7,78612296,2b62b621,6f43f734,eab00121,ba5a5b3b,81090a4c,ebe2cb8a,5a02591f), -S(e4d32dd2,710624c6,94120041,36639e21,708cb3b7,a15682ea,57e80ebe,a13738b9,3aaf833,3a7f31ac,6d6c8b85,e0831fee,3db67209,f35b0362,3b153677,6d7a4098), -S(81c6fed1,b687970b,d3716384,5c35061f,e9edbb33,bbaa609e,53a835b0,c13d6a15,934cc11e,e733fb68,1a575c98,cace3279,7a6fff4d,6bcbed2e,89836fb9,3b83597f), -S(28a654f9,58003817,95793,46ddc440,13c07f78,79c3b247,e52dbe27,97a02852,10de9cc6,571f24a3,6a08fddc,1ed27cd4,a9a0cb11,5d275d99,ceb60676,43773965), -S(532c99ae,cc7305db,5cac0294,e25c0a0e,45e270dd,4f621f2,d1e36ccf,51cb7a48,8ee3619a,61df9f49,84259ab4,744f563a,bbb45462,9eaf0670,5240d67,6b3240dd), -S(de02390a,37ec8a18,2a5891c4,f8041ef0,d548f367,4e8a91be,9e29e0ec,2b822e8,8ae501c4,32e81681,844fac5e,86bcca09,aae6f862,76994d93,7074c1ce,c3a04b33), -S(877916bc,6880f1b9,530af368,1ad44238,dcdb76cb,ef1d3f61,6856566f,bb6da5a8,807bc5e4,5c400875,42804d76,eab0f291,499622b3,dc9a7e81,c1db7839,ebc5a5f6), -S(5980d5f3,4b0c3684,a3381a84,434436fd,e0a0d6ea,1c8f16ff,b8a35793,74c30e9b,9d20e10,5e51e720,95d95766,7f479f61,34051c24,b09c8a2,125fb9c3,6a0b4b7d), -S(5246fb5a,4fb10bd9,c240b274,93abbfd0,e404f444,13f0a126,5d8fae3c,ba805fa9,8aad021b,c7317328,6ab78e8b,3e3cd613,9d881233,d1f62cd0,9a3d6260,88886c7d), -S(9b5ded4e,dd6f9c11,c3e9e760,71a7e257,74d2ea6f,c87412e1,a918f2e0,fe2075fb,80fad92,396c0f77,216187be,66619a53,d6a6ffeb,1ab70ca2,d64b19bf,2b0a95bd), -S(d2d4c183,c4ba3336,2aff6d81,263a5845,b76d1e3e,6f5a0a0c,928a1887,da2b03c7,ea15aeaa,b602f360,f3a7faef,fbf2725a,5838d041,70455d50,6ec5e1bc,ca651b2), -S(222241f9,b3408b3e,a8f7bc96,67ad4928,183557f2,754b3972,d5e938e6,36ea7857,cc2598d9,4621a8e0,3c8b444f,bc6b68e,ea584144,c770d095,b2152891,e6bde708), -S(14cc26c7,c26fa386,e29204a6,99b24119,c8642d24,256e9fa5,407bca7d,4e69c32d,9b125adc,dc2150ec,5181d2b5,5a862dc1,4de72a2b,7a04e912,cb2f6503,24101dfc), -S(292a1480,959eeb3b,468d54ff,2944786e,7702bf4c,8ebdf837,edd65177,1d5a971a,e7355cf3,e1c089b0,9362b68e,83825a25,39c88058,8dd6e1dd,ecae9447,ea4b6388), -S(6c9f4196,a35d0a9,f0517c9b,2c04a420,127140b5,ae9d2274,cd5eeffd,140ce3a,854d6c38,df5604c0,1d65c8f1,9f5e89f7,4c6b1c9c,2756fb9f,8276088c,c39dd80e), -S(fbd63ec5,8b3e0c43,4033ea2d,f4a8cd55,b4b4d24d,d1f8ed5d,6d8b1b6f,a14bf30e,e3770f0e,7b29f62e,9921f8e,2a78d2c3,a62814f,97caf2a8,304a782d,b72c6b50), -S(df91d6e9,b046fc63,d81d94b9,aad17096,a2c7fe88,b95e423d,edaf12a2,4a2edf87,2cde227b,ffa27e95,ded3f142,41d26599,da28da39,16227b43,e665aebc,f67a9fae), -S(b2ff741b,8b5d4cc0,aa987660,59652337,6ac36083,e784a181,63f653c3,667fa2fa,400a34a,e6990fc5,7e268eb9,ed2ee2ff,dcbb27a1,26f0c7a7,937617d7,19e7b0be), -S(d156797b,9de0ad57,41b759ab,38e8f935,d352b464,b01080ce,70e22376,8d6b5e23,b7e64c4d,fb332c98,9d21c2ee,67a5d5cf,d728bc07,9b448283,55d9e6d,4b0fb3b4), -S(a3814ee5,e242a6a4,65ad0681,a0193dcd,16538d6,1087c6de,fd362a8e,671e7ed2,3be12033,59d441ba,d59d88a5,64d03ce0,c67a5d18,4f883388,96f7caa9,e3dc96ca), -S(6aab0cb8,b46728b3,8b78d386,d45122af,c95bb1c9,9298cc77,299f2fd2,b5d72586,fcdcf718,caf0c93d,1f3ec76b,b4060f8e,a3863736,a5d966d7,c617fac6,6f530753), -S(5fc6e596,7b508698,4c99666c,22fc7316,54b700e,55877f73,169241ff,8b759937,57af0c61,76ffb00,626a98f7,ecf72762,9746b0cf,dc8a8914,683cc49a,6d568505), -S(7f3944e2,bcb3cb25,e36c8479,ed51019a,a61b1122,ace99dc4,82ac38a8,580c6d2a,dc039090,54244e0f,6acb6d33,fc4fee58,8e5e25f4,b23cbe55,5a330779,872f2062), -S(5485c8db,86078936,14fb7a19,73651f6e,66ad843d,e92db2f2,c4db2d5a,bb7316f5,ac39c239,b0fda325,44bfe05b,1a4ecfab,7ccb84c5,db2ec999,6d8587f7,d15bb82e), -S(e52b9934,910510fa,3611dba3,8630853,d0cfa8e8,ebd64a2c,7b59bde5,edcedf2a,cea4d745,64e8df98,d47a3ca8,7f1e45e4,728e52df,f383e391,6dca08d1,326a7e38), -S(92b17ef4,fb8f8dd7,e0307a,672b37ee,78e0dfe3,e19c094e,44a50c9d,3ad7faf2,5bd53e68,dbcb4e47,18266085,9d12a34e,943691ee,dd034cb3,1eef8a29,e35b762e), -S(7f8b2952,70f6b2e0,84503f9e,df24fb8b,e91393db,64a90971,5e68b009,aa9c3b6a,c45f0d84,d9407856,19a87d38,296f70d2,41ddf1b3,8f421d12,fd2be1a9,32d2b437), -S(cbb90912,403439ab,8d04714a,1a5ee460,70202e4d,1d7de375,36754bb2,4c8bd2b3,6966ca4f,bedcb6cc,64d72eac,fa1a699d,977dde05,5d2454e2,9deb220f,e2f51c11), -S(7d4ac2b0,6d1810b9,a3e823df,ece821c7,70c90d2e,ed0bc324,9ef1a43d,bfab3043,824fb46d,6afdf15a,7979b032,28588c23,4a9add5,6f512253,780acb93,ed7ff34d), -S(36482902,2ab638a1,df90feb6,c20ed6fa,fa81ddde,87d069d3,7cac4a6f,e92a9b32,af6530a8,1c62e72e,409d1308,d07fb227,63afad97,8e843672,b241ef60,dbb36aa3), -S(73f4eff1,ec95095f,be5d307,8a9f6db2,23e9b874,bb2d077c,c58fbdd1,d03e1f62,d7c0f36,5ab93ff1,999c6f95,d5c6102,47341004,1ed97e8e,9632b845,527078a6), -S(9a88fd12,af0611c4,b07ae62,59767f24,308d1aba,529886ae,6ef7f5ed,22e98ba4,a16e8f50,164ae75d,9712b544,ecdbada7,725c2144,3e8044d9,f3aaec64,367169c8), -S(265e4dac,6139efd6,a7866385,f0bd1cd5,e8bf205f,344ce71d,3c0ce073,766a6619,ded5a75c,ff4de7d5,f33bab64,d000b65c,e5078ff6,c01930dc,17bfc64c,826d103f), -S(6fe39213,baecad17,f8b82f25,d7621cb,3f1b1a07,2333ae38,d2d00a6e,ed8aa1a0,d6b830ed,f36775ef,7cd7c648,180a6edf,be65ab25,7304de39,791733dc,f561172d), -S(671f82c0,ac712083,8cc32fc8,85ae272d,4bc59e46,2dadae48,b4dcf279,707776ae,4aebdeae,2c42a80f,fd433d38,ad4ecab8,9e4dbd3f,d73db0b6,ae72e78,6eb7aac), -S(d83ef3be,4630e5d4,edbc6628,828b40fe,45806e60,83094433,31be3042,814bf4fb,ce89b788,8c93be59,bf0bffa7,adb87c4,a4fbdb78,73de3d04,c62b5a58,18e1ff92), -S(de2df94d,78cf43e4,720da5de,7f08de15,4b271731,8bf450f5,667956d5,596cc60f,61c4585e,3557c10c,8d22671d,8389c508,195b0ea2,e9150ed9,ca93fc53,3892283b), -S(4bf44266,3d4c7de7,872aa7c5,e5ae22a7,30dce19f,78d92abd,1b7e04ae,fa3e5dda,ea831ab3,b59eda4a,8e959003,c4a6266e,d4f691f6,1514dbef,18409b03,5b2a6594), -S(4912c91d,38722c4c,f00aec0c,895980fd,af4c6351,33021e52,ddf0ad4b,89b67f7a,f96d3a36,89e4838b,116b1529,55392373,1be5f0d,30b1d541,6c0b7839,1b24ba5c), -S(8c0bf82b,d2cdc2bb,49b2161f,9f0a528f,79f8f8a8,1b919b70,9fe5a46a,c26d417f,aa98d79c,1869d92d,251d322e,7bac3dc6,5f166c56,28250c29,9be63e4d,ae430dd6), -S(83eea34,4eb8bc40,2f4ee569,1d89214f,dd3ae674,d60cc0ab,9df0fd42,7559e0d7,9d7f5834,fe912c9f,23790306,3aa41b6,33085264,e6621a9b,9e87e151,dcb2562a), -S(754addb5,a1b21e3f,609416e5,5792c265,76b90660,736d0d0e,364aa13e,74b0a699,3145763c,c0d95a33,5e443b3,5dacc8e7,bdb2904f,b868cb27,3a505475,511f3dde), -S(3e513f87,e381efdb,14dc686d,14d85d3c,bf725e63,9d934de5,647823f0,c4eafee3,360be751,d3f097f0,b09c7d0f,1d425cfc,88e400fb,7a0aca3f,9d521e6,e79eb87a), -S(ea4cea76,f7478452,7364965e,546a7356,55d203d,5a92c3fa,336816f4,983fce7,a1b664b,e74b830d,8a49eab0,165e6945,69ce0518,98007000,e8094f92,6b3ba536), -S(eaf39608,61712ea1,88c9a2d0,c025d56d,8b52e59c,ea35f298,41f13759,625dd824,96ff00bb,eef7e8f7,23f2c7bd,7d6c3eb4,16827208,d3a2ca54,d40dbb83,4e13a2d), -S(34d3a7ad,a590d9dc,2547b9c4,b99a2e10,9689320c,61105415,c50879d,4de223c8,49eb6d27,eba087c3,1252084a,d78e187b,89473be1,1032e032,8a944e48,ce0a7bd4), -S(22f0cd6e,9e232e52,d82d70e7,d1ad0df9,3638bea4,8fa0bf16,4ab3c7e6,a1d961ee,66d0990,b57c8e13,4e2818b,910c27b1,7eb33daa,90ad5b2c,427b91e5,51514068), -S(27a48cff,114f4f76,bbce0d83,458a949f,c80b8821,fdcd35c5,b3810fd5,60d179f3,41690918,b0599515,f913db47,37083743,4f62321,72084ad6,7a730af5,b32d25b9), -S(2d845701,6ecda7b1,3a2a72f1,cdf24c12,8f4d85c2,c4b72881,45802bb4,603093a,50f1e7ed,ec9e2dd9,55678abc,e5ea06d,12ff61b9,baeb1d56,79055c32,d8654315), -S(cf2d9ab7,92247125,b0bccfee,f77a5a37,5e796957,75950d0c,af401a12,c8fb9a9f,8839d0a0,850df254,3e77dfb6,cf06f424,dd16c26b,f3aaefbd,aa3cdb5b,d0ad818e), -S(de85e4d3,75463ab0,a198a6a4,1d5f1fe4,c56af2f3,786ab9d3,705f540d,6b5a3770,1ade7a8e,1f9d595d,b67cf482,4c8e11fa,561b3625,4ec5631a,68d73907,8a9d8eb2), -S(c18e2092,299be419,77e40102,c9d4388c,84d602f3,770beca,50c03008,55ea3a66,86b9b3ed,786a570,de95e947,2fb0e61f,ac4aa85e,47792e99,25738e5c,3c4af6da), -S(df9ad184,a9e3b41f,ecbdaa0a,a48e2252,944e0384,538300cc,43f9ce48,6b224422,c4061799,db92d160,de19c4f6,a1280ca1,b62d675d,b7fca41d,ca838bd7,3d082fab), -S(fd846cbf,66ec362e,4d10a783,ba60c734,d9577ddd,18934ef8,81ee755f,d3748a95,d6db4def,d6c742a,e50ff8a4,43336754,d4244a42,a851ff72,7609a016,d0c84d32), -S(5e86fa96,c29e30f0,7b845438,5f39ac6f,43d120fc,df10d891,ef60e2b,141791f9,39f5ad4b,2e86a92f,3b38e286,5d7e1ec9,2782845b,593d1d4e,43ec73b9,2dfd6440), -S(8744ac1c,1b16d65d,daabc8ec,d6cfc40b,109dbd9f,c19e4439,1e2ec486,ad27293c,ab30e186,e4f2f48e,51ffed3e,46dab701,ba78b9af,b6987166,19c642d3,9491f1df), -S(9c4bcac1,c0a0ca58,debc6c0e,71238988,607dcdf1,415045df,83697282,84a31c1e,6467c5b2,32947b2b,30c32a18,174035df,d813d42c,593b37f9,2a8a05c5,52d2b7cd), -S(3766aac7,b9a2ee6,27691923,ef91cdb7,30a24727,2da61421,955ffdb3,5125cb7a,22b7d930,94110a51,ac72dc5,9d2bc66e,45349a1b,90a7c655,4464713e,6d2833b4), -S(e7f2d315,ea0d0f71,be63c896,3c6ba75a,2122e650,fda59f27,b4ee627c,54bdd30f,41cec687,9e6c21cc,99a3aaf7,e4fc75d7,ec163a4c,6aad8a21,22da269e,1e342d80), -S(cf50bffb,bd4aff61,80be7e75,e9004d85,2234fdd0,7b0b3e13,1b883359,7e96f40c,7c9eb80d,7808d937,eb5215a8,4ec4d330,565b2aa2,162fc4c1,b46bdb19,b93fc159), -S(5aab4d81,a4eca88e,e9cc0c20,94ced3ac,912ae932,2834a67,324aca30,956805d2,64d622dd,9afc799a,eb495ad6,dbdf31dc,7156ee66,d8a5e67,c44bf50a,94fac52c), -S(a4f6d781,9dd34aa7,18166000,79d8d7d1,eeb5b971,4549cf3e,a472126e,3cffe8c3,4c87eace,b4e535aa,36ce839c,336fe9f7,d4b0680c,e61fc525,4633d38f,a8c395bc), -S(3ccc6b5f,8188f3b8,b5805bab,c95f08d5,9b803e03,febb6f49,84dab325,1f6ce719,5b4987f1,7f9e2610,e443cb1a,2df24752,72655670,e739f0f4,3ca9c3ab,2a4dbbcb), -S(2d0a94d2,5bee2c99,1d8b312c,251e305a,5f44e1b9,29bde36f,a973e51,2919130e,f9cdc9ee,528a45e1,5d1ad338,db49b3a4,2db74785,d84cd12b,59391140,566636a1), -S(ecfa1649,da1a0bfd,41ffc294,40ad7a91,b6ef0d97,115408e7,3a05f506,e1aaa6e9,7f8a0b16,4b817533,84970c00,3c497414,ae319090,7481fa22,9a920004,8e2783cf), -S(4b97331e,38aa629c,14c37220,b6c3241f,603bcb0b,6b07a66e,c74ad1bd,bdc25d7d,65524ca8,ddb85804,a2111e69,17167d2c,105a58c3,321c27c2,2cc0256d,c30761d9), -S(acfc4bc6,99f3af13,ac70f25c,ed729ef0,866b900a,6c39705a,5e0937ba,fadd2a90,70ca7ebc,923aa022,85f91b19,3c550487,172f2f0a,8f10f0c5,29384cae,20167824), -S(2a984810,805a9eee,d24d1ba5,46825c6f,aea09889,132295c2,b4ec7e64,8db9826e,b56a531d,7fb7e8fa,ef957956,747015be,dc28da96,eccd66c7,c2727529,c2a45ad0), -S(76c6568d,551abc3b,f6102d02,17a440e1,36e80776,135dbe60,7581bad8,2aabb2e8,81e56168,c16473a9,bdadabf8,339c04d1,5d3cc74c,56465bfb,2eb0b2e2,8bd4f82), -S(6476831a,3425f0e,e8ded7b8,be239bf7,7b16d271,eb1d4b36,ba7f692,a2f155fd,90cc74bb,88acd0b,cda7e17c,48056936,9dfa8ba4,ec8d6f85,eebb19ae,f35ce085), -S(b2b49ada,50eeca27,881c3b6b,656df825,3422e3b7,1c145401,e92c5ed8,fa3dc51b,4f3f9fdd,41d2669d,b087ebf9,883f4f9b,383c4241,eb87898f,1e916392,d6838820), -S(75448fb9,5c0162e7,c3892300,bcf070ec,dc49560f,8c0f1665,f0bb081e,dcd12e05,b0b84014,c73db3a5,9963812,d99d6d0,5df7d46a,6a646929,9868d874,6308beb0), -S(643e795c,1c158422,24ccc0f0,97c18b11,dbe1fcbc,df8a4e2a,f234f465,f42cce3f,a067acf3,5c7f2e05,4ee6c40d,1c1f1eb,2850c9f1,8138642f,e6becd29,46e3d604), -S(fa200bc3,6ecefe8e,9e5c82b5,1f380c2d,a14b0478,6329dcde,9dae0546,4d109dec,8c6b6cd6,a676bf1a,c7f43bfa,29d6863d,87740099,d5a06e9a,eae4b885,44d1ecff), -S(851fe9d8,e47b0186,ce001821,59c674d,390e5481,fadf397c,67a2a35f,8cd7b1c8,e6e7b57,cc25bfa,8bb93e2a,f934e154,314dbf3a,37549659,8952de0a,3ae55a71), -S(4e462e9d,d2995148,d0091e2d,94f5660e,a5a994d,6476039d,dc0bd812,cc47ef1a,63c80573,dbba650,5ae95b0e,9c376a2f,78fb0d86,889e0ae8,33e0b823,7932cf00), -S(3e46f7ea,4606f5cb,4a8d7386,bd0fa2e6,89f03985,b9ab7cd3,1baf3cb8,24e928f9,a4d3c20c,9ce14434,2fb14481,41a381f9,fe4263c2,ce955e7f,daef45dd,97c3948a), -S(c650291,432ea873,473dce0b,c34aafbe,24a752,fd54ad97,5da33acd,66c48bca,795e9965,74baf74c,2fdd9e2b,a917f02e,aead569d,9a5069d0,73341203,772ded96), -S(219416d7,52d6258e,c69ad11e,1a2a7552,4b327412,c9431211,7b57d960,d1e23c5a,916c79f5,97ff454f,b93332c3,d0643652,73861c82,68ded6b4,9558d76c,217278da), -S(d97d3e10,8f3eb83a,9dcc03c6,76755f7f,ada5b761,69859e14,bcd4e7c1,56dfd7c8,a2f0cb2a,2fc680a3,79aecd75,1cf7758c,50398624,8381a5dd,ac9c9902,65b18a27), -S(dae2570e,67a3dcf4,ffc0f56f,ae3dd134,479b1e03,8faedb8e,2e84bc1a,3847223f,817af757,125d14f0,c9841d34,f885209e,e2b79522,53663a6a,a3077e2f,43da2c7d), -S(6d2b21e4,33b168,a6eb9eb7,496533fd,b6ec326d,e7fc7556,84547cc1,2c9c3143,9ff9697c,514175f9,6082783a,a2bdefb6,439d6826,af9a61d6,5282884d,4741262), -S(de577780,8bf5caf,428cf519,9487a81d,8fb8a2a5,2bde22fe,2f72598e,3fec4495,8ebe9150,916a70ed,1c6384a5,d133210c,53e205ec,d0ba7a04,5a6434d3,e32df9ed), -S(d04f1378,7bbc4e1f,8b1c548f,4d79fdd2,8a0f8199,49d81b51,3c63ca6d,c5c6d3,5cbcc339,3050eeac,677f8382,8499c8bf,b3d43b1f,5ec98768,ec0a71a8,d81dc3ff), -S(4353b53b,ff906815,d6a58b36,ae02cce,cbaa3fcf,a2bdb5db,7dcad258,4fa18e88,850b08e9,5714b0bd,2fbc8f2a,4ac5980b,ad30ff76,1241a5e5,5a5f01c8,a221fe83), -S(8141ba70,fb997010,1ff2ffd,865ebf7,137340bc,9eaaf3ad,279eefe4,d80953e7,ce0450d3,aeaade42,e4c66c30,2da0fae7,595524e,debbe419,316a1d89,d238ea5b), -S(8676ba13,25c85d1e,af93f424,755d17c6,70d2694d,2d52b890,540f9826,f2a1bfd1,df0c7ba7,8fbc592,46b5fb7e,8f98fb1f,ce1bff80,c23cc2fb,c1caffad,213a51f5), -S(c55ac2c5,1d918713,804abb83,e2109412,4494f614,109f32cc,62148706,98afc8a7,44e56fe6,6aa7b14f,44c6bf3b,1974e6c,dd8c7b61,73fe0067,952f0391,49512132), -S(72738507,f0b3244,e199409e,20eddb8a,8ffe7fa3,18930f45,ff0b1c9e,f7a15b90,ec121c76,e6f5caf4,7912cec8,4ae5c8a5,d5a9311f,a7f383b,d2e8622d,62e6171f), -S(f6a7158b,4dedfd94,6a4ee001,cf55ed08,33a57284,cedc4221,58cda87b,a0e1bbf8,2f37f2db,45ca86fb,b2fb6af4,df82582e,28e1e33d,bea3cefb,906d15e1,e7442f25), -S(8cb36d0f,40f21951,23ab2ace,e1ed08cf,de216970,ef6c6c96,48d79a1e,7760e58d,f397a565,d5eed2cf,427ad4ad,52d5d748,2b87bd97,ce31fb53,ad05cc57,2989819e), -S(c5cc35fd,5575f56f,6c050c24,769f4ae1,c0427e01,b953ddbb,4551ad36,93fa385b,6b5210a1,8e4b1d7b,592cb2ed,d1a66e11,545cd114,8541aaab,cf781d29,77551419), -S(bf3bbf0a,48711b91,74e120e3,b977a572,712271f9,842bab34,db42d1dd,7da678ee,6c711317,4fead9e7,c7fb5ee7,9b8f862,a3af320a,d97cd970,df12c0f3,84a3f3e2), -S(35534e77,c8dc6f7d,425d430b,b5cf4743,f3fed959,73d63a3d,771e5a5a,bf7da645,d22f018b,81b8f8a4,e2d297b6,f233e826,8fdc6168,4166f72e,2d89998b,4124159b), -S(6471c07f,de641ca4,b118958b,8ff9a9b1,27403eca,32a849c4,1b0ae1a1,b2d9ae23,ebb318bf,edcf26de,5d4bf68f,56fb898d,8c2294c4,7097bf9,2f34f3d5,6c535807), -S(9b8d568b,4f2879c2,1bfc95d8,1e97ed73,9bce2444,ad40156,7438ae1c,4b99c2ba,752531b4,92245df6,19251bb5,7071301d,f4a7f681,ce5ea509,18924173,7d00957f), -S(8a8673da,eb675829,cd5f3cb7,2c7434b8,d42c51d4,2fdc7a97,1681f7bf,4fd04e37,f2a66884,bb5ed9eb,f4e16864,3573135f,f65ad9f4,2203250,60b45cbb,1861a000), -S(b5048475,f56c6a46,db949469,2500bf4c,49b226c8,83576872,9524621c,c9807bb9,4727efba,45050af0,50b7847e,f5201101,591b5432,57ca917a,b9e6a210,20036cdc), -S(7d207c2f,40b9b31f,be509744,c325dfe5,c958c56d,92f43a15,511888aa,9deff6ef,4125af38,1e3f9562,64089375,965274a0,30ce04e3,9533b3bc,bc742b21,e6ee3582), -S(f6c8baf6,b2561144,47fd3cf5,a018b31a,846eae1f,a1d8f74e,59f315b3,43182edb,bf8137b,3aada7aa,7d582791,11d5c4fb,970669e7,2c160ed1,da9e1d1,4a2e2bc1), -S(9c67787f,84a714b,89a560f2,b876e92a,f8b2de18,6f8cf416,f5bbcb16,2e59d27,c0262b77,becc9f9d,378051bb,d2705bf0,92fd8a3d,b53cd131,aefc583a,b98e9402), -S(54d474be,7b58457a,929b9a7e,39e97b65,3478eabc,fde384f,681375cd,6896ff47,b8314502,4c1c2aa2,586342a2,f035baf4,ea086434,52ccf444,530b1c06,3e4ceed6), -S(e4dffb62,4132a5ff,6eeb946a,35f98c01,53b607c5,40811043,d1baf243,3bb23467,a580f3e5,d8d8e685,47e0c259,5e9c4d6f,a8616067,b3a437f6,ed43bb7f,a695edab), -S(d572f1e2,8f3eb14a,afe3ece6,585ee6fe,f49fce12,a2adcbde,d5f4a247,97c4a7f2,d9d268fb,2e80049b,b9a26309,69bc1692,c96b2d5b,dccdffc7,93305aa9,7011f88f), -S(bea4242a,5a5eb8a0,6f5c0cae,f38c3b81,4711a7ed,780e607e,10512d32,fb4aba82,601c583f,25936e03,ebc2406c,b248aecb,61f7ba27,894e4f17,46f34aa8,519546b), -S(e3179e2e,b6b92374,9c8f7ed0,40ff053,127a7d78,2da166d0,4639f55b,7cb74459,9a22f3ae,8df42fab,4b3d01ca,527c967c,7cf43f38,6a0d5751,8d47e7de,731b21cf), -S(8a973494,c8cc5c5b,4d8eb9a3,13bc9feb,fe6385d9,27112399,3c78e2e8,a732d4d1,fd2d15c,c9aa5128,c505fe85,786c55ee,aede07b2,94bf2466,d9845d3a,1596d8d5), -S(b87bfc57,7d8decd,3396f6,43200d10,946c0a7,f2d4ef92,4de7741c,e8acd653,62bc1f4,e3c0760f,82d953a,5d02a10,8ab3d0d9,53c463a0,295b063f,77f434ec), -S(aed2bbe,8ea08b0c,fc49c4a,4c92f63,2bebb84e,53027958,5b249cc4,c0ec61a1,76296846,a5391c5a,69df4e6e,44e9718e,622392b6,63a4ddf0,54b9e2e7,11a35bf5), -S(34fcdcb2,655b0405,2758c3ae,4f0bd15,2965dc47,9d7b63c2,b787adf5,6852835c,8b87ed68,30c88383,8eec48f,89a375f1,3a846f3e,ff0e8729,c1ad8e99,32cd4786), -S(f9586aed,be4ac742,2ad3b9f9,b8cece5,a52678b0,5b8ab318,1c6c2412,b470771,231f2be9,7b81431c,12539d6f,d247b4f,3d0dc8d8,15c2cfec,4526ab9f,e9cd6b79), -S(88125579,33848e15,f6c9d813,91e5eea,cf8ecdb2,1f55f4d4,1ff34ad3,a80e093f,d45c6727,c3340e79,a5256df0,41b4d999,e8910869,9620aa9c,bce6c3fd,7c17283), -S(ce1b52c7,f975a37,25f904df,9f602b82,52573170,96d4adc9,8043d35e,6773d354,17b65d8c,cfec6748,2a3c6d62,99dcc47,bfecad81,bfcb7d83,5f216f76,1ff9ba7b), -S(7e6885eb,5c8a5faa,6cd47921,54b2f5fa,4aa292f7,5fb16cbe,87c1ccbc,57501542,16a0e969,a212ae5c,6b4df92f,b3a510c4,c0b9ce27,c4f0f389,e77e4038,8c3cd101), -S(37589935,89c37714,3467b869,c366af1f,2d1566be,1ef950a4,ab1491fa,ed2ce425,2ab4eb91,cd533805,2020300f,b83a46ad,bb846863,6fb2a9c,c1e7c7cb,f3e56799)}, -{S(ebc119d3,8e794efa,85fcbd,5affac35,f73c7428,590ede0f,6365f1ea,87c65b4b,183a9992,3911b1b1,cd9b0fea,3667b6e1,52af7499,8d32beb3,d2ecb91d,af6e8a06), -S(28740562,ba21e3a3,69d80ec9,17b36013,8119b6b6,77b64cef,5f84f278,2fe5b3c2,2298a60,779ec4ae,86f9e0ff,7f981f2b,ea69e782,20927aa3,da793a10,3eb3d307), -S(12f64dcd,310014ae,81a7f6b7,fdcacb7,e8a9ec78,d28531d9,71ef3dad,af946fa,dde0755a,af7081cd,59da7725,e8246e97,2340c01d,eb76dd90,f0890923,54fb2d8c), -S(76134d79,133c485e,87a081c8,ce365757,f3beb361,c764220f,b16c1924,787cdf2e,2a77c2ee,b1cd5181,72101ebd,538d2f0a,10af3190,118da259,e4a53dff,d7a7b0c2), -S(89c5073,fa0877c5,50911355,475c24d4,bf8b8e38,8e9156fa,93021ed6,21429c8,40fe8b47,cdf3690f,63b3af00,efcc2aa4,b29c705,d04044f9,bb910671,b6ca995b), -S(bdcab1d6,157ea793,40f3bd0b,13365b24,b68641af,4e222d7c,b4efd8db,47b8905,b9d78e27,96820c87,850257de,746c6a05,5be5e595,aee8ced1,1dcdbca5,d92c5ed6), -S(da509ebf,2b7dfd80,d00c4c25,4b2e3b1f,df021d5c,cd1874fc,50b24141,2444e666,c3782467,e1606722,a76bbd84,dbdfd6e4,2cc41a10,cf50d921,d1bf916b,24459c50), -S(45da8013,3e8ee0d,f0a456d8,bad2d285,ab401f36,bdd520e3,c66b3d6c,925a17ef,4fd239f7,bb17c84e,3eebf9ee,c352fe82,652af898,f670dc5b,e1b9842d,9e593938), -S(d67ae553,58ac6a9f,cab9bec6,8a423738,bf7340c8,33a51cb3,2528893,24cbb1b8,d0b6ee57,e131ea57,300e228a,e1feaaf,55f1eab9,67a3ba3c,c403bad,b1dc663b), -S(6ab4478c,c8bdf1e8,7bdf566e,c24f4e46,a689459f,b002d0d5,715eb22b,62cbf077,331f13ba,e5be2960,97f8326d,1e4d3147,fc3ca83b,f4b3a4,56ae15cd,83d176b9), -S(e5d02a1a,3bae963e,9410402a,40390ca3,53d53a56,66ec6258,e82510f7,f72cc2c5,80379b63,2b5d4835,170bb358,c9040fe7,fad6b2bf,c7fd26f5,38acb1da,ba357453), -S(39acfbe8,48db640a,c2e7ac,86a1333a,ca94060e,fa88f0fe,f00d6273,74d79293,70ea1445,f7ea5f8,1148f42b,a37b2fb3,fa09f42b,9d2416ef,7fe0bde2,6e1e8f50), -S(1f8ce5d9,a815f4f5,d52c4dbc,7faf4f0f,d76a35e6,c2570632,6602bfd7,aef3b51c,3a2ec9d9,9ad3594,b223afbf,4d292f0b,88ef9372,18dc2ce6,e53df212,cc548e01), -S(5ee148dc,f4fd3d7b,b43532a4,8c782365,f944910a,eb235d67,f36642a1,b15a4581,898252a4,64cccca8,bc958dc,363cbf6d,b044492,248c0a96,aeae3bc4,26c67c93), -S(a07ec6d0,9829e04e,135566b2,d0d677ee,7e6bd606,21474cef,3e9b512a,753174d2,eb8dda9c,f3b44412,ae50c684,18453765,42697a15,33c84e78,fd75a8c7,11201514), -S(9069843c,36cca54f,aa3f5ed0,3c1d803,abd12955,4a5f8729,ced1352f,ab628d44,7140b7f0,e955a45d,aa2ddb02,846bdfcf,85163b62,718c9a51,3380b3dc,4ead8950), -S(69a98f1e,2677c441,86720bd,3b1cb073,9f06a16c,e43f7e0f,680c14f8,6540c36b,d52b75b3,a3005ab5,69041e3a,398549df,8f432e5a,c0d7e268,463b9190,191767ae), -S(c9297581,bec70b7c,55abfe17,95337b68,b99fb132,1d203a2a,29b82462,15e29633,36c4eaa0,5564673e,8ca1f783,82070d49,b8151afc,ec6c982f,2950a371,605f14c0), -S(53d50d91,1977cf5a,da1fdde4,7d44f6df,98d66efb,c858b92a,c490ee97,77c593cf,84db77c8,96dd1607,2c45c058,cf5bb2f,6435bd45,60bdbcf9,b8df71bd,404848b6), -S(ee15471,8e67e1c4,89d62145,5291a5cb,158d8fa5,84f7a134,bfc00357,ff578ed5,d9d90c79,3aefe401,c7017ff6,56d02ead,12318503,37659baf,f573c9e1,e4c65f0), -S(19e16e0a,ae3a4e80,ba0f66a9,7d415f37,784270e4,69e16560,7fe3632a,4bd8f1e3,6aabbd97,55c15f11,5a2e8287,b6fe91cf,659371f2,de5c86c2,a8deb96d,27037e72), -S(e93d52c6,12c07b0f,4f2f93f1,4b37bc92,3c3d7171,fad16472,146fb195,fd92f33d,933450e4,30e9c8ce,5a5948e,63f6d0b,40fb2ccb,adf5376d,4c076a63,9490ffac), -S(bedc3252,ab1e4676,63def49a,781cd7d7,98d01f3f,7cc1228a,9e396d86,7e8af12c,445c8bfe,9eac928a,b2d1d143,adef019a,7c243159,23a7b190,c763cbd6,dd305271), -S(28fd28e8,723d5c98,d978ac74,b070402f,3fc2315a,76d6c2e9,cd996b97,bad6375c,3ef59add,897dd001,4ef7441d,a62a8ceb,2c62b7a6,f5674ee5,b916851e,efdbf0d7), -S(7e8fc198,22ce5d20,dc04a61a,d33e4d66,c17ef03b,7fd53acd,e9c3e01b,21f3f646,ee5db413,637b4c88,d8cf2e1f,5d1d3be7,1d924962,38bbc30e,1769343d,9590cb3b), -S(b891fd94,36a14ef2,43f7ce7c,91d30887,34d1aee,8ace1fe8,ab3b29e9,2aabcb5,8af06c1e,ebf9bdbb,e1ad2f06,fdee27a5,4dc1c0a3,b08b17df,8e6ef7c5,5937c215), -S(236a16f0,21e85cf2,d5d62763,ef051bb4,c532dd26,cfdcc64c,2429f15d,8082d6db,bd24dcf9,f41f4c07,4fe6b6ea,450e3b9a,fd9c711f,b83ad683,43e65b13,3e654f3e), -S(d15acc35,21f6c40f,e7272e60,ba7b41ad,36351083,37683d43,4f9c576e,604b255e,7669301a,144b952f,cffb2e90,8d1709b8,87cec28,e7766930,eea8e753,2afb792d), -S(3b2c4a9f,cbd14308,fd612624,e5236b7d,4c363e3c,ab30aafb,a1092169,5beb3b78,69218228,5d7ebcaa,43db5109,46b93c22,ffcb7781,9c0de27e,3254ee33,3f9ed9a3), -S(b9f6b09f,a02dde42,453dbe34,b2388f55,4d042646,993ac018,5e7a6a63,2374dadd,7ee30f24,51683425,b8597189,a053a181,400df517,5934d2e7,cd00b504,484d9b3e), -S(f65baeec,e811aea7,a83f78f4,8e6db3c2,76fe63d6,11b4477a,42df67b8,4995758f,372ef8b8,9c75c669,7bd45ac9,68680c8b,14e4e558,d38e453a,2bd0c176,f6218250), -S(1f9d4799,d02782b8,f35db2db,eddb1715,e75779f0,82fd59e4,766067b0,6072bda7,86680af8,c57394c3,d50f2d5f,aab5d475,dec645fe,c02279d7,9366c450,bd3806e1), -S(c753e7d6,3dd4a9d6,384148fe,ed1a5f7f,1234182c,918dea50,2b44733f,d3f0c813,d80602df,ea4d0507,3b311a9,74be42ae,8e832f13,25790319,cf1a66b7,ac04c2d8), -S(6e294116,8eb1bc8e,55a0f2c5,e26b8b81,d6ecd829,5bb092c5,d0384073,c294e8c8,870f2e47,e00b9980,696aeafc,49adac42,32e77a5a,f5945f2,2f148d61,a9d4dcae), -S(eb2c36bf,298f419f,45fbbc61,7ea5738c,872df682,f537f965,3a58cab6,e38d2570,4619e86,3f2b9923,9709557f,932768ca,284ccf53,bdb9ef10,582d11e5,3e1afc31), -S(6ec36131,e3a55bb6,7b95712a,45ca3c8d,fe85aeb8,2746457a,cded305b,e9ba4607,6160727,f7b6db03,ad31828d,4b04a023,b07f1b41,209f4689,f126048e,21e0d9c0), -S(6825bfa,13237b39,277af3e2,1814e510,8fc51e84,abdbea42,8675ff6a,35881541,9f03c24d,c3bd1c1b,c45098c6,8f2ae07d,ccf7239,61c6a2b1,a3466d7d,1afd035a), -S(c8757c03,ce5f4fd2,2fc61bb2,e8f699ae,a733d64d,145c6fc0,58a68368,801fadc1,6601f2a7,e08e1249,5509bf1f,cf149459,928e5976,d7469e0f,e2e625e1,d9c99b0d), -S(5c1204d6,f1ca66fe,91b4cc5c,f2895ee8,2edfa489,a5b97205,808d9912,1e24a6b3,876a2e11,d790214f,d52fb598,ea7113f9,9ec08052,ff09035b,4169316c,82ba7122), -S(e0c03a38,9c612205,6b9688a7,edcc3869,5cba30ba,9038545d,33ddcff1,5f9b697e,4c0ad413,7a6e9b87,8ca914d8,31aa0371,d1bf770f,b73f1cdd,3d4dbd9d,d8fb4b21), -S(79c75424,ba72a99a,22802f65,56110084,e8adec17,355b2e8c,d2e7f8d5,13170cce,129eb5da,2ff02b6e,1fa41283,39ef9fed,3f12c606,bd55ccba,5809375f,dce59f1a), -S(8d73db65,e37a52f4,fc2b038c,56d8e371,450b65a,58614369,e1dfba92,2dd451e8,84458df6,859fd26f,ac74fda6,e7105d27,25b64fce,c4d86e9e,1dff0284,1d051d15), -S(41320642,e7de949,fc8fd03e,1b22a2ee,421bca4c,ef0e3ea,40411de4,962daddc,134f4f62,58c35358,cd33ff69,69a6b044,b36faf4a,77fb64ce,63289922,cff7d38d), -S(ae1b7bdf,21f2fe17,8a510982,f1d69a28,2f565cd4,9f3e6eec,d9412995,7b1652fe,6f6e9f98,45ad4699,a84d91b,9fd41a78,30b13310,c7f7a71c,9cdc4796,e1b33aad), -S(1d31ff82,2fffbbc6,1c3007cc,dd133dcb,624d612e,5d74acb5,f8370a8c,dd332d24,9fc68745,ee1f3a80,82efddc4,a01b75e8,6ffa49ed,698ec087,a9373623,61ae9d35), -S(f075d743,465437b,ccb185e3,c5456d2b,5546009f,79b3c591,d68e7c30,e5ddda1b,8c864d4,af8e89ea,8a1c5806,2c97768b,3e5b4c18,5f38af10,dd5a3d78,9f6cf73), -S(f9b07e9,abefdd37,a567598d,a23dd08b,7716c0d1,94cb24dd,3c6d6218,1f5fd2ed,1ca40c2a,69b92115,68e093e5,14312598,92cac6f2,c4cdfe41,16f287c1,71b1ead0), -S(14695d33,c187b712,c5f86b69,c0816fc7,cfd31486,e4fc0cd,b7042e37,cacbf5dc,9cdd12b9,c39a3237,c980047,e239b1c3,2b6145ac,853d331c,6f635efc,5cabaa82), -S(989cab0d,803b6665,33b78fbe,377d8db4,e1477f7e,6d962a93,7822e811,cfddb013,12f6454b,e88fc235,cb5f2de1,92404327,8b03c574,47c14fec,94538b54,68014a92), -S(88d1da3,4b47fb67,cbdb5eda,a463da2f,372f9605,dc0f0754,4a746ecc,a8409f4d,c2f2ae0f,38594687,7b814e11,333065b9,932cf4e4,1a6ea643,e6496175,4d46aff6), -S(2c6d9e3d,67e3a096,687b6c5e,8607293b,883017c5,35ff1594,aa8317ef,5e2fb573,678732ce,d618d76e,4ef02ae2,49485852,349cafe2,c9a78360,8a3d2c43,ff6a5d1b), -S(e0115fd9,be5488a2,e8383774,bf52b761,d75291e0,ce3d3fcc,aa642c37,66531cf9,49d36cfb,80e6ae38,d21be55c,3e885db1,fb773a3d,5c6827e8,7dc95ebf,9ac4cb3c), -S(1e994028,eb203a9c,da816a14,b08a00e9,7ec4cfeb,e6fba4c4,37dd1e41,68ed7a34,d7f4af61,ad4768af,959313d1,b5565c70,3581c4f6,b04cc1e2,bf27f202,36a6c94), -S(da12d2f4,1d60af63,a209844,1e5deb8c,1af51989,7a6edeb6,b8033621,1ac738c4,65561894,467e391f,c7de310d,fafa2ca0,c2d475a9,ddc506aa,a292d809,3272e70b), -S(aa3b79b1,4c5c6e67,ebbb8f7c,d1dac8a6,da3df0f9,af7c548d,ea0dc6c4,70830532,27a74ddc,79f6cee9,3bdaca0b,833637df,bb426cb8,58ad93e7,4fc1e285,87857cb9), -S(a25e2e8,942e3353,4a36ecef,62c71508,6f1e959f,627287d,f0e7dc67,6457acf6,3383132d,2ab2de4f,890fe37c,74b3253c,fee9265b,e2ef62c5,a755af61,abe00463), -S(c8ffe7ba,62d8ece0,843bd801,6c8043db,2e71d0a4,f91f2eea,7503824,1a3e67eb,fb507024,6a0e3286,8f6f6e67,7161b822,ac9d1aa,267658af,895cb9ad,4d94586d), -S(3352b6ba,380ee90d,d846c6af,ede2a9d6,de4d082f,46bf3a18,dfab2943,409ffbf2,fd6036e5,d7b2ff57,376967a8,42bac428,203b2784,4196fec8,64d8ee42,b7248472), -S(2ac42896,c815a831,a7b2d28e,af6a8c3a,803977d2,661fa36a,11143a43,7d179d55,2cc1490d,70b9f5f5,96cc8294,41fb5c43,44566d5c,77c651a2,34ba058f,b4b05823), -S(ac5917d7,64a4dd2c,a5c1db3a,75cf56a3,4a695e8c,ddae8c0c,74594857,cd48986d,5958f85f,f6794368,294d173c,14937aa9,eea64dd6,80dbb96b,c3e7b855,a87c92df), -S(c79122be,5424c0ff,728368c3,a0ef6ecc,3026bcd4,12ab1ff1,e3443d7b,dc2b46e9,2abca3b4,be4d53f0,40fb7d0b,3b28f4f7,44e4a96f,1e1cdfd4,cdcc7276,30332dae), -S(b3015fcf,1577fc15,337847a7,2b6c9bda,a7d6649d,711a156a,499b5e67,4e6a8ce0,2e826388,be577c02,f2fc3f2b,ca4f1ecf,546b75be,3373134b,1e440319,b78fa759), -S(b857212,b941cdd8,6f80063,3167a5e5,7d6fa385,c7ed08fd,9773de0a,4a481af8,aeb5aff7,329b6227,f614b8ee,1e2784a,ec5432f8,86d29e35,916ca3f5,7b901ff), -S(18f3f92e,a869ba6,9f64ec10,6e42e4c6,438504bb,709734f5,eac1a97,a418c23e,a9d95cb6,dbc06ba9,cf35b953,b0426ca5,167766ff,a533d47,bf40e55c,9e5cca00), -S(b6cde393,b06eb82d,ac45aa40,b094dd08,1a7b4bdf,f4a6caa1,7a1a2d9b,de336e60,81816d39,5db23bf3,9335c483,a50ee3c3,710217f8,9365a04e,1fc1cd49,20fdb244), -S(42ed0806,c78c2d5c,851f134b,341fdb4c,949c74c9,7522e681,81423a0f,64a6f1e5,fac85e8a,7151a4e3,b7b24919,828153c,237bbfbb,4a49607,a70f595d,9535d66d), -S(bad68afb,e1931a,63231202,69b4fbd2,a5b84ba,a951fa56,4ca07bab,d3160199,1b19d063,7e89fe43,894a2c4b,e8203e1e,cda6ac9f,f7e6989a,b1581d81,8c1f7ff1), -S(74c6a877,29197f39,c253450d,ed7cc4b0,948f1c05,3c91d120,668f09ed,f56eda31,e3a383c9,b0bc99ac,1eaaf1e4,47d9a088,e772095b,8a30bd75,dbb70622,44f46d29), -S(ab75cd77,a5800af0,9a2b4ed2,fdcdb6a3,d6b32076,ef5d9211,8dcdb4d6,acc25547,dabcf737,6f03afe1,6d2e8dba,e7634bcc,1cf0302,7545c57b,dbdc97f1,6bb1491a), -S(1951f597,1bf190de,295cd417,1ed7fc0b,6938e031,8403dfff,10434dca,9fd7b7c2,321f12d6,b8790ad8,2a956947,ef0a615a,76b6b678,5c765d8d,e9f04cf3,9961604e), -S(3095615a,6dce993c,646b7e39,1fd86117,82ee418b,cad9c9e9,413db342,45c76edd,9745ff66,fad21c00,68699f49,158f578d,b1ec962e,d288e008,cc667a95,95513fa7), -S(9b2a6fa,60b7fa62,f0cb6c41,91f3b7b8,fc0d549b,98520472,86abe23,4cea3c1d,4763f538,6bcc3b22,4bd2299b,92a10572,7a761b3e,709ab6d9,dc875615,43baa2b7), -S(df52e023,92e2a319,cfea1f52,c58a1039,27c14e64,8eba846c,faac077d,13493c3a,eaf8a802,9f682f59,295d3d,d44c11ae,537442c0,ac61e6ad,1971e975,5f1856d5), -S(3cf08be3,65e6164,6dfe3e73,83ca54bc,ae2e1b36,522da9cc,accd5ea3,4de03f45,d2eaaa72,8b2cc3e3,75bb14a4,4f52aa90,40df35b6,282c0b0c,df8c3a7c,8e75b435), -S(e7d92472,23f321d2,9a327ad6,4d08549b,e38a216a,d9ee8e1f,7dda5956,c65eaef1,d0cd5049,fae4996e,362efe1,f6019de9,2b57c8a5,fdd17a3c,a9cda468,e6a5e5d4), -S(fe851c52,f05568b2,ecbe964,bd80be47,98414ab3,c20fa0a6,d0b114c3,8ff6afa0,3170ce7f,99584c1,82fa6cf7,47197fe5,7f7f252f,e21a38d4,cefa09e2,697427ef), -S(993a0c6b,10fa1b82,8a3e72d8,89244094,cc60ef72,7f9f4758,53f09161,fda8a1c2,51be5ca1,3539c2c2,7a1d395c,3d89567e,cb218a99,3432a424,96ea7e69,95a6fb51), -S(ec46aba7,a6af89c2,7689933,2910bdf8,87362c46,a2a3dd0b,e1e6419f,8b2a2036,cca7634d,1afdae1c,d764d553,80190aa,96a5f444,70db8f07,fe59d460,c2a04380), -S(ac7188a6,8ecba28d,59c786e7,e127335,c332697e,2980fe52,ef3dcd2b,f8227c6c,e7ced64c,99c08050,fbcec989,89f99a7f,faf89fcd,2651d291,66f40c6b,3fba82d), -S(27e6baf8,f83129e7,14858346,ea158821,c474fe2c,fec352fa,61f00808,e662502b,84fa023d,3d371686,db30f0fc,65491b6c,d7a5043,73a08a5f,8d63f94,73f2cbfe), -S(4deb11fc,8f4610b0,c9875767,704d48aa,d55c06f7,2712d577,22f48359,38acb0c9,1769af84,c88f65c5,70df086a,e07abe6,b1a5b2fe,95da770c,ca57e11,4c6dedd3), -S(e2c30e5f,a831d62f,ce366bdf,1415fed6,574f12eb,c4ad36b4,d558081,eab8ca7f,6b76b320,252e2b24,a49da21f,f51207f6,cf2621be,992fe9e3,758e2abd,adafa7e9), -S(293bfb9d,d46baba6,8cd67e75,35e944f5,79690edf,4d17bdcd,2295d044,be309644,8c3777df,a3f4188f,4643b137,4cbc8d53,6fae283f,540d18d,514c8162,4b7af701), -S(adb8b1ad,d80a6120,e90ec376,14f08f81,b668cbbf,db85bc8a,9fb76881,f3feb2bc,7525e4c4,56995383,c9d5b8cb,b920130f,b9225012,a441eb5e,f6ec960,2181b070), -S(a03cc251,b299ce99,ced67920,11eca35c,87ecccc2,80ca61f9,b35f4fe0,8828afc3,34e992f2,9a8b7e71,804c5bbf,680622d9,536c58d3,316138bc,77adaec1,1f0a28f9), -S(e370ad9a,8a78dd7a,e7631e25,bc5ddef7,b5ee9fb3,449cc56d,3c77b12d,2450c42e,ff2d4db8,24f0f626,4f8c61c5,a3ab3cd1,d731ac1b,36503024,61f7c333,d939715a), -S(e7825767,be268da0,958756c9,c10a7f5f,a8b90b0b,f9279530,d5d60cb9,3cf9a782,e8a54111,66446979,5ad4be94,31d267df,9e471de8,9c2f386b,ef52c14f,85193030), -S(67768f1b,a78c76df,4f0e0ea7,ce2faf8,4fce8e5d,d43707a1,586354bf,77c5d369,a33cf627,c206d44f,79e3a473,a07051bf,202dbafd,cb74735f,1af2c8f1,27e4eb4c), -S(3c2296d9,a780ada1,a795d3c0,6bb3cc74,b00a7232,5c244ae0,57cb18d,5e0b8aff,bcabc5c5,2e1260d9,b14f9ee9,70b098f2,edd5163a,65b204b,fecc6a00,cf6c7f62), -S(c3ef3a3c,da7d376,2b128546,c8402603,7aebc362,c2a4d869,f2583418,2d8c8109,207ec4c2,6673447b,8d899e7,62104c68,3d0dba18,ca98c373,432cda8a,a6ffd6a5), -S(1d97f529,2fd92440,7fecb4da,a0baefab,15670b03,fd635cc0,66c078ac,fc35b80b,4457ef24,3b6c9e3b,e99d7a01,9d95b706,fc2530a4,7a88d11d,ee4083c2,fa7a9e69), -S(22bd1fa,eb1d343f,cbd595ca,f80a9128,c7b6371f,e5ac920,a31bd2a5,990a0a38,e2157272,a9ec6919,6ef17add,1855bdd,31097aa7,4e332779,9dae90d9,75155910), -S(dd8b69cb,a32f727e,e5c7e09b,5c152bea,badfec40,8ff36c66,5a95f572,82dd7b88,f8024917,d1678ffe,52ba97e3,48e74c0f,2ccb06d6,8ac7914a,378b7e5,a86dc3de), -S(2b3da42f,b0ffbe4d,69143812,a221f92e,496d381e,a420efb7,944fc66b,ee5eccfb,9299b809,47c26fb9,b5a3f004,7041f494,ad665c1d,ff304479,9fe0dedb,4ebdadfc), -S(98d2a44b,fba2fcf4,5b33a605,513d4c0f,8c036bcb,555f9142,3133be23,7e616db,70f5bcb9,b499ea99,aae3b8f7,f33169c,5af06f3b,55dfb8a1,623d7a2c,d54b556b), -S(37c7450c,933b1e12,8d4572b8,deaac8e0,80bdb588,ab90ffeb,f0d6fc37,2feb2219,ad0cab20,39622393,5d8a8ee3,2198ae9e,950be80,12b5448a,bc030b42,71920b32), -S(d8a2d303,8a0b0bb8,c85b0a07,79a88840,166babff,ec651b00,15c37f89,f11067e5,18200caa,7e7a67cf,e5c720c0,ec1f8ae0,ac083011,9ecced1e,b78802ab,30198d13), -S(c27b256d,eca6b591,c1e0021c,3d1da818,8ed96783,11a90a0d,41396932,f9214a5f,d30baf5a,3c64f47,4ce7d705,fa836a89,9161e75b,a0cdfee9,5f03c559,78024cdd), -S(b00215c5,b93cc894,c508a613,20debae0,58a3e4e1,d826e3ee,cbd168e0,384f82aa,469355eb,844e6608,7a390fcd,f43372d5,37389f99,33d240f0,3dcb0b6f,3476f0b0), -S(da646c43,2f525192,efe9b58c,5e41d190,f5ae5e36,9d8353e0,21aa9ff4,15a663ad,742d960a,863eb936,50a84bcd,5d4a1d50,d1243ccc,77698fa7,9135a351,fd5e9864), -S(381abcea,fd9ecec2,897a543a,d712bc1e,39a76062,b2d34ba9,8c06e7ba,6694a9bd,813cfc4f,a40bc405,941ca90c,73648d66,790e7925,31a6e64e,d432287c,24fd7891), -S(130361a0,1be7546e,57ce8b7c,c97cd06f,db4d2498,635821e5,d05cb8b7,46e7ea7f,448b60cd,668facba,4d56471d,d492e529,b7e204fa,778ed89c,b9ed021b,bdadd193), -S(95df1d44,7739e3ac,7e958445,1b269507,8f32d917,b512e4e2,fdb143fc,465ed004,5807bb76,184742fa,1745feb6,b3705ae3,283066ff,fbd0457f,720d2a2a,4931e728), -S(d9b612a4,a3074698,e06b2c4b,bd27b668,8c71b874,6808d245,188eec80,73292c32,b7e771af,3ca2ef2b,e3d82568,203f0a6,3e8caa73,d6f2fc32,17ad4b53,bbf6bbf0), -S(c882600,f804cc50,6342436,10b79f56,7c9d9276,948413f8,889a6bb3,fc16cf79,835220ee,694bd660,ff321b3b,d931d082,f6efba84,dccbef51,37492ceb,3c03e11e), -S(8ae9f886,4415cfb5,cbb8b67f,8076df4a,19c0aecd,82a63f66,ee5d1a76,1ca3ee6b,4e24aebb,1b507a13,fb1f3f33,7059794b,e81c5f13,4825806a,e7da3723,8be7c7e2), -S(70558a7c,756dc54f,337a3159,aedddee5,fbe3ffcf,5ebe648c,9d6c4c42,e56de4b2,67959da7,f775ca30,c942b87e,a5c7e2aa,5ee64254,4b600134,493fe07a,47a3ea82), -S(ec4bbb6f,6d88f798,832c4b59,d6e1ab57,fe559818,a2ee858c,e4273770,81c46b46,55933669,59789697,ea826bde,7929720d,6887bff7,4e910b3b,44bf757,a2cad075), -S(e7f069e6,abcceb3c,30d28256,50e8a469,3ac693a8,6ba5b120,fc827400,9f737e9f,2a9dc479,b3a7627e,3ca49295,7598d942,34f4bbf0,304c34eb,cfbfb662,1fddac1f), -S(54b175ab,7c18c090,2f0f97cf,4444f362,3916122b,1767fcf9,ec576ca7,5a2617f7,b5cb03e2,9a829c80,81f16888,3adfe85e,917e6525,8cdd4f0,cd3fe571,7adc6436), -S(da20f8ff,2b64cee8,7572fea1,21f98044,57bafdfd,3b1ead53,6fef24dd,16e08c2c,6e1898d2,b7482032,6b299591,376525f1,700ddcb,8e2c8057,40ff9327,2cee5bdf), -S(55244d3f,e177f889,3fa2e982,6ae89927,1b0bb5e0,f3764941,95a9e90a,8d1367be,abf46ed0,93f617b4,85d7719d,b4878968,ade00c3b,7c8dbc70,c21561f4,90dd3b4a), -S(a2c59a7f,d001bd82,48813d66,2c6ccc24,ad815cca,89ef749f,891a219e,956e931e,fa61c08,4a0a648b,5307e771,28a58d14,4d1084b1,58f1f824,f3d96d,d091346d), -S(d94e65ad,9f2cf491,192e5d1b,ce9d42f3,14c0a724,5c3b351c,f2ba3a3f,e70aec21,3d503a0b,df638ea7,5ffb2886,b3a9d723,2c427fb,d4921c4b,b1eefb86,2eccab8), -S(eb24a84e,aad08175,13705448,36b99c05,adc0e7f6,ae871a70,b42d24e0,a6287c55,3c4e2230,208b5750,fdf24d95,83d94db0,58e65604,d555a0be,372a5f4,a39858de), -S(69ca3107,a95583e6,c6b76b73,56b6a65d,2c45f0a6,194b69f,ec56efbe,289f8141,594001e4,46916b8a,9f977542,281016a0,8c8290e9,92e5e87f,fc16d49b,ca9f7155), -S(f7b24587,a436adea,15f6cf87,bc065d18,dec084ff,6f6582f0,3782a977,515595b,30391228,a155358,4b1f8b74,da91239d,89a4fbbb,93635cec,bc2453b4,9f355331), -S(16bfd7d3,572a6fed,c10a6e8,f6ffe3e3,9090448f,71884026,f6a16688,5f0f0d92,17a933d5,f2b3ed3b,f09927da,25331207,31a30a81,93681cb7,3bc0b2a0,c0b7f436), -S(dec8fca7,95baf9e4,379aa5fb,777777bb,178e086,1a738053,17f8d676,5cbbe9cc,99f2da03,32b83f9b,b712732c,e9b7ca53,b7bf6086,46c7642,620fc738,6b74343a), -S(f6b5b4ea,ba3f1b89,d399f6c0,eac8abe1,88a9cb21,9a9d4d3,7b578447,62f3956a,6cda2c16,8211c18e,8722e689,70fb9a23,54d09606,8e104c7b,5a6f6812,fb854a25), -S(2f547664,916072d9,2754da2b,556fd3cb,d9b67045,4bece334,960875f7,df57559a,c3c27849,64cabd54,6487f05d,45544b4b,bea58b16,e2a2e3aa,2105cff3,c8d0a5e3), -S(b98cac11,e194e80,83d39bde,8b28103b,d09bcf5b,bb163b78,33e00be3,3f52779d,dde188de,3763488e,7ddf8bb0,12291cf,848fc21d,25ad040,6217a8ea,e1fbe6e7), -S(1fc36f4c,99b540d7,a74dd2b6,1fd71f1,b095343c,3d7856c6,6febff21,b5c61286,6d165f6e,ed6343f,36dc761e,63f6068a,1a583086,cb76ad6d,a6996fd,8fb303f7), -S(13cc7352,2006a383,356e7378,cbe74e7c,873e1a8,c96f437a,995f5549,616dfa5a,f73ab51b,639aeff5,ae8deaab,e5fe7dc9,fe8cc203,ec66f16d,dd789031,6da8f614), -S(a42b8522,d7b620c2,8011137a,76719fa1,3066761a,7a612946,60c9fb3d,e37696e2,e0163b30,5f5500e,74bb9e98,c7f8763d,4cad602d,d01ee3ef,404899e1,1df9111d), -S(ad1e64b2,63b364e0,477657c4,33601197,61b2efc3,87c5b2f2,71befc20,279ca300,52e1f8c2,80ce5c76,70533ea1,4a8d75b9,e4e0ad6,199cdf0c,c570daf6,469e0a17), -S(b25ac32c,4406382f,6c28a12,f4e1b491,d7cb9a6e,2f03cbbf,46c26d95,d70b6295,db173a50,1d02a785,ab98ab65,2e814ec0,fce3ae92,e3948610,3141a844,93113f11), -S(507ddbd6,2908f782,9bd54ac7,948cea3b,ca3f5551,d5fa0b8,736ff2d4,a38440fc,76e3189,b588462c,93de2716,b5d79d42,8339a81a,1bc2d8b,e512e33d,5de5ecf8), -S(c300e40b,425d9391,4e2a8624,830f119b,3adb2e8e,d90f4873,46dd02e5,1ffe7006,b588f4f9,e9a315b4,1bc6484c,3b0cd1a,de816262,80f14767,9a1c3b31,1e48df17), -S(19d029eb,114bd8ff,952307f5,1e04593d,a4936127,dfc72bd6,8767a462,36b31b6a,e56c64e2,b1f14ecd,1f7dc29,be51fdaf,d859d6cb,78c5dd7f,5fa0f221,bec715fe), -S(b972dd3b,e3531c85,f1d9580b,8ba77429,747ad431,4c5a7947,3c54d647,bb93ba63,b1076055,6464152f,c5477005,fd6b4ec0,e8a73dc6,63fd6622,ffd31170,5ca7af0c), -S(148c6a57,f606ff5,2489a1e7,df84b1bc,11ef7b68,9cdbf0f4,f583be09,db595b9c,308e0362,2a681b0b,308f11a0,71742e4,f501d089,9f190e9c,239689d,2de198d7), -S(f8eff5a8,48a0b184,768135b,8c159bdc,ba86397,c38a2255,dd6bc746,549521cd,9fc518c5,d2bc6749,8fbb9ac0,8c22a070,e948321e,3b11473f,b96a67e1,2d788e5b), -S(61cb5332,ebb1b0c6,badb58d9,c15b8b1b,8c5b0a95,601220a2,a2fdb007,325b4442,fa90f15b,e1636b62,72ae71b,5711b43b,53580f04,86b6472d,e14737b6,8267242f), -S(9ad91194,210d4acc,b4f2fa3,f69f9fe5,707975f9,99f3e40a,9b766e7a,ae570b9d,bd770b3a,e6f6ccac,9d0dd1b9,bb5c451e,c27a8d0,ce02b491,a6c40afa,86067ce6), -S(d6985c89,71c21dc4,723540e0,9901194a,a898c0aa,33c4bd7d,34d74164,cb46ee8a,3c62000c,c8969f08,2dee7159,df6ce660,89e13b1,9c71674d,fdecb469,5e4eed89), -S(398e5cc8,4a90fcbc,1af56815,d56619e3,74e30023,9f95ed2f,3b0c3d32,fd0657d1,f82f5fe9,99c25624,9ebae25b,71946c98,b16cf462,cdcade65,ad22c608,7776fd49), -S(d5b3aa26,c2400d25,7032782,b35cffcc,902fee32,a28fdda2,f36eb3c0,1b19ea86,3f3fcae0,a7f0956b,2ab41211,a8941be3,358b22d2,1eb18b0e,c0afbf38,95e8e17a), -S(6f6e1cb2,3e212a5c,91b91407,7c90d465,eeb3c46e,74addbc3,ed228a1d,8fa201f,c11432fb,60b782ac,9dce6e69,e8a544e4,c5676f36,7c959239,c4dbf548,610b0f74), -S(23eaf533,24bda09c,ccf5edb0,8d0b5904,6c42f17f,12f64c81,54b884d2,239239e3,87aa0fe9,c37c0150,95ba3f68,96ea597a,a38f5a68,d8fdd6e9,a9eb4aa0,b6dedc57), -S(639f2502,a5f0073f,95352a3b,63982bb7,f215e0b,c80d3f7b,fc37d1b6,2ea89e18,a93481e3,8d78e490,6fe37f44,a198b85f,c6246f0,50d17193,f01962c3,c9351b24), -S(1e78e21d,4f696d89,b0b43eb5,e5d8cb03,46c9d030,65a4ee15,5f81ac27,b8fff65c,3a8103ce,e0d7e645,69e22332,911728ce,20793c12,c7d45b0f,3d840641,11221f8b), -S(1ece1fda,85a726ba,49bc7ac9,23e1599b,b070e8ce,134858b8,cb4d714f,2b539ff0,dbbc6f14,fadb9d5c,559b3b2b,df070bba,11d8777c,b5526bc9,ac951dbc,9815863f), -S(e49e79ae,f17ff1ea,b81e3c47,97310952,6dac7ac4,ecba2a57,85696de8,279af373,92b0fb30,368189ef,dacf5e40,1ec4dbd0,a4ef28bf,512167bc,42f63cf8,a7f6ba73), -S(ce0bec53,1c1eaeeb,868bd283,9b37c225,fdc90d0b,d6d82e58,20516b7b,9c9b81fe,9ca80cac,80100d58,68fd1bb9,b174b0c9,54d17492,12ebd194,5bbd526f,6f842b97), -S(df282fc1,b4fba7e4,fd75af57,805d93ce,af88590,3b57cea8,38f5edcc,2e7efb52,27487ea3,77eebb18,699eff2e,66909c2d,9daf7f0e,32e13ac2,17df0d1f,b8701c33), -S(e82d0d6e,29b68dcf,aa8ebfb,4d8d5f70,2d6a91dc,b10c5c3b,c7363360,6c937510,ce1dd596,232791f3,7efdfb4c,7da518e4,c98e8f02,d36c7230,3cb3c52,69bdab85), -S(cbf085c,5316258d,6cd5e721,b613f97d,7e22cac6,2b832bd7,e2830f34,2f748f20,a5efaf98,97cfeebd,b07bc80e,417e73db,bde10972,57684543,151c1940,a92f7e68), -S(dfd983bf,84da8670,1a475a89,66569aa2,59c36fa7,9a5f5142,fa62cf34,105817ff,91973764,28e0cd11,11b8ad8a,5f41d6d0,3ac5b930,5701d1a8,d621da05,16e6083e), -S(e89e41cb,5dd179e2,ecb2a48c,af7f3dbb,d4d9fb3,78eb0822,6652dfff,593266b6,7dcbd3a0,765dfc52,8244c19a,df657719,6ed46b1b,2bf62042,949f0f57,df872d01), -S(20b45025,780c01e0,e8bc2899,7f59aac4,ff9434f6,bf4ac433,39096769,f3e360da,4bec5654,5409a944,c68f0942,a1fca7dc,aa89a2a0,4ca9d6b9,b325eb06,9f7bff95), -S(ec4820f2,955c17b6,81381e12,8acbe1e7,75669f02,8517dd41,f4723d3e,64d75bb2,41ed16b7,5dc65672,eef6166a,b86a419b,ceddf23d,d365e63b,578388ed,bc6bb8fa), -S(b15cf70d,523695d9,48dd1f7d,2f2a12cf,aef60bfc,93a79410,2678ce11,c4233424,63b11e19,1335490,8eeb94c,6bbf1875,f867cc17,a599e83c,2aaa4553,47d549fb), -S(d9e85a98,5cb2dc07,790b0db,1e5a43b2,a51b882e,846bcc2a,8c2930eb,efb79f6f,482abc51,54846788,1b8551f5,e0162ba8,3ca192de,1ca4ba97,19ffdb18,57583b57), -S(6d8dbc0,cf0b7081,c03e9bcf,16dc7445,3c9eec0f,d21f82c8,d05c70dc,bf61db91,ee91fa7e,4f5f59a7,5841d903,ac0a3f0b,68c837d3,aedeac7c,bb9576ef,a7f7ece6), -S(b12c9714,2b5a8ef1,cb2b0cca,9316dd0e,7969a2bb,f7fa34ab,4cd412f,dbc500b1,690c027d,e9327f7f,3f761509,c57a23b0,b2d7cbc9,e5392472,8611ba10,7e5a8e61), -S(970d6bb7,2dac2f5a,7588ac62,31a7425c,aa120592,80f4cc54,19b55126,ed4f36f4,3f541ae8,2186eabc,562d3e1f,7492a8bf,68e45210,9e5d9ed1,ab59aaff,9dcbc58d), -S(41605872,337e0cc5,f9322c5c,a4dc3e81,40b8bef3,b99c1285,e0b5c53a,d08d25bc,3a52bbfb,d18d532a,53187d3f,f9140aca,38058be8,ddcafdf3,83f4204,780fbb56), -S(4889a88b,7e9a5d65,bc564fa1,12a6318e,564c5e39,4be6c4ef,875e79e,f33358e,e0757939,a788755d,c54469d1,3e82d9e,a9502478,3dcc51bb,8856c5d8,629b1da3), -S(90ac2fb5,a463523f,ee81a501,510874eb,ff69456c,3670decc,2d14b3dd,a1bc284,b6f10a6a,c316af7c,dfbb3b7c,6aa30846,10b2f44a,1e415fce,d67245d9,72d2fc63), -S(9286dbdd,9477d600,ba2a941f,e467ee8d,9a7b114c,dc42e488,8648854e,febc5a1e,5ef9e3d0,ce7f522a,c5a1e46,5281bf98,a63623dc,f300be6b,d01df5ff,6661c68c), -S(6b774b76,50623f6d,cedf0498,683c05b9,1de486e0,5f9f64b4,dd13b0ab,eea0c53e,a3dbed6e,ebe68c9a,86468874,ef2ef5ff,3142266c,756b48a,3314698a,c4a20162), -S(e5335352,fca65cbb,8fa6e275,ce8a0432,d7ddbbf6,f8854e4a,371b07c,909c42b2,30fb3def,31c8bf51,8e2542a7,83736e7e,d87f1c97,70465120,47faf3b6,7764d77a), -S(f87c5b0d,a8edd93a,bb33e606,1fc34377,54a236f1,44bc0ba6,1cd26f91,86ac75da,92434741,af204fee,a03027ae,1ee5eb45,82769d1b,c264472c,dfdddcbc,50065424), -S(dd9d3fc2,96eda501,3886376c,88af214c,3a4dfc9f,eed0776b,287cd32a,2fddd2fd,32e630b,2da6114d,f09ff5d2,eec619e4,48f849df,399e5e4a,e802efc1,dcad04a6), -S(10108724,51bbc5d9,b045666f,fc45ccde,c29b3a10,60ba8d76,5fdd1f5c,1dda495e,c86404db,ff9aabf2,599f6c35,e6a8d7f1,2654844d,add8c787,86158faa,b10b5f85), -S(22f7f223,9c8fedfa,cdfe80aa,84477ca0,df289636,2f055eea,3c63bbe5,58443a98,661ed060,8413a4b8,775b9916,14d848d0,269dc75,4d2ff2f1,b4a18fa7,ef0e19f8), -S(9a1ef62a,7567f9d6,9d45edc9,3ecdb7a3,1ee6793d,a2d387a6,304e0185,3416ae70,81f8527b,4c9fafa1,b2fdd185,57998861,4f6ea270,463f8261,814d190c,80f93f4d), -S(b04946f8,8b0c5fc2,13d215aa,53e3d90,df45d13e,bf7b665c,d41ebd3,58cbe5f4,2e92bad0,9b485af3,904446fb,14fe3624,c447e72b,41519297,133933d0,b6191869), -S(aaf764cb,7db7d191,c2dd7061,c213b469,bc270677,7ae0ce31,b0a3f6,7ec26728,4c4f42e,5ffb9d8f,e0625906,b17b7857,8afbd773,834e40bf,c7195f08,19aca859), -S(a236de9c,e071504b,e8108d5d,f5cb7ffa,d4a333e5,1afb1579,2593706e,fa04efc7,773f065a,227634be,3ec7d3b3,4ba462e4,d50f79ee,19541896,948ad725,c26bdc88), -S(3794260f,302e614,aa700f32,e41a0ee,c772d549,58b11533,2b7de77,925d7cac,d1896d9,7b5e2ee6,9ab7e55d,83381ad9,bee1b87d,d3991f53,4bb67237,830e8926), -S(a2436b37,7fa45dec,eda48686,e0705068,ea607b24,58482794,aae3345f,353f6329,e1da48be,8cc2c88,5bae924f,df1a328c,37f96261,3470a841,7784c4f,b965e05d), -S(f9616f77,6a125158,7165411a,582ccc1,2317e260,89412bb7,5c2a63a2,dbea5658,39a790f8,111db9b7,f3b69bf9,9d0982c4,6d97a18b,c937e6f1,3db36ea6,9d7471d1), -S(4a720ef3,9c907f62,720ff0f4,c5d193df,c9bd3613,6f49f72a,69aaee15,b3b7fa42,6ed9eea,cb95af1a,5b91bbe,27ccfa4d,f352a227,67a250a3,179f94e4,bee433f7), -S(dea00421,c07efdd4,24749981,713c1c13,fb23f974,fdb37f45,35314d22,b75cf0b8,2e91b078,2b3dbf41,3de9f98e,e421ef30,bad6cb5a,b57e457b,272f3f46,7709aa32), -S(7e14f09f,f55a0b2a,88518714,68340514,903b2ebd,3525937e,2b0efc79,bb1d7b41,30fa7849,3660b715,514b7fb4,5aa50324,a7958bfe,4db78914,966340ea,c8ea96d9), -S(6536425,5ab57582,feeb109e,7a9657c4,dfd8fbf7,57be61c5,a769ae58,56ae990a,bee94b18,61d474d7,40674349,1b875022,8eedcac8,99835433,529a1621,bffeaab), -S(8448e3ba,f77574f9,2bb731a8,d0d4d3f3,21531c7d,189ba5dc,2edfd54,78ecb11f,425a1eb3,727a5bea,478b82f,d9fb7c9d,b933a7e,8283e897,d1d21ad,2281d39b), -S(d2ec1adc,1d30ab11,b1ba87ed,7765f848,5d097e83,3ffaa26,2eb5aed1,5778ec35,beda7397,61ff8a32,b0965b47,55c186a3,8d24e8cd,5dad81b5,4a106abb,335c3994), -S(3b205375,ae0ddf7,c2dbba5c,9e14b5fd,e8899448,4ea0d82e,a939e1d4,f1d8dfa,bdab6d0a,8d1db118,785bddd6,81c3a402,460137f,f4f1c26a,d940708f,969df70), -S(eef96785,6012f0e2,5934efe7,b9199255,869334c2,59a62384,f2cc4b4d,6f5865f2,1806efdb,ecd0588,17db47ea,10ed1866,6bf0e9c2,7a2bd661,91d92d1f,4ba0a9cb), -S(9271ab48,6a17d2d9,c91ef3f8,73c74d6b,754bdfa7,67172cac,53ea741c,e101abd3,4ba3ed7c,1ea7d0a5,5c4ad38e,cd032e5e,782b69d5,3ade655,a8d8354,422de96b), -S(9bbefe44,70872b67,3ce6afe2,43c32b8,e2409b69,b57f15b8,e1d2b4e,d0e760f6,a1c6f4b7,cab89ff,ea846bf0,20ebfccd,77e7ad4c,68a8095f,c9b56a5b,f57e4dbb), -S(cbdbadd8,5cb42d34,cf249e78,1929bc4a,90977ed3,e6c7fb4,5f0713b7,3e3ba051,1b2a60ba,9f4f727e,c057d149,2ac04e50,42fe053d,89649be9,4fcff26e,8d3ba7cb), -S(414eb1ca,a37e098c,6d4257b3,a9e22047,652e5c0,e4872547,7e97a2d6,b89151f5,27600f8a,b3b66f86,6e6a712,c8d2d557,736b9f2f,3b7be72d,2783a5af,35cdf7cb), -S(be0e548d,4302918,60ac6c47,4593a5f7,169b3eff,c9d18878,6eccd511,e1f195bb,fd26af99,8ab759b,c9a83d54,6296efe,cb0faa62,eec5a7d9,98a0d80,e36a494d), -S(ff38855c,7925713c,80c0600f,7cc3e60d,9aceb7d4,b1199d75,2a83a67b,6b1dec1b,e42b3d08,f12b19ae,600479ca,b593fcad,bf680fb3,da54a1ca,d072d1f4,46bb8989), -S(157631db,883dc9ee,b5b3782b,fba4e430,9426acbe,5ed06fd7,662f06c7,c776e829,cad1de8e,426da993,4a8e573a,5e041952,4b3a01a2,e29049cd,c9439de5,c5cbc4a6), -S(c758ec6f,4a7d15b,efa56470,1f8a2278,ed886788,1aa2a772,c20fbff,ed05885d,e3e80138,4758c6bc,60f10beb,7d75e7c5,d0a541af,38ddde3,b7c5f709,34fe0ddb), -S(e20d3b67,cfb8226b,7b22bdd0,87044f7b,5b29a277,bb5286f,80093eed,69277e67,ce6a8a7d,c1bd236f,961610f0,15a9cda1,9ab85200,abbc6d0b,9a041ee8,9d97c743), -S(b1d70b27,a855ceea,149c0508,2f88d465,6aac5541,aabe223e,4b13028f,10a2aff7,4df082c2,87170b69,88b05b37,1d4b5181,773741cc,70544f4d,7d3742cf,77884caf), -S(f30a09e5,9c163445,5f231a0f,52d9e6b7,8c336b07,5f1ee6a3,bdfd4cc,1bf213fc,acb8bd60,eb919332,a405023f,c799072a,a2838dbc,7ef8d042,7417d61e,41c6b00c), -S(8a615da3,f0f92f20,e8dd5ee6,23178403,ac0287a3,93173dea,1bba53cc,2cd268d8,bd7a5a1f,ac8d4157,6b51f9bf,ebd581b3,ebf470d0,43731e4a,4dd391f9,423d32d9), -S(14d45568,f9b4e6ff,f8062209,7dd34f36,17d3fce3,e5357ead,baeeb480,2a43e7f7,25e65c8d,50296272,718ea121,cd5a1365,d134a134,fca3a5f6,324d7cb3,85f9f163), -S(706f64f2,a7008aa5,d3eabb07,b4a3a3bb,f18eab6b,cf605117,c70cc0a6,280e2084,cce06389,bc03b45c,cb235c88,19639a27,5a78ca00,9e99978,236411bc,687c93c9), -S(db4f0639,fdf573be,8d7d4f84,4d8f781b,51731003,24343be2,6c8805ae,fed3b91,bd1564d8,8abe4aef,dfe581bb,3673f874,38248b1e,7b11e019,6e158bf0,5cfbebcd), -S(43e3c600,4f3cd3e2,aed372d5,60348976,f420d1de,95c70a4c,eadbfc9e,df393d32,bd09845c,429c91af,9e9b3441,321c68c1,888f8c31,15960131,85c90bd8,6b9b30bc), -S(13192002,45d0e72f,e9f289f2,d9be96ac,ac2f1adb,37716658,700aae4c,91267ef6,864b391a,aa20047f,38308f95,e42f4976,494e1a35,100affc7,2d435f85,f936a039), -S(752bff23,288a0554,7f048770,da6abe2,e70431c4,60a71765,40b1c124,89ae7383,aa2af83a,92ab2a29,1c5f89e6,61a18075,d6c3e8cb,ef6fc0ae,c283e77b,56fdcd5e), -S(af0f3d24,25247b8,cbe6e377,ed72afe4,420a886b,aa995671,d638884a,ac238fe2,b7fddd96,86bcbcca,f363b3ba,ad214771,edb9a392,1bbfa25,870dbf52,a42e9622), -S(6be310a6,9ad4a56a,cf79630f,e8767f0b,c986eeef,609eee6a,f1a34657,89c3b93c,2ac934b6,f549d51e,8bc3342c,9fece7c1,c79fc301,bf006cca,20e014f4,b1a9c768), -S(a53b9a96,e9d44aff,ff7f4393,ee691d30,ca4a115f,60267b16,ce11027a,73a7ef1d,d70e70af,5e8dc02f,b3ad170,734e8b13,8567dae0,d73f9754,d6070563,8abfe3f5), -S(e782675a,5a2dc77d,383e8d03,fb2b126e,5abcc07c,391e5597,d127e60d,bd33bb45,8342ae33,fac4979b,fd47d5,b9b40d85,db40f79d,42308ef2,4110b7e7,7dd842d6), -S(eed988ec,3da0c2da,b7235b89,53ce7bb9,7ad8c4b3,7ccafe78,adf5f2d0,911a11e4,b86c5a28,fcabb2fb,4f1c83a2,77174144,b0eb86c5,aec7c52d,59b624aa,38bfff3c), -S(86783a2,5ec820bc,44aa4aff,85212dc2,fb169f73,4b3f359e,844fcf55,abb2a991,6addad83,3d08b1f3,3640ccab,4a68f35e,6ab63752,9f562c11,3ec46833,66e8da1c), -S(3304c750,d62d2678,beeb4c3f,55414ab4,f9507039,55da35a0,193ce243,503b1400,7bca1f1d,87c963b,b2ca8a41,c675b87,205af0ac,ce3d458a,e6ab5f37,fd000694), -S(cd4e3851,b2ad955f,e42e24e7,c071215d,9c4cd24,d456bbb8,452aeef4,4312532d,850be683,bb89207d,62663852,e5b1a38d,d5ec8fcb,c11944a2,adaeec97,17db7bf3), -S(c32114d4,d0c47f05,c31f859a,d26895af,8d46fe98,7565b2cd,ca7363d6,c07cf256,80cd894f,7869eb3c,7df5c5cb,279648e2,adad337,d4f80f5f,501b872,c8b7e9cd), -S(ff6fc809,143454e7,bde3e327,bd7aaeb5,6e7c8c33,93137be5,e63b0ad1,87f3fccc,75aa0f16,ad2cebf3,b8c0be54,aa991dbd,83789abd,214e36e3,3b29f06c,226d0e9), -S(64f9456c,b7b73a61,d9e788d,c31369f7,32d0e34c,5b763e9f,bfaf83a1,4890a8e7,778c77f3,fa3b7edc,afb39532,607bacb9,ed2aedc3,7734b191,ffb5b8ef,867414d5), -S(d9e41a8f,2ffb8bbc,52d10aa1,82d9b0db,f04c0326,8f45d531,500d13c,e25f3d54,728316cb,f2927363,25bb3d18,15fd624b,53e6b442,693a29e0,8d2c98c2,ca524a3), -S(b5a615d5,1241e064,81421f21,45ec55ff,c953769e,74f5c96c,f760d085,2551644e,e2889361,fa674a81,92358a00,61e7b210,c51f88ef,a442b849,d049ce6e,6e9f26eb), -S(5a0c994d,18e62a9a,44358a14,791f4a22,457551ac,5b931fb2,1856928e,a00f15d4,5a706762,8f5ca41f,7df823e1,e27f26a3,de85ad2d,cc2598e5,d8238a0e,587176d), -S(51deb73,6840951a,a0e44ab2,da2a62af,15aacfe,c2740819,9c57959e,10a03fb5,4a0a72ae,f05886b0,6c03b91d,68af04c6,818d5ca3,4e278b6e,d830833d,c15745de), -S(5d967cac,ae97fb90,7f2b8da6,9768a0f,e8a56c52,e79ed9b6,ae4e9a0b,fd92e51e,d840c983,bae8897c,e443d9aa,874bfae1,7475d00,c0728dc7,5090400,47043ef9), -S(2e71c7b8,e187f250,bd500b91,1526f3c9,154457e4,35085672,8d2bc76c,c82b8714,53d13e6d,51840bd5,3e8ddad8,6e6479a8,7b756d57,bf3e9658,c0c0f434,5da398cd), -S(c45ddde5,3660689,113cab5d,f4e218ca,159273e4,db18fb12,d2d80397,1892e9b1,e3bfafe9,fce4db8b,a68a007d,f4c6174,6addc8ce,13b63537,472a2672,48f9203e), -S(4792e0f,2bb7cc27,c44df3d5,b3dfdab7,319ee762,812ff2c6,65da6ea1,2548110d,d3fada96,78c437d8,5d9d9577,3e40ce3a,7cdfa6d1,3e7f4db,17e6502b,b17a71ec), -S(ba662d39,c5c81e15,8ba7427e,8c0633fa,e8e9ef04,7fa408ab,3836a674,328d458f,48ee6efc,f0789fcc,901cd9cf,59fe6d0c,d3212180,20f90f22,682048ce,ca9f1138), -S(be51e863,6aa87c9f,d348a0ad,a7bec639,2ebf2ab3,d4cb68c,680ef1ee,6cf6e806,71ff99cc,7f6cafa5,90bb218a,cdd62880,b19ac007,8f171c81,876370ca,affaa70d), -S(75bac33,bd6578e7,c1afb10e,3521cd97,a51546e4,eed4ad4d,e70d5348,755003a0,5d700b34,fb93c9df,70f0961,bf5902dc,c51c6ed8,163e1fa2,6972e474,9b6da1db), -S(d7647193,14152aa2,98572779,1d1120f3,106a1397,3b964b93,8149694a,fc584bfd,6fa6bb33,a75c0111,cd6f1b89,177b419f,d361676a,93d0f7a4,61c6ce99,e667d6cf), -S(9ac1d334,59882a0e,bce90ae,1a404f61,35e9465f,5be0ebbc,61a479aa,f348800d,b7195d60,a7f4141d,145fd1e0,a5e58305,b1610ec3,4f97b09f,d8a8e57c,3041f05d), -S(bde59b,e8de3bb3,cdc7f5e4,1743a489,eeb99171,a89bcba3,5eae33f8,cfd94d2,208b222a,5831abb,e5f343c6,761343f3,211078d6,ffd59690,9fc976bd,86f6808c), -S(58f7e872,6a34f41f,3720b5df,38a3df88,58d2238d,e60a88da,d4198326,f5e37ea4,13f8cc5c,ea43a637,28c5cb5e,b4fc5381,d5618b4,477758c5,4dbce46d,ad7f433e), -S(fe6d09b1,93d1a7c6,c5d5f6f1,522b63c8,aa257503,9add5cb2,21d5950d,3c4bec93,eb383e15,24f52785,6d8535e3,c6f2f8bb,deb71907,b6151510,a4839b05,7e3e6dc5), -S(8cca7fbd,d0a041b3,e196b08,353c704d,96db3817,29d42f4,513ff5,467ddd0e,23a0dcb7,dd044a24,cd9202c0,4c32cdd1,fd25c979,b0a1aa62,67bc2321,ce7a5f1), -S(a63de000,cd76bc93,7515a124,a334719c,bbd4538e,9d04791b,2b0de33b,bedd2bad,4afe72a1,d26fbe8f,8f3951dc,1dbecff9,c8aaaa9c,bdfa03b8,a6c48cf5,764f65d), -S(5a42a678,c32a688f,e7cc9688,9f93078,8b5f0126,f1eeba7a,c585b1fd,9f97003c,4117bd18,e961dac2,d15be023,6e1254d7,eba89a0,b4ff95b8,82bffc4a,7a375f3e), -S(3c01ac6f,1ba11409,6817408c,5e6191c7,d401f258,f0345c8,6b0c83c6,ead7ce90,f39943df,6465cc6f,792a99c1,b2c97727,421fc8ef,11b2cb9a,cde28709,628efb9f), -S(ae63ac2d,78e0ef81,312fd73f,105d8ecd,8d5777d0,75d06600,da8f5b4e,3e20a8be,50ccbedd,e4d4241b,bd62c0ab,68b2322d,c0e55c28,c8f71ee0,40dbfe6a,d7e33d9f), -S(c793575f,b3ca9516,945bc82b,aec1114c,5d8f8e0d,7cecaac3,31e209f8,22d01044,b2d3a441,ab01f822,366728eb,dc843b7a,82c82175,fd4ff08d,700a2018,48766b1d), -S(e6438209,26baa22c,e33b1588,1b5c0192,b14e72bc,f162f04b,5e6d5941,8053e338,90989550,9fb4a05,741ac6fe,bd4b78d0,15710c50,6c1c3adc,955604a3,1907684d), -S(5d9b21c1,3331d32d,d7827982,6d41a5e6,8ae70be2,b9d5f346,a82b8ec9,aa559323,6e086fdf,95f4a998,66b3f471,f3c722c7,4da8c7c3,1fd65705,68cb434c,1427e5af), -S(81ab7527,8cd4e683,f127e7df,2153fd93,60bd2f07,32a506e8,55f60082,7fabec86,cff8b01d,24be6850,6e068910,55a5125a,ab7a554f,81e5e8c6,78348026,ee7248fd), -S(4684137b,1e19dc84,8a521ed9,e6aa7747,548535e6,6b9fc1b5,a533c580,e7546317,8c2f57ae,7f42873d,5e3ed228,a9276a9,cd684c42,c43113e5,b465cf7d,eef75911), -S(3844877b,e43eb3e,171f614d,7a56aea1,4615ce67,b09bc928,b6a16b48,3c15639c,a2e17211,48d95e9,6690d982,4a7bc84c,c3f0388f,e54e2546,9b58f624,c3761634), -S(d4246638,80a8efb2,99d3d73b,4efd73ed,5bf70111,2b5cde7,631067fe,2b9de212,b98986a0,229fe086,c91b2a3b,4373411f,baa31c98,7f475ffa,1c29ca,93d4b80b), -S(515b8ec9,650c5448,6eab830b,4ee0bd7a,4525c8eb,19520c3c,6e6a214e,a7861c47,a7b12837,51812bf5,c37bc48f,ce08de95,94e4d619,18726c31,57bd660d,80025185), -S(4e499a52,6352b7b0,3d78af31,5597155a,eb4697b8,14ff1d5,93b9b838,6efaaf8c,bd4f5e6b,dbe5a232,c42b0ea4,e55f507f,2ca33587,349b1f0e,56a25820,60ef57d9), -S(2c9a7cf1,553e2593,c455a8af,9b12a0c4,26d579ec,6a097483,a7274edc,98dddb99,99aab288,24298866,f0f42672,395d39e7,338aee86,35c4cef4,ba45f067,83c8c8ba), -S(7d5bdb5c,fdff2871,23a9b78f,3ce189d3,ac50fd6d,fc49bef5,953ad197,8d27b0fa,c76a17fa,97ffc25c,8549d7b8,f01842bf,34afe80a,27be4c4d,fdd68229,2dc83ea3), -S(fb222262,444d6db2,43abdef2,9e0ce41b,818a177,db630c50,9340eef6,24070256,8a42ddcd,a7405cce,9782e8a5,23ab108f,3e5be176,49910b24,c8084253,46b8596), -S(b3212a32,2e415360,62622dfe,43da56df,4beeaee6,b8b5e783,df514a7a,83eed60f,c9396626,6dcc8af7,56efe8ca,e86a7b28,4b2e847a,8e571911,cae76e05,58fe5417), -S(80c90758,1ead4640,94ac1b9,3250b9b4,caebcd74,582bbf20,16f013da,1f4f01cf,d42a5504,c5be0a40,e7bc4242,32a9d703,58370eb5,a54be08c,93f43a22,6e5e6ad5), -S(50d17433,50bcf037,a310a05c,59adbac5,e2fcda09,3aa6ed87,9340efc8,7ce0e228,9e733972,8e88d9cd,8a4e9e7,7dbd7b49,114d5a71,6d91088,df928d60,743bf2ac), -S(c8e7f596,3faec5a3,a32d1ee,65d1596c,a7edc87f,486a13d2,c7ca7b84,3b358cbd,37250705,1891b406,34a9752d,942e6ff5,67fff1e2,d67a88de,ce79ec56,97f5ec38), -S(91f28714,e47e051c,84bb29e2,db84472b,e3b78524,c998a071,731e4f41,9b94d2b6,8ea1eaef,984af3cd,21be9097,99f68033,7c6e3479,643e0c68,b00963bb,d0125f0d), -S(d50a1905,ac4d2195,5c2e6733,5d38a08b,26e29809,674e1b61,8004d18,f823f402,83cdc5b5,33145488,35884fbf,f14b8e5c,35c1ffe9,29fc5222,c7e2a868,d5906827), -S(c45086cb,387b9bc8,a1d7b71,ae74a87b,50ed90e3,a0027766,98f7ad4d,809666b9,1c0abe25,d46ab7cf,dc4a5ba5,e3fcaf27,822b5f0e,1bc08af4,452be7ba,d480e605), -S(b486a681,f9b26f12,c67ba147,7ceb43c0,90539587,72dd1dc,15cf1e74,9fe3856b,f4bd7623,fe97b6e2,6f49e292,899a7f4e,e7925cd5,3fe51cc4,33f77d1b,76291240), -S(c7563596,946f57ae,f91d12a2,4dbd2d0f,726422e2,ff6ea15c,f70c2e7,868e6f8e,566fef1a,aa3316fa,e935adc5,bf1e9682,e3d00e24,2bb57e1c,3009e6b0,df58449), -S(6d0b65ea,265366c1,7740e473,f823ad65,f38081f7,86156199,421a8b46,117b2733,4b724837,8748545,c6d0511,79d22b3c,61932bc3,563eadc9,a8edc5d8,1c170f5f), -S(87973dc9,379225c,50366d92,f0591837,71828fb1,d1d3a65a,20edb955,c2e48414,bb226cc0,67c7fc4d,99791a74,301167e9,62e92498,6ebb0fad,fcdde6ae,8c39223e), -S(72e7347,cf657935,be5939bb,648bf628,6a2e870b,cdae70ed,bd2c499a,be83191d,431e74e6,bccfbf3e,3fdab221,e2274a77,947d9cc3,5bc55c01,afa2d33e,8234cccd)}, -{S(bc4bb9a6,292aa09f,5c66dc9b,667c4642,6b08211f,a9a80f5e,f3f17b,21f275de,5d0e0492,39a862ec,b9649572,6f11bc09,cebd9f29,d9407ab3,1603054d,d9b76b07), -S(59fa87bc,4f47100f,f37135c4,1f5da6e6,28b76376,e0f365d0,eec857b,4b342b19,cbd82bed,1859e567,2e37e18,e977fdc3,6997482,a2db416c,686b3b64,a3c1d66c), -S(3af64d00,ddcaaef8,172aa0d8,adf5ebe7,fea87204,38125e07,eb74a5ef,91c17acd,4d695d52,ab785972,a425f6b8,f9f51e54,7067f9ab,b2af1085,bf22d1b6,7f51202), -S(31f9458f,d3544b7c,cf0a55c0,729ccb70,a57fc498,2078ba85,1fe4bb32,164e9259,31c6bca2,eb57ad06,e74da59,c824c720,17bbabe1,2e71a906,e6ac2e2c,36833b0c), -S(f2bcf05e,bd8ef03f,55d3d5ad,dba85359,3afb6b49,d72b2df5,c8107020,185d8173,a0c011a2,513c227d,22f045d,59d763cb,7c820ab6,e0b35144,66acbf77,8c188b22), -S(9373aead,2e733de2,cd4ddfd9,43675acb,40e2fdd,79c0bf12,45f8cf95,f2ece30b,8f171f4,5c1cf577,7416c873,a87af091,2a2eb20a,82f07c43,1e1f1b00,36c3276f), -S(5d2a3111,6cf78432,c8a3b0c4,a5021720,dbdc5e94,d842779f,6df51fed,5cc1e47,fa5381e6,ecacdb0c,6f326569,771b0f5d,d7e3c3ae,7c64cad5,ec03220a,33a24c91), -S(56549c28,f339c6d5,77efa8b7,3d795f64,580dafb1,f146268a,c7e751e2,fa3f041f,7aae31dc,2b875c94,6c2ce9aa,a6fe33b3,13c3795e,a188f343,89c34a48,bc3093a0), -S(ff4aa1c6,f5120040,5d488787,65f9931f,366fad1f,8a7d9ebc,abba9805,f6684aea,faa72c87,6956050f,663c172c,b3a0a3f,56e7e698,62723659,7a20c0ee,5bec6ccd), -S(65873e26,5ad6233b,41a6d42e,ebf1fcff,e8b1ed8d,97eb9131,1ede963,f8058c6b,80b955a5,d1648b0e,ef8d883c,24c2499a,f0f9350e,d003674a,fec69be3,d9f9d2f0), -S(b3a54b5d,3e19513e,b7be4c78,633a0e77,b4ec4015,d891bb6,35557fba,eee92f4d,1aabd4dd,3a995ac3,8c021f50,f2fcc578,5cdc724b,2b657f2f,9f82e777,fd449eb0), -S(30e69221,e75f5bcd,7b017467,d36abe41,d76b3589,1f82f38a,ff79be7e,fe8a7d44,95d5120b,807d3f47,76b7ef43,3ac7db28,e6b83c07,1e33573d,4a45eb8f,51296c88), -S(3a61f393,d842419f,f9d49dcb,e169bd36,2e28f92f,9d6c197,a441027d,9edc36eb,8cc6782f,898e586,1faa62ee,dc2ceee1,b21ae86,9e40e69e,20872b74,361f6f0f), -S(f46f5bea,e58e4a74,1838e312,57e3b579,5826ad3b,6c0576c1,f8b30874,c3a5779,91e35b62,55148a94,df34dcba,d2aa00f4,95e91eae,4a1c2d97,43a7fed2,d2713854), -S(6db13572,e3b35a2d,fdee5469,52d69463,19b5a95e,9e7ed8be,95cace14,471ee6eb,38c2be05,a1fb0fe1,e9dd09da,2684b4c5,de4e93bf,60fb3816,aa4261e,fdc9d79d), -S(af86cea1,e34c2d74,fef9d3a3,43d66574,2ca64259,f848885d,be0be05b,c8cfa432,8c8a2d2,da789ccd,b7f259c4,124ae844,36890818,5272c381,16bdb76d,f71af157), -S(89e5829b,41074025,cf6929d4,63dac04a,bd3139df,21b589d2,af8a0b7c,1c3c625,f762d80c,99197627,346af77e,f5295bdb,d86b5fa7,94975c6f,881386fc,e2609ddf), -S(2d589866,819b012c,ee8b7f5,63c20617,cf7d3f3d,ad56d4e1,c909c8b4,2071e6c8,cb7b8d2c,ff2bb979,1ff6f9d6,28d6a67a,80d1029e,d8d08573,f5e3b6f8,8dfffb67), -S(93ea11e0,e298b3ac,16ba686c,f5c1b089,55ed8d67,c318dcca,cb320d08,7f33740b,df9fbfeb,fb1547a3,92954300,98dc59b0,8af26c3c,ab7b42f8,5489af52,409a11d7), -S(febd58a2,529be1d3,8176be80,7daab920,32cf355,9ffd7d,154c9962,ea66567e,299967f5,5fbbd509,76271d5c,53975b3d,a4b43d1f,71f12ba,4a618a1b,5c11e484), -S(eb2e3d64,a5eecd,bc65bf45,405c8af1,bf4683bf,465b4a1,f8dc4627,b5b5c81,3c6d2f03,b30b2e49,4d056d55,3d2cd0bf,8c8f41ed,14b260e5,7bab5d0,c77dc06f), -S(9fefc3ea,d2ff9b51,57c669d0,bfea2c9c,7bac751f,9ac83c1a,143d05f,ba408216,10f0b7fb,b685e767,41fc9a7b,6c90191c,6b428e32,d9c3e611,c97aa120,8e361bba), -S(90b9eb4f,68cec46f,b7e426c8,94576858,a49ed785,a1b5be63,9bc68e5,33db8479,9aa3cfd,271602ac,5e9e84ab,343bef4c,9f8797eb,79d247f,7fde53be,11d32335), -S(2b80ca58,85919764,80e54e26,ba726c31,8b491c9e,56ac6d4a,f2163064,c69ce44a,50a00290,17815845,90773443,1c7c82dd,2e071d54,7d4b657b,f9edb939,24cb2a65), -S(df8e261a,55523b2c,933d0d15,c4bf5a0a,a8b2d01a,bfa7e064,d48aefd4,44485775,3d043bf8,7dea2305,274957c4,b8b5b37b,cd477b00,7d86f45d,b36fb42,c53c20a7), -S(7ac6a221,445bb8a7,ddbeee44,3aaa2de9,86ec1fcb,551caac3,84e2d37c,8aa05558,746446bc,64e61523,c52e5a56,b1315151,904a3d75,43191b9c,c32172e5,f08d22af), -S(5c0ace30,4217ff80,bc37f783,aca722c9,5027492c,3335ad3c,aae56270,c58509da,39685f11,9a646344,92a1157f,ca4548aa,ee37d52b,87d0148f,850976b8,4006dc6a), -S(6cd63750,f8318534,74da52b,11b8d66f,2a72c83,582b8c88,31d6be9b,ee5a826,57ca2d88,aa5f6970,54a6cd3c,a568f9a3,cd850d31,3510b1b2,adef4822,a943b3b), -S(9cabb7fa,7d9e6d89,42dad033,a22a1acc,1587e80c,fd7a2c78,fbc9bc11,c2cba6a0,f6bd65e4,1639bfe6,44f1101f,6acf65bc,ae5f56c9,f132b37f,8233f568,a23dd0e7), -S(233059ef,878839ef,60e1756f,771003e8,9af5569a,c5b0b849,fa84184,b9b9964a,654207a9,ff112902,9c9be9e6,d3d24bc8,a61a5c8d,4c25143b,5643e004,4fba7520), -S(7cc5b46c,9944e309,86e22624,99805a7,2b9ed814,954494cd,18c74882,aa3b8f39,c7ebd041,c5877c83,2cf05c42,6569ae0a,c1a37583,ceeeffb8,8cbc7090,ebbd71de), -S(9c55c21a,48c766a9,bc31a0b6,6e65a719,ec4d181,994cb533,3bebe7f,e017faec,4037846e,c6ca685,5764a8a8,230b07b,ccb9b145,b0d4a0bd,8b26020a,2d2c9da), -S(7926a60,bfdfc1c1,4d20082d,37b4a6d9,8e7651a1,4ed2a3ce,547a99cc,feffa208,da120ef3,d60469f5,dafe0776,8717dd2,5f95fc58,87594181,4b54604a,1aff86c), -S(c52dd3ed,e63fc9db,95a88ed3,e62064dd,f7f9112f,c30acc3d,3fc8438b,7d206c14,e65252d,2ecb95f8,a45059f4,68bfccfa,75b3b3ff,2ec9bbf0,46f51b0,416592cd), -S(831432ea,8e1ebdd9,3e254f18,15ad0c16,d637b04,85d43d4a,9eff1221,5835ec2e,af620dcb,328c94fc,b238fba9,3eb0d1eb,6f3f2838,9aedc2ac,26cb4f87,ea9cfb8a), -S(e5b822e9,72a7a2fb,723c135,d6d45602,deed7cff,61124fab,ef5a4fd1,68828773,117f1b94,6f715282,bd5bcef,fc2a340d,de226d52,cf3a9643,bc8c5119,542fc9a4), -S(59b98a72,bb15c51d,15f93497,bdea606f,2505b1fb,f37e42a5,73fefa84,b00deb6c,cb1feaf,bd5325eb,e604aaf0,480cabde,d6a5bfa0,bf9c4bed,674afb3d,65dcc5d4), -S(8847961d,6547b9d2,29f1faf2,ec0aec4b,8579c8c3,b1fe967d,eec280a2,ec45fd92,5280bf82,96b0251d,29ea6573,fccae24c,bdc4af9b,77043461,32103fc0,badcacf6), -S(bddf032b,d6c8709f,4b0f7b0a,cec96259,6db33d02,3d2270c,7824307a,b88bd4f8,b2fbfc91,c7944fac,dc69076d,90a1bc58,4d202119,574f0fe2,223f7821,c8100dd), -S(966bf84d,b5ed857d,cbe278d8,25167aa,eafcd957,597e8c08,241702aa,fe983af9,85e373bb,9788f0f4,2e4d6bf1,52136f90,b0fa7325,d2c791cc,4a7103f3,4ccc0b20), -S(7a16d469,e57ae4ca,46e198b0,4f970300,c2eed190,58d81028,ff2e1283,267099ca,4bfdcb6f,cb3b9c0d,782737fd,505c984,41c82029,db95b83b,c445b581,d1ff39fa), -S(818ebad5,7b04a0c6,f1235c71,634cf8d1,945a369a,8c707856,c58d2316,5bcd13cc,3cb6c26e,a053581e,821fcb36,174e91c5,bdd56144,7e3bce4b,c69f4f28,8968493d), -S(72059db7,2d838163,58b16402,653d875e,da620a67,5628a861,c6162f18,8a2bac61,232ebf0a,d0cb25c1,78626633,d4d61d47,d358bb35,b525e624,c2d6ba41,698f813f), -S(e407793a,b1246e86,aa9f782e,b1a0422c,28846f2e,49fcd886,4348c22e,411259c4,b339b1ab,dab01588,e8abaf1b,39a29055,66c14da3,1feafaaf,ccfb140d,1dc1efb3), -S(50dd489d,851e6b2d,af877b4d,70990326,dd9f9b0e,c22ca933,99dbdee8,ddb7b8f2,a9a28ecc,6d500065,4d3a3747,27be80fa,f41faa1d,6e51406d,13622655,e6cf5ac3), -S(5b592078,d50b3a6f,c94aa2cb,5b1e3a81,74a3d644,2fd12c2b,765678e8,7e00c8a2,8ebd56cd,313938a6,681a5ea4,61409f81,a4af4495,31266c3f,b915822e,845a8d7), -S(f90cbdc0,a228212a,32eee9e9,43e786ad,3a091308,81ad5f04,8a629a7,7035998b,6ae4854f,c789ec49,bbfc5d8e,14cc250a,1b862e51,cb343ccf,a0957b18,b9eb5545), -S(cea133d7,6121db90,c6281060,ead76d4,64b3825b,79363a04,ab0c0bd4,8abd9437,c66be897,96a25bf,867cfea4,f0803e1f,ec3c5a3e,178bbe6d,a972b2e2,e677dc41), -S(a09d9e59,5a4baf0f,b1f479d5,5d3cf051,7b34c007,b41d655f,efe61dc4,4111a4b5,2f21f502,f9752e2f,9848733e,afc40463,8e29d45c,1a294ce7,d09737d8,bc9bd1bf), -S(bebb4360,ec850828,b96a774d,2da91f0f,17c0a288,47796341,d617e1b9,b8728951,ea06e33,55603e97,91871935,f01cb416,bbcd226c,83cad5b7,fbd0eb39,48254a25), -S(d7cf537c,430cb0fd,434e555c,c1303b4,3fb60476,2b7f617f,4c2fdfeb,d5654461,f4ff7415,55841324,3b944ca9,adf91cdb,dbda99c8,90dab0be,8ae2a294,9e61c0ae), -S(1ea3f684,892f93c4,aa9372d,6ba193c4,8e6abb8,868bbd17,d91827b3,54424d5,dd549d14,a684f6fa,b1a401ba,47f42a89,14b0d012,80d24bed,743e3521,16ce17e2), -S(ac0890bf,ad8cab43,fa85b5ef,c10a5c7d,dbaa0237,daf20cc6,efc94c78,d95a86fa,a16a3028,69f2ae14,4566701c,f80add76,48d11ff2,1dd2596b,c30b074f,a5f3159d), -S(6d573525,43fbf521,d49d5b15,36f83a01,748d3470,57254639,4cec6785,860000a0,98b9f97a,9ae8bc6a,7ada1bd1,9a225ffc,8727ed3c,32b169cf,c381a60,3590acdf), -S(7be891a,771227eb,fd583033,e3801618,28cdd0f2,6e72cbd4,d9ffd169,92d7f1f1,be22c30c,3cade74,14bc3a7c,c3b4e5db,7ebb4ca8,b3ef67a0,b89fadf7,7b404fd8), -S(97f0013f,10a9ba96,58a1a5e,bf8f2d6e,4f2c56ff,9acc6221,177d2ce4,fea65efb,bb88987,7b7d1929,4dd4a011,7440707f,916e1b2c,fbf2b0a,5805c5b6,d8e65e3a), -S(77c3d2b0,b7ee36dc,69b75d91,11fdc25f,3996642d,a59b87b5,5f5840ab,cd5cb1b6,769c9cd3,7c4f4059,60129e1a,4bfeff8b,d86a41c8,eaa4e3d6,826a4cf2,5185c5ab), -S(a0a234a8,da6fc04b,2c77c7a7,a3b79f5d,7200df84,76d6737a,e879e4c3,a080fe5c,b9b8a2a3,59af78,9d5f0448,3f77e1a2,923a28f0,9f928067,4bdc1aac,8e8f0bcf), -S(1374c3e7,fbb1611c,8449d724,7ff49167,230b630e,a0c2c0ea,6d438426,9a91fad1,21d482a9,d29778f7,dbc31471,fa120bf5,abfae23b,185dde67,2198c725,47721db6), -S(f6c035f7,270679a5,4cac1f52,449f357b,cc36537e,669f056,3bbe022f,541e5d67,d470bd7d,9459165b,8bd093be,a3f64f8a,fab85bab,25f31046,c3db4167,5e8e7e77), -S(1baff567,622fda3f,7171e2f1,f66498e1,da1a2973,c5ad784a,6fa5af2f,23cfdf69,e1a87fb,1dcf917f,2dd6856a,48de7762,a05e0c12,89233db2,49637e69,15a5aa4a), -S(eabb2399,ebd468e3,84bd7c14,1329f972,96b86a47,53cdefdb,3b539449,d4e04d92,92d94943,ff0dd405,fbf02d21,875b7f13,25eda73,ad65d332,d005870f,951e3db8), -S(9121e2c2,13734da8,23ec445d,cecd6740,e1e5f513,7771ef9c,72589419,25f25ce2,8b1dafb,ebf4ee9a,3c39f51b,dcb560eb,f3e27409,589505d8,a9c18946,847ddd63), -S(51616592,730c7580,c2ba7dce,8f2d7aae,b71c1796,e35223c6,8a6762a8,c0566563,5af04478,c1509a8,905e271a,80c01376,bbcb5161,a78bcef0,1b5116b4,adcf68d8), -S(5489e35a,4800b74,e7d9d8b,99841485,2fd80e19,b290d7d6,22ab9f66,de8dcc11,3ec6df58,ab461f1,9a0879c,149d042e,8e7e5c2c,98dac706,19137120,74a05492), -S(bbd6f40,774d7bb8,e3fd18d2,b7f3c2b4,d1ad882d,73e101ee,3ac247f9,b8720005,17134bcd,6f74cb12,48b10902,b9eda37a,fcf8e5bd,50604a0c,65d08952,460c04ef), -S(1d99eca2,b542ff0f,470e7b46,ffa024d0,ebef5635,c0149593,b4b34f6a,d4531cdc,2e9cc03b,b2e5a461,a3122521,e09cc6c4,63d8e6d7,c4aaffa,c9d036c9,6b74d882), -S(32c2caef,93d345c0,9451725b,84b1260c,a9defe2e,228f985f,f33c3f33,70afa675,6875bdb6,3c8d28df,71317042,d2328d5c,24614210,4d134068,a943489d,e695920c), -S(25107b07,4ac55835,81afb4d2,dbf5e1b8,21c26b56,75efb3,33abaed8,56d0a5f2,626b9614,2d70c2a,5572ff7c,606abe47,cb90f850,2c13d478,3ca4e045,bcc7ba39), -S(d542e001,894cd3e3,97ae2519,f4b69c7,59308117,9ef63ff0,a9d586b,3fb324bc,bdd28dcd,94c208f8,bed304f3,adbffc7f,76cbc70d,333dece8,b2680b6e,19076fa5), -S(c1b950e2,e7cb74e2,a4274cbc,b67772ad,5c32ee22,b18c3d99,e4a92005,3edc000f,e8329595,39709b81,58f892b7,2ac9c0a4,e1e692e4,da526980,2b046759,58f0ffda), -S(8c6c041e,b8b3daca,fe89492e,91829869,2451bc8a,e4dac8ea,8cec1d49,c25778b7,6bb9de3a,55fefdbe,4376c9ec,dea4bc24,ade146b6,c454a441,8c47120f,f1f55d56), -S(4806db6f,bcf9004,e4cc63d5,555ea5a1,cb9107d8,e060e3d8,8fb79fe0,3acf1e46,c0f5f482,288b0036,ca485a74,a6bfc264,88441487,63804ece,e620e47a,16160e95), -S(4b3e050,26545104,176aabd4,40ef4ba6,451bbb0d,5420edb0,4063c22c,2e7d8928,42ebb34d,ec06c95e,11ed8e24,90369796,2d8634f2,2641925f,f765b06d,838b5cc2), -S(be7a60ae,bc21640b,2f027c33,f6ec9422,5e66c16f,1d946ea9,dd881101,5d80a21e,1dd12d43,2b2a2f60,9d434936,ebedc2f0,b9c20747,32275c94,fb7bb15b,bb323bff), -S(550813b9,3c3dc22e,4dd576e5,50042b51,34f1a905,2b28af39,cf87bb89,84cd8211,33cfcf61,91cc032c,dc284de3,7adf0de1,a83e39f5,27273eb7,f361235a,40d6da10), -S(33133c21,98343b11,424655b0,8ed83de4,ab36c87a,1c5316a0,686145f6,62be725,fbf5d264,30a71f5d,bbf33aa,be2ba027,b8abc0cd,37d0130f,a99a6698,75f011b8), -S(dc21892a,8b5e8ad2,2d4fca59,7941bd5a,5099f82f,e47ac4be,7e705a35,9a03eb9c,7d49d315,1d6b6e97,1f8712db,197b3c8f,aa8b79d0,5957379,6b895bbe,581242d1), -S(64e648c6,98b6ee15,c168e71e,dd031c66,27486a0d,8f858342,80d55924,66421465,7244a14,2e7fa0b9,a41195d9,d74655ed,4ac3f1aa,9f055c90,326bd32a,22669878), -S(153e77e6,b1704f24,5ad12253,7f11e9af,e22c2647,67293dbd,fa51e415,950f7b2d,7bcddddc,ba3b79d,7cb6254b,a4b4abf0,a44fdc4a,131eb185,c6a480a7,755cbe6d), -S(24ea7667,d2747412,2adc6c73,4a8babff,df7850c6,a7e60647,e4825f80,9f89147,385b29ce,bad1ef7f,c661e36d,97bb9eec,5d415c7f,613d82b,39f8b131,aca17278), -S(897d6779,70dfc489,800087ee,c67c957a,5299358e,14f63610,c991db4b,530c32cb,42905602,2ecd9bd5,9d8e3d49,9e037e07,4268033c,6ae4c9b8,ea579d96,daca5c6b), -S(beaa3e34,26dbb441,5ce9c604,7db0821f,79af4e5,faafdcd8,8c89f265,77462905,c0fa8760,f9964d11,d2152f01,3590180b,53a67a35,16cf7c3c,403361b8,aab86634), -S(d2c97e5f,85b4025,a66c29bd,23b5d30c,4c8f066e,f68ece5c,df907b2e,558bf547,1e320de1,3347ea0b,13ef7f68,cfc4bbc0,e10bf7af,c031f64e,9a9f2c43,181ddb61), -S(1ec48a1f,169baa2d,ef5bf8e4,e1ec8f51,d91c1667,6906c912,ce084f2a,9aba1d6,498a5d90,6ec47ca9,f6d7c5ee,bd25f83b,a14884b5,a4ad64ef,3fe9ebed,5ef0932c), -S(313ad91d,44f622f7,785b3ca5,6cf9e8dc,389d5aea,b696342f,ce58ecb1,d6e9b45,60f8ac86,3cc5eb77,c8f83c05,81aba889,d48f65ca,b9757076,7d9973de,f4a693df), -S(93f7f233,dee42606,41f8fb3d,d67e6e9b,cb2fdcb0,905e9b0f,92fb2094,701d6ef1,1cda7163,64ce202a,b53e3cfb,b4bbdbf4,1e124e57,85f91d5e,5a5f3205,a4e4ba13), -S(56694a44,a4455ef0,a429a5ef,d11b6440,bfa6e0c1,958b8f2,e3a8d00c,b1f5feed,ae0e21b6,669e1b86,e27df62b,7038de4,fbfd1b10,72da3ebc,82432787,ba5cbaa5), -S(7a6a7dba,80380635,d851f291,d7dbf6db,bce98978,805c738e,8c80c20e,c57e3a0d,673236f9,ea37dff7,c9eeaf34,b63ae652,1b38fc9a,94c111f2,b3e253b,34f05009), -S(d4e820b7,aedaf95b,de86a889,f0adebc6,279e0ce3,b0757972,d574f64a,3fa6a6bd,42762fa9,1b1cb9df,85c55acf,95a421a2,d4da6f01,69474abf,61209ca0,4f062939), -S(62f26014,d06ef2c6,ae6d459,6e45b2e0,d7d28f11,ec84fe61,8baba130,1d483950,d53fbb59,f239a52d,592b6f98,fbe311ee,4c9d4e20,b6d9a8ca,5698503b,eba1eeb1), -S(bc5ac17c,2a9e3731,7dc80bb8,7eccb0cb,ae804158,792b6926,60cf3f53,b2446eb0,e2a67966,a8de04a8,db78b4f1,e37c6885,b99b188e,1d4a1fa3,5e9084a3,96e5d8e1), -S(80743e30,983d175a,ce9ddb09,bb1adfc8,1b059b9d,73c51b42,d29a9f5d,673fa494,eff1e042,89a84d27,2d941b5d,5bbceaff,d3b7069d,9d704317,4b35e2cc,12dad80a), -S(faf014bc,c17df331,1902a50e,fb18469,9f0344ed,b6b057ce,5c922f22,97f5ae5,47301fe0,6fb57e8b,5fd121cc,be2da9fe,e8e918b0,7a9d9228,43e41de,77e2c1f9), -S(9e89950b,e18485a8,14eeccec,4bd484bf,e2c027e9,54cae11a,52bf2a82,43a6faf4,e81f0ee6,c85c5571,f5ae6a03,3ad4791c,68f9189,507e53ab,ee15e035,6372f6e1), -S(496b3eb,ac55b991,fea92454,e844e5a3,fe7595cf,b25fe7bb,c358f0ed,38e9cff4,d13d035d,ae0d457b,540c6b67,4db20893,f75ddf53,5c6c54ff,95e46c76,14a58153), -S(24ed90c2,3547169d,bc55f880,33204740,a2fd2119,63737fd1,debc0578,400c675c,f37940f5,e3e25da7,7ffa143a,865e46fe,a1dd1230,fb42a627,9e791ee7,38b739e5), -S(9cf8971d,43eb50d2,e522fedb,9281026,659612d,2fb2bea9,d7f6a65e,cb2c0703,b0b6a53,103cd33c,6e0c0bd4,5cab3923,29012395,f8e8951a,1fc4c9dd,95cbbdaa), -S(f6c823f2,ce2006a9,6cbf68a8,61f00eaf,4d8524ad,3467f8de,8dc64911,e89b1f7f,6eee9a22,59ad8c81,277d52b2,cb3b5e44,1259fc8c,52868b74,4946b0f5,b8d9abdd), -S(4bfe7,5bafa425,7f1fd25b,12b68afa,abff6771,89f05d07,85e06d82,b6906316,4ee94fd6,a5388fc0,1ab5da36,41b5c562,9f7c966f,64cc387a,9b3336f4,34323adf), -S(d15fa5cf,a481a1b7,8c746f3c,a19e0979,8b7e777c,4841d73b,ec4b63d8,b01c0019,c6fd422,76ae3e1d,b28ce840,29b8079d,7dba4c1d,acaf27d0,d2b29bbf,5ed59f6e), -S(bd17078c,75e7c325,80cf4a88,8d43c5ac,c323d8c8,4e9d5e29,c09c8c77,14ab7397,1094e3a1,21abba10,7da189d9,2f92c5c,f00b373c,89f346eb,351450e9,7377cd4), -S(1acbdb1b,79389dd3,5dfc607e,2aa8134c,fb04a655,c4848cb6,b5b73491,cac2cd87,8d2bcfc8,72da8a7d,1b89863c,ab7610f4,297dff9e,bf9e3f18,8a6bd6e,99421c97), -S(49e5b6f7,243f19b3,c36c5411,a6e34e2a,f61a99b2,38958b93,819ec7e4,6d647af6,9af4507d,850aab9c,9b1eb3be,90c15460,3756e29e,fcba23ce,313a4dd5,290f1385), -S(15bd9023,bad0eec9,fb19a720,e0a7be10,df78b3b0,716978f,5ee37052,b19d1f92,9cbac74e,7adf5e32,8959d826,41fdcaef,1d4eb24b,a5bd24ff,8d2625a,12d0ea80), -S(9d03f121,d28dc96f,ef6eb2a8,d3737033,e9f6703a,1683aeb8,c583b78c,7910eb6,46723472,ae342ff4,fb9fa789,8e063379,3b9b6781,4bdd8f43,840110c7,4e8e03d9), -S(8abe7e21,f025f340,6929eaf8,c818b016,f7423717,c893b6fb,cbea7ec9,7db98a5e,8bde4e6c,c37c681c,4f664731,719ef10e,e0e7f6c,5739cecd,32f6bf87,c1ac6144), -S(66135e6e,e913c965,ecd190c1,9d4bcc5b,e238225f,3755aee0,64852da8,96e848df,c2c5133c,9c033d30,2029ef21,1379858a,ec918357,421b7614,13a4deff,6f855ae6), -S(5dfa7af7,596b611f,24b57d98,59a5cfd9,41ffdfdd,1e80b0a9,994966a0,338d3b27,2780b496,8fa51ba6,b6256d78,aa25249a,982c091d,40cb9336,863ef2a8,9e4caddb), -S(a5a9782f,f7c90216,3a235a3d,9f548af4,a0ccf508,1aebf0c0,f9d4d772,ae3ceac5,144a9e55,f017dcdb,fd093573,c47b9954,20cd8a63,bd7cc456,f301cfa3,b7e7b8ab), -S(fcd5fd1c,44765529,413ef8b2,63d60414,c6b1da8e,3d2e8463,f0d6567c,f9029916,9877c363,d6180a8a,b005d5ee,77eeacdd,ffc237eb,a30da48d,ac582d0a,84e8cb31), -S(95be1f47,e0aea7c,4c0720e3,fd528ece,66627ba9,3f172875,76b1490d,7a8cc395,f68eaaf,9c4986f5,32adc845,31ba80c9,2c817962,1e042503,6e58bc46,f2d18720), -S(bca58c89,dd846a85,6698681d,450afd5e,621c9ecd,3e1cbdc,d8f85582,4a9cb047,8d0160da,d653a54f,323bd258,74360e4f,573d9a18,c3360121,e18f33dc,5be1191d), -S(1508b726,9d97108c,9c4a01c2,59fe7022,dfe63662,c6b695dc,6404a9cc,3a532a8b,e4f1b655,35250561,cf8b38eb,1b43bf23,430fd354,5045c434,dce7d3de,c22528a8), -S(b2b2dff3,fb9b7b21,411195f,c095f2e5,d69dd4de,249aebea,b266f6b0,c45d65e0,f81346f6,2377c415,a05c0a4e,b0b70a3e,95361575,9241cf7a,22918713,199a5cc3), -S(b087aca7,3b1daae8,b5655de2,6ec08874,14e3c2ad,fd3c84fc,4c6ad73,b735664d,402e931a,b04132c0,2efe8d75,6197ee92,90ec0b64,abb12862,728bf679,42244f36), -S(eec45124,dea794fa,c467c17d,5f843902,2f7befc1,f535897b,da946e66,bb22dbd7,18288f3c,6d89b340,d250bbb,afa10261,a30ab71,c47d8f36,a6a29312,e79945b5), -S(9e01ac6f,214ad3e2,252051e7,9802e09f,ff5a1f5b,16fc97a2,f82c5427,515a4fb8,c92a340,a9798e40,b8026d1a,826eb59,e6db59a3,efa12ad3,b891450b,c7ed015f), -S(97c0e53a,f2dcf282,66568795,2fc72a69,33e7161d,7a9312b1,261b0085,8bdd386e,5ca75fc6,b5aeef6d,7655fc27,1fe56c05,8d7a65c7,912a23a5,e4105941,2b20cd5), -S(79f1fdd9,179d870,45f8f8d3,c0f6e14b,2c932673,1cc2e79a,4fefb3f2,9966a21c,38eb64de,e16be6b9,57c5e78a,7a64a55c,90cf0ab3,a99c964f,b0dcbc5a,7f15e40f), -S(53559fe1,d3222709,8e26093a,61770eaf,9bfcb7e3,e5de16eb,df6e8934,a9522921,4278efb3,9cb23458,305c7ce5,bde295ad,856c901c,d4c7faa4,bffd6c9e,52bae725), -S(dc3c9dff,d1ff296b,17667fa,f58231bc,d2c26a9c,8f6485,514270d0,d5d00d37,701693a6,17f6ff10,afd51c26,e760e0d6,8fe749db,aa5b35cb,636643d0,b3755ea9), -S(3b1ee2f2,9ff89f3e,78295dd1,6128690c,557e188b,f76b86c2,2698e0f2,fca33213,69d4fd8,e1886d81,d22461ca,81c20e95,ee813d9b,6bc39af6,38ba71f4,72db25f), -S(8c9b2d19,a576801e,e03f6108,84d1106b,e13481ec,817d892d,4b233aec,3514d12,55e30950,d67bff85,a1fd0efb,210f0180,d349fdd3,20f3470c,3bae1c70,21550dfe), -S(fcd42391,288b05d8,8e23e673,7d612ce2,f45896dc,7953cfa5,fd32fac6,f8ccf8e5,83c5ecd,4148c600,d9416831,68ce71be,dc571321,6ce07f5b,779a1773,412a8e47), -S(92cf957d,a51ce801,64e6ceee,76defb26,f14d1922,9e9e1933,4f13849e,f7922f44,cf066667,272a2d54,acaf3fad,2b9515f5,c8c23828,18a91eb9,d6b03a61,475e2298), -S(646d5ab7,421ef1e1,1f86c4f1,6d308cf4,401ed527,c975643d,e0221f17,6c2441b5,3313b887,226eb9e0,2956f3c4,f764892a,3b99bf6b,8106575e,55c792cf,3645dea1), -S(3a99563d,d92cf9c7,85a0882b,9f51af44,76af2e4b,dd23495f,341a524b,d3643954,8bcc950f,1eabdb50,c1cf6e63,1b491672,9dbc1df7,44769283,e52a5179,303ccae5), -S(e8979b98,5a418b6,13d4d43d,d004de47,f6cb8e38,354fe810,7f47b741,c69a780f,c407e05,a72b449e,43bd8069,9f7b2559,ec26fafc,a016c735,a8fa5142,1beec4b1), -S(5c69255d,207f650c,59fdee77,7d59dcd9,dc75e3b0,8fd7fec3,d6f69929,9dffc8bf,a1ff812a,4690c166,48a7f3c8,cfbb688,fc5450b6,29f8f0d7,41e36883,ba570674), -S(48e3a29,a1be4db1,d1fe34ff,fa352356,a75d97d9,1dd73448,10f9d8ac,ded6ecb9,8bb6341d,d3431054,893dbf21,34e02153,2a1ec461,1f42ea41,d43859a1,4a6fb78d), -S(fc9d5478,5428ea33,8bea7507,488e5505,f82e680a,778fce8c,9f84aed7,ffb235a6,884e8b36,19ec9e19,9650973e,bb160df7,a116f429,aea7b742,b1837e,43dcc4cd), -S(5768babb,8f16cf85,98c268d6,9965f913,1ba2df86,8f96958e,5c926960,9f86810f,a320eb27,3667ef78,4e0a1e0f,a4d452c5,d9eaa349,b44d00da,6373a0b3,377da289), -S(499c15bc,5bea1040,5ef65654,fce454e5,4072450c,4ce5f279,62fc1f69,9bb103f7,3b539537,3e537faa,89adc347,74721df7,ae1554ab,ce2b7ced,38f67b41,9b157e3), -S(e90e567c,20c1b561,be3a3c9d,8a227233,73503e97,a1e88e,d6928465,77188951,26425fb8,49136a00,392a8b01,4248e2f3,10b0321e,d192e9b8,744e7873,5c393396), -S(5555e213,b06a7807,98ebf522,9142f5fd,4867d080,30ff2f63,8b637d74,3ad54e42,1b82a7bc,610284b7,758d1d75,982cb069,dbf77cea,c9deb76e,62eb5324,d726b42e), -S(9b1c140e,38b3899a,c77eeafc,1784805d,1efc1363,d25ed7fa,abf923dc,dc53d9b3,94bb9ad9,9b01e6ed,af7b4807,1ac2f67,ceff22ba,3ed4a26c,7b1b82dc,9c5fb8ea), -S(268533bd,33f9c398,5d8ba9f7,d6d111b5,9ea49cf0,8227894,cd236cb9,4c4d6e45,ad5ce6d4,3f70c08d,2b1aeec7,6e7d421d,41e61276,fd2c5a7f,4d263479,177067e8), -S(9bd29abf,3d69acb,1ca7f6ac,68e47d1b,61f8612b,30c36cf,4ed79939,583590de,530faf27,794dd14b,9fc084a,dd6b3cff,e0343608,501937b1,e7f7fffd,10942e2b), -S(eccd8863,8f3b2819,d828b9c1,2c0a76ee,663f6113,ae8294ab,e7ff5719,c8962cab,18da1af3,db016cb,45d7f9ce,dd4bc478,63aa8092,c674fca5,8f03f703,82ccc799), -S(8968de12,d40a30bb,99b10962,568b1f8c,c37bac76,7fbeac7c,21b80d58,bd64560d,268bf30,ef631569,800f6ee9,548cc7c4,15c1fd7f,b21413d6,3ed5abf4,936e5b36), -S(450789b4,297aebad,346af999,d4ea3e7a,c8867ae6,19a59c13,84b1ff3e,1fd092ef,402789ae,6ace54c0,54a26184,c651e8d3,814c6fec,fdb560a7,51943ca2,24bf25ca), -S(88b90c79,49a79d99,b05a2dd3,cac61e38,783dc306,fccacd97,892a75be,34e67403,3a565d5c,eecfa071,2c9355ea,67009764,7d0e52c2,d6a6a49e,3317014f,56554bb7), -S(e5a45f20,e3f5989a,a9b04119,6f7e1e8b,95f4b397,4e1c18d0,f19bc12b,ceb5464b,d09d73d7,e6dc8239,ef9758b,ae186e54,a5cb4d71,47f6dcdb,ec933237,3b677018), -S(51b99055,b4815a86,d0bcd8b6,8a7b47ce,7e9a93b2,3ec5f6a8,7c185c34,1647cd05,4fa125a1,35f26df4,ad7ffc70,29268830,9f8ad7e5,f3683eb9,b3dcddef,45fcda0d), -S(1dfb4a44,867afdba,892b9f71,1272402b,cd38318,f8f7aea,68c16eb3,2c07d565,4312ffbf,15775c04,e187cb98,166b5bb2,c42582d7,5b8938b5,83613d66,9622253f), -S(f271ed8f,c137af31,dad55775,e38358f6,608afdd5,4cb0d1b6,883ac66b,7b645fdd,1494c658,faf514ab,912887b5,c90e6bd2,a61e9d97,7e1ffe65,a49de27b,4e393bb3), -S(ac2f0db8,43cc7ee6,e268cf62,344fd232,2f0e40db,703a7d33,5437e7ea,de7cbef8,40ddcc5a,53d8a24b,8b5ee481,ef331bca,89e76293,7d1ba22,3471c562,ee7a2dc), -S(1801ee15,c8041c65,b9727159,8194a957,a404d5b2,318308cc,d737d858,4b2015f0,df400a6f,6a50057,1ebdb755,e686b759,d604d434,b9f198e2,21b2b514,30eca9c9), -S(8d304b28,32eabf93,82d71e3d,cbc38a98,437d6a,70c5b084,4486dde2,1104dc80,fffb5a64,3fa633f7,cf36e574,31acdb02,b98cb4b5,9a0076e0,8f5e5061,623b8157), -S(4e8645ef,99a816cd,74a0fc67,48cc116e,a61133ad,8f6bbe55,46ab9aba,adb148ff,594d010d,ff31677e,8c602038,5e071e58,5a72e97e,4d1c2d0,5564c102,56441c4b), -S(b8c26b70,b1367df7,7a14a385,aaec861e,e3cd3945,7282bb2e,935271a9,6c87d589,df51bc84,95a0c2e8,ef469219,f05f054a,5a5f85ec,a20f8acf,6c424ba3,9faff23f), -S(9934e27b,8be7c41,3f5e8ec,f2eba29f,26ed2ff4,fd588918,bda07bd1,5b87f4a1,4488848e,440c0a1c,5d11a3f2,784728d1,34b9a08c,6210494e,c1cf6a0f,71c334ee), -S(56692314,f6a9764,47a1a988,f0a2faf4,e04c61f2,b835f22a,25b57290,b1ee5d14,d8d72ecc,1afc548f,cb1f71e8,144f9f7e,463edd9,5422a607,7b9b307d,15326fff), -S(737a268,a2cd3d43,d6741235,69e2e118,7ae90fc8,669d27ee,504f9e85,5eda3c2f,e3d24166,a5ba6183,730c11bc,8b41845b,3efb7154,6eb1a06f,2e90dcc7,33f68b47), -S(90d40297,4ae9d5c8,f4c59207,e58797d2,8c007a6a,4f6aeae7,9e50bb4e,fc34fa7e,2cbdc969,4e7ee150,b51a7e1f,d81d01eb,71d48027,3f349a39,8773732,4b315cc4), -S(4639872,2ae68fdf,9a98eb24,6a70946f,c9bc927f,37a3db42,f0cda419,7dec8163,6dc0a8b1,81c16b97,da97fdea,ea20bd03,cfec3999,7e192b1b,3e0bfa39,a1727f55), -S(c48cb232,1c02051f,2f1e5aa5,c99f7d00,5bb8af4a,61691f1f,493d834c,549139bb,3eb61f34,a2009094,36aced01,4a11b75f,2d35d6f5,67e5fc5e,2fc7aab4,437a2c5e), -S(eaf967eb,d5f0932e,42a3222d,ac0d874e,af154f8b,47beee08,2ca7196e,efb429f5,870d0edc,43dd51aa,6f518b4,901049e7,865565d9,3e54e475,d587d94d,ce88d994), -S(291f8c36,ae17ff86,d05a5a81,31ae3079,27221af7,7b97d66c,812a954e,ad22d49d,3b515fa0,bfdb0fec,61f838f0,e78bd29c,360b9ef8,c6f599fc,e1c518b2,f343d8c2), -S(d6280bf9,4334749d,49b19e44,b811d99b,2a522e73,dc2afa03,c130a48c,f4ff39e1,5f282a7a,be629408,9672c7cb,c9e46e1,ed2dda5b,653cc490,93f4aecb,637a1024), -S(9f96aaf7,8b26bc25,e321837e,29f3cbed,ba6fe62a,3a66c59b,cb52ae9,daddf9a9,ebbd1df8,a818a28c,e1a61b6f,ed13f139,504d33d0,5e27b5a0,b67c15,b1333394), -S(bbd26954,fbec8b4b,d27f85e,44b1273f,37321a28,fa938eeb,f5e5f50e,fb0e8a40,56a517d4,c54368cc,b40d0653,7db7ec68,79d7d4ea,dcdabc1b,722e1a64,710e9b6e), -S(35597cce,40b326e0,d9044225,82726039,fef5131,9d267240,b2455142,7ff6d7d2,ab1508d2,278b3b0b,fec8bce,4dea9bd9,31859fb0,2f600cc4,b67bf9f7,4f2b20a0), -S(8849429d,39cdb22a,b6d22361,22a59786,2baac8d7,5f858ab0,33c5037b,81eaf963,ec203255,647d27f5,f134b011,cf390703,18006dba,f5ffa74e,593c2711,f765196e), -S(f7519d31,1493f836,ae7c6f8f,e8ee5f11,ea2ddec0,90eae6ad,84c6d0c0,3249130c,de7b22f5,ef095528,5a163142,255b168b,c004ea10,86269d7b,ebf032be,d9a6452c), -S(865cfb50,e57bdc46,166d2b8,17e9b4f9,73db89b5,2fe4ff14,1898bdc,fb4f3a25,36cbfe86,15368e24,b9673fb,f593bfe3,d1a0fe03,54f98c00,bf8e59cb,be930c5d), -S(cf3d6532,8bf2bfc0,8d36a93d,8aa8e8fe,317ed071,3aaec871,48bfb50d,ab1919ee,ad96a551,9cb8691a,e1d535f2,8af23967,704dc578,b7c38cf4,84ddbc90,2c1b26a9), -S(6ede5a39,7aeb2f30,d577c225,29ed1ecf,d28c2041,75e950e,12c98c1d,2ed1c48f,eb102976,b4237833,7761ab15,a8d0c228,a42ff5d3,a1279fab,736e24b4,47ae8e3c), -S(146a2544,cdf67ec3,3bd216b8,51d4127b,bd9dda77,4a78697b,e010e61a,7442a22c,f7cac2,376c246b,ad67a10,ee0fa811,10afccc6,d76a9295,f16d6034,1876814a), -S(bb14a6fd,2129d75f,5aeda8d4,d69cae8f,55b4950,7f709a96,af39bece,8e1449a4,feb4ad7c,1a3a224c,bf4bac58,617117de,811d250,8a948a19,a94b9cd5,8560eb09), -S(69975e93,a634cdfe,2ed014c,33c65a53,b17c6025,ae499a69,599b33ae,bbe52428,e16090c4,2cb1ccd4,7c7a9b91,4fa88027,bbf7155,374fb95a,ff0a06f6,4758e0c9), -S(e281888b,e9ec00f5,71e9d807,35c1c762,4bf8b739,c94f3178,868a7291,9d550848,2066254b,53733824,2a5b697d,a05fdaa,8e2d3b6a,840a7208,6854b55d,af88c3d7), -S(96531c48,abd9bca2,19fe05e,c1ff1ff9,90a526ff,5c7b5775,804c5db1,65b425e6,de07c8f5,32e0eb64,fa76442b,e4269e52,95212bbd,a9cbeff5,40b012df,f0b3ce09), -S(59d3a12c,3b2bf72f,c4ec6d8d,88594e97,89f30670,eae71e7d,2b98e9d7,3d5deb0e,fb338126,9a57fdb5,6cecf38c,ee63631,f520fee,6c3b334a,a47afb7f,7f5150af), -S(1267bcee,c8f3f086,8187271b,3a283241,935f1822,ae5e8e8f,5a4ba753,89869795,5249aa32,41fdc011,606724fb,6085491a,d974d355,9d27f8a5,2e80c376,92b22736), -S(446310fe,7a9d1f2f,632cc948,c86ca652,7358b910,e9532e2,9f394ed0,12c45ec4,f7ff61dd,f72dfb99,bf309210,286005d7,8328137b,6394354e,dd9cdcbb,cff06cf5), -S(7edfb2fd,a3c15d42,b29440dc,b7c7e74,c9530a79,6290cc12,86ecfe49,96583244,c7dc5dcc,6fc1ac75,5eea622f,69799c77,eb5c3883,a628f14,c61f9cf9,2db4e2bf), -S(e34f4c12,896a8400,a79db9e7,a5b0f67,99fde06,5e381181,f79bbb9e,b81d5e8d,e3dd7871,3cc68c48,9a877b32,9e32869a,ca89a69b,2ba6e83c,78af9c60,79f87f7d), -S(f49e78fb,caa129ba,ad6fa192,a26ffb62,d6825cb5,f933c2a1,c8a2c872,c5ff35e9,4e1c9c4,c176653e,6b87bf9b,39c5606d,ace09e3,c3c268c1,a51e52c,c4ebae1e), -S(71d7f117,738286d5,71ce0b08,aaa1b448,fd4a9d22,2e6d4ee1,b8c0d0ea,9275656a,751401a4,2fd576ea,6bbe6e0e,e076ec36,b9db65de,a747b31d,e1a66a02,324e5b30), -S(29f56789,8efe1baf,bbbd435c,7abb043a,284d16a0,598a5a6a,49d5875d,7577dd82,c3a6e7f1,80afe6e7,b761bde1,7893aa7d,2dd34702,6558c1e7,9d4d80fe,108ea6a5), -S(435afc66,f252c63a,fbc56f9c,342aae25,bbddbfa4,9b94a8e3,3d2a68c3,6730e730,d8cbf58e,e7cdff53,e4d52865,c76b9331,7553814e,f9f8c4c4,9c93e49c,7bb98dba), -S(c326c1d1,b2d1ef3e,e4e9367a,48970337,f711bd23,3c619e18,2bc47227,2e53d813,559b707c,4a73a245,c6d57194,9ceee5dc,b5d53645,d576d6d8,309e92d2,4bc959d1), -S(83486a4f,75664f,58db5cec,96af658e,6f669946,5c5b9e71,2e66ce5f,627d6a9f,eb7258a9,30b5e703,39681d8c,452e518d,aabbbe83,1312a65,af2723ab,ab61e04c), -S(85b419ec,e16f8d3f,ef24f1dd,6f8ca2f0,ea7ce0b4,bdd6da80,20eb0f83,7c799bb,37f888ac,3474341b,30a32573,2ee9db8c,4cd9a9cf,64350f64,8845c63e,fffe6343), -S(d6b6f0b9,cfbd4126,2f6506c0,89c1132f,7da49d8e,f9afcff9,ea97a224,35a85015,c5b7229f,dfc148bc,140ab9d4,4895c5b6,db02ae00,62585521,70aed317,c0e39fc6), -S(40f7b48d,1070340d,2382ba1b,794e4069,ac9aeba0,fefa8823,aa9902f6,4386c221,985b387,a3720bcb,a99ee10b,28ad253a,9202eb0b,3167d462,b664d67,f294509d), -S(ad6a6bd0,99789a6,2b3602b2,f75af03c,33379054,cefe6397,a135cf78,a0e13a99,249eaf4f,321d9011,39ce28b,4f09ee1e,4fadc6e6,763cd737,96777f30,aede6256), -S(2e15ccdf,25e72fd3,3007b705,9703b13,5f8a94be,cdc35523,3b349a64,60331e8f,e3ed23bf,5f320a48,e1dcfb9e,38fd2bc4,fbbd5e2a,e16072a9,9f704ae5,2d4c73b3), -S(aa9a2531,8d4796c5,8443eb4d,559dd43c,29efa4f3,c994eef,a1791027,784d4fd0,a32f3a7f,cf3b4494,a4970b8b,d20f4c6e,d82833ab,eadca5b9,4ddbb5a6,e27bb427), -S(f16c0ce8,cc87f208,5f98919a,cb4dff65,b68f88da,6db10674,c4cba867,bb410345,12dd4b03,86509e2d,a79f3895,d1c3cd7c,f5735529,b049204,9b7434fa,64fd382b), -S(f27ae46f,14efa234,e034fe01,f4ed5cf9,251c99a0,fddc9e5b,13ec770,4cbb6bba,4abb2ba9,5877455,ae76d4d2,56216ca1,78b1c12f,3fa9c10e,5df21225,4071c557), -S(a966ac61,ef7d10c1,47ed0ce2,cc383cce,8d83a66b,bd18aed,8261e38e,67983e7b,5d2db9c0,ba8bf67a,d385146e,8ac20c72,9fdbcb0,581cd956,a95ab89e,a927bd2a), -S(ced076ef,4951ee63,ac196d1a,65cab7c5,5654d12e,ae16f4f5,4c2637f5,6b1cbeb8,2b763b9b,bd99ee6b,5b6c934a,ccebdd0b,952cda5,ed266d5a,986be5d4,397d9f7b), -S(9afeb8f7,f445a1ef,c7951fd4,62a0a3d2,500f3527,1f482e01,edc9815c,2deac969,93354851,99ea1fe3,f74a6991,6fa53f47,2d1918d3,c4d0d526,34909810,25830723), -S(61c405c6,93115b8e,325be640,8e30cadd,9e42dd98,8522871d,1612a44b,95c41d92,efd7f73a,f38e21c6,8fa28d86,b3a9b241,27fb686a,75c53c1e,3b693191,d972fcdf), -S(42829070,a896e684,88890114,2763cfe,3376ef87,17aabae2,43981213,9be22ded,d15986a4,412faf10,ccfc34ed,162f21a9,54cc5af4,91ff671,c4634947,9e539da0), -S(d9945ab,e280b7b1,4bf7e65d,ef4cd279,57798612,50a1bb5e,28ba8bec,2b66917e,52902f2b,af8976d2,c77a2026,a8fddd2c,8f2b948c,5086870a,168a1ea5,cf43d134), -S(bd3fb006,3748f21b,cda6236d,a13e129c,905da160,2d8c2867,f39166b9,56a37a12,47654773,9e7ad500,cd0f0853,f17bdecd,ff4eb6a0,1af3822a,1201ed09,a4e52ce1), -S(831294aa,a3fc6d7,e0179ae1,753fb809,1fafa015,9c94c40,a41f4ddc,aa6937c,27509e96,b66459f6,2698d055,7c38634a,543f1eac,ca68f3bd,4d64d3c7,5e5b7e07), -S(c74d8a85,c5d11787,31b8d227,b74cc264,b2ffeee7,ca997e49,d1b0349e,2fc121e,5e5fcdfd,cedc03b8,4555a2de,118e494d,2038a2a1,27913850,e816f707,fb9688aa), -S(1cb36b06,a6aaa255,8126fc5d,b69f172,be012a58,de7d8688,5ac5286c,33e7a20f,a84f5fb3,67c6726a,e8b60e7d,d4302e7,dcd63930,2eb425d1,b89ac986,ee0e6d57), -S(5d69d200,ccad332d,faacf513,433bac35,d78ec863,2928331f,eaab7dda,69a5ce14,4370dcdd,77fc209a,8d558c09,cd6040dd,74ff975,b2b94436,bd2ce044,214926d0), -S(585b2e1c,b53d61de,89fe127e,d20f23ee,26dfc569,67659aa,22a35928,af247514,fa29933a,8ecbd8ef,8a7e94a9,ea267f31,a2deb759,b25c1762,1753bda4,d489c1bf), -S(a222828e,1568c08,3ea870,50f9cc86,17daade7,cc60a72d,a8762f3b,40a107e2,ec282fa1,7a70e5d6,529e5d44,15dbb61e,8e4a553a,11d39f4d,e3183126,73161aa9), -S(b879ab5c,38135c35,a57ebd6f,1ec01a9b,58758942,7cf9dccb,3b6ca8f4,dacf14be,18d8831e,b11a8461,9deae96b,60c656d9,f4ed65d1,71a0f22e,27d6931f,7f34a310), -S(39168674,a5cd3c38,ec3a8293,78a2d108,d44f4fb4,8ed3b09,d491c127,c8f74a0a,e65c3f7,8bd0bea0,e96e728f,d30c8d27,10ff67d0,23dd218e,813b768,b4094faa), -S(1a4db770,85065a91,61573aa4,b96aedc0,5d81647c,fba56946,a5e2ea1,77e7bdfa,78b0b79d,111c0203,ffe518fe,f08d517,78f1a564,d21e2e31,cab63d69,1e0b1290), -S(90b6412a,2626e9ff,1dce75df,c56744d6,f471fa29,d676c0d0,cc8bf515,47b9f0aa,4a7236f5,81fa2637,ae532b97,c89fd6aa,fd2db809,6b8d2b1b,cf6c9ea2,4b3713e2), -S(a25e3d8a,119b1f0,6474144e,81677ba1,811dbfaf,195d460c,1624dee5,39f29dea,cb0591a3,816a7a98,5875ed34,5ecec9c0,cdf02537,db28464c,88022850,2478d032), -S(5dadb41c,b58297b3,e84d87b,275198e8,76c48bb8,aee3041,ed14f7a1,394bfdff,8db26ad5,ae662e79,23ba04a5,87e7b2e8,f64a52be,8a76d4e9,5193e94c,9a80f4cf), -S(29fb35a9,f0e0b7a,d19d8af6,c4dcb5f0,19ac7cbe,b7bfb535,d23de4ea,33df5d00,41ba5e42,64f63b20,eb37839e,44deaae1,47bb9a22,1ef94ab7,737efc3d,ad61693c), -S(7270c153,a2fcacf1,18644892,7795fae1,7fdd4fa0,3e9ac70a,4fd38cc5,c5e3ea33,f6c35e5c,cf398440,a96d4c8a,f981fa04,567851eb,75431a14,83e026,ff6649a1), -S(70efa7f0,33743eb,4f25db9,c43463f9,77a2cba1,ab8e08f8,59fa7780,cf7129e1,f906a344,8cca0734,ed895706,7374c12e,14e6b573,ea4c90a8,b7376eb4,20adf7be), -S(7ccc2d79,f905ef7e,83b888ac,ef445b4f,a7320fa3,79562154,d0482d62,cefffe38,b7453f38,9861e0b3,7596d5ac,e41dce1,bf45374e,845542bf,cfec71ea,76bd4cad), -S(f171415b,58f085bc,cecaa5e9,b9afa67a,a05d9577,a28ac4d8,496fcd12,9b50d0e4,95257e0f,18ed2c0b,aa1202a0,e8f62779,a7add6b4,d601deb3,4944e59e,2e638d56), -S(39baf2a4,d41f3930,33330786,9f181ce9,e15e895f,2f209948,999ba05a,350a08ae,5f4a9728,b84a666c,6a6e8318,9f1e6f91,7c97a419,1d44c8e5,6fd6c358,445be74a), -S(b146000f,16103232,297377b6,f31fc96f,afd90cf7,27f0b056,55e41f27,1830c607,92adbf3,b453cd13,1e8cefd9,1884b3c,b7da48fb,24195581,fe59d23e,9725e0b1), -S(d6127f7e,e94765aa,aa2c463a,dcd518c7,e60ad583,6bd485f4,574e9e09,57ba6556,31d3eea2,a91bdff1,6a420533,2e768ac,2531f0f2,c9d94656,26472c65,4d665745), -S(cd28080,e877f416,d6302aed,aee760fe,a2b0f90b,23549aff,87ef8af4,3841a67,f67c8c08,3d69b201,6f9261f4,81e0bd84,568137a3,777fcf45,e4a4c90d,8338aa19), -S(78d35f78,96872666,aa5f339c,b6c68680,ae42cb38,c75bc287,8e9dedd9,3b0ad38e,7544e0e1,4fa07cb3,9144fb53,7ca57508,58d1380f,cd1909b0,56b722ee,fd55217b), -S(aebbd769,392bf374,2e771e65,761cb834,d8a09f94,400a947d,c6fcf062,3e0fdd6d,15bb21b,35f0abca,5f7755e,79cd222,e58cf089,af78cd0e,8e4a6df4,4576f6d1), -S(cc7bd0af,bd44445e,64a77303,5b66a1ab,e990bc1a,475c0454,2c2e23d5,913c6878,b0bc23aa,53ccb546,51972c58,ceaf865e,1a892ba2,bb7bf626,15793163,14663e29), -S(94b69939,f6ab4f6d,6b5a18e2,4e929afa,c83c0c98,cccfe6d,5b0c1487,c5915805,cf58329b,c8ef2ee3,52ee357d,6ed05bbe,ece97acb,7936bffa,428a6913,1e3e678e), -S(4596a3e,b0156e46,c56b2492,6bf8c419,42588055,96d160c2,fea2cd15,1aa84b61,39740352,fe7ee595,2e114853,d0334099,5e9a97e,f3fb66b4,fc6b1e02,632a39f1), -S(b577c857,297428bd,c331a8e4,e46afc59,f7b2ec2,be244cc9,f52a6d4d,b41025a9,529091ed,1e5525f6,e7746c36,575041ca,89ca74f2,7a7f1378,2a36a8dd,5526abb1), -S(623cf92f,7d87dc8f,74661d3e,411aac0c,a6c9191a,1da93b06,4f756cb0,3b7a80d,6909b404,ccd9e564,b27f82e5,ab6348dc,de6cbabb,c40d964d,daeceeb4,d48d3acc), -S(e9aee76c,9559fc77,5f473da9,faf84e81,3f1d643d,693cac55,3b96e27,1197401a,3893a6a1,10d34bb5,bf007cf,c116b17e,287d3ef5,2451a3a4,e8b251a7,90c5c2b5), -S(2581ff3b,48d9f30a,e533c291,be7078c0,41d75248,fbe46a8,c984e6cc,3880dcb,1e15247e,b97fb35,14da7f82,895fdf41,f84dfcd,9501cec3,c12b1524,be8cd289), -S(72162987,71924cf2,83db564f,c75aa820,4c9d0d9b,6acda46d,7e328c61,a3147823,88da7231,356038fd,c4af67b,3a852a38,e6e12c30,87388b21,c6f357b5,37d25dfa), -S(3a25426a,b615a75e,f8a6d5c5,a5e632a2,6e8e79f4,59eb209,ad7594f1,1669cead,d5316c8a,6f24a055,1d8eb237,91b9aafb,7a00e304,35101080,a543c519,3331063), -S(ab26ff41,8cf02d7,57a0f582,1155f54b,2b5f796,b201ff90,cd78d9fa,76b45ee2,6dc0d3be,9c7e0cf6,60e5441a,7b6fb9dc,fb24211f,cd727441,dcf86644,8e83ebef), -S(9ac8ea3e,fa78c588,69cafe04,23fa3ad3,176b9234,5a3c4cf,8f2bd449,2fa38ded,4d8b4740,b0aa16,ef6a54c1,3591b0dd,58e4faf4,a28aa4c4,b1c730e3,ad66836e), -S(4c1c869d,464634bd,d849b99,a04632af,b8213762,c58d8ae0,858af29f,4a26c0fa,8c557687,bf3dc006,a90f0c3f,6ea33067,ffc34b38,9a75a2ac,3ea843ab,d7af17f2), -S(f73695bc,c6dd5e56,8185b3b8,a99182a9,f04957fd,33cb7013,d887a55f,32eb746,f615ef29,72d2cd2,c4adb932,a201567c,5672d44e,529a1248,3bcf05fe,d6b86fa8), -S(41e8d3da,705535ab,b53ff304,3490e669,4c1f754e,713afbed,34b59a59,c18d3f9b,6dd0728,21533413,b6011200,e4320941,1df89a1f,efdb4c21,8453606c,957cebe6), -S(623f4475,c0691617,1c7cfd60,2684fb11,24f934bf,524559f7,142404ce,d353e0d1,8c94a4b3,bb7de410,fe2e3d1a,c41f2bf3,c01866a1,5e354fea,596bbd4e,e90f08d6), -S(961dcf95,64da916c,9a6ed43a,a8028f8a,8c65a1fd,d561cbf2,a0d80bdf,ef10566f,4d3a2dda,d5d81a8f,9e7940cc,957a4646,c3b7a734,457ed088,998b0c10,1987f16a), -S(5273adab,8a2411b3,6e2566f0,a148d688,4003748c,c3bb79f,6bf48340,75f6ea62,780cb632,30acbef8,bca93510,74a28fb5,51573656,1802992b,52f64319,393cf529), -S(170c2667,d45ccc19,7ac05e5c,2df7a0e3,37ca47e0,68f360bc,ee9c2134,81a0a8e3,6e82b129,6d24dcab,c529e4af,538154ee,319b40df,1cf31f7e,23fee9fb,4bd3a8dc), -S(7a240b1d,5df36af9,b4d1b988,c428d12a,e64cebdf,280da6e8,dfe0d7c0,117f8e2a,d5a877a9,dc46a181,6939b345,6015c592,58591cfc,63ea46a4,d228ba1e,465ae6b4), -S(6a6564a9,abb91408,c90a508b,252b68ea,7b11cb38,aeeb6bac,4eeee422,6058ff9c,2f4c5766,e3dca65b,f991b74e,bb0c64b0,2bd2668a,62e4b97d,8f3b35e1,c3ce614e), -S(87aee56e,bee43b0e,d0fbe101,93218ccc,9d4f8d9f,c51a8780,e0955316,b97c71e5,b2979915,9110931f,d2d9f95e,d6d5217d,6d957a,c2bc6f3b,c23a4555,e19a76ab), -S(193d15e,6ca2fb6d,6ec3b10,945f1174,8476fb29,327e941,ad1f8ccd,d7d41931,fb7cd3c9,2cd51aab,2b78b0a3,b9e5f78e,5846bdd6,822e1525,10d08357,3bbf1ba4), -S(352834b4,5bff7ebf,b0a20cbe,13d51e8a,b4854209,a8c918e7,67f6986,b4c1f0cb,e2676927,9e22fddd,dccf5a71,c4b33ca1,f8e5cf24,43388704,721f3c3c,8669c8c3), -S(843ffda4,5e72ac0d,b27a17e6,65fcb27c,34d325d1,325612ba,6163d5a3,9b16e8ef,e39834d8,c2ebddb4,791a5ba9,a525e210,acef4fe5,9184e737,851785ae,9b228d55), -S(b34d4e5b,5f86717d,2c77708c,a14f42d,4ab21bfb,de36ff49,eca9ffb8,b92192cc,6e782729,bb40e31f,3a0ec687,7a6bd690,6282c723,5691fb73,6baa16bf,ccb70670), -S(98b7f92c,4d4c22c9,2783b2ef,a38b71ba,477f79e7,85d4fb11,acfb2880,709b7172,e30e234e,af0847a6,ee61a5f5,3f0f413b,d68b115,d8a726c0,61032d6,70aadf1f), -S(4e7e4cc7,a37110,6aa13c5a,e47e6962,eb774d7b,5b25d31a,7e6ac83f,ec89402d,b14d199e,9dbf18cc,e03f5cb8,e3e0b555,a6a7cde1,2fc6ba42,52956c43,27f874f7), -S(4db22218,59bcf734,f25d2a16,3af8f5a2,58422913,34bd5e2e,4a322589,d0096a61,b99740ed,41165371,e1ddfe62,4e6f3a02,47ed46cf,4c589067,d12c3a38,b75701e), -S(f1fa9b2a,6983e6d1,b36e4172,20b9fbb3,6ba4383d,cabb2da,845a63ca,8fde624a,539ecb7,cfeaec83,22861a97,4738844,53795076,1657378c,8950a660,251c50e9), -S(eec0d4a1,f551ae4e,f54ba956,e84de711,1fdb93e6,3c7b64e0,bfd4ba42,ff91fa6f,d16347ed,3ea3e986,a1067fc0,a1e443fc,c80c6277,f1018148,744f5faf,65391c35), -S(74be2d2,526daaa3,3ab34527,f26e6979,4d9dc930,7044da0c,babaffa3,be2eb41d,aec5d61e,477d998e,d18ade2a,1eeb48bf,82b34408,e6823fc8,f7b57561,f0c56ea8), -S(6d248800,29578c3,141a243c,324a7e36,c694ff50,1adc4280,31ee3d1e,ca32aad5,58acf9ed,b1b5ddcb,72da7a52,6cf089d6,839b42b7,4fecdfa,b7e6996c,d80c3e96), -S(7525d819,d1dba5b1,1a36a2b5,62a6e65c,3d2d1128,8f1945c6,7daa7149,5894c52f,458998fa,b2444201,b8a57992,50b76be2,f79599b5,fc87f83f,d47eede5,feb5351)}, -{S(c8e595d2,666f4913,1f375b67,81b9113a,d0760e5,9477ca17,8863828b,307488f0,a82cf2a9,d823af13,5c23a04b,bc12dd81,2c352a48,27e19030,8e089d9d,9c316596), -S(54970cd6,a06f81d,3566c34a,ed5eb8bd,aa49c821,41b6518d,88efb994,a67d65a2,cba9701c,b3f620b2,b4756bbe,1d7b39c2,2226b871,19e7525f,ef9f11b5,c2ba0f36), -S(f9b9b054,543a96c4,25baea4b,5b1d7b60,81596be7,7a06f02f,bcc4926e,82d2cc91,1ed468ba,7a674ff7,4e872773,85dd5fb7,fc1f1603,a5a8f249,c808aa14,775d54e1), -S(5d3a25b4,dfe080a8,a13823aa,77847487,2e6ef73b,5fb862c8,5439fe36,cc93bd64,5f49d6f5,507baeb,5e0498cf,83f218d5,743b4d93,82cf0770,a734d6a8,af76c5d1), -S(1c8ed0c3,6b0ce521,89f5ad75,8189df2b,77646a19,8fc3b7a8,9e48f978,5f903409,126ac278,e1194e47,39a5c44a,8b62640f,bec259f2,28f479c0,aa4e5abf,861501d8), -S(c8665b4b,43e23686,e27d34c6,d6739250,4af34435,287e78e3,f9e054f2,33f22168,34161d68,636cc48c,56d9618e,1c92e9e5,83c5fa4,f87c1f8e,126b1ac5,ab79fa7), -S(e7675296,10359a1f,29d2ed5f,4ee7cbbb,a4e9b5a4,5ed6cce,10d36059,6ac24773,25662f83,ea425398,328d3874,a63438ec,3995da3b,a5a731c0,45b8d269,f07a0b0d), -S(875c0b21,43d3a01,b6310ea4,7726f174,e8b9ecb3,34b65ea0,59f877b5,e7455d8c,8712b814,a3ebe72e,df1e3899,bbd34bd8,6d021e7b,a2e9763c,ff526e35,4a4286ea), -S(d4ef4e,78f2d6e9,b0e717f8,21c1a56,3902fe88,c47f208e,facb68ab,5c176f05,2fcbca4e,8338fa10,22b432da,7b40070,90473863,14e28e04,268ade75,57a2d554), -S(31513428,e66de83b,a631a2d8,44e054dd,8ecec644,134c57d2,eae9f6c8,e5bfedf1,316bafd7,aa48ab94,ae682ec2,ee1bc88,f04f2c50,c975b441,f28143b5,5d4bc909), -S(33260c29,cce9b856,dc9a50e6,d41746e5,e73fdded,1fd25d3d,c3659fd6,c2e72575,665cfbbc,9af473b,b647970e,dddc260e,d53af968,79c0cad6,e12bcd3c,392a646f), -S(b49a875c,d46f3ed2,34c3b611,88046b4c,aeffcb5c,1c7b959f,60613357,b6fcc13c,76006cfb,21f12143,6684ecfe,1524011a,a08ddfd4,c26a96b2,f56da73f,ef05fd37), -S(bf528e3e,7a8c7c91,9bc3e4fc,f0cdeb0c,7f8b58d4,4afa7663,e2fd2233,751e615a,c7e0587,674f3012,f05b7d26,f067b45a,8efcff89,bc2f341f,c0f2a829,b2d50b99), -S(b358b816,5db58b6f,64118a5a,53b0f2e3,c319fc59,e4a57657,1fa54214,108d66cf,27cdd287,96758b2f,bff761a4,9daaf43c,8864d04c,dd6bb8d3,669f393a,b74ed23d), -S(c8214724,1e0b2fdc,f054d7b7,75452bb0,98481f33,ef81f4d6,19fc8bad,715cbb76,25808ef,36f52935,700fc3c2,8f02a6a3,37b06ba3,75864817,806e35b7,26a3e9b2), -S(88c95ba8,4f5fea33,e8d848c4,24d4be91,9bcf15dc,988fb9f9,b14648d8,3bda4294,339240d6,a490aa81,e6cd03c8,af69fc90,fb43de16,e456e1e4,40334e8f,216ba662), -S(1222eb56,b6341323,87f28674,2b495da2,ad989e9a,f5dec72f,21022834,190b6a5b,30e95537,c9516bcb,8ba67b77,983f4eba,3a706386,af400253,2f54b15f,9894f072), -S(5adf18d8,e472cda5,d379e5a1,4f66cee5,da7ac014,84b685ac,9234965a,27a0cd69,b36994e8,d17c5c0b,1219db4c,1fbf5746,434c094d,e53e63ff,3d9b4cd7,ba429d1a), -S(bf3bc2,56f019e5,8c0861cc,91a5dfda,bee7f384,70e5462c,5605973a,519c682c,38356061,b7015d4b,e7f43f21,d3b76e9b,bce0c749,c7e0d96,e6bab6b5,8dfbd650), -S(10aa56bd,a7ddf207,c898b73a,22f1e8e1,18fc453b,e1539267,be025cfd,c8194571,be79e52f,59320f5a,65626557,e6218a7d,a4cdde5e,ab00b23,9b411bfd,377767df), -S(2b2c0c46,900e65c,caa1339f,34d1449d,91f937e2,2524df3e,95d9a370,d940f31a,615780b6,6839ae65,87a0bd3e,45d38f8f,d4413e3b,ca1afe68,944e7e77,917d0182), -S(a5f75480,d53b0649,dd72d8eb,a9275117,b84fc3be,288fa3d5,e274a287,27c2e669,a766ce73,12b8df27,aa950f7b,29c767e,fcea1614,de5a6b42,3a57becd,c496d6c1), -S(d886590a,d11c94e1,9aab94bf,9422377b,528c1302,20c86f14,f13ef07c,34a61d2d,2978b774,2968150c,9dd0739f,7b9c4f0f,a5214f02,f828debd,6826d5f9,62cbd01e), -S(63bf32ff,4dda2eee,8aaddd62,8cd75f44,7535c843,19441e07,801f7339,89ce1ad8,6544e852,8ed612f3,d4df9037,4fd22756,3a5d7edf,df910d68,fb4571b0,679f1238), -S(2e42372d,88db8b8a,631c083,ef77015d,c98b13a0,597c6efd,141bac97,ee8dfce1,6454e588,664fe42c,1e9b6646,e82889b7,4497d435,e46c2a77,fb05fd10,c28986f1), -S(4d3b7d17,a4a7d26f,7e79fdb7,477a8f42,e208014d,3f61445b,6c921a3,d5808110,9408735f,f9c384f0,46ff6b78,5ee8914b,a8da4502,6299e09f,9361fae0,25e8a19), -S(c0c2f170,44e952db,3b5e3125,e75c4be0,4b91081f,1858dd2c,ca1d11e3,bfeb42e3,712c1211,f321e4ee,5b014757,87a7c784,fa00d429,fbf1ffa9,a3884a10,ab633dd9), -S(832a63c5,105ae2af,8ae9a062,9f41bc12,d6d9a16,ad764346,fbf45561,fc721e3a,8eb47da6,f5ec89e9,483abe86,d9419561,26d78380,a6818efd,1d6fbd90,9088db06), -S(56db6941,c03ee58d,c4dca632,db498e62,1872a29a,41c42082,79ec7454,bfdaf0ed,c29ca102,5ea7525,68564f1e,d15153ec,aaee2ec,da3ace93,e580c8a4,93e9e4b2), -S(3b46ccef,dc3a713,10e4c8c9,215b3afb,65c354dc,c37700f2,61635e20,209cd7cb,6fd7675f,b779a43a,ec66d9d,66f47d3a,d41c3e69,9db107a,ece85e75,16d924e), -S(ca4d848e,15b27c5b,926cb160,d79ddd80,c618e30,1d0fc2e7,3fcb56af,5ec7ab10,604ec,e307566e,ebaa545a,9a080f51,e2a0b5ba,4a09c8cf,393bc4f8,6f483d27), -S(53f8eb4f,c8858582,e5990bd8,ebb19e30,fd6dc262,ba6102cb,3b71b6c9,e47c764c,30c7dc5d,4fae504b,56a103d,b9318647,c5582e09,e0868bfd,ebf2d7de,e5f6fbdc), -S(4754af73,cf1cbd8d,c231adb2,3cbb589a,705bb81e,b8ad0ab2,3a61ce0f,db6df49c,6784ed08,73ed3a36,14c7b35c,916905d3,dee4ccc3,ab82ed94,1dd4da1c,1d211af6), -S(3c593952,1d1b1fd6,976eec8f,9498235f,4ed5594f,73f0cf2a,14b8a78f,196888b2,4636c4d4,aa2e1f,c78eba99,2dc89151,3c4e380b,24aa1701,8e99785c,2088dd73), -S(a7b104b9,7c1c0fb3,1d30a49f,b2377ebf,df7020c2,d77b0b8e,b47428ea,c60ddaf6,9d7f63be,bdf87d97,d18cdeac,4f97e900,f5579bb6,6b5da626,154b3950,df14261f), -S(234cc1eb,2097b150,a72f1e7e,4c405679,69cba876,f22a9828,4e639e92,2598fc2,677e291,8042accb,e4639988,d49c85e0,3cafe4ee,601eff33,398f02da,9bffce39), -S(b7d66767,4d02da2e,3c1692d5,1dd8d383,b8456c81,c7cad8c8,b2d55204,79c10ca8,da5b5c03,1e4139f5,24920932,74b15eb3,bbd2e5f4,95ce94cb,cc4184f7,f2344d40), -S(c32a186a,6fc91998,8df6cfb7,d2a39e03,9a60f1dd,7852da99,9af32688,200f2a6e,cd027a9,a1c5d0c7,6381638b,21f5bf33,71514b49,9733cd10,fc36e3c3,3e16d262), -S(7d824a92,83976eab,a0f7aaec,4619d13d,abf75df,7062ed63,ab09ad73,7f805f7c,81745e89,a8b8c725,32c81120,c527e5bd,772adbc8,e93c4d03,856596e9,942865e7), -S(ef890d13,a3567150,2f8aec43,59e2e293,8ac0511b,13f99ba3,c1b30a0d,393e0e65,d24a9d5,bab93079,5aafb32a,fb5dd8f5,9589b27c,76a3a5f2,728b5f33,3aaf2e6f), -S(49e7a49f,df1d0355,5a83db30,1ce7de93,84d50894,36e4881,33b31031,4b8ed333,86f8051b,5ddcfd72,3c9b4961,80b5f534,48f9f20a,6560698f,43b5f59d,2205d5a5), -S(87a54ecf,9d6adc7,148da85b,3aacb374,d65eaf67,a978fb07,bbc920c9,f68de37d,7500154a,11651fb7,16bd4b1d,7d74df87,d948ad8a,441cb9b,74523eba,b06a33b0), -S(1c75fbec,2bb178f6,58f8bb0d,58c59d28,37c5bd11,e7c9766b,fc8c71c9,5bcb4fd8,ff17df79,c948583d,ae95c4c0,2be215ca,94189a75,18860da3,55a29332,39c3be51), -S(8b50c207,f02e2d39,dd556a0c,54deb2a3,3a96e8d7,8a1a4d5c,9970986b,46caac7b,9e634e62,448e57d8,8013de8e,6c1dd7fc,39aed80f,5e118cb8,2a659f6c,694874b3), -S(7b4d6114,72e2c781,4cf7a7e1,b2e0587f,f7c758d2,96bde162,7071d9a5,e9ccf458,54092c01,2da6117d,bf24543b,c8143b8f,bb90cfb5,106b3a78,18e9ab6,adb8ee2a), -S(50d14331,162d65b0,6ec4883d,936438c,5cdcc98c,3265b6aa,3e9c898a,3157eddd,2494eb8b,894cde06,5238cfeb,8841d428,e6fc09ea,14f31250,e921f7aa,c5235e7b), -S(c5638477,15e5e0cd,7412657d,63d27e6d,c8126eb0,b353acb,4146e93,d5485293,4567dd06,d6c8ad85,35415a06,eaf9c387,d15ad758,27de781e,f0b2ddd9,fb0af414), -S(cdf1a81d,b618837e,77c4c319,a78ff7c5,8ac2693f,f3ad9d76,f5fe4639,8523d152,3d29f818,1ad01726,f5a57299,e9f8d632,ea50a6f8,f7bfd917,c60cea89,2e026e9), -S(26163253,c6617468,f1b78426,b153aa75,fb2081ae,91f0291d,91785fa2,8eca2271,fe9ec597,5be387cc,600be7ce,28ff3092,fb0cc11e,d235ebb3,bca21d5a,6761f2d2), -S(ffbae863,2dbe89bb,13a44bd4,85685746,160e9cf1,5e02c547,a73b192d,3458b265,c267055f,ade9c7ea,c0ff5356,b3f1062,c764c5f8,b182207f,eec0e345,cab843f0), -S(86e20f88,bd61ef73,2133367e,45235980,b2cf0cb,9801d795,5a3a8faa,53eb6b31,7d7fc09d,a9051669,1772b443,b7204199,51587976,3110865e,96f1e9d8,676ef639), -S(7be39fab,669be73,cea39240,a16922ce,5f1c3bd4,f4036d17,97599c8f,d52bcc73,da152535,716ce5d8,3b223f72,1ead270c,d2f78d83,f1f6b8e,61c6371a,62794829), -S(5dd3e3db,62673c67,112f2457,dc42e903,3b5ea586,676d0411,2c913a03,559c9570,b31c875e,977f1205,3ebccaa7,57e69cb4,d3632130,999b5a5,ef73c4b0,5950cfe4), -S(54692082,90733c07,3032ee6c,208658bd,a87d359a,bf145837,20bdc18e,9c3abf42,a3c73d09,5209d326,8a51d21b,37058b54,93636657,c699b58f,bd209210,f936f72d), -S(d170eb9e,bd80c03,282137c3,a1a36112,e2d965be,a530f5df,fdb34634,32f0e983,82bebf36,6b21bb96,ea0a162b,1a91557,5679c33f,ceb4bce6,2698822,2db01840), -S(2ce91172,e6c42333,67487389,f31600ff,f6f0e5b1,3f7dfef4,5c3119ce,5b5d87ce,3c95d405,30b49147,5cf2e0b,e5e2b0f7,ec84551d,931d09e6,76a1e552,c221199f), -S(b133731d,95483e43,cc4f56e5,127279a8,a0d32cf,26e33971,bcdccf69,e3b04f52,bb69ce36,c7bb5973,794fa89a,d4bdfd69,8bd26211,caca7866,b12b5ffa,fe4c27a1), -S(c9e45724,8dbba2c2,7c9cd09d,de0bc5e4,2bdfe86,2f3a2e1e,12c9126,6861d76a,f36e6024,f5f7c255,e684d368,ed336ee0,668e6bf5,dadd8fb4,6c58b03b,a1417014), -S(99b6d58a,d4524f00,fb7d3c0d,4a521143,fb45283e,2a8f5ba0,e85f1833,5c979828,2acebe0c,9de8dbf3,14b3140a,fcf81a74,b1db3e46,bddd4aed,9014848b,c1598140), -S(2940748f,7feb4edf,c05a0af2,4ada767b,aaac74a5,b1f7d83f,c5590780,640f6d2e,d30e19a7,bb721cf7,f2f47351,a8754476,f97d96dd,39cd6a91,4a97dcea,597e2258), -S(7b53ce3f,456591f4,534d9476,66e01d38,bdb80580,6555d569,72404e0f,5963b5bc,c03dc414,99b7f26c,cd7cab45,c9cce637,30f9b615,19fe4d3a,e9410474,b2f62209), -S(f1e0953f,18f81648,1bc8a21d,34ddb5ae,1fe02974,1dba2322,c5ebf200,31eab9c0,93e9a091,9c6bc9a3,e4a161f8,3f94d274,b1ef4ac6,edb975bf,b62cf92b,97f1baa6), -S(6037926d,772b3333,eb75a6a3,381b3784,ede8cbaa,a4c1aac8,fe09ea20,ff3c6520,45feda12,a4bd9518,96e83b91,bbdd05c3,dee627c8,39c8fbcf,e27a050c,9b082ad6), -S(7f845fa7,49ae8a9f,cb394dba,27e7d86b,e16eb956,b08dadf,a55afca8,5a1c6850,210c0682,9d62dbd3,d1917505,4b428305,78444ed4,ec3ff807,f6593ec2,f39dc1b2), -S(d3780383,8c1390ff,c1b679be,8192b8d8,4369eaa9,5eaacb2d,df7b0d83,4fae6ab,e9d5436e,79c4622f,1ef6a773,af736727,d93f5f09,3d0abd64,acc6f37c,4b7b3975), -S(58fe6127,196f0b87,8acac65c,c0a73b52,7c979d75,ac15ddf9,7858bc4,e4f40400,340365ce,74466016,4887527d,7da89ddd,69ea1bb7,93f886f3,654dbd7d,6b9ea145), -S(798de133,1d82f361,6fe2c597,ce8ef82,9e1419fb,1615b76b,e4e44929,518aeb8a,f8eb34ed,b9275578,74d5abac,2568b1c1,9a751cf7,f2812b64,9b75da50,e0c3d269), -S(ed7c18bf,c58b3202,c97a31e7,4e82aa88,c9d554e0,18afb73e,2b8324fb,bacff740,7337a0d3,f8f42f32,ed0ecb1f,44907dc5,756a877d,d8507b94,442fc5cd,41d5432), -S(41633de2,56410771,aa494b3a,3390898d,e78aeb06,3e8a061e,18c3a2dd,d9a23f5a,ead81878,b28062b3,e421c0e6,c1202092,121fff76,80dbc99e,7af681fe,c700ff15), -S(17392b06,3fcf041b,2cd4672c,780edff2,9e1e17f1,356285b8,e80ba54d,4ca6a67b,af99f6ac,2f9e9178,2af6b677,7163a0e4,b59c4d90,63f8c2c3,9167743d,38231860), -S(c4229eac,5a8333fe,75e90571,5ec787b1,7ac350f3,3ba996d7,8f1c106e,d5f0dc3,9186b6dc,6cc14aee,8833d89b,501e4fd6,ec8158e7,2f96530,4a3a6577,8cef072), -S(a985efae,9458f1f1,8ea8ffa5,84d7dc63,25cf125f,a210886a,e1b1dd23,84c2e786,1ba41023,1036e351,7bf58cab,5870f244,315c79f1,edce488d,35907eb,a5b5e3c0), -S(b5fa6b30,6ba70431,ca33cd5f,82cb1f50,3df04589,c3c66b60,dabe0fe6,e09356a6,c1ff1440,3a4ee6af,940e1af8,f9c2596a,ebcf3691,8f9a77b9,730bf075,42c9fef7), -S(c3ce2028,9e90190c,5ace17b6,7a9a23c3,19161a36,9f33cb91,5cc57416,292d0a8,ebd0b498,59711041,3560bd36,1dffc830,8906263b,a0102ac0,2d871e34,856aa371), -S(ee376a1a,fed708c7,de2bcc3e,54a01427,5e75d8b,a6d8b417,75005eb6,8b29d94c,9c3833b3,1d73f289,cd3064f5,7a1ecdba,48194e3c,66d82f2e,e3086749,62b8aa52), -S(aa25c37,a2e2be4a,7c0c9e4c,e08e20b9,88de0af,880c1a6a,e3117910,9e5b187e,f469297f,1e3010cf,67310d9d,719f7a59,258d2184,1804cf55,66615800,3691a7a6), -S(10ad3adb,7a865784,c2e044ad,19a21199,77cdcf69,3d2d3292,26ac352f,c75d11a9,1e6858b6,1deff39a,1f69708f,56017ee8,a332ab60,a48e2783,e2dbe50,a176f355), -S(5aac0d0b,a2a5c410,39541de6,c53ae936,6fa07ca8,373831a7,fbd87a38,784af72c,4d82d068,9a91355f,6c51df81,78964947,95614a2f,5b5a4d07,20f32e1e,7be78ec2), -S(490efeaf,914e09d7,6bcf2c9e,15553327,d971c363,50fd4134,b9dac978,4a6bea86,bcd02373,44959244,9eec797e,6f50a9a0,5153b3d0,436d5d0,361e7c6e,cf8400df), -S(9c653d81,7a6f45b3,d7e001d1,140fab91,1ee8fa84,1c361ec6,2a62c0d,1f617a19,ccac651a,db81a595,ca2eaa78,f6ddec8,c18fa0e1,7ea19db8,ee4a431b,87ea83db), -S(6e2f2c34,ac914200,759acbba,28e9a2d5,718a682,61d6afff,46171c95,1010c79a,70d43c78,d52dd510,ca0660a5,40ccb0c7,75c446c8,cc5544f6,32da3c20,8fa84e80), -S(b5b1797,730398e5,c056f91c,3c63d762,cbcbf871,9a032ec4,e53a49da,6ac4c7e,db4299a,1e5d8330,abc09c26,191c592f,556236f4,677afacb,b9c08b1f,2e0c6dfe), -S(93beaed5,d689a857,a5c95522,3520b40d,a9616adc,a58e684b,6c47b343,cef0e604,7e04853e,283c490d,a9751ca2,35a3dd37,11597e26,6391bcac,443023dc,e7b58199), -S(d67e7b92,d30dcc65,ab6dcb6,da8daa6f,42aaa41e,980793a6,2cae02ca,14386b45,6903a40d,ada98666,40583bb6,7baf9b3b,4320b11b,ed904987,f11f6ef9,e985763e), -S(31d4214c,d168bba0,cde7dcd7,54415c1e,1313c411,ed3076a1,17e29a84,184ede0d,bc2ec4,65cd6863,5389a499,970ae4d2,953d1b8a,df8a6190,8af2d7bc,48c4254d), -S(4c03265e,9d1b0818,a0249b0f,acaec62d,13525fe3,3a963dfc,7cacf779,a94e42d2,4fc53174,762449a3,a54546ef,1a1a6012,4fd935f7,13fea628,1eb231ba,27efd9c5), -S(9eb8fc83,a180b5d1,d720fd4e,6c873866,1221f706,961b3087,80b226f,7f3bc065,aabb671,9a5ecb53,9266139c,642a24d9,892d3367,146d5718,bf6e2efc,d7db3dcb), -S(7cbaf999,bf2d62dd,cd5d521b,cac74f1f,4e0dbc64,ce42554a,fa140e01,c1ef4a17,a812aaae,59aa8835,7095750d,b0efce6c,411c7d8d,32077185,22470643,9e8b4094), -S(a1cf427d,9a247655,f017e35b,4f5dc500,f91d2936,b54bb1b5,cd928f5a,add7d9d5,92e76ff3,8fc6dd90,67a38f3,c974770e,ff7fb86b,b9c4cf19,724decf7,682ebe14), -S(ea47daa1,d527592d,a1b67019,acf67b5,3729c0e0,44ad194f,4a884df5,b64d1e88,8a8e6e8c,70c33c68,d249c670,3133a665,359af2f6,1b339a26,6c64c227,4091a909), -S(d2bbc061,a7dcee9f,a9d0d95c,5de7c07e,6db3ff3e,1a051042,532c0ce6,be80730,b00cc82e,6a643f46,2a605720,c862164,da039008,34f30f57,77d15564,4a85ba4a), -S(467b855a,410a691e,e4b0a463,4252d6b5,c5c6f075,acd2d942,141c2db1,fd6daeda,6fd32e37,9ff7ac09,7b9e987c,6fe6dcf4,628756a2,48dfc343,9f127a64,50ce339), -S(841cf771,c0ffcc5c,4a5d30ed,2ff39fb3,c7e3d76f,b9ade58b,2c9c3f91,30589bf7,f4bff35d,98ff8629,a9b48cc2,fad49d8a,88ae7957,33e573a,82649d75,cbbc4c32), -S(5d9f954c,d2972a26,7110d9f7,dbd34b85,ad9ad480,769b7d17,bed01d45,d523c583,ce860464,688413e6,ba64468f,6fde939b,1f9e3d95,b7955a50,6e92e235,c1f85b87), -S(1dcfbd70,cac8cb18,31531b3c,256ae415,eb846804,663fa826,7b1edf87,11d076eb,9579cfae,31cb98cb,62e54b86,cf90abeb,4b537093,898b732,98263988,b870288d), -S(6fb4b3f,2ee3128f,14d810ea,a989d5b3,5feccc55,8d44e3c1,694e5dbe,14d98cd3,f67c8f00,9205f82f,cd2d801c,6a19e35a,61ba0cba,fbbd15f5,c7259a23,14505719), -S(e17d12cf,d261f5ea,db611d02,8f3720f,e4d00e61,5383389f,48c59c0,791263a7,b8bbf87f,4aeda898,1c3c2ad1,f474a7fb,69f45180,57a8011d,7456b688,3839bf4f), -S(3fd5048a,4e2ab188,6f0b1cb8,cdd59182,3e94d853,b9640a33,cb3f5718,ac30f3eb,14d769af,5dfb719e,b4a154a1,f93e10b5,c1d23993,36e1597,2fbe4c76,9c088441), -S(36941001,5302571e,d7c4cb7c,3d479f55,e89193f7,5b52bc7d,d65ca207,41d14b2a,c747a1d8,af196bed,df1c5321,d58a0a19,171ebf1b,1a855b9a,3f90f16e,c333393f), -S(42b5541d,e161fd92,f2b92c12,826fda42,49f05c1d,2f79d951,1ee4fae5,3269e1f9,d6cf742f,11daf585,bc7b4be1,784d55de,2ba3b918,4df6d81f,723eb593,2862dc5e), -S(dcfe0685,c9452c9a,be819a8a,574bc35,760263a5,edc0e018,4093cf0c,b4406acc,fb84c487,873ee72b,49dd61e7,46a8cc1b,8485c4e8,fb5f9725,a17d98d6,62aa9d58), -S(cc5e07b4,c76bd9cf,c9b040bc,c3d0805e,487eafb4,430f2265,adabe2e,7bcd5874,6668bcb2,7a297c14,d4a046aa,59028e39,be049894,764193b7,9dc1658b,bbdc3d25), -S(74cef0b6,e59cdf5d,47244fed,491b6c0e,76d9b185,1a3f084f,9f783a67,d5f4c70b,3560eae,9a4c4b65,3831bd98,d97c5213,25b07f32,d40b215f,a93f2332,b6a8209a), -S(dd1b1359,4ee43b44,1f54a620,6e6295c9,80bc664e,3b5c19f4,273e878d,3340b605,4db95cc0,f8e2020b,c0f0eba9,d21cf630,e6c5ff77,dff8bb2a,8b496dd4,22cf6a0b), -S(f42815b4,76b4407,9ec05cfe,aba6f179,b72dea78,767fedda,3464e9c3,53b3ccb0,89004efd,2cb91fab,7c8908fd,b454672,4ad8d851,55473b21,e8e3d984,6d913098), -S(f20d41d8,c096d2eb,d480f9da,5df1bff9,570dd299,16f87ca2,19ed3fd2,d6c072e7,3eab3c48,be7e6d6c,bd1eed0b,33c54d49,72d96f86,67bd857a,8fb3190f,92b22a9d), -S(d84b9d43,20d76cb6,13df70b3,d0dbe935,852fd9b2,86978807,b6288a3d,27828a28,73c0bf55,de9ae18c,a56b98ae,3bc86a48,15d1265f,62d5856,f0f2b182,b4596941), -S(ba0ed2aa,3944454c,7581223f,d1dd113,9d340ee1,11d08d7,98f278ea,7160ca10,766d5ec,49b48092,c007fa69,a06b22ff,e02cbc30,6cbc75ca,1a5f0058,73c44299), -S(b5393ee3,7a8170c5,bbbf70,fec33e90,71e52f4c,47e21d79,e9f7413,d68050c,7eb93838,f871d769,733ff7e7,d21e3848,8632b7e1,6483202d,50a2fab7,1fd7180c), -S(820d66e8,41b5de10,e28c147,d43a0116,6cbe764d,c8ea6a42,e7743732,45b84190,cf3a65e8,80727c33,3e693586,78033805,6482b2e,53889a0,bbf834eb,c94ebbf3), -S(247cc086,26f54562,8d48634d,4bf7348d,cf60e598,5570527c,c20ce901,ef4172b5,acc2fc2a,9c939cec,a51312c,d56734f2,87d906fc,c4d42f17,82606c37,b0584dfc), -S(81c41e2e,752e0d9d,c66cc618,5aafe042,8733913f,5b597ad5,66706d72,da80dd05,8ed860ff,846ddc23,e466619e,480d944b,f171707e,721110bd,119a128c,e8a623ef), -S(24a22359,7bca9222,dc0c82f4,b7ed4ced,f5f41ddf,73e5c8a5,88bee89b,3b21fecd,7555cd9c,da2e75c6,d8c5fea1,50e3feea,b3ea1573,d7c163f5,e43b3d2f,31b0f5e6), -S(db074838,ae29a327,b85361fc,c9ad2bba,38917d58,c17ec58,9c22d6a2,f9839185,a1f7280e,35bc6b7a,b05c1704,abb46a90,43b3f7d5,30434450,f94ea1ff,f787412f), -S(6adb02c8,fe669d1a,8c7fc3e0,60eee0f0,73409111,c6013619,770d0ccb,bd8b950f,3fc12c9e,b1d19234,737a4e64,9aa06032,35d4538a,ecc6cb9f,dd1f7777,46edaf5f), -S(e06dd5c2,1d109fb6,3e5429ce,11fd5a40,5118a84f,863095c7,dbfc2374,6ce1429c,961b9d5b,c5b82b23,c8e69b15,15e28700,13094f48,c8ef49d9,37e1b440,c306eec0), -S(1b599e47,ef4e5369,bba2a71a,98cb03b3,f5d9d30a,a5e309d0,cf7e2d19,27f95c18,5a40c3b0,b949efeb,ebbd0ee7,1a81c9f3,d6fc20f6,c9effd98,f0492ef,82710072), -S(92da076a,ca5c2267,67abef5c,d06a830a,a6cd1d3a,2224a845,184b2e7a,275eebd0,db28e087,d7e29f20,d78dfa27,bccb47dc,f2a3a9ee,db0db1f2,63dad719,4ce9e997), -S(afb97660,7b94dc70,a87a2be6,53ac2f3c,9a2a474d,ef065f77,b06fd417,44b13992,68d14dd8,e3caf1c7,e39ad23c,f8e83577,d047530f,2c7d5b35,c509a3e0,51eb52ae), -S(bf4f278b,e99d1297,742600d5,d7ce7791,970de902,aad9920f,a8083a3a,a50229c,b4ed5f80,f3995be4,22fa8237,d77b1424,1fa974b1,9b725016,c20e555e,f0ea2bed), -S(c059a980,f1a7c648,95a1acd0,f9d2cd8,9dc02acf,c372740b,86fd64f7,426ff54f,dbc12822,e8155685,170456c8,4d548f39,afba1676,15655d7c,7b8c31ca,499902b8), -S(2f4d9b08,282d9adc,2d80bc6e,b4c1e2e0,553971e1,f42fb8ee,be615d47,61c023a8,fdb056fe,3604068e,2f5e5223,d3076d67,41e939fa,f2e7d0b1,76d3ec89,868cbc06), -S(a7425d49,934b13ec,85aa5c30,d628b94,f0054374,19c5a0c5,6e126a7b,261c005f,f475be59,d5dd5a7a,42d15531,df24fbd0,12d84fd8,e89ca95b,23bdd70f,10b0326e), -S(dd3d3a96,cd232751,5820439d,6455bb3a,d749947c,884a2e90,5791253b,aad726bb,9afe6071,4de46f80,d22b7ac9,a555a7f0,6e830819,437e9f98,b944d8c1,d4722027), -S(7c427ec,eed88d6,a48f7204,e43ce8b7,a4c5b6fb,ffca57b9,bd128903,c3c7fc46,495bdff1,9b1711e,918448e9,a46416de,e2d51771,43007e1d,c1a64b4b,8d1a815e), -S(bf610437,6539cc63,4a1f3e2c,4fc3f762,69752d64,2756bbfe,83bdc404,f7be496d,5bea9e3a,33d7318e,9c03baf5,3e5a0232,440ae61f,25407ab4,23514eda,1a69513a), -S(f2dad2fd,178ac78a,168981db,14c4fb0a,f7e69dbb,453f0d53,456470f0,a22cc730,e571813b,2a091f17,23c21818,789e78a0,e23e74bc,b4d037ed,f8f49fef,9623f42f), -S(51243664,8693af91,8c79fa28,d7c12b37,db24f719,bc0dd0e0,28c6c1ea,19aa42e3,fa116d7d,7ebcbfdb,8ce76cbb,e6203cea,25b65559,becd1ca4,65f7dee2,6e49746d), -S(75f316f0,c9706cda,9cbf6c8f,31266c75,5183ee71,a098359a,ef06fc3d,ad645fb8,518d90ea,af8ffe9c,44cc122d,7659d292,8a979e6f,de2654e2,e3554b71,b9e7b820), -S(565d92c9,93f08563,f65eb65e,6ae4edaf,ee409d1,e00a4e74,5d439d84,a431a5bf,b8cc1eb0,1a532023,ea17bb56,f9345420,a40b0a7a,d247ac43,4ac9347a,51bd0f31), -S(64b17b4d,a0341dac,bbda0a6a,e386e2a,64d0e517,2a4b904c,b26e45c4,497554e5,4028951b,3f17ae55,d114d6f5,ae793460,91d8d00c,c1b2aca4,f0d5b51c,3f8a7492), -S(70ba7f8e,65669610,5496614,c6c1ddef,b8c23f0c,847d8be8,37b4699d,511e3ce1,cfb1028a,2ddb2865,633f358b,e6439ba9,9fa8b1bb,eed6d988,e8652661,9bfcf28c), -S(84c79c6b,23bffd84,4cdc85f7,3180f451,3e6cc4fe,adb7056f,7de267a4,75605d68,beb80b8c,3b2ddf4c,2269431b,bde9aeb3,55e97faa,385c8776,4bd15fd8,344e8ac0), -S(c6f4eb7,106cfe74,82cdfeeb,af421137,f8665713,10616b0,b2b5ce07,8f5ff9bf,72ccb3ee,52b77765,e931298c,204e7b07,57c3845d,5abe7ebe,37db5aa0,203fc81a), -S(c58b8483,6b41a2c6,f56abcb,61cb493c,a314063d,9091ce1d,9b13cdb3,fad79f90,a1e846d6,5fce2f4f,37e210f8,cd7591d3,fe1f6c93,7fa4ac4,ec295078,7cfe84d6), -S(96e430c8,2a74ed53,7f5a181e,20faea66,ee77588d,66eeaaf7,50dd5b7b,e42ad21b,5aa2ee54,96d711c6,e8b95609,ab383b4e,993f928e,d76843d4,52a5a1fb,3e137368), -S(53868e1f,bd086477,60aae23a,3f2763f9,cf6eed71,19ce1c17,b226b48,fa85b8cb,b94b6a7d,4c86d90d,98c8d359,45949b0e,9c958ea7,651c901,90e5988d,e142493e), -S(d6bbe341,8a6bce46,2f091e5b,161dfb15,8c454eda,add230bb,254a5989,df9ef899,f1690322,6db63393,c01fb1ba,3bd83bcd,dc95741e,8ffad9e,56efdb08,837340ac), -S(a496bcf,4317fb5,c87a41f2,58e716b,98f5305c,fc957c83,c2c40397,49de94d5,2479a3ed,e3fc60f5,ea880b29,353663ba,6d9da119,52468686,bbc2d0f4,fd8dbe21), -S(5bfbaf07,3c1cb96c,45bd1191,bacd3bab,8c33ef0e,e9708164,98240b52,3f943be5,96009bac,6fee957b,2e26f717,ddf40b4a,69cdbd5a,946e70f8,b70587c3,b7fded2e), -S(955fa716,f7f0eca8,325ead5d,dac3fed,bc477c22,3c0fd563,2e37ca69,ec79f61a,418c98ff,23d7de2b,2460806a,75fc0328,5ffe9660,b7447a36,c088883d,623476ad), -S(99d3b933,e7d8c8,e1480e6b,756732a6,445036e,9b964a32,53f3cc09,f3d9211,97e70dfb,faae8f58,5a7b5da6,b0c775f4,9c095d13,5526b521,d57c29b9,b2892dae), -S(a01775d0,5b9d2fb1,277f4c3b,6edc8f7,c342c3ca,e9244fee,57cc2d9d,d5b096de,376293db,5c929468,236828a6,1e291811,316ca7fd,90efda51,2bd750f8,62ebabd8), -S(697cb417,bea89412,91ec8ed6,f62f1914,96a22208,905dec11,463014bc,2e9a04eb,d5049ba,aa04b285,f3085c24,e54ca476,cb266f3e,15699d12,fd250e39,ec4285c9), -S(b23ad54b,f9504c8a,c0bec876,71d2d41d,ee04bbcd,c5ba224f,85e3d4b6,84d8889a,8f0b0da9,db0467aa,5b21addc,d3951b72,8d23099c,47bf7767,24e1eb23,ab32e7fc), -S(c8af03ff,197dd38,cdc294d0,28c0c418,2d517dd7,54669894,812d870e,65160c40,d4537dc1,e594be6e,cf2e3ab8,6f42cc3f,a70015a9,ed8e2850,4fb6f9bc,676be0cf), -S(7ea5647a,f0f8da46,6e6b0615,28d0f472,79ae2a2f,5eaf0dc0,64ccf902,e060cf1a,bc5a47f0,d95e37c2,ad9c5fc8,48eed4f3,c62c974c,9b96b250,ec076851,12a88ed3), -S(78cb2c40,71bc6abb,cbafee4e,cd413181,cb1b5483,ea1db7e0,f902f31b,346f7ac3,86f334e5,5560d9bc,60d8463b,269c2626,45eb9964,970dea35,eacd9236,3a36d198), -S(f968919a,7d90997d,5863c9e4,e214cb37,51dfa039,75d876b2,3f1376b4,ab79cdd7,ae3950e,56e4c856,ee56e236,bd581033,6991f8a0,e9212c8d,9e9079f3,9edc2038), -S(d7c2fe4,6d1ec3b2,3dcf9992,357bffd2,aea9bfea,da187cdd,6bbaeb2,51ebf663,ec953c2c,5fb70a14,b21791a5,979a182e,c3facd73,a59d0f50,c3231485,f376039c), -S(63aa7712,4dfa263b,fc8c7b,85dda505,14d694b4,5ac9f06e,1482105d,ac04af87,d368c24c,18de3ed8,43f521d9,3633e9c1,53627e54,bdc10eef,15491802,41dbd9e5), -S(47fff446,884d94f7,a1b2253d,2f2cb718,70a6a42e,36f63feb,65fd7e98,213117d4,ac52a32f,55dfecd6,68b61733,3fb4b7c6,fbefece2,d2cd43f5,667bc42a,f17d02ef), -S(b3d96bde,5770d471,1a91b0df,17c785c,ff7f51cf,c4d46c27,7dffe07e,6c5d1173,78e408bf,6d204097,40a1145,becb61a9,c78120c9,957c6457,12254e2e,f5a1d77e), -S(f17f1d4d,7df494d4,70321d27,420deb68,22be3877,78df53b2,37876928,d6b2168a,4398f0ef,7cbf1188,dbced020,7b2aadce,440b1df1,7db6870a,a05c6d56,4038306d), -S(10833a6,6f75d109,e5251b43,f05d9069,2bc216a7,bb06032f,c2d142f3,cb1eb1fd,f77ce6f4,73e861ef,23f67a77,a5052dc3,4b617279,1e69a688,308439e8,7d91bfb4), -S(301bd783,a82ad1d0,daea7641,6575db5a,1763481b,3c2f94a4,788f7a54,6f9af647,66ee6029,13b6bf11,e8e19392,633fb8b9,e2a3dc51,bd891ad7,3fb80d31,854333be), -S(98fb5877,816a2c9d,df0192e7,beef06ba,c19b3760,b82d8e08,1f6b2431,dcc20d6f,de59596b,914b994d,83a68c1f,eacbfb8a,17b9c54,9561fd48,4f7f2f80,bcbc24cc), -S(5247f727,1de92a64,dd35147c,879ad2bf,4cdce035,2c077e0a,19164052,e19e2d68,75cae57d,3e54bac5,dd41655c,f62f6ec6,7e84255c,bc0bd176,aa505569,675ad042), -S(51d7bfa1,5829219f,6af5d2a7,1ff220e7,9de62e7c,a3909d4a,37c918e0,6b60504d,9d1a5e54,77025129,1d42c64f,14d27eb2,cadc09c7,bf3899b1,b85119b2,a5326f4b), -S(533fa077,4c05ba3f,b32ac60d,13fcc4b2,a20ccf97,bacf2abb,d2d9b6c7,54678437,a41595f7,3d604126,7b82b50c,22d39ca7,7454bde8,97dff46f,3c57f7d8,ec73e818), -S(a549dd6f,2c8f422b,dbe464c,48f61d13,b3537a7a,2fc5a8c0,91d7d33d,221ff3c5,ad126f86,b69a56d1,2ae18f0f,253a1989,ce80a74f,114e3813,2199d1ac,be03efa), -S(7b9161bd,b4d5e56a,c9df5417,fd84aa54,798b9328,46218731,ea289cb2,76a612c3,72e268d1,53fc13cd,743debad,16c98af3,4756244a,65b7f7b,33794aa3,1aaf497c), -S(21557200,4f644ced,9c2aebb1,43beca5e,d54bf17,d2cb1ea6,492f19a9,25a5be52,19dff558,9c87a8bc,d02af10c,4b32aa25,c80b2542,62ecc0cf,bf4439c5,c2184cc5), -S(93d2caf3,c1a0a83e,ecd9adb9,abefd119,1000e482,2670e678,8859fffa,a2784cd6,f443827d,c5437809,e5cd0eff,b48d7b7f,ed4b3ad1,a724cb7e,35aea03e,655895a9), -S(388a2c3,f621470d,eab3d1d8,765d6af5,629b1cd9,10ad662c,43abab6a,9cee5283,653f3611,7e335b31,48df68b5,a8cf6fbe,134cdf35,f659f14b,9036b933,654df3e8), -S(9d9c6f6d,7032898b,77dc7738,426723ec,dad11684,bde6e061,63ed6802,69aebec0,f20282b4,96183c42,8275eaf5,95834713,338112dd,9f2b0924,8445d56c,15a31276), -S(6e1d3bf3,98cfb2f9,67464d53,755f56d3,bd4de638,4425975,d96df00b,b500e825,6f8afe06,eaa52db7,291b41c5,959aecab,e7111b74,fb260d40,68f2a8d3,895012be), -S(dad8454c,5c6fc1e6,35c4ded8,1f2e3870,a5f24fea,be8b6d7b,a2adef19,32bbfb53,7c6aa3e7,615cb467,42b42973,64222157,de26f811,b4046d4e,591f9824,4fddec5e), -S(5ade9345,11ffa26b,a147ee6,fab27693,9828a8ee,7cbf5e3e,e9052b,a01e0893,ed84e129,7d98895c,b7ceed84,52db80ca,3f44d127,d484364b,652b96bd,82f8ae16), -S(d6e9e33,6a39b415,e5909463,9d621291,9c81a084,dace8a97,a0372042,14cbe366,4f274e3a,1ed0ecee,c7d1d4bb,28712e03,7632b43,e1f8b75,a9100b4a,f74e90e9), -S(a913a4b0,a990ae15,60caa68f,e45bf7b1,af500129,a7bc652c,b47e80d3,34bfedfd,1bea9464,6a332e2b,8d94dc5a,32ce31e3,1aef6c83,ea7a261,99da6cf5,7892f63c), -S(7380fa59,b95fbfe1,8e1c3809,36d10b23,27fcf8f9,21aed806,1c602498,c2c6ca5f,fa24454d,bc8cb2b8,9462febc,2e74fd72,8d300617,a601ff12,a599d2ad,bac2fb7f), -S(9614b47,50073368,4d26bd95,5b9f4df3,8dc11bfe,4ac65d17,6149e1f0,89f3a69f,12a2b07a,49812efe,1d3559f1,e282f268,813e5572,8c959a9a,129ba886,9f06a66b), -S(5f2956dc,436e7a52,176d2709,362e511c,cbda57db,ca347ec,63b63147,33f14d5a,f7b399d7,7b3e1d75,b5578e3f,f324ae9a,76c243f0,8dec8cb4,9bf7a78c,120ede0e), -S(22d7dae2,38885aaa,fd51858,f4bc1042,5d57599,2fcb4eea,eaf6c222,c0ae9e7c,6f3e789c,24247afa,9ae0adf,18bdc160,b1d6d956,7ee8fefb,e9db9ae,f0734909), -S(9e5660c9,a5f53e77,59586df,b2b56dcb,8f1af69a,aabcd59a,73573711,3fbd4dd,2868aeb0,5efe76a6,8037ca6f,d97c2769,edafed65,3f38555e,15ff41f7,fd1fb8c1), -S(7abf134a,123ee2a5,eb4bc1fe,6d06f5ad,655991c3,dfa91ebf,ae46ba80,899adf3d,c96dd41a,238cde21,3f628bba,a2488458,c0e35896,f32cf7a0,45b252ff,ab696522), -S(95da0b80,e45e13cf,f5f4f4a7,5265a310,8424fa09,f07f2c07,efb7a018,b5edc82f,ab645319,b3645cee,d1e4823f,838435e2,79f4f41a,af258432,b210a73e,569bb4e6), -S(8a095bad,b000f2e3,26b0c8a6,f1363fb3,4e2f59cd,978d736d,d05614ce,dc849fc4,4e367851,5c42cfe4,6bd3b6b1,6a09bd66,59626f10,a0087591,6b7d178f,14eae676), -S(de5f5b91,eb34ad1a,9d3c60ed,29c683b2,59f4c7ad,819bdaa5,f751c1b4,7ba28567,cb9d478c,58a02246,44f59a4a,cf2fe992,15f541f5,febe0ebe,439a1b8f,baeaba58), -S(94acffd1,b87c644d,b359cc14,c1d996eb,a1d7e773,d902dd5f,7086502,bef6180c,8e58ff91,ae72b071,abb09a19,4afadb4,b3a54c3f,91857b3b,bad991bf,a605cd78), -S(fb75db19,87635a41,e325f08e,3203e0bd,e7ecf969,e46244a3,5d63dc5b,a64a3336,14d19c5c,220b044a,72b58666,9c74ee94,2df157ae,67524f01,9707806e,1bf73c59), -S(9808674,a196cb3,eb0b2558,2a9bac0c,659741ee,ce6b1c49,678e318b,f6456081,f5532b86,3408f545,aa218a22,405b0839,9e59fdcb,e2c54230,9955aade,3660aebe), -S(f2b603e,d1d8506c,b1280f50,f3487f1e,71d797f0,f8c8a1b0,fd153683,18d843ca,1d6f91df,d7bbe002,ec34bd9e,9b843620,ff43a756,88dc1398,e23b73a4,9d3e53ea), -S(b9327718,4586a524,389f7e49,adac31f7,45ae323c,d3ccb1d6,a2abc65e,863e684f,b28c0f77,b47bdf1f,390eb8db,b94c606a,84084e09,1202dd3d,654abc10,3589b6a0), -S(c16eaf54,572c1a6e,142b6617,b38992a7,9cbbb577,348b8768,56ccf471,e21b7b63,bb9e7a6d,6d8ed16d,4f8f5009,76edb112,4d5c7ede,cb2b8abb,73de287b,5099035c), -S(97c03ecc,6a87d198,13d68f64,a3cd91bc,ddf45350,383b90be,c5565c48,531999e9,f5cf3c4d,71be1dcd,60b39aef,f1cb8ffa,62d3e07f,33d4ea1e,adaa0569,3c239ce8), -S(6a224e6a,85d31717,10013b13,14ed6c31,adfd153,df8bb9c6,47428e85,12c1786c,690a057e,ef9e425b,651f55ca,8c72169c,bf337e7f,cb779ce7,81e1ca9,5feac5a), -S(1e89ac78,be4513d9,38e58385,7256eead,54afceda,32edfe63,c70b0f75,83eb9ce6,bbc32d24,d58f47ff,2686d804,4e62e575,a1f1e805,75587b90,1a362461,93f9aea8), -S(40df4fcb,8648bed0,44050957,8ce57046,bb8daebe,5a7ee63a,e69decdf,a5de87b2,154c0c93,8f5dbeb1,80939a49,aa15239,e3308e56,ae8ac16,3be19bd9,33fd07f7), -S(a03f1ac5,a3738a09,d4888626,72f00159,59c280fb,274e9974,7447dd30,260bbf8c,9d28b67c,3455e338,1d1f84c8,d60e4fed,c39b5d05,8d17829f,ccba683d,cd65f093), -S(c7d9dc5,d2712b0f,3da6b4bf,1b6d74ba,de6f9586,a794a1e8,4918ddc,d115d1b0,b1727ad7,6666c0ea,5abfd80a,6aff8e66,b8b63c27,6a8ff457,573d8336,fe65dc0e), -S(3c1f81b0,2e8794ae,135db6d8,ea6e1cf2,adcfd535,634ddfa3,773555a0,e0efd26a,e21915fb,abd19ab1,a4cf84a2,a5275a50,24d0fb7d,c841fa43,284be38b,788d9390), -S(69503972,3c4d14a8,1cefd3c9,ad7c4a1b,d5b01ec8,530ade4f,fa7aca65,28ca332e,20bee7c6,5d499abd,f9c9fa2a,585e3f73,cc52141,f4276cfa,aa856c84,6114c1a4), -S(da655560,50683d9,5f81b2c6,e504128d,5f58fa43,4cfdee92,c0324b84,77c3ed70,297e7d88,2009d30f,bf0b5aac,1c7572c0,78192a1c,475fad61,64b25ea7,871017ba), -S(f1ec70eb,ce501e37,f79406ca,f120046e,6b064b80,b8db9d22,d41f9b8,a229cee6,8688ba6a,ff61aa53,4dd93b02,e3eed5f9,f1622d2e,6fd3a3fb,594b9bc8,5beb55bb), -S(fd0c93c5,c2334d97,1e1eafa5,6b62d377,d1104ae9,1c10e707,a404674b,796c51cf,e2529070,a0ac26ae,bfa954ad,801d0e2b,cecd4102,77a7cedf,5a707dbf,6c8ef5f1), -S(514a3ce4,b9f518c0,ebf15b1d,56687638,7eab4df0,85f93f0c,53831536,ee75c78f,8b998180,c9e78405,cf9cbf2f,7495455,6d5dd04b,bafb010b,db7a4cb3,6bd6cd30), -S(6d0e5be5,f5bcf0d2,37726045,727ce85f,336bc6c5,743c0254,9dfed03f,234fe265,df071d23,bf3e151,5995d25a,f7c8cb48,d81ec018,af8513a8,e842e3d1,484f99f2), -S(d37f48de,9143228e,d5d02ba7,f5d97b07,922e75b8,54eeb91e,86643a6f,cfd8416,f7d6e782,af5c8c0d,f9d2c80a,e582b88f,bf9b0824,6e749d0c,9ac72afe,847842c0), -S(d44815f7,46405f75,f03f4749,b5696cb7,54fe1633,7c721602,cfecd1ad,fdbaa875,a6b75d70,4d5c965b,43284bc4,d4db5d1c,980d4bba,e8f8157d,c1cc322d,44fce058), -S(6ee0ca27,441c80d,83b710d7,a6e4f5d1,a497287,a16e3f67,7ad24df4,4db8a287,60d12357,350a737b,74f857e2,ad3865c3,5dd54e00,e70d1aea,cd77c12,fedd02ba), -S(86edff95,6ae4aec4,7a8b4927,4170faab,dc19828,c14f3de2,84362bf4,5bf49d6d,c9f571d8,1fd0b910,7043a52f,79fde3fe,339b17f,ac0e6461,8c601c17,375955b9), -S(c8ea3038,f056e115,aede11d4,ce113663,da276b83,12510e72,1cd8600c,a4a573ba,a662f00d,952d21ae,e26f97b1,6b32dfa,c0b58c06,6cffcd79,3755cb3a,85fbf3e), -S(541b43c0,16ce2179,9c7db4f0,e06b6c7b,bf006f1e,2adedc1,e8f4e8e3,1572b199,27742f79,a0986843,1560799,c11e0f43,be6e8631,7abf4d25,36e09e25,38b90ade), -S(1630dee,a2d1311a,a7c0cfaa,2693595d,48c274bd,d24cbc7e,4c15e458,f7547d40,f1a92fde,a7d828e7,bf7b1c8f,512a21b9,7227eef2,daae040,f8cdfab1,a728f20b), -S(126f6117,456d919c,49325ee4,1cb1ace2,fdd5bde,31208bfb,58b5fc1,62ec799,4c23a017,73d47eaa,579e5cb5,14bb8584,7955f03d,d097d527,ff366b81,1e6abc81), -S(b6210ef7,1bd1957e,51805a9e,70c6663c,6d8aa371,e1012a46,8261653d,a3470c98,c491d5,e98bff1c,7ce97493,612dd726,bdf69d7c,a4524721,79ec57f0,fd123b87), -S(34291314,3842cc68,b0184bb7,13f7c6ae,aba928d1,5df911c3,3bddc99f,ec8a5786,4b63c3c0,ab6efb2e,bc343cdd,dd43d553,582a53a9,3c3663bd,138eb1ef,d2a245cf), -S(5aa2e234,938e26fc,12589307,afe2d797,bad41d73,3eb6dc66,da9a56cf,d4b6c4d4,db91df9f,1856f8a7,83696842,1887235,5111b973,10fb5975,154cdfb4,2f2f2e64), -S(8c50cd04,5904ac5,d9c6d555,e7bf188d,d2318edf,cd90ab90,722d8552,edbebb92,f60add37,b3578fe,f798d8a3,99834ef9,16e9ca8e,2ca8b9e0,1537e7dc,533154e6), -S(591e3233,9e5ad324,be635ef3,50884aa0,bf3efa8f,7ee012d7,8476ca35,ef586ee6,6e219d2,ff115d36,b3688e09,b4788bd,19b5e471,6f09eb41,cb598ad1,b60c069b), -S(7d4464b7,587b74e8,82c85444,4d7637b7,9b6c586e,b4a032a2,6e07b60c,470d82f8,3f1f3d44,6ada0a0c,4e082bf2,c31ac7a9,d2deee7c,4d9492ac,81d47a3,db7794f5), -S(92e55e29,e333f65d,1fe8845d,42d585cb,55db9cf3,223dc567,29906df5,bdc93387,5ff7c2aa,25b670bf,5ab2b57f,831c3e6d,b9801ba2,10aa76a1,2eaa45e8,29a64454), -S(a0fbf93c,c47198c,9492defe,fedb5ff9,dcf178ef,70a0f416,5128d18e,49083c28,dac0dc87,4bf9f134,fcae7932,46a6306b,5c876455,fb493b04,9a74f94c,82cf0a56), -S(5484f0ed,aabe9633,f0384de8,5f86e77d,8153acba,b8922863,6fabe9de,3dd12fef,180e070e,a3712386,cc4ca4de,f54c0399,fbb017cd,3ac0704e,52d60f50,8c0f2c2e), -S(f2452493,34b7983f,afe9d99c,55023ae8,c8591405,4cfc930b,3c76bda5,6c106445,6e800534,948b6349,f85c5164,ef5bd33f,f8d209eb,fc25944c,110f04bf,fa47c604), -S(d15f5c6e,20f96f4e,d1aaa912,b47198a4,fdcb1101,c258cdd3,52cf0246,2679f845,7751370,ef04b59b,bd74d4e6,286d690e,9158f004,826b2dd9,37070544,b06df5e0), -S(75ba968,f35dbf2a,bd92c08a,24930949,7a50bf27,efc51572,232e152a,a5988818,64be1522,78e3c24a,890c584e,8f2561c7,62985b74,e803d124,11910af2,487f9491), -S(c7742126,88b392df,ccb6721a,dee4f49e,ab1fa24d,84695994,f7d0a7a3,3cd52f21,e603fb71,9464ca60,a8ff9047,6093b2ff,e9091815,58ab8d7e,aaa7bf14,396610c6), -S(d15a536f,661f00d6,ce0892c5,6f7ec1ad,614becd5,9b5d3019,a24923ad,7bc828cc,b2d1c3d5,a9a84da5,cdd277b0,512835f,48b546cc,3fd36b16,f83b8cab,caad96ea), -S(64a9f14e,bbb02687,cf9ceed5,636cc349,a8e55cca,4913a221,641a0916,6afcb872,76b2ccb8,2dcb7837,97d31ddd,bbf9abfb,5173b495,6a6abd10,f9a583fb,981bafe1), -S(9eb0c54a,9490fc39,75170e03,1d3be45d,1eb54587,41db3f40,19e83ac6,be7915e9,fd570313,71616577,36c736c3,b282b0c3,f1f9146f,1aa9f,8fa1b34b,f10e87b), -S(141e12c,501af124,a22cf65d,b3996c76,44bfccdc,2920342a,4f3becfe,d279005b,1b6e9acc,c61ad52f,d8f00405,f2191432,b379492d,838865cc,58eb4bd2,c1f1735b), -S(63f9a52e,aebc297b,5665752,9cd93a78,a0ff93e1,f94629c4,bb9b19ec,68ee1895,8e403a45,497dd525,b2924861,978da88f,4823236b,338ace3e,76330b21,a9ad14c4), -S(af31b58c,47a9c9e7,3bbb583b,2178deb5,bd430031,9ddec2fa,5e66eee1,f0ed8b1e,d1fbdf75,8ac15977,cb8c9e1d,7863c465,cc4dd8e3,e299f116,74b0035d,291e1472), -S(985570e3,85b4ce30,847c2a7a,cf5a3c80,ddacb47d,dc1ce66a,d001cd13,36293ff3,5b13a12,75c5b519,10398a58,f42158c6,1c064600,809d7a8d,b31e14c0,84578854), -S(37ac2f59,ef79be35,41e46114,c4f9ad15,e6c8122,db85b62,59604adc,c8cd303b,434d325d,e4ba5b11,7b876da7,8c387d13,3d0fba87,d784cfc2,1ef689e0,4c1d52da), -S(2b002a0c,280419dd,7911a522,28ea70a9,7ec2f9b6,db5316b6,7581a6b9,7354ba70,dade84b,34a23024,785c211b,73b006d,7ad1e3f9,e344c783,89d83eca,332e4734), -S(65c4d14d,f9a0853b,61429a40,50d2aa66,19f63bc7,12517118,784c0100,9d7ee08d,4cc1bc89,aac9c9b,931e9546,cac82cd9,6051b17c,991cbafa,efd52f44,e514241d), -S(df27b45e,7a49695c,8c38d85e,5eb7e9d2,8cbffd71,8520f681,1144087e,8a372c32,cd3d4c1,5ab586fa,ba4af68d,9bf04e13,31f7e5a3,95d14c67,e4ce598a,4077fc6), -S(268c1fc,eeb3d3dc,55daac92,23b9f511,418917b0,3d8a8210,8096ac34,35a820d4,d623750,3c42a02c,5a386e1a,f39694e9,844272b1,766ee986,6d4b67f1,81086fd1), -S(cbf09fd,f85c8ff9,3b1e800d,8e5901c,35728aaf,3d2824a2,bd09e1ae,c76fe1ba,3876982e,cacf4bc0,aa53fc48,6a98cc01,8ad33f67,e4ab0abf,dc8677cb,e9619556), -S(4126180c,88d7066c,8f7877c6,5e41b4e,c15f94da,e68d57ea,a2131b1b,6b9bd2bc,1bfa8de1,71947fed,a0c8ce3a,2cec0e5e,e307f7e1,dd3b7ca7,4f0e0682,c1c3d087), -S(bea8d718,159940f,dbcbe23a,5911dda3,c75b7931,cede87a1,5cb39de3,3f35c022,e723c23e,6bce4f27,fbc219d5,7d7ea196,e3ce1273,58e7eace,9d6b686f,efc35509), -S(2275f050,a18ed0b7,af54c69a,aabdc987,9eb9dd35,7211a964,23ad6e86,48624e3a,3c025a31,1a0ad11d,c9d930d0,7bd101fa,189415f7,c705abeb,bc585948,14f4d88a), -S(1925ef48,16c17466,f7e16c4a,7c6352cd,a12a2a15,9880a482,a06f8911,21b32fe5,30f83429,fb20aa48,ca4470bd,f90f9d6f,1660e583,5868e67,94ec16ff,e06fb81e), -S(18720528,a0612661,3ea23c29,356c4a2e,db74229a,79f008a3,1d6e1357,f873cbe2,ec54426d,a41525fd,d74e018d,dca72be9,e7a28000,2abe1a12,4a73ed4,21893106), -S(b8a6972f,c526acb3,4136cbb2,4850ad15,cd70a4d0,ed66a9c,8605b257,885c9d8f,e043953a,698e3225,a35271ad,2a173fdd,a1d37ef8,98c630,d02b80a0,cd729fd), -S(3839720f,b5c7c3d6,3a0ccf99,c0f951ee,b257d818,b3ef1e52,b530aa23,8ab06887,9d58a455,9e5268e,48292e9c,c6d78275,c733c2b5,b31326bc,4a0546d9,7d950529), -S(c204f868,e6632183,88024c76,4ef92286,68ba2867,bd301c88,1bf8e7b3,e6677e0a,490e59a9,4dd95482,8b386c0e,d6778f93,5a692d4c,74f6ed47,61aeb26c,4b1eb048), -S(dab95115,4aa1451e,95cc374d,6a6d6801,9778f54,9672c4ac,f9d16b39,ac2464ef,e32e5c8d,453be5b0,8c5ca506,b7875565,7f269a75,daa83a4e,f11e1266,f442d85), -S(ff283b71,7118eaba,52225bc0,ec0328c9,72e5c13,3ffab3b,801dded4,cae7e596,36d8b7e3,4dd684d7,e9b0bdf0,3d60304d,7d990a85,a955cf3,db681d03,b0af5d43), -S(30eb08e9,6f4de692,d2eddb8e,aac47b48,1f3406e2,235560e5,b23d0b9,f2ec4597,cf05cf0,26ed3094,37aed28c,2dbb6f9e,94f83333,15f00832,1286dead,1c931be4), -S(9a51edbb,e9146fca,d3c9580e,9ee34252,6b2d59b,c0531051,76bf3ec0,b86dae9a,94d549c6,2cc12e09,63c844cc,5dce24db,834fdc93,4c8b06e9,afc10f34,f08705c8), -S(ac1836ac,2f0d0158,650238f0,7b2ed1b,111bc56b,b176558f,7e018111,ee520c09,562e108a,a842608d,7c86eeca,f6f2ebd4,ad4d14cd,48c3d068,eb658c28,ee1aca36), -S(5c33360a,1bc8e85c,b0f78d66,8f6ba33e,4537e0f9,88525a1c,b186fdf,7ec65596,8f86a399,ba2038a,9faa311c,f2646ad,66de6c86,c3280d93,71d1bdd7,d9df698b), -S(40798759,c22a7b60,464fecd7,d506bec3,3614c895,c6d60d14,d1ef646b,38559793,506dcebb,aaa057a,433b0eb8,96d35070,a871e11d,216d6a42,19689167,b8588b9e), -S(36466772,ddf9865a,c6940a62,abbbeb24,3092f44c,58e3c052,9cc0d3ac,738d99cf,60ad37de,b41ee4dd,8cfc755d,e309157e,608b0a5b,ef385836,8c7c7dd1,cbed7075), -S(e6169ba7,ccc02fd,cfe63742,910a5e9d,3a3e1661,d8da60d8,32b86e9d,487108de,f29ff08b,afa4568a,4ba97709,477b086f,31685c1b,a6de5c1d,eba8269b,32c2cf41), -S(3bd8fc06,2fe50198,b77aeb1d,d42b9536,7fc172a4,f2528ffd,597799a6,4c0661b,c73a3d92,bf87cceb,f0020063,115aaaed,ecf414eb,f03179c1,86ef37bf,b452795a), -S(aac77264,829bfc44,6c2427ee,8b732a82,3480f11c,32cfce72,35b0b5b4,6749260f,c788928d,b75ea7ba,e216d8ae,91559d05,8597b9e6,3bc2fa6d,276c29f,50bcbe7a), -S(1dc5e0f4,ed05486,c883b07e,e78f1b96,49858bcb,6dd396fd,17a19dc9,a788a1c,ee4fc404,d662abb8,bf7122b6,c3a226fa,ef491513,49231623,a9d1a796,cc6233ff), -S(82a1f055,d885501f,114fc40b,123fbfd9,f45499fc,fb8720a3,c730fe75,ef1a8601,39fdb201,d30ae709,486fbc27,1603bb93,826ca4c1,395bd9a,112ea4e6,476ec20), -S(f8721b28,ea842788,863a1ff0,339ee75,7c508ec9,49e4f4f2,71d2a460,f0c14ed7,761ba386,5850303c,4449a3a3,44ebc7ec,bbf365a9,4688f254,558289fa,5b0715c), -S(9a8d123c,71377193,79d44740,af95d63f,ee954c28,55eb7aff,56707a1b,f0ac683c,3479784a,e683a3dc,c1238f37,5b6ef82a,487f6e5f,df487ba0,10477e45,49652d9b)}, -{S(49e7429b,e0d97bf9,3f17e9a8,53fedb6a,a9bc6edd,8e85f44b,9d2f1469,b2d3b178,ff9e5dfc,2746679e,9826039d,578bac31,c08fbaac,a075214c,73c50f,74568fff), -S(e872efd9,8147527d,7cf1ee62,e4980ce8,f1a7f561,a34ab662,1d503a7a,e98c6433,c8c62103,fe01e381,2553e68,5e7d221a,974cd4e9,f3247078,de37f5b0,1b9ccde6), -S(617f6235,8bb46c55,7608c7e9,ee198fcc,77b61c64,5e953cb7,419375ce,1e06fb58,fcd7edad,db70f22c,364cca9,9a792f53,c71474a8,707e2cbd,551d2626,6b373158), -S(86810c6f,f27fc69c,31d69ee8,4b616345,fc1526d7,9dde9dd3,5e1fe6af,d8fa0f55,718e736f,6c57643c,a8c0aeb8,b8bc6466,108e0149,db197a44,14f067a6,10ca5f84), -S(89aa4974,44ded8e2,4553001f,4a6247e8,bade925c,a35fda1f,38a86f84,b5b6c581,dba8df4b,9c9f02fe,e5a996fd,f77c870d,4e447410,de27d7fd,942e554d,fb1edecb), -S(9d89ff53,d85f9e10,6c78c86e,b114c12f,6852a457,d91aa28a,75f2afbb,e9191fde,7b1b4d70,5beb53a6,84a6f596,e6b22751,28b49be5,2ad37ca5,bed6a952,68880ce6), -S(b21de2d5,767f595e,5b873e39,9c02beda,571cf7ea,48236aba,fdd69729,14e4eb86,1cafd24b,2414958,9812ceb5,1d02d5a7,14f35c04,8a333f21,922e6baf,52942c7f), -S(d64c65fb,627b3d76,135ca1c3,ac8794e7,a62609b4,a71609ad,73972df6,4f75ca5a,6301fdba,278e846d,246e4a54,10108682,7e815fad,d30a58a1,3247779e,a397bbdf), -S(85248d03,5f4598a8,618eed84,92ef45ce,29ce24f7,4476cb9f,95168197,6fdf83fc,ddde2121,e31b1986,6ccf28cb,b1f01925,7ba53c8e,88eb3f3b,a8faef83,274de6f), -S(2ccb22df,abaaa33b,6da3d166,b2f85408,231edf40,fc9f7f89,24256378,7f10984f,35fd70be,fe7d802f,c65e02de,e5aa7ac3,67ca0b20,a5e3404d,a5e59eec,8c9cef5a), -S(3f5c061,fdd98ecf,ac9fdae0,3b527223,319a871c,c385a134,d1b7e35c,9bf5d42c,a1ddd10d,1789d24b,9fb96387,8789a472,96c757ca,99233b97,899bcfe8,e7760cca), -S(2e1525d,f6ae8b7a,84932980,1d4fa138,5fc07382,1a197e00,f9a8c235,68a75647,af7a996d,71ece94d,4384bcd8,60e947a1,cde4ac6f,408c31f8,cd67f0f4,a0807f6b), -S(247becc0,556b2585,9e426838,bd34dc9c,e194ac7f,b4ace971,9ae317a6,d87f5316,bc63b0b2,8051432b,4a6917b1,7afd8b46,d8fe2599,99c8f254,1e5ec22f,cadc8c9e), -S(3b39557b,8f9bdf90,76acd422,c46d1681,f7b3d29a,40108214,2035e3a2,8c204aa7,773f2a70,7e6288a7,9c3efb89,19eb100a,772fa946,c59f0bf8,6796b76c,1d7194c6), -S(d1bb4751,49254987,5e4bba5e,a0d2cfeb,703e149c,5ef6ef14,3f4df5d8,93199e7b,75d04702,60bbb309,73bcda42,808c4cf8,1f33dd89,e5412e7a,bbc6e722,7f0e4acb), -S(2324c1d6,96933334,b3023542,c506687d,8e7b6854,cf0b1ca4,902c8874,39a3a4ab,269c5c10,3731f1c2,419a5b53,566cfee5,a878c33b,c2aec368,b1b60a3c,bfce7776), -S(5896a34b,37869f15,7d19b9e0,cfc927b,7fe0ff91,a173f480,b371d18a,1d72c0ca,ea9331b9,b281b800,38edea52,1ff8a3e7,ab0b7e2,e431e9e,51cff269,cdab8c52), -S(2553f696,b32af6e2,1cc2089a,63439911,4d7b9d96,a883651a,c66f1d8d,1b74dccc,44c3915a,6212f827,3f02a0c2,b2de1e74,295b31ec,d2457da8,faddf543,c9244ffc), -S(131b4dac,25fea2f,715da576,3c175d97,657bfd68,21224136,5da967e9,c91b8ccf,30b40489,73a61cc1,91ec22fe,3429589f,13aad7cb,cbd533b7,2e692f75,f728b668), -S(59d0164f,e8150846,874f1658,3af49019,e300a2c,4807d18a,389f9b12,60585910,eb91680,a580a52,510ae709,1702abd5,6264181e,477c99de,6cfac0e,5533ea88), -S(691e86be,3a30e851,4286fa5,517d1fbf,c9a969ae,d7837e4d,78f6ca3c,e088f2f6,b8108fd7,e5bdaa7b,9d34f1ec,b5251705,76ef53bc,243b864,d20261a2,b9a6ff5f), -S(c68d096c,23f562a2,2ce91404,6b82a43b,22b1e7b2,63e58107,96128ab,a680ca71,c5eae54f,b59583be,509466d8,95ad482e,ef73b8da,808be571,d79402aa,26723774), -S(eeaacf5b,e4ec2817,1acdec98,7b5cb678,91666932,42b4c546,8debe163,430c20da,13e8c773,d867856b,af5b27bb,ad7adf86,a3e4826e,12fb2b9d,504e63c2,2b2460c8), -S(5e3d98ad,35e8c90f,131ea3af,2c99c45e,7ebe6eca,38d02120,c0876a8a,b4b8dbe8,a019fd63,9bb8f5dc,b4776131,398be36c,b3419a3b,27596462,1ecaad5,8a3ccac7), -S(1a43b7db,a042bd97,ea23ebfc,1384587f,4f66587b,1fb0f3d7,c32af9db,449ded4a,89667998,5946f126,34f00e5b,b7f0402d,ccbc8ced,a8389e83,872ad821,3bdc2f32), -S(2222292a,ed3f69bf,1ed2cd12,3272a7b2,b57b2b29,c9f756f6,9fdcabf1,1b67dd57,6f6671e7,d22b9cd5,d70a6490,46101054,f48a39a4,797964d,c4c2df99,a982b3a7), -S(5d5bc560,8ce7cb81,ed23304e,fce25034,8dfd497f,80dd3d9e,193641ef,9358a16a,b63c4202,be581677,ec334ddf,5855e39f,9f8f9544,f9f1171a,7823f0ce,61e2051c), -S(1a669fa7,2d96cf78,886bd7d1,36e7dfb9,8311b4f6,9067f47d,12830ecb,612ab969,e45ba9ee,f80c5a3b,179726e3,4b770860,552b0a6d,6ce02e70,529bb5d8,b2eafd9e), -S(acf341a7,add1eb1f,b5dffb5f,cafad928,b40ff6a1,fc0bdc67,9380690a,7daaafa6,69a7231e,ad015747,60b6fb6c,4a7eee54,ba348bb0,1d201d86,614b9397,89c00cdf), -S(f4238dfd,447cb48b,fb9f6678,11168126,446caf0f,3345ed,a31ba759,3115318e,5cfb371f,296c3a50,6d8569f3,60902baa,35e710d3,619c14f2,3564f6bf,99bf7149), -S(cc328f03,fc2b3590,3b8cdd05,514dc673,1446fd17,3349f0d7,a7a99da3,d2271847,883c8b2a,dca40796,68b0e472,c37ac41a,c91dc5b3,1aa84cd7,7f319828,3b72e2b1), -S(8e9bba4e,5fc87283,fb3a1b71,3b493127,e0c3e5e9,e3f2da4c,51ea3d98,5f3bd579,325df34f,dd64edd4,880a8ca4,5bde671b,af67a76e,f1a5a27b,abfb42e,c2b7d29a), -S(790ccd03,fad172c5,10af246a,a6e4a87c,56db01a4,55b4bf11,8670e5f6,54b0f816,de872f4,63083283,536d6943,ce8c67b6,6476cd8b,ce802fa5,e0817c5f,7ab684ff), -S(feca35f3,f030cc1,e0cf0a86,3a11d035,95b2ccf,7569dede,1393cdaa,a972d1dc,3fa066d0,565406d4,52aefc9d,ed45133b,48933d79,e0a25533,e9a24d98,f608818e), -S(c6b38388,cb66141d,777b3d50,c5224c63,94e587b7,9b62fee1,6fa12c9f,d7771d66,3b9647e9,2ab35770,e0116e36,27a31526,ae48a595,5d46b7e9,b27e5747,c066fd80), -S(db412fb6,3f925c6b,62ed566a,de8b4768,f3c0be38,dcd165eb,eac7a081,fdcc43d7,fc305dce,74f64672,2eb963b,792f312,4b5da5c0,ec8c47fc,254648e9,e562d2c9), -S(777f3e29,83e8511d,90ec346b,1cf6ecef,4539889a,c124da88,337dfc6e,222eb810,e0abd8b1,fb97b582,27beb723,3308a89a,9dd5cfa7,303d06e9,2c2fd427,ecf3741a), -S(a8391b7a,3c3e788e,724e373d,821074ea,b1768e16,f3cf7b63,80a0f9b1,7a1b8fde,f9feb354,ca45cf5,fa10eeea,1b4f4936,2e4ab403,622cb470,26f529c4,69f61d59), -S(1b86c4d4,40532e3,968ddcd6,2012e455,34ba0045,82409c74,add1797a,fca29640,2217842d,fcf1d171,b18a57c7,1ed6d329,4491a422,45e93958,570fbf81,9e6bcb41), -S(65e2a22b,779056bb,6f7ee1cc,efd63066,e5cb594,a9496d6a,772c4e18,f2cc7d48,8adb10e4,e984b024,b420ae65,d2dbc7db,2c12b4b5,65b7b81a,434d16cf,52926238), -S(c5090c8e,ee079598,57b8bd0c,fae29cdc,e00fef57,49204908,cee6a5ab,1d4fd970,fd7d0324,fe41fd86,3b103e61,a391ee36,167af582,e07c2cd4,649d31b,86e6c976), -S(be9e98cc,c6a230a,3e63ae7b,f619d6e6,b27253a3,5f26648c,8c3f68b4,e193b24c,d32895af,d8886f1b,9aabedc6,9a79fb9d,ca71471a,97728ca,1a55e701,e7d5bcd9), -S(2ff0dd75,8de2de40,1ba00665,c251f6f9,e342265c,4a400684,ceef256e,7d6305a0,adb558ad,61769a42,3dfb2d3c,c44da3d0,15a2aba9,ebb4e29e,70fa7ae,6307f4d8), -S(5dd98c43,caea001f,75846c88,1a39fc77,cdae9882,62cac6db,f6160aba,f00c8d51,2cd50bad,48c1a136,9a37762f,e56fec65,8a8a3e36,90813d50,6dd94fb7,de90858b), -S(18280710,c4d14765,b473cbf1,567dbee7,d53a127e,2aee22d3,198dc5de,43c3745f,1c8e417d,83b0540f,fe800ec7,1937f855,a1066dd8,4f7f6a06,9722ef2,e2ab4bbc), -S(7f3fc319,62da2c5f,9e90a8f,308f69b8,d17497ef,7216a5c7,228ce9a4,1b35bbae,ff754dc7,ca0d3148,96b18f27,c516fbb9,d4d21cf8,48a61f0e,4bf3cd60,f3b1e7d), -S(96809ebf,3d08f713,87271a1,762c9d9c,17355ce1,be770361,e69506ff,f9bcc41d,412737a9,3b3d1835,cb487c78,909ccc46,624f8335,46eb168e,bd8c4408,44bdb4ab), -S(9308499,72dcf389,d1200b32,6a60b0be,72609de2,2a66989d,17c97f3c,e61f2769,fd307c40,3c29d78,14f7627,b7575ae6,40bb77f4,89272d91,4111e1a,2c81abc1), -S(a66a4d1d,1e2bf54d,b359db03,a339c40,4e0cf102,88dfa02c,da95c158,74057754,16d1cf4e,79d00675,cf6dea6,7d8b6c2e,baf59eac,cba2bfb8,e30ac368,ef875d5c), -S(4571f513,f3b73e0f,a7ca0801,30d6fc0d,ae8fe66a,3caee9ca,807177e4,40256f28,8849186b,79fa99cf,49674ed9,9010bcda,7e2458bd,bf259bf0,30a3b655,61b88842), -S(28609798,fa0a5b48,f19bc873,aa62da70,85c8b9c,271b348f,ada1ac16,a0013bcf,9716c9a,493d484d,f6c588c1,aca279be,327e59f5,92a04f5a,840bb7aa,34b407d9), -S(77b7e18,e37c4a78,721b28f5,1e6cab87,9c4149d2,92fe9675,fcc22df4,8dfd6465,179a09b5,2733b042,f702d649,4b2742a7,ef82d050,efe0992,4584d6e5,328b14cd), -S(3c25bbdd,cfa0ab2c,cce10476,79adcd9d,bb63595e,8a7bb841,cea608b6,82c71f5c,7a01946c,b0e650e4,53dce44b,eba509cb,fdafb57e,f130e4d3,facf9ebd,6d7886e), -S(c22b973b,99f9b4bc,90fc9e0d,b2d73c7a,7f1051a8,d19c474a,3bf9aa43,3b0fe52f,e0253dde,dea6cd0,1507b251,176562cb,7f73c22b,b7d10015,61fbd723,4d5eac80), -S(18c7f4a8,3f7dec0a,76dae14,3a49ecc2,4d5fd4e6,5880ac51,627c86aa,60a8ce71,978901f2,3d35e23c,36dd34d9,cae08290,641163a2,c55c3028,11fc4120,4a35653d), -S(61147763,8a8c8924,2fc31730,2e0b1475,514025f8,dff26b1a,eb4b7f28,51cfa5c,23152003,f2d12370,84ba60fc,bd653aba,37c6b20c,18c85c62,b6ee196e,2c684d5), -S(1f025444,17e67747,ab9f81b8,7a960663,ef3effb0,259d1795,f25c0a4,96847292,8d7ed884,5cd4cb73,27d31f87,ed6f881,a0de6f51,768a5ddc,b404139e,d064fb4a), -S(90493828,a1633ce5,8f962a78,2256d6e2,949f39da,9a865dca,d84b3e46,408d7b3,4c6bd158,92330e5d,1d97cf27,fc8e8fdd,99f39bbd,7ede306b,336530fb,2d46e51), -S(ce69b160,287b6724,8a11db83,418a302a,daab31a3,9c45b5a4,a02643fa,21918461,617286d3,c223891d,c86a2bc9,5727aee7,3016650d,cacd6692,c4e24a7,69b86701), -S(f20ad3bb,1b962fac,3d9b2c08,df726791,706b3006,60f894ae,379a6c02,77e3e8c5,fc83a778,44e35741,81dbaf95,de91240e,879ccd42,5c28a389,a01943d6,a954a5fe), -S(fb535599,ca57b6b3,94205071,f1c07afb,ace578b2,5d571bc3,1f669a8c,2345d7fd,b25fea48,f9f36d15,feb50f75,2bfa03a7,bfbbbd7a,8de04ba9,eb58d6f9,e4a77c1a), -S(c3793655,c789792d,e43a07f9,61d774d0,34253bdb,31c3428a,8e941731,6cfe5565,748af2bc,9459b7a9,cefee955,81d3716f,2c08d5ef,f988ef1e,85a14290,3fdd72dc), -S(34304c83,9c33334d,216d1b4c,4808d14a,f5952d45,9b8cc1dd,5e64c6d3,30807110,82a01c14,95639827,8c9a0189,5b0d1e62,572b1ce3,565ea53e,9afa8d27,36b17c75), -S(8100ba8d,43d8cf1a,53f973fc,544804c4,4c2e96b5,9a877496,7a7c4f57,862a0fd7,675c2c52,5de39794,2c42babe,8a3b8e65,1c1aba24,f2da644e,a359a0a0,892e983f), -S(b3f979e4,487081d1,44161dbe,37ef2da4,de16b9d2,aee1ca13,9f018e36,d4ee64c9,bcdfdbb3,e6cec91f,3dd41871,9fae4213,be273923,a8daf8bf,919c0145,11a93969), -S(df0ddb93,e54b94e9,cc7460ee,f14f3512,86bc8f0d,7b928a6,294f8ba4,2577910c,b640541e,b5958814,e348d634,faf04a02,3a38235b,2250eefe,3145bb40,64abecb6), -S(54a2cfcc,eefbd58d,3924f305,2bfdcce7,508e7d82,e82cf354,9a4f0141,52cb717b,17d80293,d00c0d82,47013168,24e6138d,1cc77672,7a05ddcb,909642b4,afb88578), -S(fd384aff,fa1398bc,1881dfa0,d8b72dfc,3f6a4429,52d301d1,53d8bf3,705b828b,78dcfb76,f958da03,dfd7f6be,21f36e7c,59c7effd,c4e9a305,b934e9da,2b30f684), -S(bc7325b3,181554db,1e19f120,b6bfbe0c,8e4c003a,461ac2b0,83269e23,12d3395c,c101647c,9e2ccdc7,7ad89913,699b3b42,5850e30d,e52995ba,7985f73b,db6700eb), -S(e9ed80e3,9ed744b2,1a9aaaca,1ef4959f,64ab312c,d7cce151,cc6e383e,dad0185,ab101dc0,af3ef33f,9f0d6bd7,4ab4e938,25e999e3,4730a9ea,4ee67b2f,4f0cc790), -S(8f63fb71,67716f8a,749439f8,25f2ef87,3c4e3d09,6bbe06ae,2aa8bee3,faad24ce,76d6652e,b0845f33,42b48ac0,8b2d70a3,9c601e79,fad31dd5,6701d729,1331a5ae), -S(8ed0dda7,5d3a1e9c,8a497ccc,aa3579fd,ca5f8628,239a01ab,30abebad,fc6b3476,6f4a70a4,54d8c0f1,4bad62b5,b9aca8ab,846c4bea,565870cd,28f2437f,907269c2), -S(7c2d0104,3735fa17,5deac20a,5997c20f,748baa84,75f7492e,d4889de1,f6666f2,236d1659,54504475,7677240,efee6bbc,559b64b5,96358ea7,5dd1598,f3e7fa6d), -S(d37272e9,a4bc1bac,edfb2131,2f66fa5e,dafc83fc,39ce55b5,66d7b395,9aa937da,111fb684,50913dee,2c6a1a0a,7d7092ae,8db98713,90a87a41,4ea52793,839d7492), -S(db8375b3,c8c574ca,a8d66487,13467abd,793f75ab,47daf5d8,67f9018f,901684f7,7b23db42,56ae1546,31e11cb1,37c091d2,3ea5ead4,32f2038b,27e46571,75526e3c), -S(d077223f,149956aa,1dfea1f,35f1b237,f59809a,8bb0e78a,f9bd9520,34867886,71fce205,bd0b6728,766da89b,55168777,b2dbd672,ed8b391e,97e74d25,2ad028a4), -S(1deed30f,7b7c1a02,eba5d86e,eb1e055,9c776d85,e264e842,8489264e,4f68c907,a2050287,d41e8218,9044b3b1,bd1e4c6c,3baabd0d,370d6f2a,d39676a3,ef4c672a), -S(ab0be6cf,57a6da4b,f6ba7963,aeabd62,d2aebba9,acbfffd7,a18e2579,c137752f,7d6c1113,7535c914,dc58a5bf,a53a82ee,8493ac83,cb1839fb,badc6fd0,4575b70d), -S(3c72f165,69ef77ef,a32347fd,d14e7ee4,82206c3,1fd9bb9f,367fb84b,9abb5d06,3f45f3b5,d08ab10e,1785f62b,20f2efcf,2a6b104b,cea583de,89c791c8,e2f732cd), -S(b0697da5,6030bd3a,ec311758,fbc0f56d,90544123,261eb75c,644b37c3,2f888601,50652a49,a3b7a325,67211693,197f136b,f38102a6,954dc6e3,c8325303,2378d6be), -S(906ec5ce,4273798a,9350a79e,8d64970b,3209033f,9f7c56bc,75e2b3b6,6003d338,a9a0a4cd,7c512984,ee4d1da0,13476077,80c664c9,8e0a416d,856dc7de,5923c702), -S(64b6c18b,d207619b,35f76f3c,f36b14,7f3dd79f,c0147536,25d7566a,c0350a7f,4226dcfe,f3af6ef3,40b883c,7d4bd1cc,f9ead936,d1d42a1f,59e9754c,23ce3b92), -S(b1d0d916,e6908910,1e5262e9,9ab94a46,e0a1db5,45b9c572,3dd79212,4afb34fe,be9d6c09,3c1adafb,5e8cfc25,5328a31,aa7daf65,74afd3c3,f5256ae5,33f67570), -S(55fa9d6a,d8005a2c,8889df76,6b3bacc4,dee487ca,e65a036a,9b1839b8,2a0c3c3,cfb17a06,2a9edcc7,88f5ddd8,a0f12211,c21877d,80c9f30d,cde71a8,af3c10c1), -S(c231d95b,6144337e,b25cb40c,65d6601,cb4426d4,b6d7c6f9,9bfaad11,611a1854,b0b1b6e2,4bc88bb7,a277a3f3,bfa74b9,9b1eb5fa,a16f4a7,e40f9ae7,629ebb65), -S(b6053327,960dbcdf,f13842eb,c50cf09b,d60cb656,3e1553a1,7f7985ef,7486afd5,7f195737,9ed11b9d,7ea08068,c6dbf3b4,36eac86d,2efb81b2,99f89854,65766266), -S(8ea8e96f,619bac9,c6805dd6,e8115858,50b80cf,1cd7fb59,e9090316,c9190de3,92a305a6,8a1300fb,64eff4c9,fa781270,2a85a71e,bbbc7910,a90eeb87,8b50036c), -S(cd8fe341,ce670725,22bb9043,f3e31f31,3bab3052,d1316da9,7e96bebe,710bdd8f,3a3e6072,295bebd1,7da2462c,8ad8cb3a,2c170c35,9d2b96ed,d805f0c7,fcbb4ae4), -S(3fae13ae,cc9b0b32,37d94c65,f769c57a,6265f37c,7057295c,dfbf9086,b27cb599,5baae4b3,eea7ac21,4372748f,d8b6b9f6,24755dcd,b92cb3aa,63a5ba6,16b88a97), -S(7b9399a9,49077156,b32b9cbb,7bfd9416,c6468838,c87971a0,d9e221ca,c8e4cb25,504b1b97,c7f32154,f2e5664b,8c180f96,a51783e,c041fd2d,1e8fe493,26ccadbd), -S(8ab4d5e7,e112d259,30e2b4e,7ff4cf77,b2957e10,fa9fae5e,a2f80940,8200e511,6d0328a8,69bb9ac0,71b6a4d2,939fd4ad,34066606,1c3ffeba,1500f831,8aceda6d), -S(87acd768,24a369d1,210fc798,69368ad7,fb01dafd,f5ead811,f5d03169,ba270d4d,8b9b706f,15ebb721,9654eb04,f846d1f4,49a6979d,53dd03a8,214fc285,c86baaff), -S(f8179003,b5a2ba0c,ae5e7c33,90f99da8,a1ee813c,c5ca0d10,c8b849c1,42ed6ca8,20710e6c,7ff5e563,36855a43,a372fd00,e7bc7f97,d7d0ecd0,f7a63641,a96b2c8d), -S(2a2b3fe7,d2c78d9c,3d62a9b9,202ea02d,e422f14,23e300fc,70cd66e5,ddf9e69e,ed122cc4,96eb517b,fcc5b393,8fc97001,194c3c92,f612d062,95ac6f5a,7d69ca3e), -S(aa80d414,e1f91e31,73483761,a8c34490,202ef4af,4b39e6c8,8726fc29,d6f99a39,7632d7d1,e312af35,7ad03c90,a5ef9476,cdd8541a,ec03a0a1,b02d8ef2,fa380245), -S(2e6f7aa9,193b67e8,c00703bf,d7ddea0c,199c857d,90d03571,2b41ab0,6b074d98,ee2dd743,952c47ea,e03653a9,22bc1965,6783beb1,76afef17,36bbe2b4,3af27827), -S(d3ec2365,4346428f,d38153d5,eb6f82b3,409baee4,4bdc1c6c,27b198d9,b9403d23,da15f943,6b0ec0cd,c4769650,8da28a12,32409c80,4484b395,40ca3beb,437104ea), -S(54500eb9,33d4fbc8,d8f96e3e,dbc93e47,a91b799b,510fe73,61a507f,95973a65,277be627,356c7342,56b97d1a,87f733e2,10531732,6eff535f,6ffecf48,ce635e9b), -S(b3543a2f,b3898a9f,64eb2863,7bb3a33a,82631cd8,d1e41b22,7ffb268a,d6710bb9,383187d1,bf8afbb5,dba13d77,25327d40,5c363bf3,f8e4a13c,1e259b16,c7dd8e3e), -S(7614313a,176d1ddc,c28147e8,39d54d78,5a3f42e0,5d7d436a,3be2c1f6,b7ff3606,d540b46c,d87f555d,fa8dc374,8f1c997b,5d4c1c52,1675bb7c,4e3a2d15,8c1e70e5), -S(de1c503,447eae30,e3fb1ea,bcfd108a,cbfab506,d52bc997,b1c124f5,b610af17,3b7d0b8d,e4e1de4d,c17c00e,ac0727bf,f41b0730,2080ea3c,9c18bf85,9608423a), -S(47f2fee0,8bffc7fe,5e7fb417,70ea71c6,9a30308b,cea4ebc,6b2861bb,8aa94a41,31659afe,6a09292,da939f3a,fc89e4fb,3fd2f288,7b6efd49,ef1df90c,a48d6e3a), -S(824c2c6a,f7b9f3ff,a1dcb278,ae2bb3d4,d7112ae1,cb66d524,85c49cce,35382572,dd548e84,3ac82ee5,9004320a,db9f728b,dfa0bfa8,5544e55a,fe8518f4,a9350006), -S(af4482f1,1157be70,14eb09fc,80bc1857,43ee62bd,376f7df9,f7507df2,34f6881,ed2202dc,182c188,3dd864ee,77b51deb,f8d048d5,79993a77,3fec978b,c880fe6a), -S(386c5a63,2e56795,54c53c2f,824bdd3a,c8c22364,612efef5,13942da3,cb8cfef5,dfbc9df9,f1666b9c,54f02eef,d482e71e,c33aff7,3d8c1025,7ab17b19,57489127), -S(5cacf202,1b442903,333796b7,d9d1a8c0,a8a26b00,2ab5cb3a,b6c7a5cb,87ea778e,e522602e,41b4b90a,cd6c121,4959990a,d77f3f9b,87862949,2c4119b8,54e31cae), -S(3a783ed,2357399e,8cd3c67a,a2e1f321,9900f6af,368080a6,7f18f6fb,c5442e65,d23403f1,474ec6ac,5071d084,2a05a58f,826e4418,c19451b2,b60ba182,777290c2), -S(fb6d745f,a0bbb00e,f92026a9,f216d470,9090649d,5e761f37,6e4dd81e,51c84954,39cb6685,c0001c34,1d1d5523,55bfbf94,5a97446c,593e0518,baf039c2,368be918), -S(12d8154c,ed08bba9,d6be85ad,42305603,74c82c2d,bc06d80a,2199d3ca,e113eb96,90cb6ad,3b62fcdf,d0d2f3ee,9e89f7d8,cc314d6a,bb22025a,876f4001,21a3b4a5), -S(313583fd,66ee564,f546350f,22ab1324,fbba2319,ef69cc81,6c4e9e0,26b3367,dcda990f,b4f2de57,72d6fa51,36da8215,f66d189e,dc91a46d,d50ee2c2,3398d21b), -S(d27b50d5,30a6a777,3e81ea25,77682a21,a6055afc,4bf05d1e,f0c1e5ed,a432b6da,f2a125b1,abfbd478,74b1b1f9,5d03ac5f,24610d34,d8b2ca9b,90b30c63,33dc9214), -S(d78933bb,d228b9ba,9332a511,a6d4741e,a42ca4fb,2b79b6e7,1d4f34ed,66a57e5a,61520901,c37fe630,35a0a80f,86e63939,133ec632,41f3daed,e30af5ac,2f470778), -S(a737c959,b9f386eb,e227f5aa,6cd83868,7a911290,e8ecb6e8,d24a3f18,a1171965,6648f272,322bc673,f8d4b877,aedf25b7,dbd2bcf6,bcbf3fac,ebdcf2c9,a531b149), -S(9c2033cb,d00de2ca,f6a6280a,fbb615ca,f0513816,aa12d994,e0ec0c01,37b5025f,1efcb986,dd4d223a,1fc4a7be,58bc6f3a,76b02646,c23a0c7,7f174a06,c75928d7), -S(75b51376,1d2555ab,87027458,d6302f77,26434e84,ff7bb7f2,43b5a6a,7afde413,de0d1bfe,37af2be3,302fa887,ea87a678,264534e9,c065df8,b1f3e326,a47fcf4a), -S(79fc6858,8d117c83,8a8b8134,c8071d33,2245e6b3,6107e1d6,503c3436,cb00dc8d,78d45ba9,69490bc8,7ff05b6f,2e6f8be2,8700216b,db76b74f,dbf4577b,f6169914), -S(de006398,1d8914c5,8702699e,40486195,a6647110,2b6576b0,6879b41a,207b6bee,22ac0aef,4a565e1,f159f6cd,5e04c68a,22e80d1f,f946aea4,f5127fd5,8707dc78), -S(db714e6b,52d32de8,43cd649c,a39307e6,540c048b,e0542b19,cefad32c,a9b435ef,d1ea87b3,ab9acebf,3573625d,b2f58a73,fb3864ac,369ca451,49a42262,b1915101), -S(25fa0fb5,af46c0bc,75b4fe67,fdd53d51,2303219b,38448403,186c23d9,7f7b6242,45985834,a9766f8d,9ea9dc82,3e6d55c0,75393446,f38e3e39,9b2b7b9,d6b34f6f), -S(acaac641,852406f7,69e19429,b1820703,fcedb664,407a5cce,8d96c779,c1e51edc,1bcbb918,88be19aa,4f02c320,4f18effa,cfc9c376,ac3dde0f,a529123,7f715cb4), -S(3674eede,62af1a60,77df180e,260a2d02,db43b440,b1e7ac3c,4ff368d9,8c3d8ed2,d0a393d4,7f953a8,fad2e045,91c62914,14b7ef2,694cebee,6a1c84c1,b8e19888), -S(f630a661,e54045aa,54a86a9,386e0466,a7428967,43d483ee,72a87d5e,34b255d,4ae7305a,be851491,83b7dd6b,f9faa5a3,8c2812dc,96475a3,87906759,85feefa2), -S(6b191486,9e262afc,51a94712,72b4765,78337a00,3556aa96,52acb8dd,36f1b3d0,853d994f,f728cf33,85990b39,d8736d28,faa0e8b8,c8b7c5f1,693363fb,6c842ebd), -S(c9fdccb5,be931d35,5e3e4baa,816d6cfa,7af441f,2d6b653f,d0fc90bd,c7afc681,d2d0190e,c3360886,b2b3d3b0,d8e05211,84c8fa05,b912a105,374325d3,75548908), -S(5e16743,c976a908,fdf3bd1d,46735de9,f3446673,4af3bd3e,fc6382f0,d834b500,3a8b87d8,28d99eeb,351186aa,23b76376,682ab598,165d7f4a,1c40d8ec,62840a3c), -S(67858166,15c4c7d2,f1f2da88,1aec2147,d51ae770,ff2c7afe,e007e4ce,a4faf4b7,74404a26,5f0d41e4,6e1f3bdd,929f26c1,f80b229a,18d0d3d1,68e936ac,e3447266), -S(add083aa,fb71a217,6ef2b08e,8bd713da,27c5cef8,958f47e6,f90dfb6d,1c1bf122,b835f39f,27e27cf,28f45ceb,7c26cd60,691a89f8,650dff32,44374957,c412accc), -S(5b0c33c3,b669dafd,74c876f1,72357a12,8117c8b6,59dae930,fe2310f4,f96a5d2b,6aa36784,3a973f6b,6a03faa4,b1226950,f348b6fe,e19f1c48,f4dbcb6c,3a141618), -S(5ad43f2,62f9125b,55a419bf,e6ff2a04,4b09460f,fe6f1a26,d8ab6127,33d50301,701ee81,dfea7250,fab2f190,63df6120,ce47500c,debf7371,49772e84,cc53d54a), -S(8b78adfa,af8d7d08,d1c24e36,1623da1c,659dcf91,dc51922,2e689267,7277c05d,3a0cfce1,3c25700a,9b255606,f8123a00,ffbdc3f6,8eb3fa88,cfd3b478,e4ed0fc2), -S(679bd899,2dff3884,dc680a96,134290e9,3c66029b,922706e,54f3827a,383a9e17,2a70a1b1,948a3c01,f5b9e98d,54069cf9,b5a7dfe0,d7ce12cb,731b1fa,83a8d54a), -S(6b82fe,fee6d419,b66b29e1,88954e32,6c426a92,bb539779,1bf562f2,e06fa73f,918f66f0,10980d3e,b3d62bca,d37074aa,766bd449,cb07ac04,5ec1aa25,36b258bc), -S(a2174424,8125296,680f8187,493e18cf,41501fea,2d4de1c8,25b048c1,5ef63cde,2cc8623a,42f2c485,7832e98f,a0830c33,7b873166,7ec7d7d1,f560a0d,f2f35b36), -S(e5c0134b,90cf3791,28515ea7,4a1a8be1,1f35c98a,74322879,e6144f0c,7c74ca2d,2e6b7b85,ce459368,cb2e0cb3,a3291d2d,8f1fc947,2df3111,87ee6832,3477d908), -S(d44c099f,3388ffa5,6dbd0761,814cc46e,c0f0950a,869a4fcb,af3c0022,f3bf3618,a93be4ea,b5e7b6e1,b3085f3,85e348c6,aaefff99,2c6385d3,c6b941a5,306f3940), -S(85c3c19a,33794fae,f400eaba,ddb4f122,64888604,ad1096e3,8864a304,e2c07ec2,9100190,4f8c0961,50d300e7,897caf49,c3869abd,ca59c78b,504a78b,cc313d46), -S(8398d41a,77875b8d,ed646346,c5d24772,d1b13891,98c1a196,c6247c87,c7d7b8b7,4fdba1b5,9a2455e7,5fd6a3ef,83def66e,74361e5a,7a4e5143,7e4b198f,329db7aa), -S(eaa31564,d148b856,be888987,4f4b7442,38fb849d,988bfcc2,acee61a6,adedb93b,408065a,a219f9ff,395bf932,9b172642,181495f8,43900489,9423ebad,3dfd0382), -S(d2c6b904,a0ab1acc,a12e5e1,3e794364,cc7d3c25,b53b7bde,812fe296,6fb23626,85a2ee1,df9d42cc,f44e327d,62369563,74fe8e73,c32ba9bd,153d833d,6af8cff7), -S(f00854d7,742141b8,34d0c2fc,76b73993,a9f92f1f,256b1865,e9863989,cc5bab82,3346d28,63813a88,f874c5af,eabb768f,a5621abf,c57a9002,965a597e,1f7632bd), -S(207635fc,7364852d,15a13254,9f21196,262a1535,bf6782dc,3ff2dab3,e429f9b6,ffbab84f,ec05fc12,63c6083c,7192f825,987b6f4f,a1a9ec5b,e01e1374,652700c4), -S(3cb8abfd,a8a5556,15252acb,c538f91,a8dd2523,a3ef5805,23367641,904b0fd3,9715d371,20f86a86,b98980bf,4c9fbed0,cfdc2e8c,fa86d60e,9d35222d,dbbee8e8), -S(8dccc315,1f8cba9e,384cd23c,c941a3ba,5a11be94,3af2000b,18127932,9f276291,6de7b0a9,49487cb8,6adad7e9,bfb0df97,30f460e8,ad19dccb,7b7e9a79,57fc48b4), -S(4f0780b5,137b113b,b843e566,9bf5dc39,cfe82b2,d6f61d4a,76555b56,9c93cb6,14de9aa8,8e7d9cd7,61f7d08f,41c4c92,f57f6a7,266e878c,cf407bea,11b9719f), -S(d2005b24,71e3e622,1ca597ff,9b0a59b,7eeb558f,5103a39f,630f7a45,85500810,1bf3440a,477786ec,27dad5b4,5d219403,9cefd000,802d0419,df34eb32,cdda121d), -S(4b4d17f5,c1f6b85b,60a1e1e1,a9d1ebbc,dcdeb1a6,3d076dff,541950bc,23c347d1,f8ffeeec,e591cb04,21f97aa4,f016b59d,610fda19,34470b9c,67248011,8f07332c), -S(a4d4b2c,5cc168b0,a24f2b25,4710ebf0,d5f70a4d,569a966a,cb8e1f5,2c2b7beb,f2307744,f8634646,19723122,71c7275e,2a2ffa6a,3a227294,122c8786,b6941609), -S(2fd89831,52c10fd,faaab8e5,dfdcd737,b13a394f,4c924adb,b8aee90f,2bf5d1a1,89f91750,69d4f115,d3e3cb99,4f1c298b,9de9f312,74d18976,65238a84,dd5f92b1), -S(2b66ac34,a669780c,d779423c,17e7a26f,f19cef5c,49919fc3,76255ddb,62c5e2ca,13b2ef7e,c4fb5fc,93fa016f,381dea3b,cbaa9c90,193b3c96,c1a3d86f,e2bef8c9), -S(1a1dbca8,b710565b,152f3886,e4793f37,36095569,2e782f1d,3ea662bf,87305c27,5af8c42f,99d74980,baae2dac,a58c2d05,718a0abc,ce40ab54,565e7452,69d7f0dd), -S(5c85b30c,d201e36b,c6c9d70e,da01a999,3a4f24c8,ea0e03f8,226eae2c,877538df,15ed51d7,85ebe78a,bd000285,b64685e7,98bfa397,40ae17b7,f1ddba98,a90ed521), -S(dc5a2996,fcbf99df,257b14f0,658725ec,184f3411,9271fe9b,9da19708,6aa487de,45ca8e07,e82cd9de,8dbbe106,1ade8c62,846cdbcf,85ed5b13,e51d1680,4b1e3a0), -S(ebcb525c,747d5ed8,d877f3e0,a632fd7b,88f7f894,84e16ddf,6cd8ef6b,f5925dcb,64a4b31f,50fb389f,cc92640d,c7aabfa4,189e46dd,15e7308c,8d7c551f,789aa33d), -S(a63c01fd,826ef945,43243395,2344af73,9bc5ea53,3b5e2e6c,2fe64b76,58f89238,867fcca3,7e861b09,4ef2f151,75ac0101,36cead9f,67b00d09,a50a94ad,453a1d69), -S(fbf5906e,e1e05f1b,850cfa93,34b3b230,391fcf13,94791696,fc63d6b0,71c29c58,61290a35,410dbe52,f64b4b4f,a5dba1a3,23c98bdd,f6dd7957,383bf40e,ece088ac), -S(b9d3198d,ed13334e,1d43b7a,e909713d,af368d88,a62db5b4,1552ad31,7325e249,4ce0e6b,72358d03,4375c5d4,633ee51c,ff9e453a,4ad7e88,9dde7d51,83adfee1), -S(b928d409,365d80a8,e7b3e61b,1cc2976d,c1db6158,a31be035,d1e9a8a8,66e976fc,ba4ef615,81b4f698,f653dddf,5956fd95,f6a55cc2,618c0d39,c3c789f4,61be8e7c), -S(1b4fcf81,5be7ac87,60582a9b,39b62317,4c72e043,48dc6f17,caa6fb5c,9dd46d1e,c845031a,df207d9e,3e006d11,880f5c82,50d225ca,8dd4d3c7,ed0ab170,5bea9b4e), -S(7f33cba5,c5391f36,b5d1f186,50220df5,cb79ee4e,cd1ef5b8,2b2d8280,394b7d68,91025af3,68487978,1d88dd42,f4746c5f,7cda4733,141c003f,ee4fb1fd,8523141b), -S(986de6,fbcab206,264c34ad,c38a397a,384bc794,b03e57c4,e3f0d253,fc94c3a0,b148492,16a7623d,d23d76f3,9cd22603,a88f81f0,a2351dbe,b825d1c1,6d46ad81), -S(f9d3cb99,a0ace3dd,65eb373d,24b3c05e,eb995a5b,65891ef1,3dcac23c,4784f224,3f94c6cc,95fd7fe,63c97138,90c031dc,c9361fc0,6ec5caf8,2e392c1d,b6fa6058), -S(44b5b53c,9da33493,bf040994,d195f45d,c9be8284,4d12315,4b782a98,b45383fd,7dc44fd,ff6acc88,9536ff19,4d28d892,d1e1fe0d,5d59860e,b58e6283,88a0fe8), -S(90db2c94,39ec0476,576de7fc,e6efd4d9,4cdc5052,56cf030d,ccba218a,3b3037fc,3f243dd4,4b9e8733,1548c213,9728de99,b520d31c,876dcc8d,ddb218e0,835e7f8a), -S(2369f76c,240f538e,ea7fe150,3c753bd,b41f031,5f703d3f,236745b7,ffa1f7ce,df31a9d0,dbda6762,ba904f41,3f46ce84,419a6734,56c6013b,939050b6,5d4bd15d), -S(67ded26c,dd7da1e6,d8373706,7adffda3,3d9fea3,8a7bfb87,5ba7d6f5,96ba65e5,73c5c136,d53162fe,35e5a3de,4190a79e,cc181f23,b5367ba,7d237903,890f540c), -S(3bebf79c,fa918ec9,2fda707f,800af057,13fe0ec3,efc1edbf,b9fd5917,1bee00e9,39783b0,bcae56a0,33e73001,e1fb24c8,c708c74a,fcb42664,53962973,d361f8b), -S(31cf34dd,edfeb1d9,674a2de5,11d7177f,e054181,34da2b0e,dd955c52,67eb605,659dd41,89c1c195,6dd21c44,bb37c910,df2ee864,aa5a2a61,a08a9349,34ccf9b0), -S(86439b3c,3d830a79,1f5cdde0,35821955,2eb0772,f5323278,b8baea2d,5afdec0e,8e5b5552,e244a208,6d5fc389,4965e367,77395e4c,d88b0c6c,ed513dbb,58836e0d), -S(a7041438,d237f957,cd3423d4,70bf34fc,152d1823,c389e5d1,d700a5b6,34101b4,aef966f8,c9acd2f1,625bfd1a,712d135d,c8e0f270,3fde3ee0,3c6d274b,101c26c9), -S(8c29a32b,b154eebb,a17eea82,9605b681,4f728f1e,7be0053f,139f6599,d2a6b023,a9813842,6c2ad3fc,e157de97,69caf8cb,f2db0618,b5f307c,200414c8,2fb4608c), -S(ede37b46,82448954,d786bbb4,874a61d8,dfd38de4,a7968876,c0585cfd,95ee04ce,3b9bb92f,a8e8b6ed,b30cd1cc,5225a80a,53fe738c,cbf6c2fb,4afdd6ac,7a10cf53), -S(e5cb4478,e91d2fd6,26950da6,53445dcb,5d591ea7,5915e637,3d82f963,f3ea6a2e,dda0bf97,cba5a77a,3051a09c,7d29f91a,3b8b1b3,c1649ef5,23c692ba,18cc8906), -S(e85f3a7e,cfbefff0,f3ad866b,3838208b,81d8c4e1,dd2fc809,8149f56d,e4c90aec,732a7905,ff3ffe33,d05738b6,1e6c0f57,4c1eccf8,e883a75c,76e50079,b00a9799), -S(79029c02,c2b0322f,2bf76cac,4b5f8356,4ea652c9,3ffeac8f,7f7882b,e772cb80,3e630bc3,cbf85752,f90b6312,4b9bebfa,612337d5,efc8a0a3,157dc666,27020f62), -S(9b827836,a74cdfe2,3dd8adba,542e13a5,c8e413a,cbe32695,b77fb140,8ce640b3,66e4c425,7d99f9cf,d9d6a18c,fd40e7c3,9fd37363,b0228206,f3ecb699,d6b2f2be), -S(bba7b2b7,facbfe34,b945ac0b,9d609b0f,3f0adbc3,eecf16ca,ac54484,dd564c6a,3619817a,1304fe3c,48272292,5d911d7c,ca33980a,33ddf647,19eb63e4,b7a1e6ce), -S(579c9681,cc98eda3,684b5d4,7f1ee3c4,5f8e7ace,c620509b,56f9e116,4bc905a8,48bc6bf5,90bc2d33,937df32e,a082102a,2f19a6cf,6ebf0985,6acc53cd,b2933d37), -S(23b30759,4b171e8f,ff9de455,f5eea514,e4c49e82,6ce3bbf7,6d3e750d,94c4fb8a,df57c655,45cac843,6db4dfba,abfac03e,a0489ead,6fe4dcbd,d12c2d2,21d8df8b), -S(8b4de9d4,f5c53178,aef16a7d,73429825,9e87e3e2,7a803197,98793d23,4c4c29da,a66d90c4,9d441721,3a399ac8,2c84baf2,67569201,3782a5ff,b2cf55a5,7deba029), -S(396fe929,2dbf359,ad3dfdb9,58e7337b,fe8791c4,d2ab6dbc,35d8c436,c30eea03,69fbad37,4fa06b57,9f67d8fb,48a6f09,99b77ba8,5fa7b6eb,96ce1028,44fc5371), -S(56acaed9,34f376d2,d036b7b4,7749829b,f7d32a78,bc6b419a,c25b33f6,808d94de,aae2c24d,8569060a,4398c5a5,a6173cd0,dcfa15e4,49642720,32785ff9,f0a7c164), -S(18ccd734,cfdeac35,1dbc13d7,2cd095a0,49a7c6c,e3fd781c,ed552e71,5ce14b0c,79cbb2d0,82272c7b,9af52227,4354c2fd,80a4c2df,5b434bc8,4c1e99c,f45a1e61), -S(73f91ae9,f75ee99a,227785e6,7ee3e1f0,384fc259,6a95d8e3,2436ffed,17f81c6d,f410e115,f57f618f,225caab8,388c97c6,46a37aeb,f184bf2e,408bae0d,ab2d475f), -S(f0216cb6,e9868a3a,cc859cd2,fee969f,b35fccdb,1754ea51,52995dc2,1d9b318a,e3a9a102,719d8398,610498ef,b5dcbb0,27fb3509,af587b9c,2ab5b5f6,35e2ef1d), -S(8c92a0ec,935d03d7,5395de25,3c2c9e15,7026a8d0,ae59a2b1,16d175d7,f70a8b46,8a9b5351,f7a8a20a,e159fa6f,afd58419,bd0e9dc0,def54f15,aa12abfa,65eb73c5), -S(be3bdb59,6c9ec252,5d7c23bc,788ea0d2,7f4c51b0,69182cfe,c095a13a,20b650ed,932c016a,7f006ec8,b73a6d7c,1ad1f2b,ce72706e,bd7e8713,e8a8d093,3586c9bc), -S(24fe525b,362650cd,ed8dee61,7ab4fa69,b06ecac3,fbe31947,4dbd982c,52ad2260,d9c484a8,e7aa329d,136dcd4b,612e0768,3796dfc2,a544a237,73548b9,be96d555), -S(f3a2b68a,8d16b9b1,20067bc0,6ee2f0eb,bab70ac,d6abe6b5,b12ce933,edfb2ff,a3abec92,539974c2,c2217584,2b9ec9a,3bfd4b3a,21c64a6e,ac3f608f,6bfb45aa), -S(fc9a67fe,9cb9622e,a9f20b68,3b19f623,5e12ed25,4a1371b8,196e0629,e43eaaa2,8e3329ac,2191732a,45afe600,43c6c5fb,ce9283fe,695d4f3c,9035ea60,2ceab399), -S(c539c35c,9bf0bd06,af690154,88e4eebd,bb766ef4,737c176b,3bd412d0,f933554,caeddecf,f0fd023a,dfc17791,95f18c1e,bea4bc70,b98eb85,405d5739,d5871906), -S(15871ace,89c88dc9,1d1bf56a,eb4fba,8f0fdb6f,df107705,65ef33d6,345c8ce4,70577775,4dcb9ec3,4765ad82,2070a26c,53c5fc5b,d3a6d8c5,1fe9eb83,635bb9fc), -S(1087625f,6eeca00a,fb9f7bf5,f4b94515,2316693a,ec8fff6f,57217e6,38804398,24b6cd00,e9ad027b,386afca3,44bf48a4,ad587342,2d3d24a0,5eb17150,bdc1a929), -S(98d7bcbe,6aaf808e,3909c417,66e54495,236e1724,6372f821,ea07fd82,686c0d07,b911aaec,47b9e901,4c990d08,e094d124,d8fcff77,f594244c,899a736b,e0661d89), -S(865989f9,35c9b044,7ed36d43,90ee5bb8,6403ef0e,67c3fb9c,eca1f2a2,f7e170c0,533cc475,ed1df473,30a032f,1db8ea42,d6b0fcff,f53007fb,cd41cda5,cf06cc1e), -S(b67f49bd,f912c892,9b26c35f,bfe2535c,830e8e4d,6c62930a,aa8527c6,1ef9cf14,151ef7a9,c08909a7,5daa0d85,e593c7a9,501e492,dbc41800,bf03fcf3,5c12c427), -S(b1ed1735,9a5f07a2,568d9740,3bb402ed,b313bbec,7d037bb0,cbaa2ed3,eacbd50c,5635c19c,1932696d,577a7bbd,411cff9,81bb057e,10436fc,91000bed,b638afa1), -S(6d268375,ec82b57e,7f8499fc,bda8f952,ff6cb4ee,a0f7785b,a8ff6610,84963c71,6b019ac4,d809bf4,1ebd90f5,4d8de537,6171702d,da3e4e21,b2301014,87379b95), -S(8a17346a,c18e4d6e,677db3fe,5df942cc,ddc66882,e39002dc,5815ea02,1ca5c332,c457ecbb,add867b8,70b28f7e,b27bd804,812c362d,1e94d89d,741abe02,59990928), -S(4dbaef58,9616daa4,4a8f892a,e48ac0e5,135b7385,25178135,a233af40,fbe506,90df93c3,9badbe3b,6eb28cd0,8120df1a,442429ca,d8d80108,af4bbf19,2d37b9cb), -S(cb18b241,a5d1bd30,361bf7c2,beb4a14d,3909be2d,dc7c62,d44e35c2,298b5a96,3c0a09a5,d96cd4b2,a1d15a13,341d455f,c04e3008,87c4ea96,d8f71c7f,ed84cacd), -S(cc463ae6,a1114d8c,107f543a,ef50bb07,cfcb222a,de5920ca,58ccaa19,750eb90d,31b54fa1,d115415a,b7931343,a8143a7c,cf2877d3,3d3d1f44,464163b5,c61c77c5), -S(8a0c1391,777b772a,c90d4d50,6f0a398a,45b2fc65,331a67c9,dc39aecd,835bcee5,b8d2bc1b,21248b66,2acd6e9e,1ae802f5,34558837,7da057f7,ad732684,79e4720e), -S(6fc3ccb3,acdff113,69caa83f,e304303,4a9dd77d,fcfa6c25,876cd2cf,75a5d7fc,5d0d64fd,d8f23aa3,5a7b9601,fa6d6deb,bdba27c7,2f227cd6,c4d3889e,49b15379), -S(3b10fd6a,125c3a47,2315bdc5,9686cd80,5b221012,65726bb0,64c974e,e74b778f,20bf9e4,521abdaa,347fb4a,a98a70f,303842d8,4f3e04c6,92d798ee,be97313f), -S(cd78581,a4707b5b,710bb827,b3d9c1d1,ee4a595d,29f90d50,607e3970,620ef0c2,26f5320f,2b512c50,e773a94f,3efba18a,cf343c5d,553f9ffe,67b39cbb,7f0b8831), -S(9bfce83d,b9e2cc9,969d17aa,eba0e037,22cfdaa2,a4175180,ed8d8ce3,7a7deb5d,2d2cbbf3,fc83d702,2d39191f,42eb42a8,555c3884,21add05a,18bb4376,4652477), -S(124e59c,53bf8d0b,a4189a1c,5de61726,3f6739dd,323ba104,892b505e,d8248d31,92d050a6,3e83521c,4b08061d,aa635990,46d52c4e,67c014c,5e33d7d,a6e01942), -S(20948e19,7a26173a,44011c9e,41676cd,661acb99,45a9e4ca,c0dd42c4,6fea02e1,8138a593,be21c5c2,472a37f0,5f2e9151,31bf249e,c6128dff,d218307e,4b661d48), -S(50726fe5,fad5628b,441bbed8,5347af3e,506cc7d3,43d7f0cb,213d63a,aa54365c,47b065b3,280c1f8f,585e05c,dc9f8b28,73f79479,b95a1bd4,c0a80469,eba92c48), -S(fad9bfdf,550fc926,da189531,91111112,a4120e56,db459577,aeea7e13,c2073f2e,a87e89e3,8d49513b,23aec5cc,a251098e,c6216ae8,96257461,2a7b4e08,470d680c), -S(66fe56d1,7395a7b3,b016c8b0,e5cdafef,d9e652cb,526374e,1f7000ea,b956f33c,ccabda97,a6b6b288,54efefa1,ff17f621,88b7cbc7,c3d363b3,25c31235,ecd26292), -S(8273997,5b5cbb89,e4246a1d,6428bdfd,14cf068a,6394a31c,a5cad01e,de3f6da,54d7090a,afe68aee,95a2f829,9d324bcd,9a1c4e16,17370b1f,5b940cbe,845a5013), -S(dc038ef1,5db1cab5,25660c8c,11afd35f,9423d230,2bf5b002,5df30400,a84907b9,cff2179a,904e5f81,e996700d,e64a548f,6ebd7b06,bc12a6cd,2ed74af8,9cabad6e), -S(fd501f6d,fa76dfc5,8da70f14,32eb1053,a5f82fc2,70ed661b,fea83798,acf02483,c04b3038,c2f4916b,178cd919,e953853,77d7555a,a7e3695b,1cc8fe89,d5d001b5), -S(c33af33b,fd47af39,ff687775,aa5e6ead,430821bb,695ba499,e4433a2a,d6190ed4,18555539,664c445b,6d317892,1af772d,7ae10c15,62d1ddde,91f47b5e,a1d4898b), -S(3e1835b6,34c53347,5fd5b032,334dc281,97068930,fb7bdedb,f8988b64,acddd3dd,2fcb5d65,940e235b,f8e1de7b,6aedd7d0,d2061181,dfbcd049,85df1505,a8c61db2), -S(c3b0ff1c,6a0ea466,357ebb78,f9ad0335,2b964b19,8e30e1c7,5b37bfc9,87e0061c,3ddd3d1e,7d97ee9e,748637ea,d8ec4987,d06b1f11,cf9ee9bf,12e85965,8574a95c), -S(1b690634,fa027e38,cabd8f87,3733476e,4f8e4bb0,543c5f6b,88575103,b51f29b9,3fede999,23be0482,caeb15c6,c7f2a00b,92b92a97,e66f2db,2c5d76d9,aa58210c), -S(4f661a50,fed5fbb4,ef8a1888,f1fbd3a8,b35b38fa,91d8601,80a3a70f,17f4fa8e,80e5e5c,7d41736d,29f94284,ddf06611,2cbbd024,60723497,9540c1aa,26232e59), -S(4a251861,333df3be,7b5852a0,f8eed900,dc58d2a7,3cb6d2d7,d45ac506,55126096,7b0734e,be6edf25,b9b4845d,8a93b0be,4f9958e1,2be61a3d,1513dd71,1004361c), -S(ff1c9a62,10360484,6bf46453,246be39d,7f595da8,dc17c86f,8c441b28,64b99d6a,7f01a489,404fa78c,aca02b7,f12a654,5692c8f4,fb787e4c,6e18a9e5,8e1be696), -S(4df0bff,651a53e9,30f631a0,3b6c170,ecce67a3,f92ed930,79e92099,46994deb,c79c834,33a1e795,f4334535,67e122de,bc81c4d,ab48a11e,a64af4de,4c6ebcd4), -S(2dfcd43c,a0000881,15845e7c,966004ea,bd4c909d,fb725642,18bf28d2,d66610b0,6ea9912b,e3232c75,c25b8272,820db699,bad9c292,8d2fa03b,c37dadb5,75a78b1e), -S(2cc759bf,7caff909,4abb456f,f8cb214d,f9353f97,e4f802f0,879b7ded,69eab4db,76ef9968,553c505e,697e5981,1f85a6bb,4d41418c,4b3b5dda,a024d69e,3a2a66e5), -S(a72077e5,8d73d653,66cd0f70,fe79c8ed,e9ef34a1,3e03fa67,70ae3f99,3210403b,8638634,217b7929,f8bcdfe6,4a64c053,5cd1640b,cadd7a2c,e6c5b880,90de01a8), -S(9c598d95,41c3ef74,73c94eab,20021f56,11ce40a2,34936d66,3130f788,14136c47,49702707,51df2f9b,d41b1ccb,1ca90f65,1ee65f69,75262725,b6962c56,dcdf2c4d), -S(5704f6d6,463ed861,cb25dde,343beb26,6557e3d0,7ef35c9e,cc435efd,f880622b,6d605d31,402c9bd0,9360f2d1,1a4f7a36,ddb8ee7d,543932c3,d546162c,cb0e4660), -S(d47b07dd,58962226,fdd1ec80,4a484496,ae3dba3e,41e18f9b,8e48ff60,4b00d727,26e1094b,c62614ba,1aa4df72,f3486975,6b8eafc7,b04a3770,22865b3c,a52028c1), -S(3971f023,44b7b268,754180f4,fa30d0ed,6596d59c,eb806e0f,9186c9b5,54e62b09,1895d58a,c951971,39d03562,6676fdf,cc53dfc0,317d976e,b0afb990,cc1b91f), -S(4b2be90c,e3e3a804,c469fd40,57bcfff6,6e9a220e,713455f2,ce4ee3d3,3cfa73c0,c0e2b79a,cf348a04,6f301f71,bba98de3,b9d1d8d7,ee16937d,e11e49e3,67c3cfd2), -S(2138e37a,29bbb1ba,2f051d4c,984d36a0,7531aeef,63fea098,417db4bc,241a180f,2e243bd0,69c0f7e7,f7319bfd,bbac12de,e03cf686,c97eefa6,dd58f17,c747bab2), -S(bf7bdaf,15838ccb,21a9ac7,3fd8d2c6,2013a163,85b583c,4c458db7,f8ba787a,8481d283,c1c4bac9,87ddd181,b12a2e79,a60e51a,2323c981,efc7cf51,a1768168), -S(e000b589,51237195,b81ea4ec,a4cdcb3f,b509eb80,4322ac0b,69feda94,e78fdb1a,cb527a4a,39a9c03,3dc01d1,d4221deb,b89b1126,8594dc82,fa5faf80,e538783b), -S(dbb2947c,2602e2ad,19ae7079,b6b9fbdc,59bac7dd,1e865f8f,3c802ec9,ed951414,9f646e9a,9f069a54,c1f3e88d,e8fef48d,9c6860a1,afec56be,46ac8943,d83e3cbf), -S(40bab32e,d118cc1a,bda71e7c,828d1ca7,aac8087,b720766c,409f4d78,e711dda9,ea7cd00e,c553e8c,56c9f992,b16a9830,a4ac30e5,cdae357b,148bb413,9e2b1d3e), -S(b2860f17,55e3341,eb6bbf11,a043b6bc,bf70472f,26b2d276,e9c30516,9c478b9a,bf7cc672,94909583,ac6147f6,2c9a3a64,8249513a,9f5c42eb,d0701bba,24b9b1d3), -S(d6e4a042,7f254b5,f2449539,9d6c0ed3,a741022f,f7fcf819,8a7ac04a,3e0183d6,ab1127d5,17900200,4cce6a56,7dc4b9a9,c88518c6,a8e03d4e,daabad76,f86c7be0), -S(57c70171,aaae00e5,e98dee16,e0d74df,82b05fda,8a01db96,67ce4d8c,ddfa9aa9,f4306dc3,1b82356d,8875244d,a713b6da,9fcc95cd,6c861ac1,1df62e6f,c6469e32), -S(e95ec894,230825f3,83442633,8cfef200,69ecfeb1,41c4bfc6,d0d6f2dd,216f36ad,e1f9012d,ec6f62bf,a1b5df85,c4ce2572,bd5ffb4,b8bd28d8,bf982833,e2d50eb3), -S(99d32dde,ddeec538,c8189f02,40bb4d44,cfbee72f,b3d42f9d,319dd7b6,97481451,75d2e691,ca7706e2,9d8c3686,d3fb1ca1,5a505a11,7662a2ed,347fc0a1,8531ab77), -S(be2418b9,b2c44233,b4d97d43,87085579,9219604b,f1a689fa,54523d2a,85677b93,69046a2b,8c329e27,cbbf7b9,d31f2009,9f5aa01,fd0b3905,988f2299,1d73fe99), -S(a88ef29a,67ddd120,c5d43d52,9d270c64,16750835,84a5dcc7,2f05be84,7c3b9b3e,902b663,4466410e,fd0d2251,ae10edfe,72a85d32,6d6a638c,122d7160,49c6881b), -S(95ea7c70,c4d0afc7,b31826e,c6dda0e1,491181ae,8970cf24,b99a8f41,bd428b3e,6bbd0bdf,d884903c,63a2a1c,df73f6e0,6ed335ae,53c64cc5,fc775666,6d8a15ad), -S(3341585e,671b8891,2d0b2944,334649af,a0bdebce,cd445e40,6e416ffe,f2cdc88f,bb17510c,f427e741,5b36269f,c702fbc7,42e36c20,95b69fce,bd31b7ba,fec345d4), -S(34e362c3,7c2c7b59,c972eb54,ab315cd3,da472933,34a305c7,d35c754c,3a440045,5e5d2940,3119cbd0,685f1cb0,b1e446a8,ba9ad625,8234ea7c,8652f971,c53d1b44), -S(f8c6c1c6,16b8bb82,c8d77244,86e10cfa,105e9a01,675da3c9,8e3936ee,ee01cc69,dbbe7cff,73929f21,4bf4fbd8,aba3f18e,461c4855,a204a7f6,319ffcf4,2437fbc5), -S(f4f98cf5,2be30eae,fd2ab1a6,dbfdba9f,8676cc6c,8b32a6c8,a53b10ef,dddc3051,77fed97,782ade72,bd5e41e8,c4b376f6,fde76267,b0a0cc45,a56e3f0f,ce6b2f03), -S(8b642ee4,8487a3fd,2d983039,48cd523,6456f3c5,f9d8f4e6,4f0af631,96b47d8d,22ecdb21,2e8ac0db,bf74c4b3,685339d7,e417686e,1c5337e4,872db54e,aed524c4), -S(5f6923ee,efc718e3,25d22dc,445e04ad,dc460268,58349b42,528c0078,f2a725fb,4ead0dc7,e697cc39,35d46533,73a21016,1a00ed11,273c3ba6,9c5f45a1,a4f38198), -S(1da37bdc,abdce508,9dc3aa72,2c93fb5f,64dcaec7,759064f7,82926829,b91ee1fd,1ecbb28e,f4f4b980,d92db2d3,c78919c9,e762dd5a,ae449d58,7105d84e,41f686dd), -S(ff3be7a2,cb1cf4e9,7b276ef0,235a7eec,addee879,78147bea,120e8ae1,bf888cfe,10a7bae3,da012eea,89b0cea,8deb02ba,1515ec2b,e0b83d05,a4fc152a,8b6e8371), -S(1658579f,72067096,947817e8,e9c22574,8495eb1b,75bb3729,88d45b93,d90531fc,d4538ab,19420b47,3ee869c1,cd1fecbe,f1a8ce73,871a7195,2319bad6,2ae450c), -S(96edfb55,bdc70246,21e1b92c,d2e85b07,b0ba9244,adcb5dae,f82f7afa,a97956c2,3666a36,1c8d1b06,e053ba0c,4a76dc88,2e3fe10c,e741defd,48ebee6d,4877cbbb), -S(4b4d282e,853b581e,55ec4271,e78c2cb9,ebf1cab1,8c15bdc2,2cdb05f1,7f8e44ad,2be45bac,a3257d2d,ab1a5e66,216f421a,2339eea6,89123e15,2bf7b010,e349ee2c), -S(fa12b099,eef9acd5,4c1c6224,117bfb60,12d5a208,553ca232,e030056d,1a141e17,40ed149e,d62259f5,fc98142b,9753503,ab7e9736,5238d4ea,c80b6859,52bba875), -S(c6243386,53084c9d,7bbf3b74,39f0b21a,ad2e5233,17259d9d,af2de00,1d4605ad,3b5376e7,1f08cd2d,3d319056,94608618,960e73fc,d27625a4,92613667,caacf3a)}, -{S(9a1db7bf,53241ed1,df8d3ea0,f70c0b26,76b43ebc,bcb4622a,9704b0a,3067400a,e3638ad2,95740505,455b2e1e,d495c57a,54ed8e8f,c647a6b9,c69b7dd0,715cef52), -S(90bfdcaa,eda30aca,f86d6eab,82407089,3746efbd,62f4a400,86e0589a,f3ea5cc3,9400154,63e05bef,5a4e2c2b,8681a1aa,95042864,447c7bcc,5ba2576a,eae911b7), -S(4666582a,2265fc0,643b1f3e,d003ab1a,d4567a1c,239e82d7,15a8f6c8,23616100,d7efadc1,2e71ed16,cebcd191,f34a70cf,eee6a7b0,dfa87724,dea4e464,ce50c9bc), -S(a5338432,7502bcf1,4bb11dc0,33e544bb,7aec0e46,f40145c4,db65cc46,203d969e,b228140a,7f3fcf9d,fe400a28,90200ef2,6e5f3c78,989406cc,b9fd31e2,e9d54049), -S(d6da1a9c,c1d81eb,9dc9a048,9acb4b74,d119dd52,684f12d4,3fa6a74b,7130c43,6ca8ebef,39c08b97,761cdb6,dafd2143,55715bfe,e8ab8e12,e51bf1ed,6eeed696), -S(27249c84,e21154bd,90034fe0,c5c5c510,c6b90e32,1ba4aa98,ca34be19,c918fb5,60327ac,f3fd64d1,ab14fab6,afe20b42,cd493af7,1d3fd0a8,ec2d064a,ecefed86), -S(cf6fe5b8,cc605dce,97c1b586,e3eb5945,38c02888,43bbeada,65a6b2c1,c2d66d66,21f3d35d,69afd6fb,704d1f0e,1cc2f720,2852892b,afd431f5,8fe3c1,3df78c1f), -S(cb10e984,f228da46,2063ce84,3503b423,20898a8b,98795846,8438d88d,4f0344eb,5bcab6c0,5de27bec,714ec992,dcb2875,d53f3f6d,a5ad247c,c81e8093,504504e2), -S(58c2a274,ce1e7d49,5a1d7fb9,7ff21f88,9e6e5230,5453eade,4ffad95,36037bb9,82e4a06c,5f7a5dbc,5e30b43,dac01491,addaa6e5,8b1a33b2,c082b4b8,fb50072), -S(d59e4e8,47e98edb,a494a195,25d1ffa8,63b2c22d,2476b2d1,2d704c0a,b30a56a2,bc2296d9,53902891,4278647,fc755979,c8d5cb3,502ffedc,8f412cef,51245085), -S(bd7feae1,1c4f02e4,9b1b3697,9370f319,88227ebd,9f4a6711,62e70744,6e452cb1,84cb5bd,1ad0381a,c9eaca88,b50e27da,efffe65b,f16f6bde,50bdbfee,69d22e72), -S(4757cc99,f4010ebd,d2e8c24b,ce7e86ba,febc4175,3f1f3ea9,f7afe8b1,3b0e7070,4b5cb36,55e3f5b6,bce14af,62ca1ad4,97480431,3deca874,dd2f8580,730ab36d), -S(e673b505,1e2f3e1a,f28284e9,b32d0c9d,16e7918a,1b8a13b1,602444b8,875d3d4b,f17f068,d02dc75f,dea5ebff,549a2f86,f9598c93,4db7050,915dc965,830bcc1c), -S(63d23920,6855af5c,c8c7f9d5,4986513b,455ca801,e172937e,a93a98df,78f36679,f95c588a,ba4d4bfd,fdac3c8d,f8a7d14d,7800212b,504e3deb,9220bacd,69e12f2e), -S(e74fb7b5,202d5a24,37a982f3,5018450d,ffe2e238,cd4fe3c0,60ce38d,18fa18b6,4715c0a9,f58d9421,6c3535fe,d6140395,e302e18e,2df0a870,52cd05ac,db917ae2), -S(1929be94,197feeb5,ac631038,f07c7db8,ff2226d6,c1763d47,a45c9e5e,7719c60f,c7816c80,8fe129ef,9a5bb8c6,674495f9,3f1e711,133e3cb6,19dacef3,815826e1), -S(76a43955,8d625d34,8c5cb3a6,e2274b60,8c93f08,6a0a7aea,be1858e8,7c1c359c,9752d697,a67a1743,9b5c4359,76658df4,be1452ee,1d4e0645,597f59a1,c60b3618), -S(4a3c36c,6418b8ac,920004a,4f47bfa1,1807619b,9fa39030,95f1b0a5,d91f46c1,95668552,e63f7fea,cd2b09d4,9c49e2a3,2f2fb824,11c5b819,c0efd09b,d64f6b8d), -S(9c5a32f0,d1a0f2db,253d47d5,e7c44967,26bcc7d3,b61e3731,3bbe5fad,ccbf4625,232fee50,bfd72474,af4bb5f6,afff7eb7,17efef90,7579d0b7,38542e56,67e05de8), -S(672eadd1,652ec6b6,a0c37e3e,7c8f0d5,a51d6f40,fe7bb66d,b4fed735,2e066063,ee5ba376,b53e9238,efb76b38,2424c8ce,d3b0f91c,99da4a5,7c98b7eb,48e5b891), -S(f78a9f6b,77af560d,c42d7061,831270df,21a73ecd,a7bc19e5,bff6649c,414b45ca,9f9897db,a7ef70cb,f4ceb71c,2572c3c2,b89c9c0f,a18ebdad,fc413d34,5289776), -S(2fdc690b,b0fa8c76,416b7ab0,ed6fd336,af4eb887,f13d5b1c,f7aab941,a7f63690,ab602a5b,f8ae3e5d,9aeaade1,1d126154,2f38a881,d577daa8,fe89bb22,6352c6a9), -S(3e6d45fc,5d8a498,b31d95ea,acb33144,ebb45ddf,ca3fd8f8,b5b22f4c,9d57cb6,f7e817dc,b718028f,3b18691d,8b9a25e2,884954df,59141cc7,ed939e0b,94cdb2d3), -S(6bfab01c,caec1bc7,1c38fa8c,b62ae3fe,9a24ee90,f6af6206,3b12d9dd,e83db7f4,5fa5e4e4,9d5f9641,559636fc,35b60199,68097451,10bfda67,a27de3c4,6792eddd), -S(d0e37c85,88d9a4f6,f135156a,25a15af7,2835de73,53f7b4af,336df017,d69a7fc4,8b9d798d,3cb04f70,41ac72f1,38462cbd,533324e0,871230ed,c3a06ef0,f524e20), -S(3f2a406d,eef9506c,2432dbe4,cb2d0a6c,a794356b,7953abb0,1ea486a4,e5db86da,ba0e92ef,aa00c78e,6f854963,7d8cdb5c,30869636,2cd71113,a3cea5d,9b492210), -S(d8b41f1c,2d2eef01,2b994dc7,21ca505e,818ac75f,4a396750,3fa3fdb0,2cf56fce,293fa011,7d231d10,30daa322,94d74507,3f9cb4bd,297a2f81,c812735e,33dc13eb), -S(64a07ffa,80f69a36,19f29cda,d1dc1b41,d7d58d6a,83470353,1f8aeb3b,eae51d91,b9b83f0f,43349999,d8efd66b,695bffbb,f67d3817,808149da,23978cb9,b43ef652), -S(348c104a,9bede4ae,3fff9b86,15eaafe,440a1cc2,1ff484bd,b442ad84,86dca015,41820b57,f62d6668,ce7fb53,2f3d3a94,4ac47c22,ec302d69,f98f355d,ad9e79af), -S(29fa80b3,e0a7a062,678c4612,41fefd8e,95f8e02,14795ae0,2afe449,1cf58041,6e3ae72e,ed0db6ed,1398068e,79cbed22,791076f7,515d5383,8581957,a73761d1), -S(6ecd85c0,afd6c385,15d8ca8c,30d618f1,8963b70b,fe73531a,11444a85,35c4ef29,c3e0cf48,4522b927,c1615ac7,9943e94e,aacd0849,12cd7221,308aa14d,95f05021), -S(7602cb28,f9703b3d,e0bbdf84,5e4f9326,712582b5,1a0cd719,a6674343,af2d089f,5b026bc3,bae6db2a,86f6f970,1682d8f9,82363e02,4bb703a3,945d7e19,d0b9efd), -S(a59436c1,389b4c00,5e4534a0,c7ce00b0,56f72ddb,a2b920e8,896d3bdd,74b29723,36c401e5,df5f695b,959c0474,28c9366a,774f744c,a60dba69,4fa55d25,2a5afd9c), -S(55377738,4bd49ab8,21e96778,17e0e95e,b6b08aa2,92a5ed47,9eeeb607,a0f4e176,61257b61,744f2c95,2d80a9df,29e47bb9,ad933877,eea75922,a31acb83,ce7c478e), -S(ac7ac723,2ac8d976,8e34fe45,18f5fcb5,518ea1f3,37d5bd53,5d5df329,d20a5f4e,e2317908,50bc5a02,f14ffc6d,c3785319,c30e93a3,29304698,a136d6ab,957ed52f), -S(9e49dd3d,aa78f89,af09eb7a,a87cb01e,6b55245f,dbe5b5d8,4c43db0e,1b5d26a8,e0ea375c,dc5eab64,54d16b5c,ec1435d2,14b54dc0,51806c9b,e232c64b,9843812f), -S(3537f749,4c903cc5,f5842fdd,c28aa98b,973dcbf3,20e2da65,127e4b22,4c747f59,f9cfbc26,5666e24e,1a9996fc,389ee639,ca350fa1,7a2191bb,13a2de15,63ff24a4), -S(d7ff3397,7aae895c,48e262c,1c93a0fd,2ea94961,bf19f720,77978415,e0f8591,2d3f2397,1cffe0f1,74a3ab24,614f54bf,85f4c513,21cba826,de24b150,cf77abb8), -S(76336d96,8a54c4f0,365712d5,a34c60dd,ed6de6a9,f4883994,f4ce2331,126078ec,ce745d4,62ebd771,359309e4,ee03b19f,83db6e4d,5ce7fee4,f5e3033c,9bae1c7), -S(63b503a1,615b32ee,520657d5,d2354c66,6b7ba964,a5efad65,d5957c99,65bb6991,af4ed8fb,bbe3a6ff,ee38c670,688351e1,d4a4a45c,7d5b9d5a,ebbce84,9a4ee02e), -S(a562ffee,3f8e26b7,1b3bee24,2fe06199,a198f76b,8b98a8d1,d67e176,1dc070c0,ffbc04e2,c268c14a,1a0fef4,bfa32008,f38a21f,891df618,72fedd7b,5f2cc270), -S(5be4337,20a7b123,1a171a80,fb72b580,a7045724,20d10b9c,786cb0e6,2882044b,c592daff,38d12615,b6af0225,7f39cc28,1447e965,9daaf5d6,c45bd486,f140efa6), -S(86f7afa1,e672e5e0,f33b0346,fa6e3b0b,1087f85,1526271,2ec07e9,82b80843,e7425903,c36d44df,fcbd0d4c,1a272123,18463d3b,12aaf1d4,9174c4e,3777d32c), -S(74751604,d00ecf1c,a56ca92e,9ef64457,fc2f6abf,d067cc8e,b761e120,c0019c53,94fc0537,6f69a1be,f8cfe400,31078265,39d625d6,8ca5df8e,2829469e,d3729995), -S(8b6a6378,49ca68f9,27f0b6c1,e934892d,f100384c,5d902c12,feb4956b,44016e72,862e9458,3835340a,f7c4cb5f,9ce0c566,c1a42452,c4420be3,2ed88324,3f6d7cf6), -S(9812ea51,ff0268b2,f94063d6,ec285595,ee8351d6,b95bb35a,d6577ff4,79d9d18d,c4ab286b,2e9d9545,d1ea9b8d,6ca577f0,ec7479ae,97ffbfb3,27bd9084,8f3ebe9b), -S(4bc3c5b6,3e1a82bf,3ce44d48,25c82c65,8d5d69a8,a1e5b4a9,358ed443,f89cc7eb,4eb838e1,2eed6fb2,81d9de11,cfb5dad0,b08ae9be,f7c82d80,5f3c7a19,3d46b1b6), -S(e269b40d,e9dd3fa1,b5edbad5,83a90477,2421326d,61611b51,bfca9231,4afb2c3e,76633ec,7793b5e3,7b1c3bd7,981496a0,1b9cae51,2ce5d589,2b69c1f,a437931a), -S(7abe755d,9bdc8c37,e99d6917,e5d0dfb7,7e90102d,7c278af,e10c6f6d,74880322,fad617e,3612687e,d31b7597,2bc98e83,c7af5e9d,f4a6e12b,ca812f70,1c5a7a97), -S(8eb690bf,8c75a72f,e635bc55,ad05856c,9083a672,3577d776,2743b1d4,df0d88c2,7737abfa,76ea68e3,1482d3d6,95f1a7a8,ae4249ae,37c68c95,ae605814,6a288958), -S(d0413b90,c3426609,6ea9401c,8e41f0d8,37847c1a,47a47b3b,fd6ffe82,58d3b38d,38c1b369,1865a029,af58a847,4278fd49,9ea44686,7a8b4ef8,63b6dc96,c66e1a38), -S(1bf1b231,9468cab3,2011fffc,96f296bb,8bb64c69,47b590dd,d9d8edc8,ded3668d,1a87ff27,bbf79298,807dee37,bd488762,3a9b5c7f,c5d61e4f,d4de16c3,e7988c1e), -S(bfbadb48,ae5a2997,c368e44b,beffea6,b1682b01,f492c9c2,6bca3fcf,1a0e01f6,7fe11de5,4037bcf4,3418d062,d0bf0bd8,a7399f29,e65f5ecd,9f9e2693,dca6acbe), -S(c2d48434,f2fa7dff,d206ec93,5def03b6,ef2401df,c8c3a126,10f77d49,c14f239d,68e9c025,7483ec64,fe6ec6fe,1159d5c6,400c9d0a,397f0e08,9e92430b,51883316), -S(4af55e6e,f210442b,95a50aeb,51e87ee1,b2546337,664d3a33,9c12a655,2e3ac08e,4f81a92d,fc5c3e62,da712c72,cbccee05,da2e4cd5,6f901bed,a96f9b5c,5c5f9d48), -S(d89bf279,472e7b5e,6f41f460,3d348143,d15b1dd4,7bcef4c9,1274f9fe,9f868ced,cdd02079,9e9d91c3,8fef3631,12a3edc0,962bc718,b7f467b6,45f743e7,db1d66ea), -S(c7cd49a7,27c9e003,dea93f26,fb888cb3,770f5637,58d4f40d,ccb4e0df,d2d1ba1,85bc461b,7e583884,2d4e643d,91ad3179,30d9949b,b29fd94e,4090e6b3,3cf2772a), -S(e1cf9c4f,e0b525a1,290d8ec5,1a3cfb9f,6a78d2c,e817ec9a,a39a538,4f9619af,b6aa8225,d0ebf9c3,4aa0392,a81df722,c8d29cc1,f03abff2,cb7392ba,ac78f5bf), -S(4f628bae,d84bbf1d,fd568c23,10aa10e3,a098131d,65484a80,653b4eb4,ae59b970,e86292bd,cab0f1a,63ada7af,e350fee4,2dcbc618,6838123b,186974b4,16ff2a5a), -S(90b17b58,9674a91d,7c2c9443,61cf8adf,b47e733a,bc775b57,4838fd2,d40eeaad,72c69fe2,ba39f165,5ca31f41,7ccd004c,1eca2392,2973e47e,ffb423c3,5c9f54c), -S(1e13fed8,6aed242d,c543d2b6,9d3ffa88,c87731fc,c4f6ea48,fbdccace,b60ab263,9c1a66d4,47de8c53,2f740f38,af9a52c8,160890d9,5b573c09,9981297f,df8995b4), -S(fe036a4f,713794cf,c0cd3b66,b1a124d4,c6a5374f,810d11c1,30c16fe9,1d8e81aa,f7ff5760,544b9e87,489e3c76,addbca52,308b9155,a7848716,1dd8c1d3,f3c81816), -S(2f9a25b7,73b6cb87,56d1f4ed,691a4fb3,be7ea324,bede8c0a,b9446103,dbb96323,df92e84c,7b76c4b1,f55e77ec,d541ce34,963e9f5a,f4d68fcd,1685d060,c99dda22), -S(ff65bc77,a459bd32,21742391,6e2f9438,b6a38b71,c8c06d24,84cbcdac,ac0522d8,efbb8c9b,8ac9200d,71d4a944,4dc9050c,4661ff4e,fb0c953a,c1c1dcc6,2e44071a), -S(d0e325cf,775d47a0,532b46f8,4ec41698,82aba5fe,83c572a1,1bb18b9c,84edac13,2ceef205,c424441a,fee6879a,a577e1ea,423514ff,d95bc282,6e27b5dc,72f6ddc6), -S(27700ed2,bcdf8ba3,f5ee842,945d9473,9ead9ca3,7741f31,1fad3503,e052b8ba,69c780cb,d6f2c1f2,5104dc40,cdf07ec4,ee76478e,98732995,ca85b5d8,f070c8df), -S(205bfccd,37349c79,5077f5b1,16e63990,8703cb74,f2835302,44bbdcfc,fac24a98,edf25093,8cd87a81,b6f3da85,9129b399,a1971850,86bd63a9,1c370165,a22642a5), -S(a5f79343,8b402d23,6e9bc997,cd08557c,7f83a343,32528a19,c506e5ea,8045bded,9679de58,13c2c74,cd82315b,23b6819f,4981c6ef,f1a2ee00,af5efa4f,807f2b3b), -S(aa7da8ed,a97ac1e4,d2b2abe4,c8f727a2,5643c5ba,414ecf72,70a7bd65,612b1a53,83736a4,de5bae56,8d55de7d,6e2d4d6,eb5d9965,f08e08d6,dd6419e2,dc8d4057), -S(ee53a4e,1eefa289,af562927,9d58f02d,529663d0,8a290297,d7ea92c3,64f5d41c,aa0fbd01,727c227e,662fa63d,3d6a834,476e00e5,a96cdc97,d78c21f0,f3b2a83d), -S(8fc52dea,bd8b3e4c,fc6a2490,176b74f3,cfc55118,2d5134f7,1364a8c7,b083fdc4,1a8b2a23,d9119901,7e1de607,6ace873f,32bbb342,e93a9f82,ab1c3a29,18d603f5), -S(e0f5e5ca,6395d3d2,390eca9b,4bf50320,4c1062c6,82214c36,b1b0587c,cc0912c3,4eb1d022,b4971d9b,74244e8a,5565e021,b933b2f7,e8ea60d,fc259511,a7ee436f), -S(fd31a893,17476bc5,e278bac3,99eaaf6,1716586a,38410172,48170f7e,4d7821fe,190815b5,a2affc9b,1cb91237,783959ac,2058e75f,16cc2e7c,a825ab2f,8af9ba01), -S(1533bab4,eace4f70,74067a55,593498e5,59fa78ba,b74131bb,a2a97412,4e855be7,a04ff3b9,c6209ba3,69b19863,5cf8b4da,9b6a5a04,f90e29ec,9061a32d,f3ce6361), -S(8d549288,93390895,f1310e4d,a8b8ffd0,d9f8226a,b414180b,bb280370,93aa90df,fdafa930,f892b478,c7e6cbae,3f943615,ff08c2e5,64ff61c8,dcf19ddd,5c458081), -S(1b17a4c1,736fc761,f3091367,9ff22ae6,2ce76a6d,716e9b1b,c6cf28c7,cca59a03,9435ebc9,edb1a948,bc3493e3,e7434b81,cb671439,365843d8,819b4eb,786a191f), -S(3500c8cb,e37f659e,48e3b619,7007f250,9d964708,14c06977,a9861a89,eec11b52,8d5de084,b45912af,3ab8a8b1,47304a2c,45b839a6,41713563,f11dae45,2e5ed94e), -S(42def4ea,50df55dc,cdba6c04,ac2855d0,d706ef40,6ad56ded,50d49aac,3b41c049,9e354094,29b46cec,329d906c,9f9ae965,ac3adfac,251370f5,60b91550,4a7e114c), -S(b83c1c07,2087e92,11fc3302,fafb5be7,8fd4853f,9f8aecb9,5af83278,d488600,e51c2222,910c6d19,3baa56a3,63e330c6,390dcee2,c33ad00d,771fde6d,3bcdf973), -S(beb27e28,c59f5b87,d19b0274,51a51e58,f0d10402,e7343efc,d302437f,f9ea2004,ac188f43,c0d6b91,4525f6b3,5897d7e1,7a0543c2,3ccd8001,509f50d8,a95768de), -S(9408e5fc,877c5635,5a3339bd,3b9f7a8e,22a361b9,ee5e2f1a,a2b47eb4,cd665328,c51663b2,f9ad7dd9,6b120c25,2eb8493d,d68be9f4,ed4b688c,f5d2bde3,618658a2), -S(a4d0c5e2,9cf83c46,5a567288,e6c0573d,c7766450,d88ced27,cb036db,47ecc96f,ad00c513,63a3d265,1318ed9e,352be903,30febde9,7827d8ff,1b5b5bd3,281c0c38), -S(d38d0ec0,4d3819c9,665b42f6,24089402,e923a8f5,6e7567aa,bc12e5fe,c248722f,17e171c,5c6bbc7d,dd7caddb,652dfee8,720c319f,dad6b117,56596bd8,b554397a), -S(4fa66f5a,7c294bc2,a0fb7951,7e6310f3,217c2cc9,c712f6ad,c5042610,c29b7a26,8b79a582,b3d9acb5,5653642e,8b8c6f18,f17e0541,179c4d62,8a2976aa,3c760d1), -S(ec9def33,2bcc66f0,db0e6b3f,684fddc3,ff1a7ace,80c2adc8,82e4e5df,5ce77861,9ae3da13,563aface,d4988a5a,5b3a95b0,4b72be95,dd8ec898,f46fcb29,f43cae94), -S(90422949,23fc0bb2,3263ca1d,768919a9,846e8eed,4b595e56,2d5103b9,5a479795,7d8a7b46,e557e1c2,c621d49f,b8f382c3,1feccfbf,5cb8c755,1f02309e,bc5881d4), -S(9c926be9,68275386,95549bf,2cae2278,56410e3d,1e481cad,995c687b,e44bd1b1,56208afb,875c94cc,bcbb068f,f8ef6fe6,9615f1db,21c2b43b,59c8e80f,db5670e9), -S(8d7f3cd7,2a6912ed,f0fe9343,211cb3d4,20229f19,3e956ed6,9c4a45bf,c7cb84a7,a45a7fb5,d4e9c531,4defec11,ce95e054,1ef0575f,b6b7f299,72bbb008,c9c3c3c0), -S(a95eb316,bc91485d,9a220af0,a201378a,d0319bb3,473a0db6,e919b3b8,ff181952,41664555,3aea43ef,d7819025,acad34ec,6692f9b8,bf6a86a9,7de32f18,46de13cc), -S(8ffa8414,1e806ac3,df613a68,a8395111,93569368,6e2b11ef,a1d53493,34e8da55,5dc00c59,12cedd0d,4457e779,e82ba2ee,669f7fa5,75c42e1b,abc1aa7c,7cb1bb1d), -S(2f1645b9,7b58e33e,3dbaca4e,b4ee6fde,2245c,2c9bf124,46e262b3,434641fa,d3d0a603,6ded3010,319324f,34ae1e58,a6ac0b6b,9ea15b7c,3052b574,f0b2823d), -S(95232f86,d2d1482f,a6656256,3751c2a5,16e1a8a1,66988471,f6e0aa69,f1ecea2f,7f54837c,4633f938,c0ff4fba,e59b6e4d,1a7b336,83a1ec1e,fe1ece3b,a131662e), -S(676d2a29,50e66454,97e678da,68a5bb2b,126a8eeb,874fa8aa,ee3738a,cb7b3cc9,23fb14fb,674ca1bd,8ccb8248,48334f6d,4ba47d56,c7969cf1,fa3ab1d,78a22a2f), -S(91df7ef4,3ba5bf7a,11d8418,e553c5b6,d2031b89,c644d08d,88f1cec5,9d4007e8,e7b19092,f45b6d,7742d4e9,37d80d32,63ba2945,1fee1259,a13b5b1e,42072f7b), -S(1b64a5c3,e14d8fed,ac3c5eba,e6848e10,6c9db663,b18d48f2,b948be47,e8dc3b4f,55caac6b,18f294a5,f3dc9f44,ebb276f2,fbbb506c,1a28b0de,a55ad2d3,ac5eb8c7), -S(122f6415,3a73b8c1,f1c935a8,e99590ed,16ed9660,66816cb3,57049803,c7d7420b,f5bbe828,9693d573,7016fd9e,59cabef7,5eb7fae6,ec9614c5,3c47736a,f3276855), -S(745ed438,63d669e4,397bf391,14af880,f87334cd,62897aea,634b5c7e,cc6a074a,c5cb92e5,61812f7b,65930310,88b45373,b864b51c,18326532,b2eca5ac,8608f155), -S(4724facb,e60d62dc,da536967,a4650a19,1e582045,ea209834,f1989d0c,db8baad5,ad70a8b,ec1372b7,5e3aba6f,8c031d5b,ba540395,b610fbbd,7d5b6ad7,4e32a3b7), -S(a31bdf87,40d7a1c4,88f23ae5,9b54c976,56887201,6c307531,51ed5062,dd7613a8,e77b2633,af3e9b42,a2a05b45,a0f5c9ec,28f72387,2cb5bacb,ee5a8360,2aa282a5), -S(990e8453,81efaed1,8c3fda39,7d4ba832,d509851b,8503891c,c0ea0ae3,4f5f1f7a,339aef51,e4d4ff8e,49955166,4408c312,b943df2f,fa62becf,51cac7b7,eda7d8a4), -S(bfcc3e62,cfc9808f,bdceaa55,f75331b6,c9b1528d,455c33fc,9690d84a,d89f68f1,7b07149b,cf648a16,b3be662a,d203837d,fe5a2357,1154e65a,78841ae7,a906a7c1), -S(284b543b,5ad3aa4e,5a4ab274,9acf59d0,4045bbdc,1ad204af,3a7e841b,330c7ac8,43d50b60,d23281ff,1ce15241,80c05e53,e5fb5bc4,a4e0ead9,19a2add5,f55b10d2), -S(e4c147cf,beae087f,5c9aa83b,31514ffc,5734feba,cc743203,7a7a9931,4101bc7c,72ba3a91,3a2fa186,484bf856,ea93a725,5f6e3b1f,d5bb86e2,58e45e43,52073787), -S(54cbe831,a201fa88,a3e7ca1,aa409449,509269a9,1b229892,9e9f9dba,a7e8a8c7,60705c7d,ff74d8eb,1f85b9d1,d9efcc58,fe463e04,b19f56dc,a724dfbb,630661c8), -S(c8dc9e83,d4e4f250,5e8c16f0,a5e8de3d,1ea3711b,8a927a63,baa9bb33,6ff302c0,62211dac,15b97856,2dd71543,b63edca2,4868ef5c,6bc7e547,9fe81da2,261f6150), -S(4bdbd22d,5cb98e31,ddcd1e76,fb69ae02,1915be35,5fa326e8,506c38d7,3c93dd8b,9401c173,3bdd7728,fae5ddce,d708119f,b0cfdd41,2b3fe599,e75b5a8b,b84fbc55), -S(ce988332,84a3fbb4,31b716cb,3b6530ba,bb41785b,c7f0564a,8691289d,9d35e689,2d6d9b1a,7711c5a3,2ded418f,9b52c134,e822589a,789c2b33,648324be,508f4f14), -S(2815b2a6,ab505e2d,ad759c85,6aebc3e6,133826c6,d3939a6e,8795308,5adb6bcf,2e6764f1,f90c7ce,a03c5d8,a1465d26,fb2cd430,edf9f4ec,13ea71e0,51558b7d), -S(65380aca,14b90a7f,e6c6452c,c3d811ee,88128fcf,fa009d7c,1afb3195,8c3bd1cc,a73d691b,cde27cfb,dfe4180,e6a8d2d8,62615b1d,59ad3487,dc914045,39549ee6), -S(7bf3a1ed,4e7e876a,1404493b,7ba01911,b5707f09,f18694f0,fdc35e9c,27f1b89f,b6dfdc2e,e827967d,1d1218d8,975cea61,9a740521,a0e0b702,7df1ffff,dfe45572), -S(5f635ad5,952b3f2b,e341479d,239f4ed8,8c33ed63,87f62c4,40a02665,4e469aa1,a49b5262,32361560,c2105db9,3b500fa5,bfe3ef99,7efb826d,90781ad0,143fc0c1), -S(4a212245,8bc099fa,7792d0bc,a3d1d163,58fc391a,82dc7f47,2a457268,1be9ff8b,fbeb9575,6649a3af,923b28d6,788c8662,9b488166,23349b93,755d04ff,bdbccd97), -S(1b56d138,e71aa703,e2566a6a,6f0a29fc,e7a7b999,2c454248,5ab29c6c,eafc86d8,db7b41e9,217fd201,4f4e6ad7,818dfcce,31823069,d1e87ab,85bb5ccc,c870d476), -S(cf9dee0,3d9c1724,24ebc37a,1da32a19,bec78003,29def8e1,b7c44b5b,59e880b,20ce898c,1b9dbef4,f47c5b6f,be39a8cb,91bd244,b0df0bcf,94c01616,24ae24c3), -S(89458ec9,1bcac5d6,ba51b7dd,d32119c,eee5f535,5e368e22,3a35b9ed,b8bce2fc,33ebef56,190a0820,9e508e1f,6dd57a37,141cc7b7,ae8a3583,41da1ae7,24b40f0e), -S(bc1637f8,39b45eb7,66e7ede4,af989ce2,20ec795e,d8454ead,6053a392,18c6cf13,e64e7128,240d9c9b,4018c56a,bd71e9ef,30d7cd1,8a036ff6,13e4dc52,13e88b71), -S(212c6c8c,3e2d406d,4fab7bf1,4f7dee3b,a7820821,ecee711c,f63fa0cd,49341157,2c2caa21,7ae6176f,242ac6a,c951b628,5daa7dc8,ef35e996,12b7df6a,b7966006), -S(8ec5f69a,a77e4faa,a70d129b,685f996e,36d4591a,9f03a047,d853f81c,483a371a,69eb18df,9bc54f0,804f937e,4c88eeb3,a1e089fc,6fde0ddf,e37e2de7,892b8b1c), -S(d77dfe3e,6370e677,bc0442c4,4d71e7fb,fcf1b7a0,5a39831f,6c02daea,70eef37c,e5582098,dcc957cb,6308e51a,817c2764,1c34a3ae,4a1e931c,9e741c29,241df4a3), -S(95a98fb8,178ab7b0,45931f72,f9d3411c,3d6c9bfc,47b9db77,11dba796,6600d1f4,789034c9,fa371e65,e47e936d,d5be1c62,d660c12f,d7a0164d,1507b4b1,4d5a5d58), -S(dfb9170,5c2eda68,ebfe7b2a,f2c76eb0,c65fe431,d3a893d2,b202b004,bf532063,2842d35d,73985521,4dbf015a,a64fc5d4,5c763a0c,81be6302,ab16eb45,64e1c020), -S(ae011375,773a319c,12a49e8a,24f4a84a,70817591,d739c604,e76314ee,2466136a,fba7f0ee,758357ed,f296ec2b,b4d0f9e,6c38e29e,95daa163,f75c82ac,48988ba1), -S(e906d6fc,6930a06d,846d4804,f2affda5,955c0718,e920aa47,724a4903,d644d4d,abcddd9,fa93df1a,6c4aff95,a7ff30e0,8768bc94,5baff83f,1278dcc6,fb797ac), -S(39d6a839,e4ec9f30,7a4b150c,9c20f918,5626c93a,1a077cf1,b4259d9b,cac3eb5,2b0173df,699d9213,989b16bf,a17b0996,18eac71,b6f21611,e20cad8c,f9609c2a), -S(11541976,d8c7da9d,b9864344,a2a3ecea,499f538b,224e74c1,546dbb82,a343c308,692038e0,d63da9a8,c4c7b9b1,fc3384d7,d03e2dd9,156f90d7,68d31f64,eb46231b), -S(b8edf6b7,8b0ec547,9ee981dd,e7d8052f,7d613d32,a9677bf4,623c6695,515af54e,4e391006,443f4578,7951cf57,d47100de,7982d0df,cedf7c3,36193ed7,a7f986b), -S(dd4f1c04,c7f106f6,2d8f49b3,f96b919e,774cec1d,e470e670,1f72bbd3,2236d3f0,bb46966b,fa105ade,17aba7ee,a2c11e02,ace8524,1e3da1c2,4d30ad99,dc695175), -S(794d4cc7,aee8f9da,ac4ddc7a,bb4278ea,d8de11cc,c4dad583,45c3edb5,b9c7b2b4,d0024919,35a5f7ac,6ec9a6f6,85aa16e7,61329642,c002bb59,a9a9e135,63ef3688), -S(90dec6c9,97e0906a,fe63cf90,2b6a5a6b,ead0653a,6c9a8337,154eca0a,7e1fda8,3511f4a,49540228,3956e249,e9caa7c6,222c79cf,d91fcad5,c35b3737,931308bf), -S(dbe539ca,27d132f2,e602df51,6582c3a,9bda3a82,ce3b52d6,10f4bc45,17b52119,9f52a5dc,417ffa9d,2ccdf666,63ff60,8412460b,15adde93,a11ceb9d,4f859f37), -S(a3fb9a06,7f8a9364,87bd6b2f,eea9e072,6902c046,5bd3a9fb,5afb9cf2,8af34028,b3de3a34,76028531,192d614f,c720e0ee,e7765fa0,14dfe4a0,ce0ffb9,b32f123b), -S(47c00044,c66a8c7f,f6242613,17cc9950,438544f7,31398212,bfdbbfae,d2e34ed4,215f4709,e2bfec21,6990ddd4,d37a0c46,b2cb44f9,26d3523c,ea0a8b2d,7f949015), -S(b59b3f1c,cbb0cbdc,4e430788,f934f090,aa0e1047,24d8d1e8,b7329e4e,c1d6092a,f96cdb74,a7ece8e3,a9f631cf,7a740a2e,fc9c9020,8ee0a91f,42168990,d9a3cee0), -S(c4efffa5,92a27b03,a05686e5,8ce4cbe,d4768e15,64d30450,655b6d0f,5dc5911f,7f095e1a,9108c3fa,a1b1043a,ce870f98,264916b6,f8643370,4d36da78,deb9d826), -S(df9f6d4f,e169d748,5c09f5ad,a2eb46b,be5bb378,919291d9,e3f60ac3,2644b6cc,7566af91,e7c37fdd,72b68418,e6ed1929,c17517bb,bc8666f0,d5e28eff,4d50ba54), -S(bf3d3814,11130a19,23ae0b6d,f333c61,8ea598b4,1277a568,85582688,6bf8deb9,861edd8d,276fe3c4,cb7496d2,9d313697,77df75a,d8c40a85,19ea1415,9ebf533d), -S(8b822d8f,640dbd04,d2a35aad,e4309992,3133fb0,c97073d3,b23f767d,f3468247,71db728e,40b1eb39,7cb69211,1ad24e63,79727a77,bb028db0,51ef9b67,f31d036f), -S(4a0e24e8,6d588f32,7d41addd,c4659b36,d6406a28,91ace143,d24d98cc,cfea28b6,3c79f61e,71c3c9db,11c97734,da9d9d29,7b141060,589c029f,6eb888cf,7cb6f04), -S(3df98e9e,c1bfd244,86c6e95d,8ab19c93,c89751d7,d408ae98,44c90c2f,8bee9685,fb6bd949,afc7c8d0,a16e2c45,4869cc4e,899e6b6d,701eee28,7434439,fc61074e), -S(1196aba0,2bed29e5,2ab28d7b,74301095,ca68fd6b,1e2d0893,1e3145fd,3dd1047b,d8dfd4a4,781ef486,8513bfae,d0b0ce98,5d80f6a4,556da69c,aea24c1c,7e85b27f), -S(5746e37f,709a62f,af3a720f,2c7d5ca6,5ec8a3fd,3e223b67,b839dea,60cc1505,eec14b2e,76e888a7,538f0fe1,32268576,4f91d70a,19d9e885,168af68d,5b9678b2), -S(3c807748,606480e0,9266fd22,69b9c7aa,9a2f87e9,58d3264e,77cf2140,e0f2dcef,48b70aa7,6f86e7a5,c02c1997,fa029d78,94398324,82d3396d,2283dac7,dbe23c00), -S(52885fb1,f40dad6b,7c0f7f0e,3e9e230f,b45688f1,a9f3adbe,710bbff6,d56885b0,372ba4ff,192bc456,56240432,db828847,98cc846,e810c99a,8e33476e,1a674663), -S(60fe0096,4fb56044,c506b551,3504a800,7c2534ff,52f53f54,31a479fb,166616da,75ae6371,b05b93a2,499563d9,887f69ee,f9532a1c,6695e6de,966f0b73,90100ee8), -S(55439653,f8f659fa,9f2ad854,2b1beee6,6cdf34e,d3e464e8,45ca34ac,70d88434,c7883ce8,984db19f,a1866e82,f7cb0623,e6de0446,a8ad5fa5,3dcc775e,d2a9f871), -S(18ea4c5d,24fd7a5e,9463b109,20760dc7,fb4ae56f,db00f0d1,805a9e19,c02f8687,3e19b983,93a440ee,99fb1a25,d7283f10,cdcf3b7b,8b063ee,5eb05c56,2edc9251), -S(8bfd7102,9c7a5747,8eaaa0de,1417ebcd,16731b31,935b7190,d536089d,56dece82,b8fdf97b,1a4d9d35,f32504a7,2a03be23,e71fa005,48cbe33b,8a85060a,21daaf5f), -S(e4fcbc12,22987f5a,f97c0ae9,be88dcf0,23ee2366,4a2f3b98,d19f3687,b82d89a0,7539ffb,33cfabf8,582ec993,8c034688,f8aea8c,7fb6f73,ae09ce9a,e63b9da6), -S(bb20ed68,c9a83a86,99a42cf3,9a51af62,534da50,36bd8cf2,5ef7f7ff,1f08ef85,48d64269,af2c39dd,d6c2d703,fd7832d7,c409d76f,8a8ac99b,d977e7ba,760e7428), -S(2d852cde,fe404dd0,835c781a,11a23db,bce9b015,637c4a82,e0ae009b,aa2ee8a4,d69c9056,66184051,f433e99,ce03c3fb,97107229,d509cb69,59675300,8951f4f5), -S(37f5037,beda50f6,c485b78c,ae4843d2,cbbc50bd,c3588c34,54a09dd4,4b5504d2,d2ec7671,9eb38781,d2954fab,34f475c2,2c297238,70bf7ae1,1124231,2315d8d8), -S(7a5fc0f1,5747caef,61882134,40cafb3e,e8cd6c25,9cdefac3,60c4a9d3,6c96397f,bdba60e9,bb96fbfc,e1fdc22f,d4282913,7c717a1d,f907d441,94fbe55c,bdcc7d73), -S(d50843a7,4602c5ee,298e9ea1,6ecc75de,c0bc2b0d,150546e1,4605ef8e,c0d33eb6,f95baa7,aca33535,b559aad8,ebb18df4,eec43134,6ccbdc72,a3551b53,9797b570), -S(e5141e1b,a2a9e653,5baa4cc3,71f143e4,c4e3be94,4b81ad88,4a1cbd15,1052ae67,afd5328a,75f3361d,ce8b7e84,1e091835,2ef1f4b1,986dcafd,40ac6aa1,12a65838), -S(892a2bfa,f1869c35,34b50649,f4e3bca4,2fb6845b,f831471b,4b6c80c4,650ab82c,ef6c3f52,6deeba94,563afd1,5b9246c9,b397ac2d,1ac38a79,c7f24dc,1706a402), -S(7a8b233b,94e81662,1ff28218,c60e56b8,15e7f48,9bf401c0,182f05cd,57e1aca1,de6fd62d,713590b,f0e81723,a25540ee,3a98b68,68d4bfa3,d0b64b60,1bd02202), -S(66c7766,ec95259b,ca729173,a721d3c5,a1fef897,6ea25f9e,4c5ef3bf,93a659f1,23d66628,1cdd28e1,18cea2bd,bb8bd13e,af6fe7eb,d282e5b6,858656b2,31a8463f), -S(14c8b905,9c41ba45,7c8ef52,c78bbc43,6a9dbe69,4e8ca807,1b538e0c,eff68d64,e4c77c72,5c9c5cb8,2cb26618,7fd77fcc,cff42520,5428c0b,b7a5145c,fef3ea12), -S(ef36e454,185b6147,9e0c57e5,92ac7b06,d59a4d21,6d0f4794,15fa728a,181e4024,a2b298d0,abdf1d93,7e6a15c9,4a77a72d,4cbab1b7,5b27ff46,c217d1de,b47bb006), -S(6848b754,920b0919,b96c7c54,5329951,ac7f71,7cdfcd13,9923d4e9,d4fc3ab9,a9e4722a,59c84597,a6f9eb15,50230182,af76f6e,eb8f9b80,c4b14d7,2f07623), -S(a8f4f96f,c417bf04,15116fc3,d223494e,4988e32,855e7cb3,c52f3c77,382227ef,3f5ce509,f0aa36ea,c23603e9,b08e08db,4a9df67a,bd1735ea,1f3cad02,8f63bb8b), -S(372bce7,9b26b7d6,6026375a,1d8f7858,4770d17f,e23a53f4,3d84b577,4e1d540f,ea6ea296,59226bfe,cca23e38,f341dab4,a3750d10,c9e9d662,bdf90b95,c68ff345), -S(ede230c,fa48b0b8,affa246c,af849946,3c89b87b,148259a6,bb319895,c5d1decb,76eee3c6,85fbb3c0,ed86e7ec,9bea6189,56ae98e4,d1c7a17,e9f7d796,eb8b1540), -S(1fe48c38,964fbf0,438f3b,95d15871,d8037e8,a80bcef8,9cf19a54,370457cb,33c60da0,ffed0f,392758f3,76720d71,42a66034,ecfb83ce,ecb05bc3,44fa9fcf), -S(3ef6a0ce,d6b74a75,7da5e17e,cc0b215d,9cacd353,44c90c07,cb7b86e5,2066d500,a361d55e,82a75506,ddea417e,5f3ac744,9642305b,92a9bd18,b8fd2fc9,b3e0bf77), -S(165c9a99,4f26f8ac,528caadf,57d77d82,b74d3f79,1d2f18a4,e5947aba,7e25ff56,3016f139,a0e0c5f5,abdc57c0,86489330,f3b83dea,46396fb9,d1052753,785da130), -S(e07ff9ac,650d90bf,745bb6e0,13ae6587,e96feb6c,e1c003b,c0c44a6,6ec415e0,8bccd0e8,77dec06,e4aee5d1,76313cfe,de90e6a2,8e98e618,70e31b8d,8da3540b), -S(d1133e3,62cb9ea8,4d4da51e,763d1b23,ee018984,cbb2302f,c5789278,e60cd0fb,b66e8a8c,3f41461b,8d1358c2,5761456c,b5c086eb,b67a0ba2,b02166ac,9b0b2d65), -S(fe40c8f0,41c5f50f,789b4c2,275892a4,547da456,ed1a7558,8529ecee,6810fba6,a27031bd,d4290077,ad0e50c7,787a222c,3c89b27b,13159117,eea61c29,f126831d), -S(83b7184c,2b76a015,b80c1269,a78272d4,374a00d,340500ea,ea5df081,18ab986b,41ca7c04,774653c3,87782499,ae88e219,a16e53f8,1a87b1f8,768933ca,8315df89), -S(7c230724,b72fe375,bac73f94,5df4e542,c6789c1d,ebaec636,730f07a3,6c3a0648,a173576e,8c3f56ba,543fdbbd,c650d004,3fcda4b4,4684a6cf,666b7423,9cee0152), -S(652207a8,aeb1c301,932db5d3,854efde6,da5c9912,ca6833a9,79499ba,8549dc7d,14ff67f7,d0d82988,b0b947a9,b8ff8914,8bd0727b,f72e9ba6,18028c42,792aa3c9), -S(13422e69,12a1b8d6,db99e17b,7606f3e3,b6d5cd11,5f47d50d,587e131d,477f983a,f72d5395,a5b1badd,88074638,a079797c,134d7415,a7d4be7f,23b12b43,f1f2b1b2), -S(3605aa35,29438d1,90c78de1,7223c468,ef36b28f,bf7fa6a9,d809b113,7e251481,9de174d6,43288a16,3dbaa04d,f4cd8214,f3e68c8b,13b71ff3,215447f5,2522b8ed), -S(fabe9cb9,d1e80ace,f13e49c0,d9cf2e95,12091e07,a9b0ee68,144d92aa,8a3f5f7b,7c05d1d2,7144b868,33c1dddc,8374d4e4,16df20d9,e7111415,8203ffe3,8f662823), -S(df84793b,e4c7a574,9c5cdb3,10ed4e96,c05298e3,d7c7187d,93018dce,ac6d75e2,62d04b5c,1cb578c3,8784db96,8fb8786d,59c92183,c226df41,d164fffa,c076fe2d), -S(90585ca3,730b76,78a731ad,ac186574,911212ab,58d826d9,95499433,5cffbdac,85bcac15,d41303c7,bb2b2f87,eb3d5101,eb35818,815711f4,fe72d243,50f5f6e6), -S(89e17bb8,56178598,74821db2,28956cd3,8e8cc6ef,568ff68,5d5c2e22,5cadd959,e759f802,faf4feb7,4ddc888f,38b8faa,2661c56a,367da1c0,781ceeb1,7b30e37e), -S(1d43bd3,df9f1f25,c061538b,6d4fa0f,dc6b3be1,c7443616,51420d09,7aa81e9,ddc8f865,d85daeee,6faedd8c,172568fd,d290dc12,fd41925f,868fa03,ae8176c1), -S(6899bf86,10d6f8f4,f2b50e47,1eb5bf9,77924580,3b3a8636,b161879d,35061e5,c4c472ec,37bf52b0,3de23bcf,188dafa1,5aec0c9b,4f023e9,b54a8d9b,2940a66f), -S(b42ff8f6,6ea45365,485cf5af,ad243cf2,f6d63e0e,d4a0386e,475dfc99,70b9ab65,46d2ea18,495a980e,db65262f,efec578c,ed829315,15ac74bc,83d8d385,d739b2ae), -S(cc1d2622,9e9cacc7,f84bb974,e06e9dd6,62fa261a,a90e271c,332c289,1511dbd9,206e7e03,b8c33605,ed870f52,2e31aeb8,1b9f8a70,86732a49,6761f00a,bf0396b8), -S(21f031ea,16cd5c2,3c5a809,3a93656e,950feed9,64c8e2,debc0a98,64c3b30a,2d038c76,f07d43e7,f70d289a,32115679,232bb02d,7f237f20,82f085a4,2031f61d), -S(8bd83272,4e955741,3a6f5fe2,b5d0cd06,ca80a3f6,eb8f6449,516274f8,f98c689,71559502,b2442397,62319105,3b440a7f,fcff2a76,bb4e9552,37dacf33,b26d19e), -S(74c61963,edd7e01a,5ecbc8a9,76a1f24a,fad2b1db,1e632edd,6ebbe3c5,49d2af07,9247fefa,fd6ae328,f3cb918f,3b6ec823,4c0320c,5a317a54,19fa17d1,bcaf9f99), -S(1d7e54a8,597a36fa,4a32a46f,b40fbafa,dfa50c42,c4dc2228,b30c53a4,17b38f24,cce12594,2f1fea05,1cee6589,c26ef75d,f88d7242,bf3460cb,7bac2566,498e8ce5), -S(c788085a,893e3e58,bdad60f5,a177601d,5af89805,47bb9e1,2bdd2294,a850bdc4,44292afc,2ffbfcb0,5ac838b1,224bfa98,fa09f219,b81611d2,d83c9239,4165b415), -S(d87e2357,7984ef30,a3243b79,f0a53f84,93b38e4d,6b182c47,d1e6f48e,3d38db8b,b42950a9,16c616aa,1fbecbdb,70868cf,28106872,33b3b549,388c2255,a157a50f), -S(5d3ead44,592168fe,d898a5e0,bc7c0aa,ef926d4c,6f06698a,e5274aa9,90307ef0,ccc1e0ba,51eded41,714e8039,4a626a20,1ad5b751,5e6d8ad6,25895be5,8289f1f9), -S(ac063972,75d60207,fdb67802,5d86424d,d47b7fb4,8d20402f,bc683c2,b7e9e63a,b02c5027,e2488ee2,4c53365c,d9101fb9,5bcd0c45,85e25738,36156286,fcff1c89), -S(815a5ad4,fd1e59c0,56bfeeeb,b50e5728,18a6412a,2eef8d42,7e27c871,e41fcca5,4f358e87,5c7b6e0f,ffaa3026,205c07b,4a438394,276ae929,e24ff4f0,307e956f), -S(10902a4c,a24b6807,ba67d735,3fc9582b,ebfbe13f,fadf8146,e40016b1,40956db0,bbfdd872,793fa436,5263d277,f2ae1512,b5f349c7,270561b5,4c151824,6b430743), -S(858aa1f0,dbae0cde,a7640775,44f99261,af16469c,602f31da,3345671b,93758d48,ff63509d,d56ff954,3cb112d,941fe16b,b5fef4bf,96b8923a,c0e3d3ce,6f0e4cad), -S(1be90c71,7032671e,3cffce34,1a6c507,e5564576,ebdfae2f,bb28a20d,ccbbd6de,69edc8d2,20bec442,2cc47888,22eea780,3d4a01d6,1f8da9cd,4f8533f4,146c16cd), -S(6149cd0c,162f1ae9,163751a6,e967422b,8a80816d,deaab38,e73237c0,cca923f0,9dce938f,fd20eaf,b518752a,9cafb862,8416e3e3,8ba723fa,12442844,1bc7a477), -S(20696c11,f43db49b,d891505d,cffd36a8,a0fd20ff,1c56896c,51591ff1,421680bd,397ba456,6566244b,a186055,bbbabac1,620d1b9f,9d2d06c4,44069ba2,22041d79), -S(caefe4b7,91049900,5f6247dc,f1e49aed,22493a96,933ec702,c93f83b3,455fd6c8,6191fd17,4ff0887e,886086f8,c8f9cf8,5d3d3e03,30f436c5,50ca153f,cc1af003), -S(849d894b,2720850b,bcc0bd08,678205e7,1ce2b041,40fd138f,e16709dd,f3c9981e,8909d10f,494af391,a3ae9000,7af2a292,8f066ff3,22199e64,e3416799,a25c43f3), -S(d27b2fb6,e38544f9,eff19084,cc901d70,3356937e,292c1989,856bdce1,f6a22364,8c296bb4,a89bf08e,2ecd87b5,b49db335,b6e2faf1,b1b57146,3264993,77e56175), -S(37e04b68,f476235a,728bbc12,e3572929,97243538,e37bc2a6,bdf6b7,e8ab4d63,ce346516,383c0573,9de7a2cd,c4b0c0ec,9c3f7bd5,c3e8c27,271cb9e6,7ebdba4d), -S(b3c6c10c,5eefc0c8,832d9c99,183417fa,9351868e,42952b96,2d623305,9a1a3eea,d7ad6ba,968091d,fa8c68fc,49aff425,44f35d39,a75824dd,a79c5b1b,602ed3ca), -S(5bf180e6,763045ba,1453a353,49711a67,9175a21f,f2b7b381,8c8e5d8d,4927f107,72ed6000,6cbe16df,48d037cf,237cdbb7,93705ff7,2bf38c73,e6a87f1c,46ed40e9), -S(82e13ea2,3cbf23,ed3e2f47,922b08f5,9be10fe1,48de26e1,168b0784,45705ec4,288ae681,decf904c,d490b6a4,d5a3e5a,75bee593,ddfcce76,693ca57b,f39c1805), -S(4ac56d72,b9a5587b,dbea0ca2,674d343b,15adada6,f30d7a3b,fa481f7f,69af9467,5db2d7a3,3d42f04f,c75ee27d,7a7fe9d6,3eadc5fc,ce770e3,78d09ff2,eb62d78e), -S(bcddc00a,4fc9976b,6795da19,44f181cf,6bbfc775,cf4c0212,eb419580,82eb0e4c,30eed6ad,bbd149b7,49053931,65941084,470f0338,396a6c57,9fda211d,358a48b2), -S(9331e909,bf2663b3,8ef46e21,2293e63e,c7c1559b,853c3095,cd749971,79f116db,8ccef168,4504893d,30418aa,343b3f9,3fb0db2d,895359ef,f1b78d6c,1f074fe4), -S(12df2aa,c307209a,23b543e0,7e220557,3bbd8cb9,e341fdd4,6326ecae,916c329c,48d2da1b,dc2a251f,a861339c,7b92bea5,cfaaf0b2,3f4bf625,7493df8b,228fc8c4), -S(987e316f,f09ad376,eddad996,98228fab,90573f6d,60f13772,e55429bc,e77a91c2,82484e05,45aa13ae,23007c0b,7d6e0d0a,7b8ee542,bc50ed28,55ffc819,aac4cccf), -S(7be67dd0,e377aaa8,f13899d9,3ee2e9f1,623d5efa,ece91690,82c9dde9,ac7905a3,ba82932,93f21a43,23ff368a,86c8acb9,63328f81,5f003f5b,604082b2,4d4dc3e9), -S(133110e3,5e53940e,928883e5,fe5150ab,303af955,7450d37f,20dff5db,c8e2030b,54ea08ae,730c8117,ff1abf61,e89fa960,2e434dc6,c43c6a35,3a45d535,69f7bf96), -S(a000b820,53c27e06,3b6ac0d6,2cc0bf94,449ac467,800ebf8d,5e6bfe91,bab6cb36,af600aea,4261cc05,48e7e30d,f9ba50e3,e4ca8708,aa276bf2,ea7e384c,f3e3880c), -S(df50b710,59dd653a,f1f2b8d8,f39e12fa,134f1020,4e794ba7,9a734a39,eceb2217,17b8416c,51c8d01e,7739645f,eb5344c6,2c5b05b8,d27aa83b,d02def84,c128c04d), -S(b3b6ea83,cc9ee99,d7518cf7,94fcf12e,5f2d9845,b165330a,1e55c4a9,4a601b45,7e9aaee5,3dba428c,b042c0b8,87701d57,bec9635b,f54bfb64,13742d7f,3a7576fe), -S(7c81a6e7,36ff8ba1,82e516eb,b47be4fc,98e926f,bde294de,e371f068,687953c0,9d8d9b8f,a5b608eb,46bb5fa9,e162ff4f,47e2a8f1,86f41847,1c2433b2,462aec03), -S(e370435a,c9b0d2f,175786d8,6e2bfef4,ef7bdbab,3048fdc6,abab0fa6,ceee0cfa,586bc07b,a05088bc,ceafe00a,dcceb00a,4c1a3704,2f43f011,218ea8ca,7df4f04c), -S(999bc950,1d0b31e8,5175b27,17055c41,e5711b91,fad9af7f,82018e4a,a8f092d5,592cb475,2cd85ed,23d10139,55118027,7f6b5065,9b374ec5,55cf8f08,bed57ccd), -S(2241da6d,60fa77b2,f844f4e0,6972c230,1305d1d5,5d1a1453,16436693,232a622d,1b3ca0b0,8ddfe046,b916c1c3,7e7a29ad,9d235e6f,4f9aa72a,9676d62,e3770035), -S(d4e6cce1,884a77e2,dcfb08ff,6e4717ff,ec85343b,fa2b3415,1e290c2b,e9560171,3064c1dc,9eb6fbff,baac5bcb,ba14ed43,523db1ef,8fbbeb38,3e57dc9d,945e539d), -S(d2baeaff,eb5a040b,a7627374,ebf692ee,65316c6f,b30c03a7,7a6c7882,f98d0ef2,7f5b6e13,d91cd74e,6841c97e,32ad8e4a,3d8c572,1a206b30,e89c6f19,43313f2d), -S(150db822,7f60d338,73602400,27e859b8,7e4cc5b7,749d8d16,6ec3ac03,cba95331,12938598,70c09913,a855559b,2544d3b3,3de7a12e,da4aeedb,72b44568,7f6ab9e9), -S(bd607750,1e8d489c,aa24a424,8baa60,e0a86ef8,f9f6ed17,4537d826,c3e90fbe,9617baa4,c6ee1d2a,6231b3aa,5d145b30,6e0052ea,d1a0cbf5,1f74ce5d,7461b54), -S(ba04c85e,7755ff09,97b5c7a6,552e79e7,455b85ce,3498236b,6452958a,d01e04b8,e82629e6,1513be7,719c2e52,ddb4e8e4,3530240f,d4e3f199,b1738596,9498321c), -S(be1c6207,4ee93f45,6dd94b72,afdd295b,f751df9d,a77ebbe4,8e5de0a6,a6f9ba8a,3a1fdd34,72474e68,83130c08,b1e99e51,5c3ad11b,7c321b52,fce159a7,127599d9), -S(21c4ee54,bf48268c,44996b18,aa38a92c,7553eac1,2f4bff57,e89fd389,c9ebb1d4,7a0cf9a6,c45cd57,d0a1aee,3010ed52,220194cb,ea43715e,a4252272,71064b6b), -S(2ff1ff0a,14c965f4,9ee43f0d,64ecb94a,344d36d3,d90616d3,2b208024,4729d291,47d74f0e,8c9c7dd7,580ae2eb,3bf07a4f,320c80a1,13a5eb73,cfaaf7ca,e38e9803), -S(6d5ba86e,be2f0de2,eee9d917,aa69bf71,9ee9e93c,1ce7cf74,a993435e,480b5b39,9c19c406,1d3fb92a,4dc26c8c,26bbbab8,5b4e9acd,950a7ec6,824aa915,c1f9cd66), -S(49316bcf,122ac309,2ece7f07,c1449a7e,db2bab4c,29c7243c,41dff1d0,feea6aae,3fe2db4c,26ebc1df,66a03c16,deeb4f5b,4a3a32fb,2c2db184,7dd93738,a43e68b5), -S(329b8fda,fed0ee52,b86a0963,54c2141f,c22734d9,fa8e25c1,4376d539,72f123f6,35365b1b,8ca97c37,1f3c0d34,599d114f,ee3b67c0,fa4973ca,b0aee621,5f07de1a), -S(c74140b4,8c998c17,e7895174,b461c733,e687f71a,861d5687,9535f11e,31ecf62a,4a648bd1,5ce47fd7,b9a8382,7842281f,59a6e0ac,6dd049d5,c05748cb,ec607556), -S(92f5177e,cddc78ba,37a947bf,c72d4bb4,531ea7fb,1e7c103,d312fc2f,a8e4cbc3,2d348b69,cdf37794,383739d,3af49d0f,7fd9b0b8,1b5b918,9d3cb49c,ecd25d0), -S(31ca4598,daec4eef,975b3a18,b14420fa,48634ed9,ceb31b64,faea0fb5,32673490,574e1a82,b029e852,6e12a242,a21179e3,d7835a62,384da226,c7b9c879,43ef506b), -S(f7a66fa1,103f1fde,1392d998,fd5d8c2d,9d4804c2,999df8a0,c3d6780,ea915b36,94b115b6,897e00bb,166d01e6,e0b0e3dd,7399e7a1,98985a00,f06312bf,e31ce81d), -S(39cbdcb5,8ea994fe,f678e688,c01fc74,a643b907,b7d00c59,98d609c2,898274d2,5c256316,3717961f,3dcf176,73183034,9d881d7f,11544246,1a42a9b2,8b524e8f), -S(56fe8710,6d493892,4750fedf,8cfd9597,766699b3,ef9efaf1,26fb0441,d01becff,6b16649,80e3bec2,9ec107a3,f02a0831,5ff24460,b0b0e29f,208610c4,a3ba722), -S(e9ed0bf2,81770721,b3132049,e48ec3c8,9b33e62d,6eb3f1cc,b50ce7c1,6cce6741,ed06f8a7,d93913d0,fbdbd2f3,ff5448c8,f004f690,340b84bf,ded66508,19c356ea), -S(a3e250a,e5f568f1,fdb0d60a,8856aabc,a3d35a9c,4f23c07f,587646cb,41b9d29,3d2c6652,31f48e61,a6c4b571,6ba8a07e,5c8374d9,2d0ca6f4,970aef59,3f2a78f6), -S(bc08e135,216208eb,8bed1164,3deefd2b,a89959e1,20d3aefb,4f02976c,ebea4fd1,bd59151a,ecf185d,a0da79e3,817c9b67,605b46e6,41b733eb,a70180e0,47bbc4ae), -S(1008a624,ad6badc,60b3457e,702ab324,6ccd3f90,aa64d741,69539116,64ce56f1,de2d4c03,69f0faa3,5e039afc,1a650137,cb299fdf,8840bdc5,219bc9f7,b94c7219), -S(a298705b,a7c0a8a4,7b68b674,c63d9d7a,fac19b56,eba7f866,59cace5d,fdbb4b05,7b20b074,33988789,da3b41d9,5a9f0c71,f2965ff0,16714652,926f9e32,287f703e), -S(325e58ea,980fea75,a79f4254,60afb0cb,8f68bed0,71857e89,e4e7a88e,34b5cfcd,7034e0d4,ca1844fc,47d4c813,736bcfbd,7cf0c693,cbdc1ba7,b0d29019,44212c16), -S(22d51a7e,22bc439f,9179932a,254bcdb8,eb5bd7b1,515645e0,2340cb6e,8b94cffe,1da471e6,1c8ef75b,10525d6,132a14af,9096a429,e277022a,d667e204,91a786ff), -S(490cd510,a010e368,b3e4f0e4,266bd0c9,c04e3434,6d039f0,764f5108,aa31d6f2,2ee7815f,9ec437f9,3dc69f84,b0c91231,326c0159,4cc492f0,1f9b8d88,7fc022bf), -S(f8896cfb,f2d14e5d,ab1f3c2c,1e669cae,433a8a9e,42c7e68b,206a0d88,b4aee3ec,a84aa805,677a7c6,12e7930f,b91293ec,afee667d,2b033019,ffae8d8c,bb7281da), -S(9be847b8,3ff9d27,e74db522,cbad0ceb,3feffe52,1dd8e7f,999e515e,253ab848,c2646e15,b0865eab,c459a0c0,233bb52b,e202b681,c060f06b,ebb3a39b,69cc19bf), -S(1c6e7cc3,f35b404d,61d0454f,1a9b5c58,40b96207,95b613f0,a896d781,9e29271f,352cb00b,5d556077,c9fc75eb,aa1c28db,dad01cdf,dd5e75fe,ddd43ffa,8042385c), -S(56c10f,e369938f,13863e7b,5135ffc2,6da9eebc,5cfd6eb0,7f7d1f67,fa94132,8bdc142a,f7ae1906,c63e3de9,5bbb63cd,650ed4ac,b9a2c321,e525b512,397c5e99), -S(70897a5c,2d8d2e10,d24a0c43,a689c11b,be2b9f2d,2934ae6f,b3dd130,34046227,3f9d0207,3e083e16,f64ac869,5c1616e9,8f87e8b2,c9c95ed3,3bbd85b2,dfbee7c3), -S(e2fcd5fa,5c6af2d5,1297f97c,d2f0918d,320c785c,ba3802c4,48fab36,2147f39e,5308f1c9,b9a24e1b,855b038a,41004b2d,492fe91d,8ecb076e,9aea21ce,ecaf59fe), -S(463d53de,9f07ac1c,6eb5f7ef,2bc70046,261d6a64,6fa516c8,f7677ec9,b2153acc,ca198775,f0f19d71,48c138a8,4f5472f2,f8e5cecd,e2b7df53,61261cce,f322b762), -S(663438d1,82758d86,f292f12e,cd173445,2b554cac,1561f0c5,8f5fae70,9b165c21,23eb676,75e8f8c3,e78fa6c9,99d6e185,e0f789fc,80576620,5c50518,39e15515), -S(9a8317b0,65ed508e,4c9239b7,af39f42a,1d43bd98,8fc101c1,d45987cb,ca58f7a6,ce0db1d5,4df13594,57d9df20,6a487348,97102335,dd24b2b3,6e10bac,4d9b5808), -S(da6f2ca8,915e313b,8c4b221e,b81aadd1,e7468004,8030b8f1,48d1b733,caa33be0,bb59cc06,d267cb7d,c954338,9010d49d,466e4c3c,91335f62,1c4fe7de,d17cabbb), -S(7a18820c,1774251f,c299eca7,871bb526,b01081b6,c5321056,872da42b,9198954d,3d216aa6,1702fee0,9cd2a72f,e53d6092,2b07b51f,506f7a44,ae490af8,c9da7598), -S(1240d207,3d234306,70d9f2d0,17bf81dd,728e728e,5098238d,b0d79397,2628f5ad,612c97d,13c5a948,88ea389f,e809b656,77fccfff,d5db913b,771647a6,680fc074), -S(3862d4e5,c973e75d,ac6e6ad3,1e3e24c6,e9b8f5e8,6641b20d,f0bdb04b,ca98ecbb,524c8d0c,7f485be2,decedee,8320ec4c,79b1c25b,414e129a,2f848de6,ce3997b3), -S(afe8a621,bbdb4908,5726bbdd,b0d31469,33c75a94,bde06805,179729bb,1518467d,19b94d68,8a7346b2,e80ccec5,a393b7cf,afc4954e,5793cbfa,e02d7f70,7610fc85)}, -{S(50cd2e16,997d7d45,98bb2d9b,61aceaff,5ad5f38c,8286a0e1,d08055ad,726c7800,dd19c3b,c08b8d97,88f9de1,5941f5fa,6402bbbb,5fdc708b,cfc08844,eb23733b), -S(428114c3,8fc9e242,451a001e,34df1509,1f5c14a7,870f110a,fbcb0895,4c4b2496,4c41e9fa,ef00faed,fd12d4b4,9f5322a1,47ac4a7b,f8c7fc84,3a6250fc,efefb84a), -S(c0b87aac,8a4ee530,8476632d,ca83b163,3616bda9,5609ce58,8c09a48d,f544051e,a054562d,4bbfcd57,dc7ecaba,f110a6c5,e75e2d15,226bfb27,b8f88172,2a2bcdad), -S(e7abdaf2,2ddccdcb,736bf2e6,fdd79362,b02453b6,5619ada8,c018fc62,9fe2a74d,8e8362ef,abe83261,ab1843bd,2a477a6f,4a6a4aed,462e266e,e76f5913,1277c153), -S(ab7c1829,d773868,7faf5581,150db894,4d0a4815,c31e768f,ad3b313b,b159f72c,c687f86e,7e7bf0fe,a625143c,d6d7d130,13986eb1,5b2184a1,9f42a799,fb6eb703), -S(5f041f43,9394e0e9,23c951e,1fbfb8c3,8e1e3ab,58640799,b4ecf906,a6b2f4a,9f30e2ea,d04ebee1,f5e93cbd,2ed2682c,f2c22a0f,623f981d,f59d414,8c4d2d68), -S(b1347d84,86341ce4,84433a1,d00e9dca,63b94338,3818ccf6,59b80582,a027d202,2d30882c,d961fdfd,bb6c38a5,a11b6e89,25cc7e03,fe48abf3,3bbd86a1,6a65887f), -S(6e862ad8,859cd489,16a865db,cda120c9,2a5d8862,460a823e,9c47aad3,88a1c580,8854b584,e25c1b29,1c17fa6,bafcd67b,11c9ffa6,480679c6,8e253175,3faa4ad6), -S(a1b78338,c54bec48,aedcd65f,c60b25f5,eda31e34,d6badb32,75c128b,e3b8e752,86f46d95,157e23f5,6ab1f851,93e623e7,f693d74b,a08b47e,f776eeb3,cfe2ceab), -S(5fecd94d,128ae25b,b29daffe,c0d0131c,74df3dc8,9c4d573,e59bf41b,3f83a628,4f2ee3b2,3e5a008a,4c26b525,a5dfcd69,93215d8a,8547f13c,1c871f1e,fb082c94), -S(bca9377f,c179a785,f7b470da,51bec3cc,d6306938,f21cd224,7bc69651,bec76b36,cd1b6406,a55dceb2,c34e5c70,ee7fed4a,9ea3b1c9,92425ea6,72aeaf04,e5a464f9), -S(95d910c1,684c2963,6f90ac23,32461ef8,6d87ce1c,7dbe889f,405abb1f,cd0f57e4,1f095ce2,45a207a6,3c8b0602,4b4f25f,30e541d3,c325ff2d,c2c6a9a0,2db14235), -S(77cb5deb,ce99ddaf,4aa546db,274be540,a29b5664,5fdf411b,879e726e,61bebebd,df4b42c,63787720,42a10781,fafa09d8,e0329d72,1bc2189d,5dc0b56e,4700910c), -S(152ef349,2f9a22c1,87b70012,5b08a6da,68b50df9,1e671571,5ae11edf,6a35a3e8,d22a3f0c,654d88a2,bccfa6c8,704b99d6,7f5cf72d,ec1213b,f2c682a5,1bb91c81), -S(aa9492f9,6a2f4ad9,6f9d3b57,312edb60,1ab404e2,52ebbd4e,f86d5378,aa7282a8,bad928db,b54e8af4,2931d08,612ee412,c504c28c,31274bc9,d63366c1,c7f072e7), -S(a89ab05,ccb1edbf,1d95f7e5,5b2c1aea,e1c45b03,e352b2b5,b0e6a731,898a3453,72b9172d,548e4899,d24d5feb,87df8432,e1a6dc84,8dd28233,58a48c59,578cccb3), -S(e96d95b5,93801cdc,1b2b21f8,81f4154b,3967e7f2,84fc5a25,99c4fe5c,cf0ce66e,1a43ceb6,afcb7bc1,f285aaa,57dbb2d3,10d09cc0,1942aa72,daaf550,4c3c6bfc), -S(21de9188,2c8ca8a3,847b65dd,c667c64c,8378a756,cda3b9c1,bd6e438b,8b619cfc,d1d64895,a03b455c,1f52a019,6fa3191f,7dc57f9f,419d159a,d0faa03e,ea1f09e2), -S(9df78d29,3fd3a96c,f3d73bf6,7cec9246,edc8f68e,7b10e7bc,8a14e8c1,980eeb4b,d14369c7,993e8ccd,b89ed1ec,18a3fb7d,2659f70e,384a9f3a,55761eab,5925bcb6), -S(81a04986,e34ce13c,b01e334f,78bf2a3e,941e3e4d,243418d4,46fc0cd7,86f5dfff,3b6093dc,864ad994,f1c3b88e,81a46f1f,a916b51c,2d45eb06,46793fc2,e070abc6), -S(2f725b7b,8ba1d7c9,1c7b2d0b,65fd4328,f468b516,5cca7699,3430669c,d5643b95,dfc13e39,8ee1099e,4ecbd8ec,8847caed,e9872ab6,c9b0533d,b6191ed9,fa9b0e0f), -S(794a6094,8ad0dea0,907a4010,222754ef,c6e67a7b,d6c5957c,5eb004a9,a5518693,59897754,d7799fda,fbb2cb22,57687440,4c4c1318,b73745e2,e37b7f9a,51eee929), -S(7110e58a,64e526f9,a9caf9f1,e0ded62e,53450a64,3a6cd150,76983083,1d113dee,4629d7b5,e44421d4,4631658f,23ea59ab,1f15f446,790a600,483c1539,9c597aca), -S(1d550551,fc307b9c,b16f034,b79e7937,79127f55,8258461b,a786726b,d4c4aa65,51c47d4d,70f9090a,a7f8a183,75f74d4f,ac9c98ad,5c3bb916,bd87a9,aebc3de1), -S(4973c3e,97daec54,e5b9e9a3,6343e7d8,9c57380f,803f597a,25a386a,a652da69,cf403eca,b165571f,6b509b04,284c6e36,2f082b5d,5e7bc302,3ec0e55a,e73bc4f0), -S(61f7b3ec,444021b,ee3fd421,18e7b7d,fd795b36,d0145b08,ae09e1f,c0e3b07e,7df1f20c,79e3a7db,72cc08fb,98fed87c,ea923a91,815a187c,55e4430e,cea5e963), -S(42426dcd,302f698d,9376959e,50e6f471,5b1e2371,fdb03861,6ace0e2d,e27fa90,4c054664,1c4a0ea7,8280c526,70455e3f,51bee24f,acdd46d2,e9f82afa,db42d1fd), -S(80939488,3eaccc24,b1639e9e,656e7b76,2a310c4a,778b390f,d7a708d7,69c63fc8,b83fb593,a2e198f2,5fcc7add,310c8285,c19d314c,7614371f,9db28e28,8c2d47b1), -S(3f52b480,40e1ba54,67cd752e,a0265f50,c3bd1964,8f54dc8c,8dfaaf16,d9b3cdff,207a0014,1ee322cf,24d81b6d,2a7ccd87,be4d0b94,a7df9234,c0093bca,3a36d60), -S(c09cf34,bf1b1f94,15b63dc9,8baf66f7,68b073c,6b88fe53,7a9c047c,30703ec,757fd4b7,4f0fda31,99928ba8,39999cee,f2adbef1,8cf2aee3,4ce3708e,2897f95b), -S(8c1d9d66,b10dcb56,1fc72060,db7780eb,187b38ef,b18d6222,64188a60,da748871,b413ca7b,61ffe6c,16d493d1,1f955cd6,c7d7bb53,1ec4191d,85cf2f74,4506d8e8), -S(e31c4039,f33a6a5d,8682c906,612aa37a,3f522069,3948bfa0,dab4ccda,4f08900e,17d345b3,e92d1174,73330b73,cea9b1f5,f1d95ddf,40bd027a,b9b9a0d8,f84d5e26), -S(c4d82663,9c182e6a,b12ca500,3d5eca75,ee2944de,b9222c4b,6f73c58d,62d24bf1,cf4a0f43,e81dc58,c975d59d,73811d14,b01587c3,1ace50c0,b0b41f26,1f010e8c), -S(7c2514e2,fb6bb04e,829d82a8,ed9160ef,c9db98a,f898644f,bf2d01bc,97192be0,72114f16,4ec6ba1f,c41d6b0d,6746da06,4b46a506,171707ed,36cc6051,85f57ca6), -S(fd74379a,f6a18e2a,cd330fc2,49e346b6,89f7a73a,5f4d8862,4997a3f5,826a244e,dfe69f23,b9b2e402,f612abbb,4a4fb044,6a040706,19d6596d,b9953e6d,7179a9de), -S(a1c639bc,b913e3db,5702956e,9806430c,6572e908,a129bbb7,7c8ba5c5,50edb48c,7db1fa15,4c5841fa,c2127793,e9bef5c0,f749c99,66ff8d92,5a8ffb54,e701579b), -S(922dddff,7449c027,daa267b6,83112b45,a864a11a,1bd1cb61,ca76fe3a,77a6dd09,2beb84bf,87b85974,316789f5,148e4f18,386e20f7,41ec5066,2066c454,44c840dd), -S(ea7714b1,fcdceb95,407433c3,4c43a50c,767b3db7,fc7f6e6,81e79f46,44f044c7,6936f1f3,585c04ac,a1a2a562,424e084f,44e0b404,f97f1db1,37b3f00,b02ee04e), -S(cb4c8e7a,f5aca51d,448f3463,9c631821,9dcf6377,9383ba05,5e44966f,47fd36ca,8b0ff5bd,e8285a2a,1f4a223d,f6d496c5,15825ba6,d835370d,b2313418,b947b4b2), -S(921d8dd7,ba630901,3f365eec,ba09d017,2d579b8c,9550f6f6,a6d098c0,bbd08b3a,dad72fa4,9b0f415e,d9f96bc4,78a93e71,98d9456b,6ae10f3f,a1c744c6,e494e5fb), -S(7c9467d2,2cf5a364,191bf731,1ada75a4,3d081226,ff2e359a,47868572,3af15f29,50b15ecd,73341559,32ce1c54,e9a25b96,15dda8a0,6f4bc132,cafceb57,2fb48581), -S(48d10472,c10f4c90,713f899d,65f6edd0,af1724ae,117174f,55d4667a,b440e13f,baedab21,45103f2,aa668f05,2413b8d5,61ce5957,bebcbd8b,c49fb824,1af21303), -S(880d76e4,b95a3a8d,7ab6f9d6,f2069668,80069c0c,c447dcb8,f6063d9,271b570d,150d6984,2f638d03,881480f1,bd2a1958,9728ad72,f97d909b,17f79cdf,78416360), -S(286eebb7,f9215e09,969d8300,72b15a32,fc7733a0,455d2db7,71e527ba,e81caca,8584803f,db64bd55,317dcb87,a8c316c2,f48b3417,d0087527,338635c1,f78decf9), -S(b3e39ada,c92e1922,de3922c8,2c7e19d7,b5d10f4d,5e2cd771,492ba2db,444ede5c,bf9c1afa,d2cec5c0,66cc9e9d,61cce716,f58164db,e31f389c,2b596c38,e4c0ec9), -S(749ba52b,b88bc33b,b31f7aa0,fb95a62,932e447a,9a7a2926,56d16676,d66435f9,7075f278,6b7df61b,70065a46,7591fbde,ec40001f,242775a8,67fabdc7,45221691), -S(5ddb1306,a33c61c3,f0386141,7fd924ba,3118fa2a,53943221,b24cb748,841e4aa9,9602608f,4fd2f4a,511d012,320d05ed,bf1b5ba7,4da5f6aa,2dccbf0,83a18551), -S(6ec58a5c,d0ade361,93c644cb,e96e64e1,f2b519d3,80f7162a,b962337e,5b5c8918,85bc58f4,49b7fc44,1e95721c,b9fd8cd,63e8a250,83d9ffc7,fbfff18e,a2ef7453), -S(9b2f11b2,f66f7b29,e8421aa3,549c7565,87cdb7af,24354a3d,5e397515,f53f8700,3faff052,d2557793,b14a0574,942fb52f,1a53f6ba,e7f4c6c0,a2491194,2d9ca567), -S(d260f1e7,57c31844,9e12f1c3,15d28bf9,fce06b1,f7ce5db6,3210ab74,fa45cde3,54952184,1936423f,2314754a,5b419041,7510f396,90996d90,47ff1225,46672ce4), -S(c6b77e18,b935c842,52aba9bc,2a5f9a6b,86b207ef,5487e89a,7c754a7a,bd03b3df,1ae09c2f,61732aa2,9267ba72,8e22241d,efd6762,16b3173e,239cea45,60ad3978), -S(ea2c66da,fe996ba0,ecde644c,28fef595,490710fb,1052b81,57b63260,e53e5a83,ee91b4e3,cb71b268,dbc394db,7744ef3b,ed0362af,592bf252,71b8ff62,b821b8bd), -S(d6f6061c,904d3a40,75b2c0db,7620a6a3,9a7c21aa,9ea5ed11,c661132a,8cda9031,48fd7dd2,50bf50ca,91d362d0,f646dd6b,7e0f240,4ffc2973,4f131e9c,dfaca469), -S(30538847,93e3b958,a808eeed,546484d1,10cbb833,29a2b2f7,6f61bef3,b47eb9c3,ba914a53,87705dcf,349f5257,6bce5ff,d711fff,6fc8f6d4,3fd61b1e,2b47a577), -S(38558d28,18358d69,ac6b59fd,22660f25,58d6a000,35469f41,6f0970ed,1eeb8a59,8922887b,e256a2c3,3a3ea6,e745222c,9f07e9b3,f94ab1fa,2926e04a,ccd0c609), -S(fbc47f3f,534e67ca,d6f6de48,b88a0846,ceda2d84,afbb601,db71a61a,fd2e11b9,dfbfb0a0,652fdf29,5709b06f,2e61a703,d287b2f8,cee4ca,6a9f2627,2c30fd9b), -S(614d35c7,23a14b11,f3ea097b,6aedcf2e,536e077f,85cab312,74b7c9ff,a6b3112f,5b91b524,5a85c3a9,1194e8bf,be940984,c5866702,b51417ce,7a436642,d87edadd), -S(8304c266,a9876255,70768130,ad244f73,668a6bf7,ac611ff4,e782a6b3,761e5284,e47adf0f,66d4cad7,5834e7b4,f1a26b82,d5f9285e,a567fbfc,5f7fffdc,3df10311), -S(b1d777bb,76529faf,3ee711d8,58ba2509,c378c99,4dbf27bb,deac9d98,cd0202f,11f7598a,55c079f6,7bd036e4,e3a3bffe,159477ae,45c33ac8,8321fafe,3141bdcb), -S(7b91aed5,408649e5,41ea21b8,326f9549,6228e3ac,4e460b34,d77a526a,7972e4f7,12dff7db,c620f9fc,4ba287bd,2744e1b,4294e723,cf475d58,22f718e,c2dc326a), -S(56e7d74c,a4e530aa,7ae803e8,734280de,d87092d8,78ce187f,4a13ee50,c3d58f0a,d69161fa,901bc6ea,fbe62498,4ecc70f0,24755a0c,100ace31,7e677911,5a4c038e), -S(c83cdd85,43dcd105,efe4312c,f8f5e73e,1849364,668f0e50,dc40b13c,1c44fda,bad22032,de13c4d7,f2a61ec,947f266d,812e8b3e,d7fed352,93d161a5,844c96a4), -S(fe6f32d2,68be724d,28d1344d,8406c60a,70a2a009,db4c8e42,f434534c,4df9c3f,339bc5c6,2692a66b,853a323f,d09526f,3b336c73,bb4cc097,7b78fd67,96506d6b), -S(c3f6f279,fc937a66,a494b2d5,3bc6c2ef,13088c8f,842e1d61,3c5a35b9,ef2fcb5b,41cde800,63e8bbea,b2246885,59817f05,417d5311,e9fc8b7f,6c247488,10b30d64), -S(3dc7d5c8,abb4be85,9f6ba28,67dad2a4,7ba7970b,ffd77ca8,54107333,dcea1dd5,851d695d,54d5d7d0,b7aeac6b,97a27a9f,2100fcc6,facdf142,c82cdf9f,79c5cf7e), -S(2e28aa72,54ca6c6e,5891ccdb,1a1d2a85,53008b29,77a04ea4,d5deb497,bbcb95d7,361191d5,945c523,8908e0d2,6c08ba77,aa7db32a,5f19e348,a0037255,4105f55e), -S(84796cd9,233a7af4,7518bf99,778abd4f,a0238434,b5239f49,fba6b27,90f67bae,deb650d6,be46f3df,cd80fcef,20317c93,618156bf,343e9b2f,bb158871,5ce40c2f), -S(dbbbbe08,e4c768c0,531a3158,9b8abc28,f747bf69,228d16d0,8b0091bc,b292531a,576081af,a5aef1be,9916bc4a,2abe3970,12e371b,4c05e5c6,c97879ae,9e73c8a2), -S(25f6b015,45a8e870,592d532b,de9e2e8c,feece584,1667235d,a1bac7c9,58350591,5faff24f,2fc43cca,285366d2,578814c0,879cabbe,cde4b557,e7dc6fe7,43462ba3), -S(1cdd628a,a5ae5c80,85e83c74,986dda47,1d12fd07,158b20d0,d2d58599,f4648fe3,57ed9696,31e1134a,dad47894,f40c3e56,852d1ae8,5fba733b,d46951ef,7b33e5fa), -S(255c35a5,ce78bb41,ce85bef1,9804a70e,86aee3a4,24dcffcb,47180671,475080de,783f23,71984093,7db83676,7c3e20b8,f216bb68,bfa8b90b,7d9d95f1,1bf2db1a), -S(517283fc,d1cf1144,4f7375cb,77af87b2,3a11ce7,a954feba,378fc420,a05a8c9d,612cae52,640568af,607af275,4f6060a7,40b89f00,5dc02274,f2c6b8cf,e81c2e15), -S(39ff6f76,c8e4b6d8,4e742b0a,67725f83,51b782b6,638a032c,f9690635,fed32d55,c3d54b29,bc4ab777,c027f5a7,3ee75b4,a82dfb8d,5a5aa403,9f0a8787,dc054b58), -S(bf620a81,d6ad1d03,a66ca76f,c3b20e84,2fc75ea7,ca7e1f64,9818b27c,902e1ca4,4894f0fe,c2aef2fe,67c8aeae,5a9f0424,1ef68975,955eeb0f,66f63753,5d559351), -S(4c34e4e9,7584b95c,9bc6608f,7dba493c,97022eb6,14efc494,fb721fc8,3388a06f,b94f610d,b8bc4bfa,cffbd677,264ec28c,be18cdc8,db64154d,b62c4316,e9bb59e0), -S(76bbfe7,d39d6e03,9be09174,52fb322a,dd3ea192,6b546918,41b97913,acf75247,7bed078,7752a432,f0275ba2,a97749f8,754dee1,a5cadab9,5482d27,3c99b1b1), -S(deef7e31,9decf761,18e42c7f,27f427e3,4cae0d54,d7a045f2,dbe68349,c5b011dd,d3e73e4e,8f89b39c,83c7855f,8b5e352c,64f7b8d9,7a00c5a2,4b1b7997,c1db907f), -S(23f66927,d6a94731,2b43d845,fd0ee2f5,8cc329df,8ec37f11,75392bcd,c8d48857,747d60ce,bdc9858f,cfb28fec,5841d362,5750dd35,d08d0f27,4f173fa3,2fa0c4c7), -S(e885b643,c668ee81,4b94240a,4a68126c,625eaf2e,6f9dea6b,230a0bed,dfe06d9b,b575dd15,7436244d,191e3b13,d1bc8682,76940436,16b52aeb,7c731b5f,120d4bd8), -S(4ae81c35,d39ea1cb,7e5787a9,6a7738ad,89a0aeff,c556ba4a,d4dd1c5e,bf5a4044,76a3e3f3,96b88cce,2c978354,16cb13c0,f74bf815,ea9c9397,86da049,64f06d61), -S(490cc37b,6efe437d,35043f53,682dcc1,2b2a4704,c8102413,62fe38da,44717b5f,fb5c012,b205a188,6f1d639f,228f6388,2c598299,d2d6ee45,be44d994,bb6b6328), -S(c408d649,f8524311,14582433,d4abe603,5e66413,e65dddf5,f2ce6854,95be8d4b,bc9a1d0e,18504133,4e4b43a1,9d34b07a,1b3f7cc7,290328a0,71437e12,ed80126e), -S(af445e25,7fcd5ac8,54992782,30280aa3,354d296,6d494f6b,90c883a4,829ee71e,f839efee,87643874,2440e65b,870b0e37,3fdbca41,e57f3765,2cf479c5,cb7f6882), -S(f2c1adea,d2f8e95f,ad6a475b,199cc75d,a8471b82,1da81d5f,6d8b2baf,a1ea01bc,8e3543b5,36247e35,c2117eab,9d3e6783,f48bc2b8,b20993fc,1a0ff28d,1aad1666), -S(17b3dfcc,fdd57cdc,8a617eb1,5ec80659,fc695bcc,afd3a787,fd91d8d5,69abb5b3,75f1aea4,70f52f18,d2eefeec,7fff7f48,6718f784,a47cb32f,4f2c8574,591c122c), -S(f4d6bacd,1c8ac10e,7e97a6da,8a7d1af9,1c96a67f,fe76982f,a0ac95a5,f9f5a9e1,ea6179a8,1ccba22f,4dd93b19,5e151d38,cbede6c8,70a4a383,edc7898d,1f8f19be), -S(8011232d,32d4bdef,1fb56ae7,3e231a01,b877be6,72567310,2c30478f,50652092,49b91451,23311b4e,6c038801,f84561b2,8db03ccf,3df20b68,b35714e9,56b4f67f), -S(e23dd461,b79f6b64,5da455ca,90711ab4,cc117d66,ea8c9835,67f70207,ac5e1f31,8e84c4d1,ea634402,375c4d4d,6e8c8427,fa2479fb,3461bb5e,5fbf1f06,d34c866), -S(a2f6486a,97afc8d5,8367a949,278dca64,ed265743,16827b7e,7f3710da,9d7dfbc9,a723d6fe,419317d,623f8e24,75b365d8,cee8cb15,d1c8df2e,218f1b42,a72e7170), -S(f789b715,a7d5ba20,c1f8cb05,86cfe13c,59d27b83,ad1ffca7,75b2cb7d,9af88999,149bda63,63072ad5,279885b2,be81923f,ac9c4d07,2ee57602,5d99e727,150a26eb), -S(24078518,7abb2bbc,721e59e7,923f9832,77b13422,912c983e,d8670e96,c698c1e0,7e2f792,7976ba59,20748e26,ce48b29f,6ca37a67,6c8b4094,e661d5a9,be39588f), -S(8703f78b,17ff31d6,89833226,8fa9db6c,759e6066,ef8cf8cb,719f49a0,d7af6264,3b9c4023,d92827a6,53a7798b,fb21fe94,cfeb592d,a55e21a6,8c6615ec,2bda7ada), -S(52f6da10,3d75bdfa,4e0e7637,229f0c31,a6f5aaa3,2504daff,e1ef639e,2daa16e9,5d71c088,e8480d6c,e51062f0,241d0b15,9bd143ea,451193da,e13466c2,bcbdd037), -S(c68fa920,9f3a997b,2cc91748,3570ce74,1a0dcd63,1d7b483a,6f73a3cf,17b53eba,1f26839b,86154284,28858ba3,a3084947,883053d6,3bf039ca,89753199,21e505ef), -S(ed2deef0,9f558dad,84202b6a,e2456f38,39755fe5,6afb5aa1,147adbb3,915023ec,40be5a33,a71290af,e5080e32,dd9fa12,4273f550,9e78cda2,395235fe,c78e3274), -S(3538ad8a,98625432,2e7a9655,4e12d822,812b87fd,778e4482,b255b6f5,5c301442,5a6960b5,d21b0a7d,4afd9c62,7caec1ea,e8fa82be,e2ef80f6,50c56101,ba3a76f7), -S(a9580d1a,2b6544ad,65e45228,8e0dbdae,ec6de5e2,e9efc056,ff048883,b9f435d0,1a70df90,3d932f52,a9b3123a,1384cd6a,cb5b811f,bb267179,e1e4407d,9269af21), -S(efcdd63b,3c964ee4,f04a6618,ae526958,db1ac41f,bc53978,84529401,c0c53a26,913bc698,4d51d792,919b389a,dbb2acb7,7b3df92f,138355c8,7cb3caef,8cc50c7a), -S(c518437f,7344d6e5,8cb5ae74,acefba6c,a2ad92f,57f407e7,29f39221,885a8e17,efab7c2,145a8abe,50b46c51,9a679ec0,1fa017df,7c82d27f,cd2f93fa,affb5ac0), -S(a25e878b,9cf81fca,dc06a526,a9162260,d42273c0,49e7038d,ba66a450,25fc75c6,b08a8220,ff708833,56702dd2,b4971eee,956b2711,2767448c,7f2e553b,965f7bb2), -S(ce0ed297,f5961a82,327a1d8b,2c20f8c1,b996815f,c951f8d3,3bd0c16a,3ec45c3b,c4d21e67,8456fc84,955240e6,984b0a0c,8a10eeee,f40c6a4b,76aab8d9,5e887e7f), -S(b33ac12,369bf1d6,22c2c557,7fda98e8,f6bb4389,fad53459,e824bfd,e4409229,52925428,66a98f73,aaadfca6,940490c4,91e4ca9a,da343f8c,76b7f6cf,588802d4), -S(958d34e3,58ba9546,ab139250,d47f6bba,59f13203,e07432b4,f37da854,696e134b,e0c35ab7,45e91cb1,53ee07b4,f04f1258,9eeecb89,c30d10f5,d0322a72,7285ef19), -S(cc633cb8,b2465aba,a9a4428a,5a36c8b7,cb2fca1c,9702aef,8d54d249,338dac27,b6933908,62597527,8299b8e1,5fce0cb2,1ed84a9d,2533250b,6e417d2,fc19b06b), -S(61b81bf1,3ae0ba48,eb630593,512be80d,c4960d2a,9f0a6589,65ae04d7,36b4836b,43589e39,7f4d8df6,562fd8b6,8d4ee7ba,9faf441e,b1b09b8e,22f81925,9f0a9269), -S(2ce3ee71,b411ca31,74f0c249,7feb6bc,331a492b,85480be,32193c25,6321f853,32669ee6,8062bf36,b8c8853a,eacf0826,dabc81a0,48ef504e,e2ddf10c,8d6cb4c9), -S(6ecfd338,ab60c9a2,a50cfd16,498dcb45,8e6ac09,d5517fbe,f95f54f8,1b5a7551,b73277ba,4b7486a2,594f6571,a86251cf,54a1a5b0,9aa3017a,b4c0212f,cc94ae22), -S(a4cde541,dd4897a7,95f90ed8,75907a6b,8406a888,dc807d5c,6317c7ea,7f226d0b,5cd7591e,a305d546,14ff4233,600c813b,414fad07,8c1016ea,b021cd69,1d25d879), -S(4961a20d,ae4956c6,dfd04d1a,a261bce1,ff27a2ab,e0c3cfa5,6cfe51e,24c20fe8,9bf8d311,61ebbf5f,94c71ff0,7a9a04b1,92bc6cd3,e50baefa,71de2af4,f38a8660), -S(4b099713,d4622a37,d013359f,67983269,3274d1ed,4345cdb9,96ef3550,a57064a8,dfdb479,e07a1fb,ae741a92,2a468c61,7ee4cd46,25b1041d,f554e0cf,7fc5a776), -S(b5ae6420,8130d080,6c568d95,8222a1e2,3e649a67,8af5f0f5,89acdf17,8f79e9e8,2d883796,a8f45bb9,7d30e88b,99f6b01,dd46d91e,60d20d1c,430c36b1,b8b8ca45), -S(f7f1820,23de8475,7591f366,116bd60,5312706c,2d380d7b,16f50bea,71abbb64,5e3844ae,1db871e0,c12a7205,baf101e3,77af946e,aaea64f,c9aaf9da,e1ebbc12), -S(6d2620eb,ee6ec651,792adf63,9afb0fce,ee933e69,337ab7cf,2ec85ff,917ef538,e159145f,6aeff15,2e0403eb,f3082906,f98313f0,77028f74,bbe562b8,f335b6e6), -S(a98cec29,2cad6781,d4339548,10609d7e,77f7489c,2253c04,3ec1eb03,a69eda44,c5eb7257,c5b965ec,1ee643fc,7f48ca4a,b612f616,6a3ecd7,4c8da3c5,3c4efcfd), -S(6a88d0c4,4055a898,28a7003a,1fdd9941,4c1adb0e,90ed8d9,acecadaf,6a73920e,6fe7abcf,25385db8,be815eeb,14302bb0,5a630f92,2aae66cc,b0d42ac4,92224c97), -S(8a101a08,52559761,e2c6522a,6bf8909c,2547ef9b,550ee027,45e23592,89c34afd,64248f75,469015df,d9045beb,2de9573,c1f2e2c0,9f7a4cb5,cc85511a,f7182fac), -S(ea84bd08,37bb25e8,27ca0241,2cb8bd7d,ae47661b,f2460598,7ac20c80,753249da,15be2ad9,d4a8d7b1,964db56e,8415c890,93214016,e694f258,96574d48,45c8a1dc), -S(be2f219d,60dbe256,57bd9b46,18f62e2d,7501e302,885731c5,34b1187d,2c750f31,f521ca05,48ffffa3,dd70e0bc,79602b6b,617b9ead,b64e7af7,3d9ebcc8,bbd220df), -S(418d2b33,ce151147,83a75265,a876a709,ce7f452b,de9933cf,6e7ab1e7,7412437b,52693c44,5e1ff5a1,89b856d3,9d413514,aee35974,fc4678d8,86d5f998,a18047c6), -S(3e4685e9,3c65f31d,c58656e9,a8913d19,469f5e,2d49322e,6a99af10,c1142f16,1ed3edbb,6186e995,8241f3b6,ff7659b1,bbb007f7,f9b5f91e,92d5a8b2,c780d914), -S(35e15d66,d952ab13,de14a71e,20b1ed8e,f4b3f183,db75c62f,9af7ab3f,945b2d29,813f47b2,3fe523ec,12557edb,9e1b465,4582de57,5ca3752f,2e60be32,eb4333c6), -S(f025b371,b5c98b91,6157e1b1,53aac27e,ed42d435,53ca159b,48940bdf,b0f8d262,70fd31b7,a5470435,7936f98c,cb4c27eb,115be6ea,b4de7a88,1151e5a0,4364f12b), -S(31b36d5,b52ea8cd,c0298c03,8fa4f99b,19b3ae06,65d667d3,639ea3e5,c73875c4,924ccbf2,d1890df4,783760c,e6e2f50a,8dd8838a,bc87ac29,bbf89eb7,f0b46eb2), -S(1d57ff02,22db5c5c,f6f1558b,f71f0498,b706c7a1,84dc463b,77b4e21b,9d5c1699,b6238d2e,1bf715fd,d5cc0843,dad6fdc9,e1e6d485,c3584dda,3d06a1a0,414a3b31), -S(b5b7da02,4a6626dd,f67917e0,63a3a64c,f389e8e2,a631853a,c8e5f45a,4395cf24,151c4b35,22b4f1ee,2105b3e1,4ea193b2,ba6bf1d0,feb4511a,d72444b2,66fa7f0a), -S(2a58e24d,7f43233a,55a399d3,7cc0fd91,9b451985,13bd725,e24edc1,75ff6163,4f451eb2,c7374944,7296e447,406d5025,b5da17ab,8567cf01,ccab260b,da6834f4), -S(d8e2416,99d7e8ff,15853778,bb52a218,a2ed0c45,c7ebbdc4,a7357acf,86e7cd52,e849021b,83d33fc6,826c0a35,3f4188d4,37273a7a,7adeafed,6514bba1,a4fcbca4), -S(27f9e422,dd1b9a6f,64092125,71543d87,7d8ed097,52b2e6a0,cecd81e4,659e1f41,27563650,6d56cc26,cd289851,2274314c,bef8da2f,a4b1ba19,740d8ab5,4d4c3e60), -S(2071b53,72a746ec,a0795422,ea0dc0e1,b105e1aa,fe2fdd64,b08ff2c,47f4067c,1c95ae4f,986047f3,d969e8af,99775aaf,59a94c56,a47691db,fa0175ff,17641b0c), -S(b8decd7e,15355cfb,dcdb3ab8,48b2d717,3d61113f,58d21580,9292d4ba,379a839e,2ce7737f,7dd82aa7,76560921,21cf93a,a5e3c6d9,952c3adb,b6fb1f04,4274ad71), -S(23c7a3a2,70f20e77,d62f3d77,a67535ab,5554c821,71c77bee,1b05d2e,5ea67557,b8657a68,e2ded30f,19365bcf,916037e4,a1d87db4,632c90cd,ca782e40,b27bfda4), -S(b9af932d,753ba63,f7ecf070,d20d4355,42de9c72,a93f44e5,7b978e5b,7428432f,c2b21fb9,64593524,104c980b,a53de2c1,6e7408b7,33e2ffaf,17ed540a,6253847e), -S(e461cc8f,ad51c58c,fea92090,c2d3dc1c,41971918,687368c8,4c84a04d,d094704b,c1b114e,2cccc522,6fa3f753,5b6f356d,fddcad24,86197d90,4ab00cd2,f3d0103), -S(817e0633,4b8e706b,b7282b40,a4e243c1,87b24bba,6bfb69b0,d5a366da,c383e3a1,77593627,482c198a,f29a892d,5fb50a43,d10b4fec,5937d696,ee8fc6a2,20deabd4), -S(30bc10bb,d203182a,f7dbcf39,f0ee3013,7f26980e,e5f934d4,f151f080,b1341e5a,40fb3e2c,45dd0832,cb50d0f,4f45025e,3285bb6e,adefa1fe,4192e4b2,8a77197c), -S(143f113,8c45ea5e,a6bd339b,8d1aa91a,9db0dfba,90600868,309c0b5c,1a97648,e45fd7b6,8d025855,1c35285a,87fd77c5,1403c836,e0697b9d,4dcca76a,1422a6c2), -S(f3d30c38,4926b19f,5bafd37f,ea9b7c93,d4776564,5b8b4a89,199ed005,883e8c69,2f6179e,26dcba73,81ec7e57,1eb427f3,455808c2,21926af9,79efdcf,c7ff364f), -S(54fbfba7,13facf23,1013a1b6,ed7514a,4fe11323,3c363ca5,118a7d9f,63b4c116,dbfbec7d,152e7c9,2bb98067,37e926ba,66ed85fc,2339ad8d,410ed762,4407061b), -S(81d00298,aec59abd,c3ed4b5e,11d4589c,9c7a7ad6,54add200,ea6ab124,3b0c484b,226d41fb,a46202b7,ecf1ef9c,11acb33a,cdc15547,7bbab0c,1f56f385,6401984a), -S(2c088e50,50061a7a,47d84141,a858df75,f51c5c17,717b35f1,cce982e1,209712a7,44700a1e,99cd0f9e,8d05c8a6,18a75edb,d9d7f67e,45f5f40e,4c00eda8,290212e3), -S(2c903ebd,68f2053e,7a769b86,bb017939,556b532e,1b84cd7a,2397b1f7,f108a145,2915c5b3,f16b1eb4,8ed436d7,4a79c50,72a2eb02,b989da66,b164d475,941a8b14), -S(ffac0b8c,76c6b7d9,24ed25e,3f43ffa0,b261141e,715c07c6,c327a719,6b11fd43,9c25ada3,fe7d1661,1ba95eb2,231f00ef,cd250e16,68dd85d3,96025f65,4fe7da52), -S(d81236c3,7d7dda31,849e20b3,c7aebb2,b782a1e6,17b9d6f4,f56da4bc,d860c573,ac6628ac,98c0896e,ff1802ce,a43ae085,66e902aa,abd2cefe,b910465a,9f0fcf30), -S(19d94647,ccf05308,32903c94,7f149f0a,f1f7503f,92300232,a6f33e15,7874e321,3402ad42,87ad0814,4addcf3,2f7c60a6,6f65255d,ab4bbe,b10826f0,f5a07f39), -S(2248a7b4,37bb8bf5,df85b382,224a3d68,45965330,24f8c872,f81e2c33,610ac810,c3942980,b054122c,e806a67e,7f004b18,5288ff5f,d7e17ebb,97e68e64,1c416bd1), -S(d8a71ff4,a9de84f4,f28e78e9,4815ba2f,dfe48256,7128d149,e44d5419,da84531b,d3258392,34c87aed,8534e6f8,f03802b2,e76a5f20,552873c3,991c8d31,346f67d1), -S(322a4b9c,32ffd7e0,2548cbe5,9f50c2b2,e2a8c70c,dec7e39d,61505a2d,4d780ea8,809f262f,d258b1e5,b140822b,caf74d15,9fb764d8,53b653f9,7358adc,5891b0c0), -S(4b7a2f4c,e7cdc092,9bdf7d1b,bc91a60a,2e16bd9c,ad9f1cce,38ed644c,3a790fd4,5adcd298,78333b26,20d43235,8178c2b6,a4e697bb,81c3abd1,b850a334,933573e8), -S(2d7d8029,8da39ad7,ae7ee3a8,583768ff,fee73a78,728ffdda,b3921988,2ba3d8b,6f9e5aee,bd08f707,a49f120f,26869ec1,cfe9d9f2,a6e0f0ce,b6ce545d,43951358), -S(256b5db3,24dccb17,3b525434,ca36d6fe,37d469b0,4484dec1,cd44d392,b0f7aecc,c35db3a4,61f0f477,1a5d0131,12be5a90,64bcd516,2566a373,daa82b09,415c84e8), -S(9b641c2b,b2e3ee32,cf592c06,532dcd71,af0a1196,3a82c3a7,c0e809d5,8cc9b65e,e5925900,9d981017,bc12b524,b00ba98d,393be520,651a7b0,ea8f9ca9,75142814), -S(69700df9,b800a1a0,afa144c6,3a637027,ae53a786,e9938345,e147509e,ab6d44b7,227f91a5,b0492dfd,1e9b5d,bcd02bfd,4678bf86,8e69b7ea,e97e8b17,1aa1babc), -S(5ab9358b,a7008f2e,75392981,d93d062b,849cf9f2,216c48d7,4887d50a,3d8ae5d9,7b8e1ab1,9c6e9f7b,89a524f9,e39d5a40,90179745,1ed87e58,23f23625,115043b1), -S(46fa087,213b7db1,32997f64,cf9adee0,149adaae,e4d7c9af,61aa3193,606f12e9,2c428c7e,1c80e6e8,92f89777,d8afcb8b,8c0dbf3d,f8958f83,6ff1504c,e0517443), -S(c08b8c75,cede8e1d,c3ec26f6,ba7ae08,ec22f798,aa89e258,a0291e30,ee0c06cc,8454d21,18f72ff1,17866e63,5f65c349,2baea002,97b16e47,ef8876f,d8b7f5b), -S(f50450ff,aa054493,b0660d35,521d1ce0,156443b6,f5327e68,31385219,8e39ece9,aff228cc,970fca4d,9b583c23,b8e6eda4,feb549a8,2d767b4c,e535f6ac,d68d8287), -S(e80034ad,d9f421dd,de74ef1d,7a7e6e4b,fbe2dc0e,5f50b05,f7e8560,3c52ff0f,ef285764,dc9bb2fb,e6751352,a1926075,331c4abf,51e36cb4,36c9ee36,fea34e10), -S(cdbd6ea4,b3580bd7,29032b34,7e18c839,4832d8ee,11fd7a4f,c9c63986,54790037,80f51eb3,63d9f7a1,1e4508d0,643dcaa,7fd1570a,8d3e5f71,8371e118,d29f340b), -S(7eba7974,42a779a2,5d3ece2,a022719a,94a14eb8,e6f821b2,136c0d1f,f5637f70,5cd4f314,75808559,77def43a,9c974f4d,ed3772dc,b9091e7b,28745827,477a8611), -S(b44980a8,5e5fc57d,83d9791f,54418ad,5337eb5a,61746d6,71fb200,b5971f82,ff6cc373,5122c494,fed9063b,c8ad9e04,9842c639,db750623,997570e8,76324da3), -S(71057596,36c41dfa,b4bcd0e2,5c5d1d47,e60b283c,4a9762ec,10b15464,4cb07802,3a06998d,23644db2,b9cd18ac,1a077549,57e1cb99,d75ab6dc,c81db6e8,dcd947b6), -S(c134fd2f,c63a27a8,17e8f797,a120ed41,707067,c09931de,73e71fc1,84b1015c,5cd78606,9cc187f4,a3d2acc5,7b41d22d,cff9aa26,235ec094,c892a111,8488fa75), -S(8942fdcf,4cb81983,5e03559b,c81f4da4,bdba287f,b84c0ff1,2b023658,e389e146,e50d5d33,b47da2df,3130c838,5667c158,f5034d02,bbdf0be0,5760863d,a6cf2120), -S(3aed32a6,5d3188f2,ade2e91b,552d4c56,5d75c72d,dd51efa7,ff2e2e4d,49d71c0a,9f980569,e231ae71,3f524c7b,a616c342,340a1cc7,2a0a78fa,461c732d,8b3571d0), -S(5b824633,8060ac28,f228eee5,405b10b2,8b33ddb9,9d09aab5,c8f32ca4,b3aa59e0,ee4e5740,206040cd,91c46d93,24a94b6b,6439e517,cbbd0619,80b5e4ad,91938e4c), -S(4eac5700,26a7997d,b5864e0d,1e7fff74,61cccb83,aab89c90,bed839e1,a6392220,9506b28d,aacec4f1,9843944c,690adbc1,ca8cb6c4,305510f1,31521569,fbe3281e), -S(c205259a,feb286d9,bae84b81,debad402,c60a59e5,68a0f4d0,204e909a,41119044,16dad4ed,eb541c30,38af010,5ed75ebb,e281de77,c3e61e70,344ad85e,2ca34662), -S(dd215ac7,a8023c12,a7752db5,89b72cdf,90333791,996f7f01,67162221,db0b131f,8436a84c,4d7af578,2c377394,26012793,b99f5c4b,f6c37a4d,a2ff2847,c4222a6a), -S(2d71215,5647ace7,88354c3,522da12f,fc44920a,9fe67b1f,e05f9eaf,19997db7,23cb203c,4c904541,2e942d3,da6cbf37,3f40a1f9,b6d896ab,b797955f,3666b0b1), -S(59643435,43bd6f7b,658055b,2f9e5966,303c276b,b79438bc,10014301,7b6b04ec,6bf6b2cd,7c88a172,25a68dad,e029bb0b,26137995,cbcd9d5d,8f93c6e8,fadb52d9), -S(1fc70dfa,bfb7cf69,21f682ae,ebdc182f,f0ba39ee,8c28b779,325f9e7c,152a00cc,f79507e5,51c7b44c,c9525d97,5110a19c,3d51593c,4aab618e,641d6de9,466d8df8), -S(d1dbe6bc,1821a383,d10318ca,c23cd56d,17106937,42609427,edebb18d,9ff8592a,b45168f0,d49ba0f2,6a8729e4,c860ff1d,e1dcfb0b,7c1ff20,48b2cd15,be043205), -S(4d15bd89,53a4b5cd,5d11a16f,728397a,744db565,cf744494,b67b1b4a,ff07f375,9cfbab6b,e9cdb650,fe7ef824,c3118722,e68fc601,1b8e84e3,e7028e69,d3235565), -S(dec346f8,34a5575c,d58f3bc,86ca0d8c,9ef3f556,5b091917,c80f467e,fad12a98,20741ea4,793def6c,3b46e8d5,baaa6e4a,1f529cb2,880b4142,ef0a3ed5,6d445efe), -S(ccc91a35,3532454d,9fb0d811,941eeafb,890dc07d,ab4c117c,f9547c7c,6b45645d,9e25533f,2f6bd1cc,2fd8624b,a64d42db,fd8ac325,37f09c7f,1d74fe46,40aaad82), -S(feb81407,df6f1137,e257c20c,f58a77b5,83ec8f2a,b5acd9e7,12ebe6c1,2aef1d60,b7279d4d,470318b7,86ea0630,3e78981b,ea2aba8,162adfdb,5a8949b6,1c1e3e73), -S(ffe40f24,eef97a34,e57728e7,7c445209,29058d51,1bbe823f,b354f853,63009c7a,c71020d3,2946f80c,700ca0e6,a6dd43cd,a9461db8,a25b67fa,92008da7,a96e680e), -S(a36b2254,2f8d9055,41369ca7,793eb500,2f6d8a69,410086d1,ded6bdca,692d1b6c,b9b73b65,e69950ad,f25787d3,897738b7,5306afa6,8156419,892799cb,20a9556a), -S(92a24def,2b893f11,b0056962,b41273f7,76fa4a0b,4d525f3a,14236756,3d5b240a,9e9ad443,5fda1d46,a77ab3fe,62971060,8105f5b,a6d9fa83,47508d6d,7bd8d288), -S(8fd20215,ba152223,ecc28d20,749ccbdb,9d536b64,77474808,9d2cbac3,e0a11f77,434b10d3,33418084,ad2c42a,651b52c7,bff040b9,333fae3b,26935997,7f6be47), -S(b4e6caec,c78da734,80884183,d0aefa0e,82001bc8,2c376981,f40b5c13,4c8a034d,95f192ca,cb5059f4,3c6323a2,a0e09204,4f39ecfa,92c22dfd,e0bd5365,5b500c3d), -S(9536a1c3,ee4b8aa2,8edf3a0a,e2981657,df90bd4c,c62be8dd,8aad1a85,8c4d84c5,fcf54bd4,665ebaa2,9ea4d2ed,40bc8a42,34e6e061,e325abe8,2a123b06,36d99d4b), -S(3e15d13c,75ff91bc,5e928cd,ec8e303d,286deea7,d7a4d88f,6613dfcc,a0c27c59,f98fdca2,1e3dc253,44ffab,2865181d,b830c74d,2891c80a,b71a8,904cf13a), -S(8215dd74,1eb7a889,7895feae,170dc452,f8fc451a,2037af7a,fbc02813,827ed4a5,bad149be,dec24412,4f65003d,d44656bc,5e61e332,aed71f73,b58492ba,ede0040c), -S(7b3755a6,3913920c,83a2ab1d,6a738122,bf7a67af,ddba85a1,6b9d7de9,ad6cf0ef,25752fef,1ce6ae9d,4f2ce922,fc610ea4,d4351718,f8e97bc8,bd4396c7,11697dc0), -S(cdb499d,f67a81dd,db28cfbe,bccdf877,4f8b76f,6464ff8c,221a95d8,3e3ffe6f,4b08bf10,15fe6b37,98fa8da1,7438fb88,eb96720d,495d22c6,336e0225,454268eb), -S(ac0a10fb,b902bcf8,205b2529,7724073b,55fa2837,dd99edae,e256f7d8,7c19aac,7ed1aecd,d088097f,4ec8b005,892fd069,ddfc319e,f5bb3b25,2ab7c597,d775e615), -S(1e9e3fa9,fa96a4e9,4f19c5e1,105ffc9d,fd7add4b,63c85ac0,5098c839,c0e851fa,69bffc28,5927b917,dc4dc5c1,3ceef964,27dbac93,a778a01e,227906d,6abf9df8), -S(14359ebe,e923252d,f17e2320,d97a991,c16d7819,d9791f86,65142b93,4c2bc20d,3248f24b,d31f47ef,dd34853e,dc84f8f8,17403b4c,eb737d8e,c144daa5,2e5b65da), -S(13363dd8,56df936f,35f1bb71,eb2fc4b,df232e76,1fd9ad9f,db3a6d6b,ae78e837,8160695a,7428e400,9fc88172,faa6784,b3a2d03b,71f89a5,89dd85e2,f5565436), -S(6b71ab46,20938910,bf2e16ca,6e40a653,2c6c1b58,b258ad04,b1d51656,3a5520c7,2e72f5ef,4ab06562,52e224fe,1c670b2d,39630f97,f78ee55e,d1e01f5,c967d988), -S(98f0a6aa,7590ffae,731263a5,b940dd85,6d0306c5,ae98bfc9,9d164263,ec14c21a,284bef1f,a5a54c96,f5aa7c41,ac50c5c,fa88c352,52b923bb,92da72c3,d3d7d8c9), -S(78d11179,5965328f,cda22443,91871ee2,574c0886,f82e942,12e261bc,f5c3b9eb,83802a00,84e8b578,4450a423,1bc1a99e,6b9b545c,e32881c8,8487bc45,59604f84), -S(f0856a2a,2b8b110a,dae99427,9af3da1a,a74e1b77,46d4ece1,f054bc55,905aa49c,1a80e529,2b4dd9ca,4785abff,edbbc11f,7111663c,3fdf55f6,ec3031aa,3c5f0890), -S(2c5fc446,44d1e735,3e2b3374,89eb432b,f4dfaba3,39051221,4d279de9,87d6df7f,76c8ddf9,d2339112,c10ac9d0,5a473d28,cd066ff1,acd63e5f,b49bfb8,bb34d3cd), -S(3cdff15f,9953cb19,62cf5024,4b8db26e,8180090c,d6baf7f1,f60e6184,73a9336,275922c7,6d4841c8,324d1ea7,9948765c,ea399a78,51939f80,15b0b7dc,9f22d37), -S(d36724d3,91d3fc20,d1273367,97f8d961,18543b2b,dd40a77e,88813634,1c5f5d21,bc81050a,e6cac0f,ba1bf5e7,f1232d5a,a90d3b29,a0fce8e6,4dccb5f9,3e6a4d14), -S(f91cc30f,acc100f9,ee054e7b,5aac0294,e50035b2,2e7f35ee,306a30a5,1d5d6a00,328094f4,26ac3ce,71d53f82,c3deb250,be6a44b,6704886e,424e524b,c50f3e65), -S(48c715e0,da1ce36a,13cf4b8b,d5294baf,84a3fb08,b353e43e,e9f37481,ca2beeed,9d7e13c,f09c64c5,fa4a852e,206cacc3,8d398693,31368cda,1b06d242,2f8e26dd), -S(74ca89db,72b0796,af9b6d5a,57296952,1edae51c,5a3e8a76,b1746b87,4ce9de25,c770dc38,db1a585,43367fb7,979d7016,15a0a112,61064596,ebb40e63,e41ec50f), -S(36e77506,6284060f,8f8e709b,88b90125,f3c696d5,64bc048c,8dab4b93,40fe170e,b760473,d66e32f0,a716c1f5,ae462b0a,b5e77e6e,2e30fc58,e5ac1099,eb7105db), -S(a0899b68,99176eb,77c78eb6,d4a7786c,8afe1898,d34d3cfc,5f286528,409da4c5,f57441f8,734c16af,7ca6c64a,6fbe557e,11463e6,6482f7ff,d46f1b91,eb2a3cb8), -S(3503ac4d,9c9fffeb,d188d81c,9a92e506,a91fd15f,6bc67dc5,502b3ae4,d39d8e5f,dd66ff4e,40a5da17,3d3b143b,60534b70,33a5444d,98ed15ee,a6644e10,766b7918), -S(7765e5d3,2ceb50d0,b9bf9a80,48179d59,9fbfa214,4f183c63,9de26485,a87590ea,2052dbf2,718975cf,3c225235,d2504b4a,6b9026ca,731939dd,6af8ca08,9bc7dc26), -S(eeaf76ae,d4e737b9,900d4ce3,f39a880c,e060eeb5,208bf4ee,81b173a,dfd193e9,5490a02a,4ad8595a,6afd6612,48a80146,14366bc3,4c9167a,f290e164,f32eb9d), -S(f64a505a,4116a861,12914f01,6ae52fc7,5499efe2,32178ce3,d653b030,5b0cd0b9,4a8bc675,8353b7ec,e89096ab,aaa42a2a,e8af1a51,2e6f9323,1ec71644,1a09ef3a), -S(e73f95b7,b13f0907,53ba9ad0,c8b7f2ce,83ebea09,cffdf313,868a6ade,ac9c9efe,17986166,e766d323,cad73824,8eecb239,255d37ac,af72a56c,69594ffd,78281818), -S(7d2f8553,a46fd9dc,6fbd149,abd07161,1f279250,d508b9c8,b22eb2c4,99145d36,b88723c7,462f5f81,f69c92c4,b204f499,b3b826d2,1c05ceb6,a30bb285,c4bc4fd0), -S(32dd097d,96318d8f,69cea5f,f5db9476,33aace77,9059fb08,4177b8cb,36cb334,b078ae96,3cdc78cf,bd0e5bde,532a1269,a752c8ca,c8dfaa81,6ccbf4b1,2c3057aa), -S(7caeabfb,be7e30e0,345161bf,8380e160,2415178d,314caa33,b3c99d55,1c99f506,9a449ab,6cc98b09,6487475d,cae39e13,7df05d2a,f7863080,393ac16a,802547e4), -S(e5783a81,16e1e396,4c693fa5,919aff98,bbb954a1,e8503974,a27af353,3247dc86,d9d2c1b,633e2217,b66cadd9,dcff6880,be272900,e1c966d3,3726ae66,21860fc0), -S(9c7f5cd9,c274177,1f00e117,a62bb197,d0a8a18f,2ad23261,eb04c91,47561c9a,6652063a,9b2a5abe,38ab7b50,5768a5d7,e098ac86,bf127b48,2c56a417,175cb5d5), -S(fda48685,28c4f2be,58cd9b00,6fbe1121,ef009361,f0198b2,f5c56b44,1d28e9dd,3055bc29,fe08760c,ab624154,ee98a506,9de9dee8,c1db40ff,b972db60,30af98ea), -S(ecf9f4b2,2feb14a4,14628d74,8f7e55b5,886f7d18,d107e4b4,f985df5,163c3eb1,cbbafcf,84606b89,63e4013d,3c730edc,da808338,3f681153,307929cb,905beb69), -S(ee0ca18,25428e9b,a4c0be5a,8c9da473,f73c43d1,54a6fc52,176ffa4e,c05af36f,c8b960ec,91139b08,25face64,fdfa01fc,7390804,3c4f691,bf684dec,bb10cbb9), -S(744d4c0,fb5536e4,99b0397c,8cb127f3,68865b79,fbcbdb37,ff9f9c8f,59372ebb,b9ae4d36,489ca0ec,c318098d,663fe8fb,aebf149,fb28abe2,15ef6f43,8e414a4d), -S(910d358a,710c8e22,314b9eb8,394a7770,4549fcce,c98046f9,9c0a3e04,90510c49,5ba779b8,530e57a4,fec63e86,188d269b,6081fff9,d3f49bee,b0b62e29,540ae214), -S(2434ca82,89853823,57d1f537,ef02fc12,89300332,6acc9c67,ca2f3b96,691e94c4,e4608778,311bb1fb,f88a771,f6281a0b,7f850767,af4b9699,77b1fd6e,8df34d7c), -S(cdcebffe,d7c410c4,18cac7bc,cba49a59,b3ad5ffb,4c0577ba,19e25dca,c16fbcce,9745ea09,ddeb473a,a0b861f3,7d16d83,a8a73289,d278ae12,1168a6a8,d6bf5595), -S(826f49bb,90a6b195,b7de613e,ccbd1230,930c0303,d88ee0b7,a7c40b66,cf576a56,230ee0c1,c1f86c3f,a79e98f7,e63a7a77,2ad22724,ff6ae39,ea17cf43,e2e44c8), -S(d8bb1cea,9976a5a,ef1a5e6,57b70b09,e59cdf59,c67b4de8,9694701b,fc73c7c0,e76bb7a3,60759c9,441424cf,46aaabce,331e749c,80d588da,e3039162,e1a95d35), -S(6f475ce4,d1c3ee7d,130d101f,fde3f250,d1a0d884,2239ef78,83d67254,80b750ed,13c5fe82,7c76f2c6,4739839c,4d8ab9fa,3271dc83,b949d123,532cd0eb,71809e0), -S(d8d129e7,72635a5e,bff00c26,8ea30c0a,bbe3c635,d49818c,a3251082,fda4363f,4c4f8a79,d88bdf32,9b7a7121,7572da21,f89cfbbf,22547269,1362d5ed,c50b471), -S(19aa085c,e17cd19e,c610d3af,91d9a263,3d706773,1d5f6891,e31de7bb,39d306c2,aea04c67,efe26,c46dd958,e8fb2d4b,726e003,2d33355f,e7d256a3,842f75b9), -S(3712aa15,914e6f15,50ec12b0,f7dd6b2d,854d9f95,e86e7d2f,103b9925,dea23828,f5435b64,af251cc8,72c9123f,964c1c75,47457e1e,8c8942e7,852f4fe9,a9240c84), -S(f5b9a5e4,db49b7fd,b00912a7,821b8c37,a89ce6e0,12286f40,852746f0,1d4ab4b1,7ea00e84,d03d8654,ea03759a,69a3b055,60af6f38,55dd2ccf,a2e4da9,f8820114), -S(4ffbb51b,563605a5,eb7e784b,93eb7ed5,83c65968,1446a776,443cd436,e86d9f13,ff8e7729,e235ae1c,9d0ff576,5dc8763c,7bafc9d4,f3eae4b3,b7a58871,add58688), -S(9b3fe406,55f0a924,ddb0cb1,48dbf03d,5da4f1e4,e8b7307c,6b261915,2fd5c3e8,46dd956f,583120c6,91961916,1a46023d,da55bc27,b0717029,748673ef,b6aa318c), -S(86d8917,9410b427,b8008d10,3e481c35,2f089dc3,5c263804,ca86e08d,9da279ef,9aba2027,c3e47bda,aea2eb58,617ae633,83379235,7c233d30,e070115,d46ec081), -S(414b3ae5,23a76abe,6ba71141,8ac0a61e,4915076f,a0c2528d,e20a0b5c,368d2245,bccb169e,3091f7af,bfb8a251,958ffcd4,6f0c8c5a,f1662640,6c7c9993,3fb8fdd8), -S(7aacfb93,8644090,57ef8ab1,63bffd25,d8d43166,e8f31304,57779b20,b5da5998,257b5c42,2cc77f41,a6234a9c,1ae8d2f6,e91fad8a,78c39a6b,1d380a4d,7c9684be), -S(2e51b2e3,72a64010,92ace7d7,b263f897,ed629521,d45d962f,2876c266,3e42d7f3,fbd258ad,28324ce7,6bdd4b38,44517a40,e5cbd237,3bdcdfb0,862e768f,8e6dc5eb), -S(7721f122,e26e0fba,f6a33521,841be750,5a47dbcd,941191c9,432bc25f,56aa6e55,65e23e03,f03785c7,c81695cd,b49dee81,b9f678fd,55325ce9,dcefea04,f11a79b8), -S(aa7443f8,435fd4d1,e2f1dcc9,bed52a07,66f3c62,543a0f3c,5ed7f593,e7933f9e,858be190,a656bcd3,5b377138,2c3176a,45e0a53c,8a346743,e1c595eb,f992c70b), -S(23a3de7f,147a4ca1,bcd19afa,a8e71a58,27c7e7aa,c7db0c3,40d37b4c,e97a76dd,5361192f,76a37f5,d02e697f,288daf6f,34313d58,4e33344b,32cf1c0b,2c711217), -S(ab65c884,73b68402,5929fefb,322667f1,bf02efdc,d33552ec,4d743222,2b2d7352,c2949d4a,af2c3ed0,f9284466,a572b1e0,34e56e23,4c928646,5427d60a,2f092d63), -S(5d82cbf8,71aa4029,b16d09b6,ed1a22c2,6a94bc73,c1bc11c3,ae27042e,92fabe78,2610095f,c1dd2eed,adf1ecd6,a5b15b0e,5c714fce,87f424f1,5c198588,8b2ae3b2), -S(e5338bf1,79e3b22a,306e3f36,5121f94d,cb5a072d,6acbedf3,87263387,7ee23090,a8ce14f9,36d0b486,3db6f79d,d10922f4,395804b2,37035103,b59768da,c1f8600f), -S(e936f432,e5cefe07,e4e290ad,823d90a5,c2701eea,57bebac4,81b97400,b8964544,ebb65cc,15843766,77e34e80,b665567,19189319,2a298033,a4786974,5152b5ef), -S(a8f4c429,d93c81c5,7284f59a,a3a941ae,536f7c2c,e3707973,ac3eb5b4,a0ba1ad1,4e39b9ef,5e1b885d,b3a8e72a,8c069800,fa539e6f,7f6ffb0a,4b22ac8a,66c8a83b), -S(76ffc741,af278fae,39081989,d884b195,9cb7f240,d80c35f8,989310e8,64034e40,3df6c05f,12b2ddd6,262e3837,5c2876bb,e0f7b769,7d4cca13,be11c55d,cfaf6618), -S(eed12546,217f1270,505f9235,b875f6ef,1ea38bfa,6e790cce,97d491a7,30683809,6edd20bc,75c215a2,9a162bb,f19b757b,ae5d22d0,1c7a68b9,e2e0b01c,21e4d193), -S(8a975564,196e1add,526576ee,dd330a0b,bb1dd32b,85ae095f,79666907,15637aaf,5ba79be4,6db3fc66,c2f9666e,86162767,4c408e7,241ca378,47b8b3f7,ad5c3c48), -S(87728750,a68695b5,a23a86a0,50e5a015,e721ee92,da191a77,a8945c92,e356f3bf,44746e19,eeef603a,9115bdcc,b8d4146d,a928e723,e1736c9e,a352e8b8,8bb5c6e4), -S(83e9abe0,c65a51ff,c9e70748,35d1263a,5c31db10,6647e6fe,1ff9613d,6ddc6479,2b956ce9,1dc3fc78,b5d2c0e5,abe82eb5,d1fdd4c4,f2fcfed2,acbac011,4950e7f9), -S(89f0cbc1,5c7c60e1,6503fcf8,8c70dc2f,b3f18eda,3041ab27,e917b93c,a837b60c,9b25624d,1e3d2dc7,7c4a1b6f,4daa6020,2246386,b2007dd1,efb0043a,300975b2), -S(b64246c,e22786aa,8f269907,bb819041,dc564b0d,c6e14987,c5ac8fcd,a7f5a98a,68d776ac,5200e1d9,68088a72,af4458d7,85dd81f8,37f877f2,f4884b4a,3fb4d5d7), -S(babdf57f,ca92a314,6884f3c6,509a27aa,c8793214,49f55c78,7eac3531,74074127,380fff63,5aebe191,3c6e690f,76045577,21f65949,6a1df010,32726fbe,ceba0038), -S(92eade4,5d8ebce6,3685ed69,56caa62f,2f9eccd4,55f57bc6,4a75010d,20ac2df6,3b5babc7,16be9c71,e87bb0df,54aba5c4,3bd1f820,40d98f83,f2911eab,deb32573), -S(ac69071b,c1bf2a3,b01f633b,fff39f4e,3c5376e4,620278c4,ed9d98d9,5ef7025f,252a56cf,7d6d2835,6defd43e,70e6bddd,6462bee,d37b5227,d7d9fd5e,3b95fc6c), -S(f05e2926,848849b2,a7d9b980,c5e18d11,73db7422,4a3c476b,f2c44b,4d81b49d,59aea3ba,83cbdad6,4aba7857,1228acd5,eb574350,a9d1940b,68a4e495,2ded3c0a), -S(468ccfbd,aaae8f16,b91f4,cf41ec7b,f65f5832,8a3543e7,106dedb9,be4896fa,bfa82375,5e234421,19a18f8e,d182c52,1caceef2,3811a874,8d30b143,5676a186), -S(92452b56,58086172,625ae89c,48491669,e5c38d6,6280163c,397169,79578e09,6cc0e425,1da8e662,fdd858ca,e213cfb5,ae819d79,23372d39,d5a9722d,66543782), -S(3e201b8f,ce5bc832,c336c15e,2daa7770,1835c00e,3852cb19,7a9d4a2c,a902e287,5096a11b,18ce12bb,27f935b1,3e664d26,2cfe6be7,33c8b5e3,45cafe32,9f0804f0), -S(68ef4ac,e421f24f,dd628a01,56caf9d1,24bfbfb1,d6651f35,10ca5e48,5bfff389,8ebf4cfa,190aadca,b04c256e,ff0fbb04,bce8b360,3e308fca,fd8dddc8,dda15ce), -S(d2e44a05,64718ff2,85c56932,8d8fa7c5,530977d0,56fd8090,972599a8,461b5d39,a16bc6e7,3d514070,702db8bb,34f3cfa4,12099e19,da5eac7a,f87076f2,88b88bb6)}, -{S(4bd266bd,4a730879,cb06d8dc,bd8e5854,c50b6221,d83e0a10,3afcb2a9,a64cca67,a4654a1d,835a51f0,5a877200,1768c549,909212e5,78e3b1d1,df935959,93650863), -S(c275fe8c,b742a78e,7d78945d,34d988e1,202e1807,905ee89,d348957,f44c319a,88aecab2,7d47654d,df33617a,5fae27a2,8968ebd,284f5970,e0c39a2d,1e8039bd), -S(9dbe3dc5,ca9889c5,af21701e,11c60d,2eb901f,d0981d51,faa8c79,8b766a99,26878a40,fb4f091a,7c82cbea,db50bd98,8ee84e91,f58cfdf2,647a9de0,39f614d5), -S(4471b988,ed964b29,87a79324,a251f228,321523d8,1a7039cf,43af4c90,f63c3ebb,8196836,d28e4dee,9022c609,4f078448,72e70cf,c0b8640f,a28bece3,76c5aeec), -S(a7f5ebb1,7f00f9c3,d51ee4dc,ed4d713b,916b8049,17604d2c,1c6ede6f,4a9308fd,954f55c5,83d49978,cbe0bd27,7b2eaace,92e43012,bc31d63d,6f8d117f,e1e80223), -S(f80df047,a066a8b8,e1c6c6d1,12af4a5a,92894eca,d7946929,264b81bf,b060db7b,b3295268,6d708b49,73f0861a,3ba7256c,709fc322,9983c28c,6a76aecb,48032947), -S(72a6521d,60423431,a29ef70,73467d31,f654034e,3618c2b5,b9ae057e,b6c85b2f,f2cd61c0,58988546,7197e84b,6ee01d64,d200a135,542d5a0a,fb3ad4de,507dc900), -S(e1bc0481,d40b97ad,c4eaccb9,377674d9,ff106f94,9b3ac081,965b5332,5c981be3,a717e82a,d9ee2fd8,c07e3c96,a224c449,bc16032,3d0f0f1c,5e5b0f88,47f3a7d1), -S(e44aef3c,f9651799,f07b2ed8,b9e86780,fcaf26e1,2fe122e1,edeee3bb,a45cd461,c2a599d9,cb14b881,53a18c84,3831c475,4245b403,840e8cfb,6442446,d412785a), -S(3db8c67d,1964077c,bff351e9,ff770afb,5a7836ba,8e8916ae,2246c183,86e17177,1c02f899,1cc2b1ab,94affdf4,a302042b,db88b31c,5a516b4a,6d63a667,10e7ac32), -S(107e06bc,96acffed,cafb1205,26c61c9c,7a67618c,d1d4a1f9,24f7ff89,febb8316,aaba34b8,7ea1b235,720b79c2,b84ad3db,af6da2ae,3447df19,77e0a08c,366b3cc1), -S(b8f30382,716e92d9,7607837d,b162b56a,8b50dfe4,76f5f700,832dd55a,1e686a73,90a4b3a3,d11e9bcb,55d76467,a194f32c,e2fef47,1fb2408f,b71b9326,3c722688), -S(a3d1dd0d,8a5181a,b06639ea,f4f3111d,3de0ebd0,5567b9ad,56df821a,59191b04,65b8e7a4,fbb854f4,3699e509,4a9da6eb,f277a0f7,a38dce11,8dc924f1,ba916726), -S(44f3f1a6,8fd1c5fa,9de45857,7f320273,69cfc6ee,5e30822e,cec0605a,dbde28e0,400f764,2566009f,a7482bf2,7ca5b0be,1621b94b,ef42f693,417412cd,835c922), -S(d2eafded,346b24ef,633e925f,74178ac3,5e6f4d32,173797f,1f51e12,2ca65f7,6d30ca48,b1f675ae,1e1978ca,6c05f542,2e2864cd,a58480cf,517960e4,f373d79a), -S(d07404c0,67917364,7b2e946a,87c5cece,20be2c5b,2ba551e7,864b2b30,8a7695de,d685ad61,efc4fae3,fe60574a,8a20a6f1,9243100a,4bf945d3,de002f81,3b91c185), -S(38936927,ecac3831,2417ee88,59318fb,724e758e,a175bd3d,e2247b2d,1a037a5d,da223eb8,71b3f213,ffe0abbd,8bf8152b,afccf3da,4bad091f,38ed1c5a,b90bbb9e), -S(2e0b714e,f9bf7154,cc41d846,9fb99eb0,7bed9ad,3ad4a60f,b3e88fab,974ff918,8680512b,4a6dfc2e,9bece0db,435d4420,c745b611,8feb15e0,7f1ce001,6a65fdfb), -S(fb42c1da,8d1b62dd,7949a6ee,1e8605a7,fc774863,eb4c7e70,8826aa80,c5b22aa6,272c0d71,127c514c,8b2905d3,d962080d,b5644bf0,25ae95ab,5d88b15d,596c7eee), -S(5dd9e606,61ab076d,d7ccb699,caec20ea,49b5645e,96662119,15f679d8,1dc88e70,e17753cf,6bef65ff,b2739967,e64f7402,54562b4d,9e44c297,3d1e841e,ba2ca74f), -S(5c8ac07f,466b9f4f,3d6f463d,54f16e0b,3661ff55,8a1ad864,bc86ec2c,29bd8356,f849f526,77b36737,586b8782,27a927b6,300ecb2b,cf25c53d,1cc18c02,366a9156), -S(ba773918,50f9faa4,715a8b00,bbb3abf7,c78f17e7,917172b7,958e0439,7b974887,3e38618e,743539d3,469820d8,c1e127a3,cb2cc6bc,a386087c,ea7296f5,46ef4418), -S(eaf36e71,7c23e7f8,8f1af63b,fc7e56bd,fab55922,122e868e,5456d556,eb3051cf,843239de,1e94148a,54a00e92,a649ac07,e8fb0883,7de8a3c7,405bcc0,26bec993), -S(fd76140a,9e0504c,5df9aaf7,ce77174d,d64a8131,2cdcdd5b,8b82985d,db980f2d,7da81b12,d2836ce4,ee81c288,9db2408e,38f7888a,29282a3f,22a32cb1,5630c5f4), -S(7db855ee,a3c28e7e,45f51166,f32a3af9,3fcdc75d,acab827d,3844cd0,b4e88251,8cf4f691,9dd33bd4,d95aa1ac,c9ecf926,4be5b588,7453e77e,9f69241f,9498d929), -S(dafcba5a,e148fdc,aa431fb5,db8f4edc,f43168ed,5e381fa3,e5789c89,82f2a90d,a6c718a2,92c522a7,8dd15fec,e3ddcf50,10327f8a,1f601544,dcfe0e66,41404275), -S(d7de414e,7ccdc7d1,e934b10,17980cda,fed701e,5b3c4a53,d8ec0021,bb6b7015,47ca5491,2d5fd9a2,37daa64a,6434d6eb,5a8e27bc,665d3cda,d3164fab,f185125f), -S(7391420d,d4585846,cdfbacd5,63c47521,cd3640b7,4ba43c86,3c5c09db,d389133f,243bf979,ceb34758,84130208,b3a8eca7,bf695c38,5c60685,6785fd65,b1114e79), -S(a387b4b7,6c49ea0f,9b5e20ac,79053b7,a7391c3c,984c7e0d,72116ea9,85a11f0,fe7097d3,ab64e202,e61cf2ac,27e506f1,78bb534b,1bfbc8a1,9c435da6,b13776bc), -S(49df7215,bd8ab08e,21c56507,b6e57425,bc4c443e,ff0a49e,ec4ce0ac,4caf132f,9f6eed66,1066c373,275d82a0,4908193b,5477690b,5796be1f,533f67f,b9fa18c2), -S(ebeb0f66,1a66ae8a,fd0b3442,45f78f6a,cd414431,13bf03ac,3c6f5641,b5a62dd8,fca3f129,76d11af9,81f6c175,5b9015d1,91dc21e1,a91098,3528516a,a8a22a09), -S(367a8c75,e4fac5f5,55f2f48c,23d3c344,ca4bce60,b188be03,5461d077,af8a5e9a,8064dcb0,e3c46a0c,3cbfeba5,20b18f1a,4b7171f5,7db2dd3c,829d9168,f9275792), -S(d3e2eab8,ff9af1c6,5a881738,d52ee173,7baff4c9,31937318,287cdadd,46ff98b3,f7c729cc,808f4760,5757fe5d,c150ffb,ea4bd6d2,78e3860e,56b45add,bf54875d), -S(86c329eb,3adca5dd,7e840133,9025cd69,461367b,781acf0b,fb2f760b,6b56df9,6db54fd0,401af8d6,bf94cb4d,c8230161,ddfeab22,2c6802ef,1640334c,bbafe470), -S(ac9cf2bb,fbbb0be7,8fe03b3d,5b0aedf1,3d36ec3e,d8748a68,ba873bf7,3eba049,cafebc22,ede77a8e,fd3926ab,dd69342,b3226271,9a7719e0,540afa3c,c23d60c0), -S(54f1d996,ca39664,f03ede34,3dc394c3,aae4b65a,e75aed69,1427e2fa,85995d22,971bf54,8445fe60,714cf038,6c801979,e6eaa1c4,d51aba97,24b3491f,5b490fc0), -S(a01cf61d,b77a9519,6b8d0f1b,10f087cc,3689ef3e,56e66f4b,918baece,8480e8d0,d6da0432,2822dded,838373e,70550728,1a1ddb83,375944e5,4559e360,165d6b81), -S(9c971dbd,7bd6933,d4d4c918,ee7c7236,45fab1e6,1f50f54a,5474c711,8334e8e,767e56a8,e6aabede,53566eaf,daf22c38,b2f949b6,4dcf006e,b24469e,c2ab6e82), -S(db08258e,4dfa75a8,940c111c,1691e148,42a106ae,11e6f266,8a6bd70f,fef3624,9bd0de5a,f568b6e,1d05bc6f,e6999245,3a223e91,61311b7,7e06cd6c,faa956f4), -S(1f546fc9,2f784ca,638a1c8b,74664baa,d2da0745,199aebbe,9fd1d65b,48bcaf91,5470251a,9b9d5a79,be198076,541ba922,d7692ebb,f65871d6,e9daf078,52428dd1), -S(a318a92a,e36427c7,6c8387ba,d4420b29,a8b0f583,76d6e049,e70b9a3c,55b5d799,b38888d9,574e6cf4,991d6608,ed6918a9,92ef5a1e,90d405e4,da8280d6,74f93b2b), -S(84c29d90,417579d6,6124a754,aa77b711,4758f383,20a395b3,44b0e547,d8779b2d,2957cecd,8766c432,49ccc288,c6f6b005,b2726bcf,9bff51e6,d676ddeb,ebd340dc), -S(4109a1b3,c740a287,5b06f841,def2cc2e,47d82029,bdbdedb7,7a225298,e3f010a6,334cbba3,6526b308,ca45e487,d10cf54a,fe229d66,e3538833,754c7058,5f9f368), -S(99cb215e,9ddcfba6,bc703e59,c3d3abc3,9b0824b,ca0a5cb2,35cd2a89,3fb2be6c,6e1494f4,2df30735,45ac89ea,ca3834ad,553bbfd8,ee0231e5,c803661b,82a16cef), -S(2bf5a599,18959366,e7740ef9,8e2159c9,28cdcda7,f38753f3,9e83923a,5121b490,7a70ee9f,387e09de,6a8608bf,527e9d0d,75903644,c4efdcdb,916f7cf0,bf35bdf8), -S(234f1de2,aca81510,1a9e8659,41851280,8d8801df,2d63ed83,e7c9899f,6881ccc5,d43dada1,7029e6ba,56fd9c99,29810f3e,c8bd27a3,5671781a,283abb97,12014be5), -S(7a691d3,2b6d605b,c04723ca,a6d7219e,39d73fcc,e3b4e4ce,ddde027,eb31b918,9e869d3f,d4802e57,34969854,12a84c77,42dbfb65,f70d2d4d,a7ddb858,f68c88f2), -S(963764d1,75a0cad7,8e87e2fb,d3f32dd3,e45e57f9,ccad6560,dc58e548,8bbed05e,d5faa558,ac6a9a20,74c5166c,72c15cfe,b509828c,24a1d967,8aeb6dff,5eca8a7e), -S(9d250071,90c38bd0,64f0cf4a,dd0809fc,95c02956,9d199840,e6d947fb,271573d0,5eedad5f,5930c244,b3fbec61,425da0cf,6d0eef25,87e84f42,35f08429,9e38d8a4), -S(83b30514,e1691531,5eb6b9e4,eb1affa6,533be8cc,c8af829f,5829321d,cd3aeacd,7eb7fc6a,e43b73e3,1ff48193,947eb01d,3029fab,e51e4344,a278f142,9ddc9752), -S(4365f9cb,8ea699f5,284e21bf,fd4184a9,685c6b9a,c07b555b,eae2b2f1,838d9cd8,4b0c0ca,4fbe4088,e1c55eab,f80858c9,6c5d3766,7af397ee,ffac81cb,3e2d2394), -S(7bf3588a,9d51278d,539b7e72,19e32b94,336441aa,3c56db9b,d70d1d13,4425ad3e,442a5e17,27706843,fe43b75c,ec629876,2b8a81ac,26f71371,ac78110d,67d9f54c), -S(bcd1ea95,621c195f,b37f0ea,aa7c1688,35e3ba46,e1fcdf8b,c6d4ba36,9dbd46cd,799a70c0,422c82ba,e3790abd,22346df0,8d1e80ad,9194f70,f94f9d09,50b8719a), -S(9eff139a,7e728eae,57480c55,b5a5752d,83c4b92a,96b72c98,ea7fddd9,9cfaa8fc,656a5a97,1de87e12,afcba7da,f6ee5020,7257f604,5a909707,b55a83ae,ebae5f62), -S(16edb231,17a09c6f,bc1b0142,c06d9f8a,ce125101,a48229b0,a7605a87,f3fa59db,1f41d18d,29b720e8,54cc7876,d682efda,97d27e31,3f66eb89,7e23d85b,e160c9b2), -S(890e1604,5f35d432,fb62b4b1,aa8e8aca,b08a5aa6,edced104,841ee569,f8b0dd86,7970b632,a25643ad,df338a59,4f974cd,701da359,8b845ab,bcae75b7,f2168e19), -S(630d23c6,f5586b45,59d68f49,6531cb74,e2075ae5,3ecee2d,3c1c8ac2,b01362f7,5a9c6335,dbc506fc,d8abf476,ee5f5437,290cdeb8,9c3ace9d,184658b4,67478c74), -S(9348ad11,53e90953,65a13cf5,6cf05d66,a69e509d,ccb1be8a,5a985472,f5ec3909,3632b1da,48e2ce33,97d25cd,6fa6d55a,9fed786,9a7b9bf,d2765af5,81af7206), -S(e507b132,8614fd05,e9d8fd9b,5742cebb,6e7301dc,defeedb1,5f79022e,79acbbc3,e09d5d09,2eabf8d2,d0186df3,5007570,e9e85f22,269e0342,183bd375,a5e326db), -S(81727248,d85e0f46,a8e4b09c,ee17658f,557e1dee,a7c9c12,49012f6d,76f5432,f1654495,339b6da1,981e8e87,eb95d1dd,5b62ba06,67ce8a2f,889081bf,2aadf), -S(54f7d9a1,806fc37b,668a97ed,286ab04f,a2a96f90,aaa92118,4bc0034d,431c5d18,26f8efb0,5bdb0263,2e7561f3,9f56c5c3,2f41c8b3,7771ecd,897204f,33c1da14), -S(75b272c5,88900750,4b139b59,f3188477,56aa22fb,b1981bcf,74491b05,881a4be6,1b7ef1cd,70dd43b2,851220bf,b3989bf4,66e76fc3,e9262d89,de46327c,30a73c31), -S(9880a12a,10a9692f,b542943a,ce6513e1,bc95fb8c,618331d1,413657b7,13b2a811,38e33a55,ef745420,98d92ffd,17a7882f,b2e9dd69,40deadd5,8dde4a,8c31dec8), -S(232f85b6,f3fb87cc,fac4c06d,bf585c3f,c5ff3d67,114f1187,17d68ab2,af6e24ce,44981280,9c5b77b3,ea4d6b1b,e1872fe9,c295596,839a135c,443a37c8,d0a1f405), -S(e7e0e5ce,292f1386,3f186534,200727a3,46e60312,76ec0831,3fff6810,6d378912,404fd06c,68a99234,9d86e1cf,c2aec52f,bb101169,6940c961,1c052d86,ce87cb6d), -S(7ceb4d25,1844992,86b50e20,efc3bab3,a98cf466,e22c4018,eb22a97f,51a2182f,4cd70a08,609fa1b0,d55bf37f,2be739ff,8af001a3,190b7b4c,9687a3a2,949e99f9), -S(bb22eb38,cb29566,57a046f5,2f97d3a3,83bde5ca,e0e64fc3,6c5d28b1,be701695,574027e6,92a28c07,9fa92945,cfd36c73,8ae59c35,c869d17,d460f9d3,d12f7ba3), -S(e9803291,3c7e0c3f,4e0213e6,a6488dc3,f5c0dc6c,9246b655,5dc0adee,978ec5f8,b3bd6f23,bf63d3f6,ef4b4e45,6ea7d58f,47136aad,da5b1de7,765dae5d,b4b6986c), -S(e18f27f7,f8a95e81,fe58a13,329d12f1,4118d924,2bfbbfc0,f64eb2ce,b233c15,66b93d85,a1c7dc3d,cdfc3970,ff0f61de,b6b0adb3,ad8b0db2,fe766606,3c4630c8), -S(e6243ac1,f0b1d402,363b4b37,8ca320a6,68595325,a1d0572d,38a54476,a107a2d6,5286e1b3,54a3e264,4d9c91ff,cbd141ce,58c8a6be,5b609924,5821dc49,d1e92df1), -S(a77f0928,c24f4ee9,14a84684,568ca975,322ca71f,dc78f389,9aaede60,9a3df1a8,1cc82bd5,7d6eaa18,a05e8096,441676d8,d66c1584,af2cae0,ec118bdf,bc32272f), -S(e79c0aa,51e9fa1a,c6e330aa,b9877118,ff672fd4,46f49920,fcf14f26,d74bf10c,6d952340,708203ff,109a0d,7dbedf52,866d204d,8f5c9cae,bed7c724,4d726ac7), -S(6f5ba3c7,202c796,c27d342b,9e5f62e7,b3962a71,7fda573c,87d30071,796e592f,174aa4c,789ff3a4,1c5a42ad,a3bfb2de,ad3a5351,cd9bce90,f983a9d4,e897f053), -S(701c7dc0,9edccc89,530845ee,6d76dfd0,ec06a842,49ffa8bb,1f5eccee,c8aea899,1f3a2d11,a53081ce,6c326977,911ed535,2de2df6d,e3ea92fa,7946efe1,a2afc215), -S(3c82e97d,f06da304,13439ede,3a56a48f,c4fa7c6c,9ef2a74a,cd80e58,3e3e4104,1ec4e9c9,14dfe93a,13a91edd,5f7f63d5,fe60ff4b,bb271624,d5ea48bc,7833dfd9), -S(88d3451f,3998286,2cc3b867,afd91cab,6ccc737c,4cf1f41f,1c0d702f,a2af97c3,2e3d51f9,141c94a0,1c1907e1,c5328653,a67e80a2,80883f2,2caeab79,70203d05), -S(dea9dbff,93f8f6f1,714a49a2,e9154fa,766b9627,e64049d7,4363a542,f30b0647,deb01f8d,91c3f7f0,ccfe5fba,a5525b4d,b10561c3,aefb11eb,6e540844,2813b714), -S(7e715f8b,68718d16,ec601550,f80a7f91,d1f1f3a5,ec972755,66ad93d6,af205104,9c79a5cc,3226c625,d734b73a,f34bc14d,a5d5007d,ecb402af,b815bf4f,18df8260), -S(6bfed43d,a9196990,c03f788a,9b27d023,12394f38,78bc6d64,8923ec4e,3db64d98,672d59b8,c2c40ba6,4c88e516,d5602983,7a9b328c,6c28701c,80d47927,9590a913), -S(177bd160,1c53637,28e341de,4e7f8a22,9a561665,c1548ace,7e6376eb,dc790009,17585c2c,9a90c5f1,3a97fd24,b7cd0358,762f1217,e4ce2bf,832c008d,d004186e), -S(f1b16245,4181187c,f5251139,8382026b,ac7c4355,ec7cd347,9f83a66c,db63db19,5d261ed7,3c9611ab,d983d74a,9ce05bbe,cb32b858,32d00e87,fa794482,41fa70dc), -S(aadc4097,ce6fb92a,6b77b5c1,abfdc345,85982877,5c37a522,39518559,363d2fec,825fecfc,6f11154d,89559a63,56308d34,5dfe2e8,a439ed20,eef0edaa,3d506a62), -S(ba354351,d81b0113,a215ed8a,3a900fe9,3484f35e,36988664,8c830d79,699932b5,c18c12fe,9b2fa86c,982ad09e,5d29475d,7a0b7f93,865e8300,f215affa,48bcfb66), -S(ee1f269,ab870c07,1ad7d7d5,a84b5c64,140a3bdb,68f0a5de,c4a80c52,9bc7f6a2,67f62848,f082c3da,69056b00,91ddcc2f,7687f630,7f4044c8,8196a368,d441a44f), -S(9880ef57,5b111cc2,c51b9b19,d3c154fd,30d8b967,312e30f9,2f210a9c,13b8531e,af790a63,c44bf477,8884f95f,91652c14,f1ee73ba,7c1facc3,8ccac2e9,8382b83b), -S(996a6793,873cf119,f77cb23,1c8771bd,6226d90b,d319c2d7,d9793a30,4a7686e4,983c75e2,f0ef1d60,dd60ac8c,d3df6e09,ae1a8da9,17b1c63f,f59e17c2,c19a7d38), -S(35faa9e8,7fefcabf,3aee306b,a88cb110,1514db47,9e559e6d,f8b995d3,1616395d,bb7560b9,fcdb7e2e,7522e5cd,7bc42236,79d1e546,a7f7c0c9,44186043,7dfde05a), -S(70d1471a,52f0fb45,50d2c644,b7925895,5e27917,13ac9a68,2b5351d5,333b3fcf,a84cec71,622fddae,72f4f995,2585ea84,c15968eb,666573bf,254d2144,e0a523e1), -S(ac990fcb,477409e4,442a7635,64ceb28c,26adc45a,b5b99441,e9d7219d,593ab4c,3f3ba91d,c08bf75d,5e764b72,d048fff7,fd6ee3a3,758bf5be,d9a7da1c,6446e15c), -S(f8f64b95,69be42f6,1567f537,d9e60f6b,f0608f5c,d8ad8567,ccbfa02f,34b26208,d818300c,ee7da0af,1542dcfb,9a62ebd6,86c1bcf,d9e5f41f,31f79892,fbaeaba8), -S(c24cb8c0,eb923c9b,d12db26b,9473982a,73099bc8,1f0ce101,49d153df,e77bd5f6,7f47cd6c,123cdb2f,f9772b09,9f44cd9f,643929d,bf0132c1,4f9df2ff,cf4ac056), -S(5281bd2e,f6089825,91e8310d,4d626c4,4e68ef80,b9e6abdd,6a0af7b3,4b957f1d,eb9a808d,97ae906,b029a24f,b600712e,3cbd406e,27380c8e,bcf3287f,fe1e2cdc), -S(d525c063,fbbc8ba4,dfed492e,cd056ce4,fa60b04c,25c850b0,70052ec2,6f592be4,8e5b03a,9268a809,a86f3842,10a4dfb8,1a5d4659,c2695723,db7982b8,698cb778), -S(b0a5dcc1,3b377072,9ef8ba6e,b0550b3c,968b4f1e,2a2ffe0,54a89eec,ed3adbb2,49865cce,282b337e,14ab3f17,4a07979d,38649ee1,951f8aea,8a6ba657,8bcd4356), -S(ef3b5acd,4bf27694,cd96f70,7708eb1b,26f517b0,37d44194,ef3aad38,98d53812,db292747,53593713,1c0a9be8,5b020ad,34f2040b,3b60bf65,638f4561,709889e1), -S(dca55235,2326841c,625226a2,6844d317,adbb5cdd,a08f8931,68920aff,82d300be,f48441b8,a104131b,bc1a2487,eb3760d1,8b60c53e,70b693d5,b5db49f,485ee525), -S(53a47db,565ec4e7,255ad4f7,7fa28644,2ecfd91,32a0e8ec,6e4f119c,2d090044,1ee6a228,b1615640,83a62c49,f3f92c9c,9d6d46d4,6c7a277b,7ef7705c,4a20a6b1), -S(8187e675,78d1c19f,c1624a5a,386fb1a4,2ce7df06,8487baa,f20b0975,6a40ce91,241bde96,53091ddd,49423bef,e6a1ca6b,b75e312c,46ff803b,bb709a4e,25a691f), -S(3ebd8f13,d92881af,1a43223,335c7eb0,7958b7b4,e5af5cfd,f320228,64eb7937,72b3ee1c,bf91271c,84603d64,a8feba9d,bcbe4626,57c4d084,d2d3c8af,e7489c58), -S(90de5cd1,b27da158,a73ed3c1,f23f9390,9e281c65,6d50f8d1,b70294a4,9f4bb4ee,1619b365,238cc8c,be2b62db,ddc24381,4ecf4095,8617ecfe,6315f8b7,a1d73b3c), -S(e44c5ccd,d2723f6e,c44ba386,3337d911,15a73547,c2dc77bd,bfaa6e1d,b4ba3d62,f150acd1,65fc084d,b8b442e8,8a6fd033,5a8383df,9b2639b0,3248a1b,72828129), -S(62eb6bb8,67fdb48b,f474318,99536489,437a7086,8f27287d,6ad56996,31d6c845,1014f43c,517b3a80,d2cd9e4a,7d76693f,61afef58,4ee80ff9,8d20bcc7,c077f7ad), -S(a44ce0ca,a242039e,3defa271,59976e2d,4bc9f1b,10e07b83,4aafee6a,7ae93066,511dd603,d264403f,19da6380,dd470cd3,2fcf656,2cf00b3a,d6a209b8,b244b070), -S(1f1be63b,414713ea,7060e264,ca58dee1,76677033,66002c72,fb8beb2a,a661539c,ecdfdf49,a771409b,2cc03f7c,8640cb98,49c00a82,1d40d1f9,586763bc,35815ab7), -S(30a76480,5c483013,7bbce984,10a2c250,4dc2250d,ed82f853,7caf58a5,b52bd8b5,2edb011b,ae585fce,da2e20dc,3d840c5d,704b8ee5,8578c573,d3363a0d,83168c7), -S(3d6072f5,dede706f,593d93e7,73e3555,c7ab31f5,60a83985,a575294d,1c73d135,d8348521,802df34e,ffc3956,498b0f25,91ef05cd,b71da7,20ce9b3e,b9de6db6), -S(12e42941,44a1bb18,e7944b3d,846429b0,cb9010f4,b42a31b7,e7642b73,520d2ec0,bd7a8a89,f5e1d98d,adf3dd7b,9c8b2bda,5e49f178,cf51796,9bb99903,43901cd8), -S(93b9a4b8,bf35a92c,1f008623,ef3c864b,79de76f8,5d52c4a8,67d24e5c,970d3776,10d1fa77,43bb9211,76801b67,5ed9d304,8fb25b31,65a0f544,52709615,965a7b0), -S(29cae9f5,688107b0,d7cd3686,d30c0dd2,1f65bfae,11172330,7d21b8cf,9d95a49c,dc8ba474,da42ca9e,2325123e,1dbf93fb,c25469a3,381b6833,437034e9,2b6a20be), -S(d1ecd9ae,8af12732,f9423f23,f261caa0,c75a7e,58e0ab83,7fd47568,d3da43aa,c24712cc,49a9a669,e0e46068,60a8c0d1,969aaa66,a436f3b9,1c530e3c,6c0a71e8), -S(fd43cd42,67c4d07a,d70df093,863feb4c,5f82f94d,c81c504e,f95dfce4,4092104b,d68e7968,e003ab0c,ab98beb,796dea02,e854ce39,ecd79ed6,53e001cc,3be14c78), -S(d758723b,587c3af3,52fd7d50,9ef63ac9,efd9235e,a8c8d8d2,41de2898,73d5fe94,43094c5f,1c773577,29b9638b,d180a70,b3c9ac41,8e078dd4,99f5d2b9,1f02edd7), -S(e8fbc8d6,51f9828a,2ec3ccb4,9b7fe22e,18604125,7c975ce,3c01b362,d2897e36,1c306170,f2e1fc7b,ce0d9ed9,fdfa39a4,99d6cd36,bb04716e,e1ac003a,d7573242), -S(bd8878bb,f050eb0c,bc7775ee,a3e991b9,5e72330b,fcba7b3f,cb7dcea5,f1464f2b,c3bbec0d,e87c5a17,5370e6f2,f98b7adc,3538a452,e04ba2db,3e193ba2,d9d1ba5f), -S(e47e80c0,bfd82bf4,8aed911f,236a7d96,4f370d11,c5c10912,3828e3dc,e87e0b3,1856149b,230697d0,1fa39446,9434270f,d0932196,aa7e4551,faad127,b0d22d60), -S(224963b8,57e650e1,58be4862,bb70d566,c2fbc28f,c6892eb7,6f04135b,7a91761c,28e62c6e,887010e9,7eaecc0f,b67e5630,eb2ccdb2,f95d0be8,51c43db1,54ca6e61), -S(b500417f,b75ea406,cbbd77d6,48ac1e45,70703605,8990b340,85856564,a64af549,daad3ad1,9579c990,a7e061fa,f98fbd12,5678de87,ca16c708,7130dc85,abcf1bee), -S(a06e6152,bf4d9aef,d18fc0e3,6e0eed5a,a35b316f,7db75007,ca5a175f,3a80cdb3,6faa9900,6bd783ed,d8c207d5,95843ea0,2819b277,7db69ae6,908d7ef4,4e04e781), -S(179f9602,2ccb2620,3e94101,c9bc95de,5eb6d3dd,8a04f18f,17f2ddf5,1b0df5d4,dccee7d9,30f31ea6,3903f801,d4712ae,ad5459a5,b0ff2987,b3b1f454,650180a), -S(40312ffd,1e4508a9,854c3f94,ffb878fd,a5912ba6,5ea241dc,ea82cc66,e586de28,e111c511,5399357a,eed01d11,18ec409b,febc525e,53cee921,d1dd0455,d01854d0), -S(a29e24d4,c72bd5ea,98630030,a31150b6,5a1c9676,d661ba8b,19d95d5b,ccd7bf31,a906225a,120eb05c,3885e734,75765949,a4da7e4e,a6aaeebf,2f23a011,7aa8df9b), -S(e2e4adce,eb40ffbf,f2a31a97,a34e5f4b,9dcaf149,76747838,3fc0bcb0,43139bb8,94ef60ec,26dfc1d7,dacdd451,2f8c0a0b,ccba1b04,7ae3c197,46f3c234,54a007c4), -S(2a11ab6f,7188858b,e0c8c08f,22b4bd83,3c864a74,4c43428e,2c467d4f,a71118bf,27f83304,ae9e599b,2a212050,c8c363aa,34ae58b8,13912bcc,f6df669,f01a690f), -S(23cfaf4d,57e0e9ec,a8d180d4,568016b9,4f896063,c6fb4e2d,7cf909b9,6ae048cd,62b11d6c,2c3f30e7,655d2c86,8c7fea1c,391d2982,5fdc92fa,f2ef3e5f,f2d65587), -S(cc112ba4,a6b684c0,6f95458b,18f1d41,d0c90022,1fb6af39,203efe1f,f32a07ea,7919e449,eb1720a,49f66e8f,fb3bbe76,4a5e23f7,798f47ab,281d7cb8,9409465d), -S(4d9ad572,bd2829b8,ab98f048,88ec4369,b577846c,59e70414,7128c4ae,17159456,4570249,6405ee85,4bcf1201,9b56cef0,136a4cff,cf90ce00,52711348,a459e1e5), -S(dd32548e,826e2aa9,faca198e,f911d0d,7ec33ac3,41f625c6,34c59c0,ff3e3bb9,5526048c,fcb29f30,ac84ac24,5230b0ca,a0e68e88,ad6c3c75,544bb137,4b1fb47c), -S(c4ca7cdb,93519cc1,7762ce27,249e21a,e2bc5dfb,727a4e23,a38f2938,e41e57f,8233f977,3aeb917b,c65dc1d5,a539f62f,c8403779,f1edc4b5,781e92d8,fc8bc802), -S(a1e1f0d6,2a0d616c,ece08d20,fd529521,c5872f8c,8cda2bf1,a679af71,71bc46ef,68a2a818,4340b803,c7641034,fd609333,180501a,612d3b6,c66754c8,16e5368b), -S(d099aeb2,a5fae253,6a953441,7439e745,35fa8236,96731b6,cd327332,8771bb26,c526ff8d,f32deaf,b7080667,c9d74257,f294355d,4cd10414,e8e38fb2,b3722eea), -S(87fbfc7c,ef2301a3,b50c3bdf,993c52a,b2c32ba2,893b8d60,19f224aa,9554900e,aaaa988e,cf77f228,ee4f42ba,a7ef4a64,ab475e3,3d708ee8,e2826fbb,cc3b92b8), -S(4b440dc0,d6673ff7,cae6cb6c,5ad6d54d,fac23da8,f8e1a570,82fff0b3,eb165493,35841c69,5eecaa5,1499676d,a97c197e,b60fa733,281823a4,2e0bbd8c,ce44b2b2), -S(3ccc6802,cc5fd5fb,82bcc9d1,4e2a2765,f68da87d,7fab7e0,d1c05c68,515fdb2a,3be7e4dc,fb8c734c,d9f0254d,afde26fa,1772f094,43420bc0,aab9e29a,83de67cc), -S(e98bc0f2,d6f9e71f,deb01296,d12a7a0d,b617e5cf,fe2bbc9b,ab166eba,e1a59b85,2fb5ee36,2c01c58f,9a113e18,e03a9e49,5853f5fa,a11053b1,73ebe019,58710ade), -S(5c0bb588,69cb2007,86f2d549,f4fb4146,5656739f,15c8ff95,afd057f9,5db895d2,2c69dc05,b3b5edf,a4d8c3f2,41afe00b,b67a29da,4f1a1301,83c80876,21ecb08b), -S(9c8ef657,972b5330,caa9b64f,7d7c817b,7c0b1047,ae2984f4,3d4f4085,3cd01267,98a3630e,ea6b3bda,c9e9df0a,807eabf5,baa9b920,524a7aaf,2e1e9f8d,8173917b), -S(43b18341,11a7d2c1,d5341b95,4972d28e,e734cbbb,e352460b,75fff2e4,a9921035,3d32e375,40e33c0a,5d4eab42,6849230,22a7c560,3d47e789,30022b40,8fc99f96), -S(89d86eab,b52a84cf,9e53d7b5,270cf9d8,198f032a,e43a286,e18fbfbf,3d0e59ee,bb7b7247,bfb01ad5,fe143967,e5cfa75c,d00a54d1,83322fdc,63a7e29b,5d7f47db), -S(567061ea,2b03428e,d8430f6c,5f03b469,cbb265c,ceb9d999,30509d62,25805515,ab9917,15fcc760,c9aae0c6,5862333b,b886ff7b,b423f80a,92ff44e7,f55f0259), -S(50e830fb,6efa74c4,5460d96d,bb9acb33,df2a3ad2,83602ddf,214d66d7,967bb35e,b5914d4e,24073b29,31937f67,58d69c46,917a70a8,213617fc,4f669622,401b17f9), -S(2bee6cda,ed042f5d,c28bd7b2,a9266c1a,eb502ded,379d4eae,21c8810f,7f8dfead,6bc759a,a1a950,e506c504,86392bf1,4c1d9e8d,c212192e,6f99d274,c1b82754), -S(c4482ac4,508bfd79,b4b6592e,d72b5a6b,f58f1e08,76194a5f,9829cc18,a7959fc6,e99ac34a,91d46cff,e9ab0b74,883fcd24,cc93eab,abfd4873,14920417,1bcb7b54), -S(55bb94a8,70858f43,2753df21,592479cc,32cd6533,f5c7cc6b,73517cda,1814a57,93bdc1b9,8b64d43f,6fdfce00,b8ff652b,ffdc2c75,afc4c95c,ed7644d2,86dd4224), -S(2e17cf48,bbc6b561,3fb740f4,52e2f03f,64a01a9b,bc770df2,b0a4d8a9,71e93fc5,efa5836e,183e1d1,b8e02309,5526ab9d,fb1fc046,92e1ebc,56a6e3b4,4f425c4d), -S(86fa5013,f9928726,79276993,ce380d50,ac17d961,24b48c6,b68f6565,6e39a418,d66a981f,95bf103d,3ee373b9,af27ccde,8fa454b2,1277360b,995a02b9,b7e43b24), -S(6990a5e7,d3d4da2,48f4b621,4d8d3d04,78b9bb36,6647a0d5,3cb66412,120bee3b,5a75c630,d1551aa4,ce9a8020,4ca405d6,dad9291a,e28d0fa5,e14e8df1,1ff79727), -S(1a901e6d,2bf440fc,97075337,b6188f4d,51aba0c1,4207ff29,83ac6eca,9312ab50,6a40d2c3,c497f8da,cbf7b079,7cfa1eb3,80fe0d6c,f3b74a88,7ef912dd,3d8c38f1), -S(37d9f2ff,3f14bd91,3871eda1,c5719b8c,c6e92717,dc97b308,5b0b6890,eab8284,84b05081,cd3c21e3,b36d1766,f133284d,d4abd71f,dbc94baf,33d297f3,a8a238d2), -S(8a430121,8acbc3a8,44436a0f,c476ed74,3548a445,8deeee56,55717e7a,1117166,accdb0c4,aaed4b97,658b77b8,af83248c,85456cef,ad368565,4f73b013,3a258e25), -S(452e5c3d,9c95fa1e,f5b9b508,8a2bd2d9,ad1b6871,5b07d4,d096e99d,22c7fa25,ba4d9d3d,49092858,c6a2b44a,56586ab6,8cf1d7e8,f92a4d35,7b1b91ba,509066bb), -S(dc5d9da1,efd435cc,70c5ab24,994b0fae,75e9a628,a71d1794,ea620d18,83facee,e16e5e82,91f44b12,e6512645,d9ef73b1,4ce928ac,3b4fa30f,bb2e958d,28f1263a), -S(ea6aca7f,b52088bd,7094764b,bcc2c0b6,9ffd5859,e1fba329,4212b0ed,7fda33db,d81cf674,4ffaab0c,71e43cfb,3c1b7ff1,480024bd,1691eaaf,cb5b8174,af824cfb), -S(2bc369d0,ae283c1f,ca38ee72,8a154d9e,62935f97,45f3f043,51800368,651ecca9,b469499,33f679f9,5d75cfd7,94dad8fd,b06d91ad,8c019dda,a819261f,1492eafc), -S(c4c52452,80983e50,4a599a12,782f006c,c7a5fab,5b782d18,b68a7143,ef1a382,a23e7df3,e1443d5,72278fbb,5ce63ff8,b7ac020,1544f21,3c9fc2c6,6c7a7b69), -S(42e4ce90,1240f01e,82f0f4b4,6ce1a1ab,9b26d339,b7a4e128,886031e2,6e6d08cf,61ce91e3,b05dd18f,6089cc3b,9fab7541,d23725b0,49bd16c8,9e468bfc,5af82be5), -S(288a0ac9,72a2333f,f29dcd93,faba3852,c749763f,4fe88a79,601ad6fa,7440836d,fd15dbb5,26ccdaea,7a02807f,f1edd91c,28409802,8f84eb5b,18cbd5bb,1bcc5daf), -S(1f9655aa,5434b9b6,e4b76058,6557e2c6,77df18b6,1a732003,c9cfc21c,97db70d7,98366446,9229d5b1,67bb328f,205260d5,96930a73,8f562c73,707900b1,52b15632), -S(a509bb96,95d4ec8d,93fbdbd2,7280b68,597cce37,a0d71fe7,bc0eb915,41ef6e8a,b28d1ac4,7f548df2,4de2ab4c,271a69da,4b0ae5b1,a4a8c8c6,1ffbdb21,74863e1b), -S(10a2d8da,bc8ca5dd,88b84e39,7a4a3119,61c3470c,9924491d,bf206432,a95d7d79,aed65260,d2eda695,d67a1abb,97d24e96,83ce4a38,46c46d19,6ebf3e1f,5ceec78a), -S(222588c5,3ef96af3,af198f26,34180c2f,13941afa,cf3ffa45,29bfbfdd,3de12d38,648de7b5,76a4d19f,6ebc5785,1c218a59,76feec4a,7b2aa840,6d3917f9,ab364ced), -S(39f06a75,58e5f736,fa6d85ea,6e55f841,8bf722cb,23dfc3bd,3249bf99,471f680d,6e7cbaa2,923201f6,800a817a,af7a74f9,49a8bfb5,70a8d555,d9588c4e,917cd6ae), -S(e6e0f39b,9cde4787,dfd22c28,154c1f0b,bb2a2cc,f67547eb,18117941,d4cf0b7c,5c91c032,21b8892e,bfec7a9a,21ac78c7,2c32a7fc,63882605,5c2901bb,3b99dfaa), -S(d041c732,d1728f5e,1ba5bf55,9e22c824,275d74e9,f58929e1,4197e556,b8855569,f2055dd,9cc15a6f,95874965,3cfe9399,7ea79f3c,b52ca46d,1f887620,c15e497), -S(35bcebd1,45c3cb47,946deacd,9bbb8a9d,b791f087,39a457de,52ac3a65,a2cf459d,7ef44f3e,bbe42529,5f5abbd6,590f1f06,19094a66,21812331,7d025414,147fb9a), -S(69dfb692,8e0a7fd0,4f26d73,436e955c,52a01239,9382c703,e820f214,3d5153ee,874f75cb,aa5ff884,fb3fc309,b15b36a7,df29ad73,efaf66b9,e4d578a1,1b1936c0), -S(4cffedd4,2e6412a6,5f225b6d,1901d551,4c7192bc,7c09d454,be730b24,fe126dd9,db4e13f8,a050b220,81d998bb,98e11bdb,2afeff60,62b69b20,58894e77,f3272ffd), -S(71087039,9e0a995b,baa637fc,d1a58ace,c3564514,6d203182,60539468,702d145c,4a94877,6fefab05,6380f77a,29ae7d8a,bc1bf472,28180606,a0ebdcde,8918b10e), -S(15caab55,27c3b93b,5a708d42,4fad0cd1,11b0ee7b,d80cf28d,1407e82,abcad580,61b771b1,b8290ba1,34850edd,993dcfda,61321cc1,7874b60f,ca774ceb,38c53658), -S(38dae820,1c973758,7bdf9b0,23044555,d0bd3453,702806d7,e49d7196,2efece73,b5cbaa7c,f83b4dbb,28ea4797,dfabaef7,95167b09,3ec173f3,fa4e5269,48cbb5d6), -S(359f78c4,f840f5ea,8cb0b0ac,67dc7f57,84f6cfa4,fbd3dba1,4bf658ca,190ad431,39d7df87,8c9470e7,61f9ccdd,da1bfc8c,8b34a003,89df27f6,354571fa,66a608c0), -S(fc0ace9e,607d11b9,8945c546,2f210a33,586397d5,131cefc9,7d7b6737,aa4cb19f,61cbcd8b,2131e124,292d0d69,e8543867,846dbb06,90ff745c,5ca5bad3,96596a6e), -S(1256fa76,bc6da2f,9ebfcf03,c05afabd,bb43c4cd,eb0c1af2,cfea3267,3f5127ca,9788b8bb,223f13a5,909bc219,cb582232,8f101016,db9a5799,6fe8e51e,a7e4aa33), -S(52e87225,4890364c,d8b2c5a2,34fad84a,329056df,d3131f84,6282f5cd,231c552c,b3227c4,b8932f7d,aa787ae7,c5ee5122,a0452862,43489ed3,8b9dd191,499ea46e), -S(d7c5c4d0,12f6c325,b356a323,1afc6f4a,13e11fa8,e40db671,c3d9683,20d63a41,31c65dfc,f30c4d23,3a0020e2,dd6f2829,f101da64,88589bab,11d50c5c,89e5e04f), -S(71334288,1d40474,5d7da525,c10fc11b,645bb0df,c92add65,dfdf5018,5254b1a6,52245a3b,e4cc60d7,8a029e4b,1e482311,cb1ae091,4bdb5cf8,ec6db584,2693ad53), -S(f97b9e11,1749230d,b6420cad,db097faf,fdce34db,cfb77f89,596086c8,32158e8d,5ab80620,4b7a78f4,e8b98f62,4b2c6622,9746d840,cb43cb04,bb737403,5cb57d96), -S(ce121ae9,b5128a22,917cecce,c5daa168,bdd61bda,8c17818c,ea678b04,35d73ed8,dd63e534,1131922e,6e5de85e,30d23e9b,78c24cd0,bfd68c9d,14431ff7,3cc237c5), -S(c7344dc9,75ada59,ae0fb974,fcb7e68c,d36d99e9,8bbae0b,de3cad18,fec9fc98,c617af54,e38e7c6a,733bbf11,2cfcd97b,58298ea6,d5d1e738,db85ae7,fb6d8d4c), -S(4b1e37fb,34bc0a0c,f0fc8155,96ddb468,197c76a0,fcd61b03,953d3489,79f37359,abfb2758,4f6eac6b,3a7e3230,f758d775,8cd92608,7280aee2,966d87aa,a5d974a2), -S(187c41ba,25c3d7eb,9a0c319d,c82b1c2a,5e80f96a,1e0f6be3,53891e25,d9d2fdc6,3a211ee4,4ee64261,6f515682,f30ab58d,9edccef6,2f9c51d8,48ef14c0,b1aaab1e), -S(69e6d0e5,494e7ab6,5430360c,c88cd478,fd33c196,d5984d29,cb012c14,e7c0445a,ea292c37,99f914b8,2b99707,b3e22251,646576c6,9669e66,74551217,c0266006), -S(acd53be0,92b10fda,f199b0d3,95e1461,cfbed969,303d65e0,fac52b6e,a9e6ac4,3e08e524,f1f2c044,dd581c81,9cf92a88,1a003981,1a08356a,28674c59,5829bb0d), -S(3673cf9a,1b30bf54,4b12e80d,e9400b57,6680f866,d4f40a36,ef7e364,f112de90,eb5a492c,6c7c18c5,b97a1d83,3c48a3b5,8c764572,7559d19b,a49f01e3,204d22a9), -S(29d36d36,efae37b6,96083387,f15e2300,7a1a8897,6387984e,31b8688f,789f6ab0,5a65924b,cc549712,992bf77b,514e8f67,b5b5b677,90654d14,f2813e43,45144408), -S(1f42155d,6be7d164,a376059,36d253f5,b4657286,c70d386a,ce5283de,a3dc6491,ce04e68,bd5ac22f,5ef07b0e,a0034ee1,1a6eeaa2,19d3f7de,d82a5296,84721309), -S(3152b951,db4f3586,994d7e65,fb855285,9401434d,7f9f92eb,5bea66e4,4783bc01,bc8aa531,f83267a4,84fd6485,2a13a155,ba18d89,9a2c66a6,ded6639a,ec856ad1), -S(311b8ed8,66830c54,754cdd74,a9d057f0,34566b1b,43e40d4a,85236f05,3b41808f,6f1b0365,2443f54b,3276d30e,23967ced,42476347,e9a13c19,419f1ac3,10bb3066), -S(348dd77c,cf08f8e6,d3ec8d2b,ef0ab154,f1cb1908,1a497b49,7c44ab29,c2299dec,32774af8,4e29b1ab,ca10560e,b0909ceb,5815068,d4f49fb8,e5b1766f,fbc23571), -S(632e0270,d07e3855,446017ed,d8753402,19e325c5,40079385,1f321378,b22d1427,ee608d57,3c5e5d6b,a78f90a9,58d5ec07,4068657e,e19192b1,5dfaf3a5,54f930b2), -S(750bf219,84a046a3,6a2dc2e0,351fff5e,25cb20f8,1631c91c,81c8c10c,3e251bc5,59388fe1,6b5a4f6f,59fadb9d,d37bb50c,6993330,79be47e3,344f2175,47756114), -S(1957df1e,4a617193,1f1d0f7c,fce46d02,3f0b3f49,53b593ba,bc882368,bc7ee3c7,62a95912,beee20d,43455ec3,69e0b4cd,f8d017cd,520a831d,b045226e,c7302c05), -S(bd846d21,7e08ade1,833ad435,4b5af61c,f987e071,319344f3,6ae78bb2,7fd3dd14,eb6a2269,48ba3378,4a65d1ef,5b643c6c,102b09c1,d3ee4dd7,13d8761c,a1976a12), -S(871fbe02,37350222,fe698501,e9fb8a96,985b4254,8d4c8457,5a9c1388,c3f24d35,c1660e11,5bfc3e2e,29e3c8b8,461f479f,64f60cba,5e7bb363,2cd92127,dd78d69d), -S(e7aa1f24,b4be5505,1321b35e,6aadf2fd,9cbbb45d,3cbfd0de,b990b032,70a58a42,b5f3e930,45efa4b4,54ca308d,f529c526,487e98c5,9bda3402,531d9ff9,c4f618eb), -S(879ee365,67d03ecd,7a06efcc,b7fb2b6c,8e756969,5f369c07,bca2410d,3f909399,1242e4e6,d7da2997,aa102242,16bd3e4c,905452a8,90203a43,60667fb0,c1d5647), -S(853bed4c,db8d5a90,792681a3,f654d2,c7947e70,1b94148c,204128ae,5296b2e7,d5a0bb9a,5c785ad3,faa3d26f,732ea3b6,ff50805d,344c823a,8c8f5f79,60d11dea), -S(2a40813e,c0c0fccf,8488c8ba,add7a231,7313a0ab,923797c,2abe6285,971a0d11,9552f927,f6e501ee,ecdfc1f2,1cf4001,a39e458c,23d5ceb3,c4cd1c3f,8155343f), -S(6a77953,3f265be4,d6c0de74,4137a9aa,cfbdb479,92093a61,94b3249,2a50f5f2,fd6eab4d,7fcf58e1,d2fe6b14,d34edee0,752bf837,f9f1bad2,a25e5be9,df979a1f), -S(1bf253b1,d971644,ae6bd7cf,b0beede5,c17d16c4,a50ec5c,70b050e5,159f544d,34a466d2,6e22ee07,a38928a1,a0ff40c1,d7600771,e4478c73,9820bd84,6abd0615), -S(8bb4c9b6,99634aaa,a30e6792,3d543572,2fbe69e9,b0c8f4f3,febcde8a,76700ae6,b36ad35a,7b47e2a7,1e35d002,49ca67d5,80c6d803,3aa7b3d3,340606ef,d6b0565e), -S(796cc3ac,1413160a,7f5f4c9f,4b4b1c4f,99acda5,ad71e8d9,e9bb772,dc4b01b9,1a674e53,fcc8f8da,a40badaf,4483ff63,eaba8555,2d1f264d,dfc138db,43c27c06), -S(969fbfd4,3d17cf8c,256d3bc,a7de453f,4fce7840,10c2eeee,6c3c3077,5e08b378,8f38eed2,1b64ecaf,56cb0e5e,ef83e94f,394ce1fd,9cec89a5,e2814ddf,127a3f95), -S(590500f6,ee062164,eebad106,7897f85e,75d73696,39156e73,369f2811,acf60685,71060ec,51b9d51a,aa8b90de,6b1f7d08,f446e262,3bbdefb2,4664f98b,c1becb45), -S(635f3674,4654a3b1,e905bcf3,198e9747,d6c516de,ead4fe98,c2f8a86c,4961f5d3,415b4c90,a3681e72,b8ce95dd,804dce01,b1d6740e,9d53078c,9b8144b6,cffd69ce), -S(68d94350,a15ad103,aec6b0b2,792233f7,b0d83120,ee5b1d9b,b481e84b,d04d1a2d,790350d3,32dc0cea,2977e09e,fce1c669,978a2588,9a8d6082,1f564e5a,7213606b), -S(c96e7e8,ec77ee02,335ca492,7f15b99c,e0f451eb,e07b4506,4c05467f,461f01e6,e9a31a45,b9424ddb,9adc82c3,df3d628e,bb1e9979,c9a0c650,77af2678,a6f95980), -S(7917fd53,b5be089,fecb576a,25aa257,c915f9ee,38bfe4b3,f86ff29f,488d680c,b09ce7af,8c77843c,35c5c621,65b527eb,fb28aeda,9a36829a,de905dc,d6f70ab0), -S(f55b5dad,a5205283,88d574c9,629d16b9,7f937bac,c6929255,55fd4497,38a5ef6e,34201d75,2f3869b6,f8db8a88,bb018f54,cb0a6d3f,9f87e522,e22e2db8,800acc7), -S(a257bb75,eeab4ff8,269c4124,db5a9cf1,71779493,7537b46d,52c72467,f9cec60a,f08014c8,6b355789,7730b437,bd9e84fc,22ca7740,a5cc5e81,618499e4,ac74bf6a), -S(3715ebe7,da86335f,b386a73b,c8b7a4c1,4f6e688f,ed72bbcc,83a92728,69cc52d4,976fb0b8,6a119539,90c05a68,49e22544,484dabac,577bb642,a69806a5,39161aa7), -S(c57384d7,29b0a7b7,c9814a4f,f369cb75,1a3d076b,df00dd02,e87f82f5,3dfd6817,4319c981,2610010e,6283ee27,a72f9473,5c10c4bb,d246bbe5,d6078473,b80d665b), -S(7d09cb55,b1a3d446,77dc5ada,4cb7944,c844e82a,45954ba1,ec2dfe4b,b1f49ef8,72571169,2db1e3d2,217e2e24,992882cb,fa11e4e,56c82acb,a1db0d0d,35c5238f), -S(d0a60225,5b87b479,4f2ddff7,a7b32c3f,693065ee,dfc78f35,f8ee1813,30a5319,4fe22384,42e5d371,46e730c9,7b91587,bef5a036,535e609f,de2f6f07,865ec3d1), -S(ea68a147,c69797e7,813b5279,daf2b824,e12a5ab0,69b18f91,f7cec706,c9107264,218fc72a,8e0faed1,bbd55ec5,d1b84912,a0bcd7d,a6367c4a,e6f68d4e,5d218841), -S(d1848858,d2436d03,396c84d0,3262ec0c,e4898a61,86b66e5a,f4e8143b,1713c810,91cb6ce4,c502af6e,eef8be3d,93261cea,79f102c7,12c798bf,8228143a,bc6f4ec4), -S(10883dd2,d74d3c21,a50a3b2a,1243efbc,876f94be,4f749173,9a76b7c6,c3ae13a4,376dc0b5,7c8e454a,eadb8a1c,eb53cf24,374961b1,203175d,f682c8fc,895304db), -S(4ce880c4,f0d3f822,47cef7,7266f02e,efe9d1d7,75f3e1ce,f6bdc7b5,9a1b91aa,8d8f082c,3e3d305e,91eb4032,adb695f8,51cd3ebd,78c8f6b6,cfe87cd8,6dc645b8), -S(7f43f40d,99228e89,29102200,49f40ebb,89508aa2,2472ad89,9e14d63e,69df3cb0,64bfc237,cfd6fcc2,aa1d8d5d,d709aaba,542db811,c4098d,68f8a123,39291cac), -S(91a6f844,6bf0d01e,298e8890,98866445,96e19b74,802fa565,91ea7f7a,3e01bea4,425d1750,17f81fc4,939abfc1,63aae7a1,a9e57623,3853032f,2bca878e,e53f4bb), -S(c1296478,5ef73db9,27acaf97,7c459535,15ec8dc5,ddbdd62b,d85d448b,747b25d1,72d82dba,36b200a2,4921a696,ddaff7c3,16f6027e,516a13e0,ef3c6c12,8187d956), -S(5239834d,63ea0e88,6df2db9,8496d181,1c7001c8,c845b319,309d8bad,7737b4b2,32e24dbc,d6265e8a,902264b4,345bbeb2,40363c6b,731ae6a,a9fa6194,ddf9ca51), -S(e08691ef,b43e68f9,bf315a12,7d5a93be,effbe597,f8c51e15,fcfbded3,72be397e,f304ec86,55f6255e,527f0c4a,80db724a,f4c5fe8a,e7a8174b,128d09c4,1f38bb56), -S(8ba2d25a,18b66731,5f03025e,a79c4177,24ee484,ad281e2f,a34d21ac,ad49711a,a9a0d35f,e6508408,219f5bed,f8926a97,fc070ce8,3e7c8a9b,9e319cd,842f75bd), -S(40a6b491,c6c180fd,fa4e81cf,ca69e9f,b264a519,55796ab7,1f5e1089,79c8f243,fd51d9a6,35be3859,280caf2f,c494e4d1,141b5faf,c54a9575,ab98faed,c8f0d8e), -S(176e36f4,80e9f1b7,bfece37a,55577811,a39e4390,9b12a8f,75b4ed9b,a3c5a7f8,5253aeec,58dd769f,12583d34,70248112,7720ac71,1e9b4273,b4a567c6,f6eb91e7), -S(72ee3556,e5b22f02,9eed97b,ee54c7e1,e3a69fe7,f2e83e13,401c7ee6,dd4b2b95,9b728711,1ae6f55b,1aa1a43e,271c0a4d,e0768689,62a2166c,ffc996e2,d5d2ee8b), -S(7a1aaf5,616ca51,374d539b,d67c7373,191750f8,fb5c512,5d23ae01,3297db5d,430fad10,6e887fff,ce7f8e99,97cd20cc,63abf2e4,d8783da0,f9551a57,591d72e0), -S(b7c2c82a,dffc0544,8a350835,843cebcc,7c854fa9,1dd50429,f0cbfabc,738f60e8,ba5a3066,1ae99c9c,65017efb,8dec5279,ad99b3d8,fb93e1f6,2292fb4a,16566ff0), -S(872247ed,67ad35b0,6fae570d,ec2d5717,f1aba1d0,39400e84,b4bfb997,c124b13c,6d6020c4,cba3bf3a,34d6c831,84ebd4be,5a19bb63,dc2fe3af,458ad74b,bcae582a), -S(cbc1502e,b44ece8f,c641d32c,1206aaf8,4eed904a,8b00507e,338e6017,d7decfa9,105afd03,4ec01247,27bf7159,57ef0b01,3dd37776,dc40fd7,5a0f4385,e26620ca), -S(15768fa5,72722a8d,b26efaeb,61ce7f71,95c0e10a,99d5fb09,fd1ad9dd,bc597590,8f61c181,98218dc2,8b8e0730,ba7aff7b,c5dc3730,30a27caa,d1b913e,36df0a52), -S(52301c83,5f809de1,7bdfcd79,fe3e9518,a1479df0,24a2caf,423b86f1,c685cae,3d171f90,5f13860b,778e5708,c2e3914a,c911bfb4,f70a4af1,2a1b00be,62efe3bf), -S(8fef14f4,100d0f24,b9dfbd35,12d02e0e,f4365406,8630c899,aab5bbc9,ebd6cef6,dd67918a,27d6a6c0,812153e8,481e6a42,b05ce8b2,dbed064f,b82aa417,1b788850), -S(7a4d8983,ce4101db,ecb3dc62,c228d75c,bfcb3283,d575d73f,6bec15c1,8b5cf1d9,26ae5767,13a0c2d4,dc6d4ec0,d3f8c038,48516436,ae5286f9,698bb2fa,913752f6), -S(aeee0e3c,a620b586,c34232a9,e3bc6b8d,f5b72be9,b1303be6,5c07fcf0,f3507c58,d43e4b08,6424e81f,c2b7f809,d17d9572,83adadd1,2bc2226,a190755c,82d010ae), -S(7c97458,6753cba,49ca2e69,905ea7c7,7a6f28bb,f3c7f390,d75aaf3c,3d1eb924,fbe15867,a8e7aa97,4682180,c9083321,5edfaab9,a7addde5,7e5b8037,acc9065f), -S(9428c393,31d5b775,ba3922fc,43cfb7ae,98a6dc54,1541dbc8,bd77816,1aadbc06,f1be710c,5fcacae2,4e7afb36,353b8417,35cee21,8d73310,4d58a19f,7ddce278), -S(45aee6c1,d86ac7f5,b8434541,9c37ced3,ddd54bda,5d8582f,1ea4d2a9,767dd73e,95962f5c,45c6f3a3,22f430c3,919ee03f,cab243b3,f9feb2fb,9f8b00b6,983a84b2), -S(5ab3774b,b840b2ac,e1595d53,d51c5d92,3f7b617f,1bf07ee1,a091c798,20a6cacb,125f6498,1d82a4b2,ac7b1471,a42da473,da38524d,def91d11,a045af83,89d9904), -S(28966b11,43e4d01a,d8a7d161,a3b6031,9165518c,880fdfeb,bc51e0b5,84c3b9cb,1cf95f95,e8422d0c,cbe87d43,b831ce39,b1f79026,14cb1538,a4eac1d4,438b2c7a), -S(ad71d209,83a14eb7,f963d5e9,aea67d3b,f00173c6,b7625b3a,9fc7417,f49a3a76,a72f2b57,fe593a09,2ef5263a,955598df,fc2266e0,ecda8cf7,573ab085,9a82792), -S(f918d962,ce0cc947,2539b1eb,23482e9c,a69b6254,1d0ad633,5c35adeb,cee0bdde,41446862,e8c749f9,559c002d,c42deb6c,bd2240fb,b5b0d4ec,94e0d142,e6ff8bd), -S(f0706622,6367ff84,f7cfbebc,f389d1fa,e9f97aa1,f1acfdf2,d8c6145b,e3a8a159,53af7a59,6fb697d0,2d01d8b9,b0c75304,ce1009d4,7f3c20cc,94123aa7,9c91c813), -S(800e414e,9789e121,2c8b6f71,33027b74,14da762f,8956f347,4eedc170,4e9442f2,7d1ebac5,3088ecb2,7bd8a881,78318e1c,d0ada6f,9b8f503a,57283c6f,b2039e31), -S(2fc35a13,b45daf44,8370dec9,a43237ec,1d7313d8,1113993,7e103ef4,1c90fb78,ee6b54bf,97a32d23,3755ef16,85b1f212,2e46531e,164277c,8769a6a6,2adbf6ca), -S(1bb58cc6,8606fb97,5ed32c09,f668e25b,b4795ce,84ee0e98,5dee5536,b07929a0,9e82d8c8,b37926ad,29954971,8b6dba63,229e6887,14e03042,ac3a5fbc,a8e9fb0a), -S(2479bbf1,e9ef8b33,b1a93153,47392063,19575393,3b0b760f,ed876af2,a98c285e,e58fe58d,3ca3e0ce,23bed9f0,258214a9,51741872,e5198064,af43e106,70567e66), -S(b396e44a,41e53514,411fdd39,6e1084bb,dcda0750,ae66145a,efeae86f,87994254,6536d014,1d2b6a6f,a0425f70,c7374e3d,4fb6324c,931b004e,995ae706,2762583b), -S(7c1808b2,bb1b46f3,fa79d047,ba65032d,7b2757eb,a9b1f241,2379e419,9d4242ea,bbfc916f,cd41f3f,e269d5a4,38bfc9d4,fec0dff7,739ede5,8785483c,c4657faa), -S(92e5f9c0,13a482dd,6789661a,2eaaf396,7c0321fb,1e488f92,44e8ab96,cc7273bc,e2e815b0,f9f43539,3a265354,f6880193,791a3bfe,dda916ca,ea12fda3,27e67eed), -S(6a7ab088,8ea54626,9422c715,e9b9bb43,cbc565b1,ed885200,1e49d8bd,4a79e84b,dea9872c,2c07f8c8,461d943b,cd6328bb,6fd23a5c,937d5f3b,5a87a921,94a5807f), -S(75b11622,ec6cc4e7,6887ced9,dccc7604,8bcaf51,4be6b6f,94b1d7fd,e35b5600,7f654a7a,1be8680a,d94efbcb,12a4ae65,2b0f1859,5c14ec92,df83e72c,cb98705c), -S(ca26ae7f,2b6b1e1a,1ee255d6,68d85ee1,88c7d6b3,87ca8374,e07eb9ff,8bce3df7,958ac803,5fecf72,a2e89cd3,d54e151a,575eaa9f,2e4c1742,a2d8ea21,98c0d35c), -S(e6109fb0,a6d50ce2,c9eee96a,3f5eda11,31af4f00,8ea9b2e5,eaa6619a,9b023517,92a046d0,653d61de,97ea073b,7be72083,1fa16ea4,cdd1f4f4,ba9e94d1,37e9636), -S(a99f3ba5,30d7e13c,f05c77a3,27754420,50b3e1c8,eb92da33,988b28c3,20caf85,8b73170,71d3533a,37968605,ee80b458,5c77688c,70aa6aae,1e322015,e9647713), -S(2ab7b1f,4b81ed62,9c358544,6cb81e01,77e9b0a2,43a4c81a,58e636e6,1df8f5d4,940c38f1,605f9da9,78c713f3,81d578c,88babb13,b08d7a53,f131e60e,fad6763c)}, -{S(217de5b,a47e8de,cb9d8dc3,dc8fcfd8,203c514b,b9d7bb5e,fb03584b,aa1baaff,c77bddc0,3af15e63,912e51c7,19bd8186,67f999ed,9bd801b8,11bc289b,f12864ed), -S(109382da,7088d834,bb181d52,fa1a54e6,39177311,fae56ebd,eb3a4b43,f3e95ea8,4b9d8ef8,ca4cc192,e6b60506,d9f7ecc7,a91af4c0,6e976b79,a90ad5bd,a03330be), -S(ff8486f2,d5296a82,16567549,7a46c099,56a1b1b6,15577e6b,7e789f4f,e032e31,7348e2f,b0a04014,2e23e7f2,bfac58d6,4e7b8087,2297603,dfca65cb,acfb7be2), -S(ff0252f,e7993b46,9174f525,27a6d39c,4f7dfd3e,234f7543,4aed99e3,edb8b04c,dd53af80,f6148d42,b5c7295d,150830eb,18d5c213,aa44fcab,8610ab7e,495d079c), -S(ad7b6b2d,faa1ef9e,125ddb2e,27fd5034,a576e565,c3cd7ec1,7e329e7,ebd22f52,9e1ca583,7cc8214f,1a694ced,2f216007,9b621ac6,5a2ed803,cb3bbf94,2e68b739), -S(1bcfea06,6ee96a7,63e7592d,3a9102f1,204408c9,7f191791,6b941a31,f2a257cd,c4f83f96,7e80765f,77b044db,e3488180,5fdb1cdd,294f765e,7f60cb7a,a6fa34bc), -S(95afe13,a5798934,5b22e95c,fa65a072,4e3e2914,88528290,8e99e098,2135041d,f94764e7,99b95b0a,180fd6f2,8b77ed34,699de7ba,ac4d5c74,24bc79ad,abd5690), -S(a0c4fd09,b3c27bcc,d3a52cd0,5e14873,7c49c2c0,c07cbaba,1a4aaf88,417ed9ec,1e7cf587,2ec3b0d2,f24b2b9e,531d39a5,ec30924c,44578b3b,ef82e55b,f432b1a1), -S(837f8537,d9347072,8ae81f1d,c58f6118,53be68f8,21571f83,4ea71bbb,34e7772b,7f16e8bc,fc9d7784,9d089ef0,77dd953b,508e5f0d,393ebdb3,27e823a0,c75d3b56), -S(c3637c50,fa14a7d5,307ef422,2444626d,179fa5bd,7a6702d8,29971cbf,d456c7d7,dcc3832e,901ddc80,874a82f7,e586c7fa,3cd79be2,7fbed643,ed926c90,d9b64b5c), -S(ff4d8382,9f7ef2b,b6fb2dd9,76787ed6,7cf062bf,bab5c78a,a26d5f2f,f8b2057d,64c4f671,73a6b641,7d97aa9a,fd6d3715,930c3a9a,fcd2dfb0,55aa004e,84cd26af), -S(76099a6,6bd40c1b,69009fa4,7e3237e9,4db5d6cc,4409b9e1,88c3a053,1ff1fcb6,5c7ad308,bd5ede4d,bd9ab004,38e1df54,615ed88,2b073aac,f7dadabe,f0d803e0), -S(f9f4f60c,11b4361a,ea15dc8a,19e1db4b,5f249f59,61003300,98babbc5,c74bcccb,26c524b9,1339e97b,b1de385a,b9f96636,2be8408c,65e6cc23,49505309,3aecc82f), -S(3dc564b0,6c5899f5,5e2f451b,feb11edf,90c1b843,523b51f2,686ef705,ce9d60b6,beb5613c,891141ee,a6eaef14,d5f0fe89,dbacb245,95d712e,b157ebcf,5d5db03f), -S(8ba520e,fea14cba,b5cfb96a,f09e8798,36aa60ed,ce5064e,ca04b802,78068ac6,74c2427c,42793f35,7ccd3f57,9e97e85c,38ec37a6,c4838c10,f0e315d7,aec33ec7), -S(1a32f327,c37e1617,2cbbf255,67636e65,c3a515f0,47f5332e,8a125ad0,84259bec,ac94889b,d1ba74fe,41ad4eb,5de079b6,321c3da,b76f1a6b,52382162,c8a22ff9), -S(a4fd9780,b897456b,b59da53b,7a0b00f2,54bc7044,7d0492ca,a96ca1f8,7dc3114c,e09eedf6,25923e98,2745d544,b4891cf,f443386a,e41a624,284bbada,38769bdf), -S(3c627056,5962458b,faf569c,9fd19018,1b37f5dc,4643bcec,4fca288d,e08db385,e6cf1f81,30178785,f3347f66,2cb81068,25e19f7,72da485b,79e697a8,fc822b46), -S(db75d23d,794297a9,778c28f8,6da0ec91,95e75b53,98dbe0ef,be88aa00,a64faf6d,1af59d51,3dea8f8e,8e36c811,28d113a7,5a7986a2,b6471f6,d17efd0d,e7922238), -S(9c16da05,b9020404,2a1ff95b,9b0457b9,fbb8b1b0,fbc23587,7d912b17,e11a0b5,caa3dae2,8c1f83ce,c6b69f1c,e2064fdb,4c74f239,e5793a9a,5428f5f8,bc995b2a), -S(587dbe9,ef3d647e,d0e0ed18,c1cf96a8,a1415fe1,8627b5fd,f12f8459,c1d5645b,b6869014,4e9bac2b,5256f5d9,d31fe1ab,feb3a26c,90abef50,e89a8f4b,4e461cc0), -S(1de4c4af,1aa3668a,13341760,2101a007,26268248,7c531efa,93a87d13,7aaad2c3,604efe65,d1c041e0,fc12c11b,c093c8cb,75e550dc,55b2ac,92371101,c4c5fadb), -S(cda8f01d,3c1a198c,27e29fda,c3fe8d6d,72de1d55,b36a787b,538bbd3c,be8c9709,4fe322ab,a45b3dad,db173c2f,ff700152,4faa90ba,65917b97,cb4f29c0,ab65a2bd), -S(df64862d,2c032d38,f99aa05f,372be0e6,3818b94b,9d17230,a45c4d40,dd558df6,860c2a10,68082744,f4c252eb,89eaf5ea,57cc76b3,745e35e2,a3dd077a,a3cff1cf), -S(d9895b7b,6893b227,e838bee5,9316d1e3,92743663,e4a7f917,ed308d31,e733d171,c8099481,d8badc36,11e9a266,89c46662,4a9c641f,6e954a9c,e57e55e8,7a455434), -S(e71e1d58,c307f1a0,d6060ad4,710ca427,ba47f2cc,c5cbe7e,5844e4f2,2d46e567,d34c97a7,68b60ff6,e79eb12b,94fc84dd,32522c45,99274a54,83a22906,b13c15c8), -S(5e36de9b,62a156fb,c10e9d01,5b0d2e90,a3b0b0f4,78fff430,2a58a8dc,aa42739e,40186760,c68286d8,cdd1a40f,fe0bba94,79bbcd2b,151eb361,9fbdb0ee,ffde681b), -S(9dd460b6,42869b10,740abb12,cdb7b03e,ff9b7dde,f6d88577,1bac50bf,3d2de390,66c5496f,fae9452c,af09a7a0,2c969ef4,f075da7,9132949c,e8b08a03,cace8f56), -S(313642cc,cd17e982,b924eb23,13e0634d,1324a802,bd51cb3f,80d90d0d,17d7f916,2d59ba09,e991279a,c18aea2f,bbdc40ad,23988b6f,d6082749,f3f306a1,94ec89ed), -S(6d3bae15,82708fe,61e09e8d,65318130,686af25b,3b73c60f,def2e585,3cf7c84f,441d216e,b80b00fe,15f2bea,42358150,5fd7726a,12605a2,9bd0d0d,ea5077d7), -S(22f1087a,d2f9b4db,28df386,b93700fb,cc331c65,7cc995dc,990cdf88,afaf855d,8f2377e8,9c562acf,78517ee9,917b6b29,88063caa,bdb7fc38,d7e25fb4,23650e68), -S(973d0afc,7dcd4ee2,9f7dd7fe,b12ec147,156aeecb,9218d651,f6fac991,e738f6af,fdc111fe,32d3559c,9df48e26,f8d7a5d9,ac14d12a,c78e5109,e1baf6bb,6f030a), -S(bc5a2618,f46a724f,c295af9b,5aa75cc9,4cab7d6b,ffb16709,c35e5d0e,8115f320,79f1764b,40dec87b,fc26f74a,36a040c8,752f111b,61827d15,58ea5238,580a8336), -S(fedcacf3,fbec5575,5881379a,54db4451,4a6750e8,b1bf0d5,296b17dd,aa396ff8,c7518849,85cdd0a1,3245d3f5,30685653,3e0782dc,a550d6cc,1c091363,879db1c0), -S(6fc31e9b,d5fe8f58,f2ba7559,8caeb21,f9eb8b9d,394a3fd3,3cbdae74,3b20b01,d17a98cd,3f8b08de,b18a57ac,fbd75eb,de187cc3,98b0d772,32acc3ba,41537557), -S(5ce3ac9d,eaae3874,36b13398,80d3f5e0,9ed594d5,70f8cb5f,ff5893f,11b1b419,8cac7f2,f451e966,a87b294,f0df6e54,3a6251a0,b0862c8b,2d6cff43,fb1f2a19), -S(db689f9a,c54e2f83,aee53b19,d7511624,6195610f,8a4bd546,73ecb7c3,23568fbf,2bcb293c,4d303a00,149f4c2,e4d46cbc,708e58e5,3b1f26f4,9004001f,153621b0), -S(6852395e,84e3b9a9,a99f17f2,bba96758,5d597b1e,18c3ee9c,1ffe50ac,d83021a0,96f4be82,c57402f7,b1f18258,109c6ef0,3ebb2163,3dd6c91b,503c34f3,af250703), -S(baa0ffe4,337a2053,25a06dc8,d502f954,9ab54915,2f757ce0,7ab0f19c,975759df,385a0223,5c82a31e,23b4c721,46ca49e1,f1d3d9ae,5a3ef424,da7982e4,d4ed035b), -S(8652c41c,8898804d,f377f192,9e64fb8a,e2524fb3,721fb7c5,b7f389b,f51ac7ac,1dae8810,fc3c450c,1800a806,83fb3cd,18fb5de5,ddbfcc57,72870867,ffcd0c8c), -S(e57beef4,8ab71788,262d1016,d7caf2e8,24407aa,bd32fcd6,49772c9b,dab0f98b,7557bd67,a381c515,a7d2bb84,f5a67dad,17b91f52,6d60127c,23279479,81552aa8), -S(f5d671c,3e5cafc,caa2a98,93e0ea53,b5cae255,1ca13144,f5cdb793,897d74e3,a455177d,a1c343f3,72ff895a,e0234780,f9509169,ecbcd4fe,9bc7e2b6,77dee746), -S(ad4ea4d9,4cf266a0,62f747ac,a3276163,4757ce6a,2cb1b655,1cd91232,36568664,6e20396d,78a8e653,5d915f77,a1b07f71,6c72d5a6,73c51381,ee2cb69d,8b8177ff), -S(3d000a68,de2bec93,9ecd8fb5,d9ab77a6,247971b2,7c33db,522ad3f5,b1348b89,1a923b11,358a52b9,2bcaebec,f7a60b46,b51922cc,b9c239e9,4713e3b3,455a565d), -S(4b1bb516,196f7c6f,d6b917cd,b8cebb6d,56c4c49d,3f44312,b6e54b43,b51f3278,2acf44a,efb6d3e,95ea394f,18e9945b,e3c79e8b,b3825d96,2b96cc7a,58e357c3), -S(c7edf142,aa3e3fa9,91e92b6b,4f5f40c3,1e802f21,5383bac2,5d90ebf0,74260f,9806dc46,c4c040f5,941e9489,3ff82abb,a0bc425d,44625765,ae4cade1,95a683b6), -S(71f0c9f5,7d2e0048,afbab0b,9058074c,3524ad35,1a9dc2ea,430ea159,eb702966,82a5a7b7,b4e5d028,d748774d,f90b9d52,d7086e37,2be2cd8,916b0d5c,2ecca118), -S(ae7fa0f7,275f4f18,15ec6888,4f358fa6,170f459f,442aba2d,10a8ac0e,829683dd,66c93784,6576d531,a6ba8641,772b6917,9638293d,cf4c2866,262f2221,f8e8a12c), -S(50447e92,2eb7e2bc,f96bc492,6072be78,a4f7d17c,6267f8,da513c57,7e624f4,c4536744,c06a5831,3f75787c,4b854b13,c3d3a4ef,ea09e584,93d10567,cb805ed5), -S(b693791e,4d20ab11,bc3d81f,28f5e509,fa45e1d3,9ac658f5,9a9dd7c5,e7cba800,a078ad71,af8d7312,c1b003c7,a17b7263,6f25e195,4813c05c,b4a05d41,2893559f), -S(4c8c48f,73d8a610,a6cfae50,44a31d86,40f660ed,93d306ed,7942d01b,44c5bdda,c747c2f9,400bddf7,5a96238e,17686ec1,b04a96c4,5031e5a0,68523d8e,16d1143a), -S(87af9f94,4296132a,9f23e471,8961a373,d49c9efd,ae7ca312,d3e28180,66e4c1f6,8251b125,4bdc4711,33b7d9ca,7a079120,bb04144e,a6720b0e,3de93705,32371017), -S(ddb8044c,82842cc8,a2cc1462,c803860c,19e7e40,79a4bae3,9dd7271b,85983012,6bbd6d35,264a732f,824c012,6f076c82,6247b61b,e4248260,99d6a5ab,5e208971), -S(17c12c2f,344e5da0,bba8d9,a5a145bc,d1e6a77d,cb95cc88,bcdb18b8,1accae3e,90fb2afa,a634d199,b11d426c,e974f87,e6aa765,bd98b848,dbec1af,e023afac), -S(dc115062,8630d468,d4c06d0c,6d693470,63fa22a,7a76538,d1341c45,4bc8b0ef,3542ff1e,2359824b,29d0390,e8379bac,43d8e9d1,eb5714b1,91dff000,3748bfe1), -S(7cbbc66f,84023a67,7966ffc,231e9613,9e2db2c6,2b7d2d7e,31d9e785,8ebd8feb,e5911b68,73f2e661,b67d7a0b,3aca2582,db9946ae,b925d302,e1e1c3cf,d9a1975c), -S(72cb29fd,5baafbec,9bd0abda,6f8c53fc,918e71e3,d932eac2,a86f5fd2,49b4095e,d14bbe6b,8ae0ba27,4796d5b4,fc6d6ce1,9a383389,a08535bc,9ddb3220,a04227a8), -S(fb809bdb,a32038c8,d017352f,629fc367,ed1b7eaa,97632e6b,f29a6ef7,6b90a6b,5d4c4958,a28fdd6c,c8a698a6,b7c35773,fda9c700,2776ae,b90986a7,2d65ac48), -S(fb20eed9,22031d48,de92ae40,7537769e,600db346,6de8d72,64610094,79581323,c129d99f,1e32672f,2913bc69,e76e710c,399c0256,63056546,d2332e64,fe6257cc), -S(18b7710e,aa95f5b5,79eb6c9,7d95e653,aea6ed60,3f1f3f0e,f4d570af,621a396a,c1830f7d,bc278840,9a54cb6e,f48966b1,40a4ed2b,54a1f0ed,2754142d,7bd02495), -S(dc781435,efec9436,4d4d3af1,58216ad1,c392a4b5,9adeac05,a1ca9a8b,4a196c60,625b2205,45678f7e,36dc1a54,3e9f9f05,383e3590,cc5b7450,c774226e,fb73c05f), -S(6e16acad,951b4ffe,737c6884,8a59e094,a35f9450,760693d8,9804934b,25d2be1,505091c4,8e00b8c9,bcb50e5,c5eb45c1,d706f95b,cd292994,29425b0b,f3e968ad), -S(3dda4d71,9579a27a,a6980e32,95439374,1af56e38,bb51f165,618af16f,8aa2cb36,c4a0dce1,57b2fca8,2f6eac0b,a800be12,3711694b,4b711742,cc37297d,48d27950), -S(33b53cd2,ba2f15eb,db59dca7,d096d50b,2815cd8a,d44fb218,a750dc1f,63c08130,2088291f,30e861b0,3e566d7,149b961e,d513661e,5eb44cf9,1ab808c4,2dabad38), -S(3ff3ae48,c88bd212,f35fb6d7,b06ca581,38d4cc40,24f0c0c9,f6368164,de246f9e,c177b65d,b99236bf,2161529b,870bb558,a5553f62,1da1c2ea,73297623,dcec6133), -S(1d9f4e25,4ee26361,f5837220,3e4c212d,9f46300,44574f4f,ccab16ab,50023fde,1fc1da4f,8567e4e1,fce5151f,648f31d5,f5cf22b,5973bd56,73b967fb,1bf55e1), -S(5815c873,f3a0b76c,56e79769,54540685,1a853fcc,23b62c5a,6a74df64,c90aa0c,d2c66c1d,b75425eb,8c74e822,d902890a,2d7feb27,f95cde22,648ed311,5dcd756a), -S(bffeb15e,4f70e4d6,b16c0027,eff0c9ee,594b254b,43523788,cb54e8c6,57309213,12261851,deaed15,c2eb62bc,92289c40,5714904c,c291d736,470271a4,24d6034), -S(66b01b20,8d891037,bafaf962,98d6502d,fc05adf8,24731d49,84e59425,9cc9a780,1ad93ad1,984b9404,e2439450,c728eae9,c9ad5c32,7be6299,216ac174,4b838d43), -S(db8a04c1,cbf6dfad,3ccc65b5,19fccf61,a9132332,b6786ed8,5cdc4a32,a7c4969d,2a366e8c,ef249745,fd6a3412,2e7f5403,73bf3ec4,21991101,ef7c7650,a5838337), -S(2cbd46ae,663bf92f,87d280d6,9ccfcc6e,37fc8d87,c586e7c5,891e57d9,9815f71d,40312f04,51f4b2da,ce2dac4,f6c91fe8,209fa78,60bb6247,dcdc1a1a,da4bffcc), -S(4a5fa6b,21e4cc49,83620a2e,1c13a4d,3aab84cf,4e4aa616,a4e0b340,dc1db441,8cb91277,671abe8d,c0252252,665537fe,6037a7ac,8aa142cd,6cae37f5,606313da), -S(48b756e6,3bca3d84,475e90e,23db898d,cf319138,a2bf14c1,a820e9f,768cfb35,e4b5972e,d058b90e,f38087dd,82c619a1,59a42a00,aaf7dfce,a89f679e,96d48d77), -S(6a5157b8,85721f0f,42fb387e,b50f9314,fed50fde,59bee2c4,2a12973a,2fb06b13,7d51867c,834fb385,7bcf64,c2d89094,6784d2dc,e635ad9c,6e902525,ed48f51c), -S(2788ac60,8c691e57,e062972d,398be225,16f625d4,f952f37,2c9c38db,eceacb43,6e469eaf,32db4014,12279b66,181003a3,1d6101af,5b3c24cd,dd4cf420,d71fb38b), -S(7659a365,db31c14f,ebcdc3f7,d8483383,7eb7255a,25b38956,fe013449,89176796,9db1f7f8,cddaed52,178c6d1c,ab762acb,11fc79ca,330638fd,7ee34652,35934b3d), -S(317436fa,cc0f540,dbdb8acc,e9c35266,fc4f01be,b65f3457,9655f1ff,dda3ad7a,deaf8c78,33c26e4a,f1eaf83d,16226488,ad2dac5,639cfe17,2b92f16d,95ca71e7), -S(a92f4493,84a1acb5,fc26ddf9,36b59373,bdbe563d,eb05e446,917a4414,f6e0359f,dfe5c80a,b676487b,b334e9c8,c67cff03,905905dc,a0dad7b5,c3604de,cb456d90), -S(fca66bb2,e3b45c58,2499e52e,d0c12034,2796ae4c,466391f8,ccc81f80,cc8b91ab,12c840c9,b9b20dbf,8c24ba00,59db5469,99f9f2e0,ecdfe4cf,e1f8195,31f0802d), -S(d773f231,295c4836,6c012e24,a825c921,7a1b1657,dd0f3ba7,49a541e8,b380284a,b4ef8d00,66b260a7,7b01a0fc,a4e9b8d6,31265f1b,94834e5c,f778dbd1,ec03e892), -S(af63a268,5669fe68,f3c25538,ae3cb24c,ea5aeabb,51bb6318,ae8f3bcf,3d49d198,ad7f1474,606d40a8,5e4606ee,f95c3034,f64551aa,fcab48b3,3de68f1e,eac43a08), -S(6329c0ed,27a5bc0b,b02eeb67,e79b015a,2d58ebac,9a0270f,559b6bad,f75073cb,a5ffb0e8,12e1f2a,b63c5c30,745bcd8c,cc0e9825,3ea223c3,850119e,74cda400), -S(3d4b56c3,5b51c6be,fb380e04,7e3f05a2,2d5e90fe,55cb584a,aa2e909d,a80b2a76,ff0f8a0b,f6742113,c99401d4,a4f2132e,1e6f41ce,b21241c7,986713e4,4215810f), -S(d84552b,5b70fced,a8053aac,63d2cf8e,7e6abc35,88a467c8,1193eab1,63adc404,d2f36d9,e296f0e0,1f01ac9e,30fa7db7,46a97608,2208d90b,60e4fc00,816a9580), -S(b46206b7,984144eb,a6655c9c,8aaf0658,6083971e,5f77da3f,96b260f7,8dfc4763,ef70665c,b881d9fb,c296ca88,10fbd9a2,17288e92,c0225f06,e072bf53,7830df3a), -S(b38355d3,a0b1cbdc,343c0a38,4c7f0653,b9726bdd,1a3bbd34,2614fd54,409b0864,a7cfc80,895c9ae7,36aee67e,aabe29ab,61223e08,deb06542,62393dad,eb9d4ce5), -S(a423de5c,338efcec,58349f16,70e8ea11,bab0c78a,be0d2442,4ddcd2e0,294f0bb2,e9a2e0d0,90e31783,f2d1abd5,a46e4649,33e3f111,b6f1d3c4,d7b8c93c,5975b2a2), -S(54ea680d,959b1824,15e66f4,622b6a2e,1dafbd8a,1756fbbe,d622ea43,e443c673,5d57314b,44923737,9e116877,e6f74a31,63a2ee66,44c74e42,b8617855,3ca7f009), -S(2bf96fdb,32c84cc5,7a37a941,8f5d8de3,67373eb5,a9e401cc,ab2c86bf,c4a265ac,b0a83c7a,e9ba4985,3c78bc14,8a891c75,3c259c16,4c620a73,8ab2bd3d,7b291851), -S(2425f73e,f25aa0da,588e5a96,51e91bfd,3953fb43,cf1142ed,28341f6c,c0d94885,acec2cca,1798f9bc,2b844f62,5212c411,52dc665b,c6e99704,19108b38,dc9b7cd), -S(d387f2d8,2b130fc1,80f940b8,6bca2c6c,d29fed99,2c3129e2,e1155d0e,415a1e98,af31ff4c,8312a574,9d0a9860,cfba0446,2cc8e2d1,6b516511,1225d4c7,7d388373), -S(a34c6211,815459f5,679b5518,5bb311ea,efaff5b9,cc0175bf,ecf58957,f616d49d,c88078a8,b1d1839d,c1941e5f,300f6876,63be4a91,9766063f,bfcb1e35,d81b4871), -S(cf8a62f0,66e4d06,f2cba109,8c3267f8,a435b03d,c1900e47,3eeeb3d2,bc3d7909,1e3bd7ab,5445163d,2bf834c4,2a425414,af72694a,be85a1ed,e8c53910,df5ee50b), -S(c9f930b0,a80350c,c66d2de5,ae6a8165,9a2f80a0,6c01fdde,3436a7de,5da09d2d,79ceccd4,8a9c6cac,ad77a4bc,255e7cb5,976d29d6,a3d814a7,e504cfdf,66b3af2), -S(dd05c586,86b98f5b,7ba2c17b,e3507e2d,83c31d80,eadf33d9,291abbac,e525a4bd,cdce214c,5525efa9,5e3f7dc5,8ef4bdda,d0429ed9,c59a8aa5,d520433c,eee8a34e), -S(d432cb8e,276f7e79,36f455d4,6ee3327e,70e6ae4b,a04c6ea4,9dc02557,a40a30f,d2c4a0c9,4a6ff7e5,c254bd8b,d24862ba,857b3748,9ecf2cc0,74265907,2b5be899), -S(a3b51478,dedaebf9,a5f59c9c,d7b4bd69,158c5c92,9511c5e1,d4ae7a84,b57a5d9b,e766b796,15010b2c,83a69c19,8c524b3b,10780e8b,e4fc62f8,a2ecabb4,f6fe3f51), -S(39f79580,7530e55e,3b985e2b,763fd21,78ff03b9,56b02a42,faaa87f,3100002f,bd3d83a4,e01de784,c2d106b,e645ea4d,5b6efa85,a52f17fd,c82bfde2,79761c93), -S(a3382f,9f706246,7ff434f,54e1841f,a18d8554,c3011852,f4803343,15c6a360,e4b43770,354c7ffe,29685ebc,64272360,8447cbbc,279b7e67,14bd9479,5298a156), -S(6d09fb4f,a6228cd0,93dab47d,99435c7e,9c6e2524,34c59792,bb2dd18,448a2bde,1f047149,31b69744,d6f7d61e,43e44853,6577fc6b,c2335282,109119e0,d5978db), -S(2a55377f,875e99b3,8d7c0afe,eb3e7491,1f8e41cc,8acf09d7,e9bc9763,697dd91b,14e2693e,81e893e1,67045a2e,a2be9a41,faa81fee,9e864071,f672c629,119b10db), -S(da913380,16f20888,9bfb4371,82ec0b6,1efa4d6f,14eb6f3,808c6b81,2336be7d,1776f0c2,f3cad01a,a0582732,2d2136dd,7e6020e,237a1329,6377b1a9,a3f411ea), -S(fd413737,14e6b895,9a289039,3370617f,37437de7,5c3061e9,4bd5d61,d1dcb42c,56b62876,86af6b96,a73e041e,2c45a439,468e5e18,2d91d9fd,1222d732,eaf1dbf4), -S(d39cd710,47956112,3e7679b5,cd14f400,8e1b6524,8d16d1,9b4313fc,8af4b38f,ef65114d,7e747603,b9ae1127,e1fbbffa,f488462f,3aa38844,dbc26e29,abc314e4), -S(617a173a,528ce0be,77371444,9ebf2d76,f9b58ceb,6ac21d58,885f1dc8,693870a4,52715ae3,ce098246,c6f08660,6e9ebf94,14266165,a354d81e,fb48c9a1,13688e21), -S(1350609,6f5c3382,b280837d,e640c142,65ad14c2,d06a95a1,4838014b,12569784,ac6f4d30,443fe46e,236f331d,980ccf92,d8fc5928,48a75841,c7e9f328,6b25f8ef), -S(494ca163,2000b61e,f513c04c,6f0c2e72,565fb1d2,ed371c25,8de1713e,d467531,611b3bf6,6b9efbfa,f6efd046,c426350b,cdf5536f,4134cfb9,1b4a3225,b2f096ee), -S(3fb9cb47,b84f05fe,72df9ab2,32bd4e83,da049679,ae09a93f,4081cc49,660784db,d9628fcb,1f9deca8,79d19c37,59845e55,94effc2,f0364775,9fe3838c,2674cec), -S(496f829e,b09f2d4,ff69b9f,d4e058d,de547d2d,8cff573c,3728cabb,eb59e58b,64bbf6ef,fddfb044,6e20d42d,4b34b3e4,8823839a,be3a0fb1,2654b8e9,b13a89f5), -S(dfce1042,841252f4,d1524b2c,817f3ce8,85821df9,913048e0,21aba64e,eb10799,118a24dc,eebd2a19,df7b2b0,71fd3073,e21c68c9,2aaf61c8,1fe1afd3,13dafc47), -S(2c1b46,91eba809,95ae941f,70cd60ff,a8988faa,e115c265,3c5b94a9,1e26a0d3,6c50b88e,cdd60794,32bae140,90afaee3,cbc38f76,7f7c5463,c244f9f6,54375ec8), -S(f8d91c91,1fbdf774,6829c779,cc7eb877,498b42eb,fdc8dfa4,3c81eb58,2983c45e,b80c785a,d936896f,504215e0,92eb3365,344d9a6f,763e1361,a34fcd5c,9b489f7), -S(cb9e013f,95b3ef75,2a9a15a3,5ff471c6,6d25acf8,66e89c79,f963666a,c299dbeb,3b117868,5c7e93fb,6c920f4c,25e48118,5f3e8f22,552b4e13,10dcbcab,e0e31d2c), -S(6d3a170f,6be4f0d,6c915593,7c0c7e8a,d43def0a,54876947,a36ff7e0,3103aef8,6fc40770,541ef68c,1d8e63af,18d99209,9313c6b6,6e1fdcfd,359c3a88,900f96bd), -S(ab498e5b,49558ca4,2099c7b2,14c070d,8d61e649,73fed001,11b526eb,c3ec6474,189c85f2,b1b63783,877f008d,b2ebd590,37dbd82d,865175b8,5b6376c,b2e265b5), -S(6d969788,f5204548,d2eae98,87cb5e1b,429a8fa1,8f44cd3d,32f36699,a9ce6671,a08f674a,8de23cec,d0c53cb6,29cc24ca,8c5dcd42,4ae8a7d2,8d43f2e7,57c70317), -S(3b5f696b,5d15291c,75f915f0,f043a622,1cd58678,6c7a0ae8,4533c0d4,d4ef7b58,7aee88a0,c4dd59f2,303c8b80,ed337b67,da3b33ae,fdb66c9a,3952df26,443bda02), -S(4905bed0,798f2ffe,24decf40,d3695efb,deb8fb3b,bd734395,3b027e71,9b8d057a,4365db64,4c598c10,6e4e4e91,f67f44f3,bb62140a,b5298f79,2ce32668,69ad25b4), -S(e1cb11ee,ecf54858,85575261,b749e51,db6cc08a,347fcada,da4dae9c,b6709ad0,a02e375f,da9346e9,f2473432,d74debc2,f70f5727,94027b27,6a699f0b,6206cc83), -S(53e44395,533e62a7,3f97e7b0,d449283b,7151a653,1b13d03b,154f458e,c839c5fb,ac3a2b9,c9c3f174,ec24deef,e16d8da7,f04e7776,9599207e,5fb71eb1,4dedde61), -S(5946135b,230ce11e,d28d5222,ae55d780,dc8d2fde,53342755,76546af5,d493426a,198b96aa,f9922a55,5910b8e,b8bdafcf,d700b230,aa926f90,625ebb56,4a8e488f), -S(4a238646,f0d38511,6d1b997b,6085d90e,b79b1289,53861526,55e60f79,6d378304,99da664b,5f5174b4,1dd056a9,9189e563,55d04622,17d5ca49,c61d01a4,48c94c47), -S(7234b856,dbebdbb8,f20c1fd3,4b719188,7d4ae91,3c596418,2a8455ee,d8fa34d0,2a6b196a,2eb98ca4,fa3ab40c,2b96ca16,eefa888a,5cac8676,d4f4680a,3f9c2b01), -S(dda23494,413dfc0e,f09cc4f4,8e5968ed,f9366e4e,6473afe9,eaf26c0b,7c50a347,ed097195,60b470b0,399aa60e,7210d398,eed8d9ee,1f410b36,71e2485c,c7e218c2), -S(8a8c177c,4617c43,3fdcc6c0,8685bed7,3dbe567b,31773907,acf77cdb,d95ab7f0,27adb686,1572821c,25b40be6,524fd3ac,d801877a,f689f4d2,aade7949,fc3b2248), -S(c40b2617,dcf23ff6,f1bcb76b,dd96a198,7e6ba559,1b14b267,42d5439f,653eff49,eb18ff9a,61e73c26,3ab4eb64,aa53a301,97325c38,2fbec2ee,407af143,7e102468), -S(eaa452cb,813053ba,da8be243,c5bb6c76,f3a2e87,97a5f83c,af7d15f1,e07d8088,15fde99f,89d0c428,979e0b96,83cecfd2,52117580,1dc8f7b9,ebbb1fd9,f02199a9), -S(5fdb7a4b,1dfc0d2e,42c10078,25da5cd5,a3b90346,daff2152,3b9b75e2,d1855fba,3dc00aba,890bd133,6ac4d676,9aed62df,db9a281d,2412fb9a,8e9aeafb,58bbc5da), -S(6f7cf42b,f4b09098,26538863,6c24770a,2c7789f5,dd1ffc5d,5382bc1d,fbb6df44,5ea4dbe0,dcc4a01d,4d7e6660,3026fc41,f0dfa1b,893d4934,5d05d75c,6faecebf), -S(1063f63e,51e3aad3,bf91e892,8b1b8fe5,1b941177,6580c056,60361280,63fc7629,6565cca5,5de4a54,777b24b6,7753a880,7155d632,5bace707,dabb9062,3bdb9b37), -S(f0d88838,9ed3ef56,688985b6,6077fd8,63f2e1b1,67cca7b1,e135a7a8,343e6b55,1764653c,86deecf0,ec350009,1f320d07,db1ff9a9,dd497488,386b2006,e12d2ad0), -S(9ccec5a2,869a95ed,ac9e3dfb,c19c552b,5f04ce3d,5478b16d,c28b6fc6,8b8ba0cb,838b79c1,25b010a3,624be75e,89dedc5d,9b6385e2,65f4283d,93a5271a,f896d0f5), -S(22427c29,2f19da5a,3e4a0454,9b3b35f4,901e2ac4,e073943f,5c41c733,69d5fdc,493252b7,a0a13723,baf56860,949490a9,15f2ced1,cd5c4207,9ac64efc,c94c518b), -S(78041b80,76e8935a,986a269c,68fb1bca,66d1f84b,3cb75ae6,bdfc7428,7ed74b9d,4a73feac,2a7058a2,f193e338,607c4f39,41aeeabc,d1126f0d,f4917623,afa180df), -S(ddaf719d,78d58c3,ae253ba,9cb24640,7c589367,af122d0d,a9a38d25,1d1aa757,8f7e649e,ab08bb70,f052beeb,46321ccd,9f8fba5c,e6e81dba,40b7da63,d3aa8c63), -S(3e28ec5c,4d9fac25,17b857e2,2d1e2c3e,fd9d507e,3619a21b,9d957588,769e5257,fe8b4326,fa187a9c,fadb417f,94914cee,b689f1e6,86402e88,d5a8b8e0,d9ffadd7), -S(2c659f7d,37d2ac1b,e372dee0,f6cb4997,c7dd990c,e8b1f06d,79b49aa5,a8a83ca0,c90bd67,dc1faad2,ab4086be,f7a6b310,39592bf9,3a949f0c,5793ef46,d9136fb8), -S(d4afa87e,2dc5a4aa,d001b27c,87989350,1afa374d,85a2002e,e5111bf5,d7da03a4,39d697c8,614df67d,295d7fff,20a0e333,6045bba4,6d565962,91665f18,83816707), -S(12de6449,860786cf,215f9285,a28946dd,668b0ed2,f8a0012c,c785f441,3386271d,39d68f4b,42aa5ca9,99c1953e,c216418a,7a1b83bc,c534cd8f,f50dcb25,2ed08d61), -S(19e539ec,986bc292,c0993b43,e8f03988,81fc72b0,53d530d2,812c971b,b53e35a3,41e96a03,31462b0e,e38f6a2b,774e154c,22ece598,7400c199,4aff2beb,340dcf8e), -S(3a6d63f6,e0083404,c768869c,a180b659,3efda9eb,f2a38385,7bc32e84,5e7a9f63,2897d84d,a8a13aa2,e2b96f22,d97fac13,5e65739e,ce341c1f,1e188d0d,6b29d765), -S(6fbf7d9c,5238b959,1e29dde1,cd092621,86a3f216,c8252b7d,dae85433,b08e642a,7a52157a,6c78af5e,2b9c21e6,64aea1ad,36bdf11a,459e2fb8,205fb818,d6f635df), -S(6bfe3a73,6211e70d,78be3665,fcdca331,a73d6a3f,f2cc9e50,df5b87a9,737b6d1d,1809c07d,7c997a60,d2bc187f,7ff527ff,8f162fea,10475684,6cd95920,5233391b), -S(c6f521ed,441c39dc,23c11ed4,5399ccd1,4b83e00d,524c8163,8cb0c0c7,ecd3a0c8,dfccf249,6223886a,e520ed1c,d84f4663,b44aab90,85ed836f,756a3b16,72775f4a), -S(be39757b,c2537f0f,c4c67c93,f2dc2830,b464d3c2,672f3d96,8051db68,57e6cfd9,30047462,b2f2ec23,2901060e,b05f6697,78fa42ff,ff05922b,2c253927,4d350a9f), -S(8cf591a1,9c98e274,a83cc687,ee992acb,3255320d,e3cbbea6,57fc790f,a2b84d0b,1f2d8a14,66b75c5a,34e9ba8f,6e96bc0c,6ab5e9e,e704919b,96a8d2e,87e29f81), -S(339c0d5e,5e28c33,b298bbfb,73ab7a8d,89f4b1f2,6ee853a,83d9865f,3480166,b63bb64f,7c99b7d1,15430fa5,125552a1,201fbe11,c1b90f69,a539e6e0,a8c2bf4f), -S(7ea652d7,c3309dcd,70f21d5a,e0fea7fb,81790527,c75a51f9,a37beaf2,ce867e72,22974b39,a028964e,97e00cc,7ec3491d,fe9e010,be520d4a,f2e8139a,1c602296), -S(23975673,c1723378,ecf11bbb,90d963dd,ae855472,2321c50c,eaafdde2,2a825762,2d1cd4b2,3aa66041,8fcdafe9,25ad8486,5912b905,b77588b6,deb97db0,effc7ee3), -S(52c0516d,6bef62d6,debd0879,9c96714b,85ade01c,1748053c,2e4647f8,f28e4594,deeea364,bb534e70,b74aee1f,95f528fe,e0b8c239,b6a0c228,1d4b5538,41f0bfc5), -S(a19f26a1,f4fa9b9c,42ca111a,a2b9492c,b95a792d,d23fabb7,e76ad6b5,6117a9fe,10f990c9,e9554447,ab030a5e,2db24dcc,80f17142,aa450d5e,930851fa,8eaa9a40), -S(366786e5,76b32325,1e44e4f6,e5d71c50,5361f771,8e355e3a,558beaa9,52d4a1e9,e76bb0e,ec2325f6,144801e0,d154bd6b,68701212,7233da5,c0daa306,2217c839), -S(ef26121f,f99a553b,ecafaa00,95d9e06,92fac8cb,40ba0331,1eef3b0f,eb291181,5d32068f,a1e9bfa1,487c6993,305e766f,82855bf6,b91339e0,f8804e01,6b6b8691), -S(5d81302b,9d653515,2e54d2c2,10d8dcc4,3a28393b,1da7402b,30410551,21f19b41,5094a844,9dde9d3f,3113ef85,9a0bd7b1,d1756646,bb793080,3007b2a8,f9068fa3), -S(c15513c2,652f8de6,ad273db,67312b3a,6c6c6ef3,7deece21,2703ea2,234cd929,64c2fca2,a392d4fc,ca8402e,146da89,593a1e7,25e34bd6,9c577238,30c4a449), -S(c265755b,5f628680,327c3b04,335a4b60,dee266c0,dd3bec93,708a20a3,c3ac9c1f,1367223f,dae8a304,b32c97b7,505ffc23,21d94115,579a8ca,638959d1,34dc21db), -S(d4acca04,42a53b23,ecc67ae5,d81d147f,ed477480,609fb71d,f0fff78c,20adf544,8b0aa74d,88f9fefa,affc2acd,d36479a9,ac814b3f,8cc3d01f,749ceb0f,9a90f052), -S(2a8cd5bb,2be61c60,615aba87,6df1508d,37f61b15,2429d10b,1f06599,dca26b94,8e6cc5ca,abd1c09d,4615cd80,a582bb71,156be2db,4876720e,6ccae849,5990756e), -S(74d6c1bd,65f37304,360b58bf,c443701e,f2be71f0,b366bd38,f29b876e,954f2f40,4cb209e0,6aa2459,4583b12,8572d25,1c88a2de,6d54057d,19c270d1,bf9c8077), -S(4baf4424,d78546ff,9b28f46f,ab97ca02,94ca48ac,812f13ba,7cc47b4e,ee9eabfc,b4910b45,5e06246a,c99febc8,af1cb0be,807127c7,28e29c16,a94224d2,b633065c), -S(c69cec47,387ab1ac,d20dba21,54625cf5,d42d189,3cc782c3,234e204c,9b7f28ad,514a7b5,fa667f36,bf4df18a,8ced613d,f8579abb,3e90c470,66c40280,85f0de84), -S(7300a33e,7d50b348,c28b4769,8cf8e011,ba6388fa,54a2dce4,7f83968,7b05d5e1,d0ac31f8,1958f36f,9b403154,b6426faf,73078ae2,6c4675f3,19b3bba7,c5c7128e), -S(e989b465,c21d3a2e,60687588,73333148,1e58b3f3,e0bfbcb6,efdd60ae,204e408e,a2d6a205,ada25071,c981db04,f857b005,9f906977,5d607958,7c1479fb,5e44e121), -S(c6afe364,f87a2b1f,92633e44,6b7aaa,74cb626a,79d6f325,263f1b7d,e5af90f1,87197fb9,861d254f,bc8be0d3,afab0831,9064dca1,7e8e1f66,ca55accb,f2d905f5), -S(8a026fc9,1dd4884b,ec8a7e66,cec8b7d8,7b9c78de,127dd3e5,40324032,78f70d22,34cde629,eb1fa38c,d533eac5,fc39bcf3,ae67605a,1ab75537,577a577d,1a75d079), -S(20f33fe4,41217692,124914c7,1750ae1a,86309797,7fb7ccff,93786b98,9e5cfed3,3bd39c87,c3897ed5,52f4a1bb,d8791439,5f1d10b,d827e22,30090b30,7ce9e6fc), -S(47e43518,4cf5e087,3a1b378f,cfa19adf,42abbab4,e0aedc37,2a7b0d0,1033c0fc,aa16a1a4,cadbc035,d774078f,231fe564,53c2b736,858d913f,b90169a5,3951f31e), -S(8fd41b49,adca1b48,574a559d,eb783fd6,6a8c61f8,ddc4950f,883e79f,585351d6,60409c9f,d705fe6,67d796a5,4c0dbd78,41d1b4e2,57f8747b,f69c01d2,7cac9bc5), -S(2091cea6,d9c5ac79,3c3dabda,89bba911,8d96dec1,42f77c5a,83e85c75,d67a5c91,493384b8,83d83be1,b1528700,6f466ac1,b9f5873f,4f99e8c3,b6077594,b8ba019e), -S(ecb086f2,36fc71ff,e455f9ea,3bd542d0,18d6c2c0,9564813c,5da7fea0,81568b68,24603a60,7f05cba,4d10fce,972241ca,f05b491b,dc2f324d,8fa93ec3,99359a2a), -S(364a9ddc,759693ea,cff66ed1,74e7c450,3197a2a8,a743b2eb,b7065e5d,307d4d52,11184aad,92fc83bb,11752b22,6d0290eb,725b5e4a,a2e6e25c,2095ab26,e34764c9), -S(3465069c,a194aadb,e5ae30df,f2d6eff8,1dd3acf8,7a01f6f7,38e24347,b2c6ee70,ded48ab,ac058655,e27a52ec,3ad5b9e9,d1ae3c39,25f0fcd6,b6e8ea5a,f490d15b), -S(ed1ee361,9b6709d7,cf029876,d9ad4ac,3c3bef69,c58476f6,ec719730,1f29eeb2,2c775e17,43f8422d,83b76860,d8a244ca,6a0abbc9,590a3249,1fe6817f,f395fc46), -S(194c6897,27039b42,d9d7a7a1,fc1cc4c0,ae1c16ca,9bf576d0,bab0ff09,c6d478a4,21e309ff,77590d33,9c408879,315c64b2,cfdd06c4,5b744238,1722e974,8f78734a), -S(6e9c1ed6,3fa52d39,74bd11a5,f32c382b,a6ea80c8,109a630b,39cfb9ef,50e92ca,edb9e34b,eb734475,ae167b20,900e86cd,134a2d6b,568db142,22122a54,32ee140), -S(b0db1eff,53cad7cf,ba686559,80c0b90f,6f8f1747,fe53912a,17d6ed61,c696a010,a3f2b2f,110e29e3,8d6a4518,18f04f79,6392b2a8,2d2dafb,6f0a627f,d9fbad48), -S(185fcfdb,db26b6e2,a1ebe2f6,b28b6cef,d02132ca,aa2f53f5,af734cf7,cac6e6a6,754e39e,62471511,e8d077bb,43023072,a52e9fab,d987066c,e5327cb8,a12bd843), -S(434df3c2,cd69896b,fe2ecfa6,6a9c0107,5d12283a,4a34fa68,fa2cd077,da271328,fc13d680,92b22495,fd846672,901e1679,8ec01444,5b25c11b,79ac93f0,423ae41a), -S(c2d222b8,15409db,6a5624a1,5aca06d0,56591dd6,10cb3b4f,bdde456f,608e6849,63a0a035,f5705e5e,17c95f7e,a0a93926,9da8894f,7b4f607d,b47fb04b,bada6261), -S(7c88c681,13468659,d7d89b,477ea11d,5f0443c0,cfa3baeb,6404a383,8be05b34,34b1e4d4,4a29b75a,8f6ba2b4,cf35e7b9,a9953269,30cab213,3f21325e,6f772cb1), -S(42426b3f,833b995b,825bf9c4,ee753d65,ccea144e,8cdf413a,63520819,2f1c79d5,8f188fd7,890baa42,520f957d,a12376c6,23c894ed,e48dc7d7,a8ca9300,77b9df19), -S(560c13fb,86f0a75e,24a24647,11be1c46,d7671f58,fa9c7340,df201d92,5c574518,79f5167a,315097b2,ba5bc761,34f19125,671f67b8,b9b64a07,ee8414a8,f0194ba3), -S(2dee64f7,6cb69a16,aa7245ac,afebd2d,6e46bd1f,4de9af60,fbbdad76,a84f3854,7196b1d2,fa453e67,7fe7a5f5,73e51022,9a7b7539,af0fd02a,b487cd57,46f970f0), -S(31ac84c,e896a814,3a978d7b,ed2a3ae5,d0ce9783,6717ea8c,1f44999a,d6baf5b3,24096db,a006766e,b9be4e81,9d53fb2e,c145b7b5,13cc77b7,8d175cbd,160b86e9), -S(af903e81,1b36c12f,b263759a,7905c2b7,d5bc640,ffba9974,86eabc6b,b639af8d,efa986f3,84f8ea74,2a1be187,55b500a9,22fd9ffd,5a54515e,3e5ce3fd,76d59f48), -S(cf6257f,bca09ea8,34d9da9c,b208eb8a,9d7cac38,5b6dacc3,9863adda,4eaac68b,189b50e,3b68290,ac0657d7,9e885421,e90f270c,3bd0528c,fdcc1857,9f403351), -S(32e61b5,f46e796c,ad8bbd01,41004e5e,81a2b2c2,8446352b,749f1840,9ab2e076,2ad27a1d,ed77dee9,f0ee3ba2,fe97d752,3e974514,ccfd3988,a7f0e1c2,3ac6059e), -S(5079d7cd,fc1f0f4e,decfcfd3,ee5c66cc,beb84197,d1cb9836,e04a7ee8,5e76fb94,5cc95d46,ffcf5873,cfffc0df,6e8c2599,a358fb46,3ea1baf0,225b7fd5,f6a3bf80), -S(b62c8158,5be8295f,29472b7b,b1cda9cd,bd61f9c4,23a085eb,1a31257d,fd72cec6,1d9fbcaf,7fb9e15d,eb992ddb,d09f91e7,f3c9dfd5,d4f1601a,1c303f1a,657c2b7), -S(1c74344e,8088b2d9,1d93f5fd,87a92e9b,9d97a160,2d8bfe33,d8b90b9c,af944f28,a8d98144,3354526d,14d03ae,3a2d2a3e,ad88c0f0,8d9cbad6,666f533f,3cf56656), -S(12cd5403,87768461,8098cc27,ac7e7ba4,9d697ab0,188aa938,483f06e6,7c94e95f,8c0b02f0,1d3836f2,7e5a5028,bb061a32,3389ed3f,fb1a606b,9113c205,9004994c), -S(36abd4f7,7f45d01b,2347a556,ed4c01e7,4c82611b,7e1afe94,13c43e71,29d36406,c160f21c,f4befb28,60ae1ae9,e7da4b16,242b3c6e,f129e309,7b3738a6,95fb9223), -S(199740c7,91588e9a,3c5fd265,19624ff8,ecd4335e,1fdcc482,749821c7,b0301fe6,a316790b,5704bab2,1b6dffcd,19b15604,c30b6057,8543ab6,a3f52de7,ea459c79), -S(14dc3eb3,59ea830a,b8827de0,59db6f55,4319478d,b4750e16,80a21d62,d2d6138d,82c28f9,a3ea5004,7253eaae,2c62df4e,fd4b92fa,17fce544,3c04086d,9038f5ee), -S(6d288843,e16918b2,5895f837,9f75ec44,36ff7559,8a26bec1,bcbdc683,3979c2f4,aa99f61b,59f3f7da,6efd2945,9e09fe0b,54cd2de6,cd70c538,99def857,4e0805fd), -S(9074a3f7,709dc3be,c191f276,a425278,e1d7bbb,a33e080b,cee68373,6f49714f,3eed8639,fdcbdd3c,56ea731d,dd99f99e,77a59ac6,970318c1,7d7c0801,f71b58f1), -S(b9789069,f400101e,6120d9e9,eb95ac97,203bb7b9,701578b8,364764af,d9c4f9e6,afe1ea3b,2634c97f,75e0cc9d,29d9aeb1,c035a048,a68aef3a,7c21bdca,e55c7c6e), -S(55e06b0e,ffe9047a,dd0f2d2f,567b0dd7,d67a589f,50cc684d,88a779fd,c60ebbd6,d0d2b49a,c9347ac4,b8143fde,23b6ab2e,b25b761,4dd862af,3a0d1dda,a79175ba), -S(c81b2c54,96a1db4d,aec6ca5f,b8b0cda0,68a7a049,6fed0d3e,3dea861,27337291,d11e206b,26f9daa0,731b4c28,f65feeaf,8e78f6d8,cf3bc973,873f6d2d,7d2f0d3c), -S(b202ab85,678ad74b,c007535,1016a995,5795ae15,3dc85df6,2d7178b7,e5e37cfb,e6f922f5,6c6944f0,2e643a19,d39c120c,4cb60a44,af353de2,ec653179,9ef84da7), -S(ee0deb59,e956cba8,cb9ca8fe,7c86da8d,33e1287c,616fdec0,1ba68ab9,3de8632c,63af5457,e9b6af60,9b1dc6ad,a19723a1,23e710e7,d03fe98c,5f709c1d,2456181), -S(e7e8f3e3,ca10115e,c7dce3e0,5dbf95fa,f39f537f,b8af8d86,773d9684,8417b28,158c1768,814f518d,a0904747,b96bb7fe,328f8e45,df9c2c35,9f192789,2e7d2441), -S(3b8e4edb,ab45ae8f,17670b3,ddc01fc1,7733143e,208498af,931234dd,c992c51a,e846f581,2a049bbe,94d59a62,dd43817b,fd635e7c,8eb9ca19,80b6bab9,96211c4f), -S(9117c67e,ae125762,75694252,bd88c13d,5aa5786b,2b01aabc,319c600,86b4c26c,c86a9fb,5ec90f3,a2ad0be0,d36061f1,e572e1d0,63034c81,5285a389,2f05bba1), -S(4388869b,17025257,4b754639,a7da1513,1cb9e2a7,b93ffd3f,2b254d7f,430cd1e8,9ce82f3f,4780a2de,f60d4dc1,cfe83ed3,9eac907f,4cf180a2,b829a0e6,292ab6d7), -S(98c583dc,d55186d0,54f3858b,ca84df9a,ff66e333,3fadd076,53cd87cb,66dea0ab,7877ea9,d3a5acb5,553d45b2,55e4ff92,47842b51,4342cdf6,667f83d8,a41b6155), -S(86c393a3,e24b29d4,b26ba9a0,5ce4e1bd,29214489,cde00c4d,1f4ec788,43409ef6,700b9044,8c95138e,a0adccf3,137fa827,702571fc,e1731223,ba1b4ea1,4a37d06a), -S(25d6bf73,6966cdb4,6fb06f43,83c64965,d462e118,258c36e7,76d4e193,13c0cf5c,99a98bcb,d518d7e3,7964dd4d,d677a735,8a886225,28df1cfb,f6d0e999,259e680d), -S(4e3dc2f9,cda6d077,bab34d7b,3dbfed33,5c3f85c,b350f895,5c8811f7,60c61af0,4f35e49b,6b8137e8,58c6b2f3,81ece9dc,de81b5b6,27e6274b,53d6a0e2,c5e01652), -S(4ce8d8e3,5f1a301e,c2dfd13d,43ad1f20,ae756b0b,34ef7bdc,a8f30c70,194f3f15,7e2508c8,324b8e31,2a603176,b1fc0a33,dec501b4,23e73c2c,416aed6e,2b19a3da), -S(2744cab9,e7999a7d,901b91b7,4d221bf8,be41b064,396be42e,46c80536,c5218267,db9b4ff,80782ddd,d0701665,43d94eed,ba19234b,c1881bb,47362cb8,8d90a0bd), -S(90381b83,5adc54a2,d7bc1e27,2f7a0738,dbce1103,db2b21c3,3c45242c,1ac591c0,a3c25f2a,333d8cdd,256f6f6d,d5a7e34,3332e527,50a12a2b,fb00fb37,3213d22d), -S(abdf4e8b,2437703e,6125dfc3,a33d41d8,b7ea311f,fd9b62b0,7546f6d4,8ed7af05,77a66284,1cdc961c,ac1b0990,5877f7a4,28213472,5e95684b,461bac1e,de6bffe7), -S(9f31c9e,6fe48e14,1a9bb99e,75486eb3,5896f990,e247bc05,cb648452,75cb645f,3ae168e8,b4ffed16,bec4422f,43385c17,a83597aa,692b6097,e48e542d,98ea4932), -S(2801ae6b,2083f345,6840a79f,23d638a9,a878d689,39651668,ce82c0f2,e77bb8ac,66f4fca2,c2fc9926,36ed5d9b,5b070607,f0e75d2,8474a8cd,256db66b,d4cd0d39), -S(c307afc2,d2de5ab6,3b5c5d6d,4d25c03,6278716,37f20fc2,175f6631,55172255,6f287265,4d518555,1da8c16b,9d0dcb2a,f0843b68,a3a756c5,5b6716b3,b151da1), -S(e0d0f3c9,866512f1,f78f58b1,8e573d98,6c5d978c,a5f6e73f,75509808,b2b90e6e,3c766220,204ee2fe,9d65a7c3,96e37c81,cd2de736,bfdb6c89,48f59394,38df3cdc), -S(5dce8200,28630e45,1b754c65,8946f4fd,9e4b15e2,e40116b6,acfbd145,29ff8a3c,af743c2e,5f578bea,2c9a6323,32f8fd0c,be7d385e,1e84d6e2,ccc52574,39ff3e41), -S(cf6f6b23,5d10351b,73664b8d,4e2f407a,38fad688,fd90662,29459b13,cf84acdd,c20ede1f,ca2792dd,c5a0d88b,bd8befc1,746a137e,d25defd0,c8b1c5e4,7f3bde93), -S(e73f238c,62efe49f,97359a82,467cfaa7,a7fa39af,35223bf,dc2e82d0,6162b6e6,14ad9128,d74bd306,b91df3c3,c846f203,dabafc11,49d2e8c5,99841964,954b51f9), -S(2aafc65a,f573533e,8d8e1ab3,19c11cde,60a02481,32296117,1455fae2,4f5814eb,a083c95e,cfc67a96,1f3d8b7f,ed66e2f3,c3f6175d,512a38f0,b6d974ba,cbaa4509), -S(f278ec4e,b0d210e3,24abe42b,d1d376a8,244d28d8,614b1260,e48214c6,8161b90b,507cf667,3bbc53b0,d507ff6,cb4a1c79,745b483d,487c6934,4fb4401c,275f4a00), -S(29bab26e,23fca95d,beff49f8,e5b742ed,2b32eece,f7f4d696,4a88b4de,d2b773e6,2e1b3d56,7afd6483,7bb7af1c,7be68427,bbfdae5a,43907e0a,d1f4d3c3,7ce44428), -S(a3a41ab9,8d2804de,81077a4b,73fb3832,f90edd3,40118b32,44a08633,1bd21c5a,5e292792,a0cc3fd,1df5f1e9,7c639cdb,f33b0f21,cf536e64,a2354757,ed523641), -S(3b84dce1,5e9b6ed5,b40cd906,c22a08fc,5a637d96,71c91615,d4038bb0,a3e6affb,7d2729c7,94a19c44,18851c6a,9b813735,f53bba0b,111eab88,b29fa27a,1d189b24), -S(e1a1de5b,2893e1b3,fd7d434a,d22493d5,1479e56e,2bd1699c,30fc8ee6,58c6c13a,c41ada21,d2d07fc4,f26035e5,b4d1deb2,15bb4f2c,d050b300,2d075f86,516a2ce7), -S(23b7c994,1a9a6b03,50707c20,3363b025,665fe450,bf5a89c9,d0dfa7fd,84ea303b,ed7e3e90,c09805b1,46f1f365,45fd2899,ef75f01b,47d12fed,275936b7,e2682da6), -S(56cce967,aeb8e65d,7f2897ff,e881e695,d0260f40,fa8facfe,38c0a050,19e5b160,aad07728,b298e06,ff562b76,70ec1717,c80f136,3ef477ac,abfb3b78,fb655b77), -S(8bd02de,4abac82a,3b50d1bb,7c721a38,9cdc2812,2dfe48f3,fcd30969,4d0f4191,5be841df,84a2251c,e69c2f39,690dfad8,92620119,7ba36028,861f6c6d,d32a93bf), -S(43b066ff,fd91b621,fc9b062,e0f9d362,bf02e492,f764381e,ba49a4f,2fad5662,3fb10c39,cf37eafb,162efc89,f548c8f4,eb5877d6,7e8587f9,4b8b9ce5,9aad7164), -S(89ea2a07,bfc99034,c3e9e7af,ebf87fe2,2d9b23e,e62e038c,321cb2e3,dbb8c7c5,c3069964,6a19d602,7f3dfb8d,9008556d,f969f576,61e562fc,8356c3b2,d3159a50), -S(6c382393,553e177e,164c1f38,d403df46,d05c856e,a41d7d71,3ac0cbad,1f202019,2a716067,37801041,46212c8a,4e6f7716,4c57ab39,df129e77,f31631bf,3206696a), -S(aea725d7,e59c8ce,b646ffe5,d4791760,988e4cd,d23e38cc,cbf610fa,f7066223,e0e7929a,980ca7f2,2fb46dd5,4e1b879d,3e77358,f42208af,d1a3a003,3ba0e593), -S(159ccc54,b888fc90,1f75e688,def8712e,5f79491d,5d47712d,ba3b0c12,ae2f4c84,c1ee2b1d,ec27ac4b,9f8ddcf3,74cf8696,6b353204,690b4467,d752edad,53ff5804), -S(aed9251,982bbf59,d7cc815d,fcdcff0e,76adfc30,61a042bf,1cb5fb3b,60acedab,6e90b10d,a2b23e6d,9a2abdf7,830906aa,d286c9a9,65f28a32,ab9ced92,5c966725), -S(4d669885,c053bf77,f1126cfa,f8db351d,3642c916,1a01d76c,8fb0a20a,3a54adec,6bbbcfe9,ac74987c,2e50e036,74e4ede3,5ea37b79,ab8154a4,396a15de,dd02865d), -S(1240d1a8,a04fb12e,813feea6,d0a6601c,9e6caf03,64df94e7,d2a5b522,5994ec2f,bb502ef,dff84c2c,17dd34c8,909e5a4a,cc1e6e64,aee237da,b8485004,9d09c5f), -S(7ccdef5e,4543615b,a07a8dd6,419926d4,47fb6eff,312d638e,3f5b0363,7d00a96a,7ca83bd1,3f056f7c,c46e6f2d,41ac1e9d,846c5f6f,570d956f,4c9f91b2,8e95a5b), -S(5c30be59,1bdbd093,321d2fff,ec167539,d794e22,d4b2cb53,d33c608b,cac23f25,2e44eb7b,d6a6a544,99b28ea3,865db2c2,f53de940,17e8a03b,e34ed7c8,fc70b64b), -S(fd59cf82,8f64f7d1,10c7137c,5d091b3d,7fbef206,1d2ce5e6,addf2157,c83c0578,9edcc796,7515edda,bbf4e048,5e70bd50,cb9dff87,6753d41c,6f22241d,824bd7dd), -S(5be3a507,ef4b75cd,75158a2f,aec4a5a2,d4cb85b3,92e7ccf,506661b5,5c77e277,92e45bee,9d914f7f,7e687de2,f7eb0004,5e9f9628,3e9332cd,97f5fdb9,a21a937f), -S(d1c94e0,473992b3,307b9031,93785bc1,d2c2d14b,ace6ff4a,8fc7b251,e629d3a1,9cb04ad2,8525fd34,d8fc59c7,280c72d,74fc9f2d,6ab1a5a5,c186f7bf,fb14a940), -S(7db048b3,4c03dca3,7c53df3e,6a94d789,f53308d6,a57f347e,d32d5b3d,4ab3ab03,4a7be537,189997b9,1f420593,add91bdd,fe7fd47d,6684dc21,afbc443a,68a879d6), -S(73005a1b,1ab1f7a1,ffa38625,e0d37dd1,8b54f49,34d38e64,832a78ca,c51b7e5f,6f8b689c,50fe7da2,27cc8be8,cd066588,30d4a2b8,1e80365f,526f590,96508640), -S(34cb6623,26ea9b37,c0f47c45,acb2dc87,92471834,84f9357b,e8d4894c,d4d3dae8,ae989ad4,96e480bc,375d3df,61fb2ae3,a18e6100,cbe1a40f,d090c5ea,8ebcc0c9), -S(ef5c4b6d,cf92cf9a,cd00cd86,63a44223,a49120aa,bc439f72,e6a6a7a2,13e206fa,be4790e9,d1982dfa,5e037c81,ddfdd6f7,802718e0,ebfaacf4,685a1f2a,ff9c5c38), -S(32cab877,84d37189,5ea4e2e3,22586a8d,30b86c1,fa5ecb76,573d5106,bf5f16b7,bcd4f788,20807923,7e5f1487,8d05e2aa,afb2049e,aa4c1dab,8985e413,f758de56), -S(bb183eae,900fb0ca,80e3f021,64e2291,4e40eed6,ceb4d7c,89539ad3,132d628d,94bfdd19,e0bba445,d453a0a3,e95423e5,c7c027cb,fd76df3c,93532317,fe9381ad), -S(605387d8,51ee5aa4,f39288e3,a656addc,72ac4251,5ca1c4a8,509341b3,5819c1b6,55ce59b6,8d58b114,f8a6ce41,86f8a390,9698aeaf,e1576bc1,af37713e,70a550c7), -S(2d971b20,46f30b55,9e8c1638,fde42108,60172bf2,cc088ec6,2c845f0c,4050043d,762ce259,e63f1da,7bb80d4,b23a0368,dd0ee680,aeb90a54,a0ea814d,904b1dd5), -S(5c89b962,e56d242,53a98bbf,14a8e0d9,c9a0a908,635f7717,ec2f2a0f,6a5c3641,28d38188,1e14e248,417dc0b7,5561a875,6163e1db,8517cd4f,f888df08,ab7f2974), -S(3210dcd3,617fd3e5,3da2e0f1,a6d23c20,ba27c0b6,920aea90,bd87a732,8a8fe963,171d81cc,64f4e8a9,ef43aa77,95a1821d,4b672eb3,20555016,dae40ae2,2cf24cef), -S(f00dca15,e2358867,6c9a4b9a,46706b61,af249336,99572f44,ddd87ea2,33b8b6f,3e2e529b,3010ab9c,66c73021,f28b018f,57b270ae,aabd4b4a,a2ec2a32,952125b4), -S(9d69dde8,d344fc3f,74e9c43a,eba9753a,fc22cf58,df6a430,b86b560d,c952d62,2b667455,844a1c5f,1ad56133,99e28380,d8f2b7dc,76f80817,a72ccc87,3f376e4d), -S(4fcfb13b,7a0c8f3c,1c2e943e,806ffe11,850cf942,bc5bade,5b4653c8,9f6a1cce,21e53c12,102089fd,1f010e1b,d009ff34,9d5e4d63,f299d613,d4492763,278ff580), -S(9173a3aa,b16ecd8d,5c3f2889,ddb1ee1c,2a4681fc,35926b42,7411899f,ed851a03,532556ef,794276eb,779b339b,9131f8f9,bea01f29,2018498c,c77ff751,dbc2170e)}, -{S(761cab41,3916a1f5,e131f337,e9023519,6199f789,87ef390b,3f2d8bfa,b0e9bbc6,f10272df,f7e91c40,3565da85,17fd3011,bde7b797,526d3c3,f00fb28e,f26dbd91), -S(c20afed,99f345eb,7ef90636,89598022,d06191dc,7e376b44,71036b03,1e6baa02,471f7c90,681c42fb,b2157f8d,629fafd4,87285270,6a4ab39e,c57f0de0,dece8837), -S(c1f66d62,532b6a50,fe1c1712,e2ef2258,4c03742b,7eea27fc,efad13a3,de1ddbff,49001db5,c9b8b3bf,7206526a,3a868c45,1b45eae7,586c3bcb,4685810a,52a62978), -S(684aaeac,cc13fd4e,d3dfa9a5,ebab742f,c5b9ecb3,81b49fdf,afc37edb,3b165ee5,78c2a82f,7e8484b3,9f808983,402c64b,4329c656,49bbdb29,1925baa4,89992ff1), -S(9a5a9331,3591b8b2,b3381f72,7dfa6c5b,343b9e3a,1b1c9c4,c6c9859d,e82fa566,d23e49ad,5099ba1e,58d800a5,c2e658a5,8be77b8e,ee9ef143,c541921b,671bba35), -S(37cdb6ec,c924c1c7,7fd0ae7e,d9baf38e,b46ea5cf,a161c78e,e4673968,f3eff2d2,fe025569,9a9e1ece,42619791,55cb0241,a3d16834,ef35500,7fb55080,53b161e7), -S(7228ef6c,4acd1d3a,d377d924,46fa894b,6f29926,564b33f5,6fc4968f,f66e8ce7,d4818780,533a52fa,13043159,7b22d8f0,b8ee64da,703b9422,e903595,c78b8a11), -S(78555ce1,101d40ad,88c9eb43,292e8d8c,683dac58,fc8779f7,db22d3f2,e2855ff3,9fe09f2e,660886ed,98f70203,c3308dfa,77476e27,e22c68a4,e43107c2,75501bb), -S(b078bfc2,cb4b10fd,31ce86ff,35770aa7,9979973e,26595e95,913016a9,850b2be6,1bfa79b3,f43ca2c9,93572d28,858a0301,716dfd04,eaee12b4,4e13bf79,a73fba72), -S(c3425e34,3ccc9b6a,a260cf78,7a5e15be,5c698894,2370f66e,826fa1d4,8f60a8b0,55f8dacb,54052f3,a8e42190,e5031fef,34c0eb5f,83bb252e,ac7e6eb8,161a0ab), -S(a8360f0e,4d5fc0e,81598e83,6384a5c0,6c871ff0,d1303179,e5c1c0c4,18a2b7a6,1497e874,db0af96b,35a5bbb,e3097ba8,b6fb1bcb,4d30be17,fe7a5a21,97d0dbab), -S(e02a7309,9807dabe,ee04fef8,36624471,fadbabe3,40507d0e,2abe4468,9c384458,59e707a9,416dd50f,fd07ad54,29d686fb,2402e768,3995c25,2ec4091e,c221582f), -S(fce6ed5e,2293286f,a976695e,8871c763,20af09d2,14964d31,318e197,ef80a398,168b9d4f,c9521ae2,51228f2b,f8de1d2f,8b5b183c,a918ec66,3f37f62,497ab2f7), -S(69616788,b5161a84,80f1b464,5f950703,af731632,ef807400,eab00ee8,581adf57,ab0deb81,73ae5e6a,c35a53bb,829acac1,51db1254,f73ebe70,f99d3cf9,7b3499cb), -S(2c1bdd6a,699f2e02,66d68c5e,22d8a504,8eaee31f,b8687858,555d03c8,1633ad2f,ae63f080,98a21f05,f1017956,c9bb6746,7b2d21ac,f3057151,9fcadc8c,c97d270d), -S(b1e45413,b39af497,da71e953,bfd13826,91ef295,da20be6a,2ea82d57,dedf0c32,a3343fe1,563fdf86,22f93d5e,75892e58,cb927f6f,7d3ddc6,68f87a61,96fd8ff5), -S(f1a182d2,994fa6ff,b6a587bf,a8780f4d,69b2259d,456d10df,2e73eba,4aa83567,a3ab08e,99488c03,939bd170,b4c1a7c4,c0cb8e18,1a713c1a,26f0eef4,8ab805b0), -S(840a512f,e5bbd665,83520649,efeb9284,e25fe4f9,9252dee0,b228d360,c8e6631d,899b91b7,2be1b494,1f5035b6,5c85dcda,4efa88cd,83995cf,42674fcc,486dd4de), -S(d920a9f8,b6ef812f,c021d511,ddfca976,436dc216,36792eaa,736be182,fc5ccfd1,ff26725b,21de311,d3359297,97bb6efc,479aa492,a366a1e,a4de8d9c,f0caf4d8), -S(2766bfc0,aa717b82,e7ad53ee,1604c5a6,2fb3bb6a,c7e4d6d1,4c71165,49b3b2fb,7a52c07e,70feace7,6ad0f704,e1d95215,b29b58df,9ba733d3,8a76f349,2c20b5bc), -S(a503f2de,116e492d,2b8e9cd0,e02cbc7a,56ec245,5ca27f48,7d25b316,65374cff,36a0e6c0,4e8092d6,f07fa375,c7874ac5,5c24119,7a096489,766d1d8b,350c260), -S(c2601313,43856496,92fc4795,ba6eb8a2,f6d052fe,5a8a37a5,76e036ef,163b6f6d,72d27995,ee8bbec0,de1059ee,65b8d4e9,9c828bc0,665c76ba,ff333ca,6a619635), -S(43bfab90,2f3a90de,ab1c7fbd,92b1ca9b,577c51ec,d0a5f1a,de461c84,98eed5e7,42cd4d0c,62858547,4852a2f0,7003fd0d,e37253f6,757f4c67,c2e2b22a,2aae375a), -S(3a6befed,24635ded,c7e2a341,64615858,d3b3029f,99a3f257,fe23725c,6a6d0e2f,5101cb68,d4f1c0ed,c4e33e61,e3f3bc1,99f81564,5aa9b81c,ee94e739,667b37b0), -S(67805b9f,4f6b6813,16940582,7197df9c,ee1b9307,5b4ec69a,61ea52c1,788deae9,a2f64de7,3019d67a,5db36099,b40aab16,d87ec8c4,56285e01,49e382af,81b68ba9), -S(e079dea3,f48dfbbc,ad661a6f,1c0a4627,17343004,cb18e5dd,5a7bb32f,a0e9000c,31706c43,77bd9a87,a27665e,12a60711,bf6b5bf8,acbbb29d,33318a8c,df29c11b), -S(f530e1b8,197ba44e,b7e23206,98a43b13,f05b84c5,5e4dc48,aabc3b16,68fd41b7,12995e58,aa0dc86d,15c483e6,5d01cf7,2f6a6cf8,8b53a983,92f4dad,6bb5202f), -S(974519bc,e9037b7d,84517dc8,a0c45ee6,a0e86ae,947b18c4,3dcaabee,7aaf246f,8fb156a3,cde52064,2f03f5b2,32c66fa3,12946f83,5ef77ec7,8739ce7f,4d45e6a), -S(9cde11c1,233c56e2,37e93006,cd42d785,acb74be2,e7051037,1db72065,5a6ef178,6cb6983d,8e86413b,36049815,3e2c8256,16520a1a,aa7a0370,dfcebc03,9c5da20e), -S(6e67fd2d,25a40ad,df954c26,ea452770,1fd49aa2,e7ba7cc7,17bae4b6,1fc11385,a6d2b87a,5367518a,6705af46,20ac9da2,f4c84c63,bfaaf895,449445ad,5ac0bc1e), -S(aec9f1e1,d101310f,a682316d,bb6de79c,bac5a3d1,133051c1,2a681a97,549aa904,305ed459,4670a52,de8066,9c026bc4,993b7b9b,559fb9d6,75ebd333,2608db68), -S(784d5905,e805d9e2,35e0828b,ac0abb12,7d1efc7c,d1b2f22b,304e142e,10132562,d8a6b329,f29221c9,344718c9,35b6cd3b,28aa5ff9,440cd4e8,6841c5c7,1c97ece2), -S(15e2a17c,6ddd8302,71eb8b67,e2cf6b96,2c75f28b,b5d32ef5,639ced1a,b3d6253c,55ef6683,ca7b8cb0,42ef9f48,fe5788f1,4ab256ad,f6dcfc80,d212db66,a0ee89c0), -S(4b003c6d,f6935da1,cd9cdd9c,4d4ab700,4646cabd,b7921125,98265bdb,5e2b5b36,4e621d0f,55d22df3,89c0a5d,13e3717a,eebcebb0,30d94de7,8b205a14,da58654b), -S(3fd57470,cc7d0704,d551224,5a10125e,d94d393b,3a8eaf0f,b18fdc58,e71eb1f2,2612769b,7528f3bc,9da5a240,f603010f,272b5966,c59a7bc0,a9c751ab,8f72f7dc), -S(aed36630,1d7f9738,dd439355,8174e535,de668758,b5b9ce90,3614562c,58c4fb0a,499e8a8c,befd7d93,a191d702,b39dc61c,1a7f6cf6,85432975,cd3fb006,e62a1bf6), -S(2ba768e6,da7c827a,f5456916,f0015e7c,15baf2bb,ec1e8c6b,936e37e9,376bb32d,850c242a,ae59ad30,e566e244,4b0b58c1,2b5f297e,7e200e29,3a8dbb83,9c5be04f), -S(1ba79c71,f162d72d,65821a17,6d97ee10,9913fc3b,8990d45d,5d6b2e55,4a180765,62258299,6d4376ca,5659a7ef,1771e26c,5a672521,5e69288c,ae16d819,4a845b37), -S(fd54543f,f7e27a72,e3747953,368085ed,945e6e1e,8b16032e,351fbcf4,643efc6b,e2619d2,ee6d935a,cddbc0c7,1727a9d,f5aa2a73,ccbe655a,44a1ff7,b362d55f), -S(ddea80ce,6f9e0bda,4d39337,78136c93,5293885,f0564b23,3c98a5ed,90ed0905,8218bacd,e6049f51,b3e36832,145230d6,776f0158,7c275d36,e8bbab59,c47c40b1), -S(d3dc0b5e,bb26fb78,914b9c9b,30b9b42b,69f20e94,fa8dce28,9f243a64,e53fe5f4,942c3ca8,64d9a7b8,cd21a3d8,32bccab1,c9c9b297,b53a8336,45aa4356,8b1fbb60), -S(30a0cb,8e510a1f,6ee8bdfc,f46d2dbe,be3e43f5,dff3df9c,75f96c9e,a14751ca,f43efc8f,7f47e83d,c940b8df,ab9d413e,bc4abf9d,8f8eac87,b392dd01,7946fb0), -S(1a0fe79a,4028b017,138c1649,dd58de09,7adedcc8,c57d4aab,2bd35b36,91566b2d,340eeec,d2028765,e00dac93,ebff2589,ea9bca7e,f7b7857a,783e5855,2a0cc60a), -S(ccd61837,a08fc389,25890e71,b13fd588,58995bb4,49e9b3d,bee6fd82,12ed1d66,92e1236c,7ba39599,3e71d1c8,44cac95a,9a61347c,b98622c9,92fcee9d,2f593ce9), -S(3b706e43,fd96a62,24853ff7,99df5f89,8670c268,263d27bb,1be885c3,be98a8e7,4319b438,ed6d33fc,c9f4115c,1a91a954,744dffd8,804281c5,df713334,7fb2cfc5), -S(d0441778,af56e7d2,91b83760,e024646d,abcc74b9,7e86a390,e060113f,4a01cef8,300e8744,ede079ea,eb52dfe3,f6373d25,6bb3efc3,26d80965,d65d1307,6780c1e0), -S(bd2769fb,3257a88d,4a5f4ce5,e7fcdb59,7e665429,ec9ff117,54c5bcd0,dcea9509,df765e2a,fc7006de,2459d6e3,c7ee3823,bd8bbda2,dcbbad18,7994b09a,5059d9ef), -S(18cb57b5,eccb921,50c8d8e7,5bbbbda5,ce182f40,67197079,3fe97b50,6c51893b,35b98a01,7f4a620a,172f80e,871e95df,b3dc4d,b30f317b,37809f0c,ba9f2b52), -S(81ec0ee3,4d91b585,b7153a61,2201fa41,fba04c7a,50ea2910,ad33917e,b1e524f2,a53e216a,d069520b,b7d4604,9fe3ef35,74c7bba7,2cef5177,11b6810a,a36f7ace), -S(f9a54c96,729a23ef,ad5e51c2,b8870b51,c68843ac,656b1107,49b23f66,fa013e87,ec0e8e0f,1a16aae8,c2f954cc,ac50fbbf,ed9efed2,25ecde21,dc629c0b,415fd93c), -S(c92adc3d,c2b5101,e9ad2ffd,ea2c448,3a39f563,c767e737,a5a34d1c,e84f2bfa,3e3f49d2,10b76661,71d9af9a,51f72edf,e6248022,cd15afe7,f84e6982,a5525720), -S(d0239502,2a0d5c8,f87f9b08,97daddc5,3a9300d2,1e7aacb4,d72dda9b,4564f418,4fb09e9a,3cdb4551,e56c2a0b,9e59f056,c500e390,e47b5d28,fefbb11a,4791678c), -S(593acca8,29588d90,13a41f35,8dc5e41b,678c7411,164c27ac,895fa933,d1db7978,af3c448c,bd72faff,8a52768a,23c9fdf0,68b5855c,d9f022e1,6eb26ac7,454709c7), -S(6a168acf,7b4f3a51,e56d8924,68fa3a96,d0ea4b9a,e191b860,5a6b96b7,d6834b05,f54540b1,f84d6bc6,4dac1240,ebb61fe0,1f160fb5,c00a1b24,8cdddce7,7db419ad), -S(5fbb8d4f,4b3b8d54,a51bb96b,7f58672a,5d2d6145,dd864799,804ef496,17ed6298,a87435cd,6fc5fc1c,93c4b38d,d7b2e565,88e99f,cc32597,9fe0de65,e8af034c), -S(8942bd97,115688a9,ad84039a,3dc0d80b,bdba443b,8431a530,60560745,876c5373,9366058f,5895e83b,9db6bde7,7da94b22,fbeee36e,b24db502,706de359,a81f74c8), -S(3f7a1620,f93be626,690308d0,ce5a3dae,8eefeaa4,63534032,8c3adc5c,4d68643c,9fc70963,c9b068f2,f6f8813,da2691b8,de3d3b07,c7bc1390,8f8c22dc,135d0bbb), -S(29b4db5c,7224201a,9563fc36,eb7b29d3,d6b0b640,b812591c,af21180b,9eeef26f,c8dcc8d9,8c411723,1db961a9,ea3eddb,46a21aca,b47d90e7,e10167e1,f5fcb81e), -S(f05c4970,392d0487,d8ebe570,fc5292f8,685a4895,5a9c75d1,bbaf2a95,49d0a557,f012d939,5ac0d2e2,f694bdac,dc7535,e126431f,34b8d440,b9aaab34,23774ea0), -S(fb2c83af,6ceec5db,edc822b3,4f1bc35e,90bc388a,5a45ae9f,7c256045,d8daabe,cf9e3e2a,30fa7ff6,30e221d5,7fca78,d4f59145,f4e1c063,2798c471,93a3295a), -S(b63db89d,daf39301,f1243a9d,72ba57c1,31fa2cf7,fd0e486a,c39b8190,a48a3f9d,cbb7ebf5,dc68b80b,6fcbd4f5,90162683,cd8fb0a9,17142da5,aba30eb3,1f83205), -S(c3fd72ab,c247874a,c682a44a,938c3d8d,a7ee950d,722ae51e,ae24d6d7,1ec211f9,23b0ca13,998cb9e4,216e26d3,ed9cd144,bbd2bbb4,b45b1514,e5110fd6,bab1bff1), -S(83f1e25c,209153a8,7fd7f4e2,13328ed3,97a93191,311219ae,c36c76eb,f35e2a9,b93a7947,a553a6db,868451be,96988dc6,7a569d6,6237c110,97f132e0,89c73398), -S(1dbec6a7,32838979,b4e7f03,bf791b5e,614800bb,39a56f68,10af5c09,f10c3eed,f06a2e63,c35e3168,4508a3f9,39bcd071,1892b16a,762bcd6d,85c590e2,92bfa06e), -S(56e98c,c2b21625,e9149fca,61e159e,140f9808,bf781c0c,3159cea0,f7bb51ba,c5e2636b,6bede1c3,a22a03b0,818ddb73,5f073c85,105876c1,4d8f6650,92a61563), -S(a6e497da,d0347dc1,dcf24181,efdc40c7,fb18f480,64803a6e,ab9187bd,deb4d305,88983af5,21f10582,3dac18f5,c6badc0,19e724a5,b748159f,1fa20863,9db7d6fb), -S(bd7df6a,1415e150,9759e259,7abb9edf,cebf8e42,97ca092,60200e4f,53ce53c0,90029a06,2b77274e,7ad517a1,44e3355,f08e23ed,a9161e25,e67511b4,9f32d6ef), -S(dd7a6f4a,c529d120,64d1e89c,b6106d06,8d17502,7f6ffbec,411d38a6,dc327745,bd2caeb7,19d6aa06,c97697af,1eca622f,86cf7083,9e425ac5,b7cb23b8,761d9c48), -S(5220c371,8714884,402f11e5,f93dd80e,f8d10333,f9b054a7,14a1d3a3,9664db0b,3f1fe980,d62ffa5c,d50e3ac,d88aa07d,4c9a91a0,373f1541,cca46699,6c0d76e5), -S(177ef38a,cadec4d7,d8ebceba,53a1b938,f3db0579,7c476cc6,19fb208a,1cb582f3,4f33adb1,bcbfeb1e,b9d91df,c6ce7da,6be73016,6148e3c0,eccbede6,dd3a6a3f), -S(3b99ce03,762fbee2,81bff40e,6c67ba55,fa97842b,b175673a,7f08e362,1d6bd97b,ea6ff097,77f095c0,ad161d60,20f04381,b49cc469,c2e54ffb,1f91ec9,d7523108), -S(5864b293,f81ea7ab,688bb9b0,89f9f1ce,244fec0c,b1e2db6f,9c83f58d,5701f79a,7f4f8900,b3b2a552,e452093c,20436189,d88d4493,12883c32,8ad48678,69aaba61), -S(9bd29db0,c45326e0,3ce95b3e,8a1d13d0,ed868ec7,bc3fbacc,6781a4dc,90695798,7c3fc6b9,462ce670,c1f0a604,52c8da1f,47644c51,e56948a0,a4f6c6d3,34e98b4d), -S(3a4143af,3f07e795,2eedc5d9,b3a8d87c,a52a16d9,9839bdbf,b5b80770,38e03b17,aa749ca6,9b2d316e,650384e7,19d775fc,6a1b09fc,be5f17e8,741fa129,1cc73a34), -S(8b668df6,eb568b1c,6608ec61,b88bbffe,3103a9bf,c4dafd5b,16eb611a,d3d626cb,efcb4ac8,ab30efc3,94db1c4f,2f0476f4,81789d34,2db7244,a8f34266,13977aa), -S(d1b68e26,5936b365,67c11adf,259e8bbb,2a190757,86f2fbba,a76d72ff,7cbfd9f5,57328a80,330997e9,8c8598b2,33ba682b,e6baa6a4,69acad09,6ec3ef2c,be6f6304), -S(84281721,6eb15d31,e2c6faae,1b2140dd,e9ff5419,c0555ff5,d0edfa8b,2d878506,75b6ef23,821def9a,912a7c88,74da9c7,6e4fa036,14dd8fd7,9acc639c,ade2cdc7), -S(e2da1bba,3a895d07,fc86b9b3,dbdd657c,b1ba523b,bc498ac0,eeacdaaf,22e4d77b,aeedcc86,52457101,86cbdec4,90850961,9cf09530,15faa353,f22605fe,2acb7142), -S(9cd8c718,34088f1,7f94db0e,50148e4f,81fc4c44,4c9fa34c,8bfb384d,f9c5e24e,440ef0f0,e8e641ac,ff1b2264,21975338,f711ae9e,e6c7e4ca,54d0d177,244c76d9), -S(6bcf2ff,b6c2e3be,54980550,1c8eab96,e27c814e,9b60ac42,2557317c,10419180,88af1c74,ac893eca,a43a0e44,89ed9ea0,c9e3ef4f,d8329de7,4b09eb36,9e6c8f83), -S(79fa7473,a6699efd,f0f498cf,11c40195,c1288549,d069d451,b05ecab0,fb94c8b8,53a59b8c,fef24cae,6c5f324a,19b8c30e,ddf7311a,b76d5266,ce747a90,1f46f568), -S(e3d80881,849cc86a,4d087062,dc5277a5,388f3d16,3c34503d,d6066eb1,69a5892,b6841ed8,c06ebd0c,e99bd851,afc6e2ac,5752d2c6,2a75a30a,ad1ceb1e,c7a2e70c), -S(5a6759a4,cd2529aa,8c656064,f5c5993b,8c4a90c7,4bfcb2d4,604900b,bbc55edc,5670533c,ecae979b,ed06412,7c9b218d,2f880bce,fc3939c,2db3f572,d3d3977d), -S(2c96f255,368c227,46539a06,303b328d,d8909991,a83cb991,204888d4,f48d38e5,3f8d2f14,61d1f778,83c16e42,dfbd33ed,781dd563,bd5091d1,8dfcea20,4e1eac82), -S(534f93a0,1b8b7cf6,28b721d8,af045176,45667ad4,8bad934f,4df6cefa,5327e4f,25c4e7b2,6716a3,718b9e8d,f9233f46,8e8ecc5,2e851418,13930bff,db89c0a7), -S(b21a8e26,f727f4e4,7d6091fa,1e9f3630,688f031a,fd2a7dba,6b1d682b,a87d6f6d,5bf9d718,9dcbb1e3,84051f7c,df28e4a8,2dddc440,fe8e4602,3f67b018,8513a4ea), -S(7d6964a7,3b5bd658,5bf9f92b,b4462e90,39801914,7042048d,8a55d9c7,13e39477,c4f5059f,2aa5a3df,2556d6eb,9172df43,7229a33,c3fc199b,de7395a9,41651c48), -S(5f5067af,90544909,996efe0f,250ed142,de02bbc0,315427e7,27942762,34d3286f,498a6c71,c77a4aaf,7a5db357,3a3379f9,3c9e0120,8ea82f50,936708fb,298cb60f), -S(1a6b6f9e,4d46ea18,2a4edb33,4873ba99,11e28cce,c0607b65,b716623c,e0372e80,84b1b569,5d3d68aa,5e6d514b,71ab31b1,c7d7196,ccef7fc0,797382df,bcb1f968), -S(361a14d7,c66fcb1e,109248e1,568a9ebc,de67e87,40388cb4,d2c1c0ba,aaf5516,2f3b5f71,3c150080,4af382af,e76c7f7e,f42af72d,fa83a83a,b6aa6688,45577afe), -S(b49601f8,50bc8d0e,7bc1701b,82499b2c,4a334c0e,2d8c1960,c7247300,af4a48d9,b5e2a9a7,ef215ca3,de3b39d5,853f4f22,45a4bd92,70a6f193,4c141a1c,841a7ae3), -S(3c509b32,d8095e48,f5a3087a,6bad9223,c891ce6c,fa781f2e,6c8e7d2e,8803e4ff,5945b1da,102127c5,c6dcaa04,dd00d591,57adaa12,2a3958f5,bb4b393e,b82196e9), -S(936331e0,14fc93bb,1f6a13da,3280d955,3f388e73,1ff74be0,ce36f738,901bc8b2,1862e7b5,6e58670d,5f212886,f91cfd1c,be3572aa,2edd865e,1ec2f254,9d784710), -S(9401e6b,c6183186,d465447e,adbdf85f,45e53eec,b1966dda,1493a387,55092e43,fad8a635,545c84fd,76924675,a328bdc2,61add731,fc63d3cc,57e4b274,24cbc2cf), -S(6849a7b3,6e018d2b,c0f9cc06,539ab30e,43c06fc8,6138dac5,751f0fd1,f1a4484f,ea62553f,a9fe03f0,a8bbe82f,c3974335,8bba3744,8d8c950,fabe4c5f,f20e2bb8), -S(e1d750f3,b3ea7a80,b3a42a39,487c6662,e2e73722,91d06ef8,c38b60d1,e0c22abc,8c59f043,5c12d792,8542f488,2202b79c,e792de21,809d12a4,bbd28675,57d827d4), -S(dc2436d4,268fa173,9fefe9de,81c06975,eca56d51,adcac9c4,2d7696c3,4c4fb4d1,86203b1a,313dcdde,a15f14b8,d3fe3894,e45d829e,14a00991,134ebcb,3a2e6673), -S(58892b5,10923690,2c82f057,45e55487,aa469535,984e350,1888218c,bab6e269,5a93b8d0,2633ec94,a2976bdb,238234f9,dc5ea84b,e3da3a7c,e4cfc628,d7cd9b28), -S(457138fe,f2e48bb9,73975346,80cfcd2b,3b8eff0a,a46fb460,9b6cdd96,168d71e1,f7cec976,ce010d6a,c9b558b4,3a715772,dd707c65,a810b900,2bc9cbc,406523e4), -S(b17e576,69ae6db2,88e6035,da4513e9,d5faf5d6,fc7c66d7,d68cd290,416c4449,2c1087eb,ef93f7e2,3f434394,e0146ffb,543f0e72,9c14c34c,8b22fd26,4f1aeb0), -S(f5ad8e6,968da1b8,ad2e400b,878edabb,77078aae,880938fb,59407313,68e9d809,17f5aab7,a6e19529,39294470,1bc75cdf,3527373f,dd6537d1,781a3e16,338e4b61), -S(f3f4b339,4f876752,7e3e0087,80bda1a6,9cbf9027,cbe131bf,c5b238e4,3e4cedb5,fbca590a,86e7d2d3,c784f04f,b8f5544e,8af59e82,d70549e4,dccc2d26,dd5f74fa), -S(979a2c6b,c24a9fb7,36d1ef74,f177f574,a0ec8220,5a2c3b5a,1f62ed2c,7766bba6,e69b9eb,96c2b65e,e91a5274,94368caa,e1480cfd,12711762,2212257a,cd6ce5b4), -S(b6301e9b,512e74be,92695c18,f18b57be,fc0ff988,87ee39c6,31f067b9,13f62c5b,96d8c690,7b48e6b,c7826af1,486c6ac9,1a3e1818,f7310562,86c995d6,4b0fd835), -S(1b1bfd50,1d5c0b5b,8e778ca1,fcd44b9d,c60bbc43,59ea8cb1,6c69f3aa,3a37df80,995d106b,920df44e,3120dd3c,16875e6,d5abe7aa,62c5d956,ee6baba4,cb77273), -S(b2fdd8f3,9a5f8e84,d75d8bca,d8d483b2,a8477bf6,9c12d250,188d30cb,e7ee289a,b0d183dc,4d971b81,51c6487c,39282272,2365013a,c27e3ef1,c2384ee0,2ca97072), -S(d6e43ada,76252428,bac311dc,5b49851c,79b7cfbc,dee6312d,ea051a88,8819639b,8dc6ead4,53c9781c,d297bee2,56c158fe,9aac410b,d7c392ee,367cecc7,5f86f5e2), -S(9de1baf1,ed24b6e,ee76aae6,566b3da0,2124f7c9,d526c3b2,ad15bbc8,3ec90c3a,e299b84a,acea081a,66e41b0c,5e9c84f0,2ef3bfd6,36c5a99b,4b8aac35,b7f71d9d), -S(9d6a8c3e,2247af1d,394ff76a,ad61dc9e,11da8d15,465bacf7,5075a348,681abc7f,880080f1,89cbca1d,460361e6,5388d177,da4d173,b9b3120a,af9dc8ab,2d7602), -S(6a7186ff,70065f7d,540fd40,f3e8428f,3ba6f0ac,678fa642,653adb41,3684a613,1097de94,8a2e3d94,dedff154,11d35a2f,2f75f9a3,2d65d9ac,2f47d174,24ff9455), -S(64f47f87,f05e4b03,d7d15938,1e81691,e337a08e,57169533,2f34ae8c,901760af,14cc2fce,17eefea,4981f14b,1a24a60e,73f3dd79,54ca12a9,64e1065b,c65545a8), -S(37112309,3f6bf796,11d5492,5978ab39,7e4df483,8f96b51c,39ad10f6,fe648431,45d08953,42004dc1,2cd39ea4,e1365116,b51b9ce1,b88a11ac,16295ca5,ad0f16dc), -S(9b2be865,6be732c2,9fd73a9f,7ec74827,6fc9e5c0,992ade7b,df5984e8,c7c67b2b,1cabae89,b28ae0a,6b58cce1,d9881a05,b9ae4847,5ffc3c63,eb145fa2,cb7182a7), -S(c0206346,71a326f6,5aea417f,a13ef7e5,c1054c57,ff7aa6d2,8bd7302,89243e22,ba986e12,86eb62cc,ab595158,7731c1e5,2e420b11,af4c4b9f,7e7068b7,2e8532ee), -S(cb278985,452e2fea,ec881f24,3c43dff,bac7e2e6,e8af62e0,f1a568a0,f6c67de8,b0d0c6b5,aabda249,237f86b8,f3d4aeef,ff32f9c8,2b349791,a090d5d0,4484a496), -S(9a092478,40008754,1cb7db8f,63d00d68,7a991df3,59e71657,984f3303,2b90c577,d8e49ebb,a2314b8b,2da2a1aa,49dac713,15942701,d264ff9c,e57a8abc,49d54fdf), -S(43e63cd1,d6d96399,724cae75,d5ae4fc5,94b12170,5335a3d7,b12afcee,155560f3,36d2c315,93b939f3,e7791fb2,56ea0cb,ff0374c3,be8eae7d,ef015e42,e595f962), -S(bccc009c,4012a2ae,58ac20bc,90ab1c3e,662fc7d5,57eef6be,120b5da2,25aeb10f,2a30dfd9,7b558c12,ab897ae5,5e3cb4de,3df9ffc5,326004e,8da8586b,364ae92b), -S(1753b47e,3e777908,376103c5,266147d9,2334fc29,a3ee15c4,edc9c8a5,38319f92,eaed6e86,c94a0bdd,f85cb9a0,d32cde01,c6ca2bbe,85607b56,fb363111,fed28447), -S(53f163f8,fdde3cc,39ce973,2c909ca7,29c2c5c7,415b50cf,c03a653d,1a9cf505,3ec19406,c26c6cdb,7f327e0f,1936c0e,bf85908e,49ca6085,5c5c2276,b2511473), -S(5e0545ae,f6d3ce1d,90300f33,827fe4b1,ef9277ef,17d5541,597d6ba8,6f4da13a,5207724a,a83bbaba,cd52b920,e5a6c116,552b010f,21cc8c63,d7fe518b,fed12e32), -S(e800d78b,a04fb045,a18a5f94,de52eebb,640b2ec8,a2159835,d2ecedfc,4bdb3b5a,5f3c4f8c,6bb039dc,150aa758,b4957a30,12e2eff2,657172e8,4e76328,45033b0a), -S(448d9559,94569d0f,9fb5ccd4,baf52bcb,5ca776fa,f49a3b7d,e9698fa5,50c5012,f0a64077,c97f82e4,be4d23f9,17b82f3c,6284c71f,82adc6ca,fee176c8,8b601613), -S(a2550ca7,bfbbff9d,4162360c,1274baad,bcd1c213,1ffd1714,7938fb26,cdea3b4e,4f50424b,1ebf6486,c6c5df10,4388a22d,8cdc707e,9485c87,851beed2,45c7f3eb), -S(af94b7e,f5984caa,2a14ccfa,2acbe4f2,70a0cd31,2caef778,c88b847a,be86b9e4,dde4f647,ebfccaa7,d23a5ac5,28cab9c5,8462a761,844bdbeb,e3498494,cbc16b95), -S(d434b5a3,a3c096e2,19f9e18,11f9b7a9,61ef6eff,a09da242,b595b824,5e8a4843,c068f8e0,30ac02f7,69555f1e,5656ca89,71bab03e,d5e6f865,94b3e4d7,37087350), -S(fef398e2,961ac682,8ee348b6,274a1782,7739420e,7bd36925,3a66e468,3fcfad86,ef1020de,b8d58a4b,be7b39e3,5cab7ef8,4e3269fd,248cb80c,85e83081,8aaed35e), -S(5052a736,dcdc83d,35f65bc8,d1eb40bd,7d8645f2,93bd88e6,aa2c5643,4fb77af,4e203bf8,1632f8cf,8c54c1f5,8f0342c6,612399f,348e7ca5,f9d3fb30,3d8ce1e0), -S(4fb4a757,246defcf,3b8752be,a32e819,c11a239b,97aaa45d,7bbdd92a,53a6cc45,9e6e2cb4,e02bb3d1,14c59aaa,c20150d9,3077600a,257934a7,935ceeb7,994f075), -S(518bb638,148f9d12,f0c9fc04,693745f0,656064a2,4d448224,b60d55ee,a405efa,f719e2ab,16fcc1c7,d110d68,3089a1a4,4fb5823b,db814a93,32456534,995c84d1), -S(8a8fc859,6dcf731,3b700deb,3bf9ddd7,f2732bf,e5928752,236df0e3,a9fe4c4c,896502a8,3c112e5,dbc87e63,c5cb73f5,d206e980,c017484b,999513f5,d5a5b4f), -S(47875c9e,86043157,3bc346db,d8076123,274c32b8,9baa353f,56b4efdf,8a5e7226,45174b75,7eef6f4f,70dc9371,40e72f14,832b9b5a,b44c384a,4c4b6063,1df05942), -S(48644f61,57f3099b,5828bb5a,eb886f51,1515191c,5be0dd69,32ec6618,c3870d61,8804fa4d,b44ed648,e398c863,6eac7c25,ffa3a188,71e3bd6a,395f92b2,259f5db9), -S(d5bbe7dc,9efee9ae,392b735f,b2e250da,a03023df,df0d07e4,ec84f829,bce69ec8,b542595e,dcf7e1eb,11b639dd,65335588,5c3d2491,f4db62a8,e099b7f,9c808be0), -S(ef6037f9,cf9770e7,ae5e9eda,9369caca,c7cf8101,d21c4130,cc119219,f2c3a6c7,5ccea6b,22073857,adb52256,1a37375c,b5f4c574,8716e2af,b26b190d,af69a43b), -S(a5b3fc5,2801baea,1f33f9df,270a1967,dff54723,7d7620f3,70a522e1,983ef747,8399a63,6032cb17,3c648480,74227374,dd19d172,57c74c69,eb7bd6dc,52d071f2), -S(a206b95,e51803ef,40ff83c1,8a6ac2f,553b181e,55d03f13,2536f947,7bc426c6,9149110c,5ba91d60,c25c522a,e5aad669,74a34a40,8ddc9dc8,29b5d976,f2c65867), -S(ff9c9766,f459a87d,c07235c3,3ba55ea7,25a33791,bc851645,d289b53d,1ce6291b,51706cd6,de0d2807,81b1d8ee,9ba5ce53,f6395264,6e509654,def0c037,6015313d), -S(ad502070,787ae242,9f4f9f55,418443e6,4386ceae,b20af7c3,7282399f,9f748994,b428a363,32d4f518,56f81274,d7fc023d,b03bbb08,5087b4bd,8c083c0d,77e1c7d), -S(e38920e9,3a1f1b82,f2ac5f01,ae02fcf,7b9cdcd7,d91fe7e6,14be6130,918746ef,cb55c04c,44e66359,db9a17af,780f0040,e34de88a,d10fe04a,a44da778,dcdbb26f), -S(4c0f9c54,ef982c9,be46ea7d,a380897f,c13ea12a,13de7de8,249c7483,88b30747,5f5da3e8,338e9907,c1b71021,b2177b5e,d90db096,15c78ca9,74445d49,dd5f68d2), -S(c9de9ee7,3aa50f40,b5b7b02a,9cf49627,df5196db,e72d2c58,738e5a0c,61725cb7,75a8ae6f,eb47b5f9,21aecf2d,a4bb8e56,7d4588db,2967c612,a53e1c4d,f392ee8e), -S(ab394e81,140e69ae,af0ba047,a6843253,e9875e48,b61f15e9,fb58d3b2,c61206f,a70db392,a3c6f12c,971b61e9,d92dc2d1,1bd086ab,67475e5d,6977d638,110adbc1), -S(39938f5e,24111c15,253646df,b02b4957,84a578c5,2a982a51,40d36d65,8b492cdb,a5e4ca99,a95aaf09,c3dfb75e,5c9591da,c6711e81,ac5d8fd5,891342b7,24b71598), -S(8b6785b9,82dcc8c3,2b12e79,582dfb2,2ea222b,99f3e5cd,dad2df89,8e621571,319495e2,79101993,ac2fc1d5,1770e668,16150e6,ba4fcd20,65beeeb9,169e6f96), -S(5b4e3ad,d62b1ca5,12bead13,113db6f5,52632ae9,163a4724,6fb7389c,e2775815,b8117dc3,5bb1939f,31c93f33,160daaa4,3114de60,df3db6a,a422a677,51d3fa6c), -S(bb1f0da3,ebe501fd,761e2b01,2711effd,70cd1390,7340b800,65c938b8,c938af6,3cca83b9,a6349423,669abf1c,77ca35dc,5c3c6c1c,e3fca31,6a85d66b,7da7c2e7), -S(deca6934,7ed75676,cc85c372,a0612ca9,c3a1ce69,ba67a7db,f6c92972,3b5f4e25,152adde7,67f4877d,2a9df65,8f86b090,2f2550e6,92fecdf8,9574e808,ad4fc510), -S(1e864048,c9d2a9e9,22bdc2b3,6e21065c,6dfbeae3,77712c02,ff015c61,8f65ab9a,cf00e85d,575641e8,93cc385c,7fa70aa1,22530e4,8f111035,6a50555d,ec004bfa), -S(71af1234,457ecaf3,51fde7,894858c4,90f11cb5,90fd0af,2a854597,50a33ffd,36b78c67,2aa4580e,d9e562c1,3dec5d81,bffe55ca,e5dbb208,5ffe0407,b7809ff8), -S(928ea175,c5b56f9f,a3a76080,f87389df,9b541fdf,fa409fae,8583b5a6,25f20421,5e9effe8,4fc42b4f,4e7647de,a1ee4770,2d436ae1,595bd2ce,6db80fdc,30fe2f1b), -S(28f7f51c,783ae428,73e4067f,34cf5bce,b3e53b66,d319fb7c,7165cca6,63e7d152,86c5d540,629a05b2,1583a470,3e9ecf9b,8f5573fc,ac3d04c4,9132c5ba,f6068196), -S(1d7b9551,af89db75,d2e93d25,49553373,79896eea,2d3cd7c8,fd2b9375,b5a95df4,138bc305,58a1090c,8b85cb0,c15130b1,ad375c45,57437232,a5e6333c,9dc0aaf9), -S(9b03def7,22f1df38,dad6f052,e054faf,9852a74,508808e8,38962518,3043bbc8,e9a6d8be,fbd144bc,bb23fcd7,6620164,82667553,d55a8a98,1b9f8f88,d4e5cec2), -S(c158478,636792dd,e24abf46,926ba57f,4d00f7a6,78efe168,5711abb2,beb3bb62,b772b20b,be7f1d8e,643643da,98b6389f,a28a7846,17207748,6d276d08,5bb3f6df), -S(de68187c,c951a366,ebe2de2,8f676a04,266aa791,f3705229,37ef2e19,fa1d6293,f9f28e1b,5ce0f88,66a04e,b967777,bce1cb,76ee297f,4942abbe,88b8461d), -S(1aeafc3b,f66681f3,fdb82d3,f128b12d,58432fe7,f18c92d9,dfcf272,9cd04262,aeb3fea6,b9568a8e,4152e022,83f60cee,7a8fbf42,ac3c20c7,7e339dc2,e6d5a246), -S(1222eef8,39569e79,d101b6fa,c63bc546,ad9f51e0,e27ea0e0,48da9453,4d8d4bc7,9a4790cf,4b561d6e,3143b80,86911de,49acd2c1,3ad7d975,5dd845c8,fb3bd86a), -S(568e3bbe,91d1ea0a,311018a4,b75dd711,45a6bed3,4b3f7d3f,77c1892c,a7e74fb8,24f9853,51477a98,daffcb95,5b157df7,7a8b6005,84a67fc9,7d427b29,aa74ebe0), -S(cc9f0cda,6a3b96ee,5c74785,dc4a5b97,31d0ef4d,10f97401,6935db23,12164399,bb7a50f8,6b530d0a,73162e59,4334dfca,5d1329cc,b31bc05a,3fa68c7,15c76818), -S(bfc084cb,45fb39b7,db0d16bc,fd1ba13c,a133b6ac,691aa545,bbaca6ec,dcc4bfd0,a528dd00,195c6409,6a9bfcdc,95db1c09,b1e5e0e6,6944616a,2334c297,1be07f40), -S(29cd9485,268288a6,4b1e6491,ba211ac5,94289ba1,199d1eb3,a1c013b6,f5d305c5,95283c31,38a01ae0,7cc119d0,58e8b81f,d5fba6a8,8bb4cde4,11268613,86e20a81), -S(c9aa4323,afeab574,a25023fd,a5775e33,8d216391,b10e1d10,31042e64,21f5667d,31f77398,3699d879,a5d713aa,d9b7f2f6,febd54b3,1a69afdb,d3f52232,a72338f3), -S(3a7d733c,9a73b8d2,4acb08f5,48031cd1,b26845a5,837388d9,68427a97,4cbd234f,693e8214,6e219fbb,b31e048b,8dceb28f,d5ea9b51,cf89a40b,d4f8e935,dffe4dcc), -S(2ee63f80,ccfe610f,7e6db9d4,af8defcc,b24907a7,d49d24b4,c3b5a976,73ee9968,de2bfef,b99069cf,fee3cd66,7eb2875f,3660870e,f61c70f2,6ac6b942,4314af97), -S(e1942251,ebbe37af,412340d9,2900a06d,9ced681d,48d81075,d04833f3,9f72acde,85f78728,4017fa63,28a3aaf3,c6e0750e,ac989642,8ed92993,4cf27e41,d3c37035), -S(d1a6911e,72ddf575,d81589ed,b8995e40,b0843840,72dc1df9,42ba5695,8a759b,71405cfc,f836adf5,b8e8c77,e376a7a8,ba0d4478,a30c6600,82450ba9,7264228a), -S(e02062ae,8b2a4522,4ab441bc,7e9a00d5,4b97a9a7,cca4e2bd,8dc743f1,931b81b5,5b6371d4,345f08ec,cb6db1d2,dea7b9d0,7b49ffdc,d50e9b63,23fdf855,e1cd2243), -S(7327708d,b7d3f037,8bb261ea,7db74eb0,222d891b,e14de28d,2defe3eb,a1f64a93,e71c99e7,627440fa,ad4bd9fd,3fe1a69d,5a8c109a,5165e54f,20113643,3d8baf66), -S(cd57d3f9,a726d2c7,308132bd,bc7401e3,f89d1449,57057bd2,14edcfc8,4e25e560,9e23e46c,3760b31,5c117006,99c2cbe4,319e483a,eca1641,b1a29e81,37633b6e), -S(87dbcc0,91c348f8,593c6807,1d0df231,9421e732,58e76672,e03e4d63,d4073660,823edb4c,fe506e04,49403b68,e4a69101,cca82923,82589a99,a9fd3908,8fff07c1), -S(e3499c7a,cea737f4,8359512e,98a9e5b6,2d27ca35,accb8c2,cc65c7b3,ffd28b8,3a2c7591,f0c91dff,e01a243a,986dea24,fbebc8cf,dc0387f5,78988cbf,ffe017ce), -S(5ac29de7,70553d51,284cd610,b360469a,fcc4ef23,bcee5936,942ef27c,b805779f,2a32b97d,f3e8713e,809d4f79,55525e45,65a60581,5fd582d3,82d7088b,5966523), -S(201ee48b,86a8a93e,8e12b084,2fb9cc37,25e4478e,b9d6d10e,cd1f220,c4a128ce,390e0cef,e6b561a6,6f58c07f,3569e8f6,6a467d2c,cc548281,cbd656f9,f7fbf73b), -S(8f64a6ee,3ffa42d1,e55aaea4,9e00f260,fdd33f21,394aa31d,c17a4328,87ff50cb,867a0189,2f55cc74,6e61a5bf,46796ebf,6c0e2932,b8f9d1df,a5c48af7,e491ef83), -S(5e38512b,65607ae3,f843e223,ec7f95ef,5af4bf35,edf9068,96fa76d6,c302b75f,7adeb25b,bcd0bd27,646956a4,c4a659f9,1db48f2e,532a84b5,7cba0aaa,23e28da7), -S(c812dbf1,732134df,1c459c81,f15cbf3b,4a97f959,18bcc0f,48062b04,bf133649,d22eb1c9,27d57ff7,e0baa4ff,c3b9f74e,116c8a43,ecb10cb7,32745d9e,61e708f8), -S(3f0d8071,56f38368,91a263a1,5177bb12,720eb46b,d6c9abff,5bd2d2ba,ce377b39,348f65fd,f87f7f2a,1dec49e4,8e009fc3,8f916c40,857586d4,e6063772,704d70f), -S(da9c23d4,e4fc5a12,f80b9d65,c2536366,c75a86c8,fd4fb92e,fa5e360b,5ba1993,eb01f616,fb20b8af,522a108d,b81d92f6,3b161963,bee3427b,4a49353b,928da25), -S(d266b680,fa8f6b70,4f8ece54,e52094f8,be493a4b,9a4f396,dfbefba1,4887e18f,564bb0fb,f63b5054,6a930ebf,df1afd93,7f0db851,e460c8f9,67afd274,b735681), -S(b9859cc7,2b573a92,b2752b85,692bf02f,be1f176f,1cb8be2,e954a00b,33e314a5,fb216130,8bba3bc5,cefdf81c,c21981df,2dbf0a83,d98d259,62c879bb,4ce6ab87), -S(8e52468e,486dc34c,c53cc59c,b8c9360,62935ec5,4563b9e0,8daa0a95,f8787f3f,2e3d5c59,90f228a4,e7133352,837eeb62,892e28c,7f8233ec,48ff18a2,d6564c9e), -S(438a2203,af978f12,d28fb3c6,af10ea2,13a954ef,7b0974c7,2b1113b3,e6d03b65,d8f36c0d,d6d4782e,d7194631,7b0a5745,6207517e,379c29b2,ab30cde8,e8ad33c9), -S(1a4982a9,f06bf158,9e395e10,9873ec13,1ef4a00,6a6d7b83,675c3906,1d61fbbf,93e2882e,676591ed,8acf2e3,ff22284d,abe2fab2,bdb99175,5ac72631,c5002747), -S(6ebec1f3,bdd0f019,3bb9a7a9,1d59dd92,5019400a,575dcdf2,33156bf,3e88a47a,c341309d,b462016f,afabbb56,5d763ba6,9c8f2f98,42812afd,fe0e9941,53283ba1), -S(599dc439,687d0dda,a348eb2d,337bd2d9,76a2be69,fdf5e064,1ba87e91,61f45351,c8433a55,411fdd17,ddaa9a86,bd2561c5,8b891c41,d868e764,13e5f3ee,3b3ecc1), -S(5a63cd59,aa9aedc2,91a0d50a,c7d01214,c3788f62,7e3c60ea,84d09ddf,2eb80840,3851bcf3,51ce55f0,4f92eaeb,99b3036d,a06d1f38,2a759217,50e4bf39,7d5ca685), -S(86e089a8,9f1c1644,a2e94b4a,722c6f19,9bb0403f,9a112b59,66191e31,e750f1,91ca06bf,fd48c38c,272594e7,1a113083,f6a4b275,7f279a75,3d70b984,a552e391), -S(2f2c3b0c,dc0feb58,620ab813,c8182510,a2a6f14e,9127153a,358c50f,31238370,7ee136f3,35f076a9,5b80e0dc,a8dfd8b2,691ce9df,5ce0f1b5,5dd9e3db,e156a360), -S(4e2e8b40,8602701a,2d1081d4,e41f81e3,3d9b8465,9959532e,93aca00d,9a70f005,5ec80478,d44bc01e,ad4b544a,20cc58fe,2990c0d2,4d08fc4b,2f9e0a5d,913953a7), -S(98c30f9f,4ef0aed6,17a8fee8,92934d56,10267d6c,e14832c8,b802ca00,320a9c7d,765958cd,15907b0c,dc0ad9bb,217d647f,6c85da72,49260d4d,11ec062f,9d818639), -S(f2b87023,7841e053,a20f2df1,efd265c9,f58e9132,9c280502,61f8c6e3,d6ca5afc,bdcbdcca,67fdf622,84fadc6,4ed6e727,5e82d40e,efdabad,c3d1dccf,fbd32dbb), -S(650f0256,1031a2d6,7549959b,7c358191,cf3fa7a6,30010f57,1006d2a5,20592377,2c4d23a7,44aa3b0c,6359149e,c170866c,b5874045,900b2010,d5a80dc1,e6b2892c), -S(76c3e87a,c72dda23,7ef119a3,9a128507,eba08e31,9f1a7512,5c4dde61,6523fe40,822fa37,8e7c8f19,e02954b2,5faedcda,6d2e0123,ea0b10de,70361487,9a0ec110), -S(472f9e0,9adc7ba9,179a6e8b,22985721,c994c51e,109bdd04,eb2afd6e,fe471f8a,11abccaf,296e7c8d,98e1c3f7,50069ff7,9552ddc8,5e5b55b8,4980ea03,4012072b), -S(4cbb2b87,1f8b975a,2ba257f4,340074d0,7fa897e6,7000795d,d5312e35,cb9453a2,4e31a79c,d842f6da,9e45664a,2878070,1dc87cd2,eb2cb25c,2a7833e5,4e2736e9), -S(ec70b3b,1a95b593,431ac4b5,5825e6a5,2cb88276,27165195,83924921,30805ca2,6092c54a,165bd710,a0e1f36f,18b4e4d4,cfdcf6cc,2f222599,761a9efb,e4d7807), -S(a6b1dda8,e0dfb484,60209710,69cc5398,4e4462f5,a305af62,6b7ada3c,bed5e1f7,e2c113db,21680a63,8f0ea442,52421c0c,41958de3,c7b4a24e,f39546fd,19be201), -S(4a18e595,4105c269,25468ebc,a0c9accb,1710b854,d618cffc,72eee0aa,c0e3f296,1e7cad8,cd248d4c,5dbf0207,a32b67da,2db8c8dd,4798a17b,52ae6445,728e7f6f), -S(eecb1dbb,e2451a48,53054f45,4cc640c4,3e38f20a,3957a192,c2f5827f,9384d11d,a889250,f8bca4ed,5158a55c,197459eb,50b7f10,f74158a1,75180856,b4de62b0), -S(8949f6e9,5e3143e,653889cd,4d57fea4,657aa42d,76e6297d,d20ceecd,d5def67d,e08d4e90,fd929ac6,ac3e87c8,5554e0f2,b584a31e,1be841ad,827c738,3cafeb54), -S(e85b17a0,dcdf256e,51a605c3,1859773d,a0e52a36,6312eb19,9a789246,beb7441e,3505403e,1ab0f77b,984f41e8,a8462c0d,e9d5b500,d0a8f59c,fc83a75,ee063720), -S(c7742a95,6b5c8298,bd1600c7,b756f777,bb4ab2b1,529c8419,d124d402,2b902420,a05ec2b5,8af28f9e,35a86b,4db0634b,5b7017d,7947a023,3db01ff0,64bdecc1), -S(5432c05c,814aeb02,c82e651f,7d1f7b89,e294a76d,17e5ddd0,9ec8140f,cf5a62f2,5902ac55,ddad39dd,da4b35d1,5b84f43b,c13420b6,35f28bce,a60d55a5,78d3afae), -S(39075a61,15bd6870,d1406865,4c8801d4,b9aef508,c880618d,397f9bb0,6674b17a,8bd2702c,96604b83,4114c489,367c3d3e,5e6efd50,c15b8bb3,4b2cb686,b08a49d9), -S(df43a136,af0f754e,599659ce,63d0d48c,73993927,6eef3442,e505c93f,acd025bf,1378d4e4,763c6c79,483597e2,f90824c1,830c8850,fcd32c69,52dab9d9,cd0802a5), -S(840a24a8,314f7e0b,9b3c33bf,7f6cec77,3052a0c5,54a1e180,23772bf5,1d7a4a6d,6e1be7af,f02c4536,f44db655,b859383d,5eabb37e,92b4b896,7ec1acd3,859cb1ab), -S(55d1fe11,49cc5e08,5e9ff19f,9c0823aa,9ecbc1c3,62385bb,e5d33d8d,8156628,b1b96f77,c27f17cd,df4b223e,7343f140,1849d049,4351b2bb,27aed7e8,79b686f5), -S(a8ab1f78,3a7fd00d,f5f4a814,31eed1d7,b767417a,691f28b8,38238da0,cf8fd509,2d747fa3,b164ec83,de89aec8,746781df,f7fcbcd2,67230a85,4802491a,e213a3ca), -S(3cbe8f71,c37679ad,d61e0453,3a1ebb71,99618a3b,9e8139a2,cd751d97,d4a212c0,9216bc42,a61a9734,750470c9,1bdb3fe4,510a5f0,9fa5858b,29eb7b8e,3d19641c), -S(cf1fb09c,a6b5ba69,93303a5b,695ddb27,3b527ffe,9a83e88f,9b5d45d6,b0a8f94e,cea6959,943f7e1d,f1e85391,e08fbba4,b9d84b00,6cecdbb,16f576c7,dd89c814), -S(1854629d,e22365db,5382ddd8,b6840e03,d1e12236,d31c7d10,12e8f83d,3ce1b71a,b25fdfe7,4fb81669,a24cab4e,eece5fc9,689ea40e,205b614c,4a0f250b,8f778b15), -S(6d1ebd8d,69fe133a,2e6628db,70cd4f,15d066db,2b0f42c6,2fc70dde,eb2e89a1,313ee8d9,750c0164,ef561df8,6125e72f,cb5c2233,ea36f971,197c7fe3,acc429ed), -S(29ebf614,7a918ca,371b5121,9efa033f,ff2869fc,618aec33,a4fe7aba,b916e46f,f1d5c067,382d76f4,74c159c,e88ea702,f90ad2c,5b268a7d,14ede7ab,40e11a22), -S(8e2bcc39,f60c4c62,591cd482,8125d08,4d26fc92,2e6ae30f,51882438,93dc5a40,44e3fa3e,64e14ada,e4a0a616,10862503,2e109dd1,c863814,368d423a,f96e9e56), -S(27e17225,1f6a9557,39aaa058,bedd91af,1e920758,cc0724ba,42f44f4d,45e99efa,7dd22a7d,6dc604c1,fe2850d5,41b2392a,b3c3d60f,2e712cd9,179fc5db,5fc179e8), -S(4fb44a50,574d591c,1391dabd,7f40f7bf,14514f65,927466b,2c643f36,d85063d1,fea4e431,63c1123d,9764b70a,cd843281,e108f04a,6fab19e3,da059f51,4c2a73b9), -S(929112b5,19251a93,bfd2715c,6107e5ee,d3283e0d,1849ae37,d110fd4,8eaf6be4,e382b859,a7de2309,a4dca649,66d0b744,9ffe9ba,383379be,d12871b7,19c653a2), -S(532c823a,a090cc4b,128938bc,69adb5c3,3653fc33,fa07d598,36d25ae0,808c0b70,61ecaf31,30a852cb,46de2616,f7bd24ed,8d9e1ad4,efadf570,d08a463d,b127b455), -S(7c7ec9a0,aab8cf1d,36b9447f,d7d82549,d425c217,d25cbea1,3ddb8d5e,e29a38a0,5441d917,1898ee1e,3cca969c,acaa074,62cd236c,a5cccea6,9436a086,e08142a3), -S(a81c85c2,54e52aee,1de1ee45,b79cd027,e1cc6414,4fe99ee,8ad8c572,82c0bad0,1be62473,54bc2bfe,1dc85c68,684fa9da,1ca55a58,6dc4ebc4,3cdb050d,e7acfd7), -S(38f16bb6,da377f25,aadc90b0,7fd21078,5028aed7,85dc0b07,5ad9f04,4b0ffcd7,9563c6c5,531b64a5,d06a5181,d7515b61,4a74f8ba,6226b559,4220282b,b8654273), -S(ea7a49cc,ec294031,87fb5f88,82deef27,2dad9624,76dcacfe,cf128bad,732e1686,49de39f7,5d9a4302,221d9b96,90019013,1ce39a7f,dea1c801,cfc0a2c0,b9a16995), -S(85019851,529364d4,5c84b63f,7f119f20,f3245547,2aa84b42,1ccb239d,fe536868,91b58064,2fdc0f39,284706b5,5b8e4bb8,4e112d5e,68379d94,465c3ac1,8e37cc50), -S(17e41364,244d8f16,22059363,be73839,75ad528f,f1db3390,ee65b106,beb6fe40,e90412d5,5e1b6590,e0d5968b,88dbb0bf,393ccd6f,96748e5a,205ff1b3,2f18a0f0), -S(5b49e7d9,fcad56b6,8b85d934,1b996ceb,6a555ca0,78f8d12a,e58e79f3,1d91caf9,32af7ff5,de4445e6,4bb895c5,316b171a,d911d8d7,81b16115,1e9643ad,4ce21885), -S(42baec78,86aff012,13d9d182,6e031b20,85724be0,268790e9,968d01fa,63e0e366,8298f68b,32e5caab,b8e641e6,720db67e,4150ad69,ebe90143,23f7b981,1ace8d4c), -S(5201710,64afee86,14c28123,5279e1a2,cc2775cc,85a5751e,158c66e9,2fa55d51,d12195c5,a0a08b,7cdca2da,fae86d15,d37427e0,1d266609,dc9c1adc,d5d8039b), -S(bc353c2a,8ca16349,fd021e60,8befb9a,f85c9ebb,b448d732,13220154,a02297c5,88850fa3,a61383bd,133c6fd4,65d12756,37878fb8,84bd3c31,3c4f92a,2b620edb), -S(9490256d,3acd97c2,848b24e8,8b8b2a8a,8635417a,1f228d6f,dccc3917,9c0fa397,4f4ce298,cf1dd296,b7704f9,b8f0a0d5,be42923,80bb917c,5fd49c28,55d3b662), -S(a963e733,ca168104,47ecb136,bbd2047a,97ba8f49,9222736d,eda1c7f1,75c2fff7,5385ed6b,93e6c27f,568566a9,5cf31059,de4ac850,1809319e,ce216eab,c8dc181a), -S(fb44e6f5,eca57845,76439098,2ab24ad,c84efb0,715c3b9d,df0b7b2d,a165702f,a62de478,678bee62,891c5241,9c8e77b9,d573fa6,95b0a2bd,fa5d9d61,c4362e43), -S(c1de1705,6bd1f0f6,8912dc20,29a41689,efb21e22,e24f3fc5,ff5c4498,f4fe7ea6,6297c6c2,a30e8e3c,43f534ef,475c3b35,f2a9550a,c5b9c733,63e117a4,af2829f2), -S(8c78a7cc,e7084890,8ff122c9,108980f8,b2a2b9e2,80e5536c,34b5e13e,61f8e133,459a70a1,5929d848,f8def6ef,ea8f42c,905fddb,3c0153f6,71a17b4a,b7c2c1ad), -S(5204d397,bf3ca5eb,988c1ccc,d23fe613,25202fa,88421157,cc7e7fa8,91b4e612,c02a009e,f89c5b88,b3f3a7a5,40d30ee6,75f94247,60e23fd4,8d8ce1e7,6395b7f5), -S(3cab1091,a0dc43c0,b90c60ee,44d31ecb,607da086,fa6da814,9c378acb,99c67ec9,3bcc5297,267a2da7,e228c7b8,c1677407,93feea54,bf31e3e9,f8e270df,e8d1fd19), -S(e0475cb9,9ecea30e,94ad6292,5ca5c3e7,77c30673,9d9d55c4,464a3e85,cc2f10cd,484818b4,d0f72e79,79427904,9f9aa4d4,8aeebcdb,f7f55a4d,97ddb03e,4f6018c6), -S(1165d67c,11327a34,e702775b,40a9d7b2,deaa423e,7e4d3dff,869f4a9e,3fe6ab73,63c55abf,6943f35,171595c9,63ab061b,a1c9f605,c2ee4970,767ab1cc,1bc691af), -S(f0ca20aa,59ecbddc,cdbd3f3,6c8830bc,9bedd29,b893ff74,48cc523f,bec962b2,6b2ff156,557d16a6,47453361,c4bf9f4f,41bf1e73,8f0c5536,a3dcd50c,ab88a086), -S(a3b01fa3,8e743e32,b623f2a5,cfb7300a,75457d46,6499dd5e,b1453d16,a746cdc7,19fdddaf,28030237,7310920f,3f982394,db89f510,a4a73b08,cacebc6a,2d417c78), -S(37ef5196,c8e2d69b,cc0b26c8,2bc30b9d,650a7ca1,409c77c,11e0a338,c5065ea6,df890a8d,8cb2b669,dc74c96e,19ffdbf5,abd5d898,46240fb9,18c297d6,1275ea86), -S(d99abce,1ecb8415,eaaf50bd,66f4b5f1,a5a4e5e9,d6959735,629d624d,adccbc88,9da9b4fd,2558c726,c44d10ee,f72c4699,80069045,a8660cf7,58de00cc,67be856c), -S(f77fe49c,28595198,7abfa598,915684c0,2af76675,5e2648a6,36f5c955,a78aed61,a764861d,3a8dfe39,92b2e897,ad4bebb0,8c7e2b55,e390efe8,21ffb60a,cf5e4be1), -S(88f6ec1,2aa65721,3f672e10,9d406472,7b89cf88,74dad08b,a4b54747,2bb767f9,8b6253db,a124b7ba,43fdbac8,55f8e9d5,9da23b49,e450c8e5,675442b5,f822b8dc), -S(a13a7136,640d1507,9ed90b77,12a9af52,e53e75af,4583a149,f78c2840,f383fc55,435fa5ab,6454ef1f,ede1b33e,475ffe8e,10dd5a94,4f96f340,1c184642,2672b310), -S(20940c7f,9d4abc67,d42884d0,346551ef,1b2aa54c,d8a1485d,1e23758c,e207a7fa,de5eb4e7,b619e600,3cf9c0f9,7e944f55,ab57fe23,388dbc73,66bb2120,e5aaa793), -S(298e00ed,855dd2f1,c0aef293,c55d859c,3db60fe4,b026f782,1c07d534,cb087e0e,9c45f376,466da662,583ec25b,5bdea3ac,c624731d,4bb62b2,2345fbb1,bf721990), -S(5153ac16,6b837bd3,29d98a22,56a576b9,821376cc,f7e48cb9,24e75f59,ffb6d7a,3f5ebcd5,d5ec2073,f1e43334,7ab4780d,f19a2806,d87a6477,bb73ed09,bec6bd43), -S(78c909a7,c94bcc00,b5518df2,bcd3ec09,9d5d2db0,d15321d5,b3135953,e8e1d195,735e4b40,519f4757,32042f20,410d8699,d1af7a33,94062791,b12e19d7,85ae42ea), -S(e4a4b24f,d9f7ac92,8a888507,c6d21ad4,fdaf62c9,2bb920ec,3ef96d64,a70a8567,b62c1cb7,b0e49cd9,8001dad1,52a2206d,6b397952,be03113f,7ff764cb,505502e1), -S(ca3b64ac,d4aa25df,3e7d4b64,6d5c8032,66809507,7f7f60cc,1e3138a5,2eff4800,92972d13,2f370aac,680f2a2c,feaf4e93,73199207,7f51334f,37553a04,5af089cd), -S(58e22f4b,a636677d,aecc727,d58a6ac5,77d85e31,2d41d56d,1c09c859,749798c5,cdcca924,549c867e,1a11e4dc,27bb00ae,99e0a356,5b6b37dd,26acb58e,f29f3bf0), -S(94dac55d,da61410d,926841a2,4b5ffb24,e44e3ee2,3d42efbd,8afdf3a4,3530363,4095385a,529965de,b01b9a3f,f9647b29,8f3d2119,9bdac924,5aa54df0,7e8d621a), -S(639ca66,8d7940b8,8f41c4cc,eb50b60,203b6884,c8ac9c0d,c33bbf59,926d417c,447035e4,5c9bf80c,71f8aaa3,9f9356c6,672f0db,fa01a4ef,5b1b7400,dbb70a21), -S(a6a9f38a,51d8e82a,7e04f667,e8cd638,af4cb7aa,c8b0ffa9,255f472c,c5b30250,fa935a10,4796943c,1880e3ed,d9c2504c,7e6e4bf,46036119,9458e23a,b0b025bd), -S(60179b5b,cb4ab099,b74f6a9b,853a50f1,582362ca,fd28b288,e2b339f3,27671a8d,5ef8f881,54b7b4af,ba287388,6c09d1d,c12d7070,6b960d0,b0453767,7e5d283d)}, -{S(60b01067,25cf781d,e78ba725,40508697,3f2ff6ec,1511515,6e19384,1fddda7a,624ccf87,f0ec21b9,82efbc4,6d4db878,5d20fb8e,dfe663fc,46660bb7,98c96eb), -S(74164670,d214bccc,23e32dd5,b4e7f093,c95b4628,b7b3448a,347980a,1f9b0323,827aad3a,23a648ab,e0ffef7e,d8a6d6,800e07bd,7eb1b5da,50b5dc2,8994a20c), -S(66a60beb,feb1eb8c,39857b37,158b48c0,93a90cc7,8d8aa58b,af183975,b12fd461,62f95a56,2db16e47,5ef65451,4cf82fc7,1a4379d2,cb4224fd,695d202d,8e85fbf0), -S(77272c7c,cb0ca53,17e660,adfa236c,e062992f,a59c7164,71d89755,f99ee448,a6a2d5ad,7ee9dbd6,d8a9d8d,157860a9,58e3d766,da5b82e1,5bbf83eb,7d987f7d), -S(eab2ac49,209ad561,d3beb05a,5152d5fa,f1af52a8,12ed0d40,c493d611,bd78c73d,c72f5b65,dfb7f960,a8bcf355,b80918ec,a9e8c3b3,985602d3,7ac0cae3,54645f6e), -S(ec184bfd,27c2ed17,25026464,4be6e557,db93ce3e,90ff225d,fb0cabda,cc124952,b4ed4a46,acebcbb3,9103f99e,cb65e208,2aa5990c,eba9fcac,cafdbe55,6a08a516), -S(6f5e0f0e,7c32165f,183f7834,3e12c845,86745ad6,d02d4f29,bf16ffab,31b1de93,76bf7f22,105a881d,6d190e20,bc7b5d89,ad0ee9ac,c1df6905,7035b6f7,6a9d4f61), -S(b3d820a7,466f3cb,d955acb0,c8baa787,e7f0d63f,52f9dc9e,87c6138e,60b9279c,6d769d76,91c1e61f,41b9cdce,949828be,7d17c1d,ff0c5041,7e2e3b79,fb873753), -S(ad92580b,575d6831,d2332a72,f3f888a4,713cd659,bc439870,7c000318,8e7ae426,eea9afc8,471e88c0,22463a9b,c8cb22c5,d0df87f9,201aebc0,519fb7e9,e2307073), -S(54b8cdd7,3204abb4,22d870a6,c5afcb14,81d4f117,a673e60d,155baafd,f3c5d4bb,6aadeaf4,94823ad9,df8d2429,e42a1d6,8aacec78,bf973785,a56120c8,28d23bb0), -S(ef2bb94,f14272a1,e235da4d,4ce4b043,2037c8dc,7ad8d559,958dc767,e0e75f5b,3af91f78,54bae661,9702996e,1defee92,2c0e8c3c,5fa4d37b,261c20bc,14fbed93), -S(13b87d2,8125e63f,1259b1d7,4b79c395,25bed045,256e8b00,84024bdb,48196b7f,139b380c,bba0404,463125e7,a455d454,ce7d811b,c7c14e10,90cef0ae,67d8281), -S(34ab008f,50e1a525,8cc77331,3dbf8510,7f3fda60,7ad5dfba,9aa464fa,856394c1,19178d3f,f5c51bd1,4c6d424e,c42591ea,414de041,7a3f470d,7c35dcda,77e57860), -S(7d872049,c080936c,54875ebc,49a00c41,b837b71a,18de4e70,adcb8369,95c2dfc,b572a6cb,58a2337e,2453110b,eb877a02,bff2bea1,d542714a,3a115a59,933eaea8), -S(72a2644e,2e6d7182,9f78274a,eefc9f15,9861b031,56d20d69,db62b4f8,57dd34ea,82e158bb,dc2d6100,bb5b300e,467470fe,606ddc1f,e662d3eb,3d51d9df,8383263d), -S(de81a355,37cbb00f,76aae7be,d3ce5362,c51426e4,ca012ce8,5d5f0fae,791c106c,10137d33,8a6532e,95917e92,31e5c14b,10551f6c,7bb1cd4b,5944e772,22c0f0e0), -S(f8499694,38918109,b0eced18,766add3d,8e21a5e1,a6eb640b,e4794e21,20400de,9d081c04,cf130095,fd00af83,32408bf6,ab4e262,e5150e3c,9f43a3a3,704b3d8d), -S(a5786625,1f866279,36233299,283e5dc3,838a5d9a,6fc30cdd,cb75ea90,9f3b2e94,57d57841,f173e1e9,e2959908,7e535dc6,a848132a,d6fd98b1,ea2a16e5,ff8c60b1), -S(533053dc,a24ceba7,f528c93b,bf62d61f,ec640ac1,40848f7b,9dde2ccd,f2465df1,d501e49e,3291919d,3c7a280a,1501258e,325e478e,343ae766,61cd9cfb,b856a316), -S(b85608de,dcd5543a,a90fc566,9fd94d52,b041e434,2cffc394,1cce3f40,12c23ebc,dcf01862,1051bab9,d1471d26,99f5727e,705ea2bd,8e5ffe71,df7db441,236df5c1), -S(bd1a08fa,d7d7fbd2,b46565ce,99fe28f9,635e0c41,a8b6aec2,31d949aa,a70d52ca,1a26906c,f77d43fc,ec656be8,5db770bc,65d05482,d6449f52,e23e1e70,6ac2aa15), -S(ee4e9976,9517bc1,2c7adc6c,fde381eb,b385b1a4,bf918268,5f175db9,949c99c3,738250e0,5dd8e427,95728575,fe5733f2,6b083705,301f9138,d736fb24,98c34679), -S(bcbbc6ea,2007057a,1be80335,3d086450,c48e432b,6f80ba43,bf03bebb,c48f9379,10fd6383,b5857977,87d8696,9525e0ae,b1842c23,974353f3,4eb515a1,5ff52435), -S(5c717940,e5e9546a,f9ce9d6d,c260bbed,fb678923,db861b41,1f275f0c,b18b6e02,d9144751,3ab535c0,603fbc12,adf52285,560f029c,266cda2d,69b29090,f5179f68), -S(7137b160,a5eaf92e,fe5f5c90,c3d34063,333f8204,5dd83371,31f624b8,cb7173,3025534d,6303c9a3,6ae38e66,57acdd29,48bfec24,d5ba7709,be051fb3,4537c2b8), -S(a6e79e0b,54c083ea,a6e37b9e,b54c181b,ce397786,c294abf,5d1cf475,fe34c030,aaa6aac8,4709fb5c,ac6a498,c0659da0,e2506e5f,e890c06f,5ed5081c,bd737c71), -S(9a143958,23cf2096,d81677e5,f804bd5b,790ceabb,4b15da9,b35c01f8,c6b1d81d,61bd3e2b,642e9948,50179f0a,947820f3,f241e53d,8222ec73,3ceb8bf4,cb7f08fd), -S(a51aea0e,4039ce66,b3e80814,4582aed9,d0ac0be2,95105a8b,23179025,4a2b0429,7cde7f91,96e8f417,ed7a075c,c25cb694,4e996997,3ce13a4a,941f670a,f523709d), -S(2d79629a,1069878e,76cda780,b9291c4b,45b78b7b,ac98fcd4,3ebff7b6,cc2ad200,cb01aef5,1a5fab94,ec29d73,6ff2370a,df866d45,d977fda5,2b7fe32a,e1d9a3fb), -S(6af74994,feabdaa5,fb0cb613,2f346490,bcb1a70c,7bf58e44,2cd46670,12e050d8,627e7f3e,b4e66be0,672b8bde,f119177e,f878e80c,a7b5661d,d6a9d19f,19729e9d), -S(c367583c,7d2d5d6f,3f00083a,1218645c,568a85ca,8fdc708c,7e8dce2b,c72c3ceb,baa36c7e,1c86d194,ee03efb5,c5e11b47,34bfa6,c168ef3e,fbb78f07,51a7ebab), -S(36b2293a,2dc956f3,47ef5874,9504821a,c9197e25,1716c398,f5c9dc61,c63fd5e0,95c93401,be8f3500,d971ca82,ec97def8,7d58d64b,5e4753cb,4f2cb608,72f2950d), -S(78e80bca,805183f1,76257399,63e9cf9f,a1bf2b88,eaf4147a,17d83057,bcfa32a8,b42e40aa,f852c738,fe1abb8a,e5dce499,414c2113,eb59cd2b,2a3f6c42,fa96812), -S(4f5b3550,887d9ad1,1254333d,7203aadf,d202fe5c,845b3c8f,3c0094fc,e4a32628,a4842bc8,c793e4ed,948dbbd9,cb68b7c9,3bb86827,fa9d7c3f,acfe78bf,670eeb99), -S(8f880914,9dc553da,4ed0b371,70850bfb,c305fce6,d5e7be9c,640be999,8df19b1e,f020f82a,eff490e9,fc7d4d7b,519e780c,21f86f87,5a547693,86524483,ec776674), -S(ed7f98f4,90be919d,d1f570fc,cb565424,c3537bad,d8d80e61,87b51f8d,9ebce164,d374e45b,c81bdc9d,63c824b,1bdeb2ff,5c9a3453,93540ab7,884053b7,107d8066), -S(754d2b67,65625067,14865f65,a89bd0c6,6415aff5,644d37b7,e7437e03,372d70f5,e4b5855c,14ba6a3,360d1519,98358bd0,ec2bd109,ddee46d,7a95050f,5131a9ae), -S(d0778425,311ac57e,b8ffeaee,2001b9fa,89d6cb36,49be46aa,365b81cc,c8bb903a,25e3a484,5f1c15e3,ecf6a654,69a78893,3c414b8d,c92587f9,fc8f54c6,eaf065a0), -S(c7c18e4f,7c8772d4,37e3e861,584d24f7,f428c06f,23730347,2dcfd4d6,80352ff2,6f5a02d8,1c6ff6cb,32e85004,3375c865,57f8659,83e76e0d,4f42a69a,b02ddd52), -S(96c4e50d,eb86020e,b0bfba2f,ba3da698,c7bd031c,78959022,341aa1bd,a19b4a1c,8cd7476a,78098ae2,ca166d9b,c8aa79b1,ffd9f8f0,943286ff,d563008f,6f3cfd5f), -S(3f462649,9a5e5ad9,f5ea71a0,9b4e6b7b,fea33c80,c786715b,15200580,cba306ba,32624f0e,9a3b0413,fa401f8f,6f32995c,74ab592b,792247da,970b89b6,90545bc4), -S(a1495fc5,2c642d7e,da16d1d1,289f2eef,f4993882,f2843128,6d17d34e,5949e2f1,66ce7c4d,611421e8,7f049ceb,11e9f99f,9edf2592,9da6bc45,91ffbfbc,3c73c87), -S(954ad30c,15a6c5b2,deb98983,ba7125c8,e216f1da,5531d258,513b7731,4fc86c0c,39378c22,527387af,e75d630,fa69dc8c,44586372,96e4526e,2e105fd1,af7ba0b9), -S(5692830e,c3ab78cf,6721b604,31abc539,ab14318f,cdd4d6d4,1586772a,bce39a98,5d1d9619,c335acef,22acc9a8,d32ae53e,9b227ede,50ca613d,d67065d1,252c56b8), -S(1cab4f2c,73e452a4,de0e2591,1ed22364,803a060d,ad957184,3c81258c,6a4c518d,27617c5b,d52b5d06,8cd9c2ba,df266f8f,ecdeb4cd,41bd6e0b,a2db6a2,8f4c7f3c), -S(9f1834c0,145eedf2,53211dc2,3339283e,5e7daa72,fbf6b69f,d5642a63,c551bfed,c1838a49,b3289127,7c3365f5,9f69d34a,27b48c6c,8897e9ca,f40d8753,d467d72f), -S(58988653,8035c13d,2c538f0a,1c587f2f,fc08405c,e6a1d7ad,828aef75,43b4ae8a,c4b901b4,beb24774,598bd2b7,d3450791,f2cbb37c,939594b6,593fa592,dee20590), -S(d248754e,c643d300,6d81c5c8,9e91b522,181921bf,627e813,1acab8bb,cb97b2be,76b94631,6668e319,a057648b,2369d781,c2abc77,6aa8805c,43734698,671174e7), -S(f849ae76,ad1bc714,4c2fe13c,b0ee81b3,f9abcca8,d940a161,74a69c0,b2cbfd0b,239aab7f,c1b6c054,a34deeb3,56da4e14,e15643a6,63f40642,b2a43350,80c2883d), -S(561b12a6,2e2fd36c,ca92d85b,14baafff,864e99cf,315d8902,72f81dd3,27d1f04,c4199633,801df02,b34ba9e,13462533,7bd975e3,ceb19673,7bf37bb9,daf30808), -S(8821c52b,c13c4ca5,bc7712da,9e769754,c4ab00d7,83dbc018,b1c5b383,9c41c245,63edc442,6347d646,5ea5c046,820fef62,89a28c47,df834a71,cfa9f5d4,6561444b), -S(382b0dc2,c54b6fcd,dd8ff070,6edf8f4f,2ce34daa,4f7dc15,d7f1ee0,b0ba78a0,31e1e109,35d8c994,3ed05b5a,57d91bce,81ba0f4a,8da1454,98a18e70,17f2fa39), -S(3b4fa983,26fbd82b,59a938f,1aa9d30e,2da395df,f8ed1aa3,c75f0969,b3b85712,57653c2a,8a11d192,4116c658,5b413feb,e8c56142,bda13d6a,175244c4,4b13a396), -S(5ea8db07,47f4f7a4,db0f9494,3dbf8b3b,9b04855f,93737d30,9c7ab27,8c2ba4cb,805b0db0,1d883e3b,a8f82de5,b6bc6c3e,3b05b3ed,4eb16d34,db8df937,19929403), -S(21386763,58a655e1,e878aa8,984bfe61,bbc7f1f,c16c1881,40e2cf21,63431d89,b62d321c,82082b74,4f8817d7,dc464804,c1d3e9ac,220dd1e6,a94f17d8,2250d06f), -S(934eaa8c,bbd3fad3,44cd1996,86b8a7c3,bb0ef384,4e085e55,83030bc2,bb52148f,4613cf3d,ef424be3,af392f4a,6fc474c8,3e3f2d1a,394431c6,5ee6e224,4396774e), -S(99a5472b,e9d06621,7e18be06,d9a1c1e6,a649a5e,61f3726c,87b21a31,7aac5f48,1e5a68d6,de4b2958,70cdd340,8b3d66c4,84eb4002,9d41c1a4,1d30bc97,beb14693), -S(3411cb09,5d5dcb10,49e8b927,5788779f,11516882,cc09ba6c,dac69bae,2c63362,6a3b3241,e6c3c802,dd5105dc,a1b82a8c,6bd31e57,aaaf505,fc41553b,2ac08b4e), -S(f7a6f695,824a413b,8a916cd3,c3403950,38ccc3ba,96803c71,6a498b7b,384d7fc1,7acb457d,3cda4738,bba35848,8bce971,d584ba79,e7432224,6619c0ef,9cff3ed1), -S(d4737f3e,6bce15f1,7ae3a133,bca08f13,434f25e6,8fd36a62,5672e6cf,983b1084,54a81a40,9f08a597,ba4e312d,f8789106,19189132,40f97ae6,b360d510,4a0b47b), -S(5b1e76c7,3f9c8353,b7f3c63f,ff2e48e2,d3bc05fa,857ebcc8,84e582cd,83845327,6024ce76,eaffe03f,951ca26c,a1550d96,f468385c,157d9a79,eb9a20fc,fe841e2f), -S(d201ad7a,72d692d9,e87a7a83,e865965b,48e90ae9,1481a927,34c90133,f725d589,310661e2,9fec5d37,96484ee1,bc6a6f76,e8da9e1c,f10fe672,6dfaf737,d78119d), -S(cd1f2c41,55b8119b,c5b9bc31,e5817a8a,b2268a8b,a526c005,1a3e23a7,abe8bef5,35b8f656,8b84d979,64b29050,77f01e9a,c2024236,29614688,df077aba,1b639048), -S(89c74b7c,e763801f,41ef6dcd,a452fc7f,a39f621b,39fa1061,a2b4bd4a,9649c9db,d5cc7a8e,722df783,82c168f1,91142df3,e15c161e,3a8471ef,236afa5f,a98a9f93), -S(ffcaa11f,317a856f,300df9be,1dce6c40,88bd5c28,b08861d3,87f3492a,d1004bed,ccaa2565,1ce602ba,72c899ad,f5f9be23,910ff5b5,1e3fb1b6,e2eb975b,c43c1492), -S(35903c6b,58659353,391a50b7,1a9c8186,a4dc7ede,f3455ee4,8ecc1470,263e1b8f,d44d9022,a5cfb61,4f56b02d,a83b67e1,4c3eeb78,caee0a4c,7f404471,77ae7ee0), -S(f9138261,2bc1de8,eb9d7062,80ef2b2,fa7fcd30,d157130c,784d7698,dcce5183,4709a971,d0008021,37a9ab87,27a705bf,cf1aacbc,822dab5a,d9334bd5,bcc5fd5e), -S(244ad0f3,26371ef6,f6c29f9b,7ef567ae,98a2abb0,cfa1561b,e9dc7f15,1e8833c7,53c1198c,5ddb33ac,37af979a,f40e321d,e87304d8,62efc794,2c944260,65de386b), -S(cbfeabdb,c93dee73,6f54f500,b33c2d0c,8c66b5af,68dde61f,c820ed3a,1ad2347a,f1416c9e,bc04c0a,792a1288,a20d0544,b7452aed,33f77b86,77b806e7,567914bb), -S(714246f7,3eabb0ac,af298c16,1bda9c3f,11f8fc8e,78b9616,2591242d,f0e870a3,94d8e600,cfe23c05,c9ec81e5,2c9e440a,af477c70,590f5470,31ece7f6,778edc56), -S(d776c80,63f8102e,805317ce,8e0b31dd,7b8b094d,6137c865,184ae51e,e07b924a,e66f3ab8,998ee226,f1259e4d,25d98d35,918b2cfa,abfe56,4a10c8fe,663101a1), -S(ef99b2bf,80bf084a,6483e319,9b4b578c,800eb85a,8634222a,197700c8,92a05310,94fc3ef1,12d050f7,e7d34ade,e89faf30,b651e10a,6931e4a7,ac2ecb48,fab90ba8), -S(c84a0ac1,8b659ffc,ac9e2dc7,57248e23,3d71fa98,90327e76,9441231,666f3790,e0973e42,73cd51dd,7233ca34,43dac778,3cd53c25,6816be1a,fbdd636f,936f7fdb), -S(b5572cfc,61db791c,d8b19da6,6fc11df6,e8776505,c016e6ed,96f17b97,c2edb89e,608ed024,b606b10c,5785811f,8c333fe4,95a726a2,ebe56680,b00b513c,aac4e0b8), -S(68447029,864934d5,92907821,5ec5ab99,3e00bd52,fe4994e,42978327,bf35a6f,31521acd,69c57644,ef35bfa8,cec803a2,e825c740,36a9a3e,fe831364,d00fd897), -S(fc9ee8ac,9fb265a3,7c26358f,8bff851b,d2a7aeba,2dc2a19b,153f649e,97d75605,cde1f563,b971ba67,dcf3d759,2752221a,babd8ab8,1d8a5a4f,3dda35ac,44c01d5), -S(7e86c9a0,d024eef7,91758bd6,899eee23,ff032336,9221f3f4,2b604ffb,33c473f1,2c15df40,6cad3479,841ffa5,14513883,978af93e,42aeba3e,c8ad64f8,df60da24), -S(e2b33d9a,8806ccd1,7d34a916,c4caa169,ffc9673c,e8eacde,19bbb286,85003732,5610c3fb,f0a6b39b,ec5c8cfa,db9296b5,86c6677d,61220ce2,b1d19bd5,9f44f72e), -S(ed6b2e3f,eca9b628,d98e663c,a3c72b0d,b853c8b7,a9cb9c4e,9247b8bf,84b2f3b3,6e45aa3d,f766a732,fe91f124,9148a96b,169e3b88,7dcf90ac,f972e91c,b25ae9cc), -S(78ed22a,c278758d,625e0439,3e273e7c,24acc72a,3975b497,ecad1314,df2de65,a2991712,373d669d,3afa81a5,c1e043fa,24df04e8,cc8fd13,32025186,f459913d), -S(3f3e7509,69153c5,378f64d5,7fce5aae,689f20a,8deb05ff,72077c72,b116996f,63d56b8b,92e77496,b86bd0ef,8bf803fa,f1d040d0,cd42c975,c7a08d7e,fd5056f2), -S(2540390,ca25189f,381b398e,3fd46acf,d5918215,a8bf9a17,d25179aa,fe75c1c,1c6f1725,5cac59d2,ebff7c4e,322694fe,96f5e2b7,e3927c9d,56134007,fc6dd9ec), -S(ed668903,3dee44be,80e9792b,b95408bb,5d38b016,d75490fe,2a22b118,56524fce,1a5c61f5,e738180c,cb533faf,ec9d3def,913ec31a,8c8463f3,df097f81,36375093), -S(a1a86dbc,2061e047,6ecbc303,2d25c159,414a6860,fcd818be,202a0f28,ef803224,ec9fbcb8,31f6720c,1735e505,276acd05,d957ea94,5b3af60b,6e1a2ccb,ede5b706), -S(c6064cdb,4feaaf24,89c35475,54279d3d,f1e96556,e97f1ec3,449fc747,ee8d0a2e,661f040f,ab90e5d,c9931a8b,297f2e61,9a24468e,432fb2b8,84acd0d,5cee7dea), -S(25b5f3a1,656c75ea,4ce2fc9c,bdbd2f36,78ef6e4a,9c2270a8,8b8dad5f,6f55fedf,8c48ac45,dbe199a6,5c9d72c8,7c1940c5,f17f59ca,d0c67211,5c2af898,7b142ec6), -S(b8e77df0,e23c94f,6f982ac4,37540690,441135f0,948f019,b79088d6,9eed91ce,3105acf2,23c01ac5,556b665b,d6b1919c,dde81dbf,7d44e18a,17bf67b2,833265af), -S(2a19c0de,d617ce9f,ff906686,a72bef9b,3ee2200b,ce71aa87,e18c2767,32421500,281d0c8d,dac57006,6c8d32f8,cafa5f54,404a6676,78ae9a0e,a0d19f1d,d0d24a6e), -S(5771b96e,c1a30ad8,d2087016,45df9b92,759c312,cc542ab9,126d3207,827e68df,ab4feadc,4b37a329,bf86e4,81786a0f,e1648794,689d0fed,183d7b48,fd53f760), -S(183fc4c8,62788f1c,7b7036d2,96bf7193,cdc93d6b,533b8c9b,ea28a9c2,9a5a9c10,2c019a73,5cca1086,e73948da,5d15f816,cbed1945,83014a64,24a586cf,501ff5e3), -S(31ebc0ae,656194c2,ee49f25e,28af673c,c65b2224,467ff0cc,920d3780,2dcfee7,d2db8690,89c5f10,b76d2d8f,cfd707d5,db7b3cfb,38903b6f,c4ebabde,47edd669), -S(a843fb7a,af70c96b,e7812f89,789b05c0,63824134,33476cbf,2a2b31cb,5a8d77fc,d0091386,435d082c,38fffaac,671129ab,f5e3461b,dc8295f9,9a064ee8,9371f70), -S(76c82448,6820236f,39701ac0,5290315d,a6f30e30,91d086e8,b3c934a7,871c038b,a4cc0e55,c2048935,c5c11b51,417950e9,dcd4ac6b,839b850e,efd2b890,17f5b4f7), -S(61653255,b4fecb8f,7fe9e6cc,179ded3f,955b359d,cf59cc70,1ee85750,b31a1d63,e197d8c5,d2571f03,931da039,b59989ad,390cac56,4982952b,a17e4d47,56f57582), -S(eaae448c,9a862f27,b55784b7,b3275e1,2d99d369,2aee475,dcf2d3ca,edd500d6,3cf4149b,351205e6,5ce2593a,282264aa,127953df,7da3cf9e,976af775,6be084af), -S(858c766b,faa67e75,672ed7a7,f0bf9b58,14217fca,bfa31b77,326d98a8,f6c7ec83,4d019482,93b2a3e1,d6f16dd8,8160efb,d15e29ae,e4c6b7f8,329127b1,7d0251f9), -S(cd384125,aa1dcc88,fc2c237f,2ff68117,c9517217,5b8c4f9b,a677ddf4,c2ac23a7,cdbbfc3f,d65180af,6a52f3e0,79f169a2,1dbaa8c6,bedcc4ff,be67635a,a1d51e1d), -S(5387bb96,b91fa67c,823e41ec,8dbece4e,cc1b6182,d50fe91f,44a02d74,90088659,bb7baeba,2b744ee6,8ff6ca19,64457de0,62a5e0a6,57edcac5,d6019bdf,caa25e01), -S(31ad9536,a6c16f44,c00189db,ecc8c527,304ab3b3,89bc7425,47fff91f,a088c01e,f48cae34,98357da9,5c47a41f,bb07055e,2061d037,35abe3df,8ff2fac0,cbcc246a), -S(18741256,6398f4b5,d2c34711,fa0e952,bf4de5a0,338bee49,a93daa3a,fdf29a47,5f96f31f,870511f1,a390a0bf,f9d9d383,2a7e3bb5,e8c515aa,f6022437,add8f159), -S(e1e5b96d,cdc60b81,19ca3138,9544c7b2,bfd587ce,6f42188f,115f4ac6,99e60793,cb5d9f4a,6475154c,7a285cdd,b0c115f1,765e357c,f51d8388,c03bf829,9a6720ea), -S(5184ca38,33208dd2,c04279f4,de77916c,fce7b4c2,1d45aadf,293842cd,56fdcd39,268d16e5,59d8488b,a076c82a,9587834e,87ccd65,c98feb69,9ae33005,299d2ec6), -S(d11c12e3,6646124d,c2602f0,b68543f7,e62ac955,8505f479,236ddc03,e9e6251,9d429bb2,d1378d9e,8e986f9f,a3d1349d,607df6b0,c48de566,d537c48e,10aecdd2), -S(d55753b4,93da41b8,f01da15d,ad5e71a3,655de4ae,b56a6fb5,9df058b5,f6636a9d,ee5270ac,db3d0e8d,6b46b948,9740311e,24925894,114d6c4c,52dbbe1,c4118013), -S(3f23ae1e,39238fbb,249606ef,d47502fb,30255e87,97148a90,5e3bf259,92429eae,845208cb,c6420538,410d5b2d,aaa28712,a2b77fdd,5241833f,124dd025,38d515f1), -S(837d504b,7f244155,1003c511,4e905b7,2bd9ea37,c690d9b7,381b2084,9cf7dbca,db355b5c,25d9b17,1167d31c,c5011a6e,2069863b,eb12164d,311e483a,21c2ff), -S(3d7e0c2,dab7f97,866a591b,f8187705,e31b7b3,bfea09c0,502b7a0e,c0037b5c,2a71d18d,f997d233,5a405ecb,d1ba09c8,8b282049,69215d7c,8a390435,8888a41b), -S(99f2faf7,8cdceb1a,70fb3076,3c19d54c,e16aba42,4e75be22,89f0e521,c73f3f23,778f4a0e,25c3844f,5aaa9082,cc985aef,dfe6e692,ab40eac2,9ddf668b,b28d0bee), -S(32dbf023,d57b27e0,5be2989,bbf1637a,7b3133e2,84d434f1,df8dcd56,70f9ec15,91d820ab,7a4f2350,49814592,ed2c46d9,fd7da87,a392b5e5,9dc309e8,ccb863ba), -S(2e413a5,b52d61f7,1290f182,9d24cb58,38339ebc,1b6d46f0,3c55334c,61ff64ce,474be10f,a3afedac,b9c6cee4,640424c,d7d3d6a1,437f2d0e,79e0b20a,8bdf2553), -S(955e7565,6052ab57,d05beac9,fc586758,780b8979,75642db,cd11fbaa,8e9deb7d,9276041f,cab762f9,929a6f54,a619e6aa,9613a794,96d32fe7,2e02ecfb,2a22045b), -S(1d6ec4e2,cc1a1dd3,f116845a,3173d350,c9607bd2,4e6db8e1,64220217,9208d805,2b6ff084,f5c42222,e29ab094,6f82b5b,f1cd6f3d,6d01a2ba,4d0744d7,ea95d0f0), -S(6ba994a7,9090acef,e756192f,91e97d07,82f393f1,c59f3b7a,786beee7,63ff0ec0,5c800150,c9464bb4,57190378,88247938,e26e54b8,93d25b7,6ef7ac83,78733f7f), -S(8b914ecd,2e19697e,83aa0196,70e1f955,530364fa,4f592638,b241a7a4,e07bd8ed,aafab68b,f3587e6d,8a078717,27e91eb8,4d327ad1,6fb89154,52a954af,e85f332e), -S(295e4ed6,380b91a2,a6628b5,820c11cf,ec407294,379b718a,5d4d88b4,3a2f9fd7,4e617c6f,b89074d9,818815e7,2a13d34e,58702106,f1470e80,ffce03d9,ddae9dd8), -S(efd76a5,217fca77,80aa7871,3dfb886a,f0b18e91,857ed243,2af704bd,87cb6187,e8f4d552,5e1e84fe,b89793f2,12a508d2,4b7ad2f2,903c38f0,d6729be1,6449cb1f), -S(44acefc8,e7148bbe,3c634bde,b8e4eb7b,618a135e,9c1b0ec3,6b160975,87284364,5eed55e8,8ba8ba5d,afc804a2,3cd5e1a,c161e4b,69d9bea9,da22b9f4,d130563b), -S(1e7d7ba1,475ff038,1fe4f0b9,71609d3b,d315d10e,329520f,3832418b,541b4174,887863ef,78a7ae20,acde554a,dd436aea,3f61ffc1,24023448,ac8f66fd,5e206869), -S(6fd945fd,d8043a74,c7c57341,a0581ea,c009ac76,1eef33de,277b7205,a7a248cb,6bb15fab,559c4d8f,32fae6f6,fb65c15a,222b022b,c8c57c06,b60f7b05,65f2760f), -S(34ccaf74,39ec22bb,2287400e,663350e0,1bfa2682,2fe851c2,faf4aae6,941bd5c7,91782420,76a254e1,a30b3ee0,29a19110,4af5fc0b,dbee533d,5c62a90d,2d9766dd), -S(554384e1,90581b4f,1bb6d971,9632e002,4476c913,30cdab94,5d8b86c0,491a8362,190ee656,95a73bcc,4faa6dd,9cd0113,ffae600f,fc13cdb8,14b2189,779aad2b), -S(75bc28dd,cf96c6d2,55981f0b,cf08df49,e48b162d,baa21046,89924a39,5db3386a,cd49b1f8,ead093ae,a554b9e4,d2fdcd18,ef614118,cf0baa2d,c83f2c37,92c23175), -S(4d094d69,15e92b69,b36d98d,8bc0e31e,ef6d49b5,d3d11b63,95bdd831,47cd679a,2aeb7bd9,98bb35ca,4554ed6c,91d92042,9945f775,8697684c,d0c63887,cb625264), -S(38b35099,7cde0af0,61ef1a3f,ab9e038e,988f670c,b06b39f,e611a5ed,227831ff,f0531e87,deba2ee2,117bb773,c933b780,71b2b8f1,956dcf8d,af99ee52,d69d67cd), -S(96bceef2,da234989,f4deec66,5a73ec91,6b284242,2a813a3d,f78c131f,4ba2165b,dc844f47,7ac5ea55,114aa18d,65950318,8b6592db,dfa62c75,d191e7d6,bbd70de7), -S(5badf11e,b896ab6e,f49de6bd,7b6adfef,840a0261,b173d89e,884bb453,5d7def8a,939707af,ad49890,2268485f,697d95b1,8082c75e,7b9d379f,4f7143d,27f830f), -S(ece21ae5,f5981e,e05869,fa9e581c,12773fa0,2b463515,55ded999,ce8acdd8,7771180b,9fc2d3f4,ce5d2ce0,a5e15c0f,4c29d135,62eee682,f80cbf26,fb812c9d), -S(650d7149,30417468,cb918e91,6234ff3b,1bd46f06,b90184cf,41d9112f,e472d26d,1f746358,4fd816de,89c86e9,39eab19,62a49305,775d8a86,6eb1ad35,edf48961), -S(f344bbd2,7ae90f73,b6f9a152,603dbcda,f14da6f8,f9ccdadd,88631de7,286b95a8,ae254238,b63ae9fb,89bc5be0,3e36a0bc,3bf15159,27094287,b9278988,b77a8ea), -S(982c94e3,a9dacddd,c1ae1394,cf93f8f4,91fa9261,ddd81e09,826b68e2,992c01f9,7527ad8b,39813588,6000a328,84b4f108,a4d6791e,2fbc86f0,b0038c40,ad280ea5), -S(b9885add,38946d2e,170d4bc2,361e44a2,859f2166,8577a099,f9d42c4a,170ff9db,edd69b3a,21836af3,a68c9e76,a7d62c47,3ee0042,3606ea6d,477126e3,b88f04e2), -S(4b34b984,4f57ae76,8bb666a2,b610b4f3,dc71b651,e23ae7ee,7eb2faa7,73a99e4b,4f4ea965,ccd9e929,b1d2830f,3bfe37bb,53be8f2a,a7c3a67f,9575d508,39cf2580), -S(ac8b24e5,9aa829ba,a7ebc7d1,4a25b14d,f770f0f1,158bd924,50b6e448,5af3bd7f,b25ad04,4954b659,8b8edcda,bc3b28d1,6b42a286,82602977,87c95360,ab2242a1), -S(88ed52a5,29858067,59b3ffe8,c1de8453,29d9c427,b7825931,57d8c927,43f1732c,d9dddf46,92f3d20f,7a99a3ca,a855a272,9143ceea,28c887fd,c054c6f,bfc25ba7), -S(f189d8af,9c34afb4,4dcfdbe7,996375ef,d8b9cac0,86230acd,e6972b19,1e1bba41,9a652729,1209b68f,722ff77e,38af6ff8,8595be0e,e1433afe,787716f4,8c69cc70), -S(6eb98d26,50dd58cd,8b7ee6e9,663585f5,77ccc3bd,3199d34e,2589b2f3,2deecd91,1c794824,bef31b44,b7497bd6,3966ca73,fea5ad7d,f640630c,37800e59,ac3d4afc), -S(75f5ea53,2e89dbfd,cbebd051,c129cfae,437e70e5,ae3a2d89,1b20588,94184ad6,faf379ae,6645548b,573142c6,8665eaee,882de32c,dfdc358,c778ccb2,dbca8107), -S(d62f599a,f29209ae,c7818548,f833ffcd,4d232d6,e297df96,4329d5a9,e7300c4c,61bbc3d3,79088b3d,ae30ad32,da25aa41,17b63b17,84bffd34,9cc7a5dd,9635e587), -S(2dd9167d,388f551,839fcda0,8c0b2f99,5bfb4fac,2f31dfdb,4cdf6822,72389b08,de646ee4,2a53c47f,11214ec7,cc46bb0,31ecd599,5d02935f,d49d9e0d,61c8bc4), -S(5e244f2c,87e222cd,70d4c4db,4020593f,ede6e3eb,fadb2d7,c260a12e,61349323,336b3413,ed5f1f7,f82db066,439e329c,323b5e68,26bd57a1,1038ffd3,2b236d0e), -S(9ceb7373,d13b017,1d1dabb8,4d22a756,52ee75ce,5943238,6784f06,4fa9dc80,80bf893,e4162d17,c7792fd7,d89e283b,7a6f3e88,fbccf0ec,251f09bd,93e46714), -S(aa4de7b3,6d1990f,5b2f2afa,4fa71caf,bb852321,dac68f81,c65cb997,306bf020,6cc882d6,577e5958,8d5a2a8e,ac18f0da,f29cdb84,bb1f6ec7,19b53600,4621196b), -S(dc1db767,2e425cb7,b1dd376f,37bda82c,6fcd98d7,c9dd1831,5368c4f,2e95f5f3,fdcdbdb1,926c987,81c0944e,bd13f28d,97fb9a79,2b7d4b96,8be1cc0e,a1c20b75), -S(3ef39100,83392f75,8a78325a,44dfdf2e,5083d8cb,396d2b0f,1e4fd37c,47cf799a,f057ff96,da3779fa,f9c66fa8,cc59801,44ed2dda,561370f,4c3e1800,d0dabbdc), -S(681c2240,fffaf870,ff80b853,ee1aed59,c2c6d435,d0319354,7c4ef991,1e2e4a8a,16eb0138,56342438,57d3af9,12403c06,6cc48eca,92fb6614,b839e46f,8b939450), -S(8d013629,1912293d,c39537c8,3ebfe514,3e831e69,c844a076,c227926d,e5f9a774,b422e532,e989ac8f,1369c95a,63bde2c,20f02ead,254699d6,bf3d4a76,375c08bf), -S(bdd10d52,da3d9deb,e664ad2d,e020391,665f32bd,7b236e02,adb6ad1d,7dfccece,201ee4d9,76d70c3e,cc06784c,a33b84bf,ebdaedaa,1df478f6,70128198,f1b8f66c), -S(2d34aeca,2ee9102c,bad92b30,2802386d,6e7af432,8aaeaeb3,939e3435,98715d2d,2c372a9a,4a4f0daf,a32acf6f,a40acacf,be6c668c,1306b93e,b27fb43a,a82e0083), -S(717776bd,d8c65a1,62ebb2f1,cea29ecd,9a843d5b,92f91278,3cf4c819,b26158cc,bec109f1,29997d51,e032f8f1,f453e222,4e2466ca,ae89fbd0,37a119ee,45588f), -S(a03bfc10,6f13c570,be92a85c,f72cde29,caa157cb,8b434ed5,c958f2dd,3c69ae09,8d76f55a,959eea82,c18d7328,2d5fa91d,d747fa13,67e64b0d,3d0b0a94,e58ee0e4), -S(b3516031,30e3198e,4a158cb0,108c8187,88c59939,bc813423,3bc51ca0,314832d4,3a5a4dcd,9fe0c5dc,bc17a082,396a93f8,36182c7e,2e26670f,d64ac6e5,8f022c27), -S(a927baa6,f7cf01fe,1993e1ad,c435edd,c806af66,6c9d2168,44a86bb2,2d7a8951,489734bb,4fe191bf,4535c812,a0e2d3f0,fd8020f2,ddeabbfe,c740fafa,7ccfb468), -S(54df921b,5848a4da,22c4dc63,c46876d9,53368446,e6106389,55ff00ee,61d75a13,25de0b92,52968196,18d606f5,d2c54e7b,fa6c1980,bdacd4a7,54a9b2b0,4015d8fa), -S(5822acdf,704948e3,c9112d0e,e718bcda,98eef3e,bb927d14,a1fe1952,1d64361a,c8bcb245,d5aa9e2e,7d527508,38db01b4,e2487197,a3ba351a,f2fb4b3c,19d03895), -S(a58c52f1,ca6983bb,cf2e8bfe,592b8d9c,b2a78dbc,e1f77931,14c95253,6a2d65c9,43626050,9c114db4,eae66452,599b145b,4d16b14c,cf7ce807,9a9c531b,7f3cc46b), -S(2db642ec,2bd88fed,7e624eca,e8022f7e,453cbfe1,1a6b00ff,726be4d6,89a72418,e3e73ef3,403e341e,e032ee00,e99b1f26,e710571d,81ac93f2,5855a8f7,32265440), -S(45b76e7f,65d895ec,24756195,187a4612,7dc9b31c,5e3e5376,e3af20de,b7e69a8,b2997f75,7cafe61e,f8a67043,a624e55,c10dc237,2f4b9d60,9692b269,7c616fac), -S(accc62eb,bee83904,c01a32db,e4af9b0b,50f3064c,bafee18e,eb49bcba,d53a41d3,34054eed,c77ef0d5,e865ea30,f505ba8a,ffc94474,5722651d,294a2520,fb7f4f0a), -S(1de2f5de,b1658f6b,6d20878b,9adb8a4f,6535965d,63bee989,fe23e4ed,a77f07e6,96762a16,fcb2aae6,ddce8f55,39c57f57,fbb45d09,26738e6f,82085d3c,ff0f20de), -S(5c51b67b,d4c0df54,ce75b09a,c399c293,4fd7a991,607a0aa4,a0f6629c,645f57a5,d1082c6f,66cd1aba,86df3edc,39b2e579,6e6975c8,ca018310,385173e8,5878914c), -S(8d7421b3,af8ad663,e7155f89,25bc9246,af7b3bd9,3c6a1097,afadf84f,7b041434,bdfa5121,e17dff19,6c105c34,b9d0bb18,8514a9ba,7dfee6c4,45c7855d,556409f5), -S(5608f4f9,f6d1a0de,64f22794,7fbdaefb,24b797e9,1f6db6ce,f3986d65,f0d4836c,1e03f309,f4c0f432,eae951f8,6e876f24,35364778,2249c36f,cd7115b7,8248a1d1), -S(24fced9f,ec868343,e6d6482a,1017853f,6687da3f,cc8e19d5,240a0991,6fa61791,8884a7a5,c742149f,88af0fdb,7cd59bfb,d318d8d7,60015afa,6bf0474d,eca7c214), -S(d9f8bde9,8bb83348,33783e9c,5d8ce8a7,85b9e335,6921bebf,281c97d7,bd000fe8,59d46892,a3d604fc,a378aad4,9645c747,2ecfae56,8b362e15,c0acb755,af7103c), -S(617f21e3,af5d65a3,a504fe95,34ce6bcf,71384bda,272ca49a,1c36ea32,d367c4d6,daf8e0b0,4bed8f7c,2d8ae9b6,afed54c0,904c6010,9d0c07ad,5f57178d,2cc037b3), -S(e1bbf189,83052820,ae65ac4f,e5a6d4ee,5b57c3b4,c0b2cc06,9f84b25,adccfdfb,3cd52ced,d7f04a93,86f4845c,49af86e2,c3a86984,fc4c77f1,3200017,ea68deb6), -S(83f82dc,7c709587,b883f1c9,e6cece13,2cd510bf,3664aa79,220892e5,dc2dc8c0,24c2a1f4,7c4b96f2,86265605,d9348dcf,8261737,56c5d91e,2d1beb4a,a857525c), -S(5ccbc6ff,c4362b4e,3d3a72a0,76ecdde1,1c1b07f2,680ac16d,63cca8ed,df924085,d54095ae,f357dbd9,5c12ad03,78f428c4,beaf44eb,23724fb6,cd0726cd,e1f04fb7), -S(c83a798d,c8b1ff5e,41ce6563,f35e741c,a6020a80,319b5543,1f81726,818307b6,c9cbf8a4,747baee8,2e156cf0,4b0d7762,2638e8da,7731f4ff,60bb9ad5,62b7588f), -S(c15d6466,c7f0bfb9,ab8a0013,300dc6a0,aad45c60,c2fcfbf6,7c9ca24d,7d2a21dd,cd5682ea,b41b707d,9b787315,8b4e347a,7ae682a3,cb950e1d,abad3b0,c8c42bbf), -S(e9606086,63b9bbe4,35826c1f,3830dfb9,f8479216,5c57f28b,9fd28d5,7a277a0,37fb1f6a,6d3cee79,ee2eca6d,c499fcb9,e2896942,f17fe885,25d2d57b,11c8a198), -S(f8a3fb79,afc8a94d,d69998a0,f4889dec,200b4b72,d2900c75,59371ee4,412df0d5,d5e0f5db,b4281cb2,ce21fb09,9176362,90351fdd,5961db25,ab677dcf,d4fbc0cc), -S(17f3cc7c,64540e31,ac6db6b4,ae67d100,46b7665,450cc011,dbb558a8,56a59b2e,9d815416,553ba751,79955382,12e988d0,eb0e0493,f880c217,5b90f423,5763b624), -S(6656be68,bf528239,51d7a392,ef22b258,42fb0646,8908fa1e,fd91d89e,a54f6150,741d5373,7da163c5,3e160d5c,b3f9f118,273c59af,75aec2da,bf788e8e,e870cb69), -S(67ec8648,83ad9ca4,22fb181a,2235ee66,cdb74f0b,f8e5b808,c37ee314,35598cf0,8da1ae29,4f37153c,1ad165b4,474a8f91,e7bdae4b,54b227c6,57e2d3ab,f3bf3fb9), -S(c9e8a673,3680fd41,83005ad6,97c78a4f,abd5d048,1f9bcaa,7c8eb209,68240412,fbad52cc,a0e510d5,e5c813d8,13ba4559,716e0787,4f48c20a,f783a807,c1848eae), -S(dc11b6a8,9c6b324a,f2d67e4e,9f59f32f,8898dbdb,d612f157,e0f24cee,d2709dc9,8c20a8a3,c273c882,fc6a59cf,ce74f115,1d0421d4,bc84a11f,2def142c,f2a8b080), -S(c5ec365f,7c0aa7e1,94fb5a90,ccf8fe3b,3c90e413,f3b24947,d8246024,7a2cc2d1,c5b39d08,b23bb1a9,c5886e51,abd1fb2f,d55ff334,81f020d0,6796d978,8801de79), -S(fcc03866,bfbe3215,9cffee9e,bd6874bf,10a5055a,5e56826b,37322559,5381650c,99cd7d3e,66e65f1e,5eea297b,f957c699,b844cc35,cd19dcdb,2d3a5653,f45b59e4), -S(7c96526,7ade46e5,693ecf09,cb052ae8,2a4bbcac,d07f136d,86df45c5,bf20521,db8e1dd7,3c961137,23325d6b,fb728dc8,f0a85141,ad1a00f9,53100aa1,5519d444), -S(39d11c0b,2169d3fe,4b5001b5,a8da1fe3,a7b14ae4,e329b931,f7db92d,86acd02b,46fe1f3,65805c5c,3b731dcc,d46ad37,1c2fb6f3,b446e466,ab80aaa2,5200302e), -S(3acaa37c,4acb28b5,6af7f970,ce279372,d2b998e8,5ef20932,492ba5b1,7b79240d,6effcb72,4a7c7dd8,b8bea6ca,322a8540,f38cc5df,a06677c,181c45d8,c4e4a4f2), -S(fb631a1e,25daa546,47492d26,fafddec,6f38c08e,e67e67d,af1c57f3,ac3ac79d,90b04e04,c685e4bd,4817c367,22892881,fbec8c09,1e5aaaa9,7fd6a163,b68f2eac), -S(3edc2ef,2c609f0a,c77ec4c8,c035a537,3d4ec7e9,6addfd7e,87f040d2,df98aaea,7e549063,ba715cd6,35719b86,c0b6eb30,68a71420,7f480f93,6d78f0a8,d9251d20), -S(bd4f2218,7a9f5164,a864dce0,2bd1a89f,d283e62,64255b0b,21d2f6f2,62fc419b,d5eb78a9,d2337e68,3e3a77ae,b37b170e,69f1400a,2383b339,64dc6726,7c5db5e1), -S(434d9881,70badfd9,5ab26ab,90933eb8,89bc6a88,60e6f412,1e5dee2a,f82341e8,c6af879,cbd7d5dd,16c3b06c,810d0263,2853986c,ffb11fd3,aa2be2ad,db55c4e1), -S(9633c8b0,653d8010,e785ecb3,d710b43c,37ddd97b,20f26c4,f9f41581,cdbd991c,13b53adf,b4841e2a,2590609b,46b604aa,3bd6e758,4d443db1,6a7ada9f,9a49fb71), -S(ba656a98,c63d18f0,c4aff8da,3bf05cf3,e3781cbe,db5d9083,a8828fa0,c2fbabfb,90ad3738,f28fa937,cd4149d7,90f8b4a6,d4989c5,5218023f,37742c3f,1814896d), -S(cca5c935,ad4a690d,893b3bb9,cdaf2e6,102c44da,d9446615,2a39206d,777ca72,3c060ba8,b14da1ad,41991c64,95e14465,9361c724,d895a0d3,a3694d45,56c7a146), -S(b22a22de,c827e8a6,dc630b1f,11229bf7,ce8a5030,608392e9,b03093cf,47afb358,b10c49a1,4b30449c,200bca1c,4a0f3df6,7d978988,1be46597,c1e5334d,5b5a2e4e), -S(b4253d47,beae6a36,1dc45090,c358275f,fb8e0696,11e51b3a,1aa7c2f5,273ef8f8,c0f4bbbd,e98d0960,f9a59809,83d8c4d1,35eff1c9,2ddc9f2a,6ee05146,eadec66b), -S(60d75d74,1a85d65,b9edd2de,8a03f6a5,5ac6d000,d39ca913,9fdbcc47,fc3da6e0,fb138bcc,da55de59,d496b784,9532d99f,44935e6c,b08be8dc,beefbb7d,74e1fe7f), -S(ec63d10,e66db9a3,7cb5b88d,811f2f6e,aecf51a9,e39374ae,92df325a,aa560a85,1066615c,d2fe8397,d2dd458a,f6ff36fb,60547398,29e6d6bc,74525c29,8c3d3c53), -S(8df7f52c,8324b50c,fac3e27f,6f230e9e,e4926895,c8f2785f,560ba5ca,98b9feb9,6832846c,a78a18ad,3747b1fb,d8cb6a94,fb3b4977,3db3c0b0,c873507e,f1519480), -S(f17e21f8,e97bce5c,2e63285a,f9e361c9,4a2e6b45,f437c1c1,a1310988,b63ea49f,12690d42,bb90b05,2fa4b1d7,d517f7bd,f6721a82,e0a9059d,caa5ed15,a7acf7b0), -S(4b0e0297,729ceb7c,4c6a4caa,73d76ee5,9d8f8547,9f582fa8,ec678339,58c023af,73f6affd,3afe58da,5ba3e0c0,9a043e8d,100f1275,dd9b9dfd,42ef4f47,a1aae067), -S(203174f8,fe8427ab,42bb517e,67e9c13a,3a39700a,158c3581,a0c5bf76,79f950a6,ac630f01,6b268772,72e422cf,b74a3a1e,dd1f581d,bcf2a1a0,54946a15,108c70bb), -S(ac34d445,cfa711d3,fa7a8c5c,bff5206d,d6dbd22e,737c5b21,6e6801ca,362c4b35,91a0a6aa,fbeeda5c,abeefb76,f1bd4b23,e850e1a3,9886344b,282dd0a7,f0b6985c), -S(81ffda88,a45f8b82,e3e249a7,457fd1bb,34ebd35,58619855,6ff7ecce,73dc7998,eeeb1a42,125877fb,640b160e,4930ba7,3f1e22cb,51e33946,3935787b,5d6e353b), -S(1a281d34,5b4f227f,2a6d4139,db2e29a5,7493b1e7,f099edca,ef68b3d7,dde37dc6,63baaccb,8a5c1de9,f1aa33bd,2fc19189,619a71e3,f9b290c,83fe7643,bcbfcd25), -S(ed9042d9,ad110ff0,6be64aa4,cae0422e,c9a8aa79,4dddc1fc,52df6098,8de1ffe3,9ede1c43,5d6b8a7f,61591d37,e166485,3071c894,f18f85d3,d8f145ce,98208b95), -S(1f5b14e6,1453557e,f3ccc7a0,1e2864ef,43dac2c1,ce737ba3,ffefdf2a,3de9622a,c0d40622,5a4f8b24,59ae2d22,69908c81,5f901125,1e46a683,3df83659,f2a474e4), -S(218e8943,96fa8e79,2f29b53a,de2f9155,94d95a50,1eb1a1a7,c8b01b32,75e8c117,2701de34,af2aa192,79dfc9fb,391532e7,56824da0,38c60624,3771dfe5,aeabbb96), -S(d6ec122d,463c0f2d,a994bc46,a968693b,f282ad19,6a6471f7,6516b5d9,2fea7303,57f84e4e,9d439701,19f58c6d,426265c1,25734ed7,c10db0e8,e5b87ebd,d584981e), -S(3ffb48a5,58fd6f85,b1609710,1be54107,6182a7f5,a5692074,48d82dd3,e8027e40,aa410f17,7c08cf25,a7a9e9eb,33f2b83f,c83989fe,7a737e23,e0aec6a,6eae2ca5), -S(c8c69bfa,450cbd11,6dd51750,a5fb2f0b,59b4f489,cf05c670,91a49f13,3963a50b,879d8a2f,a1c26933,5719a389,d504ebb5,498318c7,acf103ee,348d27e,cf83886e), -S(86097033,ad0a0d7a,982e748c,bce06089,2c6b55a0,17bbcdc9,d26166cd,b0fc1e81,9fcdd6e5,17916ee5,ffa48a50,a0df8ff,98a06,82059d92,43a2194f,fc89dec6), -S(37cd256b,7502a789,10296144,bd41ade8,f4a158e7,68b6ed2,723d3e57,cc5bd099,5eef9bfa,6e5e1bab,8d8170c6,2ad90725,afc38eb0,db145f59,35520a7b,7518dff6), -S(70aede0e,f89ea93b,702fd3b9,4f81a48e,aa36cfbf,f4775426,37b0d00a,80abede8,b30aab37,206b8c1c,2f852ed8,348cd387,d676f6e1,2baf457b,97fc49d6,91490f33), -S(2504fac6,acad5f23,81cdfa76,65fd1859,85e3b32d,d1767394,85d63f07,500c963e,7a455f78,9cfdc25f,d6ef9c01,8e44e6cd,2702ee9b,fbbad8a6,7ee228f3,fbc56d61), -S(b8bab480,d143bcd1,838f7f2,d13b7a54,8f7302a6,14c03cf1,3e4fa971,5478c280,8d1939f3,abd45a47,686be62b,7c079fe1,2cd2a3d6,78478afb,d21327e1,3599611b), -S(19370ea2,2e6937c8,b7d600e8,cfee9b54,e1b527d0,85d3a17b,ea2daf7f,2e6a410,c721f3ea,af20344f,98692ae1,b88c7ce1,8655a4a5,9c2c945b,aeab2756,a5ea546), -S(5e19f6c5,10bb512a,798fe39b,cb37ea2c,da70c76e,d7d1c828,9b488e9b,84ea224,ab34bc16,50a99345,772aabb7,f47f0b2,f92fdfdc,4ce7c9b4,f5bc14f,5b946b39), -S(e97888a,cd62f21e,76f5247e,fe64291c,e69b8b1c,b331a2c8,292bca63,f3dde54e,286dded8,ec435a9,2155fc1f,18688e5,e69ae21d,eff79a6d,c534e18c,3e7b114a), -S(4361dc3f,9c039f2f,750e4172,88ba8d7,36158f28,d5e0869d,44207ef,f587a8d,b05b54bd,2097d8dc,c7ded5ea,ac07e6ac,a7974500,8337891f,4b5d6c71,672cf759), -S(8e679eec,8bf365e,e5324330,3437dccb,768a3955,3c3135fd,3c168109,5ecacce4,b6dd115c,d19ecde8,4e7a2fae,be358448,3d6277d1,19ca2aa8,3bb68ae7,f5e94f49), -S(e2d80539,947ebd32,8716ce6c,74e5f09d,eabcf539,2e84dfd1,2e33219f,de8b77ec,d4515668,586e8753,74406b32,65c9727f,92e71263,b0f77447,14de6f0e,732fd175), -S(a2527f0,c754ac94,29bb5dc6,18efc820,d88c8490,df39cf13,a25b0136,37196f9d,bd16d989,90676eb4,36e735df,94a5a5d2,28aa4185,24766ae3,2c7bb12a,e9aa0508), -S(bfa67870,6db9cf88,139ce56c,4f5165c8,38a5830,d1673a9e,b4b0a218,a3a66319,f6eb6944,dd30d6af,a360a7cd,b360f58a,c17dbe8a,7eaeda38,f3b1eb2d,83c02e0c), -S(1d5bf7c9,9255f96d,b91a0f5d,82a3119d,f3d491b6,859f55c5,59389e90,a2f533e0,132b1468,f460932d,7e0ec514,8ba77405,8b8cd4d,3e47acac,e52ec9fa,618139db), -S(44f90837,9b8aba17,44415980,aec15cfb,4edbbe4a,23ce6885,9e4ba880,8a67025e,9c4f9d97,6f1581ac,29818a6c,58c70ad9,ebb08f3e,83dc1b3f,667528bc,3a1968c8), -S(f100be57,1d4ddee5,291e7123,cab57bd5,c5ecb8ca,6c8a90c4,d2f01f73,87b175f,8899a16e,3a7ad5ff,f0e3aba5,fea86e1,974dac4,d736be38,6c2ad93,8020a6dc), -S(e26927c2,f3cce898,33a60369,2513aec4,ad0d8f63,2bdceafa,e5f6900c,716be2bc,c1154830,52dc4674,238758c7,d7af495a,f32a4d01,e0c316ad,301606b8,d3136383), -S(e3a3fcc9,8fcf1ce8,fb994b68,f92b2fc3,c114f2cf,321e89a,c3ba7886,43b0f2f5,214f38cb,7020f57,ca4bd953,16960c9a,250feb38,7519bfa4,abe025aa,dddd072e), -S(59ec03fc,5195e0d4,a8df03b6,a96938bb,d5fa5a40,161f5ce,2480e205,dfc0dc3e,71421a9c,b58aa65e,180c97e7,6a90454e,d5d8a2f7,739eeb09,be7fdd80,47a4ecb8), -S(a53cb7d9,3dadccdf,18d4d01c,6217f39a,be621089,821aa92,362db85e,71cfa358,1f989a47,77a2837b,f797c249,4539069c,a24a23aa,8f1e5b35,fc401dec,69d049c0), -S(170b9efa,13e1c948,a5ea39ac,e688408c,1cb2a57a,a55aee52,e4fb21ff,2f7329cd,f092c60d,c4f8492f,d718aa74,fded9cea,426b4,7277d724,710ac0d,53ba7039), -S(e1d16c75,893035c0,63eb41c8,36bb8bcb,770f752b,718a02ad,24e688da,79ac3a14,2d58df,7b7bf0f1,60a091f1,b0b209bd,ce5516d4,53f8b799,5707721c,66ed2681), -S(d45a1024,78595ac1,abd9a582,a3afdd8c,5d33c7d4,caedef2c,747450a0,fd2d675c,8faa7ee4,3923474,12012dc8,cca109b3,dd19efc,52ae73b7,508b23e7,1826732), -S(d3f355bb,b2ecfa66,592ef13e,fe983e22,b2b90538,ee2f0aab,ee1fe982,62c336cd,ee99b839,7d4b97cf,a7851de9,366d24d3,70169091,81b5a10a,50fd53ef,bf549812), -S(6ea90fb4,e58f1eb6,f27dfba2,acd645b1,1c7cdb0c,dabf2d49,4fdbb4f0,8ced2c56,74934a84,871dc011,3e18d5a0,aa3207a5,e588a3cb,e8a3f350,4a06bb73,8ef93abd), -S(de4eff0a,ccb612a9,a79d0983,94e8a883,da348aad,74bbbea7,d477e45,c2b87436,9b30581f,b903cfe7,610429f9,f6ec1ba0,df63038d,db8117ae,ec67d7e4,1a28b9b), -S(4ba09b19,f129b3f8,db86d780,4630c6fd,9c22d620,677c66db,ce60b69c,c3bb4772,fb31e85,ce50ea1c,13af1c7e,93d9026c,e5f39474,9e91d049,1b459970,c169aa77), -S(7fb3c3ee,7c600ca7,6a2bc674,a497bfd6,67b0124c,f532d5e8,55aa2c90,c4b4826b,29b970bc,b8f5eaa1,616f3695,5a1b17c6,60b15b1,219388a6,b47a55fe,6cad1eb0), -S(ac29cbb5,dd2a95ea,5a3b6f57,8c2111a7,6bf2b060,267b467d,5ee8ed2e,554153dc,89d4c22e,acee2b3e,7e7872d6,5d1daa52,54a1a00a,f6b0f7ee,16d84477,45d01c81), -S(fe956021,e67458aa,c6fe2cea,730f272b,19fe7de9,18c98a40,ba475dca,af3142ad,52c6b42d,6fc03eaa,3ec7da94,5ed12ea3,84e16d0,590840df,6b714a59,d4bb814b), -S(336491e1,dc3fd4,8d63944b,2578a415,5727daa9,6e853935,a77b7077,d61984da,e9b8db61,51fe90fc,9bfc0635,5b9676f2,cecd1321,292d2a8,c6e30e9e,6b1478c6), -S(245c6818,aab65e40,806f8cb7,721b7dd8,b0e3854b,7daeff8b,da5827b6,4d294df1,4fc22df2,e7b93b96,b60f2ce1,a659c1ab,1a06c7be,18e5c80c,91e4dd2d,75bd8ec), -S(8c89eac1,d9ca6c06,8229986d,6d22bc3c,817dbb6c,575ff654,36653101,1a60de8d,ebcd4867,323bcc7,f8dba216,4d827a48,8b4763cd,aef0daf2,5a1c1437,d6379ce5), -S(afdaa93d,7ea7f666,e737a379,914d1b87,6899cd9d,5202e985,e365d75b,806453aa,e3e9116e,8abf33b7,ad036291,2a3dd016,2aadd1ac,902a9448,30248a60,6760cdac), -S(d447b974,fcecfa15,1fcf7ed9,8762283,7ae28f74,be8a2a2e,22c3bbf1,d9b23071,a3e79560,f79524a2,e206e9b4,1cf961c6,8f6f898d,43694114,a3f89495,6ecf970d), -S(53525693,be8fe724,c970f4c4,2b46141b,321e79a,4ffa411a,5d947bee,ac235674,5cc74ddd,7a74afe,2026885,1fe180c8,dac3246f,8c4ba44,2032d584,8afa9f4c), -S(40e60cea,6008aaf9,fee64781,b5adeb9b,f23d2db5,94f9fad,b7394481,da971273,fa32f2db,263c1f7c,987671f5,68c714dc,9d3ecca1,2b20655,2b23e5cf,8a365b65), -S(de59a6fe,1fff672a,c4655e87,f6440e4c,bfec2fc9,135f1049,efe173fd,d666acaf,205e5ac0,8cb9c3f9,9023b6d6,795488e0,61ea691,439a22f6,48bf0da7,cccccde3), -S(89f718d0,23f80ba,df0625ea,260f6ca6,dcf8fcf6,e79d35ec,67e535b5,e9cd06a8,6acf9bad,6dcc053c,f7e193d1,a4c432f5,32211761,aeffbb4d,1d53d737,6b3353a3), -S(fcd5af97,603e0558,76f24ab2,eb82de83,3c8cae9a,f19ed307,f7da1da3,f1fdac3c,3b7ea3fe,bda44592,abe9240b,8b06cea4,3a8a0ab8,aa862c85,36a17b18,fc911ab2), -S(208419aa,670256d7,94712f59,bedfe025,ad9ab43b,2037783,4e4c8f4e,9473d6af,b6171d6a,20da4ffe,f46a49ae,7233206f,d9ce1ebf,89ba01ed,9b86896e,43c9fac7), -S(d7ca0446,88d411ca,c3f3acf8,1bc3f3e0,a9feb9ef,94bf31d7,8a15563,cdfaece,3a361b1b,2ab89d27,6e120d38,7c31f97f,c4d5880c,6ace1813,b4eb95fc,37db069e), -S(30b96bd4,b284e36a,f790695a,e2c8aac7,672a0496,2f9c92f9,694780d3,92b60bc0,6e2c7f8e,d1e0d081,a34ea062,591e1854,6f79a9c,60daf218,6513e4e2,621d4852), -S(5ca0493c,3d516b44,46723477,fe8359d5,6a2e01b7,28afdca1,343de88e,92411590,60bd34f8,7d4bc12d,4179da44,3595b48c,17f34f19,b03750a4,6904a242,93af0e93), -S(de3486eb,22faa1c9,ccf774f0,e17da3ef,3ab5f7a5,ed6ba58e,bfaa2c1f,cb5c0e58,af8666d7,57c13f3d,3c2e6b02,1dad5ee1,ee4f4c82,97960b5e,84135309,4188936d), -S(8075138d,59a9cee9,5320cf41,cfad010d,90efff9b,ad50f2d,dd3ac7d9,234b4576,ea48ad8a,6a8ab6d3,5cea84ea,365b6a33,d3d593ca,9d27c5be,2df2907f,8bc5d91c), -S(5328a0d7,17f0c7d7,9b8838a,abcb0875,77eba66,eeac756a,6a365657,d4d710ab,7f33d5ca,84206a66,a9aba1,2dad6805,9aede27e,2b38d755,53756d14,9b4b5a1), -S(9fecd234,d25771f0,aee9dfa3,2286697b,faf4d34f,83eb7135,a581b225,791ce0e5,3e364215,d2eec5a3,632f01f9,9699255b,e90303c8,eeb0e8b7,56cc239,20b2dae0), -S(7084b279,e89d0f23,967a1635,96a1090c,4264504b,c2895b07,fae5f128,93150c02,481d6078,35628b54,783484e4,d4f299cc,fa3e6f5,bad67457,1037797f,b3fb7f96), -S(bbd3583e,8b7ce417,88cc23e4,eb0c331d,c8970d1b,7b186ee8,9b4cf45,c83686e5,f94d7cd4,392a9589,77ab3956,a91024fb,b77a608e,91147a6b,4be6cafa,69b9193c)}, -{S(a707efc4,89165c75,7edcea3c,ce729b44,91f04142,3fc6ea9a,704f52df,c8a0650,f2e7657c,6c618494,c01c5a90,d06b625b,c9416d63,f7b8f809,dda5076f,74fa2c92), -S(8282d8a0,cb008916,33654a11,fbfe16e,8d2dae0f,ca06175a,5183ebd,de06ec8f,44128945,d39e1b71,cbc914a6,21c95329,b6ac0b45,1f1921f9,725ff10a,2859af90), -S(100ee34d,993a06d0,cdcfeab6,3eadde22,7be8aa84,a9458fee,61448911,1bffe20c,c891d347,c63acb,c72a2a8f,c0d8d41c,2c32a9eb,5742ab35,e76b573b,3817b9ae), -S(9bed0413,465a899f,37770b6d,6e847223,28049001,73efb872,aacf122d,4eb12f1f,745eb015,938e3ce6,d38068f8,90ad253a,b0b1bde2,de636162,c0442b66,6e9e1e61), -S(2896ee21,34276bc0,131a10aa,5b0c9b39,ab5aca5a,3ceed61,cf2d27a7,5404d264,cc51d26e,ad555071,e57bf3e2,dafd77db,4f58b6ee,b844ea86,5da39b09,ef3ecc6f), -S(b95886c6,e569d641,b8e32555,bbaa562e,1f07589c,5a8f3810,d4bfeb4f,e58711f1,3fe1536d,551770a4,cd816eb6,46f2b864,77d565ff,3091d916,af8597e2,d8988b6c), -S(b32e3e0a,3ca6518b,6bdb2a9a,e3471248,5387cc5c,ffa32cca,976be3d7,ebdbf1a1,45d998f2,828248fb,2f97b503,8de02b38,493f5b62,ab8b0d7e,75cb96f3,305680f4), -S(8a760935,8c3682b2,fe8f5b8e,a9c76c61,f66ae677,48294bed,9d3c64d,702d3c47,77110a33,eb7562e7,95032a0f,5027d162,28131575,323c8f9,8aa0bcd0,9328992e), -S(ef709552,f80148fa,dc1f7007,174bfd85,81b03db8,189ca3da,96b3e749,b1843ed2,b8e9393e,c3cba6ac,2cdd2d04,6235f7cf,14965616,3722225b,9010727d,94b610eb), -S(5071af8d,2e37c4d8,11225f8c,543863f2,3d5ddfff,be2576ca,42630f38,1b967483,37248038,487113f2,74ad07fa,7dee36bd,295971d7,3a30cc58,629dfc68,cf65533e), -S(88c9a5f0,e76871dd,3afc4ef4,5643419,95642dd5,c8b1e386,b71c2471,c591a3a4,a77afc95,71af8ce7,60148b15,1e1fcdbe,c48d3b2e,580b9786,9d80196,2ce6549b), -S(fe643b36,a0ef4165,e591345b,5963d37,632c8fb8,97114b60,c4ba6f6d,c07f9033,e3c7bc7b,865c1d,4c496f36,9a79e6f7,1f79f6,e6929f26,63615855,e9509ef4), -S(d35bb10a,a23d2bc4,d2aecca7,51f1cb24,2133fc16,9f008ce3,4a29b93c,7ad21f3c,57265f67,dec367a,7addd6c3,fb23fde,f04f42f9,a291e291,3f2128cf,df041f07), -S(e3c8d76d,1ff5e0c0,21668bb8,f425487f,b7bd3a3c,eb3df289,5e4806b4,177fedcc,abbca449,95abb588,3e0a6959,6c8108c4,ddf8a50f,6c43e507,59f85556,be49efc4), -S(b7e31e11,cebd568f,658eadf7,ac57f265,fc94073c,9a779f21,5016e5fd,705f2580,da4dc770,742cc6e7,38d05ecc,6deca283,9c06125f,bb911cb6,16f0fedc,84dc2815), -S(bc486422,ae3e277a,d24fe096,120decbc,4a735e57,8bdd72a4,b3f9006a,859276d5,ac246a6e,a145a990,51c62762,dcc47fc9,ea9bf93e,7bccffd6,c82228e0,49686165), -S(79d0a8d,61039dbd,1787b140,9d8109f,3832112a,8e1ae97a,346ba122,c9f66eaf,9bccd3e9,b9b2c673,c465fed7,b774bfd1,833621e6,87727a5f,a8959528,9ee034), -S(c58bdd36,646e3dd2,ae3ab0d8,8c9b352d,c319d1de,c132493d,11f2942d,1f7592b7,ab923ba0,2cbb4bf4,35212358,66b0a420,41677486,3d67cac7,ec5e891e,b2415f6c), -S(3865f065,42ea6eb2,a0741658,5afce76f,d87646bc,a086ea6f,5838e9c6,55171a85,8c7b87af,c049de66,8578c89b,e5a49c85,64ab35b7,afa39588,6312d680,837415b4), -S(10c1b93d,f7ef0d97,4583889,d07b7680,b6ec858d,b45f9a2b,c36a2f68,9d77a4d8,3ac497e9,15b7470a,f9bd9c43,1ef3741e,b61cf7cf,a2e7fd3f,e1886fa9,4211ae45), -S(1ecd15e7,3905fd66,a86a96fb,16118d4c,a6da82d7,672f2361,fd101a3c,7203c90e,4974d5e5,9b8ce7fe,30671eb1,7bcd4d04,97c57b78,a4202261,28eea45e,b3b8131b), -S(808fa8cb,40e6440f,ab60ef45,65caadc8,f86618cd,e1c0d900,587dea31,f49a589,511ccd1f,ee3a53f1,bd12f1d1,13098694,34579292,74d13973,b0aa29e6,91d889c3), -S(e1035b36,290782dc,9e578522,ba51aea0,6621e7fe,8d5cc9ba,af0d131,ee00a6cb,ff12d04f,1d5c1bfd,859178e4,368a3a0a,f73e125d,35049e60,342186c6,ded5a753), -S(daba0ff7,a9f3cf3a,2f05cae5,b2c6a881,ff9ad5ad,9dc1f853,ebac7384,5a48e230,d4ae471e,2ebfbe0e,dde343a7,83d9fbfb,87c3d179,c72da83b,8524479e,19bc23d8), -S(106e3bdb,beade62,e8ec777,bc4044ef,c6a04d9a,5a3b5396,44ff98a4,33c94b92,1d461e65,eb1bc8f4,d3aa5773,a5cfef37,2e55dc46,45f8be3d,f53adfee,6e7e7d75), -S(82424b42,7b95dd6f,5c9bec59,b1ab98b0,c7fdb4dc,fcd1f8d8,574f4b89,6c8d359f,aedc4fba,825c48c7,4c466738,1cddd6d2,75748661,89499c96,297829c6,27945de6), -S(71213056,13ba1e9b,8b8e6727,74b718bb,2cea1e65,ac944db1,9050f9be,e6c90c84,98c54a0b,8f0a6d3,d7e821b5,907ac930,b79e683a,3ec49a39,f5043d28,acae4144), -S(6dc2c201,78620ac5,d99cb81,8474e5e,de8ec3ac,2366bb8a,19685ece,bde25a8f,2f1dc21b,abc65601,fc706aec,50b9aecd,954bf039,e3b066a0,54fca082,287b026d), -S(e7239283,2f6a23ce,252e2493,5726a774,497319c0,9f0fd327,59fb594c,6d9c8257,165dfcdf,2b117b5b,73bc5096,26b47ea7,c8d5b8f0,24beb2db,bc0f993c,d30418c), -S(5d44ef96,eb90df1f,488375e2,a3e75459,34169a9f,5bdc7477,bb7d1bc5,1b3f4ef3,87da9f1e,3346fbfc,6372637f,da5c1e13,eb561d61,ecc68e03,8167eb82,d2d05bda), -S(bbd86c11,dce2eb2e,d7424033,aff54543,2f2aed92,5b433436,f93ad8fb,57816732,f415eb1b,e921aa07,6b7b52bc,773c7e9c,f89ef076,95aa86df,92f4b72,38507c8c), -S(633050b7,3000259c,42bb380d,815b2219,14e78d79,e2a7d979,29ca8ad9,cdc40fdb,efe2db3b,16d1c829,ba0add4a,c07e7ad5,f021ba2c,9e53ff12,c93a9c36,4021779a), -S(70c4392e,d4a1652b,ff89db4d,6b1eaee8,870e1957,f98f0271,d7fb430a,85c76bcf,4d0917aa,96368ba,45a567f7,c05505d6,a349faf4,b51c06a5,848bb8d2,1fd80f0a), -S(7abb4651,6baa8c3c,47fe60f3,6ac3f91e,92d6e09c,cb8401a,a2a3095e,107df5c1,d8445036,8eb5e86c,37ba9b12,f812ba0f,f88d166f,fd1ebd98,67632a24,8eb9f388), -S(65c27141,24444b72,188eb222,650e99cd,13ae852f,e515d452,eb757225,17f63fd5,5bda906b,e1dacf0d,e65e66c3,23ad6dab,15582561,ec4faf17,35de87e4,a53ae7c5), -S(416ebda3,baf7eba2,877f312c,f86c6517,9f422d8b,8379fe9f,29b5115d,f1ec3364,ac46579d,ee0a19,bc5d3749,142f42db,6e934f90,eae78e80,d96df9e8,f932907e), -S(3d94add2,7a320b3b,da7f03ed,ae29d1d9,cf022b47,b7a0ea03,6081117e,60cbebf3,8fc54299,9bd420e,96f464c,8c3a56bb,2f1719e1,20eedd6b,37084251,f406206e), -S(4f0a9e32,76447fe9,2fb48cfc,c962a0b7,b7c391fe,16c41c8b,21a6e563,53d7c218,441e9d39,db107e8d,d8f0a99e,cf791c,2fbb37e3,2ce1d821,9011a8c1,60345bba), -S(17165596,c15ddb64,83b4d45e,8be57fe1,2a37da06,a47ad7d3,a190e88a,9d58e0f8,ed06f5d3,167dc12a,992dee28,ef331ee,443f6c9b,7e485386,7a2f4daf,c0aaf64a), -S(62f6ad56,5d8c3ede,f50452cb,4af3866a,9b40b729,ff1b66bb,c566ce9b,b07b37dd,b790cec2,a2fe6264,5913b5f8,4e2f2ab3,bb45537e,e7783908,1d8928a7,484ff315), -S(c3b43bbc,522390ec,353a2a4e,47e04008,475731d,1fb4c67e,f91eaa49,8553d857,82e45f4c,81adc79d,5a7af4ab,36cd2628,416f1229,994d6e69,d260734e,55d02eba), -S(3a943612,ee8e0359,4559290a,7d55a549,f8173b03,b04cf28e,8abcedec,38c5a81b,d63e8faf,90666215,5f74a6f7,6509be2b,c5aa2b83,b75b18b6,1c1da05d,f6c55ad3), -S(5f2291b3,1aee7ded,21c3f1a6,77e53e7b,e101be5d,a4fc29f2,680cdda2,fcd94be,fc0b1162,7dac2084,c5ad479c,671564f2,b2b13e60,f101af4b,5e7959a6,70b1fa0f), -S(4ca0b91f,9c0cafd5,b9f577b9,f1b84515,70b0521,6a4f0c9d,77c6c106,99c1036f,b254845d,cfd558f5,11d5125c,68f1d65e,7e3bb173,bdde887f,d9b48718,b45d9521), -S(6ef57d2f,6f1eaa88,afba085a,d5882c4,4d823f74,f65d16f5,4bad3bc6,940d9985,52f44465,be358f70,3d0fc3cc,3c3373e5,56be7d9b,6b0486b7,6daa8519,f2ab521), -S(dcac3acc,a1fe2f5d,e231a6ad,74da4a52,7ebbd474,d3742cc7,8f0ef74,172017fc,e0b7be39,4d422b45,be66848d,b8fb6d9d,25ece5f9,28d2b97f,db0a491e,145d0340), -S(da9601c,352fae24,9d92bcf0,6403a08f,5b85ba77,a26dd30e,851027d2,f2def143,2bbf855f,996b6358,30481f7e,794c993c,e8e5afa4,6482602c,f12ee666,ca5d24f), -S(c1f8edb3,fdda602d,ad4a53d6,5e1be6ed,cfbbed8f,12e593f3,470d0485,e4c4a3b9,51003ac7,1cda53be,7be5c073,e530da8a,551d69ac,ee40faba,90cf5c20,824f28e2), -S(71ee3721,ce03cc75,27c837cd,88018278,f2a6f05e,a70b2b4f,323f9fd8,1f8a8bd6,8a9e0467,a7ccac5a,f5adda8d,7380c84b,80575e31,90335247,41abdb94,c1fec726), -S(eb5604af,d835b055,ed67f5b1,fbc145c7,d04f8ad5,f056f13d,2166e6a1,c2eb8c98,85ff6263,314129bc,1902d56c,f76395ca,9d70ff24,2bcb8a0a,b612d46a,b6b2ef3), -S(7cd7eb9f,5edc9246,e33d0734,e2c63c09,f23fce37,cd6c084d,c5d370f1,42f58f21,50485ab7,7ee6dcc6,4d1291fe,b08fd861,f954f35b,1f64a4a6,ad4e30ba,5aeff269), -S(25674f3d,532dfc3c,10d33f39,215b9656,4ee87199,c86fb142,89ed917c,a557be9d,74d20685,274f832d,8406633c,29611fd5,f288fbff,15f6c9ef,e21b911,f26664f9), -S(106de86b,33c9c46c,f0846a80,89a6f140,1e614599,91191ea3,58b877f3,9c7c4e1d,7ab4fadf,4b78c6ca,3a11c0a1,4b47738c,2ea53040,73b3f4f6,7cdb7b9b,74ecf74f), -S(b901102c,4a27cb1d,bc8697d5,156c4efb,8f4a1eb6,7d1af30,28fe2094,5809a195,2fde128,5755900e,3d87ffac,c3fd368e,f84b284b,e30e6122,c518ec69,96b2b56a), -S(9b4d7f5d,5cc3b009,45bab53f,400e942e,6ee7a1f0,915db960,e3a319bb,2d573da3,81507aea,a3fbb6ea,75f42bd5,bc044ba6,60e89279,a0103ecf,2d99a03e,5fc447db), -S(806cb351,48bc2e18,c2261d6,22bd1113,ac9037e9,90318085,b9c46082,a19f9b83,187da40f,a8d49de8,5a6d2f66,831b8b33,5f575c39,c7c95eec,a9a30d17,dc03966d), -S(16633996,fd30bf59,f28de170,7ed7e8c0,95971754,ac04677,9e525b3c,9541be27,27ae75ff,ca485585,c6277177,7f727dd7,bce2cf00,205d9f49,43a74278,b8a361ce), -S(166f9fa0,b7930124,38912819,d2601bc7,e24b246b,9b19f53a,64f69f24,43c421b0,6289f5d7,ec71e262,822bf209,5855a7be,b2b248b6,2dbe3133,221e1ebb,84a3e7f7), -S(a656c927,7129451d,6ee2d455,9acb3c8,b15fc7ca,302adf2f,3b250a8a,499e13bd,b812bf3f,fc2d1777,6363227c,6ae339dd,39120131,187bbcad,2cf2f792,877a7993), -S(8e3275f3,4a20d2df,b236d99d,40a704b7,ff23eb63,2746767b,75e6a9e7,b78245c2,d2f08f58,55d400b,fb3f069,1124915e,547744dd,f0933f5e,c8e8e5a5,28236533), -S(9c53d1f,93b60aca,5f008d87,852a7425,c043e9e8,b0d337a,23304b51,bf763f10,460cca10,cc2768d6,8d19adb,c970d4ea,55a27d12,f2c0566a,6dd433b5,389e8059), -S(12fe0ee4,5cf521c0,a36ab1b8,970314bb,f0cfd20c,ac2eee26,bcae5b77,661fa370,6b75c75,103adb98,dae0fdac,e2b8e40,aa3eddf1,bff77d7,703ee2bc,c6eb0d4f), -S(2e317981,e91c4238,b5760ecb,90e4ddca,ddb18a97,2015eedd,30794744,dd859a40,33d11a2f,8c17c132,972a8a6c,3529a98c,50694b74,fc501db4,382f7423,772eaf76), -S(492b627c,d368c638,b9c13232,79bc34c8,f765b14,c54ce0bd,6ce655b7,20370a84,1650f188,b118104,9a18c474,a4e3fdfc,bd68f2fe,747c7cc5,fc45982a,e2533aca), -S(9c95a6c2,6684b3b4,e31d87f4,53918faa,a0d45e7b,45bf74e3,542038d3,a80a73fe,7992441d,5497a94a,14e2d0ca,acad069b,2b802584,ccc975b9,f895b8e6,58d8c580), -S(20a55d91,38623cbd,445b576,264b4129,8614bbfa,f1da06c6,c41d26b7,8639098b,a214ac95,fd6a325d,b26f0d1a,768d0168,c035568b,76758a38,a6f8feea,c8405b12), -S(813c3b1e,32812e27,27677a03,1bb3d63f,7562d127,8b62ab37,abbeebbb,51a9ddd9,13738be2,f0f657c,e6776e38,d40196ed,2dc669e2,1c281765,286830c1,4587ca2e), -S(bf197179,9e604d69,79b752f4,28e07c65,2b3727d6,837e140e,f812035c,4be106d3,8cfee411,1fd9a907,5bce32d5,54ebe54,892825fa,22b46af8,633a5ba6,d957cac5), -S(26f0847a,8e057fd9,9a625d21,df2e034d,960d610f,39b50c5b,a7398ea2,10a082db,ccd4008f,f47d05b4,47c98456,7fdbf173,fe3ca96e,596ca4d2,6dae40f9,f40d4fd), -S(716b7bfb,781d71d0,93182b2a,d72540e3,8c83a6dd,e6bd94ee,f2ae8995,1db45620,69497305,986fee26,2e2aec0,57e02e1,d396509b,7c3cea00,77d0c21,5101ee46), -S(6f6730d1,5f7377b9,6cdd97cd,91a4fc40,92539279,124bc3cf,c62bdfac,897e796,3c193854,3c7e5dd3,57ce219c,fb20d8a2,c87ec1e2,45381004,ebff0add,646fb0bb), -S(65f8ae3e,1365b723,fabed346,b3953fd1,463b1974,44972c2a,df37fa00,ab3337e,5acf164d,a3730a6c,125f9e2a,5416e7f2,a233ec0a,2c87f24a,a0cfbcfe,63f222c2), -S(b15b96c3,8bcb453c,756aafba,5726cac3,ee4b455b,ae346a79,87e42815,5758de8d,c7274128,ba2f8816,18540ee2,e9dc7de3,587b6a,ff76cccf,74dbe598,42cd691b), -S(804c9c6e,10622728,19159f49,eb579ec2,2e59cc8e,6504ba29,cf725469,3a3e60df,8f765c4f,f9a27d7a,415c918f,e501713e,20b67dcb,aeea39a2,c873a4d1,3c8d4dd5), -S(9754b3d6,438231f2,326ff09,da4554c,15888498,f2129ea2,931c3dea,341f33da,97c5eadf,adf25ec2,b3ee40b,3526a522,104a8d02,1028a5c5,57366571,e83ce032), -S(17721368,b5c35e0a,2a8ca72,f83c02eb,d1c006f3,5a3dfbe7,3adb134d,aebc69ef,b9ff7e6f,803294d3,71c72dcc,73e257b7,f2762f8f,ebc30af3,e0fa3a26,3732096b), -S(aa271646,f30cc43f,ab736d0b,2526a8fc,20318e53,785070de,35197dd1,bdbaa749,e6e4f4a8,d88785e4,de06845,714c5c31,d9c55e8b,dddc6a2e,4519555,15013462), -S(9a496db3,832fed07,8ef217ff,31ba0831,21376977,426e649,79609b23,9e5f96fb,6e37e2a2,3aabccab,452c0cdb,ed0a38ac,10e707bd,5858e9ca,610d74d7,5a4036f3), -S(c3c856b7,ed01305f,a067bf40,c78f1f4d,49af3ac2,963eebc8,94c5ce1b,13482630,956a1d62,fde75fd2,f9f0754f,f8f8041b,d8ba58d,6da21e47,39150268,5b1380d5), -S(94776b33,9b5f04b7,f3c6211c,cb925dd5,8945c761,b74df28a,79c58460,b49b9f52,97dc32ee,c164d32f,2e896312,ec07cd5a,dc51e89a,646a04ee,16bd0268,bebd08de), -S(2aa84c41,ac10c480,38c4b277,18145f87,15f992bf,ae4f8d82,1114b83b,c2fcd505,c9e4571e,be171081,cdea3858,c84999dc,e21cf638,6c03308,e9e5a36d,67e05aee), -S(5619b104,c7f5ff8e,7f3c9744,4457789,5e4fe608,b44147de,902226d2,14a614ac,73b45ac2,d6c678a8,636d68af,f00c1222,354958f9,e41b88c5,53480ecb,57a7bba5), -S(6ca32160,74987f30,c4542eae,f66abf56,2ae32531,7d70ba81,9bcf4a6c,56d29223,d81408c1,4e899b9f,62fb4648,77f5217f,9b32f028,f50be839,a1fda23e,3d6ddcad), -S(2b0de06c,802d4478,de84b508,f9c73a7b,8f6d4773,452e4599,dfc4f8d8,428ab718,805bb316,34a05f0b,919e998d,d3cc22e5,8fc684b5,371e6167,7f1e01d7,c162915f), -S(e4d4d1d4,bc074de4,884c510d,261096e4,ddb6206f,acd67c86,97f8846f,3ad11e41,aae414a1,40cd804,900653e3,1d92b947,efa2a206,f90a322b,8f8e4dd0,66667c61), -S(68c0473b,d83936ba,39f896e,ee7f6e7b,bece7d4f,77f3dc1a,32ddeadf,198df39,988095d8,e45a8ff5,ddd149fc,b8835bde,aa95a392,5ac1e282,5ef7c2b3,7b8bf708), -S(91f022c5,40ae514f,bbcb1400,67bcdcc8,d0846305,9676cfce,e5039e24,d4b52151,c57a96b1,f77156ec,88ced4f4,4401e955,10a00ad8,bfd828e6,4d9c3b52,b97325f3), -S(8e140056,3ab8bcf,a634adfc,bc9dd508,b49348d0,61d0c0c0,2b63e6f7,c56f08ea,754cf682,54a57e08,bf607155,cfa5ba1c,7cd56a1d,3edb7e82,8b9bd54d,f5f23d0a), -S(41f4e6a8,691d2e66,8efc8ad,aff3fa85,5d55f8a0,127990a6,27c33af,a2442d81,ffff7626,6d75962e,e49c042c,16086e89,13dae3c4,f75a78c3,77ce1856,ca49e3f9), -S(7d76b7eb,82d0e161,b1a97b9e,e39defe5,11d7c6dc,6fae0255,318d7bfe,5bdd197,86bad87a,21b0bff6,780eaaa3,6a30b7db,bafb4740,369841dd,da734af4,2815b2e7), -S(3a8d019c,ca085837,288e6cf2,18494433,f55c6e5c,f58513b3,6ac698c2,8d5e8c52,292ebbaf,921daf15,c7c93d5a,4fdcd646,2238f650,4cc930bb,b9327d6b,9ef4499b), -S(b8daa085,7c7c7ff0,7ee79541,55dcbfbc,749c927b,fdc74422,a281f3b9,c4e538ef,41061f31,f0c411d4,8a206fb8,bc842900,1c82c3b9,79fe3cf9,397000de,6cd89f03), -S(315b3e39,74d7644d,75a453cd,c2de9a90,423512c7,18379b38,cccde80e,c95e9da9,e8e82e5,17289192,fc9c9fa4,de1cdbea,477cc013,25060dd,2a766bdc,5381f282), -S(cadff522,8a3a947b,8e122ffa,234baaa,e7c23f13,59f18c63,49b1cdec,232c9048,bdba6e3e,15e09ef8,2f06fdef,64b20c6,f6656505,e3f06551,9bb9e54a,a671bece), -S(ffb3ce58,e72c3c41,a0dc7203,27e4b557,c524e4c8,d724f7df,7742cc52,eb74ba38,2fb99e81,f1927389,bcc94dec,e0ead426,e8631a22,a25140f0,cdb88ecd,34ccb2e4), -S(56e4455c,369dcd00,d8987d5a,46578fd0,44b9532b,2e86641b,b5260502,5ac0b9b9,d54ebdca,e2f22f40,76af78e4,448b6c6f,8d06899a,bbf5ab52,a616ef2e,dfeee9c4), -S(7740cd7b,fb64a276,30948a74,c510e0de,2c63692c,e1c9ff2f,86349bed,bc856421,c866667f,b04e9b04,638057df,8786d549,bb7980ff,bbb87799,37f9f345,ad013106), -S(ab9df6e9,81b1462d,23595e7a,6749a2ba,4fd1c579,b73435dc,de879f02,c85381b4,8258aad6,e81b1e62,b16aa87d,cd0db00f,53d46ae3,ff92a866,f50ddbe0,b919b9df), -S(f5eca856,ff675ad9,aded3baa,83465964,714a277a,58d5dec0,f08e85ac,5ad16ae4,9b8e6768,f6dfcbf0,b6789239,5a2cd72,562cb14f,4224c3b5,61c1993,f49326dd), -S(9732548d,85f535c1,41792440,bd369270,827d888e,e8f8ca29,27f5cef4,b29395e9,564e057b,e5fbf2db,cc698d28,34749b9a,6992b2a4,604ef4d9,5a42bf50,282aed8f), -S(8bfc3830,eecc3177,b6559a01,7391f883,493e045e,b6e5a173,643bd4f1,b4c42de3,7820a218,61c9ce19,5d9ae658,aaa74aad,12bd7db2,4c5e2aa3,1ff6cab9,79fb751d), -S(6ea9bded,744eed27,4aa346a7,3542bf8b,4e93e14e,5e57965,8a5d6a24,beeab56a,a4fef266,b9743c35,935cfec3,2495d6c0,c36f6ddc,b249c256,d17d5646,55278afa), -S(ff15c8b2,ce43a5a0,27817821,e556d021,356ce795,bba2c632,17d6205e,deee9116,87cf8fe9,3618a6ee,63608a4a,99bb27c3,8905b955,2df4bbeb,4b21b9c9,f3884cc7), -S(eb61006f,b575ee16,865ce8f,5809ecd4,28187875,91d924b1,5cc15e9d,a8ebe9d,8e51dfa3,c7494b58,f4447e3f,90eaa595,106fe0bf,d31eda0b,961f758d,3e01e0a5), -S(14d141e2,5ddb4621,7d99580c,918d45ca,51a9a51a,2d7917d,a39624fd,dbe87a6b,ea964fec,b49ac43e,45de4592,6ce9bc7b,f693f945,f6447649,bbccf4ef,3e011ca7), -S(36241c8a,b9b7a9ad,217c0a81,fb33281c,7b48afa9,ba1d2897,389f02aa,19cd964f,a38a1e69,2747117e,71654fdb,fc427acb,39531231,4594d08e,5a32336a,431f3b92), -S(8cd8dee1,5059932c,3c94501b,e15565c8,7e04d705,908c4c6,a2311085,5e5b261d,e949fc1f,7fe429aa,cf0c4b01,1d88e9f1,f5705ec4,2953a49,2c4f31d7,15c04380), -S(232136c1,5e76435e,333ed3ee,ceeab24f,f101cbb1,75bdb37e,5b8dea17,fe5b34df,bfc5f9cb,66063be2,7c090421,e5cb603f,f7a5c860,f9c460f4,220c10b,512c792f), -S(178316ff,4abed117,effb70ec,531f4b73,26124ac0,adbd66d9,e5a5eee6,7572e1be,5d88cdf5,90a3af33,ff5def9,1b5c8bb9,be36d3a7,a331a6f6,b4533685,ef2dc1de), -S(9341dcf0,d1b0c5d4,40004663,c56e57e2,a792cf05,a51f000f,1d192cde,6e81320b,54215ad3,3824b655,72204f8f,a9603007,8280621b,8162cbe0,153ff094,31becede), -S(e5399547,ea95b6fd,d1aab09d,b73e616e,593ac82c,6c4b030a,56b775e4,abdfcb04,c69e3608,b7202138,7b1f2a32,d445c809,1fe67869,7feca054,d94aec0c,14fee6d1), -S(da3a4d99,ae069bf9,9d65e041,69db4dc5,d9ab7482,3ac1c1d3,85d37290,807dc652,f4096d3b,ad811fcc,48faaec8,84633cd7,a7f5552f,4c7d695a,7224b0,ab05353e), -S(a5b6bb89,4594a91a,679f8d0,252fe38e,d0f8a544,8d05108,eced1e4d,133b79ce,d6cdb4cb,813a4fe3,7ebe9b33,471f619f,9d45c295,6b304491,4162417b,d0b206dc), -S(12d9cc50,8d90dc59,dc92d250,3a88424,e720c0b5,56912ba,57b8f00e,c9a4a63d,56992d51,780762a1,312f2bf5,51b657f0,5bf34f58,19d23288,2093e478,b074c818), -S(d5bf7f47,77538811,4921894e,2985b8c3,8cddb376,c9245c5f,6f1308ae,3f228620,693c17d8,40a58ab9,50b4b374,18caa8de,e0a49ce6,b471bade,43387523,30fbfc64), -S(83f06119,88ca1f4e,75490777,e864415b,abad972d,d5f4ad1b,1a295b4,205c1a99,e893d1d9,2416da8e,5fef7f76,389c59c3,94725241,4534cc86,d8518b3c,6cbb3d07), -S(fe6995d3,78e80a54,f3b1e8a7,3837904c,2d26430e,c81e5b0,11304e56,50f95f41,26a96933,8ad90a9f,4a15db70,28df1628,2214f822,6bd38a87,854dcc2,f4d490ce), -S(12af3d09,265b9f8c,fd5a74fb,62358ad6,a2cbf782,25b73a88,c5e56d29,508175ad,e28281a4,36b0476b,37588e2f,7fcbc4cc,bd88d96a,3806022b,75a4b5c0,8569cd6c), -S(1bebbb1d,3141cb9e,3723fde4,c0f939c3,7e37b67f,346fecf8,9ee9c789,7f25d89e,4f2835f0,4b875fa9,bccdb338,32ee53e,80360b6f,30e139ae,227961ef,426e0c06), -S(ddd3bfb3,173aa6d8,7d867d95,aeb66535,173c9a6a,4f34cc67,cebfaf7d,1ce4ed4,d7cf7542,c6e93a03,e3b37402,2c2877a3,65387e99,c9956071,beeab06b,69ef4d51), -S(81ddbe22,10125e0,32b5826e,651548cd,ba44a5aa,e131c0a7,2b1f48e3,7fdea8c0,80f9dd6,957aa45f,6ff32756,f87bb9d0,fb145b86,ba0b6890,5d15814a,f42b8ae4), -S(f4f5f53b,fa60b009,9317ea49,5dec1044,54352b89,5da6df0f,707d80f9,7d698da5,454cacb8,999acdb,5cc3e5d2,efac913b,4b967755,3ab998c6,8531b2e2,5ade652a), -S(b232f345,16c572e,f7d89d46,679a0458,2bdc84a2,39f35292,855ae063,fee9a1fd,8e480fcb,d3361e54,a128da49,6a2285ee,829ab82b,7a1530ad,e0f7ed1f,87ace8a9), -S(9f5a306c,c0e7f392,523ed44d,c2a74f62,cd8912fd,292feae4,493a9a90,53e43be6,d4a1e25e,46cbe19e,88b342a5,a278feb,9b9a0523,4636962f,b9697931,c47a848b), -S(4d5005c5,4b079a57,3ce42e6e,87cbec94,cdd520fb,16ff9d49,e715096a,a5ab8301,afadec78,c911fd4c,1248210c,622f17f5,7a34a6f0,1fe07abf,89ad8242,a0340732), -S(6b5d7335,6b80d4b9,9ffd3d6f,5b8376d4,6526753a,2367f046,5ed19550,4e732cb0,c0d10b3c,d9eaccf5,1eea0088,fde2ba55,17f85214,2b46fa6a,99b35a5b,811f5435), -S(896c9047,90f3a428,20715852,9b710560,bd18e038,a8dfb710,fa2bc910,ce25ca9,71ab7cc9,ddf7fe7,ea77e985,d438e0fd,34270829,1c57745e,decbb0f9,b161c4f4), -S(2812d428,7e3c5961,808326d6,8e79c93e,259c3f31,e02449ac,e2b72484,8ef7539e,eec93ec8,b2cd2b18,9ccf8d1,ec8d490a,4ea565e6,ab58eb78,3aca8f5c,b92df37f), -S(d7de63b7,421827c1,ee84acdf,c82a7e72,1eb42aef,7d91fc66,f725e8f9,dc42554a,d6dde944,ec65a85,ac0386a1,eebdc69c,b8793ee9,417e4e1e,8db8087e,bf1b6f22), -S(8dbcc742,a5856bc3,e29b009e,46985a7,67800404,82b06681,3c63a27a,667ca60c,f414fcf8,50b82712,cfcb7d3e,d92bdad2,958f75a2,9f5e69c0,67b3cadc,10da9293), -S(8f046e5f,7ec21b77,3df1015a,19a7aadd,bf5ad912,b5020ff9,b574fc9,7d442f4a,4fd50026,6f8a63cb,d603e3d6,f3f81aab,52e79e94,cb0f7159,fffbdcdf,9dba202d), -S(fc7c51d3,7e6dc2a1,bc542bdf,dab38775,54bb6787,dbe5ffab,471d79c4,8d2a0a58,a7297795,f7f9a558,abc67243,900005c5,2c619c52,bae08a62,5de66bea,81acc475), -S(e36ba16d,81996e80,36b3edcf,67136ecf,7b5dc68d,526a34b2,45843fa4,6a078f0b,25b39a4b,1b5d6240,30fa90c3,558a1eb5,df7c44cb,698f9d76,40432983,faa3b003), -S(c1c817a8,43140681,ff908319,a24684c8,dbbd179f,ac49cf4f,428688bd,3eaebc23,18e43b3b,ced5d5e9,530c05d4,6156fb9,fbfd60e4,58048825,c2d0dc78,e9575594), -S(787e110b,665a8db7,40c2ae0c,206ddfde,4491768,9aba8ca3,de737283,52b70d8a,7e22a27d,976262df,22c60307,ad61f435,b4b27dfd,85657f25,72899d2c,5fd005d9), -S(e1106094,464cd775,85b9eb8,cfe44b13,14b4e87b,54a609a9,c43dff38,995f5e27,8dff0b9c,d97f2779,fee262cf,629ab48c,483e8c09,c05657fc,6b0c83fc,3c64006e), -S(16f72b7d,9b9f8490,2989e9c1,8d067f31,b5e6773f,fc03b2b1,bf026b3c,a45ac92f,6260cc27,6f616934,9492c169,a9f97bfa,b3ad1e16,2b6a529a,7b637ed0,828f6a16), -S(1566a7af,1c3cd035,29859976,8dcd24fe,3dfd07a3,c688d048,c45f9170,b790c791,23319b6e,b9f84cae,f9c6ad8b,1c0a9c2a,6574b84c,4abef9ec,29754a1e,b3a67e2e), -S(bac2ba4d,96be7dfb,425e1279,8323068f,2a42d0c,564e3466,92a89730,7b90b66b,29291264,4e71cddc,7e78d20a,dc026e90,637eeaa7,36fb11e7,25d2e9c2,17b3c8e2), -S(b26a1e6e,1099aaee,14f3ef63,28ed7ae2,d195e04b,1d55e394,d0e11fb3,56807252,2f3566f,f7aca2a6,7e3e8e6c,294120df,86a92193,c2a0a79f,fe22c549,3385334f), -S(9a7a18ba,1cadb917,b68dc78d,119954c2,1b5778f5,a1445238,8cf7f481,7f49cf0b,14e484d,d3fe5242,1737094f,53861ee1,27a1aaf,2da7392b,f03127b0,d0d86a41), -S(49b26479,6efdf6b7,76f70672,d40644a3,e390ed50,1baaa862,1340a08c,649f907c,ca54a985,c3ff23a8,bcd6baf0,ab223fde,65b358d7,cc237b2c,3360cc53,fb7e62cb), -S(a27af3f9,728319d4,248af74a,a3e2d249,947ca87f,3e2d3293,9f574e9a,6da03f9b,226685a,8ad2073c,e8e32133,b2fca804,918d1247,ec1e3053,328e59db,70ea26d2), -S(de13bd9d,3544853f,10768f3e,8cadd376,f36726ca,5b27280b,de12a8a0,1d38f876,6fb4310d,96739a32,3b48e9f6,f215a0c2,f270d272,519e0085,ee72f325,73adb0d0), -S(6680238c,5ca916ed,5169ace,3c2e7103,3a3a26a1,89cb2cc,4420d23e,b9a98e5d,171affa,b6f370b8,c06f85a,928916c0,f6b45c1c,5ca2349f,4469aa25,c8f9b6e7), -S(c1787989,1e100300,1facb000,c41efa43,710267e3,554e0f65,f954a1f6,191388d4,68698007,38cf474b,e577d109,576c6984,cc39da19,371dac87,ae462d2f,2129abe5), -S(f0010a2f,63b6d832,256fe7ac,7b885d1,abf60db2,982b8cdc,31a8595f,23f9328e,cb3a3e15,ec21bba7,72a720cd,3f9bb93a,b0796aa8,c5ee119a,f862d5a4,e547238c), -S(2919f01f,f25e9171,1db684fd,a25c8a89,caf84f01,9caaa483,704e736b,92219e2a,f374dc4,8115ed9c,97efbf21,936cb5eb,814f40ee,40c8f97c,af29f3ea,d46c0603), -S(b110c17b,786e9b64,396003dc,3e0c9bd8,8cc4d060,e7e442a9,8bb3a1ec,2edd6663,6eeace13,a43c6cf7,33bcb313,e5cd7781,54c61fce,e4864924,f20bf45e,5cfc16ac), -S(1a41b8c2,f0bee447,3a085941,4479767d,b2c026c3,6ce0283b,337fa021,87e98435,88a46621,939d903e,9bb60506,3684ecea,7b2fba43,4f5f437c,f94c42e8,b4c274ac), -S(764fec0a,7ef7ccc1,ee478e82,dc122574,6bb18158,cac61402,fdcdae83,8177407a,b0090a4e,fb7da4aa,a54c24fc,75948587,3e1fc957,a475167d,5bfd85,7dc16f7d), -S(e9a521e,49b18a0e,1b226b11,d0397f47,8cb04d92,c8eb4cf4,4e70a0d8,c27a2f8f,b0fbbc19,7e70e9d5,765d85a4,1acfd3d7,84f06554,4008a89b,440f78ac,63a7adc5), -S(da01400,c935873c,1bd0a05d,2eac5595,c6e18682,2db4112b,b0a7af7c,f0b291f1,3fe8c281,26fac7fc,b629a6d8,9ac945a7,566f3414,d46f5e3d,3995ec40,e6aad876), -S(ab69b97d,a15898e2,d77440fc,35c31a4f,7f4930be,6a132e6e,66a529b9,b60b2796,7c80faef,ce1cb7d2,77900d17,e5887c0,c80dc0ad,b9c33fe0,5decf40c,f0c77e3d), -S(8001a2a7,3938254f,fc3a518b,2e9dc61a,bc7dcd1d,90e55812,72410380,2a91c2f,985191d5,787d0cb4,809923ed,b87dfa5d,60c18938,8e4529bd,2353fc42,9a061060), -S(5a93eede,e37ca03,194ddab9,2f9c7cf0,ae230a82,d489a9bc,87ac7180,93165e41,15c6cc54,72f571d0,c78ba2f2,8519115b,16a2256d,17ba055f,5731edfd,822220cc), -S(f0853089,da262598,d86771be,ebd4b38,c7060e9,ae9474ae,f8ba683f,1b70bb1,6508e3a5,b709d0a6,c6505be7,cfaf6744,3b741d9a,5f9adf06,7eacbae6,23a56819), -S(182a85e2,3d4af778,e652cedb,1cd6fabc,81bdb345,ec7daac9,f717249a,5d6aa519,a509c2bf,1df249a0,e477d3fd,e924146f,c9e7ff78,9f625174,587164d7,1dcc259c), -S(dc1f61eb,da442680,5dcc73bc,b6c59288,383301e,50c62a86,a9274a72,8c49ccfe,4d99f11c,be55738c,a2b889db,dee2e3dc,9d3fb44c,8cfef36c,5357396d,97c52cdc), -S(88d959a3,31bc66c9,c6aac8f7,ecc91ead,83591749,97c60a8b,7b11ddb5,fb8253f8,53eb97a8,b3714975,263bf21a,4ed923d7,39276e3d,b4cddcc9,574bc96a,f4083855), -S(53fd6fda,a8e04a9f,89fe1adb,90704589,8fe453f8,1c069b0b,5d5a9fb7,d77d612e,a8325053,95360123,422b6419,109fd9af,397ecf9b,71a6d322,b91c9c1e,ec236b4f), -S(fad9c66,bf453615,ba53a597,8e60eaf1,13e07192,1e820399,6bb850bf,237992ea,8a3a6b9,3a127d70,a36eea2,78668168,34bbb025,902cd3ab,aa499d38,8e24d657), -S(e4b96c12,223f45d2,d7bdd8e9,7ebe545a,16d23dce,1a090b3a,5ed6c9e,65512a65,57fa0c7b,39a473dd,20571bef,80a7c738,cbaa67d0,cfc7f64c,ba0be2cb,123d49bb), -S(7750e371,3b25a5eb,923c460b,967d9dd,1f00e791,cc3b52,9d3ea331,fa1010be,eecd47a,496d6a13,98e95c1b,9ca629eb,49687962,5d690434,ca41279d,a65c605f), -S(93487b6b,25ec86d3,59ef5bd8,e2cd397e,d618c2d6,98d9a6ed,28f3817a,31ae6053,f66a87b9,3dd96064,489537dd,1f9e693e,af0219bc,2b0f752e,4f53b9f4,92715fea), -S(f58b9a95,4d873bdb,931223d5,4867d818,d8c4a2fc,773a1552,35c6b182,aa8ffde2,752b711f,735bbdce,e772dbaa,89f7a95f,d81545c5,5ed25c2,8bcc40ba,4d82ff20), -S(335e471e,8756d394,8cf43e2,b32d2f7c,46147d2b,c467f089,58fb7541,89e4913f,c9e5bf5a,37b19ffb,41d39f3b,8f69a8f0,8ba01a52,559d684c,5eec3549,7413f3e), -S(e6a7d3a6,6ada823a,8b0cbf90,af3f0788,39ebeb9,85017182,74f29f58,1b9f29de,ff850986,71962405,edba654,1857c858,ff948c7e,4bd2c5fc,64afd2a6,c643720), -S(785e6bf,d3c5ae31,932304d8,27aa74f7,783277ff,fb27df66,e1596a07,705b2de0,1166938d,9604a7f8,2485ab74,af763876,2271ee5c,5a7427d8,2d8569f5,25f0008a), -S(228644d,5c0be7d4,59dd5aea,e4019421,83ea6770,ea40cbb0,38b3d1b8,f0d4cef2,1c489d4e,a1595fca,693bf7fa,d6672701,a23ee40f,b9278b1c,566d4faa,5d799c00), -S(a5ddf933,8e477ab7,fccd9344,ad45609f,7be754bc,eefba823,20f1b8e1,3ae9c15c,3e115120,5de4a550,c0f65848,804ac964,168481f2,12b2156b,544152ff,c9f39306), -S(668b35aa,b4799dfe,dca25a50,6c32ca97,3a5e6c3f,51676f82,e572602c,ec3e8a2e,63f33101,d9be94e,7d8971e1,4deec0b6,3406a621,77d5a044,bf43415e,c35a9234), -S(fae3a6f3,f9aa47af,a4babed4,7f366c09,da8e7074,fcda3f92,c74c1bec,c73aaf64,cb38f70f,61bfaca7,76fdc581,a468b53c,69d21815,11771cfc,698a9558,209736e2), -S(2fb68357,285d4ece,96ad8a3a,9c6f0f27,468c9569,3c2e1a9,8864a64c,757c754,b74b474c,133e0a4f,a8ad5032,d08acb1,531640a2,6dc09af5,6af1c862,91c06e87), -S(9f073149,dcbde92,8ba24d3,c00e54c0,c334b958,f124cf91,467cde94,9ea9848f,21e1474d,c43a9d33,43c120ad,a751e9d6,ae6c9ea0,986fdaf6,fbe6bdcf,23085d6), -S(bafcdee0,c0ad4fca,3bf95576,403dc2f7,e28884d9,b8d5f77f,4d7049ce,965ccb4a,4578e9c1,67b07364,f70d8cd,d6dda3ed,28b87cfc,b8d5c8de,48034eb9,5ad3da08), -S(7d909f21,b79fd78b,7b65abed,2da2b831,c7dd1794,cfd32f92,a4fbfc0b,3b666233,c6f2f069,f4f7aaf5,fb263dbb,389ff7ff,86a5f5a8,32c9311e,cfe31af2,38313e5c), -S(5d4ed232,4e24ae92,2f3a1aec,5a8de0a3,e7eac523,58770697,cb45c7eb,4e6730dd,878a1b35,ce2f6880,5b4786fe,eb49480,c6bed243,8e2cfa3e,4636af5c,649056b0), -S(8a97e97b,a3767b06,a9bf75f8,b7d62a4a,b22903ef,7d7717bb,7165155a,b375b959,6997ee31,72cc99b2,8f447052,b75b5615,db7a5349,f1445c6b,bf04ecf3,c8ef9f5c), -S(905aa389,b32cc33d,f9d52e49,39ad4799,8cfd03ad,bd4ed3c1,7810c0e8,8e1e064f,7102cdc0,1d6ea4c2,a426ba6c,1d4565de,c4d0f3b6,458108e4,e0539069,ff2f8a78), -S(510c5aee,f28f8345,2ff713,eb0dcd89,6d788763,af8cf565,dedd4ad2,c32f60cb,ad1f4e3a,549ba056,c3214148,504cd177,adff0933,bfaa07ef,dfad12fb,74609537), -S(66ade073,7a0510e2,40f13ac,db8337f7,80adad8a,9bb68b56,7f5d5d6b,da7cb44e,a5ce9959,f57e1e2d,8cdce9c1,33f6e684,2975a933,8bc8112c,3d68ca88,e668d19), -S(cf51bf95,42cecae3,59ab97d6,1f35ca91,a28bb48d,14ffb958,b4bc95ac,aa5b4e48,7db91cd8,306252b1,aedd7afd,ff94b28f,1e8a39e9,abfe26eb,9189cf0c,37fa5e), -S(fc409559,404b55f,27503803,9a1a36c4,bd42fa53,ab520417,94623180,57ee0622,79b14cb0,5b5f7e30,bf1ef45,cbeb10ac,a05d0819,fa9205ba,3e9d8952,afc74574), -S(832bd5f5,fd0d8771,80e65a02,6ee3c1c6,f44735c8,ce69677d,546bc2fe,fc0e44c3,b2430cc3,7d68fcd8,b35ce76e,229592cc,43ca6ba0,4c2a001d,67ccf5a0,2bbee37c), -S(d66e9431,bdc39c9d,d598c3cb,2ef18d8b,508ea830,3fe5db36,9262c476,66384bf3,b628d1b1,fef2997b,779b5f95,28fcbd,e6ce77ce,c752d83e,cbfcc05e,ab05f670), -S(1dd1514f,85d214f,4c2480a2,22cf00c1,f1ffe62d,ab452dff,6cc7f61,6c66f74,ec70290f,1eafcd75,d87e84d,cb86c460,1413175c,9f18756d,e92d6517,2f688fb6), -S(8a6b21c4,44ebfb6e,61023622,52165611,bfcc2531,1d0d59b0,49f25eeb,9894dcbf,95f6a81b,177faaff,25907a4d,61a7c323,4d7ae932,2b9f862f,a11c86a2,5c894699), -S(48fa5a8e,769fd471,122e6061,d7da307b,2a700a46,bab0656b,7fbaed37,7b997112,e4bf13ba,4456de5,b2c07597,c5b82111,ca05d178,cf0afdc8,9afd5df9,645671e9), -S(8aa75f18,7362cef5,91c58d4d,d1e196dd,5fdd9c7f,91685fe9,d4bf9025,fafbe0a7,81df12ad,b9c543f2,467c4c04,83c1358a,af08fe87,96b01d2,5e26719d,d8c06590), -S(fe10a4a2,c81f5155,e8f23469,c3b537e,b2f45237,8addbbbd,8a224a33,2c7cce6f,95abddd6,e81a6b0e,feadf6da,6bc37e93,f96f8826,efac71ce,8b36762b,dba0cca4), -S(4c29b630,af2a77ff,ed3773d9,a3d66cdf,fb100d67,8a7db0b9,1f37f6b2,249d1a6f,58ee018e,f5055aaf,c39a21cb,a68f4f46,6d6a25ae,e07440fe,2f00dbe9,103b5fd), -S(3bad5249,20c3ea2e,fc16ec86,4502804b,394f3273,5d42e047,c0cf694c,b4350adc,c553a54f,7462f2be,c8fe478b,cbdc4c2e,f693d8c7,6164f513,7e7a7a12,4c6ccd23), -S(8c087953,8616060,cf0deb02,1f46d60c,d1bc3b4,a8bbcf6b,39448603,59a2aff8,5f24e4e3,3416655c,cc35b47,633c9231,bf15443f,132c2df2,ed3d1534,52aa732e), -S(7e080d31,fa764a8b,92e74bf2,c69ee7b4,a7b2c2ec,6495814d,8901908e,443f72bb,f34e979e,c41713e6,b98d122c,a7c0fe5e,89624941,d2d6b44c,c65c4244,3f6a9094), -S(a5acd6e8,50f9b182,162ce14,3b19874b,b9ef6d4d,7c042eb2,c4dc4e21,eed6baa,85d55adf,7220b662,c5b88d63,2f1e7b40,4aba5158,2b93a22d,b3e9457c,b68ddbd1), -S(5149e4ea,600a6dc3,de6c91c9,3dd43a5e,a5e64245,1e791841,39f31749,7fc15a0e,7274076a,9b177600,85446c25,ceb68e34,217ac3c,e4c8c232,a673b0f8,496311ab), -S(e6548b3c,46de74c1,40d9480b,b01aee17,dc6dafa8,5843ff8d,e4a75878,a6ab057e,11704026,373c6c96,30da7f2b,7713a313,e64380ab,4f35d290,dc789f75,29308f6d), -S(80a85ade,2372d7f9,74bbdad1,c6e88df5,4d671f8,7447884d,ef186155,d223183b,24a1858a,5fb6aede,1a36e16,7d25b3a9,2e2f6639,64d60349,7c13e9b,3c14c7a9), -S(35ff436b,571336e7,963ca450,fcc41caf,83307da3,65468dce,28014914,7760b8d1,565b63a0,546379b6,585ba675,52fbe796,ed68a9b8,35431a74,e8f4b989,2027d8b7), -S(12a46621,fd5f9ca8,f8830338,4c150e2c,1df12e06,1dbff329,d3157638,4d67dab1,b1e29c72,e7ccf360,e8863c3,48aae396,2fc989b9,15debc6a,514da0ae,67ff38af), -S(2e4b50b3,b072a9ad,ab9b2438,bf554f0f,bdc06d62,f601bb05,7640b7c5,36949cd9,16c7ebe9,3dbf67b0,fc716d82,3f6a8fc6,4283d7be,513df237,e3afb062,eae6a10a), -S(3b893c39,58a4a0ad,49e3d2eb,b53bd3a2,fb9144f9,d46392c0,93a9affb,3d21bd2f,c965097,99ec1519,5877cad7,4ac6ac0,8c55e9d2,df34b4a6,b1758dff,c5faefc5), -S(195c553b,6de4ff4a,6b9ab252,f28f202b,504ddf2d,af69dda6,1c3d065b,592944d5,9faa60fd,79b63de4,cd3946dd,cd3baf8b,c5795e3d,e4018d7,c1733e27,82ca397d), -S(e8e5178a,c5b76d6,68cdad1c,be01cdb6,e9859609,84c05666,dc8021b2,12cc15bc,ba4eb10a,342d8742,504a468d,f784af91,b8cd1def,112dc8c3,4bae99ed,d855b0b5), -S(a5f99556,4e8d722c,a61dfc74,2cbc5ece,6f654cee,7c716335,5cd4f5e0,1decc0b3,bdce6c99,c4479cf,1547f394,8e9bfd07,ae066d7c,6baf7cf4,95ea2037,191e1594), -S(98065d45,270d94d3,e43b8c46,fc85570a,c72043e1,285d673c,ca1c668e,6373e4bc,a45d5f7d,3e6a51da,8e95333c,2333e7cc,aa938335,7bf7933f,b8004682,599db967), -S(bad7e989,8b6a97bb,98e66b9b,a2e533d4,7d33f0c4,d71c280d,efff5570,660282d7,3d3379d0,b9ad6d70,51002395,bd01c3d7,165e1f2,d61a5ce6,12dfb89b,8e4bfa45), -S(c914752d,4c1bc92f,f9fef612,77bd1633,840f9f74,2bf88bd0,d2fa2698,bfbb6377,ff8a4aa4,b0a3156c,7224f499,bc6147cd,d147aa5a,69c1c225,ce19c663,da7864ee), -S(d58c1fb2,7235da86,8284ab85,1a6ca2e6,dfcb26c6,1c544060,a0bf9083,1471aa50,8e4c5ae8,28e2ed6d,1fa1bd69,9d3a01d0,377e4fb4,bc692ab9,f2e3ede9,13bebbf4), -S(25e409e4,8a8f05e2,e0cf11d0,5a389206,18377447,cd0294f0,4a92eb02,1cbcb500,e7702eef,d40c5cac,4bc2f99e,93f0bfda,509f2409,24307664,c99fda52,a18286da), -S(22d1fef6,4140e996,9451dfbc,32f0891,7f600102,3f9cc11f,88ece53d,49321ad1,5a6c11c7,401c99a5,bed96396,9af7ca1c,bb612d1a,e1067cc9,ca4a1785,408bd79e), -S(ce176236,a9f48b50,7515532,ef8e172a,f017c5ad,87ca2f01,1c8b4ea0,64d44b89,a0266107,fd7d38da,53536d75,6e7b63dd,372566ce,643a4b1d,881e31e3,8a699508), -S(3080fc65,9c01951c,f643e315,f7d48339,e8134e09,5c5c0e21,f7b9ea35,1d859dfb,6355c53d,d8147cd9,b31be789,7bf2f65c,e3be9535,324f41c2,850b9cc5,ba607472), -S(e4798722,a4b284bd,ee6696c4,3c67aa50,11cb3616,7dd7b21a,ebe50ed2,e7d1a253,3d524d92,5dda9fcc,4422ff7,981136c4,4f373ea3,a41cfb7e,e1f068a2,466f6ffb), -S(c82b6536,1e8d8282,9350fd86,e17e63bf,75495dd7,51a967f9,51f4b7f3,eaae03a7,91b896e5,d673cea1,e6fa536,22737c68,c701e2a2,db8a4817,3c316006,b0b84a9e), -S(e911dd65,724fafff,55943a21,df3517dc,cbb3c236,e19aee86,c3f3a5f1,66e3cde4,a51bf72a,cd26179f,839e721c,1de0ab93,cf221a3a,72202b53,d8e552f0,2fbbdf97), -S(ae759e42,cf0c0935,155eb36a,5f07c251,bd4923e1,31b0477c,fb7ea478,9ca797f2,3c12355f,e7dcb9df,73362daf,d0ac689c,a6a24965,ce65fbf4,e5f9c6fb,271a8a85), -S(5a443113,c04b35ae,bbc16401,f2abf9f0,b9644cef,6e8222b0,b67fa109,a19aa3ca,6c7bb7a5,7dc10e2f,140601ad,6c1a7f3b,fe122e80,3531848,2a2495df,a7cc5221), -S(62fbf303,ce5055e4,761d6ba5,4e965e0f,cfc46a4b,e0dd885e,f3803875,e0152b31,14dfdf1f,33941493,d9bb0956,8f8214b3,cfdd18eb,6d6a79f4,c33abeb3,f6aaa86c), -S(47bad781,2ad847ef,471e3483,480fdb67,b08b5679,74f7619d,9f6b4de3,f3dae3b2,79a7976e,568e5220,8bfdf6a1,95a7d16b,8a4dca64,e53ee7c6,c8123d6c,839829a9), -S(fa4381f6,e09f9a19,72d7dc12,76fe579e,f8a9ea0e,c5ff06de,390d150a,fd3cd49d,ff76e0b4,b3f8408d,5c4d79ad,8ca85789,30692275,1d5d5d96,9aebf6e5,2971c307), -S(b891d634,64c7cf77,2b1c19f0,835869a1,50668494,e8889e85,6081ba35,7dfb0d6f,8d716524,65dd0f47,b39bd6b3,7f6efc14,c0108992,4741ccdd,71fa9a98,19e5f05), -S(eae22d01,98d6f036,5d3ac227,856633a9,d0ff6dc1,b6d5d1e5,a1b2e4dd,c7f11466,723a69f0,b551fa41,221e3a31,8fd2b60a,4baa0741,c6127e67,b542be14,9d255074), -S(765b7989,56393611,1b182aca,fa7a2a60,ad89f6da,fffaed17,ead51975,242008a1,e630c87a,91235862,444891c,42dff3bd,320a3272,2d43757d,5ee46eb,af5412f0), -S(ff77d59e,b5ef78d8,49496995,b20b98cc,c847ab95,253b3a6b,9d6119ef,5382ac12,b7791936,e1bcfad,8bd5fb0a,1b547261,ee0bee24,5c1e58b7,3fca8015,195d2b1e), -S(fcd78964,e8e5fc94,f575fea4,7d61abf2,c89ab915,2683e855,d48c6828,b95eaa6a,9f32180c,683b465f,203d4d9,2f2eacf8,396966e3,2bece1e1,413f2111,f000b000), -S(38e9c6b1,b2495801,455e5ea0,ddf4bda2,432b84c7,4f9303d4,c9d6e30c,8e87f564,ccd32af0,603f27c7,7cffff6d,9203167,3cdbe4bf,8662e224,498168c0,5e7eff1e), -S(9de95ac7,9e8ccb95,7b62bdcf,f9942194,4a691b3f,5646d800,68e2e7a0,976d944d,9d99c259,d5fdc8bd,7c29e2ea,651b4abd,354f8ac0,758077df,f46b0896,a25f99c5), -S(e4d34872,1f8f7fe,d81d810d,8fe26811,87d0eb93,5f8eb6c9,2735a55a,720354d1,1b95fd74,ebbed926,55004026,e2110fa9,5bbebf7,efb6b0b6,d7e883b8,34677cd8), -S(ff0222bd,d37a7b6e,45b182a6,cc744545,d60fb6ac,8171f625,a29d215f,1af3ed80,102d4fc0,c3434443,6b8ed145,a5a19426,247b5969,3755d3e4,dee475c5,1211c755), -S(27922e13,f03b2f70,bef94a31,589c1e7,9017c16a,9e57ede4,4af93c38,174dc1c,3f268d7c,3d9aa22a,6277ccea,c36b9377,52b94658,c44d110a,e276e560,d4bc18bf), -S(9f995f1f,76ae01ba,38b02cdd,a7f99b53,883e035,afb35b20,324fe6a6,bb65db6e,ccfa6f06,daf16088,7f2f8af4,18a5b107,cf1a83a8,12f117e1,7e938e4c,73ce924a), -S(c1b2bd23,8fa1db5,814a07a1,d6db2ac3,4f960dfc,c88970a2,9dd21c34,3fea87d0,e912dcbe,ff0391ec,7987f901,c6329c2,a070d64b,53131c5,7e99e6a0,27465f96), -S(789e932e,5665aa8c,24e2f0cc,1039cd89,da928d0a,1b4b03b6,b93fb79b,f40e04dc,25315b3b,bfe535e2,92519e89,b63da55e,f4c16a1b,d8af3394,b280ea62,3d0953a7), -S(19c54824,5815e2b7,b31d35d6,740e660b,84613096,60ee9bd9,6df823ab,1e7bf39c,9c0516aa,79e00ca6,8330d267,5b104e80,3660fcf9,4d785216,90a319a2,44885987), -S(2e73f0d4,de4f920c,5a5175bf,32e6b98f,5a49d1c0,a7af2b98,a6c6dd60,52477bf9,12dd835b,fc93af9e,680aa191,bfde6cc6,f307dfc6,aca349f7,c2affe27,40f87795), -S(5b711fa6,4463434d,d7c824ac,2a56d02e,46949ed1,d8e530b8,71e70a82,38ae224d,14329e12,940d179d,922b97e8,d2a2b7ff,6da66497,6879a790,1edd6035,f47593fe), -S(a34546f7,aded19cf,4d83329f,41cbd292,bc59f37,f290eb7c,ba28aaf0,a32a423b,9a2631a6,cb6b2989,fd2ba260,5aea7f73,c08f05f7,e025493f,459461b6,5ab24dd2), -S(850cc29,8dcb42ab,613b2974,57c80ec2,d98ef5d8,562af745,d4ffcfac,7e9c0853,b07a0e85,5cd335c2,728338d2,8a1c32c6,e3a0fb76,58b8bca3,f6bc02f3,de68a2ed), -S(8de69064,cf3f8d04,bc20a995,7677427,7b712ed1,f77fb7f7,9c361dda,2c7e8b30,34f6938d,750874d,573bd5b0,c11d9c93,b6260a9c,6ae833a4,350dd779,c515f16), -S(69d1e613,852194a2,b618483c,29517029,b3fdc8da,d679c07d,3204261,80f89170,a70f4654,8b7542b6,5da14788,56de6c5c,e06490f6,176794e1,a4dcf25e,4337d570), -S(f238036b,d55e7b7b,6d0835b5,2c3d5c2d,cdc7e6ae,6295e19c,2a0d6a63,669656c3,b401cdf1,15e8c93d,f5e230c7,a3ab387c,687fa690,d86da5e7,d038319c,468bfbfb), -S(ccc74591,1178eedc,76c98013,a52911bc,1da8f9ae,10f40277,ae51fbeb,2b6d53c0,d4cc4eab,60cbb4f2,9070717c,d6151c24,2914069a,c3a68d20,7982d758,3ecf0445), -S(ab2080d1,f6d6ed76,cc713c8b,46474648,c7d1bd31,fa6ca6a4,39d0eb8e,ec4edd4c,8da5323d,e205f2e6,4ddd80be,679dce01,3d1f2813,13fb16f8,e749902c,16362b0a), -S(96ed8ce7,36e0d3d,607e7b1c,fcf6316d,1bc60122,c1e2cfc5,5b20d379,621c564b,841b64b,af84d76a,45afd86c,28d32f79,115675b2,9a15c9a2,50c328e6,2a79695a), -S(b41e63b9,e3fff8e2,d89f2a69,b80f1d38,60a8fabc,20290d41,657467eb,9eef61bf,674d416c,82e50cbf,f001a44f,3ea4108a,c7cf8747,3b7cf851,ce9a9d1e,f5b90dd8), -S(7300ddd,4d22e101,a5ac174c,96f1ede2,e5a8af97,e4d7a5a1,e1f07be1,ec9b72ca,edb4eae6,e9d20683,6abe214,aa95cc75,a4246e14,86b05f23,ccb8c4dd,3bb18888), -S(5d152ede,6e8055ae,14c8c67c,3eac3dbc,1f080dfc,59d0f1d6,16bab4b0,460d21de,e615d095,b3ecba8c,dcede3b2,bfad0814,781b3afa,2b631928,74020df7,b62e1425), -S(bb8f9d6b,1f81a373,32a25eda,b4feaaac,9d82086,8297eb80,c1bf6c4,5f5c7cb3,772be893,a029961b,35f7174e,72dd5c44,e8c745a3,423cba1,2071ee89,92c604d9), -S(643730b4,dd3bf408,2ae96f7a,f3409b8e,690cb09d,f379e3a4,9e8d09b0,de30488d,55a68bcc,54be84a,3d79af27,e2d88740,e9e1eba9,e2149aa6,1cf4d7b1,de6f1e57), -S(82dec11a,c2c7a667,336c5d38,2224a5b4,12c7db82,5fb9adad,30552bc9,db2dbbce,7f7044e1,49f03a78,ea93c129,6bc63541,8b03e06c,5cf24bcf,7df70669,54e8ca26), -S(349382d3,95677d5c,f259f280,83c88ec9,47da1351,d26710bb,4a21d54c,cf770331,7e81f343,a9413313,91b9e4bf,e680a41f,bcd13598,bfa2fcf0,a17439f1,e8215e31), -S(4bf9f078,cacdc26b,5862aeca,d3cbf4a8,3c4321c3,62a562a9,eee4a8bb,5dc66125,6d38018b,4441d376,dd9f4bae,6e22782f,efb1c3b0,2642021c,31495b5c,8ab3fabe), -S(cf319312,ce28b168,ba4b41b7,8f06e0d7,849e672b,21aff86b,5865d32,4e0aa0f1,d1caf763,6d277e8c,edb4e03b,b676718c,7318e29c,e756a868,6932ea74,cd10a84c), -S(de892197,d6db602e,13a9f3e8,d36509a,8e79fd15,f25c9cfa,4e610ff3,eafde1d2,e2454f06,569b9b7e,121534cb,31becd31,31856640,16d5d266,a98fedee,f4026ec)}, -{S(6efd8760,aed4f239,bd97a00,63794c4,ef14acc9,f5b94862,4c7f8b51,3ff35278,74acac29,694c5307,aa221b37,f2ea068a,a269fcd3,c6d85aaf,a8c8eac1,17d7f997), -S(7b466cab,a5820335,bd6c9e51,7f31e735,d3e9276,18c36e6f,861d032c,f2c0efb7,12e04a7a,953d1ecc,c0cb9cab,6e06255,f909bc3,e0b9f2a8,e667150e,1eb879b6), -S(7d73eede,ef4f9ea,34fe9a3b,9555307c,5a8a0fcc,12bae70a,34e90b07,fd3c36eb,e4f4b5c4,8c1ecd05,e7110725,c7a39a61,9f66203,3b6a6373,fa966017,2f5c611), -S(a8d37fa1,c07cdf9b,dc6b77b7,cb6c3e5,99930870,6a2307f5,c7cc2e3b,333a6d1e,665e43c,58bec5db,c87595,8acb5fea,89a0a742,641f4df8,f1c8b238,1eee0774), -S(1f4a4126,eae02858,86df6ce9,3d6bf107,be37564e,66048131,43ff65d1,48ce4ef4,b64de137,1bc84933,95058a4,70a7135c,6202e5d1,c7406759,5269cb98,2e1159c1), -S(5f963c6d,355346e,9feb82f,90921c68,7df67c3e,6d0db15f,ee46d58b,60bee0fe,12f8f5ef,326e9b9,68ab60cc,1331fee7,11c9369b,e887067c,4dba63b4,707cf1c4), -S(93cb2373,e9272b3,378d7e29,59d7d935,e6395529,5b2b6482,15afb9b3,9bc5f573,45bdc11,d37edbd,51e816e1,5d27715e,2f50fb19,ed9a0190,573adc61,2f38db2f), -S(4f231e1f,caf63030,f596cddb,7afe9fbe,2ba93d0,e8b18213,79b349b6,7f8a3ab8,7fbc097a,f61f0c69,9b8b2660,51d332c0,ca8134c3,1c4ac6a8,d1a820f6,a389e9a5), -S(b3ebee1b,ccd21d5a,e45bad73,85779014,216cd61b,7cac39d7,5af121b6,b7438a5,a0c1a664,379cfa7,2b3a1ba8,6c6ec9a3,a62712be,1df870ee,df945b9e,62727b08), -S(9713f024,1e06a7c3,7953fafc,1fe7df85,4bef044b,28358dca,bcd82609,1a9adb0c,439c3a8,9f48152c,2a1951bb,4b70da95,3f3875c7,82650643,92717640,73f1a34c), -S(42ab6939,246a9574,185a1c12,89824dc4,87bfdf4f,bf960517,87a441b,5977d3cd,e5e24a17,416cc7e3,a4fca1f3,7666d42c,a8b19e05,28940a07,2630f668,3babe748), -S(8080c977,bc2ba584,bc40b6b7,50bec750,cf80e367,a45f64a,6639d15b,5fc696b9,e5e8290e,917024e0,5ecf369c,4e2fa4b0,76b19aac,d41f6424,7353a2b0,846db72b), -S(300d9c06,89570a8d,5066039,2a8fb68c,b84b6f7d,4629ace8,51e6aefc,5f88632a,ce1009c9,4fdd9778,50f2c2a8,f30732a3,253053ca,635b34b1,801844ea,90137c41), -S(42ab6bd7,b4a48239,3c17c778,ec1423d0,ed684ad9,41b0eb9b,ecf5090e,51a2aef5,bcd4f24a,9911df81,500c2a76,98d434e2,a5f6ca84,ab4d75c0,7b7f3460,82624b48), -S(34c3d12e,1dba4daf,aacbd46b,7a2b5506,874c150e,1c5b7f3c,3ecc3db4,b4234c60,647d9374,c25ad658,d5081ea7,ff6eda03,61cd55c5,3c8cc862,85a83bd4,17927108), -S(ed822bf1,85d879e9,94b40a42,b000b93d,8f3439a8,e1800479,fbc1c3fd,61a045b1,5e25f76b,5f44666,d94eeffd,72278034,e5414f7d,c12b3858,424aeb73,3b84e4a8), -S(66b6681d,683c7d09,963992b3,b7965df8,e152d1a0,f296a0e5,16160fa5,357c6230,306c1d1,a4e6fd30,2a9d6581,e9b1632a,56eb67b7,af92a8d1,4cbe33f1,c34f1098), -S(b80b913d,359a179a,1ded7997,f833894e,6a9f6e6e,e2d05bd4,aee84b17,13ec6369,dd03d2fc,83aec2ab,9cb999cd,82a015e,3720cdf5,a9016b35,178ece2c,a51e4ccb), -S(54d6ad3,34f5eb7d,cab082bb,e188eb7,185f6054,e3335e6e,200f8263,75b930d7,9c1f066f,bd6f050,3099adf7,e9fc7960,86353a6f,4ee8c25e,fda4bd34,81db0e67), -S(c782fad7,aabecff7,d49e45b4,495fa462,168fbd90,fc14bca2,a216bbf8,daf7f344,e94dcaa8,ac3a9363,cca59110,d42375c,988016a5,b41e64e,770b36f9,87eb23e7), -S(f8cea4a4,b451df9f,89a4e9a3,8f586d04,5fbb1640,3baa242c,4b12f7a9,97aa7b59,da610c68,9fd0ecb8,4b0fdaba,3c34a25d,70d0883d,3b686a2c,c3c257b9,68800ddb), -S(79a15047,b34dad08,500e67a0,8ba08225,31bea87a,3fea2b1e,223c2aa0,4d083e92,4e36831f,183cfe2b,5a6145cb,716ebacb,5c29c71e,2c76e51a,154db94b,8877a463), -S(c8d6d0dc,dd1dfbcf,e4d90d9d,8320f5cc,c9a141ce,7758df3c,a3252045,ea8f4789,f0275762,5102db48,dee39985,e7a91b50,4ca08125,b42de955,f3f6421d,62e29548), -S(a619ef08,787410d3,aefbea3,c6d53427,20e8359,f483a8d3,2f588d99,ece6b51d,f96dc23,1bfca372,10fc1834,8734e4e,28cfa3e2,fa5bcf82,2576714d,363d46b2), -S(1ef02ccb,45ef1e3a,bfcbe970,2f839ac2,845f7c4e,d1b2ec5b,46400db,df4665db,8aaf2a3,8dd2e57a,df53071e,4db215e6,a9885803,29c418f1,701dca95,e37f9ea7), -S(ebf69ecc,320d1188,80c6518,a05f824d,2f8be63c,77401447,fd57e381,76f52f6c,996e43a1,647c018,507a49cd,3867e73c,e0f82630,d36c9ea2,6c38bc57,41aa59a6), -S(1ec42d6f,eca86040,877404e,370d21f7,9497ad3a,2e527bc7,b6ebcd97,a5407c0a,f8180e23,290c3285,b8eda149,d26780fc,8f3a47a3,284ed732,e57e7c6f,a1629f9e), -S(f8ac97e9,a3c152f0,c71098d1,816011e4,644bbfa0,3578412b,6f03f5ad,5495cd0c,df74b06,a4ee84e1,a55836dd,6ab1a681,7bf951b9,cf163dc,70ac6cec,e286b13b), -S(557b9739,5cf5aba5,676ea063,1d404c9,b8abb95b,8672889e,d385bec5,6bbf5165,c7df864b,be165b82,5bc10790,20306b9b,8f3cd384,67edc2fd,bed045b8,fdcd09f2), -S(b44a67c3,4d85856b,62db523d,b15e1efd,b882855d,c63a7c6c,17decc01,1cbbdd4,d224fac9,dfe6f504,296703de,a7d67da8,6c530641,46823fe1,81d2c994,753d838d), -S(c9df9666,ea8eaf4a,14c8847,90e0e456,35db94d3,4d5f0680,b1727c8c,a863e398,10917719,32d9592c,fb272952,2c1a1cba,25020f33,95a6ada6,f85c92c1,996906be), -S(e56736f5,2c77db45,66bb0c10,46c8554f,444b829e,72be61bb,cb376b64,83e28683,2f32beaf,ba8a5aa4,5fc33816,ec2432c,9fe6c76b,172afc7f,8eceb879,f29651c0), -S(bebffbcd,bf56c1cc,8e42824b,ba8f0b4c,35cd732,d1eb160e,96a8ec55,13082be7,5d84e045,a5d285c6,be65e663,b51da6fa,acd3787,7748c439,73eefa88,88263df9), -S(c30e6d10,a518ff5b,2537c8a,89d2e447,c0d7518c,529c4dd5,b9575536,2d9f49f9,92da3c0e,f9ac9946,eada43f6,2d811aa8,26da78e9,849b847a,9fd0b0e,5e71d727), -S(65bf5bd3,ca8f5dfc,9a1799d0,357f24e0,2bcc4b5a,7706a454,3d08a,34512abf,7234a79c,a6c4598b,c2480b8c,5a5a8ca8,f343c41c,514054f7,42611d68,80277041), -S(680c6de7,ce4b261,3698ef55,185b7678,3d6ae7b,9587bbf,89995034,ce361a03,a22146e,3e025e43,565b5243,89bb57e7,6af1b740,7769be7e,6cd29b1a,1d472765), -S(83ffcd78,14a1455b,501381f2,523a675e,92a3a688,aef481ed,aeb0fd0a,14c37671,d780b968,b263153e,e1f5657,de678f55,6e43b840,e17e6eba,694ac093,dc9e8e7f), -S(b8c2376,6ef2d21f,5505b265,a1b27cfa,f0f5a59b,54b31407,1fa9ef5b,2457762b,28249c7c,25068a13,ce473b0e,896ece13,65a23f57,2626fb7,e5ac1e33,7976aedf), -S(99327a6c,b7606c32,92d98fb8,799f5f64,cfa4b0c5,4fba99ff,aa309287,d034bb1d,aa09fe57,4883ab5f,6b07830c,d5c12121,de3bcf52,68f8dfbb,37ccb8cd,61cfe55d), -S(3a9f4dba,2fd6493f,bbb21e8b,d36644c3,d4da0699,faf8029d,4ac7654f,380a18d,3c8c87a0,6bf2315,32a5bd1e,e44ad483,b44ada12,63d4750,6a55c567,7121fbe1), -S(65aff743,11534071,2676c7cb,2e5762ca,297acce8,535534bc,e495e27e,2b6f4353,5b11d44,8b7e2593,b8964f7,317f78b,5eb4d169,d968aa17,91259135,15087ba0), -S(457e7433,e8a8b719,e6e6b506,cdc1654f,574e5020,4ca22877,f36770ab,bf855eb0,949d5089,389f939,5e762659,53aec631,e369e8b1,38e6168d,b6528405,bf144ffb), -S(83253254,4261c8bf,b4a32676,3389afcb,9ee3d56f,44c70c08,e9e70bef,fbb092b1,3ebfdef,f0bd720e,611f0c8d,85028d87,8ffbb5d,7c19c3c1,e7a0832a,2ccbc0df), -S(98ec0257,7a1e4b16,369ffc2c,f17b0ff1,82af8b5e,25ae498b,e7acdfb1,b069e572,e2c72d87,67d16e14,44315c3d,9dd3250f,ee7c5ed,73337d03,ccb8a4d5,743537b), -S(d4b815e7,1e29d5d9,7e96c122,7ba6fece,60779b1f,574adc23,b53bc206,99c3ccd8,df98ad83,9c4a9133,d78b0d12,a8ce8765,61a3530a,29707357,65ea402f,72db0cfd), -S(88753aeb,3045bf8f,335a59a,9bd4287e,555a9005,5940a0d5,895b19a4,be237ffa,9740f21f,4abb4d3d,ae4b5f7e,9b5ab141,810ef2f3,9cf2d98d,570dcd1c,4d330ae4), -S(eae3895d,f081044f,6ea4a9db,73dd1300,b4a53f5,2a5429bc,fd60cb6d,733efd9c,4a9a829a,14149e0d,a629498,a3e03cbd,723d807c,a47a16cc,de5b9c1,a443995e), -S(752b1e2b,761e8633,7c4ec063,2fe7f626,e7038632,d93ce2d2,ea789825,97ea0d44,edeb1b08,a076b69,9fdbe919,e20dbee1,223c33d5,ffc6fdeb,36a5d1fa,4399b8e7), -S(9854c41d,104d82d,840fbfaa,d4da5b51,40c1aba7,80bafb5d,24646e10,a23f8a4,c170757f,23eb38de,5412e2ea,3a040c8e,cb10305e,69290c20,32e2719f,e26bd499), -S(81d720df,c9396536,5d977db1,410d4a5c,fd5078e2,21e368e0,5a8faf83,44097d1c,a29c17b5,518001fd,775afd10,693865e,d84cf3f0,f7bb44db,c5b3bf27,b192be60), -S(555dbc1b,7809b8d9,9db97d6b,c9c75ecf,4592fbae,3784e2a7,2150bda0,e9c8cbe8,963fb2f2,9277580f,9ae5668b,f31249c2,7429cbe2,5bbbd296,81574ae9,35e8d443), -S(31dd018d,28c81808,fce67b11,f621358,71be0366,b04d5f69,73b3f11d,df2b37a6,43837cb7,c56c10ad,1fcb57d,91bb293,aa91740,a8c5427,3f10bedb,560ac06c), -S(8c3e7d99,cd849afe,4c3e8ab8,af410bd4,3ee951ca,10307e05,4f569854,e8752d48,fd4d3081,69dfb22e,ddc706d2,36bb1918,7ab455dc,eb44e362,eea2863a,3f0341ac), -S(6fe0f368,f918ea70,b130864a,60e6541d,23daac99,49a28e44,597315f6,d85ad4f5,e30fdae,7c6731a5,ddfefba9,ae685a43,21619203,87b66a2c,799d84b2,f2d42c98), -S(f181faf7,623f82da,aa7730d9,56dfabc1,b4a662ce,c94282fc,dd3852e,8a43b91f,2e148d3d,9c470d9b,ca5be26a,5e191154,441d86f7,d6234085,203e944f,529e7256), -S(8cf18f22,23085bce,a35c8406,d9322ade,97eae156,4f741e36,2d3f57e9,e86867cb,e5123dc3,c5be133a,f25f90bd,de7101c0,6b2ebe44,cc83b7ee,a267a3a0,6a2c2b4f), -S(72cf023a,8d20a4fc,3ad5937f,cad6f47b,1030e02d,9ab0cede,58794a3e,f5c9c6dd,a2d02506,35402d63,85d0fc40,af954464,15fa929d,3dd95c,d4159edc,300fee82), -S(6c87417c,7e9ce90,b67c0ca1,469d91f0,98a9e67e,850ec140,fd489ab6,b4477ec0,7aaec9f9,a443bad9,89dd08f4,8d397d3c,35d970b,6cc9eba,df64513e,57227106), -S(54ffefda,eeb2a69e,8de97265,e8d7ef5a,576a4f1e,df7ceba1,7f94cb3a,a83a96ca,7d76707e,cf533f08,2c3e63cc,eed8cd18,9bded8ce,835a37cc,549b550b,5e82a3a5), -S(9dba00a6,d186dc34,a21207af,9aa597e4,432b8fb1,b1fbbd30,6caacbfc,4db25e35,259faa28,e791002f,138468c6,34e0c20,c5555b48,a1b8a35,6d68accb,41d8f7b8), -S(2728df39,afbc765b,38f47b21,6aca8cad,33b5b2b6,363cbdc3,3ed434ba,5c9201bf,de91b280,6bddbef0,562c02bd,7d7bd16e,7551095d,534a2566,9618539,5e22a4e3), -S(77a45f41,2353ddf2,d8cf7ac4,afeb1a3f,df6d20df,702e8207,f29286a5,c3558ba4,f1f5003f,510959e,93be5f5d,7d4f9498,70eea705,51b2383c,22215a84,8ff83fbb), -S(a0da4abe,d0890614,ba574a88,ffba223e,71163293,b4ed6df3,8b5b6e6f,997cab0b,3f542151,36570288,344391b,d3144b50,55545b2a,90e78b9d,20f894e4,2f43bff6), -S(202b20a3,c8979884,9a275f6f,7fcf6e11,4a21309f,2f340387,f663eea3,e1121028,35001416,97ae4ada,4e7e0b01,e9712385,ad971605,6e6c0cb6,c1cb6bdc,b12c3363), -S(7288cb0a,fb450439,2ce2867d,3ff3d2af,71344402,a7ec2198,152aaa40,9d85aa32,e39ceae9,6d3fb740,91531079,9770ffda,fe11434b,b5ce8213,deab8b43,c9426006), -S(de1e33bf,bf324b9f,dd8b305c,1d77e868,61dc6402,b083778e,b488275,1609417,bbcdd28a,13e3db76,e76f836e,93a4e54a,8550a389,5d02a03e,a99e80ff,cae1e3f0), -S(c88f921c,c2dc7aa,1b48d681,319a259b,33313e5c,c31ed767,737824dd,b99fb563,66ac4897,206652df,fb7224a6,771f32ae,bd75e318,21164444,62419320,d45f5e1b), -S(adc40ac3,97458429,6277e8c1,3f3b0e15,d8ab082a,e024f8ae,901cec70,36083690,f0497ce0,2c79352c,19bf649,4fdcb631,60c993b6,6d4c81a3,679a8006,b6e31779), -S(f72b6a10,5599d35e,4f5b107d,a2f9e8de,f1ce7211,7c03c8a2,5695af9d,d4a42926,41306d43,7d83913b,fdd51a1b,3c9cdbca,5d4082b1,756e1f5e,2c2851fd,b50ceed7), -S(f8bf4a89,b8577191,98efcac4,a695f9d5,d9d7f017,c9c0ad26,ce8301bc,575d8771,ea762173,96b1873,843f07f,826d6d69,e985d38a,119d7923,99b20484,cb20d8d3), -S(83523352,714c758e,3e7d1627,44e1fbe9,991b0c15,efa1345,fd9cd41e,ae84fcaa,d209aaf9,e7032525,e8f496e7,7b22011d,e20e2c0d,901e835f,2e64fd4f,d6b44e6), -S(12f7f577,31b61df1,a2f699b0,ae85b95e,92ae1fa9,7caca4a8,7b7cb6ac,4fc19145,2c52d855,505de067,213e3054,8d7416fa,ba042f93,27c21cd5,b47086c4,d01696e), -S(48254fe5,aae306d,54a14098,c87a0bae,4cbd0540,c8d36ed6,9c19abd8,ba0738fb,6f37a602,ce702d45,549ff185,338b150b,17bc868d,649ba4be,b99ff744,5ea70f3a), -S(5212fbaf,dc8a9270,fee8ca9b,ce872a3c,b875c3b3,202f92ef,b5327a4b,e466401,73fd045,69ed0d82,4169c191,8ee937c8,87824719,120996ec,11a9fdc0,ce4437a6), -S(855b8d00,c3f84266,6af52981,284b5845,36a06019,3b722fd1,483b8dd8,2880e0b2,5b494189,5d3c558c,548ee414,47327cc,13ca4e7a,5b8eb7ec,7d5da63c,7f89006), -S(49faaf81,850bfce2,7752768f,4808c91e,be1a8999,f4673650,52099584,37ce9747,6eb4c92c,a2235629,c90339f6,d7c5f136,a2329eaf,f26d6353,da9d4679,f07f8db0), -S(57afce1e,5164670a,7b3a8a8c,cbcd7261,a8775833,1f74fee,7b541174,9844bb5c,452fcaa0,1237bfb9,f3d97bed,4eda5fa9,ed72b580,c2b95953,8eb227d5,60252fdf), -S(9537b024,4e19fbbb,c17e42ec,9ac4c5ce,51fdba4f,51e7bb28,ea53ba77,661a8728,43153797,f2b3c74c,ed3cfee9,c9609683,36f2876f,2332e95a,cbfb6d5e,84dc9f3b), -S(bc816077,c64469e3,a663409d,5e175b45,ee14adb1,703e2bd3,7692b38a,31d49c6,7f5430fa,11e07543,f781482a,f95b30d,d58cc8e7,e8107b6b,54f314c0,c8e77e64), -S(dd03731,e07f5b55,3178ae07,7df0930e,de774e47,3e52e028,b7f39a5b,583f1d1b,7cdc1846,fe08633b,f9fa470b,7710d02b,8ee07902,e38290f5,788094a3,61174168), -S(132ba7c,e36518c9,195ec6e0,cf3aa576,1f0d3b76,d2124fc3,b43fbdf9,bd196170,7b59d248,388297dc,9f72b75,b8aa607d,327cd873,8be5c1ff,e8e035ba,611d599b), -S(798b3663,8f3758c3,93f93504,9584d055,e52f9cb9,abcab568,477f3265,68f5dd80,f270bd3c,5b236c6f,92bf2937,5ae4761e,1e5418a2,716326a,c62707b8,617c2f1f), -S(1db26d05,f64a6f1f,4b6911b8,3cdcfac1,bfe57344,7319baa3,8a539fa8,dbae42e0,8185bb2c,8d009b27,c7edb12f,d1760a13,e2e97747,52c3b961,48e7cd0f,2c0ca28a), -S(53600f43,411155f9,676fd005,ece88e90,ce3f68eb,bf9f418c,b1ccd460,94fb9013,e87314ca,ff3457a1,ef3a12ab,3e8f7a54,b80b7e81,91cf3378,cbeb9a1e,bb02caea), -S(31445cb8,39f9aa76,4fd46b4e,b39f0fde,18178467,81a4b1df,e9523dd9,9c37a732,58ef4007,d56b3ecc,cf08f220,d5b28cba,d9e6ef50,cf878166,9af25bd1,16239ac9), -S(3968d2b0,80d50365,b4df89e3,a50ed48c,fb41f5f4,630a1fc8,67a072cf,36775c4e,15da358c,9a674846,3fb6d243,8e8569fe,4d9ea766,713ad5c7,15461485,c876f215), -S(a040c7fa,1ddc8d42,efb964af,ca365776,99f200e8,d23cf93a,653cbfce,ea24507c,7bb2fb2a,57f4749c,83f696a1,4c974781,8af4ee58,c42c0718,1fdeb867,f54121c3), -S(2edd58db,873d3d57,42bc774d,97ea6197,152a57ff,b0f747ab,1d26f577,b8cdef89,82ec3302,ed5ea5bf,79e696e1,d67d762f,9573f895,ecf3a891,755dbd61,c11a7702), -S(b519f379,8949ae1e,1138e3c9,9a9486c2,77f44ee,1f9aa34e,b54a34c2,6f394313,5786b86a,7913b9c8,e38b6bf,2edc278f,2d4807ce,834c30da,ac3f5222,7af4a458), -S(d3be1b71,d03703e6,194d5ab8,ceaabdff,4a970fab,60caeebc,13ffadc5,3f973757,176caa0b,f46c299e,33e5ff06,294bf813,530cf048,fdd0d98c,dfd3e9a0,a42c33c7), -S(85a03707,c13f7b49,878abf34,cb77fba0,62d3d1e4,2b00f7eb,6e159c66,48290fbf,487c50b0,c811356c,499ee9fb,5fb78a84,98d70194,62a15417,c0e883f5,6baf6f45), -S(fddca890,694d87de,a2e0f92d,1e9b9e9c,7420b4da,bb5d2a89,3d282dd0,53d45a15,8a896375,7558132e,d1137feb,fc9c9c0d,4e6a6de6,1e75a8a8,ea79664d,893dcfbc), -S(d7cb9e4d,13e2b747,6f91a951,2aa93ce,c954a542,c6acd5cf,ad65bdb4,63071664,2880964a,13083d03,8755c9eb,9c2c8f57,b68660d4,a5227ab5,261d6ae7,c9ba708d), -S(98f619e3,76e7bd91,f5387e58,b57ccc84,90a6fd68,1a569cc2,caa253df,86b6959b,59d49098,67b3c6b9,8ded8edf,a67f5c4d,4ec7e,8dec78e2,68314f8b,f941867a), -S(35f36793,f5dc6d0c,c8adff91,2db459c5,dd405272,ce45031d,bb118383,d108519a,568f7399,aec63e71,9c63b0d1,480a9afc,662c8920,4bd7ba30,71b0eeee,ddf3ac2d), -S(c7e043b,b02f15ef,689666b3,8ed29704,a5059027,ae23c3ba,f75a2a90,642934c2,cb5e67d,551e180a,42274149,127c75ff,2be6113,bfe56f46,47008ff2,d6b72578), -S(cf95cb09,19655249,f16bb911,9488af73,c74ff5e5,e508e322,2a044f2e,1fb87796,d476c517,3df5b269,889ac45f,5b095db4,97c63334,ce233da9,4daebef9,aa2b88b5), -S(b38ad8a1,640c2aa5,b77db077,8a7ef7b5,b9795e36,20612fc5,e48c3ac,6fcdeae4,5e97b2cb,8dc7839a,d1f80df3,a9a7e203,140898be,6a6301ee,c3aca617,366edf66), -S(d39404f4,c9e59b56,41fbe43,c0abf3ed,4ce9065f,6d4d0224,b1cb1b33,aa97d3b9,573e8e27,44903ffa,8e1efbdf,56d3975d,23bac9ac,de0f758c,1d018e7d,d049e49b), -S(9adce43a,9f603359,5424daaf,c0ae565,c468df8,6beb9b49,ff533af4,496fcf32,e2cc9853,af216c00,4d71949b,c55a2c44,38655847,75cb2d00,ed96c5a,6f143f01), -S(66d1438c,8c9202a7,aef7d11c,682fed36,b88d5978,d7611a06,5d2ec2a1,b5aa8bd2,d1cef3de,eaa43df,617a7fa8,3a22fbcb,f8aae418,5de59e00,1e11b37c,d34cfd05), -S(442be1e4,c65e3e33,db17ed63,d852e62b,f8ff33d3,589a99c6,8d2fc4b4,dc8bfaec,63ed32e5,6bd86b07,6fc357,cd556c62,22402d35,5272f42b,a982a496,1f7889b1), -S(9c80efcb,da724a78,f6dc4de1,618b0d39,cf383c6f,d104bdd,2476147e,b6fade3e,102a9767,4ecb12be,71aa53b6,b0f353e5,6a06f1a7,b14cfd31,d48993e,4e766b86), -S(a2d10bfd,bd01700f,1c105396,bd78c7de,7baf91de,ecabc8,94938ec5,b4d99951,4a7db817,c4ce92c7,eacfc287,91992398,3042412b,ab017689,9c4113ba,6ef4bc3e), -S(847921be,b36c0615,ae10e9c1,b9791adf,667d1896,3af938e5,365eedd6,f888ee92,c4ee9b79,91ec9eac,9c08ceea,f610ec27,b3a0be64,6684b3b7,8ad1c17d,380d99ba), -S(60d7dcd6,879f9c5,6a44cc9e,26f5a5cc,6a6500ba,99fbb676,e5992457,e611b840,c4128d09,7ca3a257,113aa74c,29f063ff,52e39bd8,c8a4bd68,4c822cd3,386a652f), -S(e3a4e2b0,5d227414,38ad53a1,5366c13d,7d377dca,fed5be5e,61387448,1e3cd263,fab9bc4f,12cc2130,5b0afc2c,275cf3c2,c12682e4,1c772776,568f6219,63fe9c5), -S(af13018c,89c75180,af73b61b,5ccc891e,b42592d0,f2345c39,926a0ea2,402d6e87,eb122961,6a01567a,1d69034f,e8ca133,136694b7,761f4500,25754951,c9e38b42), -S(a3a7b943,c5304cbe,d736b95,fdfc2283,f54164c3,bc3d186e,7b017d1,dfbf9464,7b779d12,909078fd,9cccc9c6,73afaf1d,bd206420,44f941c0,4a676aeb,e2eefaf8), -S(ee99d382,c6f590c8,a9e266d9,9500e9ef,cd685630,71052e95,28be0aff,330e5476,541966c1,1cf15028,a6448de5,5837bd73,6aa11b70,bdaebc1a,1e8223ba,7a69d146), -S(142ba015,699ffb3,e6e02bd6,aaf084e4,3d100421,c5aad92c,f636691d,dcaae138,94fc5a5c,cdb79bb2,1cb733b2,50a0d4b5,cf37cfb4,75ae290b,4c53cac6,43ca7aeb), -S(75f254ae,9f98f3ea,17d9e574,5820a2df,16ef6027,d85ef056,75790b92,b345a144,63a94cfa,2b289f55,300729ce,77f9a5d3,681b944b,90719028,cd8de938,2290137b), -S(f6db52b0,1ac4f26e,80ac7f49,fc81cf48,9ebe7df9,d2085d2d,e08cfa7d,3883627,ed4006,f6c6d8c5,2bfc2fb1,8014f69b,7fce7868,7c0217cd,3d813faf,8518152a), -S(5418d34c,61fa1981,be925614,c56ac5a9,651b90b0,367cc6f0,23f4ad3b,3455798f,ec800abd,42af6eae,3584abc,cfccc4b7,14e98700,539ba36a,925da30c,ef57ebb1), -S(7ac961ec,59031427,8bbb04e4,4e79634d,a88f7cd5,d26d6ac2,a6605273,7adc5c1f,5ae54a73,cbfecefd,5574b29a,4ec5aa13,1912ef14,491ea386,85ca63c5,ade7e914), -S(eba2daa1,67aa43b,9d8d1ffc,b0784ad0,8bc563f6,243401c9,79d13396,bd9351f6,ece65820,bbe5bf06,6300f1c2,e16af4a,4d05263f,f4da582e,9e3892d9,9063a1b4), -S(bc674e6d,62757b5c,f079229,8b624c93,d1765e8a,44ce9abb,84047873,c62cc601,8056031,468638d,251fc37c,751580e8,29dfb130,f34c7f79,31618d3e,8c3b0ac7), -S(d76792aa,b3dd3405,45cd8374,958ee104,86b08dd8,1e1b99f4,c02b387d,b9cc3c9,63e21256,6b92c21a,378ce4de,cbc28dd5,2b563106,cb5afcb6,95f2aa02,fad96eed), -S(b0f0830d,80cb007,8c8f84b0,d753b059,6dc0f1a2,456cbaf1,bff5716c,158eee33,7d229908,b8acd65f,62a4c9c2,aaeee8b3,a1355e40,492552ce,1283fc52,d512fa4c), -S(86ed6a70,2cfbaf34,542ce456,b589a492,c9e19b4d,b18f4a73,3f257e1,2902bb3b,ecb26bfe,700e06c6,598bdca7,d0eb97c9,5992e438,c6d490b4,b2907af5,3850ac79), -S(fc88d9be,fe183b9f,3d952f51,79d0e2a7,2c56b79d,2a3c4408,948f4887,bf5b6113,c8e6d8a,91329b9c,c197c41d,8f2858c0,eae74ee4,5fe259ed,fd93bba9,fe3cb7e3), -S(c4e1983d,e86d3856,5381dcdc,e11910d9,2c96700d,a67bf713,3a6bf601,7461d444,39af034a,a1f8caa0,b01e4a32,2a8ae84,8e93e9a6,9c97fc9e,f8e8df08,2b211e3e), -S(6dd8075b,4456919c,bc97417f,7a94f6a1,bb9c07fb,8ed54986,8deb955d,bdc65eaf,bccb1ebf,57a86b87,2119eea5,17346eaa,bdcb5fdb,b3a71930,7bbcaf27,59781a9e), -S(a4ef5a0d,1e9a65dc,f4310820,4a2ec8f1,72aa8a8f,71604c8,39b026d8,a3a3983e,a7d682d,c7dfc382,a67678ee,12eae6ab,b6cfdb1d,7646f4ab,6c1d9269,1fbe338b), -S(9a250997,84509b90,f17c29ad,2bb39ccd,42e3147c,ab53c2a0,a739a65b,de4814cc,fd746694,ae6abc3,6898bf52,e0e6b3b8,a63766e9,d2dbc867,3f9b17c8,9135e4ff), -S(9e7b2662,58b0b90f,707211db,a9d4610d,4f49d08,c553dd00,f58c242e,2082c095,ac8fd168,bee47d4b,c8b2ffa3,72fa3ae2,657c435d,4d9f4da3,67c8c232,6d4b9820), -S(65646ccc,5f53bce3,edf35c57,137b7f5d,a49e385b,f101c5c9,b6182035,c45e0e0,6ae3b77e,cd3f9837,99287240,6a70ef79,c3dfb8b6,c3704f3d,9ba248ff,e6344092), -S(15ce9fd4,a87cdf9b,71e435d,b2148927,7ebf17f9,218d0d57,af3c632e,e227e2b1,47857e6a,2f5a9710,2c082dbd,d0edac51,65d949bb,cb9a325c,4f164958,a2413534), -S(ff44a162,2a259be3,512f234b,dee87a16,bb9d7739,cb84e527,29d60fb4,4d073fae,5ada42a4,9190f1cc,e16cea1f,392b01ba,89969695,8926f16e,f7aac2f9,a9cce2cf), -S(a5f68def,8670933d,907d508,185c3ce1,a67c62c5,33c3d65c,3c199d08,33536f99,d859eb34,2bd36baf,7e9f36de,f1dcb7c1,db6f0e19,12e7c9fc,2799afad,d210fac1), -S(4666bb71,c1e24ae6,d6c0f9d3,5a100fa4,309f30de,cc4c4935,9c937f51,243571b5,aba13ddf,96be4e04,97e758b9,d0532160,cbe62077,78297e4a,30a2ccd3,459c9e36), -S(131fc338,b0acc38c,b817a182,fd4919af,8bbaa00b,e0d80ce9,b46c50dc,8d7e972d,2761b62a,bada1136,4bc7bc3b,4fe7c0a3,b6d8be3b,d05bb3ed,dba2a071,188812b4), -S(5232eae0,3b377985,7e57c34b,4f9ee30d,a97714c0,bf33b63b,d520ec60,9bb18557,c243b06,ae8404cb,a01ab038,da6b8708,ec6698ee,f6d0f555,85f5e0,6d8b2330), -S(e95e4da8,afbb1484,ea1bf378,642ebd59,de13f70c,53f2b470,252eaf5a,c01823bd,dc77ce77,688e13d1,4083c7d1,d91fefc6,bfabde0b,bde46657,d3080d15,51cde44e), -S(9f3a7cc6,759db98b,f6b45257,8aa1a8ef,a2601d64,64028025,ddeec5a,c6fa8b6e,e5db2c3e,d23f72c,47d9d5bf,8bdfbe98,b9a1e97b,57d8a9f9,60f10fe9,8056a4c7), -S(96981f2,a1e0c0b2,1eab0a4f,fa56283a,5555bfe0,75ef938c,66dafa26,8f41d946,ae191f21,841ad677,420a77d6,ec440baa,c1426dc,dc2449a3,eeff6f7d,94e4f012), -S(d805bbe3,a8771fb3,3a22c51d,d73ad400,f7656107,3767fedb,3babebd0,226a1244,5bad82f9,ed6a1a7d,ca0532b8,87c7d7fb,1280c05a,f461321e,9065e11b,5c7aec51), -S(ae3b990d,32ad44a9,874da8f1,79e4f7e9,fca965c7,d7281f07,1df80c63,2b9dc432,3810d68a,b5cf8ee6,af08c822,d922621,8197cc39,194ba913,492064a8,5405a346), -S(69fdac,1c5be33e,fce9fb73,49f936d9,ad0d9afd,e1df6d00,df6599bc,4870b6bd,2fbb05fd,3e82f2ca,8c0340e2,d43f0d99,98f12f1f,c433046a,52aba97b,9d30ff3b), -S(1b0c0ecf,b0e9e6b2,238ee645,e33b44ef,5f102985,77df53e9,26fc2f82,d1aee964,9400ea2e,ba2d25f5,2607b213,8b30475a,67e5dbab,bf8e5ca3,38f84bd3,947adade), -S(7e2e1b2e,8f69a883,9d9e3993,312c9bdd,78a2390,251d4a1c,209b0caa,47eb0171,674c4c18,e61fd02b,660ec735,67fe7340,591c2db2,924c9430,bfab3948,d3a84eef), -S(d42acdb,d02a6a9f,da7f9d83,9d8c240c,7ae50331,3aae1d56,a0e1798d,8e668ba5,2c54cff7,bda5ac87,3d044272,b7bd52a7,dda6a14c,c9bf9e07,3b0375d6,6489e70c), -S(6a746102,1f9780c7,5eee2394,823354ae,cfdef6d2,46892b1d,c7150863,1e6f4c93,f7957ef3,1cb47e0b,9e3563e8,1fbe69fa,1e687e2f,3e3efe50,d21cc4b7,26053d29), -S(ad164b38,d21a5211,84b6d47c,be01953a,5f5b8a97,7f0d5888,b9fd9495,691f2749,5709a9db,404b1a06,5f965af1,7ca7a2d7,f036f39c,556af11e,9a0a7340,52c2b5d), -S(867099cb,84481d32,d9a4f46e,2e3338cc,9d5f14cc,f65d97d8,441fc8be,38e36296,8688faf9,7a3eeadf,8a42e884,3e0ac108,90f7f417,8620c0b0,49d13e44,9190ed8c), -S(d52d12cf,3cca7ad6,ea0ed7a3,92c4da04,8d31e279,63b1a9e9,ee5e9d07,b3ceb2c6,fce207b7,1aa22562,2f589efb,750f984b,b52208a1,6c07990c,768020e9,9711a80), -S(da5ccb53,c4c46a06,1ffbb2e,4814520d,ea373d68,1d426071,c9ca49c4,db5efcc7,28b00c21,4cf71f17,601cd24b,4516dd20,4f12fea6,c7fac2a5,43a2176f,1f150aed), -S(3e8a38b,505d7916,8e518d17,39198d6e,65139b44,edb38001,72a92b0e,410c4174,f7b82a9,62980288,47e06c3,e51e1a6d,f2ae9cf2,e2468e01,8ef79534,a8d6e0b1), -S(42a6d29e,4952ebd3,7169a99f,fa59742b,58bc24a6,c861dbff,ce79346d,78b7bce6,e6da3768,2124c365,878d577d,d1358dd2,b39a4bbf,e25f8bb3,dc97a533,c40ffa7a), -S(728aac39,15d078d7,4b687a75,6b166e05,d9636a71,bfb1103d,aa78fd2e,b8f22519,db2159e2,a71d66e0,e68e504d,40d60bfb,34f8be08,838c1435,f9018ea6,bd88c876), -S(ab5218a8,a7c5ef3d,f7538035,a1812787,f6cc2019,798935ce,92d9fa34,be65f3d1,fcbb8182,d8cc462,7ad1082,795c7b87,3932e97c,6bbaa7f4,2af231ff,67dc7b8), -S(e655414,ceff2752,990448ab,9159c7ae,50490932,a356bf80,d1669a6e,ad808506,cc0bf966,9915d938,219c197d,37762c8e,491d7cc9,48f1c993,c4406dc,384018a8), -S(9ee3eddd,519e44e4,c53bd4a5,f7101964,ac47a421,c72fe25a,96f79516,96c078c8,31f39cb9,f5441d,613eb470,5e9ea328,ff1f0b74,3835e7a0,f9b6ab5b,bb9de8a9), -S(dd7893db,e0028143,fe5739a,832e4aa1,ffecb200,d13f7b1d,a4877234,4330c15e,a38052e6,e03f06ea,d3c3f712,964457a7,52c7eef0,ca315f56,4060022a,66f6ee3e), -S(e7ab0025,d07507c6,6cd34270,8c0a89fd,53195b4e,ff3ede18,69488886,9eb91cc4,caede34a,6f8cda34,77bacb2a,935113f5,93b69979,18102777,bbc26128,9b0cb112), -S(47f608df,6d649b02,e55fdab2,a2bb4743,2986b9f8,61460cc7,c4961f51,89b57e91,179f29c6,6dd174de,bfa95876,22434b35,2e48f45d,658bf7af,d26a19a3,50333560), -S(3015cb0,87376de7,a18e7349,556b2351,72f27f37,e3a217ea,c7a43762,bd3e57c,a2e673e2,6b0f1888,14cffe51,2ff43eb0,c241e239,1f130630,dfab55a0,e12c844e), -S(aa7f171d,463433c3,93139c76,71d1a0cb,8b7745c4,3f3b1f1b,1669e3a9,75120ded,b8c9d145,9f9e9651,bee3a7f3,fdb71bb0,6deaafdd,1912896f,4b6a0e74,6869144e), -S(1847e63b,ca44c694,9ec3ac84,773af743,337d2dd7,46b6c5a3,ea9520ab,5af25469,ac19fac4,e3dd014,349c44d1,3436cb8e,465a754d,eb3f3c2,ae71eade,6c5a067a), -S(c11064d2,f638bedf,f762b481,719c85ca,7797e913,79cc3d12,3137ae2a,7a273179,7f74f429,8b47a566,bd3b6eae,80b47dcd,38e8780e,2ceb8833,dbd74462,c8f3db3f), -S(de6928c,f298091d,d1a42817,22d8923d,de25c954,ebfb273,80e17943,c641cbee,b02cffb5,47247542,be586c6,e88536dc,f6882d91,e76aa7fc,8769c2b6,5c585cd6), -S(2b8b1dc9,f379f2fc,a30d1f28,7877b47b,42f04b20,214c0beb,13aa2d28,83c52d12,1f660659,b7ea56c7,edd02c57,d6daa12c,d13671f,b657dd02,e75905b0,64d51d81), -S(90b39618,3eea7012,c537b000,f5f1ad28,e0416fe,6b1b874,effbfbfb,b963be57,bf37d7fc,ef9ca5eb,6b9886a3,b6b87f3e,976535eb,31cbc0b,464e69af,fefdf9d), -S(4fdfd77c,a033de11,59fc95c,ae07cd03,c570380e,ad2a376a,957bb26e,89bd4a8f,a1b30601,245aef10,ee891ce9,83cdbc66,390baaf7,b9c833bb,ecc34148,79f6a866), -S(7e2c3510,9c0a3eba,7b8b9d4a,c3c8d1e5,31304e45,25404814,fd66c3f3,3f12a1a0,39a8b59f,ed4d9d3d,29d8d1c3,130c1fd1,dbe7f2ea,cbc0770e,fa18e76f,3322a107), -S(4b80ce19,a7101706,b4bcc308,a4cd92b6,f8177a97,e2b2b6e6,1ebc2ca5,32c4b48,b72eb80f,55486930,94c8bbb7,bc6985c6,29c85d10,aff7d243,e5ead021,2b44587b), -S(8b07cf,264b3d2a,21705a59,dd82bc7b,573508f0,597831e0,336db2c5,c3702e3b,1b992b9b,8fe1a29d,d9781827,edb8ec89,49f6d412,12fe7e24,212f805a,4c4ff0ed), -S(3b65c4e1,d3171be6,67b01021,55644627,d64f9375,bc36fd3d,2c2a4fab,47a59e68,573fc9a9,1a09f5ba,78ed796b,496e1d68,a3f529d6,d0a77095,5ad16baf,e7b1e047), -S(baa6b559,e674ace6,a0378536,8643b0ff,42d8ead5,1c8d937a,7b1de152,62956003,eac99c3f,696ee584,7080f488,3b112c7,f6c69b2e,61a6e20c,135f5933,86289a3f), -S(e6453682,6cb25506,4107be9b,b0c2c225,5038c11b,96226fd6,5f8db8ce,70e32fe1,f74e605c,71912ac9,5e2399df,4f3ad24b,1c3a23a4,4b5ebca3,5ab8f31c,737d9aa4), -S(1aee4f20,a2db8e58,f33a8eaf,4a8218a4,b93212a2,60aea21f,64acfb56,3c8c5e83,3fc248a0,956a3136,daba7450,49e6330f,845ffac0,c2ed2f93,36ad1862,eb8b331), -S(8810ec79,33613ee3,49e0dba5,4a8ae34e,67a01322,46830eb6,41dea38d,c47f5941,c9c15ef8,c6a57a44,e9ea1832,c1c62dd2,c8aaba21,48d2153a,6e5a9001,281a273a), -S(cecb3ed3,a3380083,c8217e07,4cc0473a,3cd2c9f8,1ca8bc29,4494b01a,fa1bdcee,8ea11818,8b25ffcc,7d83039e,af605c9c,4132c83d,e97cb207,ca83f43f,26a557cc), -S(ea24fc58,d19415dd,aa780932,f7fded2b,e88987f9,9387d43b,24773ba2,1b810bc5,5176a2d7,a5d955a7,6452bb2c,49048329,b83ebcf1,2f3433ec,79573c14,4446e149), -S(facd3728,c43fb0e1,7f03a1ae,a7997e47,615706dc,3427039f,b994e14a,9a06d7be,ebe7826a,fec22f08,3108c710,9b944cb4,c4427b62,11f1f85c,474da8b8,25965d11), -S(439fdac4,66739dd,82c29854,fa9d599b,6fae190b,18192065,8a6cfd7a,1cbc9a5,f8bba187,677d0d3c,d50ee132,3cda2daf,d75aa6a6,1fca861c,2836d096,d1e3ff39), -S(167491d1,34593c79,6cb90f5f,868cea3f,56ef9b1d,e36a010f,a9d90eb2,9818d9cd,38303727,58f84ddb,ad5733a9,ef131555,14c314fc,4749efa3,4562c441,201d506a), -S(31ae24ac,8a76f509,2b721ef5,102623d7,eda96598,84563c1e,8177e3ec,6abf6ae,c3dfe7bb,c8017a0,e2f501a3,c5f11e04,d5a64dd7,ba2d0ed3,2082b7cc,fbeb2e1a), -S(b51857f5,526b8179,3e7bc5ec,7b74062c,57dbb146,1fe68d3,48dc3d55,d1c2d66d,f4313526,d268b372,5d1368bb,d40ac55b,d5f43377,de17bd6d,efd8f536,7c346f3e), -S(ce9c7eed,356d5ae3,b3334031,550f375d,35cd6e0d,eaa760b4,aac1141c,bda83df8,560b3067,c53c8f79,5916c5bb,34d99c02,efe4e5f1,f4cb47c6,f0662aee,2f07807), -S(1a9dc184,362a2f5c,58c53c53,160fde7d,f7b4c64a,e9753b7d,2d98be7,8c91cb33,bf4f3c80,8798aa25,bbca244e,1a070a57,c2ea26a1,59ae4ffa,84a4125f,c3b1823b), -S(3b3050a0,724a3c3,746e5bcd,832799cb,875758b9,2302eae4,82bc3c22,f17cd341,be5afdd,5fed6544,23bb069d,6dd96cfb,1b82cd9e,14dcb35,e0d7333f,54f924a5), -S(a4493930,c44f988c,fb634d59,5a0defbc,b6e9b809,133c0925,5c8ccc06,b93dca40,da27ecbe,97603604,2a559942,7176dbd4,fcc95ada,beedaa43,e40d5ec3,de5c4770), -S(47667272,59f47404,5fefe2ec,7f266c25,f9583c16,ca8fd4da,3149e8d1,bbf7dcef,526f565f,caa55541,d31524b,e942ab80,a895d270,a8cfdcf3,99dca02,75cc0f0c), -S(82715959,aa92d89f,91a7f53,af2d7e2a,2a3e8b85,2e30003e,caaea68b,774bb918,85188269,f1c8e6b3,328f1e04,1e4b79f1,8345dba6,49541f76,30dfd9fd,c1957b9a), -S(caff710b,8a246b27,1b7b8cb7,aa0eea69,3a1ab37,e58612b4,efbeb2b9,f1d4c1b3,7d20c6b4,5cc53865,7485ad82,43e7757,131528d3,ec134a13,b009032d,bae1ae23), -S(6270f6ce,665d2b6f,7d6ebcab,f556a681,78da916e,86b543c5,97771fc3,bee9efa,700f4b6c,b1487e66,af0ef5e7,9e98585e,b22c8e05,66cdd93f,db0e6ac2,809c4271), -S(f5d502e0,33d809c2,32f5eeec,bb4fa68a,97d5d231,6e06442b,2a3e5bc6,fcbdd6af,e802e5e8,ef9d6c91,ee5b858c,f6d62ccc,302eb555,2529cf5a,808dce72,14e3644c), -S(3a0482ce,c7c453f9,6a4d6f35,d8e3e51c,5f94b58f,a68e607,fa09cd44,ce09ccb5,fdd0d694,5601b9d5,437e587b,ca0df637,e17e7ea8,cedf9a6a,9f6f164e,f979e523), -S(54f22100,7ffff6d9,d5886947,8f164fcc,a67cfe3e,65986be4,bf9bf65f,8af89959,3b9af1d6,9036d3d4,6a6d121a,9653452f,61c3454b,2c786fbc,c497f0f2,e0ff792d), -S(7049ffd7,46bff6ed,c29f2e5a,d3dd5397,e96cc7cb,a1c30eb6,e71994ff,2036fd97,6e127611,95338ac8,ee94c953,5aa13afa,4f79d1d7,63994baa,e932b468,729501db), -S(f79cc302,7b4eb747,a7d67fb7,b1bda0ae,e47dae79,b410a6e,dcfda1c6,8c69b1f8,81d75d83,a5bc0e36,25d6aecc,6319120c,1c8df3ee,eeaebdbf,50ab9629,47715a9f), -S(fa0fba16,15c8c22b,3895ad47,8a8e2ea7,3438092d,150c86c2,8527b38c,2077a9f5,5f351702,7e1a8231,1eedd70,4cb519ad,f550dc64,dd1321f,705fa6c2,54a18947), -S(49b2fedb,7acc5ed9,7ab5efa9,e5b35377,b8dfe602,a0fa8a2c,5294abd8,9768aff9,f6b7325c,29f5f6b4,f3b18c9,366a85d4,60df8b78,ace02604,8af1cb1d,972e4042), -S(3623f1ae,9e3bc23b,7e9d758c,4444489,c3d9477e,eaf61b08,37f6ed,b9e0978a,f2176087,f401aeb1,f245a2a6,962afec9,fa7425c9,25cdff19,d137bbd9,f756885d), -S(67ada72e,262c36b3,cafec765,ec0209ad,c926b367,e5b8730c,b5d4db5e,37741312,7b1d7d71,511d4b61,450f847c,242ff70f,9729b2aa,c2e2d97a,4083e7a9,c07ca08d), -S(aa61ad71,44db1e8a,7d8a2f4e,80b471ec,bb891cec,7d16a8de,99ae20d7,9a11d00c,b344fdaa,bbaad87e,56d9093c,2fdd0bd,59316f31,2dce7a6,344ffdff,84ea71fb), -S(5dcce9b5,ba254153,bf270d61,494776bd,84f7be8b,f6a6ec2,9c2e3189,98e243d7,cd3b40e4,6bb08d2,5797da0a,6afd9066,63211e04,fba739aa,6e4f7f1e,d3068746), -S(8fbd32e3,c91dc619,ae0863ca,47b95a2f,3d8ffd91,1e41ce5c,b9bdf529,2504b1a3,b89f6d35,691e8155,703441de,b0d2d726,83247df2,ea46357b,ef5676a9,e582f29a), -S(dd31d01a,7af2d173,ba0c5c1c,ab7e59ec,cf8882cd,47904372,45d8a786,d1bd3480,91b2ec5c,59193d1b,1117763f,8c913d87,af40f6fb,abe53ef3,3e7548d1,eb211155), -S(1a9b64a2,52ecc6b4,4c17f134,cf32dead,66e4344e,44c200da,8c261d76,838a775a,1a2b618e,e96fc285,6be86b09,fa6caf61,4f7ee3ce,3bc34ce3,72c522e1,4a95905e), -S(ff9613fc,de744879,ce9a7c85,11508428,771d9421,b760d75,39adc805,61db7678,9a736730,5df91c31,9711c882,ede59e77,c09e2c6,f8b05232,2c0f79d2,77a4ebf), -S(3f29e50a,f584e0be,71247373,be4e9e33,8fca36e2,28f8498,ab57bf37,31deaed,b41490f6,72bcecd2,7c45a524,ccec1502,8186fd1a,759e4ec3,ce2e4a4a,abcca36e), -S(66457fff,d8836522,26260eed,4d00726d,ab8a56ae,26c68feb,f6ed99a3,ce782963,511b11cf,9237b49c,ab1bffdf,681f59ca,957a8182,ca2827b3,6cc962ca,d2becb29), -S(cd369d78,9ab5764a,a42dbd61,7fa711b4,757b17ba,fbf012c2,17a30cd8,dd42fd6c,42299f3b,674dee41,655ccb47,7783b8b,e54e0ca1,ffde384e,dd4cebd3,283196e1), -S(ad9bb10f,622b22d3,7c25ed15,323f1675,c6d12016,3f059469,6a8f508c,318c045,73f1883b,ef27a26e,a2dd4ae4,c399be8,2101c1ef,a6e67dc1,77dc343c,c56d66db), -S(2bf2ef32,e0277bcd,5ecafa49,910eaf8b,f107d591,fd0fe0d7,77b1ceea,c600c42f,6b8dfca5,f91f53fd,5fa8ae2e,53e72c95,9823c44,d2c4e7f9,7badc1b8,56e6fa80), -S(e7498183,bd8f01e0,c272e36f,1581c1da,907d7b06,8e3d6cd0,3d80c051,30dfdcd9,409fe739,b7f28ef2,4b94cc71,8856c99a,e67aaa3f,bf3bc8de,d71cc22c,9d4e4911), -S(b3921311,72c00c5d,fde1ed00,6aa50d01,9353bd2a,9e27afd8,60a71e02,123e7887,486cb8,d742f42d,9e00b8,e82083ef,bd1b8334,9babb4c5,a3a85c2f,9441fce1), -S(6cdd0e5b,edda536b,9c747302,4c3a8645,ee929f54,ed7f23b9,7a1cfd1c,77489e24,b190166d,b0ad70d9,f0b422f8,e5f0a0ec,91bd9cb5,f8bcdfbf,2c7594b,71c19e1e), -S(51bb4ad5,379c8dac,c5e6e19,6735c84e,9dde67b8,bdf4457d,35bf937a,3d726a8d,49bcb2c7,a0d6af45,8544b9da,674449e4,c099a56f,d0dba507,6b02a9df,5ce294d4), -S(c57bbff0,297f3040,3b81de70,fe524300,5b7456f7,997f4037,f6206e0c,277c74f0,316c5ab3,95b66038,ec5772e2,7aa2f7b5,b54e5511,6ff35e0a,5c4aa11c,efa8d05c), -S(ae2607b,d956ff85,12b5554c,b188978e,e0408c13,82739be,4e68b9d0,7bdc45eb,294424cf,51378200,ad3eae19,26f89a73,ec3398ec,8af9026,5ea556bf,83833a27), -S(95671646,1c47678d,5012d1e6,5b918e89,c96f699b,a7ecf63f,d6eb275b,1fe508dc,abbdc408,a59b2e85,95a7a2d6,fd133767,849888b2,f17070f2,9e827fa8,17bc66cb), -S(e98b0e03,d1011075,928809f0,aa62f238,40e8319f,b0108be0,2925a291,967c7702,ba34d7bd,138fabe2,11ac56a2,2d385316,4cdcb1db,ee647cbd,73493391,a87027ba), -S(c0f9812e,b7f529aa,fe875709,1928b262,1277a751,73011d63,b0c92efe,a02291a6,ed5f2cd8,5e85ce14,9f59f50,f3a6db29,67095adf,91b08dc2,fdacc0d1,d3d56391), -S(fd4dd84f,75fe56b7,543a60c1,7a3ca1b4,6f7b9b3,6d6d5c4b,eaa18a6e,6c4ec6f7,cbe12b0f,c1bc2973,ab395480,50d768b0,8c9ff86a,97f2ab4e,942cf095,a10603cd), -S(f00052f0,700d99e6,4d94e1a8,a888abce,3b15b52d,1d08f20,3234e5e8,9ee6cdaa,709b247f,f1daf175,ad7c29c3,bb5ec78,1521c5a3,3e4674bd,d97d9891,7efb07d5), -S(44d51252,7024b64b,f6d30ed2,9e176fe1,fbf22cd7,5fbbcb13,4aedeecd,5ed2c023,eca73cf2,b90a0f38,2745a43e,64048010,259c0c74,1deea6fd,bdcaf497,9b1e2f2f), -S(15651366,b6cba09d,9409023f,964e48fb,422f3211,832000ab,6e84e1ec,faaa1472,bd79070b,a7100d6d,63795ff7,43a26834,85996819,e9bd81c8,b08dc473,5e6bab6e), -S(f8ea84ac,35b6e596,5b6ea25,8411855f,71de79ba,ccca4ef9,b79eec8c,c9e098a4,58da08b5,26d6d3b,22ee2b0f,7e04d2b,ad902b8f,9f4f1f5,454cc0ec,fef6a2a7), -S(f4be9c47,94b6e479,8ba892ee,3aee0fbe,b0cd7ace,1c9d2f4d,ac03d92f,3efa405,e6828465,7a6e2175,361a914d,4d09eb7,2468da10,d72dd3b8,47b71e5b,6c8593e2), -S(65cbda31,ff7780f5,2b31a743,ac03eabc,4f2e3155,8083f198,46a03ca0,d582e348,b8433ae9,848e425a,603c4591,8f64288,fb58c184,454c6c1e,e9d8748b,c3a546ee), -S(e1bee56e,3f500a9f,4b5e0557,157bcdfe,9223c357,2d70ccef,8b8542e7,f24bf9f8,c5b84a5d,395d9c19,8f1cab7b,3a9cfbf4,dd129a03,e9fb6019,b99c48e2,a0d574fa), -S(7de38584,d12ff024,a179f361,5c44d704,c4dfcac0,4939a8e4,a46d1574,7b6eaff9,2797f251,ce328323,e181c130,59ff6d2a,261a12f7,ebcc0dd0,55771a4f,edf812bd), -S(5767e926,fd4ad964,f4bfb7b1,c6326e55,97f9cce3,ada51a20,6b4808f9,e8abbbbc,64a80f76,8a89806b,98f0bb01,b370c200,149c5484,a9cb5f3c,af8e47a4,27813693), -S(828bdd32,18e6f809,6c1fb305,1e797ca8,3914f9d3,ad051eda,d2964cb2,dee88c6e,5a7f7cbe,166f2cc7,b747a1a9,3e3de1f0,3a0da8c4,82eaf9e7,d5ee7e7f,e4936882), -S(617fc9fe,3af26495,bc6277a,86387377,55398b94,1665b70c,32d5a2ae,3d8d2909,278aa70e,58c0ba89,f44dcefc,bcaa7212,e52d8eb2,f3735772,11e864f,2d522ecf), -S(1f823558,2c08ac8f,f58648db,194bd6bd,1f3659b5,5fccd0f8,67c9f11,86e20634,bf356f2c,fa221b73,bb118567,518147b8,f0c8f19f,b82ab45,41e12b1e,c9fbebca), -S(f6229866,82530e4b,301cc0cd,576e9fbd,a65bd52a,d85a3ace,6477bd57,af52c718,9d2cb0b6,ff327470,e8beeda1,1e2d390e,28917515,a8bbd587,ec303d77,f57ed72f), -S(423a8b60,fe61752c,95353258,acddc1d5,5ac7f226,695d1e73,984ab059,8810f220,feb12e01,7501fe26,72059bf0,dffd41a,f952a4e9,84491463,29a4d294,895eb654), -S(f55b2c40,6ff6f463,1a2715e9,d1471c98,9f3df537,75e5980a,2a48032d,9936ff12,67888b7,e6116a5f,94380503,d1fe63ea,a3ea7f71,64e79500,a0db1201,31acc6cc), -S(cdff1ae7,ce2ba4ba,8c8aa999,aea60f06,f6dff050,2e802f6,8f27a352,edf9e3d4,81cd9da7,9fb9adf2,31243148,623906ff,3e80d730,a4977dc4,16539452,58d8f2e4), -S(ba7cfaa5,96502414,984b4105,739c5fdc,a77c6eae,f8b96cdf,8b8e9fe6,f7f62819,bdcd7dfc,ab11f75f,e5eb04c5,5e7d8f4e,b622ddd,8134e668,cc9f27cb,bdda688c), -S(4a7b5b47,865e94ef,65ee1053,ffb75ca9,8a7a01e7,78d8c9f3,9a8d5c9,ff2daeaf,c64ad5b9,2a5b9995,77eb3a4b,5347ebee,99e5bc19,15b1f43d,5af38361,9050e5a6), -S(26a13407,1f6b82b,239bfdc8,ca2a7f94,110a63a8,b20ed990,71d63e5b,938ed91a,14fab6a3,819f4bdd,348ede08,397d7f81,d514e99,cd777fb9,f42917b8,4cc80b7d), -S(154f8ad5,405cee5b,42ea1910,427ccab0,1861c0e7,29a1ddc8,7e8307a7,5102bc4b,37c6a2b1,f7532681,7621f58,75db7b09,18118be9,6259ce12,ecb15459,3231209d), -S(184496b6,b31e534d,ea2a9712,f22b83b5,a82bd14c,2cb90b8f,b20cb735,3d4b9e39,bdb92f21,7807d1a8,82912dfc,50b3af67,ad9e936a,6409e263,961a82f1,31fc4c0f), -S(2d781eb,a2253f32,75feaa51,fcef2a34,413effb9,2f6523b,371fbe54,3f33789f,5c0f0c47,b11b4b38,5e8d2d75,eaab2d02,39c2e63f,125f21d0,17d34fd9,d1f6a91d), -S(cd6fb1d9,790c93a8,3813fcd,8036c0c8,af3c431,f21d334d,8816001a,41eb83ae,15f0f885,511a12b2,804c90e8,cab5d209,76db1e9a,9fe18326,9d1c7570,5bc24f65), -S(97f9ed25,9852a72,3b4bd360,681d52da,fc7d17b4,5e7656de,1448e499,ceba2aa8,3c609c78,25553260,a85ccd6a,3fea7b00,aa87e76b,3e0e08c8,2f7c3fe9,ce760cef), -S(72765585,fe283950,cb316f48,d847132,8782681e,54dad1f1,c0a0a50c,c4086767,147e2389,3ad0d7d6,a3472bff,2c6560b5,93b554b0,e6247618,3439c576,205b4fd6), -S(fcb0ecd5,93a00061,2439cb19,f7e5f71a,4612ec9d,1b9b825b,8ca322fb,daddcf3,5e9f5967,f7131ebc,1959da85,94069704,bab1d58,4a06cc8f,78cd4140,9f532eff), -S(ad12b476,ef630659,2fb0fdbf,522314cb,9f185f2a,e420b057,880068e9,7fba5539,38ee0f47,57ce8f0a,bb6cbb47,ecce2e86,5ab84597,f6aa91bc,4c4c6b52,68755886), -S(372e498f,7ac9618e,3850fbdd,c9c01995,d96747be,2183e472,8dac7ac5,a1c7cf65,4d5de2e,940b12c5,fdc8dfac,69c7da20,4b92e570,b59a8bb,2cd930e7,42b76cb2), -S(dd613209,fe9e2699,9371509b,5162b3e6,e3557515,c73eeac4,800f6e28,28b56fb,fb1c28bd,c0b4c0c2,bcb53557,5b3b4377,c9f29786,31ae6c65,490ef38e,7fcbe1c), -S(8da18bf,6f680ffa,bc4104a2,4b397a87,25240704,287d7532,72df2321,dd94402d,46ccd8a9,401c4fb1,9c81a737,43330fd8,d3a60361,b94e47f1,68342280,373e7264), -S(1800dce0,a2f3a3bc,29d40690,ccddba47,fe8a71df,e646fae1,15d4a784,391a13e3,b333eed5,deb1b43b,c6646a2c,909012d0,21c0796d,c14c90f7,d49c6b68,52e1920d), -S(b6041277,4cd089d9,9c3f4434,2d328b6a,bfbde44,11a60f38,ffdab086,74b834a9,3157019a,32bc8cde,344e60b0,970b26db,4be7077f,956e98bd,39cc7915,64a13f2f), -S(8be5e638,5fe5f9bd,813449e3,bd76b6da,b4ed7fec,ba853ee3,a302270b,556281ec,e114a14,136a7341,5e8af8bd,23dd589c,cb10441,aa173eaa,21c06ff3,c03ff1fb), -S(1ddbdfad,990c5764,ab076a62,27497400,410f5d84,3b9f403b,d4f51e5b,f0736518,b2688561,7ff17294,9c8f89ca,2827f0e0,a1483e8,b856a659,a009dc68,c5683f0), -S(15458735,4f122df2,18c33929,8fcd0bd9,d032411a,cb76df93,31345ba9,668413c9,1b3d7e33,cda314fa,fb90abdb,b1ee2105,27b35732,f0b77f39,69c942a2,fbc54195), -S(925114ed,22625dd6,d4d947df,87a2b63a,a97f3a6e,d47afec6,9e11a1b3,3b798630,55e48dbf,a47c887e,e3ba5758,4f697f6,7f6a1d73,fedae7f6,f63e4592,cfb33e03), -S(9111ec73,d2e56190,7db6c07b,e7324fbe,ab51d18f,8423d484,cb6a0d,a0a7ad27,f7317b13,4befd605,a28b6549,1b2752f3,26c86370,f5042832,1dc22b0b,9240c8d7), -S(f2d1a752,ab206393,7f780a3b,9f39d87e,9d257c22,beb1d286,9434256d,ba9dc3ea,39d4603d,e66337cb,f0b9d39c,cc40c16f,4835ea6c,aed5d7b6,2cf67ccb,35d5e752), -S(2588d10d,a854b844,afb998bc,23aa3742,76938d27,b08ddf70,48605df9,ad55fd52,826c2422,4d95ae53,daa562cc,88e44e52,5d3ff878,ae350e30,c1c633f,219824b5)}, -{S(2def7e67,7906cf3f,3677e7b6,1b0a8f8,985fbd9b,23265ea7,18a5c16e,139f0a8,650a89bb,df8c8326,d364fae7,558de827,a529780c,9b7bf8f1,c6925632,7c59c74c), -S(6e6cbdef,4d5cbace,b79293f,ecf1a4a4,5de81e3e,97e4c30a,ccd6cf79,5668a013,729e4c49,2f454b35,4b127cc3,788bb93d,fd83061b,7f7f6ccf,c24d3fae,d96a7f6d), -S(29d56adc,c1fe441b,123a94e3,fb8df47f,d8bb8565,40c1d3a2,d8e7ed35,c4eae6f5,6a3aed22,6ebdde19,d2bafb8c,68656edc,9e3da959,f2af9872,3ad29a04,8a549a33), -S(c243cf24,3cc28801,e120fdc7,ab6f8ad7,531a5053,1094cc2c,3a9476fa,e0491344,3decbb31,22c91c6f,502eb3c1,7ac22bd1,509643af,3bbcafa2,ae2b6eed,18decff4), -S(2d2bddef,e75d43d4,a8b4ab19,b2259a6f,24bfda1c,11fedbf5,a12fc353,f0039157,215173e1,1a9ac83e,b339dfa6,ed66efa9,da876aae,5d1a690,4c8ea43e,63b683b6), -S(d2796d04,f82115d2,c4849c4c,be608005,1a2dca90,9773a524,56b2fc44,8bd6d7e7,be176139,829c1b69,352e502f,23b724d8,1181ce81,c447e253,a2bc132d,e3bee967), -S(48cda6ae,152ca92f,287a9cf7,ae9be740,29cb8e3f,afc859f5,31f920da,883eb4b9,55fc18ef,af858cdf,a098c4fd,8e3f41a0,92292093,a3c66866,1361edb1,c07956be), -S(702bff16,c5121a82,cdb8d6ed,fab0e741,f76c08a1,70bdddb3,8ff191bb,3a96ec64,5525ce00,3cbab9fa,58b60b7b,5b5e85a1,e208517f,91b0caf4,9adc0c5d,ac0e6e23), -S(98d066f4,30911d2,238cdc81,5133563b,338f9a28,2da63518,6635af43,fcdc27d5,6f10df8b,7bbc5ed6,a64f1884,1087d5f5,6cdf8df0,f9dd493d,23f6996f,ff39e065), -S(44e69b1d,5b7c3816,af2aa890,dec5e389,cbdfe5d6,44d6c0e2,f36527a2,6127b24d,1ad0e960,7be9fbb,efde8dc3,6030d3a6,41e325b9,48129ac2,b26cc1bf,11b331c0), -S(adde6eeb,fcd63063,ce995ba5,3641b01e,f0797d41,d9e18f78,43972f89,9d7a518d,7002020d,f2576876,2d82a067,139387c,7956680b,65fd70ae,3d75bfd6,fd0f77a2), -S(f0f09803,b43d4c1a,f187d94e,3dd9be54,703cae52,5f15fa37,ddcfbf24,98c9c24f,96f4a35a,40523728,10ebd243,ac6d1419,672fe0d0,c013f1d3,460089a9,2457f7dc), -S(dad39c7b,d3edaea6,3ff16c4f,a9a30a9,36d7e447,939327d0,d4a7fa4b,33d7126,6a927d43,3237ff27,f3f87631,c85e4294,1b188fc,d5ec4780,a58409a,cc95d02), -S(b44484cb,b4dc709b,4c21cbbb,2d7d94a2,c5435cb5,1fda7dd4,c3b787f,55df5d1,70e35874,be7a22c3,1e43f2ef,8b4eb222,5c1dc3a8,cde5fc0d,56ab9970,bf4db709), -S(84dd9c05,3cecdabb,b3ecf8f7,c8737e22,634fea44,80c03148,38d6bd35,6a15634c,7cc6a067,81eefe79,d565946a,96114b52,8a482eda,a9028c5c,b925f037,a75335b1), -S(e45d6bb0,50e66a94,d22b770c,9500d960,6f529222,441bf9fe,7856899d,edf3537c,5ec38fe5,7508aac0,eeea33ac,3aa44dc3,e600d184,a4ddb9fd,64acd359,be96336b), -S(25f043ae,b509364f,43ee5ba0,291c95bd,d442fdac,3f00e338,6397fd4b,295416ac,42456a08,64245a0e,5dc9d06e,1f4aee74,b4ca1c80,1281bdf0,59e319af,f79c7ecb), -S(77c7a59b,64cf6153,275c083c,ebecc3f3,59e66002,3bd2344b,a465cc5f,d44b6938,6415da93,e98298ce,60d96880,2dec1899,84badce3,642ee36,70558d0f,bfddce01), -S(1930909f,61cda446,a270581a,2bfb8ef8,14af75ab,aff6db5e,c9235020,af199c3f,4b7d06a9,5a7f72b4,ad189ff2,348a63c6,522e8b15,38309e97,cbbcb121,50f53498), -S(14125e3c,7fae63,cf0103fb,8bb86de4,b97572ce,eb872dd,5d850825,c1c5b43b,dd1327ad,8570188c,1817ee7e,37a164b0,9f37fa90,88784d96,f91704bc,e3e50b71), -S(c8e7c8ae,b060e8e3,1e768fe7,779ea91c,3e62cfdb,80893516,825d13cf,6636face,e08a5ea1,9b5a859e,6f8f6a1,43dbf751,854fd9b4,2ba6c1fb,80acdd9d,9db87987), -S(3258309e,4b1682ef,5622aa75,ee7a109c,ad650ed2,93edd279,55fdb064,c35abd92,4a192aa,838bc722,8c0d7fd0,200d55b5,241cc762,d252d138,dcfabe8c,e2ffbcd5), -S(42a5f570,4745968b,a836648,373af34d,d09c8f86,536004a8,6e043c9a,4c11a57a,2bff198b,5e8bd837,3011ccb0,1fa54719,7030f47b,eaf44ce8,6faaa86b,166ca642), -S(f0d3e1ec,fd41bc71,d2950d5,d6db5614,e1b560ea,f8119175,f7286a8b,d9c6b563,f4c2e948,a30208b3,a7943bb5,564747e0,50e079f7,703a0d5e,f8039d8f,50acc8d0), -S(7f918a96,3c4b42f9,17c61ed3,f4be8d22,c9055005,a5a3f02a,6def60e7,305ab89e,c5e60518,189e093c,62d6f7bd,de1d723d,878683f1,22b9ad69,2a300a42,c5ce9b5), -S(c8663293,f25331c4,a42b1e16,bced09c4,bf7407ae,595e1331,24d0f7ed,99cf422a,df5f065f,d7ee1232,8a3428d5,c8485a28,d882f31d,e66856a6,ee4aa396,79d978f7), -S(778cb411,8c5128b4,8641ca54,2cbed0fb,e9240380,ad3736c0,cff889d7,1a6cc639,8a1d3417,6f2fd7b0,20b46be0,7905b963,cc1a3970,c2bc1995,daea532f,9ce8ecf8), -S(11e3d37,e28172c7,de168ff1,2fcab6f3,3441c007,1e562bc7,d0f13392,df64d0dd,a811db15,8e49072a,7a238be1,128618f7,d7ed2e15,bd437aa3,69cd2a8e,3d28d95a), -S(d65b7bb2,143c9f85,c5c43c46,57cbb87,3d9df9eb,876fa72e,a1f1a221,37a370a7,f2823561,e19c6208,64a1e8ec,ead2101d,175b7255,2ccb63dd,937a5049,3033b986), -S(d02ecfd4,74b5d84e,96111bbb,c88bca3d,95498de1,4d133893,2c4c6068,9f19efe8,87c93642,866c847a,d592a36b,bfbbfc8a,68b3da63,a7d7f380,ce472b0b,9e0f1325), -S(978310ef,548ad9fc,1872bb08,dd0f9ad,98889ea7,719c5cea,fdcf1bb6,9853e2f,d067d57a,4e7ebeb1,f05127c7,9c4ba3e2,fbc3c2ba,9cd9f2b,66182d69,2c699e21), -S(66d8712f,a2221e85,3f4301c1,cb8b1413,ad9288cb,bc64a778,4881de9b,bc1ace0e,67f8a70a,475e9208,c1fe988a,e9ef79b3,67295abe,9ae283a1,5801260c,f916f8f1), -S(da8b079f,280a64db,a73ed601,2d183e75,175534e6,cc295a63,477f6905,15b3daf0,c55f2528,8812131a,99a89f92,cd6204a6,26a7681b,e4460ddf,9a1940c5,8764f43b), -S(1a2bb7c8,96722b4d,54828c68,8708bae7,31937165,daf08d98,eb02fe0a,a59cd00a,f0cada44,48f88668,e46425d0,f64452f8,42be2fc9,bf33002e,fee5cd76,39e5d581), -S(2a55bbff,5aecb50b,97b974be,f0cd3203,34752370,957a9e60,37f2930c,e11a75af,69f9db00,b89a2063,1b4097a0,f90ef087,a9f7cd81,ba15c60a,faff63a6,a4add6a), -S(2fa92f18,83e0ab3d,d6976573,83734908,a4873e8,bacb0577,c44bf104,5500b6c3,bc24564b,d4f60723,14aa2864,216c6984,22caf8dd,afe0e4c3,a86e12b1,5faed4f4), -S(5548afc4,b095db29,28511e52,bdd99a63,18e5e15e,17e99da5,b9e0ef0,375b0999,784726b1,d2152b34,4b0c1a2f,b90893ec,80ffca3a,85fe3f65,7be4a850,175982e9), -S(d4a524cf,6659a1a5,e24a40c2,8e4c9cf7,da607f9f,c209f88c,63c35dd,4af282b5,a73bd4b2,599d92c8,395be7eb,cb70d741,154291db,151e988d,9a7a4f84,b277b886), -S(e0fb0973,32dfe006,54ea1a3b,858d8d6b,30c26fcb,c4339ef3,165b861,ead90352,43ade413,92521afb,1e87f477,45ca8b61,23775ed4,9a1c789f,49a2290e,1d032def), -S(ec03ed52,bcf2ed6c,c7fc2a19,c95a53cc,3b66e344,4d35ae06,e5d17e2a,b6311f0c,a83cf9ac,89accdc4,667686c1,4dd83d8,d3633ad2,6420da7b,321b3123,4d8150ce), -S(dad8eb7a,a7a8686d,d78c18ca,7f0d4d29,edb8ddc0,4e5dc2ed,4e0f0694,1551aec1,10e00983,af99a823,a32d82f4,2d7845df,d3828133,963ba48a,19497860,d975c600), -S(c883f469,e74f4434,9b4e1459,5fccb517,7e2c2f8b,445feece,901dbe96,a2556ee6,2bf2b62b,5b1c3415,29a822e2,16ede0cd,b75419b7,d212774d,7cf3721c,4b9d496b), -S(8c71d17f,cd711b3c,4e2c1214,64d9dc47,c36db06b,c877a0c5,8a31cc25,2ba585a6,9b248bce,7f4899db,4c8e250,c642d24b,20419ab3,a65cd4cb,624433c6,37aedae6), -S(4be86c17,32474f86,f8331f50,b316e0ce,d6591d47,49875e5,33e1b825,7b5cba39,c4ea74d5,62489423,45aa7cf7,82bab029,8fe58092,4943d3a4,d2fc6f0d,7d0fb590), -S(f5eaf803,98fa27f8,27771d6d,50dba53f,32beb3f3,40d6c045,cf8b4253,644bbf5a,32809769,fce5eb19,f0877c19,317e6200,11303b0b,7ade7e37,abbec95e,fc83740a), -S(585c8726,bdfb440f,8cee9bc2,4461e3f1,8cc7431c,e8f1ead9,af2525ad,8b32abce,3ffa336b,a5bde184,676f33dc,e46c4114,4dc412a1,8db059a2,d7c6b021,7728c62e), -S(9175ea6f,746ee2d1,bc893b3b,6faf835e,ef72ba7e,588128a6,56cab59f,737871d8,83cd907d,b0d601f4,88cca1eb,283cc2d6,99913dd8,391eaf27,cb18ab21,6c13cd8a), -S(c5898c32,306bebf7,7a89cafc,29b49af3,d1ab7fa6,95072cd8,6a8c2bd6,aa8f5d14,2313c593,c67e797,49e44600,7181b257,dbc876a7,e3e04747,c3db35c7,d8df24e9), -S(d101d707,76661eda,ea604ac2,2e449d83,57b638b1,aae03a6f,2683ebd,f6e2c413,7186ba53,b8b1d9bd,b4dd2fd3,7b48c3c4,144bd996,f4254291,3c4316c5,2a98ef87), -S(72213fe9,8e8c62cd,bbf8264e,6ac01240,f3dcde5b,b5f71b46,4d8d5617,6fa65efd,80b256e6,21a5041,63b31c96,7753adfc,9c27b4d8,cea73e91,dda2d5a2,7bc50fd6), -S(274c0fa9,f1dde789,1f88b202,4c4e78ca,ed19ec00,7c6c7a05,6028fae2,d8ca3f2a,d5557bdb,96e52182,83cfa76d,f9f0f83f,2619f951,a7bffb66,8cf3732e,7beb88a7), -S(7d3a1d16,66c2b5e0,4f7ed96e,3762d04,118aa293,69fcd8a9,1cd8bdd4,6e862e2e,a004e644,7b49421c,af6c82e2,1bde2b4e,84d663d1,a39ac9e8,5ba43b4d,73e7010c), -S(77069337,2c31713f,1108bca1,730e3d0f,927d0c8e,4ce7dbed,c2c02a60,b3e54d0e,a935c735,18c40ad9,5cbc8b51,9c859f7d,b48be573,cf45e6f8,cd47b8d0,1546372c), -S(ee44b4ff,e008f122,b4ce1a11,d98cc674,e340c874,f0c5c0be,8008624f,b13a937e,90e4a82a,8f002b78,7fc34998,cf015340,dd4854f0,78d87641,bfcbca47,df06a728), -S(61c0e32c,e6615b09,304ee233,90435b99,912b6de4,766e0c14,5345956f,af9e89c1,7531bfb8,414347fb,650127c6,b1f78ff7,97a092c3,2c37d358,8e612cda,9faeb851), -S(bd7026fb,b47a72ea,d28eb317,35ff8ab8,ff244b96,51fe4205,adff8247,2b9d0aaa,6dd60501,40359152,83b7a16a,3d0481e,e8c7b99e,29843068,28c41727,28f21b9f), -S(8fe350c5,b5882f87,ee976108,2ef77b55,8355e02c,9ac40ed9,76d45187,9e0fa902,21b32a84,f2f31dca,9072b843,6c21ee47,9c02c710,48642a62,2c485449,b907f6), -S(93226eea,b65a86e7,c0fedc1a,f6b038d8,7f587823,a9a2ab13,a9975ad3,ffc8bb3a,d294880e,867877d9,b5d87b20,3e7d7860,71167666,fac09b3e,9fd82033,84c4d904), -S(1fee0dd0,4dea34c7,fc6473ab,e89c2e43,215c5dda,6918e089,50d7005e,df1e21c7,dd7b1dec,b1a85eb0,69cfb830,be847f89,8012321,549e2611,92e719fc,2ace36e4), -S(e6304e92,38fedcd3,580cbe51,564589bb,18ad3cf1,3846dfe1,ba40786a,bea415ff,219302d2,53133378,ab25b331,bbfa4ec0,e88178dd,c2a39378,dee7ce64,4c8dc6af), -S(91f97b4a,11051415,7564c8ea,2a60303e,f6f5941,7cc5a556,ff244e18,444ea39a,80fc4cc,3d57cf97,6c9e7794,d89e1b33,d5849b02,72d3e544,5f73fb5,655d54a), -S(7ff60990,34769cb7,5a697d0,418ec2e2,9c5a9716,9ad6d127,ab106518,9fb7b2de,d7fcdbaa,8aa89058,e1f0cbf8,409b9879,6672b305,b6b24a61,42562de3,2b1dc49e), -S(a418647e,61276567,84939f3c,2375d1cb,82871b1,b8004a12,1cda8826,1eb5595,62797683,2528565c,78a7f4b9,d55fa782,bc97a3cc,598c7579,d48b136c,eeffc022), -S(26d408c6,39f97be2,511b4816,5e862d13,f6aa816e,1e936474,63eb47d6,eacfbd67,2e3448d7,fac889c,c9499396,c2de66b7,cddc064,186b6df6,3a6a831a,6672c34b), -S(56f12bda,d8b630c7,5ee497a4,93d48907,63eb1bd7,93d03fee,a19ff997,f42f5464,4d1a3990,7c650896,4fa7ed4,e815379,8e2adf10,80ba7246,3b4e3536,1e34c3fd), -S(e350608b,35cc41f,9fda92f9,34d16e58,c53244df,1446b03c,2e782a53,2926c9c4,b20d72bf,506c2bc0,b35e022c,c6e2bbfc,f34c71bc,a4b44a2f,317741e8,bffc1dc9), -S(5a7bd940,cc23b3e6,614c92db,a08bbc7b,63dffd6f,11117b2f,80c2fe2f,849de903,502e5557,8fcc9495,411c7d18,9979f7fe,8f4f587e,53991dfa,4ade527a,43cfcecb), -S(99ef5580,b219aa84,4cd407f7,d949c07,f7452587,bab97ac1,faf0b143,7351be63,512adebd,49f4f2aa,a26dfb8f,e5c483ba,6ed5b4ea,5d4ecb88,bb165a3e,2494faf7), -S(99c0c468,a95e76f0,37988aa4,b2ca903a,64a95b17,19f119f8,e12aadb6,5438b9ca,fdcaec6d,c390c33f,31b4074d,7e5a81fd,f2b9f8cd,b5f14957,533bd406,fc68ce33), -S(a9f80643,5f1442bb,8a14f402,6ff6ad43,4d84e34f,cd499aa,adecb2d5,125f1829,533e1697,3a3b7b4e,1e82a4e4,115f8be9,b811e787,61fb10dd,6908e0a7,aee4a7e0), -S(8ed6f9a6,2ea10768,4f90825a,e81d486e,92a9a890,78d144ed,53f54cb7,3568baaa,d99f33c3,b7311023,c4266c5d,adae7ce5,a6409fba,d3767f3d,669aacd8,230d8568), -S(84dff52e,25665e13,102e23c8,698e8990,e5d63e86,330703bb,54242843,8fc9a46f,b1bc70eb,f8ff0905,e2ba529f,1af149ea,536fceec,2a5621ab,bcf89756,ab0f69cb), -S(1bc3844d,78f82cb6,ada3b0d8,86b4f89d,1a4344ba,431070a3,3f3dbc77,2c523410,94580bbe,a198dc00,2b226e48,7a745090,ec603b3f,aa6e5847,8a8832b8,3b0fb096), -S(436e0b9e,aa94e6e,b20f58c4,678ba5fb,5e1d79ca,a7bf4179,3b91c962,325979e5,1615e98e,ce7056c0,428e55ad,f4353400,4ee4e158,347ac5f0,715b0f7f,86c17047), -S(45f8a062,4d3ba9dc,d577dee2,f5387f25,3eb3b53c,31fc6e97,836bffc6,f85b9357,b7a628b9,b9068247,d8415fcb,c5f6e6c0,e72dd75f,cb1abb62,c947cd06,5ef22ed), -S(b86ae36a,bb489583,84e95ee6,8c46c0bd,8f0110e9,98e34595,1f6e6b59,fef4e2d6,2e3ef338,ebe96f24,ac112d8c,a6803f9c,338179e8,c54420c2,981d0159,27d983ec), -S(247b2b62,79dc1d09,6085fa0a,390bc09f,2caf6d90,24f953a7,54aaa29e,a418574a,4d3fc5ab,9b3912ae,f67ff98c,2e641ba9,bc23aa8c,f60ae6d9,cd41ec93,7c4a834a), -S(737bc72c,964ee56c,822f1e31,9ad6f9f6,57785748,55689eff,492c7587,a98deae9,2aa7dfa,d4f105b8,690a507,8fe81eba,2736c301,6ea4fe62,71e47d50,18e4e01e), -S(d2ecf284,fe7663a3,810ed1da,c8533d5b,a647004a,3e22683f,78dcf0f2,1db4c5c8,2fc3895d,beca5b8e,17a2e3dc,3346b957,3eaf4457,ab0a140a,6d119304,9349df04), -S(3cac275f,98f2ef42,b0f78a1a,52218150,a18fe23d,b1361151,a3dc7477,fec811ea,a426ed39,41b7ef3e,48b0e267,fc1cbe50,4b1e5671,f4dec906,a2659792,2ccb6259), -S(f74a08a4,6fdbfa99,843c24a2,f9e5fec5,b941c29,43a25cf,131deb7f,1c3303ff,6fb92df,aafdc8ee,cd7c3416,fc89fb5a,458c2c97,84f71698,c512981d,a8edfb2a), -S(91d44932,56fd4608,48f04de7,25b3fc8c,656a38d6,f8e319f7,1ecf513,146eefcc,cf058db7,69aabd80,12ea780e,10aed66f,4bd5e356,1b0d359d,167ebb3,2830edd8), -S(d194e53c,1a2a2c80,f7bb24be,b372d751,118da62e,9901d94b,66cfd289,19387bc6,aeeb2818,d00b7307,79fc14d5,31a3d803,5e5642d3,b7335543,13c8fda4,c940b387), -S(ec18acf5,a9624f91,1273482a,b03ec7a3,345ccc2e,282a6fc1,cbf89a2a,45e798b7,ca9f64ec,caa12673,a2901fe3,684ac70f,501b4d63,601fccfb,4cb08e53,86671cfe), -S(488bc882,77874baa,6fc9edab,ee101b5e,1d082a4e,d49da47a,af5e6650,90e0566c,9487231c,3e6681ff,bbf953da,54ba603c,89a00340,c4e50c51,545a5c6d,d51b98b8), -S(25d4374a,7f1eb525,825253ef,a3ff3747,e4555f36,9fec50af,21716ae6,8a11d34,cf475aea,53df9a1,13670563,e0ade1b0,d4d90da2,11b87318,315f368c,d53c5e18), -S(5db16271,c0d7e9cb,dab1baa1,4dba4fdd,1716a7b2,8c2e07c8,186899ab,18a6418c,344f8bf6,b722e92b,ed436fcf,41be9a08,327002fc,7b3b57a9,2044800c,a0d1b2a6), -S(402bb93e,8162ae4d,f23f5d72,611eebc9,8d4c00a1,e4d8967a,da1bf524,9ad1547f,f0c0b1f5,aa183000,7a964ed9,12bacd81,9a36b55d,7d2c7c1f,12da6066,a28c1d68), -S(87b76fd2,91fd3508,52544b80,85b07b94,20fc325f,a0ecf42d,9354df82,467d836e,f0a2c79f,4613218a,3b35cbf4,24b5fea1,7d2ee9c7,ab912be7,62270195,8b70c133), -S(e2d73ca3,ffca1eb4,191eb705,c22cfeeb,a7f573f8,463a0cc1,c73bcaf1,3cf6c791,61b861e2,5aa3711a,b92aa74c,814b4df8,37172f43,ea0da2ac,d81ae961,1735fa85), -S(1e59b370,be38e5d6,4f8b6fdf,7c2351af,75ff9d32,1f583d58,bcd0e8be,ee0855fb,d166688f,24b4b33e,b171343a,87bf8828,5cd5d073,a5023bfa,dc542660,70d3cf13), -S(52ef3e6f,5aecda7e,e2a6451a,ec2badeb,235829de,b7cf6e1c,5a6970ae,662e2078,533ca8b5,8d9e2e7c,2a992a22,3f385846,748a1686,34e1fb2a,48d3f133,8512bb08), -S(a4b1cd10,20a321cb,53717818,ad0d39fb,5e9524db,4456e0c8,eab045e5,b2a97be7,979d9ed3,4601d962,3f084e04,9ce4683d,783b912e,6a92c07a,38ae744e,fa7d046f), -S(bb01149c,2352baba,8f3fcca6,a8fdf9da,854d7,7efebf92,6a0d49e,abcfd871,b186fcef,1d368ceb,351d5e35,35d19052,7373a9,36a625c4,c0b3cd21,d4188720), -S(978e8fe7,c4088cb1,27f9e8d7,5dc43453,ed16470f,4f940413,eb800ec1,b315f269,6f7f521b,1493b81e,6f099fb7,22ae2a65,f706a351,2b74338d,b708bfa6,4a34f6e5), -S(7e61704c,77e4a6f6,925a1c48,8965a72f,7bc8e76d,cf316371,13f682,b5fbc0ca,da66aaa2,c39dd05f,7f5803bd,e5bfa0a4,21eb628a,12df0869,6c6614f0,176b15bb), -S(87c537a9,b97dc885,3b7957b8,2cd9ec81,b8b65d58,47a23106,e6df3d5a,cac3fccf,4939698a,6123ae1c,42cc6ff1,fd006fa3,2cb0a5da,a3889721,f04a4a59,e0fd7dde), -S(590b5b95,37a08784,f804111d,6ccd7df1,7bd317ef,aebd7bdc,96f3df4c,aa8ad437,7aaf5053,1c187684,ed8238af,c621e151,dd6e7c6a,2c18bdc8,9914a1f6,cfde5e29), -S(913a2ff7,a9416e56,afde1c6c,6273d7df,150deb4b,f2db3f3a,7ff7fa8c,173ccc09,e865c6d1,33da3db7,2dda798,9a5b860d,671c9de9,d6132784,30b5a552,85a9854f), -S(b01fa220,1ba66785,aaff5f59,347586e,162ccb08,ca58179d,5dccaeb7,636b4db3,d5589b8f,2ba1ef60,23936d96,f2772d4d,cfad1f26,cf124265,6765dc2b,7d9f543a), -S(511fc077,bed929a0,249c65d1,3f59c607,b8bd0279,c3ffa23e,8c6c4ab1,800b6363,74b03bef,b913cf04,f44fe5ed,40ff2ff5,9e85db23,34ba902d,84dad90b,68a72912), -S(d8597fba,dd03e235,defd0d4f,72c054ba,880390aa,c1c356c9,1eee50f7,8ba567b5,86bfd1e7,f1df87e4,be26c892,d2c1a634,1904c414,bf84dc81,d65f701,efe90bc1), -S(34b46527,86464956,6dfcf2e3,5717955e,4529f88d,786ed832,f879bb9b,5f24ad6,916bacd4,52fb69a,e8f20094,8846e706,e3cf466c,a34a7c6,b9a24df1,1d48edac), -S(f68965c5,55a826be,187306c3,8695dbcf,370c5fd9,1a018912,ca143d8f,b9e96c07,2342eb5a,bea7b80c,837a18c7,ed606930,248ba6d4,f5ea3650,9a3aa10b,c0326dbc), -S(80bab356,e346b2b0,511775f4,be1a7bb3,fba9c65f,5cd035e,b9300162,547e75c0,e96dd58a,53a9e313,2c3b494f,2c53bb56,da17f573,8bc90a10,58063906,52c33363), -S(55a3ac1d,88f00e04,ec95215b,68f37594,9e10abb,ebb1928c,6cea668e,62897e7b,31b5984c,4280d3ed,125d2223,57718f54,b8e406d0,bf4feccf,2deba94d,45cfd5bf), -S(7e0e03c3,f82556f5,a85322ad,61cc60b5,d096c684,19c76b77,f328f51c,bc5daa41,36b4f520,f84f8e1,7fc79bec,bc2d4340,e77c5b0e,4fa944b,c0cb2f07,4c5bb1ce), -S(fbe1fd76,8dab92ec,b56819c8,901cb8e8,cabbd809,f61c0f83,70fc5697,7a90b28f,6fdb62b,d011208e,aca8f8bd,68ef539d,a6a5552b,8187327c,19c6f4a5,40b1e750), -S(ef2a9571,ba9090ec,1c50d5e5,d8955609,2f7e7610,625860d3,c0e1f22d,e66e7a0f,5ae0a396,d6cfe9eb,7e3e6923,e7d1d925,851fa4b1,38217320,92191366,a3aa1c27), -S(81652fcb,7a968f46,a38a6b9a,f3f6d831,577fd45,dbe0cd75,ca4ae8d3,c34812dc,bb130db,74334258,e5dff98c,cf8e72b9,95b986f3,7177c98b,ae6f7747,3d869e17), -S(e0daf5e0,a32eb5ea,606b2760,62c8a60c,a4b476ab,b5f2b172,9a15c529,11509e75,8eecb80f,c47d33de,c036c661,e940aa9d,26bc8541,369315b9,b7552487,d32e0f4c), -S(cf0a6b13,f6ea26b3,8927139f,1c5fe769,6f297e00,46e4f529,1c4d5c60,57dc917d,b8c731e7,5d0dda67,63c1cec9,b70cc4a7,e39a7ca3,c1dfe8c8,4a895d03,b3b185ab), -S(a5b5cf9b,35914a4b,6af16c2a,ffb6bc8b,5228ac11,ea91da48,fca654dc,b6b8bcae,e6fa217a,42e72a81,b8f564fd,a5438d3c,5d0ce8f3,71b1d6d7,c577d70e,f0daaae3), -S(d4c1d178,b462e260,c6b7eb43,b71dfa56,899fe5d9,a421da4a,edded57d,4a0010bf,339fe1d4,83f047e2,cf2cc9d3,bcdb8f0a,df9b491c,ac87a512,e901586a,50f35276), -S(3d343aa3,c6bfd408,1b64d616,2523b272,ae207a5e,bec0e530,4e0792ea,3743b150,5dae9987,49073817,cc513c16,382edfe5,749a8dcc,62f4dba1,3e0c88eb,c978abfc), -S(34242394,db9874c7,14664ff2,90cb1be9,c48c1746,d53aeba1,536fae00,7ed83a4d,59203b4,b8b3e0d,9c34790f,f9cd0716,8606cade,9af8ca2f,b77a6fae,d6e10ae), -S(aa8c1b42,7588ce4a,2a0fb437,25a27bd6,6f598323,fd525e88,a3a586e0,d2d64a08,2f1dcc5c,269065c7,a966036e,c281d05,39d4cc40,fe42fc37,667a49e8,850fcc00), -S(699d3ea,9658f9e9,7fc0b69,4927f4a0,bd95dec3,cf104144,8167e4b,50482c74,416ac99,d59c046f,a754a7ba,d37b474b,ae7d2192,f90719e1,39b6af6a,e2b2fc84), -S(1cd6ac9b,93f5b488,5c06c9d7,a44ea260,11c9537f,d75f5abf,e9d7ced6,c14a994e,818a63b3,d367f655,4afc7651,7fc85fdf,3c69b881,242eadb5,8649ce89,f1905e00), -S(297c80bf,24a78c2a,245008bf,40a828a8,575e6362,5c555653,980f8313,6ccfd660,5ccb3479,60c1c639,60da5605,4bfd8d5b,61ee83aa,d815164a,b387dc37,a44b412d), -S(915638c5,f9d1b491,99f6ea3e,c1843d4,33b832cb,fad78dc6,ad55fd10,9eaf31d3,bd097f22,440a0c35,e5648ff7,724fe5,2163edd4,3c1b2fd2,7c49d61c,7194f225), -S(f8274560,da2fd048,5b974537,16844970,d1c0c1e0,ab450703,739aebe1,28a7788,58c71185,2a63aac9,5a080ac1,3d786a6d,75488625,622afdcc,f5344ab2,adea04fd), -S(94b4e84c,61fa07a8,6c35d554,816f2131,3727f614,d641f3e9,8ff74509,fcfd444a,9a30a0fa,30f3a772,747e3a0e,b0d17ad1,c029558b,a5e0478c,160c109,fd43df77), -S(de72f827,3ecfa2ce,67d55302,9f242afb,c3ac130c,4e711a41,545edb3c,dcb90d64,3b64bab4,4141392b,76e492e1,49c166db,272e23b8,dbf3fb13,b17396bf,1c3834b3), -S(6e7b3c5f,4bf9bd45,1c5b25d9,23fb5768,7aa2b1be,dbfa3317,db823b8b,968263fd,5f7c0be4,ba960cad,e120bde3,c8ab685f,e80f96d1,5a012993,d1890b89,563cd7d8), -S(3e4c6252,307c116c,33f5e2db,5690dc4c,57210b58,3b2250e6,ace138a5,24a1b376,e82d521f,4b50a3e7,482ebd30,93f7ed8d,70c6dd1e,6339af4,7ef453cd,ba3a91a), -S(99a27d9c,802a5519,3f9b767c,3d9c04b3,7c6445b8,e49887b2,55bf325c,118bd175,2cba1615,5809eb23,8e8a35f8,7d80c011,2b0b1587,1e56c567,26dbe6c6,d9a477a1), -S(24b5cc41,130a9fc0,d694c99c,a00edba7,2c8d2a94,7db35421,6ac18ee9,6a88e99b,d409cef3,7e0fda7f,27478fa0,651ac750,bab44341,98d60fb0,50db541d,f416c488), -S(903e8ceb,229db84f,803346f6,9db1b473,4d375dad,b29ee771,c194c1c9,4f068066,405c25cb,2ce89007,bac620bd,1e7bb959,c61fb5f5,cb60bec2,15a978c2,91c63aad), -S(77702bf1,2ddf612,5d3803c7,19be7b60,c4dfc0a,54bfb54b,c58d2595,230e92f,dfd2bbd0,8cb1b67,f26bc57d,2b9bfaa4,7a03872,2011c58b,619794b4,c0bf5eb9), -S(27aee8e5,3f4ba917,29f463a0,888834ec,e83a022,bc9862fa,fc5ecfe1,d082fb41,1be8786f,2ef69516,e18131be,28cfb9b2,ec0ff57,6dc75c84,5f2a7080,94b40bfa), -S(ef967d14,d819d4e5,5324496e,868c3167,b94393ab,e3382466,44fd2b59,efccaabd,98858ad2,fe5db334,740a3bf5,fec4bad1,96d39e5a,f09209e8,95e086f5,8a252975), -S(a2228f83,18c5fc47,1536bbb8,9baf820c,8b2b48bb,8ffbd4d5,56ae162d,bb80a78e,79e06c54,ae0030f3,a6275aa9,8897e7e2,637ed005,c6aadb63,33575232,b54b2bff), -S(5ef437b0,d9a17584,6bb1e711,7b7fa86b,504385fd,307bcaa7,ab558ab3,d2bc5707,5aeb2e4f,83a73719,e1268a48,6a578d84,3104f0c6,86749b59,7c4b3fee,8ae5b586), -S(35be1b54,47f8a2a,512deda4,31958c11,9b187997,66eed6d9,d30040e4,363274dd,6539313a,1d5328c7,bb389c47,98c08c05,f9412c1b,31c08509,3af720cf,6c604288), -S(4e548261,89c3c699,eeee1560,b9876e4e,5e0c8677,f849a9f,e2355d2d,aff7aff0,49bbccfa,2a7078db,d032fd27,98a701c1,c8947c0c,fecfc1a1,38dfa387,4ab436c8), -S(37d9ca55,6ce9a853,b79fc831,69b6778a,43737dff,f5eda67e,eba8f267,867018c,9a9ca2dc,2512c397,a16780f2,25686b51,7c40d90d,d97a8077,91be382e,86378d10), -S(ad37553e,383b985,a4054cc8,a909af65,5daa7957,c380be16,aed94ab6,407ad12e,98e09fca,76eca761,9e3905c8,ef688726,feb7891b,3695d06b,5af5aa3f,f92dac3a), -S(55b0a9fd,7dee7ff9,84cadfd2,fafa3f5e,30cc6fd3,72597902,c8cb9163,55e2a0d5,97da1eeb,96599624,39eec4f0,7fe182a2,cfef4a9e,55a21b1d,64a43a8a,8edbfbed), -S(c79778d6,64e3f159,5c9ab43e,3930b722,f734079c,eb131b50,badaa53,337669e0,1dc01b47,e9908908,d318e947,8cec0a8c,37f7427c,bef205f7,9000617c,ea33c723), -S(ce6964a0,b5fa0b4a,67385884,12d6ed28,75da7d26,dccaac81,7f3aad1d,4a9500c4,faad869b,e4e0262f,fd67cc01,a0523f98,d15d9cbb,7bf7e8f3,fce7e20,26b7f765), -S(70f8af3c,f7fea8de,e62a3ec4,770828f0,52f819ca,e031c9c9,a0706d0d,b4d5751a,b4c4a600,6e4f831e,c4bd750d,62a52d0d,57399b71,ccb71f6d,c00287b1,67a1dfd2), -S(11f0d683,9f28915e,24d941e3,7cca8754,bab9a8f4,96807679,89300b02,8e79a041,1adad681,9d726c2e,2bec5f69,75ad8a4f,c7209872,35ea7486,2ff38333,2335a647), -S(36a0d630,625c455,5c8b711f,a28e2d0a,4ea34f6b,c81ac8a2,6861d58f,ac3bc9c0,89c1e59a,fab4fd9e,3245ba79,876404f,b4cdc7a6,2a9a90a,f307a8b3,17453467), -S(791e10ba,970b964e,db48c4c,fe698317,fcb64bf3,db8418e4,86c45e6a,fb0e1819,e9ee5073,73d105c6,b7012ee0,ba60b9f5,89d98773,f0bcea03,14d6f707,7746669f), -S(cfb370,cb6de70c,58c40464,c20c1cdb,9850be9f,ad9a4af4,2bbeb6b9,f173725,3f5bef6c,814390a6,c99037da,eb7fa919,7e9c806,50efc919,6650a42f,ae425619), -S(1d5b7762,bfc3fe49,bcbc3176,158f186c,f909c04a,31480b17,2451acd2,8024321d,ad60b8cf,215cdfb6,62a29985,c9f185c2,19936929,b9cc5911,4cf5329c,44ba080b), -S(304bcf43,342c9d7f,fa8e05c,66cd140a,57c4f58,d223a1e2,6b93a374,7c73882d,e250d896,acc87906,b79d9ca9,63246ce1,9ddd44fc,4e834643,f2d592ae,219f9767), -S(60bc17e6,9cebe27b,b504d28a,b657064,3bafd4b4,2d82e3a5,77dc8c5f,4a05c4ce,e45ae47f,6088f05e,f6709166,9f608598,ecca924d,ae7ad37c,1852009f,e23912a1), -S(cfa64de9,ee4a849a,de71b1b4,340b8d18,1341d00f,e86bca01,3d62d800,3e20454d,2e72bcaa,1967c37f,a8f8ec78,b82b5f6d,3c7d0136,28bca50f,c884825a,6c967e92), -S(400e67b0,bbefc4f0,7aeaee57,1c495584,de4e7832,377bf171,ee3e38a2,69e53d73,762d4b13,f91d4e40,ba0a3fbe,3c085922,3386add9,b8b1c432,88052b9e,cdb8fa3b), -S(fd3ebc1,e1c751dc,7f897ec1,f0ae0817,22136109,11010904,6c105497,47602cde,43699e3,74af29c9,692fed1b,acfe00c4,f2d91908,eb7cc181,7c270c76,453343ae), -S(60a18f0,740f1caa,ea056b17,9808ddc4,aedac1f8,482bfeb6,a97516e5,d84c0a30,6efbcdd8,114ddc58,cfc193c7,f11ce4f0,931b3f56,4290253e,a5289d25,7e7d1350), -S(c08a77f2,b9bfe746,ef89631e,1bbe07b8,5007d1eb,bb18547,6d7f8f49,4283e1c5,6a94da87,4c350d0b,cc23ac89,9d342752,97421c77,d7b7293d,669cace8,78121770), -S(247f8ba7,b8cbaf03,2358985d,955b4ae5,673622fb,ce1b68c,877db077,d91fa63,a180777e,3b8b7d6f,733d0565,b038b345,d598a9eb,1d592949,8463940e,99f7d74b), -S(18b7101d,a65cface,68d7ecea,5b926eaf,79722f9d,5962a86d,e1eed6be,ca08e4fc,60b7377d,eb39da03,f5bad331,f41586bc,6e3bfff9,f7c9eb7f,aae6f7df,8869f7da), -S(4f6bc39b,33d45e5,325116d6,f8eeb341,d15a3f40,57b64775,932f9b11,a92e1959,1cab1c18,422dc38a,e1a8d4d4,ecc84748,4c47d862,42ee4dfd,28624a72,bf693433), -S(45ce69b1,cdd90a2c,a14a2f87,b12d1f8a,7425935e,2f2ecd5e,6f25b087,acc4ff2b,3f850036,ead34b81,3eeffba6,c3b9dc77,8675152d,f569bc28,d4e74539,896f4b34), -S(8ef39f34,27339934,a1b969f5,b203d187,2d3c467b,1a25ca0b,d59b385f,d78d0cde,926604a6,8f82a4e7,a7e5507c,e1f1730d,c43f9a10,bb15bc15,9d8b940a,7403a5b5), -S(cd83545b,fd621045,245390b0,938c12ed,d530949f,6ebf0e5e,90ca8617,637d2cdb,ec79aec2,77d9b2a6,1721b499,ecde68f1,44faf32a,7984550f,54fe9208,517a0dc9), -S(95482d05,3fd19bfd,20a218d,82442cca,89d2f1fd,883300fe,9898e7af,3e1e7c3f,233aad3d,c798660,1aaa61ce,ecfdc48e,9b3e09d0,76a14945,eaec9d67,60713743), -S(f96fbc5f,eef4ffcc,d5c8ce74,a390858c,24cdb060,529974f6,fb7a7afc,759d7684,d41bbd7f,54c6ba72,aa64996,dc8237a1,27d767f8,ae4ada04,26879426,6343d663), -S(c31f5733,a92bc02f,28aa1abe,6dbc932,96ef1980,a8b876b4,941aa05f,3e4415ca,cbb9afbc,166505de,b160f3a3,fbc99c6,8b9aa548,ba80b83b,e70700ab,611d6bed), -S(e710e709,b2d1abaa,ea81e54d,4c913029,61d058d3,4aaa329d,bf673da7,6cc50f87,e6078cc9,c093a8c4,804ade7e,a2bd8f74,78b93dfe,47cadcdb,18be11b,dd450acc), -S(3209825e,8e6a7a03,cbb96e9a,cec60e29,fb3d2113,310a5f27,69c789d6,fd2d0ea4,4a1b86bd,fa71c5ee,fb640c0d,2fdf6941,42790350,a48b7189,41cded36,e6627117), -S(d26aa999,c82be0b4,25268242,c969c812,7160c34,8d61060d,2cd95fda,4ad91572,193c9343,5ad89189,37df995,5b8ea66a,5f81fd49,aa463d63,bea7e793,d7867078), -S(f505f201,a5f0a8b5,420db5be,304e3824,5552efc,d7736f27,a70d63e0,846f7a05,affbf297,4fd36a6d,45cd403d,e620fd5c,24ee5094,82f03dbd,4ae8d1e2,8047e07), -S(e81d7da0,665574cc,11b5c7b7,c7d49ea0,e12e5a31,d8d4059d,e589c87f,8ca189de,cd36628e,f84c929f,bd057c9e,9c429e0a,28562415,7a1f718c,5f6d9c6b,2402a25f), -S(d183676d,573926af,6b409350,fcec841a,9d7450fb,2c122dee,dc7f061,8ee870f,4401a6cc,1b298b4b,b7069ca0,70452571,1406bdfb,8d991e0c,a252461c,155a37dc), -S(7d8eb701,a4555db0,e28755cd,b99ec00b,188a5fd5,aba9fd63,b0fe59a2,e5f69621,26dfe0ea,387948f4,320a99b1,79cbab72,e0e7b4d,dd91023e,3ada4706,b1e14de1), -S(62b18c1e,6b41494d,242c807f,aea4cb90,6c369829,bd480aa1,51d42ad6,f2ab6e16,806a683c,ca4ba62c,d0d7210a,2a642a97,11a2c336,2cbbdd40,a14c49dd,7445157c), -S(3beffdc1,3d43053,e4975be1,2212ef06,756e420b,28c1da19,7f719140,40754d83,19f74783,30213117,c1cdb3fb,c500423,14c36c4,bb0b6073,504e29d3,2a7a81e2), -S(883c1fc,6c1e9ab1,f8728eb6,7e3c820b,bce57c8e,78920acd,88c56b69,8e21b57b,a6ee80db,2f153833,f397e1e9,f7d0bd3,b68e3a9f,a83fc262,88a3460,241f30ff), -S(cb54c3f1,d3007e9c,a6f4c7de,7cd6e728,22ed6627,3d64251d,23df0352,ca7f3f56,aee4eed6,3bde44e9,132e8405,c088e412,c8dd4856,9be5a980,adf9969,261282c), -S(40b26863,67d38ed4,ec41c0f0,b8393698,969c98e,e3233fbb,b2c9fee6,14fc52b2,9f3c3a8,44703528,e8a3d025,d536832f,f17e0988,4e90a75b,82705e61,c5b4f811), -S(90431e86,74d9685e,4c91e51a,a897fd1,b5aee499,7a8c7405,508d77a7,d0d742ca,b35bc817,b63059ca,8c21e0b6,f3c198b5,ad7f19d3,7711d02f,4695712b,e8706df5), -S(5ad701b,3bc26c4f,cdcd7882,71d259d8,1d134c0c,53063b21,c740d7d9,9c235474,615f2956,b5056865,3103ab4f,d53a1e00,49bce03,db115d5e,8dd36c11,1615f997), -S(75a3782c,51dbe62a,f9da5199,17e3a59e,b04511d9,f11b7312,7dd35b8e,6da95cd2,38061610,c0052d14,bfc4ef8,62d92a5,d59bca62,9fb7a240,299ab954,8ae21484), -S(28e60b08,2edec9a6,1fdabde1,b65c2e0a,333b5b2f,2c8cb97a,fc20ccf9,13792765,c96cac7f,4efb4633,8d63ddd5,33968f6,d09f074f,28e3c57e,dc868e7b,df4105b6), -S(7dc515d7,f7f20959,7e52b182,97b5933b,2ef9ef30,38e18236,39f6ac5d,214762e8,37738e78,9222d0d,5d7e7979,19b0ce29,81b7be24,abd4e0f0,8b989500,a348218c), -S(a8ad8d74,cf467d29,a97690b0,a1c539c9,604e5bb,77d4f719,fe1b7507,d51215d9,4180c361,21659aa3,fa84ca98,8676b3c9,23639184,ee991576,3ab9878b,558fba54), -S(6a71e2e7,99f1c56c,e38052c5,767ecb1f,85c2abb0,55832994,18417a12,9bae566e,481b3cce,208f33c6,6d4181e5,7648061a,86246ccd,31f92eaa,6200591c,1662b7cd), -S(78d0ae79,7a94ae5c,b338574c,1bb635bb,3207b491,fa42e6fb,7c861eba,ddc195dd,1d9e9cff,32ebca9f,d707544f,ead5363f,15a9af8c,e11d8036,49c6fd8f,cca067d), -S(1feb4e2c,357837d3,8ed62d33,4cba95c3,54ab6bf7,2d9f1007,b7419ecd,6bffb072,8e096dfe,15e187e3,92c4a26,2b94d5cb,63fc4cdf,f14e1b76,33d40946,ab074a45), -S(e9a3ce53,cb11bdd0,6c0be1e0,848b94e7,ef68d881,88069893,2facab4b,d19b2344,878838a3,d85a38a5,60a45847,20d8ea0a,34cfe7c1,6b65f35a,60b766f,d77d5fae), -S(2043c86c,4c96437f,f96ce0fe,ab5f428f,76966c30,4dbe6637,397d6b35,730e73d6,82eae267,3e2fc564,c128723a,b74feabf,905218a6,6567ea0a,4cfa74ec,5ee7d22d), -S(d02b8896,63ada221,3e6b458,7bbaec0a,2b1cd8b3,40a815e,fd9f3e36,c782727,c5c4cd5a,4bbcf08b,e1b8620e,24930490,c9f0d61f,66ef0c2a,937e2077,b178f8c4), -S(345b51da,c452419b,6cc320ae,8222c72b,12073fc5,a77ea07f,fffc10d8,61482094,5a0406fd,42916840,8fe4c276,bae94cb,710f6cbb,994da133,932c9d7,cc73242d), -S(275d0e66,da342f04,c9cbd00,18219dee,1a42f9fa,418d0a55,3f98b88d,ef845ce3,3fc25f10,74ad90e0,4ff09d42,204eda1e,a63fa50c,152cea14,d322ae5c,2c4f6dd0), -S(64709e5b,8c4eeeef,9b92177a,b4a04de5,f0150612,c84657ab,855d0145,ecb3aaf,c3b0e1c,56a5a00d,868f2a1e,35a40b0a,9d6b55d8,2df87d15,95b1890b,8b9a3a94), -S(64bb29f9,5e7f48fc,d436891,8d527785,2ba8a6bc,f2e1df43,f7dc4123,ae2b3be1,1f4a8fec,eba87217,3cf8bba3,bd19598a,ea1c8998,945f5b32,f1f52d00,8ed1355b), -S(6f401b0,2e10c301,27dcfc91,2e3a3396,93e8d2,f392507c,338dc113,d019e520,d9a59488,ea1e613a,99bfe1d9,dbd36a1c,3b65ff90,fe8983ce,9665ccbe,1108073), -S(3af33a8b,63b062d5,30b7ed95,c9d279c3,7be8e95e,6e173411,9d354814,b361abcc,4a5f16b0,b6ac8371,b2674adb,933a7f62,d22c6133,1ccab67,e6abbff8,66124fae), -S(a3feef6a,34754c7c,d888e898,bfe5080d,e3669502,d5ec3fbd,ecfb2dfb,8853fe54,a3e7e218,6d88e82,f600be21,5ea5bb93,44a6e10c,464e5f7f,e1ea24a0,3eafdcfe), -S(2e6f36d8,910a303f,c4c93cf,660c31a7,ae7b2ef6,c2ab5cb,940f9623,e2de83ec,3ca98ac7,a03b0b11,1104bc99,d693d068,7350c4bf,f911c183,1848bdd5,bf35e66e), -S(5d7cbc21,3016b19b,2dde662b,a677902f,cfdcb91e,25dd62ea,583b6375,1cdb5aee,871c5aa0,d44c404f,b42badbe,a9b99a43,29db7694,47b93d92,bf5dfdb2,648f4677), -S(383c7ab9,6e772e7e,47b01559,ee3bd4ce,9b86b38,a6f57968,64e45eb7,112fa1fd,254fea35,3ab6bfa5,2018668d,9f3cf2ba,bdb4aa59,28bd6a07,852c4b4a,b9bbda6c), -S(96aafbb4,1d6c96d8,72a6a577,13b25b75,814966c,ec1f0162,31b74dd1,46322ce3,bdf9a817,4c367d1c,51d4be31,70cdee51,a937445e,f19c1c10,52da1f67,e9e9561e), -S(4700205b,e431bf70,6728bf7d,16172589,7d104107,5153a9d8,7796bc96,49d479a8,4117c528,9d404239,97f67970,65d3a9dc,6b3f8c13,1008489e,6b23a631,6f86551c), -S(f81281d6,7377a69b,5ee7c680,744ea61a,668eb128,dc404955,f541b0c,e414b37d,e54bd7b6,783b6888,4bc72551,1e97c5eb,ccef5049,a28fa13a,a15232da,eed7e23e), -S(d898d15c,276b3b92,77f39c23,93f60540,6a7e201,443cce6f,d873d8a1,44eb5a,5785dd47,80f67f3a,7efab06c,bbb1044f,98d4425b,b0f1cc99,3b6b4b2a,a5504d4f), -S(56297c68,51dff96c,6122ae9a,1cdd2ce4,b1aef6ed,884e5998,28c77de5,eeef72d6,4f2494f6,5ebbf2ea,acf70249,f543c97b,add6f6ba,3b152b22,2b371a83,2f8664e3), -S(1adf1f2c,a5f3c153,ce8a6dfc,c1a5a21b,d98b99e2,135b6e8b,494c6ba3,2703822f,13fc7044,cf6c75be,ed84aa6,bb1fe11a,9f36c562,5a152c6d,81b373c0,42bb99a3), -S(f42c77d3,b6b36250,bf4f535f,27c00c8d,61b5ed76,d4928138,cc0e672a,7c72851c,3700f507,c90c93c,6fa6648b,40df90e9,b3292356,4a9bd471,4cc310f,e48da924), -S(17aee799,938d30d3,7edb6b8c,19d4d0ad,86ecdc34,c4b7d504,9d2b3b9,3e10cbf9,2527fb75,a787f794,a5f06a55,c3b33f7b,c575948a,c5454bdc,c14c598f,34459647), -S(55acc75,4a188608,46ffc6d,a6e3e2e1,18cad61d,e508d333,784fc716,555c98e2,982a4306,65448652,14f42c31,18e3214e,3981529c,422a0c76,d30d45d4,777aa87c), -S(d06c7e99,dbaf0943,6a6790be,e7487614,95ace755,448580d2,7614a30f,9bb7b5f,a6958136,41f3025d,de7ffc89,689b385b,b3c6ab83,6b1f21a,28e492f,de7a6fa5), -S(905423fa,3f9bd590,1a502d2c,7d4ac0d,2f728dac,3199db44,b35362eb,c964c8b6,1c33ef01,ffd75d94,bdd523f0,a41d629d,bb5ccf7c,9305d309,b3ab0842,16cc81ed), -S(8e799bdc,f32e5256,218dfaf8,5d08b6e4,d083975e,5ff2059f,c5b57966,3dc8cbad,60d46f36,c0e04600,bee76037,3af3196b,78b0957d,7cda51db,f1ff0c8e,fe6454ad), -S(653174f,8da924ee,322a18cc,8dc1e89,2ebfd90,dd1ddb95,6cf0646b,1e87ffb5,ace4b278,27361b77,59031384,57d0df70,9756272e,2f9af74f,55651c40,db5c4cf5), -S(77569132,e25d0051,b81f7692,d46faa9a,640e7d67,30cbb6b8,60078810,5267336c,15b2a80f,d78fd28c,d65d1e4e,4e81ef8c,37c8ae46,e66ea794,b60a0e87,f8203d53), -S(ec162da5,7ea2e308,183ce06e,d2fbff2b,3ec6e70f,e9d8ee2e,a4861160,205e506e,597cd367,d22409f5,b5737cd2,f1878b7d,c5d73603,3470839f,daf2d0a2,1b1a6424), -S(dd4a71b1,70f06062,b476aa37,aa025299,3d6d5020,a30f56df,6f31bf64,5633c6cd,ee4544c7,866617b1,584ce6bb,78627918,7222b0be,77d7ec4b,21e842e9,32c8ed30), -S(39ea945b,1d56a29,bab310a1,194f2e20,e13af9ba,5e37cd5e,d24c7203,9f4805fb,b29aebd6,9849c35,9dad83fb,56774bd8,3628f423,b724efea,80f778a8,370240bc), -S(bc774075,cd344d6d,a2f00112,3201bad3,bc52199c,b099441e,1d2beffd,16c13ae6,9e2d4f9f,2e019b0c,d3a8f248,31780f74,16569a42,58ac8f07,9945e179,c087959e), -S(de53be6a,6ee4fda9,ff2f399b,ae8b36b,b8331c83,c76756d2,3ef734da,57c60246,335c66f3,7472e014,3831d92c,bbbbc826,9046105d,64bde79e,108e09d6,b3f6f23c), -S(6cea6faa,a27557d9,d4561e57,ea755ee3,3d9f6905,36f91ed6,da93267a,fe758b88,e187e21f,4b67e4ff,7a285d97,1d42080,12638b5,ff88d4f2,ffd5cafb,6860a928), -S(fb5f6a80,5875c22,f2b4dac3,9c0a6f05,849fe524,586860c0,c3f9ca19,8091045c,6bbc77a1,f95ffef4,2105ed15,1ba96fa9,688e9e,cbdeaef6,81394b61,a4cf8f1b), -S(79a6afb,7ab3b569,e913cf30,72ec03ba,82c4aa4f,6f90be32,354286cf,52350b8a,32bbd09c,7e512933,eae14a47,fb940fd4,c60c3cc,c27b26b4,4588b278,6eaed993), -S(bacd7215,27863177,9a1878bd,800dfc59,95041824,3bbd492f,98ece53c,454f8613,f6ccba02,47279a13,371077d9,9d8e5e19,6e0c8f28,ee4ff9c5,21f2e928,c8a8dc1e), -S(15820a62,6c489416,14856974,18ebfae6,a7148dfa,895caa28,691bc056,c0e6bd52,14de4c03,8ebb058c,51b82407,1c58cac6,1bf4d105,e2f1bd77,419aa4dd,168d57bf), -S(9bf21f25,14f78ce3,5bf4ee31,334882ea,74106a98,bc5f1a56,d7de831d,8fc007ad,66962819,7a38b3d7,9af6dea6,e4d0f9a5,c03cc43,20742d2,83cb6573,7972622a), -S(b4c70aee,a8a836bd,cb3ff409,d0ef44a1,ee4bbc17,e93d233d,f4fbb081,3883c0db,48f35a4f,c9a9deb9,a454cef0,c0a2fe75,fa23ddb1,d1a2ec6e,2f16aa92,59bad8b4), -S(56d682aa,9381f1ae,4f356230,1f2f6bd7,e39f3e1a,1ec7eaf8,4894bdd9,78489b47,6c95eb11,4fc24964,b9bbe344,bdc32627,ccf1e6b2,b7ce8ba,e466c728,d348efbf), -S(7c7a9846,11fbd84a,9962cdea,1aea4ef,3572d15a,99b1f3dd,7676974e,f797b377,c1372815,d6ace43d,139a57b1,d37937a6,2f0b56f8,bb24b48e,a42aeed0,1715c7fc), -S(a89c7e,16838239,fdb87872,6c107176,7befb82f,ecb9e14,5768bab4,b823e2fa,957df64f,eba5b191,b6ef724c,18a1c874,75728177,682311ec,d709cf65,5ed37dc3), -S(7fac1495,4974d3d7,ac54034a,b497ff66,3f6cb327,506cb906,b0fd3028,f85d3dbc,a5c140ad,9a1bfaf1,ea578aa1,b14ca9fd,49473ad6,32300652,1f7e434a,dc45c4d1), -S(1e3032ae,8406cbda,e7bde21f,44a6ed5e,feb5787c,18c1ed16,1892c24,45294cf,a73be032,b2e98fa2,5fe054b5,d6d30081,b6b331b1,80124e8d,d85e2fa4,c69666ea), -S(abe408a9,5079597,bb9ab65c,852a985d,65391aa,7de247cd,76b44a02,67691d7d,1df3e191,219619ac,79bd7808,b5166a62,29babd11,e287989,65e15651,8472e8ba), -S(45ace807,55779736,65e5235,1133622,9bb6d606,6b5f09f0,76f5f984,51322f4,da7668a8,b0906440,ab68c7dc,41602d25,4bc05a78,f5a4320b,1775331c,537f3d87), -S(2ddf9c36,4dd4a1cc,c3582ed1,e44c0b21,1644c44,525f9641,c726afb5,af481780,cc3f4d02,36cdea64,cb350d0b,9c44d223,ebed2cb3,a66f44df,5e296ab6,41b61679), -S(41818580,a97d4a79,f6952aa7,db37d288,a40bf8e2,5328201c,284130f1,216868dc,4d6212b,47944485,c4e2c4ef,b556b856,2de81a46,89f0401b,2d7ac123,fc83913a), -S(905ac526,b7aa8986,1b2cd233,16455338,fb0310b1,adabeea3,a8e66fb0,5d2b7c50,f166e203,33ce73bc,df2ae289,9aab8004,568f3af6,381f0914,1d980155,7674d7aa), -S(89b95280,7022c368,d05f2fd3,10a13a24,1436909a,6695c999,f448b2ea,2be1c642,8d450758,5f2ff980,3a74f447,8a403ac,60c4c28d,54a77556,89748c58,f1efd1fd), -S(d4ab0d06,df52b5d8,9cbf1c74,9d25ac32,9abdc525,1d260933,490a45a8,bd5b0eb9,f5991ea3,6906dbda,efd4c6ad,6cd36380,9b978396,765c5ffd,f538091b,b25bf652), -S(aa3327dc,8c9232f0,48c14e27,fd235a6,58db506e,7de5e2bf,33edde07,38109ed,9dbaebe5,644b9728,23539091,56551b3c,540d9c85,3fda5bde,725fb89,d6bba192), -S(2d4b4ef0,3699faa3,a519a0a,72ea3ba1,d2f43f0a,c22a13e9,3fef213f,48b1773d,e6720da0,40eb745e,f99124f6,dce35709,2048462c,5623ccd9,f58fb739,e2314fcd), -S(fdb1cc8f,966c7bc6,8d264c56,8066a106,b102c741,11e40514,a2521dc5,5ecd5035,541b7302,a6e38776,30b178b4,b692ae76,3d59b5c5,cf5e5bfe,6427de67,c271dc27), -S(9a711c07,1b47a858,230c5111,5622f83,44808f0c,ed08c7ba,95170a83,1139b5ac,3fc4720d,1e63f39f,f4170950,78a268d,b7f9d911,3cd8bbec,6e65696f,e7e3e44f), -S(aabbe7fc,608871d5,48530bcc,44006a66,319d002a,4d0b49a2,d9c6ca4b,ab9d39a0,2ab2892b,bee509ed,8f221a9a,4f9be9fc,d9d3a2d3,3d7b54ad,383064aa,b2eb9465), -S(238bf052,fa44eb80,3ad4b6e,264942b6,da3ef420,a6c2f113,b2ce2020,9341d0e2,db6d37a1,47552f6b,8f6ec7ba,7554d4b1,49ff8372,2ed461ac,6d5d5a33,90afb0fc), -S(b276da77,f35f5a18,30ac7277,230b70de,1359c3da,c8e68155,6862a37a,6bea9fcf,8b2f05ca,cda2bc01,898d45a2,b9b20bc9,380d3beb,c5f0b346,96d4f4fd,8958a1dc), -S(5a7141a0,afda71c6,a3e8eda1,83409a64,e48fafdd,1965c00f,f711f7bb,ba1625c0,34d782c5,18ffbf0d,c6f9b0e0,b8403cf3,14cb817d,3e84a7f8,63589aca,cb44dbb4), -S(d186323c,b93ab6a4,b435154c,8c5d094d,51a8aa5d,586db604,d1fddce0,f35fe864,65c383fc,ac4a0450,1d483bba,62a1ee4f,247aaffc,7f7c790,eb4fce7b,782ebd32), -S(908bc35,6d29a3f5,1684bc27,72bfcc5c,552ef35c,a2fe9ece,f08111ec,8c368e7c,93fd8d48,6ad5cdde,c7ea498c,ba825468,caed6c4e,ac1c46bc,43411f3d,de9091b7), -S(21e05a2c,6ae8e1da,d9e4d553,3841c89,2d24f91a,aa201b95,f5f3a25d,d07231f9,d8cda13a,c6f7c54b,abcf3096,997e59a9,617b806a,1d805a5b,9d5d8621,d37a2505), -S(224de404,5c6b241b,4b705523,777dc0e0,dfde304f,c6be8077,cd831d0e,c738e33,bf8c695d,5ef0b37,52c84199,d7ebcfa8,d4988d32,f64a79d1,f0863ada,b6f84804), -S(3fbed77f,3851705f,55eac28c,f3921f23,c67a44a6,3d2dfd01,89d78835,d6106a6e,2139e1c6,4d48a58e,24306471,6bdd7098,c7644018,966a2b02,236b64a8,e628b532), -S(5adb241c,b09f712a,b5520909,53114781,388a6f2b,66218069,d6f5c758,1e4edb2a,9932237d,1be0cb9,2d18dfcc,6ccced53,e6cfee60,d897b6c9,b40c3ee,2b5cc9ec), -S(a4396528,ec7f9a,cd8550a7,7245eca6,117c4e8c,c50a51b3,28063d68,a744d7f0,efb8924d,7f921890,71b1366e,e8d0b620,af274d45,56f2d992,ac709d71,9f5252d3), -S(e36dc303,56a9e037,c9ececb0,764aa755,e1493e23,5ddea3ac,44ed4caa,4fea7bc7,338d5c5b,f5a84dad,5e865696,2ed14c15,70d4eb8b,89fa60a9,973921aa,dfd44353), -S(a6c6c231,238ab32f,361743f4,5d337eab,4a529a42,dc45f1c0,670fcbd8,a0dc22ae,4a3433e5,b415460e,4816b9c6,c1db0657,58aa6279,ad4f47c2,a5f07219,c50d00d6), -S(df09e277,b56e0f7c,2e93d8e4,d47778a8,3aa32c99,b0ac74c9,d64ffe8f,5e44b900,b77cd700,b6027f96,9c80a4e5,a2435750,35ed890e,30fdd9af,b41abe4d,81de4e94), -S(803abc31,138b3d57,9a18a580,bf0520e5,d9328812,14f5587,e49371e3,fe03b02f,a270bed5,2ef7cd2d,4d5cdec5,9d92c980,6e700c33,a487b4e3,f507332,99b54aaf), -S(ad15ba0b,c5cdcb53,6b55cb2f,171d1db0,712ff30d,b10d05f8,bce4d70d,22bc0bc1,fe7faa5e,1699e6d0,1e31be29,b5770756,fa6485f2,f3077f82,33789582,bb5949e), -S(85cdfde5,65959eaa,d025b6a0,1616b7ee,8f710833,187243dd,1103a0ee,65031993,facaf5d7,31fb65cb,f10dbf78,70ca3fc6,68a0581a,4eb73326,15d03f4b,87b53204)}, -{S(9705d56f,f75c7d2c,bacc47a4,a6cf8b10,300c688c,fdbd1b1,528f41b9,652d49fa,c53f7f11,896f2edb,fc957dd7,2cc90856,c5df9d86,43e42489,70182843,84201b98), -S(69db829,eba841e5,c2a1d54a,7f8857d4,4e898caa,fc8d990,eba45c75,9986958b,6b5589ec,635f24b1,4892d895,c56cadae,635de22d,de7b5b09,43e1c4a0,d83f0120), -S(4a8da056,c550978c,725da71f,6cf59df0,e13e3d86,b2255f10,827060bb,9af50961,abc04394,216df6bb,1052db88,e23237a8,13985857,a8048c7a,51787b4,ee7913e0), -S(775d4538,834d66c0,d41a5627,f2fbec9d,a5ec1e12,dea8572,7a32413a,5cbc3612,2c423943,5281901c,6e6665e9,d98655a4,91477e73,fbb3874e,7793a3b5,4b2ccaae), -S(b9eb2bff,b24696e9,36393471,a13ea71e,7ad68377,e78b9eb6,cb40d9f2,7da4632d,c54bb96a,383df77e,a0d77c53,ae2fcbaf,ccf53c73,99e4ee2,faeb338e,8cb40e8f), -S(a8aeb77d,ddeac4b2,71efb2a9,4f44dc31,9f32a0b9,7a1d0e67,8b4bde2c,a3a59233,8fde1a77,e2c76aa1,b5ba70da,dd37af0d,d98115b7,f17d26ff,ed936a7b,5803374a), -S(16f1cb1f,1e8bb14f,b475b130,ff1d0ad3,167b9249,efb9fe20,b31ab365,cb92fc60,9cfb2bed,8c1eb7db,6bc1b7b5,baa88916,b8f68fbb,d23be873,3c54c038,3ad0ac4b), -S(64563829,eaaaa500,c57bee41,f356b8c2,fe7c89a6,93ac0fc7,35044ded,5ae6292a,7298e685,c9bf4faf,bbd527f2,7620ae5c,2c3a342a,4c8d919a,72afcbbc,8b53a50c), -S(614092fe,2588e655,484871f8,3479d350,319b21dd,511e93bf,db81f898,7b2f3137,d10cb0e5,1201122e,fbcb3788,133fc545,7b0a4569,b44ac629,31421019,909adfbf), -S(e0b693d6,60f49c41,d3dbe7fc,51fba3a7,744a062a,46b57b8b,36504e9a,1585f5ea,21cb0611,a5014796,a744a507,2a4ebb2e,41dac48,87bd660f,e1f14a39,819e8c5a), -S(f3ee19e6,d27afdfe,a932fac,72f25828,a6f52c1d,671dd85d,3db0426d,74b8439a,d7c32438,6b62fe7b,fe894468,aff8262c,38bd0eed,4374c9f4,618d16bd,e2925874), -S(fcdb259,b019b7c0,ad0b2e93,f07a89d9,e26f121a,7974944f,85dabfbe,ebac9359,883cb06f,fbe5a647,60711b8f,d99783e0,4f59cee9,31d5a3f2,2cf1d692,894fe4b1), -S(bcad7844,a44ec239,dd113ada,7acf73e8,6271c920,72afb585,60b0f002,a09a539d,428f8d0d,529add2,73ff3728,83f92160,940e71f9,c0a06da2,3084363b,a2586edf), -S(8d54b2e0,f4083478,d6a2ea0a,1416ea8c,fe176621,30e2bb28,fb733656,9ae4ca98,c6d6ba83,fd780d91,ecc8016f,841fbb62,1726fda6,5840f183,7ad17bc6,33106a3f), -S(c9513674,d582a1e4,d91f6ef0,55920a50,1fc230f5,e5bfcf42,8c1b15df,d7f3a8e9,d01c55eb,4d685119,8026badd,3425d4a8,f56e7ba2,6c306b32,5686e279,81aa5cb9), -S(51268b15,a1d43b33,b95e92e3,cfdc7740,679cbae8,ff6a36e6,1da3a34,c8eba7ca,19699ee6,98d95b66,95e21f40,64421d25,a95aa7b9,9eb7ff0a,69331e34,c24952ba), -S(7b46c85d,6364fed5,87230ce0,9e932aca,ca356858,1ecdfa8e,f9b236e,1ee7b671,edda0f22,6808b01f,2bb5df80,2c9b613d,469eda9,e90be70e,4657342e,67519cde), -S(bff9cc3,b68413cb,9f9eae8d,f84adfc4,563069e6,28ff023d,6ee3cfda,8f97a935,651a2d85,cc10831f,f1571320,500415b7,24f232e3,30f47261,8d482924,40259e9e), -S(b5370f4e,f8b3af3f,3e936c34,e7c8cd89,21d4ecc3,7e5a5c0,a205fd37,9abc0aa8,6e889dff,6350f4ec,c3a413ed,694c1ae3,367d463f,be212a76,bc2a5a4a,b59bb09f), -S(72623c52,8e665a8,80c31e78,88b5777e,6b53f02a,6ede4aae,f2ed3bc1,ed351d42,4e2c6c63,c762652b,43383c13,806162dd,1992bbdf,88a3c714,a5f29522,a0db689b), -S(446e4144,8f66c9b,8eb06f5b,e8fec592,9abeacb7,befae28a,cae5091b,798d4f0f,62da012a,fc3d4eb3,4207db5a,8579c581,6a8b1543,b201e1f2,90b413bc,a57f7306), -S(428248b6,49cd424e,12b81504,46443a3a,b6e921cd,79e9344e,4613c653,7d0fc039,864dfa6a,fb191af,91286054,ba7f09fd,75e3d661,c91f939,ef834325,aa26703f), -S(c252c5c4,13e2a430,18ffeb55,355644a0,15e04cec,31424a41,9533af9a,eac0b688,c37efc23,26a2d965,9563b7cb,cf0953f8,cb3ec5ee,3c7ef263,3a6389ad,eb00fbac), -S(b5feaf98,f617055e,b976f63d,55901b93,7e63662c,5b6453a5,79a0c905,c951c037,5372b044,fca66887,566df1d0,6fe0aa12,d8405f84,529db971,a6422820,e6ce7f08), -S(c628a5d,72550157,365031d4,fe16f6f7,94636130,94447c07,e767ec63,8d62986b,539fb7a2,9bd686c8,9e98a1fa,ba95a493,2650b98e,f92198c4,534e58aa,39de796d), -S(f1d0b5f0,d6e30201,2bb50ede,eaf78813,f0a72315,6ef086a4,415e2d97,44acfa73,cd8accc8,fc951f05,5409599a,6da7e5e7,beee325f,2a7466f9,9be63efd,f6d9416d), -S(1d46b065,ac7fd9ea,5771363,dd2ca1a4,cadaf6e7,8e93a037,87aec58,af30f179,f3518f13,c9aa688e,7770d0a,d4dd505e,a22b4430,402ec3a,664fdf89,e9b6e752), -S(2bc0409a,b43950c3,16588fb6,51db2509,a66b074e,6df5d35e,a2ad0fa2,1dc32dbe,2a6df1c9,97bdd5bb,c831d308,d292a30e,68e1dc03,c16ef2a3,183ea616,b16a2891), -S(388a72ca,cfb9856d,174f0937,dc6d721f,63f915a4,6c2fb4f1,1b0cb296,8390109d,2f70bdaf,ebff44d5,b7f6ec79,48184e57,63831421,5dc35d40,48e5400b,dbc84d5b), -S(5404f49a,61865863,859fd7d4,2f008480,e93d8c50,3654525c,38c09ed3,66f95640,71626266,fd861532,a73eba6b,69c6fc4e,2c727ba4,b10e6274,821f3b71,fbd3ab2d), -S(eda6db04,9e8ec72e,c224ebf8,417f2123,8a50b2c5,b149d4f6,2a9bd2d6,78a0f67b,b016fd67,fb3f3fbd,7e53c210,94795570,7ff177e6,38f5a8db,74847496,5618858a), -S(3b71b31e,eef08efc,571669dd,c4deee31,e72f898f,5c83766b,8e58db66,e0c6b4a0,8dc3e307,4780ee6,b8122e3b,d6137998,1c80b72f,66f9f3fc,46bcd11b,a78b821e), -S(1ab86db3,750a687c,39c7a672,c115c29b,1f8f4ba8,586b9957,6b6b1894,7858d52,f60a122,80e05d3c,cd0cfd97,e1029cb5,728ff2d2,df077af,13645402,51412618), -S(eaa96c50,98e79e7f,27b3887b,39a6f74c,983eb44a,9b9fb7f8,e36f4582,596061a,4da962ab,c183ec56,5e37b1ee,3f75c531,3be12425,df54b4be,e4510b45,a84969db), -S(b3b4b315,6609efaa,7964743b,c6789f67,8e40b123,c336f64a,51bb322b,79a6e569,30d6e2e8,4b2cf3cf,e44b86a3,6f3655a,4e1b8e5,442084c0,454f5fde,c5cfa180), -S(1dbf8ef4,174e8259,ccb03ff2,bbacced,d04b30e2,301a4627,77669f9d,4e02f006,6292dfd9,f5df7ab7,31103e38,da6b59cf,4ea57664,887e8804,b61492ea,add33edd), -S(74a9e0ca,b7f1168d,d1ddd81d,fd00e731,7acb92e7,a81ad625,6f655fbc,561dcb05,aea7175a,f97dbff,a0ffcef7,1c89a8cf,d101b3c0,6f424d9e,bced721f,19578d7c), -S(17d35d3,507f39c8,b7429cd0,9c04fa49,efb0d47c,a0c1a0e7,6a303c85,ac5d35f0,88a8998b,603095ff,1771d3e6,d7d69ce8,268c8f6f,20df114d,88cf83c4,e148c4a3), -S(890a566,fb2b0ac7,1a269b9f,90a20877,3611a6c4,ded7874,ecb8482a,f758b0ec,6cd1086d,8ad35581,bf49b063,b1818b20,8e2cb340,17a9c0c8,1a197450,e8d7fd8c), -S(13d1b6bc,13d5b669,6a6a423a,906476dd,d3a671cc,ebd5e119,a8cbf6db,622ecbb7,1099ec23,c79d6dcf,3d2380b,eba653f4,a3fb4bd5,bfe22e4e,abd2e57f,3953fc85), -S(775298a0,c8968fc4,6c7c7e7f,571a784,13ad7766,a9409a6b,6ce02a2b,3e033934,2c3640fa,17aba57d,e2dfa700,ec4ae691,28579db9,91ba8670,a5d8f0ec,b9009c86), -S(ccdbc86b,a89a8496,35c20279,223ff5ec,8a545acb,58b04b53,eb2aea74,ef56ccad,9d229bdc,2b1731a5,730c8f75,5edca111,c52cece1,a65949f0,f51525c6,2f4e6abc), -S(704800e9,c4e03a4d,9aa9e41d,8619508c,9d17766b,217a3d3f,cc5efca0,67594157,7da8e92c,22174290,d08c222c,db33b345,c45388bc,da9434d0,99514d59,2660c24b), -S(3b958586,e7bac33,711be679,30158ea2,38bd6801,f087ae0f,e694e482,a4654c06,93e08192,d074e631,6f7681bb,49b9398a,cda6fbed,c42d372b,2bf3bff4,66ec70dc), -S(1ef945be,6fab11ec,4b48a57d,d2c3ec3a,5eefe46d,afc58284,a005e02f,6d5a8dc,1ffb979c,66ab8493,8a12fc83,52eaf5ed,431c3d14,d6e472cd,503bb1d4,1180c069), -S(72ba6f,627d78a6,c265ffcb,2c8a1e3e,c716f52f,4dcda188,4ab23325,b3bdb1eb,7cf1eef7,aca4f18d,1b1324d1,ae6bcf24,3c870fe7,5a977c6a,c6872ef,c1602afb), -S(2fc567f4,3df8fed0,1eed527f,8b4338d6,92143c20,13b963fd,343aaa4a,ae3e971,c3375e3d,e52b9c17,647e36f0,b4a60031,5837b2e9,c61d039b,1e934ef4,b9cb8864), -S(6c80f08c,30b3b243,1c3a4b1d,b2cdcae,505c671a,11dab05a,4ecfd68a,e5cbdec3,46dc33f8,8b54e177,88358d5f,bfc4c834,4e376338,8cbe10aa,22ae5062,5d3ed7da), -S(587724ef,65997e21,e38bfc75,80707319,c3065fd3,9dfb9cf6,fcb3de84,d28a0f3a,4993a8cd,7f22b55a,88818c49,8eb18807,a93d1246,f0f1efa5,6ce0efe5,68366dd9), -S(f82fa826,8a43213b,5d871f8c,fdb6a6d1,e706ad8f,2b8930a2,c495bb90,39d1d5a1,78749a3d,b47e256b,9ab3ed40,9b9ba1f,741ddaa5,431f4f22,896ebdee,8ddb5d98), -S(18177602,341d74bf,9ae572c7,d60febee,fe37fe20,80c89722,434b9ad4,3c935dd1,aed1c747,a87e00eb,2fd8ca9a,b860ebff,f6ff6b6a,9a2dd505,534b28cf,1f37f7e6), -S(842785a0,11028ad7,4704fd7d,15e9284a,cee1272d,936c1300,d8598623,de359971,d507ec1d,cfe03f65,61a7b192,6c14e4cc,dec54fb8,4587a9a0,cafafa5e,81b35f77), -S(c22076f3,441370ae,c874a32d,297b54c6,f284efb3,95741124,21428332,140763ce,109248e7,857ca454,cd9fc292,731d800e,8a29d13,e557224,bdc47992,717306c4), -S(14c75d2,c7f48020,7f6c7b1a,ef4be041,d2c13f4e,48a9d9a7,b4809f2f,a20ebc67,267d7fa5,be716683,2f48fe5,f782b719,c707edb4,4e2eb6e9,3217e6d9,adb78647), -S(ebbf722c,67339545,ab15b2c5,f6c517e2,e32b319,a5c526d8,656ab4eb,4a72486b,2c56f524,3d33c2d7,7c989453,3108ae44,f8b5d86c,9082fee3,c99236c0,258e42ff), -S(9313e212,4ad5658c,9a50fd28,70af7f26,9661fefa,41b0b5bb,25b8cc05,9b8a2892,92d4a8ea,73210fbd,a730c8ad,50a19e7b,11f65025,a2fb2915,7af992e7,b9d449ed), -S(5549d2ac,f2a7b23a,908d1529,696530a1,41ffc39f,323cae7,374666c4,12d9fc5a,87a51da1,f8766aae,f1161369,67259d,6137b607,b579a215,59e9e3f3,3a4368b7), -S(dcc897ed,9f994741,1e15bef6,8eae2771,27ee8d5f,b2ef8ecb,f47e057f,801c7b1f,5bc17162,f6470848,a4b222cd,357a4e63,c3a15ce0,5fecfb1b,19290b7d,6af6bdfa), -S(a9ead801,344ca82f,738dc5af,85534bad,d320aa7e,2af4420d,b4479cb7,d9d747e0,1e3f6e3b,d065bdc0,99630291,9f2e408,361c0f,76ad5c7f,4ce3f220,a69fb30), -S(4e7e2308,67db8bae,df576eab,ea65f2ee,23efb749,e0047ec5,370b0db3,2897997,6f59c99a,15fc73e8,e393805c,d04a1254,5b8292e6,e8cc8cdd,cc426b16,90b9643d), -S(6d52baca,67e37e9d,cd68597e,f2ec6b83,27abd9cd,c5088043,f420168,726d7c8a,8e721f7c,7d77b0ee,17f2bcf9,b5b1b9b,da9545fb,1f4d4c7c,d544f070,2af986ef), -S(2b4bab06,bebed117,b09c6304,18185408,23b27f24,72223ab1,9dfa9d41,25271d00,c8e41ed1,6e4812e8,c32b8c9,4ec4c4a4,f3f00c7e,2a5bfe2d,27b6ea9e,82329cc), -S(21b85eb6,104564aa,c8b070ca,52b993af,4260e911,4cec2a4b,92041c05,f420285e,712a8ae5,e03bfcac,f6d39f31,ae20c22f,c702b364,35fbcdb8,6a14b1be,7622ebcf), -S(b95236b8,fe6becfb,98249114,a26e910b,62bd5286,e10a0dff,dd145b5f,ee2dd84e,3f0b83ca,e4549f4d,4512b410,57757c4b,7a3b115c,32819af7,6c31d204,c029fc21), -S(7b2b3f20,5debfddf,17bd4922,188c6bb9,a1dfdae5,910803c7,24a6cb4,d5f827e4,4e60c6c4,c1932812,457f7bce,98b8b77c,66512966,9149860d,726b3f08,4beaa2a4), -S(b2333534,312b443e,3d5a5559,67da3b7c,caca2947,2aab9281,d389e10e,2071cc71,5bb0be9b,d27c0b27,b2a2a68,d0767f2e,7ef79a4b,4dffd183,2163d7fa,9cf98ba9), -S(20067cc5,1be142a2,b6f5f30b,18fb52db,a675bf8b,669b1fcb,d297f73e,93920522,a80c956a,f0206a2c,74b11133,82fcf2ef,883114a7,a72012b8,d7dacd7b,ef696999), -S(d092a75,8080d695,2464009f,672a00ba,f49d884d,744a749b,fd884228,8670f2bd,da092b71,78d8a373,fe5dbb6b,2822c9e3,901b356b,714044a8,6b70bc5b,e5018f9b), -S(91f482c9,2e9c481e,79b596ac,e716270a,ee9e9cd0,3d502c9a,96a6e8ee,114d6887,af9bf0d1,ccb2bc3,3d8d3c4c,20346223,19104e3,53ccaa29,4de71967,634e0b08), -S(51bff42d,76705ed2,334de997,dc6d916d,86274f42,494a86f1,e57ec18e,538d195,2ac758d,cfb59a56,e483d361,d7a5e3ec,de0a640b,f94ac8,cb9c4a19,9fe423c9), -S(285483a7,8b621501,b294bd80,3469a136,2ffce135,a526574a,38d29d66,c69733e6,c5f3d286,f82fd0fe,f799902c,76421359,921280d7,72a91c42,33379711,e55a1e15), -S(848dde1c,490b4a3f,2aeaa7e3,97cd2840,23539cdb,a3a79752,601e5868,a29d7110,182c5fa8,574c673f,91302647,2f9fda27,dee3f57d,19c10e04,e84ea4,f532902a), -S(bed1c6d6,82d48d91,3b6ece9c,c71cc51b,418d6f5f,f2f5fc78,f4d27bfe,8eea513e,7f278fee,8696dbb3,fc762602,dcbe1a5b,653b8738,e93ecafd,8c23a90c,d82aa45c), -S(46d3d211,67a906f2,64f7ea9d,231cf44d,f523afce,8b99c3c0,b5f88ce0,f19fad02,7da52bc,905f1f2b,78c798f4,4ff85e90,c4b7ca2,4d2ab28b,cfee6cc8,373676e9), -S(7fcc6146,3554506e,931212e3,fb68719,914943c4,a067c3c9,a0952225,c5f39fc4,ac90244,c5d5446,20b17f6a,75cf6dba,6a05895,e1f3a097,85fd6ba6,a440ec68), -S(a3cd5ea0,b43c25e1,c45aeae7,1d05fab,e9009262,8b544d6c,364abd1b,a4c0b9a3,312ab3bb,fbd8cdab,1c7d01b1,53baab40,517eae29,b8ccb28f,27278a3f,7bdf0b85), -S(c446daba,1825a802,1d62796b,1ef604eb,d905db5f,9874eecf,7be2ef0b,1cd2e9fa,1562aed0,d869425d,3adfb280,a959fbcc,195f632f,f6d8695f,f8eb3381,f7f274b1), -S(77c9a086,1095246e,b59ec6b9,5af0c435,a64ac0f0,a238fa70,6c5aaaf1,3d9e32d0,8a89b6d,442a911f,66d1c966,997331a3,db74fdc4,a1305ec9,e13f2c1c,4f1524e7), -S(19e2aaa4,fef00f4f,64ec5b45,d8cf58f0,37ffecbe,f305ad18,eca01edf,33e62cd0,2d636e48,ab56e09,12b922a,d567164e,93f6185f,4b3b5b54,73dd3b62,5a1bf359), -S(5e6a3b49,60264ebd,1b98d889,5722f263,471343d0,a18f540,141b6d17,f5d0ac3c,8f91deaf,390e1d5e,dc5c329b,b8a067a0,e5f497c2,39fbb4ac,3de3c3d6,ac61f35a), -S(6d90b780,b75219c0,5e5f30cb,61f5c9a0,44c446e6,8bfa56f3,f80d54dd,6c06aa91,6e02731a,dcd7f45a,d52a3550,f6b37f32,4a913c2f,6e48f264,480e3248,a06eeea6), -S(e4358de0,e3e65fa2,25d164dd,cadd7ef,cda7a801,86d11fd6,92222d90,24131cdc,8621625f,69c4cb56,67f92d53,74bf8746,aac1d17e,a9401978,89aa4db9,677c2320), -S(6088bfbc,79b7fe62,df884d2b,ff605794,9659ed63,3d9b7543,ffa88cf6,db81063a,ff27059d,811db138,a061d6fd,e4c289d1,54d7c28d,1a13bac0,10004c83,9146cd44), -S(89aad23e,2b364a3f,6f4e218b,2a519c35,51b58eff,fc0b264c,549e2d41,f1552464,1f1e9915,1a56f61c,e48f3a75,4fe02fb,2cc591e5,8e7289fe,39c88345,3c868b10), -S(c354a06b,468e1503,803d69d5,919a68ee,9e60509b,7d85b543,dc06a004,215525ef,e6656a2,bd6c2569,aed8d779,e061842d,3a65f9ca,a46cf5cb,11a870c5,3411e09f), -S(960513c9,bf25992e,265e09c8,4749b4fc,d3dd1b9d,8de5ba17,88099526,2e2fce90,f2cee526,e2f19b4f,b089e3e5,aa4f3d4,dcd5be51,67afb83b,4471a220,f961fe26), -S(915bfb4b,e41aef95,f4b84b87,5f4b0f11,89397160,c8b0abc3,5c976a08,29c7b534,e1238986,b3b6ea5e,528fc6fc,ce95be98,a0490c37,e2964739,6294a245,5580607f), -S(54a414f1,cb9bec65,f1e8f09a,f12d91de,8615f47c,370a3a18,78beeee6,8297e07a,9d9accac,fbf02cf3,a99c5d58,9e9cbc3e,45e9080f,1d345fdb,93ba4306,c6972ae2), -S(4495cbdf,4f71fc3d,bbaccefb,1eec5f13,acdffd13,9a0e9a5,cb798086,a8a46b2e,1100fcf5,8f571f89,4b625179,31a33fa9,eb2683b8,9d6f9ae8,748d6615,7e40f6fd), -S(737740a4,35247754,b4264e73,7f7c4572,94bb0b0d,102d535d,86995ea1,68b7aac7,601553b9,eb20b8d6,8a0b9562,139d75e3,d3003a4,12837753,29c3696c,42f02f63), -S(e0dfd6fd,1e6def44,55afe74e,dfa69eb1,310ea3b2,6d55a13,73cc0118,7ca720c4,e6d63ccb,96084257,8b764a05,15ab78a2,a5afc188,a8f7a4e1,52adfd3a,e56c6bd7), -S(b4ccf2f2,4a114f61,cb24bbcb,f300a643,3190effd,4930afac,fb2bd4e2,1cffbcc0,3d9fda60,7a752c7e,4316f355,fd0fba2f,1f38bf3d,e9a78bf5,5ebe58ee,e7d13a0c), -S(9efadc19,dc6bea69,e0b4a59,e0bb9e35,a1d4906c,4d612da6,f32f7f33,c96345be,19e891e7,b714e7ac,32f801a,bdc2904e,df8882c5,dbe25ad0,f414fc95,da4915bc), -S(3a4058b1,cfc8bd88,499ddc79,796f07ef,a59bcd4b,bcd37137,2d76f95e,bc177c95,d3024cba,358ffffa,aa3a95f6,cac1dfa7,1d5d4f59,91598a33,f02f3141,81acbee5), -S(30ac9730,53bfc762,7f7bb8e4,a97ce1f4,3918418,e3ad8f1b,edca9bd8,dd7f6ab6,495b6849,a4d4d9e7,8ffc49c8,976b5f9f,a631e1d1,95fce967,416659cf,f91c6147), -S(248a974b,35f025e6,1a462050,38a0a856,d136b68a,2ef09691,69332629,a35cf2e9,b25a8e72,efb765f2,66794992,9b3ae32d,f148021e,63aae20a,d4450e3c,6b5fb5b5), -S(107899a5,11fa2b90,fbe5889c,fef115f,f0c9cac7,62f82cf,12487318,63169a2,ea1c4278,811fbe5a,6f011375,35b584d1,a85d3236,c66d52a5,845a6ffb,3706f8cd), -S(91905b3,e5602f5e,6a780acb,4a33f7d5,4d87b239,dc9f19e4,99560d22,b062e897,caadc62b,71d3fcc8,d9d5e410,7a11fb75,832693af,46ae99e4,d8f7d140,900b82a2), -S(e103d0f1,1e7bfd74,821dd503,53b08f2b,3c56338,f4750fdc,76b4bbac,f7ab2404,eb65ee56,1dbd1e1f,d5437b7,b86b1502,3bf423ee,f75e7620,aa6558c8,a039f741), -S(f35e2c54,f2e8f2e3,fdd18dbb,e0244de4,5b9fe772,7c00727a,5f12d7b1,def1c45c,a01aaabe,85682057,b649ed03,e9786133,e5d22cee,4e5c56a8,31bb310d,fc03cf78), -S(5cda0c4b,ae3e3ab,8aeaf59b,ce9b57bc,da0d8cc1,b638cb8c,aab26347,e8188bb,d992c965,4e8a3d6a,4838c9db,64fa1114,e88986ad,da948ddf,52ca17f6,f600c219), -S(cecf5b7,1a36fd7e,2990dd73,9fd150e9,e6183368,436b9702,f9dfa05d,a88220a1,34bec823,e6cf7184,f837e738,3c4b5edb,3ab3f027,d3034639,b038efee,5dafc8d0), -S(5761d842,db207d20,42e3df0f,d95f13b,8f09210b,c7c8521f,4c33ce69,5473c28c,31c68feb,48e1eb87,afa40cd0,a4e55c9d,862c914b,714a290,4dbefb01,d59e4dcc), -S(d4b5e716,5ed18b35,61994dc0,e2af0ca6,3d34d053,d89d211f,4157434c,dae8b10b,137db71,89d25a86,cdcbc931,ad30c5f3,27c368e0,6beb1335,746cf6d7,bbecb07b), -S(6e9a9ebb,9cdd9729,f3bd261a,ee9ccc5,3d55a9a3,fb79d370,489ebac5,9951df97,32db39cc,a1a862db,172670eb,132f79cf,dfeb7022,ebe19b87,3d9781f1,1691f4a9), -S(ab4f56f1,941e7a55,7f7090f0,ba8b10d0,13db8e61,f702ec07,c4b99b2a,a54e12d0,c1a1fc11,51f23ef9,521ab291,cff740fa,42e00fd7,1ed3012c,86e72709,9374c637), -S(6f9165f7,e1f44fc1,1f7bfe76,7e8f7f77,3d25caec,17cc7357,d0b99ff2,1258134c,350f1c38,50c74078,3dc7a5bf,3b590cc6,45063e44,f46dfae5,b1c961d5,822b5840), -S(ba866c2f,67d4b6f0,8317a5ee,32519cd0,93c17fc6,6421a156,a4056eca,dceacec3,93fa72ce,612e210a,42f81d5a,f3c16d26,36895eb5,4e2d8d98,e6d3589f,d6ec72da), -S(35834355,a9445a8,40cd6b00,72e6a3be,54d80301,7da65bbe,cd1bef4,6788ed6e,92097690,e15e333b,55aaf635,62676402,cff85231,885060a2,2a29f263,667e6b5e), -S(50864d50,6835ed6f,86b25b45,11db0367,d88de358,62046623,573e35fc,6524b4f4,e970bd97,a9692202,376f485f,5548a980,188650dc,91ea1351,8cded8ed,7724508a), -S(ccaeb079,8fc41009,fce22bc3,3f191412,4be3fc03,cf9031ea,84f1a017,b9d5b3e3,b0ca53ef,45ed8340,f448edae,2ff784c5,c0b3bf3e,ff93cba0,8c2ebfa,eaf64df3), -S(46f30e66,cb54b89f,17063c32,dd1543e7,e73d4a08,758560a6,e62e7329,63076c0d,b84bafbe,69b45a62,498dd9ed,d202506b,9be830d1,6d6fecd5,69fb8f96,6a6a3042), -S(265cd9de,e006d582,45a04fc8,82f0ba5,b7fc91c3,6535e748,514ec587,c7f80327,7199f872,7a6d937b,6347d351,2b0050ac,a8e37652,3d922cf,f60c4b4a,846a0f57), -S(31cf7fd4,4e30a151,5e8a06e7,347416ce,104338af,3cc8deb2,ebde204e,de6fad28,5e1a97a0,bb0d965c,ece3be90,b971fcb2,a5d52ddc,5f19cd1c,9db15671,e5101d4a), -S(61110e5e,f84ac25f,85154139,d8d6c850,9ec024e5,5f796b69,f69e7bf6,3c41ce05,b67f5359,bcdfc138,963568c0,b386996d,82b77005,563cf104,2736856d,e548abf3), -S(539655be,97322448,a93f3760,9e67a02,ae39b00c,ce1bd156,cf9e78fd,65788661,105f9f23,4f075bd2,dbc1b74e,3e81dead,125792de,6025efe5,7463588e,eb5a7015), -S(e899c784,7f0b1e06,d4dcdcd8,1d978af0,aa00395b,af7e82f,a25c1534,1281b81f,f37e6134,1687ee5,942992f3,138238eb,1b2f13d0,7353f69,905c0b02,f629f436), -S(ae2d2d8a,be3313d3,33ff5efd,3d31b73d,799b1684,47478e38,7821ebff,8d722ab8,680721ee,9acdb2a,bf38c78a,910cf9a9,3beb66ff,d086c982,639ef987,3c234ac9), -S(b9e7abb3,9eeb4754,5d79bc29,97187c99,c41eb1ec,7fd6eda4,33eabdb,d60a5470,638a8f7a,b02eba6d,84d23582,46180a2d,864be6e5,a6abd36e,b2609ca0,3d0e0ee4), -S(2b20a9bd,a7a6730e,95454586,a6778672,6bc18e60,9a765fc8,c54cfe75,ea0a5a06,2e442fab,623d335a,e9c2a2d7,f89349cb,cd2af4e0,218841c6,d5e0bb9,22d0e382), -S(72fc3a7e,46d9a6be,f381e977,7253e8e5,f9db3afd,46648e8f,33b65080,ddd2d199,85cdc38e,d45cf08d,c23ea251,cf8a8c49,6ee654da,ed173c93,ee380d30,2a0f29bc), -S(db069c4d,3b0faba,af16a827,74452e57,72aa87f4,ff3b97ba,cf17c75b,349e4d86,b794f792,85fa96f8,a7037f7d,ca851a52,7a83afca,26965e73,6408ecc4,1247c3e6), -S(7cf3ebd5,aa1b2065,7d7d0ff6,a34a72e5,60436327,afd1f548,ef45eb4c,46b01b82,51de8d27,2ac224a5,2e5c2645,1a9863a1,8c9f8c03,43663023,d7621a9,21f1d855), -S(73b0a3f3,233b1fa0,30fc1062,69453fa2,2120b0f,e6f91d1d,c637e0d8,6573ac63,e04e33b0,b118fd12,30a816ba,a5ad9265,90ff186d,7187a7a8,cb740e29,8de71787), -S(32769d34,ca2c15e0,6e520b40,6a8cafb2,1f541f25,130dee67,7f4bc606,d3480db5,59ee4d85,31b67173,a8c1aafb,83ba9ac7,2f72dc7a,238e1630,5a3ad39e,d508334e), -S(bce22865,2f6cb032,82f50e4f,c834216b,59a6e9c3,e787cc81,fe8391fc,3f2b7101,d5ec8a38,93820cfa,85daf98c,281c1059,51986ac5,5f4ec530,925db0e8,c98661d5), -S(6911f551,e3522b85,93a1160b,356a5254,968a45aa,cb9fb870,37e3cb28,7674ea84,d26573f4,f3a58064,83d6d814,553f8dfe,e1d3b413,66062b42,ecb1f4be,56c39839), -S(171de86c,6dbcd466,2cc5a0a6,967dea53,46411198,a8fad3c6,a21761a0,5f3303df,4c6652c3,ed4e1b35,119473d5,96ce0350,19ac08,acfcc66b,8664c86,21288b0f), -S(8afa0269,be8300fe,592b612b,19758692,bed5d98,6374838c,126981a0,60a8af40,6f93d092,f4d82898,7d3aaa28,d8764c8f,937902c6,a2fa6380,91d4e6c4,d07d8eb8), -S(9c6f623b,1feb0699,59b129d9,aea3349a,13b92c41,ff7cae56,3f39adc3,474a3721,c6033ad1,f7045dc2,76f1937d,31d01a83,cee9a2c2,e6e8e0cc,c130c852,76a76b78), -S(5c88e5,bc110d8,ab0e77b1,e1592dcd,d576774e,4efc3499,5d05dd43,fdc8a22a,33edaf3a,e34fc2ae,b2d1743,c5be7c31,7ca09368,8226b5b6,c98be55a,18c162f1), -S(244116d6,b514bc40,7e5f5ead,624efe69,dcd1997d,881a6490,d2db3517,5cd57fd6,e9194bf2,e27251ea,60f4761a,5114d205,c4d2c13a,c9fe5887,61098e90,beb5b353), -S(db49b35a,9dd72d8c,8d0f0424,20c769f5,955658ee,7eff4ced,9dd7d31b,c0252dda,222806de,3c908a10,c71528f4,132e59b5,d14480e2,391a8aeb,8a6f7de6,1c3bc66e), -S(e208bc35,609acd41,72adc7f7,94ba78a7,9103d213,78c1ef29,7dddabbd,d782598d,f8b4fe8,6f6f1fb2,3c4dc711,8991a334,7314a3d0,1428fabb,6167bd64,dbb31e6a), -S(2da52754,60fb82c2,d39a242b,fcbf3433,be971662,acf9c5be,923859e6,443f3d61,6270758b,6974d5c7,3e5139f0,35d1e218,aed29c9c,bf17b6e6,b8ac6708,b09c69d7), -S(3df8292c,e26a8c51,3e5af6f0,4bf7323d,de655d97,dc00ae71,eb8e1488,bddc3132,98b07c95,c45573a7,97481882,b2f91bcb,6aee1d75,21377640,b6a52721,9d420750), -S(a2a22d6c,e949e74f,813c68fa,587c00ed,3c044c2,42456a6a,70b83f30,d8bf954a,6f4c0800,efe49001,9770f0cd,ddced4bc,d9a3994f,a1721cc7,df0576cb,e289b9a4), -S(8a240ca0,aa79c339,b274df12,b5d739f9,97a84246,b330c28c,fb148c8f,dbe40559,e8aabf1,7ab14974,899689c1,113e002d,2a410d3,b06cc5c1,d0fe5eb4,1bc480a5), -S(fd61d479,d57d73b,1085b312,2c5026a6,588e64f9,f642148b,589de7bd,418a3b45,e0e660e0,642739ac,f2127785,dd23475d,e83dbe72,2915b732,cd19dde8,38b240f), -S(b9cf694,82581706,6565e261,e9c231e,4e95ee01,4a8eb744,12472b86,d5b2861d,969b8e83,a3c2b9d,a4f496bc,b4f7cd78,a7e418b4,c793676c,7e1a8c,fa6bd33d), -S(91ee433b,c5c7e9e9,becb58f2,bd659171,2131260d,8a26d65e,b3fe33b8,442fc3aa,86215e62,1cd6542f,32c9ac7c,930282f1,de0cf7bb,6f6f46d7,a29ffa28,22127b70), -S(1cda7a25,3e8caf86,bc67a7ce,7fe66799,e4ece2c5,64622557,f3b402e,e4b6a6a7,28e11403,94b46fac,df5950f2,9f44a66c,e0c0fdd6,942f1856,db17019a,40cc7623), -S(52471c90,2508a47a,718f3abe,285b8be0,e9e1e243,35e27673,35a25746,2c864fcb,94d8cf1f,5c08836e,7dbd2373,860d78d0,c17960d1,5babf5e9,fe85838c,1923673d), -S(dffa4f8e,137745c5,d11b8330,59ba9fd3,3d09c9b3,bab12c64,dda46a2a,63ba3b33,982d5daa,f0bf5143,e59e5c2b,54051c11,f8e42e30,adac79fb,6cd19446,e56ef372), -S(7d5d28b8,88d15a4,3721de73,d1e3be0d,677b6153,58a3664e,63bcfd04,c85bd47e,9f987506,34bf602d,fc02ae9,9332b494,9f4d1f21,84a96f70,b7c51051,5546556e), -S(8e65236a,47ce5e43,671364a,2e99c5ac,4375f3a2,9110560c,fcb4895e,637be7b4,d4800683,8beea2a4,9b220e38,345e0719,b91f2315,caa6bf8,1ce59b58,c0ec0b79), -S(e8f250d3,f4365f7,696a9b58,b09aba7b,e884be51,86c5f1a6,d513b9c7,bb3c6718,7548cb27,8710e668,27aa9940,6caaf865,e7b723bd,e21b6ebb,855b8150,cba0bddb), -S(87cef4ca,dd9dc07e,a82c0f5e,943e5ea,42b2a9c2,8ed24e46,5604a85c,a98e08a5,736974c8,9718b1b7,95fab8c0,9cb4a3fc,1dc9c73f,cbf0eac,848a4421,7cdbe789), -S(48485885,4cd24d10,aa546441,e132dcba,b433b740,b9eaca38,cb80eaaf,bef064a9,91a91c0f,87523cdd,c6fdfae8,d16145ab,a2c67a44,e7e9655f,417531a8,9e44f693), -S(6f7180a9,be73fe3b,3c88817a,154ecf8f,3102fc3e,a1dddf97,4eefa00,224d7149,e1ecb8a0,bcd0f4f4,8e039dfb,8974b552,4456c764,f4e668e3,9640c3da,4cf24931), -S(d2f859c8,29ff75b5,cd951da5,2fcf0794,251293a0,7e8f0bbd,925216c2,4441fe05,c5edfca0,805026dc,32644722,70f22291,f65b60f2,5f93648b,f4163ad6,d12b704a), -S(38454e28,6e44de11,7f44b4e6,27ad0b15,d555c6f4,f8450624,d5b717f4,88c5f47,916bf1c4,eb9c5159,3e52e3a0,e1414e97,652997c1,fb9fdb03,f34e96d,4c8cfe1e), -S(b039e580,64f64b6c,dfcca8a5,1c93b169,8aa14b60,a2bb6ac7,d098987d,6b72b5dd,17cc6940,313d054e,34ababa7,99fbb1f,a518df36,b2896039,adfdee62,dd5f65ed), -S(5633c240,8a81d35c,61d6d5fe,3f678,220109a7,97716250,aea118a0,52939b04,3997de40,6495a96,ee3e655,3a69b04c,b11730a,709f1077,a5ac9916,85c0ded6), -S(a4f3f220,a7e2c9f4,bbf541d9,8ea71661,e142bb2b,76b4b7d7,af989652,2d2cc79f,40064f02,5dd4bbd7,9bf80bd0,f697dd6b,26ca8ea4,d04252df,ce5888b6,5622e669), -S(94568051,acf08d5f,e36691a3,14b44373,f46065d5,af48e08f,f34adc34,d3d7c15b,59672baa,3698714d,2983e23,1e7d985e,acc15cec,1dff4ef2,dbede100,972d2e16), -S(a4ddf835,3421309e,a41570f3,cbb0002f,5fe81975,35dab4ae,179a7f0b,dd24472c,ce127d08,cac2622,56f116a4,c993f504,b6df5833,731d04a8,1c0f0154,c4126078), -S(259799cb,4a4a4238,5bc3806e,17f19a56,844ba9de,8e303d2c,1cc0ee3a,a7831da3,aeffe3bf,b15297b3,4919cf90,cc808308,ec41c63d,f4af573e,b1d46675,20aff2b2), -S(d65f0bc,b0065fa6,4b13abe0,b621b2d7,b08cca48,2eed0267,8b131fc0,e1967dcd,eacecf44,defa0ba3,3bb5e8f3,9ed0bd15,5ab9aa57,81a22307,ea0633aa,64f98f23), -S(94ae2db9,1ea43b15,fcb2acac,93cfafe7,36874373,efa30c31,98f10b3,b94a1b93,8df119e3,d4872a0f,3b40d3dc,fbb894a7,59f5719f,b81f875f,71ab5b7e,f8cf7db0), -S(126fff6e,9e1c65cd,d7e8aff0,6a20c00e,cdad4440,64ffa43,675a0df1,f7c0ab35,b4eb051b,e05cc632,ac1e23bb,23814d1c,91caab71,6b214dfd,41f6f44c,bfe2dd72), -S(3c8081a4,4183a093,45397a2f,c895877,79139c29,ec6dcf0e,d24016a8,e9d3b210,45a3dfb0,9ff805eb,f7533bcc,1022e0b,8c69b658,88a0393b,66ad3151,b0c3bd57), -S(210f6bb1,25fee215,9a04d068,c87093d8,303ea3f9,1f8f20a4,69dcffac,39295f72,d96e5591,4b2f9eb3,20b9e17c,f3e9a9db,9f284be0,3575b192,3e8d561a,bb5e4d5f), -S(54e9e6d5,df0555b,3a29f1a4,33623e38,5edf8a41,d19fc0b7,c82f151,f14a73fe,ba04d63d,36b3d5c0,3ac704fe,7d15d939,918b8311,1f83bc55,4cd56c33,ea709936), -S(1e65329b,765365a8,6a111355,eb0308f7,c1702263,f8ad9e35,46bb285a,2fe6bfd6,e265bf55,5e975aa9,f2d8b9c5,420c33eb,1a05eb58,ff40da46,2760971a,d044b654), -S(4380d3fa,48cc932b,4f5453a6,24dd7dc3,b4071e7b,eb1a1295,ad8e64a,aa7b40b3,6da29a3a,30cb7bfa,26bbd0ea,cd84c98,c4091683,be9e9742,8dca4fff,5c2a6393), -S(c3990744,d6f84a2f,490a9e8d,feac8534,4b1d4524,1a573d53,9718b6f1,c1bac2fd,2387052b,2161f56e,fb3efa32,13bbe3ec,97e2c78,24c648d6,913bd9b6,c8feb342), -S(d7e1c842,25966972,5de9fb3c,25ec9fb6,4ad1ed23,566e2930,292507b3,e099dc34,5e1cc09,97290936,184c22f9,747e043c,dfb86fde,142dc129,77502a2c,4ad3fbef), -S(f14fa91c,140d3de,5936b6b1,5e4a1bab,8aa22013,ceb72503,27f608e9,2e048f8d,8f429f64,7396fc1c,fb5c33cf,e982cb9e,a762735e,7e595335,19b2e302,a976f0cb), -S(c7837842,5ff42ae5,fbaf9186,81440523,3286f91,5e170133,d81ef705,e80c4f4c,84ade3df,47e23a3d,9f16de8,f61c7d1b,b0428619,8ca74b68,78947cb7,4a5faf43), -S(f39bfca0,beac1ee1,2e98624f,32830908,609e7c64,37175322,1650e813,3874b0c9,19e4fcce,fbc53b63,a3a6baa1,252b7331,fe5365f4,86300711,f6c438cd,4da8aab6), -S(703da707,37e1c78d,1a6dea54,6e896d59,984b1ac8,188fb720,ad837273,86a2c188,e8b3547a,23877467,75c9bcb6,1ed4b4d8,9ee22da2,1052bfc3,aaefceab,698f3322), -S(ba5f3f79,b3d5be05,a3d85b78,16738253,7fbb206d,841f8871,b9f578d2,2c17126d,40acdb1f,c139be,8a1350e8,3d52ae1c,449b3874,71794282,d5ba72a7,5aee5a78), -S(af43cb78,d080053b,7fa4cb34,4d70be1d,57f2acb5,e6718bce,abcff626,c8a44d4,ecb553f,1aa18a31,e8ba2306,22898b2d,fee8d6e5,2dfe6ca1,2ecb5f73,71a5987c), -S(3a3cbce,2b4e40e7,f2c32398,9dd6d35b,74f666e8,48d73e8f,b5810439,f0e1749,f29b185,7c7c98e0,696795dc,f243b662,835c6d00,9a7e55d8,612f6841,d3b891de), -S(81c28d3f,6cb88bfc,dab4f911,98e1184c,d0455bbd,998e8ef6,e98cef0c,fbfe101b,5fb09335,f0527b23,555db9,e5079979,13b75422,d75b5059,198341c8,542c53c9), -S(e9e5ce5b,3c613100,5c4e57de,6133cab4,d65d953d,a4536926,fbcbfdce,1ca56fcf,f9016f,bf8ed329,4a1a5fd0,cd66bbac,e0cd87bc,e51adc95,628b1a8a,25ac1f4), -S(bb45dc5f,e2265ec7,60353992,45f51c8b,72b642ec,219396b5,5ab0edbb,f890c4c,b375975c,c8107cbd,1f5068ab,c3f2f62,f1e9b76f,befef470,be29d5d5,a615408a), -S(38356fe5,4d91f656,79bf2558,36290b9b,b0840b9a,fccbc6a9,163c164a,3e4c7f30,17101271,b3881a72,24373054,39bbda94,6ff03805,abcc35e7,d960a46b,54122ae6), -S(fe6f885a,2996a35d,2886e6ff,e1d0945f,515f5853,c0b9e922,ea82c4e8,db2b2385,2310d0b3,6846cb50,bc3159eb,37cc6b8,47645b07,207ec23a,c75b26e4,fcc0f96c), -S(f84f2cc6,f645b44f,b4cfa5bf,2840caac,c6f512d4,4b0aca89,987bcf07,af8089e1,dd3ed3fa,5ea7f359,8c2b2030,92ede474,b2f594a9,61d7fd6f,8348813d,bdb97f9f), -S(8f2921e1,dae78a3a,4557d895,50de9bff,7641749b,c963764f,e12bb329,2ac092a,9c7f813,20fbf8a4,b4f08b57,58b02cf9,1472612f,113f1be7,fdcccdc5,2336058d), -S(28dd6677,d6085587,46523eef,46aa90fa,496f04c,94e8aa00,2636212a,913eabe3,3f6da403,cfcac4ae,f2bac7ee,9788590e,5cf58a6b,8de534bc,a2dfe892,44309e34), -S(307b5b7b,d959def4,9d3518b1,a53cffa6,f1d87c73,157a0713,b3276821,30face1,b32135db,5ef40508,184b19f8,d3f150b9,8eaa6c4c,edefbfba,ff300b2,86177d70), -S(caa54ba5,ec29788,c53ae86,c58b8436,dd9a62a,cd41797d,1cfba1ce,2c70f251,71ba3e8d,9025e404,aca75114,3b74e0eb,4ef2fe4c,179c1146,e774b432,1e51d7b5), -S(2c2d5637,4a4d6333,83f5051,c6beef25,884f41c8,c5474107,e8f19532,580c8e63,897e1870,4a3767aa,3ce72f7d,dd4bbc7,b8a77594,469cfba9,f3a366a,807ba256), -S(7aa31729,dd90cc03,e40e41b3,5682ed5f,1ac4addb,3287c2df,b4061369,18065e02,e5662d23,55a0c036,73b120a4,fa430d93,fa1a6b34,c371e464,3e40432b,44aecf85), -S(2f882827,4abc0c90,27b6b76b,f60523cc,fade023e,42148f2e,5e237c20,e5da840b,d402a02,3dedbaae,ce4d003e,95daf219,cf47b98f,ad547a92,fe77090b,b9772ae3), -S(a4243ce6,15596c36,ea766263,4142a9ea,817676d8,a9f6c7c2,2e6ab9b9,a74a2fa0,6a2f60,20ec81bf,3d32c353,49f29fa0,db06e8fc,d4058dbd,5214aa0b,8ddbc595), -S(8b7b7e38,a9b704f1,3dc12d15,1f46a3d4,950abd52,cbdc79cd,693e00ad,b7556934,2cc742ce,60e35db4,fb432d93,299e5fcb,f7647856,d8ae4e8e,2bbfa6fd,a60a6a84), -S(da61f7c,31e2ae17,39b188cb,59c9132e,e7120f34,b49a846,66538a2b,f338911e,c8d93b53,d102dd0e,20da925c,e6f63c04,4239fa5a,2d04df8a,9fe68f23,6d03b6d4), -S(38925464,b72e70e0,361c0420,ac92348e,3d208b63,37e55b31,6ce554de,afc2fe09,c96c91f3,c452504c,fa868726,7985c532,181fd1ef,82344a45,4392a4fa,8e534c82), -S(ddc0043,46b27c54,d6a927a9,a053195,335c476,bc602490,96b1c62e,e06b6cef,be6ced65,445cda54,2cef4ff9,2f85289f,bc6c5007,362a4cad,5df4ec03,b450e7bd), -S(5c82a52d,84832270,3cc7506f,fc457b46,8aa8d5e7,1c55a4e0,2dc1971a,a298ee6e,49839199,fe6d88d7,3a75b59,d06a2fb8,a0dae45d,29c35cac,161866c2,caff5021), -S(b9793612,74eca1cb,e5a41462,aec446a1,d70cfe40,61925ce2,558980f,c1d9d435,c59da470,8771c732,d7c94291,8dd76768,ceabdc74,4fb49700,6305b591,2cac9d50), -S(be9ef1b,591477fa,7e3b3f2d,a0c9cb1f,37dbc3ea,f4529f69,2f455f57,fe3a026e,9617409a,97621fa9,b8f8d926,ffc895bc,eb60d2b7,37708bca,99258077,e9d5999c), -S(397f89f4,ea848a85,860efd86,5ef395e6,26e9657a,2cf04097,7af1e8c0,f75e6953,baa93eee,2bfc5d47,e096d20e,c31a2a07,ea369c85,66dd8402,80dccafc,86e991e1), -S(ee263d15,e4437d90,9f1960f6,504663d6,410a12e6,3f70bb86,de33e148,2ba907d3,2512cbc,bc9cbd9e,f0037e87,d51e6fa7,9d96c748,69b702e1,aef8614,859604bd), -S(3c93ad7a,85d2c4f9,1e03bae8,1d9ab6f1,d706779a,41387c9f,4b24ae1e,c8b7497b,ad1aaa38,5db82667,984d53f,88cb0564,6140f339,3b936f3,6d39099e,fca9aa36), -S(fcf7a309,e1362a1c,6659c2a8,e504ca6,8815e320,9ee6a8e7,96c4f173,f1769216,970368e2,15005e71,7cb31c4a,b0963246,796656c6,be28022b,e458fc9d,424bea47), -S(7237b824,1ea29c9,5f7d216d,e15a1c67,9f4f546f,6f79e306,14e2b2dc,226b9402,597f98f4,8ac7e00f,db3ffd2f,88e3e16,57417a6a,25c18b20,c2bef0c7,fb49e6c0), -S(1198ec44,7691883f,5045634,c4475b75,95c2ef24,29e7124c,2ac93bf0,2c0de7cb,ff51c40e,d65465fc,4688436f,7f5d873f,d8be9b50,87dadf04,54b64ff6,e9f8f789), -S(bc5d666a,7d29ca8,21112968,8395a4aa,2fcf4f94,a8437d22,6ccf2501,5ff713a5,6e7ad8e7,b74c48f3,45e71e1c,605bf4cb,808862d1,aa292686,4723b14f,c8169c22), -S(1e05f444,c110aafd,e3c828b,97db2721,d9ae0270,456aafbe,3a2c5579,ea3a2154,3e432d3c,baeb8056,105b67c0,c0e1551b,eeb617f7,c8ea4ac6,4cd29f27,c77b534f), -S(2d7ece5d,4ee96a96,91a5812d,7bf888c8,6f0992a2,51ecd061,b583965a,895c94f7,9a9d0b4b,da5d4500,49ac087b,a30bc507,aba5baf8,f98ede76,debf59f9,be1390e2), -S(3b717ec2,ffb0f062,55cc8241,f972709c,6c3507ea,8e11beee,d5e267e3,2fb576ba,5176f106,23d062e,ec697f2f,c7090352,4fd6700,95baf419,d0251030,101cc915), -S(304652cc,3fffd5c,c86daa47,ba797d5,14d7f3bc,11f5fb04,83b7c217,794a7156,c0767215,17b5f18,f92e6995,f35fc65a,434aba1d,f48a2977,62d1a04a,a587d479), -S(2c9f0acf,c4f3b56f,4a0c6262,1fac78f5,1a486173,dd6bf323,d66bfc48,13ea753f,b12aea95,b7543ce0,40291db2,1ba73dd1,2f0be788,38a81d9e,8e00e0dd,7400ab05), -S(bd236103,9f096e04,770bcd3c,3a10d5fd,66ef7fa4,a6c869b,52146314,90ae5dec,d28b95e4,6774745b,23ad0dfb,dd4766d9,8a2f770e,446a5c16,3277499b,e21b6511), -S(e97ff1d7,4ac00778,97caa1d0,a640ffdf,3bac580c,beda2fbd,23f25f3a,e9a26f5c,f093150d,95ea1a72,3a54e382,8c919940,3c296d5e,fd2ab41b,25cbfdb0,9aff5ee6), -S(f8ae0f13,a6beb793,46450b3f,53f36ce2,8c81fa18,56bbedf8,87e9723,9e15026,3988af1a,f632948,8e7bcc78,5cdc1ae4,a572141a,6cd15429,e6b1b40f,5b44e529), -S(6a944e92,c051b864,d4d26bb7,594f4ace,43951291,44b6d255,5667cc08,86dc515,13a75d28,c910c56a,a5dd2e75,9893d4a7,d86f0efb,dcf715b0,28c45277,50745660), -S(fdcc9b7c,4cc46a5c,8b114e05,c1f44bda,ad11957f,f05a0544,7fd49ce2,7c6ebb5b,72b243f0,1c142e35,f19653ad,a3d8012a,67f0501,a155a644,67629b26,58943381), -S(841e3eb7,17767093,19efc620,4b1dbf4a,d339564d,7ae6ff8c,647a9c27,93e9a5c6,1e5d0b55,7e50e0d5,9abecec5,de33570,d2a57d8b,a2c2d4a2,e90c0ac4,d4edca19), -S(fecf1c0a,32317cf8,469f181c,5bd52ae8,50913793,53569b28,c0c90c0c,dfc7b248,c61056df,56ac8e15,1077dc68,bd0a4819,c19ccecc,552dd14a,bfd6a457,516ce448), -S(82efa605,ac4e5e4d,1b68bb8c,b3f8d24e,47af1820,a7600345,757a36dc,2b241c52,171f1693,a2a0c1df,531d3d2b,5da06241,651482b2,3eaba4fe,c5d0500e,868db6a), -S(5ca04a7,afee22b4,c250d0b2,98691a5e,6b6805a6,b44da5b3,6b8a100,4fcdced3,7bf3a990,465166b4,e8d19ede,f41d7ec0,c7ad86a8,2ac57853,fdc731bf,15a3df09), -S(db455b79,de85315b,ed8ee65e,d8b5d659,5df2d2ed,9eb6e9cf,ab939fe7,93105df1,d821dce7,395db88a,98624ed6,44705a39,e2e53e6a,ff3b7405,3e8b9e18,4e1efa5f), -S(f0033201,aa7e6293,de70665,38eb3133,d2a6b56,5e73ace7,81fc98ed,ee458fb1,612fe4,d18f43a1,12988418,42d875b3,2c9525fa,154b859b,8258f904,d69c5d08), -S(77172496,3722d684,2039d1b9,92eea093,4c0fab8e,4be3389d,7d5eef1c,c31fd291,af3b1ad6,499c3224,aa47c6da,26064bd1,a2357acd,db722182,19350cbe,b84ed1d7), -S(7f27ed8a,c56722a0,730ca755,f23bbe11,ac868be5,e5571f70,5b11df40,28771532,adc25cec,11fe3569,7c8618ea,85005c05,b0fc73c2,db51d6a6,fb55c4d7,6ab9094a), -S(919105a,5d0f13b9,d0c6618e,21257efc,587858b5,6b6b4477,849f43dc,ed12bc0,54c7da67,731e00d1,316a0461,3debdef1,623feefd,784702e,eb42b995,4da27472), -S(e04d08e8,ab086e2e,155ac0b8,408c0163,e2db4afd,57703ec6,8a14c43b,3ddeee1b,742a114b,87e041df,93d15822,80a41360,86b9294b,20efeaf2,4d6b44b6,68a891ff), -S(82c95d88,5715b88b,5c583b9a,467a5c83,4b066ad9,3dde97be,866eb8f7,fa23452b,dd594973,f5cc5595,55d31870,fd9dd65d,c2b79733,c9db8c44,987314a4,d6ca0bed), -S(634fbc51,4efde752,b8726840,82372231,6166a17,ed706b00,1ca80ada,e4c43d8c,61cc9b14,11cc8e1,3f6a5243,64b04221,ece416c8,f5f381aa,8c3ff977,2c20042), -S(d85436a0,1c84e01a,c71ec9d6,93fae5b6,21764db2,1a8604cd,c7b37b21,452348eb,d4f9e6d8,5e65d57c,8bef1acf,a844d20f,1055c756,9690a10d,a230f5f0,8e0f9f8c), -S(200772b5,67197246,2ca9c5c0,e042d0b7,6990a34a,506494f4,f66265fa,4458459f,15e7e0b4,23c66afb,92411156,5e40b8e1,47c97bb0,28bbbabe,8e1a83cc,49b96e23), -S(8d8e235a,8c425a9f,d3556276,2b3c5404,ee0d8e2d,2e41c785,a05f34e6,1ce50acf,74032ab2,8e67f7c1,71bad531,fb1fefd5,d4aad08a,f44543ec,3e731dde,6d2877b1), -S(a5936747,fd423569,cb233184,77b992eb,d2d996bd,b47908a9,59d1a556,bbd51804,4cd3cbc8,ee2e795f,fcf5fb64,4deecb2b,45d6aca0,d70bb33,83f7d16a,d52ad109), -S(486156c4,8f785096,ddffbfc1,fb1d358e,2fa7600e,4decc327,e8b31014,21b75001,dbbef974,6482e537,225f5459,f3f7f62c,b0229307,72c1f251,75ae3a20,f6410527), -S(be858e3b,217489fb,1401b203,fb268592,ca1ff022,4d6fa329,78de85d3,b8a49324,f0bff99,e982b3e3,be3a45ed,f96f19,38d98b51,5b899d16,3abe2e53,bb67e331), -S(641e9c7c,cf17bc7a,45bd5298,af2829ac,b0d78a28,7c03f056,982e14ba,807ad7a7,c4bfc1b2,e338f2bf,7c9afc27,63ad340f,b5b27787,fba888a4,b8c4cd86,cf745fb1), -S(e8566e5a,1e855981,c6e275aa,3199dca3,3ddbb528,482ef60b,2e87c9cf,544cdcf6,94adf4a6,1643a235,9ac421ce,c5aa5ccb,779d4a9c,62bc01f8,93643405,4329b8bb), -S(f826dbe,15974b59,f4c45c11,584ce96f,56494195,4ae5972c,876a5358,82c5ca5a,79babdd,ab8c5a53,4f527ef1,459ae3bf,990f9bbb,a0d1dee9,d6ce6c53,330b9a96), -S(ed712f5b,a2d886d1,5e7bfb43,9c57bc1d,c2f9adb3,9bcdb62a,29c05d2b,1b483a07,36830fc8,b64cded9,719e6552,2ac7c6fb,3d6dee60,dfe6ad8e,30c5588,e4a3d876), -S(bd372233,901475d5,a6a2e1b,e11240a7,bf866bf4,cdecea09,541c718e,202991f8,4a24709c,cc93a928,9706125a,8922c828,fc309dd1,533e702b,fbe0fe7b,218f5c65), -S(f196cfc9,50001e76,1e6453eb,3afb64dc,46c793c6,58304f0f,ca3fa342,66da40e,274b3da1,eb8ac4d9,aac325c5,187b1507,ea4e24b6,1a74c2f7,84e9218d,d4c6f68), -S(d0b4c5ad,98eaed0e,6011c072,a2de350a,5c24da34,5a60980c,fd1c73d8,3d1ea674,9cadcf76,7371d792,6b818ee1,b4be2c53,5cc1d760,bfb7c47d,dbd846c0,c2568449), -S(41051a05,8771b3e7,a8fd33af,1838b679,b13c480d,ecc065a2,a3386d9b,25c822cc,ccbf9cf1,df8ebe76,159ded17,2268f71e,c3f44e4b,2d5a2efd,5d4ff9b1,7f41f8be), -S(1d8f44db,4d7f28b7,8b911ca4,9f622337,414fb0b8,81b75ea1,e93a757e,36cfa0df,e486e0d4,83987655,8d4671d,537b47ca,f734157f,6843118,ec5a3293,839fb77a), -S(71fbe897,6c6e30db,b71530be,42cc3fd1,80d60acd,fb3533c2,c0f2720e,e1a9bd43,84560b27,383d8db1,5558a2a4,a8107878,4c62325f,60ba0669,69573488,262efa7f), -S(7f42e7a9,cc3960d4,98e05160,95477ca9,a23cfb84,675f1b0e,c38e01e6,86daa99,ab0c4acc,6ae1fad3,82eeab7a,e7d1450,6db254e9,6abc9a9,d8c55c9f,7e09621d), -S(8a9c65d6,5c400f53,db6a3f86,ece6e185,1295df9c,19a55e34,348d5de1,c6242448,87d177f8,12769257,ca0f6e42,e1db9067,2387b8fb,f0462051,59a55d8c,79377af1), -S(d7b721e5,332820f1,c8f16624,4e3ea5f0,b63117ca,983ae4ee,9017d44b,ab18b5ff,b2b5b7c5,9b0fe6fb,386e185e,44cb43db,76e005f2,a5cc57f5,4690841b,7de26d19), -S(fc81762,38dbbc4b,3969fa08,31c22a19,bd163b3,4327452e,467b91ab,940622a3,b5f38676,ba86221,b0a02c03,6819df58,f2dec21c,51f456eb,7213289,6f7a54bf), -S(54e5db5d,2f87f24b,6e62ba97,6d941198,8584b337,ed801172,82080190,821d2418,ffa698d6,3e953ebf,b755c0c5,15976246,b5ecfa0e,397051ad,136f88fe,81987e14), -S(b18d7cc2,4023df48,776ad32,b64b234,1ae42cf,74b19038,6f3de4f2,bb029bf6,a12abedd,ead9d502,eb28a8ea,d65b2a19,29ddd548,1a7fb93d,e8d43b94,bfdc8547), -S(22df5ec9,d2acaa17,473e0ea7,2ca2eb49,9622677b,6abc063d,1bbb3648,7bd3294b,4d98a1e7,8dbfa279,227a6090,b61a5831,a6eeec3,519710c7,85679d5,61b48a6b), -S(6ca320d1,fd3750b6,5606108f,43585ab5,fa3663d9,65428a40,28c17eb1,95790eb5,b346253d,d2912350,86ffaf0b,bf7af93e,3b4f44a9,fb820a53,286067d4,98019e87), -S(9df9049a,7cf65986,5c88b93b,3688e9f0,53eacd78,561d97bf,58358952,f1318a9b,984b2aad,3891f7f8,df36b785,b56f4967,1f572f11,2d87023e,6003b3f5,fb80f3db), -S(6e96057d,9827d88a,5ae84c28,c1aa2158,af62d298,2cc26c05,30d48d2e,d879aa0b,92cf1366,8b9784d4,25c16b50,afdaadf7,e7c114b7,783050c8,7715d6f5,1d273a36), -S(5719e0f4,60efeb2b,78eab426,ce8a0623,3f092d2c,97d9edf9,3d22d403,a07fb86e,5c27677b,63486c8d,3f2454eb,30d5d511,bee44e6a,5bebca46,8e1e7b38,61c69a12), -S(87e1fdf2,c83a698a,9fa294a5,252894c5,4f84b148,178a28f0,42870a24,e7ce1175,654db1d7,c34e78a6,e9120a54,6b9df354,b7d385fe,13a3522c,72adbd4e,660f2cf5), -S(9c915f39,cee954f2,3d534662,f2d381de,834a1fb5,13739902,6c1b6b97,53050fad,8b068e52,e6821405,8974c43d,8902a00b,d2aa49cc,f0c4adfa,fe631e09,ce658112), -S(d77ce2dc,6b94603d,c2093771,ee39e720,93150705,56ee100b,a4a2738d,b6d22ada,81bc70f5,96f31096,a2054807,aad9e9e,63260eb6,9d524289,71675300,8d71bfbd), -S(ef509ae6,9fa82146,ac152c96,d76313de,c1857882,a71e8955,270497e7,33a3af9d,a614aaee,6fa558ea,fe7d8d3d,4090192b,c8a7b70c,d4dbd766,a965d684,544e5bbe)}, -{S(5b27aec1,c644f0a9,ba7f6486,9a960ea6,28343ab,da3feab2,4a2d6add,754866a2,3d1f365c,2aee6c1e,ab2f1879,429b6275,5d1bac85,2998ef25,8a914bfc,ca280b43), -S(51509477,fb7660cb,b15636f7,a53b1e42,6066823,690af014,b227d14e,e428efc9,f43b885b,4db6e28d,d93b9feb,f035014e,8600b6f6,ad6fbf13,6eafd789,2fdae717), -S(484b85f0,516bcba3,ee08f829,97496e55,b3856c94,25682c80,837a8d65,16096083,8649305e,2f245dc5,d4a9082f,a29f9421,fb20ad34,2754d8a7,8ed0e3c3,ae933ac), -S(8fd997a6,792e739f,83666c5e,25bbbb47,ada14d89,d3386cae,2084dcc9,f546ad7c,f85d46e1,1eb472b7,3c4c3731,bdc3620e,c2991b29,599871e5,e215af28,9ef08cdb), -S(5fbed326,3a7332e3,104dab58,c47932c8,a3f262fb,14fa35bb,a5021344,e965871d,225d98be,876cb5df,db578da0,c25be784,5ca1f5aa,7ec273a1,7b9b3ad4,5998202d), -S(d3ac3c1f,84be4b7,1e47da62,ca159e02,5cbf45c3,a40b34b,c3f3b28b,b0bbf1d,b2b94603,f6769cda,f9a766a6,31d7f48,e194f51f,2250347a,34719c55,beb30e17), -S(6233110,a8f6b13b,fa99dc25,b912344d,1cac4cab,f25318e8,c7d1884c,9985a468,dd458304,e3782dee,71ac4c33,c4e45e3d,79dbff13,437f9b99,ffa991bd,778e0707), -S(3cdd0f3a,b2b52a8,65ad9d4d,d65e089c,e2a66772,a20d5dad,9768fd5,6ca5efe7,ee940af9,90ead7a1,a7916eb0,44470103,b73c39da,23288072,1ff245fb,93b021b2), -S(9aa9bf7c,d8b58d8,411fde00,84e05511,6f11dabf,a699a1c5,614eeb3e,4af41bae,71d72932,7f05269,a99de5d,cee09c4e,dcdd3b76,a4465d21,ceac33e4,3741ef6a), -S(aec139f4,4598b687,c14d01ab,250160ca,abf5d9e0,1cd69959,2ed2e988,22345aa6,d8307e0f,9018ded8,d883339d,7ebe1fa,8ad39889,d0853c89,4743e704,d5afa618), -S(7f99f6ff,4d46e361,8e55f46a,ed55b95f,3203ee16,848893de,c33c5756,1184611,bdb6721f,987283ec,873e80ed,450d8c5d,9e7e2a02,ae56fc45,9e69d3c2,d2016c69), -S(8d850e4a,e682f751,22cadc1d,ea01a22b,377ed983,c833a4b6,e5945fca,4d227b2f,94c22c5c,3864879d,e4b861d5,e9e33523,e5f848b4,fbbb8d3,4aa21a,85066e3c), -S(194b8c89,7231a783,ea9a835e,ca4b6744,f0d0fdc7,232ddd43,237fb622,14c869f,db961536,179e4275,5b9bb682,95d1c75e,b2b7a19d,d5084960,7d9622d9,cdf46937), -S(760ad01d,c8e83c2f,ee63caad,9a86f648,f6b72424,4aa158d9,66b05647,eb6cebb9,9d08a9fa,1d21e580,d34c9fc9,10b8c294,522379fd,c61fb056,895261bc,cc827a3d), -S(c2186e23,813e84c6,222138b0,1ab17c55,d47af51d,8e4239bc,1600fd66,d971cbc2,200a33c8,7f9e6d4,1d5d602e,6002089c,6246345,107e8b5d,5abcd35e,7203ac68), -S(4ef2336e,857336cc,dcf3c9a9,48685847,1f639021,bad06218,8a66e4a5,dbadd35f,67f8d186,e79780d2,b063e723,eef5531a,d95a653b,4289e98b,d4df52be,1b40e8e5), -S(16d03f6b,c21a2a55,bb0467e0,fb8668da,de88ccc8,cbdf562e,39c992e0,4cb66545,82a7c24f,b5dbbbd6,4ce566e1,94834d22,7127ab7d,ebce6fcf,60ce1482,4ffadacd), -S(edb76db2,a1d454cf,e8b9761d,951fbefe,49054fd7,fbc7e800,5051ae27,5b41e8e2,343aba4,56c46bef,17a254e4,df28e783,cb6b09cb,f40b062d,22a04aca,701b66d0), -S(b505feef,7c6f5219,7cd9b159,5db0e30e,f1f3be2,7e65001e,df1a9f4d,ed86af06,fbd1a957,d0a4e43a,652c2555,312ace49,92e2647d,5167c18d,86410bca,87705e18), -S(50e755f5,f14333c4,13be7594,34be8d74,3691156c,12a46ef2,c730839d,3871f097,a2925d1f,263c9c2b,32c4fe8f,4cb2b7bb,8cb6cff8,3f0ff900,213afd01,e5d7f01c), -S(6fb573f1,529a88c7,9f278108,82d9c8df,2a02ee28,84168ea,7ac41219,23d7a96b,e34f7cb1,e4c93ccc,8e7ec63d,4cd5c198,efba1a26,fbd24ca,2f09d378,30bf2589), -S(3cd35cf0,c96e32f7,2023447a,f9ada5f3,8082543e,12bbbebc,947fc3ee,215ec98c,24ae2376,10990d87,f4d9257d,45857e86,de05f6ea,b06c889d,c44d948c,dd5c4b84), -S(6b853761,e19278c8,11a01f0,499779fb,a2daec9d,a5ece88d,b25ee726,21f42eff,fceae86a,242bcc35,885a83fe,ca3807e4,13f46408,8d46f68b,860ae389,c3f6aae6), -S(d32d3024,34b1cddb,ab02db35,4144d96d,845028b7,c8b5b45,adeb3ad,84eba58e,762cc6a2,78b94842,7a7fac39,de201c91,c92f25b6,b472456e,67407ad4,9b977b45), -S(64275dbd,a2ecc977,3026dde9,f1a098d0,63986d88,8e958430,23ebae9c,82218f6a,e27c46c8,41829e88,2276ab9,e146635c,953db6e4,f1295efa,3111b0c9,40695056), -S(1becd08a,a4aa040b,51fe7380,396a18d4,1fac0c66,91093cd5,d74a31a3,2b2e3a9e,abc07812,ee13caa5,b040cf7f,ff4637ab,a9e69db6,7834efa3,2f864858,ab138989), -S(f9976dde,8c971e73,fbcd5ef7,50947027,711d5a7c,bb273871,cc293cc7,f4a1f732,408ca6e7,ceb96781,f0b2f4a0,af58f2e8,52ad5438,3399ddc6,e9a65144,282aebe9), -S(fa71702c,91ef2cca,d80796,ef0c6246,9ef32e16,8f5c9ddc,9fc7241d,f3ebd2d9,94491856,fd63fe93,7ae6e95b,b35bc6c7,85732cd7,7305a83c,65ff9ed4,42f5e11b), -S(b5ee5d7f,60398c08,f66d568d,1ce39d82,5c64c7d7,c65c030f,3e35e86e,c87b0036,d2c62b4a,71f9c662,9914ac79,7f34203c,eea50a58,ca8ed06d,582755b,380ec185), -S(7aa05776,3de6393f,a4b36ecf,5aca8f74,6e5e68ef,152065c,820a2207,80452ca4,58d54e32,840a40d0,b2a8a175,4138a62c,f054aad8,85e97731,9fb3fd6f,d9729bfe), -S(74b062cc,f09ac530,e607089a,8efb5a06,656dec8c,e1d1dc01,370e43eb,39594b1a,6d93d5e8,eb3244d8,8457e0ff,66cacb14,d38e286e,f42aa6c,3236b2ea,883e9f64), -S(dd56f2ee,f4dbedf8,ba5efcdb,c569ed21,4aeb7f0c,e3aed757,e72c91ea,9dae7642,c8a30e73,efb151de,d38785f3,2f5a9030,4e62becb,b0c470b7,1f049dff,7b75c9a), -S(a05bc315,ed5ccf78,34d888a5,788263e8,573a4321,7b0480fb,960e0a3b,e7575d0,9b8568a3,1b1b8f6,ad507db8,b6016280,28f43990,1c9e9f94,14ded563,6d06a78d), -S(c19022f0,5c316bd8,e5c50a4c,1a0a6808,b7a1a696,8ccec214,da81e039,53baafd2,110b1cbf,5a01e8f7,95d0b996,a3e6c2aa,3645ffeb,59a77473,e51c4810,665a415a), -S(feca2015,14edddc9,8aba216b,cc37722f,f6c60202,d16c6925,422582f,dfb241f5,61c06c06,d0e50e98,2d9ea3d9,44079084,e37b5c9f,9aaffbaf,c89d73d0,20dfdcc9), -S(d3d271c9,2b843b36,a24f1928,efd4f197,c90f176a,70539f,e290b150,24a4bd89,9179320d,bd5577e2,d7e58d67,131e47c9,118e78bb,18690f7a,74e9b38c,99cdf6e8), -S(2d12ae62,3f4b552d,4b7cdcd6,8f16c9e2,58d83cdc,b5fe567b,a5216cd0,6e94a2fe,469fca9f,8d15b969,8687e33f,4a6cb20d,aa8aee7a,a2911802,f6f26f1d,fb22d63), -S(55c31675,9974d7ea,57b0c133,b6e1f1b4,9ecf0c15,feaf74f6,b63d6d8,ff525a92,de38ca29,5f85b65c,4b56dbf8,22edea40,19f61207,f16b6364,6943d43b,4a959f14), -S(739facb8,74194ac1,e60a2206,10a82629,4f1bea44,ccb08f67,33fb30dd,79706bca,dd77cfb3,641a3786,109dcd08,700edada,8701732b,819f41f,14a55104,9ef8f38d), -S(9768a20,2ecc0ba5,8524d10a,c6d2c18e,611a1215,401a8ca6,571828cb,ae5759bf,5d35c2bd,2e7019e1,6e6bed11,15a16d72,dd4c5ce2,fd848434,4d8bd392,c4a680ff), -S(2161e7b9,858db630,a1bdb50a,6b13a6b9,829c302a,a836f0e0,d89f5a35,70065067,c565cffb,915ff76,7bab8f73,aba21a7a,9168274,d52681b5,301f76ae,a9b6daf4), -S(2a9fced1,fe2b258c,6de7b534,212419e0,c6c1cd6a,50257dc8,79f954d4,c351d7a7,887f8024,d75a1f72,e61807f0,d8c310a3,5df7829f,714433e2,214f9180,ae552e9d), -S(769d9e4e,8a1967a9,1df6e8b7,cf282ab8,7f9e773c,5dcb94ae,8af7b125,6254b879,53537a42,ffa46e16,63821069,f5bbc62c,d7a0206a,7407aa8,154c82f,dc390650), -S(6fe3bbae,441f902e,7ea02e32,44e3ecfc,6c45ca71,9bdd5e4f,23f7fb3f,540d45ed,d0cb3379,c858c9e4,6115517a,c65d3452,16dc744c,60a6f1c5,7cbaa8cc,f4462123), -S(6226690b,d8d94bb7,168670ce,8b4d18e7,a35f0fef,ab50c816,195f0b4,37fa16e1,cc8f53f,9d16582a,fd2be5b1,8db42faf,e8d83ce5,481a88a0,9c54ed2b,7023c3ba), -S(1e5d9adc,dfb56218,1d10999b,336412b7,d8fcb37e,dc5d20ab,8f8cc789,55e8a72e,221d5b4c,58ee5fc4,8cd34b1a,cc9fe795,2d890d35,4047746e,405d83cf,392184dc), -S(9e978fa2,ce0875b4,ff79d6bb,4f56a9c6,10d646db,c81cdb06,5430f9e8,4198b707,9608823,828dc9e1,2835e261,1026ea34,c9b4583,46ed41b6,4bbf8441,fd621e35), -S(ef6ed3e0,587229f5,aca0534b,f632fb13,f4067712,9d41350f,2e92bc1b,cc1d6f8a,c9852e66,260fa65b,13ba714a,2629177c,80030b2d,867f4e98,83e60ceb,402e5ad1), -S(3c104b7b,79c14740,46a032e4,8ac22ed0,1a8b8812,3fd1b457,977ecf3b,b82e2720,809d1774,22521dfa,f05dd418,e5783577,d542d683,8904cfe3,35d8215f,1ee63b6b), -S(5fcf6b6f,de14e372,11d15178,fe37c914,bb9802f0,e67cd3f6,3fe72688,e9fd2dfe,4e468677,2032e358,25c89a7d,28fa840f,ef33bfee,7622421a,f2393182,ffd8123f), -S(d3f81471,d6d530de,7b8fb0c6,125c1b0,596e4430,dd89a22d,94a516e3,3c1cdaca,31da0106,ebbd0289,c68bf092,381054ff,718a8bb2,aa65a9d,47a0ef45,acdb8e7d), -S(c1d365d1,98ff150,ba208d1d,486de98f,1cb9e23b,4e83c58e,40d15f77,9b12688,7c11b3b7,5b8dfb0c,ddf97f80,e3ee4655,1242897e,2152048a,cf4910f3,2b819a3e), -S(c935f87c,752efe3f,d1208536,2c49321e,ad521ffd,b11fea5c,24e1ed72,cea77a28,1cd31bc4,46b90688,266b9f3c,74426c89,ae4c442c,4184c3d6,206deb3c,a92d1fe5), -S(2a88eb26,49349f3e,7fd6a43,78a8fdeb,86df60b4,dea3416,1c811a59,44a98040,e7fed2fc,a145255f,a06e13bf,9bbfb1be,6e15e330,9fd624ad,9b352c8f,1caff852), -S(313ff59d,1dceac83,4c70fc63,f1f32df6,ceb4253f,8327ee35,ce4ac575,9ec2821e,d0ca06e1,30d083eb,8a7501a1,dc80398,e67a133c,973121cb,377e31d8,fc4bfa14), -S(ebb8d7d3,81dffa3c,8ad10bba,aada6598,98ba7694,7662bfaa,e5acbfb4,36e6931,f01e6b28,fe03ffb9,42ebd387,a29c2896,32bfb526,58a7abb,34c10bb5,24cacf8), -S(208055ea,a3c94762,5e9cdbe6,91584b6a,a060d127,63f9a305,ca360baa,9d601a7a,ff382321,b7f3b513,1551c441,f6a8365,13d16c74,f3b74345,a5100ed4,de88e00), -S(1579f653,1ae0ef0f,b9da909d,959b82a7,1e158400,b5d34f5c,8d66667f,cc6e5c92,50f898cb,60c9630b,507bf817,fbfb7d3a,29d3772c,74e7a7d6,19bf4198,7a09136f), -S(4b40b410,56a43404,559ec18a,1bb18544,ad8896a0,c8182f51,b9bd0b7a,ca178f51,a9f22e06,79e43402,d6397eed,285db77b,15ff1073,6a367a95,3a439961,8cca3fac), -S(67673db1,2edf2be8,c0d330f,b26a04bc,bd0e6714,5c7b0984,11a59719,e845be8e,c34f45ec,ae724308,2245e950,f62b0c2,2b6e1b1a,eaf5d8d1,b503d9fd,e09e8cca), -S(8c1ec49b,81d8e41c,3bffb5f3,7765bad8,474f647c,833318f7,b6227608,a1f8a9ef,fbdcb1a4,a418b7b,5398835f,8f68de59,c7430754,87f52c50,a968c40c,35f3149e), -S(d823fe57,c0934eb,a2f15d1e,b445418e,e5092ffd,b3241d94,3748dd70,9e4d0733,b20ce02c,69b038e4,a5e37858,8dd0dcc2,f2433141,a2fbe473,e56d860b,379fe4), -S(d16cd142,a198d5b3,e2e855c3,b1b900ba,12d0e241,c914377c,1c880cbe,c3e9a10e,e0fc81d8,9d32e421,70161026,97e51be3,91a984be,739b23fc,6e3d6649,109ca782), -S(34353521,1fba36f,58fb6f55,aa0ccd4f,4052ccd5,8edccb05,164e82bf,111b0af9,4a9ce50d,2d0bbb0c,66a74a00,c91d5f7c,92b416b3,f0bca8b1,38e5f456,fc48f6fa), -S(254b9165,d4afe2c5,eb4360ef,2240fcf8,f8f4ce78,8237bc4e,c8edd63d,92a8b4fe,3c7267a9,5df9d1d5,96208351,1739729b,25d07ec0,53f30233,acbf1f88,b9cd1f7b), -S(a993528f,cb239c1d,eb824cfc,41ea09ef,72cbec61,ebcaf0c,4ea7890e,3aae0f3f,78b41a68,6f832e10,576820f3,552b181a,ef3b133a,fd5dca99,c7fd7b7b,247336c6), -S(dc431b9b,2d0002c5,d46079ce,463fb29d,6fca380c,4edf8188,34c354cf,7f123f13,32ff1932,2de938f9,9be1fbd3,3c553510,8c1dc5d7,caff8dd8,c4db6218,54b9bba9), -S(bcbc08dc,4ce90c27,54b9a79,ffec9320,3c78b60e,adb3f750,2cecfe12,d475773e,fb691bf6,8394b040,d2049147,6ee7ec8c,6d69baf7,a2ebdb5a,3b455088,3285e468), -S(20ab53a0,d5a26bab,ff0700c8,945e2487,fef10dc1,1c523b2a,14dfa8e9,fa6d68bf,c6ec861d,dfe29d4d,1a23d3d0,99802f20,ade886d1,257f669c,3315ab5d,effef915), -S(c58dcb0a,8700faf3,55a26e39,58c61617,3c2d5c07,824041da,71dc5d0b,6bc351b2,78ba4b31,5d716184,9bf53d1e,94a6ec8a,2268538a,58ce2f17,fa1ab6eb,beb9810d), -S(3d665b4c,831577a8,c536598a,3cfdb3b,85e1f45d,566a0b9c,a6852ae4,171be6b9,e6a349a1,36827310,e362adc7,cde91f6d,e6330122,592d1dcf,a7917d1f,8948fece), -S(6f8d4774,efe7b37b,d26f5849,22b78273,cc5ad16d,80f0f4da,8c54e167,33c5c7ec,b63ff2af,2fed919f,256de972,bda71f9e,e4a5256a,22782a0b,c06a7a48,57876d44), -S(97daf45c,8666f208,ee72dcad,c4658613,b8466605,be2e83db,69104973,5516b1df,e33deab,5ee28d64,b818e2fb,6acbe9c1,cf060142,210235b0,dbd9514a,ddb57402), -S(c712fcea,95039f2e,a87762fb,5e5fcba3,dbf7ff6e,658bb64,71a4f890,88e6106e,174f28a4,9b38ff36,1c28941c,b89c1d62,4606c269,6619d157,f05be89a,ca550fd7), -S(f42d3ea6,d791c681,ef6c16ce,9ab763dc,df7e1f54,42512b3e,f9ef8904,f6f30927,abb04412,3f2f1329,17cb8a01,26d21fee,59606715,6a3735cd,4cf2969f,a506eee0), -S(a77b7262,61365881,c1aeb570,12555deb,6fe98240,cfebf712,386fca2e,efe460e3,3200fd50,9500ff2c,df4bc618,f43e705c,b5000762,dc3bfd57,4ac66722,edc06daf), -S(82af11e3,34b229e,16877594,b9f7f157,8cf51255,c7521ebe,ebab9a81,a2b1bf76,3182824d,7afc4ee4,2e5b3965,65f07bdd,b47d0f3e,39685096,e96bf5de,4c00f47e), -S(b015e32e,802b997b,4c8db911,4cd0a3f7,8fe91699,a9d3c344,f03c77ad,508bb842,28aae64f,70b35de9,992216dc,ca1cd63c,d41179e9,b7ebee7b,964031c5,3cc56a00), -S(580ae367,e9118f01,858d82d8,20ed6c9e,923f3d,be934b3c,d0860fcd,1fdaa714,94a96e04,8b7d8b49,fd12bc04,d6a0f7b4,a0bd671a,dde14d92,9d8eda25,ef3ce73d), -S(b24a5ed9,65ed6463,b30b0be4,ee048957,2c62524a,50937daf,e863dc0e,4ea3484d,ed8897b2,3354ddae,149620fd,a3f7e17e,c8a5b46c,fd0d955e,7326ab1,2c7542c3), -S(5f9b9a03,2b21c8e1,31e13c2c,8019db2e,524a85f6,3ae03014,d27bca62,971b938a,3f954d07,f7ef5c7e,e4b288d8,3722e458,d38d5950,b38ee4b8,35ddb017,68a1680e), -S(61d23399,c8750a26,ff4220ff,c3a7564f,f6df92a2,fc133ee6,c9228ac7,56a77b8e,a3ea3176,80b9fe5c,25c74f3a,5cd0f4e1,73f9a47b,f13c6757,3ad9584f,81c0d0fc), -S(39129baa,19373bf1,db83360e,c1cf46f6,cf6041f,7aecbdbd,c0cd8155,4047f4b,e524c633,cad2a058,3826b241,a0f9f90f,1c29aaa8,7fe9043f,61f243b7,35966525), -S(9f4eb067,ba8943b2,7d9c90de,e3e3f570,9d470e03,4400b49c,8863852b,e42d2d82,7decbcb,df928f29,2359c31,5c4e9d1f,7c81daeb,4153b6e9,835fb10d,cff87699), -S(c3c41675,59499453,4ebfe29,32fc3a8c,fb0bd4b8,f58fcdc6,111e68a1,2931d68,9a6e07d6,271039b8,e3198823,589508c4,353888e5,46e8a759,873fca67,a687aadf), -S(389932dd,1bdb022b,aff12e7d,96ad188e,f2a38d,e07db076,d4ff0292,878a581e,591e7dea,d8378307,82c9df98,3eee4623,d736bf1c,7cada52f,9e9775c0,9b2c0e7f), -S(6a24296b,4ed7585b,b6e1a7cf,a6bae760,bd87c580,c5136641,ae890ba6,c6aca188,d389a8dd,df70e094,32a77278,89142e7d,7a1ed1dd,63e56961,14d4b9a4,fdf7d48e), -S(a3adc560,82a6a35b,76013450,a511c437,29000a3f,4df1cd21,d5a37aff,25236ffb,9e298b2d,73533849,d981556e,c4ccd2df,2cf8a84d,49fb32da,414725d2,e8bc8172), -S(b1761d8,b63ede1d,92aa5d47,9de387c5,10085632,dcec781d,44b1cad6,ff59a49a,16e10005,9f5b54eb,fde33551,d68eb053,a91a17a8,65703a4b,a0e4fcd0,ee35927a), -S(da2439b6,9512ddbb,8a3bdf44,c3dba4ee,1047594d,f274a33f,db442c6f,3313cb9,23a2b190,cd307fd,354474c4,95e6b0c2,df104478,e337e7d4,9acf1204,666f16bb), -S(5247030d,514afa45,41d07a69,e5670aff,71d42ca8,d6258e5,298efd35,2ea5912e,76a36497,2edb4c57,e29d6de,9990e7d5,f542c84c,764831fa,86ef5ab1,938e27af), -S(8d2dd8c8,80fd50f,94fa6552,3270fe1a,61c92810,3aa1fc44,d2db7955,765e9f6a,1a99666d,2f76e63a,ed386a7c,25a6e66d,cf3552f8,5979cbfb,355a91cc,ddee161e), -S(f964ec9b,b42fff6a,87d268fb,b6f58bce,c53bbe95,5780f6d2,765c682e,3b29ee6a,f1b5d480,1aea1445,177b7e30,7ec2ebdd,4615fefc,59b22312,1ef80277,45790fb5), -S(388ac82f,677422aa,c6576748,59fe634a,c9768335,b9f6402,dc089b40,186b8898,5a93f486,77033639,b9c0861a,c82e6326,e7a20e73,9fb651f7,ca99c3b6,b56e0e9), -S(e67c3d3b,760b9bd2,10cd6ed8,d261c0a9,3a24395b,5bff814f,18d1b1ef,efc5e322,370323bf,db8d6a31,8066dcf,439c9447,72c8a049,9df2486f,426a1a4f,297b3c47), -S(e3cf3c48,39595c97,a6efef6,98e75220,4d6ae09c,d4e7c231,24e16902,a175b95,91e50db9,f3a1a3c5,634fc2,6dcf9010,6fc27d4b,aa24e659,fd247c5f,93c83593), -S(b16d475c,c60b5286,2bd250b6,f4ca284c,69e30698,96eb3633,18ef6b7d,3928cddc,ef3fe367,312a3e06,b992f862,8e5b0c75,5b6f6ff8,fd62cf8d,a0353a52,1e6558), -S(758a7aa2,9433f0e8,ddcb6e85,70ffddee,2c487f7a,7800e6ee,7eaea634,c8c3b7a5,cbc5ebe,9bb4f480,2d50f99d,746065fa,7c484a84,30643962,50508ed0,a75ddc49), -S(3c2b2b05,10564b7b,7f53dcc,406d4329,e0faae16,6259edf9,ef26d1ca,308f0352,19f44e13,cd4e6107,2983cd91,81f942a0,f4cf0f4,8a10426b,c3f30dcb,8693af36), -S(ff644ef5,ec4f91c1,33ea443f,d783573e,debc003,7f74cac5,af866a37,302cae5a,50eaed81,332176c4,20e63c38,9ad9faf0,75e45a26,8119342c,b635231,1778e3ca), -S(2ccf4da9,9aa616c1,900f566,89d356a5,1396526,d488b635,f10c368,ae066c2d,46da8b3f,ef5c7994,9f94721a,2656b55c,6946d493,49a03aa5,fdf90c0f,4a152ed5), -S(5cf33ec4,cf6f3af0,18e94ca3,2d31845c,f1c4764b,2ccf3992,48467c4,b3f11924,a5cf6368,c5b617bf,6c69c7f9,fb0c769f,285720e1,432fe54b,def57fcf,8fa25b1f), -S(5ba03c13,93b9a100,928e6e3d,a0cdeb2c,8be4d653,93a233a9,b7811e4c,d242da22,15f9029,4890222,960a70e6,8046c2c5,de15de6b,8ada4243,64357c39,b11cedad), -S(ff9cb0f2,62e3a7b1,d5ebe749,112c8b02,4c766789,c2973446,ca2b8884,e5eb1035,f5194ead,3d090604,86d7f0cb,f72fb540,273eebd2,7c94a199,6f9f35a0,3834886), -S(b747105a,da190d97,48094f54,ef60d1d0,30e3f57b,f32d5477,5c6929c2,975a3978,18f9265f,b2cf77ca,f5aa62a1,8e82933a,2cdad96b,2866b5ed,c18196e6,97e9565c), -S(48c6d033,45abe61d,aca1dd55,8d782685,d05bf49f,2897fd37,ac112e98,1feb0ca9,853a71eb,1a1dc7f5,78adf995,a254e545,a1effac6,7afafa22,cd2c6be5,d9915b42), -S(27d839e0,b29aac17,b84a7654,b2e60cc4,6b8d02ed,8079a525,cd0463a7,f21cfd2b,9974f97b,504bcbeb,d8d3f3d1,1db05229,69a72357,2de8ed56,ef877402,8a435c55), -S(8fc52f0,3dc76184,195d95ef,baca3ced,9aa1b3e2,5f36c75d,65e67d4a,28337ad3,6e024d2a,ef78ac8a,d59450cc,de13c8a5,2d23eeeb,13d11cd9,7b4a9fdd,be716a69), -S(afcfe9a7,44837fea,d3140ce3,4e281510,5fa23b8d,1f497440,8d6ac3c7,70b46c6a,253c825c,8bc94bbf,3dd2a33f,f6eebd7e,203a34,69858d9a,6b48638,5ca557d), -S(e4a30e5e,16db32a1,83532b32,d466e985,d664be39,bae1dd8e,2e34ea05,d8575028,58bb5c1d,95922c2b,62aafb36,6bf22c8b,35d8947f,a082c4e,ce9d8ea9,cf24eda5), -S(76ee906e,b69e9ea9,667d4582,99c6c47d,c0868bda,ad8622d9,b8a85a9c,be6faca,88f10eae,25307ed8,e519abac,a00f721c,8d08e1da,344bdd62,5f6077d3,4295f4ae), -S(bd58f596,ba832cb4,2e3d7445,428f79c1,59da797b,317cc471,88188f3c,715d3cd4,8bbd7cd1,a511e88c,d7a904f1,6db60414,d4555337,1f72435d,cde9b5d8,715d169b), -S(8d450276,b722186d,2e93ed73,3e45fd3c,660225a7,eea0d90d,bb6b7370,1b2dd80c,271816bf,4c5676a,86efe5c3,5ddcc606,804f4cf8,15d19937,16733964,e00d552e), -S(7dad1a19,4b46b8de,f3d16ee2,6fb3d1b2,a9d9c026,c5923bb3,f4f88bfb,736c2b7a,ebd7b4fb,6afc3648,746823c4,d179687d,6d1b41a7,fbb597af,f028844f,b6377681), -S(de25311c,898c652a,40fa3c4c,6022d195,e4f5d336,5f8781e2,2b0bd1db,5c733c73,194b36a1,1d99a3c5,4e7c5e7e,31846b12,4229ea92,74737a57,22056cc2,56f3723a), -S(cb204893,6466f088,32470071,1afa626a,a8289325,913f28d2,f1e17ef2,8fabe7ff,c60b4373,bc81fd85,b871c930,827b6833,cfeb6708,c40c1942,676cd766,ddd7b390), -S(6ab3128f,9735753e,341ac4df,9e4daadd,aa5034e4,831b9681,15634e41,da047af5,ddccce3,47c9c588,88169f04,78859080,27c821e0,1400212d,4e40ebb0,999c9464), -S(c4b853bb,81d90026,c6463268,6440bc6c,42cb7afc,513a748c,dbf09039,82e98774,6ab31853,982a0b98,48173818,215f13bb,940248db,26eaa964,8300dda4,1482850f), -S(4a489c6e,cd52b4dd,33956733,977fa0d6,25e4f721,d5389076,91a4a251,e1c65902,7f7d73aa,23f31098,c5522a38,1172fa16,a10b4e26,9457c09d,15c14954,bcc794f), -S(d58a8e44,50f0ad1c,298d3add,5ae874a9,5734c031,3d2f27c5,5966c468,d8b0bd3c,7bcd6ddf,d7759f7b,3523852a,704862bf,4994f6ed,4a85c430,e9696d8d,365fda41), -S(fcb440d8,6d7441f7,52b1aa2f,28d4d5ea,ec2fab70,a7739b7d,af6678d5,837425e3,ac13b9d6,a0022a93,67d81f8d,f7824b73,11a98184,30c5bf50,89f21a61,4b1d3686), -S(3cb6a8f9,b1f8058a,dd2f9076,19a3fa97,8f13089f,fd0e41bc,8ca94760,9dfa9762,4968d4a1,8674164,74d98e8d,7110df5c,8c1ce11,903bb98e,4fac0a4d,1082edd4), -S(2e719fb6,2c09e74c,46fbd39,abdc8e06,69e38992,4424a985,60aa405e,99ef47b4,bfccaa88,e1105982,de52f422,15c5cfe3,a82b7c4a,b5e0edee,46ae657a,46bc6d30), -S(809d777f,f7e7d3a,d02f4c83,fab4e618,15a1c29e,caeb6d4d,8573889e,33035a5b,4d04a535,67a1a24f,f04f4e8e,259ebef9,cac4e89b,31cd8135,2f7037aa,da84c69b), -S(6538984a,31b67a2,2bd11be0,2daa7449,2abe195a,86c08fe9,d1465e99,e08a407e,10610211,327949c1,f8e4b459,831e8fcb,2b7b4db7,c53dba33,acfcd510,aa22e935), -S(e67dac32,6ff78b27,eb24b489,85d1ab53,60441d3b,62258756,74741a67,c0b37d33,48065a5e,21dd1e4b,b5c3a085,16f00aaf,a57e98aa,9c714663,63d168bd,90b72337), -S(6fee80f8,cd36865e,f4548366,70f9e40f,3ebb2754,aed3f5cf,1d73faa5,e7e7c72c,d3d52778,2d4675b0,16addc86,445378c8,5fe38f75,3e3bbdb2,d8a73e12,461a5d1a), -S(9940330,2dbfb6cd,45a98327,e00fc86d,171b39bb,811a0af7,bf0916c8,b04fd369,2a5bb90d,126b586c,6cebfa67,7518d008,b2348e11,362a5636,8e0b1d0f,8046aee9), -S(43224e6f,292a71e0,3e1b3168,4a30fa0c,a681fe1,283dabaa,f5629633,5dfa242f,b6caef5f,77e5598b,b8a477e8,66cffba2,30927e28,d8e55b3f,fe71fab6,90c6f567), -S(804e1a5b,8e16bb85,f041f46b,a0fa8ca6,a65fa2b3,48432e66,ec10eafc,1737ce1c,2b77d1c,b1acd0d,878013d5,465779e3,a55713bf,2be71990,7471962d,e07857f4), -S(f52a94fd,6bb9d519,3692059d,868901a6,33743257,3ec200f9,61b6d964,d090f849,33512a99,94327132,501a0fbb,166ea870,f7bf1ed1,657d3080,f4d7ee1d,acc85128), -S(6febda44,3ab8d9a8,756333af,86ce177f,32d782a6,114a7464,4b1fd081,9a436087,65fb2b1c,8df03ea4,2e72c6bc,82e2a39c,57f7912f,8f513fc7,bf97a45c,4f9e1fa4), -S(da0532a6,176166de,9350ae75,7ee99a5e,9502f292,f842e94d,74d35230,518876a4,b3ff19c7,f141a7b4,f24dde01,a82f988d,8178555c,38e0816f,e1da20fc,d724f510), -S(1db46fae,ef1d0a54,9217028c,1fcf73f5,6bd573fd,6c4b1730,f3cb99bf,2e163ba5,496640fb,ab04b388,3a35ef75,5d2a0ae2,17522488,a567d7f1,7bd951b5,98ee7456), -S(e14ae4c,2f1483e5,a580d3c3,6ff82525,a6df21eb,ac91aa5d,39391e5b,650b5436,d54ba5f3,2db765ab,b8f6e464,5320cba,c029c13c,2edec227,d57d3cb2,b8b6faec), -S(a382424e,a89563df,e7157fd7,b438c992,604a49bf,1462f590,b84591f,88ef7e01,b8a510c1,4bb0f355,6d432ddf,859d87f7,9f4c4448,522bdd86,a4e99328,2ad6f960), -S(266c1844,3daaa40f,821c1ae7,7da98daf,aab29b79,36ada9dd,238c5fd2,73b45614,e3f38773,27910ef8,d5cec282,9b7d8b29,83a184da,870ab8bf,4f43e6dd,4f0cabc6), -S(e7b29b98,b1cea663,3e686d67,19778d3f,f6af2d87,e93bd576,10c95232,e8ed5d29,ecf316db,b2a445fa,2ec84705,b453314d,48e16de7,6310b78d,a19f8a45,36f27bd1), -S(d36a3000,869795e0,9eaf616b,6e131204,d341db61,7a18ef66,e133a59a,acc47bb2,24b6bc32,487bed32,9d9bc27d,b08ab6e8,114bb6ea,e813d80a,c3dc7add,9ded3979), -S(c9783ed7,85dca51d,55e55a39,4c4e9b91,9c4d4c3f,ea461afc,51eef4bd,3a351cdd,e8e62138,4b4aa109,6d269fc2,a364a3be,e4584bd5,c551435,3dcdedb0,9037bbb8), -S(764eda83,aa90cd1d,9cb96785,e4df2614,aba504bc,33403866,b6f13b38,521bbf79,9d1fc736,72bd368a,cf6f9d32,489a81ee,782ef74,964c44b5,6dc4bd2a,ad4363e6), -S(f757e8d5,aae09922,278d2301,77f1c80b,5466f76a,f9f8d106,f0814d0d,b152484f,83ef8bdb,17c78a8e,1a4c54d5,d356170c,79ad312,6d62ef94,94c1b683,1798adfd), -S(a180a3ef,400e4918,9cd8b3,e12b3907,5b268be8,4c83956e,9e08c6e8,230b7fdd,ebd5b8c,75f1ecb9,cf2c8ff6,e863447f,7c821219,8944686f,b1b758bd,ef9e84f3), -S(5ed707bb,96ac41d8,8d85db26,fef84af6,d5f7d8d1,a680a0c4,8f23a1fa,89e37dd0,bf45cf6b,d0bb550e,590dca49,fe2b158d,e91c2835,3c75f49,98c1c446,8ad03e8c), -S(f8dc28cb,f149265f,6b6499fc,baa6ecaf,78300a37,2dcae813,59cd0d8a,e00cc52,179468ee,d7fa52ac,372cbf1c,c5974532,de4198ec,10e75f95,43461ce,fff87415), -S(8ad564f9,5abb28a4,5c807ce3,1b487918,f6f963c5,ac0cf977,c5fb7957,2954d080,acf894e0,35653758,fbbcb5a5,63d5c196,60d29b3f,315a784a,29168df2,98c8053c), -S(14503a2e,83fe0cfb,bdca0382,e872da3,bd7b6d6e,96e02415,258a8989,55a18e5,8955e448,67226b0c,c529f16a,35a5297e,dee0fae5,228ad6c1,257a0204,93334896), -S(86a30681,82b8006c,282bed7e,9b4654b3,ebf5c4ea,90c92311,a56a876b,3d78d183,1213bad,e418b68b,46ee5494,a7dfb32f,d74218ca,594686d6,f5b8b6a,26a4c3b7), -S(8b226ca2,c060c2aa,13e581fc,9ca8e471,bf8d1c4e,228f9de0,2015465,43b7c70d,4c264984,52085c7b,e549c4ad,fee6e710,9cc7b9ad,b94e0ad7,f7798930,917d1509), -S(ebd1c317,db586e4a,3792ecf4,4b2e45f0,ac727360,2848667d,19efedf6,c4c942b8,7c252d24,d2639fd2,2c0a7ce2,fb277157,f421e3b3,4d1e0f6f,ffe31410,213d06c3), -S(1420c547,78d72aa2,1f54a5c5,83f82c02,b5f3f64e,cdd16250,3741f4d2,c01d0b67,ab4ad7be,d53adc3b,158b7cd6,7cdffade,beaf126,f17b8c32,62d62ffd,764bc686), -S(e9728ee2,3744dc09,1e798ed0,786d7ec5,a31cd5f0,d2e019ae,3f52b8c2,42973d9c,9f0edbe8,edd17b87,3403b94b,b9e8fb8,62cc4463,52944322,8531a365,107c8861), -S(c2c41287,cdef251c,518c1820,ae86f38c,ac816984,b14f3fa0,4060a425,699cb291,ba991c3a,2d04b449,5dc04fb,6bf6b820,a4c62a01,f76dd8d1,4897ebbb,cb40825b), -S(6a63edda,8380737b,365e58fb,3a0fe1c5,816a8c05,f24b33f0,ba0c4473,45a0ba51,54ff065a,cd9c9ce2,876b5066,4f56599c,f22fd280,ae8fbc2c,92c38eac,c0c0fc1e), -S(63ad7964,e9af4b60,78319699,f8846900,e41a159f,c5d1b924,bbef3fb3,cdb2d098,bcc3e4d,2c17926a,d70f43cb,31c4a2a9,1a89a8d,3b79a8b0,1ec9d9c1,49b606c3), -S(c9e80434,cac460e9,bc245b8b,6cf501ff,3d64bb7a,a4ea5dca,c8932dbd,609e8354,87b2ee6e,a42e02a,9fac38bb,c013391,b9af1965,dbce484,c5a3bc02,86fa6172), -S(c547f029,6388b9de,f6502985,2ebee9fb,f9e4b8b7,f7a320e6,c7576d9e,e30ba1e9,a014b375,7c859ac2,29527273,78886397,56324353,25906a28,ca6e737e,acce884f), -S(a21349a2,a171bced,4034c1bc,f79150ff,84830ee9,95bac1b2,b1bedc13,c95f0d31,ea32dcce,6af2b400,4cb4213a,a67f3448,2b09672b,546e578b,28adc6b0,ce022db3), -S(4457ae67,185fce79,deff71cc,f73de43d,23a9f4b6,f374f637,c8a99b6d,2d582d7a,1278a7cc,6f1a5a6d,58824021,af2657e0,87ece4ab,fc5dab51,f85312aa,f6468fb4), -S(4c6743de,9af3d665,a0192f80,bd015fd0,d16fd42d,8d026175,df9cb80a,84e0fcb2,86cfa514,7d0a88b3,6a0b976b,eb5530dc,fea2cd7d,b6fb0409,bf1bad24,33bd6aa7), -S(6d591172,8f3f1fa1,3fdf09cd,7045404,d150e597,64704152,1ba15b64,a8782af1,fd22b976,4e7007d9,ddcd3b89,9f060e45,c59e4a9,470f4d87,153581b0,11b7d2b2), -S(1aae2b60,88895bf9,d199f120,506faa23,85c63220,81047e48,1dd7d0ae,6a6f128e,c3e73fe9,db489a15,87ed17c9,88d29145,848bac85,134857a5,7f2233fe,b558f030), -S(8a42240a,ffad26ea,8125ba65,2ba897c0,69eb1e7f,e821451,4521519,817c3fb7,927c6b3c,9b35482c,55199381,b4997821,70be3f27,3a1ea14b,97dcb193,901787ee), -S(a4b366e7,8dfcd7b2,3f997552,663afb38,3de01400,2798e0d6,b20ce8fd,43a78cf3,b6c6dc21,b22334bb,69f6db03,4860840e,da5c23ab,d3206be4,cfa3ad3b,b1a41c4b), -S(44b8576e,7a2cf334,d5e9db51,86605975,36504ee2,3c138e9c,86fa9589,91a8a08b,79e1e4c8,2a61e956,1bd8076f,5fa8d029,d5150348,ced9a145,95b9a1f1,82a05d54), -S(88efb8a7,eb91f4ea,6b97a97a,30bf21f3,94326140,ec60eeca,23adafc1,fb11ae22,c540c164,542181ed,38036b5c,417a6b22,819c4818,73da6882,c394d87d,21011fe), -S(3d939a17,76686fce,f2e544c1,2406e89a,aa7256d4,8415e59e,f00e3599,1b630682,cb784214,6c633d16,4f3e47e5,d7fca1fd,bb46e76d,d94b7588,d21d6ab1,f6e1ae97), -S(6cc31f3e,3e5e3dc1,ff2008d0,27ae58a9,a73857e0,26d1d304,3aee9f90,664aa53,15923b66,8ba62960,f2938e29,9c230e02,fee1f3b9,936c4658,36f685ed,e0863073), -S(c8c42052,4a7837e1,57e5b15f,85c4768e,883148b9,bc490f12,27a2ffaa,9e5219ca,99f0b3e0,6c2c6bdf,6a105e14,5745e7fa,328bd209,720157eb,c665321e,c99c708), -S(fe57812f,c8650a76,6c34f0dc,468f008c,71db839,331038ae,accbca1a,30d1ab9d,27f732e8,23ca34a4,dec45aad,7c2a4cd3,43ba0cba,f2bfb75c,6ed6deac,2e524249), -S(451482a6,1cd89411,e533ffb,d5e3326,d1d6d7e6,caa31fe5,7531f892,5333a253,c03602bf,83bdd5e0,edea9cb7,328d8315,d568f3f2,be8ef1c1,7172c940,768ba474), -S(e3aed935,8a98ade3,1206182a,66254c6e,4215efda,e5f75f0c,d72923d7,2d6caa73,f357e418,4cb28038,cf3d4abd,c9cae8e5,90a6da68,a984c169,242d2725,cf5b7829), -S(26f048ff,87b2f0be,2559e62e,9e66aeac,222901b9,59bf20f1,df872ac5,b3172107,49fc51e,712b390d,9fd38df5,2023112c,85f2f29,5521bc,4ba8334d,7a133a0e), -S(f77e22bd,5403193c,4532800f,2db0a283,d0c000f2,18a09b89,d8d10175,184089ea,7a8f9b5f,6e94cea8,dc8c4276,a7aebc47,8c2d296,4c37e3a5,5db10ec1,10c2d385), -S(2aa4ea08,d6580fe,2c0fd0b9,cb266837,7b6bf2e5,853adc74,bc58804f,b8735e4c,81c26240,7984cf2a,8ffedaa0,dcd359ae,9772773c,534b9075,9ef97d49,755bbddf), -S(93de5e98,8e136037,37cf4d1a,284125cf,2b2cded5,261b7b2b,9759f7a6,62aa5f53,5d2f3168,2a9c0f64,caa483f2,1a84d28f,3004dcd9,5d3344c3,e67b28b5,61e74d59), -S(90f86beb,d1c5534b,105b7618,606bae2a,b0fbdb6,d4fa3f4d,f78f12e1,fbb81ae4,c887f5ca,fe5a0803,9e9d16cf,e5f61c12,678586cd,fbc7f65b,ab01b60c,be5dc191), -S(e0a415c0,68e137c3,b5d3228e,d9d22d8b,b343fcd3,916f2e06,f2499528,1cdd5948,140cdfac,a0276f79,adfb826f,4c9b4a6c,f619034c,a7a3d0bc,9d948abd,32320e80), -S(e9f6cc7f,e29f218f,be6aee63,32f731e0,5ab28caf,254939dd,46e3fbe2,5fb6948d,7c91feac,7fb402d7,8f71be8d,98dee704,c1a0a4cb,43c319a9,9b78e555,62349a39), -S(136657f8,f5006a7e,89bdb5e6,e9a7e477,f78a29f5,ea5ab67d,c948a9af,680afdcd,b8570d97,c025fa85,6e1c95c7,a70db126,f2588430,cc01da2c,81fa49a,1e388b4c), -S(2a11afe3,c4e73600,5a0be836,60f7c99e,6cb0acd2,b6a0745e,69d4c1ee,605cbaa6,a28072d2,50bec98,ded00976,d905fab5,91aee0f1,997386f2,c798b102,46bde95e), -S(d7ceade,fc762de0,36ae242b,588ddd80,ad002019,aa885514,b98545e4,30ebe453,20e318b9,67c2f786,c53f63db,8686acee,84bbb7c8,3435b9bc,e6c664c9,8832fb37), -S(505fb394,d184e5c8,d9a826d5,55ba9525,7ffc00df,3c0ede33,7153bc89,86e1a925,c30ce615,771a2219,40d3987e,52af5c30,8fe45b41,d5078eb3,821fcb8c,9ef722c6), -S(330418e8,93f9360a,40656da8,883d1fc4,89441e5d,5a533c1b,23480695,8e67ecb,2103e7a2,e02ef7a4,c245b479,f6778cf7,e6419d4,41bba641,6f6c18ea,8bbd2459), -S(1467a11c,31ff8b94,2270cd53,54297b4d,e22aaa6d,3aae02b9,51e7f998,e0345eab,9d3e32fd,bce7daff,10685a08,afbaa791,bc0ebc38,d7095045,1b227db0,74a18cf1), -S(d58c9888,fbb41521,ded03c08,fd61032f,c403eecb,1c810032,e5eed64,a93c878,cefe41e4,8431eb2b,6c6e9877,fb83ac78,dffc5147,3c1e5929,28539567,a08871a8), -S(16169695,7d2625ed,b6aa9bc3,9f7dc514,e6c5e60a,39114c34,b960874f,c8c66c82,fff007a0,918a75ed,5bbbe234,dffda70a,7e17006f,1e4afec6,140b9a3,b762969a), -S(7c58b323,1bdca93a,a19b84e0,4312a347,5addc621,91c66fa5,a4bf97a4,b8b5552d,b1aa2ae7,cbd6f1ce,12b33408,513930c5,6335758e,f28f2a8c,c239f727,55ff37f3), -S(7c40af3d,d3e774cb,7c56e809,23b9fa92,f0cafb2b,f1eecb22,9c204cfc,58ef311,4dc0ca37,90e023e2,83b8878,bbca65c4,28b7e89a,76bb0b63,e92e9d20,3dde7cae), -S(a862b5d4,978928c0,49a466de,94176192,f1a57ab7,a849e548,ac12fb9e,369c916e,ca9126cf,7c1176ef,e6fbceaf,26760dcf,b1c24a28,96a3e3e5,a0051d60,ddcb4ecb), -S(17b54d00,5d185207,b4d8966c,62d3c535,c94c6140,166374b2,958b27d3,ae202765,37399472,b28ecddc,7e54d0f8,d80448ba,a0ac56b5,df9b1cd1,6cf44139,4ed92816), -S(40d75436,113043be,31bdee82,2ecc3a69,bbd157d7,72ec9b73,a4a3c96c,da28a6f6,835aa9ea,ab4c1ddb,35fa50e0,e26891d8,2b7e01e2,a237f4c8,c66c413e,faa7e140), -S(32b82a0a,5c267263,3e021c81,ddc1341,7a69e8b9,7b814dab,d529e38,424bb064,ecb8c97b,aeed6bd5,c8b922f3,1b4634b6,fa5393af,aa5e4ee2,c84d4aa1,651b4935), -S(ea460efc,85f7644b,bc9729a6,ce55296a,4277f0cf,3032775c,ff7fb96,da4c56e0,e8637568,b09fae6b,40a89f55,6f0cd0dc,a710fce4,b37329c6,57cdb05b,71b5b513), -S(cb5fcb0c,942a860b,6cbdbcf0,1b8498d8,68c8b9ab,bb224b79,4b8fc38a,9fedf311,3248669e,9fbf75d0,f64d466d,e42fa01b,deffdce2,99b45c1d,c7d8154c,fba41a5c), -S(79432c0,23a213cd,44c29e2e,f7ec5bad,1b4888ec,6673a84a,40a398b2,33aba92a,67cc9316,c2347676,b64e88ed,18fe3ff8,5c9e35b3,cf78d5aa,79c757bc,74d445c2), -S(9dce010c,4ce908c7,d0d79509,27b8803a,d695e8b1,67671865,2f97e264,3a7b683d,49419fca,ede145fd,7cdc7f8b,65dc7b95,11a72fef,2264fb79,1c8d40d5,a39171bc), -S(43b8b5bb,9b56581c,ce92eacf,29fa66ed,f76037d4,3656e4a6,bc0b7f1a,cc42803c,c83017d3,30b17369,70fc16e3,cf5c85f3,199d2d8f,a7179a06,1940bcb2,65313dce), -S(b0c8eb7e,c0fb39fc,b6f3c18b,ef96cae6,b9a23f00,751a4d6a,3a2f5f40,75e544,d66399c,d48302d3,2dfb5d26,9219eb3f,d81412be,c523df58,77e5227b,d65463f0), -S(b981ee1e,4f26ee24,63e81f77,f16dc05b,646e1fdf,d2a075f6,aa422e77,b3577cad,8a582c30,4d062936,baed15a8,9c39ebd8,2d5645d1,c0fdbd6a,d48c587,7626c612), -S(d04c88d9,8ff5570f,6fa37dd9,432966e4,bb524a58,d3ad8cc9,21d0ca06,8fa80889,dfb4007e,4f3ca38,304373a2,931dc322,7469d8f,9683e7c1,dbe59c2a,a17713fe), -S(d00d8053,68667056,55eca05e,53fa60f0,cd778e40,647154a3,c106a3e,5b8a90f,74785ee9,87323562,b815f4d,f9316a91,e489186d,7b1ef978,7ee398ad,51d8f94), -S(87dac80f,34b74bdd,6b2047a1,ebc132bb,c83fded,82405d4b,691d25f8,3e4226c3,da7e507c,2b135b69,501319c4,77ed0b20,731b56be,3dbfb386,4e0f4867,f03b120a), -S(95249c91,bdb94571,7b03d8cd,86bfcd36,3d51c012,38593cdf,243407c1,9322f8f4,a139a970,bff6a5ec,3d9876e5,6dc11286,56c98b90,ed6fa58f,157d7476,deb6bc50), -S(eaa86b89,f5a4befa,1caf1828,bcda7c32,792b468e,9e7530e5,13f1518c,3014cd5c,329bf9c5,6e431d21,a4cee5d2,beb4584,e7aa01d0,5935d7a8,44ee79ff,85f582c2), -S(b2ede9a8,6f324bce,3f62448c,a401d636,9a6ef8ca,89a48a9e,f9fa3bd,9138cd74,d942f74e,89ea55f8,a2642deb,652bf827,79252c83,b91782ed,6b3244a,439139dd), -S(c03fbf90,797b672e,24d06d02,fd70ce22,778309b8,96053128,70f48b97,aff20585,c5d44056,b4fca7af,4b7b16b5,fee76438,f2a271c4,655df4c0,8de3f634,4cac13f), -S(6da64321,c0642b04,ea7eadc2,a7739b20,7af8f1d2,fa99d26e,8e924241,4eba2a25,a08c3484,bf46e429,d7ced694,41412b1e,e2258109,b8c17dba,3370cd37,b8a77546), -S(9269c7c1,4ce5d777,dab467fe,3376662e,6f266272,5e2695f1,fa375b9b,1a1c2c4d,4dccb6b2,ecaf9f7a,fa3fe17b,e2a4054d,bcaa6e33,25b32070,24d5e324,ba1ba6b0), -S(a0933917,a532ed22,7a575482,c1090486,71a6cf38,1c6d825f,98f1938b,d3837992,c079790a,56f5e530,52760bff,8c76df6e,ceba6071,3e90dbc3,88b3527d,64aeaf9), -S(bf2cda66,ceb98433,d3e54e48,cfc15b2b,92c94031,ca9810d9,cbf2562d,c61d7017,2d31e7f0,ebe2068b,c16e81dc,bf1caa0c,6ddf3b52,13849e91,a2bc1bc7,4fecc72c), -S(d1bbcb50,4b9d78ca,ef980ea0,d2b6e8fd,7abc0d8b,3c9227c6,eeee3cb,956d6be,a1292ee9,ae1c3057,c45ea7ce,68cdf9d3,c19a6889,e58b321e,e9858dff,f4d324d8), -S(3cc406f,a049f410,2a752ba9,30f83d98,81110a45,db5fc387,c2d43a44,de33bfde,1bc1a076,f06dc2b5,ec1bc062,c9c480c2,39eb5418,4006e94e,623d2bc6,cb00ac91), -S(5fb9744c,a35cf11c,e11392c3,92bf0a98,5082ac15,5b265fd3,4cd61ad8,55532230,8bd17d0d,c7cbe859,4ff79a3a,15ded6a2,81bb065b,a78726a3,d3819ff8,58dbe34e), -S(27509ed6,ff7bfb6d,31ff0333,a994f531,abed34fc,de8ecf75,642351f6,b259cf3,bf2f0e5e,913d926d,cdca7918,57afbae2,309a4206,b408bc9f,d75b3abb,174d14bb), -S(a619b048,626b9e12,86535c8c,b5fdd8e4,1a64e834,1a8d27e5,d4179569,5fbf70dd,9f79dd50,8e50dec7,fafb80fe,99889701,54f382e2,c2b24d74,6d6d82e9,97049dad), -S(1f8ea1f8,4bd83b5e,56a8e6db,67b5416e,1052a6ba,cdd161b,420d7b46,7070ce02,69b2865e,bd3cb91b,548a4aaa,81d74310,88bb6c18,2d914697,39322037,12760963), -S(fd33ff10,574f02d2,e9c52bf,9a70b430,50917f88,a8eeaa9c,938c5f40,dcd1868a,25fd0d1d,80a21136,c8ac4a8c,4f369b57,d6221a67,3aefd4ce,be30d19c,9334c47e), -S(75799364,7cc47d16,55dda6b2,a269f061,f575ec91,e05af43a,f7e219f4,4b5d2380,d58645ed,d803ca11,f12fb489,9ffbf03d,daf82c98,2b6529f7,28e476d2,22fecea6), -S(fa0717af,d0f83028,3e8e22c1,c240d540,b81b761c,a1daba1,b45ba00,9246985a,ed48a3d0,cab1c4d1,59ef8f0d,e64a2442,c02acdea,43b5b16f,42a75a7c,68b787f3), -S(164fa71c,51623816,52949c27,33c668e5,2a5e3812,a3532452,a6ef44ce,28f49da2,11ecd95c,3dbd9463,4867af2c,290cc555,ef22832f,d7040873,35fba559,e4f010a7), -S(a213fae7,5dd15057,4b6205dc,fe03a2e8,cecbc7ea,1aab088a,fe20e8a3,b46a9a5,c135078d,f26d341,a767acf1,c7b449a9,4ccbd00,23459452,4f5b8f50,9b841042), -S(515d702,8406f03,6e5acef2,1445abbb,daf7ecff,5a31a664,a24396d2,f5d12b0a,db966859,4449028b,f3e6f53f,5bc250f1,51ef3df1,59e26c0f,9f4a346e,d60f3876), -S(3c41f639,e7705929,425ba8c4,2b2f77b6,6a461c81,3bb4e8e3,341eca66,a1344175,f57f10d2,46735f9,f6b741cb,4fc57242,7e5504c2,f6259b13,5745c5f3,a1b8bde9), -S(b8bb579a,f9826958,8e288e37,3be73f8e,7b573e1b,b7f5c1ae,3ad27474,1e9f19bb,5c51d169,607ae4a2,5e9fa70a,f67e6df1,89f1d7d4,705c2854,9e4d731c,f5f97278), -S(fe3701d7,1ecc1c21,3bed8ea2,94447981,75577963,2f8dfa1a,3cee1c47,858da678,8b69946e,8b7226c4,ccb1c5cd,8b416504,98fb7a06,ff8d27f0,da3de97b,74dc06c3), -S(9e7880b8,5a2dc9f0,143407b7,304b60ee,8dbc2b44,4f751fbc,f1b4d25a,da219985,595e4ea1,2e495f97,f61d9220,4f8d06f4,1a78a3,5b6014f6,e82ed051,2697ce7c), -S(b0d1246e,50c2dccf,7cc9746a,afa49227,62487f19,aa6835f1,1379a6e,f3c0f6a3,1dd6e8ef,973d8dc1,fa440594,a70b989a,80728e32,17fa0250,b7c1de39,b1174b45), -S(355aaa35,f5699e0d,e8fa3d4b,d361123d,5b8bf5f0,c74a149d,7cc024e8,2998f7fb,f905e0d5,b3abd09b,5f9b8c36,25f2597c,3430da0f,3439b16a,ada46421,4b678d55), -S(6eef7ac0,ee4da5d4,c8bb3e45,ebc67395,592f313,1d1ba424,1f909ede,818d6364,b0e832d3,92ea4728,7a35d4ec,861a43cf,6733ccb1,bdda8c9e,dd5ee835,92671a5e), -S(7fbbf8ce,f3e99b11,8def70c4,aff57b17,79e4e341,750f7b76,e44245de,8d90ed7d,3032f38b,6570cdd,e39cd075,e4acf1e5,815a065e,f2a84a7a,8f23fb20,6a0c99e2), -S(a9d4c727,a682f85c,b992544e,4e910ac2,beae12af,4fd74ca9,583ff9c8,c06644b1,794e13d1,fa08b167,433be416,c73d7f5c,c21413d9,a3d1393b,84e7e470,a6918686), -S(332dd1b8,ab8e5b66,5c614e8c,807a9015,56612396,adab5c4e,e8ad5856,9c44b1da,d4b39084,5fc9c364,21dd644,c323b5f5,f5d45b39,2885065,dc6667c1,2cbf6b12), -S(ba843971,6fd06d83,e4ad8774,4a82ca41,32954db8,b2bfbdcd,4935f6da,3df7ace,78facd39,b9739785,dab82b40,7dda50e2,db5d4b78,b9e57fcf,8c240b20,5aedb9c1), -S(ac7129c3,3aecb4ed,e60d0ce6,2e2cb73c,798cbbc9,58ef50a5,5bdcd2fd,d167b648,7376ed23,196f4c1d,cf8b5104,5e2c808f,a7bcf43e,2fb9f85a,ac2b3929,4d704edd), -S(17408c0a,8946aa45,387f043c,874deced,6a15eb37,7bcdbcfa,b7ec087a,80516034,cc942afd,78203ab9,77583109,a499b71e,18566987,48c2ee70,ee8a1c8e,60af5c31), -S(4f0df589,d69887f1,ae4e72af,61c083ec,8ab634b1,7b82d533,2d587a22,6f8eca30,e734fe8,926d6662,50cebfcb,50d48e42,593350b3,f2456e77,b6ff5dcc,9e3f3b6d), -S(b0d20898,74f0e672,92856890,51749d54,dc4ad1de,f6d12d3,243830ca,f8da2848,2e790c5a,79ebb86e,fd5a068f,864a7266,fe6d12e9,ec664f02,162ea3ae,e004a808), -S(39d07f28,30d2f3e8,29ab5672,db6888c0,fd224c68,57f3d0c1,aba89da,3f7ca96b,590a0812,e58609d2,e28ae3e2,9305da12,f46b8b0,70c07b2d,a644a956,12f6eba5), -S(20762b89,7ef06eec,ffce19ee,918ba264,4e93a2e3,9f46163a,99a0b218,a94171ac,e1e15917,3e3d5e4d,89cebf5d,6269b14e,784a0d72,e617fb1d,cf7bda13,33bbf989), -S(d2f0ccfe,813772cd,f3b75442,bc16e554,4edde28d,b6c64729,16764483,7b104626,c6efce8c,c63919f4,65a6778f,4b397573,4c4a93b9,43a40ea3,f44d4cef,78ce5199), -S(19520039,cb11eaba,ec1ef6e,676202bf,d5bc4bf8,4e40ed2b,2daa2a4a,2e07095c,fea234e7,3b01e2f6,d03768f4,a534c93e,c6e3cd50,457f27cd,7b6998df,b6e4cd7b), -S(3787750c,f3d73be9,52209ea2,38558541,8b6e79b0,fe1a303b,ef82fd6d,b2c9bf94,b91b2fbc,a09d6fe,b19dae3d,49416fc4,a7c1134e,22982bf1,4aa0678e,c5cdc030), -S(13abbdc1,a65ebbc2,2988a796,bb369866,4211dfce,d3a04d6a,6730d5db,6087b34f,9e4c4a2,b691acc0,b034b690,5488bff6,5397a267,13ed67f2,1374db17,fa8e8b21), -S(602a458e,1cd32ffc,d35ce5cc,c5d7b597,7e20c0cf,66a936df,4eeab00a,b7b31918,167ce780,91340b37,dbb5ab8c,e6fd602f,534149f8,4d67b16d,29724802,a8aeec61), -S(71082819,584ef5,2a690803,d24fde15,148e193f,35534d48,f7a1932b,d3f69928,9b2cb12f,668f96aa,824e3f94,79ee706b,c09723a5,4a588cca,22ed898c,c9aa219f), -S(6349c108,312beebe,145d750c,1ef2721,d536c507,4f0123db,9777e920,c72fc1f5,131f675e,95b5c1fd,856cff13,57a494cb,46e19a26,b9218b67,c6cd2823,c9e877b3), -S(892b764f,e954b331,7c5f8564,b67e7255,1287a06b,32bb476b,f616fcc6,ba329331,b0a0a00f,91d0d637,258aacec,9bd0ac32,e10ff4a2,dbdab74a,a15bcac3,d3fe55ba), -S(c2f38edd,371ef544,a1443296,afeb6a93,6705e89e,fb23a13c,3dc6b619,ea7516cc,6ba10142,71ab78f3,1603a39,dee7ae62,7ee034be,ab1fa0bf,61e18e7e,df40fa9f), -S(bea4f01a,7c61d100,da78c48b,e6277e38,6ec6c265,89a2274a,fd2e1792,b5f74618,d27126b9,9b074a95,690cff35,cbf949b1,8cf0c449,d76f2511,59f1a217,293ceb44), -S(7bdabeea,d320217b,d5e2e84b,eb28b664,e9632606,28a0f281,ec4f2edb,3f3b4bb,49c45d86,f06c42b,4e6e2664,3c4613e9,411103bb,b7abd818,1ab8a0ca,b9ea116), -S(a913e0ec,5e360f89,9c611be6,144a16b7,ff3d03cf,28851ecf,67ab457,53ec31f,9bc12b6a,8595914,333fa4ef,3096cd6,71ee444b,7bd6da65,67d91ff2,d1f278b9), -S(ec6ab00b,e272be1c,f0d359f1,a7fa0f13,55a151a6,d03a05a3,6fee5019,6275846,42d200db,e0edcf3,634055e4,d66cd689,b197f872,d91bf660,e797518f,f4c2ad), -S(a6142783,bdafb512,62b2359b,11286fe1,f15d7464,47f4f507,318800dc,c55ef428,cefd1ba0,4c19a732,aa498eac,9734197c,889cc973,6fd0800d,a051cac2,b0e4bdd2), -S(5f8fea38,cb38f90f,342d7daa,95912083,7340591,c4b98ac7,c9c8cccd,1f2ce457,54c0d093,45974a7b,268f152b,d96541ad,80561ec5,264af970,9ddcf7c,80bd5a55), -S(7b222e07,2d7cc37f,a3d73009,31ae8a3d,cc264153,6c538457,c153ebb6,d84ef26d,9dbae136,e560e343,af858aa4,20e077d9,f4e19cc1,c4f709d7,7875b44,780b90bd)}, -{S(53512a21,4a659914,82cc157f,da02880f,7c4ff9e6,47a93136,c1e55725,9ce7132f,3ccac75b,13cc40fa,5ab2e017,80f55f2e,b8e6a7e7,22b2e6b1,13a28316,b3c99d3), -S(da8a162,a47944c9,9880ddd,c2bf133e,4ec5d836,54609c06,68dbd68d,63784b58,a94bfb99,53fb0921,7b659c08,fecf83a,92b7ed8d,8138c8b1,45f9198a,f7df758d), -S(6eb60bb9,26ae0a8a,3f23d58c,e7dc6b23,f5c17366,2467ed14,61be451a,7513f97b,14225da1,8bb8ae78,8478014,6dc68934,8e4d60e8,41a46ce2,71fedc19,c512d6a0), -S(b03b0869,1b3495c1,5d06c55f,54f1d324,b353d848,31d5c43c,4d524d3a,52b485dd,d7a61b34,9f42ad82,7145f010,e00fbfb4,2e20140c,a0d420ee,11069b25,12147e1c), -S(8eb61e15,83ab8058,a3603895,7709ff11,85eb6bdc,14043909,1b1754f0,506c9bc4,c7ddb27,4c723f0,620fe2ff,2eb11365,1e19c551,32925a05,1b2a297c,9dde4a91), -S(e09474b1,3a1975c6,147f69ac,abe0941a,333ad7e,59495b9d,20747e3c,92f65d8e,98b01b17,b57f285e,b0b9b0c,52f8f390,cf2afd9c,7e90a024,c8758ff5,11008725), -S(20679abb,aa71c3b1,e4ae9454,dbb55cc9,fba632f2,548cc28a,e7f65ef3,c52335f7,158b4f49,53ef5e70,b1c1b847,1f7530c5,39a9e251,98ecab8b,d178b7fd,6b51d391), -S(51e2c9dd,b8da0e35,ac6b6325,4daeeff9,cfb2cfb4,94ea2ca2,46e9ba28,4b86ff33,309b9033,a723ed89,9ffecc25,2fc3c44a,d4bfa991,9c968ab6,664f53d0,4c9d3757), -S(b8760392,98ced8b4,2f1e9a81,2980e5b6,2e2ac1e4,2d6e8525,4bb7046f,68077fdb,310711c9,2b821f61,66854bde,4988708a,67e6c0f0,dd392b77,2435a50b,47d9277a), -S(ae072fd0,c88a0514,a1db9641,50022cf6,c186d645,57be5748,7f8a1029,7cf32f6d,862e7709,f135acb2,2d3f2239,f1d33af8,288f7434,191f84f,f6a0bef6,c5544cb1), -S(3390c74a,fe49647a,8c55fbe6,6b7eef3d,11462c16,8f4a4fe1,447fa5ad,3899ab0,ad8390b9,b98fb90f,b8885691,380229bc,24295d8,995c7810,5a7929b2,d0979027), -S(dd7625a7,10121e02,527bcff1,80f5ea43,efe1c39b,50c20176,6d172c4a,1dc58501,4f6b4942,ac8b6d5,849f2301,9f5112e1,c250b7c3,4f603e99,80ca8743,8d7c8f70), -S(ba116ac6,d0c9cfd9,16e059ee,d94ec9f0,b726e16e,851d771,340eb6fe,4bba54fb,aabc01d3,e65fe86a,4206570f,14571b10,5e226e3c,7d603b54,c1266f0e,258ca5de), -S(dc7ce33b,19c27352,a277797d,a5b70697,6e875638,e5315232,ccc814b9,a2ebd97a,5e4a0969,91396fa6,6d1d81ca,de2d54e4,f0e4e835,ef95f74d,3f21f234,d5f5cd62), -S(200a15dc,6f7b0885,bc49b66a,dcd41acf,b084059d,f55971d5,90173b46,e0755ba7,e68be603,f2c09661,af4e8ef8,b36ac49,270b97cd,f37260fe,9c27fba4,ebc3d828), -S(4969c231,3887e01d,c2837bce,68667593,beab92d3,6f7b0bab,c8368c6e,7ba31d5a,75a8e9b1,5ab4c54,a88a8678,12b93d0e,81887adb,3653518e,81d5124c,4503ffdb), -S(6f04a5cd,5913ac08,dfbe8f6c,57ce496b,dc05930e,56245464,6685ac62,85c3abd8,19fe0060,42a12c30,b7db3cf2,cf3e7a01,abd09063,6c84e285,2a045d4,301a8954), -S(41d07a8f,26009140,e5e338e,7b3e136c,b8b51e01,dd80d441,de584af5,74412fee,a77aeda5,4ea2b2cc,853e3b6d,c128c15a,6e758ff9,d22a8a38,3e28605c,8000113d), -S(dc52e1dc,e07a94e2,e1b7f59e,18e25e0e,eee2ea86,3f127649,a818e786,cc0f3269,c26c196b,a42c4a7c,331af677,e3ef1f63,8133dd2a,bcdc3c37,218b594,6547b3cd), -S(e5c26f1b,311566,152138e9,33ff4834,c17e6ce8,62c84c66,4068dd93,5fcf72da,2f293b72,9c67a27a,6cb096ee,53726ce9,fa88ffde,f8c657c6,af27d995,c4df36ac), -S(44b04185,5f6f4c6f,e6e6ca5,d71dbe95,2e1706fe,f9db95b0,9b073566,c235d50f,18f4285,cf142a82,bd26a508,2bb6b319,eecf0ead,a12f3d20,800de5d7,94d3858), -S(2c4644c2,4ca3b395,655beb0c,32d610e2,f9477a30,7757b0d3,dca3f87,4b7580b4,6c726213,c7864e17,3ff2ed6d,861ef4ce,6b83882c,1c319b9f,6ab76765,26f5f7c), -S(e3b2e18a,24306e18,c4cc6b9f,f42fda12,ea84329c,dacf0484,331bceb2,639f8ced,8a11b73e,4de49f5,6b00a3c8,2b366df6,afab3320,ed732254,c1deac3f,e2d4e601), -S(de42b164,ce28acaf,ac6440e0,274882f,158c1e31,2f080371,5f4ee6f7,6bf6f03c,385de0b5,c533196e,b3d3d0fd,fdd4d0f3,d173566b,7d5f1f6d,5c6c3735,7a98249), -S(3d018969,a03f0134,5b26adb6,31d7abcd,e6399f56,c532d486,bce5b501,98e4b68e,e8dc92f7,6a007d98,f6a548e5,3da24c30,d85b4008,2e7b923e,35a5f18e,93d772f9), -S(c77978c6,4caccd00,27b31a61,769a06ca,636f8603,49fec444,4821952d,9a2fa7d,869c3fc8,1f722012,750d9f96,349ee0bf,e08044c4,f8af04e0,80a03caa,84331df7), -S(f68d647c,e49e9660,efc740d7,1394b8e1,699764a2,9679660a,67566ffa,ead3d9a6,1d64d46e,1ffbb7ba,912b5659,656ce860,cb897a78,21958d3b,ef0185da,fee27c61), -S(dcf7708b,a5c5e05a,4d65200b,77b5ec5a,f08ba85a,46a76bca,dc1cb444,fef50aba,80c88800,d22637cc,6082bdf5,6774efe8,31095951,172909d3,4a400798,c34db159), -S(3dcc7aa8,90604a5d,bb22a5d6,91a42080,ff5844c,5c756fcf,86a2b0cb,becae,4b1721cb,e93246d2,9913fec7,16673f3b,8a02e3ac,dd258db1,d2a22bf0,4412bbce), -S(961f4700,f8c7db80,a5157a76,181c9420,9950735a,e1805e85,7b204f6b,e9b7d33a,85d980ef,b7a33331,4fe0c3e9,1ad61569,69ca8902,6951ce84,cf26c0b9,7d67ae21), -S(54d1da7b,87d57e72,1a6fb923,7b7be29e,db200b81,dd891b9b,9183e3f9,d61da16c,c7467f66,9010912f,e5dd6bd6,ea97451e,3a95d89d,2abcd2ca,ff0a3a9,b90ffa0b), -S(1072acc9,b5fb92fc,41b3fada,7d5a4434,13c73a1,734ffd33,94df394f,ffbff1ae,87594f8,f1f834e4,24756584,40664f8c,418ad3e,7a250e6e,863baa8f,a37e44ab), -S(ae4d4dbd,e751b25f,ea37ee64,bc8db97,ded52741,72f97b8d,64149db0,b8fafa33,d19761c0,b0370155,817e2022,8bf31e5e,3bd0f021,3f4b23e,881b6d5c,733fcd54), -S(328c26e,cb0f4648,4ab9dc2,c33d35a2,d0ead36e,8d1778bc,2771cf6b,55486c2d,63137d2f,a34981fe,f2e12dd5,5825b824,43f052f4,96211a46,995f0001,e6fe8322), -S(ae60aade,4c91ca13,d847353c,61ca90b3,205aafb1,c5c2f2b3,305c81a3,e4c7fd3f,913184ae,93837553,2916117e,34e04698,96b052c4,a93763a0,5f8d7153,2201f1e2), -S(a608ba7f,cac3c42a,20a61800,4d317248,e5fb7e69,b230cf53,567a4114,5d7cabe6,273eaec7,75b37b48,bb6f6ac5,695e8887,f8bde091,1884684b,e64b111c,f767ba1a), -S(ca5033f2,97194ff5,b850ce4f,77f303ac,6188e43a,848fa8cc,b1423289,da634671,34bde31,85e18a14,c0701ae3,4941de08,7e55cf6b,acbfd7bb,9a68fb53,62656790), -S(9fe36400,aa701955,6fb4bc0d,3740bc9f,363dcab7,2eccb27c,35a5d1f2,30f047de,2f841d40,bc786920,af86c55e,61c17d46,84b31096,72dea08e,3c04caa5,82ef33a3), -S(380fb487,1f841eb2,69c93474,4e737089,ddca3014,d9c8f760,40f39b7d,1e9271f9,c7c9944,cfa05673,85d49f7c,7051a04d,dd2d7bcc,36f0469c,8904dcd1,354dfd5f), -S(dfc4a0c,73ff4237,2716889d,e05c88bb,74462b15,2b02b692,6b41af3c,d52bfab1,31809a46,1eb7dcbc,8766031c,d8e02fdc,c882c7ee,a1e2f7e1,5342bb44,53b859bc), -S(561af1ed,8ddbf862,5f1553f0,31e1cdfa,34b8f095,6bbb8ed0,365ad1f0,5c3b589a,965b8e9,c6926a32,edbd7251,251a8a05,e83e40f7,7ae3163a,4a6044b6,20e39620), -S(d0a17522,1cdaf650,ed93f289,ff3d2199,e8fb3f81,7dfdfa95,f7685715,75a6e058,81f7478b,83dcff41,ec9c0cd6,c1515e02,d7eb550,282f37ed,168e6229,ce5c5d56), -S(3f42f09,cd5db26b,df31bc12,a82b6517,aeabeaf3,8c4a316d,27594a03,ecf3de3c,c0494e41,89ece4d9,d08a3c53,ea2bce3a,a65ac759,eaaf07aa,c1a809be,7482ef9e), -S(b7142a5b,239386c4,35fed19e,46fad0d6,2b4974c,f9a7c582,fc45af40,a34ca699,17db42dc,624a1d07,83b3bd69,fb6a8a05,e4175134,9a3d9561,1d4a74d4,28f42a12), -S(c3e483,cd0b21da,31845a93,b75b60b4,800b5e59,43a9708a,251d0135,91d54cae,8e67983e,1469d74d,c61be1f3,f606adcc,a02c5556,a1f06fe4,2f6dce0f,c4c5236d), -S(49d0ae34,23572f85,595efe03,963d6032,5bdd79e1,7a538a54,e43706b4,cf4453a0,fc1505b7,e4e126ba,2a0dfc66,d8bc8616,27918a9b,df985045,9df4bd6,2e0d2fba), -S(9f8373d2,f0053731,f0e1cb2b,1ab08fbe,8ea1a930,87908d7d,5dc06491,7afb4719,f22bf0cc,9b1b995,ce01a96b,1f73f6af,bf92ddf4,ca57e29f,80cbe5ac,a8604ef4), -S(f760b681,1374bc96,102e537b,8b187cc6,989602ec,118efca4,5391a344,eb82ba03,4592a7ac,655cc29,72e26d63,9a99eef5,ace2ecaf,ab414772,de2f8227,87c4d750), -S(4f465aea,bbb79ea8,60c87a8d,541f9c01,afa48dc6,765c24ec,b6a49901,307c80d2,adaa88cb,e882a86a,2d7c2ddb,d5eb2385,faffe9a,ff52481c,dfd6b1dd,f72eb3f7), -S(4f3dacce,862428f7,ab62b4fc,e20d1f12,19183207,64c2a51d,a80fcf1f,f86ed5de,97f8326c,21558e18,d4b7376c,1c14822f,d53c68d3,394dbfac,80a583e3,c668bad1), -S(f1905b3,d04cb49d,3db59404,4037ef71,e42f4311,d59b3160,b917e355,75ca9e3f,c8c005b5,5f49132d,fb2d316a,b0214872,dbf36f7b,f2c876e,6397ac87,ce6b1f3d), -S(8ee0a2bc,f853a469,27efaa1e,3356f1b4,61796e7d,7496cc87,8daa3f8d,11e46fb1,67b6599a,d8037160,f298c595,dd0a5a40,dddac020,d8c8c99e,c846cb81,13c13232), -S(a8f55dec,3872a5c8,c3d7272,6dc06f7e,5c7bff2b,9a8354ac,a184f0e7,8024a4e7,a27ffb57,47c61b33,fe555376,5e2148ca,76fba57e,fef4dcc0,3777dea0,3b2ffaf7), -S(e4cc6907,4387a6a,2e94ef7c,97daa582,9c2f84a3,9b71e76a,c0ef146c,a3209cc4,297b82a3,115c3eb1,eb75677a,bcca1e55,9d2caa0,31e1554e,abb697b3,90218e2b), -S(e3c2e255,57edab4b,64295050,94470b06,e380e503,cd55b106,52cf9fc1,d56c45d1,6621db25,53c70d69,f96facce,bbfd4ea8,32262010,35983521,360bbbb9,43110b8f), -S(8a27f3d0,b4c0ba60,b2875b70,33d386a2,e93e2263,a7f8ccf7,85a0a2f3,6488092e,9525a706,c37af8f1,5ec496b9,ecac74a2,e96ef02e,9c30abf1,2279bb5d,100a2ce9), -S(94f34fb0,2d416fb,4819e24f,165617c5,8929c2b5,a0d00bd,e8c3e71,7ef188ef,c5cf6f02,c0bd9e80,15a436e5,eb837289,66bf2b68,64a5ab82,88564fc5,166ac90f), -S(2a1e9e10,2e0ec944,bbb7c570,2ec1d655,525bc965,85dddf63,e4b4fc6d,ba65943f,64099714,f1c157cd,90393aa2,893703c1,ecacd1c1,87c30518,dcb05be1,d7eac677), -S(cfadcd6e,b147c4d5,3502b628,ceaf389,73ff3aa6,b46a304e,ab7a4608,8a7fbcb1,21cb905,2c53efa7,ffc62ba5,7ea8b29c,4eae5801,2ac40525,6f095363,ae169da9), -S(5f7ab5d1,86b95bce,a294528c,91bee6d1,c4dd6b9b,7f393f7d,db09a3d9,5d268189,9ba6285a,5ece8f7e,5cb8f8aa,4aa83910,3a2ff288,2864aa10,cd6f96a,297392c8), -S(38f751fa,d2993ca6,c3712a16,6981cb52,168492c7,2676c7b2,94463647,5510d2a0,ee57807b,89b36b02,d1452079,6438428b,7fa4b2c4,d4f52070,2f00ea00,33b7c957), -S(7c5283d8,c775232b,b03608ca,3707a2e7,5fffbfbb,1aef19fc,5823d8ca,2c5ee31a,6f645f62,29c3b646,c2b6b5f3,c2755ae,75a5a0d0,a6b732c6,38e946bd,637f7ce2), -S(d78a18d9,ed411883,568b398d,56426fb2,41bb3e0a,4bea3503,18314611,b297d090,fec8298d,79aff51b,ccb9f9fc,ed37639e,aded3174,4d0d934a,b19c0945,8b538559), -S(291affe5,8fabbd34,f011da48,53e100d3,a6638761,fc66874f,4760f7ba,769c9e7e,79c609f8,7ff45288,943bf869,4ec6d4e8,66c77f36,92d9e328,a85b1db9,92bec6af), -S(8cddced6,c63b74c3,608fe52d,aaae8c2b,15be6e3,e2eaa564,ab77d22c,f6e2eb32,dc05e6e8,e917755d,3e54ea2c,21d74781,6e6ab14c,8ad778d9,b7809ab,aeb12d79), -S(67716149,58e24e55,e786ae7d,64174609,5edd9dc4,c70ee3bc,d6764bb9,10253c2c,274f078e,7852a04b,fc766272,1c8290ae,95a7b036,45b20ad,9376504b,92642b16), -S(54bca4a8,96c5abdb,c8170b62,bc7479c4,dd33f4f3,75f709db,eccde832,73d452a3,7b1f1e00,b7f117a0,92196f02,1e499e,5b0a5f12,e4361596,5fd253eb,4891110e), -S(68df83,b0c12c86,a7ddd748,cd687bce,13ca941a,83b2a172,676971d8,566dc3a8,81fbb9d4,49ff2bb,851ade7b,18a5449e,83b2a02a,4be387fe,77eabdf5,964935f), -S(245ac706,b6009bc7,34782325,c176f05d,d5cecda1,9a0183b1,d546cb4e,55f975a1,72718f65,fbffadf6,dc9ebab6,515e7866,af3bf119,739207e,415d4ef0,f1d902a2), -S(548bb01c,70b6cb4b,d5e21e8f,dcbbdc13,76601235,9b1ae88f,2d615bfb,73ace38f,67aba9c0,d0532fa5,c71134f9,e80fa73,f47ad308,e27b6a2,3a3620de,f7e109a8), -S(548d71c6,c5dec0cb,a98c55f,720493d8,f16c14c7,97245548,5249ae86,cfeafc81,9c811c7d,5f7b67d6,728cadf8,aa0c3f39,54130c9f,81a3af38,24e556e9,40212668), -S(aaf4621c,4679308c,93fb34b3,d882aee,f7bed71c,23e5bb36,644b69d9,23ba66d8,bd4c368d,e9bdf4f,9788125d,9db04c58,aed4de1f,ecbbc52,2ef49b39,e0d8f54a), -S(bd0a071b,396afe8a,51a790fa,f11c5db4,2fb2dba6,a38b4f90,f7df7d86,f3fd0bb0,3dee630,46d723a2,1299893a,9f5b0371,e9d30aa4,d24ca28,aa9b1fe2,2636e05f), -S(57ad7d5f,7f45090e,4ffdb906,17ddb128,df3210bf,e10509da,dd71b00b,aa135e5f,58ba58c,b22308a4,d7d7c1fd,5f3935dc,69a5996a,d5825bb4,2fa73034,ad1957f4), -S(308c94cf,c0234e10,5c147a0d,155818bb,d6f534f5,3c02ceb8,14fe03fb,1e0c2c2d,90860fef,f41da4d4,b457e267,3585b997,2fc2465d,de0749d0,dbc3b8d5,251629cd), -S(ed769107,95f5a585,9fa26429,7e51b183,ed30cd21,ce489c48,6268ff01,9d500407,395ae9ea,b309c345,a6aed39b,f2fa5b62,a85801b2,74242b41,433735a6,41a3375f), -S(e4ca72c4,2e3d099d,f48a2154,b7f7ecb8,53ec83e3,4a25c1dd,f7fe224e,50dd6a9d,5c67482e,fd84dc6e,96e3b258,758ef03,a9b72b1c,e210ee6b,b6125143,f2a14f8f), -S(e0cebeb7,32a3881,66a10ad9,e4099f23,3b1ab63f,f214916,a2b24c77,de8c5d2f,6b15c084,c58da2ca,c074f02a,7dcf05ee,8b836bd2,bd7811f2,53df8995,6de6b3b8), -S(da35f459,40db892c,9fe6d0df,98f18323,cac75843,d5362cdd,1706cf59,329faf4a,59ac2e36,d811cce,3f9596f8,c7376f89,5c13bd99,1e7377bf,b9742aa3,7ff78bbd), -S(e1b0a76d,b4bd9e71,ce6bb854,670d2d6b,a6e8f792,bc303d36,bf3a9b97,46ad7833,1561faf7,6a4f6e4f,506ffb62,dc55deb5,6cfadfcc,9e4b14d3,fc5f9dc3,a5c8b801), -S(7a51bcef,7b352661,a73ba2c0,27c2fd57,2d77c45,ea8fcfa7,c39cf9e4,e95d7e36,dfd9a155,29682f33,cbe45ecf,4c0438db,e11a6fa4,51017b94,a33a4f14,5db35a2a), -S(b51f1635,6a08d923,dc87b99d,94399f2,41cf62a9,62eed5e8,de8b9a65,53d139c2,e48542ba,633cf153,43b97d28,157f19f,374a8b1,c154abe0,1624d5b1,17387b41), -S(62be0f15,6e567bf2,452b941b,2ff646b8,97708993,8c054273,7ec99683,d07c22f1,63c8e8ba,3941e7a0,f90ca26c,2fbf9341,df5db636,c113566f,a8bd1193,411de1ad), -S(78012331,5815683b,59ac7d62,54055360,4d4a73e6,453b405,b7364664,5dc78282,a02a235d,68bc552f,6627e23d,d01c2dcf,3752b513,a5e3d925,f9e43a17,4c947ad8), -S(19d975dd,16aacc11,a25b6d36,580dcace,3cb19e55,f4a0c9f5,b221a847,c8d64d2a,621bcee6,c7662473,ac82570d,7f888020,18ce7b83,7b635b3f,d44ecae2,d0633f12), -S(ea6d786e,dd234888,561afd6,a57d9d38,2a07450b,8bf787ff,b5763d3c,f9f7e5cf,ec4d538c,de2077de,a8c68b96,69bcfd9,700e2e3b,ef671a3e,38bd9d50,c785ed7a), -S(edfdbc79,dda15c6b,b74fe3d0,711d933c,8d466dcf,b0a51334,48e9025e,85c0e669,e503a18e,e2ce2fa2,3512c4b9,c7e70dc,ff70cc6d,e6f78e1,74fc64e5,dfd4a2e4), -S(d79bbe99,7c2ed85f,1f687ce8,b761caef,9629d374,ff3a1c5c,2e62aa55,848ba917,c87c80fb,db44be0,466cc253,5fee352,b52b65cc,c9ce620c,eeb0e09b,30dc49a5), -S(9a3c43a0,230fb046,ece16ba3,29999f45,ffbfd674,a1034025,8ed4b71a,d76dbaca,84ebd352,b26289f3,d0f0827c,fbc95da4,79baa21d,6a98c85f,1a54e773,d06dfb9a), -S(bba0583a,9915f4a4,5a015244,29bb3362,6d36cec9,f6d6e966,3d0d0e93,ab296a5f,f2f880d5,8b29cc71,23b7212d,a0068bc7,17ed8651,b262d8a2,67f2b959,4726eb79), -S(bfc82f8d,50227d6f,bd7be2fb,fa481d35,9b2399ee,ad216a36,5ee7a0e6,25843e83,43c7cc25,f3c527e7,a42e15f0,d73dcded,987ead91,4dca8a71,f6e45269,e0132aff), -S(e5a790dc,5c6399ba,43519268,e22fa9ef,1d93073b,e4b5a07e,d8c7ff25,c8674a1c,2dbe7dd6,c60650b8,91baa13e,7580afb1,c68c213b,cdbcb32c,b7d2f7a8,88f76a47), -S(c48038af,f4b316cc,928b2b94,decd9975,dae28b6a,46dc0d9c,808a5f17,3b251f23,8f1af5ae,31eae121,b5c53e8b,59766137,7e064f33,107784e,751c0bba,43cadd4a), -S(a0663a89,a8770439,4322ae5a,f2d6132a,e6882f72,7a30c7d6,c774d34a,50947e8f,6b3e8a03,6f099441,1b598704,55a2ae52,894a4aac,b49717da,4ac053ac,4a152d9b), -S(776c11b,2c5b2766,ec2d3376,63672bf1,933e6bb1,70d96423,484cc0e,f75fa07d,7ad71572,7d6552ea,62188868,8ed43013,53846bd3,da2e772c,e5e7752d,ade5505f), -S(6cfbc277,48c72aad,d60b2a5f,b04160f3,45fe3f2b,ce005f66,4a25e444,87ef44e5,96d309b,11b41b41,e851fd16,c4c751b2,be08a35e,d912bc21,8673ee4d,44d535b), -S(6cde4b89,ae0d961d,3faf8024,b64fad52,9bef7e4f,9f7792f6,ae242f6,7f559915,d86bb9b0,de0a82ad,ede30426,98526356,5d7ba22d,6be061d1,f31e479b,3590e3d8), -S(c2eb111a,62da4ddf,72cea94b,a85d2777,1ed639c,6c511c65,cd15dce1,6d4ed6ee,ccb342f5,3248ed9,b4e9c8a3,edc75d,cd519754,ec0e82cc,970a0190,40100231), -S(199dbd18,e72e70eb,7c16d374,c32e4f21,6f6f1015,96b91690,a846edeb,83366c79,3daa0e0d,33059817,dec9591c,a3981891,7a10a344,1d5d5be9,2ce4d81e,1e24ca3f), -S(7b175876,b6cecc08,324f0564,244b7912,59a04060,d63d9bb7,b1f9952,39b7cfcc,426a29de,e407029e,80872b20,3309b9d3,e99e9099,3892162f,385f7576,d9aef02), -S(8c182626,ba2b47e8,8415413,4c131ec5,d0464001,9ddc60f,7136ac5a,cb7f7f70,3eb5783c,c185c51,12afd02,16ccb429,d35ae768,3ff5f3ec,7de3fca0,b24369cd), -S(c21bf9c0,31fc1e5a,a18bcabd,fd278fe,ac280c08,d1edf19b,9dab3ffd,de8a6d5,9832eb2a,26d38233,f057708f,4465772,baeab661,c0b958ec,95e0e02b,94bfc543), -S(28003d74,2da7249d,67abb09f,36ef29bd,3eec106,5c02926e,eef4198,a17ea4b,f7a23dc7,779c9bce,64ee2bd2,eca6fea3,78cbda92,40c6cc9f,cef560e4,9b4dfeed), -S(de29158f,43169b19,4de65951,1c905015,2b0990cc,d24e73dd,a9b0fbeb,660749a7,2a39a6ab,42b79a7,f243a8f6,112333a5,8451866a,280dfe7a,ccf156b6,8f1f6f2a), -S(5c8c9c5e,8066e79a,38e3450f,59f2e504,2a65db6f,44233598,4bf0e4dc,37550e62,d33b710f,8d84ee3a,b8481efe,7cc4099e,8a47d64e,bc0433d4,f966fb05,7e4d68c2), -S(33853003,86c14fe8,1ae5ea18,1cd3ac20,87ed14d,6014bf9e,cc8b386d,dcd10541,db06c040,7ffee11c,5dca0af2,1856426a,97f3831a,850d4107,12b314ee,42ca1129), -S(43506cf0,bcb58366,a3faaf0a,fc8ca79d,3022cd0c,7b17ba3e,a7ea2e24,8332670b,4869e72,44c0fe15,39a93b9e,c1c16e59,880394cb,3cdda9fd,d545d4d5,968d86bf), -S(d13850f0,fa4e1a3b,12397c37,8b2f6654,46247ff1,d270538e,fa4d77c8,ae27b2df,91588b2c,c27f879f,ddd8a8ca,22165952,38224cab,e3090655,cb02b045,e869ac34), -S(995b5075,c2e57ac5,3bf1d8c,8b9a4900,207c9dfe,b0dcf3c9,86662c2c,9ac162c4,c75e3e71,3c7887e,1a47a400,dcba8a5d,4fc7841c,7f76f0d,e150bd28,ec3b14d0), -S(6af47ea0,6e2e8217,62482960,10afad10,b48d75e5,ee95f04d,66dce112,592cd7a5,2d6b4963,ee90bd6,21ec5220,6416178b,5d7b0853,7fe8cba5,ed06a25b,1078752f), -S(fa6a5eb9,780c0714,6f5abc1e,52bf1113,bd512198,95233975,4d58673a,64db761e,e57e10c3,d00af8ed,f4d601aa,e236e17e,91ec638c,d01c0c5,aba1d243,b95c89e1), -S(6d4b83ac,e44638b0,1a729bda,479705ee,e4194525,182dc1cf,f3002fdc,1ca3aada,1f57193,38c38891,fc6a0b52,c49c6bfa,c5de856,72c9ac41,3b137834,ae7ce48b), -S(6ea5d9b4,d638bdc7,22e03664,fb63d6b2,368a9bc5,eb6f68c6,61f79579,d89d9de0,c0c306a5,6073a961,c7e85e0f,3221bf96,b09f8ade,da8ef6cb,8289c8e,54540af8), -S(1a2f35c0,349c0cd5,1e4c9fa8,b8ffe4fd,8c595994,2d172dda,bb8bd8d2,d22628d2,55357f7a,cd9a9694,f2fb8a31,46546a4d,ae705945,766f8565,d8dee125,a9735003), -S(34f6720,2a17f704,80565d92,d5d268f1,95cc0873,efbb0a45,62ee87b0,bada9e07,fb3bb7f7,f878b28a,2fdd81ce,71465d96,e3dc32a2,1dea4715,61f464fd,29b19cbd), -S(93cb896e,64d0c453,3d82977a,872ae1be,1f1bd6c1,d4404ea,f7688496,2a214a86,f3028814,8f07a191,4e908ef3,66d447e7,1100fbc9,4ad1e4d5,bdd01540,135ce7f9), -S(1d5bda0d,c6378439,d30df39,5516e605,7c8b5f6b,fdda8582,ccefec6e,3d68bafb,45e2182b,a2377a32,df9b590e,943920ba,482db2e1,443c4269,37a6fcd7,14555175), -S(4d0c346d,7c4c5730,4125f376,9ecbca25,33a737e0,d5c4a85c,357a8f4b,792c02e2,4dfdb5b4,b04c0188,e8b1593f,a9d82ff9,ea4c8314,50231cfd,f5d0edb5,6f7679e1), -S(808f8958,d263ad70,bdd91b0f,76f352b5,c5c280a0,90ad41ab,28d60bda,69b52052,cf8dc4f9,eaa81931,f29a4e04,a0929d3b,c710f43a,845d6b8f,c8c9af81,7fc66d77), -S(6dfb47f6,e33f8073,9251982f,7fde21be,1bfdb916,41a8fbd0,1a36a2a8,6b10a3b7,447bb5a5,e1895243,d33d3883,e8210f3d,b412df54,adc9e35f,313a8006,141efe99), -S(8894aa46,b158f826,12ad4455,35ec03bf,c2625d61,58de4278,2848a919,65fe5e,3d280519,aef54f53,81a73760,6c4ace08,e48e87a2,71beadb,cb17314a,5a0e4b85), -S(bef6abd2,a6a2d391,a045c2db,24456a53,3dbda4bd,4e39c3b5,afb1e845,9cc6efa3,b329a528,f05589f,375c188d,83a3b7f2,89a40276,7482dd2a,4c5b07d9,df7543d9), -S(2588cbc7,171a57b5,afbc6685,6546fcee,6f1bba26,7cf73a8e,1eee643a,290c8b7a,2b6872f7,a85118de,ebfbb42e,21bdbdef,73426417,f2cf9a66,e430892e,c189f192), -S(e1362758,cbced085,6d7ef7c,9fd4023a,6aaff6a8,46be23e5,fb7e143a,e50d2fa4,1d4b750a,e8fd53d5,bab60889,36db9fd6,1c05bed6,87abc705,5882a4d4,45754599), -S(f1bfab09,821e2d48,b8849002,5222762,b703615c,e89300b,3774a966,c5bb2dd7,5cc77e20,b0ccdb36,c48687e4,bfe5e264,50dbc5e8,df38b1c8,322777cd,1396d309), -S(f3c5dcc0,778156a4,ed1fb225,bf1617b,cd56a4d1,4d91ab0b,a135b900,ff5cbe74,297e4146,42d565da,17933bea,4bae64,188843cf,9ba103e2,c33e533,15ca5ff4), -S(b8c26559,6fe544a2,e34bedd1,88a82771,8e48f880,ef1a9e00,d4cb7ece,84f79c23,9fe1b2b9,f3e3f392,8ff8b8d4,a72670c,dd9979f2,883f44de,f74dc6b5,be093390), -S(780b8246,11dffdaa,2ba0f9b6,154305b0,6a536c10,923fb056,ee6939c3,c456f6ff,802f9ed4,f6e395c8,b783b21a,d5b7e58d,6d3e17d0,b73c3607,39d21ace,7f05004b), -S(ff5d8fb9,f80b0d2b,9135052d,97cd1bed,de7c0622,f0c7c9d4,7add4578,62570cb2,9cde8f57,d9f72bae,e90a6e0,89911674,bfb126ad,933439df,c9c1498c,eb38aa6e), -S(9b05a751,91f7b248,f3eeaa5,2fed8be1,b1da6e9b,12313382,3bf46a8b,220bebe3,17c9939a,92db1886,e178faac,633fc1af,4249149,3b8e1c02,51c78d78,5c5ed5f2), -S(ce661b0c,12d51507,d8a066d0,5f43680f,909407c6,9b0de379,875ba50c,c8aefad8,ec469d8b,c9095247,53f92cb6,415445ee,7fb4a67e,d28d3019,6e1e1d06,d585237a), -S(20916590,d0a22ae8,3bcf92fc,91b93643,188d2289,12eca21d,5cefdb6d,a46654b4,2d7bf778,66ef1253,92854ac3,7846a5c6,3feb6b14,ba1b36a1,3b77ac3c,8670e871), -S(ee7c4337,24aab6a0,fa304ac,50501cd1,a540309d,99a63c56,6b20165f,1283cfca,9e3f97ca,ea42cc45,51283884,b19c2d11,50c420e0,745ce88,8ae82918,4db7c50c), -S(a23a466,57083750,56b5712c,2891b543,150c474d,2d02b9a1,8d72603f,b695ca09,f5b2c285,b4f341b2,966e71ce,d1e5c64c,e05e8058,ff2b4a2b,616e6f5c,40f5516a), -S(21193f,20328f14,cb0d47e8,6bccbd5b,e1a2fca9,fb1294de,6cca05ac,f5697768,16147a71,cb2d0f18,38f1e80b,f395a13a,9c630167,caac326d,aa890139,ce162042), -S(89db6f1b,d405c8d,b29673c4,2dad2574,ebec14ee,9cd6ad0f,1ac55f42,eff5067b,20c82a6f,ad90c731,420cdbe4,47e57450,d544006e,16ed9088,e5a77089,4911b3ea), -S(1162e4a3,4f3a6d,6b360059,258a1a4b,2a316064,b2e0aa56,3acf1a5f,812a9682,2433cddb,650c9234,aa4d6d85,f8442d83,1a9fb48a,9e92e62b,aac0ba2b,c90d1807), -S(6c439ed1,e0dcaa04,a87d4bd8,6898fbfe,80fd130a,c4721fd2,8707ca68,d1a99104,b221ecd9,2da68080,ec98c4da,be4c615,e2091f90,4031f875,db1e27fe,4dc852f2), -S(ba5b6e84,f225ce20,7cccccc7,6646f78a,3da1942a,55792678,18e70aec,b651daf3,9c50d8e4,f3e0386,72bed48c,985787ed,62c4aed9,1f32b1e7,482801b2,be4e09bb), -S(deb90434,437d5b7d,32228c47,e3e384ba,4424010c,20689aec,99809623,22cc3527,54ae32de,29288f59,e78e0fe0,b690b148,d60487b6,971e6c01,7561f49e,3b5855b7), -S(19120ae8,baaa0394,8db3e91c,973ce918,e3b80039,15b8df5c,564f8b7,ee7d4485,c260a8e6,e3abca0e,8b84a937,a9f5e19a,160d7178,d40906cb,4b2221f0,d6b9b84c), -S(d3f5dabe,754636a0,741b81a4,5abfcd5b,90b8acd6,94e58419,df0dfe57,e2e45c8a,f58f03b9,5c18b14c,859786e9,24ae9ed3,8d6c800c,57793e64,fc4a711b,71829149), -S(84b37eff,d81d892a,df94d68b,2776ae21,47c56d3a,c9ce48b1,a5057830,eea659c2,b54b242f,7e438a9,ed18b0fe,cc8a4552,dd9351a8,f763a5eb,6a217669,444a96ea), -S(32127236,3f659d58,2e0871a3,5aeeb25a,ab7acb6e,90c1feb4,dff53f4,a3eaf0a,cf01c0f0,8bb8ca11,dc6b019d,dddbbfe,ed3d40d7,2d06116b,62618179,fa8d32ff), -S(1e07bece,17458a93,98c489a8,aa0acb83,21743558,f009aaf7,1be7034d,c6263023,b0b063f0,c11ecbf,f055cd8d,6e43d009,a7519613,44498adc,3f7c87a,441ec9be), -S(d77e610f,8a969baf,fdacde3e,44abcb7c,27207311,c037e516,5a96f17d,a656ac7,645ef0e5,2e4f0786,5a7cac65,54066137,fd8536a1,2a4aa0bd,8f535254,72e731cf), -S(fa630fde,2aeebd4,7ac7caf9,3c6b4523,cecc5f4f,5a26d0d9,a11d6b11,19816c14,acebe389,85a9dac6,f3d80e0a,a4271c8e,c81aa049,d9eeb36a,e89fc522,55ace7d3), -S(e3e53a9f,a0d0286a,f56f1418,20ba1c38,1697e298,49fe82ab,4ae5109b,2bb2ac32,f0eb1f22,e432dc55,98844676,1fcdddce,de875b5d,f7d8cef8,109e389b,8720819c), -S(1372173c,a0754968,db48bb68,87d1c81b,47686f89,c6859fd8,3d608fa,8a767367,31ab8ad8,be50a9bd,99a738f0,345ba781,a2d39e94,1ad9ef81,4d4ed33b,bad08cc0), -S(5a82c886,754bfec9,69fbf970,2d87183c,4c6ecec1,53e50d49,d4a3e1ff,341b9b3a,b8abb03b,63e4bdcc,a58b3717,7f349fa7,4c87afa4,79ecc3ef,7e15352b,6d59d61d), -S(aba39636,9a7a032d,8cda05eb,588a04e,e0b3e75b,dea52776,16af7bc,14423f4,63bc3d87,8f419a78,440099d0,e26f7e73,8597982e,4708604c,e8eaedc8,2c54a34c), -S(1db97bee,460e7aef,f3132d52,48ecf43b,911efec5,1051efda,9a231ca3,a366bb86,8a297bee,fa67a334,97cfd06,211c0e0e,b876e570,e255f415,c37bfec4,bdcc129), -S(d115ae92,b28c2144,a62c6272,50cf5b62,7641533a,e5c2aadc,cafaa9fb,7f180c0f,b7bda4eb,63064115,fe29dec9,4af5f9f3,12a354e8,24827fe5,d33e0737,ac3a8657), -S(15234a63,9b7e216f,7d035d46,7146b90,2812f449,cd7fc332,ac8d773d,b042eb65,8c0d946,a55f5703,1c9ee375,b7e146d3,b1325114,72527aff,d4a6d36b,e96bf6a), -S(25290f2a,b404b4a1,19bf8895,c0c31357,1b9cac69,7d25c6aa,303cfd38,f375b190,f7b23d34,2ac85b40,9729f41e,6977d70a,394c037e,8b43c148,e8d7ad5f,1cd35a0f), -S(6a75480,e949ab33,dec0849d,80e4e458,e8a3da3f,bc7f0c10,521d752f,5fcfac3d,8ed6efb0,3dab1dfd,fb3d7c1a,90419b59,b4ed6a09,b76a1234,ec8f1890,ada92a06), -S(37060ba6,e749f01b,99de96,ca96ee67,ba0c6765,6c1d10c4,8952aae8,80350ed2,7b5eaca1,b6ececc8,87dfc4c5,79cfa9bf,c9e72bf3,a6bcf79a,3877caa3,553a420c), -S(e3bab26c,6646c20,279cd320,76c75574,4177fe6f,77de9821,36ec5162,5d13f5f9,3377bfe2,55a7c6e2,24ca5ab2,e36d535,75bc4333,75bff71a,8ebc1257,5f7fb0e5), -S(ddad1dba,85a9b343,bc53d5e5,956b8b7e,11331b3e,8a572679,4b275930,b9f31e07,412686c2,1acfe9f5,3ddf0e5a,f5ff827f,c3c912d4,7a4a4d55,37a9a5fa,29bdc4ed), -S(6cb6f196,a0deb885,568b7595,c3cd5198,d8755e78,9f194a53,ffb863a6,4858968d,56918ec5,2263ef0a,e34da425,69277e1,be8b7c97,880081e9,1532216e,c3798e87), -S(f5dc85a2,d7c3da94,833d7254,aa8c4a7b,6b105193,eac25377,d20ff6ba,26a608cb,a311c934,58419e7,823207c1,8d1cec01,dab3a2a3,248d1be5,e36d5b1,b076054d), -S(d8d0a942,57fc6e64,975a62b0,4620f382,c8946d2b,3a14397c,6f7465a2,1021645b,7d0c9f12,291e0493,87202b90,cbeb3d52,328a002,3b79b3cf,6c22e1c2,bbf4474f), -S(a9bf9157,b48c2e92,537bc4a6,43d03a4c,a0276831,a00ae6c7,b31a6d44,ebdce70e,34444099,98aa2495,e7d0ce03,fb265ac4,76ed8c84,ae87812e,b52ed5de,d482c1af), -S(e88b3754,d452d447,67b7765e,9bcc318e,2426e82,6f038685,e696b9d1,e2fc509,609f6fce,4e37102b,dc9def2f,77551726,a43d2b7,8d81a672,7997a94b,a6824723), -S(3f5ce314,ec4060ce,9d6ffcbe,bc6fe525,c9f5b80f,7f64b92e,242a4768,5002f619,bbcc8269,297e4467,950bdbbc,e0eba72d,815822fd,6679f5aa,122b5b1c,f1ab4571), -S(fccd783c,c1b4a564,cf93810,adebcc17,c2417f3f,d9358d59,ac32c13d,98c30305,65388d09,5f8d7c6a,1c0a40f6,16748b7e,30708444,acc9f90e,b644727d,b1984852), -S(6e372625,ca297c57,192852da,61b97651,1b0a6306,9bc63bd3,bbc17fa3,2c03765b,3216c5cd,2edfbc3e,1e2da24a,64c3de41,1229bad2,e44b4548,86b4766d,db184885), -S(364b023a,893779f,d8dc892,189f7565,b6642766,439d3e4,f9a27111,e001e191,74ceda0f,32a56290,8d9649ea,56c3bdbe,9a4c0bd3,dab2b99c,f9067a62,d34a9b6c), -S(99374e3d,dea10db6,b493a0c2,3c2cceda,8ecb2b41,6364136e,2f8acbd,51d01791,f9d261f6,733d7826,af2502f7,8fadd97b,c3644559,a1d18162,388c8eb7,b372ae53), -S(f1e858b0,2f8bab0b,12711388,70310289,9f40b11d,ba24c309,89e237c2,e5ae6aa8,3538eca7,9ae4f5cc,da8085c7,b53ddf55,adbc1b51,8d4ce4bf,9f00e22e,b7afa426), -S(96424847,ba09f93,37b83bc4,f5b5a4d,a79bbd37,41258d1f,95dafe86,f3b8751a,af2e7579,e2c1cb46,5a8a5d53,473f7d37,398d33c2,6c51f5b5,954fc1eb,bafc5ffa), -S(2f57a7c1,de175570,8ea98914,787ed66e,246a24bc,2ee81fc8,81ebc6a8,838f8e50,dddb2d2e,6254b5e0,e090ac4c,f758879,1c51b32c,f70361d7,f898258a,a7853c48), -S(4762735f,ba8aea2b,9eebe42a,b1eadf24,1cbfb083,163f8f8b,104257cc,360d308,b03f799b,2b504ad1,e98ca6c9,fc27a851,63fbc620,9de110ba,cbcfe7c7,783a0860), -S(6390203c,6c219a18,e6390e45,e8cef444,ca6de696,4ae43a44,e0700dc6,a735a125,a9e6e44,5a3aced8,f072c0a0,1f5d1d54,8f6059b2,880edaa,fb42fe8b,cd4787b1), -S(2986e39c,d19ad213,b171b4ef,c24bac25,50a6fafd,7907f9bc,440af15a,35926a3c,ac5cab3,b35f667d,e4d2d7a3,48010cdf,bfe0e6ef,67287bc9,ec39daab,395a1e52), -S(67337f65,973e6144,e4f10db4,d8e29ec4,46a03304,b6a949bb,cbac7ffc,ffb4ac7e,66589e70,64003376,8043360c,977e35da,41e22f6c,3c3299a8,e0642b4a,55c1b99d), -S(3f9f9f1d,e2775ba8,96debdb,a7cbe0d6,5d2058c2,4a54eb7,c021c226,96aefaf4,776f68c3,292e0ef0,ec737629,d15c8410,7e40dc7c,fe846936,3f2cb18,b4e772e4), -S(c42e2e02,20f965e5,3b40eda,a3d7b450,24b943e4,2067b40c,4662f6d8,1cdcedd4,89ae9af5,95837e93,6f419b4,7e8e0e3c,a768bda9,a6a5aac,801b30d,b34e0bd0), -S(89f638a1,7ad9e13a,378cd116,38a7ca27,181b7d83,6d8423de,a2ac857,9a1cb5c8,83397996,e70f91d8,5a72747a,9c2dcdb,fe895967,1e2001e0,b8ec5acb,67f4d008), -S(677a6390,82642fb8,dbafefb,7cda5bda,294e6f45,73312359,f6cf6551,ba0f2013,c3d208f6,e7c0dbf,f35ea183,9cce662,df4c0c79,d9ca62da,942a7601,f90c5d5a), -S(e5f2952e,36002cff,3787b459,f2b566d9,aded6da,b00b31ca,88c05bb1,789c56c0,6e635a5c,a6bfe707,f8111c0a,8853caa3,52ae42d5,2835ad76,7e6b0b34,de24d626), -S(e9d7e208,e3550536,e827e2db,1b5e33dd,6e3f520f,eca9c121,38ce6c79,cf9bc2cf,b2c90c54,90ef649b,51508c18,f9e2a87d,c95e7446,7434d9fe,cf362304,6c75a548), -S(76a0047c,a21f1cdf,f1934c3,73ab3c14,801f3342,e96dc8b3,d9c9f9ed,8ed32b33,28c5e795,f0cc967d,36a06b75,51338d8c,1967a2ea,47468a93,a79927a8,b93f22fa), -S(6e25a2c7,1c4d0918,45156c41,a6158082,44141684,a148b2aa,a0a29116,4ce9f7a6,b47a5db,c22779dc,f8368917,ab2ad290,f0ca9387,738a2cf8,f6fd00f7,f7120c22), -S(5dccf366,b6a32767,f0e9f544,315d56,754780b8,ffe31bd0,4cbd4082,8df79dad,3ca94a06,188ffb75,81f6db19,4a40b3f7,c827828d,5339c9f2,1f0bd167,2de0f8eb), -S(4f082d78,87db1b89,744007cc,14743578,634c144f,c199dc5e,6b024570,595aa74a,c982c1c8,8a724114,e164361e,12cc6810,7639a530,97392b24,f11e89f9,e3c63525), -S(73dedc7c,8cd2b6d4,de56e4ac,9fd8e7ee,77f314f4,11d66953,2da150cb,896025c6,5805bc18,3267c258,8a7a5820,1e5c8f59,f05e8384,a380486,af07c89c,1b1a318a), -S(8ac4c219,fa1cb64f,625b7b6f,c1278cd1,2958c9c6,4cbc964d,127bdb2a,e472b43c,7dff6939,5f076e57,6882d7e2,d0fcb544,1e301834,cb5085e6,6000cb23,cb621cae), -S(72388fba,92feb394,fc6e6cf7,a849752c,41665040,54271441,c7a9cdae,facdba6a,cb846fcc,e7518e85,54d90f1c,286b889b,31bc2910,4915f30a,b36bd43b,e2234e8c), -S(4b11582,3f8b93a8,5907a139,5d4ef6f1,2a34576d,bb021c66,9ec26ed5,150e5fcf,ae353938,3897397f,15daf2c2,736c3929,93a1d05d,45268cea,3cd62ef0,a340f5c6), -S(b4b2effe,f45073e1,57b3beb9,59a177ee,89dc672f,c14cf312,fae3449,60064d00,bdfc076f,17d0523b,a83d21bf,e0f78623,ca0e777,eb78415d,965c4f6d,d1476472), -S(8143ce9f,a7b5b232,3d3d6337,8892531d,12e3152e,e14ff290,1790300e,99434113,9b6c8eed,b575ba3f,94029d9a,5e7eb6b5,1952b760,2550e10,babec290,b0fcf0a1), -S(83c04e84,9fd179d0,d6add7c2,6ee808e2,a75262eb,51301dfc,a15e6a16,4e698c51,a4c05e15,156790e,802f7670,2d10dc49,239f8d1e,fc9d612d,c7e8aa85,20b789a1), -S(7f5b9f0,57d3b50c,c39e81e,150a741a,488c0bd1,2ca18fe5,cf871b6f,22832554,8246a447,5609e61a,a474db4a,c9f526f1,197cdc40,86c7ecb0,edd7ecce,2539aae7), -S(e27a13f6,a1b82bba,ae5d0212,e0fa90a3,a6885ca4,684f91e6,dfc8343c,14841979,c9164ce9,a53ef56b,b5805464,7becc9bd,64a49103,70487438,87152f38,237ad8b8), -S(4ba91b4d,e63fb74e,9c06885,340dec13,8f6013c8,f58abb7,5ef0a748,bc323cff,6595582f,fdf487f4,feb2eed0,206bd640,7f1a24fc,3cdb0fd3,bcab0d30,739efdb5), -S(37a80af0,650f33e6,360fac3,19b28e3b,817bad51,bedf9193,c745a45e,93f378fe,5edff10,fd0229ac,3ee2794f,155c7f12,b50a08c6,7b5e6d43,8931af1a,a039f892), -S(65587572,6c9a2bfe,9c2faa59,474247c,6955cf20,1bcf6c3e,513e7b54,2b5dba5f,8cbfa42f,ee790c4b,ea965128,14063b46,25131ec3,72028680,3fe69ae,2e896389), -S(a289ebad,8d4a93eb,f7cad50f,1477246f,1345a3db,7699c9f3,9a7d94c5,1433f957,41ab3d30,9b10aed2,32fb4d6,ebd906ba,50e94f34,9e4e6ddb,a65ba374,d4bb6f82), -S(d70d75b4,93a9b2b0,9af912d9,50336091,3e8278da,e73f188e,9d7f5f5,b159aa8e,fd76cbca,4edacf41,f568b81d,8f854fec,439a0ddb,caa0ede2,5f7986b9,a6ce746e), -S(97c66bff,6c03339d,9b688460,58e4bf90,12273be2,32b1f5d2,89a426d3,72024ebc,3db99430,4cb5571d,7c5ff64e,76a90913,8ba307a5,ee8aafb6,6bc884a7,590d0e7c), -S(b88b642,5b8aee75,ce0643d4,3e2a168d,2b1178c8,a9d3e5a,ce2aa55,1130f8bf,cb954eca,4898b75d,db5f9c4f,68f8d9b8,6fb7352c,112e222d,4e5ea298,6a47df3b), -S(41fdc70a,bca5624a,cfe93282,1550ed70,d31133f1,83692b29,c8013601,afe6d0e3,608a7ed2,d675b20e,6a9cbb69,7df4a79a,f70a570f,a2676830,39b69c27,a984fdc0), -S(3f2304f1,b643cdfe,630e184b,854895aa,c2a03f61,59c70ed4,a9837fc0,c0869434,df5e1d6d,11333420,be9df6b6,5eced485,ff0e4d5d,3ed79ec3,788e15be,dba57b56), -S(7da74b0,687c9c5f,d063f1cf,44b2c644,d51b2e17,49a3f8b2,b98b0d4a,7ab43258,2537394c,a042c341,b5faa3b0,35f5f19c,fc2ec9a,f6f34c52,34980336,1d89fc99), -S(88487901,eaf30bb9,27ed414,1a9112be,dbc46be0,52f43a1f,e910f23b,52073fac,6bb951c2,b7f30e71,9ee77955,50189ee3,9972adb7,fdb7a8f9,f335c8ba,51aaf659), -S(ad5c1c1c,ec3033d3,9f3d1ced,41f2e369,de9883ba,3f78e7b2,5dd658bc,42aeecfd,90001dd,b99673e2,37405bbb,f4d4321a,496f4350,660bb9d8,d5613846,e4e6fe6f), -S(bd8dc061,3da485f3,43335bf3,88a57a50,429d436f,a74a83e9,8d9d93a4,868a38af,173d962a,fa7cf6ea,65c8755d,870e4eca,1ef9ba70,97d9bf6a,be26b575,1fccef16), -S(900c9c35,ac4e9132,4f60b380,c7e80b88,f33c9d7e,242a248f,6425f010,63d99af9,5a6e22ae,dade8294,169c4645,a4bd0e73,ee212154,47a4f06e,6a662a0a,a7b88cb4), -S(e9384af4,a6f649c2,720601aa,7c5e62ba,2c60537b,1fd2c416,b2985601,1d18165,61295342,ed716c76,c4d35706,95a69bd,65fd9a2b,832ac562,59686967,1833b0cc), -S(b053211e,e18fe64c,aba2f7fa,9d8b8d5,e79e11f5,8188a811,12b2f9bb,e61ca72d,440ce2cb,27a783b7,defa2d0c,a0334f84,7d623960,ec5007b8,56f8c7cd,932a89cc), -S(6e4ec6d2,3a333b66,56977023,2e7ca03a,5fe1475a,d82bb93d,a1aa6489,997a65a2,306fbe38,9ef70003,2d69ff0c,8d483ca2,c321fde0,5e7bb1eb,8414015b,c1ec8527), -S(546aaf63,1b68768a,cb4240cd,917afaab,60aab408,17e7d5e4,74525ebb,2638eecd,ab3e9be0,841c2b05,5b85516d,a7d89a82,9264d773,c3d6f92e,4a01a7dc,e157d02b), -S(312287b0,260355aa,7b5ca09c,aa8773b8,27c1d703,eaefe0e0,99097e6,4f6cabf2,eb73ca95,f36a0d11,45ea347f,dac667f6,c32e7ddb,aa2ea5ce,e5f5443b,9de2b90), -S(95453155,af512fa0,8c745c6,d125b76a,d0c76c3c,fa21e64,ee9109b9,bda25b04,958266b7,5200f00c,bbe904ba,80294860,bdf8ab4b,43ea7df1,72badd31,55fa414a), -S(c0846d82,c4e06acf,9208af16,3c854637,242a7751,bcbd2f7c,f0c48cf8,b690bddd,3701a7e6,7161f8a8,8a3c8af6,337a7c63,864c1b08,6cc96321,a1748cf3,f51026c4), -S(d2f24301,44d98d6c,a873294b,26a0f0b,e1fa3e20,96e98fd2,c2fc59fa,3744a432,c8bec973,52fd66be,ddc74ddd,83117873,3ebdbf65,1115fd23,58344938,4f56b194), -S(1fd84c4e,abd5a38,847dc661,158677ba,1c53ca44,4a45fde2,b9f333e9,c5345dfa,59402870,3c5aff7,a508eea7,a419cc32,d2c72742,4e3f71aa,b54ebb37,c4c18afa), -S(441c5505,ccac21ea,630d129d,538cb631,6a315281,d7b5165f,c8e837df,6de93828,9c035747,37779fca,92991de4,e4d771dd,a683c2d,97d15c3b,941fbcb3,7936670b), -S(f48aff13,ccb0f2b9,29e760bd,fee45815,bc1b5962,93bdd09d,ca16feb9,e83553fa,a543a386,5a9762ad,90c4c270,743db1af,6a5764a0,ab75415f,3c8be28c,8d90890d), -S(2758e9f4,7bc46ffa,19a0d74a,1a9faafe,effb2c71,5f271d52,6071c340,78228f69,1acdef34,44060612,367591d8,38256b45,1cb883a6,d749d80d,12edef00,ade9290a), -S(af1d3280,417af143,129fd94,cb216f9b,d73beac7,c09a9d31,e7db9023,f568c3e8,27fac1d7,6f33eb8d,7766cacf,ff91936f,2c540a0a,a0e60c9,a6942fa4,2329ea66), -S(299f64ab,28071d25,4614d985,380918d6,944174db,1c9d815b,bd334e80,b961aa0f,80ac4e19,47b1d355,ab9a85e3,e8c009bb,f6ee09a,9f99c599,4a81369,607ed3c8), -S(b45cbdcf,14222123,d45d9f19,bc92236c,6ed90909,91081804,e0bf57a5,e0c724eb,1330030a,d6b49e4,5106118,1c9ae21d,606591c0,e326c5e6,ce09ef4a,37f1d15e), -S(be8f11b1,c27d3ccc,40224467,c26ec9d9,f7c60038,deb6b296,2d3ee415,11292062,1db86cf8,130bdeea,debf75e1,8bdf0d7,83357050,b7c4079d,1eacecdb,19b7c34e), -S(9274a7c5,af18755a,ecf84a48,9a0c81f2,9debcc09,9e875e76,fa3572fe,9dafe482,539bd087,e98d5d23,49ba9422,a99f4f3d,4241441a,59347c9f,57526ba2,358bdc98), -S(8455cf49,a3e4806a,46747459,ea510a3c,5ddcd79e,1c062750,6478e38f,1577f3d,dd941fca,cb4c717e,3523a7d5,6206cbd4,3e4e2993,36f7698e,605b97b,4d927b5), -S(8a4ae542,f82437db,801fc18f,ee57f9c6,d355d55d,29cbfef3,a498845d,5acca7b2,fce5096b,712cf054,bea762b3,521ac601,946d193a,cb229791,9409145f,753b84f9), -S(1de9a879,fa9677,69fc9f3e,d0ac8bff,327d284,97278947,7672a972,bdb192f1,ae095175,6c8dd516,b1bf6734,ff4f6b11,4dc0b94,3d01659b,4525347c,3be62b30), -S(764826a8,88303d4a,45db3a44,7fe13a8a,555f0973,da32ab3f,79c0b504,81ca23fe,14b29537,dc0e8a79,d2a64d1f,d8eb96a3,9d624216,deb614e5,2102b7d3,45dd9f1), -S(19470720,24d9f677,652300a,da20e5ff,39814a7d,daa7a363,ad3100da,7ca8cd3e,c7d36a40,62edfcbd,243b7c02,f0313494,4db0d7d5,6097018,23e17244,3a49b4f2), -S(346e886,d5a228ae,5b894ba1,fd25465d,47baa88d,f2c48000,9db7562f,e75f5e26,f2b61353,c4b6aff7,52318707,99e0e262,8c7d1da0,6b510f7c,bb995ba6,e1048f), -S(4aab5528,f4423b9,9485dacc,66de7f6e,94c34b6d,623e9ed8,538b2d4b,97f74fcf,a9ffb993,3a816aef,69fcd7d5,78930e65,d05afb67,55370005,4913d30d,3f2f5759), -S(3265157a,52941c75,a280bfd8,780e1ac3,62f1f5d8,20e62ca7,ed7d8b86,1440642,1dcf93c,525ec12b,97d1a700,f09f37f7,2d57a4a2,adc359ea,b1a514ac,a8862e9e), -S(74970421,4aa5ba55,2d0ea93a,b57d7788,5bbfa9db,2c074169,345a6c08,5053029d,88ce8b1d,77f1ee5a,63967f86,a8b77cd5,c5785f18,73566125,7c99358c,9f78ba1f), -S(6060ee1c,bdd369bc,a0e75dcf,36bedb15,a6c168c6,a65e4d9f,f065bf7e,c4afa889,eedda38,3a9aab25,689ce477,75273558,f2757adc,4a4d78a9,b693a1a9,f57a6e90), -S(6c5ad52a,ccd3dd47,427ed711,538e5517,7aef476c,e9a3856e,c5ea6b23,60b5cb41,70e69676,421bcd4a,e23f252,a4d2201d,ab77846d,9fa00303,60f39880,6a252b8b), -S(59b3bdd4,e63f22e9,7bb57319,c5dcef38,573c40d0,4dda14f0,cf799479,abfd0d70,be998425,f4f56645,2eccbb83,e4ffa58b,1144d70e,f9a28249,5bdee74a,6904c15), -S(d2d11068,deff8644,b07d75e5,6eb440c8,1da830cd,427d4b2f,558150e,83fdf333,41f882d5,5b07cfd8,9212f717,77b3a846,ca57ea11,c40d480,16db8e11,f3faac3), -S(3a87cca1,e244a5d1,b237d776,a170f5b5,5efbf254,dc1a67cf,f9578af4,6f9d784,47b25110,42be177f,bdc07222,9bae8b89,8e6b2638,6fdf236f,93148d78,31f71fba), -S(82f63ea4,34aa60b6,fb16196a,c2979486,12a12e50,c5ecda17,8e0f6317,d858d026,22a4e99d,e5d95329,bd8662b7,82c32ae8,eb0b494d,6dc1d395,daa7fb23,97c5caa2), -S(bbdaac46,6d3bd845,fe67a5fa,3ee5ed3f,cd2e762b,e35220b,e9fda52a,51795bbc,eaeb68f0,4ffce7d9,257236f7,f266bd5a,a85833d9,f4a06eeb,766bd426,b403b515), -S(d3c4d162,862026ab,9263571f,4df35e1,c0789887,99bffad0,2b677a63,4d20a367,cc6b3c0c,c1cfaa4c,ebaba6b5,57b914a3,f23618aa,f7282448,2f3d6ff9,966bc6ef), -S(558d059c,52a0b251,462be6a3,d8e0020,f5c0d6e6,44407dfd,62828a29,8eac4f3b,bf82d395,2e5a6d58,6108ee1a,f7bfdbcd,b4450f4b,30c72aeb,6109ed01,7c338a7b), -S(880bf94f,48db9565,cca7e8d7,b646ab31,e9be0736,727c4266,ec68ae38,c0a04196,8cc3decc,aa0fbd8,36aa86b5,ca245e74,8e22e8f3,1b34fa8a,5a1de2e3,32d10218), -S(5bcf6861,946ca2f6,258abc7a,9db72de4,20170290,ca0c6765,9bf93286,5d806dd0,ffdf39b7,1a08f3a4,1be73acb,d9ee2924,af21c53,22b9ff48,94408928,3cf22d59), -S(53f70440,f6c09489,edaf304e,c064466b,2bd9ed5b,e9affe95,a8cb22db,d842abd6,a7e74cf4,55af4dff,3b3bef74,902daa5f,da664d20,be94863c,63cad3be,30b13ab3), -S(d6c95017,439fcd33,9d122e80,a36ce813,f8eb4312,2db80ae6,e4b09c5f,277237ea,b9ce6112,53a6a066,7fd411cc,a1584cf,b1f05348,240b9b5d,f73aa3f2,637073c), -S(7d78776a,46072c1a,15c23544,f013d058,a3485a49,83a1593e,aa8c2c25,351c0bf1,7caf8c7f,c802918d,602be0d8,48eea77c,58c9d65,15a7f9c4,8df5e3d7,ebc941ec), -S(30586c43,54218314,3881348b,e81076f1,e8d3b527,8bbfae38,229ab1a6,6b9a49c9,d3e968c0,f94cf4e8,85b22bac,45cff2d2,e2fab151,36b2a2b3,fc2949c,1f9698f8), -S(93b3fc28,34ea8639,8a15fa40,2ff48069,3bbd0710,c560915f,e66b798,2e402625,e9382fb8,5dc35590,27b78b8d,13730cff,c2b4dcda,64d27dfa,105fd5dd,b307436c), -S(27375095,c1ae101c,11f6fe18,cb926f38,175d90a6,9e394884,4fe5331d,e466ec87,6aa32240,9ad70cf6,1b8ce6ac,6c518959,accef648,37839a07,8d18aac5,51ada043), -S(b4ec8bdf,f517180b,5c87fd51,e5ecea5e,5ea6d107,525fab0b,6b80a0a8,d462345b,76950c00,5a2a7e57,888082fa,631ba270,af02a5c7,73e57869,f3295ff,74b18bf2), -S(efbb3723,c386d2d2,bf0806e6,c42bf0d2,4bf94b7,b10d0dbd,d4ebbe06,d0a22d21,af0d1096,4781bae7,c7438228,b2525fed,962bedb0,b741cacd,9a7027ab,6a3b29a7), -S(2b6ebf5b,24e78685,65aaf770,ba36142,51bbfb72,f49af29f,c55dff7d,a55674c2,396a0cd1,886fcda3,172fca09,807c929e,afe8b5b6,38d63b05,6baffaa0,743ed723), -S(8229420,323c9f9b,d88bdf0a,ac9035,fd33c3f4,b1411cf9,28a248e9,bd71f95b,e8566565,2dfa438e,289d021,4a1531a5,632b1369,24c01cca,6897842c,1dea3995)}, -{S(534e9d8,bea140bb,4970b516,c42f2677,dc413f42,9b7c56de,e261f60d,ec68f9d8,e55aff90,1098b0a9,ea377acd,b62dc479,da109514,2654107a,28c68e9f,73b1cba), -S(c3d305e3,8e23eef1,707ff287,74f82631,ffcf3814,ceac1e41,52d932a1,67c24c51,10234701,f8a8bc0e,66bd6d38,d3924b0e,b57bc295,2d2c190,e6ccb935,2baf8778), -S(1f3f8c12,8d216272,ccbe44e9,43e82acb,d91ad650,72bd8ecf,adcfb1c4,38c44272,e5c4b103,a42d6238,39886157,43bcf8ac,ae397188,1abd5299,d8152ee5,674bb58f), -S(84f33b31,be4a83e8,6ead05ce,df1c9eca,57c60eaa,fa917c7f,56f75572,902d360f,854aadec,13bb6307,70855f06,a77ded40,5be99eaa,93a06b08,dc0fd7f7,525613b3), -S(9b4e0dc6,aed24421,2160f3d2,a0ad4ea2,8c9193e1,e442f632,a956b03,7f9b4db5,4d3d4970,9c0a7244,5e0b9537,2510902e,6fcf18d3,be72cb9d,c3c8a252,cbb593b9), -S(5eeed41,8a5e9d4,fc0be136,b5799c78,bf819dc7,32280d6a,43f10f39,e17cf8da,7615a870,c5cfeb70,1ab28456,a912dd6c,c2b87fe9,8aedc101,bf3beff1,89edd2e8), -S(413932e7,c2e1fe6c,dc1e8330,3c60e361,dcaa1fbf,88e3f329,96a77df,f39b594b,6891ea57,c7572d9a,b134ec3b,bbb65547,3e6932db,1d34a142,26b806f0,afc2cacf), -S(f73a8ee3,b7345479,19a49698,af05acec,1771cfa4,91d3bdcb,81cd997c,b63ce64a,37047e7b,e5742560,9e1640c6,5e89b560,138a00c8,e11700af,3061c185,4bf8a2f1), -S(5edb35c6,c68b4956,2cb6a0cb,3e75990b,7106668a,fbb71f37,2b167e49,5f535b9c,deedc3a8,56a5ee53,60e34c44,e7169af5,7a86438,b982c966,48e37b64,683bfc0f), -S(71eb89c3,8f391043,3c7c1b8f,a3689201,ea234d5d,b82a78ad,2deaff4f,c2bcf53b,350f58f8,1a2a8a76,4c70b16b,6d6f5040,882ec073,1fc9e3e3,f09c2daa,f113d5d), -S(ba4b99b9,71d6e91b,32227a44,be3712f7,93908f54,9ea958db,c1a425be,ed53cb5e,4b985486,76b813f5,df3c84b4,ef8f3279,94c65e14,525357e2,5f82a782,f2e1a041), -S(1975444e,ccabe01b,dabf3542,f3bd4651,94515698,c2b03f16,fb56559a,8d5c66f9,88287b5e,140a9558,2e65ea24,613cd20a,e2811e72,3fb8b12c,dc7c5fda,c5e0f50b), -S(e1ef5109,f37af125,d6f01cde,7b90dd77,cda704d5,121e436d,8ee8bf15,e2e4d4c3,458d2e4d,c8cd77fc,10b26fa4,c19f202b,d66fa6c8,e2fd2e4d,56299e7b,5fc9063f), -S(983839a2,7b582450,5aba0977,80dcdc26,cab2250d,d895a876,b17a4a82,3faedf63,e236159b,9c330576,cfb674de,a1bec238,3018b697,b8e41cb6,1992c5d1,bf49c588), -S(3f4997c6,b1efec78,fc198097,af19e301,16efe029,3cf4ac86,dda22ff2,78394c8f,e92d795f,d14cd101,eb15c75a,41c854ba,267d0557,47c81536,e887f97d,b67e3be8), -S(1095049a,b90e7946,c24bc411,892f911c,6b72d0fc,12af1186,ec43dc7,bec41a6b,85cfc876,55842640,8f24e382,a4e91ee4,7411a3d3,f4a257a2,6419b495,68363dbe), -S(567729a7,12f183b,e7ea601,68aaaead,594a778a,e9b936d8,a397a78d,f53ff5a1,cee7716c,68bb61b4,586d03e4,95f7bf0e,7c215870,e9f1dc0b,1f08111f,d855ee4), -S(ccfcb55,f8da139e,ba60480,ca57d942,5fe16cc0,902ba610,fe8fd2cc,cbcdc016,4e4d8abf,8517b55b,8f6c0dad,3adc94e6,8d995917,de33d623,432cdfd8,188ba22a), -S(869ad71d,22fb7aa7,7b5b65e2,c7b85a45,34185b07,a70a7a5f,fdc963e9,6de4c2ed,3bf234ab,30c8244f,d7a6671f,cff79848,ac53e1ff,fe104aa3,387824c1,f6a3659b), -S(5288d151,6d72c379,e14361e9,41835760,73e67c92,6919ad4b,a69e29c6,43d416e0,2f010e43,ecffa3ae,3d8200b7,e6f35ea5,31cd3db5,c5079b33,1ec1611d,1881f8e1), -S(b771768e,9e7bdb3d,76ae8a00,c4258be1,db77c45f,92318dac,777e9ff1,7ad71320,b068224,7f3fbb45,8e7deef6,7b52710a,5c6c38c7,5a94c154,9e503d81,72da0fe8), -S(7444e64,88164e8e,575729e7,88dc3197,b32d04d7,403f9565,611ed212,a708b98d,ea2a9cd7,49c5a3f9,f2d509e9,5a69745,a5ff933e,1c87c141,ac5112c8,b70a4667), -S(6e995fdd,ba6e0954,cbf84ac1,1d0990c7,ec5fa3ea,6b6f070b,2a68844e,ecea4ca0,743017fc,340132db,cb1d73ef,d1bf5bb7,95b8a0ab,8b898af0,3b2f36c0,b5b7d921), -S(b60c9741,38e10b6,e879b4ac,8de83494,7e345e8,cb5a4320,9a5bf1cf,286f0f85,469d652a,c9cf7d15,268daacd,4630da47,d74ae560,6ecc49c6,9ce00afa,df51d990), -S(70f4f8a5,42de7bc8,48555b84,6c058d1,eed230b8,6864a079,fb91f662,ed27f6c6,21323c29,bd6321cd,e946dfdf,d705894a,5025e2aa,abe9a0db,5efd1223,db2b2457), -S(b23f838b,3aea4309,7b1fdfcd,bad0a3e6,225ad4fb,a01ad0c8,49985f90,8a7120f1,7569db8f,46491a9d,b6566f95,92e126e3,6fa681b7,d0653b53,c45e2cd4,57c3bc4b), -S(9e447e8c,5d040a11,4964ac92,d91eadd4,80597e42,5181be50,5027019,df6ab481,c58a3c86,7fa55ad9,46e0f3f2,729a389,b8da3706,81c895be,5697090b,310e8834), -S(6f98b221,30ae2b8b,4f5852e7,d7e6ef2,1241ff92,ffb63148,4c8265b7,6d863f2a,c4f8bec3,3f9b7f66,a9827e8c,216489c1,c93506d4,42938861,4658e7bf,239a6419), -S(ecfcb0e8,f66c9de8,4d4f93af,e890e083,1b785a19,7b7994f8,c6d5ff4,63532df3,4d1d6d29,429e7c92,4f91a6a3,43b8e805,748b420c,b5536186,9c709033,87696ced), -S(baf48656,8401761d,2994b7bd,44d886ca,9a1dcf85,14f1796c,5b39326d,8f9d5690,ad60d65b,28f193f1,5a120a7b,9bc692f0,100e6189,d26703ee,1a941cf8,bbfe0e2f), -S(574e43be,ee264130,8e0e8d5b,dbf3f28b,3027c865,e13184d2,d2e1256f,4c56a401,e664d4d4,ecbae2fc,45cb7963,e9722bb0,8e72ce14,82f97e69,3388090e,602bc9c5), -S(b289585c,25bf9b38,9d89b7f,5b98dc76,a8e7ca73,f753aa26,f5d6ee10,27e3c41d,7cd41d56,6a17bf53,444f8ff2,3ef7d117,4459b1d8,1bfb1534,cbe7828c,e717ec68), -S(61ad4ac1,7baf7294,a482354a,1aefeba5,882b1353,b898bbe3,815103ed,14eb0411,d09a31a0,2defec0c,fa80ec5a,d4412b4a,fee6ae94,559db5ad,1bd7a349,142b352), -S(adc1d894,31f83ab7,a6ee5ac9,49b0b3b,62a28c80,c5737387,47136161,494e967,bbc7affa,2fe3a76,96cf69b8,e0c95b38,5f836d89,638ea2e5,8347db7b,dc316d4d), -S(345384f4,491801d7,11dfaae9,f7fcc4c2,adcae518,a993d0b3,f43b0e47,5d440b5b,bdd2e3ca,a0826774,e5e40693,c531cd7b,49514b2b,fec5b39c,9d995106,dfbfb5b), -S(e2fff030,ca48a7cb,6d587044,fdd94a9,d81f5605,57750b77,7435ef6f,f4af95e5,847990ab,1fa110a9,ff895c51,20d9a300,c805b343,3b1fd578,a62815be,77cad922), -S(b0342b00,a1bb6391,7154ea18,f3ab0649,45051137,1004c15,2a6eed35,adea23b2,1cbc4c91,888f52d,efbb6551,bbac455,ade7d78f,9e507516,ce0fc70e,d67e2515), -S(948901c3,3f670c89,e4393400,14bf7e4c,e59955c1,959929b4,ee74b3e3,112ad9a3,2a39d44c,93906444,48294f82,bbea8bc,b431d2a3,48435b88,5eeab283,ce9c49ff), -S(a7f64583,3fd0a62,367d4675,b94a5a49,f9fdf94d,c6597ea8,164a00ca,7a3d5315,b4fd7015,75ab42e3,9d51622b,c5639f5,9b67fc4c,a4f2f62a,7b6bc3b8,fc037d3c), -S(50147d69,fa4c421,25b1b7d6,74cca767,11db050b,fd2efb0f,d2f05036,796f446b,5445ac4e,674244d3,532f046e,127692f0,71057a33,b7b40f73,b897e8fa,213e2ce), -S(ff1db721,3b669b14,1f92a729,de0952a,86da626,97fb91a4,908441bb,117cfd00,62e7eb6a,3060afae,2084883a,662f780,ba42efda,13c1509b,13123789,364aab01), -S(29ca39b0,ca50e1d9,c718e00c,7176c506,c2eae92a,157cb0c7,1fc50790,7278b727,61bb5ca6,85823de7,fba69cc,1cf9a21e,eadffbeb,15267ada,a8def3c9,a54de3a7), -S(62cd6a0e,a50250da,650615fb,de2e19a0,6d0b74d7,316d7445,79f2be9d,f4023545,bd75298b,c2a3ce99,7e7eaf8,fedd90e9,9dcff8fa,e345ec42,c85e5ecf,61ee1654), -S(4aa8cbe6,57418299,e63f85c2,38d077b3,a1162f88,7d9430c6,1ec2fea7,ada0a758,6e360a94,7b07c27,9fd97867,e2ddd59e,3e77308b,169383e1,a7174188,fe507bf2), -S(6640eff0,e4a7b619,1f66b3c0,ae5e0b7d,92e2955e,23ee7beb,8ebf2e39,65ae591f,b4634bcc,7ef0e6f8,5dfc3694,27a0fa2b,a0e9c0e9,caa03a4c,fd90b50f,72feacb2), -S(d899ae0f,b22f7740,73013f98,9386e5ba,da6077e9,dc49feb5,ecb195a,bc6969c7,2dcb982b,e71ec202,472b4c77,d725c59c,ef6a5725,606d8226,30482554,16eb8287), -S(c9691967,9032dc88,a4580ca,b338fa3d,812ddfd6,7067917b,a2a1289b,5330c6a6,47a8d9ad,608a3bb5,9eabd2f1,8ec9bf89,4c3cabb5,97ff03f0,93a89d8c,a6b4fc82), -S(a4d25f7,3af5311f,26435b3a,31455ec,ee7a3b6,d6c7e850,14875a23,a7ad35c9,bfb5b89,af0362f7,f7f20fd8,a442c285,6f4d330d,247dc6a0,f8434a6,6c5a6d79), -S(edec5d54,3804127b,a814f23,3aa3be2e,e5e46a6b,ec12d2b6,9ed7648f,c30ac1cb,d6009320,5fbdae39,38d1f797,a5184457,7b645345,c36f1d80,705e3c82,f97bfd78), -S(257170ba,c36336aa,2591c583,48455370,9192432,10eca66a,79001a4c,8f340577,13a0acff,184799ef,a7211d79,41340b6c,ad8732a3,d57745cb,383bdf42,ff8e39ed), -S(f5ae8c79,b6a65f05,dc014993,7f60b25a,6def44ac,30275e9a,d787ba73,fc5305e,5634e58f,b5603ba8,bdcabe67,7f757371,c377c1b1,3f67366f,c36027e0,d953d2c2), -S(86c0376,2172c6d9,f53a9370,ca9d1ce1,79a2bb2e,c48211ce,d06732ac,80c9402f,964b4829,a76d7654,91e6a165,504b2302,5efaab99,b4cfc14c,2e84a801,fd220d6), -S(3d481453,e00c8714,4c6048ae,e5e44267,1a601b5e,fa6430fb,54203ae4,c6fd070e,69bda5df,ce150a83,d861f309,349b3397,32620170,d2d9c259,5507c7dd,591f0dc5), -S(8a8ef7e1,733c3e75,c3b39fd,7cac0656,6af1bd74,a240fcb3,b52979c8,2a56e2d6,846956b2,da6760b1,852cc3e4,d0eb39a1,7fd79c78,73dc1c65,9afb53b7,b25db246), -S(ec2eb41,21923a7b,4449d61d,9e9a996a,75469c05,e86a4911,16c15206,97d741e5,488c3501,9fccb8c8,33b09546,9c27eae8,66a133ab,991a24bf,c00691b3,9e1d5be1), -S(a8c08ac3,b959476d,8e58e8da,72323b81,33f55721,318c664c,ff5eb491,7aa19562,83bf5e5f,d76c877a,f10cb1d0,8b92d9e0,3a8f7db0,2c571449,ce3f5ea7,adb3d9c8), -S(eef63253,739af912,b7cacbdb,3e190add,f2931c2d,e0997fbc,5ce02cbc,56a53e75,14c4d6d4,5143b60a,f0a75249,42582d70,fdc17027,e13a2460,84523417,9a5cddf8), -S(65dc0be9,e7028f3a,c15e5e2b,1d27d339,d12a3a40,eee78b5e,4942975c,f65a781f,d635b3a7,97b5ac7b,c072fe35,9a7ffdb8,b1aecb13,fe933b3d,cb627b47,abb2e652), -S(e0cd5d6f,81a70576,2c65193c,c0a2eda2,aa5ba2b9,c9fbca52,5148a4c8,2f2c746a,5ced8640,19c48e1b,8f1f97da,ea66cb96,fc71ef84,36b87a53,e2b5a841,1d474cd0), -S(66d2d27f,eca16c6c,f8a68712,85f4dc01,92fd503e,6fd39cbe,89007d76,20a966d4,56551c4,ba79a293,fbad2b84,4dd1f5a7,a6c8a688,656a79d6,764b9b0f,df4f45b), -S(36d496cb,2749b975,9f4474c6,a4dc0283,e19a2e29,1c488623,210ba1db,1154ebe,a46cd868,c01b05f3,3508961c,61f0a83c,3ea06996,829aef29,37a93c7e,8840514c), -S(4f53c3f2,5a858506,e11681f0,dbfffded,b6bfbc8c,63ed6d09,3028a55c,c19683a5,2a31675e,7e0f8382,625bec94,83bae5cd,76602e36,1dac153,45209b10,78fdcffe), -S(9c6719c4,2f375d6a,c2891fab,c71bfa16,a40ef26d,b0ce93e1,46634221,da12d8a1,38c92598,10c67724,14f83d45,db2a5506,a993e277,f20a8430,97ba286,b2be9afc), -S(115eae71,89f32e1c,28f86c62,abb7cc2c,5fcfb927,6b3d7655,8f7f1a47,8c9ce0b8,229377d0,9b80dd76,4fab10f9,7cb8c1ad,5f0c89b4,47ac663c,780fdf6a,71a0acf7), -S(4f06c1f,ca76fc9b,d58fdd6f,12d0c64c,df9ef87f,fa579b3c,fe7f8819,aa68595b,12292991,95f91eb,18105a0d,b576fd33,1eba5e9b,f6944557,e9a54d9c,c7ac9437), -S(1f18b838,ecfb11b9,34a37132,6d765ad8,b4a1f11a,6ad51d67,3e7d5bc6,8823e742,fe6d5003,e851cbbb,1d575d39,d48ba2d2,de8858c5,95e2e73b,26127e61,fea194cc), -S(905708d9,b066738a,252116d3,451b2330,5ad84a12,92199acf,1bc0eb86,b7209109,7b3cb65f,6f34a189,584ce179,4112007c,71b2d6f7,9667880d,684768e0,9d706d0f), -S(bccf7efa,808ee0b0,f19080f3,cb4c0fa1,2dc46c87,2a7ee71a,1c1a171e,b9f03962,66b9d38a,5582ad7e,8ed7b0c5,2d4e5aa4,a14fe624,a51d02cf,7553f7be,fd2f9ffa), -S(fb6505d7,2fa3e83c,26d7cc0e,e8e8e160,1c46ff4f,299b06ba,7b5250f2,a20a4ca3,75935eb7,e923dffc,c3b0bf80,4861a3e0,a721266a,1395f424,16f26d27,9a582ca5), -S(208d0bb2,1fee812c,e93934a6,c5571d1a,a8d8b6eb,3ad58357,90661718,86a4c103,7ab4af2a,e062e5c3,9f83467e,31d95f4a,c1e0d0aa,d77e2128,a8916233,97379bce), -S(8ff01550,87e8359c,f5081e09,71b5b80a,e482507a,217114a5,8115577d,ffbbd5a8,47c83838,5bee81ae,6738ccce,e1149821,e433b9e0,e11cc919,3bd180d1,97a07519), -S(dd938972,59966349,9edba2e0,1932c7c7,883c99b1,11f3dd2b,f6b079,770f7cd0,c485988b,373de68c,9a07d8d2,3d8380d9,ce28f9dc,9dcd3abb,99705aec,c87f0ea2), -S(247f0d44,50e75f8a,724bc9b0,821e7e62,cfcc6983,860b1997,c73b7b90,515cbb1f,6b861e4f,2f5e0cf,38d91847,f5d159b2,25b43236,2e67771f,da2dcb2c,d79644e2), -S(2deabce2,d1d31515,86894e19,1a5af1c2,7fde9b45,455910d9,598adc57,e46c8823,77016b04,643d44f8,6f279dfa,1a86f3ba,428493e4,89b16462,62e018ff,d70efd8e), -S(97bcfcd8,dfd8f0c8,e7c09773,746ca7c9,de813c3f,14f6e39e,4e597559,adfd7ad0,5f948bc1,84d2ed00,ca4d3be6,6972c568,916e7120,cedb84b8,29f35cd5,dba65e35), -S(d2a6e659,e88b061a,e26bb48f,10e4f1ea,30da5df7,2e9cbe4f,451fb413,c0eb9c00,d6c0e56f,cb2d383c,dc77b93,2c41566e,acd21f2a,93537f4b,683d2f72,547d9779), -S(8a3069f0,b374dda7,b7c1e34f,80ade1b1,b439e517,595a5c88,8e3ab8b2,b2541e36,b13ecf0d,729b7cbf,aeb2ea9,6a80e6ae,32f9d46f,57ce4114,4c24f61c,b0c7183a), -S(6160e9a8,a3c82af9,bfe8468b,5142d7a7,32d00cf8,2ced3a6b,333c188e,ee6c0df9,9c174f47,42f0d46d,aa03966a,e00595af,355c39d6,a7b17ab,637580a4,ab9802be), -S(ff32347c,eb8aed18,ea6c314e,15ba2437,702b9d8e,a775f6f,a1b84b27,83837b2,d09e3f86,e37d1190,9f6ea512,44f9225a,6b8570a0,c90b8511,7a1eab62,f3220a37), -S(170d2456,58ccd0fb,d8c01df2,a84132d8,3eb94d08,d8fb7b53,a929fd4f,38ad26cb,a83ab99b,176dcb0a,e80c5f50,5a454f15,12622c22,e6f7309c,7a827a59,944c4e8a), -S(8acc0889,91014a93,e3649980,b6eb6172,44f56e10,8094b6ae,a7f16e19,1e566e9a,ecfb977e,a900e0a1,f6b8247d,703ebeb1,4524d5d6,95f6e46b,85ec9e52,a5795a85), -S(f80b78d9,22cd9e20,83569df3,ddf58b41,dadcc3d,2a3edb2c,e31cf234,5a31cbf3,fd1ad87b,98a42acf,273a268b,c4f7493a,cc28cb9f,9794c833,153a0947,eaab549b), -S(41b21d40,5602d26c,78028eb1,acb7160,9e53fb02,7215c405,edd90586,1fbc1a8e,55480fb1,3d718aa2,59f4cf19,b7eb7638,2d07c372,c9202c87,b7037993,90f309b8), -S(3d49ee22,22bc61a0,9cabfe95,bd981686,73c2b42b,5d22698,21ec7cd9,6a488ce,2d461269,bfc6dae,48280ed,ae07ca1d,cb8d3e8,a1c9404a,971e416b,d2a5cd2d), -S(7f9812f5,30f80bab,f35a5df3,ac0c4d68,7227fa14,74ff6057,1f8faee4,32cb8c74,805fec79,b3607318,574a9308,831c4db,1fb1cde0,c0094b6f,6e19b924,35e0f118), -S(d5a33585,6c8da16a,6ebe776f,3cd08d7,e32fa2f5,c484a299,6abb9e84,60d0cd6d,fb1e3d96,f95a139a,2c968563,73813e8a,7cfe6ca2,bb97ed22,1e374337,9637668a), -S(a138a71d,854f2f76,5f8d681e,84e91b52,9940c342,8f69184c,d469edd6,43d2ce2d,ddecbce3,a48b0457,66ef7511,b041f6af,f2df22e5,51aa033a,8325faec,bd9ef061), -S(d9a0f20a,ebb51238,14e55212,4b6d723c,1f972951,446d736f,b4d20e5e,a9dc2304,fb63e167,90c817fa,40185611,ea346e18,a12fd1da,fe3266ba,c8c8dc1f,2312797), -S(31b4f50a,d3476189,62a34537,10a1a995,e9e25283,af87725d,e2767e08,4f276324,98b32741,c8e1aa6f,70655814,ba0f34df,7f2ac7d9,40604bb3,4216d8b6,9e03d07a), -S(23105202,c01e6e2,6fc5da32,5d65644c,e067817a,6b54779f,fb9f1faf,57b15a5d,2da13e2b,63b8c792,56a7b49,c44e0014,9f461967,7f2b4709,d158aa38,189f08), -S(2e9bcbd2,8fa1b69f,76193011,9ecd8f38,c88d2c7e,f051780f,cb82d587,8e5fab55,93ac2ec4,33abd509,fa71237e,9ab6a421,4d453bb,9fed86c,2bf9b727,a84de903), -S(7a560f5e,d2952cf3,342a1273,5c627eba,49eaa668,f3ea67d1,9a0bcc92,9b172ed,32d1b9e9,5e1df2de,4155bca0,bc404615,957b16b3,45568590,74a119ec,a24eb984), -S(10d8b5b9,f230099,9b15ed43,17282c23,dba62c42,6725e112,6cdaa3ba,f07564f2,3e5d4465,4ff6faf7,3d3c5a64,bf27251b,de0320c8,b8f5e7c3,f2933225,4f0832d7), -S(924850a5,d61c8491,6ae458ca,491d87ac,ca095e0c,3a37e5d,528785e9,10730e8a,6f115681,341d7598,552d8eb6,7171ddda,40594be8,5da3b9d7,7918d2d8,3316c738), -S(f36a988d,2be42bf9,d39a2b40,c2447f81,6dc2a91d,20edb89e,c8b00c97,c972d837,56ccee9d,619f4b0d,2fc0ec9,ed60ef01,1f10b55,2569dcf4,dd922917,d8912764), -S(7a9b644c,a0b45902,39849b1c,b03687be,75be77e9,b50685b6,1c9d7052,5933ab2e,ac13dd6f,d4f8cfc5,27990d16,cdc88720,4a5a14a7,f15287e2,7b5b4c9b,3ecca461), -S(e9de9ec1,40076c59,afa8264c,e4ee7209,5b88b08e,dcfc120c,9a3e9003,72542abc,284d6201,15f1f94e,54bf097f,b9407695,c62e76f0,f2138bdf,932da8cb,86a13865), -S(aa9ac192,d202973a,2074a2f3,7414ec0b,6ebecbcd,f201a6fc,e43d74e7,8544bac6,95fb5730,f524225e,a7af1ec,8e34a6b,b7300dc3,7df97888,fd0bdfd7,4986e2e5), -S(31b66efb,b2da072b,16d9b35d,5175dd6e,96b8c227,abc0f2a5,94e02f9,e693a20c,e3c18398,aaf7bc6,776f306e,23b1f001,17fdf03a,72474f2f,ed3b0d6b,70cb5baf), -S(7eda3d4e,2257ae72,abe80be1,8edf5496,3a8bea8a,a2be745e,8402734e,97d19d4,ce5e61af,de4301bd,974ea8ed,8239a368,bb8f0b57,1a6bd9fa,c3327594,c4abfad2), -S(297bab00,4b5e8c60,b27fc169,257f1217,48af6f99,65caf54f,67ce172a,e69e2b4f,eee4fd66,57a4aa8e,5eafb1a,e95e466e,976cedfa,b32f8f4d,31a820e0,cc470eef), -S(389f8ab1,2be46a3f,e5d2fd38,9598890d,cbb8d1bf,fd36dc10,8cdf8532,91e477a6,530394ba,2647c712,aecbe545,dec368b,21eaed67,a9d694e2,abfe1e83,1a2ee1ae), -S(36122688,726cf2a1,b2ac26a9,375608c7,2024a751,6543ce67,2393159a,98fdccaf,661b4134,4ed2bc7,c3596a83,b812fdbc,ca95cb74,f7b322a6,ca1b8167,aaf34666), -S(ef5f9544,a9c4148f,6a637ff4,39bff5d0,9bba2824,1d115c37,a5918070,d02f9a8,2111a85b,369cfc85,6db8941d,8af8a357,869712d3,76ac94db,55f3e0e3,e5e8770b), -S(d2c7599,c6bd388d,def00aed,b0cf74b2,b41646ff,5bb690ee,2f72ef10,1f55212b,ad863280,67ab378,1fe9c59a,bc54b06c,9420059c,6fcea9f5,f0bf563d,2f87dc8f), -S(67a35c0b,fb6a1655,23740a0f,23b6a8a6,854c22a4,113a665d,1c35a2ea,c83b72bd,dd5b811b,e4454aa,c7c9adea,b7368235,f3dc2bad,a6b7a2dc,99e86f97,f9d7409b), -S(6b667d3f,158c02f7,32ebedd6,552ef5d1,443df008,2e1b724c,dbaaf43b,efbd2480,c920f76c,c082ad16,d7564ff,9952fca8,3fd4e059,5e11a711,2337cadf,f5f51cb4), -S(c8cd3584,214589f5,62690e9f,71a63e17,64b0e3c8,33f26cda,8388be55,6e336296,c5d0bcd1,7b737bd1,66a2421f,8e1dfa80,64b3ede2,5ddb4ceb,cc8f9335,6ec468cc), -S(8b2f358e,b781cdb7,b8db96ec,7d42b75d,56c494ce,7561daf,b3d0ba8,360c281f,aac9391b,cbce3257,1d01e5c0,82eaf632,65628c28,77e72671,161fc2d7,21425e61), -S(55b0917d,f039f139,bda403ad,7fe1ebd8,912c0434,379ff3a0,da5996b8,bf2b2f7,f592415b,3ec3a143,c9b681b9,cf8c8139,2ed67439,ca67a162,e083cd76,27da169e), -S(c0eeaa0,81a38627,16dc09fb,f8e154bd,6e70e14f,a92168eb,93673780,a8fa76e9,9824a6b1,fd3df6fd,94ef8e7b,b1d9351e,cd3ee62a,e70a1eb9,91b56527,7c695e23), -S(fe75017c,665e766a,13b2b632,cc29e61d,9bd5755d,b9c4f065,e764d658,7204997f,157a23bf,72c25ace,ebee10d5,aca71726,6d6c4cfd,983530b0,3d47e6b4,9027d0fd), -S(bf4458c3,ba27b2c0,cde6911b,6cb61a6f,53642c6e,367f83d8,e294e3c5,2b18e13b,8d34a93e,e7f7ff98,3196cd08,c8344cd9,eaa83481,3f606e8d,9b2f6ef8,bf91ee64), -S(7254ec2a,c6ad1be8,2fd75bca,ebdce771,f4ebca92,eadc0bbf,3c5146db,a8d3760d,6302fe68,4243ed5a,887eb664,46f709c8,e60a6db9,ed062c33,1fc556e6,6f87cd0c), -S(4eae1e2e,b75b8cc5,73688f02,bfd5af22,ca928244,6dc8af5b,9dcf1118,f37ea23a,2a98f93a,613b9b1f,b3725d62,60510ce0,e718d07c,f913fda5,3b4f8b28,ddca064f), -S(b929111b,4b6b6caf,184238e0,82fd9a3e,8b9893c6,ff80a091,8b8e2b22,da6e0d2a,5a207daa,f75abd10,142948a2,cd2e806b,23322e1b,1f52b739,a9c7ab26,2f44e91), -S(6c57b3ba,18fabea3,25dd2711,52e5d857,a2853fdd,5f73db49,cc2e1c25,c98caa91,5a3fed55,397696c2,a0e98573,a30375a3,1b59b343,35c77918,3908ba58,4bb96a76), -S(607ff89f,3c3e3635,a6b83591,546594c2,a20de4b2,e59a01f2,696a9d25,caa0b1ab,47f4a3bc,ec375b6f,2510df4,7ca3d932,524e7c9b,656beb5c,65603c9b,1dbc8a3c), -S(a5f8ae36,a163ee23,d9c2744f,1f32de1,25744a64,f0e21009,445f08a3,9dd8aabf,274fc698,60f62f3,cadab3cd,23086876,31dcc845,43c98f65,b826ba0c,5b27352), -S(bdfc9b7b,ea97cfa7,4e97a822,fb6d8dd9,cdd2784,186f01b2,40db0851,95e1a07f,b02f7e83,56b72dda,81e38cf3,d5cf071b,e3c4c595,118c1cf4,61f01b1d,fb678090), -S(386bc7b,42591be5,41547b61,f0c96e13,6b168ef1,338f0f3c,ca2e59bf,e4f902c8,aaaccc7c,37655f05,1e0bb44e,396b2512,68bb806b,1e1ae4ee,598ab2c0,7b920f17), -S(14b9ba9a,c5eed3ee,9f4365dd,56e703a,2bc35d0d,af288bd8,1b9ceb03,82444a69,53d17e83,d76141e5,81c03eb,367076fe,a831a4c3,3a756cba,e564c851,e71c9a84), -S(e8b86b8e,f0424769,d0a6abd6,f0090030,7e851f7b,11a31012,b404e4e4,c062b1ee,f829b4e,bd2a0a55,253c7fce,73b27cce,9e31acd,fd8345f0,b973143c,25ef7900), -S(ed4cf2fa,b4108d10,c07630e8,333fdeec,af062396,eee23aee,e06365dd,ae880631,8eff37c6,5480bc59,6271ef5b,41743d9f,89a4685d,d497bdc0,8f6a11a3,56d07535), -S(6ccfba61,23d3296e,acc2f6ac,ed746ea3,6c7ce287,6e758fe9,b38603f2,3a1ed8fd,86ad0ff9,ee5d758a,2c2736ce,af4b2d50,a23c60d7,d952409a,9bb0c836,34dcf7c3), -S(4f3dad6f,4f718586,f2ce5239,b7ff5f05,ca384f7,a3171edc,6b11103,55a015b2,20858d8d,ef722f1,3a6e11d0,7d0a1db6,257496c5,e1f64d4,182592e5,f57334db), -S(ebe62fea,9af5d236,30dccf98,cb1eb472,38dc964e,5a145831,fd7b65d7,6b55833a,f828d7a,d18cab39,1af532ed,33cb2ae4,3b677836,b95bc3a5,2807d5a7,7df2eb86), -S(f4608ee8,a9ff5e52,15fd6257,43e58f5,af5ee536,9bf8e5fe,9bb8d371,e40e86bc,44dbb6aa,c7bb3a3b,fdea778a,7a6ce04c,dfe22a5a,c054951,2a52ac0a,499a5962), -S(63be7855,faa99716,cd77c389,5b2eb8d6,ae5d29eb,f64916cc,f7eaec1b,6f81ae30,b1463e0a,44d15252,21670fd8,4a1ed48,24b6effe,f6820787,ebc76cac,68db082d), -S(17306e73,c5487073,30f41a4e,e94370ef,36c07686,c55ce03d,ab6cb6fa,ef1ae2b5,b3f971de,6e09f1a8,7b083dd6,44c5edd2,a67449a4,520dfd5a,6742630a,8fb258f4), -S(81dc632,ba371e74,18cb0986,8a3e11fb,738f7857,9210bc06,cd0f9e73,4c91a064,cac8a551,b5ce80dc,2e5b400a,f10e209d,9b1864a8,ebf554ec,f36056e9,3b99b69f), -S(6ec14358,b2734ab7,3059643b,c60dab0e,d8d46c41,5ca1815b,cc215408,19b71e71,3f6c7c4b,24cd34d0,aa9cec16,cc17e321,76e2c0b3,24bef53e,9b6f3dc6,a4f4d617), -S(dc7cb981,dd03dcbf,66e63e85,158aabeb,db7e2aa2,c4a04db8,e88e8628,28000afc,d187b91b,be3dc2bc,44f29d22,e2a5611,6c9ddd2e,6a946077,deff44df,6109bc4f), -S(8a49a003,8dd13eaf,7223a2d5,50503fb0,ce0f5c2f,a7a03d5d,5ce03517,803899c4,47e6b637,1876be40,dc5b64d4,4bc5fb89,966c49c6,2d4f85b7,c7867ff3,1819f8de), -S(b252b5d3,a75c18d3,79ea1959,67559d02,8b8ab87f,c4c5bcd,842e5de,8e2c406c,eec6b95,c2d5af38,84ca69d4,2134d318,646774cc,4d05f78c,7978e8f0,80072b54), -S(6c30393f,d1f285d0,37f412af,38411133,c1bd1db0,6bef205f,12fa94a,4eb35412,b8c88541,acc9c862,c0186985,cf58419d,1c24905b,1d1abbf9,2b59a381,829fced3), -S(aa8b25e6,583d6898,6ff108a9,a4be30d,5a5149c4,45387abd,e9c1cd74,f3246ccd,1c51efb9,e6225d4f,b7b67bf,1b12de21,718fc945,d18a1679,f5ff6ff9,94d158d4), -S(28b46490,768800c0,4c94fd8d,8ef8c29d,fd66fe24,f379cfeb,a0a9b9e1,53acb33c,7e348f08,308e1ddc,6ffc48f,8e8a137e,785a0aff,fff18285,bc5b7bf3,54ca8253), -S(54b0ae43,66382f3e,83a01082,7e08e596,de37fa5,8c012e90,20a24347,ca1eb5dc,facb37df,f0bc59ba,72260606,d8e94f7e,3f71f600,78f6854f,2fdafffb,cac30332), -S(f8f03b0e,b981e371,a0994d64,6ed73e5e,a36d74e,7a349861,20e25d71,7f43c6b,642c63b8,96d9e995,32dd3403,40f91e0b,35f5d990,f6cbb768,253251e0,d7965737), -S(9c1be533,26c1a43c,f0fc5e13,83627414,89b4df8f,71224d24,6bc07c1b,f22c89d7,4d420abd,af53f191,f1e6622e,bd51e638,9e2cb2b6,a7c51885,f21937e7,3de7e73a), -S(c9b65328,864d0371,86b146d8,fc208126,dac6bea8,31778af6,e944f338,3c72553a,db91182a,b8a8ca07,3e2fae97,41cd81d8,d17c8776,9f2c0492,2b76ee93,c42af5a0), -S(7d945104,a4ebd202,dbd4be75,1cd14d8a,e07700ab,804de7f5,1cf6d254,bbb9489c,77231839,b8d9e627,ef6ed20c,e88146ad,7addbc91,f1522399,da31b84e,7b21a033), -S(2b307a7b,99ad1892,cda61d2a,10c1d972,b5855905,a64309d0,6397732b,c98ab549,8c38783d,51162a87,8e84554f,9b6d106e,e3064b89,3d368341,f96faefe,9a0ceafa), -S(2e7c5d29,c0393ab9,7b93a628,8d6b1da1,d212687,5d45c961,317665f9,9db55ed0,58b9c7f5,19ba5e3b,5d988b51,d50545a8,9a74bf20,1cbf0cb3,64936a06,7c8110e1), -S(accc9c09,4ddabe8f,81433d11,852f2583,85dc0463,9618ea1c,b06fe50,68358940,80ce4a4e,9ae09021,b8945aa9,1e4401f6,aadbdcce,421f6f32,ce7f1317,508cb799), -S(a67ecfd4,3735a152,4908375d,d21bdbf4,824be481,a8ff6201,8145c624,c5cf74db,e993c3f8,5aed69a0,f9b44ffb,80b5156c,33f809c5,e9efef1c,fbeb7b25,c6152911), -S(42f5d252,3d508a01,e7177947,29eee1a,fb7be04c,90539d9e,afe32638,b252e158,7194bfeb,f9ec8e1f,5039d582,ed7d28c1,99d5b07f,bde10b1e,e3b4bb64,148b5119), -S(15bc89ec,5d3b2889,d26e77c1,33eb832f,bded1d29,ce975905,d9355b2f,d99ea1ce,4e0d28ca,7aa69933,6f41e3bc,57a9639,81e2b92d,7b80794d,4787251b,f7fdb0d6), -S(7d68bf90,45c79869,5a8ef33e,f7fc4386,5ac90c37,8d3beebf,6ba3973f,e9d8e507,d14998be,f5bab5fe,fb94ebf6,9c0bf133,a6606b43,f621c861,ca1cbbb3,ae3fccaf), -S(82541ac5,9196f73c,99f9ee01,ef266c5e,908e91b8,b341e052,ae2576eb,17b90025,29eb3c8b,8ef826a5,6565c9ef,c2b2e47b,94e12736,131d1e0d,5b235d0c,169c2934), -S(242399a8,9c5a056e,8073a5ee,45475787,b31ff7e5,3d451f2a,d0437580,a479239a,19d5ce74,8c9a4a09,606e7c0b,6b486098,b743d018,c45e5e5d,8f39a966,fece6ae8), -S(cae84567,8cb2b2a8,de8040d4,3b32e0c6,d42dc902,3db4aa,273d24d7,17a85e7b,edca07ac,15d81467,81185e1c,4829951c,2569fa15,3b7e7ddd,22b58ad6,3b736094), -S(5c3711c7,e676ef0c,f889ce6f,57d9f92c,1cd91023,2b6fa410,75fe70a7,ce4b3db3,9b5e75c4,eef0358e,6732b7ad,56797ce7,82a21fb,d13aede0,d563638e,eaf62eab), -S(bade63a7,a4a443d,26d58900,bec36c28,940f4b32,fce20afc,2adf307c,3ef9d71,3c801bee,78daef8b,5cdcd5c6,bd0e63cd,712c2dc2,8e34cfc9,e01beec,b198d687), -S(cff82bbf,2e6412f8,18af5ae6,f9947aef,5d89eb32,cd8e9961,848f75f9,f9e4aaee,c0624130,346ae6ac,e5e76b6a,a2d836f,bb2f07e3,1467b8b1,76af0345,d8f5a137), -S(b3e4bcf9,f9e80edc,c4249cd4,58794fd3,921ac31f,a5f72c7b,e6f7dbfa,29f5c7d8,c045724b,8630771e,2772cdc2,53b2842e,1ec994eb,52296f3,6e2061b8,b32b9d3a), -S(24c22e2e,55f24320,65e91ef3,503bc571,c5290bab,ff95329e,17644e6b,8ef22386,2f91c5f5,6184c519,6f945739,4f101034,fb5fb146,ea61e009,39641a9e,d8178890), -S(29de67d7,edfddf52,6346fbdb,62e87e58,a0ffe4f4,7ca14a47,426238a5,3a3e2188,69dda846,e0620850,ae6d3fb7,1e6b9f00,814a0a59,ec7e94e5,e412a57d,ea4b02b0), -S(c8377575,d34b474c,de02b73e,5cce9eb0,c80c26c1,a925f090,d6b6804e,accfb653,306f4844,da7b237,38adcfc0,3ae9ac48,206cdc73,7c97eb11,c48c7951,52a9cfc4), -S(bc1c0c6b,b6a169c4,10ad87f4,d1f6b25,3313637,8d766bae,ee9401fd,b6895515,7d794eb0,81d9476d,c4d3cf0b,21b99537,9446a6ad,788f0f94,8acbba71,b20df5b0), -S(8b49586f,e4b4f33a,82ddfa9e,e83b7f94,177c1f39,30707f20,95a3d841,bebe44b1,42fe0fa6,14cc26a0,d2608c6a,31fdb1dd,993aa33f,6d32bdaa,1f9715a7,3e11340a), -S(fc52e593,28af4bb2,ae6abd18,8ce99b49,d8cb823b,7c6418fd,8a5f9757,44ebac16,f130072,79a1eeef,5483bb81,2ceb9090,35fd5df1,b757fbe2,679e2d1d,16d5a5c6), -S(43fcee45,79e58f65,d25edfd,f429d89a,f8e7364e,c0f2358b,83772ac4,27ccf626,907821bb,e43827ab,c210b2f8,c984d6c5,def4ee2,5761a9f7,90049477,874ef309), -S(2634e802,fe58e3a,62b9105e,5e37d8a6,f530831d,d4bba691,a6753df2,1482fba4,5d9b9de8,ab3f68ba,1e681048,c67274d,d1fe0cd,4e639454,a2fac6f9,5cdedca8), -S(56f19f08,a31f7d57,2bd94314,4a22245d,9ce74a11,30920573,9ca68569,76b35dd9,b453c349,678dc948,bdf804a8,4f54373f,c4891fd5,7058f1b,43296f59,b89d1fd2), -S(6f7c37a7,b3b96ea9,daae285,31763ca5,d481c1cf,42237ee7,a1ed6554,68de3aff,eafacefc,292a5d0f,b50cc875,ff7c8ff3,aa1923db,68461f1c,de04bb6f,729715a2), -S(59b44c32,ca7c1a74,ca69dbe0,c47f6199,79b997a0,df691d3a,4c7f3a76,9a543723,3ae06964,698b97de,fc3af051,9f13559e,813e7839,c893a0a9,bad75ea2,bc35e302), -S(e7acd0f0,d0560ce7,2d6cd805,d197fe6d,4948721e,b5e4c40c,c2014e78,9bb5c8cd,c95b5d74,5bb6058d,80ec04da,5135d92d,a447ea0e,9154b1d,93a5a014,ae2faaa8), -S(7ffef78a,e04da609,6754fec1,11fbe130,5fdc80d0,3e7b801c,28e23be0,40cb4e97,579c1fe7,54812978,46f2bf3a,57e1f850,ff4fdee8,8d3949d9,68e81d2b,792b39da), -S(5d068102,af4129c4,49c1e749,91ac0c15,dd2a7e29,fdca33f0,84f228bf,f19f5ec4,75f0179e,d77c3cdd,3cd1ec37,3e2d6d60,5425c215,ff009f26,66b8f7ba,77dc07ba), -S(cb90c398,7f6e05ef,ebee67e4,d9725200,eabd14a7,67c10cca,6fc546c6,ca67996d,c6a9a0cf,d18bdee9,8e054e4d,9df247dc,55ed473d,ed372138,cb21ebce,809d3a96), -S(5faaa0f9,63293ddd,83c2a841,6363cfe9,e102c0df,f4af7e81,c046540b,2fa3d653,66548b52,dd344ca0,2e0352d3,f14578a4,cdfd3a32,b410abee,683d316,61205e51), -S(35fc3454,7f04856f,3fd3ea4c,63c07a0d,bc0e6e2e,37216712,5da6347b,3c53b8ca,a4e3cb12,bc29dca7,800893c2,cddd4482,f3334d53,e215fd91,a01c0f4d,45162cb8), -S(ae1fbe74,e44c15b,263565ff,9f578ed2,39741d8,960e82bf,d8788a95,f744bfdd,d711400b,3b458a9a,75e416fd,c4d0efe4,5ba5666b,9280fb38,3d2bfdd5,83a89a15), -S(76f8768a,5ecf11e6,15671063,999ce164,73286582,c4238ac4,f8ef7e20,d1358f67,da94a126,d55ecf1f,8c899678,cbd7e53d,1171d7f0,6d72ffd3,e166374c,58b4f4d5), -S(f454c1f2,b7b447ab,dd2b0308,472a1e19,c1844e63,40225166,e5ddf571,e8f93d52,5ac5010a,1b03dfd5,baf4bb7a,943f0e16,4aa1df65,5166d021,c9db0ee6,abc3f425), -S(3366b897,99dc33d,a1f900ee,57c2c316,d6c2fc16,f71355ea,219731cc,280c0c7e,dd29b0db,9449e2c,7f80888a,783ef223,bc8cf8ed,be82f1ec,c45bbfa4,b054a77a), -S(2a73966c,9b1aa2ac,7b5b310a,bac40490,253f6cbe,29c5250a,dc57d979,f660741d,77359574,39ae6d7f,157723bd,ab2e1181,209f0f6c,fe5f4d0a,a9b0ebc5,cbed1294), -S(3885f7c6,d80f0060,1d60a213,923e2591,f055ff3c,39425d32,43302b6e,82a0cf2f,d024dd79,fb17c9f1,7db519d8,2dd4012f,f353fe5e,c81025cd,deebcb39,65ed069a), -S(ef33a6e0,f5da4ca,904aad24,5f2ada01,a77a93a9,11935aaa,68bd32b2,a6bf81a1,2ba2099c,3af09778,aeda97b,be4c4311,cd3e1636,f2244580,1a9c8ced,5ac81a52), -S(c8b25a4c,bfefb603,34300d02,585c729d,fccf541f,4942b040,c7b0c442,3f8603a3,480ac47a,674e42b3,a884dc55,be736c23,ca69e81,1af56106,efa66122,78214cf7), -S(6e0f7e4e,e4eacada,cf3862a9,8af74f97,99060f9d,73a9eab3,f3db3a77,20a945c7,4bf3222f,eccfffa5,5afee33e,9d39602e,e0ef3c67,870817a3,a9bb5b31,78469272), -S(32a987ef,6cd9c989,aa1d1fcd,5997169,2db6ba4,f4c8ca08,4b1607f1,697b202c,5c4eb708,50a58a74,5b91143d,ea849068,ab8b1b77,6fd2ec80,eef53d60,2cab45fb), -S(1299c334,60ee62bb,68847930,82ce6c49,bff80a9f,4fe33196,7b09a05,b22aa04,50ec11da,9d7a89c2,68bf0314,7b67803b,824b59c,9d496a5b,8c0d9955,31c8626e), -S(ce9f9a2,55aa6b62,a3184c2,8ea5d204,581fdb7b,1945d9db,2c245e6b,4d0b0d6c,c694fe1f,f93ae622,e5816c37,cf581f3a,4832442,d171b413,f86d4c25,ccbf0cf), -S(ad42db1,1ebf460e,f7954df5,3d7cd6e3,a7eea34,6ea8ca1,2ed4d5ce,83badabd,7c0538e8,a29f66e9,d2b3a235,9b00bc42,6809ceb5,11d476b2,38719673,a70e7b09), -S(fadae65c,500d39f0,377ced91,b0a9c469,3db78832,b31b14bd,78996dde,4b764bfd,a4b8e5b4,e398a8b9,90ddaae4,7247a975,2f2267f0,41a867e,e3b0774e,1a692ca3), -S(14e71e8b,76377b2,52b60ee3,f089d612,402ddf9d,92f2046a,cc7474db,1cf56f69,7121d880,5bea69c8,233dd120,f86b914e,cd080537,649b6cdf,74830f87,73aefc55), -S(b15e94d5,5edb91a1,9883f6c7,5bacc56f,2dd2c1e4,950e267f,c4415968,a75d7730,dbff7f2a,57d7072a,4a076dc8,a2d26233,1eff662a,ce10d24d,e3c8ab57,8251765d), -S(e343c0bd,240de1fa,f1ef780b,4922ddc5,453649c5,7a08e9cf,99f162c0,ffc12e7d,b9b65d5,3861e229,777bbb4e,85ea417f,32354b9b,8796bb47,2f6eb67a,2e3d22b6), -S(c3ce72df,4730b13b,95398abd,fa02c834,c5d20e37,9ebce9bc,b77a777c,f9fc3299,ec87a4e7,71c04584,f6dbacd,10fec1f2,c8bbbf25,9954d596,2309f0de,48ed9573), -S(fb70a931,895d44c0,e31a9dd6,bc2a1cb5,250212e0,5ed1f55f,5c668e3a,8390677,d86125a8,cbc9437c,561ec1cd,95b5190,328588be,6bf7a25a,94271547,1fee6a69), -S(b150b153,be5afb36,f6bf7b27,ec687612,265e3177,2534bc4e,8ac92607,9a3ef16d,571ee1f1,7c499be9,89b86781,229abfbb,db83272b,c7496f17,52719c2d,b0812c40), -S(2e71970b,913e3006,84eccff9,aa4c914a,22c6cff7,3bdeddd5,781f68f6,177adc4d,829fcbf6,1ff72af4,6bfe69ea,d928283d,45db7cae,b1b59252,7dc6496e,22a6ffd0), -S(d361c4dc,3df5e874,cb459096,d319957,398e2a5f,337208b8,6053315b,263ed230,5225f55d,49f2d8b,ffdc241a,b54b5a43,b3856b7a,60cde97c,5e860561,f2da2861), -S(3f30591c,d464af5e,ca79c060,7e6a8ca9,c6a2c2f2,86177290,fda65a82,522566ba,fc41d72b,f20b86e4,6be3c20b,890fe8a3,ceba4805,bfc61c7c,66532693,7de90e22), -S(2f6a706d,f5efe7b2,bf409606,5da98b97,86ceef57,36677935,c08e0b8c,b125db55,99bf95d1,b348b522,a1cbfc73,f2a4e692,1836256a,97bcee77,51ff5091,6fcaf620), -S(c8c72176,255d0e32,ce4d7caf,aa9b7467,ff49ac94,34beb017,9883b22a,4254620d,580ea490,a94a8310,cca59b41,43fd4740,40ed92bf,7eb25bef,a87cf930,a974c943), -S(a5d65fc4,9bf06fa8,6018067b,7ade5ee1,a541bc2c,bee0edc5,6a144f0,6be32808,ed70ce9e,16053764,35c0875,5cbfa6b0,d1fe923a,fc9035c2,1d26fda9,58c36ccd), -S(4a6c4b07,7c6c9dec,d7d6f98d,59eface4,ba2fc654,df7d14a6,57f108e5,d3f91d29,2d2a4b3f,1a9aa787,cb747f7d,961c4cc3,cbd62de2,ceada2e1,a71648ae,feadcea6), -S(97d610e2,8b3771a3,204235eb,faccbe5,29d1a6fd,5003d6d5,4b37cfc2,80550354,a441235b,593f0649,ba50d405,fa597b25,60c2be24,2ff43ff8,3b635327,94e67c51), -S(b9f1688f,4161e507,d8f540f9,4294a967,739231bc,a89c7d8a,c54ee365,1ab65111,363ad626,e5ff0d,7f43aadf,5228fbe9,b60efd2a,336518ae,53a0e36c,206d5d0a), -S(1b748bf2,690e8cd8,e06c5200,5a654bd6,38bc62d6,63ce1194,c4bea3e2,82f2c351,db0ce849,96bdfcea,497bc8ef,dcbd6e89,d0305b1c,4b6dac31,4e480b45,a5a9cbeb), -S(ec9d3d1b,3ac0e4e8,c01c8cbc,5d498201,1f52cb5f,dc7dd0a2,6f447457,aa9da7ab,2934e845,ee13267,b3dfbd3e,5d77cc77,214779ba,51bf7f67,ac3cb131,1000369c), -S(1b28bc0b,ac8ce96a,a3d49611,1f66c77e,b030a49b,e9ee788,d8e395ed,495c037a,ad5e12d2,bdba39cf,5efafe12,f7588e5d,c5f2bc82,c7a0ea88,217307a5,c996378f), -S(6e2929b8,1060c4ce,c6b3f071,40c8b23c,48a87efb,9765f292,13993cb2,9c046638,d68c4ec8,ffac30e0,f2642595,aee701a6,5c254247,a1397726,b0c40a77,1060a8fb), -S(122307d9,313a11c0,e411e78c,d66bd2c4,5aecfad2,3221b558,d124674d,1c66489b,f5713161,cb284025,efa004e3,a70f1374,b1ec2450,78f2252d,6c7da11a,ddb5ae11), -S(81df90ca,92efd148,9383a7d7,c69d4c4b,bcf5b781,e59834df,9ca30da7,cbfa1ed,fbe1932e,421a7a67,30e4a7c9,371ee8cc,a985fd2b,dc1cd465,769ef494,b0c8d6ad), -S(fda38e5b,f685c939,6a2a71da,b66d02b1,a1da8953,c659c880,bd201879,d275a01f,2c729bbe,39467247,601c9b48,80dc7ba6,193f8270,a742ec1,5076da82,65db9bb), -S(45aab7c3,69af7188,9986b609,e16493a7,38a255a5,d4c27a3d,96888275,54bfdce0,4a512b2f,77c0aa0,e5aa021e,2bb63904,aa7c74aa,daf424d5,da8676c,e043fcf0), -S(14b463dd,57d236da,fa835f57,6c4cf514,73180d39,efec4d18,9a9cd1e5,91df4f57,ac3bee1e,d77fb0c4,3cc852e0,90fdebb3,1bd87006,7129210c,9334beeb,896e66b5), -S(5a8fd8db,833621c,e8e21f81,e2f30db8,2a98e6e0,8eddb80d,6a2e63a3,fd7da2bb,6f6c8e76,d846f5bc,b53a88b1,349b95ed,34239991,1e552740,1e58cbb3,bf42c8e9), -S(62b727f8,6bf49290,2600e83b,5a24974e,c35444d9,92c2f083,7bc4dc53,d3ed119,d7daa7a7,b8a0d462,598be5b1,6d36aad0,c07aafe5,600e3955,81c352aa,d6135b21), -S(1cfc0220,cb0f64b7,51fc05a7,897b3840,fb2a1c33,777fedf4,7ebb4c9b,e6059ee,d3a90002,d2f8c20d,1174fcf7,8591ce07,5e2b34f8,83d634f4,7b27d5c4,3680bbfe), -S(89efac24,9b798548,2c3ada7e,c7792632,fe872f4a,b6001e7d,48605b12,cf8cecd,a5d062a0,1e40b4eb,de2e10e6,684d9b6d,2b860f65,9cb6c51,676ee74b,40e5f612), -S(cbddc8ab,e37d0494,cecb4878,cb0bad9d,da00c1e9,c0876437,3405ec56,2318afdf,53ec167f,d0f1123c,3ebb9cac,476c86d5,94762b5c,7a365153,776695a7,169f06a3), -S(d020dfcb,c5e78a1a,36e1f8e6,3530d03a,5b53e1d5,41d05a46,d4e24318,706515d,cc811700,740dfdab,752f818a,cee554e4,d7e142bc,eb5f6e77,9399e160,c7646048), -S(2430846e,6e768e57,d4776cda,448ab651,c876cb6c,aa8fce63,34cfa4b0,826a0e25,9bfdb42c,e711af1f,a0cfeaf5,8264cb52,4d4d9eb7,a9fc1328,4351e209,8818c559), -S(7d3eeede,5d8e3320,80d0dcf6,3a8c6929,4951e765,d881e0af,febaef73,bd9548af,a4b9e695,85b2921f,fd651eee,e320eeff,52df838a,17efeb60,16d5cee6,d4475ca9), -S(4bdedbab,af06488c,28fa5a7d,ebe15b63,759986bc,535b4ccf,66f28e8a,1126803a,e4ad8238,94741e42,c28b330d,16b16d40,d538d081,41f0a5c,92890934,e3c09dc2), -S(65569131,959b4da6,d2b52217,9569e44e,cd7e7ca5,515ffd71,fb4b3444,246f925a,87049181,3adc7c36,9bcb7696,f90485f3,66beaf52,9cd09e04,36d51cb1,6e84514c), -S(7df015c0,7404bd5,518ef8c0,1aa4c5e6,8773800f,fad367c5,5b10254,45e720b,6e936006,2fad0fcd,a52ae9f2,bb7e3f5,ad0ed702,50e474f8,c4e6b62b,93885bf8), -S(90eda060,55bec90f,ae0545c2,30fe67de,99da2fec,f158aff2,ff4c8a1d,419eef9a,c5a0e7fb,f8f5f20d,25f09076,6a8741e0,5e7c49c9,c6408dc1,fc02e84d,79ee165c), -S(b36d9a3c,1a6c46e2,fef6dea2,26b1bc6f,e957849d,d11170d6,25746bed,bd3d2846,3ad18694,f8c0e199,77d0a56c,161a71f2,72d9090d,96a376d4,7d6ee99b,5f3ae29f), -S(7fa2d360,27f7a698,e5e4dece,16f7f78,5878ccbc,dec5f03a,8041805a,609f01ba,2bc2c266,d8d013cc,c215e3cb,8afc5b8f,254b0656,98281044,8f946d65,8870703a), -S(fd314b51,71ddfb60,16f3dc94,859aff4,5b01e7a5,5ebb3c0c,a2ef8262,4c41fd08,28539bd3,657ce721,4f6d88b8,f8f85565,996ec40f,fdce88a6,5820a8f8,4e6271f1), -S(6e37f52b,ab64fbc4,a22cc014,b81151c2,623069a6,6c617fec,f8d32d25,38e23f9b,fe6910bb,2e2e366f,28ef13db,183bfea,924603f9,58847477,ebf816e4,33cbdd34), -S(31ee76c4,de143395,a1d99eb,98e8a579,d88b3450,69ff0b82,8335ad2d,72dda523,155d6f31,9548c9bd,62cc219b,db6f95cd,23295ab0,253e42b2,cbc34fd1,775dc0dd), -S(947c2b1d,604787c3,e30cf04,31fa2b4a,7d823c84,584feb3,5f68545b,639df62d,bc50bcbc,dc6e530c,45892e31,d71f719a,1d515060,ecb123d2,a37eb89d,45fa682a), -S(8a8349c8,46a41e93,fa097893,c4fcbd1c,7c25e3a0,afb17929,72a7a872,570e5abb,fdbfe661,fc2940e4,b8c0fee5,7245915c,7f8c9ba2,1f548bf7,d5c654c,785b94a3), -S(7733640a,13671b1e,eccf3527,3cb9ee8f,d79cd08,ea57eacc,97b39bcd,6ad669b1,7ce5c5d5,abb13079,486bc91a,ececa9d8,d0d1f84f,a5d74e57,e4727db8,833f8c05), -S(a9ec8a22,7c262bfd,f5b00b9f,1acc80fd,4f5d46f3,d24d59d6,7c2cd83,3be94a38,f0d9bb94,ff97aaf8,54b3640e,7926a99,8a731a5f,4800c573,d1279d14,5e4d422c), -S(9837810c,86ca85a5,ffcebe9b,714d4b1e,f5c0ab5b,2650e163,d62fc668,204aa566,bc477f5e,ff56a588,bc68f7dc,42644fea,532d7a25,3f84d17a,9ef7a91d,5f3113bd), -S(9020fe03,9de18af6,61b70206,5b615ee3,de3ea6eb,a8c30d9e,24d4bf13,56db96dd,3a0ac3b5,d1832113,8421bc8a,f978771c,53b98110,6c49afe5,711b4b54,f9fb8567), -S(d769695f,f6f22d11,99224b69,f66aacef,8c6cc911,e43fddf9,481b46d9,97a2ecf1,e8f2a6b5,f05be025,a84fe0a7,23ec54dd,b21c32b4,b4d5cc89,5bdd8e66,d8ecf934), -S(a7668280,48ab1e2b,e843b0db,7a9462ee,3ff0a5d6,f7c12ce9,496b302d,99a23042,42a1296,92217f3f,d7de8cb6,df48b8af,11d8d089,5c93703d,a242c7be,d8033dc3), -S(ba26a7ef,1e0b979e,3541227f,2dec3d6a,7ea6f8b,9e9b46f9,93c02b3e,fe1d9611,b0d283fb,1adccd83,be7122b8,b59e6d4b,589204b3,e96adb4c,a6e19ec0,ef1c142), -S(175ba624,70d63d4f,6a3a030d,a1515677,8e589e8d,80ba62d2,1719a906,68293971,211232fe,97508523,4d0dae11,14831009,229fb25e,51f97182,476558b8,adc218dd), -S(1fdb147b,860c3254,b4ae5513,14839573,da2d0272,be69628f,1b395a03,bc8afca1,b42d0b99,325acf05,a3564d77,55cf9c9b,3208e5ec,24e5ef12,b6180fab,8b3f4a4a), -S(986d3acf,c5cc74db,c844c28e,d91276ee,729a5588,e1f504f,1e6f96e4,a7a21607,7229d56,4a9dd4b4,79f8d8e,17951887,870a4303,53707369,aa8e8d6,deeefce7), -S(39ad0832,b18dbfe,1fde87e7,c5d3b948,75fd76,9941c2bc,d605f3d1,beb94e29,f85bea41,f0c36603,8ea8038f,874d612c,43b928b6,4116550,8878515d,fd74b6c3), -S(3a318109,745a25bb,c6e45068,ed37553f,b2591404,3a7dbfc3,9e67d1e0,24bb2f12,2cd3e0db,d2545332,e4bb3e99,8c338c8b,66fc5061,81c6595c,37804541,8c507a16), -S(617d3fd8,87b99438,6eec49af,4358e73a,bdf52dce,f26ac8a1,52be64f7,e0e8b2ae,a45b906a,45c2207,e4db008,e4fa961e,6c483c24,3c0d7fd6,b11af11,e5f8b444), -S(d1171cb7,e5a3daf4,7b7818a3,2fceb153,58c87d4b,84488cc8,1e930bc8,adc467ea,bc725547,a2d40dd,8d8ed471,1869d711,38118b5f,bd00f0e8,3e1967b4,880da3c), -S(61f610ef,de8aedf,f012a109,5e5ad596,9d06ed54,214e6f33,c69643ac,50df0ca3,405ed3cc,5ae1b566,fcd069f2,e8b67520,74700b94,689eaa7a,3fdacdf6,a798e091), -S(8caab88e,e5fa3cf3,59a8ead3,2d80a4b7,b57453fb,e90a75b5,ea9e4f0e,5ffcb7ca,8b7608f2,c7480114,d8b04bc3,7f089f8f,2075fd9b,5b4a49eb,bd0ab1c1,8ce31a9b), -S(b73ee255,bef7518c,12be7d6d,36314c8,3fcf3c7c,5b0bf2f5,3a1add92,82bf729a,716c6c00,5a82e1f8,1f493753,f4e2527b,99bfd9b9,988b5e94,f7652ffc,6c32b7f9), -S(ca72f63b,ff6ed94e,c1fc4f3,427e90bf,a16ee627,b9112358,1620c156,6f95c1,a554deaf,c8bb3a56,d809c044,49efd477,7d083da5,690ba56d,2a4e2679,71d6b0e3), -S(f861644d,d5693cb4,b4a8256,8a5297a5,595a64b9,5f9744aa,683dd91d,8d58b301,66223ae0,99284fc6,ff5bcbdf,cb0bae0e,cd954610,d4c152b8,b979b08a,c4d4adb4), -S(ffca4bc9,b9a2e17d,250d4357,14c882bb,7e837054,4bee35f8,818e696b,7a7c2c17,4c57c13a,e3d97da4,8644c47e,2cdc4d15,5f6add44,5544a853,f8e46bef,271399de), -S(c36a0163,5935ea3b,f590d4b4,656cbe2c,2e62d8db,ddec2eb9,ab867de,8d9dba5d,d9ed3116,dfe337c1,44025ab8,e607256b,f870c4bf,a885bbc7,3ece4b29,ea6122ac), -S(bfa4fbd2,c9fe8b16,9520ffec,277fdc19,cd53dced,1866d5a9,404cf89f,6141e4da,f76e0423,4fae8abd,892368eb,e48945aa,a3684136,aa5b7a0a,d85d0d07,79af3ce7), -S(fa7be3d7,db544548,45d4bd1d,43c7960,89aa1eb2,4c0f81c0,16645d77,83ed508f,b82cdfcc,4df4b465,4c95530f,d621435e,8679aee0,9918a06,131775be,8cf4e324), -S(818a90d7,5939e32a,af92c601,af9eb717,88443e57,b7759bd,9e7e2be6,238a699a,c951ef89,8127b426,1c7d6224,377fe63a,2706636c,525ee10e,30e11a85,c160b50a), -S(ede3411,d3acaa0b,650aee14,29f910d3,5ffd5684,eaba0280,8971f2f2,330e2880,8a2d5c96,ae4ce2e9,739ff957,c595591a,63a58132,10b86a62,bc4cd164,54b8bc7a)}, -{S(dd7503a2,a3e15e7,39eb9b1f,856d6e33,be4890b2,f40cfea8,1bdf516c,b942731,ca9cd04e,c3789ab4,5088b819,953e08a0,b8adb8b,b2b6f7c8,661a2d3b,83a54c77), -S(b0aafd22,9e0fb326,b5ce8cef,578803c1,da2be933,1f47b343,370c2e22,18bde7d6,570b1e28,a519d9a0,2f9d06b0,6637bd8b,6c7f7e51,5a7c541f,7263e05a,87270081), -S(6d5417c3,2d66d6e6,a2d2c599,366ab000,99cad0b7,55f8f3e5,15afc018,98b9efff,786eee97,bf1a1c9,a57de5f4,94be0a29,663b08ef,5162e971,50dc240e,59d9d489), -S(9c64eb60,9a9469ad,fec8d298,50a08f7d,d4e99710,37c9e7c3,7eab2eab,cbce5b4,60569102,1deb5b10,705231c3,e29dd6e3,b613e6c8,eb313cc,68fd581c,eab98ac3), -S(d219f302,cc6de5c9,8360c088,881465e,22fc572b,8217734c,742231b4,ee487bee,89710994,239f6120,df848623,489173e6,f337c99a,71fbc319,75e768ac,43cdf91d), -S(792810f6,6b9cf54c,ebd8ff1d,159f966a,7da61fb0,34651402,e878e5aa,2b044259,9d2d44c4,b52b24b0,7c3dd127,43fb81f1,e96991f4,53c06839,cd86a2c8,faadfc68), -S(c9913dd5,bef25d08,327d7441,b0793f4e,e3e89b5f,15cdfb3,483f8663,3644d75,e6f5b61c,6beb820c,64beb375,4d80f3f2,6e7aeba1,f4a490d2,e6dda2c,b3131e24), -S(a836402d,582230fc,bc8c944f,18d5391c,3c934e1e,ae1a5f6,2cd6ce3f,b454e6d4,dd8417ac,a9ea2e51,13043d8d,10c8be13,e48a17da,e1d78f84,da4ca58f,d07221c7), -S(46b82270,4a808581,f9dd6d4a,ac7cf765,90dc3308,dd54a6f6,3d4c49d7,f5652310,1e8ffdc8,a786fb63,4a56eecb,ed370af5,9d6300b2,cd05c1b,5bf28d4d,69e64c9f), -S(eb25a657,ff10f29d,4a0b336d,feb63364,774f28ff,8c6eea04,25df2e41,1cc8c49b,6547a11c,9cceffee,5d43a330,69034c93,94777b74,63c1f774,167423c3,2b53bba9), -S(d1548f7d,b928ce6,86e8e71,c0080731,3a1cea63,838c013d,5d52fda0,17af443,b15384ba,3d62a403,920b6936,54c30a87,7cd359a8,2b63f037,64ac24d7,2a8fa367), -S(ddb36d9f,c6c6c026,6c79f2c1,50eebf46,36737eca,d0091321,c1b293b,52837cd7,8e0cf327,fb2f9548,4905200d,1111da22,aec01189,c8db56b4,6680c03f,4d938f29), -S(46737d55,d4b1c924,c58e100c,161206f5,84e01948,22853e82,e641825f,4eb1023f,4374a770,809a9424,12e75c89,75b98345,48e6579c,8b4b1314,29cec398,6b2eb00b), -S(35772697,7312b547,60f2db9f,443d8165,1cb1fc26,dd977dae,3c659685,7330d3f6,813075b9,d73fd95b,78a9e1d8,a9f24595,98b127cb,90c942a0,8b451e71,e40ba38a), -S(17bca82e,46ab960c,193dab14,7eacf706,4326205e,7fe4dd6d,464d359f,6a0f4229,b882798a,dc357f06,4a98dc47,2eb3708e,26cf45ef,48f28c9d,11456658,1e49c7fd), -S(e22d5891,b992aba4,ef31503d,bb64d447,1cbb4013,86f69d10,37770b8,7c04f855,af5fc7cc,3e92b04b,3b61297e,d7c66dd4,47b81728,1f455c43,bbfb69dc,91396744), -S(3960875a,16521b2c,89c87efa,c0ef7a5c,7a1332b5,a84c34f4,4496c57c,d5c9af0f,859ec9e1,f08de5c6,2fad60b7,18533a9,d18cdc9d,91174ef2,c3eb0653,f6c3e5b6), -S(96e92234,e193254f,5629fd37,aef039e1,1457988,7b18ca19,a578bbe,3a23826f,afc02da1,3693bd69,738f991d,9d2e9b96,afb01e67,b05857d2,3054a7a8,85d55f44), -S(f032903e,40e7c8fe,fbf79c7e,a4eec837,6193c3eb,cc919ef4,ec867909,42c8188c,1406b7a3,f9a284aa,c0d48b95,47d0f934,2b6d3c43,4c6b78f5,4b1d9bf2,ff7a14a1), -S(59f8f5e7,1bbd9631,ec5e86ee,e78dc60e,71c74037,db8e32f,4932ea11,9a153973,7b72a4ae,87d78ccd,3758f961,12cd4287,d18e4cee,7abe996,d51f3276,aa28a3c0), -S(8f4c4baf,36df38ed,da5cab7a,90b5d3cd,fb7a6b85,bb000440,35d88928,27b811f4,fab6a3ae,f7d0d7e8,a45367d0,b1c9c4bc,9b6ecd7a,f6739401,8659560c,8d1e6d8f), -S(f19b8fe6,a84b2993,a1af87e4,313208e0,ba301270,3aec1a52,8ea60bb9,eb97333f,d8610a62,ee6014e8,b0eec123,c6b68ae4,62b0be9f,c79788ff,631f7a38,f134a74d), -S(a382dad7,66c4cbe3,336f2a2b,a11044c,31f5de9,6a1fa90d,479baed9,8ea9eac2,9f7b4cb8,c17383dc,ae9e8e71,81cc9f77,6823626a,f8da9b87,e5773edc,9fbb8a67), -S(337af005,48b956ee,58867d93,d230b0f7,313229de,4adcab17,55a24f02,c3c86210,41b3267a,48e288f6,42ed4fa,357a9d84,f77b1e5c,67a6b20,8e8596aa,40ff3cc6), -S(48e35721,f03fcee6,e50f875c,57fda488,75c6b2e,1e0f71b7,da97866a,de121d49,65070589,1a1e0a5e,d2df20c1,bcaf00f3,11b08c8c,a161e1c,7db290f0,a24c1a3b), -S(2db6b295,1a20b609,819d9e52,7d7bbfa8,d47a11a1,33a54de1,49e2994a,ed25d800,d16c6aa7,313723b8,e9c49f8d,66b0e9b2,6ce3ae04,5f1da4f1,355c02c2,4c1685fc), -S(2024d4ea,eb5c75a5,d26263e7,7803fcc,77fbe3bf,ab6106d6,ba134f6a,18e2794d,57bd2c8a,5c3b8289,d4d39930,cf2092a3,2e9b87b8,f8155eeb,65ae9b88,60b92159), -S(3a7aba1b,95085b3,89b07280,219011db,10fad2eb,c003f17f,2576f166,4c0f733f,2263ef94,65065e4b,36ecd1d6,e77fc8ee,2054103a,28434207,e02669eb,df00e444), -S(d476e308,a3456bfb,3ea08fdc,357addb0,3b5f3102,248e63aa,20b8af78,e5e27566,827fb49f,ac326d69,364a3ed5,f87e3e22,297d752a,8c77d399,7c6300d4,3358c19f), -S(b98a3bcb,5ef6e7d9,c7bb8fac,6d5de4d8,c9770950,994dddfd,c0e5567c,bcbfc6aa,c2e6c22e,ec6e855b,890bfd97,b916ae1b,d7f38a9d,51f1ddd7,fb11c44a,5ec058ce), -S(95af1e4d,e478a281,46edbe66,972c1672,815a12f4,eb975fe0,ecf7f988,d03bdf8a,9b5a9c50,c9616d82,98f43a56,62ed85ac,bae447fe,60985627,b6df1ba3,7600fbdb), -S(eaa4b025,2304fdde,1708446,df75b2b3,2ba9754b,ad68af41,515f5228,91a2ca3e,7d04324f,2a522df4,c8686ccf,52086869,8e892ec6,aec91b83,b6e460d3,b0e39d23), -S(113a2818,f9099722,36d3eaaa,14d52f54,27592ab,b924dc45,d6ccf5b4,a02094ef,8fe91af0,62011fa8,cd0f6ede,c5467c8f,d8bc8043,f9760d9d,14c31fe1,1fea3f1), -S(bf5b27b,81d5bc7,ec597a53,accae88b,bed993a9,fcb78a96,d0fdb750,66f90baa,7d7f5fc8,7c6766d9,78a359cc,5a486844,e62003fc,7756ad34,3b5966ae,cd9d7bde), -S(42d53197,4663cd32,c80d71d8,15d3655f,f4e8911e,971a53f,9ba1758e,79fcae1d,87daf2ec,3cbccd53,84bcc89b,9668954,a73283fb,5d5608a8,5746ff2,de26a528), -S(946a933,98ac78bd,a3f92424,f6bb6383,ef7ce19b,2912457d,b26e7654,f25012ff,ca7d7457,b0a52c33,4656671e,c6e68e70,b283df8f,7a033a21,7f013cb8,8259df8c), -S(1c53769,28cabbe6,3b6e52e9,a7577c54,53cf4071,e1050257,6e7f4609,763d1285,95340099,49a53bd6,44045cfe,6c17053b,7cef08e2,6cbc1975,c2fb203f,7810a4b0), -S(c31bab3a,c9cddb5e,91a69aa6,95545d25,5550a6cb,ed8d55d8,faf94523,4edfc242,2786d686,771c3e6f,a04ecb04,cab881fb,bebe70af,1c83f7fa,1fa2922b,2dc62e0), -S(81df0d06,1f3519d3,3e8f7743,8b917498,6ddcb6d8,cdeb5bca,2ba03fc,6d1b2bf5,183ade12,f68baa5a,c702b5d,2ada2794,bd038524,63796f7e,c885b5fa,96dd92b), -S(3825dea5,f42fc36e,37367606,1d8c4589,48aa11a5,12449590,22cf258,acc068d8,b6286350,2fa61c64,9ed1f3f,d64cdf9c,bb882d2e,82723e11,73628333,4c2354e9), -S(9aed85ef,5bd25a21,46007433,b1131528,6510ab0d,7918224a,dcb81585,ebece06,73e1712f,d6b3d56c,53bda6fd,acdee776,aa87f994,71c8cf28,17c05fc6,e5512bf5), -S(3b4c21f6,c0a815f5,80a75488,5b02087c,eee77de2,704b1661,d2c42329,169ae892,997bc30b,1e5ec3eb,df3076bd,d7ff8906,322c229f,fff17b5f,51316dd0,4778f062), -S(bbebedba,d7fe330c,1e50de77,62dafe8b,70cc8cf5,11c44dcb,1cdd55ba,82ed870e,27f2dd33,573ea340,355f9a9c,6cffe63e,44108290,f27fde3e,7c934d52,febe1af0), -S(babf0cd8,58f49844,5902a704,da20c759,881df7a7,27842f98,f3ace994,1937a7e,8b05b19a,62a9b997,4b0a9668,d598c929,c4ec6493,6015fdde,c134720e,fcb32081), -S(a420c65b,33426f3,674a5859,cc16d583,96b3c325,22fd2dbd,3ac9e179,1e5bc48d,695d3557,787ffb5d,8e69293a,afa250f4,6a0bbdbf,7fae0540,94f43885,d92d2544), -S(a31dd94f,9fd72006,abb783f4,c9c8801e,400c4d3c,f4f81906,d853fccf,e3c1cf77,8b49b9b2,8c513ddc,6f31577f,5a576ca9,bcfad648,fe0556fb,30aa3dc8,cf4c9ee4), -S(d4ea9865,929456a9,20c3a461,c3931efc,e73479f2,e63ae5ea,6e1fc227,1bbe518,f214c3f3,844daf1e,8aafcab0,89e1ddaf,6621ab0,975346a1,b04642b0,9a5be061), -S(995c4191,bb5b5831,e32ff6e,6be060d1,339bc41,50af35f8,e69b03c1,3ff55505,a4c0262b,d585aa19,26009953,34f83f21,951dc3c1,a5b9cc12,c7250fd0,c8619259), -S(77ea55e7,8d08e3b2,233db269,37d1259c,ce4acae,5989d056,d4bb4bbf,a7ea1cfa,637a160b,ce9307b5,a21985f6,6bd9c4c1,8f0a0679,3dc6c5d6,d491a2d,ea034f50), -S(f42d8da4,9862d140,30c9e4a0,5349a650,166d7904,97ff4a6e,403908b9,d95293ef,c1df830a,2e091a6c,e65f4443,f7c5d51,86838e07,dd90b0ee,f90b0134,b181b30e), -S(10e6c84a,53be364e,92542b00,2e5303ab,d93507e0,5e3699bf,aa865838,8df504f5,4f191ec3,974d9a23,28443d0b,a6ad8ad3,4a04e06c,608d15cf,d3b50d54,70d2fdb9), -S(2f27eea3,7a95ed63,f1a1c228,4ce37d72,a8e116cd,b5555f10,52307156,818b7162,ffdbcfd6,4b71c526,5c19b6dd,4fe9f0fa,e993bd10,a727384a,84807308,7588fd8a), -S(4ca6d0ee,294e7961,b9716d8,3d9065fd,a362dd0b,1ee95784,3e33c27b,464cbef9,6e37c568,801d5be3,7bc240f5,908229ba,bf7f44d3,26591bdf,58ddb69b,742b417f), -S(17e3a714,cdfa9919,b3a2ab6b,faca1a98,819258de,53877067,84bcbaf0,8e38e807,4422fc06,1df9484,7163efe9,f6a75626,f1cb4db1,dc563dc6,6250850,99a2d1cf), -S(86db66f7,2e0897f7,5a78295,45ed56f7,f94dabd6,c3ca13fd,4b715e78,24778889,116731bf,d85bc78b,277b09f0,5e341374,7ebf0977,587ea430,7e4fb0e4,b3c1d864), -S(5a67a2dd,e738eade,230815c1,cc2e259d,9c0e750b,1d42ee3,c4636368,d2add861,9c5b305c,d9dc561a,ef396711,faa7b196,b149f7fd,48c7f608,13d96ab6,1c23813), -S(bc5e682a,cb10eafc,319401a1,deaa5a8f,97d8b1d0,d65b847f,fa396df6,5f2d3cd9,bff7f649,3404076b,1c978bc,22b56cf,de56a233,414bf112,39ef0c2b,ba8c1c4f), -S(55e25010,b08cc417,3062a4a8,20b00001,fe53546d,bbcd0c86,ca21c3cb,22291201,6ba72697,9becfa8d,53fcb128,f3193f8f,74a99a7d,82aab685,cfa1fbac,8f1d71cd), -S(4b53215d,7c5d43f2,ce8e109d,c98d2f5d,af1ba4f2,7a713d04,22253cbf,c9dd1f4,2e96d,bc79001b,64a12093,67c36c77,dc8cc188,b9f632d1,56bd53a0,462bba31), -S(8d71406c,8eba2f08,efe9a88b,72faee9a,e149c857,d625b710,c443219f,c2e24997,68aad2e1,dad539d9,dcfd641f,be7c1ea9,d4239e2,e881e6af,57260011,bcd0d61d), -S(443ff7d1,5f92816a,7e64e005,f0fed100,efad65eb,cfdd7e81,a6d4df72,a2a91932,3be7e0e8,bfbeeea0,e15f1a4d,cd9b1f7d,85d519a8,1215c2e5,319db187,5d3c5c31), -S(a3081493,6d7359a0,bd8b0adb,78b79ec8,388f783a,f02b2759,318b0178,870ef633,5d89f521,e1029655,432a688,aceb1beb,ba824618,f9eae95e,ee0f56da,21364207), -S(33eb575a,aa3d6ecf,eba5869d,b7eb1340,bde18656,3ff4c32e,bc32793b,4bf50129,296dc28b,b33aa01,684894d4,d2766575,d420b02d,6cb23152,79b370bb,8836181f), -S(4c09fb9d,a61435e7,9e2f9faa,37cad82e,ca906e27,f5d17d,da991e54,e7650e12,1c3e8af,ff50589e,ee448778,8157fa7b,570a9063,d76e6eee,df6b8d98,140c3322), -S(8c0f258c,9162cdcf,9d60168f,bd98b995,8fe2c59b,fe334b76,2b05d397,8ca4cb29,8f04e391,d6abd5b3,1c3de519,2266acfc,c3010617,24a204f3,f209aa49,96ecfc54), -S(e7e0ec2c,d18151bb,7d46c17d,b34b36d9,c38c0e78,4d6c4a53,5661ff13,7de3ea5e,b569bbb6,35f01a5e,c7e3011a,95fcd613,357328b0,f589c77c,a49550cd,63ed698a), -S(33466e36,f172c0c9,41af8635,80f7393a,21111ca9,9962be43,c96aa29c,6418d949,e434328b,8b94157d,72f0329e,7d8497c2,a189a23b,8b663e5c,c6a6431,3d9cb1d2), -S(74546f84,2d5f2f0d,56c6de7c,e25dad70,47664eff,8b53139c,2101b450,ffb7e83e,72ade537,f344465b,349412b8,c5a52396,b811b3c8,64b693c6,995b168a,3d52a146), -S(2a057c20,49eb78fd,6b1e101f,f1ad93ec,237c31d3,b9eb5a61,cfb9707c,10aa3fdf,12f3ed71,9ef62004,29e31f76,50d42a26,3ffec21f,18618ab7,a1978341,34e628f2), -S(6ef7e589,77b46681,18725285,d6a80278,af326e69,37a1a2ea,c38db58,5dfdf391,7b7f2f2a,61a36fa9,92c25c9,de3c375f,1e653426,21657b1a,46e73afe,185293c6), -S(bb07cd89,749683c3,d0d1822f,b2044a0d,89295a1c,489a083a,d4e0d686,5fdda7e2,93217977,cd636dd2,5dc61a32,278701db,488d4b0b,bca43fda,5f616ed1,bc853e67), -S(86a512e6,6aeb62b4,a3f0e3ff,b3ab705d,55da48e8,5c83fcca,8bae1ed2,c7c310,69efee26,59130cad,c307d137,348dc40,5e797bc3,c0e08888,19381382,7c9b70a8), -S(2e98a430,bcbc702e,d038c769,2d0a18a2,9e68ce5a,33297dc4,d0c6b344,55141fc0,ea01fe68,7ef121ec,d612d3c7,95bc2b4e,aa8a79de,a7a6421d,6d0ca841,4364a8c6), -S(1e94d53d,8f2efb80,fd5f36d6,48517bf,a81f5eea,6e6cc95b,125c0f4b,7f6b544a,4c6da236,bdf33222,7cabe303,ebb08be,5d72cc94,ffe09f83,7f89050c,250055cf), -S(8436f6c,1c597134,be20a252,3808f764,a77cc015,92e2c0fd,d99af978,2ef98f0c,5d088601,2a449b15,e7ca98cc,b12c14d5,e56dcc11,21eab5ce,8fd64442,735202a8), -S(dd438a23,a4ba1fa5,8691429d,7a20119f,26b998ad,bb041770,4fbb7603,7fc939e5,c371b95e,1d2db347,89ae43cb,ad439c87,c75d9cad,370dab9e,771ddb8f,f50fee46), -S(a50a202d,dcf0fa6f,270ed4b4,47ee2d09,55aa5ff3,50bde518,b5365807,5e921a1a,13357652,4cc6d018,e3cbae93,d87adf36,15a518ca,9421d847,92b9b6a8,fa45b5e3), -S(7dda8de4,b278bfd5,3b7d4573,1c3df0d3,a32c8459,37dbfd55,6176c034,359b6054,249585e6,a11e174,ba72b6ea,cf02bc58,f53ad9ea,131f22b3,f273a38b,2ea12e71), -S(8c34d5b1,77080808,84081f8c,f36340a6,2526ad47,8402301f,248cab43,c59b510,d3370606,3ac61796,a8b55004,64e458c6,36c6fae0,ac4fc255,b99e03a7,fd39679b), -S(f2af02db,a23f80fb,26dae144,8c01030b,7dd11c7e,e670731b,5a3c8d43,cf70b3eb,3b91daa6,e360244c,ecd16f73,ea6b2ec0,e2bf1af1,1fee0530,7d031861,6df7cd6a), -S(f52e29a5,fc161198,8ab924dd,300a2063,eef50892,c8aab719,989a7c57,c61b5472,c8d317a1,e4bd73e,1520b519,bf5e99b9,537d4014,11554768,ce1c8d59,dfb6485d), -S(ec3bfc26,168616da,7521601b,8213cac6,ff0525f0,bf1e9480,bf74ca36,5043aa50,b85fb266,cdc767a9,9256a2f8,fe3d5f67,13c46dcf,db0e5668,c51e57d9,e40c68c1), -S(2606e785,bb3bb8e0,e9509d6d,d3f13edf,cb945c27,4b170b8e,f0a1049e,c6324d,1eec7f74,981f1afe,b519e261,a9459140,fac8c0f6,798c4bb0,7402b03f,a9f9c4d7), -S(643cc5fe,b10472c1,b7767be3,3d089e97,6e1dae65,766f64b2,13ca7308,fb1a859,4001bf5f,5b1f1152,41c0a5d7,7c402f58,81466079,7217151d,ca52167b,98cfbc6), -S(7af91d3e,31685c25,e4665b8c,60857fb1,a9eebfbc,b119995,bb30886d,49fec506,ef793e78,d32b7dca,50fd2281,76e9deda,fba1ae5c,51012a9a,5e0f11f9,efa36d02), -S(f92595bb,ebf4e875,5a4c090f,cc7479ec,e36df57e,54d02703,77492a59,695dff86,3d693004,acd31ed3,edc6b849,f0276908,3b62f97b,ffe2ce1c,f030bab7,8edf42c), -S(56d8be78,ba1b90f2,f1e2bdc6,98676605,84ef5cf2,42061f99,a372b8af,3bb81492,37346441,7138d5fc,827ed55f,7342e423,b3413d18,a9450670,bd9f7639,e3f7d1cf), -S(5e72a946,f62a82d7,e1a6bdce,d4563e4d,d11ade3,630c48e,e7dde8f,4431cef9,f963609b,37e6e3a7,647bf3bf,370016d8,e6db7c3,18194eac,b8abb926,1f4a6483), -S(915889dd,b578d98d,b96c9d55,e6d10bd2,85448210,19ad5652,5ac888a6,11ebd12c,fc5c61d2,2b2a6235,51af62ea,56e53daa,a4ba1d57,e1124834,e0c3e547,da8a00fb), -S(eb8dbbb4,b11a53ca,4b00a8f0,6bc5d957,9659ed80,df9556e2,99d77d80,1372996c,3f7d9ccf,b1229e71,fd5d3193,4af913d5,e645050a,91095df7,e9703fc7,5552129), -S(11d9d597,213183c3,cb33f43a,36289f32,94fab62,eb073b5d,9ad2b71e,a1a4475f,80f85384,db3424f3,707412a3,6bdf4e67,4adcfc0,4b2e3957,f9ea2e46,416d85c9), -S(4bb5ac37,b29cde8c,a1c39e5d,b3d75401,26617089,c82b5aff,c61f8122,1e5fa6b9,6345048b,ffa2f89a,4e008daf,91784b02,5bddf7ba,3fbd5357,ec1f8c04,f8f9ae5), -S(542f585d,616db634,689e86e0,bfb7b3f6,58fbd6fb,83d0070c,bb13e85e,17e1f793,8858748d,b65083e,9946ba84,3c842492,475e508d,4bf5bb08,6259e5cf,b47757fb), -S(518c6d50,6d72aaa0,ada7bceb,11e1bda,bc0cff3b,2008651,fc50eb54,cf4207fe,c0415146,d6bc2c5f,9f5bc476,a372c8cc,60778f04,b02d580e,64d37a9f,5380d3ab), -S(92931216,496359a8,4a9f2efe,f2032335,1588c283,3f9055d2,d107b81a,7a689f61,3070db07,ccce7e90,a9f20897,fa4c7e27,fb86bb5b,2b0a8a2b,a63e555f,1fade8b5), -S(e9ee9698,eb0f0b82,763be736,798cc34a,4d290a96,db7cf297,7d067d0a,3989d715,ae81b62a,52d7ef27,29fd82d0,1c0ad810,bdfdd46d,d8052126,52b76eea,ac196035), -S(8c8d5876,6f4419ad,5015839a,4c7fb487,dae2c7ae,990a889a,af2d6e88,81a3808a,e5c71696,20452ab,8e38e8ad,8bd8d5a7,e3d1107b,df7d8756,12bddf2b,7f83f05), -S(98f6e4b8,211c9a68,f912dd9b,784ede0a,314a9721,92dd0ea4,540a9e35,ee10b93d,14e8736,c7ea071,8d864e7b,1ba92a0a,101b333f,b33c0978,59151f8e,f39b4341), -S(f76805a3,925534d4,2188dc28,e47ebbf,18a783d1,71dd3b0a,88115ba3,3bde61c9,7a35dab,99b9991e,73e17ebb,47a231e1,66f8363,e27911ea,aa1968b1,c9babb58), -S(302be8a1,aaddbb7,8417d663,ade6d83,160b7107,87193f1e,46d1def6,b6e5a279,cc2a879b,6235c998,a97d50f9,c495dce2,d99448c9,6dc6075,d20746a9,d73943d6), -S(f53ed104,dc5d432e,61057264,4fdad4ee,57b0997,419c4df7,20206a2a,9e14f479,f05e2aaa,14bf3414,ccf324c3,1d8a91ec,eb3296e3,8e2efb1b,8d18ba9e,cee03ad1), -S(bef68e21,4972047,4ada606a,5b8615bb,812bacb3,f2214104,1ed69ab7,4ffc6389,5ddec4ee,3257d388,c1a3f5eb,39440748,480117e4,9787eadf,6d3daad5,7a30c95), -S(4ebeaac2,693c7ba8,bf0f03ba,1455dc46,bcc77b6b,d0a49e24,4a691880,ac38cb4c,f327fd30,55273e42,35f77b8,d081451c,60206100,15da9086,88e9cc82,6e547fa1), -S(51848db0,9cc33ab3,767adac0,11c1b94c,832b85ee,632d6f41,d65d098a,becbc89f,673a636,c3990364,af443053,77a5e59f,fb39049,e4ab37ae,53a1007f,8c064153), -S(bfd27c68,24c034c5,c153628b,ffdbc62f,afe32fc2,caa5d474,fd1a5b9c,d1cf8d5c,30928327,debc1be6,eb58b381,2132154d,5a7faaea,b3a5a522,8d1496f5,fbc4ccd0), -S(deed81fd,719445b7,37fd23b1,f2f98f8c,690ad80f,1c50c719,79d41526,34bd1af8,14ca4015,7c9371e5,8039b307,6ce0142e,79ae3ef9,5686882d,318a61e5,8afacc8c), -S(83e853f6,d88bbb57,f2e29871,7e3d3e0b,bc23f16b,d2ec5488,4cbcd3ed,de170518,14829326,aeca293f,10f54ac4,5110bd37,d6adc578,a8e6b22b,13698e55,70210479), -S(c2a957b3,3c8b0ef7,15b8ac0e,f8781632,63e90354,86e96e7,a398f59b,91e4292c,5cfba0bb,f943c955,54d31994,630f3ee3,599b7192,d869bcf,24c9839f,806c0bab), -S(2cb61575,18b65cec,dc17545,e8dacdb,28f81985,85fae30d,857d37cb,ab0c23a5,9bbc8c4a,5dae47e0,6ae03f04,bcee9600,2c17f719,fed38740,64734ce,3470a600), -S(7b1c1fd6,f4af2484,25cea23e,840ac8a2,ad8839ff,5c8c34af,9d1d72fd,30f80b23,6c51b243,7e523306,abd95216,70d6ced,235e0bfd,3b9e46e,b4e582cb,d1f1b76b), -S(f78fc2b1,6d61cbd3,4687e1a3,ce9e97f1,dae8a483,75b338c7,d595fd05,db40a4ef,dea54b8f,c9b55943,b2931963,a895bbc4,4453cb1c,d1530d41,19e506ee,b0702071), -S(1918eacc,3658dffc,ef195768,c1819559,8c550cc0,33333796,714c7eed,1ce780a2,c0a289a,22ae8b28,87658b8,41a98c47,71f317e8,cc972ad1,155fedb,da9f9fa9), -S(12905e26,7d6a0007,df0d059a,f285061e,d14f756a,27943f28,1cfbf93c,b343e7b,433b1923,cd4367,4b6b9495,42dd097e,7a025026,7dc060c3,ed3a1778,1441ac62), -S(969a637c,eb80c1af,b8cffe95,c6b6fab8,6329ba73,dc7e996d,a0617f90,48a39d37,6e751f3,b60c1ba7,57519dbf,fa7ac98e,6ed094bb,3bd9cb44,f65650fe,6e8b31d7), -S(5933a9a2,b818cf0f,d39633e1,9641697,410bef1f,127bc9be,cd183d1a,f85f44ab,b42ac6b,c2de2526,5e3c1584,31e92065,a97d6e5f,3602185b,1fbc1589,757c86e5), -S(54b58e7d,a63c1993,2a4c092b,c93e4d24,c8abac,76488fd1,9f56dae8,b943017a,ac117398,ad4ef6ce,d0166c50,69804db3,78bc9b84,a9f5f718,b0311beb,f08986fb), -S(77004384,69bbc239,8a70863c,1d7e31e3,b2f1dcff,64beb2a7,c0a083ae,8f4240f5,8a8649e3,7f3ad219,bb164490,529153a2,aab7185d,639040c7,1b5ad628,d3ee107a), -S(768e2c77,32678997,42c6badb,4d87ec8e,34af657a,4f1d6376,d01b456,7f0f9828,56078dbf,1128686a,1a1435a6,3dfb39c8,91c270a,2b230754,4409e9b2,1f2c7a03), -S(b66b24b8,5248a97,a913e1da,6d0d1454,53e0fc61,66ecc62e,2bd39ba0,c3639f27,3037bbb8,e205213a,4bb524dd,49c667f0,408b69f5,428e4caf,1ec811e3,cf5c68b6), -S(1ffc3c5a,d8e38090,ac36e8a7,c44c6ca4,c0a227cd,1192bbac,2804d033,c50534e,f2d8a481,63ab76fc,391ed0ea,de7b02e8,1580058c,8b84886f,f6d7032d,b95b503c), -S(94b3d61,4d0a5e2,9e7e9ee7,1e2ee7ec,87b14085,cf6f9fea,2ed31d31,517511c5,33c88c8b,8204f465,93acdf8b,a837d4d,5a388670,fb24a861,dd4f35b6,b674ed4c), -S(3a94b6b9,b1b8a82a,267f7ac5,9b52bb7c,52b790fd,ee341265,ee1b6e34,e3e7387d,4db0480d,d2b8f2c7,2c60c55c,5e050e2d,f86bbe1c,98b74bc7,f1d3a44c,3b1df370), -S(2b53bbf,2bb1cdf8,44b25bf3,d1931ede,9e5e1450,78dbaf68,7f4e7852,6a6716f7,70be0ac3,170f7490,cabea8a,63a6fd66,3f1ce8fa,efc5343,566f4b1e,2ca08e6), -S(e5183136,cfc8b732,3f926cd7,95dd8766,25a8c155,d5c8c457,53777c9,beb13494,93c62979,e67f9f86,cc0ec570,273f2c7a,876fcb5b,f88022bc,a8666e1,814207ad), -S(c4c07268,a805e384,db81b877,9d1dde0b,9af6e197,b6bf254,db6aec02,94dc5bc7,2127f162,e2cee5dd,96055ff4,a7bcdb57,19a00742,f295007a,b839eb54,eb317566), -S(2a89c94a,8dee1950,3bc5e772,b2ff9608,a57c4ff0,dc6f7c0b,c1d2b76c,26c9610f,10da34f9,eb14e294,8f2a06cd,dc211eed,93c670ea,47592135,dc33faac,bbf8a170), -S(35b035e9,8cc6f96e,d7dc957e,e07c7afb,fc936653,72561568,25e44f5d,fe4ea0e6,4818477d,aeed402c,870fc50,6197a0f1,5c72a378,e42785e6,be38bb21,6d4ce91), -S(f0a3e92d,647c07e5,5a435907,34c0ee65,758e09aa,bc2a81c9,f6d6926,c03a9cd3,18e7a09d,720e65f0,b1b8fdad,66d4322b,99733bfd,f8c5fba5,afa930dd,f441f095), -S(4db3c367,f3ba6727,fa274289,675d2fbd,1ec7ca8a,94d97bd0,46815f04,368407fb,d5e0dc2d,80f3893e,f1871740,dfff1589,ff75940,e163f8eb,115e4b17,dc1cf693), -S(9a0fa624,b0eb8dd2,f50ab259,cdd9b17f,7a6f318,93786640,56a49867,89a5d27,68e82527,18684672,ed4df389,98b830ea,1547ff45,f48cff63,5d291bcb,e80f3cd5), -S(19f72db8,e604db7c,ef2e8478,c04540cd,c3806c1e,eb9e8071,38f0a272,275d451f,3cc5df1b,dd845f6d,a4747261,f8e1f821,c7e6f2d9,d9cf9a90,d3c7edcd,b6fb940d), -S(306fc07b,7e543dac,ac240f8e,7ac82cb3,df70a2ac,1bdebc61,adc65fb3,e696743,f27b90e5,a2a5abf8,19c90983,51521f03,26532b1d,37875466,f87289f7,244a3919), -S(c46e7e67,a036ae7c,b30ae479,d0f87d7e,6cc8297a,3bd4c1ed,c2436e6,b52f532b,723dc476,426eea8d,2179eb11,35599275,2cc391fd,4c25ffb9,a3942356,a56899a8), -S(a950852b,587a01aa,7a1d4688,8ded73c9,cbadc922,e44fce64,61a5aa5e,dde2366e,79a12ef4,18763f51,62ccc65d,86c94012,363cc21a,61d12982,ebcf2ac2,c6337791), -S(8cad422a,4ea9d987,48703d5e,eb95d48f,1f73d893,91c7c239,f96a7155,98bfd153,111116da,fcc7a212,a1e6e0ee,4e824611,a3896543,aee02f46,61bd5ace,2a67c652), -S(3b922988,8c2bd057,785b4013,fd14446b,7261928b,a8907ff0,da433d2e,61302362,4eb99bb4,d152e218,8cf3464a,68fa266,500dec96,5842c2e3,a3dc16d,e6edd74a), -S(36129c09,42906435,56970a6f,ccab5f71,113b82b5,819ed4f8,451ff01d,209a9cc0,b30ebe06,b9b4a4cf,8451d8bd,7d9534de,375a396e,b2d7bc21,67a56f42,6426d3f5), -S(8a0a960a,e3bf57b2,ae76893a,b665856c,e09a6f0e,2748c703,2d951cbb,6ba038ad,e29f3916,4928405d,84dee9fe,973f613a,3c5e1c97,c6e5e814,a927a6ce,60efc2bb), -S(641f4fe,dc351cb1,93a088c6,b6ad8867,442cb913,7f0ded13,4ef0f2c8,d721b887,600a51b0,f80a351b,ce7965e1,eec4c8ea,9feee470,80b920f5,67e4c979,84b48dcc), -S(cca5d72b,8d78990b,267cf3eb,246545e4,d416eac1,600078,2861bf05,c0132b3d,7ea6d271,f01c4250,d07e782c,32f0d6e7,177d7714,e2277282,4968092c,e0444f42), -S(c6ca654b,fe45c9b9,1f3869de,2f96f27e,351a7f1b,4839f7a0,9db2966c,f81f052c,894661b7,2d156df4,2b307506,d990ec47,935b0605,9aa97bd4,26b0df6a,9e3d2183), -S(2a959d49,c5161f7,6ce10ee9,cee3047a,be9c620,569a702a,9827dc66,84f6f35e,918b7a8e,e283539f,cb52fe91,1f5039c2,321a6e8,be0c4449,66bcd7f4,594d1e8b), -S(bfa77e7e,3dd28fd8,a04842e6,6f01a9ad,476ff448,18e4a3ed,ab2a8b6,9ba42ad8,d85cdccd,2f5bbba4,1718b70b,c10cfab7,272377e2,5a578ee9,be991b4d,583cd62d), -S(6cb9b861,de296ad6,363da904,46618eae,fa852ee5,ec1df0a,d0a6955f,7b9c6d97,978d0afc,29cb0cdf,f2ac432d,cde6af4,1aa6bb4e,219a0687,11924142,deae9f1f), -S(83446c25,f0496ada,69354c67,8a1ae34f,154afba8,318be7e4,ec52e5cc,ce9dd139,7d4c3e81,98a8905b,63572a16,5fb7701c,c8f0c53,3a01f47b,532eeced,39cbd620), -S(590279e9,f8a2ccd1,c62b85a9,87b528ea,d746a42a,fa07b358,3c5d6349,ef678b13,75627950,5089c0de,33822465,14565c8a,cd131b14,949626af,15c56e47,bdda7f1f), -S(311d1ac6,4b7b1a8d,7c6ba19a,ee5869b2,2d769098,a6e4ef1e,3837082f,ebab23c2,c0b9714a,e1627902,45649db8,b7eda70e,25cc9905,57397adf,39c2c1ba,bcefc497), -S(f63f9d45,10f232ec,5c1f3831,6e16594e,a82d133d,6dd4c365,1da3f34c,c8197be5,ecbd7232,4e732295,750d8c5c,b0290d04,9c778707,4cab27ab,35aeb978,3c743a7c), -S(b772d2eb,c76f6f99,7722aea0,fb55cd6b,592fc0f,c8b87511,d85226b1,845a517f,6b4b0363,7186cb53,ef0d2dbe,3ec16efb,df0b5de8,dabd4d9e,871f7174,94f80538), -S(4dbc968e,8697c131,7d9bc180,f98a1320,bf69fedd,24d71b35,c1e87c95,13420335,f6ea65ec,44c5e25a,549dad16,ff129abc,153393e0,e76b20e5,c1b1ebc8,9ec169bd), -S(2acfa0fc,a5377dfc,21519105,a5f434f0,914fc259,95bb811f,1d17dea3,2345bac1,682e091a,47b18d6e,7595bd46,28130bf7,faef8df7,e8224e02,3d87ee03,b3be8ff8), -S(d77801d0,eac64c02,cbcb795b,f030ef,37a131ca,f07ef6da,2f3ed0c9,f7c8922,166fed02,aeb1395f,bca109e8,5d599f9a,df684cec,418c7576,a4e67e3e,e1abd7ae), -S(92006fab,e11362be,2c89d0bf,e1250e9d,3c5282ea,38be9206,f35cf913,496c9481,2a5b39bb,755a809c,f76ef97b,7e59f00b,70c94a4a,9dda4bf5,523e3cc7,2ac83832), -S(43af4cc0,66155b9c,fd9decf5,e95ecc50,3c69e99b,b5dde00d,bc859732,f4f7d79,7415eb35,75c9e0e0,c237dfbb,af245290,11f5ae9d,63ced644,f8c5af7a,c3e59c48), -S(c018d581,152fb656,c43eabf5,f4e7aa9,c8c5f722,f5352fc,3dda72d5,dacbf451,f9bc1975,acd5aa76,f2744c85,22a07211,daef05ca,8ab0c200,6196acd8,29fcc9aa), -S(968bba6e,77c83e6f,be7272e4,f6288349,329058e9,c3b197e6,f9b56dbb,8587f2ce,3a841d0d,1066ee35,4fe70855,3bf034ea,4da917ee,87d27a0c,f60f8e99,ca45e065), -S(6481bb71,dce335a6,98972f0a,bef2b4eb,5302893d,175e1f53,9a93dec7,53d8e4eb,94073fa3,98393d5b,ab446695,889f9805,6fd31d8b,c14b5ef8,8669736a,5586d3bc), -S(22d38699,cdd4d0a9,ff6bf179,d611b831,647bbf23,5da1fb6e,ec063070,d5420cde,fd4c6d72,ffcaf8fe,3410a0dd,27497df8,98e02920,272a4daf,8967d547,4fd2cef5), -S(acaf068f,34b0fdc4,b86f606,1f96d172,69f63e48,c739f1e3,46cba1f6,9e4c6164,6f9cae55,559fad61,e20bde43,ae671832,85e83ad7,429f031a,b365cc40,349ee3d6), -S(1d2f237,b91c5642,d3dc3c47,9db9716f,47bb34e5,2bdfb7b4,1640e517,f83778bd,9036f65c,eb367bd7,9018993a,9e01b350,fc903bb0,ada247b3,26761011,bd70e0f9), -S(42bf9891,9c347e33,65990f49,6cb09a3c,654b7a09,29cc483,e9028191,4797b6ee,56ed030d,f2fd51e9,98c63f3c,338892b3,49b2c30e,9ac6b3a9,a0f1c18,16b5bada), -S(b48f90cf,18157b0,de5721e5,c0b1986b,1c16f2cf,1b973578,d8b3a41d,6d18f774,40c392a9,c94e2ef,aa5aa88d,36eddf6d,d01a1e37,60d8e391,4ff19646,94557641), -S(8ec7123e,551695cf,c1668bce,86377900,f79e7311,85c5e39b,9d24bbf2,e6409313,f2f58364,339fd734,910c9b65,be0574c9,2bb9efec,ecde3b50,67850d71,d98adbff), -S(7dd11415,1359f2ae,81d4b18e,5afc6657,788d2bae,5c76728c,d1d25265,a2dc2801,32f37924,4f7389d7,7f23333e,4c4920a5,5658254f,dd7febb1,2c3d9d9b,ba631c09), -S(33556f01,4bd89b67,52e7e1ca,1d5fc7ba,faf6e25b,8a49f57e,51c293e8,6cfc4a8f,5c8467cc,3553a8fa,1e322b04,83a0e3b,fee08772,69582178,668c51ad,f3661454), -S(f92da876,e7df1d95,cc2f820b,47921a26,413cb84d,ea6e05d1,da3c70c0,6f5151aa,907d6a04,dae7f625,409e9d3a,8a92f636,f5496ea6,c15825a0,c9d6d6ad,54068a45), -S(77810caa,1e90962e,31ca5e91,2c310bde,cd010016,1f124b73,81492437,5d24f5e0,205b009e,d933e873,a2e12c0,5ced5536,c9b8918,2776bcbe,b297a955,bbc892be), -S(5740459c,5ba49bee,db0fbd8b,5a5dd0a5,24d47dad,ccdbb28,567ce303,58e70b22,7092b9d5,a3c96984,da084d42,f2bc5f1e,a51cb1e4,b8508c18,6ec7066a,74141f68), -S(b7cea84f,84d3af1a,797d90b1,f7a460d8,de9f4a6a,2f2887ab,8f464123,bf844cf1,22f82480,7b05e21,4b885ffa,e8576fa4,c44a3824,5e256d55,cbb1a5ee,343f577a), -S(5180dbdf,73208c2c,b5e605f0,9f6403d9,ea5bc592,29007598,bad6a913,a80f5493,247992bd,bd823a2e,6ee55330,57d78d36,913654d,c3e089b3,fc042fec,15ee0262), -S(ac413c18,ff3bb767,9070b698,e2108268,9bc59a13,1f011baa,59799d9a,daf43cbc,c2dc42e9,78569e63,ab08b155,1e4c52d6,9f770211,86803f60,dc752573,d536af5a), -S(f7a5bdb,71b339c8,19ddddf6,10ff7be4,6af7dc87,6466473f,a01f314e,67bc52e6,6b572fee,bdeb8cb2,9b72dc1d,5df185b6,c50f5ed2,5e95a61,c1dd4822,72ca2adb), -S(6980f38e,6b164eeb,8eeca173,15c6874e,c35bf6ce,78779e4f,19327df2,b1f57dfe,e19f87b4,4e72b29d,c55a47d8,2b5d9621,f15d51fc,deac84b7,87ac2ddc,40af3935), -S(98adb6fc,879900e8,2ede0825,32da151f,b7a16a5b,8d2b9eb2,4e8dadb3,46ac67d5,a7349dcf,c4786a3c,2686fee6,c8d43a37,b91c1b82,886f853b,fcb6831e,c8404262), -S(c46cfd35,101d86ed,965d16b8,55992ca0,932822a,550a71f,54543922,54b00e36,72c03b83,34d944f5,9c4f553f,c25ff5c7,d887d5dc,4e82f90f,cdce7e41,52977e32), -S(71caf0c8,2402b643,ff0b26f5,7060658f,d29294bb,7695524e,99692495,b69584ad,b11c3736,436c04dc,3f4503e0,27ab7a76,2ccb1bb9,74922f92,8fd63012,e174fa68), -S(cf46226b,243fd1b7,984a38cb,f27a7fd7,e7a35a9a,e972b0cd,4b438c86,c6df89a8,f40d1f01,ed7ca764,11a3e0ff,55d702d6,19a68ff,88d4df9b,3f7d9c3d,b96738fc), -S(d8f271a,a092d515,176b611,25abe9d1,85a15d55,b486818d,b571a5c6,4c51b493,3878f749,5d4d9981,5ba550ef,3dabec35,fba40c5e,d10c4b54,fcf63b23,24b91e97), -S(6d60b710,8fb40460,f893c53a,34c12054,6a02c037,821f2a31,55976104,11657d48,a03c71bb,788b915d,9ac25950,30d8c31,65c0c1c9,ed2abde8,96d3c985,3f14bdd9), -S(924f3ddc,7d5d3764,66b47124,b75361db,8afc0eae,7848e860,debefb75,452ef586,c594e3d2,15f58f5a,255958b1,4936df62,3b68a854,4fba7aeb,58a54905,b19c5f25), -S(a668983,5487c800,a1c34b9e,ce7b2347,1e4f5f5b,3be7b591,3390ebcf,2928308e,626c8044,942f74f7,8d255207,5f9d18ed,8982a341,583f1314,4f53dbba,40c94c0f), -S(7fbd491f,ec466132,c2838c46,a5d6ee7b,9dc0318e,3b3bd3ef,88d3cef0,6465cfed,6cceabee,fa659f6a,c083355f,b14cae2c,53657f1a,3c536b4,193312d4,d4a28e36), -S(85122c42,ebe8457f,be82707,e49e0b1c,be3995a1,2998ccd1,629b84ee,935efa56,1cfe76e1,922e4cbb,1023dd88,2bc03dbe,c0be2cce,9fde0797,92adb2cc,925dad51), -S(3ac4d527,3be6b39e,d6326132,fc212640,450791cc,9eb43b39,a77c750d,8acad644,f1d8d690,c1011f,46f003ed,6f9a3342,ca0e918f,4096fcfd,406644a6,2cca296b), -S(838144ae,70bbc188,a05f03bd,9123b93f,e4bf4485,8e380e2d,5d6723e5,fe955cf3,9d8aa248,2bebcfbc,cbcdf87f,c2342618,74e99bb0,507f472c,e86a1b5c,59307a64), -S(4551b877,fa1d9811,e9fb6afc,acfd873f,7507103f,58ccf82,feeab7af,8e893ee4,ba0da9c1,1fb2719f,9a81e745,fe4ac1a0,221b01dc,7e3eab5f,9552027c,87b2fb30), -S(baebea51,e0fdc8f4,cb3bb20b,cb3f4bf2,b37ce31,121d6b5a,7a3313fd,29fffa44,41a4785,df2c9ad2,99b0d0a4,2032b8d9,2f56835a,7bad7ac3,68370046,52c66446), -S(8c03e4da,5be53c8c,6c6c1dd7,ced8fe99,b88de276,73ec3ee4,f5152a70,d0bbac1b,bef7a8d7,df0651ea,1d328729,b0f85ef6,a22b3d66,64ff04b5,fa1c9dda,2073d25e), -S(8d23846c,34ff8756,bd30eed3,1befcd53,4b171dc7,da0715d6,df3104ac,23104ef9,49ae984b,be3cb83,1c2a18d0,f527df0d,27eae720,922f34a,b270888d,9361b708), -S(362c58de,902d1c62,19da8e4,e8ff33f1,61d7c001,202cb2e0,add6bc30,dedba48c,235a0ee0,909dd6da,d1d8a8b,f5f1720b,d6d7e38a,b2b5bab6,788f1983,a5de3137), -S(f836b56e,2892fe8a,a88aa77b,e345c48a,572d0cc4,87d75ddd,99e3e471,bd0461ad,c4254af,e34e6705,12d3652a,38801946,92a7b170,be6fc60f,555c3835,84ca0611), -S(75374bdc,ddbdd08,2e408d8,4fae0652,bc6d1e48,89a7f0,bd1d2257,d75d4f4f,8b77030b,4ee786c4,2973b7a3,905d207e,46448c36,c7d7db5b,280f5936,eed70ee8), -S(ec299deb,26cfa600,a6385db,f04c5b0d,128231af,6453fe62,29bf32f0,71bd1733,be200050,afb2e277,5f4b5688,8ceb6af9,50f901bb,b9a7dc2c,34f9df46,297cda1c), -S(c2ec7bab,4350cb7a,d45f3c55,701203ad,bc00f9e3,17c2465e,efae7069,fed17a1f,33b1bd74,3375dfd8,f4c69ded,f7232449,4c376132,5afc8e6e,a6b67aaf,b4570355), -S(62a96481,d4d9b559,e9ccd855,2d6307b4,8a5d03bb,7a9e7ec3,de8d193,c33ab2dd,c14bf21f,58c2f112,f399e6e,ada45660,6c80fcb,debd967b,e3e3af90,caa3d1a), -S(6da7531,4b8bf8d7,7d72a367,63696a33,4bf5dd8b,f192e2b2,aa646277,f0d6ee3b,70da7974,1576f5ab,da432280,f269ad51,5369a399,5a7de050,ac7eff5,8b7f96c8), -S(af59c78a,126296c5,f19dba32,b9e414de,dd2f1c34,6d6900d7,3ea52e56,5e9cbdea,35b963b1,94d1071d,7769e4a4,3fee70fe,4a63a0c3,bffa2c12,88ca2a82,a7c38bf8), -S(a86e3627,551f2831,b88021d7,d8cff6cf,50fc07b8,5fbb0889,bab026b6,6fec63be,dd205467,4213f012,d45022fc,75de7c2e,b3c71348,efd536fb,1e5f875e,1ae55c63), -S(2c59179e,d9c22abf,b8856e9b,311abbb9,7ec61cc,7ab145cf,5cac94fa,77d65004,e94a1b85,fc8c3c8,aa86338d,819f7139,96a5b72d,68952a6e,8ae48c47,aef247a9), -S(f406f78c,7be2e678,d8315272,e7d861f5,250a4bf7,354da2f2,dacfa22c,d56e43fc,fe719c86,4d66efb5,16a49af4,a86bf463,6130891c,7fc7da01,4394a319,d66b0493), -S(c89f1828,1d899423,83dc622b,7e6017f4,cc02b55c,5c48c824,5568aa3a,c3c25566,40a58eff,8043e3f5,753f9f54,31f170fc,795ade25,d6200e0e,bed182a7,8012de93), -S(36179740,ea6dd2d2,d2a537a1,c9aebd8f,c9a570cd,6fc25453,1d58866c,83ee051b,80643869,fe206f68,4824330c,18073366,9b2b7e97,51f1282e,3c52fbf9,f4899a90), -S(ab5d8e67,7fc654cb,88458b7c,e43b830d,74b441da,9a1af152,9147dceb,13bb2907,b2ecd95b,bc828f3f,53af76a,b5d60dfe,aa681270,74d8ca61,2558c778,ced8aae6), -S(b1e79103,da12fe0b,51259b9f,3c4b74da,1d8075ac,e1aa912d,ed6da9e8,2bb14706,b726371e,7c872caf,42c049d2,96f998a7,c928d991,535550d,a13af044,bc61a1c3), -S(9792e304,67ce4e2d,77f288fc,34c6b2fd,dde99e31,4f0137b1,f2da1d7c,603f5754,d880bcd2,6a74445d,4ad0bd78,2963cd03,9ba288b3,44711889,2ff00de9,4e966be1), -S(d8180648,f046c427,db5a9912,6d54a1c2,915ffb17,c686704d,38fbe1fd,d60cf774,c4767b5a,fb34dd33,e5de912d,b0619e5,c39fdb89,2c131bf4,97cceaf2,aab6f2af), -S(9aeac423,159b5746,565a65e4,c00c12ad,537385ed,9fcf267a,802e2290,ec19633e,7990008b,db7ff6c6,cf110dfa,96249b74,c5173d7a,f7489d4d,86424749,5ea3c63e), -S(2aaeff31,78bfd5ce,b9aa4af4,71555de6,7b1c2bb6,61bd9aa,8591f15e,8148e97,629620c5,8542d054,86245859,e608b5e4,55c45fdc,32177c19,34eb9b6c,23554f89), -S(bd0451c9,211fbabf,21a6b969,29edcd7c,43f10d34,219c6d16,1c5910d4,ae8b5928,23d4a749,b11a1fad,68a8e65e,5c940315,ff326947,868dd92d,9f6f9221,44a4a642), -S(205c5f6b,88865d9b,b53cf8e9,7e97d781,8e038c60,b8177ffa,9501590,96ce5592,b8848543,287401c7,7229f94c,840e36c2,bb93acb4,eecf9ab1,5bba1b49,97d3745a), -S(a3d24c8,f351ce59,6f2da6c2,def943f9,6ff13d0a,c7efb29d,ca3c39d6,5281b96a,28d5fdb1,a8c1934b,a98508bd,8b17168a,a78cf549,1b3b3636,8164e95f,17e8bef3), -S(468f528e,8f2b12c8,4b90df66,8c401f4e,634b2b9,421d1a1c,1079578e,2739160e,3070d8d1,9cee21ba,510b72dc,b17b7e72,7c0adc0a,baf58150,a24fb409,9f203f03), -S(6a106a2,ad8bf04f,a0ea0c66,179b3a4d,df0eace4,954a40c5,ad3d611a,ff7965d,fe893d8b,20f94be4,ed7b20bb,4feca170,75d2e5c3,61cbf44b,387947b3,8d996a91), -S(e59d055,1f1f0a40,6e94a2ad,c92b1e5e,54b74ffd,8d0af6ba,ad25de6b,97a470a8,b0693f96,9257ca3a,da93a54e,f3c29a62,20cf4c33,a9cc6915,f51e4d50,8ceb7efb), -S(ee7f4a6a,6e37fbfa,f7db77ef,ae9e8745,c5ae64be,338a6b52,e5138ac7,860340dc,c92c0a11,17b2bdc3,d043f6e5,b90f3cbe,412a9a61,79ae3f00,7c397589,69eb1616), -S(d42377d8,5dabf33c,99268106,f86e7939,c87ed35e,affacd68,d211b4ab,70ec2c05,ef130233,589a5fc6,5a23a029,e1857b86,d6cb276a,8f37bb8c,996dce4b,e72bded4), -S(e21015b4,d76f0245,8dffad7d,f67151f0,ff4c4d1b,ad5e13f4,a6e197c7,2e4c31c8,b78e9d47,31a4c0c,3e29e9dd,2173ab2,16a5b8ec,522604ad,43111600,bc3e1733), -S(53c5434,9f0270dd,4c76d116,eb2df817,b66b504,87367767,d4a796b9,e4516f2c,5a4b7adb,66ace9af,59d1286e,3d89b2f,de525b27,6c27c1d2,1d7a38b6,b1b9f1d5), -S(df9917f7,6cf50cd7,2b8b06cc,cba9a47,b7e0f64b,481adcda,a6942a96,2319e81e,171d72e6,cad16682,bea2a90d,72b0aa4d,899e1627,18b96109,4a501515,2b754453), -S(79eccd0e,f2d48da,3ccdf12,91269dc8,21453173,7991bd38,ec3ebb33,56a594df,72371a43,74284937,aa92,6eb5e8c0,6911bf1d,4efb097a,8d78f46,da1a87b7), -S(3a472336,4c182521,81f90fb,66d768c6,a1a46cd,85c86108,3a09696e,922dcb44,bcaefa87,7b8d963f,d6e535f2,db3d189e,4fdd8626,94b0b60f,136b25f8,14e3154d), -S(edc9be56,27acba38,178b0c6f,cb7ce6e1,f6ecada7,a592d6e3,e859a16b,459c6d7d,bee091af,de809fc6,9b819ff7,1691f13f,321dd702,3944432b,a278df70,4ea02eef), -S(9adb48f1,439c1850,1895ae30,649992af,3ce3d085,13c6a92f,5226f3c9,ec09e5ef,3dd78cea,3a3169dd,78afb39c,ff690eba,e9cd5f3c,42d7c583,ef093a57,635a1df6), -S(942953c3,b620e636,63f2bb83,6c2c3a9f,6cf4a931,2587f57d,9489ffb2,38895bf9,415c121,6ed101f2,698cc0f0,9c3ec0a0,c0e8458a,3aaf5879,87ff1b0,89992932), -S(92c539de,88e6d094,e64c4b25,51da4149,19677124,d8d1e53b,4d0a81a8,53501619,c9b5c7e2,dc61d875,4f33243,de28ed78,adea8e56,e193ab0c,d1f5464b,e9003a45), -S(29d33ba1,e9972c80,2f135a4e,add34b21,408be4ee,29d7be7f,c7f8ade,3ed07cfb,847cda60,a3e6627e,5abffd6d,b56502b5,f26df3c4,630f4f76,aa868899,63566e7a), -S(727abd10,6aeb6f80,f1dd6319,4bd4abb2,2db5d8cd,e7676273,cb0b4246,17983d2b,476962db,5de3493c,58dcfa1d,fd206a44,11f590a8,2c7aa7cf,3fb377d8,623c9639), -S(d898349d,89eb2d49,f2865e19,88c3b5e9,f43ba281,6a0ae0d5,b031e186,b23fdfa7,4d3083bd,681a3a1b,988d3bfd,70fd6b13,3a1d2264,feadd852,b2298450,f729c471), -S(88526dd8,a52010d0,fdcd0223,7db54b43,f73b7195,cb3b2081,96257c7e,ced4649,686926f8,6457861b,4eec6999,626115b7,f9e29e0d,74e44027,5df2f583,7b75699c), -S(6b64ec54,3e5c83d0,b36711ec,b0a4b8a9,25fce55e,4923fcd8,6dcb48f5,43bcc107,8a7d84ca,e8431663,3d635a78,9598a22a,532465e6,f86e6eff,108449d,a5b0ddd4), -S(9017d917,e7e80f70,e5fad8f0,3cf0bcf3,b20bd8f7,95c4728d,e259bf0c,933088c0,e2a9c53d,e1278404,60828e57,eb5de14b,eea14cb3,41bd4d6e,4b960ae2,807299b2), -S(2f7b4a5,591268c6,eaf64c76,5a8321dd,2485ee36,bb1b338c,b1473535,658c376d,8f2cce5e,42869466,a3658460,c0ecbb46,5d850b26,85642b52,e01f3b08,544fb94e), -S(316bc4ba,1dec120a,7a10ef1a,aaf40d63,9f404948,ba27f46c,58763508,4809c78,3522dbc9,f861c154,771952da,7dc04ef,5b5100f2,b4355177,b62ace04,a717d056), -S(69c07c8e,2c1facc,7ac6e08d,3b74f1df,cc24751c,ada31142,72d2e313,78d76683,474693bd,649a0877,a3eba75c,910ba3fb,bf8aab97,5fcae30f,cf47a51f,e9a59f24), -S(154e4dbf,787e808d,c19031a2,df25536e,4bc6a71,b03d8f77,5c652812,75a84a30,e79e1a4e,2440cea0,c6c63098,ecfbc52,f5cbec08,39589beb,251af76a,50eac221), -S(61c158a6,b963f853,66598998,908f85f9,bda6ad6c,827702ba,f81922ed,2b675b4e,d63cadd2,c63ef3af,7c8e9695,4ebb28ec,48dd2c86,a69505be,d06ab3ab,c4bb4fed), -S(97dd50fa,eda2da43,aedfcde3,9d55b52,de43af06,13435b7c,6744dcba,81cb9b3f,e99138b,1c86d820,70ff2e82,413b19ae,d83eb23d,636c4380,70116490,bebad75e), -S(b2a43ae1,947e0e8c,e2009813,eae3e500,ce67b1c2,cc19701f,5b6cced2,e775cd57,291593c1,dee03645,4d0b8be2,642cafbb,cb3b7fb,a045e402,2006c702,3532167e), -S(20580468,68663d06,568988f6,17442d5a,6a65762f,cdbe91ab,128ef99,990d722d,ea32d66d,56f1fc93,fd559c0c,e8b200e8,e423d097,26e564f8,8f53b3c5,e8dda8d4), -S(c2b98b13,bbf661c8,f4cae855,158f095a,9b62947,134c5da0,9dd2d377,959ffdba,3d6386f6,915a7e26,c63ee1ee,6970928a,6f0e4e29,cd3ad665,fa4164a5,a8b2cd7c), -S(fc6c98af,7fbf38e,53690a78,34d82a56,170a18f7,a4e702ec,6e918510,2700611d,9ccd38cc,f8aa409c,1a9e0b14,d01bc9ca,69b5ed4d,7f92a177,e42930a0,222cc755), -S(21157d1e,1bca5a3f,2dd0153d,b9af3079,e1e531dc,9eafb9fb,5042af2a,e67d7000,254860bc,97cecac,b4cba1db,79b13fc2,199f037c,aa963d4c,bfa2b9d5,70456cd), -S(316ea33d,dd576b35,e45fc5ea,5e384070,68ca63ed,1149807,68a7c6a0,d6c628f1,dc236dc6,d0ab4c12,63124830,633729a6,9b20a22d,7d395af0,38d6bdc4,34983baf), -S(21b825c5,44a41bc1,9f048a0c,9a532a6c,18df41e3,e7cbf6db,97c871d4,a3cd0039,9d85ccda,c67a4a39,ba10128b,382925d8,6cebbc0d,70354ffe,aaf89ae9,1fec461f), -S(65a4b32c,e116790e,f671e6ef,8ad317fb,efb815bd,fcc1708f,32c0c078,2ed41140,634c9efc,6470a929,8844f082,5a9d34c3,ab14778,7969f095,a1b45f1d,dec806bb), -S(cbdce03,45e01ae7,77ebf819,41123ae8,b4683169,246c5156,6afd6a54,e9eb6844,5414d24f,ecd1a159,70882003,3726c1dd,ad939df2,9a12dee3,224fb9f0,a89f03f2), -S(9c4d4ee8,3a36544,ab38334a,46586864,bc7c301f,710d67fd,226d6e59,a6532374,868f765d,3dd5823e,7e2e6791,21bcd41e,9b89df55,27e191ad,c5016463,ac7c7991), -S(4c890df9,dee96da9,7ad0b768,16a50240,2c9fad7d,5ea13a04,3eebae41,678214f,397de76a,319e758c,199e2343,6990a34e,79b968f9,1139324b,66e5f7f0,114cc9b5), -S(c7f4c3e3,f7ccd93e,2449c653,393ff2f9,c8d362aa,3dd01128,9879c983,f9b49229,d2ef30d0,68321b54,91519698,79d8dafb,8d2c5ad0,9117687e,10c5a57e,ae4df846), -S(e8c810ee,daa58b8e,687fa493,6d833930,e7de9bda,f73f11ca,23734756,d4d05af4,2690ab19,e6c9df94,349600a9,269c76aa,633c4dbc,abf24604,3cebdc83,1e117d03), -S(a3f51d28,ad743812,3cf9a169,d6581d9a,3d41a131,a8109eb9,a38bb3ad,9f66187f,3f87496d,d5f9ec37,2e3d0e79,7c12e7e1,c328658f,49cbf237,a4e36415,76b89e75), -S(ee0baf50,f62282d6,b560d1ff,c18196a1,a038b27,f081da32,1d82f3f1,82c27b17,4e4dee4b,182056b3,dc809d4d,2160a5a2,b6dc8ef0,e933e45b,5bd1375b,c677321b), -S(346b4fc7,535f3a2e,79330614,e0618d0f,c2a44ffe,a684076c,704764b4,8ab3d95a,98a41f22,cbe44fe5,37116f8b,9ee68e3b,48ed63d8,33cb9567,278c520a,e400bbd2), -S(55fc8976,b796bf67,9de4b2bb,aea29d6a,e3cd032f,7611e59d,75b8ffbc,55c32b79,2e5d3a9d,f8b32c5d,bde33229,f2e9c852,702dbd58,31bb1917,2e47685,c395ad1f), -S(4ebe6051,7453c3a8,a7b65c1f,fa7d0b89,c4cd4166,f2b8c670,3a71484a,f62dc563,6fbc68f5,a7b3431a,1dd6ff18,b7f1676e,a42ca708,f56e50b9,8700ed3a,560b3850), -S(14bcdbcd,73f2896,c8b37bc7,e06c195d,17349c69,9be4ce19,3fe4e145,a79e20eb,2bacba55,a4611886,7e3c11c4,4f14bfa4,d5c702ab,b2385584,e07d7b08,42a8ec61)}, -{S(c8116b60,1f8d72c6,24957215,46b844f6,bf6bae0b,7575a77,f1f6c6c2,5524fa2b,b7477ca6,de2004df,34882c65,3a46821b,53372f13,ed822cbf,40c20bd9,ddd1d6bd), -S(f59c22fd,8c5a2e,c990f3a5,e6adcd12,f7cdc433,88ddc16c,aa41b9b2,2fd8dddd,8f63f807,eb1b96ae,ec9a49db,818e1228,b9d9da5e,5b1603b8,f5c65900,782a6c53), -S(effdde86,efffab86,6d1da179,211a52e9,b3ce9fcf,c5c3282a,1a87cbf0,aecc882b,57f4a91b,b88d9746,1d1ea75d,4eb2501,46899ac2,ca707ae7,88f35b3e,9f6f8e36), -S(6a4d17f7,3eb94a48,a369cc8c,4c827003,8967190,3d6ac75c,cac7516c,e78a8da8,51f297a9,23bc21f2,ea576db0,15b49d80,27fb1ea7,597179d6,fc47d749,5621d8d), -S(7af337ee,d52f0c7d,ffd0628f,7866d621,dc867661,7dade077,2655f1e,3c331d6b,9b202463,320d18f9,2db990ec,e41aae7b,112d6390,33418eab,7f86c874,a040e2c), -S(4a9b0428,2687d362,66d8f33,8cbc38f9,8d6e6f8b,bd5dce2,b911d192,2e70a583,c2646913,7c7023ff,abadbcab,4da4b90e,8ea8736a,fecb569e,dd822733,8422d74a), -S(53a776a9,e10f53a8,454795db,bb340cd3,fd0ec50b,51a164bd,549ac834,ede835cf,1b976c44,de266928,49631bc2,950b4d24,f11fce3e,a728674c,8713d3e,35f8c0cd), -S(48ed6e74,c75c7733,1aaef9cf,ce06038b,bb405ffc,160c5711,b98ad6e3,44baf62f,fa56b3e6,b826b847,667ab6c0,ade30415,39d67509,61c0c199,14715bb1,bfb218e9), -S(65db9062,2328f7cb,e9afb758,294e0d63,d0042b6f,7615225,ffbd341b,16c5acd6,1ff10083,e9f66f89,bec1330,dc309813,2d434191,2eaff4ca,b3c20177,7001096b), -S(be836639,aa622020,9ae01ae1,f96f9256,9ab7aca1,2f5a7277,903dd653,18f9dcb8,293ab5e3,c50f117c,71dae650,b16fe28e,bc14eff8,38fac552,6adb3393,e177ffe), -S(5ceb4539,42c966e1,65c0e346,2172bf2,e6e167ba,261d0e61,b67df26a,9857b747,88d78492,95312fa7,ee43ffb1,775282f8,f692a83,c6b4a72c,a1ebb44d,28983f00), -S(216fd6b3,c5358b4e,831327fe,2918d70,ac627bc2,e12ce34a,adcbb23a,c0ed2a8b,d450d01b,83fd1935,f0a7c919,cb91d162,dfd14cdc,3d15661e,a303952f,ed70e684), -S(354a9835,50c72d71,37f8d393,2895f1c3,b2e6bc19,1d9ef2ec,3a2b7dbc,3cd2ef76,e4df044d,4ff91794,3e6d4c59,90095781,5ee0338d,79329ffb,ed74bc19,103fdb6a), -S(4215c5e7,7d2cdd03,25f38b38,8a204013,62114d94,1bc57216,56e57878,b2750502,b4d82696,1aedb8f9,60da2950,cb5b489e,857e30e5,20a8e1b6,84dd4032,d8b6a494), -S(79bb1258,ef4deb1f,4a2baa34,91d9e27a,7b75774c,133b9112,3e5fd848,37a57aa1,d467fc67,dc932c7c,48d69609,f955701a,e6a30205,42a51c2c,10591fd2,134bfd1b), -S(eff02038,49797c99,68c8d63b,14a4d84,f4852504,2ab269b8,182b2207,ba94eff5,79a6fc31,e09c939e,f69a345a,56b90c39,2dd58054,e3f23e9,c16f84dc,ffde8e0b), -S(856e40d0,54323270,3ae30d75,8405401b,72f7ec1e,96cf59ec,1f3b8465,23466dc1,d1200346,5e56370e,96663479,bad5f6f,8fa4713e,79217649,c48eaa8e,4bfaa8b7), -S(f020d944,14008a39,59feeeda,49fc388,d41246d5,39a5bfc8,8f9673f,8b0213a0,e88d23f4,5919f0b0,a037f4ac,aad9de03,3f070c2a,f967fcb6,e251c17,69b62658), -S(ce486f16,39af644a,c70dfdff,6955db6d,ffd6f69f,1dc86c40,a318729d,e6823239,8c0fe4cd,debc1c38,37325664,f8cb0235,b6f32ba3,809dab3b,60c3119c,ded40b4e), -S(2cd69598,f476efc2,4b65aa98,27607a9d,3c643033,3cc78072,7e3047ea,a3a7244d,d287d0a3,6749cc57,bac0159f,1c4d738c,a965dadc,be36bf2d,f3f55372,6ecdbb3b), -S(f7d9e16d,c71c9b21,be93bc6c,b00888ab,974c7568,cc09479,16b09532,7c486850,6e561ec8,7e17d433,22163af,8253b659,15d04fd5,24a941c7,a186ab15,4be2d0a4), -S(e1f1b231,3a8bb5e5,e030d6e9,ec921515,6004a01e,f6d737ca,ae4ee585,80377a7c,bdb81500,9c94dad7,69b8744a,2d19cb59,8335ccaf,d840ddf,8817d4b9,735a8e3d), -S(677543bf,d07c8fce,d24cefd3,bf38bd0a,40079c68,1349bf24,c8fe25b7,26365fb4,3a7bd8d6,c442438e,3a1a53ff,d2a6b9d2,e0b3a565,de374417,189d0dc,888c02ff), -S(b8a18d49,b1d4593b,d103b5a7,dcbe4845,e0ad2644,41d1d60b,ad1e9252,1dcd773e,78ff6195,aaec6cd6,cbbbcb23,a81c6ac1,6bad7a54,7b0ca465,5e1db742,2a0c8edf), -S(b8f4e588,1f4155,b7a4fa26,1e34ac3a,3d776ff3,d5a69c44,6774ed8f,e57201a6,69dd7683,ab9bca83,a64ac013,ba62d2ce,1ac5866c,f9cb046d,84f69b34,168896cb), -S(4520c74e,5c39f18e,47d16c21,51f90013,395f2cdb,c59d7f2e,fa40be99,e843855e,ebc0a6df,bbe76c29,d1f32546,cf7038eb,ab3a5e2,bed16a31,acc587b4,41051093), -S(431f3a79,57636916,5d1e1b7d,dcc1be51,6138a26b,beb1a3e8,5c49f42e,fa6d9c88,6cf98a2b,1f747122,2f6835a2,116b8e94,8dfbe5de,72cd9e7e,7499493b,bc5e590c), -S(a03b812d,fd8291ba,ef0d00c2,25437a90,d8362fd,6c5f1b03,965cb3bb,ae9664a2,b3a8f60,a26d6adb,5e761692,a8cf3738,3dc30e79,6417e4a,23db565,487ed88), -S(2440160d,4b874cac,adf4e1a7,6eb079d9,810be0ee,2a8d6cf,5f9756e4,936608c2,c5823453,f331649e,45a228eb,4b524ea6,89047e70,31ce2894,61f119ae,a865ea7), -S(c62fc4bf,ec4f9113,1f5d3c0d,36807b15,35a52246,225b3959,4fdb8f3d,d8539bbc,a7257908,497a26c1,484c0d25,75052095,a1d71db9,ea5b61f5,e8c4257e,291129e2), -S(1de53f0b,82e708fb,369fbce6,72595b67,5ccc73a6,15797faf,333ad7a,7ab16b,ce3ad57a,99b253a5,ede23b7e,e39c7c8d,e5a1cbaa,8bba04cb,d11d1183,c226bdcc), -S(e7ff8510,10f96b2d,80fefc2e,cb1506,3e29d450,13dc39fa,524dfd38,4e1a5ad0,eb8ec381,58f629b4,79599ab6,346fe86,c1159368,161d275f,e55810d2,84d3d768), -S(e06c81cb,ff536295,a2c025f8,6bfde632,ef52d427,2c4d002d,dba88b4e,82570c1,590c13db,1df2b414,d392d8ed,d8b2a303,3d50460,4f1b921e,1099714,c6e2fd1f), -S(28a5c19e,1a67cc90,f5cb15f8,b969d5ca,503b20fb,e5a52dd1,4304c5ea,4ed6ef5,66b9f844,184c75ab,223c5cb1,8b4ceeaf,490969c9,8cddd8d1,122c6e87,6b2e590b), -S(a7bdb9a,631e67b6,9474ac3e,fffdb6d8,454df8c3,87589e1a,7aa6788c,ba47f72b,99d88a77,61bdfc23,271675fe,5dfb2e70,6a728eca,dc83286c,2f7d0d2d,b14ebb9e), -S(44d3cd82,87cdb65f,90f38467,ee478633,8ba82810,ba9ff195,c55b752,22d27fad,35b7a398,80755784,57b41ad,43bfba60,78d7ee48,7d6cb190,9070c80a,3e1dc4c8), -S(7c42f052,87446002,3b609b2,8ec61849,221a62ef,11e6e3c0,718c1c25,27a03bdd,c57bd1a,a31b2fd0,690e0551,6ff9e744,243e0bf1,91161aad,8e798b39,2484d707), -S(f3555643,f09b3164,6c415bbf,c2031605,eea9abdd,9b76d431,10e61c9c,4afcbda8,2b982eb2,a3cbef3c,d1af4315,178f7c9,236f6dd8,e4bf9ae4,7ee56039,ef9ae98e), -S(dd917a87,6382ee0d,10e22c1e,3bd48a26,4d74cbdd,ca1a062a,8c84cf76,1c59d390,2c958858,2cc386b8,42fc7041,7994e479,f3027693,9011c10c,9aa35f52,335545e3), -S(220dcd6e,447f847d,d0d08170,e9a6a817,38cc5c8a,9e911b0f,1dc4aa8f,946d0cd5,7bc7de64,70ff4484,db2696,4ff06c34,665382d6,91d25bda,95ed8bb7,18c0a558), -S(ea30144c,7ac98f2,90ee04b9,9f5fdbb6,e08cb88a,fc99d635,a3daec8,3393f191,a41b4d67,abe18ac4,79d87a90,63b7f0ca,e5adaca6,cc9471ab,b121cea0,427c620d), -S(32825a95,6bc7e979,b03437a4,efeae923,fba1d408,9ea77ea,9a1dd25a,66f63920,e34d81c,e28759c9,ba0c8b31,e57a0a9d,a45cedc4,9e57addb,b81a3c27,30b5882c), -S(78d197a1,975db98,d2014422,58784a7b,4aeacdc5,f72df33,9aea0a9f,8cec5ab1,1fbeaf4b,8c470387,f2d35e9c,36ada81c,7ec62d23,ec8bfa50,2af1868a,92f9def3), -S(e74f8d82,a67f687f,1ffaf4b7,268ac9d9,dbaf42e7,6c1bce34,9d473521,8a4d1d42,695440b7,a234caf9,1f72cf0f,255d4dae,398f4077,93f40211,bafe60db,bdb804aa), -S(de66c91e,9ddd0fc8,96fa32ed,ac4487bd,2a8fcd51,f4f14c3e,c0cf19f1,532ad5b7,3b1f48ed,30df76af,b0630c27,9914594c,58159b83,42c97763,498c8ba7,deb73aa5), -S(9cdc5f48,299b1090,e0902be6,6fffcf06,ae630650,e5cde3f6,9e719314,d75f2334,5ba9d4e,7dc788ec,ba0b53ac,3a68309f,21971371,e2db812e,566ee46,a61e7fe8), -S(50ce38e3,809cd6c6,601a095e,d5a63594,2cd40f15,f97cb332,fc19d70e,a1214e9a,b7ed76bf,a0e0687c,44b66bbc,ec0fbadc,94fa09de,5b1476d0,6207e256,dca2fd7e), -S(aadaad2b,a6d873e5,a77ed2d9,ce26cb0e,349c7b6f,6847636b,566f47bc,7ef52c69,233b40ba,b4082ff5,c7122143,a45656f5,2989b62e,391bce37,d7aa245b,6c84efe), -S(7b219f5f,8f045219,5959621d,6c161a70,b4ef7a57,cbe7c9f4,fd539af5,71b8e0f2,8efedce8,dff914cd,e050209d,3bb91af8,c8d781ef,a87729a7,c5a6fb6f,8183ab6e), -S(31dda168,6e3ee50e,4e39f01a,68797bc4,7763ff27,5fa4489e,386d9902,c6c328ed,688d2e05,64b66581,cc5b1234,20a6c331,d33019c3,84a63c8a,a6f14be8,5d392201), -S(ea514512,aecfb0f3,94e59d7f,d9d558a8,cf535464,4f2f0963,2e2c6364,b1d57b5f,aa2ed069,dfd3144b,c9aa00d9,5037b099,9c35ba17,d6ee79cf,3e9aa5e9,f5dcca2), -S(bb2f9ac4,107288f5,66be0b4b,7b294e61,ec868a7e,4bb26a04,e4f473c6,9bc8e40a,6fb56eae,bd923ddd,c5028472,aaad2e0d,b0c80465,2e59c87e,45246502,606a0f74), -S(b9401bb,bcaaeab4,9ac42f6e,d36891f1,bddbe0a2,81ec4cf9,8d5f306a,ee9a5,ea40ae75,812da94,9bfcfeef,d22fa5d7,654eef70,34d3393d,6959a59c,2312dfcc), -S(dbf74d05,475cca1b,218bd219,8b24eace,99e0c4ac,56fffe3e,6f8f782f,8f338437,95f6b97c,eed1b3e7,b8de7f15,55f7ac5f,28649660,a458df0b,1806512f,f10dd82b), -S(cbc07e16,64041096,9e78dcb6,585abe6,9ee2dcd3,3febb64c,1f5b8bc9,419023bf,513e2160,56a3dd13,516092bc,fe6a5f4b,3c2b2843,a55ab69f,12f8387e,840a1772), -S(14504eff,814dfaa2,78704245,f0b11c4b,99f0c104,1d103e8f,a221a4f2,d3354164,a61998da,9bbce03b,e1bd153c,c33e85e6,cd2c7b18,a2ff9f6a,4cdba579,593471d4), -S(5b6d95ad,e3defd6,742e2e16,f4ca48e7,118e2ca2,cce878bf,f8b3f2df,fdf4895c,841ad4cf,b538795c,32000893,e0306415,b15edb8f,d83772b1,4de4f2d1,ecb180bd), -S(de084c,e1cf681a,f081212d,7e08f5df,89ec249a,fa419bf3,189339c,8a962f09,7790872e,2b35ded2,78f496a2,8e6c4907,8867c0b7,fd0910b,900c68f4,c11831da), -S(ed4e253f,3e7e781e,86290b2e,56eed44a,47b6f73e,74282d0,b7b54f7c,d75a97de,94a21c29,5850d088,d6cb20e1,9a2a3975,b27db744,4f19d257,cb3c1bef,1a329cb3), -S(3e8f32ec,ea23ba55,cb6d0fd1,41aa2225,9531ec35,bd7f3ec2,7291b798,431e2ee8,1875388b,5a9d4571,66179379,4e7c5046,ebd10c34,9f5df4f1,ed50c11d,952bef32), -S(4d2afcdf,bcdfe440,eb211566,efa59e4b,38385f69,5e7e2063,4c3b4606,32e5a23c,4694e00c,6b55863d,693d68b7,678791b9,f09df4b6,98df84bc,69940429,cbe10a39), -S(84fec62,e92704e6,1013bba3,4dff3876,5e4221ec,f72ae24a,1e80a814,632a5505,b74a1f4,9b9283f9,d6d01827,8bad2cc6,73cad8b1,99a1dc83,bc0ec561,78a2539e), -S(8114debc,44e517e1,1d900358,d0b831a1,38275cb3,371ac707,c4334544,bf076dd3,3bb2baf8,a42a57ce,d6e1942d,8324c795,cb05b978,dad8d20e,6eadf721,9f2b2d74), -S(fcec2f7d,20af0406,370f4aef,b2bd168,592d6a21,d5963127,3f3b836e,d1d881ef,b59d480c,b37372ce,d5ff46f0,5f1700,ea5dc847,1ecd2983,42599bcf,eb696ff0), -S(c000ee62,5a6ae49a,b0226f97,dbef0469,bd02e7fa,a8e3d4e2,b509a6ec,cef15876,b13e0e83,dc9c8f89,6c82ee3d,6cbfa8bb,4beea7af,5210a6ef,1d331180,83946dea), -S(142a5689,bc43523e,6f0c2922,78b7c68b,c588ca37,aa934997,63438dac,f5662669,cfdfe57f,2b80c32,f90af575,195dc71b,b7890d94,c27385f5,1451429e,41de8119), -S(3935bcce,35fe92b8,a2722b4c,5252f5,e6252b49,2ed2b8c4,759fea06,211bae0d,23a96df2,80a4006e,9674b0d0,e44ff5a2,f7073656,3539de18,a87529c0,4640a769), -S(46c985ec,74815b72,97d7052,35990967,1257337e,efb0ed46,93a06124,6bc5d717,952cc49d,f7f79ad7,8c279195,dd24fad9,ad75413a,5ab78869,f1c686ca,52dfe9e3), -S(2770cd58,25287db7,b352380b,b894ca9b,a8ee672,5153b7ea,1f28b254,566d1e27,c29b9df,d3028c3d,b7859d8,30de1490,e1f8abc9,c95994be,13696587,8ffe9b99), -S(8be87133,6feaa5a2,c5c3ce6,8d58159d,75c54e90,12922dd3,da4b534,31bc8153,efeeea2d,440e6127,bc12331,61a18497,68a280c7,6858bcb7,3a5980b6,baa4dd39), -S(675af413,e5bcd4e5,1c522a85,9dc1f3bb,14356298,62117c2f,90107af5,496fb8ae,54678238,ae95415,219b860e,985acd37,9d501ce3,c68b208d,2756cd64,6b357578), -S(5696c5c9,6f8f3b03,f1b3aba3,af85f160,67c309a5,bf4fb8cc,586a1f40,cc4e58a5,f675529f,73ed6987,ba2b1bf5,d202554d,8de9143e,809582f1,4ecfffb8,6a0cf850), -S(2e0f5a9f,5406695a,ba5bac9c,69865f34,ee2cfe1f,5662c055,8d88b422,76d5cbbd,7bb0e1ba,ea55cc81,29b074a1,3380f9be,c67af07a,e91ac96d,c0a46b92,6148fc4a), -S(def49b1a,84ce9199,bfeae925,7a96c403,5dacab0c,80e58a7b,a69609f8,7d3a5214,54c75dcd,2294d953,cd990cb2,a2840c11,813fa97,19178421,18f9774e,de4aefc2), -S(d33f0bbe,51af9602,83b64d36,fa6f8042,fead9d96,138769ed,25b55fe0,6e4b0013,8a9b41d8,32fb7aae,dfe94380,cf2fd2c7,c0e7592f,e3a8c32f,b1cd4aa7,6112227f), -S(6ad93b61,5b5da7dd,8145ea46,7a99fbf8,57529d5f,f25d1aa8,f935163d,4b2911ae,1fc64130,7e4228fc,2354227e,60b67305,9415c19f,d2a084f9,e9caa39b,d2b5cefa), -S(2c886c1c,ba67d840,6e33ef48,6c3e63a7,c3d9610a,67033bc4,f19c0840,784a98aa,79fe3de0,7363b7af,7d3a41ff,5d3aec6f,ef80426f,be455e12,526120f,5b884823), -S(10e59c98,b357ee38,3c306e3b,9c1be538,420881d3,2de1462b,aaace4f9,d84c252e,450e954a,92655710,c3e6279a,94fcb52f,c9aac9f9,2dccb95d,97109030,49cc71b6), -S(32725d0a,dfad10fc,c95db4b0,4ba65569,e88ec325,9cdbf02,5194c69a,3a18722f,d87902ed,f0f1ce28,3bbb3fe8,113f6bb8,9976348c,965094e8,1e24c28c,911d8533), -S(b066a5a6,da035350,33888fdb,87e28292,4ae805fa,45b462da,82ba0622,e6fce040,5337766c,2ef3fe37,42571ab2,286246d5,95ba7087,d3c38332,6490feea,1863a5d2), -S(6ddc1ecc,e8c7cb21,a681be75,a2143ffd,2663b75d,9ede8a15,d0b5189d,8c52f63e,c4da0af6,8eadeae3,ed9b5b61,a73bad5d,1ae8c080,2777441f,cb15910,153284fc), -S(c82cdab,1659a9b8,2ba0414c,bffaea32,eec1b41e,615bb47c,786abfbd,43698d7c,91e026f6,781ecd32,ab59bc5e,2ec3061e,5f6af1fe,bb6e627f,167cbdd7,afca63e7), -S(d932562b,6cfb8034,ea75e656,502ed81d,2b5b80a0,ae85aee1,29f677ce,aa5a282d,ad101b8f,97aadb58,d0b3d8d9,1cd24950,de0a8baf,646e9d9f,734f0f97,5043edad), -S(ec3f50bb,efa0b462,66993e4,233e5e11,f4bf4d56,19aad9c6,37638bfe,d8e45916,d63f29d,3f7b0b6d,b8514712,2343f51a,ff1cf956,e5f49bcb,3a9ea5bd,639dc2a1), -S(b5ff4795,4d6fe3a0,22303189,6eab5c14,bcb6dd3f,497ca561,1e3c9af9,b7e9cd79,16605e0a,5a862ccd,b9349159,13da9d4d,dd537edd,817a0e24,d0d59101,61105b18), -S(b1f153eb,697dde61,36beb382,da8702dd,a51e61c0,963c6d45,338982ef,dee9dc7a,fa1ba411,1823398e,23462cfe,339924d6,b6eec980,729159ef,20f8c8d9,f8143645), -S(42206dfb,8dc8eaac,d0f04c0a,da3a2cd,38c60bc4,6d1fd148,8fe12c04,f15904f4,c44393e6,2969b4b7,ac388f07,8b997de6,d4e08893,dd17699d,9a1cc885,84f3c5dc), -S(56cb266e,152ea2f6,1db917f8,c9b592e,3ddb2643,341da585,c4291d80,d7bfdc62,f7e9f332,8e963d0f,a3d149e9,c4c590d,e835747a,b75df64a,41d919b4,4fb18ba3), -S(5e1d6097,991e9fb5,b099e173,d263199c,cc3e626f,b512e6cd,cece57a4,888e6f9c,a151698a,aebc1dd2,93e29cc6,bad03cc3,2a6785ae,61da1f71,d50240d4,825962af), -S(4acabf0a,8cfa489f,34a622db,9e22536f,2da926e6,97d72756,eff9dd84,72d7b207,5bb50941,836bfafc,7e3f693c,28818a30,825a2b7f,39282d7c,87fc543a,5981d96d), -S(1a9bd6cb,59008470,48b638e5,576d24d2,175afb0e,fdf4c499,fb4aa143,328cd058,36fc0b8f,6605f00a,9822ba7e,c97fffc5,9214a479,eb6c361e,dad89e13,7d23b896), -S(649da46c,ccf59f43,e04c1456,9db1da2b,7506bf36,fd5a1aee,6505d8a2,bb812f5a,251efafe,6319ae16,7d69c617,46e2fb8b,edf77fba,b0ba1fda,1ac30ebd,21c65ac3), -S(66e9a7b6,5682def8,a7a7db04,781614d1,3e176461,b833771b,6001dcb0,f87d316f,ae3d2f9b,442bad03,e27a8d42,fbaf2f9c,294c82dd,fd5b892a,b5aa2a54,df3f9375), -S(d2f13641,6c42c603,82cbb4e0,108a937a,cfbdfbb2,d3195d69,ae3ec647,50fd2e25,e8de2060,b52a7ed8,b1bacdfc,de026f95,a9027727,4a6fc948,76dacfa5,5db7cb35), -S(2737e1e1,5af922ee,fec76921,7064ef52,fe555f93,b01ce4ac,e03d6103,93742abd,f9e08b6c,dba1824,d1cb2efb,d9c5bc22,5a71193d,5626ffbe,9f8bdd1b,48aefbaa), -S(e7a21d74,2203c820,e7da2fac,333c1797,a90b69cf,9b909dce,7b71c052,5c690576,b9888022,82323a5f,8c327eff,d4d10836,23e53b2b,7e0d0c20,cbb48978,f2326034), -S(16acf8f9,854c5d89,5f761823,9a557dd9,320fc976,d2df1012,502437e4,7778efb2,1dd09906,c2c229ca,28e49088,dafc49bb,5033eedb,4cde30d3,8881a2b1,e3368411), -S(74462c7a,64d0ee15,cfc48ab7,874a5f91,c4788e0b,dca9560c,eee55fcc,c2ace309,c9468199,6e11ccc7,ae58428b,310a2057,9f8d686b,a15c2ed0,7f999027,5766eea4), -S(77e35da8,705a03cf,ad891f9a,a2c2e56e,c0c5b88a,38f9ec3f,8dae4c68,cea94ae2,7cde0915,9188be27,54c4a653,ae576321,5a8c442e,6931c5ae,f4657d68,3e30eb61), -S(314c833,d308857e,cc5f6268,406463e7,e2d91a5a,f536647,2382ba41,70c403b2,3ae0facd,f3d955d4,dd4b61e7,ca1f2e7d,92656772,2c08274d,cc98d60c,4ee0bea4), -S(36466998,e5449878,7b27b47b,b8dd54b,617e9132,d6252fb0,1f760e7b,dd242979,7fc61d6d,deefb379,9fa87cf1,aa05da7a,84f750c,e7a37b9f,e30bc4a,4b350915), -S(427338f3,644f6efd,e43b1069,b34517bf,af02bbe0,7638766,76c4cfff,65a01bfd,5d9113ee,13c7917e,ea760105,9476aee6,572f2322,5fcb9ecc,ce4a9cf5,bedefdc3), -S(73afaa20,a2fe0855,c35f1025,aa78f181,fd57928,b3e63d23,8b125432,79327923,d82ab0fa,1f9f08ae,551ed521,b6687a50,b4b4b530,4d5128de,172c77d4,72acf933), -S(dc9ee41b,d5ba5686,319ff6d7,62f1af02,4619b15b,c6dce9c7,3c5392f9,62ecf255,bd5653dd,11485718,68521a7f,68bdbc7a,5f58f46,3e81aad,ed200261,6e95cd33), -S(c32592c1,4a401b52,867fb0f3,6de768ec,11cf13ac,d2eeb1c0,31cc83e0,a500cc21,d9e5f61e,b052b496,b8b59217,75d47cb9,d774c89c,76d76d33,e932c50f,ff156324), -S(356db8da,9f3fe561,a9d21d23,5264fbce,bfc08242,e304e4a2,1b4dd044,7c4288cf,ca4cf6be,9c91b8f6,2d66b101,79246c20,6b99d5e,eec50a42,88d1b7b1,3bb00e3), -S(3ec546f0,fb367683,c4d07c50,c58468df,1a36ba4d,887bd57b,f574cc8f,575f321c,ecd4a716,1c65ccd5,e767df14,53aca971,16376c5,861dbb30,33258bed,fad26f50), -S(b2fa7570,216d4194,64306918,f80d6727,4dde9aee,7b801988,3e6807d0,78722255,919188ee,a4c77dfb,a460af47,72547de3,bf591a96,fae85fa1,696a3d1,dad8dd8f), -S(593ecbac,a3f6e76a,bf97d83c,719922f8,3e17a2e3,a054eb40,e6cbf867,c4fc5d49,7d23ffa1,c168f083,3765170c,7ab2f66a,3d4f8c84,1b9f18fd,f3e92918,51421656), -S(646075c4,181fadd7,937d0b14,75450f09,3f91e170,9644ff32,a71176ab,4b973839,5196abc7,e219433,bbc998d7,57b34f78,93fd3aab,c3be5c3d,20b352b8,5a6c157a), -S(6518d32,d20f4490,a605e95f,2fe826e1,1f4d6295,21cee6b1,d4d505d0,50416849,38bb02b2,2d415ca2,3c95ab41,ee54c4e9,f383e5c2,1dba2dae,a2a24a81,599708ef), -S(9c67d572,bbaa2341,9f704542,95a6160f,39b42ccf,eb46d56c,7781f3f5,69eb155,3fcad5b4,953f933e,3a7ec832,e799794b,38c99476,e85a6a8d,58a20c35,b9777602), -S(3976b774,1e135f5f,2ea4a874,11f9138a,ab02aba9,b4c54a5,9ca2683e,262e09b2,fcd77da9,dd3ddca6,6993d5cf,f997be4b,147eacc1,2bd18c4,a1f18525,fc5fd5a0), -S(508b5272,6918dcea,c92e43c7,b697f2b4,9cbd9d23,1057d116,2d34058,e08b06dd,79d3e174,2bdabd3a,1faf65ba,82477bbb,3631f08b,ab87dfe3,1fc76f2a,a4fa8ec3), -S(bd5c99bf,44d5202f,3b1855df,7dfd11d8,71d7cee4,cfe38e6b,243591cc,ee69cc81,4b15cf0d,cfa1764e,365568b0,630423c0,2f81a041,2c2aec76,7c70d441,bf35a6fd), -S(2011b669,509f7a9b,6987692f,f1ee2a86,1bc8a6c1,f1b2d252,4cf4052b,129e6683,902dfb06,4304a94b,9ae930cb,b2d28c3b,835d3852,93b170ac,b0a8fee7,4ad64a9a), -S(24f22f32,25e5fd67,6ff10f6b,c9e7a829,322329c5,d716af48,ad95a32f,289cce7a,3c39cfac,e2a2eff6,1f034f4f,394ddcf3,31efd98e,3247b3e2,a60c462f,4846c4f7), -S(a845991a,70b6c165,f465ec35,fa698977,ebd6a3de,490f7ec,6a3d82ff,72a8dc76,b8b71cbc,84975cf6,2000b12a,ad56029d,b58e828,f1e37578,73231c52,f03bd158), -S(f75a1682,f24cd7c3,f654f9c8,38bf93b5,f5519a2a,39f7226d,3635f4eb,1e496577,be008fbd,d42449f6,8b571d29,48cda471,ee3a28a9,df4ed840,756d1840,4f917cd), -S(d438d864,6173e175,9962a565,5dfc0545,3e7edf89,22f79aac,78806b51,697cee7d,bf0149a1,33476cf,b6ad8062,94a937d8,6a929ad9,f19a5929,fe648798,6e931ac3), -S(42deb8a4,38b7d9cf,2216533a,22047aa8,3666c4dc,188c1517,b506c42d,add6a9c2,a2d98969,5875a67e,18deaf94,3a73d1cc,798fb025,46949078,ef2063e5,63362ba1), -S(abc5db92,a7ec7944,f4a7c07d,edf53272,2c62e77f,30852f7c,47b34df8,41b1567c,d4917a0,b967ab9e,b05355d3,601e106c,c93d7094,e8e2d452,5731350b,11ee3c2e), -S(203a579a,3298edee,6e5b8f,be8c3a53,825f798f,447fb5e6,c3d0a68b,69dc2600,6bad56e2,c4403cd0,423211fc,38810f40,31696852,af4eb6ae,939fce9a,a2253660), -S(f69ee455,42cc8bd1,490ae8a9,efae8a94,5c5efbc,ba078b11,c79c73,492278f8,2f1ba10c,e93b9f58,a19baf63,46706a9c,78b70faf,dd55d998,c394a8d8,713654c6), -S(838a8e3e,88527ba5,57c80ec,e8818ac5,5cd73ac4,aae26883,bd4b8048,f4fafb29,661859d,6d99d8e8,17bbf643,73726d45,1379744f,4bc93c7f,b228370e,b4d369ae), -S(99d1e947,767fef9f,71ebef00,91d2b7a1,f23481c1,fa3f7d3,4883a18e,59f6f846,673dec94,4b3d82b,358cab99,2a434932,91bad282,e0c9c41e,6dcc4f7d,5737f696), -S(390abce4,4a25d121,301d79a3,dd273897,29145890,c82c712d,760429d2,c7fedf32,e2e868b1,6bb5c3b0,f6305c4d,aa00a536,5e2aac02,71649fc8,b3e309d4,281db193), -S(4e5e2983,59d53274,a2c5ea8e,ae4d9659,bf7b9919,454dfd3d,a86a3705,272e2004,db0b88e9,a3d30e62,696ceac8,1028dbba,144157f8,4073e422,24026681,a7184339), -S(5bc3dcc2,1e1ecbfc,6a14e36e,ed26527b,6f44b03f,c16f146f,23c2d1c4,535c315,d16a5275,99e9b315,6235d74e,957daf90,1ec9f9c7,de9eb7a3,ef6f8138,1b5b29a), -S(8ba374d2,f56e7da7,c6a7b17e,a4234abe,9f6da593,77b13a5a,3f1089d4,cab2f7fa,1e0479fd,8410af5f,3b0bfa63,612146cd,735cc6d3,3e72f982,2b18419c,939d9f5d), -S(6c8747af,cfdedb6a,a45b90c,bad3b269,6bf15c16,202e36dc,5b0488cd,cf954983,75e49114,df83874e,f9ad28d8,3f3bef59,256503e8,f8ae22bb,f7f18f00,94b3b119), -S(3892cbdd,7fb925b2,18e6bca,9c58426c,9a96eb2a,a5f3db54,fb861d0c,323049e5,817622b8,96e224c9,84d265ee,bfd2a996,f6444413,992fd2fa,de91ea39,aec39e4b), -S(8f001a25,19acf72c,f9b3e528,7d060816,3f84b4b4,16d377f,9b70b417,859fb58c,b3c34e61,685378c6,b757b0fc,a961763b,af2e35f7,810ee236,f1d0d7df,92000cf4), -S(4a8ab909,fed31731,50f16b44,785ecba0,af5ceed6,83e1a2b1,6be2a91d,643fa00a,ac88cd4e,26a8754f,d33646af,faff3f74,f04480d6,b988e24c,a5f6a979,25325b5d), -S(49002f29,145514e,f9f81133,284752d6,ca973ef9,daaec307,6f279b3a,6ca9d1a7,3a73249b,318fcad0,65233591,2a07d90,39d1c05d,cd40865b,eb0d3fec,a2bc7c67), -S(1ad5bdc0,2ef4ff42,6d0d079b,3d680e5e,65b0431c,b664eda1,9baec880,6604db88,cb55d682,1e63786a,e496f903,d8b4db91,c22e48e,893347d8,3110ed32,34869d92), -S(316f40f,be3c495b,9256456,1daf8f94,3bc7533f,56d09351,4052be97,fc3f8c1d,eeff684a,8a37200e,ac0f16a6,90c1b69b,c52ef929,8bb1868a,2e9554b5,cd218461), -S(e8408480,72d6ba93,3fec095a,6320008,f28a073d,73625de5,a4fc0f7a,c242f55b,6ba42703,5ac578f0,6ab1e6f3,2b760bf8,b91f89c2,d37faa1d,86fbfda3,e0cf8871), -S(b3c81c6e,d24d910e,a9fded30,a61e2706,829f9e82,87a84755,bad14bf1,36eff3f2,57077559,8581b2e9,254a9c35,5aa6e25c,fe7ff2b2,7c1e0175,38161f6d,6e3da4e1), -S(9b0cc368,c402b063,669e96fa,17dd0c17,bfa19114,966319f5,7b5ffa0f,5c0635fe,c5ecb380,a239b714,99cc147d,8087b453,b01d131c,d49f07e4,60278983,e975614d), -S(bfddfb26,ac59c5f7,f6d9693f,c5498e49,cb1c2b46,452f926e,b120c79d,f49c52b1,8cc30f2c,4bb7897a,1bf13f71,b5618ffb,18adec2b,5710c0f8,d7e915c9,abc918cf), -S(989861b4,ac8b6cbf,56d8442c,d753c833,1830ebb6,369ce4c8,95343abd,2e887fc6,f7a269e9,3ff86bf4,23265f28,d4a392ed,1c8e1383,5792d43,cf4de508,3dbec068), -S(96a6e19d,336af93b,71093fe0,a63836f0,4286b43d,4abba61f,66aaa28b,1732b09,66df4497,c453f01,6425ec93,c6858ae5,300f3757,eabd41cb,da6a05ae,90f8f41e), -S(cc2561c5,1261c57c,8ca2318c,5c5d095e,7de2294d,5776aa74,9870631,34eba9dd,a11a6b85,a79efa99,e72e14e5,c3348d3c,d27af941,305ca3c3,1c48a0d8,ee247cd), -S(9f0b93b7,8666076c,c4f75d50,c67b6e44,96d23b30,b48154f4,f0b11307,fffa174d,256dd20a,f8c0fe19,8ca0cf98,befeb0ce,ca81fcb4,7fc0822c,76bc809c,13eb549d), -S(a7e5f4ce,d6eb2995,a0c1fc5,5a644b16,2ba6ea53,20c7abac,dc36e6c5,15cbd06c,ba65401a,3e1b856,53d98ce2,3596842,287cf1c5,fd249ace,8dedb067,8553e1b3), -S(c4949322,cadf34d,bd82a36e,331145b5,42fb3109,44dca7b0,e0beb9be,8131bf52,912f12e6,5f3fccf0,34e14147,556598a8,550fddbc,9c7f9844,637dfaa6,4d6dbf2d), -S(68040ac4,351a1f3d,ec88abbe,bae3072f,bcfeb944,94ec6610,4793ae21,a8285212,9d5f59cb,316f3a53,3f7eac34,ffa386d1,c555d3a9,49eedf36,b7276e32,e7ac416e), -S(f77daad7,5893592f,978438fe,578e5124,2f98d202,ad07f6f4,1dd4a238,8e3878af,d0f7fa3a,adee3b5b,27f95fb1,4d4e157d,b524c6f9,15c3f5b,7d57fb36,e82dc91e), -S(371fd993,87312364,852234ca,6dcc7d2a,cd58f4b0,c73903f,ba08a0e6,2a81540a,365b2f9b,b4938fae,a9065bf8,5cd88a40,4ee3a651,a8b226fc,e760161e,734fa5e), -S(eab4b429,32320270,ad6e3b6a,5784067b,6439d0fc,d5f0c0ea,579ae702,9d615d29,541f762c,6d825cc,66544ced,5965b077,943e270,ec7a7e20,b1401923,12aabdce), -S(5d8d97a9,fc50bd4a,fd326a61,5492f596,e10a52dd,6dc836d,44128fee,a43f0371,1acaca55,f82d78f9,cb28bc7c,cd9c2409,20066526,3fcb4a3a,f375e44,59c68e10), -S(d37ec7ae,89fd69e1,b9c64095,d5986a7e,b90f6f6a,9daa2638,6138a42d,357c9cc0,ddd875f9,6cf1e99d,fb4478b0,817899cf,1b6cb89f,87fdeb09,c72c539b,9c850e84), -S(7db9b694,ed838749,d320effc,2ed0f86f,1fb0f7dc,e2ce09e0,a5024bb0,d039c6a0,4e74039b,b6018328,bd89a2b3,284ccb70,6d464ead,e9562946,5374744d,222dafcd), -S(b02fdeff,df11614,63c01a8c,1a2c6def,41c5e64a,656e1daf,f8b73443,af060020,39666b4c,14e7c169,3ab2aea8,993f7dff,814df0e6,73c38448,caf88486,ab0307b0), -S(c89a4af,f4141ec4,5a586aa7,53a2937c,e6ad3122,45256466,31336c3e,f401cf2f,b4b2066c,f0c9b0d2,d1cc0ca1,5dac6578,dc7cf9c1,4077dbe6,1a92263c,141e50bd), -S(fd4a625,69fb8443,fe70739,f7c6f9,3794d7ab,5d25c0c2,c099b390,ba733601,741308ef,8600fe30,b912c49e,6b2cbc24,4b84bf30,52e690e7,2f478bd2,12b647d4), -S(f5322b3f,786e45ac,6655c11b,ccda223e,d4689bbf,e5fc6253,e248be82,c0c2ca6a,69f2c31c,96afab78,86220dad,fb9a0c74,c3eb5463,93142221,50369064,1081bf22), -S(f8daf170,7075b29,bdc36d65,a5ed4256,b21cee78,8dc4776a,e3a3c40a,19a2014,7b7fecc9,c302068f,80e73041,5eb31c25,4a38da9b,a72725df,898d4226,ad6585a0), -S(6317fe9b,cdb3eb9e,b7379d82,54253a26,786febff,88b5549c,d4f4614d,40c174a6,8c52a679,a471672,d9e46d44,d69167a1,b962ccc5,38e1a42e,2bf5c731,f94f43a1), -S(5446a1f5,5a7e226d,f1dd2c49,8d49e2cf,19ff8f0a,34c6bc3b,66fc19b,ec036064,826f2d2c,1c347caf,57c90c16,582ebf72,1d02a4ad,52b78254,2f97d10c,d9238e3d), -S(4973367f,ba057d1,9fcda3b0,37d2e672,cc3cb6c3,f2ffd427,c99822c3,b42154dd,8e9b4d0d,9008ef0b,c82764f7,3cc7cac4,331b88b6,740b0590,30327699,82bb0364), -S(3bac5c37,462fc0a6,11d3d47f,b4857256,f4180689,adb7c16f,885841c9,f56694a7,486dec34,2d7525e2,6766d0b7,fa0442ef,3defbb9c,41e4e6d6,5f458191,c5cb79c2), -S(1f0d6603,c942f882,cc8c8f34,98bf9fb2,eefba019,9d95943a,2a209964,bf585b99,869162ab,b05b77d7,337ef0a6,2ff485eb,af6d8182,1e96078c,611ea8c8,338c26dd), -S(2011eaf5,4d8d9b95,787ac7c7,9d8d733a,9846ef9d,ef227091,2f0d3177,599b7f60,d66ecd62,711364c6,c98c95ec,57dca58b,2f972e63,1a759133,c6cb206c,285d12c4), -S(b016df8e,4c7671d3,44e6e84a,64ac5a0d,af2535f3,b614b132,7c9b2daf,724b2dfd,823ba8f2,ba237731,aead8dac,68f0843d,fed9c5ab,8393de12,b0615d5a,908d6d9f), -S(bb9c3029,384c85b7,d9af0869,b5f039be,4a6e792d,1e863357,e1e95ba5,fab61bbf,79fa55bb,47b97456,f0d4d754,5c6a57c4,5824e868,7eae06fd,a07f227e,b49cf76c), -S(e7cb468e,271042bb,3197a88c,bd4a4b53,5581c5bf,455e0ae0,f3f35a90,8311ec41,f0e67e9b,10717789,628cd4da,8eac012d,c7c58083,3ccb18ae,d39bdf1f,b61d0dbc), -S(738b7b48,6ec3d4f2,4fb699e0,a6a9f947,1418eca2,5688da1c,722be81a,78ce60b3,d76aa53c,4129e5ba,88881647,a9e3320a,1751339a,3c10a8c0,b879bd32,e87f104c), -S(31413f55,d4e5c14a,e091c228,74e971a6,1658b881,7dc983df,4ac98264,4b455e82,c86d2a0f,467f93af,b8ef127f,9c818700,cf54f240,e16dd738,c4e90899,d8a5af35), -S(7ddae61,d231a764,794dd836,1779522c,2be61c66,e79f8a28,79914093,8a6e9e39,86aaced5,6ab82f10,5bbffa0c,e73781fe,5494c6b4,35309de1,441077cd,93d7a57b), -S(fd5a44c3,ee4cc565,d2115a3c,16aed5fa,7b005fcd,fff3e537,3d90f226,398c9a04,1dd95003,722e3a31,991dfdd0,495160ff,ea55aab0,7109d060,d414229,c8f5be83), -S(c3a768a3,fd24ac30,4cbbaba3,7cc52ab8,82e3256,b7d54d14,9628ca4a,a8687f43,2a0d6f89,9df7dff5,eacea751,a825ddbe,ecacdc69,5c071093,ad79583a,32de93c), -S(ccca92e,d2ad3249,c5dc5881,8540e2e1,c89c6ac3,9a98401b,f719f008,e8fa5a3d,5fe2b717,302699d,fb7dba86,c368f67d,6a6f3593,d3845906,3621f73e,28dbd1fa), -S(9e5fbca1,7c3a766c,eda0755e,84bc0f9c,1017335d,1ce0f70d,b8b09de1,568ef319,9f8e25d2,8a01b693,864dac0f,ac82453e,41305f50,3c5dae08,42ec41c1,5e7af238), -S(43908294,409a955,9d02f8b5,4084b120,bb980c59,9c9003c6,4ba2760e,c69118ff,343d27f9,5120670b,ff8dc482,66646eea,6ea37813,3ec1fb06,ff5d9756,64327e38), -S(30e3052f,3f97372f,56d505fc,6081ce75,662169a4,a4743cb8,de4e3288,32cf9c3a,d144aa9b,9cc60ab8,436afaee,a6e6b64a,bc0178af,b05c3db6,42c91254,8ecece83), -S(b5b28b37,6e2d4586,c4c3a7c1,d701b28b,50da01ad,c18b91f7,a45daabd,134a1d69,ca0eb341,26746304,bccfae1a,4200420c,41af0558,596123a5,c7edbe9d,3fe04fb4), -S(4eb1aab2,b71aec48,84d626d1,8ee1d90f,77feff11,cf3fb8c8,32ee501e,48c4ae8,1247cb08,580b0c96,ae5e72fc,f7066ca6,e46c5b3e,3b8091ec,8ae5bb30,e5a7cabd), -S(b814e42b,abd14fe6,55cc4641,22d024d3,7cfa9f64,ab59cada,fcbcfc56,f1fa9201,ed8db1d6,2621bf32,23fb81ff,922a0e10,b4ab5cf3,3370aef3,df70ae19,6383b06d), -S(e5ef7b0e,270a0c4a,3f4df516,b516a19a,cb45648a,424a4967,39b9b75e,ac4bc497,7cd38616,dce6fc2f,fbdac49b,59afde1f,397546e4,1fdd2c7d,b8e9efb2,6b1300ea), -S(e0228a88,c62229bb,4fd0d563,5a66ef1b,e499265c,9163d09a,40170969,81f3c2f7,63ec23be,6c858aa,8390d038,665664b0,f085bbd3,d3fd6982,b2150d8,6695e0d5), -S(3abf7af5,f504422e,686aaa6d,86f519a4,ec6d8ad,b1c7db9e,75091545,5885459e,95110201,2b8c0149,dffc0cfa,b1510529,9bfd537c,43c2a1e7,613c4007,7a8be9a7), -S(16c5a86a,57dbdc0d,84320d49,610b637,437d8a27,5bc108a1,702bb27,dfc04e1a,f5387f3a,7596aff2,2a9ead9e,fd87da3c,68bf5efe,b277899c,7ef19394,cc698cb), -S(8350a35,c1fc83f0,3c306984,799d6baa,3a41bed8,45cb2126,ad8025a5,6f1da1ea,3abd0a5c,83976b4d,79f150af,f47a684f,931090d5,61a61a50,a4ebfa7f,d74aa002), -S(58199602,d1ba3202,bffd7311,8679e8ec,7d5dc6f7,f937eb4f,be70b8b,4379bce9,290dd5db,a4091af5,50975e3f,1f0d42e5,d375a26a,5c6768cf,7eade4c0,ed315166), -S(492c0e3c,8442495d,52d4d356,91d03e3d,133d56fa,7371d64e,ccb384af,907fc5da,c7bbfe15,342b1d6,c48cfe7a,595bbab3,d7c4674f,ad9f92f0,30e2d602,4cd10ed8), -S(adc96fa5,f21e4e6,5c5951d6,53379f3a,b2d92ded,ac038d70,ff1e644e,7c7d4de8,750faf48,16e45f4c,697a610c,11dc363d,4846564e,afef6e7a,335d5d,2af0e171), -S(9567b748,4584b4ae,21e6a12f,cc8b5185,e2137c1f,5f30deac,eadd6b55,ecb64964,b9a445c9,3c4d8a7,fb0b4469,45976ee2,cd47ea88,ca3269e,b559e689,84b1a130), -S(e700f079,11611a38,b0ce3273,b420135e,17ec189d,d1574695,d3452530,c8a59f99,e6685c21,6ed61c08,444b51ce,86681796,8814c1af,aa712a32,15e6619c,85bb0bc0), -S(c412823e,31b1f066,9d067de0,d2e2ed09,bda7b53b,6482d8bd,7f352a4e,74e4cabc,8809a001,3f12ebaa,3b01df9d,355c199d,854574fa,374a85fd,6d066377,6957e9e7), -S(50675ee9,1d350fc1,61e189e7,a4cf4955,d987c194,1b01ce9e,1473add2,ede4cde8,2f67926e,7c4baed0,e0a25df1,468c79e6,b07f8bd1,9d460a24,4233f988,45547047), -S(34f8f31e,7a6d98d9,73eb395b,3368b0d3,c566cb2,c2a8379d,bec31c1c,859dbca2,db990a81,fe7a234a,e63b751f,369ef489,aa6929d8,97a3587e,483d19da,dd1b40e2), -S(6bca946d,e15dbd77,9bed6b31,25986a06,50051c2,db72ebe4,81ed24b1,f9cb4d5b,ba942bdf,73219596,9fb8357a,4bbbdc33,c08f1c17,da37e409,50077c6,da41456), -S(3972511a,f367daf8,192f2725,8597c14f,e151bb46,5b8c195e,610a11d6,e51451ae,36f1e442,82786dd2,8f05981d,292c2241,9844deed,5bed41ef,fb0aa2c1,d798541e), -S(756e5104,3011d1c,e992ce99,76c09063,6560e9e3,a85de433,6d9218aa,11796c34,4d714894,96279d96,7ed41034,77fb1c87,db269661,8c452dd,ca0fda9b,e8c31951), -S(e5508c1a,b9e90d6a,237e631e,507bdbdd,ed3672a8,38ee0f7c,72eb4587,b4231e4,24fcc0fd,f5079407,e3c66b02,9e2f37f3,bec5ba72,25487101,b7e68b08,731572e0), -S(d90085d8,d80452b5,cb99dafc,8fa4aa3e,819c6ab9,a407beab,4bc6446,b5225596,e3cbc413,bf74b383,d2f8e92a,9d6062bf,a579fe37,e171734a,e50ac682,da75710c), -S(46470f31,77b6ecd5,34add036,8cf9724e,398963e8,573d3d01,ce3f9d5e,b14f50cf,1a670f11,15b60d70,ac4c2b27,8f7a684a,73446d52,e3c2a8ef,7a84a06,8512f6e), -S(4e92916a,a3787bda,7cc677cd,6f7d26cd,4a6847cb,23d1e3d,beb32de0,51fb89f9,6bdd060e,739e3122,a48e7657,e03ebf35,bc43f4e,3ad864cd,49242d29,fd3537a4), -S(78fec768,fbf2658f,78f21a83,5f9e327a,67d4101b,5ca9fcf0,e69e7421,d69a3045,5de2a6ca,25adc6e6,82333b72,f30557e3,f2f003b8,1dc817e4,be0ea20f,acdb9f59), -S(36327d81,a5a94289,105df5d5,7ed407e8,f14a741e,998f1017,3592811e,f052a126,3325ff53,33c1395,d2548216,4eb153e8,ed94a950,8376cdee,941e3417,f2f0ea46), -S(2e3d6f12,18373ec6,6435d58,92b54576,545668bf,80fe51ed,eee5ca7b,7a5f8806,6f2afbd6,6465fce8,308eb046,1041a23e,f4515687,64f8148d,a377e329,4b6dbce8), -S(96dfe31a,87620ab,647e0c2e,6e9bad96,4ac4ecce,28d299e7,e80f25af,da5885c8,9a1d9194,3507b674,fea7b185,21a2b70d,ac27b4ea,b370b9b3,a0c2ad0c,2bc37628), -S(298711da,2e303ebe,2cc5928f,e437ce90,ba675b2b,b896ee44,920fe3cb,e34ec55,dbe55194,8671be1a,1af18584,5db9fdd4,c4a586e1,98a350e4,c1326d04,5aa3c593), -S(cd603c3e,326a7c25,575b07cb,d86e0a9,d764675a,b3013622,12ffdf5,708ed855,f0d100ce,2690b76d,62858759,8638c992,4736b18,8beb66d1,328ff5b2,4a1fe52b), -S(5a90312c,30a58754,cfc6d248,669d029a,7da84243,9de2b1dc,7731a460,b05b6e21,fc0af827,5890da91,ac2032ef,e82b418a,2ca1c37c,4a19ed0b,8cee0ffe,7386fb37), -S(61ce7b79,1d46fea8,8f4dfb34,474577ad,8ecb02a,ab23153e,c0ece543,5c472e3a,4c5bebe3,2b82502c,8c68ecee,57f29fd,ee7f45dd,fe5bd985,2418c809,6ebabede), -S(df3ffe23,d13b2b4f,4090daf5,a51f343d,17123083,edc4172c,368ca75a,8bfbb16b,9a21d41,39e53dc,836868cf,9c1d0eef,d4660455,7ffbd379,cb7a118e,36273f2), -S(24470f10,b0e5171c,aeaab136,2ea9c1f2,3ff3a4d9,66a1b7c0,5110b734,43a363db,ce557547,69df589b,bd4438b0,14d4f4d,bfb56977,43656c25,83981c78,5803d5a7), -S(67b07bd3,c96164c4,da09d5f0,be038a2e,74ade7dc,cda4e7aa,28699156,36708765,e0183e53,445a2936,a44df51e,c6d42bbf,21369b65,134accf,c0a6ca68,9adc03e), -S(7e3c57f1,43f1157d,f06eb86c,e7a3d625,df513d2c,1187b1ef,2b4a8778,cb9b1192,81aa590e,90de3ee5,3b68d336,c6c77dcd,925742d5,642baf50,f41e6258,ebbdd5b2), -S(784310f1,462cd93a,dae83002,7904934a,2a6682b5,6124c5da,ac037d87,61dab615,5365ac1c,d2f3bffb,f8454ba6,6743cb70,a08781b8,ce95efef,b2b7d60b,fbb7e2e1), -S(ac75ac17,87006c3,e687effb,5822615f,c5608cf6,3ce43ea9,affc8d,e4a9167c,d75aedc7,42240a0a,79f79c91,93c9aee2,9bba3238,a5ac9154,d98d9664,27faa81), -S(943e4dd2,ae1d3f5e,ba7448e8,15d44c3f,ed1b2333,46c6b1b4,b6ff8386,980c6fd3,d08dfc2d,29ebf8d,30fbcd9,e93e4d70,d42e6526,bc2e7842,ce3cebc1,f8105b58), -S(4f750c16,909060e1,f7509604,9030e65,1e6a768e,a3601d3d,f2f0eef8,e18df94,e434f91a,cd77e31b,c9adb0ca,87860de7,6360c0b6,88accd44,715a114c,aac8eb7b), -S(1a609a28,76eb1228,58678cd4,57c3b762,9f0208a3,ba653603,3f887a4f,7df50ee3,99dd674f,864e8662,3ae00cbd,2a484dde,29e9de3d,7ec83f92,ba60f93e,bf316b31), -S(d2fbcb43,5c932861,2d3fcbce,f84ae490,3003b61f,c7927cb6,d7134196,f8858c76,55b6ca82,280880c8,3d66ea27,e8e24ca7,670bee29,1c4fdc11,56bf661c,2f2e0eaa), -S(5c6e8973,c1c98cf6,71d5cef,4acc76b3,b4c5165d,ce162d04,543d4fc5,3d97cf62,9a3271f2,d829451c,8f32652e,c43b717e,a6008478,637b32c6,66a9a40e,2f157c2), -S(be670a91,1930e634,a65aa675,56e342d9,15037a49,845d46d8,ac14a8b7,6024d8ab,4b4418a5,6583d2b5,6a58e324,a7b57eb7,b5111cbf,8c6a39a0,5b22d86e,b51e2dd0), -S(afb47c08,42e4ec13,13fcc64d,98fe73b7,d6bc3a97,c2ac8823,45a82507,e3842e3a,3b448b26,f1e586bc,9425fb77,37a70de7,f559c1fc,97c9fce9,5da20bd3,945648a2), -S(6de4f9b8,29fb7313,d27bc525,c5116408,d03f653d,56244f0b,bce94fc5,2de49039,653e08a0,26d7c2be,dd67b32d,5d031255,5c5e9c5d,b7aa632,c59f971a,85ea0458), -S(91cb27e0,1e60b6b3,6bb7df48,2dd4542e,d36951d8,53971a85,127f414d,67ef279b,5db95774,f7b60f6,70ac3c7a,41bfce24,6aa8816e,4545040,df4bca6a,7173829e), -S(a3e3386e,86c6d952,ad929b79,6cbcc967,2677138f,b051b3c0,53e2b4bd,2d6b7d0a,e7364d0c,b404b835,4f65c0f9,68ae823a,be5c6cdb,a02a72dc,b5ecf7d9,64eca22d), -S(fbf251e5,6b61ed54,467aa548,cf4a4667,258f0334,f6064625,b00d546b,c61f8e10,1a1c0c11,14634786,e9101685,15c0ea29,bf2b2537,529912de,13ef3fbf,3b789722), -S(e0bfa77c,21555000,4b38957e,a287519c,c222b0ef,81f71d76,9c3608aa,7ca6e7a8,fd778438,2ed98141,1254767,d770866,84c3eb94,1fd4a506,81cb05d,311cad5f), -S(6d612d53,3d7cd076,d1494641,af14db85,7db44e5a,c22ff57a,13c198cd,b2cb50dd,62cee347,915640f6,73a23081,f5999fbd,5fccabe9,b84a0409,ee85160c,93fc6dca), -S(393c515b,5d1f771a,e6134c4,c06cda2f,27b01b66,c3976ca6,9879de82,146e0dd5,147e097,83f65b3f,f5e29f6a,12df5fcb,2ae22d9,857f9653,67efc9cf,6210ec7b), -S(bb340fb,c45c7b6,8d3b1863,9ab961d3,b455a803,c7ad6807,62077c08,6fe10bdf,cb210b7b,bd7edac4,fafecb0a,82efa8bc,3b6fbf63,711d24d,2b0969cb,f39ffe44), -S(139ad93,4a0d12a2,83c50f54,99d5cbff,fa746252,6856a5bd,98bb59a,42f6512e,1c2582c6,b1da1d1c,4c8e85a1,77bc212c,ac448eac,564f0ea2,a23f721d,4c153ede), -S(b49f8e1d,ca33f0fc,5713a853,bfdc8e16,edee6fe8,eed7e310,ae0e6d73,e4483c12,2d2d0750,bf422c6,e49b12c,407bb05d,203a44e9,92e0fe5d,af596676,7552bbaf), -S(78099937,bdd416a4,8c9480d6,82a9741d,d57c89f6,a4ab2b8a,8890937e,b3f16713,b3981d6a,8b4f3045,e3d20e74,264b3d78,48b0f9ea,f8d0ebb0,2bc4a2a6,7da3a93c), -S(64cd225e,a4604ff8,b61a8c71,c3f71d7a,62423add,5c851e89,b2430cf,f6300ee4,89f2cb3f,560f0a1,c5e26497,149ffc59,cf4ea956,f20f039e,f2578092,5c2b4a5e), -S(70cd9c8b,7250da54,cc7ec051,43f087ec,c1642e69,b5b74d95,e728a0e2,27f6415c,57ac1d32,dbb0e87d,9a8ea661,87c4bf6f,bb4aa780,18f7611f,c94419e1,6829af3b), -S(a20709e7,d075779e,baa742d7,1e224373,dc7f9692,f56fa9a0,e8d81847,28e23c5c,3f269cb3,28b57b3f,48db2e3d,aebea0fc,c1d456d5,a366052d,2dec91d3,5405a53c), -S(fc3957cf,c85c590d,f2d6e797,c0aeffcd,452ed47b,57213830,20b3f3b1,56149203,65ef1279,884a1a2,bf632178,e23fd9ee,3128a268,bd75b70b,bc03a177,22daae7), -S(e21c288,805a1fbe,8c0df51a,c5360c8f,69c0c10,624aa044,c071ad18,8dca17d4,9fd946d9,8cb67d2f,200fd03f,c3f4fd77,2ee3c24d,6bdc0d89,55e314c4,8151944a), -S(3f6b8f7a,d68d5d6c,fec93aca,7c9716e5,9bbeeedc,dcf2dfc5,713046d1,1617e06f,97112f31,f5e31334,e258e311,bcee3160,3c75f8e,4a67f039,50dfb30,8eff1605), -S(c630444d,7d6a8d6,f396b431,cbad44fa,88f034f0,aef8f6a,ec8e4921,a3373204,2d459073,ecfba3c0,f538dcbf,65a54822,b8d615ef,ced3a394,6d31821a,921cff7e), -S(1b2bab7f,4e833c7e,432d81db,d7b34e2a,e62c3c43,ad1ba0b2,f3cd3d38,88d96f55,e2caec88,ec4d6660,81cd2bd4,fcad109c,fbdce4d2,c0a24aca,d665fb56,e4e143d6), -S(b6a433b3,1f1a70a3,e53775,e5d173f,3d890bb5,b7ceeb9,a62369e2,94705711,95d10503,8959c755,95d8d76,c30861bb,acbda484,9a448481,6f4931cd,34e59d1), -S(b12a9bd6,4b0f0cdf,9568e3bd,a6b7fc7,40f66c00,398ef73f,74dc968a,cce34b7e,ce8dbd0a,9ec6059d,b17f37a0,dd12b6df,6d809b9,47702dbb,a0e30f31,6b10a6f8), -S(f16e345c,70a20726,616ab118,a5a5f252,b0e14377,79208dc3,194ec16,7e8f1922,62657132,12d111cf,bbe9af4b,be8071d4,55eae6a6,d3c5e153,4efda17f,5cd66f42), -S(b4b85e71,f1ee5898,4c660f17,e48ea158,73963356,b8adcfaf,5257459b,77d02399,baf95723,70486c9,567d6258,ee4b403d,70966cbf,4ca6e0dd,b5f8772,1e053f45), -S(b43dc473,1f85b542,4a8252d0,ef1e5681,720405fc,ae4e6406,7d721eca,552d4128,5f9ae2eb,f5f08f78,12181d44,6111ea2c,ab5c66ed,1cebb8c4,2c1e4a50,f3653d), -S(3e657382,cbcbe472,cd8f7e2f,6ed72623,9fc1fde3,15633d5,b3219e70,cda875a7,ad430305,8aeb7ff8,9be1b737,260e1e7a,5d6e8a08,3ad7f5b2,2912b9d4,10ba267e), -S(c30ed331,8f2a76bc,3bf292c9,fd98ba86,3039ec2a,b3acf028,174da3c6,dee3e3dc,54b642f9,3c5ca6fe,987cd9c5,4726d4c8,f59f464c,b847c319,df74ce4e,7da24376), -S(8ca8ad3,7ac218da,1f2c33bf,73a681f0,1c3fc0a9,35bd7540,fbc3f2bf,82e0763,e48ac338,eef9096c,e3d0e679,249c9183,4d0cb3bc,b45fa70e,7aa8356c,8fd3fd53), -S(a75b601a,aeb33b04,d3e201ea,bedbc5d3,35f516f6,3c34fe6d,e7d58a00,a6bcf3c7,b1b814e0,b143a048,75a4c5de,14a74d3a,ddcae6b,b220a806,1a980b18,4a3b49e6), -S(e542c034,9fbd716,d92f0aa3,ab2c7be7,4e81d38,39bbf04c,38f9d933,33e2447d,93f4ddd2,af3134a0,89c3ccf9,34f61ae2,67530a42,12cdbd4,7641f7b4,c21e732b), -S(460de699,4c3b21da,6cb661b2,3cea142f,cee1b50d,efaa3d72,3d55d54c,60bf9258,93de277,b9acd4a6,89bb02e2,b284cf78,4731e219,540c7131,e2636ae4,4183ba80), -S(e5df9251,7e1611d8,5218f013,4f4bb212,9a0a2bb3,b65b2678,45c83bcd,60f29d05,758dda47,b25e31fb,56a8c18c,f91773b2,6bd26548,6925fc0f,a5e34787,a881f731), -S(7bf153ea,7a8cfc9d,e7558c8d,5354f7c6,f8b41e14,7ba7a8ef,4296289c,f134e6a,94367f87,3ea37ec,cf3e1be0,6600f27e,5a4c32ac,1fc4959d,f5f9a6d5,c4e161), -S(c9e8e330,8a57d46d,65a3ca70,86a0440b,1bc37ac8,8dae6d46,66c4497c,5867688c,c7f12a8,d727c5be,5d2dd18e,1a996ca6,b5477b78,a2b671a9,6fd6a391,95ca831e), -S(dc45e141,d9f18643,db12b41e,facbb17d,6d30da7c,65ceed2f,c481df55,1b6fa25c,52d23e99,46eb60d7,acd8cd47,ce592359,9216c796,320c6657,cb4e411f,e175f104), -S(f4b4ec85,6b55bb4a,aceee0f0,56cff661,eec827c8,8a452911,8bff2ace,3c0b4a81,18d14680,57ad90c7,161f7667,b512f34c,fce3bb84,c135c474,d67c4afe,49b589c2)}, -{S(e7ff8d5c,83bd5846,5c967b5,37ac0f36,b9ffe9d2,fc7531e,ef183cb1,7369c066,9a9c3c4b,e482031b,f6dc69fa,843ea90e,de165479,26ba201b,5f05b00a,dbcc30a8), -S(ad51f3f2,e91d632,a13569d9,2e0bbb82,f566e7df,cc8d5541,54dffddc,2724c05b,1039c9fc,c61bb90f,7050e8ab,deecf700,80509a64,8fd2520f,9789501b,315da78b), -S(2459de87,8ed4337c,fb77d945,4f6d2e15,7153048b,1ff76121,f5ea4fd5,cc77dec3,296ddfe4,ef31a5c9,65300ccd,6bdcf369,20e7b2c6,c1368f08,6e416a48,3d517fc6), -S(959743b4,de6c9311,b95949e3,5f20f06d,6cbdf08,ad40b2a0,5239cb2d,4fe99ef6,1726fe6f,2e6815db,96242e97,ef5dc384,b8cd9ff6,67ae475e,a5417100,bc882cf7), -S(fa08226c,62476f0b,88392127,219b071,6316d6e7,c21b3a44,4a07a2a0,cfad3bf7,f24e916,75b2860e,e6e6416f,d9e6b119,ee65e6dd,c27f02e4,3524509b,bf9beaee), -S(da3f52f6,1102d1e9,3c213935,736e4cdf,72ad32a5,32db4f2c,3e388eac,e403b3ee,93c3a997,4d4c2f61,9338054c,15f681af,d8da7b13,cd89607e,dd5491e1,9d695416), -S(893806c6,fc32e583,997b5859,870df579,dd750d08,49dce8a8,2cf47cb9,a92ded25,959c9301,c7982c96,4e4bd09b,abf38f44,bbb54529,82404e22,7b862e48,adfd6276), -S(5cf0831e,319d8690,ee7f690c,c0b15734,9152c12c,acbd82b5,49c8eecd,b4f17043,2cf5c316,25fed805,97bed5db,4cdd3680,f97d389e,c83a5fc2,1766bd9a,6f95b607), -S(7c0f67a2,ed9c4e10,7e06248d,51c79f70,7e62b409,afa37f0,2bac0b80,f2b04417,748bacd4,2401ffd,e374d639,86414233,c4b7eadd,5449bebb,9dab7248,c5dca538), -S(1c2380e3,d084e808,751c4e06,d0d815ba,a333c94c,ba5f6de6,379dcc86,79f4cf6a,2d6480f4,d237bc92,d05e761b,4818051f,afecec25,9afe2cc,cd032537,f3b21e8a), -S(411596,bca0efd6,f1262542,cddbbf3c,a90852af,80689683,47f9c0b8,919b0696,6774a5ed,2c06a3e5,d369fc8b,1c1ef075,bcd96b15,8f724e57,38ebf92d,7eb6a983), -S(862e0b2c,19500fd8,8d00f2cb,14af4628,bdcefc88,ae87a663,c9e901ba,c2cfc537,6fd77f08,124c45c7,44ec81b,e420401c,399ee4ca,aa8779af,9f4a9b9b,5bfb3c66), -S(fa787fe0,faa2a7fb,8dd1ec29,f81171c4,82e893bc,2aedf4fd,4a762bc6,dfc26752,428f4df5,8e057e0e,491fc4a,82cae796,1cad059c,9ef367ea,a15a4a24,42d91241), -S(e15885a0,2af497df,34b4c324,d22c88dd,a3e34da2,74de0b12,c2c9ce12,d566d33c,3ec3b7c9,209357e6,1f360789,a37b4c78,910d2518,3d367ce,5af7075a,842a1e08), -S(9c7f6bd2,8261d396,97365037,b57f2767,91ae02d3,4de1c089,646423e1,404fb32d,844efbb3,e720a3dc,a5431147,8d0aba48,221d48ce,8a05a385,9505f4a,458f7fb7), -S(b99277ec,fc7ced54,58300c7,783d1d43,67d40dfe,48cc1743,e99540,b46eed6e,91832791,f0aab15d,a293a4e,c107bf69,64895eae,ef0b7b4a,4db1de1c,f8f7bb97), -S(ea5c5c32,6b221ebd,47bf8838,91a0ab8a,abcbc30e,982a5add,5f7517bd,58f68927,9258ed81,2f732f1a,43aa6b76,f9982d24,8be669e9,42cc5f92,90925d07,b96c651f), -S(c8e45dd0,37f1538a,ddfb79e3,5eaf2d1,f5c43535,50857741,481b8bc3,b00270c4,46183384,f3460d3,702632c9,bc340b42,2baeabeb,624d2aa8,1275ced,e2d04df4), -S(2785615e,b34e2395,5fef2170,18ce8e9b,8520ff6c,7f0b0654,40e2e44a,99b633aa,5f4d2fe3,8f56db89,5052ccad,b7e2229,5295ce9c,9028f37f,709cc9ca,6b86368c), -S(bdba87f2,7b750cab,87e4f36b,f2a4ca30,49c5af49,d11d9562,fd67ee3,5215c2aa,507a9b83,dd4a40a2,3aa5970,673f89e4,3dc6c387,28b3db8a,78ee2c9b,40a2b99f), -S(bb358e33,a07a280b,b87b703,6df7d832,6e531a38,c1ff6f48,5c955057,e97a2524,d62efa5a,435d192d,c40c39a7,2c654e34,a6d8837e,b33a602a,1097f1ed,40f1dabb), -S(bc59cb40,190d6454,c356e22a,af552e02,a6f7f671,8e56ab94,10ed6e51,539ce74e,3a3b07b7,2404e40c,96c561f3,ce227241,e7035c13,29c7e566,8cb92126,c6543af2), -S(19654121,d2e13ac4,dc087c0c,373c8e98,e4447c5f,83c976ef,2358cac0,d7b726aa,9832eba,58a67ec7,4d993935,b2451ff,3118c1f8,bf4f2d98,5ac9b2b4,dc4347d9), -S(2f222e27,6c7059bd,88d87b7,a7268fce,c7250741,1cbf52ac,7ac1ef04,dcfdc769,5d7695a4,37686bc4,df42d1a7,43a7c025,820fde6a,1fbdf17e,846115b0,3e64ddc2), -S(9a34f22d,628e0863,52860024,7b4e3b76,60d2c88e,e663a6ad,57f673c8,238a7e6a,86c1a12,29bb251,c6e87b37,d135cd90,e2a7d01a,4a067f67,6d8895f7,57085b46), -S(e526e57e,73b17b34,8288e79e,4f26f864,95beed8b,f9476dbb,26cda51e,b4cec5d7,5b7d63de,97200b0e,e76b2bf4,82e01ed0,19324e63,16e5142a,8058128b,6409e8e9), -S(7a28a623,cedd623f,37b33b39,149858f6,ff7adb4f,f06b1661,3dd23da9,2b68626c,41144248,b2f62a79,e9019071,aacbf63b,b8ba1238,a6738d90,ac6429d2,d7a485b0), -S(cd3a96eb,8c378c46,de954c9d,8252dbaf,1db12f7a,88a55190,87d046cf,58df5665,9649b78b,22c76b71,919b8a2c,7a0d6a4a,5be2f0be,4f1b8a2b,ca2e898,15dcda74), -S(44201d8c,23ae0de7,6e9ca9ed,e0a052e4,753a4a12,87129b55,f33ab4ba,5bf095e4,730f8bf5,53e528e1,ab26d7df,a5767a04,b3fd8653,7769cd0b,8d1b5f49,bd95692b), -S(1d5fd8ff,14da9436,118e41a2,55df6bc,52a69e6a,755d7e70,a48ffd3d,ebc4c88c,a53b538,a3c553fb,4bec6c1d,259fc11c,4259126f,12a61f5e,1c4bdfb0,de34b167), -S(9f96c868,f95bbd10,486cf72c,a1bd1cb5,e45768a5,8a5142d1,61e03b78,8f1c92f5,7a9f8938,fd39796b,6eec3f74,a970b183,dea912cd,cce14843,86ba0ae5,e6b2e785), -S(671e2f85,60f16300,f60173e,18ff716a,9028b22e,8937c118,c21fbf11,f54b1e15,58310025,7287d122,2a866a6d,8e85a041,72531a92,7d727e8d,77c33049,32f50d22), -S(59215ba3,afb0aca9,1f61f7de,d69ac95c,3b0a6ab3,cc5fd312,2d23b287,7d645805,433b9b65,197f8360,d222580d,832c2cea,dedbc92,610b8c0,4e0ed5b9,45b52583), -S(ce3be955,ebf0a088,57bc0859,55898466,8b428982,ef1061ca,a564c48,9fa8b57b,81ce7ad6,224e95e4,d7449cd7,41628408,48249b,d2e5d0b6,6757cb73,7622def3), -S(5f6145e8,1cb8ca27,a9d1fd53,9058f5f1,cc423d07,a23f79e3,d1256541,689cfd5a,f129799e,6a9044a4,784ced66,40285789,c8b71aa2,2fb9a2e2,92a73f0,b7686ee2), -S(ae14d7e5,ce5ff7cf,a419effa,9272aef2,7e0ad99f,1b440679,9d362033,2640672e,5f8670c,cdc2b366,90d07259,9fb1e560,5e71e079,2bf6a2a0,928a8438,1c42beac), -S(61837dd8,7d096602,62119a7,f102eaf9,d01edcd,8c6a9335,488b5c80,535573d0,dbd49194,1eeecad9,3bb5688d,6bff2bd9,fb4573ce,b21dfa1,2766de1e,1b63c8c2), -S(3ef98234,eb70107a,f69be2f6,b3f935f5,f1bec759,2b66262,f048c8a0,8252ee83,451acc9e,7c4c21,346e9ee3,dcfe4a77,d35bf00b,d0f2e3c5,42591441,c90b5354), -S(b1e94abb,912be054,1c38bd4a,a954ccba,f92b41d0,82a74ca8,59ccbc21,755d00be,e8d76ab,ec5aa0f2,49b33481,ac6abb04,700edc61,da8627a1,26812abb,ae5f67e7), -S(a0cdddf5,ac430d5b,f5fd1755,6025d4ed,4f9a0471,83749ea6,232a8061,f27672fe,3c50bac3,f0c01cc9,5c10cc51,b14ef6d9,fed1a7dd,b6d07721,947cb606,8ac81cc0), -S(c0650540,c32945b0,8e42c487,50f2dcde,8c35dadd,2069dbc4,28c8a318,48c0b841,660e38c9,eeb11cb3,aa2b61ef,d7ab4796,85161be4,f4b1547,e701fdd1,bb3dfaef), -S(fc2efae0,77ef8607,286aa5b2,5b114f1,fdd82e6,ef425b23,5170fdec,5d95ffc1,f96a8710,7fa5aa8f,6fc0cce,9885840f,737e1b12,4d6d35ff,e1dccab2,4a863901), -S(d420dc89,758a24be,dabeda8a,27651138,2eacc153,3395db23,71ca98a1,8fd72f57,83f34a52,7245d018,d2d599c1,299845b4,42a06b9,c93142f4,74935632,9052fae), -S(af32c241,a6c86715,471e3ba1,4bcfb60d,c9c33ae8,84ec4403,97b35281,b36ee336,9fe0c80a,1962f8e5,5c2060f2,eb24a7db,1187037c,662cf832,18e0381f,4f92083b), -S(cc44e6b3,c7d4dd22,b4e24310,ba7fd59b,efcb05d7,1411781c,979aea2f,635c62ab,cb05b4de,c8ce6dfa,2f229629,48edb6e4,ec0f2a8,aa53932f,94cda08f,b81e3da3), -S(a7d3a168,b175a11b,ca46067e,c603ccbc,1d7cf852,edefe1ba,ae633a38,318bd97d,361fb00f,5344bc31,450732cf,30b8d728,2aa100c8,4c52b160,9b0dd3f7,66405a2e), -S(41ce228f,e6911ef6,5b93a0d,39d4c4ab,1b4f9ea8,9f34f190,56b6edc4,90834b65,85f7677b,61323fdd,7c0b21d8,572c7029,4118fab8,d432d330,dbaa24df,bf506964), -S(a3532f8b,1137f907,19baa4ae,b0f6f909,412eea8d,290385dc,9c0465e8,a3f9f900,94848f20,d1f41d8a,c433f01c,74a0f120,15f2423,23780597,6c6ddf2b,a369186c), -S(d51d0609,2a9316b1,495c380f,78cf6b0f,53f11fe3,b89399ab,6120d494,b18ec5c7,8efa991d,4a35009e,1b0f7adf,72207c6e,a1ac67a1,6fc009cf,fb25f63d,7706efb4), -S(2155010e,7820453a,4e18b616,6439995c,35e9f1fe,bd4b8c98,31c2f062,ad5db9c3,d951af7,792f7575,a0209ed7,3558efc,8858aaf3,a7dbdd05,1701538c,e0abd925), -S(b02e9c81,6370cd9c,a78da82d,927e1d43,ff27a07b,a8a3e773,a66fa344,331d1d1e,e184e2ed,276eaa1b,40cd9696,a98c41e8,7eb2f0f7,fa3039ad,9a18bfab,48141331), -S(d79e98f7,724ff7c7,13510c81,a00a6056,b769dc28,25ddb5b6,6e21540f,a0b9df8,dae7bca1,8896e67c,9f8855d8,4b2dc1f3,97e47230,d4915e99,33897687,c1e7ab0f), -S(1754242e,1719e21e,5dc63a64,5759d3aa,5003d20b,db8a2ca4,a5375e78,308c4423,7373ae8c,97c5def2,fa602af3,3491f50,b26a986d,b1255f63,9b3e1f26,3ad0d856), -S(a7b70ad8,4807a34c,45adf85d,93afb7a9,30ad1b1d,25d58847,c278957,bd96d64e,9cc8d7ca,d66f00c3,5e0c9476,ceb4f915,76cbf1d,2ff34b80,aa913e5,758bccc7), -S(a4e7077a,8be0e97,d322f62f,74fb5112,c885975b,4e5d106d,1df93a05,10382a76,52580b99,2959cfac,bb27800c,37e0605,7a26bd85,c97154d7,c51b5b01,f0496749), -S(14371fca,1e37adf9,3593be37,2e634fd2,69d004ea,50d2f412,77e0b74c,d82491a6,5130d626,4d570bf0,a9a1511,af29105,eb1937db,fae1f027,45a2e725,bd63589c), -S(3a23c190,995df13b,12556cd,90c4c05d,5bfd4154,8016d31d,85ea4506,356ca3bc,b32f623f,a95922c1,9579f532,9fe6d0df,b3b3c63a,adf1f56e,30b946d0,e6be0352), -S(643cf33a,9530502a,65e26491,b895ea3a,27be865a,231dc0cf,b42249b8,b8eade6d,58321730,ca9a20df,ea6be90c,a7f056b1,ec3da1d1,e2befd74,5a39a46e,24257f04), -S(35fba1a3,f33025ca,96401513,b443d042,c5036ca4,3221b0a4,ef5fe943,34c1a27f,5f5a4c87,a7499afc,4de8a475,8651e50b,d97c292,f5c4fb16,6114e871,d0d651aa), -S(fc62b528,b601895f,93e27224,843b4d29,9d542c5,2235430d,c3e85c1c,4a0685a8,c5ed07b5,4b4f18e9,26be84fa,9d1653a2,716c8e8d,3a0343d2,e6b78e92,53a411c7), -S(2b15210f,b126f37c,6bc76ddb,db6d24b9,dc39d531,8527a917,ed1553cc,524ea86c,deb7b72b,256402c4,24ae46e0,f2e4e09c,12471358,3b73f41,79fa737b,3f53facb), -S(1e011ea,5ad8f791,e430b18b,d302d3ab,b229f715,a68f3d49,c1c2f3b6,285fb369,b9dd2a2a,25937c98,6905428e,73d811c0,8e1d5729,bd6bfd8b,50eb91e8,4ebfb1a4), -S(9bbdefcf,cb0c9e8d,747180aa,6aa72af,917fbd5e,ee2e6dfc,f05bd301,56496e4,6824df9b,a8ce39dc,e7da66d1,a430be26,9faaa54,a83f5441,2d5ac6d5,761bc83b), -S(691a5651,e5773488,24a36cd3,755c20dd,289a17a5,953608d9,905976c5,4136d4d9,c03caa0c,a1bc376,b736d2b8,812966f,6f1b955c,1e68a8b1,a12120ba,ec4f12ab), -S(f68ec286,730a42b0,4ef5c596,b0235e5b,50eea2a3,94ae6f9f,a91086da,47acb9e2,5ef0b31e,86dd166b,f447b7f7,2b82ceb9,668f2a90,88a190a1,6bd5a230,8699a54f), -S(33685765,121d623,9f73b969,efe2ccb8,ad715377,c7f110d1,579fbcca,5b005ccf,cf71270c,c3c8d129,8d6f060a,f6cb343b,b7c807e6,580779bd,1df6d7b2,e90d80ac), -S(18c1347a,cd1a2eeb,7f42bb9c,de08e166,63676348,fdd4c533,d3f51064,b940dc16,a9ccae7b,d22c73ef,eca3a4dc,a56c3cbf,eb3f8177,d9e5cae4,48568a5a,2d83a31f), -S(9235cbd2,37fd6ddd,d596bab0,e2cd4d29,98a28d5c,b3b738cd,6f79fa76,83570357,60bb571,7ee5c69d,7ed19477,94b8d2aa,7901b993,89496993,1e3480f6,89d37742), -S(8d6f63e6,8b7e79c7,1d62bb8e,8e1f3ec,8c5dfe93,21f5ff57,c930ca6,f9d255e0,a1eeab9e,f6bc9a38,45836630,4a1021d,ab2d4f66,4c5cc6d2,c50be827,7fe61915), -S(e34a6e35,8163ec00,f6abbeb5,14b5453,9c7ea2c,8afac9b6,81402ea8,de5947f0,375f0fc0,882bd435,1f294812,b0fdcf5b,8f36b772,5bd93994,343d1bab,a3db8b33), -S(7c92a80e,483c9c33,bb18163c,7b4e7710,96e77f5,c182e4ff,95e8737c,9294b2b5,f9775ba5,6779dec8,dd5448ca,ba1bf760,5c531e2b,f71ffe22,2b8c2b60,93cbe3fa), -S(15d91f0f,49153ad9,3fa9bd53,71f98b4d,84d0bc8c,13310859,547a510b,94ed08fa,c0b61781,ce3b4f30,89e99387,e084827e,b148be8a,cfaf6a8f,1251a5a8,ada84194), -S(68f00c8d,4741c078,f99595c8,230bf510,bcb84a12,9149ba8a,5b495d0b,d3307226,49004e85,f9eb6650,83b1ed05,12199ba4,2da74f30,a70898cb,2ed05253,fc5a809f), -S(c2cf12ad,851d4a49,56a2f861,2cde0fb7,caf83f2c,41af4d98,b74f039f,b2a95bc8,f4643722,186a375b,be0e17af,9832042d,62132982,ef33a626,b6a02f84,f086b59f), -S(8d378751,b5f13626,2fb3eae8,5491a3a0,b3af4b01,f759f06d,4b418116,c3ba30a1,5a47d6f8,878671da,104fb6ab,7101efa1,718414cf,2017221e,8cb171bc,a13d4d), -S(cd4e82f,2592b5af,1cdbb44b,3dbcd3ac,76d0ad92,fca50789,f1152722,1eb4f3ae,734884e2,6d207cff,a145ffda,2f3304ca,3697958b,b1f5ad2c,9cc2c812,99128107), -S(b9983c8b,61629cea,2f44717b,3139b3c8,ad1dbbac,24f8ffc1,db9078b,92e8f8b8,1e0b83c4,349dbfd7,16dcc892,115e93af,2cc1176b,7d386686,dfa7a2c9,a56810a8), -S(1d2d687b,ddc2f510,f0a721c7,4ff6d8c0,ac157929,189dcdd6,2c508577,aabbb982,4c3427ad,4dde568d,5ed5555d,5de4cdc7,fcb6b071,afd342ea,7fb3966a,872d2d5c), -S(9073d8ee,47e31106,718dcc5d,e0e46e0c,bdc8e822,66bc8fb5,b23bcf80,ccf240a3,6a2a92f7,bbefae74,1472e3e5,6702ab5d,a6d20993,1cd7daa9,1a3d985f,5aea46c3), -S(25d31f95,1416d832,59f433aa,89e4df66,49d18a11,1395d676,b44759ee,46931139,40aa1c2,9a4ea4da,d24a915a,7d476769,3a1881f0,d70499ac,f4f78f89,91cf3b8a), -S(d04504f8,9b93075f,822de8d2,27dd8617,f6ae2fe8,10ac8fbf,97c7d788,bd459cab,7c4d4ae6,56d118b2,17abb932,d6283480,5be6a4ab,cb98ceac,8a85085,8f0e2d92), -S(a4afa77,7e76e1d1,64901460,bf63e3ad,c84fa1e5,7ee4cc17,d8a083e4,2e587f1f,f56ac642,f7bc019c,61dea3ea,6891c962,71147228,33d8055c,954b45fb,934325e2), -S(59eb6b42,7e586eee,677ce715,c06ffd16,35ecc418,caf8b707,5e2c9192,f838e4c,cf25adbe,5d0d1c37,1ab4778d,ddb1333e,6b02b377,8c73302a,43262b5a,312e8415), -S(6fbde8a2,a9495849,c0e94866,e3cc7b7d,891738a8,7bfa388a,cda84358,6190ba65,e988c40e,b2cfd713,597290f1,7c37d165,df711c9a,f2ce6989,52204cd7,4b8cce9c), -S(186a8e0a,c9a61bc1,ffd397a7,62f153c4,fd14c2d,78a03e03,8fe826f5,eb5d16b9,d1ccfb7e,fdfa1486,8d35048e,99050caf,73bb0236,ffd33bd3,bcb431c1,868e5e53), -S(3224499b,b9712ed6,b1dc5157,6ceb2d77,356dde1a,263c370d,9a71582f,c4e93ed0,5364c748,54f5e7c4,950f5aeb,d3a56626,7da78898,e3a37af7,a2c5a528,23cdfdd8), -S(b2de,174a7592,ce9b287f,82bb4f60,3a4aa039,4bb308f3,4d282a0f,8e8a1105,a9fa1bcf,424a0d14,5e86c4ed,be0d5a31,dd85772,cecd7fdc,ba1e4b02,b47109e0), -S(19d45a35,f42efc85,283240b6,8f69626e,92cba511,5d265093,b33b71bf,36601850,757b26d7,65853163,fd4818e6,91154aab,c81448ea,19277b70,da37e910,e2bdb66b), -S(9e23f113,8a337fbd,42335454,6e2e3503,3c888aff,f61b4143,3673395e,bfca6285,80ef2fd4,bfdfde72,ab5c2ed3,6e8eca00,54d01eb6,a93542d0,6a562d6b,3342f051), -S(6b494c5a,79789306,9e236dd4,33a15381,f7ba8b42,3502efc1,896ff5c0,16871c28,56ca6202,a860a1c,25898600,eb2f2fc,f5636c0,bb2ba0db,f32cb433,b590812d), -S(b3e4116b,3d05150c,af5821f5,6c33b111,c28a3f18,8c8cf2b5,e5a5f271,115839ec,3bc7caa8,11f4b7f0,c30b0bac,51852c16,2e256b93,dff1d54c,4504fa1,eef9f5e4), -S(9f67548,4e8ce41b,e65902d1,ef56e8e8,46193052,3fcf48d8,e1f49fd0,9d9cfe91,3d8dda39,bb6e6c78,1c0861d7,73461dfa,7c19e10f,dd20f37e,a6d3f152,b1bd1d98), -S(47aa3648,91f116b7,e4115bc7,7419efb,9a267adc,4bcff4cb,1ab58c75,5eca5e5d,1f9ec89b,b253b6d2,997abf0a,46d4a3d,de45d605,a94f4ea,a4ac136d,b57eff2b), -S(b8ec4a26,53d82b24,da269a85,f51fe333,d6f6e9ec,94dd4bd8,3a90b68e,1742baa1,d4564479,b9c3ce14,882fd697,1db7d242,c91a4b8a,da63dd6,41c17bd6,77dda872), -S(ad2d7fd4,dc176f04,2c8a78a2,7eea73ea,7fcd0b16,29bbe1fe,f9eb9589,9173af0f,b4014396,2f84f00e,6210258e,ca6120ff,987601dd,80df3501,af664ea2,3f6e63f3), -S(aa9676f9,85435e57,4db82def,70905ed8,a8cc4495,539a8ab7,42f9b934,e6f1eab2,60b257d,83b39810,b6220fb4,95e61578,f264e817,71dfe6f3,7ce8363c,dbf8ea1), -S(12c23100,2fd6b31e,30929a8,e8d6b02a,593a89d0,b3f20a54,2012ce0e,d74738e,bf8e1682,8b06c853,f061462e,b5f90191,e1af5a66,1d4b01d3,a7be42c9,7f2a3ac), -S(5d1f0df0,d561494a,5e8b9566,a297c018,9562b441,ee91ed93,a43a4141,b7383c13,88a65ea,c63e0dae,244e3e7b,b7fedd20,6fc32f47,35891902,c0dbdece,5e304ec1), -S(ea92ae52,1b21942,78ca6b4f,770c56a9,59403652,39533c74,b0b99ea0,1e32791f,22358430,bf3e4aac,e7c6ae80,7c315bdb,7b7b94eb,4c17442b,bcbae6,b311562), -S(961abd49,90513726,15d8414b,d68edb80,9c698317,c3317d94,d064e272,f2e7c328,b581fb5,949a2345,f561fcb3,21dfcaac,9c235e70,f144079c,3304d48d,d20583f8), -S(41e8edf9,b2b5e7c8,86a9c82e,2780da4e,cc551d3,5f186c0a,caf456bd,fa08d7ff,8afe0efa,fb1b41ef,189ea40c,2f7c1df,f76f740,b2b4d30e,b0afb19e,92cfe615), -S(18cd2b39,1cc5a7c5,8fc7855c,51e9a737,f5bce753,bf7f35b5,3b7ac1dc,b9138f28,86493807,f42083b5,1ce4114a,d159098b,ccd4b6e8,3bbbfd0a,bbfeeb46,6f065ed), -S(2369e0f5,5cfa67c7,788b1d97,a7aed58d,ef0a3727,10a82e8,a459e55c,8cb998df,b3b5c65d,399bcca0,71829793,55d59d4a,f8dbaf89,8c10aecd,d35330fa,dd2011d5), -S(722b21ec,9e6436ba,c87ed647,2d28c33d,e4e4c792,de5e9b0d,85581f19,32f91f9f,5d757d,d475ab0d,390861e0,fb204ac5,dbaaeb48,d2a48014,d3a03ded,3293c497), -S(3b6661c7,33773220,40a45f9,527f1e6b,b3657e8f,de4d5beb,b4213f6c,130933ad,d480a018,3f031d7b,c4ec6965,5b0d3ce8,bc0f5ff7,5694977d,d2810188,f739f8f0), -S(2baa92ab,fd1b3a06,7bc34db6,d3a1b82e,afa2eecf,f82cdfd3,a2bd2da8,d5072ad9,4583b0a7,e1c0b53,c165b5e5,cd4e41f0,27179f60,328fe313,4b0c5d5b,9b32b3d6), -S(2fd0279e,bb08f28,5e4e385,6ab7bca8,dac262e9,968c2341,9049611b,6db8374,e377f24,92d0bf24,89a8094,5516f528,4871dda3,26e6d3cb,a81c55ca,41d62d5f), -S(911e62fc,dfbb1636,bf80d445,d711e328,4ea6c362,629e2aa9,f8f48a4c,8a0bdc32,2339b90a,a771f035,4bcf1f38,d7dbd8d7,643f260f,65f4fa2a,bec27e3e,ce6f8471), -S(5ecf9075,7d277b40,fe4ef091,a525cafa,fcabb2d8,da8b7670,d3d25680,b1c425c6,9690ebc2,1de37095,9abdb2e0,37b3b34b,db367933,888d9db3,e903f8ff,c5b85d7c), -S(270a9301,2167aa21,5c5da736,fe3e32d7,efa97b65,f7c89a7c,62a6ed28,e3038e3e,445f24c3,8998530d,39964c6b,d51d75df,fbe176f8,91b606ba,d4557cfa,a71d9f9e), -S(bc9e7f14,8244cfe8,b408be81,b79d904e,bcec0cb3,f4e540fc,f6f469d7,f73151f2,5dbda6e3,49377393,c6d90189,26bef6c4,59fd597,c50848eb,1808cf31,13b7e704), -S(163e1b86,bf0ecf2c,61a630d9,428f2fbb,7772032f,df990bf,1e276e98,a84ba2d9,3c25bb36,4f1d6a0c,c70cfb84,70604f61,4bad22fd,bf305058,667dd0,5934711c), -S(1706ad54,9dc1b0f9,bd1e5fd2,729802a9,8e6f6d96,24694b2e,3d37615d,b5565999,b16c7d90,403b6d24,65ee6526,54ab19b2,5c43cfef,fb6b33fe,12c56912,5618df71), -S(7e66578a,356ac4c9,636e0369,a7b1368c,cbe06189,602aa938,95a48826,a5c4d2c5,77e51712,195393c8,f95d032f,2bf1d39e,60b805b9,f5aedc31,a511f1a9,ffd976d7), -S(ddae1e49,1e8b0572,95884c3b,ef5ffbaa,dc6a7ecb,d8849521,177f7d81,868caca2,be7719ae,508d035d,88cbc2d8,3ea232da,657c78ea,401bcb05,9382c39e,959d5251), -S(5b44e6c3,a382e500,2a53ba57,fd6e92ed,8296341a,2e81095e,8ca22a18,fa76b450,443bf958,ffd1fa9a,1bc8ee27,ef49e457,cb23e6bd,dc6d251e,8e28130e,e6ce6892), -S(33d32ee9,f66d00bd,85d7e24d,7fa3172,8352668d,56be6f1f,71cead36,b1035f4,d3372856,106025f7,aac97103,4efc5c51,4c6128bd,6737fe,325ff277,f25fdcbb), -S(7bbc0b90,9491363a,cfa10e65,84d693f3,8b2a2164,1d2d886a,3c348c86,d7f98e11,ccfdd17d,532ecbe7,c654ec54,65928836,1dd2ee63,136d36aa,415fad03,f94facea), -S(a3da83e8,db0f8d0c,ad680373,f92426,26aea70a,c68c641d,648b2d94,244d68eb,305b0d91,6337a600,4f17626c,835a1cb4,c5d97f35,f75e7e44,ae3ea4ae,10d5b40f), -S(f5155f1a,2b196a3f,aa07d4ff,5fb91890,d37196af,1354d1b9,88ea4412,c57e9244,d060c7fa,f1666aae,f38d5256,b20893b4,961c3b4d,40fa9739,7a52cd00,4a2af8f7), -S(c948aa6c,ee9b8481,fed5b207,5100f0df,db799e6d,76d1af83,6d198f84,d6a028bb,6943ef15,988941,3b274855,1e0245c9,52172cce,8eb29444,e7728c20,a8da32d2), -S(518ae279,d1dbc26d,3b940b7c,f7c98eec,bc7660d5,af24dc72,ab8e6b0d,329b0d32,c8bf4d50,74471ad6,2f4ad9f,df065490,c81c1ce4,6a8b8847,b1e1b826,99b5ebee), -S(82fd524f,467bd6f8,bf84b427,d81b643f,ad38940f,ffaa2da1,f659dc6e,263ffb9d,2ccd7ea0,ffe0dea7,f591df01,5d1ae314,71f2cc9a,67c610ab,5bfe8f46,57a0647d), -S(250edb5a,1b6e4778,4dbf0bc1,510f9716,f5682aab,b975826d,2f715427,8d56cb5a,a625aed6,663ac946,ee805c8,11328923,9aae6503,1efab534,e152ded,e4d1f138), -S(d13596ab,e37d242e,ec6a50ad,95a171b9,c0cad0d1,5e6cf674,35cc87d5,1be1a6a9,fbbc5a7b,b3592ca4,5a994365,cb67d31e,68d2cbc9,ff790d44,366a6a6a,f85d80e5), -S(70f6d617,e21a9df6,370d044c,53804f62,9e6589d0,5900b9dc,849a8d05,719fd55b,5fc30143,ea245a03,ec0e9f01,a1e99f5,9ae16eb4,e693e3f8,732fe9be,b2c9b4bb), -S(f633f446,9b1617aa,8731ebdf,2b5e98e8,8ec97865,751bf6e1,f509842a,aba63251,3de28e7a,de2588d7,bc53ede7,3e9acbf5,5688ab6a,2cca8910,2ec03998,f70a6d28), -S(e3364ef5,183476d6,757ddd79,39447825,e06491b7,9fb5e6b6,c98e3280,e9dcea5f,f061aa9c,c5bb20e1,9084fcf5,a8e799ff,75670c3f,3fad80e3,ba3973a,be12b76), -S(c98a303f,7bdd7f06,3e09dec0,e9b5f449,f470e4c5,cfa11162,25517636,2ad7cf8c,94dec242,a375b65c,b1fad8a2,ecc6de3,c2f4be0d,e8751764,f320ad9e,35dc5de4), -S(fef6c023,5025dd17,5c8f5f02,78f7d9b4,515b7915,359e1c8d,bfa29a4b,67c1d654,9bdaca13,7b42cfba,f1075814,3409879c,249d5028,b1ef10e9,77a73c2f,749e9ce2), -S(c4413aa6,18fe751c,a50aeecd,478757f4,b23e8193,5304248f,8d93596a,fa489988,7003e5d3,3bca34cf,625d8cdf,f6910bea,16a39e5,dcd20fd2,1822b51e,55098cba), -S(b9719377,b83703f4,efb68dfd,b61c3d6c,bf9bb302,3747dbe0,c5c95437,6d56fe3,e57f0725,462f5f5d,b4c5162a,9b01fc,f52ea86f,6a7a5670,3daed54c,3672d825), -S(e72c8bff,84730fb9,7342adf9,67ad5eaf,6a90282,ed52b70b,6d9dc90f,e2395fa9,10f49bd6,79c3e7ab,21aeecf5,bea893d1,9836fe8,9a228a5b,ab7289f1,5f911543), -S(4e197fbe,2d935c0b,9280ab4a,26422b10,93a0fd4b,85a686c,7abfb2d7,621564b2,2c74f5e6,4e5205a2,7efa68cb,2ae9dc38,7467e102,5ef54a0c,4acc7319,4d372a), -S(88639d8,35b91e12,f381ef72,2c9308e1,fe898804,6432d577,7d515ea8,1797f360,1a49a5cf,75b1c8b0,a842f222,565a35b1,41b3c2a8,8d1b8881,34ff86c8,9ca4dc41), -S(a951d30a,c53e183a,9d74088f,8fed089e,1719f04f,39368d31,c0cd7b3c,b873f2ef,7f9e5508,a782c449,3ce8eea6,52195560,a1dc74d0,cfd8bb2a,4368fcf2,6ec783cb), -S(67028a77,3ff55e84,d4f19a99,f651d9e4,abcdd680,1add3739,c1688c18,22ccba72,bb611a0d,d5ad4674,e9a4fa5,63c6bcf9,a5dddf04,f195a9c4,c917d36,4d5a2ebb), -S(ba7643e5,13b102d9,f8fb5ae9,cf106d11,5d97a50c,d7e5cbbe,c13d24a2,be04a85b,f52f2e3b,88a49709,352b2421,2691882a,eb853ab5,7437e712,b83ceec9,2c25d7cf), -S(b3673761,b46a0444,cf221e48,22ba2f72,36e0c3b3,d16962c4,6e52bf2,334f099f,69dfa764,cdbca112,7a173798,abd8148c,eced792,b4cde92a,833db24b,992ae90d), -S(d6815b9b,296aea82,f1504323,1e6145b,cda92a3e,915daa0a,8a179902,7becd8bd,bf3ef3a5,8086833f,c579f9d2,2b7af47e,f97ac341,aa3aa2ed,2c74eb66,58178360), -S(b5c7dca1,94b68a14,fbd05f42,63b0feab,9e1dae1d,42dcac2d,1a30f70c,bee14c34,ceada44e,540b26d3,c37eafbb,12cf0cd2,54a9528f,77d37e1b,c19cd226,1aa70d08), -S(5a73c77a,7426af6c,f2d393aa,40189923,e47eb697,58fd76b4,5c8159bf,f7f8b900,bc90f626,9d8572c9,cfb6cebe,b6700fd5,49fd0157,ab545a5d,1f1970a9,47786b1a), -S(4e38c28a,e5fce8a2,ebee4340,e0d99788,340dc758,f3740072,41a297c6,41d8aba0,ecdf41ff,e5533cc7,8a9ee3c5,77dcf2db,bf589531,ca9e1ed9,d5b9e23a,27915eec), -S(59fb08d1,c85ddda1,dbbe6b64,7745591c,68bb7a44,608a22ec,9a83902b,14acdd61,f4c21cf1,6869d2e5,355ac8a3,227345d4,eacf74bf,af742fc9,413354ef,8ca1884b), -S(62ac0b80,e2040117,14a508b4,42cc0564,40f38eb3,e4f0e19b,4d8d05cb,bd19382b,e0d4ebf2,5bca30dc,95c0cfaf,140a0d67,29341751,881b955,9e03eb70,98ff11ba), -S(ec16d69,b7cd751,c44ea4c4,9b7c917f,45cf3c57,efd49263,58af0837,70c32498,8c8aaaee,14344b77,23c17e31,752dd638,fd8bc3ea,cace7522,3c712b6e,82d1316a), -S(3dd4a6f6,9d614c5f,87de1bc3,101beee,8b66a1ca,749842ac,dfe5ed3d,2d4b780a,2d5e6b54,464bd991,113c5ed6,50ff5af3,ca2a18f2,ab43ed6,5437ea13,3ba99fdf), -S(5e404405,3710c999,a77d9048,cc651c54,718936d2,d4d8d8f1,ef416a54,51861aec,c6c2bc4a,1e8682a,2426b02e,92bb7094,2f8db6ff,fa6b375,79b50146,66f31f7d), -S(66032f1,f55b606f,fc68ac3a,92683cb0,d447137,430ce435,9d1f06da,10954f99,fb14ad80,f168e517,fdacf38d,c197fa71,6ae1157c,ccf0948b,a7f0914d,ff8d040), -S(25c4c534,8ee76e19,799d3f9b,f56d3566,57332560,693e362,b7935ebb,85d7056e,1d7b9e9d,6e52f220,e82647c,a560c02c,ebd3f608,f11260ee,c9b16b58,76123b6b), -S(fd70c030,435fa972,793551b1,e409739c,6f148342,e833bb16,c4dac4a8,a853f0cc,10870dde,23c4097d,505f2d17,d3dd93d6,eb9c1300,49cb0fa9,2ed63c0f,feb73e80), -S(ded2703f,3fc6bcc1,eb96a925,650823df,583ae86c,cb43836a,19ca31e5,69c1cebe,5957989a,db61c969,8d61eaa1,938ad6b,cfa3543c,e13811dc,cf5b4ba1,24d62a5a), -S(9943048e,7097dc4b,709012f6,d298137,dc8e471c,a66ccbb1,f023bcb4,938c02f4,57fa4b31,b80df627,b9c212b0,4bfbbdd8,d1dfdb03,ece420d6,35d0ec9e,4e86384c), -S(313dc488,9214c7ef,960f2f95,b55b8083,d1adde1c,775f7f6a,62b57c01,aed5b95,bc02f247,668a334e,349d8ebc,6d7a1ba2,1f99ff1c,ddd10c2b,59aed3c0,815b1e5c), -S(1b9ce18f,9360e5db,8da1fa8c,f5ff96a3,1a898f19,2eceb059,c39f6cbd,4de5c920,84937b84,5336904a,4047c917,6d1f54e5,4e1a15a6,52a97668,6249987,82f230c6), -S(4bfacb3c,18ebd5d1,bf71ca5f,b1b6bde7,b314d2fc,ca1c05bc,f4021595,e15c6cd8,a33c205f,d4ac1624,d4ebb554,816d6435,86e08ce0,6ccc762e,232cc7ea,d65aa5ee), -S(f6843448,522403ce,a3e4597,30648835,2399f699,421db1b5,2fe33bb6,d21c614b,ce80913c,eb14f530,d153104f,202dad87,2f000f16,fb60316c,bdd40c79,4c95ee85), -S(930816a1,ca19458b,c2badcc6,3cf66d0c,6312f52e,853b5365,1b829b3f,2666ca70,4b29edf1,55385f57,63dc4008,77c846b0,4c810747,4def410a,c796f58,f61b849b), -S(b9d0798f,2ead9231,7face0a8,31869066,76711e1c,f3a9a465,8f51c039,7f76c066,4ecdaede,bae33f4d,79240d11,ce0b0564,62ad9f0f,51b6d7e9,e69a283a,4770053c), -S(1e8a7b02,60d58ae8,902fc57c,5a1648c4,e14d1a6f,696e7aec,c2cbe5d7,2e5439a8,e8c76d70,913dafc9,d157d030,8ed328fa,e08150b6,4a48754b,907954aa,4aeaacd9), -S(ac754bcc,c9c7b4e3,6551b654,a0620086,412db1de,14e422d4,c9111c64,c8b08b0b,3a8450b7,e841959b,93d3bc25,ced04aaa,4df90b90,d1ccbcf1,2fd88bc4,fdb366a6), -S(7e04fd28,1770ae0a,8fcb64d5,6e911667,a50170a8,3fc691d0,b0a8e1f4,73de3c2,73c37d99,cdfe5941,62b7b620,34be369a,c7da1d8b,e7d863b9,a90de407,24acb7b0), -S(ff903b99,13bc9005,8f237e9a,50f83707,a6f7d24a,d62142f3,16fb89ac,fad9ee9a,37cd140,36415c21,6e899a0c,2e8ccbd5,8f3eacb8,c88b1182,8436888b,899b412f), -S(d1edc0e4,44e92bd6,be858374,8f8fecb9,dab0d6f7,c74d410a,c412865c,9bf95d00,c10e796,3dd91bf7,c1754154,ec82460f,817d919,d13c52f8,d6578e8,52a8f87c), -S(62ce4177,9ba5fd6,332d188b,3a8ed98b,3883f013,731ec72b,8b0842d,ef0d5e58,ff141435,2b26b61c,ea78f67,de7ed56b,7895c03e,e3c28050,151b5a67,625b2d5c), -S(c8e885bd,5d0d5399,47addcba,879e7fa9,b075f871,e484f7bb,69081c47,8540c845,2d0d3f40,77cf511d,f93a278,91795dbe,e5087584,eab4fb83,e18e5d76,8d939dea), -S(62b1a52b,de107e62,4567357e,de49b08c,30c31e8,9c1743cf,a033fec,6bb8ab3d,9ed15063,ce1c8d00,1f19b388,ec678025,9cd5d951,4e263453,d5bf98ac,bd64d1b8), -S(88589c8e,9d35e6b4,5788bf01,bf3c6672,32324529,3d8014ba,525f016d,6f721e1e,be4804a5,d5b49ebe,8dd127b6,e55a7702,92a1c0d1,dc431fe,f5e4e873,103e1fea), -S(75e47add,7a7f2099,1a12916f,9ebe39b5,1409e82f,67afdf7b,d1d7464,1b83a85d,786b9b83,818e81ed,e3fefad7,c7203e57,99b4100,7cdd291c,321adcab,31b57bba), -S(d56588f9,982aa917,ce28e887,44ffba41,4cc1046a,a0122d2d,afb8715f,a9afe3b4,b14c6ab1,3a1793e5,68b171a5,1ecdf179,d78818b7,9cf7b1c3,97841a64,97b5e3c3), -S(9be8f7c3,efadd410,8c24dfcb,3a14a279,8cab4de9,8f5ec786,de7a4448,d9150e52,705ae8a3,a554f092,c677eebd,605661f7,4c463b81,97444d96,a5bda8a4,60315337), -S(96c95643,ac2805bd,421dfbf0,8a4801fa,69b6815c,bd31156d,f12207fc,48831c43,656b790d,35e598a8,dffed7d5,9b0b827b,3c46bb1c,3e5163f2,a4b71236,c6bb1b64), -S(9dcdb2ee,239faf20,2bfa036f,5d6adf4f,8d1add19,8def404d,a9447867,b126becd,3b727773,d3587698,7605dc66,12dea6b6,46052652,abfc3ec8,576740ab,81291e89), -S(b33d2b97,e31618b4,d9273d4e,82893e01,d85bb2c8,7d0d1059,f989bf3a,7022d2bc,2c447cc1,6e680637,12a4789,6ecaed55,83cc9e94,525d7c19,9e47416a,8569d5d), -S(74232d9,547bf3eb,fe4921dd,92d77131,3f5c97c,203c0db9,12106698,aa9d5c8e,6fd43ac9,ac04eead,7566e40b,3d04975b,315a36c6,e5b72cd0,14d365b1,b7a3836), -S(937ffd12,72a7df14,21df0c9a,3e015d0d,be72932c,3489fa2b,d34f72f2,763469e8,55e9e0d2,54d3379a,a6e35511,acf9dcbb,372d5b8f,271bb7f6,4c2cf77e,bf624234), -S(1513a5a3,7aa52a65,d659a7f,b0e762fc,67a8a196,8f2b6ae2,bdb02955,5d92476d,8d99d771,6cc3d831,9eca3b97,8c91d239,a7ef6b03,a13eeb25,ad94f4a4,20ad3eb9), -S(c7464b4f,bdd39bc5,4ce45b87,e4db3a3b,22fc52ac,b649266f,f7dd69bd,65b2843b,bc0d264,e48aa14b,bcbdf505,9a35fe99,395f03d6,60635150,cb8424b0,c93eee25), -S(cfdc9326,cede0724,5a89824d,1cfe590,c0945793,88812f11,4bed6577,ef7432ce,a8df1cf3,5d471afe,ad43f88e,46e5cd84,ece5fe8,fadc55b8,e79d6eb8,2466a270), -S(aa5529af,861568f8,cd4ac26c,fb1f5e3b,5ddf564d,ba4f3b5e,8d3ec5d2,606530f8,3273795b,31e53e0e,e34ce1d,aaee7801,309c0315,926eacba,fbb0fb6,4f0a948b), -S(206bf37d,599c665c,1bd20187,93f526af,1099819b,4780f2a7,6f5c3797,4eb404cd,7de063ba,3271773f,56ca358d,335a015b,8ae8a45b,b4a9cffa,2f20872d,9bc654b3), -S(3f21852f,621d5a6d,4c91f27e,82018b7b,4369c15a,69664cc4,6cdd8195,1f3ef14f,db8e7b5,fe7d9972,6da564a1,78131727,3ee6e005,908513d1,3903aa3d,d036123), -S(4c562c1e,9e4bb491,17948e93,f94b4146,c918554f,7d351300,5ef7f181,2c9900e3,1809f902,c6f694de,7909c8e6,ea4e938a,c1d9e6af,7707bd05,3a7d8560,24875012), -S(a692c8a7,a3b306de,48481c93,8f0a9814,e081bf11,6857f217,4c1ccf1e,a8448a30,7a660fa7,def1429f,4c72e44b,9fad10a4,7639942f,56a647c1,d609f3d9,26a40a9e), -S(981d35b5,5998f57d,58a62d9d,af65e53b,419b99d8,2d2eeea2,bede4da8,ec400a2,d20db6e,211c3ffe,ecfa43c4,79a43ab3,8590a142,9d9520d0,62f1ec1d,9f1c574a), -S(8afa1616,3350087b,1e286bfe,5d610463,41adfef8,8b0fd809,336137a8,92d32e45,54924c6f,5c2dd61b,e5b1186c,7fb8519,29af1989,f468049b,bd5c3cbd,387a28c7), -S(ba7cc113,f1e3bc3e,ae14c2cf,94fb1ee8,bdfa60ab,52582ce3,595df63a,d08c1e17,ffec33d6,d42e2233,baf02780,a60272f9,3531b1fb,158a4bac,6c6a488c,fc23d03e), -S(166f2dc7,661c9e5a,aa51582f,4cd08cbb,47c6afca,143c4231,36144cf8,ce69ced7,132e0d13,6a292cb5,9f0503aa,589b37a2,dd1c9244,c492b8ef,647d79c4,778bd94a), -S(bc9fd332,f66ac57e,46ff7801,a7d38b0c,f2befd5a,2513688e,b29fc5af,902f1c07,8f58e1a2,2958600b,dd64a428,7b6b25a1,dda32351,dd45453d,d03b99ad,e406e240), -S(e363fb9f,77378eb9,2600491,386a884a,24839001,cc516bd6,44cf6e57,b1e66507,3f83ecdb,907afc42,b47ca948,fdfd3b73,dfcf1e5a,7cdfe1dd,41a188a2,1b5f8b1b), -S(c8883193,9b5b7ab2,2af8763d,52efbd5f,50939606,920325e4,805842e1,3faa3cc7,5db2a08c,6e8ad455,f542d2b3,9b8203e1,39c5b0a3,d1fb1ac,763ee4b0,4b9c1f7f), -S(76149173,1a20a975,16607b53,501c45a7,f94df1a6,e0f15301,bb0bbd4b,eae97439,e75b67c1,fc2bda74,9f834d8,c9439b43,c33aa4ea,f2fb9116,9804615c,8c1269c5), -S(8c19284c,f62a4116,a40ec5f5,43cdc2b7,e7615400,d1090f86,2f378ac5,81f4b5d8,bd93accb,5c42ca6d,a4e6ac37,b2bb8359,42bf659e,a0e6beed,bd754e5f,749bce8c), -S(7664fc89,5d8de0b7,b19f18be,cb9a9b1,783f97de,3167bc39,7c03d007,18311a7,861d8f0f,125d051c,9f808064,346bbfad,410fdddb,aa31aad,cda7a713,1d65a3a), -S(7aef0296,33664cd7,694a5d0,aecc0466,541535fd,b1540c38,8f0e0e9e,24e96b77,e02f2ba1,8e92d161,33d29d1a,c087cf29,3a91acac,662c7208,b9157032,d0c829ce), -S(cd222d7c,b49b957,e5252c06,7f649ec2,dae145c4,d82a82b6,8693a242,6b7ba40b,c261f956,dfbed5c0,e876492d,7325b964,3dfb2075,68ccc93c,14b1e8eb,d3fc1b59), -S(5055e224,c61b34ec,9cbe93e8,ea4c9488,19d94338,edf6daf3,72eda45c,da9f0971,4fe31a71,bc782d4c,720add07,4cf97c47,dbc1f38a,3a9d9cf5,955e1760,5f185651), -S(23a80902,a97669c4,4b20f49c,fee841a6,b5a99b5d,d423f4a0,5d573a3e,4833984f,6a57ed,265744e,f4d18250,435f695a,b80b944,d0153b77,e9e9a20d,bd98c659), -S(b9879ec3,2ad8fecd,35022a2,1625c159,a31a72b6,5d3f3c67,5dc8e114,c5f59de1,439d2afb,aecc48f6,310e18c1,2e31c9c0,cf91162b,43b153a2,f901a19f,1efe8e10), -S(918e367b,531fa89c,8ca89c2d,cad34aba,c937cc00,be3a2b18,bd1585ea,c4678a4,800078df,6b700c11,85418749,27a8402a,db41811c,77d0fd4,aa435c2b,7a3f0a2), -S(6cd0f4f1,c03f35c0,65815638,10906fa9,a41bbc26,da1bd7c2,ef39a4c4,66e49252,ef644bd6,ed42cf0d,3ad17638,5c239fca,61056021,b001ef9,dcafd370,cdc06156), -S(8a0c443c,3e26680a,3dc8483,e0a067,553f7ffb,af939922,1c35a766,b12286c0,6c30af1b,9a97958e,11d1e24f,3e8ce846,1ff37795,556772d1,56514015,a46951b1), -S(563b11b,a7f5d351,729b8537,1fdccea5,d7081262,8c1e265d,10c29172,d9a3252d,81c0a2c7,8b36ca17,29c9c02f,8050e3bd,ce46607c,5409c50,10f8031a,ec872593), -S(27e88b96,29eb9d92,e57ce3e7,75063c04,4a1f9f0a,dc94a139,abe56b05,77718f94,ea04c851,41e06d26,31564122,80c86d83,89c1f15c,3c7e98a5,610e52ea,19b1305c), -S(95288e29,a554b7e8,15ee68c7,16772a5,4320a7b1,20a38865,f3838345,f9edd5d2,d81b97b4,2404966d,3c4160e1,59f275ef,b91cae46,d9a33f51,34455ca0,496e4472), -S(b86033e8,e3bde32f,859f6af0,bb87b72a,b1b88648,776e1e14,273e52d6,205e0186,e120cc94,5de7563e,915979e1,15ee7cd4,4875d50,bf6b93db,8a133cac,227091db), -S(644a2090,82c7984d,447eeadb,2b21fb36,599d2c1f,366a3af3,44afd230,9b780c8e,b49cefa2,c0865df5,f6f6df65,24b39f7d,67eb07f6,ab6e550,390351a6,a2a1a00c), -S(1f2c4207,2e803f99,d1389efb,209ab0e9,2d7891d2,531f6710,60371c19,7b0f41df,98db8e40,69dab24c,4fc6e13f,37e805bf,45d30c28,9d4455f1,9670299f,a6c6a804), -S(dab5435,220297e0,e738e798,f1f8375f,dc813874,7a633f05,1be409bd,d6a3b8ab,91b6c193,de219ec3,ab3d6635,d4c41a1a,6059372c,a8afe185,7013e474,79fcb382), -S(5ae6a897,467fd90c,f693a5a1,d89d4fbc,4f11680c,86f5f99,30af1866,a1f27137,40612777,fde69d15,7d51d85b,137fe92d,c269c42f,4423531d,548fe248,44d0502b), -S(9bffceb8,9acee7f4,68cfeaec,6d597672,6f227197,6506c5b2,6c5cef5d,7545265a,a265cc26,fd6332b3,fe6c7487,23ce3d5c,12eac750,59947de0,9face60a,4df250a9), -S(f38cf54,b77eb8c3,2d339dfb,df288a11,3058b4e6,2f8c4ffa,2bd29e2c,e6c7b677,2daff1e4,54069fd7,63f422a,15e9cd91,65b5d97a,ea0cbf55,103dd751,9faa55b7), -S(350d6b26,8058c8ce,4684a5da,32e3eae8,caf387be,ea9c95c,311d0209,47122dc3,8ff3be71,e94dd657,281c9f28,780b015,1a2abf2c,2c2ed9fd,e7d0adda,6c5e0690), -S(1ab92290,615207f1,34859fcb,26ccc8c,ab9d5ba9,f30d12b1,ecd7210d,c68cf573,2f1c5e0a,53d449d8,3a5d1507,9992dea1,b481e607,e6c99f7a,5e0193c7,2a426d61), -S(9e98be16,cf2ef9a5,fa3a320d,5f844cb3,c715420b,d44db10c,8f24b0c8,be65cff7,9ff6de6,ea416ea2,72d8e438,e132a86b,a03c272f,378a4726,aa72800e,d0214a3f), -S(9e7b45ed,8f0738fd,58784c7d,a42312a3,53f12676,9fc3ab56,9c4cc69d,25a5b1f,22be7dc,e6e513c6,1a733f45,980f2f60,ff4653cc,49391baa,f4b27174,98f79668), -S(6b6c1553,cab82490,7c5c480f,88daa7f2,7e57b870,5110e1e,7e7a5be8,4314844e,4c10d4fe,d431a4d9,6b719188,b2027764,53885709,eeec2837,32832497,319c9626), -S(1d28f09b,37cc3c4e,3f7ee903,6adefb71,6423e5e5,8840c6bf,d3c03151,db723a1a,acbaeae,cbdc3e9c,85e36db4,aad508b9,9a152373,547613c7,a3455769,872e55b0), -S(55e861ef,3de7675d,857b8ba4,73aec3e0,de0f529d,3a9f4a04,11ec4d4f,5a996d75,a942b32c,44618065,af08a1fd,73e052a8,78df075e,e54cc160,eb9846b5,d46db7b3), -S(10f1258,4bdbfbc5,6ce7b023,78a5e908,9457956,65f4e49f,a53f7143,3deda9a,4ce2f90e,efc88f33,f12edecf,1af91612,e3f84dbd,91f45bf4,5833012f,63e02398), -S(48ae6885,ed275a41,2bc61a67,399ed1aa,cb968182,2775dcf,9012cdaa,a6b21ccf,8b4b5cab,e5471381,46c62a82,102d43bf,5b83d993,41d026f7,c1525ed0,8c2238fe), -S(c6f5c5c6,73642a35,59c06df0,18527de6,7fdb9f4d,75c98f01,8f45913e,932c1481,4a4d4894,e31d2adb,d150b184,51cf16b9,cf7e3741,c4ed2511,c0765480,2f59fde8), -S(f38923af,ff4cd9d,cb16d571,3a68e18a,7fc163d0,8835d283,3676caae,5156fe49,e36986c8,d7e07fb5,6a1f4266,d980c113,43cad9cd,f7e4619e,17a45642,6425eff9), -S(10883b32,87b20d7c,7e60048f,13f179db,e169b82,f9a95f87,5271861b,36170d85,59be5146,d328574e,d837776e,c0748043,369bad42,b38ebe6b,861861a1,8c5307f0), -S(87262e3a,832a6c07,d6d32fe5,8f0e85c7,40591c6f,21da8ae1,5f8fd137,454a383d,7db37cc3,11decb91,cb4fcb0e,9e73bf0d,c91b3a5,53292f8a,f5036dc1,baaf4473), -S(cd4b75e4,7fc954fb,b71c21c8,28322c9,a54871f6,2ba2a803,780954eb,46c9c54a,6cbe7868,8b5722e6,ac75f9e,c93a7a4,39350a67,7ef31f53,c4c73b33,cdbfe124), -S(468fce11,bbde91ec,fa738924,9a07a39d,b0851d0c,3cb60f96,cbab165f,f5c69242,93c66305,d55a21bb,e14bc51e,be8d9c8c,14f0e8ee,caef9b49,567a8f03,6b2d06ad), -S(f5d9aa66,9cc173b5,5850e784,fbab08db,d0f11e6c,fc3243d,ff6d1a7f,89f517d2,aedf8598,b11b8c00,34f1e3a0,ed4c6c2a,db1688bb,35bad212,ad692896,2b045d13), -S(48276e7f,91c2068c,161e97e,7587a30,a79ee120,cc30a9a0,571da1de,53f9e253,a59189b9,306aaa38,848b7b7b,4653e6bd,68944d6b,46a4899d,44ed2367,3ecc241c), -S(7709db32,f9a551a,23dbdb7e,824fcc7,720f24c0,3c58c68f,d2b5ce2,cfb59cce,f8b35a2d,ec4b7698,58fe791e,c240f54d,8b5ffde7,f24119b2,7ab20fcc,8ad07f0), -S(a7b6e973,d1c62f03,6eae2674,bb5b37d6,c5ce3187,41776833,d7f3e8c1,ed2e6ac0,116042cc,3b409748,162db6f0,69ebdb11,53aece8b,37c277eb,28c9a2ba,c7c8224f), -S(7c5f0e06,652e8870,74d0bc97,e9c0023c,e2cac507,659d1a07,5f9c9fae,2d77afc0,e9156afa,24565d92,fadc1aea,f49e1bc4,b28606e2,5bcee2ba,f7c9a87b,b510113b), -S(14a0e517,1a796c5c,1bcfdbc6,f0431dcd,6fb7a8ed,4d6f1621,be01cf2c,64ae0166,231ab7b1,1c3d84fe,1e35b994,43d7f7da,a0bb4e46,834e92d5,e5c689b8,427b24e5), -S(fec19af0,286c251e,82aa7ec3,c5a8b048,9ee4b6e4,8e62c59f,7cec1aee,45b7323b,18cb5d01,5506074d,c94d0a0a,261301ce,d042405c,e4f01f39,2bfb40c7,62b47a8), -S(5788e079,beda8301,e290a04d,dd11c173,6112ac99,76c4857a,ba479485,5d457873,e2c6e721,b5bca7ba,add95284,9257927d,86877477,e8468b6b,9235b30c,557fd7e3), -S(513c9124,d7e1726f,73b39525,377c2761,48697c71,594615b5,f18c6695,b4d589a6,659ffbe,fb3ff7b0,2e5ee01d,eee0ea65,8a562af,722076cd,3cb2ec56,16533beb), -S(d96da66f,fa79adb0,80d06968,bb9243c1,dc6dcccb,1e9250bf,6243a1e0,9578ff8a,76eb65d9,6d520da1,34941ccd,8af2f32b,6050feb9,2ab39835,931b901,60a5e481), -S(37033146,69c7eda3,e598a616,12c65c76,8b5cefd2,3371928c,191c3d16,4d1b495d,fb886600,ffb6e95e,dc704a62,f5105795,474ce36,45d54d24,8cc53fdb,7a28e978), -S(493d5ec5,ea8957ce,6608e59e,66e8a6c7,a8aab1d4,fa14230c,8c3a6288,37e60b2c,594cc0df,dd37f4ff,d235e2be,1cb98f61,8485e453,6c301d21,11267528,3bbb5097), -S(71e0fd4,937ae3f4,84d521c4,86f01485,a94bf45a,6a0d2472,d7c5b97c,19d99068,7551009b,73422956,afab9675,1dfa7eb3,9feeacc1,4d220714,1cf157,78f7087e), -S(fe36f2fb,971a1eb1,9a158190,cab6d80a,60601d96,231b5aee,b4c4b332,b35c7031,f72e5fdf,b8ac9af1,263f5492,2caec24e,dda604eb,953a3b02,4e29d70b,55266f87), -S(c734995b,fd73d82b,8555fa56,56465102,b6b14813,272103d5,2de7d6db,fb9455ce,713ab271,3c718906,3faa274b,dc2bfc7f,4f65dbe7,80e07c0f,7b625d70,89f31714), -S(e56a3832,f58b284a,6454f8d1,73f2dbde,b8212cc,a9196524,e1856c98,6dfd76b8,cb301f78,26b39496,6d9f9953,7302ec8f,27af592d,fb8e7e1d,acd5242e,ee2b8cb9), -S(c511bbd4,e242f5fb,a2202900,45f4f125,ab2b588c,f9b375d4,4910fa55,be8ca373,3b96300d,7713d05e,d22eb08,bc039eea,ba2f36f5,80398e61,b3a74581,5f884408), -S(f7ccc53,75c59fb2,90408676,ddd9f1d5,ff6d66fa,1172e0de,cba38ea8,a160a457,45081507,f4a14598,ad0f4278,1f14b8da,72ce889c,f23b52c4,ec5fd1f6,9939e054), -S(8219112e,48f1a2b7,7a03f20e,3eeee016,ac69818,f22adf72,3679e2bf,3586dcd5,205e4b4,2b9ed249,a63d4a5d,853ecc4d,4d37b0a8,4841e959,d46ca7ed,f42a7c40), -S(34df67c5,b0a9400b,9b9eebf2,132426c6,281bfbb1,402cd49c,1fd38bfe,c19f6afb,34066c5f,d45751fa,df681c95,791fba62,79bc76cd,a70ce02,92ba7c41,34fc5d58), -S(9b969626,16414928,6cd8ba65,75572291,f1a885bc,1ef82fcd,7c445637,da1654a8,12e52b50,2fda57c6,ea330d5a,415d47d0,a1e5a138,b7968c7c,3543dff2,9578c13b), -S(68add94c,a17a6ef3,85d23fbc,5d7763b9,15c29bc6,2a520139,24154a60,66d0eafa,281bd1a5,71629916,1a911be9,88a13f64,e8065610,219bdbe4,5271f4ce,2113d77c), -S(143eb857,7844f677,2b01db8a,d6cb84d9,fc1bda3d,638325d,b29d280e,16a7f36e,a50cd3fc,f771ca36,58f2b9ee,4133f17e,d72383f0,94492358,76bf04a3,296b7df2), -S(7b463842,1537aaf7,2e6f0800,cb9c0428,b1dcd22f,73694b83,63f9b2a6,86d94bc,3bed2d2f,c7b5a092,e6e8eb33,1f945a24,65936fac,90a3f244,942895be,ff42895f), -S(1857638f,ef86615f,7bf0665c,3b5d9cf4,c51690bf,c96481b5,78d30131,8a32349,64adcbbb,22267bec,c7a40d4f,6eaf66ad,9c133182,b4af858,6b0c4aa2,e30a37f2), -S(bf84f3bf,d726e0f7,2463bd38,4c14b35d,f9502148,4e78f001,b848fdc0,4d7a823b,4cbaf2c8,71bd8ecd,4439fba7,193a9bca,d26653d7,a4dc7a00,f0a35189,e1949139), -S(4482f7c7,1bc8f76d,9bfe9148,77ac76a7,6131501a,55fc5556,c4e95ac7,68c9ef11,f5af5b16,10733ce5,bdadc3e6,d1df5de1,314495df,3185f7c5,14151c94,908ffcc2), -S(715e384a,100bc5a0,20857ab2,57a352a3,b7ce41e1,a742cdc0,ab1354f9,d3483e93,13703919,b85f567d,87d2e6ae,c2ad89d9,743030f,9b32f277,34c3e9c1,4b5fb1d8), -S(ff90a61b,98f591b0,ffad3ad,3dfc0432,1093acf6,18b0f71a,f637a335,e9627726,908c8caa,f88ae7a,c215cc30,7d7fea86,1d69ca24,7b1c0949,57f022c4,ac130335)}, -{S(d8f08d18,ece61855,5b06a3b5,ac8e7cf,a6375446,cbc7c8db,ad924f78,69e7f00e,46a91d23,910957eb,db830624,73839954,2cea0570,2f67a09d,d7d19217,646606e), -S(fb32ea9c,4f434cdc,db41595e,58f16466,7fd92a08,8a182823,137cd308,9974551f,415b1d67,d845a304,a92f9f62,65d09c20,32bcc521,4303d791,95b05cab,95ea05c), -S(49523899,174fdf41,e4a551f8,423da35d,f3cf0ffa,1f2b8b12,d2a51764,9d8f8b91,6f9c0b72,c5c6fbe4,3fc3d956,7e4bb980,975b744a,dc9ecdfa,8ca42f46,d7164130), -S(c02d61bd,9ca243ba,f2907638,3dade862,bb6ec35d,861a9829,10a084c7,7dee331,fa82b2c8,f015d9c7,b7329bcf,51f60a93,60d54d5,2b24506b,db542d9b,23aa7e6e), -S(a344867a,cf07375a,295cd97f,68093020,af6a1da1,d871b330,a52ab3d7,b4cd0ae,5b1c6f72,531ff281,88ace548,4f193dfb,b8fb233c,b251c788,22dce3bd,3a824c5e), -S(96ba694,48bd703f,a8aa21f2,4257bcb6,2e98751,42d32af,63bb6a37,4ad262c4,35c74902,7d4d0a4a,1550b7ed,cf791da3,7aff1aa3,a446225b,5ce2c0da,aa85c82c), -S(278eba80,511ce15c,f00617ca,21d62211,35f5c4c1,87d959aa,cb098b7b,4b56e51e,ad903485,bee432c3,5ec613a7,68175d93,4f0e855,28b76b41,1c6ad8a5,510510d2), -S(554be9de,b938c4a6,fadc2fb2,77178b95,37719f20,8b7f06d8,7993d06f,c3500bdd,931e3263,34c1e96c,a4c88583,92a8b7a4,c17f7582,e4d0b7eb,6cfef36c,7e2d6f0e), -S(26a4f40c,968bcc7f,cc4002ca,b7ee20c9,3996a600,b4f81df4,66692d3d,5a6c19cc,67f7c990,ba734ebd,af5b5263,cc28624b,9014b7b4,443ed322,fecf49b3,3760b5e4), -S(67a90211,86d66afa,172fa6a1,dbd9b3af,9e3fc726,e5ba6916,59f066f4,fdc6af14,23ddf5f8,96203f49,9be9db01,5451305e,57e51d54,95672895,3968ae1,fcc835db), -S(d3bd63e,d5555686,fa88a122,294ba841,33be6280,17a21f65,285d4651,214b1ecd,f0fd835b,5f27da51,1216ebfc,f5af7740,8fc053b7,dedbdb37,40f6fef4,4cec8bf9), -S(f0dccbe7,ce8362ec,e7f8d550,b0967d4d,fbf6f9c5,1ee4e7fa,b3ab9b50,2b0411e4,7e63fbef,ed68f1ee,6f3143e7,a8e5f2e6,edc77db7,3d34b821,1e062b36,6ff0b8d7), -S(56cf2a5f,d7f41d22,cbe716bf,183a9eea,370f9bb7,5620f460,56c9023f,b8402952,600de0ed,c86b4f7a,93423beb,6a2b29de,749d05b0,4725b5c7,2fbb60e9,7fcf815a), -S(1a60d0d1,73316260,721542e2,33c6be2d,e0088476,e24fc61d,3d0cc619,dd3c1564,bc90efa5,3588b420,2cd46e61,a826a47a,b9f5e45d,eff920ef,100efa34,c179743e), -S(bc406d21,ba9b9a12,a38b6572,5490462d,2be4d0c6,8922fa01,b02e34db,ebfe8e71,6ca29bb6,878fc1dd,13cf814e,c9bff5ba,12a3d55b,13c3aeb1,6d588ddb,371c1981), -S(376ecde8,891b479e,490c80b,b81d15c7,c5b19a7d,4f838db8,b580338d,5745e583,9296ec3d,9256e491,3ccd38f2,e6331513,c7040e20,4d0e8344,6e9e8de9,42699fe6), -S(64cb1c7f,ec791b1b,7b94c8b5,969410b2,52243c7c,3068eb11,99d2a56c,aa2c1330,f43fdc60,76e80c11,4f19dba5,4f51da94,822a98f0,986ebcd8,6160ec7b,b249227b), -S(6f089f0c,2b95a26,e3cd8d95,98469f,c0795e0a,6be85b5d,fcb47071,c5413db0,dad7a3d8,e61e2a7b,ff7f9357,314d4405,8cdc1aae,c1bee22a,461c6b41,23ada4e2), -S(90b30e36,bfb33081,d54a5383,c77116cc,50e1a333,1b319150,98736d29,e4bad6f0,589000af,241a4c83,bc2defea,9b653ce2,988fe376,77b31abd,7f384762,758e98b9), -S(82f0acf,4a764dc2,59218ff3,397618b3,2e341ed9,6f4961c5,f5a6d559,654194f8,ac0f10a8,4728d82f,b8784cfb,b72814d6,868006b8,1d00894,26825a0f,3c3404b6), -S(3460815f,6036aed,4a2e264d,8e17b1b5,6c10d77b,5c021cac,69ee3a4d,ffb3df8f,c11a4b6a,c66ba79c,e6bd00c0,286aa96,de72f162,3a4f8d3b,1a4bc421,c9f33340), -S(b8c0311c,c21b7f08,46e66ebe,f3dcb726,53de4e83,4e450a06,e394d25d,195cb7e,64d4046d,6ef0fd1e,30a71c10,d85f0f07,8ce3113a,e904764c,c5a29ef6,c983b327), -S(f7bdf7b3,b610fcd6,cd2712e7,7a30d38c,2df3bb69,183ee96b,408bef1f,f57dfc59,fdb15f4c,61f276f3,343e2ca1,38d69b12,339e7e5a,dcceebae,39c768f8,95a0bf92), -S(ea32acb5,b5ef1dda,bdd4ef41,52ee856a,6e298277,f5f9c95b,e1adf49f,cba85262,1c0c5f11,3a3a033,790b073,9317fbbe,874afb39,72935a3f,52a309fd,6432e0d6), -S(e184d302,f708d25f,5af8d023,cb6b416,ffda5bbd,9f592edc,ab4f1890,3671b604,21c74686,4200438e,9cf66cf8,19292129,dda4fe13,965becca,8a1fd18c,e753abe), -S(69e75799,f0c0098a,3225e598,a7e8fd98,1218de4c,42aaa680,4ccf7c92,a45fe071,cdd2c796,c85d0930,8aeaa1b6,9a535c5c,6cf9d607,b2b296db,33d0b61c,b4d7711b), -S(a70c1082,119c47d4,75af4a96,1e61f0dc,284733af,c89e403f,9a5dd65,d465980e,3193967,8665bfd5,b37cd1a9,62f86cff,43b5f058,ae9045fc,c571cd62,bf390e9f), -S(f63e5154,9819926d,254f76c2,6d4a7b95,f01e612b,8b885073,f7ad23f9,dfe82d32,57521b53,d9a8a71f,71ae4b31,df7999d0,40395ce9,f0b70cfc,396bee62,40364b68), -S(9f62320,94d674fe,3959eaf5,b947df18,7e894594,8becef29,28bf7aee,983e108,9430b33b,5bf4d79f,1683da6d,ba74adfa,dc19489a,be9eb3f8,9f00a793,37fe9b38), -S(9802daf,4ba214c0,d19ba4de,77d92223,7f120914,7595135e,9ad3c75b,7731638e,98cbe71a,b035839a,3a2f3449,d6261dde,c14501e7,53523afb,4406c657,1fe5d2b4), -S(e86c5944,58017291,318caa82,8fd86a2c,d4ac8a67,c42dbd2f,f57b2b38,f47c9e0c,9e069a55,94596844,8f5bc2f,f97d9660,62f99bac,f74d46dd,5196b37f,f8503c26), -S(40d57e52,c21f1daf,3ea1d981,5f4da45b,807f083b,9e68f2c1,ec5b6d56,e2921871,99115564,76906b4e,5deea9ea,29ef8dcd,c1841b15,bd662ab2,720a28ae,d788e9c4), -S(b797d0a7,4ed78f63,475364cf,fdc42fd9,8a3fdaca,19c7decc,cc7cf10,7cf2f8b9,cbae44e4,773eae4,70f777ea,cc108650,fefdbf31,723eeb6,a77ccac1,129c3cbc), -S(a1b4bb86,61ba1626,c55158af,f04dd2db,b9bec0e2,943d91a0,1b043756,3fdea24f,fb8977c,b1088ff6,e6a462ae,1b8cca01,a0f6c737,816c3b3,d28d8ad7,b42630f5), -S(862cbd75,f1b8115e,45497c3,ce7f1058,200c3bfd,d9cc6ac5,b65b2e4d,abc06241,ddb98861,50925a0b,1c3445b6,a7f418be,7d5ee05d,9b7d1cf9,2ec5b633,9b0a5002), -S(45a2e88b,38c2439,53a33a6,e75c1e83,22a9f14a,bfd6e7cc,db786490,932caab4,23c86383,6a2e35f2,b9b7f8e7,a88ce40,f600eaec,af84848d,10ee1739,7341516b), -S(ebd1c9b9,e01beb16,7504b3e2,80c00ecc,6f44e085,a86a1b71,fe13fd87,3df558e7,d5ef72b7,10fd592a,64020176,a4aa890c,99ce47c7,f3d01e49,349aad20,b6e38c74), -S(1db6b315,14f71408,e876aecb,be1ffe74,a09b8e82,9f05c3eb,18186e9e,b461696a,c7236c85,b7436661,c2edcbb,5247ecb3,2a7d62e1,6d4cdc88,a7648b29,62dca534), -S(51704f97,7873b83,2e36660c,59658078,5acf0396,d29e046,5717ef5d,129a3cd2,672722c0,18401e21,e053ecd8,a219a972,b57b4b1a,56a8c767,7c6b53a7,f0c77a8c), -S(da77e611,fc5ca13a,65bc55db,af4c6c9c,43a7fc41,b58c57b2,4d25925a,99b22bf4,cff8b8c4,a8d3227a,919899c4,201f1bbd,49cdf4bb,506ad705,4c8e2f1e,a6c9dac2), -S(e7daaf33,ef909752,654c1b25,376be54a,22d0b5a6,b35655d0,87a204e8,d1830449,718d5a10,661fda9f,e6bb3fb,a1d3718f,fed1e441,64adc00c,f752ff1d,35e4b020), -S(ea15fe2f,cd9ae892,ff561ad7,7cd2be6,cff695e0,5cbbc15e,444cb45f,10d13269,d3d9b9ef,722dbea3,20a07f39,bd1b52f3,271759b,91bcf24a,caa6945,47d05cb4), -S(60dcb663,ab81db6a,89176bec,5a6a381c,bd6c8b66,de4dfda2,6d50c407,964492b1,42cebc,b7972c8f,e97e440,fc64c330,e4cb21f,114b852e,6cd7dd35,e9c7eaf9), -S(a975633c,5a609935,9c63714f,a474b40,72862cdc,1a3b1bdc,dcaf646c,1197dc9f,51f4cdad,89e63175,49c37342,d757b326,2b1da11e,1617f4a7,b0441c6d,8a1b9664), -S(b5d14a97,7e06d85c,f6189346,bf392516,56f9e92e,3e3b95e7,200cb68e,7a9bb4d2,27979c8c,d556d442,4d128608,8ddcc444,849df743,ca3ea38d,e077f8b2,71263654), -S(581cf880,1cd23788,8be62ec9,e99f814b,939fa6de,f4497b2c,bcfaf8bb,f9fb217,a211bf28,117f8b31,28f353f0,a3ecd2db,d35435c0,79b39b9f,2d2ebae3,e39c2247), -S(38e354da,80f408f3,48af877,138b8b32,f18c1a84,a5323e3e,6a275bd0,34a18ffa,b22ceb25,690855e3,e4e75553,b6e9d619,302d7b8a,f00226d9,8341e406,4d5d9e9b), -S(a62c3ca7,31e863eb,f630dddd,c75f7a7f,315b1a5d,8ebd7659,7d63294,7651524e,bd2de025,270f22d2,41927db1,b2d83c3a,6c4593b3,c93bd192,ee490b0e,b4b896b9), -S(cdf7529e,32b73c24,39c5e793,cda2367b,8cda3ec1,12b68572,5fade16c,5de12859,34003733,4953c33e,3aca52ae,7578a837,64218bd7,661d15,e4e6b150,88f5372d), -S(b00ee5a9,eec1ec97,a673404f,b67e8b01,26051e51,df23ce94,1bcce1d7,c9c0be80,d0ecff3f,45fe1bfb,7d7eac6d,1b27f465,80b22bfd,2b2b0853,c382c06b,df1b1be1), -S(bb7bd0bd,f9b827ca,28e7ad35,e7e42ac7,ac667dd6,5f64f18a,2af8b385,774f7382,ca9903a3,6fab02f3,31afea78,71802d82,6e45fc4c,e7f1453a,ada65ac9,fd15942b), -S(c2e32d40,c675193e,a8097d9c,9beec3e3,64009574,11e46e7d,520b5fb8,44119d69,63c49dc3,5c2ea496,894da7ff,d8b33e82,c70e44,d0b51caf,6e9d6235,c8d78f57), -S(20aa257b,4fd347b,4361295e,bd969d65,60366497,bd0f17a5,5f9b8142,827081ce,c8a82baf,9b95576b,34b6b80c,2ee4669,8bfd4562,59ec9911,4b58bc74,cda90533), -S(35095083,4f7f8218,6e0a8085,2cf56948,3928090b,84d2c068,e0c3c4ce,9819c4fc,1d0bb1ce,2c061784,35df09fb,c21596d3,2334bd77,ad1206ab,41515089,93589b81), -S(4f731112,8d44033d,7380e5d9,71826f5c,1f1cc587,fbdd361f,be8974e2,2526a2c,69d35d5c,e051f2c2,54c8b68f,40033467,b516378a,573d7f22,8ad5e070,f497109e), -S(34746007,54abb4c9,2b9f1a9b,33b51139,114bcfb6,ddbe9e2a,1e9182a6,ba52cc5c,29f6bf7b,7b31c57,b83e9f41,a9fb151b,744f0bf4,bd2dfa1e,5a5ffd14,e3528ded), -S(62f72456,b06b6bbd,70c2045e,8c1deec4,d1ca74c9,aeaf68c5,52d424f9,be280edf,13e619bc,d667afc5,81d293aa,3bcb80e,fe3212a6,9750e45b,94740aa8,286c72cc), -S(b1d18497,47415d89,7fd3b791,9e2a1cb0,e47efc1,2f6dd61b,93da9d5,99cc3083,19eee106,bf3f71ac,436cd33d,9fbccc4c,2ba50ebd,20e93478,ff0a6c9a,96fcd5fe), -S(9f8bdabe,3e85c253,40047952,812a913d,f9d83038,d869f535,e5c7ae7a,c286ef9e,abae000c,3e24af88,242df5cd,3a3786f1,7c8f1a7e,7604be96,7495b6e6,7ec09284), -S(c3d3786d,31cbaf4,57de58c9,c3ac3527,ff40e817,ef36bd5f,34c005f6,2967989e,b39ece7c,3e76a6bf,fd14dff0,a066e977,6565bc22,5c26d446,5d6b193d,d37dd7de), -S(749984be,1953ea05,318445b6,52c970bf,32cd173c,3b222686,a054fce6,787f634d,43c4b03,c395080a,20d13e6b,edd78d74,7e9e326c,c267f358,43eea751,d6ae31f7), -S(8b345416,f6b91613,4ae7c45a,de0d2ba1,75aaa225,795d94aa,4c554a66,9c08f5b,2166a466,d1ea4969,fcf766df,ecb263d6,339a8331,7b342ed1,a4fa6019,23af6d0f), -S(af805191,730b8c9b,2ac105a7,eeecbff9,497c9414,58ee28cd,9bfc40c9,5078c366,ff3dfd92,1e3c1dcc,669a3f7,799277f1,591d0176,bd707f9a,442a219,7eb6ae4e), -S(c626aa89,da7a7971,c7923825,d31ab64e,2305ff94,1b724334,f8c8f1aa,ae60e0d8,325304f9,926dc306,6002e743,e3ae4ab9,b2eae44c,ee907075,fd179222,5c051c05), -S(7f6dc30c,271e6382,db40583d,acf2d121,8803d63a,41980369,316950a3,a1490878,a1224a09,8257f494,331235ca,9d0fb42c,9f5727bf,74e98d60,f624e4b9,a742c7d0), -S(f90f030e,30cf9a10,582d022e,b148e12,d442a9fe,2345a552,564731f7,6c9aa92d,d1ec7fa4,677bcd7c,ae9602c9,2cb9a486,1ce7f6f0,9e6c53b,210144bf,608962ed), -S(f9844b5,6b5ee53f,d41b2d5d,a8eba633,1a8518ff,4f2fb920,368a15b0,6bcb091c,165af5b8,7ff690c1,e5e44f78,b0f04f89,70b6a370,8100e86a,ee82d24d,fd10ef3e), -S(b091a817,66903079,42158c,acdfa7c2,a42526c4,f19736fc,aa62bcd9,2548acd3,5e2c1b91,f6059ea5,5595a105,5a7c4827,4beb810,59c7fdff,e1365be1,a6c2454e), -S(bb291c6c,a65e98b,4f075b05,becee4bf,757ced5,33d97edb,f4920c3b,82880d96,4abf12d1,e910f80d,47c81d41,ee9fc67d,59f8b4,5dbc58d7,16fe5d96,4420af42), -S(af63ce57,fe9f7568,8422ead6,40b64638,d474f848,d26c9cc6,2b89b457,4bf42ba5,abcfd290,320b7554,fe5ebf2,2554043e,a61397e6,6b1b6b6c,441ee203,da003203), -S(563c787c,a9c7a042,d1d8e916,fa653eeb,3bb455d3,d81d96ea,6c04021f,764f29d1,4f5329e0,9aaaa37e,997c09b0,47c924eb,1a9b813e,da648875,58365385,918faba), -S(6795237d,a651f9bb,c4603d87,cf14d4cd,9ebdc9b6,b0143c7a,97a99cd3,2715cb5a,cfbcc0c8,a4ca9939,e7050925,43becf45,59d953d,840d2393,2a2648e2,e3ee1078), -S(6d6158d7,3629a6ed,9437b26a,2c91e31,fb6965d7,505ed096,ee74ec84,3a95ea95,3923c2a6,ae7282a8,dc3e04e6,664c4bca,8842a0bb,95164731,5b47b85e,2b3c8bfb), -S(88a45a7e,512c33c3,ea439da1,e9715f4f,c397125f,e26cb7b4,227f2227,628a57f4,dc384c97,bc2c5e45,5133e5f0,21c0d3b4,76680c02,41e8e31b,b1d96c71,3164b7d2), -S(8cf77e1d,7a4bf247,18c29f7b,66946820,bae990ea,262dbfb5,ed63a701,dc2bf3cf,8d70e07,e7eae6bf,47d224c3,46bae612,329ee6ff,e39a84ff,640b25b3,9877cd6), -S(5bf3fc7c,c212a2c9,a90cea06,44503842,d9f5fe28,fddc0a89,b5610fbf,1a38820c,1e64ea7,193f3cc6,c4c62c77,fc27d686,1aacd775,2b66b82d,f95952ab,ca6488df), -S(74ffe6ff,73a6a663,40e6c2d,77c410c5,c1b46e04,7ff796c3,85238675,e3eb97b4,c31e7707,33d8ecaf,bfa3a3fc,6ace4cb9,4faf3eb5,445f3701,1de882a6,2a4915f2), -S(330b3676,9e60504e,e3225ce0,36fcfe97,8b74c62f,e8ab9007,ea1452f0,6a06ccbc,cf80c153,1165f279,a718ceb4,76e90d,3394d01c,ef6f159e,1225b2b1,51bc3c09), -S(471e94ca,1b8de1e5,eefd39ed,7b5f997c,9e9f20e6,fea65549,8ba33f6d,a5976c0b,ad5b07fc,2a5a049e,fd210e27,b849a842,749c5e43,f6321e17,18e20dd4,4d228c8f), -S(b8133090,5a4ead1,dec7dd81,df97aa7c,daf67e09,58f16739,e5ab2f12,f309cc2e,49fa5ef2,c2a95064,4ebceafd,732fcd7a,3a4c906d,95902646,e779dce2,4021591c), -S(b251f7a,36774d66,f98d89be,15e553e,d85d4bd3,2a170b7d,f4fe842f,d35644e2,cc71d8f7,daa8e846,5b5d6230,e2a25a4f,f92195e9,de33e32e,6970fc54,97001a40), -S(c0ed75ca,6ee80f93,5f7d86ea,8e1bb463,c90aad6b,145873a7,2884f5ec,a18dd90e,73ca6688,b5221c2e,6e82c261,fdf19c26,fd167035,d71f08c1,9190391d,b88efd50), -S(bdc5e903,e371fc46,828133be,5c4d72c3,3f19a203,c4800fc8,59d343a8,7c844c93,ec59e7b8,ac2b2c18,c51487af,84349cfd,f6842a15,cd148e9e,ded4202e,fa0579dd), -S(911cc60d,78c5909,4bd95589,61a99522,fc9c66ff,68370934,40ce6531,e730fc97,8b7c67c7,b33a60d4,bf75fb25,a47d3942,f6c95aec,5a9bc3a,4e8012e1,1274459f), -S(a5e02e09,a00fd3e8,fa7925b2,7206d296,eeff1b9e,18528376,860f2244,1b174f71,4fda8ecb,7fbb77a,dd05273b,ef51f2fb,c9abd87,eb87b9f,50d5a3a7,835e9d21), -S(36917617,6a66b671,684334de,9d6434fc,269197ca,ff36b95c,e8f36870,6e475e8,dfb20c43,78817585,552cd193,2b45dc37,b66a63cf,166560c9,746a9f82,ec3c4fc5), -S(91ded03b,67863303,92abd862,c2f2e870,80524c2c,c0940a0e,820c55f2,175d7533,95e7aed4,46172d6b,ea382418,5f1a5cb,dc26cada,26451556,81b55f08,6bb82f9a), -S(7d5a3667,26e40c76,923867d8,6a5b5cc7,58d84663,8a8f664f,a0b79d20,85824482,cf50b22,7f9d7889,bcc082ee,30d2f08c,1c18b2a3,7443ad43,86d6cf87,a59d77bf), -S(929edbc1,75eb61ef,f1a564e7,d843fe72,c4a49e06,1b704002,56b49b27,7c632eb7,bad98323,4d603b,c85d2747,2e02f089,850725d8,2d905c2d,12d1e730,24bcfb7d), -S(179206e5,861ca493,b3336805,4eb8b46,3a47a189,d4210ff4,5b8f29ce,2b8b593a,1abca34e,f7c9b56d,d72ee602,713b8fdd,ace3007e,a88d774d,40a6aa20,6c1c3e69), -S(e3548935,e28bc944,d29928a2,935e5bbf,a0285c2,337dad5,3fa40a07,377b4de1,2a886052,358b95a9,c25af629,e6d5d2c5,a7dacc44,eb6108c4,46c07af2,cc3977b), -S(e4092cef,884cea2e,51a5a82e,ff8a3ca1,6cb38a71,142ea0cf,476aa293,f9e63303,bac63e08,b0d90160,d8d937c6,ce0eee8f,c01af5f8,a84d2970,ef2c9f8b,ad1bda9a), -S(fb1294c9,c564a667,6bc88f4,90ea39ff,e2dba6e5,4165f6ef,92c90675,138c82a5,9fa392ec,ef922e7e,6bd19f36,99682069,19e799a4,be30125f,5563d3f9,46e01132), -S(ad376df4,e6025dff,693bfe2a,665a09cc,ba64f12d,1b4f9d5a,11e0c880,ebc745ad,fa246c63,fd5f84cc,d104c8b8,ebdae50e,3b86fe7f,976c4a95,c94ac06b,9c6df68f), -S(8f723cda,9a28aca,dfa0f86d,fbf2a831,700dc839,dc40392d,61904711,1f7fbf13,9bddb64d,75a288f6,e92b8838,5affe05e,1c07982a,2c9a8519,d20ed505,7acbafbf), -S(4a674fd7,4ef0139e,d151a994,ad3f859b,aa2c52fc,7766361,949ff86,a1159bb1,f0e5ed3a,ee6a94dc,a2b7a353,dc42801b,faddfcb9,4f1d5b56,f606d77f,ea4df16), -S(6651b5c,307d465c,1fd4c0af,c6edbe5a,e292eaa8,417db4ae,82b53612,66c5e7d2,5d02e21b,68dc7c4f,414c0cc,650909e7,cd46add0,fc91c7b7,98e00907,2ab85c35), -S(e6229fb8,c2a0a7e6,c9aa31fe,71e75cd2,292dbf2d,2c5461ac,a57bf13b,f57c073d,86aef20,5c78e3ed,6cba8445,49aae8d,cb548182,f31714ed,ba2e0b02,2d594429), -S(aa55bd38,39e91fd9,a6080dd9,46b441a7,193ea997,b1e6f72d,f735c675,56e5d7e4,66eda908,504bcd50,19a3b220,1a16f7ee,3692aeaf,ae8b265b,caedff43,19abb2a4), -S(8932bd7b,b1d9bacd,2fc5aeb0,6ad7dd4f,989a8417,793d2d71,b0c1ed64,592822b5,72cdbd0c,56b29915,54b68484,b75dfb3f,fe04eef6,5d522c55,d1c62bc8,8615f9da), -S(10f3bfd0,ee76006e,c113a1d3,37a5cdca,3601da68,1ec1758b,d1286304,a49808d4,89a27069,cb6bcf5a,8848d3b6,7d65c529,749007b9,3143b395,87318e90,4cd4b53a), -S(dca42b0,8e19ba70,db8bfcea,e52da664,956a3a3a,fff18dfc,6f9d4ee2,7194cd14,f6c76a86,eb3008dc,206d76e4,94ee3224,d345f4dc,ce44b54,fa5810e1,903a073f), -S(1251d8e4,9d6c61ae,a266acdd,53be9579,c993ceac,1c62db42,94a4ec65,e942b305,2a722ec5,5f800261,a937883a,ecada795,efa50c56,f12fcee1,20f81ed0,269cf5f9), -S(28b48ca7,c8c57bcd,4cbf70c0,81e46910,d1964ad1,af2e2305,184c3e2c,d7a6161d,3a7a1202,90d5ee64,9c4c1bba,d43d7e2e,6a5710db,924d3943,ea06a6d7,ffbb3bd7), -S(675a33aa,76d1658c,54a956a9,2e8f6487,b24e1417,a179cad7,c0c93cb7,6f8b7f50,8bb59b9c,94156814,a00d2621,d0fc87a1,be4c6165,33704160,82e825ba,62845cbf), -S(8b5b6b75,1d7bcd6a,dcc0f5b2,6e231abb,9d613ae,f80a561a,51463d22,e0ce9acb,e0b17875,6c146090,fb03f5aa,b952d904,3a0b45d1,d1a66b8b,3773c94c,1c657ba1), -S(35b8251e,bf562c69,2e0d11d9,dbe01290,fcebdac1,fdb9f467,9b5c2094,9a0517b,82dd2707,cb4b6758,ba7e7b09,cdfddbb0,11920b0,9ffae6ce,d3ad2e1c,648eadbc), -S(a9ba52e8,4bd13565,1ae96df8,bbddd59d,628657c6,2e0a133c,e2f59a01,8c8efad9,bac10321,1f614972,70c26dfe,47060b9f,d50764c2,461c9bd5,11bf502,a0b83d28), -S(eba36b0a,c20fb216,f8a4d8bf,ff21a478,d80389ab,51d6ac20,df5b2b41,834c56e6,60440923,e9c15c5f,72b7dbe8,5c3c13cc,58fd4ab3,a9a99ca0,372dbdb4,d4af1658), -S(e47ef3bb,b6f8cee6,11c05d2c,681a7fe7,2393628d,77f93adb,b875461b,712440cf,30989ca4,57112c77,2c2cdfb8,bb9e3751,343e8455,6ac9e86,db43920d,8c20d3d7), -S(36b0132d,2058e379,c9b1b23f,c13de925,ff61d8d3,4e8c37fc,afe17d92,670fb23e,5fd9aa2d,43c9a6e3,ddd8752f,9a3bb676,c4049d3c,f849274d,34a60a95,c4c19e0e), -S(dbe78ebf,6db49199,70c4f04e,56e62811,d0067aca,b05fadaa,bde4bc0d,bd2b1dbf,9b40dc7,b2a4fe2c,cba721ee,ffad0810,f909353d,ac53e731,945e418a,2846a8d8), -S(19da9bb9,e0b2626a,c9069f24,3292462f,2394e209,82a7f8d2,fd0bdf26,ecd61d00,3dea2ad6,50c8006a,f4af6848,56348dce,53d56d61,d7f03cf7,aec76a72,559d7c13), -S(25d7a7f7,24bbaa17,83b79913,25ab7c40,da5f3d91,bb13a8b7,8101e970,b1295790,1b675e72,354bd3fe,21c0884e,f0a5802e,45f8fe8d,3b0c0d92,7a53741f,231ae06e), -S(a5ad3cde,de3d64e5,aa1ba02b,10771048,8ea62934,6781a0dc,ad93f3b5,4c15fcda,d14651a5,823fbd07,4a107950,7e55089f,fab0b4f7,5e8021da,767528c2,2e37d72f), -S(b2c32ac6,925348e7,1adcc149,656c21d7,3343d7f9,a97fc90a,6c0ecb9e,4835fc53,a2fbf853,602cf32e,881540f4,eea48400,6a67568f,4d69f2db,3adff02f,9b687716), -S(de3610ea,e95e73c0,fe303cc2,9b1bae4,c3ee5009,a5751e40,6e0dc64d,c2128809,83fd3a89,3e9264f6,b0d9768f,b2137665,65ddb286,9b53279c,b7ac524e,e8383e29), -S(d91d23de,8b442f29,d0ab4a23,182a429c,299cfde5,8f2f991,53139d6c,3028098b,e00a507e,48a68d49,c489063,39942d9d,a7a81cce,6865487a,4b18b34,b1b2e65e), -S(ef90ef91,265655f5,7d776fe1,a153289,87052919,448049c9,b3342a94,9f66dc83,a44f99d9,e9e3cc67,9b819232,14b4de83,d95a65cf,c3af495a,2e961a68,21511c54), -S(aecd0136,83f0c6b2,d9434651,94d6d6b2,c727d3b9,3409887f,821f0bdf,ce30101,59b3d669,1952dcd1,bb351f31,aa281dcc,b5f7cba6,a612d5b7,7d3da3d7,92da741), -S(192c250a,31468e22,56c25dde,ed840d9f,e9da10a5,b9dcd4fa,505f418b,9993c86c,e311e20a,cd56146c,c03db59d,799a1d51,e3955b72,7137daf1,5dc8939a,3e7d0f85), -S(85aae3c2,2a26d60f,c14c46f3,d789cf89,5b23cd96,c4515ba9,87609fd4,dce41a3f,54bcad5,166281d0,bd33587a,52a16a3f,13d7b1e8,8bc009e8,7c4f59d6,e13ce99a), -S(24dfbf0,c22d29d,bb3f59eb,27dc89da,7c0a83d0,7b42445a,4993e205,43a97bb5,64858a97,8471f3fa,aa838ff1,b3ecfef6,1d47e3d,bb684028,bfd6c194,dfa05928), -S(909ff9e2,d591a673,40cc7df0,e73be5c0,ce19c4a3,24679306,995f6344,bd692f3e,5b956095,a5d4598f,9dfd693f,893ccfc7,d77adf8,bdfe9ccc,8497125c,1c07046f), -S(fe24c76e,900f320c,c41bac2,e625293b,ef871944,b0586680,3e0848a1,e15a60f,ae054925,3338878a,b1e8d268,b6feb271,512aba65,e7e8b243,7fd4867e,74b5fc30), -S(7704fbb0,13a7ccb,5b0c73d2,cf6fd87c,ce4c8d8d,f49515e9,9145b3aa,e02b2d6c,21ee85ac,405e2cc7,c9fe7a8f,7b59c71e,82dbfa33,bddbf113,64435f8,53139dd8), -S(e136bd1c,9b7cb6d4,aac07f42,1f1da3d1,eb9a8935,dcdd8097,7c137daf,869d7c11,c9d44b0f,92b5e04d,aedb2155,eb1930ea,802b205b,880db2f8,62575a48,22acf521), -S(c6efeb81,850462e,72ae763e,2c1d2f39,741babf9,5b7559bf,c28d263a,8944aee8,f6bf9cd9,413259e7,85490c49,cfc74576,c23bf0ff,9599b877,2acce426,1d3e273), -S(5d09a4c1,1c1d913d,d83c33ef,1377ded6,7affae57,899b5742,347291b7,c434edf2,15a6d501,a857e00a,ab42d1a0,525089ec,cc48d185,7f5dbe69,e3687bb1,2982cdf9), -S(9989c1ce,c3865ba2,41cbfe91,1b72edd2,ccdb8b44,9a837284,730b903f,b45507fc,81cfc11f,e8de5fc,6f850c66,21bfc5d8,9d7d2bb9,e8b9b2a,dfd23f8e,d2fe8d40), -S(c8d0b073,2930e2db,f149c156,c5957f79,fecc319e,f4abe588,860dd44a,d74779c9,bb96deb1,e23ebf7b,afc79ea6,ff7fd012,e2faff01,8f2d17fb,38fecd52,29aed776), -S(7ba25516,877adf65,6719f4ce,e867b4a7,3d7bb18a,735a6043,47d5d5fe,47be46b6,f66f2364,5fd24d13,39407ee8,241b07bf,7e6a08c0,d3a1e683,67b450b0,f3eda69a), -S(be8f83a5,5e50defc,b8357409,3b727cf3,578a270a,c478ada4,22e0cb8f,907edefa,c38ed801,1af0e3c6,55989b08,af329cd,340f469b,d0bbcbec,6504cd34,aa44ab9b), -S(9bd6c57b,438e1ede,cfba0916,d744ef9,8b010164,ba46675c,1206d9cd,67c3380d,d15ae82c,33b85d22,9df4349,ce48b582,10c1baa,689fb6d0,51721d22,334ae972), -S(e8927a5e,9f511cbb,ef935f7a,a90c64b1,666c8be7,1445cc8d,193ec922,1662177b,cb6f084f,a41e1bf8,110a98e3,bfaff1,43ef6ccc,56170ca5,de520a6b,381010d3), -S(c4243e89,4608658b,df46225a,85da8f71,dc75464b,fa29dba,6d096423,81b77ea8,d501050b,89abe5df,fb9a11e1,6d1f2bb6,d081b20b,4f0d9895,70ec128b,21e2c124), -S(582f0c51,20f5c79e,76dde6cf,624b11f8,1e9663a9,5eab0480,8d4156ea,61e70723,1f0c54b6,1cff944b,b9bbae8e,1d2570f4,315e3c8a,f067d289,3d9860c8,4885d7a6), -S(d384563e,67e85943,67725600,81f4287e,fd7c6fdb,6e29ee62,ff4f447f,91a4882a,b90fc799,7f76171,c7a76d35,7aff06b,df5b3d00,a1d6f089,bbb2acb9,e749b6de), -S(5655f9e3,5bdea0d5,d7d023d0,7a5d415,52c39f1,a9530241,55b647e7,e757e40f,4f60c357,bd0a7577,475c8e5c,9c6e099,1a21523e,821cbcd2,665d1ead,c6075a39), -S(b1209637,51d5e9a4,5bfdeafc,5aa9f45c,9c29681,2c4769fe,6db03118,cf0a2d53,eadaaa67,96ecf2b9,57944958,c9fb1cf6,986f387f,50d1387b,d4b94eb1,aed1e625), -S(bb6ad704,477295a6,710cdc87,f7df5c4c,c3b82fdc,749f8464,474fc61e,b307d4d6,7d0d1fd5,ea113783,7071f705,7bb783cd,a4b55908,9af6eb59,1d6c18af,434ddb34), -S(3daa25bf,5223a09e,fbfa63a3,405e8c76,b059bca9,38d513cc,693bcfbf,514cbd95,e876c903,22d97d60,fdb0cd64,cc9ad575,cebde9f1,41d67c82,7f542034,5c7c6ec3), -S(b32bb726,3f40831d,a8e00e27,db8ce14e,ff1ddf5c,4e48eb4f,deca0531,3770c016,916fe7ad,2726bc93,c242f50a,4e3e69bf,db965402,55440262,ccc5c055,136dcd4), -S(a7f331b5,26d74b9a,67ff3453,2399ba79,4fdd4d1b,1b99dae,1b7806e1,8a0a7f11,786b90b0,72c5a702,12db8173,2dd486c8,ba59c937,ea9182dd,f85275e7,d6622c6f), -S(30086238,dd36b617,f8505367,a015f6e0,2f14079,3b4dc5a4,442d8628,1ac8caf1,9b87d837,644f4ec6,c161c8c9,ae923bb3,f40f6cb9,6538c0f8,aa8c4ed9,42eccc8c), -S(1ec0343c,f9afd13c,57ef2b2b,4006c740,dc03bb3,62ee8129,c4cb35a3,299b1ab3,8b645dc1,91012651,3df47f7a,e33f201d,35cc1d73,2184952c,f605f68f,ba8a2e34), -S(e8059ca5,3aa197cc,3468c797,81b36245,4ebd8b86,7227a9aa,21816967,52d28587,39f9b33,e91eb4d6,fc769d6d,1b43fc0d,ee8f1841,8c682c96,5beb1e7c,9280d23c), -S(fbdc998b,96eade37,61e0b0df,a6c4fa5f,7794576c,91d5dc52,f9753e3f,748c5afd,4789bbef,e1f68f8b,2058e41c,c513858a,29a48cb7,be41ce56,248ffe3,996d043a), -S(3ab5a2fb,fbf2acf8,2becd224,4239ff2a,808aad64,41b1b47,1aaa9e67,12bbc29a,d20c99de,14e44cc2,18a42ee5,34fed723,25f225ac,8c68f2ab,d6c19341,5921e5b3), -S(94b611e0,63334b9c,195ff7c,894cabc5,2ce902ab,5b17a572,1a697c3a,8a4903d6,d8d70dea,a7d8fadc,da7eae42,3ea8cc29,285c32c2,30a8731b,52710126,dd03769a), -S(2cd6e98a,65c1ec8,6596781d,4239a71b,8e0c8a0,4c3dd8fa,c7925a07,2c246e3d,67bb6602,75d229a3,a28f51a4,a19cf6a9,f138f72f,5bcc2ce7,c689d699,b23a59df), -S(500f58a0,e8929d68,f4fd8e13,5fea7e6b,afb562a6,ce1086a1,19871799,c5a4f2c8,80924142,bbe02b2a,7decc045,23b6c132,af14283c,6f715abb,113a12ac,a92b4205), -S(4c1ef59c,5030213b,dab7be6b,c3f4272e,b7d4e07e,981a3160,cde6797f,821c507c,d878f643,a0f82a73,d7c9928d,ff243584,77475dbd,2076e7af,aa1c54ee,e66ce565), -S(b69d8ca6,6b0dd8ef,df2e7c11,1dbf7876,a3ffcef0,424f1943,49256446,78ff24be,1ba714ad,96ba9f32,456e4288,5b9d018a,f3cbb43,37e5a0cf,ebcfc5db,9ad76c87), -S(53def7f5,bbace323,cb0a38f7,2268fb93,1e4f546f,a72e5b5d,2d5733eb,6d39dbb4,1533c9ca,5c0142e2,e1e1ec89,d0536b,282cb784,7ae5245f,ef978581,e3aee5ab), -S(a7f043ca,731d58b4,c5048ffd,12028f94,bbcfaa96,efc52a94,6c78c42b,748ed508,8ada0d66,1aeb2b7f,36eaa00b,56424547,ea5af2c7,954b8801,9e8e62ef,ef9e1832), -S(7d3609c7,7a0cb4e,5294c831,d05d9028,e1d16d60,7495da06,b241a87a,23fb93c3,9ade4159,fbe98e1a,41297877,383f023b,5a7973ee,afd17af,65ee4753,d24a4f9b), -S(a488a3dc,20442c4f,aa127f1e,28d85b20,5681be3,311e5063,c7a2a356,1312569f,4325102b,66f100b5,7facdca1,7973b3a8,f9cc5d97,3f018e4e,7d035e5a,5d2549d6), -S(9c340a46,94b8bae9,d7e6a922,db9c750b,3089101e,946c3e58,88a4222b,42a05d9d,cc580dd3,679db392,74ab94c,d054f264,42c9ff72,5cf5c1c8,a485a48f,8f571ede), -S(44a788f2,c070a53,5c4111f8,6cf636c4,5ca83338,e0b71781,44e7c542,c289480a,99d57358,ee53d719,9acf8ee8,b679cf9a,5c44611b,bc17a734,caa914de,25d7b22d), -S(3039da67,d1d2a063,9b92c0c4,c7c6f415,c142acdf,ce21bba1,98de3bcd,ee9bdb9,c11845fb,32021c59,8d7cb0a5,a7c3da2c,851306e2,75af5398,e406dd34,fb5b167b), -S(6381f67,a6f5e9d9,535ca436,c92bb8c2,9d8eca9d,b335e159,fccb4609,484d401b,9f480076,aa6715c8,2fc04c58,d30cc445,156b7d9d,b1e4c1f6,3744ebef,5060cf4f), -S(7ab7ff64,d2955841,1872da55,7ed988a7,ba182fef,480d36e8,3b65f1f,cf0c0c3d,76262668,bd45b55a,dd32839c,591b6a70,9e4e7ce6,e9fdcf55,c78e9e83,dbdd6096), -S(668e29f,6b3dcb44,14e4c22,cc2fcc8b,3a20c00,89f94ad1,3f279c1a,41d7df7d,4afeba02,4ea185d,caf130cf,f7f12af7,7dfb3cfb,1871d641,83dddeb8,86545563), -S(9fde56c3,ac8016f6,ef6dfdc6,da621198,501eca9e,377c594b,e063b24,e0721dd0,dea4c586,233873f0,3ebab8db,900b4c21,6df32c7e,12b1f1a7,be26d46f,880022b6), -S(70f3ea86,cf318a63,e44ab07e,a4cdb22b,929e42a8,9c1eaa0e,a0d56bb7,a9d63592,eacecebe,3e94160,bf370703,2fbec0d8,e83f5bb1,429ecb12,4f11974d,913d4332), -S(68794d4,cb77a07d,f2d09cad,7b14c8c6,a8c35da4,9cb9be35,ec6c19d0,a3e4fb6c,aaf0efb4,5be195f6,29b8ea14,ec137e33,f14cb692,b3aa59f5,a71bcbff,d8511633), -S(708c3036,27cdb4a,58ec9884,6c23e392,e7d8e1a,c7c0dbd9,d640dffd,23938a24,113daf12,a5b57f22,fbdebece,3727474a,8289c4a9,2474135e,13970c7a,d3802084), -S(c74bba7e,2d764df9,e6e76441,6b40e019,5caccecf,75c8f0b1,fb3ca353,2236cf10,a97b858d,1ada13c3,3ff98a0d,404e3e46,768ecac0,b224b965,7d620c3f,ce3aad05), -S(186dec13,501477b0,dcd69175,c57d33f6,264603be,256b3029,b5f9dd9f,fcb5ceeb,59a646ac,96924f8f,cc02e6b4,14a2234,f49d78fd,6b64dbfb,f8baa0d,8acedc77), -S(94486ee,b0535256,ecdcdc9,576faecf,9cbb7c12,8286352c,3f3f249d,458e8ddf,4e5290f6,bf22cdec,8f7d4617,531562ee,f7402174,b13d149a,390fd9fd,17ec3e7e), -S(304f7074,5b9561c0,7facf83e,8e593af3,cff8d174,2d2472ca,bcc08ee2,9b7617ba,77654948,8a95197c,612d6bb9,20e6c9e,b2c2236f,5e28ccd5,6744152,f46ddd9), -S(97046baf,d42c5a5d,b8b892cf,7c36ea67,86dee4d7,bffbd572,20f9a122,26038a5d,7ab1305a,103c1cf5,a77f298a,489db57a,2c9148c3,6a834da3,ee108971,8eb3d43a), -S(e4b52916,3f73e5e6,45c44686,3b786f53,46b048af,3d1fef24,e80ded13,ffd89b0b,7409a638,452fe0a8,7f1e717c,b0e3496d,14b9e3f3,e6f4d048,52f622f6,ba4ac2fb), -S(b9d303a2,75452bee,7800cea1,1c06db97,4057adc5,62bf5aa,41c34e5,18f5ee9c,4c818cd8,a24b7775,35ed8738,bdd8d45,76408c87,ad172563,6c536ff2,ce6475dc), -S(fc459ce4,3283c842,1a16554b,d5eac61e,3e4b60c6,2b090c52,465788cb,120d2295,2b2e75ab,10a60dff,1e11bddb,62457bd4,585b262b,e671f5de,84ec3bef,d5b0b232), -S(19828f90,5f901716,bafd9bfa,856e8fd9,c19eb83e,37c8e5a1,11366a77,11a26790,5bf76d98,46398c34,6b021018,6dec4ad8,c03b866b,e0edd8c3,9f09fef2,d7c38bba), -S(e10dbb26,999ffd14,f29fb5e7,e3b3b78,1519e63f,ea0fd26b,b1b593c1,8267dfa9,c3c04bfd,799303ad,de767ff4,2baf9759,82c48d95,5f127ad1,d59ff73d,cbfc456d), -S(2e53cd28,acba99fc,6763f788,a644e314,1df5e17e,c50003af,48206aab,d81a3396,4393815b,db8dbe25,6b0269f5,4220200d,278fa537,666b5cea,34cd8e77,854ac02b), -S(f6d174c9,60516f44,6054b7ba,a0f82557,87ac2e94,c966762a,f7c428c8,8b9de7b2,68ff3c54,a3257f1,7b27a5a6,ee7cfa88,97493d3d,b0899b47,c56d4950,ba263a9f), -S(7d18482c,704eae8f,c6a33f77,923d9063,eb3e8e5c,28ce3d3d,8ffd3e17,ebb82881,a126d78,eac1033b,a223cf66,81faaf93,bf523dc9,409f03ed,abcf241a,b0a6e3f9), -S(b2c02f09,b930691c,a017197f,bfefa1c,bedbfa2e,640a66ea,fcb1c11d,f574d9f4,19fa7f66,cead7607,d404c33d,2491a6eb,ea0d3b00,4ef41bbe,13148508,b0a9d29a), -S(253d6786,8bf2626e,acf690da,8a26d777,bf9807ae,ccec3804,e1b7808,bd16ab91,145f6933,f9ba0d51,18eb8985,43a01106,bc702915,373bfabe,4ac970c5,27c17a00), -S(6e496a5a,28a74cad,4b4fa30c,48dcc62c,3f4b4fa7,e8151a10,3540aeb6,70c20d14,c7884130,274649e9,4e61623a,ead39ff,ff3b8a4,526509b7,7ae8586b,fe315ece), -S(774a8bed,36e7eb32,8e89734a,e5c0568f,f1659e3a,73890010,ca4a0e6,dd24a4ad,cfdb3a1c,1d8bb371,2e8f2ca7,2c578568,9db680a5,68c18e5d,4e423b84,df9fe798), -S(59bc8e0,e63848e3,79e0912c,4a0c9572,10023a93,a0dc4303,7b3b9e1b,7b834762,db8ceeae,61f6adf4,ac08c5fd,586209e6,f4879fbd,6aa9a1b4,4c67b4f6,69eabebd), -S(46659043,eed0a625,42513ca9,678cef04,2fcd952e,29be4926,fedf79ff,acc8b686,3a5f51a1,4c9fd813,3f11ee7e,6eca075e,f90c91fb,a10fb251,250b4cfd,9281082c), -S(aa92c411,308d9d48,fb62d7a1,2999083f,c52b5d79,196dc91f,e829ef04,41745aa0,d70ec349,f27a1393,ba8d57fa,968974ee,ab0d8e81,a497415f,d38e156f,bb029864), -S(36382200,5bea75e3,8c2483f3,eb95f6b0,a7f53f10,32bfb1dd,537cbe0f,4049f56,c9b9c28b,c2bf0056,91eb3e99,2efd5bd4,ffeeffb3,e7fed235,79af40e0,961489ad), -S(c3e4fb46,e400fd1f,e106c056,838cfb2b,c1cbcd66,ac9c19bc,e7df1e29,a7bd25ba,96b6c598,512215b6,a30486d,9f8b0c91,4589022c,194df5ee,30d62c2a,b9e83fbf), -S(71105f47,e372fab4,81cf29b0,ab5605d6,84c00224,ae1b9449,7c8d3c59,26077cfb,f7218aaa,d2a95c0,55f30f69,3fc087f4,101f5db1,1c9ce88a,629c5711,a1f1ef51), -S(676066da,6bc50ae2,e2e46f61,dea75ac1,12cb085f,2f00ccd8,5fef1e47,56059f3f,ea9e25c0,6c19d572,8b4bb333,35e94202,d252b9d6,33a1b04f,a7b4129a,2efa83f), -S(2616418c,11f5536b,c8873830,9758a819,f7b30e86,f4a16f90,ffde0685,e91a12aa,80b92bae,591f59cd,8d480401,644ac3c,940e917b,a32e7a4f,f4a2d5c8,cc417de7), -S(3bf5d07c,715fad35,45ff092c,18cee285,3de0d50,c9d68225,3596eac1,42111d18,e382d006,2c4b4536,c6432557,afd0b909,fa047ef3,1cbf2d8c,1eff9ea9,9a95fac0), -S(5e9d4316,db96d6c0,a5247809,8b22c654,7d873b1e,a4089071,86f81da8,71d057b3,e22c05b7,dfb5dc29,c07a735a,31bed0a3,2e071de7,41d734cd,dadd832,1dfe56d9), -S(3c153e81,e6ded587,dff1c8a3,ae5758bc,58c271ec,aa9dc005,1441ab2,a5aa123b,366fff49,b67b57f3,84b5f027,83b02d5a,f731f3b5,c6e8c089,949a0f2d,998636cc), -S(187518bf,347b87e8,e9955bca,b7937e80,7c41ef41,97511d9a,daa50f3d,9f628708,15f4ea6e,17a6649,36a9c04d,c76ed314,64632d23,6fb6a9c9,2aa0a4ca,afebfcc9), -S(edae6892,ad2cd7b5,9f559f88,b2d72fed,6bb27aa8,c7351194,388b38eb,4af9a6ad,e97c8ccb,225f734c,8416c605,52f24689,fe0e4f10,2d62ceca,d78d9ed8,7bf3c3c1), -S(e8bf332f,26d4471e,fac8264,2b3e3cf0,6c210792,ae39d343,d7c7c4c7,46ce79ba,60f53327,95e2a862,f6d82ed8,5e2d652,70fdfbe5,8118033b,105c3c2e,53257b73), -S(cd1eb398,4dc73522,e791f8ca,ac528da1,bf9c908,e446fd9f,7bdf4016,51138d2c,8a845cc,74325e82,14be35fd,cf520f3f,2a64240e,18d85bb2,18d97d0,4cc6b366), -S(7d7bed7b,2dc04b84,5b9b8460,e366d1d7,a49d87f4,45998a12,b6e379d9,461b035,bb7faea9,bd2a992e,1535cbcf,bb78b955,f89d8f81,ea650384,75399ea3,fa63e6ab), -S(b9de73cf,8fe63fcb,56b992c8,668e6368,7672c856,1e9be11c,9de51d7b,8eeb6516,c6884b86,8e115321,1bb98a8,1ecc8165,25a8600e,69155f49,fca83e5d,7dc8e0c1), -S(b5622f5d,2ff1b4ac,5b1a675b,192dc2b3,595a43cb,1120f249,fa55f7a2,69e15b8f,d8f3afc1,388938f1,25c3d4fb,fae7bbdc,93925fa6,e46298d4,e0d7a3c5,451ca1b4), -S(eb0e1fb5,8a74273c,c8912e76,5f150947,2cc12c33,2329a24,a7f7423d,83a3a049,e3b4fa95,1b958a1b,92b3596e,9e8905eb,934a121e,f15cf758,a5112575,4702caaa), -S(232a33f5,72cf2459,fe985373,2de8fa5,df1efe7d,32b14eaa,43190ec7,6a9450a9,144ca6c,7a114e35,37434426,699433c1,fb0cf4a8,bb9f65c0,14011849,f962b332), -S(e32e4c4e,b57ee32c,173f08d0,ae571335,cf4fa22d,d32e7754,740f174c,d8914ac0,f0669f6b,12525ee7,3d1a6e65,af27124e,89df20,5829eb27,2bbef862,ac053ada), -S(d89046a4,a915391c,856fba77,d4699c48,2b72200,4efd83f8,893fcc1d,f944e2f6,72595560,28e14090,c76d1219,9d133bb6,156a2cd3,aa5df1bc,c18c8b58,27a2ce04), -S(ea2fe94c,ff11c532,6c867e75,7544beda,8c39bbae,c3c2b8a7,62c3fb5b,5dc0b23d,10b02985,baf66352,e86f6e9c,a2c0cdd2,cda7ef48,79460ac9,d58f3a61,16663437), -S(71b224c3,7088851,25ed762,3caf674c,5e3863dd,d5eeb116,29a056e8,b054dd79,6002d88c,2fe7340,6dbf9c34,40eb5501,3a3757d,831e5f96,b35605fe,47fffe92), -S(29568f1a,11070ddf,bedb2f41,10246352,cab977f4,dd6cfbcc,be397575,dbfd270a,a68279c7,440fe321,fabcd58a,f7ab6923,e0f627c,909d6ecd,d009d130,aeef7b7c), -S(57badf5f,dd22af1b,11dcd60,e875d9b6,86e043cc,d4ff11d1,c91089dc,cc8230b9,7507b060,bbca59a5,aa19f813,eed95faf,8569dfa7,6d2bc327,660a06ba,8fda2b3f), -S(30d84aac,10a7b86d,d55fca2a,377e007d,1f8b8cbd,4fa9d7a1,4eadaf8d,d6481491,cd1df453,b553de9,1ae59e95,d08fbf64,eb9af82a,d0d4fc46,4d1574b4,f9131a3e), -S(79ac7c66,ff73d627,62a749be,c66c589a,67e33546,7a13709d,d72d9a01,98ec405a,803f34c1,e8b06902,52a3805e,abb30bd8,3942f1eb,84433ac8,57d22cc6,4ae0b04e), -S(6700636b,cf6a757b,8afe6fd6,d26def0b,6ae61da,ba7c502b,2a34301c,203af68b,91fbf4a4,c94105fa,8fa7de5b,6b6ba4a5,f34d677e,cf732db2,b660db50,e6a654d8), -S(84ab5f25,501abd97,a9d56f3e,5fe50bb4,4c2baae,85509b98,d38a91d9,74dad801,2dac84da,6b805b3f,6ab306df,22e254bf,d6c14574,f0f42be3,8d37cefc,38dde8d5), -S(e372663a,7464dbf5,48f0d0b9,c91867d9,e76ebcc4,ccae7105,7046b8d5,360365cd,6e80f9a1,21723a6e,da7dc2d9,b82afb01,2e3b1712,c7ccbd3e,2fe5b4c2,270e58de), -S(4a9ea0c6,57e21f97,9641f891,8975dfd0,28118b66,c9a2d38f,8b197a94,bdbb09e8,815246c3,2173ced9,13a82877,393df34,f8de1b75,c2b42abc,7dcd80c8,d19f1b5e), -S(a05157fd,f91c475e,97e110c2,969869bd,31435fad,2aa242fd,c4ac2e3c,c845b0bc,76d82bab,176ca9f,c3cb1b25,541e0407,91b79739,2581c4d9,fdff832d,3685ac6f), -S(bbd11f9a,62d74bf2,49e4831b,fb253ceb,8e94eeee,bba1d08b,b88ee5ea,53e940c4,762540c6,24e7ec7a,487586d,727949bd,d4d7162f,b5d1dd69,3a10f6db,f41193e4), -S(a7fbbd53,62d41020,6fddadf2,36782aaa,f33d5945,5bc00106,9ff41bd0,41cc53b2,aae57e60,607a0d7f,5d12da7f,62a51075,5aea3686,5b12b678,3d27456b,6a2f8a04), -S(6d984c7a,816b611c,8731f553,2ea1e6ed,54717a1f,4163ea72,9825bbf2,814050b9,c551d373,8b815e9b,5256a8c6,4152db2b,d8bf881e,c10254bc,a584f7c,f5dde7d7), -S(ccf5595d,81440526,6244e5fe,87eb293,3dd5e684,b90d58c,1eade733,e7c1d2e5,862179cd,ed77b0f6,1adc0f6b,334f6942,94d71057,f42a017c,9920277,3021dc16), -S(e0b6855a,e19ed610,51c9fa8d,4bb9834,a27e999a,81d4584,1945963b,8c5ba5cc,9626aff2,cc89288b,768fe91,3ffa5ca6,8a99b9ef,d904677c,fdd02892,815ec4fb), -S(4b3347b9,62a0b644,4942cf83,a30420c2,f164bac3,7aea2003,ebe5d232,58dfa3d3,5e38a814,d2ec02b9,7f12afdb,ff857692,e9ff35e1,1ab85cb1,613393cd,3e36b365), -S(646ffbff,5ff88f03,863722db,f554d9d2,64a4e14f,d2ffce79,d9f965bd,aac5c401,335e01bb,bd97b4c2,36d18b0f,53ff37f7,f5fc39a4,79092a76,1c159e56,c2162340), -S(977b9528,ab51f6b0,1e7a33d7,2a85216e,e5fc37b3,c0acb9b2,de3ecdef,38ea1e77,b16d9644,394c5ea5,2c7aa42b,543763b7,1b4d284b,a81c2fc,e4866d87,b1a65234), -S(3e80074c,b8c8b1fd,3dc97c7d,9e79fbba,1ae672fc,5eb43b3,c1ca69a7,8b70224e,6069492c,139fbced,707c65af,1e97270f,818af208,738a5b33,f73ee222,a90feed5), -S(15b035b1,108ad096,a201b0db,5cb152f9,793f9355,22e8d68c,adedbaf3,eaa1824,a95eee2d,e2f7fd5b,1d07c262,d07837a2,20683b29,805cb5,a19febb8,424a33e8), -S(e195cb6d,d4c21ad1,f054188f,31664108,1f029be2,22850118,8a6464f0,a2a93449,9d1babfd,9848c2be,15c89136,a3aec42a,8f85c2b,f91613ac,12db2737,b6bf41d), -S(1a309895,5513c42d,48db553b,22e27fa8,7d823df3,2ecdbceb,45ddb4c2,8d874bd7,69c52bdd,8835d6ce,99e3afa4,259c1513,4f988c24,f64fb913,c9353775,7c86df9c), -S(83aced50,fd6ff475,e135c85b,c705cafc,7e5eea1b,c6b370b5,728ab888,54ec74b4,d0ccd0a3,3e276d64,90079d05,4aad8732,6de6b6db,5e909fa3,c2546d4c,aa9fed40), -S(f2619c96,b0e5ae71,fa78c661,b40f321c,f96d6b25,ad8cd2a7,53fee657,4d41b147,9ff732f3,4c68e66e,6940e4b0,e5d0d94f,f223d53e,6900c80a,eeb60778,1d64f77f), -S(a49c15bb,3f6c8aa9,11117942,9f609456,ee4380eb,3fef3073,ab0f6c1d,33a4e3f7,70874663,301c27ff,551962a8,6c561ba8,6f1b36b6,20325864,a76faa52,31cbfa26), -S(e96fc9aa,2e1032b9,2a9f5263,4c35b7d,f583ca,fe774756,97c33a2f,703197f,54a1bc34,1fbcd484,34d1254c,73b9533c,8cc11db5,92363fff,10a996a,864f79b8), -S(64489edb,18791a7,f1f4be16,ac93de2d,e5445cce,ff8172d0,bb467dd8,e7971d14,5c343cc,b6723d79,ec75ad08,69aa1308,4180518a,679bff85,6e8b0e3c,21c41115), -S(9ef3f569,84c53365,8bb39b13,9271e54e,c5d376c6,f9f533d1,adf94921,ea7c066e,f87998e8,831d20ca,1b611314,7e426acf,768ca63,f6b7eabf,a4e6fca0,ac33c377), -S(5391ea1f,ba16db25,999f093d,c8308dff,a2ef9aca,17cea315,6c974bf,28540218,36dc27c7,c3a74f8c,332cb471,cdbfe71d,22b12ace,a2c86e6,24104da8,bef66212), -S(b98831ce,adac19c8,2787e84,cb443685,4208f189,b24040ec,2bca6366,6c601c5e,d753c01f,8410fff0,8278a570,16bf736d,a5ef8a0,f1d9eec0,c17a0f22,74f8458), -S(f2f9050e,b8d42461,b8d11189,3a3de4dc,425a7468,5b34a0dd,7bd3ee98,284496ff,74dd4077,4f0ea177,ba875cc0,f8b504e4,f7d352ea,8ada429e,bd49510a,c155cb9c), -S(e76ddc1c,179ef377,a8da15d7,8c3cd8d1,a775089b,8d542e42,1e6220c2,4390aa35,ecc8baba,1cf42a6c,87918ed9,f70cd24f,b1a3deab,8ed86640,fdc6ee89,ca7ffe76), -S(e1c86064,1f85ad29,afbb6092,9dcfe648,82fc149b,952d1c2e,d50c6a44,13b2d5fc,1d418333,15eb3b54,9c067140,97283de5,fba554ad,2ea510d5,f1c12d83,e730e25e), -S(9dfc52d9,e3e55bd4,2bb21cd1,74a54c02,dfef16e4,758c10c7,ccc0bc81,af509ac5,be552b18,e576d5ec,6961893c,1498253e,c1539068,aeebae6b,80994a10,8140d7d), -S(24e672b6,905f5ba0,186acbbf,6a344c15,f3c59291,8c23922c,fc928b2,5aab8ad0,3b4799ba,9e23bc85,b622d248,9343f39d,59e80244,e25806f7,7d919504,89c5400b), -S(e4be87d5,2cb2fc8e,bb793449,5c94b07e,65aa86a1,6f9b63f1,b24a859a,c0737096,ac28b858,a4083916,eaafc195,81dc8f7b,e163608c,1f69c9d0,87a76446,71110b4a), -S(4379567f,ec797600,9a98d7ae,e3ae123f,dcbb167,2de5e367,bbb40e9c,ab87fdcd,9a2cd1d4,7ed65b8,c2ce95e7,451ad868,c1ffd81b,929ec58,49d82a1c,753440a4), -S(923722c8,f0b1b91e,261a32c6,75fbb26,ba4522de,b9610173,25764974,8c8eb107,b51b46ae,8a3951f2,7d564cd3,395a6d64,27b5232e,2c5b9ad3,6419ef5,d4a5cbaa), -S(7f749af,3301792c,826a1162,b3e86f1,35d1d9c2,e82275c2,a112ecba,bc0f374,d31fcb26,20b1f7b2,d671a52d,ccee8b1c,f47858fa,d28bfb91,475c6889,dc19cf47), -S(c657ab98,6bb3b2ec,87c09d23,530a9136,e85ff051,4d588230,bb9a2326,b058a052,a4f46786,410619bd,60d33aa8,1d8b7def,62c47ed1,bffc872a,941dd1bf,198c8ba3), -S(7f6ff017,2459d2cb,4f305aaf,ff17cac6,5a450ad0,d705310b,418184bc,7bd2b6b0,7ff8f3c8,782d2bc1,8e466df1,f3463a0c,a73dfd06,6cf874dd,65c8418e,91e6c1ab), -S(79b46336,478f2d3e,60e8d0cf,2c905b8d,c0b981af,6ab4cbc6,b36d238b,9d5acfda,7a31811d,95662ab,dbbef71a,5a0672fb,eb34ef37,c39d9ef2,e6f4f27,6e1d6514), -S(df51181e,5ad2e6a,5392c92b,14d762a3,f823123,d4243b57,21c1fa89,bdb2c386,210b2061,bcdea7ab,2e2e98e7,66fd68b4,63330ab6,9e7b1349,5a349087,fd18dc63), -S(5d60493a,4becf377,f66ff41f,9fd3a6fd,5603e504,b4d436fe,bb53c1f6,9038b75b,83de8acc,d2fad488,aef0adad,5a4c314b,6e9ed8b4,9adf56ad,57bdbcf1,a4dc947e), -S(f5b49912,1eb62fa2,c8db16b1,c3cc8ec,f89bdcfc,fee6c5c4,7978bfc2,16ea8a2f,5b0d4f37,8a436098,6b4597e0,a90557a8,a272c668,ec1ad310,c68e30f5,8a409927), -S(67556489,5729a58c,719c2c90,1e6ed73c,16909594,74100b06,2f64e242,c79a1ce9,2df2fd1e,ca39c5fd,a73bc75,bb9e5ad1,ac6571e3,322b433a,1b09022f,80ac4e63), -S(b6e3dab4,d13b42c,54238d14,4a47aff8,782562b0,28422017,ab775b2e,51baca6c,ae4adb5d,67855986,92c72c0b,c617ab63,4c65068d,d603e762,a75c273,e9622722), -S(b62a111e,6f15ec98,6c570b78,316f8857,5f59844c,deaa7fb4,3f76642c,8bc4b064,16a1dfb,551d006c,ca3fb15b,2d250287,41c2a5,35944e19,f7f1c2c3,59b0288d)}, -{S(ca3c008e,cf9efd5f,75cc1035,f9edaa7c,46b17d25,9895b0e3,b3523b6e,eee9daaf,a676aea9,3ce9bb,128ffc34,deb96b0f,72179d28,77406d04,6d0c8b5c,3572f4d2), -S(cda11502,15f6a502,96b3e042,445220f8,54e32a97,32f1e883,e41cb082,90e51c56,ae62e394,7f16dcaf,e5a6a54a,5beae349,a620d996,599ff570,36a9b6a0,3be63dcc), -S(43a90be4,b0efb9f3,422e5374,69fdba07,6f746874,b513f247,854b78f6,4937fb15,4799a0ff,b4026ebc,f57c8b5c,137d4373,ace4fad2,4e2c1705,34940b03,c6a2f0df), -S(612fbcdd,9f251b85,c43ea00,57b847fd,db78f2d1,6031505d,26a81920,e4c32619,aeb8a7f3,332bb112,fdd78825,fbaaedf1,199431df,929c5cde,b5a173b6,721fc139), -S(a2417653,34077e0f,3201dc47,f6ec3fe5,546b08e6,4f12dfb6,3e0ce0e6,18db62fb,271d6d97,9f686ac3,c4191cb2,1a3cfc65,66471502,b9e85207,47948345,1199a73d), -S(fc216e07,b2bc34e3,bba2f0e4,db770bc,33676cc9,1a5f24f7,cb2028d1,7e4c5f9c,fb16790c,386611bd,e567b83e,571a8fd8,97332566,6d2aea7c,903bb4a2,b5354b5), -S(6d44d409,e5f13c7b,e51c1835,f5b223b3,801b3895,802f6164,63f5a51c,449da3d2,6389e29d,957a6961,d796620b,23ad36f0,45dfddbd,533345e6,679bcf06,9ab214d3), -S(7783276c,a37fc014,3ce53700,c7ec741d,33c5222f,f4a10434,270fe9f3,cf70e9d3,9939b8b4,1c64a8e,6efd144c,78334bd9,33b86122,88ca1de4,22cb361d,eda16a82), -S(89339ebd,e4693665,ca9b88c7,f0a4c76d,2639e81c,86c349ea,aab9b974,a618d2de,6fa55c4c,ae7d0246,4e6d6f05,8ac772fe,1456c5c5,2d2b008b,afa9e4e8,bc7e99ba), -S(1ece996b,4408d,f01a9e25,7a6d8746,cdc75105,e614f6b0,5ac9c66,1226e55c,ab521d8e,effac213,38abac36,12958256,316d6858,594ddc46,9de7718f,d2714f48), -S(9c0434e,e311b25b,e1c4f60f,52e17c5d,59563a8e,c1b5278e,595e3ab9,32ceaa6e,a56270e5,c5e402d8,a1b84f23,6899e35c,b558ad6,3a168172,e1d60cf8,da904791), -S(87af4f94,912398cb,174965b,ca3e7e1e,957c67d7,fec69db1,a334154b,39fb41e4,5e981846,bff7a54e,ad594fc9,4cee7666,1a532bed,77e20165,12b58a3a,208fc410), -S(7bc7f81f,98686420,9b81fee2,aa157f6b,28b668ce,440dbaa6,f7a84fb3,5f3efc42,fc60d70a,908353ff,2f59fdcb,83a02ba6,5e20e6f7,5a73f0c0,b7cc096a,9b745208), -S(6ab61063,7567c0aa,c32da688,1d8e1918,b50a359e,c480a235,eea76e03,56d3472b,455f4f81,d6b88c81,72011644,f56f97b6,f2e0d2e3,e93780c1,ab0fe6ea,26388c16), -S(ff71967a,d8766265,b45a9cea,ba7542df,5bd35c9c,60fb5306,4d4de071,e0157e15,edd9241f,19d3bcba,c2470941,4fe7902d,14ef2c17,b3a2cb3a,481e4238,1618e94b), -S(9d4cc871,2f95c218,52c07b13,5c783ca2,3d9d2dcb,e8f2a78,8c9f042d,4629979d,ea4bbdfe,b3fffcad,9ff3426c,fafc59c7,254b6977,601eac7e,7355bf3d,ab7d7ffc), -S(e19a2aa5,49b720ea,2002b863,47dcccd5,b764f5c9,9bf63760,93612d03,cb5627d1,16c930a,b0dda080,45b0c758,4ffbc063,37a9d42,27fa5d8,33f61e9e,356fbbb2), -S(fbf6c918,fdb5292b,17df3aab,e54664b2,80e59ec,e9ed6103,e5f3557c,e7e9320a,84454694,62f6d530,4a82cdf1,3310527b,50fcc8ff,13751550,cdd6da1,ccf20b9f), -S(f9912cc9,597a48a2,7a581be2,c72cf767,effcfaf,c0ad7a04,af2aa105,8fe1a19f,dd2c8c9f,da952245,1e9521dc,f5899430,51f4ea56,6ce31d67,d2936ad8,209eb005), -S(52ea2681,cc2b8988,3d283a50,77ff1af3,95ba85da,3c70f20b,fd1d6652,1f9aeba,c6440e0a,8d700973,5c5b6e1c,6aac224a,76481a30,5f732630,30353cb,4cd630fd), -S(164d8059,3689a410,d49574a0,925192a6,f1a55289,187b3c97,30030142,36d940ec,46ade58c,909d01a4,fd827090,d266362e,cf2a374f,95b2463f,e184288e,9534ede3), -S(e32e1230,46171571,6410013d,b1fb8ba2,f8914aa9,43cafc5f,91ac552f,4d8e24a7,4af269c7,ed6218ae,6c1db9a9,4e5832bf,a29457c8,4c814d52,24dc9e2e,42674407), -S(d57bdde2,6e43bd76,5a33cb8c,a4e54db4,df3798da,5d930148,37eb0dca,35e0f999,7a74180e,5225fec0,20a10d63,2cb2134c,c4109799,22508f5c,d86332ae,8ea7c89e), -S(b5bc01b6,4203cb60,caf4a7c6,e48a1c25,a92d0eb3,bac74789,cf5288b3,80839576,30403b6b,2824a95b,7810301e,b467cc7,b882e5c0,a02c28bc,bae550d2,5c83289c), -S(73b1be34,b9229a1b,bc7e8cda,6027b7d0,4c60ea20,3942fa98,98f5a4b8,98b510d1,7336599c,9aeef8a6,296637b4,13b2f22,4c5ad7d,fc00b225,9152c891,249539b6), -S(a165d932,4b255170,998d39ce,39d392b2,cbccf282,2dc1acd1,c364fe28,dce909f5,f24c5fc8,cd8cb2c9,2bed63ea,a9a2dfcd,932915d9,dc2e9199,d2626fd6,b360f64), -S(92eb21ef,fb8d4e26,89bcad2a,2c4f1e57,85a8fefb,e4b6f8db,c0fc1681,3618058b,7ed25a50,4174b429,103968f2,8f4a03ef,96b583dd,840c32f8,ee1e7774,3e9ced10), -S(6a15d7d5,c5a1d77e,a7544c52,123d0e30,492a021d,3ef16056,46dbd533,e181ebf4,d4d14e77,54a5cada,520f218a,58611e5a,dd6c4c1,755abce8,6050b0fd,ad239957), -S(75ea5369,8a9f0d5b,49a0401b,b2db3286,5a8620cf,d29212d0,1bb097d0,1547cbea,f3e1dbb3,d50fc3aa,e6c16113,1271112b,4fc78855,ea6f303e,51268c9b,2535b159), -S(a3c4dca4,1ba14d89,51b088a,5667f8a2,f8ae1e3,e0438a86,c330c484,4ea34fe8,8113e61c,bc74488e,96fa68df,12fe199f,b0b2366,de19294a,de19ab0c,a24dbd31), -S(be54fb56,80bd0b30,3d331242,63714604,36c66704,8630035e,191c4a2c,f69400cd,15a679af,a8b0c05d,b5408a2e,b3ddf648,86bfe8bd,721abc7b,8bc4aca9,f1eb0e5b), -S(ff1244e4,a157e177,f5700b47,9787853c,c517c335,7dc1f548,a19ad178,f6a40b4,db21c79a,12f90142,befed50c,e9763426,b99b4d9e,f3f37c17,25abd50d,7cadf848), -S(84038a62,5d232480,997e8ee1,5b0e04a,547e2381,74955b30,14da26ea,8aac7c1e,87552fb2,b09c56a9,a81e40d4,9fab776d,62c1a5bf,63a84e01,9b869c9,40f7ac51), -S(50f7f61f,46489c82,2a8ee22a,7e79ca89,1ae4a185,9004a039,da3d16a2,fbe61608,6eb139c5,f399d702,5094ae5e,3035d3a9,e355e4f4,2ccad686,566d298,42eb788d), -S(c05af73b,9858124d,8ccb5eb0,232d8821,d98d220d,f4ade4fb,99519c07,ac665ab1,7493a780,35acd676,966604de,13af29d0,3a78a962,7cf3bb3d,1b1663d9,6a7e36b3), -S(1f480d5c,2a1d1761,ea954284,d2a072a,a66bb6f0,738d2640,4ec9cd34,bcff91b7,10207028,def341b,44a34078,f07af764,2a879d2f,a9e3a18b,ea7450be,1d3e1770), -S(a0676e87,8944445f,d40dd575,fb0214b5,983b164b,2fede667,b36f16da,4ca3e338,6cf3c93c,9ca2fd3a,b0ac23c4,33064a6,d1a6d275,3614be7e,a72cb3ce,e9e02f0e), -S(13e73034,7c823fb6,2769ebb3,ebe492ac,243a3bb0,2f84bbf1,6de239a5,f1fe62a4,564f2cda,316ad30f,5a552164,2a1ff7a8,92ad0afb,8bf2928,ff5e3970,9005f251), -S(18a96b04,1592fdec,101b7df2,6dec0d49,6be4ca32,be96f54d,436242f9,8092c481,cf03371e,e4d2d4c9,2ea7ad23,db3f8f97,d1a96a73,13b70e82,c3ee58ea,f7567ff2), -S(9592f438,339a1044,85ae414b,d30cad38,929004dc,e73fdf8,c86fa2c6,776e5bac,40de2fc4,66571358,ccab78f2,fa40acf4,d7c98188,31d475e5,556e7b68,d6c37235), -S(bd76f4f0,b9ffa96a,1a563855,6b35d855,f07580d4,45d10505,b1e5f546,255429fa,551cfb81,d1d05bdc,e66cfddf,a4843228,423540a4,278e5a9a,55137a9b,37866d6b), -S(fbc20168,bd1f044d,2ebddf8,a7dc1b2b,97d7399f,21d29fef,fba5f8f2,fb60b84b,d459b367,6516cafa,b6dcc1b3,8ddb10f3,8ea3ac,7f73b4b1,3052ff45,6d624c2e), -S(240584b5,5c64bdcf,4f233adc,eb7c9c7c,41d1863a,b0ff7ba1,68f74c8,1ddff33e,221e273d,ac154ab1,f4d259f7,e5803f5a,dcb297a0,48a39637,6e15327d,fc6b194b), -S(76798d07,c586b782,51e6accd,593a2534,70c77c59,da326d1c,f8ff561,8ab0e8c5,64ae34a8,8c9dbeb3,901a997b,eeb4a9ee,4b486c1c,b3dd9da3,218106cc,7d07292), -S(7a9f198,966c08ef,f9259fd9,5a3a198b,eddf9f77,384b671a,cbc16ba,5465b618,abc994a5,8a0c8dd,d98200c8,eb951e61,16a553a2,27ef6e16,bbb27bea,e0191a66), -S(dc8ca205,279a54bd,8552336e,31e02c72,909e4c9c,d7560616,1ab4e439,173edc73,b08feff6,221c061d,7891890f,be84a459,a57eb118,b67c4ff4,7ae62d56,7c158f9a), -S(575a0e7c,dfd55dc0,f86bdeff,7ac8a740,168f976f,be2eb9a2,2bcfe376,290e9085,5f0303eb,5d8ee545,485c945d,5ea765f9,7aeef7f4,e7d6b802,184261f4,9995f574), -S(50e48366,e86ae12f,14a9a78b,22e76176,fed8e25c,ccec2033,f85e7473,96756ea2,8af4e0e2,57b6479a,d58b2f24,2f256a20,ea30864,89b84b2e,27da8481,d8eccd3b), -S(9c98498,d5bfb24d,23f25983,952263cd,9513fadb,a91dd60a,26b7dedc,6fb42e6,c5ea0af6,4b90d3f3,37bbc24a,c2138426,bb349f6c,d8b23829,d0ea1da0,2107ecd), -S(dc253e10,17608817,898ca299,2d325aa0,20f88ac1,676e81d0,d81e75a3,884015d,add05f5,1d8ce337,a62e2401,399015a7,608c1446,7cc042be,2da908f9,b6ee807b), -S(9ccddfc1,8c88e1ca,cd5773b2,b378ee98,e4ed6084,d8fe9a06,e115fd67,a6f01671,439d7033,6ad30482,a7bb89f5,425c5295,cd888c44,b0a0bbd2,7b2b0ad9,499b8ec4), -S(3654e9ba,ff41cae8,6129545f,9207cc3c,315773d0,b230e4d3,24456721,f220e8d4,98eb6499,702161fb,feb0d263,1702bdda,52aa5ea1,867351ba,779f485,7ae3d59f), -S(af31613f,e474bdf1,7320682e,4d1b35f6,ed6ae63f,806a7cb9,f9a47ea2,fd8a38c3,c5fdf037,2cd6f61d,bfb96b98,19819aa3,3848b84c,4b1b69dc,cbb6d9a9,5e3fd807), -S(d8e1f1,d2913c6e,553ae630,64cf7673,437c2843,7f715720,3567b881,7552c73c,e20ce3d1,b6d10cc2,517dcd67,ea82d676,555e66f2,3ed742a0,597065c1,d849b9a4), -S(b3ef1895,7f8f2cf3,3545a9d4,7e0c3c4d,7e24e363,85c1d680,67104d9e,1f2884c0,8c2f8d97,32ab264f,a5d63cdd,f36cc4bf,4cf4ae6c,8e0fb04a,c232364c,37b0e53e), -S(d2d86d8a,68ff342e,a6c3c79f,42ded832,9098af79,dc2c83e,39e5a728,889f1bd6,9cd4fae9,db605e9b,fe25c52b,14d75e2c,a8c9b58f,c6c18d76,c5fca9b7,f6b9d2ce), -S(a4ac3b1d,39a44643,b0487b6c,76cf24f1,114eac8e,2163740e,b63776ea,52432f91,b2278137,c5a81c23,e9bfca31,fd6cfbe9,f11cf1bf,d1f32573,f581d68b,5acf4a99), -S(b12353c7,56fc4737,7d7f0383,6f6c6f62,594323f3,cb27d4b2,d64c4b81,ee3e0b7d,6813fa5b,a5ef894f,6fee8ae9,ebf2b1c1,c6298976,560c731a,df87fcbd,f916a837), -S(5f1a8fd7,b5299929,c5e1865,c28eebaa,13c558c,cce6f26a,edfa80a3,a1450646,b043c995,c6d66c56,77f7dc03,f7e599e3,70e89ff7,899ca5e7,165ebb15,f590d867), -S(ad4222e9,583e2afb,2c56a116,500514d1,92c0b10d,4eb66592,2334c817,623aa28a,97e34c9f,bd9650b5,a5444e2,4a04c5a0,78ced6e1,2e21f516,60a3d4a4,fd2319f6), -S(289585d2,886d9020,8870975d,93373b87,b3ab1909,21d392c,82abb695,22681e2,a40915cd,21358a51,798e18a7,9595b3b6,b7a645cb,2905bf75,db2c2438,2ad63073), -S(3ed81e00,a9607ac1,8167afd1,e25d80e1,9a4c1a23,69682ec6,9f40ba13,d86e818,59ce30f9,8f646855,ce9fafb,abf7b2b9,deb1be30,de5edf17,7462fe3d,66f02e27), -S(5c12a417,91a0f2bc,42cbb301,346b4e09,d68d4720,aef188e,7ba44469,e2e63f4c,540ad65c,9432a241,5a1e1af3,2d6f8c88,8c47a741,52d6224,f3d5e486,7a219c6a), -S(62e3fef7,6ec4db38,5010b30f,ac2803ec,27088e79,2db7f8f,72be35f,895ffb61,c0c8efdf,f9589931,14c1bd72,891e2743,b3189ec7,1f05d5e8,a0d7cfd1,753279af), -S(677740ec,ea09a280,7968ea8d,fed5cfa0,58d9564e,8f22f96b,79303074,58015089,cec6fce,30608c7b,2cf3bee7,353be7bf,a8265b2a,a6f058bd,1fd87059,f261beab), -S(ccb0c3cd,7d9ae81,f366e10d,c5444cb6,b713088c,739ca70b,fa214359,9b806937,4562fac0,408cc5a6,a961d8f3,92ac2566,cf02b599,7d645d57,bd81f678,dbd9c43c), -S(2db401c8,d474f7ea,a25088d9,d835a9ec,b1ae4f04,bedd711e,154ccd12,79a5e68,654a9bf0,ab608472,51922ffb,aea4769b,29894a4e,be1d175b,973fbdd6,7393bce3), -S(514a03c3,5204855,f4339a8a,d8894a5e,f0f7f8cd,b02d597,6d4ff85c,7a37fd1a,25d67f20,94a0f6c1,49999c5b,dd4808ad,d49f0875,882bfbaa,b391a8ee,7f7f32e1), -S(90e74327,cd112d5a,b93ec168,56b3292f,45eb178f,5578ea2b,a51a8b03,2b51c78d,fdb46efa,92e1972f,7c269259,3ed95630,74752c76,cce15d51,c1fcb011,19b7f797), -S(a9ef7f4f,857083f4,1eb3cdf1,76b738d7,f25b8c3a,e4705a26,21d791c2,abdcea1f,8dd007cc,7c6da435,267329ba,17435394,6319fdbd,8cdc9ce5,2250cbf8,252d8de4), -S(7dc56b22,14d62402,1c42f6f4,f148c146,6156c1f7,7d14d505,6e65ac0,693952f3,ba58259,523d0aba,a8bebda7,dfc67df9,4e28aa03,957357d7,235725ff,bd6cbab0), -S(11f8b2c0,a75a1423,42da84dd,4d04e5cc,e499f5e8,cefd2b5d,e73ec422,1718239f,29e26227,6ed2f32d,7824ec3b,5b776fcb,ea5800b9,2acf0a31,bff27cd0,7c8cee02), -S(9d0ce33,8fbd0443,3de6d15b,6dc3605c,edff75a7,4cd08e53,7e078ed8,bfd3a1bd,ea0b5cf,3a63c7ea,6b17dd3,fa19139,9078d02b,760f7d2c,f56d4a83,a8f0bffe), -S(9116520a,ff9d1ad1,e6c1031f,f9388b1,b1b2bdef,52f49937,a93752a0,75bb21d7,2ab7c4ff,47368f76,c1df0b33,54bdbee,157d7b2f,df4e19d9,d1f09c87,75d95c0f), -S(89c5fbce,ba4859ae,2706d0a1,e4ea2956,ebe71d40,3d1eb34d,7042291e,6f584015,c3a99137,2fe042ec,1dd7c83d,4e915231,cd5ad4dd,5bdb3877,bee1f9a6,8dd368c), -S(2f4fba9e,eba5a0a7,b22dbf3a,9867bb06,ebf3c4d4,ca5353ed,315b1752,3163d4bb,6c156492,d245e1cf,7673aa12,e78d0b45,d6171dc7,be574418,aecb9f12,3d6e8ad9), -S(905912fd,599f59e9,a3009b0a,7eb38034,fd9ab746,336831cd,a1985ba5,37d39931,9a7716b0,3524e8dc,714c76b7,a486660b,2ab30e45,b3bed8e4,f24e62bc,d1705272), -S(13cbfa57,515d5d33,1d8823f2,a8b5e083,19239bc,b1920aad,42d4f6c6,9934d0d7,f36e2353,700f0313,9236618a,ab0b5fde,5a8e14af,8e5e12f,47fda9c3,79ac150a), -S(cc939020,199611b1,c97458b9,cb9494cd,a9dfb14c,a2cce863,3ea361b4,68fd0857,a33978fd,e5c6a683,90dc368f,37e01e76,e2c08a1b,512fd2bd,d71abb9c,87ab7bf4), -S(6ff68519,e62b3e23,744a2136,2292bc79,3c7bda5c,4ef1ad09,81843ef7,183dd564,6d4676cc,baa85268,a4694ef8,55e86386,1f0f5a3c,38c8cb94,4ff81c53,c0737da1), -S(60a82e4a,5084495a,ad08d440,45639dbb,e0c34867,6dc3bd33,4f447815,6702418c,666c2a2b,ff70a40e,c01c5f34,cca48f00,16896e55,f14d21c1,e2fa80df,d4352943), -S(57231292,66d1532,f352005f,b3e789d7,b19409f8,cebec41,b8b43330,cef1a7,5904c51,ad1f7ac8,ca6a0ad6,971588c3,42f98ba8,6fab3f9,b07b648a,26f3269c), -S(c50d8b68,bb031e89,131a9be3,1882c8dc,bb109fd7,6df989d0,4b0009e,cd2db9e3,10286cb5,875480b9,3bc78987,9615095,9126c3ee,c66e23e2,3b21231f,d41fc039), -S(ea74572a,bb5ac532,fadcfc73,b85328f5,de42ce24,d79950b8,7f6e0c98,e6fec3f2,c68a3ff6,254bd3c9,febab9ba,c6dba6f,33d34551,d8bf2c14,ffc29c09,10ab374c), -S(430f73e0,8eec3d03,8bab8afd,9b30a5b3,5008ddd7,4cb85aeb,7b836ade,3f25f6da,27e179cb,ed69a2ff,ccceef02,cd1b8b9,6591deb3,b94a905d,df9e0df6,f6e8fc7), -S(dfd0f623,61e9baad,2fede6ed,9a6dcff5,3bf259fc,704c37b7,6b9a3665,a0296709,a9ed876d,5cfdf560,d3896579,57ce1aa6,13795b86,1e2e493f,719b8cd1,85e11f84), -S(f486a524,89f858be,ab920853,b27e5ef,945ebfb1,def5bbdb,8a7f1761,451ec105,f50aa3d0,cc587372,a1e941d7,608c86bd,10bdeb39,60cf57c8,482113a8,d3039da1), -S(3ddb3b7a,9b0218d0,2fc62004,33d21317,5d811aa5,a5d6b9cb,53ceee05,75341982,84017fa6,1ed2827f,f65d3bc2,3343effd,403f77c0,4524be5f,4c763bcd,d04b70a7), -S(c5938802,42f1bf38,5f5574e6,815ea291,b13578a6,cf8a31ca,d516d3fe,ebfb1488,5c0f3858,e6dd3b7e,f68b4368,dc3b5a95,d866e2bb,fe269527,fdf4b3af,e9196375), -S(11c60556,d6584b79,882f75c3,92e036e4,2aa702be,1f545e15,403eff6f,e27cb59,8544c8df,51e9a3fe,790fbbbe,f768e45f,c8a39319,1b18b4f5,8ae85d17,eac28fed), -S(ab609b1,52efce6a,eaea4c68,e498d414,9fe8aff,28196efa,a39a897f,5969382c,a4f7fd94,e87c1a0b,b9502f5,438c7a30,b6fb836f,17a19720,ab07e286,f94c8eb4), -S(7c188bb,109dc167,bb66cf50,58f263c3,ca8f58f5,66c9c0b6,b838bf9c,7cca26b9,1236a5a,bb04ef11,81b22343,327607c1,8693eea2,3c129a3c,377ee493,d332a5f4), -S(bae48149,f37ba68,24c47e5d,1fde4ee7,14f1cacb,8cec8ae2,de547927,768699e7,433d31de,c9619480,c2984475,5e7c3813,bfec984d,b0d9fed4,f25e94ea,8e747cd6), -S(88ec8b53,d57f2ff3,db3661b2,46989ecc,63c0f757,6acc7c17,cd0f5792,b006b5f3,9f35942c,28f0198b,cc3afbd7,b8f28ddd,1dceafa1,4db9557b,35d4984a,e80160bb), -S(67efbcd0,b5cbc215,c453d642,d1b19bb4,437509,33ff6afa,1ef923e6,cc83768c,6575c0c3,489a7bc3,7865d32f,dd8f2a24,a4be1df3,ec7765eb,ae09f10d,342538cd), -S(12f7791f,4b9310a4,c9d333bc,eabc3472,9762040a,5713829a,9a58bc72,47e51db5,15eba5f1,e156cd5b,409ffcca,876dc51,9f4f6e17,93ecef35,7b32dedf,fb12b402), -S(bc145b46,130e431e,18b357e8,a47f90a1,c38842d2,7fadd3b3,58d21959,daa3effd,4a62a5de,d23f1d44,ee86ae12,a03e4a6,5d1794c3,d7621871,cced4b58,116c97e5), -S(514fc2c,e7c864fb,b54fb8c4,545dbef7,7fbe45fc,d7ae312f,8866c608,12658866,552ca131,45466fa8,b6ce58ae,77c01a39,1f9001a8,bd9e6a4e,fb434b6b,9d63b79), -S(7c2bfe51,f4a9a32d,2f7feae1,96fdaa4b,45670ed6,f9c02940,633680ca,afae3f88,88bb43f3,996bb5fd,ea4a37d,e8c5270b,571644db,e1704bf6,aa207aaf,cc2742f1), -S(7710c58e,36f3ca17,8b96dc57,21acdbce,e37f7879,6f9f251a,df4c8dbf,599c6185,f600262d,d2a15427,ed6ea68,4482efe4,f57084c4,ce1ca445,8f85f646,4d954696), -S(5d4cda56,c705e89e,8afcd145,5490d589,63de5bf3,79d20a4c,acb1ba1d,c2effa6,f6a2f87a,cf9acd28,c7b12c4f,a42bc4d2,3e5c726,1d404813,30b99d15,533cca94), -S(e3bff796,4e38d5a1,946d54a5,5a7c9999,8faf4e08,2eeaf460,7dbb37fe,10b49bcc,7d6b4ab3,5d711881,a26d7327,bcd8eded,61cf85aa,f56b244f,58d4106e,8558f3e6), -S(75b80f78,c88f6e67,9ff252d3,e7c10a87,c2933642,53fcf204,1625457e,542c9398,db3b2fde,be9e05a4,a722ad7a,aeca21e7,3ef934d4,372f192a,a07b081e,c6419681), -S(4f640190,51d6332b,d29ab6c3,7511cb28,ba111146,189e4ed9,8b945e96,d4ceb5a9,626d0d0d,ef4192ba,a7874638,fcc07075,fd65b688,4615cb3e,5c63167e,965293de), -S(4f90520a,ee7b050f,cdbcc57f,cb03f361,f950e5f5,bd723d1,33de2990,df09219f,f12a8382,f2b1a67,c9868b2a,566e8734,2ac332f3,87d7864d,23ab4d33,395c4144), -S(f5ee8ddd,c044fb9f,babb5ced,4ab56f0,c4d357e0,69066828,23b02321,6fac446c,ec53db7f,cec7c393,d8b74749,981f6f32,c4462dac,6f0a56e4,34d52b34,d97b9d3d), -S(69727ad7,b48c376f,cb2c4cb6,b5c0e4ee,cb1f5925,f1928599,c55c4f2c,b31cf7be,39b486c2,3804bb69,b39d727c,eee110be,966da862,32eabbba,73ef17af,1c8df334), -S(23d1da9d,42bd74d7,cccdef4e,aa79e725,32fde7fd,b43522cc,b0c8166,1090f19,a168e435,f673bfaa,84115cbc,85a25973,5aa26ed8,86a1136e,ed3fedaf,b939e9d1), -S(8add82ca,322cb7d0,68e98c5e,d4f66993,50a2b2af,5bf0ba10,4e012389,f90a38,cee02a7,1df433a8,46ab9f11,503702c8,b93d609,fbf882b5,6465a9ca,445238eb), -S(874552f4,f2b5552a,b9e9dd9e,a8bcd62c,52f3036d,2b7d7a7a,3bf206db,18490830,12197e8d,de19c33f,37f50ba2,362642a3,87741090,68b2ba51,c5b13fe6,5d3b3a18), -S(7b5e3f54,d959d208,17c7c518,62628a07,ae2ad59c,6bc4458f,467e213c,ba145fe,bc3a8595,527be77f,c8cad2b,e9cbd810,8fc7104,9eef7ef1,924255de,6aa6fce3), -S(298e18e,d4790215,d0a82b37,b09d6b7c,90ee8408,13f6cb33,b150a3ea,d14fe41c,a2504d96,a1345a22,8e14e82a,eb160798,c7bb5cda,6ccd4bb3,74093c69,93e0294a), -S(22bfb660,2b823430,e44d0358,300a5fd3,853577ef,79b73104,12122749,74af1edd,ee318018,3617fc09,4d3a3707,df38e9a1,bf9ec587,45e251fb,8a127137,3c9b3e85), -S(41dcf360,e9b5b5b8,bee689f9,1446a874,5a4df0fe,1963c132,5d05227a,313d08b,103125ef,ac9a3fcf,f8033bb5,659b81f4,982a2f31,7382c0bf,b4c4a73,8479da5), -S(71b0f642,7f6127ad,77318fe5,27f57c41,e34af0dc,311669af,fe695a46,102dba7f,b6bb548d,f92c9087,c1f0d543,2737e853,d5a03e2f,e607057,352084ec,3060d823), -S(c36150f6,be139991,3df1cb29,3324da28,bbf75056,aa8102b1,e2be7e8,a669eaef,ec869956,1d5d9e8e,73268641,d7a7d01b,f1613d5b,145d2631,97abaddb,ae8eadc9), -S(26c0a835,20d9ae57,77ec9e5e,af9836fc,389a671a,6823f705,6eb5562,bde7193b,1939de0f,da69f7c1,fdeba6fb,f982cc12,b39640b5,f92253ce,9c84667c,9e75d56f), -S(5cce3427,e2cd7404,2cbf501b,2349bcdd,e1e9cc1b,d9ac179b,e848dd89,7378be5b,8148375f,ad9d42e4,6562dd11,463aff04,281c00be,12b40b8a,b97b638f,3a525901), -S(cdb56ff0,9c36fe2e,74546bcf,44b996c7,ec11862c,a5c0f0a6,1c352bb7,771f3f7b,f97dd0c4,6d0409d7,3559d6b1,a450a8,ba5e8d5e,dc0f1a32,df840f06,20348fc), -S(379abd64,fa180ad7,9343b3d,d2b6ab31,5534a19,dd59e25e,9a37271b,de58e2e5,512f6ce1,c2fa1202,2a6dc666,25f3b8a9,56c1a5,ccd5ddef,6c1b94c1,1c507472), -S(8c32725f,d1fa4998,794bed8e,eafeb3d7,c24caba6,4a693aad,14055160,e0eb4df3,e91ae4de,54a8db16,bfdf48de,d3835586,ed1cb6f4,f767eb04,343cc260,c2a008a2), -S(6f6c310b,c1afe979,cf032c40,2f594512,ab074b31,f336579a,b9e52fcc,6543e882,87cd5368,561c5897,d00a2a97,2166950,5b4f9e1a,a1aaf8f3,cd817e9,5e48df08), -S(299829f3,2cb34343,5caa2fb9,426e24c0,5a84466,2c2aa34a,ac75d454,50b54b39,3bbd3e13,50a11a04,31b44d63,24eec80c,64065603,3960c6e8,b82b6711,d660bed9), -S(5275ff78,3529d268,51fb398d,5559b300,ac09ddfd,39cf0bbb,e02f50d4,13fe62de,7d3356f5,a74c829a,bbd294f,cb302d69,c30fdaa8,64c1ab4b,fc734e5f,ea8f848d), -S(3e04cfc2,e7cea4e8,4c3ca490,2ce0ff69,883e19f1,6952252a,51edfda3,6ad04b5d,39536901,283e998f,ed4ecf2b,e708d5d3,9b19c290,c76b8faa,4cd4f94f,7f05e813), -S(58273a33,3dae61a2,71970034,3c72d8ba,697a1fd3,527bb291,e098ad6d,173525ba,c2f0e095,98d4d04,fb156dda,49676761,774d09b0,e43fc92c,7957ae66,396e57a2), -S(4f43ee17,95d428aa,ddff7252,536a7bb0,29fab5a8,cb60f3e3,21ceb52c,410e49a9,d17315b,c0288557,c4a9a48,8372722f,ce0bfc3c,4ee0572c,6682934a,18fa2c75), -S(b8b61408,4abbb43,10b2551a,8fbd7503,9856cc49,4f793567,cd7c205f,21cd9174,b45edf3b,ae914c9e,cd7fe61c,bee4278,5bfd96e9,c6493fae,b465e10c,8e6aa815), -S(9ff66284,41cfba00,c15074b4,aaac29b5,c12c3d0,59009391,880db30c,69bb700d,95f71bb3,8875faad,373a2dc0,b18f1d31,cf161cbb,b1d1d5fd,fe2abeb2,e1a6df69), -S(69176264,329a1ad7,8bbacedd,3b99a5d0,c3694973,c4a5df27,d7facc58,b25b3231,10fd42f1,1bf91b0a,a330bbfb,b598b7,be2c2faa,354e148,b3903a6e,697bd350), -S(94546c5a,b4a5dcc1,d9a8fa0,ac117012,470247a7,913d0acc,e8c7c2b0,d98ad04c,7894e112,11e816e,a03586c0,33a737df,8e11ec0,7c85295b,1305f575,2a9bf9fe), -S(fc476882,d286cf0d,3e29b73c,744cee4b,563289a6,c367fa59,ab3e93d2,b0f71314,8680b7ec,6d633583,ad923db3,1ee3dec9,6b4ddd95,c331a670,d759ab82,ffa07ed3), -S(d5279e6f,62490fff,5ca2f0b6,7a8153fa,3a5fb95f,2262dd3d,4e62fdb3,bfd116ff,831b6dc5,7f16d6b5,c25c6b46,9111fa5,48cfe44f,76eeb9b1,55614b7b,aacec99b), -S(8174add4,de57b198,9a999ac,9ccfeb1d,78a21fa4,bdbdb88f,792829f6,3d21923b,39292fef,300539b1,ec4ea7e5,9a943b18,e4cab57b,36c8fcb,47a96d0a,73facc18), -S(dfd1f8a1,88cd5554,6cc5b417,c2c30cd3,c34ea95e,a9087a9c,cd240cd0,9d6b8494,6616b3c6,881b9cfc,cf0438de,1e9bb54c,f213c9c3,d0458ce1,e49f3da7,17c6ff33), -S(40d6faf6,aca0880b,6f639406,a187f116,6e1d1656,763a223,cf2d9805,f8059521,26402921,86884ddb,59030708,d12a34b7,1e1f592d,b8316aaa,50f3b95,3dee82fd), -S(a06e4e4e,df868121,9ee140b1,1d688bde,1e9f0050,cb9e122e,e12bd046,b6fd999a,76f0b3b2,522571c1,28cd7423,273e0a0d,5ce2e41e,dcf844ab,3a44b18a,f29fe0e6), -S(8ed7e5b,efcd7322,7b537ffb,728d5c01,450445f4,5f187ff1,5182fd57,817c7e02,fdff3f74,179e2229,a680a538,73288b80,17819a8,953f358b,25ee7b8f,c2c1a89c), -S(1b7d6838,d0b5a412,9c0fd19,cc917166,c9c351d1,33d8db84,7f39ffdb,463dcfc,c50a0eb9,a20ff1f7,67c21dde,9a74271f,2d2e7c8d,3a45251,8bd61ba7,9953c58), -S(c991fd97,ac37ffa7,968bb26d,1793ffde,49ed283f,699b4620,7520849e,cda25769,9cc861dd,b39e36a8,c408a09d,cb2b22ce,c0302a6a,3b1ed1a9,d89f9784,e0f0b766), -S(849cdec4,66bcc09f,9a689c,299fce1,d1b37e8e,c59d9184,3d519da4,937d2117,c759660a,92c29619,70188f0d,8a539585,88ca929d,f9468ed0,3be6d6fe,cbcded23), -S(4ced9d61,7462a2b4,3cfa38db,1e4489f,3e527425,d48807f7,bf73cd93,a731e351,a9954e80,fb6c42c7,165b4cee,976199ac,2e6871b3,b088fae0,f040f09c,b91a0ea7), -S(fa952014,80bed20a,514df1dd,6d8541e2,f7bb05f7,4eda2a56,ed1d2a0a,6300ea2a,3e887eb6,edc0c858,18b1bbb4,8a54027a,aaa11988,c8063f14,98f7d1a9,64b8d818), -S(aafb82be,ff591455,e3c11ee2,ed724caf,46f86053,708699f4,38180f5e,a0156d90,63bd1026,f928de57,cba2fe5c,890d02b8,1afd2eea,2ff8a5d7,6708c70d,6172dab1), -S(9788ab96,c57bcb54,3797c014,a20704d6,56eef193,f0459b4b,b2617a90,3ba30842,1e81188e,28ba4be6,d244ae0e,2574d0bb,ab51fdc1,5ca4472b,b7b82a9d,dab005a6), -S(58fffe9d,6d6e176e,d006b35,52133322,c8e95d2c,4040fd4a,3a04ce94,dd5d0241,6f8bf132,7d0aee77,4e88f397,e2cd1594,39cd3c32,5a0313e6,d63e5e52,5974a647), -S(65d3d1c9,f10eb74c,6a27fbdd,f39d4ec2,8995aa50,3bdaec76,2f7051a0,23190b4b,42c3128d,959d7b3d,b585043e,3d042252,6e2c1b3e,714a2938,42cafeae,22333ced), -S(5240e75a,419ff988,d9e9a27,1a9719be,3d2c960b,eb574aee,fe278acc,5466fbbc,56aaa8d7,76953819,904cecbe,cbfd680e,99df80e5,c6a9100b,1fb8a570,6d28fa7b), -S(6f00eae2,ddbcbec3,cdbb2079,d7300565,12087a6d,b2f5df8,8d2db4ec,9358a8b8,81ae19b7,88ada62f,dd68da42,fcea16d4,699467,dbcfb314,51cfa318,e71388a3), -S(a7c58025,ec88b71b,bbe8a9f3,15b3b182,3ac7ea83,95ff1ae5,eb0889ac,d7a5aeb2,4decc4ac,78e45b5d,b76f969f,59dbd448,c0100f21,79aed6f9,bdd089c4,5f02dccc), -S(f5534fc1,b0bd55c7,e0af5eea,c11567fe,b5694f1,cc60830f,cac6ebf,ba0bc0b2,a7ee28d1,7624a2ae,32841821,e1ca4934,c10e6087,819ef9b5,f0b56e1b,4467a9c4), -S(f43aa167,8f4c4a1d,2fe2551b,33c4eae9,5d7b12d0,276d37cc,a4e68e01,71521f6f,a64c65a7,1c7db76d,bc11cb6f,e9842c12,ba6653a4,2cf0bd8d,46656e31,feee083), -S(28cd19c8,3d8265ab,f0d38cb8,9f8be926,ee8df072,f096a363,94193af5,d16d9923,58625794,ac267f89,a6734390,a6bb719a,d5e9e2ae,6e0ea241,aad5407,7cc1bc26), -S(572703f6,5d834c93,d0e09fab,e92b1add,34245158,33682bcc,2e62c218,451ef85b,44daf6ac,a9af4ae0,a7026240,8074e4ae,72ad4d79,8145d431,760b26a6,33d05799), -S(27c6a3b,92bf753e,ec6b35ec,491fcf65,ee5387cc,b96cd73e,651b9b11,40b347f3,a881835a,4d28683,670934ab,95939dc9,5a0e5974,7cc9dc4d,c39d4a9c,12fe763e), -S(30a0db50,ecc1bf4e,3c34a171,ff648cd2,8a3fa45b,786cf15e,de01aa47,33a99eee,cb47e7d0,cae5a279,702aaaa3,a2865888,1676d851,9d15805b,cb8bf75e,23940a1), -S(d27e417f,f83b3a04,36ade27f,1b5448a6,fdc91da6,342584af,47f2b8c0,3d21ccf5,6d304d52,c9ddda31,14b68be0,49b57d55,45d43d4d,501b07c2,8d295a33,8f8ec396), -S(5bd5b0db,57c473b4,de32fba4,fb7b68a3,9f6e6c46,c6e72e50,b6ae8fc3,259331dc,cafd77c8,2b16bc35,a46a7c5,fc715c3e,cee644e2,4c000335,b472aa5d,4efc5a7d), -S(37e99dea,23a18371,1f23b80c,1e05f3ff,45ba6351,10c9fa7a,b927c808,e3e6fc45,3dcaf312,f8dfe055,ef6abba1,3e5eb0b6,70ce3c7,5724fcbf,67c61730,629ae0bf), -S(6b001dbe,be7a3db,6fa70b38,f46d13cb,77d759d6,ce6b7fd,153b87b,aa67f94b,7cbffcc0,f3d48278,d9d6b09,7923f646,b56d9fe1,77ce1111,d2abd2cb,6244aa85), -S(e4bfded,5c81c0b9,f1ae3fb8,7ac88e1a,d468ef72,bb3321b3,c3a4d549,fc073820,dcdce7a6,76b0b3f0,45b6331b,fb75ae0a,610473e4,b551a001,18674a8e,a3ef1d73), -S(ac834f65,dd566124,f837f049,bf0d73bf,4884a1dc,f1756462,3cbf375b,6c57aa9e,1bd6227f,c5265e61,53d0f350,6c698bc,a973669,1260d911,2e918308,48cedf1b), -S(d36b1cc6,e6fc735e,6e83957d,87e2c74f,8cc50202,ddff7610,fbdde385,22f40d3b,293f6494,c2ffc78c,8955a544,fbd4ca05,898e3560,e05f0949,cb6aec2c,a18994ae), -S(d2a214c2,b88a5126,1284b25f,d7f5ac2c,e04f8333,144ce351,dc057262,c9a1fce8,17fccbad,720577df,1db1230c,e2c68fb3,b603ce29,a26a6370,4fba4060,8c4dac60), -S(f3f9329b,ebaf25c8,7efc393c,66c308bd,461f55fb,c721975,6a504edd,f46d95c7,799cab78,1d1c65f9,2a5193a3,e6124166,586536c,f4389a35,d886bc95,f033ca0b), -S(3aa1cd82,ce4a7838,4cbfa6a2,85fc66f5,53edc1a3,2816b1eb,85142e86,528e0cc8,4b24bf4,3a8266ec,4223b77d,3452f3b6,72596458,11c5cd2f,8f043d71,88f87dd9), -S(4abb7ae,40395b18,5a1017e9,d8887ffa,480f57c5,41c9eda8,578f7e16,538c61dd,4b96d913,161669fe,43230df9,a18bc71e,e8d36dac,de48c3b,d9600b46,a29babec), -S(89ebe2c1,845fd4b,461cb4,bf9992e,5f08ca21,d9d24f32,2733f259,c53d8a92,dfeeba58,f1d23a91,a85b3405,2b875f04,e056732c,a576f8df,aa5dec9d,2dd747a7), -S(92915a37,29c505d7,493cc142,b2e16913,6c8d2015,fe68992c,eae45b1,62d465c3,1ac2d867,24260b1f,396777cc,61f0261a,d8a603a0,e3efbca4,fbe5f485,378ef947), -S(5367ad90,3c5d684c,920f38,76c3bc32,c0b42a65,e1ee8d0a,e59de048,15bf8e80,82bcfbd9,11bdc542,306c0a1d,dc4aa5d0,353bb0c9,3b36d255,8657e40c,85e121e1), -S(dba0a47f,2fd5e7c8,5c2c8bc3,69981126,15769156,852b0f24,1e6ea83c,e56a8817,7a8830c1,377a2973,35a66c63,40cec55e,7e57648,29f32586,3f4ca9ff,8d95c0ed), -S(ea85fbf1,911e9827,59ec5e0f,a87b1c39,ff555ef2,ab294982,1aca68a3,648251d9,164f58be,9b8c16e4,ac9001a1,815d5f37,4b7e050c,21cad8d2,b2be4a19,ceb0c359), -S(84e3099c,ddad8d5,82c7dfbf,df03f19c,54e214c0,a0d5e679,7feb9f3b,dd32e43,980b77a3,1d08480a,5ef191d0,5c8cf0fc,48d5039c,583ee3f0,d37a8151,c49fcf90), -S(edd595e2,f8cddbdf,71f39b87,9a063da9,8ad70ea0,f030d9b7,28bb666e,54eb9286,89f1969f,95953dba,a1ad1cc6,29cbac93,a4620a8f,5c9f63da,a62ee923,98ee0f49), -S(1a3f3b62,26834d98,23f80f02,963e0878,90d60328,d911374e,167c75e3,51247b23,afb1a632,652762b3,db6b6259,ca8452c0,b194eb76,f16e2cad,1096539b,2386ee41), -S(dc425571,5dd53bb7,f572a949,895fa277,23f6c177,a234d2d5,e3c6a67a,fc458f37,f1c54b9d,54679c34,dbd9452f,f5813e9a,138d56cf,c7d8162b,c1eecb9,20edf717), -S(f86b4286,8b3f187e,4ba6fbab,91b83a4b,60acae17,b800e594,cc996004,138ed24e,7ea7b45e,b5a2340b,92fb24b6,f02c51d7,14c02c88,e9fa216f,595253dd,58e6227e), -S(46d26f41,447935f0,af56788d,b33b640e,e661de65,ed1a49f3,db91ff13,48aebe29,5e79cbe0,80117377,6db73c6b,eed3fe8a,e7e30979,2208cf9f,e6c40850,f7257fc0), -S(fa42a015,e023a7e9,cbb36e76,b94593d3,2306a05d,9067ca2a,717c8ef3,2740575,9da9d901,41de45d5,52c6bc89,6c43655f,f8a35748,ac145c9c,ebc09dce,df93b9c), -S(d03e4507,fe4c815a,ea50b0c7,1469fab8,e1215ed2,c32710c3,ef90e85f,8123314c,d3676737,18dee1f2,a1c4444b,9f1f1b8b,c049717f,9c4cdf50,3ba74ec7,3d404e50), -S(a4aecddf,221518f7,b058d538,918281e5,7f36b313,d00aa7d8,d6277fab,13f6ac95,77738ad8,eab86a97,1711b719,21edfee9,edab979b,8799a123,b16d8a58,354dc0ac), -S(f0c70330,433998a8,627c2116,e5352b1e,d9754c24,3d775132,b48d3db,e150a7e0,5392f238,cc30eec0,aa887b99,29759f5e,1d9c252b,dc6d8989,3e46008c,4129140), -S(4f34fd4e,155fb49e,7f1d2407,f65d8d94,5ab8bf,14c33255,e764579d,28252d6e,29f3e40c,2fc42f54,dada4b65,3d103afd,e38027a2,3dca44e5,15e6c561,16bbb839), -S(ae34daf2,44babaaa,fe89f02c,8ed39b2d,ed4f09a0,db8cb7ba,e4145e61,954ca965,16b58ef7,f394d988,24c7019d,738a7dba,5be8afae,45bcc2f2,4cc7dd44,f60561ed), -S(4637fc06,95c91eba,d195450c,4067cd74,14c646c,8885beae,e99e6338,dace2e20,43a38d49,362174ae,52683128,ebc753f2,71e398d7,fa906f5e,22ff4dc2,2622171f), -S(7cca0cb7,f940ad95,6a0a4d4b,e040a3c7,4b7304b2,975eece3,eac0b4f6,fa240c08,34845b82,6a4df5b0,10f4ada5,b6c83ad9,5f932a33,8b319027,92796374,35c0ed9), -S(bc374aad,71cf40,8a1eabe1,20d44340,faf0f3a2,774b378f,90f08faf,3a7c626,4bd1b099,9f649446,20c7a58b,45081f50,178626c1,5f00451b,b3617b09,5ecabf74), -S(cf3bed1a,37aade71,b025c9b1,dfc46205,51b3dca3,10ff6bf0,4a89a492,85c6f4c2,7ac96d8f,1b856617,3896f216,d6756362,bd5a9ea7,9e521668,b0d3a05,f778f6ee), -S(e36904da,5d6970cc,44faa475,c6dfb02b,579adaf0,4612dc2d,a7c9a166,e7c771ab,1f164e1e,24a1452b,af2dde00,e8ee182d,2c9c84fd,1cfa67e6,f8ea5f00,376cb404), -S(f6b29ac4,3a3b28f9,453e5a58,ba715cda,7691126,bee6af97,e1c5bee4,199cf34f,81156562,89bd32f,f74a1484,15390fc0,a1451536,99ec5f72,97b191e7,98d75e12), -S(855b98e1,be5557c2,cc7825bd,ceba8296,4921a391,12ec245c,3d89fb52,a443b680,9d4d92f6,af921190,1129dae8,15e93939,9994d482,ed93bea0,a88ae69f,c3614f22), -S(c534fa2f,e0eb93a4,86a708ca,2bacdb6,74b17471,11fae4a5,1d4dc063,ce06873,9ee94f74,b1239ee1,cb96fc2c,4269b1e1,7980451b,881145a0,9ca5511e,985a57e9), -S(1615956,54dbb60e,9d446655,7b673,c5f7b662,ae1bd976,2096b356,1fde395,5cf45f18,5d88f4e9,3d8eef94,aa64996e,1648cb98,3bca5ae3,8f5d2a96,b1cd241a), -S(61ca23d9,875bfabb,d23096fb,a12f043f,d036053d,a4fd7f40,ffe63b5d,ca176fb1,699b75c,1391d3da,18405c5e,825520a2,d0c49c60,b07417ce,89bcb2c5,15ba1a05), -S(8ab48e3c,5cd1c014,473ed567,89edf015,917f7b09,47fda85d,294e531d,89124079,58b7a6d8,2bce79f4,189f0b43,7d009e06,43127468,1dd4d50f,ca2ac326,99dacaad), -S(b56e89d4,28960847,be87d5f6,59727e68,80f71a6c,a023dcd7,c5f0878,e3146d99,bac8519a,5d2c472d,ee3a2578,d0ff2a17,5e6801f7,8eead578,116c59b,f5bda8bc), -S(197dd8ad,b359a388,b7920a8,9395aa80,1c98c278,888dd30,cce2f2d0,2aec4d27,383205d4,8c7b943d,2e66c725,979acbfb,d5a62947,bd251407,e4481ed0,d5faa6e7), -S(b8388b28,61f8c667,18653876,526d02e5,27d20c29,e612002d,514ba09,853f694a,7963e44d,997c532c,bae94319,74aef26f,b5761b3d,5c8a2e76,2d35907,cb3ffd28), -S(5f6eebb,2ca12aec,b80ad8bb,b926fc93,53281e26,60660c29,41ca2cd3,b16c428c,5e5c92d4,41644c68,4d68e47c,c63c71ff,54634805,97955591,b8f68915,c506d92d), -S(cc4f7d7b,8e5b1d1f,f3c166a9,51832dc0,9503cc2f,e0fb1784,6f4910e1,eccc396b,a5701729,65400983,90d49ee3,10629444,b53f7a5b,3e31bec3,7eb99ddc,f02c8d95), -S(1bf0da05,6984e8e3,3741cd04,16e74372,2cc918b6,bfc964a1,1d63d0cb,590c5c86,e461a594,368cb7a5,4c93c589,67928a37,b6037b72,71113804,b2e64d8b,a840d00), -S(217cd3b7,9c1d9727,fd781ced,dbe735b4,2d655e69,e5f7ba8d,ce5eb68f,feb1913f,fe3fff21,ad8744e4,6e3fad85,4bed0d9d,f28b0bbb,96df1b40,b711ea21,b5241985), -S(55b99e36,7b8f7cd6,24ace387,2cb2675d,c25e6226,b1201b4f,4e1b039e,38365d75,706543ad,5c20ce2b,5501e8b8,4bf1d26c,fc07e60c,f40ae25,951fa46b,9ceee474), -S(db0bc491,688dcff1,6c81f280,a80ab2f6,c5efb3ce,2715f202,3f999ea2,805a59bc,2096cc70,588ea476,613ccb8d,c98a1989,8f729420,9adc1a3e,c77b126d,b277ecf6), -S(d961e10c,a83ebb9e,f39e3019,c1b378a,d94cc902,6eab0f3e,d203585,92a8e44c,87f46ee5,14689bde,3821f844,9f97a2a2,bb1db0f6,d2916674,1cfa028b,d21f40a3), -S(18ecc615,8d15a17b,50737a0e,6bc6953f,ee9f18cc,e20de26e,642a434d,d292032,63ada9c7,e3a8e367,970af87,20417ad2,eef85059,70b81b76,609fe8f7,c3a00ca4), -S(6ff356d5,262df09a,33ec10f,eb2e48b7,db91d6c8,dcc92f9e,e4fc39a3,813bba67,5bdd7a71,c46cc142,7d8a1835,e7ffee23,d0e025a8,e3027b1f,4892af19,2a2f0e0d), -S(49263558,22218dc2,943140c5,3a706f11,46faabef,f0fccaa9,77df5f99,44a77b2,d4d9db7b,7999d45b,9b51d776,6235e129,80c2d936,1943d867,65c4a54,5fb58e14), -S(ba68fca3,2b5e907c,896b3d2e,b9869a09,9d0f0fd8,bf8e06d9,64a6938f,3175f281,694d19f8,c8428ae6,16a78a85,57c9ae25,96a56c8a,1bb9f679,33d6e351,4d59fe8f), -S(5c461a52,3bc37bc5,39ae9769,5b59599a,86d3046a,36f4922d,a6f68212,19a89bff,d98b7b7c,5190ddee,481a5c3f,7982b4c5,b483822e,a211ccff,bc44d03e,983295ac), -S(43e3275a,bcf17dfc,7560d135,22f3154b,ccaa6090,245a79e9,373bd867,f48da149,fbb015d6,9f2aa00b,63c81226,b9165afa,1ee6be9c,8e680adc,4d2e5256,6c7723c8), -S(384bc1cb,8221098,4ff0a800,dbc85225,cb4a5f1f,477b4228,5c59c7bc,262c29ad,21061a79,e7dbb527,9ac6fc8f,e2d87642,cfd71eba,12220403,8792cbc7,9d8bce1e), -S(460c55f2,fda793b1,5aff59b4,cc819f12,de803b1d,5c938a2a,d30649d4,a38b58d0,832f6713,e63fe5d3,dde9534b,29d216e7,2434dbe5,6f54c9cc,ea683b17,33075c2b), -S(5e4a763,28fdeb17,b7cd2a8c,47b58307,538c6f17,397fcec,c9e5a377,6a39383d,3b3eb0ee,d7e28701,7bf034d1,dc1f239f,64756481,531d3692,bf639eba,2ad6e02c), -S(5ee48142,c3cb1ee5,45f6579,a36c589a,f886719b,c0b7bef7,c49c7a93,f3b610d9,55192e86,467835c4,b488b869,3f6cb7fc,94e49b03,8272abf6,69cfaffe,234c783e), -S(13b5072a,bb3d2943,c24fc4db,5b5759c2,290d6c92,11bdb80a,3b729478,71f3322f,ae8e7641,39207e9,ca438902,e75cf685,641cf5b9,674ba9a5,e9b26195,30180497), -S(2f2fa1fe,582dd71e,3bfc0e34,f1f5e8ef,12598b52,1ac2847d,90b5dbe9,152ba45e,82967c82,1d7dcf0e,6c624483,863c6c28,76ec8adb,43bb44ff,b211ded5,e7c397aa), -S(1b7be0da,e6633eec,f7895c64,29ea8088,1c2ec66f,2a273819,ec3331ee,830d7c1b,cd884cee,15652542,4bd8b512,8c05a77f,3c292260,c8d30471,8eab87a2,46f75ad0), -S(247531dc,f0bd40ff,7208bf59,2fea5982,440e3f05,8da7ba03,efc7cb94,4b48180,cdbf3227,62033470,e47cef0a,a5c9f2ac,9ca08b01,82140d52,549d24bd,d0f17ccd), -S(274ea538,f2e50569,9f52a7ff,bd058c83,95fd75fe,98fb66f0,ffab658,a1e1556,5aec461e,79c048e7,794586e6,43d10236,37f8c376,7d158968,16ea0ed1,56fab125), -S(82935503,db88453b,8794b70e,9b5a3e37,a804547,48d80c3f,d2e2a85b,844ac085,d507862d,98c035d,c1dd3d1a,3a7679ac,bd80df3a,4e8c4fcb,5b5761f8,c9605d7f), -S(cae0cdae,216c0e62,e8324d9d,95b15285,e43708a0,dbf435fd,d355fcd6,227d2536,f442e7f,d546d149,d0075926,fbd6e15a,805a85b0,a78ee674,c15ba3a9,a6d67b70), -S(a5a0080e,55ccd7c5,d6f708d3,34a78c49,b22442d3,5bce311c,b660af79,39cc70db,c71d761a,98c974bc,570f303e,d64875c0,d9e64f44,63d9db4,fa2d0e8b,80900c12), -S(740c4a8d,2dcc8a6,b11feeec,8f60afb2,e59b02ea,788d5f4b,62da8397,dc88733e,c8f3eb37,de1a1332,c6e010e1,913ea2bb,14b10e1b,d139dfb2,2858e760,eaa16f05), -S(551b7b30,507b2df3,c07955b7,ae91260f,86d899d,ff28e68c,67d8abf,cfc0d936,4c21135,c84fd85a,ff5839f,5192a854,25b18720,4a92582a,1b4308d5,a4c0db9b), -S(e11dd54e,f04d524,7ebbd72b,edffb50e,d0d4ff23,8cdad3fb,f1ea8067,93378b5e,46bb0d5a,be23f71a,3f16f455,c25b19c0,49fb9d25,9db6c94b,9b6b1f17,6edf8fed), -S(570d4783,29cc718,55de654,48255925,a5b094cb,5c55f10c,4793e532,60c9163b,331519d1,e5444f30,a4b1b753,a769eb4,d21d824e,a8151a40,2fab9b47,1c2d5625), -S(20a184e6,df5a35b8,30e97ee7,c3d4390,eede5a69,ce1c36c5,a77948f4,edc4812f,e46f676e,7b524c40,a6135f3c,7474d8f3,c3b0d45a,1a5ed4ec,91308a8b,b89b5a9e), -S(c7daba6a,960243f7,ef0664b8,f66ddb24,8a7686a1,2095370a,36316ce9,a4f5abca,6207f622,619ff1eb,fbe5264c,7f7bfac1,fd0d96e5,fe1a8298,a7ff4d3a,83707327), -S(b9d8e4ba,50549b01,491df2c8,dd596ed2,4ce5ac19,deb88450,a69a8237,d45f6507,5aae938a,46a3b4c7,6dc96894,798d2dc8,443795ad,6a393f31,a042d5c8,83ec7d12), -S(5f9629b7,ecbc8b0c,62374b50,620146fe,980791a,dd24d2c8,b2b3b786,9800a4c0,1ddfd8f1,ef4083dd,c6da5173,d16d68d5,7425fc02,e3943d9,a594e98a,ec06285c), -S(33d159bd,d0610753,10d3c1f9,ce89bfa7,affc80c4,5d193df9,55647519,357095f3,42c8b3e6,9b81c478,57a33b1b,1cda5b68,3662c1ab,f99ef9,5ed1b250,9a5cfb90), -S(8788f2ac,518a4024,3607d127,381f1a1,ea3e581c,89b8d90a,2d2c6e70,f94ddf6e,14112b9a,ef954527,811f9249,5de47e6c,eed1858e,5eba4aba,b1580360,fa05af7b), -S(804b97ae,219b7647,15bd259,255d3275,a5d5cddf,3e750578,13354081,6d9b6f81,abc3a542,1e195c33,88c0c4a3,f8448ebb,ca3ff868,a41c7c0c,2ecfdfa6,409bcc24), -S(195bde17,6cd7ea62,9611d9a6,c55ce4c,e7cdcd37,2d64ae45,f7d449f2,ea32f6d0,6005b5a6,890e472,af884f6f,6d5c8111,1003e809,6e66e22c,1468c962,2724111d), -S(9ab1e545,c9808482,2fbe050d,bab124f2,71b16028,e6e21247,ccd63332,26500c42,cb6bd747,4b6df912,e130b611,c762583,c81f7c5,38dc9766,e27f9194,6d1aa02e), -S(e87cfa04,8fa5bd1,305f73ed,971c6d23,81fa39ad,3d583744,c243bfb9,fcc9023c,7fb05d17,d789734f,7a9c1644,21a28365,3321f261,752025d2,b91cfc70,703e50e9), -S(5195bc3d,5ab8164,4ec40b0c,ff5fb1a6,c749064,9dad884b,ba48e92d,6f35e5fc,2b7ec6fa,97b441d5,ecefb879,35e059db,55d0e3a1,6d693899,d3c0b213,4fb04981), -S(eb2d3530,17df63b4,eb17dd73,ee58d282,78d01137,34a41020,cdf0444,8556792e,58a4f4cf,9247f908,3c28a9e4,da38e8b0,3cbf9e4f,2b92715c,28781d86,771ffee3), -S(8169465c,2da73cfc,daf3f3e8,538a47cd,ce088ccf,475af747,11585bfc,14c39426,1665d78d,e7ffa7e4,810ea80c,f12d3925,239b5c6f,69652fd3,44ba8bf2,e0126db3), -S(96d8634f,aa85174c,69e313c6,430eaaec,bd2ffe3b,55a1a0ae,e78fcb66,af33a3c8,869f9e70,344df870,be6a021,8bcf5e71,afc8a290,51d875d0,5c76f72f,e8fbc0cd), -S(3a071936,1f0234f1,9cc3c7df,40eaf836,4669615c,9520b0e9,c56ab987,dbb36bc7,e43415dd,cc244c05,fff14e0,f21cdc29,dddcb403,5678584b,1a3c5484,e98d9625), -S(cd3f1530,5cc9a03e,d05ab14,a81c58d,2485785,289e2b1,7382d45b,b935ca4e,c451f28a,e7aeea28,ee7ae093,46b352d6,bcbfc3a9,b0bc9d62,9eebba56,877ce9f1), -S(677e2061,8d0b42ae,6c38532,669cbfe2,56ac4b5a,40f1de16,42d97a45,ae34fdb7,ec23dbc2,bf750958,9be01e95,ad253816,7a24b700,1d9a8a20,218f0866,2dc2e378), -S(f816047d,1606074b,c54ef03c,e205dc5c,cc8182f3,739ab8b2,7dd09fa0,50d2912f,de012e8f,89ab0ca4,d8f8e323,6e0c2545,a6105fc3,602e978b,f42a5652,fffe864d), -S(11f9ecb0,4f273b9a,a699a3ff,4588ea19,2504c00f,55145cf4,10cecd40,b5f46f8b,168c4fb6,afedb0d6,b0bed70b,610c5538,e796e0f5,851e6d36,99fc49a9,f62c5b10), -S(efb9a14c,f6a30d5d,f30de8fe,f9ce92eb,6f566f8b,b65152ae,323ae56c,88da79a9,dda5df31,f184601f,a45747b0,3017ad22,e49c3892,fdc28c7d,c0d7e099,7cfad33), -S(e7b66913,dc55fe07,a9941600,17241de0,7867a77,8fe4f998,19efb096,8d426966,adab1d03,c8b96717,db800f98,e09ae855,2c653266,84886f3f,15c08bc2,10bab6e5), -S(6fd3c1e9,6c176c59,f94791d,fb9cff5e,901f676a,fd7e66e5,f69184ab,7b4e31db,ebbac252,36e640f8,df593a37,817911de,b85a5597,bb0d902b,7a97ff4,18689609), -S(2667971,943d720e,7d64d2b6,3d7fb50f,525c9214,fc89c957,7e00c007,4c39a907,9c1fb427,29e57196,33af3187,ee109b46,fe708cd8,5f222b25,bc0c5ae1,300ca331), -S(e34d8507,b11a4ddd,9fdd654a,ea6c4876,5473bb13,c9f18e6f,c8b6e3d1,5eac015f,d34c6080,22a54602,fccbab5a,e1cbd5fe,7ca599ee,75c51117,b9537c7f,44f90268), -S(e8b6557,441ce4af,7ca27f49,75107ff6,3b108058,d42d5e08,86bf3bd3,46e52e24,b15eb15b,b3fcc5f7,e3fcaf48,8f5048dc,a4c587a0,5b982613,c78965ad,b0d2027e), -S(b49f84fc,3ed84f9b,3ced0a5,7f953116,897c892e,d0249365,d8c733aa,b97d4b95,4f0a63e,42aae565,32225dc5,894c6fce,15f2b25b,e762f49f,a1d74d5e,6a23fffa), -S(99b0e1f4,cf7fc243,ea34dd0d,73705809,935b6c03,c0a687ed,7bf8d69e,d79dc2cd,b61a5574,17e236fc,a0615fcb,4d6ba1e2,21fd49a8,4003e8e1,b4e4a648,b6a088ad), -S(1fce8906,c4c420d3,75ee3ed1,2e603855,fda8bcdd,f47cac56,3595d3ee,6b4cbbc9,daf0cedd,acfa2409,e861d1,5cb260b1,eb84e1fb,22f8f483,e4524750,8c3bbc0d), -S(df85a7c0,fc08b916,43ebcc41,6bc86ac,bf4581da,fe0f7418,66704eaf,c24efce6,5d1866a4,3f06fa8e,a36ddf3f,39afbdd4,97372ac5,2d13629a,d546d4aa,ce7af9e2)}, -{S(8a4e9691,3533875d,b8559500,65c90785,a78233ac,ef24113c,f6ed543a,e6a40024,57d9444,8d091df9,602e6c7f,c3f88934,d45a7c76,18da574b,4d4c15a6,6925bcf4), -S(f8922b8f,c310a77c,c3e33a17,d88534ab,ac952dea,355fa763,14e2d886,44b70136,dad313f1,5e0ff701,acc8fdc1,b849a1d4,569de031,6a6cb83c,51629e89,99aeddfd), -S(d9e5586b,cdef070f,978bcaba,36cb7828,8ba43e5c,f0273389,750c95b8,4cf76c,f04abc01,6a060cbc,3a0d1d8c,240995ce,bb6c0d2,d9cdec87,fc8b9f39,dac5b50e), -S(6a206413,757143bb,c552fa3e,180d8e98,cb96a816,136dbc2a,8cd4c7de,6f508a44,55ee4d0f,189bd91,5323aad,b452a7be,298c183,b6843f5,25cf7b4c,ffc7b6c), -S(130bf00d,5caf1767,83d11a2f,acfc3cfa,ed0549c,5ecc381a,d1927051,517e4e88,506fc4f6,8b8be0b4,9537efba,d532f50b,156f5370,725c23b,66b0b758,50a45c71), -S(d85e7a59,54c93649,44d0aca6,8a534e68,42bfaebe,1806bb41,1af01358,d2d4f47a,8a8d3741,21f7390,879a892b,fba08959,23db88ac,867b9ea9,6888c43b,b651642d), -S(88c5e26f,91f4dec6,5d222318,81d7eb57,d3f7e498,fb1866f9,5015e045,d0108eb3,59d66b66,cb05e136,95d5bb41,d25e5b87,6b02af1f,7f29fc10,c67001c4,4bbb7cc9), -S(be062a25,7cb5ede8,e5926608,9a762e30,816d4463,cc5b2338,f4aa6309,f7722aad,16f30af4,c27c3f38,82219d94,a49468c2,3e8cb1da,747ff22f,e23c7dbc,b032d3c1), -S(292e8df5,2c77c161,6277b962,e10c43be,1c820aeb,80f083fe,879dd961,51cb84ef,7c7bafb3,a3bab2bb,2f9dfda2,68904ee7,823e6fc2,2077e41a,af16ed6d,e2ac43ea), -S(b14d3f06,8a0eaf5d,6dfa519a,d0a692e,3020b5e2,8c31b79f,ce6400f0,12e0de71,c383938,630762a6,ca5646f1,f2f02e6f,939575bb,353a9dc9,2a42d50a,857ded94), -S(f41b4e53,7560be3,b604d846,558b6990,639d00da,c6c7e98e,c07d1574,a71aa7f5,c34e8e3e,8102f564,fcc5f376,94d80a65,b616dcb2,d025b701,fa615539,6a105255), -S(5fb4006f,35994912,403a952,a1f53d15,202d8305,389fc093,4e4fa6f1,236892c1,1c5d613,e61f1cb0,e0805743,519fb564,5bf14c51,e61e6cd8,bf08c5b4,9417b96a), -S(e4e428fa,f6ba9c36,1593230d,e73afeee,9b580d5a,ead54f55,2e464031,bc6dfa24,ab8d0919,f7e8a7b4,99719862,6943e144,25d15360,ca0da2f2,637d8542,10158268), -S(53e304ca,eb03205f,f80fea6f,3ea38010,531e1d2b,c6d1fd25,804ad799,e2f05984,434777cc,b848ef4c,f6c205f6,621d5cc5,97c8c2d8,34ed12e2,28e3fc02,4bc4fc6c), -S(664a810a,a0894cbe,2f85817e,93b1d731,5a4047e8,266df3b2,e8ab5aaf,b790e0b7,f5ebf5e8,38f7fbf4,b904e874,48de1d1d,6befad46,ca68db2d,c08f8d43,4b6e57f3), -S(4a697e76,a5db2e31,34b646b7,a59e8ad6,9ca45eb6,b77aee2e,2f82f113,4d698262,8d5d47fb,76769327,7b24d6d4,6221e67f,cc9b937c,31e30fba,9e5ae198,597cedd6), -S(7e227b69,18cf61b2,e33e5996,192a0ff2,89cc6853,9e8a5ce5,65163662,83d8c423,299b7e8d,d2e45efc,166a37f8,d1036a60,40c5b43d,d88cbdc8,729669c1,98d5847f), -S(88afc703,96dc444b,70b8c36a,a30f5a6e,212dfa93,d4eacd3b,11e47e25,9bc7d42d,844425ba,79016a22,cb99d0ee,6ad40ec3,d0cd5639,1717eaca,1425e3e5,98db73ef), -S(75ba04f8,349f8c8e,69aee4fd,662eb9b0,aaba10cc,555caaeb,c12eec36,70179d36,fc0a0931,cc6d5662,ac8bc2cc,c7dbcdf9,db139e47,c5ba80cc,8778d11f,ddb3caee), -S(85c4f2fc,b3f7103b,6970a16f,8ad3d1ef,e1cedc24,3c576235,d9af669d,5f7a5a94,b575c9df,4162c450,4b61412,a3887a44,94bf88db,cf4c6ac,52af5e0e,52382ad7), -S(5a3265da,5b752377,50fafc55,e2affb2a,b2721932,c9021dc8,5bdc79ce,66d0bf0d,8101544d,688db281,c9a7588c,dd72dd63,734561a6,a91bec5f,52641a23,d4e091c7), -S(6177daf6,809f918,f8fca135,f71b89eb,e8700dd9,47243c2,c36fa883,182df3b9,8ffaf7ef,3c8c6422,33d7d43a,c01fd1be,a74c3dd8,3554cb81,7939ef62,cbc8b592), -S(3b8f7e37,b09e7276,36068698,fd87351d,950129ee,eee44a88,9c7a7e39,d49e2c5e,8ce941d,a2ba686a,e3264228,48a6e76e,a0118a7c,55fb37d7,7fd6b9de,15b867cf), -S(47892789,cdde36ea,29dfee45,74173afc,11515dcb,fc53a82b,5c2b29da,9201c8f4,d4717288,94fbd69,44c690b9,97ade5ea,d2c10917,4fe36517,57118d6f,b6264461), -S(f8dff091,8493e499,fc13a155,933384d9,fa83972e,9b099bc7,236bfc07,6e24966b,a06048a0,ca130916,94217147,1d803d56,99cd9c6a,cb98ee56,96637e5f,2a7d923b), -S(dccdbe61,aa1ea411,8443d950,3887f76e,c5e09092,de7c9c7c,642c5755,da678a79,f4cf61f,c7e1630b,2cae9d87,6eb29ceb,dc9b24a9,76c9540,f7845233,c9998493), -S(da4f38f8,13dbfd52,b45af510,59377f94,7f8f0158,38135451,d9713746,80e9c3cc,da4a6ea6,f8526f63,46edb7e0,cbdf3ffa,586f64e3,280b8052,4d2c19b9,f343976), -S(999029c2,9badca65,16360432,56f3bb93,f1b608ac,5084711e,242d9b76,2b1bf371,dbd72bca,1f01a2a3,2a760f89,e45df463,319362d4,61df25ec,1ec9a71c,e85140e7), -S(6c502c,1cf38e63,65275058,dc610392,2bceeed3,ee0a1aac,2838327a,a4543303,f0f4c4d7,b68d69a8,7209c888,7b725b2a,2a8c2c5f,b7c9ecf7,6c1f71fc,e398b92c), -S(9c31fb8b,f57d654b,a0ff1bab,9fa0ee2c,9bc86017,67876b66,83cd8c09,1124f421,b6ebd670,b4e352b6,320134a9,fd765d26,b2e1f109,f5f55958,23d7eebb,d1bfdb31), -S(fbc3232d,c40bf025,1a0551ef,4f3ad4c8,51ab66a1,f2c709e4,70a751b9,9f9cef27,552b310b,6587b1ec,1b84242a,3df96073,e35d0f7d,d47f09ec,b3021773,1fdf308d), -S(90e71b55,cdc8e2d4,f12fce5e,4719b8f7,5da7966c,4480557b,58e567c2,eaf48ddb,ff989ae9,1f195713,886dd3bf,6fcbf0bd,70d62153,9d4b4ee0,b0d2d15e,65340644), -S(829c0322,efef509d,a5284d8,96d3df37,54c21f77,f83a1093,1cf2fd92,a1594905,8b6ae670,d9b03d21,da2ae14a,5e09e0d3,65d31b3f,e1da61ac,7499a908,47715ec4), -S(db748c28,5a6b3d42,9b9086cd,8a50d16e,15788a48,2f06a43a,2b7da677,d41c8f60,f4bf5a7a,bb4492b,4dfec99c,e7c4cc15,2bf32cec,78a3cf7a,4833c10,251f411a), -S(e44f84e3,3d2ec8a9,2d905c8f,1d6d46bb,f8b730f5,a07fc25a,47e3eb50,4adbd5f1,d1fe0cde,a9becec4,260d0700,7ba21d92,cb7e069b,4f81bbae,bab8da7f,9ba68594), -S(3e9c39e6,7d0891e0,9cf7eed5,b0abaf27,b98798dd,c926dd87,12be6af9,6610f6dc,c04e44ad,a09d96ab,5d38ae1,94d65109,ecb95d3b,6b79d019,9641dc8,699789d8), -S(4fed63dc,b7587725,113e087c,fb0b25b2,6056314e,690b6312,1e906e0,5d98c34a,c69bc4b2,ee67000b,b66b6f6e,648cd1ad,ef9ce6a0,4add42ec,38e0156,dd8e8af8), -S(501c9927,f0b4c19b,6b0a9595,2387324,b9f31d90,93303544,ea002f57,4b83c51d,14770577,38a701ed,c15fb98,c6e224be,8464e4e7,1f0e3350,899bffc9,c1ccd33f), -S(98af3ab1,9c4fff23,8d70f1a,efb4a80b,234664da,ec2e44c4,4df93226,e7aaf714,f84cfcf6,9cf1960b,6d13cc27,aa875a5d,3b29907e,455d5925,c0a3096d,44924405), -S(849672bd,d259016b,8e07d627,e57813a0,e355bae7,ed64ccd4,251a36e4,48d0821c,8d0366fd,764169a8,779d21ca,f53ab78e,caa8a627,32b74612,5e831d17,9147d2c), -S(34f142d5,744dda88,aadad850,e7f469d7,140dd5ee,fd3dba28,86f3503d,16fe60e,3c3d20fd,c13b78fa,d0b7fe35,3bec2bea,b1509a12,a03b1e79,c5ad2294,41292728), -S(ffe5fd9,b78378bf,4738931,e03752bb,75855c54,f4e3dc8c,c369c070,450e24f8,dc57ffd6,b87dd1e1,dc466dc,6423e1e8,4174a5a6,c014e069,ae812d80,3c6abdd6), -S(b43a85b,808e6d6d,32d56edb,5d64af6d,cbfef633,2cf662fc,cd137d2a,8b505c0d,1e61d507,8ee9ec4c,c6be2a87,657cd3a5,f30d508e,c35e459e,e2d0032a,702bf4e5), -S(42be63ce,a0b6e88a,5d98661e,c99d493d,dbb78f09,ccc8fd30,eee4e148,ffb0cfdd,38d7e392,19f5a87d,e36b4937,8f1ed166,23e93619,165e2968,84294946,adb1e9d1), -S(9996eb8f,f8c8bfa,d4a4c502,2d8ccf86,f59dc8af,750734e7,e054f783,2b6c0f05,f1c9387d,9720275b,171a93dd,4bdb8ef0,7b73763f,5323d5df,df515ead,2bc40aa2), -S(66f17b8c,fb9b6003,b6160370,8f86f93b,3555c338,d3a346f1,fd9db3a7,37c197d3,4d0233a2,eb52e023,33c7d4dd,53703ac5,c566ccd5,b1e76b2,423e891f,60a8dff9), -S(ffd5e8b1,b2587ba9,79e90dcf,c6acdb82,86328779,224a4edd,dae1bbdf,6db06568,d75d57a,4d17dab6,43fa10bb,35857dfd,f2f7afce,f6c5bebe,7e13645c,f6f8e3a1), -S(ae1f1297,8a7a37ad,87a8aa8e,1e89f0d6,15040c25,d6d47193,e33f12b8,e28baf60,e38669e5,18c7cfef,4ee61807,b51fe9fa,403f1528,ebf2b27b,af0a15b4,fd39f5bf), -S(d330d887,3bf11a6c,f9b0c1ef,46ea64d9,973f14a5,a93cdb8f,7d84f515,33a34b90,b56e5c4c,8f236f34,78ab2620,ace7ded2,1395174a,76c5c62,2ac50b78,da16ae14), -S(1d2ff433,4e908a9a,fa5572d7,8dca2a81,8f8a651f,4bda506c,ec0aeec0,91a4391d,292d6a4e,5811de83,e318a6e5,861581c2,192b1f59,30f42d1,40893a20,efefe2fb), -S(8dc6cfa6,cab6f691,bf468059,7400efbf,8dfa76c1,8edfb8f7,ea78c24f,3bce2bf7,78874b78,47543ed8,2f983f80,c1e83ee4,b0dabf2d,3fb7d695,ab1860a7,967ffb10), -S(5ef0e616,b545e053,21bca097,ef424f4a,ed40b6f9,93a550e5,e11bd637,59266713,c739cd37,7700a1b2,6dcef2fa,c219d05f,646d86a5,850505d4,21ba8b38,54d0708b), -S(60b3faed,cd527d8b,6f806cb0,f234a3ff,df62a755,87d3f543,efab95ef,e6ab104f,e1e0cf1,e737f246,c1c3bf6f,92140a3a,34c98d53,32ed25a2,d7a48247,98d5ccc8), -S(d160c9c0,133d78bc,62a2e946,49cba513,783682d0,dad71915,ce208a9b,446a303a,bf466216,73b02b7,a782178b,f7113433,73cb299f,233b11ca,4d4014f0,2fbdafad), -S(201b7a0d,5f431299,34172b40,1744d18f,477d0724,6ad2016d,c8ac7d3d,32ce0e93,1fb192ee,55ebdb37,52b6ac29,c7485a7e,f8b8a0a0,a480def8,fa07ed29,d3afdb4d), -S(7d104d3c,62abee57,1f2d2243,c95bdca5,dc702807,fb060577,bcd1e50e,697c929,a680c234,1c12a157,f604ac5a,b74ae532,5fc59b5c,d8ad784a,5d66fd27,ed3958bf), -S(8e279e59,c87df705,b764c456,563703bb,1836aea8,93dbe8d4,b0249223,13e3801a,aebc7cbf,ea3fb75a,6f059f9a,57bf8ea2,d0758d51,c0d57696,f5eb4d38,6d1d61ca), -S(b206020b,a960cc8e,ba4d0263,bb0f2241,a91341ce,f0102509,7cf7ef52,97f96935,a249971e,6bcfd543,c4b603a2,70ea667b,8524c136,c15913fe,91bb009b,796da003), -S(1e6cb8e0,4b998c17,b0887731,24ad3f44,ae7a89e9,b33ca730,62233a4a,a6b8bac,a50a3841,9da361b1,f89a8fc8,f29a3fc9,a6f8aa5c,36516ea7,2ca4cc15,96330dc0), -S(449005b9,3279d7d2,9965e131,50fb7cdc,18619541,759706ac,6908ff71,ce5c2cd7,62f1e74d,1f31de28,221d0dec,3d063f76,ba5e742a,52d0b48f,22d01ad,58791862), -S(4030002f,2374d275,3e9176d4,3bb4c2a1,c7a4821c,f6b7119e,bba2d4b1,2e4b5bfc,a80b25cb,a4a75603,af82a624,b493ba8f,c46ab68a,968bff49,a0e1cf8d,9b7a4d93), -S(c75f32b4,8122b7dd,bbfb4879,30fe0ba1,99072105,6891b932,e2c7ea3c,eaf270b,309afd60,f5a0f780,5675646b,37029da9,601468d8,71ee3685,cf6a3ad,104f5017), -S(77a73c5f,1548cf98,9c284c5e,9f1ecb9d,ab55d2b3,982750bf,65eb7097,ed159e1d,112d6329,29e9aa4a,83c2fe95,531c0717,d84c9ddb,87ceb9b0,65e9328f,83c3699a), -S(f6a55eb6,d05a9183,d3908776,40a5bd0e,2a6b83d2,40cd5840,e25a8bfa,d2116328,ad0834ef,8672b707,dc99c4e7,1c9fc935,725ebc8a,df45cf00,99cac306,4a56796), -S(cbe913f4,48359096,dfb1b168,fb42d92b,d873b82a,956ad9c6,5e64a2b6,d826614b,893edb65,d2262b17,f5e466f3,88592e96,ddd70b65,65606ac8,289cf396,991a25aa), -S(f29ae654,8a6aeb10,849191e5,e87e2c0f,d8e70af,a15b8ec4,848407bd,36389d06,1dd72984,6e220fd8,90a1370,38c98e04,b096de6d,a7ce7339,ae697daf,db11905e), -S(32307117,b8d2902e,e325090f,97b518a8,beb9e27a,d3cb4d69,fc0b54ba,ecb14316,7970c3f5,13f69df0,400c725b,e84b1267,fe7f205,7a70c5ab,56ab0ef5,679ebfb6), -S(426e118d,b8ff1f7c,18ae29a1,b88e0f2c,2c286658,6c1c2179,edbd719b,31399dfc,7889d383,427740b1,4c37ae36,e51710f2,f5a8decf,a456d0c,a83ac66d,230828e4), -S(229c2322,7c4956af,938ac061,9640e04d,2c647692,e0e985ee,28cdc767,96f260a6,a056790,cbf36663,b09cf7e5,4b622f74,b185454a,6682d9b1,6cb2af2f,3ca8a7ed), -S(bb7cb68,23726026,12072e34,8cd4504d,50a3d286,669cb748,e69cd0ab,dcc93e8a,9d537ff4,532cd020,17756733,72ae3cbb,7aaac7eb,901c1e69,5fd57f02,9c336e5c), -S(d3460edf,f1405cb2,ef9c9fab,eeb71796,c9d48f66,96f8fd20,56a99863,2d278e8c,d9cc7b14,cd657e73,e5fb7207,9d421490,46266a34,7610b3ef,b631c78e,ed02419a), -S(d12b97a5,d5b7d74c,c8dd8f7d,45fabf75,105ebd5d,9990d99b,7d0738f3,49db1180,51dd8885,e6131a1f,320e1516,3d6e35dc,4978fb96,b531aba6,67231968,a2f0fca7), -S(f75899e4,e383c412,f6f9c764,38d38cc0,d0550d28,a150292e,45a2aaf3,c7025ff2,7ba7f1fd,d978939a,79b482eb,24776178,ebee022b,48f66c33,e7a8de58,7fc3870c), -S(9d3aca30,fadb9f90,778aab4c,b7b88706,cfced983,ca62ecdd,4724d58e,6575a754,f0f41826,c426e8c9,a832a211,c1835693,9a1c7c63,3de95bd3,7e6d9b6e,db41d16c), -S(63454665,5133d840,de3af8af,def0395,cce4e97d,8e0030c,94f8cdba,cd72c3b5,19994348,daf379d,5c626f75,12109e43,bda0e527,137d425,9d9ebe32,2fb9aca9), -S(4ec235fa,47217cc7,9e2cc90,216626f4,2861f8d3,e61665f4,37c83ef1,acfdb8c0,d0b35b1e,ac498e36,38fa5da8,310a8f64,62cbd671,9d4b9c2e,c3be9835,cdda0a8e), -S(27dc4da8,e16e0d62,4a0204e2,3a8c11dd,4ebc5504,3cfe98a4,7d91ab19,92bfdfa7,6ad18e5,fc0e8d1a,421f6cea,8276b506,96e0308d,3983823c,de917e88,195ae3a5), -S(7479c3f3,6a4b4d1e,fea25a45,a3c4b79e,919707ef,ef92c830,6d693c00,e9ff2096,5faaec2b,a9343e26,cd32a68d,7f441d7f,3ea614c5,3703ec81,c43962f6,9934b3ee), -S(3420c98d,a020a034,e094ced,fb80c251,6c84a959,f9ddaf7e,ed889927,9d98cd03,b6af487a,c26a55a7,30552322,b73b05d4,a7e819d,7fd84873,4345870f,6ce5b8ac), -S(4afb97a5,68556ba9,350dde2d,85709057,ac4f34f0,e9700939,57bc90c5,540c61d3,1a129c50,23c3e419,fa0d5bb1,74acacc8,9aaa1114,ee38b937,406b5da6,b99fd29d), -S(e431caf2,6d33fbc7,28a789fc,ce00f3a6,c4629958,6a03ccee,e84a385e,cbae856a,9d11cc02,df57742e,d01e9169,7e5bb434,5829d076,747b065a,782c8619,da4369c7), -S(94a651f4,4b112523,3fd880a8,99191f1d,9cd5064c,227c2fc4,de1eaaec,9439ebf9,85eca2e4,717816e1,6c28a5f2,c90fa6a7,fe4222ae,f811ae1e,acbcabb7,6271ed7a), -S(96ea121b,60d051fe,d5381fc8,38b70e86,257626b5,91184577,337fc62c,529355f0,b3a56efa,b898b7b6,b2d90341,cc91faa2,24e410ef,fdd9d7a3,6770765b,c412dd82), -S(4b7e0cfa,250661d8,fc2e52d1,4a2969d3,b301de21,cc7eff3f,d7d7d7da,e2404d9f,d5d48777,c77930ba,96d179c5,10734cc5,21ca4ab7,a8d7cdc2,2960ddca,c03ecfdd), -S(7ee44334,6c87bae0,c3bee1a,273f09d2,d687fbad,fe060ce6,ff376c10,1ef266,ca4d7e06,2a28edf4,3419d107,41ab1017,da1bbb4,2e26a282,5d8d5a07,6e377b5c), -S(e31aa2dd,5bb618c4,63da1ee6,ae50ab1e,ad967b48,ff8df86c,f0c9ad2f,9e530ab4,3b3f92b7,7845a7d1,6a5b02f9,13354e6b,5388583e,546bdf9c,34cedd17,a9d4e11c), -S(15755ea9,907f998b,f75d38af,d4716cb6,4ab3fd19,2a3b62f2,f597708b,33697405,3ae19c16,8fec504d,8cf4320,c08c2dd7,605e2fef,1d8ebc74,1330e78e,9803504d), -S(2d2da66,d08289e9,f1674782,1214edfe,9de40a91,f1a378bd,e5802bc7,95023cb9,2e48b7f7,6dd20f2c,df2b0c18,1d5c691b,7836c6e9,8755aa05,62277426,53df2a99), -S(1b4bdf1d,d34b1b24,384d28d0,27c404b4,2691ec78,3949b8a0,65615a35,ce5c6c18,33590a6c,679a3058,5fd82459,f609559a,edf525e5,7eea0870,22d60d8a,dc57af5e), -S(3de0d336,b7bfa62e,5bfd8265,4a149e0,fb9a9add,6ef9679f,1e96b911,2f4bff69,ea44028d,b24468f3,bec7b60c,22c72efb,ae8f86e,90c3e2c2,b885b228,f7a1e123), -S(55d6d2b2,9314bad1,ae87da3e,e30f01d8,8844d27f,6e85a071,539824fa,dbc064c5,ae68132d,6f412ca0,3d70b23a,cf88d7e1,2443da6,cd5c2914,1e44199a,685cd459), -S(7ff2bf7,4696ee5c,fd709fa5,5d6bd376,b67fec2f,1c8b8982,64628e7,445cdc13,aa0f1082,f90052a5,c7a92350,cb3e27ed,9ad895a7,a73d4929,3864223a,b2640cea), -S(6fd69f09,3f4cf5d0,26703a,a0836ff0,2dc344c7,ba36bfdf,c98fe932,c70ce775,a2a95599,4651742,728572e1,5a9854a2,3cead0ee,c7edf4a8,f79ec569,36cf300d), -S(c644d73f,c2170115,78c4572e,9b8ed701,c36dafd8,e1602efb,8788c0df,a0b6ad48,38fa94e8,46ac717d,88862e2c,94e90e15,97a9144e,2e1900bf,1cb40218,e22cc2aa), -S(864820fa,f8975085,f69432ff,2f638054,8b972f33,7b74386f,d113300b,d672cd3c,b08492ff,37610ff2,fe86d3aa,a3c62747,3be55698,f183bf58,f67872f8,cfc9cbe4), -S(cc3f0782,8c7e73f9,a3cab59,be37008d,6574acb2,f7c4f0bd,4cefd6cf,b10c25e1,41751bc0,b9b0ada8,9d7e430b,600b00f2,987c0639,bd910c32,d1e8ede1,b183780b), -S(a7c1d70b,73e901b0,b892059f,4968d287,7026847e,187766f4,7b82ad0b,e874fe5f,87a6357e,83bc6dce,d3a3700a,1536920b,b0dabf6b,2ea70f7d,1a88917f,ec51890a), -S(f10a662,f02cab01,f47c6415,70e9a020,2584f160,8a69c02b,cc5509f,e54a7391,70422b17,3c20d128,30da1a71,57935a87,7d6db2d7,b7ee5272,5b756a5f,a0ca8891), -S(36ae45a6,efd7f4ef,7f66a206,82d027f,25b8cdca,410901da,1152b2bf,2df0f14a,ebd682f,c4cf31dd,c39b23bc,de979cbc,7000724,8d4c75c1,dea2c62f,37823e63), -S(ae3d1eaa,e04070e1,610c70e,190f599d,b2ed8dbb,5aa4be6,1af5c82a,83757f9e,6045833e,b1521caf,3303bea,eecff1e,a98477fd,ca29999e,4ff55264,24e87117), -S(8b961a4b,917a59d2,4ad0f94d,fe7840e8,f7f6573c,61de7f50,b3814920,754e5891,3a198cd9,e2d40f2e,7d5796aa,fef0b84,91dde435,1aa57366,65263ed4,5f136fee), -S(86d77e77,f7c5e4cc,dd2ff3a0,1589e422,8aa30d9c,162370e4,1ca47040,89b4e0ab,c0cf8d72,aa3b90a9,56bc8827,d3b33c1c,70707114,e3dab774,68894c31,3ecf21d9), -S(ea77fb69,a07e27ff,a2bc1815,27a7219e,2433a38f,98a05f18,9faba452,82722666,38f055e7,cab474a0,79bd635f,135d608c,c0b8b2aa,b48de933,c2e48386,74e943ec), -S(d5612e3f,304cf63e,23c280a7,872679bf,9861ae4c,965b79aa,db2e1ba4,cdecfd94,29e27659,26aca4a0,da8f3a61,dab6ee38,23e47fb1,36dcf792,181c958a,3ac24a78), -S(ce8968de,589a9b5f,49ddb8af,eb06ac29,ea053b5a,ab3c6dcc,69dd132e,5f2d115d,26f18c48,8de54fba,bd476b9e,8a6d049e,25d3d750,b8fe9595,a9eed52d,1865b98d), -S(728ccebd,7f098fd9,96bc257e,919961c5,4260365b,50f31d56,bb749b7f,6250b577,298522b3,d6e77839,97fc8fc4,5d4e853c,e530e768,6363b86e,8a68a717,fc5e4742), -S(ac7e69d1,d7d529a5,42fdc047,f9094729,45fd8af1,4ae3d71c,246a7c80,3cc7b1bc,af4c4fc2,9680bda0,bd2506d,7f64f4f5,f7b891e0,c50fe059,3246f97b,ebe10d1), -S(633605d1,9d61b598,da661292,2b6e5763,c765960f,c044c5e3,a4405449,cbd0fae4,fcce18e7,3c419aa7,85a55b57,41902cf6,855d2775,e8be678c,18388a0d,cd2b5de), -S(ea93cce3,888035ac,5a187cc9,70e6232c,37e2d0cb,31d9b5ca,33e567ee,62948add,d842a18,e2153217,98a620fb,c6e40ec8,66c9c6e,aabeaa31,7d6a01e5,294a8b0b), -S(75d25df7,63b00703,5e21753d,7e4cdde9,3001a820,6dd834a8,6e4e41ad,38e9cfd4,ddd41a0b,4528af7e,df820374,68eeba16,e2fecdd7,1378dea1,f6d0f734,8593233d), -S(b28186a4,b7bb240a,8987119a,7114faba,d163c3b2,66349ce6,328ec7c1,62ab3fee,4aa77c0f,8db9be55,58488234,61d6206b,80ca3788,f195a47c,ccfb7688,18bfb34e), -S(43638d8e,3331ad3b,9e4cda5a,fcfe5c76,b1a61811,1f08ee42,1c008d4d,187300ef,fa90b3a1,44d0f073,64734dd8,698beec8,8b916fa9,a7aa7d9e,d019d69e,5bad5af7), -S(19eda20a,1ca63328,29a7404f,51c7fc4d,93d0ee1b,76461ee6,42a07c07,3d73a1ea,a6c5aaf8,6a9546ca,81689f75,68709261,642a2d37,d104b7b7,98a4ebce,f42c5506), -S(f6a557e2,68fb6b99,5e2a9342,d5e4ab19,b95bf279,17285ece,11268477,427d092b,b10451be,cc64fc69,7801012d,7d58e4c0,17365faa,6a9db69e,fc7ae505,638e4204), -S(bed211ac,c6fff91,f1baf145,27c8d007,1b19022f,13e54f41,3fc83b7d,1c9aef54,b97ef30e,a42822fb,fde43ffd,28184f8,fd58e314,ef69bd1f,b1961314,fe4bd3ca), -S(593c25d2,f6059501,347cd47a,9658b04b,9fd81c8b,5754dd32,35ef3d51,c7ce052e,1e3f108a,c81dfbdb,eb544d31,d7892d4d,27d4e146,779135d6,eb2d81c0,c3ebe674), -S(207d923a,211e86c7,7d8357cd,19b95bd,ba4aa7ee,61d147a3,a4149942,2a23ab47,92fae109,11615ee0,9a3932c3,7945aabc,6b14e5e,a5934a92,b6dfb9d7,a68ba39e), -S(2c2029cd,d7aa039a,1b43c84c,5f0db4b8,8093192d,584818f1,f938eb4a,5c5accd8,35a55e55,41a70031,c5ac72a1,2a94d94e,1f467015,8ebfe17,70d2aeb4,76478cd4), -S(4f8e148c,6fdf65c7,4152d84c,5462eb59,e6bedfc4,3ce6382d,db24d20d,43e0927f,12fd3323,143df955,9f3ce8ef,30203320,893fe063,b17a9f58,5594062d,4478beac), -S(954cad68,1049614b,9bb5995a,f69868e9,44efaf89,5ef61aef,7d09e74,24151879,56c8e285,5df18b97,4147fffa,a561d425,c1d0b1ea,8cfae8d,4dbd3462,7bc57614), -S(d2b06281,2acb2483,bf26dfbe,5a61fa2a,2dc995dc,835a5ca2,86fd2d33,b273a129,debd115a,2a711cc2,16ded426,d442b504,475a5f2c,d7e651c2,13b79f99,74ab9997), -S(1682ab4d,ae292e8f,26520ab1,b8f8aca6,33cdd6a8,a0d585f3,5048551d,f4b6d354,80c160a0,9300aab0,f30df084,fa0bd259,fce78972,7f0a78b6,96562edf,d820667a), -S(b9252ea7,f64ee2e3,4cf31c3b,d9e065ff,1e0349b6,3f6669aa,19e42a71,72312586,4e48711b,3f0fe7a,89fee250,b116862a,e00da579,d7e29427,fe2ad3c5,e0ddccb9), -S(a1123f7a,81cc5e43,2a54785d,f1cc614b,7ebe0dd8,b6362e1f,cf41bd65,c3c4faaa,a0d31492,82dcf09b,2814c88d,d5aeb9af,2c16ff1d,3e1e05c2,68c8aa5a,8f5716c4), -S(f47f6d8c,a7950f23,a4a08d07,f5b8889b,c30e8ad2,8510d198,3dfed29e,e47af463,6873567a,2820f91c,506878c1,69e98a70,f3d6696c,455f1752,21a4e1c2,44dc62b2), -S(8efbf718,f124b5f6,807d3493,fb3dfbc6,f1c4f0a6,9ce81d20,3b13f422,b6ac1c88,6e05c0fb,77d12e84,64fe1b30,8207ceb9,a297334c,e937eee7,a9a45ea0,bfffb734), -S(56a8aa37,ece2a01,5f0efa3c,41f541a1,a9078c03,39b6af5d,9c9486c6,93bbf553,fa191d76,62b7189f,9ad68823,8655343d,71e7527f,2e72d3d3,1d25a4ce,719c7146), -S(cc2d4945,5659cd0d,19924df6,6be02e32,16e93423,9ab657ca,9003431c,cfe8e450,94a34e9a,a0814633,33b53121,3c375d6a,dd554ef8,cacee52a,a177ff9d,42cf39f0), -S(ea38154d,ee6d08cf,50c3497e,6e15a1b2,d265fbe2,cb945a09,a34aec36,35f18583,d1e16b50,cc5a8d51,f043ec05,1992ec53,d7020cb5,5d05519a,25d364f7,e498b28b), -S(82cbb42b,854e7f28,a2a786bf,6cfb4642,3fef958a,dc2fae99,5590d311,82d46c2b,96310134,eeaeb35f,5e2ae9e9,2c26e731,e0e65da6,b37124ef,c6c89e58,b7434314), -S(5f23519,92aa09d6,1ad78103,df0a060c,e939782d,774ec196,c261d6b4,5e42ff01,7e02b11b,5efb1a31,43fbb204,d63a7c5b,8a04a66c,1f5ec292,277ed353,adb8f95b), -S(d182f035,18ea0c6,a16056ae,a071a1b0,920d7a9f,37137429,5fa89f4b,1b4b229,268c5c3,f0d47748,effe1eb1,3b1b5340,4f61da2,6e56db7c,f2e35d89,a6bdde8c), -S(51e72ca2,3f22bfd0,f6405e3,57ba5221,310fa8f1,fc054e30,a34a0271,3051e9a0,307f4e74,b97c917a,281acb4,25d1df8d,ffd5e578,9b1d80f8,160c1ab1,ed79322a), -S(bb193d73,f08c5946,faec6f10,aa13f855,aee34bc0,c4b60c3d,2ae0c37,359f7b83,87cd0d87,d9d83fb7,3b382cc6,35d6dd63,29116267,5f1e3647,ca62a68,fedf7143), -S(9aa07141,e67fa1ff,cc307760,5b73625e,f804246b,a4e8e568,f0a7c111,76c61de0,b58aea99,47244021,1020a64,584172c,21c6f641,a14c43cf,377c1f68,b8ced736), -S(aba5e67d,8aa2366d,e77c9d58,1e221fa1,b0f0db3f,2d3679ab,dfffc4ea,45ad84d3,4fbdee40,48ffd408,712e17b9,2b9fbb67,ec7c9ed7,e6ef052a,b8dd0ecc,62fa91f), -S(bb9a0c87,e1fd476f,e8cac1fa,7f6cad71,78297b32,9fce8d9d,332758c1,1a8ef09c,a9c38e66,add0e7ab,538c62e,fd7c2eaf,3ee221e3,cdf581ff,3fcc1bb8,bf638332), -S(b531f3ba,bb94cf91,b492d253,a36de81c,476360b1,91ded661,7eecff08,403eefec,3f653457,6dadc53f,f2a268a0,b8389ad6,a21653aa,c4b65b72,758fd6ca,27f3b570), -S(f7e9407,d1f8f9de,182e273f,98984d57,de4f7c61,227c98ad,36589c2d,64728812,f3f15a91,8d2a5c47,d7fabf29,dd2a2380,73ef645f,924d04ee,31dea489,f6882844), -S(3aacd2b8,2013ac34,75a7cb05,e52c1853,c10f7b66,68e5f8fb,eaaedf64,342e2b82,2d33a32d,7f745929,3915760a,4fb04c30,f649541,a246396d,8cfefbe4,26f6573e), -S(f11a09a7,edc46b58,313c31ea,93364d17,4940c58f,8a8fcc4f,2bb132d6,bae01730,7a42dec,b0eb3b71,a400cc5c,4ac848aa,1e3cebcd,c38a1407,3eb6f568,6dc68d5a), -S(642ede12,2ed16043,ca028a10,e014fcea,52d6a3a2,9399cec0,afff3009,598e967d,7f86f11e,f79a0e2b,66ccc91a,3164617f,f08c85db,c4f1e4f2,a0972c43,8e15b6de), -S(a04415aa,28f065b4,5b60f57,2f665229,dbfaaafa,e8c0561e,9e37e1a0,79231a49,a32b2e0a,4e9a23af,58b398a6,56aeb0ae,6a98ba4b,abd1db60,8959da55,14710f08), -S(b0904d2f,333c0cad,9eb4f5b3,ebd1c176,3488ed9b,25f640a2,e9379df8,b4d170a1,ed8bd456,999ae102,edb20bf8,3f903319,97233e29,35e1c52d,13a52cce,32a5e958), -S(e50f98e1,162614c1,6f2effc7,4853d7b7,2fa13e2f,2fc0b864,dfa1656b,2e1a0a40,5e7ad119,80f9533a,bd541065,c1309f90,1eb49aa2,34386f14,88ddc3f9,3406e986), -S(5d6772d0,2007fbef,4d385766,ab4b4fbf,1b3fc017,6f883d5b,395e5a35,763c9e12,f4dbe650,89e165c0,1fcd49e5,5991db5d,3cfff2fe,1730862c,3f3105d5,a9433e6a), -S(c971d45e,c78b70fb,70d2e4b4,b427b82c,4c569d0f,1d9e85fb,e4703d27,58fa97f,9c148ffd,295bb61a,d3a34548,625a447,65a7599d,5d0da8be,c30dad98,c735440b), -S(f118ec13,304f8826,bb744d7c,eb87181b,fe25c3a5,ed8df1a0,eb05bb65,860b738b,292a85ae,eaa3cc59,3dd8adc,64fa9e71,2824227a,2139d7b8,5720b289,f1ea54fe), -S(6b38d88d,e7629ab7,82d2af4c,93a62371,bfaff595,d422b5cf,b12e0fd,1155f5ba,b1a49c69,5439c867,5f491cbc,e3c5971d,87ae5a60,faf13c1f,7cb9536b,37f780b4), -S(95c357d6,24a2f744,d8989a28,8bdb7c0b,241413e6,5a26c877,8382270f,c291af61,142845eb,991aaaba,3e755ed4,3ff0afed,34643413,5bb13034,43b21a83,4f3c0e31), -S(feb4122c,23e68298,f4601b3,edb1de03,b7137341,6527e483,f16a14b6,660425f7,2b7f5ab8,1a2fd416,24d3fd71,781be6a5,1e8cb43c,7ea8265e,e5d92978,30388bb1), -S(bc0eae5c,fec4873d,5d34f0a0,86a96ce2,51369a01,ad2d5137,746bafde,a574d9a1,1fe1f281,999033a4,39f4c0da,5c1cf6e2,365b139a,29f82785,caadebef,ba5de3a6), -S(93f71e0d,d7ee6b9c,a017de05,db2a52e2,d2175cf0,2c1aa194,1c6256d,74907872,1bd2c197,6108b712,27e0bd78,b0a2a036,6564c979,5d1ab6de,7a12a0bc,3913c8cf), -S(f8388a97,45191a86,efda904c,8bc06801,faa3bc37,8a2425dd,2dff9a4a,4ee5d7bd,af2b9260,c452261d,584144b2,91b5388,3eeb5014,c0fb0a89,e8b78f0,9525b5a4), -S(c7e727a4,a0fc2d3c,4a5cdea6,c93049a4,52d3646f,35951918,eb379c56,50c544ad,37f5bade,6d3d9076,45a4154d,7d30ce2e,cb77a3b5,695080ad,bbdb8a33,4c7f7514), -S(328eb6a4,7cb82340,768d099,45902d56,3707c86b,261b9ce3,aeac6734,e76c4d48,ff1a5828,4f402090,c32f7b07,7e8c3098,7c3af703,604c22ca,aeb4acba,e7f52c97), -S(beb0522a,acc84b29,e0ab8233,6ca02733,9b4df195,bfb01a18,b38dcb3b,7c8a1e21,82d7508e,9491e2d3,d74a4229,df4d6020,1c6a86b8,a3a448c4,35dd20b2,f993e6b), -S(d3dada60,563278d9,38e48e79,f2e6bf8d,5caf0f90,affbdffa,c30d6e06,3f69cee8,8dc2beaf,34b916d2,b542121d,8e181735,1c55a766,ee46f2c8,bfb8b7e3,d5ff6826), -S(42111151,45ecbd47,1c8a812a,192b3a7a,ab43cbf,ddc49dcc,5a92f350,86069c33,f9428e07,f33cbf7c,7afd7cd2,f6afefc7,b0fa30c1,ecebcf92,30e20c17,7d94aeb4), -S(bc2034dc,72217bef,895c8d3e,5a5414eb,882e8efe,3dc8cb0b,cbab0edd,1bbca0a,141caac9,de3a48ed,ac6eb47a,fb195238,f3784171,4d7f3807,8d492a9e,a70d386f), -S(b8035a3e,9bdac3c2,58da038,5de2ee25,98ca621,d90db03,4057b674,21e2bd1d,f7af5751,a8e51665,4cad2e0c,61a94970,6b5151ec,1eb07cd8,1713c716,7a44f357), -S(740fa667,cc333c48,4880eeac,ebbf5fc9,34d3ac55,ea04d8c,9365e5ad,c3a404b7,33893248,b4e2e874,8694ac43,d5e6aba1,3afe26ae,3a51a613,d7e0541c,d9ba91f4), -S(673c1c4b,16c6a75c,28725630,340aab0c,8a7b8648,4b17714b,c955f160,e3ee09a2,c3f99423,2521122,d0dd518c,d9fc94cc,5b4c836d,9665cec1,1a024995,342f31ea), -S(a74784c,dd6cfd32,972124a5,dbc0233b,f0222de1,9f90ac0,87e95ab6,f40c62bf,ef2a3085,9a86e0fe,f96b2e5e,b7a63820,122e2dcc,a4f2102a,b501f2d8,1a88378d), -S(db1d8dd4,bbffccab,bf1b90c1,9b92535f,4ada68c,9d3cbf86,c0d700fd,61d4beb7,ddaaf64a,54972f9c,ea2c2fd1,27e17223,1dc38360,6e0589dd,a3f8d62d,80c0a5be), -S(ffb9ae70,2307914e,a9e4160a,1cb68f84,3fd03778,8a013f2b,f9e1d725,b09d8b40,352b1e7e,69e5afc2,6eae5b56,b2b7ba9d,ab174019,a03df463,ba510aab,c4c9e859), -S(ed27b183,29dd25c3,4a760942,b1aad66d,a1439b86,250db95d,98799c63,a9bf2fa8,8460eaf1,554c31f8,5c6baf21,126163e2,cfa9d290,17bfff10,9d295c8c,ddf391e9), -S(70a453f0,52682a36,1dd33a79,a65e4080,7bb95541,5d0b0c72,ca3d2b15,7e57bce3,2e40f3c,25554c85,cafe5e78,9aee14a5,131ba6dd,b9edfbae,338e8db4,653e908f), -S(377a14ea,78d4f864,5262ebc0,5f55a310,6a329376,be0d567d,a327988e,4e1560ac,ef069fd6,264ab8c6,b290c4be,6558cd27,2745d9d2,7ea22521,b79524e6,230a7c47), -S(39fb1a0a,924546aa,ee6b8f4c,65218a6e,56ee0e2c,3833a784,3858eaa2,f57f3399,e4bd9a53,8419ea44,30b041b9,e93186ee,d9ba4846,b6125f1e,c549f34d,ea5c2f87), -S(d255491b,62a9ffd3,5512555b,4c413eb3,b412ed6c,9b585baa,875c5643,70d9aa00,da4094ca,fff6616b,51ed389e,a5b9b3af,641f872a,7166427d,d24c5973,be24d067), -S(342d8017,5754c01f,504e6c0c,c4c6c8b4,a1079dcd,89de2927,a3227a1c,756de1f4,de8160ca,ad4a4f31,791fdbdd,4b9ab3c9,db9098f1,2db64ad9,d6f90ba4,a9b13a6c), -S(92e8a7d3,d4e8bbc8,4427ab1,a35e5a0e,c2d81c04,c98ff34a,325b4abc,2863fef8,e8bddcfe,876f7c55,86470c56,bcca444f,fee67417,8a592e0b,b9f5b1c3,b2a7e9f7), -S(eef2dd87,66dd8259,fd821f30,3771574d,4477283a,614e463,d81238b5,b08141eb,39a91138,ac12e0eb,da43724d,686d9207,1db46682,746d532d,55426a53,87b98023), -S(2efc16ec,974042f8,b1a91132,2ea4f521,71f76da0,196cba89,12faf48a,cbab65ce,97c0079a,3151c8a4,7dacf1ee,25bf3157,48a83cfa,1f3be2ce,1954731d,a2cd56ac), -S(3d2def4f,dcacdfb0,8dbb75e3,1627baf4,6deec0c3,6c4bb3cf,f96f13a1,2066ae14,41ab6cbe,eeae8634,2f95027f,e472834c,e626206b,3e1ce1a7,71b717a3,39e5827c), -S(ea23f622,95a65d24,162d88b7,6a577b64,1abca822,1c29d23f,56e4f929,a19dbe10,aaac26f5,c8b5bf21,38a9dd73,8ce69b01,6c6b4f82,4685fa39,c2de56ca,3c58b664), -S(f01557e5,ea723ed8,2d5e4e02,f4358ef5,5b0234b8,182bd4c6,e6310103,768eac09,8bd31626,7fb3e7e6,ae828401,fd00712c,9f4f4c7a,cee8f708,4eae9da3,38e12378), -S(1f645466,d562b0c,4618217c,4cef306d,7156a5e7,45327a55,40619bb8,2934a8e3,cf9dc7d8,e7c1c0cd,28d9bf5d,83a7b33d,e1060c01,eaf58d4d,10fde41c,495b954d), -S(6fa762,97a3cd7a,9799f3c1,95f56864,c5a8ad78,f4014c53,1dc83fea,244003f4,3bea377e,9183478f,89f94127,3bf5222b,148ebfd5,7125fe96,147243a0,d07c14c2), -S(71061b69,c5a32537,d40254c,fcc5f67d,cd4a8,40911295,8a8e3f3e,5f060a6d,a980fae6,eec78bd5,3c926649,96239cff,eaa10169,7580799d,5b38ff74,8f0f7a78), -S(518db918,8ed0bf54,75234c9a,7e9c0395,8796645c,89104797,5a8602cd,e7401e3a,10c50bd0,aa0fb6a0,62b964ff,65a5102c,d6bbb192,3dfaf2d7,edfbaecc,77cefbe1), -S(6f7fc8db,8d00e22e,6f30c093,573d9f5f,fa939796,6ddf5a59,6126f896,88e99dcc,e417e5fb,b55fc324,1a283315,3ff234e0,c9ac49c,13ae48f5,b84941b0,702a7c08), -S(1e09fb70,ea2c11c8,601fdaa7,7734b369,7e5efada,77b38869,8553d4ef,e1bde2ab,b8bf422e,c93c03ce,9d9ed0e,de058d20,e0fdf535,63ba16cc,494d6648,fac3a027), -S(54bd2f4d,961177c0,dfb4814e,bf5eee4e,21b12ca3,eaccea46,e70e117,76ad1fc4,358e0d73,79368299,f33ddb71,1722c2ec,8912877,c3891c8c,bc55e453,7c803962), -S(53ca166b,2eebb5cf,59a35287,5f6fd200,dda76f66,e3341ffb,1adb783f,4a1ce584,ded51d62,7769372e,42540e0f,20ff4a3b,2d912b4,6eaec7e,4e891ec4,18fcd0ed), -S(dd28eb5f,5fccf394,81467a6e,746461f0,3e4cdd04,6e7e6f36,534f6384,daad4ab5,8d702671,6e5e098b,648ae87b,6b782374,a2a3eebc,eb4e3835,470d4831,1f7dcaa8), -S(ce29f160,90fde1e6,13cc16cd,16cc7b8d,7e6e1203,cb1f1b5e,a724d65e,4d91aa28,d44c4dc7,90586159,ed9f9d18,dccfd95,e24bf6aa,c1bc3530,ec871473,330680fa), -S(6d25e798,ea08596,7cd9e0f2,da65b546,8e885d92,ed8cb0c0,8a266dc1,6b4e222,1d18fc8a,4010f407,aafcc995,8fe38f89,fa5f6260,e3288f8d,e4d98f94,377d624e), -S(6deeb20b,cdb46236,969035cf,58365ea8,224830a5,6cc187ef,6d938353,920ffb36,b19d7a95,b829c318,96d2833b,9277c9b8,7e28c6cb,c81c4c2b,d114afb4,c5266c55), -S(72c4d5e7,68866f63,b53a27c,74ef9b43,35e7fd11,2e13db1b,93654078,f625574,ed233d0a,1994d701,62869eb2,b7a2cd20,d82277d5,3109a9c3,e6e97f47,d727dd54), -S(79efc60b,64c060c1,a142efe0,5dd75ed0,a5b4ea0,85e5a10f,c6620db9,92525420,101b68f0,6ae4a3ce,2e33f003,1ecc3b1f,11dc24fa,d9f28a82,ebb2f5f8,380b3c8a), -S(a8cb5ee,ee7550e7,41f2150f,2e458dbe,f8d32b87,dcacf424,5cd089f9,7cb6c0ef,fefde564,3f885730,d60fa2ef,c85f4b16,d86d1690,3b2a8bb5,4b5c18b7,73085054), -S(dd8e43e6,828c9363,32793374,9d29a822,66bc8b1,4e320750,3d415831,bd7373e2,5b1321c4,744cd3ae,9348ed3b,5e4cbdb9,5e1d7256,e7ddf7c3,fa1fe9dc,494469a6), -S(8ad3b3e6,a237ed9e,8f94d669,2f5a7725,b0779bb7,ae06c57d,1c25e449,4c95479a,45b978b8,500757ba,51a05069,32f17d9a,bfaecbe2,2cc63c1,5a9b617d,98b071ab), -S(cb3497d0,7c72e534,75618cbc,29224ff2,17fb9659,9d51a6e4,1559f323,9c699c4b,72914c58,8daf6396,d4d9b70e,9476d967,aa60e574,b637ea1e,25c20fe0,1355509b), -S(fb77666b,b8c6cab,ca7ecb4f,e88f1e0c,199a81f1,319b6a6e,9cf2dfc7,e9128147,f122b377,84326ffe,21a707c,a3bfe74,2e433894,7c791814,855501ed,255a2ab4), -S(f2f16cf6,6a9943b6,19b321ac,76186ac5,6e65c2c7,aa9c87f0,15029f6,36749c74,aebb617c,88115519,58f90c87,5f021df4,e3c83e22,9f787275,db39eb05,9b3d9e82), -S(607cad82,2d0a117e,cf29dbbd,c7a5c6cd,d4b67f7f,6bf6271,c58de368,50692907,f2344d08,4e7db14f,70463f4f,20e9c379,538f0031,285d9c6d,1cd33d5,beec40f8), -S(efc8352e,dff912a1,936ca01c,18da7ba2,c9397f42,2cd58738,4ce321,4baac332,52006389,6229a8fa,e24e1686,4c5a643a,425e20ef,46febfdc,7d9c43d1,f767ca7b), -S(63d31f76,805cfe95,4db3470a,1d7215,505fa39a,cbc69048,58f801fd,eef99804,97cd5656,86da7de7,4d12cd9c,6e5b0c5a,c4f7f22d,3d44b372,a907c233,8f963e7c), -S(7e64f2b7,c2083661,8f2e2d21,e86ffa91,be646231,c61ac353,c32cdc25,953a01c0,c9222645,5b1ccb79,e00e905,2bf2c9db,91d41728,58e46f84,811bce9e,8b0713f7), -S(b5f29487,3a276b67,2d2de980,c6f74a23,d7bb465d,e9bd3362,45ca65ed,f942b85f,76459975,a0569a4,8b2b463f,375be7b4,f05e1cd3,3ee33a75,61ea8292,850d1089), -S(a0f6ba4c,b52187c8,9c4b1218,b7f57773,94551352,61582217,7e649893,dc3cbd8e,94d62e8,8f584baf,f0ff883c,1ebea341,d71f8bc3,59807c6c,eafd845d,361f09bb), -S(ef4130f9,88666de0,2aa37978,daaeb7e0,fbdddfba,d8953c5,6011f839,e974d0a7,322d77c3,dcfd1537,99043ed3,339a2b98,87538059,714a459c,1ddbc6dd,c9e720d7), -S(d6fb60f6,4b5409b1,7d10e23d,4f311d9c,4af5dde4,f1f07616,11e0eafe,13c2bae1,72f99e2b,bc790349,144b0ebb,67b35ba6,a62b94ec,b8bda4ea,c32de255,bb071651), -S(4f69ae06,8930b9aa,bc2bec95,8b3f28b4,5b488e34,c3ac0dcf,ee05368d,1f7d0b19,b72573b5,b86157ab,1e414c20,c0e073a2,e583f031,ddbd4141,1b3e26c3,e3447d57), -S(9fe97728,7de04cad,e939e6ca,d32afe4f,865b0423,9103850d,688fd06b,db10b2be,60cce398,c46ae002,a34a9ffd,d2ef6045,23f442cb,9f7ef392,ed292ce2,ce54256a), -S(b328b5a2,1adec912,66aca0c1,98084578,59036c5d,be3b6e8c,a9476b95,6954aff2,355076d6,a48803b5,fce76401,4e5b9e3a,d7f3a270,a7c50cdc,442fa9c7,71a3dcdf), -S(f8d16f5f,14885b0b,c5d556d0,8f6050ac,62ee00d7,c3e5ed7f,2ff6b8a3,54e54bad,dd483037,70d67a5d,32e7e58b,dd83dec7,b5c8e14c,a26ae5fd,58867401,837a332b), -S(422cc48e,415b2e68,7ff7896a,b32fc6d5,e3c433b4,ec2b511a,42178b6a,9ffe73ca,664821ae,781b98ab,c6f08fc6,ad11a76b,aed4429e,b7e879ff,134355c3,4b4528b9), -S(c8bb5046,1e4bd041,afd84d63,998dca63,de940192,7314d666,7c19db57,a8f629f2,1455fd5a,945165b7,2186e9de,ffe01764,108d6f03,bf4007c0,53ec7b8a,a6a7d07a), -S(7303bd5a,4e82fd3c,a94c94e,c2f4a06a,7d60c272,b2dda534,48eec8ec,ffdb80cb,7c593252,6a031a82,673eea15,263523c9,44f3ec0e,975203db,7cc302ca,83316c0d), -S(3455bd06,7de934dc,301f4a47,807106cc,24e3d8fc,9bdce088,4c1d01ec,2250dddb,d48aee56,e99cd267,d2cd8cc1,ee9fc3ac,88cd3d6a,2e58aa97,6586eaf6,e2052db7), -S(a419f5c3,a053b04a,a7137049,cc9452e7,268f43fe,528d7232,f0950270,b9d5c2c3,dee8994f,b9feefc9,d1f5f529,5444214e,2190de46,5a514282,5ade1a46,c439c1fe), -S(31602357,e187796,39867d23,89962d8c,3d5e9c35,7a2ace5e,83b6397a,585d5a73,21168419,4dcbe58b,95cf6e85,dc6040bf,d62894c4,bc5abfd3,e42603f6,ef86bae1), -S(3a0395c3,ccbc8006,a889e8b7,f6de9f70,44f2cebc,5c595f40,9d632166,c35831bc,25705a8a,213464ed,38fea19c,e1ed5ca5,2c0f8bbe,debd4388,bc8565a2,faffdbf5), -S(88067788,1627b285,336ff69,3ffd3728,6d0f154b,b743e273,2ff29598,178f5f17,c0980505,2fa7c70b,fd34ce6c,f27e5197,3414cc7f,1f57afb1,18385e9d,893963d0), -S(e1e1edd,146391e7,aff005c8,8f5d1347,5b393ef5,3a017b17,84a6dc4a,e29f5b18,e95592c1,5005cee1,f27c649b,2409c3f5,71870c85,c389861d,3e285e7e,7754a3aa), -S(113aebc3,2beb62a7,6e57a820,1c3602cf,d654ede4,d58e10bc,3545d84,cb406362,afc21a5b,5155c143,45bf5b47,50295ed3,db00ed7b,ae83205a,a0c504f7,fa5a2db4), -S(cdb6f34,7ba8177d,57e58fec,f22424b,fd3a276,96d386f4,9abaa40a,7f03bc2a,8959bea5,7d63b46,ae5d4d34,358a49ee,142b9b7d,137bb2dc,f4a937c,45338b08), -S(f9e9688,15a87cfc,85c00d90,2d7ce467,5086c566,49246f8a,bc655dbe,c1c82882,7152976c,19e3aa37,aa63d7c1,b9b45111,923b3b7a,df49dab,ae50226f,f39c1fb5), -S(7e7c0a6a,272ca295,c7ff3de7,906ce47b,9470e583,6afd4218,67143d5a,ea1d67b5,b66f3565,d68d55e3,b7542ed8,2b12e217,e4b47879,d9dda727,bec58094,da9d1886), -S(72995966,366251e4,57009324,5e29989f,f15670,af4acdb9,3eca8d47,3d1bab8b,9a8dc60c,3232eb18,9b454b51,d9db82b3,dcce9f54,e30e430e,26aae1b1,221594a0), -S(973afb4c,aa2688a5,b7e4f679,e68c2e4,df25ccb0,d56de80d,f6522000,6eb4dc1c,30055694,1c0eb266,906933dc,9c1758b,7a6181fe,8c400191,bbd978b,13f5f55f), -S(2d550e3a,f5b2d5f8,3cb4c695,431ed8e,62344236,66eb0eff,7759d4bb,39fa2dc1,5f6eba0c,e447bc92,70d35709,87eb9b17,89e7721,a7ef2ed8,8f749dc8,37dd7e71), -S(ed44931c,7d509be8,706150b0,3f24426a,571fde4c,e7b2d3ae,488a3576,37f6ec28,48e05525,e9b38639,6da1fdfc,40a134b8,1e05fc60,c7bccfee,8a8ac358,e9fd09f5), -S(6de88a88,b7b34f50,a8990a4a,742bc1d5,62d6b332,810451f,1c0081e9,18268975,5c435e32,379e62b7,46ed6518,b304ad1,65130b66,158cf41c,5418e490,edfc5535), -S(337611a2,907cdd12,c6c482a1,9b89fd74,1547fcf4,ed6ee721,cbcb66f9,b90967b4,1a438459,eac97f8b,53e45562,4a25ab67,f52cc6a7,fd3cea42,5ad08dfb,31d6bd2c), -S(aff600ef,329fc815,d36abbf1,3eb59530,58e74ddb,9df425e6,49662123,d8c429ca,ab8aa32,642dbcf9,994134f4,65a9e760,ce8cbf17,540d2f3c,fba6a31,9eab56f6), -S(4b15c510,47c6cc2,309c7eff,d3124f66,d56198a5,4da997f3,48f35fb2,7250504,5cc00333,f6399193,ff90ec0,54a726a,fcc492a6,bde386b6,57e481f3,18000cf3), -S(4683f46d,b9cda227,cbff9940,23995184,92c61151,a67508f8,5629945d,42a89345,cf1e8d43,b85cd621,2da2bed4,ce556ad3,ff0abd6a,1d40e445,629d727c,1e072e3a), -S(9ee0eea4,850864e5,c8239602,f84a9044,b966f84b,1aac7690,3fd096b8,fb09145d,c4c0698,e2611fc1,c7bd1c6f,f86e0fc2,19e3532e,defaf5c4,ae79410,db9e94ee), -S(ca4b7b7f,e02e953d,e622359a,f1834997,e5190c70,c149430e,d76aff1d,e166a0eb,e899496d,bca56f10,f2823c41,365400a2,723ea0ae,72f062ad,c36c0bb5,8e6ac820), -S(cf62993,f5be553f,a7492b3e,45934937,4536aada,f8db809c,cd01fa40,49364a2f,fda0bda9,d0f450a4,3c95a5a2,1526fff4,1b63c08,8a320b2,1ee9716c,cf2613d), -S(cc35c60b,288f8ce5,4120178a,dbac3e19,6e76ebac,159e45f,43afe82f,c034f459,8a6657e2,f8b99b03,3c6e29b6,f3bf373f,c117b6cc,f7ef935b,43b9a1d0,890d8bdc), -S(36a1bb7a,5f4ff871,b5ffe08f,90ecfca8,7c19eb0c,d110d770,20aff404,95b72e0c,1750a693,51de455b,1325e926,75dfe3e8,94de9f37,2d2697ca,954944f5,87d8706f), -S(a04c1bdc,7ec653a,fc549370,25d202d3,1bb7c21c,73de8160,160693df,ce42b5f8,4dd93af4,37e300a,8452a7db,af6824b0,e566a935,632c3487,f768988f,d874e74f), -S(484cd2a9,99cec03d,85872e48,84ee50f5,2172089f,8f1aef0b,d3ec6595,2a228a86,9a65d51b,bf64776d,53e40da3,85b84485,3c780342,6952446,35a78ed6,e1cefaa5), -S(398f027b,8ef951a4,2ad7c665,f5fdfce1,831ecd67,23f45154,62c636cd,db3b8a64,99577f76,a6a3b0bd,ac4d50a2,24c10250,727ce349,856f4e7d,eb1406bd,62d9b36b), -S(d62300fd,a6d242df,58be11b4,fb754306,62dcbde4,6e86b1c0,d1419da9,99beb256,cf11becc,84928784,d23a74b6,4dbd8ce6,37a1537a,3d9d0f43,17803da6,d1bf5e97), -S(4c41dc69,be8c1aba,9da4469e,2c1e3eb1,14b07fb2,db63785d,da03c53a,faf0f147,a83d7f0d,fd92a665,d73a2f8d,520f1a2e,ad6b2465,57ae2736,9618d10d,b114680f), -S(9a5086b0,1ba7ea1f,6cbd3be4,8acdf6de,29e8f733,b120aad,daa7e41b,3b1b2708,f4eedd2e,814d1f5c,33f44080,e4d50452,4deeba2b,4b2ca528,320bbfa9,cc3c65f3), -S(a457659e,51a7154,e5836fd8,4948cb3c,227986ad,f9fb8acc,89a3159f,d723b478,5c59c117,4e9962dd,94f3b084,8a544983,54ec4962,f0d666df,889c420d,78845ae2), -S(ea79c22f,13e6cdd8,e282defc,9cd6ed68,5d39b48b,c6c13c55,3bdc8aa5,8a90f78f,87223587,c3cde568,81217ec8,ef0dc431,89af8095,d7e9f82a,86142207,d8b5c356), -S(e19dd143,cd0a9f3e,8535edf4,a3dc7e7a,4c49a25e,1771f8f0,3fb5eba,1a9e10d6,d15a39c4,86b79714,89b2afb8,13b412b7,c1de54c5,c3fd2ff7,791bfb2e,d6a498c), -S(c7b277ed,9bada568,2f7a87cd,6435e0bc,948fcb1,2551ad92,e188b664,fb5f59ca,7d1e37cf,3093775a,1b0aec4,93b77c92,f6d6f32f,a1d8438a,b75add39,70b5eb00), -S(c1fb0836,5dd42214,2098c397,b11a63d6,43afc082,16c0686,d1540d4f,d39f2f85,438d6559,d07fe7e4,1e775a3c,66e79f30,a065a62d,fdecea46,e8ec0967,a5b5b8de), -S(1a5b6bd7,152c8c0e,6958cd5c,9344bc7c,5d7869f6,bd08d698,88e69e49,8ae62ed2,166a9f1d,b2b3a729,e374af09,40bad6ff,7646504d,36d40465,2c826ed7,98195f0f), -S(8e3f1e45,42438eb3,2635c65a,a817c325,3affb9b1,a1603d0a,d3fe06a5,83cf338b,e6b26e2d,9e310afc,e702dd5,4bcc2815,1dee0a86,1e31a16b,79fa0900,f94e320), -S(ed9ffd27,1fd7b569,fdb187d2,7d1d97b1,3a4b88bc,aa13639a,62a6b45b,cfd00dc1,5fb45391,d5a636d,1d757e5e,472865aa,556092e0,870f45af,a325e26d,40f755be), -S(873a3db9,be376cc5,f4516913,d8235555,624cea02,16c3231a,72750c44,12cf4992,3d5e2304,2b04870f,d3cb61bd,2f618b3e,4f1dbd3f,2b585026,fcebe608,7f0a5a03), -S(d3ef70a,eb5ed2ad,375ca185,69278cba,3d037dc7,b0f63ca2,442804f8,1840e686,f4bae13,fd55a2c5,ec93a87d,c2b4134c,aba2fead,39dbb555,29d70795,45a9488c), -S(d2127f38,8f3b4e7c,b0d24f80,27f27e55,fca1110,288a1c1f,da46441b,21327919,18f2b4b9,69df9a42,1a87cc43,47e2ab53,146d6b82,fe3c19ef,2df361bf,579cb3a0), -S(5e73dbe7,e8961e0e,32b9af6a,4443623c,cd3f992e,b024cd1a,59bfac9a,ad6c9f4f,4d8299bf,b505c0f4,5835cda0,b7fef2ac,640a5835,6a7e498c,b0f34480,34527405), -S(b9eae3f6,9af01cb5,48cd994,db6beee7,7e45fba3,782a9ba2,83b340e0,fa89bba1,b7ad76ae,189735b,f4ad8e8,dbeabe72,ed40b2ae,2c9351de,1beb1252,d4424b65)}, -{S(458f8dbf,9cef8cbc,5d2046c7,42ca6297,e8fc76a,ad22fd3,af4f9a8e,2173d857,57074c8f,14a36b5f,6924517,6e3dc7b6,4d12a08d,8d00565,e70e0ca1,56f29820), -S(68e7cdbe,47bb0fec,37fb7860,a71533f5,5eddfd2d,8ad7c9ef,cc266009,65c627a7,3bb96d5e,f0cf90ec,13614c2a,c46039e5,e6e30782,48f855ba,8f8bce36,f66b8a90), -S(c220e26b,6d3cdf7b,b1cf434,ec5fca6c,eaec952b,e61d213,16601ec,6e06b259,3fdfaceb,268183bb,9914c5ab,ae804206,a3711bc0,d649c407,82d3d2ce,93e350bd), -S(fc458625,75cc7343,312902d6,8e160a08,f82fdb0d,60df16e,575f893b,94592e52,e2236fb4,e6af3e39,4faaf83a,3c6b418,c560abf8,eca40f29,d3cb91e9,e13a8ab9), -S(7afc4446,f445a33a,64fcc04d,269529f4,1e16f567,550a8280,4027bf24,1d08e895,3ee4443d,2cb04a,3643f6ff,90c0b3da,a43c8333,82c62d6,5a024a68,e7e7f06d), -S(4cea2d22,d19a898e,fca4a7d7,499252bf,1957379d,a6004,df9c7df1,60dba4e0,c97fe09e,84024a28,ef88985,6fa1feaf,bee116db,a88962eb,36be946b,d2da76c2), -S(633cd50e,b00633ac,6d5b1bfc,89d97e24,abdd932a,ee9f265e,95dac73a,65627e0c,750ccac8,f09d9f86,7117781a,6b20ce6b,6a4bdcff,7ab04769,a8dcd1d2,c541bdcd), -S(20224a29,28ae9e78,87bf4242,67333b0f,fd59349a,2321b8b9,c28af552,c98fa7a4,94944b75,4b6a0ba4,7c647332,e9369b,dc57f98d,5a010925,4bf6d2a4,eeaf88e6), -S(29d9b1ac,7ad67ad5,ce2e965d,e7ddadeb,43bafd47,f0fef02b,2f553693,1f45029c,dfa93352,cf5dd7b8,3e5a9646,da2a3f3f,152372bf,285b75dd,1517e6f1,7859c03c), -S(54859abe,18867be1,dc85a087,4cc7237a,597bce13,866686d9,43e6bcac,ec4fe7f5,1d956ff9,31259641,1faa0b22,b2639487,d0392514,58c5eb8,7918fc2e,26916864), -S(9c3c1ee2,ad3fad0c,e5e6ad1b,9b1f5875,1ad30927,9aefb1d9,4e8f408,c3406d42,b31e5e91,18bbb027,f3ab9d42,ba1cf854,753dc66,641cb367,7e8db07a,4b7d4fa8), -S(c4e812d,5a640e68,70a42601,694341d3,5e964f04,fb52f1bb,819166a3,4fb8732d,f9494ed1,b776c04a,769308b7,4d312781,5f9c3d6d,c7ff4b17,cfa1fa31,87435938), -S(4f8fc5f6,cb4e73e2,e24b94dc,63aef340,b871abe9,2fb53525,ef0ac7c2,e04f571,d81880e1,b3d0c55c,8d28bb51,5f1a10cd,245fb5e3,70eca394,d80ba83,d7615512), -S(2223062d,f1572257,9330efcb,2c5a90f5,6d9c33f9,87ef9b9f,9c79db75,dfde7b49,8fbefa3f,37c855e3,ca3732f0,2d0c0c60,b73384a8,3458b05b,eb74da89,acd6c1f9), -S(cb3b77a1,defe7162,63ad33b3,5db0ffa2,e80d7,e00dae7a,91abeec0,17fb2a8f,29cafee4,8cda21fd,d692d241,2358b229,559d7b2a,c93e5eec,9e4e7386,728dcf62), -S(cb520a70,3b9abc62,9a039af8,ef7f8f50,fbaaa21d,721c1bf0,d2f680ac,56061581,58643940,fc79dda6,35b846c4,fdcab298,6a2969e0,16886e,93ba4532,cb03140e), -S(c1163c31,a922395c,7afb6fbf,19a848df,ff20dc1a,38f1c86d,89e6779,3c97473,8f4e7bff,a21a812b,ed0c00dc,55972ed,173bcd4c,36476bc6,70d5177d,73e539bf), -S(82a01624,64aca6ec,17abad94,4756cbb0,b27bbae7,120e3564,c1c83776,138a1e46,9eebe6a6,140227a3,15d7f23c,176cebcf,21f61112,86dcf337,21deffae,d701a856), -S(972acc1a,194b29c7,1d626053,34704ed,95201c9b,92e5bfa0,937b7369,dd389794,48ac34b,936ba87c,1a952b91,8a82f0f0,26ddf57c,2ea44cbe,d15f6ce0,da73a4c9), -S(11c28dfa,639403f9,f8283916,dd32194a,d116ec21,e56e6393,f743ccd1,1b1fa275,8a008459,24e50c2a,d3a713fd,53fe4998,86cfe86d,2f31b8a0,b2903a48,ec16b1ba), -S(d308b5fe,c8e87dea,6ff1917b,8b853701,7dd6a46f,97c268fe,7dd2a672,92ff3bad,83ccbd2e,82917e04,fe00fd3,cf837c0c,efc34a81,54c2f068,3fb079ac,3a1dcab4), -S(f4551b7f,aef3bda0,51ed6978,45d37d52,97a9ce9f,4b684334,fbac03ab,ad0ab7b5,7ac85f32,e5cc407c,5432ac50,ee015a7,e2fb3191,90d8855e,7c5ed488,ce5c6211), -S(23daae11,946de442,7934b351,a38df422,2f8f5424,b2dba51a,98548718,3c21d2ff,48dd1fc6,ef5ca525,88b21118,7c172792,ff9aba3,d18aab3a,19d9dc0a,d795763a), -S(1d225202,4bd2b32,87400ca3,e8de9bfc,366cea7d,c87007f0,e36d49ab,32f3d389,e711a6d0,692025ac,74755d2b,46c8ccf3,1824dac6,35a48cb1,af6fe2a,ba17f178), -S(b500c6e5,1111339,527ae172,11055236,912f7cfc,8e67c4ba,94dbf39b,3aa349f4,7a65e1ea,dda398f8,5da9f82,d5bff3df,41b92854,29994d8e,b9ad0fb8,ec9610bd), -S(135294b,236c6f34,478921c7,d463c14b,92da01b0,226b0bbf,bae7f392,fc1ab605,8f77291b,b39dda82,33e6e523,7d313f60,3bda29b3,4961a6d2,4e474397,2f6bc068), -S(1fc67f92,9f12d181,73e45951,eb64aa45,627d2fa6,61a2d35,25e818d4,3d4b2ebb,f4174ab5,dd5ccf0f,d6522310,20bca7dc,553fc88f,952007bb,b5012789,ae9d1bd1), -S(47ae7668,3654ec8,a3904f7b,dd02efb0,ae4c8489,7deffa8f,a71aab26,d82dbd52,1e20245,990a0f45,9368065f,edfc7d08,ffdde726,1c8f79eb,68adc042,de1bcd88), -S(750b52fd,7ded02cc,886c9105,8dc98545,67c8c62f,c7dcddcf,ba74e552,dd8343a8,2df52ef3,2d8f79f0,9423792,341ba29b,d78cbda3,252347bd,123fdf78,5ab9b8b9), -S(148870bc,fbdea326,62c20304,aa2d9edd,91de2474,433711f9,75e977e5,d3b9cf8d,a0848bf8,6cfe26d5,3c4a0960,97925a32,d296db69,d3348c7d,71f7d5df,223b3747), -S(ea916e64,4958c33b,1610c7c7,b865a315,eede0d2,4881b156,4bd234ee,e372be92,387af6d8,4e8beaa6,a4df0813,db45aab0,6612bc74,aaf4a292,5a838322,a18ff4dd), -S(1aa70a60,273c70ba,51ff5fdb,2037bc1f,5ff9e0ad,f2551fff,a2176bb9,757fb4f5,a578a726,53233bbe,fd34673e,4890e0b0,d2609bee,5fcae095,1fdd2711,b618954a), -S(a51395bb,6cf06cb9,b2898e7e,d39c1011,ea8e4539,cd3f5c17,4150ab6f,7b0f170f,50820591,ed76ec84,a0ea2b57,b11a10a3,d46f5b73,71a67016,f952c497,3cbdd83f), -S(c6d532c,a8745145,e005f8a0,82b57eea,a235d56c,4688d98e,5cd4a911,d0b381f8,fcd16c55,4a38f1a7,3f82ddef,a3dbfe97,7d554b37,e6b60727,4a37ca7d,28473b2), -S(c42dcb2e,169a5276,e0dd6195,3f7991d6,2d4e9459,5934dcd0,e4daa217,1f050bcf,9ea1f3bc,e274ba98,a38d76b8,1af87fb,4f760b1d,940a1ffa,fc6c8a32,59cbb197), -S(ae7ef14e,5f93dd3f,3ce400c6,c6944a2f,e14617ed,af42aa9e,dec2f269,fafa21b1,465a5540,e5a4349c,1ff0bb26,a660a935,373deb42,f16e900c,f66d638,38113dc4), -S(ffa64715,253ecee5,2ab8dd71,17100a64,936e7d19,3e8230c4,1d06c0f7,b516b91a,1bdb95d,631fa76d,1a8fe556,44c69cfa,b0997ab0,16b256c0,30a7ab5e,fb0de0fe), -S(def35473,ca162629,2f49c77c,2cba01fb,af7c94dd,8f9a21e1,9883901e,8305e3d8,68962e7a,aaceac89,1d5da447,40442b70,f2248b4a,b6b5bf03,f1e00a66,3b0378c), -S(52d2f036,925d466e,45b33be1,8d16ffd4,4b1d191e,10d0d72d,209ebc4a,3f8358c,88a7454f,260b9d74,28afdc59,1ebba74b,710c1b11,ecc755cd,ff482e0d,bd859719), -S(6ab19082,9a23767b,404d25f2,355fccb0,5625b6fe,88bfec66,409668a5,e5c0cf1d,85c26852,95550088,ac9ffd07,dfd972b,dc6f25e0,6509e9a7,92d59b2c,afe63ca3), -S(188dcd54,5c0859ae,6916c4c5,44f3ce1f,7f747007,a6a8d26f,5843f88a,8dbb6b79,9146ab39,c1ed37e4,557aa5aa,c557f874,bf47b4ed,2d2216c4,64b66572,50feffc4), -S(d6ede828,c35972b0,7105bfa,ce6396d4,12fdab87,19f93ad2,cde46a4,219b4faf,8316a8fb,2c30c3ae,88cf61fe,ab875c03,3254a2d2,e1c5eb70,24f83973,3db48b51), -S(a363f5dc,ab07afa1,bb0d93f3,df44f786,4f5f60aa,330afc5a,45368fe2,55df6097,a5839073,c4ebc180,50232a4,a6ce7e4e,b3ac6114,eebf3be5,b978e1fa,7218b660), -S(8ff6e368,f82040cb,9647c91f,7bbc75e1,7a163f0f,7c9295c3,e7901026,e4fcf2d5,fa8fc30e,8607708d,1e2fa7e2,6d4c13dc,3d560fef,c19cf1ed,5dabf5de,8ba890c8), -S(4dfb283f,fcc74939,60d239a4,d364d773,21f1426,b48f99a9,5572ee88,17ac59d2,a6561134,2c7559e8,8b180a59,a0708b97,9e9b381,a1541e0e,a7b6cfd5,b7aec1f0), -S(59c8a74b,ebcb88da,5b8cda4f,1af16c77,ce323f1b,1a9bea22,bbf8a38e,f5a8a6bb,9ec04d7b,e7d56114,f72c0fbd,b462332f,6f921765,93affd25,6a37ef5d,91eba83), -S(9b8dd571,edc71d3c,3337aafe,b3c33f8b,a1a35db9,fb071cd7,577fd5f6,f3a1d3f4,ce7249c1,e00c87db,1149e014,7c531efc,ad8bb3ff,75e51a52,318743bf,74bb84ee), -S(a410bd11,12ddb03,410eef03,ce8ea4ac,f1663660,c12c97de,bd4a2532,9ee2fced,4fa2da11,2c0f4a1f,5520ac16,7809d7e6,2faa8b9a,c442b84f,e2badf94,84368117), -S(6a78a5f8,eb495f28,dfec9329,6b026bcc,f88defff,ebdf4986,782cb546,332fc840,c90ada0f,24723e43,2a7aabc1,931954d4,cf60908d,38302255,a79231a7,93f02f86), -S(1126bde0,fdbf76fc,722bf379,43126763,a3a3fd6e,5f86e9c0,d5ed9eb3,7b9f29f0,d85252d9,ffd674ce,3d73ba20,49fb2b57,f1bb9073,daab3d2b,79bbeb,11bec42d), -S(ecd869b6,4057202,af53378f,a9e57c86,949b2b78,8034656f,912371f4,e5f122ae,cd94268e,b999b0f8,baa47cc7,d84b78c3,4817cfbf,43594655,2a138d8a,7c75b201), -S(deddc4ac,6aaf1649,b69dab89,7650fbd8,f4eda196,ec973025,7bd24cdc,7df2a94e,bd6d69b2,fb809b58,95812ad6,d1a4b029,f3861c52,4fde59f5,ab72a378,8bde28a), -S(4305fccf,95196da2,1aa49916,601b4f00,97e0b145,93e7a6ed,967768a5,836750c2,b997bcf,cc942007,c6b30a6f,a4f8ac41,52b92f52,fb9a3561,2015e846,4e4c4a8d), -S(c6235374,bcf2ad2c,6ec1e9a5,55080ab2,3765f1bb,892991fa,6df94a32,ac0ee35,e878dfc1,7a210fd2,ef572fb8,3ba9c4c7,b7d67dac,446a7066,ae0fac29,1b326401), -S(de7be4ea,50937662,a22a85ec,b2cb6f64,eff08302,13456045,e86d459c,1d36cfe7,b6beae42,d2d26eaa,20ea9941,e7ac5b88,d13e35a6,ac457f39,b80382e0,1c1fcbc1), -S(83faaa90,c129b256,736d231a,aaeb56c,851cd0b8,8a32066e,1587fe71,3d26e7c5,d5aa97c2,9eddce7b,58f9d96b,10a2fde7,4c1ec756,d30cd5d,bac03a2f,f4f5af16), -S(3ea3ac7f,976f5a3e,81cf5ea4,4325c73d,8fdfc7b2,57512f70,236abafe,925c1d94,edcbdef8,de65f541,9c5dfd7a,6b1e03ea,5b15803b,161a403c,8775e29b,7a64f3a1), -S(9a51b8a4,5bbce94d,8ce04cf5,dfe4bb76,cc8eb592,9aba8964,1ec58e,9d979461,661bbf31,86f36500,d45bc5b6,58071b27,9b3d327a,a86108ae,790f1065,dd45780d), -S(a3c3005b,5df20d43,411dbe7a,3daf352c,c43b8a87,564a9891,c237b7b6,2a485369,20603c49,2c90c32b,616fecf,286a13f5,213402a0,c0f8d64,e2a39b2b,bfa978df), -S(8685133d,3f0b48e3,fffc28f7,ece3b6f5,2789d948,68107d3a,4cd380ea,a00040f7,4b07a1a0,91f3fe2b,272d594,9336ff7f,d88d758e,d7c157eb,5e9efc65,4bc52c2), -S(f4512104,eba12a54,aa6d497f,59a256a0,ff1eac53,573c2ad,e480684a,99635bc8,538b015c,a96decb7,ba0ce9fd,b14393a6,7825205b,ff2c712,1f96d27a,3beb83ec), -S(709fd8b7,1795cc61,892ef282,10049b56,28f1b6ab,e5ba9a5f,285777f4,320d88c0,4a742056,abf637d7,e9b75e1f,938778fd,4117f87c,7699a67a,1c08e3ac,a2275622), -S(68a4a2c2,c222513d,b7aadee8,3d05a13c,9ae4c422,6d8ccffb,f6b6b88f,f59bce44,706c2374,afa7cb27,8a95d8bd,6aa98533,ea7fc003,33678c38,65153006,3589db2f), -S(38bfc02c,3430c92d,958b80fc,ba196f4d,9c4656c4,3f667cef,1ce0726f,d6be250f,a05c4f47,7b44a3ee,aa21107b,3a679db2,5aaa738,c474436a,c7dee4a2,228fd940), -S(c2e84b8e,f4380fe0,a674f5bf,3c55d3f9,3b060e08,6b207344,923f28c7,b7935fb7,bf1a2c1d,677595f2,33ae6530,d3bc151d,6b33294f,57d3ac23,78749450,6a0a189), -S(4425f7db,6cf56461,147ca518,732f101a,39c7f585,b5ff88f0,43ba3e3e,a47bb597,4ff5698b,88fa8489,b08c4094,3cda74ab,b5801911,d36232f5,9b358d12,193b3d9c), -S(98c57e63,521541b8,acbbd5c,f568b1f5,d3cd74bb,c30562c0,12518cf,96617e48,f49e42f0,8c236a61,e08d2d86,ec245822,64117ccf,6edb80df,403bf084,6e25aea9), -S(dbf6760b,351925ec,dc6976af,97a088cc,63115fa8,5fde9763,e1524c1e,ce901cc7,909d7429,73923501,e69d1bf9,ba1ad177,f99da741,560af1ab,9cd07e80,7b4f5f8a), -S(b42ef95c,79d167e0,6e29a6ce,ffb76ab5,c96f7455,21f128bd,faccb108,d7f2a609,6a3374a2,5edac6d3,744eb2d6,f39a94f5,44f852f4,779f2a98,6f1de5e3,fd729323), -S(a1034444,997dba07,20de1194,c355a1e5,ce182420,b19033c,ed68dc08,fcc2507e,b2cb95f5,d58044f2,36088bde,cf0d3af7,fe9b10d1,aef8f355,b688c68f,18829bcc), -S(47e80598,1a97f80,fd0f1a14,12d0d1e1,33d7e4fb,bda4c1b6,1dfea483,3589a59a,d33bdc2b,30d0c301,bf85e5c2,c364f1b6,f88b83c4,9e51c9a4,22229b82,10471443), -S(a355147f,281d4518,f36bc6ac,820478a1,6f0a1f50,bef72be6,aa53d420,3dff20df,627a5765,41031765,c3751c39,e9217493,f9da1927,b496eedd,8466709c,4a47a0a9), -S(b02ce0ed,6196748f,cbbc3809,7ec6e7d7,80186023,cf96239,e5a79834,4edcd3eb,f6cbeb1b,2b0b17b8,b620b799,14810a4c,8c47e404,89573b08,ccf826f8,7d8656a5), -S(87aca9d6,450aa411,8f56176b,49646304,dfd5d3dd,84f4508c,3a4617d1,92843418,82a93bd4,b6e4e426,27404ef1,7d837656,e0f876e9,1bb4b9b2,89e678d5,a430bbc6), -S(1dbe7199,bd248d19,5531ef66,260096a1,9614fb65,e90c2f5a,49ce3056,2cc60f29,ea49e29d,60082d51,7a807196,33c55ebf,f243a2d6,254ad322,8d614943,d19a5828), -S(a16909ba,d4fec20a,8b6ade2f,8ba3cfc1,d347812,f35b96b7,9b2910b9,de4e7ea0,496f1a32,3593a23d,ffb5f0c8,d9b599cc,18e101e4,215fe501,41147e07,6ce86a8c), -S(56e18008,832f45c5,30b819d4,a84416f6,db9b952f,84478dd9,243a293e,2d576867,16399c95,8ce72e9a,b2a3b2ed,becc8f5d,c220e632,60a1cc9c,57db3a4c,12e1943c), -S(d32b7ba3,d0af5b68,21d7d716,6f7d827d,f67c2f02,8510ab10,31e4ae6c,2beff031,8b1cadde,54e84e5e,5a0cfe29,a838865f,9dba3867,85016145,e9f81478,a6a20ddb), -S(55e603a3,8081a476,f37d73b7,645f3de3,9db27208,e0d1574d,99a7350e,95c76631,a9c50870,a3fe9f7b,da389eac,963e26f7,51a6f289,351025f1,b621d611,8b5872e5), -S(d8c1fd0b,a561bb0,3d44e9ca,33850198,3163f44a,5d6f3b71,118283e9,bc3c4feb,ef835785,9bee101b,dfbc2cad,7af7b10d,a777e78c,ee9277a0,ba29fba6,d9ee0568), -S(1bcec745,f89f938b,466bf429,3ccddd5c,c8566c9,2ccc25d3,a1cba363,b65bbb2f,b344f901,cd6317f,b4380012,d6fa9caf,64a5f75a,b4347f14,a227ea5d,bbbf2023), -S(8e9825f4,af70c5d8,15dbd92a,148cd259,30372bf5,f86d2a02,e700b156,812cc9ba,3290e56f,6876100f,6e20db9a,723bf99b,72a7be04,a3162d62,386abacb,ba377a80), -S(2581a86b,bd224745,a6518042,add5a63f,b640efad,191ecfa7,a582503,6c5797ad,4f08900b,e4e1abea,63c9fd36,c6939bb6,dc91f066,88ae9318,5049332c,be32e994), -S(d32004b3,48c65b67,80891f3d,7ef8c029,1cfba007,1cf03f18,c0b97cf9,bca71bfa,256a990,7442d77c,a1e3cfae,48a8230e,a03c0889,29c12275,994ab662,e9beb3d), -S(7b6724a5,a0090968,311ea2bd,d3ecb7e7,c7246bbf,b6a0793f,599a2146,faeab5ea,48a676,fe3a185b,cc6f7188,86bd7064,3ec7d20e,ff94b8a3,c1953b3e,a2f8db4a), -S(83d6737f,fee8bd73,eb4beda0,1916f875,85d9fc78,2f726243,f31a2289,456deee2,1d28e79c,c010e982,9a94adc8,35022da4,e9dc67aa,ae5751af,64c53f13,afed61e9), -S(472bd739,ece53ef4,12979f4a,89b6bb45,fad8b374,14478a14,afd13a57,3c315cf,27698c4d,861e5cca,831112cd,449980ec,1d81bef,6a396b6b,fa0da65e,ab164dcb), -S(8ea8e81b,22657ed,51bc721f,2f7956ff,fddab5b5,c703415f,ddeb524a,16123765,a301e8f8,67b1038e,56964048,2dfd39aa,9ba6cf7b,773df76e,eeb46882,2a229c7e), -S(1f931775,2da7d946,b6d9ed47,75ac74cd,6029531f,27487c1b,cfd2ab3b,faa7f6ff,37277158,e6b5c0de,5436191c,1ad8f944,7b316876,ae519306,f28a3606,ec8db8f7), -S(2a6aa0b1,106ddbf8,dceb8988,cfb33c82,4d55af5c,670d1e77,873f4a,ce74f4fc,889e4d41,b885fa99,21b66aed,83f46883,ec6cdddd,67a0ca45,dd12ed1e,ee6ad292), -S(9ff77e8,ce5259d8,58431c69,bf001dbf,fecfa5f0,bc356057,eed7543d,13486274,b8f0037c,c9c3b771,dd6b18e9,95be0ca1,23daf9ca,5bddbb35,a609811c,cd1ced95), -S(7a9b1d0b,a3f1414c,1ab3054e,f9c2fd5c,ebdc1931,ef670d1c,78db9549,6b1af514,a2407af2,ceaa367f,d6d4d733,49d77a2b,993062f3,d6ca8e0f,89d21eb,beab2b93), -S(37de2b08,4bcb4b22,e4643fb8,5f777b48,944a2351,88036c45,793d2d81,c984ee5a,c788ecf5,3900585a,a4226825,f89f9ef2,8cd25d37,565adb3c,a61e1c0c,ce4bf1ed), -S(6c3236dd,a08f2a08,9694f01,a4864dd5,d5ac105c,8c7cbc5f,7d2060fc,b4e8519b,2472d89,10106497,6ac425c0,43714ad7,d5ec4f66,fcd50af4,abcd690b,d219971c), -S(7c0038b9,2f2a96ca,115a853a,557be238,146eb196,8e7b8e88,4801a56a,fc8976d6,d68bd242,5586cc14,49fbe019,deab8a9,97a56dd5,f52b02c1,24e7b8b,141525f0), -S(24449d21,51eec6d2,49d6b613,d1b03e29,3b36185b,ecd95bf1,a52cdeed,890afc8d,3929bfa1,d9648c49,aa4144c9,584424df,895622c8,9a7a37a9,8462bddf,ecde7a2), -S(640d6b44,2c5e0388,7ea7c4ea,17ad3e5,977dfe97,907200a6,a43fb6f7,73848db9,db3d21e8,237ffa32,8d389e4,d93f33e3,cb75ab12,dea034c2,83b5a3a8,c7169b1a), -S(d2372e52,bc1d97b,8ccda950,37148f3c,1516d519,b171a9e3,6a3e87ca,619a52e2,21331dec,da625e2f,7330888,a31be425,9f69f49b,47e38e9f,85eba5b6,fdf4094b), -S(7143910b,fba2abd3,d2e7d7d8,f7c67344,581afa60,cd82827e,547de354,e5299a76,1965b472,4873bb50,c2b55cdd,dbefeb1c,e184d9cf,97ac9142,a49bbfdb,37e4669f), -S(275557d5,46e5acae,1ae98537,8d787b51,73b260a0,57e8b884,7bfbbe2,d15d5555,ca93b2ff,79544d54,8a784fcc,52fc30c0,49337a19,2b88533c,550432c2,6555e47b), -S(290231be,bf6b01e5,7904e066,5b1265d,ef4debb9,d14865b8,75341d98,de3ea5c9,acd3bcca,8ad8ca8c,b7a43edc,69fe9746,50d63593,71dc4d6b,a76e0c1b,bbf41cd), -S(93db5e11,7fe021e2,ca71621,29087cfe,93a2ecf2,560b6c0a,91044253,3dd4e351,11d18431,959d1dd4,8227844f,251a9c4a,134523a3,cc8c175c,f3f509d5,9da8d869), -S(8d346bf2,d4bae98e,ab44629d,720680bd,610f61b,32f6c109,9ef48434,6e3642cc,ab9975d6,3d4dc8e8,e90f2413,e93b2ad,e15f848e,7589451c,a7b735d9,c45f0a56), -S(6d7e8457,c1ac7255,c612d8c,99a1e850,d95d9058,113b852a,4ff0513e,e83e4f06,cade7182,8f92acab,a7d5ad5a,65fd84bc,15c57af4,499607b7,dcdd8c1b,20d75cc1), -S(23a703e2,540ba5d8,dfd5c7bd,183be8b8,a2ac028c,c51806ab,8ce1874c,5f66eaaa,5153dc37,e939eaba,35caeeee,ead1f666,ad62e15a,2f078b42,15cdc33,3372e839), -S(2ecada78,339caa89,a3baa456,15cd0040,9e7e7f4f,15fd5f02,665d5674,3ff48a7c,b2110739,2dea146c,2df5856c,aeed7577,a6bcced1,cddc56b,68462f0,f7999d5a), -S(2516768b,6d6ed0f8,9550c2a7,7167e0cd,34d10a24,7bc10f4,9c7ff55a,650bda2b,f363a634,be194643,68957ff8,2e329184,f2a6982e,51d4cc58,ec24cfbe,f0e6f95a), -S(c958904,ec9c6ddc,37f16d48,b56c74f8,64c547a1,c001e2a8,fadf0a3e,7069ea47,2dcfe201,8111bccb,29ef1f45,827d2b4a,753afd51,ed9927cc,395057df,7591bea), -S(c82c9164,9760ba4b,bed19bf6,a2323fa8,c61ca2d2,d27f70a3,b5798d10,c33eb5d2,531d2f00,be4f3c9a,1c08079b,b7aea0b,c78fd8e,30f5e2e9,27f465f,b814938a), -S(73d756a8,f79d7da7,362dd79c,5c0c3226,45e6d6f7,fe43234,1f6d7208,b9e9f5e2,2a80441e,c1b321e6,3ea1f341,838ff513,ec05a23f,e42b73e3,6dfb4a41,b96580a4), -S(78921b3b,ccd1d7b5,ac721e44,b5c6c8e8,371ae531,d36576b5,464b1fa6,6a3921d9,ade914f6,8802342d,93413c4f,8b67d343,d79252a6,d023f712,9e464e7,111e3044), -S(63ad2efc,c1e11521,139528c1,be3af253,ccbb4f8c,af95b00a,7a6467c4,d682f126,29b54282,c8718452,7ae954c0,1039c1f4,ac7953f0,5250b6be,47cc0b2f,69cbf28f), -S(448bd0fb,d7b22662,d6680a1d,57d81a21,a54256c9,d0a882d2,ed5c6f6a,e1e5cfb8,ce23a4b8,cbf12323,ccd55287,e5c68cf9,751ed0a9,1ad563fd,35688ee9,8c526d46), -S(ad41c647,5145c360,fbf6579,8a54ca90,7fbc9b70,a9323501,8ecc6a43,3ee564bb,c1830237,87a2872c,2884ebd1,f1ae7a1f,8e96ab7,99d1dcbe,eb39e68d,796a5659), -S(65b45a74,13b2e78d,20d1476f,c21ad4b3,2807b174,19eb89b3,fc799f92,7cae5a82,11aed89c,d5bfbc7a,9138885d,f64a38e4,d46a270b,ada85cc8,3a3ed7d7,65015331), -S(5e7db226,92f3d7f2,da0811a7,d0aa0d4f,6adb5651,3ac6a386,7c0cea91,ab212b01,d8250eaa,46275c9b,71f43f6e,cffb063,7b90a827,bc89f513,e769dc00,d5e28150), -S(37fb22a4,7feaec72,7db1d62e,390e7b8c,ed1d20e9,7f934137,1d5276bf,5c1110b0,9a537c0c,8da9c43a,6b7924e5,a6b29e9,17ae9e25,e8afa6fe,926ba053,f591c090), -S(4ec7c867,aff4fa7d,ade9777e,2d4a0793,fe1a1ecc,fa4765b5,aff9064d,98f16a50,433ec3e0,57138a6a,cf7ea45c,f2a91041,2e356c0c,751bb535,1856e37d,295143dd), -S(85b5685a,8e784360,dd1eb47a,9805165c,bf77dc81,56c93b68,54766ad3,87cfbcd5,b866861a,6da7efa1,fd3d5360,2b94daff,c0cbd09d,5707f3c2,b47d76e6,2f2037ec), -S(3a390af9,11caff4e,76bf870d,972465ee,f6f8da0d,c7232add,5ae9dd87,32be2269,f5052db7,7f43411f,ac6553c1,3d930945,a8833641,8af417e4,5033a8d1,a1a52c90), -S(44d40682,4608651c,4fb418ce,99391d55,6d93b631,d489f92e,fbbd56a9,c49736f2,1461465,fed84aa3,ebfc39b2,c1cbd1fd,b7472c43,5c9034e2,82d59c34,9dae7cd4), -S(9aa43d73,41ceef39,1b1bfb31,f620c39a,434e5235,2c14c28,8a50490b,9c62295,ad6272c5,19439e27,5a1c94c5,b3940b23,956d2656,d9870163,17e57d99,3d18b2), -S(1a5d114f,d0bda301,e76f3721,ff1e06ae,fb40cf85,b16c5dc8,a9bdce20,6ac8bb80,cd57ee40,1f4203f3,e1875926,199fab9d,9102a3fa,c851822b,a5bc489,6e1c7cc8), -S(711c1d24,299032bc,f2959c63,8139ae5b,b528b56f,e1a1b829,f7b8afbd,e2effc8c,98bdc11e,d2ec73b5,532332fc,478ab4ec,65626bdf,85287f8e,dbf1d8b0,5f163450), -S(3dc0955b,86e2d6d7,49bbc95f,2760978e,fda7483d,1f3b07c0,7d97ffb6,6961b0ed,f4af5628,d74d3fa1,daa5c072,9c1ad396,1b0792c1,b6fbd235,64debbf8,86d3051), -S(9cafea3,411e251a,8776e3b0,72f11229,8a23125a,5bd995a9,a4655031,9907df23,743b8ad7,ebcb4eb4,9469225a,7a2ee594,bd534c16,a8dd68d3,a58373ca,85f2b01c), -S(faddddfd,96d20fe,ec2b0c84,8ea7e6fb,f89dffa9,efadf475,6eedc815,b61a404c,ebc560c8,253927f5,a928584e,8e87b950,dfe26bd6,d37b739f,b0e9163d,c6312c8), -S(b539be0f,8ed02ba,f7787d73,df02e1bd,3210b88f,df1dfba7,a0138713,8a2d5a8d,e0271fef,2d0581fa,5ca30caa,8a101711,341d4221,b6b0a7ed,776ce399,e370561d), -S(5e3634d9,b7ff4279,3685022f,d3165c03,2ef8ed0b,c8a7d02b,685ab5ba,8557ac03,565b3913,355bb664,12225097,4e33e9ac,27cd38ed,a804824b,83985011,60f44200), -S(609ad796,d50d20e9,9cbe6ec,650eba26,ceee3c56,a6889917,44deafab,6a7a5904,54f9351d,9aa7d0db,822788be,bb1cc2eb,3300c144,1c7a4c01,230b47f3,7e67a9a8), -S(6ed020f1,fe8d7e4,73812756,3325e0c3,290b9a5e,d2723929,584f177d,4d9d429c,a1e48a25,b02ba024,eadde7e0,ea82c900,cb297d2e,b550c289,d664d4a4,b9b85edd), -S(5083663a,afe468d4,ec901e5a,14d2593c,b28c5948,1fdbca52,347d6aeb,4b7ce960,6aa5586,7467c6a5,dfc41278,c855727f,7a8b4168,98bdebd1,f9c6a918,a1d31aad), -S(e1c334c9,e355ae43,7e48335e,691a2aaa,64c3bf7a,16c77810,6bfff582,2a324df8,4603f15a,d7c85327,15502c35,cbe0ec58,e4ba8ac3,d038c4d3,ee3b4b77,74a13c07), -S(8c51fc03,ca1ed69b,4b627be3,3a7943fe,e1c15c47,ff7bc83,89961e40,6552907e,2a51ee78,7d48f8e2,53e82deb,a07083eb,b9513615,7f2a796b,c040b1d0,7582033), -S(4711e429,d9cd2b6,e539eb68,884d2a97,375c2cbf,fb30d6b4,1718eca8,9f3fa41c,ce826e2,711b6e6e,9a487a8,4ae72f80,a5308c21,1db0ecf5,706abe6,6b0565a1), -S(277440ea,ae6a1839,6f72ace2,c5cbc75a,41866c7c,c761bf3b,7bbcda07,ef5558a3,345f1584,9e4ef4b7,31964dbc,f9f899f1,def99279,ac2acbaf,3d1eeef1,bfd0685), -S(b9d1ebcb,91db7845,426accc3,578ec4d1,6df30fd2,9650b47,5c154d65,7a23bd5a,ea0ca814,399a76b9,5107501a,40ef0206,ddb1e9f,4933399e,35db6385,3dd2cb2e), -S(29c07ab6,e703dfe2,896985d,4d894d5e,5b793b6b,7ef2f5f6,dba00348,a8882fa3,7565e4e8,4b5485e1,661bb0ab,4b672cd2,5e9d58d6,48049ac6,8f2457e1,98b04a8f), -S(b9d17c46,9733963a,2f20626a,ef4f2184,6da791b,5e63194c,128432f5,58ccc682,5dcad0d8,7e08bfad,43e55633,3403f5b0,76482dae,d731e01e,3284c945,7c6eacee), -S(961e90a2,904e80f,1be65717,a0401722,6821876f,fecfa598,b216b04c,b4645c8e,5ab0efab,7112254f,722d021,a4da595c,99429a1a,5b242b1b,9243a8e2,54acd804), -S(40865cb6,f002104a,54a45d9d,da84e6a8,f98a3bd8,364275ba,4e14554e,2438f6f4,5b822fda,eb719e33,75309c75,b7c115af,351de484,98867a13,6b1fffb3,1e277d7b), -S(5efc3d76,307a2cbd,34e7d009,92263a44,c4e76e50,f1c213fe,b7fd6ed2,342f1a08,40bcc04b,cb227f3e,3cac4a7f,446bad6,6a304df5,a4128bd5,46f9f40d,a3e12f46), -S(13caf790,6a97e5ae,6f674956,c1586c67,57d3d56f,3d18d522,c4f365ed,97b54e87,156a85ca,74541ff2,9489b562,28324549,5cc42397,c54792e,2ba485b4,a86bb65b), -S(657e9dec,84a9120a,308a5235,6555c56d,6c1c98f1,cd946480,def7913,7e50f7fc,600ce754,7d74b757,c1e371c4,73401734,8fd6dbb3,72019f10,bcb4f4c0,bab1614b), -S(fec2b1d6,ab46c020,ed672687,7f2ec85c,214f36bf,149b2c1b,e75ae29c,54050071,3ec9964,20d9954e,edd8848b,c439fce5,740ddb41,c404c52b,f76865fb,26c48b8), -S(bafc595,37308fb3,c691f1e2,45908e92,776d76df,f6af7002,c581afff,320a4abd,2d8b8ef1,aab42751,27d0ba95,dedd27a0,29951664,e7ab9d54,b3a4a24c,faa3e386), -S(927cdbe3,2c1d78a1,89a4e3df,4ce6661f,149d7e16,d0cc7dbf,c287e492,891540c,e46911dd,cdcd70a9,f99f6892,18899fd,d3ff666,ae4533f6,dcfb441f,2b7da62d), -S(b443d061,1ea3a164,2e31195d,111bdb01,b6a3999b,e4377780,e19c3614,c0d7092c,e95b7ecb,e196c667,a19dbd2e,ff0115ff,9f0ce1a6,7f44d20a,a47d2990,e6b48c64), -S(e1836c7f,8b7dd235,f6af1b89,b7a13ad7,22dbad8a,78b1b37e,f6e5ff5,a6bc992a,57b02ceb,713319e6,9ebd7e6,844f374c,5871a792,e2109eae,d2cb5222,6c314e8d), -S(9f661b3b,c5829c51,2fc613a5,ad8aadb7,5c78edb9,9b84de7,683c6de9,d2a93f78,70e14e0e,558e94ac,aabb847d,3acde465,14c13177,45d45226,b6ca9911,f23ecd6d), -S(e835b453,6f13ae6e,7103137,bb695ed9,4d07507e,9fee8f9c,af661e9c,1525d3e4,192463e0,f1111a94,9f6236d3,1c0d6620,af9e0a3d,1f13f83e,7c4adaaa,76c81953), -S(a29fe97a,2ecbc4d4,f7156ae9,d6bfef6,ef601e26,4f92a115,48b5cd26,7cb26b3d,23b7d6a,15681341,6e1b8fb2,cebcbcb9,698d245f,b920f8eb,3d6b46d8,9cd25cbf), -S(396cf745,6127f3,31ca0fb4,95d98b32,7a738a69,260f7345,9eb79f0f,edc6a7b8,31b6ff3c,26879dde,6ebc9873,22a32b10,e283a256,1c1a65d1,928d3e02,de2505f8), -S(d1bd75ac,c37a3119,8f768b38,f665039,7d2f331a,32018a66,526058bc,aab440c5,5c17fcc5,b8e2500a,4edc3cef,ced52f2d,e20e7c41,bce4fead,8e12a880,aab8a185), -S(de72076,62274020,1791b51b,39fdf2e,297b7c2d,d358ac3c,375dae4a,494df54,d33d439,d4508520,6021c95b,cb1b22ba,b1595800,54056f86,82d73580,c50692e5), -S(958e9c41,4b096f8b,2d1ba41e,f5142a17,339cf57d,689d7d13,dcc22355,91418331,628b63d1,4e4cb154,a31d9752,9e50a1dc,f2684b40,47c27c39,bd54a0ff,dca06ed7), -S(38bae438,9a283e43,283d6a06,94e7ba16,b026dd59,3b505a09,6ee0f67f,eaaff536,9fb69e6c,73b27204,30968157,d5782423,cd4b7809,f09f280,93f5964e,6c06b170), -S(d620240,753af5bf,f1719165,f9d8116d,54c97a2b,5f99b7a8,97eea7c0,428dd1b5,66cd4f98,1b037f95,eeca433d,71d37fb8,b4a53f9e,853943a,ee0f5254,e42d89ec), -S(7de22847,c93ed32,6ff056f6,a002a7d7,e5d13361,e2580ef,d2cb682f,28e6ab96,c40be4d2,1273633a,e0ea9448,4bbf29e4,2b9bd775,b77802fd,31167d50,76a9b34e), -S(df0b50b6,679ed759,35883080,ac9196e9,ba5844b6,d9e541e2,bedb7693,c7af37c3,f09fe7aa,bb08fa37,aa5413f5,e17dc1e2,a07f83e7,4aaf160d,ad3ead56,1509e152), -S(578581fc,184af60f,80d648a6,97ab999d,f5ddec3e,b6046528,b9fc6233,7de81fc3,552be39,a8587bfb,d8de2f2f,6b923fde,20c7ee70,3a1c0c09,12ae85b7,56495ed4), -S(cca6a75a,131b5389,b2f8ae71,7d1a9f5,2258d3f0,4ed22b2,c836f7ce,3035def8,1787070,1bff0d8c,b74f5f95,1c6e011,f4e682f2,5d744f98,4c351b64,59669a4e), -S(6f81f602,b2054706,4a7c7b12,d5f13022,8657a77,e0bd1669,ed1541a4,b8eaf068,6ff959d0,1288bbb3,eb7a59b3,2eaa8945,8e4c6754,2a9bba0,668bf14a,ebb308ee), -S(90725203,94d2fb81,59e2ce17,5fb27da,7239f36f,61c70250,78a69c12,27fc0cd0,34a471f6,eb168b59,4a6a53ab,b93bad33,7da670e1,8bdd1eda,53b34849,94c21abf), -S(4e952fb8,b5e484b6,4ce1c1,c66e94de,3bb3a64f,26585c03,969e834b,291e597b,f7910643,47cbaa3a,e88dd796,ddac4794,c6500c76,147a26f9,c8f596b5,50da9961), -S(1985193,527e87ab,5b7dd218,718486f,1ed4b7f1,a444ee6f,21f273cb,901aa0f3,b067191e,df69ed50,b0771d24,2d99c8c7,22f1bfcc,bef31bb2,8d245f3f,b0acd3e5), -S(5dae1881,7a2bbb01,23561907,a22445,78e4dfa3,c6373f21,efe3f159,58abb5f8,7c6bd578,301ea8ab,f2b555c,66420c77,b84c6959,f96938af,eff54db5,4014d51a), -S(96a46ff6,e78bb2f0,4b299985,6d56310b,4df9702d,7306b30d,cdc7ca4e,68114e77,3f871bf5,d3a4ee91,17653bb8,5a98e599,d86ae580,17e8963b,9b18400c,979994d9), -S(31482d19,6ce07585,bc1268cc,a355df50,b9009f17,fa1e4f39,9876fe2b,51eb361d,50dfcba3,ce43896,1fc51f06,5ac4e58a,4757e75f,419a9525,5263830f,fb936e9d), -S(94c128e9,6d36f7f9,540da468,a2fd488c,ad615f6f,7920b201,27311941,db6e2405,595f29f0,f9622e32,b62e3ead,9f9ac21e,d07d7c07,7bba623,6c7e57cb,747da989), -S(a16882ec,b52def37,227e2990,3dc15e4,d4bf10ca,1b1adf31,c9cace43,348182bc,53f6d3d,6dd5603c,2f2bc7ab,677a6133,c138e26e,c030ee9e,705ce002,62e11f5c), -S(f0f5ef2f,f0f63cc6,fb7b3d99,6a5b14df,99a53a45,3a1fa425,3ff3ce71,4168cbe0,598b5ce,44e168c3,bef06c4b,c032924a,da454c75,b53d17cf,cdc2ea7d,93e3b883), -S(3aceda5f,190d83bf,f5111acc,d57d4d2c,5b7692bc,62f480b9,f5cd539a,b2ef0c1a,5b8f973a,16151dee,92930702,f3bc7f1b,93a096a5,ca4ff3e4,8a41bdcb,f78ba60c), -S(4e1eb580,b3e3bcd4,4b2905a0,d07d7334,befcca94,c7cbf639,1710948,cf2e66b3,c1d6ad62,c10bec2c,127446d5,34863682,196ce8f,4a966319,2be7764a,46e733d8), -S(322fa340,76bee9e1,697206c8,38cdbbd3,d54c3a30,82c22b3f,1ae17da9,a9047856,c4493e49,b5cb97d,eab7ccae,8f1547c5,98e286b,5e7301de,cd50656f,25dfc1ca), -S(4aaf3569,2b080f70,aafe6374,f0007570,d23fb620,cbb60a43,305f5e3f,29e9d189,1dc30c11,91f985c3,39bc8592,8390bc0a,c99d3efa,98f4bfd7,df2f86cf,7c297dca), -S(c18629a7,17d1b01e,e2f4bc72,2c86fc26,878884d9,a770b62e,d7167f83,631ff2b6,3438211e,bd80ab41,dcd4e76e,c742aa3c,1c859cb9,1fe0960f,eb0dc74e,d119a7e6), -S(239f97ee,44d77679,7a91a196,82c9064d,4552b4a5,33033377,6dd74ae2,fdef44db,dbf917e,c66d0b04,a0bd607d,6448a678,1821933d,26d51865,35d3d587,ea680a96), -S(c0fde604,387fa85e,5c5cba98,346042db,83a64e6f,103d7448,22b6298c,98bc7100,28ad14a8,30b7be30,58ce8e09,7fdbc87e,a3c60b3e,840ad9fa,a7cad01d,b83a15ac), -S(95ec759a,5526cd4e,eb9d00c6,9702dd89,3ae115fa,de3629c6,5fcf5134,2f389355,2f899643,711c5f72,8fb442aa,59139fa3,b1b0b4a8,ce75ba07,67aa958,eca943b1), -S(7da3bc4e,867885e8,febb8c6a,e5da50e4,55fa749c,adbc5800,1b70ebc6,96ee9b89,dd989b8,c4bc42e5,8b41fcac,bc1e1f17,bb77aefb,964bfe45,fbae0843,6dec8cc2), -S(120fc1d6,12db86b9,f352582c,e2761ad9,8a29444c,c438e2f3,5f523d83,e2bc3d,437828d4,5357a2cb,ffad57f,f991e91e,83466aef,584dd7b,a3b24d9,31eb6cb2), -S(50e42888,366a1fe2,83cb22d3,df324d3e,e52f58bd,26bdd4c9,67575f7a,5adc380b,2fdd99e8,427f9b30,1e132beb,3e0fbb43,8e6ffa8b,147c825b,e4453fbc,1318e015), -S(275dbcf6,ab238c94,740100b4,29356528,69de76a,9d84d7b4,9b88d526,9b8d5339,90e835b0,f20a7177,936c5717,fc18d0a0,28a31e65,53c32be2,699ae03f,6ef2807d), -S(59d174a2,bb918007,f3e044b2,7acf5e6,8264d529,cae342e3,fed00475,d95b86c8,dabbd87c,b49bd118,a663a848,2f7b1c51,9fcb0fcb,48f2f966,7a13ab2c,ab122860), -S(f8926a6d,5d824029,8f572847,6439f60f,528cded2,2849f182,e173f84c,cb75e1fc,8c641986,c4fb6a7,acea7627,e4f6872,26f86de0,a2160a63,1b2e1a26,9fa5f6b6), -S(d765faa2,b9cdc6c1,d9f070f5,4fe286c0,60351c66,c7a241bc,94d10e4c,7287e7ae,ff732ad8,fa7f0c3a,9ced3ffc,f5bec9e5,2d1600eb,4ce4d781,20481559,82c30ec4), -S(bc83f94c,7be686df,9caff340,35c6e393,1fc2a33d,7a09fe0,b5d09e64,a0610dc5,772d167,e762b3bc,df68c291,656a4259,cda67486,e430c7f5,492c66b4,b3e61fb1), -S(5a8b0422,21313e22,c5a2cb24,ec6199fc,a4e95da4,d5f59629,ca33f4e1,419d5626,2f609bb8,966ba692,84fb6854,5dff5b2d,f1463504,5bbfb145,4fbf40df,c9884fd8), -S(b106e89c,b4da505b,912da09c,44f42d11,a2de8836,28623cf5,7f27742c,a3852a97,90ed9bae,78ce94c5,5e4e971e,16013f9e,6902838a,f7f851fd,100c8e64,babdaba8), -S(c55445eb,439db24f,deaeb4a3,5a71ac1c,8915b051,350d4007,15cb9d70,2319b0da,98b517e0,32c9a963,f22e25d6,f3306f91,a4b604b9,6591729e,64b73794,55d0137c), -S(f05845b4,5f975462,e1051499,d8189cba,89bbd435,6ca3ba68,7b9994e,81dfefac,11511fa6,126f8d88,14c5de2b,dc92bd79,9a466940,3ec8a5f6,f445c59d,bcf779d7), -S(35620920,f58bace8,7dc7f750,876b59bd,980ad703,b3127c3,ba53c20d,56fb5755,759d3f68,60643a2f,d6c946ba,5bb70f61,fba28208,77dc47fa,a4d9ae14,9d6ac9ee), -S(f70c93ab,7145bcdc,2ba3a9c7,f423da0,26a39180,6dc3686c,fe32408a,f659f918,84f71fc6,818151bd,c620e79f,a2d380e0,eb37391a,4a56b919,eb14b2b,cabee697), -S(858916af,74216be7,beb2dc10,47f941b5,157d7f19,c9b60900,bc844703,79b4bd3f,77b78d3f,5fc4e872,3b7cec8d,8653ea2f,298a1057,88bb4cbc,18e4fc99,108620c), -S(4b690a4d,a3649304,96fbeef6,da701b8e,569e61c1,6456659e,4c229813,d7118d67,d64261b4,4f26a263,55e787f8,fe2fd5fa,55f44b29,5cfa9c2d,8cc90830,60ef8b69), -S(37542949,6cf4e6eb,36b733d4,ecf1533d,4ef38ed0,768ff1a5,58dd210,ef8d950,3fac2cbc,a4280d61,1e30efcd,cccd1392,374d351,ed9dc460,61041741,2d0efb97), -S(870a9ee9,e2a00f61,af0d1f0f,967971ad,c5afef39,b52a3d5b,de74802b,a39cec0,a4751ec2,989ad16f,460f3071,ebe3865f,3319bbee,7bc7c285,e8215ca7,831a81c0), -S(28c63e6e,99936241,73c0c5e5,7c74543f,dcbbb678,bc786746,809d3206,3c0bb3f3,f0c610d2,e268cc32,3dd39ec5,51723b9d,22cbb5f2,f59171b,14771bf3,a4ec7183), -S(1045176,321bf271,cf34eab,686d3ec1,26000d6c,b1e66d55,860cde39,e5b00885,2cdaf0,11879aa,10231e46,ac93baf1,7bc92067,24f97521,7e2fbde5,cd7dda17), -S(9872ed48,bfef1218,35ff27d9,168740f8,38c2628e,15dc1a17,d5c72ee8,df21aa5d,f744a757,b922361a,3976de72,7ed83300,885cfd50,5f6be5ee,2ef9bd5a,1823640), -S(12f16ba8,5a2833f7,1af7244a,36228deb,38075fe,222f4d6d,6c02744f,b5731a9d,5538557c,f3d2b832,77db6634,8119a3f2,9e272b9b,bad3dce8,df38c3f8,33dc9095), -S(96489f8b,407618ec,698cf6bb,1366664d,7f14cde2,3d3417d2,80f0a3e7,cec87c23,4e78ceda,5f034e7,8eeee63,bf263fd2,35b8d60e,93263fe2,fc2acc89,fabc7728), -S(5380517d,3a681527,cc2aa8ed,29075afe,9eb0660f,cd4d381e,803ca7fb,2bea7245,d37ef6e5,f3c824fa,75ef185a,22d6e6c8,d8ff865b,433388b1,a6e6cd7a,4bebcb1e), -S(2f33b34c,3b22eb72,5d27688f,96f94ed7,23c840f7,549063c1,386e447b,faaea56a,c86fc369,59426e76,8f005d41,5c7316be,bbf1bfb2,54add259,91ad2961,8e9f50aa), -S(cdcede30,e227f45,18d39336,204641e9,27a61c6f,801aa002,5f892be5,7b49e574,dc3b0562,5e5dc396,26c1ca3f,5f2fa1a4,dfc28dc0,18d6ca0a,b21966ba,5d1ece42), -S(a9642c56,2e284ef9,5cedc32c,94c55dc8,3768344,e7317ce7,730da1f3,c6ba501a,cb3bc00d,de25189c,b8894fa5,219eda80,934941a4,8dc8e140,9b0d467c,ffb1cd95), -S(32b67c85,f0f4219e,2ae8e63a,ac95b210,32674730,6a37317a,19a52235,73bb7641,d8bf9f41,e584dfc3,de237e70,79cc170e,96c2cc6d,62042157,ef60ee02,3d142213), -S(4d095001,ec45ad22,1c9cca7a,d588dbdf,91156878,688758ac,63514992,128e50f5,c66d7dd9,9206f339,e0b80e51,f6ee72d,619c77bc,4ef33b46,1c3b8617,7359fc62), -S(f51d320f,bd158ea2,71cdaf12,651e3eab,e7deff0b,434a8b06,b3b31f4d,f6d6547c,7233df17,a17de7d,3a87118,97006ca7,8c7cd5d4,7a86403e,24f050ef,dcf3bff4), -S(f0dfe901,237b4b5a,ba6deb8c,39c87cad,5bf4dd5f,6a5e55da,d7565ded,c4e50089,eab06c8d,6bc7801e,7aea2e6c,919db667,324f0377,ea58b070,2e87b10,7857130f), -S(2921d36c,4766c1f,775ec19,302f5690,3898a835,aa8dadad,6c8202ae,270e38bb,a79c8e4f,cb59c784,3f81b66d,57060d2f,7c7acecb,c2399191,b7f98ae6,771cf849), -S(99ad0478,e840c3ef,470a47d9,ff66a197,b62881a1,6189d9ae,13d8bea9,3c1c0994,3e9fc2f7,d37d580c,a16eda71,ff6d1995,47f18ce3,515adca9,c08ed241,d1607f82), -S(970f064d,32c1eadb,b42ca1a,8893dbcb,dad1b9c6,3b99a15,e772407b,3aa1489a,efc34e6e,38e29927,9ee73b0c,9970cefa,f471f130,9518b8c4,81e7f67f,ffd807ae), -S(8d995e26,e9ebcc56,d2f9637a,df1db60a,e1b51d12,9850edb7,ef020a2,7ace35b7,1ed723ca,17892eb0,63ee5164,ee8e7216,96a3c3ad,67a3d8a5,a0d87803,37c01176), -S(c650e8c8,f995291a,a1feb490,dd9ae957,7506f591,c308b423,6ca005d3,ced75866,505e36d9,2ab967e0,a1168424,60639c72,646b0569,d3651800,316126d8,810a9444), -S(aba9f9d5,ae231382,b3583971,c875f4fe,4c51007f,6d55e1da,79d7e369,c21964fc,e6a176c8,34fc11b1,6f270f69,f4f54f1a,fab4729a,20cf6348,9cdbd551,ae5d1fb5), -S(1068b9a4,19f849a1,5dcef7d3,9b3b55dc,2eefe04f,554f283,212b489b,79b79d69,20993e51,4344e2b7,28188465,340b28c6,5331a7f1,a6aeb6c9,7f09e9ee,701f3828), -S(598358f1,cd3aafb1,9328dbad,62b65232,4aacc23c,87b37271,e8604caf,d69fc3e7,4297b258,6c94df83,6fe6c528,fd1b8fd9,62969227,d854e09c,375f85ea,58cd78f), -S(d4a638b0,1ffac322,48dc1844,75e3d06b,3b6b9a4e,971c7153,da49fe20,f44853dc,e9e708a6,5bd3b39b,15ca6606,512933e7,97b4adba,e72cee79,c79605ed,cf601d6f), -S(38421e4e,fc54951,1560c7d0,dd947c84,652530e0,d5155ece,8795936b,83b5e115,cbd0d873,ef6c0d90,9890b820,e8c063a2,35d2071a,97cf73f5,74ef2ddf,83ddf168), -S(2cbc4bab,442eae5e,aca1cccb,4a589c6a,8822138d,c3a35885,132dbc52,7648712,174b4deb,3b28ddef,426aa586,314b7b62,4e9253c0,1fc2dd7,ee94ae0c,57d3f5a8), -S(202d232b,4244ee54,3fb77958,32c149ff,8ee9a4bd,86c02037,634f5254,9f2dedec,67d64143,1915831,bef7e85e,f057ad07,a6de2cd4,3578ba0,eeb5cc70,1d16a499), -S(4faee6e9,90601af2,3f204f8a,615506a,82288490,a14f692b,86c8585a,52b4c94d,b45c0547,98d18942,7349a87f,5abfe689,68d14f82,d5ea836f,131ad030,ad31c8a6), -S(976db42d,c73a4705,fd782bb,2a87f260,19f6d218,3da3ef97,e0e19304,87ef7b42,2e543c4c,721512f0,81c7a6ef,987776cb,11318c52,ae6e2883,7d52a160,d183c31d), -S(9dbbc369,218c5741,36a0dc48,a17055ba,2a8b1580,88932e85,9a0b8188,5cd11309,e93dccf8,4dfa1519,45f6f38,d634a21a,b431f21e,ed8fd004,e27ea99,4c9d648), -S(660a226e,48ce5825,14c0f49c,d27621b8,f52657b4,17b8c1a0,ac9ecd0b,b9e0cc16,6d2c4b6f,74432c0b,ca351ebc,27a72b6f,68ad7a1a,8c509d8,8308be90,d7f7454f), -S(2ccc9a2,5c61d492,5293f4da,cfcbd818,11bdc998,7aa58258,f161210,40773237,5abce831,b2b09a34,4d93a77f,b8bbe8e7,d6334cd3,be3fc86c,154c74be,c191e9a5), -S(dd9d0f81,6c41936c,fc90cf9,3cc8f14d,8494f853,2b3b72d5,95d94742,8a01a4b,f30ca0ba,3db463a8,2b82b1fe,3f310936,c58906e5,ca07e4bf,9f4482b8,360ce7ba), -S(1314cac1,d751b3bb,c867e592,9df56ff6,99f810dd,f76ea0d6,f68a3e7b,4d95051d,8d3631cb,226a854f,143c1d09,89dd1ce4,7d943432,43060f78,ed3af3e4,f0d8d41d), -S(b1abd6ee,fff64a72,83c26a60,be0d1cc,f5152df6,b85655d0,9495d405,f2ccffd1,549457e9,b4f2edec,63f81471,12957918,baf8deaf,7d8a4b1f,489c24a9,44f210fb), -S(5d8e23e,1212800b,56e7740a,2f20c402,6483ce0f,755e36bf,fc4ee667,3df1b32f,973cab61,da46c5a8,6d1633ee,1fa28892,6e1d814b,800762b4,e4599ec1,803c0af5), -S(ae0bfb9,b5567b95,34510cc4,ad8dde2c,50c1dc53,6c9ce5e9,ee97fc70,f8b4f562,a8d15459,7fa1a816,3eb33c40,6b78ff19,b4927a3a,fe48a8a8,1492884,46ced08f), -S(b2ed6275,b818b2d5,ccb807c5,262d5578,c83743b3,701217c1,8188ec52,bec10325,5281815a,b21491d1,62e0b3d5,1334fbca,54731fff,f5d44ac0,396f477e,ab566896), -S(5d5c034d,228aeed2,270dec13,deb5418,3205a996,509211a6,8884c2dc,42d7d7e2,316c32ad,36906509,2e0112ef,eef93269,e251f83a,9ea7781f,ad59122,ae2ad4b7), -S(3d94f70b,39605f40,23107882,b491cda5,6f1b9ffb,3fcc47,51e4309c,812c428e,b3de1921,d29a77fb,ae8c6460,c3ecf92,22b88c4c,3a96cacb,e4385416,7898d7b1), -S(5c0dc575,84732fe0,5098de0d,45926c0b,3f8075d9,2ece92eb,f910263f,3e0d6df0,34c7fbd3,171b85d6,65bdd9ae,30f671f6,688a55bc,cd68c0e5,1153348a,16b75a88), -S(15d25179,6b55cc34,5beb9bbb,f6ad1aa1,b11b60b7,5bcd80a3,2a44c180,879e3513,46632865,ce1e74e5,f3a89a58,35adfb01,eec8e0f0,34b84aad,a0d2d901,ee07fa81), -S(86e5faf9,dc091174,bad52eac,2c83f945,3bfd9f82,13505e10,323255ab,b9e8d0f5,3bf19876,8c8b5f39,ba25a9ff,5d112600,956072e2,7775af11,52bec5c9,7b2396ea), -S(308c0956,4ee3aa0f,792e8630,3ede1407,d3d3da3f,423408e8,7b0c5aa1,2d6aef57,7c39d220,975a21d6,5ce1e2ea,930bd585,203d9b45,bf5f2eba,ecc5b245,e95f0abb), -S(19f9d4ac,c7de487b,cccae45b,2515f727,196911db,d799c7f2,a68078b3,181099c6,645522a8,adeb841a,81e27714,ddc40585,81cb8b24,e7d9620f,c940590b,b14f14a4), -S(a05d82c2,4493370b,cb7f1639,16865c71,3e89d968,8c96919,ab99ad92,afe96a35,1576f727,6c65e32c,1dc1ad98,2f75749b,75589cd1,43ad60b6,2163a8e9,87cb35), -S(6453661d,303acf74,751bc7ae,e8226647,b17b5808,f3f8dd63,4c00a78,94e830b1,145993d6,ab6592bc,b6b242d4,432be395,de7d0014,479aba5c,88a48cf6,adaea7ab), -S(adb18972,9de87486,3207f954,4e3eeafe,fa255209,4a8c0170,44a952be,aac0485b,2c67657f,d6a2b08e,28463e9d,abf708f2,2c790aaf,907af16e,598f325d,f657211f), -S(8a6ea198,371f94e9,288943c0,5e387cbb,b2071935,3562fdd8,f9fbe899,ac31ce00,d5b817e2,4f5b3fb,e25212a1,fccb6e1f,1ba55211,ff2e0123,c71175b7,bb94597b), -S(9e18eaa9,621ea829,38505584,a5879eff,446303ce,9cf61bbc,eaa6c495,7f259778,3310042f,54b5ae46,1c996f45,abf27c3b,5df06779,3c931927,4689da07,46254968), -S(27ec08,dbc47af0,d3db2aa1,a3b4b22f,5cb42750,b4ad6680,9815ef21,ac44a8bd,292fd5ba,9371d8e8,d4126197,18bfb564,2ed1f537,3303754b,af6a77bd,271d660d), -S(4ab3436e,34fbe37a,aea7dfb3,70d93352,ff4a7c22,53f1ff2c,8453c5e8,cadec2c2,90221aff,faacaed6,760b1c91,50eb695c,a1117054,1ee068f3,8c684e6f,b005b406), -S(46d75d8e,b2b5ccda,2d6819f2,1338b125,61a9c872,1d8956d5,b9c73148,4d928895,8153db74,27f7c4e3,381567c6,e2629702,8db4a5ac,c8762ec8,181a5da9,b531b6aa), -S(469ff047,7ddcf32b,a0c71766,474b5730,3b687406,c22e51b8,9f5fcedb,d154e270,acf0fde8,b426233b,20ffe9d5,5d1bea51,5a19a9ca,dc642a02,6928c05a,e068f747), -S(1d0a4e9a,ff31f94a,456c974b,ccd5169d,594b7263,5e817f29,4ac1cc45,52d3c6d5,52d567e8,1316fa28,1c2dbe62,75e51bf1,32f2a573,77e0825d,eb024a1,8e637683), -S(d1f25e6f,5038f784,84ffb8cc,7b5b67ce,908b3050,371ac332,228c3f79,577e6e3f,6cc0b7b2,76a948ec,54b79662,6fe435f1,5c68abdc,9fdcf8ad,41485a7c,58291f77), -S(56e97220,8d42989e,2a0313ce,203dd87,e8bdd09e,38bcd097,6e3d047d,7b8eb385,c78f2ca5,93d563d9,6caf585b,25873cba,3f4d1f31,3e31fa32,df2e9e0b,7538cfa6), -S(61f040fc,eb4db17c,7675ce64,73721c47,785e30f2,217f03c2,5e1fd723,d40644a1,950c39d5,1994a902,e637cbba,e0afa218,50e5b191,ef5b5939,3257d67e,555a1d3e), -S(ceb5f3a4,e47483e0,a6137f38,1ea23678,81c3df5b,830f80f3,1a08a3e5,e5181f0d,6a31aeaa,7533fba6,7e79f63c,abeef7e4,f130f37e,1922f17f,af20a63b,51a1c485), -S(d9b195a2,dfb91ba5,814e54f0,3bce3f30,6b7f880f,594e8dff,684cdf8a,bcf63634,130e6034,3fba9959,898d4227,a8b4e79a,5a4055e1,a22cffa9,8b445c6,4684233)}, -{S(5e8cc841,c1b251c5,317faaa,89f6c9b2,107e793,4abe27d,adca6318,38a9ca72,9c1c881e,10e9f194,e00388e1,e2414f5,74946554,d2656ceb,392dd6c3,611eb982), -S(498fb0a5,c2a2a7fa,2e89a846,d7987897,b3e843f,8d664911,277c85cf,3ad0c128,c480af90,6f0aa1dc,8330d211,aa409649,3da0257c,8d09d5d,8b1aee13,f7e6f26d), -S(9060ce66,41a763c4,8d0948b7,670c1d71,1ac2a81a,431b979c,946eb25e,3c8ff8f2,567b9831,a2555c20,6dfc4c41,9ea75b99,d02a00fd,f3942ea7,e27c44c5,98df4d7a), -S(b528d336,1c7c3cd5,5480aba,4421c209,cdc234b,f948593f,98eb3c2,95a18396,1326dec0,490078f5,7c541200,9f131410,9fff1f92,eea82577,2fcb8834,c59f0c33), -S(5b0e61ef,8c9ca491,83508642,8cef89f6,75f49ee0,f33fc8a8,5783e6fc,3b4c59b7,bf1f0c2a,ebc45330,1d12e8f3,43b4d3fd,df0e40df,b78cf093,bff413da,923f913f), -S(22e892c2,258575c6,e6ba67f4,e0e36853,27771a2,28ff9ecf,a2efb43f,c9f1c7d9,2b20a268,bfc51047,a8b28952,795b91de,624a3487,9abe535,3cfd3a11,87a86493), -S(70bc895a,ad0c993c,25155e97,9d9276f4,8227b6b6,d7a31bb4,b64a969,8102e886,7c0be1e8,f268015e,987392b5,15f60d04,d1453e7f,fd5929b5,2176e24d,ac10da80), -S(1dd63c17,421bf994,3a85019f,777bd41c,fbea006d,d4e0b80,2effda5a,8591b87a,2fd392ce,2e25e393,9bad93d5,616c65d9,87718cd5,9b8cfe4d,e54473fa,49c86735), -S(7d3658a6,df58d88c,7ea92964,3dad19ce,12f295e7,b8b4e710,9b9297f8,ea83a088,6ce3e119,496fe842,f7e2fa75,b635c11b,bb4d00c3,843216bc,82c31cf6,46d9f715), -S(aa02cb68,5acd4d74,f2c547e9,43aa7360,6a960d80,72aac984,b44bb492,e61b1d94,1db77713,702ed407,655dc5df,55ae0329,a30aca7b,d5655ebd,91dec954,feb0e02c), -S(e015e1f2,10b7eefd,775369b7,64192078,edaf3118,9d7a5382,28a744e5,5ee7f068,dd69db3b,a82ab3a3,86e1f09,a6c3b8b1,37b48021,a560c0c0,a8c910c1,e315b721), -S(ec50fee6,402b79de,afec1f9e,25778b95,5b36273a,6974963e,3cddb748,1166bd4b,21b5136d,2a71804c,6c90a89a,70bc05f6,afa26558,ca1aab74,610cda3f,7adf0f03), -S(213d69ae,6ea3a73d,3566a2d0,10f6c42e,d0c3b60c,9f104706,153b48da,2b155415,198a8c8e,ab3c11e0,2b0d69ae,7ec09ff3,e69ebe21,8a849655,14c46aac,786954e), -S(5ace25ab,eeca3eef,3439dc5d,7313a07e,7cc94c45,5332d38f,5fd367a3,cc88b2a3,2ddb1c5a,168ebf76,6080304b,df44e644,d5b34ef2,3ac49fa6,3b19390,83fea9b), -S(fd0ab7dd,a0907d2d,7349f860,4cb4794d,db9d0a2,dab0e6e8,7fdd90e6,49a3ce19,6ab30bc8,fd9fa11c,835509f1,c4e9b0a2,faba9de0,4f2b8ba5,e3ca666e,cd1aed56), -S(a8af0736,a5e408ec,84b46f55,16e04fa3,bed5f733,f8b99e90,192bf2ec,ae1fbd4,aea37eb2,6f9b6ee7,90eac699,92a53732,91a68317,efd3e651,f27636a,878a531), -S(a4effed2,dd088a36,ad6902ba,db705a35,187f721,20e747b0,2011839d,76d68be5,5efc6581,210022b7,fd8d3dd3,f11c95ba,99a28e44,c316c8af,7510816c,256848a0), -S(290bfa2c,8971750f,90aa6762,aa1b2b9f,e9eb50b9,cff25ada,4a7239ae,3524a799,1e16aeb,1fe3c65b,395a06e6,49545ee1,95f0a6ae,9954f6f0,dfc1f528,ef7d0759), -S(25496b16,b62fbf6c,3e9c59b,de7df4f,6216256e,3b968588,e184bd6e,b9543eaf,6964be4f,d9fc2dbd,146774fb,1eb37f0f,a13a11e2,35b1c870,fde75c,ecf750d6), -S(8585f972,5efd5404,fbd73e8f,c78a4e10,8089f024,f6ddd66b,28d56031,b98f970e,4e61cd98,c9ed1efa,6dd112c,ca27383f,1614b0f4,728ce990,9251309d,13c2777b), -S(b4fabb0e,52f273b,9e5e245f,82a151a9,296d93ea,d690378a,2653eb7c,a68020a8,5a0d976f,2d34b780,34ccadd9,30371689,f1e3c5a,6ce774a0,db9da3e7,aaed0542), -S(4c902996,a5a7ddde,3bc42bf3,31fb1cb3,61ec471c,6b9d8e9c,249d9e74,693c9e8e,3d118fb8,4e8061f6,3c8c5f09,f60298ef,c7983887,d1522034,8c9aef13,9759347d), -S(8a1fb43e,3591b453,ea7353ed,f3414793,2cb2e5e4,33aa01cb,cde2a865,27954691,40982292,e5b49878,b7471564,a84606f3,6e128d08,3d542e57,ab04acfc,dc1f122b), -S(f93d9de4,43d93908,8529abc2,d27efc02,682e96f5,79133ea2,e65c44dd,4cf5e6bf,15c9e50,696af51b,64e3b7f0,19b3e27f,7dac74bb,d72a0007,18c4c3ed,10db4873), -S(8755c259,f333b12b,88917775,cd5c2536,431e77df,f80a59da,d2dd7a1a,a56c930a,d2d681f5,d6259780,8d5c4a4b,9169d9c4,181edf5a,cbf4b817,d27b4e2a,3adbe697), -S(30f44aa7,9d8a39da,3abc6085,b6d5f33d,bd96f266,e6f37382,c20e749b,efced3f0,8acdbec8,2461ef14,f4096274,cb08f3cf,149e0041,7c075595,ab24fe9c,5ec15b96), -S(691a190,7e98a004,98af8c72,3850acf,81f07e76,b70afd62,96174058,84bf4a26,df902e4d,3e7294dd,66952c08,4e562954,2e6cf93e,94cc0d9c,672d097b,38844483), -S(998d8727,55f5c048,1d738583,e3a80de7,c6abac0,249f01a4,1b890d98,2ce74471,cf9b4563,67eeb428,865a1416,ce7b7f60,ae953bab,ba7a67a8,15ca6a5a,bb4b7567), -S(21f95845,8adf4ff6,d500e082,56454d33,7893cda0,e02ee161,7368a2ff,1aa66dc5,d88c985c,3c40ad,219ad336,ced08e32,f328a0fa,f4cb8ea1,9cd17762,7b4b257f), -S(107b438f,8273931d,d14d9b3c,dc5a102d,41f24887,9342d3b4,539a9d76,a04cb362,a41365b1,4d0857fd,da9d15b3,76dee746,55d259ae,91b3e97,c61bb70b,4d0c3a87), -S(b8f40c64,3d17a3a5,5329f710,5a8c799,66ac1466,30d64264,1262824c,b276c705,81d88197,c24f85c4,88c96401,4a34bed,17067ad0,d640ecc6,8482a3df,b374647), -S(33ff357a,ebfbf690,b97644d5,af3b5766,7e564c25,5685458d,1d0dca97,f28b9cb9,59de095e,dbb83b14,1610f1d6,289c21d1,811e875b,dcaeeec9,40c6bd8,4ebed43d), -S(6f2c27e8,46c1b5e,b02c57e0,2f8b78bd,af6a6489,858ec5e8,e60c7e84,c92f8a42,a20f6853,3e180ab0,bab00ac1,d517c66b,9f81088f,f2ad751b,63fec4df,d2beb5e6), -S(510f00da,f51cbe28,7bb0eae,59abcca,f3dfd507,976b92a4,558de2bc,91761621,f268b1e0,549117a1,b2123754,ca50589f,283db3d3,95c1e081,bbe9d027,ac3a8561), -S(fcd2aa5e,5c3fd7ca,a1c9dddd,30feb5b5,c3abab65,924c1865,913ffa5e,5658d2d5,662318b7,2cc9a9e3,5fb122b1,d74cfd8d,55eeca4b,a0d6f998,aa9dd09,266bfb3f), -S(9292c47,e36ad0d9,957a90d2,8fc00580,745a52ab,f14f3d61,c9c02163,e43c41b8,80ea3a5c,16f68cb2,67837544,289d1ea4,48056da5,51b56bc3,e243d45f,51b770c), -S(30a07a32,2d6deb75,7c3fdf92,db896b78,25b4043,87e7120,eed7cc56,3fc1886b,b07239e3,68803d55,96f843ef,929529ce,96df7e47,36a2cb35,dbe30aeb,1ff5c3b), -S(4ace91fd,2db5f7c4,29e6fac3,ed7aaf6f,46217f3,e2a67ba4,74423f4f,5f2a47f8,18db8c0c,eacc55b9,fa98ad2e,da9634b9,c47aec7f,9cd8e89b,41913e20,ba2ad9cb), -S(63ed08cb,b10860a5,4b6c0428,8f345cf3,f6e0a48e,9935727d,9070bfe2,dc0ade69,f24eaabd,e3cb05e7,c74d3be6,d17bed4a,2d4257cb,e69b876b,c161f8c2,4b8ae792), -S(66e91d3d,e5f63aa4,8fd6d3d,9129f60a,c030cc88,a2ee10da,5c187832,ee309ac4,5d90f490,8f5f0269,cadec883,e4ac47d,7f0b8d2a,cdb979ba,78f1576e,7644aa74), -S(e6faaf1e,1b7eb6b,e1daa8a2,f7f3fad0,e0250e35,f59b4ad8,a80fb38,5c0ca6c,3ae02379,79d9c291,68a8f555,8469b4e0,98dba357,7ec85f01,8f4043b8,72e78ee3), -S(c1006c5f,f598f904,94edfaa6,2eab93eb,e11a44a8,5e3e1014,91218cb,13e7b497,b6d15bf4,28df9655,bf70336c,ff7b6d80,b7890d9c,82b0323f,20f45935,6635f4c3), -S(f9cf093a,f613d28c,695f146d,5790f6a6,379feb52,1a337d66,a5032f93,46a0c7a3,e017544d,56a9dba6,e9c248d7,9bdfca89,8b521ffe,b5e68a9a,26ad6f2e,46299bc5), -S(90d1d995,67f6afb,37806ce1,997c8917,e6ff7191,5b6bb4a5,cf1433b6,9ef433f1,44b0e285,e03ac5b9,5e4352e1,13775a20,66cdd3fd,fc4a90bb,9d39b6d5,a796864b), -S(5e48b3fb,eeeb724e,8442fb8d,1510770c,c0e879f,94ba1ae7,f67a853c,57a38996,20650a89,dc8e0869,5f6c2b16,d8620af6,b9de2333,e29ad5d5,56445f54,e4c19a56), -S(90ca5392,1fbc1d53,7402708b,82d3d4a9,366c39f2,4fe6bcea,8435b5c6,544a4090,ced1590c,b11bed19,8a14eec9,44f1a117,d51a26f6,df89f62d,d4c0ff2c,d38758e7), -S(7d4a162f,6d359758,9a9cc446,f111da83,4ac9540d,7dc3fde5,8fb8d3c0,fd63eb8a,445033ab,53a9ae3b,7ecd39fe,aff2b18e,8d308de8,dec4fd18,8243ec1a,caa5ce56), -S(3344eff3,c3a56453,f2d37f8,1970c94,5ee2bc68,b85f53cd,3f4baa3e,2784488c,4966989f,f6372f19,5eb32554,9642e3a0,954ffca3,b650fa01,a7246743,ffde881d), -S(dcaf9831,99beb377,18623330,197415fa,667848a7,634b4821,610bdd7e,453794af,44c24125,71252bc4,db15ade5,abe3813d,f8425f1c,8a1f3281,6d33077a,bff19bf1), -S(57fb24ce,887ef2fe,f02be42a,a09f6e24,1bcfc52f,a58c8bb7,fae08613,6431dbc8,c2044794,1200e77e,a1d18139,55f58a30,c9707f22,42529a16,c1bbab3f,dce4ca23), -S(bc4dc9f0,54afeea2,2bf06988,265d01c8,b3cd5d47,d745c75b,a234f6fd,9231b3b6,9dffd7a4,1627e744,a637017,eb54fc22,4d949bd4,1b1f868b,865765df,13508cb3), -S(299f90b3,ee45e1e4,3ee1dced,2b302caf,11094a75,9e1bb90f,6c751330,d13e1f6b,6bc5dffe,53dd7c39,51623cc6,a7f61314,7d1847e2,73d03369,836e39a1,e6da81b3), -S(5a239aed,c93efe47,3141523d,fea3af03,16aee518,8629e8c2,e279eff0,62b0717d,117ad8f4,ea8a387e,d9f01296,e00c5864,ac93a78d,1968ee4e,9c325402,63acc5c4), -S(609b6afd,77d8c8c4,3c14ea1b,e56dc2b6,beca0239,faa88f43,59f9e6e0,1ebb8839,a576ec45,1bb52bf,39e9981a,4079f3bc,8e417bda,36797411,5e95e384,74632481), -S(663283fc,3d0fcade,ef669583,180a8e1d,b297cdaf,672121b4,4c481533,1d06bc26,139c7dac,f30b9031,de97c069,76812e66,7cf59091,7f0ac6be,f606afd3,c4f30448), -S(eedf6685,d605ca2,e97b801,ebc72b5d,e135f782,df6c243f,140bf172,9b23f671,a6da00b7,3ac5edf,b83e8fc2,5d6603aa,72c2af47,62b7ba2a,4ad98aea,53c8f0a), -S(ed14e1a8,73f82d1f,4e211823,b0632e49,3ce198ff,ec6c19e2,b9467791,8164fad9,fda82b27,3517f8ac,2464cb9c,b0edf241,ef91ebc8,2bda29c6,de3f6602,736c97c1), -S(f7c21813,63a5efb5,9c57da8f,eaef4738,38b9d34,8d3b16c3,ac28bc0e,b11c773a,9bd65899,bc4d15f8,875ceaf5,936ae25e,b4e9f,ce5963a,dc6095ac,5b867c17), -S(d407ed6d,b840bfc0,75c392a1,bd446340,9fb8f35d,80d9d4ae,95ea7bda,bb35e1ed,9f2af608,93692dc8,11330ac,35e317a1,fa856984,cc635354,43846545,5a9953d2), -S(32d706e,fa5382d3,ceaf0543,8e77971a,19e0e491,275d0381,ed705326,86f52376,66f4e0e7,1529c73f,aaffd9ac,a6846e3d,e2e8386a,939d02b0,7f64baa7,1d6c0f04), -S(ebe33ee5,f6baef23,ebfda782,e9ef55a6,d1b94e84,b76e7784,6d2827a7,82484a2c,27137340,2fcf2cf2,8ed164cd,7fedb8cc,178dc3f1,f02be690,ecb64938,cd942487), -S(5359d4ad,617f0a27,70392201,a2a1dbc7,fc5479c7,93be1cce,23b905e3,2751dd8,cbffabdc,ce183e6a,acbb21ea,86cd4fd8,97dd22c2,582f49b0,9f51e846,db2e8b2a), -S(92f718f3,8d2c428d,cb9dcf3c,847375e8,7f53d165,45a89dfd,629516c7,e5efa5bd,ca140596,6d82382a,453a5a4a,98ac315c,4351a4d8,5518af2b,996a0b3c,55edb05b), -S(70ec6cac,37a78311,8394e3a7,5a0756c2,117b8eb2,bf330440,ff6cd5fd,854df5ea,a1c909da,7c0cb4d4,141334f4,2a819c39,30af0877,8b4ea63e,601e3356,5d0bd54d), -S(72a4c06d,21fc5b6e,978addb3,95c1da3d,7c6390f,98f0abf9,26770ea6,d33c24cf,e811ff7f,ccf7f961,3c16b50,f74ce397,ec1c3e4a,877dd71b,b15cda1,c3027159), -S(ca5a0a96,e40e0530,344b532c,be4fcc47,2d243192,4c19019c,c602a6a4,45148259,b3274b9e,f30bc965,eb518686,3bdea539,130657,8199d2b0,4c56558c,a1bc19a2), -S(50e52b93,574a12e5,1f8c562c,2d335c54,4aa6edd,b3a83c4f,95ae5509,80b76261,dc5c4d8e,ac4d34c2,71af7d5b,abd714b5,194441d,72fefa4e,d1b4ac42,6e44d477), -S(e5ca0666,86f060f7,7c1d869a,94f02407,962cb101,1bdbb6cd,dad786fa,15761a6e,4ee18b3,7b15138b,61618a3,a7632c68,4f31cea,4d0c59f8,a6ce82a5,2c5480fb), -S(73560753,377906d5,9ac8c104,57742dc6,2d37b454,658d90ff,a4cfcbe8,f0e311d2,35ece58c,a5c7e200,47f80080,28fcacd8,2c8254fd,99fb392,f8e3b96e,31f40e4b), -S(a419a2e1,362adc6a,6fa18354,dcdd0cdb,37a4f8f9,bd1347b6,8763276f,b7acea19,c10fd807,3afc6f05,a2775e52,5d880417,f1c684e8,6dae0e35,9e600cf,9a6fd02f), -S(64a26b02,59fdc9f8,86ce26ac,cd826316,95eaaa3e,d95f9504,93c00505,ab149aa2,b03fca02,6b90848,965de8c4,6adadb8a,ff41f633,6c4af3b8,2a064880,f455b07b), -S(a8db77bb,4528572b,1630adce,107c8cd2,a296783a,acfbd84b,8cce742b,2c519e56,fa81ec4,7565b607,39dc4769,39624240,725afb64,df8ad9e2,70291dc6,acd1b19c), -S(95d43497,c9e2f1ae,4ecf2a6e,7839ed5f,135ca565,909fae2a,9590ffd4,2137e772,7977da8c,7d6d8880,d5c6a7ac,56b1ab4a,12d101f4,a26bc594,3c1ec394,5e085b7d), -S(184ad7a,9d1f54be,ae9bacd0,30707699,16e4158f,f1c7a9a3,e7303f38,53011793,7731244,6ceed0fa,3a832731,b477db26,743ccf3c,f3d8c09c,242c3327,6c67e3e7), -S(2f0ae3fe,5aa29a17,3a2718a1,91171d8a,7d33d2ee,6cc201de,4afbb00b,62db95e2,90f37a42,efb5787,6ed382cc,3a243179,4860ffaa,848b6299,52c6ace3,7dce5f28), -S(aa487bf7,fd746413,60e46513,4dec0aee,84287354,a74600d,65d02102,8deec2e3,d5de9cff,94ba3830,ece6a020,e9bda5aa,d999e97,a0ab4a0f,27fec770,ac2231ce), -S(54551633,398a72f2,66754798,5d2cab2b,6a107d84,72f8c06f,a34ed482,3a2a133e,4c33cc27,c462a5f1,e02bde02,aabb69ea,7a6c258d,55c6ee2c,a7b573f2,a7d970bc), -S(3b28883a,7df3010c,90b8613f,1b7639f0,7d766ebf,e3c1a02d,3bb20c14,156747aa,a3b1af7b,b133f94d,d2f720d0,aae669e8,b0a1b6c6,c2e14b66,72383cad,c28dbc71), -S(b3910ffe,6c153fe7,59ac3097,fd1a3b12,181deaac,f2cc3310,c036ac54,ccaab3d7,e242b0f8,de758d5e,ffb5e824,9cda6202,3686bbfe,439bed7e,eeec0c88,5b7efada), -S(679c5fd0,ddb09e92,77bd7c4e,651c862b,4fc18991,3892a31,6d0ed64c,1b66a0bd,f3cf0bd5,7e4085ab,7dce51b1,479e4ebc,63efb364,d11902a1,5d84b89,5599eaa4), -S(978d478b,3ad85f55,4b19a2f9,22f57cde,3d235bc1,92511422,fee2ad13,82a79f9d,fe0acd64,df69cdd1,985021ee,135050ec,879ffc35,b14deaf6,ade2734f,91781de7), -S(7e683666,eefc660c,e4326801,2690fac,4b0e3812,7de197a2,ca46270b,cba20572,250becb5,eda33bbb,cfc594bd,3675a82e,d5eeb642,bf755d2a,9e137ae2,1bd218ba), -S(8b90f968,26c56532,990cc0e6,8aa007d7,4555d566,7be7f23a,306788d6,cad77664,bc021a57,8e37d617,4a8320e8,e7bf68,4841096f,e191588b,79219fc0,d2559f6b), -S(b4e60f20,b7c71a14,80710413,fe81fcc3,88e83167,2183c36b,71185522,112f854f,d12ced59,7834d01,70a69bef,fb516ae3,4c67fea9,573bbe48,b3c2cc7d,edfbf0ad), -S(47d28ba0,3be64972,b30e7cb2,d4193440,bd4efc5,17194eca,2ef59cd1,78c6429d,304390c2,7a550fe6,23c9d6d1,465241d9,5827362d,ddaff80d,26ab1bf,9e32cc43), -S(2441a57c,1b9cea4e,28076f12,7fac389a,1068247b,56a1a4d7,7a2d5c1c,5945dad5,ff976ebd,3df8763d,aae65b64,c579408d,96b51a6e,9b3a85b4,401c25d8,fc9263fb), -S(3d69b290,d22112aa,ac7e2e7a,ded5cd9d,80754cd3,20831381,6e3840ae,d986ba78,bf7a0570,53ea3a3a,f27a866a,f0920ab,47f72d5a,f9859c31,6239aebb,d8d4ebf4), -S(2ec76c7e,3d684284,902f1725,54eb3dd2,b0c4304,4807a25b,472febf6,e9e6d1b4,97112d42,6850ee23,e57ae095,2565ee23,66c04ac1,6a388a44,14264767,20e38ac4), -S(972cb83c,80859ff8,96b0a318,a3a25386,3b6c99a0,49faca99,d36d5150,36da0e60,9668359c,953d20b6,e1873041,f0aea3c4,8e5a1d43,e4abab48,c0eaa391,8f7d8e98), -S(dfa2ccc6,9cb6c27f,6c072fc8,bc875c5b,e716c701,81b451f7,a85735ba,29363243,6342e27b,f9dff0e1,48fce3b0,1f9e569f,6af4a97f,b434725f,feff488c,501a7b4c), -S(3ee11d8d,8a46cdb3,8af24cd,f5f23f6d,2f18bc60,9f89fe14,ca0326a6,2a75c4f6,41ec4c72,ae99670f,2c5a4d8e,f0b2b211,fd3ea5fd,33b9158e,383c3ac2,d5c759cc), -S(bdc7399e,a6415348,77c66ce9,c62c1a96,7dfb72ec,6ef61c,e50dc71c,cdb3df96,90bddf9d,21aa5a98,8737c202,f89213d5,dd43c352,90a5cc96,40653be2,813f3f26), -S(d170eb03,dfad39f5,2e72298b,881e7c40,df9c4ee0,94cf092,25ef7b25,4250ac25,c9b3b36,937a83dc,c0592f27,202db5ae,9868f917,e6155e55,c9e0b3dd,8daa9085), -S(7153994,4971899a,8eff44c9,f38d4dba,e9315f,abff6106,a74231d9,97d4c66d,a95c07cc,e5d41397,7bdec5d3,bcbeb106,9dd90aea,ec57b911,3c6e3a69,baba78b6), -S(516ebb6c,f30e37d3,25bd8a77,f99e32eb,f2a84716,45bdc04b,a39b514d,268e9927,72504ee6,53710799,f5295c69,c022854f,b6ea6ff1,576c667,ab936d66,e651d103), -S(9de88063,6bcab6db,c7967dca,ce14949b,75529de1,73b46fc0,37a8c450,d5686d29,399f8480,c0f68bde,64ccd187,f247e09,30cc258,69e4779b,868d0af6,1e2dd1d5), -S(3a59c31f,dfae0e1b,a9b83db5,6f1fc0f6,51a0f9ca,8dc49c15,6e8d4ba4,a3ecd58b,a0513e83,600b57ce,3f87c762,6c0092d8,f88e0b4d,4b45a291,61abcd83,d2e93bc), -S(f533472b,fed40d17,566587fe,6f9e3c7e,3a657962,acb80e5b,319003c8,9b0b16f2,2fcf2b72,102dcb28,b36d8014,ee850bf5,9700d4d4,ae07769a,61bc0730,6a92304), -S(31b9170a,cefb23e2,330495da,dcc8729e,ce63a807,7406c4f4,de3d118d,1b759abc,111324ec,fdd8522c,64c0ba5b,a73cb848,9f1e77e8,d19c9731,dcfc59d2,26a88f41), -S(17ea4c86,6e3293d6,6cb535f2,db4ec265,331a4881,a9eb9941,2064ee60,38c3f8fe,a88536de,8cbec45,3d6fdcf4,3e3b5771,25ab4791,e2f318f2,c7572b19,7f3f02de), -S(f7a2f7a4,9462978,6f82557a,ec27a021,21995935,d5ac4adf,804b28bb,36ae5086,8a7ed1fa,60125463,96e3a50a,5616c515,3c5b6676,92bae5ea,f418bb57,8c4f42cc), -S(4a6b83ac,11a8d30f,c2bc4ccb,71b312ac,9ce05d77,3ca4a971,2f45f16c,c4a36099,c198732c,fbdaf72b,2c0471ab,5b4e2ac1,16d62e15,c5cf3bdd,c7fc2377,1db156ef), -S(d61e0f2b,757b2147,36f69e8,80f7882,26796f21,34c8ac39,7f023f60,9a222df6,dc369e3b,a99264d8,1041e2f5,decb93d8,7f3ddc5d,ebdad99a,1993e432,f92326ab), -S(ffc48a38,3faa0772,995f2074,4329141,1ded8a68,69f54f9a,53e14426,8d2d7788,edf446f2,660f6fe9,95129656,fafb76f,c1ef96fb,7227c4ac,8660cf16,867aec57), -S(986f203c,c3400685,610c83b4,fcf7a0da,636d92c4,f6f0bdb9,99b01321,ba47b952,7e152eec,4ea0a4d4,8f594801,40e5bfed,6539ddff,60646b86,ab463f9c,1c1cd72a), -S(e078d96e,97b33ea7,bf1a118d,8e45104b,18da1b7a,f799b5c2,2fc95db0,869a4b56,500aea63,487620e2,1c89ac2e,187eb32b,5567f715,2a090d9e,8e493190,c0b904c4), -S(a0b76ce8,3dfbfa5b,9ffbed50,736a676a,8e3e58df,aa3684b,68943ba3,f89d0ee5,5087ed66,33d4eafa,d7f962ee,11844da6,6e152831,8d780d83,5a9e7341,77c2551), -S(e6137a2e,1c22146a,81b622c8,947ebd54,5ee49505,e7343d6b,434ae440,f74deccf,b9598911,43813abd,14323cf8,fd880dbc,bb4ac611,e961c461,94d0f78a,1118b35), -S(bc966ce,8e2d896d,454cf19f,8126bd2,fd21f912,9e0c5b56,3afc6483,d5a8de1a,d7391926,bbf51367,c0d84d14,9fda784d,4f5e4db1,a4a71868,e8dc9968,ad27cd7a), -S(4fed3ecb,7303d658,48260222,6bb94148,b56a753b,902c3655,47db1db9,9b355624,87d3c83b,c4336625,4ddddcc1,a380b9a6,a7796f7e,6da00426,5c067f85,7c446b5f), -S(53151e3e,793f7ef9,a75180c4,ec3106ab,af3452f5,1a8c5301,1607ef98,3fb208b2,ba84da4a,dd761991,f375cfe5,146ba47e,d79e8983,8ab1e71b,737ea419,7aad93c), -S(f1ea6a7a,1595f99f,187287e1,2ca4cebd,8268da53,17c9deda,31c9c828,c91ba210,77d27512,38290ab7,4a75d9e1,63238537,555b51be,c0644f11,9409c1c1,7895c2ca), -S(4ce24395,80fa27b7,3a3bbed7,379b19d9,4c59e23b,1d482237,3de48d84,1e7650e8,258ae955,11a0890e,5912f651,f7705920,1971d6,82ea9abc,92d34888,f134aede), -S(20f5aca6,c33e91e5,97b66f07,30a7eaa9,4badf23a,b6f7653a,69f7a638,8ca20808,58642a87,964fd398,259037fc,c0c3e028,392eb7ff,15646480,1656cad8,7b6165f3), -S(5a84a300,9a7cb6a9,e86447b3,9d449bd8,3ce4e8a3,88395cc8,b851d961,df2bdca4,a724823c,bfa39a73,c02e8509,78d661d9,fc8dc8a1,e3a98c21,45448b2d,2c0d8d26), -S(4cc4b57,2e4cf18f,212315c4,65ed2464,b7850846,d64872ae,7b98d316,73853a6b,72594713,74be90df,fdccec2f,3a84b30f,74d6cbbf,fe966fd8,77de5b51,f9eeb409), -S(84aa8352,80aff2fc,b747f2d8,6e6d3f7b,5828ee7b,c0024d9,9b9a4998,fb809d48,a33e80be,b6131f8a,6ede3e5e,2bd265e8,5773a903,5912ac45,83cebc02,e0f70585), -S(4354311,ff6b6381,92ffa63f,a7a52fc6,cadcdd05,9adaafcb,7695686b,478dccdc,fa6b68e5,9d7f3aea,8d90d21a,ff26041b,68f68660,745bfee4,179d9e3a,2683f06e), -S(5be8ea1c,c7412e23,fe4a505f,aa15006c,ed823cb6,1853dde8,2e7af0a0,f06cc196,a2c76a9c,959b6b5e,d71dc83b,7a81e43c,a22a019b,8ecc54b0,eddfce5e,af9cbb45), -S(a69f7034,b680b802,189c6e8c,9cccd352,ce9ce14b,a50f9d41,a5991af3,e1822a07,df0cb8d6,86a38785,77235cd0,edf76b1c,9e902d2a,aac44b99,c916c3b5,848755b1), -S(f278be9f,11ce9c4d,2fc94317,98f3f552,b3f73bca,7da23757,93ea99ab,8aa0418d,8ec2cd50,6f3cadfe,2eea65a8,7cd8be99,a29d57c6,69482737,44e48289,d5eb283f), -S(28cf2333,17cd2dad,a4c83715,d0af39c2,cbdf7d98,7c90e1df,8709bdb8,929caf1e,a7905953,6c19b52a,459803cd,3a2ffb3d,d5597e5b,656c05bd,86d8e3ed,a9b7dc51), -S(45071195,99d6f85d,1e585fb8,2d4bf807,1b8ba01a,5487ef8a,b80d0508,2edc7b45,4951b428,1340ae42,1586824a,24933dcd,31a954,880d3c0,cc49864,72b6bfd0), -S(6df50945,4355e918,36a945ff,fdd68626,1b20f362,b1a7f601,9041506a,7cbade3f,38301bfc,e21d32db,83951120,954e9d56,179bf6d2,7fa3d5ab,7c37ef40,5245a031), -S(4db57458,b29c47ff,6f8b8ee5,12d897d6,36226380,4be13a48,6837f8e7,ebe147c5,e51039eb,7f9c8b93,3ad3c932,1b254cc9,f6221e35,13cba26b,a7c3e6ea,44f93ae6), -S(ad0ab782,d9a93270,b7083a32,b1913b7e,b0fb1947,9c8d8be5,ea74d0b,2590e087,50ecbadb,d801fdb6,5d40e84b,1511522b,3e603d06,5bf3a6a4,2b864558,c72c3fa4), -S(acab606b,aa8bc48,c452487c,700ddbc,daa04799,e9f57811,c47587c3,18d3900b,5be0eb5f,3f78292f,c248b704,f6cb2df1,891a05c7,822d9b47,35efd687,35b2e6c0), -S(16168437,b019abc,49fcab11,f7c0f2cd,14c2f784,dbfaeb40,f3790404,c4348d51,c68bc496,f40d5e97,4fdbaa51,dcf54ea,fb50abd,5ecb9f87,99bb3533,262ce86d), -S(5f03f4,a6cc9ad2,475d0f90,2090888c,31ae6eca,b08f7e4f,da8db504,876c8915,c918b3fa,1104d382,1d862299,17e0c5d5,cfbbf924,f69c24c9,d97b7091,157d7ed), -S(6da6938d,ef8b701,fcb228a3,c9066555,b4f7f0a3,297de3af,39d42897,5f0a27d0,f3ca7083,79910a1a,cdb94e7,9a7c8eab,e2c1b779,b749ad6a,fb4579b8,a3c56b6), -S(6b25cffd,587c71a9,3a736f8f,f5daeea0,26734350,fd158415,727fe6fc,6d309f86,dbf00735,d0c10049,27d582d3,8e61257a,770067fd,f9418dc6,73cf132a,c33f7b74), -S(7c48e557,27b1bed3,604cc3f6,7e47e24,b6f9b8a,7cd56cb9,f531ea5d,ef793f12,4d251353,73636962,126782f2,170cec17,e08483b,5b651f78,f0723da0,d6d4369f), -S(6769e622,cfbfe289,337de46f,4b6e1843,97fdc046,4560255d,9fc74c06,b00fc7a,523669ca,56e3e24f,b2490db3,6ea0bc33,6851041,d9146dac,1aace8c7,3a55e92b), -S(f83e990d,87486667,11214f8b,6a4643e1,901251c6,118d4d2b,a9087678,5313984b,b9decf7f,44c2cb00,d3d8858a,164a1,7ccbb6f9,5bbfa72d,6792ced0,4786a12a), -S(f3034416,5db59472,d7753efc,b55203b4,44b3a5f0,88825c4b,145d982b,38d369f3,3b765eb4,fae61edf,4a4c3b11,c71c5359,d8920eb,5cca2896,226e85ba,5932458c), -S(b2051f1c,5e6b22e7,d565ce94,bdd27c14,885322d0,e7bd3db9,eb13cdde,b26fd66a,b3245d05,2e93fc5,362d7e0a,4a4eebd9,ef8fd1d6,15c8a343,e308ef26,b9e331b6), -S(443958e8,fc9271a2,5215abbc,ad1bbcd1,887286ff,53d0d6e3,7803df80,f26094c7,3ae3f492,f51f287e,3f881bae,b16f4ca5,60583593,108053c9,352a48aa,95ceb545), -S(e8c5c31d,8e814515,b992ef4f,28bed3e3,ba6b2ffb,373a62d1,45976712,da8f5ad2,9d9e9d26,83c6b623,3d867d0e,727d00d7,fb5b7312,74d58bc3,b036b74f,8c22f676), -S(8b997cb4,8291df62,82ab7ac8,f6a917ec,330e76ee,4d21147e,ac15d3,2a9900ef,ba8e7e28,9bd40fc2,ee71f32e,48b1ab1f,1daf8c1e,6147cca2,a11befd7,e93b6920), -S(18ce6b3,126fd15d,29377619,4ad888c1,9355c739,7099d851,60111cd8,55199865,2f4ec4ea,4d215ec1,e102f7c9,ba9137da,5e75e00c,52b4d740,57bd37fa,61bcf038), -S(5b28c60f,a6c84a2b,dad6febd,f7cfc5c8,9fcf0e8f,d5cc8882,9540330b,8eaccc7,4d1c0d1,bb90266a,219592ae,ee619a4f,7b07c3a5,430ae20d,945f2121,2a652cdc), -S(5d4bf89d,fc3e8ac6,50f7c29f,6d878ce9,a1ba9cd9,d5970a58,ba7975ee,16496844,ee920d1d,8d7ee256,7f556433,90d0cf8,48458f75,f81b9f36,5c48dcdf,d60a96ab), -S(1fc5cd84,8a5680cd,76deb83c,f8ec6d99,db0e2fa3,7d7ac5bf,feb07fc0,ce0f0d9f,239f7252,18017a1c,d8419aa7,229eee96,37251ba3,a4a1eff4,9e42a29e,4f61eeb5), -S(e5a33510,603428c9,10cb5bd7,1da8bbca,3b50e97,46475a49,9d69b7df,badf601a,ee53e84a,a7e18842,a6879ba,ab59998f,62b6eac5,499230de,55a5c681,5d287a65), -S(c5ff6446,39c1772b,efe07d3,aad6dad0,5ba3074d,588d362a,6b5de6db,9d26707b,f11fe8bc,7f449e9,ecb22301,f131c6e9,7f4cbc52,af8fa880,6272705e,527a8e5f), -S(8246573e,b3ebc64a,c2118bce,9a275eef,6df0a34,61057e4c,a8836187,620041d0,fbe4a4c9,3bf019d3,2c2beaaa,ace3e4af,6c924195,8af4e387,d4ab3ef1,5146491c), -S(e9e9fd34,83b18055,cbbc8e33,cc6f3fc4,c507bb8a,84a09254,4822b44b,3d6a2910,45a4b02e,18da3327,80ab1f5c,37545bef,551c9a1,98616099,14bad711,1b4efd0d), -S(c3e53eb3,7d3a9fdb,bc2ab9c4,83656ff8,375bf18b,34aac991,ab5a6584,19d5f2a5,f95cb1ef,a793934a,2c1b0dc2,a0746974,75a29040,7f4413e7,449cb71a,af96225), -S(f54901b,fceceb3e,5beab5de,e9a93344,f354d956,5a989fd2,21cc8442,51944dab,57c0cb7d,8a79b236,608d7971,c1590672,8b5039ac,32db50f4,f50ca4fa,eabf3014), -S(d5cad259,e0716691,b5a1f8c5,970b4bf6,c7329aae,e4ab647f,daed2388,85b4fc55,4d944544,63cdfbd2,d769628e,bc60f501,ebf1d1ba,a1e4d68e,4a50e57,7afd7fa0), -S(fdfe1cc6,51fda605,d30582ae,d6d3e74e,855c278f,4151145,312f22e,ac142bbd,42f5dcb9,5772bf4d,4451614f,854f5ac5,e753533b,4d16e8a7,ee2a1adb,64df9029), -S(4db28db1,f69d04e3,27a438f6,199a5f98,292a6380,5e8b7edd,b36d341d,28d2e790,fafccf3c,394ad72d,40e938e2,5eb64079,f8617499,313241a4,99a840f8,733786dd), -S(1dffedf6,a430c31c,9875ea06,227583b,5e5160d0,b2d975b3,452a99ec,dea4d3d7,67bc0a31,ec97cb9b,fe191614,ded30a63,f77025cb,5cd7acc1,2e3d84fe,24b590b6), -S(41239a63,857928c3,e4d51a41,f77129a4,d60c7d44,9b6028d5,3b183efc,2452403a,8ac22f58,288c4a53,b6703f49,cff08a9e,39c16516,126b2803,9a0759f8,776ac785), -S(f2ecdfa9,adab5e32,eb7740b2,4eeb0fa2,649baced,1a69b03f,d47434a7,3d0c28e0,133952e0,ec187463,6d5f15f8,d2ab385d,aa58bade,36b9984c,ab94a591,70f2beb4), -S(7e74762d,c7c312a2,2fb7a48a,b9b393bb,7f540f7c,279eff83,c2170f2f,27132da3,9c7e6962,f6fd9cfb,a83a7b7a,85062f9d,add8a558,cc4cba51,d6079072,b7775daa), -S(613df89e,dc48052a,b497e0f9,571703f5,78e0ffcf,b116c162,277319b6,df774ffd,9cfa93b4,61200eef,c2e7855d,898a4198,52921aab,a30412f6,218095c9,4827d672), -S(caa6c1f6,c176e31c,a2baaf8f,39a1b5e0,c1c28443,ac8503d6,f4a55759,8e8180e,556a1519,73ece75,8e68d10b,151039a3,ed0521ca,c19281e0,255ec99b,10c21a26), -S(267f26da,2393ffe2,18f5c574,ad4fb6de,634ee94d,ee5ff952,10dd72b,1c550f5f,234fdc5,fd8e9412,650512c7,a510dd4d,f5ae9c88,83ecb1c2,edd2a3ec,d4bc3824), -S(8a26bd9a,b45c1aa0,772d794e,b088a941,2414b48c,82e2a118,23e869e8,3dea895,68ec5163,a955ab1,7c338a15,d2b66d36,5734f015,4e21e750,1387e978,452d9902), -S(29593a26,f0b9a728,c0248f06,4471e56e,4fc8d38,9823f7da,aff9e46d,81b9eae,710860e0,a9c98dd4,b1086e7d,2364be88,8741253c,9b8a7772,7b4ac275,53cf9b72), -S(5676cbf9,a0a41fb7,cbe1f3c0,a202bf7c,4458e938,964d903a,65325526,27454bd2,96cf5b8,1aa71fbf,f1f60e7a,2e4d28ee,ef7d0288,1b63d8fa,da9a10e7,8fdf7723), -S(6db9282,fe0ff035,b279a832,6f1c4f63,839a6c67,788e2e5,af7a4492,ecbcd9bc,4788671b,aae2f709,a2377b86,2c30af5c,49c721ee,fb2e3f91,20d49eac,821bbede), -S(db46b01b,c6047a92,e9e5c8b6,24f6aeab,16b213e7,91fdaade,8f045c55,d8de4275,9bd83ff8,31737782,21f161ef,ea079ea5,1e459023,445d8255,8e5f318e,949b52bb), -S(fa91fa0c,c71a2f21,38c61aeb,f451b435,1ae6a432,53a242e9,249727c,7c649ada,7c518caa,bf9fc9e2,c88a9ddb,712f32c,d8d04d7f,54dae53e,7dcc154d,e8826b33), -S(9752d6d9,e7dcc767,8bbce21a,5a7a3ea7,66d70518,fb59f435,eb6cd1a3,40f84dd8,9d1c48aa,2965ccfd,c03f5bfe,41a073b3,da6948b8,457e6e0d,c8a13de0,149a00f1), -S(ac9c0ed2,2e66bb0c,83ccb76f,62ee840b,5f2d6f5,568697e9,b0223009,63cf3c2e,37532994,58f79d71,df7d1b04,91523c98,9d30578b,706e3665,6c897fb1,1746c948), -S(71a9d71f,1f44b087,e02f7f28,5c47c947,f143d9d5,95e59dc9,64233226,d51c15f3,998119d9,7ad626e5,28e971bf,6ce85176,e3b9a095,1426f6d5,6ce8eaa2,81d6401d), -S(fbb85fdd,c4c25602,13ec981c,a40e69d5,6f3c6132,d1ffa38a,87b25c1e,87e40ecf,85882651,1c142a57,6bcf5f9b,1fbb0786,38511629,4c1c82a7,21e24bbd,16551bfb), -S(ad1fbec6,59b15b66,d34190c0,cc9165de,e48221d,eb1666e9,4d18042c,26db21e5,b579467e,d7d83215,c260dd2c,f089b2ce,513aa5ca,c9ac705e,e5841a65,8a583e18), -S(2af71297,ce1d4633,4ab66dee,42d005eb,845b927a,e6ae91ca,2fc8d414,58ceeb68,7477917c,5a456710,266815f4,39135116,69654290,36968cf8,e6983ee4,c508e605), -S(c0ae4daa,d71b2fce,d9c9b40,76be40e,a0cae11a,3d86ebe2,282f52d5,b86f39ec,61343833,f5d4ebf7,4445c133,37fef065,13fa3e0f,66cc7937,698b0cb6,9225fc9c), -S(93178803,9a374b99,df4135a3,50e1be5a,efd2e73,fa9c050a,d0b48812,a654c529,1bc01acf,3bf8b64f,6ac15664,c163ebfa,4a1a6ce1,4f9d3a9f,6e5ccd45,beaba2ce), -S(25458ec3,e24ae756,51f84ef1,a2bf49f,c19e86c7,99022de6,b7b58933,82a0050b,eeb2e93a,e357cf8a,9afbb9b7,fc0e97de,d80876cd,f08ee79b,ac07324b,cd41463c), -S(136e031b,1ab7a45e,6b8c3b53,7a615fc3,9e89d81d,a822e60f,aca2a496,e651e974,4cf2e215,8bc5c677,60e7d9bd,e9a476d5,d44a1c98,804e2697,a28dd17b,d4f5fa10), -S(5fefc4b1,2a3caf6f,3d025f3c,3510085e,ecc1ed97,46ccc265,1167cb0f,7fcd1af2,5cf8288,30eb25ff,1ad53354,acc72f49,5eb558f4,776b219d,bdec8ae9,24b1f125), -S(807a0f68,dd6026b7,2116e606,90a39596,e8558ce1,d11ffc9b,dbf2c574,40b82c38,12a2f38d,c84c41e8,2526fe56,2b877aae,10f575de,7edfb5ce,25f6a93b,158535e7), -S(8579c776,ad8f4fa3,65bd4efe,cf0b66be,3cf33cd2,61efc2cb,387c9a13,13947c34,7d888de6,9403e15d,3489748f,5d85bf7e,fd8213b0,673403fc,28a3d7e5,c3559198), -S(7374f757,46d03189,46386205,bc5d222e,243034a,3e0d4566,48777a3e,9239dce0,396af260,b295933d,2b6ae205,6fe53231,7ffec745,c4c95621,c1588d68,c3fd3f75), -S(a076997a,d9c613d4,adad3eee,9cb00a08,dd747840,4fe33fa7,34dcf3b7,58e8670f,8eef221,804526da,bc1b88eb,4320ea86,8d36ba82,775d059a,dcc4017b,6356f60e), -S(88494285,1a2626c7,f52abe1f,b31f124d,6fe0563d,c962c35b,ac690b96,27fbc604,e0a56299,86cb2c2d,a790688b,c63542ab,7362969d,d40d9ce8,5ec09e87,672cfe35), -S(682bb535,2da425c,87a541b1,35925e63,a161a84c,30beff50,b1c34193,fce7a6d,cea25359,481132c9,e9792a9c,4beedca3,4d16c3f9,f46349b4,e9d6cda3,e55f9b6d), -S(f80aa12,f4fd2631,26e01c2a,2cb0f86e,4293d3b8,87fc954d,daeab57,cbbe18fd,f6a2f24e,458214d4,c07d9191,23f8b6e0,af62d656,6657ff2d,c9894fc6,11917100), -S(f077e470,ca971bfa,9c762c61,132f5dd5,53eba38c,9629a8a4,9fae5b00,a23334ba,8bebf838,df798f83,88200f99,cdbcac9,8495681a,e4debeec,3f5ea4a2,b07bd87c), -S(1cffbe02,6cd70d89,f27a9db5,284a94ce,c9705d06,72b64bda,89b3a23f,c8b4a098,ea668c0d,61b0307a,15a303c9,cdab0ace,2ce5f1ef,8772dfdc,85d936e2,57bfe49), -S(7694c9e6,c10ece3c,f7ca1bc5,aac059a8,32f541df,da8342b3,ae31ea66,35d3c5e2,98054fd,39bf818,91b0d50a,ebf214a1,23010078,e75b20dc,c6c6c768,493899ff), -S(54f25d1e,1de2c437,39bcd34c,8a7e7d9e,d322a6ef,bc025143,de17b95f,e5cbae3b,a0a13012,cdff3d30,6bd3e863,9b1156d1,17c1f74f,8be3d8c6,a3d7a77d,e20c3d30), -S(ec3ab50,419649d4,78592017,c539f924,122d8aa5,4104309f,fc213499,8b608cd3,9f147580,8523383c,83f75c37,4b802589,fb1b0f60,99f20cc6,3497979c,4e558b4d), -S(21db4eeb,7f414ad,d9d951f2,ea33b9dc,8ac6f752,5549c982,174a4742,7dc99145,b4cb3a0e,a408bb1d,31e946b1,f0a99344,b0f2fae0,183088a9,543bef43,61950b22), -S(9e76ef4d,aa872a56,514bf43b,767a4bec,59dd96ad,9c436e39,807a4e5b,ff7b96a,7245b4cc,a609a698,bb3c6ab3,78d5236d,aaa3d8a4,c8502f5f,83432d62,b46685b8), -S(ef1c1a18,9fff9518,b1b40bf8,1edf4505,6a46bd92,1bd93c3b,1291597c,1d50bf29,ccfa479e,cb5e2217,ee9d2af4,42cd873f,953ff640,4127f760,2cd465d1,6590f309), -S(2fc501dc,d994ee04,81f1603,78a056b4,44b211cc,85e23459,f9969f57,626b05f6,29385f01,6b4180a6,93533c57,63e33818,ffc4f63e,72f78174,91532bf6,89d3b847), -S(52fc0f14,ce831d5,85e242e0,8421d021,cb58ec34,1d3d718a,34764966,48017b80,ee55bc21,120709fa,67251940,2531b231,e9713263,b28f52c9,a294b32a,cd7b2a07), -S(86932072,532e1a89,80b5ea8d,896deb75,6ceb8a11,87affd5f,c5eac0a,8ab374e6,efa4d9fe,3cb01ae9,b685e938,1a7ed4ae,b673d6cf,3fd8b47a,d55b2b22,cfe771c0), -S(d5001bc,4888eb3a,28ff21c5,52fdcfb9,f64be472,d677500c,2c6ad71c,854731cd,20a40358,579069a6,b246ea31,3e58b5ec,6569ae72,ddc20a0a,5ad7bc14,70aac129), -S(197d8ed,db431380,ac8419bc,a9a415d0,c19ff38e,84145635,a50eb5f4,fc026731,137d9984,ec510a78,130587a,59a3091a,24581fe8,40f49bb4,aebbfa3,9367ccb6), -S(f0efe141,83441eb,acd172a9,5496b85b,648deef6,9dcbb653,be2993fc,ab70eae0,1df1c523,4433bc9,7050c858,f477652d,636edbe9,8b3f51ef,b1a2ec17,6a0ad6b7), -S(7657e05b,c0659f26,2f2e86c7,73dd6dde,1e650064,5fad0165,4b52803d,c1c06599,26407f2f,a1c5c820,b729b9be,4a3c7c6e,b5c0ca46,f9c07d52,654bbd67,2a2d5f35), -S(6d037db3,bd776672,ab096fd6,e048768b,3acb7e5b,14cb4a77,ad8fa2cf,b67f7605,81d83989,87d95d38,5412e93d,43cd82e1,1060bfac,72d689c6,4d0572,7356db5), -S(16243eb9,d4eeb5ad,a68617e9,1dd8fd82,87db58ba,f7b65a40,db756936,54653ea5,fb3d260d,abd9a44d,e8795df0,cf9959d6,b94bbe4e,caf9c715,c4612c2a,4cea9615), -S(a59b5c4c,f732c9ef,f10b7ce,6e918562,d6082906,8509eef2,17c539a7,7601a48d,ae27b1d7,77021234,d703c423,cc7052b5,7f23388f,371d2a07,e0188630,ddbe4cb4), -S(33da8d1b,ba39bbc9,fdf39d17,1b8256f8,853da773,184d62e1,6d0d6ead,198b3cf,50bb1787,a917a656,622be1c6,1948adcb,1992153e,9b7725df,b93007db,7865719a), -S(4e5b40ec,c1dec23e,ffd4d2ed,4b3be8c1,b2a37ae9,e7d17d02,a00c046d,6173c48e,a68713c,3cefb9aa,559caa17,ff33b2e,476cee33,27dd5026,157ae77d,98bced0b), -S(86c5fb99,352060fd,2125290f,cc4625ca,2aabeda9,5470c14d,91afbe64,36511ae2,aa638940,d79a2237,c1cbc174,14ccee68,aa6dee00,c411dc3c,caf3b4e6,a24d5a24), -S(f3082a0,934921a7,6dc3d0fe,45d4badf,c0bb26d2,8b597a4b,bc7bb719,e43c5e7d,2f7a82ad,fd0099ee,3afbe9ca,a279ebbc,55841101,e1d2361c,1b7b4e81,98d78a90), -S(9eed2803,f83079db,90d50731,3fd889db,adf10be7,625a6455,709690fe,318df86d,1eba34d9,e0eb25b0,2494e3d4,14bbb963,69b6b6b0,f1ac8936,58170039,4ae254bb), -S(5045129,bafa3288,6d6678f8,eb0fa73,c182dc1c,ea039839,9e7eaf01,13d10432,f9290714,bb6972df,99d58a5a,50bab590,8c274310,1455d479,db9851a9,242c658b), -S(5083cdc1,1249ae24,4d1891a9,d74ee53b,90bb57e9,25fe26ac,32c364ee,99544031,ad385238,f304b7ec,6726ce24,9477326,15ec400c,c60069ef,cba2ffd1,c33ae39b), -S(6c1f547f,41bd9771,aa16cc9a,e19e5787,52e06b06,3d1aa740,dd219bd4,b8413ded,4e42a565,5169be0f,a65a471c,fd3fedac,58dea3aa,7cfc31b0,39902c6f,9938341), -S(bd455ad6,2c32f8e1,98f92a6e,ad5f8d1d,4ce6ab3b,57de4c76,d4a2557c,9d0cc2ca,ee672a2f,e514b76c,ad8af99e,20840aa0,231c423d,450451c2,66130160,a51db589), -S(3ef7949a,2f73d9eb,29390e2f,621cc651,54a31770,d49664bf,6602f8a5,3107df1d,faacb2a3,7050f0e7,d3d5e0be,edf3f658,ba30da79,df8fbc81,167bfee9,aece4f69), -S(8f45c59e,dbdd7f48,cdbb0fad,c2058ca1,b7007ba7,4ed1a121,4c6b562,7bcf6acf,357a629d,1e9800d5,c1f83981,81a39afd,56b1fdc8,9eec847d,a72fdb26,8d7fbcad), -S(3f7d488d,82c85663,b618af77,30a1b987,f662238d,9ce02ed7,f5160677,99ded34,c61323a6,bd1d8c43,506e24b7,e0635d72,e8eff076,db783b56,5f9424c6,8a1b53b4), -S(3700e5de,478887df,4f0819f0,86a2199a,a12d5925,f8e5c32b,c40738d2,edb329f8,8218c49a,3f40c04f,2a9ebf98,cdbb2d5e,1e9f2b51,5dbecc94,76f6e54f,26711232), -S(47ac5d4e,e3147cce,3d3e0c66,fb0c3a8e,a1d9c0fc,92dde919,7153ef9a,b4de1642,37b484b,4f0b4016,341a8b02,8136228b,6744ad3a,a871971c,6fb07a93,d16dbef5), -S(40cd13b1,6b0d24c6,d730c135,6ee2ba56,cfe6bcaa,d38ada27,230441ec,b50d5f81,31ed93d9,a98b6945,58c0130,b57c8c27,5caf386e,690cb1c,96b530ff,7a3ca4e2), -S(d491b581,10b6e137,57d20933,b356a977,51d3d03b,327354e9,aa1aee11,c8dfa15,85bcff81,4b5601dd,2eb27e1c,ff7d1489,93a98cea,9ec0553b,d14f108c,beabad07), -S(eabf656c,8b8e7de,a4a4ad70,d9a17911,d56891ef,7f6c32a,22078713,84f0b3f2,2ff10143,49e265ff,16619e7b,c7528fb9,9b3dbfce,e0c1e6b1,c30ec1be,47cf4e5b), -S(ed8abca4,ac4d7946,1ab4e3a5,5c05cea3,834381c,c7ec940e,c1b390c8,cce350d0,6b54dc69,86bc76fd,fef49c22,4b536795,2961b8f6,5ac6f552,73c4052b,dc8285da), -S(150968f6,3a67fde4,b4b404eb,866fd66b,50b822e,43f4e684,230cd720,e2e8e6d0,93e824ec,28bc5a84,f21b7717,d08ce64f,f5ede647,81538f4,a6f84332,4704c6e0), -S(83cab683,9ce8d260,7398446b,9c8f63d2,e4e1471a,f183f482,b22dc360,c59403f2,8f570cf4,391133d0,e31c363,84cf5195,f160ceea,b96e44,ba79893c,ddfaaa0d), -S(b3f062b0,189836e0,e9cc7acd,5c3c7810,bd287bdb,c0d64b4a,27202ea,f3a05b41,730f1110,ad1e7dc7,f6e1b84e,9a332c86,2003ec5c,f9e75835,97c07530,dcf9feb1), -S(7c226926,b567438e,cacc7662,2fa3f806,2888db46,f3e41649,d2bd5142,1a90f83e,563b94de,fa1719a2,b7f09c8e,5b31476d,8b8ee80e,9dfae6f6,aa0f6a6,45ecc33d), -S(b9416bdc,9862a2c2,cf1a50ce,132d07d2,8862f6dc,19e36f03,ad3100c9,659fcb99,5ee3e16a,5be0ad7,9c908fc5,f61c7024,678d2c93,47dd1c95,45734edf,e52fc618), -S(ece2cc3d,10edaa0d,4fe86a0f,b2d682c,aaf4d50,2913d942,8d704590,c2b3147e,5e79ac71,109cdd4d,12ff674e,b512cde,3a8004df,f2746165,e55233b6,2ea6fa07), -S(1dd18b36,369ddbc6,5a8d84a4,69262341,e6dc55dc,6362e7c3,5be5d5e6,ae72c0d5,4f7679d,e9ef807e,be2c1d39,163b7b17,1cfd22e2,6e4fb466,d8af03b7,1539ec98), -S(beefd37,fa712452,695bc66b,4fee98af,bd772c13,e63d0ca5,d62a7b0c,a8a2a3bc,caafe844,5be9307a,e872d297,991a9e42,7364ab4c,257168e5,660c5297,8a623aba), -S(d7f42137,7048d65e,39bb5032,ca991d91,184a98f5,4c35b3a3,73c118cc,d276d3cb,64e78d01,8e179101,41685830,dce8ab9,3285ebd3,ceb9817d,76edf7bc,524716d), -S(737fee9,6a6e5ae1,98bab025,2554e3f6,12517cf9,2614a503,4ab7b882,d97555bc,ac29b0c1,fb66bdac,a3ca5f19,3ac71997,87573d85,8353b9ac,c30ab147,bdf379bb), -S(784f4c1d,6a815b8c,6e429596,183e6e17,e846a50a,c65f0c0b,abd1d943,e115a307,ac5124ea,29517daf,782c5698,e5318d0a,fa0a05ca,d7a9d395,bd17c3c7,9c3a9972), -S(982794d0,a4430900,e6254f33,40924116,ec055a4c,8c0715f6,72af4cdd,e1bfeae0,90b9959c,3ad2170e,9bb70c1c,676ab6d2,584b97c3,855d9ec6,93307407,e57a3c7d), -S(7532737,c45039c,768b4cfb,71aed614,c8c8f977,70c94bb,1c8d5bd3,cd092d2a,b495750c,b0e5fd38,7f7f08cf,b5d2cf40,5f5c9a07,8184fdaa,5af78135,895be55d), -S(2900819a,badaa25b,5e79c9d5,7d35a079,4e587f3d,f75ca042,736969e6,a4db24ce,e7489b71,d1e8492d,66a1c6b0,dd23a453,12095649,b902f68,9789eac8,eec97435), -S(7c615aa5,b7134559,82fccde3,8c90d0ba,2d3a09f4,6bdbab02,4dd7b6a5,cc9fc205,4189a5c,d5830638,53569ebd,77855a63,f70229bc,f9322b2,2546df2e,e687cf50), -S(13749da6,79887b0a,d7e4f461,ae125385,c5126eb3,63d88327,6f0a4773,ee00193c,c2ee7f13,49def3cc,5d7963d9,2bee09d2,c36128ce,a5a0fbb6,964a0c14,a7644e92), -S(4ed1478a,b92b688e,aa491c7e,e3134ca9,7cc71cbc,3cb32ed4,a69c5b13,4e73b526,16f25a92,fb8e8042,ce2105de,e9133b82,3be2277e,66dfaa9b,368a2c5b,6b980a28), -S(f1efd577,6955489b,57759ad6,3c5cd042,383c1cf4,a1ea3719,8b1ad624,8d2649ed,909afd94,20027b64,aaeea435,25c77989,674411c9,14bcfbfb,7edc1055,e0b0ba6), -S(eec2b3d1,446835e2,ed2b9c32,80f320d5,296fae6a,fee19e4a,e38da171,6d0e35c7,a9f0beef,738d4ff8,f56bcb57,8bb509ba,8ef9e07e,3abe009a,9f0e1a7f,9d1609e7), -S(1d45c89f,fddd05a5,5043c44d,b8d0211a,f49f3aba,31e3ac62,5687413,4ecaa89,ab2abf54,db899f51,6c19848d,f0fb6e8e,9b43de72,3c74c33,9ac74611,7a64592c), -S(61531e01,5b2f0ca3,e36a20e6,b6d7f2ba,e2a1e245,340afb7,f134c3c8,799374ae,fae6274c,1e646987,2aa0b680,8a7fda0b,f3d495a1,24e859c0,2ac50be2,72dd4596), -S(a1b129b7,c1803643,6136bc8e,f7b99895,c5551ae4,71b2c0cc,ee48c266,bcdf2808,b9f97676,9623c4b0,bf10a738,6081cb23,f68693cd,626abaa6,b3874be2,5af886c8), -S(27e38dcd,d63bab65,c77eedfa,7e1f4b46,203ff350,20c86fb0,4ce2ffb8,af8d7056,81f30a56,7340be31,52ce5c6b,877f2c67,a7db7acc,7f24e13b,bf836660,9d61f04e), -S(64919bfc,50072a00,8769f559,3ad0e5b7,72ed6575,81ecf37c,8c759a3d,51149fc4,5759727c,20ae86e,b38aa3f,5e53b848,8ecd2b,477dca0a,ffb83903,65e70900), -S(d392e5cf,3c2d4a0a,20779b28,f4957800,ec7148aa,63b2bcb2,348afe9b,d28ad57d,54062719,a0ee0869,b1a99d9a,e4716487,70386747,9ead4774,66df29e1,78c87c6b), -S(6b9fe223,333b0802,34fb49d4,85218d11,9123c430,94e4ffba,38f33bb2,dbe7d9e2,5ea16bea,b5101109,4d34ec62,e6a63a71,c78de1f1,fcb7ce23,4ba2f51e,e4eb2ef1), -S(b1a505c,eb85f130,ef6e4a49,e429b0c5,51a87831,f850ed83,6bc8649d,6097ce12,a887e16a,805c0708,45589bff,2b22fc6f,4187cc06,cecef137,9130becb,5d5d149f), -S(8bd25993,c653b1e3,6f477988,61743aba,a5ffdaf,fd0890c3,caeb2963,736cbb44,341aef51,13b0d08d,90e90ffa,56570d57,5777260f,e85a15c2,2b5b3139,4f0a8c20), -S(2da121de,147507bd,b8836321,40394006,afc65465,7c6d4399,97cf6c88,ce0c4016,3ec87a24,eb19c502,848ff433,7ac3f48b,9a56ca56,3d0bffe8,eaa98e97,49f04aaa), -S(147541,9e9e9ff8,5b93f56,2832e74f,6c8c311a,676a759e,7dc62c63,5faa0b07,40fb95e4,810607ce,7ed10d9d,61404078,10ddbc55,261badc0,5e07bd1a,579ca271), -S(7c48371b,7eb5655f,b9d95bc3,5660d783,b1884573,d2934346,c5a5342b,a0949cb0,8b8cfb2,4cab96fa,1ee1e5d7,7dade5bd,23fa7868,445d9ad4,723529db,38110dae), -S(6ac2912f,d959d41c,19ff8ac4,bc136e85,91944b79,470d633f,b9fe65f0,f72541f4,63351f35,d4a7787a,31ef0bd6,f28aedd7,864ec5ab,7d841f11,9163e351,e070fcba), -S(db08e4fd,63e16bf6,abc05d78,be6bccc7,c9b8e15e,334ad697,9205a2e9,c2100e15,eeb0ba62,e1a5ee98,c2e2cc5a,8d9cbf11,d265019c,9eea8f50,4aa1e50,a422d4e), -S(4160dad,5255da89,12f69754,77b445a7,26fb7b8f,6ae8e2bb,d6276ae7,2a31afb8,ab0817bc,7a9b6907,9f6db9f3,c9a77718,23a1d79d,9f2739b2,cbeca18f,e5b8fbf8), -S(3794fc72,f432c983,2f9ba8dd,b46b1c64,d979e899,78b3c14f,2f903ec4,75af091e,a898cdf,7cdaf6c0,3715e38a,4bea1081,fda150b3,7faa4a11,ddbdc350,c7e0bb05), -S(244b87a4,fcecef37,76c16c5c,24c7785,be3b3c13,46595363,b8c066ec,45bfe561,9642f5fd,e0ec25ed,bd2129ca,6c023ec1,a2eadac7,f6ec5b7d,2b7fe894,41e5aa11), -S(9de52b81,157165cc,aef44485,4c2b3535,a599a79,80d024de,5334b385,ecbb2e91,74fca165,26fe2f87,a41ce510,4dd5634,5cf98c11,803c0392,3eb4b8b7,60240c02)} -#endif -}; -#undef S diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar.h deleted file mode 100644 index 14aea0e0..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar.h +++ /dev/null @@ -1,114 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCALAR_H -#define SECP256K1_SCALAR_H - -#include "util.h" - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#if defined(EXHAUSTIVE_TEST_ORDER) -#include "scalar_low.h" -#elif defined(SECP256K1_WIDEMUL_INT128) -#include "scalar_4x64.h" -#elif defined(SECP256K1_WIDEMUL_INT64) -#include "scalar_8x32.h" -#else -#error "Please select wide multiplication implementation" -#endif - -/** Clear a scalar to prevent the leak of sensitive data. */ -static void rustsecp256k1zkp_v0_8_0_scalar_clear(rustsecp256k1zkp_v0_8_0_scalar *r); - -/** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */ -static unsigned int rustsecp256k1zkp_v0_8_0_scalar_get_bits(const rustsecp256k1zkp_v0_8_0_scalar *a, unsigned int offset, unsigned int count); - -/** Access bits from a scalar. Not constant time. */ -static unsigned int rustsecp256k1zkp_v0_8_0_scalar_get_bits_var(const rustsecp256k1zkp_v0_8_0_scalar *a, unsigned int offset, unsigned int count); - -/** Set a scalar from a big endian byte array. The scalar will be reduced modulo group order `n`. - * In: bin: pointer to a 32-byte array. - * Out: r: scalar to be set. - * overflow: non-zero if the scalar was bigger or equal to `n` before reduction, zero otherwise (can be NULL). - */ -static void rustsecp256k1zkp_v0_8_0_scalar_set_b32(rustsecp256k1zkp_v0_8_0_scalar *r, const unsigned char *bin, int *overflow); - -/** Set a scalar from a big endian byte array and returns 1 if it is a valid - * seckey and 0 otherwise. */ -static int rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(rustsecp256k1zkp_v0_8_0_scalar *r, const unsigned char *bin); - -/** Set a scalar to an unsigned integer. */ -static void rustsecp256k1zkp_v0_8_0_scalar_set_int(rustsecp256k1zkp_v0_8_0_scalar *r, unsigned int v); - -/** Set a scalar to an unsigned 64-bit integer */ -static void rustsecp256k1zkp_v0_8_0_scalar_set_u64(rustsecp256k1zkp_v0_8_0_scalar *r, uint64_t v); - -/** Convert a scalar to a byte array. */ -static void rustsecp256k1zkp_v0_8_0_scalar_get_b32(unsigned char *bin, const rustsecp256k1zkp_v0_8_0_scalar* a); - -/** Add two scalars together (modulo the group order). Returns whether it overflowed. */ -static int rustsecp256k1zkp_v0_8_0_scalar_add(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b); - -/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */ -static void rustsecp256k1zkp_v0_8_0_scalar_cadd_bit(rustsecp256k1zkp_v0_8_0_scalar *r, unsigned int bit, int flag); - -/** Multiply two scalars (modulo the group order). */ -static void rustsecp256k1zkp_v0_8_0_scalar_mul(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b); - -/** Shift a scalar right by some amount strictly between 0 and 16, returning - * the low bits that were shifted off */ -static int rustsecp256k1zkp_v0_8_0_scalar_shr_int(rustsecp256k1zkp_v0_8_0_scalar *r, int n); - -/** Compute the square of a scalar (modulo the group order). */ -static void rustsecp256k1zkp_v0_8_0_scalar_sqr(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a); - -/** Compute the inverse of a scalar (modulo the group order). */ -static void rustsecp256k1zkp_v0_8_0_scalar_inverse(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a); - -/** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */ -static void rustsecp256k1zkp_v0_8_0_scalar_inverse_var(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a); - -/** Compute the complement of a scalar (modulo the group order). */ -static void rustsecp256k1zkp_v0_8_0_scalar_negate(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a); - -/** Check whether a scalar equals zero. */ -static int rustsecp256k1zkp_v0_8_0_scalar_is_zero(const rustsecp256k1zkp_v0_8_0_scalar *a); - -/** Check whether a scalar equals one. */ -static int rustsecp256k1zkp_v0_8_0_scalar_is_one(const rustsecp256k1zkp_v0_8_0_scalar *a); - -/** Check whether a scalar, considered as an nonnegative integer, is even. */ -static int rustsecp256k1zkp_v0_8_0_scalar_is_even(const rustsecp256k1zkp_v0_8_0_scalar *a); - -/** Check whether a scalar is higher than the group order divided by 2. */ -static int rustsecp256k1zkp_v0_8_0_scalar_is_high(const rustsecp256k1zkp_v0_8_0_scalar *a); - -/** Conditionally negate a number, in constant time. - * Returns -1 if the number was negated, 1 otherwise */ -static int rustsecp256k1zkp_v0_8_0_scalar_cond_negate(rustsecp256k1zkp_v0_8_0_scalar *a, int flag); - -/** Compare two scalars. */ -static int rustsecp256k1zkp_v0_8_0_scalar_eq(const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b); - -/** Find r1 and r2 such that r1+r2*2^128 = k. */ -static void rustsecp256k1zkp_v0_8_0_scalar_split_128(rustsecp256k1zkp_v0_8_0_scalar *r1, rustsecp256k1zkp_v0_8_0_scalar *r2, const rustsecp256k1zkp_v0_8_0_scalar *k); -/** Find r1 and r2 such that r1+r2*lambda = k, - * where r1 and r2 or their negations are maximum 128 bits long (see rustsecp256k1zkp_v0_8_0_ge_mul_lambda). */ -static void rustsecp256k1zkp_v0_8_0_scalar_split_lambda(rustsecp256k1zkp_v0_8_0_scalar *r1, rustsecp256k1zkp_v0_8_0_scalar *r2, const rustsecp256k1zkp_v0_8_0_scalar *k); - -/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ -static void rustsecp256k1zkp_v0_8_0_scalar_mul_shift_var(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b, unsigned int shift); - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ -static void rustsecp256k1zkp_v0_8_0_scalar_cmov(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, int flag); - -/** Generate two scalars from a 32-byte seed and an integer using the chacha20 stream cipher */ -static void rustsecp256k1zkp_v0_8_0_scalar_chacha20(rustsecp256k1zkp_v0_8_0_scalar *r1, rustsecp256k1zkp_v0_8_0_scalar *r2, const unsigned char *seed, uint64_t idx); - -#endif /* SECP256K1_SCALAR_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_4x64_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_4x64_impl.h deleted file mode 100644 index fe0af361..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_4x64_impl.h +++ /dev/null @@ -1,1131 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_IMPL_H -#define SECP256K1_SCALAR_REPR_IMPL_H - -#include "scalar.h" -#include - -#include "modinv64_impl.h" - -/* Limbs of the secp256k1 order. */ -#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) -#define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL) -#define SECP256K1_N_2 ((uint64_t)0xFFFFFFFFFFFFFFFEULL) -#define SECP256K1_N_3 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) - -/* Limbs of 2^256 minus the secp256k1 order. */ -#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) -#define SECP256K1_N_C_1 (~SECP256K1_N_1) -#define SECP256K1_N_C_2 (1) - -/* Limbs of half the secp256k1 order. */ -#define SECP256K1_N_H_0 ((uint64_t)0xDFE92F46681B20A0ULL) -#define SECP256K1_N_H_1 ((uint64_t)0x5D576E7357A4501DULL) -#define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) -#define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL) - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_scalar_clear(rustsecp256k1zkp_v0_8_0_scalar *r) { - r->d[0] = 0; - r->d[1] = 0; - r->d[2] = 0; - r->d[3] = 0; -} - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_scalar_set_int(rustsecp256k1zkp_v0_8_0_scalar *r, unsigned int v) { - r->d[0] = v; - r->d[1] = 0; - r->d[2] = 0; - r->d[3] = 0; -} - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_scalar_set_u64(rustsecp256k1zkp_v0_8_0_scalar *r, uint64_t v) { - r->d[0] = v; - r->d[1] = 0; - r->d[2] = 0; - r->d[3] = 0; -} - -SECP256K1_INLINE static unsigned int rustsecp256k1zkp_v0_8_0_scalar_get_bits(const rustsecp256k1zkp_v0_8_0_scalar *a, unsigned int offset, unsigned int count) { - VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6); - return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1); -} - -SECP256K1_INLINE static unsigned int rustsecp256k1zkp_v0_8_0_scalar_get_bits_var(const rustsecp256k1zkp_v0_8_0_scalar *a, unsigned int offset, unsigned int count) { - VERIFY_CHECK(count < 32); - VERIFY_CHECK(offset + count <= 256); - if ((offset + count - 1) >> 6 == offset >> 6) { - return rustsecp256k1zkp_v0_8_0_scalar_get_bits(a, offset, count); - } else { - VERIFY_CHECK((offset >> 6) + 1 < 4); - return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & ((((uint64_t)1) << count) - 1); - } -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_check_overflow(const rustsecp256k1zkp_v0_8_0_scalar *a) { - int yes = 0; - int no = 0; - no |= (a->d[3] < SECP256K1_N_3); /* No need for a > check. */ - no |= (a->d[2] < SECP256K1_N_2); - yes |= (a->d[2] > SECP256K1_N_2) & ~no; - no |= (a->d[1] < SECP256K1_N_1); - yes |= (a->d[1] > SECP256K1_N_1) & ~no; - yes |= (a->d[0] >= SECP256K1_N_0) & ~no; - return yes; -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_reduce(rustsecp256k1zkp_v0_8_0_scalar *r, unsigned int overflow) { - uint128_t t; - VERIFY_CHECK(overflow <= 1); - t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0; - r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[1] + overflow * SECP256K1_N_C_1; - r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[2] + overflow * SECP256K1_N_C_2; - r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint64_t)r->d[3]; - r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; - return overflow; -} - -static int rustsecp256k1zkp_v0_8_0_scalar_add(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b) { - int overflow; - uint128_t t = (uint128_t)a->d[0] + b->d[0]; - r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[1] + b->d[1]; - r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[2] + b->d[2]; - r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[3] + b->d[3]; - r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - overflow = t + rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r); - VERIFY_CHECK(overflow == 0 || overflow == 1); - rustsecp256k1zkp_v0_8_0_scalar_reduce(r, overflow); - return overflow; -} - -static void rustsecp256k1zkp_v0_8_0_scalar_cadd_bit(rustsecp256k1zkp_v0_8_0_scalar *r, unsigned int bit, int flag) { - uint128_t t; - VERIFY_CHECK(bit < 256); - bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ - t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); - r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); - r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[2] + (((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F)); - r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[3] + (((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F)); - r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; -#ifdef VERIFY - VERIFY_CHECK((t >> 64) == 0); - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r) == 0); -#endif -} - -static void rustsecp256k1zkp_v0_8_0_scalar_set_b32(rustsecp256k1zkp_v0_8_0_scalar *r, const unsigned char *b32, int *overflow) { - int over; - r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56; - r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56; - r->d[2] = (uint64_t)b32[15] | (uint64_t)b32[14] << 8 | (uint64_t)b32[13] << 16 | (uint64_t)b32[12] << 24 | (uint64_t)b32[11] << 32 | (uint64_t)b32[10] << 40 | (uint64_t)b32[9] << 48 | (uint64_t)b32[8] << 56; - r->d[3] = (uint64_t)b32[7] | (uint64_t)b32[6] << 8 | (uint64_t)b32[5] << 16 | (uint64_t)b32[4] << 24 | (uint64_t)b32[3] << 32 | (uint64_t)b32[2] << 40 | (uint64_t)b32[1] << 48 | (uint64_t)b32[0] << 56; - over = rustsecp256k1zkp_v0_8_0_scalar_reduce(r, rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r)); - if (overflow) { - *overflow = over; - } -} - -static void rustsecp256k1zkp_v0_8_0_scalar_get_b32(unsigned char *bin, const rustsecp256k1zkp_v0_8_0_scalar* a) { - bin[0] = a->d[3] >> 56; bin[1] = a->d[3] >> 48; bin[2] = a->d[3] >> 40; bin[3] = a->d[3] >> 32; bin[4] = a->d[3] >> 24; bin[5] = a->d[3] >> 16; bin[6] = a->d[3] >> 8; bin[7] = a->d[3]; - bin[8] = a->d[2] >> 56; bin[9] = a->d[2] >> 48; bin[10] = a->d[2] >> 40; bin[11] = a->d[2] >> 32; bin[12] = a->d[2] >> 24; bin[13] = a->d[2] >> 16; bin[14] = a->d[2] >> 8; bin[15] = a->d[2]; - bin[16] = a->d[1] >> 56; bin[17] = a->d[1] >> 48; bin[18] = a->d[1] >> 40; bin[19] = a->d[1] >> 32; bin[20] = a->d[1] >> 24; bin[21] = a->d[1] >> 16; bin[22] = a->d[1] >> 8; bin[23] = a->d[1]; - bin[24] = a->d[0] >> 56; bin[25] = a->d[0] >> 48; bin[26] = a->d[0] >> 40; bin[27] = a->d[0] >> 32; bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_is_zero(const rustsecp256k1zkp_v0_8_0_scalar *a) { - return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; -} - -static void rustsecp256k1zkp_v0_8_0_scalar_negate(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a) { - uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (rustsecp256k1zkp_v0_8_0_scalar_is_zero(a) == 0); - uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1; - r->d[0] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[1]) + SECP256K1_N_1; - r->d[1] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[2]) + SECP256K1_N_2; - r->d[2] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[3]) + SECP256K1_N_3; - r->d[3] = t & nonzero; -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_is_one(const rustsecp256k1zkp_v0_8_0_scalar *a) { - return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0; -} - -static int rustsecp256k1zkp_v0_8_0_scalar_is_high(const rustsecp256k1zkp_v0_8_0_scalar *a) { - int yes = 0; - int no = 0; - no |= (a->d[3] < SECP256K1_N_H_3); - yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; - no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; /* No need for a > check. */ - no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; - yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; - yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; - return yes; -} - -static int rustsecp256k1zkp_v0_8_0_scalar_cond_negate(rustsecp256k1zkp_v0_8_0_scalar *r, int flag) { - /* If we are flag = 0, mask = 00...00 and this is a no-op; - * if we are flag = 1, mask = 11...11 and this is identical to rustsecp256k1zkp_v0_8_0_scalar_negate */ - uint64_t mask = !flag - 1; - uint64_t nonzero = (rustsecp256k1zkp_v0_8_0_scalar_is_zero(r) != 0) - 1; - uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); - r->d[0] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); - r->d[1] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); - r->d[2] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); - r->d[3] = t & nonzero; - return 2 * (mask == 0) - 1; -} - -/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ - -/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define muladd(a,b) { \ - uint64_t tl, th; \ - { \ - uint128_t t = (uint128_t)a * b; \ - th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ - tl = t; \ - } \ - c0 += tl; /* overflow is handled on the next line */ \ - th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \ - c1 += th; /* overflow is handled on the next line */ \ - c2 += (c1 < th); /* never overflows by contract (verified in the next line) */ \ - VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ -} - -/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ -#define muladd_fast(a,b) { \ - uint64_t tl, th; \ - { \ - uint128_t t = (uint128_t)a * b; \ - th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ - tl = t; \ - } \ - c0 += tl; /* overflow is handled on the next line */ \ - th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \ - c1 += th; /* never overflows by contract (verified in the next line) */ \ - VERIFY_CHECK(c1 >= th); \ -} - -/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define muladd2(a,b) { \ - uint64_t tl, th, th2, tl2; \ - { \ - uint128_t t = (uint128_t)a * b; \ - th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ - tl = t; \ - } \ - th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \ - c2 += (th2 < th); /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ - tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \ - th2 += (tl2 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \ - c0 += tl2; /* overflow is handled on the next line */ \ - th2 += (c0 < tl2); /* second overflow is handled on the next line */ \ - c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ - c1 += th2; /* overflow is handled on the next line */ \ - c2 += (c1 < th2); /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ -} - -/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define sumadd(a) { \ - unsigned int over; \ - c0 += (a); /* overflow is handled on the next line */ \ - over = (c0 < (a)); \ - c1 += over; /* overflow is handled on the next line */ \ - c2 += (c1 < over); /* never overflows by contract */ \ -} - -/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ -#define sumadd_fast(a) { \ - c0 += (a); /* overflow is handled on the next line */ \ - c1 += (c0 < (a)); /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ - VERIFY_CHECK(c2 == 0); \ -} - -/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. */ -#define extract(n) { \ - (n) = c0; \ - c0 = c1; \ - c1 = c2; \ - c2 = 0; \ -} - -/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. c2 is required to be zero. */ -#define extract_fast(n) { \ - (n) = c0; \ - c0 = c1; \ - c1 = 0; \ - VERIFY_CHECK(c2 == 0); \ -} - -static void rustsecp256k1zkp_v0_8_0_scalar_reduce_512(rustsecp256k1zkp_v0_8_0_scalar *r, const uint64_t *l) { -#ifdef USE_ASM_X86_64 - /* Reduce 512 bits into 385. */ - uint64_t m0, m1, m2, m3, m4, m5, m6; - uint64_t p0, p1, p2, p3, p4; - uint64_t c; - - __asm__ __volatile__( - /* Preload. */ - "movq 32(%%rsi), %%r11\n" - "movq 40(%%rsi), %%r12\n" - "movq 48(%%rsi), %%r13\n" - "movq 56(%%rsi), %%r14\n" - /* Initialize r8,r9,r10 */ - "movq 0(%%rsi), %%r8\n" - "xorq %%r9, %%r9\n" - "xorq %%r10, %%r10\n" - /* (r8,r9) += n0 * c0 */ - "movq %8, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - /* extract m0 */ - "movq %%r8, %q0\n" - "xorq %%r8, %%r8\n" - /* (r9,r10) += l1 */ - "addq 8(%%rsi), %%r9\n" - "adcq $0, %%r10\n" - /* (r9,r10,r8) += n1 * c0 */ - "movq %8, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += n0 * c1 */ - "movq %9, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* extract m1 */ - "movq %%r9, %q1\n" - "xorq %%r9, %%r9\n" - /* (r10,r8,r9) += l2 */ - "addq 16(%%rsi), %%r10\n" - "adcq $0, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += n2 * c0 */ - "movq %8, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += n1 * c1 */ - "movq %9, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += n0 */ - "addq %%r11, %%r10\n" - "adcq $0, %%r8\n" - "adcq $0, %%r9\n" - /* extract m2 */ - "movq %%r10, %q2\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += l3 */ - "addq 24(%%rsi), %%r8\n" - "adcq $0, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += n3 * c0 */ - "movq %8, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += n2 * c1 */ - "movq %9, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += n1 */ - "addq %%r12, %%r8\n" - "adcq $0, %%r9\n" - "adcq $0, %%r10\n" - /* extract m3 */ - "movq %%r8, %q3\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += n3 * c1 */ - "movq %9, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += n2 */ - "addq %%r13, %%r9\n" - "adcq $0, %%r10\n" - "adcq $0, %%r8\n" - /* extract m4 */ - "movq %%r9, %q4\n" - /* (r10,r8) += n3 */ - "addq %%r14, %%r10\n" - "adcq $0, %%r8\n" - /* extract m5 */ - "movq %%r10, %q5\n" - /* extract m6 */ - "movq %%r8, %q6\n" - : "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6) - : "S"(l), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) - : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc"); - - /* Reduce 385 bits into 258. */ - __asm__ __volatile__( - /* Preload */ - "movq %q9, %%r11\n" - "movq %q10, %%r12\n" - "movq %q11, %%r13\n" - /* Initialize (r8,r9,r10) */ - "movq %q5, %%r8\n" - "xorq %%r9, %%r9\n" - "xorq %%r10, %%r10\n" - /* (r8,r9) += m4 * c0 */ - "movq %12, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - /* extract p0 */ - "movq %%r8, %q0\n" - "xorq %%r8, %%r8\n" - /* (r9,r10) += m1 */ - "addq %q6, %%r9\n" - "adcq $0, %%r10\n" - /* (r9,r10,r8) += m5 * c0 */ - "movq %12, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += m4 * c1 */ - "movq %13, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* extract p1 */ - "movq %%r9, %q1\n" - "xorq %%r9, %%r9\n" - /* (r10,r8,r9) += m2 */ - "addq %q7, %%r10\n" - "adcq $0, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += m6 * c0 */ - "movq %12, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += m5 * c1 */ - "movq %13, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += m4 */ - "addq %%r11, %%r10\n" - "adcq $0, %%r8\n" - "adcq $0, %%r9\n" - /* extract p2 */ - "movq %%r10, %q2\n" - /* (r8,r9) += m3 */ - "addq %q8, %%r8\n" - "adcq $0, %%r9\n" - /* (r8,r9) += m6 * c1 */ - "movq %13, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - /* (r8,r9) += m5 */ - "addq %%r12, %%r8\n" - "adcq $0, %%r9\n" - /* extract p3 */ - "movq %%r8, %q3\n" - /* (r9) += m6 */ - "addq %%r13, %%r9\n" - /* extract p4 */ - "movq %%r9, %q4\n" - : "=&g"(p0), "=&g"(p1), "=&g"(p2), "=g"(p3), "=g"(p4) - : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) - : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc"); - - /* Reduce 258 bits into 256. */ - __asm__ __volatile__( - /* Preload */ - "movq %q5, %%r10\n" - /* (rax,rdx) = p4 * c0 */ - "movq %7, %%rax\n" - "mulq %%r10\n" - /* (rax,rdx) += p0 */ - "addq %q1, %%rax\n" - "adcq $0, %%rdx\n" - /* extract r0 */ - "movq %%rax, 0(%q6)\n" - /* Move to (r8,r9) */ - "movq %%rdx, %%r8\n" - "xorq %%r9, %%r9\n" - /* (r8,r9) += p1 */ - "addq %q2, %%r8\n" - "adcq $0, %%r9\n" - /* (r8,r9) += p4 * c1 */ - "movq %8, %%rax\n" - "mulq %%r10\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - /* Extract r1 */ - "movq %%r8, 8(%q6)\n" - "xorq %%r8, %%r8\n" - /* (r9,r8) += p4 */ - "addq %%r10, %%r9\n" - "adcq $0, %%r8\n" - /* (r9,r8) += p2 */ - "addq %q3, %%r9\n" - "adcq $0, %%r8\n" - /* Extract r2 */ - "movq %%r9, 16(%q6)\n" - "xorq %%r9, %%r9\n" - /* (r8,r9) += p3 */ - "addq %q4, %%r8\n" - "adcq $0, %%r9\n" - /* Extract r3 */ - "movq %%r8, 24(%q6)\n" - /* Extract c */ - "movq %%r9, %q0\n" - : "=g"(c) - : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) - : "rax", "rdx", "r8", "r9", "r10", "cc", "memory"); -#else - uint128_t c; - uint64_t c0, c1, c2; - uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7]; - uint64_t m0, m1, m2, m3, m4, m5; - uint32_t m6; - uint64_t p0, p1, p2, p3; - uint32_t p4; - - /* Reduce 512 bits into 385. */ - /* m[0..6] = l[0..3] + n[0..3] * SECP256K1_N_C. */ - c0 = l[0]; c1 = 0; c2 = 0; - muladd_fast(n0, SECP256K1_N_C_0); - extract_fast(m0); - sumadd_fast(l[1]); - muladd(n1, SECP256K1_N_C_0); - muladd(n0, SECP256K1_N_C_1); - extract(m1); - sumadd(l[2]); - muladd(n2, SECP256K1_N_C_0); - muladd(n1, SECP256K1_N_C_1); - sumadd(n0); - extract(m2); - sumadd(l[3]); - muladd(n3, SECP256K1_N_C_0); - muladd(n2, SECP256K1_N_C_1); - sumadd(n1); - extract(m3); - muladd(n3, SECP256K1_N_C_1); - sumadd(n2); - extract(m4); - sumadd_fast(n3); - extract_fast(m5); - VERIFY_CHECK(c0 <= 1); - m6 = c0; - - /* Reduce 385 bits into 258. */ - /* p[0..4] = m[0..3] + m[4..6] * SECP256K1_N_C. */ - c0 = m0; c1 = 0; c2 = 0; - muladd_fast(m4, SECP256K1_N_C_0); - extract_fast(p0); - sumadd_fast(m1); - muladd(m5, SECP256K1_N_C_0); - muladd(m4, SECP256K1_N_C_1); - extract(p1); - sumadd(m2); - muladd(m6, SECP256K1_N_C_0); - muladd(m5, SECP256K1_N_C_1); - sumadd(m4); - extract(p2); - sumadd_fast(m3); - muladd_fast(m6, SECP256K1_N_C_1); - sumadd_fast(m5); - extract_fast(p3); - p4 = c0 + m6; - VERIFY_CHECK(p4 <= 2); - - /* Reduce 258 bits into 256. */ - /* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */ - c = p0 + (uint128_t)SECP256K1_N_C_0 * p4; - r->d[0] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; - c += p1 + (uint128_t)SECP256K1_N_C_1 * p4; - r->d[1] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; - c += p2 + (uint128_t)p4; - r->d[2] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; - c += p3; - r->d[3] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; -#endif - - /* Final reduction of r. */ - rustsecp256k1zkp_v0_8_0_scalar_reduce(r, c + rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r)); -} - -static void rustsecp256k1zkp_v0_8_0_scalar_mul_512(uint64_t l[8], const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b) { -#ifdef USE_ASM_X86_64 - const uint64_t *pb = b->d; - __asm__ __volatile__( - /* Preload */ - "movq 0(%%rdi), %%r15\n" - "movq 8(%%rdi), %%rbx\n" - "movq 16(%%rdi), %%rcx\n" - "movq 0(%%rdx), %%r11\n" - "movq 8(%%rdx), %%r12\n" - "movq 16(%%rdx), %%r13\n" - "movq 24(%%rdx), %%r14\n" - /* (rax,rdx) = a0 * b0 */ - "movq %%r15, %%rax\n" - "mulq %%r11\n" - /* Extract l0 */ - "movq %%rax, 0(%%rsi)\n" - /* (r8,r9,r10) = (rdx) */ - "movq %%rdx, %%r8\n" - "xorq %%r9, %%r9\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += a0 * b1 */ - "movq %%r15, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += a1 * b0 */ - "movq %%rbx, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* Extract l1 */ - "movq %%r8, 8(%%rsi)\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += a0 * b2 */ - "movq %%r15, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += a1 * b1 */ - "movq %%rbx, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += a2 * b0 */ - "movq %%rcx, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* Extract l2 */ - "movq %%r9, 16(%%rsi)\n" - "xorq %%r9, %%r9\n" - /* (r10,r8,r9) += a0 * b3 */ - "movq %%r15, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* Preload a3 */ - "movq 24(%%rdi), %%r15\n" - /* (r10,r8,r9) += a1 * b2 */ - "movq %%rbx, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += a2 * b1 */ - "movq %%rcx, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += a3 * b0 */ - "movq %%r15, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* Extract l3 */ - "movq %%r10, 24(%%rsi)\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += a1 * b3 */ - "movq %%rbx, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += a2 * b2 */ - "movq %%rcx, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += a3 * b1 */ - "movq %%r15, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* Extract l4 */ - "movq %%r8, 32(%%rsi)\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += a2 * b3 */ - "movq %%rcx, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += a3 * b2 */ - "movq %%r15, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* Extract l5 */ - "movq %%r9, 40(%%rsi)\n" - /* (r10,r8) += a3 * b3 */ - "movq %%r15, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - /* Extract l6 */ - "movq %%r10, 48(%%rsi)\n" - /* Extract l7 */ - "movq %%r8, 56(%%rsi)\n" - : "+d"(pb) - : "S"(l), "D"(a->d) - : "rax", "rbx", "rcx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "cc", "memory"); -#else - /* 160 bit accumulator. */ - uint64_t c0 = 0, c1 = 0; - uint32_t c2 = 0; - - /* l[0..7] = a[0..3] * b[0..3]. */ - muladd_fast(a->d[0], b->d[0]); - extract_fast(l[0]); - muladd(a->d[0], b->d[1]); - muladd(a->d[1], b->d[0]); - extract(l[1]); - muladd(a->d[0], b->d[2]); - muladd(a->d[1], b->d[1]); - muladd(a->d[2], b->d[0]); - extract(l[2]); - muladd(a->d[0], b->d[3]); - muladd(a->d[1], b->d[2]); - muladd(a->d[2], b->d[1]); - muladd(a->d[3], b->d[0]); - extract(l[3]); - muladd(a->d[1], b->d[3]); - muladd(a->d[2], b->d[2]); - muladd(a->d[3], b->d[1]); - extract(l[4]); - muladd(a->d[2], b->d[3]); - muladd(a->d[3], b->d[2]); - extract(l[5]); - muladd_fast(a->d[3], b->d[3]); - extract_fast(l[6]); - VERIFY_CHECK(c1 == 0); - l[7] = c0; -#endif -} - -static void rustsecp256k1zkp_v0_8_0_scalar_sqr_512(uint64_t l[8], const rustsecp256k1zkp_v0_8_0_scalar *a) { -#ifdef USE_ASM_X86_64 - __asm__ __volatile__( - /* Preload */ - "movq 0(%%rdi), %%r11\n" - "movq 8(%%rdi), %%r12\n" - "movq 16(%%rdi), %%r13\n" - "movq 24(%%rdi), %%r14\n" - /* (rax,rdx) = a0 * a0 */ - "movq %%r11, %%rax\n" - "mulq %%r11\n" - /* Extract l0 */ - "movq %%rax, 0(%%rsi)\n" - /* (r8,r9,r10) = (rdx,0) */ - "movq %%rdx, %%r8\n" - "xorq %%r9, %%r9\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += 2 * a0 * a1 */ - "movq %%r11, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* Extract l1 */ - "movq %%r8, 8(%%rsi)\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += 2 * a0 * a2 */ - "movq %%r11, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += a1 * a1 */ - "movq %%r12, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* Extract l2 */ - "movq %%r9, 16(%%rsi)\n" - "xorq %%r9, %%r9\n" - /* (r10,r8,r9) += 2 * a0 * a3 */ - "movq %%r11, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += 2 * a1 * a2 */ - "movq %%r12, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* Extract l3 */ - "movq %%r10, 24(%%rsi)\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += 2 * a1 * a3 */ - "movq %%r12, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += a2 * a2 */ - "movq %%r13, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* Extract l4 */ - "movq %%r8, 32(%%rsi)\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += 2 * a2 * a3 */ - "movq %%r13, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* Extract l5 */ - "movq %%r9, 40(%%rsi)\n" - /* (r10,r8) += a3 * a3 */ - "movq %%r14, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - /* Extract l6 */ - "movq %%r10, 48(%%rsi)\n" - /* Extract l7 */ - "movq %%r8, 56(%%rsi)\n" - : - : "S"(l), "D"(a->d) - : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc", "memory"); -#else - /* 160 bit accumulator. */ - uint64_t c0 = 0, c1 = 0; - uint32_t c2 = 0; - - /* l[0..7] = a[0..3] * b[0..3]. */ - muladd_fast(a->d[0], a->d[0]); - extract_fast(l[0]); - muladd2(a->d[0], a->d[1]); - extract(l[1]); - muladd2(a->d[0], a->d[2]); - muladd(a->d[1], a->d[1]); - extract(l[2]); - muladd2(a->d[0], a->d[3]); - muladd2(a->d[1], a->d[2]); - extract(l[3]); - muladd2(a->d[1], a->d[3]); - muladd(a->d[2], a->d[2]); - extract(l[4]); - muladd2(a->d[2], a->d[3]); - extract(l[5]); - muladd_fast(a->d[3], a->d[3]); - extract_fast(l[6]); - VERIFY_CHECK(c1 == 0); - l[7] = c0; -#endif -} - -#undef sumadd -#undef sumadd_fast -#undef muladd -#undef muladd_fast -#undef muladd2 -#undef extract -#undef extract_fast - -static void rustsecp256k1zkp_v0_8_0_scalar_mul(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b) { - uint64_t l[8]; - rustsecp256k1zkp_v0_8_0_scalar_mul_512(l, a, b); - rustsecp256k1zkp_v0_8_0_scalar_reduce_512(r, l); -} - -static int rustsecp256k1zkp_v0_8_0_scalar_shr_int(rustsecp256k1zkp_v0_8_0_scalar *r, int n) { - int ret; - VERIFY_CHECK(n > 0); - VERIFY_CHECK(n < 16); - ret = r->d[0] & ((1 << n) - 1); - r->d[0] = (r->d[0] >> n) + (r->d[1] << (64 - n)); - r->d[1] = (r->d[1] >> n) + (r->d[2] << (64 - n)); - r->d[2] = (r->d[2] >> n) + (r->d[3] << (64 - n)); - r->d[3] = (r->d[3] >> n); - return ret; -} - -static void rustsecp256k1zkp_v0_8_0_scalar_sqr(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a) { - uint64_t l[8]; - rustsecp256k1zkp_v0_8_0_scalar_sqr_512(l, a); - rustsecp256k1zkp_v0_8_0_scalar_reduce_512(r, l); -} - -static void rustsecp256k1zkp_v0_8_0_scalar_split_128(rustsecp256k1zkp_v0_8_0_scalar *r1, rustsecp256k1zkp_v0_8_0_scalar *r2, const rustsecp256k1zkp_v0_8_0_scalar *k) { - r1->d[0] = k->d[0]; - r1->d[1] = k->d[1]; - r1->d[2] = 0; - r1->d[3] = 0; - r2->d[0] = k->d[2]; - r2->d[1] = k->d[3]; - r2->d[2] = 0; - r2->d[3] = 0; -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_eq(const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b) { - return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0; -} - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_scalar_mul_shift_var(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b, unsigned int shift) { - uint64_t l[8]; - unsigned int shiftlimbs; - unsigned int shiftlow; - unsigned int shifthigh; - VERIFY_CHECK(shift >= 256); - rustsecp256k1zkp_v0_8_0_scalar_mul_512(l, a, b); - shiftlimbs = shift >> 6; - shiftlow = shift & 0x3F; - shifthigh = 64 - shiftlow; - r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0; - rustsecp256k1zkp_v0_8_0_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); -} - -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_scalar_cmov(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, int flag) { - uint64_t mask0, mask1; - VG_CHECK_VERIFY(r->d, sizeof(r->d)); - mask0 = flag + ~((uint64_t)0); - mask1 = ~mask0; - r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); - r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1); - r->d[2] = (r->d[2] & mask0) | (a->d[2] & mask1); - r->d[3] = (r->d[3] & mask0) | (a->d[3] & mask1); -} - -#define ROTL32(x,n) ((x) << (n) | (x) >> (32-(n))) -#define QUARTERROUND(a,b,c,d) \ - a += b; d = ROTL32(d ^ a, 16); \ - c += d; b = ROTL32(b ^ c, 12); \ - a += b; d = ROTL32(d ^ a, 8); \ - c += d; b = ROTL32(b ^ c, 7); - -#if defined(SECP256K1_BIG_ENDIAN) -#define LE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) -#elif defined(SECP256K1_LITTLE_ENDIAN) -#define LE32(p) (p) -#endif - -static void rustsecp256k1zkp_v0_8_0_scalar_chacha20(rustsecp256k1zkp_v0_8_0_scalar *r1, rustsecp256k1zkp_v0_8_0_scalar *r2, const unsigned char *seed, uint64_t idx) { - size_t n; - size_t over_count = 0; - uint32_t seed32[8]; - uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; - int over1, over2; - - memcpy((void *) seed32, (const void *) seed, 32); - do { - x0 = 0x61707865; - x1 = 0x3320646e; - x2 = 0x79622d32; - x3 = 0x6b206574; - x4 = LE32(seed32[0]); - x5 = LE32(seed32[1]); - x6 = LE32(seed32[2]); - x7 = LE32(seed32[3]); - x8 = LE32(seed32[4]); - x9 = LE32(seed32[5]); - x10 = LE32(seed32[6]); - x11 = LE32(seed32[7]); - x12 = idx; - x13 = idx >> 32; - x14 = 0; - x15 = over_count; - - n = 10; - while (n--) { - QUARTERROUND(x0, x4, x8,x12) - QUARTERROUND(x1, x5, x9,x13) - QUARTERROUND(x2, x6,x10,x14) - QUARTERROUND(x3, x7,x11,x15) - QUARTERROUND(x0, x5,x10,x15) - QUARTERROUND(x1, x6,x11,x12) - QUARTERROUND(x2, x7, x8,x13) - QUARTERROUND(x3, x4, x9,x14) - } - - x0 += 0x61707865; - x1 += 0x3320646e; - x2 += 0x79622d32; - x3 += 0x6b206574; - x4 += LE32(seed32[0]); - x5 += LE32(seed32[1]); - x6 += LE32(seed32[2]); - x7 += LE32(seed32[3]); - x8 += LE32(seed32[4]); - x9 += LE32(seed32[5]); - x10 += LE32(seed32[6]); - x11 += LE32(seed32[7]); - x12 += idx; - x13 += idx >> 32; - x14 += 0; - x15 += over_count; - - r1->d[3] = (((uint64_t) x0) << 32) | x1; - r1->d[2] = (((uint64_t) x2) << 32) | x3; - r1->d[1] = (((uint64_t) x4) << 32) | x5; - r1->d[0] = (((uint64_t) x6) << 32) | x7; - r2->d[3] = (((uint64_t) x8) << 32) | x9; - r2->d[2] = (((uint64_t) x10) << 32) | x11; - r2->d[1] = (((uint64_t) x12) << 32) | x13; - r2->d[0] = (((uint64_t) x14) << 32) | x15; - - over1 = rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r1); - over2 = rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r2); - over_count++; - } while (over1 | over2); -} - -#undef ROTL32 -#undef QUARTERROUND -#undef LE32 - -static void rustsecp256k1zkp_v0_8_0_scalar_from_signed62(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_modinv64_signed62 *a) { - const uint64_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4]; - - /* The output from rustsecp256k1zkp_v0_8_0_modinv64{_var} should be normalized to range [0,modulus), and - * have limbs in [0,2^62). The modulus is < 2^256, so the top limb must be below 2^(256-62*4). - */ - VERIFY_CHECK(a0 >> 62 == 0); - VERIFY_CHECK(a1 >> 62 == 0); - VERIFY_CHECK(a2 >> 62 == 0); - VERIFY_CHECK(a3 >> 62 == 0); - VERIFY_CHECK(a4 >> 8 == 0); - - r->d[0] = a0 | a1 << 62; - r->d[1] = a1 >> 2 | a2 << 60; - r->d[2] = a2 >> 4 | a3 << 58; - r->d[3] = a3 >> 6 | a4 << 56; - -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r) == 0); -#endif -} - -static void rustsecp256k1zkp_v0_8_0_scalar_to_signed62(rustsecp256k1zkp_v0_8_0_modinv64_signed62 *r, const rustsecp256k1zkp_v0_8_0_scalar *a) { - const uint64_t M62 = UINT64_MAX >> 2; - const uint64_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3]; - -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_scalar_check_overflow(a) == 0); -#endif - - r->v[0] = a0 & M62; - r->v[1] = (a0 >> 62 | a1 << 2) & M62; - r->v[2] = (a1 >> 60 | a2 << 4) & M62; - r->v[3] = (a2 >> 58 | a3 << 6) & M62; - r->v[4] = a3 >> 56; -} - -static const rustsecp256k1zkp_v0_8_0_modinv64_modinfo rustsecp256k1zkp_v0_8_0_const_modinfo_scalar = { - {{0x3FD25E8CD0364141LL, 0x2ABB739ABD2280EELL, -0x15LL, 0, 256}}, - 0x34F20099AA774EC1LL -}; - -static void rustsecp256k1zkp_v0_8_0_scalar_inverse(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *x) { - rustsecp256k1zkp_v0_8_0_modinv64_signed62 s; -#ifdef VERIFY - int zero_in = rustsecp256k1zkp_v0_8_0_scalar_is_zero(x); -#endif - rustsecp256k1zkp_v0_8_0_scalar_to_signed62(&s, x); - rustsecp256k1zkp_v0_8_0_modinv64(&s, &rustsecp256k1zkp_v0_8_0_const_modinfo_scalar); - rustsecp256k1zkp_v0_8_0_scalar_from_signed62(r, &s); - -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_scalar_is_zero(r) == zero_in); -#endif -} - -static void rustsecp256k1zkp_v0_8_0_scalar_inverse_var(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *x) { - rustsecp256k1zkp_v0_8_0_modinv64_signed62 s; -#ifdef VERIFY - int zero_in = rustsecp256k1zkp_v0_8_0_scalar_is_zero(x); -#endif - rustsecp256k1zkp_v0_8_0_scalar_to_signed62(&s, x); - rustsecp256k1zkp_v0_8_0_modinv64_var(&s, &rustsecp256k1zkp_v0_8_0_const_modinfo_scalar); - rustsecp256k1zkp_v0_8_0_scalar_from_signed62(r, &s); - -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_scalar_is_zero(r) == zero_in); -#endif -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_is_even(const rustsecp256k1zkp_v0_8_0_scalar *a) { - return !(a->d[0] & 1); -} - -#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_low.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_low.h deleted file mode 100644 index 828e8cd5..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_low.h +++ /dev/null @@ -1,17 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_H -#define SECP256K1_SCALAR_REPR_H - -#include - -/** A scalar modulo the group order of the secp256k1 curve. */ -typedef uint32_t rustsecp256k1zkp_v0_8_0_scalar; - -#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) (d0) - -#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_low_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_low_impl.h deleted file mode 100644 index cf6b0028..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_low_impl.h +++ /dev/null @@ -1,149 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_IMPL_H -#define SECP256K1_SCALAR_REPR_IMPL_H - -#include "scalar.h" - -#include - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_is_even(const rustsecp256k1zkp_v0_8_0_scalar *a) { - return !(*a & 1); -} - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_scalar_clear(rustsecp256k1zkp_v0_8_0_scalar *r) { *r = 0; } -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_scalar_set_int(rustsecp256k1zkp_v0_8_0_scalar *r, unsigned int v) { *r = v; } -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_scalar_set_u64(rustsecp256k1zkp_v0_8_0_scalar *r, uint64_t v) { *r = v % EXHAUSTIVE_TEST_ORDER; } - -SECP256K1_INLINE static unsigned int rustsecp256k1zkp_v0_8_0_scalar_get_bits(const rustsecp256k1zkp_v0_8_0_scalar *a, unsigned int offset, unsigned int count) { - if (offset < 32) - return ((*a >> offset) & ((((uint32_t)1) << count) - 1)); - else - return 0; -} - -SECP256K1_INLINE static unsigned int rustsecp256k1zkp_v0_8_0_scalar_get_bits_var(const rustsecp256k1zkp_v0_8_0_scalar *a, unsigned int offset, unsigned int count) { - return rustsecp256k1zkp_v0_8_0_scalar_get_bits(a, offset, count); -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_check_overflow(const rustsecp256k1zkp_v0_8_0_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; } - -static int rustsecp256k1zkp_v0_8_0_scalar_add(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b) { - *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER; - return *r < *b; -} - -static void rustsecp256k1zkp_v0_8_0_scalar_cadd_bit(rustsecp256k1zkp_v0_8_0_scalar *r, unsigned int bit, int flag) { - if (flag && bit < 32) - *r += ((uint32_t)1 << bit); -#ifdef VERIFY - VERIFY_CHECK(bit < 32); - /* Verify that adding (1 << bit) will not overflow any in-range scalar *r by overflowing the underlying uint32_t. */ - VERIFY_CHECK(((uint32_t)1 << bit) - 1 <= UINT32_MAX - EXHAUSTIVE_TEST_ORDER); - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r) == 0); -#endif -} - -static void rustsecp256k1zkp_v0_8_0_scalar_set_b32(rustsecp256k1zkp_v0_8_0_scalar *r, const unsigned char *b32, int *overflow) { - int i; - int over = 0; - *r = 0; - for (i = 0; i < 32; i++) { - *r = (*r * 0x100) + b32[i]; - if (*r >= EXHAUSTIVE_TEST_ORDER) { - over = 1; - *r %= EXHAUSTIVE_TEST_ORDER; - } - } - if (overflow) *overflow = over; -} - -static void rustsecp256k1zkp_v0_8_0_scalar_get_b32(unsigned char *bin, const rustsecp256k1zkp_v0_8_0_scalar* a) { - memset(bin, 0, 32); - bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a; -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_is_zero(const rustsecp256k1zkp_v0_8_0_scalar *a) { - return *a == 0; -} - -static void rustsecp256k1zkp_v0_8_0_scalar_negate(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a) { - if (*a == 0) { - *r = 0; - } else { - *r = EXHAUSTIVE_TEST_ORDER - *a; - } -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_is_one(const rustsecp256k1zkp_v0_8_0_scalar *a) { - return *a == 1; -} - -static int rustsecp256k1zkp_v0_8_0_scalar_is_high(const rustsecp256k1zkp_v0_8_0_scalar *a) { - return *a > EXHAUSTIVE_TEST_ORDER / 2; -} - -static int rustsecp256k1zkp_v0_8_0_scalar_cond_negate(rustsecp256k1zkp_v0_8_0_scalar *r, int flag) { - if (flag) rustsecp256k1zkp_v0_8_0_scalar_negate(r, r); - return flag ? -1 : 1; -} - -static void rustsecp256k1zkp_v0_8_0_scalar_mul(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b) { - *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; -} - -static int rustsecp256k1zkp_v0_8_0_scalar_shr_int(rustsecp256k1zkp_v0_8_0_scalar *r, int n) { - int ret; - VERIFY_CHECK(n > 0); - VERIFY_CHECK(n < 16); - ret = *r & ((1 << n) - 1); - *r >>= n; - return ret; -} - -static void rustsecp256k1zkp_v0_8_0_scalar_sqr(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a) { - *r = (*a * *a) % EXHAUSTIVE_TEST_ORDER; -} - -static void rustsecp256k1zkp_v0_8_0_scalar_split_128(rustsecp256k1zkp_v0_8_0_scalar *r1, rustsecp256k1zkp_v0_8_0_scalar *r2, const rustsecp256k1zkp_v0_8_0_scalar *a) { - *r1 = *a; - *r2 = 0; -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_eq(const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b) { - return *a == *b; -} - -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_scalar_cmov(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, int flag) { - uint32_t mask0, mask1; - VG_CHECK_VERIFY(r, sizeof(*r)); - mask0 = flag + ~((uint32_t)0); - mask1 = ~mask0; - *r = (*r & mask0) | (*a & mask1); -} - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_scalar_chacha20(rustsecp256k1zkp_v0_8_0_scalar *r1, rustsecp256k1zkp_v0_8_0_scalar *r2, const unsigned char *seed, uint64_t n) { - *r1 = (seed[0] + n) % EXHAUSTIVE_TEST_ORDER; - *r2 = (seed[1] + n) % EXHAUSTIVE_TEST_ORDER; -} - -static void rustsecp256k1zkp_v0_8_0_scalar_inverse(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *x) { - int i; - *r = 0; - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) - if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) - *r = i; - /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus - * have a composite group order; fix it in exhaustive_tests.c). */ - VERIFY_CHECK(*r != 0); -} - -static void rustsecp256k1zkp_v0_8_0_scalar_inverse_var(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *x) { - rustsecp256k1zkp_v0_8_0_scalar_inverse(r, x); -} - -#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scratch.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scratch.h deleted file mode 100644 index ea2be4b5..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scratch.h +++ /dev/null @@ -1,42 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2017 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_SCRATCH_H -#define SECP256K1_SCRATCH_H - -/* The typedef is used internally; the struct name is used in the public API - * (where it is exposed as a different typedef) */ -typedef struct rustsecp256k1zkp_v0_8_0_scratch_space_struct { - /** guard against interpreting this object as other types */ - unsigned char magic[8]; - /** actual allocated data */ - void *data; - /** amount that has been allocated (i.e. `data + offset` is the next - * available pointer) */ - size_t alloc_size; - /** maximum size available to allocate */ - size_t max_size; -} rustsecp256k1zkp_v0_8_0_scratch; - -static rustsecp256k1zkp_v0_8_0_scratch* rustsecp256k1zkp_v0_8_0_scratch_create(const rustsecp256k1zkp_v0_8_0_callback* error_callback, size_t max_size); - -static void rustsecp256k1zkp_v0_8_0_scratch_destroy(const rustsecp256k1zkp_v0_8_0_callback* error_callback, rustsecp256k1zkp_v0_8_0_scratch* scratch); - -/** Returns an opaque object used to "checkpoint" a scratch space. Used - * with `rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint` to undo allocations. */ -static size_t rustsecp256k1zkp_v0_8_0_scratch_checkpoint(const rustsecp256k1zkp_v0_8_0_callback* error_callback, const rustsecp256k1zkp_v0_8_0_scratch* scratch); - -/** Applies a check point received from `rustsecp256k1zkp_v0_8_0_scratch_checkpoint`, - * undoing all allocations since that point. */ -static void rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(const rustsecp256k1zkp_v0_8_0_callback* error_callback, rustsecp256k1zkp_v0_8_0_scratch* scratch, size_t checkpoint); - -/** Returns the maximum allocation the scratch space will allow */ -static size_t rustsecp256k1zkp_v0_8_0_scratch_max_allocation(const rustsecp256k1zkp_v0_8_0_callback* error_callback, const rustsecp256k1zkp_v0_8_0_scratch* scratch, size_t n_objects); - -/** Returns a pointer into the most recently allocated frame, or NULL if there is insufficient available space */ -static void *rustsecp256k1zkp_v0_8_0_scratch_alloc(const rustsecp256k1zkp_v0_8_0_callback* error_callback, rustsecp256k1zkp_v0_8_0_scratch* scratch, size_t n); - -#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/secp256k1.c b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/secp256k1.c deleted file mode 100644 index ca28518a..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/secp256k1.c +++ /dev/null @@ -1,811 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#define SECP256K1_BUILD - -#include "../include/secp256k1.h" -#include "../include/secp256k1_preallocated.h" - -#include "assumptions.h" -#include "util.h" -#include "field_impl.h" -#include "scalar_impl.h" -#include "group_impl.h" -#include "eccommit_impl.h" -#include "ecmult_impl.h" -#include "ecmult_const_impl.h" -#include "ecmult_gen_impl.h" -#include "ecdsa_impl.h" -#include "eckey_impl.h" -#include "hash_impl.h" -#include "scratch_impl.h" -#include "selftest.h" - -#ifdef SECP256K1_NO_BUILD -# error "secp256k1.h processed without SECP256K1_BUILD defined while building secp256k1.c" -#endif - -#if defined(VALGRIND) -#include -#endif - -#ifdef ENABLE_MODULE_GENERATOR -#include "include/secp256k1_generator.h" -#endif - -#ifdef ENABLE_MODULE_RANGEPROOF -#include "include/secp256k1_rangeproof.h" -#endif - -#ifdef ENABLE_MODULE_ECDSA_S2C -#include "include/secp256k1_ecdsa_s2c.h" -static void rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_save(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* opening, rustsecp256k1zkp_v0_8_0_ge* ge); -#else -typedef void rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening; -static void rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_save(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* opening, rustsecp256k1zkp_v0_8_0_ge* ge) { - (void) opening; - (void) ge; - VERIFY_CHECK(0); -} -#endif - -#define ARG_CHECK(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - rustsecp256k1zkp_v0_8_0_callback_call(&ctx->illegal_callback, #cond); \ - return 0; \ - } \ -} while(0) - -#define ARG_CHECK_NO_RETURN(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - rustsecp256k1zkp_v0_8_0_callback_call(&ctx->illegal_callback, #cond); \ - } \ -} while(0) - -struct rustsecp256k1zkp_v0_8_0_context_struct { - rustsecp256k1zkp_v0_8_0_ecmult_gen_context ecmult_gen_ctx; - rustsecp256k1zkp_v0_8_0_callback illegal_callback; - rustsecp256k1zkp_v0_8_0_callback error_callback; - int declassify; -}; - -static const rustsecp256k1zkp_v0_8_0_context rustsecp256k1zkp_v0_8_0_context_no_precomp_ = { - { 0 }, - { rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn, 0 }, - { rustsecp256k1zkp_v0_8_0_default_error_callback_fn, 0 }, - 0 -}; -const rustsecp256k1zkp_v0_8_0_context *rustsecp256k1zkp_v0_8_0_context_no_precomp = &rustsecp256k1zkp_v0_8_0_context_no_precomp_; - -size_t rustsecp256k1zkp_v0_8_0_context_preallocated_size(unsigned int flags) { - size_t ret = sizeof(rustsecp256k1zkp_v0_8_0_context); - /* A return value of 0 is reserved as an indicator for errors when we call this function internally. */ - VERIFY_CHECK(ret != 0); - - if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { - rustsecp256k1zkp_v0_8_0_callback_call(&default_illegal_callback, - "Invalid flags"); - return 0; - } - - return ret; -} - -size_t rustsecp256k1zkp_v0_8_0_context_preallocated_clone_size(const rustsecp256k1zkp_v0_8_0_context* ctx) { - size_t ret = sizeof(rustsecp256k1zkp_v0_8_0_context); - VERIFY_CHECK(ctx != NULL); - return ret; -} - -rustsecp256k1zkp_v0_8_0_context* rustsecp256k1zkp_v0_8_0_context_preallocated_create(void* prealloc, unsigned int flags) { - size_t prealloc_size; - rustsecp256k1zkp_v0_8_0_context* ret; - - if (!rustsecp256k1zkp_v0_8_0_selftest()) { - rustsecp256k1zkp_v0_8_0_callback_call(&default_error_callback, "self test failed"); - } - - prealloc_size = rustsecp256k1zkp_v0_8_0_context_preallocated_size(flags); - if (prealloc_size == 0) { - return NULL; - } - VERIFY_CHECK(prealloc != NULL); - ret = (rustsecp256k1zkp_v0_8_0_context*)prealloc; - ret->illegal_callback = default_illegal_callback; - ret->error_callback = default_error_callback; - - /* Flags have been checked by rustsecp256k1zkp_v0_8_0_context_preallocated_size. */ - VERIFY_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_CONTEXT); - rustsecp256k1zkp_v0_8_0_ecmult_gen_context_build(&ret->ecmult_gen_ctx); - ret->declassify = !!(flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY); - - return ret; -} - -rustsecp256k1zkp_v0_8_0_context* rustsecp256k1zkp_v0_8_0_context_preallocated_clone(const rustsecp256k1zkp_v0_8_0_context* ctx, void* prealloc) { - rustsecp256k1zkp_v0_8_0_context* ret; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(prealloc != NULL); - - ret = (rustsecp256k1zkp_v0_8_0_context*)prealloc; - *ret = *ctx; - return ret; -} - -void rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(rustsecp256k1zkp_v0_8_0_context* ctx) { - ARG_CHECK_NO_RETURN(ctx != rustsecp256k1zkp_v0_8_0_context_no_precomp); - if (ctx != NULL) { - rustsecp256k1zkp_v0_8_0_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); - } -} - -void rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(rustsecp256k1zkp_v0_8_0_context* ctx, void (*fun)(const char* message, void* data), const void* data) { - ARG_CHECK_NO_RETURN(ctx != rustsecp256k1zkp_v0_8_0_context_no_precomp); - if (fun == NULL) { - fun = rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn; - } - ctx->illegal_callback.fn = fun; - ctx->illegal_callback.data = data; -} - -void rustsecp256k1zkp_v0_8_0_context_set_error_callback(rustsecp256k1zkp_v0_8_0_context* ctx, void (*fun)(const char* message, void* data), const void* data) { - ARG_CHECK_NO_RETURN(ctx != rustsecp256k1zkp_v0_8_0_context_no_precomp); - if (fun == NULL) { - fun = rustsecp256k1zkp_v0_8_0_default_error_callback_fn; - } - ctx->error_callback.fn = fun; - ctx->error_callback.data = data; -} - -/* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour - * of the software. This is setup for use with valgrind but could be substituted with - * the appropriate instrumentation for other analysis tools. - */ -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_declassify(const rustsecp256k1zkp_v0_8_0_context* ctx, const void *p, size_t len) { -#if defined(VALGRIND) - if (EXPECT(ctx->declassify,0)) VALGRIND_MAKE_MEM_DEFINED(p, len); -#else - (void)ctx; - (void)p; - (void)len; -#endif -} - -static int rustsecp256k1zkp_v0_8_0_pubkey_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ge* ge, const rustsecp256k1zkp_v0_8_0_pubkey* pubkey) { - if (sizeof(rustsecp256k1zkp_v0_8_0_ge_storage) == 64) { - /* When the rustsecp256k1zkp_v0_8_0_ge_storage type is exactly 64 byte, use its - * representation inside rustsecp256k1zkp_v0_8_0_pubkey, as conversion is very fast. - * Note that rustsecp256k1zkp_v0_8_0_pubkey_save must use the same representation. */ - rustsecp256k1zkp_v0_8_0_ge_storage s; - memcpy(&s, &pubkey->data[0], sizeof(s)); - rustsecp256k1zkp_v0_8_0_ge_from_storage(ge, &s); - } else { - /* Otherwise, fall back to 32-byte big endian for X and Y. */ - rustsecp256k1zkp_v0_8_0_fe x, y; - rustsecp256k1zkp_v0_8_0_fe_set_b32(&x, pubkey->data); - rustsecp256k1zkp_v0_8_0_fe_set_b32(&y, pubkey->data + 32); - rustsecp256k1zkp_v0_8_0_ge_set_xy(ge, &x, &y); - } - ARG_CHECK(!rustsecp256k1zkp_v0_8_0_fe_is_zero(&ge->x)); - return 1; -} - -static void rustsecp256k1zkp_v0_8_0_pubkey_save(rustsecp256k1zkp_v0_8_0_pubkey* pubkey, rustsecp256k1zkp_v0_8_0_ge* ge) { - if (sizeof(rustsecp256k1zkp_v0_8_0_ge_storage) == 64) { - rustsecp256k1zkp_v0_8_0_ge_storage s; - rustsecp256k1zkp_v0_8_0_ge_to_storage(&s, ge); - memcpy(&pubkey->data[0], &s, sizeof(s)); - } else { - VERIFY_CHECK(!rustsecp256k1zkp_v0_8_0_ge_is_infinity(ge)); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge->x); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge->y); - rustsecp256k1zkp_v0_8_0_fe_get_b32(pubkey->data, &ge->x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(pubkey->data + 32, &ge->y); - } -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey* pubkey, const unsigned char *input, size_t inputlen) { - rustsecp256k1zkp_v0_8_0_ge Q; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - memset(pubkey, 0, sizeof(*pubkey)); - ARG_CHECK(input != NULL); - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&Q, input, inputlen)) { - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_ge_is_in_correct_subgroup(&Q)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_pubkey_save(pubkey, &Q); - rustsecp256k1zkp_v0_8_0_ge_clear(&Q); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *output, size_t *outputlen, const rustsecp256k1zkp_v0_8_0_pubkey* pubkey, unsigned int flags) { - rustsecp256k1zkp_v0_8_0_ge Q; - size_t len; - int ret = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(outputlen != NULL); - ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33u : 65u)); - len = *outputlen; - *outputlen = 0; - ARG_CHECK(output != NULL); - memset(output, 0, len); - ARG_CHECK(pubkey != NULL); - ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); - if (rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &Q, pubkey)) { - ret = rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); - if (ret) { - *outputlen = len; - } - } - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_pubkey* pubkey0, const rustsecp256k1zkp_v0_8_0_pubkey* pubkey1) { - unsigned char out[2][33]; - const rustsecp256k1zkp_v0_8_0_pubkey* pk[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - pk[0] = pubkey0; pk[1] = pubkey1; - for (i = 0; i < 2; i++) { - size_t out_size = sizeof(out[i]); - /* If the public key is NULL or invalid, ec_pubkey_serialize will call - * the illegal_callback and return 0. In that case we will serialize the - * key as all zeros which is less than any valid public key. This - * results in consistent comparisons even if NULL or invalid pubkeys are - * involved and prevents edge cases such as sorting algorithms that use - * this function and do not terminate as a result. */ - if (!rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, out[i], &out_size, pk[i], SECP256K1_EC_COMPRESSED)) { - /* Note that ec_pubkey_serialize should already set the output to - * zero in that case, but it's not guaranteed by the API, we can't - * test it and writing a VERIFY_CHECK is more complex than - * explicitly memsetting (again). */ - memset(out[i], 0, sizeof(out[i])); - } - } - return rustsecp256k1zkp_v0_8_0_memcmp_var(out[0], out[1], sizeof(out[0])); -} - -static void rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_scalar* r, rustsecp256k1zkp_v0_8_0_scalar* s, const rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig) { - (void)ctx; - if (sizeof(rustsecp256k1zkp_v0_8_0_scalar) == 32) { - /* When the rustsecp256k1zkp_v0_8_0_scalar type is exactly 32 byte, use its - * representation inside rustsecp256k1zkp_v0_8_0_ecdsa_signature, as conversion is very fast. - * Note that rustsecp256k1zkp_v0_8_0_ecdsa_signature_save must use the same representation. */ - memcpy(r, &sig->data[0], 32); - memcpy(s, &sig->data[32], 32); - } else { - rustsecp256k1zkp_v0_8_0_scalar_set_b32(r, &sig->data[0], NULL); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(s, &sig->data[32], NULL); - } -} - -static void rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, const rustsecp256k1zkp_v0_8_0_scalar* r, const rustsecp256k1zkp_v0_8_0_scalar* s) { - if (sizeof(rustsecp256k1zkp_v0_8_0_scalar) == 32) { - memcpy(&sig->data[0], r, 32); - memcpy(&sig->data[32], s, 32); - } else { - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&sig->data[0], r); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&sig->data[32], s); - } -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(input != NULL); - - if (rustsecp256k1zkp_v0_8_0_ecdsa_sig_parse(&r, &s, input, inputlen)) { - rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(sig, &r, &s); - return 1; - } else { - memset(sig, 0, sizeof(*sig)); - return 0; - } -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, const unsigned char *input64) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - int ret = 1; - int overflow = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(input64 != NULL); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&r, &input64[0], &overflow); - ret &= !overflow; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&s, &input64[32], &overflow); - ret &= !overflow; - if (ret) { - rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(sig, &r, &s); - } else { - memset(sig, 0, sizeof(*sig)); - } - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *output, size_t *outputlen, const rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output != NULL); - ARG_CHECK(outputlen != NULL); - ARG_CHECK(sig != NULL); - - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &r, &s, sig); - return rustsecp256k1zkp_v0_8_0_ecdsa_sig_serialize(output, outputlen, &r, &s); -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *output64, const rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output64 != NULL); - ARG_CHECK(sig != NULL); - - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &r, &s, sig); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&output64[0], &r); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&output64[32], &s); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_signature *sigout, const rustsecp256k1zkp_v0_8_0_ecdsa_signature *sigin) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - int ret = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sigin != NULL); - - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &r, &s, sigin); - ret = rustsecp256k1zkp_v0_8_0_scalar_is_high(&s); - if (sigout != NULL) { - if (ret) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&s, &s); - } - rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(sigout, &r, &s); - } - - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_verify(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_ecdsa_signature *sig, const unsigned char *msghash32, const rustsecp256k1zkp_v0_8_0_pubkey *pubkey) { - rustsecp256k1zkp_v0_8_0_ge q; - rustsecp256k1zkp_v0_8_0_scalar r, s; - rustsecp256k1zkp_v0_8_0_scalar m; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(msghash32 != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(pubkey != NULL); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&m, msghash32, NULL); - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &r, &s, sig); - return (!rustsecp256k1zkp_v0_8_0_scalar_is_high(&s) && - rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &q, pubkey) && - rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&r, &s, &q, &m)); -} - -static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *offset, const void *data, unsigned int len) { - memcpy(buf + *offset, data, len); - *offset += len; -} - -static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { - unsigned char keydata[112]; - unsigned int offset = 0; - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256 rng; - unsigned int i; - rustsecp256k1zkp_v0_8_0_scalar msg; - unsigned char msgmod32[32]; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&msg, msg32, NULL); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(msgmod32, &msg); - /* We feed a byte array to the PRNG as input, consisting of: - * - the private key (32 bytes) and reduced message (32 bytes), see RFC 6979 3.2d. - * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. - * - optionally 16 extra bytes with the algorithm name. - * Because the arguments have distinct fixed lengths it is not possible for - * different argument mixtures to emulate each other and result in the same - * nonces. - */ - buffer_append(keydata, &offset, key32, 32); - buffer_append(keydata, &offset, msgmod32, 32); - if (data != NULL) { - buffer_append(keydata, &offset, data, 32); - } - if (algo16 != NULL) { - buffer_append(keydata, &offset, algo16, 16); - } - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_initialize(&rng, keydata, offset); - memset(keydata, 0, sizeof(keydata)); - for (i = 0; i <= counter; i++) { - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); - } - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_finalize(&rng); - return 1; -} - -const rustsecp256k1zkp_v0_8_0_nonce_function rustsecp256k1zkp_v0_8_0_nonce_function_rfc6979 = nonce_function_rfc6979; -const rustsecp256k1zkp_v0_8_0_nonce_function rustsecp256k1zkp_v0_8_0_nonce_function_default = nonce_function_rfc6979; - -static int rustsecp256k1zkp_v0_8_0_ecdsa_sign_inner(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_scalar* r, rustsecp256k1zkp_v0_8_0_scalar* s, int* recid, rustsecp256k1zkp_v0_8_0_sha256* s2c_sha, rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening *s2c_opening, const unsigned char* s2c_data32, const unsigned char *msg32, const unsigned char *seckey, rustsecp256k1zkp_v0_8_0_nonce_function noncefp, const void* noncedata) { - rustsecp256k1zkp_v0_8_0_scalar sec, non, msg; - int ret = 0; - int is_sec_valid; - unsigned char nonce32[32]; - unsigned int count = 0; - /* Default initialization here is important so we won't pass uninit values to the cmov in the end */ - *r = rustsecp256k1zkp_v0_8_0_scalar_zero; - *s = rustsecp256k1zkp_v0_8_0_scalar_zero; - if (recid) { - *recid = 0; - } - if (noncefp == NULL) { - noncefp = rustsecp256k1zkp_v0_8_0_nonce_function_default; - } - /* sign-to-contract commitments only work with the default nonce function, - * because we need to ensure that s2c_data is actually hashed into the nonce and - * not just ignored. Otherwise an attacker can exfiltrate the secret key by - * signing the same message thrice with different commitments. */ - VERIFY_CHECK(s2c_data32 == NULL || noncefp == rustsecp256k1zkp_v0_8_0_nonce_function_default); - - /* Fail if the secret key is invalid. */ - is_sec_valid = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&sec, seckey); - rustsecp256k1zkp_v0_8_0_scalar_cmov(&sec, &rustsecp256k1zkp_v0_8_0_scalar_one, !is_sec_valid); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&msg, msg32, NULL); - while (1) { - int is_nonce_valid; - ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); - if (!ret) { - break; - } - is_nonce_valid = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&non, nonce32); - /* The nonce is still secret here, but it being invalid is is less likely than 1:2^255. */ - rustsecp256k1zkp_v0_8_0_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid)); - if (is_nonce_valid) { - if (s2c_data32 != NULL) { - rustsecp256k1zkp_v0_8_0_gej nonce_pj; - rustsecp256k1zkp_v0_8_0_ge nonce_p; - - /* Compute original nonce commitment/pubkey */ - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_pj, &non); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&nonce_p, &nonce_pj); - if (s2c_opening != NULL) { - rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_save(s2c_opening, &nonce_p); - } - - /* Because the nonce is valid, the nonce point isn't the point - * at infinity and we can declassify that information to be able to - * serialize the point. */ - rustsecp256k1zkp_v0_8_0_declassify(ctx, &nonce_p.infinity, sizeof(nonce_p.infinity)); - - /* Tweak nonce with s2c commitment. */ - ret = rustsecp256k1zkp_v0_8_0_ec_commit_seckey(&non, &nonce_p, s2c_sha, s2c_data32, 32); - rustsecp256k1zkp_v0_8_0_declassify(ctx, &ret, sizeof(ret)); /* may be secret that the tweak falied, but happens with negligible probability */ - if (!ret) { - break; - } - } - - ret = rustsecp256k1zkp_v0_8_0_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, r, s, &sec, &msg, &non, recid); - /* The final signature is no longer a secret, nor is the fact that we were successful or not. */ - rustsecp256k1zkp_v0_8_0_declassify(ctx, &ret, sizeof(ret)); - if (ret) { - break; - } - } - count++; - } - /* We don't want to declassify is_sec_valid and therefore the range of - * seckey. As a result is_sec_valid is included in ret only after ret was - * used as a branching variable. */ - ret &= is_sec_valid; - memset(nonce32, 0, 32); - rustsecp256k1zkp_v0_8_0_scalar_clear(&msg); - rustsecp256k1zkp_v0_8_0_scalar_clear(&non); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sec); - rustsecp256k1zkp_v0_8_0_scalar_cmov(r, &rustsecp256k1zkp_v0_8_0_scalar_zero, !ret); - rustsecp256k1zkp_v0_8_0_scalar_cmov(s, &rustsecp256k1zkp_v0_8_0_scalar_zero, !ret); - if (recid) { - const int zero = 0; - rustsecp256k1zkp_v0_8_0_int_cmov(recid, &zero, !ret); - } - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_sign(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, rustsecp256k1zkp_v0_8_0_nonce_function noncefp, const void* noncedata) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - int ret; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msghash32 != NULL); - ARG_CHECK(signature != NULL); - ARG_CHECK(seckey != NULL); - - ret = rustsecp256k1zkp_v0_8_0_ecdsa_sign_inner(ctx, &r, &s, NULL, NULL, NULL, NULL, msghash32, seckey, noncefp, noncedata); - rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(signature, &r, &s); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_seckey_verify(const rustsecp256k1zkp_v0_8_0_context* ctx, const unsigned char *seckey) { - rustsecp256k1zkp_v0_8_0_scalar sec; - int ret; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - - ret = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&sec, seckey); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sec); - return ret; -} - -static int rustsecp256k1zkp_v0_8_0_ec_pubkey_create_helper(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context *ecmult_gen_ctx, rustsecp256k1zkp_v0_8_0_scalar *seckey_scalar, rustsecp256k1zkp_v0_8_0_ge *p, const unsigned char *seckey) { - rustsecp256k1zkp_v0_8_0_gej pj; - int ret; - - ret = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(seckey_scalar, seckey); - rustsecp256k1zkp_v0_8_0_scalar_cmov(seckey_scalar, &rustsecp256k1zkp_v0_8_0_scalar_one, !ret); - - rustsecp256k1zkp_v0_8_0_ecmult_gen(ecmult_gen_ctx, &pj, seckey_scalar); - rustsecp256k1zkp_v0_8_0_ge_set_gej(p, &pj); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_create(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *pubkey, const unsigned char *seckey) { - rustsecp256k1zkp_v0_8_0_ge p; - rustsecp256k1zkp_v0_8_0_scalar seckey_scalar; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - memset(pubkey, 0, sizeof(*pubkey)); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(seckey != NULL); - - ret = rustsecp256k1zkp_v0_8_0_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey); - rustsecp256k1zkp_v0_8_0_pubkey_save(pubkey, &p); - rustsecp256k1zkp_v0_8_0_memczero(pubkey, sizeof(*pubkey), !ret); - - rustsecp256k1zkp_v0_8_0_scalar_clear(&seckey_scalar); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_seckey_negate(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *seckey) { - rustsecp256k1zkp_v0_8_0_scalar sec; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - - ret = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&sec, seckey); - rustsecp256k1zkp_v0_8_0_scalar_cmov(&sec, &rustsecp256k1zkp_v0_8_0_scalar_zero, !ret); - rustsecp256k1zkp_v0_8_0_scalar_negate(&sec, &sec); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(seckey, &sec); - - rustsecp256k1zkp_v0_8_0_scalar_clear(&sec); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_privkey_negate(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *seckey) { - return rustsecp256k1zkp_v0_8_0_ec_seckey_negate(ctx, seckey); -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_negate(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *pubkey) { - int ret = 0; - rustsecp256k1zkp_v0_8_0_ge p; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - - ret = rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &p, pubkey); - memset(pubkey, 0, sizeof(*pubkey)); - if (ret) { - rustsecp256k1zkp_v0_8_0_ge_neg(&p, &p); - rustsecp256k1zkp_v0_8_0_pubkey_save(pubkey, &p); - } - return ret; -} - - -static int rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add_helper(rustsecp256k1zkp_v0_8_0_scalar *sec, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_scalar term; - int overflow = 0; - int ret = 0; - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&term, tweak32, &overflow); - ret = (!overflow) & rustsecp256k1zkp_v0_8_0_eckey_privkey_tweak_add(sec, &term); - rustsecp256k1zkp_v0_8_0_scalar_clear(&term); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_scalar sec; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - ARG_CHECK(tweak32 != NULL); - - ret = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&sec, seckey); - ret &= rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add_helper(&sec, tweak32); - rustsecp256k1zkp_v0_8_0_scalar_cmov(&sec, &rustsecp256k1zkp_v0_8_0_scalar_zero, !ret); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(seckey, &sec); - - rustsecp256k1zkp_v0_8_0_scalar_clear(&sec); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_privkey_tweak_add(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - return rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add(ctx, seckey, tweak32); -} - -static int rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add_helper(rustsecp256k1zkp_v0_8_0_ge *p, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_scalar term; - int overflow = 0; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&term, tweak32, &overflow); - return !overflow && rustsecp256k1zkp_v0_8_0_eckey_pubkey_tweak_add(p, &term); -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *pubkey, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_ge p; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(tweak32 != NULL); - - ret = rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &p, pubkey); - memset(pubkey, 0, sizeof(*pubkey)); - ret = ret && rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add_helper(&p, tweak32); - if (ret) { - rustsecp256k1zkp_v0_8_0_pubkey_save(pubkey, &p); - } - - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_scalar factor; - rustsecp256k1zkp_v0_8_0_scalar sec; - int ret = 0; - int overflow = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - ARG_CHECK(tweak32 != NULL); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&factor, tweak32, &overflow); - ret = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&sec, seckey); - ret &= (!overflow) & rustsecp256k1zkp_v0_8_0_eckey_privkey_tweak_mul(&sec, &factor); - rustsecp256k1zkp_v0_8_0_scalar_cmov(&sec, &rustsecp256k1zkp_v0_8_0_scalar_zero, !ret); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(seckey, &sec); - - rustsecp256k1zkp_v0_8_0_scalar_clear(&sec); - rustsecp256k1zkp_v0_8_0_scalar_clear(&factor); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_privkey_tweak_mul(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - return rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul(ctx, seckey, tweak32); -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_mul(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *pubkey, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_ge p; - rustsecp256k1zkp_v0_8_0_scalar factor; - int ret = 0; - int overflow = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(tweak32 != NULL); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&factor, tweak32, &overflow); - ret = !overflow && rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &p, pubkey); - memset(pubkey, 0, sizeof(*pubkey)); - if (ret) { - if (rustsecp256k1zkp_v0_8_0_eckey_pubkey_tweak_mul(&p, &factor)) { - rustsecp256k1zkp_v0_8_0_pubkey_save(pubkey, &p); - } else { - ret = 0; - } - } - - return ret; -} - -int rustsecp256k1zkp_v0_8_0_context_randomize(rustsecp256k1zkp_v0_8_0_context* ctx, const unsigned char *seed32) { - VERIFY_CHECK(ctx != NULL); - if (rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) { - rustsecp256k1zkp_v0_8_0_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); - } - return 1; -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_combine(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *pubnonce, const rustsecp256k1zkp_v0_8_0_pubkey * const *pubnonces, size_t n) { - size_t i; - rustsecp256k1zkp_v0_8_0_gej Qj; - rustsecp256k1zkp_v0_8_0_ge Q; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubnonce != NULL); - memset(pubnonce, 0, sizeof(*pubnonce)); - ARG_CHECK(n >= 1); - ARG_CHECK(pubnonces != NULL); - - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&Qj); - - for (i = 0; i < n; i++) { - ARG_CHECK(pubnonces[i] != NULL); - rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &Q, pubnonces[i]); - rustsecp256k1zkp_v0_8_0_gej_add_ge(&Qj, &Qj, &Q); - } - if (rustsecp256k1zkp_v0_8_0_gej_is_infinity(&Qj)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_ge_set_gej(&Q, &Qj); - rustsecp256k1zkp_v0_8_0_pubkey_save(pubnonce, &Q); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_tagged_sha256(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *hash32, const unsigned char *tag, size_t taglen, const unsigned char *msg, size_t msglen) { - rustsecp256k1zkp_v0_8_0_sha256 sha; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(hash32 != NULL); - ARG_CHECK(tag != NULL); - ARG_CHECK(msg != NULL); - - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, tag, taglen); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, msg, msglen); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, hash32); - return 1; -} - -#ifdef ENABLE_MODULE_BPPP -#include "modules/bppp/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_ECDH -#include "modules/ecdh/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_RECOVERY -#include "modules/recovery/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_EXTRAKEYS -#include "modules/extrakeys/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG -#include "modules/schnorrsig/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_ECDSA_S2C -#include "modules/ecdsa_s2c/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_ECDSA_ADAPTOR -#include "modules/ecdsa_adaptor/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_MUSIG -#include "modules/musig/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_GENERATOR -#include "modules/generator/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_RANGEPROOF -#include "modules/rangeproof/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_WHITELIST -#include "modules/whitelist/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_SURJECTIONPROOF -#include "modules/surjection/main_impl.h" -#endif - diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/secp256k1.c.orig b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/secp256k1.c.orig deleted file mode 100644 index b378a749..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/secp256k1.c.orig +++ /dev/null @@ -1,850 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#define SECP256K1_BUILD - -#include "../include/secp256k1.h" -#include "../include/secp256k1_preallocated.h" - -#include "assumptions.h" -#include "util.h" -#include "field_impl.h" -#include "scalar_impl.h" -#include "group_impl.h" -#include "eccommit_impl.h" -#include "ecmult_impl.h" -#include "ecmult_const_impl.h" -#include "ecmult_gen_impl.h" -#include "ecdsa_impl.h" -#include "eckey_impl.h" -#include "hash_impl.h" -#include "scratch_impl.h" -#include "selftest.h" - -#ifdef SECP256K1_NO_BUILD -# error "secp256k1.h processed without SECP256K1_BUILD defined while building secp256k1.c" -#endif - -#if defined(VALGRIND) -#include -#endif - -#ifdef ENABLE_MODULE_GENERATOR -#include "include/secp256k1_generator.h" -#endif - -#ifdef ENABLE_MODULE_RANGEPROOF -#include "include/secp256k1_rangeproof.h" -#endif - -#ifdef ENABLE_MODULE_ECDSA_S2C -#include "include/secp256k1_ecdsa_s2c.h" -static void rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_save(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* opening, rustsecp256k1zkp_v0_8_0_ge* ge); -#else -typedef void rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening; -static void rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_save(rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening* opening, rustsecp256k1zkp_v0_8_0_ge* ge) { - (void) opening; - (void) ge; - VERIFY_CHECK(0); -} -#endif - -#define ARG_CHECK(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - rustsecp256k1zkp_v0_8_0_callback_call(&ctx->illegal_callback, #cond); \ - return 0; \ - } \ -} while(0) - -#define ARG_CHECK_NO_RETURN(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - rustsecp256k1zkp_v0_8_0_callback_call(&ctx->illegal_callback, #cond); \ - } \ -} while(0) - -struct rustsecp256k1zkp_v0_8_0_context_struct { - rustsecp256k1zkp_v0_8_0_ecmult_gen_context ecmult_gen_ctx; - rustsecp256k1zkp_v0_8_0_callback illegal_callback; - rustsecp256k1zkp_v0_8_0_callback error_callback; - int declassify; -}; - -static const rustsecp256k1zkp_v0_8_0_context rustsecp256k1zkp_v0_8_0_context_no_precomp_ = { - { 0 }, - { rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn, 0 }, - { rustsecp256k1zkp_v0_8_0_default_error_callback_fn, 0 }, - 0 -}; -const rustsecp256k1zkp_v0_8_0_context *rustsecp256k1zkp_v0_8_0_context_no_precomp = &rustsecp256k1zkp_v0_8_0_context_no_precomp_; - -size_t rustsecp256k1zkp_v0_8_0_context_preallocated_size(unsigned int flags) { - size_t ret = sizeof(rustsecp256k1zkp_v0_8_0_context); - /* A return value of 0 is reserved as an indicator for errors when we call this function internally. */ - VERIFY_CHECK(ret != 0); - - if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { - rustsecp256k1zkp_v0_8_0_callback_call(&default_illegal_callback, - "Invalid flags"); - return 0; - } - - return ret; -} - -size_t rustsecp256k1zkp_v0_8_0_context_preallocated_clone_size(const rustsecp256k1zkp_v0_8_0_context* ctx) { - size_t ret = sizeof(rustsecp256k1zkp_v0_8_0_context); - VERIFY_CHECK(ctx != NULL); - return ret; -} - -rustsecp256k1zkp_v0_8_0_context* rustsecp256k1zkp_v0_8_0_context_preallocated_create(void* prealloc, unsigned int flags) { - size_t prealloc_size; - rustsecp256k1zkp_v0_8_0_context* ret; - - if (!rustsecp256k1zkp_v0_8_0_selftest()) { - rustsecp256k1zkp_v0_8_0_callback_call(&default_error_callback, "self test failed"); - } - - prealloc_size = rustsecp256k1zkp_v0_8_0_context_preallocated_size(flags); - if (prealloc_size == 0) { - return NULL; - } - VERIFY_CHECK(prealloc != NULL); - ret = (rustsecp256k1zkp_v0_8_0_context*)prealloc; - ret->illegal_callback = default_illegal_callback; - ret->error_callback = default_error_callback; - - /* Flags have been checked by rustsecp256k1zkp_v0_8_0_context_preallocated_size. */ - VERIFY_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_CONTEXT); - rustsecp256k1zkp_v0_8_0_ecmult_gen_context_build(&ret->ecmult_gen_ctx); - ret->declassify = !!(flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY); - - return ret; -} - -rustsecp256k1zkp_v0_8_0_context* rustsecp256k1zkp_v0_8_0_context_create(unsigned int flags) { - size_t const prealloc_size = rustsecp256k1zkp_v0_8_0_context_preallocated_size(flags); - rustsecp256k1zkp_v0_8_0_context* ctx = (rustsecp256k1zkp_v0_8_0_context*)checked_malloc(&default_error_callback, prealloc_size); - if (EXPECT(rustsecp256k1zkp_v0_8_0_context_preallocated_create(ctx, flags) == NULL, 0)) { - free(ctx); - return NULL; - } - - return ctx; -} - -rustsecp256k1zkp_v0_8_0_context* rustsecp256k1zkp_v0_8_0_context_preallocated_clone(const rustsecp256k1zkp_v0_8_0_context* ctx, void* prealloc) { - rustsecp256k1zkp_v0_8_0_context* ret; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(prealloc != NULL); - - ret = (rustsecp256k1zkp_v0_8_0_context*)prealloc; - *ret = *ctx; - return ret; -} - -rustsecp256k1zkp_v0_8_0_context* rustsecp256k1zkp_v0_8_0_context_clone(const rustsecp256k1zkp_v0_8_0_context* ctx) { - rustsecp256k1zkp_v0_8_0_context* ret; - size_t prealloc_size; - - VERIFY_CHECK(ctx != NULL); - prealloc_size = rustsecp256k1zkp_v0_8_0_context_preallocated_clone_size(ctx); - ret = (rustsecp256k1zkp_v0_8_0_context*)checked_malloc(&ctx->error_callback, prealloc_size); - ret = rustsecp256k1zkp_v0_8_0_context_preallocated_clone(ctx, ret); - return ret; -} - -void rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(rustsecp256k1zkp_v0_8_0_context* ctx) { - ARG_CHECK_NO_RETURN(ctx != rustsecp256k1zkp_v0_8_0_context_no_precomp); - if (ctx != NULL) { - rustsecp256k1zkp_v0_8_0_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); - } -} - -void rustsecp256k1zkp_v0_8_0_context_destroy(rustsecp256k1zkp_v0_8_0_context* ctx) { - if (ctx != NULL) { - rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(ctx); - free(ctx); - } -} - -void rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(rustsecp256k1zkp_v0_8_0_context* ctx, void (*fun)(const char* message, void* data), const void* data) { - ARG_CHECK_NO_RETURN(ctx != rustsecp256k1zkp_v0_8_0_context_no_precomp); - if (fun == NULL) { - fun = rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn; - } - ctx->illegal_callback.fn = fun; - ctx->illegal_callback.data = data; -} - -void rustsecp256k1zkp_v0_8_0_context_set_error_callback(rustsecp256k1zkp_v0_8_0_context* ctx, void (*fun)(const char* message, void* data), const void* data) { - ARG_CHECK_NO_RETURN(ctx != rustsecp256k1zkp_v0_8_0_context_no_precomp); - if (fun == NULL) { - fun = rustsecp256k1zkp_v0_8_0_default_error_callback_fn; - } - ctx->error_callback.fn = fun; - ctx->error_callback.data = data; -} - -rustsecp256k1zkp_v0_8_0_scratch_space* rustsecp256k1zkp_v0_8_0_scratch_space_create(const rustsecp256k1zkp_v0_8_0_context* ctx, size_t max_size) { - VERIFY_CHECK(ctx != NULL); - return rustsecp256k1zkp_v0_8_0_scratch_create(&ctx->error_callback, max_size); -} - -void rustsecp256k1zkp_v0_8_0_scratch_space_destroy(const rustsecp256k1zkp_v0_8_0_context *ctx, rustsecp256k1zkp_v0_8_0_scratch_space* scratch) { - VERIFY_CHECK(ctx != NULL); - rustsecp256k1zkp_v0_8_0_scratch_destroy(&ctx->error_callback, scratch); -} - -/* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour - * of the software. This is setup for use with valgrind but could be substituted with - * the appropriate instrumentation for other analysis tools. - */ -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_declassify(const rustsecp256k1zkp_v0_8_0_context* ctx, const void *p, size_t len) { -#if defined(VALGRIND) - if (EXPECT(ctx->declassify,0)) VALGRIND_MAKE_MEM_DEFINED(p, len); -#else - (void)ctx; - (void)p; - (void)len; -#endif -} - -static int rustsecp256k1zkp_v0_8_0_pubkey_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ge* ge, const rustsecp256k1zkp_v0_8_0_pubkey* pubkey) { - if (sizeof(rustsecp256k1zkp_v0_8_0_ge_storage) == 64) { - /* When the rustsecp256k1zkp_v0_8_0_ge_storage type is exactly 64 byte, use its - * representation inside rustsecp256k1zkp_v0_8_0_pubkey, as conversion is very fast. - * Note that rustsecp256k1zkp_v0_8_0_pubkey_save must use the same representation. */ - rustsecp256k1zkp_v0_8_0_ge_storage s; - memcpy(&s, &pubkey->data[0], sizeof(s)); - rustsecp256k1zkp_v0_8_0_ge_from_storage(ge, &s); - } else { - /* Otherwise, fall back to 32-byte big endian for X and Y. */ - rustsecp256k1zkp_v0_8_0_fe x, y; - rustsecp256k1zkp_v0_8_0_fe_set_b32(&x, pubkey->data); - rustsecp256k1zkp_v0_8_0_fe_set_b32(&y, pubkey->data + 32); - rustsecp256k1zkp_v0_8_0_ge_set_xy(ge, &x, &y); - } - ARG_CHECK(!rustsecp256k1zkp_v0_8_0_fe_is_zero(&ge->x)); - return 1; -} - -static void rustsecp256k1zkp_v0_8_0_pubkey_save(rustsecp256k1zkp_v0_8_0_pubkey* pubkey, rustsecp256k1zkp_v0_8_0_ge* ge) { - if (sizeof(rustsecp256k1zkp_v0_8_0_ge_storage) == 64) { - rustsecp256k1zkp_v0_8_0_ge_storage s; - rustsecp256k1zkp_v0_8_0_ge_to_storage(&s, ge); - memcpy(&pubkey->data[0], &s, sizeof(s)); - } else { - VERIFY_CHECK(!rustsecp256k1zkp_v0_8_0_ge_is_infinity(ge)); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge->x); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge->y); - rustsecp256k1zkp_v0_8_0_fe_get_b32(pubkey->data, &ge->x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(pubkey->data + 32, &ge->y); - } -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey* pubkey, const unsigned char *input, size_t inputlen) { - rustsecp256k1zkp_v0_8_0_ge Q; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - memset(pubkey, 0, sizeof(*pubkey)); - ARG_CHECK(input != NULL); - if (!rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&Q, input, inputlen)) { - return 0; - } - if (!rustsecp256k1zkp_v0_8_0_ge_is_in_correct_subgroup(&Q)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_pubkey_save(pubkey, &Q); - rustsecp256k1zkp_v0_8_0_ge_clear(&Q); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *output, size_t *outputlen, const rustsecp256k1zkp_v0_8_0_pubkey* pubkey, unsigned int flags) { - rustsecp256k1zkp_v0_8_0_ge Q; - size_t len; - int ret = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(outputlen != NULL); - ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33u : 65u)); - len = *outputlen; - *outputlen = 0; - ARG_CHECK(output != NULL); - memset(output, 0, len); - ARG_CHECK(pubkey != NULL); - ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); - if (rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &Q, pubkey)) { - ret = rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); - if (ret) { - *outputlen = len; - } - } - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_pubkey* pubkey0, const rustsecp256k1zkp_v0_8_0_pubkey* pubkey1) { - unsigned char out[2][33]; - const rustsecp256k1zkp_v0_8_0_pubkey* pk[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - pk[0] = pubkey0; pk[1] = pubkey1; - for (i = 0; i < 2; i++) { - size_t out_size = sizeof(out[i]); - /* If the public key is NULL or invalid, ec_pubkey_serialize will call - * the illegal_callback and return 0. In that case we will serialize the - * key as all zeros which is less than any valid public key. This - * results in consistent comparisons even if NULL or invalid pubkeys are - * involved and prevents edge cases such as sorting algorithms that use - * this function and do not terminate as a result. */ - if (!rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, out[i], &out_size, pk[i], SECP256K1_EC_COMPRESSED)) { - /* Note that ec_pubkey_serialize should already set the output to - * zero in that case, but it's not guaranteed by the API, we can't - * test it and writing a VERIFY_CHECK is more complex than - * explicitly memsetting (again). */ - memset(out[i], 0, sizeof(out[i])); - } - } - return rustsecp256k1zkp_v0_8_0_memcmp_var(out[0], out[1], sizeof(out[0])); -} - -static void rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_scalar* r, rustsecp256k1zkp_v0_8_0_scalar* s, const rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig) { - (void)ctx; - if (sizeof(rustsecp256k1zkp_v0_8_0_scalar) == 32) { - /* When the rustsecp256k1zkp_v0_8_0_scalar type is exactly 32 byte, use its - * representation inside rustsecp256k1zkp_v0_8_0_ecdsa_signature, as conversion is very fast. - * Note that rustsecp256k1zkp_v0_8_0_ecdsa_signature_save must use the same representation. */ - memcpy(r, &sig->data[0], 32); - memcpy(s, &sig->data[32], 32); - } else { - rustsecp256k1zkp_v0_8_0_scalar_set_b32(r, &sig->data[0], NULL); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(s, &sig->data[32], NULL); - } -} - -static void rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, const rustsecp256k1zkp_v0_8_0_scalar* r, const rustsecp256k1zkp_v0_8_0_scalar* s) { - if (sizeof(rustsecp256k1zkp_v0_8_0_scalar) == 32) { - memcpy(&sig->data[0], r, 32); - memcpy(&sig->data[32], s, 32); - } else { - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&sig->data[0], r); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&sig->data[32], s); - } -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(input != NULL); - - if (rustsecp256k1zkp_v0_8_0_ecdsa_sig_parse(&r, &s, input, inputlen)) { - rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(sig, &r, &s); - return 1; - } else { - memset(sig, 0, sizeof(*sig)); - return 0; - } -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, const unsigned char *input64) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - int ret = 1; - int overflow = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(input64 != NULL); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&r, &input64[0], &overflow); - ret &= !overflow; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&s, &input64[32], &overflow); - ret &= !overflow; - if (ret) { - rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(sig, &r, &s); - } else { - memset(sig, 0, sizeof(*sig)); - } - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *output, size_t *outputlen, const rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output != NULL); - ARG_CHECK(outputlen != NULL); - ARG_CHECK(sig != NULL); - - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &r, &s, sig); - return rustsecp256k1zkp_v0_8_0_ecdsa_sig_serialize(output, outputlen, &r, &s); -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *output64, const rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output64 != NULL); - ARG_CHECK(sig != NULL); - - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &r, &s, sig); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&output64[0], &r); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&output64[32], &s); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_signature *sigout, const rustsecp256k1zkp_v0_8_0_ecdsa_signature *sigin) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - int ret = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sigin != NULL); - - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &r, &s, sigin); - ret = rustsecp256k1zkp_v0_8_0_scalar_is_high(&s); - if (sigout != NULL) { - if (ret) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&s, &s); - } - rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(sigout, &r, &s); - } - - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_verify(const rustsecp256k1zkp_v0_8_0_context* ctx, const rustsecp256k1zkp_v0_8_0_ecdsa_signature *sig, const unsigned char *msghash32, const rustsecp256k1zkp_v0_8_0_pubkey *pubkey) { - rustsecp256k1zkp_v0_8_0_ge q; - rustsecp256k1zkp_v0_8_0_scalar r, s; - rustsecp256k1zkp_v0_8_0_scalar m; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(msghash32 != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(pubkey != NULL); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&m, msghash32, NULL); - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &r, &s, sig); - return (!rustsecp256k1zkp_v0_8_0_scalar_is_high(&s) && - rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &q, pubkey) && - rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&r, &s, &q, &m)); -} - -static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *offset, const void *data, unsigned int len) { - memcpy(buf + *offset, data, len); - *offset += len; -} - -static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { - unsigned char keydata[112]; - unsigned int offset = 0; - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256 rng; - unsigned int i; - rustsecp256k1zkp_v0_8_0_scalar msg; - unsigned char msgmod32[32]; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&msg, msg32, NULL); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(msgmod32, &msg); - /* We feed a byte array to the PRNG as input, consisting of: - * - the private key (32 bytes) and reduced message (32 bytes), see RFC 6979 3.2d. - * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. - * - optionally 16 extra bytes with the algorithm name. - * Because the arguments have distinct fixed lengths it is not possible for - * different argument mixtures to emulate each other and result in the same - * nonces. - */ - buffer_append(keydata, &offset, key32, 32); - buffer_append(keydata, &offset, msgmod32, 32); - if (data != NULL) { - buffer_append(keydata, &offset, data, 32); - } - if (algo16 != NULL) { - buffer_append(keydata, &offset, algo16, 16); - } - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_initialize(&rng, keydata, offset); - memset(keydata, 0, sizeof(keydata)); - for (i = 0; i <= counter; i++) { - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); - } - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_finalize(&rng); - return 1; -} - -const rustsecp256k1zkp_v0_8_0_nonce_function rustsecp256k1zkp_v0_8_0_nonce_function_rfc6979 = nonce_function_rfc6979; -const rustsecp256k1zkp_v0_8_0_nonce_function rustsecp256k1zkp_v0_8_0_nonce_function_default = nonce_function_rfc6979; - -static int rustsecp256k1zkp_v0_8_0_ecdsa_sign_inner(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_scalar* r, rustsecp256k1zkp_v0_8_0_scalar* s, int* recid, rustsecp256k1zkp_v0_8_0_sha256* s2c_sha, rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening *s2c_opening, const unsigned char* s2c_data32, const unsigned char *msg32, const unsigned char *seckey, rustsecp256k1zkp_v0_8_0_nonce_function noncefp, const void* noncedata) { - rustsecp256k1zkp_v0_8_0_scalar sec, non, msg; - int ret = 0; - int is_sec_valid; - unsigned char nonce32[32]; - unsigned int count = 0; - /* Default initialization here is important so we won't pass uninit values to the cmov in the end */ - *r = rustsecp256k1zkp_v0_8_0_scalar_zero; - *s = rustsecp256k1zkp_v0_8_0_scalar_zero; - if (recid) { - *recid = 0; - } - if (noncefp == NULL) { - noncefp = rustsecp256k1zkp_v0_8_0_nonce_function_default; - } - /* sign-to-contract commitments only work with the default nonce function, - * because we need to ensure that s2c_data is actually hashed into the nonce and - * not just ignored. Otherwise an attacker can exfiltrate the secret key by - * signing the same message thrice with different commitments. */ - VERIFY_CHECK(s2c_data32 == NULL || noncefp == rustsecp256k1zkp_v0_8_0_nonce_function_default); - - /* Fail if the secret key is invalid. */ - is_sec_valid = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&sec, seckey); - rustsecp256k1zkp_v0_8_0_scalar_cmov(&sec, &rustsecp256k1zkp_v0_8_0_scalar_one, !is_sec_valid); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&msg, msg32, NULL); - while (1) { - int is_nonce_valid; - ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); - if (!ret) { - break; - } - is_nonce_valid = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&non, nonce32); - /* The nonce is still secret here, but it being invalid is is less likely than 1:2^255. */ - rustsecp256k1zkp_v0_8_0_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid)); - if (is_nonce_valid) { - if (s2c_data32 != NULL) { - rustsecp256k1zkp_v0_8_0_gej nonce_pj; - rustsecp256k1zkp_v0_8_0_ge nonce_p; - - /* Compute original nonce commitment/pubkey */ - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_pj, &non); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&nonce_p, &nonce_pj); - if (s2c_opening != NULL) { - rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening_save(s2c_opening, &nonce_p); - } - - /* Because the nonce is valid, the nonce point isn't the point - * at infinity and we can declassify that information to be able to - * serialize the point. */ - rustsecp256k1zkp_v0_8_0_declassify(ctx, &nonce_p.infinity, sizeof(nonce_p.infinity)); - - /* Tweak nonce with s2c commitment. */ - ret = rustsecp256k1zkp_v0_8_0_ec_commit_seckey(&non, &nonce_p, s2c_sha, s2c_data32, 32); - rustsecp256k1zkp_v0_8_0_declassify(ctx, &ret, sizeof(ret)); /* may be secret that the tweak falied, but happens with negligible probability */ - if (!ret) { - break; - } - } - - ret = rustsecp256k1zkp_v0_8_0_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, r, s, &sec, &msg, &non, recid); - /* The final signature is no longer a secret, nor is the fact that we were successful or not. */ - rustsecp256k1zkp_v0_8_0_declassify(ctx, &ret, sizeof(ret)); - if (ret) { - break; - } - } - count++; - } - /* We don't want to declassify is_sec_valid and therefore the range of - * seckey. As a result is_sec_valid is included in ret only after ret was - * used as a branching variable. */ - ret &= is_sec_valid; - memset(nonce32, 0, 32); - rustsecp256k1zkp_v0_8_0_scalar_clear(&msg); - rustsecp256k1zkp_v0_8_0_scalar_clear(&non); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sec); - rustsecp256k1zkp_v0_8_0_scalar_cmov(r, &rustsecp256k1zkp_v0_8_0_scalar_zero, !ret); - rustsecp256k1zkp_v0_8_0_scalar_cmov(s, &rustsecp256k1zkp_v0_8_0_scalar_zero, !ret); - if (recid) { - const int zero = 0; - rustsecp256k1zkp_v0_8_0_int_cmov(recid, &zero, !ret); - } - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ecdsa_sign(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, rustsecp256k1zkp_v0_8_0_nonce_function noncefp, const void* noncedata) { - rustsecp256k1zkp_v0_8_0_scalar r, s; - int ret; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msghash32 != NULL); - ARG_CHECK(signature != NULL); - ARG_CHECK(seckey != NULL); - - ret = rustsecp256k1zkp_v0_8_0_ecdsa_sign_inner(ctx, &r, &s, NULL, NULL, NULL, NULL, msghash32, seckey, noncefp, noncedata); - rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(signature, &r, &s); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_seckey_verify(const rustsecp256k1zkp_v0_8_0_context* ctx, const unsigned char *seckey) { - rustsecp256k1zkp_v0_8_0_scalar sec; - int ret; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - - ret = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&sec, seckey); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sec); - return ret; -} - -static int rustsecp256k1zkp_v0_8_0_ec_pubkey_create_helper(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context *ecmult_gen_ctx, rustsecp256k1zkp_v0_8_0_scalar *seckey_scalar, rustsecp256k1zkp_v0_8_0_ge *p, const unsigned char *seckey) { - rustsecp256k1zkp_v0_8_0_gej pj; - int ret; - - ret = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(seckey_scalar, seckey); - rustsecp256k1zkp_v0_8_0_scalar_cmov(seckey_scalar, &rustsecp256k1zkp_v0_8_0_scalar_one, !ret); - - rustsecp256k1zkp_v0_8_0_ecmult_gen(ecmult_gen_ctx, &pj, seckey_scalar); - rustsecp256k1zkp_v0_8_0_ge_set_gej(p, &pj); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_create(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *pubkey, const unsigned char *seckey) { - rustsecp256k1zkp_v0_8_0_ge p; - rustsecp256k1zkp_v0_8_0_scalar seckey_scalar; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - memset(pubkey, 0, sizeof(*pubkey)); - ARG_CHECK(rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(seckey != NULL); - - ret = rustsecp256k1zkp_v0_8_0_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey); - rustsecp256k1zkp_v0_8_0_pubkey_save(pubkey, &p); - rustsecp256k1zkp_v0_8_0_memczero(pubkey, sizeof(*pubkey), !ret); - - rustsecp256k1zkp_v0_8_0_scalar_clear(&seckey_scalar); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_seckey_negate(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *seckey) { - rustsecp256k1zkp_v0_8_0_scalar sec; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - - ret = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&sec, seckey); - rustsecp256k1zkp_v0_8_0_scalar_cmov(&sec, &rustsecp256k1zkp_v0_8_0_scalar_zero, !ret); - rustsecp256k1zkp_v0_8_0_scalar_negate(&sec, &sec); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(seckey, &sec); - - rustsecp256k1zkp_v0_8_0_scalar_clear(&sec); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_privkey_negate(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *seckey) { - return rustsecp256k1zkp_v0_8_0_ec_seckey_negate(ctx, seckey); -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_negate(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *pubkey) { - int ret = 0; - rustsecp256k1zkp_v0_8_0_ge p; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - - ret = rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &p, pubkey); - memset(pubkey, 0, sizeof(*pubkey)); - if (ret) { - rustsecp256k1zkp_v0_8_0_ge_neg(&p, &p); - rustsecp256k1zkp_v0_8_0_pubkey_save(pubkey, &p); - } - return ret; -} - - -static int rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add_helper(rustsecp256k1zkp_v0_8_0_scalar *sec, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_scalar term; - int overflow = 0; - int ret = 0; - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&term, tweak32, &overflow); - ret = (!overflow) & rustsecp256k1zkp_v0_8_0_eckey_privkey_tweak_add(sec, &term); - rustsecp256k1zkp_v0_8_0_scalar_clear(&term); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_scalar sec; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - ARG_CHECK(tweak32 != NULL); - - ret = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&sec, seckey); - ret &= rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add_helper(&sec, tweak32); - rustsecp256k1zkp_v0_8_0_scalar_cmov(&sec, &rustsecp256k1zkp_v0_8_0_scalar_zero, !ret); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(seckey, &sec); - - rustsecp256k1zkp_v0_8_0_scalar_clear(&sec); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_privkey_tweak_add(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - return rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add(ctx, seckey, tweak32); -} - -static int rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add_helper(rustsecp256k1zkp_v0_8_0_ge *p, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_scalar term; - int overflow = 0; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&term, tweak32, &overflow); - return !overflow && rustsecp256k1zkp_v0_8_0_eckey_pubkey_tweak_add(p, &term); -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *pubkey, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_ge p; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(tweak32 != NULL); - - ret = rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &p, pubkey); - memset(pubkey, 0, sizeof(*pubkey)); - ret = ret && rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add_helper(&p, tweak32); - if (ret) { - rustsecp256k1zkp_v0_8_0_pubkey_save(pubkey, &p); - } - - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_scalar factor; - rustsecp256k1zkp_v0_8_0_scalar sec; - int ret = 0; - int overflow = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - ARG_CHECK(tweak32 != NULL); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&factor, tweak32, &overflow); - ret = rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&sec, seckey); - ret &= (!overflow) & rustsecp256k1zkp_v0_8_0_eckey_privkey_tweak_mul(&sec, &factor); - rustsecp256k1zkp_v0_8_0_scalar_cmov(&sec, &rustsecp256k1zkp_v0_8_0_scalar_zero, !ret); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(seckey, &sec); - - rustsecp256k1zkp_v0_8_0_scalar_clear(&sec); - rustsecp256k1zkp_v0_8_0_scalar_clear(&factor); - return ret; -} - -int rustsecp256k1zkp_v0_8_0_ec_privkey_tweak_mul(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - return rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul(ctx, seckey, tweak32); -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_mul(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *pubkey, const unsigned char *tweak32) { - rustsecp256k1zkp_v0_8_0_ge p; - rustsecp256k1zkp_v0_8_0_scalar factor; - int ret = 0; - int overflow = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(tweak32 != NULL); - - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&factor, tweak32, &overflow); - ret = !overflow && rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &p, pubkey); - memset(pubkey, 0, sizeof(*pubkey)); - if (ret) { - if (rustsecp256k1zkp_v0_8_0_eckey_pubkey_tweak_mul(&p, &factor)) { - rustsecp256k1zkp_v0_8_0_pubkey_save(pubkey, &p); - } else { - ret = 0; - } - } - - return ret; -} - -int rustsecp256k1zkp_v0_8_0_context_randomize(rustsecp256k1zkp_v0_8_0_context* ctx, const unsigned char *seed32) { - VERIFY_CHECK(ctx != NULL); - if (rustsecp256k1zkp_v0_8_0_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) { - rustsecp256k1zkp_v0_8_0_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); - } - return 1; -} - -int rustsecp256k1zkp_v0_8_0_ec_pubkey_combine(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_pubkey *pubnonce, const rustsecp256k1zkp_v0_8_0_pubkey * const *pubnonces, size_t n) { - size_t i; - rustsecp256k1zkp_v0_8_0_gej Qj; - rustsecp256k1zkp_v0_8_0_ge Q; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubnonce != NULL); - memset(pubnonce, 0, sizeof(*pubnonce)); - ARG_CHECK(n >= 1); - ARG_CHECK(pubnonces != NULL); - - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&Qj); - - for (i = 0; i < n; i++) { - ARG_CHECK(pubnonces[i] != NULL); - rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &Q, pubnonces[i]); - rustsecp256k1zkp_v0_8_0_gej_add_ge(&Qj, &Qj, &Q); - } - if (rustsecp256k1zkp_v0_8_0_gej_is_infinity(&Qj)) { - return 0; - } - rustsecp256k1zkp_v0_8_0_ge_set_gej(&Q, &Qj); - rustsecp256k1zkp_v0_8_0_pubkey_save(pubnonce, &Q); - return 1; -} - -int rustsecp256k1zkp_v0_8_0_tagged_sha256(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *hash32, const unsigned char *tag, size_t taglen, const unsigned char *msg, size_t msglen) { - rustsecp256k1zkp_v0_8_0_sha256 sha; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(hash32 != NULL); - ARG_CHECK(tag != NULL); - ARG_CHECK(msg != NULL); - - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, tag, taglen); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, msg, msglen); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, hash32); - return 1; -} - -#ifdef ENABLE_MODULE_BPPP -#include "modules/bppp/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_ECDH -#include "modules/ecdh/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_RECOVERY -#include "modules/recovery/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_EXTRAKEYS -#include "modules/extrakeys/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG -#include "modules/schnorrsig/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_ECDSA_S2C -#include "modules/ecdsa_s2c/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_ECDSA_ADAPTOR -#include "modules/ecdsa_adaptor/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_MUSIG -#include "modules/musig/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_GENERATOR -#include "modules/generator/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_RANGEPROOF -#include "modules/rangeproof/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_WHITELIST -#include "modules/whitelist/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_SURJECTIONPROOF -#include "modules/surjection/main_impl.h" -#endif - diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/testrand_impl.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/testrand_impl.h deleted file mode 100644 index c06e3d71..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/testrand_impl.h +++ /dev/null @@ -1,215 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille, Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_TESTRAND_IMPL_H -#define SECP256K1_TESTRAND_IMPL_H - -#include -#include -#include -#include - -#include "testrand.h" -#include "hash.h" - -static uint64_t rustsecp256k1zkp_v0_8_0_test_state[4]; -static uint64_t rustsecp256k1zkp_v0_8_0_test_rng_integer; -static int rustsecp256k1zkp_v0_8_0_test_rng_integer_bits_left = 0; - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_testrand_seed(const unsigned char *seed16) { - static const unsigned char PREFIX[19] = "secp256k1 test init"; - unsigned char out32[32]; - rustsecp256k1zkp_v0_8_0_sha256 hash; - int i; - - /* Use SHA256(PREFIX || seed16) as initial state. */ - rustsecp256k1zkp_v0_8_0_sha256_initialize(&hash); - rustsecp256k1zkp_v0_8_0_sha256_write(&hash, PREFIX, sizeof(PREFIX)); - rustsecp256k1zkp_v0_8_0_sha256_write(&hash, seed16, 16); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&hash, out32); - for (i = 0; i < 4; ++i) { - uint64_t s = 0; - int j; - for (j = 0; j < 8; ++j) s = (s << 8) | out32[8*i + j]; - rustsecp256k1zkp_v0_8_0_test_state[i] = s; - } - rustsecp256k1zkp_v0_8_0_test_rng_integer_bits_left = 0; -} - -SECP256K1_INLINE static uint64_t rotl(const uint64_t x, int k) { - return (x << k) | (x >> (64 - k)); -} - -SECP256K1_INLINE static uint64_t rustsecp256k1zkp_v0_8_0_testrand64(void) { - /* Test-only Xoshiro256++ RNG. See https://prng.di.unimi.it/ */ - const uint64_t result = rotl(rustsecp256k1zkp_v0_8_0_test_state[0] + rustsecp256k1zkp_v0_8_0_test_state[3], 23) + rustsecp256k1zkp_v0_8_0_test_state[0]; - const uint64_t t = rustsecp256k1zkp_v0_8_0_test_state[1] << 17; - rustsecp256k1zkp_v0_8_0_test_state[2] ^= rustsecp256k1zkp_v0_8_0_test_state[0]; - rustsecp256k1zkp_v0_8_0_test_state[3] ^= rustsecp256k1zkp_v0_8_0_test_state[1]; - rustsecp256k1zkp_v0_8_0_test_state[1] ^= rustsecp256k1zkp_v0_8_0_test_state[2]; - rustsecp256k1zkp_v0_8_0_test_state[0] ^= rustsecp256k1zkp_v0_8_0_test_state[3]; - rustsecp256k1zkp_v0_8_0_test_state[2] ^= t; - rustsecp256k1zkp_v0_8_0_test_state[3] = rotl(rustsecp256k1zkp_v0_8_0_test_state[3], 45); - return result; -} - -SECP256K1_INLINE static uint64_t rustsecp256k1zkp_v0_8_0_testrand_bits(int bits) { - uint64_t ret; - if (rustsecp256k1zkp_v0_8_0_test_rng_integer_bits_left < bits) { - rustsecp256k1zkp_v0_8_0_test_rng_integer = rustsecp256k1zkp_v0_8_0_testrand64(); - rustsecp256k1zkp_v0_8_0_test_rng_integer_bits_left = 64; - } - ret = rustsecp256k1zkp_v0_8_0_test_rng_integer; - rustsecp256k1zkp_v0_8_0_test_rng_integer >>= bits; - rustsecp256k1zkp_v0_8_0_test_rng_integer_bits_left -= bits; - ret &= ((~((uint64_t)0)) >> (64 - bits)); - return ret; -} - -SECP256K1_INLINE static uint32_t rustsecp256k1zkp_v0_8_0_testrand32(void) { - return rustsecp256k1zkp_v0_8_0_testrand_bits(32); -} - -static uint32_t rustsecp256k1zkp_v0_8_0_testrand_int(uint32_t range) { - /* We want a uniform integer between 0 and range-1, inclusive. - * B is the smallest number such that range <= 2**B. - * two mechanisms implemented here: - * - generate B bits numbers until one below range is found, and return it - * - find the largest multiple M of range that is <= 2**(B+A), generate B+A - * bits numbers until one below M is found, and return it modulo range - * The second mechanism consumes A more bits of entropy in every iteration, - * but may need fewer iterations due to M being closer to 2**(B+A) then - * range is to 2**B. The array below (indexed by B) contains a 0 when the - * first mechanism is to be used, and the number A otherwise. - */ - static const int addbits[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0}; - uint32_t trange, mult; - int bits = 0; - if (range <= 1) { - return 0; - } - trange = range - 1; - while (trange > 0) { - trange >>= 1; - bits++; - } - if (addbits[bits]) { - bits = bits + addbits[bits]; - mult = ((~((uint32_t)0)) >> (32 - bits)) / range; - trange = range * mult; - } else { - trange = range; - mult = 1; - } - while(1) { - uint32_t x = rustsecp256k1zkp_v0_8_0_testrand_bits(bits); - if (x < trange) { - return (mult == 1) ? x : (x % range); - } - } -} - -static void rustsecp256k1zkp_v0_8_0_testrand256(unsigned char *b32) { - int i; - for (i = 0; i < 4; ++i) { - uint64_t val = rustsecp256k1zkp_v0_8_0_testrand64(); - b32[0] = val; - b32[1] = val >> 8; - b32[2] = val >> 16; - b32[3] = val >> 24; - b32[4] = val >> 32; - b32[5] = val >> 40; - b32[6] = val >> 48; - b32[7] = val >> 56; - b32 += 8; - } -} - -static void rustsecp256k1zkp_v0_8_0_testrand_bytes_test(unsigned char *bytes, size_t len) { - size_t bits = 0; - memset(bytes, 0, len); - while (bits < len * 8) { - int now; - uint32_t val; - now = 1 + (rustsecp256k1zkp_v0_8_0_testrand_bits(6) * rustsecp256k1zkp_v0_8_0_testrand_bits(5) + 16) / 31; - val = rustsecp256k1zkp_v0_8_0_testrand_bits(1); - while (now > 0 && bits < len * 8) { - bytes[bits / 8] |= val << (bits % 8); - now--; - bits++; - } - } -} - -static void rustsecp256k1zkp_v0_8_0_testrand256_test(unsigned char *b32) { - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(b32, 32); -} - -SECP256K1_INLINE static int64_t rustsecp256k1zkp_v0_8_0_testrandi64(uint64_t min, uint64_t max) { - uint64_t range; - uint64_t r; - uint64_t clz; - VERIFY_CHECK(max >= min); - if (max == min) { - return min; - } - range = max - min; - clz = rustsecp256k1zkp_v0_8_0_clz64_var(range); - do { - r = ((uint64_t)rustsecp256k1zkp_v0_8_0_testrand32() << 32) | rustsecp256k1zkp_v0_8_0_testrand32(); - r >>= clz; - } while (r > range); - return min + (int64_t)r; -} - -static void rustsecp256k1zkp_v0_8_0_testrand_flip(unsigned char *b, size_t len) { - b[rustsecp256k1zkp_v0_8_0_testrand_int(len)] ^= (1 << rustsecp256k1zkp_v0_8_0_testrand_bits(3)); -} - -static void rustsecp256k1zkp_v0_8_0_testrand_init(const char* hexseed) { - unsigned char seed16[16] = {0}; - if (hexseed && strlen(hexseed) != 0) { - int pos = 0; - while (pos < 16 && hexseed[0] != 0 && hexseed[1] != 0) { - unsigned short sh; - if ((sscanf(hexseed, "%2hx", &sh)) == 1) { - seed16[pos] = sh; - } else { - break; - } - hexseed += 2; - pos++; - } - } else { - FILE *frand = fopen("/dev/urandom", "rb"); - if ((frand == NULL) || fread(&seed16, 1, sizeof(seed16), frand) != sizeof(seed16)) { - uint64_t t = time(NULL) * (uint64_t)1337; - fprintf(stderr, "WARNING: could not read 16 bytes from /dev/urandom; falling back to insecure PRNG\n"); - seed16[0] ^= t; - seed16[1] ^= t >> 8; - seed16[2] ^= t >> 16; - seed16[3] ^= t >> 24; - seed16[4] ^= t >> 32; - seed16[5] ^= t >> 40; - seed16[6] ^= t >> 48; - seed16[7] ^= t >> 56; - } - if (frand) { - fclose(frand); - } - } - - printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); - rustsecp256k1zkp_v0_8_0_testrand_seed(seed16); -} - -static void rustsecp256k1zkp_v0_8_0_testrand_finish(void) { - unsigned char run32[32]; - rustsecp256k1zkp_v0_8_0_testrand256(run32); - printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); -} - -#endif /* SECP256K1_TESTRAND_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/tests_exhaustive.c b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/tests_exhaustive.c deleted file mode 100644 index 5ea88fe0..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/tests_exhaustive.c +++ /dev/null @@ -1,459 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2016 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#include -#include -#include - -#ifndef EXHAUSTIVE_TEST_ORDER -/* see group_impl.h for allowable values */ -#define EXHAUSTIVE_TEST_ORDER 13 -#endif - -#include "secp256k1.c" -#include "../include/secp256k1.h" -#include "assumptions.h" -#include "group.h" -#include "testrand_impl.h" -#include "ecmult_compute_table_impl.h" -#include "ecmult_gen_compute_table_impl.h" - -static int count = 2; - -/** stolen from tests.c */ -void ge_equals_ge(const rustsecp256k1zkp_v0_8_0_ge *a, const rustsecp256k1zkp_v0_8_0_ge *b) { - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; - } - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&a->x, &b->x)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&a->y, &b->y)); -} - -void ge_equals_gej(const rustsecp256k1zkp_v0_8_0_ge *a, const rustsecp256k1zkp_v0_8_0_gej *b) { - rustsecp256k1zkp_v0_8_0_fe z2s; - rustsecp256k1zkp_v0_8_0_fe u1, u2, s1, s2; - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; - } - /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&z2s, &b->z); - rustsecp256k1zkp_v0_8_0_fe_mul(&u1, &a->x, &z2s); - u2 = b->x; rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&u2); - rustsecp256k1zkp_v0_8_0_fe_mul(&s1, &a->y, &z2s); rustsecp256k1zkp_v0_8_0_fe_mul(&s1, &s1, &b->z); - s2 = b->y; rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&s2); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&u1, &u2)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&s1, &s2)); -} - -void random_fe(rustsecp256k1zkp_v0_8_0_fe *x) { - unsigned char bin[32]; - do { - rustsecp256k1zkp_v0_8_0_testrand256(bin); - if (rustsecp256k1zkp_v0_8_0_fe_set_b32(x, bin)) { - return; - } - } while(1); -} -/** END stolen from tests.c */ - -static uint32_t num_cores = 1; -static uint32_t this_core = 0; - -SECP256K1_INLINE static int skip_section(uint64_t* iter) { - if (num_cores == 1) return 0; - *iter += 0xe7037ed1a0b428dbULL; - return ((((uint32_t)*iter ^ (*iter >> 32)) * num_cores) >> 32) != this_core; -} - -int rustsecp256k1zkp_v0_8_0_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, - const unsigned char *key32, const unsigned char *algo16, - void *data, unsigned int attempt) { - rustsecp256k1zkp_v0_8_0_scalar s; - int *idata = data; - (void)msg32; - (void)key32; - (void)algo16; - /* Some nonces cannot be used because they'd cause s and/or r to be zero. - * The signing function has retry logic here that just re-calls the nonce - * function with an increased `attempt`. So if attempt > 0 this means we - * need to change the nonce to avoid an infinite loop. */ - if (attempt > 0) { - *idata = (*idata + 1) % EXHAUSTIVE_TEST_ORDER; - } - rustsecp256k1zkp_v0_8_0_scalar_set_int(&s, *idata); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(nonce32, &s); - return 1; -} - -void test_exhaustive_endomorphism(const rustsecp256k1zkp_v0_8_0_ge *group) { - int i; - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { - rustsecp256k1zkp_v0_8_0_ge res; - rustsecp256k1zkp_v0_8_0_ge_mul_lambda(&res, &group[i]); - ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res); - } -} - -void test_exhaustive_addition(const rustsecp256k1zkp_v0_8_0_ge *group, const rustsecp256k1zkp_v0_8_0_gej *groupj) { - int i, j; - uint64_t iter = 0; - - /* Sanity-check (and check infinity functions) */ - CHECK(rustsecp256k1zkp_v0_8_0_ge_is_infinity(&group[0])); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&groupj[0])); - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { - CHECK(!rustsecp256k1zkp_v0_8_0_ge_is_infinity(&group[i])); - CHECK(!rustsecp256k1zkp_v0_8_0_gej_is_infinity(&groupj[i])); - } - - /* Check all addition formulae */ - for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { - rustsecp256k1zkp_v0_8_0_fe fe_inv; - if (skip_section(&iter)) continue; - rustsecp256k1zkp_v0_8_0_fe_inv(&fe_inv, &groupj[j].z); - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { - rustsecp256k1zkp_v0_8_0_ge zless_gej; - rustsecp256k1zkp_v0_8_0_gej tmp; - /* add_var */ - rustsecp256k1zkp_v0_8_0_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL); - ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp); - /* add_ge */ - if (j > 0) { - rustsecp256k1zkp_v0_8_0_gej_add_ge(&tmp, &groupj[i], &group[j]); - ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp); - } - /* add_ge_var */ - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL); - ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp); - /* add_zinv_var */ - zless_gej.infinity = groupj[j].infinity; - zless_gej.x = groupj[j].x; - zless_gej.y = groupj[j].y; - rustsecp256k1zkp_v0_8_0_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv); - ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp); - } - } - - /* Check doubling */ - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { - rustsecp256k1zkp_v0_8_0_gej tmp; - rustsecp256k1zkp_v0_8_0_gej_double(&tmp, &groupj[i]); - ge_equals_gej(&group[(2 * i) % EXHAUSTIVE_TEST_ORDER], &tmp); - rustsecp256k1zkp_v0_8_0_gej_double_var(&tmp, &groupj[i], NULL); - ge_equals_gej(&group[(2 * i) % EXHAUSTIVE_TEST_ORDER], &tmp); - } - - /* Check negation */ - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { - rustsecp256k1zkp_v0_8_0_ge tmp; - rustsecp256k1zkp_v0_8_0_gej tmpj; - rustsecp256k1zkp_v0_8_0_ge_neg(&tmp, &group[i]); - ge_equals_ge(&group[EXHAUSTIVE_TEST_ORDER - i], &tmp); - rustsecp256k1zkp_v0_8_0_gej_neg(&tmpj, &groupj[i]); - ge_equals_gej(&group[EXHAUSTIVE_TEST_ORDER - i], &tmpj); - } -} - -void test_exhaustive_ecmult(const rustsecp256k1zkp_v0_8_0_ge *group, const rustsecp256k1zkp_v0_8_0_gej *groupj) { - int i, j, r_log; - uint64_t iter = 0; - for (r_log = 1; r_log < EXHAUSTIVE_TEST_ORDER; r_log++) { - for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { - if (skip_section(&iter)) continue; - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { - rustsecp256k1zkp_v0_8_0_gej tmp; - rustsecp256k1zkp_v0_8_0_scalar na, ng; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&na, i); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&ng, j); - - rustsecp256k1zkp_v0_8_0_ecmult(&tmp, &groupj[r_log], &na, &ng); - ge_equals_gej(&group[(i * r_log + j) % EXHAUSTIVE_TEST_ORDER], &tmp); - - if (i > 0) { - rustsecp256k1zkp_v0_8_0_ecmult_const(&tmp, &group[i], &ng, 256); - ge_equals_gej(&group[(i * j) % EXHAUSTIVE_TEST_ORDER], &tmp); - } - } - } - } -} - -typedef struct { - rustsecp256k1zkp_v0_8_0_scalar sc[2]; - rustsecp256k1zkp_v0_8_0_ge pt[2]; -} ecmult_multi_data; - -static int ecmult_multi_callback(rustsecp256k1zkp_v0_8_0_scalar *sc, rustsecp256k1zkp_v0_8_0_ge *pt, size_t idx, void *cbdata) { - ecmult_multi_data *data = (ecmult_multi_data*) cbdata; - *sc = data->sc[idx]; - *pt = data->pt[idx]; - return 1; -} - -void test_exhaustive_ecmult_multi(const rustsecp256k1zkp_v0_8_0_context *ctx, const rustsecp256k1zkp_v0_8_0_ge *group) { - int i, j, k, x, y; - uint64_t iter = 0; - rustsecp256k1zkp_v0_8_0_scratch *scratch = rustsecp256k1zkp_v0_8_0_scratch_create(&ctx->error_callback, 4096); - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { - for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { - for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { - for (x = 0; x < EXHAUSTIVE_TEST_ORDER; x++) { - if (skip_section(&iter)) continue; - for (y = 0; y < EXHAUSTIVE_TEST_ORDER; y++) { - rustsecp256k1zkp_v0_8_0_gej tmp; - rustsecp256k1zkp_v0_8_0_scalar g_sc; - ecmult_multi_data data; - - rustsecp256k1zkp_v0_8_0_scalar_set_int(&data.sc[0], i); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&data.sc[1], j); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&g_sc, k); - data.pt[0] = group[x]; - data.pt[1] = group[y]; - - rustsecp256k1zkp_v0_8_0_ecmult_multi_var(&ctx->error_callback, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2); - ge_equals_gej(&group[(i * x + j * y + k) % EXHAUSTIVE_TEST_ORDER], &tmp); - } - } - } - } - } - rustsecp256k1zkp_v0_8_0_scratch_destroy(&ctx->error_callback, scratch); -} - -void r_from_k(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_ge *group, int k, int* overflow) { - rustsecp256k1zkp_v0_8_0_fe x; - unsigned char x_bin[32]; - k %= EXHAUSTIVE_TEST_ORDER; - x = group[k].x; - rustsecp256k1zkp_v0_8_0_fe_normalize(&x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(x_bin, &x); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(r, x_bin, overflow); -} - -void test_exhaustive_verify(const rustsecp256k1zkp_v0_8_0_context *ctx, const rustsecp256k1zkp_v0_8_0_ge *group) { - int s, r, msg, key; - uint64_t iter = 0; - for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) { - for (r = 1; r < EXHAUSTIVE_TEST_ORDER; r++) { - for (msg = 1; msg < EXHAUSTIVE_TEST_ORDER; msg++) { - for (key = 1; key < EXHAUSTIVE_TEST_ORDER; key++) { - rustsecp256k1zkp_v0_8_0_ge nonconst_ge; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig; - rustsecp256k1zkp_v0_8_0_pubkey pk; - rustsecp256k1zkp_v0_8_0_scalar sk_s, msg_s, r_s, s_s; - rustsecp256k1zkp_v0_8_0_scalar s_times_k_s, msg_plus_r_times_sk_s; - int k, should_verify; - unsigned char msg32[32]; - - if (skip_section(&iter)) continue; - - rustsecp256k1zkp_v0_8_0_scalar_set_int(&s_s, s); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&r_s, r); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&msg_s, msg); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&sk_s, key); - - /* Verify by hand */ - /* Run through every k value that gives us this r and check that *one* works. - * Note there could be none, there could be multiple, ECDSA is weird. */ - should_verify = 0; - for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { - rustsecp256k1zkp_v0_8_0_scalar check_x_s; - r_from_k(&check_x_s, group, k, NULL); - if (r_s == check_x_s) { - rustsecp256k1zkp_v0_8_0_scalar_set_int(&s_times_k_s, k); - rustsecp256k1zkp_v0_8_0_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); - rustsecp256k1zkp_v0_8_0_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); - rustsecp256k1zkp_v0_8_0_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); - should_verify |= rustsecp256k1zkp_v0_8_0_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); - } - } - /* nb we have a "high s" rule */ - should_verify &= !rustsecp256k1zkp_v0_8_0_scalar_is_high(&s_s); - - /* Verify by calling verify */ - rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(&sig, &r_s, &s_s); - memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); - rustsecp256k1zkp_v0_8_0_pubkey_save(&pk, &nonconst_ge); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(msg32, &msg_s); - CHECK(should_verify == - rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg32, &pk)); - } - } - } - } -} - -void test_exhaustive_sign(const rustsecp256k1zkp_v0_8_0_context *ctx, const rustsecp256k1zkp_v0_8_0_ge *group) { - int i, j, k; - uint64_t iter = 0; - - /* Loop */ - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { /* message */ - for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { /* key */ - if (skip_section(&iter)) continue; - for (k = 1; k < EXHAUSTIVE_TEST_ORDER; k++) { /* nonce */ - const int starting_k = k; - int ret; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig; - rustsecp256k1zkp_v0_8_0_scalar sk, msg, r, s, expected_r; - unsigned char sk32[32], msg32[32]; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&msg, i); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&sk, j); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(sk32, &sk); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(msg32, &msg); - - ret = rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig, msg32, sk32, rustsecp256k1zkp_v0_8_0_nonce_function_smallint, &k); - CHECK(ret == 1); - - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &r, &s, &sig); - /* Note that we compute expected_r *after* signing -- this is important - * because our nonce-computing function function might change k during - * signing. */ - r_from_k(&expected_r, group, k, NULL); - CHECK(r == expected_r); - CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || - (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); - - /* Overflow means we've tried every possible nonce */ - if (k < starting_k) { - break; - } - } - } - } - - /* We would like to verify zero-knowledge here by counting how often every - * possible (s, r) tuple appears, but because the group order is larger - * than the field order, when coercing the x-values to scalar values, some - * appear more often than others, so we are actually not zero-knowledge. - * (This effect also appears in the real code, but the difference is on the - * order of 1/2^128th the field order, so the deviation is not useful to a - * computationally bounded attacker.) - */ -} - -#ifdef ENABLE_MODULE_RECOVERY -#include "src/modules/recovery/tests_exhaustive_impl.h" -#endif - -#ifdef ENABLE_MODULE_EXTRAKEYS -#include "src/modules/extrakeys/tests_exhaustive_impl.h" -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG -#include "src/modules/schnorrsig/tests_exhaustive_impl.h" -#endif - -int main(int argc, char** argv) { - int i; - rustsecp256k1zkp_v0_8_0_gej groupj[EXHAUSTIVE_TEST_ORDER]; - rustsecp256k1zkp_v0_8_0_ge group[EXHAUSTIVE_TEST_ORDER]; - unsigned char rand32[32]; - rustsecp256k1zkp_v0_8_0_context *ctx; - - /* Disable buffering for stdout to improve reliability of getting - * diagnostic information. Happens right at the start of main because - * setbuf must be used before any other operation on the stream. */ - setbuf(stdout, NULL); - /* Also disable buffering for stderr because it's not guaranteed that it's - * unbuffered on all systems. */ - setbuf(stderr, NULL); - - printf("Exhaustive tests for order %lu\n", (unsigned long)EXHAUSTIVE_TEST_ORDER); - - /* find iteration count */ - if (argc > 1) { - count = strtol(argv[1], NULL, 0); - } - printf("test count = %i\n", count); - - /* find random seed */ - rustsecp256k1zkp_v0_8_0_testrand_init(argc > 2 ? argv[2] : NULL); - - /* set up split processing */ - if (argc > 4) { - num_cores = strtol(argv[3], NULL, 0); - this_core = strtol(argv[4], NULL, 0); - if (num_cores < 1 || this_core >= num_cores) { - fprintf(stderr, "Usage: %s [count] [seed] [numcores] [thiscore]\n", argv[0]); - return 1; - } - printf("running tests for core %lu (out of [0..%lu])\n", (unsigned long)this_core, (unsigned long)num_cores - 1); - } - - /* Recreate the ecmult{,_gen} tables using the right generator (as selected via EXHAUSTIVE_TEST_ORDER) */ - rustsecp256k1zkp_v0_8_0_ecmult_gen_compute_table(&rustsecp256k1zkp_v0_8_0_ecmult_gen_prec_table[0][0], &rustsecp256k1zkp_v0_8_0_ge_const_g, ECMULT_GEN_PREC_BITS); - rustsecp256k1zkp_v0_8_0_ecmult_compute_two_tables(rustsecp256k1zkp_v0_8_0_pre_g, rustsecp256k1zkp_v0_8_0_pre_g_128, WINDOW_G, &rustsecp256k1zkp_v0_8_0_ge_const_g); - - while (count--) { - /* Build context */ - ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_testrand256(rand32); - CHECK(rustsecp256k1zkp_v0_8_0_context_randomize(ctx, rand32)); - - /* Generate the entire group */ - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&groupj[0]); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&group[0], &groupj[0]); - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { - rustsecp256k1zkp_v0_8_0_gej_add_ge(&groupj[i], &groupj[i - 1], &rustsecp256k1zkp_v0_8_0_ge_const_g); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&group[i], &groupj[i]); - if (count != 0) { - /* Set a different random z-value for each Jacobian point, except z=1 - is used in the last iteration. */ - rustsecp256k1zkp_v0_8_0_fe z; - random_fe(&z); - rustsecp256k1zkp_v0_8_0_gej_rescale(&groupj[i], &z); - } - - /* Verify against ecmult_gen */ - { - rustsecp256k1zkp_v0_8_0_scalar scalar_i; - rustsecp256k1zkp_v0_8_0_gej generatedj; - rustsecp256k1zkp_v0_8_0_ge generated; - - rustsecp256k1zkp_v0_8_0_scalar_set_int(&scalar_i, i); - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&generated, &generatedj); - - CHECK(group[i].infinity == 0); - CHECK(generated.infinity == 0); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&generated.x, &group[i].x)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&generated.y, &group[i].y)); - } - } - - /* Run the tests */ - test_exhaustive_endomorphism(group); - test_exhaustive_addition(group, groupj); - test_exhaustive_ecmult(group, groupj); - test_exhaustive_ecmult_multi(ctx, group); - test_exhaustive_sign(ctx, group); - test_exhaustive_verify(ctx, group); - -#ifdef ENABLE_MODULE_RECOVERY - test_exhaustive_recovery(ctx, group); -#endif -#ifdef ENABLE_MODULE_EXTRAKEYS - test_exhaustive_extrakeys(ctx, group); -#endif -#ifdef ENABLE_MODULE_SCHNORRSIG - test_exhaustive_schnorrsig(ctx); -#endif - - rustsecp256k1zkp_v0_8_0_context_destroy(ctx); - } - - rustsecp256k1zkp_v0_8_0_testrand_finish(); - - printf("no problems found\n"); - return 0; -} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/util.h b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/util.h deleted file mode 100644 index e1d1ba7e..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/util.h +++ /dev/null @@ -1,367 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille, Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_UTIL_H -#define SECP256K1_UTIL_H - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#include -#include -#include -#include - -typedef struct { - void (*fn)(const char *text, void* data); - const void* data; -} rustsecp256k1zkp_v0_8_0_callback; - -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_callback_call(const rustsecp256k1zkp_v0_8_0_callback * const cb, const char * const text) { - cb->fn(text, (void*)cb->data); -} - -#ifndef USE_EXTERNAL_DEFAULT_CALLBACKS -static void rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn(const char* str, void* data) { - (void)data; - fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); - abort(); -} -static void rustsecp256k1zkp_v0_8_0_default_error_callback_fn(const char* str, void* data) { - (void)data; - fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); - abort(); -} -#else -void rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn(const char* str, void* data); -void rustsecp256k1zkp_v0_8_0_default_error_callback_fn(const char* str, void* data); -#endif - -static const rustsecp256k1zkp_v0_8_0_callback default_illegal_callback = { - rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn, - NULL -}; - -static const rustsecp256k1zkp_v0_8_0_callback default_error_callback = { - rustsecp256k1zkp_v0_8_0_default_error_callback_fn, - NULL -}; - - -#ifdef DETERMINISTIC -#define TEST_FAILURE(msg) do { \ - fprintf(stderr, "%s\n", msg); \ - abort(); \ -} while(0); -#else -#define TEST_FAILURE(msg) do { \ - fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, msg); \ - abort(); \ -} while(0) -#endif - -#if SECP256K1_GNUC_PREREQ(3, 0) -#define EXPECT(x,c) __builtin_expect((x),(c)) -#else -#define EXPECT(x,c) (x) -#endif - -#ifdef DETERMINISTIC -#define CHECK(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - TEST_FAILURE("test condition failed"); \ - } \ -} while(0) -#else -#define CHECK(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - TEST_FAILURE("test condition failed: " #cond); \ - } \ -} while(0) -#endif - -/* Like assert(), but when VERIFY is defined, and side-effect safe. */ -#if defined(COVERAGE) -#define VERIFY_CHECK(check) -#define VERIFY_SETUP(stmt) -#elif defined(VERIFY) -#define VERIFY_CHECK CHECK -#define VERIFY_SETUP(stmt) do { stmt; } while(0) -#else -#define VERIFY_CHECK(cond) do { (void)(cond); } while(0) -#define VERIFY_SETUP(stmt) -#endif - -/* Define `VG_UNDEF` and `VG_CHECK` when VALGRIND is defined */ -#if !defined(VG_CHECK) -# if defined(VALGRIND) -# include -# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) -# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) -# else -# define VG_UNDEF(x,y) -# define VG_CHECK(x,y) -# endif -#endif - -/* Like `VG_CHECK` but on VERIFY only */ -#if defined(VERIFY) -#define VG_CHECK_VERIFY(x,y) VG_CHECK((x), (y)) -#else -#define VG_CHECK_VERIFY(x,y) -#endif - -#if defined(__BIGGEST_ALIGNMENT__) -#define ALIGNMENT __BIGGEST_ALIGNMENT__ -#else -/* Using 16 bytes alignment because common architectures never have alignment - * requirements above 8 for any of the types we care about. In addition we - * leave some room because currently we don't care about a few bytes. */ -#define ALIGNMENT 16 -#endif - -#define ROUND_TO_ALIGN(size) ((((size) + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT) - -/* Extract the sign of an int64, take the abs and return a uint64, constant time. */ -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_sign_and_abs64(uint64_t *out, int64_t in) { - uint64_t mask0, mask1; - int ret; - ret = in < 0; - mask0 = ret + ~((uint64_t)0); - mask1 = ~mask0; - *out = (uint64_t)in; - *out = (*out & mask0) | ((~*out + 1) & mask1); - return ret; -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_clz64_var(uint64_t x) { - int ret; - if (!x) { - return 64; - } -# if defined(HAVE_BUILTIN_CLZLL) - ret = __builtin_clzll(x); -# else - /*FIXME: debruijn fallback. */ - for (ret = 0; ((x & (1ULL << 63)) == 0); x <<= 1, ret++); -# endif - return ret; -} - -/* Macro for restrict, when available and not in a VERIFY build. */ -#if defined(SECP256K1_BUILD) && defined(VERIFY) -# define SECP256K1_RESTRICT -#else -# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) -# if SECP256K1_GNUC_PREREQ(3,0) -# define SECP256K1_RESTRICT __restrict__ -# elif (defined(_MSC_VER) && _MSC_VER >= 1400) -# define SECP256K1_RESTRICT __restrict -# else -# define SECP256K1_RESTRICT -# endif -# else -# define SECP256K1_RESTRICT restrict -# endif -#endif - -#if defined(_WIN32) -# define I64FORMAT "I64d" -# define I64uFORMAT "I64u" -#else -# define I64FORMAT "lld" -# define I64uFORMAT "llu" -#endif - -#if defined(__GNUC__) -# define SECP256K1_GNUC_EXT __extension__ -#else -# define SECP256K1_GNUC_EXT -#endif - -/* If SECP256K1_{LITTLE,BIG}_ENDIAN is not explicitly provided, infer from various other system macros. */ -#if !defined(SECP256K1_LITTLE_ENDIAN) && !defined(SECP256K1_BIG_ENDIAN) -/* Inspired by https://github.com/rofl0r/endianness.h/blob/9853923246b065a3b52d2c43835f3819a62c7199/endianness.h#L52L73 */ -# if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ - defined(_X86_) || defined(__x86_64__) || defined(__i386__) || \ - defined(__i486__) || defined(__i586__) || defined(__i686__) || \ - defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) || \ - defined(__ARMEL__) || defined(__AARCH64EL__) || \ - (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \ - (defined(_LITTLE_ENDIAN) && _LITTLE_ENDIAN == 1) || \ - defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM) /* MSVC */ -# define SECP256K1_LITTLE_ENDIAN -# endif -# if (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ - defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) || \ - defined(__MICROBLAZEEB__) || defined(__ARMEB__) || defined(__AARCH64EB__) || \ - (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \ - (defined(_BIG_ENDIAN) && _BIG_ENDIAN == 1) -# define SECP256K1_BIG_ENDIAN -# endif -#endif -#if defined(SECP256K1_LITTLE_ENDIAN) == defined(SECP256K1_BIG_ENDIAN) -# error Please make sure that either SECP256K1_LITTLE_ENDIAN or SECP256K1_BIG_ENDIAN is set, see src/util.h. -#endif - -/* Zero memory if flag == 1. Flag must be 0 or 1. Constant time. */ -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_memczero(void *s, size_t len, int flag) { - unsigned char *p = (unsigned char *)s; - /* Access flag with a volatile-qualified lvalue. - This prevents clang from figuring out (after inlining) that flag can - take only be 0 or 1, which leads to variable time code. */ - volatile int vflag = flag; - unsigned char mask = -(unsigned char) vflag; - while (len) { - *p &= ~mask; - p++; - len--; - } -} - -/** Semantics like memcmp. Variable-time. - * - * We use this to avoid possible compiler bugs with memcmp, e.g. - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189 - */ -static SECP256K1_INLINE int rustsecp256k1zkp_v0_8_0_memcmp_var(const void *s1, const void *s2, size_t n) { - const unsigned char *p1 = s1, *p2 = s2; - size_t i; - - for (i = 0; i < n; i++) { - int diff = p1[i] - p2[i]; - if (diff != 0) { - return diff; - } - } - return 0; -} - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized and non-negative.*/ -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_int_cmov(int *r, const int *a, int flag) { - unsigned int mask0, mask1, r_masked, a_masked; - /* Access flag with a volatile-qualified lvalue. - This prevents clang from figuring out (after inlining) that flag can - take only be 0 or 1, which leads to variable time code. */ - volatile int vflag = flag; - - /* Casting a negative int to unsigned and back to int is implementation defined behavior */ - VERIFY_CHECK(*r >= 0 && *a >= 0); - - mask0 = (unsigned int)vflag + ~0u; - mask1 = ~mask0; - r_masked = ((unsigned int)*r & mask0); - a_masked = ((unsigned int)*a & mask1); - - *r = (int)(r_masked | a_masked); -} - -/* If USE_FORCE_WIDEMUL_{INT128,INT64} is set, use that wide multiplication implementation. - * Otherwise use the presence of __SIZEOF_INT128__ to decide. - */ -#if defined(USE_FORCE_WIDEMUL_INT128) -# define SECP256K1_WIDEMUL_INT128 1 -#elif defined(USE_FORCE_WIDEMUL_INT64) -# define SECP256K1_WIDEMUL_INT64 1 -#elif defined(UINT128_MAX) || defined(__SIZEOF_INT128__) -# define SECP256K1_WIDEMUL_INT128 1 -#else -# define SECP256K1_WIDEMUL_INT64 1 -#endif -#if defined(SECP256K1_WIDEMUL_INT128) -# if !defined(UINT128_MAX) && defined(__SIZEOF_INT128__) -SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; -SECP256K1_GNUC_EXT typedef __int128 int128_t; -#define UINT128_MAX ((uint128_t)(-1)) -#define INT128_MAX ((int128_t)(UINT128_MAX >> 1)) -#define INT128_MIN (-INT128_MAX - 1) -/* No (U)INT128_C macros because compilers providing __int128 do not support 128-bit literals. */ -# endif -#endif - -#ifndef __has_builtin -#define __has_builtin(x) 0 -#endif - -/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. - * This function is only intended to be used as fallback for - * rustsecp256k1zkp_v0_8_0_ctz32_var, but permits it to be tested separately. */ -static SECP256K1_INLINE int rustsecp256k1zkp_v0_8_0_ctz32_var_debruijn(uint32_t x) { - static const uint8_t debruijn[32] = { - 0x00, 0x01, 0x02, 0x18, 0x03, 0x13, 0x06, 0x19, 0x16, 0x04, 0x14, 0x0A, - 0x10, 0x07, 0x0C, 0x1A, 0x1F, 0x17, 0x12, 0x05, 0x15, 0x09, 0x0F, 0x0B, - 0x1E, 0x11, 0x08, 0x0E, 0x1D, 0x0D, 0x1C, 0x1B - }; - return debruijn[((x & -x) * 0x04D7651F) >> 27]; -} - -/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. - * This function is only intended to be used as fallback for - * rustsecp256k1zkp_v0_8_0_ctz64_var, but permits it to be tested separately. */ -static SECP256K1_INLINE int rustsecp256k1zkp_v0_8_0_ctz64_var_debruijn(uint64_t x) { - static const uint8_t debruijn[64] = { - 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, - 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, - 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, - 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 - }; - return debruijn[((x & -x) * 0x022FDD63CC95386D) >> 58]; -} - -/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. */ -static SECP256K1_INLINE int rustsecp256k1zkp_v0_8_0_ctz32_var(uint32_t x) { - VERIFY_CHECK(x != 0); -#if (__has_builtin(__builtin_ctz) || SECP256K1_GNUC_PREREQ(3,4)) - /* If the unsigned type is sufficient to represent the largest uint32_t, consider __builtin_ctz. */ - if (((unsigned)UINT32_MAX) == UINT32_MAX) { - return __builtin_ctz(x); - } -#endif -#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4)) - /* Otherwise consider __builtin_ctzl (the unsigned long type is always at least 32 bits). */ - return __builtin_ctzl(x); -#else - /* If no suitable CTZ builtin is available, use a (variable time) software emulation. */ - return rustsecp256k1zkp_v0_8_0_ctz32_var_debruijn(x); -#endif -} - -/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. */ -static SECP256K1_INLINE int rustsecp256k1zkp_v0_8_0_ctz64_var(uint64_t x) { - VERIFY_CHECK(x != 0); -#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4)) - /* If the unsigned long type is sufficient to represent the largest uint64_t, consider __builtin_ctzl. */ - if (((unsigned long)UINT64_MAX) == UINT64_MAX) { - return __builtin_ctzl(x); - } -#endif -#if (__has_builtin(__builtin_ctzll) || SECP256K1_GNUC_PREREQ(3,4)) - /* Otherwise consider __builtin_ctzll (the unsigned long long type is always at least 64 bits). */ - return __builtin_ctzll(x); -#else - /* If no suitable CTZ builtin is available, use a (variable time) software emulation. */ - return rustsecp256k1zkp_v0_8_0_ctz64_var_debruijn(x); -#endif -} - -/* Read a uint32_t in big endian */ -SECP256K1_INLINE static uint32_t rustsecp256k1zkp_v0_8_0_read_be32(const unsigned char* p) { - return (uint32_t)p[0] << 24 | - (uint32_t)p[1] << 16 | - (uint32_t)p[2] << 8 | - (uint32_t)p[3]; -} - -/* Write a uint32_t in big endian */ -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_write_be32(unsigned char* p, uint32_t x) { - p[3] = x; - p[2] = x >> 8; - p[1] = x >> 16; - p[0] = x >> 24; -} - -#endif /* SECP256K1_UTIL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/util.h.orig b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/util.h.orig deleted file mode 100644 index d8f8a954..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/util.h.orig +++ /dev/null @@ -1,383 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille, Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_UTIL_H -#define SECP256K1_UTIL_H - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#include -#include -#include -#include - -typedef struct { - void (*fn)(const char *text, void* data); - const void* data; -} rustsecp256k1zkp_v0_8_0_callback; - -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_callback_call(const rustsecp256k1zkp_v0_8_0_callback * const cb, const char * const text) { - cb->fn(text, (void*)cb->data); -} - -#ifndef USE_EXTERNAL_DEFAULT_CALLBACKS -static void rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn(const char* str, void* data) { - (void)data; - fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); - abort(); -} -static void rustsecp256k1zkp_v0_8_0_default_error_callback_fn(const char* str, void* data) { - (void)data; - fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); - abort(); -} -#else -void rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn(const char* str, void* data); -void rustsecp256k1zkp_v0_8_0_default_error_callback_fn(const char* str, void* data); -#endif - -static const rustsecp256k1zkp_v0_8_0_callback default_illegal_callback = { - rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn, - NULL -}; - -static const rustsecp256k1zkp_v0_8_0_callback default_error_callback = { - rustsecp256k1zkp_v0_8_0_default_error_callback_fn, - NULL -}; - - -#ifdef DETERMINISTIC -#define TEST_FAILURE(msg) do { \ - fprintf(stderr, "%s\n", msg); \ - abort(); \ -} while(0); -#else -#define TEST_FAILURE(msg) do { \ - fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, msg); \ - abort(); \ -} while(0) -#endif - -#if SECP256K1_GNUC_PREREQ(3, 0) -#define EXPECT(x,c) __builtin_expect((x),(c)) -#else -#define EXPECT(x,c) (x) -#endif - -#ifdef DETERMINISTIC -#define CHECK(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - TEST_FAILURE("test condition failed"); \ - } \ -} while(0) -#else -#define CHECK(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - TEST_FAILURE("test condition failed: " #cond); \ - } \ -} while(0) -#endif - -/* Like assert(), but when VERIFY is defined, and side-effect safe. */ -#if defined(COVERAGE) -#define VERIFY_CHECK(check) -#define VERIFY_SETUP(stmt) -#elif defined(VERIFY) -#define VERIFY_CHECK CHECK -#define VERIFY_SETUP(stmt) do { stmt; } while(0) -#else -#define VERIFY_CHECK(cond) do { (void)(cond); } while(0) -#define VERIFY_SETUP(stmt) -#endif - -/* Define `VG_UNDEF` and `VG_CHECK` when VALGRIND is defined */ -#if !defined(VG_CHECK) -# if defined(VALGRIND) -# include -# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) -# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) -# else -# define VG_UNDEF(x,y) -# define VG_CHECK(x,y) -# endif -#endif - -/* Like `VG_CHECK` but on VERIFY only */ -#if defined(VERIFY) -#define VG_CHECK_VERIFY(x,y) VG_CHECK((x), (y)) -#else -#define VG_CHECK_VERIFY(x,y) -#endif - -static SECP256K1_INLINE void *checked_malloc(const rustsecp256k1zkp_v0_8_0_callback* cb, size_t size) { - void *ret = malloc(size); - if (ret == NULL) { - rustsecp256k1zkp_v0_8_0_callback_call(cb, "Out of memory"); - } - return ret; -} - -static SECP256K1_INLINE void *checked_realloc(const rustsecp256k1zkp_v0_8_0_callback* cb, void *ptr, size_t size) { - void *ret = realloc(ptr, size); - if (ret == NULL) { - rustsecp256k1zkp_v0_8_0_callback_call(cb, "Out of memory"); - } - return ret; -} - -#if defined(__BIGGEST_ALIGNMENT__) -#define ALIGNMENT __BIGGEST_ALIGNMENT__ -#else -/* Using 16 bytes alignment because common architectures never have alignment - * requirements above 8 for any of the types we care about. In addition we - * leave some room because currently we don't care about a few bytes. */ -#define ALIGNMENT 16 -#endif - -#define ROUND_TO_ALIGN(size) ((((size) + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT) - -/* Extract the sign of an int64, take the abs and return a uint64, constant time. */ -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_sign_and_abs64(uint64_t *out, int64_t in) { - uint64_t mask0, mask1; - int ret; - ret = in < 0; - mask0 = ret + ~((uint64_t)0); - mask1 = ~mask0; - *out = (uint64_t)in; - *out = (*out & mask0) | ((~*out + 1) & mask1); - return ret; -} - -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_clz64_var(uint64_t x) { - int ret; - if (!x) { - return 64; - } -# if defined(HAVE_BUILTIN_CLZLL) - ret = __builtin_clzll(x); -# else - /*FIXME: debruijn fallback. */ - for (ret = 0; ((x & (1ULL << 63)) == 0); x <<= 1, ret++); -# endif - return ret; -} - -/* Macro for restrict, when available and not in a VERIFY build. */ -#if defined(SECP256K1_BUILD) && defined(VERIFY) -# define SECP256K1_RESTRICT -#else -# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) -# if SECP256K1_GNUC_PREREQ(3,0) -# define SECP256K1_RESTRICT __restrict__ -# elif (defined(_MSC_VER) && _MSC_VER >= 1400) -# define SECP256K1_RESTRICT __restrict -# else -# define SECP256K1_RESTRICT -# endif -# else -# define SECP256K1_RESTRICT restrict -# endif -#endif - -#if defined(_WIN32) -# define I64FORMAT "I64d" -# define I64uFORMAT "I64u" -#else -# define I64FORMAT "lld" -# define I64uFORMAT "llu" -#endif - -#if defined(__GNUC__) -# define SECP256K1_GNUC_EXT __extension__ -#else -# define SECP256K1_GNUC_EXT -#endif - -/* If SECP256K1_{LITTLE,BIG}_ENDIAN is not explicitly provided, infer from various other system macros. */ -#if !defined(SECP256K1_LITTLE_ENDIAN) && !defined(SECP256K1_BIG_ENDIAN) -/* Inspired by https://github.com/rofl0r/endianness.h/blob/9853923246b065a3b52d2c43835f3819a62c7199/endianness.h#L52L73 */ -# if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ - defined(_X86_) || defined(__x86_64__) || defined(__i386__) || \ - defined(__i486__) || defined(__i586__) || defined(__i686__) || \ - defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) || \ - defined(__ARMEL__) || defined(__AARCH64EL__) || \ - (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \ - (defined(_LITTLE_ENDIAN) && _LITTLE_ENDIAN == 1) || \ - defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM) /* MSVC */ -# define SECP256K1_LITTLE_ENDIAN -# endif -# if (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ - defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) || \ - defined(__MICROBLAZEEB__) || defined(__ARMEB__) || defined(__AARCH64EB__) || \ - (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \ - (defined(_BIG_ENDIAN) && _BIG_ENDIAN == 1) -# define SECP256K1_BIG_ENDIAN -# endif -#endif -#if defined(SECP256K1_LITTLE_ENDIAN) == defined(SECP256K1_BIG_ENDIAN) -# error Please make sure that either SECP256K1_LITTLE_ENDIAN or SECP256K1_BIG_ENDIAN is set, see src/util.h. -#endif - -/* Zero memory if flag == 1. Flag must be 0 or 1. Constant time. */ -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_memczero(void *s, size_t len, int flag) { - unsigned char *p = (unsigned char *)s; - /* Access flag with a volatile-qualified lvalue. - This prevents clang from figuring out (after inlining) that flag can - take only be 0 or 1, which leads to variable time code. */ - volatile int vflag = flag; - unsigned char mask = -(unsigned char) vflag; - while (len) { - *p &= ~mask; - p++; - len--; - } -} - -/** Semantics like memcmp. Variable-time. - * - * We use this to avoid possible compiler bugs with memcmp, e.g. - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189 - */ -static SECP256K1_INLINE int rustsecp256k1zkp_v0_8_0_memcmp_var(const void *s1, const void *s2, size_t n) { - const unsigned char *p1 = s1, *p2 = s2; - size_t i; - - for (i = 0; i < n; i++) { - int diff = p1[i] - p2[i]; - if (diff != 0) { - return diff; - } - } - return 0; -} - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized and non-negative.*/ -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_int_cmov(int *r, const int *a, int flag) { - unsigned int mask0, mask1, r_masked, a_masked; - /* Access flag with a volatile-qualified lvalue. - This prevents clang from figuring out (after inlining) that flag can - take only be 0 or 1, which leads to variable time code. */ - volatile int vflag = flag; - - /* Casting a negative int to unsigned and back to int is implementation defined behavior */ - VERIFY_CHECK(*r >= 0 && *a >= 0); - - mask0 = (unsigned int)vflag + ~0u; - mask1 = ~mask0; - r_masked = ((unsigned int)*r & mask0); - a_masked = ((unsigned int)*a & mask1); - - *r = (int)(r_masked | a_masked); -} - -/* If USE_FORCE_WIDEMUL_{INT128,INT64} is set, use that wide multiplication implementation. - * Otherwise use the presence of __SIZEOF_INT128__ to decide. - */ -#if defined(USE_FORCE_WIDEMUL_INT128) -# define SECP256K1_WIDEMUL_INT128 1 -#elif defined(USE_FORCE_WIDEMUL_INT64) -# define SECP256K1_WIDEMUL_INT64 1 -#elif defined(UINT128_MAX) || defined(__SIZEOF_INT128__) -# define SECP256K1_WIDEMUL_INT128 1 -#else -# define SECP256K1_WIDEMUL_INT64 1 -#endif -#if defined(SECP256K1_WIDEMUL_INT128) -# if !defined(UINT128_MAX) && defined(__SIZEOF_INT128__) -SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; -SECP256K1_GNUC_EXT typedef __int128 int128_t; -#define UINT128_MAX ((uint128_t)(-1)) -#define INT128_MAX ((int128_t)(UINT128_MAX >> 1)) -#define INT128_MIN (-INT128_MAX - 1) -/* No (U)INT128_C macros because compilers providing __int128 do not support 128-bit literals. */ -# endif -#endif - -#ifndef __has_builtin -#define __has_builtin(x) 0 -#endif - -/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. - * This function is only intended to be used as fallback for - * rustsecp256k1zkp_v0_8_0_ctz32_var, but permits it to be tested separately. */ -static SECP256K1_INLINE int rustsecp256k1zkp_v0_8_0_ctz32_var_debruijn(uint32_t x) { - static const uint8_t debruijn[32] = { - 0x00, 0x01, 0x02, 0x18, 0x03, 0x13, 0x06, 0x19, 0x16, 0x04, 0x14, 0x0A, - 0x10, 0x07, 0x0C, 0x1A, 0x1F, 0x17, 0x12, 0x05, 0x15, 0x09, 0x0F, 0x0B, - 0x1E, 0x11, 0x08, 0x0E, 0x1D, 0x0D, 0x1C, 0x1B - }; - return debruijn[((x & -x) * 0x04D7651F) >> 27]; -} - -/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. - * This function is only intended to be used as fallback for - * rustsecp256k1zkp_v0_8_0_ctz64_var, but permits it to be tested separately. */ -static SECP256K1_INLINE int rustsecp256k1zkp_v0_8_0_ctz64_var_debruijn(uint64_t x) { - static const uint8_t debruijn[64] = { - 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, - 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, - 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, - 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 - }; - return debruijn[((x & -x) * 0x022FDD63CC95386D) >> 58]; -} - -/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. */ -static SECP256K1_INLINE int rustsecp256k1zkp_v0_8_0_ctz32_var(uint32_t x) { - VERIFY_CHECK(x != 0); -#if (__has_builtin(__builtin_ctz) || SECP256K1_GNUC_PREREQ(3,4)) - /* If the unsigned type is sufficient to represent the largest uint32_t, consider __builtin_ctz. */ - if (((unsigned)UINT32_MAX) == UINT32_MAX) { - return __builtin_ctz(x); - } -#endif -#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4)) - /* Otherwise consider __builtin_ctzl (the unsigned long type is always at least 32 bits). */ - return __builtin_ctzl(x); -#else - /* If no suitable CTZ builtin is available, use a (variable time) software emulation. */ - return rustsecp256k1zkp_v0_8_0_ctz32_var_debruijn(x); -#endif -} - -/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. */ -static SECP256K1_INLINE int rustsecp256k1zkp_v0_8_0_ctz64_var(uint64_t x) { - VERIFY_CHECK(x != 0); -#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4)) - /* If the unsigned long type is sufficient to represent the largest uint64_t, consider __builtin_ctzl. */ - if (((unsigned long)UINT64_MAX) == UINT64_MAX) { - return __builtin_ctzl(x); - } -#endif -#if (__has_builtin(__builtin_ctzll) || SECP256K1_GNUC_PREREQ(3,4)) - /* Otherwise consider __builtin_ctzll (the unsigned long long type is always at least 64 bits). */ - return __builtin_ctzll(x); -#else - /* If no suitable CTZ builtin is available, use a (variable time) software emulation. */ - return rustsecp256k1zkp_v0_8_0_ctz64_var_debruijn(x); -#endif -} - -/* Read a uint32_t in big endian */ -SECP256K1_INLINE static uint32_t rustsecp256k1zkp_v0_8_0_read_be32(const unsigned char* p) { - return (uint32_t)p[0] << 24 | - (uint32_t)p[1] << 16 | - (uint32_t)p[2] << 8 | - (uint32_t)p[3]; -} - -/* Write a uint32_t in big endian */ -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_write_be32(unsigned char* p, uint32_t x) { - p[3] = x; - p[2] = x >> 8; - p[1] = x >> 16; - p[0] = x >> 24; -} - -#endif /* SECP256K1_UTIL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/valgrind_ctime_test.c b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/valgrind_ctime_test.c deleted file mode 100644 index 547f6063..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/valgrind_ctime_test.c +++ /dev/null @@ -1,315 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2020 Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#include -#include -#include - -#include "../include/secp256k1.h" -#include "assumptions.h" -#include "util.h" - -#ifdef ENABLE_MODULE_ECDH -#include "../include/secp256k1_ecdh.h" -#endif - -#ifdef ENABLE_MODULE_RECOVERY -#include "../include/secp256k1_recovery.h" -#endif - -#ifdef ENABLE_MODULE_EXTRAKEYS -#include "../include/secp256k1_extrakeys.h" -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG -#include "../include/secp256k1_schnorrsig.h" -#endif - -#ifdef ENABLE_MODULE_ECDSA_S2C -#include "include/secp256k1_ecdsa_s2c.h" -#endif - -#ifdef ENABLE_MODULE_ECDSA_ADAPTOR -#include "include/secp256k1_ecdsa_adaptor.h" -#endif - -#ifdef ENABLE_MODULE_MUSIG -#include "include/secp256k1_musig.h" -#endif - -void run_tests(rustsecp256k1zkp_v0_8_0_context *ctx, unsigned char *key); - -int main(void) { - rustsecp256k1zkp_v0_8_0_context* ctx; - unsigned char key[32]; - int ret, i; - - if (!RUNNING_ON_VALGRIND) { - fprintf(stderr, "This test can only usefully be run inside valgrind.\n"); - fprintf(stderr, "Usage: libtool --mode=execute valgrind ./valgrind_ctime_test\n"); - return 1; - } - ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN - | SECP256K1_CONTEXT_VERIFY - | SECP256K1_CONTEXT_DECLASSIFY); - /** In theory, testing with a single secret input should be sufficient: - * If control flow depended on secrets the tool would generate an error. - */ - for (i = 0; i < 32; i++) { - key[i] = i + 65; - } - - run_tests(ctx, key); - - /* Test context randomisation. Do this last because it leaves the context - * tainted. */ - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - ret = rustsecp256k1zkp_v0_8_0_context_randomize(ctx, key); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret); - - rustsecp256k1zkp_v0_8_0_context_destroy(ctx); - return 0; -} - -void run_tests(rustsecp256k1zkp_v0_8_0_context *ctx, unsigned char *key) { - rustsecp256k1zkp_v0_8_0_ecdsa_signature signature; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - size_t siglen = 74; - size_t outputlen = 33; - int i; - int ret; - unsigned char msg[32]; - unsigned char sig[74]; - unsigned char spubkey[33]; -#ifdef ENABLE_MODULE_RECOVERY - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature recoverable_signature; - int recid; -#endif -#ifdef ENABLE_MODULE_EXTRAKEYS - rustsecp256k1zkp_v0_8_0_keypair keypair; -#endif - - for (i = 0; i < 32; i++) { - msg[i] = i + 1; - } - - /* Test keygen. */ - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - ret = rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, key); - VALGRIND_MAKE_MEM_DEFINED(&pubkey, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, spubkey, &outputlen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - - /* Test signing. */ - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - ret = rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &signature, msg, key, NULL, NULL); - VALGRIND_MAKE_MEM_DEFINED(&signature, sizeof(rustsecp256k1zkp_v0_8_0_ecdsa_signature)); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature)); - -#ifdef ENABLE_MODULE_ECDH - /* Test ECDH. */ - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - ret = rustsecp256k1zkp_v0_8_0_ecdh(ctx, msg, &pubkey, key, NULL, NULL); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); -#endif - -#ifdef ENABLE_MODULE_RECOVERY - /* Test signing a recoverable signature. */ - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - ret = rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(ctx, &recoverable_signature, msg, key, NULL, NULL); - VALGRIND_MAKE_MEM_DEFINED(&recoverable_signature, sizeof(recoverable_signature)); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recoverable_signature)); - CHECK(recid >= 0 && recid <= 3); -#endif - - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - ret = rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, key); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - ret = rustsecp256k1zkp_v0_8_0_ec_seckey_negate(ctx, key); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - VALGRIND_MAKE_MEM_UNDEFINED(msg, 32); - ret = rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add(ctx, key, msg); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - VALGRIND_MAKE_MEM_UNDEFINED(msg, 32); - ret = rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul(ctx, key, msg); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - - /* Test keypair_create and keypair_xonly_tweak_add. */ -#ifdef ENABLE_MODULE_EXTRAKEYS - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - ret = rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, key); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - - /* The tweak is not treated as a secret in keypair_tweak_add */ - VALGRIND_MAKE_MEM_DEFINED(msg, 32); - ret = rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(ctx, &keypair, msg); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - VALGRIND_MAKE_MEM_UNDEFINED(&keypair, sizeof(keypair)); - ret = rustsecp256k1zkp_v0_8_0_keypair_sec(ctx, key, &keypair); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - ret = rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, key); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - ret = rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); -#endif - -#ifdef ENABLE_MODULE_ECDSA_S2C - { - unsigned char s2c_data[32] = {0}; - unsigned char s2c_data_comm[32] = {0}; - rustsecp256k1zkp_v0_8_0_ecdsa_s2c_opening s2c_opening; - - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - VALGRIND_MAKE_MEM_UNDEFINED(s2c_data, 32); - ret = rustsecp256k1zkp_v0_8_0_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, msg, key, s2c_data); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - - VALGRIND_MAKE_MEM_UNDEFINED(s2c_data, 32); - ret = rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_host_commit(ctx, s2c_data_comm, s2c_data); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - VALGRIND_MAKE_MEM_UNDEFINED(s2c_data, 32); - ret = rustsecp256k1zkp_v0_8_0_ecdsa_anti_exfil_signer_commit(ctx, &s2c_opening, msg, key, s2c_data); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - } -#endif - -#ifdef ENABLE_MODULE_ECDSA_ADAPTOR - { - unsigned char adaptor_sig[162]; - unsigned char deckey[32]; - unsigned char expected_deckey[32]; - rustsecp256k1zkp_v0_8_0_pubkey enckey; - - for (i = 0; i < 32; i++) { - deckey[i] = i + 2; - } - - ret = rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &enckey, deckey); - CHECK(ret == 1); - - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - ret = rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt(ctx, adaptor_sig, key, &enckey, msg, NULL, NULL); - VALGRIND_MAKE_MEM_DEFINED(adaptor_sig, sizeof(adaptor_sig)); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - - VALGRIND_MAKE_MEM_UNDEFINED(deckey, 32); - ret = rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt(ctx, &signature, deckey, adaptor_sig); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - - VALGRIND_MAKE_MEM_UNDEFINED(&signature, 32); - ret = rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover(ctx, expected_deckey, &signature, adaptor_sig, &enckey); - VALGRIND_MAKE_MEM_DEFINED(expected_deckey, sizeof(expected_deckey)); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - - VALGRIND_MAKE_MEM_DEFINED(deckey, sizeof(deckey)); - ret = rustsecp256k1zkp_v0_8_0_memcmp_var(deckey, expected_deckey, sizeof(expected_deckey)); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 0); - } -#endif - -#ifdef ENABLE_MODULE_MUSIG - { - rustsecp256k1zkp_v0_8_0_pubkey pk; - const rustsecp256k1zkp_v0_8_0_pubkey *pk_ptr[1]; - rustsecp256k1zkp_v0_8_0_xonly_pubkey agg_pk; - unsigned char session_id[32]; - rustsecp256k1zkp_v0_8_0_musig_secnonce secnonce; - rustsecp256k1zkp_v0_8_0_musig_pubnonce pubnonce; - const rustsecp256k1zkp_v0_8_0_musig_pubnonce *pubnonce_ptr[1]; - rustsecp256k1zkp_v0_8_0_musig_aggnonce aggnonce; - rustsecp256k1zkp_v0_8_0_musig_keyagg_cache cache; - rustsecp256k1zkp_v0_8_0_musig_session session; - rustsecp256k1zkp_v0_8_0_musig_partial_sig partial_sig; - const rustsecp256k1zkp_v0_8_0_musig_partial_sig *partial_sig_ptr[1]; - unsigned char extra_input[32]; - unsigned char sec_adaptor[32]; - rustsecp256k1zkp_v0_8_0_pubkey adaptor; - unsigned char pre_sig[64]; - int nonce_parity; - - pk_ptr[0] = &pk; - pubnonce_ptr[0] = &pubnonce; - VALGRIND_MAKE_MEM_DEFINED(key, 32); - memcpy(session_id, key, sizeof(session_id)); - session_id[0] = session_id[0] + 1; - memcpy(extra_input, key, sizeof(extra_input)); - extra_input[0] = extra_input[0] + 2; - memcpy(sec_adaptor, key, sizeof(sec_adaptor)); - sec_adaptor[0] = extra_input[0] + 3; - partial_sig_ptr[0] = &partial_sig; - - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, key)); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_pub(ctx, &pk, &keypair)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_pubkey_agg(ctx, NULL, &agg_pk, &cache, pk_ptr, 1)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &adaptor, sec_adaptor)); - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - VALGRIND_MAKE_MEM_UNDEFINED(session_id, sizeof(session_id)); - VALGRIND_MAKE_MEM_UNDEFINED(extra_input, sizeof(extra_input)); - VALGRIND_MAKE_MEM_UNDEFINED(sec_adaptor, sizeof(sec_adaptor)); - ret = rustsecp256k1zkp_v0_8_0_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_id, key, &pk, msg, &cache, extra_input); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_process(ctx, &session, &aggnonce, msg, &cache, &adaptor) == 1); - - ret = rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, key); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - ret = rustsecp256k1zkp_v0_8_0_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &cache, &session); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - - VALGRIND_MAKE_MEM_DEFINED(&partial_sig, sizeof(partial_sig)); - CHECK(rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg(ctx, pre_sig, &session, partial_sig_ptr, 1)); - VALGRIND_MAKE_MEM_DEFINED(pre_sig, sizeof(pre_sig)); - - CHECK(rustsecp256k1zkp_v0_8_0_musig_nonce_parity(ctx, &nonce_parity, &session)); - ret = rustsecp256k1zkp_v0_8_0_musig_adapt(ctx, sig, pre_sig, sec_adaptor, nonce_parity); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - ret = rustsecp256k1zkp_v0_8_0_musig_extract_adaptor(ctx, sec_adaptor, sig, pre_sig, nonce_parity); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); - CHECK(ret == 1); - } -#endif -} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/surjection_impl.h.patch b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/surjection_impl.h.patch deleted file mode 100644 index 1e1e73f1..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/surjection_impl.h.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/surjection_impl.h b/secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/surjection_impl.h -index 8680d0b..0c82d19 100644 ---- a/secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/surjection_impl.h -+++ b/secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/surjection_impl.h -@@ -7,7 +7,6 @@ - #ifndef _SECP256K1_SURJECTION_IMPL_H_ - #define _SECP256K1_SURJECTION_IMPL_H_ - --#include - #include - - #include "../../eckey.h" diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/surjection_main_impl.h.patch b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/surjection_main_impl.h.patch deleted file mode 100644 index 3282eebd..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/surjection_main_impl.h.patch +++ /dev/null @@ -1,61 +0,0 @@ -diff --git a/secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/main_impl.h b/secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/main_impl.h -index 5367fe5..afa5103 100644 ---- a/secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/main_impl.h -+++ b/secp256k1-zkp-sys/depend/secp256k1/src/modules/surjection/main_impl.h -@@ -6,7 +6,6 @@ - #ifndef SECP256K1_MODULE_SURJECTION_MAIN - #define SECP256K1_MODULE_SURJECTION_MAIN - --#include - #include - - #if defined HAVE_CONFIG_H -@@ -172,48 +172,6 @@ static size_t secp256k1_surjectionproof_csprng_next(secp256k1_surjectionproof_cs - } - } - --/* While '_allocate_initialized' may be a wordy suffix for this function, and '_create' -- * may have been more appropriate, '_create' could be confused with '_generate', -- * as the meanings for the words are close. Therefore, more wordy, but less -- * ambiguous suffix was chosen. */ --int secp256k1_surjectionproof_allocate_initialized(const secp256k1_context* ctx, secp256k1_surjectionproof** proof_out_p, size_t *input_index, const secp256k1_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, const secp256k1_fixed_asset_tag* fixed_output_tag, const size_t n_max_iterations, const unsigned char *random_seed32) { -- int ret = 0; -- secp256k1_surjectionproof* proof; -- -- VERIFY_CHECK(ctx != NULL); -- -- ARG_CHECK(proof_out_p != NULL); -- *proof_out_p = 0; -- -- proof = (secp256k1_surjectionproof*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_surjectionproof)); -- if (proof != NULL) { -- ret = secp256k1_surjectionproof_initialize(ctx, proof, input_index, fixed_input_tags, n_input_tags, n_input_tags_to_use, fixed_output_tag, n_max_iterations, random_seed32); -- if (ret) { -- *proof_out_p = proof; -- } -- else { -- free(proof); -- } -- } -- return ret; --} -- --/* secp256k1_surjectionproof structure may also be allocated on the stack, -- * and initialized explicitly via secp256k1_surjectionproof_initialize(). -- * Supplying stack-allocated struct to _destroy() will result in calling -- * free() with the pointer that points at the stack, with disasterous -- * consequences. Thus, it is not advised to mix heap- and stack-allocating -- * approaches to working with this struct. It is possible to detect this -- * situation by using additional field in the struct that can be set to -- * special value depending on the allocation path, and check it here. -- * But currently, it is not seen as big enough concern to warrant this extra code .*/ --void secp256k1_surjectionproof_destroy(secp256k1_surjectionproof* proof) { -- if (proof != NULL) { -- VERIFY_CHECK(proof->n_inputs <= SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS); -- free(proof); -- } --} -- - int secp256k1_surjectionproof_initialize(const secp256k1_context* ctx, secp256k1_surjectionproof* proof, size_t *input_index, const secp256k1_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, const secp256k1_fixed_asset_tag* fixed_output_tag, const size_t n_max_iterations, const unsigned char *random_seed32) { - secp256k1_surjectionproof_csprng csprng; - size_t n_iterations = 0; diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/util.h.patch b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/util.h.patch deleted file mode 100644 index 92731c74..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/util.h.patch +++ /dev/null @@ -1,17 +0,0 @@ -71,86d70 -< static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) { -< void *ret = malloc(size); -< if (ret == NULL) { -< secp256k1_callback_call(cb, "Out of memory"); -< } -< return ret; -< } -< -< static SECP256K1_INLINE void *checked_realloc(const secp256k1_callback* cb, void *ptr, size_t size) { -< void *ret = realloc(ptr, size); -< if (ret == NULL) { -< secp256k1_callback_call(cb, "Out of memory"); -< } -< return ret; -< } -< diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/src/error_callbacks.rs b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/src/error_callbacks.rs deleted file mode 100644 index bf59d9d5..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/src/error_callbacks.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Defines the external error callbacks for the secp256k1zkp context. -//! -//! We need to define these callbacks so we can enable the `USE_EXTERNAL_DEFAULT_CALLBACKS` feature flag. -//! Without this feature flag, the C code does not compile to WASM. -//! -//! We are not using the context from libsecp256k1zkp but are reusing the one from libsecp256k1 so these callbacks don't need to actually do anything and can be empty. - -use secp256k1_sys::types::{c_char, c_void}; - -#[no_mangle] -#[cfg(not(feature = "external-symbols"))] -pub unsafe extern "C" fn rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn( - _: *const c_char, - _data: *mut c_void, -) { - unimplemented!("should never be called, see rustdoc above") -} - -#[no_mangle] -#[cfg(not(feature = "external-symbols"))] -pub unsafe extern "C" fn rustsecp256k1zkp_v0_8_0_default_error_callback_fn( - _: *const c_char, - _data: *mut c_void, -) { - unimplemented!("should never be called. see rustdoc above") -} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/src/lib.rs b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/src/lib.rs deleted file mode 100644 index 4c0c816f..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/src/lib.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![allow(warnings)] -// Bitcoin secp256k1 bindings -// Written in 2014 by -// Dawid Ciężarkiewicz -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// -//! # secp256k1-zkp-sys FFI bindings -//! Direct bindings to the underlying C library functions. These should -//! not be needed for most users. - -// Coding conventions -#![deny(non_upper_case_globals)] -#![deny(non_camel_case_types)] -#![deny(non_snake_case)] -#![deny(unused_mut)] -#![cfg_attr(all(not(test), not(feature = "std")), no_std)] -#[cfg(any(test, feature = "std"))] -extern crate core; -#[macro_use] -extern crate secp256k1_sys; -pub use secp256k1_sys::*; - -mod error_callbacks; -mod zkp; - -pub use zkp::*; diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/src/zkp.rs b/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/src/zkp.rs deleted file mode 100644 index 2b39e751..00000000 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/src/zkp.rs +++ /dev/null @@ -1,1024 +0,0 @@ -use core::{fmt, hash}; -use zkp::hash::Hash; -use {types::*, Context, Keypair, PublicKey, Signature, XOnlyPublicKey}; - -/// Rangeproof maximum length -pub const RANGEPROOF_MAX_LENGTH: size_t = 5134; -pub const ECDSA_ADAPTOR_SIGNATURE_LENGTH: size_t = 162; - -/// The maximum number of whitelist keys. -pub const WHITELIST_MAX_N_KEYS: size_t = 255; - -extern "C" { - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_pedersen_commitment_parse" - )] - // Parse a 33-byte commitment into 64 byte internal commitment object - pub fn secp256k1_pedersen_commitment_parse( - cx: *const Context, - commit: *mut PedersenCommitment, - input: *const c_uchar, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_pedersen_commitment_serialize" - )] - // Serialize a 64-byte commit object into a 33 byte serialized byte sequence - pub fn secp256k1_pedersen_commitment_serialize( - cx: *const Context, - output: *mut c_uchar, - commit: *const PedersenCommitment, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_pedersen_commit" - )] - // Generates a pedersen commitment: *commit = blind * G + value * G2. - // The commitment is 33 bytes, the blinding factor is 32 bytes. - pub fn secp256k1_pedersen_commit( - ctx: *const Context, - commit: *mut PedersenCommitment, - blind: *const c_uchar, - value: u64, - value_gen: *const PublicKey, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_pedersen_blind_generator_blind_sum" - )] - /// Sets the final Pedersen blinding factor correctly when the generators themselves - /// have blinding factors. - /// - /// Consider a generator of the form A' = A + rG, where A is the "real" generator - /// but A' is the generator provided to verifiers. Then a Pedersen commitment - /// P = vA' + r'G really has the form vA + (vr + r')G. To get all these (vr + r') - /// to sum to zero for multiple commitments, we take three arrays consisting of - /// the `v`s, `r`s, and `r'`s, respectively called `value`s, `generator_blind`s - /// and `blinding_factor`s, and sum them. - /// - /// The function then subtracts the sum of all (vr + r') from the last element - /// of the `blinding_factor` array, setting the total sum to zero. - /// - /// Returns 1: Blinding factor successfully computed. - /// 0: Error. A blinding_factor or generator_blind are larger than the group - /// order (probability for random 32 byte number < 2^-127). Retry with - /// different values. - /// - /// In: ctx: pointer to a context object - /// value: array of asset values, `v` in the above paragraph. - /// May not be NULL unless `n_total` is 0. - /// generator_blind: array of asset blinding factors, `r` in the above paragraph - /// May not be NULL unless `n_total` is 0. - /// n_total: Total size of the above arrays - /// n_inputs: How many of the initial array elements represent commitments that - /// will be negated in the final sum - /// In/Out: blinding_factor: array of commitment blinding factors, `r'` in the above paragraph - /// May not be NULL unless `n_total` is 0. - /// the last value will be modified to get the total sum to zero. - pub fn secp256k1_pedersen_blind_generator_blind_sum( - ctx: *const Context, - value: *const u64, - generator_blind: *const *const c_uchar, - blinding_factor: *const *mut c_uchar, - n_total: size_t, - n_inputs: size_t, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_pedersen_verify_tally" - )] - // Takes two list of 64-byte commitments and sums the first set and - // subtracts the second and verifies that they sum to 0. - pub fn secp256k1_pedersen_verify_tally( - ctx: *const Context, - commits: *const &PedersenCommitment, - pcnt: size_t, - ncommits: *const &PedersenCommitment, - ncnt: size_t, - ) -> c_int; - - #[cfg(feature = "std")] - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_rangeproof_info" - )] - pub fn secp256k1_rangeproof_info( - ctx: *const Context, - exp: *mut c_int, - mantissa: *mut c_int, - min_value: *mut u64, - max_value: *mut u64, - proof: *const c_uchar, - plen: size_t, - ) -> c_int; - - #[cfg(feature = "std")] - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_rangeproof_rewind" - )] - pub fn secp256k1_rangeproof_rewind( - ctx: *const Context, - blind_out: *mut c_uchar, - value_out: *mut u64, - message_out: *mut c_uchar, - outlen: *mut size_t, - nonce: *const c_uchar, - min_value: *mut u64, - max_value: *mut u64, - commit: *const PedersenCommitment, - proof: *const c_uchar, - plen: size_t, - extra_commit: *const c_uchar, - extra_commit_len: size_t, - gen: *const PublicKey, - ) -> c_int; - - #[cfg(feature = "std")] - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_rangeproof_verify" - )] - pub fn secp256k1_rangeproof_verify( - ctx: *const Context, - min_value: &mut u64, - max_value: &mut u64, - commit: *const PedersenCommitment, - proof: *const c_uchar, - plen: size_t, - extra_commit: *const c_uchar, - extra_commit_len: size_t, - gen: *const PublicKey, - ) -> c_int; - - #[cfg(feature = "std")] - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_rangeproof_sign" - )] - pub fn secp256k1_rangeproof_sign( - ctx: *const Context, - proof: *mut c_uchar, - plen: *mut size_t, - min_value: u64, - commit: *const PedersenCommitment, - blind: *const c_uchar, - nonce: *const c_uchar, - exp: c_int, - min_bits: c_int, - value: u64, - message: *const c_uchar, - msg_len: size_t, - extra_commit: *const c_uchar, - extra_commit_len: size_t, - gen: *const PublicKey, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_surjectionproof_initialize" - )] - pub fn secp256k1_surjectionproof_initialize( - ctx: *const Context, - proof: *mut SurjectionProof, - input_index: *mut size_t, - fixed_input_tags: *const Tag, - n_input_tags: size_t, - n_input_tags_to_use: size_t, - fixed_output_tag: *const Tag, - n_max_iterations: size_t, - random_seed32: *const c_uchar, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_surjectionproof_serialize" - )] - pub fn secp256k1_surjectionproof_serialize( - ctx: *const Context, - output: *mut c_uchar, - outputlen: *mut size_t, - proof: *const SurjectionProof, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_surjectionproof_serialized_size" - )] - pub fn secp256k1_surjectionproof_serialized_size( - ctx: *const Context, - proof: *const SurjectionProof, - ) -> size_t; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_surjectionproof_parse" - )] - pub fn secp256k1_surjectionproof_parse( - ctx: *const Context, - proof: *mut SurjectionProof, - input_bytes: *const c_uchar, - input_len: size_t, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_surjectionproof_generate" - )] - pub fn secp256k1_surjectionproof_generate( - ctx: *const Context, - proof: *mut SurjectionProof, - ephemeral_input_tags: *const PublicKey, - n_ephemeral_input_tags: size_t, - ephemeral_output_tag: *const PublicKey, - input_index: size_t, - input_blinding_key: *const c_uchar, - output_blinding_key: *const c_uchar, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_surjectionproof_verify" - )] - pub fn secp256k1_surjectionproof_verify( - ctx: *const Context, - proof: *const SurjectionProof, - ephemeral_input_tags: *const PublicKey, - n_ephemeral_input_tags: size_t, - ephemeral_output_tag: *const PublicKey, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_generator_generate_blinded" - )] - pub fn secp256k1_generator_generate_blinded( - ctx: *const Context, - gen: *mut PublicKey, - key32: *const c_uchar, - blind32: *const c_uchar, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_generator_serialize" - )] - pub fn secp256k1_generator_serialize( - ctx: *const Context, - output: *mut c_uchar, - gen: *const PublicKey, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_generator_parse" - )] - pub fn secp256k1_generator_parse( - ctx: *const Context, - output: *mut PublicKey, - bytes: *const c_uchar, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_nonce_function_ecdsa_adaptor" - )] - pub static secp256k1_nonce_function_ecdsa_adaptor: EcdsaAdaptorNonceFn; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_encrypt" - )] - pub fn secp256k1_ecdsa_adaptor_encrypt( - cx: *const Context, - adaptor_sig162: *mut EcdsaAdaptorSignature, - seckey32: *const c_uchar, - enckey: *const PublicKey, - msg32: *const c_uchar, - noncefp: EcdsaAdaptorNonceFn, - ndata: *mut c_void, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_verify" - )] - pub fn secp256k1_ecdsa_adaptor_verify( - cx: *const Context, - adaptor_sig162: *const EcdsaAdaptorSignature, - pubkey: *const PublicKey, - msg32: *const c_uchar, - enckey: *const PublicKey, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_decrypt" - )] - pub fn secp256k1_ecdsa_adaptor_decrypt( - cx: *const Context, - sig: *mut Signature, - deckey32: *const c_uchar, - adaptor_sig162: *const EcdsaAdaptorSignature, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_ecdsa_adaptor_recover" - )] - pub fn secp256k1_ecdsa_adaptor_recover( - cx: *const Context, - deckey32: *mut c_uchar, - sig: *const Signature, - adaptor_sig162: *const EcdsaAdaptorSignature, - enckey: *const PublicKey, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_whitelist_signature_parse" - )] - pub fn secp256k1_whitelist_signature_parse( - cx: *const Context, - sig: *mut WhitelistSignature, - input: *const c_uchar, - input_len: size_t, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_whitelist_signature_serialize" - )] - pub fn secp256k1_whitelist_signature_serialize( - ctx: *const Context, - output: *mut c_uchar, - outputlen: *mut size_t, - sig: *const WhitelistSignature, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_whitelist_sign" - )] - pub fn secp256k1_whitelist_sign( - ctx: *const Context, - sig: *mut WhitelistSignature, - online_keys: *const PublicKey, - offline_keys: *const PublicKey, - n_keys: size_t, - sub_pubkey: *const PublicKey, - online_seckey: *const c_uchar, - summed_seckey: *const c_uchar, - index: size_t, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_whitelist_verify" - )] - pub fn secp256k1_whitelist_verify( - ctx: *const Context, - sig: *const WhitelistSignature, - online_keys: *const PublicKey, - offline_keys: *const PublicKey, - n_keys: size_t, - sub_pubkey: *const PublicKey, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_pubnonce_parse" - )] - pub fn secp256k1_musig_pubnonce_parse( - cx: *const Context, - nonce: *mut MusigPubNonce, - in66: *const c_uchar, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_pubnonce_serialize" - )] - pub fn secp256k1_musig_pubnonce_serialize( - cx: *const Context, - out66: *mut c_uchar, - nonce: *const MusigPubNonce, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_aggnonce_parse" - )] - pub fn secp256k1_musig_aggnonce_parse( - cx: *const Context, - nonce: *mut MusigAggNonce, - in66: *const c_uchar, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_aggnonce_serialize" - )] - pub fn secp256k1_musig_aggnonce_serialize( - cx: *const Context, - out66: *mut c_uchar, - nonce: *const MusigAggNonce, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_partial_sig_parse" - )] - pub fn secp256k1_musig_partial_sig_parse( - cx: *const Context, - sig: *mut MusigPartialSignature, - in32: *const c_uchar, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_partial_sig_serialize" - )] - pub fn secp256k1_musig_partial_sig_serialize( - cx: *const Context, - out32: *mut c_uchar, - sig: *const MusigPartialSignature, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_pubkey_agg" - )] - pub fn secp256k1_musig_pubkey_agg( - cx: *const Context, - scratch: *mut ScratchSpace, - combined_pk: *mut XOnlyPublicKey, - keyagg_cache: *mut MusigKeyAggCache, - pubkeys: *const *const PublicKey, - n_pubkeys: size_t, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_pubkey_get" - )] - pub fn secp256k1_musig_pubkey_get( - cx: *const Context, - agg_pk: *mut PublicKey, - keyagg_cache: *const MusigKeyAggCache, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_pubkey_ec_tweak_add" - )] - pub fn secp256k1_musig_pubkey_ec_tweak_add( - cx: *const Context, - output_pubkey: *mut PublicKey, - keyagg_cache: *mut MusigKeyAggCache, - tweak32: *const c_uchar, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_pubkey_xonly_tweak_add" - )] - pub fn secp256k1_musig_pubkey_xonly_tweak_add( - cx: *const Context, - output_pubkey: *mut PublicKey, - keyagg_cache: *mut MusigKeyAggCache, - tweak32: *const c_uchar, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_nonce_gen" - )] - pub fn secp256k1_musig_nonce_gen( - cx: *const Context, - secnonce: *mut MusigSecNonce, - pubnonce: *mut MusigPubNonce, - session_id32: *const c_uchar, - seckey: *const c_uchar, - pubkey: *const PublicKey, - msg32: *const c_uchar, - keyagg_cache: *const MusigKeyAggCache, - extra_input32: *const c_uchar, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_nonce_agg" - )] - pub fn secp256k1_musig_nonce_agg( - cx: *const Context, - aggnonce: *mut MusigAggNonce, - pubnonces: *const *const MusigPubNonce, - n_pubnonces: size_t, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_nonce_process" - )] - pub fn secp256k1_musig_nonce_process( - cx: *const Context, - session: *mut MusigSession, - aggnonce: *const MusigAggNonce, - msg32: *const c_uchar, - keyagg_cache: *const MusigKeyAggCache, - adaptor: *const PublicKey, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_partial_sign" - )] - pub fn secp256k1_musig_partial_sign( - cx: *const Context, - partial_sig: *mut MusigPartialSignature, - secnonce: *mut MusigSecNonce, - keypair: *const Keypair, - keyagg_cache: *const MusigKeyAggCache, - session: *const MusigSession, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_partial_sig_verify" - )] - pub fn secp256k1_musig_partial_sig_verify( - cx: *const Context, - partial_sig: *const MusigPartialSignature, - pubnonce: *const MusigPubNonce, - pubkey: *const PublicKey, - keyagg_cache: *const MusigKeyAggCache, - session: *const MusigSession, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_partial_sig_agg" - )] - pub fn secp256k1_musig_partial_sig_agg( - cx: *const Context, - sig64: *mut c_uchar, - session: *const MusigSession, - partial_sigs: *const *const MusigPartialSignature, - n_sigs: size_t, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_nonce_parity" - )] - pub fn secp256k1_musig_nonce_parity( - cx: *const Context, - nonce_parity: *mut c_int, - session: *const MusigSession, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_adapt" - )] - pub fn secp256k1_musig_adapt( - cx: *const Context, - sig64: *mut c_uchar, - pre_sig64: *const c_uchar, - sec_adaptor32: *const c_uchar, - nonce_parity: c_int, - ) -> c_int; - - #[cfg_attr( - not(feature = "external-symbols"), - link_name = "rustsecp256k1zkp_v0_8_0_musig_extract_adaptor" - )] - pub fn secp256k1_musig_extract_adaptor( - cx: *const Context, - sec_adaptor32: *mut c_uchar, - sig64: *const c_uchar, - pre_sig64: *const c_uchar, - nonce_parity: c_int, - ) -> c_int; -} - -#[repr(C)] -#[derive(Clone)] -pub struct SurjectionProof { - #[doc = " Total number of input asset tags"] - pub n_inputs: size_t, - #[doc = " Bitmap of which input tags are used in the surjection proof"] - pub used_inputs: [c_uchar; 32usize], - #[doc = " Borromean signature: e0, scalars"] - pub data: [c_uchar; 8224usize], -} - -impl fmt::Debug for SurjectionProof { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let slice = &self.data[..]; - - f.debug_struct("SurjectionProof") - .field("n_inputs", &self.n_inputs) - .field("used_inputs", &self.used_inputs) - .field("data", &slice) - .finish() - } -} - -impl PartialEq for SurjectionProof { - fn eq(&self, other: &Self) -> bool { - self.n_inputs == other.n_inputs - && self.used_inputs == other.used_inputs - && self.data[..] == other.data[..] - } -} - -impl Eq for SurjectionProof {} - -impl Ord for SurjectionProof { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - match self.n_inputs.cmp(&other.n_inputs) { - core::cmp::Ordering::Equal => {} - ord => return ord, - } - match self.used_inputs.cmp(&other.used_inputs) { - core::cmp::Ordering::Equal => {} - ord => return ord, - } - self.data.cmp(&other.data) - } -} - -impl PartialOrd for SurjectionProof { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Default for SurjectionProof { - fn default() -> Self { - SurjectionProof::new() - } -} - -impl hash::Hash for SurjectionProof { - fn hash(&self, state: &mut H) { - self.n_inputs.hash(state); - self.used_inputs.hash(state); - for byte in self.data.iter() { - byte.hash(state); - } - } -} - -impl SurjectionProof { - pub fn new() -> Self { - Self { - n_inputs: 0, - used_inputs: [0u8; 32], - data: [0u8; 8224], - } - } -} - -#[cfg(feature = "std")] -#[repr(C)] -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct RangeProof(Box<[c_uchar]>); - -#[cfg(feature = "std")] -impl RangeProof { - pub fn new(bytes: &[u8]) -> Self { - RangeProof(bytes.into()) - } - - pub fn len(&self) -> usize { - self.0.len() - } - - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - pub fn as_ptr(&self) -> *const c_uchar { - self.0.as_ptr() - } - - pub fn to_bytes(&self) -> Vec { - self.0.to_vec() - } -} - -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub struct Tag([c_uchar; 32]); -impl_array_newtype!(Tag, c_uchar, 32); -impl_raw_debug!(Tag); - -impl Tag { - pub fn new() -> Self { - Tag([0; 32]) - } -} - -impl Default for Tag { - fn default() -> Self { - Tag::new() - } -} - -impl From<[u8; 32]> for Tag { - fn from(bytes: [u8; 32]) -> Self { - Tag(bytes) - } -} - -impl From for [u8; 32] { - fn from(tag: Tag) -> Self { - tag.0 - } -} - -// TODO: Replace this with ffi::PublicKey? -#[repr(C)] -#[derive(Copy, Clone, Ord, PartialOrd)] -pub struct PedersenCommitment([c_uchar; 64]); -impl_array_newtype!(PedersenCommitment, c_uchar, 64); -impl_raw_debug!(PedersenCommitment); - -impl PedersenCommitment { - pub fn new() -> Self { - PedersenCommitment([0; 64]) - } -} - -impl Default for PedersenCommitment { - fn default() -> Self { - PedersenCommitment::new() - } -} - -impl PartialEq for PedersenCommitment { - fn eq(&self, other: &Self) -> bool { - self.0[..] == other.0[..] - } -} - -impl Eq for PedersenCommitment {} - -impl Hash for PedersenCommitment { - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - -/// A ring signature for the "whitelist" scheme. -#[repr(C)] -#[derive(Clone)] -pub struct WhitelistSignature { - /// The number of keys. - pub n_keys: size_t, - /// The signature in the form of e0 + n_keys s values. - pub data: [u8; 32 * (1 + WHITELIST_MAX_N_KEYS)], -} - -impl hash::Hash for WhitelistSignature { - fn hash(&self, state: &mut H) { - self.n_keys.hash(state); - self.data[..].hash(state); - } -} - -impl PartialEq for WhitelistSignature { - fn eq(&self, other: &Self) -> bool { - self.n_keys == other.n_keys && self.data[..] == other.data[..] - } -} -impl Eq for WhitelistSignature {} - -impl Default for WhitelistSignature { - fn default() -> WhitelistSignature { - WhitelistSignature { - n_keys: 0, - data: [0; 32 * (1 + WHITELIST_MAX_N_KEYS)], - } - } -} - -/// Same as secp256k1_nonce_function_hardened with the exception of using the -/// compressed 33-byte encoding for the pubkey argument. -pub type EcdsaAdaptorNonceFn = Option< - unsafe extern "C" fn( - nonce32: *mut c_uchar, - msg32: *const c_uchar, - key32: *const c_uchar, - pk33: *const c_uchar, - algo: *const c_uchar, - algo_len: size_t, - data: *mut c_void, - ) -> c_int, ->; - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct EcdsaAdaptorSignature([u8; ECDSA_ADAPTOR_SIGNATURE_LENGTH]); -impl_array_newtype!(EcdsaAdaptorSignature, u8, ECDSA_ADAPTOR_SIGNATURE_LENGTH); -impl_raw_debug!(EcdsaAdaptorSignature); - -impl Default for EcdsaAdaptorSignature { - fn default() -> EcdsaAdaptorSignature { - EcdsaAdaptorSignature::new() - } -} - -impl PartialEq for EcdsaAdaptorSignature { - fn eq(&self, other: &Self) -> bool { - &self.0[..] == &other.0[..] - } -} - -impl Eq for EcdsaAdaptorSignature {} - -impl EcdsaAdaptorSignature { - /// Create a new (zeroed) ecdsa adaptor signature usable for the FFI interface - pub fn new() -> Self { - EcdsaAdaptorSignature([0u8; ECDSA_ADAPTOR_SIGNATURE_LENGTH]) - } - - /// Create a new ecdsa adaptor signature usable for the FFI interface from raw bytes - /// - /// # Safety - /// - /// Does not check the validity of the underlying representation. If it is - /// invalid the result may be assertation failures (and process aborts) from - /// the underlying library. You should not use this method except with data - /// that you obtained from the FFI interface of the same version of this - /// library. - pub unsafe fn from_array_unchecked(data: [c_uchar; ECDSA_ADAPTOR_SIGNATURE_LENGTH]) -> Self { - Self(data) - } -} - -#[repr(C)] -pub struct ScratchSpace(c_int); - -pub const MUSIG_KEYAGG_LEN: usize = 197; -pub const MUSIG_SECNONCE_LEN: usize = 132; -pub const MUSIG_PUBNONCE_LEN: usize = 132; -pub const MUSIG_AGGNONCE_LEN: usize = 132; -pub const MUSIG_AGGNONCE_SERIALIZED_LEN: usize = 66; -pub const MUSIG_PUBNONCE_SERIALIZED_LEN: usize = 66; -pub const MUSIG_SESSION_LEN: usize = 133; -pub const MUSIG_PART_SIG_LEN: usize = 36; - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct MusigKeyAggCache([c_uchar; MUSIG_KEYAGG_LEN]); -impl_array_newtype!(MusigKeyAggCache, c_uchar, MUSIG_KEYAGG_LEN); -impl_raw_debug!(MusigKeyAggCache); - -#[cfg(not(fuzzing))] -impl PartialEq for MusigKeyAggCache { - fn eq(&self, other: &Self) -> bool { - self.0[..] == other.0[..] - } -} - -#[cfg(not(fuzzing))] -impl Eq for MusigKeyAggCache {} - -impl MusigKeyAggCache { - pub fn new() -> Self { - MusigKeyAggCache([0; MUSIG_KEYAGG_LEN]) - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct MusigSecNonce(pub(crate) [c_uchar; MUSIG_SECNONCE_LEN]); -impl_array_newtype!(MusigSecNonce, c_uchar, MUSIG_SECNONCE_LEN); -impl_raw_debug!(MusigSecNonce); - -#[cfg(not(fuzzing))] -impl PartialEq for MusigSecNonce { - fn eq(&self, other: &Self) -> bool { - &self.0[..] == &other.0[..] - } -} - -#[cfg(not(fuzzing))] -impl Eq for MusigSecNonce {} - -impl MusigSecNonce { - pub fn new() -> Self { - MusigSecNonce([0; MUSIG_SECNONCE_LEN]) - } - - /// Don't use this. Refer to the documentation of wrapper APIs in rust-zkp crate. - // - // No need for strong warning here, the user cannot use the ffi types directly in any of the APIs - pub fn dangerous_from_bytes(bytes: [c_uchar; MUSIG_SECNONCE_LEN]) -> Self { - MusigSecNonce(bytes) - } - - /// Don't use this. Refer to the documentation of wrapper APIs in rust-zkp crate. - // - // No need for strong warning here, the user cannot use the ffi types directly in any of the high level APIs - pub fn dangerous_into_bytes(self) -> [c_uchar; MUSIG_SECNONCE_LEN] { - self.0 - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct MusigPubNonce([c_uchar; MUSIG_PUBNONCE_LEN]); -impl_array_newtype!(MusigPubNonce, c_uchar, MUSIG_PUBNONCE_LEN); -impl_raw_debug!(MusigPubNonce); - -#[cfg(not(fuzzing))] -impl PartialEq for MusigPubNonce { - fn eq(&self, other: &Self) -> bool { - &self.0[..] == &other.0[..] - } -} - -#[cfg(not(fuzzing))] -impl Eq for MusigPubNonce {} - -impl MusigPubNonce { - pub fn new() -> Self { - MusigPubNonce([0; MUSIG_PUBNONCE_LEN]) - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct MusigAggNonce([c_uchar; MUSIG_AGGNONCE_LEN]); -impl_array_newtype!(MusigAggNonce, c_uchar, MUSIG_AGGNONCE_LEN); -impl_raw_debug!(MusigAggNonce); - -#[cfg(not(fuzzing))] -impl PartialEq for MusigAggNonce { - fn eq(&self, other: &Self) -> bool { - &self.0[..] == &other.0[..] - } -} - -#[cfg(not(fuzzing))] -impl Eq for MusigAggNonce {} - -impl MusigAggNonce { - pub fn new() -> Self { - MusigAggNonce([0; MUSIG_AGGNONCE_LEN]) - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct MusigSession([c_uchar; MUSIG_SESSION_LEN]); -impl_array_newtype!(MusigSession, c_uchar, MUSIG_SESSION_LEN); -impl_raw_debug!(MusigSession); - -#[cfg(not(fuzzing))] -impl PartialEq for MusigSession { - fn eq(&self, other: &Self) -> bool { - &self.0[..] == &other.0[..] - } -} - -#[cfg(not(fuzzing))] -impl Eq for MusigSession {} - -impl MusigSession { - pub fn new() -> Self { - MusigSession([0; MUSIG_SESSION_LEN]) - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct MusigPartialSignature([c_uchar; MUSIG_PART_SIG_LEN]); -impl_array_newtype!(MusigPartialSignature, c_uchar, MUSIG_PART_SIG_LEN); -impl_raw_debug!(MusigPartialSignature); - -#[cfg(not(fuzzing))] -impl PartialEq for MusigPartialSignature { - fn eq(&self, other: &Self) -> bool { - &self.0[..] == &other.0[..] - } -} - -#[cfg(not(fuzzing))] -impl Eq for MusigPartialSignature {} - -impl MusigPartialSignature { - pub fn new() -> Self { - MusigPartialSignature([0; MUSIG_PART_SIG_LEN]) - } -} diff --git a/ark-rust-secp256k1-zkp/contrib/test.sh b/ark-rust-secp256k1-zkp/contrib/test.sh deleted file mode 100755 index 5a32f566..00000000 --- a/ark-rust-secp256k1-zkp/contrib/test.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/sh -ex - -FEATURES="hashes global-context lowmemory rand rand-std recovery serde" - -cargo --version -rustc --version - -# Make all cargo invocations verbose -export CARGO_TERM_VERBOSE=true - -# Defaults / sanity checks -cargo build --all -cargo test --all - -if [ "$DO_FEATURE_MATRIX" = true ]; then - cargo build --all --no-default-features - #This doesn't work but probably should --andrew - #cargo test --all --no-default-features - - # All features - cargo build --all --no-default-features --features="$FEATURES" - cargo test --all --features="$FEATURES" - # Single features - for feature in ${FEATURES} - do - cargo build --all --no-default-features --features="$feature" - cargo test --all --features="$feature" - done - - # Other combos - RUSTFLAGS='--cfg=rust_secp_fuzz' cargo test --all - RUSTFLAGS='--cfg=rust_secp_fuzz' cargo test --all --features="$FEATURES" - cargo test --all --features="rand rand-std" - cargo test --all --features="rand serde" - - cargo test --all --all-features - RUSTFLAGS='--cfg=rust_secp_fuzz' RUSTDOCFLAGS='--cfg=rust_secp_fuzz' cargo test --all --all-features -fi - -# Docs -if [ "$DO_DOCS" = true ]; then - cargo doc --all --features="$FEATURES" -fi - -# Webassembly stuff -if [ "$DO_WASM" = true ]; then - clang --version - wasm-pack build - wasm-pack test --node; -fi - -# Address Sanitizer -if [ "$DO_ASAN" = true ]; then - clang --version - cargo clean - CC='clang -fsanitize=address -fno-omit-frame-pointer' \ - RUSTFLAGS='-Zsanitizer=address -Clinker=clang -Cforce-frame-pointers=yes' \ - ASAN_OPTIONS='detect_leaks=1 detect_invalid_pointer_pairs=1 detect_stack_use_after_return=1' \ - cargo test --lib --all --features="$FEATURES" -Zbuild-std --target x86_64-unknown-linux-gnu -fi - -# Lint if told to -if [ "$DO_LINT" = true ] -then - ( - cargo fmt --all -- --check - ) -fi - -exit 0 diff --git a/ark-rust-secp256k1-zkp/src/lib.rs b/ark-rust-secp256k1-zkp/src/lib.rs deleted file mode 100644 index a48648a5..00000000 --- a/ark-rust-secp256k1-zkp/src/lib.rs +++ /dev/null @@ -1,181 +0,0 @@ -#![allow(warnings)] -// Bitcoin secp256k1 bindings -// Written in 2014 by -// Dawid Ciężarkiewicz -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . - -//! # Secp256k1-zkp -//! -//! Rust bindings for libsecp256k1-zkp, a fork of Pieter Wuille's secp256k1 library. -//! -//! This library re-exports everything from `secp256k1` and adds bindings for the following modules: -//! -//! - generators -//! - range proofs -//! - pedersen commitments -//! -//! As such, it can be used as a drop-in replacement for `secp256k1`. All types are interoperable -//! (as long as you are dependening on the correct version) which means [`SecretKey`]s and the -//! [`Context`] are interoperable. - -// Coding conventions -#![cfg_attr(docsrs, feature(doc_auto_cfg))] -#![warn(missing_docs)] -#![cfg_attr(all(not(test), not(feature = "std")), no_std)] - -/// Re-export of the internal FFI bindings crate -pub extern crate secp256k1_zkp_sys; -/// Re-export of the internal FFI bindings crate under the alternate name `ffi` -pub use secp256k1_zkp_sys as ffi; - -extern crate secp256k1; - -#[cfg(feature = "hashes")] -pub use secp256k1::hashes; -/// Re-export of the `rand` crate -#[cfg(feature = "actual-rand")] -pub extern crate actual_rand as rand; -/// Re-export of the `serde` crate -#[cfg(feature = "serde")] -pub extern crate actual_serde as serde; -#[cfg(any(test, feature = "std"))] -extern crate core; -#[cfg(all(test, feature = "serde"))] -extern crate serde_test; -#[cfg(all(test, target_arch = "wasm32"))] -#[macro_use] -extern crate wasm_bindgen_test; - -pub use crate::PublicKey; -pub use crate::SecretKey; -use core::fmt; -use core::str; -pub use secp256k1::constants; -pub use secp256k1::ecdh; -pub use secp256k1::ecdsa; -pub use secp256k1::schnorr; -pub use secp256k1::*; - -#[cfg(feature = "serde")] -mod serde_util; -mod zkp; -pub use crate::zkp::*; -pub use secp256k1::Error as UpstreamError; - -/// An ECDSA error -#[derive(Copy, PartialEq, Eq, Clone, Debug)] -pub enum Error { - /// Calling through to `secp256k1` resulted in an error. - Upstream(UpstreamError), - /// Failed to produce a surjection proof because of an internal error within `libsecp256k1-zkp` - CannotProveSurjection, - /// Given bytes don't represent a valid surjection proof - InvalidSurjectionProof, - /// Given bytes don't represent a valid pedersen commitment - InvalidPedersenCommitment, - /// Failed to produce a range proof because of an internal error within `libsecp256k1-zkp` - CannotMakeRangeProof, - /// Given range proof does not prove that the commitment is within a range - InvalidRangeProof, - /// Bad generator - InvalidGenerator, - /// Tweak must of len 32 - InvalidTweakLength, - /// Tweak must be less than secp curve order - TweakOutOfBounds, - /// Given bytes don't represent a valid adaptor signature - InvalidEcdsaAdaptorSignature, - /// Failed to decrypt an adaptor signature because of an internal error within - /// `libsecp256k1-zkp` - CannotDecryptAdaptorSignature, - /// Failed to recover an adaptor secret from an adaptor signature because of an internal error - /// within `libsecp256k1-zkp` - CannotRecoverAdaptorSecret, - /// Given adaptor signature is not valid for the provided combination of public key, encryption - /// key and message - CannotVerifyAdaptorSignature, - /// Given bytes don't represent a valid whitelist signature - InvalidWhitelistSignature, - /// Invalid PAK list - InvalidPakList, - /// Couldn't create whitelist signature with the given data. - CannotCreateWhitelistSignature, - /// The given whitelist signature doesn't correctly prove inclusion in the whitelist. - InvalidWhitelistProof, -} - -// Passthrough Debug to Display, since errors should be user-visible -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - let str = match *self { - Error::CannotProveSurjection => "failed to prove surjection", - Error::InvalidSurjectionProof => "malformed surjection proof", - Error::InvalidPedersenCommitment => "malformed pedersen commitment", - Error::CannotMakeRangeProof => "failed to generate range proof", - Error::InvalidRangeProof => "failed to verify range proof", - Error::InvalidGenerator => "malformed generator", - Error::InvalidEcdsaAdaptorSignature => "malformed ecdsa adaptor signature", - Error::CannotDecryptAdaptorSignature => "failed to decrypt adaptor signature", - Error::CannotRecoverAdaptorSecret => "failed to recover adaptor secret", - Error::CannotVerifyAdaptorSignature => "failed to verify adaptor signature", - Error::Upstream(inner) => return write!(f, "{}", inner), - Error::InvalidTweakLength => "Tweak must of size 32", - Error::TweakOutOfBounds => "Tweak must be less than secp curve order", - Error::InvalidWhitelistSignature => "malformed whitelist signature", - Error::InvalidPakList => "invalid PAK list", - Error::CannotCreateWhitelistSignature => { - "cannot create whitelist signature with the given data" - } - Error::InvalidWhitelistProof => { - "given whitelist signature doesn't correctly prove inclusion in the whitelist" - } - }; - - f.write_str(str) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for Error {} - -impl From for Error { - fn from(e: UpstreamError) -> Self { - Error::Upstream(e) - } -} - -/// Utility function used to parse hex into a target u8 buffer. Returns -/// the number of bytes converted or an error if it encounters an invalid -/// character or unexpected end of string. -fn from_hex(hex: &str, target: &mut [u8]) -> Result { - if hex.len() % 2 == 1 || hex.len() > target.len() * 2 { - return Err(()); - } - - let mut b = 0; - let mut idx = 0; - for c in hex.bytes() { - b <<= 4; - match c { - b'A'..=b'F' => b |= c - b'A' + 10, - b'a'..=b'f' => b |= c - b'a' + 10, - b'0'..=b'9' => b |= c - b'0', - _ => return Err(()), - } - if (idx & 1) == 1 { - target[idx / 2] = b; - b = 0; - } - idx += 1; - } - Ok(idx / 2) -} diff --git a/ark-rust-secp256k1-zkp/src/serde_util.rs b/ark-rust-secp256k1-zkp/src/serde_util.rs deleted file mode 100644 index bc815bc5..00000000 --- a/ark-rust-secp256k1-zkp/src/serde_util.rs +++ /dev/null @@ -1,69 +0,0 @@ -use core::fmt; -use core::marker::PhantomData; -use core::str::{self, FromStr}; -use serde::de; - -/// A serde visitor that works for `T`s implementing `FromStr`. -pub struct FromStrVisitor { - expectation: &'static str, - _pd: PhantomData, -} - -impl FromStrVisitor { - pub fn new(expectation: &'static str) -> Self { - FromStrVisitor { - expectation, - _pd: PhantomData, - } - } -} - -impl<'de, T> de::Visitor<'de> for FromStrVisitor -where - T: FromStr, - ::Err: fmt::Display, -{ - type Value = T; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(self.expectation) - } - - fn visit_str(self, v: &str) -> Result { - FromStr::from_str(v).map_err(E::custom) - } -} - -pub struct BytesVisitor { - expectation: &'static str, - parse_fn: F, -} - -impl BytesVisitor -where - F: FnOnce(&[u8]) -> Result, - Err: fmt::Display, -{ - pub fn new(expectation: &'static str, parse_fn: F) -> Self { - BytesVisitor { - expectation, - parse_fn, - } - } -} - -impl<'de, F, T, Err> de::Visitor<'de> for BytesVisitor -where - F: FnOnce(&[u8]) -> Result, - Err: fmt::Display, -{ - type Value = T; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(self.expectation) - } - - fn visit_bytes(self, v: &[u8]) -> Result { - (self.parse_fn)(v).map_err(E::custom) - } -} diff --git a/ark-rust-secp256k1-zkp/src/zkp/ecdsa_adaptor.rs b/ark-rust-secp256k1-zkp/src/zkp/ecdsa_adaptor.rs deleted file mode 100644 index 2f692066..00000000 --- a/ark-rust-secp256k1-zkp/src/zkp/ecdsa_adaptor.rs +++ /dev/null @@ -1,498 +0,0 @@ -//! # ECDSA Adaptor -//! Support for ECDSA based adaptor signatures. -//! -//! WARNING: ECDSA adaptor signatures are insecure when the secret key is reused -//! in certain other crypto schemes. See -//! https://github.com/ElementsProject/secp256k1-zkp/blob/6955af5ca8930aa674e5fdbc4343e722b25e0ca8/include/secp256k1_ecdsa_adaptor.h#L14 -//! for details. -//! - -use crate::ffi::{self, CPtr, ECDSA_ADAPTOR_SIGNATURE_LENGTH}; -#[cfg(feature = "rand-std")] -use crate::rand::thread_rng; -#[cfg(feature = "actual-rand")] -use crate::rand::{CryptoRng, Rng}; -use crate::{constants, PublicKey, Secp256k1, SecretKey}; -use crate::{ecdsa::Signature, Verification}; -use crate::{from_hex, Error}; -use crate::{Message, Signing}; -use core::{fmt, ptr, str}; - -/// Represents an adaptor signature and dleq proof. -#[derive(Debug, PartialEq, Clone, Copy, Eq)] -pub struct EcdsaAdaptorSignature(ffi::EcdsaAdaptorSignature); - -impl fmt::LowerHex for EcdsaAdaptorSignature { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for ch in self.0.as_ref().iter() { - write!(f, "{:02x}", ch)?; - } - Ok(()) - } -} - -impl fmt::Display for EcdsaAdaptorSignature { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::LowerHex::fmt(self, f) - } -} - -impl str::FromStr for EcdsaAdaptorSignature { - type Err = Error; - fn from_str(s: &str) -> Result { - let mut res = [0; ECDSA_ADAPTOR_SIGNATURE_LENGTH]; - match from_hex(s, &mut res) { - Ok(ECDSA_ADAPTOR_SIGNATURE_LENGTH) => { - EcdsaAdaptorSignature::from_slice(&res[0..ECDSA_ADAPTOR_SIGNATURE_LENGTH]) - } - _ => Err(Error::InvalidEcdsaAdaptorSignature), - } - } -} - -#[cfg(feature = "serde")] -impl ::serde::Serialize for EcdsaAdaptorSignature { - fn serialize(&self, s: S) -> Result { - if s.is_human_readable() { - s.collect_str(self) - } else { - s.serialize_bytes(self.0.as_ref()) - } - } -} - -#[cfg(feature = "serde")] -impl<'de> ::serde::Deserialize<'de> for EcdsaAdaptorSignature { - fn deserialize>(d: D) -> Result { - use crate::serde_util; - - if d.is_human_readable() { - d.deserialize_str(serde_util::FromStrVisitor::new("an ASCII hex string")) - } else { - d.deserialize_bytes(serde_util::BytesVisitor::new( - "a bytestring", - EcdsaAdaptorSignature::from_slice, - )) - } - } -} - -impl CPtr for EcdsaAdaptorSignature { - type Target = ffi::EcdsaAdaptorSignature; - fn as_c_ptr(&self) -> *const Self::Target { - self.as_ptr() - } - - fn as_mut_c_ptr(&mut self) -> *mut Self::Target { - self.as_mut_ptr() - } -} - -impl AsRef<[u8]> for EcdsaAdaptorSignature { - fn as_ref(&self) -> &[u8] { - self.0.as_ref() - } -} - -impl EcdsaAdaptorSignature { - /// Creates an [`EcdsaAdaptorSignature`] directly from a slice - #[inline] - pub fn from_slice(data: &[u8]) -> Result { - match data.len() { - ECDSA_ADAPTOR_SIGNATURE_LENGTH => { - let mut ret = [0; ECDSA_ADAPTOR_SIGNATURE_LENGTH]; - ret[..].copy_from_slice(data); - unsafe { - Ok(EcdsaAdaptorSignature( - ffi::EcdsaAdaptorSignature::from_array_unchecked(ret), - )) - } - } - _ => Err(Error::InvalidEcdsaAdaptorSignature), - } - } - - /// Obtains a raw const pointer suitable for use with FFI functions - #[inline] - pub fn as_ptr(&self) -> *const ffi::EcdsaAdaptorSignature { - &self.0 - } - - /// Obtains a raw mutable pointer suitable for use with FFI functions - #[inline] - pub fn as_mut_ptr(&mut self) -> *mut ffi::EcdsaAdaptorSignature { - &mut self.0 - } -} - -impl EcdsaAdaptorSignature { - /// Creates an adaptor signature along with a proof to verify the adaptor signature. - /// This function derives a nonce using a similar process as described in BIP-340. - /// The nonce derivation process is strengthened against side channel - /// attacks by providing auxiliary randomness using the ThreadRng random number generator. - /// Requires compilation with "rand-std" feature. - #[cfg(feature = "rand-std")] - pub fn encrypt( - secp: &Secp256k1, - msg: &Message, - sk: &SecretKey, - enckey: &PublicKey, - ) -> EcdsaAdaptorSignature { - let mut rng = thread_rng(); - EcdsaAdaptorSignature::encrypt_with_rng(secp, msg, sk, enckey, &mut rng) - } - - /// Creates an adaptor signature along with a proof to verify the adaptor signature, - /// This function derives a nonce using a similar process as described in BIP-340. - /// The nonce derivation process is strengthened against side channel - /// attacks by providing auxiliary randomness using the provided random number generator. - /// Requires compilation with "rand" feature. - #[cfg(feature = "actual-rand")] - pub fn encrypt_with_rng( - secp: &Secp256k1, - msg: &Message, - sk: &SecretKey, - enckey: &PublicKey, - rng: &mut R, - ) -> EcdsaAdaptorSignature { - let mut aux = [0u8; 32]; - rng.fill_bytes(&mut aux); - EcdsaAdaptorSignature::encrypt_with_aux_rand(secp, msg, sk, enckey, &aux) - } - - /// Creates an adaptor signature along with a proof to verify the adaptor signature, - /// without using any auxiliary random data. Note that using this function - /// is still considered safe. - pub fn encrypt_no_aux_rand( - secp: &Secp256k1, - msg: &Message, - sk: &SecretKey, - enckey: &PublicKey, - ) -> EcdsaAdaptorSignature { - let mut adaptor_sig = ffi::EcdsaAdaptorSignature::new(); - - let res = unsafe { - ffi::secp256k1_ecdsa_adaptor_encrypt( - secp.ctx().as_ptr(), - &mut adaptor_sig, - sk.as_c_ptr(), - enckey.as_c_ptr(), - msg.as_c_ptr(), - ffi::secp256k1_nonce_function_ecdsa_adaptor, - ptr::null_mut(), - ) - }; - debug_assert_eq!(res, 1); - - EcdsaAdaptorSignature(adaptor_sig) - } - - /// Creates an adaptor signature along with a proof to verify the adaptor signature. - /// This function derives a nonce using a similar process as described in BIP-340. - /// The nonce derivation process is strengthened against side channel attacks by - /// using the provided auxiliary random data. - pub fn encrypt_with_aux_rand( - secp: &Secp256k1, - msg: &Message, - sk: &SecretKey, - enckey: &PublicKey, - aux_rand: &[u8; 32], - ) -> EcdsaAdaptorSignature { - let mut adaptor_sig = ffi::EcdsaAdaptorSignature::new(); - - let res = unsafe { - ffi::secp256k1_ecdsa_adaptor_encrypt( - secp.ctx().as_ptr(), - &mut adaptor_sig, - sk.as_c_ptr(), - enckey.as_c_ptr(), - msg.as_c_ptr(), - ffi::secp256k1_nonce_function_ecdsa_adaptor, - aux_rand.as_c_ptr() as *mut ffi::types::c_void, - ) - }; - debug_assert_eq!(res, 1); - - EcdsaAdaptorSignature(adaptor_sig) - } - - /// Creates an ECDSA signature from an adaptor signature and an adaptor secret. - pub fn decrypt(&self, decryption_key: &SecretKey) -> Result { - unsafe { - let mut signature = ffi::Signature::new(); - let ret = ffi::secp256k1_ecdsa_adaptor_decrypt( - ffi::secp256k1_context_no_precomp, - &mut signature, - decryption_key.as_c_ptr(), - self.as_c_ptr(), - ); - - if ret != 1 { - return Err(Error::CannotDecryptAdaptorSignature); - } - - Ok(Signature::from(signature)) - } - } - - /// Extracts the adaptor secret from the complete signature and the adaptor signature. - pub fn recover( - &self, - secp: &Secp256k1, - sig: &Signature, - encryption_key: &PublicKey, - ) -> Result { - let mut data: [u8; constants::SECRET_KEY_SIZE] = [0; constants::SECRET_KEY_SIZE]; - - let ret = unsafe { - ffi::secp256k1_ecdsa_adaptor_recover( - secp.ctx().as_ptr(), - data.as_mut_c_ptr(), - sig.as_c_ptr(), - self.as_c_ptr(), - encryption_key.as_c_ptr(), - ) - }; - - if ret != 1 { - return Err(Error::CannotRecoverAdaptorSecret); - } - - Ok(SecretKey::from_slice(&data)?) - } - - /// Verifies that the adaptor secret can be extracted from the adaptor signature and the completed ECDSA signature. - pub fn verify( - &self, - secp: &Secp256k1, - msg: &Message, - pubkey: &PublicKey, - encryption_key: &PublicKey, - ) -> Result<(), Error> { - let res = unsafe { - ffi::secp256k1_ecdsa_adaptor_verify( - secp.ctx().as_ptr(), - self.as_c_ptr(), - pubkey.as_c_ptr(), - msg.as_c_ptr(), - encryption_key.as_c_ptr(), - ) - }; - - if res != 1 { - return Err(Error::CannotVerifyAdaptorSignature); - }; - - Ok(()) - } -} - -#[cfg(all(test, feature = "global-context"))] -mod tests { - use super::Message; - use super::*; - #[cfg(not(rust_secp_fuzz))] - use crate::rand::{rngs::ThreadRng, thread_rng, RngCore}; - use crate::SECP256K1; - - #[cfg(not(rust_secp_fuzz))] - fn test_ecdsa_adaptor_signature_helper( - encrypt: fn(&Message, &SecretKey, &PublicKey, &mut ThreadRng) -> EcdsaAdaptorSignature, - ) { - let mut rng = thread_rng(); - let (seckey, pubkey) = SECP256K1.generate_keypair(&mut rng); - let (adaptor_secret, adaptor) = SECP256K1.generate_keypair(&mut rng); - let msg = Message::from_slice(&[2u8; 32]).unwrap(); - let adaptor_sig = encrypt(&msg, &seckey, &adaptor, &mut rng); - - adaptor_sig - .verify(&SECP256K1, &msg, &pubkey, &adaptor) - .expect("adaptor signature to be valid"); - adaptor_sig - .verify(&SECP256K1, &msg, &adaptor, &pubkey) - .expect_err("adaptor signature to be invalid"); - let sig = adaptor_sig - .decrypt(&adaptor_secret) - .expect("to be able to decrypt using the correct secret"); - SECP256K1 - .verify_ecdsa(&msg, &sig, &pubkey) - .expect("signature to be valid"); - let recovered = adaptor_sig - .recover(&SECP256K1, &sig, &adaptor) - .expect("to be able to recover the secret"); - assert_eq!(adaptor_secret, recovered); - } - - #[test] - #[cfg(not(rust_secp_fuzz))] - fn test_ecdsa_adaptor_signature_encrypt() { - test_ecdsa_adaptor_signature_helper(|msg, sk, adaptor, _| { - EcdsaAdaptorSignature::encrypt(&SECP256K1, msg, sk, adaptor) - }) - } - - #[test] - #[cfg(not(rust_secp_fuzz))] - fn test_ecdsa_adaptor_signature_encrypt_with_rng() { - test_ecdsa_adaptor_signature_helper(|msg, sk, adaptor, rng| { - EcdsaAdaptorSignature::encrypt_with_rng(&SECP256K1, msg, sk, adaptor, rng) - }) - } - - #[test] - #[cfg(not(rust_secp_fuzz))] - fn test_ecdsa_adaptor_signature_encrypt_with_aux_rand() { - test_ecdsa_adaptor_signature_helper(|msg, sk, adaptor, rng| { - let mut aux_rand = [0; 32]; - rng.fill_bytes(&mut aux_rand); - EcdsaAdaptorSignature::encrypt_with_aux_rand(&SECP256K1, msg, sk, adaptor, &aux_rand) - }) - } - - #[test] - #[cfg(not(rust_secp_fuzz))] - fn test_ecdsa_adaptor_signature_encrypt_no_aux_rand() { - test_ecdsa_adaptor_signature_helper(|msg, sk, adaptor, _| { - EcdsaAdaptorSignature::encrypt_no_aux_rand(&SECP256K1, msg, sk, adaptor) - }) - } - - #[test] - fn test_ecdsa_adaptor_signature_plain_valid() { - let msg = msg_from_str("8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d"); - let pubkey = "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c" - .parse() - .unwrap(); - let encryption_key = "02c2662c97488b07b6e819124b8989849206334a4c2fbdf691f7b34d2b16e9c293" - .parse() - .unwrap(); - let adaptor_sig : EcdsaAdaptorSignature = "03424d14a5471c048ab87b3b83f6085d125d5864249ae4297a57c84e74710bb6730223f325042fce535d040fee52ec13231bf709ccd84233c6944b90317e62528b2527dff9d659a96db4c99f9750168308633c1867b70f3a18fb0f4539a1aecedcd1fc0148fc22f36b6303083ece3f872b18e35d368b3958efe5fb081f7716736ccb598d269aa3084d57e1855e1ea9a45efc10463bbf32ae378029f5763ceb40173f" - .parse() - .unwrap(); - - adaptor_sig - .verify(&SECP256K1, &msg, &pubkey, &encryption_key) - .expect("adaptor signature verification to pass"); - - let sig = compact_sig_from_str("424d14a5471c048ab87b3b83f6085d125d5864249ae4297a57c84e74710bb67329e80e0ee60e57af3e625bbae1672b1ecaa58effe613426b024fa1621d903394"); - let expected_decryption_key: SecretKey = - "0b2aba63b885a0f0e96fa0f303920c7fb7431ddfa94376ad94d969fbf4109dc8" - .parse() - .unwrap(); - - let recovered = adaptor_sig - .recover(&SECP256K1, &sig, &encryption_key) - .expect("to be able to recover the decryption key"); - - assert_eq!(expected_decryption_key, recovered); - } - - #[test] - fn test_ecdsa_adaptor_signature_wrong_proof() { - let msg = msg_from_str("8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d"); - let pubkey = "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c" - .parse() - .unwrap(); - let encryption_key = "0214ccb756249ad6e733c80285ea7ac2ee12ffebbcee4e556e6810793a60c45ad4" - .parse() - .unwrap(); - let adaptor_sig: EcdsaAdaptorSignature = "03f94dca206d7582c015fb9bffe4e43b14591b30ef7d2b464d103ec5e116595dba03127f8ac3533d249280332474339000922eb6a58e3b9bf4fc7e01e4b4df2b7a4100a1e089f16e5d70bb89f961516f1de0684cc79db978495df2f399b0d01ed7240fa6e3252aedb58bdc6b5877b0c602628a235dd1ccaebdddcbe96198c0c21bead7b05f423b673d14d206fa1507b2dbe2722af792b8c266fc25a2d901d7e2c335" - .parse() - .unwrap(); - - adaptor_sig - .verify(&SECP256K1, &msg, &pubkey, &encryption_key) - .expect_err("providing a wrong proof should fail validation"); - } - - #[test] - fn test_ecdsa_adaptor_signature_recover_wrong_sig_r_value() { - let encryption_key = "035176d24129741b0fcaa5fd6750727ce30860447e0a92c9ebebdeb7c3f93995ed" - .parse() - .unwrap(); - let adaptor_sig: EcdsaAdaptorSignature = "03aa86d78059a91059c29ec1a757c4dc029ff636a1e6c1142fefe1e9d7339617c003a8153e50c0c8574a38d389e61bbb0b5815169e060924e4b5f2e78ff13aa7ad858e0c27c4b9eed9d60521b3f54ff83ca4774be5fb3a680f820a35e8840f4aaf2de88e7c5cff38a37b78725904ef97bb82341328d55987019bd38ae1745e3efe0f8ea8bdfede0d378fc1f96e944a7505249f41e93781509ee0bade77290d39cd12" - .parse() - .unwrap(); - - let sig = compact_sig_from_str("f7f7fe6bd056fc4abd70d335f72d0aa1e8406bba68f3e579e4789475323564a452c46176c7fb40aa37d5651341f55697dab27d84a213b30c93011a7790bace8c"); - adaptor_sig - .recover(&SECP256K1, &sig, &encryption_key) - .expect_err("providing wrong r value should prevent us from recovering decryption key"); - } - - #[test] - fn test_ecdsa_adaptor_signature_recover_from_high_s_signature() { - let encryption_key = "02042537e913ad74c4bbd8da9607ad3b9cb297d08e014afc51133083f1bd687a62" - .parse() - .unwrap(); - let adaptor_sig: EcdsaAdaptorSignature = "032c637cd797dd8c2ce261907ed43e82d6d1a48cbabbbece801133dd8d70a01b1403eb615a3e59b1cbbf4f87acaf645be1eda32a066611f35dd5557802802b14b19c81c04c3fefac5783b2077bd43fa0a39ab8a64d4d78332a5d621ea23eca46bc011011ab82dda6deb85699f508744d70d4134bea03f784d285b5c6c15a56e4e1fab4bc356abbdebb3b8fe1e55e6dd6d2a9ea457e91b2e6642fae69f9dbb5258854" - .parse() - .unwrap(); - - let sig = compact_sig_from_str("2c637cd797dd8c2ce261907ed43e82d6d1a48cbabbbece801133dd8d70a01b14b5f24321f550b7b9dd06ee4fcfd82bdad8b142ff93a790cc4d9f7962b38c6a3b"); - let expected_decryption_key: SecretKey = - "324719b51ff2474c9438eb76494b0dc0bcceeb529f0a5428fd198ad8f886e99c" - .parse() - .unwrap(); - let recovered = adaptor_sig - .recover(&SECP256K1, &sig, &encryption_key) - .expect("with high s we should still be able to recover the decryption key"); - - assert_eq!(expected_decryption_key, recovered); - } - - #[cfg(feature = "serde")] - #[test] - fn test_ecdsa_adaptor_sig_de_serialization() { - use serde_test::Configure; - use serde_test::{assert_tokens, Token}; - - let sig = EcdsaAdaptorSignature::from_slice(&[ - 3, 44, 99, 124, 215, 151, 221, 140, 44, 226, 97, 144, 126, 212, 62, 130, 214, 209, 164, - 140, 186, 187, 190, 206, 128, 17, 51, 221, 141, 112, 160, 27, 20, 3, 235, 97, 90, 62, - 89, 177, 203, 191, 79, 135, 172, 175, 100, 91, 225, 237, 163, 42, 6, 102, 17, 243, 93, - 213, 85, 120, 2, 128, 43, 20, 177, 156, 129, 192, 76, 63, 239, 172, 87, 131, 178, 7, - 123, 212, 63, 160, 163, 154, 184, 166, 77, 77, 120, 51, 42, 93, 98, 30, 162, 62, 202, - 70, 188, 1, 16, 17, 171, 130, 221, 166, 222, 184, 86, 153, 245, 8, 116, 77, 112, 212, - 19, 75, 234, 3, 247, 132, 210, 133, 181, 198, 193, 90, 86, 228, 225, 250, 180, 188, 53, - 106, 187, 222, 187, 59, 143, 225, 229, 94, 109, 214, 210, 169, 234, 69, 126, 145, 178, - 230, 100, 47, 174, 105, 249, 219, 181, 37, 136, 84, - ]) - .unwrap(); - - assert_tokens( - &sig.readable(), - &[Token::Str( - "032c637cd797dd8c2ce261907ed43e82d6d1a48cbabbbece801133dd8d70a01b1403eb615a3e59b1cbbf4f87acaf645be1eda32a066611f35dd5557802802b14b19c81c04c3fefac5783b2077bd43fa0a39ab8a64d4d78332a5d621ea23eca46bc011011ab82dda6deb85699f508744d70d4134bea03f784d285b5c6c15a56e4e1fab4bc356abbdebb3b8fe1e55e6dd6d2a9ea457e91b2e6642fae69f9dbb5258854", - )], - ); - - assert_tokens( - &sig.compact(), - &[Token::Bytes(&[ - 3, 44, 99, 124, 215, 151, 221, 140, 44, 226, 97, 144, 126, 212, 62, 130, 214, 209, - 164, 140, 186, 187, 190, 206, 128, 17, 51, 221, 141, 112, 160, 27, 20, 3, 235, 97, - 90, 62, 89, 177, 203, 191, 79, 135, 172, 175, 100, 91, 225, 237, 163, 42, 6, 102, - 17, 243, 93, 213, 85, 120, 2, 128, 43, 20, 177, 156, 129, 192, 76, 63, 239, 172, - 87, 131, 178, 7, 123, 212, 63, 160, 163, 154, 184, 166, 77, 77, 120, 51, 42, 93, - 98, 30, 162, 62, 202, 70, 188, 1, 16, 17, 171, 130, 221, 166, 222, 184, 86, 153, - 245, 8, 116, 77, 112, 212, 19, 75, 234, 3, 247, 132, 210, 133, 181, 198, 193, 90, - 86, 228, 225, 250, 180, 188, 53, 106, 187, 222, 187, 59, 143, 225, 229, 94, 109, - 214, 210, 169, 234, 69, 126, 145, 178, 230, 100, 47, 174, 105, 249, 219, 181, 37, - 136, 84, - ])], - ); - } - - fn msg_from_str(input: &str) -> Message { - let mut buf = [0u8; 32]; - from_hex(input, &mut buf).unwrap(); - Message::from_slice(&buf).unwrap() - } - - fn compact_sig_from_str(input: &str) -> Signature { - let mut buf = [0u8; 64]; - from_hex(input, &mut buf).unwrap(); - Signature::from_compact(&buf).unwrap() - } -} diff --git a/ark-rust-secp256k1-zkp/src/zkp/generator.rs b/ark-rust-secp256k1-zkp/src/zkp/generator.rs deleted file mode 100644 index 66f28da0..00000000 --- a/ark-rust-secp256k1-zkp/src/zkp/generator.rs +++ /dev/null @@ -1,270 +0,0 @@ -use crate::ffi::{self, CPtr}; -use crate::{constants, from_hex, Error, Secp256k1, Signing, Tag}; -use core::{fmt, str}; -#[cfg(feature = "actual-rand")] -use rand::Rng; - -/// Represents a blinding factor/Tweak on secp256k1 curve -/// -/// Contrary to a [`crate::SecretKey`], the value 0 is also a valid tweak. -/// Values outside secp curve order are invalid tweaks. -#[derive(Default, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] -pub struct Tweak([u8; constants::SECRET_KEY_SIZE]); -secp256k1_zkp_sys::impl_array_newtype!(Tweak, u8, constants::SECRET_KEY_SIZE); - -/// The zero Tweak -pub const ZERO_TWEAK: Tweak = Tweak([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]); - -impl fmt::Debug for Tweak { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Tweak(")?; - for i in self[..].iter() { - write!(f, "{:02x}", i)?; - } - write!(f, ")") - } -} - -impl fmt::LowerHex for Tweak { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for ch in &self.0[..] { - write!(f, "{:02x}", *ch)?; - } - Ok(()) - } -} - -impl fmt::Display for Tweak { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::LowerHex::fmt(self, f) - } -} - -impl str::FromStr for Tweak { - type Err = Error; - fn from_str(s: &str) -> Result { - let mut res = [0; constants::SECRET_KEY_SIZE]; - match from_hex(s, &mut res) { - Ok(constants::SECRET_KEY_SIZE) => Tweak::from_inner(res), - _ => Err(Error::InvalidTweakLength), - } - } -} - -impl Tweak { - /// Generate a new random Tweak - #[cfg(feature = "actual-rand")] - pub fn new(rng: &mut R) -> Tweak { - let mut ret = [0u8; constants::SECRET_KEY_SIZE]; - rng.fill_bytes(&mut ret); - Tweak(ret) - } - - /// Converts a byte slice to a Tweak - /// Fails if tweak is not 32 bytes or if tweak is outside secp curve order - #[inline] - pub fn from_slice(data: &[u8]) -> Result { - match data.len() { - constants::SECRET_KEY_SIZE => { - let mut ret = [0; constants::SECRET_KEY_SIZE]; - unsafe { - if ffi::secp256k1_ec_seckey_verify( - ffi::secp256k1_context_no_precomp, - data.as_ref().as_c_ptr(), - ) == 0 - { - if data.iter().all(|x| *x == 0) { - return Ok(Tweak(ret)); - } - return Err(Error::TweakOutOfBounds); - } - } - ret[..].copy_from_slice(data); - Ok(Tweak(ret)) - } - _ => Err(Error::InvalidTweakLength), - } - } - - /// Converts a `SECRET_KEY_SIZE`(32)- array to a tweak - #[inline] - pub fn from_inner(data: [u8; 32]) -> Result { - unsafe { - if ffi::secp256k1_ec_seckey_verify( - ffi::secp256k1_context_no_precomp, - data.as_ref().as_c_ptr(), - ) == 0 - { - if data.iter().all(|x| *x == 0) { - return Ok(Tweak(data)); - } - return Err(Error::TweakOutOfBounds); - } - } - Ok(Tweak(data)) - } -} -/// Represents a generator on the secp256k1 curve. -/// -/// A generator is a public key internally but has a slightly different serialization with the first byte being tweaked. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub struct Generator(ffi::PublicKey); - -impl Generator { - /// Serialize the generator to a byte array. - pub fn serialize(&self) -> [u8; 33] { - let mut output = [0u8; 33]; - - let ret = unsafe { - ffi::secp256k1_generator_serialize( - ffi::secp256k1_context_no_precomp, - output.as_mut_ptr(), - &self.0, - ) - }; - // TODO: Replace most assert_eq with debug_assert_eq - assert_eq!(ret, 1); - - output - } - - /// Parse a generator from a slice of bytes. - pub fn from_slice(bytes: &[u8]) -> Result { - let mut public_key = unsafe { ffi::PublicKey::new() }; - - let ret = unsafe { - ffi::secp256k1_generator_parse( - ffi::secp256k1_context_no_precomp, - &mut public_key, - bytes.as_ptr(), - ) - }; - - if ret == 0 { - return Err(Error::InvalidGenerator); - } - - Ok(Generator(public_key)) - } - - /// Creates a new [`Generator`] by blinding a [`Tag`] using the given blinding factor. - /// Use [Generator::new_unblinded] for creating a [`Generator`] with zero blinding factor - pub fn new_blinded(secp: &Secp256k1, tag: Tag, blinding_factor: Tweak) -> Self { - let mut generator = unsafe { ffi::PublicKey::new() }; - - let ret = unsafe { - ffi::secp256k1_generator_generate_blinded( - secp.ctx().as_ptr(), - &mut generator, - tag.into_inner().as_c_ptr(), - blinding_factor.as_c_ptr(), - ) - }; - assert_eq!(ret, 1); - - Generator(generator) - } - - /// Creates a new unblinded [`Generator`] by from [`Tag`] - /// Same as using zero [`Tweak`] with [`Generator::new_blinded`] - pub fn new_unblinded(secp: &Secp256k1, tag: Tag) -> Self { - Generator::new_blinded(secp, tag, ZERO_TWEAK) - } - - /// Extracts the internal representation of this generator. - /// - /// This is `pub(crate)` because generators have a different serialization from regular public keys. - /// As such, certain invariants need to be upheld which is easier if we don't allow users to access the internal representation of generators. - #[cfg(feature = "std")] // for un-used warnings - pub(crate) fn as_inner(&self) -> &ffi::PublicKey { - &self.0 - } -} - -impl fmt::LowerHex for Generator { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let ser = self.serialize(); - for ch in &ser[..] { - write!(f, "{:02x}", *ch)?; - } - Ok(()) - } -} - -impl fmt::Display for Generator { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::LowerHex::fmt(self, f) - } -} - -impl str::FromStr for Generator { - type Err = Error; - fn from_str(s: &str) -> Result { - let mut res = [0; constants::PUBLIC_KEY_SIZE]; - match from_hex(s, &mut res) { - Ok(constants::PUBLIC_KEY_SIZE) => Self::from_slice(&res[0..constants::PUBLIC_KEY_SIZE]), - _ => Err(Error::InvalidGenerator), - } - } -} - -#[cfg(feature = "serde")] -impl ::serde::Serialize for Generator { - fn serialize(&self, s: S) -> Result { - if s.is_human_readable() { - s.collect_str(self) - } else { - s.serialize_bytes(&self.serialize()) - } - } -} - -#[cfg(feature = "serde")] -impl<'de> ::serde::Deserialize<'de> for Generator { - fn deserialize>(d: D) -> Result { - use crate::serde_util; - - if d.is_human_readable() { - d.deserialize_str(serde_util::FromStrVisitor::new("an ASCII hex string")) - } else { - d.deserialize_bytes(serde_util::BytesVisitor::new( - "a bytestring", - Generator::from_slice, - )) - } - } -} - -#[cfg(feature = "serde")] -impl ::serde::Serialize for Tweak { - fn serialize(&self, s: S) -> Result { - if s.is_human_readable() { - s.collect_str(self) - } else { - s.serialize_bytes(self.as_ref()) - } - } -} - -#[cfg(feature = "serde")] -impl<'de> ::serde::Deserialize<'de> for Tweak { - fn deserialize>(d: D) -> Result { - use crate::serde_util; - - if d.is_human_readable() { - d.deserialize_str(serde_util::FromStrVisitor::new("an ASCII hex string")) - } else { - d.deserialize_bytes(serde_util::BytesVisitor::new( - "a bytestring", - Tweak::from_slice, - )) - } - } -} - -#[cfg(test)] -mod tests { - // TODO: Test prefix of serialization -} diff --git a/ark-rust-secp256k1-zkp/src/zkp/mod.rs b/ark-rust-secp256k1-zkp/src/zkp/mod.rs deleted file mode 100644 index 5bd0e8f6..00000000 --- a/ark-rust-secp256k1-zkp/src/zkp/mod.rs +++ /dev/null @@ -1,28 +0,0 @@ -mod ecdsa_adaptor; -mod generator; -#[cfg(feature = "std")] -pub mod musig; -#[cfg(feature = "std")] -pub use self::musig::new_musig_nonce_pair; - -#[cfg(feature = "std")] -mod pedersen; -#[cfg(feature = "std")] -mod rangeproof; -#[cfg(feature = "std")] -mod surjection_proof; -mod tag; -mod whitelist; - -pub use self::ecdsa_adaptor::*; -pub use self::generator::*; -#[cfg(feature = "std")] -pub use self::musig::*; -#[cfg(feature = "std")] -pub use self::pedersen::*; -#[cfg(feature = "std")] -pub use self::rangeproof::*; -#[cfg(feature = "std")] -pub use self::surjection_proof::*; -pub use self::tag::*; -pub use self::whitelist::*; diff --git a/ark-rust-secp256k1-zkp/src/zkp/musig.rs b/ark-rust-secp256k1-zkp/src/zkp/musig.rs deleted file mode 100644 index 7a8948b9..00000000 --- a/ark-rust-secp256k1-zkp/src/zkp/musig.rs +++ /dev/null @@ -1,1518 +0,0 @@ -//! This module implements high-level Rust bindings for a Schnorr-based -//! multi-signature scheme called MuSig2 [paper](https://eprint.iacr.org/2020/1261). -//! It is compatible with bip-schnorr. -//! -//! The module also supports adaptor signatures as described in -//! [scriptless-scripts repo](https://github.com/ElementsProject/scriptless-scripts) -//! -//! The documentation in this module is for reference and may not be sufficient -//! for advanced use-cases. A full description of the C API usage along with security considerations -//! can be found in [C-musig.md](secp256k1-sys/depend/secp256k1/src/modules/musig/musig.md). -use core::fmt; -use {core, std}; - -use crate::ffi::{self, CPtr}; -use crate::ZERO_TWEAK; -use crate::{schnorr, Keypair, XOnlyPublicKey}; -use crate::{Message, PublicKey, Secp256k1, SecretKey, Tweak}; -use crate::{Signing, Verification}; -use secp256k1::Parity; - -#[cfg(feature = "actual-rand")] -use rand::{CryptoRng, RngCore}; -use secp256k1_zkp_sys::MUSIG_SECNONCE_LEN; - -/// Cached data related to a key aggregation. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct MusigKeyAggCache(ffi::MusigKeyAggCache, XOnlyPublicKey); - -/// Session Id for a MuSig session. -/// -/// # NOTE: -/// -/// Each call to this nonce generation APIs must have a UNIQUE session_id. This must NOT BE -/// REUSED in subsequent calls to nonce generation APIs such as [`MusigKeyAggCache::nonce_gen`] -/// or [`new_musig_nonce_pair`]. -pub struct MusigSessionId([u8; 32]); - -impl MusigSessionId { - /// Creates a new [`MusigSessionId`] with thread local random bytes - #[cfg(feature = "rand-std")] - #[cfg_attr(docsrs, doc(cfg(feature = "rand-std")))] - pub fn random() -> Self { - MusigSessionId::new(&mut rand::thread_rng()) - } - - /// Creates a new [`MusigSessionId`] with random bytes from the given rng - #[cfg(feature = "actual-rand")] - pub fn new(rng: &mut R) -> Self { - let mut session_id = [0u8; 32]; - rng.fill_bytes(&mut session_id); - MusigSessionId(session_id) - } - - /// Creates a new [`MusigSessionId`] with the given bytes. - /// - /// Special care must be taken that the bytes are unique for each call to - /// [`MusigKeyAggCache::nonce_gen`] or [`new_musig_nonce_pair`]. The simplest - /// recommendation is to use a random 32-byte value. Refer to upstream libsecp256k1-zkp - /// documentation for more details. - /// - /// In rand-std environment, [`MusigSessionId::random`] can be used to generate a random - /// session id using thread rng. - pub fn assume_unique_per_nonce_gen(inner: [u8; 32]) -> Self { - MusigSessionId(inner) - } - - /// Obtains the inner bytes of the [`MusigSessionId`]. - pub fn to_bytes(&self) -> [u8; 32] { - self.0 - } - - /// Obtains a reference to the inner bytes of the [`MusigSessionId`]. - pub fn as_bytes(&self) -> &[u8; 32] { - &self.0 - } -} - -impl CPtr for MusigKeyAggCache { - type Target = ffi::MusigKeyAggCache; - - fn as_c_ptr(&self) -> *const Self::Target { - self.as_ptr() - } - - fn as_mut_c_ptr(&mut self) -> *mut Self::Target { - self.as_mut_ptr() - } -} - -impl MusigKeyAggCache { - /// Creates a new [`MusigKeyAggCache`] by supplying a list of PublicKeys used in the session. - /// - /// Computes a combined public key and the hash of the given public keys. - /// - /// Different orders of `pubkeys` result in different `agg_pk`s. - /// The pubkeys can be sorted lexicographically before combining with which - /// ensures the same resulting `agg_pk` for the same multiset of pubkeys. - /// This is useful to do before aggregating pubkeys, such that the order of pubkeys - /// does not affect the combined public key. - /// - /// # Returns - /// - /// A [`MusigKeyAggCache`] the can be used [`MusigKeyAggCache::nonce_gen`] and [`MusigSession::new`]. - /// - /// # Args: - /// - /// * `secp` - Secp256k1 context object initialized for verification - /// * `pubkeys` - Input array of public keys to combine. The order is important; a - /// different order will result in a different combined public key - /// - /// Example: - /// - /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1_zkp::rand::{thread_rng, RngCore}; - /// # use secp256k1_zkp::{MusigKeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey}; - /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); - /// # - /// let key_agg_cache = MusigKeyAggCache::new(&secp, &[pub_key1, pub_key2]); - /// let _agg_pk = key_agg_cache.agg_pk(); - /// # } - /// ``` - pub fn new(secp: &Secp256k1, pubkeys: &[PublicKey]) -> Self { - let cx = secp.ctx().as_ptr(); - let pubkey_ptrs = pubkeys.iter().map(|k| k.as_c_ptr()).collect::>(); - let mut key_agg_cache = ffi::MusigKeyAggCache::new(); - - unsafe { - let mut agg_pk = XOnlyPublicKey::from(ffi::XOnlyPublicKey::new()); - if ffi::secp256k1_musig_pubkey_agg( - cx, - // Pass null ptr as scratch space - core::ptr::null_mut(), - agg_pk.as_mut_c_ptr(), - &mut key_agg_cache, - pubkey_ptrs.as_ptr(), - pubkey_ptrs.len(), - ) == 0 - { - // Returns 0 only if the keys are malformed that never happens in safe rust type system. - unreachable!("Invalid XOnlyPublicKey in input pubkeys") - } else { - MusigKeyAggCache(key_agg_cache, agg_pk) - } - } - } - - /// Obtains the aggregate public key for this [`MusigKeyAggCache`] - pub fn agg_pk(&self) -> XOnlyPublicKey { - self.1 - } - - /// Obtains the aggregate public key for this [`MusigKeyAggCache`] as a full [`PublicKey`]. - /// - /// This is only useful if you need the non-xonly public key, in particular for - /// plain (non-xonly) tweaking or batch-verifying multiple key aggregations - /// (not supported yet). - pub fn agg_pk_full(&self) -> PublicKey { - unsafe { - let mut pk = PublicKey::from(ffi::PublicKey::new()); - if ffi::secp256k1_musig_pubkey_get( - ffi::secp256k1_context_no_precomp, - pk.as_mut_c_ptr(), - self.as_ptr(), - ) == 0 - { - // Returns 0 only if the keys are malformed that never happens in safe rust type system. - unreachable!("All the arguments are valid") - } else { - pk - } - } - } - - /// Apply ordinary "EC" tweaking to a public key in a [`MusigKeyAggCache`]. - /// - /// This is done by adding the generator multiplied with `tweak32` to it. Returns the tweaked [`PublicKey`]. - /// This is useful for deriving child keys from an aggregate public key via BIP32. - /// This function is required if you want to _sign_ for a tweaked aggregate key. - /// - /// # Arguments: - /// - /// * `secp` : [`Secp256k1`] context object initialized for verification - /// * `tweak`: tweak of type [`SecretKey`] with which to tweak the aggregated key - /// - /// # Errors: - /// - /// If resulting public key would be invalid (only when the tweak is the negation of the corresponding - /// secret key). For uniformly random 32-byte arrays(for example, in BIP 32 derivation) the chance of - /// being invalid is negligible (around 1 in 2^128). - /// - /// Example: - /// - /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1_zkp::rand::{thread_rng, RngCore}; - /// # use secp256k1_zkp::{MusigKeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey}; - /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); - /// # - /// let mut key_agg_cache = MusigKeyAggCache::new(&secp, &[pub_key1, pub_key2]); - /// - /// let tweak = SecretKey::from_slice(b"Insecure tweak, Don't use this!!").unwrap(); // tweak could be from BIP32 - /// let _tweaked_key = key_agg_cache.pubkey_ec_tweak_add(&secp, tweak).unwrap(); - /// # } - /// ``` - pub fn pubkey_ec_tweak_add( - &mut self, - secp: &Secp256k1, - tweak: SecretKey, - ) -> Result { - let cx = secp.ctx().as_ptr(); - unsafe { - let mut out = PublicKey::from(ffi::PublicKey::new()); - if ffi::secp256k1_musig_pubkey_ec_tweak_add( - cx, - out.as_mut_c_ptr(), - self.as_mut_ptr(), - tweak.as_c_ptr(), - ) == 0 - { - Err(MusigTweakErr::InvalidTweak) - } else { - Ok(out) - } - } - } - - /// Apply "x-only" tweaking to a public key in a [`MusigKeyAggCache`]. - /// - /// This is done by adding the generator multiplied with `tweak32` to it. Returns the tweaked [`XOnlyPublicKey`]. - /// This is useful in creating taproot outputs. - /// This function is required if you want to _sign_ for a tweaked aggregate key. - /// - /// # Arguments: - /// - /// * `secp` : [`Secp256k1`] context object initialized for verification - /// * `tweak`: tweak of type [`SecretKey`] with which to tweak the aggregated key - /// - /// # Errors: - /// - /// If resulting public key would be invalid (only when the tweak is the negation of the corresponding - /// secret key). For uniformly random 32-byte arrays(for example, in BIP341 taproot tweaks) the chance of - /// being invalid is negligible (around 1 in 2^128) - /// - /// Example: - /// - /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1_zkp::rand::{thread_rng, RngCore}; - /// # use secp256k1_zkp::{MusigKeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey}; - /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); - /// - /// let mut key_agg_cache = MusigKeyAggCache::new(&secp, &[pub_key1, pub_key2]); - /// - /// let tweak = SecretKey::from_slice(b"Insecure tweak, Don't use this!!").unwrap(); // tweak could be from tap - /// let _x_only_key_tweaked = key_agg_cache.pubkey_xonly_tweak_add(&secp, tweak).unwrap(); - /// # } - /// ``` - pub fn pubkey_xonly_tweak_add( - &mut self, - secp: &Secp256k1, - tweak: SecretKey, - ) -> Result { - let cx = secp.ctx().as_ptr(); - unsafe { - let mut out = PublicKey::from(ffi::PublicKey::new()); - if ffi::secp256k1_musig_pubkey_xonly_tweak_add( - cx, - out.as_mut_c_ptr(), - self.as_mut_ptr(), - tweak.as_c_ptr(), - ) == 0 - { - Err(MusigTweakErr::InvalidTweak) - } else { - Ok(out) - } - } - } - - /// Starts a signing session by generating a nonce - /// - /// This function outputs a secret nonce that will be required for signing and a - /// corresponding public nonce that is intended to be sent to other signers. - /// - /// MuSig differs from regular Schnorr signing in that implementers _must_ take - /// special care to not reuse a nonce. If you cannot provide a `sec_key`, `session_id` - /// UNIFORMLY RANDOM AND KEPT SECRET (even from other signers). - /// Refer to libsecp256k1-zkp documentation for additional considerations. - /// - /// Musig2 nonces can be precomputed without knowing the aggregate public key, the message to sign. - /// See the `new_nonce_pair` method that allows generating [`MusigSecNonce`] and [`MusigPubNonce`] - /// with only the `session_id` field. - /// - /// Remember that nonce reuse will immediately leak the secret key! - /// - /// # Returns: - /// - /// A pair of ([`MusigSecNonce`], [`MusigPubNonce`]) that can be later used signing and aggregation - /// - /// # Arguments: - /// - /// * `secp` : [`Secp256k1`] context object initialized for signing - /// * `session_id`: [`MusigSessionId`] Uniform random identifier for this session. Each call to this - /// function must have a UNIQUE `session_id`. - /// * `pub_key`: [`PublicKey`] of the signer creating the nonce. - /// * `msg`: [`Message`] that will be signed later on. - /// * `extra_rand`: Additional randomness for mis-use resistance - /// - /// # Errors: - /// - /// * `ZeroSession`: if the `session_id` is supplied is all zeros. - /// - /// Example: - /// - /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1_zkp::rand::{thread_rng, RngCore}; - /// # use secp256k1_zkp::{MusigKeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, MusigSessionId, Message}; - /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); - /// # - /// let key_agg_cache = MusigKeyAggCache::new(&secp, &[pub_key1, pub_key2]); - /// // The session id must be sampled at random. Read documentation for more details. - /// let session_id = MusigSessionId::new(&mut thread_rng()); - /// - /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); - /// - /// // Provide the current time for mis-use resistance - /// let extra_rand : Option<[u8; 32]> = None; - /// let (_sec_nonce, _pub_nonce) = key_agg_cache.nonce_gen(&secp, session_id, pub_key1, msg, extra_rand) - /// .expect("non zero session id"); - /// # } - /// ``` - pub fn nonce_gen( - &self, - secp: &Secp256k1, - session_id: MusigSessionId, - pub_key: PublicKey, - msg: Message, - extra_rand: Option<[u8; 32]>, - ) -> Result<(MusigSecNonce, MusigPubNonce), MusigNonceGenError> { - // The secret key here is supplied as NULL. This is okay because we supply the - // public key and the message. - // This makes a simple API for the user because it does not require them to pass here. - new_musig_nonce_pair( - secp, - session_id, - Some(&self), - None, - pub_key, - Some(msg), - extra_rand, - ) - } - - /// Get a const pointer to the inner MusigKeyAggCache - pub fn as_ptr(&self) -> *const ffi::MusigKeyAggCache { - &self.0 - } - - /// Get a mut pointer to the inner MusigKeyAggCache - pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigKeyAggCache { - &mut self.0 - } -} - -/// Musig tweaking related errors. -#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)] -pub enum MusigTweakErr { - /// Invalid tweak (tweak is the negation of the corresponding secret key). - InvalidTweak, -} - -#[cfg(feature = "std")] -impl std::error::Error for MusigTweakErr {} - -impl fmt::Display for MusigTweakErr { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self { - MusigTweakErr::InvalidTweak => write!( - f, - "Invalid Tweak: This only happens when - tweak is negation of secret key" - ), - } - } -} - -/// Musig Nonce generation errors -#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)] -pub enum MusigNonceGenError { - /// Supplied a zero session id - ZeroSession, -} - -#[cfg(feature = "std")] -impl std::error::Error for MusigNonceGenError {} - -impl fmt::Display for MusigNonceGenError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self { - MusigNonceGenError::ZeroSession => write!(f, "Supplied a zero session id"), - } - } -} -/// Low level API for starting a signing session by generating a nonce. -/// -/// Use [`MusigKeyAggCache::nonce_gen`] whenever -/// possible. This API provides full flexibility in providing custom nonce generation, -/// but should be use with care. -/// -/// This function outputs a secret nonce that will be required for signing and a -/// corresponding public nonce that is intended to be sent to other signers. -/// -/// MuSig differs from regular Schnorr signing in that implementers _must_ take -/// special care to not reuse a nonce. If you cannot provide a `sec_key`, `session_id` -/// UNIFORMLY RANDOM AND KEPT SECRET (even from other signers). Refer to libsecp256k1-zkp -/// documentation for additional considerations. -/// -/// Musig2 nonces can be precomputed without knowing the aggregate public key, the message to sign. -/// Refer to libsecp256k1-zkp documentation for additional considerations. -/// -/// # Arguments: -/// -/// * `secp` : [`Secp256k1`] context object initialized for signing -/// * `session_id`: [`MusigSessionId`] Uniform random identifier for this session. Each call to this -/// function must have a UNIQUE `session_id`. -/// * `sec_key`: Optional [`SecretKey`] that we will use to sign to a create partial signature. Provide this -/// for maximal mis-use resistance. -/// * `pub_key`: [`PublicKey`] that we will use to create partial signature. The secnonce -/// output of this function cannot be used to sign for any other public key. -/// * `msg`: Optional [`Message`] that will be signed later on. Provide this for maximal misuse resistance. -/// * `extra_rand`: Additional randomness for mis-use resistance. Provide this for maximal misuse resistance -/// -/// Remember that nonce reuse will immediately leak the secret key! -/// -/// # Errors: -/// -/// * `ZeroSession`: if the `session_id` is supplied is all zeros. -/// -/// Example: -/// -/// ```rust -/// # # [cfg(any(test, feature = "rand-std"))] { -/// # use secp256k1_zkp::rand::{thread_rng, RngCore}; -/// # use secp256k1_zkp::{PublicKey, Secp256k1, SecretKey, new_musig_nonce_pair, MusigSessionId}; -/// # let secp = Secp256k1::new(); -/// // The session id must be sampled at random. Read documentation for more details. -/// let session_id = MusigSessionId::new(&mut thread_rng()); -/// let sk = SecretKey::new(&mut thread_rng()); -/// let pk = PublicKey::from_secret_key(&secp, &sk); -/// -/// // Supply extra auxillary randomness to prevent misuse(for example, time of day) -/// let extra_rand : Option<[u8; 32]> = None; -/// -/// let (_sec_nonce, _pub_nonce) = new_musig_nonce_pair(&secp, session_id, None, Some(sk), pk, None, None) -/// .expect("non zero session id"); -/// # } -/// ``` -pub fn new_musig_nonce_pair( - secp: &Secp256k1, - session_id: MusigSessionId, - key_agg_cache: Option<&MusigKeyAggCache>, - sec_key: Option, - pub_key: PublicKey, - msg: Option, - extra_rand: Option<[u8; 32]>, -) -> Result<(MusigSecNonce, MusigPubNonce), MusigNonceGenError> { - let cx = secp.ctx().as_ptr(); - let extra_ptr = extra_rand - .as_ref() - .map(|e| e.as_ptr()) - .unwrap_or(core::ptr::null()); - let sk_ptr = sec_key - .as_ref() - .map(|e| e.as_c_ptr()) - .unwrap_or(core::ptr::null()); - let msg_ptr = msg - .as_ref() - .map(|ref e| e.as_c_ptr()) - .unwrap_or(core::ptr::null()); - let cache_ptr = key_agg_cache - .map(|e| e.as_ptr()) - .unwrap_or(core::ptr::null()); - unsafe { - let mut sec_nonce = MusigSecNonce(ffi::MusigSecNonce::new()); - let mut pub_nonce = MusigPubNonce(ffi::MusigPubNonce::new()); - if ffi::secp256k1_musig_nonce_gen( - cx, - sec_nonce.as_mut_ptr(), - pub_nonce.as_mut_ptr(), - session_id.as_bytes().as_ptr(), - sk_ptr, - pub_key.as_c_ptr(), - msg_ptr, - cache_ptr, - extra_ptr, - ) == 0 - { - // Rust type system guarantees that - // - input secret key is valid - // - msg is 32 bytes - // - Key agg cache is valid - // - extra input is 32 bytes - // This can only happen when the session id is all zeros - Err(MusigNonceGenError::ZeroSession) - } else { - Ok((sec_nonce, pub_nonce)) - } - } -} - -/// A Musig partial signature. -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct MusigPartialSignature(ffi::MusigPartialSignature); - -impl CPtr for MusigPartialSignature { - type Target = ffi::MusigPartialSignature; - - fn as_c_ptr(&self) -> *const Self::Target { - self.as_ptr() - } - - fn as_mut_c_ptr(&mut self) -> *mut Self::Target { - self.as_mut_ptr() - } -} - -impl MusigPartialSignature { - /// Serialize a MuSigPartialSignature. - /// - /// # Returns - /// - /// 32-byte array - pub fn serialize(&self) -> [u8; 32] { - let mut data = [0; 32]; - unsafe { - if ffi::secp256k1_musig_partial_sig_serialize( - ffi::secp256k1_context_no_precomp, - data.as_mut_ptr(), - self.as_ptr(), - ) == 0 - { - // Only fails if args are null pointer which is possible in safe rust - unreachable!("Serialization cannot fail") - } else { - data - } - } - } - - /// Deserialize a MusigPartialSignature from bytes. - /// - /// # Errors: - /// - /// - ArgLenMismatch: If the signature is not 32 bytes - /// - MalformedArg: If the signature is 32 bytes, but out of curve order - pub fn from_slice(data: &[u8]) -> Result { - let mut part_sig = MusigPartialSignature(ffi::MusigPartialSignature::new()); - if data.len() != 32 { - return Err(ParseError::ArgLenMismatch { - expected: 32, - got: data.len(), - }); - } - unsafe { - if ffi::secp256k1_musig_partial_sig_parse( - ffi::secp256k1_context_no_precomp, - part_sig.as_mut_ptr(), - data.as_ptr(), - ) == 0 - { - Err(ParseError::MalformedArg) - } else { - Ok(part_sig) - } - } - } - - /// Get a const pointer to the inner MusigPartialSignature - pub fn as_ptr(&self) -> *const ffi::MusigPartialSignature { - &self.0 - } - - /// Get a mut pointer to the inner MusigPartialSignature - pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigPartialSignature { - &mut self.0 - } -} - -/// Musig partial signature parsing errors -#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)] -pub enum ParseError { - /// Length mismatch - ArgLenMismatch { - /// Expected size. - expected: usize, - /// Actual size. - got: usize, - }, - /// Parse Argument is malformed. This might occur if the point is on the secp order, - /// or if the secp scalar is outside of group order - MalformedArg, -} - -#[cfg(feature = "std")] -impl std::error::Error for ParseError {} - -impl fmt::Display for ParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match *self { - ParseError::ArgLenMismatch { expected, got } => { - write!(f, "Argument must be {} bytes, got {}", expected, got) - } - ParseError::MalformedArg => write!(f, "Malformed parse argument"), - } - } -} - -/// Creates a signature from a pre-signature and an adaptor. -/// -/// # Arguments: -/// -/// * `pre_sig` : [`schnorr::Signature`] to which the adaptor is to be added -/// * `sec_adaptor` : Secret adaptor of [`Tweak`] type to add to pre signature -/// * `nonce_parity`: The [`Parity`] obtained by [`MusigSession::nonce_parity`] for the session -/// used to compute `pre_sig`. -/// -/// # Returns: -/// -/// The [`schnorr::Signature`] with the adaptor applied. -/// -pub fn adapt( - pre_sig: schnorr::Signature, - sec_adaptor: Tweak, - nonce_parity: Parity, -) -> schnorr::Signature { - unsafe { - let mut sig = pre_sig; - if ffi::secp256k1_musig_adapt( - ffi::secp256k1_context_no_precomp, - sig.as_mut_c_ptr(), - pre_sig.as_c_ptr(), - sec_adaptor.as_c_ptr(), - nonce_parity.to_i32(), - ) == 0 - { - // Only fails when the arguments are invalid which is not possible in safe rust - unreachable!("Arguments must be valid and well-typed") - } else { - schnorr::Signature::from_slice(sig.as_ref()) - .expect("Adapted signatures from pre-sig must be valid schnorr signatures") - } - } -} - -/// Extracts a secret adaptor from a MuSig. -/// -/// Extracts a secret adaptor from a MuSig, given all parties' partial -/// signatures. This function will not fail unless given grossly invalid data; if it -/// is merely given signatures that do not verify, the returned value will be -/// nonsense. It is therefore important that all data be verified at earlier steps of -/// any protocol that uses this function. -/// -/// # Arguments: -/// -/// * `sig`: the [`schnorr::Signature`] with the adaptor applied. -/// * `pre_sig` : Secret adaptor of [`SecretKey`] type to add to pre signature -/// corresponding to `sig`. This is the aggregation of all [`MusigPartialSignature`] without -/// the adaptor -/// * `nonce_parity`: The [`Parity`] obtained by [`MusigSession::nonce_parity`] for the session -/// used to compute `pre_sig64`. -/// -/// # Returns: -/// -/// The adaptor secret of [`Tweak`]. The [`Tweak`] type is like [`SecretKey`], but also -/// allows for representing the zero value. -/// -/// Example: -/// -/// ```rust -/// # # [cfg(any(test, feature = "rand-std"))] { -/// # use secp256k1_zkp::rand::{thread_rng, RngCore}; -/// # use secp256k1_zkp::{MusigKeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, MusigSessionId, Message, MusigAggNonce, MusigSession, adapt, extract_adaptor, Tweak}; -/// # let secp = Secp256k1::new(); -/// # let sk1 = SecretKey::new(&mut thread_rng()); -/// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); -/// # let sk2 = SecretKey::new(&mut thread_rng()); -/// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); -/// -/// let key_agg_cache = MusigKeyAggCache::new(&secp, &[pub_key1, pub_key2]); -/// // The session id must be sampled at random. Read documentation for more details. -/// -/// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); -/// -/// // Provide the current time for mis-use resistance -/// let session_id1 = MusigSessionId::new(&mut thread_rng()); -/// let (mut sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_id1, pub_key1, msg, None) -/// .expect("non zero session id"); -/// -/// // Signer two does the same. Possibly on a different device -/// let session_id2 = MusigSessionId::new(&mut thread_rng()); -/// let (mut sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_id2, pub_key2, msg, None) -/// .expect("non zero session id"); -/// -/// let aggnonce = MusigAggNonce::new(&secp, &[pub_nonce1, pub_nonce2]); -/// -/// // Tweak with a secret adaptor -/// let adapt_sec = SecretKey::new(&mut thread_rng()); -/// let adapt_pub = PublicKey::from_secret_key(&secp, &adapt_sec); -/// let adapt_sec = Tweak::from_slice(adapt_sec.as_ref()).unwrap(); -/// -/// let session = MusigSession::with_adaptor( -/// &secp, -/// &key_agg_cache, -/// aggnonce, -/// msg, -/// adapt_pub, // adaptor here -/// ); -/// -/// let partial_sig1 = session.partial_sign( -/// &secp, -/// sec_nonce1, -/// &Keypair::from_secret_key(&secp, &sk1), -/// &key_agg_cache, -/// ).unwrap(); -/// -/// // Other party creates the other partial signature -/// let partial_sig2 = session.partial_sign( -/// &secp, -/// sec_nonce2, -/// &Keypair::from_secret_key(&secp, &sk2), -/// &key_agg_cache, -/// ).unwrap(); -/// -/// let nonce_parity = session.nonce_parity(); -/// let pre_sig = session.partial_sig_agg(&[partial_sig1, partial_sig2]); -/// // Get the final schnorr signature -/// let schnorr_sig = adapt(pre_sig, adapt_sec, nonce_parity); -/// -/// let extracted_sec = extract_adaptor( -/// schnorr_sig, -/// pre_sig, -/// nonce_parity, -/// ); -/// assert_eq!(extracted_sec, adapt_sec); -/// # } -/// ``` -pub fn extract_adaptor( - sig: schnorr::Signature, - pre_sig: schnorr::Signature, - nonce_parity: Parity, -) -> Tweak { - unsafe { - let mut secret = ZERO_TWEAK; - if ffi::secp256k1_musig_extract_adaptor( - ffi::secp256k1_context_no_precomp, - secret.as_mut_c_ptr(), - sig.as_c_ptr(), - pre_sig.as_c_ptr(), - nonce_parity.to_i32(), - ) == 0 - { - // Only fails when the arguments are invalid which is not possible in safe rust - unreachable!("Arguments must be valid and well-typed") - } else { - secret - } - } -} - -/// Musig Secret Nonce. -/// -/// This structure MUST NOT be copied or -/// read or written to it directly. A signer who is online throughout the whole -/// process and can keep this structure in memory can use the provided API -/// functions for a safe standard workflow. See -/// for -/// more details about the risks associated with serializing or deserializing -/// this structure. There are no serialization and parsing functions (yet). -/// -/// Note this deliberately does not implement `Copy` or `Clone`. After creation, the only -/// use of this nonce is [`MusigSession::partial_sign`] API that takes ownership of this -/// and drops it. This is to prevent accidental misuse of this nonce. -/// -/// A signer who is online throughout the whole process and can keep this -/// structure in memory can use the provided API functions for a safe standard -/// workflow. -/// -/// Signers that pre-computes and saves these nonces are not yet supported. Users -/// who want to serialize this must use unsafe rust to do so. -#[derive(Debug, Eq, PartialEq)] -pub struct MusigSecNonce(ffi::MusigSecNonce); - -impl CPtr for MusigSecNonce { - type Target = ffi::MusigSecNonce; - - fn as_c_ptr(&self) -> *const Self::Target { - self.as_ptr() - } - - fn as_mut_c_ptr(&mut self) -> *mut Self::Target { - self.as_mut_ptr() - } -} - -impl MusigSecNonce { - /// Get a const pointer to the inner MusigKeyAggCache - pub fn as_ptr(&self) -> *const ffi::MusigSecNonce { - &self.0 - } - - /// Get a mut pointer to the inner MusigKeyAggCache - pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigSecNonce { - &mut self.0 - } - - /// Function to return a copy of the internal array. See WARNING before using this function. - /// - /// # Warning: - /// This structure MUST NOT be copied or read or written to directly. A - /// signer who is online throughout the whole process and can keep this - /// structure in memory can use the provided API functions for a safe standard - /// workflow. See - /// https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/ for - /// more details about the risks associated with serializing or deserializing - /// this structure. - /// - /// We repeat, copying this data structure can result in nonce reuse which will - /// leak the secret signing key. - pub fn dangerous_into_bytes(self) -> [u8; MUSIG_SECNONCE_LEN] { - self.0.dangerous_into_bytes() - } - - /// Function to create a new MusigKeyAggCoef from a 32 byte array. See WARNING before using this function. - /// - /// Refer to [`MusigSecNonce::dangerous_serialize`] for more details. - pub fn dangerous_from_bytes(array: [u8; MUSIG_SECNONCE_LEN]) -> Self { - MusigSecNonce(ffi::MusigSecNonce::dangerous_from_bytes(array)) - } -} - -/// An individual MuSig public nonce. Not to be confused with [`MusigAggNonce`]. -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct MusigPubNonce(ffi::MusigPubNonce); - -impl CPtr for MusigPubNonce { - type Target = ffi::MusigPubNonce; - - fn as_c_ptr(&self) -> *const Self::Target { - self.as_ptr() - } - - fn as_mut_c_ptr(&mut self) -> *mut Self::Target { - self.as_mut_ptr() - } -} - -impl MusigPubNonce { - /// Serialize a MusigPubNonce - pub fn serialize(&self) -> [u8; ffi::MUSIG_PUBNONCE_SERIALIZED_LEN] { - let mut data = [0; ffi::MUSIG_PUBNONCE_SERIALIZED_LEN]; - unsafe { - if ffi::secp256k1_musig_pubnonce_serialize( - ffi::secp256k1_context_no_precomp, - data.as_mut_ptr(), - self.as_ptr(), - ) == 0 - { - // Only fails when the arguments are invalid which is not possible in safe rust - unreachable!("Arguments must be valid and well-typed") - } else { - data - } - } - } - - /// Deserialize a MusigPubNonce from a portable byte representation - /// - /// # Errors: - /// - /// - ArgLenMismatch: If the [`MusigPubNonce`] is not 132 bytes - /// - MalformedArg: If the [`MusigPubNonce`] is 132 bytes, but out of curve order - pub fn from_slice(data: &[u8]) -> Result { - let mut pubnonce = MusigPubNonce(ffi::MusigPubNonce::new()); - if data.len() != ffi::MUSIG_PUBNONCE_SERIALIZED_LEN { - return Err(ParseError::ArgLenMismatch { - expected: ffi::MUSIG_PUBNONCE_SERIALIZED_LEN, - got: data.len(), - }); - } - unsafe { - if ffi::secp256k1_musig_pubnonce_parse( - ffi::secp256k1_context_no_precomp, - pubnonce.as_mut_ptr(), - data.as_ptr(), - ) == 0 - { - Err(ParseError::MalformedArg) - } else { - Ok(pubnonce) - } - } - } - - /// Get a const pointer to the inner MusigPubNonce - pub fn as_ptr(&self) -> *const ffi::MusigPubNonce { - &self.0 - } - - /// Get a mut pointer to the inner MusigPubNonce - pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigPubNonce { - &mut self.0 - } -} - -/// Musig aggregated nonce computed by aggregating all individual public nonces -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct MusigAggNonce(ffi::MusigAggNonce); - -impl CPtr for MusigAggNonce { - type Target = ffi::MusigAggNonce; - - fn as_c_ptr(&self) -> *const Self::Target { - self.as_ptr() - } - - fn as_mut_c_ptr(&mut self) -> *mut Self::Target { - self.as_mut_ptr() - } -} - -impl MusigAggNonce { - /// Combine received public nonces into a single aggregated nonce - /// - /// This is useful to reduce the communication between signers, because instead - /// of everyone sending nonces to everyone else, there can be one party - /// receiving all nonces, combining the nonces with this function and then - /// sending only the combined nonce back to the signers. - /// - /// Example: - /// - /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1_zkp::rand::{thread_rng, RngCore}; - /// # use secp256k1_zkp::{MusigKeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, MusigSessionId, Message, MusigAggNonce}; - /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); - /// - /// # let key_agg_cache = MusigKeyAggCache::new(&secp, &[pub_key1, pub_key2]); - /// // The session id must be sampled at random. Read documentation for more details. - /// - /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); - /// - /// let session_id1 = MusigSessionId::new(&mut thread_rng()); - /// let (_sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_id1, pub_key1, msg, None) - /// .expect("non zero session id"); - /// - /// // Signer two does the same: Possibly on a different device - /// let session_id2 = MusigSessionId::new(&mut thread_rng()); - /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_id2, pub_key2, msg, None) - /// .expect("non zero session id"); - /// - /// let aggnonce = MusigAggNonce::new(&secp, &[pub_nonce1, pub_nonce2]); - /// # } - /// ``` - pub fn new(secp: &Secp256k1, nonces: &[MusigPubNonce]) -> Self { - let mut aggnonce = MusigAggNonce(ffi::MusigAggNonce::new()); - let nonce_ptrs = nonces.iter().map(|n| n.as_ptr()).collect::>(); - unsafe { - if ffi::secp256k1_musig_nonce_agg( - secp.ctx().as_ptr(), - aggnonce.as_mut_ptr(), - nonce_ptrs.as_ptr(), - nonce_ptrs.len(), - ) == 0 - { - // This can only crash if the individual nonces are invalid which is not possible is rust. - // Note that even if aggregate nonce is point at infinity, the musig spec sets it as `G` - unreachable!("Public key nonces are well-formed and valid in rust typesystem") - } else { - aggnonce - } - } - } - - /// Serialize a MusigAggNonce into a 66 bytes array. - pub fn serialize(&self) -> [u8; ffi::MUSIG_AGGNONCE_SERIALIZED_LEN] { - let mut data = [0; ffi::MUSIG_AGGNONCE_SERIALIZED_LEN]; - unsafe { - if ffi::secp256k1_musig_aggnonce_serialize( - ffi::secp256k1_context_no_precomp, - data.as_mut_ptr(), - self.as_ptr(), - ) == 0 - { - // Only fails when the arguments are invalid which is not possible in safe rust - unreachable!("Arguments must be valid and well-typed") - } else { - data - } - } - } - - /// Deserialize a MusigAggNonce from byte slice - /// - /// # Errors: - /// - /// - ArgLenMismatch: If the slice is not 66 bytes - /// - MalformedArg: If the byte slice is 66 bytes, but the [`MusigAggNonce`] is invalid - pub fn from_slice(data: &[u8]) -> Result { - if data.len() != ffi::MUSIG_AGGNONCE_SERIALIZED_LEN { - return Err(ParseError::ArgLenMismatch { - expected: ffi::MUSIG_AGGNONCE_SERIALIZED_LEN, - got: data.len(), - }); - } - let mut aggnonce = MusigAggNonce(ffi::MusigAggNonce::new()); - unsafe { - if ffi::secp256k1_musig_aggnonce_parse( - ffi::secp256k1_context_no_precomp, - aggnonce.as_mut_ptr(), - data.as_ptr(), - ) == 0 - { - Err(ParseError::MalformedArg) - } else { - Ok(aggnonce) - } - } - } - - /// Get a const pointer to the inner MusigAggNonce - pub fn as_ptr(&self) -> *const ffi::MusigAggNonce { - &self.0 - } - - /// Get a mut pointer to the inner MusigAggNonce - pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigAggNonce { - &mut self.0 - } -} - -/// A musig Singing session. -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct MusigSession(ffi::MusigSession); - -impl CPtr for MusigSession { - type Target = ffi::MusigSession; - - fn as_c_ptr(&self) -> *const Self::Target { - self.as_ptr() - } - - fn as_mut_c_ptr(&mut self) -> *mut Self::Target { - self.as_mut_ptr() - } -} - -impl MusigSession { - /// Creates a new musig signing session. - /// - /// Takes the public nonces of all signers and computes a session that is - /// required for signing and verification of partial signatures. - /// - /// See [`MusigSession::with_adaptor`] for adaptor signatures. - /// - /// # Returns: - /// - /// A [`MusigSession`] that can be later used for signing. - /// - /// # Arguments: - /// - /// * `secp` : [`Secp256k1`] context object initialized for signing - /// * `key_agg_cache`: [`MusigKeyAggCache`] to be used for this session - /// * `agg_nonce`: [`MusigAggNonce`], the aggregate nonce - /// * `msg`: [`Message`] that will be signed later on. - /// * `adaptor`: The adaptor of type [`PublicKey`] if this is signing session is a part of - /// an adaptor signature protocol. - /// - /// Example: - /// - /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1_zkp::rand::{thread_rng, RngCore}; - /// # use secp256k1_zkp::{MusigKeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, MusigSessionId, Message, MusigAggNonce, MusigSession}; - /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); - /// - /// # let key_agg_cache = MusigKeyAggCache::new(&secp, &[pub_key1, pub_key2]); - /// // The session id must be sampled at random. Read documentation for more details. - /// - /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); - /// - /// // Provide the current time for mis-use resistance - /// let session_id1 = MusigSessionId::new(&mut thread_rng()); - /// let extra_rand1 : Option<[u8; 32]> = None; - /// let (_sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_id1, pub_key1, msg, extra_rand1) - /// .expect("non zero session id"); - /// - /// // Signer two does the same. Possibly on a different device - /// let session_id2 = MusigSessionId::new(&mut thread_rng()); - /// let extra_rand2 : Option<[u8; 32]> = None; - /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_id2, pub_key2, msg, extra_rand2) - /// .expect("non zero session id"); - /// - /// let aggnonce = MusigAggNonce::new(&secp, &[pub_nonce1, pub_nonce2]); - /// - /// let session = MusigSession::new( - /// &secp, - /// &key_agg_cache, - /// aggnonce, - /// msg, - /// ); - /// # } - /// ``` - pub fn new( - secp: &Secp256k1, - key_agg_cache: &MusigKeyAggCache, - agg_nonce: MusigAggNonce, - msg: Message, - ) -> Self { - Self::with_optional_adapter(secp, key_agg_cache, agg_nonce, msg, None) - } - - /// Same as [`MusigSession::new`] but with an adapter. - /// - /// The output of partial signature aggregation will be a pre-signature which - /// is not a valid Schnorr signature. In order to create a valid signature, - /// the pre-signature and the secret adaptor must be provided to [`adapt`]. - pub fn with_adaptor( - secp: &Secp256k1, - key_agg_cache: &MusigKeyAggCache, - agg_nonce: MusigAggNonce, - msg: Message, - adaptor: PublicKey, - ) -> Self { - Self::with_optional_adapter(secp, key_agg_cache, agg_nonce, msg, Some(adaptor)) - } - - /// Internal function to create a new MusigSession with an optional adaptor. - fn with_optional_adapter( - secp: &Secp256k1, - key_agg_cache: &MusigKeyAggCache, - agg_nonce: MusigAggNonce, - msg: Message, - adaptor: Option, - ) -> Self { - let mut session = MusigSession(ffi::MusigSession::new()); - let adaptor_ptr = match adaptor { - Some(a) => a.as_c_ptr(), - None => core::ptr::null(), - }; - unsafe { - if ffi::secp256k1_musig_nonce_process( - secp.ctx().as_ptr(), - session.as_mut_ptr(), - agg_nonce.as_ptr(), - msg.as_c_ptr(), - key_agg_cache.as_ptr(), - adaptor_ptr, - ) == 0 - { - // Only fails on cryptographically unreachable codes or if the args are invalid. - // None of which can occur in safe rust. - unreachable!("Impossible to construct invalid arguments in safe rust. - Also reaches here if R1 + R2*b == point at infinity, but only occurs with 1/1^128 probability") - } else { - session - } - } - } - - /// Produces a partial signature for a given key pair and secret nonce. - /// - /// Remember that nonce reuse will immediately leak the secret key! - /// - /// # Returns: - /// - /// A [`MusigPartialSignature`] that can be later be aggregated into a [`schnorr::Signature`] - /// - /// # Arguments: - /// - /// * `secp` : [`Secp256k1`] context object initialized for signing - /// * `sec_nonce`: [`MusigSecNonce`] to be used for this session that has never - /// been used before. For mis-use resistance, this API takes a mutable reference - /// to `sec_nonce` and sets it to zero even if the partial signing fails. - /// * `key_pair`: The [`Keypair`] to sign the message - /// * `key_agg_cache`: [`MusigKeyAggCache`] containing the aggregate pubkey used in - /// the creation of this session - /// - /// # Errors: - /// - /// - If the provided [`MusigSecNonce`] has already been used for signing - /// - pub fn partial_sign( - &self, - secp: &Secp256k1, - mut secnonce: MusigSecNonce, - keypair: &Keypair, - key_agg_cache: &MusigKeyAggCache, - ) -> Result { - unsafe { - let mut partial_sig = MusigPartialSignature(ffi::MusigPartialSignature::new()); - if ffi::secp256k1_musig_partial_sign( - secp.ctx().as_ptr(), - partial_sig.as_mut_ptr(), - secnonce.as_mut_ptr(), - keypair.as_c_ptr(), - key_agg_cache.as_ptr(), - self.as_ptr(), - ) == 0 - { - // Since the arguments in rust are always session_valid, the only reason - // this will fail if the nonce was reused. - Err(MusigSignError::NonceReuse) - } else { - Ok(partial_sig) - } - } - } - - /// Checks that an individual partial signature verifies - /// - /// This function is essential when using protocols with adaptor signatures. - /// However, it is not essential for regular MuSig's, in the sense that if any - /// partial signatures does not verify, the full signature will also not verify, so the - /// problem will be caught. But this function allows determining the specific party - /// who produced an invalid signature, so that signing can be restarted without them. - /// - /// # Returns: - /// - /// true if the partial signature successfully verifies, otherwise returns false - /// - /// # Arguments: - /// - /// * `secp` : [`Secp256k1`] context object initialized for signing - /// * `key_agg_cache`: [`MusigKeyAggCache`] containing the aggregate pubkey used in - /// the creation of this session - /// * `partial_sig`: [`MusigPartialSignature`] sent by the signer associated with - /// the given `pub_nonce` and `pubkey` - /// * `pub_nonce`: The [`MusigPubNonce`] of the signer associated with the `partial_sig` - /// and `pub_key` - /// * `pub_key`: The [`XOnlyPublicKey`] of the signer associated with the given - /// `partial_sig` and `pub_nonce` - /// - /// Example: - /// - /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1_zkp::rand::{thread_rng, RngCore}; - /// # use secp256k1_zkp::{MusigKeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, MusigSessionId, Message, MusigAggNonce, MusigSession}; - /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); - /// - /// # let key_agg_cache = MusigKeyAggCache::new(&secp, &[pub_key1, pub_key2]); - /// // The session id must be sampled at random. Read documentation for more details. - /// - /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); - /// - /// // Provide the current time for mis-use resistance - /// let session_id1 = MusigSessionId::new(&mut thread_rng()); - /// let (mut sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_id1, pub_key1, msg, None) - /// .expect("non zero session id"); - /// - /// // Signer two does the same. Possibly on a different device - /// let session_id2 = MusigSessionId::new(&mut thread_rng()); - /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_id2, pub_key2, msg, None) - /// .expect("non zero session id"); - /// - /// let aggnonce = MusigAggNonce::new(&secp, &[pub_nonce1, pub_nonce2]); - /// - /// let session = MusigSession::new( - /// &secp, - /// &key_agg_cache, - /// aggnonce, - /// msg, - /// ); - /// - /// let keypair = Keypair::from_secret_key(&secp, &sk1); - /// let partial_sig1 = session.partial_sign( - /// &secp, - /// sec_nonce1, - /// &keypair, - /// &key_agg_cache, - /// ).unwrap(); - /// - /// assert!(session.partial_verify( - /// &secp, - /// &key_agg_cache, - /// partial_sig1, - /// pub_nonce1, - /// pub_key1, - /// )); - /// # } - /// ``` - pub fn partial_verify( - &self, - secp: &Secp256k1, - key_agg_cache: &MusigKeyAggCache, - partial_sig: MusigPartialSignature, - pub_nonce: MusigPubNonce, - pub_key: PublicKey, - ) -> bool { - let cx = secp.ctx().as_ptr(); - unsafe { - ffi::secp256k1_musig_partial_sig_verify( - cx, - partial_sig.as_ptr(), - pub_nonce.as_ptr(), - pub_key.as_c_ptr(), - key_agg_cache.as_ptr(), - self.as_ptr(), - ) == 1 - } - } - - /// Aggregate partial signatures for this session into a single [`schnorr::Signature`] - /// - /// # Returns: - /// - /// A single [`schnorr::Signature`]. Note that this does *NOT* mean that the signature verifies with respect to the - /// aggregate public key. - /// - /// # Arguments: - /// - /// * `partial_sigs`: Array of [`MusigPartialSignature`] to be aggregated - /// - /// ```rust - /// # # [cfg(any(test, feature = "rand-std"))] { - /// # use secp256k1_zkp::rand::{thread_rng, RngCore}; - /// # use secp256k1_zkp::{MusigKeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, MusigSessionId, Message, MusigAggNonce, MusigSession}; - /// # let secp = Secp256k1::new(); - /// # let sk1 = SecretKey::new(&mut thread_rng()); - /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); - /// # let sk2 = SecretKey::new(&mut thread_rng()); - /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); - /// - /// let key_agg_cache = MusigKeyAggCache::new(&secp, &[pub_key1, pub_key2]); - /// // The session id must be sampled at random. Read documentation for more details. - /// - /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); - /// - /// // Provide the current time for mis-use resistance - /// let session_id1 = MusigSessionId::new(&mut thread_rng()); - /// let (mut sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_id1, pub_key1, msg, None) - /// .expect("non zero session id"); - /// - /// // Signer two does the same. Possibly on a different device - /// let session_id2 = MusigSessionId::new(&mut thread_rng()); - /// let (mut sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_id2, pub_key2, msg, None) - /// .expect("non zero session id"); - /// - /// let aggnonce = MusigAggNonce::new(&secp, &[pub_nonce1, pub_nonce2]); - /// - /// let session = MusigSession::new( - /// &secp, - /// &key_agg_cache, - /// aggnonce, - /// msg, - /// ); - /// - /// let partial_sig1 = session.partial_sign( - /// &secp, - /// sec_nonce1, - /// &Keypair::from_secret_key(&secp, &sk1), - /// &key_agg_cache, - /// ).unwrap(); - /// - /// // Other party creates the other partial signature - /// let partial_sig2 = session.partial_sign( - /// &secp, - /// sec_nonce2, - /// &Keypair::from_secret_key(&secp, &sk2), - /// &key_agg_cache, - /// ).unwrap(); - /// - /// let schnorr_sig = session.partial_sig_agg(&[partial_sig1, partial_sig2]); - /// let agg_pk = key_agg_cache.agg_pk(); - /// - /// // Get the final schnorr signature - /// assert!(secp.verify_schnorr(&schnorr_sig, &msg, &agg_pk).is_ok()) - /// # } - /// ``` - pub fn partial_sig_agg(&self, partial_sigs: &[MusigPartialSignature]) -> schnorr::Signature { - let part_sigs = partial_sigs.iter().map(|s| s.as_ptr()).collect::>(); - let mut sig = [0u8; 64]; - unsafe { - if ffi::secp256k1_musig_partial_sig_agg( - ffi::secp256k1_context_no_precomp, - sig.as_mut_ptr(), - self.as_ptr(), - part_sigs.as_ptr(), - part_sigs.len(), - ) == 0 - { - // All arguments are well-typed partial signatures - unreachable!("Impossible to construct invalid(not well-typed) partial signatures") - } else { - // Resulting signature must be well-typed. Does not mean that will be succeed verification - schnorr::Signature::from_slice(&sig) - .expect("Resulting signature must be well-typed") - } - } - } - - /// Extracts the nonce_parity bit from a session - /// - /// This is used for adaptor signatures - pub fn nonce_parity(&self) -> Parity { - let mut parity = 0i32; - unsafe { - if ffi::secp256k1_musig_nonce_parity( - ffi::secp256k1_context_no_precomp, - &mut parity, - self.as_ptr(), - ) == 0 - { - unreachable!("Well-typed and valid arguments to the function") - } else { - Parity::from_i32(parity).expect("Parity guaranteed to be binary") - } - } - } - - /// Get a const pointer to the inner MusigSession - pub fn as_ptr(&self) -> *const ffi::MusigSession { - &self.0 - } - - /// Get a mut pointer to the inner MusigSession - pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigSession { - &mut self.0 - } -} - -/// Musig Signing errors -#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)] -pub enum MusigSignError { - /// Musig nonce re-used. - /// When creating a partial signature, nonce is cleared and set to all zeros. - /// This error is caused when we create a partial signature with zero nonce. - // Note: Because of the current borrowing rules around nonce, this should be impossible. - // Maybe, we can just unwrap this and not have error at all? - NonceReuse, -} - -#[cfg(feature = "std")] -impl std::error::Error for MusigSignError {} - -impl fmt::Display for MusigSignError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self { - MusigSignError::NonceReuse => write!(f, "Musig signing nonce re-used"), - } - } -} - -#[cfg(all(test, feature = "global-context"))] -mod tests { - use super::*; - use rand::{thread_rng, RngCore}; - - #[test] - fn test_key_agg_cache() { - let secp = Secp256k1::new(); - let mut sec_bytes = [0; 32]; - thread_rng().fill_bytes(&mut sec_bytes); - let sec_key = SecretKey::from_slice(&sec_bytes).unwrap(); - let pub_key = PublicKey::from_secret_key(&secp, &sec_key); - - let _key_agg_cache = MusigKeyAggCache::new(&secp, &[pub_key, pub_key]); - } - - #[test] - fn test_nonce_parsing() { - let secp = Secp256k1::new(); - let sec_bytes = [1; 32]; - let sec_key = SecretKey::from_slice(&sec_bytes).unwrap(); - let pub_key = PublicKey::from_secret_key(&secp, &sec_key); - - let key_agg_cache = MusigKeyAggCache::new(&secp, &[pub_key, pub_key]); - let msg = Message::from_digest_slice(&[3; 32]).unwrap(); - let session_id = MusigSessionId::assume_unique_per_nonce_gen([1; 32]); - let (_secnonce, pubnonce) = key_agg_cache - .nonce_gen(&secp, session_id, pub_key, msg, None) - .expect("non zero session id"); - let pubnonce_ser = pubnonce.serialize(); - let parsed_pubnonce = MusigPubNonce::from_slice(&pubnonce_ser).unwrap(); - - assert_eq!(parsed_pubnonce, pubnonce); - } -} diff --git a/ark-rust-secp256k1-zkp/src/zkp/pedersen.rs b/ark-rust-secp256k1-zkp/src/zkp/pedersen.rs deleted file mode 100644 index 4d38d32d..00000000 --- a/ark-rust-secp256k1-zkp/src/zkp/pedersen.rs +++ /dev/null @@ -1,370 +0,0 @@ -use ffi::CPtr; - -use crate::ffi; -use crate::{from_hex, Error, Generator, Secp256k1, Signing, Tweak, ZERO_TWEAK}; -use core::{fmt, slice, str}; - -/// Represents a commitment to a single u64 value. -#[derive(Debug, PartialEq, Clone, Copy, Eq, Hash, PartialOrd, Ord)] -pub struct PedersenCommitment(ffi::PedersenCommitment); - -impl PedersenCommitment { - /// Serialize a pedersen commitment. - /// - /// The format of this serialization is stable and platform-independent. - pub fn serialize(&self) -> [u8; 33] { - let mut bytes = [0u8; 33]; - - let ret = unsafe { - ffi::secp256k1_pedersen_commitment_serialize( - ffi::secp256k1_context_no_precomp, - bytes.as_mut_ptr(), - &self.0, - ) - }; - assert_eq!(ret, 1, "failed to serialize pedersen commitment"); - - bytes - } - - /// Parse a pedersen commitment from a byte slice. - pub fn from_slice(bytes: &[u8]) -> Result { - let mut commitment = ffi::PedersenCommitment::default(); - - let ret = unsafe { - ffi::secp256k1_pedersen_commitment_parse( - ffi::secp256k1_context_no_precomp, - &mut commitment, - bytes.as_ptr(), - ) - }; - - if ret != 1 { - return Err(Error::InvalidPedersenCommitment); - } - - Ok(PedersenCommitment(commitment)) - } - - /// Create a new [`PedersenCommitment`] that commits to the given value with - /// a certain blinding factor and generator. - /// Use the [PedersenCommitment::new_unblinded] for creating a commitment - /// using zero blinding factor. - pub fn new( - secp: &Secp256k1, - value: u64, - blinding_factor: Tweak, - generator: Generator, - ) -> Self { - let mut commitment = ffi::PedersenCommitment::default(); - - let ret = unsafe { - ffi::secp256k1_pedersen_commit( - secp.ctx().as_ptr(), - &mut commitment, - blinding_factor.as_c_ptr(), - value, - generator.as_inner(), - ) - }; - assert_eq!( - ret, 1, - "failed to create pedersen commitment, likely a bad blinding factor" - ); - - PedersenCommitment(commitment) - } - - /// Create a new [`PedersenCommitment`] that commits to the given value - /// with a zero blinding factor and the [`Generator`]. - pub fn new_unblinded( - secp: &Secp256k1, - value: u64, - generator: Generator, - ) -> Self { - PedersenCommitment::new(secp, value, ZERO_TWEAK, generator) - } - - pub(crate) fn as_inner(&self) -> &ffi::PedersenCommitment { - &self.0 - } -} - -/// Represents all secret data involved in making a [`PedersenCommitment`] where one of the generators is blinded. -/// -/// A Pedersen commitment of the form `P = vT' + r'G` can be expressed as `vT + (vr + r')G` if `T' = T + rG` with: -/// - `v` = `value` -/// - `T` being a public key generated from a [`Tag`] -/// - `r` = `generator_blinding_factor` -/// - `r'` = `value_blinding_factor` -#[derive(Debug)] -pub struct CommitmentSecrets { - /// The value that is committed to. - pub value: u64, - /// The blinding factor used when committing to the value. - pub value_blinding_factor: Tweak, - /// The blinding factor used when producing the [`Generator`] that is necessary to commit to the value. - pub generator_blinding_factor: Tweak, -} - -impl CommitmentSecrets { - /// Constructor. - pub fn new(value: u64, value_blinding_factor: Tweak, generator_blinding_factor: Tweak) -> Self { - CommitmentSecrets { - value, - value_blinding_factor, - generator_blinding_factor, - } - } -} - -/// Compute a blinding factor such that the sum of all blinding factors in both sets is equal. -pub fn compute_adaptive_blinding_factor( - secp: &Secp256k1, - value: u64, - generator_blinding_factor: Tweak, - set_a: &[CommitmentSecrets], - set_b: &[CommitmentSecrets], -) -> Tweak { - let value_blinding_factor_placeholder = ZERO_TWEAK; // this placeholder will be filled with the generated blinding factor - - let (mut values, mut secrets) = set_a - .iter() - .chain(set_b.iter()) - .map(|c| { - ( - c.value, - (c.value_blinding_factor, c.generator_blinding_factor), - ) - }) - .unzip::<_, _, Vec<_>, Vec<_>>(); - values.push(value); - secrets.push((value_blinding_factor_placeholder, generator_blinding_factor)); - - let (vbf, gbf) = secrets - .iter_mut() - .map(|(s_v, s_g)| (s_v.as_mut_c_ptr(), s_g.as_c_ptr())) - .unzip::<_, _, Vec<_>, Vec<_>>(); - - let ret = unsafe { - ffi::secp256k1_pedersen_blind_generator_blind_sum( - secp.ctx().as_ptr(), - values.as_ptr(), - gbf.as_ptr(), - vbf.as_ptr(), - set_a.len() + set_b.len() + 1, - set_a.len(), - ) - }; - assert_eq!(1, ret, "failed to compute blinding factor"); - - let last = vbf.last().expect("this vector is never empty"); - let slice = unsafe { slice::from_raw_parts(*last, 32) }; - Tweak::from_slice(slice).expect("data is always 32 bytes") -} - -/// Verifies that the sum of the committed values within the commitments of both sets is equal. -#[must_use] -pub fn verify_commitments_sum_to_equal( - secp: &Secp256k1, - a: &[PedersenCommitment], - b: &[PedersenCommitment], -) -> bool { - let a = a.iter().map(|c| &c.0).collect::>(); - let b = b.iter().map(|c| &c.0).collect::>(); - - let ret = unsafe { - ffi::secp256k1_pedersen_verify_tally( - secp.ctx().as_ptr(), - a.as_ptr(), - a.len(), - b.as_ptr(), - b.len(), - ) - }; - - ret == 1 -} - -impl fmt::LowerHex for PedersenCommitment { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let ser = self.serialize(); - for ch in &ser[..] { - write!(f, "{:02x}", *ch)?; - } - Ok(()) - } -} - -impl fmt::Display for PedersenCommitment { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::LowerHex::fmt(self, f) - } -} - -impl str::FromStr for PedersenCommitment { - type Err = Error; - fn from_str(s: &str) -> Result { - let mut res = [0; 33]; - match from_hex(s, &mut res) { - Ok(33) => Self::from_slice(&res[0..33]), - _ => Err(Error::InvalidPedersenCommitment), - } - } -} - -#[cfg(feature = "serde")] -impl ::serde::Serialize for PedersenCommitment { - fn serialize(&self, s: S) -> Result { - if s.is_human_readable() { - s.collect_str(self) - } else { - s.serialize_bytes(&self.serialize()) - } - } -} - -#[cfg(feature = "serde")] -impl<'de> ::serde::Deserialize<'de> for PedersenCommitment { - fn deserialize>(d: D) -> Result { - use crate::serde_util; - - if d.is_human_readable() { - d.deserialize_str(serde_util::FromStrVisitor::new("an ASCII hex string")) - } else { - d.deserialize_bytes(serde_util::BytesVisitor::new( - "a bytestring", - PedersenCommitment::from_slice, - )) - } - } -} - -#[cfg(all(test, feature = "global-context"))] -mod tests { - use std::str::FromStr; - - use super::*; - use crate::{Tag, SECP256K1}; - use rand::thread_rng; - - #[cfg(target_arch = "wasm32")] - use wasm_bindgen_test::wasm_bindgen_test as test; - - impl CommitmentSecrets { - pub fn random(value: u64) -> Self { - Self { - value, - value_blinding_factor: Tweak::new(&mut thread_rng()), - generator_blinding_factor: Tweak::new(&mut thread_rng()), - } - } - - pub fn commit(&self, tag: Tag) -> PedersenCommitment { - let generator = Generator::new_blinded(SECP256K1, tag, self.generator_blinding_factor); - - PedersenCommitment::new(SECP256K1, self.value, self.value_blinding_factor, generator) - } - } - - #[test] - fn test_unblinded_pedersen_commitments() { - let tag = Tag::random(); - let unblinded_gen = Generator::new_unblinded(SECP256K1, tag); - let one_comm = PedersenCommitment::new_unblinded(SECP256K1, 1, unblinded_gen); // 1*G - let two_comm = PedersenCommitment::new_unblinded(SECP256K1, 2, unblinded_gen); // 2*G - let three_comm = PedersenCommitment::new_unblinded(SECP256K1, 3, unblinded_gen); // 3*G - let six_comm = PedersenCommitment::new_unblinded(SECP256K1, 6, unblinded_gen); // 6*G - - let commitment_sums_are_equal = verify_commitments_sum_to_equal( - SECP256K1, - &[one_comm, two_comm, three_comm], - &[six_comm], - ); - - assert!(commitment_sums_are_equal); - } - - #[test] - fn test_serialize_and_parse_pedersen_commitment() { - let commitment = CommitmentSecrets::random(1000).commit(Tag::random()); - - let bytes = commitment.serialize(); - let got = PedersenCommitment::from_slice(&bytes).unwrap(); - - assert_eq!(got, commitment); - } - - #[test] - fn test_equal_sum_of_commitments() { - let tag_1 = Tag::random(); - let tag_2 = Tag::random(); - - let secrets_1 = CommitmentSecrets::random(1000); - let commitment_1 = secrets_1.commit(tag_1); - let secrets_2 = CommitmentSecrets::random(1000); - let commitment_2 = secrets_2.commit(tag_2); - - let secrets_3 = CommitmentSecrets::random(1000); - let commitment_3 = secrets_3.commit(tag_1); - - let tbf_4 = Tweak::new(&mut thread_rng()); - let blinded_tag_4 = Generator::new_blinded(SECP256K1, tag_2, tbf_4); - let vbf_4 = compute_adaptive_blinding_factor( - SECP256K1, - 1000, - tbf_4, - &[secrets_1, secrets_2], - &[secrets_3], - ); - let commitment_4 = PedersenCommitment::new(SECP256K1, 1000, vbf_4, blinded_tag_4); - - let commitment_sums_are_equal = verify_commitments_sum_to_equal( - SECP256K1, - &[commitment_1, commitment_2], - &[commitment_3, commitment_4], - ); - - assert!(commitment_sums_are_equal); - } - - #[test] - fn test_pedersen_from_str() { - let commitment = CommitmentSecrets::random(1000).commit(Tag::random()); - - let string = commitment.to_string(); - let from_str = PedersenCommitment::from_str(&string); - - assert_eq!(Ok(commitment), from_str) - } - - #[cfg(feature = "serde")] - #[test] - fn test_pedersen_de_serialization() { - use serde_test::Configure; - use serde_test::{assert_tokens, Token}; - - let commitment = PedersenCommitment::from_slice(&[ - 9, 7, 166, 63, 171, 227, 228, 157, 87, 19, 233, 218, 252, 171, 254, 202, 228, 138, 19, - 124, 26, 29, 131, 42, 33, 212, 151, 151, 89, 0, 135, 201, 254, - ]) - .unwrap(); - - assert_tokens( - &commitment.readable(), - &[Token::Str( - "0907a63fabe3e49d5713e9dafcabfecae48a137c1a1d832a21d49797590087c9fe", - )], - ); - - assert_tokens( - &commitment.compact(), - &[Token::Bytes(&[ - 9, 7, 166, 63, 171, 227, 228, 157, 87, 19, 233, 218, 252, 171, 254, 202, 228, 138, - 19, 124, 26, 29, 131, 42, 33, 212, 151, 151, 89, 0, 135, 201, 254, - ])], - ); - } - - // TODO: Test prefix of serialization -} diff --git a/ark-rust-secp256k1-zkp/src/zkp/rangeproof.rs b/ark-rust-secp256k1-zkp/src/zkp/rangeproof.rs deleted file mode 100644 index 499a50ab..00000000 --- a/ark-rust-secp256k1-zkp/src/zkp/rangeproof.rs +++ /dev/null @@ -1,371 +0,0 @@ -use ffi::CPtr; - -use crate::ffi::RANGEPROOF_MAX_LENGTH; -use crate::from_hex; -use crate::Error; -use crate::Generator; -use crate::PedersenCommitment; -use crate::Verification; -use crate::{ffi, Secp256k1, SecretKey, Signing, Tweak}; -use std::ops::Range; -use std::str; - -/// Represents a range proof. -/// -/// TODO: Store rangeproof info -#[derive(Debug, PartialEq, Clone, Eq, Hash, PartialOrd, Ord)] -pub struct RangeProof { - inner: ffi::RangeProof, -} - -impl RangeProof { - /// Serialize to bytes. - pub fn serialize(&self) -> Vec { - self.inner.to_bytes() - } - - /// Parse from byte slice. - /// - /// TODO: Rename to parse (and other similar functions) - pub fn from_slice(bytes: &[u8]) -> Result { - let mut exp = 0; - let mut mantissa = 0; - let mut min_value = 0; - let mut max_value = 0; - - let ret = unsafe { - ffi::secp256k1_rangeproof_info( - ffi::secp256k1_context_no_precomp, - &mut exp, - &mut mantissa, - &mut min_value, - &mut max_value, - bytes.as_ptr(), - bytes.len(), - ) - }; - - if ret == 0 { - return Err(Error::InvalidRangeProof); - } - - Ok(RangeProof { - inner: ffi::RangeProof::new(bytes), - }) - } - - /// Get length. - pub fn len(&self) -> usize { - self.inner.len() - } - - /// Check if it's empty. - pub fn is_empty(&self) -> bool { - self.inner.is_empty() - } - - /// Prove that `commitment` hides a value within a range, with the lower bound set to `min_value`. - #[allow(clippy::too_many_arguments)] - pub fn new( - secp: &Secp256k1, - min_value: u64, - commitment: PedersenCommitment, - value: u64, - commitment_blinding: Tweak, - message: &[u8], - additional_commitment: &[u8], - sk: SecretKey, - exp: i32, - min_bits: u8, - additional_generator: Generator, - ) -> Result { - let mut proof = [0u8; RANGEPROOF_MAX_LENGTH]; - let mut proof_length = RANGEPROOF_MAX_LENGTH; - - let ret = unsafe { - ffi::secp256k1_rangeproof_sign( - secp.ctx().as_ptr(), - proof.as_mut_ptr(), - &mut proof_length, - min_value, - commitment.as_inner(), - commitment_blinding.as_c_ptr(), - sk.as_c_ptr(), - exp, - min_bits as i32, - value, - message.as_ptr(), - message.len(), - additional_commitment.as_ptr(), - additional_commitment.len(), - additional_generator.as_inner(), - ) - }; - - if ret == 0 { - return Err(Error::CannotMakeRangeProof); - } - - Ok(RangeProof { - inner: ffi::RangeProof::new(&proof[..proof_length]), - }) - } - - /// Verify that the committed value is within a range. - /// - /// If the verification is successful, return the actual range of possible values. - pub fn verify( - &self, - secp: &Secp256k1, - commitment: PedersenCommitment, - additional_commitment: &[u8], - additional_generator: Generator, - ) -> Result, Error> { - let mut min_value = 0u64; - let mut max_value = 0u64; - - let ret = unsafe { - ffi::secp256k1_rangeproof_verify( - secp.ctx().as_ptr(), - &mut min_value, - &mut max_value, - commitment.as_inner(), - self.inner.as_ptr(), - self.inner.len(), - additional_commitment.as_ptr(), - additional_commitment.len(), - additional_generator.as_inner(), - ) - }; - - if ret == 0 { - return Err(Error::InvalidRangeProof); - } - - Ok(Range { - start: min_value, - end: max_value + 1, - }) - } - - /// Verify a range proof proof and rewind the proof to recover information sent by its author. - pub fn rewind( - &self, - secp: &Secp256k1, - commitment: PedersenCommitment, - sk: SecretKey, - additional_commitment: &[u8], - additional_generator: Generator, - ) -> Result<(Opening, Range), Error> { - let mut min_value = 0u64; - let mut max_value = 0u64; - - let mut blinding_factor = [0u8; 32]; - let mut value = 0u64; - let mut message = [0u8; 4096]; - let mut message_length = 4096usize; - - let ret = unsafe { - ffi::secp256k1_rangeproof_rewind( - secp.ctx().as_ptr(), - blinding_factor.as_mut_ptr(), - &mut value, - message.as_mut_ptr(), - &mut message_length, - sk.as_c_ptr(), - &mut min_value, - &mut max_value, - commitment.as_inner(), - self.inner.as_ptr(), - self.inner.len(), - additional_commitment.as_ptr(), - additional_commitment.len(), - additional_generator.as_inner(), - ) - }; - - if ret == 0 { - return Err(Error::InvalidRangeProof); - } - - let opening = Opening { - value, - blinding_factor: Tweak::from_slice(&blinding_factor)?, - message: message[..message_length].into(), - }; - - let range = Range { - start: min_value, - end: max_value + 1, - }; - - Ok((opening, range)) - } -} - -#[cfg(feature = "hashes")] -impl ::core::fmt::Display for RangeProof { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - use internals::hex::display::DisplayHex; - - write!(f, "{:x}", &self.serialize().as_slice().as_hex()) - } -} - -impl str::FromStr for RangeProof { - type Err = Error; - fn from_str(s: &str) -> Result { - let mut res = vec![0u8; s.len() / 2]; - match from_hex(s, &mut res) { - Ok(_) => RangeProof::from_slice(&res), - _ => Err(Error::InvalidRangeProof), - } - } -} - -#[cfg(all(feature = "serde", feature = "hashes"))] -impl ::serde::Serialize for RangeProof { - fn serialize(&self, s: S) -> Result { - if s.is_human_readable() { - s.collect_str(&self) - } else { - s.serialize_bytes(&self.serialize()) - } - } -} - -#[cfg(all(feature = "serde", feature = "hashes"))] -impl<'de> ::serde::Deserialize<'de> for RangeProof { - fn deserialize>(d: D) -> Result { - use crate::serde_util; - - if d.is_human_readable() { - d.deserialize_str(serde_util::FromStrVisitor::new("an ASCII hex string")) - } else { - d.deserialize_bytes(serde_util::BytesVisitor::new( - "a bytestring", - RangeProof::from_slice, - )) - } - } -} - -/// The result of rewinding a range proof. -/// -/// Rewinding a range proof reveals ("opens") the stored information and allows us to access information the prover embedded in the proof. -pub struct Opening { - /// The value that the prover originally committed to in the Pedersen commitment. - pub value: u64, - /// The blinding factor that was used to create the Pedersen commitment of above value. - pub blinding_factor: Tweak, - /// The message that was embedded by the prover. - pub message: Box<[u8]>, -} - -#[cfg(all(test, feature = "global-context"))] // use global context for convenience -mod tests { - use super::*; - use crate::{CommitmentSecrets, Tag, SECP256K1}; - use rand::thread_rng; - - #[cfg(target_arch = "wasm32")] - use wasm_bindgen_test::wasm_bindgen_test as test; - - #[test] - fn create_and_verify_range_proof() { - let value = 1_000; - let commitment_secrets = CommitmentSecrets::random(value); - let tag = Tag::random(); - let commitment = commitment_secrets.commit(tag); - - let message = b"foo"; - let additional_commitment = b"bar"; - - let sk = SecretKey::new(&mut thread_rng()); - let additional_generator = - Generator::new_blinded(SECP256K1, tag, commitment_secrets.generator_blinding_factor); - - let proof = RangeProof::new( - SECP256K1, - 1, - commitment, - value, - commitment_secrets.value_blinding_factor, - message, - additional_commitment, - sk, - 0, - 52, - additional_generator, - ) - .unwrap(); - - proof - .verify( - SECP256K1, - commitment, - additional_commitment, - additional_generator, - ) - .unwrap(); - - #[cfg(feature = "hashes")] - { - use std::str::FromStr; - use std::string::ToString; - let proof_str = proof.to_string(); - assert_eq!(proof, RangeProof::from_str(&proof_str).unwrap()); - } - } - - #[test] - fn rewind_range_proof() { - let value = 1_000; - let commitment_secrets = CommitmentSecrets::random(value); - let tag = Tag::random(); - let commitment = commitment_secrets.commit(tag); - - let message = b"foo"; - let additional_commitment = b"bar"; - - let sk = SecretKey::new(&mut thread_rng()); - let additional_generator = - Generator::new_blinded(SECP256K1, tag, commitment_secrets.generator_blinding_factor); - - let proof = RangeProof::new( - SECP256K1, - 1, - commitment, - value, - commitment_secrets.value_blinding_factor, - message, - additional_commitment, - sk, - 0, - 52, - additional_generator, - ) - .unwrap(); - - let (opening, _range) = proof - .rewind( - SECP256K1, - commitment, - sk, - additional_commitment, - additional_generator, - ) - .unwrap(); - - assert_eq!(opening.value, commitment_secrets.value); - assert_eq!( - opening.blinding_factor, - commitment_secrets.value_blinding_factor - ); - - assert!(opening.message.starts_with(message)); - assert!(opening - .message - .ends_with(&vec![0; opening.message.len() - message.len()])); - } -} diff --git a/ark-rust-secp256k1-zkp/src/zkp/surjection_proof.rs b/ark-rust-secp256k1-zkp/src/zkp/surjection_proof.rs deleted file mode 100644 index a2deddd5..00000000 --- a/ark-rust-secp256k1-zkp/src/zkp/surjection_proof.rs +++ /dev/null @@ -1,326 +0,0 @@ -use crate::ffi; -use crate::from_hex; -use crate::Verification; -use crate::{Error, Generator, Secp256k1}; -use core::mem::size_of; -use std::str; - -/// Represents a surjection proof. -#[derive(Debug, PartialEq, Clone, Eq, Hash, PartialOrd, Ord)] -pub struct SurjectionProof { - inner: ffi::SurjectionProof, -} - -#[cfg(feature = "actual-rand")] -mod with_rand { - use super::*; - use crate::{Signing, Tag, Tweak}; - use ffi::CPtr; - use rand::Rng; - - impl SurjectionProof { - /// Prove that a given tag - when blinded - is contained within another set of blinded tags. - /// - /// Mathematically, we are proving that there exists a surjective mapping between the domain and codomain of tags. - /// Blinding a tag produces a [`Generator`]. As such, to create this proof we need to provide the `[Generator]`s and the respective blinding factors that were used to create them. - pub fn new( - secp: &Secp256k1, - rng: &mut R, - codomain_tag: Tag, - codomain_blinding_factor: Tweak, - domain: &[(Generator, Tag, Tweak)], - ) -> Result { - let mut proof = ffi::SurjectionProof::new(); - - let mut seed = [0u8; 32]; - rng.fill_bytes(&mut seed); - - let mut domain_index = 0; - let max_iteration = 100; - - let mut domain_blinded_tags = Vec::with_capacity(domain.len()); - let mut domain_tags = Vec::with_capacity(domain.len()); - let mut domain_blinding_factors = Vec::with_capacity(domain.len()); - - for (blinded_tag, tag, bf) in domain { - domain_blinded_tags.push(*blinded_tag.as_inner()); - domain_tags.push(tag.into_inner()); - domain_blinding_factors.push(*bf); - } - - let ret = unsafe { - ffi::secp256k1_surjectionproof_initialize( - secp.ctx().as_ptr(), - &mut proof, - &mut domain_index, - domain_tags.as_ptr(), - domain.len(), - domain.len().min(3), - codomain_tag.as_inner(), - max_iteration, - seed.as_ptr(), - ) - }; - - if ret == 0 { - return Err(Error::CannotProveSurjection); - } - - let codomain_blinded_tag = - Generator::new_blinded(secp, codomain_tag, codomain_blinding_factor); - - let ret = unsafe { - ffi::secp256k1_surjectionproof_generate( - secp.ctx().as_ptr(), - &mut proof, - domain_blinded_tags.as_ptr(), - domain.len(), - codomain_blinded_tag.as_inner(), - domain_index, - domain - .get(domain_index) - .ok_or(Error::CannotProveSurjection)? - .2 - .as_c_ptr(), // TODO: Return dedicated error here? - codomain_blinding_factor.as_c_ptr(), - ) - }; - - if ret == 0 { - return Err(Error::CannotProveSurjection); - } - - Ok(SurjectionProof { inner: proof }) - } - } -} - -impl SurjectionProof { - /// Creates a surjection proof from a slice of bytes. - pub fn from_slice(bytes: &[u8]) -> Result { - let mut proof = ffi::SurjectionProof::new(); - - let ret = unsafe { - ffi::secp256k1_surjectionproof_parse( - ffi::secp256k1_context_no_precomp, - &mut proof, - bytes.as_ptr(), - bytes.len(), - ) - }; - - if ret != 1 { - return Err(Error::InvalidSurjectionProof); - } - - Ok(SurjectionProof { inner: proof }) - } - - /// Serializes a surjection proof. - /// - /// The format of this serialization is stable and platform-independent. - pub fn serialize(&self) -> Vec { - let mut size = unsafe { - ffi::secp256k1_surjectionproof_serialized_size( - ffi::secp256k1_context_no_precomp, - &self.inner, - ) - }; - - let mut bytes = vec![0u8; size]; - - let ret = unsafe { - ffi::secp256k1_surjectionproof_serialize( - ffi::secp256k1_context_no_precomp, - bytes.as_mut_ptr(), - &mut size, - &self.inner, - ) - }; - assert_eq!(ret, 1, "failed to serialize surjection proof"); // This is safe as long as we correctly computed the size of the proof upfront using `secp256k1_surjectionproof_serialized_size`. - - bytes - } - - /// Find the length of surjection proof when serialized - #[allow(clippy::len_without_is_empty)] - pub fn len(&self) -> usize { - unsafe { - ffi::secp256k1_surjectionproof_serialized_size( - ffi::secp256k1_context_no_precomp, - &self.inner, - ) - } - } - - /// Whether the proof has zero length - /// - /// Always returns `false` since a surjection proof must contain at least - /// one 32-byte hash. - pub fn is_empty(&self) -> bool { - false - } - - /// Verify a surjection proof. - #[must_use] - pub fn verify( - &self, - secp: &Secp256k1, - codomain: Generator, - domain: &[Generator], - ) -> bool { - // Safety: Generator and ffi::PublicKey are the same size and layout. - let domain_blinded_tags = unsafe { - debug_assert_eq!(size_of::(), size_of::()); - - &*(domain as *const [Generator] as *const [ffi::PublicKey]) - }; - - let ret = unsafe { - ffi::secp256k1_surjectionproof_verify( - secp.ctx().as_ptr(), - &self.inner, - domain_blinded_tags.as_ptr(), - domain_blinded_tags.len(), - codomain.as_inner(), - ) - }; - - ret == 1 - } -} - -#[cfg(feature = "hashes")] -impl ::core::fmt::Display for SurjectionProof { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - use internals::hex::display::DisplayHex; - - write!(f, "{:x}", &self.serialize().as_slice().as_hex()) - } -} - -impl str::FromStr for SurjectionProof { - type Err = Error; - fn from_str(s: &str) -> Result { - let mut res = vec![0u8; s.len() / 2]; - match from_hex(s, &mut res) { - Ok(_) => SurjectionProof::from_slice(&res), - _ => Err(Error::InvalidSurjectionProof), - } - } -} - -#[cfg(all(feature = "serde", feature = "hashes"))] -impl ::serde::Serialize for SurjectionProof { - fn serialize(&self, s: S) -> Result { - if s.is_human_readable() { - s.collect_str(&self) - } else { - s.serialize_bytes(&self.serialize()) - } - } -} - -#[cfg(all(feature = "serde", feature = "hashes"))] -impl<'de> ::serde::Deserialize<'de> for SurjectionProof { - fn deserialize>(d: D) -> Result { - use crate::serde_util; - - if d.is_human_readable() { - d.deserialize_str(serde_util::FromStrVisitor::new("an ASCII hex string")) - } else { - d.deserialize_bytes(serde_util::BytesVisitor::new( - "a bytestring", - SurjectionProof::from_slice, - )) - } - } -} - -#[cfg(all(test, feature = "global-context"))] // use global context for convenience -mod tests { - use super::*; - use crate::{Tag, Tweak, SECP256K1}; - use rand::thread_rng; - - #[cfg(target_arch = "wasm32")] - use wasm_bindgen_test::wasm_bindgen_test as test; - - #[test] - fn test_create_and_verify_surjection_proof() { - // create three random tags - let (domain_tag_1, domain_blinded_tag_1, domain_bf_1) = random_blinded_tag(); - let (domain_tag_2, domain_blinded_tag_2, domain_bf_2) = random_blinded_tag(); - let (domain_tag_3, domain_blinded_tag_3, domain_bf_3) = random_blinded_tag(); - - // pick the first one as the codomain - let codomain_tag_1 = domain_tag_1; - let (codomain_blinded_tag_1, codomain_bf_1) = blind_tag(codomain_tag_1); - - let proof = SurjectionProof::new( - SECP256K1, - &mut thread_rng(), - codomain_tag_1, - codomain_bf_1, - &[ - (domain_blinded_tag_1, domain_tag_1, domain_bf_1), - (domain_blinded_tag_2, domain_tag_2, domain_bf_2), - (domain_blinded_tag_3, domain_tag_3, domain_bf_3), - ], - ) - .unwrap(); - - assert!(proof.verify( - SECP256K1, - codomain_blinded_tag_1, - &[ - domain_blinded_tag_1, - domain_blinded_tag_2, - domain_blinded_tag_3 - ], - )) - } - - #[test] - fn test_serialize_and_parse_surjection_proof() { - let (domain_tag_1, domain_blinded_tag_1, domain_bf_1) = random_blinded_tag(); - let codomain_tag_1 = domain_tag_1; - let (_, codomain_bf_1) = blind_tag(codomain_tag_1); - - let proof = SurjectionProof::new( - SECP256K1, - &mut thread_rng(), - codomain_tag_1, - codomain_bf_1, - &[(domain_blinded_tag_1, domain_tag_1, domain_bf_1)], - ) - .unwrap(); - let bytes = proof.serialize(); - let parsed = SurjectionProof::from_slice(&bytes).unwrap(); - - assert_eq!(parsed, proof); - - #[cfg(feature = "hashes")] - { - use std::str::FromStr; - use std::string::ToString; - let proof_str = proof.to_string(); - assert_eq!(proof, SurjectionProof::from_str(&proof_str).unwrap()); - } - } - - fn random_blinded_tag() -> (Tag, Generator, Tweak) { - let tag = Tag::random(); - - let (blinded_tag, bf) = blind_tag(tag); - - (tag, blinded_tag, bf) - } - - fn blind_tag(tag: Tag) -> (Generator, Tweak) { - let bf = Tweak::new(&mut thread_rng()); - let blinded_tag = Generator::new_blinded(SECP256K1, tag, bf); - - (blinded_tag, bf) - } -} diff --git a/ark-rust-secp256k1-zkp/src/zkp/tag.rs b/ark-rust-secp256k1-zkp/src/zkp/tag.rs deleted file mode 100644 index eafbff87..00000000 --- a/ark-rust-secp256k1-zkp/src/zkp/tag.rs +++ /dev/null @@ -1,65 +0,0 @@ -use crate::ffi; -use core::fmt; - -/// Represents a tag. -/// -/// Tags are 32-byte data structures used in surjection proofs. Usually, tags are created from hashes. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)] -pub struct Tag(ffi::Tag); - -impl Tag { - pub(crate) fn into_inner(self) -> ffi::Tag { - self.0 - } - - #[cfg(all(feature = "actual-rand", feature = "std"))] - pub(crate) fn as_inner(&self) -> &ffi::Tag { - &self.0 - } -} - -impl AsRef<[u8]> for Tag { - fn as_ref(&self) -> &[u8] { - self.0.as_ref() - } -} - -impl fmt::Display for Tag { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{:x}", self) - } -} - -impl fmt::LowerHex for Tag { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - for i in self.0.as_ref() { - write!(f, "{:02x}", i)?; - } - Ok(()) - } -} - -#[cfg(all(test, feature = "rand-std"))] -impl Tag { - pub fn random() -> Self { - use rand::thread_rng; - use rand::RngCore; - - let mut bytes = [0u8; 32]; - thread_rng().fill_bytes(&mut bytes); - - Self::from(bytes) - } -} - -impl From<[u8; 32]> for Tag { - fn from(bytes: [u8; 32]) -> Self { - Tag(ffi::Tag::from(bytes)) - } -} - -impl From for [u8; 32] { - fn from(tag: Tag) -> Self { - tag.0.into() - } -} diff --git a/ark-rust-secp256k1-zkp/src/zkp/whitelist.rs b/ark-rust-secp256k1-zkp/src/zkp/whitelist.rs deleted file mode 100644 index ff1c8555..00000000 --- a/ark-rust-secp256k1-zkp/src/zkp/whitelist.rs +++ /dev/null @@ -1,456 +0,0 @@ -//! Bindings for the "whitelist" ring signature implementation in secp256k1-zkp. -//! -//! This implementation is used for Liquid PAK list inclusion proofs. - -#[cfg(feature = "std")] -use std::{fmt, str}; - -use crate::ffi::CPtr; -#[cfg(feature = "std")] -use crate::from_hex; -use crate::{ffi, Error, PublicKey, Secp256k1, SecretKey, Signing, Verification}; - -/// A whitelist ring signature. -#[derive(Clone, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct WhitelistSignature(ffi::WhitelistSignature); - -impl WhitelistSignature { - /// Number of keys in the whitelist. - pub fn n_keys(&self) -> usize { - self.0.n_keys - } - - /// Serialize to bytes. - #[cfg(feature = "std")] - pub fn serialize(&self) -> Vec { - let mut buf = vec![0; 33 + 32 * self.n_keys()]; - - let mut out_len = buf.len(); - let ret = unsafe { - ffi::secp256k1_whitelist_signature_serialize( - ffi::secp256k1_context_no_precomp, - buf.as_mut_ptr(), - &mut out_len, - &self.0, - ) - }; - assert_eq!(ret, 1, "failed to serialize whitelist signature"); - assert_eq!( - out_len, - buf.len(), - "whitelist serialized to unexpected length" - ); - - buf - } - - /// Parse a whitelist ring signature from a byte slice. - pub fn from_slice(bytes: &[u8]) -> Result { - let mut sig = ffi::WhitelistSignature::default(); - - let ret = unsafe { - ffi::secp256k1_whitelist_signature_parse( - ffi::secp256k1_context_no_precomp, - &mut sig, - bytes.as_ptr(), - bytes.len(), - ) - }; - if ret != 1 { - return Err(Error::InvalidWhitelistSignature); - } - - Ok(WhitelistSignature(sig)) - } - - /// Create a new whitelist ring signature for the given PAK list and whitelist key. - pub fn new( - secp: &Secp256k1, - online_keys: &[PublicKey], - offline_keys: &[PublicKey], - whitelist_key: &PublicKey, - online_secret_key: &SecretKey, - summed_secret_key: &SecretKey, - key_index: usize, - ) -> Result { - if online_keys.len() != offline_keys.len() { - return Err(Error::InvalidPakList); - } - let n_keys = online_keys.len(); - - let mut sig = ffi::WhitelistSignature::default(); - let ret = unsafe { - ffi::secp256k1_whitelist_sign( - secp.ctx().as_ptr(), - &mut sig, - // These two casts are legit because PublicKey has repr(transparent). - online_keys.as_c_ptr() as *const ffi::PublicKey, - offline_keys.as_c_ptr() as *const ffi::PublicKey, - n_keys, - whitelist_key.as_c_ptr(), - online_secret_key.as_c_ptr(), - summed_secret_key.as_c_ptr(), - key_index, - ) - }; - if ret != 1 { - return Err(Error::CannotCreateWhitelistSignature); - } - - Ok(WhitelistSignature(sig)) - } - - /// Verify the given whitelist signature against the PAK list and whitelist key. - pub fn verify( - &self, - secp: &Secp256k1, - online_keys: &[PublicKey], - offline_keys: &[PublicKey], - whitelist_key: &PublicKey, - ) -> Result<(), Error> { - if online_keys.len() != offline_keys.len() { - return Err(Error::InvalidPakList); - } - let n_keys = online_keys.len(); - - let ret = unsafe { - ffi::secp256k1_whitelist_verify( - secp.ctx().as_ptr(), - &self.0, - // These two casts are legit because PublicKey has repr(transparent). - online_keys.as_c_ptr() as *const ffi::PublicKey, - offline_keys.as_c_ptr() as *const ffi::PublicKey, - n_keys, - whitelist_key.as_c_ptr(), - ) - }; - if ret != 1 { - return Err(Error::InvalidWhitelistProof); - } - - Ok(()) - } - - /// Obtains a raw const pointer suitable for use with FFI functions - #[inline] - pub fn as_ptr(&self) -> *const ffi::WhitelistSignature { - &self.0 - } - - /// Obtains a raw mutable pointer suitable for use with FFI functions - #[inline] - pub fn as_mut_ptr(&mut self) -> *mut ffi::WhitelistSignature { - &mut self.0 - } -} - -#[cfg(feature = "std")] -impl fmt::LowerHex for WhitelistSignature { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for ch in self.serialize().iter() { - write!(f, "{:02x}", ch)?; - } - Ok(()) - } -} - -#[cfg(feature = "std")] -impl fmt::Display for WhitelistSignature { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::LowerHex::fmt(self, f) - } -} - -#[cfg(feature = "std")] -impl fmt::Debug for WhitelistSignature { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -#[cfg(feature = "std")] -impl str::FromStr for WhitelistSignature { - type Err = Error; - fn from_str(s: &str) -> Result { - let mut buf = vec![0; s.len() / 2]; - from_hex(s, &mut buf).map_err(|_| Error::InvalidWhitelistSignature)?; - WhitelistSignature::from_slice(&buf) - } -} - -#[cfg(all(feature = "serde", feature = "std"))] -impl ::serde::Serialize for WhitelistSignature { - fn serialize(&self, s: S) -> Result { - if s.is_human_readable() { - s.collect_str(self) - } else { - s.serialize_bytes(&self.serialize()) - } - } -} - -#[cfg(all(feature = "serde", feature = "std"))] -impl<'de> ::serde::Deserialize<'de> for WhitelistSignature { - fn deserialize>(d: D) -> Result { - use crate::serde_util; - - if d.is_human_readable() { - d.deserialize_str(serde_util::FromStrVisitor::new("an ASCII hex string")) - } else { - d.deserialize_bytes(serde_util::BytesVisitor::new( - "a bytestring", - WhitelistSignature::from_slice, - )) - } - } -} - -impl CPtr for WhitelistSignature { - type Target = ffi::WhitelistSignature; - fn as_c_ptr(&self) -> *const Self::Target { - self.as_ptr() - } - - fn as_mut_c_ptr(&mut self) -> *mut Self::Target { - self.as_mut_ptr() - } -} - -#[cfg(all(test, feature = "global-context"))] -mod tests { - use super::*; - use crate::SECP256K1; - use rand::thread_rng; - - fn test_whitelist_proof_roundtrip(n_keys: usize) { - let mut rng = thread_rng(); - let (keys_online, pak_online) = (0..n_keys) - .map(|_| SECP256K1.generate_keypair(&mut rng)) - .unzip::<_, _, Vec<_>, Vec<_>>(); - let (keys_offline, pak_offline) = (0..n_keys) - .map(|_| SECP256K1.generate_keypair(&mut rng)) - .unzip::<_, _, Vec<_>, Vec<_>>(); - - let (whitelist_sk, whitelist_pk) = SECP256K1.generate_keypair(&mut rng); - - for our_idx in vec![0, n_keys / 2, n_keys - 1].into_iter() { - // sign - - let summed_key = keys_offline[our_idx] - .clone() - .add_tweak(&whitelist_sk.into()) - .unwrap(); - - let signature = WhitelistSignature::new( - SECP256K1, - &pak_online, - &pak_offline, - &whitelist_pk, - &keys_online[our_idx], - &summed_key, - our_idx, - ) - .unwrap(); - assert_eq!(n_keys, signature.n_keys()); - - // verify - - signature - .verify(SECP256K1, &pak_online, &pak_offline, &whitelist_pk) - .unwrap(); - - // round trip - - let encoded = signature.serialize(); - let decoded = WhitelistSignature::from_slice(&encoded).unwrap(); - assert_eq!(n_keys, decoded.n_keys()); - assert_eq!(signature, decoded); - decoded - .verify(SECP256K1, &pak_online, &pak_offline, &whitelist_pk) - .unwrap(); - } - } - - #[test] - fn test_whitelist_proof_roundtrip_n1() { - test_whitelist_proof_roundtrip(1); - } - - #[test] - fn test_whitelist_proof_roundtrip_n50() { - test_whitelist_proof_roundtrip(50); - } - - #[test] - fn test_whitelist_proof_roundtrip_n255() { - test_whitelist_proof_roundtrip(255); - } - - #[test] - fn test_whitelist_proof_invalid() { - let n_keys = 255; - - let mut rng = thread_rng(); - let (keys_online, pak_online) = (0..n_keys) - .map(|_| SECP256K1.generate_keypair(&mut rng)) - .unzip::<_, _, Vec<_>, Vec<_>>(); - let (keys_offline, pak_offline) = (0..n_keys) - .map(|_| SECP256K1.generate_keypair(&mut rng)) - .unzip::<_, _, Vec<_>, Vec<_>>(); - - let (whitelist_sk, whitelist_pk) = SECP256K1.generate_keypair(&mut rng); - - let our_idx = 100; - let summed_key = keys_offline[our_idx] - .clone() - .add_tweak(&whitelist_sk.into()) - .unwrap(); - - { - // wrong pak - let offline = pak_offline[1..].to_vec(); - assert_eq!( - Err(Error::InvalidPakList), - WhitelistSignature::new( - SECP256K1, - &pak_online, - &offline, // wrong pak - &whitelist_pk, - &keys_online[our_idx], - &summed_key, - our_idx, - ) - ); - } - - let correct_signature = WhitelistSignature::new( - SECP256K1, - &pak_online, - &pak_offline, - &whitelist_pk, - &keys_online[our_idx], - &summed_key, - our_idx, - ) - .unwrap(); - - { - // wrong n_keys - let sig = unsafe { - let sig = correct_signature.clone(); - let ptr = sig.as_c_ptr() as *mut ffi::WhitelistSignature; - (*ptr).n_keys -= 1; - sig - }; - assert_eq!( - Err(Error::InvalidWhitelistProof), - sig.verify(SECP256K1, &pak_online, &pak_offline, &whitelist_pk,) - ); - } - - { - // wrong pak - let offline = pak_offline[1..].to_vec(); - assert_eq!( - Err(Error::InvalidPakList), - correct_signature.verify(SECP256K1, &pak_online, &offline, &whitelist_pk,) - ); - } - - { - // verify for online pubkey - assert_eq!( - Err(Error::InvalidWhitelistProof), - correct_signature.verify( - SECP256K1, - &pak_online, - &pak_offline, - &pak_online[our_idx], - ) - ); - } - - { - // verify for offline pubkey - assert_eq!( - Err(Error::InvalidWhitelistProof), - correct_signature.verify( - SECP256K1, - &pak_online, - &pak_offline, - &pak_offline[our_idx], - ) - ); - } - - { - // incorrectly serialized with byte added - let mut encoded = correct_signature.serialize(); - encoded.push(42); - assert_eq!( - Err(Error::InvalidWhitelistSignature), - WhitelistSignature::from_slice(&encoded), - ); - } - - { - // incorrectly serialized with byte changed - let mut encoded = correct_signature.serialize(); - let len = encoded.len(); - encoded[len - 1] = encoded[len - 1] ^ 0x01; - let decoded = WhitelistSignature::from_slice(&encoded).unwrap(); - assert_eq!( - Err(Error::InvalidWhitelistProof), - decoded.verify(SECP256K1, &pak_online, &pak_offline, &whitelist_pk,) - ); - } - - { - // offline key instead of summed - let sig = WhitelistSignature::new( - SECP256K1, - &pak_online, - &pak_offline, - &whitelist_pk, - &keys_online[our_idx], - &keys_offline[our_idx], // actual offline key, not summed - our_idx, - ) - .unwrap(); - - assert_eq!( - Err(Error::InvalidWhitelistProof), - sig.verify(SECP256K1, &pak_online, &pak_offline, &whitelist_pk,) - ); - assert_eq!( - Err(Error::InvalidWhitelistProof), - sig.verify(SECP256K1, &pak_online, &pak_offline, &pak_offline[our_idx],) - ); - } - - { - // whitelist key instead of summed - let sig = WhitelistSignature::new( - SECP256K1, - &pak_online, - &pak_offline, - &whitelist_pk, - &keys_online[our_idx], - &whitelist_sk, // whitelist key, not summed - our_idx, - ) - .unwrap(); - - assert_eq!( - Err(Error::InvalidWhitelistProof), - sig.verify(SECP256K1, &pak_online, &pak_offline, &whitelist_pk,) - ); - } - - assert_eq!( - Ok(()), - correct_signature.verify(SECP256K1, &pak_online, &pak_offline, &whitelist_pk,) - ); - } -} diff --git a/ark-rust-secp256k1/CHANGELOG.md b/ark-rust-secp256k1/CHANGELOG.md new file mode 100644 index 00000000..866fafb9 --- /dev/null +++ b/ark-rust-secp256k1/CHANGELOG.md @@ -0,0 +1,326 @@ +# 0.30.0 - 2024-10-08 + +* Allow signing variable-length messages [#706](https://github.com/rust-bitcoin/rust-secp256k1/pull/706) +* Bump MSRV to 1.63 [#709](https://github.com/rust-bitcoin/rust-secp256k1/pull/709) +* Deprecate `Message::from_digest_slice` in favor of `Message::from_digest` [#712](https://github.com/rust-bitcoin/rust-secp256k1/pull/712) +* Truncate debug output of `SecretKey`; tighten `bitcoin_hashes` dependency version [#722](https://github.com/rust-bitcoin/rust-secp256k1/pull/722) +* Simplify and improve consistency of secret key types' debug output [#726](https://github.com/rust-bitcoin/rust-secp256k1/pull/726) +* Simplify and improve consistency of public key types' debug output [#745](https://github.com/rust-bitcoin/rust-secp256k1/pull/745) +* Feature-gate `KeyPair::from_str` on `global-context` or `alloc` [#728](https://github.com/rust-bitcoin/rust-secp256k1/pull/728) +* Add infallible constructors for `schnorr::Signature` from byteslices [#730](https://github.com/rust-bitcoin/rust-secp256k1/pull/730) +* Deprecate slice-parsing methods in favor of array-parsing ones [#737](https://github.com/rust-bitcoin/rust-secp256k1/pull/737) +* Make `RecoveryId` an enum rather than integer [#743](https://github.com/rust-bitcoin/rust-secp256k1/pull/743) + +# 0.29.0 - 2024-04-02 + +* Deprecate `ThirtyTwoByteHash` [#686](https://github.com/rust-bitcoin/rust-secp256k1/pull/686) + + This trait turned out to be problematic during upgrade because we support a ranged dependency for + `bitcoin_hashes`. Consider implementing `From for Message` for your type iff your type is a 32 + byte hash (ie, output from a hash algorithm that produces a 32 byte digest like sha256). When + using the impl, consider using `Message::from` instead of `hash.into()` because we will be + introducing generics in a future version and the compiler will not be able to work out the target + type. + +* Bump MSRV to Rust `v1.56.1` [#693](https://github.com/rust-bitcoin/rust-secp256k1/pull/693) +* Upgrade `hashes` using range dependency `version = ">= 0.12, <= 0.14"` [#690](https://github.com/rust-bitcoin/rust-secp256k1/pull/690) +* Depend on latest `secp256k1-sys` (vendors `secp256k1 v0.4.1`) [#688](https://github.com/rust-bitcoin/rust-secp256k1/pull/688) + +# 0.28.2 - 2024-01-30 + +* Implement `Hash` for `Scalar` [#674](https://github.com/rust-bitcoin/rust-secp256k1/pull/674) +* Implement `Ord` and `PartialOrd` for `RecoverableSignature` [#611](https://github.com/rust-bitcoin/rust-secp256k1/pull/611) +* Add byte accessors to `ElligatorSwiftSharedSecret` [#676](https://github.com/rust-bitcoin/rust-secp256k1/pull/676) + +# 0.28.1 - 2024-01-03 + +* Update secp265k1-sys to 0.9.2 (contains some fixes for WASM and [a FFI binding fix](https://github.com/rust-bitcoin/rust-secp256k1/pull/6700)) +* Various improvements to the `SerializedSignature` type [#658](https://github.com/rust-bitcoin/rust-secp256k1/pull/658) [#659](https://github.com/rust-bitcoin/rust-secp256k1/pull/659) + +# 0.28.0 - 2023-10-23 + +* Add bindings to the ElligatorSwift implementation [#627](https://github.com/rust-bitcoin/rust-secp256k1/pull/627) +* Depend on recent release of `bitcoin_hashes` v0.13.0 [#621](https://github.com/rust-bitcoin/rust-secp256k1/pull/621) +* Add a verify function to `PublicKey` [#618](https://github.com/rust-bitcoin/rust-secp256k1/pull/618) +* Add serialize function for schnorr::Signature [#607](https://github.com/rust-bitcoin/rust-secp256k1/pull/607) +* Bump MSRV to 1.48 [#595](https://github.com/rust-bitcoin/rust-secp256k1/pull/595) +* Remove implementations of `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` from the + `impl_array_newtype` macro. Users will now need to derive these traits if they are wanted. + +# 0.27.0 - 2023-03-15 + +* [Depend on newly release `bitcoin_hashes` v0.12](https://github.com/rust-bitcoin/rust-secp256k1/pull/588). +* [Implement `Debug` trait for `Scalar` type](https://github.com/rust-bitcoin/rust-secp256k1/pull/578). +* [Implement `insecure-erase`](https://github.com/rust-bitcoin/rust-secp256k1/pull/582). + +# 0.26.0 - 2202-12-19 + +* Update libsecp25k1 to v0.2.0 + +# 0.25.0 - 2022-12-07 + +* [Fix soundness issue with `preallocated_gen_new`](https://github.com/rust-bitcoin/rust-secp256k1/pull/548) +* Update to `secp256k1-sys` [v0.7.0](https://github.com/rust-bitcoin/rust-secp256k1/pull/549) +* Use type system to [improve safety](https://github.com/rust-bitcoin/rust-secp256k1/pull/483). +* [Change secp256k1-sys symbol names to 0_6_1](https://github.com/rust-bitcoin/rust-secp256k1/pull/490). +* [Introduce `rustfmt`](https://github.com/rust-bitcoin/rust-secp256k1/pull/499) to the codebase. +* [Make all raw pointer methods go through the CPtr trait](https://github.com/rust-bitcoin/rust-secp256k1/pull/507). +* [Make comparison functions stable](https://github.com/rust-bitcoin/rust-secp256k1/pull/518). +* [Remove](https://github.com/rust-bitcoin/rust-secp256k1/pull/512) public constant `ONE_KEY` (consider using `FromStr` as a replacement). + +# 0.24.1 - 2022-10-25 + +* [Fix broken deserialization logic of `KeyPair`](https://github.com/rust-bitcoin/rust-secp256k1/issues/491) that previously always panicked. After the patch deserialization only panics if neither the `global-context` nor the `alloc` (default) feature is active. + +# 0.24.0 - 2022-07-20 + +* Upgrade to new release of [bitcoin_hashes](https://github.com/rust-bitcoin/bitcoin_hashes/releases/tag/0.11.0). + +# 0.23.4 - 2022-07-14 + +* [Disable automatic rerandomization of contexts under WASM](https://github.com/rust-bitcoin/rust-secp256k1/pull/474) + +# 0.23.3 - 2022-06-29 + +* [Add must_use for mut self key manipulation methods](https://github.com/rust-bitcoin/rust-secp256k1/pull/465) +* [Fix fuzzing feature guard](https://github.com/rust-bitcoin/rust-secp256k1/pull/466) + +# 0.23.2 - 2022-06-27 + +* [Move `cbor` to dev-dependencies](https://github.com/rust-bitcoin/rust-secp256k1/pull/461) +* [Derive `Hash` for `RecoverableSignature`](https://github.com/rust-bitcoin/rust-secp256k1/pull/462) + +# 0.23.1 - 2022-06-24 + +[Enable "rand/std_rng" feature](https://github.com/rust-bitcoin/rust-secp256k1/pull/460) when the crate's "rnd-std" feature is enabled. + +# 0.23.0 - 2022-06-21 + +The major change in this version is the increase of the Minimum Supported Rust Version (MSRV) from 1.29 to 1.41.1, this is a big change because it introduces Rust Edition 2018 to the codebase along with all the benefits that brings. + +## Breaking changes + +* [MSRV bumped to 1.41.1 and edition changed to 2018](https://github.com/rust-bitcoin/rust-secp256k1/pull/331) +* serde implements serialize [fixed-width arrays](https://github.com/rust-bitcoin/rust-secp256k1/pull/406) as tuples in binary formats to avoid encoding the length +* Key tweaking methods renamed and refactored to use a more [functional-style](https://github.com/rust-bitcoin/rust-secp256k1/pull/406), they now accept a [new Scalar](https://github.com/rust-bitcoin/rust-secp256k1/pull/445) type instead of raw slices +* Update [`rand` dependency to 0.8](https://github.com/rust-bitcoin/rust-secp256k1/pull/331) +* `KeyPair::from_secret_key` [borrows SecretKey](https://github.com/rust-bitcoin/rust-secp256k1/pull/430) instead of taking ownership +* `SerializedSignature` no longer implements `Default` + +## New features/APIs + +* Several convenience/conversion methods between [keys](https://github.com/rust-bitcoin/rust-secp256k1/pull/430) +* [`sign_ecdsa_with_noncedata` and `sign_ecdsa_recoverable_with_noncedata`](https://github.com/rust-bitcoin/rust-secp256k1/pull/425) can be used to add additional entropy to ECDSA signatures +* Errors now display their sources if std is unavailable, with std they rely on the consumer to use the source() method +* [Implemented `TryFrom` for `Parity`](https://github.com/rust-bitcoin/rust-secp256k1/pull/409) +* The [alloc feature](https://github.com/rust-bitcoin/rust-secp256k1/pull/331) can be used on targets with allocators without a standard library +* `SharedSecret` can be created from a slice, parsed from a hex string, or [(de)serialized using serde](https://github.com/rust-bitcoin/rust-secp256k1/pull/418) +* `SerializedSignature` implements `IntoIterator` (both owned and shared reference) +* We now [derive `std::hash::Hash` for `Signature`](https://github.com/rust-bitcoin/rust-secp256k1/pull/441) + +## Other improvements + +* `global-context` feature now activates `global-context-less-secure`. +* `githooks/` directory added for contributors +* [Clippy is now used in CI](https://github.com/rust-bitcoin/rust-secp256k1/pull/448) and the code is clippy-compliant +* Various documentation improvements +* Various CI/development improvements +* Various code quality improvements/refactors + + +# 0.22.1 - 2022-03-10 + +* [Reintroduce](https://github.com/rust-bitcoin/rust-secp256k1/pull/417) accidentally removed possibility to create `SharedSecret` from byte serialization + +# 0.22.0 - 2022-03-08 + +* Disable `bitcoin_hashes/std` by default; [add `bitcoin-hashes-std` feature to re-enable it](https://github.com/rust-bitcoin/rust-secp256k1/pull/410) +* Rename [more `schnorrsig` methods to `schnorr`](https://github.com/rust-bitcoin/rust-secp256k1/pull/411) +* [Obfuscate `SharedSecret` string serialization](https://github.com/rust-bitcoin/rust-secp256k1/pull/396) +* [Simplify `SharedSecret` API](https://github.com/rust-bitcoin/rust-secp256k1/pull/402) to use a 32-byte buffer; users of custom hashes should now use bare arrays rather than this type. +* Change [serde serialization of `Parity`](https://github.com/rust-bitcoin/rust-secp256k1/pull/401) from `i32` to `u8`; clean up [error handling](https://github.com/rust-bitcoin/rust-secp256k1/pull/403) + +# 0.21.3 - 2022-01-31 + +* Several documentation improvements ([#366](https://github.com/rust-bitcoin/rust-secp256k1/pull/366), [#365](https://github.com/rust-bitcoin/rust-secp256k1/pull/365), [#373](https://github.com/rust-bitcoin/rust-secp256k1/pull/373), [#381](https://github.com/rust-bitcoin/rust-secp256k1/pull/381), [#369](https://github.com/rust-bitcoin/rust-secp256k1/pull/369), [#389](https://github.com/rust-bitcoin/rust-secp256k1/pull/389), [#391](https://github.com/rust-bitcoin/rust-secp256k1/pull/391), [#397](https://github.com/rust-bitcoin/rust-secp256k1/pull/397), [#399](https://github.com/rust-bitcoin/rust-secp256k1/pull/399), [#340](https://github.com/rust-bitcoin/rust-secp256k1/pull/365)) +* Deprecate the [`generate_schnorrsig_keypair` method](https://github.com/rust-bitcoin/rust-secp256k1/pull/372) (unclear value) +* Add [serde traits to `KeyPair`](https://github.com/rust-bitcoin/rust-secp256k1/pull/379) +* Redo the [API of the new `Parity` type](https://github.com/rust-bitcoin/rust-secp256k1/pull/382) to more clearly match our desired semantics; **the `From` impl on this type is now deprecated**. Also [#400](https://github.com/rust-bitcoin/rust-secp256k1/pull/400). +* Randomize [the global context on creation](https://github.com/rust-bitcoin/rust-secp256k1/pull/385) when possible; weaken [`global-context-less-secure` feature accordingly](https://github.com/rust-bitcoin/rust-secp256k1/pull/407). +* Improve [the global context API](https://github.com/rust-bitcoin/rust-secp256k1/pull/392) +* Fix [the `Debug` impl](https://github.com/rust-bitcoin/rust-secp256k1/pull/393) for `RecoverableSignature` +* Implement [`LowerHex` and `Display`](https://github.com/rust-bitcoin/rust-secp256k1/pull/398) + +# 0.21.0 - 2022-01-02 + +* Fix `KeyPair::from_seckey_slice` [error return value](https://github.com/rust-bitcoin/rust-secp256k1/pull/316) +* Reduce the `lowmemory` [precomp table size](https://github.com/rust-bitcoin/rust-secp256k1/pull/323) +* [Add `KeyPair::serialize_sec`](https://github.com/rust-bitcoin/rust-secp256k1/pull/308) +* Increase [`bitcoin_hashes` version to 0.10](https://github.com/rust-bitcoin/rust-secp256k1/pull/326); rename `secp256k1::bitcoin_hashes` module to `secp256k1::hashes` to align with `bitcoin` crate naming +* Add new [error variant for `PublicKey::combine_keys`](https://github.com/rust-bitcoin/rust-secp256k1/pull/304) +* Change `Display` and `Debug` for secret keys to [only output a truncated hash](https://github.com/rust-bitcoin/rust-secp256k1/pull/312) +* [Improve documentation](https://github.com/rust-bitcoin/rust-secp256k1/pull/307) +* [Implement `Hash` for `schnorrsig::Signature`](https://github.com/rust-bitcoin/rust-secp256k1/pull/335) +* Refactor modules to put [Schnorr and ECDSA on more equal footing](https://github.com/rust-bitcoin/rust-secp256k1/pull/327) +* Add serde traits [for `KeyPair` type](https://github.com/rust-bitcoin/rust-secp256k1/pull/313) +* Fix [context bound requirements for a few methods](https://github.com/rust-bitcoin/rust-secp256k1/pull/342) +* Add a [static immutable-zero aligned type](https://github.com/rust-bitcoin/rust-secp256k1/pull/345) +* Change `tweak_add_assign` and `tweak_add_check` to [use an opaque `Parity` type rather than a boolean](https://github.com/rust-bitcoin/rust-secp256k1/pull/344/) + +# 0.20.3 - 2021-06-10 + +* Fix [`SecretKey` validation in `from_str`](https://github.com/rust-bitcoin/rust-secp256k1/pull/296) +* Add [`global-context-less-secure` feature](https://github.com/rust-bitcoin/rust-secp256k1/pull/279) which creates a non-randomized global context (and does not require `rand` or `std`) +* Add [`schnorrsig::KeyPair::from_secret_key` convenience function](https://github.com/rust-bitcoin/rust-secp256k1/pull/294) +* Add [`combine_keys` function to `PublicKey`](https://github.com/rust-bitcoin/rust-secp256k1/pull/291) +* [Reduce symbol visibility in C compilation to allow LTO to work](https://github.com/rust-bitcoin/rust-secp256k1/pull/289) +* Add [`alloc` feature](https://github.com/rust-bitcoin/rust-secp256k1/pull/300) **requiring rustc 1.36+** to enable context creation without std +* [Rewrite stubbed-out-for-fuzzing version of the library](https://github.com/rust-bitcoin/rust-secp256k1/pull/282) to improve fuzzer accessibility + +# 0.20.2 - 2021-04-27 + +* Fix some WASM build issues +* Add [some missing `#derive`s to `Error`](https://github.com/rust-bitcoin/rust-secp256k1/pull/277/) +* Add [serde support for Schnorr signatures and for deserializing from owned types](https://github.com/rust-bitcoin/rust-secp256k1/pull/270/) + +# 0.20.0 - 2020-12-21 + +* [remove `ffi::PublicKey::blank`](https://github.com/rust-bitcoin/rust-secp256k1/pull/232) and replace with unsafe [`ffi::PublicKey::new` and `ffi::PublicKey::from_array_unchecked`](https://github.com/rust-bitcoin/rust-secp256k1/pull/253/); similar for all other FFI types +* [support wasm32-wasi target](https://github.com/rust-bitcoin/rust-secp256k1/pull/242) +* [make the global-context feature depend on the rand-std feature](https://github.com/rust-bitcoin/rust-secp256k1/pull/246) +* [add a lexicographic ordering to `PublicKey`](https://github.com/rust-bitcoin/rust-secp256k1/pull/248) which does **not** match the ordering used by Bitcoin Core (matching this would be impossible as it requires tracking a compressedness flag, which libsecp256k1 does not have) +* [implement BIP340 Schnorr signatures](https://github.com/rust-bitcoin/rust-secp256k1/pull/237) +* [require use of new `AlignedType` in preallocated-context API to enforce alignment requirements](https://github.com/rust-bitcoin/rust-secp256k1/pull/233); previously it was possible to get UB by using misaligned memory stores +* [enforce correct alignment when using preallocated context API](https://github.com/rust-bitcoin/rust-secp256k1/pull/233) +* [stop using cargo features for dangerous build-breaking options, require setting `RUSTFLAGS` instead](https://github.com/rust-bitcoin/rust-secp256k1/pull/263) +* [implement low-R signing and function to grind even smaller signatures](https://github.com/rust-bitcoin/rust-secp256k1/pull/259) +* [remove endomorphism feature, following upstream in enabling it by default](https://github.com/rust-bitcoin/rust-secp256k1/pull/257) + +# 0.19.0 - 2020-08-27 + +* **Update MSRV to 1.29.0** + +# 0.18.0 - 2020-08-26 + +* Add feature-gated `bitcoin_hashes` dependency and [`ThirtyTwoByteHash` trait](https://github.com/rust-bitcoin/rust-secp256k1/pull/206/) +* Add feature-gated [global static context](https://github.com/rust-bitcoin/rust-secp256k1/pull/224) +* Allow [all-zero messages](https://github.com/rust-bitcoin/rust-secp256k1/pull/207) to be constructed +* Bump rust-secp-sys to 0.2.0 + +# 0.17.2 +- Fix linking in the `fuzztarget` feature. + +# 0.17.1 + +- Correctly prefix the secp256k1-sys links field in Cargo.toml. + +# 0.17.0 + +- Move FFI into secp256k1-sys crate. +- Add `external-symbols` feature for not building upstream. +- Add functions to create a context from a raw pointer. +- Support passing custom hash functions to ECDH. +- Wrap Secp256k1 from raw context in a ManuallyDrop. + +# 0.15.4 - 2019-09-06 + +- Add `rand-std` feature. +- Pin the cc build-dep version to `< 1.0.42` to remain + compatible with rustc 1.22.0. +- Changed all `as_*ptr()` to a new safer `CPtr` trait + +# 0.15.2 - 2019-08-08 + +- Add feature `lowmemory` that reduces the EC mult window size to require + significantly less memory for the validation context (~680B instead of + ~520kB), at the cost of slower validation. It does not affect the speed of + signing, nor the size of the signing context. + +# 0.15.0 - 2019-07-25 + +* Implement hex human-readable serde for PublicKey +* Implement fmt::LowerHex for SecretKey and PublicKey +* Relax `cc` dependency requirements +* Add links manifest key to prevent cross-version linkage + +# 0.14.1 - 2019-07-14 + +* Implemented FFI functions: `secp256k1_context_create` and `secp256k1_context_destroy` in rust. + +# 0.14.0 - 2019-07-08 + +* [Feature-gate endormorphism optimization](https://github.com/rust-bitcoin/rust-secp256k1/pull/120) + because of a lack of clarity with respect to patents +* Got full no-std support including eliminating all use of libc in C bindings. + [PR 1](https://github.com/rust-bitcoin/rust-secp256k1/pull/115) + [PR 2](https://github.com/rust-bitcoin/rust-secp256k1/pull/125). + This library should be usable in bare-metal environments and with rust-wasm. + Thanks to Elichai Turkel for driving this forward! +* Update upstream libsecp256k1 version to 143dc6e9ee31852a60321b23eea407d2006171da + +# 0.13.0 - 2019-05-21 + +* Update minimum supported rust compiler 1.22. +* Replace `serialize_der` function with `SerializedSignature` struct. +* Allow building without a standard library (`no_std`). `std` feature is on by default. +* Add human readable serialization to `Signatures` and `SecretKeys`. +* Stop displaying 0 bytes if a `Signature` is less than 72 bytes. +* Only compile recovery module if feature `recovery` is set (non-default). +* Update `rand` dependency from 0.4 to 0.6 and add `rand_core` 0.4 dependency. +* Relax `cc` dependency requirements. + +# 0.12.2 - 2019-01-18 + +* Fuzzer bug fix + +# 0.12.1 - 2019-01-15 + +* Minor bug fixes +* Fixed `cc` crate version to maintain minimum compiler version without breakage +* Removed `libc` dependency as it our uses have been subsumed into stdlib + +# 0.12.0 - 2018-12-03 + +* **Overhaul API to remove context object when no precomputation is needed** +* Add `ThirtyTwoByteHash` trait which allows infallible conversions to `Message`s +* Disallow 0-valued `Message` objects since signatures on them are forgeable for all keys +* Remove `ops::Index` implementations for `Signature` +* Remove depecated constants and unsafe `ZERO_KEY` constant + +# 0.11.5 - 2018-11-09 + +* Use `pub extern crate` to export dependencies whose types are exported + +# 0.11.4 - 2018-11-04 + +* Add `FromStr` and `Display` for `Signature` and both key types +* Fix `build.rs` for Windows and rustfmt configuration for docs.rs +* Correct endianness issue for `Signature` `Debug` output + +# 0.11.3 - 2018-10-28 + +* No changes, just fixed docs.rs configuration + +# 0.11.2 - 2018-09-11 + +* Correct endianness issue in RFC6979 nonce generation + +# 0.11.1 - 2018-08-22 + +* Put `PublicKey::combine` back because it is currently needed to implement Lightning BOLT 3 + +# 0.11.0 - 2018-08-22 + +* Update `rand` to 0.4 and `gcc` 0.3 to `cc` 1.0. (`rand` 0.5 exists but has a lot of breaking changes and no longer compiles with 1.14.0.) +* Remove `PublicKey::combine` from API since it cannot be used with anything else in the API +* Detect whether 64-bit compilation is possible, and do it if we can (big performance improvement) + +# 0.10.0 - 2018-07-25 + +* A [complete API overhaul](https://github.com/rust-bitcoin/rust-secp256k1/pull/27) to move many runtime errors into compiletime errors +* Update [libsecp256k1 to `1e6f1f5ad5e7f1e3ef79313ec02023902bf8`](https://github.com/rust-bitcoin/rust-secp256k1/pull/32). Should be no visible changes. +* [Remove `PublicKey::new()` and `PublicKey::is_valid()`](https://github.com/rust-bitcoin/rust-secp256k1/pull/37) since `new` was unsafe and it should now be impossible to create invalid `PublicKey` objects through the API +* [Reintroduce serde support](https://github.com/rust-bitcoin/rust-secp256k1/pull/38) behind a feature gate using serde 1.0 +* Clean up build process and various typos + + diff --git a/ark-rust-secp256k1/Cargo-minimal.lock b/ark-rust-secp256k1/Cargo-minimal.lock new file mode 100644 index 00000000..d3fe48f7 --- /dev/null +++ b/ark-rust-secp256k1/Cargo-minimal.lock @@ -0,0 +1,591 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "base-x" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9ad92e7876f320bf1ba3325acb19d1bfcfdfdf52d15cbe7bd38314cf81854d" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitcoin-io" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] + +[[package]] +name = "bumpalo" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" + +[[package]] +name = "byteorder" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" + +[[package]] +name = "cc" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" + +[[package]] +name = "cfg-if" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen", +] + +[[package]] +name = "discard" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a9117502da3c5657cb8e2ca7ffcf52d659f00c78c5127d1ebadc2ebe76465be" + +[[package]] +name = "dtoa" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5edd69c67b2f8e0911629b7e6b8a34cb3956613cd7c6e6414966dee349c2db4f" + +[[package]] +name = "getrandom" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" +dependencies = [ + "cfg-if 0.1.2", + "libc", + "stdweb", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "half" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6c0438de3ca4d8cac2eec62b228e2f8865cfe9ebefea720406774223fa2d2e" + +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + +[[package]] +name = "itoa" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91fd9dc2c587067de817fec4ad355e3818c3d893a78cab32a0a474c7a15bb8d5" + +[[package]] +name = "js-sys" +version = "0.3.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" + +[[package]] +name = "libc" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dfca3d9957906e8d1e6a0b641dc9a59848e793f1da2165889fd4f62d10d79c" + +[[package]] +name = "log" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a89a0c46ba789b8a247d4c567aed4d7c68e624672d238b45cc3ec20dc9f940" +dependencies = [ + "cfg-if 0.1.2", +] + +[[package]] +name = "num-traits" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51eab148f171aefad295f8cece636fc488b9b392ef544da31ea4b8ef6b9e9c39" + +[[package]] +name = "ppv-lite86" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" + +[[package]] +name = "proc-macro2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa93823f53cfd0f5ac117b189aed6cfdfb2cfc0a9d82e956dd7927595ed7d46" +dependencies = [ + "unicode-xid 0.1.0", +] + +[[package]] +name = "proc-macro2" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53f5ffe53a6b28e37c9c1ce74893477864d64f74778a93a4beb43c8fa167f639" +dependencies = [ + "unicode-xid 0.2.0", +] + +[[package]] +name = "quote" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f0fc799e40f2a2c2be239825b30b686f1bd1d2e0e3d5e943b14c1380db49acf" + +[[package]] +name = "quote" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b925e6c90a6272d38f6a2f87b3ee68760bc1db9572f8f93dbbb25429fb9e7fe3" +dependencies = [ + "proc-macro2 0.4.4", +] + +[[package]] +name = "quote" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab938ebe6f1c82426b5fb82eaf10c3e3028c53deaa3fbe38f5904b37cf4d767" +dependencies = [ + "proc-macro2 1.0.13", +] + +[[package]] +name = "rand" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76330fb486679b4ace3670f117bbc9e16204005c4bde9c4bd372f45bed34f12" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rustc_version" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e114e275f7c9b5d50bb52b28f9aac1921209f02aa6077c8b255e21eefaf8ffa" +dependencies = [ + "semver", +] + +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "secp256k1" +version = "0.30.0" +dependencies = [ + "bincode", + "bitcoin_hashes", + "getrandom", + "hex_lit", + "rand", + "rand_core", + "secp256k1-sys", + "serde", + "serde_cbor", + "serde_test", + "wasm-bindgen-test", +] + +[[package]] +name = "secp256k1-sys" +version = "0.11.0" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "semver" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" + +[[package]] +name = "serde_cbor" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6ef26f80c739ba7709ec3275c582a1691c5b261f4ce06edd8f539008fa1a36d" +dependencies = [ + "byteorder", + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a61ecb8511aaff381424f98b49a059017420ec60e15e8d63b645701af7fa9b8" +dependencies = [ + "quote 0.3.8", + "serde_derive_internals", + "syn 0.11.10", +] + +[[package]] +name = "serde_derive_internals" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "021c338d22c7e30f957a6ab7e388cb6098499dda9fd4ba1661ee074ca7a180d1" +dependencies = [ + "syn 0.11.10", + "synom", +] + +[[package]] +name = "serde_json" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9b1ec939469a124b27e208106550c38358ed4334d2b1b5b3825bc1ee37d946a" +dependencies = [ + "dtoa", + "itoa", + "num-traits", + "serde", +] + +[[package]] +name = "serde_test" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "482765e11e55174e2d74a611674d09ed96712c00e0777e305a0c416dfef5fa40" +dependencies = [ + "serde", +] + +[[package]] +name = "sha1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" + +[[package]] +name = "stdweb" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68c0ce28cf7400ed022e18da3c4591e14e1df02c70e93573cc59921b3923aeb" +dependencies = [ + "discard", + "rustc_version", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e21ebd9179de08f2300a65454268a17ea3de204627458588c84319c4def3930" +dependencies = [ + "proc-macro2 0.4.4", + "quote 0.6.0", + "serde", + "serde_derive", + "syn 0.15.0", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e68f7d08b76979a43e93fe043b66d2626e35d41d68b0b85519202c6dd8ac59fa" +dependencies = [ + "base-x", + "proc-macro2 0.4.4", + "quote 0.6.0", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn 0.15.0", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e93e3ace205c4c1926b882cf8d8209e86acd445fda5fcf850455c3d178651c7" + +[[package]] +name = "syn" +version = "0.11.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171b739972d9a1bfb169e8077238b51f9ebeaae4ff6e08072f7ba386a8802da2" +dependencies = [ + "quote 0.3.8", + "synom", + "unicode-xid 0.0.4", +] + +[[package]] +name = "syn" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ec67da440de95ec3a63fa50541afc4f433d1f410f1f0926b6c4b169660c721" +dependencies = [ + "proc-macro2 0.4.4", + "quote 0.6.0", + "unicode-xid 0.1.0", +] + +[[package]] +name = "syn" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef781e621ee763a2a40721a8861ec519cb76966aee03bb5d00adb6a31dc1c1de" +dependencies = [ + "proc-macro2 1.0.13", + "quote 1.0.0", + "unicode-xid 0.2.0", +] + +[[package]] +name = "synom" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fece1853fb872b0acdc3ff88f37c474018e125ef81cd4cb8c0ca515746b62ed" +dependencies = [ + "unicode-xid 0.0.4", +] + +[[package]] +name = "unicode-xid" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasm-bindgen" +version = "0.2.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2 1.0.13", + "quote 1.0.0", + "syn 1.0.27", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe9756085a84584ee9457a002b7cdfe0bfff169f45d2591d8be1345a6780e35" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084" +dependencies = [ + "quote 1.0.0", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549" +dependencies = [ + "proc-macro2 1.0.13", + "quote 1.0.0", + "syn 1.0.27", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158" + +[[package]] +name = "wasm-bindgen-test" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3d30c1e43ebb4c4835f8163456d16f83dd6c1831424cb22680c680ef5f8ea8" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "scoped-tls", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f093012630c0c14be061ac7a8d99f82a94e2b1cfd74619fa71090705d2c91be" +dependencies = [ + "proc-macro2 1.0.13", + "quote 1.0.0", +] + +[[package]] +name = "web-sys" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721c6263e2c66fd44501cc5efbfa2b7dfa775d13e4ea38c46299646ed1f9c70a" +dependencies = [ + "js-sys", + "wasm-bindgen", +] diff --git a/ark-rust-secp256k1/Cargo-recent.lock b/ark-rust-secp256k1/Cargo-recent.lock new file mode 100644 index 00000000..71f42992 --- /dev/null +++ b/ark-rust-secp256k1/Cargo-recent.lock @@ -0,0 +1,366 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitcoin-io" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "secp256k1" +version = "0.30.0" +dependencies = [ + "bincode", + "bitcoin_hashes", + "getrandom", + "hex_lit", + "rand", + "rand_core", + "secp256k1-sys", + "serde", + "serde_cbor", + "serde_test", + "wasm-bindgen-test", +] + +[[package]] +name = "secp256k1-sys" +version = "0.11.0" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.157" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707de5fcf5df2b5788fca98dd7eab490bc2fd9b7ef1404defc462833b83f25ca" + +[[package]] +name = "serde_cbor" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7081ed758ec726a6ed8ee7e92f5d3f6e6f8c3901b1f972e3a4a2f2599fad14f" +dependencies = [ + "byteorder", + "half", + "serde", +] + +[[package]] +name = "serde_test" +version = "1.0.157" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4231c6fab29d02b3cc705db3422aa36f7d23f1e1c096c947c8b8816d7c43dd45" +dependencies = [ + "serde", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "wasm-bindgen-test" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db36fc0f9fb209e88fb3642590ae0205bb5a56216dabd963ba15879fe53a30b" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "scoped-tls", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0734759ae6b3b1717d661fe4f016efcfb9828f5edb4520c18eaee05af3b43be9" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] diff --git a/ark-rust-secp256k1/Cargo.toml b/ark-rust-secp256k1/Cargo.toml new file mode 100644 index 00000000..12ac0ded --- /dev/null +++ b/ark-rust-secp256k1/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "ark-secp256k1" +version = "0.31.0" +authors = [ "Dawid Ciężarkiewicz ", + "Andrew Poelstra " ] +license = "CC0-1.0" +homepage = "https://github.com/rust-bitcoin/rust-secp256k1/" +repository = "https://github.com/rust-bitcoin/rust-secp256k1/" +documentation = "https://docs.rs/secp256k1/" +description = "Rust wrapper library for Pieter Wuille's `libsecp256k1`. Implements ECDSA and BIP 340 signatures for the SECG elliptic curve group secp256k1 and related utilities." +keywords = [ "crypto", "ECDSA", "secp256k1", "libsecp256k1", "bitcoin" ] +readme = "README.md" +edition = "2021" +rust-version = "1.63.0" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[features] +default = ["std"] +std = ["alloc", "secp256k1-sys/std", "rand?/std", "rand?/std_rng", "rand?/thread_rng", "hashes?/std"] +# allow use of Secp256k1::new and related API that requires an allocator +alloc = ["secp256k1-sys/alloc"] +recovery = ["secp256k1-sys/recovery"] +lowmemory = ["secp256k1-sys/lowmemory"] +global-context = ["std"] +# disable re-randomization of the global context, which provides some +# defense-in-depth against sidechannel attacks. You should only use +# this feature if you expect the `rand` crate's thread_rng to panic. +# (If you are sure the `rand` and `std` features will not be enabled, e.g. +# if you are doing a no-std build, then this feature does nothing +# and is not necessary.) +global-context-less-secure = ["global-context"] + +[dependencies] +secp256k1-sys = { version = "0.11.0", default-features = false, path = "./secp256k1-sys" } + +hashes = { package = "bitcoin_hashes", version = "0.14", default-features = false, optional = true } +rand = { version = "0.9", default-features = false, optional = true } +serde = { version = "1.0.103", default-features = false, optional = true } + +[dev-dependencies] +rand_core = "0.9" +serde_cbor = "0.10.0" +serde_test = "1.0.19" +bincode = "1.3.3" +hex_lit = "0.1.1" + +[target.wasm32-unknown-unknown.dev-dependencies] +wasm-bindgen-test = "0.3" +getrandom = { version = "0.3", features = ["wasm_js"] } + +[lints.rust] +unexpected_cfgs = { level = "deny", check-cfg = ['cfg(bench)', 'cfg(secp256k1_fuzz)', 'cfg(rust_secp_no_symbol_renaming)'] } diff --git a/ark-rust-secp256k1/Cross.toml b/ark-rust-secp256k1/Cross.toml new file mode 100644 index 00000000..cc9bc4cf --- /dev/null +++ b/ark-rust-secp256k1/Cross.toml @@ -0,0 +1,2 @@ +[target.x86_64-pc-windows-gnu] +image = "ghcr.io/cross-rs/x86_64-pc-windows-gnu:main" diff --git a/ark-rust-secp256k1-zkp/LICENSE b/ark-rust-secp256k1/LICENSE similarity index 100% rename from ark-rust-secp256k1-zkp/LICENSE rename to ark-rust-secp256k1/LICENSE diff --git a/ark-rust-secp256k1/README.md b/ark-rust-secp256k1/README.md new file mode 100644 index 00000000..7cb55adf --- /dev/null +++ b/ark-rust-secp256k1/README.md @@ -0,0 +1,71 @@ +
+

Rust Secp256k1

+ +

+ Crate Info + CC0 1.0 Universal Licensed + CI Status + API Docs + Rustc Version 1.56.1+ +

+
+ +`rust-secp256k1` is a wrapper around [libsecp256k1](https://github.com/bitcoin-core/secp256k1), a C +library implementing various cryptographic functions using the [SECG](https://www.secg.org/) curve +[secp256k1](https://en.bitcoin.it/wiki/Secp256k1). + +This library: + +* exposes type-safe Rust bindings for all `libsecp256k1` functions +* implements key generation +* implements deterministic nonce generation via RFC6979 +* implements many unit tests, adding to those already present in `libsecp256k1` +* makes no allocations (except in unit tests) for efficiency and use in freestanding implementations + +### Contributing + +Contributions to this library are welcome. A few guidelines: + +* Any breaking changes must have an accompanied entry in CHANGELOG.md +* No new dependencies, please. +* No crypto should be implemented in Rust, with the possible exception of hash functions. Cryptographic contributions should be directed upstream to libsecp256k1. +* This library should always compile with any combination of features on **Rust 1.56.1**. + +### Githooks + +To assist devs in catching errors _before_ running CI we provide some githooks. If you do not +already have locally configured githooks you can use the ones in this repository by running, in the +root directory of the repository: +``` +git config --local core.hooksPath githooks/ +``` + +Alternatively add symlinks in your `.git/hooks` directory to any of the githooks we provide. + +### Benchmarks + +We use a custom Rust compiler configuration conditional to guard the bench mark code. To run the +bench marks use: `RUSTFLAGS='--cfg=bench' cargo +nightly bench --features=recovery`. + +### A note on `non_secure_erase` + +This crate's secret types (`SecretKey`, `Keypair`, `SharedSecret`, `Scalar`, and `DisplaySecret`) +have a method called `non_secure_erase` that *attempts* to overwrite the contained secret. This +method is provided to assist other libraries in building secure secret erasure. However, this +library makes no guarantees about the security of using `non_secure_erase`. In particular, +the compiler doesn't have any concept of secrets and in most cases can arbitrarily move or copy +values anywhere it pleases. For more information, consult the [`zeroize`](https://docs.rs/zeroize) +documentation. + +## Fuzzing + +If you want to fuzz this library, or any library which depends on it, you will +probably want to disable the actual cryptography, since fuzzers are unable to +forge signatures and therefore won't test many interesting codepaths. To instead +use a trivially-broken but fuzzer-accessible signature scheme, compile with +`--cfg=secp256k1_fuzz` in your `RUSTFLAGS` variable. + +Note that `cargo hfuzz` does **not** set this config flag automatically. In 0.27.0 +and earlier versions, we used the `--cfg=fuzzing` which honggfuzz does set, but we +changed this because there was no way to override it. + diff --git a/ark-rust-secp256k1/clippy.toml b/ark-rust-secp256k1/clippy.toml new file mode 100644 index 00000000..b3c3a24c --- /dev/null +++ b/ark-rust-secp256k1/clippy.toml @@ -0,0 +1 @@ +msrv = "1.63.0" diff --git a/ark-rust-secp256k1/contrib/crates.sh b/ark-rust-secp256k1/contrib/crates.sh new file mode 100755 index 00000000..43e296b1 --- /dev/null +++ b/ark-rust-secp256k1/contrib/crates.sh @@ -0,0 +1,8 @@ +# No shebang, this file should not be executed. +# shellcheck disable=SC2148 +# +# disable verify unused vars, despite the fact that they are used when sourced +# shellcheck disable=SC2034 + +# Dot for single crate in workspace to test. +CRATES=(".") diff --git a/ark-rust-secp256k1/contrib/extra_tests.sh b/ark-rust-secp256k1/contrib/extra_tests.sh new file mode 100755 index 00000000..909d9c25 --- /dev/null +++ b/ark-rust-secp256k1/contrib/extra_tests.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash + +set -ex + +REPO_DIR=$(git rev-parse --show-toplevel) + +# Make all cargo invocations verbose. +export CARGO_TERM_VERBOSE=true + +# Set to false to turn off verbose output. +flag_verbose=true + +# Use the current `Cargo.lock` file without updating it. +cargo="cargo --locked" + +main() { + source_test_vars # Get feature list. + local features="$FEATURES_WITH_STD" + + RUSTFLAGS='--cfg=secp256k1_fuzz' RUSTDOCFLAGS='--cfg=secp256k1_fuzz' $cargo test --locked --all + RUSTFLAGS='--cfg=secp256k1_fuzz' RUSTDOCFLAGS='--cfg=secp256k1_fuzz' $cargo test --locked --all --features="$features" + + $cargo test --all --features="rand serde" +} + +# ShellCheck can't follow non-constant source, `test_vars_script` is correct. +# shellcheck disable=SC1090 +source_test_vars() { + local test_vars_script="$REPO_DIR/contrib/test_vars.sh" + + verbose_say "Sourcing $test_vars_script" + + if [ -e "$test_vars_script" ]; then + # Set crate specific variables. + . "$test_vars_script" + else + err "Missing $test_vars_script" + fi +} + +say() { + echo "extra_tests: $1" +} + +verbose_say() { + if [ "$flag_verbose" = true ]; then + say "$1" + fi +} + +err() { + echo "$1" >&2 + exit 1 +} + +# +# Main script +# +main "$@" +exit 0 diff --git a/ark-rust-secp256k1/contrib/no-std.sh b/ark-rust-secp256k1/contrib/no-std.sh new file mode 100755 index 00000000..c896bd89 --- /dev/null +++ b/ark-rust-secp256k1/contrib/no-std.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# +# Run no-std tests, requires nightly toolchain. + +set -euox pipefail + +main() { + need_nightly + check_required_commands + + pushd no_std_test > /dev/null + + xargo run --release --target=x86_64-unknown-linux-gnu | grep -q "Verified Successfully" + xargo run --release --target=x86_64-unknown-linux-gnu --features=alloc | grep -q "Verified alloc Successfully" + + popd +} + +# Check all the commands we use are present in the current environment. +check_required_commands() { + need_cmd xargo +} + +need_cmd() { + if ! command -v "$1" > /dev/null 2>&1 + then err "need '$1' (command not found)" + fi +} + +err() { + echo "$1" >&2 + exit 1 +} + +need_nightly() { + cargo_ver=$(cargo --version) + if echo "$cargo_ver" | grep -q -v nightly; then + err "Need a nightly compiler; have $(cargo --version)" + fi +} + +# +# Main script +# +main "$@" +exit 0 diff --git a/ark-rust-secp256k1/contrib/sanitizer.sh b/ark-rust-secp256k1/contrib/sanitizer.sh new file mode 100755 index 00000000..86e3c69b --- /dev/null +++ b/ark-rust-secp256k1/contrib/sanitizer.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# +# Run the Address/Memory Sanitizer tests. + +set -euox pipefail + +REPO_DIR=$(git rev-parse --show-toplevel) + +# Set to true to enable verbose output. +flag_verbose=false + +main() { + source_test_vars # Get feature list. + local features="$FEATURES_WITH_STD" + + clang --version + cargo clean + + CC='clang -fsanitize=address -fno-omit-frame-pointer' \ + RUSTFLAGS='-Zsanitizer=address -Clinker=clang -Cforce-frame-pointers=yes' \ + ASAN_OPTIONS='detect_leaks=1 detect_invalid_pointer_pairs=1 detect_stack_use_after_return=1' \ + cargo test --lib --all --features="$features" -Zbuild-std --target x86_64-unknown-linux-gnu + cargo clean + + # The -Cllvm-args=-msan-eager-checks=0 flag was added to overcome this issue: + # https://github.com/rust-bitcoin/rust-secp256k1/pull/573#issuecomment-1399465995 + CC='clang -fsanitize=memory -fno-omit-frame-pointer' \ + RUSTFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins -Cforce-frame-pointers=yes -Cllvm-args=-msan-eager-checks=0' \ + cargo test --lib --all --features="$features" -Zbuild-std --target x86_64-unknown-linux-gnu +} + +# ShellCheck can't follow non-constant source, `test_vars_script` is correct. +# shellcheck disable=SC1090 +source_test_vars() { + local test_vars_script="$REPO_DIR/contrib/test_vars.sh" + + verbose_say "Sourcing $test_vars_script" + + if [ -e "$test_vars_script" ]; then + # Set crate specific variables. + . "$test_vars_script" + else + err "Missing $test_vars_script" + fi +} + +say() { + echo "extra_tests: $1" +} + +verbose_say() { + if [ "$flag_verbose" = true ]; then + say "$1" + fi +} + +err() { + echo "$1" >&2 + exit 1 +} + +# +# Main script +# +main "$@" +exit 0 diff --git a/ark-rust-secp256k1/contrib/test_vars.sh b/ark-rust-secp256k1/contrib/test_vars.sh new file mode 100644 index 00000000..0bbc175a --- /dev/null +++ b/ark-rust-secp256k1/contrib/test_vars.sh @@ -0,0 +1,14 @@ +# No shebang, this file should not be executed. +# shellcheck disable=SC2148 +# +# disable verify unused vars, despite the fact that they are used when sourced +# shellcheck disable=SC2034 + +# Test all these features with "std" enabled. +FEATURES_WITH_STD="hashes global-context global-context-less-secure lowmemory rand recovery serde" + +# Test all these features without "std" enabled. +FEATURES_WITHOUT_STD="hashes global-context global-context-less-secure lowmemory rand recovery serde alloc" + +# Run these examples. +EXAMPLES="sign_verify:hashes,std sign_verify_recovery:hashes,std,recovery generate_keys:rand,std" diff --git a/ark-rust-secp256k1/contrib/update-lock-files.sh b/ark-rust-secp256k1/contrib/update-lock-files.sh new file mode 100755 index 00000000..02ba1f7c --- /dev/null +++ b/ark-rust-secp256k1/contrib/update-lock-files.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# +# Update the minimal/recent lock file + +set -euo pipefail + +for file in Cargo-minimal.lock Cargo-recent.lock; do + cp --force "$file" Cargo.lock + cargo check + cp --force Cargo.lock "$file" +done diff --git a/ark-rust-secp256k1/contrib/wasm.sh b/ark-rust-secp256k1/contrib/wasm.sh new file mode 100755 index 00000000..3d8bd8b9 --- /dev/null +++ b/ark-rust-secp256k1/contrib/wasm.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# +# Run the WASM tests. +# +# The wasm-pack command does not correctly pass args to cargo so we cannot use --locked and test +# with per-commited lockfiles (recent/minimal). Just run the WASM tests from here instead. + +set -euox pipefail + +clang --version +CARGO_TARGET_DIR=wasm cargo install --force wasm-pack +printf '\n[lib]\ncrate-type = ["cdylib", "rlib"]\n' >> Cargo.toml +CC=clang wasm-pack build +CC=clang wasm-pack test --node diff --git a/ark-rust-secp256k1/justfile b/ark-rust-secp256k1/justfile new file mode 100644 index 00000000..81a770d3 --- /dev/null +++ b/ark-rust-secp256k1/justfile @@ -0,0 +1,38 @@ +default: + @just --list + +# Cargo build everything. +build: + cargo build --workspace --all-targets --all-features + +# Cargo check everything. +check: + cargo check --workspace --all-targets --all-features + +# Lint everything. +lint: + cargo +$(cat ./nightly-version) clippy --workspace --all-targets --all-features -- --deny warnings + +# Run cargo fmt. +fmt: + cargo +$(cat ./nightly-version) fmt --all + +# Check the formatting. +format: + cargo +$(cat ./nightly-version) fmt --all --check + +# Quick and dirty CI useful for pre-push checks. +sane: lint + cargo test --quiet --workspace --all-targets --no-default-features > /dev/null || exit 1 + cargo test --quiet --workspace --all-targets > /dev/null || exit 1 + cargo test --quiet --workspace --all-targets --all-features > /dev/null || exit 1 + + # doctests don't get run from workspace root with `cargo test`. + cargo test --quiet --workspace --doc || exit 1 + + # Make an attempt to catch feature gate problems in doctests + cargo test --doc --no-default-features > /dev/null || exit 1 + +# Update the recent and minimal lock files. +update-lock-files: + ./contrib/update-lock-files.sh diff --git a/ark-rust-secp256k1/nightly-version b/ark-rust-secp256k1/nightly-version new file mode 100644 index 00000000..c33b8d13 --- /dev/null +++ b/ark-rust-secp256k1/nightly-version @@ -0,0 +1 @@ +nightly-2024-08-04 diff --git a/ark-rust-secp256k1/rustfmt.toml b/ark-rust-secp256k1/rustfmt.toml new file mode 100644 index 00000000..47e9866c --- /dev/null +++ b/ark-rust-secp256k1/rustfmt.toml @@ -0,0 +1,81 @@ +# Eventually this shoud be: ignore = [] +ignore = [ + "secp256k1-sys" +] + +hard_tabs = false +tab_spaces = 4 +newline_style = "Auto" +indent_style = "Block" + +max_width = 100 # This is number of characters. +# `use_small_heuristics` is ignored if the granular width config values are explicitly set. +use_small_heuristics = "Max" # "Max" == All granular width settings same as `max_width`. +# # Granular width configuration settings. These are percentages of `max_width`. +# fn_call_width = 60 +# attr_fn_like_width = 70 +# struct_lit_width = 18 +# struct_variant_width = 35 +# array_width = 60 +# chain_width = 60 +# single_line_if_else_max_width = 50 + +wrap_comments = false +format_code_in_doc_comments = false +comment_width = 100 # Default 80 +normalize_comments = false +normalize_doc_attributes = false +format_strings = false +format_macro_matchers = false +format_macro_bodies = true +hex_literal_case = "Preserve" +empty_item_single_line = true +struct_lit_single_line = true +fn_single_line = true # Default false +where_single_line = false +imports_indent = "Block" +imports_layout = "Mixed" +imports_granularity = "Module" # Default "Preserve" +group_imports = "StdExternalCrate" # Default "Preserve" +reorder_imports = true +reorder_modules = true +reorder_impl_items = false +type_punctuation_density = "Wide" +space_before_colon = false +space_after_colon = true +spaces_around_ranges = false +binop_separator = "Front" +remove_nested_parens = true +combine_control_expr = true +overflow_delimited_expr = false +struct_field_align_threshold = 0 +enum_discrim_align_threshold = 0 +match_arm_blocks = false # Default true +match_arm_leading_pipes = "Never" +force_multiline_blocks = false +fn_params_layout = "Tall" +brace_style = "SameLineWhere" +control_brace_style = "AlwaysSameLine" +trailing_semicolon = true +trailing_comma = "Vertical" +match_block_trailing_comma = false +blank_lines_upper_bound = 1 +blank_lines_lower_bound = 0 +edition = "2018" +version = "One" +inline_attribute_width = 0 +format_generated_files = true +merge_derives = true +use_try_shorthand = false +use_field_init_shorthand = false +force_explicit_abi = true +condense_wildcard_suffixes = false +color = "Auto" +unstable_features = false +disable_all_formatting = false +skip_children = false +show_parse_errors = true +error_on_line_overflow = false +error_on_unformatted = false +emit_mode = "Files" +make_backup = false diff --git a/ark-rust-secp256k1/secp256k1-sys/CHANGELOG.md b/ark-rust-secp256k1/secp256k1-sys/CHANGELOG.md new file mode 100644 index 00000000..d2ec7042 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/CHANGELOG.md @@ -0,0 +1,55 @@ +# 0.10.0 - 2024-03-28 + +* Bump MSRV to Rust `v1.56.1` [#693](https://github.com/rust-bitcoin/rust-secp256k1/pull/693) +* Vendor `secp256k1 v0.4.1` [#688](https://github.com/rust-bitcoin/rust-secp256k1/pull/688) + +# 0.9.2 - 2023-12-18 + +* Fix incorrect FFI binding for `secp256k1_pubkey_combine` + +# 0.9.1 - 2023-12-07 + +* Patch out any instances of printf in upstream [#663](https://github.com/rust-bitcoin/rust-secp256k1/pull/663) + +# 0.9.0 - 2023-10-23 + +* Add bindings to the ElligatorSwift implementation [#627](https://github.com/rust-bitcoin/rust-secp256k1/pull/627) +* Update vendored lib secp256k1 to v0.4.0 [#653](https://github.com/rust-bitcoin/rust-secp256k1/pull/653) +* Bump MSRV to 1.48 [#595](https://github.com/rust-bitcoin/rust-secp256k1/pull/595) + +# 0.8.1 - 2023-03-16 + +* [Implement `insecure-erase`](https://github.com/rust-bitcoin/rust-secp256k1/pull/582). + +# 0.8.0 - 2202-12-19 + +* Update libsecp25k1 to v0.2.0 + +# 0.7.0 - 2022-12-01 + +* [Make comparison functions stable across library versions](https://github.com/rust-bitcoin/rust-secp256k1/pull/518) +* Add public methods `cmp_fast_unstable` and `eq_fast_unstable` for types that contain an inner array (see PR linked above). + +# 0.6.0 - 2022-06-21 + +* [Bump MSRV to 1.41](https://github.com/rust-bitcoin/rust-secp256k1/pull/331) +* [Re-implement `Ord` on `PublicKey` using upstream ordering function](https://github.com/rust-bitcoin/rust-secp256k1/pull/449) + +# 0.5.1 - 2022-04-30 + +* [Fix WASM build](https://github.com/rust-bitcoin/rust-secp256k1/pull/421) + +# 0.3.0 - 2020-08-27 + +* **Update MSRV to 1.29.0** + +# 0.2.0 - 2020-08-26 + +* Update upstream to `670cdd3f8be25f81472b2d16dcd228b0d24a5c45` +* [Add missing return](https://github.com/rust-bitcoin/rust-secp256k1/pull/195) `c_int` to `NonceFn` +* [Got wasm support working again](https://github.com/rust-bitcoin/rust-secp256k1/pull/208) +* Removed `cc` restriction, rustc 1.22 support [now requires some downstream effort](https://github.com/rust-bitcoin/rust-secp256k1/pull/204) +* [Exposed a reference to the underlying byte array](https://github.com/rust-bitcoin/rust-secp256k1/pull/219) for all byte-array-wrapping types +* Allow all-zeroes `Message` [to be constructed](https://github.com/rust-bitcoin/rust-secp256k1/pull/207) +* Expose `secp256k1_ec_pubkey_negate` [from upstream](https://github.com/rust-bitcoin/rust-secp256k1/pull/222) + diff --git a/ark-rust-secp256k1/secp256k1-sys/Cargo.toml b/ark-rust-secp256k1/secp256k1-sys/Cargo.toml new file mode 100644 index 00000000..7a5e98b6 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "secp256k1-sys" +version = "0.11.0" +authors = [ "Dawid Ciężarkiewicz ", + "Andrew Poelstra ", + "Steven Roose " ] +license = "CC0-1.0" +homepage = "https://github.com/rust-bitcoin/rust-secp256k1/" +repository = "https://github.com/rust-bitcoin/rust-secp256k1/" +documentation = "https://docs.rs/secp256k1-sys/" +description = "FFI for Pieter Wuille's `libsecp256k1` library." +keywords = [ "secp256k1", "libsecp256k1", "ffi" ] +readme = "README.md" +build = "build.rs" +links = "rustsecp256k1_v0_11" +edition = "2021" +rust-version = "1.63.0" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[build-dependencies] +cc = "1.0.28" + +[dev-dependencies] +libc = "0.2" + +[features] +default = ["std"] +recovery = [] +lowmemory = [] +std = ["alloc"] +alloc = [] + +[lints.rust] +unexpected_cfgs = { level = "deny", check-cfg = ['cfg(bench)', 'cfg(secp256k1_fuzz)', 'cfg(rust_secp_no_symbol_renaming)'] } diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/LICENSE b/ark-rust-secp256k1/secp256k1-sys/LICENSE similarity index 100% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/LICENSE rename to ark-rust-secp256k1/secp256k1-sys/LICENSE diff --git a/ark-rust-secp256k1/secp256k1-sys/README.md b/ark-rust-secp256k1/secp256k1-sys/README.md new file mode 100644 index 00000000..5d4649b7 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/README.md @@ -0,0 +1,52 @@ +
+

Rust secp256k1-sys

+ +

+ Crate Info + CC0 1.0 Universal Licensed + API Docs + Rustc Version 1.56.1+ +

+
+ +Provides low-level bindings to the C FFI exposed by [libsecp256k1](https://github.com/bitcoin-core/secp256k1). + +## Vendoring + +The default build process is to build using the vendored `libsecp256k1` sources in the `depend` +directory. These sources are prefixed with a special rust-secp256k1-sys-specific prefix +`rustsecp256k1_v1_2_3_`. + +This prefix ensures that no symbol collision can happen: + +- When a Rust project has two different versions of `rust-secp256k1` in its depepdency tree, or +- When `rust-secp256k1` is used for building a static library in a context where existing + `libsecp256k1` symbols are already linked. + +To update the vendored sources, use the `vendor-libsecp.sh` script: `./vendor-libsecp.sh ` + +- Where `` is the git revision of `libsecp256k1` to checkout. If you do not specify a revision, + the script will simply clone the repo and use whatever revision the default branch is pointing to. + +## Linking to external symbols + +**Danger: doing this incorrectly may have catastrophic consequences!** + +This is mainly intended for applications consisting of various programming languages that intend to +link the same library to save space, or bundles of multiple binaries coming from the same source. Do +not use this to link to a random secp256k1 library you found in your OS! If you are packaging +software that depends on `rust-secp256k1`, using this flag to link to another package, make sure you +stay within the binary compatibility guarantees of that package. For example, in Debian if you need +`libsecp256k1 1.2.3`, make sure your package requires a version strictly`>= 1.2.3 << 1.2.4`. Note +also that unless you're packaging the library for an official repository you should prefix your +package and the library with a string specific to you. E.g. if you have a set of packages called +`my-awesome-packages` you should package `libsecp256k1` as `libmy-awesome-packages-secp256k1` and +depend on that library/package name from your application. + +If you want to compile this library without using the bundled symbols (which may be required for +integration into other build systems), you can do so by adding `--cfg=rust_secp_no_symbol_renaming'` +to your `RUSTFLAGS` variable. + +## Minimum Supported Rust Version + +This library should always compile with any combination of features on **Rust 1.56.1**. diff --git a/ark-rust-secp256k1/secp256k1-sys/build.rs b/ark-rust-secp256k1/secp256k1-sys/build.rs new file mode 100644 index 00000000..35d7c34c --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/build.rs @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! # Build script + +#![allow(warnings)] +// Coding conventions +#![deny(non_upper_case_globals)] +#![deny(non_camel_case_types)] +#![deny(non_snake_case)] +#![deny(unused_mut)] +#![warn(missing_docs)] + +extern crate cc; + +use std::env; + +fn main() { + // Actual build + let mut base_config = cc::Build::new(); + base_config + .include("depend/secp256k1/") + .include("depend/secp256k1/include") + .include("depend/secp256k1/src") + .flag_if_supported("-Wno-unused-function") // some ecmult stuff is defined but not used upstream + .flag_if_supported("-Wno-unused-parameter") // patching out printf causes this warning + .define("SECP256K1_API", Some("")) + .define("ENABLE_MODULE_ECDH", Some("1")) + .define("ENABLE_MODULE_SCHNORRSIG", Some("1")) + .define("ENABLE_MODULE_EXTRAKEYS", Some("1")) + .define("ENABLE_MODULE_ELLSWIFT", Some("1")) + .define("ENABLE_MODULE_MUSIG", Some("1")) + // upstream sometimes introduces calls to printf, which we cannot compile + // with WASM due to its lack of libc. printf is never necessary and we can + // just #define it away. + .define("printf(...)", Some("")); + + if cfg!(feature = "lowmemory") { + base_config.define("ECMULT_WINDOW_SIZE", Some("4")); // A low-enough value to consume negligible memory + base_config.define("ECMULT_GEN_PREC_BITS", Some("2")); + } else { + base_config.define("ECMULT_GEN_PREC_BITS", Some("4")); + base_config.define("ECMULT_WINDOW_SIZE", Some("15")); // This is the default in the configure file (`auto`) + } + base_config.define("USE_EXTERNAL_DEFAULT_CALLBACKS", Some("1")); + #[cfg(feature = "recovery")] + base_config.define("ENABLE_MODULE_RECOVERY", Some("1")); + + // WASM headers and size/align defines. + if env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "wasm32" { + base_config.include("wasm/wasm-sysroot").file("wasm/wasm.c"); + } + + // secp256k1 + base_config + .file("depend/secp256k1/contrib/lax_der_parsing.c") + .file("depend/secp256k1/src/precomputed_ecmult_gen.c") + .file("depend/secp256k1/src/precomputed_ecmult.c") + .file("depend/secp256k1/src/secp256k1.c"); + + if base_config.try_compile("libsecp256k1.a").is_err() { + // Some embedded platforms may not have, eg, string.h available, so if the build fails + // simply try again with the wasm sysroot (but without the wasm type sizes) in the hopes + // that it works. + base_config.include("wasm/wasm-sysroot"); + base_config.compile("libsecp256k1.a"); + } +} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/check_uint128_t.c b/ark-rust-secp256k1/secp256k1-sys/depend/check_uint128_t.c similarity index 100% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/check_uint128_t.c rename to ark-rust-secp256k1/secp256k1-sys/depend/check_uint128_t.c diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/lax_der_parsing.c.patch b/ark-rust-secp256k1/secp256k1-sys/depend/lax_der_parsing.c.patch new file mode 100644 index 00000000..59b23e0d --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/lax_der_parsing.c.patch @@ -0,0 +1,6 @@ +10c10,12 +< +--- +> extern int secp256k1_ecdsa_signature_parse_compact( +> const secp256k1_context *ctx, +> secp256k1_ecdsa_signature *sig, const unsigned char *input64); diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/scratch.h.patch b/ark-rust-secp256k1/secp256k1-sys/depend/scratch.h.patch new file mode 100644 index 00000000..10e28877 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/scratch.h.patch @@ -0,0 +1,5 @@ +26,29d25 +< static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size); +< +< static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch); +< diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/scratch_impl.h.patch b/ark-rust-secp256k1/secp256k1-sys/depend/scratch_impl.h.patch similarity index 100% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/scratch_impl.h.patch rename to ark-rust-secp256k1/secp256k1-sys/depend/scratch_impl.h.patch index 0afb47be..c956a833 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/scratch_impl.h.patch +++ b/ark-rust-secp256k1/secp256k1-sys/depend/scratch_impl.h.patch @@ -14,11 +14,11 @@ < < static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) { < if (scratch != NULL) { -< VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */ < if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { < secp256k1_callback_call(error_callback, "invalid scratch space"); < return; < } +< VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */ < memset(scratch->magic, 0, sizeof(scratch->magic)); < free(scratch); < } diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1-HEAD-revision.txt b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1-HEAD-revision.txt similarity index 59% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1-HEAD-revision.txt rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1-HEAD-revision.txt index 076dc9cd..ecdc0e55 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1-HEAD-revision.txt +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1-HEAD-revision.txt @@ -1,2 +1,2 @@ # This file was automatically created by vendor-libsecp.sh -1d256089004a19bdbead7c5676e52c8e07b09fce +0cdc758a56360bf58a851fe91085a327ec97685a diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1.c.patch b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1.c.patch similarity index 67% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1.c.patch rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1.c.patch index c39705a0..c1da0c44 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1.c.patch +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1.c.patch @@ -1,4 +1,4 @@ -139,149d138 +140,150d139 < secp256k1_context* secp256k1_context_create(unsigned int flags) { < size_t const prealloc_size = secp256k1_context_preallocated_size(flags); < secp256k1_context* ctx = (secp256k1_context*)checked_malloc(&default_error_callback, prealloc_size); @@ -10,34 +10,41 @@ < return ctx; < } < -164,174d152 +162,174d150 < secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { < secp256k1_context* ret; < size_t prealloc_size; < < VERIFY_CHECK(ctx != NULL); +< ARG_CHECK(secp256k1_context_is_proper(ctx)); +< < prealloc_size = secp256k1_context_preallocated_clone_size(ctx); < ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, prealloc_size); < ret = secp256k1_context_preallocated_clone(ctx, ret); < return ret; < } < -183,189d160 +186,197d161 < void secp256k1_context_destroy(secp256k1_context* ctx) { -< if (ctx != NULL) { -< secp256k1_context_preallocated_destroy(ctx); -< free(ctx); +< ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx)); +< +< /* Defined as noop */ +< if (ctx == NULL) { +< return; < } +< +< secp256k1_context_preallocated_destroy(ctx); +< free(ctx); < } < -206,215d176 +223,232d185 < } < -< secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) { +< static secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) { < VERIFY_CHECK(ctx != NULL); < return secp256k1_scratch_create(&ctx->error_callback, max_size); < } < -< void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) { +< static void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) { < VERIFY_CHECK(ctx != NULL); < secp256k1_scratch_destroy(&ctx->error_callback, scratch); diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1.h.patch b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1.h.patch new file mode 100644 index 00000000..084cc89f --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1.h.patch @@ -0,0 +1,24 @@ +236d235 +< SECP256K1_API const secp256k1_context *secp256k1_context_static; +239,240d237 +< SECP256K1_API const secp256k1_context *secp256k1_context_no_precomp +< SECP256K1_DEPRECATED("Use secp256k1_context_static instead"); +286,289d282 +< SECP256K1_API secp256k1_context *secp256k1_context_create( +< unsigned int flags +< ) SECP256K1_WARN_UNUSED_RESULT; +< +302,305d294 +< SECP256K1_API secp256k1_context *secp256k1_context_clone( +< const secp256k1_context *ctx +< ) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; +< +320,323d308 +< SECP256K1_API void secp256k1_context_destroy( +< secp256k1_context *ctx +< ) SECP256K1_ARG_NONNULL(1); +< +636d610 +< SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; +639d612 +< SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_default; diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.cirrus.yml b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.cirrus.yml new file mode 100644 index 00000000..81a4f043 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.cirrus.yml @@ -0,0 +1,101 @@ +env: + ### cirrus config + CIRRUS_CLONE_DEPTH: 1 + ### compiler options + HOST: + WRAPPER_CMD: + # Specific warnings can be disabled with -Wno-error=foo. + # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual. + WERROR_CFLAGS: -Werror -pedantic-errors + MAKEFLAGS: -j4 + BUILD: check + ### secp256k1 config + ECMULTWINDOW: 15 + ECMULTGENKB: 22 + ASM: no + WIDEMUL: auto + WITH_VALGRIND: yes + EXTRAFLAGS: + ### secp256k1 modules + EXPERIMENTAL: no + ECDH: no + RECOVERY: no + EXTRAKEYS: no + SCHNORRSIG: no + MUSIG: no + ELLSWIFT: no + ### test options + SECP256K1_TEST_ITERS: 64 + BENCH: yes + SECP256K1_BENCH_ITERS: 2 + CTIMETESTS: yes + # Compile and run the tests + EXAMPLES: yes + +cat_logs_snippet: &CAT_LOGS + always: + cat_tests_log_script: + - cat tests.log || true + cat_noverify_tests_log_script: + - cat noverify_tests.log || true + cat_exhaustive_tests_log_script: + - cat exhaustive_tests.log || true + cat_ctime_tests_log_script: + - cat ctime_tests.log || true + cat_bench_log_script: + - cat bench.log || true + cat_config_log_script: + - cat config.log || true + cat_test_env_script: + - cat test_env.log || true + cat_ci_env_script: + - env + +linux_arm64_container_snippet: &LINUX_ARM64_CONTAINER + env_script: + - env | tee /tmp/env + build_script: + - DOCKER_BUILDKIT=1 docker build --file "ci/linux-debian.Dockerfile" --tag="ci_secp256k1_arm" + - docker image prune --force # Cleanup stale layers + test_script: + - docker run --rm --mount "type=bind,src=./,dst=/ci_secp256k1" --env-file /tmp/env --replace --name "ci_secp256k1_arm" "ci_secp256k1_arm" bash -c "cd /ci_secp256k1/ && ./ci/ci.sh" + +task: + name: "ARM64: Linux (Debian stable)" + persistent_worker: + labels: + type: arm64 + env: + ECDH: yes + RECOVERY: yes + EXTRAKEYS: yes + SCHNORRSIG: yes + MUSIG: yes + ELLSWIFT: yes + matrix: + # Currently only gcc-snapshot, the other compilers are tested on GHA with QEMU + - env: { CC: 'gcc-snapshot' } + << : *LINUX_ARM64_CONTAINER + << : *CAT_LOGS + +task: + name: "ARM64: Linux (Debian stable), Valgrind" + persistent_worker: + labels: + type: arm64 + env: + ECDH: yes + RECOVERY: yes + EXTRAKEYS: yes + SCHNORRSIG: yes + MUSIG: yes + ELLSWIFT: yes + WRAPPER_CMD: 'valgrind --error-exitcode=42' + SECP256K1_TEST_ITERS: 2 + matrix: + - env: { CC: 'gcc' } + - env: { CC: 'clang' } + - env: { CC: 'gcc-snapshot' } + - env: { CC: 'clang-snapshot' } + << : *LINUX_ARM64_CONTAINER + << : *CAT_LOGS diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/.gitattributes b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.gitattributes similarity index 100% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/.gitattributes rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.gitattributes diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.github/actions/install-homebrew-valgrind/action.yml b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.github/actions/install-homebrew-valgrind/action.yml new file mode 100644 index 00000000..ce10eb26 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.github/actions/install-homebrew-valgrind/action.yml @@ -0,0 +1,33 @@ +name: "Install Valgrind" +description: "Install Homebrew's Valgrind package and cache it." +runs: + using: "composite" + steps: + - run: | + brew tap LouisBrunner/valgrind + brew fetch --HEAD LouisBrunner/valgrind/valgrind + echo "CI_HOMEBREW_CELLAR_VALGRIND=$(brew --cellar valgrind)" >> "$GITHUB_ENV" + shell: bash + + - run: | + sw_vers > valgrind_fingerprint + brew --version >> valgrind_fingerprint + git -C "$(brew --cache)/valgrind--git" rev-parse HEAD >> valgrind_fingerprint + cat valgrind_fingerprint + shell: bash + + - uses: actions/cache@v4 + id: cache + with: + path: ${{ env.CI_HOMEBREW_CELLAR_VALGRIND }} + key: ${{ github.job }}-valgrind-${{ hashFiles('valgrind_fingerprint') }} + + - if: steps.cache.outputs.cache-hit != 'true' + run: | + brew install --HEAD LouisBrunner/valgrind/valgrind + shell: bash + + - if: steps.cache.outputs.cache-hit == 'true' + run: | + brew link valgrind + shell: bash diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.github/actions/run-in-docker-action/action.yml b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.github/actions/run-in-docker-action/action.yml new file mode 100644 index 00000000..74933686 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.github/actions/run-in-docker-action/action.yml @@ -0,0 +1,54 @@ +name: 'Run in Docker with environment' +description: 'Run a command in a Docker container, while passing explicitly set environment variables into the container.' +inputs: + dockerfile: + description: 'A Dockerfile that defines an image' + required: true + tag: + description: 'A tag of an image' + required: true + command: + description: 'A command to run in a container' + required: false + default: ./ci/ci.sh +runs: + using: "composite" + steps: + - uses: docker/setup-buildx-action@v3 + + - uses: docker/build-push-action@v5 + id: main_builder + continue-on-error: true + with: + context: . + file: ${{ inputs.dockerfile }} + tags: ${{ inputs.tag }} + load: true + cache-from: type=gha + + - uses: docker/build-push-action@v5 + id: retry_builder + if: steps.main_builder.outcome == 'failure' + with: + context: . + file: ${{ inputs.dockerfile }} + tags: ${{ inputs.tag }} + load: true + cache-from: type=gha + + - # Workaround for https://github.com/google/sanitizers/issues/1614 . + # The underlying issue has been fixed in clang 18.1.3. + run: sudo sysctl -w vm.mmap_rnd_bits=28 + shell: bash + + - # Tell Docker to pass environment variables in `env` into the container. + run: > + docker run \ + $(echo '${{ toJSON(env) }}' | jq -r 'keys[] | "--env \(.) "') \ + --volume ${{ github.workspace }}:${{ github.workspace }} \ + --workdir ${{ github.workspace }} \ + ${{ inputs.tag }} bash -c " + git config --global --add safe.directory ${{ github.workspace }} + ${{ inputs.command }} + " + shell: bash diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.github/workflows/ci.yml b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.github/workflows/ci.yml new file mode 100644 index 00000000..54b2fab1 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.github/workflows/ci.yml @@ -0,0 +1,890 @@ +name: CI +on: + pull_request: + push: + branches: + - '**' + tags-ignore: + - '**' + +concurrency: + group: ${{ github.event_name != 'pull_request' && github.run_id || github.ref }} + cancel-in-progress: true + +env: + ### compiler options + HOST: + WRAPPER_CMD: + # Specific warnings can be disabled with -Wno-error=foo. + # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual. + WERROR_CFLAGS: '-Werror -pedantic-errors' + MAKEFLAGS: '-j4' + BUILD: 'check' + ### secp256k1 config + ECMULTWINDOW: 15 + ECMULTGENKB: 86 + ASM: 'no' + WIDEMUL: 'auto' + WITH_VALGRIND: 'yes' + EXTRAFLAGS: + ### secp256k1 modules + EXPERIMENTAL: 'no' + ECDH: 'no' + RECOVERY: 'no' + EXTRAKEYS: 'no' + SCHNORRSIG: 'no' + MUSIG: 'no' + ELLSWIFT: 'no' + ### test options + SECP256K1_TEST_ITERS: 64 + BENCH: 'yes' + SECP256K1_BENCH_ITERS: 2 + CTIMETESTS: 'yes' + # Compile and run the examples. + EXAMPLES: 'yes' + +jobs: + docker_cache: + name: "Build Docker image" + runs-on: ubuntu-latest + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + # See: https://github.com/moby/buildkit/issues/3969. + driver-opts: | + network=host + + - name: Build container + uses: docker/build-push-action@v5 + with: + file: ./ci/linux-debian.Dockerfile + tags: linux-debian-image + cache-from: type=gha + cache-to: type=gha,mode=min + + linux_debian: + name: "x86_64: Linux (Debian stable)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { WIDEMUL: 'int64', RECOVERY: 'yes' } + - env_vars: { WIDEMUL: 'int64', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } + - env_vars: { WIDEMUL: 'int128' } + - env_vars: { WIDEMUL: 'int128_struct', ELLSWIFT: 'yes' } + - env_vars: { WIDEMUL: 'int128', RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } + - env_vars: { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes' } + - env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' } + - env_vars: { RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes' } + - env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', CPPFLAGS: '-DVERIFY' } + - env_vars: { BUILD: 'distcheck', WITH_VALGRIND: 'no', CTIMETESTS: 'no', BENCH: 'no' } + - env_vars: { CPPFLAGS: '-DDETERMINISTIC' } + - env_vars: { CFLAGS: '-O0', CTIMETESTS: 'no' } + - env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } + - env_vars: { ECMULTGENKB: 2, ECMULTWINDOW: 2 } + - env_vars: { ECMULTGENKB: 86, ECMULTWINDOW: 4 } + cc: + - 'gcc' + - 'clang' + - 'gcc-snapshot' + - 'clang-snapshot' + + env: + CC: ${{ matrix.cc }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + i686_debian: + name: "i686: Linux (Debian stable)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + cc: + - 'i686-linux-gnu-gcc' + - 'clang --target=i686-pc-linux-gnu -isystem /usr/i686-linux-gnu/include' + + env: + HOST: 'i686-linux-gnu' + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CC: ${{ matrix.cc }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + s390x_debian: + name: "s390x (big-endian): Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'qemu-s390x' + SECP256K1_TEST_ITERS: 16 + HOST: 's390x-linux-gnu' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + arm32_debian: + name: "ARM32: Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: {} + - env_vars: { EXPERIMENTAL: 'yes', ASM: 'arm32' } + + env: + WRAPPER_CMD: 'qemu-arm' + SECP256K1_TEST_ITERS: 16 + HOST: 'arm-linux-gnueabihf' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + arm64_debian: + name: "ARM64: Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'qemu-aarch64' + SECP256K1_TEST_ITERS: 16 + HOST: 'aarch64-linux-gnu' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { } # gcc + - env_vars: # clang + CC: 'clang --target=aarch64-linux-gnu' + - env_vars: # clang-snapshot + CC: 'clang-snapshot --target=aarch64-linux-gnu' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + ppc64le_debian: + name: "ppc64le: Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'qemu-ppc64le' + SECP256K1_TEST_ITERS: 16 + HOST: 'powerpc64le-linux-gnu' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + valgrind_debian: + name: "Valgrind (memcheck)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { CC: 'clang', ASM: 'auto' } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' } + - env_vars: { CC: 'clang', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 } + + env: + # The `--error-exitcode` is required to make the test fail if valgrind found errors, + # otherwise it will return 0 (https://www.valgrind.org/docs/manual/manual-core.html). + WRAPPER_CMD: 'valgrind --error-exitcode=42' + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + SECP256K1_TEST_ITERS: 2 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + sanitizers_debian: + name: "UBSan, ASan, LSan" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { CC: 'clang', ASM: 'auto' } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' } + - env_vars: { CC: 'clang', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 } + + env: + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + CFLAGS: '-fsanitize=undefined,address -g' + UBSAN_OPTIONS: 'print_stacktrace=1:halt_on_error=1' + ASAN_OPTIONS: 'strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1' + LSAN_OPTIONS: 'use_unaligned=1' + SECP256K1_TEST_ITERS: 32 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + msan_debian: + name: "MSan" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: + CTIMETESTS: 'yes' + CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g' + - env_vars: + ECMULTGENKB: 2 + ECMULTWINDOW: 2 + CTIMETESTS: 'yes' + CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g -O3' + - env_vars: + # -fsanitize-memory-param-retval is clang's default, but our build system disables it + # when ctime_tests when enabled. + CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -fsanitize-memory-param-retval -g' + CTIMETESTS: 'no' + + env: + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CC: 'clang' + SECP256K1_TEST_ITERS: 32 + ASM: 'no' + WITH_VALGRIND: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + mingw_debian: + name: ${{ matrix.configuration.job_name }} + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'wine' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + strategy: + fail-fast: false + matrix: + configuration: + - job_name: 'x86_64 (mingw32-w64): Windows (Debian stable, Wine)' + env_vars: + HOST: 'x86_64-w64-mingw32' + - job_name: 'i686 (mingw32-w64): Windows (Debian stable, Wine)' + env_vars: + HOST: 'i686-w64-mingw32' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + x86_64-macos-native: + name: "x86_64: macOS Ventura, Valgrind" + # See: https://github.com/actions/runner-images#available-images. + runs-on: macos-13 + + env: + CC: 'clang' + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_INSTALL_CLEANUP: 1 + + strategy: + fail-fast: false + matrix: + env_vars: + - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128_struct', ECMULTGENKB: 2, ECMULTWINDOW: 4 } + - { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY', CTIMETESTS: 'no' } + - BUILD: 'distcheck' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Homebrew packages + run: | + brew install --quiet automake libtool gcc + ln -s $(brew --prefix gcc)/bin/gcc-?? /usr/local/bin/gcc + + - name: Install and cache Valgrind + uses: ./.github/actions/install-homebrew-valgrind + + - name: CI script + env: ${{ matrix.env_vars }} + run: ./ci/ci.sh + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + arm64-macos-native: + name: "ARM64: macOS Sonoma" + # See: https://github.com/actions/runner-images#available-images. + runs-on: macos-14 + + env: + CC: 'clang' + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_INSTALL_CLEANUP: 1 + WITH_VALGRIND: 'no' + CTIMETESTS: 'no' + + strategy: + fail-fast: false + matrix: + env_vars: + - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128_struct', ECMULTGENPRECISION: 2, ECMULTWINDOW: 4 } + - { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY' } + - BUILD: 'distcheck' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Homebrew packages + run: | + brew install --quiet automake libtool gcc + ln -s $(brew --prefix gcc)/bin/gcc-?? /usr/local/bin/gcc + + - name: CI script + env: ${{ matrix.env_vars }} + run: ./ci/ci.sh + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + win64-native: + name: ${{ matrix.configuration.job_name }} + # See: https://github.com/actions/runner-images#available-images. + runs-on: windows-2022 + + strategy: + fail-fast: false + matrix: + configuration: + - job_name: 'x64 (MSVC): Windows (VS 2022, shared)' + cmake_options: '-A x64 -DBUILD_SHARED_LIBS=ON' + - job_name: 'x64 (MSVC): Windows (VS 2022, static)' + cmake_options: '-A x64 -DBUILD_SHARED_LIBS=OFF' + - job_name: 'x64 (MSVC): Windows (VS 2022, int128_struct)' + cmake_options: '-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct' + - job_name: 'x64 (MSVC): Windows (VS 2022, int128_struct with __(u)mulh)' + cmake_options: '-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct' + cpp_flags: '/DSECP256K1_MSVC_MULH_TEST_OVERRIDE' + - job_name: 'x86 (MSVC): Windows (VS 2022)' + cmake_options: '-A Win32' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Generate buildsystem + run: cmake -E env CFLAGS="/WX ${{ matrix.configuration.cpp_flags }}" cmake -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON ${{ matrix.configuration.cmake_options }} + + - name: Build + run: cmake --build build --config RelWithDebInfo -- /p:UseMultiToolTask=true /maxCpuCount + + - name: Binaries info + # Use the bash shell included with Git for Windows. + shell: bash + run: | + cd build/bin/RelWithDebInfo && file *tests.exe bench*.exe libsecp256k1-*.dll || true + + - name: Check + run: | + ctest -C RelWithDebInfo --test-dir build -j ([int]$env:NUMBER_OF_PROCESSORS + 1) + build\bin\RelWithDebInfo\bench_ecmult.exe + build\bin\RelWithDebInfo\bench_internal.exe + build\bin\RelWithDebInfo\bench.exe + + win64-native-headers: + name: "x64 (MSVC): C++ (public headers)" + # See: https://github.com/actions/runner-images#available-images. + runs-on: windows-2022 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Add cl.exe to PATH + uses: ilammy/msvc-dev-cmd@v1 + + - name: C++ (public headers) + run: | + cl.exe -c -WX -TP include/*.h + + cxx_fpermissive_debian: + name: "C++ -fpermissive (entire project)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + CC: 'g++' + CFLAGS: '-fpermissive -g' + CPPFLAGS: '-DSECP256K1_CPLUSPLUS_TEST_OVERRIDE' + WERROR_CFLAGS: + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + cxx_headers_debian: + name: "C++ (public headers)" + runs-on: ubuntu-latest + needs: docker_cache + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + command: | + g++ -Werror include/*.h + clang -Werror -x c++-header include/*.h + + sage: + name: "SageMath prover" + runs-on: ubuntu-latest + container: + image: sagemath/sagemath:latest + options: --user root + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + run: | + cd sage + sage prove_group_implementations.sage + + release: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - run: ./autogen.sh && ./configure --enable-dev-mode && make distcheck + + - name: Check installation with Autotools + env: + CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/install + run: | + ./autogen.sh && ./configure --prefix=${{ env.CI_INSTALL }} && make clean && make install && ls -RlAh ${{ env.CI_INSTALL }} + gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=${{ env.CI_INSTALL }}/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"${{ env.CI_INSTALL }}/lib" && ./ecdsa + + - name: Check installation with CMake + env: + CI_BUILD: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/build + CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/install + run: | + cmake -B ${{ env.CI_BUILD }} -DCMAKE_INSTALL_PREFIX=${{ env.CI_INSTALL }} && cmake --build ${{ env.CI_BUILD }} && cmake --install ${{ env.CI_BUILD }} && ls -RlAh ${{ env.CI_INSTALL }} + gcc -o ecdsa examples/ecdsa.c -I ${{ env.CI_INSTALL }}/include -L ${{ env.CI_INSTALL }}/lib*/ -l secp256k1 -Wl,-rpath,"${{ env.CI_INSTALL }}/lib",-rpath,"${{ env.CI_INSTALL }}/lib64" && ./ecdsa diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/.gitignore b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.gitignore similarity index 77% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/.gitignore rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.gitignore index 9be37772..bffba8cb 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/.gitignore +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/.gitignore @@ -1,26 +1,24 @@ bench -bench_bppp bench_ecmult -bench_generator -bench_rangeproof bench_internal -bench_whitelist +noverify_tests tests -example_musig exhaustive_tests precompute_ecmult_gen precompute_ecmult -valgrind_ctime_test +ctime_tests ecdh_example ecdsa_example schnorr_example +ellswift_example +musig_example *.exe *.so *.a *.csv -!.gitignore *.log *.trs +*.sage.py Makefile configure @@ -39,8 +37,6 @@ libtool *.lo *.o *~ -*.log -*.trs coverage/ coverage.html @@ -49,8 +45,6 @@ coverage.*.html *.gcno *.gcov -src/libsecp256k1-config.h -src/libsecp256k1-config.h.in build-aux/ar-lib build-aux/config.guess build-aux/config.sub @@ -65,8 +59,9 @@ build-aux/m4/ltversion.m4 build-aux/missing build-aux/compile build-aux/test-driver -src/stamp-h1 libsecp256k1.pc -contrib/gh-pr-create.sh -musig_example +### CMake +/CMakeUserPresets.json +# Default CMake build directory. +/build diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/CHANGELOG.md b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/CHANGELOG.md new file mode 100644 index 00000000..ee447c0c --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/CHANGELOG.md @@ -0,0 +1,174 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.6.0] - 2024-11-04 + +#### Added + - New module `musig` implements the MuSig2 multisignature scheme according to the [BIP 327 specification](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki). See: + - Header file `include/secp256k1_musig.h` which defines the new API. + - Document `doc/musig.md` for further notes on API usage. + - Usage example `examples/musig.c`. + - New CMake variable `SECP256K1_APPEND_LDFLAGS` for appending linker flags to the build command. + +#### Changed + - API functions now use a significantly more robust method to clear secrets from the stack before returning. However, secret clearing remains a best-effort security measure and cannot guarantee complete removal. + - Any type `secp256k1_foo` can now be forward-declared using `typedef struct secp256k1_foo secp256k1_foo;` (or also `struct secp256k1_foo;` in C++). + - Organized CMake build artifacts into dedicated directories (`bin/` for executables, `lib/` for libraries) to improve build output structure and Windows shared library compatibility. + +#### Removed + - Removed the `secp256k1_scratch_space` struct and its associated functions `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` because the scratch space was unused in the API. + +#### ABI Compatibility +The symbols `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` were removed. +Otherwise, the library maintains backward compatibility with versions 0.3.x through 0.5.x. + +## [0.5.1] - 2024-08-01 + +#### Added + - Added usage example for an ElligatorSwift key exchange. + +#### Changed + - The default size of the precomputed table for signing was changed from 22 KiB to 86 KiB. The size can be changed with the configure option `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake). + - "auto" is no longer an accepted value for the `--with-ecmult-window` and `--with-ecmult-gen-kb` configure options (this also applies to `SECP256K1_ECMULT_WINDOW_SIZE` and `SECP256K1_ECMULT_GEN_KB` in CMake). To achieve the same configuration as previously provided by the "auto" value, omit setting the configure option explicitly. + +#### Fixed + - Fixed compilation when the extrakeys module is disabled. + +#### ABI Compatibility +The ABI is backward compatible with versions 0.5.0, 0.4.x and 0.3.x. + +## [0.5.0] - 2024-05-06 + +#### Added + - New function `secp256k1_ec_pubkey_sort` that sorts public keys using lexicographic (of compressed serialization) order. + +#### Changed + - The implementation of the point multiplication algorithm used for signing and public key generation was changed, resulting in improved performance for those operations. + - The related configure option `--ecmult-gen-precision` was replaced with `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake). + - This changes the supported precomputed table sizes for these operations. The new supported sizes are 2 KiB, 22 KiB, or 86 KiB (while the old supported sizes were 32 KiB, 64 KiB, or 512 KiB). + +#### ABI Compatibility +The ABI is backward compatible with versions 0.4.x and 0.3.x. + +## [0.4.1] - 2023-12-21 + +#### Changed + - The point multiplication algorithm used for ECDH operations (module `ecdh`) was replaced with a slightly faster one. + - Optional handwritten x86_64 assembly for field operations was removed because modern C compilers are able to output more efficient assembly. This change results in a significant speedup of some library functions when handwritten x86_64 assembly is enabled (`--with-asm=x86_64` in GNU Autotools, `-DSECP256K1_ASM=x86_64` in CMake), which is the default on x86_64. Benchmarks with GCC 10.5.0 show a 10% speedup for `secp256k1_ecdsa_verify` and `secp256k1_schnorrsig_verify`. + +#### ABI Compatibility +The ABI is backward compatible with versions 0.4.0 and 0.3.x. + +## [0.4.0] - 2023-09-04 + +#### Added + - New module `ellswift` implements ElligatorSwift encoding for public keys and x-only Diffie-Hellman key exchange for them. + ElligatorSwift permits representing secp256k1 public keys as 64-byte arrays which cannot be distinguished from uniformly random. See: + - Header file `include/secp256k1_ellswift.h` which defines the new API. + - Document `doc/ellswift.md` which explains the mathematical background of the scheme. + - The [paper](https://eprint.iacr.org/2022/759) on which the scheme is based. + - We now test the library with unreleased development snapshots of GCC and Clang. This gives us an early chance to catch miscompilations and constant-time issues introduced by the compiler (such as those that led to the previous two releases). + +#### Fixed + - Fixed symbol visibility in Windows DLL builds, where three internal library symbols were wrongly exported. + +#### Changed + - When consuming libsecp256k1 as a static library on Windows, the user must now define the `SECP256K1_STATIC` macro before including `secp256k1.h`. + +#### ABI Compatibility +This release is backward compatible with the ABI of 0.3.0, 0.3.1, and 0.3.2. Symbol visibility is now believed to be handled properly on supported platforms and is now considered to be part of the ABI. Please report any improperly exported symbols as a bug. + +## [0.3.2] - 2023-05-13 +We strongly recommend updating to 0.3.2 if you use or plan to use GCC >=13 to compile libsecp256k1. When in doubt, check the GCC version using `gcc -v`. + +#### Security + - Module `ecdh`: Fix "constant-timeness" issue with GCC 13.1 (and potentially future versions of GCC) that could leave applications using libsecp256k1's ECDH module vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow during ECDH computations when libsecp256k1 is compiled with GCC 13.1. + +#### Fixed + - Fixed an old bug that permitted compilers to potentially output bad assembly code on x86_64. In theory, it could lead to a crash or a read of unrelated memory, but this has never been observed on any compilers so far. + +#### Changed + - Various improvements and changes to CMake builds. CMake builds remain experimental. + - Made API versioning consistent with GNU Autotools builds. + - Switched to `BUILD_SHARED_LIBS` variable for controlling whether to build a static or a shared library. + - Added `SECP256K1_INSTALL` variable for the controlling whether to install the build artefacts. + - Renamed asm build option `arm` to `arm32`. Use `--with-asm=arm32` instead of `--with-asm=arm` (GNU Autotools), and `-DSECP256K1_ASM=arm32` instead of `-DSECP256K1_ASM=arm` (CMake). + +#### ABI Compatibility +The ABI is compatible with versions 0.3.0 and 0.3.1. + +## [0.3.1] - 2023-04-10 +We strongly recommend updating to 0.3.1 if you use or plan to use Clang >=14 to compile libsecp256k1, e.g., Xcode >=14 on macOS has Clang >=14. When in doubt, check the Clang version using `clang -v`. + +#### Security + - Fix "constant-timeness" issue with Clang >=14 that could leave applications using libsecp256k1 vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow and secret-dependent memory accesses in conditional moves of memory objects when libsecp256k1 is compiled with Clang >=14. + +#### Added + - Added tests against [Project Wycheproof's](https://github.com/google/wycheproof/) set of ECDSA test vectors (Bitcoin "low-S" variant), a fixed set of test cases designed to trigger various edge cases. + +#### Changed + - Increased minimum required CMake version to 3.13. CMake builds remain experimental. + +#### ABI Compatibility +The ABI is compatible with version 0.3.0. + +## [0.3.0] - 2023-03-08 + +#### Added + - Added experimental support for CMake builds. Traditional GNU Autotools builds (`./configure` and `make`) remain fully supported. + - Usage examples: Added a recommended method for securely clearing sensitive data, e.g., secret keys, from memory. + - Tests: Added a new test binary `noverify_tests`. This binary runs the tests without some additional checks present in the ordinary `tests` binary and is thereby closer to production binaries. The `noverify_tests` binary is automatically run as part of the `make check` target. + +#### Fixed + - Fixed declarations of API variables for MSVC (`__declspec(dllimport)`). This fixes MSVC builds of programs which link against a libsecp256k1 DLL dynamically and use API variables (and not only API functions). Unfortunately, the MSVC linker now will emit warning `LNK4217` when trying to link against libsecp256k1 statically. Pass `/ignore:4217` to the linker to suppress this warning. + +#### Changed + - Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.) + - Forbade randomizing (copies of) `secp256k1_context_static`. Randomizing a copy of `secp256k1_context_static` did not have any effect and did not provide defense-in-depth protection against side-channel attacks. Create a new context if you want to benefit from randomization. + +#### Removed + - Removed the configuration header `src/libsecp256k1-config.h`. We recommend passing flags to `./configure` or `cmake` to set configuration options (see `./configure --help` or `cmake -LH`). If you cannot or do not want to use one of the supported build systems, pass configuration flags such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG` manually to the compiler (see the file `configure.ac` for supported flags). + +#### ABI Compatibility +Due to changes in the API regarding `secp256k1_context_static` described above, the ABI is *not* compatible with previous versions. + +## [0.2.0] - 2022-12-12 + +#### Added + - Added usage examples for common use cases in a new `examples/` directory. + - Added `secp256k1_selftest`, to be used in conjunction with `secp256k1_context_static`. + - Added support for 128-bit wide multiplication on MSVC for x86_64 and arm64, giving roughly a 20% speedup on those platforms. + +#### Changed + - Enabled modules `schnorrsig`, `extrakeys` and `ecdh` by default in `./configure`. + - The `secp256k1_nonce_function_rfc6979` nonce function, used by default by `secp256k1_ecdsa_sign`, now reduces the message hash modulo the group order to match the specification. This only affects improper use of ECDSA signing API. + +#### Deprecated + - Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead. + - Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`. + - Module `schnorrsig`: renamed `secp256k1_schnorrsig_sign` to `secp256k1_schnorrsig_sign32`. + +#### ABI Compatibility +Since this is the first release, we do not compare application binary interfaces. +However, there are earlier unreleased versions of libsecp256k1 that are *not* ABI compatible with this version. + +## [0.1.0] - 2013-03-05 to 2021-12-25 + +This version was in fact never released. +The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6). +Therefore, this version number does not uniquely identify a set of source files. + +[0.6.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.1...v0.6.0 +[0.5.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.0...v0.5.1 +[0.5.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.1...v0.5.0 +[0.4.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.0...v0.4.1 +[0.4.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...v0.4.0 +[0.3.2]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...v0.3.2 +[0.3.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...v0.3.1 +[0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0 +[0.2.0]: https://github.com/bitcoin-core/secp256k1/compare/423b6d19d373f1224fd671a982584d7e7900bc93..v0.2.0 +[0.1.0]: https://github.com/bitcoin-core/secp256k1/commit/423b6d19d373f1224fd671a982584d7e7900bc93 diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/CMakeLists.txt b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/CMakeLists.txt new file mode 100644 index 00000000..041bfa3d --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/CMakeLists.txt @@ -0,0 +1,405 @@ +cmake_minimum_required(VERSION 3.16) + +#============================= +# Project / Package metadata +#============================= +project(libsecp256k1 + # The package (a.k.a. release) version is based on semantic versioning 2.0.0 of + # the API. All changes in experimental modules are treated as + # backwards-compatible and therefore at most increase the minor version. + VERSION 0.6.0 + DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1." + HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1" + LANGUAGES C +) +enable_testing() +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) + +if(CMAKE_VERSION VERSION_LESS 3.21) + # Emulates CMake 3.21+ behavior. + if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + set(PROJECT_IS_TOP_LEVEL ON) + set(${PROJECT_NAME}_IS_TOP_LEVEL ON) + else() + set(PROJECT_IS_TOP_LEVEL OFF) + set(${PROJECT_NAME}_IS_TOP_LEVEL OFF) + endif() +endif() + +# The library version is based on libtool versioning of the ABI. The set of +# rules for updating the version can be found here: +# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +# All changes in experimental modules are treated as if they don't affect the +# interface and therefore only increase the revision. +set(${PROJECT_NAME}_LIB_VERSION_CURRENT 5) +set(${PROJECT_NAME}_LIB_VERSION_REVISION 0) +set(${PROJECT_NAME}_LIB_VERSION_AGE 0) + +#============================= +# Language setup +#============================= +set(CMAKE_C_STANDARD 90) +set(CMAKE_C_EXTENSIONS OFF) + +#============================= +# Configurable options +#============================= +option(BUILD_SHARED_LIBS "Build shared libraries." ON) +option(SECP256K1_DISABLE_SHARED "Disable shared library. Overrides BUILD_SHARED_LIBS." OFF) +if(SECP256K1_DISABLE_SHARED) + set(BUILD_SHARED_LIBS OFF) +endif() + +option(SECP256K1_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL}) + +## Modules + +# We declare all options before processing them, to make sure we can express +# dependendencies while processing. +option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON) +option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF) +option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON) +option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON) +option(SECP256K1_ENABLE_MODULE_MUSIG "Enable musig module." ON) +option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON) + +# Processing must be done in a topological sorting of the dependency graph +# (dependent module first). +if(SECP256K1_ENABLE_MODULE_ELLSWIFT) + add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1) +endif() + +if(SECP256K1_ENABLE_MODULE_MUSIG) + if(DEFINED SECP256K1_ENABLE_MODULE_SCHNORRSIG AND NOT SECP256K1_ENABLE_MODULE_SCHNORRSIG) + message(FATAL_ERROR "Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.") + endif() + set(SECP256K1_ENABLE_MODULE_SCHNORRSIG ON) + add_compile_definitions(ENABLE_MODULE_MUSIG=1) +endif() + +if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) + if(DEFINED SECP256K1_ENABLE_MODULE_EXTRAKEYS AND NOT SECP256K1_ENABLE_MODULE_EXTRAKEYS) + message(FATAL_ERROR "Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.") + endif() + set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON) + add_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1) +endif() + +if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) + add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1) +endif() + +if(SECP256K1_ENABLE_MODULE_RECOVERY) + add_compile_definitions(ENABLE_MODULE_RECOVERY=1) +endif() + +if(SECP256K1_ENABLE_MODULE_ECDH) + add_compile_definitions(ENABLE_MODULE_ECDH=1) +endif() + +option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF) +if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS) + add_compile_definitions(USE_EXTERNAL_DEFAULT_CALLBACKS=1) +endif() + +set(SECP256K1_ECMULT_WINDOW_SIZE 15 CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. The default value is a reasonable setting for desktop machines (currently 15). [default=15]") +set_property(CACHE SECP256K1_ECMULT_WINDOW_SIZE PROPERTY STRINGS 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24) +include(CheckStringOptionValue) +check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE) +add_compile_definitions(ECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE}) + +set(SECP256K1_ECMULT_GEN_KB 86 CACHE STRING "The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms). Larger values result in possibly better signing or key generation performance at the cost of a larger table. Valid choices are 2, 22, 86. The default value is a reasonable setting for desktop machines (currently 86). [default=86]") +set_property(CACHE SECP256K1_ECMULT_GEN_KB PROPERTY STRINGS 2 22 86) +check_string_option_value(SECP256K1_ECMULT_GEN_KB) +if(SECP256K1_ECMULT_GEN_KB EQUAL 2) + add_compile_definitions(COMB_BLOCKS=2) + add_compile_definitions(COMB_TEETH=5) +elseif(SECP256K1_ECMULT_GEN_KB EQUAL 22) + add_compile_definitions(COMB_BLOCKS=11) + add_compile_definitions(COMB_TEETH=6) +elseif(SECP256K1_ECMULT_GEN_KB EQUAL 86) + add_compile_definitions(COMB_BLOCKS=43) + add_compile_definitions(COMB_TEETH=6) +endif() + +set(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY "OFF" CACHE STRING "Test-only override of the (autodetected by the C code) \"widemul\" setting. Legal values are: \"OFF\", \"int128_struct\", \"int128\" or \"int64\". [default=OFF]") +set_property(CACHE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY PROPERTY STRINGS "OFF" "int128_struct" "int128" "int64") +check_string_option_value(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) +if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) + string(TOUPPER "${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}" widemul_upper_value) + add_compile_definitions(USE_FORCE_WIDEMUL_${widemul_upper_value}=1) +endif() +mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) + +set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]") +set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32") +check_string_option_value(SECP256K1_ASM) +if(SECP256K1_ASM STREQUAL "arm32") + enable_language(ASM) + include(CheckArm32Assembly) + check_arm32_assembly() + if(HAVE_ARM32_ASM) + add_compile_definitions(USE_EXTERNAL_ASM=1) + else() + message(FATAL_ERROR "ARM32 assembly requested but not available.") + endif() +elseif(SECP256K1_ASM) + include(CheckX86_64Assembly) + check_x86_64_assembly() + if(HAVE_X86_64_ASM) + set(SECP256K1_ASM "x86_64") + add_compile_definitions(USE_ASM_X86_64=1) + elseif(SECP256K1_ASM STREQUAL "AUTO") + set(SECP256K1_ASM "OFF") + else() + message(FATAL_ERROR "x86_64 assembly requested but not available.") + endif() +endif() + +option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF) +if(NOT SECP256K1_EXPERIMENTAL) + if(SECP256K1_ASM STREQUAL "arm32") + message(FATAL_ERROR "ARM32 assembly is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.") + endif() +endif() + +set(SECP256K1_VALGRIND "AUTO" CACHE STRING "Build with extra checks for running inside Valgrind. [default=AUTO]") +set_property(CACHE SECP256K1_VALGRIND PROPERTY STRINGS "AUTO" "OFF" "ON") +check_string_option_value(SECP256K1_VALGRIND) +if(SECP256K1_VALGRIND) + find_package(Valgrind MODULE) + if(Valgrind_FOUND) + set(SECP256K1_VALGRIND ON) + include_directories(${Valgrind_INCLUDE_DIR}) + add_compile_definitions(VALGRIND) + elseif(SECP256K1_VALGRIND STREQUAL "AUTO") + set(SECP256K1_VALGRIND OFF) + else() + message(FATAL_ERROR "Valgrind support requested but valgrind/memcheck.h header not available.") + endif() +endif() + +option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." ON) +option(SECP256K1_BUILD_TESTS "Build tests." ON) +option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." ON) +option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." ${SECP256K1_VALGRIND}) +option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF) + +# Redefine configuration flags. +# We leave assertions on, because they are only used in the examples, and we want them always on there. +if(MSVC) + string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") + string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") +else() + string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") + string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") + # Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.) + string(REGEX REPLACE "-O3( |$)" "-O2\\1" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") +endif() + +# Define custom "Coverage" build type. +set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O0 -DCOVERAGE=1 --coverage" CACHE STRING + "Flags used by the C compiler during \"Coverage\" builds." + FORCE +) +set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING + "Flags used for linking binaries during \"Coverage\" builds." + FORCE +) +set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING + "Flags used by the shared libraries linker during \"Coverage\" builds." + FORCE +) +mark_as_advanced( + CMAKE_C_FLAGS_COVERAGE + CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE +) + +if(PROJECT_IS_TOP_LEVEL) + get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + set(default_build_type "RelWithDebInfo") + if(is_multi_config) + set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING + "Supported configuration types." + FORCE + ) + else() + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY + STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" + ) + if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting build type to \"${default_build_type}\" as none was specified") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING + "Choose the type of build." + FORCE + ) + endif() + endif() +endif() + +include(TryAppendCFlags) +if(MSVC) + # Keep the following commands ordered lexicographically. + try_append_c_flags(/W3) # Production quality warning level. + try_append_c_flags(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned". + try_append_c_flags(/wd4244) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data". + try_append_c_flags(/wd4267) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data". + # Eliminate deprecation warnings for the older, less secure functions. + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) +else() + # Keep the following commands ordered lexicographically. + try_append_c_flags(-pedantic) + try_append_c_flags(-Wall) # GCC >= 2.95 and probably many other compilers. + try_append_c_flags(-Wcast-align) # GCC >= 2.95. + try_append_c_flags(-Wcast-align=strict) # GCC >= 8.0. + try_append_c_flags(-Wconditional-uninitialized) # Clang >= 3.0 only. + try_append_c_flags(-Wextra) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions. + try_append_c_flags(-Wnested-externs) + try_append_c_flags(-Wno-long-long) # GCC >= 3.0, -Wlong-long is implied by -pedantic. + try_append_c_flags(-Wno-overlength-strings) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic. + try_append_c_flags(-Wno-unused-function) # GCC >= 3.0, -Wunused-function is implied by -Wall. + try_append_c_flags(-Wreserved-identifier) # Clang >= 13.0 only. + try_append_c_flags(-Wshadow) + try_append_c_flags(-Wstrict-prototypes) + try_append_c_flags(-Wundef) +endif() + +set(CMAKE_C_VISIBILITY_PRESET hidden) + +set(print_msan_notice) +if(SECP256K1_BUILD_CTIME_TESTS) + include(CheckMemorySanitizer) + check_memory_sanitizer(msan_enabled) + if(msan_enabled) + try_append_c_flags(-fno-sanitize-memory-param-retval) + set(print_msan_notice YES) + endif() + unset(msan_enabled) +endif() + +set(SECP256K1_APPEND_CFLAGS "" CACHE STRING "Compiler flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.") +if(SECP256K1_APPEND_CFLAGS) + # Appending to this low-level rule variable is the only way to + # guarantee that the flags appear at the end of the command line. + string(APPEND CMAKE_C_COMPILE_OBJECT " ${SECP256K1_APPEND_CFLAGS}") +endif() + +set(SECP256K1_APPEND_LDFLAGS "" CACHE STRING "Linker flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.") +if(SECP256K1_APPEND_LDFLAGS) + # Appending to this low-level rule variable is the only way to + # guarantee that the flags appear at the end of the command line. + string(APPEND CMAKE_C_CREATE_SHARED_LIBRARY " ${SECP256K1_APPEND_LDFLAGS}") + string(APPEND CMAKE_C_LINK_EXECUTABLE " ${SECP256K1_APPEND_LDFLAGS}") +endif() + +if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) +endif() +if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +endif() +if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +endif() +add_subdirectory(src) +if(SECP256K1_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() + +message("\n") +message("secp256k1 configure summary") +message("===========================") +message("Build artifacts:") +if(BUILD_SHARED_LIBS) + set(library_type "Shared") +else() + set(library_type "Static") +endif() + +message(" library type ........................ ${library_type}") +message("Optional modules:") +message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}") +message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}") +message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}") +message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}") +message(" musig ............................... ${SECP256K1_ENABLE_MODULE_MUSIG}") +message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}") +message("Parameters:") +message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}") +message(" ecmult gen table size ............... ${SECP256K1_ECMULT_GEN_KB} KiB") +message("Optional features:") +message(" assembly ............................ ${SECP256K1_ASM}") +message(" external callbacks .................. ${SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS}") +if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) + message(" wide multiplication (test-only) ..... ${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}") +endif() +message("Optional binaries:") +message(" benchmark ........................... ${SECP256K1_BUILD_BENCHMARK}") +message(" noverify_tests ...................... ${SECP256K1_BUILD_TESTS}") +set(tests_status "${SECP256K1_BUILD_TESTS}") +if(CMAKE_BUILD_TYPE STREQUAL "Coverage") + set(tests_status OFF) +endif() +message(" tests ............................... ${tests_status}") +message(" exhaustive tests .................... ${SECP256K1_BUILD_EXHAUSTIVE_TESTS}") +message(" ctime_tests ......................... ${SECP256K1_BUILD_CTIME_TESTS}") +message(" examples ............................ ${SECP256K1_BUILD_EXAMPLES}") +message("") +if(CMAKE_CROSSCOMPILING) + set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}") +else() + set(cross_status "FALSE") +endif() +message("Cross compiling ....................... ${cross_status}") +message("Valgrind .............................. ${SECP256K1_VALGRIND}") +get_directory_property(definitions COMPILE_DEFINITIONS) +string(REPLACE ";" " " definitions "${definitions}") +message("Preprocessor defined macros ........... ${definitions}") +message("C compiler ............................ ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION}, ${CMAKE_C_COMPILER}") +message("CFLAGS ................................ ${CMAKE_C_FLAGS}") +get_directory_property(compile_options COMPILE_OPTIONS) +string(REPLACE ";" " " compile_options "${compile_options}") +message("Compile options ....................... " ${compile_options}) +if(NOT is_multi_config) + message("Build type:") + message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}") + string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type) + message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_${build_type}}") + message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}") + message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}") +else() + message("Supported configurations .............. ${CMAKE_CONFIGURATION_TYPES}") + message("RelWithDebInfo configuration:") + message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELWITHDEBINFO}") + message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}") + message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}") + message("Debug configuration:") + message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_DEBUG}") + message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}") + message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") +endif() +if(SECP256K1_APPEND_CFLAGS) + message("SECP256K1_APPEND_CFLAGS ............... ${SECP256K1_APPEND_CFLAGS}") +endif() +if(SECP256K1_APPEND_LDFLAGS) + message("SECP256K1_APPEND_LDFLAGS .............. ${SECP256K1_APPEND_LDFLAGS}") +endif() +message("") +if(print_msan_notice) + message( + "Note:\n" + " MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to compile options\n" + " to avoid false positives in ctime_tests. Pass -DSECP256K1_BUILD_CTIME_TESTS=OFF to avoid this.\n" + ) +endif() +if(SECP256K1_EXPERIMENTAL) + message( + " ******\n" + " WARNING: experimental build\n" + " Experimental features do not have stable APIs or properties, and may not be safe for production use.\n" + " ******\n" + ) +endif() diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/CMakePresets.json b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/CMakePresets.json new file mode 100644 index 00000000..b35cd805 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/CMakePresets.json @@ -0,0 +1,19 @@ +{ + "cmakeMinimumRequired": {"major": 3, "minor": 21, "patch": 0}, + "version": 3, + "configurePresets": [ + { + "name": "dev-mode", + "displayName": "Development mode (intended only for developers of the library)", + "cacheVariables": { + "SECP256K1_EXPERIMENTAL": "ON", + "SECP256K1_ENABLE_MODULE_RECOVERY": "ON", + "SECP256K1_BUILD_EXAMPLES": "ON" + }, + "warnings": { + "dev": true, + "uninitialized": true + } + } + ] +} diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/CONTRIBUTING.md b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/CONTRIBUTING.md new file mode 100644 index 00000000..2722c44e --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/CONTRIBUTING.md @@ -0,0 +1,108 @@ +# Contributing to libsecp256k1 + +## Scope + +libsecp256k1 is a library for elliptic curve cryptography on the curve secp256k1, not a general-purpose cryptography library. +The library primarily serves the needs of the Bitcoin Core project but provides additional functionality for the benefit of the wider Bitcoin ecosystem. + +## Adding new functionality or modules + +The libsecp256k1 project welcomes contributions in the form of new functionality or modules, provided they are within the project's scope. + +It is the responsibility of the contributors to convince the maintainers that the proposed functionality is within the project's scope, high-quality and maintainable. +Contributors are recommended to provide the following in addition to the new code: + +* **Specification:** + A specification can help significantly in reviewing the new code as it provides documentation and context. + It may justify various design decisions, give a motivation and outline security goals. + If the specification contains pseudocode, a reference implementation or test vectors, these can be used to compare with the proposed libsecp256k1 code. +* **Security Arguments:** + In addition to a defining the security goals, it should be argued that the new functionality meets these goals. + Depending on the nature of the new functionality, a wide range of security arguments are acceptable, ranging from being "obviously secure" to rigorous proofs of security. +* **Relevance Arguments:** + The relevance of the new functionality for the Bitcoin ecosystem should be argued by outlining clear use cases. + +These are not the only factors taken into account when considering to add new functionality. +The proposed new libsecp256k1 code must be of high quality, including API documentation and tests, as well as featuring a misuse-resistant API design. + +We recommend reaching out to other contributors (see [Communication Channels](#communication-channels)) and get feedback before implementing new functionality. + +## Communication channels + +Most communication about libsecp256k1 occurs on the GitHub repository: in issues, pull request or on the discussion board. + +Additionally, there is an IRC channel dedicated to libsecp256k1, with biweekly meetings (see channel topic). +The channel is `#secp256k1` on Libera Chat. +The easiest way to participate on IRC is with the web client, [web.libera.chat](https://web.libera.chat/#secp256k1). +Chat history logs can be found at https://gnusha.org/secp256k1/. + +## Contributor workflow & peer review + +The Contributor Workflow & Peer Review in libsecp256k1 are similar to Bitcoin Core's workflow and review processes described in its [CONTRIBUTING.md](https://github.com/bitcoin/bitcoin/blob/master/CONTRIBUTING.md). + +### Coding conventions + +In addition, libsecp256k1 tries to maintain the following coding conventions: + +* No runtime heap allocation (e.g., no `malloc`) unless explicitly requested by the caller (via `rustsecp256k1_v0_11_context_create` or `rustsecp256k1_v0_11_scratch_space_create`, for example). Moreover, it should be possible to use the library without any heap allocations. +* The tests should cover all lines and branches of the library (see [Test coverage](#coverage)). +* Operations involving secret data should be tested for being constant time with respect to the secrets (see [src/ctime_tests.c](src/ctime_tests.c)). +* Local variables containing secret data should be cleared explicitly to try to delete secrets from memory. +* Use `rustsecp256k1_v0_11_memcmp_var` instead of `memcmp` (see [#823](https://github.com/bitcoin-core/secp256k1/issues/823)). +* As a rule of thumb, the default values for configuration options should target standard desktop machines and align with Bitcoin Core's defaults, and the tests should mostly exercise the default configuration (see [#1549](https://github.com/bitcoin-core/secp256k1/issues/1549#issuecomment-2200559257)). + +#### Style conventions + +* Commits should be atomic and diffs should be easy to read. For this reason, do not mix any formatting fixes or code moves with actual code changes. Make sure each individual commit is hygienic: that it builds successfully on its own without warnings, errors, regressions, or test failures. +* New code should adhere to the style of existing, in particular surrounding, code. Other than that, we do not enforce strict rules for code formatting. +* The code conforms to C89. Most notably, that means that only `/* ... */` comments are allowed (no `//` line comments). Moreover, any declarations in a `{ ... }` block (e.g., a function) must appear at the beginning of the block before any statements. When you would like to declare a variable in the middle of a block, you can open a new block: + ```C + void secp256k_foo(void) { + unsigned int x; /* declaration */ + int y = 2*x; /* declaration */ + x = 17; /* statement */ + { + int a, b; /* declaration */ + a = x + y; /* statement */ + secp256k_bar(x, &b); /* statement */ + } + } + ``` +* Use `unsigned int` instead of just `unsigned`. +* Use `void *ptr` instead of `void* ptr`. +* Arguments of the publicly-facing API must have a specific order defined in [include/secp256k1.h](include/secp256k1.h). +* User-facing comment lines in headers should be limited to 80 chars if possible. +* All identifiers in file scope should start with `rustsecp256k1_v0_11_`. +* Avoid trailing whitespace. + +### Tests + +#### Coverage + +This library aims to have full coverage of reachable lines and branches. + +To create a test coverage report, configure with `--enable-coverage` (use of GCC is necessary): + + $ ./configure --enable-coverage + +Run the tests: + + $ make check + +To create a report, `gcovr` is recommended, as it includes branch coverage reporting: + + $ gcovr --exclude 'src/bench*' --print-summary + +To create a HTML report with coloured and annotated source code: + + $ mkdir -p coverage + $ gcovr --exclude 'src/bench*' --html --html-details -o coverage/coverage.html + +#### Exhaustive tests + +There are tests of several functions in which a small group replaces secp256k1. +These tests are *exhaustive* since they provide all elements and scalars of the small group as input arguments (see [src/tests_exhaustive.c](src/tests_exhaustive.c)). + +### Benchmarks + +See `src/bench*.c` for examples of benchmarks. diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/COPYING b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/COPYING similarity index 100% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/COPYING rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/COPYING diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/Makefile.am b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/Makefile.am similarity index 55% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/Makefile.am rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/Makefile.am index a129ea01..6b7c64f5 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/Makefile.am +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/Makefile.am @@ -1,5 +1,3 @@ -.PHONY: clean-precomp precomp - ACLOCAL_AMFLAGS = -I build-aux/m4 # AM_CFLAGS will be automatically prepended to CFLAGS by Automake when compiling some foo @@ -8,7 +6,7 @@ AM_CFLAGS = $(SECP_CFLAGS) lib_LTLIBRARIES = libsecp256k1.la include_HEADERS = include/secp256k1.h -include_HEADERS += include/rustsecp256k1zkp_v0_8_0_preallocated.h +include_HEADERS += include/rustsecp256k1_v0_11_preallocated.h noinst_HEADERS = noinst_HEADERS += src/scalar.h noinst_HEADERS += src/scalar_4x64.h @@ -20,8 +18,6 @@ noinst_HEADERS += src/scalar_8x32_impl.h noinst_HEADERS += src/scalar_low_impl.h noinst_HEADERS += src/group.h noinst_HEADERS += src/group_impl.h -noinst_HEADERS += src/eccommit.h -noinst_HEADERS += src/eccommit_impl.h noinst_HEADERS += src/ecdsa.h noinst_HEADERS += src/ecdsa_impl.h noinst_HEADERS += src/eckey.h @@ -41,7 +37,6 @@ noinst_HEADERS += src/field_10x26_impl.h noinst_HEADERS += src/field_5x52.h noinst_HEADERS += src/field_5x52_impl.h noinst_HEADERS += src/field_5x52_int128_impl.h -noinst_HEADERS += src/field_5x52_asm_impl.h noinst_HEADERS += src/modinv32.h noinst_HEADERS += src/modinv32_impl.h noinst_HEADERS += src/modinv64.h @@ -49,7 +44,15 @@ noinst_HEADERS += src/modinv64_impl.h noinst_HEADERS += src/precomputed_ecmult.h noinst_HEADERS += src/precomputed_ecmult_gen.h noinst_HEADERS += src/assumptions.h +noinst_HEADERS += src/checkmem.h +noinst_HEADERS += src/testutil.h noinst_HEADERS += src/util.h +noinst_HEADERS += src/int128.h +noinst_HEADERS += src/int128_impl.h +noinst_HEADERS += src/int128_native.h +noinst_HEADERS += src/int128_native_impl.h +noinst_HEADERS += src/int128_struct.h +noinst_HEADERS += src/int128_struct_impl.h noinst_HEADERS += src/scratch.h noinst_HEADERS += src/scratch_impl.h noinst_HEADERS += src/selftest.h @@ -60,20 +63,24 @@ noinst_HEADERS += src/hash_impl.h noinst_HEADERS += src/field.h noinst_HEADERS += src/field_impl.h noinst_HEADERS += src/bench.h -noinst_HEADERS += src/basic-config.h +noinst_HEADERS += src/wycheproof/ecdsa_rustsecp256k1_v0_11_sha256_bitcoin_test.h +noinst_HEADERS += src/hsort.h +noinst_HEADERS += src/hsort_impl.h noinst_HEADERS += contrib/lax_der_parsing.h noinst_HEADERS += contrib/lax_der_parsing.c noinst_HEADERS += contrib/lax_der_privatekey_parsing.h noinst_HEADERS += contrib/lax_der_privatekey_parsing.c -noinst_HEADERS += examples/random.h +noinst_HEADERS += examples/examples_util.h -PRECOMPUTED_LIB = librustsecp256k1zkp_v0_8_0_precomputed.la +PRECOMPUTED_LIB = librustsecp256k1_v0_11_precomputed.la noinst_LTLIBRARIES = $(PRECOMPUTED_LIB) -librustsecp256k1zkp_v0_8_0_precomputed_la_SOURCES = src/precomputed_ecmult.c src/precomputed_ecmult_gen.c -librustsecp256k1zkp_v0_8_0_precomputed_la_CPPFLAGS = $(SECP_INCLUDES) +librustsecp256k1_v0_11_precomputed_la_SOURCES = src/precomputed_ecmult.c src/precomputed_ecmult_gen.c +# We need `-I$(top_srcdir)/src` in VPATH builds if librustsecp256k1_v0_11_precomputed_la_SOURCES have been recreated in the build tree. +# This helps users and packagers who insist on recreating the precomputed files (e.g., Gentoo). +librustsecp256k1_v0_11_precomputed_la_CPPFLAGS = -I$(top_srcdir)/src $(SECP_CONFIG_DEFINES) if USE_EXTERNAL_ASM -COMMON_LIB = librustsecp256k1zkp_v0_8_0_common.la +COMMON_LIB = librustsecp256k1_v0_11_common.la else COMMON_LIB = endif @@ -84,60 +91,63 @@ pkgconfig_DATA = libsecp256k1.pc if USE_EXTERNAL_ASM if USE_ASM_ARM -librustsecp256k1zkp_v0_8_0_common_la_SOURCES = src/asm/field_10x26_arm.s +librustsecp256k1_v0_11_common_la_SOURCES = src/asm/field_10x26_arm.s endif endif -librustsecp256k1zkp_v0_8_0_la_SOURCES = src/secp256k1.c -librustsecp256k1zkp_v0_8_0_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) -librustsecp256k1zkp_v0_8_0_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) -librustsecp256k1zkp_v0_8_0_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE) - -if VALGRIND_ENABLED -librustsecp256k1zkp_v0_8_0_la_CPPFLAGS += -DVALGRIND -endif +librustsecp256k1_v0_11_la_SOURCES = src/secp256k1.c +librustsecp256k1_v0_11_la_CPPFLAGS = $(SECP_CONFIG_DEFINES) +librustsecp256k1_v0_11_la_LIBADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) +librustsecp256k1_v0_11_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE) noinst_PROGRAMS = if USE_BENCHMARK noinst_PROGRAMS += bench bench_internal bench_ecmult bench_SOURCES = src/bench.c -bench_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) +bench_LDADD = libsecp256k1.la +bench_CPPFLAGS = $(SECP_CONFIG_DEFINES) bench_internal_SOURCES = src/bench_internal.c -bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) -bench_internal_CPPFLAGS = $(SECP_INCLUDES) +bench_internal_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) +bench_internal_CPPFLAGS = $(SECP_CONFIG_DEFINES) bench_ecmult_SOURCES = src/bench_ecmult.c -bench_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) -bench_ecmult_CPPFLAGS = $(SECP_INCLUDES) +bench_ecmult_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) +bench_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES) endif TESTS = if USE_TESTS +TESTS += noverify_tests +noinst_PROGRAMS += noverify_tests +noverify_tests_SOURCES = src/tests.c +noverify_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) +noverify_tests_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) +noverify_tests_LDFLAGS = -static +if !ENABLE_COVERAGE +TESTS += tests noinst_PROGRAMS += tests -tests_SOURCES = src/tests.c -tests_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) -if VALGRIND_ENABLED -tests_CPPFLAGS += -DVALGRIND -noinst_PROGRAMS += valgrind_ctime_test -valgrind_ctime_test_SOURCES = src/valgrind_ctime_test.c -valgrind_ctime_test_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +tests_SOURCES = $(noverify_tests_SOURCES) +tests_CPPFLAGS = $(noverify_tests_CPPFLAGS) -DVERIFY +tests_LDADD = $(noverify_tests_LDADD) +tests_LDFLAGS = $(noverify_tests_LDFLAGS) endif -if !ENABLE_COVERAGE -tests_CPPFLAGS += -DVERIFY endif -tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) -tests_LDFLAGS = -static -TESTS += tests + +if USE_CTIME_TESTS +noinst_PROGRAMS += ctime_tests +ctime_tests_SOURCES = src/ctime_tests.c +ctime_tests_LDADD = libsecp256k1.la +ctime_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) endif if USE_EXHAUSTIVE_TESTS noinst_PROGRAMS += exhaustive_tests exhaustive_tests_SOURCES = src/tests_exhaustive.c -exhaustive_tests_CPPFLAGS = $(SECP_INCLUDES) +exhaustive_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) if !ENABLE_COVERAGE exhaustive_tests_CPPFLAGS += -DVERIFY endif # Note: do not include $(PRECOMPUTED_LIB) in exhaustive_tests (it uses runtime-generated tables). -exhaustive_tests_LDADD = $(SECP_LIBS) $(COMMON_LIB) +exhaustive_tests_LDADD = $(COMMON_LIB) exhaustive_tests_LDFLAGS = -static TESTS += exhaustive_tests endif @@ -145,7 +155,7 @@ endif if USE_EXAMPLES noinst_PROGRAMS += ecdsa_example ecdsa_example_SOURCES = examples/ecdsa.c -ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include +ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC ecdsa_example_LDADD = libsecp256k1.la ecdsa_example_LDFLAGS = -static if BUILD_WINDOWS @@ -155,7 +165,7 @@ TESTS += ecdsa_example if ENABLE_MODULE_ECDH noinst_PROGRAMS += ecdh_example ecdh_example_SOURCES = examples/ecdh.c -ecdh_example_CPPFLAGS = -I$(top_srcdir)/include +ecdh_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC ecdh_example_LDADD = libsecp256k1.la ecdh_example_LDFLAGS = -static if BUILD_WINDOWS @@ -166,7 +176,7 @@ endif if ENABLE_MODULE_SCHNORRSIG noinst_PROGRAMS += schnorr_example schnorr_example_SOURCES = examples/schnorr.c -schnorr_example_CPPFLAGS = -I$(top_srcdir)/include +schnorr_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC schnorr_example_LDADD = libsecp256k1.la schnorr_example_LDFLAGS = -static if BUILD_WINDOWS @@ -174,10 +184,21 @@ schnorr_example_LDFLAGS += -lbcrypt endif TESTS += schnorr_example endif +if ENABLE_MODULE_ELLSWIFT +noinst_PROGRAMS += ellswift_example +ellswift_example_SOURCES = examples/ellswift.c +ellswift_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC +ellswift_example_LDADD = libsecp256k1.la +ellswift_example_LDFLAGS = -static +if BUILD_WINDOWS +ellswift_example_LDFLAGS += -lbcrypt +endif +TESTS += ellswift_example +endif if ENABLE_MODULE_MUSIG noinst_PROGRAMS += musig_example musig_example_SOURCES = examples/musig.c -musig_example_CPPFLAGS = -I$(top_srcdir)/include +musig_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC musig_example_LDADD = libsecp256k1.la musig_example_LDFLAGS = -static if BUILD_WINDOWS @@ -192,19 +213,19 @@ EXTRA_PROGRAMS = precompute_ecmult precompute_ecmult_gen CLEANFILES = $(EXTRA_PROGRAMS) precompute_ecmult_SOURCES = src/precompute_ecmult.c -precompute_ecmult_CPPFLAGS = $(SECP_INCLUDES) -precompute_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB) +precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY +precompute_ecmult_LDADD = $(COMMON_LIB) precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c -precompute_ecmult_gen_CPPFLAGS = $(SECP_INCLUDES) -precompute_ecmult_gen_LDADD = $(SECP_LIBS) $(COMMON_LIB) +precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY +precompute_ecmult_gen_LDADD = $(COMMON_LIB) # See Automake manual, Section "Errors with distclean". # We don't list any dependencies for the prebuilt files here because # otherwise make's decision whether to rebuild them (even in the first # build by a normal user) depends on mtimes, and thus is very fragile. # This means that rebuilds of the prebuilt files always need to be -# forced by deleting them, e.g., by invoking `make clean-precomp`. +# forced by deleting them. src/precomputed_ecmult.c: $(MAKE) $(AM_MAKEFLAGS) precompute_ecmult$(EXEEXT) ./precompute_ecmult$(EXEEXT) @@ -219,45 +240,51 @@ precomp: $(PRECOMP) # e.g., after `make maintainer-clean`). BUILT_SOURCES = $(PRECOMP) -maintainer-clean-local: clean-precomp - +.PHONY: clean-precomp clean-precomp: rm -f $(PRECOMP) +maintainer-clean-local: clean-precomp -EXTRA_DIST = autogen.sh SECURITY.md - -if ENABLE_MODULE_BPPP -include src/modules/bppp/Makefile.am.include -endif +### Pregenerated test vectors +### (see the comments in the previous section for detailed rationale) +TESTVECTORS = src/wycheproof/ecdsa_rustsecp256k1_v0_11_sha256_bitcoin_test.h + +src/wycheproof/ecdsa_rustsecp256k1_v0_11_sha256_bitcoin_test.h: + mkdir -p $(@D) + python3 $(top_srcdir)/tools/tests_wycheproof_generate.py $(top_srcdir)/src/wycheproof/ecdsa_rustsecp256k1_v0_11_sha256_bitcoin_test.json > $@ + +testvectors: $(TESTVECTORS) + +BUILT_SOURCES += $(TESTVECTORS) + +.PHONY: clean-testvectors +clean-testvectors: + rm -f $(TESTVECTORS) +maintainer-clean-local: clean-testvectors + +### Additional files to distribute +EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md +EXTRA_DIST += doc/release-process.md doc/safegcd_implementation.md +EXTRA_DIST += doc/ellswift.md doc/musig.md +EXTRA_DIST += examples/EXAMPLES_COPYING +EXTRA_DIST += sage/gen_exhaustive_groups.sage +EXTRA_DIST += sage/gen_split_lambda_constants.sage +EXTRA_DIST += sage/group_prover.sage +EXTRA_DIST += sage/prove_group_implementations.sage +EXTRA_DIST += sage/rustsecp256k1_v0_11_params.sage +EXTRA_DIST += sage/weierstrass_prover.sage +EXTRA_DIST += src/wycheproof/WYCHEPROOF_COPYING +EXTRA_DIST += src/wycheproof/ecdsa_rustsecp256k1_v0_11_sha256_bitcoin_test.json +EXTRA_DIST += tools/tests_wycheproof_generate.py if ENABLE_MODULE_ECDH include src/modules/ecdh/Makefile.am.include endif -if ENABLE_MODULE_MUSIG -include src/modules/musig/Makefile.am.include -endif - if ENABLE_MODULE_RECOVERY include src/modules/recovery/Makefile.am.include endif -if ENABLE_MODULE_GENERATOR -include src/modules/generator/Makefile.am.include -endif - -if ENABLE_MODULE_RANGEPROOF -include src/modules/rangeproof/Makefile.am.include -endif - -if ENABLE_MODULE_WHITELIST -include src/modules/whitelist/Makefile.am.include -endif - -if ENABLE_MODULE_SURJECTIONPROOF -include src/modules/surjection/Makefile.am.include -endif - if ENABLE_MODULE_EXTRAKEYS include src/modules/extrakeys/Makefile.am.include endif @@ -266,10 +293,10 @@ if ENABLE_MODULE_SCHNORRSIG include src/modules/schnorrsig/Makefile.am.include endif -if ENABLE_MODULE_ECDSA_S2C -include src/modules/ecdsa_s2c/Makefile.am.include +if ENABLE_MODULE_MUSIG +include src/modules/musig/Makefile.am.include endif -if ENABLE_MODULE_ECDSA_ADAPTOR -include src/modules/ecdsa_adaptor/Makefile.am.include +if ENABLE_MODULE_ELLSWIFT +include src/modules/ellswift/Makefile.am.include endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/README.md b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/README.md similarity index 63% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/README.md rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/README.md index 7ac1e0a0..222e5fb7 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/README.md +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/README.md @@ -1,9 +1,10 @@ libsecp256k1 ============ -[![Build Status](https://api.cirrus-ci.com/github/bitcoin-core/secp256k1.svg?branch=master)](https://cirrus-ci.com/github/bitcoin-core/secp256k1) +![Dependencies: None](https://img.shields.io/badge/dependencies-none-success) +[![irc.libera.chat #secp256k1](https://img.shields.io/badge/irc.libera.chat-%23secp256k1-success)](https://web.libera.chat/#secp256k1) -Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1. +High-performance high-assurance C library for digital signatures and other cryptographic primitives on the secp256k1 elliptic curve. This library is intended to be the highest quality publicly available library for cryptography on the secp256k1 curve. However, the primary focus of its development has been for usage in the Bitcoin system and usage unlike Bitcoin's may be less well tested, verified, or suffer from a less well thought out interface. Correct usage requires some care and consideration that the library is fit for your application's purpose. @@ -15,12 +16,12 @@ Features: * Derandomized ECDSA (via RFC6979 or with a caller provided function.) * Very efficient implementation. * Suitable for embedded systems. +* No runtime dependencies. * Optional module for public key recovery. * Optional module for ECDH key exchange. * Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki). -* Optional module for ECDSA adaptor signatures (experimental). - -Experimental features have not received enough scrutiny to satisfy the standard of quality of this library but are made available for testing and review by the community. The APIs of these features should not be considered stable. +* Optional module for ElligatorSwift key exchange according to [BIP-324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki). +* Optional module for MuSig2 Schnorr multi-signatures according to [BIP-327](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki). Implementation details ---------------------- @@ -34,7 +35,7 @@ Implementation details * Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.") * Field operations * Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1). - * Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys). + * Using 5 52-bit limbs * Using 10 26-bit limbs (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan). * This is an experimental feature that has not received enough scrutiny to satisfy the standard of quality of this library but is made available for testing and review by the community. * Scalar operations @@ -60,10 +61,8 @@ Implementation details * Optional runtime blinding which attempts to frustrate differential power analysis. * The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally. -Build steps ------------ - -libsecp256k1 is built using autotools: +Building with Autotools +----------------------- $ ./autogen.sh $ ./configure @@ -73,35 +72,52 @@ libsecp256k1 is built using autotools: To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags. -Usage examples ------------ - Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`. - * [ECDSA example](examples/ecdsa.c) - * [Schnorr signatures example](examples/schnorr.c) - * [Deriving a shared secret (ECDH) example](examples/ecdh.c) - To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`. +Building with CMake (experimental) +---------------------------------- -Test coverage ------------ +To maintain a pristine source tree, CMake encourages to perform an out-of-source build by using a separate dedicated build tree. + +### Building on POSIX systems + + $ mkdir build && cd build + $ cmake .. + $ cmake --build . + $ ctest # run the test suite + $ sudo cmake --install . # optional + +To compile optional modules (such as Schnorr signatures), you need to run `cmake` with additional flags (such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG=ON`). Run `cmake .. -LH` to see the full list of available flags. -This library aims to have full coverage of the reachable lines and branches. +### Cross compiling -To create a test coverage report, configure with `--enable-coverage` (use of GCC is necessary): +To alleviate issues with cross compiling, preconfigured toolchain files are available in the `cmake` directory. +For example, to cross compile for Windows: - $ ./configure --enable-coverage + $ cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-w64-mingw32.toolchain.cmake -Run the tests: +To cross compile for Android with [NDK](https://developer.android.com/ndk/guides/cmake) (using NDK's toolchain file, and assuming the `ANDROID_NDK_ROOT` environment variable has been set): - $ make check + $ cmake .. -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=28 -To create a report, `gcovr` is recommended, as it includes branch coverage reporting: +### Building on Windows - $ gcovr --exclude 'src/bench*' --print-summary +To build on Windows with Visual Studio, a proper [generator](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators) must be specified for a new build tree. -To create a HTML report with coloured and annotated source code: +The following example assumes using of Visual Studio 2022 and CMake v3.21+. - $ mkdir -p coverage - $ gcovr --exclude 'src/bench*' --html --html-details -o coverage/coverage.html +In "Developer Command Prompt for VS 2022": + + >cmake -G "Visual Studio 17 2022" -A x64 -S . -B build + >cmake --build build --config RelWithDebInfo + +Usage examples +----------- +Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`. + * [ECDSA example](examples/ecdsa.c) + * [Schnorr signatures example](examples/schnorr.c) + * [Deriving a shared secret (ECDH) example](examples/ecdh.c) + * [ElligatorSwift key exchange example](examples/ellswift.c) + +To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`. Benchmark ------------ @@ -119,3 +135,8 @@ Reporting a vulnerability ------------ See [SECURITY.md](SECURITY.md) + +Contributing to libsecp256k1 +------------ + +See [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/SECURITY.md b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/SECURITY.md similarity index 100% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/SECURITY.md rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/SECURITY.md diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/autogen.sh b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/autogen.sh similarity index 100% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/autogen.sh rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/autogen.sh diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/build-aux/m4/bitcoin_secp.m4 b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/build-aux/m4/bitcoin_secp.m4 similarity index 55% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/build-aux/m4/bitcoin_secp.m4 rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/build-aux/m4/bitcoin_secp.m4 index dda770e0..048267fa 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/build-aux/m4/bitcoin_secp.m4 +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/build-aux/m4/bitcoin_secp.m4 @@ -1,15 +1,35 @@ dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell. -AC_DEFUN([SECP_64BIT_ASM_CHECK],[ +AC_DEFUN([SECP_X86_64_ASM_CHECK],[ AC_MSG_CHECKING(for x86_64 assembly availability) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include ]],[[ uint64_t a = 11, tmp; __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx"); - ]])],[has_64bit_asm=yes],[has_64bit_asm=no]) -AC_MSG_RESULT([$has_64bit_asm]) + ]])], [has_x86_64_asm=yes], [has_x86_64_asm=no]) +AC_MSG_RESULT([$has_x86_64_asm]) +]) + +AC_DEFUN([SECP_ARM32_ASM_CHECK], [ + AC_MSG_CHECKING(for ARM32 assembly availability) + SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS="$CFLAGS" + CFLAGS="-x assembler" + AC_LINK_IFELSE([AC_LANG_SOURCE([[ + .syntax unified + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .text + .global main + main: + ldr r0, =0x002A + mov r7, #1 + swi 0 + ]])], [has_arm32_asm=yes], [has_arm32_asm=no]) + AC_MSG_RESULT([$has_arm32_asm]) + CFLAGS="$SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS" ]) AC_DEFUN([SECP_VALGRIND_CHECK],[ +AC_MSG_CHECKING([for valgrind support]) if test x"$has_valgrind" != x"yes"; then CPPFLAGS_TEMP="$CPPFLAGS" CPPFLAGS="$VALGRIND_CPPFLAGS $CPPFLAGS" @@ -19,8 +39,26 @@ if test x"$has_valgrind" != x"yes"; then #if defined(NVALGRIND) # error "Valgrind does not support this platform." #endif - ]])], [has_valgrind=yes; AC_DEFINE(HAVE_VALGRIND,1,[Define this symbol if valgrind is installed, and it supports the host platform])]) + ]])], [has_valgrind=yes]) + CPPFLAGS="$CPPFLAGS_TEMP" fi +AC_MSG_RESULT($has_valgrind) +]) + +AC_DEFUN([SECP_MSAN_CHECK], [ +AC_MSG_CHECKING(whether MemorySanitizer is enabled) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ + #if defined(__has_feature) + # if __has_feature(memory_sanitizer) + /* MemorySanitizer is enabled. */ + # elif + # error "MemorySanitizer is disabled." + # endif + #else + # error "__has_feature is not defined." + #endif + ]])], [msan_enabled=yes], [msan_enabled=no]) +AC_MSG_RESULT([$msan_enabled]) ]) dnl SECP_TRY_APPEND_CFLAGS(flags, VAR) diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/ci/ci.sh b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/ci/ci.sh new file mode 100755 index 00000000..3636deaf --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/ci/ci.sh @@ -0,0 +1,149 @@ +#!/bin/sh + +set -eux + +export LC_ALL=C + +# Print commit and relevant CI environment to allow reproducing the job outside of CI. +git show --no-patch +print_environment() { + # Turn off -x because it messes up the output + set +x + # There are many ways to print variable names and their content. This one + # does not rely on bash. + for var in WERROR_CFLAGS MAKEFLAGS BUILD \ + ECMULTWINDOW ECMULTGENKB ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \ + EXPERIMENTAL ECDH RECOVERY EXTRAKEYS MUSIG SCHNORRSIG ELLSWIFT \ + SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\ + EXAMPLES \ + HOST WRAPPER_CMD \ + CC CFLAGS CPPFLAGS AR NM \ + UBSAN_OPTIONS ASAN_OPTIONS LSAN_OPTIONS + do + eval "isset=\${$var+x}" + if [ -n "$isset" ]; then + eval "val=\${$var}" + # shellcheck disable=SC2154 + printf '%s="%s" ' "$var" "$val" + fi + done + echo "$0" + set -x +} +print_environment + +env >> test_env.log + +# If gcc is requested, assert that it's in fact gcc (and not some symlinked Apple clang). +case "${CC:-undefined}" in + *gcc*) + $CC -v 2>&1 | grep -q "gcc version" || exit 1; + ;; +esac + +if [ -n "${CC+x}" ]; then + # The MSVC compiler "cl" doesn't understand "-v" + $CC -v || true +fi +if [ "$WITH_VALGRIND" = "yes" ]; then + valgrind --version +fi +if [ -n "$WRAPPER_CMD" ]; then + $WRAPPER_CMD --version +fi + +# Workaround for https://bugs.kde.org/show_bug.cgi?id=452758 (fixed in valgrind 3.20.0). +case "${CC:-undefined}" in + clang*) + if [ "$CTIMETESTS" = "yes" ] && [ "$WITH_VALGRIND" = "yes" ] + then + export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4" + else + case "$WRAPPER_CMD" in + valgrind*) + export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4" + ;; + esac + fi + ;; +esac + +./autogen.sh + +./configure \ + --enable-experimental="$EXPERIMENTAL" \ + --with-test-override-wide-multiply="$WIDEMUL" --with-asm="$ASM" \ + --with-ecmult-window="$ECMULTWINDOW" \ + --with-ecmult-gen-kb="$ECMULTGENKB" \ + --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \ + --enable-module-ellswift="$ELLSWIFT" \ + --enable-module-extrakeys="$EXTRAKEYS" \ + --enable-module-schnorrsig="$SCHNORRSIG" \ + --enable-module-musig="$MUSIG" \ + --enable-examples="$EXAMPLES" \ + --enable-ctime-tests="$CTIMETESTS" \ + --with-valgrind="$WITH_VALGRIND" \ + --host="$HOST" $EXTRAFLAGS + +# We have set "-j" in MAKEFLAGS. +build_exit_code=0 +make > make.log 2>&1 || build_exit_code=$? +cat make.log +if [ $build_exit_code -ne 0 ]; then + case "${CC:-undefined}" in + *snapshot*) + # Ignore internal compiler errors in gcc-snapshot and clang-snapshot + grep -e "internal compiler error:" -e "PLEASE submit a bug report" make.log + return $?; + ;; + *) + return 1; + ;; + esac +fi + +# Print information about binaries so that we can see that the architecture is correct +file *tests* || true +file bench* || true +file .libs/* || true + +# This tells `make check` to wrap test invocations. +export LOG_COMPILER="$WRAPPER_CMD" + +make "$BUILD" + +# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool +EXEC='./libtool --mode=execute' +if [ -n "$WRAPPER_CMD" ] +then + EXEC="$EXEC $WRAPPER_CMD" +fi + +if [ "$BENCH" = "yes" ] +then + { + $EXEC ./bench_ecmult + $EXEC ./bench_internal + $EXEC ./bench + } >> bench.log 2>&1 +fi + +if [ "$CTIMETESTS" = "yes" ] +then + if [ "$WITH_VALGRIND" = "yes" ]; then + ./libtool --mode=execute valgrind --error-exitcode=42 ./ctime_tests > ctime_tests.log 2>&1 + else + $EXEC ./ctime_tests > ctime_tests.log 2>&1 + fi +fi + +# Rebuild precomputed files (if not cross-compiling). +if [ -z "$HOST" ] +then + make clean-precomp clean-testvectors + make precomp testvectors +fi + +# Check that no repo files have been modified by the build. +# (This fails for example if the precomp files need to be updated in the repo.) +git diff --exit-code diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/ci/linux-debian.Dockerfile b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/ci/linux-debian.Dockerfile new file mode 100644 index 00000000..241bfa97 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/ci/linux-debian.Dockerfile @@ -0,0 +1,79 @@ +FROM debian:stable-slim + +SHELL ["/bin/bash", "-c"] + +WORKDIR /root + +# A too high maximum number of file descriptors (with the default value +# inherited from the docker host) can cause issues with some of our tools: +# - sanitizers hanging: https://github.com/google/sanitizers/issues/1662 +# - valgrind crashing: https://stackoverflow.com/a/75293014 +# This is not be a problem on our CI hosts, but developers who run the image +# on their machines may run into this (e.g., on Arch Linux), so warn them. +# (Note that .bashrc is only executed in interactive bash shells.) +RUN echo 'if [[ $(ulimit -n) -gt 200000 ]]; then echo "WARNING: Very high value reported by \"ulimit -n\". Consider passing \"--ulimit nofile=32768\" to \"docker run\"."; fi' >> /root/.bashrc + +RUN dpkg --add-architecture i386 && \ + dpkg --add-architecture s390x && \ + dpkg --add-architecture armhf && \ + dpkg --add-architecture arm64 && \ + dpkg --add-architecture ppc64el + +# dkpg-dev: to make pkg-config work in cross-builds +# llvm: for llvm-symbolizer, which is used by clang's UBSan for symbolized stack traces +RUN apt-get update && apt-get install --no-install-recommends -y \ + git ca-certificates \ + make automake libtool pkg-config dpkg-dev valgrind qemu-user \ + gcc clang llvm libclang-rt-dev libc6-dbg \ + g++ \ + gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan8:i386 \ + gcc-s390x-linux-gnu libc6-dev-s390x-cross libc6-dbg:s390x \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \ + gcc-mingw-w64-x86-64-win32 wine64 wine \ + gcc-mingw-w64-i686-win32 wine32 \ + python3 && \ + if ! ( dpkg --print-architecture | grep --quiet "arm64" ) ; then \ + apt-get install --no-install-recommends -y \ + gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 ;\ + fi && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# Build and install gcc snapshot +ARG GCC_SNAPSHOT_MAJOR=15 +RUN apt-get update && apt-get install --no-install-recommends -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \ + mkdir gcc && cd gcc && \ + wget --progress=dot:giga --https-only --recursive --accept '*.tar.xz' --level 1 --no-directories "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}" && \ + wget "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}/sha512.sum" && \ + sha512sum --check --ignore-missing sha512.sum && \ + # We should have downloaded exactly one tar.xz file + ls && \ + [ $(ls *.tar.xz | wc -l) -eq "1" ] && \ + tar xf *.tar.xz && \ + mkdir gcc-build && cd gcc-build && \ + ../*/configure --prefix=/opt/gcc-snapshot --enable-languages=c --disable-bootstrap --disable-multilib --without-isl && \ + make -j $(nproc) && \ + make install && \ + cd ../.. && rm -rf gcc && \ + ln -s /opt/gcc-snapshot/bin/gcc /usr/bin/gcc-snapshot && \ + apt-get autoremove -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# Install clang snapshot, see https://apt.llvm.org/ +RUN \ + # Setup GPG keys of LLVM repository + apt-get update && apt-get install --no-install-recommends -y wget && \ + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && \ + # Add repository for this Debian release + . /etc/os-release && echo "deb http://apt.llvm.org/${VERSION_CODENAME} llvm-toolchain-${VERSION_CODENAME} main" >> /etc/apt/sources.list && \ + apt-get update && \ + # Determine the version number of the LLVM development branch + LLVM_VERSION=$(apt-cache search --names-only '^clang-[0-9]+$' | sort -V | tail -1 | cut -f1 -d" " | cut -f2 -d"-" ) && \ + # Install + apt-get install --no-install-recommends -y "clang-${LLVM_VERSION}" && \ + # Create symlink + ln -s "/usr/bin/clang-${LLVM_VERSION}" /usr/bin/clang-snapshot && \ + # Clean up + apt-get autoremove -y wget && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/CheckArm32Assembly.cmake b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/CheckArm32Assembly.cmake new file mode 100644 index 00000000..baeeff02 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/CheckArm32Assembly.cmake @@ -0,0 +1,6 @@ +function(check_arm32_assembly) + try_compile(HAVE_ARM32_ASM + ${PROJECT_BINARY_DIR}/check_arm32_assembly + SOURCES ${PROJECT_SOURCE_DIR}/cmake/source_arm32.s + ) +endfunction() diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/CheckMemorySanitizer.cmake b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/CheckMemorySanitizer.cmake new file mode 100644 index 00000000..d9ef681e --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/CheckMemorySanitizer.cmake @@ -0,0 +1,18 @@ +include_guard(GLOBAL) +include(CheckCSourceCompiles) + +function(check_memory_sanitizer output) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + check_c_source_compiles(" + #if defined(__has_feature) + # if __has_feature(memory_sanitizer) + /* MemorySanitizer is enabled. */ + # elif + # error \"MemorySanitizer is disabled.\" + # endif + #else + # error \"__has_feature is not defined.\" + #endif + " HAVE_MSAN) + set(${output} ${HAVE_MSAN} PARENT_SCOPE) +endfunction() diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/CheckStringOptionValue.cmake b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/CheckStringOptionValue.cmake new file mode 100644 index 00000000..5a4d939b --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/CheckStringOptionValue.cmake @@ -0,0 +1,10 @@ +function(check_string_option_value option) + get_property(expected_values CACHE ${option} PROPERTY STRINGS) + if(expected_values) + if(${option} IN_LIST expected_values) + return() + endif() + message(FATAL_ERROR "${option} value is \"${${option}}\", but must be one of ${expected_values}.") + endif() + message(AUTHOR_WARNING "The STRINGS property must be set before invoking `check_string_option_value' function.") +endfunction() diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/CheckX86_64Assembly.cmake b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/CheckX86_64Assembly.cmake new file mode 100644 index 00000000..ae82cd47 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/CheckX86_64Assembly.cmake @@ -0,0 +1,14 @@ +include(CheckCSourceCompiles) + +function(check_x86_64_assembly) + check_c_source_compiles(" + #include + + int main() + { + uint64_t a = 11, tmp; + __asm__ __volatile__(\"movq $0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\"); + } + " HAVE_X86_64_ASM) + set(HAVE_X86_64_ASM ${HAVE_X86_64_ASM} PARENT_SCOPE) +endfunction() diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/FindValgrind.cmake b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/FindValgrind.cmake new file mode 100644 index 00000000..3af5e691 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/FindValgrind.cmake @@ -0,0 +1,41 @@ +if(CMAKE_HOST_APPLE) + find_program(BREW_COMMAND brew) + execute_process( + COMMAND ${BREW_COMMAND} --prefix valgrind + OUTPUT_VARIABLE valgrind_brew_prefix + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endif() + +set(hints_paths) +if(valgrind_brew_prefix) + set(hints_paths ${valgrind_brew_prefix}/include) +endif() + +find_path(Valgrind_INCLUDE_DIR + NAMES valgrind/memcheck.h + HINTS ${hints_paths} +) + +if(Valgrind_INCLUDE_DIR) + include(CheckCSourceCompiles) + set(CMAKE_REQUIRED_INCLUDES ${Valgrind_INCLUDE_DIR}) + check_c_source_compiles(" + #include + #if defined(NVALGRIND) + # error \"Valgrind does not support this platform.\" + #endif + + int main() {} + " Valgrind_WORKS) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Valgrind + REQUIRED_VARS Valgrind_INCLUDE_DIR Valgrind_WORKS +) + +mark_as_advanced( + Valgrind_INCLUDE_DIR +) diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/GeneratePkgConfigFile.cmake b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/GeneratePkgConfigFile.cmake new file mode 100644 index 00000000..9c1d7f1d --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/GeneratePkgConfigFile.cmake @@ -0,0 +1,8 @@ +function(generate_pkg_config_file in_file) + set(prefix ${CMAKE_INSTALL_PREFIX}) + set(exec_prefix \${prefix}) + set(libdir \${exec_prefix}/${CMAKE_INSTALL_LIBDIR}) + set(includedir \${prefix}/${CMAKE_INSTALL_INCLUDEDIR}) + set(PACKAGE_VERSION ${PROJECT_VERSION}) + configure_file(${in_file} ${PROJECT_NAME}.pc @ONLY) +endfunction() diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/TryAppendCFlags.cmake b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/TryAppendCFlags.cmake new file mode 100644 index 00000000..251cb61c --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/TryAppendCFlags.cmake @@ -0,0 +1,24 @@ +include(CheckCCompilerFlag) + +function(rustsecp256k1_v0_11_check_c_flags_internal flags output) + string(MAKE_C_IDENTIFIER "${flags}" result) + string(TOUPPER "${result}" result) + set(result "C_SUPPORTS_${result}") + if(NOT MSVC) + set(CMAKE_REQUIRED_FLAGS "-Werror") + endif() + + # This avoids running a linker. + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + check_c_compiler_flag("${flags}" ${result}) + + set(${output} ${${result}} PARENT_SCOPE) +endfunction() + +# Append flags to the COMPILE_OPTIONS directory property if CC accepts them. +macro(try_append_c_flags) + rustsecp256k1_v0_11_check_c_flags_internal("${ARGV}" result) + if(result) + add_compile_options(${ARGV}) + endif() +endmacro() diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake new file mode 100644 index 00000000..0d91912b --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake @@ -0,0 +1,3 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR arm) +set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/config.cmake.in b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/config.cmake.in new file mode 100644 index 00000000..46b180ab --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/config.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake") + +check_required_components(@PROJECT_NAME@) diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/source_arm32.s b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/source_arm32.s new file mode 100644 index 00000000..d3d93470 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/source_arm32.s @@ -0,0 +1,9 @@ +.syntax unified +.eabi_attribute 24, 1 +.eabi_attribute 25, 1 +.text +.global main +main: + ldr r0, =0x002A + mov r7, #1 + swi 0 diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake new file mode 100644 index 00000000..96119b72 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake @@ -0,0 +1,3 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86_64) +set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/configure.ac b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/configure.ac new file mode 100644 index 00000000..f880a357 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/configure.ac @@ -0,0 +1,517 @@ +AC_PREREQ([2.60]) + +# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of +# the API. All changes in experimental modules are treated as +# backwards-compatible and therefore at most increase the minor version. +define(_PKG_VERSION_MAJOR, 0) +define(_PKG_VERSION_MINOR, 6) +define(_PKG_VERSION_PATCH, 0) +define(_PKG_VERSION_IS_RELEASE, true) + +# The library version is based on libtool versioning of the ABI. The set of +# rules for updating the version can be found here: +# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +# All changes in experimental modules are treated as if they don't affect the +# interface and therefore only increase the revision. +define(_LIB_VERSION_CURRENT, 5) +define(_LIB_VERSION_REVISION, 0) +define(_LIB_VERSION_AGE, 0) + +AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1]) + +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([build-aux/m4]) +AC_CANONICAL_HOST + +# Require Automake 1.11.2 for AM_PROG_AR +AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects]) + +# Make the compilation flags quiet unless V=1 is used. +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +if test "${CFLAGS+set}" = "set"; then + CFLAGS_overridden=yes +else + CFLAGS_overridden=no +fi +AC_PROG_CC +AM_PROG_AS +AM_PROG_AR + +# Clear some cache variables as a workaround for a bug that appears due to a bad +# interaction between AM_PROG_AR and LT_INIT when combining MSVC's archiver lib.exe. +# https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54421 +AS_UNSET(ac_cv_prog_AR) +AS_UNSET(ac_cv_prog_ac_ct_AR) +LT_INIT([win32-dll]) + +build_windows=no + +case $host_os in + *darwin*) + if test x$cross_compiling != xyes; then + AC_CHECK_PROG([BREW], brew, brew) + if test x$BREW = xbrew; then + # These Homebrew packages may be keg-only, meaning that they won't be found + # in expected paths because they may conflict with system files. Ask + # Homebrew where each one is located, then adjust paths accordingly. + if $BREW list --versions valgrind >/dev/null; then + valgrind_prefix=$($BREW --prefix valgrind 2>/dev/null) + VALGRIND_CPPFLAGS="-I$valgrind_prefix/include" + fi + else + AC_CHECK_PROG([PORT], port, port) + # If homebrew isn't installed and macports is, add the macports default paths + # as a last resort. + if test x$PORT = xport; then + CPPFLAGS="$CPPFLAGS -isystem /opt/local/include" + LDFLAGS="$LDFLAGS -L/opt/local/lib" + fi + fi + fi + ;; + cygwin*|mingw*) + build_windows=yes + ;; +esac + +# Try if some desirable compiler flags are supported and append them to SECP_CFLAGS. +# +# These are our own flags, so we append them to our own SECP_CFLAGS variable (instead of CFLAGS) as +# recommended in the automake manual (Section "Flag Variables Ordering"). CFLAGS belongs to the user +# and we are not supposed to touch it. In the Makefile, we will need to ensure that SECP_CFLAGS +# is prepended to CFLAGS when invoking the compiler so that the user always has the last word (flag). +# +# Another advantage of not touching CFLAGS is that the contents of CFLAGS will be picked up by +# libtool for compiling helper executables. For example, when compiling for Windows, libtool will +# generate entire wrapper executables (instead of simple wrapper scripts as on Unix) to ensure +# proper operation of uninstalled programs linked by libtool against the uninstalled shared library. +# These executables are compiled from C source file for which our flags may not be appropriate, +# e.g., -std=c89 flag has lead to undesirable warnings in the past. +# +# TODO We should analogously not touch CPPFLAGS and LDFLAGS but currently there are no issues. +AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [ + # GCC and compatible (incl. clang) + if test "x$GCC" = "xyes"; then + # Try to append -Werror to CFLAGS temporarily. Otherwise checks for some unsupported + # flags will succeed. + # Note that failure to append -Werror does not necessarily mean that -Werror is not + # supported. The compiler may already be warning about something unrelated, for example + # about some path issue. If that is the case, -Werror cannot be used because all + # of those warnings would be turned into errors. + SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS" + SECP_TRY_APPEND_CFLAGS([-Werror], CFLAGS) + + SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic. + SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic. + SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers + SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall. + SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions. + SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95 + SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0 + SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only + SECP_TRY_APPEND_CFLAGS([-Wreserved-identifier], $1) # Clang >= 13.0 only + SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0 + + CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS" + fi + + # MSVC + # Assume MSVC if we're building for Windows but not with GCC or compatible; + # libtool makes the same assumption internally. + # Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path. + if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then + SECP_TRY_APPEND_CFLAGS([-W3], $1) # Production quality warning level. + SECP_TRY_APPEND_CFLAGS([-wd4146], $1) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned". + SECP_TRY_APPEND_CFLAGS([-wd4244], $1) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data". + SECP_TRY_APPEND_CFLAGS([-wd4267], $1) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data". + # Eliminate deprecation warnings for the older, less secure functions. + CPPFLAGS="-D_CRT_SECURE_NO_WARNINGS $CPPFLAGS" + fi +]) +SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS) + +### +### Define config arguments +### + +# In dev mode, we enable all binaries and modules by default but individual options can still be overridden explicitly. +# Check for dev mode first because SECP_SET_DEFAULT needs enable_dev_mode set. +AC_ARG_ENABLE(dev_mode, [], [], + [enable_dev_mode=no]) + +AC_ARG_ENABLE(benchmark, + AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]), [], + [SECP_SET_DEFAULT([enable_benchmark], [yes], [yes])]) + +AC_ARG_ENABLE(coverage, + AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]), [], + [SECP_SET_DEFAULT([enable_coverage], [no], [no])]) + +AC_ARG_ENABLE(tests, + AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [], + [SECP_SET_DEFAULT([enable_tests], [yes], [yes])]) + +AC_ARG_ENABLE(ctime_tests, + AS_HELP_STRING([--enable-ctime-tests],[compile constant-time tests [default=yes if valgrind enabled]]), [], + [SECP_SET_DEFAULT([enable_ctime_tests], [auto], [auto])]) + +AC_ARG_ENABLE(experimental, + AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [], + [SECP_SET_DEFAULT([enable_experimental], [no], [yes])]) + +AC_ARG_ENABLE(exhaustive_tests, + AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]), [], + [SECP_SET_DEFAULT([enable_exhaustive_tests], [yes], [yes])]) + +AC_ARG_ENABLE(examples, + AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [], + [SECP_SET_DEFAULT([enable_examples], [no], [yes])]) + +AC_ARG_ENABLE(module_ecdh, + AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_ecdh], [yes], [yes])]) + +AC_ARG_ENABLE(module_recovery, + AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [], + [SECP_SET_DEFAULT([enable_module_recovery], [no], [yes])]) + +AC_ARG_ENABLE(module_extrakeys, + AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_extrakeys], [yes], [yes])]) + +AC_ARG_ENABLE(module_schnorrsig, + AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])]) + +AC_ARG_ENABLE(module_musig, + AS_HELP_STRING([--enable-module-musig],[enable MuSig2 module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_musig], [yes], [yes])]) + +AC_ARG_ENABLE(module_ellswift, + AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])]) + +AC_ARG_ENABLE(external_default_callbacks, + AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [], + [SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])]) + +# Test-only override of the (autodetected by the C code) "widemul" setting. +# Legal values are: +# * int64 (for [u]int64_t), +# * int128 (for [unsigned] __int128), +# * int128_struct (for int128 implemented as a structure), +# * and auto (the default). +AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto]) + +AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm32|no|auto], +[assembly to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto]) + +AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE], +[window size for ecmult precomputation for verification, specified as integer in range [2..24].] +[Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.] +[The table will store 2^(SIZE-1) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.] +[A window size larger than 15 will require you delete the prebuilt precomputed_ecmult.c file so that it can be rebuilt.] +[For very large window sizes, use "make -j 1" to reduce memory use during compilation.] +[The default value is a reasonable setting for desktop machines (currently 15). [default=15]] +)], +[set_ecmult_window=$withval], [set_ecmult_window=15]) + +AC_ARG_WITH([ecmult-gen-kb], [AS_HELP_STRING([--with-ecmult-gen-kb=2|22|86], +[The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms).] +[Larger values result in possibly better signing/keygeneration performance at the cost of a larger table.] +[The default value is a reasonable setting for desktop machines (currently 86). [default=86]] +)], +[set_ecmult_gen_kb=$withval], [set_ecmult_gen_kb=86]) + +AC_ARG_WITH([valgrind], [AS_HELP_STRING([--with-valgrind=yes|no|auto], +[Build with extra checks for running inside Valgrind [default=auto]] +)], +[req_valgrind=$withval], [req_valgrind=auto]) + +### +### Handle config options (except for modules) +### + +if test x"$req_valgrind" = x"no"; then + enable_valgrind=no +else + SECP_VALGRIND_CHECK + if test x"$has_valgrind" != x"yes"; then + if test x"$req_valgrind" = x"yes"; then + AC_MSG_ERROR([Valgrind support explicitly requested but valgrind/memcheck.h header not available]) + fi + enable_valgrind=no + else + enable_valgrind=yes + fi +fi + +if test x"$enable_ctime_tests" = x"auto"; then + enable_ctime_tests=$enable_valgrind +fi + +print_msan_notice=no +if test x"$enable_ctime_tests" = x"yes"; then + SECP_MSAN_CHECK + # MSan on Clang >=16 reports unitialized memory in function parameters and return values, even if + # the uninitalized variable is never actually "used". This is called "eager" checking, and it's + # sounds like good idea for normal use of MSan. However, it yields many false positives in the + # ctime_tests because many return values depend on secret (i.e., "uninitialized") values, and + # we're only interested in detecting branches (which count as "uses") on secret data. + if test x"$msan_enabled" = x"yes"; then + SECP_TRY_APPEND_CFLAGS([-fno-sanitize-memory-param-retval], SECP_CFLAGS) + print_msan_notice=yes + fi +fi + +if test x"$enable_coverage" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOVERAGE=1" + SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS" + # If coverage is enabled, and the user has not overridden CFLAGS, + # override Autoconf's value "-g -O2" with "-g". Otherwise we'd end up + # with "-O0 --coverage -g -O2". + if test "$CFLAGS_overridden" = "no"; then + CFLAGS="-g" + fi + LDFLAGS="--coverage $LDFLAGS" +else + # Most likely the CFLAGS already contain -O2 because that is autoconf's default. + # We still add it here because passing it twice is not an issue, and handling + # this case would just add unnecessary complexity (see #896). + SECP_CFLAGS="-O2 $SECP_CFLAGS" +fi + +if test x"$req_asm" = x"auto"; then + SECP_X86_64_ASM_CHECK + if test x"$has_x86_64_asm" = x"yes"; then + set_asm=x86_64 + fi + if test x"$set_asm" = x; then + set_asm=no + fi +else + set_asm=$req_asm + case $set_asm in + x86_64) + SECP_X86_64_ASM_CHECK + if test x"$has_x86_64_asm" != x"yes"; then + AC_MSG_ERROR([x86_64 assembly requested but not available]) + fi + ;; + arm32) + SECP_ARM32_ASM_CHECK + if test x"$has_arm32_asm" != x"yes"; then + AC_MSG_ERROR([ARM32 assembly requested but not available]) + fi + ;; + no) + ;; + *) + AC_MSG_ERROR([invalid assembly selection]) + ;; + esac +fi + +# Select assembly +enable_external_asm=no + +case $set_asm in +x86_64) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_ASM_X86_64=1" + ;; +arm32) + enable_external_asm=yes + ;; +no) + ;; +*) + AC_MSG_ERROR([invalid assembly selection]) + ;; +esac + +if test x"$enable_external_asm" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_ASM=1" +fi + + +# Select wide multiplication implementation +case $set_widemul in +int128_struct) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128_STRUCT=1" + ;; +int128) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128=1" + ;; +int64) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT64=1" + ;; +auto) + ;; +*) + AC_MSG_ERROR([invalid wide multiplication implementation]) + ;; +esac + +error_window_size=['window size for ecmult precomputation not an integer in range [2..24]'] +case $set_ecmult_window in +''|*[[!0-9]]*) + # no valid integer + AC_MSG_ERROR($error_window_size) + ;; +*) + if test "$set_ecmult_window" -lt 2 -o "$set_ecmult_window" -gt 24 ; then + # not in range + AC_MSG_ERROR($error_window_size) + fi + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DECMULT_WINDOW_SIZE=$set_ecmult_window" + ;; +esac + +case $set_ecmult_gen_kb in +2) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=2 -DCOMB_TEETH=5" + ;; +22) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=11 -DCOMB_TEETH=6" + ;; +86) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=43 -DCOMB_TEETH=6" + ;; +*) + AC_MSG_ERROR(['ecmult gen table size not 2, 22 or 86']) + ;; +esac + +if test x"$enable_valgrind" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES $VALGRIND_CPPFLAGS -DVALGRIND" +fi + +# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI). +# We don't want to set the user variable CFLAGS in CI because this would disable +# autoconf's logic for setting default CFLAGS, which we would like to test in CI. +SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS" + +### +### Handle module options +### + +# Processing must be done in a reverse topological sorting of the dependency graph +# (dependent module first). +if test x"$enable_module_ellswift" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1" +fi + +if test x"$enable_module_musig" = x"yes"; then + if test x"$enable_module_schnorrsig" = x"no"; then + AC_MSG_ERROR([Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.]) + fi + enable_module_schnorrsig=yes + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_MUSIG=1" +fi + +if test x"$enable_module_schnorrsig" = x"yes"; then + if test x"$enable_module_extrakeys" = x"no"; then + AC_MSG_ERROR([Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.]) + fi + enable_module_extrakeys=yes + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG=1" +fi + +if test x"$enable_module_extrakeys" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_EXTRAKEYS=1" +fi + +if test x"$enable_module_recovery" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_RECOVERY=1" +fi + +if test x"$enable_module_ecdh" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1" +fi + +if test x"$enable_external_default_callbacks" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_DEFAULT_CALLBACKS=1" +fi + +### +### Check for --enable-experimental if necessary +### + +if test x"$enable_experimental" = x"no"; then + if test x"$set_asm" = x"arm32"; then + AC_MSG_ERROR([ARM32 assembly is experimental. Use --enable-experimental to allow.]) + fi +fi + +### +### Generate output +### + +AC_CONFIG_FILES([Makefile libsecp256k1.pc]) +AC_SUBST(SECP_CFLAGS) +AC_SUBST(SECP_CONFIG_DEFINES) +AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) +AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"]) +AM_CONDITIONAL([USE_CTIME_TESTS], [test x"$enable_ctime_tests" = x"yes"]) +AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"]) +AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"]) +AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"]) +AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"]) +AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"]) +AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"]) +AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT) +AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION) +AC_SUBST(LIB_VERSION_AGE, _LIB_VERSION_AGE) + +AC_OUTPUT + +echo +echo "Build Options:" +echo " with external callbacks = $enable_external_default_callbacks" +echo " with benchmarks = $enable_benchmark" +echo " with tests = $enable_tests" +echo " with ctime tests = $enable_ctime_tests" +echo " with coverage = $enable_coverage" +echo " with examples = $enable_examples" +echo " module ecdh = $enable_module_ecdh" +echo " module recovery = $enable_module_recovery" +echo " module extrakeys = $enable_module_extrakeys" +echo " module schnorrsig = $enable_module_schnorrsig" +echo " module musig = $enable_module_musig" +echo " module ellswift = $enable_module_ellswift" +echo +echo " asm = $set_asm" +echo " ecmult window size = $set_ecmult_window" +echo " ecmult gen table size = $set_ecmult_gen_kb KiB" +# Hide test-only options unless they're used. +if test x"$set_widemul" != xauto; then +echo " wide multiplication = $set_widemul" +fi +echo +echo " valgrind = $enable_valgrind" +echo " CC = $CC" +echo " CPPFLAGS = $CPPFLAGS" +echo " SECP_CFLAGS = $SECP_CFLAGS" +echo " CFLAGS = $CFLAGS" +echo " LDFLAGS = $LDFLAGS" + +if test x"$print_msan_notice" = x"yes"; then + echo + echo "Note:" + echo " MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to SECP_CFLAGS" + echo " to avoid false positives in ctime_tests. Pass --disable-ctime-tests to avoid this." +fi + +if test x"$enable_experimental" = x"yes"; then + echo + echo "WARNING: Experimental build" + echo " Experimental features do not have stable APIs or properties, and may not be safe for" + echo " production use." +fi diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/lax_der_parsing.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/contrib/lax_der_parsing.c similarity index 84% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/lax_der_parsing.c rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/contrib/lax_der_parsing.c index f3ac2927..82b0a3a6 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/lax_der_parsing.c +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/contrib/lax_der_parsing.c @@ -7,8 +7,10 @@ #include #include "lax_der_parsing.h" - -int rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der_lax(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { +extern int rustsecp256k1_v0_11_ecdsa_signature_parse_compact( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_ecdsa_signature *sig, const unsigned char *input64); +int rustsecp256k1_v0_11_ecdsa_signature_parse_der_lax(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { size_t rpos, rlen, spos, slen; size_t pos = 0; size_t lenbyte; @@ -16,7 +18,7 @@ int rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der_lax(const rustsecp256k1zkp int overflow = 0; /* Hack to initialize sig with a correctly-parsed but invalid signature. */ - rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + rustsecp256k1_v0_11_ecdsa_signature_parse_compact(ctx, sig, tmpsig); /* Sequence tag byte */ if (pos == inputlen || input[pos] != 0x30) { @@ -137,11 +139,11 @@ int rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der_lax(const rustsecp256k1zkp } if (!overflow) { - overflow = !rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + overflow = !rustsecp256k1_v0_11_ecdsa_signature_parse_compact(ctx, sig, tmpsig); } if (overflow) { memset(tmpsig, 0, 64); - rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + rustsecp256k1_v0_11_ecdsa_signature_parse_compact(ctx, sig, tmpsig); } return 1; } diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/lax_der_parsing.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/contrib/lax_der_parsing.h similarity index 90% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/lax_der_parsing.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/contrib/lax_der_parsing.h index 315650aa..633d9310 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/lax_der_parsing.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/contrib/lax_der_parsing.h @@ -26,8 +26,8 @@ * certain violations are easily supported. You may need to adapt it. * * Do not use this for new systems. Use well-defined DER or compact signatures - * instead if you have the choice (see rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der and - * rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact). + * instead if you have the choice (see rustsecp256k1_v0_11_ecdsa_signature_parse_der and + * rustsecp256k1_v0_11_ecdsa_signature_parse_compact). * * The supported violations are: * - All numbers are parsed as nonnegative integers, even though X.609-0207 @@ -67,8 +67,8 @@ extern "C" { * * Returns: 1 when the signature could be parsed, 0 otherwise. * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input: a pointer to the signature to be parsed + * Out: sig: pointer to a signature object + * In: input: pointer to the signature to be parsed * inputlen: the length of the array pointed to be input * * This function will accept any valid DER encoded signature, even if the @@ -83,9 +83,9 @@ extern "C" { * encoded numbers are out of range, signature validation with it is * guaranteed to fail for every message and public key. */ -int rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der_lax( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, +int rustsecp256k1_v0_11_ecdsa_signature_parse_der_lax( + const rustsecp256k1_v0_11_context* ctx, + rustsecp256k1_v0_11_ecdsa_signature* sig, const unsigned char *input, size_t inputlen ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/lax_der_privatekey_parsing.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/contrib/lax_der_privatekey_parsing.c similarity index 86% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/lax_der_privatekey_parsing.c rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/contrib/lax_der_privatekey_parsing.c index ebdeb11d..3f0a7553 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/lax_der_privatekey_parsing.c +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/contrib/lax_der_privatekey_parsing.c @@ -8,7 +8,7 @@ #include "lax_der_privatekey_parsing.h" -int ec_privkey_import_der(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) { +int ec_privkey_import_der(const rustsecp256k1_v0_11_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) { const unsigned char *end = privkey + privkeylen; int lenb = 0; int len = 0; @@ -45,17 +45,17 @@ int ec_privkey_import_der(const rustsecp256k1zkp_v0_8_0_context* ctx, unsigned c return 0; } if (privkey[1]) memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); - if (!rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, out32)) { + if (!rustsecp256k1_v0_11_ec_seckey_verify(ctx, out32)) { memset(out32, 0, 32); return 0; } return 1; } -int ec_privkey_export_der(const rustsecp256k1zkp_v0_8_0_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { - rustsecp256k1zkp_v0_8_0_pubkey pubkey; +int ec_privkey_export_der(const rustsecp256k1_v0_11_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { + rustsecp256k1_v0_11_pubkey pubkey; size_t pubkeylen = 0; - if (!rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, key32)) { + if (!rustsecp256k1_v0_11_ec_pubkey_create(ctx, &pubkey, key32)) { *privkeylen = 0; return 0; } @@ -79,7 +79,7 @@ int ec_privkey_export_der(const rustsecp256k1zkp_v0_8_0_context *ctx, unsigned c memcpy(ptr, key32, 32); ptr += 32; memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); pubkeylen = 33; - rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); + rustsecp256k1_v0_11_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); ptr += pubkeylen; *privkeylen = ptr - privkey; } else { @@ -104,7 +104,7 @@ int ec_privkey_export_der(const rustsecp256k1zkp_v0_8_0_context *ctx, unsigned c memcpy(ptr, key32, 32); ptr += 32; memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); pubkeylen = 65; - rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); + rustsecp256k1_v0_11_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); ptr += pubkeylen; *privkeylen = ptr - privkey; } diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/lax_der_privatekey_parsing.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/contrib/lax_der_privatekey_parsing.h similarity index 92% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/lax_der_privatekey_parsing.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/contrib/lax_der_privatekey_parsing.h index c9363778..01d2518f 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/lax_der_privatekey_parsing.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/contrib/lax_der_privatekey_parsing.h @@ -43,8 +43,7 @@ extern "C" { /** Export a private key in DER format. * * Returns: 1 if the private key was valid. - * Args: ctx: pointer to a context object, initialized for signing (cannot - * be NULL) + * Args: ctx: pointer to a context object (not rustsecp256k1_v0_11_context_static). * Out: privkey: pointer to an array for storing the private key in BER. * Should have space for 279 bytes, and cannot be NULL. * privkeylen: Pointer to an int where the length of the private key in @@ -58,10 +57,10 @@ extern "C" { * simple 32-byte private keys are sufficient. * * Note that this function does not guarantee correct DER output. It is - * guaranteed to be parsable by rustsecp256k1zkp_v0_8_0_ec_privkey_import_der + * guaranteed to be parsable by rustsecp256k1_v0_11_ec_privkey_import_der */ SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der( - const rustsecp256k1zkp_v0_8_0_context* ctx, + const rustsecp256k1_v0_11_context* ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *seckey, @@ -83,7 +82,7 @@ SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der( * key. */ SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der( - const rustsecp256k1zkp_v0_8_0_context* ctx, + const rustsecp256k1_v0_11_context* ctx, unsigned char *seckey, const unsigned char *privkey, size_t privkeylen diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/doc/ellswift.md b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/doc/ellswift.md new file mode 100644 index 00000000..64885a32 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/doc/ellswift.md @@ -0,0 +1,483 @@ +# ElligatorSwift for secp256k1 explained + +In this document we explain how the `ellswift` module implementation is related to the +construction in the +["SwiftEC: Shallue–van de Woestijne Indifferentiable Function To Elliptic Curves"](https://eprint.iacr.org/2022/759) +paper by Jorge Chávez-Saab, Francisco Rodríguez-Henríquez, and Mehdi Tibouchi. + +* [1. Introduction](#1-introduction) +* [2. The decoding function](#2-the-decoding-function) + + [2.1 Decoding for `secp256k1`](#21-decoding-for-secp256k1) +* [3. The encoding function](#3-the-encoding-function) + + [3.1 Switching to *v, w* coordinates](#31-switching-to-v-w-coordinates) + + [3.2 Avoiding computing all inverses](#32-avoiding-computing-all-inverses) + + [3.3 Finding the inverse](#33-finding-the-inverse) + + [3.4 Dealing with special cases](#34-dealing-with-special-cases) + + [3.5 Encoding for `secp256k1`](#35-encoding-for-secp256k1) +* [4. Encoding and decoding full *(x, y)* coordinates](#4-encoding-and-decoding-full-x-y-coordinates) + + [4.1 Full *(x, y)* coordinates for `secp256k1`](#41-full-x-y-coordinates-for-secp256k1) + +## 1. Introduction + +The `ellswift` module effectively introduces a new 64-byte public key format, with the property +that (uniformly random) public keys can be encoded as 64-byte arrays which are computationally +indistinguishable from uniform byte arrays. The module provides functions to convert public keys +from and to this format, as well as convenience functions for key generation and ECDH that operate +directly on ellswift-encoded keys. + +The encoding consists of the concatenation of two (32-byte big endian) encoded field elements $u$ +and $t.$ Together they encode an x-coordinate on the curve $x$, or (see further) a full point $(x, y)$ on +the curve. + +**Decoding** consists of decoding the field elements $u$ and $t$ (values above the field size $p$ +are taken modulo $p$), and then evaluating $F_u(t)$, which for every $u$ and $t$ results in a valid +x-coordinate on the curve. The functions $F_u$ will be defined in [Section 2](#2-the-decoding-function). + +**Encoding** a given $x$ coordinate is conceptually done as follows: +* Loop: + * Pick a uniformly random field element $u.$ + * Compute the set $L = F_u^{-1}(x)$ of $t$ values for which $F_u(t) = x$, which may have up to *8* elements. + * With probability $1 - \dfrac{\\#L}{8}$, restart the loop. + * Select a uniformly random $t \in L$ and return $(u, t).$ + +This is the *ElligatorSwift* algorithm, here given for just x-coordinates. An extension to full +$(x, y)$ points will be given in [Section 4](#4-encoding-and-decoding-full-x-y-coordinates). +The algorithm finds a uniformly random $(u, t)$ among (almost all) those +for which $F_u(t) = x.$ Section 3.2 in the paper proves that the number of such encodings for +almost all x-coordinates on the curve (all but at most 39) is close to two times the field size +(specifically, it lies in the range $2q \pm (22\sqrt{q} + O(1))$, where $q$ is the size of the field). + +## 2. The decoding function + +First some definitions: +* $\mathbb{F}$ is the finite field of size $q$, of characteristic 5 or more, and $q \equiv 1 \mod 3.$ + * For `secp256k1`, $q = 2^{256} - 2^{32} - 977$, which satisfies that requirement. +* Let $E$ be the elliptic curve of points $(x, y) \in \mathbb{F}^2$ for which $y^2 = x^3 + ax + b$, with $a$ and $b$ + public constants, for which $\Delta_E = -16(4a^3 + 27b^2)$ is a square, and at least one of $(-b \pm \sqrt{-3 \Delta_E} / 36)/2$ is a square. + This implies that the order of $E$ is either odd, or a multiple of *4*. + If $a=0$, this condition is always fulfilled. + * For `secp256k1`, $a=0$ and $b=7.$ +* Let the function $g(x) = x^3 + ax + b$, so the $E$ curve equation is also $y^2 = g(x).$ +* Let the function $h(x) = 3x^3 + 4a.$ +* Define $V$ as the set of solutions $(x_1, x_2, x_3, z)$ to $z^2 = g(x_1)g(x_2)g(x_3).$ +* Define $S_u$ as the set of solutions $(X, Y)$ to $X^2 + h(u)Y^2 = -g(u)$ and $Y \neq 0.$ +* $P_u$ is a function from $\mathbb{F}$ to $S_u$ that will be defined below. +* $\psi_u$ is a function from $S_u$ to $V$ that will be defined below. + +**Note**: In the paper: +* $F_u$ corresponds to $F_{0,u}$ there. +* $P_u(t)$ is called $P$ there. +* All $S_u$ sets together correspond to $S$ there. +* All $\psi_u$ functions together (operating on elements of $S$) correspond to $\psi$ there. + +Note that for $V$, the left hand side of the equation $z^2$ is square, and thus the right +hand must also be square. As multiplying non-squares results in a square in $\mathbb{F}$, +out of the three right-hand side factors an even number must be non-squares. +This implies that exactly *1* or exactly *3* out of +$\\{g(x_1), g(x_2), g(x_3)\\}$ must be square, and thus that for any $(x_1,x_2,x_3,z) \in V$, +at least one of $\\{x_1, x_2, x_3\\}$ must be a valid x-coordinate on $E.$ There is one exception +to this, namely when $z=0$, but even then one of the three values is a valid x-coordinate. + +**Define** the decoding function $F_u(t)$ as: +* Let $(x_1, x_2, x_3, z) = \psi_u(P_u(t)).$ +* Return the first element $x$ of $(x_3, x_2, x_1)$ which is a valid x-coordinate on $E$ (i.e., $g(x)$ is square). + +$P_u(t) = (X(u, t), Y(u, t))$, where: + +$$ +\begin{array}{lcl} +X(u, t) & = & \left\\{\begin{array}{ll} + \dfrac{g(u) - t^2}{2t} & a = 0 \\ + \dfrac{g(u) + h(u)(Y_0(u) - X_0(u)t)^2}{X_0(u)(1 + h(u)t^2)} & a \neq 0 +\end{array}\right. \\ +Y(u, t) & = & \left\\{\begin{array}{ll} + \dfrac{X(u, t) + t}{u \sqrt{-3}} = \dfrac{g(u) + t^2}{2tu\sqrt{-3}} & a = 0 \\ + Y_0(u) + t(X(u, t) - X_0(u)) & a \neq 0 +\end{array}\right. +\end{array} +$$ + +$P_u(t)$ is defined: +* For $a=0$, unless: + * $u = 0$ or $t = 0$ (division by zero) + * $g(u) = -t^2$ (would give $Y=0$). +* For $a \neq 0$, unless: + * $X_0(u) = 0$ or $h(u)t^2 = -1$ (division by zero) + * $Y_0(u) (1 - h(u)t^2) = 2X_0(u)t$ (would give $Y=0$). + +The functions $X_0(u)$ and $Y_0(u)$ are defined in Appendix A of the paper, and depend on various properties of $E.$ + +The function $\psi_u$ is the same for all curves: $\psi_u(X, Y) = (x_1, x_2, x_3, z)$, where: + +$$ +\begin{array}{lcl} + x_1 & = & \dfrac{X}{2Y} - \dfrac{u}{2} && \\ + x_2 & = & -\dfrac{X}{2Y} - \dfrac{u}{2} && \\ + x_3 & = & u + 4Y^2 && \\ + z & = & \dfrac{g(x_3)}{2Y}(u^2 + ux_1 + x_1^2 + a) = \dfrac{-g(u)g(x_3)}{8Y^3} +\end{array} +$$ + +### 2.1 Decoding for `secp256k1` + +Put together and specialized for $a=0$ curves, decoding $(u, t)$ to an x-coordinate is: + +**Define** $F_u(t)$ as: +* Let $X = \dfrac{u^3 + b - t^2}{2t}.$ +* Let $Y = \dfrac{X + t}{u\sqrt{-3}}.$ +* Return the first $x$ in $(u + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u}{2}, \dfrac{X}{2Y} - \dfrac{u}{2})$ for which $g(x)$ is square. + +To make sure that every input decodes to a valid x-coordinate, we remap the inputs in case +$P_u$ is not defined (when $u=0$, $t=0$, or $g(u) = -t^2$): + +**Define** $F_u(t)$ as: +* Let $u'=u$ if $u \neq 0$; $1$ otherwise (guaranteeing $u' \neq 0$). +* Let $t'=t$ if $t \neq 0$; $1$ otherwise (guaranteeing $t' \neq 0$). +* Let $t''=t'$ if $g(u') \neq -t'^2$; $2t'$ otherwise (guaranteeing $t'' \neq 0$ and $g(u') \neq -t''^2$). +* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$ +* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$ +* Return the first $x$ in $(u' + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u'}{2}, \dfrac{X}{2Y} - \dfrac{u'}{2})$ for which $x^3 + b$ is square. + +The choices here are not strictly necessary. Just returning a fixed constant in any of the undefined cases would suffice, +but the approach here is simple enough and gives fairly uniform output even in these cases. + +**Note**: in the paper these conditions result in $\infty$ as output, due to the use of projective coordinates there. +We wish to avoid the need for callers to deal with this special case. + +This is implemented in `rustsecp256k1_v0_11_ellswift_xswiftec_frac_var` (which decodes to an x-coordinate represented as a fraction), and +in `rustsecp256k1_v0_11_ellswift_xswiftec_var` (which outputs the actual x-coordinate). + +## 3. The encoding function + +To implement $F_u^{-1}(x)$, the function to find the set of inverses $t$ for which $F_u(t) = x$, we have to reverse the process: +* Find all the $(X, Y) \in S_u$ that could have given rise to $x$, through the $x_1$, $x_2$, or $x_3$ formulas in $\psi_u.$ +* Map those $(X, Y)$ solutions to $t$ values using $P_u^{-1}(X, Y).$ +* For each of the found $t$ values, verify that $F_u(t) = x.$ +* Return the remaining $t$ values. + +The function $P_u^{-1}$, which finds $t$ given $(X, Y) \in S_u$, is significantly simpler than $P_u:$ + +$$ +P_u^{-1}(X, Y) = \left\\{\begin{array}{ll} +Yu\sqrt{-3} - X & a = 0 \\ +\dfrac{Y-Y_0(u)}{X-X_0(u)} & a \neq 0 \land X \neq X_0(u) \\ +\dfrac{-X_0(u)}{h(u)Y_0(u)} & a \neq 0 \land X = X_0(u) \land Y = Y_0(u) +\end{array}\right. +$$ + +The third step above, verifying that $F_u(t) = x$, is necessary because for the $(X, Y)$ values found through the $x_1$ and $x_2$ expressions, +it is possible that decoding through $\psi_u(X, Y)$ yields a valid $x_3$ on the curve, which would take precedence over the +$x_1$ or $x_2$ decoding. These $(X, Y)$ solutions must be rejected. + +Since we know that exactly one or exactly three out of $\\{x_1, x_2, x_3\\}$ are valid x-coordinates for any $t$, +the case where either $x_1$ or $x_2$ is valid and in addition also $x_3$ is valid must mean that all three are valid. +This means that instead of checking whether $x_3$ is on the curve, it is also possible to check whether the other one out of +$x_1$ and $x_2$ is on the curve. This is significantly simpler, as it turns out. + +Observe that $\psi_u$ guarantees that $x_1 + x_2 = -u.$ So given either $x = x_1$ or $x = x_2$, the other one of the two can be computed as +$-u - x.$ Thus, when encoding $x$ through the $x_1$ or $x_2$ expressions, one can simply check whether $g(-u-x)$ is a square, +and if so, not include the corresponding $t$ values in the returned set. As this does not need $X$, $Y$, or $t$, this condition can be determined +before those values are computed. + +It is not possible that an encoding found through the $x_1$ expression decodes to a different valid x-coordinate using $x_2$ (which would +take precedence), for the same reason: if both $x_1$ and $x_2$ decodings were valid, $x_3$ would be valid as well, and thus take +precedence over both. Because of this, the $g(-u-x)$ being square test for $x_1$ and $x_2$ is the only test necessary to guarantee the found $t$ +values round-trip back to the input $x$ correctly. This is the reason for choosing the $(x_3, x_2, x_1)$ precedence order in the decoder; +any order which does not place $x_3$ first requires more complicated round-trip checks in the encoder. + +### 3.1 Switching to *v, w* coordinates + +Before working out the formulas for all this, we switch to different variables for $S_u.$ Let $v = (X/Y - u)/2$, and +$w = 2Y.$ Or in the other direction, $X = w(u/2 + v)$ and $Y = w/2:$ +* $S_u'$ becomes the set of $(v, w)$ for which $w^2 (u^2 + uv + v^2 + a) = -g(u)$ and $w \neq 0.$ +* For $a=0$ curves, $P_u^{-1}$ can be stated for $(v,w)$ as $P_u^{'-1}(v, w) = w\left(\frac{\sqrt{-3}-1}{2}u - v\right).$ +* $\psi_u$ can be stated for $(v, w)$ as $\psi_u'(v, w) = (x_1, x_2, x_3, z)$, where + +$$ +\begin{array}{lcl} + x_1 & = & v \\ + x_2 & = & -u - v \\ + x_3 & = & u + w^2 \\ + z & = & \dfrac{g(x_3)}{w}(u^2 + uv + v^2 + a) = \dfrac{-g(u)g(x_3)}{w^3} +\end{array} +$$ + +We can now write the expressions for finding $(v, w)$ given $x$ explicitly, by solving each of the $\\{x_1, x_2, x_3\\}$ +expressions for $v$ or $w$, and using the $S_u'$ equation to find the other variable: +* Assuming $x = x_1$, we find $v = x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions). +* Assuming $x = x_2$, we find $v = -u-x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions). +* Assuming $x = x_3$, we find $w = \pm\sqrt{x-u}$ and $v = -u/2 \pm \sqrt{-w^2(4g(u) + w^2h(u))}/(2w^2)$ (four solutions). + +### 3.2 Avoiding computing all inverses + +The *ElligatorSwift* algorithm as stated in Section 1 requires the computation of $L = F_u^{-1}(x)$ (the +set of all $t$ such that $(u, t)$ decode to $x$) in full. This is unnecessary. + +Observe that the procedure of restarting with probability $(1 - \frac{\\#L}{8})$ and otherwise returning a +uniformly random element from $L$ is actually equivalent to always padding $L$ with $\bot$ values up to length 8, +picking a uniformly random element from that, restarting whenever $\bot$ is picked: + +**Define** *ElligatorSwift(x)* as: +* Loop: + * Pick a uniformly random field element $u.$ + * Compute the set $L = F_u^{-1}(x).$ + * Let $T$ be the 8-element vector consisting of the elements of $L$, plus $8 - \\#L$ times $\\{\bot\\}.$ + * Select a uniformly random $t \in T.$ + * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. + +Now notice that the order of elements in $T$ does not matter, as all we do is pick a uniformly +random element in it, so we do not need to have all $\bot$ values at the end. +As we have 8 distinct formulas for finding $(v, w)$ (taking the variants due to $\pm$ into account), +we can associate every index in $T$ with exactly one of those formulas, making sure that: +* Formulas that yield no solutions (due to division by zero or non-existing square roots) or invalid solutions are made to return $\bot.$ +* For the $x_1$ and $x_2$ cases, if $g(-u-x)$ is a square, $\bot$ is returned instead (the round-trip check). +* In case multiple formulas would return the same non- $\bot$ result, all but one of those must be turned into $\bot$ to avoid biasing those. + +The last condition above only occurs with negligible probability for cryptographically-sized curves, but is interesting +to take into account as it allows exhaustive testing in small groups. See [Section 3.4](#34-dealing-with-special-cases) +for an analysis of all the negligible cases. + +If we define $T = (G_{0,u}(x), G_{1,u}(x), \ldots, G_{7,u}(x))$, with each $G_{i,u}$ matching one of the formulas, +the loop can be simplified to only compute one of the inverses instead of all of them: + +**Define** *ElligatorSwift(x)* as: +* Loop: + * Pick a uniformly random field element $u.$ + * Pick a uniformly random integer $c$ in $[0,8).$ + * Let $t = G_{c,u}(x).$ + * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. + +This is implemented in `rustsecp256k1_v0_11_ellswift_xelligatorswift_var`. + +### 3.3 Finding the inverse + +To implement $G_{c,u}$, we map $c=0$ to the $x_1$ formula, $c=1$ to the $x_2$ formula, and $c=2$ and $c=3$ to the $x_3$ formula. +Those are then repeated as $c=4$ through $c=7$ for the other sign of $w$ (noting that in each formula, $w$ is a square root of some expression). +Ignoring the negligible cases, we get: + +**Define** $G_{c,u}(x)$ as: +* If $c \in \\{0, 1, 4, 5\\}$ (for $x_1$ and $x_2$ formulas): + * If $g(-u-x)$ is square, return $\bot$ (as $x_3$ would be valid and take precedence). + * If $c \in \\{0, 4\\}$ (the $x_1$ formula) let $v = x$, otherwise let $v = -u-x$ (the $x_2$ formula) + * Let $s = -g(u)/(u^2 + uv + v^2 + a)$ (using $s = w^2$ in what follows). +* Otherwise, when $c \in \\{2, 3, 6, 7\\}$ (for $x_3$ formulas): + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4g(u) + sh(u))}.$ + * Let $v = (r/s - u)/2$ if $c \in \\{3, 7\\}$; $(-r/s - u)/2$ otherwise. +* Let $w = \sqrt{s}.$ +* Depending on $c:$ + * If $c \in \\{0, 1, 2, 3\\}:$ return $P_u^{'-1}(v, w).$ + * If $c \in \\{4, 5, 6, 7\\}:$ return $P_u^{'-1}(v, -w).$ + +Whenever a square root of a non-square is taken, $\bot$ is returned; for both square roots this happens with roughly +50% on random inputs. Similarly, when a division by 0 would occur, $\bot$ is returned as well; this will only happen +with negligible probability. A division by 0 in the first branch in fact cannot occur at all, because $u^2 + uv + v^2 + a = 0$ +implies $g(-u-x) = g(x)$ which would mean the $g(-u-x)$ is square condition has triggered +and $\bot$ would have been returned already. + +**Note**: In the paper, the $case$ variable corresponds roughly to the $c$ above, but only takes on 4 possible values (1 to 4). +The conditional negation of $w$ at the end is done randomly, which is equivalent, but makes testing harder. We choose to +have the $G_{c,u}$ be deterministic, and capture all choices in $c.$ + +Now observe that the $c \in \\{1, 5\\}$ and $c \in \\{3, 7\\}$ conditions effectively perform the same $v \rightarrow -u-v$ +transformation. Furthermore, that transformation has no effect on $s$ in the first branch +as $u^2 + ux + x^2 + a = u^2 + u(-u-x) + (-u-x)^2 + a.$ Thus we can extract it out and move it down: + +**Define** $G_{c,u}(x)$ as: +* If $c \in \\{0, 1, 4, 5\\}:$ + * If $g(-u-x)$ is square, return $\bot.$ + * Let $s = -g(u)/(u^2 + ux + x^2 + a).$ + * Let $v = x.$ +* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4g(u) + sh(u))}.$ + * Let $v = (r/s - u)/2.$ +* Let $w = \sqrt{s}.$ +* Depending on $c:$ + * If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w).$ + * If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w).$ + * If $c \in \\{4, 6\\}:$ return $P_u^{'-1}(v, -w).$ + * If $c \in \\{5, 7\\}:$ return $P_u^{'-1}(-u-v, -w).$ + +This shows there will always be exactly 0, 4, or 8 $t$ values for a given $(u, x)$ input. +There can be 0, 1, or 2 $(v, w)$ pairs before invoking $P_u^{'-1}$, and each results in 4 distinct $t$ values. + +### 3.4 Dealing with special cases + +As mentioned before there are a few cases to deal with which only happen in a negligibly small subset of inputs. +For cryptographically sized fields, if only random inputs are going to be considered, it is unnecessary to deal with these. Still, for completeness +we analyse them here. They generally fall into two categories: cases in which the encoder would produce $t$ values that +do not decode back to $x$ (or at least cannot guarantee that they do), and cases in which the encoder might produce the same +$t$ value for multiple $c$ inputs (thereby biasing that encoding): + +* In the branch for $x_1$ and $x_2$ (where $c \in \\{0, 1, 4, 5\\}$): + * When $g(u) = 0$, we would have $s=w=Y=0$, which is not on $S_u.$ This is only possible on even-ordered curves. + Excluding this also removes the one condition under which the simplified check for $x_3$ on the curve + fails (namely when $g(x_1)=g(x_2)=0$ but $g(x_3)$ is not square). + This does exclude some valid encodings: when both $g(u)=0$ and $u^2+ux+x^2+a=0$ (also implying $g(x)=0$), + the $S_u'$ equation degenerates to $0 = 0$, and many valid $t$ values may exist. Yet, these cannot be targeted uniformly by the + encoder anyway as there will generally be more than 8. + * When $g(x) = 0$, the same $t$ would be produced as in the $x_3$ branch (where $c \in \\{2, 3, 6, 7\\}$) which we give precedence + as it can deal with $g(u)=0$. + This is again only possible on even-ordered curves. +* In the branch for $x_3$ (where $c \in \\{2, 3, 6, 7\\}$): + * When $s=0$, a division by zero would occur. + * When $v = -u-v$ and $c \in \\{3, 7\\}$, the same $t$ would be returned as in the $c \in \\{2, 6\\}$ cases. + It is equivalent to checking whether $r=0$. + This cannot occur in the $x_1$ or $x_2$ branches, as it would trigger the $g(-u-x)$ is square condition. + A similar concern for $w = -w$ does not exist, as $w=0$ is already impossible in both branches: in the first + it requires $g(u)=0$ which is already outlawed on even-ordered curves and impossible on others; in the second it would trigger division by zero. +* Curve-specific special cases also exist that need to be rejected, because they result in $(u,t)$ which is invalid to the decoder, or because of division by zero in the encoder: + * For $a=0$ curves, when $u=0$ or when $t=0$. The latter can only be reached by the encoder when $g(u)=0$, which requires an even-ordered curve. + * For $a \neq 0$ curves, when $X_0(u)=0$, when $h(u)t^2 = -1$, or when $w(u + 2v) = 2X_0(u)$ while also either $w \neq 2Y_0(u)$ or $h(u)=0$. + +**Define** a version of $G_{c,u}(x)$ which deals with all these cases: +* If $a=0$ and $u=0$, return $\bot.$ +* If $a \neq 0$ and $X_0(u)=0$, return $\bot.$ +* If $c \in \\{0, 1, 4, 5\\}:$ + * If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only). + * If $g(-u-x)$ is square, return $\bot.$ + * Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero). + * Let $v = x.$ +* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square. + * If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$ + * If $s = 0$, return $\bot.$ + * Let $v = (r/s - u)/2.$ +* Let $w = \sqrt{s}$; return $\bot$ if not square. +* If $a \neq 0$ and $w(u+2v) = 2X_0(u)$ and either $w \neq 2Y_0(u)$ or $h(u) = 0$, return $\bot.$ +* Depending on $c:$ + * If $c \in \\{0, 2\\}$, let $t = P_u^{'-1}(v, w).$ + * If $c \in \\{1, 3\\}$, let $t = P_u^{'-1}(-u-v, w).$ + * If $c \in \\{4, 6\\}$, let $t = P_u^{'-1}(v, -w).$ + * If $c \in \\{5, 7\\}$, let $t = P_u^{'-1}(-u-v, -w).$ +* If $a=0$ and $t=0$, return $\bot$ (even curves only). +* If $a \neq 0$ and $h(u)t^2 = -1$, return $\bot.$ +* Return $t.$ + +Given any $u$, using this algorithm over all $x$ and $c$ values, every $t$ value will be reached exactly once, +for an $x$ for which $F_u(t) = x$ holds, except for these cases that will not be reached: +* All cases where $P_u(t)$ is not defined: + * For $a=0$ curves, when $u=0$, $t=0$, or $g(u) = -t^2.$ + * For $a \neq 0$ curves, when $h(u)t^2 = -1$, $X_0(u) = 0$, or $Y_0(u) (1 - h(u) t^2) = 2X_0(u)t.$ +* When $g(u)=0$, the potentially many $t$ values that decode to an $x$ satisfying $g(x)=0$ using the $x_2$ formula. These were excluded by the $g(u)=0$ condition in the $c \in \\{0, 1, 4, 5\\}$ branch. + +These cases form a negligible subset of all $(u, t)$ for cryptographically sized curves. + +### 3.5 Encoding for `secp256k1` + +Specialized for odd-ordered $a=0$ curves: + +**Define** $G_{c,u}(x)$ as: +* If $u=0$, return $\bot.$ +* If $c \in \\{0, 1, 4, 5\\}:$ + * If $(-u-x)^3 + b$ is square, return $\bot$ + * Let $s = -(u^3 + b)/(u^2 + ux + x^2)$ (cannot cause division by 0). + * Let $v = x.$ +* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4(u^3 + b) + 3su^2)}$; return $\bot$ if not square. + * If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$ + * If $s = 0$, return $\bot.$ + * Let $v = (r/s - u)/2.$ +* Let $w = \sqrt{s}$; return $\bot$ if not square. +* Depending on $c:$ + * If $c \in \\{0, 2\\}:$ return $w(\frac{\sqrt{-3}-1}{2}u - v).$ + * If $c \in \\{1, 3\\}:$ return $w(\frac{\sqrt{-3}+1}{2}u + v).$ + * If $c \in \\{4, 6\\}:$ return $w(\frac{-\sqrt{-3}+1}{2}u + v).$ + * If $c \in \\{5, 7\\}:$ return $w(\frac{-\sqrt{-3}-1}{2}u - v).$ + +This is implemented in `rustsecp256k1_v0_11_ellswift_xswiftec_inv_var`. + +And the x-only ElligatorSwift encoding algorithm is still: + +**Define** *ElligatorSwift(x)* as: +* Loop: + * Pick a uniformly random field element $u.$ + * Pick a uniformly random integer $c$ in $[0,8).$ + * Let $t = G_{c,u}(x).$ + * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. + +Note that this logic does not take the remapped $u=0$, $t=0$, and $g(u) = -t^2$ cases into account; it just avoids them. +While it is not impossible to make the encoder target them, this would increase the maximum number of $t$ values for a given $(u, x)$ +combination beyond 8, and thereby slow down the ElligatorSwift loop proportionally, for a negligible gain in uniformity. + +## 4. Encoding and decoding full *(x, y)* coordinates + +So far we have only addressed encoding and decoding x-coordinates, but in some cases an encoding +for full points with $(x, y)$ coordinates is desirable. It is possible to encode this information +in $t$ as well. + +Note that for any $(X, Y) \in S_u$, $(\pm X, \pm Y)$ are all on $S_u.$ Moreover, all of these are +mapped to the same x-coordinate. Negating $X$ or negating $Y$ just results in $x_1$ and $x_2$ +being swapped, and does not affect $x_3.$ This will not change the outcome x-coordinate as the order +of $x_1$ and $x_2$ only matters if both were to be valid, and in that case $x_3$ would be used instead. + +Still, these four $(X, Y)$ combinations all correspond to distinct $t$ values, so we can encode +the sign of the y-coordinate in the sign of $X$ or the sign of $Y.$ They correspond to the +four distinct $P_u^{'-1}$ calls in the definition of $G_{u,c}.$ + +**Note**: In the paper, the sign of the y coordinate is encoded in a separately-coded bit. + +To encode the sign of $y$ in the sign of $Y:$ + +**Define** *Decode(u, t)* for full $(x, y)$ as: +* Let $(X, Y) = P_u(t).$ +* Let $x$ be the first value in $(u + 4Y^2, \frac{-X}{2Y} - \frac{u}{2}, \frac{X}{2Y} - \frac{u}{2})$ for which $g(x)$ is square. +* Let $y = \sqrt{g(x)}.$ +* If $sign(y) = sign(Y)$, return $(x, y)$; otherwise return $(x, -y).$ + +And encoding would be done using a $G_{c,u}(x, y)$ function defined as: + +**Define** $G_{c,u}(x, y)$ as: +* If $c \in \\{0, 1\\}:$ + * If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only). + * If $g(-u-x)$ is square, return $\bot.$ + * Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero). + * Let $v = x.$ +* Otherwise, when $c \in \\{2, 3\\}:$ + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square. + * If $c = 3$ and $r = 0$, return $\bot.$ + * Let $v = (r/s - u)/2.$ +* Let $w = \sqrt{s}$; return $\bot$ if not square. +* Let $w' = w$ if $sign(w/2) = sign(y)$; $-w$ otherwise. +* Depending on $c:$ + * If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w').$ + * If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w').$ + +Note that $c$ now only ranges $[0,4)$, as the sign of $w'$ is decided based on that of $y$, rather than on $c.$ +This change makes some valid encodings unreachable: when $y = 0$ and $sign(Y) \neq sign(0)$. + +In the above logic, $sign$ can be implemented in several ways, such as parity of the integer representation +of the input field element (for prime-sized fields) or the quadratic residuosity (for fields where +$-1$ is not square). The choice does not matter, as long as it only takes on two possible values, and for $x \neq 0$ it holds that $sign(x) \neq sign(-x)$. + +### 4.1 Full *(x, y)* coordinates for `secp256k1` + +For $a=0$ curves, there is another option. Note that for those, +the $P_u(t)$ function translates negations of $t$ to negations of (both) $X$ and $Y.$ Thus, we can use $sign(t)$ to +encode the y-coordinate directly. Combined with the earlier remapping to guarantee all inputs land on the curve, we get +as decoder: + +**Define** *Decode(u, t)* as: +* Let $u'=u$ if $u \neq 0$; $1$ otherwise. +* Let $t'=t$ if $t \neq 0$; $1$ otherwise. +* Let $t''=t'$ if $u'^3 + b + t'^2 \neq 0$; $2t'$ otherwise. +* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$ +* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$ +* Let $x$ be the first element of $(u' + 4Y^2, \frac{-X}{2Y} - \frac{u'}{2}, \frac{X}{2Y} - \frac{u'}{2})$ for which $g(x)$ is square. +* Let $y = \sqrt{g(x)}.$ +* Return $(x, y)$ if $sign(y) = sign(t)$; $(x, -y)$ otherwise. + +This is implemented in `rustsecp256k1_v0_11_ellswift_swiftec_var`. The used $sign(x)$ function is the parity of $x$ when represented as in integer in $[0,q).$ + +The corresponding encoder would invoke the x-only one, but negating the output $t$ if $sign(t) \neq sign(y).$ + +This is implemented in `rustsecp256k1_v0_11_ellswift_elligatorswift_var`. + +Note that this is only intended for encoding points where both the x-coordinate and y-coordinate are unpredictable. When encoding x-only points +where the y-coordinate is implicitly even (or implicitly square, or implicitly in $[0,q/2]$), the encoder in +[Section 3.5](#35-encoding-for-secp256k1) must be used, or a bias is reintroduced that undoes all the benefit of using ElligatorSwift +in the first place. diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/doc/musig.md b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/doc/musig.md new file mode 100644 index 00000000..de61c0f9 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/doc/musig.md @@ -0,0 +1,54 @@ +Notes on the musig module API +=========================== + +The following sections contain additional notes on the API of the musig module (`include/rustsecp256k1_v0_11_musig.h`). +A usage example can be found in `examples/musig.c`. + +## API misuse + +The musig API is designed with a focus on misuse resistance. +However, due to the interactive nature of the MuSig protocol, there are additional failure modes that are not present in regular (single-party) Schnorr signature creation. +While the results can be catastrophic (e.g. leaking of the secret key), it is unfortunately not possible for the musig implementation to prevent all such failure modes. + +Therefore, users of the musig module must take great care to make sure of the following: + +1. A unique nonce per signing session is generated in `rustsecp256k1_v0_11_musig_nonce_gen`. + See the corresponding comment in `include/rustsecp256k1_v0_11_musig.h` for how to ensure that. +2. The `rustsecp256k1_v0_11_musig_secnonce` structure is never copied or serialized. + See also the comment on `rustsecp256k1_v0_11_musig_secnonce` in `include/rustsecp256k1_v0_11_musig.h`. +3. Opaque data structures are never written to or read from directly. + Instead, only the provided accessor functions are used. + +## Key Aggregation and (Taproot) Tweaking + +Given a set of public keys, the aggregate public key is computed with `rustsecp256k1_v0_11_musig_pubkey_agg`. +A plain tweak can be added to the resulting public key with `rustsecp256k1_v0_11_ec_pubkey_tweak_add` by setting the `tweak32` argument to the hash defined in BIP 32. Similarly, a Taproot tweak can be added with `rustsecp256k1_v0_11_xonly_pubkey_tweak_add` by setting the `tweak32` argument to the TapTweak hash defined in BIP 341. +Both types of tweaking can be combined and invoked multiple times if the specific application requires it. + +## Signing + +This is covered by `examples/musig.c`. +Essentially, the protocol proceeds in the following steps: + +1. Generate a keypair with `rustsecp256k1_v0_11_keypair_create` and obtain the public key with `rustsecp256k1_v0_11_keypair_pub`. +2. Call `rustsecp256k1_v0_11_musig_pubkey_agg` with the pubkeys of all participants. +3. Optionally add a (Taproot) tweak with `rustsecp256k1_v0_11_musig_pubkey_xonly_tweak_add` and a plain tweak with `rustsecp256k1_v0_11_musig_pubkey_ec_tweak_add`. +4. Generate a pair of secret and public nonce with `rustsecp256k1_v0_11_musig_nonce_gen` and send the public nonce to the other signers. +5. Someone (not necessarily the signer) aggregates the public nonces with `rustsecp256k1_v0_11_musig_nonce_agg` and sends it to the signers. +6. Process the aggregate nonce with `rustsecp256k1_v0_11_musig_nonce_process`. +7. Create a partial signature with `rustsecp256k1_v0_11_musig_partial_sign`. +8. Verify the partial signatures (optional in some scenarios) with `rustsecp256k1_v0_11_musig_partial_sig_verify`. +9. Someone (not necessarily the signer) obtains all partial signatures and aggregates them into the final Schnorr signature using `rustsecp256k1_v0_11_musig_partial_sig_agg`. + +The aggregate signature can be verified with `rustsecp256k1_v0_11_schnorrsig_verify`. + +Steps 1 through 5 above can occur before or after the signers are aware of the message to be signed. +Whenever possible, it is recommended to generate the nonces only after the message is known. +This provides enhanced defense-in-depth measures, protecting against potential API misuse in certain scenarios. +However, it does require two rounds of communication during the signing process. +The alternative, generating the nonces in a pre-processing step before the message is known, eliminates these additional protective measures but allows for non-interactive signing. +Similarly, the API supports an alternative protocol flow where generating the aggregate key (steps 1 to 3) is allowed to happen after exchanging nonces (steps 4 to 5). + +## Verification + +A participant who wants to verify the partial signatures, but does not sign itself may do so using the above instructions except that the verifier skips steps 1, 4 and 7. diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/doc/release-process.md b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/doc/release-process.md new file mode 100644 index 00000000..a64bae0f --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/doc/release-process.md @@ -0,0 +1,94 @@ +# Release process + +This document outlines the process for releasing versions of the form `$MAJOR.$MINOR.$PATCH`. + +We distinguish between two types of releases: *regular* and *maintenance* releases. +Regular releases are releases of a new major or minor version as well as patches of the most recent release. +Maintenance releases, on the other hand, are required for patches of older releases. + +You should coordinate with the other maintainers on the release date, if possible. +This date will be part of the release entry in [CHANGELOG.md](../CHANGELOG.md) and it should match the dates of the remaining steps in the release process (including the date of the tag and the GitHub release). +It is best if the maintainers are present during the release, so they can help ensure that the process is followed correctly and, in the case of a regular release, they are aware that they should not modify the master branch between merging the PR in step 1 and the PR in step 3. + +This process also assumes that there will be no minor releases for old major releases. + +We aim to cut a regular release every 3-4 months, approximately twice as frequent as major Bitcoin Core releases. Every second release should be published one month before the feature freeze of the next major Bitcoin Core release, allowing sufficient time to update the library in Core. + +## Sanity checks +Perform these checks when reviewing the release PR (see below): + +1. Ensure `make distcheck` doesn't fail. + ```shell + ./autogen.sh && ./configure --enable-dev-mode && make distcheck + ``` +2. Check installation with autotools: + ```shell + dir=$(mktemp -d) + ./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -RlAh $dir + gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=$dir/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"$dir/lib" && ./ecdsa + ``` +3. Check installation with CMake: + ```shell + dir=$(mktemp -d) + build=$(mktemp -d) + cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build && cmake --install $build && ls -RlAh $dir + gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa + ``` +4. Use the [`check-abi.sh`](/tools/check-abi.sh) tool to verify that there are no unexpected ABI incompatibilities and that the version number and the release notes accurately reflect all potential ABI changes. To run this tool, the `abi-dumper` and `abi-compliance-checker` packages are required. + ```shell + tools/check-abi.sh + ``` + +## Regular release + +1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that + * finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) by + * adding a section for the release (make sure that the version number is a link to a diff between the previous and new version), + * removing the `[Unreleased]` section header, + * ensuring that the release notes are not missing entries (check the `needs-changelog` label on github), and + * including an entry for `### ABI Compatibility` if it doesn't exist, + * sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and, + * if this is not a patch release, + * updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac`, and + * updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`. +2. Perform the [sanity checks](#sanity-checks) on the PR branch. +3. After the PR is merged, tag the commit, and push the tag: + ``` + RELEASE_COMMIT= + git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" $RELEASE_COMMIT + git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH + ``` +4. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that + * sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`, + * increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and + * adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md). + + If other maintainers are not present to approve the PR, it can be merged without ACKs. +5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). +6. Send an announcement email to the bitcoin-dev mailing list. + +## Maintenance release + +Note that bug fixes need to be backported only to releases for which no compatible release without the bug exists. + +1. If there's no maintenance branch `$MAJOR.$MINOR`, create one: + ``` + git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.$((PATCH - 1)) + git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR + ``` +2. Open a pull request to the `$MAJOR.$MINOR` branch that + * includes the bug fixes, + * finalizes the release notes similar to a regular release, + * increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac` + and the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt` + (with commit message `"release: bump versions for $MAJOR.$MINOR.$PATCH"`, for example). +3. Perform the [sanity checks](#sanity-checks) on the PR branch. +4. After the PRs are merged, update the release branch, tag the commit, and push the tag: + ``` + git checkout $MAJOR.$MINOR && git pull + git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" + git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH + ``` +6. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). +7. Send an announcement email to the bitcoin-dev mailing list. +8. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md). diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/doc/safegcd_implementation.md b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/doc/safegcd_implementation.md similarity index 91% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/doc/safegcd_implementation.md rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/doc/safegcd_implementation.md index 063aa8ef..5dbbb7bb 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/doc/safegcd_implementation.md +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/doc/safegcd_implementation.md @@ -1,7 +1,7 @@ # The safegcd implementation in libsecp256k1 explained -This document explains the modular inverse implementation in the `src/modinv*.h` files. It is based -on the paper +This document explains the modular inverse and Jacobi symbol implementations in the `src/modinv*.h` files. +It is based on the paper ["Fast constant-time gcd computation and modular inversion"](https://gcd.cr.yp.to/papers.html#safegcd) by Daniel J. Bernstein and Bo-Yin Yang. The references below are for the Date: 2019.04.13 version. @@ -410,7 +410,7 @@ sufficient even. Given that every loop iteration performs *N* divsteps, it will To deal with the branches in `divsteps_n_matrix` we will replace them with constant-time bitwise operations (and hope the C compiler isn't smart enough to turn them back into branches; see -`valgrind_ctime_test.c` for automated tests that this isn't the case). To do so, observe that a +`ctime_tests.c` for automated tests that this isn't the case). To do so, observe that a divstep can be written instead as (compare to the inner loop of `gcd` in section 1). ```python @@ -769,3 +769,51 @@ def modinv_var(M, Mi, x): d, e = update_de(d, e, t, M, Mi) return normalize(f, d, Mi) ``` + +## 8. From GCDs to Jacobi symbol + +We can also use a similar approach to calculate Jacobi symbol *(x | M)* by keeping track of an +extra variable *j*, for which at every step *(x | M) = j (g | f)*. As we update *f* and *g*, we +make corresponding updates to *j* using +[properties of the Jacobi symbol](https://en.wikipedia.org/wiki/Jacobi_symbol#Properties): +* *((g/2) | f)* is either *(g | f)* or *-(g | f)*, depending on the value of *f mod 8* (negating if it's *3* or *5*). +* *(f | g)* is either *(g | f)* or *-(g | f)*, depending on *f mod 4* and *g mod 4* (negating if both are *3*). + +These updates depend only on the values of *f* and *g* modulo *4* or *8*, and can thus be applied +very quickly, as long as we keep track of a few additional bits of *f* and *g*. Overall, this +calculation is slightly simpler than the one for the modular inverse because we no longer need to +keep track of *d* and *e*. + +However, one difficulty of this approach is that the Jacobi symbol *(a | n)* is only defined for +positive odd integers *n*, whereas in the original safegcd algorithm, *f, g* can take negative +values. We resolve this by using the following modified steps: + +```python + # Before + if delta > 0 and g & 1: + delta, f, g = 1 - delta, g, (g - f) // 2 + + # After + if delta > 0 and g & 1: + delta, f, g = 1 - delta, g, (g + f) // 2 +``` + +The algorithm is still correct, since the changed divstep, called a "posdivstep" (see section 8.4 +and E.5 in the paper) preserves *gcd(f, g)*. However, there's no proof that the modified algorithm +will converge. The justification for posdivsteps is completely empirical: in practice, it appears +that the vast majority of nonzero inputs converge to *f=g=gcd(f0, g0)* in a +number of steps proportional to their logarithm. + +Note that: +- We require inputs to satisfy *gcd(x, M) = 1*, as otherwise *f=1* is not reached. +- We require inputs *x &neq; 0*, because applying posdivstep with *g=0* has no effect. +- We need to update the termination condition from *g=0* to *f=1*. + +We account for the possibility of nonconvergence by only performing a bounded number of +posdivsteps, and then falling back to square-root based Jacobi calculation if a solution has not +yet been found. + +The optimizations in sections 3-7 above are described in the context of the original divsteps, but +in the C implementation we also adapt most of them (not including "avoiding modulus operations", +since it's not necessary to track *d, e*, and "constant-time operation", since we never calculate +Jacobi symbols for secret data) to the posdivsteps version. diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/CMakeLists.txt b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/CMakeLists.txt new file mode 100644 index 00000000..565116d6 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/CMakeLists.txt @@ -0,0 +1,31 @@ +function(add_example name) + set(target_name ${name}_example) + add_executable(${target_name} ${name}.c) + target_include_directories(${target_name} PRIVATE + ${PROJECT_SOURCE_DIR}/include + ) + target_link_libraries(${target_name} + secp256k1 + $<$:bcrypt> + ) + set(test_name ${name}_example) + add_test(NAME rustsecp256k1_v0_11_${test_name} COMMAND ${target_name}) +endfunction() + +add_example(ecdsa) + +if(SECP256K1_ENABLE_MODULE_ECDH) + add_example(ecdh) +endif() + +if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) + add_example(schnorr) +endif() + +if(SECP256K1_ENABLE_MODULE_ELLSWIFT) + add_example(ellswift) +endif() + +if(SECP256K1_ENABLE_MODULE_MUSIG) + add_example(musig) +endif() diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/EXAMPLES_COPYING b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/EXAMPLES_COPYING similarity index 100% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/EXAMPLES_COPYING rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/EXAMPLES_COPYING diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/ecdh.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/ecdh.c similarity index 60% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/ecdh.c rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/ecdh.c index b8637e69..1c9d87d9 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/ecdh.c +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/ecdh.c @@ -14,8 +14,7 @@ #include #include -#include "random.h" - +#include "examples_util.h" int main(void) { unsigned char seckey1[32]; @@ -27,56 +26,50 @@ int main(void) { unsigned char randomize[32]; int return_val; size_t len; - rustsecp256k1zkp_v0_8_0_pubkey pubkey1; - rustsecp256k1zkp_v0_8_0_pubkey pubkey2; - - /* The specification in secp256k1.h states that `rustsecp256k1zkp_v0_8_0_ec_pubkey_create` - * needs a context object initialized for signing, which is why we create - * a context with the SECP256K1_CONTEXT_SIGN flag. - * (The docs for `rustsecp256k1zkp_v0_8_0_ecdh` don't require any special context, just - * some initialized context) */ - rustsecp256k1zkp_v0_8_0_context* ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN); + rustsecp256k1_v0_11_pubkey pubkey1; + rustsecp256k1_v0_11_pubkey pubkey2; + + /* Before we can call actual API functions, we need to create a "context". */ + rustsecp256k1_v0_11_context* ctx = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); if (!fill_random(randomize, sizeof(randomize))) { printf("Failed to generate randomness\n"); return 1; } /* Randomizing the context is recommended to protect against side-channel - * leakage See `rustsecp256k1zkp_v0_8_0_context_randomize` in secp256k1.h for more + * leakage See `rustsecp256k1_v0_11_context_randomize` in secp256k1.h for more * information about it. This should never fail. */ - return_val = rustsecp256k1zkp_v0_8_0_context_randomize(ctx, randomize); + return_val = rustsecp256k1_v0_11_context_randomize(ctx, randomize); assert(return_val); /*** Key Generation ***/ - - /* If the secret key is zero or out of range (bigger than secp256k1's - * order), we try to sample a new key. Note that the probability of this - * happening is negligible. */ - while (1) { - if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { - printf("Failed to generate randomness\n"); - return 1; - } - if (rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, seckey1) && rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, seckey2)) { - break; - } + if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we fail. Note that the probability of this occurring is negligible + * with a properly functioning random number generator. */ + if (!rustsecp256k1_v0_11_ec_seckey_verify(ctx, seckey1) || !rustsecp256k1_v0_11_ec_seckey_verify(ctx, seckey2)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return 1; } /* Public key creation using a valid context with a verified secret key should never fail */ - return_val = rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey1, seckey1); + return_val = rustsecp256k1_v0_11_ec_pubkey_create(ctx, &pubkey1, seckey1); assert(return_val); - return_val = rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey2, seckey2); + return_val = rustsecp256k1_v0_11_ec_pubkey_create(ctx, &pubkey2, seckey2); assert(return_val); /* Serialize pubkey1 in a compressed form (33 bytes), should always return 1 */ len = sizeof(compressed_pubkey1); - return_val = rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, compressed_pubkey1, &len, &pubkey1, SECP256K1_EC_COMPRESSED); + return_val = rustsecp256k1_v0_11_ec_pubkey_serialize(ctx, compressed_pubkey1, &len, &pubkey1, SECP256K1_EC_COMPRESSED); assert(return_val); /* Should be the same size as the size of the output, because we passed a 33 byte array. */ assert(len == sizeof(compressed_pubkey1)); /* Serialize pubkey2 in a compressed form (33 bytes) */ len = sizeof(compressed_pubkey2); - return_val = rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, compressed_pubkey2, &len, &pubkey2, SECP256K1_EC_COMPRESSED); + return_val = rustsecp256k1_v0_11_ec_pubkey_serialize(ctx, compressed_pubkey2, &len, &pubkey2, SECP256K1_EC_COMPRESSED); assert(return_val); /* Should be the same size as the size of the output, because we passed a 33 byte array. */ assert(len == sizeof(compressed_pubkey2)); @@ -85,12 +78,12 @@ int main(void) { /* Perform ECDH with seckey1 and pubkey2. Should never fail with a verified * seckey and valid pubkey */ - return_val = rustsecp256k1zkp_v0_8_0_ecdh(ctx, shared_secret1, &pubkey2, seckey1, NULL, NULL); + return_val = rustsecp256k1_v0_11_ecdh(ctx, shared_secret1, &pubkey2, seckey1, NULL, NULL); assert(return_val); /* Perform ECDH with seckey2 and pubkey1. Should never fail with a verified * seckey and valid pubkey */ - return_val = rustsecp256k1zkp_v0_8_0_ecdh(ctx, shared_secret2, &pubkey1, seckey2, NULL, NULL); + return_val = rustsecp256k1_v0_11_ecdh(ctx, shared_secret2, &pubkey1, seckey2, NULL, NULL); assert(return_val); /* Both parties should end up with the same shared secret */ @@ -109,19 +102,19 @@ int main(void) { print_hex(shared_secret1, sizeof(shared_secret1)); /* This will clear everything from the context and free the memory */ - rustsecp256k1zkp_v0_8_0_context_destroy(ctx); + rustsecp256k1_v0_11_context_destroy(ctx); /* It's best practice to try to clear secrets from memory after using them. * This is done because some bugs can allow an attacker to leak memory, for - * example through "out of bounds" array access (see Heartbleed), Or the OS + * example through "out of bounds" array access (see Heartbleed), or the OS * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. * - * TODO: Prevent these writes from being optimized out, as any good compiler + * Here we are preventing these writes from being optimized out, as any good compiler * will remove any writes that aren't used. */ - memset(seckey1, 0, sizeof(seckey1)); - memset(seckey2, 0, sizeof(seckey2)); - memset(shared_secret1, 0, sizeof(shared_secret1)); - memset(shared_secret2, 0, sizeof(shared_secret2)); + secure_erase(seckey1, sizeof(seckey1)); + secure_erase(seckey2, sizeof(seckey2)); + secure_erase(shared_secret1, sizeof(shared_secret1)); + secure_erase(shared_secret2, sizeof(shared_secret2)); return 0; } diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/ecdsa.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/ecdsa.c similarity index 62% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/ecdsa.c rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/ecdsa.c index 1d80c276..fcc9797f 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/ecdsa.c +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/ecdsa.c @@ -13,9 +13,7 @@ #include -#include "random.h" - - +#include "examples_util.h" int main(void) { /* Instead of signing the message directly, we must sign a 32-byte hash. @@ -34,48 +32,42 @@ int main(void) { unsigned char compressed_pubkey[33]; unsigned char serialized_signature[64]; size_t len; - int is_signature_valid; + int is_signature_valid, is_signature_valid2; int return_val; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig; - /* The specification in secp256k1.h states that `rustsecp256k1zkp_v0_8_0_ec_pubkey_create` needs - * a context object initialized for signing and `rustsecp256k1zkp_v0_8_0_ecdsa_verify` needs - * a context initialized for verification, which is why we create a context - * for both signing and verification with the SECP256K1_CONTEXT_SIGN and - * SECP256K1_CONTEXT_VERIFY flags. */ - rustsecp256k1zkp_v0_8_0_context* ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + rustsecp256k1_v0_11_pubkey pubkey; + rustsecp256k1_v0_11_ecdsa_signature sig; + /* Before we can call actual API functions, we need to create a "context". */ + rustsecp256k1_v0_11_context* ctx = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); if (!fill_random(randomize, sizeof(randomize))) { printf("Failed to generate randomness\n"); return 1; } /* Randomizing the context is recommended to protect against side-channel - * leakage See `rustsecp256k1zkp_v0_8_0_context_randomize` in secp256k1.h for more + * leakage See `rustsecp256k1_v0_11_context_randomize` in secp256k1.h for more * information about it. This should never fail. */ - return_val = rustsecp256k1zkp_v0_8_0_context_randomize(ctx, randomize); + return_val = rustsecp256k1_v0_11_context_randomize(ctx, randomize); assert(return_val); /*** Key Generation ***/ - - /* If the secret key is zero or out of range (bigger than secp256k1's - * order), we try to sample a new key. Note that the probability of this - * happening is negligible. */ - while (1) { - if (!fill_random(seckey, sizeof(seckey))) { - printf("Failed to generate randomness\n"); - return 1; - } - if (rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, seckey)) { - break; - } + if (!fill_random(seckey, sizeof(seckey))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we fail. Note that the probability of this occurring is negligible + * with a properly functioning random number generator. */ + if (!rustsecp256k1_v0_11_ec_seckey_verify(ctx, seckey)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return 1; } /* Public key creation using a valid context with a verified secret key should never fail */ - return_val = rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, seckey); + return_val = rustsecp256k1_v0_11_ec_pubkey_create(ctx, &pubkey, seckey); assert(return_val); /* Serialize the pubkey in a compressed form(33 bytes). Should always return 1. */ len = sizeof(compressed_pubkey); - return_val = rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, compressed_pubkey, &len, &pubkey, SECP256K1_EC_COMPRESSED); + return_val = rustsecp256k1_v0_11_ec_pubkey_serialize(ctx, compressed_pubkey, &len, &pubkey, SECP256K1_EC_COMPRESSED); assert(return_val); /* Should be the same size as the size of the output, because we passed a 33 byte array. */ assert(len == sizeof(compressed_pubkey)); @@ -86,31 +78,31 @@ int main(void) { * custom nonce function, passing `NULL` will use the RFC-6979 safe default. * Signing with a valid context, verified secret key * and the default nonce function should never fail. */ - return_val = rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig, msg_hash, seckey, NULL, NULL); + return_val = rustsecp256k1_v0_11_ecdsa_sign(ctx, &sig, msg_hash, seckey, NULL, NULL); assert(return_val); /* Serialize the signature in a compact form. Should always return 1 * according to the documentation in secp256k1.h. */ - return_val = rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact(ctx, serialized_signature, &sig); + return_val = rustsecp256k1_v0_11_ecdsa_signature_serialize_compact(ctx, serialized_signature, &sig); assert(return_val); /*** Verification ***/ /* Deserialize the signature. This will return 0 if the signature can't be parsed correctly. */ - if (!rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact(ctx, &sig, serialized_signature)) { + if (!rustsecp256k1_v0_11_ecdsa_signature_parse_compact(ctx, &sig, serialized_signature)) { printf("Failed parsing the signature\n"); return 1; } /* Deserialize the public key. This will return 0 if the public key can't be parsed correctly. */ - if (!rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey))) { + if (!rustsecp256k1_v0_11_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey))) { printf("Failed parsing the public key\n"); return 1; } /* Verify a signature. This will return 1 if it's valid and 0 if it's not. */ - is_signature_valid = rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg_hash, &pubkey); + is_signature_valid = rustsecp256k1_v0_11_ecdsa_verify(ctx, &sig, msg_hash, &pubkey); printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false"); printf("Secret Key: "); @@ -120,18 +112,26 @@ int main(void) { printf("Signature: "); print_hex(serialized_signature, sizeof(serialized_signature)); - /* This will clear everything from the context and free the memory */ - rustsecp256k1zkp_v0_8_0_context_destroy(ctx); + rustsecp256k1_v0_11_context_destroy(ctx); + + /* Bonus example: if all we need is signature verification (and no key + generation or signing), we don't need to use a context created via + rustsecp256k1_v0_11_context_create(). We can simply use the static (i.e., global) + context rustsecp256k1_v0_11_context_static. See its description in + include/secp256k1.h for details. */ + is_signature_valid2 = rustsecp256k1_v0_11_ecdsa_verify(rustsecp256k1_v0_11_context_static, + &sig, msg_hash, &pubkey); + assert(is_signature_valid2 == is_signature_valid); /* It's best practice to try to clear secrets from memory after using them. * This is done because some bugs can allow an attacker to leak memory, for - * example through "out of bounds" array access (see Heartbleed), Or the OS + * example through "out of bounds" array access (see Heartbleed), or the OS * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. * - * TODO: Prevent these writes from being optimized out, as any good compiler + * Here we are preventing these writes from being optimized out, as any good compiler * will remove any writes that aren't used. */ - memset(seckey, 0, sizeof(seckey)); + secure_erase(seckey, sizeof(seckey)); return 0; } diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/ellswift.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/ellswift.c new file mode 100644 index 00000000..c5052974 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/ellswift.c @@ -0,0 +1,121 @@ +/************************************************************************* + * Written in 2024 by Sebastian Falbesoner * + * To the extent possible under law, the author(s) have dedicated all * + * copyright and related and neighboring rights to the software in this * + * file to the public domain worldwide. This software is distributed * + * without any warranty. For the CC0 Public Domain Dedication, see * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +/** This file demonstrates how to use the ElligatorSwift module to perform + * a key exchange according to BIP 324. Additionally, see the documentation + * in include/rustsecp256k1_v0_11_ellswift.h and doc/ellswift.md. + */ + +#include +#include +#include + +#include +#include + +#include "examples_util.h" + +int main(void) { + rustsecp256k1_v0_11_context* ctx; + unsigned char randomize[32]; + unsigned char auxrand1[32]; + unsigned char auxrand2[32]; + unsigned char seckey1[32]; + unsigned char seckey2[32]; + unsigned char ellswift_pubkey1[64]; + unsigned char ellswift_pubkey2[64]; + unsigned char shared_secret1[32]; + unsigned char shared_secret2[32]; + int return_val; + + /* Create a secp256k1 context */ + ctx = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); + if (!fill_random(randomize, sizeof(randomize))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* Randomizing the context is recommended to protect against side-channel + * leakage. See `rustsecp256k1_v0_11_context_randomize` in secp256k1.h for more + * information about it. This should never fail. */ + return_val = rustsecp256k1_v0_11_context_randomize(ctx, randomize); + assert(return_val); + + /*** Generate secret keys ***/ + if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we fail. Note that the probability of this occurring is negligible + * with a properly functioning random number generator. */ + if (!rustsecp256k1_v0_11_ec_seckey_verify(ctx, seckey1) || !rustsecp256k1_v0_11_ec_seckey_verify(ctx, seckey2)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return 1; + } + + /* Generate ElligatorSwift public keys. This should never fail with valid context and + verified secret keys. Note that providing additional randomness (fourth parameter) is + optional, but recommended. */ + if (!fill_random(auxrand1, sizeof(auxrand1)) || !fill_random(auxrand2, sizeof(auxrand2))) { + printf("Failed to generate randomness\n"); + return 1; + } + return_val = rustsecp256k1_v0_11_ellswift_create(ctx, ellswift_pubkey1, seckey1, auxrand1); + assert(return_val); + return_val = rustsecp256k1_v0_11_ellswift_create(ctx, ellswift_pubkey2, seckey2, auxrand2); + assert(return_val); + + /*** Create the shared secret on each side ***/ + + /* Perform x-only ECDH with seckey1 and ellswift_pubkey2. Should never fail + * with a verified seckey and valid pubkey. Note that both parties pass both + * EllSwift pubkeys in the same order; the pubkey of the calling party is + * determined by the "party" boolean (sixth parameter). */ + return_val = rustsecp256k1_v0_11_ellswift_xdh(ctx, shared_secret1, ellswift_pubkey1, ellswift_pubkey2, + seckey1, 0, rustsecp256k1_v0_11_ellswift_xdh_hash_function_bip324, NULL); + assert(return_val); + + /* Perform x-only ECDH with seckey2 and ellswift_pubkey1. Should never fail + * with a verified seckey and valid pubkey. */ + return_val = rustsecp256k1_v0_11_ellswift_xdh(ctx, shared_secret2, ellswift_pubkey1, ellswift_pubkey2, + seckey2, 1, rustsecp256k1_v0_11_ellswift_xdh_hash_function_bip324, NULL); + assert(return_val); + + /* Both parties should end up with the same shared secret */ + return_val = memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1)); + assert(return_val == 0); + + printf( " Secret Key1: "); + print_hex(seckey1, sizeof(seckey1)); + printf( "EllSwift Pubkey1: "); + print_hex(ellswift_pubkey1, sizeof(ellswift_pubkey1)); + printf("\n Secret Key2: "); + print_hex(seckey2, sizeof(seckey2)); + printf( "EllSwift Pubkey2: "); + print_hex(ellswift_pubkey2, sizeof(ellswift_pubkey2)); + printf("\n Shared Secret: "); + print_hex(shared_secret1, sizeof(shared_secret1)); + + /* This will clear everything from the context and free the memory */ + rustsecp256k1_v0_11_context_destroy(ctx); + + /* It's best practice to try to clear secrets from memory after using them. + * This is done because some bugs can allow an attacker to leak memory, for + * example through "out of bounds" array access (see Heartbleed), or the OS + * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. + * + * Here we are preventing these writes from being optimized out, as any good compiler + * will remove any writes that aren't used. */ + secure_erase(seckey1, sizeof(seckey1)); + secure_erase(seckey2, sizeof(seckey2)); + secure_erase(shared_secret1, sizeof(shared_secret1)); + secure_erase(shared_secret2, sizeof(shared_secret2)); + + return 0; +} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/random.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/examples_util.h similarity index 66% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/random.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/examples_util.h index 439226f0..3293b640 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/random.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/examples_util.h @@ -17,7 +17,13 @@ */ #if defined(_WIN32) +/* + * The defined WIN32_NO_STATUS macro disables return code definitions in + * windows.h, which avoids "macro redefinition" MSVC warnings in ntstatus.h. + */ +#define WIN32_NO_STATUS #include +#undef WIN32_NO_STATUS #include #include #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) @@ -71,3 +77,32 @@ static void print_hex(unsigned char* data, size_t size) { } printf("\n"); } + +#if defined(_MSC_VER) +// For SecureZeroMemory +#include +#endif +/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */ +static void secure_erase(void *ptr, size_t len) { +#if defined(_MSC_VER) + /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */ + SecureZeroMemory(ptr, len); +#elif defined(__GNUC__) + /* We use a memory barrier that scares the compiler away from optimizing out the memset. + * + * Quoting Adam Langley in commit ad1907fe73334d6c696c8539646c21b11178f20f + * in BoringSSL (ISC License): + * As best as we can tell, this is sufficient to break any optimisations that + * might try to eliminate "superfluous" memsets. + * This method used in memzero_explicit() the Linux kernel, too. Its advantage is that it is + * pretty efficient, because the compiler can still implement the memset() efficiently, + * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by + * Yang et al. (USENIX Security 2017) for more background. + */ + memset(ptr, 0, len); + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +#else + void *(*volatile const volatile_memset)(void *, int, size_t) = memset; + volatile_memset(ptr, 0, len); +#endif +} diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/musig.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/musig.c new file mode 100644 index 00000000..a9ead971 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/musig.c @@ -0,0 +1,260 @@ +/************************************************************************* + * To the extent possible under law, the author(s) have dedicated all * + * copyright and related and neighboring rights to the software in this * + * file to the public domain worldwide. This software is distributed * + * without any warranty. For the CC0 Public Domain Dedication, see * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +/** This file demonstrates how to use the MuSig module to create a + * 3-of-3 multisignature. Additionally, see the documentation in + * include/rustsecp256k1_v0_11_musig.h and doc/musig.md. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "examples_util.h" + +struct signer_secrets { + rustsecp256k1_v0_11_keypair keypair; + rustsecp256k1_v0_11_musig_secnonce secnonce; +}; + +struct signer { + rustsecp256k1_v0_11_pubkey pubkey; + rustsecp256k1_v0_11_musig_pubnonce pubnonce; + rustsecp256k1_v0_11_musig_partial_sig partial_sig; +}; + + /* Number of public keys involved in creating the aggregate signature */ +#define N_SIGNERS 3 +/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */ +static int create_keypair(const rustsecp256k1_v0_11_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) { + unsigned char seckey[32]; + + if (!fill_random(seckey, sizeof(seckey))) { + printf("Failed to generate randomness\n"); + return 0; + } + /* Try to create a keypair with a valid context. This only fails if the + * secret key is zero or out of range (greater than secp256k1's order). Note + * that the probability of this occurring is negligible with a properly + * functioning random number generator. */ + if (!rustsecp256k1_v0_11_keypair_create(ctx, &signer_secrets->keypair, seckey)) { + return 0; + } + if (!rustsecp256k1_v0_11_keypair_pub(ctx, &signer->pubkey, &signer_secrets->keypair)) { + return 0; + } + + secure_erase(seckey, sizeof(seckey)); + return 1; +} + +/* Tweak the pubkey corresponding to the provided keyagg cache, update the cache + * and return the tweaked aggregate pk. */ +static int tweak(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_xonly_pubkey *agg_pk, rustsecp256k1_v0_11_musig_keyagg_cache *cache) { + rustsecp256k1_v0_11_pubkey output_pk; + /* For BIP 32 tweaking the plain_tweak is set to a hash as defined in BIP + * 32. */ + unsigned char plain_tweak[32] = "this could be a BIP32 tweak...."; + /* For Taproot tweaking the xonly_tweak is set to the TapTweak hash as + * defined in BIP 341 */ + unsigned char xonly_tweak[32] = "this could be a Taproot tweak.."; + + + /* Plain tweaking which, for example, allows deriving multiple child + * public keys from a single aggregate key using BIP32 */ + if (!rustsecp256k1_v0_11_musig_pubkey_ec_tweak_add(ctx, NULL, cache, plain_tweak)) { + return 0; + } + /* Note that we did not provide an output_pk argument, because the + * resulting pk is also saved in the cache and so if one is just interested + * in signing, the output_pk argument is unnecessary. On the other hand, if + * one is not interested in signing, the same output_pk can be obtained by + * calling `rustsecp256k1_v0_11_musig_pubkey_get` right after key aggregation to get + * the full pubkey and then call `rustsecp256k1_v0_11_ec_pubkey_tweak_add`. */ + + /* Xonly tweaking which, for example, allows creating Taproot commitments */ + if (!rustsecp256k1_v0_11_musig_pubkey_xonly_tweak_add(ctx, &output_pk, cache, xonly_tweak)) { + return 0; + } + /* Note that if we wouldn't care about signing, we can arrive at the same + * output_pk by providing the untweaked public key to + * `rustsecp256k1_v0_11_xonly_pubkey_tweak_add` (after converting it to an xonly pubkey + * if necessary with `rustsecp256k1_v0_11_xonly_pubkey_from_pubkey`). */ + + /* Now we convert the output_pk to an xonly pubkey to allow to later verify + * the Schnorr signature against it. For this purpose we can ignore the + * `pk_parity` output argument; we would need it if we would have to open + * the Taproot commitment. */ + if (!rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(ctx, agg_pk, NULL, &output_pk)) { + return 0; + } + return 1; +} + +/* Sign a message hash with the given key pairs and store the result in sig */ +static int sign(const rustsecp256k1_v0_11_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const rustsecp256k1_v0_11_musig_keyagg_cache *cache, const unsigned char *msg32, unsigned char *sig64) { + int i; + const rustsecp256k1_v0_11_musig_pubnonce *pubnonces[N_SIGNERS]; + const rustsecp256k1_v0_11_musig_partial_sig *partial_sigs[N_SIGNERS]; + /* The same for all signers */ + rustsecp256k1_v0_11_musig_session session; + rustsecp256k1_v0_11_musig_aggnonce agg_pubnonce; + + for (i = 0; i < N_SIGNERS; i++) { + unsigned char seckey[32]; + unsigned char session_secrand[32]; + /* Create random session ID. It is absolutely necessary that the session ID + * is unique for every call of rustsecp256k1_v0_11_musig_nonce_gen. Otherwise + * it's trivial for an attacker to extract the secret key! */ + if (!fill_random(session_secrand, sizeof(session_secrand))) { + return 0; + } + if (!rustsecp256k1_v0_11_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) { + return 0; + } + /* Initialize session and create secret nonce for signing and public + * nonce to send to the other signers. */ + if (!rustsecp256k1_v0_11_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_secrand, seckey, &signer[i].pubkey, msg32, NULL, NULL)) { + return 0; + } + pubnonces[i] = &signer[i].pubnonce; + + secure_erase(seckey, sizeof(seckey)); + } + + /* Communication round 1: Every signer sends their pubnonce to the + * coordinator. The coordinator runs rustsecp256k1_v0_11_musig_nonce_agg and sends + * agg_pubnonce to each signer */ + if (!rustsecp256k1_v0_11_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, N_SIGNERS)) { + return 0; + } + + /* Every signer creates a partial signature */ + for (i = 0; i < N_SIGNERS; i++) { + /* Initialize the signing session by processing the aggregate nonce */ + if (!rustsecp256k1_v0_11_musig_nonce_process(ctx, &session, &agg_pubnonce, msg32, cache)) { + return 0; + } + /* partial_sign will clear the secnonce by setting it to 0. That's because + * you must _never_ reuse the secnonce (or use the same session_secrand to + * create a secnonce). If you do, you effectively reuse the nonce and + * leak the secret key. */ + if (!rustsecp256k1_v0_11_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, cache, &session)) { + return 0; + } + partial_sigs[i] = &signer[i].partial_sig; + } + /* Communication round 2: Every signer sends their partial signature to the + * coordinator, who verifies the partial signatures and aggregates them. */ + for (i = 0; i < N_SIGNERS; i++) { + /* To check whether signing was successful, it suffices to either verify + * the aggregate signature with the aggregate public key using + * rustsecp256k1_v0_11_schnorrsig_verify, or verify all partial signatures of all + * signers individually. Verifying the aggregate signature is cheaper but + * verifying the individual partial signatures has the advantage that it + * can be used to determine which of the partial signatures are invalid + * (if any), i.e., which of the partial signatures cause the aggregate + * signature to be invalid and thus the protocol run to fail. It's also + * fine to first verify the aggregate sig, and only verify the individual + * sigs if it does not work. + */ + if (!rustsecp256k1_v0_11_musig_partial_sig_verify(ctx, &signer[i].partial_sig, &signer[i].pubnonce, &signer[i].pubkey, cache, &session)) { + return 0; + } + } + return rustsecp256k1_v0_11_musig_partial_sig_agg(ctx, sig64, &session, partial_sigs, N_SIGNERS); +} + +int main(void) { + rustsecp256k1_v0_11_context* ctx; + int i; + struct signer_secrets signer_secrets[N_SIGNERS]; + struct signer signers[N_SIGNERS]; + const rustsecp256k1_v0_11_pubkey *pubkeys_ptr[N_SIGNERS]; + rustsecp256k1_v0_11_xonly_pubkey agg_pk; + rustsecp256k1_v0_11_musig_keyagg_cache cache; + unsigned char msg[32] = "this_could_be_the_hash_of_a_msg"; + unsigned char sig[64]; + + /* Create a secp256k1 context */ + ctx = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); + printf("Creating key pairs......"); + fflush(stdout); + for (i = 0; i < N_SIGNERS; i++) { + if (!create_keypair(ctx, &signer_secrets[i], &signers[i])) { + printf("FAILED\n"); + return 1; + } + pubkeys_ptr[i] = &signers[i].pubkey; + } + printf("ok\n"); + + /* The aggregate public key produced by rustsecp256k1_v0_11_musig_pubkey_agg depends + * on the order of the provided public keys. If there is no canonical order + * of the signers, the individual public keys can optionally be sorted with + * rustsecp256k1_v0_11_ec_pubkey_sort to ensure that the aggregate public key is + * independent of the order of signers. */ + printf("Sorting public keys....."); + fflush(stdout); + if (!rustsecp256k1_v0_11_ec_pubkey_sort(ctx, pubkeys_ptr, N_SIGNERS)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + + printf("Combining public keys..."); + fflush(stdout); + /* If you just want to aggregate and not sign, you can call + * rustsecp256k1_v0_11_musig_pubkey_agg with the keyagg_cache argument set to NULL + * while providing a non-NULL agg_pk argument. */ + if (!rustsecp256k1_v0_11_musig_pubkey_agg(ctx, NULL, &cache, pubkeys_ptr, N_SIGNERS)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + printf("Tweaking................"); + fflush(stdout); + /* Optionally tweak the aggregate key */ + if (!tweak(ctx, &agg_pk, &cache)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + printf("Signing message........."); + fflush(stdout); + if (!sign(ctx, signer_secrets, signers, &cache, msg, sig)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + printf("Verifying signature....."); + fflush(stdout); + if (!rustsecp256k1_v0_11_schnorrsig_verify(ctx, sig, msg, 32, &agg_pk)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + + /* It's best practice to try to clear secrets from memory after using them. + * This is done because some bugs can allow an attacker to leak memory, for + * example through "out of bounds" array access (see Heartbleed), or the OS + * swapping them to disk. Hence, we overwrite secret key material with zeros. + * + * Here we are preventing these writes from being optimized out, as any good compiler + * will remove any writes that aren't used. */ + for (i = 0; i < N_SIGNERS; i++) { + secure_erase(&signer_secrets[i], sizeof(signer_secrets[i])); + } + rustsecp256k1_v0_11_context_destroy(ctx); + return 0; +} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/schnorr.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/schnorr.c similarity index 59% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/schnorr.c rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/schnorr.c index be2f4d3a..e41be3ee 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/examples/schnorr.c +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/examples/schnorr.c @@ -15,64 +15,57 @@ #include #include -#include "random.h" +#include "examples_util.h" int main(void) { - unsigned char msg[12] = "Hello World!"; + unsigned char msg[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'}; unsigned char msg_hash[32]; - unsigned char tag[17] = "my_fancy_protocol"; + unsigned char tag[] = {'m', 'y', '_', 'f', 'a', 'n', 'c', 'y', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l'}; unsigned char seckey[32]; unsigned char randomize[32]; unsigned char auxiliary_rand[32]; unsigned char serialized_pubkey[32]; unsigned char signature[64]; - int is_signature_valid; + int is_signature_valid, is_signature_valid2; int return_val; - rustsecp256k1zkp_v0_8_0_xonly_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_keypair keypair; - /* The specification in rustsecp256k1zkp_v0_8_0_extrakeys.h states that `rustsecp256k1zkp_v0_8_0_keypair_create` - * needs a context object initialized for signing. And in rustsecp256k1zkp_v0_8_0_schnorrsig.h - * they state that `rustsecp256k1zkp_v0_8_0_schnorrsig_verify` needs a context initialized for - * verification, which is why we create a context for both signing and verification - * with the SECP256K1_CONTEXT_SIGN and SECP256K1_CONTEXT_VERIFY flags. */ - rustsecp256k1zkp_v0_8_0_context* ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + rustsecp256k1_v0_11_xonly_pubkey pubkey; + rustsecp256k1_v0_11_keypair keypair; + /* Before we can call actual API functions, we need to create a "context". */ + rustsecp256k1_v0_11_context* ctx = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); if (!fill_random(randomize, sizeof(randomize))) { printf("Failed to generate randomness\n"); return 1; } /* Randomizing the context is recommended to protect against side-channel - * leakage See `rustsecp256k1zkp_v0_8_0_context_randomize` in secp256k1.h for more + * leakage See `rustsecp256k1_v0_11_context_randomize` in secp256k1.h for more * information about it. This should never fail. */ - return_val = rustsecp256k1zkp_v0_8_0_context_randomize(ctx, randomize); + return_val = rustsecp256k1_v0_11_context_randomize(ctx, randomize); assert(return_val); /*** Key Generation ***/ - - /* If the secret key is zero or out of range (bigger than secp256k1's - * order), we try to sample a new key. Note that the probability of this - * happening is negligible. */ - while (1) { - if (!fill_random(seckey, sizeof(seckey))) { - printf("Failed to generate randomness\n"); - return 1; - } - /* Try to create a keypair with a valid context, it should only fail if - * the secret key is zero or out of range. */ - if (rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, seckey)) { - break; - } + if (!fill_random(seckey, sizeof(seckey))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* Try to create a keypair with a valid context. This only fails if the + * secret key is zero or out of range (greater than secp256k1's order). Note + * that the probability of this occurring is negligible with a properly + * functioning random number generator. */ + if (!rustsecp256k1_v0_11_keypair_create(ctx, &keypair, seckey)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return 1; } /* Extract the X-only public key from the keypair. We pass NULL for * `pk_parity` as the parity isn't needed for signing or verification. - * `rustsecp256k1zkp_v0_8_0_keypair_xonly_pub` supports returning the parity for + * `rustsecp256k1_v0_11_keypair_xonly_pub` supports returning the parity for * other use cases such as tests or verifying Taproot tweaks. * This should never fail with a valid context and public key. */ - return_val = rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(ctx, &pubkey, NULL, &keypair); + return_val = rustsecp256k1_v0_11_keypair_xonly_pub(ctx, &pubkey, NULL, &keypair); assert(return_val); /* Serialize the public key. Should always return 1 for a valid public key. */ - return_val = rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, serialized_pubkey, &pubkey); + return_val = rustsecp256k1_v0_11_xonly_pubkey_serialize(ctx, serialized_pubkey, &pubkey); assert(return_val); /*** Signing ***/ @@ -80,7 +73,7 @@ int main(void) { /* Instead of signing (possibly very long) messages directly, we sign a * 32-byte hash of the message in this example. * - * We use rustsecp256k1zkp_v0_8_0_tagged_sha256 to create this hash. This function expects + * We use rustsecp256k1_v0_11_tagged_sha256 to create this hash. This function expects * a context-specific "tag", which restricts the context in which the signed * messages should be considered valid. For example, if protocol A mandates * to use the tag "my_fancy_protocol" and protocol B mandates to use the tag @@ -91,7 +84,7 @@ int main(void) { * message that has intended consequences in the intended context (e.g., * protocol A) but would have unintended consequences if it were valid in * some other context (e.g., protocol B). */ - return_val = rustsecp256k1zkp_v0_8_0_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg)); + return_val = rustsecp256k1_v0_11_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg)); assert(return_val); /* Generate 32 bytes of randomness to use with BIP-340 schnorr signing. */ @@ -102,30 +95,30 @@ int main(void) { /* Generate a Schnorr signature. * - * We use the rustsecp256k1zkp_v0_8_0_schnorrsig_sign32 function that provides a simple + * We use the rustsecp256k1_v0_11_schnorrsig_sign32 function that provides a simple * interface for signing 32-byte messages (which in our case is a hash of * the actual message). BIP-340 recommends passing 32 bytes of randomness * to the signing function to improve security against side-channel attacks. * Signing with a valid context, a 32-byte message, a verified keypair, and * any 32 bytes of auxiliary random data should never fail. */ - return_val = rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(ctx, signature, msg_hash, &keypair, auxiliary_rand); + return_val = rustsecp256k1_v0_11_schnorrsig_sign32(ctx, signature, msg_hash, &keypair, auxiliary_rand); assert(return_val); /*** Verification ***/ /* Deserialize the public key. This will return 0 if the public key can't * be parsed correctly */ - if (!rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(ctx, &pubkey, serialized_pubkey)) { + if (!rustsecp256k1_v0_11_xonly_pubkey_parse(ctx, &pubkey, serialized_pubkey)) { printf("Failed parsing the public key\n"); return 1; } /* Compute the tagged hash on the received messages using the same tag as the signer. */ - return_val = rustsecp256k1zkp_v0_8_0_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg)); + return_val = rustsecp256k1_v0_11_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg)); assert(return_val); /* Verify a signature. This will return 1 if it's valid and 0 if it's not. */ - is_signature_valid = rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, signature, msg_hash, 32, &pubkey); + is_signature_valid = rustsecp256k1_v0_11_schnorrsig_verify(ctx, signature, msg_hash, 32, &pubkey); printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false"); @@ -137,16 +130,24 @@ int main(void) { print_hex(signature, sizeof(signature)); /* This will clear everything from the context and free the memory */ - rustsecp256k1zkp_v0_8_0_context_destroy(ctx); + rustsecp256k1_v0_11_context_destroy(ctx); + + /* Bonus example: if all we need is signature verification (and no key + generation or signing), we don't need to use a context created via + rustsecp256k1_v0_11_context_create(). We can simply use the static (i.e., global) + context rustsecp256k1_v0_11_context_static. See its description in + include/secp256k1.h for details. */ + is_signature_valid2 = rustsecp256k1_v0_11_schnorrsig_verify(rustsecp256k1_v0_11_context_static, + signature, msg_hash, 32, &pubkey); + assert(is_signature_valid2 == is_signature_valid); /* It's best practice to try to clear secrets from memory after using them. * This is done because some bugs can allow an attacker to leak memory, for - * example through "out of bounds" array access (see Heartbleed), Or the OS + * example through "out of bounds" array access (see Heartbleed), or the OS * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. * - * TODO: Prevent these writes from being optimized out, as any good compiler + * Here we are preventing these writes from being optimized out, as any good compiler * will remove any writes that aren't used. */ - memset(seckey, 0, sizeof(seckey)); - + secure_erase(seckey, sizeof(seckey)); return 0; } diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1.h similarity index 53% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1.h index c09ffbdf..300b6c91 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1.h @@ -7,7 +7,7 @@ extern "C" { #include -/* Unless explicitly stated all pointer arguments must not be NULL. +/** Unless explicitly stated all pointer arguments must not be NULL. * * The following rules specify the order of arguments in API calls: * @@ -24,39 +24,30 @@ extern "C" { * 5. Opaque data pointers follow the function pointer they are to be passed to. */ -/** Opaque data structure that holds context information (precomputed tables etc.). +/** Opaque data structure that holds context information * - * The purpose of context structures is to cache large precomputed data tables - * that are expensive to construct, and also to maintain the randomization data - * for blinding. + * The primary purpose of context objects is to store randomization data for + * enhanced protection against side-channel leakage. This protection is only + * effective if the context is randomized after its creation. See + * rustsecp256k1_v0_11_context_create for creation of contexts and + * rustsecp256k1_v0_11_context_randomize for randomization. * - * Do not create a new context object for each operation, as construction is - * far slower than all other API calls (~100 times slower than an ECDSA - * verification). + * A secondary purpose of context objects is to store pointers to callback + * functions that the library will call when certain error states arise. See + * rustsecp256k1_v0_11_context_set_error_callback as well as + * rustsecp256k1_v0_11_context_set_illegal_callback for details. Future library versions + * may use context objects for additional purposes. * * A constructed context can safely be used from multiple threads * simultaneously, but API calls that take a non-const pointer to a context * need exclusive access to it. In particular this is the case for - * rustsecp256k1zkp_v0_8_0_context_destroy, rustsecp256k1zkp_v0_8_0_context_preallocated_destroy, - * and rustsecp256k1zkp_v0_8_0_context_randomize. + * rustsecp256k1_v0_11_context_destroy, rustsecp256k1_v0_11_context_preallocated_destroy, + * and rustsecp256k1_v0_11_context_randomize. * * Regarding randomization, either do it once at creation time (in which case * you do not need any locking for the other calls), or use a read-write lock. */ -typedef struct rustsecp256k1zkp_v0_8_0_context_struct rustsecp256k1zkp_v0_8_0_context; - -/** Opaque data structure that holds rewriteable "scratch space" - * - * The purpose of this structure is to replace dynamic memory allocations, - * because we target architectures where this may not be available. It is - * essentially a resizable (within specified parameters) block of bytes, - * which is initially created either by memory allocation or TODO as a pointer - * into some fixed rewritable space. - * - * Unlike the context object, this cannot safely be shared between threads - * without additional synchronization logic. - */ -typedef struct rustsecp256k1zkp_v0_8_0_scratch_space_struct rustsecp256k1zkp_v0_8_0_scratch_space; +typedef struct rustsecp256k1_v0_11_context_struct rustsecp256k1_v0_11_context; /** Opaque data structure that holds a parsed and valid public key. * @@ -64,25 +55,25 @@ typedef struct rustsecp256k1zkp_v0_8_0_scratch_space_struct rustsecp256k1zkp_v0_ * guaranteed to be portable between different platforms or versions. It is * however guaranteed to be 64 bytes in size, and can be safely copied/moved. * If you need to convert to a format suitable for storage or transmission, - * use rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize and rustsecp256k1zkp_v0_8_0_ec_pubkey_parse. To - * compare keys, use rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp. + * use rustsecp256k1_v0_11_ec_pubkey_serialize and rustsecp256k1_v0_11_ec_pubkey_parse. To + * compare keys, use rustsecp256k1_v0_11_ec_pubkey_cmp. */ -typedef struct { +typedef struct rustsecp256k1_v0_11_pubkey { unsigned char data[64]; -} rustsecp256k1zkp_v0_8_0_pubkey; +} rustsecp256k1_v0_11_pubkey; -/** Opaque data structured that holds a parsed ECDSA signature. +/** Opaque data structure that holds a parsed ECDSA signature. * * The exact representation of data inside is implementation defined and not * guaranteed to be portable between different platforms or versions. It is * however guaranteed to be 64 bytes in size, and can be safely copied/moved. * If you need to convert to a format suitable for storage, transmission, or - * comparison, use the rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_* and - * rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_* functions. + * comparison, use the rustsecp256k1_v0_11_ecdsa_signature_serialize_* and + * rustsecp256k1_v0_11_ecdsa_signature_parse_* functions. */ -typedef struct { +typedef struct rustsecp256k1_v0_11_ecdsa_signature { unsigned char data[64]; -} rustsecp256k1zkp_v0_8_0_ecdsa_signature; +} rustsecp256k1_v0_11_ecdsa_signature; /** A pointer to a function to deterministically generate a nonce. * @@ -100,7 +91,7 @@ typedef struct { * Except for test cases, this function should compute some cryptographic hash of * the message, the algorithm, the key and the attempt. */ -typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function)( +typedef int (*rustsecp256k1_v0_11_nonce_function)( unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, @@ -118,19 +109,7 @@ typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function)( # endif # endif -# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) -# if SECP256K1_GNUC_PREREQ(2,7) -# define SECP256K1_INLINE __inline__ -# elif (defined(_MSC_VER)) -# define SECP256K1_INLINE __inline -# else -# define SECP256K1_INLINE -# endif -# else -# define SECP256K1_INLINE inline -# endif - -/** When this header is used at build-time the SECP256K1_BUILD define needs to be set +/* When this header is used at build-time the SECP256K1_BUILD define needs to be set * to correctly setup export attributes and nullness checks. This is normally done * by secp256k1.c but to guard against this header being included before secp256k1.c * has had a chance to set the define (e.g. via test harnesses that just includes @@ -141,23 +120,51 @@ typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function)( # define SECP256K1_NO_BUILD #endif -#ifndef SECP256K1_API -# if defined(_WIN32) -# ifdef SECP256K1_BUILD -# define SECP256K1_API __declspec(dllexport) +/* Symbol visibility. */ +#if defined(_WIN32) + /* GCC for Windows (e.g., MinGW) accepts the __declspec syntax + * for MSVC compatibility. A __declspec declaration implies (but is not + * exactly equivalent to) __attribute__ ((visibility("default"))), and so we + * actually want __declspec even on GCC, see "Microsoft Windows Function + * Attributes" in the GCC manual and the recommendations in + * https://gcc.gnu.org/wiki/Visibility. */ +# if defined(SECP256K1_BUILD) +# if defined(DLL_EXPORT) || defined(SECP256K1_DLL_EXPORT) + /* Building libsecp256k1 as a DLL. + * 1. If using Libtool, it defines DLL_EXPORT automatically. + * 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */ +# define SECP256K1_API extern __declspec (dllexport) # else -# define SECP256K1_API + /* Building libsecp256k1 as a static library on Windows. + * No declspec is needed, and so we would want the non-Windows-specific + * logic below take care of this case. However, this may result in setting + * __attribute__ ((visibility("default"))), which is supposed to be a noop + * on Windows but may trigger warnings when compiling with -flto due to a + * bug in GCC, see + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116478 . */ +# define SECP256K1_API extern # endif -# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD) -# define SECP256K1_API __attribute__ ((visibility ("default"))) + /* The user must define SECP256K1_STATIC when consuming libsecp256k1 as a static + * library on Windows. */ +# elif !defined(SECP256K1_STATIC) + /* Consuming libsecp256k1 as a DLL. */ +# define SECP256K1_API extern __declspec (dllimport) +# endif +#endif +#ifndef SECP256K1_API +/* All cases not captured by the Windows-specific logic. */ +# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD) + /* Building libsecp256k1 using GCC or compatible. */ +# define SECP256K1_API extern __attribute__ ((visibility ("default"))) # else -# define SECP256K1_API + /* Fall back to standard C's extern. */ +# define SECP256K1_API extern # endif #endif -/**Warning attributes - * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out - * some paranoid null checks. */ +/* Warning attributes + * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out + * some paranoid null checks. */ # if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) # define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) # else @@ -169,7 +176,7 @@ typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function)( # define SECP256K1_ARG_NONNULL(_x) # endif -/** Attribute for marking functions, types, and variables as deprecated */ +/* Attribute for marking functions, types, and variables as deprecated */ #if !defined(SECP256K1_BUILD) && defined(__has_attribute) # if __has_attribute(__deprecated__) # define SECP256K1_DEPRECATED(_msg) __attribute__ ((__deprecated__(_msg))) @@ -180,24 +187,28 @@ typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function)( # define SECP256K1_DEPRECATED(_msg) #endif -/** All flags' lower 8 bits indicate what they're for. Do not use directly. */ +/* All flags' lower 8 bits indicate what they're for. Do not use directly. */ #define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1) #define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0) #define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) -/** The higher bits contain the actual data. Do not use directly. */ +/* The higher bits contain the actual data. Do not use directly. */ #define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8) #define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9) #define SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY (1 << 10) #define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) -/** Flags to pass to rustsecp256k1zkp_v0_8_0_context_create, rustsecp256k1zkp_v0_8_0_context_preallocated_size, and - * rustsecp256k1zkp_v0_8_0_context_preallocated_create. */ +/** Context flags to pass to rustsecp256k1_v0_11_context_create, rustsecp256k1_v0_11_context_preallocated_size, and + * rustsecp256k1_v0_11_context_preallocated_create. */ +#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) + +/** Deprecated context flags. These flags are treated equivalent to SECP256K1_CONTEXT_NONE. */ #define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) #define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN) + +/* Testing flag. Do not use. */ #define SECP256K1_CONTEXT_DECLASSIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY) -#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) -/** Flag to pass to rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize. */ +/** Flag to pass to rustsecp256k1_v0_11_ec_pubkey_serialize. */ #define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) #define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) @@ -208,49 +219,90 @@ typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function)( #define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06 #define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07 -/** A simple secp256k1 context object with no precomputed tables. These are useful for - * type serialization/parsing functions which require a context object to maintain - * API consistency, but currently do not require expensive precomputations or dynamic - * allocations. +/** A built-in constant secp256k1 context object with static storage duration, to be + * used in conjunction with rustsecp256k1_v0_11_selftest. + * + * This context object offers *only limited functionality* , i.e., it cannot be used + * for API functions that perform computations involving secret keys, e.g., signing + * and public key generation. If this restriction applies to a specific API function, + * it is mentioned in its documentation. See rustsecp256k1_v0_11_context_create if you need a + * full context object that supports all functionality offered by the library. + * + * It is highly recommended to call rustsecp256k1_v0_11_selftest before using this context. */ -SECP256K1_API extern const rustsecp256k1zkp_v0_8_0_context *rustsecp256k1zkp_v0_8_0_context_no_precomp; + +/** Deprecated alias for rustsecp256k1_v0_11_context_static. */ + +/** Perform basic self tests (to be used in conjunction with rustsecp256k1_v0_11_context_static) + * + * This function performs self tests that detect some serious usage errors and + * similar conditions, e.g., when the library is compiled for the wrong endianness. + * This is a last resort measure to be used in production. The performed tests are + * very rudimentary and are not intended as a replacement for running the test + * binaries. + * + * It is highly recommended to call this before using rustsecp256k1_v0_11_context_static. + * It is not necessary to call this function before using a context created with + * rustsecp256k1_v0_11_context_create (or rustsecp256k1_v0_11_context_preallocated_create), which will + * take care of performing the self tests. + * + * If the tests fail, this function will call the default error handler to abort the + * program (see rustsecp256k1_v0_11_context_set_error_callback). + */ +SECP256K1_API void rustsecp256k1_v0_11_selftest(void); + /** Create a secp256k1 context object (in dynamically allocated memory). * * This function uses malloc to allocate memory. It is guaranteed that malloc is * called at most once for every call of this function. If you need to avoid dynamic - * memory allocation entirely, see the functions in rustsecp256k1zkp_v0_8_0_preallocated.h. + * memory allocation entirely, see rustsecp256k1_v0_11_context_static and the functions in + * rustsecp256k1_v0_11_preallocated.h. + * + * Returns: pointer to a newly created context object. + * In: flags: Always set to SECP256K1_CONTEXT_NONE (see below). * - * Returns: a newly created context object. - * In: flags: which parts of the context to initialize. + * The only valid non-deprecated flag in recent library versions is + * SECP256K1_CONTEXT_NONE, which will create a context sufficient for all functionality + * offered by the library. All other (deprecated) flags will be treated as equivalent + * to the SECP256K1_CONTEXT_NONE flag. Though the flags parameter primarily exists for + * historical reasons, future versions of the library may introduce new flags. * - * See also rustsecp256k1zkp_v0_8_0_context_randomize. + * If the context is intended to be used for API functions that perform computations + * involving secret keys, e.g., signing and public key generation, then it is highly + * recommended to call rustsecp256k1_v0_11_context_randomize on the context before calling + * those API functions. This will provide enhanced protection against side-channel + * leakage, see rustsecp256k1_v0_11_context_randomize for details. + * + * Do not create a new context object for each operation, as construction and + * randomization can take non-negligible time. */ - /** Copy a secp256k1 context object (into dynamically allocated memory). * * This function uses malloc to allocate memory. It is guaranteed that malloc is * called at most once for every call of this function. If you need to avoid dynamic - * memory allocation entirely, see the functions in rustsecp256k1zkp_v0_8_0_preallocated.h. + * memory allocation entirely, see the functions in rustsecp256k1_v0_11_preallocated.h. + * + * Cloning rustsecp256k1_v0_11_context_static is not possible, and should not be emulated by + * the caller (e.g., using memcpy). Create a new context instead. * - * Returns: a newly created context object. - * Args: ctx: an existing context to copy + * Returns: pointer to a newly created context object. + * Args: ctx: pointer to a context to copy (not rustsecp256k1_v0_11_context_static). */ - /** Destroy a secp256k1 context object (created in dynamically allocated memory). * * The context pointer may not be used afterwards. * - * The context to destroy must have been created using rustsecp256k1zkp_v0_8_0_context_create - * or rustsecp256k1zkp_v0_8_0_context_clone. If the context has instead been created using - * rustsecp256k1zkp_v0_8_0_context_preallocated_create or rustsecp256k1zkp_v0_8_0_context_preallocated_clone, the - * behaviour is undefined. In that case, rustsecp256k1zkp_v0_8_0_context_preallocated_destroy must + * The context to destroy must have been created using rustsecp256k1_v0_11_context_create + * or rustsecp256k1_v0_11_context_clone. If the context has instead been created using + * rustsecp256k1_v0_11_context_preallocated_create or rustsecp256k1_v0_11_context_preallocated_clone, the + * behaviour is undefined. In that case, rustsecp256k1_v0_11_context_preallocated_destroy must * be used instead. * - * Args: ctx: an existing context to destroy, constructed using - * rustsecp256k1zkp_v0_8_0_context_create or rustsecp256k1zkp_v0_8_0_context_clone + * Args: ctx: pointer to a context to destroy, constructed using + * rustsecp256k1_v0_11_context_create or rustsecp256k1_v0_11_context_clone + * (i.e., not rustsecp256k1_v0_11_context_static). */ - /** Set a callback function to be called when an illegal argument is passed to * an API call. It will only trigger for violations that are mentioned * explicitly in the header. @@ -272,73 +324,61 @@ SECP256K1_API extern const rustsecp256k1zkp_v0_8_0_context *rustsecp256k1zkp_v0_ * USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build * has been configured with --enable-external-default-callbacks. Then the * following two symbols must be provided to link against: - * - void rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn(const char* message, void* data); - * - void rustsecp256k1zkp_v0_8_0_default_error_callback_fn(const char* message, void* data); + * - void rustsecp256k1_v0_11_default_illegal_callback_fn(const char *message, void *data); + * - void rustsecp256k1_v0_11_default_error_callback_fn(const char *message, void *data); * The library can call these default handlers even before a proper callback data - * pointer could have been set using rustsecp256k1zkp_v0_8_0_context_set_illegal_callback or - * rustsecp256k1zkp_v0_8_0_context_set_error_callback, e.g., when the creation of a context + * pointer could have been set using rustsecp256k1_v0_11_context_set_illegal_callback or + * rustsecp256k1_v0_11_context_set_error_callback, e.g., when the creation of a context * fails. In this case, the corresponding default handler will be called with * the data pointer argument set to NULL. * - * Args: ctx: an existing context object. - * In: fun: a pointer to a function to call when an illegal argument is + * Args: ctx: pointer to a context object. + * In: fun: pointer to a function to call when an illegal argument is * passed to the API, taking a message and an opaque pointer. * (NULL restores the default handler.) * data: the opaque pointer to pass to fun above, must be NULL for the default handler. * - * See also rustsecp256k1zkp_v0_8_0_context_set_error_callback. + * See also rustsecp256k1_v0_11_context_set_error_callback. */ -SECP256K1_API void rustsecp256k1zkp_v0_8_0_context_set_illegal_callback( - rustsecp256k1zkp_v0_8_0_context* ctx, - void (*fun)(const char* message, void* data), - const void* data +SECP256K1_API void rustsecp256k1_v0_11_context_set_illegal_callback( + rustsecp256k1_v0_11_context *ctx, + void (*fun)(const char *message, void *data), + const void *data ) SECP256K1_ARG_NONNULL(1); /** Set a callback function to be called when an internal consistency check - * fails. The default is crashing. + * fails. + * + * The default callback writes an error message to stderr and calls abort + * to abort the program. * * This can only trigger in case of a hardware failure, miscompilation, * memory corruption, serious bug in the library, or other error would can * otherwise result in undefined behaviour. It will not trigger due to mere - * incorrect usage of the API (see rustsecp256k1zkp_v0_8_0_context_set_illegal_callback + * incorrect usage of the API (see rustsecp256k1_v0_11_context_set_illegal_callback * for that). After this callback returns, anything may happen, including * crashing. * - * Args: ctx: an existing context object. - * In: fun: a pointer to a function to call when an internal error occurs, + * Args: ctx: pointer to a context object. + * In: fun: pointer to a function to call when an internal error occurs, * taking a message and an opaque pointer (NULL restores the - * default handler, see rustsecp256k1zkp_v0_8_0_context_set_illegal_callback + * default handler, see rustsecp256k1_v0_11_context_set_illegal_callback * for details). * data: the opaque pointer to pass to fun above, must be NULL for the default handler. * - * See also rustsecp256k1zkp_v0_8_0_context_set_illegal_callback. + * See also rustsecp256k1_v0_11_context_set_illegal_callback. */ -SECP256K1_API void rustsecp256k1zkp_v0_8_0_context_set_error_callback( - rustsecp256k1zkp_v0_8_0_context* ctx, - void (*fun)(const char* message, void* data), - const void* data +SECP256K1_API void rustsecp256k1_v0_11_context_set_error_callback( + rustsecp256k1_v0_11_context *ctx, + void (*fun)(const char *message, void *data), + const void *data ) SECP256K1_ARG_NONNULL(1); -/** Create a secp256k1 scratch space object. - * - * Returns: a newly created scratch space. - * Args: ctx: an existing context object. - * In: size: amount of memory to be available as scratch space. Some extra - * (<100 bytes) will be allocated for extra accounting. - */ - -/** Destroy a secp256k1 scratch space. - * - * The pointer may not be used afterwards. - * Args: ctx: a secp256k1 context object. - * scratch: space to destroy - */ - /** Parse a variable-length public key into the pubkey object. * * Returns: 1 if the public key was fully valid. * 0 if the public key could not be parsed or is invalid. - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object. * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a * parsed version of input. If not, its value is undefined. * In: input: pointer to a serialized public key @@ -348,9 +388,9 @@ SECP256K1_API void rustsecp256k1zkp_v0_8_0_context_set_error_callback( * 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header * byte 0x06 or 0x07) format public keys. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey_parse( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey* pubkey, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_pubkey_parse( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *input, size_t inputlen ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -358,23 +398,23 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey /** Serialize a pubkey object into a serialized byte sequence. * * Returns: 1 always. - * Args: ctx: a secp256k1 context object. - * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if + * Args: ctx: pointer to a context object. + * Out: output: pointer to a 65-byte (if compressed==0) or 33-byte (if * compressed==1) byte array to place the serialized key * in. - * In/Out: outputlen: a pointer to an integer which is initially set to the + * In/Out: outputlen: pointer to an integer which is initially set to the * size of output, and is overwritten with the written * size. - * In: pubkey: a pointer to a rustsecp256k1zkp_v0_8_0_pubkey containing an + * In: pubkey: pointer to a rustsecp256k1_v0_11_pubkey containing an * initialized public key. * flags: SECP256K1_EC_COMPRESSED if serialization should be in * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API int rustsecp256k1_v0_11_ec_pubkey_serialize( + const rustsecp256k1_v0_11_context *ctx, unsigned char *output, size_t *outputlen, - const rustsecp256k1zkp_v0_8_0_pubkey* pubkey, + const rustsecp256k1_v0_11_pubkey *pubkey, unsigned int flags ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); @@ -383,55 +423,69 @@ SECP256K1_API int rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize( * Returns: <0 if the first public key is less than the second * >0 if the first public key is greater than the second * 0 if the two public keys are equal - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object * In: pubkey1: first public key to compare * pubkey2: second public key to compare */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_pubkey* pubkey1, - const rustsecp256k1zkp_v0_8_0_pubkey* pubkey2 +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_pubkey_cmp( + const rustsecp256k1_v0_11_context *ctx, + const rustsecp256k1_v0_11_pubkey *pubkey1, + const rustsecp256k1_v0_11_pubkey *pubkey2 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +/** Sort public keys using lexicographic (of compressed serialization) order + * + * Returns: 0 if the arguments are invalid. 1 otherwise. + * + * Args: ctx: pointer to a context object + * In: pubkeys: array of pointers to pubkeys to sort + * n_pubkeys: number of elements in the pubkeys array + */ +SECP256K1_API int rustsecp256k1_v0_11_ec_pubkey_sort( + const rustsecp256k1_v0_11_context *ctx, + const rustsecp256k1_v0_11_pubkey **pubkeys, + size_t n_pubkeys +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + /** Parse an ECDSA signature in compact (64 bytes) format. * * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input64: a pointer to the 64-byte array to parse + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input64: pointer to the 64-byte array to parse * * The signature must consist of a 32-byte big endian R value, followed by a * 32-byte big endian S value. If R or S fall outside of [0..order-1], the * encoding is invalid. R and S with value 0 are allowed in the encoding. * * After the call, sig will always be initialized. If parsing failed or R or - * S are zero, the resulting sig value is guaranteed to fail validation for any - * message and public key. + * S are zero, the resulting sig value is guaranteed to fail verification for + * any message and public key. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_signature_parse_compact( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_ecdsa_signature *sig, const unsigned char *input64 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Parse a DER ECDSA signature. * * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input: a pointer to the signature to be parsed + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input: pointer to the signature to be parsed * inputlen: the length of the array pointed to be input * * This function will accept any valid DER encoded signature, even if the * encoded numbers are out of range. * * After the call, sig will always be initialized. If parsing failed or the - * encoded numbers are out of range, signature validation with it is + * encoded numbers are out of range, signature verification with it is * guaranteed to fail for every message and public key. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_signature_parse_der( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_ecdsa_signature *sig, const unsigned char *input, size_t inputlen ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -439,41 +493,41 @@ SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der( /** Serialize an ECDSA signature in DER format. * * Returns: 1 if enough space was available to serialize, 0 otherwise - * Args: ctx: a secp256k1 context object - * Out: output: a pointer to an array to store the DER serialization - * In/Out: outputlen: a pointer to a length integer. Initially, this integer + * Args: ctx: pointer to a context object + * Out: output: pointer to an array to store the DER serialization + * In/Out: outputlen: pointer to a length integer. Initially, this integer * should be set to the length of output. After the call * it will be set to the length of the serialization (even * if 0 was returned). - * In: sig: a pointer to an initialized signature object + * In: sig: pointer to an initialized signature object */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_signature_serialize_der( + const rustsecp256k1_v0_11_context *ctx, unsigned char *output, size_t *outputlen, - const rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig + const rustsecp256k1_v0_11_ecdsa_signature *sig ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Serialize an ECDSA signature in compact (64 byte) format. * * Returns: 1 - * Args: ctx: a secp256k1 context object - * Out: output64: a pointer to a 64-byte array to store the compact serialization - * In: sig: a pointer to an initialized signature object + * Args: ctx: pointer to a context object + * Out: output64: pointer to a 64-byte array to store the compact serialization + * In: sig: pointer to an initialized signature object * - * See rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact for details about the encoding. + * See rustsecp256k1_v0_11_ecdsa_signature_parse_compact for details about the encoding. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_signature_serialize_compact( + const rustsecp256k1_v0_11_context *ctx, unsigned char *output64, - const rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig + const rustsecp256k1_v0_11_ecdsa_signature *sig ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Verify an ECDSA signature. * * Returns: 1: correct signature * 0: incorrect or unparseable signature - * Args: ctx: a secp256k1 context object, initialized for verification. + * Args: ctx: pointer to a context object * In: sig: the signature being verified. * msghash32: the 32-byte message hash being verified. * The verifier must make sure to apply a cryptographic @@ -489,27 +543,27 @@ SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact( * form are accepted. * * If you need to accept ECDSA signatures from sources that do not obey this - * rule, apply rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize to the signature prior to - * validation, but be aware that doing so results in malleable signatures. + * rule, apply rustsecp256k1_v0_11_ecdsa_signature_normalize to the signature prior to + * verification, but be aware that doing so results in malleable signatures. * * For details, see the comments for that function. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ecdsa_verify( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_ecdsa_signature *sig, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ecdsa_verify( + const rustsecp256k1_v0_11_context *ctx, + const rustsecp256k1_v0_11_ecdsa_signature *sig, const unsigned char *msghash32, - const rustsecp256k1zkp_v0_8_0_pubkey *pubkey + const rustsecp256k1_v0_11_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Convert a signature to a normalized lower-S form. * * Returns: 1 if sigin was not normalized, 0 if it already was. - * Args: ctx: a secp256k1 context object - * Out: sigout: a pointer to a signature to fill with the normalized form, + * Args: ctx: pointer to a context object + * Out: sigout: pointer to a signature to fill with the normalized form, * or copy if the input was already normalized. (can be NULL if * you're only interested in whether the input was already * normalized). - * In: sigin: a pointer to a signature to check/normalize (can be identical to sigout) + * In: sigin: pointer to a signature to check/normalize (can be identical to sigout) * * With ECDSA a third-party can forge a second distinct signature of the same * message, given a single initial signature, but without knowing the key. This @@ -537,67 +591,67 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ecdsa_ver * accept various non-unique encodings, so care should be taken when this * property is required for an application. * - * The rustsecp256k1zkp_v0_8_0_ecdsa_sign function will by default create signatures in the - * lower-S form, and rustsecp256k1zkp_v0_8_0_ecdsa_verify will not accept others. In case + * The rustsecp256k1_v0_11_ecdsa_sign function will by default create signatures in the + * lower-S form, and rustsecp256k1_v0_11_ecdsa_verify will not accept others. In case * signatures come from a system that cannot enforce this property, - * rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize must be called before verification. + * rustsecp256k1_v0_11_ecdsa_signature_normalize must be called before verification. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_signature *sigout, - const rustsecp256k1zkp_v0_8_0_ecdsa_signature *sigin +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_signature_normalize( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_ecdsa_signature *sigout, + const rustsecp256k1_v0_11_ecdsa_signature *sigin ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); /** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of * extra entropy. */ -SECP256K1_API extern const rustsecp256k1zkp_v0_8_0_nonce_function rustsecp256k1zkp_v0_8_0_nonce_function_rfc6979; -/** A default safe nonce generation function (currently equal to rustsecp256k1zkp_v0_8_0_nonce_function_rfc6979). */ -SECP256K1_API extern const rustsecp256k1zkp_v0_8_0_nonce_function rustsecp256k1zkp_v0_8_0_nonce_function_default; +/** A default safe nonce generation function (currently equal to rustsecp256k1_v0_11_nonce_function_rfc6979). */ /** Create an ECDSA signature. * * Returns: 1: signature created * 0: the nonce generation function failed, or the secret key was invalid. - * Args: ctx: pointer to a context object, initialized for signing. + * Args: ctx: pointer to a context object (not rustsecp256k1_v0_11_context_static). * Out: sig: pointer to an array where the signature will be placed. * In: msghash32: the 32-byte message hash being signed. * seckey: pointer to a 32-byte secret key. * noncefp: pointer to a nonce generation function. If NULL, - * rustsecp256k1zkp_v0_8_0_nonce_function_default is used. + * rustsecp256k1_v0_11_nonce_function_default is used. * ndata: pointer to arbitrary data used by the nonce generation function * (can be NULL). If it is non-NULL and - * rustsecp256k1zkp_v0_8_0_nonce_function_default is used, then ndata must be a + * rustsecp256k1_v0_11_nonce_function_default is used, then ndata must be a * pointer to 32-bytes of additional data. * * The created signature is always in lower-S form. See - * rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize for more details. + * rustsecp256k1_v0_11_ecdsa_signature_normalize for more details. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_sign( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_signature *sig, +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_sign( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_ecdsa_signature *sig, const unsigned char *msghash32, const unsigned char *seckey, - rustsecp256k1zkp_v0_8_0_nonce_function noncefp, + rustsecp256k1_v0_11_nonce_function noncefp, const void *ndata ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); -/** Verify an ECDSA secret key. +/** Verify an elliptic curve secret key. * * A secret key is valid if it is not 0 and less than the secp256k1 curve order * when interpreted as an integer (most significant byte first). The * probability of choosing a 32-byte string uniformly at random which is an - * invalid secret key is negligible. + * invalid secret key is negligible. However, if it does happen it should + * be assumed that the randomness source is severely broken and there should + * be no retry. * * Returns: 1: secret key is valid * 0: secret key is invalid * Args: ctx: pointer to a context object. * In: seckey: pointer to a 32-byte secret key. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_seckey_verify( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_seckey_verify( + const rustsecp256k1_v0_11_context *ctx, const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); @@ -605,38 +659,38 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_seckey * * Returns: 1: secret was valid, public key stores. * 0: secret was invalid, try again. - * Args: ctx: pointer to a context object, initialized for signing. + * Args: ctx: pointer to a context object (not rustsecp256k1_v0_11_context_static). * Out: pubkey: pointer to the created public key. * In: seckey: pointer to a 32-byte secret key. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey_create( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *pubkey, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_pubkey_create( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Negates a secret key in place. * * Returns: 0 if the given secret key is invalid according to - * rustsecp256k1zkp_v0_8_0_ec_seckey_verify. 1 otherwise + * rustsecp256k1_v0_11_ec_seckey_verify. 1 otherwise * Args: ctx: pointer to a context object * In/Out: seckey: pointer to the 32-byte secret key to be negated. If the * secret key is invalid according to - * rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this function returns 0 and + * rustsecp256k1_v0_11_ec_seckey_verify, this function returns 0 and * seckey will be set to some unspecified value. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_seckey_negate( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_seckey_negate( + const rustsecp256k1_v0_11_context *ctx, unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); -/** Same as rustsecp256k1zkp_v0_8_0_ec_seckey_negate, but DEPRECATED. Will be removed in +/** Same as rustsecp256k1_v0_11_ec_seckey_negate, but DEPRECATED. Will be removed in * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_privkey_negate( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_privkey_negate( + const rustsecp256k1_v0_11_context *ctx, unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) - SECP256K1_DEPRECATED("Use rustsecp256k1zkp_v0_8_0_ec_seckey_negate instead"); + SECP256K1_DEPRECATED("Use rustsecp256k1_v0_11_ec_seckey_negate instead"); /** Negates a public key in place. * @@ -644,9 +698,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_privke * Args: ctx: pointer to a context object * In/Out: pubkey: pointer to the public key to be negated. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey_negate( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *pubkey +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_pubkey_negate( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); /** Tweak a secret key by adding tweak to it. @@ -656,45 +710,45 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey * otherwise. * Args: ctx: pointer to a context object. * In/Out: seckey: pointer to a 32-byte secret key. If the secret key is - * invalid according to rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this + * invalid according to rustsecp256k1_v0_11_ec_seckey_verify, this * function returns 0. seckey will be set to some unspecified * value if this function returns 0. - * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to - * rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this function returns 0. For - * uniformly random 32-byte arrays the chance of being invalid - * is negligible (around 1 in 2^128). + * In: tweak32: pointer to a 32-byte tweak, which must be valid according to + * rustsecp256k1_v0_11_ec_seckey_verify or 32 zero bytes. For uniformly + * random 32-byte tweaks, the chance of being invalid is + * negligible (around 1 in 2^128). */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_seckey_tweak_add( + const rustsecp256k1_v0_11_context *ctx, unsigned char *seckey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Same as rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add, but DEPRECATED. Will be removed in +/** Same as rustsecp256k1_v0_11_ec_seckey_tweak_add, but DEPRECATED. Will be removed in * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_privkey_tweak_add( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_privkey_tweak_add( + const rustsecp256k1_v0_11_context *ctx, unsigned char *seckey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) - SECP256K1_DEPRECATED("Use rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add instead"); + SECP256K1_DEPRECATED("Use rustsecp256k1_v0_11_ec_seckey_tweak_add instead"); /** Tweak a public key by adding tweak times the generator to it. * * Returns: 0 if the arguments are invalid or the resulting public key would be * invalid (only when the tweak is the negation of the corresponding * secret key). 1 otherwise. - * Args: ctx: pointer to a context object initialized for validation. + * Args: ctx: pointer to a context object. * In/Out: pubkey: pointer to a public key object. pubkey will be set to an * invalid value if this function returns 0. - * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to - * rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this function returns 0. For - * uniformly random 32-byte arrays the chance of being invalid - * is negligible (around 1 in 2^128). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *pubkey, + * In: tweak32: pointer to a 32-byte tweak, which must be valid according to + * rustsecp256k1_v0_11_ec_seckey_verify or 32 zero bytes. For uniformly + * random 32-byte tweaks, the chance of being invalid is + * negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_pubkey_tweak_add( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -703,73 +757,80 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey * Returns: 0 if the arguments are invalid. 1 otherwise. * Args: ctx: pointer to a context object. * In/Out: seckey: pointer to a 32-byte secret key. If the secret key is - * invalid according to rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this + * invalid according to rustsecp256k1_v0_11_ec_seckey_verify, this * function returns 0. seckey will be set to some unspecified * value if this function returns 0. * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to - * rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this function returns 0. For + * rustsecp256k1_v0_11_ec_seckey_verify, this function returns 0. For * uniformly random 32-byte arrays the chance of being invalid * is negligible (around 1 in 2^128). */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_seckey_tweak_mul( + const rustsecp256k1_v0_11_context *ctx, unsigned char *seckey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Same as rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in +/** Same as rustsecp256k1_v0_11_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_privkey_tweak_mul( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_privkey_tweak_mul( + const rustsecp256k1_v0_11_context *ctx, unsigned char *seckey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) - SECP256K1_DEPRECATED("Use rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul instead"); + SECP256K1_DEPRECATED("Use rustsecp256k1_v0_11_ec_seckey_tweak_mul instead"); /** Tweak a public key by multiplying it by a tweak value. * * Returns: 0 if the arguments are invalid. 1 otherwise. - * Args: ctx: pointer to a context object initialized for validation. + * Args: ctx: pointer to a context object. * In/Out: pubkey: pointer to a public key object. pubkey will be set to an * invalid value if this function returns 0. * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to - * rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this function returns 0. For + * rustsecp256k1_v0_11_ec_seckey_verify, this function returns 0. For * uniformly random 32-byte arrays the chance of being invalid * is negligible (around 1 in 2^128). */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_mul( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *pubkey, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_pubkey_tweak_mul( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Updates the context randomization to protect against side-channel leakage. - * Returns: 1: randomization successfully updated or nothing to randomize +/** Randomizes the context to provide enhanced protection against side-channel leakage. + * + * Returns: 1: randomization successful * 0: error - * Args: ctx: pointer to a context object. - * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state) + * Args: ctx: pointer to a context object (not rustsecp256k1_v0_11_context_static). + * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state). * - * While secp256k1 code is written to be constant-time no matter what secret - * values are, it's possible that a future compiler may output code which isn't, + * While secp256k1 code is written and tested to be constant-time no matter what + * secret values are, it is possible that a compiler may output code which is not, * and also that the CPU may not emit the same radio frequencies or draw the same - * amount power for all values. - * - * This function provides a seed which is combined into the blinding value: that - * blinding value is added before each multiplication (and removed afterwards) so - * that it does not affect function results, but shields against attacks which - * rely on any input-dependent behaviour. - * - * This function has currently an effect only on contexts initialized for signing - * because randomization is currently used only for signing. However, this is not - * guaranteed and may change in the future. It is safe to call this function on - * contexts not initialized for signing; then it will have no effect and return 1. - * - * You should call this after rustsecp256k1zkp_v0_8_0_context_create or - * rustsecp256k1zkp_v0_8_0_context_clone (and rustsecp256k1zkp_v0_8_0_context_preallocated_create or - * rustsecp256k1zkp_v0_8_0_context_clone, resp.), and you may call this repeatedly afterwards. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_context_randomize( - rustsecp256k1zkp_v0_8_0_context* ctx, + * amount of power for all values. Randomization of the context shields against + * side-channel observations which aim to exploit secret-dependent behaviour in + * certain computations which involve secret keys. + * + * It is highly recommended to call this function on contexts returned from + * rustsecp256k1_v0_11_context_create or rustsecp256k1_v0_11_context_clone (or from the corresponding + * functions in rustsecp256k1_v0_11_preallocated.h) before using these contexts to call API + * functions that perform computations involving secret keys, e.g., signing and + * public key generation. It is possible to call this function more than once on + * the same context, and doing so before every few computations involving secret + * keys is recommended as a defense-in-depth measure. Randomization of the static + * context rustsecp256k1_v0_11_context_static is not supported. + * + * Currently, the random seed is mainly used for blinding multiplications of a + * secret scalar with the elliptic curve base point. Multiplications of this + * kind are performed by exactly those API functions which are documented to + * require a context that is not rustsecp256k1_v0_11_context_static. As a rule of thumb, + * these are all functions which take a secret key (or a keypair) as an input. + * A notable exception to that rule is the ECDH module, which relies on a different + * kind of elliptic curve point multiplication and thus does not benefit from + * enhanced protection against side-channel leakage currently. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_context_randomize( + rustsecp256k1_v0_11_context *ctx, const unsigned char *seed32 ) SECP256K1_ARG_NONNULL(1); @@ -782,10 +843,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_context_r * In: ins: pointer to array of pointers to public keys. * n: the number of public keys to add together (must be at least 1). */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey_combine( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *out, - const rustsecp256k1zkp_v0_8_0_pubkey * const * ins, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_pubkey_combine( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *out, + const rustsecp256k1_v0_11_pubkey * const *ins, size_t n ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -805,8 +866,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey * msg: pointer to an array containing the message * msglen: length of the message array */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_tagged_sha256( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_tagged_sha256( + const rustsecp256k1_v0_11_context *ctx, unsigned char *hash32, const unsigned char *tag, size_t taglen, diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1.h.orig b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1.h.orig similarity index 52% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1.h.orig rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1.h.orig index 09cc839b..f7f11d6e 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1.h.orig +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1.h.orig @@ -7,7 +7,7 @@ extern "C" { #include -/* Unless explicitly stated all pointer arguments must not be NULL. +/** Unless explicitly stated all pointer arguments must not be NULL. * * The following rules specify the order of arguments in API calls: * @@ -24,39 +24,30 @@ extern "C" { * 5. Opaque data pointers follow the function pointer they are to be passed to. */ -/** Opaque data structure that holds context information (precomputed tables etc.). +/** Opaque data structure that holds context information * - * The purpose of context structures is to cache large precomputed data tables - * that are expensive to construct, and also to maintain the randomization data - * for blinding. + * The primary purpose of context objects is to store randomization data for + * enhanced protection against side-channel leakage. This protection is only + * effective if the context is randomized after its creation. See + * rustsecp256k1_v0_11_context_create for creation of contexts and + * rustsecp256k1_v0_11_context_randomize for randomization. * - * Do not create a new context object for each operation, as construction is - * far slower than all other API calls (~100 times slower than an ECDSA - * verification). + * A secondary purpose of context objects is to store pointers to callback + * functions that the library will call when certain error states arise. See + * rustsecp256k1_v0_11_context_set_error_callback as well as + * rustsecp256k1_v0_11_context_set_illegal_callback for details. Future library versions + * may use context objects for additional purposes. * * A constructed context can safely be used from multiple threads * simultaneously, but API calls that take a non-const pointer to a context * need exclusive access to it. In particular this is the case for - * rustsecp256k1zkp_v0_8_0_context_destroy, rustsecp256k1zkp_v0_8_0_context_preallocated_destroy, - * and rustsecp256k1zkp_v0_8_0_context_randomize. + * rustsecp256k1_v0_11_context_destroy, rustsecp256k1_v0_11_context_preallocated_destroy, + * and rustsecp256k1_v0_11_context_randomize. * * Regarding randomization, either do it once at creation time (in which case * you do not need any locking for the other calls), or use a read-write lock. */ -typedef struct rustsecp256k1zkp_v0_8_0_context_struct rustsecp256k1zkp_v0_8_0_context; - -/** Opaque data structure that holds rewriteable "scratch space" - * - * The purpose of this structure is to replace dynamic memory allocations, - * because we target architectures where this may not be available. It is - * essentially a resizable (within specified parameters) block of bytes, - * which is initially created either by memory allocation or TODO as a pointer - * into some fixed rewritable space. - * - * Unlike the context object, this cannot safely be shared between threads - * without additional synchronization logic. - */ -typedef struct rustsecp256k1zkp_v0_8_0_scratch_space_struct rustsecp256k1zkp_v0_8_0_scratch_space; +typedef struct rustsecp256k1_v0_11_context_struct rustsecp256k1_v0_11_context; /** Opaque data structure that holds a parsed and valid public key. * @@ -64,25 +55,25 @@ typedef struct rustsecp256k1zkp_v0_8_0_scratch_space_struct rustsecp256k1zkp_v0_ * guaranteed to be portable between different platforms or versions. It is * however guaranteed to be 64 bytes in size, and can be safely copied/moved. * If you need to convert to a format suitable for storage or transmission, - * use rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize and rustsecp256k1zkp_v0_8_0_ec_pubkey_parse. To - * compare keys, use rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp. + * use rustsecp256k1_v0_11_ec_pubkey_serialize and rustsecp256k1_v0_11_ec_pubkey_parse. To + * compare keys, use rustsecp256k1_v0_11_ec_pubkey_cmp. */ -typedef struct { +typedef struct rustsecp256k1_v0_11_pubkey { unsigned char data[64]; -} rustsecp256k1zkp_v0_8_0_pubkey; +} rustsecp256k1_v0_11_pubkey; -/** Opaque data structured that holds a parsed ECDSA signature. +/** Opaque data structure that holds a parsed ECDSA signature. * * The exact representation of data inside is implementation defined and not * guaranteed to be portable between different platforms or versions. It is * however guaranteed to be 64 bytes in size, and can be safely copied/moved. * If you need to convert to a format suitable for storage, transmission, or - * comparison, use the rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_* and - * rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_* functions. + * comparison, use the rustsecp256k1_v0_11_ecdsa_signature_serialize_* and + * rustsecp256k1_v0_11_ecdsa_signature_parse_* functions. */ -typedef struct { +typedef struct rustsecp256k1_v0_11_ecdsa_signature { unsigned char data[64]; -} rustsecp256k1zkp_v0_8_0_ecdsa_signature; +} rustsecp256k1_v0_11_ecdsa_signature; /** A pointer to a function to deterministically generate a nonce. * @@ -100,7 +91,7 @@ typedef struct { * Except for test cases, this function should compute some cryptographic hash of * the message, the algorithm, the key and the attempt. */ -typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function)( +typedef int (*rustsecp256k1_v0_11_nonce_function)( unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, @@ -118,19 +109,7 @@ typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function)( # endif # endif -# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) -# if SECP256K1_GNUC_PREREQ(2,7) -# define SECP256K1_INLINE __inline__ -# elif (defined(_MSC_VER)) -# define SECP256K1_INLINE __inline -# else -# define SECP256K1_INLINE -# endif -# else -# define SECP256K1_INLINE inline -# endif - -/** When this header is used at build-time the SECP256K1_BUILD define needs to be set +/* When this header is used at build-time the SECP256K1_BUILD define needs to be set * to correctly setup export attributes and nullness checks. This is normally done * by secp256k1.c but to guard against this header being included before secp256k1.c * has had a chance to set the define (e.g. via test harnesses that just includes @@ -141,23 +120,51 @@ typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function)( # define SECP256K1_NO_BUILD #endif -#ifndef SECP256K1_API -# if defined(_WIN32) -# ifdef SECP256K1_BUILD -# define SECP256K1_API __declspec(dllexport) +/* Symbol visibility. */ +#if defined(_WIN32) + /* GCC for Windows (e.g., MinGW) accepts the __declspec syntax + * for MSVC compatibility. A __declspec declaration implies (but is not + * exactly equivalent to) __attribute__ ((visibility("default"))), and so we + * actually want __declspec even on GCC, see "Microsoft Windows Function + * Attributes" in the GCC manual and the recommendations in + * https://gcc.gnu.org/wiki/Visibility. */ +# if defined(SECP256K1_BUILD) +# if defined(DLL_EXPORT) || defined(SECP256K1_DLL_EXPORT) + /* Building libsecp256k1 as a DLL. + * 1. If using Libtool, it defines DLL_EXPORT automatically. + * 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */ +# define SECP256K1_API extern __declspec (dllexport) # else -# define SECP256K1_API + /* Building libsecp256k1 as a static library on Windows. + * No declspec is needed, and so we would want the non-Windows-specific + * logic below take care of this case. However, this may result in setting + * __attribute__ ((visibility("default"))), which is supposed to be a noop + * on Windows but may trigger warnings when compiling with -flto due to a + * bug in GCC, see + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116478 . */ +# define SECP256K1_API extern # endif -# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD) -# define SECP256K1_API __attribute__ ((visibility ("default"))) + /* The user must define SECP256K1_STATIC when consuming libsecp256k1 as a static + * library on Windows. */ +# elif !defined(SECP256K1_STATIC) + /* Consuming libsecp256k1 as a DLL. */ +# define SECP256K1_API extern __declspec (dllimport) +# endif +#endif +#ifndef SECP256K1_API +/* All cases not captured by the Windows-specific logic. */ +# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD) + /* Building libsecp256k1 using GCC or compatible. */ +# define SECP256K1_API extern __attribute__ ((visibility ("default"))) # else -# define SECP256K1_API + /* Fall back to standard C's extern. */ +# define SECP256K1_API extern # endif #endif -/**Warning attributes - * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out - * some paranoid null checks. */ +/* Warning attributes + * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out + * some paranoid null checks. */ # if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) # define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) # else @@ -169,7 +176,7 @@ typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function)( # define SECP256K1_ARG_NONNULL(_x) # endif -/** Attribute for marking functions, types, and variables as deprecated */ +/* Attribute for marking functions, types, and variables as deprecated */ #if !defined(SECP256K1_BUILD) && defined(__has_attribute) # if __has_attribute(__deprecated__) # define SECP256K1_DEPRECATED(_msg) __attribute__ ((__deprecated__(_msg))) @@ -180,24 +187,28 @@ typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function)( # define SECP256K1_DEPRECATED(_msg) #endif -/** All flags' lower 8 bits indicate what they're for. Do not use directly. */ +/* All flags' lower 8 bits indicate what they're for. Do not use directly. */ #define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1) #define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0) #define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) -/** The higher bits contain the actual data. Do not use directly. */ +/* The higher bits contain the actual data. Do not use directly. */ #define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8) #define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9) #define SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY (1 << 10) #define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) -/** Flags to pass to rustsecp256k1zkp_v0_8_0_context_create, rustsecp256k1zkp_v0_8_0_context_preallocated_size, and - * rustsecp256k1zkp_v0_8_0_context_preallocated_create. */ +/** Context flags to pass to rustsecp256k1_v0_11_context_create, rustsecp256k1_v0_11_context_preallocated_size, and + * rustsecp256k1_v0_11_context_preallocated_create. */ +#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) + +/** Deprecated context flags. These flags are treated equivalent to SECP256K1_CONTEXT_NONE. */ #define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) #define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN) + +/* Testing flag. Do not use. */ #define SECP256K1_CONTEXT_DECLASSIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY) -#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) -/** Flag to pass to rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize. */ +/** Flag to pass to rustsecp256k1_v0_11_ec_pubkey_serialize. */ #define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) #define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) @@ -208,25 +219,68 @@ typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function)( #define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06 #define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07 -/** A simple secp256k1 context object with no precomputed tables. These are useful for - * type serialization/parsing functions which require a context object to maintain - * API consistency, but currently do not require expensive precomputations or dynamic - * allocations. +/** A built-in constant secp256k1 context object with static storage duration, to be + * used in conjunction with rustsecp256k1_v0_11_selftest. + * + * This context object offers *only limited functionality* , i.e., it cannot be used + * for API functions that perform computations involving secret keys, e.g., signing + * and public key generation. If this restriction applies to a specific API function, + * it is mentioned in its documentation. See rustsecp256k1_v0_11_context_create if you need a + * full context object that supports all functionality offered by the library. + * + * It is highly recommended to call rustsecp256k1_v0_11_selftest before using this context. */ -SECP256K1_API extern const rustsecp256k1zkp_v0_8_0_context *rustsecp256k1zkp_v0_8_0_context_no_precomp; +SECP256K1_API const rustsecp256k1_v0_11_context *rustsecp256k1_v0_11_context_static; + +/** Deprecated alias for rustsecp256k1_v0_11_context_static. */ +SECP256K1_API const rustsecp256k1_v0_11_context *rustsecp256k1_v0_11_context_no_precomp +SECP256K1_DEPRECATED("Use rustsecp256k1_v0_11_context_static instead"); + +/** Perform basic self tests (to be used in conjunction with rustsecp256k1_v0_11_context_static) + * + * This function performs self tests that detect some serious usage errors and + * similar conditions, e.g., when the library is compiled for the wrong endianness. + * This is a last resort measure to be used in production. The performed tests are + * very rudimentary and are not intended as a replacement for running the test + * binaries. + * + * It is highly recommended to call this before using rustsecp256k1_v0_11_context_static. + * It is not necessary to call this function before using a context created with + * rustsecp256k1_v0_11_context_create (or rustsecp256k1_v0_11_context_preallocated_create), which will + * take care of performing the self tests. + * + * If the tests fail, this function will call the default error handler to abort the + * program (see rustsecp256k1_v0_11_context_set_error_callback). + */ +SECP256K1_API void rustsecp256k1_v0_11_selftest(void); + /** Create a secp256k1 context object (in dynamically allocated memory). * * This function uses malloc to allocate memory. It is guaranteed that malloc is * called at most once for every call of this function. If you need to avoid dynamic - * memory allocation entirely, see the functions in rustsecp256k1zkp_v0_8_0_preallocated.h. + * memory allocation entirely, see rustsecp256k1_v0_11_context_static and the functions in + * rustsecp256k1_v0_11_preallocated.h. + * + * Returns: pointer to a newly created context object. + * In: flags: Always set to SECP256K1_CONTEXT_NONE (see below). * - * Returns: a newly created context object. - * In: flags: which parts of the context to initialize. + * The only valid non-deprecated flag in recent library versions is + * SECP256K1_CONTEXT_NONE, which will create a context sufficient for all functionality + * offered by the library. All other (deprecated) flags will be treated as equivalent + * to the SECP256K1_CONTEXT_NONE flag. Though the flags parameter primarily exists for + * historical reasons, future versions of the library may introduce new flags. * - * See also rustsecp256k1zkp_v0_8_0_context_randomize. + * If the context is intended to be used for API functions that perform computations + * involving secret keys, e.g., signing and public key generation, then it is highly + * recommended to call rustsecp256k1_v0_11_context_randomize on the context before calling + * those API functions. This will provide enhanced protection against side-channel + * leakage, see rustsecp256k1_v0_11_context_randomize for details. + * + * Do not create a new context object for each operation, as construction and + * randomization can take non-negligible time. */ -SECP256K1_API rustsecp256k1zkp_v0_8_0_context* rustsecp256k1zkp_v0_8_0_context_create( +SECP256K1_API rustsecp256k1_v0_11_context *rustsecp256k1_v0_11_context_create( unsigned int flags ) SECP256K1_WARN_UNUSED_RESULT; @@ -234,30 +288,34 @@ SECP256K1_API rustsecp256k1zkp_v0_8_0_context* rustsecp256k1zkp_v0_8_0_context_c * * This function uses malloc to allocate memory. It is guaranteed that malloc is * called at most once for every call of this function. If you need to avoid dynamic - * memory allocation entirely, see the functions in rustsecp256k1zkp_v0_8_0_preallocated.h. + * memory allocation entirely, see the functions in rustsecp256k1_v0_11_preallocated.h. + * + * Cloning rustsecp256k1_v0_11_context_static is not possible, and should not be emulated by + * the caller (e.g., using memcpy). Create a new context instead. * - * Returns: a newly created context object. - * Args: ctx: an existing context to copy + * Returns: pointer to a newly created context object. + * Args: ctx: pointer to a context to copy (not rustsecp256k1_v0_11_context_static). */ -SECP256K1_API rustsecp256k1zkp_v0_8_0_context* rustsecp256k1zkp_v0_8_0_context_clone( - const rustsecp256k1zkp_v0_8_0_context* ctx +SECP256K1_API rustsecp256k1_v0_11_context *rustsecp256k1_v0_11_context_clone( + const rustsecp256k1_v0_11_context *ctx ) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; /** Destroy a secp256k1 context object (created in dynamically allocated memory). * * The context pointer may not be used afterwards. * - * The context to destroy must have been created using rustsecp256k1zkp_v0_8_0_context_create - * or rustsecp256k1zkp_v0_8_0_context_clone. If the context has instead been created using - * rustsecp256k1zkp_v0_8_0_context_preallocated_create or rustsecp256k1zkp_v0_8_0_context_preallocated_clone, the - * behaviour is undefined. In that case, rustsecp256k1zkp_v0_8_0_context_preallocated_destroy must + * The context to destroy must have been created using rustsecp256k1_v0_11_context_create + * or rustsecp256k1_v0_11_context_clone. If the context has instead been created using + * rustsecp256k1_v0_11_context_preallocated_create or rustsecp256k1_v0_11_context_preallocated_clone, the + * behaviour is undefined. In that case, rustsecp256k1_v0_11_context_preallocated_destroy must * be used instead. * - * Args: ctx: an existing context to destroy, constructed using - * rustsecp256k1zkp_v0_8_0_context_create or rustsecp256k1zkp_v0_8_0_context_clone + * Args: ctx: pointer to a context to destroy, constructed using + * rustsecp256k1_v0_11_context_create or rustsecp256k1_v0_11_context_clone + * (i.e., not rustsecp256k1_v0_11_context_static). */ -SECP256K1_API void rustsecp256k1zkp_v0_8_0_context_destroy( - rustsecp256k1zkp_v0_8_0_context* ctx +SECP256K1_API void rustsecp256k1_v0_11_context_destroy( + rustsecp256k1_v0_11_context *ctx ) SECP256K1_ARG_NONNULL(1); /** Set a callback function to be called when an illegal argument is passed to @@ -281,81 +339,61 @@ SECP256K1_API void rustsecp256k1zkp_v0_8_0_context_destroy( * USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build * has been configured with --enable-external-default-callbacks. Then the * following two symbols must be provided to link against: - * - void rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn(const char* message, void* data); - * - void rustsecp256k1zkp_v0_8_0_default_error_callback_fn(const char* message, void* data); + * - void rustsecp256k1_v0_11_default_illegal_callback_fn(const char *message, void *data); + * - void rustsecp256k1_v0_11_default_error_callback_fn(const char *message, void *data); * The library can call these default handlers even before a proper callback data - * pointer could have been set using rustsecp256k1zkp_v0_8_0_context_set_illegal_callback or - * rustsecp256k1zkp_v0_8_0_context_set_error_callback, e.g., when the creation of a context + * pointer could have been set using rustsecp256k1_v0_11_context_set_illegal_callback or + * rustsecp256k1_v0_11_context_set_error_callback, e.g., when the creation of a context * fails. In this case, the corresponding default handler will be called with * the data pointer argument set to NULL. * - * Args: ctx: an existing context object. - * In: fun: a pointer to a function to call when an illegal argument is + * Args: ctx: pointer to a context object. + * In: fun: pointer to a function to call when an illegal argument is * passed to the API, taking a message and an opaque pointer. * (NULL restores the default handler.) * data: the opaque pointer to pass to fun above, must be NULL for the default handler. * - * See also rustsecp256k1zkp_v0_8_0_context_set_error_callback. + * See also rustsecp256k1_v0_11_context_set_error_callback. */ -SECP256K1_API void rustsecp256k1zkp_v0_8_0_context_set_illegal_callback( - rustsecp256k1zkp_v0_8_0_context* ctx, - void (*fun)(const char* message, void* data), - const void* data +SECP256K1_API void rustsecp256k1_v0_11_context_set_illegal_callback( + rustsecp256k1_v0_11_context *ctx, + void (*fun)(const char *message, void *data), + const void *data ) SECP256K1_ARG_NONNULL(1); /** Set a callback function to be called when an internal consistency check - * fails. The default is crashing. + * fails. + * + * The default callback writes an error message to stderr and calls abort + * to abort the program. * * This can only trigger in case of a hardware failure, miscompilation, * memory corruption, serious bug in the library, or other error would can * otherwise result in undefined behaviour. It will not trigger due to mere - * incorrect usage of the API (see rustsecp256k1zkp_v0_8_0_context_set_illegal_callback + * incorrect usage of the API (see rustsecp256k1_v0_11_context_set_illegal_callback * for that). After this callback returns, anything may happen, including * crashing. * - * Args: ctx: an existing context object. - * In: fun: a pointer to a function to call when an internal error occurs, + * Args: ctx: pointer to a context object. + * In: fun: pointer to a function to call when an internal error occurs, * taking a message and an opaque pointer (NULL restores the - * default handler, see rustsecp256k1zkp_v0_8_0_context_set_illegal_callback + * default handler, see rustsecp256k1_v0_11_context_set_illegal_callback * for details). * data: the opaque pointer to pass to fun above, must be NULL for the default handler. * - * See also rustsecp256k1zkp_v0_8_0_context_set_illegal_callback. + * See also rustsecp256k1_v0_11_context_set_illegal_callback. */ -SECP256K1_API void rustsecp256k1zkp_v0_8_0_context_set_error_callback( - rustsecp256k1zkp_v0_8_0_context* ctx, - void (*fun)(const char* message, void* data), - const void* data -) SECP256K1_ARG_NONNULL(1); - -/** Create a secp256k1 scratch space object. - * - * Returns: a newly created scratch space. - * Args: ctx: an existing context object. - * In: size: amount of memory to be available as scratch space. Some extra - * (<100 bytes) will be allocated for extra accounting. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT rustsecp256k1zkp_v0_8_0_scratch_space* rustsecp256k1zkp_v0_8_0_scratch_space_create( - const rustsecp256k1zkp_v0_8_0_context* ctx, - size_t size -) SECP256K1_ARG_NONNULL(1); - -/** Destroy a secp256k1 scratch space. - * - * The pointer may not be used afterwards. - * Args: ctx: a secp256k1 context object. - * scratch: space to destroy - */ -SECP256K1_API void rustsecp256k1zkp_v0_8_0_scratch_space_destroy( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_scratch_space* scratch +SECP256K1_API void rustsecp256k1_v0_11_context_set_error_callback( + rustsecp256k1_v0_11_context *ctx, + void (*fun)(const char *message, void *data), + const void *data ) SECP256K1_ARG_NONNULL(1); /** Parse a variable-length public key into the pubkey object. * * Returns: 1 if the public key was fully valid. * 0 if the public key could not be parsed or is invalid. - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object. * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a * parsed version of input. If not, its value is undefined. * In: input: pointer to a serialized public key @@ -365,9 +403,9 @@ SECP256K1_API void rustsecp256k1zkp_v0_8_0_scratch_space_destroy( * 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header * byte 0x06 or 0x07) format public keys. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey_parse( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey* pubkey, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_pubkey_parse( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *input, size_t inputlen ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -375,23 +413,23 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey /** Serialize a pubkey object into a serialized byte sequence. * * Returns: 1 always. - * Args: ctx: a secp256k1 context object. - * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if + * Args: ctx: pointer to a context object. + * Out: output: pointer to a 65-byte (if compressed==0) or 33-byte (if * compressed==1) byte array to place the serialized key * in. - * In/Out: outputlen: a pointer to an integer which is initially set to the + * In/Out: outputlen: pointer to an integer which is initially set to the * size of output, and is overwritten with the written * size. - * In: pubkey: a pointer to a rustsecp256k1zkp_v0_8_0_pubkey containing an + * In: pubkey: pointer to a rustsecp256k1_v0_11_pubkey containing an * initialized public key. * flags: SECP256K1_EC_COMPRESSED if serialization should be in * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API int rustsecp256k1_v0_11_ec_pubkey_serialize( + const rustsecp256k1_v0_11_context *ctx, unsigned char *output, size_t *outputlen, - const rustsecp256k1zkp_v0_8_0_pubkey* pubkey, + const rustsecp256k1_v0_11_pubkey *pubkey, unsigned int flags ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); @@ -400,55 +438,69 @@ SECP256K1_API int rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize( * Returns: <0 if the first public key is less than the second * >0 if the first public key is greater than the second * 0 if the two public keys are equal - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object * In: pubkey1: first public key to compare * pubkey2: second public key to compare */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_pubkey* pubkey1, - const rustsecp256k1zkp_v0_8_0_pubkey* pubkey2 +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_pubkey_cmp( + const rustsecp256k1_v0_11_context *ctx, + const rustsecp256k1_v0_11_pubkey *pubkey1, + const rustsecp256k1_v0_11_pubkey *pubkey2 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +/** Sort public keys using lexicographic (of compressed serialization) order + * + * Returns: 0 if the arguments are invalid. 1 otherwise. + * + * Args: ctx: pointer to a context object + * In: pubkeys: array of pointers to pubkeys to sort + * n_pubkeys: number of elements in the pubkeys array + */ +SECP256K1_API int rustsecp256k1_v0_11_ec_pubkey_sort( + const rustsecp256k1_v0_11_context *ctx, + const rustsecp256k1_v0_11_pubkey **pubkeys, + size_t n_pubkeys +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + /** Parse an ECDSA signature in compact (64 bytes) format. * * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input64: a pointer to the 64-byte array to parse + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input64: pointer to the 64-byte array to parse * * The signature must consist of a 32-byte big endian R value, followed by a * 32-byte big endian S value. If R or S fall outside of [0..order-1], the * encoding is invalid. R and S with value 0 are allowed in the encoding. * * After the call, sig will always be initialized. If parsing failed or R or - * S are zero, the resulting sig value is guaranteed to fail validation for any - * message and public key. + * S are zero, the resulting sig value is guaranteed to fail verification for + * any message and public key. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_signature_parse_compact( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_ecdsa_signature *sig, const unsigned char *input64 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Parse a DER ECDSA signature. * * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input: a pointer to the signature to be parsed + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input: pointer to the signature to be parsed * inputlen: the length of the array pointed to be input * * This function will accept any valid DER encoded signature, even if the * encoded numbers are out of range. * * After the call, sig will always be initialized. If parsing failed or the - * encoded numbers are out of range, signature validation with it is + * encoded numbers are out of range, signature verification with it is * guaranteed to fail for every message and public key. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_signature_parse_der( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_ecdsa_signature *sig, const unsigned char *input, size_t inputlen ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -456,41 +508,41 @@ SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der( /** Serialize an ECDSA signature in DER format. * * Returns: 1 if enough space was available to serialize, 0 otherwise - * Args: ctx: a secp256k1 context object - * Out: output: a pointer to an array to store the DER serialization - * In/Out: outputlen: a pointer to a length integer. Initially, this integer + * Args: ctx: pointer to a context object + * Out: output: pointer to an array to store the DER serialization + * In/Out: outputlen: pointer to a length integer. Initially, this integer * should be set to the length of output. After the call * it will be set to the length of the serialization (even * if 0 was returned). - * In: sig: a pointer to an initialized signature object + * In: sig: pointer to an initialized signature object */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_signature_serialize_der( + const rustsecp256k1_v0_11_context *ctx, unsigned char *output, size_t *outputlen, - const rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig + const rustsecp256k1_v0_11_ecdsa_signature *sig ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Serialize an ECDSA signature in compact (64 byte) format. * * Returns: 1 - * Args: ctx: a secp256k1 context object - * Out: output64: a pointer to a 64-byte array to store the compact serialization - * In: sig: a pointer to an initialized signature object + * Args: ctx: pointer to a context object + * Out: output64: pointer to a 64-byte array to store the compact serialization + * In: sig: pointer to an initialized signature object * - * See rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact for details about the encoding. + * See rustsecp256k1_v0_11_ecdsa_signature_parse_compact for details about the encoding. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_signature_serialize_compact( + const rustsecp256k1_v0_11_context *ctx, unsigned char *output64, - const rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig + const rustsecp256k1_v0_11_ecdsa_signature *sig ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Verify an ECDSA signature. * * Returns: 1: correct signature * 0: incorrect or unparseable signature - * Args: ctx: a secp256k1 context object, initialized for verification. + * Args: ctx: pointer to a context object * In: sig: the signature being verified. * msghash32: the 32-byte message hash being verified. * The verifier must make sure to apply a cryptographic @@ -506,27 +558,27 @@ SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact( * form are accepted. * * If you need to accept ECDSA signatures from sources that do not obey this - * rule, apply rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize to the signature prior to - * validation, but be aware that doing so results in malleable signatures. + * rule, apply rustsecp256k1_v0_11_ecdsa_signature_normalize to the signature prior to + * verification, but be aware that doing so results in malleable signatures. * * For details, see the comments for that function. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ecdsa_verify( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_ecdsa_signature *sig, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ecdsa_verify( + const rustsecp256k1_v0_11_context *ctx, + const rustsecp256k1_v0_11_ecdsa_signature *sig, const unsigned char *msghash32, - const rustsecp256k1zkp_v0_8_0_pubkey *pubkey + const rustsecp256k1_v0_11_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Convert a signature to a normalized lower-S form. * * Returns: 1 if sigin was not normalized, 0 if it already was. - * Args: ctx: a secp256k1 context object - * Out: sigout: a pointer to a signature to fill with the normalized form, + * Args: ctx: pointer to a context object + * Out: sigout: pointer to a signature to fill with the normalized form, * or copy if the input was already normalized. (can be NULL if * you're only interested in whether the input was already * normalized). - * In: sigin: a pointer to a signature to check/normalize (can be identical to sigout) + * In: sigin: pointer to a signature to check/normalize (can be identical to sigout) * * With ECDSA a third-party can forge a second distinct signature of the same * message, given a single initial signature, but without knowing the key. This @@ -554,67 +606,69 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ecdsa_ver * accept various non-unique encodings, so care should be taken when this * property is required for an application. * - * The rustsecp256k1zkp_v0_8_0_ecdsa_sign function will by default create signatures in the - * lower-S form, and rustsecp256k1zkp_v0_8_0_ecdsa_verify will not accept others. In case + * The rustsecp256k1_v0_11_ecdsa_sign function will by default create signatures in the + * lower-S form, and rustsecp256k1_v0_11_ecdsa_verify will not accept others. In case * signatures come from a system that cannot enforce this property, - * rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize must be called before verification. + * rustsecp256k1_v0_11_ecdsa_signature_normalize must be called before verification. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_signature *sigout, - const rustsecp256k1zkp_v0_8_0_ecdsa_signature *sigin +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_signature_normalize( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_ecdsa_signature *sigout, + const rustsecp256k1_v0_11_ecdsa_signature *sigin ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); /** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of * extra entropy. */ -SECP256K1_API extern const rustsecp256k1zkp_v0_8_0_nonce_function rustsecp256k1zkp_v0_8_0_nonce_function_rfc6979; +SECP256K1_API const rustsecp256k1_v0_11_nonce_function rustsecp256k1_v0_11_nonce_function_rfc6979; -/** A default safe nonce generation function (currently equal to rustsecp256k1zkp_v0_8_0_nonce_function_rfc6979). */ -SECP256K1_API extern const rustsecp256k1zkp_v0_8_0_nonce_function rustsecp256k1zkp_v0_8_0_nonce_function_default; +/** A default safe nonce generation function (currently equal to rustsecp256k1_v0_11_nonce_function_rfc6979). */ +SECP256K1_API const rustsecp256k1_v0_11_nonce_function rustsecp256k1_v0_11_nonce_function_default; /** Create an ECDSA signature. * * Returns: 1: signature created * 0: the nonce generation function failed, or the secret key was invalid. - * Args: ctx: pointer to a context object, initialized for signing. + * Args: ctx: pointer to a context object (not rustsecp256k1_v0_11_context_static). * Out: sig: pointer to an array where the signature will be placed. * In: msghash32: the 32-byte message hash being signed. * seckey: pointer to a 32-byte secret key. * noncefp: pointer to a nonce generation function. If NULL, - * rustsecp256k1zkp_v0_8_0_nonce_function_default is used. + * rustsecp256k1_v0_11_nonce_function_default is used. * ndata: pointer to arbitrary data used by the nonce generation function * (can be NULL). If it is non-NULL and - * rustsecp256k1zkp_v0_8_0_nonce_function_default is used, then ndata must be a + * rustsecp256k1_v0_11_nonce_function_default is used, then ndata must be a * pointer to 32-bytes of additional data. * * The created signature is always in lower-S form. See - * rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize for more details. + * rustsecp256k1_v0_11_ecdsa_signature_normalize for more details. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_sign( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_signature *sig, +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_sign( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_ecdsa_signature *sig, const unsigned char *msghash32, const unsigned char *seckey, - rustsecp256k1zkp_v0_8_0_nonce_function noncefp, + rustsecp256k1_v0_11_nonce_function noncefp, const void *ndata ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); -/** Verify an ECDSA secret key. +/** Verify an elliptic curve secret key. * * A secret key is valid if it is not 0 and less than the secp256k1 curve order * when interpreted as an integer (most significant byte first). The * probability of choosing a 32-byte string uniformly at random which is an - * invalid secret key is negligible. + * invalid secret key is negligible. However, if it does happen it should + * be assumed that the randomness source is severely broken and there should + * be no retry. * * Returns: 1: secret key is valid * 0: secret key is invalid * Args: ctx: pointer to a context object. * In: seckey: pointer to a 32-byte secret key. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_seckey_verify( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_seckey_verify( + const rustsecp256k1_v0_11_context *ctx, const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); @@ -622,38 +676,38 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_seckey * * Returns: 1: secret was valid, public key stores. * 0: secret was invalid, try again. - * Args: ctx: pointer to a context object, initialized for signing. + * Args: ctx: pointer to a context object (not rustsecp256k1_v0_11_context_static). * Out: pubkey: pointer to the created public key. * In: seckey: pointer to a 32-byte secret key. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey_create( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *pubkey, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_pubkey_create( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Negates a secret key in place. * * Returns: 0 if the given secret key is invalid according to - * rustsecp256k1zkp_v0_8_0_ec_seckey_verify. 1 otherwise + * rustsecp256k1_v0_11_ec_seckey_verify. 1 otherwise * Args: ctx: pointer to a context object * In/Out: seckey: pointer to the 32-byte secret key to be negated. If the * secret key is invalid according to - * rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this function returns 0 and + * rustsecp256k1_v0_11_ec_seckey_verify, this function returns 0 and * seckey will be set to some unspecified value. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_seckey_negate( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_seckey_negate( + const rustsecp256k1_v0_11_context *ctx, unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); -/** Same as rustsecp256k1zkp_v0_8_0_ec_seckey_negate, but DEPRECATED. Will be removed in +/** Same as rustsecp256k1_v0_11_ec_seckey_negate, but DEPRECATED. Will be removed in * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_privkey_negate( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_privkey_negate( + const rustsecp256k1_v0_11_context *ctx, unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) - SECP256K1_DEPRECATED("Use rustsecp256k1zkp_v0_8_0_ec_seckey_negate instead"); + SECP256K1_DEPRECATED("Use rustsecp256k1_v0_11_ec_seckey_negate instead"); /** Negates a public key in place. * @@ -661,9 +715,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_privke * Args: ctx: pointer to a context object * In/Out: pubkey: pointer to the public key to be negated. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey_negate( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *pubkey +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_pubkey_negate( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); /** Tweak a secret key by adding tweak to it. @@ -673,45 +727,45 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey * otherwise. * Args: ctx: pointer to a context object. * In/Out: seckey: pointer to a 32-byte secret key. If the secret key is - * invalid according to rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this + * invalid according to rustsecp256k1_v0_11_ec_seckey_verify, this * function returns 0. seckey will be set to some unspecified * value if this function returns 0. - * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to - * rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this function returns 0. For - * uniformly random 32-byte arrays the chance of being invalid - * is negligible (around 1 in 2^128). + * In: tweak32: pointer to a 32-byte tweak, which must be valid according to + * rustsecp256k1_v0_11_ec_seckey_verify or 32 zero bytes. For uniformly + * random 32-byte tweaks, the chance of being invalid is + * negligible (around 1 in 2^128). */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_seckey_tweak_add( + const rustsecp256k1_v0_11_context *ctx, unsigned char *seckey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Same as rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add, but DEPRECATED. Will be removed in +/** Same as rustsecp256k1_v0_11_ec_seckey_tweak_add, but DEPRECATED. Will be removed in * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_privkey_tweak_add( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_privkey_tweak_add( + const rustsecp256k1_v0_11_context *ctx, unsigned char *seckey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) - SECP256K1_DEPRECATED("Use rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add instead"); + SECP256K1_DEPRECATED("Use rustsecp256k1_v0_11_ec_seckey_tweak_add instead"); /** Tweak a public key by adding tweak times the generator to it. * * Returns: 0 if the arguments are invalid or the resulting public key would be * invalid (only when the tweak is the negation of the corresponding * secret key). 1 otherwise. - * Args: ctx: pointer to a context object initialized for validation. + * Args: ctx: pointer to a context object. * In/Out: pubkey: pointer to a public key object. pubkey will be set to an * invalid value if this function returns 0. - * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to - * rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this function returns 0. For - * uniformly random 32-byte arrays the chance of being invalid - * is negligible (around 1 in 2^128). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *pubkey, + * In: tweak32: pointer to a 32-byte tweak, which must be valid according to + * rustsecp256k1_v0_11_ec_seckey_verify or 32 zero bytes. For uniformly + * random 32-byte tweaks, the chance of being invalid is + * negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_pubkey_tweak_add( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -720,73 +774,80 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey * Returns: 0 if the arguments are invalid. 1 otherwise. * Args: ctx: pointer to a context object. * In/Out: seckey: pointer to a 32-byte secret key. If the secret key is - * invalid according to rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this + * invalid according to rustsecp256k1_v0_11_ec_seckey_verify, this * function returns 0. seckey will be set to some unspecified * value if this function returns 0. * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to - * rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this function returns 0. For + * rustsecp256k1_v0_11_ec_seckey_verify, this function returns 0. For * uniformly random 32-byte arrays the chance of being invalid * is negligible (around 1 in 2^128). */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_seckey_tweak_mul( + const rustsecp256k1_v0_11_context *ctx, unsigned char *seckey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Same as rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in +/** Same as rustsecp256k1_v0_11_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_privkey_tweak_mul( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_privkey_tweak_mul( + const rustsecp256k1_v0_11_context *ctx, unsigned char *seckey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) - SECP256K1_DEPRECATED("Use rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul instead"); + SECP256K1_DEPRECATED("Use rustsecp256k1_v0_11_ec_seckey_tweak_mul instead"); /** Tweak a public key by multiplying it by a tweak value. * * Returns: 0 if the arguments are invalid. 1 otherwise. - * Args: ctx: pointer to a context object initialized for validation. + * Args: ctx: pointer to a context object. * In/Out: pubkey: pointer to a public key object. pubkey will be set to an * invalid value if this function returns 0. * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to - * rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this function returns 0. For + * rustsecp256k1_v0_11_ec_seckey_verify, this function returns 0. For * uniformly random 32-byte arrays the chance of being invalid * is negligible (around 1 in 2^128). */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_mul( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *pubkey, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_pubkey_tweak_mul( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Updates the context randomization to protect against side-channel leakage. - * Returns: 1: randomization successfully updated or nothing to randomize +/** Randomizes the context to provide enhanced protection against side-channel leakage. + * + * Returns: 1: randomization successful * 0: error - * Args: ctx: pointer to a context object. - * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state) + * Args: ctx: pointer to a context object (not rustsecp256k1_v0_11_context_static). + * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state). * - * While secp256k1 code is written to be constant-time no matter what secret - * values are, it's possible that a future compiler may output code which isn't, + * While secp256k1 code is written and tested to be constant-time no matter what + * secret values are, it is possible that a compiler may output code which is not, * and also that the CPU may not emit the same radio frequencies or draw the same - * amount power for all values. - * - * This function provides a seed which is combined into the blinding value: that - * blinding value is added before each multiplication (and removed afterwards) so - * that it does not affect function results, but shields against attacks which - * rely on any input-dependent behaviour. - * - * This function has currently an effect only on contexts initialized for signing - * because randomization is currently used only for signing. However, this is not - * guaranteed and may change in the future. It is safe to call this function on - * contexts not initialized for signing; then it will have no effect and return 1. - * - * You should call this after rustsecp256k1zkp_v0_8_0_context_create or - * rustsecp256k1zkp_v0_8_0_context_clone (and rustsecp256k1zkp_v0_8_0_context_preallocated_create or - * rustsecp256k1zkp_v0_8_0_context_clone, resp.), and you may call this repeatedly afterwards. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_context_randomize( - rustsecp256k1zkp_v0_8_0_context* ctx, + * amount of power for all values. Randomization of the context shields against + * side-channel observations which aim to exploit secret-dependent behaviour in + * certain computations which involve secret keys. + * + * It is highly recommended to call this function on contexts returned from + * rustsecp256k1_v0_11_context_create or rustsecp256k1_v0_11_context_clone (or from the corresponding + * functions in rustsecp256k1_v0_11_preallocated.h) before using these contexts to call API + * functions that perform computations involving secret keys, e.g., signing and + * public key generation. It is possible to call this function more than once on + * the same context, and doing so before every few computations involving secret + * keys is recommended as a defense-in-depth measure. Randomization of the static + * context rustsecp256k1_v0_11_context_static is not supported. + * + * Currently, the random seed is mainly used for blinding multiplications of a + * secret scalar with the elliptic curve base point. Multiplications of this + * kind are performed by exactly those API functions which are documented to + * require a context that is not rustsecp256k1_v0_11_context_static. As a rule of thumb, + * these are all functions which take a secret key (or a keypair) as an input. + * A notable exception to that rule is the ECDH module, which relies on a different + * kind of elliptic curve point multiplication and thus does not benefit from + * enhanced protection against side-channel leakage currently. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_context_randomize( + rustsecp256k1_v0_11_context *ctx, const unsigned char *seed32 ) SECP256K1_ARG_NONNULL(1); @@ -799,10 +860,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_context_r * In: ins: pointer to array of pointers to public keys. * n: the number of public keys to add together (must be at least 1). */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey_combine( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *out, - const rustsecp256k1zkp_v0_8_0_pubkey * const * ins, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ec_pubkey_combine( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *out, + const rustsecp256k1_v0_11_pubkey * const *ins, size_t n ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -822,8 +883,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ec_pubkey * msg: pointer to an array containing the message * msglen: length of the message array */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_tagged_sha256( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_tagged_sha256( + const rustsecp256k1_v0_11_context *ctx, unsigned char *hash32, const unsigned char *tag, size_t taglen, diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_ecdh.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_ecdh.h similarity index 63% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_ecdh.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_ecdh.h index aff6e9ae..edf23a54 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_ecdh.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_ecdh.h @@ -10,15 +10,15 @@ extern "C" { /** A pointer to a function that hashes an EC point to obtain an ECDH secret * * Returns: 1 if the point was successfully hashed. - * 0 will cause rustsecp256k1zkp_v0_8_0_ecdh to fail and return 0. + * 0 will cause rustsecp256k1_v0_11_ecdh to fail and return 0. * Other return values are not allowed, and the behaviour of - * rustsecp256k1zkp_v0_8_0_ecdh is undefined for other return values. + * rustsecp256k1_v0_11_ecdh is undefined for other return values. * Out: output: pointer to an array to be filled by the function * In: x32: pointer to a 32-byte x coordinate * y32: pointer to a 32-byte y coordinate * data: arbitrary data pointer that is passed through */ -typedef int (*rustsecp256k1zkp_v0_8_0_ecdh_hash_function)( +typedef int (*rustsecp256k1_v0_11_ecdh_hash_function)( unsigned char *output, const unsigned char *x32, const unsigned char *y32, @@ -27,11 +27,11 @@ typedef int (*rustsecp256k1zkp_v0_8_0_ecdh_hash_function)( /** An implementation of SHA256 hash function that applies to compressed public key. * Populates the output parameter with 32 bytes. */ -SECP256K1_API extern const rustsecp256k1zkp_v0_8_0_ecdh_hash_function rustsecp256k1zkp_v0_8_0_ecdh_hash_function_sha256; +SECP256K1_API const rustsecp256k1_v0_11_ecdh_hash_function rustsecp256k1_v0_11_ecdh_hash_function_sha256; -/** A default ECDH hash function (currently equal to rustsecp256k1zkp_v0_8_0_ecdh_hash_function_sha256). +/** A default ECDH hash function (currently equal to rustsecp256k1_v0_11_ecdh_hash_function_sha256). * Populates the output parameter with 32 bytes. */ -SECP256K1_API extern const rustsecp256k1zkp_v0_8_0_ecdh_hash_function rustsecp256k1zkp_v0_8_0_ecdh_hash_function_default; +SECP256K1_API const rustsecp256k1_v0_11_ecdh_hash_function rustsecp256k1_v0_11_ecdh_hash_function_default; /** Compute an EC Diffie-Hellman secret in constant time * @@ -39,20 +39,20 @@ SECP256K1_API extern const rustsecp256k1zkp_v0_8_0_ecdh_hash_function rustsecp25 * 0: scalar was invalid (zero or overflow) or hashfp returned 0 * Args: ctx: pointer to a context object. * Out: output: pointer to an array to be filled by hashfp. - * In: pubkey: a pointer to a rustsecp256k1zkp_v0_8_0_pubkey containing an initialized public key. + * In: pubkey: pointer to a rustsecp256k1_v0_11_pubkey containing an initialized public key. * seckey: a 32-byte scalar with which to multiply the point. * hashfp: pointer to a hash function. If NULL, - * rustsecp256k1zkp_v0_8_0_ecdh_hash_function_sha256 is used + * rustsecp256k1_v0_11_ecdh_hash_function_sha256 is used * (in which case, 32 bytes will be written to output). * data: arbitrary data pointer that is passed through to hashfp - * (can be NULL for rustsecp256k1zkp_v0_8_0_ecdh_hash_function_sha256). + * (can be NULL for rustsecp256k1_v0_11_ecdh_hash_function_sha256). */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ecdh( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ecdh( + const rustsecp256k1_v0_11_context *ctx, unsigned char *output, - const rustsecp256k1zkp_v0_8_0_pubkey *pubkey, + const rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *seckey, - rustsecp256k1zkp_v0_8_0_ecdh_hash_function hashfp, + rustsecp256k1_v0_11_ecdh_hash_function hashfp, void *data ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_ellswift.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_ellswift.h new file mode 100644 index 00000000..e7b9d4c4 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_ellswift.h @@ -0,0 +1,200 @@ +#ifndef SECP256K1_ELLSWIFT_H +#define SECP256K1_ELLSWIFT_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This module provides an implementation of ElligatorSwift as well as a + * version of x-only ECDH using it (including compatibility with BIP324). + * + * ElligatorSwift is described in https://eprint.iacr.org/2022/759 by + * Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding + * uniformly chosen public keys as 64-byte arrays which are indistinguishable + * from uniformly random arrays. + * + * Let f be the function from pairs of field elements to point X coordinates, + * defined as follows (all operations modulo p = 2^256 - 2^32 - 977) + * f(u,t): + * - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852, + * a square root of -3. + * - If u=0, set u=1 instead. + * - If t=0, set t=1 instead. + * - If u^3 + t^2 + 7 = 0, multiply t by 2. + * - Let X = (u^3 + 7 - t^2) / (2 * t) + * - Let Y = (X + t) / (C * u) + * - Return the first in [u + 4 * Y^2, (-X/Y - u) / 2, (X/Y - u) / 2] that is an + * X coordinate on the curve (at least one of them is, for any u and t). + * + * Then an ElligatorSwift encoding of x consists of the 32-byte big-endian + * encodings of field elements u and t concatenated, where f(u,t) = x. + * The encoding algorithm is described in the paper, and effectively picks a + * uniformly random pair (u,t) among those which encode x. + * + * If the Y coordinate is relevant, it is given the same parity as t. + * + * Changes w.r.t. the paper: + * - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point + * at infinity in the paper. Here they are remapped to finite points. + * - The paper uses an additional encoding bit for the parity of y. Here the + * parity of t is used (negating t does not affect the decoded x coordinate, + * so this is possible). + * + * For mathematical background about the scheme, see the doc/ellswift.md file. + */ + +/** A pointer to a function used by rustsecp256k1_v0_11_ellswift_xdh to hash the shared X + * coordinate along with the encoded public keys to a uniform shared secret. + * + * Returns: 1 if a shared secret was successfully computed. + * 0 will cause rustsecp256k1_v0_11_ellswift_xdh to fail and return 0. + * Other return values are not allowed, and the behaviour of + * rustsecp256k1_v0_11_ellswift_xdh is undefined for other return values. + * Out: output: pointer to an array to be filled by the function + * In: x32: pointer to the 32-byte serialized X coordinate + * of the resulting shared point (will not be NULL) + * ell_a64: pointer to the 64-byte encoded public key of party A + * (will not be NULL) + * ell_b64: pointer to the 64-byte encoded public key of party B + * (will not be NULL) + * data: arbitrary data pointer that is passed through + */ +typedef int (*rustsecp256k1_v0_11_ellswift_xdh_hash_function)( + unsigned char *output, + const unsigned char *x32, + const unsigned char *ell_a64, + const unsigned char *ell_b64, + void *data +); + +/** An implementation of an rustsecp256k1_v0_11_ellswift_xdh_hash_function which uses + * SHA256(prefix64 || ell_a64 || ell_b64 || x32), where prefix64 is the 64-byte + * array pointed to by data. */ +SECP256K1_API const rustsecp256k1_v0_11_ellswift_xdh_hash_function rustsecp256k1_v0_11_ellswift_xdh_hash_function_prefix; + +/** An implementation of an rustsecp256k1_v0_11_ellswift_xdh_hash_function compatible with + * BIP324. It returns H_tag(ell_a64 || ell_b64 || x32), where H_tag is the + * BIP340 tagged hash function with tag "bip324_ellswift_xonly_ecdh". Equivalent + * to rustsecp256k1_v0_11_ellswift_xdh_hash_function_prefix with prefix64 set to + * SHA256("bip324_ellswift_xonly_ecdh")||SHA256("bip324_ellswift_xonly_ecdh"). + * The data argument is ignored. */ +SECP256K1_API const rustsecp256k1_v0_11_ellswift_xdh_hash_function rustsecp256k1_v0_11_ellswift_xdh_hash_function_bip324; + +/** Construct a 64-byte ElligatorSwift encoding of a given pubkey. + * + * Returns: 1 always. + * Args: ctx: pointer to a context object + * Out: ell64: pointer to a 64-byte array to be filled + * In: pubkey: pointer to a rustsecp256k1_v0_11_pubkey containing an + * initialized public key + * rnd32: pointer to 32 bytes of randomness + * + * It is recommended that rnd32 consists of 32 uniformly random bytes, not + * known to any adversary trying to detect whether public keys are being + * encoded, though 16 bytes of randomness (padded to an array of 32 bytes, + * e.g., with zeros) suffice to make the result indistinguishable from + * uniform. The randomness in rnd32 must not be a deterministic function of + * the pubkey (it can be derived from the private key, though). + * + * It is not guaranteed that the computed encoding is stable across versions + * of the library, even if all arguments to this function (including rnd32) + * are the same. + * + * This function runs in variable time. + */ +SECP256K1_API int rustsecp256k1_v0_11_ellswift_encode( + const rustsecp256k1_v0_11_context *ctx, + unsigned char *ell64, + const rustsecp256k1_v0_11_pubkey *pubkey, + const unsigned char *rnd32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Decode a 64-bytes ElligatorSwift encoded public key. + * + * Returns: always 1 + * Args: ctx: pointer to a context object + * Out: pubkey: pointer to a rustsecp256k1_v0_11_pubkey that will be filled + * In: ell64: pointer to a 64-byte array to decode + * + * This function runs in variable time. + */ +SECP256K1_API int rustsecp256k1_v0_11_ellswift_decode( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *pubkey, + const unsigned char *ell64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Compute an ElligatorSwift public key for a secret key. + * + * Returns: 1: secret was valid, public key was stored. + * 0: secret was invalid, try again. + * Args: ctx: pointer to a context object + * Out: ell64: pointer to a 64-byte array to receive the ElligatorSwift + * public key + * In: seckey32: pointer to a 32-byte secret key + * auxrnd32: (optional) pointer to 32 bytes of randomness + * + * Constant time in seckey and auxrnd32, but not in the resulting public key. + * + * It is recommended that auxrnd32 contains 32 uniformly random bytes, though + * it is optional (and does result in encodings that are indistinguishable from + * uniform even without any auxrnd32). It differs from the (mandatory) rnd32 + * argument to rustsecp256k1_v0_11_ellswift_encode in this regard. + * + * This function can be used instead of calling rustsecp256k1_v0_11_ec_pubkey_create + * followed by rustsecp256k1_v0_11_ellswift_encode. It is safer, as it uses the secret + * key as entropy for the encoding (supplemented with auxrnd32, if provided). + * + * Like rustsecp256k1_v0_11_ellswift_encode, this function does not guarantee that the + * computed encoding is stable across versions of the library, even if all + * arguments (including auxrnd32) are the same. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ellswift_create( + const rustsecp256k1_v0_11_context *ctx, + unsigned char *ell64, + const unsigned char *seckey32, + const unsigned char *auxrnd32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Given a private key, and ElligatorSwift public keys sent in both directions, + * compute a shared secret using x-only Elliptic Curve Diffie-Hellman (ECDH). + * + * Returns: 1: shared secret was successfully computed + * 0: secret was invalid or hashfp returned 0 + * Args: ctx: pointer to a context object. + * Out: output: pointer to an array to be filled by hashfp. + * In: ell_a64: pointer to the 64-byte encoded public key of party A + * (will not be NULL) + * ell_b64: pointer to the 64-byte encoded public key of party B + * (will not be NULL) + * seckey32: pointer to our 32-byte secret key + * party: boolean indicating which party we are: zero if we are + * party A, non-zero if we are party B. seckey32 must be + * the private key corresponding to that party's ell_?64. + * This correspondence is not checked. + * hashfp: pointer to a hash function. + * data: arbitrary data pointer passed through to hashfp. + * + * Constant time in seckey32. + * + * This function is more efficient than decoding the public keys, and performing + * ECDH on them. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ellswift_xdh( + const rustsecp256k1_v0_11_context *ctx, + unsigned char *output, + const unsigned char *ell_a64, + const unsigned char *ell_b64, + const unsigned char *seckey32, + int party, + rustsecp256k1_v0_11_ellswift_xdh_hash_function hashfp, + void *data +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_ELLSWIFT_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_extrakeys.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_extrakeys.h similarity index 50% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_extrakeys.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_extrakeys.h index b5b7c138..ddcf821a 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_extrakeys.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_extrakeys.h @@ -16,12 +16,12 @@ extern "C" { * guaranteed to be portable between different platforms or versions. It is * however guaranteed to be 64 bytes in size, and can be safely copied/moved. * If you need to convert to a format suitable for storage, transmission, use - * use rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize and rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse. To - * compare keys, use rustsecp256k1zkp_v0_8_0_xonly_pubkey_cmp. + * use rustsecp256k1_v0_11_xonly_pubkey_serialize and rustsecp256k1_v0_11_xonly_pubkey_parse. To + * compare keys, use rustsecp256k1_v0_11_xonly_pubkey_cmp. */ -typedef struct { +typedef struct rustsecp256k1_v0_11_xonly_pubkey { unsigned char data[64]; -} rustsecp256k1zkp_v0_8_0_xonly_pubkey; +} rustsecp256k1_v0_11_xonly_pubkey; /** Opaque data structure that holds a keypair consisting of a secret and a * public key. @@ -30,23 +30,23 @@ typedef struct { * guaranteed to be portable between different platforms or versions. It is * however guaranteed to be 96 bytes in size, and can be safely copied/moved. */ -typedef struct { +typedef struct rustsecp256k1_v0_11_keypair { unsigned char data[96]; -} rustsecp256k1zkp_v0_8_0_keypair; +} rustsecp256k1_v0_11_keypair; /** Parse a 32-byte sequence into a xonly_pubkey object. * * Returns: 1 if the public key was fully valid. * 0 if the public key could not be parsed or is invalid. * - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object. * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a * parsed version of input. If not, it's set to an invalid value. * In: input32: pointer to a serialized xonly_pubkey. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_xonly_pubkey* pubkey, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_xonly_pubkey_parse( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_xonly_pubkey *pubkey, const unsigned char *input32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -54,14 +54,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_xonly_pub * * Returns: 1 always. * - * Args: ctx: a secp256k1 context object. - * Out: output32: a pointer to a 32-byte array to place the serialized key in. - * In: pubkey: a pointer to a rustsecp256k1zkp_v0_8_0_xonly_pubkey containing an initialized public key. + * Args: ctx: pointer to a context object. + * Out: output32: pointer to a 32-byte array to place the serialized key in. + * In: pubkey: pointer to a rustsecp256k1_v0_11_xonly_pubkey containing an initialized public key. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API int rustsecp256k1_v0_11_xonly_pubkey_serialize( + const rustsecp256k1_v0_11_context *ctx, unsigned char *output32, - const rustsecp256k1zkp_v0_8_0_xonly_pubkey* pubkey + const rustsecp256k1_v0_11_xonly_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Compare two x-only public keys using lexicographic order @@ -69,17 +69,17 @@ SECP256K1_API int rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize( * Returns: <0 if the first public key is less than the second * >0 if the first public key is greater than the second * 0 if the two public keys are equal - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object. * In: pubkey1: first public key to compare * pubkey2: second public key to compare */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_xonly_pubkey_cmp( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_xonly_pubkey* pk1, - const rustsecp256k1zkp_v0_8_0_xonly_pubkey* pk2 +SECP256K1_API int rustsecp256k1_v0_11_xonly_pubkey_cmp( + const rustsecp256k1_v0_11_context *ctx, + const rustsecp256k1_v0_11_xonly_pubkey *pk1, + const rustsecp256k1_v0_11_xonly_pubkey *pk2 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Converts a rustsecp256k1zkp_v0_8_0_pubkey into a rustsecp256k1zkp_v0_8_0_xonly_pubkey. +/** Converts a rustsecp256k1_v0_11_pubkey into a rustsecp256k1_v0_11_xonly_pubkey. * * Returns: 1 always. * @@ -90,11 +90,11 @@ SECP256K1_API int rustsecp256k1zkp_v0_8_0_xonly_pubkey_cmp( * the negation of the pubkey and set to 0 otherwise. * In: pubkey: pointer to a public key that is converted. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_xonly_pubkey *xonly_pubkey, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_xonly_pubkey_from_pubkey( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_xonly_pubkey *xonly_pubkey, int *pk_parity, - const rustsecp256k1zkp_v0_8_0_pubkey *pubkey + const rustsecp256k1_v0_11_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); /** Tweak an x-only public key by adding the generator multiplied with tweak32 @@ -102,34 +102,34 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_xonly_pub * * Note that the resulting point can not in general be represented by an x-only * pubkey because it may have an odd Y coordinate. Instead, the output_pubkey - * is a normal rustsecp256k1zkp_v0_8_0_pubkey. + * is a normal rustsecp256k1_v0_11_pubkey. * * Returns: 0 if the arguments are invalid or the resulting public key would be * invalid (only when the tweak is the negation of the corresponding * secret key). 1 otherwise. * - * Args: ctx: pointer to a context object initialized for verification. + * Args: ctx: pointer to a context object. * Out: output_pubkey: pointer to a public key to store the result. Will be set * to an invalid value if this function returns 0. * In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to. - * tweak32: pointer to a 32-byte tweak. If the tweak is invalid - * according to rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this function - * returns 0. For uniformly random 32-byte arrays the - * chance of being invalid is negligible (around 1 in 2^128). + * tweak32: pointer to a 32-byte tweak, which must be valid + * according to rustsecp256k1_v0_11_ec_seckey_verify or 32 zero + * bytes. For uniformly random 32-byte tweaks, the chance of + * being invalid is negligible (around 1 in 2^128). */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *output_pubkey, - const rustsecp256k1zkp_v0_8_0_xonly_pubkey *internal_pubkey, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_xonly_pubkey_tweak_add( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *output_pubkey, + const rustsecp256k1_v0_11_xonly_pubkey *internal_pubkey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Checks that a tweaked pubkey is the result of calling - * rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add with internal_pubkey and tweak32. + * rustsecp256k1_v0_11_xonly_pubkey_tweak_add with internal_pubkey and tweak32. * * The tweaked pubkey is represented by its 32-byte x-only serialization and * its pk_parity, which can both be obtained by converting the result of - * tweak_add to a rustsecp256k1zkp_v0_8_0_xonly_pubkey. + * tweak_add to a rustsecp256k1_v0_11_xonly_pubkey. * * Note that this alone does _not_ verify that the tweaked pubkey is a * commitment. If the tweak is not chosen in a specific way, the tweaked pubkey @@ -137,35 +137,38 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_xonly_pub * * Returns: 0 if the arguments are invalid or the tweaked pubkey is not the * result of tweaking the internal_pubkey with tweak32. 1 otherwise. - * Args: ctx: pointer to a context object initialized for verification. + * Args: ctx: pointer to a context object. * In: tweaked_pubkey32: pointer to a serialized xonly_pubkey. * tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization * is passed in as tweaked_pubkey32). This must match the * pk_parity value that is returned when calling - * rustsecp256k1zkp_v0_8_0_xonly_pubkey with the tweaked pubkey, or + * rustsecp256k1_v0_11_xonly_pubkey with the tweaked pubkey, or * this function will fail. * internal_pubkey: pointer to an x-only public key object to apply the tweak to. * tweak32: pointer to a 32-byte tweak. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check( + const rustsecp256k1_v0_11_context *ctx, const unsigned char *tweaked_pubkey32, int tweaked_pk_parity, - const rustsecp256k1zkp_v0_8_0_xonly_pubkey *internal_pubkey, + const rustsecp256k1_v0_11_xonly_pubkey *internal_pubkey, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); -/** Compute the keypair for a secret key. +/** Compute the keypair for a valid secret key. + * + * See the documentation of `rustsecp256k1_v0_11_ec_seckey_verify` for more information + * about the validity of secret keys. * - * Returns: 1: secret was valid, keypair is ready to use - * 0: secret was invalid, try again with a different secret - * Args: ctx: pointer to a context object, initialized for signing. + * Returns: 1: secret key is valid + * 0: secret key is invalid + * Args: ctx: pointer to a context object (not rustsecp256k1_v0_11_context_static). * Out: keypair: pointer to the created keypair. * In: seckey: pointer to a 32-byte secret key. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_keypair_create( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_keypair *keypair, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_keypair_create( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_keypair *keypair, const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -176,101 +179,70 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_keypair_c * Out: seckey: pointer to a 32-byte buffer for the secret key. * In: keypair: pointer to a keypair. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_keypair_sec( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_keypair_sec( + const rustsecp256k1_v0_11_context *ctx, unsigned char *seckey, - const rustsecp256k1zkp_v0_8_0_keypair *keypair + const rustsecp256k1_v0_11_keypair *keypair ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Get the public key from a keypair. * * Returns: 1 always. - * Args: ctx: pointer to a context object. - * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to - * the keypair public key. If not, it's set to an invalid value. + * Args: ctx: pointer to a context object. + * Out: pubkey: pointer to a pubkey object, set to the keypair public key. * In: keypair: pointer to a keypair. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_keypair_pub( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *pubkey, - const rustsecp256k1zkp_v0_8_0_keypair *keypair +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_keypair_pub( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *pubkey, + const rustsecp256k1_v0_11_keypair *keypair ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Get the x-only public key from a keypair. * - * This is the same as calling rustsecp256k1zkp_v0_8_0_keypair_pub and then - * rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey. + * This is the same as calling rustsecp256k1_v0_11_keypair_pub and then + * rustsecp256k1_v0_11_xonly_pubkey_from_pubkey. * * Returns: 1 always. * Args: ctx: pointer to a context object. - * Out: pubkey: pointer to an xonly_pubkey object. If 1 is returned, it is set - * to the keypair public key after converting it to an - * xonly_pubkey. If not, it's set to an invalid value. + * Out: pubkey: pointer to an xonly_pubkey object, set to the keypair + * public key after converting it to an xonly_pubkey. * pk_parity: Ignored if NULL. Otherwise, pointer to an integer that will be set to the - * pk_parity argument of rustsecp256k1zkp_v0_8_0_xonly_pubkey_from_pubkey. + * pk_parity argument of rustsecp256k1_v0_11_xonly_pubkey_from_pubkey. * In: keypair: pointer to a keypair. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_keypair_xonly_pub( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_xonly_pubkey *pubkey, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_keypair_xonly_pub( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_xonly_pubkey *pubkey, int *pk_parity, - const rustsecp256k1zkp_v0_8_0_keypair *keypair + const rustsecp256k1_v0_11_keypair *keypair ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); /** Tweak a keypair by adding tweak32 to the secret key and updating the public * key accordingly. * - * Calling this function and then rustsecp256k1zkp_v0_8_0_keypair_pub results in the same - * public key as calling rustsecp256k1zkp_v0_8_0_keypair_xonly_pub and then - * rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add. + * Calling this function and then rustsecp256k1_v0_11_keypair_pub results in the same + * public key as calling rustsecp256k1_v0_11_keypair_xonly_pub and then + * rustsecp256k1_v0_11_xonly_pubkey_tweak_add. * * Returns: 0 if the arguments are invalid or the resulting keypair would be * invalid (only when the tweak is the negation of the keypair's * secret key). 1 otherwise. * - * Args: ctx: pointer to a context object initialized for verification. + * Args: ctx: pointer to a context object. * In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to * an invalid value if this function returns 0. - * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according - * to rustsecp256k1zkp_v0_8_0_ec_seckey_verify, this function returns 0. For - * uniformly random 32-byte arrays the chance of being invalid - * is negligible (around 1 in 2^128). + * In: tweak32: pointer to a 32-byte tweak, which must be valid according to + * rustsecp256k1_v0_11_ec_seckey_verify or 32 zero bytes. For uniformly + * random 32-byte tweaks, the chance of being invalid is + * negligible (around 1 in 2^128). */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_keypair *keypair, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_keypair_xonly_tweak_add( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_keypair *keypair, const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Compare two public keys using lexicographic order - * - * Returns: <0 if the first public key is less than the second - * >0 if the first public key is greater than the second - * 0 if the two public keys are equal - * Args: ctx: a secp256k1 context object. - * In: pubkey1: first public key to compare - * pubkey2: second public key to compare - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_pubkey_cmp( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_pubkey* pk1, - const rustsecp256k1zkp_v0_8_0_pubkey* pk2 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Sorts public keys using lexicographic order - * - * Returns: 0 if the arguments are invalid. 1 otherwise. - * - * Args: ctx: pointer to a context object - * In: pubkeys: array of pointers to pubkeys to sort - * n_pubkeys: number of elements in the pubkeys array - */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_pubkey_sort( - const rustsecp256k1zkp_v0_8_0_context* ctx, - const rustsecp256k1zkp_v0_8_0_pubkey **pubkeys, - size_t n_pubkeys -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - #ifdef __cplusplus } #endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_musig.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_musig.h new file mode 100644 index 00000000..ec1e49bd --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_musig.h @@ -0,0 +1,588 @@ +#ifndef SECP256K1_MUSIG_H +#define SECP256K1_MUSIG_H + +#include "secp256k1_extrakeys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/** This module implements BIP 327 "MuSig2 for BIP340-compatible + * Multi-Signatures" + * (https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki) + * v1.0.0. You can find an example demonstrating the musig module in + * examples/musig.c. + * + * The module also supports BIP 341 ("Taproot") public key tweaking. + * + * It is recommended to read the documentation in this include file carefully. + * Further notes on API usage can be found in doc/musig.md + * + * Since the first version of MuSig is essentially replaced by MuSig2, we use + * MuSig, musig and MuSig2 synonymously unless noted otherwise. + */ + +/** Opaque data structures + * + * The exact representation of data inside the opaque data structures is + * implementation defined and not guaranteed to be portable between different + * platforms or versions. With the exception of `rustsecp256k1_v0_11_musig_secnonce`, the + * data structures can be safely copied/moved. If you need to convert to a + * format suitable for storage, transmission, or comparison, use the + * corresponding serialization and parsing functions. + */ + +/** Opaque data structure that caches information about public key aggregation. + * + * Guaranteed to be 197 bytes in size. No serialization and parsing functions + * (yet). + */ +typedef struct rustsecp256k1_v0_11_musig_keyagg_cache { + unsigned char data[197]; +} rustsecp256k1_v0_11_musig_keyagg_cache; + +/** Opaque data structure that holds a signer's _secret_ nonce. + * + * Guaranteed to be 132 bytes in size. + * + * WARNING: This structure MUST NOT be copied or read or written to directly. A + * signer who is online throughout the whole process and can keep this + * structure in memory can use the provided API functions for a safe standard + * workflow. + * + * Copying this data structure can result in nonce reuse which will leak the + * secret signing key. + */ +typedef struct rustsecp256k1_v0_11_musig_secnonce { + unsigned char data[132]; +} rustsecp256k1_v0_11_musig_secnonce; + +/** Opaque data structure that holds a signer's public nonce. + * + * Guaranteed to be 132 bytes in size. Serialized and parsed with + * `musig_pubnonce_serialize` and `musig_pubnonce_parse`. + */ +typedef struct rustsecp256k1_v0_11_musig_pubnonce { + unsigned char data[132]; +} rustsecp256k1_v0_11_musig_pubnonce; + +/** Opaque data structure that holds an aggregate public nonce. + * + * Guaranteed to be 132 bytes in size. Serialized and parsed with + * `musig_aggnonce_serialize` and `musig_aggnonce_parse`. + */ +typedef struct rustsecp256k1_v0_11_musig_aggnonce { + unsigned char data[132]; +} rustsecp256k1_v0_11_musig_aggnonce; + +/** Opaque data structure that holds a MuSig session. + * + * This structure is not required to be kept secret for the signing protocol to + * be secure. Guaranteed to be 133 bytes in size. No serialization and parsing + * functions (yet). + */ +typedef struct rustsecp256k1_v0_11_musig_session { + unsigned char data[133]; +} rustsecp256k1_v0_11_musig_session; + +/** Opaque data structure that holds a partial MuSig signature. + * + * Guaranteed to be 36 bytes in size. Serialized and parsed with + * `musig_partial_sig_serialize` and `musig_partial_sig_parse`. + */ +typedef struct rustsecp256k1_v0_11_musig_partial_sig { + unsigned char data[36]; +} rustsecp256k1_v0_11_musig_partial_sig; + +/** Parse a signer's public nonce. + * + * Returns: 1 when the nonce could be parsed, 0 otherwise. + * Args: ctx: pointer to a context object + * Out: nonce: pointer to a nonce object + * In: in66: pointer to the 66-byte nonce to be parsed + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_musig_pubnonce_parse( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_musig_pubnonce *nonce, + const unsigned char *in66 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a signer's public nonce + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * Out: out66: pointer to a 66-byte array to store the serialized nonce + * In: nonce: pointer to the nonce + */ +SECP256K1_API int rustsecp256k1_v0_11_musig_pubnonce_serialize( + const rustsecp256k1_v0_11_context *ctx, + unsigned char *out66, + const rustsecp256k1_v0_11_musig_pubnonce *nonce +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse an aggregate public nonce. + * + * Returns: 1 when the nonce could be parsed, 0 otherwise. + * Args: ctx: pointer to a context object + * Out: nonce: pointer to a nonce object + * In: in66: pointer to the 66-byte nonce to be parsed + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_musig_aggnonce_parse( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_musig_aggnonce *nonce, + const unsigned char *in66 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an aggregate public nonce + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * Out: out66: pointer to a 66-byte array to store the serialized nonce + * In: nonce: pointer to the nonce + */ +SECP256K1_API int rustsecp256k1_v0_11_musig_aggnonce_serialize( + const rustsecp256k1_v0_11_context *ctx, + unsigned char *out66, + const rustsecp256k1_v0_11_musig_aggnonce *nonce +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse a MuSig partial signature. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: in32: pointer to the 32-byte signature to be parsed + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_musig_partial_sig_parse( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_musig_partial_sig *sig, + const unsigned char *in32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a MuSig partial signature + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * Out: out32: pointer to a 32-byte array to store the serialized signature + * In: sig: pointer to the signature + */ +SECP256K1_API int rustsecp256k1_v0_11_musig_partial_sig_serialize( + const rustsecp256k1_v0_11_context *ctx, + unsigned char *out32, + const rustsecp256k1_v0_11_musig_partial_sig *sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Computes an aggregate public key and uses it to initialize a keyagg_cache + * + * Different orders of `pubkeys` result in different `agg_pk`s. + * + * Before aggregating, the pubkeys can be sorted with `rustsecp256k1_v0_11_ec_pubkey_sort` + * which ensures the same `agg_pk` result for the same multiset of pubkeys. + * This is useful to do before `pubkey_agg`, such that the order of pubkeys + * does not affect the aggregate public key. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: agg_pk: the MuSig-aggregated x-only public key. If you do not need it, + * this arg can be NULL. + * keyagg_cache: if non-NULL, pointer to a musig_keyagg_cache struct that + * is required for signing (or observing the signing session + * and verifying partial signatures). + * In: pubkeys: input array of pointers to public keys to aggregate. The order + * is important; a different order will result in a different + * aggregate public key. + * n_pubkeys: length of pubkeys array. Must be greater than 0. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_musig_pubkey_agg( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_xonly_pubkey *agg_pk, + rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, + const rustsecp256k1_v0_11_pubkey * const *pubkeys, + size_t n_pubkeys +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(4); + +/** Obtain the aggregate public key from a keyagg_cache. + * + * This is only useful if you need the non-xonly public key, in particular for + * plain (non-xonly) tweaking or batch-verifying multiple key aggregations + * (not implemented). + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: agg_pk: the MuSig-aggregated public key. + * In: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by + * `musig_pubkey_agg` + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_musig_pubkey_get( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *agg_pk, + const rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Apply plain "EC" tweaking to a public key in a given keyagg_cache by adding + * the generator multiplied with `tweak32` to it. This is useful for deriving + * child keys from an aggregate public key via BIP 32 where `tweak32` is set to + * a hash as defined in BIP 32. + * + * Callers are responsible for deriving `tweak32` in a way that does not reduce + * the security of MuSig (for example, by following BIP 32). + * + * The tweaking method is the same as `rustsecp256k1_v0_11_ec_pubkey_tweak_add`. So after + * the following pseudocode buf and buf2 have identical contents (absent + * earlier failures). + * + * rustsecp256k1_v0_11_musig_pubkey_agg(..., keyagg_cache, pubkeys, ...) + * rustsecp256k1_v0_11_musig_pubkey_get(..., agg_pk, keyagg_cache) + * rustsecp256k1_v0_11_musig_pubkey_ec_tweak_add(..., output_pk, tweak32, keyagg_cache) + * rustsecp256k1_v0_11_ec_pubkey_serialize(..., buf, ..., output_pk, ...) + * rustsecp256k1_v0_11_ec_pubkey_tweak_add(..., agg_pk, tweak32) + * rustsecp256k1_v0_11_ec_pubkey_serialize(..., buf2, ..., agg_pk, ...) + * + * This function is required if you want to _sign_ for a tweaked aggregate key. + * If you are only computing a public key but not intending to create a + * signature for it, use `rustsecp256k1_v0_11_ec_pubkey_tweak_add` instead. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: output_pubkey: pointer to a public key to store the result. Will be set + * to an invalid value if this function returns 0. If you + * do not need it, this arg can be NULL. + * In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by + * `musig_pubkey_agg` + * In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes + * `rustsecp256k1_v0_11_ec_seckey_verify` and is not equal to the + * secret key corresponding to the public key represented + * by keyagg_cache or its negation. For uniformly random + * 32-byte arrays the chance of being invalid is + * negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_musig_pubkey_ec_tweak_add( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *output_pubkey, + rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Apply x-only tweaking to a public key in a given keyagg_cache by adding the + * generator multiplied with `tweak32` to it. This is useful for creating + * Taproot outputs where `tweak32` is set to a TapTweak hash as defined in BIP + * 341. + * + * Callers are responsible for deriving `tweak32` in a way that does not reduce + * the security of MuSig (for example, by following Taproot BIP 341). + * + * The tweaking method is the same as `rustsecp256k1_v0_11_xonly_pubkey_tweak_add`. So in + * the following pseudocode xonly_pubkey_tweak_add_check (absent earlier + * failures) returns 1. + * + * rustsecp256k1_v0_11_musig_pubkey_agg(..., agg_pk, keyagg_cache, pubkeys, ...) + * rustsecp256k1_v0_11_musig_pubkey_xonly_tweak_add(..., output_pk, keyagg_cache, tweak32) + * rustsecp256k1_v0_11_xonly_pubkey_serialize(..., buf, output_pk) + * rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(..., buf, ..., agg_pk, tweak32) + * + * This function is required if you want to _sign_ for a tweaked aggregate key. + * If you are only computing a public key but not intending to create a + * signature for it, use `rustsecp256k1_v0_11_xonly_pubkey_tweak_add` instead. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: output_pubkey: pointer to a public key to store the result. Will be set + * to an invalid value if this function returns 0. If you + * do not need it, this arg can be NULL. + * In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by + * `musig_pubkey_agg` + * In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes + * `rustsecp256k1_v0_11_ec_seckey_verify` and is not equal to the + * secret key corresponding to the public key represented + * by keyagg_cache or its negation. For uniformly random + * 32-byte arrays the chance of being invalid is + * negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_musig_pubkey_xonly_tweak_add( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *output_pubkey, + rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Starts a signing session by generating a nonce + * + * This function outputs a secret nonce that will be required for signing and a + * corresponding public nonce that is intended to be sent to other signers. + * + * MuSig differs from regular Schnorr signing in that implementers _must_ take + * special care to not reuse a nonce. This can be ensured by following these rules: + * + * 1. Each call to this function must have a UNIQUE session_secrand32 that must + * NOT BE REUSED in subsequent calls to this function and must be KEPT + * SECRET (even from other signers). + * 2. If you already know the seckey, message or aggregate public key + * cache, they can be optionally provided to derive the nonce and increase + * misuse-resistance. The extra_input32 argument can be used to provide + * additional data that does not repeat in normal scenarios, such as the + * current time. + * 3. Avoid copying (or serializing) the secnonce. This reduces the possibility + * that it is used more than once for signing. + * + * If you don't have access to good randomness for session_secrand32, but you + * have access to a non-repeating counter, then see + * rustsecp256k1_v0_11_musig_nonce_gen_counter. + * + * Remember that nonce reuse will leak the secret key! + * Note that using the same seckey for multiple MuSig sessions is fine. + * + * Returns: 0 if the arguments are invalid and 1 otherwise + * Args: ctx: pointer to a context object (not rustsecp256k1_v0_11_context_static) + * Out: secnonce: pointer to a structure to store the secret nonce + * pubnonce: pointer to a structure to store the public nonce + * In/Out: + * session_secrand32: a 32-byte session_secrand32 as explained above. Must be unique to this + * call to rustsecp256k1_v0_11_musig_nonce_gen and must be uniformly + * random. If the function call is successful, the + * session_secrand32 buffer is invalidated to prevent reuse. + * In: + * seckey: the 32-byte secret key that will later be used for signing, if + * already known (can be NULL) + * pubkey: public key of the signer creating the nonce. The secnonce + * output of this function cannot be used to sign for any + * other public key. While the public key should correspond + * to the provided seckey, a mismatch will not cause the + * function to return 0. + * msg32: the 32-byte message that will later be signed, if already known + * (can be NULL) + * keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate + * (and potentially tweaked) public key if already known + * (can be NULL) + * extra_input32: an optional 32-byte array that is input to the nonce + * derivation function (can be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_musig_nonce_gen( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_musig_secnonce *secnonce, + rustsecp256k1_v0_11_musig_pubnonce *pubnonce, + unsigned char *session_secrand32, + const unsigned char *seckey, + const rustsecp256k1_v0_11_pubkey *pubkey, + const unsigned char *msg32, + const rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, + const unsigned char *extra_input32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6); + + +/** Alternative way to generate a nonce and start a signing session + * + * This function outputs a secret nonce that will be required for signing and a + * corresponding public nonce that is intended to be sent to other signers. + * + * This function differs from `rustsecp256k1_v0_11_musig_nonce_gen` by accepting a + * non-repeating counter value instead of a secret random value. This requires + * that a secret key is provided to `rustsecp256k1_v0_11_musig_nonce_gen_counter` + * (through the keypair argument), as opposed to `rustsecp256k1_v0_11_musig_nonce_gen` + * where the seckey argument is optional. + * + * MuSig differs from regular Schnorr signing in that implementers _must_ take + * special care to not reuse a nonce. This can be ensured by following these rules: + * + * 1. The nonrepeating_cnt argument must be a counter value that never repeats, + * i.e., you must never call `rustsecp256k1_v0_11_musig_nonce_gen_counter` twice with + * the same keypair and nonrepeating_cnt value. For example, this implies + * that if the same keypair is used with `rustsecp256k1_v0_11_musig_nonce_gen_counter` + * on multiple devices, none of the devices should have the same counter + * value as any other device. + * 2. If the seckey, message or aggregate public key cache is already available + * at this stage, any of these can be optionally provided, in which case + * they will be used in the derivation of the nonce and increase + * misuse-resistance. The extra_input32 argument can be used to provide + * additional data that does not repeat in normal scenarios, such as the + * current time. + * 3. Avoid copying (or serializing) the secnonce. This reduces the possibility + * that it is used more than once for signing. + * + * Remember that nonce reuse will leak the secret key! + * Note that using the same keypair for multiple MuSig sessions is fine. + * + * Returns: 0 if the arguments are invalid and 1 otherwise + * Args: ctx: pointer to a context object (not rustsecp256k1_v0_11_context_static) + * Out: secnonce: pointer to a structure to store the secret nonce + * pubnonce: pointer to a structure to store the public nonce + * In: + * nonrepeating_cnt: the value of a counter as explained above. Must be + * unique to this call to rustsecp256k1_v0_11_musig_nonce_gen. + * keypair: keypair of the signer creating the nonce. The secnonce + * output of this function cannot be used to sign for any + * other keypair. + * msg32: the 32-byte message that will later be signed, if already known + * (can be NULL) + * keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate + * (and potentially tweaked) public key if already known + * (can be NULL) + * extra_input32: an optional 32-byte array that is input to the nonce + * derivation function (can be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_musig_nonce_gen_counter( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_musig_secnonce *secnonce, + rustsecp256k1_v0_11_musig_pubnonce *pubnonce, + uint64_t nonrepeating_cnt, + const rustsecp256k1_v0_11_keypair *keypair, + const unsigned char *msg32, + const rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, + const unsigned char *extra_input32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); + +/** Aggregates the nonces of all signers into a single nonce + * + * This can be done by an untrusted party to reduce the communication + * between signers. Instead of everyone sending nonces to everyone else, there + * can be one party receiving all nonces, aggregating the nonces with this + * function and then sending only the aggregate nonce back to the signers. + * + * If the aggregator does not compute the aggregate nonce correctly, the final + * signature will be invalid. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: aggnonce: pointer to an aggregate public nonce object for + * musig_nonce_process + * In: pubnonces: array of pointers to public nonces sent by the + * signers + * n_pubnonces: number of elements in the pubnonces array. Must be + * greater than 0. + */ +SECP256K1_API int rustsecp256k1_v0_11_musig_nonce_agg( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_musig_aggnonce *aggnonce, + const rustsecp256k1_v0_11_musig_pubnonce * const *pubnonces, + size_t n_pubnonces +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Takes the aggregate nonce and creates a session that is required for signing + * and verification of partial signatures. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: session: pointer to a struct to store the session + * In: aggnonce: pointer to an aggregate public nonce object that is the + * output of musig_nonce_agg + * msg32: the 32-byte message to sign + * keyagg_cache: pointer to the keyagg_cache that was used to create the + * aggregate (and potentially tweaked) pubkey + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_musig_nonce_process( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_musig_session *session, + const rustsecp256k1_v0_11_musig_aggnonce *aggnonce, + const unsigned char *msg32, + const rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + +/** Produces a partial signature + * + * This function overwrites the given secnonce with zeros and will abort if given a + * secnonce that is all zeros. This is a best effort attempt to protect against nonce + * reuse. However, this is of course easily defeated if the secnonce has been + * copied (or serialized). Remember that nonce reuse will leak the secret key! + * + * For signing to succeed, the secnonce provided to this function must have + * been generated for the provided keypair. This means that when signing for a + * keypair consisting of a seckey and pubkey, the secnonce must have been + * created by calling musig_nonce_gen with that pubkey. Otherwise, the + * illegal_callback is called. + * + * This function does not verify the output partial signature, deviating from + * the BIP 327 specification. It is recommended to verify the output partial + * signature with `rustsecp256k1_v0_11_musig_partial_sig_verify` to prevent random or + * adversarially provoked computation errors. + * + * Returns: 0 if the arguments are invalid or the provided secnonce has already + * been used for signing, 1 otherwise + * Args: ctx: pointer to a context object + * Out: partial_sig: pointer to struct to store the partial signature + * In/Out: secnonce: pointer to the secnonce struct created in + * musig_nonce_gen that has been never used in a + * partial_sign call before and has been created for the + * keypair + * In: keypair: pointer to keypair to sign the message with + * keyagg_cache: pointer to the keyagg_cache that was output when the + * aggregate public key for this session + * session: pointer to the session that was created with + * musig_nonce_process + */ +SECP256K1_API int rustsecp256k1_v0_11_musig_partial_sign( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_musig_partial_sig *partial_sig, + rustsecp256k1_v0_11_musig_secnonce *secnonce, + const rustsecp256k1_v0_11_keypair *keypair, + const rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, + const rustsecp256k1_v0_11_musig_session *session +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); + +/** Verifies an individual signer's partial signature + * + * The signature is verified for a specific signing session. In order to avoid + * accidentally verifying a signature from a different or non-existing signing + * session, you must ensure the following: + * 1. The `keyagg_cache` argument is identical to the one used to create the + * `session` with `musig_nonce_process`. + * 2. The `pubkey` argument must be identical to the one sent by the signer + * before aggregating it with `musig_pubkey_agg` to create the + * `keyagg_cache`. + * 3. The `pubnonce` argument must be identical to the one sent by the signer + * before aggregating it with `musig_nonce_agg` and using the result to + * create the `session` with `musig_nonce_process`. + * + * It is not required to call this function in regular MuSig sessions, because + * if any partial signature does not verify, the final signature will not + * verify either, so the problem will be caught. However, this function + * provides the ability to identify which specific partial signature fails + * verification. + * + * Returns: 0 if the arguments are invalid or the partial signature does not + * verify, 1 otherwise + * Args ctx: pointer to a context object + * In: partial_sig: pointer to partial signature to verify, sent by + * the signer associated with `pubnonce` and `pubkey` + * pubnonce: public nonce of the signer in the signing session + * pubkey: public key of the signer in the signing session + * keyagg_cache: pointer to the keyagg_cache that was output when the + * aggregate public key for this signing session + * session: pointer to the session that was created with + * `musig_nonce_process` + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_musig_partial_sig_verify( + const rustsecp256k1_v0_11_context *ctx, + const rustsecp256k1_v0_11_musig_partial_sig *partial_sig, + const rustsecp256k1_v0_11_musig_pubnonce *pubnonce, + const rustsecp256k1_v0_11_pubkey *pubkey, + const rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, + const rustsecp256k1_v0_11_musig_session *session +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); + +/** Aggregates partial signatures + * + * Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean + * the resulting signature verifies). + * Args: ctx: pointer to a context object + * Out: sig64: complete (but possibly invalid) Schnorr signature + * In: session: pointer to the session that was created with + * musig_nonce_process + * partial_sigs: array of pointers to partial signatures to aggregate + * n_sigs: number of elements in the partial_sigs array. Must be + * greater than 0. + */ +SECP256K1_API int rustsecp256k1_v0_11_musig_partial_sig_agg( + const rustsecp256k1_v0_11_context *ctx, + unsigned char *sig64, + const rustsecp256k1_v0_11_musig_session *session, + const rustsecp256k1_v0_11_musig_partial_sig * const *partial_sigs, + size_t n_sigs +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_preallocated.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_preallocated.h similarity index 55% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_preallocated.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_preallocated.h index de77ee15..7ec542ec 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_preallocated.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_preallocated.h @@ -16,8 +16,8 @@ extern "C" { * objects created by functions in secp256k1.h, i.e., they can be passed to any * API function that expects a context object (see secp256k1.h for details). The * only exception is that context objects created by functions in this module - * must be destroyed using rustsecp256k1zkp_v0_8_0_context_preallocated_destroy (in this - * module) instead of rustsecp256k1zkp_v0_8_0_context_destroy (in secp256k1.h). + * must be destroyed using rustsecp256k1_v0_11_context_preallocated_destroy (in this + * module) instead of rustsecp256k1_v0_11_context_destroy (in secp256k1.h). * * It is guaranteed that functions in this module will not call malloc or its * friends realloc, calloc, and free. @@ -27,24 +27,24 @@ extern "C" { * caller-provided memory. * * The purpose of this function is to determine how much memory must be provided - * to rustsecp256k1zkp_v0_8_0_context_preallocated_create. + * to rustsecp256k1_v0_11_context_preallocated_create. * * Returns: the required size of the caller-provided memory block * In: flags: which parts of the context to initialize. */ -SECP256K1_API size_t rustsecp256k1zkp_v0_8_0_context_preallocated_size( +SECP256K1_API size_t rustsecp256k1_v0_11_context_preallocated_size( unsigned int flags ) SECP256K1_WARN_UNUSED_RESULT; /** Create a secp256k1 context object in caller-provided memory. * * The caller must provide a pointer to a rewritable contiguous block of memory - * of size at least rustsecp256k1zkp_v0_8_0_context_preallocated_size(flags) bytes, suitably + * of size at least rustsecp256k1_v0_11_context_preallocated_size(flags) bytes, suitably * aligned to hold an object of any type. * * The block of memory is exclusively owned by the created context object during * the lifetime of this context object, which begins with the call to this - * function and ends when a call to rustsecp256k1zkp_v0_8_0_context_preallocated_destroy + * function and ends when a call to rustsecp256k1_v0_11_context_preallocated_destroy * (which destroys the context object again) returns. During the lifetime of the * context object, the caller is obligated not to access this block of memory, * i.e., the caller may not read or write the memory, e.g., by copying the memory @@ -52,17 +52,19 @@ SECP256K1_API size_t rustsecp256k1zkp_v0_8_0_context_preallocated_size( * in the memory. In simpler words, the prealloc pointer (or any pointer derived * from it) should not be used during the lifetime of the context object. * - * Returns: a newly created context object. - * In: prealloc: a pointer to a rewritable contiguous block of memory of - * size at least rustsecp256k1zkp_v0_8_0_context_preallocated_size(flags) + * Returns: pointer to newly created context object. + * In: prealloc: pointer to a rewritable contiguous block of memory of + * size at least rustsecp256k1_v0_11_context_preallocated_size(flags) * bytes, as detailed above. * flags: which parts of the context to initialize. * - * See also rustsecp256k1zkp_v0_8_0_context_randomize (in secp256k1.h) - * and rustsecp256k1zkp_v0_8_0_context_preallocated_destroy. + * See rustsecp256k1_v0_11_context_create (in secp256k1.h) for further details. + * + * See also rustsecp256k1_v0_11_context_randomize (in secp256k1.h) + * and rustsecp256k1_v0_11_context_preallocated_destroy. */ -SECP256K1_API rustsecp256k1zkp_v0_8_0_context* rustsecp256k1zkp_v0_8_0_context_preallocated_create( - void* prealloc, +SECP256K1_API rustsecp256k1_v0_11_context *rustsecp256k1_v0_11_context_preallocated_create( + void *prealloc, unsigned int flags ) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; @@ -70,31 +72,34 @@ SECP256K1_API rustsecp256k1zkp_v0_8_0_context* rustsecp256k1zkp_v0_8_0_context_p * caller-provided memory. * * Returns: the required size of the caller-provided memory block. - * In: ctx: an existing context to copy. + * In: ctx: pointer to a context to copy. */ -SECP256K1_API size_t rustsecp256k1zkp_v0_8_0_context_preallocated_clone_size( - const rustsecp256k1zkp_v0_8_0_context* ctx +SECP256K1_API size_t rustsecp256k1_v0_11_context_preallocated_clone_size( + const rustsecp256k1_v0_11_context *ctx ) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; /** Copy a secp256k1 context object into caller-provided memory. * * The caller must provide a pointer to a rewritable contiguous block of memory - * of size at least rustsecp256k1zkp_v0_8_0_context_preallocated_size(flags) bytes, suitably + * of size at least rustsecp256k1_v0_11_context_preallocated_size(flags) bytes, suitably * aligned to hold an object of any type. * * The block of memory is exclusively owned by the created context object during * the lifetime of this context object, see the description of - * rustsecp256k1zkp_v0_8_0_context_preallocated_create for details. + * rustsecp256k1_v0_11_context_preallocated_create for details. + * + * Cloning rustsecp256k1_v0_11_context_static is not possible, and should not be emulated by + * the caller (e.g., using memcpy). Create a new context instead. * - * Returns: a newly created context object. - * Args: ctx: an existing context to copy. - * In: prealloc: a pointer to a rewritable contiguous block of memory of - * size at least rustsecp256k1zkp_v0_8_0_context_preallocated_size(flags) + * Returns: pointer to a newly created context object. + * Args: ctx: pointer to a context to copy (not rustsecp256k1_v0_11_context_static). + * In: prealloc: pointer to a rewritable contiguous block of memory of + * size at least rustsecp256k1_v0_11_context_preallocated_size(flags) * bytes, as detailed above. */ -SECP256K1_API rustsecp256k1zkp_v0_8_0_context* rustsecp256k1zkp_v0_8_0_context_preallocated_clone( - const rustsecp256k1zkp_v0_8_0_context* ctx, - void* prealloc +SECP256K1_API rustsecp256k1_v0_11_context *rustsecp256k1_v0_11_context_preallocated_clone( + const rustsecp256k1_v0_11_context *ctx, + void *prealloc ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_WARN_UNUSED_RESULT; /** Destroy a secp256k1 context object that has been created in @@ -103,22 +108,23 @@ SECP256K1_API rustsecp256k1zkp_v0_8_0_context* rustsecp256k1zkp_v0_8_0_context_p * The context pointer may not be used afterwards. * * The context to destroy must have been created using - * rustsecp256k1zkp_v0_8_0_context_preallocated_create or rustsecp256k1zkp_v0_8_0_context_preallocated_clone. - * If the context has instead been created using rustsecp256k1zkp_v0_8_0_context_create or - * rustsecp256k1zkp_v0_8_0_context_clone, the behaviour is undefined. In that case, - * rustsecp256k1zkp_v0_8_0_context_destroy must be used instead. + * rustsecp256k1_v0_11_context_preallocated_create or rustsecp256k1_v0_11_context_preallocated_clone. + * If the context has instead been created using rustsecp256k1_v0_11_context_create or + * rustsecp256k1_v0_11_context_clone, the behaviour is undefined. In that case, + * rustsecp256k1_v0_11_context_destroy must be used instead. * * If required, it is the responsibility of the caller to deallocate the block * of memory properly after this function returns, e.g., by calling free on the - * preallocated pointer given to rustsecp256k1zkp_v0_8_0_context_preallocated_create or - * rustsecp256k1zkp_v0_8_0_context_preallocated_clone. + * preallocated pointer given to rustsecp256k1_v0_11_context_preallocated_create or + * rustsecp256k1_v0_11_context_preallocated_clone. * - * Args: ctx: an existing context to destroy, constructed using - * rustsecp256k1zkp_v0_8_0_context_preallocated_create or - * rustsecp256k1zkp_v0_8_0_context_preallocated_clone. + * Args: ctx: pointer to a context to destroy, constructed using + * rustsecp256k1_v0_11_context_preallocated_create or + * rustsecp256k1_v0_11_context_preallocated_clone + * (i.e., not rustsecp256k1_v0_11_context_static). */ -SECP256K1_API void rustsecp256k1zkp_v0_8_0_context_preallocated_destroy( - rustsecp256k1zkp_v0_8_0_context* ctx +SECP256K1_API void rustsecp256k1_v0_11_context_preallocated_destroy( + rustsecp256k1_v0_11_context *ctx ) SECP256K1_ARG_NONNULL(1); #ifdef __cplusplus diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_recovery.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_recovery.h similarity index 54% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_recovery.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_recovery.h index c409a002..d6b0d602 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_recovery.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_recovery.h @@ -7,35 +7,35 @@ extern "C" { #endif -/** Opaque data structured that holds a parsed ECDSA signature, +/** Opaque data structure that holds a parsed ECDSA signature, * supporting pubkey recovery. * * The exact representation of data inside is implementation defined and not * guaranteed to be portable between different platforms or versions. It is * however guaranteed to be 65 bytes in size, and can be safely copied/moved. * If you need to convert to a format suitable for storage or transmission, use - * the rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_* and - * rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_* functions. + * the rustsecp256k1_v0_11_ecdsa_signature_serialize_* and + * rustsecp256k1_v0_11_ecdsa_signature_parse_* functions. * * Furthermore, it is guaranteed that identical signatures (including their * recoverability) will have identical representation, so they can be * memcmp'ed. */ -typedef struct { +typedef struct rustsecp256k1_v0_11_ecdsa_recoverable_signature { unsigned char data[65]; -} rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature; +} rustsecp256k1_v0_11_ecdsa_recoverable_signature; /** Parse a compact ECDSA signature (64 bytes + recovery id). * * Returns: 1 when the signature could be parsed, 0 otherwise - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input64: a pointer to a 64-byte compact signature + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input64: pointer to a 64-byte compact signature * recid: the recovery id (0, 1, 2 or 3) */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature* sig, +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_ecdsa_recoverable_signature *sig, const unsigned char *input64, int recid ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -43,50 +43,50 @@ SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_comp /** Convert a recoverable signature into a normal signature. * * Returns: 1 - * Args: ctx: a secp256k1 context object. - * Out: sig: a pointer to a normal signature. - * In: sigin: a pointer to a recoverable signature. + * Args: ctx: pointer to a context object. + * Out: sig: pointer to a normal signature. + * In: sigin: pointer to a recoverable signature. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_convert( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_signature* sig, - const rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature* sigin +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_recoverable_signature_convert( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_ecdsa_signature *sig, + const rustsecp256k1_v0_11_ecdsa_recoverable_signature *sigin ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Serialize an ECDSA signature in compact format (64 bytes + recovery id). * * Returns: 1 - * Args: ctx: a secp256k1 context object. - * Out: output64: a pointer to a 64-byte array of the compact signature. - * recid: a pointer to an integer to hold the recovery id. - * In: sig: a pointer to an initialized signature object. + * Args: ctx: pointer to a context object. + * Out: output64: pointer to a 64-byte array of the compact signature. + * recid: pointer to an integer to hold the recovery id. + * In: sig: pointer to an initialized signature object. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_serialize_compact( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_recoverable_signature_serialize_compact( + const rustsecp256k1_v0_11_context *ctx, unsigned char *output64, int *recid, - const rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature* sig + const rustsecp256k1_v0_11_ecdsa_recoverable_signature *sig ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Create a recoverable ECDSA signature. * * Returns: 1: signature created * 0: the nonce generation function failed, or the secret key was invalid. - * Args: ctx: pointer to a context object, initialized for signing. + * Args: ctx: pointer to a context object (not rustsecp256k1_v0_11_context_static). * Out: sig: pointer to an array where the signature will be placed. * In: msghash32: the 32-byte message hash being signed. * seckey: pointer to a 32-byte secret key. * noncefp: pointer to a nonce generation function. If NULL, - * rustsecp256k1zkp_v0_8_0_nonce_function_default is used. + * rustsecp256k1_v0_11_nonce_function_default is used. * ndata: pointer to arbitrary data used by the nonce generation function - * (can be NULL for rustsecp256k1zkp_v0_8_0_nonce_function_default). + * (can be NULL for rustsecp256k1_v0_11_nonce_function_default). */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature *sig, +SECP256K1_API int rustsecp256k1_v0_11_ecdsa_sign_recoverable( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_ecdsa_recoverable_signature *sig, const unsigned char *msghash32, const unsigned char *seckey, - rustsecp256k1zkp_v0_8_0_nonce_function noncefp, + rustsecp256k1_v0_11_nonce_function noncefp, const void *ndata ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); @@ -94,15 +94,15 @@ SECP256K1_API int rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable( * * Returns: 1: public key successfully recovered (which guarantees a correct signature). * 0: otherwise. - * Args: ctx: pointer to a context object, initialized for verification. + * Args: ctx: pointer to a context object. * Out: pubkey: pointer to the recovered public key. * In: sig: pointer to initialized signature that supports pubkey recovery. * msghash32: the 32-byte message hash assumed to be signed. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_ecdsa_recover( - const rustsecp256k1zkp_v0_8_0_context* ctx, - rustsecp256k1zkp_v0_8_0_pubkey *pubkey, - const rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature *sig, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_ecdsa_recover( + const rustsecp256k1_v0_11_context *ctx, + rustsecp256k1_v0_11_pubkey *pubkey, + const rustsecp256k1_v0_11_ecdsa_recoverable_signature *sig, const unsigned char *msghash32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_schnorrsig.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_schnorrsig.h similarity index 70% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_schnorrsig.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_schnorrsig.h index 149a7c04..3efe3815 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/include/secp256k1_schnorrsig.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/include/secp256k1_schnorrsig.h @@ -15,7 +15,7 @@ extern "C" { /** A pointer to a function to deterministically generate a nonce. * - * Same as rustsecp256k1zkp_v0_8_0_nonce function with the exception of accepting an + * Same as rustsecp256k1_v0_11_nonce function with the exception of accepting an * additional pubkey argument and not requiring an attempt argument. The pubkey * argument can protect signature schemes with key-prefixed challenge hash * inputs against reusing the nonce when signing with the wrong precomputed @@ -38,7 +38,7 @@ extern "C" { * Except for test cases, this function should compute some cryptographic hash of * the message, the key, the pubkey, the algorithm description, and data. */ -typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function_hardened)( +typedef int (*rustsecp256k1_v0_11_nonce_function_hardened)( unsigned char *nonce32, const unsigned char *msg, size_t msglen, @@ -61,7 +61,7 @@ typedef int (*rustsecp256k1zkp_v0_8_0_nonce_function_hardened)( * Therefore, to create BIP-340 compliant signatures, algo must be set to * "BIP0340/nonce" and algolen to 13. */ -SECP256K1_API extern const rustsecp256k1zkp_v0_8_0_nonce_function_hardened rustsecp256k1zkp_v0_8_0_nonce_function_bip340; +SECP256K1_API const rustsecp256k1_v0_11_nonce_function_hardened rustsecp256k1_v0_11_nonce_function_bip340; /** Data structure that contains additional arguments for schnorrsig_sign_custom. * @@ -73,17 +73,17 @@ SECP256K1_API extern const rustsecp256k1zkp_v0_8_0_nonce_function_hardened rusts * and has no other function than making sure the object is * initialized. * noncefp: pointer to a nonce generation function. If NULL, - * rustsecp256k1zkp_v0_8_0_nonce_function_bip340 is used + * rustsecp256k1_v0_11_nonce_function_bip340 is used * ndata: pointer to arbitrary data used by the nonce generation function * (can be NULL). If it is non-NULL and - * rustsecp256k1zkp_v0_8_0_nonce_function_bip340 is used, then ndata must be a + * rustsecp256k1_v0_11_nonce_function_bip340 is used, then ndata must be a * pointer to 32-byte auxiliary randomness as per BIP-340. */ -typedef struct { +typedef struct rustsecp256k1_v0_11_schnorrsig_extraparams { unsigned char magic[4]; - rustsecp256k1zkp_v0_8_0_nonce_function_hardened noncefp; - void* ndata; -} rustsecp256k1zkp_v0_8_0_schnorrsig_extraparams; + rustsecp256k1_v0_11_nonce_function_hardened noncefp; + void *ndata; +} rustsecp256k1_v0_11_schnorrsig_extraparams; #define SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC { 0xda, 0x6f, 0xb3, 0x8c } #define SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT {\ @@ -95,18 +95,18 @@ typedef struct { /** Create a Schnorr signature. * * Does _not_ strictly follow BIP-340 because it does not verify the resulting - * signature. Instead, you can manually use rustsecp256k1zkp_v0_8_0_schnorrsig_verify and + * signature. Instead, you can manually use rustsecp256k1_v0_11_schnorrsig_verify and * abort if it fails. * * This function only signs 32-byte messages. If you have messages of a * different size (or the same size but without a context-specific tag * prefix), it is recommended to create a 32-byte message hash with - * rustsecp256k1zkp_v0_8_0_tagged_sha256 and then sign the hash. Tagged hashing allows + * rustsecp256k1_v0_11_tagged_sha256 and then sign the hash. Tagged hashing allows * providing an context-specific tag for domain separation. This prevents * signatures from being valid in multiple contexts by accident. * * Returns 1 on success, 0 on failure. - * Args: ctx: pointer to a context object, initialized for signing. + * Args: ctx: pointer to a context object (not rustsecp256k1_v0_11_context_static). * Out: sig64: pointer to a 64-byte array to store the serialized signature. * In: msg32: the 32-byte message being signed. * keypair: pointer to an initialized keypair. @@ -116,63 +116,71 @@ typedef struct { * BIP-340 "Default Signing" for a full explanation of this * argument and for guidance if randomness is expensive. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_schnorrsig_sign32( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API int rustsecp256k1_v0_11_schnorrsig_sign32( + const rustsecp256k1_v0_11_context *ctx, unsigned char *sig64, const unsigned char *msg32, - const rustsecp256k1zkp_v0_8_0_keypair *keypair, + const rustsecp256k1_v0_11_keypair *keypair, const unsigned char *aux_rand32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); -/** Same as rustsecp256k1zkp_v0_8_0_schnorrsig_sign32, but DEPRECATED. Will be removed in +/** Same as rustsecp256k1_v0_11_schnorrsig_sign32, but DEPRECATED. Will be removed in * future versions. */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_schnorrsig_sign( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API int rustsecp256k1_v0_11_schnorrsig_sign( + const rustsecp256k1_v0_11_context *ctx, unsigned char *sig64, const unsigned char *msg32, - const rustsecp256k1zkp_v0_8_0_keypair *keypair, + const rustsecp256k1_v0_11_keypair *keypair, const unsigned char *aux_rand32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) - SECP256K1_DEPRECATED("Use rustsecp256k1zkp_v0_8_0_schnorrsig_sign32 instead"); + SECP256K1_DEPRECATED("Use rustsecp256k1_v0_11_schnorrsig_sign32 instead"); /** Create a Schnorr signature with a more flexible API. * - * Same arguments as rustsecp256k1zkp_v0_8_0_schnorrsig_sign except that it allows signing + * Same arguments as rustsecp256k1_v0_11_schnorrsig_sign except that it allows signing * variable length messages and accepts a pointer to an extraparams object that * allows customizing signing by passing additional arguments. * - * Creates the same signatures as schnorrsig_sign if msglen is 32 and the - * extraparams.ndata is the same as aux_rand32. + * Equivalent to rustsecp256k1_v0_11_schnorrsig_sign32(..., aux_rand32) if msglen is 32 + * and extraparams is initialized as follows: + * ``` + * rustsecp256k1_v0_11_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + * extraparams.ndata = (unsigned char*)aux_rand32; + * ``` * + * Returns 1 on success, 0 on failure. + * Args: ctx: pointer to a context object (not rustsecp256k1_v0_11_context_static). + * Out: sig64: pointer to a 64-byte array to store the serialized signature. * In: msg: the message being signed. Can only be NULL if msglen is 0. - * msglen: length of the message - * extraparams: pointer to a extraparams object (can be NULL) + * msglen: length of the message. + * keypair: pointer to an initialized keypair. + * extraparams: pointer to an extraparams object (can be NULL). */ -SECP256K1_API int rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API int rustsecp256k1_v0_11_schnorrsig_sign_custom( + const rustsecp256k1_v0_11_context *ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, - const rustsecp256k1zkp_v0_8_0_keypair *keypair, - rustsecp256k1zkp_v0_8_0_schnorrsig_extraparams *extraparams + const rustsecp256k1_v0_11_keypair *keypair, + rustsecp256k1_v0_11_schnorrsig_extraparams *extraparams ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5); /** Verify a Schnorr signature. * * Returns: 1: correct signature * 0: incorrect signature - * Args: ctx: a secp256k1 context object, initialized for verification. + * Args: ctx: pointer to a context object. * In: sig64: pointer to the 64-byte signature to verify. * msg: the message being verified. Can only be NULL if msglen is 0. * msglen: length of the message - * pubkey: pointer to an x-only public key to verify with (cannot be NULL) + * pubkey: pointer to an x-only public key to verify with */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1zkp_v0_8_0_schnorrsig_verify( - const rustsecp256k1zkp_v0_8_0_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int rustsecp256k1_v0_11_schnorrsig_verify( + const rustsecp256k1_v0_11_context *ctx, const unsigned char *sig64, const unsigned char *msg, size_t msglen, - const rustsecp256k1zkp_v0_8_0_xonly_pubkey *pubkey + const rustsecp256k1_v0_11_xonly_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5); #ifdef __cplusplus diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/libsecp256k1.pc.in b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/libsecp256k1.pc.in similarity index 92% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/libsecp256k1.pc.in rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/libsecp256k1.pc.in index 694e98ee..0fb6f48a 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/libsecp256k1.pc.in +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/libsecp256k1.pc.in @@ -9,5 +9,4 @@ URL: https://github.com/bitcoin-core/secp256k1 Version: @PACKAGE_VERSION@ Cflags: -I${includedir} Libs: -L${libdir} -lsecp256k1 -Libs.private: @SECP_LIBS@ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/gen_exhaustive_groups.sage b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/gen_exhaustive_groups.sage new file mode 100644 index 00000000..14104111 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/gen_exhaustive_groups.sage @@ -0,0 +1,156 @@ +load("rustsecp256k1_v0_11_params.sage") + +MAX_ORDER = 1000 + +# Set of (curve) orders we have encountered so far. +orders_done = set() + +# Map from (subgroup) orders to [b, int(gen.x), int(gen.y), gen, lambda] for those subgroups. +solutions = {} + +# Iterate over curves of the form y^2 = x^3 + B. +for b in range(1, P): + # There are only 6 curves (up to isomorphism) of the form y^2 = x^3 + B. Stop once we have tried all. + if len(orders_done) == 6: + break + + E = EllipticCurve(F, [0, b]) + print("Analyzing curve y^2 = x^3 + %i" % b) + n = E.order() + + # Skip curves with an order we've already tried + if n in orders_done: + print("- Isomorphic to earlier curve") + print() + continue + orders_done.add(n) + + # Skip curves isomorphic to the real secp256k1 + if n.is_pseudoprime(): + assert E.is_isomorphic(C) + print("- Isomorphic to secp256k1") + print() + continue + + print("- Finding prime subgroups") + + # Map from group_order to a set of independent generators for that order. + curve_gens = {} + + for g in E.gens(): + # Find what prime subgroups of group generated by g exist. + g_order = g.order() + for f, _ in g.order().factor(): + # Skip subgroups that have bad size. + if f < 4: + print(f" - Subgroup of size {f}: too small") + continue + if f > MAX_ORDER: + print(f" - Subgroup of size {f}: too large") + continue + + # Construct a generator for that subgroup. + gen = g * (g_order // f) + assert(gen.order() == f) + + # Add to set the minimal multiple of gen. + curve_gens.setdefault(f, set()).add(min([j*gen for j in range(1, f)])) + print(f" - Subgroup of size {f}: ok") + + for f in sorted(curve_gens.keys()): + print(f"- Constructing group of order {f}") + cbrts = sorted([int(c) for c in Integers(f)(1).nth_root(3, all=true) if c != 1]) + gens = list(curve_gens[f]) + sol_count = 0 + no_endo_count = 0 + + # Consider all non-zero linear combinations of the independent generators. + for j in range(1, f**len(gens)): + gen = sum(gens[k] * ((j // f**k) % f) for k in range(len(gens))) + assert not gen.is_zero() + assert (f*gen).is_zero() + + # Find lambda for endomorphism. Skip if none can be found. + lam = None + for l in cbrts: + if l*gen == E(BETA*gen[0], gen[1]): + lam = l + break + + if lam is None: + no_endo_count += 1 + else: + sol_count += 1 + solutions.setdefault(f, []).append((b, int(gen[0]), int(gen[1]), gen, lam)) + + print(f" - Found {sol_count} generators (plus {no_endo_count} without endomorphism)") + + print() + +def output_generator(g, name): + print(f"#define {name} SECP256K1_GE_CONST(\\") + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) + print(")") + +def output_b(b): + print(f"#define SECP256K1_B {int(b)}") + +print() +print("To be put in src/group_impl.h:") +print() +print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */") +for f in sorted(solutions.keys()): + # Use as generator/2 the one with lowest b, and lowest (x, y) generator (interpreted as non-negative integers). + b, _, _, HALF_G, lam = min(solutions[f]) + output_generator(2 * HALF_G, f"SECP256K1_G_ORDER_{f}") +print("/** Generator for secp256k1, value 'g' defined in") +print(" * \"Standards for Efficient Cryptography\" (SEC2) 2.7.1.") +print(" */") +output_generator(G, "SECP256K1_G") +print("/* These exhaustive group test orders and generators are chosen such that:") +print(" * - The field size is equal to that of secp256k1, so field code is the same.") +print(" * - The curve equation is of the form y^2=x^3+B for some small constant B.") +print(" * - The subgroup has a generator 2*P, where P.x is as small as possible.") +print(f" * - The subgroup has size less than {MAX_ORDER} to permit exhaustive testing.") +print(" * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y).") +print(" */") +print("#if defined(EXHAUSTIVE_TEST_ORDER)") +first = True +for f in sorted(solutions.keys()): + b, _, _, _, lam = min(solutions[f]) + print(f"# {'if' if first else 'elif'} EXHAUSTIVE_TEST_ORDER == {f}") + first = False + print() + print(f"static const rustsecp256k1_v0_11_ge rustsecp256k1_v0_11_ge_const_g = SECP256K1_G_ORDER_{f};") + output_b(b) + print() +print("# else") +print("# error No known generator for the specified exhaustive test group order.") +print("# endif") +print("#else") +print() +print("static const rustsecp256k1_v0_11_ge rustsecp256k1_v0_11_ge_const_g = SECP256K1_G;") +output_b(7) +print() +print("#endif") +print("/* End of section generated by sage/gen_exhaustive_groups.sage. */") + + +print() +print() +print("To be put in src/scalar_impl.h:") +print() +print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */") +first = True +for f in sorted(solutions.keys()): + _, _, _, _, lam = min(solutions[f]) + print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f)) + first = False + print("# define EXHAUSTIVE_TEST_LAMBDA %i" % lam) +print("# else") +print("# error No known lambda for the specified exhaustive test group order.") +print("# endif") +print("/* End of section generated by sage/gen_exhaustive_groups.sage. */") diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/gen_split_lambda_constants.sage b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/gen_split_lambda_constants.sage similarity index 82% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/gen_split_lambda_constants.sage rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/gen_split_lambda_constants.sage index 5ef1b877..65cb8741 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/gen_split_lambda_constants.sage +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/gen_split_lambda_constants.sage @@ -1,9 +1,9 @@ -""" Generates the constants used in rustsecp256k1zkp_v0_8_0_scalar_split_lambda. +""" Generates the constants used in rustsecp256k1_v0_11_scalar_split_lambda. -See the comments for rustsecp256k1zkp_v0_8_0_scalar_split_lambda in src/scalar_impl.h for detailed explanations. +See the comments for rustsecp256k1_v0_11_scalar_split_lambda in src/scalar_impl.h for detailed explanations. """ -load("rustsecp256k1zkp_v0_8_0_params.sage") +load("rustsecp256k1_v0_11_params.sage") def inf_norm(v): """Returns the infinity norm of a vector.""" @@ -24,17 +24,17 @@ def gauss_reduction(i1, i2): v2[1] -= m*v1[1] def find_split_constants_gauss(): - """Find constants for rustsecp256k1zkp_v0_8_0_scalar_split_lamdba using gauss reduction.""" + """Find constants for rustsecp256k1_v0_11_scalar_split_lamdba using gauss reduction.""" (v11, v12), (v21, v22) = gauss_reduction([0, N], [1, int(LAMBDA)]) - # We use related vectors in rustsecp256k1zkp_v0_8_0_scalar_split_lambda. + # We use related vectors in rustsecp256k1_v0_11_scalar_split_lambda. A1, B1 = -v21, -v11 A2, B2 = v22, -v21 return A1, B1, A2, B2 def find_split_constants_explicit_tof(): - """Find constants for rustsecp256k1zkp_v0_8_0_scalar_split_lamdba using the trace of Frobenius. + """Find constants for rustsecp256k1_v0_11_scalar_split_lamdba using the trace of Frobenius. See Benjamin Smith: "Easy scalar decompositions for efficient scalar multiplication on elliptic curves and genus 2 Jacobians" (https://eprint.iacr.org/2013/672), Example 2 @@ -51,7 +51,7 @@ def find_split_constants_explicit_tof(): A2 = Integer((t + c)/2 - 1) B2 = Integer(1 - (t - c)/2) - # We use a negated b values in rustsecp256k1zkp_v0_8_0_scalar_split_lambda. + # We use a negated b values in rustsecp256k1_v0_11_scalar_split_lambda. B1, B2 = -B1, -B2 return A1, B1, A2, B2 @@ -90,7 +90,7 @@ def rnddiv2(v): return v >> 1 def scalar_lambda_split(k): - """Equivalent to rustsecp256k1zkp_v0_8_0_scalar_lambda_split().""" + """Equivalent to rustsecp256k1_v0_11_scalar_lambda_split().""" c1 = rnddiv2((k * G1) >> 383) c2 = rnddiv2((k * G2) >> 383) c1 = (c1 * -B1) % N diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/group_prover.sage b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/group_prover.sage similarity index 99% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/group_prover.sage rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/group_prover.sage index 9305c215..bb092953 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/group_prover.sage +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/group_prover.sage @@ -198,7 +198,7 @@ def normalize_factor(p): (8) * (-bx + ax)^3 ``` """ - # Assert p is not 0 and that its non-zero coeffients are coprime. + # Assert p is not 0 and that its non-zero coefficients are coprime. # (We could just work with the primitive part p/p.content() but we want to be # aware if factor() does not return a primitive part in future sage versions.) assert p.content() == 1 diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/prove_group_implementations.sage b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/prove_group_implementations.sage similarity index 68% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/prove_group_implementations.sage rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/prove_group_implementations.sage index 5f12a318..ff2275e1 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/prove_group_implementations.sage +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/prove_group_implementations.sage @@ -5,8 +5,8 @@ import sys load("group_prover.sage") load("weierstrass_prover.sage") -def formula_rustsecp256k1zkp_v0_8_0_gej_double_var(a): - """libsecp256k1's rustsecp256k1zkp_v0_8_0_gej_double_var, used by various addition functions""" +def formula_rustsecp256k1_v0_11_gej_double_var(a): + """libsecp256k1's rustsecp256k1_v0_11_gej_double_var, used by various addition functions""" rz = a.Z * a.Y s = a.Y^2 l = a.X^2 @@ -24,8 +24,8 @@ def formula_rustsecp256k1zkp_v0_8_0_gej_double_var(a): ry = -ry return jacobianpoint(rx, ry, rz) -def formula_rustsecp256k1zkp_v0_8_0_gej_add_var(branch, a, b): - """libsecp256k1's rustsecp256k1zkp_v0_8_0_gej_add_var""" +def formula_rustsecp256k1_v0_11_gej_add_var(branch, a, b): + """libsecp256k1's rustsecp256k1_v0_11_gej_add_var""" if branch == 0: return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b) if branch == 1: @@ -40,34 +40,31 @@ def formula_rustsecp256k1zkp_v0_8_0_gej_add_var(branch, a, b): s2 = s2 * a.Z h = -u1 h = h + u2 - i = -s1 - i = i + s2 + i = -s2 + i = i + s1 if branch == 2: - r = formula_rustsecp256k1zkp_v0_8_0_gej_double_var(a) + r = formula_rustsecp256k1_v0_11_gej_double_var(a) return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r) if branch == 3: return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity()) - i2 = i^2 + t = h * b.Z + rz = a.Z * t h2 = h^2 + h2 = -h2 h3 = h2 * h - h = h * b.Z - rz = a.Z * h t = u1 * h2 - rx = t - rx = rx * 2 + rx = i^2 rx = rx + h3 - rx = -rx - rx = rx + i2 - ry = -rx - ry = ry + t - ry = ry * i + rx = rx + t + rx = rx + t + t = t + rx + ry = t * i h3 = h3 * s1 - h3 = -h3 ry = ry + h3 return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) -def formula_rustsecp256k1zkp_v0_8_0_gej_add_ge_var(branch, a, b): - """libsecp256k1's rustsecp256k1zkp_v0_8_0_gej_add_ge_var, which assume bz==1""" +def formula_rustsecp256k1_v0_11_gej_add_ge_var(branch, a, b): + """libsecp256k1's rustsecp256k1_v0_11_gej_add_ge_var, which assume bz==1""" if branch == 0: return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b) if branch == 1: @@ -80,43 +77,41 @@ def formula_rustsecp256k1zkp_v0_8_0_gej_add_ge_var(branch, a, b): s2 = s2 * a.Z h = -u1 h = h + u2 - i = -s1 - i = i + s2 + i = -s2 + i = i + s1 if (branch == 2): - r = formula_rustsecp256k1zkp_v0_8_0_gej_double_var(a) + r = formula_rustsecp256k1_v0_11_gej_double_var(a) return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) if (branch == 3): return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) - i2 = i^2 - h2 = h^2 - h3 = h * h2 rz = a.Z * h + h2 = h^2 + h2 = -h2 + h3 = h2 * h t = u1 * h2 - rx = t - rx = rx * 2 + rx = i^2 rx = rx + h3 - rx = -rx - rx = rx + i2 - ry = -rx - ry = ry + t - ry = ry * i + rx = rx + t + rx = rx + t + t = t + rx + ry = t * i h3 = h3 * s1 - h3 = -h3 ry = ry + h3 return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) -def formula_rustsecp256k1zkp_v0_8_0_gej_add_zinv_var(branch, a, b): - """libsecp256k1's rustsecp256k1zkp_v0_8_0_gej_add_zinv_var""" +def formula_rustsecp256k1_v0_11_gej_add_zinv_var(branch, a, b): + """libsecp256k1's rustsecp256k1_v0_11_gej_add_zinv_var""" bzinv = b.Z^(-1) if branch == 0: - return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a) - if branch == 1: + rinf = b.Infinity bzinv2 = bzinv^2 bzinv3 = bzinv2 * bzinv rx = b.X * bzinv2 ry = b.Y * bzinv3 rz = 1 - return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz)) + return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz, rinf)) + if branch == 1: + return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) azz = a.Z * bzinv z12 = azz^2 u1 = a.X @@ -126,38 +121,34 @@ def formula_rustsecp256k1zkp_v0_8_0_gej_add_zinv_var(branch, a, b): s2 = s2 * azz h = -u1 h = h + u2 - i = -s1 - i = i + s2 + i = -s2 + i = i + s1 if branch == 2: - r = formula_rustsecp256k1zkp_v0_8_0_gej_double_var(a) + r = formula_rustsecp256k1_v0_11_gej_double_var(a) return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) if branch == 3: return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) - i2 = i^2 + rz = a.Z * h h2 = h^2 - h3 = h * h2 - rz = a.Z - rz = rz * h + h2 = -h2 + h3 = h2 * h t = u1 * h2 - rx = t - rx = rx * 2 + rx = i^2 rx = rx + h3 - rx = -rx - rx = rx + i2 - ry = -rx - ry = ry + t - ry = ry * i + rx = rx + t + rx = rx + t + t = t + rx + ry = t * i h3 = h3 * s1 - h3 = -h3 ry = ry + h3 return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) -def formula_rustsecp256k1zkp_v0_8_0_gej_add_ge(branch, a, b): - """libsecp256k1's rustsecp256k1zkp_v0_8_0_gej_add_ge""" +def formula_rustsecp256k1_v0_11_gej_add_ge(branch, a, b): + """libsecp256k1's rustsecp256k1_v0_11_gej_add_ge""" zeroes = {} nonzeroes = {} a_infinity = False - if (branch & 4) != 0: + if (branch & 2) != 0: nonzeroes.update({a.Infinity : 'a_infinite'}) a_infinity = True else: @@ -176,15 +167,11 @@ def formula_rustsecp256k1zkp_v0_8_0_gej_add_ge(branch, a, b): m_alt = -u2 tt = u1 * m_alt rr = rr + tt - degenerate = (branch & 3) == 3 - if (branch & 1) != 0: + degenerate = (branch & 1) != 0 + if degenerate: zeroes.update({m : 'm_zero'}) else: nonzeroes.update({m : 'm_nonzero'}) - if (branch & 2) != 0: - zeroes.update({rr : 'rr_zero'}) - else: - nonzeroes.update({rr : 'rr_nonzero'}) rr_alt = s1 rr_alt = rr_alt * 2 m_alt = m_alt + u1 @@ -199,13 +186,6 @@ def formula_rustsecp256k1zkp_v0_8_0_gej_add_ge(branch, a, b): n = m t = rr_alt^2 rz = a.Z * m_alt - infinity = False - if (branch & 8) != 0: - if not a_infinity: - infinity = True - zeroes.update({rz : 'r.z=0'}) - else: - nonzeroes.update({rz : 'r.z!=0'}) t = t + q rx = t t = t * 2 @@ -218,12 +198,15 @@ def formula_rustsecp256k1zkp_v0_8_0_gej_add_ge(branch, a, b): rx = b.X ry = b.Y rz = 1 - if infinity: + if (branch & 4) != 0: + zeroes.update({rz : 'r.z = 0'}) return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity()) + else: + nonzeroes.update({rz : 'r.z != 0'}) return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz)) -def formula_rustsecp256k1zkp_v0_8_0_gej_add_ge_old(branch, a, b): - """libsecp256k1's old rustsecp256k1zkp_v0_8_0_gej_add_ge, which fails when ay+by=0 but ax!=bx""" +def formula_rustsecp256k1_v0_11_gej_add_ge_old(branch, a, b): + """libsecp256k1's old rustsecp256k1_v0_11_gej_add_ge, which fails when ay+by=0 but ax!=bx""" a_infinity = (branch & 1) != 0 zero = {} nonzero = {} @@ -286,17 +269,17 @@ def formula_rustsecp256k1zkp_v0_8_0_gej_add_ge_old(branch, a, b): if __name__ == "__main__": success = True - success = success & check_symbolic_jacobian_weierstrass("rustsecp256k1zkp_v0_8_0_gej_add_var", 0, 7, 5, formula_rustsecp256k1zkp_v0_8_0_gej_add_var) - success = success & check_symbolic_jacobian_weierstrass("rustsecp256k1zkp_v0_8_0_gej_add_ge_var", 0, 7, 5, formula_rustsecp256k1zkp_v0_8_0_gej_add_ge_var) - success = success & check_symbolic_jacobian_weierstrass("rustsecp256k1zkp_v0_8_0_gej_add_zinv_var", 0, 7, 5, formula_rustsecp256k1zkp_v0_8_0_gej_add_zinv_var) - success = success & check_symbolic_jacobian_weierstrass("rustsecp256k1zkp_v0_8_0_gej_add_ge", 0, 7, 16, formula_rustsecp256k1zkp_v0_8_0_gej_add_ge) - success = success & (not check_symbolic_jacobian_weierstrass("rustsecp256k1zkp_v0_8_0_gej_add_ge_old [should fail]", 0, 7, 4, formula_rustsecp256k1zkp_v0_8_0_gej_add_ge_old)) + success = success & check_symbolic_jacobian_weierstrass("rustsecp256k1_v0_11_gej_add_var", 0, 7, 5, formula_rustsecp256k1_v0_11_gej_add_var) + success = success & check_symbolic_jacobian_weierstrass("rustsecp256k1_v0_11_gej_add_ge_var", 0, 7, 5, formula_rustsecp256k1_v0_11_gej_add_ge_var) + success = success & check_symbolic_jacobian_weierstrass("rustsecp256k1_v0_11_gej_add_zinv_var", 0, 7, 5, formula_rustsecp256k1_v0_11_gej_add_zinv_var) + success = success & check_symbolic_jacobian_weierstrass("rustsecp256k1_v0_11_gej_add_ge", 0, 7, 8, formula_rustsecp256k1_v0_11_gej_add_ge) + success = success & (not check_symbolic_jacobian_weierstrass("rustsecp256k1_v0_11_gej_add_ge_old [should fail]", 0, 7, 4, formula_rustsecp256k1_v0_11_gej_add_ge_old)) if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive": - success = success & check_exhaustive_jacobian_weierstrass("rustsecp256k1zkp_v0_8_0_gej_add_var", 0, 7, 5, formula_rustsecp256k1zkp_v0_8_0_gej_add_var, 43) - success = success & check_exhaustive_jacobian_weierstrass("rustsecp256k1zkp_v0_8_0_gej_add_ge_var", 0, 7, 5, formula_rustsecp256k1zkp_v0_8_0_gej_add_ge_var, 43) - success = success & check_exhaustive_jacobian_weierstrass("rustsecp256k1zkp_v0_8_0_gej_add_zinv_var", 0, 7, 5, formula_rustsecp256k1zkp_v0_8_0_gej_add_zinv_var, 43) - success = success & check_exhaustive_jacobian_weierstrass("rustsecp256k1zkp_v0_8_0_gej_add_ge", 0, 7, 16, formula_rustsecp256k1zkp_v0_8_0_gej_add_ge, 43) - success = success & (not check_exhaustive_jacobian_weierstrass("rustsecp256k1zkp_v0_8_0_gej_add_ge_old [should fail]", 0, 7, 4, formula_rustsecp256k1zkp_v0_8_0_gej_add_ge_old, 43)) + success = success & check_exhaustive_jacobian_weierstrass("rustsecp256k1_v0_11_gej_add_var", 0, 7, 5, formula_rustsecp256k1_v0_11_gej_add_var, 43) + success = success & check_exhaustive_jacobian_weierstrass("rustsecp256k1_v0_11_gej_add_ge_var", 0, 7, 5, formula_rustsecp256k1_v0_11_gej_add_ge_var, 43) + success = success & check_exhaustive_jacobian_weierstrass("rustsecp256k1_v0_11_gej_add_zinv_var", 0, 7, 5, formula_rustsecp256k1_v0_11_gej_add_zinv_var, 43) + success = success & check_exhaustive_jacobian_weierstrass("rustsecp256k1_v0_11_gej_add_ge", 0, 7, 8, formula_rustsecp256k1_v0_11_gej_add_ge, 43) + success = success & (not check_exhaustive_jacobian_weierstrass("rustsecp256k1_v0_11_gej_add_ge_old [should fail]", 0, 7, 4, formula_rustsecp256k1_v0_11_gej_add_ge_old, 43)) sys.exit(int(not success)) diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/secp256k1_params.sage b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/secp256k1_params.sage similarity index 100% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/secp256k1_params.sage rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/secp256k1_params.sage diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/weierstrass_prover.sage b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/weierstrass_prover.sage similarity index 100% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/sage/weierstrass_prover.sage rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/sage/weierstrass_prover.sage diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/CMakeLists.txt b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/CMakeLists.txt new file mode 100644 index 00000000..bc2e04ba --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/CMakeLists.txt @@ -0,0 +1,176 @@ +# Must be included before CMAKE_INSTALL_INCLUDEDIR is used. +include(GNUInstallDirs) + +add_library(rustsecp256k1_v0_11_precomputed OBJECT EXCLUDE_FROM_ALL + precomputed_ecmult.c + precomputed_ecmult_gen.c +) + +# Add objects explicitly rather than linking to the object libs to keep them +# from being exported. +add_library(secp256k1 secp256k1.c $) + +add_library(rustsecp256k1_v0_11_asm INTERFACE) +if(SECP256K1_ASM STREQUAL "arm32") + add_library(rustsecp256k1_v0_11_asm_arm OBJECT EXCLUDE_FROM_ALL) + target_sources(rustsecp256k1_v0_11_asm_arm PUBLIC + asm/field_10x26_arm.s + ) + target_sources(secp256k1 PRIVATE $) + target_link_libraries(rustsecp256k1_v0_11_asm INTERFACE rustsecp256k1_v0_11_asm_arm) +endif() + +if(WIN32) + # Define our export symbol only for shared libs. + set_target_properties(secp256k1 PROPERTIES DEFINE_SYMBOL SECP256K1_DLL_EXPORT) + target_compile_definitions(secp256k1 INTERFACE $<$>:SECP256K1_STATIC>) +endif() + +# Object libs don't know if they're being built for a shared or static lib. +# Grab the PIC property from secp256k1 which knows. +get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE) +set_target_properties(rustsecp256k1_v0_11_precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic}) + +target_include_directories(secp256k1 INTERFACE + # Add the include path for parent projects so that they don't have to manually add it. + $>:${PROJECT_SOURCE_DIR}/include>> + $ +) + +# This emulates Libtool to make sure Libtool and CMake agree on the ABI version, +# see below "Calculate the version variables" in build-aux/ltmain.sh. +math(EXPR ${PROJECT_NAME}_soversion "${${PROJECT_NAME}_LIB_VERSION_CURRENT} - ${${PROJECT_NAME}_LIB_VERSION_AGE}") +set_target_properties(secp256k1 PROPERTIES + SOVERSION ${${PROJECT_NAME}_soversion} +) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set_target_properties(secp256k1 PROPERTIES + VERSION ${${PROJECT_NAME}_soversion}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION} + ) +elseif(APPLE) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.17) + math(EXPR ${PROJECT_NAME}_compatibility_version "${${PROJECT_NAME}_LIB_VERSION_CURRENT} + 1") + set_target_properties(secp256k1 PROPERTIES + MACHO_COMPATIBILITY_VERSION ${${PROJECT_NAME}_compatibility_version} + MACHO_CURRENT_VERSION ${${PROJECT_NAME}_compatibility_version}.${${PROJECT_NAME}_LIB_VERSION_REVISION} + ) + unset(${PROJECT_NAME}_compatibility_version) + elseif(BUILD_SHARED_LIBS) + message(WARNING + "The 'compatibility version' and 'current version' values of the DYLIB " + "will diverge from the values set by the GNU Libtool. To ensure " + "compatibility, it is recommended to upgrade CMake to at least version 3.17." + ) + endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(${PROJECT_NAME}_windows "secp256k1") + if(MSVC) + set(${PROJECT_NAME}_windows "${PROJECT_NAME}") + endif() + set_target_properties(secp256k1 PROPERTIES + ARCHIVE_OUTPUT_NAME "${${PROJECT_NAME}_windows}" + RUNTIME_OUTPUT_NAME "${${PROJECT_NAME}_windows}-${${PROJECT_NAME}_soversion}" + ) + unset(${PROJECT_NAME}_windows) +endif() +unset(${PROJECT_NAME}_soversion) + +if(SECP256K1_BUILD_BENCHMARK) + add_executable(bench bench.c) + target_link_libraries(bench secp256k1) + add_executable(bench_internal bench_internal.c) + target_link_libraries(bench_internal rustsecp256k1_v0_11_precomputed rustsecp256k1_v0_11_asm) + add_executable(bench_ecmult bench_ecmult.c) + target_link_libraries(bench_ecmult rustsecp256k1_v0_11_precomputed rustsecp256k1_v0_11_asm) +endif() + +if(SECP256K1_BUILD_TESTS) + add_executable(noverify_tests tests.c) + target_link_libraries(noverify_tests rustsecp256k1_v0_11_precomputed rustsecp256k1_v0_11_asm) + add_test(NAME rustsecp256k1_v0_11_noverify_tests COMMAND noverify_tests) + if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage") + add_executable(tests tests.c) + target_compile_definitions(tests PRIVATE VERIFY) + target_link_libraries(tests rustsecp256k1_v0_11_precomputed rustsecp256k1_v0_11_asm) + add_test(NAME rustsecp256k1_v0_11_tests COMMAND tests) + endif() +endif() + +if(SECP256K1_BUILD_EXHAUSTIVE_TESTS) + # Note: do not include rustsecp256k1_v0_11_precomputed in exhaustive_tests (it uses runtime-generated tables). + add_executable(exhaustive_tests tests_exhaustive.c) + target_link_libraries(exhaustive_tests rustsecp256k1_v0_11_asm) + target_compile_definitions(exhaustive_tests PRIVATE $<$>:VERIFY>) + add_test(NAME rustsecp256k1_v0_11_exhaustive_tests COMMAND exhaustive_tests) +endif() + +if(SECP256K1_BUILD_CTIME_TESTS) + add_executable(ctime_tests ctime_tests.c) + target_link_libraries(ctime_tests secp256k1) +endif() + +if(SECP256K1_INSTALL) + install(TARGETS secp256k1 + EXPORT ${PROJECT_NAME}-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + set(${PROJECT_NAME}_headers + "${PROJECT_SOURCE_DIR}/include/secp256k1.h" + "${PROJECT_SOURCE_DIR}/include/rustsecp256k1_v0_11_preallocated.h" + ) + if(SECP256K1_ENABLE_MODULE_ECDH) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/rustsecp256k1_v0_11_ecdh.h") + endif() + if(SECP256K1_ENABLE_MODULE_RECOVERY) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/rustsecp256k1_v0_11_recovery.h") + endif() + if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/rustsecp256k1_v0_11_extrakeys.h") + endif() + if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/rustsecp256k1_v0_11_schnorrsig.h") + endif() + if(SECP256K1_ENABLE_MODULE_MUSIG) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/rustsecp256k1_v0_11_musig.h") + endif() + if(SECP256K1_ENABLE_MODULE_ELLSWIFT) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/rustsecp256k1_v0_11_ellswift.h") + endif() + install(FILES ${${PROJECT_NAME}_headers} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + install(EXPORT ${PROJECT_NAME}-targets + FILE ${PROJECT_NAME}-targets.cmake + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + ) + + include(CMakePackageConfigHelpers) + configure_package_config_file( + ${PROJECT_SOURCE_DIR}/cmake/config.cmake.in + ${PROJECT_NAME}-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + NO_SET_AND_CHECK_MACRO + ) + write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake + COMPATIBILITY SameMinorVersion + ) + + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + ) + + include(GeneratePkgConfigFile) + generate_pkg_config_file(${PROJECT_SOURCE_DIR}/libsecp256k1.pc.in) + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig + ) +endif() diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/asm/field_10x26_arm.s b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/asm/field_10x26_arm.s similarity index 98% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/asm/field_10x26_arm.s rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/asm/field_10x26_arm.s index c80043e8..fb79bf90 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/asm/field_10x26_arm.s +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/asm/field_10x26_arm.s @@ -27,8 +27,9 @@ Note: .set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff .align 2 - .global rustsecp256k1zkp_v0_8_0_fe_mul_inner - .type rustsecp256k1zkp_v0_8_0_fe_mul_inner, %function + .global rustsecp256k1_v0_11_fe_mul_inner + .type rustsecp256k1_v0_11_fe_mul_inner, %function + .hidden rustsecp256k1_v0_11_fe_mul_inner @ Arguments: @ r0 r Restrict: can overlap with a, not with b @ r1 a @@ -36,7 +37,7 @@ Note: @ Stack (total 4+10*4 = 44) @ sp + #0 saved 'r' pointer @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 -rustsecp256k1zkp_v0_8_0_fe_mul_inner: +rustsecp256k1_v0_11_fe_mul_inner: stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} sub sp, sp, #48 @ frame=44 + alignment str r0, [sp, #0] @ save result address, we need it only at the end @@ -511,18 +512,19 @@ rustsecp256k1zkp_v0_8_0_fe_mul_inner: add sp, sp, #48 ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} - .size rustsecp256k1zkp_v0_8_0_fe_mul_inner, .-rustsecp256k1zkp_v0_8_0_fe_mul_inner + .size rustsecp256k1_v0_11_fe_mul_inner, .-rustsecp256k1_v0_11_fe_mul_inner .align 2 - .global rustsecp256k1zkp_v0_8_0_fe_sqr_inner - .type rustsecp256k1zkp_v0_8_0_fe_sqr_inner, %function + .global rustsecp256k1_v0_11_fe_sqr_inner + .type rustsecp256k1_v0_11_fe_sqr_inner, %function + .hidden rustsecp256k1_v0_11_fe_sqr_inner @ Arguments: @ r0 r Can overlap with a @ r1 a @ Stack (total 4+10*4 = 44) @ sp + #0 saved 'r' pointer @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 -rustsecp256k1zkp_v0_8_0_fe_sqr_inner: +rustsecp256k1_v0_11_fe_sqr_inner: stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} sub sp, sp, #48 @ frame=44 + alignment str r0, [sp, #0] @ save result address, we need it only at the end @@ -909,5 +911,6 @@ rustsecp256k1zkp_v0_8_0_fe_sqr_inner: add sp, sp, #48 ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} - .size rustsecp256k1zkp_v0_8_0_fe_sqr_inner, .-rustsecp256k1zkp_v0_8_0_fe_sqr_inner + .size rustsecp256k1_v0_11_fe_sqr_inner, .-rustsecp256k1_v0_11_fe_sqr_inner + .section .note.GNU-stack,"",%progbits diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/assumptions.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/assumptions.h new file mode 100644 index 00000000..e29b7d55 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/assumptions.h @@ -0,0 +1,87 @@ +/*********************************************************************** + * Copyright (c) 2020 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ASSUMPTIONS_H +#define SECP256K1_ASSUMPTIONS_H + +#include + +#include "util.h" +#if defined(SECP256K1_INT128_NATIVE) +#include "int128_native.h" +#endif + +/* This library, like most software, relies on a number of compiler implementation defined (but not undefined) + behaviours. Although the behaviours we require are essentially universal we test them specifically here to + reduce the odds of experiencing an unwelcome surprise. +*/ + +#if defined(__has_attribute) +# if __has_attribute(__unavailable__) +__attribute__((__unavailable__("Don't call this function. It only exists because STATIC_ASSERT cannot be used outside a function."))) +# endif +#endif +static void rustsecp256k1_v0_11_assumption_checker(void) { + /* Bytes are 8 bits. */ + STATIC_ASSERT(CHAR_BIT == 8); + + /* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32 + without signed overflow, which would be undefined behaviour. */ + STATIC_ASSERT(UINT_MAX <= UINT32_MAX); + + /* Conversions from unsigned to signed outside of the bounds of the signed type are + implementation-defined. Verify that they function as reinterpreting the lower + bits of the input in two's complement notation. Do this for conversions: + - from uint(N)_t to int(N)_t with negative result + - from uint(2N)_t to int(N)_t with negative result + - from int(2N)_t to int(N)_t with negative result + - from int(2N)_t to int(N)_t with positive result */ + + /* To int8_t. */ + STATIC_ASSERT(((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55)); + STATIC_ASSERT((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33); + STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF); + STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34); + + /* To int16_t. */ + STATIC_ASSERT((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322); + STATIC_ASSERT((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C); + STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4); + STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678); + + /* To int32_t. */ + STATIC_ASSERT((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B); + STATIC_ASSERT((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE); + STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8); + STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789); + + /* To int64_t. */ + STATIC_ASSERT((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL); +#if defined(SECP256K1_INT128_NATIVE) + STATIC_ASSERT((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL); + STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL); + STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL); + + /* To int128_t. */ + STATIC_ASSERT((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL)); +#endif + + /* Right shift on negative signed values is implementation defined. Verify that it + acts as a right shift in two's complement with sign extension (i.e duplicating + the top bit into newly added bits). */ + STATIC_ASSERT((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA); + STATIC_ASSERT((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A); + STATIC_ASSERT((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48); + STATIC_ASSERT((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL); +#if defined(SECP256K1_INT128_NATIVE) + STATIC_ASSERT((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)); +#endif + + /* This function is not supposed to be called. */ + VERIFY_CHECK(0); +} + +#endif /* SECP256K1_ASSUMPTIONS_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/bench.c similarity index 59% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench.c rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/bench.c index 42fb1309..0b2c6bb1 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench.c +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/bench.c @@ -11,7 +11,7 @@ #include "util.h" #include "bench.h" -void help(int default_iters) { +static void help(int default_iters) { printf("Benchmarks the following algorithms:\n"); printf(" - ECDSA signing/verification\n"); @@ -38,6 +38,8 @@ void help(int default_iters) { printf(" ecdsa : all ECDSA algorithms--sign, verify, recovery (if enabled)\n"); printf(" ecdsa_sign : ECDSA siging algorithm\n"); printf(" ecdsa_verify : ECDSA verification algorithm\n"); + printf(" ec : all EC public key algorithms (keygen)\n"); + printf(" ec_keygen : EC public key generation\n"); #ifdef ENABLE_MODULE_RECOVERY printf(" ecdsa_recover : ECDSA public key recovery algorithm\n"); @@ -53,47 +55,49 @@ void help(int default_iters) { printf(" schnorrsig_verify : Schnorr verification algorithm\n"); #endif +#ifdef ENABLE_MODULE_ELLSWIFT + printf(" ellswift : all ElligatorSwift benchmarks (encode, decode, keygen, ecdh)\n"); + printf(" ellswift_encode : ElligatorSwift encoding\n"); + printf(" ellswift_decode : ElligatorSwift decoding\n"); + printf(" ellswift_keygen : ElligatorSwift key generation\n"); + printf(" ellswift_ecdh : ECDH on ElligatorSwift keys\n"); +#endif + printf("\n"); } typedef struct { - rustsecp256k1zkp_v0_8_0_context *ctx; + rustsecp256k1_v0_11_context *ctx; unsigned char msg[32]; unsigned char key[32]; unsigned char sig[72]; size_t siglen; unsigned char pubkey[33]; size_t pubkeylen; -} bench_verify_data; +} bench_data; static void bench_verify(void* arg, int iters) { int i; - bench_verify_data* data = (bench_verify_data*)arg; + bench_data* data = (bench_data*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig; + rustsecp256k1_v0_11_pubkey pubkey; + rustsecp256k1_v0_11_ecdsa_signature sig; data->sig[data->siglen - 1] ^= (i & 0xFF); data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0)); data->sig[data->siglen - 1] ^= (i & 0xFF); data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); } } -typedef struct { - rustsecp256k1zkp_v0_8_0_context* ctx; - unsigned char msg[32]; - unsigned char key[32]; -} bench_sign_data; - static void bench_sign_setup(void* arg) { int i; - bench_sign_data *data = (bench_sign_data*)arg; + bench_data *data = (bench_data*)arg; for (i = 0; i < 32; i++) { data->msg[i] = i + 1; @@ -105,15 +109,15 @@ static void bench_sign_setup(void* arg) { static void bench_sign_run(void* arg, int iters) { int i; - bench_sign_data *data = (bench_sign_data*)arg; + bench_data *data = (bench_data*)arg; unsigned char sig[74]; for (i = 0; i < iters; i++) { size_t siglen = 74; int j; - rustsecp256k1zkp_v0_8_0_ecdsa_signature signature; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature)); + rustsecp256k1_v0_11_ecdsa_signature signature; + CHECK(rustsecp256k1_v0_11_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL)); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature)); for (j = 0; j < 32; j++) { data->msg[j] = sig[j]; data->key[j] = sig[j + 32]; @@ -121,23 +125,51 @@ static void bench_sign_run(void* arg, int iters) { } } +static void bench_keygen_setup(void* arg) { + int i; + bench_data *data = (bench_data*)arg; + + for (i = 0; i < 32; i++) { + data->key[i] = i + 65; + } +} + +static void bench_keygen_run(void *arg, int iters) { + int i; + bench_data *data = (bench_data*)arg; + + for (i = 0; i < iters; i++) { + unsigned char pub33[33]; + size_t len = 33; + rustsecp256k1_v0_11_pubkey pubkey; + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(data->ctx, &pubkey, data->key)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(data->ctx, pub33, &len, &pubkey, SECP256K1_EC_COMPRESSED)); + memcpy(data->key, pub33 + 1, 32); + } +} + + #ifdef ENABLE_MODULE_ECDH -#include "modules/ecdh/bench_impl.h" +# include "modules/ecdh/bench_impl.h" #endif #ifdef ENABLE_MODULE_RECOVERY -#include "modules/recovery/bench_impl.h" +# include "modules/recovery/bench_impl.h" #endif #ifdef ENABLE_MODULE_SCHNORRSIG -#include "modules/schnorrsig/bench_impl.h" +# include "modules/schnorrsig/bench_impl.h" +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT +# include "modules/ellswift/bench_impl.h" #endif int main(int argc, char** argv) { int i; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig; - bench_verify_data data; + rustsecp256k1_v0_11_pubkey pubkey; + rustsecp256k1_v0_11_ecdsa_signature sig; + bench_data data; int d = argc == 1; int default_iters = 20000; @@ -145,7 +177,9 @@ int main(int argc, char** argv) { /* Check for invalid user arguments */ char* valid_args[] = {"ecdsa", "verify", "ecdsa_verify", "sign", "ecdsa_sign", "ecdh", "recover", - "ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign"}; + "ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign", "ec", + "keygen", "ec_keygen", "ellswift", "encode", "ellswift_encode", "decode", + "ellswift_decode", "ellswift_keygen", "ellswift_ecdh"}; size_t valid_args_size = sizeof(valid_args)/sizeof(valid_args[0]); int invalid_args = have_invalid_args(argc, argv, valid_args, valid_args_size); @@ -164,7 +198,7 @@ int main(int argc, char** argv) { /* Check if the user tries to benchmark optional module without building it */ #ifndef ENABLE_MODULE_ECDH - if (have_flag(argc, argv, "ecdh")) { + if (have_flag(argc, argv, "ecdh")) { fprintf(stderr, "./bench: ECDH module not enabled.\n"); fprintf(stderr, "Use ./configure --enable-module-ecdh.\n\n"); return 1; @@ -172,7 +206,7 @@ int main(int argc, char** argv) { #endif #ifndef ENABLE_MODULE_RECOVERY - if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) { + if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) { fprintf(stderr, "./bench: Public key recovery module not enabled.\n"); fprintf(stderr, "Use ./configure --enable-module-recovery.\n\n"); return 1; @@ -180,15 +214,25 @@ int main(int argc, char** argv) { #endif #ifndef ENABLE_MODULE_SCHNORRSIG - if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) { + if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) { fprintf(stderr, "./bench: Schnorr signatures module not enabled.\n"); fprintf(stderr, "Use ./configure --enable-module-schnorrsig.\n\n"); return 1; } #endif - /* ECDSA verification benchmark */ - data.ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); +#ifndef ENABLE_MODULE_ELLSWIFT + if (have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ellswift_encode") || have_flag(argc, argv, "ellswift_decode") || + have_flag(argc, argv, "encode") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_keygen") || + have_flag(argc, argv, "ellswift_ecdh")) { + fprintf(stderr, "./bench: ElligatorSwift module not enabled.\n"); + fprintf(stderr, "Use ./configure --enable-module-ellswift.\n\n"); + return 1; + } +#endif + + /* ECDSA benchmark */ + data.ctx = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); for (i = 0; i < 32; i++) { data.msg[i] = 1 + i; @@ -197,23 +241,19 @@ int main(int argc, char** argv) { data.key[i] = 33 + i; } data.siglen = 72; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(data.ctx, &pubkey, data.key)); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL)); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(data.ctx, &pubkey, data.key)); data.pubkeylen = 33; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); print_output_table_header_row(); if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "ecdsa_verify")) run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters); - rustsecp256k1zkp_v0_8_0_context_destroy(data.ctx); - - /* ECDSA signing benchmark */ - data.ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN); - if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "ecdsa_sign")) run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "ec") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ec_keygen")) run_benchmark("ec_keygen", bench_keygen_run, bench_keygen_setup, NULL, &data, 10, iters); - rustsecp256k1zkp_v0_8_0_context_destroy(data.ctx); + rustsecp256k1_v0_11_context_destroy(data.ctx); #ifdef ENABLE_MODULE_ECDH /* ECDH benchmarks */ @@ -230,5 +270,10 @@ int main(int argc, char** argv) { run_schnorrsig_bench(iters, argc, argv); #endif +#ifdef ENABLE_MODULE_ELLSWIFT + /* ElligatorSwift benchmarks */ + run_ellswift_bench(iters, argc, argv); +#endif + return 0; } diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/bench.h similarity index 83% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/bench.h index aa275fe9..1564b1a1 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/bench.h @@ -7,22 +7,38 @@ #ifndef SECP256K1_BENCH_H #define SECP256K1_BENCH_H +#include #include #include #include -#include "sys/time.h" + +#if (defined(_MSC_VER) && _MSC_VER >= 1900) +# include +#else +# include +#endif static int64_t gettime_i64(void) { +#if (defined(_MSC_VER) && _MSC_VER >= 1900) + /* C11 way to get wallclock time */ + struct timespec tv; + if (!timespec_get(&tv, TIME_UTC)) { + fputs("timespec_get failed!", stderr); + exit(1); + } + return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL; +#else struct timeval tv; gettimeofday(&tv, NULL); return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL; +#endif } #define FP_EXP (6) #define FP_MULT (1000000LL) /* Format fixed point number. */ -void print_number(const int64_t x) { +static void print_number(const int64_t x) { int64_t x_abs, y; int c, i, rounding, g; /* g = integer part size, c = fractional part size */ size_t ptr; @@ -79,7 +95,7 @@ void print_number(const int64_t x) { printf("%-*s", FP_EXP, &buffer[ptr + g]); /* Prints fractional part */ } -void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) { +static void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) { int i; int64_t min = INT64_MAX; int64_t sum = 0; @@ -113,7 +129,7 @@ void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void printf("\n"); } -int have_flag(int argc, char** argv, char *flag) { +static int have_flag(int argc, char** argv, char *flag) { char** argm = argv + argc; argv++; while (argv != argm) { @@ -129,7 +145,7 @@ int have_flag(int argc, char** argv, char *flag) { returns: - 1 if the user entered an invalid argument - 0 if all the user entered arguments are valid */ -int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) { +static int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) { size_t i; int found_valid; char** argm = argv + argc; @@ -151,7 +167,7 @@ int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) { return 0; } -int get_iters(int default_iters) { +static int get_iters(int default_iters) { char* env = getenv("SECP256K1_BENCH_ITERS"); if (env) { return strtol(env, NULL, 0); @@ -160,7 +176,7 @@ int get_iters(int default_iters) { } } -void print_output_table_header_row(void) { +static void print_output_table_header_row(void) { char* bench_str = "Benchmark"; /* left justified */ char* min_str = " Min(us) "; /* center alignment */ char* avg_str = " Avg(us) "; diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_ecmult.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/bench_ecmult.c similarity index 64% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_ecmult.c rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/bench_ecmult.c index b6353cee..d42dc416 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_ecmult.c +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/bench_ecmult.c @@ -18,7 +18,7 @@ #define POINTS 32768 -void help(char **argv) { +static void help(char **argv) { printf("Benchmark EC multiplication algorithms\n"); printf("\n"); printf("Usage: %s \n", argv[0]); @@ -35,14 +35,14 @@ void help(char **argv) { typedef struct { /* Setup once in advance */ - rustsecp256k1zkp_v0_8_0_context* ctx; - rustsecp256k1zkp_v0_8_0_scratch_space* scratch; - rustsecp256k1zkp_v0_8_0_scalar* scalars; - rustsecp256k1zkp_v0_8_0_ge* pubkeys; - rustsecp256k1zkp_v0_8_0_gej* pubkeys_gej; - rustsecp256k1zkp_v0_8_0_scalar* seckeys; - rustsecp256k1zkp_v0_8_0_gej* expected_output; - rustsecp256k1zkp_v0_8_0_ecmult_multi_func ecmult_multi; + rustsecp256k1_v0_11_context* ctx; + rustsecp256k1_v0_11_scratch_space* scratch; + rustsecp256k1_v0_11_scalar* scalars; + rustsecp256k1_v0_11_ge* pubkeys; + rustsecp256k1_v0_11_gej* pubkeys_gej; + rustsecp256k1_v0_11_scalar* seckeys; + rustsecp256k1_v0_11_gej* expected_output; + rustsecp256k1_v0_11_ecmult_multi_func ecmult_multi; /* Changes per benchmark */ size_t count; @@ -54,7 +54,7 @@ typedef struct { size_t offset2; /* Benchmark output. */ - rustsecp256k1zkp_v0_8_0_gej* output; + rustsecp256k1_v0_11_gej* output; } bench_data; /* Hashes x into [0, POINTS) twice and store the result in offset1 and offset2. */ @@ -67,26 +67,24 @@ static void hash_into_offset(bench_data* data, size_t x) { * sum(outputs) ?= (sum(scalars_gen) + sum(seckeys)*sum(scalars))*G */ static void bench_ecmult_teardown_helper(bench_data* data, size_t* seckey_offset, size_t* scalar_offset, size_t* scalar_gen_offset, int iters) { int i; - rustsecp256k1zkp_v0_8_0_gej sum_output, tmp; - rustsecp256k1zkp_v0_8_0_scalar sum_scalars; + rustsecp256k1_v0_11_gej sum_output, tmp; + rustsecp256k1_v0_11_scalar sum_scalars; - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&sum_output); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sum_scalars); + rustsecp256k1_v0_11_gej_set_infinity(&sum_output); + rustsecp256k1_v0_11_scalar_set_int(&sum_scalars, 0); for (i = 0; i < iters; ++i) { - rustsecp256k1zkp_v0_8_0_gej_add_var(&sum_output, &sum_output, &data->output[i], NULL); + rustsecp256k1_v0_11_gej_add_var(&sum_output, &sum_output, &data->output[i], NULL); if (scalar_gen_offset != NULL) { - rustsecp256k1zkp_v0_8_0_scalar_add(&sum_scalars, &sum_scalars, &data->scalars[(*scalar_gen_offset+i) % POINTS]); + rustsecp256k1_v0_11_scalar_add(&sum_scalars, &sum_scalars, &data->scalars[(*scalar_gen_offset+i) % POINTS]); } if (seckey_offset != NULL) { - rustsecp256k1zkp_v0_8_0_scalar s = data->seckeys[(*seckey_offset+i) % POINTS]; - rustsecp256k1zkp_v0_8_0_scalar_mul(&s, &s, &data->scalars[(*scalar_offset+i) % POINTS]); - rustsecp256k1zkp_v0_8_0_scalar_add(&sum_scalars, &sum_scalars, &s); + rustsecp256k1_v0_11_scalar s = data->seckeys[(*seckey_offset+i) % POINTS]; + rustsecp256k1_v0_11_scalar_mul(&s, &s, &data->scalars[(*scalar_offset+i) % POINTS]); + rustsecp256k1_v0_11_scalar_add(&sum_scalars, &sum_scalars, &s); } } - rustsecp256k1zkp_v0_8_0_ecmult_gen(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars); - rustsecp256k1zkp_v0_8_0_gej_neg(&tmp, &tmp); - rustsecp256k1zkp_v0_8_0_gej_add_var(&tmp, &tmp, &sum_output, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&tmp)); + rustsecp256k1_v0_11_ecmult_gen(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&tmp, &sum_output)); } static void bench_ecmult_setup(void* arg) { @@ -101,7 +99,7 @@ static void bench_ecmult_gen(void* arg, int iters) { int i; for (i = 0; i < iters; ++i) { - rustsecp256k1zkp_v0_8_0_ecmult_gen(&data->ctx->ecmult_gen_ctx, &data->output[i], &data->scalars[(data->offset1+i) % POINTS]); + rustsecp256k1_v0_11_ecmult_gen(&data->ctx->ecmult_gen_ctx, &data->output[i], &data->scalars[(data->offset1+i) % POINTS]); } } @@ -115,7 +113,7 @@ static void bench_ecmult_const(void* arg, int iters) { int i; for (i = 0; i < iters; ++i) { - rustsecp256k1zkp_v0_8_0_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], 256); + rustsecp256k1_v0_11_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS]); } } @@ -129,7 +127,7 @@ static void bench_ecmult_1p(void* arg, int iters) { int i; for (i = 0; i < iters; ++i) { - rustsecp256k1zkp_v0_8_0_ecmult(&data->output[i], &data->pubkeys_gej[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], NULL); + rustsecp256k1_v0_11_ecmult(&data->output[i], &data->pubkeys_gej[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], NULL); } } @@ -140,12 +138,10 @@ static void bench_ecmult_1p_teardown(void* arg, int iters) { static void bench_ecmult_0p_g(void* arg, int iters) { bench_data* data = (bench_data*)arg; - rustsecp256k1zkp_v0_8_0_scalar zero; int i; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&zero, 0); for (i = 0; i < iters; ++i) { - rustsecp256k1zkp_v0_8_0_ecmult(&data->output[i], NULL, &zero, &data->scalars[(data->offset1+i) % POINTS]); + rustsecp256k1_v0_11_ecmult(&data->output[i], NULL, &rustsecp256k1_v0_11_scalar_zero, &data->scalars[(data->offset1+i) % POINTS]); } } @@ -159,7 +155,7 @@ static void bench_ecmult_1p_g(void* arg, int iters) { int i; for (i = 0; i < iters/2; ++i) { - rustsecp256k1zkp_v0_8_0_ecmult(&data->output[i], &data->pubkeys_gej[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], &data->scalars[(data->offset1+i) % POINTS]); + rustsecp256k1_v0_11_ecmult(&data->output[i], &data->pubkeys_gej[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], &data->scalars[(data->offset1+i) % POINTS]); } } @@ -185,12 +181,12 @@ static void run_ecmult_bench(bench_data* data, int iters) { run_benchmark(str, bench_ecmult_1p_g, bench_ecmult_setup, bench_ecmult_1p_g_teardown, data, 10, 2*iters); } -static int bench_ecmult_multi_callback(rustsecp256k1zkp_v0_8_0_scalar* sc, rustsecp256k1zkp_v0_8_0_ge* ge, size_t idx, void* arg) { +static int bench_ecmult_multi_callback(rustsecp256k1_v0_11_scalar* sc, rustsecp256k1_v0_11_ge* ge, size_t idx, void* arg) { bench_data* data = (bench_data*)arg; if (data->includes_g) ++idx; if (idx == 0) { *sc = data->scalars[data->offset1]; - *ge = rustsecp256k1zkp_v0_8_0_ge_const_g; + *ge = rustsecp256k1_v0_11_ge_const_g; } else { *sc = data->scalars[(data->offset1 + idx) % POINTS]; *ge = data->pubkeys[(data->offset2 + idx - 1) % POINTS]; @@ -224,14 +220,14 @@ static void bench_ecmult_multi_teardown(void* arg, int iters) { iters = iters / data->count; /* Verify the results in teardown, to avoid doing comparisons while benchmarking. */ for (iter = 0; iter < iters; ++iter) { - rustsecp256k1zkp_v0_8_0_gej tmp; - rustsecp256k1zkp_v0_8_0_gej_add_var(&tmp, &data->output[iter], &data->expected_output[iter], NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&tmp)); + rustsecp256k1_v0_11_gej tmp; + rustsecp256k1_v0_11_gej_add_var(&tmp, &data->output[iter], &data->expected_output[iter], NULL); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&tmp)); } } -static void generate_scalar(uint32_t num, rustsecp256k1zkp_v0_8_0_scalar* scalar) { - rustsecp256k1zkp_v0_8_0_sha256 sha256; +static void generate_scalar(uint32_t num, rustsecp256k1_v0_11_scalar* scalar) { + rustsecp256k1_v0_11_sha256 sha256; unsigned char c[10] = {'e', 'c', 'm', 'u', 'l', 't', 0, 0, 0, 0}; unsigned char buf[32]; int overflow = 0; @@ -239,16 +235,15 @@ static void generate_scalar(uint32_t num, rustsecp256k1zkp_v0_8_0_scalar* scalar c[7] = num >> 8; c[8] = num >> 16; c[9] = num >> 24; - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha256); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256, c, sizeof(c)); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha256, buf); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(scalar, buf, &overflow); + rustsecp256k1_v0_11_sha256_initialize(&sha256); + rustsecp256k1_v0_11_sha256_write(&sha256, c, sizeof(c)); + rustsecp256k1_v0_11_sha256_finalize(&sha256, buf); + rustsecp256k1_v0_11_scalar_set_b32(scalar, buf, &overflow); CHECK(!overflow); } static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_g, int num_iters) { char str[32]; - static const rustsecp256k1zkp_v0_8_0_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); size_t iters = 1 + num_iters / count; size_t iter; @@ -258,15 +253,15 @@ static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_ /* Compute (the negation of) the expected results directly. */ hash_into_offset(data, data->count); for (iter = 0; iter < iters; ++iter) { - rustsecp256k1zkp_v0_8_0_scalar tmp; - rustsecp256k1zkp_v0_8_0_scalar total = data->scalars[(data->offset1++) % POINTS]; + rustsecp256k1_v0_11_scalar tmp; + rustsecp256k1_v0_11_scalar total = data->scalars[(data->offset1++) % POINTS]; size_t i = 0; for (i = 0; i + 1 < count; ++i) { - rustsecp256k1zkp_v0_8_0_scalar_mul(&tmp, &data->seckeys[(data->offset2++) % POINTS], &data->scalars[(data->offset1++) % POINTS]); - rustsecp256k1zkp_v0_8_0_scalar_add(&total, &total, &tmp); + rustsecp256k1_v0_11_scalar_mul(&tmp, &data->seckeys[(data->offset2++) % POINTS], &data->scalars[(data->offset1++) % POINTS]); + rustsecp256k1_v0_11_scalar_add(&total, &total, &tmp); } - rustsecp256k1zkp_v0_8_0_scalar_negate(&total, &total); - rustsecp256k1zkp_v0_8_0_ecmult(&data->expected_output[iter], NULL, &zero, &total); + rustsecp256k1_v0_11_scalar_negate(&total, &total); + rustsecp256k1_v0_11_ecmult(&data->expected_output[iter], NULL, &rustsecp256k1_v0_11_scalar_zero, &total); } /* Run the benchmark. */ @@ -285,7 +280,7 @@ int main(int argc, char **argv) { int iters = get_iters(10000); - data.ecmult_multi = rustsecp256k1zkp_v0_8_0_ecmult_multi_var; + data.ecmult_multi = rustsecp256k1_v0_11_ecmult_multi_var; if (argc > 1) { if(have_flag(argc, argv, "-h") @@ -295,10 +290,10 @@ int main(int argc, char **argv) { return 0; } else if(have_flag(argc, argv, "pippenger_wnaf")) { printf("Using pippenger_wnaf:\n"); - data.ecmult_multi = rustsecp256k1zkp_v0_8_0_ecmult_pippenger_batch_single; + data.ecmult_multi = rustsecp256k1_v0_11_ecmult_pippenger_batch_single; } else if(have_flag(argc, argv, "strauss_wnaf")) { printf("Using strauss_wnaf:\n"); - data.ecmult_multi = rustsecp256k1zkp_v0_8_0_ecmult_strauss_batch_single; + data.ecmult_multi = rustsecp256k1_v0_11_ecmult_strauss_batch_single; } else if(have_flag(argc, argv, "simple")) { printf("Using simple algorithm:\n"); } else { @@ -308,33 +303,33 @@ int main(int argc, char **argv) { } } - data.ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - scratch_size = rustsecp256k1zkp_v0_8_0_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16; + data.ctx = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); + scratch_size = rustsecp256k1_v0_11_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16; if (!have_flag(argc, argv, "simple")) { - data.scratch = rustsecp256k1zkp_v0_8_0_scratch_space_create(data.ctx, scratch_size); + data.scratch = rustsecp256k1_v0_11_scratch_space_create(data.ctx, scratch_size); } else { data.scratch = NULL; } /* Allocate stuff */ - data.scalars = malloc(sizeof(rustsecp256k1zkp_v0_8_0_scalar) * POINTS); - data.seckeys = malloc(sizeof(rustsecp256k1zkp_v0_8_0_scalar) * POINTS); - data.pubkeys = malloc(sizeof(rustsecp256k1zkp_v0_8_0_ge) * POINTS); - data.pubkeys_gej = malloc(sizeof(rustsecp256k1zkp_v0_8_0_gej) * POINTS); - data.expected_output = malloc(sizeof(rustsecp256k1zkp_v0_8_0_gej) * (iters + 1)); - data.output = malloc(sizeof(rustsecp256k1zkp_v0_8_0_gej) * (iters + 1)); + data.scalars = malloc(sizeof(rustsecp256k1_v0_11_scalar) * POINTS); + data.seckeys = malloc(sizeof(rustsecp256k1_v0_11_scalar) * POINTS); + data.pubkeys = malloc(sizeof(rustsecp256k1_v0_11_ge) * POINTS); + data.pubkeys_gej = malloc(sizeof(rustsecp256k1_v0_11_gej) * POINTS); + data.expected_output = malloc(sizeof(rustsecp256k1_v0_11_gej) * (iters + 1)); + data.output = malloc(sizeof(rustsecp256k1_v0_11_gej) * (iters + 1)); /* Generate a set of scalars, and private/public keypairs. */ - rustsecp256k1zkp_v0_8_0_gej_set_ge(&data.pubkeys_gej[0], &rustsecp256k1zkp_v0_8_0_ge_const_g); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&data.seckeys[0], 1); + rustsecp256k1_v0_11_gej_set_ge(&data.pubkeys_gej[0], &rustsecp256k1_v0_11_ge_const_g); + rustsecp256k1_v0_11_scalar_set_int(&data.seckeys[0], 1); for (i = 0; i < POINTS; ++i) { generate_scalar(i, &data.scalars[i]); if (i) { - rustsecp256k1zkp_v0_8_0_gej_double_var(&data.pubkeys_gej[i], &data.pubkeys_gej[i - 1], NULL); - rustsecp256k1zkp_v0_8_0_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]); + rustsecp256k1_v0_11_gej_double_var(&data.pubkeys_gej[i], &data.pubkeys_gej[i - 1], NULL); + rustsecp256k1_v0_11_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]); } } - rustsecp256k1zkp_v0_8_0_ge_set_all_gej_var(data.pubkeys, data.pubkeys_gej, POINTS); + rustsecp256k1_v0_11_ge_set_all_gej_var(data.pubkeys, data.pubkeys_gej, POINTS); print_output_table_header_row(); @@ -358,9 +353,9 @@ int main(int argc, char **argv) { } if (data.scratch != NULL) { - rustsecp256k1zkp_v0_8_0_scratch_space_destroy(data.ctx, data.scratch); + rustsecp256k1_v0_11_scratch_space_destroy(data.ctx, data.scratch); } - rustsecp256k1zkp_v0_8_0_context_destroy(data.ctx); + rustsecp256k1_v0_11_context_destroy(data.ctx); free(data.scalars); free(data.pubkeys); free(data.pubkeys_gej); diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_internal.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/bench_internal.c similarity index 53% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_internal.c rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/bench_internal.c index 4f6a4e53..e9a301b8 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/bench_internal.c +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/bench_internal.c @@ -14,20 +14,38 @@ #include "field_impl.h" #include "group_impl.h" #include "scalar_impl.h" -#include "ecmult_const_impl.h" #include "ecmult_impl.h" #include "bench.h" +static void help(int default_iters) { + printf("Benchmarks various internal routines.\n"); + printf("\n"); + printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters); + printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n"); + printf("\n"); + printf("Usage: ./bench_internal [args]\n"); + printf("By default, all benchmarks will be run.\n"); + printf("args:\n"); + printf(" help : display this help and exit\n"); + printf(" scalar : all scalar operations (add, half, inverse, mul, negate, split)\n"); + printf(" field : all field operations (half, inverse, issquare, mul, normalize, sqr, sqrt)\n"); + printf(" group : all group operations (add, double, to_affine)\n"); + printf(" ecmult : all point multiplication operations (ecmult_wnaf) \n"); + printf(" hash : all hash algorithms (hmac, rng6979, sha256)\n"); + printf(" context : all context object operations (context_create)\n"); + printf("\n"); +} + typedef struct { - rustsecp256k1zkp_v0_8_0_scalar scalar[2]; - rustsecp256k1zkp_v0_8_0_fe fe[4]; - rustsecp256k1zkp_v0_8_0_ge ge[2]; - rustsecp256k1zkp_v0_8_0_gej gej[2]; + rustsecp256k1_v0_11_scalar scalar[2]; + rustsecp256k1_v0_11_fe fe[4]; + rustsecp256k1_v0_11_ge ge[2]; + rustsecp256k1_v0_11_gej gej[2]; unsigned char data[64]; int wnaf[256]; } bench_inv; -void bench_setup(void* arg) { +static void bench_setup(void* arg) { bench_inv *data = (bench_inv*)arg; static const unsigned char init[4][32] = { @@ -63,329 +81,327 @@ void bench_setup(void* arg) { } }; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&data->scalar[0], init[0], NULL); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&data->scalar[1], init[1], NULL); - rustsecp256k1zkp_v0_8_0_fe_set_b32(&data->fe[0], init[0]); - rustsecp256k1zkp_v0_8_0_fe_set_b32(&data->fe[1], init[1]); - rustsecp256k1zkp_v0_8_0_fe_set_b32(&data->fe[2], init[2]); - rustsecp256k1zkp_v0_8_0_fe_set_b32(&data->fe[3], init[3]); - CHECK(rustsecp256k1zkp_v0_8_0_ge_set_xo_var(&data->ge[0], &data->fe[0], 0)); - CHECK(rustsecp256k1zkp_v0_8_0_ge_set_xo_var(&data->ge[1], &data->fe[1], 1)); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&data->gej[0], &data->ge[0]); - rustsecp256k1zkp_v0_8_0_gej_rescale(&data->gej[0], &data->fe[2]); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&data->gej[1], &data->ge[1]); - rustsecp256k1zkp_v0_8_0_gej_rescale(&data->gej[1], &data->fe[3]); + rustsecp256k1_v0_11_scalar_set_b32(&data->scalar[0], init[0], NULL); + rustsecp256k1_v0_11_scalar_set_b32(&data->scalar[1], init[1], NULL); + rustsecp256k1_v0_11_fe_set_b32_limit(&data->fe[0], init[0]); + rustsecp256k1_v0_11_fe_set_b32_limit(&data->fe[1], init[1]); + rustsecp256k1_v0_11_fe_set_b32_limit(&data->fe[2], init[2]); + rustsecp256k1_v0_11_fe_set_b32_limit(&data->fe[3], init[3]); + CHECK(rustsecp256k1_v0_11_ge_set_xo_var(&data->ge[0], &data->fe[0], 0)); + CHECK(rustsecp256k1_v0_11_ge_set_xo_var(&data->ge[1], &data->fe[1], 1)); + rustsecp256k1_v0_11_gej_set_ge(&data->gej[0], &data->ge[0]); + rustsecp256k1_v0_11_gej_rescale(&data->gej[0], &data->fe[2]); + rustsecp256k1_v0_11_gej_set_ge(&data->gej[1], &data->ge[1]); + rustsecp256k1_v0_11_gej_rescale(&data->gej[1], &data->fe[3]); memcpy(data->data, init[0], 32); memcpy(data->data + 32, init[1], 32); } -void bench_scalar_add(void* arg, int iters) { +static void bench_scalar_add(void* arg, int iters) { int i, j = 0; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - j += rustsecp256k1zkp_v0_8_0_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + j += rustsecp256k1_v0_11_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); } CHECK(j <= iters); } -void bench_scalar_negate(void* arg, int iters) { +static void bench_scalar_negate(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&data->scalar[0], &data->scalar[0]); + rustsecp256k1_v0_11_scalar_negate(&data->scalar[0], &data->scalar[0]); } } -void bench_scalar_sqr(void* arg, int iters) { +static void bench_scalar_half(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; + rustsecp256k1_v0_11_scalar s = data->scalar[0]; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_scalar_sqr(&data->scalar[0], &data->scalar[0]); + rustsecp256k1_v0_11_scalar_half(&s, &s); } + + data->scalar[0] = s; } -void bench_scalar_mul(void* arg, int iters) { +static void bench_scalar_mul(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_scalar_mul(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + rustsecp256k1_v0_11_scalar_mul(&data->scalar[0], &data->scalar[0], &data->scalar[1]); } } -void bench_scalar_split(void* arg, int iters) { +static void bench_scalar_split(void* arg, int iters) { int i, j = 0; bench_inv *data = (bench_inv*)arg; + rustsecp256k1_v0_11_scalar tmp; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_scalar_split_lambda(&data->scalar[0], &data->scalar[1], &data->scalar[0]); - j += rustsecp256k1zkp_v0_8_0_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + rustsecp256k1_v0_11_scalar_split_lambda(&tmp, &data->scalar[1], &data->scalar[0]); + j += rustsecp256k1_v0_11_scalar_add(&data->scalar[0], &tmp, &data->scalar[1]); } CHECK(j <= iters); } -void bench_scalar_inverse(void* arg, int iters) { +static void bench_scalar_inverse(void* arg, int iters) { int i, j = 0; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_scalar_inverse(&data->scalar[0], &data->scalar[0]); - j += rustsecp256k1zkp_v0_8_0_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + rustsecp256k1_v0_11_scalar_inverse(&data->scalar[0], &data->scalar[0]); + j += rustsecp256k1_v0_11_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); } CHECK(j <= iters); } -void bench_scalar_inverse_var(void* arg, int iters) { +static void bench_scalar_inverse_var(void* arg, int iters) { int i, j = 0; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_scalar_inverse_var(&data->scalar[0], &data->scalar[0]); - j += rustsecp256k1zkp_v0_8_0_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + rustsecp256k1_v0_11_scalar_inverse_var(&data->scalar[0], &data->scalar[0]); + j += rustsecp256k1_v0_11_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); } CHECK(j <= iters); } -void bench_field_half(void* arg, int iters) { +static void bench_field_half(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_fe_half(&data->fe[0]); + rustsecp256k1_v0_11_fe_half(&data->fe[0]); } } -void bench_field_normalize(void* arg, int iters) { +static void bench_field_normalize(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_fe_normalize(&data->fe[0]); + rustsecp256k1_v0_11_fe_normalize(&data->fe[0]); } } -void bench_field_normalize_weak(void* arg, int iters) { +static void bench_field_normalize_weak(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&data->fe[0]); + rustsecp256k1_v0_11_fe_normalize_weak(&data->fe[0]); } } -void bench_field_mul(void* arg, int iters) { +static void bench_field_mul(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_fe_mul(&data->fe[0], &data->fe[0], &data->fe[1]); + rustsecp256k1_v0_11_fe_mul(&data->fe[0], &data->fe[0], &data->fe[1]); } } -void bench_field_sqr(void* arg, int iters) { +static void bench_field_sqr(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_fe_sqr(&data->fe[0], &data->fe[0]); + rustsecp256k1_v0_11_fe_sqr(&data->fe[0], &data->fe[0]); } } -void bench_field_inverse(void* arg, int iters) { +static void bench_field_inverse(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_fe_inv(&data->fe[0], &data->fe[0]); - rustsecp256k1zkp_v0_8_0_fe_add(&data->fe[0], &data->fe[1]); + rustsecp256k1_v0_11_fe_inv(&data->fe[0], &data->fe[0]); + rustsecp256k1_v0_11_fe_add(&data->fe[0], &data->fe[1]); } } -void bench_field_inverse_var(void* arg, int iters) { +static void bench_field_inverse_var(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_fe_inv_var(&data->fe[0], &data->fe[0]); - rustsecp256k1zkp_v0_8_0_fe_add(&data->fe[0], &data->fe[1]); + rustsecp256k1_v0_11_fe_inv_var(&data->fe[0], &data->fe[0]); + rustsecp256k1_v0_11_fe_add(&data->fe[0], &data->fe[1]); } } -void bench_field_sqrt(void* arg, int iters) { +static void bench_field_sqrt(void* arg, int iters) { int i, j = 0; bench_inv *data = (bench_inv*)arg; - rustsecp256k1zkp_v0_8_0_fe t; + rustsecp256k1_v0_11_fe t; for (i = 0; i < iters; i++) { t = data->fe[0]; - j += rustsecp256k1zkp_v0_8_0_fe_sqrt(&data->fe[0], &t); - rustsecp256k1zkp_v0_8_0_fe_add(&data->fe[0], &data->fe[1]); + j += rustsecp256k1_v0_11_fe_sqrt(&data->fe[0], &t); + rustsecp256k1_v0_11_fe_add(&data->fe[0], &data->fe[1]); } CHECK(j <= iters); } -void bench_group_double_var(void* arg, int iters) { - int i; +static void bench_field_is_square_var(void* arg, int iters) { + int i, j = 0; bench_inv *data = (bench_inv*)arg; + rustsecp256k1_v0_11_fe t = data->fe[0]; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_gej_double_var(&data->gej[0], &data->gej[0], NULL); + j += rustsecp256k1_v0_11_fe_is_square_var(&t); + rustsecp256k1_v0_11_fe_add(&t, &data->fe[1]); + rustsecp256k1_v0_11_fe_normalize_var(&t); } + CHECK(j <= iters); } -void bench_group_add_var(void* arg, int iters) { +static void bench_group_double_var(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_gej_add_var(&data->gej[0], &data->gej[0], &data->gej[1], NULL); + rustsecp256k1_v0_11_gej_double_var(&data->gej[0], &data->gej[0], NULL); } } -void bench_group_add_affine(void* arg, int iters) { +static void bench_group_add_var(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_gej_add_ge(&data->gej[0], &data->gej[0], &data->ge[1]); + rustsecp256k1_v0_11_gej_add_var(&data->gej[0], &data->gej[0], &data->gej[1], NULL); } } -void bench_group_add_affine_var(void* arg, int iters) { +static void bench_group_add_affine(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&data->gej[0], &data->gej[0], &data->ge[1], NULL); + rustsecp256k1_v0_11_gej_add_ge(&data->gej[0], &data->gej[0], &data->ge[1]); } } -void bench_group_jacobi_var(void* arg, int iters) { - int i, j = 0; +static void bench_group_add_affine_var(void* arg, int iters) { + int i; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - j += rustsecp256k1zkp_v0_8_0_gej_has_quad_y_var(&data->gej[0]); - /* Vary the Y and Z coordinates of the input (the X coordinate doesn't matter to - rustsecp256k1zkp_v0_8_0_gej_has_quad_y_var). Note that the resulting coordinates will - generally not correspond to a point on the curve, but this is not a problem - for the code being benchmarked here. Adding and normalizing have less - overhead than EC operations (which could guarantee the point remains on the - curve). */ - rustsecp256k1zkp_v0_8_0_fe_add(&data->gej[0].y, &data->fe[1]); - rustsecp256k1zkp_v0_8_0_fe_add(&data->gej[0].z, &data->fe[2]); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&data->gej[0].y); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&data->gej[0].z); + rustsecp256k1_v0_11_gej_add_ge_var(&data->gej[0], &data->gej[0], &data->ge[1], NULL); } - CHECK(j <= iters); } -void bench_group_to_affine_var(void* arg, int iters) { +static void bench_group_add_zinv_var(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; - for (i = 0; i < iters; ++i) { - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&data->ge[1], &data->gej[0]); - /* Use the output affine X/Y coordinates to vary the input X/Y/Z coordinates. - Similar to bench_group_jacobi_var, this approach does not result in - coordinates of points on the curve. */ - rustsecp256k1zkp_v0_8_0_fe_add(&data->gej[0].x, &data->ge[1].y); - rustsecp256k1zkp_v0_8_0_fe_add(&data->gej[0].y, &data->fe[2]); - rustsecp256k1zkp_v0_8_0_fe_add(&data->gej[0].z, &data->ge[1].x); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&data->gej[0].x); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&data->gej[0].y); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&data->gej[0].z); + for (i = 0; i < iters; i++) { + rustsecp256k1_v0_11_gej_add_zinv_var(&data->gej[0], &data->gej[0], &data->ge[1], &data->gej[0].y); } } -void bench_ecmult_wnaf(void* arg, int iters) { - int i, bits = 0, overflow = 0; +static void bench_group_to_affine_var(void* arg, int iters) { + int i; bench_inv *data = (bench_inv*)arg; - for (i = 0; i < iters; i++) { - bits += rustsecp256k1zkp_v0_8_0_ecmult_wnaf(data->wnaf, 256, &data->scalar[0], WINDOW_A); - overflow += rustsecp256k1zkp_v0_8_0_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + for (i = 0; i < iters; ++i) { + rustsecp256k1_v0_11_ge_set_gej_var(&data->ge[1], &data->gej[0]); + /* Use the output affine X/Y coordinates to vary the input X/Y/Z coordinates. + Note that the resulting coordinates will generally not correspond to a point + on the curve, but this is not a problem for the code being benchmarked here. + Adding and normalizing have less overhead than EC operations (which could + guarantee the point remains on the curve). */ + rustsecp256k1_v0_11_fe_add(&data->gej[0].x, &data->ge[1].y); + rustsecp256k1_v0_11_fe_add(&data->gej[0].y, &data->fe[2]); + rustsecp256k1_v0_11_fe_add(&data->gej[0].z, &data->ge[1].x); + rustsecp256k1_v0_11_fe_normalize_var(&data->gej[0].x); + rustsecp256k1_v0_11_fe_normalize_var(&data->gej[0].y); + rustsecp256k1_v0_11_fe_normalize_var(&data->gej[0].z); } - CHECK(overflow >= 0); - CHECK(bits <= 256*iters); } -void bench_wnaf_const(void* arg, int iters) { +static void bench_ecmult_wnaf(void* arg, int iters) { int i, bits = 0, overflow = 0; bench_inv *data = (bench_inv*)arg; for (i = 0; i < iters; i++) { - bits += rustsecp256k1zkp_v0_8_0_wnaf_const(data->wnaf, &data->scalar[0], WINDOW_A, 256); - overflow += rustsecp256k1zkp_v0_8_0_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + bits += rustsecp256k1_v0_11_ecmult_wnaf(data->wnaf, 256, &data->scalar[0], WINDOW_A); + overflow += rustsecp256k1_v0_11_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); } CHECK(overflow >= 0); CHECK(bits <= 256*iters); } - -void bench_sha256(void* arg, int iters) { +static void bench_sha256(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; - rustsecp256k1zkp_v0_8_0_sha256 sha; + rustsecp256k1_v0_11_sha256 sha; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha, data->data, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha, data->data); + rustsecp256k1_v0_11_sha256_initialize(&sha); + rustsecp256k1_v0_11_sha256_write(&sha, data->data, 32); + rustsecp256k1_v0_11_sha256_finalize(&sha, data->data); } } -void bench_hmac_sha256(void* arg, int iters) { +static void bench_hmac_sha256(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; - rustsecp256k1zkp_v0_8_0_hmac_sha256 hmac; + rustsecp256k1_v0_11_hmac_sha256 hmac; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_hmac_sha256_initialize(&hmac, data->data, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hmac, data->data, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_finalize(&hmac, data->data); + rustsecp256k1_v0_11_hmac_sha256_initialize(&hmac, data->data, 32); + rustsecp256k1_v0_11_hmac_sha256_write(&hmac, data->data, 32); + rustsecp256k1_v0_11_hmac_sha256_finalize(&hmac, data->data); } } -void bench_rfc6979_hmac_sha256(void* arg, int iters) { +static void bench_rfc6979_hmac_sha256(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256 rng; + rustsecp256k1_v0_11_rfc6979_hmac_sha256 rng; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(&rng, data->data, 32); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_generate(&rng, data->data, 32); } } -void bench_context_verify(void* arg, int iters) { +static void bench_context(void* arg, int iters) { int i; (void)arg; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_context_destroy(rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_VERIFY)); - } -} - -void bench_context_sign(void* arg, int iters) { - int i; - (void)arg; - for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_context_destroy(rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN)); + rustsecp256k1_v0_11_context_destroy(rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE)); } } int main(int argc, char **argv) { bench_inv data; - int iters = get_iters(20000); + int default_iters = 20000; + int iters = get_iters(default_iters); int d = argc == 1; /* default */ + + if (argc > 1) { + if (have_flag(argc, argv, "-h") + || have_flag(argc, argv, "--help") + || have_flag(argc, argv, "help")) { + help(default_iters); + return 0; + } + } + print_output_table_header_row(); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "half")) run_benchmark("scalar_half", bench_scalar_half, bench_setup, NULL, &data, 10, iters*100); if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, iters*100); if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100); - if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, iters); @@ -398,24 +414,23 @@ int main(int argc, char **argv) { if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "issquare")) run_benchmark("field_is_square_var", bench_field_is_square_var, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, iters*10); - if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_zinv_var", bench_group_add_zinv_var, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "to_affine")) run_benchmark("group_to_affine_var", bench_group_to_affine_var, bench_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 1 + iters/1000); - if (d || have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 1 + iters/100); + if (d || have_flag(argc, argv, "context")) run_benchmark("context_create", bench_context, bench_setup, NULL, &data, 10, iters); return 0; } diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/checkmem.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/checkmem.h new file mode 100644 index 00000000..7e333ce5 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/checkmem.h @@ -0,0 +1,102 @@ +/*********************************************************************** + * Copyright (c) 2022 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +/* The code here is inspired by Kris Kwiatkowski's approach in + * https://github.com/kriskwiatkowski/pqc/blob/main/src/common/ct_check.h + * to provide a general interface for memory-checking mechanisms, primarily + * for constant-time checking. + */ + +/* These macros are defined by this header file: + * + * - SECP256K1_CHECKMEM_ENABLED: + * - 1 if memory-checking integration is available, 0 otherwise. + * This is just a compile-time macro. Use the next macro to check it is actually + * available at runtime. + * - SECP256K1_CHECKMEM_RUNNING(): + * - Acts like a function call, returning 1 if memory checking is available + * at runtime. + * - SECP256K1_CHECKMEM_CHECK(p, len): + * - Assert or otherwise fail in case the len-byte memory block pointed to by p is + * not considered entirely defined. + * - SECP256K1_CHECKMEM_CHECK_VERIFY(p, len): + * - Like SECP256K1_CHECKMEM_CHECK, but only works in VERIFY mode. + * - SECP256K1_CHECKMEM_UNDEFINE(p, len): + * - marks the len-byte memory block pointed to by p as undefined data (secret data, + * in the context of constant-time checking). + * - SECP256K1_CHECKMEM_DEFINE(p, len): + * - marks the len-byte memory pointed to by p as defined data (public data, in the + * context of constant-time checking). + * - SECP256K1_CHECKMEM_MSAN_DEFINE(p, len): + * - Like SECP256K1_CHECKMEM_DEFINE, but applies only to memory_sanitizer. + * + */ + +#ifndef SECP256K1_CHECKMEM_H +#define SECP256K1_CHECKMEM_H + +/* Define a statement-like macro that ignores the arguments. */ +#define SECP256K1_CHECKMEM_NOOP(p, len) do { (void)(p); (void)(len); } while(0) + +/* If compiling under msan, map the SECP256K1_CHECKMEM_* functionality to msan. + * Choose this preferentially, even when VALGRIND is defined, as msan-compiled + * binaries can't be run under valgrind anyway. */ +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# include +# define SECP256K1_CHECKMEM_ENABLED 1 +# define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len)) +# define SECP256K1_CHECKMEM_DEFINE(p, len) __msan_unpoison((p), (len)) +# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) __msan_unpoison((p), (len)) +# define SECP256K1_CHECKMEM_CHECK(p, len) __msan_check_mem_is_initialized((p), (len)) +# define SECP256K1_CHECKMEM_RUNNING() (1) +# endif +#endif + +#if !defined SECP256K1_CHECKMEM_MSAN_DEFINE +# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +#endif + +/* If valgrind integration is desired (through the VALGRIND define), implement the + * SECP256K1_CHECKMEM_* macros using valgrind. */ +#if !defined SECP256K1_CHECKMEM_ENABLED +# if defined VALGRIND +# include +# if defined(__clang__) && defined(__APPLE__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wreserved-identifier" +# endif +# include +# if defined(__clang__) && defined(__APPLE__) +# pragma clang diagnostic pop +# endif +# define SECP256K1_CHECKMEM_ENABLED 1 +# define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len)) +# define SECP256K1_CHECKMEM_DEFINE(p, len) VALGRIND_MAKE_MEM_DEFINED((p), (len)) +# define SECP256K1_CHECKMEM_CHECK(p, len) VALGRIND_CHECK_MEM_IS_DEFINED((p), (len)) + /* VALGRIND_MAKE_MEM_DEFINED returns 0 iff not running on memcheck. + * This is more precise than the RUNNING_ON_VALGRIND macro, which + * checks for valgrind in general instead of memcheck specifically. */ +# define SECP256K1_CHECKMEM_RUNNING() (VALGRIND_MAKE_MEM_DEFINED(NULL, 0) != 0) +# endif +#endif + +/* As a fall-back, map these macros to dummy statements. */ +#if !defined SECP256K1_CHECKMEM_ENABLED +# define SECP256K1_CHECKMEM_ENABLED 0 +# define SECP256K1_CHECKMEM_UNDEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +# define SECP256K1_CHECKMEM_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +# define SECP256K1_CHECKMEM_CHECK(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +# define SECP256K1_CHECKMEM_RUNNING() (0) +#endif + +#if defined VERIFY +#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_CHECK((p), (len)) +#else +#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +#endif + +#endif /* SECP256K1_CHECKMEM_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ctime_tests.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ctime_tests.c new file mode 100644 index 00000000..19c0abe3 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ctime_tests.c @@ -0,0 +1,266 @@ +/*********************************************************************** + * Copyright (c) 2020 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#include +#include + +#include "../include/secp256k1.h" +#include "assumptions.h" +#include "checkmem.h" + +#if !SECP256K1_CHECKMEM_ENABLED +# error "This tool cannot be compiled without memory-checking interface (valgrind or msan)" +#endif + +#ifdef ENABLE_MODULE_ECDH +# include "../include/rustsecp256k1_v0_11_ecdh.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "../include/rustsecp256k1_v0_11_recovery.h" +#endif + +#ifdef ENABLE_MODULE_EXTRAKEYS +# include "../include/rustsecp256k1_v0_11_extrakeys.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +#include "../include/secp256k1_schnorrsig.h" +#endif + +#ifdef ENABLE_MODULE_MUSIG +#include "../include/secp256k1_musig.h" +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT +#include "../include/secp256k1_ellswift.h" +#endif + +static void run_tests(rustsecp256k1_v0_11_context *ctx, unsigned char *key); + +int main(void) { + rustsecp256k1_v0_11_context* ctx; + unsigned char key[32]; + int ret, i; + + if (!SECP256K1_CHECKMEM_RUNNING()) { + fprintf(stderr, "This test can only usefully be run inside valgrind because it was not compiled under msan.\n"); + fprintf(stderr, "Usage: libtool --mode=execute valgrind ./ctime_tests\n"); + return 1; + } + ctx = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_DECLASSIFY); + /** In theory, testing with a single secret input should be sufficient: + * If control flow depended on secrets the tool would generate an error. + */ + for (i = 0; i < 32; i++) { + key[i] = i + 65; + } + + run_tests(ctx, key); + + /* Test context randomisation. Do this last because it leaves the context + * tainted. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = rustsecp256k1_v0_11_context_randomize(ctx, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret); + + rustsecp256k1_v0_11_context_destroy(ctx); + return 0; +} + +static void run_tests(rustsecp256k1_v0_11_context *ctx, unsigned char *key) { + rustsecp256k1_v0_11_ecdsa_signature signature; + rustsecp256k1_v0_11_pubkey pubkey; + size_t siglen = 74; + size_t outputlen = 33; + int i; + int ret; + unsigned char msg[32]; + unsigned char sig[74]; + unsigned char spubkey[33]; +#ifdef ENABLE_MODULE_RECOVERY + rustsecp256k1_v0_11_ecdsa_recoverable_signature recoverable_signature; + int recid; +#endif +#ifdef ENABLE_MODULE_EXTRAKEYS + rustsecp256k1_v0_11_keypair keypair; +#endif +#ifdef ENABLE_MODULE_ELLSWIFT + unsigned char ellswift[64]; + static const unsigned char prefix[64] = {'t', 'e', 's', 't'}; +#endif + + for (i = 0; i < 32; i++) { + msg[i] = i + 1; + } + + /* Test keygen. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = rustsecp256k1_v0_11_ec_pubkey_create(ctx, &pubkey, key); + SECP256K1_CHECKMEM_DEFINE(&pubkey, sizeof(rustsecp256k1_v0_11_pubkey)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret); + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(ctx, spubkey, &outputlen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + + /* Test signing. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = rustsecp256k1_v0_11_ecdsa_sign(ctx, &signature, msg, key, NULL, NULL); + SECP256K1_CHECKMEM_DEFINE(&signature, sizeof(rustsecp256k1_v0_11_ecdsa_signature)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature)); + +#ifdef ENABLE_MODULE_ECDH + /* Test ECDH. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = rustsecp256k1_v0_11_ecdh(ctx, msg, &pubkey, key, NULL, NULL); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); +#endif + +#ifdef ENABLE_MODULE_RECOVERY + /* Test signing a recoverable signature. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = rustsecp256k1_v0_11_ecdsa_sign_recoverable(ctx, &recoverable_signature, msg, key, NULL, NULL); + SECP256K1_CHECKMEM_DEFINE(&recoverable_signature, sizeof(recoverable_signature)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret); + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recoverable_signature)); + CHECK(recid >= 0 && recid <= 3); +#endif + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = rustsecp256k1_v0_11_ec_seckey_verify(ctx, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = rustsecp256k1_v0_11_ec_seckey_negate(ctx, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(msg, 32); + ret = rustsecp256k1_v0_11_ec_seckey_tweak_add(ctx, key, msg); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(msg, 32); + ret = rustsecp256k1_v0_11_ec_seckey_tweak_mul(ctx, key, msg); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + /* Test keypair_create and keypair_xonly_tweak_add. */ +#ifdef ENABLE_MODULE_EXTRAKEYS + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = rustsecp256k1_v0_11_keypair_create(ctx, &keypair, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + /* The tweak is not treated as a secret in keypair_tweak_add */ + SECP256K1_CHECKMEM_DEFINE(msg, 32); + ret = rustsecp256k1_v0_11_keypair_xonly_tweak_add(ctx, &keypair, msg); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(&keypair, sizeof(keypair)); + ret = rustsecp256k1_v0_11_keypair_sec(ctx, key, &keypair); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = rustsecp256k1_v0_11_keypair_create(ctx, &keypair, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + ret = rustsecp256k1_v0_11_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); +#endif + +#ifdef ENABLE_MODULE_MUSIG + { + rustsecp256k1_v0_11_pubkey pk; + const rustsecp256k1_v0_11_pubkey *pk_ptr[1]; + rustsecp256k1_v0_11_xonly_pubkey agg_pk; + unsigned char session_secrand[32]; + uint64_t nonrepeating_cnt = 0; + rustsecp256k1_v0_11_musig_secnonce secnonce; + rustsecp256k1_v0_11_musig_pubnonce pubnonce; + const rustsecp256k1_v0_11_musig_pubnonce *pubnonce_ptr[1]; + rustsecp256k1_v0_11_musig_aggnonce aggnonce; + rustsecp256k1_v0_11_musig_keyagg_cache cache; + rustsecp256k1_v0_11_musig_session session; + rustsecp256k1_v0_11_musig_partial_sig partial_sig; + unsigned char extra_input[32]; + + pk_ptr[0] = &pk; + pubnonce_ptr[0] = &pubnonce; + SECP256K1_CHECKMEM_DEFINE(key, 32); + memcpy(session_secrand, key, sizeof(session_secrand)); + session_secrand[0] = session_secrand[0] + 1; + memcpy(extra_input, key, sizeof(extra_input)); + extra_input[0] = extra_input[0] + 2; + + CHECK(rustsecp256k1_v0_11_keypair_create(ctx, &keypair, key)); + CHECK(rustsecp256k1_v0_11_keypair_pub(ctx, &pk, &keypair)); + CHECK(rustsecp256k1_v0_11_musig_pubkey_agg(ctx, &agg_pk, &cache, pk_ptr, 1)); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(session_secrand, sizeof(session_secrand)); + SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input)); + ret = rustsecp256k1_v0_11_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_secrand, key, &pk, msg, &cache, extra_input); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + ret = rustsecp256k1_v0_11_musig_nonce_gen_counter(ctx, &secnonce, &pubnonce, nonrepeating_cnt, &keypair, msg, &cache, extra_input); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + CHECK(rustsecp256k1_v0_11_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1)); + /* Make sure that previous tests don't undefine msg. It's not used as a secret here. */ + SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg)); + CHECK(rustsecp256k1_v0_11_musig_nonce_process(ctx, &session, &aggnonce, msg, &cache) == 1); + + ret = rustsecp256k1_v0_11_keypair_create(ctx, &keypair, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + ret = rustsecp256k1_v0_11_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &cache, &session); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + } +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = rustsecp256k1_v0_11_ellswift_create(ctx, ellswift, key, NULL); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = rustsecp256k1_v0_11_ellswift_create(ctx, ellswift, key, ellswift); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + for (i = 0; i < 2; i++) { + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift)); + ret = rustsecp256k1_v0_11_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, rustsecp256k1_v0_11_ellswift_xdh_hash_function_bip324, NULL); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift)); + ret = rustsecp256k1_v0_11_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, rustsecp256k1_v0_11_ellswift_xdh_hash_function_prefix, (void *)prefix); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + } + +#endif +} diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecdsa.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecdsa.h new file mode 100644 index 00000000..77ae9498 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecdsa.h @@ -0,0 +1,21 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECDSA_H +#define SECP256K1_ECDSA_H + +#include + +#include "scalar.h" +#include "group.h" +#include "ecmult.h" + +static int rustsecp256k1_v0_11_ecdsa_sig_parse(rustsecp256k1_v0_11_scalar *r, rustsecp256k1_v0_11_scalar *s, const unsigned char *sig, size_t size); +static int rustsecp256k1_v0_11_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *s); +static int rustsecp256k1_v0_11_ecdsa_sig_verify(const rustsecp256k1_v0_11_scalar* r, const rustsecp256k1_v0_11_scalar* s, const rustsecp256k1_v0_11_ge *pubkey, const rustsecp256k1_v0_11_scalar *message); +static int rustsecp256k1_v0_11_ecdsa_sig_sign(const rustsecp256k1_v0_11_ecmult_gen_context *ctx, rustsecp256k1_v0_11_scalar* r, rustsecp256k1_v0_11_scalar* s, const rustsecp256k1_v0_11_scalar *seckey, const rustsecp256k1_v0_11_scalar *message, const rustsecp256k1_v0_11_scalar *nonce, int *recid); + +#endif /* SECP256K1_ECDSA_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecdsa_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecdsa_impl.h similarity index 55% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecdsa_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecdsa_impl.h index bda3f1f6..2c8cb4dd 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecdsa_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecdsa_impl.h @@ -16,37 +16,24 @@ #include "ecdsa.h" /** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1 - * sage: for t in xrange(1023, -1, -1): - * .. p = 2**256 - 2**32 - t - * .. if p.is_prime(): - * .. print '%x'%p - * .. break - * 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f' - * sage: a = 0 - * sage: b = 7 - * sage: F = FiniteField (p) - * sage: '%x' % (EllipticCurve ([F (a), F (b)]).order()) - * 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141' + * $ sage -c 'load("rustsecp256k1_v0_11_params.sage"); print(hex(N))' + * 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 */ -static const rustsecp256k1zkp_v0_8_0_fe rustsecp256k1zkp_v0_8_0_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( +static const rustsecp256k1_v0_11_fe rustsecp256k1_v0_11_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL ); /** Difference between field and order, values 'p' and 'n' values defined in * "Standards for Efficient Cryptography" (SEC2) 2.7.1. - * sage: p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F - * sage: a = 0 - * sage: b = 7 - * sage: F = FiniteField (p) - * sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order()) - * '14551231950b75fc4402da1722fc9baee' + * $ sage -c 'load("rustsecp256k1_v0_11_params.sage"); print(hex(P-N))' + * 0x14551231950b75fc4402da1722fc9baee */ -static const rustsecp256k1zkp_v0_8_0_fe rustsecp256k1zkp_v0_8_0_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( +static const rustsecp256k1_v0_11_fe rustsecp256k1_v0_11_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL ); -static int rustsecp256k1zkp_v0_8_0_der_read_len(size_t *len, const unsigned char **sigp, const unsigned char *sigend) { +static int rustsecp256k1_v0_11_der_read_len(size_t *len, const unsigned char **sigp, const unsigned char *sigend) { size_t lenleft; unsigned char b1; VERIFY_CHECK(len != NULL); @@ -79,8 +66,7 @@ static int rustsecp256k1zkp_v0_8_0_der_read_len(size_t *len, const unsigned char } if (lenleft > sizeof(size_t)) { /* The resulting length would exceed the range of a size_t, so - * certainly longer than the passed array size. - */ + * it is certainly longer than the passed array size. */ return 0; } while (lenleft > 0) { @@ -89,7 +75,9 @@ static int rustsecp256k1zkp_v0_8_0_der_read_len(size_t *len, const unsigned char lenleft--; } if (*len > (size_t)(sigend - *sigp)) { - /* Result exceeds the length of the passed array. */ + /* Result exceeds the length of the passed array. + (Checking this is the responsibility of the caller but it + can't hurt do it here, too.) */ return 0; } if (*len < 128) { @@ -99,7 +87,7 @@ static int rustsecp256k1zkp_v0_8_0_der_read_len(size_t *len, const unsigned char return 1; } -static int rustsecp256k1zkp_v0_8_0_der_parse_integer(rustsecp256k1zkp_v0_8_0_scalar *r, const unsigned char **sig, const unsigned char *sigend) { +static int rustsecp256k1_v0_11_der_parse_integer(rustsecp256k1_v0_11_scalar *r, const unsigned char **sig, const unsigned char *sigend) { int overflow = 0; unsigned char ra[32] = {0}; size_t rlen; @@ -109,7 +97,7 @@ static int rustsecp256k1zkp_v0_8_0_der_parse_integer(rustsecp256k1zkp_v0_8_0_sca return 0; } (*sig)++; - if (rustsecp256k1zkp_v0_8_0_der_read_len(&rlen, sig, sigend) == 0) { + if (rustsecp256k1_v0_11_der_read_len(&rlen, sig, sigend) == 0) { return 0; } if (rlen == 0 || rlen > (size_t)(sigend - *sig)) { @@ -141,23 +129,23 @@ static int rustsecp256k1zkp_v0_8_0_der_parse_integer(rustsecp256k1zkp_v0_8_0_sca } if (!overflow) { if (rlen) memcpy(ra + 32 - rlen, *sig, rlen); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(r, ra, &overflow); + rustsecp256k1_v0_11_scalar_set_b32(r, ra, &overflow); } if (overflow) { - rustsecp256k1zkp_v0_8_0_scalar_set_int(r, 0); + rustsecp256k1_v0_11_scalar_set_int(r, 0); } (*sig) += rlen; return 1; } -static int rustsecp256k1zkp_v0_8_0_ecdsa_sig_parse(rustsecp256k1zkp_v0_8_0_scalar *rr, rustsecp256k1zkp_v0_8_0_scalar *rs, const unsigned char *sig, size_t size) { +static int rustsecp256k1_v0_11_ecdsa_sig_parse(rustsecp256k1_v0_11_scalar *rr, rustsecp256k1_v0_11_scalar *rs, const unsigned char *sig, size_t size) { const unsigned char *sigend = sig + size; size_t rlen; if (sig == sigend || *(sig++) != 0x30) { /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */ return 0; } - if (rustsecp256k1zkp_v0_8_0_der_read_len(&rlen, &sig, sigend) == 0) { + if (rustsecp256k1_v0_11_der_read_len(&rlen, &sig, sigend) == 0) { return 0; } if (rlen != (size_t)(sigend - sig)) { @@ -165,10 +153,10 @@ static int rustsecp256k1zkp_v0_8_0_ecdsa_sig_parse(rustsecp256k1zkp_v0_8_0_scala return 0; } - if (!rustsecp256k1zkp_v0_8_0_der_parse_integer(rr, &sig, sigend)) { + if (!rustsecp256k1_v0_11_der_parse_integer(rr, &sig, sigend)) { return 0; } - if (!rustsecp256k1zkp_v0_8_0_der_parse_integer(rs, &sig, sigend)) { + if (!rustsecp256k1_v0_11_der_parse_integer(rs, &sig, sigend)) { return 0; } @@ -180,12 +168,12 @@ static int rustsecp256k1zkp_v0_8_0_ecdsa_sig_parse(rustsecp256k1zkp_v0_8_0_scala return 1; } -static int rustsecp256k1zkp_v0_8_0_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const rustsecp256k1zkp_v0_8_0_scalar* ar, const rustsecp256k1zkp_v0_8_0_scalar* as) { +static int rustsecp256k1_v0_11_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const rustsecp256k1_v0_11_scalar* ar, const rustsecp256k1_v0_11_scalar* as) { unsigned char r[33] = {0}, s[33] = {0}; unsigned char *rp = r, *sp = s; size_t lenR = 33, lenS = 33; - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&r[1], ar); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&s[1], as); + rustsecp256k1_v0_11_scalar_get_b32(&r[1], ar); + rustsecp256k1_v0_11_scalar_get_b32(&s[1], as); while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; } while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; } if (*size < 6+lenS+lenR) { @@ -204,42 +192,43 @@ static int rustsecp256k1zkp_v0_8_0_ecdsa_sig_serialize(unsigned char *sig, size_ return 1; } -static int rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(const rustsecp256k1zkp_v0_8_0_scalar *sigr, const rustsecp256k1zkp_v0_8_0_scalar *sigs, const rustsecp256k1zkp_v0_8_0_ge *pubkey, const rustsecp256k1zkp_v0_8_0_scalar *message) { +static int rustsecp256k1_v0_11_ecdsa_sig_verify(const rustsecp256k1_v0_11_scalar *sigr, const rustsecp256k1_v0_11_scalar *sigs, const rustsecp256k1_v0_11_ge *pubkey, const rustsecp256k1_v0_11_scalar *message) { unsigned char c[32]; - rustsecp256k1zkp_v0_8_0_scalar sn, u1, u2; + rustsecp256k1_v0_11_scalar sn, u1, u2; #if !defined(EXHAUSTIVE_TEST_ORDER) - rustsecp256k1zkp_v0_8_0_fe xr; + rustsecp256k1_v0_11_fe xr; #endif - rustsecp256k1zkp_v0_8_0_gej pubkeyj; - rustsecp256k1zkp_v0_8_0_gej pr; + rustsecp256k1_v0_11_gej pubkeyj; + rustsecp256k1_v0_11_gej pr; - if (rustsecp256k1zkp_v0_8_0_scalar_is_zero(sigr) || rustsecp256k1zkp_v0_8_0_scalar_is_zero(sigs)) { + if (rustsecp256k1_v0_11_scalar_is_zero(sigr) || rustsecp256k1_v0_11_scalar_is_zero(sigs)) { return 0; } - rustsecp256k1zkp_v0_8_0_scalar_inverse_var(&sn, sigs); - rustsecp256k1zkp_v0_8_0_scalar_mul(&u1, &sn, message); - rustsecp256k1zkp_v0_8_0_scalar_mul(&u2, &sn, sigr); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&pubkeyj, pubkey); - rustsecp256k1zkp_v0_8_0_ecmult(&pr, &pubkeyj, &u2, &u1); - if (rustsecp256k1zkp_v0_8_0_gej_is_infinity(&pr)) { + rustsecp256k1_v0_11_scalar_inverse_var(&sn, sigs); + rustsecp256k1_v0_11_scalar_mul(&u1, &sn, message); + rustsecp256k1_v0_11_scalar_mul(&u2, &sn, sigr); + rustsecp256k1_v0_11_gej_set_ge(&pubkeyj, pubkey); + rustsecp256k1_v0_11_ecmult(&pr, &pubkeyj, &u2, &u1); + if (rustsecp256k1_v0_11_gej_is_infinity(&pr)) { return 0; } #if defined(EXHAUSTIVE_TEST_ORDER) { - rustsecp256k1zkp_v0_8_0_scalar computed_r; - rustsecp256k1zkp_v0_8_0_ge pr_ge; - rustsecp256k1zkp_v0_8_0_ge_set_gej(&pr_ge, &pr); - rustsecp256k1zkp_v0_8_0_fe_normalize(&pr_ge.x); + rustsecp256k1_v0_11_scalar computed_r; + rustsecp256k1_v0_11_ge pr_ge; + rustsecp256k1_v0_11_ge_set_gej(&pr_ge, &pr); + rustsecp256k1_v0_11_fe_normalize(&pr_ge.x); - rustsecp256k1zkp_v0_8_0_fe_get_b32(c, &pr_ge.x); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&computed_r, c, NULL); - return rustsecp256k1zkp_v0_8_0_scalar_eq(sigr, &computed_r); + rustsecp256k1_v0_11_fe_get_b32(c, &pr_ge.x); + rustsecp256k1_v0_11_scalar_set_b32(&computed_r, c, NULL); + return rustsecp256k1_v0_11_scalar_eq(sigr, &computed_r); } #else - rustsecp256k1zkp_v0_8_0_scalar_get_b32(c, sigr); - rustsecp256k1zkp_v0_8_0_fe_set_b32(&xr, c); + rustsecp256k1_v0_11_scalar_get_b32(c, sigr); + /* we can ignore the fe_set_b32_limit return value, because we know the input is in range */ + (void)rustsecp256k1_v0_11_fe_set_b32_limit(&xr, c); /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) * in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p), @@ -255,18 +244,18 @@ static int rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(const rustsecp256k1zkp_v0_8_ * <=> (xr * pr.z^2 mod p == pr.x) || (xr + n < p && (xr + n) * pr.z^2 mod p == pr.x) * * Thus, we can avoid the inversion, but we have to check both cases separately. - * rustsecp256k1zkp_v0_8_0_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test. + * rustsecp256k1_v0_11_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test. */ - if (rustsecp256k1zkp_v0_8_0_gej_eq_x_var(&xr, &pr)) { + if (rustsecp256k1_v0_11_gej_eq_x_var(&xr, &pr)) { /* xr * pr.z^2 mod p == pr.x, so the signature is valid. */ return 1; } - if (rustsecp256k1zkp_v0_8_0_fe_cmp_var(&xr, &rustsecp256k1zkp_v0_8_0_ecdsa_const_p_minus_order) >= 0) { + if (rustsecp256k1_v0_11_fe_cmp_var(&xr, &rustsecp256k1_v0_11_ecdsa_const_p_minus_order) >= 0) { /* xr + n >= p, so we can skip testing the second case. */ return 0; } - rustsecp256k1zkp_v0_8_0_fe_add(&xr, &rustsecp256k1zkp_v0_8_0_ecdsa_const_order_as_fe); - if (rustsecp256k1zkp_v0_8_0_gej_eq_x_var(&xr, &pr)) { + rustsecp256k1_v0_11_fe_add(&xr, &rustsecp256k1_v0_11_ecdsa_const_order_as_fe); + if (rustsecp256k1_v0_11_gej_eq_x_var(&xr, &pr)) { /* (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid. */ return 1; } @@ -274,42 +263,42 @@ static int rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(const rustsecp256k1zkp_v0_8_ #endif } -static int rustsecp256k1zkp_v0_8_0_ecdsa_sig_sign(const rustsecp256k1zkp_v0_8_0_ecmult_gen_context *ctx, rustsecp256k1zkp_v0_8_0_scalar *sigr, rustsecp256k1zkp_v0_8_0_scalar *sigs, const rustsecp256k1zkp_v0_8_0_scalar *seckey, const rustsecp256k1zkp_v0_8_0_scalar *message, const rustsecp256k1zkp_v0_8_0_scalar *nonce, int *recid) { +static int rustsecp256k1_v0_11_ecdsa_sig_sign(const rustsecp256k1_v0_11_ecmult_gen_context *ctx, rustsecp256k1_v0_11_scalar *sigr, rustsecp256k1_v0_11_scalar *sigs, const rustsecp256k1_v0_11_scalar *seckey, const rustsecp256k1_v0_11_scalar *message, const rustsecp256k1_v0_11_scalar *nonce, int *recid) { unsigned char b[32]; - rustsecp256k1zkp_v0_8_0_gej rp; - rustsecp256k1zkp_v0_8_0_ge r; - rustsecp256k1zkp_v0_8_0_scalar n; + rustsecp256k1_v0_11_gej rp; + rustsecp256k1_v0_11_ge r; + rustsecp256k1_v0_11_scalar n; int overflow = 0; int high; - rustsecp256k1zkp_v0_8_0_ecmult_gen(ctx, &rp, nonce); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&r, &rp); - rustsecp256k1zkp_v0_8_0_fe_normalize(&r.x); - rustsecp256k1zkp_v0_8_0_fe_normalize(&r.y); - rustsecp256k1zkp_v0_8_0_fe_get_b32(b, &r.x); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(sigr, b, &overflow); + rustsecp256k1_v0_11_ecmult_gen(ctx, &rp, nonce); + rustsecp256k1_v0_11_ge_set_gej(&r, &rp); + rustsecp256k1_v0_11_fe_normalize(&r.x); + rustsecp256k1_v0_11_fe_normalize(&r.y); + rustsecp256k1_v0_11_fe_get_b32(b, &r.x); + rustsecp256k1_v0_11_scalar_set_b32(sigr, b, &overflow); if (recid) { /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria. */ - *recid = (overflow << 1) | rustsecp256k1zkp_v0_8_0_fe_is_odd(&r.y); - } - rustsecp256k1zkp_v0_8_0_scalar_mul(&n, sigr, seckey); - rustsecp256k1zkp_v0_8_0_scalar_add(&n, &n, message); - rustsecp256k1zkp_v0_8_0_scalar_inverse(sigs, nonce); - rustsecp256k1zkp_v0_8_0_scalar_mul(sigs, sigs, &n); - rustsecp256k1zkp_v0_8_0_scalar_clear(&n); - rustsecp256k1zkp_v0_8_0_gej_clear(&rp); - rustsecp256k1zkp_v0_8_0_ge_clear(&r); - high = rustsecp256k1zkp_v0_8_0_scalar_is_high(sigs); - rustsecp256k1zkp_v0_8_0_scalar_cond_negate(sigs, high); + *recid = (overflow << 1) | rustsecp256k1_v0_11_fe_is_odd(&r.y); + } + rustsecp256k1_v0_11_scalar_mul(&n, sigr, seckey); + rustsecp256k1_v0_11_scalar_add(&n, &n, message); + rustsecp256k1_v0_11_scalar_inverse(sigs, nonce); + rustsecp256k1_v0_11_scalar_mul(sigs, sigs, &n); + rustsecp256k1_v0_11_scalar_clear(&n); + rustsecp256k1_v0_11_gej_clear(&rp); + rustsecp256k1_v0_11_ge_clear(&r); + high = rustsecp256k1_v0_11_scalar_is_high(sigs); + rustsecp256k1_v0_11_scalar_cond_negate(sigs, high); if (recid) { *recid ^= high; } /* P.x = order is on the curve, so technically sig->r could end up being zero, which would be an invalid signature. * This is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N. */ - return (int)(!rustsecp256k1zkp_v0_8_0_scalar_is_zero(sigr)) & (int)(!rustsecp256k1zkp_v0_8_0_scalar_is_zero(sigs)); + return (int)(!rustsecp256k1_v0_11_scalar_is_zero(sigr)) & (int)(!rustsecp256k1_v0_11_scalar_is_zero(sigs)); } #endif /* SECP256K1_ECDSA_IMPL_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/eckey.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/eckey.h new file mode 100644 index 00000000..10eefa9b --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/eckey.h @@ -0,0 +1,25 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECKEY_H +#define SECP256K1_ECKEY_H + +#include + +#include "group.h" +#include "scalar.h" +#include "ecmult.h" +#include "ecmult_gen.h" + +static int rustsecp256k1_v0_11_eckey_pubkey_parse(rustsecp256k1_v0_11_ge *elem, const unsigned char *pub, size_t size); +static int rustsecp256k1_v0_11_eckey_pubkey_serialize(rustsecp256k1_v0_11_ge *elem, unsigned char *pub, size_t *size, int compressed); + +static int rustsecp256k1_v0_11_eckey_privkey_tweak_add(rustsecp256k1_v0_11_scalar *key, const rustsecp256k1_v0_11_scalar *tweak); +static int rustsecp256k1_v0_11_eckey_pubkey_tweak_add(rustsecp256k1_v0_11_ge *key, const rustsecp256k1_v0_11_scalar *tweak); +static int rustsecp256k1_v0_11_eckey_privkey_tweak_mul(rustsecp256k1_v0_11_scalar *key, const rustsecp256k1_v0_11_scalar *tweak); +static int rustsecp256k1_v0_11_eckey_pubkey_tweak_mul(rustsecp256k1_v0_11_ge *key, const rustsecp256k1_v0_11_scalar *tweak); + +#endif /* SECP256K1_ECKEY_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/eckey_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/eckey_impl.h new file mode 100644 index 00000000..2bd1bdb0 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/eckey_impl.h @@ -0,0 +1,92 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECKEY_IMPL_H +#define SECP256K1_ECKEY_IMPL_H + +#include "eckey.h" + +#include "scalar.h" +#include "field.h" +#include "group.h" +#include "ecmult_gen.h" + +static int rustsecp256k1_v0_11_eckey_pubkey_parse(rustsecp256k1_v0_11_ge *elem, const unsigned char *pub, size_t size) { + if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) { + rustsecp256k1_v0_11_fe x; + return rustsecp256k1_v0_11_fe_set_b32_limit(&x, pub+1) && rustsecp256k1_v0_11_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD); + } else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { + rustsecp256k1_v0_11_fe x, y; + if (!rustsecp256k1_v0_11_fe_set_b32_limit(&x, pub+1) || !rustsecp256k1_v0_11_fe_set_b32_limit(&y, pub+33)) { + return 0; + } + rustsecp256k1_v0_11_ge_set_xy(elem, &x, &y); + if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) && + rustsecp256k1_v0_11_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { + return 0; + } + return rustsecp256k1_v0_11_ge_is_valid_var(elem); + } else { + return 0; + } +} + +static int rustsecp256k1_v0_11_eckey_pubkey_serialize(rustsecp256k1_v0_11_ge *elem, unsigned char *pub, size_t *size, int compressed) { + if (rustsecp256k1_v0_11_ge_is_infinity(elem)) { + return 0; + } + rustsecp256k1_v0_11_fe_normalize_var(&elem->x); + rustsecp256k1_v0_11_fe_normalize_var(&elem->y); + rustsecp256k1_v0_11_fe_get_b32(&pub[1], &elem->x); + if (compressed) { + *size = 33; + pub[0] = rustsecp256k1_v0_11_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN; + } else { + *size = 65; + pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED; + rustsecp256k1_v0_11_fe_get_b32(&pub[33], &elem->y); + } + return 1; +} + +static int rustsecp256k1_v0_11_eckey_privkey_tweak_add(rustsecp256k1_v0_11_scalar *key, const rustsecp256k1_v0_11_scalar *tweak) { + rustsecp256k1_v0_11_scalar_add(key, key, tweak); + return !rustsecp256k1_v0_11_scalar_is_zero(key); +} + +static int rustsecp256k1_v0_11_eckey_pubkey_tweak_add(rustsecp256k1_v0_11_ge *key, const rustsecp256k1_v0_11_scalar *tweak) { + rustsecp256k1_v0_11_gej pt; + rustsecp256k1_v0_11_gej_set_ge(&pt, key); + rustsecp256k1_v0_11_ecmult(&pt, &pt, &rustsecp256k1_v0_11_scalar_one, tweak); + + if (rustsecp256k1_v0_11_gej_is_infinity(&pt)) { + return 0; + } + rustsecp256k1_v0_11_ge_set_gej(key, &pt); + return 1; +} + +static int rustsecp256k1_v0_11_eckey_privkey_tweak_mul(rustsecp256k1_v0_11_scalar *key, const rustsecp256k1_v0_11_scalar *tweak) { + int ret; + ret = !rustsecp256k1_v0_11_scalar_is_zero(tweak); + + rustsecp256k1_v0_11_scalar_mul(key, key, tweak); + return ret; +} + +static int rustsecp256k1_v0_11_eckey_pubkey_tweak_mul(rustsecp256k1_v0_11_ge *key, const rustsecp256k1_v0_11_scalar *tweak) { + rustsecp256k1_v0_11_gej pt; + if (rustsecp256k1_v0_11_scalar_is_zero(tweak)) { + return 0; + } + + rustsecp256k1_v0_11_gej_set_ge(&pt, key); + rustsecp256k1_v0_11_ecmult(&pt, &pt, tweak, &rustsecp256k1_v0_11_scalar_zero); + rustsecp256k1_v0_11_ge_set_gej(key, &pt); + return 1; +} + +#endif /* SECP256K1_ECKEY_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult.h similarity index 66% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult.h index 6c8c5077..3eb3acf0 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult.h @@ -11,7 +11,18 @@ #include "scalar.h" #include "scratch.h" -/* Noone will ever need more than a window size of 24. The code might +#ifndef ECMULT_WINDOW_SIZE +# define ECMULT_WINDOW_SIZE 15 +# ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_MSG("ECMULT_WINDOW_SIZE undefined, assuming default value") +# endif +#endif + +#ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_DEF(ECMULT_WINDOW_SIZE) +#endif + +/* No one will ever need more than a window size of 24. The code might * be correct for larger values of ECMULT_WINDOW_SIZE but this is not * tested. * @@ -30,9 +41,9 @@ #define ECMULT_TABLE_SIZE(w) (1L << ((w)-2)) /** Double multiply: R = na*A + ng*G */ -static void rustsecp256k1zkp_v0_8_0_ecmult(rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_gej *a, const rustsecp256k1zkp_v0_8_0_scalar *na, const rustsecp256k1zkp_v0_8_0_scalar *ng); +static void rustsecp256k1_v0_11_ecmult(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_scalar *na, const rustsecp256k1_v0_11_scalar *ng); -typedef int (rustsecp256k1zkp_v0_8_0_ecmult_multi_callback)(rustsecp256k1zkp_v0_8_0_scalar *sc, rustsecp256k1zkp_v0_8_0_ge *pt, size_t idx, void *data); +typedef int (rustsecp256k1_v0_11_ecmult_multi_callback)(rustsecp256k1_v0_11_scalar *sc, rustsecp256k1_v0_11_ge *pt, size_t idx, void *data); /** * Multi-multiply: R = inp_g_sc * G + sum_i ni * Ai. @@ -45,6 +56,6 @@ typedef int (rustsecp256k1zkp_v0_8_0_ecmult_multi_callback)(rustsecp256k1zkp_v0_ * 0 if there is not enough scratch space for a single point or * callback returns 0 */ -static int rustsecp256k1zkp_v0_8_0_ecmult_multi_var(const rustsecp256k1zkp_v0_8_0_callback* error_callback, rustsecp256k1zkp_v0_8_0_scratch *scratch, rustsecp256k1zkp_v0_8_0_gej *r, const rustsecp256k1zkp_v0_8_0_scalar *inp_g_sc, rustsecp256k1zkp_v0_8_0_ecmult_multi_callback cb, void *cbdata, size_t n); +static int rustsecp256k1_v0_11_ecmult_multi_var(const rustsecp256k1_v0_11_callback* error_callback, rustsecp256k1_v0_11_scratch *scratch, rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_scalar *inp_g_sc, rustsecp256k1_v0_11_ecmult_multi_callback cb, void *cbdata, size_t n); #endif /* SECP256K1_ECMULT_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_compute_table.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_compute_table.h similarity index 61% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_compute_table.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_compute_table.h index 33cef0be..714fa004 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_compute_table.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_compute_table.h @@ -8,9 +8,9 @@ #define SECP256K1_ECMULT_COMPUTE_TABLE_H /* Construct table of all odd multiples of gen in range 1..(2**(window_g-1)-1). */ -static void rustsecp256k1zkp_v0_8_0_ecmult_compute_table(rustsecp256k1zkp_v0_8_0_ge_storage* table, int window_g, const rustsecp256k1zkp_v0_8_0_gej* gen); +static void rustsecp256k1_v0_11_ecmult_compute_table(rustsecp256k1_v0_11_ge_storage* table, int window_g, const rustsecp256k1_v0_11_gej* gen); -/* Like rustsecp256k1zkp_v0_8_0_ecmult_compute_table, but one for both gen and gen*2^128. */ -static void rustsecp256k1zkp_v0_8_0_ecmult_compute_two_tables(rustsecp256k1zkp_v0_8_0_ge_storage* table, rustsecp256k1zkp_v0_8_0_ge_storage* table_128, int window_g, const rustsecp256k1zkp_v0_8_0_ge* gen); +/* Like rustsecp256k1_v0_11_ecmult_compute_table, but one for both gen and gen*2^128. */ +static void rustsecp256k1_v0_11_ecmult_compute_two_tables(rustsecp256k1_v0_11_ge_storage* table, rustsecp256k1_v0_11_ge_storage* table_128, int window_g, const rustsecp256k1_v0_11_ge* gen); #endif /* SECP256K1_ECMULT_COMPUTE_TABLE_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_compute_table_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_compute_table_impl.h new file mode 100644 index 00000000..f8096f8c --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_compute_table_impl.h @@ -0,0 +1,49 @@ +/***************************************************************************************************** + * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + *****************************************************************************************************/ + +#ifndef SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H +#define SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H + +#include "ecmult_compute_table.h" +#include "group_impl.h" +#include "field_impl.h" +#include "ecmult.h" +#include "util.h" + +static void rustsecp256k1_v0_11_ecmult_compute_table(rustsecp256k1_v0_11_ge_storage* table, int window_g, const rustsecp256k1_v0_11_gej* gen) { + rustsecp256k1_v0_11_gej gj; + rustsecp256k1_v0_11_ge ge, dgen; + int j; + + gj = *gen; + rustsecp256k1_v0_11_ge_set_gej_var(&ge, &gj); + rustsecp256k1_v0_11_ge_to_storage(&table[0], &ge); + + rustsecp256k1_v0_11_gej_double_var(&gj, gen, NULL); + rustsecp256k1_v0_11_ge_set_gej_var(&dgen, &gj); + + for (j = 1; j < ECMULT_TABLE_SIZE(window_g); ++j) { + rustsecp256k1_v0_11_gej_set_ge(&gj, &ge); + rustsecp256k1_v0_11_gej_add_ge_var(&gj, &gj, &dgen, NULL); + rustsecp256k1_v0_11_ge_set_gej_var(&ge, &gj); + rustsecp256k1_v0_11_ge_to_storage(&table[j], &ge); + } +} + +/* Like rustsecp256k1_v0_11_ecmult_compute_table, but one for both gen and gen*2^128. */ +static void rustsecp256k1_v0_11_ecmult_compute_two_tables(rustsecp256k1_v0_11_ge_storage* table, rustsecp256k1_v0_11_ge_storage* table_128, int window_g, const rustsecp256k1_v0_11_ge* gen) { + rustsecp256k1_v0_11_gej gj; + int i; + + rustsecp256k1_v0_11_gej_set_ge(&gj, gen); + rustsecp256k1_v0_11_ecmult_compute_table(table, window_g, &gj); + for (i = 0; i < 128; ++i) { + rustsecp256k1_v0_11_gej_double_var(&gj, &gj, NULL); + } + rustsecp256k1_v0_11_ecmult_compute_table(table_128, window_g, &gj); +} + +#endif /* SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_const.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_const.h new file mode 100644 index 00000000..a13d4468 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_const.h @@ -0,0 +1,38 @@ +/*********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECMULT_CONST_H +#define SECP256K1_ECMULT_CONST_H + +#include "scalar.h" +#include "group.h" + +/** + * Multiply: R = q*A (in constant-time for q) + */ +static void rustsecp256k1_v0_11_ecmult_const(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_ge *a, const rustsecp256k1_v0_11_scalar *q); + +/** + * Same as rustsecp256k1_v0_11_ecmult_const, but takes in an x coordinate of the base point + * only, specified as fraction n/d (numerator/denominator). Only the x coordinate of the result is + * returned. + * + * If known_on_curve is 0, a verification is performed that n/d is a valid X + * coordinate, and 0 is returned if not. Otherwise, 1 is returned. + * + * d being NULL is interpreted as d=1. If non-NULL, d must not be zero. q must not be zero. + * + * Constant time in the value of q, but not any other inputs. + */ +static int rustsecp256k1_v0_11_ecmult_const_xonly( + rustsecp256k1_v0_11_fe *r, + const rustsecp256k1_v0_11_fe *n, + const rustsecp256k1_v0_11_fe *d, + const rustsecp256k1_v0_11_scalar *q, + int known_on_curve +); + +#endif /* SECP256K1_ECMULT_CONST_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_const_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_const_impl.h new file mode 100644 index 00000000..ba258de9 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_const_impl.h @@ -0,0 +1,399 @@ +/*********************************************************************** + * Copyright (c) 2015, 2022 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECMULT_CONST_IMPL_H +#define SECP256K1_ECMULT_CONST_IMPL_H + +#include "scalar.h" +#include "group.h" +#include "ecmult_const.h" +#include "ecmult_impl.h" + +#if defined(EXHAUSTIVE_TEST_ORDER) +/* We need 2^ECMULT_CONST_GROUP_SIZE - 1 to be less than EXHAUSTIVE_TEST_ORDER, because + * the tables cannot have infinities in them (this breaks the effective-affine technique's + * z-ratio tracking) */ +# if EXHAUSTIVE_TEST_ORDER == 199 +# define ECMULT_CONST_GROUP_SIZE 4 +# elif EXHAUSTIVE_TEST_ORDER == 13 +# define ECMULT_CONST_GROUP_SIZE 3 +# elif EXHAUSTIVE_TEST_ORDER == 7 +# define ECMULT_CONST_GROUP_SIZE 2 +# else +# error "Unknown EXHAUSTIVE_TEST_ORDER" +# endif +#else +/* Group size 4 or 5 appears optimal. */ +# define ECMULT_CONST_GROUP_SIZE 5 +#endif + +#define ECMULT_CONST_TABLE_SIZE (1L << (ECMULT_CONST_GROUP_SIZE - 1)) +#define ECMULT_CONST_GROUPS ((129 + ECMULT_CONST_GROUP_SIZE - 1) / ECMULT_CONST_GROUP_SIZE) +#define ECMULT_CONST_BITS (ECMULT_CONST_GROUPS * ECMULT_CONST_GROUP_SIZE) + +/** Fill a table 'pre' with precomputed odd multiples of a. + * + * The resulting point set is brought to a single constant Z denominator, stores the X and Y + * coordinates as ge points in pre, and stores the global Z in globalz. + * + * 'pre' must be an array of size ECMULT_CONST_TABLE_SIZE. + */ +static void rustsecp256k1_v0_11_ecmult_const_odd_multiples_table_globalz(rustsecp256k1_v0_11_ge *pre, rustsecp256k1_v0_11_fe *globalz, const rustsecp256k1_v0_11_gej *a) { + rustsecp256k1_v0_11_fe zr[ECMULT_CONST_TABLE_SIZE]; + + rustsecp256k1_v0_11_ecmult_odd_multiples_table(ECMULT_CONST_TABLE_SIZE, pre, zr, globalz, a); + rustsecp256k1_v0_11_ge_table_set_globalz(ECMULT_CONST_TABLE_SIZE, pre, zr); +} + +/* Given a table 'pre' with odd multiples of a point, put in r the signed-bit multiplication of n with that point. + * + * For example, if ECMULT_CONST_GROUP_SIZE is 4, then pre is expected to contain 8 entries: + * [1*P, 3*P, 5*P, 7*P, 9*P, 11*P, 13*P, 15*P]. n is then expected to be a 4-bit integer (range 0-15), and its + * bits are interpreted as signs of powers of two to look up. + * + * For example, if n=4, which is 0100 in binary, which is interpreted as [- + - -], so the looked up value is + * [ -(2^3) + (2^2) - (2^1) - (2^0) ]*P = -7*P. Every valid n translates to an odd number in range [-15,15], + * which means we just need to look up one of the precomputed values, and optionally negate it. + */ +#define ECMULT_CONST_TABLE_GET_GE(r,pre,n) do { \ + unsigned int m = 0; \ + /* If the top bit of n is 0, we want the negation. */ \ + volatile unsigned int negative = ((n) >> (ECMULT_CONST_GROUP_SIZE - 1)) ^ 1; \ + /* Let n[i] be the i-th bit of n, then the index is + * sum(cnot(n[i]) * 2^i, i=0..l-2) + * where cnot(b) = b if n[l-1] = 1 and 1 - b otherwise. + * For example, if n = 4, in binary 0100, the index is 3, in binary 011. + * + * Proof: + * Let + * x = sum((2*n[i] - 1)*2^i, i=0..l-1) + * = 2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 1 + * be the value represented by n. + * The index is (x - 1)/2 if x > 0 and -(x + 1)/2 otherwise. + * Case x > 0: + * n[l-1] = 1 + * index = sum(n[i] * 2^i, i=0..l-1) - 2^(l-1) + * = sum(n[i] * 2^i, i=0..l-2) + * Case x <= 0: + * n[l-1] = 0 + * index = -(2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 2)/2 + * = 2^(l-1) - 1 - sum(n[i] * 2^i, i=0..l-1) + * = sum((1 - n[i]) * 2^i, i=0..l-2) + */ \ + unsigned int index = ((unsigned int)(-negative) ^ n) & ((1U << (ECMULT_CONST_GROUP_SIZE - 1)) - 1U); \ + rustsecp256k1_v0_11_fe neg_y; \ + VERIFY_CHECK((n) < (1U << ECMULT_CONST_GROUP_SIZE)); \ + VERIFY_CHECK(index < (1U << (ECMULT_CONST_GROUP_SIZE - 1))); \ + /* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one + * or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \ + (r)->x = (pre)[m].x; \ + (r)->y = (pre)[m].y; \ + for (m = 1; m < ECMULT_CONST_TABLE_SIZE; m++) { \ + /* This loop is used to avoid secret data in array indices. See + * the comment in ecmult_gen_impl.h for rationale. */ \ + rustsecp256k1_v0_11_fe_cmov(&(r)->x, &(pre)[m].x, m == index); \ + rustsecp256k1_v0_11_fe_cmov(&(r)->y, &(pre)[m].y, m == index); \ + } \ + (r)->infinity = 0; \ + rustsecp256k1_v0_11_fe_negate(&neg_y, &(r)->y, 1); \ + rustsecp256k1_v0_11_fe_cmov(&(r)->y, &neg_y, negative); \ +} while(0) + +/* For K as defined in the comment of rustsecp256k1_v0_11_ecmult_const, we have several precomputed + * formulas/constants. + * - in exhaustive test mode, we give an explicit expression to compute it at compile time: */ +#ifdef EXHAUSTIVE_TEST_ORDER +static const rustsecp256k1_v0_11_scalar rustsecp256k1_v0_11_ecmult_const_K = ((SECP256K1_SCALAR_CONST(0, 0, 0, (1U << (ECMULT_CONST_BITS - 128)) - 2U, 0, 0, 0, 0) + EXHAUSTIVE_TEST_ORDER - 1U) * (1U + EXHAUSTIVE_TEST_LAMBDA)) % EXHAUSTIVE_TEST_ORDER; +/* - for the real secp256k1 group we have constants for various ECMULT_CONST_BITS values. */ +#elif ECMULT_CONST_BITS == 129 +/* For GROUP_SIZE = 1,3. */ +static const rustsecp256k1_v0_11_scalar rustsecp256k1_v0_11_ecmult_const_K = SECP256K1_SCALAR_CONST(0xac9c52b3ul, 0x3fa3cf1ful, 0x5ad9e3fdul, 0x77ed9ba4ul, 0xa880b9fcul, 0x8ec739c2ul, 0xe0cfc810ul, 0xb51283ceul); +#elif ECMULT_CONST_BITS == 130 +/* For GROUP_SIZE = 2,5. */ +static const rustsecp256k1_v0_11_scalar rustsecp256k1_v0_11_ecmult_const_K = SECP256K1_SCALAR_CONST(0xa4e88a7dul, 0xcb13034eul, 0xc2bdd6bful, 0x7c118d6bul, 0x589ae848ul, 0x26ba29e4ul, 0xb5c2c1dcul, 0xde9798d9ul); +#elif ECMULT_CONST_BITS == 132 +/* For GROUP_SIZE = 4,6 */ +static const rustsecp256k1_v0_11_scalar rustsecp256k1_v0_11_ecmult_const_K = SECP256K1_SCALAR_CONST(0x76b1d93dul, 0x0fae3c6bul, 0x3215874bul, 0x94e93813ul, 0x7937fe0dul, 0xb66bcaaful, 0xb3749ca5ul, 0xd7b6171bul); +#else +# error "Unknown ECMULT_CONST_BITS" +#endif + +static void rustsecp256k1_v0_11_ecmult_const(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_ge *a, const rustsecp256k1_v0_11_scalar *q) { + /* The approach below combines the signed-digit logic from Mike Hamburg's + * "Fast and compact elliptic-curve cryptography" (https://eprint.iacr.org/2012/309) + * Section 3.3, with the GLV endomorphism. + * + * The idea there is to interpret the bits of a scalar as signs (1 = +, 0 = -), and compute a + * point multiplication in that fashion. Let v be an n-bit non-negative integer (0 <= v < 2^n), + * and v[i] its i'th bit (so v = sum(v[i] * 2^i, i=0..n-1)). Then define: + * + * C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1) + * + * Then it holds that C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1) + * = (2*sum(v[i] * 2^i, i=0..l-1) + 1 - 2^l) * A + * = (2*v + 1 - 2^l) * A + * + * Thus, one can compute q*A as C_256((q + 2^256 - 1) / 2, A). This is the basis for the + * paper's signed-digit multi-comb algorithm for multiplication using a precomputed table. + * + * It is appealing to try to combine this with the GLV optimization: the idea that a scalar + * s can be written as s1 + lambda*s2, where lambda is a curve-specific constant such that + * lambda*A is easy to compute, and where s1 and s2 are small. In particular we have the + * rustsecp256k1_v0_11_scalar_split_lambda function which performs such a split with the resulting s1 + * and s2 in range (-2^128, 2^128) mod n. This does work, but is uninteresting: + * + * To compute q*A: + * - Let s1, s2 = split_lambda(q) + * - Let R1 = C_256((s1 + 2^256 - 1) / 2, A) + * - Let R2 = C_256((s2 + 2^256 - 1) / 2, lambda*A) + * - Return R1 + R2 + * + * The issue is that while s1 and s2 are small-range numbers, (s1 + 2^256 - 1) / 2 (mod n) + * and (s2 + 2^256 - 1) / 2 (mod n) are not, undoing the benefit of the splitting. + * + * To make it work, we want to modify the input scalar q first, before splitting, and then only + * add a 2^128 offset of the split results (so that they end up in the single 129-bit range + * [0,2^129]). A slightly smaller offset would work due to the bounds on the split, but we pick + * 2^128 for simplicity. Let s be the scalar fed to split_lambda, and f(q) the function to + * compute it from q: + * + * To compute q*A: + * - Compute s = f(q) + * - Let s1, s2 = split_lambda(s) + * - Let v1 = s1 + 2^128 (mod n) + * - Let v2 = s2 + 2^128 (mod n) + * - Let R1 = C_l(v1, A) + * - Let R2 = C_l(v2, lambda*A) + * - Return R1 + R2 + * + * l will thus need to be at least 129, but we may overshoot by a few bits (see + * further), so keep it as a variable. + * + * To solve for s, we reason: + * q*A = R1 + R2 + * <=> q*A = C_l(s1 + 2^128, A) + C_l(s2 + 2^128, lambda*A) + * <=> q*A = (2*(s1 + 2^128) + 1 - 2^l) * A + (2*(s2 + 2^128) + 1 - 2^l) * lambda*A + * <=> q*A = (2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda)) * A + * <=> q = 2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda) (mod n) + * <=> q = 2*s + (2^129 + 1 - 2^l) * (1 + lambda) (mod n) + * <=> s = (q + (2^l - 2^129 - 1) * (1 + lambda)) / 2 (mod n) + * <=> f(q) = (q + K) / 2 (mod n) + * where K = (2^l - 2^129 - 1)*(1 + lambda) (mod n) + * + * We will process the computation of C_l(v1, A) and C_l(v2, lambda*A) in groups of + * ECMULT_CONST_GROUP_SIZE, so we set l to the smallest multiple of ECMULT_CONST_GROUP_SIZE + * that is not less than 129; this equals ECMULT_CONST_BITS. + */ + + /* The offset to add to s1 and s2 to make them non-negative. Equal to 2^128. */ + static const rustsecp256k1_v0_11_scalar S_OFFSET = SECP256K1_SCALAR_CONST(0, 0, 0, 1, 0, 0, 0, 0); + rustsecp256k1_v0_11_scalar s, v1, v2; + rustsecp256k1_v0_11_ge pre_a[ECMULT_CONST_TABLE_SIZE]; + rustsecp256k1_v0_11_ge pre_a_lam[ECMULT_CONST_TABLE_SIZE]; + rustsecp256k1_v0_11_fe global_z; + int group, i; + + /* We're allowed to be non-constant time in the point, and the code below (in particular, + * rustsecp256k1_v0_11_ecmult_const_odd_multiples_table_globalz) cannot deal with infinity in a + * constant-time manner anyway. */ + if (rustsecp256k1_v0_11_ge_is_infinity(a)) { + rustsecp256k1_v0_11_gej_set_infinity(r); + return; + } + + /* Compute v1 and v2. */ + rustsecp256k1_v0_11_scalar_add(&s, q, &rustsecp256k1_v0_11_ecmult_const_K); + rustsecp256k1_v0_11_scalar_half(&s, &s); + rustsecp256k1_v0_11_scalar_split_lambda(&v1, &v2, &s); + rustsecp256k1_v0_11_scalar_add(&v1, &v1, &S_OFFSET); + rustsecp256k1_v0_11_scalar_add(&v2, &v2, &S_OFFSET); + +#ifdef VERIFY + /* Verify that v1 and v2 are in range [0, 2^129-1]. */ + for (i = 129; i < 256; ++i) { + VERIFY_CHECK(rustsecp256k1_v0_11_scalar_get_bits_limb32(&v1, i, 1) == 0); + VERIFY_CHECK(rustsecp256k1_v0_11_scalar_get_bits_limb32(&v2, i, 1) == 0); + } +#endif + + /* Calculate odd multiples of A and A*lambda. + * All multiples are brought to the same Z 'denominator', which is stored + * in global_z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + */ + rustsecp256k1_v0_11_gej_set_ge(r, a); + rustsecp256k1_v0_11_ecmult_const_odd_multiples_table_globalz(pre_a, &global_z, r); + for (i = 0; i < ECMULT_CONST_TABLE_SIZE; i++) { + rustsecp256k1_v0_11_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); + } + + /* Next, we compute r = C_l(v1, A) + C_l(v2, lambda*A). + * + * We proceed in groups of ECMULT_CONST_GROUP_SIZE bits, operating on that many bits + * at a time, from high in v1, v2 to low. Call these bits1 (from v1) and bits2 (from v2). + * + * Now note that ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1) loads into t a point equal + * to C_{ECMULT_CONST_GROUP_SIZE}(bits1, A), and analogously for pre_lam_a / bits2. + * This means that all we need to do is add these looked up values together, multiplied + * by 2^(ECMULT_GROUP_SIZE * group). + */ + for (group = ECMULT_CONST_GROUPS - 1; group >= 0; --group) { + /* Using the _var get_bits function is ok here, since it's only variable in offset and count, not in the scalar. */ + unsigned int bits1 = rustsecp256k1_v0_11_scalar_get_bits_var(&v1, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE); + unsigned int bits2 = rustsecp256k1_v0_11_scalar_get_bits_var(&v2, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE); + rustsecp256k1_v0_11_ge t; + int j; + + ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1); + if (group == ECMULT_CONST_GROUPS - 1) { + /* Directly set r in the first iteration. */ + rustsecp256k1_v0_11_gej_set_ge(r, &t); + } else { + /* Shift the result so far up. */ + for (j = 0; j < ECMULT_CONST_GROUP_SIZE; ++j) { + rustsecp256k1_v0_11_gej_double(r, r); + } + rustsecp256k1_v0_11_gej_add_ge(r, r, &t); + } + ECMULT_CONST_TABLE_GET_GE(&t, pre_a_lam, bits2); + rustsecp256k1_v0_11_gej_add_ge(r, r, &t); + } + + /* Map the result back to the secp256k1 curve from the isomorphic curve. */ + rustsecp256k1_v0_11_fe_mul(&r->z, &r->z, &global_z); +} + +static int rustsecp256k1_v0_11_ecmult_const_xonly(rustsecp256k1_v0_11_fe* r, const rustsecp256k1_v0_11_fe *n, const rustsecp256k1_v0_11_fe *d, const rustsecp256k1_v0_11_scalar *q, int known_on_curve) { + + /* This algorithm is a generalization of Peter Dettman's technique for + * avoiding the square root in a random-basepoint x-only multiplication + * on a Weierstrass curve: + * https://mailarchive.ietf.org/arch/msg/cfrg/7DyYY6gg32wDgHAhgSb6XxMDlJA/ + * + * + * === Background: the effective affine technique === + * + * Let phi_u be the isomorphism that maps (x, y) on secp256k1 curve y^2 = x^3 + 7 to + * x' = u^2*x, y' = u^3*y on curve y'^2 = x'^3 + u^6*7. This new curve has the same order as + * the original (it is isomorphic), but moreover, has the same addition/doubling formulas, as + * the curve b=7 coefficient does not appear in those formulas (or at least does not appear in + * the formulas implemented in this codebase, both affine and Jacobian). See also Example 9.5.2 + * in https://www.math.auckland.ac.nz/~sgal018/crypto-book/ch9.pdf. + * + * This means any linear combination of secp256k1 points can be computed by applying phi_u + * (with non-zero u) on all input points (including the generator, if used), computing the + * linear combination on the isomorphic curve (using the same group laws), and then applying + * phi_u^{-1} to get back to secp256k1. + * + * Switching to Jacobian coordinates, note that phi_u applied to (X, Y, Z) is simply + * (X, Y, Z/u). Thus, if we want to compute (X1, Y1, Z) + (X2, Y2, Z), with identical Z + * coordinates, we can use phi_Z to transform it to (X1, Y1, 1) + (X2, Y2, 1) on an isomorphic + * curve where the affine addition formula can be used instead. + * If (X3, Y3, Z3) = (X1, Y1) + (X2, Y2) on that curve, then our answer on secp256k1 is + * (X3, Y3, Z3*Z). + * + * This is the effective affine technique: if we have a linear combination of group elements + * to compute, and all those group elements have the same Z coordinate, we can simply pretend + * that all those Z coordinates are 1, perform the computation that way, and then multiply the + * original Z coordinate back in. + * + * The technique works on any a=0 short Weierstrass curve. It is possible to generalize it to + * other curves too, but there the isomorphic curves will have different 'a' coefficients, + * which typically does affect the group laws. + * + * + * === Avoiding the square root for x-only point multiplication === + * + * In this function, we want to compute the X coordinate of q*(n/d, y), for + * y = sqrt((n/d)^3 + 7). Its negation would also be a valid Y coordinate, but by convention + * we pick whatever sqrt returns (which we assume to be a deterministic function). + * + * Let g = y^2*d^3 = n^3 + 7*d^3. This also means y = sqrt(g/d^3). + * Further let v = sqrt(d*g), which must exist as d*g = y^2*d^4 = (y*d^2)^2. + * + * The input point (n/d, y) also has Jacobian coordinates: + * + * (n/d, y, 1) + * = (n/d * v^2, y * v^3, v) + * = (n/d * d*g, y * sqrt(d^3*g^3), v) + * = (n/d * d*g, sqrt(y^2 * d^3*g^3), v) + * = (n*g, sqrt(g/d^3 * d^3*g^3), v) + * = (n*g, sqrt(g^4), v) + * = (n*g, g^2, v) + * + * It is easy to verify that both (n*g, g^2, v) and its negation (n*g, -g^2, v) have affine X + * coordinate n/d, and this holds even when the square root function doesn't have a + * deterministic sign. We choose the (n*g, g^2, v) version. + * + * Now switch to the effective affine curve using phi_v, where the input point has coordinates + * (n*g, g^2). Compute (X, Y, Z) = q * (n*g, g^2) there. + * + * Back on secp256k1, that means q * (n*g, g^2, v) = (X, Y, v*Z). This last point has affine X + * coordinate X / (v^2*Z^2) = X / (d*g*Z^2). Determining the affine Y coordinate would involve + * a square root, but as long as we only care about the resulting X coordinate, no square root + * is needed anywhere in this computation. + */ + + rustsecp256k1_v0_11_fe g, i; + rustsecp256k1_v0_11_ge p; + rustsecp256k1_v0_11_gej rj; + + /* Compute g = (n^3 + B*d^3). */ + rustsecp256k1_v0_11_fe_sqr(&g, n); + rustsecp256k1_v0_11_fe_mul(&g, &g, n); + if (d) { + rustsecp256k1_v0_11_fe b; + VERIFY_CHECK(!rustsecp256k1_v0_11_fe_normalizes_to_zero(d)); + rustsecp256k1_v0_11_fe_sqr(&b, d); + VERIFY_CHECK(SECP256K1_B <= 8); /* magnitude of b will be <= 8 after the next call */ + rustsecp256k1_v0_11_fe_mul_int(&b, SECP256K1_B); + rustsecp256k1_v0_11_fe_mul(&b, &b, d); + rustsecp256k1_v0_11_fe_add(&g, &b); + if (!known_on_curve) { + /* We need to determine whether (n/d)^3 + 7 is square. + * + * is_square((n/d)^3 + 7) + * <=> is_square(((n/d)^3 + 7) * d^4) + * <=> is_square((n^3 + 7*d^3) * d) + * <=> is_square(g * d) + */ + rustsecp256k1_v0_11_fe c; + rustsecp256k1_v0_11_fe_mul(&c, &g, d); + if (!rustsecp256k1_v0_11_fe_is_square_var(&c)) return 0; + } + } else { + rustsecp256k1_v0_11_fe_add_int(&g, SECP256K1_B); + if (!known_on_curve) { + /* g at this point equals x^3 + 7. Test if it is square. */ + if (!rustsecp256k1_v0_11_fe_is_square_var(&g)) return 0; + } + } + + /* Compute base point P = (n*g, g^2), the effective affine version of (n*g, g^2, v), which has + * corresponding affine X coordinate n/d. */ + rustsecp256k1_v0_11_fe_mul(&p.x, &g, n); + rustsecp256k1_v0_11_fe_sqr(&p.y, &g); + p.infinity = 0; + + /* Perform x-only EC multiplication of P with q. */ + VERIFY_CHECK(!rustsecp256k1_v0_11_scalar_is_zero(q)); + rustsecp256k1_v0_11_ecmult_const(&rj, &p, q); + VERIFY_CHECK(!rustsecp256k1_v0_11_gej_is_infinity(&rj)); + + /* The resulting (X, Y, Z) point on the effective-affine isomorphic curve corresponds to + * (X, Y, Z*v) on the secp256k1 curve. The affine version of that has X coordinate + * (X / (Z^2*d*g)). */ + rustsecp256k1_v0_11_fe_sqr(&i, &rj.z); + rustsecp256k1_v0_11_fe_mul(&i, &i, &g); + if (d) rustsecp256k1_v0_11_fe_mul(&i, &i, d); + rustsecp256k1_v0_11_fe_inv(&i, &i); + rustsecp256k1_v0_11_fe_mul(r, &rj.x, &i); + + return 1; +} + +#endif /* SECP256K1_ECMULT_CONST_IMPL_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_gen.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_gen.h new file mode 100644 index 00000000..10f73288 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_gen.h @@ -0,0 +1,143 @@ +/*********************************************************************** + * Copyright (c) Pieter Wuille, Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECMULT_GEN_H +#define SECP256K1_ECMULT_GEN_H + +#include "scalar.h" +#include "group.h" + + +/* Configuration parameters for the signed-digit multi-comb algorithm: + * + * - COMB_BLOCKS is the number of blocks the input is split into. Each + * has a corresponding table. + * - COMB_TEETH is the number of bits simultaneously covered by one table. + * - COMB_RANGE is the number of bits in supported scalars. For production + * purposes, only 256 is reasonable, but smaller numbers are supported for + * exhaustive test mode. + * + * The comb's spacing (COMB_SPACING), or the distance between the teeth, + * is defined as ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)). Each block covers + * COMB_SPACING * COMB_TEETH consecutive bits in the input. + * + * The size of the precomputed table is COMB_BLOCKS * (1 << (COMB_TEETH - 1)) + * rustsecp256k1_v0_11_ge_storages. + * + * The number of point additions equals COMB_BLOCKS * COMB_SPACING. Each point + * addition involves a cmov from (1 << (COMB_TEETH - 1)) table entries and a + * conditional negation. + * + * The number of point doublings is COMB_SPACING - 1. */ + +#if defined(EXHAUSTIVE_TEST_ORDER) +/* We need to control these values for exhaustive tests because + * the table cannot have infinities in them (rustsecp256k1_v0_11_ge_storage + * doesn't support infinities) */ +# undef COMB_BLOCKS +# undef COMB_TEETH +# if EXHAUSTIVE_TEST_ORDER == 7 +# define COMB_RANGE 3 +# define COMB_BLOCKS 1 +# define COMB_TEETH 2 +# elif EXHAUSTIVE_TEST_ORDER == 13 +# define COMB_RANGE 4 +# define COMB_BLOCKS 1 +# define COMB_TEETH 2 +# elif EXHAUSTIVE_TEST_ORDER == 199 +# define COMB_RANGE 8 +# define COMB_BLOCKS 2 +# define COMB_TEETH 3 +# else +# error "Unknown exhaustive test order" +# endif +# if (COMB_RANGE >= 32) || ((EXHAUSTIVE_TEST_ORDER >> (COMB_RANGE - 1)) != 1) +# error "COMB_RANGE != ceil(log2(EXHAUSTIVE_TEST_ORDER+1))" +# endif +#else /* !defined(EXHAUSTIVE_TEST_ORDER) */ +# define COMB_RANGE 256 +#endif /* defined(EXHAUSTIVE_TEST_ORDER) */ + +/* Use (11, 6) as default configuration, which results in a 22 kB table. */ +#ifndef COMB_BLOCKS +# define COMB_BLOCKS 11 +# ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_MSG("COMB_BLOCKS undefined, assuming default value") +# endif +#endif +#ifndef COMB_TEETH +# define COMB_TEETH 6 +# ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_MSG("COMB_TEETH undefined, assuming default value") +# endif +#endif +/* Use ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)) as COMB_SPACING. */ +#define COMB_SPACING CEIL_DIV(COMB_RANGE, COMB_BLOCKS * COMB_TEETH) + +/* Range checks on the parameters. */ + +/* The remaining COMB_* parameters are derived values, don't modify these. */ +/* - The number of bits covered by all the blocks; must be at least COMB_RANGE. */ +#define COMB_BITS (COMB_BLOCKS * COMB_TEETH * COMB_SPACING) +/* - The number of entries per table. */ +#define COMB_POINTS (1 << (COMB_TEETH - 1)) + +/* Sanity checks. */ +#if !(1 <= COMB_BLOCKS && COMB_BLOCKS <= 256) +# error "COMB_BLOCKS must be in the range [1, 256]" +#endif +#if !(1 <= COMB_TEETH && COMB_TEETH <= 8) +# error "COMB_TEETH must be in the range [1, 8]" +#endif +#if COMB_BITS < COMB_RANGE +# error "COMB_BLOCKS * COMB_TEETH * COMB_SPACING is too low" +#endif + +/* These last 2 checks are not strictly required, but prevent gratuitously inefficient + * configurations. Note that they compare with 256 rather than COMB_RANGE, so they do + * permit somewhat excessive values for the exhaustive test case, where testing with + * suboptimal parameters may be desirable. */ +#if (COMB_BLOCKS - 1) * COMB_TEETH * COMB_SPACING >= 256 +# error "COMB_BLOCKS can be reduced" +#endif +#if COMB_BLOCKS * (COMB_TEETH - 1) * COMB_SPACING >= 256 +# error "COMB_TEETH can be reduced" +#endif + +#ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_DEF(COMB_RANGE) +# pragma message DEBUG_CONFIG_DEF(COMB_BLOCKS) +# pragma message DEBUG_CONFIG_DEF(COMB_TEETH) +# pragma message DEBUG_CONFIG_DEF(COMB_SPACING) +#endif + +typedef struct { + /* Whether the context has been built. */ + int built; + + /* Values chosen such that + * + * n*G == comb(n + scalar_offset, G/2) + ge_offset. + * + * This expression lets us use scalar blinding and optimize the comb precomputation. See + * ecmult_gen_impl.h for more details. */ + rustsecp256k1_v0_11_scalar scalar_offset; + rustsecp256k1_v0_11_ge ge_offset; + + /* Factor used for projective blinding. This value is used to rescale the Z + * coordinate of the first table lookup. */ + rustsecp256k1_v0_11_fe proj_blind; +} rustsecp256k1_v0_11_ecmult_gen_context; + +static void rustsecp256k1_v0_11_ecmult_gen_context_build(rustsecp256k1_v0_11_ecmult_gen_context* ctx); +static void rustsecp256k1_v0_11_ecmult_gen_context_clear(rustsecp256k1_v0_11_ecmult_gen_context* ctx); + +/** Multiply with the generator: R = a*G */ +static void rustsecp256k1_v0_11_ecmult_gen(const rustsecp256k1_v0_11_ecmult_gen_context* ctx, rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_scalar *a); + +static void rustsecp256k1_v0_11_ecmult_gen_blind(rustsecp256k1_v0_11_ecmult_gen_context *ctx, const unsigned char *seed32); + +#endif /* SECP256K1_ECMULT_GEN_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_gen_compute_table.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_gen_compute_table.h similarity index 66% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_gen_compute_table.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_gen_compute_table.h index 25d21afb..66690174 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/ecmult_gen_compute_table.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_gen_compute_table.h @@ -1,5 +1,5 @@ /*********************************************************************** - * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * + * Copyright (c) Pieter Wuille, Gregory Maxwell * * Distributed under the MIT software license, see the accompanying * * file COPYING or https://www.opensource.org/licenses/mit-license.php.* ***********************************************************************/ @@ -9,6 +9,6 @@ #include "ecmult_gen.h" -static void rustsecp256k1zkp_v0_8_0_ecmult_gen_compute_table(rustsecp256k1zkp_v0_8_0_ge_storage* table, const rustsecp256k1zkp_v0_8_0_ge* gen, int bits); +static void rustsecp256k1_v0_11_ecmult_gen_compute_table(rustsecp256k1_v0_11_ge_storage* table, const rustsecp256k1_v0_11_ge* gen, int blocks, int teeth, int spacing); #endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_gen_compute_table_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_gen_compute_table_impl.h new file mode 100644 index 00000000..4d44ccc9 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_gen_compute_table_impl.h @@ -0,0 +1,108 @@ +/*********************************************************************** + * Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H +#define SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H + +#include "ecmult_gen_compute_table.h" +#include "group_impl.h" +#include "field_impl.h" +#include "scalar_impl.h" +#include "ecmult_gen.h" +#include "util.h" + +static void rustsecp256k1_v0_11_ecmult_gen_compute_table(rustsecp256k1_v0_11_ge_storage* table, const rustsecp256k1_v0_11_ge* gen, int blocks, int teeth, int spacing) { + size_t points = ((size_t)1) << (teeth - 1); + size_t points_total = points * blocks; + rustsecp256k1_v0_11_ge* prec = checked_malloc(&default_error_callback, points_total * sizeof(*prec)); + rustsecp256k1_v0_11_gej* ds = checked_malloc(&default_error_callback, teeth * sizeof(*ds)); + rustsecp256k1_v0_11_gej* vs = checked_malloc(&default_error_callback, points_total * sizeof(*vs)); + rustsecp256k1_v0_11_gej u; + size_t vs_pos = 0; + rustsecp256k1_v0_11_scalar half; + int block, i; + + VERIFY_CHECK(points_total > 0); + + /* u is the running power of two times gen we're working with, initially gen/2. */ + rustsecp256k1_v0_11_scalar_half(&half, &rustsecp256k1_v0_11_scalar_one); + rustsecp256k1_v0_11_gej_set_infinity(&u); + for (i = 255; i >= 0; --i) { + /* Use a very simple multiplication ladder to avoid dependency on ecmult. */ + rustsecp256k1_v0_11_gej_double_var(&u, &u, NULL); + if (rustsecp256k1_v0_11_scalar_get_bits_limb32(&half, i, 1)) { + rustsecp256k1_v0_11_gej_add_ge_var(&u, &u, gen, NULL); + } + } +#ifdef VERIFY + { + /* Verify that u*2 = gen. */ + rustsecp256k1_v0_11_gej double_u; + rustsecp256k1_v0_11_gej_double_var(&double_u, &u, NULL); + VERIFY_CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&double_u, gen)); + } +#endif + + for (block = 0; block < blocks; ++block) { + int tooth; + /* Here u = 2^(block*teeth*spacing) * gen/2. */ + rustsecp256k1_v0_11_gej sum; + rustsecp256k1_v0_11_gej_set_infinity(&sum); + for (tooth = 0; tooth < teeth; ++tooth) { + /* Here u = 2^((block*teeth + tooth)*spacing) * gen/2. */ + /* Make sum = sum(2^((block*teeth + t)*spacing), t=0..tooth) * gen/2. */ + rustsecp256k1_v0_11_gej_add_var(&sum, &sum, &u, NULL); + /* Make u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */ + rustsecp256k1_v0_11_gej_double_var(&u, &u, NULL); + /* Make ds[tooth] = u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */ + ds[tooth] = u; + /* Make u = 2^((block*teeth + tooth + 1)*spacing) * gen/2, unless at the end. */ + if (block + tooth != blocks + teeth - 2) { + int bit_off; + for (bit_off = 1; bit_off < spacing; ++bit_off) { + rustsecp256k1_v0_11_gej_double_var(&u, &u, NULL); + } + } + } + /* Now u = 2^((block*teeth + teeth)*spacing) * gen/2 + * = 2^((block+1)*teeth*spacing) * gen/2 */ + + /* Next, compute the table entries for block number block in Jacobian coordinates. + * The entries will occupy vs[block*points + i] for i=0..points-1. + * We start by computing the first (i=0) value corresponding to all summed + * powers of two times G being negative. */ + rustsecp256k1_v0_11_gej_neg(&vs[vs_pos++], &sum); + /* And then teeth-1 times "double" the range of i values for which the table + * is computed: in each iteration, double the table by taking an existing + * table entry and adding ds[tooth]. */ + for (tooth = 0; tooth < teeth - 1; ++tooth) { + size_t stride = ((size_t)1) << tooth; + size_t index; + for (index = 0; index < stride; ++index, ++vs_pos) { + rustsecp256k1_v0_11_gej_add_var(&vs[vs_pos], &vs[vs_pos - stride], &ds[tooth], NULL); + } + } + } + VERIFY_CHECK(vs_pos == points_total); + + /* Convert all points simultaneously from rustsecp256k1_v0_11_gej to rustsecp256k1_v0_11_ge. */ + rustsecp256k1_v0_11_ge_set_all_gej_var(prec, vs, points_total); + /* Convert all points from rustsecp256k1_v0_11_ge to rustsecp256k1_v0_11_ge_storage output. */ + for (block = 0; block < blocks; ++block) { + size_t index; + for (index = 0; index < points; ++index) { + VERIFY_CHECK(!rustsecp256k1_v0_11_ge_is_infinity(&prec[block * points + index])); + rustsecp256k1_v0_11_ge_to_storage(&table[block * points + index], &prec[block * points + index]); + } + } + + /* Free memory. */ + free(vs); + free(ds); + free(prec); +} + +#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_gen_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_gen_impl.h new file mode 100644 index 00000000..b6cf0cd9 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_gen_impl.h @@ -0,0 +1,341 @@ +/*********************************************************************** + * Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECMULT_GEN_IMPL_H +#define SECP256K1_ECMULT_GEN_IMPL_H + +#include "util.h" +#include "scalar.h" +#include "group.h" +#include "ecmult_gen.h" +#include "hash_impl.h" +#include "precomputed_ecmult_gen.h" + +static void rustsecp256k1_v0_11_ecmult_gen_context_build(rustsecp256k1_v0_11_ecmult_gen_context *ctx) { + rustsecp256k1_v0_11_ecmult_gen_blind(ctx, NULL); + ctx->built = 1; +} + +static int rustsecp256k1_v0_11_ecmult_gen_context_is_built(const rustsecp256k1_v0_11_ecmult_gen_context* ctx) { + return ctx->built; +} + +static void rustsecp256k1_v0_11_ecmult_gen_context_clear(rustsecp256k1_v0_11_ecmult_gen_context *ctx) { + ctx->built = 0; + rustsecp256k1_v0_11_scalar_clear(&ctx->scalar_offset); + rustsecp256k1_v0_11_ge_clear(&ctx->ge_offset); + rustsecp256k1_v0_11_fe_clear(&ctx->proj_blind); +} + +/* Compute the scalar (2^COMB_BITS - 1) / 2, the difference between the gn argument to + * rustsecp256k1_v0_11_ecmult_gen, and the scalar whose encoding the table lookup bits are drawn + * from (before applying blinding). */ +static void rustsecp256k1_v0_11_ecmult_gen_scalar_diff(rustsecp256k1_v0_11_scalar* diff) { + int i; + + /* Compute scalar -1/2. */ + rustsecp256k1_v0_11_scalar neghalf; + rustsecp256k1_v0_11_scalar_half(&neghalf, &rustsecp256k1_v0_11_scalar_one); + rustsecp256k1_v0_11_scalar_negate(&neghalf, &neghalf); + + /* Compute offset = 2^(COMB_BITS - 1). */ + *diff = rustsecp256k1_v0_11_scalar_one; + for (i = 0; i < COMB_BITS - 1; ++i) { + rustsecp256k1_v0_11_scalar_add(diff, diff, diff); + } + + /* The result is the sum 2^(COMB_BITS - 1) + (-1/2). */ + rustsecp256k1_v0_11_scalar_add(diff, diff, &neghalf); +} + +static void rustsecp256k1_v0_11_ecmult_gen(const rustsecp256k1_v0_11_ecmult_gen_context *ctx, rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_scalar *gn) { + uint32_t comb_off; + rustsecp256k1_v0_11_ge add; + rustsecp256k1_v0_11_fe neg; + rustsecp256k1_v0_11_ge_storage adds; + rustsecp256k1_v0_11_scalar d; + /* Array of uint32_t values large enough to store COMB_BITS bits. Only the bottom + * 8 are ever nonzero, but having the zero padding at the end if COMB_BITS>256 + * avoids the need to deal with out-of-bounds reads from a scalar. */ + uint32_t recoded[(COMB_BITS + 31) >> 5] = {0}; + int first = 1, i; + + memset(&adds, 0, sizeof(adds)); + + /* We want to compute R = gn*G. + * + * To blind the scalar used in the computation, we rewrite this to be + * R = (gn - b)*G + b*G, with a blinding value b determined by the context. + * + * The multiplication (gn-b)*G will be performed using a signed-digit multi-comb (see Section + * 3.3 of "Fast and compact elliptic-curve cryptography" by Mike Hamburg, + * https://eprint.iacr.org/2012/309). + * + * Let comb(s, P) = sum((2*s[i]-1)*2^i*P for i=0..COMB_BITS-1), where s[i] is the i'th bit of + * the binary representation of scalar s. So the s[i] values determine whether -2^i*P (s[i]=0) + * or +2^i*P (s[i]=1) are added together. COMB_BITS is at least 256, so all bits of s are + * covered. By manipulating: + * + * comb(s, P) = sum((2*s[i]-1)*2^i*P for i=0..COMB_BITS-1) + * <=> comb(s, P) = sum((2*s[i]-1)*2^i for i=0..COMB_BITS-1) * P + * <=> comb(s, P) = (2*sum(s[i]*2^i for i=0..COMB_BITS-1) - sum(2^i for i=0..COMB_BITS-1)) * P + * <=> comb(s, P) = (2*s - (2^COMB_BITS - 1)) * P + * + * If we wanted to compute (gn-b)*G as comb(s, G), it would need to hold that + * + * (gn - b) * G = (2*s - (2^COMB_BITS - 1)) * G + * <=> s = (gn - b + (2^COMB_BITS - 1))/2 (mod order) + * + * We use an alternative here that avoids the modular division by two: instead we compute + * (gn-b)*G as comb(d, G/2). For that to hold it must be the case that + * + * (gn - b) * G = (2*d - (2^COMB_BITS - 1)) * (G/2) + * <=> d = gn - b + (2^COMB_BITS - 1)/2 (mod order) + * + * Adding precomputation, our final equations become: + * + * ctx->scalar_offset = (2^COMB_BITS - 1)/2 - b (mod order) + * ctx->ge_offset = b*G + * d = gn + ctx->scalar_offset (mod order) + * R = comb(d, G/2) + ctx->ge_offset + * + * comb(d, G/2) function is then computed by summing + or - 2^(i-1)*G, for i=0..COMB_BITS-1, + * depending on the value of the bits d[i] of the binary representation of scalar d. + */ + + /* Compute the scalar d = (gn + ctx->scalar_offset). */ + rustsecp256k1_v0_11_scalar_add(&d, &ctx->scalar_offset, gn); + /* Convert to recoded array. */ + for (i = 0; i < 8 && i < ((COMB_BITS + 31) >> 5); ++i) { + recoded[i] = rustsecp256k1_v0_11_scalar_get_bits_limb32(&d, 32 * i, 32); + } + rustsecp256k1_v0_11_scalar_clear(&d); + + /* In rustsecp256k1_v0_11_ecmult_gen_prec_table we have precomputed sums of the + * (2*d[i]-1) * 2^(i-1) * G points, for various combinations of i positions. + * We rewrite our equation in terms of these table entries. + * + * Let mask(b) = sum(2^((b*COMB_TEETH + t)*COMB_SPACING) for t=0..COMB_TEETH-1), + * with b ranging from 0 to COMB_BLOCKS-1. So for example with COMB_BLOCKS=11, + * COMB_TEETH=6, COMB_SPACING=4, we would have: + * mask(0) = 2^0 + 2^4 + 2^8 + 2^12 + 2^16 + 2^20, + * mask(1) = 2^24 + 2^28 + 2^32 + 2^36 + 2^40 + 2^44, + * mask(2) = 2^48 + 2^52 + 2^56 + 2^60 + 2^64 + 2^68, + * ... + * mask(10) = 2^240 + 2^244 + 2^248 + 2^252 + 2^256 + 2^260 + * + * We will split up the bits d[i] using these masks. Specifically, each mask is + * used COMB_SPACING times, with different shifts: + * + * d = (d & mask(0)<<0) + (d & mask(1)<<0) + ... + (d & mask(COMB_BLOCKS-1)<<0) + + * (d & mask(0)<<1) + (d & mask(1)<<1) + ... + (d & mask(COMB_BLOCKS-1)<<1) + + * ... + * (d & mask(0)<<(COMB_SPACING-1)) + ... + * + * Now define table(b, m) = (m - mask(b)/2) * G, and we will precompute these values for + * b=0..COMB_BLOCKS-1, and for all values m which (d & mask(b)) can take (so m can take on + * 2^COMB_TEETH distinct values). + * + * If m=(d & mask(b)), then table(b, m) is the sum of 2^i * (2*d[i]-1) * G/2, with i + * iterating over the set bits in mask(b). In our example, table(2, 2^48 + 2^56 + 2^68) + * would equal (2^48 - 2^52 + 2^56 - 2^60 - 2^64 + 2^68) * G/2. + * + * With that, we can rewrite comb(d, G/2) as: + * + * 2^0 * (table(0, d>>0 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>0 & mask(COMP_BLOCKS-1))) + * + 2^1 * (table(0, d>>1 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>1 & mask(COMP_BLOCKS-1))) + * + 2^2 * (table(0, d>>2 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>2 & mask(COMP_BLOCKS-1))) + * + ... + * + 2^(COMB_SPACING-1) * (table(0, d>>(COMB_SPACING-1) & mask(0)) + ...) + * + * Or more generically as + * + * sum(2^i * sum(table(b, d>>i & mask(b)), b=0..COMB_BLOCKS-1), i=0..COMB_SPACING-1) + * + * This is implemented using an outer loop that runs in reverse order over the lines of this + * equation, which in each iteration runs an inner loop that adds the terms of that line and + * then doubles the result before proceeding to the next line. + * + * In pseudocode: + * c = infinity + * for comb_off in range(COMB_SPACING - 1, -1, -1): + * for block in range(COMB_BLOCKS): + * c += table(block, (d >> comb_off) & mask(block)) + * if comb_off > 0: + * c = 2*c + * return c + * + * This computes c = comb(d, G/2), and thus finally R = c + ctx->ge_offset. Note that it would + * be possible to apply an initial offset instead of a final offset (moving ge_offset to take + * the place of infinity above), but the chosen approach allows using (in a future improvement) + * an incomplete addition formula for most of the multiplication. + * + * The last question is how to implement the table(b, m) function. For any value of b, + * m=(d & mask(b)) can only take on at most 2^COMB_TEETH possible values (the last one may have + * fewer as there mask(b) may exceed the curve order). So we could create COMB_BLOCK tables + * which contain a value for each such m value. + * + * Now note that if m=(d & mask(b)), then flipping the relevant bits of m results in negating + * the result of table(b, m). This is because table(b,m XOR mask(b)) = table(b, mask(b) - m) = + * (mask(b) - m - mask(b)/2)*G = (-m + mask(b)/2)*G = -(m - mask(b)/2)*G = -table(b, m). + * Because of this it suffices to only store the first half of the m values for every b. If an + * entry from the second half is needed, we look up its bit-flipped version instead, and negate + * it. + * + * rustsecp256k1_v0_11_ecmult_gen_prec_table[b][index] stores the table(b, m) entries. Index + * is the relevant mask(b) bits of m packed together without gaps. */ + + /* Outer loop: iterate over comb_off from COMB_SPACING - 1 down to 0. */ + comb_off = COMB_SPACING - 1; + while (1) { + uint32_t block; + uint32_t bit_pos = comb_off; + /* Inner loop: for each block, add table entries to the result. */ + for (block = 0; block < COMB_BLOCKS; ++block) { + /* Gather the mask(block)-selected bits of d into bits. They're packed: + * bits[tooth] = d[(block*COMB_TEETH + tooth)*COMB_SPACING + comb_off]. */ + uint32_t bits = 0, sign, abs, index, tooth; + /* Instead of reading individual bits here to construct the bits variable, + * build up the result by xoring rotated reads together. In every iteration, + * one additional bit is made correct, starting at the bottom. The bits + * above that contain junk. This reduces leakage by avoiding computations + * on variables that can have only a low number of possible values (e.g., + * just two values when reading a single bit into a variable.) See: + * https://www.usenix.org/system/files/conference/usenixsecurity18/sec18-alam.pdf + */ + for (tooth = 0; tooth < COMB_TEETH; ++tooth) { + /* Construct bitdata s.t. the bottom bit is the bit we'd like to read. + * + * We could just set bitdata = recoded[bit_pos >> 5] >> (bit_pos & 0x1f) + * but this would simply discard the bits that fall off at the bottom, + * and thus, for example, bitdata could still have only two values if we + * happen to shift by exactly 31 positions. We use a rotation instead, + * which ensures that bitdata doesn't loose entropy. This relies on the + * rotation being atomic, i.e., the compiler emitting an actual rot + * instruction. */ + uint32_t bitdata = rustsecp256k1_v0_11_rotr32(recoded[bit_pos >> 5], bit_pos & 0x1f); + + /* Clear the bit at position tooth, but sssh, don't tell clang. */ + uint32_t volatile vmask = ~(1 << tooth); + bits &= vmask; + + /* Write the bit into position tooth (and junk into higher bits). */ + bits ^= bitdata << tooth; + bit_pos += COMB_SPACING; + } + + /* If the top bit of bits is 1, flip them all (corresponding to looking up + * the negated table value), and remember to negate the result in sign. */ + sign = (bits >> (COMB_TEETH - 1)) & 1; + abs = (bits ^ -sign) & (COMB_POINTS - 1); + VERIFY_CHECK(sign == 0 || sign == 1); + VERIFY_CHECK(abs < COMB_POINTS); + + /** This uses a conditional move to avoid any secret data in array indexes. + * _Any_ use of secret indexes has been demonstrated to result in timing + * sidechannels, even when the cache-line access patterns are uniform. + * See also: + * "A word of warning", CHES 2013 Rump Session, by Daniel J. Bernstein and Peter Schwabe + * (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and + * "Cache Attacks and Countermeasures: the Case of AES", RSA 2006, + * by Dag Arne Osvik, Adi Shamir, and Eran Tromer + * (https://www.tau.ac.il/~tromer/papers/cache.pdf) + */ + for (index = 0; index < COMB_POINTS; ++index) { + rustsecp256k1_v0_11_ge_storage_cmov(&adds, &rustsecp256k1_v0_11_ecmult_gen_prec_table[block][index], index == abs); + } + + /* Set add=adds or add=-adds, in constant time, based on sign. */ + rustsecp256k1_v0_11_ge_from_storage(&add, &adds); + rustsecp256k1_v0_11_fe_negate(&neg, &add.y, 1); + rustsecp256k1_v0_11_fe_cmov(&add.y, &neg, sign); + + /* Add the looked up and conditionally negated value to r. */ + if (EXPECT(first, 0)) { + /* If this is the first table lookup, we can skip addition. */ + rustsecp256k1_v0_11_gej_set_ge(r, &add); + /* Give the entry a random Z coordinate to blind intermediary results. */ + rustsecp256k1_v0_11_gej_rescale(r, &ctx->proj_blind); + first = 0; + } else { + rustsecp256k1_v0_11_gej_add_ge(r, r, &add); + } + } + + /* Double the result, except in the last iteration. */ + if (comb_off-- == 0) break; + rustsecp256k1_v0_11_gej_double(r, r); + } + + /* Correct for the scalar_offset added at the start (ge_offset = b*G, while b was + * subtracted from the input scalar gn). */ + rustsecp256k1_v0_11_gej_add_ge(r, r, &ctx->ge_offset); + + /* Cleanup. */ + rustsecp256k1_v0_11_fe_clear(&neg); + rustsecp256k1_v0_11_ge_clear(&add); + rustsecp256k1_v0_11_memclear(&adds, sizeof(adds)); + rustsecp256k1_v0_11_memclear(&recoded, sizeof(recoded)); +} + +/* Setup blinding values for rustsecp256k1_v0_11_ecmult_gen. */ +static void rustsecp256k1_v0_11_ecmult_gen_blind(rustsecp256k1_v0_11_ecmult_gen_context *ctx, const unsigned char *seed32) { + rustsecp256k1_v0_11_scalar b; + rustsecp256k1_v0_11_scalar diff; + rustsecp256k1_v0_11_gej gb; + rustsecp256k1_v0_11_fe f; + unsigned char nonce32[32]; + rustsecp256k1_v0_11_rfc6979_hmac_sha256 rng; + unsigned char keydata[64]; + + /* Compute the (2^COMB_BITS - 1)/2 term once. */ + rustsecp256k1_v0_11_ecmult_gen_scalar_diff(&diff); + + if (seed32 == NULL) { + /* When seed is NULL, reset the final point and blinding value. */ + rustsecp256k1_v0_11_ge_neg(&ctx->ge_offset, &rustsecp256k1_v0_11_ge_const_g); + rustsecp256k1_v0_11_scalar_add(&ctx->scalar_offset, &rustsecp256k1_v0_11_scalar_one, &diff); + ctx->proj_blind = rustsecp256k1_v0_11_fe_one; + return; + } + /* The prior blinding value (if not reset) is chained forward by including it in the hash. */ + rustsecp256k1_v0_11_scalar_get_b32(keydata, &ctx->scalar_offset); + /** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data, + * and guards against weak or adversarial seeds. This is a simpler and safer interface than + * asking the caller for blinding values directly and expecting them to retry on failure. + */ + VERIFY_CHECK(seed32 != NULL); + memcpy(keydata + 32, seed32, 32); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_initialize(&rng, keydata, 64); + rustsecp256k1_v0_11_memclear(keydata, sizeof(keydata)); + + /* Compute projective blinding factor (cannot be 0). */ + rustsecp256k1_v0_11_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + rustsecp256k1_v0_11_fe_set_b32_mod(&f, nonce32); + rustsecp256k1_v0_11_fe_cmov(&f, &rustsecp256k1_v0_11_fe_one, rustsecp256k1_v0_11_fe_normalizes_to_zero(&f)); + ctx->proj_blind = f; + + /* For a random blinding value b, set scalar_offset=diff-b, ge_offset=bG */ + rustsecp256k1_v0_11_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + rustsecp256k1_v0_11_scalar_set_b32(&b, nonce32, NULL); + /* The blinding value cannot be zero, as that would mean ge_offset = infinity, + * which rustsecp256k1_v0_11_gej_add_ge cannot handle. */ + rustsecp256k1_v0_11_scalar_cmov(&b, &rustsecp256k1_v0_11_scalar_one, rustsecp256k1_v0_11_scalar_is_zero(&b)); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_finalize(&rng); + rustsecp256k1_v0_11_ecmult_gen(ctx, &gb, &b); + rustsecp256k1_v0_11_scalar_negate(&b, &b); + rustsecp256k1_v0_11_scalar_add(&ctx->scalar_offset, &b, &diff); + rustsecp256k1_v0_11_ge_set_gej(&ctx->ge_offset, &gb); + + /* Clean up. */ + rustsecp256k1_v0_11_memclear(nonce32, sizeof(nonce32)); + rustsecp256k1_v0_11_scalar_clear(&b); + rustsecp256k1_v0_11_gej_clear(&gb); + rustsecp256k1_v0_11_fe_clear(&f); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_clear(&rng); +} + +#endif /* SECP256K1_ECMULT_GEN_IMPL_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_impl.h new file mode 100644 index 00000000..2077c1db --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/ecmult_impl.h @@ -0,0 +1,853 @@ +/****************************************************************************** + * Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + ******************************************************************************/ + +#ifndef SECP256K1_ECMULT_IMPL_H +#define SECP256K1_ECMULT_IMPL_H + +#include +#include + +#include "util.h" +#include "group.h" +#include "scalar.h" +#include "ecmult.h" +#include "precomputed_ecmult.h" + +#if defined(EXHAUSTIVE_TEST_ORDER) +/* We need to lower these values for exhaustive tests because + * the tables cannot have infinities in them (this breaks the + * affine-isomorphism stuff which tracks z-ratios) */ +# if EXHAUSTIVE_TEST_ORDER > 128 +# define WINDOW_A 5 +# elif EXHAUSTIVE_TEST_ORDER > 8 +# define WINDOW_A 4 +# else +# define WINDOW_A 2 +# endif +#else +/* optimal for 128-bit and 256-bit exponents. */ +# define WINDOW_A 5 +/** Larger values for ECMULT_WINDOW_SIZE result in possibly better + * performance at the cost of an exponentially larger precomputed + * table. The exact table size is + * (1 << (WINDOW_G - 2)) * sizeof(rustsecp256k1_v0_11_ge_storage) bytes, + * where sizeof(rustsecp256k1_v0_11_ge_storage) is typically 64 bytes but can + * be larger due to platform-specific padding and alignment. + * Two tables of this size are used (due to the endomorphism + * optimization). + */ +#endif + +#define WNAF_BITS 128 +#define WNAF_SIZE_BITS(bits, w) CEIL_DIV(bits, w) +#define WNAF_SIZE(w) WNAF_SIZE_BITS(WNAF_BITS, w) + +/* The number of objects allocated on the scratch space for ecmult_multi algorithms */ +#define PIPPENGER_SCRATCH_OBJECTS 6 +#define STRAUSS_SCRATCH_OBJECTS 5 + +#define PIPPENGER_MAX_BUCKET_WINDOW 12 + +/* Minimum number of points for which pippenger_wnaf is faster than strauss wnaf */ +#define ECMULT_PIPPENGER_THRESHOLD 88 + +#define ECMULT_MAX_POINTS_PER_BATCH 5000000 + +/** Fill a table 'pre_a' with precomputed odd multiples of a. + * pre_a will contain [1*a,3*a,...,(2*n-1)*a], so it needs space for n group elements. + * zr needs space for n field elements. + * + * Although pre_a is an array of _ge rather than _gej, it actually represents elements + * in Jacobian coordinates with their z coordinates omitted. The omitted z-coordinates + * can be recovered using z and zr. Using the notation z(b) to represent the omitted + * z coordinate of b: + * - z(pre_a[n-1]) = 'z' + * - z(pre_a[i-1]) = z(pre_a[i]) / zr[i] for n > i > 0 + * + * Lastly the zr[0] value, which isn't used above, is set so that: + * - a.z = z(pre_a[0]) / zr[0] + */ +static void rustsecp256k1_v0_11_ecmult_odd_multiples_table(int n, rustsecp256k1_v0_11_ge *pre_a, rustsecp256k1_v0_11_fe *zr, rustsecp256k1_v0_11_fe *z, const rustsecp256k1_v0_11_gej *a) { + rustsecp256k1_v0_11_gej d, ai; + rustsecp256k1_v0_11_ge d_ge; + int i; + + VERIFY_CHECK(!a->infinity); + + rustsecp256k1_v0_11_gej_double_var(&d, a, NULL); + + /* + * Perform the additions using an isomorphic curve Y^2 = X^3 + 7*C^6 where C := d.z. + * The isomorphism, phi, maps a secp256k1 point (x, y) to the point (x*C^2, y*C^3) on the other curve. + * In Jacobian coordinates phi maps (x, y, z) to (x*C^2, y*C^3, z) or, equivalently to (x, y, z/C). + * + * phi(x, y, z) = (x*C^2, y*C^3, z) = (x, y, z/C) + * d_ge := phi(d) = (d.x, d.y, 1) + * ai := phi(a) = (a.x*C^2, a.y*C^3, a.z) + * + * The group addition functions work correctly on these isomorphic curves. + * In particular phi(d) is easy to represent in affine coordinates under this isomorphism. + * This lets us use the faster rustsecp256k1_v0_11_gej_add_ge_var group addition function that we wouldn't be able to use otherwise. + */ + rustsecp256k1_v0_11_ge_set_xy(&d_ge, &d.x, &d.y); + rustsecp256k1_v0_11_ge_set_gej_zinv(&pre_a[0], a, &d.z); + rustsecp256k1_v0_11_gej_set_ge(&ai, &pre_a[0]); + ai.z = a->z; + + /* pre_a[0] is the point (a.x*C^2, a.y*C^3, a.z*C) which is equivalent to a. + * Set zr[0] to C, which is the ratio between the omitted z(pre_a[0]) value and a.z. + */ + zr[0] = d.z; + + for (i = 1; i < n; i++) { + rustsecp256k1_v0_11_gej_add_ge_var(&ai, &ai, &d_ge, &zr[i]); + rustsecp256k1_v0_11_ge_set_xy(&pre_a[i], &ai.x, &ai.y); + } + + /* Multiply the last z-coordinate by C to undo the isomorphism. + * Since the z-coordinates of the pre_a values are implied by the zr array of z-coordinate ratios, + * undoing the isomorphism here undoes the isomorphism for all pre_a values. + */ + rustsecp256k1_v0_11_fe_mul(z, &ai.z, &d.z); +} + +SECP256K1_INLINE static void rustsecp256k1_v0_11_ecmult_table_verify(int n, int w) { + (void)n; + (void)w; + VERIFY_CHECK(((n) & 1) == 1); + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); +} + +SECP256K1_INLINE static void rustsecp256k1_v0_11_ecmult_table_get_ge(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_ge *pre, int n, int w) { + rustsecp256k1_v0_11_ecmult_table_verify(n,w); + if (n > 0) { + *r = pre[(n-1)/2]; + } else { + *r = pre[(-n-1)/2]; + rustsecp256k1_v0_11_fe_negate(&(r->y), &(r->y), 1); + } +} + +SECP256K1_INLINE static void rustsecp256k1_v0_11_ecmult_table_get_ge_lambda(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_ge *pre, const rustsecp256k1_v0_11_fe *x, int n, int w) { + rustsecp256k1_v0_11_ecmult_table_verify(n,w); + if (n > 0) { + rustsecp256k1_v0_11_ge_set_xy(r, &x[(n-1)/2], &pre[(n-1)/2].y); + } else { + rustsecp256k1_v0_11_ge_set_xy(r, &x[(-n-1)/2], &pre[(-n-1)/2].y); + rustsecp256k1_v0_11_fe_negate(&(r->y), &(r->y), 1); + } +} + +SECP256K1_INLINE static void rustsecp256k1_v0_11_ecmult_table_get_ge_storage(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_ge_storage *pre, int n, int w) { + rustsecp256k1_v0_11_ecmult_table_verify(n,w); + if (n > 0) { + rustsecp256k1_v0_11_ge_from_storage(r, &pre[(n-1)/2]); + } else { + rustsecp256k1_v0_11_ge_from_storage(r, &pre[(-n-1)/2]); + rustsecp256k1_v0_11_fe_negate(&(r->y), &(r->y), 1); + } +} + +/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits), + * with the following guarantees: + * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1) + * - two non-zero entries in wnaf are separated by at least w-1 zeroes. + * - the number of set values in wnaf is returned. This number is at most 256, and at most one more + * than the number of bits in the (absolute value) of the input. + */ +static int rustsecp256k1_v0_11_ecmult_wnaf(int *wnaf, int len, const rustsecp256k1_v0_11_scalar *a, int w) { + rustsecp256k1_v0_11_scalar s; + int last_set_bit = -1; + int bit = 0; + int sign = 1; + int carry = 0; + + VERIFY_CHECK(wnaf != NULL); + VERIFY_CHECK(0 <= len && len <= 256); + VERIFY_CHECK(a != NULL); + VERIFY_CHECK(2 <= w && w <= 31); + + for (bit = 0; bit < len; bit++) { + wnaf[bit] = 0; + } + + s = *a; + if (rustsecp256k1_v0_11_scalar_get_bits_limb32(&s, 255, 1)) { + rustsecp256k1_v0_11_scalar_negate(&s, &s); + sign = -1; + } + + bit = 0; + while (bit < len) { + int now; + int word; + if (rustsecp256k1_v0_11_scalar_get_bits_limb32(&s, bit, 1) == (unsigned int)carry) { + bit++; + continue; + } + + now = w; + if (now > len - bit) { + now = len - bit; + } + + word = rustsecp256k1_v0_11_scalar_get_bits_var(&s, bit, now) + carry; + + carry = (word >> (w-1)) & 1; + word -= carry << w; + + wnaf[bit] = sign * word; + last_set_bit = bit; + + bit += now; + } +#ifdef VERIFY + { + int verify_bit = bit; + + VERIFY_CHECK(carry == 0); + + while (verify_bit < 256) { + VERIFY_CHECK(rustsecp256k1_v0_11_scalar_get_bits_limb32(&s, verify_bit, 1) == 0); + verify_bit++; + } + } +#endif + return last_set_bit + 1; +} + +struct rustsecp256k1_v0_11_strauss_point_state { + int wnaf_na_1[129]; + int wnaf_na_lam[129]; + int bits_na_1; + int bits_na_lam; +}; + +struct rustsecp256k1_v0_11_strauss_state { + /* aux is used to hold z-ratios, and then used to hold pre_a[i].x * BETA values. */ + rustsecp256k1_v0_11_fe* aux; + rustsecp256k1_v0_11_ge* pre_a; + struct rustsecp256k1_v0_11_strauss_point_state* ps; +}; + +static void rustsecp256k1_v0_11_ecmult_strauss_wnaf(const struct rustsecp256k1_v0_11_strauss_state *state, rustsecp256k1_v0_11_gej *r, size_t num, const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_scalar *na, const rustsecp256k1_v0_11_scalar *ng) { + rustsecp256k1_v0_11_ge tmpa; + rustsecp256k1_v0_11_fe Z; + /* Split G factors. */ + rustsecp256k1_v0_11_scalar ng_1, ng_128; + int wnaf_ng_1[129]; + int bits_ng_1 = 0; + int wnaf_ng_128[129]; + int bits_ng_128 = 0; + int i; + int bits = 0; + size_t np; + size_t no = 0; + + rustsecp256k1_v0_11_fe_set_int(&Z, 1); + for (np = 0; np < num; ++np) { + rustsecp256k1_v0_11_gej tmp; + rustsecp256k1_v0_11_scalar na_1, na_lam; + if (rustsecp256k1_v0_11_scalar_is_zero(&na[np]) || rustsecp256k1_v0_11_gej_is_infinity(&a[np])) { + continue; + } + /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ + rustsecp256k1_v0_11_scalar_split_lambda(&na_1, &na_lam, &na[np]); + + /* build wnaf representation for na_1 and na_lam. */ + state->ps[no].bits_na_1 = rustsecp256k1_v0_11_ecmult_wnaf(state->ps[no].wnaf_na_1, 129, &na_1, WINDOW_A); + state->ps[no].bits_na_lam = rustsecp256k1_v0_11_ecmult_wnaf(state->ps[no].wnaf_na_lam, 129, &na_lam, WINDOW_A); + VERIFY_CHECK(state->ps[no].bits_na_1 <= 129); + VERIFY_CHECK(state->ps[no].bits_na_lam <= 129); + if (state->ps[no].bits_na_1 > bits) { + bits = state->ps[no].bits_na_1; + } + if (state->ps[no].bits_na_lam > bits) { + bits = state->ps[no].bits_na_lam; + } + + /* Calculate odd multiples of a. + * All multiples are brought to the same Z 'denominator', which is stored + * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + * The exception is the precomputed G table points, which are actually + * affine. Compared to the base used for other points, they have a Z ratio + * of 1/Z, so we can use rustsecp256k1_v0_11_gej_add_zinv_var, which uses the same + * isomorphism to efficiently add with a known Z inverse. + */ + tmp = a[np]; + if (no) { + rustsecp256k1_v0_11_gej_rescale(&tmp, &Z); + } + rustsecp256k1_v0_11_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &Z, &tmp); + if (no) rustsecp256k1_v0_11_fe_mul(state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &(a[np].z)); + + ++no; + } + + /* Bring them to the same Z denominator. */ + if (no) { + rustsecp256k1_v0_11_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux); + } + + for (np = 0; np < no; ++np) { + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + rustsecp256k1_v0_11_fe_mul(&state->aux[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i].x, &rustsecp256k1_v0_11_const_beta); + } + } + + if (ng) { + /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ + rustsecp256k1_v0_11_scalar_split_128(&ng_1, &ng_128, ng); + + /* Build wnaf representation for ng_1 and ng_128 */ + bits_ng_1 = rustsecp256k1_v0_11_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G); + bits_ng_128 = rustsecp256k1_v0_11_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G); + if (bits_ng_1 > bits) { + bits = bits_ng_1; + } + if (bits_ng_128 > bits) { + bits = bits_ng_128; + } + } + + rustsecp256k1_v0_11_gej_set_infinity(r); + + for (i = bits - 1; i >= 0; i--) { + int n; + rustsecp256k1_v0_11_gej_double_var(r, r, NULL); + for (np = 0; np < no; ++np) { + if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) { + rustsecp256k1_v0_11_ecmult_table_get_ge(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); + rustsecp256k1_v0_11_gej_add_ge_var(r, r, &tmpa, NULL); + } + if (i < state->ps[np].bits_na_lam && (n = state->ps[np].wnaf_na_lam[i])) { + rustsecp256k1_v0_11_ecmult_table_get_ge_lambda(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); + rustsecp256k1_v0_11_gej_add_ge_var(r, r, &tmpa, NULL); + } + } + if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { + rustsecp256k1_v0_11_ecmult_table_get_ge_storage(&tmpa, rustsecp256k1_v0_11_pre_g, n, WINDOW_G); + rustsecp256k1_v0_11_gej_add_zinv_var(r, r, &tmpa, &Z); + } + if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { + rustsecp256k1_v0_11_ecmult_table_get_ge_storage(&tmpa, rustsecp256k1_v0_11_pre_g_128, n, WINDOW_G); + rustsecp256k1_v0_11_gej_add_zinv_var(r, r, &tmpa, &Z); + } + } + + if (!r->infinity) { + rustsecp256k1_v0_11_fe_mul(&r->z, &r->z, &Z); + } +} + +static void rustsecp256k1_v0_11_ecmult(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_scalar *na, const rustsecp256k1_v0_11_scalar *ng) { + rustsecp256k1_v0_11_fe aux[ECMULT_TABLE_SIZE(WINDOW_A)]; + rustsecp256k1_v0_11_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + struct rustsecp256k1_v0_11_strauss_point_state ps[1]; + struct rustsecp256k1_v0_11_strauss_state state; + + state.aux = aux; + state.pre_a = pre_a; + state.ps = ps; + rustsecp256k1_v0_11_ecmult_strauss_wnaf(&state, r, 1, a, na, ng); +} + +static size_t rustsecp256k1_v0_11_strauss_scratch_size(size_t n_points) { + static const size_t point_size = (sizeof(rustsecp256k1_v0_11_ge) + sizeof(rustsecp256k1_v0_11_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct rustsecp256k1_v0_11_strauss_point_state) + sizeof(rustsecp256k1_v0_11_gej) + sizeof(rustsecp256k1_v0_11_scalar); + return n_points*point_size; +} + +static int rustsecp256k1_v0_11_ecmult_strauss_batch(const rustsecp256k1_v0_11_callback* error_callback, rustsecp256k1_v0_11_scratch *scratch, rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_scalar *inp_g_sc, rustsecp256k1_v0_11_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { + rustsecp256k1_v0_11_gej* points; + rustsecp256k1_v0_11_scalar* scalars; + struct rustsecp256k1_v0_11_strauss_state state; + size_t i; + const size_t scratch_checkpoint = rustsecp256k1_v0_11_scratch_checkpoint(error_callback, scratch); + + rustsecp256k1_v0_11_gej_set_infinity(r); + if (inp_g_sc == NULL && n_points == 0) { + return 1; + } + + /* We allocate STRAUSS_SCRATCH_OBJECTS objects on the scratch space. If these + * allocations change, make sure to update the STRAUSS_SCRATCH_OBJECTS + * constant and strauss_scratch_size accordingly. */ + points = (rustsecp256k1_v0_11_gej*)rustsecp256k1_v0_11_scratch_alloc(error_callback, scratch, n_points * sizeof(rustsecp256k1_v0_11_gej)); + scalars = (rustsecp256k1_v0_11_scalar*)rustsecp256k1_v0_11_scratch_alloc(error_callback, scratch, n_points * sizeof(rustsecp256k1_v0_11_scalar)); + state.aux = (rustsecp256k1_v0_11_fe*)rustsecp256k1_v0_11_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(rustsecp256k1_v0_11_fe)); + state.pre_a = (rustsecp256k1_v0_11_ge*)rustsecp256k1_v0_11_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(rustsecp256k1_v0_11_ge)); + state.ps = (struct rustsecp256k1_v0_11_strauss_point_state*)rustsecp256k1_v0_11_scratch_alloc(error_callback, scratch, n_points * sizeof(struct rustsecp256k1_v0_11_strauss_point_state)); + + if (points == NULL || scalars == NULL || state.aux == NULL || state.pre_a == NULL || state.ps == NULL) { + rustsecp256k1_v0_11_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + + for (i = 0; i < n_points; i++) { + rustsecp256k1_v0_11_ge point; + if (!cb(&scalars[i], &point, i+cb_offset, cbdata)) { + rustsecp256k1_v0_11_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + rustsecp256k1_v0_11_gej_set_ge(&points[i], &point); + } + rustsecp256k1_v0_11_ecmult_strauss_wnaf(&state, r, n_points, points, scalars, inp_g_sc); + rustsecp256k1_v0_11_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 1; +} + +/* Wrapper for rustsecp256k1_v0_11_ecmult_multi_func interface */ +static int rustsecp256k1_v0_11_ecmult_strauss_batch_single(const rustsecp256k1_v0_11_callback* error_callback, rustsecp256k1_v0_11_scratch *scratch, rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_scalar *inp_g_sc, rustsecp256k1_v0_11_ecmult_multi_callback cb, void *cbdata, size_t n) { + return rustsecp256k1_v0_11_ecmult_strauss_batch(error_callback, scratch, r, inp_g_sc, cb, cbdata, n, 0); +} + +static size_t rustsecp256k1_v0_11_strauss_max_points(const rustsecp256k1_v0_11_callback* error_callback, rustsecp256k1_v0_11_scratch *scratch) { + return rustsecp256k1_v0_11_scratch_max_allocation(error_callback, scratch, STRAUSS_SCRATCH_OBJECTS) / rustsecp256k1_v0_11_strauss_scratch_size(1); +} + +/** Convert a number to WNAF notation. + * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. + * It has the following guarantees: + * - each wnaf[i] is either 0 or an odd integer between -(1 << w) and (1 << w) + * - the number of words set is always WNAF_SIZE(w) + * - the returned skew is 0 or 1 + */ +static int rustsecp256k1_v0_11_wnaf_fixed(int *wnaf, const rustsecp256k1_v0_11_scalar *s, int w) { + int skew = 0; + int pos; + int max_pos; + int last_w; + const rustsecp256k1_v0_11_scalar *work = s; + + if (rustsecp256k1_v0_11_scalar_is_zero(s)) { + for (pos = 0; pos < WNAF_SIZE(w); pos++) { + wnaf[pos] = 0; + } + return 0; + } + + if (rustsecp256k1_v0_11_scalar_is_even(s)) { + skew = 1; + } + + wnaf[0] = rustsecp256k1_v0_11_scalar_get_bits_var(work, 0, w) + skew; + /* Compute last window size. Relevant when window size doesn't divide the + * number of bits in the scalar */ + last_w = WNAF_BITS - (WNAF_SIZE(w) - 1) * w; + + /* Store the position of the first nonzero word in max_pos to allow + * skipping leading zeros when calculating the wnaf. */ + for (pos = WNAF_SIZE(w) - 1; pos > 0; pos--) { + int val = rustsecp256k1_v0_11_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w); + if(val != 0) { + break; + } + wnaf[pos] = 0; + } + max_pos = pos; + pos = 1; + + while (pos <= max_pos) { + int val = rustsecp256k1_v0_11_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w); + if ((val & 1) == 0) { + wnaf[pos - 1] -= (1 << w); + wnaf[pos] = (val + 1); + } else { + wnaf[pos] = val; + } + /* Set a coefficient to zero if it is 1 or -1 and the proceeding digit + * is strictly negative or strictly positive respectively. Only change + * coefficients at previous positions because above code assumes that + * wnaf[pos - 1] is odd. + */ + if (pos >= 2 && ((wnaf[pos - 1] == 1 && wnaf[pos - 2] < 0) || (wnaf[pos - 1] == -1 && wnaf[pos - 2] > 0))) { + if (wnaf[pos - 1] == 1) { + wnaf[pos - 2] += 1 << w; + } else { + wnaf[pos - 2] -= 1 << w; + } + wnaf[pos - 1] = 0; + } + ++pos; + } + + return skew; +} + +struct rustsecp256k1_v0_11_pippenger_point_state { + int skew_na; + size_t input_pos; +}; + +struct rustsecp256k1_v0_11_pippenger_state { + int *wnaf_na; + struct rustsecp256k1_v0_11_pippenger_point_state* ps; +}; + +/* + * pippenger_wnaf computes the result of a multi-point multiplication as + * follows: The scalars are brought into wnaf with n_wnaf elements each. Then + * for every i < n_wnaf, first each point is added to a "bucket" corresponding + * to the point's wnaf[i]. Second, the buckets are added together such that + * r += 1*bucket[0] + 3*bucket[1] + 5*bucket[2] + ... + */ +static int rustsecp256k1_v0_11_ecmult_pippenger_wnaf(rustsecp256k1_v0_11_gej *buckets, int bucket_window, struct rustsecp256k1_v0_11_pippenger_state *state, rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_scalar *sc, const rustsecp256k1_v0_11_ge *pt, size_t num) { + size_t n_wnaf = WNAF_SIZE(bucket_window+1); + size_t np; + size_t no = 0; + int i; + int j; + + for (np = 0; np < num; ++np) { + if (rustsecp256k1_v0_11_scalar_is_zero(&sc[np]) || rustsecp256k1_v0_11_ge_is_infinity(&pt[np])) { + continue; + } + state->ps[no].input_pos = np; + state->ps[no].skew_na = rustsecp256k1_v0_11_wnaf_fixed(&state->wnaf_na[no*n_wnaf], &sc[np], bucket_window+1); + no++; + } + rustsecp256k1_v0_11_gej_set_infinity(r); + + if (no == 0) { + return 1; + } + + for (i = n_wnaf - 1; i >= 0; i--) { + rustsecp256k1_v0_11_gej running_sum; + + for(j = 0; j < ECMULT_TABLE_SIZE(bucket_window+2); j++) { + rustsecp256k1_v0_11_gej_set_infinity(&buckets[j]); + } + + for (np = 0; np < no; ++np) { + int n = state->wnaf_na[np*n_wnaf + i]; + struct rustsecp256k1_v0_11_pippenger_point_state point_state = state->ps[np]; + rustsecp256k1_v0_11_ge tmp; + int idx; + + if (i == 0) { + /* correct for wnaf skew */ + int skew = point_state.skew_na; + if (skew) { + rustsecp256k1_v0_11_ge_neg(&tmp, &pt[point_state.input_pos]); + rustsecp256k1_v0_11_gej_add_ge_var(&buckets[0], &buckets[0], &tmp, NULL); + } + } + if (n > 0) { + idx = (n - 1)/2; + rustsecp256k1_v0_11_gej_add_ge_var(&buckets[idx], &buckets[idx], &pt[point_state.input_pos], NULL); + } else if (n < 0) { + idx = -(n + 1)/2; + rustsecp256k1_v0_11_ge_neg(&tmp, &pt[point_state.input_pos]); + rustsecp256k1_v0_11_gej_add_ge_var(&buckets[idx], &buckets[idx], &tmp, NULL); + } + } + + for(j = 0; j < bucket_window; j++) { + rustsecp256k1_v0_11_gej_double_var(r, r, NULL); + } + + rustsecp256k1_v0_11_gej_set_infinity(&running_sum); + /* Accumulate the sum: bucket[0] + 3*bucket[1] + 5*bucket[2] + 7*bucket[3] + ... + * = bucket[0] + bucket[1] + bucket[2] + bucket[3] + ... + * + 2 * (bucket[1] + 2*bucket[2] + 3*bucket[3] + ...) + * using an intermediate running sum: + * running_sum = bucket[0] + bucket[1] + bucket[2] + ... + * + * The doubling is done implicitly by deferring the final window doubling (of 'r'). + */ + for(j = ECMULT_TABLE_SIZE(bucket_window+2) - 1; j > 0; j--) { + rustsecp256k1_v0_11_gej_add_var(&running_sum, &running_sum, &buckets[j], NULL); + rustsecp256k1_v0_11_gej_add_var(r, r, &running_sum, NULL); + } + + rustsecp256k1_v0_11_gej_add_var(&running_sum, &running_sum, &buckets[0], NULL); + rustsecp256k1_v0_11_gej_double_var(r, r, NULL); + rustsecp256k1_v0_11_gej_add_var(r, r, &running_sum, NULL); + } + return 1; +} + +/** + * Returns optimal bucket_window (number of bits of a scalar represented by a + * set of buckets) for a given number of points. + */ +static int rustsecp256k1_v0_11_pippenger_bucket_window(size_t n) { + if (n <= 1) { + return 1; + } else if (n <= 4) { + return 2; + } else if (n <= 20) { + return 3; + } else if (n <= 57) { + return 4; + } else if (n <= 136) { + return 5; + } else if (n <= 235) { + return 6; + } else if (n <= 1260) { + return 7; + } else if (n <= 4420) { + return 9; + } else if (n <= 7880) { + return 10; + } else if (n <= 16050) { + return 11; + } else { + return PIPPENGER_MAX_BUCKET_WINDOW; + } +} + +/** + * Returns the maximum optimal number of points for a bucket_window. + */ +static size_t rustsecp256k1_v0_11_pippenger_bucket_window_inv(int bucket_window) { + switch(bucket_window) { + case 1: return 1; + case 2: return 4; + case 3: return 20; + case 4: return 57; + case 5: return 136; + case 6: return 235; + case 7: return 1260; + case 8: return 1260; + case 9: return 4420; + case 10: return 7880; + case 11: return 16050; + case PIPPENGER_MAX_BUCKET_WINDOW: return SIZE_MAX; + } + return 0; +} + + +SECP256K1_INLINE static void rustsecp256k1_v0_11_ecmult_endo_split(rustsecp256k1_v0_11_scalar *s1, rustsecp256k1_v0_11_scalar *s2, rustsecp256k1_v0_11_ge *p1, rustsecp256k1_v0_11_ge *p2) { + rustsecp256k1_v0_11_scalar tmp = *s1; + rustsecp256k1_v0_11_scalar_split_lambda(s1, s2, &tmp); + rustsecp256k1_v0_11_ge_mul_lambda(p2, p1); + + if (rustsecp256k1_v0_11_scalar_is_high(s1)) { + rustsecp256k1_v0_11_scalar_negate(s1, s1); + rustsecp256k1_v0_11_ge_neg(p1, p1); + } + if (rustsecp256k1_v0_11_scalar_is_high(s2)) { + rustsecp256k1_v0_11_scalar_negate(s2, s2); + rustsecp256k1_v0_11_ge_neg(p2, p2); + } +} + +/** + * Returns the scratch size required for a given number of points (excluding + * base point G) without considering alignment. + */ +static size_t rustsecp256k1_v0_11_pippenger_scratch_size(size_t n_points, int bucket_window) { + size_t entries = 2*n_points + 2; + size_t entry_size = sizeof(rustsecp256k1_v0_11_ge) + sizeof(rustsecp256k1_v0_11_scalar) + sizeof(struct rustsecp256k1_v0_11_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); + return (sizeof(rustsecp256k1_v0_11_gej) << bucket_window) + sizeof(struct rustsecp256k1_v0_11_pippenger_state) + entries * entry_size; +} + +static int rustsecp256k1_v0_11_ecmult_pippenger_batch(const rustsecp256k1_v0_11_callback* error_callback, rustsecp256k1_v0_11_scratch *scratch, rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_scalar *inp_g_sc, rustsecp256k1_v0_11_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { + const size_t scratch_checkpoint = rustsecp256k1_v0_11_scratch_checkpoint(error_callback, scratch); + /* Use 2(n+1) with the endomorphism, when calculating batch + * sizes. The reason for +1 is that we add the G scalar to the list of + * other scalars. */ + size_t entries = 2*n_points + 2; + rustsecp256k1_v0_11_ge *points; + rustsecp256k1_v0_11_scalar *scalars; + rustsecp256k1_v0_11_gej *buckets; + struct rustsecp256k1_v0_11_pippenger_state *state_space; + size_t idx = 0; + size_t point_idx = 0; + int bucket_window; + + rustsecp256k1_v0_11_gej_set_infinity(r); + if (inp_g_sc == NULL && n_points == 0) { + return 1; + } + bucket_window = rustsecp256k1_v0_11_pippenger_bucket_window(n_points); + + /* We allocate PIPPENGER_SCRATCH_OBJECTS objects on the scratch space. If + * these allocations change, make sure to update the + * PIPPENGER_SCRATCH_OBJECTS constant and pippenger_scratch_size + * accordingly. */ + points = (rustsecp256k1_v0_11_ge *) rustsecp256k1_v0_11_scratch_alloc(error_callback, scratch, entries * sizeof(*points)); + scalars = (rustsecp256k1_v0_11_scalar *) rustsecp256k1_v0_11_scratch_alloc(error_callback, scratch, entries * sizeof(*scalars)); + state_space = (struct rustsecp256k1_v0_11_pippenger_state *) rustsecp256k1_v0_11_scratch_alloc(error_callback, scratch, sizeof(*state_space)); + if (points == NULL || scalars == NULL || state_space == NULL) { + rustsecp256k1_v0_11_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + state_space->ps = (struct rustsecp256k1_v0_11_pippenger_point_state *) rustsecp256k1_v0_11_scratch_alloc(error_callback, scratch, entries * sizeof(*state_space->ps)); + state_space->wnaf_na = (int *) rustsecp256k1_v0_11_scratch_alloc(error_callback, scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int)); + buckets = (rustsecp256k1_v0_11_gej *) rustsecp256k1_v0_11_scratch_alloc(error_callback, scratch, ((size_t)1 << bucket_window) * sizeof(*buckets)); + if (state_space->ps == NULL || state_space->wnaf_na == NULL || buckets == NULL) { + rustsecp256k1_v0_11_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + + if (inp_g_sc != NULL) { + scalars[0] = *inp_g_sc; + points[0] = rustsecp256k1_v0_11_ge_const_g; + idx++; + rustsecp256k1_v0_11_ecmult_endo_split(&scalars[0], &scalars[1], &points[0], &points[1]); + idx++; + } + + while (point_idx < n_points) { + if (!cb(&scalars[idx], &points[idx], point_idx + cb_offset, cbdata)) { + rustsecp256k1_v0_11_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + idx++; + rustsecp256k1_v0_11_ecmult_endo_split(&scalars[idx - 1], &scalars[idx], &points[idx - 1], &points[idx]); + idx++; + point_idx++; + } + + rustsecp256k1_v0_11_ecmult_pippenger_wnaf(buckets, bucket_window, state_space, r, scalars, points, idx); + rustsecp256k1_v0_11_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 1; +} + +/* Wrapper for rustsecp256k1_v0_11_ecmult_multi_func interface */ +static int rustsecp256k1_v0_11_ecmult_pippenger_batch_single(const rustsecp256k1_v0_11_callback* error_callback, rustsecp256k1_v0_11_scratch *scratch, rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_scalar *inp_g_sc, rustsecp256k1_v0_11_ecmult_multi_callback cb, void *cbdata, size_t n) { + return rustsecp256k1_v0_11_ecmult_pippenger_batch(error_callback, scratch, r, inp_g_sc, cb, cbdata, n, 0); +} + +/** + * Returns the maximum number of points in addition to G that can be used with + * a given scratch space. The function ensures that fewer points may also be + * used. + */ +static size_t rustsecp256k1_v0_11_pippenger_max_points(const rustsecp256k1_v0_11_callback* error_callback, rustsecp256k1_v0_11_scratch *scratch) { + size_t max_alloc = rustsecp256k1_v0_11_scratch_max_allocation(error_callback, scratch, PIPPENGER_SCRATCH_OBJECTS); + int bucket_window; + size_t res = 0; + + for (bucket_window = 1; bucket_window <= PIPPENGER_MAX_BUCKET_WINDOW; bucket_window++) { + size_t n_points; + size_t max_points = rustsecp256k1_v0_11_pippenger_bucket_window_inv(bucket_window); + size_t space_for_points; + size_t space_overhead; + size_t entry_size = sizeof(rustsecp256k1_v0_11_ge) + sizeof(rustsecp256k1_v0_11_scalar) + sizeof(struct rustsecp256k1_v0_11_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); + + entry_size = 2*entry_size; + space_overhead = (sizeof(rustsecp256k1_v0_11_gej) << bucket_window) + entry_size + sizeof(struct rustsecp256k1_v0_11_pippenger_state); + if (space_overhead > max_alloc) { + break; + } + space_for_points = max_alloc - space_overhead; + + n_points = space_for_points/entry_size; + n_points = n_points > max_points ? max_points : n_points; + if (n_points > res) { + res = n_points; + } + if (n_points < max_points) { + /* A larger bucket_window may support even more points. But if we + * would choose that then the caller couldn't safely use any number + * smaller than what this function returns */ + break; + } + } + return res; +} + +/* Computes ecmult_multi by simply multiplying and adding each point. Does not + * require a scratch space */ +static int rustsecp256k1_v0_11_ecmult_multi_simple_var(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_scalar *inp_g_sc, rustsecp256k1_v0_11_ecmult_multi_callback cb, void *cbdata, size_t n_points) { + size_t point_idx; + rustsecp256k1_v0_11_gej tmpj; + + rustsecp256k1_v0_11_gej_set_infinity(r); + rustsecp256k1_v0_11_gej_set_infinity(&tmpj); + /* r = inp_g_sc*G */ + rustsecp256k1_v0_11_ecmult(r, &tmpj, &rustsecp256k1_v0_11_scalar_zero, inp_g_sc); + for (point_idx = 0; point_idx < n_points; point_idx++) { + rustsecp256k1_v0_11_ge point; + rustsecp256k1_v0_11_gej pointj; + rustsecp256k1_v0_11_scalar scalar; + if (!cb(&scalar, &point, point_idx, cbdata)) { + return 0; + } + /* r += scalar*point */ + rustsecp256k1_v0_11_gej_set_ge(&pointj, &point); + rustsecp256k1_v0_11_ecmult(&tmpj, &pointj, &scalar, NULL); + rustsecp256k1_v0_11_gej_add_var(r, r, &tmpj, NULL); + } + return 1; +} + +/* Compute the number of batches and the batch size given the maximum batch size and the + * total number of points */ +static int rustsecp256k1_v0_11_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n_batch_points, size_t max_n_batch_points, size_t n) { + if (max_n_batch_points == 0) { + return 0; + } + if (max_n_batch_points > ECMULT_MAX_POINTS_PER_BATCH) { + max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH; + } + if (n == 0) { + *n_batches = 0; + *n_batch_points = 0; + return 1; + } + /* Compute ceil(n/max_n_batch_points) and ceil(n/n_batches) */ + *n_batches = CEIL_DIV(n, max_n_batch_points); + *n_batch_points = CEIL_DIV(n, *n_batches); + return 1; +} + +typedef int (*rustsecp256k1_v0_11_ecmult_multi_func)(const rustsecp256k1_v0_11_callback* error_callback, rustsecp256k1_v0_11_scratch*, rustsecp256k1_v0_11_gej*, const rustsecp256k1_v0_11_scalar*, rustsecp256k1_v0_11_ecmult_multi_callback cb, void*, size_t); +static int rustsecp256k1_v0_11_ecmult_multi_var(const rustsecp256k1_v0_11_callback* error_callback, rustsecp256k1_v0_11_scratch *scratch, rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_scalar *inp_g_sc, rustsecp256k1_v0_11_ecmult_multi_callback cb, void *cbdata, size_t n) { + size_t i; + + int (*f)(const rustsecp256k1_v0_11_callback* error_callback, rustsecp256k1_v0_11_scratch*, rustsecp256k1_v0_11_gej*, const rustsecp256k1_v0_11_scalar*, rustsecp256k1_v0_11_ecmult_multi_callback cb, void*, size_t, size_t); + size_t n_batches; + size_t n_batch_points; + + rustsecp256k1_v0_11_gej_set_infinity(r); + if (inp_g_sc == NULL && n == 0) { + return 1; + } else if (n == 0) { + rustsecp256k1_v0_11_ecmult(r, r, &rustsecp256k1_v0_11_scalar_zero, inp_g_sc); + return 1; + } + if (scratch == NULL) { + return rustsecp256k1_v0_11_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); + } + + /* Compute the batch sizes for Pippenger's algorithm given a scratch space. If it's greater than + * a threshold use Pippenger's algorithm. Otherwise use Strauss' algorithm. + * As a first step check if there's enough space for Pippenger's algo (which requires less space + * than Strauss' algo) and if not, use the simple algorithm. */ + if (!rustsecp256k1_v0_11_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, rustsecp256k1_v0_11_pippenger_max_points(error_callback, scratch), n)) { + return rustsecp256k1_v0_11_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); + } + if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) { + f = rustsecp256k1_v0_11_ecmult_pippenger_batch; + } else { + if (!rustsecp256k1_v0_11_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, rustsecp256k1_v0_11_strauss_max_points(error_callback, scratch), n)) { + return rustsecp256k1_v0_11_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); + } + f = rustsecp256k1_v0_11_ecmult_strauss_batch; + } + for(i = 0; i < n_batches; i++) { + size_t nbp = n < n_batch_points ? n : n_batch_points; + size_t offset = n_batch_points*i; + rustsecp256k1_v0_11_gej tmp; + if (!f(error_callback, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) { + return 0; + } + rustsecp256k1_v0_11_gej_add_var(r, r, &tmp, NULL); + n -= nbp; + } + return 1; +} + +#endif /* SECP256K1_ECMULT_IMPL_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field.h new file mode 100644 index 00000000..dd4e3835 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field.h @@ -0,0 +1,350 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_FIELD_H +#define SECP256K1_FIELD_H + +#include "util.h" + +/* This file defines the generic interface for working with rustsecp256k1_v0_11_fe + * objects, which represent field elements (integers modulo 2^256 - 2^32 - 977). + * + * The actual definition of the rustsecp256k1_v0_11_fe type depends on the chosen field + * implementation; see the field_5x52.h and field_10x26.h files for details. + * + * All rustsecp256k1_v0_11_fe objects have implicit properties that determine what + * operations are permitted on it. These are purely a function of what + * rustsecp256k1_v0_11_fe_ operations are applied on it, generally (implicitly) fixed at + * compile time, and do not depend on the chosen field implementation. Despite + * that, what these properties actually entail for the field representation + * values depends on the chosen field implementation. These properties are: + * - magnitude: an integer in [0,32] + * - normalized: 0 or 1; normalized=1 implies magnitude <= 1. + * + * In VERIFY mode, they are materialized explicitly as fields in the struct, + * allowing run-time verification of these properties. In that case, the field + * implementation also provides a rustsecp256k1_v0_11_fe_verify routine to verify that + * these fields match the run-time value and perform internal consistency + * checks. */ +#ifdef VERIFY +# define SECP256K1_FE_VERIFY_FIELDS \ + int magnitude; \ + int normalized; +#else +# define SECP256K1_FE_VERIFY_FIELDS +#endif + +#if defined(SECP256K1_WIDEMUL_INT128) +#include "field_5x52.h" +#elif defined(SECP256K1_WIDEMUL_INT64) +#include "field_10x26.h" +#else +#error "Please select wide multiplication implementation" +#endif + +#ifdef VERIFY +/* Magnitude and normalized value for constants. */ +#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) \ + /* Magnitude is 0 for constant 0; 1 otherwise. */ \ + , (((d7) | (d6) | (d5) | (d4) | (d3) | (d2) | (d1) | (d0)) != 0) \ + /* Normalized is 1 unless sum(d_i<<(32*i) for i=0..7) exceeds field modulus. */ \ + , (!(((d7) & (d6) & (d5) & (d4) & (d3) & (d2)) == 0xfffffffful && ((d1) == 0xfffffffful || ((d1) == 0xfffffffe && (d0 >= 0xfffffc2f))))) +#else +#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) +#endif + +/** This expands to an initializer for a rustsecp256k1_v0_11_fe valued sum((i*32) * d_i, i=0..7) mod p. + * + * It has magnitude 1, unless d_i are all 0, in which case the magnitude is 0. + * It is normalized, unless sum(2^(i*32) * d_i, i=0..7) >= p. + * + * SECP256K1_FE_CONST_INNER is provided by the implementation. + */ +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) SECP256K1_FE_VERIFY_CONST((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) } + +static const rustsecp256k1_v0_11_fe rustsecp256k1_v0_11_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); +static const rustsecp256k1_v0_11_fe rustsecp256k1_v0_11_const_beta = SECP256K1_FE_CONST( + 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, + 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul +); + +#ifndef VERIFY +/* In non-VERIFY mode, we #define the fe operations to be identical to their + * internal field implementation, to avoid the potential overhead of a + * function call (even though presumably inlinable). */ +# define rustsecp256k1_v0_11_fe_normalize rustsecp256k1_v0_11_fe_impl_normalize +# define rustsecp256k1_v0_11_fe_normalize_weak rustsecp256k1_v0_11_fe_impl_normalize_weak +# define rustsecp256k1_v0_11_fe_normalize_var rustsecp256k1_v0_11_fe_impl_normalize_var +# define rustsecp256k1_v0_11_fe_normalizes_to_zero rustsecp256k1_v0_11_fe_impl_normalizes_to_zero +# define rustsecp256k1_v0_11_fe_normalizes_to_zero_var rustsecp256k1_v0_11_fe_impl_normalizes_to_zero_var +# define rustsecp256k1_v0_11_fe_set_int rustsecp256k1_v0_11_fe_impl_set_int +# define rustsecp256k1_v0_11_fe_is_zero rustsecp256k1_v0_11_fe_impl_is_zero +# define rustsecp256k1_v0_11_fe_is_odd rustsecp256k1_v0_11_fe_impl_is_odd +# define rustsecp256k1_v0_11_fe_cmp_var rustsecp256k1_v0_11_fe_impl_cmp_var +# define rustsecp256k1_v0_11_fe_set_b32_mod rustsecp256k1_v0_11_fe_impl_set_b32_mod +# define rustsecp256k1_v0_11_fe_set_b32_limit rustsecp256k1_v0_11_fe_impl_set_b32_limit +# define rustsecp256k1_v0_11_fe_get_b32 rustsecp256k1_v0_11_fe_impl_get_b32 +# define rustsecp256k1_v0_11_fe_negate_unchecked rustsecp256k1_v0_11_fe_impl_negate_unchecked +# define rustsecp256k1_v0_11_fe_mul_int_unchecked rustsecp256k1_v0_11_fe_impl_mul_int_unchecked +# define rustsecp256k1_v0_11_fe_add rustsecp256k1_v0_11_fe_impl_add +# define rustsecp256k1_v0_11_fe_mul rustsecp256k1_v0_11_fe_impl_mul +# define rustsecp256k1_v0_11_fe_sqr rustsecp256k1_v0_11_fe_impl_sqr +# define rustsecp256k1_v0_11_fe_cmov rustsecp256k1_v0_11_fe_impl_cmov +# define rustsecp256k1_v0_11_fe_to_storage rustsecp256k1_v0_11_fe_impl_to_storage +# define rustsecp256k1_v0_11_fe_from_storage rustsecp256k1_v0_11_fe_impl_from_storage +# define rustsecp256k1_v0_11_fe_inv rustsecp256k1_v0_11_fe_impl_inv +# define rustsecp256k1_v0_11_fe_inv_var rustsecp256k1_v0_11_fe_impl_inv_var +# define rustsecp256k1_v0_11_fe_get_bounds rustsecp256k1_v0_11_fe_impl_get_bounds +# define rustsecp256k1_v0_11_fe_half rustsecp256k1_v0_11_fe_impl_half +# define rustsecp256k1_v0_11_fe_add_int rustsecp256k1_v0_11_fe_impl_add_int +# define rustsecp256k1_v0_11_fe_is_square_var rustsecp256k1_v0_11_fe_impl_is_square_var +#endif /* !defined(VERIFY) */ + +/** Normalize a field element. + * + * On input, r must be a valid field element. + * On output, r represents the same value but has normalized=1 and magnitude=1. + */ +static void rustsecp256k1_v0_11_fe_normalize(rustsecp256k1_v0_11_fe *r); + +/** Give a field element magnitude 1. + * + * On input, r must be a valid field element. + * On output, r represents the same value but has magnitude=1. Normalized is unchanged. + */ +static void rustsecp256k1_v0_11_fe_normalize_weak(rustsecp256k1_v0_11_fe *r); + +/** Normalize a field element, without constant-time guarantee. + * + * Identical in behavior to rustsecp256k1_v0_11_fe_normalize, but not constant time in r. + */ +static void rustsecp256k1_v0_11_fe_normalize_var(rustsecp256k1_v0_11_fe *r); + +/** Determine whether r represents field element 0. + * + * On input, r must be a valid field element. + * Returns whether r = 0 (mod p). + */ +static int rustsecp256k1_v0_11_fe_normalizes_to_zero(const rustsecp256k1_v0_11_fe *r); + +/** Determine whether r represents field element 0, without constant-time guarantee. + * + * Identical in behavior to rustsecp256k1_v0_11_normalizes_to_zero, but not constant time in r. + */ +static int rustsecp256k1_v0_11_fe_normalizes_to_zero_var(const rustsecp256k1_v0_11_fe *r); + +/** Set a field element to an integer in range [0,0x7FFF]. + * + * On input, r does not need to be initialized, a must be in [0,0x7FFF]. + * On output, r represents value a, is normalized and has magnitude (a!=0). + */ +static void rustsecp256k1_v0_11_fe_set_int(rustsecp256k1_v0_11_fe *r, int a); + +/** Clear a field element to prevent leaking sensitive information. */ +static void rustsecp256k1_v0_11_fe_clear(rustsecp256k1_v0_11_fe *a); + +/** Determine whether a represents field element 0. + * + * On input, a must be a valid normalized field element. + * Returns whether a = 0 (mod p). + * + * This behaves identical to rustsecp256k1_v0_11_normalizes_to_zero{,_var}, but requires + * normalized input (and is much faster). + */ +static int rustsecp256k1_v0_11_fe_is_zero(const rustsecp256k1_v0_11_fe *a); + +/** Determine whether a (mod p) is odd. + * + * On input, a must be a valid normalized field element. + * Returns (int(a) mod p) & 1. + */ +static int rustsecp256k1_v0_11_fe_is_odd(const rustsecp256k1_v0_11_fe *a); + +/** Determine whether two field elements are equal. + * + * On input, a and b must be valid field elements with magnitudes not exceeding + * 1 and 31, respectively. + * Returns a = b (mod p). + */ +static int rustsecp256k1_v0_11_fe_equal(const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe *b); + +/** Compare the values represented by 2 field elements, without constant-time guarantee. + * + * On input, a and b must be valid normalized field elements. + * Returns 1 if a > b, -1 if a < b, and 0 if a = b (comparisons are done as integers + * in range 0..p-1). + */ +static int rustsecp256k1_v0_11_fe_cmp_var(const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe *b); + +/** Set a field element equal to the element represented by a provided 32-byte big endian value + * interpreted modulo p. + * + * On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array. + * On output, r = a (mod p). It will have magnitude 1, and not be normalized. + */ +static void rustsecp256k1_v0_11_fe_set_b32_mod(rustsecp256k1_v0_11_fe *r, const unsigned char *a); + +/** Set a field element equal to a provided 32-byte big endian value, checking for overflow. + * + * On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array. + * On output, r = a if (a < p), it will be normalized with magnitude 1, and 1 is returned. + * If a >= p, 0 is returned, and r will be made invalid (and must not be used without overwriting). + */ +static int rustsecp256k1_v0_11_fe_set_b32_limit(rustsecp256k1_v0_11_fe *r, const unsigned char *a); + +/** Convert a field element to 32-byte big endian byte array. + * On input, a must be a valid normalized field element, and r a pointer to a 32-byte array. + * On output, r = a (mod p). + */ +static void rustsecp256k1_v0_11_fe_get_b32(unsigned char *r, const rustsecp256k1_v0_11_fe *a); + +/** Negate a field element. + * + * On input, r does not need to be initialized. a must be a valid field element with + * magnitude not exceeding m. m must be an integer constant expression in [0,31]. + * Performs {r = -a}. + * On output, r will not be normalized, and will have magnitude m+1. + */ +#define rustsecp256k1_v0_11_fe_negate(r, a, m) ASSERT_INT_CONST_AND_DO(m, rustsecp256k1_v0_11_fe_negate_unchecked(r, a, m)) + +/** Like rustsecp256k1_v0_11_fe_negate_unchecked but m is not checked to be an integer constant expression. + * + * Should not be called directly outside of tests. + */ +static void rustsecp256k1_v0_11_fe_negate_unchecked(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, int m); + +/** Add a small integer to a field element. + * + * Performs {r += a}. The magnitude of r increases by 1, and normalized is cleared. + * a must be in range [0,0x7FFF]. + */ +static void rustsecp256k1_v0_11_fe_add_int(rustsecp256k1_v0_11_fe *r, int a); + +/** Multiply a field element with a small integer. + * + * On input, r must be a valid field element. a must be an integer constant expression in [0,32]. + * The magnitude of r times a must not exceed 32. + * Performs {r *= a}. + * On output, r's magnitude is multiplied by a, and r will not be normalized. + */ +#define rustsecp256k1_v0_11_fe_mul_int(r, a) ASSERT_INT_CONST_AND_DO(a, rustsecp256k1_v0_11_fe_mul_int_unchecked(r, a)) + +/** Like rustsecp256k1_v0_11_fe_mul_int but a is not checked to be an integer constant expression. + * + * Should not be called directly outside of tests. + */ +static void rustsecp256k1_v0_11_fe_mul_int_unchecked(rustsecp256k1_v0_11_fe *r, int a); + +/** Increment a field element by another. + * + * On input, r and a must be valid field elements, not necessarily normalized. + * The sum of their magnitudes must not exceed 32. + * Performs {r += a}. + * On output, r will not be normalized, and will have magnitude incremented by a's. + */ +static void rustsecp256k1_v0_11_fe_add(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a); + +/** Multiply two field elements. + * + * On input, a and b must be valid field elements; r does not need to be initialized. + * r and a may point to the same object, but neither may point to the object pointed + * to by b. The magnitudes of a and b must not exceed 8. + * Performs {r = a * b} + * On output, r will have magnitude 1, but won't be normalized. + */ +static void rustsecp256k1_v0_11_fe_mul(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe * SECP256K1_RESTRICT b); + +/** Square a field element. + * + * On input, a must be a valid field element; r does not need to be initialized. The magnitude + * of a must not exceed 8. + * Performs {r = a**2} + * On output, r will have magnitude 1, but won't be normalized. + */ +static void rustsecp256k1_v0_11_fe_sqr(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a); + +/** Compute a square root of a field element. + * + * On input, a must be a valid field element with magnitude<=8; r need not be initialized. + * If sqrt(a) exists, performs {r = sqrt(a)} and returns 1. + * Otherwise, sqrt(-a) exists. The function performs {r = sqrt(-a)} and returns 0. + * The resulting value represented by r will be a square itself. + * Variables r and a must not point to the same object. + * On output, r will have magnitude 1 but will not be normalized. + */ +static int rustsecp256k1_v0_11_fe_sqrt(rustsecp256k1_v0_11_fe * SECP256K1_RESTRICT r, const rustsecp256k1_v0_11_fe * SECP256K1_RESTRICT a); + +/** Compute the modular inverse of a field element. + * + * On input, a must be a valid field element; r need not be initialized. + * Performs {r = a**(p-2)} (which maps 0 to 0, and every other element to its + * inverse). + * On output, r will have magnitude (a.magnitude != 0) and be normalized. + */ +static void rustsecp256k1_v0_11_fe_inv(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a); + +/** Compute the modular inverse of a field element, without constant-time guarantee. + * + * Behaves identically to rustsecp256k1_v0_11_fe_inv, but is not constant-time in a. + */ +static void rustsecp256k1_v0_11_fe_inv_var(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a); + +/** Convert a field element to rustsecp256k1_v0_11_fe_storage. + * + * On input, a must be a valid normalized field element. + * Performs {r = a}. + */ +static void rustsecp256k1_v0_11_fe_to_storage(rustsecp256k1_v0_11_fe_storage *r, const rustsecp256k1_v0_11_fe *a); + +/** Convert a field element back from rustsecp256k1_v0_11_fe_storage. + * + * On input, r need not be initialized. + * Performs {r = a}. + * On output, r will be normalized and will have magnitude 1. + */ +static void rustsecp256k1_v0_11_fe_from_storage(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe_storage *a); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +static void rustsecp256k1_v0_11_fe_storage_cmov(rustsecp256k1_v0_11_fe_storage *r, const rustsecp256k1_v0_11_fe_storage *a, int flag); + +/** Conditionally move a field element in constant time. + * + * On input, both r and a must be valid field elements. Flag must be 0 or 1. + * Performs {r = flag ? a : r}. + * + * On output, r's magnitude will be the maximum of both input magnitudes. + * It will be normalized if and only if both inputs were normalized. + */ +static void rustsecp256k1_v0_11_fe_cmov(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, int flag); + +/** Halve the value of a field element modulo the field prime in constant-time. + * + * On input, r must be a valid field element. + * On output, r will be normalized and have magnitude floor(m/2) + 1 where m is + * the magnitude of r on input. + */ +static void rustsecp256k1_v0_11_fe_half(rustsecp256k1_v0_11_fe *r); + +/** Sets r to a field element with magnitude m, normalized if (and only if) m==0. + * The value is chosen so that it is likely to trigger edge cases related to + * internal overflows. */ +static void rustsecp256k1_v0_11_fe_get_bounds(rustsecp256k1_v0_11_fe *r, int m); + +/** Determine whether a is a square (modulo p). + * + * On input, a must be a valid field element. + */ +static int rustsecp256k1_v0_11_fe_is_square_var(const rustsecp256k1_v0_11_fe *a); + +/** Check invariants on a field element (no-op unless VERIFY is enabled). */ +static void rustsecp256k1_v0_11_fe_verify(const rustsecp256k1_v0_11_fe *a); +#define SECP256K1_FE_VERIFY(a) rustsecp256k1_v0_11_fe_verify(a) + +/** Check that magnitude of a is at most m (no-op unless VERIFY is enabled). */ +static void rustsecp256k1_v0_11_fe_verify_magnitude(const rustsecp256k1_v0_11_fe *a, int m); +#define SECP256K1_FE_VERIFY_MAGNITUDE(a, m) rustsecp256k1_v0_11_fe_verify_magnitude(a, m) + +#endif /* SECP256K1_FIELD_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_10x26.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_10x26.h similarity index 63% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_10x26.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_10x26.h index 088a237a..0371dc41 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_10x26.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_10x26.h @@ -9,16 +9,29 @@ #include +/** This field implementation represents the value as 10 uint32_t limbs in base + * 2^26. */ typedef struct { - /* X = sum(i=0..9, n[i]*2^(i*26)) mod p - * where p = 2^256 - 0x1000003D1 - */ + /* A field element f represents the sum(i=0..9, f.n[i] << (i*26)) mod p, + * where p is the field modulus, 2^256 - 2^32 - 977. + * + * The individual limbs f.n[i] can exceed 2^26; the field's magnitude roughly + * corresponds to how much excess is allowed. The value + * sum(i=0..9, f.n[i] << (i*26)) may exceed p, unless the field element is + * normalized. */ uint32_t n[10]; -#ifdef VERIFY - int magnitude; - int normalized; -#endif -} rustsecp256k1zkp_v0_8_0_fe; + /* + * Magnitude m requires: + * n[i] <= 2 * m * (2^26 - 1) for i=0..8 + * n[9] <= 2 * m * (2^22 - 1) + * + * Normalized requires: + * n[i] <= (2^26 - 1) for i=0..8 + * sum(i=0..9, n[i] << (i*26)) < p + * (together these imply n[9] <= 2^22 - 1) + */ + SECP256K1_FE_VERIFY_FIELDS +} rustsecp256k1_v0_11_fe; /* Unpacks a constant into a overlapping multi-limbed FE element. */ #define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ @@ -34,15 +47,9 @@ typedef struct { (((uint32_t)d7) >> 10) \ } -#ifdef VERIFY -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} -#else -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} -#endif - typedef struct { uint32_t n[8]; -} rustsecp256k1zkp_v0_8_0_fe_storage; +} rustsecp256k1_v0_11_fe_storage; #define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }} #define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0] diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_10x26_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_10x26_impl.h similarity index 82% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_10x26_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_10x26_impl.h index 404fe6db..a85241b9 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_10x26_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_10x26_impl.h @@ -7,51 +7,37 @@ #ifndef SECP256K1_FIELD_REPR_IMPL_H #define SECP256K1_FIELD_REPR_IMPL_H +#include "checkmem.h" #include "util.h" #include "field.h" #include "modinv32_impl.h" -/** See the comment at the top of field_5x52_impl.h for more details. - * - * Here, we represent field elements as 10 uint32_t's in base 2^26, least significant first, - * where limbs can contain >26 bits. - * A magnitude M means: - * - 2*M*(2^22-1) is the max (inclusive) of the most significant limb - * - 2*M*(2^26-1) is the max (inclusive) of the remaining limbs - */ - #ifdef VERIFY -static void rustsecp256k1zkp_v0_8_0_fe_verify(const rustsecp256k1zkp_v0_8_0_fe *a) { +static void rustsecp256k1_v0_11_fe_impl_verify(const rustsecp256k1_v0_11_fe *a) { const uint32_t *d = a->n; - int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; - r &= (d[0] <= 0x3FFFFFFUL * m); - r &= (d[1] <= 0x3FFFFFFUL * m); - r &= (d[2] <= 0x3FFFFFFUL * m); - r &= (d[3] <= 0x3FFFFFFUL * m); - r &= (d[4] <= 0x3FFFFFFUL * m); - r &= (d[5] <= 0x3FFFFFFUL * m); - r &= (d[6] <= 0x3FFFFFFUL * m); - r &= (d[7] <= 0x3FFFFFFUL * m); - r &= (d[8] <= 0x3FFFFFFUL * m); - r &= (d[9] <= 0x03FFFFFUL * m); - r &= (a->magnitude >= 0); - r &= (a->magnitude <= 32); + int m = a->normalized ? 1 : 2 * a->magnitude; + VERIFY_CHECK(d[0] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[1] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[2] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[3] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[4] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[5] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[6] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[7] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[8] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[9] <= 0x03FFFFFUL * m); if (a->normalized) { - r &= (a->magnitude <= 1); - if (r && (d[9] == 0x03FFFFFUL)) { + if (d[9] == 0x03FFFFFUL) { uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2]; if (mid == 0x3FFFFFFUL) { - r &= ((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); + VERIFY_CHECK((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); } } } - VERIFY_CHECK(r == 1); } #endif -static void rustsecp256k1zkp_v0_8_0_fe_get_bounds(rustsecp256k1zkp_v0_8_0_fe *r, int m) { - VERIFY_CHECK(m >= 0); - VERIFY_CHECK(m <= 2048); +static void rustsecp256k1_v0_11_fe_impl_get_bounds(rustsecp256k1_v0_11_fe *r, int m) { r->n[0] = 0x3FFFFFFUL * 2 * m; r->n[1] = 0x3FFFFFFUL * 2 * m; r->n[2] = 0x3FFFFFFUL * 2 * m; @@ -62,14 +48,9 @@ static void rustsecp256k1zkp_v0_8_0_fe_get_bounds(rustsecp256k1zkp_v0_8_0_fe *r, r->n[7] = 0x3FFFFFFUL * 2 * m; r->n[8] = 0x3FFFFFFUL * 2 * m; r->n[9] = 0x03FFFFFUL * 2 * m; -#ifdef VERIFY - r->magnitude = m; - r->normalized = (m == 0); - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static void rustsecp256k1zkp_v0_8_0_fe_normalize(rustsecp256k1zkp_v0_8_0_fe *r) { +static void rustsecp256k1_v0_11_fe_impl_normalize(rustsecp256k1_v0_11_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -116,15 +97,9 @@ static void rustsecp256k1zkp_v0_8_0_fe_normalize(rustsecp256k1zkp_v0_8_0_fe *r) r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static void rustsecp256k1zkp_v0_8_0_fe_normalize_weak(rustsecp256k1zkp_v0_8_0_fe *r) { +static void rustsecp256k1_v0_11_fe_impl_normalize_weak(rustsecp256k1_v0_11_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -148,14 +123,9 @@ static void rustsecp256k1zkp_v0_8_0_fe_normalize_weak(rustsecp256k1zkp_v0_8_0_fe r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static void rustsecp256k1zkp_v0_8_0_fe_normalize_var(rustsecp256k1zkp_v0_8_0_fe *r) { +static void rustsecp256k1_v0_11_fe_impl_normalize_var(rustsecp256k1_v0_11_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -203,15 +173,9 @@ static void rustsecp256k1zkp_v0_8_0_fe_normalize_var(rustsecp256k1zkp_v0_8_0_fe r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static int rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(const rustsecp256k1zkp_v0_8_0_fe *r) { +static int rustsecp256k1_v0_11_fe_impl_normalizes_to_zero(const rustsecp256k1_v0_11_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -240,7 +204,7 @@ static int rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(const rustsecp256k1zkp_ return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -static int rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(const rustsecp256k1zkp_v0_8_0_fe *r) { +static int rustsecp256k1_v0_11_fe_impl_normalizes_to_zero_var(const rustsecp256k1_v0_11_fe *r) { uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; uint32_t z0, z1; uint32_t x; @@ -292,53 +256,22 @@ static int rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(const rustsecp256k1 return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_set_int(rustsecp256k1zkp_v0_8_0_fe *r, int a) { - VERIFY_CHECK(0 <= a && a <= 0x7FFF); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_set_int(rustsecp256k1_v0_11_fe *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; -#ifdef VERIFY - r->magnitude = (a != 0); - r->normalized = 1; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_fe_is_zero(const rustsecp256k1zkp_v0_8_0_fe *a) { +SECP256K1_INLINE static int rustsecp256k1_v0_11_fe_impl_is_zero(const rustsecp256k1_v0_11_fe *a) { const uint32_t *t = a->n; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - rustsecp256k1zkp_v0_8_0_fe_verify(a); -#endif return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; } -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_fe_is_odd(const rustsecp256k1zkp_v0_8_0_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - rustsecp256k1zkp_v0_8_0_fe_verify(a); -#endif +SECP256K1_INLINE static int rustsecp256k1_v0_11_fe_impl_is_odd(const rustsecp256k1_v0_11_fe *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_clear(rustsecp256k1zkp_v0_8_0_fe *a) { +static int rustsecp256k1_v0_11_fe_impl_cmp_var(const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe *b) { int i; -#ifdef VERIFY - a->magnitude = 0; - a->normalized = 1; -#endif - for (i=0; i<10; i++) { - a->n[i] = 0; - } -} - -static int rustsecp256k1zkp_v0_8_0_fe_cmp_var(const rustsecp256k1zkp_v0_8_0_fe *a, const rustsecp256k1zkp_v0_8_0_fe *b) { - int i; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - rustsecp256k1zkp_v0_8_0_fe_verify(a); - rustsecp256k1zkp_v0_8_0_fe_verify(b); -#endif for (i = 9; i >= 0; i--) { if (a->n[i] > b->n[i]) { return 1; @@ -350,8 +283,7 @@ static int rustsecp256k1zkp_v0_8_0_fe_cmp_var(const rustsecp256k1zkp_v0_8_0_fe * return 0; } -static int rustsecp256k1zkp_v0_8_0_fe_set_b32(rustsecp256k1zkp_v0_8_0_fe *r, const unsigned char *a) { - int ret; +static void rustsecp256k1_v0_11_fe_impl_set_b32_mod(rustsecp256k1_v0_11_fe *r, const unsigned char *a) { r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24); r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22); r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20); @@ -362,26 +294,15 @@ static int rustsecp256k1zkp_v0_8_0_fe_set_b32(rustsecp256k1zkp_v0_8_0_fe *r, con r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18); r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24); r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14); +} - ret = !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); -#ifdef VERIFY - r->magnitude = 1; - if (ret) { - r->normalized = 1; - rustsecp256k1zkp_v0_8_0_fe_verify(r); - } else { - r->normalized = 0; - } -#endif - return ret; +static int rustsecp256k1_v0_11_fe_impl_set_b32_limit(rustsecp256k1_v0_11_fe *r, const unsigned char *a) { + rustsecp256k1_v0_11_fe_impl_set_b32_mod(r, a); + return !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void rustsecp256k1zkp_v0_8_0_fe_get_b32(unsigned char *r, const rustsecp256k1zkp_v0_8_0_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - rustsecp256k1zkp_v0_8_0_fe_verify(a); -#endif +static void rustsecp256k1_v0_11_fe_impl_get_b32(unsigned char *r, const rustsecp256k1_v0_11_fe *a) { r[0] = (a->n[9] >> 14) & 0xff; r[1] = (a->n[9] >> 6) & 0xff; r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3); @@ -416,15 +337,15 @@ static void rustsecp256k1zkp_v0_8_0_fe_get_b32(unsigned char *r, const rustsecp2 r[31] = a->n[0] & 0xff; } -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_negate(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a, int m) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= m); - rustsecp256k1zkp_v0_8_0_fe_verify(a); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_negate_unchecked(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, int m) { + /* For all legal values of m (0..31), the following properties hold: */ VERIFY_CHECK(0x3FFFC2FUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); VERIFY_CHECK(0x3FFFFBFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); VERIFY_CHECK(0x3FFFFFFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); VERIFY_CHECK(0x03FFFFFUL * 2 * (m + 1) >= 0x03FFFFFUL * 2 * m); -#endif + + /* Due to the properties above, the left hand in the subtractions below is never less than + * the right hand. */ r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0]; r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1]; r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2]; @@ -435,14 +356,9 @@ SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_negate(rustsecp256k1zkp_ r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7]; r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8]; r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9]; -#ifdef VERIFY - r->magnitude = m + 1; - r->normalized = 0; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_mul_int(rustsecp256k1zkp_v0_8_0_fe *r, int a) { +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_mul_int_unchecked(rustsecp256k1_v0_11_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; @@ -453,17 +369,9 @@ SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_mul_int(rustsecp256k1zkp r->n[7] *= a; r->n[8] *= a; r->n[9] *= a; -#ifdef VERIFY - r->magnitude *= a; - r->normalized = 0; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_add(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a) { -#ifdef VERIFY - rustsecp256k1zkp_v0_8_0_fe_verify(a); -#endif +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_add(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a) { r->n[0] += a->n[0]; r->n[1] += a->n[1]; r->n[2] += a->n[2]; @@ -474,28 +382,23 @@ SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_add(rustsecp256k1zkp_v0_ r->n[7] += a->n[7]; r->n[8] += a->n[8]; r->n[9] += a->n[9]; -#ifdef VERIFY - r->magnitude += a->magnitude; - r->normalized = 0; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif +} + +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_add_int(rustsecp256k1_v0_11_fe *r, int a) { + r->n[0] += a; } #if defined(USE_EXTERNAL_ASM) /* External assembler implementation */ -void rustsecp256k1zkp_v0_8_0_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b); -void rustsecp256k1zkp_v0_8_0_fe_sqr_inner(uint32_t *r, const uint32_t *a); +void rustsecp256k1_v0_11_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b); +void rustsecp256k1_v0_11_fe_sqr_inner(uint32_t *r, const uint32_t *a); #else -#ifdef VERIFY #define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) -#else -#define VERIFY_BITS(x, n) do { } while(0) -#endif -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) { +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) { uint64_t c, d; uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8; uint32_t t9, t1, t0, t2, t3, t4, t5, t6, t7; @@ -825,7 +728,7 @@ SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_mul_inner(uint32_t *r, c /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_sqr_inner(uint32_t *r, const uint32_t *a) { +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_sqr_inner(uint32_t *r, const uint32_t *a) { uint64_t c, d; uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8; uint32_t t9, t0, t1, t2, t3, t4, t5, t6, t7; @@ -1100,40 +1003,19 @@ SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_sqr_inner(uint32_t *r, c } #endif -static void rustsecp256k1zkp_v0_8_0_fe_mul(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a, const rustsecp256k1zkp_v0_8_0_fe * SECP256K1_RESTRICT b) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - VERIFY_CHECK(b->magnitude <= 8); - rustsecp256k1zkp_v0_8_0_fe_verify(a); - rustsecp256k1zkp_v0_8_0_fe_verify(b); - VERIFY_CHECK(r != b); - VERIFY_CHECK(a != b); -#endif - rustsecp256k1zkp_v0_8_0_fe_mul_inner(r->n, a->n, b->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_mul(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe * SECP256K1_RESTRICT b) { + rustsecp256k1_v0_11_fe_mul_inner(r->n, a->n, b->n); } -static void rustsecp256k1zkp_v0_8_0_fe_sqr(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - rustsecp256k1zkp_v0_8_0_fe_verify(a); -#endif - rustsecp256k1zkp_v0_8_0_fe_sqr_inner(r->n, a->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_sqr(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a) { + rustsecp256k1_v0_11_fe_sqr_inner(r->n, a->n); } -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_cmov(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a, int flag) { +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_cmov(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, int flag) { uint32_t mask0, mask1; - VG_CHECK_VERIFY(r->n, sizeof(r->n)); - mask0 = flag + ~((uint32_t)0); + volatile int vflag = flag; + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); + mask0 = vflag + ~((uint32_t)0); mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); @@ -1145,25 +1027,14 @@ static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_cmov(rustsecp256k1zkp_v0 r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); -#ifdef VERIFY - if (flag) { - r->magnitude = a->magnitude; - r->normalized = a->normalized; - } -#endif } -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_half(rustsecp256k1zkp_v0_8_0_fe *r) { +static SECP256K1_INLINE void rustsecp256k1_v0_11_fe_impl_half(rustsecp256k1_v0_11_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; uint32_t one = (uint32_t)1; uint32_t mask = -(t0 & one) >> 6; -#ifdef VERIFY - rustsecp256k1zkp_v0_8_0_fe_verify(r); - VERIFY_CHECK(r->magnitude < 32); -#endif - /* Bounds analysis (over the rationals). * * Let m = r->magnitude @@ -1210,10 +1081,8 @@ static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_half(rustsecp256k1zkp_v0 * * Current bounds: t0..t8 <= C * (m/2 + 1/2) * t9 <= D * (m/2 + 1/4) - */ - -#ifdef VERIFY - /* Therefore the output magnitude (M) has to be set such that: + * + * Therefore the output magnitude (M) has to be set such that: * t0..t8: C * M >= C * (m/2 + 1/2) * t9: D * M >= D * (m/2 + 1/4) * @@ -1223,16 +1092,13 @@ static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_half(rustsecp256k1zkp_v0 * and since we want the smallest such integer value for M: * M == floor(m/2) + 1 */ - r->magnitude = (r->magnitude >> 1) + 1; - r->normalized = 0; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_storage_cmov(rustsecp256k1zkp_v0_8_0_fe_storage *r, const rustsecp256k1zkp_v0_8_0_fe_storage *a, int flag) { +static SECP256K1_INLINE void rustsecp256k1_v0_11_fe_storage_cmov(rustsecp256k1_v0_11_fe_storage *r, const rustsecp256k1_v0_11_fe_storage *a, int flag) { uint32_t mask0, mask1; - VG_CHECK_VERIFY(r->n, sizeof(r->n)); - mask0 = flag + ~((uint32_t)0); + volatile int vflag = flag; + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); + mask0 = vflag + ~((uint32_t)0); mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); @@ -1244,10 +1110,7 @@ static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_storage_cmov(rustsecp256 r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); } -static void rustsecp256k1zkp_v0_8_0_fe_to_storage(rustsecp256k1zkp_v0_8_0_fe_storage *r, const rustsecp256k1zkp_v0_8_0_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif +static void rustsecp256k1_v0_11_fe_impl_to_storage(rustsecp256k1_v0_11_fe_storage *r, const rustsecp256k1_v0_11_fe *a) { r->n[0] = a->n[0] | a->n[1] << 26; r->n[1] = a->n[1] >> 6 | a->n[2] << 20; r->n[2] = a->n[2] >> 12 | a->n[3] << 14; @@ -1258,7 +1121,7 @@ static void rustsecp256k1zkp_v0_8_0_fe_to_storage(rustsecp256k1zkp_v0_8_0_fe_sto r->n[7] = a->n[8] >> 16 | a->n[9] << 10; } -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_from_storage(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe_storage *a) { +static SECP256K1_INLINE void rustsecp256k1_v0_11_fe_impl_from_storage(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe_storage *a) { r->n[0] = a->n[0] & 0x3FFFFFFUL; r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL); r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL); @@ -1269,19 +1132,14 @@ static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_from_storage(rustsecp256 r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL); r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL); r->n[9] = a->n[7] >> 10; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static void rustsecp256k1zkp_v0_8_0_fe_from_signed30(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_modinv32_signed30 *a) { +static void rustsecp256k1_v0_11_fe_from_signed30(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_modinv32_signed30 *a) { const uint32_t M26 = UINT32_MAX >> 6; const uint32_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4], a5 = a->v[5], a6 = a->v[6], a7 = a->v[7], a8 = a->v[8]; - /* The output from rustsecp256k1zkp_v0_8_0_modinv32{_var} should be normalized to range [0,modulus), and + /* The output from rustsecp256k1_v0_11_modinv32{_var} should be normalized to range [0,modulus), and * have limbs in [0,2^30). The modulus is < 2^256, so the top limb must be below 2^(256-30*8). */ VERIFY_CHECK(a0 >> 30 == 0); @@ -1304,23 +1162,13 @@ static void rustsecp256k1zkp_v0_8_0_fe_from_signed30(rustsecp256k1zkp_v0_8_0_fe r->n[7] = (a6 >> 2 ) & M26; r->n[8] = (a6 >> 28 | a7 << 2) & M26; r->n[9] = (a7 >> 24 | a8 << 6); - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static void rustsecp256k1zkp_v0_8_0_fe_to_signed30(rustsecp256k1zkp_v0_8_0_modinv32_signed30 *r, const rustsecp256k1zkp_v0_8_0_fe *a) { +static void rustsecp256k1_v0_11_fe_to_signed30(rustsecp256k1_v0_11_modinv32_signed30 *r, const rustsecp256k1_v0_11_fe *a) { const uint32_t M30 = UINT32_MAX >> 2; const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4], a5 = a->n[5], a6 = a->n[6], a7 = a->n[7], a8 = a->n[8], a9 = a->n[9]; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif - r->v[0] = (a0 | a1 << 26) & M30; r->v[1] = (a1 >> 4 | a2 << 22) & M30; r->v[2] = (a2 >> 8 | a3 << 18) & M30; @@ -1333,35 +1181,52 @@ static void rustsecp256k1zkp_v0_8_0_fe_to_signed30(rustsecp256k1zkp_v0_8_0_modin r->v[8] = a9 >> 6; } -static const rustsecp256k1zkp_v0_8_0_modinv32_modinfo rustsecp256k1zkp_v0_8_0_const_modinfo_fe = { +static const rustsecp256k1_v0_11_modinv32_modinfo rustsecp256k1_v0_11_const_modinfo_fe = { {{-0x3D1, -4, 0, 0, 0, 0, 0, 0, 65536}}, 0x2DDACACFL }; -static void rustsecp256k1zkp_v0_8_0_fe_inv(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *x) { - rustsecp256k1zkp_v0_8_0_fe tmp; - rustsecp256k1zkp_v0_8_0_modinv32_signed30 s; +static void rustsecp256k1_v0_11_fe_impl_inv(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *x) { + rustsecp256k1_v0_11_fe tmp = *x; + rustsecp256k1_v0_11_modinv32_signed30 s; - tmp = *x; - rustsecp256k1zkp_v0_8_0_fe_normalize(&tmp); - rustsecp256k1zkp_v0_8_0_fe_to_signed30(&s, &tmp); - rustsecp256k1zkp_v0_8_0_modinv32(&s, &rustsecp256k1zkp_v0_8_0_const_modinfo_fe); - rustsecp256k1zkp_v0_8_0_fe_from_signed30(r, &s); + rustsecp256k1_v0_11_fe_normalize(&tmp); + rustsecp256k1_v0_11_fe_to_signed30(&s, &tmp); + rustsecp256k1_v0_11_modinv32(&s, &rustsecp256k1_v0_11_const_modinfo_fe); + rustsecp256k1_v0_11_fe_from_signed30(r, &s); +} - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(r) == rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(&tmp)); +static void rustsecp256k1_v0_11_fe_impl_inv_var(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *x) { + rustsecp256k1_v0_11_fe tmp = *x; + rustsecp256k1_v0_11_modinv32_signed30 s; + + rustsecp256k1_v0_11_fe_normalize_var(&tmp); + rustsecp256k1_v0_11_fe_to_signed30(&s, &tmp); + rustsecp256k1_v0_11_modinv32_var(&s, &rustsecp256k1_v0_11_const_modinfo_fe); + rustsecp256k1_v0_11_fe_from_signed30(r, &s); } -static void rustsecp256k1zkp_v0_8_0_fe_inv_var(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *x) { - rustsecp256k1zkp_v0_8_0_fe tmp; - rustsecp256k1zkp_v0_8_0_modinv32_signed30 s; +static int rustsecp256k1_v0_11_fe_impl_is_square_var(const rustsecp256k1_v0_11_fe *x) { + rustsecp256k1_v0_11_fe tmp; + rustsecp256k1_v0_11_modinv32_signed30 s; + int jac, ret; tmp = *x; - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&tmp); - rustsecp256k1zkp_v0_8_0_fe_to_signed30(&s, &tmp); - rustsecp256k1zkp_v0_8_0_modinv32_var(&s, &rustsecp256k1zkp_v0_8_0_const_modinfo_fe); - rustsecp256k1zkp_v0_8_0_fe_from_signed30(r, &s); - - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(r) == rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(&tmp)); + rustsecp256k1_v0_11_fe_normalize_var(&tmp); + /* rustsecp256k1_v0_11_jacobi32_maybe_var cannot deal with input 0. */ + if (rustsecp256k1_v0_11_fe_is_zero(&tmp)) return 1; + rustsecp256k1_v0_11_fe_to_signed30(&s, &tmp); + jac = rustsecp256k1_v0_11_jacobi32_maybe_var(&s, &rustsecp256k1_v0_11_const_modinfo_fe); + if (jac == 0) { + /* rustsecp256k1_v0_11_jacobi32_maybe_var failed to compute the Jacobi symbol. Fall back + * to computing a square root. This should be extremely rare with random + * input (except in VERIFY mode, where a lower iteration count is used). */ + rustsecp256k1_v0_11_fe dummy; + ret = rustsecp256k1_v0_11_fe_sqrt(&dummy, &tmp); + } else { + ret = jac >= 0; + } + return ret; } #endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_5x52.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_5x52.h similarity index 64% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_5x52.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_5x52.h index 8a01767b..d14ae4d8 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_5x52.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_5x52.h @@ -9,16 +9,29 @@ #include +/** This field implementation represents the value as 5 uint64_t limbs in base + * 2^52. */ typedef struct { - /* X = sum(i=0..4, n[i]*2^(i*52)) mod p - * where p = 2^256 - 0x1000003D1 - */ + /* A field element f represents the sum(i=0..4, f.n[i] << (i*52)) mod p, + * where p is the field modulus, 2^256 - 2^32 - 977. + * + * The individual limbs f.n[i] can exceed 2^52; the field's magnitude roughly + * corresponds to how much excess is allowed. The value + * sum(i=0..4, f.n[i] << (i*52)) may exceed p, unless the field element is + * normalized. */ uint64_t n[5]; -#ifdef VERIFY - int magnitude; - int normalized; -#endif -} rustsecp256k1zkp_v0_8_0_fe; + /* + * Magnitude m requires: + * n[i] <= 2 * m * (2^52 - 1) for i=0..3 + * n[4] <= 2 * m * (2^48 - 1) + * + * Normalized requires: + * n[i] <= (2^52 - 1) for i=0..3 + * sum(i=0..4, n[i] << (i*52)) < p + * (together these imply n[4] <= 2^48 - 1) + */ + SECP256K1_FE_VERIFY_FIELDS +} rustsecp256k1_v0_11_fe; /* Unpacks a constant into a overlapping multi-limbed FE element. */ #define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ @@ -29,15 +42,9 @@ typedef struct { ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \ } -#ifdef VERIFY -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} -#else -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} -#endif - typedef struct { uint64_t n[4]; -} rustsecp256k1zkp_v0_8_0_fe_storage; +} rustsecp256k1_v0_11_fe_storage; #define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \ (d0) | (((uint64_t)(d1)) << 32), \ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_5x52_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_5x52_impl.h similarity index 59% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_5x52_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_5x52_impl.h index 9d570118..1387e891 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/field_5x52_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_5x52_impl.h @@ -7,73 +7,40 @@ #ifndef SECP256K1_FIELD_REPR_IMPL_H #define SECP256K1_FIELD_REPR_IMPL_H -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - +#include "checkmem.h" #include "util.h" #include "field.h" #include "modinv64_impl.h" -#if defined(USE_ASM_X86_64) -#include "field_5x52_asm_impl.h" -#else #include "field_5x52_int128_impl.h" -#endif - -/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F, - * represented as 5 uint64_t's in base 2^52, least significant first. Note that the limbs are allowed to - * contain >52 bits each. - * - * Each field element has a 'magnitude' associated with it. Internally, a magnitude M means: - * - 2*M*(2^48-1) is the max (inclusive) of the most significant limb - * - 2*M*(2^52-1) is the max (inclusive) of the remaining limbs - * - * Operations have different rules for propagating magnitude to their outputs. If an operation takes a - * magnitude M as a parameter, that means the magnitude of input field elements can be at most M (inclusive). - * - * Each field element also has a 'normalized' flag. A field element is normalized if its magnitude is either - * 0 or 1, and its value is already reduced modulo the order of the field. - */ #ifdef VERIFY -static void rustsecp256k1zkp_v0_8_0_fe_verify(const rustsecp256k1zkp_v0_8_0_fe *a) { +static void rustsecp256k1_v0_11_fe_impl_verify(const rustsecp256k1_v0_11_fe *a) { const uint64_t *d = a->n; - int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; + int m = a->normalized ? 1 : 2 * a->magnitude; /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ - r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m); - r &= (a->magnitude >= 0); - r &= (a->magnitude <= 2048); + VERIFY_CHECK(d[0] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[1] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[2] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[3] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[4] <= 0x0FFFFFFFFFFFFULL * m); if (a->normalized) { - r &= (a->magnitude <= 1); - if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { - r &= (d[0] < 0xFFFFEFFFFFC2FULL); + if ((d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { + VERIFY_CHECK(d[0] < 0xFFFFEFFFFFC2FULL); } } - VERIFY_CHECK(r == 1); } #endif -static void rustsecp256k1zkp_v0_8_0_fe_get_bounds(rustsecp256k1zkp_v0_8_0_fe *r, int m) { - VERIFY_CHECK(m >= 0); - VERIFY_CHECK(m <= 2048); +static void rustsecp256k1_v0_11_fe_impl_get_bounds(rustsecp256k1_v0_11_fe *r, int m) { r->n[0] = 0xFFFFFFFFFFFFFULL * 2 * m; r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * m; r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * m; r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * m; r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * m; -#ifdef VERIFY - r->magnitude = m; - r->normalized = (m == 0); - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static void rustsecp256k1zkp_v0_8_0_fe_normalize(rustsecp256k1zkp_v0_8_0_fe *r) { +static void rustsecp256k1_v0_11_fe_impl_normalize(rustsecp256k1_v0_11_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -108,15 +75,9 @@ static void rustsecp256k1zkp_v0_8_0_fe_normalize(rustsecp256k1zkp_v0_8_0_fe *r) t4 &= 0x0FFFFFFFFFFFFULL; r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static void rustsecp256k1zkp_v0_8_0_fe_normalize_weak(rustsecp256k1zkp_v0_8_0_fe *r) { +static void rustsecp256k1_v0_11_fe_impl_normalize_weak(rustsecp256k1_v0_11_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -133,14 +94,9 @@ static void rustsecp256k1zkp_v0_8_0_fe_normalize_weak(rustsecp256k1zkp_v0_8_0_fe VERIFY_CHECK(t4 >> 49 == 0); r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static void rustsecp256k1zkp_v0_8_0_fe_normalize_var(rustsecp256k1zkp_v0_8_0_fe *r) { +static void rustsecp256k1_v0_11_fe_impl_normalize_var(rustsecp256k1_v0_11_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -176,15 +132,9 @@ static void rustsecp256k1zkp_v0_8_0_fe_normalize_var(rustsecp256k1zkp_v0_8_0_fe } r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static int rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(const rustsecp256k1zkp_v0_8_0_fe *r) { +static int rustsecp256k1_v0_11_fe_impl_normalizes_to_zero(const rustsecp256k1_v0_11_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ @@ -207,7 +157,7 @@ static int rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(const rustsecp256k1zkp_ return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); } -static int rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(const rustsecp256k1zkp_v0_8_0_fe *r) { +static int rustsecp256k1_v0_11_fe_impl_normalizes_to_zero_var(const rustsecp256k1_v0_11_fe *r) { uint64_t t0, t1, t2, t3, t4; uint64_t z0, z1; uint64_t x; @@ -248,53 +198,22 @@ static int rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(const rustsecp256k1 return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); } -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_set_int(rustsecp256k1zkp_v0_8_0_fe *r, int a) { - VERIFY_CHECK(0 <= a && a <= 0x7FFF); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_set_int(rustsecp256k1_v0_11_fe *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; -#ifdef VERIFY - r->magnitude = (a != 0); - r->normalized = 1; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_fe_is_zero(const rustsecp256k1zkp_v0_8_0_fe *a) { +SECP256K1_INLINE static int rustsecp256k1_v0_11_fe_impl_is_zero(const rustsecp256k1_v0_11_fe *a) { const uint64_t *t = a->n; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - rustsecp256k1zkp_v0_8_0_fe_verify(a); -#endif return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; } -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_fe_is_odd(const rustsecp256k1zkp_v0_8_0_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - rustsecp256k1zkp_v0_8_0_fe_verify(a); -#endif +SECP256K1_INLINE static int rustsecp256k1_v0_11_fe_impl_is_odd(const rustsecp256k1_v0_11_fe *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_clear(rustsecp256k1zkp_v0_8_0_fe *a) { - int i; -#ifdef VERIFY - a->magnitude = 0; - a->normalized = 1; -#endif - for (i=0; i<5; i++) { - a->n[i] = 0; - } -} - -static int rustsecp256k1zkp_v0_8_0_fe_cmp_var(const rustsecp256k1zkp_v0_8_0_fe *a, const rustsecp256k1zkp_v0_8_0_fe *b) { +static int rustsecp256k1_v0_11_fe_impl_cmp_var(const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe *b) { int i; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - rustsecp256k1zkp_v0_8_0_fe_verify(a); - rustsecp256k1zkp_v0_8_0_fe_verify(b); -#endif for (i = 4; i >= 0; i--) { if (a->n[i] > b->n[i]) { return 1; @@ -306,8 +225,7 @@ static int rustsecp256k1zkp_v0_8_0_fe_cmp_var(const rustsecp256k1zkp_v0_8_0_fe * return 0; } -static int rustsecp256k1zkp_v0_8_0_fe_set_b32(rustsecp256k1zkp_v0_8_0_fe *r, const unsigned char *a) { - int ret; +static void rustsecp256k1_v0_11_fe_impl_set_b32_mod(rustsecp256k1_v0_11_fe *r, const unsigned char *a) { r->n[0] = (uint64_t)a[31] | ((uint64_t)a[30] << 8) | ((uint64_t)a[29] << 16) @@ -342,25 +260,15 @@ static int rustsecp256k1zkp_v0_8_0_fe_set_b32(rustsecp256k1zkp_v0_8_0_fe *r, con | ((uint64_t)a[2] << 24) | ((uint64_t)a[1] << 32) | ((uint64_t)a[0] << 40); - ret = !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL)); -#ifdef VERIFY - r->magnitude = 1; - if (ret) { - r->normalized = 1; - rustsecp256k1zkp_v0_8_0_fe_verify(r); - } else { - r->normalized = 0; - } -#endif - return ret; +} + +static int rustsecp256k1_v0_11_fe_impl_set_b32_limit(rustsecp256k1_v0_11_fe *r, const unsigned char *a) { + rustsecp256k1_v0_11_fe_impl_set_b32_mod(r, a); + return !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL)); } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void rustsecp256k1zkp_v0_8_0_fe_get_b32(unsigned char *r, const rustsecp256k1zkp_v0_8_0_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - rustsecp256k1zkp_v0_8_0_fe_verify(a); -#endif +static void rustsecp256k1_v0_11_fe_impl_get_b32(unsigned char *r, const rustsecp256k1_v0_11_fe *a) { r[0] = (a->n[4] >> 40) & 0xFF; r[1] = (a->n[4] >> 32) & 0xFF; r[2] = (a->n[4] >> 24) & 0xFF; @@ -395,113 +303,67 @@ static void rustsecp256k1zkp_v0_8_0_fe_get_b32(unsigned char *r, const rustsecp2 r[31] = a->n[0] & 0xFF; } -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_negate(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a, int m) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= m); - rustsecp256k1zkp_v0_8_0_fe_verify(a); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_negate_unchecked(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, int m) { + /* For all legal values of m (0..31), the following properties hold: */ VERIFY_CHECK(0xFFFFEFFFFFC2FULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m); VERIFY_CHECK(0xFFFFFFFFFFFFFULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m); VERIFY_CHECK(0x0FFFFFFFFFFFFULL * 2 * (m + 1) >= 0x0FFFFFFFFFFFFULL * 2 * m); -#endif + + /* Due to the properties above, the left hand in the subtractions below is never less than + * the right hand. */ r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0]; r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1]; r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2]; r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3]; r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4]; -#ifdef VERIFY - r->magnitude = m + 1; - r->normalized = 0; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_mul_int(rustsecp256k1zkp_v0_8_0_fe *r, int a) { +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_mul_int_unchecked(rustsecp256k1_v0_11_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; r->n[3] *= a; r->n[4] *= a; -#ifdef VERIFY - r->magnitude *= a; - r->normalized = 0; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_fe_add(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a) { -#ifdef VERIFY - rustsecp256k1zkp_v0_8_0_fe_verify(a); -#endif +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_add_int(rustsecp256k1_v0_11_fe *r, int a) { + r->n[0] += a; +} + +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_add(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a) { r->n[0] += a->n[0]; r->n[1] += a->n[1]; r->n[2] += a->n[2]; r->n[3] += a->n[3]; r->n[4] += a->n[4]; -#ifdef VERIFY - r->magnitude += a->magnitude; - r->normalized = 0; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static void rustsecp256k1zkp_v0_8_0_fe_mul(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a, const rustsecp256k1zkp_v0_8_0_fe * SECP256K1_RESTRICT b) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - VERIFY_CHECK(b->magnitude <= 8); - rustsecp256k1zkp_v0_8_0_fe_verify(a); - rustsecp256k1zkp_v0_8_0_fe_verify(b); - VERIFY_CHECK(r != b); - VERIFY_CHECK(a != b); -#endif - rustsecp256k1zkp_v0_8_0_fe_mul_inner(r->n, a->n, b->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_mul(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe * SECP256K1_RESTRICT b) { + rustsecp256k1_v0_11_fe_mul_inner(r->n, a->n, b->n); } -static void rustsecp256k1zkp_v0_8_0_fe_sqr(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - rustsecp256k1zkp_v0_8_0_fe_verify(a); -#endif - rustsecp256k1zkp_v0_8_0_fe_sqr_inner(r->n, a->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_sqr(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a) { + rustsecp256k1_v0_11_fe_sqr_inner(r->n, a->n); } -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_cmov(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *a, int flag) { +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_impl_cmov(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, int flag) { uint64_t mask0, mask1; - VG_CHECK_VERIFY(r->n, sizeof(r->n)); - mask0 = flag + ~((uint64_t)0); + volatile int vflag = flag; + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); + mask0 = vflag + ~((uint64_t)0); mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); -#ifdef VERIFY - if (flag) { - r->magnitude = a->magnitude; - r->normalized = a->normalized; - } -#endif } -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_half(rustsecp256k1zkp_v0_8_0_fe *r) { +static SECP256K1_INLINE void rustsecp256k1_v0_11_fe_impl_half(rustsecp256k1_v0_11_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; uint64_t one = (uint64_t)1; uint64_t mask = -(t0 & one) >> 12; -#ifdef VERIFY - rustsecp256k1zkp_v0_8_0_fe_verify(r); - VERIFY_CHECK(r->magnitude < 32); -#endif - /* Bounds analysis (over the rationals). * * Let m = r->magnitude @@ -538,10 +400,8 @@ static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_half(rustsecp256k1zkp_v0 * * Current bounds: t0..t3 <= C * (m/2 + 1/2) * t4 <= D * (m/2 + 1/4) - */ - -#ifdef VERIFY - /* Therefore the output magnitude (M) has to be set such that: + * + * Therefore the output magnitude (M) has to be set such that: * t0..t3: C * M >= C * (m/2 + 1/2) * t4: D * M >= D * (m/2 + 1/4) * @@ -551,16 +411,13 @@ static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_half(rustsecp256k1zkp_v0 * and since we want the smallest such integer value for M: * M == floor(m/2) + 1 */ - r->magnitude = (r->magnitude >> 1) + 1; - r->normalized = 0; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_storage_cmov(rustsecp256k1zkp_v0_8_0_fe_storage *r, const rustsecp256k1zkp_v0_8_0_fe_storage *a, int flag) { +static SECP256K1_INLINE void rustsecp256k1_v0_11_fe_storage_cmov(rustsecp256k1_v0_11_fe_storage *r, const rustsecp256k1_v0_11_fe_storage *a, int flag) { uint64_t mask0, mask1; - VG_CHECK_VERIFY(r->n, sizeof(r->n)); - mask0 = flag + ~((uint64_t)0); + volatile int vflag = flag; + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); + mask0 = vflag + ~((uint64_t)0); mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); @@ -568,34 +425,26 @@ static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_storage_cmov(rustsecp256 r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); } -static void rustsecp256k1zkp_v0_8_0_fe_to_storage(rustsecp256k1zkp_v0_8_0_fe_storage *r, const rustsecp256k1zkp_v0_8_0_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif +static void rustsecp256k1_v0_11_fe_impl_to_storage(rustsecp256k1_v0_11_fe_storage *r, const rustsecp256k1_v0_11_fe *a) { r->n[0] = a->n[0] | a->n[1] << 52; r->n[1] = a->n[1] >> 12 | a->n[2] << 40; r->n[2] = a->n[2] >> 24 | a->n[3] << 28; r->n[3] = a->n[3] >> 36 | a->n[4] << 16; } -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_fe_from_storage(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe_storage *a) { +static SECP256K1_INLINE void rustsecp256k1_v0_11_fe_impl_from_storage(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe_storage *a) { r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL; r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL); r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL); r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL); r->n[4] = a->n[3] >> 16; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static void rustsecp256k1zkp_v0_8_0_fe_from_signed62(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_modinv64_signed62 *a) { +static void rustsecp256k1_v0_11_fe_from_signed62(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_modinv64_signed62 *a) { const uint64_t M52 = UINT64_MAX >> 12; const uint64_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4]; - /* The output from rustsecp256k1zkp_v0_8_0_modinv64{_var} should be normalized to range [0,modulus), and + /* The output from rustsecp256k1_v0_11_modinv64{_var} should be normalized to range [0,modulus), and * have limbs in [0,2^62). The modulus is < 2^256, so the top limb must be below 2^(256-62*4). */ VERIFY_CHECK(a0 >> 62 == 0); @@ -609,22 +458,12 @@ static void rustsecp256k1zkp_v0_8_0_fe_from_signed62(rustsecp256k1zkp_v0_8_0_fe r->n[2] = (a1 >> 42 | a2 << 20) & M52; r->n[3] = (a2 >> 32 | a3 << 30) & M52; r->n[4] = (a3 >> 22 | a4 << 40); - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - rustsecp256k1zkp_v0_8_0_fe_verify(r); -#endif } -static void rustsecp256k1zkp_v0_8_0_fe_to_signed62(rustsecp256k1zkp_v0_8_0_modinv64_signed62 *r, const rustsecp256k1zkp_v0_8_0_fe *a) { +static void rustsecp256k1_v0_11_fe_to_signed62(rustsecp256k1_v0_11_modinv64_signed62 *r, const rustsecp256k1_v0_11_fe *a) { const uint64_t M62 = UINT64_MAX >> 2; const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4]; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif - r->v[0] = (a0 | a1 << 52) & M62; r->v[1] = (a1 >> 10 | a2 << 42) & M62; r->v[2] = (a2 >> 20 | a3 << 32) & M62; @@ -632,39 +471,52 @@ static void rustsecp256k1zkp_v0_8_0_fe_to_signed62(rustsecp256k1zkp_v0_8_0_modin r->v[4] = a4 >> 40; } -static const rustsecp256k1zkp_v0_8_0_modinv64_modinfo rustsecp256k1zkp_v0_8_0_const_modinfo_fe = { +static const rustsecp256k1_v0_11_modinv64_modinfo rustsecp256k1_v0_11_const_modinfo_fe = { {{-0x1000003D1LL, 0, 0, 0, 256}}, 0x27C7F6E22DDACACFLL }; -static void rustsecp256k1zkp_v0_8_0_fe_inv(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *x) { - rustsecp256k1zkp_v0_8_0_fe tmp; - rustsecp256k1zkp_v0_8_0_modinv64_signed62 s; +static void rustsecp256k1_v0_11_fe_impl_inv(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *x) { + rustsecp256k1_v0_11_fe tmp = *x; + rustsecp256k1_v0_11_modinv64_signed62 s; - tmp = *x; - rustsecp256k1zkp_v0_8_0_fe_normalize(&tmp); - rustsecp256k1zkp_v0_8_0_fe_to_signed62(&s, &tmp); - rustsecp256k1zkp_v0_8_0_modinv64(&s, &rustsecp256k1zkp_v0_8_0_const_modinfo_fe); - rustsecp256k1zkp_v0_8_0_fe_from_signed62(r, &s); + rustsecp256k1_v0_11_fe_normalize(&tmp); + rustsecp256k1_v0_11_fe_to_signed62(&s, &tmp); + rustsecp256k1_v0_11_modinv64(&s, &rustsecp256k1_v0_11_const_modinfo_fe); + rustsecp256k1_v0_11_fe_from_signed62(r, &s); +} -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(r) == rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(&tmp)); -#endif +static void rustsecp256k1_v0_11_fe_impl_inv_var(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *x) { + rustsecp256k1_v0_11_fe tmp = *x; + rustsecp256k1_v0_11_modinv64_signed62 s; + + rustsecp256k1_v0_11_fe_normalize_var(&tmp); + rustsecp256k1_v0_11_fe_to_signed62(&s, &tmp); + rustsecp256k1_v0_11_modinv64_var(&s, &rustsecp256k1_v0_11_const_modinfo_fe); + rustsecp256k1_v0_11_fe_from_signed62(r, &s); } -static void rustsecp256k1zkp_v0_8_0_fe_inv_var(rustsecp256k1zkp_v0_8_0_fe *r, const rustsecp256k1zkp_v0_8_0_fe *x) { - rustsecp256k1zkp_v0_8_0_fe tmp; - rustsecp256k1zkp_v0_8_0_modinv64_signed62 s; +static int rustsecp256k1_v0_11_fe_impl_is_square_var(const rustsecp256k1_v0_11_fe *x) { + rustsecp256k1_v0_11_fe tmp; + rustsecp256k1_v0_11_modinv64_signed62 s; + int jac, ret; tmp = *x; - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&tmp); - rustsecp256k1zkp_v0_8_0_fe_to_signed62(&s, &tmp); - rustsecp256k1zkp_v0_8_0_modinv64_var(&s, &rustsecp256k1zkp_v0_8_0_const_modinfo_fe); - rustsecp256k1zkp_v0_8_0_fe_from_signed62(r, &s); - -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(r) == rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(&tmp)); -#endif + rustsecp256k1_v0_11_fe_normalize_var(&tmp); + /* rustsecp256k1_v0_11_jacobi64_maybe_var cannot deal with input 0. */ + if (rustsecp256k1_v0_11_fe_is_zero(&tmp)) return 1; + rustsecp256k1_v0_11_fe_to_signed62(&s, &tmp); + jac = rustsecp256k1_v0_11_jacobi64_maybe_var(&s, &rustsecp256k1_v0_11_const_modinfo_fe); + if (jac == 0) { + /* rustsecp256k1_v0_11_jacobi64_maybe_var failed to compute the Jacobi symbol. Fall back + * to computing a square root. This should be extremely rare with random + * input (except in VERIFY mode, where a lower iteration count is used). */ + rustsecp256k1_v0_11_fe dummy; + ret = rustsecp256k1_v0_11_fe_sqrt(&dummy, &tmp); + } else { + ret = jac >= 0; + } + return ret; } #endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_5x52_int128_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_5x52_int128_impl.h new file mode 100644 index 00000000..042b1470 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_5x52_int128_impl.h @@ -0,0 +1,274 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H +#define SECP256K1_FIELD_INNER5X52_IMPL_H + +#include + +#include "int128.h" +#include "util.h" + +#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) +#define VERIFY_BITS_128(x, n) VERIFY_CHECK(rustsecp256k1_v0_11_u128_check_bits((x), (n))) + +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { + rustsecp256k1_v0_11_uint128 c, d; + uint64_t t3, t4, tx, u0; + uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; + const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; + + VERIFY_BITS(a[0], 56); + VERIFY_BITS(a[1], 56); + VERIFY_BITS(a[2], 56); + VERIFY_BITS(a[3], 56); + VERIFY_BITS(a[4], 52); + VERIFY_BITS(b[0], 56); + VERIFY_BITS(b[1], 56); + VERIFY_BITS(b[2], 56); + VERIFY_BITS(b[3], 56); + VERIFY_BITS(b[4], 52); + VERIFY_CHECK(r != b); + VERIFY_CHECK(a != b); + + /* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. + * for 0 <= x <= 4, px is a shorthand for sum(a[i]*b[x-i], i=0..x). + * for 4 <= x <= 8, px is a shorthand for sum(a[i]*b[x-i], i=(x-4)..4) + * Note that [x 0 0 0 0 0] = [x*R]. + */ + + rustsecp256k1_v0_11_u128_mul(&d, a0, b[3]); + rustsecp256k1_v0_11_u128_accum_mul(&d, a1, b[2]); + rustsecp256k1_v0_11_u128_accum_mul(&d, a2, b[1]); + rustsecp256k1_v0_11_u128_accum_mul(&d, a3, b[0]); + VERIFY_BITS_128(&d, 114); + /* [d 0 0 0] = [p3 0 0 0] */ + rustsecp256k1_v0_11_u128_mul(&c, a4, b[4]); + VERIFY_BITS_128(&c, 112); + /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + rustsecp256k1_v0_11_u128_accum_mul(&d, R, rustsecp256k1_v0_11_u128_to_u64(&c)); rustsecp256k1_v0_11_u128_rshift(&c, 64); + VERIFY_BITS_128(&d, 115); + VERIFY_BITS_128(&c, 48); + /* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + t3 = rustsecp256k1_v0_11_u128_to_u64(&d) & M; rustsecp256k1_v0_11_u128_rshift(&d, 52); + VERIFY_BITS(t3, 52); + VERIFY_BITS_128(&d, 63); + /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + + rustsecp256k1_v0_11_u128_accum_mul(&d, a0, b[4]); + rustsecp256k1_v0_11_u128_accum_mul(&d, a1, b[3]); + rustsecp256k1_v0_11_u128_accum_mul(&d, a2, b[2]); + rustsecp256k1_v0_11_u128_accum_mul(&d, a3, b[1]); + rustsecp256k1_v0_11_u128_accum_mul(&d, a4, b[0]); + VERIFY_BITS_128(&d, 115); + /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + rustsecp256k1_v0_11_u128_accum_mul(&d, R << 12, rustsecp256k1_v0_11_u128_to_u64(&c)); + VERIFY_BITS_128(&d, 116); + /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + t4 = rustsecp256k1_v0_11_u128_to_u64(&d) & M; rustsecp256k1_v0_11_u128_rshift(&d, 52); + VERIFY_BITS(t4, 52); + VERIFY_BITS_128(&d, 64); + /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + tx = (t4 >> 48); t4 &= (M >> 4); + VERIFY_BITS(tx, 4); + VERIFY_BITS(t4, 48); + /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + + rustsecp256k1_v0_11_u128_mul(&c, a0, b[0]); + VERIFY_BITS_128(&c, 112); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ + rustsecp256k1_v0_11_u128_accum_mul(&d, a1, b[4]); + rustsecp256k1_v0_11_u128_accum_mul(&d, a2, b[3]); + rustsecp256k1_v0_11_u128_accum_mul(&d, a3, b[2]); + rustsecp256k1_v0_11_u128_accum_mul(&d, a4, b[1]); + VERIFY_BITS_128(&d, 114); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = rustsecp256k1_v0_11_u128_to_u64(&d) & M; rustsecp256k1_v0_11_u128_rshift(&d, 52); + VERIFY_BITS(u0, 52); + VERIFY_BITS_128(&d, 62); + /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = (u0 << 4) | tx; + VERIFY_BITS(u0, 56); + /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + rustsecp256k1_v0_11_u128_accum_mul(&c, u0, R >> 4); + VERIFY_BITS_128(&c, 113); + /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + r[0] = rustsecp256k1_v0_11_u128_to_u64(&c) & M; rustsecp256k1_v0_11_u128_rshift(&c, 52); + VERIFY_BITS(r[0], 52); + VERIFY_BITS_128(&c, 61); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ + + rustsecp256k1_v0_11_u128_accum_mul(&c, a0, b[1]); + rustsecp256k1_v0_11_u128_accum_mul(&c, a1, b[0]); + VERIFY_BITS_128(&c, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ + rustsecp256k1_v0_11_u128_accum_mul(&d, a2, b[4]); + rustsecp256k1_v0_11_u128_accum_mul(&d, a3, b[3]); + rustsecp256k1_v0_11_u128_accum_mul(&d, a4, b[2]); + VERIFY_BITS_128(&d, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + rustsecp256k1_v0_11_u128_accum_mul(&c, rustsecp256k1_v0_11_u128_to_u64(&d) & M, R); rustsecp256k1_v0_11_u128_rshift(&d, 52); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 62); + /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + r[1] = rustsecp256k1_v0_11_u128_to_u64(&c) & M; rustsecp256k1_v0_11_u128_rshift(&c, 52); + VERIFY_BITS(r[1], 52); + VERIFY_BITS_128(&c, 63); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + + rustsecp256k1_v0_11_u128_accum_mul(&c, a0, b[2]); + rustsecp256k1_v0_11_u128_accum_mul(&c, a1, b[1]); + rustsecp256k1_v0_11_u128_accum_mul(&c, a2, b[0]); + VERIFY_BITS_128(&c, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ + rustsecp256k1_v0_11_u128_accum_mul(&d, a3, b[4]); + rustsecp256k1_v0_11_u128_accum_mul(&d, a4, b[3]); + VERIFY_BITS_128(&d, 114); + /* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + rustsecp256k1_v0_11_u128_accum_mul(&c, R, rustsecp256k1_v0_11_u128_to_u64(&d)); rustsecp256k1_v0_11_u128_rshift(&d, 64); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 50); + /* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + r[2] = rustsecp256k1_v0_11_u128_to_u64(&c) & M; rustsecp256k1_v0_11_u128_rshift(&c, 52); + VERIFY_BITS(r[2], 52); + VERIFY_BITS_128(&c, 63); + /* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + rustsecp256k1_v0_11_u128_accum_mul(&c, R << 12, rustsecp256k1_v0_11_u128_to_u64(&d)); + rustsecp256k1_v0_11_u128_accum_u64(&c, t3); + VERIFY_BITS_128(&c, 100); + /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[3] = rustsecp256k1_v0_11_u128_to_u64(&c) & M; rustsecp256k1_v0_11_u128_rshift(&c, 52); + VERIFY_BITS(r[3], 52); + VERIFY_BITS_128(&c, 48); + /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = rustsecp256k1_v0_11_u128_to_u64(&c) + t4; + VERIFY_BITS(r[4], 49); + /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} + +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_sqr_inner(uint64_t *r, const uint64_t *a) { + rustsecp256k1_v0_11_uint128 c, d; + uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; + uint64_t t3, t4, tx, u0; + const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; + + VERIFY_BITS(a[0], 56); + VERIFY_BITS(a[1], 56); + VERIFY_BITS(a[2], 56); + VERIFY_BITS(a[3], 56); + VERIFY_BITS(a[4], 52); + + /** [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. + * px is a shorthand for sum(a[i]*a[x-i], i=0..x). + * Note that [x 0 0 0 0 0] = [x*R]. + */ + + rustsecp256k1_v0_11_u128_mul(&d, a0*2, a3); + rustsecp256k1_v0_11_u128_accum_mul(&d, a1*2, a2); + VERIFY_BITS_128(&d, 114); + /* [d 0 0 0] = [p3 0 0 0] */ + rustsecp256k1_v0_11_u128_mul(&c, a4, a4); + VERIFY_BITS_128(&c, 112); + /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + rustsecp256k1_v0_11_u128_accum_mul(&d, R, rustsecp256k1_v0_11_u128_to_u64(&c)); rustsecp256k1_v0_11_u128_rshift(&c, 64); + VERIFY_BITS_128(&d, 115); + VERIFY_BITS_128(&c, 48); + /* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + t3 = rustsecp256k1_v0_11_u128_to_u64(&d) & M; rustsecp256k1_v0_11_u128_rshift(&d, 52); + VERIFY_BITS(t3, 52); + VERIFY_BITS_128(&d, 63); + /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + + a4 *= 2; + rustsecp256k1_v0_11_u128_accum_mul(&d, a0, a4); + rustsecp256k1_v0_11_u128_accum_mul(&d, a1*2, a3); + rustsecp256k1_v0_11_u128_accum_mul(&d, a2, a2); + VERIFY_BITS_128(&d, 115); + /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + rustsecp256k1_v0_11_u128_accum_mul(&d, R << 12, rustsecp256k1_v0_11_u128_to_u64(&c)); + VERIFY_BITS_128(&d, 116); + /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + t4 = rustsecp256k1_v0_11_u128_to_u64(&d) & M; rustsecp256k1_v0_11_u128_rshift(&d, 52); + VERIFY_BITS(t4, 52); + VERIFY_BITS_128(&d, 64); + /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + tx = (t4 >> 48); t4 &= (M >> 4); + VERIFY_BITS(tx, 4); + VERIFY_BITS(t4, 48); + /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + + rustsecp256k1_v0_11_u128_mul(&c, a0, a0); + VERIFY_BITS_128(&c, 112); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ + rustsecp256k1_v0_11_u128_accum_mul(&d, a1, a4); + rustsecp256k1_v0_11_u128_accum_mul(&d, a2*2, a3); + VERIFY_BITS_128(&d, 114); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = rustsecp256k1_v0_11_u128_to_u64(&d) & M; rustsecp256k1_v0_11_u128_rshift(&d, 52); + VERIFY_BITS(u0, 52); + VERIFY_BITS_128(&d, 62); + /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = (u0 << 4) | tx; + VERIFY_BITS(u0, 56); + /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + rustsecp256k1_v0_11_u128_accum_mul(&c, u0, R >> 4); + VERIFY_BITS_128(&c, 113); + /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + r[0] = rustsecp256k1_v0_11_u128_to_u64(&c) & M; rustsecp256k1_v0_11_u128_rshift(&c, 52); + VERIFY_BITS(r[0], 52); + VERIFY_BITS_128(&c, 61); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ + + a0 *= 2; + rustsecp256k1_v0_11_u128_accum_mul(&c, a0, a1); + VERIFY_BITS_128(&c, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ + rustsecp256k1_v0_11_u128_accum_mul(&d, a2, a4); + rustsecp256k1_v0_11_u128_accum_mul(&d, a3, a3); + VERIFY_BITS_128(&d, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + rustsecp256k1_v0_11_u128_accum_mul(&c, rustsecp256k1_v0_11_u128_to_u64(&d) & M, R); rustsecp256k1_v0_11_u128_rshift(&d, 52); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 62); + /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + r[1] = rustsecp256k1_v0_11_u128_to_u64(&c) & M; rustsecp256k1_v0_11_u128_rshift(&c, 52); + VERIFY_BITS(r[1], 52); + VERIFY_BITS_128(&c, 63); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + + rustsecp256k1_v0_11_u128_accum_mul(&c, a0, a2); + rustsecp256k1_v0_11_u128_accum_mul(&c, a1, a1); + VERIFY_BITS_128(&c, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ + rustsecp256k1_v0_11_u128_accum_mul(&d, a3, a4); + VERIFY_BITS_128(&d, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + rustsecp256k1_v0_11_u128_accum_mul(&c, R, rustsecp256k1_v0_11_u128_to_u64(&d)); rustsecp256k1_v0_11_u128_rshift(&d, 64); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 50); + /* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = rustsecp256k1_v0_11_u128_to_u64(&c) & M; rustsecp256k1_v0_11_u128_rshift(&c, 52); + VERIFY_BITS(r[2], 52); + VERIFY_BITS_128(&c, 63); + /* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + rustsecp256k1_v0_11_u128_accum_mul(&c, R << 12, rustsecp256k1_v0_11_u128_to_u64(&d)); + rustsecp256k1_v0_11_u128_accum_u64(&c, t3); + VERIFY_BITS_128(&c, 100); + /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[3] = rustsecp256k1_v0_11_u128_to_u64(&c) & M; rustsecp256k1_v0_11_u128_rshift(&c, 52); + VERIFY_BITS(r[3], 52); + VERIFY_BITS_128(&c, 48); + /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = rustsecp256k1_v0_11_u128_to_u64(&c) + t4; + VERIFY_BITS(r[4], 49); + /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} + +#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_impl.h new file mode 100644 index 00000000..d44d4d45 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/field_impl.h @@ -0,0 +1,457 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_FIELD_IMPL_H +#define SECP256K1_FIELD_IMPL_H + +#include "field.h" +#include "util.h" + +#if defined(SECP256K1_WIDEMUL_INT128) +#include "field_5x52_impl.h" +#elif defined(SECP256K1_WIDEMUL_INT64) +#include "field_10x26_impl.h" +#else +#error "Please select wide multiplication implementation" +#endif + +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_clear(rustsecp256k1_v0_11_fe *a) { + rustsecp256k1_v0_11_memclear(a, sizeof(rustsecp256k1_v0_11_fe)); +} + +SECP256K1_INLINE static int rustsecp256k1_v0_11_fe_equal(const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe *b) { + rustsecp256k1_v0_11_fe na; + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY(b); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 1); + SECP256K1_FE_VERIFY_MAGNITUDE(b, 31); + + rustsecp256k1_v0_11_fe_negate(&na, a, 1); + rustsecp256k1_v0_11_fe_add(&na, b); + return rustsecp256k1_v0_11_fe_normalizes_to_zero(&na); +} + +static int rustsecp256k1_v0_11_fe_sqrt(rustsecp256k1_v0_11_fe * SECP256K1_RESTRICT r, const rustsecp256k1_v0_11_fe * SECP256K1_RESTRICT a) { + /** Given that p is congruent to 3 mod 4, we can compute the square root of + * a mod p as the (p+1)/4'th power of a. + * + * As (p+1)/4 is an even number, it will have the same result for a and for + * (-a). Only one of these two numbers actually has a square root however, + * so we test at the end by squaring and comparing to the input. + * Also because (p+1)/4 is an even number, the computed square root is + * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). + */ + rustsecp256k1_v0_11_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; + int j, ret; + + VERIFY_CHECK(r != a); + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 8); + + /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in + * { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: + * 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] + */ + + rustsecp256k1_v0_11_fe_sqr(&x2, a); + rustsecp256k1_v0_11_fe_mul(&x2, &x2, a); + + rustsecp256k1_v0_11_fe_sqr(&x3, &x2); + rustsecp256k1_v0_11_fe_mul(&x3, &x3, a); + + x6 = x3; + for (j=0; j<3; j++) { + rustsecp256k1_v0_11_fe_sqr(&x6, &x6); + } + rustsecp256k1_v0_11_fe_mul(&x6, &x6, &x3); + + x9 = x6; + for (j=0; j<3; j++) { + rustsecp256k1_v0_11_fe_sqr(&x9, &x9); + } + rustsecp256k1_v0_11_fe_mul(&x9, &x9, &x3); + + x11 = x9; + for (j=0; j<2; j++) { + rustsecp256k1_v0_11_fe_sqr(&x11, &x11); + } + rustsecp256k1_v0_11_fe_mul(&x11, &x11, &x2); + + x22 = x11; + for (j=0; j<11; j++) { + rustsecp256k1_v0_11_fe_sqr(&x22, &x22); + } + rustsecp256k1_v0_11_fe_mul(&x22, &x22, &x11); + + x44 = x22; + for (j=0; j<22; j++) { + rustsecp256k1_v0_11_fe_sqr(&x44, &x44); + } + rustsecp256k1_v0_11_fe_mul(&x44, &x44, &x22); + + x88 = x44; + for (j=0; j<44; j++) { + rustsecp256k1_v0_11_fe_sqr(&x88, &x88); + } + rustsecp256k1_v0_11_fe_mul(&x88, &x88, &x44); + + x176 = x88; + for (j=0; j<88; j++) { + rustsecp256k1_v0_11_fe_sqr(&x176, &x176); + } + rustsecp256k1_v0_11_fe_mul(&x176, &x176, &x88); + + x220 = x176; + for (j=0; j<44; j++) { + rustsecp256k1_v0_11_fe_sqr(&x220, &x220); + } + rustsecp256k1_v0_11_fe_mul(&x220, &x220, &x44); + + x223 = x220; + for (j=0; j<3; j++) { + rustsecp256k1_v0_11_fe_sqr(&x223, &x223); + } + rustsecp256k1_v0_11_fe_mul(&x223, &x223, &x3); + + /* The final result is then assembled using a sliding window over the blocks. */ + + t1 = x223; + for (j=0; j<23; j++) { + rustsecp256k1_v0_11_fe_sqr(&t1, &t1); + } + rustsecp256k1_v0_11_fe_mul(&t1, &t1, &x22); + for (j=0; j<6; j++) { + rustsecp256k1_v0_11_fe_sqr(&t1, &t1); + } + rustsecp256k1_v0_11_fe_mul(&t1, &t1, &x2); + rustsecp256k1_v0_11_fe_sqr(&t1, &t1); + rustsecp256k1_v0_11_fe_sqr(r, &t1); + + /* Check that a square root was actually calculated */ + + rustsecp256k1_v0_11_fe_sqr(&t1, r); + ret = rustsecp256k1_v0_11_fe_equal(&t1, a); + +#ifdef VERIFY + if (!ret) { + rustsecp256k1_v0_11_fe_negate(&t1, &t1, 1); + rustsecp256k1_v0_11_fe_normalize_var(&t1); + VERIFY_CHECK(rustsecp256k1_v0_11_fe_equal(&t1, a)); + } +#endif + return ret; +} + +#ifndef VERIFY +static void rustsecp256k1_v0_11_fe_verify(const rustsecp256k1_v0_11_fe *a) { (void)a; } +static void rustsecp256k1_v0_11_fe_verify_magnitude(const rustsecp256k1_v0_11_fe *a, int m) { (void)a; (void)m; } +#else +static void rustsecp256k1_v0_11_fe_impl_verify(const rustsecp256k1_v0_11_fe *a); +static void rustsecp256k1_v0_11_fe_verify(const rustsecp256k1_v0_11_fe *a) { + /* Magnitude between 0 and 32. */ + SECP256K1_FE_VERIFY_MAGNITUDE(a, 32); + /* Normalized is 0 or 1. */ + VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1)); + /* If normalized, magnitude must be 0 or 1. */ + if (a->normalized) SECP256K1_FE_VERIFY_MAGNITUDE(a, 1); + /* Invoke implementation-specific checks. */ + rustsecp256k1_v0_11_fe_impl_verify(a); +} + +static void rustsecp256k1_v0_11_fe_verify_magnitude(const rustsecp256k1_v0_11_fe *a, int m) { + VERIFY_CHECK(m >= 0); + VERIFY_CHECK(m <= 32); + VERIFY_CHECK(a->magnitude <= m); +} + +static void rustsecp256k1_v0_11_fe_impl_normalize(rustsecp256k1_v0_11_fe *r); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_normalize(rustsecp256k1_v0_11_fe *r) { + SECP256K1_FE_VERIFY(r); + + rustsecp256k1_v0_11_fe_impl_normalize(r); + r->magnitude = 1; + r->normalized = 1; + + SECP256K1_FE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_fe_impl_normalize_weak(rustsecp256k1_v0_11_fe *r); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_normalize_weak(rustsecp256k1_v0_11_fe *r) { + SECP256K1_FE_VERIFY(r); + + rustsecp256k1_v0_11_fe_impl_normalize_weak(r); + r->magnitude = 1; + + SECP256K1_FE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_fe_impl_normalize_var(rustsecp256k1_v0_11_fe *r); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_normalize_var(rustsecp256k1_v0_11_fe *r) { + SECP256K1_FE_VERIFY(r); + + rustsecp256k1_v0_11_fe_impl_normalize_var(r); + r->magnitude = 1; + r->normalized = 1; + + SECP256K1_FE_VERIFY(r); +} + +static int rustsecp256k1_v0_11_fe_impl_normalizes_to_zero(const rustsecp256k1_v0_11_fe *r); +SECP256K1_INLINE static int rustsecp256k1_v0_11_fe_normalizes_to_zero(const rustsecp256k1_v0_11_fe *r) { + SECP256K1_FE_VERIFY(r); + + return rustsecp256k1_v0_11_fe_impl_normalizes_to_zero(r); +} + +static int rustsecp256k1_v0_11_fe_impl_normalizes_to_zero_var(const rustsecp256k1_v0_11_fe *r); +SECP256K1_INLINE static int rustsecp256k1_v0_11_fe_normalizes_to_zero_var(const rustsecp256k1_v0_11_fe *r) { + SECP256K1_FE_VERIFY(r); + + return rustsecp256k1_v0_11_fe_impl_normalizes_to_zero_var(r); +} + +static void rustsecp256k1_v0_11_fe_impl_set_int(rustsecp256k1_v0_11_fe *r, int a); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_set_int(rustsecp256k1_v0_11_fe *r, int a) { + VERIFY_CHECK(0 <= a && a <= 0x7FFF); + + rustsecp256k1_v0_11_fe_impl_set_int(r, a); + r->magnitude = (a != 0); + r->normalized = 1; + + SECP256K1_FE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_fe_impl_add_int(rustsecp256k1_v0_11_fe *r, int a); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_add_int(rustsecp256k1_v0_11_fe *r, int a) { + VERIFY_CHECK(0 <= a && a <= 0x7FFF); + SECP256K1_FE_VERIFY(r); + + rustsecp256k1_v0_11_fe_impl_add_int(r, a); + r->magnitude += 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static int rustsecp256k1_v0_11_fe_impl_is_zero(const rustsecp256k1_v0_11_fe *a); +SECP256K1_INLINE static int rustsecp256k1_v0_11_fe_is_zero(const rustsecp256k1_v0_11_fe *a) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(a->normalized); + + return rustsecp256k1_v0_11_fe_impl_is_zero(a); +} + +static int rustsecp256k1_v0_11_fe_impl_is_odd(const rustsecp256k1_v0_11_fe *a); +SECP256K1_INLINE static int rustsecp256k1_v0_11_fe_is_odd(const rustsecp256k1_v0_11_fe *a) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(a->normalized); + + return rustsecp256k1_v0_11_fe_impl_is_odd(a); +} + +static int rustsecp256k1_v0_11_fe_impl_cmp_var(const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe *b); +SECP256K1_INLINE static int rustsecp256k1_v0_11_fe_cmp_var(const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe *b) { + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY(b); + VERIFY_CHECK(a->normalized); + VERIFY_CHECK(b->normalized); + + return rustsecp256k1_v0_11_fe_impl_cmp_var(a, b); +} + +static void rustsecp256k1_v0_11_fe_impl_set_b32_mod(rustsecp256k1_v0_11_fe *r, const unsigned char *a); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_set_b32_mod(rustsecp256k1_v0_11_fe *r, const unsigned char *a) { + rustsecp256k1_v0_11_fe_impl_set_b32_mod(r, a); + r->magnitude = 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static int rustsecp256k1_v0_11_fe_impl_set_b32_limit(rustsecp256k1_v0_11_fe *r, const unsigned char *a); +SECP256K1_INLINE static int rustsecp256k1_v0_11_fe_set_b32_limit(rustsecp256k1_v0_11_fe *r, const unsigned char *a) { + if (rustsecp256k1_v0_11_fe_impl_set_b32_limit(r, a)) { + r->magnitude = 1; + r->normalized = 1; + SECP256K1_FE_VERIFY(r); + return 1; + } else { + /* Mark the output field element as invalid. */ + r->magnitude = -1; + return 0; + } +} + +static void rustsecp256k1_v0_11_fe_impl_get_b32(unsigned char *r, const rustsecp256k1_v0_11_fe *a); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_get_b32(unsigned char *r, const rustsecp256k1_v0_11_fe *a) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(a->normalized); + + rustsecp256k1_v0_11_fe_impl_get_b32(r, a); +} + +static void rustsecp256k1_v0_11_fe_impl_negate_unchecked(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, int m); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_negate_unchecked(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, int m) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(m >= 0 && m <= 31); + SECP256K1_FE_VERIFY_MAGNITUDE(a, m); + + rustsecp256k1_v0_11_fe_impl_negate_unchecked(r, a, m); + r->magnitude = m + 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_fe_impl_mul_int_unchecked(rustsecp256k1_v0_11_fe *r, int a); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_mul_int_unchecked(rustsecp256k1_v0_11_fe *r, int a) { + SECP256K1_FE_VERIFY(r); + + VERIFY_CHECK(a >= 0 && a <= 32); + VERIFY_CHECK(a*r->magnitude <= 32); + rustsecp256k1_v0_11_fe_impl_mul_int_unchecked(r, a); + r->magnitude *= a; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_fe_impl_add(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_add(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a) { + SECP256K1_FE_VERIFY(r); + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(r->magnitude + a->magnitude <= 32); + + rustsecp256k1_v0_11_fe_impl_add(r, a); + r->magnitude += a->magnitude; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_fe_impl_mul(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe * SECP256K1_RESTRICT b); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_mul(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe * SECP256K1_RESTRICT b) { + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY(b); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 8); + SECP256K1_FE_VERIFY_MAGNITUDE(b, 8); + VERIFY_CHECK(r != b); + VERIFY_CHECK(a != b); + + rustsecp256k1_v0_11_fe_impl_mul(r, a, b); + r->magnitude = 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_fe_impl_sqr(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_sqr(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a) { + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 8); + + rustsecp256k1_v0_11_fe_impl_sqr(r, a); + r->magnitude = 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_fe_impl_cmov(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, int flag); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_cmov(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *a, int flag) { + VERIFY_CHECK(flag == 0 || flag == 1); + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY(r); + + rustsecp256k1_v0_11_fe_impl_cmov(r, a, flag); + if (a->magnitude > r->magnitude) r->magnitude = a->magnitude; + if (!a->normalized) r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_fe_impl_to_storage(rustsecp256k1_v0_11_fe_storage *r, const rustsecp256k1_v0_11_fe *a); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_to_storage(rustsecp256k1_v0_11_fe_storage *r, const rustsecp256k1_v0_11_fe *a) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(a->normalized); + + rustsecp256k1_v0_11_fe_impl_to_storage(r, a); +} + +static void rustsecp256k1_v0_11_fe_impl_from_storage(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe_storage *a); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_from_storage(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe_storage *a) { + rustsecp256k1_v0_11_fe_impl_from_storage(r, a); + r->magnitude = 1; + r->normalized = 1; + + SECP256K1_FE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_fe_impl_inv(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *x); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_inv(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *x) { + int input_is_zero = rustsecp256k1_v0_11_fe_normalizes_to_zero(x); + SECP256K1_FE_VERIFY(x); + + rustsecp256k1_v0_11_fe_impl_inv(r, x); + r->magnitude = x->magnitude > 0; + r->normalized = 1; + + VERIFY_CHECK(rustsecp256k1_v0_11_fe_normalizes_to_zero(r) == input_is_zero); + SECP256K1_FE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_fe_impl_inv_var(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *x); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_inv_var(rustsecp256k1_v0_11_fe *r, const rustsecp256k1_v0_11_fe *x) { + int input_is_zero = rustsecp256k1_v0_11_fe_normalizes_to_zero(x); + SECP256K1_FE_VERIFY(x); + + rustsecp256k1_v0_11_fe_impl_inv_var(r, x); + r->magnitude = x->magnitude > 0; + r->normalized = 1; + + VERIFY_CHECK(rustsecp256k1_v0_11_fe_normalizes_to_zero(r) == input_is_zero); + SECP256K1_FE_VERIFY(r); +} + +static int rustsecp256k1_v0_11_fe_impl_is_square_var(const rustsecp256k1_v0_11_fe *x); +SECP256K1_INLINE static int rustsecp256k1_v0_11_fe_is_square_var(const rustsecp256k1_v0_11_fe *x) { + int ret; + rustsecp256k1_v0_11_fe tmp = *x, sqrt; + SECP256K1_FE_VERIFY(x); + + ret = rustsecp256k1_v0_11_fe_impl_is_square_var(x); + rustsecp256k1_v0_11_fe_normalize_weak(&tmp); + VERIFY_CHECK(ret == rustsecp256k1_v0_11_fe_sqrt(&sqrt, &tmp)); + return ret; +} + +static void rustsecp256k1_v0_11_fe_impl_get_bounds(rustsecp256k1_v0_11_fe* r, int m); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_get_bounds(rustsecp256k1_v0_11_fe* r, int m) { + VERIFY_CHECK(m >= 0); + VERIFY_CHECK(m <= 32); + + rustsecp256k1_v0_11_fe_impl_get_bounds(r, m); + r->magnitude = m; + r->normalized = (m == 0); + + SECP256K1_FE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_fe_impl_half(rustsecp256k1_v0_11_fe *r); +SECP256K1_INLINE static void rustsecp256k1_v0_11_fe_half(rustsecp256k1_v0_11_fe *r) { + SECP256K1_FE_VERIFY(r); + SECP256K1_FE_VERIFY_MAGNITUDE(r, 31); + + rustsecp256k1_v0_11_fe_impl_half(r); + r->magnitude = (r->magnitude >> 1) + 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +#endif /* defined(VERIFY) */ + +#endif /* SECP256K1_FIELD_IMPL_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/group.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/group.h new file mode 100644 index 00000000..afc71916 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/group.h @@ -0,0 +1,212 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_GROUP_H +#define SECP256K1_GROUP_H + +#include "field.h" + +/** A group element in affine coordinates on the secp256k1 curve, + * or occasionally on an isomorphic curve of the form y^2 = x^3 + 7*t^6. + * Note: For exhaustive test mode, secp256k1 is replaced by a small subgroup of a different curve. + */ +typedef struct { + rustsecp256k1_v0_11_fe x; + rustsecp256k1_v0_11_fe y; + int infinity; /* whether this represents the point at infinity */ +} rustsecp256k1_v0_11_ge; + +#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0} +#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} + +/** A group element of the secp256k1 curve, in jacobian coordinates. + * Note: For exhastive test mode, secp256k1 is replaced by a small subgroup of a different curve. + */ +typedef struct { + rustsecp256k1_v0_11_fe x; /* actual X: x/z^2 */ + rustsecp256k1_v0_11_fe y; /* actual Y: y/z^3 */ + rustsecp256k1_v0_11_fe z; + int infinity; /* whether this represents the point at infinity */ +} rustsecp256k1_v0_11_gej; + +#define SECP256K1_GEJ_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), 0} +#define SECP256K1_GEJ_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} + +typedef struct { + rustsecp256k1_v0_11_fe_storage x; + rustsecp256k1_v0_11_fe_storage y; +} rustsecp256k1_v0_11_ge_storage; + +#define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))} + +#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) + +/** Maximum allowed magnitudes for group element coordinates + * in affine (x, y) and jacobian (x, y, z) representation. */ +#define SECP256K1_GE_X_MAGNITUDE_MAX 4 +#define SECP256K1_GE_Y_MAGNITUDE_MAX 3 +#define SECP256K1_GEJ_X_MAGNITUDE_MAX 4 +#define SECP256K1_GEJ_Y_MAGNITUDE_MAX 4 +#define SECP256K1_GEJ_Z_MAGNITUDE_MAX 1 + +/** Set a group element equal to the point with given X and Y coordinates */ +static void rustsecp256k1_v0_11_ge_set_xy(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_fe *x, const rustsecp256k1_v0_11_fe *y); + +/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness + * for Y. Return value indicates whether the result is valid. */ +static int rustsecp256k1_v0_11_ge_set_xo_var(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_fe *x, int odd); + +/** Determine whether x is a valid X coordinate on the curve. */ +static int rustsecp256k1_v0_11_ge_x_on_curve_var(const rustsecp256k1_v0_11_fe *x); + +/** Determine whether fraction xn/xd is a valid X coordinate on the curve (xd != 0). */ +static int rustsecp256k1_v0_11_ge_x_frac_on_curve_var(const rustsecp256k1_v0_11_fe *xn, const rustsecp256k1_v0_11_fe *xd); + +/** Check whether a group element is the point at infinity. */ +static int rustsecp256k1_v0_11_ge_is_infinity(const rustsecp256k1_v0_11_ge *a); + +/** Check whether a group element is valid (i.e., on the curve). */ +static int rustsecp256k1_v0_11_ge_is_valid_var(const rustsecp256k1_v0_11_ge *a); + +/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ +static void rustsecp256k1_v0_11_ge_neg(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_ge *a); + +/** Set a group element equal to another which is given in jacobian coordinates. Constant time. */ +static void rustsecp256k1_v0_11_ge_set_gej(rustsecp256k1_v0_11_ge *r, rustsecp256k1_v0_11_gej *a); + +/** Set a group element equal to another which is given in jacobian coordinates. */ +static void rustsecp256k1_v0_11_ge_set_gej_var(rustsecp256k1_v0_11_ge *r, rustsecp256k1_v0_11_gej *a); + +/** Set a batch of group elements equal to the inputs given in jacobian coordinates */ +static void rustsecp256k1_v0_11_ge_set_all_gej_var(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_gej *a, size_t len); + +/** Bring a batch of inputs to the same global z "denominator", based on ratios between + * (omitted) z coordinates of adjacent elements. + * + * Although the elements a[i] are _ge rather than _gej, they actually represent elements + * in Jacobian coordinates with their z coordinates omitted. + * + * Using the notation z(b) to represent the omitted z coordinate of b, the array zr of + * z coordinate ratios must satisfy zr[i] == z(a[i]) / z(a[i-1]) for 0 < 'i' < len. + * The zr[0] value is unused. + * + * This function adjusts the coordinates of 'a' in place so that for all 'i', z(a[i]) == z(a[len-1]). + * In other words, the initial value of z(a[len-1]) becomes the global z "denominator". Only the + * a[i].x and a[i].y coordinates are explicitly modified; the adjustment of the omitted z coordinate is + * implicit. + * + * The coordinates of the final element a[len-1] are not changed. + */ +static void rustsecp256k1_v0_11_ge_table_set_globalz(size_t len, rustsecp256k1_v0_11_ge *a, const rustsecp256k1_v0_11_fe *zr); + +/** Check two group elements (affine) for equality in variable time. */ +static int rustsecp256k1_v0_11_ge_eq_var(const rustsecp256k1_v0_11_ge *a, const rustsecp256k1_v0_11_ge *b); + +/** Set a group element (affine) equal to the point at infinity. */ +static void rustsecp256k1_v0_11_ge_set_infinity(rustsecp256k1_v0_11_ge *r); + +/** Set a group element (jacobian) equal to the point at infinity. */ +static void rustsecp256k1_v0_11_gej_set_infinity(rustsecp256k1_v0_11_gej *r); + +/** Set a group element (jacobian) equal to another which is given in affine coordinates. */ +static void rustsecp256k1_v0_11_gej_set_ge(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_ge *a); + +/** Check two group elements (jacobian) for equality in variable time. */ +static int rustsecp256k1_v0_11_gej_eq_var(const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_gej *b); + +/** Check two group elements (jacobian and affine) for equality in variable time. */ +static int rustsecp256k1_v0_11_gej_eq_ge_var(const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_ge *b); + +/** Compare the X coordinate of a group element (jacobian). + * The magnitude of the group element's X coordinate must not exceed 31. */ +static int rustsecp256k1_v0_11_gej_eq_x_var(const rustsecp256k1_v0_11_fe *x, const rustsecp256k1_v0_11_gej *a); + +/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ +static void rustsecp256k1_v0_11_gej_neg(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a); + +/** Check whether a group element is the point at infinity. */ +static int rustsecp256k1_v0_11_gej_is_infinity(const rustsecp256k1_v0_11_gej *a); + +/** Set r equal to the double of a. Constant time. */ +static void rustsecp256k1_v0_11_gej_double(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a); + +/** Set r equal to the double of a. If rzr is not-NULL this sets *rzr such that r->z == a->z * *rzr (where infinity means an implicit z = 0). */ +static void rustsecp256k1_v0_11_gej_double_var(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a, rustsecp256k1_v0_11_fe *rzr); + +/** Set r equal to the sum of a and b. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */ +static void rustsecp256k1_v0_11_gej_add_var(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_gej *b, rustsecp256k1_v0_11_fe *rzr); + +/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */ +static void rustsecp256k1_v0_11_gej_add_ge(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_ge *b); + +/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient + than rustsecp256k1_v0_11_gej_add_var. It is identical to rustsecp256k1_v0_11_gej_add_ge but without constant-time + guarantee, and b is allowed to be infinity. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */ +static void rustsecp256k1_v0_11_gej_add_ge_var(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_ge *b, rustsecp256k1_v0_11_fe *rzr); + +/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */ +static void rustsecp256k1_v0_11_gej_add_zinv_var(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_ge *b, const rustsecp256k1_v0_11_fe *bzinv); + +/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */ +static void rustsecp256k1_v0_11_ge_mul_lambda(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_ge *a); + +/** Clear a rustsecp256k1_v0_11_gej to prevent leaking sensitive information. */ +static void rustsecp256k1_v0_11_gej_clear(rustsecp256k1_v0_11_gej *r); + +/** Clear a rustsecp256k1_v0_11_ge to prevent leaking sensitive information. */ +static void rustsecp256k1_v0_11_ge_clear(rustsecp256k1_v0_11_ge *r); + +/** Convert a group element to the storage type. */ +static void rustsecp256k1_v0_11_ge_to_storage(rustsecp256k1_v0_11_ge_storage *r, const rustsecp256k1_v0_11_ge *a); + +/** Convert a group element back from the storage type. */ +static void rustsecp256k1_v0_11_ge_from_storage(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_ge_storage *a); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +static void rustsecp256k1_v0_11_gej_cmov(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a, int flag); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +static void rustsecp256k1_v0_11_ge_storage_cmov(rustsecp256k1_v0_11_ge_storage *r, const rustsecp256k1_v0_11_ge_storage *a, int flag); + +/** Rescale a jacobian point by b which must be non-zero. Constant-time. */ +static void rustsecp256k1_v0_11_gej_rescale(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_fe *b); + +/** Convert a group element that is not infinity to a 64-byte array. The output + * array is platform-dependent. */ +static void rustsecp256k1_v0_11_ge_to_bytes(unsigned char *buf, const rustsecp256k1_v0_11_ge *a); + +/** Convert a 64-byte array into group element. This function assumes that the + * provided buffer correctly encodes a group element. */ +static void rustsecp256k1_v0_11_ge_from_bytes(rustsecp256k1_v0_11_ge *r, const unsigned char *buf); + +/** Convert a group element (that is allowed to be infinity) to a 64-byte + * array. The output array is platform-dependent. */ +static void rustsecp256k1_v0_11_ge_to_bytes_ext(unsigned char *data, const rustsecp256k1_v0_11_ge *ge); + +/** Convert a 64-byte array into a group element. This function assumes that the + * provided buffer is the output of rustsecp256k1_v0_11_ge_to_bytes_ext. */ +static void rustsecp256k1_v0_11_ge_from_bytes_ext(rustsecp256k1_v0_11_ge *ge, const unsigned char *data); + +/** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve. + * + * In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the + * group, and this function returns always true. + * + * When compiling in exhaustive test mode, a slightly different curve equation is used, leading to a group with a + * (very) small subgroup, and that subgroup is what is used for all cryptographic operations. In that mode, this + * function checks whether a point that is on the curve is in fact also in that subgroup. + */ +static int rustsecp256k1_v0_11_ge_is_in_correct_subgroup(const rustsecp256k1_v0_11_ge* ge); + +/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */ +static void rustsecp256k1_v0_11_ge_verify(const rustsecp256k1_v0_11_ge *a); +#define SECP256K1_GE_VERIFY(a) rustsecp256k1_v0_11_ge_verify(a) + +/** Check invariants on a Jacobian group element (no-op unless VERIFY is enabled). */ +static void rustsecp256k1_v0_11_gej_verify(const rustsecp256k1_v0_11_gej *a); +#define SECP256K1_GEJ_VERIFY(a) rustsecp256k1_v0_11_gej_verify(a) + +#endif /* SECP256K1_GROUP_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/group_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/group_impl.h new file mode 100644 index 00000000..765bf595 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/group_impl.h @@ -0,0 +1,974 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_GROUP_IMPL_H +#define SECP256K1_GROUP_IMPL_H + +#include + +#include "field.h" +#include "group.h" +#include "util.h" + +/* Begin of section generated by sage/gen_exhaustive_groups.sage. */ +#define SECP256K1_G_ORDER_7 SECP256K1_GE_CONST(\ + 0x66625d13, 0x317ffe44, 0x63d32cff, 0x1ca02b9b,\ + 0xe5c6d070, 0x50b4b05e, 0x81cc30db, 0xf5166f0a,\ + 0x1e60e897, 0xa7c00c7c, 0x2df53eb6, 0x98274ff4,\ + 0x64252f42, 0x8ca44e17, 0x3b25418c, 0xff4ab0cf\ +) +#define SECP256K1_G_ORDER_13 SECP256K1_GE_CONST(\ + 0xa2482ff8, 0x4bf34edf, 0xa51262fd, 0xe57921db,\ + 0xe0dd2cb7, 0xa5914790, 0xbc71631f, 0xc09704fb,\ + 0x942536cb, 0xa3e49492, 0x3a701cc3, 0xee3e443f,\ + 0xdf182aa9, 0x15b8aa6a, 0x166d3b19, 0xba84b045\ +) +#define SECP256K1_G_ORDER_199 SECP256K1_GE_CONST(\ + 0x7fb07b5c, 0xd07c3bda, 0x553902e2, 0x7a87ea2c,\ + 0x35108a7f, 0x051f41e5, 0xb76abad5, 0x1f2703ad,\ + 0x0a251539, 0x5b4c4438, 0x952a634f, 0xac10dd4d,\ + 0x6d6f4745, 0x98990c27, 0x3a4f3116, 0xd32ff969\ +) +/** Generator for secp256k1, value 'g' defined in + * "Standards for Efficient Cryptography" (SEC2) 2.7.1. + */ +#define SECP256K1_G SECP256K1_GE_CONST(\ + 0x79be667e, 0xf9dcbbac, 0x55a06295, 0xce870b07,\ + 0x029bfcdb, 0x2dce28d9, 0x59f2815b, 0x16f81798,\ + 0x483ada77, 0x26a3c465, 0x5da4fbfc, 0x0e1108a8,\ + 0xfd17b448, 0xa6855419, 0x9c47d08f, 0xfb10d4b8\ +) +/* These exhaustive group test orders and generators are chosen such that: + * - The field size is equal to that of secp256k1, so field code is the same. + * - The curve equation is of the form y^2=x^3+B for some small constant B. + * - The subgroup has a generator 2*P, where P.x is as small as possible. + * - The subgroup has size less than 1000 to permit exhaustive testing. + * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y). + */ +#if defined(EXHAUSTIVE_TEST_ORDER) +# if EXHAUSTIVE_TEST_ORDER == 7 + +static const rustsecp256k1_v0_11_ge rustsecp256k1_v0_11_ge_const_g = SECP256K1_G_ORDER_7; +#define SECP256K1_B 6 + +# elif EXHAUSTIVE_TEST_ORDER == 13 + +static const rustsecp256k1_v0_11_ge rustsecp256k1_v0_11_ge_const_g = SECP256K1_G_ORDER_13; +#define SECP256K1_B 2 + +# elif EXHAUSTIVE_TEST_ORDER == 199 + +static const rustsecp256k1_v0_11_ge rustsecp256k1_v0_11_ge_const_g = SECP256K1_G_ORDER_199; +#define SECP256K1_B 4 + +# else +# error No known generator for the specified exhaustive test group order. +# endif +#else + +static const rustsecp256k1_v0_11_ge rustsecp256k1_v0_11_ge_const_g = SECP256K1_G; +#define SECP256K1_B 7 + +#endif +/* End of section generated by sage/gen_exhaustive_groups.sage. */ + +static void rustsecp256k1_v0_11_ge_verify(const rustsecp256k1_v0_11_ge *a) { + SECP256K1_FE_VERIFY(&a->x); + SECP256K1_FE_VERIFY(&a->y); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->x, SECP256K1_GE_X_MAGNITUDE_MAX); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->y, SECP256K1_GE_Y_MAGNITUDE_MAX); + VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); + (void)a; +} + +static void rustsecp256k1_v0_11_gej_verify(const rustsecp256k1_v0_11_gej *a) { + SECP256K1_FE_VERIFY(&a->x); + SECP256K1_FE_VERIFY(&a->y); + SECP256K1_FE_VERIFY(&a->z); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->x, SECP256K1_GEJ_X_MAGNITUDE_MAX); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX); + VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); + (void)a; +} + +/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */ +static void rustsecp256k1_v0_11_ge_set_gej_zinv(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_fe *zi) { + rustsecp256k1_v0_11_fe zi2; + rustsecp256k1_v0_11_fe zi3; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_FE_VERIFY(zi); + VERIFY_CHECK(!a->infinity); + + rustsecp256k1_v0_11_fe_sqr(&zi2, zi); + rustsecp256k1_v0_11_fe_mul(&zi3, &zi2, zi); + rustsecp256k1_v0_11_fe_mul(&r->x, &a->x, &zi2); + rustsecp256k1_v0_11_fe_mul(&r->y, &a->y, &zi3); + r->infinity = a->infinity; + + SECP256K1_GE_VERIFY(r); +} + +/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */ +static void rustsecp256k1_v0_11_ge_set_ge_zinv(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_ge *a, const rustsecp256k1_v0_11_fe *zi) { + rustsecp256k1_v0_11_fe zi2; + rustsecp256k1_v0_11_fe zi3; + SECP256K1_GE_VERIFY(a); + SECP256K1_FE_VERIFY(zi); + VERIFY_CHECK(!a->infinity); + + rustsecp256k1_v0_11_fe_sqr(&zi2, zi); + rustsecp256k1_v0_11_fe_mul(&zi3, &zi2, zi); + rustsecp256k1_v0_11_fe_mul(&r->x, &a->x, &zi2); + rustsecp256k1_v0_11_fe_mul(&r->y, &a->y, &zi3); + r->infinity = a->infinity; + + SECP256K1_GE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_ge_set_xy(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_fe *x, const rustsecp256k1_v0_11_fe *y) { + SECP256K1_FE_VERIFY(x); + SECP256K1_FE_VERIFY(y); + + r->infinity = 0; + r->x = *x; + r->y = *y; + + SECP256K1_GE_VERIFY(r); +} + +static int rustsecp256k1_v0_11_ge_is_infinity(const rustsecp256k1_v0_11_ge *a) { + SECP256K1_GE_VERIFY(a); + + return a->infinity; +} + +static void rustsecp256k1_v0_11_ge_neg(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_ge *a) { + SECP256K1_GE_VERIFY(a); + + *r = *a; + rustsecp256k1_v0_11_fe_normalize_weak(&r->y); + rustsecp256k1_v0_11_fe_negate(&r->y, &r->y, 1); + + SECP256K1_GE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_ge_set_gej(rustsecp256k1_v0_11_ge *r, rustsecp256k1_v0_11_gej *a) { + rustsecp256k1_v0_11_fe z2, z3; + SECP256K1_GEJ_VERIFY(a); + + r->infinity = a->infinity; + rustsecp256k1_v0_11_fe_inv(&a->z, &a->z); + rustsecp256k1_v0_11_fe_sqr(&z2, &a->z); + rustsecp256k1_v0_11_fe_mul(&z3, &a->z, &z2); + rustsecp256k1_v0_11_fe_mul(&a->x, &a->x, &z2); + rustsecp256k1_v0_11_fe_mul(&a->y, &a->y, &z3); + rustsecp256k1_v0_11_fe_set_int(&a->z, 1); + r->x = a->x; + r->y = a->y; + + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_ge_set_gej_var(rustsecp256k1_v0_11_ge *r, rustsecp256k1_v0_11_gej *a) { + rustsecp256k1_v0_11_fe z2, z3; + SECP256K1_GEJ_VERIFY(a); + + if (rustsecp256k1_v0_11_gej_is_infinity(a)) { + rustsecp256k1_v0_11_ge_set_infinity(r); + return; + } + r->infinity = 0; + rustsecp256k1_v0_11_fe_inv_var(&a->z, &a->z); + rustsecp256k1_v0_11_fe_sqr(&z2, &a->z); + rustsecp256k1_v0_11_fe_mul(&z3, &a->z, &z2); + rustsecp256k1_v0_11_fe_mul(&a->x, &a->x, &z2); + rustsecp256k1_v0_11_fe_mul(&a->y, &a->y, &z3); + rustsecp256k1_v0_11_fe_set_int(&a->z, 1); + rustsecp256k1_v0_11_ge_set_xy(r, &a->x, &a->y); + + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_ge_set_all_gej_var(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_gej *a, size_t len) { + rustsecp256k1_v0_11_fe u; + size_t i; + size_t last_i = SIZE_MAX; +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GEJ_VERIFY(&a[i]); + } +#endif + + for (i = 0; i < len; i++) { + if (a[i].infinity) { + rustsecp256k1_v0_11_ge_set_infinity(&r[i]); + } else { + /* Use destination's x coordinates as scratch space */ + if (last_i == SIZE_MAX) { + r[i].x = a[i].z; + } else { + rustsecp256k1_v0_11_fe_mul(&r[i].x, &r[last_i].x, &a[i].z); + } + last_i = i; + } + } + if (last_i == SIZE_MAX) { + return; + } + rustsecp256k1_v0_11_fe_inv_var(&u, &r[last_i].x); + + i = last_i; + while (i > 0) { + i--; + if (!a[i].infinity) { + rustsecp256k1_v0_11_fe_mul(&r[last_i].x, &r[i].x, &u); + rustsecp256k1_v0_11_fe_mul(&u, &u, &a[last_i].z); + last_i = i; + } + } + VERIFY_CHECK(!a[last_i].infinity); + r[last_i].x = u; + + for (i = 0; i < len; i++) { + if (!a[i].infinity) { + rustsecp256k1_v0_11_ge_set_gej_zinv(&r[i], &a[i], &r[i].x); + } + } + +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GE_VERIFY(&r[i]); + } +#endif +} + +static void rustsecp256k1_v0_11_ge_table_set_globalz(size_t len, rustsecp256k1_v0_11_ge *a, const rustsecp256k1_v0_11_fe *zr) { + size_t i; + rustsecp256k1_v0_11_fe zs; +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GE_VERIFY(&a[i]); + SECP256K1_FE_VERIFY(&zr[i]); + } +#endif + + if (len > 0) { + i = len - 1; + /* Ensure all y values are in weak normal form for fast negation of points */ + rustsecp256k1_v0_11_fe_normalize_weak(&a[i].y); + zs = zr[i]; + + /* Work our way backwards, using the z-ratios to scale the x/y values. */ + while (i > 0) { + if (i != len - 1) { + rustsecp256k1_v0_11_fe_mul(&zs, &zs, &zr[i]); + } + i--; + rustsecp256k1_v0_11_ge_set_ge_zinv(&a[i], &a[i], &zs); + } + } + +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GE_VERIFY(&a[i]); + } +#endif +} + +static void rustsecp256k1_v0_11_gej_set_infinity(rustsecp256k1_v0_11_gej *r) { + r->infinity = 1; + rustsecp256k1_v0_11_fe_set_int(&r->x, 0); + rustsecp256k1_v0_11_fe_set_int(&r->y, 0); + rustsecp256k1_v0_11_fe_set_int(&r->z, 0); + + SECP256K1_GEJ_VERIFY(r); +} + +static void rustsecp256k1_v0_11_ge_set_infinity(rustsecp256k1_v0_11_ge *r) { + r->infinity = 1; + rustsecp256k1_v0_11_fe_set_int(&r->x, 0); + rustsecp256k1_v0_11_fe_set_int(&r->y, 0); + + SECP256K1_GE_VERIFY(r); +} + +static void rustsecp256k1_v0_11_gej_clear(rustsecp256k1_v0_11_gej *r) { + rustsecp256k1_v0_11_memclear(r, sizeof(rustsecp256k1_v0_11_gej)); +} + +static void rustsecp256k1_v0_11_ge_clear(rustsecp256k1_v0_11_ge *r) { + rustsecp256k1_v0_11_memclear(r, sizeof(rustsecp256k1_v0_11_ge)); +} + +static int rustsecp256k1_v0_11_ge_set_xo_var(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_fe *x, int odd) { + rustsecp256k1_v0_11_fe x2, x3; + int ret; + SECP256K1_FE_VERIFY(x); + + r->x = *x; + rustsecp256k1_v0_11_fe_sqr(&x2, x); + rustsecp256k1_v0_11_fe_mul(&x3, x, &x2); + r->infinity = 0; + rustsecp256k1_v0_11_fe_add_int(&x3, SECP256K1_B); + ret = rustsecp256k1_v0_11_fe_sqrt(&r->y, &x3); + rustsecp256k1_v0_11_fe_normalize_var(&r->y); + if (rustsecp256k1_v0_11_fe_is_odd(&r->y) != odd) { + rustsecp256k1_v0_11_fe_negate(&r->y, &r->y, 1); + } + + SECP256K1_GE_VERIFY(r); + return ret; +} + +static void rustsecp256k1_v0_11_gej_set_ge(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_ge *a) { + SECP256K1_GE_VERIFY(a); + + r->infinity = a->infinity; + r->x = a->x; + r->y = a->y; + rustsecp256k1_v0_11_fe_set_int(&r->z, 1); + + SECP256K1_GEJ_VERIFY(r); +} + +static int rustsecp256k1_v0_11_gej_eq_var(const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_gej *b) { + rustsecp256k1_v0_11_gej tmp; + SECP256K1_GEJ_VERIFY(b); + SECP256K1_GEJ_VERIFY(a); + + rustsecp256k1_v0_11_gej_neg(&tmp, a); + rustsecp256k1_v0_11_gej_add_var(&tmp, &tmp, b, NULL); + return rustsecp256k1_v0_11_gej_is_infinity(&tmp); +} + +static int rustsecp256k1_v0_11_gej_eq_ge_var(const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_ge *b) { + rustsecp256k1_v0_11_gej tmp; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(b); + + rustsecp256k1_v0_11_gej_neg(&tmp, a); + rustsecp256k1_v0_11_gej_add_ge_var(&tmp, &tmp, b, NULL); + return rustsecp256k1_v0_11_gej_is_infinity(&tmp); +} + +static int rustsecp256k1_v0_11_ge_eq_var(const rustsecp256k1_v0_11_ge *a, const rustsecp256k1_v0_11_ge *b) { + rustsecp256k1_v0_11_fe tmp; + SECP256K1_GE_VERIFY(a); + SECP256K1_GE_VERIFY(b); + + if (a->infinity != b->infinity) return 0; + if (a->infinity) return 1; + + tmp = a->x; + rustsecp256k1_v0_11_fe_normalize_weak(&tmp); + if (!rustsecp256k1_v0_11_fe_equal(&tmp, &b->x)) return 0; + + tmp = a->y; + rustsecp256k1_v0_11_fe_normalize_weak(&tmp); + if (!rustsecp256k1_v0_11_fe_equal(&tmp, &b->y)) return 0; + + return 1; +} + +static int rustsecp256k1_v0_11_gej_eq_x_var(const rustsecp256k1_v0_11_fe *x, const rustsecp256k1_v0_11_gej *a) { + rustsecp256k1_v0_11_fe r; + SECP256K1_FE_VERIFY(x); + SECP256K1_GEJ_VERIFY(a); + VERIFY_CHECK(!a->infinity); + + rustsecp256k1_v0_11_fe_sqr(&r, &a->z); rustsecp256k1_v0_11_fe_mul(&r, &r, x); + return rustsecp256k1_v0_11_fe_equal(&r, &a->x); +} + +static void rustsecp256k1_v0_11_gej_neg(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a) { + SECP256K1_GEJ_VERIFY(a); + + r->infinity = a->infinity; + r->x = a->x; + r->y = a->y; + r->z = a->z; + rustsecp256k1_v0_11_fe_normalize_weak(&r->y); + rustsecp256k1_v0_11_fe_negate(&r->y, &r->y, 1); + + SECP256K1_GEJ_VERIFY(r); +} + +static int rustsecp256k1_v0_11_gej_is_infinity(const rustsecp256k1_v0_11_gej *a) { + SECP256K1_GEJ_VERIFY(a); + + return a->infinity; +} + +static int rustsecp256k1_v0_11_ge_is_valid_var(const rustsecp256k1_v0_11_ge *a) { + rustsecp256k1_v0_11_fe y2, x3; + SECP256K1_GE_VERIFY(a); + + if (a->infinity) { + return 0; + } + /* y^2 = x^3 + 7 */ + rustsecp256k1_v0_11_fe_sqr(&y2, &a->y); + rustsecp256k1_v0_11_fe_sqr(&x3, &a->x); rustsecp256k1_v0_11_fe_mul(&x3, &x3, &a->x); + rustsecp256k1_v0_11_fe_add_int(&x3, SECP256K1_B); + return rustsecp256k1_v0_11_fe_equal(&y2, &x3); +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_gej_double(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a) { + /* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */ + rustsecp256k1_v0_11_fe l, s, t; + SECP256K1_GEJ_VERIFY(a); + + r->infinity = a->infinity; + + /* Formula used: + * L = (3/2) * X1^2 + * S = Y1^2 + * T = -X1*S + * X3 = L^2 + 2*T + * Y3 = -(L*(X3 + T) + S^2) + * Z3 = Y1*Z1 + */ + + rustsecp256k1_v0_11_fe_mul(&r->z, &a->z, &a->y); /* Z3 = Y1*Z1 (1) */ + rustsecp256k1_v0_11_fe_sqr(&s, &a->y); /* S = Y1^2 (1) */ + rustsecp256k1_v0_11_fe_sqr(&l, &a->x); /* L = X1^2 (1) */ + rustsecp256k1_v0_11_fe_mul_int(&l, 3); /* L = 3*X1^2 (3) */ + rustsecp256k1_v0_11_fe_half(&l); /* L = 3/2*X1^2 (2) */ + rustsecp256k1_v0_11_fe_negate(&t, &s, 1); /* T = -S (2) */ + rustsecp256k1_v0_11_fe_mul(&t, &t, &a->x); /* T = -X1*S (1) */ + rustsecp256k1_v0_11_fe_sqr(&r->x, &l); /* X3 = L^2 (1) */ + rustsecp256k1_v0_11_fe_add(&r->x, &t); /* X3 = L^2 + T (2) */ + rustsecp256k1_v0_11_fe_add(&r->x, &t); /* X3 = L^2 + 2*T (3) */ + rustsecp256k1_v0_11_fe_sqr(&s, &s); /* S' = S^2 (1) */ + rustsecp256k1_v0_11_fe_add(&t, &r->x); /* T' = X3 + T (4) */ + rustsecp256k1_v0_11_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */ + rustsecp256k1_v0_11_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */ + rustsecp256k1_v0_11_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */ + + SECP256K1_GEJ_VERIFY(r); +} + +static void rustsecp256k1_v0_11_gej_double_var(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a, rustsecp256k1_v0_11_fe *rzr) { + SECP256K1_GEJ_VERIFY(a); + + /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, + * Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have + * y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. + * + * Having said this, if this function receives a point on a sextic twist, e.g. by + * a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6, + * since -6 does have a cube root mod p. For this point, this function will not set + * the infinity flag even though the point doubles to infinity, and the result + * point will be gibberish (z = 0 but infinity = 0). + */ + if (a->infinity) { + rustsecp256k1_v0_11_gej_set_infinity(r); + if (rzr != NULL) { + rustsecp256k1_v0_11_fe_set_int(rzr, 1); + } + return; + } + + if (rzr != NULL) { + *rzr = a->y; + rustsecp256k1_v0_11_fe_normalize_weak(rzr); + } + + rustsecp256k1_v0_11_gej_double(r, a); + + SECP256K1_GEJ_VERIFY(r); +} + +static void rustsecp256k1_v0_11_gej_add_var(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_gej *b, rustsecp256k1_v0_11_fe *rzr) { + /* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ + rustsecp256k1_v0_11_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GEJ_VERIFY(b); + + if (a->infinity) { + VERIFY_CHECK(rzr == NULL); + *r = *b; + return; + } + if (b->infinity) { + if (rzr != NULL) { + rustsecp256k1_v0_11_fe_set_int(rzr, 1); + } + *r = *a; + return; + } + + rustsecp256k1_v0_11_fe_sqr(&z22, &b->z); + rustsecp256k1_v0_11_fe_sqr(&z12, &a->z); + rustsecp256k1_v0_11_fe_mul(&u1, &a->x, &z22); + rustsecp256k1_v0_11_fe_mul(&u2, &b->x, &z12); + rustsecp256k1_v0_11_fe_mul(&s1, &a->y, &z22); rustsecp256k1_v0_11_fe_mul(&s1, &s1, &b->z); + rustsecp256k1_v0_11_fe_mul(&s2, &b->y, &z12); rustsecp256k1_v0_11_fe_mul(&s2, &s2, &a->z); + rustsecp256k1_v0_11_fe_negate(&h, &u1, 1); rustsecp256k1_v0_11_fe_add(&h, &u2); + rustsecp256k1_v0_11_fe_negate(&i, &s2, 1); rustsecp256k1_v0_11_fe_add(&i, &s1); + if (rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&h)) { + if (rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&i)) { + rustsecp256k1_v0_11_gej_double_var(r, a, rzr); + } else { + if (rzr != NULL) { + rustsecp256k1_v0_11_fe_set_int(rzr, 0); + } + rustsecp256k1_v0_11_gej_set_infinity(r); + } + return; + } + + r->infinity = 0; + rustsecp256k1_v0_11_fe_mul(&t, &h, &b->z); + if (rzr != NULL) { + *rzr = t; + } + rustsecp256k1_v0_11_fe_mul(&r->z, &a->z, &t); + + rustsecp256k1_v0_11_fe_sqr(&h2, &h); + rustsecp256k1_v0_11_fe_negate(&h2, &h2, 1); + rustsecp256k1_v0_11_fe_mul(&h3, &h2, &h); + rustsecp256k1_v0_11_fe_mul(&t, &u1, &h2); + + rustsecp256k1_v0_11_fe_sqr(&r->x, &i); + rustsecp256k1_v0_11_fe_add(&r->x, &h3); + rustsecp256k1_v0_11_fe_add(&r->x, &t); + rustsecp256k1_v0_11_fe_add(&r->x, &t); + + rustsecp256k1_v0_11_fe_add(&t, &r->x); + rustsecp256k1_v0_11_fe_mul(&r->y, &t, &i); + rustsecp256k1_v0_11_fe_mul(&h3, &h3, &s1); + rustsecp256k1_v0_11_fe_add(&r->y, &h3); + + SECP256K1_GEJ_VERIFY(r); +} + +static void rustsecp256k1_v0_11_gej_add_ge_var(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_ge *b, rustsecp256k1_v0_11_fe *rzr) { + /* Operations: 8 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ + rustsecp256k1_v0_11_fe z12, u1, u2, s1, s2, h, i, h2, h3, t; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(b); + + if (a->infinity) { + VERIFY_CHECK(rzr == NULL); + rustsecp256k1_v0_11_gej_set_ge(r, b); + return; + } + if (b->infinity) { + if (rzr != NULL) { + rustsecp256k1_v0_11_fe_set_int(rzr, 1); + } + *r = *a; + return; + } + + rustsecp256k1_v0_11_fe_sqr(&z12, &a->z); + u1 = a->x; + rustsecp256k1_v0_11_fe_mul(&u2, &b->x, &z12); + s1 = a->y; + rustsecp256k1_v0_11_fe_mul(&s2, &b->y, &z12); rustsecp256k1_v0_11_fe_mul(&s2, &s2, &a->z); + rustsecp256k1_v0_11_fe_negate(&h, &u1, SECP256K1_GEJ_X_MAGNITUDE_MAX); rustsecp256k1_v0_11_fe_add(&h, &u2); + rustsecp256k1_v0_11_fe_negate(&i, &s2, 1); rustsecp256k1_v0_11_fe_add(&i, &s1); + if (rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&h)) { + if (rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&i)) { + rustsecp256k1_v0_11_gej_double_var(r, a, rzr); + } else { + if (rzr != NULL) { + rustsecp256k1_v0_11_fe_set_int(rzr, 0); + } + rustsecp256k1_v0_11_gej_set_infinity(r); + } + return; + } + + r->infinity = 0; + if (rzr != NULL) { + *rzr = h; + } + rustsecp256k1_v0_11_fe_mul(&r->z, &a->z, &h); + + rustsecp256k1_v0_11_fe_sqr(&h2, &h); + rustsecp256k1_v0_11_fe_negate(&h2, &h2, 1); + rustsecp256k1_v0_11_fe_mul(&h3, &h2, &h); + rustsecp256k1_v0_11_fe_mul(&t, &u1, &h2); + + rustsecp256k1_v0_11_fe_sqr(&r->x, &i); + rustsecp256k1_v0_11_fe_add(&r->x, &h3); + rustsecp256k1_v0_11_fe_add(&r->x, &t); + rustsecp256k1_v0_11_fe_add(&r->x, &t); + + rustsecp256k1_v0_11_fe_add(&t, &r->x); + rustsecp256k1_v0_11_fe_mul(&r->y, &t, &i); + rustsecp256k1_v0_11_fe_mul(&h3, &h3, &s1); + rustsecp256k1_v0_11_fe_add(&r->y, &h3); + + SECP256K1_GEJ_VERIFY(r); + if (rzr != NULL) SECP256K1_FE_VERIFY(rzr); +} + +static void rustsecp256k1_v0_11_gej_add_zinv_var(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_ge *b, const rustsecp256k1_v0_11_fe *bzinv) { + /* Operations: 9 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ + rustsecp256k1_v0_11_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(b); + SECP256K1_FE_VERIFY(bzinv); + + if (a->infinity) { + rustsecp256k1_v0_11_fe bzinv2, bzinv3; + r->infinity = b->infinity; + rustsecp256k1_v0_11_fe_sqr(&bzinv2, bzinv); + rustsecp256k1_v0_11_fe_mul(&bzinv3, &bzinv2, bzinv); + rustsecp256k1_v0_11_fe_mul(&r->x, &b->x, &bzinv2); + rustsecp256k1_v0_11_fe_mul(&r->y, &b->y, &bzinv3); + rustsecp256k1_v0_11_fe_set_int(&r->z, 1); + SECP256K1_GEJ_VERIFY(r); + return; + } + if (b->infinity) { + *r = *a; + return; + } + + /** We need to calculate (rx,ry,rz) = (ax,ay,az) + (bx,by,1/bzinv). Due to + * secp256k1's isomorphism we can multiply the Z coordinates on both sides + * by bzinv, and get: (rx,ry,rz*bzinv) = (ax,ay,az*bzinv) + (bx,by,1). + * This means that (rx,ry,rz) can be calculated as + * (ax,ay,az*bzinv) + (bx,by,1), when not applying the bzinv factor to rz. + * The variable az below holds the modified Z coordinate for a, which is used + * for the computation of rx and ry, but not for rz. + */ + rustsecp256k1_v0_11_fe_mul(&az, &a->z, bzinv); + + rustsecp256k1_v0_11_fe_sqr(&z12, &az); + u1 = a->x; + rustsecp256k1_v0_11_fe_mul(&u2, &b->x, &z12); + s1 = a->y; + rustsecp256k1_v0_11_fe_mul(&s2, &b->y, &z12); rustsecp256k1_v0_11_fe_mul(&s2, &s2, &az); + rustsecp256k1_v0_11_fe_negate(&h, &u1, SECP256K1_GEJ_X_MAGNITUDE_MAX); rustsecp256k1_v0_11_fe_add(&h, &u2); + rustsecp256k1_v0_11_fe_negate(&i, &s2, 1); rustsecp256k1_v0_11_fe_add(&i, &s1); + if (rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&h)) { + if (rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&i)) { + rustsecp256k1_v0_11_gej_double_var(r, a, NULL); + } else { + rustsecp256k1_v0_11_gej_set_infinity(r); + } + return; + } + + r->infinity = 0; + rustsecp256k1_v0_11_fe_mul(&r->z, &a->z, &h); + + rustsecp256k1_v0_11_fe_sqr(&h2, &h); + rustsecp256k1_v0_11_fe_negate(&h2, &h2, 1); + rustsecp256k1_v0_11_fe_mul(&h3, &h2, &h); + rustsecp256k1_v0_11_fe_mul(&t, &u1, &h2); + + rustsecp256k1_v0_11_fe_sqr(&r->x, &i); + rustsecp256k1_v0_11_fe_add(&r->x, &h3); + rustsecp256k1_v0_11_fe_add(&r->x, &t); + rustsecp256k1_v0_11_fe_add(&r->x, &t); + + rustsecp256k1_v0_11_fe_add(&t, &r->x); + rustsecp256k1_v0_11_fe_mul(&r->y, &t, &i); + rustsecp256k1_v0_11_fe_mul(&h3, &h3, &s1); + rustsecp256k1_v0_11_fe_add(&r->y, &h3); + + SECP256K1_GEJ_VERIFY(r); +} + + +static void rustsecp256k1_v0_11_gej_add_ge(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_ge *b) { + /* Operations: 7 mul, 5 sqr, 21 add/cmov/half/mul_int/negate/normalizes_to_zero */ + rustsecp256k1_v0_11_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; + rustsecp256k1_v0_11_fe m_alt, rr_alt; + int degenerate; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(b); + VERIFY_CHECK(!b->infinity); + + /* In: + * Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks. + * In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002. + * we find as solution for a unified addition/doubling formula: + * lambda = ((x1 + x2)^2 - x1 * x2 + a) / (y1 + y2), with a = 0 for secp256k1's curve equation. + * x3 = lambda^2 - (x1 + x2) + * 2*y3 = lambda * (x1 + x2 - 2 * x3) - (y1 + y2). + * + * Substituting x_i = Xi / Zi^2 and yi = Yi / Zi^3, for i=1,2,3, gives: + * U1 = X1*Z2^2, U2 = X2*Z1^2 + * S1 = Y1*Z2^3, S2 = Y2*Z1^3 + * Z = Z1*Z2 + * T = U1+U2 + * M = S1+S2 + * Q = -T*M^2 + * R = T^2-U1*U2 + * X3 = R^2+Q + * Y3 = -(R*(2*X3+Q)+M^4)/2 + * Z3 = M*Z + * (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.) + * + * This formula has the benefit of being the same for both addition + * of distinct points and doubling. However, it breaks down in the + * case that either point is infinity, or that y1 = -y2. We handle + * these cases in the following ways: + * + * - If b is infinity we simply bail by means of a VERIFY_CHECK. + * + * - If a is infinity, we detect this, and at the end of the + * computation replace the result (which will be meaningless, + * but we compute to be constant-time) with b.x : b.y : 1. + * + * - If a = -b, we have y1 = -y2, which is a degenerate case. + * But here the answer is infinity, so we simply set the + * infinity flag of the result, overriding the computed values + * without even needing to cmov. + * + * - If y1 = -y2 but x1 != x2, which does occur thanks to certain + * properties of our curve (specifically, 1 has nontrivial cube + * roots in our field, and the curve equation has no x coefficient) + * then the answer is not infinity but also not given by the above + * equation. In this case, we cmov in place an alternate expression + * for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these + * expressions for lambda are defined, they are equal, and can be + * obtained from each other by multiplication by (y1 + y2)/(y1 + y2) + * then substitution of x^3 + 7 for y^2 (using the curve equation). + * For all pairs of nonzero points (a, b) at least one is defined, + * so this covers everything. + */ + + rustsecp256k1_v0_11_fe_sqr(&zz, &a->z); /* z = Z1^2 */ + u1 = a->x; /* u1 = U1 = X1*Z2^2 (GEJ_X_M) */ + rustsecp256k1_v0_11_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ + s1 = a->y; /* s1 = S1 = Y1*Z2^3 (GEJ_Y_M) */ + rustsecp256k1_v0_11_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */ + rustsecp256k1_v0_11_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ + t = u1; rustsecp256k1_v0_11_fe_add(&t, &u2); /* t = T = U1+U2 (GEJ_X_M+1) */ + m = s1; rustsecp256k1_v0_11_fe_add(&m, &s2); /* m = M = S1+S2 (GEJ_Y_M+1) */ + rustsecp256k1_v0_11_fe_sqr(&rr, &t); /* rr = T^2 (1) */ + rustsecp256k1_v0_11_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 (2) */ + rustsecp256k1_v0_11_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (1) */ + rustsecp256k1_v0_11_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (2) */ + /* If lambda = R/M = R/0 we have a problem (except in the "trivial" + * case that Z = z1z2 = 0, and this is special-cased later on). */ + degenerate = rustsecp256k1_v0_11_fe_normalizes_to_zero(&m); + /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. + * This means either x1 == beta*x2 or beta*x1 == x2, where beta is + * a nontrivial cube root of one. In either case, an alternate + * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2), + * so we set R/M equal to this. */ + rr_alt = s1; + rustsecp256k1_v0_11_fe_mul_int(&rr_alt, 2); /* rr_alt = Y1*Z2^3 - Y2*Z1^3 (GEJ_Y_M*2) */ + rustsecp256k1_v0_11_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 (GEJ_X_M+2) */ + + rustsecp256k1_v0_11_fe_cmov(&rr_alt, &rr, !degenerate); /* rr_alt (GEJ_Y_M*2) */ + rustsecp256k1_v0_11_fe_cmov(&m_alt, &m, !degenerate); /* m_alt (GEJ_X_M+2) */ + /* Now Ralt / Malt = lambda and is guaranteed not to be Ralt / 0. + * From here on out Ralt and Malt represent the numerator + * and denominator of lambda; R and M represent the explicit + * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ + rustsecp256k1_v0_11_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */ + rustsecp256k1_v0_11_fe_negate(&q, &t, + SECP256K1_GEJ_X_MAGNITUDE_MAX + 1); /* q = -T (GEJ_X_M+2) */ + rustsecp256k1_v0_11_fe_mul(&q, &q, &n); /* q = Q = -T*Malt^2 (1) */ + /* These two lines use the observation that either M == Malt or M == 0, + * so M^3 * Malt is either Malt^4 (which is computed by squaring), or + * zero (which is "computed" by cmov). So the cost is one squaring + * versus two multiplications. */ + rustsecp256k1_v0_11_fe_sqr(&n, &n); /* n = Malt^4 (1) */ + rustsecp256k1_v0_11_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (GEJ_Y_M+1) */ + rustsecp256k1_v0_11_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ + rustsecp256k1_v0_11_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */ + rustsecp256k1_v0_11_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */ + r->x = t; /* r->x = X3 = Ralt^2 + Q (2) */ + rustsecp256k1_v0_11_fe_mul_int(&t, 2); /* t = 2*X3 (4) */ + rustsecp256k1_v0_11_fe_add(&t, &q); /* t = 2*X3 + Q (5) */ + rustsecp256k1_v0_11_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*X3 + Q) (1) */ + rustsecp256k1_v0_11_fe_add(&t, &n); /* t = Ralt*(2*X3 + Q) + M^3*Malt (GEJ_Y_M+2) */ + rustsecp256k1_v0_11_fe_negate(&r->y, &t, + SECP256K1_GEJ_Y_MAGNITUDE_MAX + 2); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (GEJ_Y_M+3) */ + rustsecp256k1_v0_11_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 ((GEJ_Y_M+3)/2 + 1) */ + + /* In case a->infinity == 1, replace r with (b->x, b->y, 1). */ + rustsecp256k1_v0_11_fe_cmov(&r->x, &b->x, a->infinity); + rustsecp256k1_v0_11_fe_cmov(&r->y, &b->y, a->infinity); + rustsecp256k1_v0_11_fe_cmov(&r->z, &rustsecp256k1_v0_11_fe_one, a->infinity); + + /* Set r->infinity if r->z is 0. + * + * If a->infinity is set, then r->infinity = (r->z == 0) = (1 == 0) = false, + * which is correct because the function assumes that b is not infinity. + * + * Now assume !a->infinity. This implies Z = Z1 != 0. + * + * Case y1 = -y2: + * In this case we could have a = -b, namely if x1 = x2. + * We have degenerate = true, r->z = (x1 - x2) * Z. + * Then r->infinity = ((x1 - x2)Z == 0) = (x1 == x2) = (a == -b). + * + * Case y1 != -y2: + * In this case, we can't have a = -b. + * We have degenerate = false, r->z = (y1 + y2) * Z. + * Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */ + r->infinity = rustsecp256k1_v0_11_fe_normalizes_to_zero(&r->z); + + SECP256K1_GEJ_VERIFY(r); +} + +static void rustsecp256k1_v0_11_gej_rescale(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_fe *s) { + /* Operations: 4 mul, 1 sqr */ + rustsecp256k1_v0_11_fe zz; + SECP256K1_GEJ_VERIFY(r); + SECP256K1_FE_VERIFY(s); + VERIFY_CHECK(!rustsecp256k1_v0_11_fe_normalizes_to_zero_var(s)); + + rustsecp256k1_v0_11_fe_sqr(&zz, s); + rustsecp256k1_v0_11_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ + rustsecp256k1_v0_11_fe_mul(&r->y, &r->y, &zz); + rustsecp256k1_v0_11_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ + rustsecp256k1_v0_11_fe_mul(&r->z, &r->z, s); /* r->z *= s */ + + SECP256K1_GEJ_VERIFY(r); +} + +static void rustsecp256k1_v0_11_ge_to_storage(rustsecp256k1_v0_11_ge_storage *r, const rustsecp256k1_v0_11_ge *a) { + rustsecp256k1_v0_11_fe x, y; + SECP256K1_GE_VERIFY(a); + VERIFY_CHECK(!a->infinity); + + x = a->x; + rustsecp256k1_v0_11_fe_normalize(&x); + y = a->y; + rustsecp256k1_v0_11_fe_normalize(&y); + rustsecp256k1_v0_11_fe_to_storage(&r->x, &x); + rustsecp256k1_v0_11_fe_to_storage(&r->y, &y); +} + +static void rustsecp256k1_v0_11_ge_from_storage(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_ge_storage *a) { + rustsecp256k1_v0_11_fe_from_storage(&r->x, &a->x); + rustsecp256k1_v0_11_fe_from_storage(&r->y, &a->y); + r->infinity = 0; + + SECP256K1_GE_VERIFY(r); +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_gej_cmov(rustsecp256k1_v0_11_gej *r, const rustsecp256k1_v0_11_gej *a, int flag) { + SECP256K1_GEJ_VERIFY(r); + SECP256K1_GEJ_VERIFY(a); + + rustsecp256k1_v0_11_fe_cmov(&r->x, &a->x, flag); + rustsecp256k1_v0_11_fe_cmov(&r->y, &a->y, flag); + rustsecp256k1_v0_11_fe_cmov(&r->z, &a->z, flag); + r->infinity ^= (r->infinity ^ a->infinity) & flag; + + SECP256K1_GEJ_VERIFY(r); +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_ge_storage_cmov(rustsecp256k1_v0_11_ge_storage *r, const rustsecp256k1_v0_11_ge_storage *a, int flag) { + rustsecp256k1_v0_11_fe_storage_cmov(&r->x, &a->x, flag); + rustsecp256k1_v0_11_fe_storage_cmov(&r->y, &a->y, flag); +} + +static void rustsecp256k1_v0_11_ge_mul_lambda(rustsecp256k1_v0_11_ge *r, const rustsecp256k1_v0_11_ge *a) { + SECP256K1_GE_VERIFY(a); + + *r = *a; + rustsecp256k1_v0_11_fe_mul(&r->x, &r->x, &rustsecp256k1_v0_11_const_beta); + + SECP256K1_GE_VERIFY(r); +} + +static int rustsecp256k1_v0_11_ge_is_in_correct_subgroup(const rustsecp256k1_v0_11_ge* ge) { +#ifdef EXHAUSTIVE_TEST_ORDER + rustsecp256k1_v0_11_gej out; + int i; + SECP256K1_GE_VERIFY(ge); + + /* A very simple EC multiplication ladder that avoids a dependency on ecmult. */ + rustsecp256k1_v0_11_gej_set_infinity(&out); + for (i = 0; i < 32; ++i) { + rustsecp256k1_v0_11_gej_double_var(&out, &out, NULL); + if ((((uint32_t)EXHAUSTIVE_TEST_ORDER) >> (31 - i)) & 1) { + rustsecp256k1_v0_11_gej_add_ge_var(&out, &out, ge, NULL); + } + } + return rustsecp256k1_v0_11_gej_is_infinity(&out); +#else + SECP256K1_GE_VERIFY(ge); + + (void)ge; + /* The real secp256k1 group has cofactor 1, so the subgroup is the entire curve. */ + return 1; +#endif +} + +static int rustsecp256k1_v0_11_ge_x_on_curve_var(const rustsecp256k1_v0_11_fe *x) { + rustsecp256k1_v0_11_fe c; + rustsecp256k1_v0_11_fe_sqr(&c, x); + rustsecp256k1_v0_11_fe_mul(&c, &c, x); + rustsecp256k1_v0_11_fe_add_int(&c, SECP256K1_B); + return rustsecp256k1_v0_11_fe_is_square_var(&c); +} + +static int rustsecp256k1_v0_11_ge_x_frac_on_curve_var(const rustsecp256k1_v0_11_fe *xn, const rustsecp256k1_v0_11_fe *xd) { + /* We want to determine whether (xn/xd) is on the curve. + * + * (xn/xd)^3 + 7 is square <=> xd*xn^3 + 7*xd^4 is square (multiplying by xd^4, a square). + */ + rustsecp256k1_v0_11_fe r, t; + VERIFY_CHECK(!rustsecp256k1_v0_11_fe_normalizes_to_zero_var(xd)); + + rustsecp256k1_v0_11_fe_mul(&r, xd, xn); /* r = xd*xn */ + rustsecp256k1_v0_11_fe_sqr(&t, xn); /* t = xn^2 */ + rustsecp256k1_v0_11_fe_mul(&r, &r, &t); /* r = xd*xn^3 */ + rustsecp256k1_v0_11_fe_sqr(&t, xd); /* t = xd^2 */ + rustsecp256k1_v0_11_fe_sqr(&t, &t); /* t = xd^4 */ + VERIFY_CHECK(SECP256K1_B <= 31); + rustsecp256k1_v0_11_fe_mul_int(&t, SECP256K1_B); /* t = 7*xd^4 */ + rustsecp256k1_v0_11_fe_add(&r, &t); /* r = xd*xn^3 + 7*xd^4 */ + return rustsecp256k1_v0_11_fe_is_square_var(&r); +} + +static void rustsecp256k1_v0_11_ge_to_bytes(unsigned char *buf, const rustsecp256k1_v0_11_ge *a) { + rustsecp256k1_v0_11_ge_storage s; + + /* We require that the rustsecp256k1_v0_11_ge_storage type is exactly 64 bytes. + * This is formally not guaranteed by the C standard, but should hold on any + * sane compiler in the real world. */ + STATIC_ASSERT(sizeof(rustsecp256k1_v0_11_ge_storage) == 64); + VERIFY_CHECK(!rustsecp256k1_v0_11_ge_is_infinity(a)); + rustsecp256k1_v0_11_ge_to_storage(&s, a); + memcpy(buf, &s, 64); +} + +static void rustsecp256k1_v0_11_ge_from_bytes(rustsecp256k1_v0_11_ge *r, const unsigned char *buf) { + rustsecp256k1_v0_11_ge_storage s; + + STATIC_ASSERT(sizeof(rustsecp256k1_v0_11_ge_storage) == 64); + memcpy(&s, buf, 64); + rustsecp256k1_v0_11_ge_from_storage(r, &s); +} + +static void rustsecp256k1_v0_11_ge_to_bytes_ext(unsigned char *data, const rustsecp256k1_v0_11_ge *ge) { + if (rustsecp256k1_v0_11_ge_is_infinity(ge)) { + memset(data, 0, 64); + } else { + rustsecp256k1_v0_11_ge_to_bytes(data, ge); + } +} + +static void rustsecp256k1_v0_11_ge_from_bytes_ext(rustsecp256k1_v0_11_ge *ge, const unsigned char *data) { + static const unsigned char zeros[64] = { 0 }; + if (rustsecp256k1_v0_11_memcmp_var(data, zeros, sizeof(zeros)) == 0) { + rustsecp256k1_v0_11_ge_set_infinity(ge); + } else { + rustsecp256k1_v0_11_ge_from_bytes(ge, data); + } +} + +#endif /* SECP256K1_GROUP_IMPL_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/hash.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/hash.h new file mode 100644 index 00000000..357763aa --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/hash.h @@ -0,0 +1,44 @@ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_HASH_H +#define SECP256K1_HASH_H + +#include +#include + +typedef struct { + uint32_t s[8]; + unsigned char buf[64]; + uint64_t bytes; +} rustsecp256k1_v0_11_sha256; + +static void rustsecp256k1_v0_11_sha256_initialize(rustsecp256k1_v0_11_sha256 *hash); +static void rustsecp256k1_v0_11_sha256_write(rustsecp256k1_v0_11_sha256 *hash, const unsigned char *data, size_t size); +static void rustsecp256k1_v0_11_sha256_finalize(rustsecp256k1_v0_11_sha256 *hash, unsigned char *out32); +static void rustsecp256k1_v0_11_sha256_clear(rustsecp256k1_v0_11_sha256 *hash); + +typedef struct { + rustsecp256k1_v0_11_sha256 inner, outer; +} rustsecp256k1_v0_11_hmac_sha256; + +static void rustsecp256k1_v0_11_hmac_sha256_initialize(rustsecp256k1_v0_11_hmac_sha256 *hash, const unsigned char *key, size_t size); +static void rustsecp256k1_v0_11_hmac_sha256_write(rustsecp256k1_v0_11_hmac_sha256 *hash, const unsigned char *data, size_t size); +static void rustsecp256k1_v0_11_hmac_sha256_finalize(rustsecp256k1_v0_11_hmac_sha256 *hash, unsigned char *out32); +static void rustsecp256k1_v0_11_hmac_sha256_clear(rustsecp256k1_v0_11_hmac_sha256 *hash); + +typedef struct { + unsigned char v[32]; + unsigned char k[32]; + int retry; +} rustsecp256k1_v0_11_rfc6979_hmac_sha256; + +static void rustsecp256k1_v0_11_rfc6979_hmac_sha256_initialize(rustsecp256k1_v0_11_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen); +static void rustsecp256k1_v0_11_rfc6979_hmac_sha256_generate(rustsecp256k1_v0_11_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen); +static void rustsecp256k1_v0_11_rfc6979_hmac_sha256_finalize(rustsecp256k1_v0_11_rfc6979_hmac_sha256 *rng); +static void rustsecp256k1_v0_11_rfc6979_hmac_sha256_clear(rustsecp256k1_v0_11_rfc6979_hmac_sha256 *rng); + +#endif /* SECP256K1_HASH_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/hash_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/hash_impl.h similarity index 61% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/hash_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/hash_impl.h index 780021af..373af72d 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/hash_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/hash_impl.h @@ -28,7 +28,7 @@ (h) = t1 + t2; \ } while(0) -static void rustsecp256k1zkp_v0_8_0_sha256_initialize(rustsecp256k1zkp_v0_8_0_sha256 *hash) { +static void rustsecp256k1_v0_11_sha256_initialize(rustsecp256k1_v0_11_sha256 *hash) { hash->s[0] = 0x6a09e667ul; hash->s[1] = 0xbb67ae85ul; hash->s[2] = 0x3c6ef372ul; @@ -41,26 +41,26 @@ static void rustsecp256k1zkp_v0_8_0_sha256_initialize(rustsecp256k1zkp_v0_8_0_sh } /** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */ -static void rustsecp256k1zkp_v0_8_0_sha256_transform(uint32_t* s, const unsigned char* buf) { +static void rustsecp256k1_v0_11_sha256_transform(uint32_t* s, const unsigned char* buf) { uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; - Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[0])); - Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[4])); - Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[8])); - Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[12])); - Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[16])); - Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[20])); - Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[24])); - Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[28])); - Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[32])); - Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[36])); - Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[40])); - Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[44])); - Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[48])); - Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[52])); - Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[56])); - Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = rustsecp256k1zkp_v0_8_0_read_be32(&buf[60])); + Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = rustsecp256k1_v0_11_read_be32(&buf[0])); + Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = rustsecp256k1_v0_11_read_be32(&buf[4])); + Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = rustsecp256k1_v0_11_read_be32(&buf[8])); + Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = rustsecp256k1_v0_11_read_be32(&buf[12])); + Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = rustsecp256k1_v0_11_read_be32(&buf[16])); + Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = rustsecp256k1_v0_11_read_be32(&buf[20])); + Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = rustsecp256k1_v0_11_read_be32(&buf[24])); + Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = rustsecp256k1_v0_11_read_be32(&buf[28])); + Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = rustsecp256k1_v0_11_read_be32(&buf[32])); + Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = rustsecp256k1_v0_11_read_be32(&buf[36])); + Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = rustsecp256k1_v0_11_read_be32(&buf[40])); + Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = rustsecp256k1_v0_11_read_be32(&buf[44])); + Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = rustsecp256k1_v0_11_read_be32(&buf[48])); + Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = rustsecp256k1_v0_11_read_be32(&buf[52])); + Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = rustsecp256k1_v0_11_read_be32(&buf[56])); + Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = rustsecp256k1_v0_11_read_be32(&buf[60])); Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1)); Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2)); @@ -123,7 +123,7 @@ static void rustsecp256k1zkp_v0_8_0_sha256_transform(uint32_t* s, const unsigned s[7] += h; } -static void rustsecp256k1zkp_v0_8_0_sha256_write(rustsecp256k1zkp_v0_8_0_sha256 *hash, const unsigned char *data, size_t len) { +static void rustsecp256k1_v0_11_sha256_write(rustsecp256k1_v0_11_sha256 *hash, const unsigned char *data, size_t len) { size_t bufsize = hash->bytes & 0x3F; hash->bytes += len; VERIFY_CHECK(hash->bytes >= len); @@ -133,87 +133,94 @@ static void rustsecp256k1zkp_v0_8_0_sha256_write(rustsecp256k1zkp_v0_8_0_sha256 memcpy(hash->buf + bufsize, data, chunk_len); data += chunk_len; len -= chunk_len; - rustsecp256k1zkp_v0_8_0_sha256_transform(hash->s, hash->buf); + rustsecp256k1_v0_11_sha256_transform(hash->s, hash->buf); bufsize = 0; } if (len) { /* Fill the buffer with what remains. */ - memcpy(((unsigned char*)hash->buf) + bufsize, data, len); + memcpy(hash->buf + bufsize, data, len); } } -static void rustsecp256k1zkp_v0_8_0_sha256_finalize(rustsecp256k1zkp_v0_8_0_sha256 *hash, unsigned char *out32) { +static void rustsecp256k1_v0_11_sha256_finalize(rustsecp256k1_v0_11_sha256 *hash, unsigned char *out32) { static const unsigned char pad[64] = {0x80}; unsigned char sizedesc[8]; int i; /* The maximum message size of SHA256 is 2^64-1 bits. */ VERIFY_CHECK(hash->bytes < ((uint64_t)1 << 61)); - rustsecp256k1zkp_v0_8_0_write_be32(&sizedesc[0], hash->bytes >> 29); - rustsecp256k1zkp_v0_8_0_write_be32(&sizedesc[4], hash->bytes << 3); - rustsecp256k1zkp_v0_8_0_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64)); - rustsecp256k1zkp_v0_8_0_sha256_write(hash, sizedesc, 8); + rustsecp256k1_v0_11_write_be32(&sizedesc[0], hash->bytes >> 29); + rustsecp256k1_v0_11_write_be32(&sizedesc[4], hash->bytes << 3); + rustsecp256k1_v0_11_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64)); + rustsecp256k1_v0_11_sha256_write(hash, sizedesc, 8); for (i = 0; i < 8; i++) { - rustsecp256k1zkp_v0_8_0_write_be32(&out32[4*i], hash->s[i]); + rustsecp256k1_v0_11_write_be32(&out32[4*i], hash->s[i]); hash->s[i] = 0; } } /* Initializes a sha256 struct and writes the 64 byte string * SHA256(tag)||SHA256(tag) into it. */ -static void rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(rustsecp256k1zkp_v0_8_0_sha256 *hash, const unsigned char *tag, size_t taglen) { +static void rustsecp256k1_v0_11_sha256_initialize_tagged(rustsecp256k1_v0_11_sha256 *hash, const unsigned char *tag, size_t taglen) { unsigned char buf[32]; - rustsecp256k1zkp_v0_8_0_sha256_initialize(hash); - rustsecp256k1zkp_v0_8_0_sha256_write(hash, tag, taglen); - rustsecp256k1zkp_v0_8_0_sha256_finalize(hash, buf); + rustsecp256k1_v0_11_sha256_initialize(hash); + rustsecp256k1_v0_11_sha256_write(hash, tag, taglen); + rustsecp256k1_v0_11_sha256_finalize(hash, buf); - rustsecp256k1zkp_v0_8_0_sha256_initialize(hash); - rustsecp256k1zkp_v0_8_0_sha256_write(hash, buf, 32); - rustsecp256k1zkp_v0_8_0_sha256_write(hash, buf, 32); + rustsecp256k1_v0_11_sha256_initialize(hash); + rustsecp256k1_v0_11_sha256_write(hash, buf, 32); + rustsecp256k1_v0_11_sha256_write(hash, buf, 32); } -static void rustsecp256k1zkp_v0_8_0_hmac_sha256_initialize(rustsecp256k1zkp_v0_8_0_hmac_sha256 *hash, const unsigned char *key, size_t keylen) { +static void rustsecp256k1_v0_11_sha256_clear(rustsecp256k1_v0_11_sha256 *hash) { + rustsecp256k1_v0_11_memclear(hash, sizeof(*hash)); +} + +static void rustsecp256k1_v0_11_hmac_sha256_initialize(rustsecp256k1_v0_11_hmac_sha256 *hash, const unsigned char *key, size_t keylen) { size_t n; unsigned char rkey[64]; if (keylen <= sizeof(rkey)) { memcpy(rkey, key, keylen); memset(rkey + keylen, 0, sizeof(rkey) - keylen); } else { - rustsecp256k1zkp_v0_8_0_sha256 sha256; - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha256); - rustsecp256k1zkp_v0_8_0_sha256_write(&sha256, key, keylen); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&sha256, rkey); + rustsecp256k1_v0_11_sha256 sha256; + rustsecp256k1_v0_11_sha256_initialize(&sha256); + rustsecp256k1_v0_11_sha256_write(&sha256, key, keylen); + rustsecp256k1_v0_11_sha256_finalize(&sha256, rkey); memset(rkey + 32, 0, 32); } - rustsecp256k1zkp_v0_8_0_sha256_initialize(&hash->outer); + rustsecp256k1_v0_11_sha256_initialize(&hash->outer); for (n = 0; n < sizeof(rkey); n++) { rkey[n] ^= 0x5c; } - rustsecp256k1zkp_v0_8_0_sha256_write(&hash->outer, rkey, sizeof(rkey)); + rustsecp256k1_v0_11_sha256_write(&hash->outer, rkey, sizeof(rkey)); - rustsecp256k1zkp_v0_8_0_sha256_initialize(&hash->inner); + rustsecp256k1_v0_11_sha256_initialize(&hash->inner); for (n = 0; n < sizeof(rkey); n++) { rkey[n] ^= 0x5c ^ 0x36; } - rustsecp256k1zkp_v0_8_0_sha256_write(&hash->inner, rkey, sizeof(rkey)); - memset(rkey, 0, sizeof(rkey)); + rustsecp256k1_v0_11_sha256_write(&hash->inner, rkey, sizeof(rkey)); + rustsecp256k1_v0_11_memclear(rkey, sizeof(rkey)); } -static void rustsecp256k1zkp_v0_8_0_hmac_sha256_write(rustsecp256k1zkp_v0_8_0_hmac_sha256 *hash, const unsigned char *data, size_t size) { - rustsecp256k1zkp_v0_8_0_sha256_write(&hash->inner, data, size); +static void rustsecp256k1_v0_11_hmac_sha256_write(rustsecp256k1_v0_11_hmac_sha256 *hash, const unsigned char *data, size_t size) { + rustsecp256k1_v0_11_sha256_write(&hash->inner, data, size); } -static void rustsecp256k1zkp_v0_8_0_hmac_sha256_finalize(rustsecp256k1zkp_v0_8_0_hmac_sha256 *hash, unsigned char *out32) { +static void rustsecp256k1_v0_11_hmac_sha256_finalize(rustsecp256k1_v0_11_hmac_sha256 *hash, unsigned char *out32) { unsigned char temp[32]; - rustsecp256k1zkp_v0_8_0_sha256_finalize(&hash->inner, temp); - rustsecp256k1zkp_v0_8_0_sha256_write(&hash->outer, temp, 32); - memset(temp, 0, 32); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&hash->outer, out32); + rustsecp256k1_v0_11_sha256_finalize(&hash->inner, temp); + rustsecp256k1_v0_11_sha256_write(&hash->outer, temp, 32); + rustsecp256k1_v0_11_memclear(temp, sizeof(temp)); + rustsecp256k1_v0_11_sha256_finalize(&hash->outer, out32); } +static void rustsecp256k1_v0_11_hmac_sha256_clear(rustsecp256k1_v0_11_hmac_sha256 *hash) { + rustsecp256k1_v0_11_memclear(hash, sizeof(*hash)); +} -static void rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_initialize(rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) { - rustsecp256k1zkp_v0_8_0_hmac_sha256 hmac; +static void rustsecp256k1_v0_11_rfc6979_hmac_sha256_initialize(rustsecp256k1_v0_11_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) { + rustsecp256k1_v0_11_hmac_sha256 hmac; static const unsigned char zero[1] = {0x00}; static const unsigned char one[1] = {0x01}; @@ -221,47 +228,47 @@ static void rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_initialize(rustsecp256k1 memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */ /* RFC6979 3.2.d. */ - rustsecp256k1zkp_v0_8_0_hmac_sha256_initialize(&hmac, rng->k, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hmac, rng->v, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hmac, zero, 1); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hmac, key, keylen); - rustsecp256k1zkp_v0_8_0_hmac_sha256_finalize(&hmac, rng->k); - rustsecp256k1zkp_v0_8_0_hmac_sha256_initialize(&hmac, rng->k, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hmac, rng->v, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_finalize(&hmac, rng->v); + rustsecp256k1_v0_11_hmac_sha256_initialize(&hmac, rng->k, 32); + rustsecp256k1_v0_11_hmac_sha256_write(&hmac, rng->v, 32); + rustsecp256k1_v0_11_hmac_sha256_write(&hmac, zero, 1); + rustsecp256k1_v0_11_hmac_sha256_write(&hmac, key, keylen); + rustsecp256k1_v0_11_hmac_sha256_finalize(&hmac, rng->k); + rustsecp256k1_v0_11_hmac_sha256_initialize(&hmac, rng->k, 32); + rustsecp256k1_v0_11_hmac_sha256_write(&hmac, rng->v, 32); + rustsecp256k1_v0_11_hmac_sha256_finalize(&hmac, rng->v); /* RFC6979 3.2.f. */ - rustsecp256k1zkp_v0_8_0_hmac_sha256_initialize(&hmac, rng->k, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hmac, rng->v, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hmac, one, 1); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hmac, key, keylen); - rustsecp256k1zkp_v0_8_0_hmac_sha256_finalize(&hmac, rng->k); - rustsecp256k1zkp_v0_8_0_hmac_sha256_initialize(&hmac, rng->k, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hmac, rng->v, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_finalize(&hmac, rng->v); + rustsecp256k1_v0_11_hmac_sha256_initialize(&hmac, rng->k, 32); + rustsecp256k1_v0_11_hmac_sha256_write(&hmac, rng->v, 32); + rustsecp256k1_v0_11_hmac_sha256_write(&hmac, one, 1); + rustsecp256k1_v0_11_hmac_sha256_write(&hmac, key, keylen); + rustsecp256k1_v0_11_hmac_sha256_finalize(&hmac, rng->k); + rustsecp256k1_v0_11_hmac_sha256_initialize(&hmac, rng->k, 32); + rustsecp256k1_v0_11_hmac_sha256_write(&hmac, rng->v, 32); + rustsecp256k1_v0_11_hmac_sha256_finalize(&hmac, rng->v); rng->retry = 0; } -static void rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) { +static void rustsecp256k1_v0_11_rfc6979_hmac_sha256_generate(rustsecp256k1_v0_11_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) { /* RFC6979 3.2.h. */ static const unsigned char zero[1] = {0x00}; if (rng->retry) { - rustsecp256k1zkp_v0_8_0_hmac_sha256 hmac; - rustsecp256k1zkp_v0_8_0_hmac_sha256_initialize(&hmac, rng->k, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hmac, rng->v, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hmac, zero, 1); - rustsecp256k1zkp_v0_8_0_hmac_sha256_finalize(&hmac, rng->k); - rustsecp256k1zkp_v0_8_0_hmac_sha256_initialize(&hmac, rng->k, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hmac, rng->v, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_finalize(&hmac, rng->v); + rustsecp256k1_v0_11_hmac_sha256 hmac; + rustsecp256k1_v0_11_hmac_sha256_initialize(&hmac, rng->k, 32); + rustsecp256k1_v0_11_hmac_sha256_write(&hmac, rng->v, 32); + rustsecp256k1_v0_11_hmac_sha256_write(&hmac, zero, 1); + rustsecp256k1_v0_11_hmac_sha256_finalize(&hmac, rng->k); + rustsecp256k1_v0_11_hmac_sha256_initialize(&hmac, rng->k, 32); + rustsecp256k1_v0_11_hmac_sha256_write(&hmac, rng->v, 32); + rustsecp256k1_v0_11_hmac_sha256_finalize(&hmac, rng->v); } while (outlen > 0) { - rustsecp256k1zkp_v0_8_0_hmac_sha256 hmac; + rustsecp256k1_v0_11_hmac_sha256 hmac; int now = outlen; - rustsecp256k1zkp_v0_8_0_hmac_sha256_initialize(&hmac, rng->k, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hmac, rng->v, 32); - rustsecp256k1zkp_v0_8_0_hmac_sha256_finalize(&hmac, rng->v); + rustsecp256k1_v0_11_hmac_sha256_initialize(&hmac, rng->k, 32); + rustsecp256k1_v0_11_hmac_sha256_write(&hmac, rng->v, 32); + rustsecp256k1_v0_11_hmac_sha256_finalize(&hmac, rng->v); if (now > 32) { now = 32; } @@ -273,10 +280,12 @@ static void rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(rustsecp256k1zk rng->retry = 1; } -static void rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_finalize(rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256 *rng) { - memset(rng->k, 0, 32); - memset(rng->v, 0, 32); - rng->retry = 0; +static void rustsecp256k1_v0_11_rfc6979_hmac_sha256_finalize(rustsecp256k1_v0_11_rfc6979_hmac_sha256 *rng) { + (void) rng; +} + +static void rustsecp256k1_v0_11_rfc6979_hmac_sha256_clear(rustsecp256k1_v0_11_rfc6979_hmac_sha256 *rng) { + rustsecp256k1_v0_11_memclear(rng, sizeof(*rng)); } #undef Round diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/hsort.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/hsort.h new file mode 100644 index 00000000..8c8660ff --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/hsort.h @@ -0,0 +1,33 @@ +/*********************************************************************** + * Copyright (c) 2021 Russell O'Connor, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_HSORT_H +#define SECP256K1_HSORT_H + +#include +#include + +/* In-place, iterative heapsort with an interface matching glibc's qsort_r. This + * is preferred over standard library implementations because they generally + * make no guarantee about being fast for malicious inputs. + * Remember that heapsort is unstable. + * + * In/Out: ptr: pointer to the array to sort. The contents of the array are + * sorted in ascending order according to the comparison function. + * In: count: number of elements in the array. + * size: size in bytes of each element. + * cmp: pointer to a comparison function that is called with two + * arguments that point to the objects being compared. The cmp_data + * argument of rustsecp256k1_v0_11_hsort is passed as third argument. The + * function must return an integer less than, equal to, or greater + * than zero if the first argument is considered to be respectively + * less than, equal to, or greater than the second. + * cmp_data: pointer passed as third argument to cmp. + */ +static void rustsecp256k1_v0_11_hsort(void *ptr, size_t count, size_t size, + int (*cmp)(const void *, const void *, void *), + void *cmp_data); +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/hsort_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/hsort_impl.h new file mode 100644 index 00000000..310ec197 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/hsort_impl.h @@ -0,0 +1,125 @@ +/*********************************************************************** + * Copyright (c) 2021 Russell O'Connor, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_HSORT_IMPL_H +#define SECP256K1_HSORT_IMPL_H + +#include "hsort.h" + +/* An array is a heap when, for all non-zero indexes i, the element at index i + * compares as less than or equal to the element at index parent(i) = (i-1)/2. + */ + +static SECP256K1_INLINE size_t rustsecp256k1_v0_11_heap_child1(size_t i) { + VERIFY_CHECK(i <= (SIZE_MAX - 1)/2); + return 2*i + 1; +} + +static SECP256K1_INLINE size_t rustsecp256k1_v0_11_heap_child2(size_t i) { + VERIFY_CHECK(i <= SIZE_MAX/2 - 1); + return rustsecp256k1_v0_11_heap_child1(i)+1; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_heap_swap64(unsigned char *a, unsigned char *b, size_t len) { + unsigned char tmp[64]; + VERIFY_CHECK(len <= 64); + memcpy(tmp, a, len); + memmove(a, b, len); + memcpy(b, tmp, len); +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_heap_swap(unsigned char *arr, size_t i, size_t j, size_t stride) { + unsigned char *a = arr + i*stride; + unsigned char *b = arr + j*stride; + size_t len = stride; + while (64 < len) { + rustsecp256k1_v0_11_heap_swap64(a + (len - 64), b + (len - 64), 64); + len -= 64; + } + rustsecp256k1_v0_11_heap_swap64(a, b, len); +} + +/* This function accepts an array arr containing heap_size elements, each of + * size stride. The elements in the array at indices >i satisfy the max-heap + * property, i.e., for any element at index j (where j > i), all of its children + * are smaller than the element itself. The purpose of the function is to update + * the array so that all elements at indices >=i satisfy the max-heap + * property. */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_heap_down(unsigned char *arr, size_t i, size_t heap_size, size_t stride, + int (*cmp)(const void *, const void *, void *), void *cmp_data) { + while (i < heap_size/2) { + VERIFY_CHECK(i <= SIZE_MAX/2 - 1); + /* Proof: + * i < heap_size/2 + * i + 1 <= heap_size/2 + * 2*i + 2 <= heap_size <= SIZE_MAX + * 2*i <= SIZE_MAX - 2 + */ + + VERIFY_CHECK(rustsecp256k1_v0_11_heap_child1(i) < heap_size); + /* Proof: + * i < heap_size/2 + * i + 1 <= heap_size/2 + * 2*i + 2 <= heap_size + * 2*i + 1 < heap_size + * child1(i) < heap_size + */ + + /* Let [x] be notation for the contents at arr[x*stride]. + * + * If [child1(i)] > [i] and [child2(i)] > [i], + * swap [i] with the larger child to ensure the new parent is larger + * than both children. When [child1(i)] == [child2(i)], swap [i] with + * [child2(i)]. + * Else if [child1(i)] > [i], swap [i] with [child1(i)]. + * Else if [child2(i)] > [i], swap [i] with [child2(i)]. + */ + if (rustsecp256k1_v0_11_heap_child2(i) < heap_size + && 0 <= cmp(arr + rustsecp256k1_v0_11_heap_child2(i)*stride, arr + rustsecp256k1_v0_11_heap_child1(i)*stride, cmp_data)) { + if (0 < cmp(arr + rustsecp256k1_v0_11_heap_child2(i)*stride, arr + i*stride, cmp_data)) { + rustsecp256k1_v0_11_heap_swap(arr, i, rustsecp256k1_v0_11_heap_child2(i), stride); + i = rustsecp256k1_v0_11_heap_child2(i); + } else { + /* At this point we have [child2(i)] >= [child1(i)] and we have + * [child2(i)] <= [i], and thus [child1(i)] <= [i] which means + * that the next comparison can be skipped. */ + return; + } + } else if (0 < cmp(arr + rustsecp256k1_v0_11_heap_child1(i)*stride, arr + i*stride, cmp_data)) { + rustsecp256k1_v0_11_heap_swap(arr, i, rustsecp256k1_v0_11_heap_child1(i), stride); + i = rustsecp256k1_v0_11_heap_child1(i); + } else { + return; + } + } + /* heap_size/2 <= i + * heap_size/2 < i + 1 + * heap_size < 2*i + 2 + * heap_size <= 2*i + 1 + * heap_size <= child1(i) + * Thus child1(i) and child2(i) are now out of bounds and we are at a leaf. + */ +} + +/* In-place heap sort. */ +static void rustsecp256k1_v0_11_hsort(void *ptr, size_t count, size_t size, + int (*cmp)(const void *, const void *, void *), + void *cmp_data) { + size_t i; + + for (i = count/2; 0 < i; --i) { + rustsecp256k1_v0_11_heap_down(ptr, i-1, count, size, cmp, cmp_data); + } + for (i = count; 1 < i; --i) { + /* Extract the largest value from the heap */ + rustsecp256k1_v0_11_heap_swap(ptr, 0, i-1, size); + + /* Repair the heap condition */ + rustsecp256k1_v0_11_heap_down(ptr, 0, i-1, size, cmp, cmp_data); + } +} + +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128.h new file mode 100644 index 00000000..85d55729 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128.h @@ -0,0 +1,90 @@ +#ifndef SECP256K1_INT128_H +#define SECP256K1_INT128_H + +#include "util.h" + +#if defined(SECP256K1_WIDEMUL_INT128) +# if defined(SECP256K1_INT128_NATIVE) +# include "int128_native.h" +# elif defined(SECP256K1_INT128_STRUCT) +# include "int128_struct.h" +# else +# error "Please select int128 implementation" +# endif + +/* Construct an unsigned 128-bit value from a high and a low 64-bit value. */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_load(rustsecp256k1_v0_11_uint128 *r, uint64_t hi, uint64_t lo); + +/* Multiply two unsigned 64-bit values a and b and write the result to r. */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_mul(rustsecp256k1_v0_11_uint128 *r, uint64_t a, uint64_t b); + +/* Multiply two unsigned 64-bit values a and b and add the result to r. + * The final result is taken modulo 2^128. + */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_accum_mul(rustsecp256k1_v0_11_uint128 *r, uint64_t a, uint64_t b); + +/* Add an unsigned 64-bit value a to r. + * The final result is taken modulo 2^128. + */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_accum_u64(rustsecp256k1_v0_11_uint128 *r, uint64_t a); + +/* Unsigned (logical) right shift. + * Non-constant time in n. + */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_rshift(rustsecp256k1_v0_11_uint128 *r, unsigned int n); + +/* Return the low 64-bits of a 128-bit value as an unsigned 64-bit value. */ +static SECP256K1_INLINE uint64_t rustsecp256k1_v0_11_u128_to_u64(const rustsecp256k1_v0_11_uint128 *a); + +/* Return the high 64-bits of a 128-bit value as an unsigned 64-bit value. */ +static SECP256K1_INLINE uint64_t rustsecp256k1_v0_11_u128_hi_u64(const rustsecp256k1_v0_11_uint128 *a); + +/* Write an unsigned 64-bit value to r. */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_from_u64(rustsecp256k1_v0_11_uint128 *r, uint64_t a); + +/* Tests if r is strictly less than to 2^n. + * n must be strictly less than 128. + */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_u128_check_bits(const rustsecp256k1_v0_11_uint128 *r, unsigned int n); + +/* Construct an signed 128-bit value from a high and a low 64-bit value. */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_load(rustsecp256k1_v0_11_int128 *r, int64_t hi, uint64_t lo); + +/* Multiply two signed 64-bit values a and b and write the result to r. */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_mul(rustsecp256k1_v0_11_int128 *r, int64_t a, int64_t b); + +/* Multiply two signed 64-bit values a and b and add the result to r. + * Overflow or underflow from the addition is undefined behaviour. + */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_accum_mul(rustsecp256k1_v0_11_int128 *r, int64_t a, int64_t b); + +/* Compute a*d - b*c from signed 64-bit values and write the result to r. */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_det(rustsecp256k1_v0_11_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d); + +/* Signed (arithmetic) right shift. + * Non-constant time in b. + */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_rshift(rustsecp256k1_v0_11_int128 *r, unsigned int b); + +/* Return the input value modulo 2^64. */ +static SECP256K1_INLINE uint64_t rustsecp256k1_v0_11_i128_to_u64(const rustsecp256k1_v0_11_int128 *a); + +/* Return the value as a signed 64-bit value. + * Requires the input to be between INT64_MIN and INT64_MAX. + */ +static SECP256K1_INLINE int64_t rustsecp256k1_v0_11_i128_to_i64(const rustsecp256k1_v0_11_int128 *a); + +/* Write a signed 64-bit value to r. */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_from_i64(rustsecp256k1_v0_11_int128 *r, int64_t a); + +/* Compare two 128-bit values for equality. */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_i128_eq_var(const rustsecp256k1_v0_11_int128 *a, const rustsecp256k1_v0_11_int128 *b); + +/* Tests if r is equal to sign*2^n (sign must be 1 or -1). + * n must be strictly less than 127. + */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_i128_check_pow2(const rustsecp256k1_v0_11_int128 *r, unsigned int n, int sign); + +#endif + +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_impl.h new file mode 100644 index 00000000..cfc57340 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_impl.h @@ -0,0 +1,18 @@ +#ifndef SECP256K1_INT128_IMPL_H +#define SECP256K1_INT128_IMPL_H + +#include "util.h" + +#include "int128.h" + +#if defined(SECP256K1_WIDEMUL_INT128) +# if defined(SECP256K1_INT128_NATIVE) +# include "int128_native_impl.h" +# elif defined(SECP256K1_INT128_STRUCT) +# include "int128_struct_impl.h" +# else +# error "Please select int128 implementation" +# endif +#endif + +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_native.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_native.h new file mode 100644 index 00000000..95c6361f --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_native.h @@ -0,0 +1,19 @@ +#ifndef SECP256K1_INT128_NATIVE_H +#define SECP256K1_INT128_NATIVE_H + +#include +#include "util.h" + +#if !defined(UINT128_MAX) && defined(__SIZEOF_INT128__) +SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; +SECP256K1_GNUC_EXT typedef __int128 int128_t; +# define UINT128_MAX ((uint128_t)(-1)) +# define INT128_MAX ((int128_t)(UINT128_MAX >> 1)) +# define INT128_MIN (-INT128_MAX - 1) +/* No (U)INT128_C macros because compilers providing __int128 do not support 128-bit literals. */ +#endif + +typedef uint128_t rustsecp256k1_v0_11_uint128; +typedef int128_t rustsecp256k1_v0_11_int128; + +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_native_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_native_impl.h new file mode 100644 index 00000000..c708a0b6 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_native_impl.h @@ -0,0 +1,94 @@ +#ifndef SECP256K1_INT128_NATIVE_IMPL_H +#define SECP256K1_INT128_NATIVE_IMPL_H + +#include "int128.h" +#include "util.h" + +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_load(rustsecp256k1_v0_11_uint128 *r, uint64_t hi, uint64_t lo) { + *r = (((uint128_t)hi) << 64) + lo; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_mul(rustsecp256k1_v0_11_uint128 *r, uint64_t a, uint64_t b) { + *r = (uint128_t)a * b; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_accum_mul(rustsecp256k1_v0_11_uint128 *r, uint64_t a, uint64_t b) { + *r += (uint128_t)a * b; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_accum_u64(rustsecp256k1_v0_11_uint128 *r, uint64_t a) { + *r += a; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_rshift(rustsecp256k1_v0_11_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + *r >>= n; +} + +static SECP256K1_INLINE uint64_t rustsecp256k1_v0_11_u128_to_u64(const rustsecp256k1_v0_11_uint128 *a) { + return (uint64_t)(*a); +} + +static SECP256K1_INLINE uint64_t rustsecp256k1_v0_11_u128_hi_u64(const rustsecp256k1_v0_11_uint128 *a) { + return (uint64_t)(*a >> 64); +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_from_u64(rustsecp256k1_v0_11_uint128 *r, uint64_t a) { + *r = a; +} + +static SECP256K1_INLINE int rustsecp256k1_v0_11_u128_check_bits(const rustsecp256k1_v0_11_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + return (*r >> n == 0); +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_load(rustsecp256k1_v0_11_int128 *r, int64_t hi, uint64_t lo) { + *r = (((uint128_t)(uint64_t)hi) << 64) + lo; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_mul(rustsecp256k1_v0_11_int128 *r, int64_t a, int64_t b) { + *r = (int128_t)a * b; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_accum_mul(rustsecp256k1_v0_11_int128 *r, int64_t a, int64_t b) { + int128_t ab = (int128_t)a * b; + VERIFY_CHECK(0 <= ab ? *r <= INT128_MAX - ab : INT128_MIN - ab <= *r); + *r += ab; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_det(rustsecp256k1_v0_11_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) { + int128_t ad = (int128_t)a * d; + int128_t bc = (int128_t)b * c; + VERIFY_CHECK(0 <= bc ? INT128_MIN + bc <= ad : ad <= INT128_MAX + bc); + *r = ad - bc; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_rshift(rustsecp256k1_v0_11_int128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + *r >>= n; +} + +static SECP256K1_INLINE uint64_t rustsecp256k1_v0_11_i128_to_u64(const rustsecp256k1_v0_11_int128 *a) { + return (uint64_t)*a; +} + +static SECP256K1_INLINE int64_t rustsecp256k1_v0_11_i128_to_i64(const rustsecp256k1_v0_11_int128 *a) { + VERIFY_CHECK(INT64_MIN <= *a && *a <= INT64_MAX); + return *a; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_from_i64(rustsecp256k1_v0_11_int128 *r, int64_t a) { + *r = a; +} + +static SECP256K1_INLINE int rustsecp256k1_v0_11_i128_eq_var(const rustsecp256k1_v0_11_int128 *a, const rustsecp256k1_v0_11_int128 *b) { + return *a == *b; +} + +static SECP256K1_INLINE int rustsecp256k1_v0_11_i128_check_pow2(const rustsecp256k1_v0_11_int128 *r, unsigned int n, int sign) { + VERIFY_CHECK(n < 127); + VERIFY_CHECK(sign == 1 || sign == -1); + return (*r == (int128_t)((uint128_t)sign << n)); +} + +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_struct.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_struct.h new file mode 100644 index 00000000..d0b7d01c --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_struct.h @@ -0,0 +1,14 @@ +#ifndef SECP256K1_INT128_STRUCT_H +#define SECP256K1_INT128_STRUCT_H + +#include +#include "util.h" + +typedef struct { + uint64_t lo; + uint64_t hi; +} rustsecp256k1_v0_11_uint128; + +typedef rustsecp256k1_v0_11_uint128 rustsecp256k1_v0_11_int128; + +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_struct_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_struct_impl.h new file mode 100644 index 00000000..d89d74e9 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/int128_struct_impl.h @@ -0,0 +1,205 @@ +#ifndef SECP256K1_INT128_STRUCT_IMPL_H +#define SECP256K1_INT128_STRUCT_IMPL_H + +#include "int128.h" +#include "util.h" + +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */ +# include +# if defined(_M_ARM64) || defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE) +/* On ARM64 MSVC, use __(u)mulh for the upper half of 64x64 multiplications. + (Define SECP256K1_MSVC_MULH_TEST_OVERRIDE to test this code path on X64, + which supports both __(u)mulh and _umul128.) */ +# if defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE) +# pragma message(__FILE__ ": SECP256K1_MSVC_MULH_TEST_OVERRIDE is defined, forcing use of __(u)mulh.") +# endif +static SECP256K1_INLINE uint64_t rustsecp256k1_v0_11_umul128(uint64_t a, uint64_t b, uint64_t* hi) { + *hi = __umulh(a, b); + return a * b; +} + +static SECP256K1_INLINE int64_t rustsecp256k1_v0_11_mul128(int64_t a, int64_t b, int64_t* hi) { + *hi = __mulh(a, b); + return (uint64_t)a * (uint64_t)b; +} +# else +/* On x84_64 MSVC, use native _(u)mul128 for 64x64->128 multiplications. */ +# define rustsecp256k1_v0_11_umul128 _umul128 +# define rustsecp256k1_v0_11_mul128 _mul128 +# endif +#else +/* On other systems, emulate 64x64->128 multiplications using 32x32->64 multiplications. */ +static SECP256K1_INLINE uint64_t rustsecp256k1_v0_11_umul128(uint64_t a, uint64_t b, uint64_t* hi) { + uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b; + uint64_t lh = (uint32_t)a * (b >> 32); + uint64_t hl = (a >> 32) * (uint32_t)b; + uint64_t hh = (a >> 32) * (b >> 32); + uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl; + *hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32); + return (mid34 << 32) + (uint32_t)ll; +} + +static SECP256K1_INLINE int64_t rustsecp256k1_v0_11_mul128(int64_t a, int64_t b, int64_t* hi) { + uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b; + int64_t lh = (uint32_t)a * (b >> 32); + int64_t hl = (a >> 32) * (uint32_t)b; + int64_t hh = (a >> 32) * (b >> 32); + uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl; + *hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32); + return (mid34 << 32) + (uint32_t)ll; +} +#endif + +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_load(rustsecp256k1_v0_11_uint128 *r, uint64_t hi, uint64_t lo) { + r->hi = hi; + r->lo = lo; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_mul(rustsecp256k1_v0_11_uint128 *r, uint64_t a, uint64_t b) { + r->lo = rustsecp256k1_v0_11_umul128(a, b, &r->hi); +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_accum_mul(rustsecp256k1_v0_11_uint128 *r, uint64_t a, uint64_t b) { + uint64_t lo, hi; + lo = rustsecp256k1_v0_11_umul128(a, b, &hi); + r->lo += lo; + r->hi += hi + (r->lo < lo); +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_accum_u64(rustsecp256k1_v0_11_uint128 *r, uint64_t a) { + r->lo += a; + r->hi += r->lo < a; +} + +/* Unsigned (logical) right shift. + * Non-constant time in n. + */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_rshift(rustsecp256k1_v0_11_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + if (n >= 64) { + r->lo = r->hi >> (n-64); + r->hi = 0; + } else if (n > 0) { +#if defined(_MSC_VER) && defined(_M_X64) + VERIFY_CHECK(n < 64); + r->lo = __shiftright128(r->lo, r->hi, n); +#else + r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n; +#endif + r->hi >>= n; + } +} + +static SECP256K1_INLINE uint64_t rustsecp256k1_v0_11_u128_to_u64(const rustsecp256k1_v0_11_uint128 *a) { + return a->lo; +} + +static SECP256K1_INLINE uint64_t rustsecp256k1_v0_11_u128_hi_u64(const rustsecp256k1_v0_11_uint128 *a) { + return a->hi; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_u128_from_u64(rustsecp256k1_v0_11_uint128 *r, uint64_t a) { + r->hi = 0; + r->lo = a; +} + +static SECP256K1_INLINE int rustsecp256k1_v0_11_u128_check_bits(const rustsecp256k1_v0_11_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + return n >= 64 ? r->hi >> (n - 64) == 0 + : r->hi == 0 && r->lo >> n == 0; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_load(rustsecp256k1_v0_11_int128 *r, int64_t hi, uint64_t lo) { + r->hi = hi; + r->lo = lo; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_mul(rustsecp256k1_v0_11_int128 *r, int64_t a, int64_t b) { + int64_t hi; + r->lo = (uint64_t)rustsecp256k1_v0_11_mul128(a, b, &hi); + r->hi = (uint64_t)hi; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_accum_mul(rustsecp256k1_v0_11_int128 *r, int64_t a, int64_t b) { + int64_t hi; + uint64_t lo = (uint64_t)rustsecp256k1_v0_11_mul128(a, b, &hi); + r->lo += lo; + hi += r->lo < lo; + /* Verify no overflow. + * If r represents a positive value (the sign bit is not set) and the value we are adding is a positive value (the sign bit is not set), + * then we require that the resulting value also be positive (the sign bit is not set). + * Note that (X <= Y) means (X implies Y) when X and Y are boolean values (i.e. 0 or 1). + */ + VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi <= 0x7fffffffffffffffu)); + /* Verify no underflow. + * If r represents a negative value (the sign bit is set) and the value we are adding is a negative value (the sign bit is set), + * then we require that the resulting value also be negative (the sign bit is set). + */ + VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi > 0x7fffffffffffffffu)); + r->hi += hi; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_dissip_mul(rustsecp256k1_v0_11_int128 *r, int64_t a, int64_t b) { + int64_t hi; + uint64_t lo = (uint64_t)rustsecp256k1_v0_11_mul128(a, b, &hi); + hi += r->lo < lo; + /* Verify no overflow. + * If r represents a positive value (the sign bit is not set) and the value we are subtracting is a negative value (the sign bit is set), + * then we require that the resulting value also be positive (the sign bit is not set). + */ + VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi <= 0x7fffffffffffffffu)); + /* Verify no underflow. + * If r represents a negative value (the sign bit is set) and the value we are subtracting is a positive value (the sign sign bit is not set), + * then we require that the resulting value also be negative (the sign bit is set). + */ + VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi > 0x7fffffffffffffffu)); + r->hi -= hi; + r->lo -= lo; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_det(rustsecp256k1_v0_11_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) { + rustsecp256k1_v0_11_i128_mul(r, a, d); + rustsecp256k1_v0_11_i128_dissip_mul(r, b, c); +} + +/* Signed (arithmetic) right shift. + * Non-constant time in n. + */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_rshift(rustsecp256k1_v0_11_int128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + if (n >= 64) { + r->lo = (uint64_t)((int64_t)(r->hi) >> (n-64)); + r->hi = (uint64_t)((int64_t)(r->hi) >> 63); + } else if (n > 0) { + r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n; + r->hi = (uint64_t)((int64_t)(r->hi) >> n); + } +} + +static SECP256K1_INLINE uint64_t rustsecp256k1_v0_11_i128_to_u64(const rustsecp256k1_v0_11_int128 *a) { + return a->lo; +} + +static SECP256K1_INLINE int64_t rustsecp256k1_v0_11_i128_to_i64(const rustsecp256k1_v0_11_int128 *a) { + /* Verify that a represents a 64 bit signed value by checking that the high bits are a sign extension of the low bits. */ + VERIFY_CHECK(a->hi == -(a->lo >> 63)); + return (int64_t)rustsecp256k1_v0_11_i128_to_u64(a); +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_i128_from_i64(rustsecp256k1_v0_11_int128 *r, int64_t a) { + r->hi = (uint64_t)(a >> 63); + r->lo = (uint64_t)a; +} + +static SECP256K1_INLINE int rustsecp256k1_v0_11_i128_eq_var(const rustsecp256k1_v0_11_int128 *a, const rustsecp256k1_v0_11_int128 *b) { + return a->hi == b->hi && a->lo == b->lo; +} + +static SECP256K1_INLINE int rustsecp256k1_v0_11_i128_check_pow2(const rustsecp256k1_v0_11_int128 *r, unsigned int n, int sign) { + VERIFY_CHECK(n < 127); + VERIFY_CHECK(sign == 1 || sign == -1); + return n >= 64 ? r->hi == (uint64_t)sign << (n - 64) && r->lo == 0 + : r->hi == (uint64_t)(sign >> 1) && r->lo == (uint64_t)sign << n; +} + +#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modinv32.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modinv32.h similarity index 56% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modinv32.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modinv32.h index f5a551cc..269fbe8e 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modinv32.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modinv32.h @@ -7,10 +7,6 @@ #ifndef SECP256K1_MODINV32_H #define SECP256K1_MODINV32_H -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - #include "util.h" /* A signed 30-bit limb representation of integers. @@ -18,15 +14,15 @@ * Its value is sum(v[i] * 2^(30*i), i=0..8). */ typedef struct { int32_t v[9]; -} rustsecp256k1zkp_v0_8_0_modinv32_signed30; +} rustsecp256k1_v0_11_modinv32_signed30; typedef struct { /* The modulus in signed30 notation, must be odd and in [3, 2^256]. */ - rustsecp256k1zkp_v0_8_0_modinv32_signed30 modulus; + rustsecp256k1_v0_11_modinv32_signed30 modulus; /* modulus^{-1} mod 2^30 */ uint32_t modulus_inv30; -} rustsecp256k1zkp_v0_8_0_modinv32_modinfo; +} rustsecp256k1_v0_11_modinv32_modinfo; /* Replace x with its modular inverse mod modinfo->modulus. x must be in range [0, modulus). * If x is zero, the result will be zero as well. If not, the inverse must exist (i.e., the gcd of @@ -34,9 +30,14 @@ typedef struct { * * On output, all of x's limbs will be in [0, 2^30). */ -static void rustsecp256k1zkp_v0_8_0_modinv32_var(rustsecp256k1zkp_v0_8_0_modinv32_signed30 *x, const rustsecp256k1zkp_v0_8_0_modinv32_modinfo *modinfo); +static void rustsecp256k1_v0_11_modinv32_var(rustsecp256k1_v0_11_modinv32_signed30 *x, const rustsecp256k1_v0_11_modinv32_modinfo *modinfo); + +/* Same as rustsecp256k1_v0_11_modinv32_var, but constant time in x (not in the modulus). */ +static void rustsecp256k1_v0_11_modinv32(rustsecp256k1_v0_11_modinv32_signed30 *x, const rustsecp256k1_v0_11_modinv32_modinfo *modinfo); -/* Same as rustsecp256k1zkp_v0_8_0_modinv32_var, but constant time in x (not in the modulus). */ -static void rustsecp256k1zkp_v0_8_0_modinv32(rustsecp256k1zkp_v0_8_0_modinv32_signed30 *x, const rustsecp256k1zkp_v0_8_0_modinv32_modinfo *modinfo); +/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus + * cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result + * cannot be computed. */ +static int rustsecp256k1_v0_11_jacobi32_maybe_var(const rustsecp256k1_v0_11_modinv32_signed30 *x, const rustsecp256k1_v0_11_modinv32_modinfo *modinfo); #endif /* SECP256K1_MODINV32_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modinv32_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modinv32_impl.h similarity index 51% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modinv32_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modinv32_impl.h index a6b3698a..82eaec25 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modinv32_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modinv32_impl.h @@ -21,10 +21,10 @@ */ #ifdef VERIFY -static const rustsecp256k1zkp_v0_8_0_modinv32_signed30 SECP256K1_SIGNED30_ONE = {{1}}; +static const rustsecp256k1_v0_11_modinv32_signed30 SECP256K1_SIGNED30_ONE = {{1}}; /* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^30). */ -static void rustsecp256k1zkp_v0_8_0_modinv32_mul_30(rustsecp256k1zkp_v0_8_0_modinv32_signed30 *r, const rustsecp256k1zkp_v0_8_0_modinv32_signed30 *a, int alen, int32_t factor) { +static void rustsecp256k1_v0_11_modinv32_mul_30(rustsecp256k1_v0_11_modinv32_signed30 *r, const rustsecp256k1_v0_11_modinv32_signed30 *a, int alen, int32_t factor) { const int32_t M30 = (int32_t)(UINT32_MAX >> 2); int64_t c = 0; int i; @@ -38,11 +38,11 @@ static void rustsecp256k1zkp_v0_8_0_modinv32_mul_30(rustsecp256k1zkp_v0_8_0_modi } /* Return -1 for ab*factor. A consists of alen limbs; b has 9. */ -static int rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(const rustsecp256k1zkp_v0_8_0_modinv32_signed30 *a, int alen, const rustsecp256k1zkp_v0_8_0_modinv32_signed30 *b, int32_t factor) { +static int rustsecp256k1_v0_11_modinv32_mul_cmp_30(const rustsecp256k1_v0_11_modinv32_signed30 *a, int alen, const rustsecp256k1_v0_11_modinv32_signed30 *b, int32_t factor) { int i; - rustsecp256k1zkp_v0_8_0_modinv32_signed30 am, bm; - rustsecp256k1zkp_v0_8_0_modinv32_mul_30(&am, a, alen, 1); /* Normalize all but the top limb of a. */ - rustsecp256k1zkp_v0_8_0_modinv32_mul_30(&bm, b, 9, factor); + rustsecp256k1_v0_11_modinv32_signed30 am, bm; + rustsecp256k1_v0_11_modinv32_mul_30(&am, a, alen, 1); /* Normalize all but the top limb of a. */ + rustsecp256k1_v0_11_modinv32_mul_30(&bm, b, 9, factor); for (i = 0; i < 8; ++i) { /* Verify that all but the top limb of a and b are normalized. */ VERIFY_CHECK(am.v[i] >> 30 == 0); @@ -60,11 +60,11 @@ static int rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(const rustsecp256k1zkp_v0 * to it to bring it to range [0,modulus). If sign < 0, the input will also be negated in the * process. The input must have limbs in range (-2^30,2^30). The output will have limbs in range * [0,2^30). */ -static void rustsecp256k1zkp_v0_8_0_modinv32_normalize_30(rustsecp256k1zkp_v0_8_0_modinv32_signed30 *r, int32_t sign, const rustsecp256k1zkp_v0_8_0_modinv32_modinfo *modinfo) { +static void rustsecp256k1_v0_11_modinv32_normalize_30(rustsecp256k1_v0_11_modinv32_signed30 *r, int32_t sign, const rustsecp256k1_v0_11_modinv32_modinfo *modinfo) { const int32_t M30 = (int32_t)(UINT32_MAX >> 2); int32_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4], r5 = r->v[5], r6 = r->v[6], r7 = r->v[7], r8 = r->v[8]; - int32_t cond_add, cond_negate; + volatile int32_t cond_add, cond_negate; #ifdef VERIFY /* Verify that all limbs are in range (-2^30,2^30). */ @@ -73,8 +73,8 @@ static void rustsecp256k1zkp_v0_8_0_modinv32_normalize_30(rustsecp256k1zkp_v0_8_ VERIFY_CHECK(r->v[i] >= -M30); VERIFY_CHECK(r->v[i] <= M30); } - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, -2) > 0); /* r > -2*modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, -2) > 0); /* r > -2*modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */ #endif /* In a first step, add the modulus if the input is negative, and then negate if requested. @@ -144,7 +144,6 @@ static void rustsecp256k1zkp_v0_8_0_modinv32_normalize_30(rustsecp256k1zkp_v0_8_ r->v[7] = r7; r->v[8] = r8; -#ifdef VERIFY VERIFY_CHECK(r0 >> 30 == 0); VERIFY_CHECK(r1 >> 30 == 0); VERIFY_CHECK(r2 >> 30 == 0); @@ -154,9 +153,8 @@ static void rustsecp256k1zkp_v0_8_0_modinv32_normalize_30(rustsecp256k1zkp_v0_8_ VERIFY_CHECK(r6 >> 30 == 0); VERIFY_CHECK(r7 >> 30 == 0); VERIFY_CHECK(r8 >> 30 == 0); - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 0) >= 0); /* r >= 0 */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */ -#endif + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 0) >= 0); /* r >= 0 */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */ } /* Data type for transition matrices (see section 3 of explanation). @@ -166,7 +164,7 @@ static void rustsecp256k1zkp_v0_8_0_modinv32_normalize_30(rustsecp256k1zkp_v0_8_ */ typedef struct { int32_t u, v, q, r; -} rustsecp256k1zkp_v0_8_0_modinv32_trans2x2; +} rustsecp256k1_v0_11_modinv32_trans2x2; /* Compute the transition matrix and zeta for 30 divsteps. * @@ -178,7 +176,7 @@ typedef struct { * * Implements the divsteps_n_matrix function from the explanation. */ -static int32_t rustsecp256k1zkp_v0_8_0_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_t g0, rustsecp256k1zkp_v0_8_0_modinv32_trans2x2 *t) { +static int32_t rustsecp256k1_v0_11_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_t g0, rustsecp256k1_v0_11_modinv32_trans2x2 *t) { /* u,v,q,r are the elements of the transformation matrix being built up, * starting with the identity matrix. Semantically they are signed integers * in range [-2^30,2^30], but here represented as unsigned mod 2^32. This @@ -186,7 +184,8 @@ static int32_t rustsecp256k1zkp_v0_8_0_modinv32_divsteps_30(int32_t zeta, uint32 * being inside [-2^31,2^31) means that casting to signed works correctly. */ uint32_t u = 1, v = 0, q = 0, r = 1; - uint32_t c1, c2, f = f0, g = g0, x, y, z; + volatile uint32_t c1, c2; + uint32_t mask1, mask2, f = f0, g = g0, x, y, z; int i; for (i = 0; i < 30; ++i) { @@ -195,23 +194,25 @@ static int32_t rustsecp256k1zkp_v0_8_0_modinv32_divsteps_30(int32_t zeta, uint32 VERIFY_CHECK((q * f0 + r * g0) == g << i); /* Compute conditional masks for (zeta < 0) and for (g & 1). */ c1 = zeta >> 31; - c2 = -(g & 1); + mask1 = c1; + c2 = g & 1; + mask2 = -c2; /* Compute x,y,z, conditionally negated versions of f,u,v. */ - x = (f ^ c1) - c1; - y = (u ^ c1) - c1; - z = (v ^ c1) - c1; + x = (f ^ mask1) - mask1; + y = (u ^ mask1) - mask1; + z = (v ^ mask1) - mask1; /* Conditionally add x,y,z to g,q,r. */ - g += x & c2; - q += y & c2; - r += z & c2; - /* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */ - c1 &= c2; + g += x & mask2; + q += y & mask2; + r += z & mask2; + /* In what follows, mask1 is a condition mask for (zeta < 0) and (g & 1). */ + mask1 &= mask2; /* Conditionally change zeta into -zeta-2 or zeta-1. */ - zeta = (zeta ^ c1) - 1; + zeta = (zeta ^ mask1) - 1; /* Conditionally add g,q,r to f,u,v. */ - f += g & c1; - u += q & c1; - v += r & c1; + f += g & mask1; + u += q & mask1; + v += r & mask1; /* Shifts */ g >>= 1; u <<= 1; @@ -232,6 +233,21 @@ static int32_t rustsecp256k1zkp_v0_8_0_modinv32_divsteps_30(int32_t zeta, uint32 return zeta; } +/* rustsecp256k1_v0_11_modinv32_inv256[i] = -(2*i+1)^-1 (mod 256) */ +static const uint8_t rustsecp256k1_v0_11_modinv32_inv256[128] = { + 0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59, + 0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31, + 0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89, + 0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61, + 0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9, + 0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91, + 0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9, + 0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1, + 0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19, + 0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1, + 0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01 +}; + /* Compute the transition matrix and eta for 30 divsteps (variable time). * * Input: eta: initial eta @@ -242,23 +258,8 @@ static int32_t rustsecp256k1zkp_v0_8_0_modinv32_divsteps_30(int32_t zeta, uint32 * * Implements the divsteps_n_matrix_var function from the explanation. */ -static int32_t rustsecp256k1zkp_v0_8_0_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, rustsecp256k1zkp_v0_8_0_modinv32_trans2x2 *t) { - /* inv256[i] = -(2*i+1)^-1 (mod 256) */ - static const uint8_t inv256[128] = { - 0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59, - 0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31, - 0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89, - 0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61, - 0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9, - 0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91, - 0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9, - 0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1, - 0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19, - 0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1, - 0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01 - }; - - /* Transformation matrix; see comments in rustsecp256k1zkp_v0_8_0_modinv32_divsteps_30. */ +static int32_t rustsecp256k1_v0_11_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, rustsecp256k1_v0_11_modinv32_trans2x2 *t) { + /* Transformation matrix; see comments in rustsecp256k1_v0_11_modinv32_divsteps_30. */ uint32_t u = 1, v = 0, q = 0, r = 1; uint32_t f = f0, g = g0, m; uint16_t w; @@ -266,7 +267,7 @@ static int32_t rustsecp256k1zkp_v0_8_0_modinv32_divsteps_30_var(int32_t eta, uin for (;;) { /* Use a sentinel bit to count zeros only up to i. */ - zeros = rustsecp256k1zkp_v0_8_0_ctz32_var(g | (UINT32_MAX << i)); + zeros = rustsecp256k1_v0_11_ctz32_var(g | (UINT32_MAX << i)); /* Perform zeros divsteps at once; they all just divide g by two. */ g >>= zeros; u <<= zeros; @@ -297,7 +298,7 @@ static int32_t rustsecp256k1zkp_v0_8_0_modinv32_divsteps_30_var(int32_t eta, uin VERIFY_CHECK(limit > 0 && limit <= 30); m = (UINT32_MAX >> (32 - limit)) & 255U; /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */ - w = (g * inv256[(f >> 1) & 127]) & m; + w = (g * rustsecp256k1_v0_11_modinv32_inv256[(f >> 1) & 127]) & m; /* Do so. */ g += f * w; q += u * w; @@ -317,6 +318,86 @@ static int32_t rustsecp256k1zkp_v0_8_0_modinv32_divsteps_30_var(int32_t eta, uin return eta; } +/* Compute the transition matrix and eta for 30 posdivsteps (variable time, eta=-delta), and keeps track + * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^32 rather than 2^30, because + * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2). + * + * Input: eta: initial eta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign + * by applying the returned transformation matrix to it. The other bits of *jacp may + * change, but are meaningless. + * Return: final eta + */ +static int32_t rustsecp256k1_v0_11_modinv32_posdivsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, rustsecp256k1_v0_11_modinv32_trans2x2 *t, int *jacp) { + /* Transformation matrix. */ + uint32_t u = 1, v = 0, q = 0, r = 1; + uint32_t f = f0, g = g0, m; + uint16_t w; + int i = 30, limit, zeros; + int jac = *jacp; + + for (;;) { + /* Use a sentinel bit to count zeros only up to i. */ + zeros = rustsecp256k1_v0_11_ctz32_var(g | (UINT32_MAX << i)); + /* Perform zeros divsteps at once; they all just divide g by two. */ + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + /* Update the bottom bit of jac: when dividing g by an odd power of 2, + * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */ + jac ^= (zeros & ((f >> 1) ^ (f >> 2))); + /* We're done once we've done 30 posdivsteps. */ + if (i == 0) break; + VERIFY_CHECK((f & 1) == 1); + VERIFY_CHECK((g & 1) == 1); + VERIFY_CHECK((u * f0 + v * g0) == f << (30 - i)); + VERIFY_CHECK((q * f0 + r * g0) == g << (30 - i)); + /* If eta is negative, negate it and replace f,g with g,f. */ + if (eta < 0) { + uint32_t tmp; + eta = -eta; + /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign + * if both f and g are 3 mod 4. */ + jac ^= ((f & g) >> 1); + tmp = f; f = g; g = tmp; + tmp = u; u = q; q = tmp; + tmp = v; v = r; r = tmp; + } + /* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more + * than i can be cancelled out (as we'd be done before that point), and no more than eta+1 + * can be done as its sign will flip once that happens. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + /* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */ + VERIFY_CHECK(limit > 0 && limit <= 30); + m = (UINT32_MAX >> (32 - limit)) & 255U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */ + w = (g * rustsecp256k1_v0_11_modinv32_inv256[(f >> 1) & 127]) & m; + /* Do so. */ + g += f * w; + q += u * w; + r += v * w; + VERIFY_CHECK((g & m) == 0); + } + /* Return data in t and return value. */ + t->u = (int32_t)u; + t->v = (int32_t)v; + t->q = (int32_t)q; + t->r = (int32_t)r; + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2 or -2, + * the aggregate of 30 of them will have determinant 2^30 or -2^30. */ + VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30 || + (int64_t)t->u * t->r - (int64_t)t->v * t->q == -(((int64_t)1) << 30)); + *jacp = jac; + return eta; +} + /* Compute (t/2^30) * [d, e] mod modulus, where t is a transition matrix for 30 divsteps. * * On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range @@ -324,22 +405,19 @@ static int32_t rustsecp256k1zkp_v0_8_0_modinv32_divsteps_30_var(int32_t eta, uin * * This implements the update_de function from the explanation. */ -static void rustsecp256k1zkp_v0_8_0_modinv32_update_de_30(rustsecp256k1zkp_v0_8_0_modinv32_signed30 *d, rustsecp256k1zkp_v0_8_0_modinv32_signed30 *e, const rustsecp256k1zkp_v0_8_0_modinv32_trans2x2 *t, const rustsecp256k1zkp_v0_8_0_modinv32_modinfo* modinfo) { +static void rustsecp256k1_v0_11_modinv32_update_de_30(rustsecp256k1_v0_11_modinv32_signed30 *d, rustsecp256k1_v0_11_modinv32_signed30 *e, const rustsecp256k1_v0_11_modinv32_trans2x2 *t, const rustsecp256k1_v0_11_modinv32_modinfo* modinfo) { const int32_t M30 = (int32_t)(UINT32_MAX >> 2); const int32_t u = t->u, v = t->v, q = t->q, r = t->r; int32_t di, ei, md, me, sd, se; int64_t cd, ce; int i; -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ - VERIFY_CHECK((labs(u) + labs(v)) >= 0); /* |u|+|v| doesn't overflow */ - VERIFY_CHECK((labs(q) + labs(r)) >= 0); /* |q|+|r| doesn't overflow */ - VERIFY_CHECK((labs(u) + labs(v)) <= M30 + 1); /* |u|+|v| <= 2^30 */ - VERIFY_CHECK((labs(q) + labs(r)) <= M30 + 1); /* |q|+|r| <= 2^30 */ -#endif + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ + VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */ + VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */ + /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ sd = d->v[8] >> 31; se = e->v[8] >> 31; @@ -374,19 +452,18 @@ static void rustsecp256k1zkp_v0_8_0_modinv32_update_de_30(rustsecp256k1zkp_v0_8_ /* What remains is limb 9 of t*[d,e]+modulus*[md,me]; store it as output limb 8. */ d->v[8] = (int32_t)cd; e->v[8] = (int32_t)ce; -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ -#endif + + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ } /* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps. * * This implements the update_fg function from the explanation. */ -static void rustsecp256k1zkp_v0_8_0_modinv32_update_fg_30(rustsecp256k1zkp_v0_8_0_modinv32_signed30 *f, rustsecp256k1zkp_v0_8_0_modinv32_signed30 *g, const rustsecp256k1zkp_v0_8_0_modinv32_trans2x2 *t) { +static void rustsecp256k1_v0_11_modinv32_update_fg_30(rustsecp256k1_v0_11_modinv32_signed30 *f, rustsecp256k1_v0_11_modinv32_signed30 *g, const rustsecp256k1_v0_11_modinv32_trans2x2 *t) { const int32_t M30 = (int32_t)(UINT32_MAX >> 2); const int32_t u = t->u, v = t->v, q = t->q, r = t->r; int32_t fi, gi; @@ -421,7 +498,7 @@ static void rustsecp256k1zkp_v0_8_0_modinv32_update_fg_30(rustsecp256k1zkp_v0_8_ * * This implements the update_fg function from the explanation in modinv64_impl.h. */ -static void rustsecp256k1zkp_v0_8_0_modinv32_update_fg_30_var(int len, rustsecp256k1zkp_v0_8_0_modinv32_signed30 *f, rustsecp256k1zkp_v0_8_0_modinv32_signed30 *g, const rustsecp256k1zkp_v0_8_0_modinv32_trans2x2 *t) { +static void rustsecp256k1_v0_11_modinv32_update_fg_30_var(int len, rustsecp256k1_v0_11_modinv32_signed30 *f, rustsecp256k1_v0_11_modinv32_signed30 *g, const rustsecp256k1_v0_11_modinv32_trans2x2 *t) { const int32_t M30 = (int32_t)(UINT32_MAX >> 2); const int32_t u = t->u, v = t->v, q = t->q, r = t->r; int32_t fi, gi; @@ -452,65 +529,61 @@ static void rustsecp256k1zkp_v0_8_0_modinv32_update_fg_30_var(int len, rustsecp2 } /* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */ -static void rustsecp256k1zkp_v0_8_0_modinv32(rustsecp256k1zkp_v0_8_0_modinv32_signed30 *x, const rustsecp256k1zkp_v0_8_0_modinv32_modinfo *modinfo) { +static void rustsecp256k1_v0_11_modinv32(rustsecp256k1_v0_11_modinv32_signed30 *x, const rustsecp256k1_v0_11_modinv32_modinfo *modinfo) { /* Start with d=0, e=1, f=modulus, g=x, zeta=-1. */ - rustsecp256k1zkp_v0_8_0_modinv32_signed30 d = {{0}}; - rustsecp256k1zkp_v0_8_0_modinv32_signed30 e = {{1}}; - rustsecp256k1zkp_v0_8_0_modinv32_signed30 f = modinfo->modulus; - rustsecp256k1zkp_v0_8_0_modinv32_signed30 g = *x; + rustsecp256k1_v0_11_modinv32_signed30 d = {{0}}; + rustsecp256k1_v0_11_modinv32_signed30 e = {{1}}; + rustsecp256k1_v0_11_modinv32_signed30 f = modinfo->modulus; + rustsecp256k1_v0_11_modinv32_signed30 g = *x; int i; int32_t zeta = -1; /* zeta = -(delta+1/2); delta is initially 1/2. */ /* Do 20 iterations of 30 divsteps each = 600 divsteps. 590 suffices for 256-bit inputs. */ for (i = 0; i < 20; ++i) { /* Compute transition matrix and new zeta after 30 divsteps. */ - rustsecp256k1zkp_v0_8_0_modinv32_trans2x2 t; - zeta = rustsecp256k1zkp_v0_8_0_modinv32_divsteps_30(zeta, f.v[0], g.v[0], &t); + rustsecp256k1_v0_11_modinv32_trans2x2 t; + zeta = rustsecp256k1_v0_11_modinv32_divsteps_30(zeta, f.v[0], g.v[0], &t); /* Update d,e using that transition matrix. */ - rustsecp256k1zkp_v0_8_0_modinv32_update_de_30(&d, &e, &t, modinfo); + rustsecp256k1_v0_11_modinv32_update_de_30(&d, &e, &t, modinfo); /* Update f,g using that transition matrix. */ -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif - rustsecp256k1zkp_v0_8_0_modinv32_update_fg_30(&f, &g, &t); -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */ + + rustsecp256k1_v0_11_modinv32_update_fg_30(&f, &g, &t); + + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */ } /* At this point sufficient iterations have been performed that g must have reached 0 * and (if g was not originally 0) f must now equal +/- GCD of the initial f, g * values i.e. +/- 1, and d now contains +/- the modular inverse. */ -#ifdef VERIFY + /* g == 0 */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&g, 9, &SECP256K1_SIGNED30_ONE, 0) == 0); - /* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, -1) == 0 || - rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, 1) == 0 || - (rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && - rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && - (rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) == 0 || - rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) == 0))); -#endif + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&g, 9, &SECP256K1_SIGNED30_ONE, 0) == 0); + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, -1) == 0 || + rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, 1) == 0 || + (rustsecp256k1_v0_11_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && + rustsecp256k1_v0_11_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && + rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) == 0)); /* Optionally negate d, normalize to [0,modulus), and return it. */ - rustsecp256k1zkp_v0_8_0_modinv32_normalize_30(&d, f.v[8], modinfo); + rustsecp256k1_v0_11_modinv32_normalize_30(&d, f.v[8], modinfo); *x = d; } /* Compute the inverse of x modulo modinfo->modulus, and replace x with it (variable time). */ -static void rustsecp256k1zkp_v0_8_0_modinv32_var(rustsecp256k1zkp_v0_8_0_modinv32_signed30 *x, const rustsecp256k1zkp_v0_8_0_modinv32_modinfo *modinfo) { +static void rustsecp256k1_v0_11_modinv32_var(rustsecp256k1_v0_11_modinv32_signed30 *x, const rustsecp256k1_v0_11_modinv32_modinfo *modinfo) { /* Start with d=0, e=1, f=modulus, g=x, eta=-1. */ - rustsecp256k1zkp_v0_8_0_modinv32_signed30 d = {{0, 0, 0, 0, 0, 0, 0, 0, 0}}; - rustsecp256k1zkp_v0_8_0_modinv32_signed30 e = {{1, 0, 0, 0, 0, 0, 0, 0, 0}}; - rustsecp256k1zkp_v0_8_0_modinv32_signed30 f = modinfo->modulus; - rustsecp256k1zkp_v0_8_0_modinv32_signed30 g = *x; + rustsecp256k1_v0_11_modinv32_signed30 d = {{0, 0, 0, 0, 0, 0, 0, 0, 0}}; + rustsecp256k1_v0_11_modinv32_signed30 e = {{1, 0, 0, 0, 0, 0, 0, 0, 0}}; + rustsecp256k1_v0_11_modinv32_signed30 f = modinfo->modulus; + rustsecp256k1_v0_11_modinv32_signed30 g = *x; #ifdef VERIFY int i = 0; #endif @@ -521,18 +594,18 @@ static void rustsecp256k1zkp_v0_8_0_modinv32_var(rustsecp256k1zkp_v0_8_0_modinv3 /* Do iterations of 30 divsteps each until g=0. */ while (1) { /* Compute transition matrix and new eta after 30 divsteps. */ - rustsecp256k1zkp_v0_8_0_modinv32_trans2x2 t; - eta = rustsecp256k1zkp_v0_8_0_modinv32_divsteps_30_var(eta, f.v[0], g.v[0], &t); + rustsecp256k1_v0_11_modinv32_trans2x2 t; + eta = rustsecp256k1_v0_11_modinv32_divsteps_30_var(eta, f.v[0], g.v[0], &t); /* Update d,e using that transition matrix. */ - rustsecp256k1zkp_v0_8_0_modinv32_update_de_30(&d, &e, &t, modinfo); + rustsecp256k1_v0_11_modinv32_update_de_30(&d, &e, &t, modinfo); /* Update f,g using that transition matrix. */ -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif - rustsecp256k1zkp_v0_8_0_modinv32_update_fg_30_var(len, &f, &g, &t); + + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + + rustsecp256k1_v0_11_modinv32_update_fg_30_var(len, &f, &g, &t); /* If the bottom limb of g is 0, there is a chance g=0. */ if (g.v[0] == 0) { cond = 0; @@ -556,32 +629,97 @@ static void rustsecp256k1zkp_v0_8_0_modinv32_var(rustsecp256k1zkp_v0_8_0_modinv3 g.v[len - 2] |= (uint32_t)gn << 30; --len; } -#ifdef VERIFY + VERIFY_CHECK(++i < 25); /* We should never need more than 25*30 = 750 divsteps */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ } /* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of * the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */ -#ifdef VERIFY + /* g == 0 */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&g, len, &SECP256K1_SIGNED30_ONE, 0) == 0); - /* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */ - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, -1) == 0 || - rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, 1) == 0 || - (rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && - rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && - (rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) == 0 || - rustsecp256k1zkp_v0_8_0_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) == 0))); -#endif + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&g, len, &SECP256K1_SIGNED30_ONE, 0) == 0); + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, -1) == 0 || + rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, 1) == 0 || + (rustsecp256k1_v0_11_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && + rustsecp256k1_v0_11_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && + rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) == 0)); /* Optionally negate d, normalize to [0,modulus), and return it. */ - rustsecp256k1zkp_v0_8_0_modinv32_normalize_30(&d, f.v[len - 1], modinfo); + rustsecp256k1_v0_11_modinv32_normalize_30(&d, f.v[len - 1], modinfo); *x = d; } +/* Do up to 50 iterations of 30 posdivsteps (up to 1500 steps; more is extremely rare) each until f=1. + * In VERIFY mode use a lower number of iterations (750, close to the median 756), so failure actually occurs. */ +#ifdef VERIFY +#define JACOBI32_ITERATIONS 25 +#else +#define JACOBI32_ITERATIONS 50 +#endif + +/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */ +static int rustsecp256k1_v0_11_jacobi32_maybe_var(const rustsecp256k1_v0_11_modinv32_signed30 *x, const rustsecp256k1_v0_11_modinv32_modinfo *modinfo) { + /* Start with f=modulus, g=x, eta=-1. */ + rustsecp256k1_v0_11_modinv32_signed30 f = modinfo->modulus; + rustsecp256k1_v0_11_modinv32_signed30 g = *x; + int j, len = 9; + int32_t eta = -1; /* eta = -delta; delta is initially 1 */ + int32_t cond, fn, gn; + int jac = 0; + int count; + + /* The input limbs must all be non-negative. */ + VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0 && g.v[5] >= 0 && g.v[6] >= 0 && g.v[7] >= 0 && g.v[8] >= 0); + + /* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we + * require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or + * time out). */ + VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4] | g.v[5] | g.v[6] | g.v[7] | g.v[8]) != 0); + + for (count = 0; count < JACOBI32_ITERATIONS; ++count) { + /* Compute transition matrix and new eta after 30 posdivsteps. */ + rustsecp256k1_v0_11_modinv32_trans2x2 t; + eta = rustsecp256k1_v0_11_modinv32_posdivsteps_30_var(eta, f.v[0] | ((uint32_t)f.v[1] << 30), g.v[0] | ((uint32_t)g.v[1] << 30), &t, &jac); + /* Update f,g using that transition matrix. */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + + rustsecp256k1_v0_11_modinv32_update_fg_30_var(len, &f, &g, &t); + /* If the bottom limb of f is 1, there is a chance that f=1. */ + if (f.v[0] == 1) { + cond = 0; + /* Check if the other limbs are also 0. */ + for (j = 1; j < len; ++j) { + cond |= f.v[j]; + } + /* If so, we're done. If f=1, the Jacobi symbol (g | f)=1. */ + if (cond == 0) return 1 - 2*(jac & 1); + } + + /* Determine if len>1 and limb (len-1) of both f and g is 0. */ + fn = f.v[len - 1]; + gn = g.v[len - 1]; + cond = ((int32_t)len - 2) >> 31; + cond |= fn; + cond |= gn; + /* If so, reduce length. */ + if (cond == 0) --len; + + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* The loop failed to converge to f=g after 1500 iterations. Return 0, indicating unknown result. */ + return 0; +} + #endif /* SECP256K1_MODINV32_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modinv64.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modinv64.h similarity index 58% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modinv64.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modinv64.h index b947ef8e..8ecb3835 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modinv64.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modinv64.h @@ -7,10 +7,6 @@ #ifndef SECP256K1_MODINV64_H #define SECP256K1_MODINV64_H -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - #include "util.h" #ifndef SECP256K1_WIDEMUL_INT128 @@ -22,15 +18,15 @@ * Its value is sum(v[i] * 2^(62*i), i=0..4). */ typedef struct { int64_t v[5]; -} rustsecp256k1zkp_v0_8_0_modinv64_signed62; +} rustsecp256k1_v0_11_modinv64_signed62; typedef struct { /* The modulus in signed62 notation, must be odd and in [3, 2^256]. */ - rustsecp256k1zkp_v0_8_0_modinv64_signed62 modulus; + rustsecp256k1_v0_11_modinv64_signed62 modulus; /* modulus^{-1} mod 2^62 */ uint64_t modulus_inv62; -} rustsecp256k1zkp_v0_8_0_modinv64_modinfo; +} rustsecp256k1_v0_11_modinv64_modinfo; /* Replace x with its modular inverse mod modinfo->modulus. x must be in range [0, modulus). * If x is zero, the result will be zero as well. If not, the inverse must exist (i.e., the gcd of @@ -38,9 +34,14 @@ typedef struct { * * On output, all of x's limbs will be in [0, 2^62). */ -static void rustsecp256k1zkp_v0_8_0_modinv64_var(rustsecp256k1zkp_v0_8_0_modinv64_signed62 *x, const rustsecp256k1zkp_v0_8_0_modinv64_modinfo *modinfo); +static void rustsecp256k1_v0_11_modinv64_var(rustsecp256k1_v0_11_modinv64_signed62 *x, const rustsecp256k1_v0_11_modinv64_modinfo *modinfo); + +/* Same as rustsecp256k1_v0_11_modinv64_var, but constant time in x (not in the modulus). */ +static void rustsecp256k1_v0_11_modinv64(rustsecp256k1_v0_11_modinv64_signed62 *x, const rustsecp256k1_v0_11_modinv64_modinfo *modinfo); -/* Same as rustsecp256k1zkp_v0_8_0_modinv64_var, but constant time in x (not in the modulus). */ -static void rustsecp256k1zkp_v0_8_0_modinv64(rustsecp256k1zkp_v0_8_0_modinv64_signed62 *x, const rustsecp256k1zkp_v0_8_0_modinv64_modinfo *modinfo); +/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus + * cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result + * cannot be computed. */ +static int rustsecp256k1_v0_11_jacobi64_maybe_var(const rustsecp256k1_v0_11_modinv64_signed62 *x, const rustsecp256k1_v0_11_modinv64_modinfo *modinfo); #endif /* SECP256K1_MODINV64_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modinv64_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modinv64_impl.h new file mode 100644 index 00000000..723cbc49 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modinv64_impl.h @@ -0,0 +1,780 @@ +/*********************************************************************** + * Copyright (c) 2020 Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODINV64_IMPL_H +#define SECP256K1_MODINV64_IMPL_H + +#include "int128.h" +#include "modinv64.h" + +/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and + * modular inversion" by Daniel J. Bernstein and Bo-Yin Yang. + * + * For an explanation of the algorithm, see doc/safegcd_implementation.md. This file contains an + * implementation for N=62, using 62-bit signed limbs represented as int64_t. + */ + +/* Data type for transition matrices (see section 3 of explanation). + * + * t = [ u v ] + * [ q r ] + */ +typedef struct { + int64_t u, v, q, r; +} rustsecp256k1_v0_11_modinv64_trans2x2; + +#ifdef VERIFY +/* Helper function to compute the absolute value of an int64_t. + * (we don't use abs/labs/llabs as it depends on the int sizes). */ +static int64_t rustsecp256k1_v0_11_modinv64_abs(int64_t v) { + VERIFY_CHECK(v > INT64_MIN); + if (v < 0) return -v; + return v; +} + +static const rustsecp256k1_v0_11_modinv64_signed62 SECP256K1_SIGNED62_ONE = {{1}}; + +/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^62). */ +static void rustsecp256k1_v0_11_modinv64_mul_62(rustsecp256k1_v0_11_modinv64_signed62 *r, const rustsecp256k1_v0_11_modinv64_signed62 *a, int alen, int64_t factor) { + const uint64_t M62 = UINT64_MAX >> 2; + rustsecp256k1_v0_11_int128 c, d; + int i; + rustsecp256k1_v0_11_i128_from_i64(&c, 0); + for (i = 0; i < 4; ++i) { + if (i < alen) rustsecp256k1_v0_11_i128_accum_mul(&c, a->v[i], factor); + r->v[i] = rustsecp256k1_v0_11_i128_to_u64(&c) & M62; rustsecp256k1_v0_11_i128_rshift(&c, 62); + } + if (4 < alen) rustsecp256k1_v0_11_i128_accum_mul(&c, a->v[4], factor); + rustsecp256k1_v0_11_i128_from_i64(&d, rustsecp256k1_v0_11_i128_to_i64(&c)); + VERIFY_CHECK(rustsecp256k1_v0_11_i128_eq_var(&c, &d)); + r->v[4] = rustsecp256k1_v0_11_i128_to_i64(&c); +} + +/* Return -1 for ab*factor. A has alen limbs; b has 5. */ +static int rustsecp256k1_v0_11_modinv64_mul_cmp_62(const rustsecp256k1_v0_11_modinv64_signed62 *a, int alen, const rustsecp256k1_v0_11_modinv64_signed62 *b, int64_t factor) { + int i; + rustsecp256k1_v0_11_modinv64_signed62 am, bm; + rustsecp256k1_v0_11_modinv64_mul_62(&am, a, alen, 1); /* Normalize all but the top limb of a. */ + rustsecp256k1_v0_11_modinv64_mul_62(&bm, b, 5, factor); + for (i = 0; i < 4; ++i) { + /* Verify that all but the top limb of a and b are normalized. */ + VERIFY_CHECK(am.v[i] >> 62 == 0); + VERIFY_CHECK(bm.v[i] >> 62 == 0); + } + for (i = 4; i >= 0; --i) { + if (am.v[i] < bm.v[i]) return -1; + if (am.v[i] > bm.v[i]) return 1; + } + return 0; +} + +/* Check if the determinant of t is equal to 1 << n. If abs, check if |det t| == 1 << n. */ +static int rustsecp256k1_v0_11_modinv64_det_check_pow2(const rustsecp256k1_v0_11_modinv64_trans2x2 *t, unsigned int n, int abs) { + rustsecp256k1_v0_11_int128 a; + rustsecp256k1_v0_11_i128_det(&a, t->u, t->v, t->q, t->r); + if (rustsecp256k1_v0_11_i128_check_pow2(&a, n, 1)) return 1; + if (abs && rustsecp256k1_v0_11_i128_check_pow2(&a, n, -1)) return 1; + return 0; +} +#endif + +/* Take as input a signed62 number in range (-2*modulus,modulus), and add a multiple of the modulus + * to it to bring it to range [0,modulus). If sign < 0, the input will also be negated in the + * process. The input must have limbs in range (-2^62,2^62). The output will have limbs in range + * [0,2^62). */ +static void rustsecp256k1_v0_11_modinv64_normalize_62(rustsecp256k1_v0_11_modinv64_signed62 *r, int64_t sign, const rustsecp256k1_v0_11_modinv64_modinfo *modinfo) { + const int64_t M62 = (int64_t)(UINT64_MAX >> 2); + int64_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4]; + volatile int64_t cond_add, cond_negate; + +#ifdef VERIFY + /* Verify that all limbs are in range (-2^62,2^62). */ + int i; + for (i = 0; i < 5; ++i) { + VERIFY_CHECK(r->v[i] >= -M62); + VERIFY_CHECK(r->v[i] <= M62); + } + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, -2) > 0); /* r > -2*modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */ +#endif + + /* In a first step, add the modulus if the input is negative, and then negate if requested. + * This brings r from range (-2*modulus,modulus) to range (-modulus,modulus). As all input + * limbs are in range (-2^62,2^62), this cannot overflow an int64_t. Note that the right + * shifts below are signed sign-extending shifts (see assumptions.h for tests that that is + * indeed the behavior of the right shift operator). */ + cond_add = r4 >> 63; + r0 += modinfo->modulus.v[0] & cond_add; + r1 += modinfo->modulus.v[1] & cond_add; + r2 += modinfo->modulus.v[2] & cond_add; + r3 += modinfo->modulus.v[3] & cond_add; + r4 += modinfo->modulus.v[4] & cond_add; + cond_negate = sign >> 63; + r0 = (r0 ^ cond_negate) - cond_negate; + r1 = (r1 ^ cond_negate) - cond_negate; + r2 = (r2 ^ cond_negate) - cond_negate; + r3 = (r3 ^ cond_negate) - cond_negate; + r4 = (r4 ^ cond_negate) - cond_negate; + /* Propagate the top bits, to bring limbs back to range (-2^62,2^62). */ + r1 += r0 >> 62; r0 &= M62; + r2 += r1 >> 62; r1 &= M62; + r3 += r2 >> 62; r2 &= M62; + r4 += r3 >> 62; r3 &= M62; + + /* In a second step add the modulus again if the result is still negative, bringing + * r to range [0,modulus). */ + cond_add = r4 >> 63; + r0 += modinfo->modulus.v[0] & cond_add; + r1 += modinfo->modulus.v[1] & cond_add; + r2 += modinfo->modulus.v[2] & cond_add; + r3 += modinfo->modulus.v[3] & cond_add; + r4 += modinfo->modulus.v[4] & cond_add; + /* And propagate again. */ + r1 += r0 >> 62; r0 &= M62; + r2 += r1 >> 62; r1 &= M62; + r3 += r2 >> 62; r2 &= M62; + r4 += r3 >> 62; r3 &= M62; + + r->v[0] = r0; + r->v[1] = r1; + r->v[2] = r2; + r->v[3] = r3; + r->v[4] = r4; + + VERIFY_CHECK(r0 >> 62 == 0); + VERIFY_CHECK(r1 >> 62 == 0); + VERIFY_CHECK(r2 >> 62 == 0); + VERIFY_CHECK(r3 >> 62 == 0); + VERIFY_CHECK(r4 >> 62 == 0); + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 0) >= 0); /* r >= 0 */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */ +} + +/* Compute the transition matrix and eta for 59 divsteps (where zeta=-(delta+1/2)). + * Note that the transformation matrix is scaled by 2^62 and not 2^59. + * + * Input: zeta: initial zeta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Return: final zeta + * + * Implements the divsteps_n_matrix function from the explanation. + */ +static int64_t rustsecp256k1_v0_11_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_t g0, rustsecp256k1_v0_11_modinv64_trans2x2 *t) { + /* u,v,q,r are the elements of the transformation matrix being built up, + * starting with the identity matrix times 8 (because the caller expects + * a result scaled by 2^62). Semantically they are signed integers + * in range [-2^62,2^62], but here represented as unsigned mod 2^64. This + * permits left shifting (which is UB for negative numbers). The range + * being inside [-2^63,2^63) means that casting to signed works correctly. + */ + uint64_t u = 8, v = 0, q = 0, r = 8; + volatile uint64_t c1, c2; + uint64_t mask1, mask2, f = f0, g = g0, x, y, z; + int i; + + for (i = 3; i < 62; ++i) { + VERIFY_CHECK((f & 1) == 1); /* f must always be odd */ + VERIFY_CHECK((u * f0 + v * g0) == f << i); + VERIFY_CHECK((q * f0 + r * g0) == g << i); + /* Compute conditional masks for (zeta < 0) and for (g & 1). */ + c1 = zeta >> 63; + mask1 = c1; + c2 = g & 1; + mask2 = -c2; + /* Compute x,y,z, conditionally negated versions of f,u,v. */ + x = (f ^ mask1) - mask1; + y = (u ^ mask1) - mask1; + z = (v ^ mask1) - mask1; + /* Conditionally add x,y,z to g,q,r. */ + g += x & mask2; + q += y & mask2; + r += z & mask2; + /* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */ + mask1 &= mask2; + /* Conditionally change zeta into -zeta-2 or zeta-1. */ + zeta = (zeta ^ mask1) - 1; + /* Conditionally add g,q,r to f,u,v. */ + f += g & mask1; + u += q & mask1; + v += r & mask1; + /* Shifts */ + g >>= 1; + u <<= 1; + v <<= 1; + /* Bounds on zeta that follow from the bounds on iteration count (max 10*59 divsteps). */ + VERIFY_CHECK(zeta >= -591 && zeta <= 591); + } + /* Return data in t and return value. */ + t->u = (int64_t)u; + t->v = (int64_t)v; + t->q = (int64_t)q; + t->r = (int64_t)r; + + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2, the + * aggregate of 59 of them will have determinant 2^59. Multiplying with the initial + * 8*identity (which has determinant 2^6) means the overall outputs has determinant + * 2^65. */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_det_check_pow2(t, 65, 0)); + + return zeta; +} + +/* Compute the transition matrix and eta for 62 divsteps (variable time, eta=-delta). + * + * Input: eta: initial eta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Return: final eta + * + * Implements the divsteps_n_matrix_var function from the explanation. + */ +static int64_t rustsecp256k1_v0_11_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, rustsecp256k1_v0_11_modinv64_trans2x2 *t) { + /* Transformation matrix; see comments in rustsecp256k1_v0_11_modinv64_divsteps_62. */ + uint64_t u = 1, v = 0, q = 0, r = 1; + uint64_t f = f0, g = g0, m; + uint32_t w; + int i = 62, limit, zeros; + + for (;;) { + /* Use a sentinel bit to count zeros only up to i. */ + zeros = rustsecp256k1_v0_11_ctz64_var(g | (UINT64_MAX << i)); + /* Perform zeros divsteps at once; they all just divide g by two. */ + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + /* We're done once we've done 62 divsteps. */ + if (i == 0) break; + VERIFY_CHECK((f & 1) == 1); + VERIFY_CHECK((g & 1) == 1); + VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i)); + VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i)); + /* Bounds on eta that follow from the bounds on iteration count (max 12*62 divsteps). */ + VERIFY_CHECK(eta >= -745 && eta <= 745); + /* If eta is negative, negate it and replace f,g with g,-f. */ + if (eta < 0) { + uint64_t tmp; + eta = -eta; + tmp = f; f = g; g = -tmp; + tmp = u; u = q; q = -tmp; + tmp = v; v = r; r = -tmp; + /* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled + * out (as we'd be done before that point), and no more than eta+1 can be done as its + * sign will flip again once that happens. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + VERIFY_CHECK(limit > 0 && limit <= 62); + /* m is a mask for the bottom min(limit, 6) bits. */ + m = (UINT64_MAX >> (64 - limit)) & 63U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 6) + * bits. */ + w = (f * g * (f * f - 2)) & m; + } else { + /* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as + * eta tends to be smaller here. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + VERIFY_CHECK(limit > 0 && limit <= 62); + /* m is a mask for the bottom min(limit, 4) bits. */ + m = (UINT64_MAX >> (64 - limit)) & 15U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 4) + * bits. */ + w = f + (((f + 1) & 4) << 1); + w = (-w * g) & m; + } + g += f * w; + q += u * w; + r += v * w; + VERIFY_CHECK((g & m) == 0); + } + /* Return data in t and return value. */ + t->u = (int64_t)u; + t->v = (int64_t)v; + t->q = (int64_t)q; + t->r = (int64_t)r; + + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2, the + * aggregate of 62 of them will have determinant 2^62. */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_det_check_pow2(t, 62, 0)); + + return eta; +} + +/* Compute the transition matrix and eta for 62 posdivsteps (variable time, eta=-delta), and keeps track + * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^64 rather than 2^62, because + * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2). + * + * Input: eta: initial eta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign + * by applying the returned transformation matrix to it. The other bits of *jacp may + * change, but are meaningless. + * Return: final eta + */ +static int64_t rustsecp256k1_v0_11_modinv64_posdivsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, rustsecp256k1_v0_11_modinv64_trans2x2 *t, int *jacp) { + /* Transformation matrix; see comments in rustsecp256k1_v0_11_modinv64_divsteps_62. */ + uint64_t u = 1, v = 0, q = 0, r = 1; + uint64_t f = f0, g = g0, m; + uint32_t w; + int i = 62, limit, zeros; + int jac = *jacp; + + for (;;) { + /* Use a sentinel bit to count zeros only up to i. */ + zeros = rustsecp256k1_v0_11_ctz64_var(g | (UINT64_MAX << i)); + /* Perform zeros divsteps at once; they all just divide g by two. */ + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + /* Update the bottom bit of jac: when dividing g by an odd power of 2, + * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */ + jac ^= (zeros & ((f >> 1) ^ (f >> 2))); + /* We're done once we've done 62 posdivsteps. */ + if (i == 0) break; + VERIFY_CHECK((f & 1) == 1); + VERIFY_CHECK((g & 1) == 1); + VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i)); + VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i)); + /* If eta is negative, negate it and replace f,g with g,f. */ + if (eta < 0) { + uint64_t tmp; + eta = -eta; + tmp = f; f = g; g = tmp; + tmp = u; u = q; q = tmp; + tmp = v; v = r; r = tmp; + /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign + * if both f and g are 3 mod 4. */ + jac ^= ((f & g) >> 1); + /* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled + * out (as we'd be done before that point), and no more than eta+1 can be done as its + * sign will flip again once that happens. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + VERIFY_CHECK(limit > 0 && limit <= 62); + /* m is a mask for the bottom min(limit, 6) bits. */ + m = (UINT64_MAX >> (64 - limit)) & 63U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 6) + * bits. */ + w = (f * g * (f * f - 2)) & m; + } else { + /* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as + * eta tends to be smaller here. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + VERIFY_CHECK(limit > 0 && limit <= 62); + /* m is a mask for the bottom min(limit, 4) bits. */ + m = (UINT64_MAX >> (64 - limit)) & 15U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 4) + * bits. */ + w = f + (((f + 1) & 4) << 1); + w = (-w * g) & m; + } + g += f * w; + q += u * w; + r += v * w; + VERIFY_CHECK((g & m) == 0); + } + /* Return data in t and return value. */ + t->u = (int64_t)u; + t->v = (int64_t)v; + t->q = (int64_t)q; + t->r = (int64_t)r; + + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2 or -2, + * the aggregate of 62 of them will have determinant 2^62 or -2^62. */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_det_check_pow2(t, 62, 1)); + + *jacp = jac; + return eta; +} + +/* Compute (t/2^62) * [d, e] mod modulus, where t is a transition matrix scaled by 2^62. + * + * On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range + * (-2^62,2^62). + * + * This implements the update_de function from the explanation. + */ +static void rustsecp256k1_v0_11_modinv64_update_de_62(rustsecp256k1_v0_11_modinv64_signed62 *d, rustsecp256k1_v0_11_modinv64_signed62 *e, const rustsecp256k1_v0_11_modinv64_trans2x2 *t, const rustsecp256k1_v0_11_modinv64_modinfo* modinfo) { + const uint64_t M62 = UINT64_MAX >> 2; + const int64_t d0 = d->v[0], d1 = d->v[1], d2 = d->v[2], d3 = d->v[3], d4 = d->v[4]; + const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4]; + const int64_t u = t->u, v = t->v, q = t->q, r = t->r; + int64_t md, me, sd, se; + rustsecp256k1_v0_11_int128 cd, ce; + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_abs(u) <= (((int64_t)1 << 62) - rustsecp256k1_v0_11_modinv64_abs(v))); /* |u|+|v| <= 2^62 */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_abs(q) <= (((int64_t)1 << 62) - rustsecp256k1_v0_11_modinv64_abs(r))); /* |q|+|r| <= 2^62 */ + + /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ + sd = d4 >> 63; + se = e4 >> 63; + md = (u & sd) + (v & se); + me = (q & sd) + (r & se); + /* Begin computing t*[d,e]. */ + rustsecp256k1_v0_11_i128_mul(&cd, u, d0); + rustsecp256k1_v0_11_i128_accum_mul(&cd, v, e0); + rustsecp256k1_v0_11_i128_mul(&ce, q, d0); + rustsecp256k1_v0_11_i128_accum_mul(&ce, r, e0); + /* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */ + md -= (modinfo->modulus_inv62 * rustsecp256k1_v0_11_i128_to_u64(&cd) + md) & M62; + me -= (modinfo->modulus_inv62 * rustsecp256k1_v0_11_i128_to_u64(&ce) + me) & M62; + /* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */ + rustsecp256k1_v0_11_i128_accum_mul(&cd, modinfo->modulus.v[0], md); + rustsecp256k1_v0_11_i128_accum_mul(&ce, modinfo->modulus.v[0], me); + /* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */ + VERIFY_CHECK((rustsecp256k1_v0_11_i128_to_u64(&cd) & M62) == 0); rustsecp256k1_v0_11_i128_rshift(&cd, 62); + VERIFY_CHECK((rustsecp256k1_v0_11_i128_to_u64(&ce) & M62) == 0); rustsecp256k1_v0_11_i128_rshift(&ce, 62); + /* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */ + rustsecp256k1_v0_11_i128_accum_mul(&cd, u, d1); + rustsecp256k1_v0_11_i128_accum_mul(&cd, v, e1); + rustsecp256k1_v0_11_i128_accum_mul(&ce, q, d1); + rustsecp256k1_v0_11_i128_accum_mul(&ce, r, e1); + if (modinfo->modulus.v[1]) { /* Optimize for the case where limb of modulus is zero. */ + rustsecp256k1_v0_11_i128_accum_mul(&cd, modinfo->modulus.v[1], md); + rustsecp256k1_v0_11_i128_accum_mul(&ce, modinfo->modulus.v[1], me); + } + d->v[0] = rustsecp256k1_v0_11_i128_to_u64(&cd) & M62; rustsecp256k1_v0_11_i128_rshift(&cd, 62); + e->v[0] = rustsecp256k1_v0_11_i128_to_u64(&ce) & M62; rustsecp256k1_v0_11_i128_rshift(&ce, 62); + /* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */ + rustsecp256k1_v0_11_i128_accum_mul(&cd, u, d2); + rustsecp256k1_v0_11_i128_accum_mul(&cd, v, e2); + rustsecp256k1_v0_11_i128_accum_mul(&ce, q, d2); + rustsecp256k1_v0_11_i128_accum_mul(&ce, r, e2); + if (modinfo->modulus.v[2]) { /* Optimize for the case where limb of modulus is zero. */ + rustsecp256k1_v0_11_i128_accum_mul(&cd, modinfo->modulus.v[2], md); + rustsecp256k1_v0_11_i128_accum_mul(&ce, modinfo->modulus.v[2], me); + } + d->v[1] = rustsecp256k1_v0_11_i128_to_u64(&cd) & M62; rustsecp256k1_v0_11_i128_rshift(&cd, 62); + e->v[1] = rustsecp256k1_v0_11_i128_to_u64(&ce) & M62; rustsecp256k1_v0_11_i128_rshift(&ce, 62); + /* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */ + rustsecp256k1_v0_11_i128_accum_mul(&cd, u, d3); + rustsecp256k1_v0_11_i128_accum_mul(&cd, v, e3); + rustsecp256k1_v0_11_i128_accum_mul(&ce, q, d3); + rustsecp256k1_v0_11_i128_accum_mul(&ce, r, e3); + if (modinfo->modulus.v[3]) { /* Optimize for the case where limb of modulus is zero. */ + rustsecp256k1_v0_11_i128_accum_mul(&cd, modinfo->modulus.v[3], md); + rustsecp256k1_v0_11_i128_accum_mul(&ce, modinfo->modulus.v[3], me); + } + d->v[2] = rustsecp256k1_v0_11_i128_to_u64(&cd) & M62; rustsecp256k1_v0_11_i128_rshift(&cd, 62); + e->v[2] = rustsecp256k1_v0_11_i128_to_u64(&ce) & M62; rustsecp256k1_v0_11_i128_rshift(&ce, 62); + /* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */ + rustsecp256k1_v0_11_i128_accum_mul(&cd, u, d4); + rustsecp256k1_v0_11_i128_accum_mul(&cd, v, e4); + rustsecp256k1_v0_11_i128_accum_mul(&ce, q, d4); + rustsecp256k1_v0_11_i128_accum_mul(&ce, r, e4); + rustsecp256k1_v0_11_i128_accum_mul(&cd, modinfo->modulus.v[4], md); + rustsecp256k1_v0_11_i128_accum_mul(&ce, modinfo->modulus.v[4], me); + d->v[3] = rustsecp256k1_v0_11_i128_to_u64(&cd) & M62; rustsecp256k1_v0_11_i128_rshift(&cd, 62); + e->v[3] = rustsecp256k1_v0_11_i128_to_u64(&ce) & M62; rustsecp256k1_v0_11_i128_rshift(&ce, 62); + /* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */ + d->v[4] = rustsecp256k1_v0_11_i128_to_i64(&cd); + e->v[4] = rustsecp256k1_v0_11_i128_to_i64(&ce); + + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ +} + +/* Compute (t/2^62) * [f, g], where t is a transition matrix scaled by 2^62. + * + * This implements the update_fg function from the explanation. + */ +static void rustsecp256k1_v0_11_modinv64_update_fg_62(rustsecp256k1_v0_11_modinv64_signed62 *f, rustsecp256k1_v0_11_modinv64_signed62 *g, const rustsecp256k1_v0_11_modinv64_trans2x2 *t) { + const uint64_t M62 = UINT64_MAX >> 2; + const int64_t f0 = f->v[0], f1 = f->v[1], f2 = f->v[2], f3 = f->v[3], f4 = f->v[4]; + const int64_t g0 = g->v[0], g1 = g->v[1], g2 = g->v[2], g3 = g->v[3], g4 = g->v[4]; + const int64_t u = t->u, v = t->v, q = t->q, r = t->r; + rustsecp256k1_v0_11_int128 cf, cg; + /* Start computing t*[f,g]. */ + rustsecp256k1_v0_11_i128_mul(&cf, u, f0); + rustsecp256k1_v0_11_i128_accum_mul(&cf, v, g0); + rustsecp256k1_v0_11_i128_mul(&cg, q, f0); + rustsecp256k1_v0_11_i128_accum_mul(&cg, r, g0); + /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ + VERIFY_CHECK((rustsecp256k1_v0_11_i128_to_u64(&cf) & M62) == 0); rustsecp256k1_v0_11_i128_rshift(&cf, 62); + VERIFY_CHECK((rustsecp256k1_v0_11_i128_to_u64(&cg) & M62) == 0); rustsecp256k1_v0_11_i128_rshift(&cg, 62); + /* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */ + rustsecp256k1_v0_11_i128_accum_mul(&cf, u, f1); + rustsecp256k1_v0_11_i128_accum_mul(&cf, v, g1); + rustsecp256k1_v0_11_i128_accum_mul(&cg, q, f1); + rustsecp256k1_v0_11_i128_accum_mul(&cg, r, g1); + f->v[0] = rustsecp256k1_v0_11_i128_to_u64(&cf) & M62; rustsecp256k1_v0_11_i128_rshift(&cf, 62); + g->v[0] = rustsecp256k1_v0_11_i128_to_u64(&cg) & M62; rustsecp256k1_v0_11_i128_rshift(&cg, 62); + /* Compute limb 2 of t*[f,g], and store it as output limb 1. */ + rustsecp256k1_v0_11_i128_accum_mul(&cf, u, f2); + rustsecp256k1_v0_11_i128_accum_mul(&cf, v, g2); + rustsecp256k1_v0_11_i128_accum_mul(&cg, q, f2); + rustsecp256k1_v0_11_i128_accum_mul(&cg, r, g2); + f->v[1] = rustsecp256k1_v0_11_i128_to_u64(&cf) & M62; rustsecp256k1_v0_11_i128_rshift(&cf, 62); + g->v[1] = rustsecp256k1_v0_11_i128_to_u64(&cg) & M62; rustsecp256k1_v0_11_i128_rshift(&cg, 62); + /* Compute limb 3 of t*[f,g], and store it as output limb 2. */ + rustsecp256k1_v0_11_i128_accum_mul(&cf, u, f3); + rustsecp256k1_v0_11_i128_accum_mul(&cf, v, g3); + rustsecp256k1_v0_11_i128_accum_mul(&cg, q, f3); + rustsecp256k1_v0_11_i128_accum_mul(&cg, r, g3); + f->v[2] = rustsecp256k1_v0_11_i128_to_u64(&cf) & M62; rustsecp256k1_v0_11_i128_rshift(&cf, 62); + g->v[2] = rustsecp256k1_v0_11_i128_to_u64(&cg) & M62; rustsecp256k1_v0_11_i128_rshift(&cg, 62); + /* Compute limb 4 of t*[f,g], and store it as output limb 3. */ + rustsecp256k1_v0_11_i128_accum_mul(&cf, u, f4); + rustsecp256k1_v0_11_i128_accum_mul(&cf, v, g4); + rustsecp256k1_v0_11_i128_accum_mul(&cg, q, f4); + rustsecp256k1_v0_11_i128_accum_mul(&cg, r, g4); + f->v[3] = rustsecp256k1_v0_11_i128_to_u64(&cf) & M62; rustsecp256k1_v0_11_i128_rshift(&cf, 62); + g->v[3] = rustsecp256k1_v0_11_i128_to_u64(&cg) & M62; rustsecp256k1_v0_11_i128_rshift(&cg, 62); + /* What remains is limb 5 of t*[f,g]; store it as output limb 4. */ + f->v[4] = rustsecp256k1_v0_11_i128_to_i64(&cf); + g->v[4] = rustsecp256k1_v0_11_i128_to_i64(&cg); +} + +/* Compute (t/2^62) * [f, g], where t is a transition matrix for 62 divsteps. + * + * Version that operates on a variable number of limbs in f and g. + * + * This implements the update_fg function from the explanation. + */ +static void rustsecp256k1_v0_11_modinv64_update_fg_62_var(int len, rustsecp256k1_v0_11_modinv64_signed62 *f, rustsecp256k1_v0_11_modinv64_signed62 *g, const rustsecp256k1_v0_11_modinv64_trans2x2 *t) { + const uint64_t M62 = UINT64_MAX >> 2; + const int64_t u = t->u, v = t->v, q = t->q, r = t->r; + int64_t fi, gi; + rustsecp256k1_v0_11_int128 cf, cg; + int i; + VERIFY_CHECK(len > 0); + /* Start computing t*[f,g]. */ + fi = f->v[0]; + gi = g->v[0]; + rustsecp256k1_v0_11_i128_mul(&cf, u, fi); + rustsecp256k1_v0_11_i128_accum_mul(&cf, v, gi); + rustsecp256k1_v0_11_i128_mul(&cg, q, fi); + rustsecp256k1_v0_11_i128_accum_mul(&cg, r, gi); + /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ + VERIFY_CHECK((rustsecp256k1_v0_11_i128_to_u64(&cf) & M62) == 0); rustsecp256k1_v0_11_i128_rshift(&cf, 62); + VERIFY_CHECK((rustsecp256k1_v0_11_i128_to_u64(&cg) & M62) == 0); rustsecp256k1_v0_11_i128_rshift(&cg, 62); + /* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting + * down by 62 bits). */ + for (i = 1; i < len; ++i) { + fi = f->v[i]; + gi = g->v[i]; + rustsecp256k1_v0_11_i128_accum_mul(&cf, u, fi); + rustsecp256k1_v0_11_i128_accum_mul(&cf, v, gi); + rustsecp256k1_v0_11_i128_accum_mul(&cg, q, fi); + rustsecp256k1_v0_11_i128_accum_mul(&cg, r, gi); + f->v[i - 1] = rustsecp256k1_v0_11_i128_to_u64(&cf) & M62; rustsecp256k1_v0_11_i128_rshift(&cf, 62); + g->v[i - 1] = rustsecp256k1_v0_11_i128_to_u64(&cg) & M62; rustsecp256k1_v0_11_i128_rshift(&cg, 62); + } + /* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */ + f->v[len - 1] = rustsecp256k1_v0_11_i128_to_i64(&cf); + g->v[len - 1] = rustsecp256k1_v0_11_i128_to_i64(&cg); +} + +/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */ +static void rustsecp256k1_v0_11_modinv64(rustsecp256k1_v0_11_modinv64_signed62 *x, const rustsecp256k1_v0_11_modinv64_modinfo *modinfo) { + /* Start with d=0, e=1, f=modulus, g=x, zeta=-1. */ + rustsecp256k1_v0_11_modinv64_signed62 d = {{0, 0, 0, 0, 0}}; + rustsecp256k1_v0_11_modinv64_signed62 e = {{1, 0, 0, 0, 0}}; + rustsecp256k1_v0_11_modinv64_signed62 f = modinfo->modulus; + rustsecp256k1_v0_11_modinv64_signed62 g = *x; + int i; + int64_t zeta = -1; /* zeta = -(delta+1/2); delta starts at 1/2. */ + + /* Do 10 iterations of 59 divsteps each = 590 divsteps. This suffices for 256-bit inputs. */ + for (i = 0; i < 10; ++i) { + /* Compute transition matrix and new zeta after 59 divsteps. */ + rustsecp256k1_v0_11_modinv64_trans2x2 t; + zeta = rustsecp256k1_v0_11_modinv64_divsteps_59(zeta, f.v[0], g.v[0], &t); + /* Update d,e using that transition matrix. */ + rustsecp256k1_v0_11_modinv64_update_de_62(&d, &e, &t, modinfo); + /* Update f,g using that transition matrix. */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */ + + rustsecp256k1_v0_11_modinv64_update_fg_62(&f, &g, &t); + + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* At this point sufficient iterations have been performed that g must have reached 0 + * and (if g was not originally 0) f must now equal +/- GCD of the initial f, g + * values i.e. +/- 1, and d now contains +/- the modular inverse. */ + + /* g == 0 */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&g, 5, &SECP256K1_SIGNED62_ONE, 0) == 0); + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, -1) == 0 || + rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, 1) == 0 || + (rustsecp256k1_v0_11_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && + rustsecp256k1_v0_11_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && + rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) == 0)); + + /* Optionally negate d, normalize to [0,modulus), and return it. */ + rustsecp256k1_v0_11_modinv64_normalize_62(&d, f.v[4], modinfo); + *x = d; +} + +/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (variable time). */ +static void rustsecp256k1_v0_11_modinv64_var(rustsecp256k1_v0_11_modinv64_signed62 *x, const rustsecp256k1_v0_11_modinv64_modinfo *modinfo) { + /* Start with d=0, e=1, f=modulus, g=x, eta=-1. */ + rustsecp256k1_v0_11_modinv64_signed62 d = {{0, 0, 0, 0, 0}}; + rustsecp256k1_v0_11_modinv64_signed62 e = {{1, 0, 0, 0, 0}}; + rustsecp256k1_v0_11_modinv64_signed62 f = modinfo->modulus; + rustsecp256k1_v0_11_modinv64_signed62 g = *x; +#ifdef VERIFY + int i = 0; +#endif + int j, len = 5; + int64_t eta = -1; /* eta = -delta; delta is initially 1 */ + int64_t cond, fn, gn; + + /* Do iterations of 62 divsteps each until g=0. */ + while (1) { + /* Compute transition matrix and new eta after 62 divsteps. */ + rustsecp256k1_v0_11_modinv64_trans2x2 t; + eta = rustsecp256k1_v0_11_modinv64_divsteps_62_var(eta, f.v[0], g.v[0], &t); + /* Update d,e using that transition matrix. */ + rustsecp256k1_v0_11_modinv64_update_de_62(&d, &e, &t, modinfo); + /* Update f,g using that transition matrix. */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + + rustsecp256k1_v0_11_modinv64_update_fg_62_var(len, &f, &g, &t); + /* If the bottom limb of g is zero, there is a chance that g=0. */ + if (g.v[0] == 0) { + cond = 0; + /* Check if the other limbs are also 0. */ + for (j = 1; j < len; ++j) { + cond |= g.v[j]; + } + /* If so, we're done. */ + if (cond == 0) break; + } + + /* Determine if len>1 and limb (len-1) of both f and g is 0 or -1. */ + fn = f.v[len - 1]; + gn = g.v[len - 1]; + cond = ((int64_t)len - 2) >> 63; + cond |= fn ^ (fn >> 63); + cond |= gn ^ (gn >> 63); + /* If so, reduce length, propagating the sign of f and g's top limb into the one below. */ + if (cond == 0) { + f.v[len - 2] |= (uint64_t)fn << 62; + g.v[len - 2] |= (uint64_t)gn << 62; + --len; + } + + VERIFY_CHECK(++i < 12); /* We should never need more than 12*62 = 744 divsteps */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of + * the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */ + + /* g == 0 */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&g, len, &SECP256K1_SIGNED62_ONE, 0) == 0); + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, -1) == 0 || + rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, 1) == 0 || + (rustsecp256k1_v0_11_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && + rustsecp256k1_v0_11_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && + rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) == 0)); + + /* Optionally negate d, normalize to [0,modulus), and return it. */ + rustsecp256k1_v0_11_modinv64_normalize_62(&d, f.v[len - 1], modinfo); + *x = d; +} + +/* Do up to 25 iterations of 62 posdivsteps (up to 1550 steps; more is extremely rare) each until f=1. + * In VERIFY mode use a lower number of iterations (744, close to the median 756), so failure actually occurs. */ +#ifdef VERIFY +#define JACOBI64_ITERATIONS 12 +#else +#define JACOBI64_ITERATIONS 25 +#endif + +/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */ +static int rustsecp256k1_v0_11_jacobi64_maybe_var(const rustsecp256k1_v0_11_modinv64_signed62 *x, const rustsecp256k1_v0_11_modinv64_modinfo *modinfo) { + /* Start with f=modulus, g=x, eta=-1. */ + rustsecp256k1_v0_11_modinv64_signed62 f = modinfo->modulus; + rustsecp256k1_v0_11_modinv64_signed62 g = *x; + int j, len = 5; + int64_t eta = -1; /* eta = -delta; delta is initially 1 */ + int64_t cond, fn, gn; + int jac = 0; + int count; + + /* The input limbs must all be non-negative. */ + VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0); + + /* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we + * require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or + * time out). */ + VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4]) != 0); + + for (count = 0; count < JACOBI64_ITERATIONS; ++count) { + /* Compute transition matrix and new eta after 62 posdivsteps. */ + rustsecp256k1_v0_11_modinv64_trans2x2 t; + eta = rustsecp256k1_v0_11_modinv64_posdivsteps_62_var(eta, f.v[0] | ((uint64_t)f.v[1] << 62), g.v[0] | ((uint64_t)g.v[1] << 62), &t, &jac); + /* Update f,g using that transition matrix. */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + + rustsecp256k1_v0_11_modinv64_update_fg_62_var(len, &f, &g, &t); + /* If the bottom limb of f is 1, there is a chance that f=1. */ + if (f.v[0] == 1) { + cond = 0; + /* Check if the other limbs are also 0. */ + for (j = 1; j < len; ++j) { + cond |= f.v[j]; + } + /* If so, we're done. When f=1, the Jacobi symbol (g | f)=1. */ + if (cond == 0) return 1 - 2*(jac & 1); + } + + /* Determine if len>1 and limb (len-1) of both f and g is 0. */ + fn = f.v[len - 1]; + gn = g.v[len - 1]; + cond = ((int64_t)len - 2) >> 63; + cond |= fn; + cond |= gn; + /* If so, reduce length. */ + if (cond == 0) --len; + + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(rustsecp256k1_v0_11_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* The loop failed to converge to f=g after 1550 iterations. Return 0, indicating unknown result. */ + return 0; +} + +#endif /* SECP256K1_MODINV64_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdh/Makefile.am.include b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ecdh/Makefile.am.include similarity index 71% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdh/Makefile.am.include rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ecdh/Makefile.am.include index 34d3c738..1477c19c 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdh/Makefile.am.include +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ecdh/Makefile.am.include @@ -1,4 +1,4 @@ -include_HEADERS += include/rustsecp256k1zkp_v0_8_0_ecdh.h +include_HEADERS += include/rustsecp256k1_v0_11_ecdh.h noinst_HEADERS += src/modules/ecdh/main_impl.h noinst_HEADERS += src/modules/ecdh/tests_impl.h noinst_HEADERS += src/modules/ecdh/bench_impl.h diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdh/bench_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ecdh/bench_impl.h similarity index 72% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdh/bench_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ecdh/bench_impl.h index ab552c35..82d5a8b0 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/ecdh/bench_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ecdh/bench_impl.h @@ -7,11 +7,11 @@ #ifndef SECP256K1_MODULE_ECDH_BENCH_H #define SECP256K1_MODULE_ECDH_BENCH_H -#include "../include/secp256k1_ecdh.h" +#include "../../../include/secp256k1_ecdh.h" typedef struct { - rustsecp256k1zkp_v0_8_0_context *ctx; - rustsecp256k1zkp_v0_8_0_pubkey point; + rustsecp256k1_v0_11_context *ctx; + rustsecp256k1_v0_11_pubkey point; unsigned char scalar[32]; } bench_ecdh_data; @@ -29,7 +29,7 @@ static void bench_ecdh_setup(void* arg) { for (i = 0; i < 32; i++) { data->scalar[i] = i + 1; } - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); } static void bench_ecdh(void* arg, int iters) { @@ -38,20 +38,20 @@ static void bench_ecdh(void* arg, int iters) { bench_ecdh_data *data = (bench_ecdh_data*)arg; for (i = 0; i < iters; i++) { - CHECK(rustsecp256k1zkp_v0_8_0_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1); + CHECK(rustsecp256k1_v0_11_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1); } } -void run_ecdh_bench(int iters, int argc, char** argv) { +static void run_ecdh_bench(int iters, int argc, char** argv) { bench_ecdh_data data; int d = argc == 1; /* create a context with no capabilities */ - data.ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_FLAGS_TYPE_CONTEXT); + data.ctx = rustsecp256k1_v0_11_context_create(SECP256K1_FLAGS_TYPE_CONTEXT); if (d || have_flag(argc, argv, "ecdh")) run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, iters); - rustsecp256k1zkp_v0_8_0_context_destroy(data.ctx); + rustsecp256k1_v0_11_context_destroy(data.ctx); } #endif /* SECP256K1_MODULE_ECDH_BENCH_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ecdh/main_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ecdh/main_impl.h new file mode 100644 index 00000000..fe055a2a --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ecdh/main_impl.h @@ -0,0 +1,74 @@ +/*********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_MAIN_H +#define SECP256K1_MODULE_ECDH_MAIN_H + +#include "../../../include/secp256k1_ecdh.h" +#include "../../ecmult_const_impl.h" + +static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) { + unsigned char version = (y32[31] & 0x01) | 0x02; + rustsecp256k1_v0_11_sha256 sha; + (void)data; + + rustsecp256k1_v0_11_sha256_initialize(&sha); + rustsecp256k1_v0_11_sha256_write(&sha, &version, 1); + rustsecp256k1_v0_11_sha256_write(&sha, x32, 32); + rustsecp256k1_v0_11_sha256_finalize(&sha, output); + rustsecp256k1_v0_11_sha256_clear(&sha); + + return 1; +} + +const rustsecp256k1_v0_11_ecdh_hash_function rustsecp256k1_v0_11_ecdh_hash_function_sha256 = ecdh_hash_function_sha256; +const rustsecp256k1_v0_11_ecdh_hash_function rustsecp256k1_v0_11_ecdh_hash_function_default = ecdh_hash_function_sha256; + +int rustsecp256k1_v0_11_ecdh(const rustsecp256k1_v0_11_context* ctx, unsigned char *output, const rustsecp256k1_v0_11_pubkey *point, const unsigned char *scalar, rustsecp256k1_v0_11_ecdh_hash_function hashfp, void *data) { + int ret = 0; + int overflow = 0; + rustsecp256k1_v0_11_gej res; + rustsecp256k1_v0_11_ge pt; + rustsecp256k1_v0_11_scalar s; + unsigned char x[32]; + unsigned char y[32]; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(point != NULL); + ARG_CHECK(scalar != NULL); + + if (hashfp == NULL) { + hashfp = rustsecp256k1_v0_11_ecdh_hash_function_default; + } + + rustsecp256k1_v0_11_pubkey_load(ctx, &pt, point); + rustsecp256k1_v0_11_scalar_set_b32(&s, scalar, &overflow); + + overflow |= rustsecp256k1_v0_11_scalar_is_zero(&s); + rustsecp256k1_v0_11_scalar_cmov(&s, &rustsecp256k1_v0_11_scalar_one, overflow); + + rustsecp256k1_v0_11_ecmult_const(&res, &pt, &s); + rustsecp256k1_v0_11_ge_set_gej(&pt, &res); + + /* Compute a hash of the point */ + rustsecp256k1_v0_11_fe_normalize(&pt.x); + rustsecp256k1_v0_11_fe_normalize(&pt.y); + rustsecp256k1_v0_11_fe_get_b32(x, &pt.x); + rustsecp256k1_v0_11_fe_get_b32(y, &pt.y); + + ret = hashfp(output, x, y, data); + + rustsecp256k1_v0_11_memclear(x, sizeof(x)); + rustsecp256k1_v0_11_memclear(y, sizeof(y)); + rustsecp256k1_v0_11_scalar_clear(&s); + rustsecp256k1_v0_11_ge_clear(&pt); + rustsecp256k1_v0_11_gej_clear(&res); + + return !!ret & !overflow; +} + +#endif /* SECP256K1_MODULE_ECDH_MAIN_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ecdh/tests_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ecdh/tests_impl.h new file mode 100644 index 00000000..8d2200d9 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ecdh/tests_impl.h @@ -0,0 +1,152 @@ +/*********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_TESTS_H +#define SECP256K1_MODULE_ECDH_TESTS_H + +static int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + (void)output; + (void)x; + (void)y; + (void)data; + return 0; +} + +static int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + (void)data; + /* Save x and y as uncompressed public key */ + output[0] = 0x04; + memcpy(output + 1, x, 32); + memcpy(output + 33, y, 32); + return 1; +} + +static void test_ecdh_api(void) { + rustsecp256k1_v0_11_pubkey point; + unsigned char res[32]; + unsigned char s_one[32] = { 0 }; + s_one[31] = 1; + + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &point, s_one) == 1); + + /* Check all NULLs are detected */ + CHECK(rustsecp256k1_v0_11_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdh(CTX, NULL, &point, s_one, NULL, NULL)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdh(CTX, res, NULL, s_one, NULL, NULL)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdh(CTX, res, &point, NULL, NULL, NULL)); + CHECK(rustsecp256k1_v0_11_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1); +} + +static void test_ecdh_generator_basepoint(void) { + unsigned char s_one[32] = { 0 }; + rustsecp256k1_v0_11_pubkey point[2]; + int i; + + s_one[31] = 1; + /* Check against pubkey creation when the basepoint is the generator */ + for (i = 0; i < 2 * COUNT; ++i) { + rustsecp256k1_v0_11_sha256 sha; + unsigned char s_b32[32]; + unsigned char output_ecdh[65]; + unsigned char output_ser[32]; + unsigned char point_ser[65]; + size_t point_ser_len = sizeof(point_ser); + rustsecp256k1_v0_11_scalar s; + + testutil_random_scalar_order(&s); + rustsecp256k1_v0_11_scalar_get_b32(s_b32, &s); + + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &point[0], s_one) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &point[1], s_b32) == 1); + + /* compute using ECDH function with custom hash function */ + CHECK(rustsecp256k1_v0_11_ecdh(CTX, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1); + /* compute "explicitly" */ + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1); + /* compare */ + CHECK(rustsecp256k1_v0_11_memcmp_var(output_ecdh, point_ser, 65) == 0); + + /* compute using ECDH function with default hash function */ + CHECK(rustsecp256k1_v0_11_ecdh(CTX, output_ecdh, &point[0], s_b32, NULL, NULL) == 1); + /* compute "explicitly" */ + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); + rustsecp256k1_v0_11_sha256_initialize(&sha); + rustsecp256k1_v0_11_sha256_write(&sha, point_ser, point_ser_len); + rustsecp256k1_v0_11_sha256_finalize(&sha, output_ser); + /* compare */ + CHECK(rustsecp256k1_v0_11_memcmp_var(output_ecdh, output_ser, 32) == 0); + } +} + +static void test_bad_scalar(void) { + unsigned char s_zero[32] = { 0 }; + unsigned char s_overflow[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + }; + unsigned char s_rand[32] = { 0 }; + unsigned char output[32]; + rustsecp256k1_v0_11_scalar rand; + rustsecp256k1_v0_11_pubkey point; + + /* Create random point */ + testutil_random_scalar_order(&rand); + rustsecp256k1_v0_11_scalar_get_b32(s_rand, &rand); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &point, s_rand) == 1); + + /* Try to multiply it by bad values */ + CHECK(rustsecp256k1_v0_11_ecdh(CTX, output, &point, s_zero, NULL, NULL) == 0); + CHECK(rustsecp256k1_v0_11_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 0); + /* ...and a good one */ + s_overflow[31] -= 1; + CHECK(rustsecp256k1_v0_11_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 1); + + /* Hash function failure results in ecdh failure */ + CHECK(rustsecp256k1_v0_11_ecdh(CTX, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0); +} + +/** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */ +static void test_result_basepoint(void) { + rustsecp256k1_v0_11_pubkey point; + rustsecp256k1_v0_11_scalar rand; + unsigned char s[32]; + unsigned char s_inv[32]; + unsigned char out[32]; + unsigned char out_inv[32]; + unsigned char out_base[32]; + int i; + + unsigned char s_one[32] = { 0 }; + s_one[31] = 1; + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &point, s_one) == 1); + CHECK(rustsecp256k1_v0_11_ecdh(CTX, out_base, &point, s_one, NULL, NULL) == 1); + + for (i = 0; i < 2 * COUNT; i++) { + testutil_random_scalar_order(&rand); + rustsecp256k1_v0_11_scalar_get_b32(s, &rand); + rustsecp256k1_v0_11_scalar_inverse(&rand, &rand); + rustsecp256k1_v0_11_scalar_get_b32(s_inv, &rand); + + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &point, s) == 1); + CHECK(rustsecp256k1_v0_11_ecdh(CTX, out, &point, s_inv, NULL, NULL) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(out, out_base, 32) == 0); + + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &point, s_inv) == 1); + CHECK(rustsecp256k1_v0_11_ecdh(CTX, out_inv, &point, s, NULL, NULL) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(out_inv, out_base, 32) == 0); + } +} + +static void run_ecdh_tests(void) { + test_ecdh_api(); + test_ecdh_generator_basepoint(); + test_bad_scalar(); + test_result_basepoint(); +} + +#endif /* SECP256K1_MODULE_ECDH_TESTS_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/Makefile.am.include b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/Makefile.am.include new file mode 100644 index 00000000..9e77d069 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/Makefile.am.include @@ -0,0 +1,5 @@ +include_HEADERS += include/rustsecp256k1_v0_11_ellswift.h +noinst_HEADERS += src/modules/ellswift/bench_impl.h +noinst_HEADERS += src/modules/ellswift/main_impl.h +noinst_HEADERS += src/modules/ellswift/tests_impl.h +noinst_HEADERS += src/modules/ellswift/tests_exhaustive_impl.h diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/bench_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/bench_impl.h new file mode 100644 index 00000000..59f4e52d --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/bench_impl.h @@ -0,0 +1,106 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ELLSWIFT_BENCH_H +#define SECP256K1_MODULE_ELLSWIFT_BENCH_H + +#include "../../../include/secp256k1_ellswift.h" + +typedef struct { + rustsecp256k1_v0_11_context *ctx; + rustsecp256k1_v0_11_pubkey point[256]; + unsigned char rnd64[64]; +} bench_ellswift_data; + +static void bench_ellswift_setup(void *arg) { + int i; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + static const unsigned char init[64] = { + 0x78, 0x1f, 0xb7, 0xd4, 0x67, 0x7f, 0x08, 0x68, + 0xdb, 0xe3, 0x1d, 0x7f, 0x1b, 0xb0, 0xf6, 0x9e, + 0x0a, 0x64, 0xca, 0x32, 0x9e, 0xc6, 0x20, 0x79, + 0x03, 0xf3, 0xd0, 0x46, 0x7a, 0x0f, 0xd2, 0x21, + 0xb0, 0x2c, 0x46, 0xd8, 0xba, 0xca, 0x26, 0x4f, + 0x8f, 0x8c, 0xd4, 0xdd, 0x2d, 0x04, 0xbe, 0x30, + 0x48, 0x51, 0x1e, 0xd4, 0x16, 0xfd, 0x42, 0x85, + 0x62, 0xc9, 0x02, 0xf9, 0x89, 0x84, 0xff, 0xdc + }; + memcpy(data->rnd64, init, 64); + for (i = 0; i < 256; ++i) { + int j; + CHECK(rustsecp256k1_v0_11_ellswift_decode(data->ctx, &data->point[i], data->rnd64)); + for (j = 0; j < 64; ++j) { + data->rnd64[j] += 1; + } + } + CHECK(rustsecp256k1_v0_11_ellswift_encode(data->ctx, data->rnd64, &data->point[255], init + 16)); +} + +static void bench_ellswift_encode(void *arg, int iters) { + int i; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + + for (i = 0; i < iters; i++) { + CHECK(rustsecp256k1_v0_11_ellswift_encode(data->ctx, data->rnd64, &data->point[i & 255], data->rnd64 + 16)); + } +} + +static void bench_ellswift_create(void *arg, int iters) { + int i; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + + for (i = 0; i < iters; i++) { + unsigned char buf[64]; + CHECK(rustsecp256k1_v0_11_ellswift_create(data->ctx, buf, data->rnd64, data->rnd64 + 32)); + memcpy(data->rnd64, buf, 64); + } +} + +static void bench_ellswift_decode(void *arg, int iters) { + int i; + rustsecp256k1_v0_11_pubkey out; + size_t len; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + + for (i = 0; i < iters; i++) { + CHECK(rustsecp256k1_v0_11_ellswift_decode(data->ctx, &out, data->rnd64) == 1); + len = 33; + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(data->ctx, data->rnd64 + (i % 32), &len, &out, SECP256K1_EC_COMPRESSED)); + } +} + +static void bench_ellswift_xdh(void *arg, int iters) { + int i; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + + for (i = 0; i < iters; i++) { + int party = i & 1; + CHECK(rustsecp256k1_v0_11_ellswift_xdh(data->ctx, + data->rnd64 + (i % 33), + data->rnd64, + data->rnd64, + data->rnd64 + ((i + 16) % 33), + party, + rustsecp256k1_v0_11_ellswift_xdh_hash_function_bip324, + NULL) == 1); + } +} + +void run_ellswift_bench(int iters, int argc, char **argv) { + bench_ellswift_data data; + int d = argc == 1; + + /* create a context with signing capabilities */ + data.ctx = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); + + if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "encode") || have_flag(argc, argv, "ellswift_encode")) run_benchmark("ellswift_encode", bench_ellswift_encode, bench_ellswift_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_decode")) run_benchmark("ellswift_decode", bench_ellswift_decode, bench_ellswift_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ellswift_keygen")) run_benchmark("ellswift_keygen", bench_ellswift_create, bench_ellswift_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ecdh") || have_flag(argc, argv, "ellswift_ecdh")) run_benchmark("ellswift_ecdh", bench_ellswift_xdh, bench_ellswift_setup, NULL, &data, 10, iters); + + rustsecp256k1_v0_11_context_destroy(data.ctx); +} + +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/main_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/main_impl.h new file mode 100644 index 00000000..b778ecdf --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/main_impl.h @@ -0,0 +1,592 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ELLSWIFT_MAIN_H +#define SECP256K1_MODULE_ELLSWIFT_MAIN_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_ellswift.h" +#include "../../eckey.h" +#include "../../hash.h" + +/** c1 = (sqrt(-3)-1)/2 */ +static const rustsecp256k1_v0_11_fe rustsecp256k1_v0_11_ellswift_c1 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40); +/** c2 = (-sqrt(-3)-1)/2 = -(c1+1) */ +static const rustsecp256k1_v0_11_fe rustsecp256k1_v0_11_ellswift_c2 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ee); +/** c3 = (-sqrt(-3)+1)/2 = -c1 = c2+1 */ +static const rustsecp256k1_v0_11_fe rustsecp256k1_v0_11_ellswift_c3 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ef); +/** c4 = (sqrt(-3)+1)/2 = -c2 = c1+1 */ +static const rustsecp256k1_v0_11_fe rustsecp256k1_v0_11_ellswift_c4 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa41); + +/** Decode ElligatorSwift encoding (u, t) to a fraction xn/xd representing a curve X coordinate. */ +static void rustsecp256k1_v0_11_ellswift_xswiftec_frac_var(rustsecp256k1_v0_11_fe *xn, rustsecp256k1_v0_11_fe *xd, const rustsecp256k1_v0_11_fe *u, const rustsecp256k1_v0_11_fe *t) { + /* The implemented algorithm is the following (all operations in GF(p)): + * + * - Let c0 = sqrt(-3) = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852. + * - If u = 0, set u = 1. + * - If t = 0, set t = 1. + * - If u^3+7+t^2 = 0, set t = 2*t. + * - Let X = (u^3+7-t^2)/(2*t). + * - Let Y = (X+t)/(c0*u). + * - If x3 = u+4*Y^2 is a valid x coordinate, return it. + * - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it. + * - Return x1 = (X/Y-u)/2 (which is now guaranteed to be a valid x coordinate). + * + * Introducing s=t^2, g=u^3+7, and simplifying x1=-(x2+u) we get: + * + * - Let c0 = ... + * - If u = 0, set u = 1. + * - If t = 0, set t = 1. + * - Let s = t^2 + * - Let g = u^3+7 + * - If g+s = 0, set t = 2*t, s = 4*s + * - Let X = (g-s)/(2*t). + * - Let Y = (X+t)/(c0*u) = (g+s)/(2*c0*t*u). + * - If x3 = u+4*Y^2 is a valid x coordinate, return it. + * - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it. + * - Return x1 = -(x2+u). + * + * Now substitute Y^2 = -(g+s)^2/(12*s*u^2) and X/Y = c0*u*(g-s)/(g+s). This + * means X and Y do not need to be evaluated explicitly anymore. + * + * - ... + * - If g+s = 0, set s = 4*s. + * - If x3 = u-(g+s)^2/(3*s*u^2) is a valid x coordinate, return it. + * - If x2 = (-c0*u*(g-s)/(g+s)-u)/2 is a valid x coordinate, return it. + * - Return x1 = -(x2+u). + * + * Simplifying x2 using 2 additional constants: + * + * - Let c1 = (c0-1)/2 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40. + * - Let c2 = (-c0-1)/2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee. + * - ... + * - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it. + * - ... + * + * Writing x3 as a fraction: + * + * - ... + * - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) ... + * - ... + + * Overall, we get: + * + * - Let c1 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40. + * - Let c2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee. + * - If u = 0, set u = 1. + * - If t = 0, set s = 1, else set s = t^2. + * - Let g = u^3+7. + * - If g+s = 0, set s = 4*s. + * - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) is a valid x coordinate, return it. + * - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it. + * - Return x1 = -(x2+u). + */ + rustsecp256k1_v0_11_fe u1, s, g, p, d, n, l; + u1 = *u; + if (EXPECT(rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&u1), 0)) u1 = rustsecp256k1_v0_11_fe_one; + rustsecp256k1_v0_11_fe_sqr(&s, t); + if (EXPECT(rustsecp256k1_v0_11_fe_normalizes_to_zero_var(t), 0)) s = rustsecp256k1_v0_11_fe_one; + rustsecp256k1_v0_11_fe_sqr(&l, &u1); /* l = u^2 */ + rustsecp256k1_v0_11_fe_mul(&g, &l, &u1); /* g = u^3 */ + rustsecp256k1_v0_11_fe_add_int(&g, SECP256K1_B); /* g = u^3 + 7 */ + p = g; /* p = g */ + rustsecp256k1_v0_11_fe_add(&p, &s); /* p = g+s */ + if (EXPECT(rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&p), 0)) { + rustsecp256k1_v0_11_fe_mul_int(&s, 4); + /* Recompute p = g+s */ + p = g; /* p = g */ + rustsecp256k1_v0_11_fe_add(&p, &s); /* p = g+s */ + } + rustsecp256k1_v0_11_fe_mul(&d, &s, &l); /* d = s*u^2 */ + rustsecp256k1_v0_11_fe_mul_int(&d, 3); /* d = 3*s*u^2 */ + rustsecp256k1_v0_11_fe_sqr(&l, &p); /* l = (g+s)^2 */ + rustsecp256k1_v0_11_fe_negate(&l, &l, 1); /* l = -(g+s)^2 */ + rustsecp256k1_v0_11_fe_mul(&n, &d, &u1); /* n = 3*s*u^3 */ + rustsecp256k1_v0_11_fe_add(&n, &l); /* n = 3*s*u^3-(g+s)^2 */ + if (rustsecp256k1_v0_11_ge_x_frac_on_curve_var(&n, &d)) { + /* Return x3 = n/d = (3*s*u^3-(g+s)^2)/(3*s*u^2) */ + *xn = n; + *xd = d; + return; + } + *xd = p; + rustsecp256k1_v0_11_fe_mul(&l, &rustsecp256k1_v0_11_ellswift_c1, &s); /* l = c1*s */ + rustsecp256k1_v0_11_fe_mul(&n, &rustsecp256k1_v0_11_ellswift_c2, &g); /* n = c2*g */ + rustsecp256k1_v0_11_fe_add(&n, &l); /* n = c1*s+c2*g */ + rustsecp256k1_v0_11_fe_mul(&n, &n, &u1); /* n = u*(c1*s+c2*g) */ + /* Possible optimization: in the invocation below, p^2 = (g+s)^2 is computed, + * which we already have computed above. This could be deduplicated. */ + if (rustsecp256k1_v0_11_ge_x_frac_on_curve_var(&n, &p)) { + /* Return x2 = n/p = u*(c1*s+c2*g)/(g+s) */ + *xn = n; + return; + } + rustsecp256k1_v0_11_fe_mul(&l, &p, &u1); /* l = u*(g+s) */ + rustsecp256k1_v0_11_fe_add(&n, &l); /* n = u*(c1*s+c2*g)+u*(g+s) */ + rustsecp256k1_v0_11_fe_negate(xn, &n, 2); /* n = -u*(c1*s+c2*g)-u*(g+s) */ + + VERIFY_CHECK(rustsecp256k1_v0_11_ge_x_frac_on_curve_var(xn, &p)); + /* Return x3 = n/p = -(u*(c1*s+c2*g)/(g+s)+u) */ +} + +/** Decode ElligatorSwift encoding (u, t) to X coordinate. */ +static void rustsecp256k1_v0_11_ellswift_xswiftec_var(rustsecp256k1_v0_11_fe *x, const rustsecp256k1_v0_11_fe *u, const rustsecp256k1_v0_11_fe *t) { + rustsecp256k1_v0_11_fe xn, xd; + rustsecp256k1_v0_11_ellswift_xswiftec_frac_var(&xn, &xd, u, t); + rustsecp256k1_v0_11_fe_inv_var(&xd, &xd); + rustsecp256k1_v0_11_fe_mul(x, &xn, &xd); +} + +/** Decode ElligatorSwift encoding (u, t) to point P. */ +static void rustsecp256k1_v0_11_ellswift_swiftec_var(rustsecp256k1_v0_11_ge *p, const rustsecp256k1_v0_11_fe *u, const rustsecp256k1_v0_11_fe *t) { + rustsecp256k1_v0_11_fe x; + rustsecp256k1_v0_11_ellswift_xswiftec_var(&x, u, t); + rustsecp256k1_v0_11_ge_set_xo_var(p, &x, rustsecp256k1_v0_11_fe_is_odd(t)); +} + +/* Try to complete an ElligatorSwift encoding (u, t) for X coordinate x, given u and x. + * + * There may be up to 8 distinct t values such that (u, t) decodes back to x, but also + * fewer, or none at all. Each such partial inverse can be accessed individually using a + * distinct input argument c (in range 0-7), and some or all of these may return failure. + * The following guarantees exist: + * - Given (x, u), no two distinct c values give the same successful result t. + * - Every successful result maps back to x through rustsecp256k1_v0_11_ellswift_xswiftec_var. + * - Given (x, u), all t values that map back to x can be reached by combining the + * successful results from this function over all c values, with the exception of: + * - this function cannot be called with u=0 + * - no result with t=0 will be returned + * - no result for which u^3 + t^2 + 7 = 0 will be returned. + * + * The rather unusual encoding of bits in c (a large "if" based on the middle bit, and then + * using the low and high bits to pick signs of square roots) is to match the paper's + * encoding more closely: c=0 through c=3 match branches 1..4 in the paper, while c=4 through + * c=7 are copies of those with an additional negation of sqrt(w). + */ +static int rustsecp256k1_v0_11_ellswift_xswiftec_inv_var(rustsecp256k1_v0_11_fe *t, const rustsecp256k1_v0_11_fe *x_in, const rustsecp256k1_v0_11_fe *u_in, int c) { + /* The implemented algorithm is this (all arithmetic, except involving c, is mod p): + * + * - If (c & 2) = 0: + * - If (-x-u) is a valid X coordinate, fail. + * - Let s=-(u^3+7)/(u^2+u*x+x^2). + * - If s is not square, fail. + * - Let v=x. + * - If (c & 2) = 2: + * - Let s=x-u. + * - If s is not square, fail. + * - Let r=sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist. + * - If (c & 1) = 1 and r = 0, fail. + * - If s=0, fail. + * - Let v=(r/s-u)/2. + * - Let w=sqrt(s). + * - If (c & 5) = 0: return -w*(c3*u + v). + * - If (c & 5) = 1: return w*(c4*u + v). + * - If (c & 5) = 4: return w*(c3*u + v). + * - If (c & 5) = 5: return -w*(c4*u + v). + */ + rustsecp256k1_v0_11_fe x = *x_in, u = *u_in, g, v, s, m, r, q; + int ret; + + rustsecp256k1_v0_11_fe_normalize_weak(&x); + rustsecp256k1_v0_11_fe_normalize_weak(&u); + + VERIFY_CHECK(c >= 0 && c < 8); + VERIFY_CHECK(rustsecp256k1_v0_11_ge_x_on_curve_var(&x)); + + if (!(c & 2)) { + /* c is in {0, 1, 4, 5}. In this case we look for an inverse under the x1 (if c=0 or + * c=4) formula, or x2 (if c=1 or c=5) formula. */ + + /* If -u-x is a valid X coordinate, fail. This would yield an encoding that roundtrips + * back under the x3 formula instead (which has priority over x1 and x2, so the decoding + * would not match x). */ + m = x; /* m = x */ + rustsecp256k1_v0_11_fe_add(&m, &u); /* m = u+x */ + rustsecp256k1_v0_11_fe_negate(&m, &m, 2); /* m = -u-x */ + /* Test if (-u-x) is a valid X coordinate. If so, fail. */ + if (rustsecp256k1_v0_11_ge_x_on_curve_var(&m)) return 0; + + /* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [first part] */ + rustsecp256k1_v0_11_fe_sqr(&s, &m); /* s = (u+x)^2 */ + rustsecp256k1_v0_11_fe_negate(&s, &s, 1); /* s = -(u+x)^2 */ + rustsecp256k1_v0_11_fe_mul(&m, &u, &x); /* m = u*x */ + rustsecp256k1_v0_11_fe_add(&s, &m); /* s = -(u^2 + u*x + x^2) */ + + /* Note that at this point, s = 0 is impossible. If it were the case: + * s = -(u^2 + u*x + x^2) = 0 + * => u^2 + u*x + x^2 = 0 + * => (u + 2*x) * (u^2 + u*x + x^2) = 0 + * => 2*x^3 + 3*x^2*u + 3*x*u^2 + u^3 = 0 + * => (x + u)^3 + x^3 = 0 + * => x^3 = -(x + u)^3 + * => x^3 + B = (-u - x)^3 + B + * + * However, we know x^3 + B is square (because x is on the curve) and + * that (-u-x)^3 + B is not square (the rustsecp256k1_v0_11_ge_x_on_curve_var(&m) + * test above would have failed). This is a contradiction, and thus the + * assumption s=0 is false. */ + VERIFY_CHECK(!rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&s)); + + /* If s is not square, fail. We have not fully computed s yet, but s is square iff + * -(u^3+7)*(u^2+u*x+x^2) is square (because a/b is square iff a*b is square and b is + * nonzero). */ + rustsecp256k1_v0_11_fe_sqr(&g, &u); /* g = u^2 */ + rustsecp256k1_v0_11_fe_mul(&g, &g, &u); /* g = u^3 */ + rustsecp256k1_v0_11_fe_add_int(&g, SECP256K1_B); /* g = u^3+7 */ + rustsecp256k1_v0_11_fe_mul(&m, &s, &g); /* m = -(u^3 + 7)*(u^2 + u*x + x^2) */ + if (!rustsecp256k1_v0_11_fe_is_square_var(&m)) return 0; + + /* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [second part] */ + rustsecp256k1_v0_11_fe_inv_var(&s, &s); /* s = -1/(u^2 + u*x + x^2) [no div by 0] */ + rustsecp256k1_v0_11_fe_mul(&s, &s, &g); /* s = -(u^3 + 7)/(u^2 + u*x + x^2) */ + + /* Let v = x. */ + v = x; + } else { + /* c is in {2, 3, 6, 7}. In this case we look for an inverse under the x3 formula. */ + + /* Let s = x-u. */ + rustsecp256k1_v0_11_fe_negate(&m, &u, 1); /* m = -u */ + s = m; /* s = -u */ + rustsecp256k1_v0_11_fe_add(&s, &x); /* s = x-u */ + + /* If s is not square, fail. */ + if (!rustsecp256k1_v0_11_fe_is_square_var(&s)) return 0; + + /* Let r = sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist. */ + rustsecp256k1_v0_11_fe_sqr(&g, &u); /* g = u^2 */ + rustsecp256k1_v0_11_fe_mul(&q, &s, &g); /* q = s*u^2 */ + rustsecp256k1_v0_11_fe_mul_int(&q, 3); /* q = 3*s*u^2 */ + rustsecp256k1_v0_11_fe_mul(&g, &g, &u); /* g = u^3 */ + rustsecp256k1_v0_11_fe_mul_int(&g, 4); /* g = 4*u^3 */ + rustsecp256k1_v0_11_fe_add_int(&g, 4 * SECP256K1_B); /* g = 4*(u^3+7) */ + rustsecp256k1_v0_11_fe_add(&q, &g); /* q = 4*(u^3+7)+3*s*u^2 */ + rustsecp256k1_v0_11_fe_mul(&q, &q, &s); /* q = s*(4*(u^3+7)+3*u^2*s) */ + rustsecp256k1_v0_11_fe_negate(&q, &q, 1); /* q = -s*(4*(u^3+7)+3*u^2*s) */ + if (!rustsecp256k1_v0_11_fe_is_square_var(&q)) return 0; + ret = rustsecp256k1_v0_11_fe_sqrt(&r, &q); /* r = sqrt(-s*(4*(u^3+7)+3*u^2*s)) */ +#ifdef VERIFY + VERIFY_CHECK(ret); +#else + (void)ret; +#endif + + /* If (c & 1) = 1 and r = 0, fail. */ + if (EXPECT((c & 1) && rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&r), 0)) return 0; + + /* If s = 0, fail. */ + if (EXPECT(rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&s), 0)) return 0; + + /* Let v = (r/s-u)/2. */ + rustsecp256k1_v0_11_fe_inv_var(&v, &s); /* v = 1/s [no div by 0] */ + rustsecp256k1_v0_11_fe_mul(&v, &v, &r); /* v = r/s */ + rustsecp256k1_v0_11_fe_add(&v, &m); /* v = r/s-u */ + rustsecp256k1_v0_11_fe_half(&v); /* v = (r/s-u)/2 */ + } + + /* Let w = sqrt(s). */ + ret = rustsecp256k1_v0_11_fe_sqrt(&m, &s); /* m = sqrt(s) = w */ + VERIFY_CHECK(ret); + + /* Return logic. */ + if ((c & 5) == 0 || (c & 5) == 5) { + rustsecp256k1_v0_11_fe_negate(&m, &m, 1); /* m = -w */ + } + /* Now m = {-w if c&5=0 or c&5=5; w otherwise}. */ + rustsecp256k1_v0_11_fe_mul(&u, &u, c&1 ? &rustsecp256k1_v0_11_ellswift_c4 : &rustsecp256k1_v0_11_ellswift_c3); + /* u = {c4 if c&1=1; c3 otherwise}*u */ + rustsecp256k1_v0_11_fe_add(&u, &v); /* u = {c4 if c&1=1; c3 otherwise}*u + v */ + rustsecp256k1_v0_11_fe_mul(t, &m, &u); + return 1; +} + +/** Use SHA256 as a PRNG, returning SHA256(hasher || cnt). + * + * hasher is a SHA256 object to which an incrementing 4-byte counter is written to generate randomness. + * Writing 13 bytes (4 bytes for counter, plus 9 bytes for the SHA256 padding) cannot cross a + * 64-byte block size boundary (to make sure it only triggers a single SHA256 compression). */ +static void rustsecp256k1_v0_11_ellswift_prng(unsigned char* out32, const rustsecp256k1_v0_11_sha256 *hasher, uint32_t cnt) { + rustsecp256k1_v0_11_sha256 hash = *hasher; + unsigned char buf4[4]; +#ifdef VERIFY + size_t blocks = hash.bytes >> 6; +#endif + buf4[0] = cnt; + buf4[1] = cnt >> 8; + buf4[2] = cnt >> 16; + buf4[3] = cnt >> 24; + rustsecp256k1_v0_11_sha256_write(&hash, buf4, 4); + rustsecp256k1_v0_11_sha256_finalize(&hash, out32); + + /* Writing and finalizing together should trigger exactly one SHA256 compression. */ + VERIFY_CHECK(((hash.bytes) >> 6) == (blocks + 1)); +} + +/** Find an ElligatorSwift encoding (u, t) for X coordinate x, and random Y coordinate. + * + * u32 is the 32-byte big endian encoding of u; t is the output field element t that still + * needs encoding. + * + * hasher is a hasher in the rustsecp256k1_v0_11_ellswift_prng sense, with the same restrictions. */ +static void rustsecp256k1_v0_11_ellswift_xelligatorswift_var(unsigned char *u32, rustsecp256k1_v0_11_fe *t, const rustsecp256k1_v0_11_fe *x, const rustsecp256k1_v0_11_sha256 *hasher) { + /* Pool of 3-bit branch values. */ + unsigned char branch_hash[32]; + /* Number of 3-bit values in branch_hash left. */ + int branches_left = 0; + /* Field elements u and branch values are extracted from RNG based on hasher for consecutive + * values of cnt. cnt==0 is first used to populate a pool of 64 4-bit branch values. The 64 + * cnt values that follow are used to generate field elements u. cnt==65 (and multiples + * thereof) are used to repopulate the pool and start over, if that were ever necessary. + * On average, 4 iterations are needed. */ + uint32_t cnt = 0; + while (1) { + int branch; + rustsecp256k1_v0_11_fe u; + /* If the pool of branch values is empty, populate it. */ + if (branches_left == 0) { + rustsecp256k1_v0_11_ellswift_prng(branch_hash, hasher, cnt++); + branches_left = 64; + } + /* Take a 3-bit branch value from the branch pool (top bit is discarded). */ + --branches_left; + branch = (branch_hash[branches_left >> 1] >> ((branches_left & 1) << 2)) & 7; + /* Compute a new u value by hashing. */ + rustsecp256k1_v0_11_ellswift_prng(u32, hasher, cnt++); + /* overflow is not a problem (we prefer uniform u32 over uniform u). */ + rustsecp256k1_v0_11_fe_set_b32_mod(&u, u32); + /* Since u is the output of a hash, it should practically never be 0. We could apply the + * u=0 to u=1 correction here too to deal with that case still, but it's such a low + * probability event that we do not bother. */ + VERIFY_CHECK(!rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&u)); + + /* Find a remainder t, and return it if found. */ + if (EXPECT(rustsecp256k1_v0_11_ellswift_xswiftec_inv_var(t, x, &u, branch), 0)) break; + } +} + +/** Find an ElligatorSwift encoding (u, t) for point P. + * + * This is similar rustsecp256k1_v0_11_ellswift_xelligatorswift_var, except it takes a full group element p + * as input, and returns an encoding that matches the provided Y coordinate rather than a random + * one. + */ +static void rustsecp256k1_v0_11_ellswift_elligatorswift_var(unsigned char *u32, rustsecp256k1_v0_11_fe *t, const rustsecp256k1_v0_11_ge *p, const rustsecp256k1_v0_11_sha256 *hasher) { + rustsecp256k1_v0_11_ellswift_xelligatorswift_var(u32, t, &p->x, hasher); + rustsecp256k1_v0_11_fe_normalize_var(t); + if (rustsecp256k1_v0_11_fe_is_odd(t) != rustsecp256k1_v0_11_fe_is_odd(&p->y)) { + rustsecp256k1_v0_11_fe_negate(t, t, 1); + rustsecp256k1_v0_11_fe_normalize_var(t); + } +} + +/** Set hash state to the BIP340 tagged hash midstate for "rustsecp256k1_v0_11_ellswift_encode". */ +static void rustsecp256k1_v0_11_ellswift_sha256_init_encode(rustsecp256k1_v0_11_sha256* hash) { + rustsecp256k1_v0_11_sha256_initialize(hash); + hash->s[0] = 0xd1a6524bul; + hash->s[1] = 0x028594b3ul; + hash->s[2] = 0x96e42f4eul; + hash->s[3] = 0x1037a177ul; + hash->s[4] = 0x1b8fcb8bul; + hash->s[5] = 0x56023885ul; + hash->s[6] = 0x2560ede1ul; + hash->s[7] = 0xd626b715ul; + + hash->bytes = 64; +} + +int rustsecp256k1_v0_11_ellswift_encode(const rustsecp256k1_v0_11_context *ctx, unsigned char *ell64, const rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *rnd32) { + rustsecp256k1_v0_11_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(ell64 != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(rnd32 != NULL); + + if (rustsecp256k1_v0_11_pubkey_load(ctx, &p, pubkey)) { + rustsecp256k1_v0_11_fe t; + unsigned char p64[64] = {0}; + size_t ser_size; + int ser_ret; + rustsecp256k1_v0_11_sha256 hash; + + /* Set up hasher state; the used RNG is H(pubkey || "\x00"*31 || rnd32 || cnt++), using + * BIP340 tagged hash with tag "rustsecp256k1_v0_11_ellswift_encode". */ + rustsecp256k1_v0_11_ellswift_sha256_init_encode(&hash); + ser_ret = rustsecp256k1_v0_11_eckey_pubkey_serialize(&p, p64, &ser_size, 1); +#ifdef VERIFY + VERIFY_CHECK(ser_ret && ser_size == 33); +#else + (void)ser_ret; +#endif + rustsecp256k1_v0_11_sha256_write(&hash, p64, sizeof(p64)); + rustsecp256k1_v0_11_sha256_write(&hash, rnd32, 32); + + /* Compute ElligatorSwift encoding and construct output. */ + rustsecp256k1_v0_11_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */ + rustsecp256k1_v0_11_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */ + return 1; + } + /* Only reached in case the provided pubkey is invalid. */ + memset(ell64, 0, 64); + return 0; +} + +/** Set hash state to the BIP340 tagged hash midstate for "rustsecp256k1_v0_11_ellswift_create". */ +static void rustsecp256k1_v0_11_ellswift_sha256_init_create(rustsecp256k1_v0_11_sha256* hash) { + rustsecp256k1_v0_11_sha256_initialize(hash); + hash->s[0] = 0xd29e1bf5ul; + hash->s[1] = 0xf7025f42ul; + hash->s[2] = 0x9b024773ul; + hash->s[3] = 0x094cb7d5ul; + hash->s[4] = 0xe59ed789ul; + hash->s[5] = 0x03bc9786ul; + hash->s[6] = 0x68335b35ul; + hash->s[7] = 0x4e363b53ul; + + hash->bytes = 64; +} + +int rustsecp256k1_v0_11_ellswift_create(const rustsecp256k1_v0_11_context *ctx, unsigned char *ell64, const unsigned char *seckey32, const unsigned char *auxrnd32) { + rustsecp256k1_v0_11_ge p; + rustsecp256k1_v0_11_fe t; + rustsecp256k1_v0_11_sha256 hash; + rustsecp256k1_v0_11_scalar seckey_scalar; + int ret; + static const unsigned char zero32[32] = {0}; + + /* Sanity check inputs. */ + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(ell64 != NULL); + memset(ell64, 0, 64); + ARG_CHECK(rustsecp256k1_v0_11_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey32 != NULL); + + /* Compute (affine) public key */ + ret = rustsecp256k1_v0_11_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey32); + rustsecp256k1_v0_11_declassify(ctx, &p, sizeof(p)); /* not constant time in produced pubkey */ + rustsecp256k1_v0_11_fe_normalize_var(&p.x); + rustsecp256k1_v0_11_fe_normalize_var(&p.y); + + /* Set up hasher state. The used RNG is H(privkey || "\x00"*32 [|| auxrnd32] || cnt++), + * using BIP340 tagged hash with tag "rustsecp256k1_v0_11_ellswift_create". */ + rustsecp256k1_v0_11_ellswift_sha256_init_create(&hash); + rustsecp256k1_v0_11_sha256_write(&hash, seckey32, 32); + rustsecp256k1_v0_11_sha256_write(&hash, zero32, sizeof(zero32)); + rustsecp256k1_v0_11_declassify(ctx, &hash, sizeof(hash)); /* private key is hashed now */ + if (auxrnd32) rustsecp256k1_v0_11_sha256_write(&hash, auxrnd32, 32); + + /* Compute ElligatorSwift encoding and construct output. */ + rustsecp256k1_v0_11_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */ + rustsecp256k1_v0_11_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */ + + rustsecp256k1_v0_11_memczero(ell64, 64, !ret); + rustsecp256k1_v0_11_scalar_clear(&seckey_scalar); + + return ret; +} + +int rustsecp256k1_v0_11_ellswift_decode(const rustsecp256k1_v0_11_context *ctx, rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *ell64) { + rustsecp256k1_v0_11_fe u, t; + rustsecp256k1_v0_11_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(ell64 != NULL); + + rustsecp256k1_v0_11_fe_set_b32_mod(&u, ell64); + rustsecp256k1_v0_11_fe_set_b32_mod(&t, ell64 + 32); + rustsecp256k1_v0_11_fe_normalize_var(&t); + rustsecp256k1_v0_11_ellswift_swiftec_var(&p, &u, &t); + rustsecp256k1_v0_11_pubkey_save(pubkey, &p); + return 1; +} + +static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { + rustsecp256k1_v0_11_sha256 sha; + + rustsecp256k1_v0_11_sha256_initialize(&sha); + rustsecp256k1_v0_11_sha256_write(&sha, data, 64); + rustsecp256k1_v0_11_sha256_write(&sha, ell_a64, 64); + rustsecp256k1_v0_11_sha256_write(&sha, ell_b64, 64); + rustsecp256k1_v0_11_sha256_write(&sha, x32, 32); + rustsecp256k1_v0_11_sha256_finalize(&sha, output); + rustsecp256k1_v0_11_sha256_clear(&sha); + + return 1; +} + +/** Set hash state to the BIP340 tagged hash midstate for "bip324_ellswift_xonly_ecdh". */ +static void rustsecp256k1_v0_11_ellswift_sha256_init_bip324(rustsecp256k1_v0_11_sha256* hash) { + rustsecp256k1_v0_11_sha256_initialize(hash); + hash->s[0] = 0x8c12d730ul; + hash->s[1] = 0x827bd392ul; + hash->s[2] = 0x9e4fb2eeul; + hash->s[3] = 0x207b373eul; + hash->s[4] = 0x2292bd7aul; + hash->s[5] = 0xaa5441bcul; + hash->s[6] = 0x15c3779ful; + hash->s[7] = 0xcfb52549ul; + + hash->bytes = 64; +} + +static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { + rustsecp256k1_v0_11_sha256 sha; + + (void)data; + + rustsecp256k1_v0_11_ellswift_sha256_init_bip324(&sha); + rustsecp256k1_v0_11_sha256_write(&sha, ell_a64, 64); + rustsecp256k1_v0_11_sha256_write(&sha, ell_b64, 64); + rustsecp256k1_v0_11_sha256_write(&sha, x32, 32); + rustsecp256k1_v0_11_sha256_finalize(&sha, output); + rustsecp256k1_v0_11_sha256_clear(&sha); + + return 1; +} + +const rustsecp256k1_v0_11_ellswift_xdh_hash_function rustsecp256k1_v0_11_ellswift_xdh_hash_function_prefix = ellswift_xdh_hash_function_prefix; +const rustsecp256k1_v0_11_ellswift_xdh_hash_function rustsecp256k1_v0_11_ellswift_xdh_hash_function_bip324 = ellswift_xdh_hash_function_bip324; + +int rustsecp256k1_v0_11_ellswift_xdh(const rustsecp256k1_v0_11_context *ctx, unsigned char *output, const unsigned char *ell_a64, const unsigned char *ell_b64, const unsigned char *seckey32, int party, rustsecp256k1_v0_11_ellswift_xdh_hash_function hashfp, void *data) { + int ret = 0; + int overflow; + rustsecp256k1_v0_11_scalar s; + rustsecp256k1_v0_11_fe xn, xd, px, u, t; + unsigned char sx[32]; + const unsigned char* theirs64; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(ell_a64 != NULL); + ARG_CHECK(ell_b64 != NULL); + ARG_CHECK(seckey32 != NULL); + ARG_CHECK(hashfp != NULL); + + /* Load remote public key (as fraction). */ + theirs64 = party ? ell_a64 : ell_b64; + rustsecp256k1_v0_11_fe_set_b32_mod(&u, theirs64); + rustsecp256k1_v0_11_fe_set_b32_mod(&t, theirs64 + 32); + rustsecp256k1_v0_11_ellswift_xswiftec_frac_var(&xn, &xd, &u, &t); + + /* Load private key (using one if invalid). */ + rustsecp256k1_v0_11_scalar_set_b32(&s, seckey32, &overflow); + overflow = rustsecp256k1_v0_11_scalar_is_zero(&s); + rustsecp256k1_v0_11_scalar_cmov(&s, &rustsecp256k1_v0_11_scalar_one, overflow); + + /* Compute shared X coordinate. */ + rustsecp256k1_v0_11_ecmult_const_xonly(&px, &xn, &xd, &s, 1); + rustsecp256k1_v0_11_fe_normalize(&px); + rustsecp256k1_v0_11_fe_get_b32(sx, &px); + + /* Invoke hasher */ + ret = hashfp(output, sx, ell_a64, ell_b64, data); + + rustsecp256k1_v0_11_memclear(sx, sizeof(sx)); + rustsecp256k1_v0_11_fe_clear(&px); + rustsecp256k1_v0_11_scalar_clear(&s); + + return !!ret & !overflow; +} + +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/tests_exhaustive_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/tests_exhaustive_impl.h new file mode 100644 index 00000000..1c6e5e4e --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/tests_exhaustive_impl.h @@ -0,0 +1,39 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_EXHAUSTIVE_H +#define SECP256K1_MODULE_ELLSWIFT_TESTS_EXHAUSTIVE_H + +#include "../../../include/secp256k1_ellswift.h" +#include "main_impl.h" + +static void test_exhaustive_ellswift(const rustsecp256k1_v0_11_context *ctx, const rustsecp256k1_v0_11_ge *group) { + int i; + + /* Note that SwiftEC/ElligatorSwift are inherently curve operations, not + * group operations, and this test only checks the curve points which are in + * a tiny subgroup. In that sense it can't be really seen as exhaustive as + * it doesn't (and for computational reasons obviously cannot) test the + * entire domain ellswift operates under. */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + rustsecp256k1_v0_11_scalar scalar_i; + unsigned char sec32[32]; + unsigned char ell64[64]; + rustsecp256k1_v0_11_pubkey pub_decoded; + rustsecp256k1_v0_11_ge ge_decoded; + + /* Construct ellswift pubkey from exhaustive loop scalar i. */ + rustsecp256k1_v0_11_scalar_set_int(&scalar_i, i); + rustsecp256k1_v0_11_scalar_get_b32(sec32, &scalar_i); + CHECK(rustsecp256k1_v0_11_ellswift_create(ctx, ell64, sec32, NULL)); + + /* Decode ellswift pubkey and check that it matches the precomputed group element. */ + rustsecp256k1_v0_11_ellswift_decode(ctx, &pub_decoded, ell64); + rustsecp256k1_v0_11_pubkey_load(ctx, &ge_decoded, &pub_decoded); + CHECK(rustsecp256k1_v0_11_ge_eq_var(&ge_decoded, &group[i])); + } +} + +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/tests_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/tests_impl.h new file mode 100644 index 00000000..67b59097 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/ellswift/tests_impl.h @@ -0,0 +1,436 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_H +#define SECP256K1_MODULE_ELLSWIFT_TESTS_H + +#include "../../../include/secp256k1_ellswift.h" + +struct ellswift_xswiftec_inv_test { + int enc_bitmap; + rustsecp256k1_v0_11_fe u; + rustsecp256k1_v0_11_fe x; + rustsecp256k1_v0_11_fe encs[8]; +}; + +struct ellswift_decode_test { + unsigned char enc[64]; + rustsecp256k1_v0_11_fe x; + int odd_y; +}; + +struct ellswift_xdh_test { + unsigned char priv_ours[32]; + unsigned char ellswift_ours[64]; + unsigned char ellswift_theirs[64]; + int initiating; + unsigned char shared_secret[32]; +}; + +/* Set of (point, encodings) test vectors, selected to maximize branch coverage, part of the BIP324 + * test vectors. Created using an independent implementation, and tested decoding against paper + * authors' code. */ +static const struct ellswift_xswiftec_inv_test ellswift_xswiftec_inv_tests[] = { + {0xcc, SECP256K1_FE_CONST(0x05ff6bda, 0xd900fc32, 0x61bc7fe3, 0x4e2fb0f5, 0x69f06e09, 0x1ae437d3, 0xa52e9da0, 0xcbfb9590), SECP256K1_FE_CONST(0x80cdf637, 0x74ec7022, 0xc89a5a85, 0x58e373a2, 0x79170285, 0xe0ab2741, 0x2dbce510, 0xbdfe23fc), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x45654798, 0xece071ba, 0x79286d04, 0xf7f3eb1c, 0x3f1d17dd, 0x883610f2, 0xad2efd82, 0xa287466b), SECP256K1_FE_CONST(0x0aeaa886, 0xf6b76c71, 0x58452418, 0xcbf5033a, 0xdc5747e9, 0xe9b5d3b2, 0x303db969, 0x36528557), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xba9ab867, 0x131f8e45, 0x86d792fb, 0x080c14e3, 0xc0e2e822, 0x77c9ef0d, 0x52d1027c, 0x5d78b5c4), SECP256K1_FE_CONST(0xf5155779, 0x0948938e, 0xa7badbe7, 0x340afcc5, 0x23a8b816, 0x164a2c4d, 0xcfc24695, 0xc9ad76d8)}}, + {0x33, SECP256K1_FE_CONST(0x1737a85f, 0x4c8d146c, 0xec96e3ff, 0xdca76d99, 0x03dcf3bd, 0x53061868, 0xd478c78c, 0x63c2aa9e), SECP256K1_FE_CONST(0x39e48dd1, 0x50d2f429, 0xbe088dfd, 0x5b61882e, 0x7e840748, 0x3702ae9a, 0x5ab35927, 0xb15f85ea), {SECP256K1_FE_CONST(0x1be8cc0b, 0x04be0c68, 0x1d0c6a68, 0xf733f82c, 0x6c896e0c, 0x8a262fcd, 0x392918e3, 0x03a7abf4), SECP256K1_FE_CONST(0x605b5814, 0xbf9b8cb0, 0x66667c9e, 0x5480d22d, 0xc5b6c92f, 0x14b4af3e, 0xe0a9eb83, 0xb03685e3), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xe41733f4, 0xfb41f397, 0xe2f39597, 0x08cc07d3, 0x937691f3, 0x75d9d032, 0xc6d6e71b, 0xfc58503b), SECP256K1_FE_CONST(0x9fa4a7eb, 0x4064734f, 0x99998361, 0xab7f2dd2, 0x3a4936d0, 0xeb4b50c1, 0x1f56147b, 0x4fc9764c), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0x1aaa1cce, 0xbf9c7241, 0x91033df3, 0x66b36f69, 0x1c4d902c, 0x228033ff, 0x4516d122, 0xb2564f68), SECP256K1_FE_CONST(0xc7554125, 0x9d3ba98f, 0x207eaa30, 0xc69634d1, 0x87d0b6da, 0x594e719e, 0x420f4898, 0x638fc5b0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0x2323a1d0, 0x79b0fd72, 0xfc8bb62e, 0xc34230a8, 0x15cb0596, 0xc2bfac99, 0x8bd6b842, 0x60f5dc26), SECP256K1_FE_CONST(0x239342df, 0xb675500a, 0x34a19631, 0x0b8d87d5, 0x4f49dcac, 0x9da50c17, 0x43ceab41, 0xa7b249ff), {SECP256K1_FE_CONST(0xf63580b8, 0xaa49c484, 0x6de56e39, 0xe1b3e73f, 0x171e881e, 0xba8c66f6, 0x14e67e5c, 0x975dfc07), SECP256K1_FE_CONST(0xb6307b33, 0x2e699f1c, 0xf77841d9, 0x0af25365, 0x404deb7f, 0xed5edb30, 0x90db49e6, 0x42a156b6), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x09ca7f47, 0x55b63b7b, 0x921a91c6, 0x1e4c18c0, 0xe8e177e1, 0x45739909, 0xeb1981a2, 0x68a20028), SECP256K1_FE_CONST(0x49cf84cc, 0xd19660e3, 0x0887be26, 0xf50dac9a, 0xbfb21480, 0x12a124cf, 0x6f24b618, 0xbd5ea579), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0x2dc90e64, 0x0cb646ae, 0x9164c0b5, 0xa9ef0169, 0xfebe34dc, 0x4437d6e4, 0x6acb0e27, 0xe219d1e8), SECP256K1_FE_CONST(0xd236f19b, 0xf349b951, 0x6e9b3f4a, 0x5610fe96, 0x0141cb23, 0xbbc8291b, 0x9534f1d7, 0x1de62a47), {SECP256K1_FE_CONST(0xe69df7d9, 0xc026c366, 0x00ebdf58, 0x80726758, 0x47c0c431, 0xc8eb7306, 0x82533e96, 0x4b6252c9), SECP256K1_FE_CONST(0x4f18bbdf, 0x7c2d6c5f, 0x818c1880, 0x2fa35cd0, 0x69eaa79f, 0xff74e4fc, 0x837c80d9, 0x3fece2f8), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x19620826, 0x3fd93c99, 0xff1420a7, 0x7f8d98a7, 0xb83f3bce, 0x37148cf9, 0x7dacc168, 0xb49da966), SECP256K1_FE_CONST(0xb0e74420, 0x83d293a0, 0x7e73e77f, 0xd05ca32f, 0x96155860, 0x008b1b03, 0x7c837f25, 0xc0131937), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xcc, SECP256K1_FE_CONST(0x3edd7b39, 0x80e2f2f3, 0x4d1409a2, 0x07069f88, 0x1fda5f96, 0xf08027ac, 0x4465b63d, 0xc278d672), SECP256K1_FE_CONST(0x053a98de, 0x4a27b196, 0x1155822b, 0x3a3121f0, 0x3b2a1445, 0x8bd80eb4, 0xa560c4c7, 0xa85c149c), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb3dae4b7, 0xdcf858e4, 0xc6968057, 0xcef2b156, 0x46543152, 0x6538199c, 0xf52dc1b2, 0xd62fda30), SECP256K1_FE_CONST(0x4aa77dd5, 0x5d6b6d3c, 0xfa10cc9d, 0x0fe42f79, 0x232e4575, 0x661049ae, 0x36779c1d, 0x0c666d88), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x4c251b48, 0x2307a71b, 0x39697fa8, 0x310d4ea9, 0xb9abcead, 0x9ac7e663, 0x0ad23e4c, 0x29d021ff), SECP256K1_FE_CONST(0xb558822a, 0xa29492c3, 0x05ef3362, 0xf01bd086, 0xdcd1ba8a, 0x99efb651, 0xc98863e1, 0xf3998ea7)}}, + {0x00, SECP256K1_FE_CONST(0x4295737e, 0xfcb1da6f, 0xb1d96b9c, 0xa7dcd1e3, 0x20024b37, 0xa736c494, 0x8b625981, 0x73069f70), SECP256K1_FE_CONST(0xfa7ffe4f, 0x25f88362, 0x831c087a, 0xfe2e8a9b, 0x0713e2ca, 0xc1ddca6a, 0x383205a2, 0x66f14307), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xff, SECP256K1_FE_CONST(0x587c1a0c, 0xee91939e, 0x7f784d23, 0xb963004a, 0x3bf44f5d, 0x4e32a008, 0x1995ba20, 0xb0fca59e), SECP256K1_FE_CONST(0x2ea98853, 0x0715e8d1, 0x0363907f, 0xf2512452, 0x4d471ba2, 0x454d5ce3, 0xbe3f0419, 0x4dfd3a3c), {SECP256K1_FE_CONST(0xcfd5a094, 0xaa0b9b88, 0x91b76c6a, 0xb9438f66, 0xaa1c095a, 0x65f9f701, 0x35e81712, 0x92245e74), SECP256K1_FE_CONST(0xa89057d7, 0xc6563f0d, 0x6efa19ae, 0x84412b8a, 0x7b47e791, 0xa191ecdf, 0xdf2af84f, 0xd97bc339), SECP256K1_FE_CONST(0x475d0ae9, 0xef46920d, 0xf07b3411, 0x7be5a081, 0x7de1023e, 0x3cc32689, 0xe9be145b, 0x406b0aef), SECP256K1_FE_CONST(0xa0759178, 0xad802324, 0x54f827ef, 0x05ea3e72, 0xad8d7541, 0x8e6d4cc1, 0xcd4f5306, 0xc5e7c453), SECP256K1_FE_CONST(0x302a5f6b, 0x55f46477, 0x6e489395, 0x46bc7099, 0x55e3f6a5, 0x9a0608fe, 0xca17e8ec, 0x6ddb9dbb), SECP256K1_FE_CONST(0x576fa828, 0x39a9c0f2, 0x9105e651, 0x7bbed475, 0x84b8186e, 0x5e6e1320, 0x20d507af, 0x268438f6), SECP256K1_FE_CONST(0xb8a2f516, 0x10b96df2, 0x0f84cbee, 0x841a5f7e, 0x821efdc1, 0xc33cd976, 0x1641eba3, 0xbf94f140), SECP256K1_FE_CONST(0x5f8a6e87, 0x527fdcdb, 0xab07d810, 0xfa15c18d, 0x52728abe, 0x7192b33e, 0x32b0acf8, 0x3a1837dc)}}, + {0xcc, SECP256K1_FE_CONST(0x5fa88b33, 0x65a635cb, 0xbcee003c, 0xce9ef51d, 0xd1a310de, 0x277e441a, 0xbccdb7be, 0x1e4ba249), SECP256K1_FE_CONST(0x79461ff6, 0x2bfcbcac, 0x4249ba84, 0xdd040f2c, 0xec3c63f7, 0x25204dc7, 0xf464c16b, 0xf0ff3170), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x6bb700e1, 0xf4d7e236, 0xe8d193ff, 0x4a76c1b3, 0xbcd4e2b2, 0x5acac3d5, 0x1c8dac65, 0x3fe909a0), SECP256K1_FE_CONST(0xf4c73410, 0x633da7f6, 0x3a4f1d55, 0xaec6dd32, 0xc4c6d89e, 0xe74075ed, 0xb5515ed9, 0x0da9e683), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x9448ff1e, 0x0b281dc9, 0x172e6c00, 0xb5893e4c, 0x432b1d4d, 0xa5353c2a, 0xe3725399, 0xc016f28f), SECP256K1_FE_CONST(0x0b38cbef, 0x9cc25809, 0xc5b0e2aa, 0x513922cd, 0x3b392761, 0x18bf8a12, 0x4aaea125, 0xf25615ac)}}, + {0xcc, SECP256K1_FE_CONST(0x6fb31c75, 0x31f03130, 0xb42b155b, 0x952779ef, 0xbb46087d, 0xd9807d24, 0x1a48eac6, 0x3c3d96d6), SECP256K1_FE_CONST(0x56f81be7, 0x53e8d4ae, 0x4940ea6f, 0x46f6ec9f, 0xda66a6f9, 0x6cc95f50, 0x6cb2b574, 0x90e94260), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x59059774, 0x795bdb7a, 0x837fbe11, 0x40a5fa59, 0x984f48af, 0x8df95d57, 0xdd6d1c05, 0x437dcec1), SECP256K1_FE_CONST(0x22a644db, 0x79376ad4, 0xe7b3a009, 0xe58b3f13, 0x137c54fd, 0xf911122c, 0xc93667c4, 0x7077d784), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xa6fa688b, 0x86a42485, 0x7c8041ee, 0xbf5a05a6, 0x67b0b750, 0x7206a2a8, 0x2292e3f9, 0xbc822d6e), SECP256K1_FE_CONST(0xdd59bb24, 0x86c8952b, 0x184c5ff6, 0x1a74c0ec, 0xec83ab02, 0x06eeedd3, 0x36c9983a, 0x8f8824ab)}}, + {0x00, SECP256K1_FE_CONST(0x704cd226, 0xe71cb682, 0x6a590e80, 0xdac90f2d, 0x2f5830f0, 0xfdf135a3, 0xeae3965b, 0xff25ff12), SECP256K1_FE_CONST(0x138e0afa, 0x68936ee6, 0x70bd2b8d, 0xb53aedbb, 0x7bea2a85, 0x97388b24, 0xd0518edd, 0x22ad66ec), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0x725e9147, 0x92cb8c89, 0x49e7e116, 0x8b7cdd8a, 0x8094c91c, 0x6ec2202c, 0xcd53a6a1, 0x8771edeb), SECP256K1_FE_CONST(0x8da16eb8, 0x6d347376, 0xb6181ee9, 0x74832275, 0x7f6b36e3, 0x913ddfd3, 0x32ac595d, 0x788e0e44), {SECP256K1_FE_CONST(0xdd357786, 0xb9f68733, 0x30391aa5, 0x62580965, 0x4e43116e, 0x82a5a5d8, 0x2ffd1d66, 0x24101fc4), SECP256K1_FE_CONST(0xa0b7efca, 0x01814594, 0xc59c9aae, 0x8e497001, 0x86ca5d95, 0xe88bcc80, 0x399044d9, 0xc2d8613d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x22ca8879, 0x460978cc, 0xcfc6e55a, 0x9da7f69a, 0xb1bcee91, 0x7d5a5a27, 0xd002e298, 0xdbefdc6b), SECP256K1_FE_CONST(0x5f481035, 0xfe7eba6b, 0x3a636551, 0x71b68ffe, 0x7935a26a, 0x1774337f, 0xc66fbb25, 0x3d279af2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0x78fe6b71, 0x7f2ea4a3, 0x2708d79c, 0x151bf503, 0xa5312a18, 0xc0963437, 0xe865cc6e, 0xd3f6ae97), SECP256K1_FE_CONST(0x8701948e, 0x80d15b5c, 0xd8f72863, 0xeae40afc, 0x5aced5e7, 0x3f69cbc8, 0x179a3390, 0x2c094d98), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x44, SECP256K1_FE_CONST(0x7c37bb9c, 0x5061dc07, 0x413f11ac, 0xd5a34006, 0xe64c5c45, 0x7fdb9a43, 0x8f217255, 0xa961f50d), SECP256K1_FE_CONST(0x5c1a76b4, 0x4568eb59, 0xd6789a74, 0x42d9ed7c, 0xdc6226b7, 0x752b4ff8, 0xeaf8e1a9, 0x5736e507), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb94d30cd, 0x7dbff60b, 0x64620c17, 0xca0fafaa, 0x40b3d1f5, 0x2d077a60, 0xa2e0cafd, 0x145086c2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x46b2cf32, 0x824009f4, 0x9b9df3e8, 0x35f05055, 0xbf4c2e0a, 0xd2f8859f, 0x5d1f3501, 0xebaf756d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0x82388888, 0x967f82a6, 0xb444438a, 0x7d44838e, 0x13c0d478, 0xb9ca060d, 0xa95a41fb, 0x94303de6), SECP256K1_FE_CONST(0x29e96541, 0x70628fec, 0x8b497289, 0x8b113cf9, 0x8807f460, 0x9274f4f3, 0x140d0674, 0x157c90a0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0x91298f57, 0x70af7a27, 0xf0a47188, 0xd24c3b7b, 0xf98ab299, 0x0d84b0b8, 0x98507e3c, 0x561d6472), SECP256K1_FE_CONST(0x144f4ccb, 0xd9a74698, 0xa88cbf6f, 0xd00ad886, 0xd339d29e, 0xa19448f2, 0xc572cac0, 0xa07d5562), {SECP256K1_FE_CONST(0xe6a0ffa3, 0x807f09da, 0xdbe71e0f, 0x4be4725f, 0x2832e76c, 0xad8dc1d9, 0x43ce8393, 0x75eff248), SECP256K1_FE_CONST(0x837b8e68, 0xd4917544, 0x764ad090, 0x3cb11f86, 0x15d2823c, 0xefbb06d8, 0x9049dbab, 0xc69befda), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x195f005c, 0x7f80f625, 0x2418e1f0, 0xb41b8da0, 0xd7cd1893, 0x52723e26, 0xbc317c6b, 0x8a1009e7), SECP256K1_FE_CONST(0x7c847197, 0x2b6e8abb, 0x89b52f6f, 0xc34ee079, 0xea2d7dc3, 0x1044f927, 0x6fb62453, 0x39640c55), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0xb682f3d0, 0x3bbb5dee, 0x4f54b5eb, 0xfba931b4, 0xf52f6a19, 0x1e5c2f48, 0x3c73c66e, 0x9ace97e1), SECP256K1_FE_CONST(0x904717bf, 0x0bc0cb78, 0x73fcdc38, 0xaa97f19e, 0x3a626309, 0x72acff92, 0xb24cc6dd, 0xa197cb96), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x77, SECP256K1_FE_CONST(0xc17ec69e, 0x665f0fb0, 0xdbab48d9, 0xc2f94d12, 0xec8a9d7e, 0xacb58084, 0x83309180, 0x1eb0b80b), SECP256K1_FE_CONST(0x147756e6, 0x6d96e31c, 0x426d3cc8, 0x5ed0c4cf, 0xbef6341d, 0xd8b28558, 0x5aa574ea, 0x0204b55e), {SECP256K1_FE_CONST(0x6f4aea43, 0x1a0043bd, 0xd03134d6, 0xd9159119, 0xce034b88, 0xc32e50e8, 0xe36c4ee4, 0x5eac7ae9), SECP256K1_FE_CONST(0xfd5be16d, 0x4ffa2690, 0x126c67c3, 0xef7cb9d2, 0x9b74d397, 0xc78b06b3, 0x605fda34, 0xdc9696a6), SECP256K1_FE_CONST(0x5e9c6079, 0x2a2f000e, 0x45c6250f, 0x296f875e, 0x174efc0e, 0x9703e628, 0x706103a9, 0xdd2d82c7), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x90b515bc, 0xe5ffbc42, 0x2fcecb29, 0x26ea6ee6, 0x31fcb477, 0x3cd1af17, 0x1c93b11a, 0xa1538146), SECP256K1_FE_CONST(0x02a41e92, 0xb005d96f, 0xed93983c, 0x1083462d, 0x648b2c68, 0x3874f94c, 0x9fa025ca, 0x23696589), SECP256K1_FE_CONST(0xa1639f86, 0xd5d0fff1, 0xba39daf0, 0xd69078a1, 0xe8b103f1, 0x68fc19d7, 0x8f9efc55, 0x22d27968), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xcc, SECP256K1_FE_CONST(0xc25172fc, 0x3f29b6fc, 0x4a1155b8, 0x57523315, 0x5486b274, 0x64b74b8b, 0x260b499a, 0x3f53cb14), SECP256K1_FE_CONST(0x1ea9cbdb, 0x35cf6e03, 0x29aa31b0, 0xbb0a702a, 0x65123ed0, 0x08655a93, 0xb7dcd528, 0x0e52e1ab), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x7422edc7, 0x843136af, 0x0053bb88, 0x54448a82, 0x99994f9d, 0xdcefd3a9, 0xa92d4546, 0x2c59298a), SECP256K1_FE_CONST(0x78c7774a, 0x266f8b97, 0xea23d05d, 0x064f033c, 0x77319f92, 0x3f6b78bc, 0xe4e20bf0, 0x5fa5398d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x8bdd1238, 0x7bcec950, 0xffac4477, 0xabbb757d, 0x6666b062, 0x23102c56, 0x56d2bab8, 0xd3a6d2a5), SECP256K1_FE_CONST(0x873888b5, 0xd9907468, 0x15dc2fa2, 0xf9b0fcc3, 0x88ce606d, 0xc0948743, 0x1b1df40e, 0xa05ac2a2)}}, + {0x00, SECP256K1_FE_CONST(0xcab6626f, 0x832a4b12, 0x80ba7add, 0x2fc5322f, 0xf011caed, 0xedf7ff4d, 0xb6735d50, 0x26dc0367), SECP256K1_FE_CONST(0x2b2bef08, 0x52c6f7c9, 0x5d72ac99, 0xa23802b8, 0x75029cd5, 0x73b248d1, 0xf1b3fc80, 0x33788eb6), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0xd8621b4f, 0xfc85b9ed, 0x56e99d8d, 0xd1dd24ae, 0xdcecb147, 0x63b861a1, 0x7112dc77, 0x1a104fd2), SECP256K1_FE_CONST(0x812cabe9, 0x72a22aa6, 0x7c7da0c9, 0x4d8a9362, 0x96eb9949, 0xd70c37cb, 0x2b248757, 0x4cb3ce58), {SECP256K1_FE_CONST(0xfbc5febc, 0x6fdbc9ae, 0x3eb88a93, 0xb982196e, 0x8b6275a6, 0xd5a73c17, 0x387e000c, 0x711bd0e3), SECP256K1_FE_CONST(0x8724c96b, 0xd4e5527f, 0x2dd195a5, 0x1c468d2d, 0x211ba2fa, 0xc7cbe0b4, 0xb3434253, 0x409fb42d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x043a0143, 0x90243651, 0xc147756c, 0x467de691, 0x749d8a59, 0x2a58c3e8, 0xc781fff2, 0x8ee42b4c), SECP256K1_FE_CONST(0x78db3694, 0x2b1aad80, 0xd22e6a5a, 0xe3b972d2, 0xdee45d05, 0x38341f4b, 0x4cbcbdab, 0xbf604802), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0xda463164, 0xc6f4bf71, 0x29ee5f0e, 0xc00f65a6, 0x75a8adf1, 0xbd931b39, 0xb64806af, 0xdcda9a22), SECP256K1_FE_CONST(0x25b9ce9b, 0x390b408e, 0xd611a0f1, 0x3ff09a59, 0x8a57520e, 0x426ce4c6, 0x49b7f94f, 0x2325620d), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xcc, SECP256K1_FE_CONST(0xdafc971e, 0x4a3a7b6d, 0xcfb42a08, 0xd9692d82, 0xad9e7838, 0x523fcbda, 0x1d4827e1, 0x4481ae2d), SECP256K1_FE_CONST(0x250368e1, 0xb5c58492, 0x304bd5f7, 0x2696d27d, 0x526187c7, 0xadc03425, 0xe2b7d81d, 0xbb7e4e02), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x370c28f1, 0xbe665efa, 0xcde6aa43, 0x6bf86fe2, 0x1e6e314c, 0x1e53dd04, 0x0e6c73a4, 0x6b4c8c49), SECP256K1_FE_CONST(0xcd8acee9, 0x8ffe5653, 0x1a84d7eb, 0x3e48fa40, 0x34206ce8, 0x25ace907, 0xd0edf0ea, 0xeb5e9ca2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xc8f3d70e, 0x4199a105, 0x321955bc, 0x9407901d, 0xe191ceb3, 0xe1ac22fb, 0xf1938c5a, 0x94b36fe6), SECP256K1_FE_CONST(0x32753116, 0x7001a9ac, 0xe57b2814, 0xc1b705bf, 0xcbdf9317, 0xda5316f8, 0x2f120f14, 0x14a15f8d)}}, + {0x44, SECP256K1_FE_CONST(0xe0294c8b, 0xc1a36b41, 0x66ee92bf, 0xa70a5c34, 0x976fa982, 0x9405efea, 0x8f9cd54d, 0xcb29b99e), SECP256K1_FE_CONST(0xae9690d1, 0x3b8d20a0, 0xfbbf37be, 0xd8474f67, 0xa04e142f, 0x56efd787, 0x70a76b35, 0x9165d8a1), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xdcd45d93, 0x5613916a, 0xf167b029, 0x058ba3a7, 0x00d37150, 0xb9df3472, 0x8cb05412, 0xc16d4182), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x232ba26c, 0xa9ec6e95, 0x0e984fd6, 0xfa745c58, 0xff2c8eaf, 0x4620cb8d, 0x734fabec, 0x3e92baad), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0xe148441c, 0xd7b92b8b, 0x0e4fa3bd, 0x68712cfd, 0x0d709ad1, 0x98cace61, 0x1493c10e, 0x97f5394e), SECP256K1_FE_CONST(0x164a6397, 0x94d74c53, 0xafc4d329, 0x4e79cdb3, 0xcd25f99f, 0x6df45c00, 0x0f758aba, 0x54d699c0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xff, SECP256K1_FE_CONST(0xe4b00ec9, 0x7aadcca9, 0x7644d3b0, 0xc8a931b1, 0x4ce7bcf7, 0xbc877954, 0x6d6e35aa, 0x5937381c), SECP256K1_FE_CONST(0x94e9588d, 0x41647b3f, 0xcc772dc8, 0xd83c67ce, 0x3be00353, 0x8517c834, 0x103d2cd4, 0x9d62ef4d), {SECP256K1_FE_CONST(0xc88d25f4, 0x1407376b, 0xb2c03a7f, 0xffeb3ec7, 0x811cc434, 0x91a0c3aa, 0xc0378cdc, 0x78357bee), SECP256K1_FE_CONST(0x51c02636, 0xce00c234, 0x5ecd89ad, 0xb6089fe4, 0xd5e18ac9, 0x24e3145e, 0x6669501c, 0xd37a00d4), SECP256K1_FE_CONST(0x205b3512, 0xdb40521c, 0xb200952e, 0x67b46f67, 0xe09e7839, 0xe0de4400, 0x4138329e, 0xbd9138c5), SECP256K1_FE_CONST(0x58aab390, 0xab6fb55c, 0x1d1b8089, 0x7a207ce9, 0x4a78fa5b, 0x4aa61a33, 0x398bcae9, 0xadb20d3e), SECP256K1_FE_CONST(0x3772da0b, 0xebf8c894, 0x4d3fc580, 0x0014c138, 0x7ee33bcb, 0x6e5f3c55, 0x3fc87322, 0x87ca8041), SECP256K1_FE_CONST(0xae3fd9c9, 0x31ff3dcb, 0xa1327652, 0x49f7601b, 0x2a1e7536, 0xdb1ceba1, 0x9996afe2, 0x2c85fb5b), SECP256K1_FE_CONST(0xdfa4caed, 0x24bfade3, 0x4dff6ad1, 0x984b9098, 0x1f6187c6, 0x1f21bbff, 0xbec7cd60, 0x426ec36a), SECP256K1_FE_CONST(0xa7554c6f, 0x54904aa3, 0xe2e47f76, 0x85df8316, 0xb58705a4, 0xb559e5cc, 0xc6743515, 0x524deef1)}}, + {0x00, SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xff, SECP256K1_FE_CONST(0xe6bcb5c3, 0xd63467d4, 0x90bfa54f, 0xbbc6092a, 0x7248c25e, 0x11b248dc, 0x2964a6e1, 0x5edb1457), SECP256K1_FE_CONST(0x19434a3c, 0x29cb982b, 0x6f405ab0, 0x4439f6d5, 0x8db73da1, 0xee4db723, 0xd69b591d, 0xa124e7d8), {SECP256K1_FE_CONST(0x67119877, 0x832ab8f4, 0x59a82165, 0x6d8261f5, 0x44a553b8, 0x9ae4f25c, 0x52a97134, 0xb70f3426), SECP256K1_FE_CONST(0xffee02f5, 0xe649c07f, 0x0560eff1, 0x867ec7b3, 0x2d0e595e, 0x9b1c0ea6, 0xe2a4fc70, 0xc97cd71f), SECP256K1_FE_CONST(0xb5e0c189, 0xeb5b4bac, 0xd025b744, 0x4d74178b, 0xe8d5246c, 0xfa4a9a20, 0x7964a057, 0xee969992), SECP256K1_FE_CONST(0x5746e459, 0x1bf7f4c3, 0x044609ea, 0x372e9086, 0x03975d27, 0x9fdef834, 0x9f0b08d3, 0x2f07619d), SECP256K1_FE_CONST(0x98ee6788, 0x7cd5470b, 0xa657de9a, 0x927d9e0a, 0xbb5aac47, 0x651b0da3, 0xad568eca, 0x48f0c809), SECP256K1_FE_CONST(0x0011fd0a, 0x19b63f80, 0xfa9f100e, 0x7981384c, 0xd2f1a6a1, 0x64e3f159, 0x1d5b038e, 0x36832510), SECP256K1_FE_CONST(0x4a1f3e76, 0x14a4b453, 0x2fda48bb, 0xb28be874, 0x172adb93, 0x05b565df, 0x869b5fa7, 0x1169629d), SECP256K1_FE_CONST(0xa8b91ba6, 0xe4080b3c, 0xfbb9f615, 0xc8d16f79, 0xfc68a2d8, 0x602107cb, 0x60f4f72b, 0xd0f89a92)}}, + {0x33, SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), {SECP256K1_FE_CONST(0x4f867ad8, 0xbb3d8404, 0x09d26b67, 0x307e6210, 0x0153273f, 0x72fa4b74, 0x84becfa1, 0x4ebe7408), SECP256K1_FE_CONST(0x5bbc4f59, 0xe452cc5f, 0x22a99144, 0xb10ce898, 0x9a89a995, 0xec3cea1c, 0x91ae10e8, 0xf721bb5d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb0798527, 0x44c27bfb, 0xf62d9498, 0xcf819def, 0xfeacd8c0, 0x8d05b48b, 0x7b41305d, 0xb1418827), SECP256K1_FE_CONST(0xa443b0a6, 0x1bad33a0, 0xdd566ebb, 0x4ef31767, 0x6576566a, 0x13c315e3, 0x6e51ef16, 0x08de40d2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xcc, SECP256K1_FE_CONST(0xf455605b, 0xc85bf48e, 0x3a908c31, 0x023faf98, 0x381504c6, 0xc6d3aeb9, 0xede55f8d, 0xd528924d), SECP256K1_FE_CONST(0xd31fbcd5, 0xcdb798f6, 0xc00db669, 0x2f8fe896, 0x7fa9c79d, 0xd10958f4, 0xa194f013, 0x74905e99), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x0c00c571, 0x5b56fe63, 0x2d814ad8, 0xa77f8e66, 0x628ea47a, 0x6116834f, 0x8c1218f3, 0xa03cbd50), SECP256K1_FE_CONST(0xdf88e44f, 0xac84fa52, 0xdf4d59f4, 0x8819f18f, 0x6a8cd415, 0x1d162afa, 0xf773166f, 0x57c7ff46), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xf3ff3a8e, 0xa4a9019c, 0xd27eb527, 0x58807199, 0x9d715b85, 0x9ee97cb0, 0x73ede70b, 0x5fc33edf), SECP256K1_FE_CONST(0x20771bb0, 0x537b05ad, 0x20b2a60b, 0x77e60e70, 0x95732bea, 0xe2e9d505, 0x088ce98f, 0xa837fce9)}}, + {0xff, SECP256K1_FE_CONST(0xf58cd4d9, 0x830bad32, 0x2699035e, 0x8246007d, 0x4be27e19, 0xb6f53621, 0x317b4f30, 0x9b3daa9d), SECP256K1_FE_CONST(0x78ec2b3d, 0xc0948de5, 0x60148bbc, 0x7c6dc963, 0x3ad5df70, 0xa5a5750c, 0xbed72180, 0x4f082a3b), {SECP256K1_FE_CONST(0x6c4c580b, 0x76c75940, 0x43569f9d, 0xae16dc28, 0x01c16a1f, 0xbe128608, 0x81b75f8e, 0xf929bce5), SECP256K1_FE_CONST(0x94231355, 0xe7385c5f, 0x25ca436a, 0xa6419147, 0x1aea4393, 0xd6e86ab7, 0xa35fe2af, 0xacaefd0d), SECP256K1_FE_CONST(0xdff2a195, 0x1ada6db5, 0x74df8340, 0x48149da3, 0x397a75b8, 0x29abf58c, 0x7e69db1b, 0x41ac0989), SECP256K1_FE_CONST(0xa52b66d3, 0xc9070355, 0x48028bf8, 0x04711bf4, 0x22aba95f, 0x1a666fc8, 0x6f4648e0, 0x5f29caae), SECP256K1_FE_CONST(0x93b3a7f4, 0x8938a6bf, 0xbca96062, 0x51e923d7, 0xfe3e95e0, 0x41ed79f7, 0x7e48a070, 0x06d63f4a), SECP256K1_FE_CONST(0x6bdcecaa, 0x18c7a3a0, 0xda35bc95, 0x59be6eb8, 0xe515bc6c, 0x29179548, 0x5ca01d4f, 0x5350ff22), SECP256K1_FE_CONST(0x200d5e6a, 0xe525924a, 0x8b207cbf, 0xb7eb625c, 0xc6858a47, 0xd6540a73, 0x819624e3, 0xbe53f2a6), SECP256K1_FE_CONST(0x5ad4992c, 0x36f8fcaa, 0xb7fd7407, 0xfb8ee40b, 0xdd5456a0, 0xe5999037, 0x90b9b71e, 0xa0d63181)}}, + {0x00, SECP256K1_FE_CONST(0xfd7d912a, 0x40f182a3, 0x588800d6, 0x9ebfb504, 0x8766da20, 0x6fd7ebc8, 0xd2436c81, 0xcbef6421), SECP256K1_FE_CONST(0x8d37c862, 0x054debe7, 0x31694536, 0xff46b273, 0xec122b35, 0xa9bf1445, 0xac3c4ff9, 0xf262c952), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, +}; + +/* Set of (encoding, xcoord) test vectors, selected to maximize branch coverage, part of the BIP324 + * test vectors. Created using an independent implementation, and tested decoding against the paper + * authors' code. */ +static const struct ellswift_decode_test ellswift_decode_tests[] = { + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 1}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0}, + {{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0}, + {{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0}, + {{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x74e880b3, 0xffd18fe3, 0xcddf7902, 0x522551dd, 0xf97fa4a3, 0x5a3cfda8, 0x197f9470, 0x81a57b8f), 0}, + {{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x377b643f, 0xce2271f6, 0x4e5c8101, 0x566107c1, 0xbe498074, 0x50917838, 0x04f65478, 0x1ac9217c), 1}, + {{0x12, 0x36, 0x58, 0x44, 0x4f, 0x32, 0xbe, 0x8f, 0x02, 0xea, 0x20, 0x34, 0xaf, 0xa7, 0xef, 0x4b, 0xbe, 0x8a, 0xdc, 0x91, 0x8c, 0xeb, 0x49, 0xb1, 0x27, 0x73, 0xb6, 0x25, 0xf4, 0x90, 0xb3, 0x68, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8d, 0xc5, 0xfe, 0x11}, SECP256K1_FE_CONST(0xed16d65c, 0xf3a9538f, 0xcb2c139f, 0x1ecbc143, 0xee148271, 0x20cbc265, 0x9e667256, 0x800b8142), 0}, + {{0x14, 0x6f, 0x92, 0x46, 0x4d, 0x15, 0xd3, 0x6e, 0x35, 0x38, 0x2b, 0xd3, 0xca, 0x5b, 0x0f, 0x97, 0x6c, 0x95, 0xcb, 0x08, 0xac, 0xdc, 0xf2, 0xd5, 0xb3, 0x57, 0x06, 0x17, 0x99, 0x08, 0x39, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x45, 0xe9, 0x3b}, SECP256K1_FE_CONST(0x0d5cd840, 0x427f941f, 0x65193079, 0xab8e2e83, 0x024ef2ee, 0x7ca558d8, 0x8879ffd8, 0x79fb6657), 0}, + {{0x15, 0xfd, 0xf5, 0xcf, 0x09, 0xc9, 0x07, 0x59, 0xad, 0xd2, 0x27, 0x2d, 0x57, 0x4d, 0x2b, 0xb5, 0xfe, 0x14, 0x29, 0xf9, 0xf3, 0xc1, 0x4c, 0x65, 0xe3, 0x19, 0x4b, 0xf6, 0x1b, 0x82, 0xaa, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0xcf, 0xd9, 0x06}, SECP256K1_FE_CONST(0x16d0e439, 0x46aec93f, 0x62d57eb8, 0xcde68951, 0xaf136cf4, 0xb307938d, 0xd1447411, 0xe07bffe1), 1}, + {{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0}, + {{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0}, + {{0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x98bec3b2, 0xa351fa96, 0xcfd191c1, 0x77835193, 0x1b9e9ba9, 0xad1149f6, 0xd9eadca8, 0x0981b801), 0}, + {{0x40, 0x56, 0xa3, 0x4a, 0x21, 0x0e, 0xec, 0x78, 0x92, 0xe8, 0x82, 0x06, 0x75, 0xc8, 0x60, 0x09, 0x9f, 0x85, 0x7b, 0x26, 0xaa, 0xd8, 0x54, 0x70, 0xee, 0x6d, 0x3c, 0xf1, 0x30, 0x4a, 0x9d, 0xcf, 0x37, 0x5e, 0x70, 0x37, 0x42, 0x71, 0xf2, 0x0b, 0x13, 0xc9, 0x98, 0x6e, 0xd7, 0xd3, 0xc1, 0x77, 0x99, 0x69, 0x8c, 0xfc, 0x43, 0x5d, 0xbe, 0xd3, 0xa9, 0xf3, 0x4b, 0x38, 0xc8, 0x23, 0xc2, 0xb4}, SECP256K1_FE_CONST(0x868aac20, 0x03b29dbc, 0xad1a3e80, 0x3855e078, 0xa89d1654, 0x3ac64392, 0xd1224172, 0x98cec76e), 0}, + {{0x41, 0x97, 0xec, 0x37, 0x23, 0xc6, 0x54, 0xcf, 0xdd, 0x32, 0xab, 0x07, 0x55, 0x06, 0x64, 0x8b, 0x2f, 0xf5, 0x07, 0x03, 0x62, 0xd0, 0x1a, 0x4f, 0xff, 0x14, 0xb3, 0x36, 0xb7, 0x8f, 0x96, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb3, 0xab, 0x1e, 0x95}, SECP256K1_FE_CONST(0xba5a6314, 0x502a8952, 0xb8f456e0, 0x85928105, 0xf665377a, 0x8ce27726, 0xa5b0eb7e, 0xc1ac0286), 0}, + {{0x47, 0xeb, 0x3e, 0x20, 0x8f, 0xed, 0xcd, 0xf8, 0x23, 0x4c, 0x94, 0x21, 0xe9, 0xcd, 0x9a, 0x7a, 0xe8, 0x73, 0xbf, 0xbd, 0xbc, 0x39, 0x37, 0x23, 0xd1, 0xba, 0x1e, 0x1e, 0x6a, 0x8e, 0x6b, 0x24, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xd1, 0x2c, 0xb1}, SECP256K1_FE_CONST(0xd192d520, 0x07e541c9, 0x807006ed, 0x0468df77, 0xfd214af0, 0xa795fe11, 0x9359666f, 0xdcf08f7c), 0}, + {{0x5e, 0xb9, 0x69, 0x6a, 0x23, 0x36, 0xfe, 0x2c, 0x3c, 0x66, 0x6b, 0x02, 0xc7, 0x55, 0xdb, 0x4c, 0x0c, 0xfd, 0x62, 0x82, 0x5c, 0x7b, 0x58, 0x9a, 0x7b, 0x7b, 0xb4, 0x42, 0xe1, 0x41, 0xc1, 0xd6, 0x93, 0x41, 0x3f, 0x00, 0x52, 0xd4, 0x9e, 0x64, 0xab, 0xec, 0x6d, 0x58, 0x31, 0xd6, 0x6c, 0x43, 0x61, 0x28, 0x30, 0xa1, 0x7d, 0xf1, 0xfe, 0x43, 0x83, 0xdb, 0x89, 0x64, 0x68, 0x10, 0x02, 0x21}, SECP256K1_FE_CONST(0xef6e1da6, 0xd6c7627e, 0x80f7a723, 0x4cb08a02, 0x2c1ee1cf, 0x29e4d0f9, 0x642ae924, 0xcef9eb38), 1}, + {{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0}, + {{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0}, + {{0x85, 0x1b, 0x1c, 0xa9, 0x45, 0x49, 0x37, 0x1c, 0x4f, 0x1f, 0x71, 0x87, 0x32, 0x1d, 0x39, 0xbf, 0x51, 0xc6, 0xb7, 0xfb, 0x61, 0xf7, 0xcb, 0xf0, 0x27, 0xc9, 0xda, 0x62, 0x02, 0x1b, 0x7a, 0x65, 0xfc, 0x54, 0xc9, 0x68, 0x37, 0xfb, 0x22, 0xb3, 0x62, 0xed, 0xa6, 0x3e, 0xc5, 0x2e, 0xc8, 0x3d, 0x81, 0xbe, 0xdd, 0x16, 0x0c, 0x11, 0xb2, 0x2d, 0x96, 0x5d, 0x9f, 0x4a, 0x6d, 0x64, 0xd2, 0x51}, SECP256K1_FE_CONST(0x3e731051, 0xe12d3323, 0x7eb324f2, 0xaa5b16bb, 0x868eb49a, 0x1aa1fadc, 0x19b6e876, 0x1b5a5f7b), 1}, + {{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0}, + {{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0}, + {{0xa0, 0xf1, 0x84, 0x92, 0x18, 0x3e, 0x61, 0xe8, 0x06, 0x3e, 0x57, 0x36, 0x06, 0x59, 0x14, 0x21, 0xb0, 0x6b, 0xc3, 0x51, 0x36, 0x31, 0x57, 0x8a, 0x73, 0xa3, 0x9c, 0x1c, 0x33, 0x06, 0x23, 0x9f, 0x2f, 0x32, 0x90, 0x4f, 0x0d, 0x2a, 0x33, 0xec, 0xca, 0x8a, 0x54, 0x51, 0x70, 0x5b, 0xb5, 0x37, 0xd3, 0xbf, 0x44, 0xe0, 0x71, 0x22, 0x60, 0x25, 0xcd, 0xbf, 0xd2, 0x49, 0xfe, 0x0f, 0x7a, 0xd6}, SECP256K1_FE_CONST(0x97a09cf1, 0xa2eae7c4, 0x94df3c6f, 0x8a9445bf, 0xb8c09d60, 0x832f9b0b, 0x9d5eabe2, 0x5fbd14b9), 0}, + {{0xa1, 0xed, 0x0a, 0x0b, 0xd7, 0x9d, 0x8a, 0x23, 0xcf, 0xe4, 0xec, 0x5f, 0xef, 0x5b, 0xa5, 0xcc, 0xcf, 0xd8, 0x44, 0xe4, 0xff, 0x5c, 0xb4, 0xb0, 0xf2, 0xe7, 0x16, 0x27, 0x34, 0x1f, 0x1c, 0x5b, 0x17, 0xc4, 0x99, 0x24, 0x9e, 0x0a, 0xc0, 0x8d, 0x5d, 0x11, 0xea, 0x1c, 0x2c, 0x8c, 0xa7, 0x00, 0x16, 0x16, 0x55, 0x9a, 0x79, 0x94, 0xea, 0xde, 0xc9, 0xca, 0x10, 0xfb, 0x4b, 0x85, 0x16, 0xdc}, SECP256K1_FE_CONST(0x65a89640, 0x744192cd, 0xac64b2d2, 0x1ddf989c, 0xdac75007, 0x25b645be, 0xf8e2200a, 0xe39691f2), 0}, + {{0xba, 0x94, 0x59, 0x4a, 0x43, 0x27, 0x21, 0xaa, 0x35, 0x80, 0xb8, 0x4c, 0x16, 0x1d, 0x0d, 0x13, 0x4b, 0xc3, 0x54, 0xb6, 0x90, 0x40, 0x4d, 0x7c, 0xd4, 0xec, 0x57, 0xc1, 0x6d, 0x3f, 0xbe, 0x98, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xea, 0x50, 0x7d, 0xd7}, SECP256K1_FE_CONST(0x5e0d7656, 0x4aae92cb, 0x347e01a6, 0x2afd389a, 0x9aa401c7, 0x6c8dd227, 0x543dc9cd, 0x0efe685a), 0}, + {{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x2d97f96c, 0xac882dfe, 0x73dc44db, 0x6ce0f1d3, 0x1d624135, 0x8dd5d74e, 0xb3d3b500, 0x03d24c2b), 0}, + {{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x65, 0x07, 0xd0, 0x9a}, SECP256K1_FE_CONST(0xe7008afe, 0x6e8cbd50, 0x55df120b, 0xd748757c, 0x686dadb4, 0x1cce75e4, 0xaddcc5e0, 0x2ec02b44), 1}, + {{0xc5, 0x98, 0x1b, 0xae, 0x27, 0xfd, 0x84, 0x40, 0x1c, 0x72, 0xa1, 0x55, 0xe5, 0x70, 0x7f, 0xbb, 0x81, 0x1b, 0x2b, 0x62, 0x06, 0x45, 0xd1, 0x02, 0x8e, 0xa2, 0x70, 0xcb, 0xe0, 0xee, 0x22, 0x5d, 0x4b, 0x62, 0xaa, 0x4d, 0xca, 0x65, 0x06, 0xc1, 0xac, 0xdb, 0xec, 0xc0, 0x55, 0x25, 0x69, 0xb4, 0xb2, 0x14, 0x36, 0xa5, 0x69, 0x2e, 0x25, 0xd9, 0x0d, 0x3b, 0xc2, 0xeb, 0x7c, 0xe2, 0x40, 0x78}, SECP256K1_FE_CONST(0x948b40e7, 0x181713bc, 0x018ec170, 0x2d3d054d, 0x15746c59, 0xa7020730, 0xdd13ecf9, 0x85a010d7), 0}, + {{0xc8, 0x94, 0xce, 0x48, 0xbf, 0xec, 0x43, 0x30, 0x14, 0xb9, 0x31, 0xa6, 0xad, 0x42, 0x26, 0xd7, 0xdb, 0xd8, 0xea, 0xa7, 0xb6, 0xe3, 0xfa, 0xa8, 0xd0, 0xef, 0x94, 0x05, 0x2b, 0xcf, 0x8c, 0xff, 0x33, 0x6e, 0xeb, 0x39, 0x19, 0xe2, 0xb4, 0xef, 0xb7, 0x46, 0xc7, 0xf7, 0x1b, 0xbc, 0xa7, 0xe9, 0x38, 0x32, 0x30, 0xfb, 0xbc, 0x48, 0xff, 0xaf, 0xe7, 0x7e, 0x8b, 0xcc, 0x69, 0x54, 0x24, 0x71}, SECP256K1_FE_CONST(0xf1c91acd, 0xc2525330, 0xf9b53158, 0x434a4d43, 0xa1c547cf, 0xf29f1550, 0x6f5da4eb, 0x4fe8fa5a), 1}, + {{0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x872d81ed, 0x8831d999, 0x8b67cb71, 0x05243edb, 0xf86c10ed, 0xfebb786c, 0x110b02d0, 0x7b2e67cd), 0}, + {{0xd9, 0x17, 0xb7, 0x86, 0xda, 0xc3, 0x56, 0x70, 0xc3, 0x30, 0xc9, 0xc5, 0xae, 0x59, 0x71, 0xdf, 0xb4, 0x95, 0xc8, 0xae, 0x52, 0x3e, 0xd9, 0x7e, 0xe2, 0x42, 0x01, 0x17, 0xb1, 0x71, 0xf4, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x01, 0xf6, 0xf6}, SECP256K1_FE_CONST(0xe45b71e1, 0x10b831f2, 0xbdad8651, 0x994526e5, 0x8393fde4, 0x328b1ec0, 0x4d598971, 0x42584691), 1}, + {{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0}, + {{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0}, + {{0xe7, 0xee, 0x58, 0x14, 0xc1, 0x70, 0x6b, 0xf8, 0xa8, 0x93, 0x96, 0xa9, 0xb0, 0x32, 0xbc, 0x01, 0x4c, 0x2c, 0xac, 0x9c, 0x12, 0x11, 0x27, 0xdb, 0xf6, 0xc9, 0x92, 0x78, 0xf8, 0xbb, 0x53, 0xd1, 0xdf, 0xd0, 0x4d, 0xbc, 0xda, 0x8e, 0x35, 0x24, 0x66, 0xb6, 0xfc, 0xd5, 0xf2, 0xde, 0xa3, 0xe1, 0x7d, 0x5e, 0x13, 0x31, 0x15, 0x88, 0x6e, 0xda, 0x20, 0xdb, 0x8a, 0x12, 0xb5, 0x4d, 0xe7, 0x1b}, SECP256K1_FE_CONST(0xe842c6e3, 0x529b2342, 0x70a5e977, 0x44edc34a, 0x04d7ba94, 0xe44b6d25, 0x23c9cf01, 0x95730a50), 1}, + {{0xf2, 0x92, 0xe4, 0x68, 0x25, 0xf9, 0x22, 0x5a, 0xd2, 0x3d, 0xc0, 0x57, 0xc1, 0xd9, 0x1c, 0x4f, 0x57, 0xfc, 0xb1, 0x38, 0x6f, 0x29, 0xef, 0x10, 0x48, 0x1c, 0xb1, 0xd2, 0x25, 0x18, 0x59, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x11, 0xc9, 0x89}, SECP256K1_FE_CONST(0x3cea2c53, 0xb8b01701, 0x66ac7da6, 0x7194694a, 0xdacc84d5, 0x6389225e, 0x330134da, 0xb85a4d55), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x02, 0x8c, 0x59, 0x00, 0x63, 0xf6, 0x4d, 0x5a, 0x7f, 0x1c, 0x14, 0x91, 0x5c, 0xd6, 0x1e, 0xac, 0x88, 0x6a, 0xb2, 0x95, 0xbe, 0xbd, 0x91, 0x99, 0x25, 0x04, 0xcf, 0x77, 0xed, 0xb0, 0x28, 0xbd, 0xd6, 0x26, 0x7f}, SECP256K1_FE_CONST(0x3fde5713, 0xf8282eea, 0xd7d39d42, 0x01f44a7c, 0x85a5ac8a, 0x0681f35e, 0x54085c6b, 0x69543374), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x2c, 0x57, 0x09, 0xe7, 0x15, 0x6c, 0x41, 0x77, 0x17, 0xf2, 0xfe, 0xab, 0x14, 0x71, 0x41, 0xec, 0x3d, 0xa1, 0x9f, 0xb7, 0x59, 0x57, 0x5c, 0xc6, 0xe3, 0x7b, 0x2e, 0xa5, 0xac, 0x93, 0x09, 0xf2, 0x6f, 0x0f, 0x66}, SECP256K1_FE_CONST(0xd2469ab3, 0xe04acbb2, 0x1c65a180, 0x9f39caaf, 0xe7a77c13, 0xd10f9dd3, 0x8f391c01, 0xdc499c52), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3a, 0x08, 0xcc, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x60, 0xe9, 0xf0}, SECP256K1_FE_CONST(0x38e2a5ce, 0x6a93e795, 0xe16d2c39, 0x8bc99f03, 0x69202ce2, 0x1e8f09d5, 0x6777b40f, 0xc512bccc), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0x91, 0x25, 0x7d, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x864b3dc9, 0x02c37670, 0x9c10a93a, 0xd4bbe29f, 0xce0012f3, 0xdc8672c6, 0x286bba28, 0xd7d6d6fc), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, 0x5d, 0x6c, 0x1c, 0x32, 0x2c, 0xad, 0xf5, 0x99, 0xdb, 0xb8, 0x64, 0x81, 0x52, 0x2b, 0x3c, 0xc5, 0x5f, 0x15, 0xa6, 0x79, 0x32, 0xdb, 0x2a, 0xfa, 0x01, 0x11, 0xd9, 0xed, 0x69, 0x81, 0xbc, 0xd1, 0x24, 0xbf, 0x44}, SECP256K1_FE_CONST(0x766dfe4a, 0x700d9bee, 0x288b903a, 0xd58870e3, 0xd4fe2f0e, 0xf780bcac, 0x5c823f32, 0x0d9a9bef), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8e, 0x42, 0x6f, 0x03, 0x92, 0x38, 0x90, 0x78, 0xc1, 0x2b, 0x1a, 0x89, 0xe9, 0x54, 0x2f, 0x05, 0x93, 0xbc, 0x96, 0xb6, 0xbf, 0xde, 0x82, 0x24, 0xf8, 0x65, 0x4e, 0xf5, 0xd5, 0xcd, 0xa9, 0x35, 0xa3, 0x58, 0x21, 0x94}, SECP256K1_FE_CONST(0xfaec7bc1, 0x987b6323, 0x3fbc5f95, 0x6edbf37d, 0x54404e74, 0x61c58ab8, 0x631bc68e, 0x451a0478), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x91, 0x19, 0x21, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x45, 0xf0, 0xf1, 0xeb}, SECP256K1_FE_CONST(0xec29a50b, 0xae138dbf, 0x7d8e2482, 0x5006bb5f, 0xc1a2cc12, 0x43ba335b, 0xc6116fb9, 0xe498ec1f), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x98, 0xeb, 0x9a, 0xb7, 0x6e, 0x84, 0x49, 0x9c, 0x48, 0x3b, 0x3b, 0xf0, 0x62, 0x14, 0xab, 0xfe, 0x06, 0x5d, 0xdd, 0xf4, 0x3b, 0x86, 0x01, 0xde, 0x59, 0x6d, 0x63, 0xb9, 0xe4, 0x5a, 0x16, 0x6a, 0x58, 0x05, 0x41, 0xfe}, SECP256K1_FE_CONST(0x1e0ff2de, 0xe9b09b13, 0x6292a9e9, 0x10f0d6ac, 0x3e552a64, 0x4bba39e6, 0x4e9dd3e3, 0xbbd3d4d4), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x8b7dd5c3, 0xedba9ee9, 0x7b70eff4, 0x38f22dca, 0x9849c825, 0x4a2f3345, 0xa0a572ff, 0xeaae0928), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x0881950c, 0x8f51d6b9, 0xa6387465, 0xd5f12609, 0xef1bb254, 0x12a08a74, 0xcb2dfb20, 0x0c74bfbf), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa2, 0xf5, 0xcd, 0x83, 0x88, 0x16, 0xc1, 0x6c, 0x4f, 0xe8, 0xa1, 0x66, 0x1d, 0x60, 0x6f, 0xdb, 0x13, 0xcf, 0x9a, 0xf0, 0x4b, 0x97, 0x9a, 0x2e, 0x15, 0x9a, 0x09, 0x40, 0x9e, 0xbc, 0x86, 0x45, 0xd5, 0x8f, 0xde, 0x02}, SECP256K1_FE_CONST(0x2f083207, 0xb9fd9b55, 0x0063c31c, 0xd62b8746, 0xbd543bdc, 0x5bbf10e3, 0xa35563e9, 0x27f440c8), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x64, 0xd1, 0x62, 0x75, 0x05, 0x46, 0xce, 0x42, 0xb0, 0x43, 0x13, 0x61, 0xe5, 0x2d, 0x4f, 0x52, 0x42, 0xd8, 0xf2, 0x4f, 0x33, 0xe6, 0xb1, 0xf9, 0x9b, 0x59, 0x16, 0x47, 0xcb, 0xc8, 0x08, 0xf4, 0x62, 0xaf, 0x51}, SECP256K1_FE_CONST(0xd41244d1, 0x1ca4f652, 0x40687759, 0xf95ca9ef, 0xbab767ed, 0xedb38fd1, 0x8c36e18c, 0xd3b6f6a9), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xe5, 0xbe, 0x52, 0x37, 0x2d, 0xd6, 0xe8, 0x94, 0xb2, 0xa3, 0x26, 0xfc, 0x36, 0x05, 0xa6, 0xe8, 0xf3, 0xc6, 0x9c, 0x71, 0x0b, 0xf2, 0x7d, 0x63, 0x0d, 0xfe, 0x20, 0x04, 0x98, 0x8b, 0x78, 0xeb, 0x6e, 0xab, 0x36}, SECP256K1_FE_CONST(0x64bf84dd, 0x5e03670f, 0xdb24c0f5, 0xd3c2c365, 0x736f51db, 0x6c92d950, 0x10716ad2, 0xd36134c8), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfb, 0xb9, 0x82, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0xd6, 0xdb, 0x1f}, SECP256K1_FE_CONST(0x1c92ccdf, 0xcf4ac550, 0xc28db57c, 0xff0c8515, 0xcb26936c, 0x786584a7, 0x0114008d, 0x6c33a34b), 0}, +}; + +/* Set of expected ellswift_xdh BIP324 shared secrets, given private key, encodings, initiating, + * taken from the BIP324 test vectors. Created using an independent implementation, and tested + * against the paper authors' decoding code. */ +static const struct ellswift_xdh_test ellswift_xdh_tests_bip324[] = { + {{0x61, 0x06, 0x2e, 0xa5, 0x07, 0x1d, 0x80, 0x0b, 0xbf, 0xd5, 0x9e, 0x2e, 0x8b, 0x53, 0xd4, 0x7d, 0x19, 0x4b, 0x09, 0x5a, 0xe5, 0xa4, 0xdf, 0x04, 0x93, 0x6b, 0x49, 0x77, 0x2e, 0xf0, 0xd4, 0xd7}, {0xec, 0x0a, 0xdf, 0xf2, 0x57, 0xbb, 0xfe, 0x50, 0x0c, 0x18, 0x8c, 0x80, 0xb4, 0xfd, 0xd6, 0x40, 0xf6, 0xb4, 0x5a, 0x48, 0x2b, 0xbc, 0x15, 0xfc, 0x7c, 0xef, 0x59, 0x31, 0xde, 0xff, 0x0a, 0xa1, 0x86, 0xf6, 0xeb, 0x9b, 0xba, 0x7b, 0x85, 0xdc, 0x4d, 0xcc, 0x28, 0xb2, 0x87, 0x22, 0xde, 0x1e, 0x3d, 0x91, 0x08, 0xb9, 0x85, 0xe2, 0x96, 0x70, 0x45, 0x66, 0x8f, 0x66, 0x09, 0x8e, 0x47, 0x5b}, {0xa4, 0xa9, 0x4d, 0xfc, 0xe6, 0x9b, 0x4a, 0x2a, 0x0a, 0x09, 0x93, 0x13, 0xd1, 0x0f, 0x9f, 0x7e, 0x7d, 0x64, 0x9d, 0x60, 0x50, 0x1c, 0x9e, 0x1d, 0x27, 0x4c, 0x30, 0x0e, 0x0d, 0x89, 0xaa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xaf, 0x88, 0xd5}, 1, {0xc6, 0x99, 0x2a, 0x11, 0x7f, 0x5e, 0xdb, 0xea, 0x70, 0xc3, 0xf5, 0x11, 0xd3, 0x2d, 0x26, 0xb9, 0x79, 0x8b, 0xe4, 0xb8, 0x1a, 0x62, 0xea, 0xee, 0x1a, 0x5a, 0xca, 0xa8, 0x45, 0x9a, 0x35, 0x92}}, + {{0x1f, 0x9c, 0x58, 0x1b, 0x35, 0x23, 0x18, 0x38, 0xf0, 0xf1, 0x7c, 0xf0, 0xc9, 0x79, 0x83, 0x5b, 0xac, 0xcb, 0x7f, 0x3a, 0xbb, 0xbb, 0x96, 0xff, 0xcc, 0x31, 0x8a, 0xb7, 0x1e, 0x6e, 0x12, 0x6f}, {0xa1, 0x85, 0x5e, 0x10, 0xe9, 0x4e, 0x00, 0xba, 0xa2, 0x30, 0x41, 0xd9, 0x16, 0xe2, 0x59, 0xf7, 0x04, 0x4e, 0x49, 0x1d, 0xa6, 0x17, 0x12, 0x69, 0x69, 0x47, 0x63, 0xf0, 0x18, 0xc7, 0xe6, 0x36, 0x93, 0xd2, 0x95, 0x75, 0xdc, 0xb4, 0x64, 0xac, 0x81, 0x6b, 0xaa, 0x1b, 0xe3, 0x53, 0xba, 0x12, 0xe3, 0x87, 0x6c, 0xba, 0x76, 0x28, 0xbd, 0x0b, 0xd8, 0xe7, 0x55, 0xe7, 0x21, 0xeb, 0x01, 0x40}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0, {0xa0, 0x13, 0x8f, 0x56, 0x4f, 0x74, 0xd0, 0xad, 0x70, 0xbc, 0x33, 0x7d, 0xac, 0xc9, 0xd0, 0xbf, 0x1d, 0x23, 0x49, 0x36, 0x4c, 0xaf, 0x11, 0x88, 0xa1, 0xe6, 0xe8, 0xdd, 0xb3, 0xb7, 0xb1, 0x84}}, + {{0x02, 0x86, 0xc4, 0x1c, 0xd3, 0x09, 0x13, 0xdb, 0x0f, 0xdf, 0xf7, 0xa6, 0x4e, 0xbd, 0xa5, 0xc8, 0xe3, 0xe7, 0xce, 0xf1, 0x0f, 0x2a, 0xeb, 0xc0, 0x0a, 0x76, 0x50, 0x44, 0x3c, 0xf4, 0xc6, 0x0d}, {0xd1, 0xee, 0x8a, 0x93, 0xa0, 0x11, 0x30, 0xcb, 0xf2, 0x99, 0x24, 0x9a, 0x25, 0x8f, 0x94, 0xfe, 0xb5, 0xf4, 0x69, 0xe7, 0xd0, 0xf2, 0xf2, 0x8f, 0x69, 0xee, 0x5e, 0x9a, 0xa8, 0xf9, 0xb5, 0x4a, 0x60, 0xf2, 0xc3, 0xff, 0x2d, 0x02, 0x36, 0x34, 0xec, 0x7f, 0x41, 0x27, 0xa9, 0x6c, 0xc1, 0x16, 0x62, 0xe4, 0x02, 0x89, 0x4c, 0xf1, 0xf6, 0x94, 0xfb, 0x9a, 0x7e, 0xaa, 0x5f, 0x1d, 0x92, 0x44}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x22, 0xd5, 0xe4, 0x41, 0x52, 0x4d, 0x57, 0x1a, 0x52, 0xb3, 0xde, 0xf1, 0x26, 0x18, 0x9d, 0x3f, 0x41, 0x68, 0x90, 0xa9, 0x9d, 0x4d, 0xa6, 0xed, 0xe2, 0xb0, 0xcd, 0xe1, 0x76, 0x0c, 0xe2, 0xc3, 0xf9, 0x84, 0x57, 0xae}, 1, {0x25, 0x0b, 0x93, 0x57, 0x0d, 0x41, 0x11, 0x49, 0x10, 0x5a, 0xb8, 0xcb, 0x0b, 0xc5, 0x07, 0x99, 0x14, 0x90, 0x63, 0x06, 0x36, 0x8c, 0x23, 0xe9, 0xd7, 0x7c, 0x2a, 0x33, 0x26, 0x5b, 0x99, 0x4c}}, + {{0x6c, 0x77, 0x43, 0x2d, 0x1f, 0xda, 0x31, 0xe9, 0xf9, 0x42, 0xf8, 0xaf, 0x44, 0x60, 0x7e, 0x10, 0xf3, 0xad, 0x38, 0xa6, 0x5f, 0x8a, 0x4b, 0xdd, 0xae, 0x82, 0x3e, 0x5e, 0xff, 0x90, 0xdc, 0x38}, {0xd2, 0x68, 0x50, 0x70, 0xc1, 0xe6, 0x37, 0x6e, 0x63, 0x3e, 0x82, 0x52, 0x96, 0x63, 0x4f, 0xd4, 0x61, 0xfa, 0x9e, 0x5b, 0xdf, 0x21, 0x09, 0xbc, 0xeb, 0xd7, 0x35, 0xe5, 0xa9, 0x1f, 0x3e, 0x58, 0x7c, 0x5c, 0xb7, 0x82, 0xab, 0xb7, 0x97, 0xfb, 0xf6, 0xbb, 0x50, 0x74, 0xfd, 0x15, 0x42, 0xa4, 0x74, 0xf2, 0xa4, 0x5b, 0x67, 0x37, 0x63, 0xec, 0x2d, 0xb7, 0xfb, 0x99, 0xb7, 0x37, 0xbb, 0xb9}, {0x56, 0xbd, 0x0c, 0x06, 0xf1, 0x03, 0x52, 0xc3, 0xa1, 0xa9, 0xf4, 0xb4, 0xc9, 0x2f, 0x6f, 0xa2, 0xb2, 0x6d, 0xf1, 0x24, 0xb5, 0x78, 0x78, 0x35, 0x3c, 0x1f, 0xc6, 0x91, 0xc5, 0x1a, 0xbe, 0xa7, 0x7c, 0x88, 0x17, 0xda, 0xee, 0xb9, 0xfa, 0x54, 0x6b, 0x77, 0xc8, 0xda, 0xf7, 0x9d, 0x89, 0xb2, 0x2b, 0x0e, 0x1b, 0x87, 0x57, 0x4e, 0xce, 0x42, 0x37, 0x1f, 0x00, 0x23, 0x7a, 0xa9, 0xd8, 0x3a}, 0, {0x19, 0x18, 0xb7, 0x41, 0xef, 0x5f, 0x9d, 0x1d, 0x76, 0x70, 0xb0, 0x50, 0xc1, 0x52, 0xb4, 0xa4, 0xea, 0xd2, 0xc3, 0x1b, 0xe9, 0xae, 0xcb, 0x06, 0x81, 0xc0, 0xcd, 0x43, 0x24, 0x15, 0x08, 0x53}}, + {{0xa6, 0xec, 0x25, 0x12, 0x7c, 0xa1, 0xaa, 0x4c, 0xf1, 0x6b, 0x20, 0x08, 0x4b, 0xa1, 0xe6, 0x51, 0x6b, 0xaa, 0xe4, 0xd3, 0x24, 0x22, 0x28, 0x8e, 0x9b, 0x36, 0xd8, 0xbd, 0xdd, 0x2d, 0xe3, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x3d, 0x7e, 0xcc, 0xa5, 0x3e, 0x33, 0xe1, 0x85, 0xa8, 0xb9, 0xbe, 0x4e, 0x76, 0x99, 0xa9, 0x7c, 0x6f, 0xf4, 0xc7, 0x95, 0x52, 0x2e, 0x59, 0x18, 0xab, 0x7c, 0xd6, 0xb6, 0x88, 0x4f, 0x67, 0xe6, 0x83, 0xf3, 0xdc}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0x73, 0x0b, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 1, {0xdd, 0x21, 0x0a, 0xa6, 0x62, 0x9f, 0x20, 0xbb, 0x32, 0x8e, 0x5d, 0x89, 0xda, 0xa6, 0xeb, 0x2a, 0xc3, 0xd1, 0xc6, 0x58, 0xa7, 0x25, 0x53, 0x6f, 0xf1, 0x54, 0xf3, 0x1b, 0x53, 0x6c, 0x23, 0xb2}}, + {{0x0a, 0xf9, 0x52, 0x65, 0x9e, 0xd7, 0x6f, 0x80, 0xf5, 0x85, 0x96, 0x6b, 0x95, 0xab, 0x6e, 0x6f, 0xd6, 0x86, 0x54, 0x67, 0x28, 0x27, 0x87, 0x86, 0x84, 0xc8, 0xb5, 0x47, 0xb1, 0xb9, 0x4f, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x10, 0x17, 0xfd, 0x92, 0xfd, 0x31, 0x63, 0x7c, 0x26, 0xc9, 0x06, 0xb4, 0x20, 0x92, 0xe1, 0x1c, 0xc0, 0xd3, 0xaf, 0xae, 0x8d, 0x90, 0x19, 0xd2, 0x57, 0x8a, 0xf2, 0x27, 0x35, 0xce, 0x7b, 0xc4, 0x69, 0xc7, 0x2d}, {0x96, 0x52, 0xd7, 0x8b, 0xae, 0xfc, 0x02, 0x8c, 0xd3, 0x7a, 0x6a, 0x92, 0x62, 0x5b, 0x8b, 0x8f, 0x85, 0xfd, 0xe1, 0xe4, 0xc9, 0x44, 0xad, 0x3f, 0x20, 0xe1, 0x98, 0xbe, 0xf8, 0xc0, 0x2f, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0xe9, 0x18, 0x70}, 0, {0x35, 0x68, 0xf2, 0xae, 0xa2, 0xe1, 0x4e, 0xf4, 0xee, 0x4a, 0x3c, 0x2a, 0x8b, 0x8d, 0x31, 0xbc, 0x5e, 0x31, 0x87, 0xba, 0x86, 0xdb, 0x10, 0x73, 0x9b, 0x4f, 0xf8, 0xec, 0x92, 0xff, 0x66, 0x55}}, + {{0xf9, 0x0e, 0x08, 0x0c, 0x64, 0xb0, 0x58, 0x24, 0xc5, 0xa2, 0x4b, 0x25, 0x01, 0xd5, 0xae, 0xaf, 0x08, 0xaf, 0x38, 0x72, 0xee, 0x86, 0x0a, 0xa8, 0x0b, 0xdc, 0xd4, 0x30, 0xf7, 0xb6, 0x34, 0x94}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0x51, 0x73, 0x76, 0x5d, 0xc2, 0x02, 0xcf, 0x02, 0x9a, 0xd3, 0xf1, 0x54, 0x79, 0x73, 0x5d, 0x57, 0x69, 0x7a, 0xf1, 0x2b, 0x01, 0x31, 0xdd, 0x21, 0x43, 0x0d, 0x57, 0x72, 0xe4, 0xef, 0x11, 0x47, 0x4d, 0x58, 0xb9}, {0x12, 0xa5, 0x0f, 0x3f, 0xaf, 0xea, 0x7c, 0x1e, 0xea, 0xda, 0x4c, 0xf8, 0xd3, 0x37, 0x77, 0x70, 0x4b, 0x77, 0x36, 0x14, 0x53, 0xaf, 0xc8, 0x3b, 0xda, 0x91, 0xee, 0xf3, 0x49, 0xae, 0x04, 0x4d, 0x20, 0x12, 0x6c, 0x62, 0x00, 0x54, 0x7e, 0xa5, 0xa6, 0x91, 0x17, 0x76, 0xc0, 0x5d, 0xee, 0x2a, 0x7f, 0x1a, 0x9b, 0xa7, 0xdf, 0xba, 0xbb, 0xbd, 0x27, 0x3c, 0x3e, 0xf2, 0x9e, 0xf4, 0x6e, 0x46}, 1, {0xe2, 0x54, 0x61, 0xfb, 0x0e, 0x4c, 0x16, 0x2e, 0x18, 0x12, 0x3e, 0xcd, 0xe8, 0x83, 0x42, 0xd5, 0x4d, 0x44, 0x96, 0x31, 0xe9, 0xb7, 0x5a, 0x26, 0x6f, 0xd9, 0x26, 0x0c, 0x2b, 0xb2, 0xf4, 0x1d}}, +}; + +/** This is a hasher for ellswift_xdh which just returns the shared X coordinate. + * + * This is generally a bad idea as it means changes to the encoding of the + * exchanged public keys do not affect the shared secret. However, it's used here + * in tests to be able to verify the X coordinate through other means. + */ +static int ellswift_xdh_hash_x32(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { + (void)ell_a64; + (void)ell_b64; + (void)data; + memcpy(output, x32, 32); + return 1; +} + +void run_ellswift_tests(void) { + int i = 0; + /* Test vectors. */ + for (i = 0; (unsigned)i < sizeof(ellswift_xswiftec_inv_tests) / sizeof(ellswift_xswiftec_inv_tests[0]); ++i) { + const struct ellswift_xswiftec_inv_test *testcase = &ellswift_xswiftec_inv_tests[i]; + int c; + for (c = 0; c < 8; ++c) { + rustsecp256k1_v0_11_fe t; + int ret = rustsecp256k1_v0_11_ellswift_xswiftec_inv_var(&t, &testcase->x, &testcase->u, c); + CHECK(ret == ((testcase->enc_bitmap >> c) & 1)); + if (ret) { + rustsecp256k1_v0_11_fe x2; + CHECK(fe_equal(&t, &testcase->encs[c])); + rustsecp256k1_v0_11_ellswift_xswiftec_var(&x2, &testcase->u, &testcase->encs[c]); + CHECK(fe_equal(&testcase->x, &x2)); + } + } + } + for (i = 0; (unsigned)i < sizeof(ellswift_decode_tests) / sizeof(ellswift_decode_tests[0]); ++i) { + const struct ellswift_decode_test *testcase = &ellswift_decode_tests[i]; + rustsecp256k1_v0_11_pubkey pubkey; + rustsecp256k1_v0_11_ge ge; + int ret; + ret = rustsecp256k1_v0_11_ellswift_decode(CTX, &pubkey, testcase->enc); + CHECK(ret); + ret = rustsecp256k1_v0_11_pubkey_load(CTX, &ge, &pubkey); + CHECK(ret); + CHECK(fe_equal(&testcase->x, &ge.x)); + CHECK(rustsecp256k1_v0_11_fe_is_odd(&ge.y) == testcase->odd_y); + } + for (i = 0; (unsigned)i < sizeof(ellswift_xdh_tests_bip324) / sizeof(ellswift_xdh_tests_bip324[0]); ++i) { + const struct ellswift_xdh_test *test = &ellswift_xdh_tests_bip324[i]; + unsigned char shared_secret[32]; + int ret; + int party = !test->initiating; + const unsigned char* ell_a64 = party ? test->ellswift_theirs : test->ellswift_ours; + const unsigned char* ell_b64 = party ? test->ellswift_ours : test->ellswift_theirs; + ret = rustsecp256k1_v0_11_ellswift_xdh(CTX, shared_secret, + ell_a64, ell_b64, + test->priv_ours, + party, + rustsecp256k1_v0_11_ellswift_xdh_hash_function_bip324, + NULL); + CHECK(ret); + CHECK(rustsecp256k1_v0_11_memcmp_var(shared_secret, test->shared_secret, 32) == 0); + } + /* Verify that rustsecp256k1_v0_11_ellswift_encode + decode roundtrips. */ + for (i = 0; i < 1000 * COUNT; i++) { + unsigned char rnd32[32]; + unsigned char ell64[64]; + rustsecp256k1_v0_11_ge g, g2; + rustsecp256k1_v0_11_pubkey pubkey, pubkey2; + /* Generate random public key and random randomizer. */ + testutil_random_ge_test(&g); + rustsecp256k1_v0_11_pubkey_save(&pubkey, &g); + testrand256(rnd32); + /* Convert the public key to ElligatorSwift and back. */ + rustsecp256k1_v0_11_ellswift_encode(CTX, ell64, &pubkey, rnd32); + rustsecp256k1_v0_11_ellswift_decode(CTX, &pubkey2, ell64); + rustsecp256k1_v0_11_pubkey_load(CTX, &g2, &pubkey2); + /* Compare with original. */ + CHECK(rustsecp256k1_v0_11_ge_eq_var(&g, &g2)); + } + /* Verify the behavior of rustsecp256k1_v0_11_ellswift_create */ + for (i = 0; i < 400 * COUNT; i++) { + unsigned char auxrnd32[32], sec32[32]; + rustsecp256k1_v0_11_scalar sec; + rustsecp256k1_v0_11_gej res; + rustsecp256k1_v0_11_ge dec; + rustsecp256k1_v0_11_pubkey pub; + unsigned char ell64[64]; + int ret; + /* Generate random secret key and random randomizer. */ + if (i & 1) testrand256_test(auxrnd32); + testutil_random_scalar_order_test(&sec); + rustsecp256k1_v0_11_scalar_get_b32(sec32, &sec); + /* Construct ElligatorSwift-encoded public keys for that key. */ + ret = rustsecp256k1_v0_11_ellswift_create(CTX, ell64, sec32, (i & 1) ? auxrnd32 : NULL); + CHECK(ret); + /* Decode it, and compare with traditionally-computed public key. */ + rustsecp256k1_v0_11_ellswift_decode(CTX, &pub, ell64); + rustsecp256k1_v0_11_pubkey_load(CTX, &dec, &pub); + rustsecp256k1_v0_11_ecmult(&res, NULL, &rustsecp256k1_v0_11_scalar_zero, &sec); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&res, &dec)); + } + /* Verify that rustsecp256k1_v0_11_ellswift_xdh computes the right shared X coordinate. */ + for (i = 0; i < 800 * COUNT; i++) { + unsigned char ell64[64], sec32[32], share32[32]; + rustsecp256k1_v0_11_scalar sec; + rustsecp256k1_v0_11_ge dec, res; + rustsecp256k1_v0_11_fe share_x; + rustsecp256k1_v0_11_gej decj, resj; + rustsecp256k1_v0_11_pubkey pub; + int ret; + /* Generate random secret key. */ + testutil_random_scalar_order_test(&sec); + rustsecp256k1_v0_11_scalar_get_b32(sec32, &sec); + /* Generate random ElligatorSwift encoding for the remote key and decode it. */ + testrand256_test(ell64); + testrand256_test(ell64 + 32); + rustsecp256k1_v0_11_ellswift_decode(CTX, &pub, ell64); + rustsecp256k1_v0_11_pubkey_load(CTX, &dec, &pub); + rustsecp256k1_v0_11_gej_set_ge(&decj, &dec); + /* Compute the X coordinate of seckey*pubkey using ellswift_xdh. Note that we + * pass ell64 as claimed (but incorrect) encoding for sec32 here; this works + * because the "hasher" function we use here ignores the ell64 arguments. */ + ret = rustsecp256k1_v0_11_ellswift_xdh(CTX, share32, ell64, ell64, sec32, i & 1, &ellswift_xdh_hash_x32, NULL); + CHECK(ret); + (void)rustsecp256k1_v0_11_fe_set_b32_limit(&share_x, share32); /* no overflow is possible */ + SECP256K1_FE_VERIFY(&share_x); + /* Compute seckey*pubkey directly. */ + rustsecp256k1_v0_11_ecmult(&resj, &decj, &sec, NULL); + rustsecp256k1_v0_11_ge_set_gej(&res, &resj); + /* Compare. */ + CHECK(fe_equal(&res.x, &share_x)); + } + /* Verify the joint behavior of rustsecp256k1_v0_11_ellswift_xdh */ + for (i = 0; i < 200 * COUNT; i++) { + unsigned char auxrnd32a[32], auxrnd32b[32], auxrnd32a_bad[32], auxrnd32b_bad[32]; + unsigned char sec32a[32], sec32b[32], sec32a_bad[32], sec32b_bad[32]; + rustsecp256k1_v0_11_scalar seca, secb; + unsigned char ell64a[64], ell64b[64], ell64a_bad[64], ell64b_bad[64]; + unsigned char share32a[32], share32b[32], share32_bad[32]; + unsigned char prefix64[64]; + rustsecp256k1_v0_11_ellswift_xdh_hash_function hash_function; + void* data; + int ret; + + /* Pick hasher to use. */ + if ((i % 3) == 0) { + hash_function = ellswift_xdh_hash_x32; + data = NULL; + } else if ((i % 3) == 1) { + hash_function = rustsecp256k1_v0_11_ellswift_xdh_hash_function_bip324; + data = NULL; + } else { + hash_function = rustsecp256k1_v0_11_ellswift_xdh_hash_function_prefix; + testrand256_test(prefix64); + testrand256_test(prefix64 + 32); + data = prefix64; + } + + /* Generate random secret keys and random randomizers. */ + testrand256_test(auxrnd32a); + testrand256_test(auxrnd32b); + testutil_random_scalar_order_test(&seca); + /* Draw secb uniformly at random to make sure that the secret keys + * differ */ + testutil_random_scalar_order(&secb); + rustsecp256k1_v0_11_scalar_get_b32(sec32a, &seca); + rustsecp256k1_v0_11_scalar_get_b32(sec32b, &secb); + + /* Construct ElligatorSwift-encoded public keys for those keys. */ + /* For A: */ + ret = rustsecp256k1_v0_11_ellswift_create(CTX, ell64a, sec32a, auxrnd32a); + CHECK(ret); + /* For B: */ + ret = rustsecp256k1_v0_11_ellswift_create(CTX, ell64b, sec32b, auxrnd32b); + CHECK(ret); + + /* Compute the shared secret both ways and compare with each other. */ + /* For A: */ + ret = rustsecp256k1_v0_11_ellswift_xdh(CTX, share32a, ell64a, ell64b, sec32a, 0, hash_function, data); + CHECK(ret); + /* For B: */ + ret = rustsecp256k1_v0_11_ellswift_xdh(CTX, share32b, ell64a, ell64b, sec32b, 1, hash_function, data); + CHECK(ret); + /* And compare: */ + CHECK(rustsecp256k1_v0_11_memcmp_var(share32a, share32b, 32) == 0); + + /* Verify that the shared secret doesn't match if other side's public key is incorrect. */ + /* For A (using a bad public key for B): */ + memcpy(ell64b_bad, ell64b, sizeof(ell64a_bad)); + testrand_flip(ell64b_bad, sizeof(ell64b_bad)); + ret = rustsecp256k1_v0_11_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data); + CHECK(ret); /* Mismatching encodings don't get detected by rustsecp256k1_v0_11_ellswift_xdh. */ + CHECK(rustsecp256k1_v0_11_memcmp_var(share32_bad, share32a, 32) != 0); + /* For B (using a bad public key for A): */ + memcpy(ell64a_bad, ell64a, sizeof(ell64a_bad)); + testrand_flip(ell64a_bad, sizeof(ell64a_bad)); + ret = rustsecp256k1_v0_11_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data); + CHECK(ret); + CHECK(rustsecp256k1_v0_11_memcmp_var(share32_bad, share32b, 32) != 0); + + /* Verify that the shared secret doesn't match if the private key is incorrect. */ + /* For A: */ + memcpy(sec32a_bad, sec32a, sizeof(sec32a_bad)); + testrand_flip(sec32a_bad, sizeof(sec32a_bad)); + ret = rustsecp256k1_v0_11_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a_bad, 0, hash_function, data); + CHECK(!ret || rustsecp256k1_v0_11_memcmp_var(share32_bad, share32a, 32) != 0); + /* For B: */ + memcpy(sec32b_bad, sec32b, sizeof(sec32b_bad)); + testrand_flip(sec32b_bad, sizeof(sec32b_bad)); + ret = rustsecp256k1_v0_11_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b_bad, 1, hash_function, data); + CHECK(!ret || rustsecp256k1_v0_11_memcmp_var(share32_bad, share32b, 32) != 0); + + if (hash_function != ellswift_xdh_hash_x32) { + /* Verify that the shared secret doesn't match when a different encoding of the same public key is used. */ + /* For A (changing B's public key): */ + memcpy(auxrnd32b_bad, auxrnd32b, sizeof(auxrnd32b_bad)); + testrand_flip(auxrnd32b_bad, sizeof(auxrnd32b_bad)); + ret = rustsecp256k1_v0_11_ellswift_create(CTX, ell64b_bad, sec32b, auxrnd32b_bad); + CHECK(ret); + ret = rustsecp256k1_v0_11_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data); + CHECK(ret); + CHECK(rustsecp256k1_v0_11_memcmp_var(share32_bad, share32a, 32) != 0); + /* For B (changing A's public key): */ + memcpy(auxrnd32a_bad, auxrnd32a, sizeof(auxrnd32a_bad)); + testrand_flip(auxrnd32a_bad, sizeof(auxrnd32a_bad)); + ret = rustsecp256k1_v0_11_ellswift_create(CTX, ell64a_bad, sec32a, auxrnd32a_bad); + CHECK(ret); + ret = rustsecp256k1_v0_11_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data); + CHECK(ret); + CHECK(rustsecp256k1_v0_11_memcmp_var(share32_bad, share32b, 32) != 0); + + /* Verify that swapping sides changes the shared secret. */ + /* For A (claiming to be B): */ + ret = rustsecp256k1_v0_11_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a, 1, hash_function, data); + CHECK(ret); + CHECK(rustsecp256k1_v0_11_memcmp_var(share32_bad, share32a, 32) != 0); + /* For B (claiming to be A): */ + ret = rustsecp256k1_v0_11_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b, 0, hash_function, data); + CHECK(ret); + CHECK(rustsecp256k1_v0_11_memcmp_var(share32_bad, share32b, 32) != 0); + } + } + + /* Test hash initializers. */ + { + rustsecp256k1_v0_11_sha256 sha, sha_optimized; + static const unsigned char encode_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'e', 'n', 'c', 'o', 'd', 'e'}; + static const unsigned char create_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'c', 'r', 'e', 'a', 't', 'e'}; + static const unsigned char bip324_tag[] = {'b', 'i', 'p', '3', '2', '4', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'x', 'o', 'n', 'l', 'y', '_', 'e', 'c', 'd', 'h'}; + + /* Check that hash initialized by + * rustsecp256k1_v0_11_ellswift_sha256_init_encode has the expected + * state. */ + rustsecp256k1_v0_11_sha256_initialize_tagged(&sha, encode_tag, sizeof(encode_tag)); + rustsecp256k1_v0_11_ellswift_sha256_init_encode(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); + + /* Check that hash initialized by + * rustsecp256k1_v0_11_ellswift_sha256_init_create has the expected + * state. */ + rustsecp256k1_v0_11_sha256_initialize_tagged(&sha, create_tag, sizeof(create_tag)); + rustsecp256k1_v0_11_ellswift_sha256_init_create(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); + + /* Check that hash initialized by + * rustsecp256k1_v0_11_ellswift_sha256_init_bip324 has the expected + * state. */ + rustsecp256k1_v0_11_sha256_initialize_tagged(&sha, bip324_tag, sizeof(bip324_tag)); + rustsecp256k1_v0_11_ellswift_sha256_init_bip324(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); + } +} + +#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/Makefile.am.include b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/extrakeys/Makefile.am.include similarity index 50% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/Makefile.am.include rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/extrakeys/Makefile.am.include index acc1f0ed..dcfade50 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/extrakeys/Makefile.am.include +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/extrakeys/Makefile.am.include @@ -1,6 +1,4 @@ -include_HEADERS += include/rustsecp256k1zkp_v0_8_0_extrakeys.h +include_HEADERS += include/rustsecp256k1_v0_11_extrakeys.h noinst_HEADERS += src/modules/extrakeys/tests_impl.h noinst_HEADERS += src/modules/extrakeys/tests_exhaustive_impl.h noinst_HEADERS += src/modules/extrakeys/main_impl.h -noinst_HEADERS += src/modules/extrakeys/hsort.h -noinst_HEADERS += src/modules/extrakeys/hsort_impl.h diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/extrakeys/main_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/extrakeys/main_impl.h new file mode 100644 index 00000000..3b18ca1f --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/extrakeys/main_impl.h @@ -0,0 +1,285 @@ +/*********************************************************************** + * Copyright (c) 2020 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_EXTRAKEYS_MAIN_H +#define SECP256K1_MODULE_EXTRAKEYS_MAIN_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_extrakeys.h" +#include "../../util.h" + +static SECP256K1_INLINE int rustsecp256k1_v0_11_xonly_pubkey_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ge *ge, const rustsecp256k1_v0_11_xonly_pubkey *pubkey) { + return rustsecp256k1_v0_11_pubkey_load(ctx, ge, (const rustsecp256k1_v0_11_pubkey *) pubkey); +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_xonly_pubkey_save(rustsecp256k1_v0_11_xonly_pubkey *pubkey, rustsecp256k1_v0_11_ge *ge) { + rustsecp256k1_v0_11_pubkey_save((rustsecp256k1_v0_11_pubkey *) pubkey, ge); +} + +int rustsecp256k1_v0_11_xonly_pubkey_parse(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_xonly_pubkey *pubkey, const unsigned char *input32) { + rustsecp256k1_v0_11_ge pk; + rustsecp256k1_v0_11_fe x; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(input32 != NULL); + + if (!rustsecp256k1_v0_11_fe_set_b32_limit(&x, input32)) { + return 0; + } + if (!rustsecp256k1_v0_11_ge_set_xo_var(&pk, &x, 0)) { + return 0; + } + if (!rustsecp256k1_v0_11_ge_is_in_correct_subgroup(&pk)) { + return 0; + } + rustsecp256k1_v0_11_xonly_pubkey_save(pubkey, &pk); + return 1; +} + +int rustsecp256k1_v0_11_xonly_pubkey_serialize(const rustsecp256k1_v0_11_context* ctx, unsigned char *output32, const rustsecp256k1_v0_11_xonly_pubkey *pubkey) { + rustsecp256k1_v0_11_ge pk; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output32 != NULL); + memset(output32, 0, 32); + ARG_CHECK(pubkey != NULL); + + if (!rustsecp256k1_v0_11_xonly_pubkey_load(ctx, &pk, pubkey)) { + return 0; + } + rustsecp256k1_v0_11_fe_get_b32(output32, &pk.x); + return 1; +} + +int rustsecp256k1_v0_11_xonly_pubkey_cmp(const rustsecp256k1_v0_11_context* ctx, const rustsecp256k1_v0_11_xonly_pubkey* pk0, const rustsecp256k1_v0_11_xonly_pubkey* pk1) { + unsigned char out[2][32]; + const rustsecp256k1_v0_11_xonly_pubkey* pk[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + pk[0] = pk0; pk[1] = pk1; + for (i = 0; i < 2; i++) { + /* If the public key is NULL or invalid, xonly_pubkey_serialize will + * call the illegal_callback and return 0. In that case we will + * serialize the key as all zeros which is less than any valid public + * key. This results in consistent comparisons even if NULL or invalid + * pubkeys are involved and prevents edge cases such as sorting + * algorithms that use this function and do not terminate as a + * result. */ + if (!rustsecp256k1_v0_11_xonly_pubkey_serialize(ctx, out[i], pk[i])) { + /* Note that xonly_pubkey_serialize should already set the output to + * zero in that case, but it's not guaranteed by the API, we can't + * test it and writing a VERIFY_CHECK is more complex than + * explicitly memsetting (again). */ + memset(out[i], 0, sizeof(out[i])); + } + } + return rustsecp256k1_v0_11_memcmp_var(out[0], out[1], sizeof(out[1])); +} + +/** Keeps a group element as is if it has an even Y and otherwise negates it. + * y_parity is set to 0 in the former case and to 1 in the latter case. + * Requires that the coordinates of r are normalized. */ +static int rustsecp256k1_v0_11_extrakeys_ge_even_y(rustsecp256k1_v0_11_ge *r) { + int y_parity = 0; + VERIFY_CHECK(!rustsecp256k1_v0_11_ge_is_infinity(r)); + + if (rustsecp256k1_v0_11_fe_is_odd(&r->y)) { + rustsecp256k1_v0_11_fe_negate(&r->y, &r->y, 1); + y_parity = 1; + } + return y_parity; +} + +int rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_xonly_pubkey *xonly_pubkey, int *pk_parity, const rustsecp256k1_v0_11_pubkey *pubkey) { + rustsecp256k1_v0_11_ge pk; + int tmp; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(xonly_pubkey != NULL); + ARG_CHECK(pubkey != NULL); + + if (!rustsecp256k1_v0_11_pubkey_load(ctx, &pk, pubkey)) { + return 0; + } + tmp = rustsecp256k1_v0_11_extrakeys_ge_even_y(&pk); + if (pk_parity != NULL) { + *pk_parity = tmp; + } + rustsecp256k1_v0_11_xonly_pubkey_save(xonly_pubkey, &pk); + return 1; +} + +int rustsecp256k1_v0_11_xonly_pubkey_tweak_add(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *output_pubkey, const rustsecp256k1_v0_11_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { + rustsecp256k1_v0_11_ge pk; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output_pubkey != NULL); + memset(output_pubkey, 0, sizeof(*output_pubkey)); + ARG_CHECK(internal_pubkey != NULL); + ARG_CHECK(tweak32 != NULL); + + if (!rustsecp256k1_v0_11_xonly_pubkey_load(ctx, &pk, internal_pubkey) + || !rustsecp256k1_v0_11_ec_pubkey_tweak_add_helper(&pk, tweak32)) { + return 0; + } + rustsecp256k1_v0_11_pubkey_save(output_pubkey, &pk); + return 1; +} + +int rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(const rustsecp256k1_v0_11_context* ctx, const unsigned char *tweaked_pubkey32, int tweaked_pk_parity, const rustsecp256k1_v0_11_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { + rustsecp256k1_v0_11_ge pk; + unsigned char pk_expected32[32]; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(internal_pubkey != NULL); + ARG_CHECK(tweaked_pubkey32 != NULL); + ARG_CHECK(tweak32 != NULL); + + if (!rustsecp256k1_v0_11_xonly_pubkey_load(ctx, &pk, internal_pubkey) + || !rustsecp256k1_v0_11_ec_pubkey_tweak_add_helper(&pk, tweak32)) { + return 0; + } + rustsecp256k1_v0_11_fe_normalize_var(&pk.x); + rustsecp256k1_v0_11_fe_normalize_var(&pk.y); + rustsecp256k1_v0_11_fe_get_b32(pk_expected32, &pk.x); + + return rustsecp256k1_v0_11_memcmp_var(&pk_expected32, tweaked_pubkey32, 32) == 0 + && rustsecp256k1_v0_11_fe_is_odd(&pk.y) == tweaked_pk_parity; +} + +static void rustsecp256k1_v0_11_keypair_save(rustsecp256k1_v0_11_keypair *keypair, const rustsecp256k1_v0_11_scalar *sk, rustsecp256k1_v0_11_ge *pk) { + rustsecp256k1_v0_11_scalar_get_b32(&keypair->data[0], sk); + rustsecp256k1_v0_11_pubkey_save((rustsecp256k1_v0_11_pubkey *)&keypair->data[32], pk); +} + + +static int rustsecp256k1_v0_11_keypair_seckey_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_scalar *sk, const rustsecp256k1_v0_11_keypair *keypair) { + int ret; + + ret = rustsecp256k1_v0_11_scalar_set_b32_seckey(sk, &keypair->data[0]); + /* We can declassify ret here because sk is only zero if a keypair function + * failed (which zeroes the keypair) and its return value is ignored. */ + rustsecp256k1_v0_11_declassify(ctx, &ret, sizeof(ret)); + ARG_CHECK(ret); + return ret; +} + +/* Load a keypair into pk and sk (if non-NULL). This function declassifies pk + * and ARG_CHECKs that the keypair is not invalid. It always initializes sk and + * pk with dummy values. */ +static int rustsecp256k1_v0_11_keypair_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_scalar *sk, rustsecp256k1_v0_11_ge *pk, const rustsecp256k1_v0_11_keypair *keypair) { + int ret; + const rustsecp256k1_v0_11_pubkey *pubkey = (const rustsecp256k1_v0_11_pubkey *)&keypair->data[32]; + + /* Need to declassify the pubkey because pubkey_load ARG_CHECKs if it's + * invalid. */ + rustsecp256k1_v0_11_declassify(ctx, pubkey, sizeof(*pubkey)); + ret = rustsecp256k1_v0_11_pubkey_load(ctx, pk, pubkey); + if (sk != NULL) { + ret = ret && rustsecp256k1_v0_11_keypair_seckey_load(ctx, sk, keypair); + } + if (!ret) { + *pk = rustsecp256k1_v0_11_ge_const_g; + if (sk != NULL) { + *sk = rustsecp256k1_v0_11_scalar_one; + } + } + return ret; +} + +int rustsecp256k1_v0_11_keypair_create(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_keypair *keypair, const unsigned char *seckey32) { + rustsecp256k1_v0_11_scalar sk; + rustsecp256k1_v0_11_ge pk; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(keypair != NULL); + memset(keypair, 0, sizeof(*keypair)); + ARG_CHECK(rustsecp256k1_v0_11_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey32 != NULL); + + ret = rustsecp256k1_v0_11_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &sk, &pk, seckey32); + rustsecp256k1_v0_11_keypair_save(keypair, &sk, &pk); + rustsecp256k1_v0_11_memczero(keypair, sizeof(*keypair), !ret); + + rustsecp256k1_v0_11_scalar_clear(&sk); + return ret; +} + +int rustsecp256k1_v0_11_keypair_sec(const rustsecp256k1_v0_11_context* ctx, unsigned char *seckey, const rustsecp256k1_v0_11_keypair *keypair) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + memset(seckey, 0, 32); + ARG_CHECK(keypair != NULL); + + memcpy(seckey, &keypair->data[0], 32); + return 1; +} + +int rustsecp256k1_v0_11_keypair_pub(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *pubkey, const rustsecp256k1_v0_11_keypair *keypair) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(keypair != NULL); + + memcpy(pubkey->data, &keypair->data[32], sizeof(*pubkey)); + return 1; +} + +int rustsecp256k1_v0_11_keypair_xonly_pub(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_xonly_pubkey *pubkey, int *pk_parity, const rustsecp256k1_v0_11_keypair *keypair) { + rustsecp256k1_v0_11_ge pk; + int tmp; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(keypair != NULL); + + if (!rustsecp256k1_v0_11_keypair_load(ctx, NULL, &pk, keypair)) { + return 0; + } + tmp = rustsecp256k1_v0_11_extrakeys_ge_even_y(&pk); + if (pk_parity != NULL) { + *pk_parity = tmp; + } + rustsecp256k1_v0_11_xonly_pubkey_save(pubkey, &pk); + + return 1; +} + +int rustsecp256k1_v0_11_keypair_xonly_tweak_add(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_keypair *keypair, const unsigned char *tweak32) { + rustsecp256k1_v0_11_ge pk; + rustsecp256k1_v0_11_scalar sk; + int y_parity; + int ret; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(keypair != NULL); + ARG_CHECK(tweak32 != NULL); + + ret = rustsecp256k1_v0_11_keypair_load(ctx, &sk, &pk, keypair); + memset(keypair, 0, sizeof(*keypair)); + + y_parity = rustsecp256k1_v0_11_extrakeys_ge_even_y(&pk); + if (y_parity == 1) { + rustsecp256k1_v0_11_scalar_negate(&sk, &sk); + } + + ret &= rustsecp256k1_v0_11_ec_seckey_tweak_add_helper(&sk, tweak32); + ret &= rustsecp256k1_v0_11_ec_pubkey_tweak_add_helper(&pk, tweak32); + + rustsecp256k1_v0_11_declassify(ctx, &ret, sizeof(ret)); + if (ret) { + rustsecp256k1_v0_11_keypair_save(keypair, &sk, &pk); + } + + rustsecp256k1_v0_11_scalar_clear(&sk); + return ret; +} + +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h new file mode 100644 index 00000000..54dccce7 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h @@ -0,0 +1,68 @@ +/*********************************************************************** + * Copyright (c) 2020 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H +#define SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H + +#include "../../../include/secp256k1_extrakeys.h" +#include "main_impl.h" + +static void test_exhaustive_extrakeys(const rustsecp256k1_v0_11_context *ctx, const rustsecp256k1_v0_11_ge* group) { + rustsecp256k1_v0_11_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1]; + rustsecp256k1_v0_11_pubkey pubkey[EXHAUSTIVE_TEST_ORDER - 1]; + rustsecp256k1_v0_11_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1]; + int parities[EXHAUSTIVE_TEST_ORDER - 1]; + unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32]; + int i; + + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + rustsecp256k1_v0_11_fe fe; + rustsecp256k1_v0_11_scalar scalar_i; + unsigned char buf[33]; + int parity; + + rustsecp256k1_v0_11_scalar_set_int(&scalar_i, i); + rustsecp256k1_v0_11_scalar_get_b32(buf, &scalar_i); + + /* Construct pubkey and keypair. */ + CHECK(rustsecp256k1_v0_11_keypair_create(ctx, &keypair[i - 1], buf)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(ctx, &pubkey[i - 1], buf)); + + /* Construct serialized xonly_pubkey from keypair. */ + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parities[i - 1], &keypair[i - 1])); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1])); + + /* Parse the xonly_pubkey back and verify it matches the previously serialized value. */ + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(ctx, &xonly_pubkey[i - 1], xonly_pubkey_bytes[i - 1])); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1])); + CHECK(rustsecp256k1_v0_11_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0); + + /* Construct the xonly_pubkey from the pubkey, and verify it matches the same. */ + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(ctx, &xonly_pubkey[i - 1], &parity, &pubkey[i - 1])); + CHECK(parity == parities[i - 1]); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1])); + CHECK(rustsecp256k1_v0_11_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0); + + /* Compare the xonly_pubkey bytes against the precomputed group. */ + rustsecp256k1_v0_11_fe_set_b32_mod(&fe, xonly_pubkey_bytes[i - 1]); + CHECK(rustsecp256k1_v0_11_fe_equal(&fe, &group[i].x)); + + /* Check the parity against the precomputed group. */ + fe = group[i].y; + rustsecp256k1_v0_11_fe_normalize_var(&fe); + CHECK(rustsecp256k1_v0_11_fe_is_odd(&fe) == parities[i - 1]); + + /* Verify that the higher half is identical to the lower half mirrored. */ + if (i > EXHAUSTIVE_TEST_ORDER / 2) { + CHECK(rustsecp256k1_v0_11_memcmp_var(xonly_pubkey_bytes[i - 1], xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - i - 1], 32) == 0); + CHECK(parities[i - 1] == 1 - parities[EXHAUSTIVE_TEST_ORDER - i - 1]); + } + } + + /* TODO: keypair/xonly_pubkey tweak tests */ +} + +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/extrakeys/tests_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/extrakeys/tests_impl.h new file mode 100644 index 00000000..544ce31b --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/extrakeys/tests_impl.h @@ -0,0 +1,483 @@ +/*********************************************************************** + * Copyright (c) 2020 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_H +#define SECP256K1_MODULE_EXTRAKEYS_TESTS_H + +#include "../../../include/secp256k1_extrakeys.h" + +static void test_xonly_pubkey(void) { + rustsecp256k1_v0_11_pubkey pk; + rustsecp256k1_v0_11_xonly_pubkey xonly_pk, xonly_pk_tmp; + rustsecp256k1_v0_11_ge pk1; + rustsecp256k1_v0_11_ge pk2; + rustsecp256k1_v0_11_fe y; + unsigned char sk[32]; + unsigned char xy_sk[32]; + unsigned char buf32[32]; + unsigned char ones32[32]; + unsigned char zeros64[64] = { 0 }; + int pk_parity; + int i; + + testrand256(sk); + memset(ones32, 0xFF, 32); + testrand256(xy_sk); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + + /* Test xonly_pubkey_from_pubkey */ + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, NULL, &pk_parity, &pk)); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, NULL)); + memset(&pk, 0, sizeof(pk)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk)); + + /* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */ + memset(sk, 0, sizeof(sk)); + sk[0] = 1; + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pk, &xonly_pk, sizeof(pk)) == 0); + CHECK(pk_parity == 0); + + /* Choose a secret key such that pubkey and xonly_pubkey are each others + * negation. */ + sk[0] = 2; + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&xonly_pk, &pk, sizeof(xonly_pk)) != 0); + CHECK(pk_parity == 1); + rustsecp256k1_v0_11_pubkey_load(CTX, &pk1, &pk); + rustsecp256k1_v0_11_pubkey_load(CTX, &pk2, (rustsecp256k1_v0_11_pubkey *) &xonly_pk); + CHECK(rustsecp256k1_v0_11_fe_equal(&pk1.x, &pk2.x) == 1); + rustsecp256k1_v0_11_fe_negate(&y, &pk2.y, 1); + CHECK(rustsecp256k1_v0_11_fe_equal(&pk1.y, &y) == 1); + + /* Test xonly_pubkey_serialize and xonly_pubkey_parse */ + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, NULL, &xonly_pk)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, buf32, NULL)); + CHECK(rustsecp256k1_v0_11_memcmp_var(buf32, zeros64, 32) == 0); + { + /* A pubkey filled with 0s will fail to serialize due to pubkey_load + * special casing. */ + rustsecp256k1_v0_11_xonly_pubkey pk_tmp; + memset(&pk_tmp, 0, sizeof(pk_tmp)); + /* pubkey_load calls illegal callback */ + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, buf32, &pk_tmp)); + } + + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, NULL, buf32)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &xonly_pk, NULL)); + + /* Serialization and parse roundtrip */ + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &xonly_pk_tmp, buf32) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0); + + /* Test parsing invalid field elements */ + memset(&xonly_pk, 1, sizeof(xonly_pk)); + /* Overflowing field element */ + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &xonly_pk, ones32) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); + memset(&xonly_pk, 1, sizeof(xonly_pk)); + /* There's no point with x-coordinate 0 on secp256k1 */ + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &xonly_pk, zeros64) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); + /* If a random 32-byte string can not be parsed with ec_pubkey_parse + * (because interpreted as X coordinate it does not correspond to a point on + * the curve) then xonly_pubkey_parse should fail as well. */ + for (i = 0; i < COUNT; i++) { + unsigned char rand33[33]; + testrand256(&rand33[1]); + rand33[0] = SECP256K1_TAG_PUBKEY_EVEN; + if (!rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pk, rand33, 33)) { + memset(&xonly_pk, 1, sizeof(xonly_pk)); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); + } else { + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 1); + } + } +} + +static void test_xonly_pubkey_comparison(void) { + unsigned char pk1_ser[32] = { + 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, + 0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23 + }; + const unsigned char pk2_ser[32] = { + 0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d, + 0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c + }; + rustsecp256k1_v0_11_xonly_pubkey pk1; + rustsecp256k1_v0_11_xonly_pubkey pk2; + + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &pk1, pk1_ser) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &pk2, pk2_ser) == 1); + + CHECK_ILLEGAL_VOID(CTX, CHECK(rustsecp256k1_v0_11_xonly_pubkey_cmp(CTX, NULL, &pk2) < 0)); + CHECK_ILLEGAL_VOID(CTX, CHECK(rustsecp256k1_v0_11_xonly_pubkey_cmp(CTX, &pk1, NULL) > 0)); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_cmp(CTX, &pk2, &pk2) == 0); + memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */ + CHECK_ILLEGAL_VOID(CTX, CHECK(rustsecp256k1_v0_11_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0)); + { + int32_t ecount = 0; + rustsecp256k1_v0_11_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0); + CHECK(ecount == 2); + rustsecp256k1_v0_11_context_set_illegal_callback(CTX, NULL, NULL); + } + CHECK_ILLEGAL_VOID(CTX, CHECK(rustsecp256k1_v0_11_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0)); +} + +static void test_xonly_pubkey_tweak(void) { + unsigned char zeros64[64] = { 0 }; + unsigned char overflows[32]; + unsigned char sk[32]; + rustsecp256k1_v0_11_pubkey internal_pk; + rustsecp256k1_v0_11_xonly_pubkey internal_xonly_pk; + rustsecp256k1_v0_11_pubkey output_pk; + int pk_parity; + unsigned char tweak[32]; + int i; + + memset(overflows, 0xff, sizeof(overflows)); + testrand256(tweak); + testrand256(sk); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &internal_pk, sk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); + + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, NULL, &internal_xonly_pk, tweak)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &output_pk, NULL, tweak)); + /* NULL internal_xonly_pk zeroes the output_pk */ + CHECK(rustsecp256k1_v0_11_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, NULL)); + /* NULL tweak zeroes the output_pk */ + CHECK(rustsecp256k1_v0_11_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); + + /* Invalid tweak zeroes the output_pk */ + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); + + /* A zero tweak is fine */ + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, zeros64) == 1); + + /* Fails if the resulting key was infinity */ + for (i = 0; i < COUNT; i++) { + rustsecp256k1_v0_11_scalar scalar_tweak; + /* Because sk may be negated before adding, we need to try with tweak = + * sk as well as tweak = -sk. */ + rustsecp256k1_v0_11_scalar_set_b32(&scalar_tweak, sk, NULL); + rustsecp256k1_v0_11_scalar_negate(&scalar_tweak, &scalar_tweak); + rustsecp256k1_v0_11_scalar_get_b32(tweak, &scalar_tweak); + CHECK((rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, sk) == 0) + || (rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 0)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); + } + + /* Invalid pk with a valid tweak */ + memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk)); + testrand256(tweak); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); +} + +static void test_xonly_pubkey_tweak_check(void) { + unsigned char zeros64[64] = { 0 }; + unsigned char overflows[32]; + unsigned char sk[32]; + rustsecp256k1_v0_11_pubkey internal_pk; + rustsecp256k1_v0_11_xonly_pubkey internal_xonly_pk; + rustsecp256k1_v0_11_pubkey output_pk; + rustsecp256k1_v0_11_xonly_pubkey output_xonly_pk; + unsigned char output_pk32[32]; + unsigned char buf32[32]; + int pk_parity; + unsigned char tweak[32]; + + memset(overflows, 0xff, sizeof(overflows)); + testrand256(tweak); + testrand256(sk); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &internal_pk, sk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); + + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, buf32, &output_xonly_pk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, NULL, pk_parity, &internal_xonly_pk, tweak)); + /* invalid pk_parity value */ + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, buf32, 2, &internal_xonly_pk, tweak) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, NULL, tweak)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, NULL)); + + memset(tweak, 1, sizeof(tweak)); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, NULL, &internal_pk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, output_pk32, &output_xonly_pk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1); + + /* Wrong pk_parity */ + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0); + /* Wrong public key */ + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, buf32, &internal_xonly_pk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 0); + + /* Overflowing tweak not allowed */ + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); +} + +/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1 + * additional pubkeys by calling tweak_add. Then verifies every tweak starting + * from the last pubkey. */ +#define N_PUBKEYS 32 +static void test_xonly_pubkey_tweak_recursive(void) { + unsigned char sk[32]; + rustsecp256k1_v0_11_pubkey pk[N_PUBKEYS]; + unsigned char pk_serialized[32]; + unsigned char tweak[N_PUBKEYS - 1][32]; + int i; + + testrand256(sk); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pk[0], sk) == 1); + /* Add tweaks */ + for (i = 0; i < N_PUBKEYS - 1; i++) { + rustsecp256k1_v0_11_xonly_pubkey xonly_pk; + memset(tweak[i], i + 1, sizeof(tweak[i])); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk[i]) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &pk[i + 1], &xonly_pk, tweak[i]) == 1); + } + + /* Verify tweaks */ + for (i = N_PUBKEYS - 1; i > 0; i--) { + rustsecp256k1_v0_11_xonly_pubkey xonly_pk; + int pk_parity; + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk[i]) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, pk_serialized, &xonly_pk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk[i - 1]) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1); + } +} +#undef N_PUBKEYS + +static void test_keypair(void) { + unsigned char sk[32]; + unsigned char sk_tmp[32]; + unsigned char zeros96[96] = { 0 }; + unsigned char overflows[32]; + rustsecp256k1_v0_11_keypair keypair; + rustsecp256k1_v0_11_pubkey pk, pk_tmp; + rustsecp256k1_v0_11_xonly_pubkey xonly_pk, xonly_pk_tmp; + int pk_parity, pk_parity_tmp; + + CHECK(sizeof(zeros96) == sizeof(keypair)); + memset(overflows, 0xFF, sizeof(overflows)); + + /* Test keypair_create */ + testrand256(sk); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_keypair_create(CTX, NULL, sk)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_keypair_create(CTX, &keypair, NULL)); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + CHECK_ILLEGAL(STATIC_CTX, rustsecp256k1_v0_11_keypair_create(STATIC_CTX, &keypair, sk)); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); + + /* Invalid secret key */ + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, zeros96) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, overflows) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); + + /* Test keypair_pub */ + testrand256(sk); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + CHECK(rustsecp256k1_v0_11_keypair_pub(CTX, &pk, &keypair) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_keypair_pub(CTX, NULL, &keypair)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_keypair_pub(CTX, &pk, NULL)); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); + + /* Using an invalid keypair is fine for keypair_pub */ + memset(&keypair, 0, sizeof(keypair)); + CHECK(rustsecp256k1_v0_11_keypair_pub(CTX, &pk, &keypair) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); + + /* keypair holds the same pubkey as pubkey_create */ + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + CHECK(rustsecp256k1_v0_11_keypair_pub(CTX, &pk_tmp, &keypair) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0); + + /** Test keypair_xonly_pub **/ + testrand256(sk); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair)); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &xonly_pk, NULL, &keypair) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, NULL)); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); + /* Using an invalid keypair will set the xonly_pk to 0 (first reset + * xonly_pk). */ + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1); + memset(&keypair, 0, sizeof(keypair)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair)); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); + + /** keypair holds the same xonly pubkey as pubkey_create **/ + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0); + CHECK(pk_parity == pk_parity_tmp); + + /* Test keypair_seckey */ + testrand256(sk); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + CHECK(rustsecp256k1_v0_11_keypair_sec(CTX, sk_tmp, &keypair) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_keypair_sec(CTX, NULL, &keypair)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_keypair_sec(CTX, sk_tmp, NULL)); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); + + /* keypair returns the same seckey it got */ + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + CHECK(rustsecp256k1_v0_11_keypair_sec(CTX, sk_tmp, &keypair) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(sk, sk_tmp, sizeof(sk_tmp)) == 0); + + + /* Using an invalid keypair is fine for keypair_seckey */ + memset(&keypair, 0, sizeof(keypair)); + CHECK(rustsecp256k1_v0_11_keypair_sec(CTX, sk_tmp, &keypair) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); +} + +static void test_keypair_add(void) { + unsigned char sk[32]; + rustsecp256k1_v0_11_keypair keypair; + unsigned char overflows[32]; + unsigned char zeros96[96] = { 0 }; + unsigned char tweak[32]; + int i; + + CHECK(sizeof(zeros96) == sizeof(keypair)); + testrand256(sk); + testrand256(tweak); + memset(overflows, 0xFF, 32); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + + CHECK(rustsecp256k1_v0_11_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK(rustsecp256k1_v0_11_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK(rustsecp256k1_v0_11_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_keypair_xonly_tweak_add(CTX, NULL, tweak)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_keypair_xonly_tweak_add(CTX, &keypair, NULL)); + /* This does not set the keypair to zeroes */ + CHECK(rustsecp256k1_v0_11_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0); + + /* Invalid tweak zeroes the keypair */ + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + CHECK(rustsecp256k1_v0_11_keypair_xonly_tweak_add(CTX, &keypair, overflows) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); + + /* A zero tweak is fine */ + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + CHECK(rustsecp256k1_v0_11_keypair_xonly_tweak_add(CTX, &keypair, zeros96) == 1); + + /* Fails if the resulting keypair was (sk=0, pk=infinity) */ + for (i = 0; i < COUNT; i++) { + rustsecp256k1_v0_11_scalar scalar_tweak; + rustsecp256k1_v0_11_keypair keypair_tmp; + testrand256(sk); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + memcpy(&keypair_tmp, &keypair, sizeof(keypair)); + /* Because sk may be negated before adding, we need to try with tweak = + * sk as well as tweak = -sk. */ + rustsecp256k1_v0_11_scalar_set_b32(&scalar_tweak, sk, NULL); + rustsecp256k1_v0_11_scalar_negate(&scalar_tweak, &scalar_tweak); + rustsecp256k1_v0_11_scalar_get_b32(tweak, &scalar_tweak); + CHECK((rustsecp256k1_v0_11_keypair_xonly_tweak_add(CTX, &keypair, sk) == 0) + || (rustsecp256k1_v0_11_keypair_xonly_tweak_add(CTX, &keypair_tmp, tweak) == 0)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0 + || rustsecp256k1_v0_11_memcmp_var(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0); + } + + /* Invalid keypair with a valid tweak */ + memset(&keypair, 0, sizeof(keypair)); + testrand256(tweak); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_keypair_xonly_tweak_add(CTX, &keypair, tweak)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); + /* Only seckey part of keypair invalid */ + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + memset(&keypair, 0, 32); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_keypair_xonly_tweak_add(CTX, &keypair, tweak)); + /* Only pubkey part of keypair invalid */ + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + memset(&keypair.data[32], 0, 64); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_keypair_xonly_tweak_add(CTX, &keypair, tweak)); + + /* Check that the keypair_tweak_add implementation is correct */ + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + for (i = 0; i < COUNT; i++) { + rustsecp256k1_v0_11_xonly_pubkey internal_pk; + rustsecp256k1_v0_11_xonly_pubkey output_pk; + rustsecp256k1_v0_11_pubkey output_pk_xy; + rustsecp256k1_v0_11_pubkey output_pk_expected; + unsigned char pk32[32]; + unsigned char sk32[32]; + int pk_parity; + + testrand256(tweak); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1); + CHECK(rustsecp256k1_v0_11_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1); + + /* Check that it passes xonly_pubkey_tweak_add_check */ + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, pk32, &output_pk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, pk32, pk_parity, &internal_pk, tweak) == 1); + + /* Check that the resulting pubkey matches xonly_pubkey_tweak_add */ + CHECK(rustsecp256k1_v0_11_keypair_pub(CTX, &output_pk_xy, &keypair) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add(CTX, &output_pk_expected, &internal_pk, tweak) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); + + /* Check that the secret key in the keypair is tweaked correctly */ + CHECK(rustsecp256k1_v0_11_keypair_sec(CTX, sk32, &keypair) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &output_pk_expected, sk32) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); + } +} + +static void run_extrakeys_tests(void) { + /* xonly key test cases */ + test_xonly_pubkey(); + test_xonly_pubkey_tweak(); + test_xonly_pubkey_tweak_check(); + test_xonly_pubkey_tweak_recursive(); + test_xonly_pubkey_comparison(); + + /* keypair tests */ + test_keypair(); + test_keypair_add(); +} + +#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/Makefile.am.include b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/Makefile.am.include similarity index 72% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/Makefile.am.include rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/Makefile.am.include index 5d9dc608..d478ec75 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/Makefile.am.include +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/Makefile.am.include @@ -1,8 +1,8 @@ -include_HEADERS += include/rustsecp256k1zkp_v0_8_0_musig.h +include_HEADERS += include/rustsecp256k1_v0_11_musig.h noinst_HEADERS += src/modules/musig/main_impl.h noinst_HEADERS += src/modules/musig/keyagg.h noinst_HEADERS += src/modules/musig/keyagg_impl.h noinst_HEADERS += src/modules/musig/session.h noinst_HEADERS += src/modules/musig/session_impl.h -noinst_HEADERS += src/modules/musig/adaptor_impl.h noinst_HEADERS += src/modules/musig/tests_impl.h +noinst_HEADERS += src/modules/musig/vectors.h diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/keyagg.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/keyagg.h new file mode 100644 index 00000000..bee2a322 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/keyagg.h @@ -0,0 +1,32 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_H +#define SECP256K1_MODULE_MUSIG_KEYAGG_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_musig.h" + +#include "../../group.h" +#include "../../scalar.h" + +typedef struct { + rustsecp256k1_v0_11_ge pk; + /* If there is no "second" public key, second_pk is set to the point at + * infinity */ + rustsecp256k1_v0_11_ge second_pk; + unsigned char pks_hash[32]; + /* tweak is identical to value tacc[v] in the specification. */ + rustsecp256k1_v0_11_scalar tweak; + /* parity_acc corresponds to (1 - gacc[v])/2 in the spec. So if gacc[v] is + * -1, parity_acc is 1. Otherwise, parity_acc is 0. */ + int parity_acc; +} rustsecp256k1_v0_11_keyagg_cache_internal; + +static int rustsecp256k1_v0_11_keyagg_cache_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_keyagg_cache_internal *cache_i, const rustsecp256k1_v0_11_musig_keyagg_cache *cache); + +static void rustsecp256k1_v0_11_musig_keyaggcoef(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_keyagg_cache_internal *cache_i, rustsecp256k1_v0_11_ge *pk); + +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/keyagg_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/keyagg_impl.h new file mode 100644 index 00000000..c21b45d8 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/keyagg_impl.h @@ -0,0 +1,291 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H +#define SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H + +#include + +#include "keyagg.h" +#include "../../eckey.h" +#include "../../ecmult.h" +#include "../../field.h" +#include "../../group.h" +#include "../../hash.h" +#include "../../util.h" + +static const unsigned char rustsecp256k1_v0_11_musig_keyagg_cache_magic[4] = { 0xf4, 0xad, 0xbb, 0xdf }; + +/* A keyagg cache consists of + * - 4 byte magic set during initialization to allow detecting an uninitialized + * object. + * - 64 byte aggregate (and potentially tweaked) public key + * - 64 byte "second" public key (set to the point at infinity if not present) + * - 32 byte hash of all public keys + * - 1 byte the parity of the internal key (if tweaked, otherwise 0) + * - 32 byte tweak + */ +/* Requires that cache_i->pk is not infinity. */ +static void rustsecp256k1_v0_11_keyagg_cache_save(rustsecp256k1_v0_11_musig_keyagg_cache *cache, const rustsecp256k1_v0_11_keyagg_cache_internal *cache_i) { + unsigned char *ptr = cache->data; + memcpy(ptr, rustsecp256k1_v0_11_musig_keyagg_cache_magic, 4); + ptr += 4; + rustsecp256k1_v0_11_ge_to_bytes(ptr, &cache_i->pk); + ptr += 64; + rustsecp256k1_v0_11_ge_to_bytes_ext(ptr, &cache_i->second_pk); + ptr += 64; + memcpy(ptr, cache_i->pks_hash, 32); + ptr += 32; + *ptr = cache_i->parity_acc; + ptr += 1; + rustsecp256k1_v0_11_scalar_get_b32(ptr, &cache_i->tweak); +} + +static int rustsecp256k1_v0_11_keyagg_cache_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_keyagg_cache_internal *cache_i, const rustsecp256k1_v0_11_musig_keyagg_cache *cache) { + const unsigned char *ptr = cache->data; + ARG_CHECK(rustsecp256k1_v0_11_memcmp_var(ptr, rustsecp256k1_v0_11_musig_keyagg_cache_magic, 4) == 0); + ptr += 4; + rustsecp256k1_v0_11_ge_from_bytes(&cache_i->pk, ptr); + ptr += 64; + rustsecp256k1_v0_11_ge_from_bytes_ext(&cache_i->second_pk, ptr); + ptr += 64; + memcpy(cache_i->pks_hash, ptr, 32); + ptr += 32; + cache_i->parity_acc = *ptr & 1; + ptr += 1; + rustsecp256k1_v0_11_scalar_set_b32(&cache_i->tweak, ptr, NULL); + return 1; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("KeyAgg list")||SHA256("KeyAgg list"). */ +static void rustsecp256k1_v0_11_musig_keyagglist_sha256(rustsecp256k1_v0_11_sha256 *sha) { + rustsecp256k1_v0_11_sha256_initialize(sha); + + sha->s[0] = 0xb399d5e0ul; + sha->s[1] = 0xc8fff302ul; + sha->s[2] = 0x6badac71ul; + sha->s[3] = 0x07c5b7f1ul; + sha->s[4] = 0x9701e2eful; + sha->s[5] = 0x2a72ecf8ul; + sha->s[6] = 0x201a4c7bul; + sha->s[7] = 0xab148a38ul; + sha->bytes = 64; +} + +/* Computes pks_hash = tagged_hash(pk[0], ..., pk[np-1]) */ +static int rustsecp256k1_v0_11_musig_compute_pks_hash(const rustsecp256k1_v0_11_context *ctx, unsigned char *pks_hash, const rustsecp256k1_v0_11_pubkey * const* pks, size_t np) { + rustsecp256k1_v0_11_sha256 sha; + size_t i; + + rustsecp256k1_v0_11_musig_keyagglist_sha256(&sha); + for (i = 0; i < np; i++) { + unsigned char ser[33]; + size_t ser_len = sizeof(ser); + if (!rustsecp256k1_v0_11_ec_pubkey_serialize(ctx, ser, &ser_len, pks[i], SECP256K1_EC_COMPRESSED)) { + return 0; + } + VERIFY_CHECK(ser_len == sizeof(ser)); + rustsecp256k1_v0_11_sha256_write(&sha, ser, sizeof(ser)); + } + rustsecp256k1_v0_11_sha256_finalize(&sha, pks_hash); + return 1; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("KeyAgg coefficient")||SHA256("KeyAgg coefficient"). */ +static void rustsecp256k1_v0_11_musig_keyaggcoef_sha256(rustsecp256k1_v0_11_sha256 *sha) { + rustsecp256k1_v0_11_sha256_initialize(sha); + + sha->s[0] = 0x6ef02c5aul; + sha->s[1] = 0x06a480deul; + sha->s[2] = 0x1f298665ul; + sha->s[3] = 0x1d1134f2ul; + sha->s[4] = 0x56a0b063ul; + sha->s[5] = 0x52da4147ul; + sha->s[6] = 0xf280d9d4ul; + sha->s[7] = 0x4484be15ul; + sha->bytes = 64; +} + +/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and + * otherwise tagged_hash(pks_hash, pk) where pks_hash is the hash of public keys. + * second_pk is the point at infinity in case there is no second_pk. Assumes + * that pk is not the point at infinity and that the Y-coordinates of pk and + * second_pk are normalized. */ +static void rustsecp256k1_v0_11_musig_keyaggcoef_internal(rustsecp256k1_v0_11_scalar *r, const unsigned char *pks_hash, rustsecp256k1_v0_11_ge *pk, const rustsecp256k1_v0_11_ge *second_pk) { + VERIFY_CHECK(!rustsecp256k1_v0_11_ge_is_infinity(pk)); + + if (!rustsecp256k1_v0_11_ge_is_infinity(second_pk) + && rustsecp256k1_v0_11_ge_eq_var(pk, second_pk)) { + rustsecp256k1_v0_11_scalar_set_int(r, 1); + } else { + rustsecp256k1_v0_11_sha256 sha; + unsigned char buf[33]; + size_t buflen = sizeof(buf); + int ret; + rustsecp256k1_v0_11_musig_keyaggcoef_sha256(&sha); + rustsecp256k1_v0_11_sha256_write(&sha, pks_hash, 32); + ret = rustsecp256k1_v0_11_eckey_pubkey_serialize(pk, buf, &buflen, 1); +#ifdef VERIFY + /* Serialization does not fail since the pk is not the point at infinity + * (according to this function's precondition). */ + VERIFY_CHECK(ret && buflen == sizeof(buf)); +#else + (void) ret; +#endif + rustsecp256k1_v0_11_sha256_write(&sha, buf, sizeof(buf)); + rustsecp256k1_v0_11_sha256_finalize(&sha, buf); + rustsecp256k1_v0_11_scalar_set_b32(r, buf, NULL); + } +} + +/* Assumes that pk is not the point at infinity and that the Y-coordinates of pk + * and cache_i->second_pk are normalized. */ +static void rustsecp256k1_v0_11_musig_keyaggcoef(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_keyagg_cache_internal *cache_i, rustsecp256k1_v0_11_ge *pk) { + rustsecp256k1_v0_11_musig_keyaggcoef_internal(r, cache_i->pks_hash, pk, &cache_i->second_pk); +} + +typedef struct { + const rustsecp256k1_v0_11_context *ctx; + /* pks_hash is the hash of the public keys */ + unsigned char pks_hash[32]; + const rustsecp256k1_v0_11_pubkey * const* pks; + rustsecp256k1_v0_11_ge second_pk; +} rustsecp256k1_v0_11_musig_pubkey_agg_ecmult_data; + +/* Callback for batch EC multiplication to compute keyaggcoef_0*P0 + keyaggcoef_1*P1 + ... */ +static int rustsecp256k1_v0_11_musig_pubkey_agg_callback(rustsecp256k1_v0_11_scalar *sc, rustsecp256k1_v0_11_ge *pt, size_t idx, void *data) { + rustsecp256k1_v0_11_musig_pubkey_agg_ecmult_data *ctx = (rustsecp256k1_v0_11_musig_pubkey_agg_ecmult_data *) data; + int ret; + ret = rustsecp256k1_v0_11_pubkey_load(ctx->ctx, pt, ctx->pks[idx]); +#ifdef VERIFY + /* pubkey_load can't fail because the same pks have already been loaded in + * `musig_compute_pks_hash` (and we test this). */ + VERIFY_CHECK(ret); +#else + (void) ret; +#endif + rustsecp256k1_v0_11_musig_keyaggcoef_internal(sc, ctx->pks_hash, pt, &ctx->second_pk); + return 1; +} + +int rustsecp256k1_v0_11_musig_pubkey_agg(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_xonly_pubkey *agg_pk, rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, const rustsecp256k1_v0_11_pubkey * const* pubkeys, size_t n_pubkeys) { + rustsecp256k1_v0_11_musig_pubkey_agg_ecmult_data ecmult_data; + rustsecp256k1_v0_11_gej pkj; + rustsecp256k1_v0_11_ge pkp; + size_t i; + + VERIFY_CHECK(ctx != NULL); + if (agg_pk != NULL) { + memset(agg_pk, 0, sizeof(*agg_pk)); + } + ARG_CHECK(pubkeys != NULL); + ARG_CHECK(n_pubkeys > 0); + + ecmult_data.ctx = ctx; + ecmult_data.pks = pubkeys; + + rustsecp256k1_v0_11_ge_set_infinity(&ecmult_data.second_pk); + for (i = 1; i < n_pubkeys; i++) { + if (rustsecp256k1_v0_11_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) { + rustsecp256k1_v0_11_ge pk; + if (!rustsecp256k1_v0_11_pubkey_load(ctx, &pk, pubkeys[i])) { + return 0; + } + ecmult_data.second_pk = pk; + break; + } + } + + if (!rustsecp256k1_v0_11_musig_compute_pks_hash(ctx, ecmult_data.pks_hash, pubkeys, n_pubkeys)) { + return 0; + } + /* TODO: actually use optimized ecmult_multi algorithms by providing a + * scratch space */ + if (!rustsecp256k1_v0_11_ecmult_multi_var(&ctx->error_callback, NULL, &pkj, NULL, rustsecp256k1_v0_11_musig_pubkey_agg_callback, (void *) &ecmult_data, n_pubkeys)) { + /* In order to reach this line with the current implementation of + * ecmult_multi_var one would need to provide a callback that can + * fail. */ + return 0; + } + rustsecp256k1_v0_11_ge_set_gej(&pkp, &pkj); + rustsecp256k1_v0_11_fe_normalize_var(&pkp.y); + /* The resulting public key is infinity with negligible probability */ + VERIFY_CHECK(!rustsecp256k1_v0_11_ge_is_infinity(&pkp)); + if (keyagg_cache != NULL) { + rustsecp256k1_v0_11_keyagg_cache_internal cache_i = { 0 }; + cache_i.pk = pkp; + cache_i.second_pk = ecmult_data.second_pk; + memcpy(cache_i.pks_hash, ecmult_data.pks_hash, sizeof(cache_i.pks_hash)); + rustsecp256k1_v0_11_keyagg_cache_save(keyagg_cache, &cache_i); + } + + if (agg_pk != NULL) { + rustsecp256k1_v0_11_extrakeys_ge_even_y(&pkp); + rustsecp256k1_v0_11_xonly_pubkey_save(agg_pk, &pkp); + } + return 1; +} + +int rustsecp256k1_v0_11_musig_pubkey_get(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *agg_pk, const rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache) { + rustsecp256k1_v0_11_keyagg_cache_internal cache_i; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(agg_pk != NULL); + memset(agg_pk, 0, sizeof(*agg_pk)); + ARG_CHECK(keyagg_cache != NULL); + + if (!rustsecp256k1_v0_11_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + rustsecp256k1_v0_11_pubkey_save(agg_pk, &cache_i.pk); + return 1; +} + +static int rustsecp256k1_v0_11_musig_pubkey_tweak_add_internal(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *output_pubkey, rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32, int xonly) { + rustsecp256k1_v0_11_keyagg_cache_internal cache_i; + int overflow = 0; + rustsecp256k1_v0_11_scalar tweak; + + VERIFY_CHECK(ctx != NULL); + if (output_pubkey != NULL) { + memset(output_pubkey, 0, sizeof(*output_pubkey)); + } + ARG_CHECK(keyagg_cache != NULL); + ARG_CHECK(tweak32 != NULL); + + if (!rustsecp256k1_v0_11_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + rustsecp256k1_v0_11_scalar_set_b32(&tweak, tweak32, &overflow); + if (overflow) { + return 0; + } + if (xonly && rustsecp256k1_v0_11_extrakeys_ge_even_y(&cache_i.pk)) { + cache_i.parity_acc ^= 1; + rustsecp256k1_v0_11_scalar_negate(&cache_i.tweak, &cache_i.tweak); + } + rustsecp256k1_v0_11_scalar_add(&cache_i.tweak, &cache_i.tweak, &tweak); + if (!rustsecp256k1_v0_11_eckey_pubkey_tweak_add(&cache_i.pk, &tweak)) { + return 0; + } + /* eckey_pubkey_tweak_add fails if cache_i.pk is infinity */ + VERIFY_CHECK(!rustsecp256k1_v0_11_ge_is_infinity(&cache_i.pk)); + rustsecp256k1_v0_11_keyagg_cache_save(keyagg_cache, &cache_i); + if (output_pubkey != NULL) { + rustsecp256k1_v0_11_pubkey_save(output_pubkey, &cache_i.pk); + } + return 1; +} + +int rustsecp256k1_v0_11_musig_pubkey_ec_tweak_add(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *output_pubkey, rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) { + return rustsecp256k1_v0_11_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 0); +} + +int rustsecp256k1_v0_11_musig_pubkey_xonly_tweak_add(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *output_pubkey, rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) { + return rustsecp256k1_v0_11_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 1); +} + +#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/main_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/main_impl.h similarity index 67% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/main_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/main_impl.h index 53a62979..a1311e41 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/main_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/main_impl.h @@ -1,14 +1,12 @@ /********************************************************************** - * Copyright (c) 2018 Andrew Poelstra, Jonas Nick * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef SECP256K1_MODULE_MUSIG_MAIN -#define SECP256K1_MODULE_MUSIG_MAIN +#ifndef SECP256K1_MODULE_MUSIG_MAIN_H +#define SECP256K1_MODULE_MUSIG_MAIN_H #include "keyagg_impl.h" #include "session_impl.h" -#include "adaptor_impl.h" #endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/session.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/session.h similarity index 55% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/session.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/session.h index 78bd4f20..d010a9b8 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/session.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/session.h @@ -1,5 +1,4 @@ /*********************************************************************** - * Copyright (c) 2021 Jonas Nick * * Distributed under the MIT software license, see the accompanying * * file COPYING or https://www.opensource.org/licenses/mit-license.php.* ***********************************************************************/ @@ -15,11 +14,11 @@ typedef struct { int fin_nonce_parity; unsigned char fin_nonce[32]; - rustsecp256k1zkp_v0_8_0_scalar noncecoef; - rustsecp256k1zkp_v0_8_0_scalar challenge; - rustsecp256k1zkp_v0_8_0_scalar s_part; -} rustsecp256k1zkp_v0_8_0_musig_session_internal; + rustsecp256k1_v0_11_scalar noncecoef; + rustsecp256k1_v0_11_scalar challenge; + rustsecp256k1_v0_11_scalar s_part; +} rustsecp256k1_v0_11_musig_session_internal; -static int rustsecp256k1zkp_v0_8_0_musig_session_load(const rustsecp256k1zkp_v0_8_0_context* ctx, rustsecp256k1zkp_v0_8_0_musig_session_internal *session_i, const rustsecp256k1zkp_v0_8_0_musig_session *session); +static int rustsecp256k1_v0_11_musig_session_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_musig_session_internal *session_i, const rustsecp256k1_v0_11_musig_session *session); #endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/session_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/session_impl.h new file mode 100644 index 00000000..41891024 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/session_impl.h @@ -0,0 +1,816 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_SESSION_IMPL_H +#define SECP256K1_MODULE_MUSIG_SESSION_IMPL_H + +#include + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_extrakeys.h" +#include "../../../include/secp256k1_musig.h" + +#include "keyagg.h" +#include "session.h" +#include "../../eckey.h" +#include "../../hash.h" +#include "../../scalar.h" +#include "../../util.h" + +/* Outputs 33 zero bytes if the given group element is the point at infinity and + * otherwise outputs the compressed serialization */ +static void rustsecp256k1_v0_11_musig_ge_serialize_ext(unsigned char *out33, rustsecp256k1_v0_11_ge* ge) { + if (rustsecp256k1_v0_11_ge_is_infinity(ge)) { + memset(out33, 0, 33); + } else { + int ret; + size_t size = 33; + ret = rustsecp256k1_v0_11_eckey_pubkey_serialize(ge, out33, &size, 1); +#ifdef VERIFY + /* Serialize must succeed because the point is not at infinity */ + VERIFY_CHECK(ret && size == 33); +#else + (void) ret; +#endif + } +} + +/* Outputs the point at infinity if the given byte array is all zero, otherwise + * attempts to parse compressed point serialization. */ +static int rustsecp256k1_v0_11_musig_ge_parse_ext(rustsecp256k1_v0_11_ge* ge, const unsigned char *in33) { + unsigned char zeros[33] = { 0 }; + + if (rustsecp256k1_v0_11_memcmp_var(in33, zeros, sizeof(zeros)) == 0) { + rustsecp256k1_v0_11_ge_set_infinity(ge); + return 1; + } + if (!rustsecp256k1_v0_11_eckey_pubkey_parse(ge, in33, 33)) { + return 0; + } + return rustsecp256k1_v0_11_ge_is_in_correct_subgroup(ge); +} + +static const unsigned char rustsecp256k1_v0_11_musig_secnonce_magic[4] = { 0x22, 0x0e, 0xdc, 0xf1 }; + +static void rustsecp256k1_v0_11_musig_secnonce_save(rustsecp256k1_v0_11_musig_secnonce *secnonce, const rustsecp256k1_v0_11_scalar *k, const rustsecp256k1_v0_11_ge *pk) { + memcpy(&secnonce->data[0], rustsecp256k1_v0_11_musig_secnonce_magic, 4); + rustsecp256k1_v0_11_scalar_get_b32(&secnonce->data[4], &k[0]); + rustsecp256k1_v0_11_scalar_get_b32(&secnonce->data[36], &k[1]); + rustsecp256k1_v0_11_ge_to_bytes(&secnonce->data[68], pk); +} + +static int rustsecp256k1_v0_11_musig_secnonce_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_scalar *k, rustsecp256k1_v0_11_ge *pk, const rustsecp256k1_v0_11_musig_secnonce *secnonce) { + int is_zero; + ARG_CHECK(rustsecp256k1_v0_11_memcmp_var(&secnonce->data[0], rustsecp256k1_v0_11_musig_secnonce_magic, 4) == 0); + /* We make very sure that the nonce isn't invalidated by checking the values + * in addition to the magic. */ + is_zero = rustsecp256k1_v0_11_is_zero_array(&secnonce->data[4], 2 * 32); + rustsecp256k1_v0_11_declassify(ctx, &is_zero, sizeof(is_zero)); + ARG_CHECK(!is_zero); + + rustsecp256k1_v0_11_scalar_set_b32(&k[0], &secnonce->data[4], NULL); + rustsecp256k1_v0_11_scalar_set_b32(&k[1], &secnonce->data[36], NULL); + rustsecp256k1_v0_11_ge_from_bytes(pk, &secnonce->data[68]); + return 1; +} + +/* If flag is true, invalidate the secnonce; otherwise leave it. Constant-time. */ +static void rustsecp256k1_v0_11_musig_secnonce_invalidate(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_musig_secnonce *secnonce, int flag) { + rustsecp256k1_v0_11_memczero(secnonce->data, sizeof(secnonce->data), flag); + /* The flag argument is usually classified. So, the line above makes the + * magic and public key classified. However, we need both to be + * declassified. Note that we don't declassify the entire object, because if + * flag is 0, then k[0] and k[1] have not been zeroed. */ + rustsecp256k1_v0_11_declassify(ctx, secnonce->data, sizeof(rustsecp256k1_v0_11_musig_secnonce_magic)); + rustsecp256k1_v0_11_declassify(ctx, &secnonce->data[68], 64); +} + +static const unsigned char rustsecp256k1_v0_11_musig_pubnonce_magic[4] = { 0xf5, 0x7a, 0x3d, 0xa0 }; + +/* Saves two group elements into a pubnonce. Requires that none of the provided + * group elements is infinity. */ +static void rustsecp256k1_v0_11_musig_pubnonce_save(rustsecp256k1_v0_11_musig_pubnonce* nonce, const rustsecp256k1_v0_11_ge* ges) { + int i; + memcpy(&nonce->data[0], rustsecp256k1_v0_11_musig_pubnonce_magic, 4); + for (i = 0; i < 2; i++) { + rustsecp256k1_v0_11_ge_to_bytes(nonce->data + 4+64*i, &ges[i]); + } +} + +/* Loads two group elements from a pubnonce. Returns 1 unless the nonce wasn't + * properly initialized */ +static int rustsecp256k1_v0_11_musig_pubnonce_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ge* ges, const rustsecp256k1_v0_11_musig_pubnonce* nonce) { + int i; + + ARG_CHECK(rustsecp256k1_v0_11_memcmp_var(&nonce->data[0], rustsecp256k1_v0_11_musig_pubnonce_magic, 4) == 0); + for (i = 0; i < 2; i++) { + rustsecp256k1_v0_11_ge_from_bytes(&ges[i], nonce->data + 4 + 64*i); + } + return 1; +} + +static const unsigned char rustsecp256k1_v0_11_musig_aggnonce_magic[4] = { 0xa8, 0xb7, 0xe4, 0x67 }; + +static void rustsecp256k1_v0_11_musig_aggnonce_save(rustsecp256k1_v0_11_musig_aggnonce* nonce, const rustsecp256k1_v0_11_ge* ges) { + int i; + memcpy(&nonce->data[0], rustsecp256k1_v0_11_musig_aggnonce_magic, 4); + for (i = 0; i < 2; i++) { + rustsecp256k1_v0_11_ge_to_bytes_ext(&nonce->data[4 + 64*i], &ges[i]); + } +} + +static int rustsecp256k1_v0_11_musig_aggnonce_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ge* ges, const rustsecp256k1_v0_11_musig_aggnonce* nonce) { + int i; + + ARG_CHECK(rustsecp256k1_v0_11_memcmp_var(&nonce->data[0], rustsecp256k1_v0_11_musig_aggnonce_magic, 4) == 0); + for (i = 0; i < 2; i++) { + rustsecp256k1_v0_11_ge_from_bytes_ext(&ges[i], &nonce->data[4 + 64*i]); + } + return 1; +} + +static const unsigned char rustsecp256k1_v0_11_musig_session_cache_magic[4] = { 0x9d, 0xed, 0xe9, 0x17 }; + +/* A session consists of + * - 4 byte session cache magic + * - 1 byte the parity of the final nonce + * - 32 byte serialized x-only final nonce + * - 32 byte nonce coefficient b + * - 32 byte signature challenge hash e + * - 32 byte scalar s that is added to the partial signatures of the signers + */ +static void rustsecp256k1_v0_11_musig_session_save(rustsecp256k1_v0_11_musig_session *session, const rustsecp256k1_v0_11_musig_session_internal *session_i) { + unsigned char *ptr = session->data; + + memcpy(ptr, rustsecp256k1_v0_11_musig_session_cache_magic, 4); + ptr += 4; + *ptr = session_i->fin_nonce_parity; + ptr += 1; + memcpy(ptr, session_i->fin_nonce, 32); + ptr += 32; + rustsecp256k1_v0_11_scalar_get_b32(ptr, &session_i->noncecoef); + ptr += 32; + rustsecp256k1_v0_11_scalar_get_b32(ptr, &session_i->challenge); + ptr += 32; + rustsecp256k1_v0_11_scalar_get_b32(ptr, &session_i->s_part); +} + +static int rustsecp256k1_v0_11_musig_session_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_musig_session_internal *session_i, const rustsecp256k1_v0_11_musig_session *session) { + const unsigned char *ptr = session->data; + + ARG_CHECK(rustsecp256k1_v0_11_memcmp_var(ptr, rustsecp256k1_v0_11_musig_session_cache_magic, 4) == 0); + ptr += 4; + session_i->fin_nonce_parity = *ptr; + ptr += 1; + memcpy(session_i->fin_nonce, ptr, 32); + ptr += 32; + rustsecp256k1_v0_11_scalar_set_b32(&session_i->noncecoef, ptr, NULL); + ptr += 32; + rustsecp256k1_v0_11_scalar_set_b32(&session_i->challenge, ptr, NULL); + ptr += 32; + rustsecp256k1_v0_11_scalar_set_b32(&session_i->s_part, ptr, NULL); + return 1; +} + +static const unsigned char rustsecp256k1_v0_11_musig_partial_sig_magic[4] = { 0xeb, 0xfb, 0x1a, 0x32 }; + +static void rustsecp256k1_v0_11_musig_partial_sig_save(rustsecp256k1_v0_11_musig_partial_sig* sig, rustsecp256k1_v0_11_scalar *s) { + memcpy(&sig->data[0], rustsecp256k1_v0_11_musig_partial_sig_magic, 4); + rustsecp256k1_v0_11_scalar_get_b32(&sig->data[4], s); +} + +static int rustsecp256k1_v0_11_musig_partial_sig_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_scalar *s, const rustsecp256k1_v0_11_musig_partial_sig* sig) { + int overflow; + + ARG_CHECK(rustsecp256k1_v0_11_memcmp_var(&sig->data[0], rustsecp256k1_v0_11_musig_partial_sig_magic, 4) == 0); + rustsecp256k1_v0_11_scalar_set_b32(s, &sig->data[4], &overflow); + /* Parsed signatures can not overflow */ + VERIFY_CHECK(!overflow); + return 1; +} + +int rustsecp256k1_v0_11_musig_pubnonce_parse(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_musig_pubnonce* nonce, const unsigned char *in66) { + rustsecp256k1_v0_11_ge ges[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(nonce != NULL); + ARG_CHECK(in66 != NULL); + + for (i = 0; i < 2; i++) { + if (!rustsecp256k1_v0_11_eckey_pubkey_parse(&ges[i], &in66[33*i], 33)) { + return 0; + } + if (!rustsecp256k1_v0_11_ge_is_in_correct_subgroup(&ges[i])) { + return 0; + } + } + rustsecp256k1_v0_11_musig_pubnonce_save(nonce, ges); + return 1; +} + +int rustsecp256k1_v0_11_musig_pubnonce_serialize(const rustsecp256k1_v0_11_context* ctx, unsigned char *out66, const rustsecp256k1_v0_11_musig_pubnonce* nonce) { + rustsecp256k1_v0_11_ge ges[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out66 != NULL); + memset(out66, 0, 66); + ARG_CHECK(nonce != NULL); + + if (!rustsecp256k1_v0_11_musig_pubnonce_load(ctx, ges, nonce)) { + return 0; + } + for (i = 0; i < 2; i++) { + int ret; + size_t size = 33; + ret = rustsecp256k1_v0_11_eckey_pubkey_serialize(&ges[i], &out66[33*i], &size, 1); +#ifdef VERIFY + /* serialize must succeed because the point was just loaded */ + VERIFY_CHECK(ret && size == 33); +#else + (void) ret; +#endif + } + return 1; +} + +int rustsecp256k1_v0_11_musig_aggnonce_parse(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_musig_aggnonce* nonce, const unsigned char *in66) { + rustsecp256k1_v0_11_ge ges[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(nonce != NULL); + ARG_CHECK(in66 != NULL); + + for (i = 0; i < 2; i++) { + if (!rustsecp256k1_v0_11_musig_ge_parse_ext(&ges[i], &in66[33*i])) { + return 0; + } + } + rustsecp256k1_v0_11_musig_aggnonce_save(nonce, ges); + return 1; +} + +int rustsecp256k1_v0_11_musig_aggnonce_serialize(const rustsecp256k1_v0_11_context* ctx, unsigned char *out66, const rustsecp256k1_v0_11_musig_aggnonce* nonce) { + rustsecp256k1_v0_11_ge ges[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out66 != NULL); + memset(out66, 0, 66); + ARG_CHECK(nonce != NULL); + + if (!rustsecp256k1_v0_11_musig_aggnonce_load(ctx, ges, nonce)) { + return 0; + } + for (i = 0; i < 2; i++) { + rustsecp256k1_v0_11_musig_ge_serialize_ext(&out66[33*i], &ges[i]); + } + return 1; +} + +int rustsecp256k1_v0_11_musig_partial_sig_parse(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_musig_partial_sig* sig, const unsigned char *in32) { + rustsecp256k1_v0_11_scalar tmp; + int overflow; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(in32 != NULL); + + /* Ensure that using the signature will fail if parsing fails (and the user + * doesn't check the return value). */ + memset(sig, 0, sizeof(*sig)); + + rustsecp256k1_v0_11_scalar_set_b32(&tmp, in32, &overflow); + if (overflow) { + return 0; + } + rustsecp256k1_v0_11_musig_partial_sig_save(sig, &tmp); + return 1; +} + +int rustsecp256k1_v0_11_musig_partial_sig_serialize(const rustsecp256k1_v0_11_context* ctx, unsigned char *out32, const rustsecp256k1_v0_11_musig_partial_sig* sig) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out32 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(rustsecp256k1_v0_11_memcmp_var(&sig->data[0], rustsecp256k1_v0_11_musig_partial_sig_magic, 4) == 0); + + memcpy(out32, &sig->data[4], 32); + return 1; +} + +/* Write optional inputs into the hash */ +static void rustsecp256k1_v0_11_nonce_function_musig_helper(rustsecp256k1_v0_11_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) { + unsigned char zero[7] = { 0 }; + /* The spec requires length prefixes to be between 1 and 8 bytes + * (inclusive) */ + VERIFY_CHECK(prefix_size >= 1 && prefix_size <= 8); + /* Since the length of all input data fits in a byte, we can always pad the + * length prefix with prefix_size - 1 zero bytes. */ + rustsecp256k1_v0_11_sha256_write(sha, zero, prefix_size - 1); + if (data != NULL) { + rustsecp256k1_v0_11_sha256_write(sha, &len, 1); + rustsecp256k1_v0_11_sha256_write(sha, data, len); + } else { + len = 0; + rustsecp256k1_v0_11_sha256_write(sha, &len, 1); + } +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("MuSig/aux")||SHA256("MuSig/aux"). */ +static void rustsecp256k1_v0_11_nonce_function_musig_sha256_tagged_aux(rustsecp256k1_v0_11_sha256 *sha) { + rustsecp256k1_v0_11_sha256_initialize(sha); + sha->s[0] = 0xa19e884bul; + sha->s[1] = 0xf463fe7eul; + sha->s[2] = 0x2f18f9a2ul; + sha->s[3] = 0xbeb0f9fful; + sha->s[4] = 0x0f37e8b0ul; + sha->s[5] = 0x06ebd26ful; + sha->s[6] = 0xe3b243d2ul; + sha->s[7] = 0x522fb150ul; + sha->bytes = 64; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("MuSig/nonce")||SHA256("MuSig/nonce"). */ +static void rustsecp256k1_v0_11_nonce_function_musig_sha256_tagged(rustsecp256k1_v0_11_sha256 *sha) { + rustsecp256k1_v0_11_sha256_initialize(sha); + sha->s[0] = 0x07101b64ul; + sha->s[1] = 0x18003414ul; + sha->s[2] = 0x0391bc43ul; + sha->s[3] = 0x0e6258eeul; + sha->s[4] = 0x29d26b72ul; + sha->s[5] = 0x8343937eul; + sha->s[6] = 0xb7a0a4fbul; + sha->s[7] = 0xff568a30ul; + sha->bytes = 64; +} + +static void rustsecp256k1_v0_11_nonce_function_musig(rustsecp256k1_v0_11_scalar *k, const unsigned char *session_secrand, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) { + rustsecp256k1_v0_11_sha256 sha; + unsigned char rand[32]; + unsigned char i; + unsigned char msg_present; + + if (seckey32 != NULL) { + rustsecp256k1_v0_11_nonce_function_musig_sha256_tagged_aux(&sha); + rustsecp256k1_v0_11_sha256_write(&sha, session_secrand, 32); + rustsecp256k1_v0_11_sha256_finalize(&sha, rand); + for (i = 0; i < 32; i++) { + rand[i] ^= seckey32[i]; + } + } else { + memcpy(rand, session_secrand, sizeof(rand)); + } + + rustsecp256k1_v0_11_nonce_function_musig_sha256_tagged(&sha); + rustsecp256k1_v0_11_sha256_write(&sha, rand, sizeof(rand)); + rustsecp256k1_v0_11_nonce_function_musig_helper(&sha, 1, pk33, 33); + rustsecp256k1_v0_11_nonce_function_musig_helper(&sha, 1, agg_pk32, 32); + msg_present = msg32 != NULL; + rustsecp256k1_v0_11_sha256_write(&sha, &msg_present, 1); + if (msg_present) { + rustsecp256k1_v0_11_nonce_function_musig_helper(&sha, 8, msg32, 32); + } + rustsecp256k1_v0_11_nonce_function_musig_helper(&sha, 4, extra_input32, 32); + + for (i = 0; i < 2; i++) { + unsigned char buf[32]; + rustsecp256k1_v0_11_sha256 sha_tmp = sha; + rustsecp256k1_v0_11_sha256_write(&sha_tmp, &i, 1); + rustsecp256k1_v0_11_sha256_finalize(&sha_tmp, buf); + rustsecp256k1_v0_11_scalar_set_b32(&k[i], buf, NULL); + + /* Attempt to erase secret data */ + rustsecp256k1_v0_11_memclear(buf, sizeof(buf)); + rustsecp256k1_v0_11_sha256_clear(&sha_tmp); + } + rustsecp256k1_v0_11_memclear(rand, sizeof(rand)); + rustsecp256k1_v0_11_sha256_clear(&sha); +} + +static int rustsecp256k1_v0_11_musig_nonce_gen_internal(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_musig_secnonce *secnonce, rustsecp256k1_v0_11_musig_pubnonce *pubnonce, const unsigned char *input_nonce, const unsigned char *seckey, const rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *msg32, const rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { + rustsecp256k1_v0_11_scalar k[2]; + rustsecp256k1_v0_11_ge nonce_pts[2]; + int i; + unsigned char pk_ser[33]; + size_t pk_ser_len = sizeof(pk_ser); + unsigned char aggpk_ser[32]; + unsigned char *aggpk_ser_ptr = NULL; + rustsecp256k1_v0_11_ge pk; + int pk_serialize_success; + int ret = 1; + + ARG_CHECK(pubnonce != NULL); + memset(pubnonce, 0, sizeof(*pubnonce)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(rustsecp256k1_v0_11_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + + /* Check that the seckey is valid to be able to sign for it later. */ + if (seckey != NULL) { + rustsecp256k1_v0_11_scalar sk; + ret &= rustsecp256k1_v0_11_scalar_set_b32_seckey(&sk, seckey); + rustsecp256k1_v0_11_scalar_clear(&sk); + } + + if (keyagg_cache != NULL) { + rustsecp256k1_v0_11_keyagg_cache_internal cache_i; + if (!rustsecp256k1_v0_11_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + /* The loaded point cache_i.pk can not be the point at infinity. */ + rustsecp256k1_v0_11_fe_get_b32(aggpk_ser, &cache_i.pk.x); + aggpk_ser_ptr = aggpk_ser; + } + if (!rustsecp256k1_v0_11_pubkey_load(ctx, &pk, pubkey)) { + return 0; + } + pk_serialize_success = rustsecp256k1_v0_11_eckey_pubkey_serialize(&pk, pk_ser, &pk_ser_len, 1); + +#ifdef VERIFY + /* A pubkey cannot be the point at infinity */ + VERIFY_CHECK(pk_serialize_success); + VERIFY_CHECK(pk_ser_len == sizeof(pk_ser)); +#else + (void) pk_serialize_success; +#endif + + rustsecp256k1_v0_11_nonce_function_musig(k, input_nonce, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32); + VERIFY_CHECK(!rustsecp256k1_v0_11_scalar_is_zero(&k[0])); + VERIFY_CHECK(!rustsecp256k1_v0_11_scalar_is_zero(&k[1])); + rustsecp256k1_v0_11_musig_secnonce_save(secnonce, k, &pk); + rustsecp256k1_v0_11_musig_secnonce_invalidate(ctx, secnonce, !ret); + + for (i = 0; i < 2; i++) { + rustsecp256k1_v0_11_gej nonce_ptj; + rustsecp256k1_v0_11_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj, &k[i]); + rustsecp256k1_v0_11_ge_set_gej(&nonce_pts[i], &nonce_ptj); + rustsecp256k1_v0_11_declassify(ctx, &nonce_pts[i], sizeof(nonce_pts[i])); + rustsecp256k1_v0_11_scalar_clear(&k[i]); + rustsecp256k1_v0_11_gej_clear(&nonce_ptj); + } + /* None of the nonce_pts will be infinity because k != 0 with overwhelming + * probability */ + rustsecp256k1_v0_11_musig_pubnonce_save(pubnonce, nonce_pts); + return ret; +} + +int rustsecp256k1_v0_11_musig_nonce_gen(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_musig_secnonce *secnonce, rustsecp256k1_v0_11_musig_pubnonce *pubnonce, unsigned char *session_secrand32, const unsigned char *seckey, const rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *msg32, const rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { + int ret = 1; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secnonce != NULL); + memset(secnonce, 0, sizeof(*secnonce)); + ARG_CHECK(session_secrand32 != NULL); + + /* Check in constant time that the session_secrand32 is not 0 as a + * defense-in-depth measure that may protect against a faulty RNG. */ + ret &= !rustsecp256k1_v0_11_is_zero_array(session_secrand32, 32); + + /* We can declassify because branching on ret is only relevant when this + * function called with an invalid session_secrand32 argument */ + rustsecp256k1_v0_11_declassify(ctx, &ret, sizeof(ret)); + if (ret == 0) { + rustsecp256k1_v0_11_musig_secnonce_invalidate(ctx, secnonce, 1); + return 0; + } + + ret &= rustsecp256k1_v0_11_musig_nonce_gen_internal(ctx, secnonce, pubnonce, session_secrand32, seckey, pubkey, msg32, keyagg_cache, extra_input32); + + /* Set the session_secrand32 buffer to zero to prevent the caller from using + * nonce_gen multiple times with the same buffer. */ + rustsecp256k1_v0_11_memczero(session_secrand32, 32, ret); + return ret; +} + +int rustsecp256k1_v0_11_musig_nonce_gen_counter(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_musig_secnonce *secnonce, rustsecp256k1_v0_11_musig_pubnonce *pubnonce, uint64_t nonrepeating_cnt, const rustsecp256k1_v0_11_keypair *keypair, const unsigned char *msg32, const rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { + unsigned char buf[32] = { 0 }; + unsigned char seckey[32]; + rustsecp256k1_v0_11_pubkey pubkey; + int ret; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secnonce != NULL); + memset(secnonce, 0, sizeof(*secnonce)); + ARG_CHECK(keypair != NULL); + + rustsecp256k1_v0_11_write_be64(buf, nonrepeating_cnt); + /* keypair_sec and keypair_pub do not fail if the arguments are not NULL */ + ret = rustsecp256k1_v0_11_keypair_sec(ctx, seckey, keypair); + VERIFY_CHECK(ret); + ret = rustsecp256k1_v0_11_keypair_pub(ctx, &pubkey, keypair); + VERIFY_CHECK(ret); +#ifndef VERIFY + (void) ret; +#endif + + if (!rustsecp256k1_v0_11_musig_nonce_gen_internal(ctx, secnonce, pubnonce, buf, seckey, &pubkey, msg32, keyagg_cache, extra_input32)) { + return 0; + } + rustsecp256k1_v0_11_memclear(seckey, sizeof(seckey)); + return 1; +} + +static int rustsecp256k1_v0_11_musig_sum_pubnonces(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_gej *summed_pubnonces, const rustsecp256k1_v0_11_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { + size_t i; + int j; + + rustsecp256k1_v0_11_gej_set_infinity(&summed_pubnonces[0]); + rustsecp256k1_v0_11_gej_set_infinity(&summed_pubnonces[1]); + + for (i = 0; i < n_pubnonces; i++) { + rustsecp256k1_v0_11_ge nonce_pts[2]; + if (!rustsecp256k1_v0_11_musig_pubnonce_load(ctx, nonce_pts, pubnonces[i])) { + return 0; + } + for (j = 0; j < 2; j++) { + rustsecp256k1_v0_11_gej_add_ge_var(&summed_pubnonces[j], &summed_pubnonces[j], &nonce_pts[j], NULL); + } + } + return 1; +} + +int rustsecp256k1_v0_11_musig_nonce_agg(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_musig_aggnonce *aggnonce, const rustsecp256k1_v0_11_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { + rustsecp256k1_v0_11_gej aggnonce_ptsj[2]; + rustsecp256k1_v0_11_ge aggnonce_pts[2]; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(aggnonce != NULL); + ARG_CHECK(pubnonces != NULL); + ARG_CHECK(n_pubnonces > 0); + + if (!rustsecp256k1_v0_11_musig_sum_pubnonces(ctx, aggnonce_ptsj, pubnonces, n_pubnonces)) { + return 0; + } + rustsecp256k1_v0_11_ge_set_all_gej_var(aggnonce_pts, aggnonce_ptsj, 2); + rustsecp256k1_v0_11_musig_aggnonce_save(aggnonce, aggnonce_pts); + return 1; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("MuSig/noncecoef")||SHA256("MuSig/noncecoef"). */ +static void rustsecp256k1_v0_11_musig_compute_noncehash_sha256_tagged(rustsecp256k1_v0_11_sha256 *sha) { + rustsecp256k1_v0_11_sha256_initialize(sha); + sha->s[0] = 0x2c7d5a45ul; + sha->s[1] = 0x06bf7e53ul; + sha->s[2] = 0x89be68a6ul; + sha->s[3] = 0x971254c0ul; + sha->s[4] = 0x60ac12d2ul; + sha->s[5] = 0x72846dcdul; + sha->s[6] = 0x6c81212ful; + sha->s[7] = 0xde7a2500ul; + sha->bytes = 64; +} + +/* tagged_hash(aggnonce[0], aggnonce[1], agg_pk, msg) */ +static void rustsecp256k1_v0_11_musig_compute_noncehash(unsigned char *noncehash, rustsecp256k1_v0_11_ge *aggnonce, const unsigned char *agg_pk32, const unsigned char *msg) { + unsigned char buf[33]; + rustsecp256k1_v0_11_sha256 sha; + int i; + + rustsecp256k1_v0_11_musig_compute_noncehash_sha256_tagged(&sha); + for (i = 0; i < 2; i++) { + rustsecp256k1_v0_11_musig_ge_serialize_ext(buf, &aggnonce[i]); + rustsecp256k1_v0_11_sha256_write(&sha, buf, sizeof(buf)); + } + rustsecp256k1_v0_11_sha256_write(&sha, agg_pk32, 32); + rustsecp256k1_v0_11_sha256_write(&sha, msg, 32); + rustsecp256k1_v0_11_sha256_finalize(&sha, noncehash); +} + +/* out_nonce = nonce_pts[0] + b*nonce_pts[1] */ +static void rustsecp256k1_v0_11_effective_nonce(rustsecp256k1_v0_11_gej *out_nonce, const rustsecp256k1_v0_11_ge *nonce_pts, const rustsecp256k1_v0_11_scalar *b) { + rustsecp256k1_v0_11_gej tmp; + + rustsecp256k1_v0_11_gej_set_ge(&tmp, &nonce_pts[1]); + rustsecp256k1_v0_11_ecmult(out_nonce, &tmp, b, NULL); + rustsecp256k1_v0_11_gej_add_ge_var(out_nonce, out_nonce, &nonce_pts[0], NULL); +} + +static void rustsecp256k1_v0_11_musig_nonce_process_internal(int *fin_nonce_parity, unsigned char *fin_nonce, rustsecp256k1_v0_11_scalar *b, rustsecp256k1_v0_11_ge *aggnonce_pts, const unsigned char *agg_pk32, const unsigned char *msg) { + unsigned char noncehash[32]; + rustsecp256k1_v0_11_ge fin_nonce_pt; + rustsecp256k1_v0_11_gej fin_nonce_ptj; + + rustsecp256k1_v0_11_musig_compute_noncehash(noncehash, aggnonce_pts, agg_pk32, msg); + rustsecp256k1_v0_11_scalar_set_b32(b, noncehash, NULL); + /* fin_nonce = aggnonce_pts[0] + b*aggnonce_pts[1] */ + rustsecp256k1_v0_11_effective_nonce(&fin_nonce_ptj, aggnonce_pts, b); + rustsecp256k1_v0_11_ge_set_gej(&fin_nonce_pt, &fin_nonce_ptj); + if (rustsecp256k1_v0_11_ge_is_infinity(&fin_nonce_pt)) { + fin_nonce_pt = rustsecp256k1_v0_11_ge_const_g; + } + /* fin_nonce_pt is not the point at infinity */ + rustsecp256k1_v0_11_fe_normalize_var(&fin_nonce_pt.x); + rustsecp256k1_v0_11_fe_get_b32(fin_nonce, &fin_nonce_pt.x); + rustsecp256k1_v0_11_fe_normalize_var(&fin_nonce_pt.y); + *fin_nonce_parity = rustsecp256k1_v0_11_fe_is_odd(&fin_nonce_pt.y); +} + +int rustsecp256k1_v0_11_musig_nonce_process(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_musig_session *session, const rustsecp256k1_v0_11_musig_aggnonce *aggnonce, const unsigned char *msg32, const rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache) { + rustsecp256k1_v0_11_keyagg_cache_internal cache_i; + rustsecp256k1_v0_11_ge aggnonce_pts[2]; + unsigned char fin_nonce[32]; + rustsecp256k1_v0_11_musig_session_internal session_i; + unsigned char agg_pk32[32]; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(session != NULL); + ARG_CHECK(aggnonce != NULL); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(keyagg_cache != NULL); + + if (!rustsecp256k1_v0_11_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + rustsecp256k1_v0_11_fe_get_b32(agg_pk32, &cache_i.pk.x); + + if (!rustsecp256k1_v0_11_musig_aggnonce_load(ctx, aggnonce_pts, aggnonce)) { + return 0; + } + + rustsecp256k1_v0_11_musig_nonce_process_internal(&session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_pts, agg_pk32, msg32); + rustsecp256k1_v0_11_schnorrsig_challenge(&session_i.challenge, fin_nonce, msg32, 32, agg_pk32); + + /* If there is a tweak then set `challenge` times `tweak` to the `s`-part.*/ + rustsecp256k1_v0_11_scalar_set_int(&session_i.s_part, 0); + if (!rustsecp256k1_v0_11_scalar_is_zero(&cache_i.tweak)) { + rustsecp256k1_v0_11_scalar e_tmp; + rustsecp256k1_v0_11_scalar_mul(&e_tmp, &session_i.challenge, &cache_i.tweak); + if (rustsecp256k1_v0_11_fe_is_odd(&cache_i.pk.y)) { + rustsecp256k1_v0_11_scalar_negate(&e_tmp, &e_tmp); + } + session_i.s_part = e_tmp; + } + memcpy(session_i.fin_nonce, fin_nonce, sizeof(session_i.fin_nonce)); + rustsecp256k1_v0_11_musig_session_save(session, &session_i); + return 1; +} + +static void rustsecp256k1_v0_11_musig_partial_sign_clear(rustsecp256k1_v0_11_scalar *sk, rustsecp256k1_v0_11_scalar *k) { + rustsecp256k1_v0_11_scalar_clear(sk); + rustsecp256k1_v0_11_scalar_clear(&k[0]); + rustsecp256k1_v0_11_scalar_clear(&k[1]); +} + +int rustsecp256k1_v0_11_musig_partial_sign(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_musig_partial_sig *partial_sig, rustsecp256k1_v0_11_musig_secnonce *secnonce, const rustsecp256k1_v0_11_keypair *keypair, const rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, const rustsecp256k1_v0_11_musig_session *session) { + rustsecp256k1_v0_11_scalar sk; + rustsecp256k1_v0_11_ge pk, keypair_pk; + rustsecp256k1_v0_11_scalar k[2]; + rustsecp256k1_v0_11_scalar mu, s; + rustsecp256k1_v0_11_keyagg_cache_internal cache_i; + rustsecp256k1_v0_11_musig_session_internal session_i; + int ret; + + VERIFY_CHECK(ctx != NULL); + + ARG_CHECK(secnonce != NULL); + /* Fails if the magic doesn't match */ + ret = rustsecp256k1_v0_11_musig_secnonce_load(ctx, k, &pk, secnonce); + /* Set nonce to zero to avoid nonce reuse. This will cause subsequent calls + * of this function to fail */ + memset(secnonce, 0, sizeof(*secnonce)); + if (!ret) { + rustsecp256k1_v0_11_musig_partial_sign_clear(&sk, k); + return 0; + } + + ARG_CHECK(partial_sig != NULL); + ARG_CHECK(keypair != NULL); + ARG_CHECK(keyagg_cache != NULL); + ARG_CHECK(session != NULL); + + if (!rustsecp256k1_v0_11_keypair_load(ctx, &sk, &keypair_pk, keypair)) { + rustsecp256k1_v0_11_musig_partial_sign_clear(&sk, k); + return 0; + } + ARG_CHECK(rustsecp256k1_v0_11_fe_equal(&pk.x, &keypair_pk.x) + && rustsecp256k1_v0_11_fe_equal(&pk.y, &keypair_pk.y)); + if (!rustsecp256k1_v0_11_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + rustsecp256k1_v0_11_musig_partial_sign_clear(&sk, k); + return 0; + } + + /* Negate sk if rustsecp256k1_v0_11_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc. + * This corresponds to the line "Let d = g⋅gacc⋅d' mod n" in the + * specification. */ + if ((rustsecp256k1_v0_11_fe_is_odd(&cache_i.pk.y) + != cache_i.parity_acc)) { + rustsecp256k1_v0_11_scalar_negate(&sk, &sk); + } + + /* Multiply KeyAgg coefficient */ + rustsecp256k1_v0_11_musig_keyaggcoef(&mu, &cache_i, &pk); + rustsecp256k1_v0_11_scalar_mul(&sk, &sk, &mu); + + if (!rustsecp256k1_v0_11_musig_session_load(ctx, &session_i, session)) { + rustsecp256k1_v0_11_musig_partial_sign_clear(&sk, k); + return 0; + } + + if (session_i.fin_nonce_parity) { + rustsecp256k1_v0_11_scalar_negate(&k[0], &k[0]); + rustsecp256k1_v0_11_scalar_negate(&k[1], &k[1]); + } + + /* Sign */ + rustsecp256k1_v0_11_scalar_mul(&s, &session_i.challenge, &sk); + rustsecp256k1_v0_11_scalar_mul(&k[1], &session_i.noncecoef, &k[1]); + rustsecp256k1_v0_11_scalar_add(&k[0], &k[0], &k[1]); + rustsecp256k1_v0_11_scalar_add(&s, &s, &k[0]); + rustsecp256k1_v0_11_musig_partial_sig_save(partial_sig, &s); + rustsecp256k1_v0_11_musig_partial_sign_clear(&sk, k); + return 1; +} + +int rustsecp256k1_v0_11_musig_partial_sig_verify(const rustsecp256k1_v0_11_context* ctx, const rustsecp256k1_v0_11_musig_partial_sig *partial_sig, const rustsecp256k1_v0_11_musig_pubnonce *pubnonce, const rustsecp256k1_v0_11_pubkey *pubkey, const rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, const rustsecp256k1_v0_11_musig_session *session) { + rustsecp256k1_v0_11_keyagg_cache_internal cache_i; + rustsecp256k1_v0_11_musig_session_internal session_i; + rustsecp256k1_v0_11_scalar mu, e, s; + rustsecp256k1_v0_11_gej pkj; + rustsecp256k1_v0_11_ge nonce_pts[2]; + rustsecp256k1_v0_11_gej rj; + rustsecp256k1_v0_11_gej tmp; + rustsecp256k1_v0_11_ge pkp; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(partial_sig != NULL); + ARG_CHECK(pubnonce != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(keyagg_cache != NULL); + ARG_CHECK(session != NULL); + + if (!rustsecp256k1_v0_11_musig_session_load(ctx, &session_i, session)) { + return 0; + } + + if (!rustsecp256k1_v0_11_musig_pubnonce_load(ctx, nonce_pts, pubnonce)) { + return 0; + } + /* Compute "effective" nonce rj = nonce_pts[0] + b*nonce_pts[1] */ + /* TODO: use multiexp to compute -s*G + e*mu*pubkey + nonce_pts[0] + b*nonce_pts[1] */ + rustsecp256k1_v0_11_effective_nonce(&rj, nonce_pts, &session_i.noncecoef); + + if (!rustsecp256k1_v0_11_pubkey_load(ctx, &pkp, pubkey)) { + return 0; + } + if (!rustsecp256k1_v0_11_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + /* Multiplying the challenge by the KeyAgg coefficient is equivalent + * to multiplying the signer's public key by the coefficient, except + * much easier to do. */ + rustsecp256k1_v0_11_musig_keyaggcoef(&mu, &cache_i, &pkp); + rustsecp256k1_v0_11_scalar_mul(&e, &session_i.challenge, &mu); + + /* Negate e if rustsecp256k1_v0_11_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc. + * This corresponds to the line "Let g' = g⋅gacc mod n" and the multiplication "g'⋅e" + * in the specification. */ + if (rustsecp256k1_v0_11_fe_is_odd(&cache_i.pk.y) + != cache_i.parity_acc) { + rustsecp256k1_v0_11_scalar_negate(&e, &e); + } + + if (!rustsecp256k1_v0_11_musig_partial_sig_load(ctx, &s, partial_sig)) { + return 0; + } + /* Compute -s*G + e*pkj + rj (e already includes the keyagg coefficient mu) */ + rustsecp256k1_v0_11_scalar_negate(&s, &s); + rustsecp256k1_v0_11_gej_set_ge(&pkj, &pkp); + rustsecp256k1_v0_11_ecmult(&tmp, &pkj, &e, &s); + if (session_i.fin_nonce_parity) { + rustsecp256k1_v0_11_gej_neg(&rj, &rj); + } + rustsecp256k1_v0_11_gej_add_var(&tmp, &tmp, &rj, NULL); + + return rustsecp256k1_v0_11_gej_is_infinity(&tmp); +} + +int rustsecp256k1_v0_11_musig_partial_sig_agg(const rustsecp256k1_v0_11_context* ctx, unsigned char *sig64, const rustsecp256k1_v0_11_musig_session *session, const rustsecp256k1_v0_11_musig_partial_sig * const* partial_sigs, size_t n_sigs) { + size_t i; + rustsecp256k1_v0_11_musig_session_internal session_i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(session != NULL); + ARG_CHECK(partial_sigs != NULL); + ARG_CHECK(n_sigs > 0); + + if (!rustsecp256k1_v0_11_musig_session_load(ctx, &session_i, session)) { + return 0; + } + for (i = 0; i < n_sigs; i++) { + rustsecp256k1_v0_11_scalar term; + if (!rustsecp256k1_v0_11_musig_partial_sig_load(ctx, &term, partial_sigs[i])) { + return 0; + } + rustsecp256k1_v0_11_scalar_add(&session_i.s_part, &session_i.s_part, &term); + } + rustsecp256k1_v0_11_scalar_get_b32(&sig64[32], &session_i.s_part); + memcpy(&sig64[0], session_i.fin_nonce, 32); + return 1; +} + +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/tests_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/tests_impl.h new file mode 100644 index 00000000..853011ba --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/tests_impl.h @@ -0,0 +1,1143 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_TESTS_IMPL_H +#define SECP256K1_MODULE_MUSIG_TESTS_IMPL_H + +#include +#include + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_extrakeys.h" +#include "../../../include/secp256k1_musig.h" + +#include "session.h" +#include "keyagg.h" +#include "../../scalar.h" +#include "../../field.h" +#include "../../group.h" +#include "../../hash.h" +#include "../../util.h" + +#include "vectors.h" + +static int create_keypair_and_pk(rustsecp256k1_v0_11_keypair *keypair, rustsecp256k1_v0_11_pubkey *pk, const unsigned char *sk) { + int ret; + rustsecp256k1_v0_11_keypair keypair_tmp; + ret = rustsecp256k1_v0_11_keypair_create(CTX, &keypair_tmp, sk); + ret &= rustsecp256k1_v0_11_keypair_pub(CTX, pk, &keypair_tmp); + if (keypair != NULL) { + *keypair = keypair_tmp; + } + return ret; +} + +/* Just a simple (non-tweaked) 2-of-2 MuSig aggregate, sign, verify + * test. */ +static void musig_simple_test(void) { + unsigned char sk[2][32]; + rustsecp256k1_v0_11_keypair keypair[2]; + rustsecp256k1_v0_11_musig_pubnonce pubnonce[2]; + const rustsecp256k1_v0_11_musig_pubnonce *pubnonce_ptr[2]; + rustsecp256k1_v0_11_musig_aggnonce aggnonce; + unsigned char msg[32]; + rustsecp256k1_v0_11_xonly_pubkey agg_pk; + rustsecp256k1_v0_11_musig_keyagg_cache keyagg_cache; + unsigned char session_secrand[2][32]; + rustsecp256k1_v0_11_musig_secnonce secnonce[2]; + rustsecp256k1_v0_11_pubkey pk[2]; + const rustsecp256k1_v0_11_pubkey *pk_ptr[2]; + rustsecp256k1_v0_11_musig_partial_sig partial_sig[2]; + const rustsecp256k1_v0_11_musig_partial_sig *partial_sig_ptr[2]; + unsigned char final_sig[64]; + rustsecp256k1_v0_11_musig_session session; + int i; + + testrand256(msg); + for (i = 0; i < 2; i++) { + testrand256(sk[i]); + pk_ptr[i] = &pk[i]; + pubnonce_ptr[i] = &pubnonce[i]; + partial_sig_ptr[i] = &partial_sig[i]; + + CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i])); + if (i == 0) { + testrand256(session_secrand[i]); + CHECK(rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[i], &pubnonce[i], session_secrand[i], sk[i], &pk[i], NULL, NULL, NULL) == 1); + } else { + uint64_t nonrepeating_cnt = 0; + CHECK(rustsecp256k1_v0_11_musig_nonce_gen_counter(CTX, &secnonce[i], &pubnonce[i], nonrepeating_cnt, &keypair[i], NULL, NULL, NULL) == 1); + } + } + + CHECK(rustsecp256k1_v0_11_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(rustsecp256k1_v0_11_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); + CHECK(rustsecp256k1_v0_11_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache) == 1); + + for (i = 0; i < 2; i++) { + CHECK(rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[i], &secnonce[i], &keypair[i], &keyagg_cache, &session) == 1); + CHECK(rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[i], &pubnonce[i], &pk[i], &keyagg_cache, &session) == 1); + } + + CHECK(rustsecp256k1_v0_11_musig_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, 2) == 1); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), &agg_pk) == 1); +} + +/* Generate two pubnonces such that both group elements of their sum (calculated + * with rustsecp256k1_v0_11_musig_sum_pubnonces) are infinity. */ +static void pubnonce_summing_to_inf(rustsecp256k1_v0_11_musig_pubnonce *pubnonce) { + rustsecp256k1_v0_11_ge ge[2]; + int i; + rustsecp256k1_v0_11_gej summed_pubnonces[2]; + const rustsecp256k1_v0_11_musig_pubnonce *pubnonce_ptr[2]; + + testutil_random_ge_test(&ge[0]); + testutil_random_ge_test(&ge[1]); + + for (i = 0; i < 2; i++) { + rustsecp256k1_v0_11_musig_pubnonce_save(&pubnonce[i], ge); + pubnonce_ptr[i] = &pubnonce[i]; + rustsecp256k1_v0_11_ge_neg(&ge[0], &ge[0]); + rustsecp256k1_v0_11_ge_neg(&ge[1], &ge[1]); + } + + rustsecp256k1_v0_11_musig_sum_pubnonces(CTX, summed_pubnonces, pubnonce_ptr, 2); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&summed_pubnonces[0])); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&summed_pubnonces[1])); +} + +int memcmp_and_randomize(unsigned char *value, const unsigned char *expected, size_t len) { + int ret; + size_t i; + ret = rustsecp256k1_v0_11_memcmp_var(value, expected, len); + for (i = 0; i < len; i++) { + value[i] = testrand_bits(8); + } + return ret; +} + +static void musig_api_tests(void) { + rustsecp256k1_v0_11_musig_partial_sig partial_sig[2]; + const rustsecp256k1_v0_11_musig_partial_sig *partial_sig_ptr[2]; + rustsecp256k1_v0_11_musig_partial_sig invalid_partial_sig; + const rustsecp256k1_v0_11_musig_partial_sig *invalid_partial_sig_ptr[2]; + unsigned char pre_sig[64]; + unsigned char buf[32]; + unsigned char sk[2][32]; + rustsecp256k1_v0_11_keypair keypair[2]; + rustsecp256k1_v0_11_keypair invalid_keypair; + unsigned char max64[64]; + unsigned char zeros132[132] = { 0 }; + unsigned char session_secrand[2][32]; + unsigned char nonrepeating_cnt = 0; + rustsecp256k1_v0_11_musig_secnonce secnonce[2]; + rustsecp256k1_v0_11_musig_secnonce secnonce_tmp; + rustsecp256k1_v0_11_musig_secnonce invalid_secnonce; + rustsecp256k1_v0_11_musig_pubnonce pubnonce[2]; + const rustsecp256k1_v0_11_musig_pubnonce *pubnonce_ptr[2]; + unsigned char pubnonce_ser[66]; + rustsecp256k1_v0_11_musig_pubnonce inf_pubnonce[2]; + const rustsecp256k1_v0_11_musig_pubnonce *inf_pubnonce_ptr[2]; + rustsecp256k1_v0_11_musig_pubnonce invalid_pubnonce; + const rustsecp256k1_v0_11_musig_pubnonce *invalid_pubnonce_ptr[1]; + rustsecp256k1_v0_11_musig_aggnonce aggnonce; + unsigned char aggnonce_ser[66]; + unsigned char msg[32]; + rustsecp256k1_v0_11_xonly_pubkey agg_pk; + rustsecp256k1_v0_11_pubkey full_agg_pk; + rustsecp256k1_v0_11_musig_keyagg_cache keyagg_cache; + rustsecp256k1_v0_11_musig_keyagg_cache invalid_keyagg_cache; + rustsecp256k1_v0_11_musig_session session; + rustsecp256k1_v0_11_musig_session invalid_session; + rustsecp256k1_v0_11_pubkey pk[2]; + const rustsecp256k1_v0_11_pubkey *pk_ptr[2]; + rustsecp256k1_v0_11_pubkey invalid_pk; + const rustsecp256k1_v0_11_pubkey *invalid_pk_ptr2[2]; + const rustsecp256k1_v0_11_pubkey *invalid_pk_ptr3[3]; + unsigned char tweak[32]; + int i; + + /** setup **/ + memset(max64, 0xff, sizeof(max64)); + memset(&invalid_keypair, 0, sizeof(invalid_keypair)); + memset(&invalid_pk, 0, sizeof(invalid_pk)); + memset(&invalid_secnonce, 0, sizeof(invalid_secnonce)); + memset(&invalid_partial_sig, 0, sizeof(invalid_partial_sig)); + pubnonce_summing_to_inf(inf_pubnonce); + /* Simulate structs being uninitialized by setting it to 0s. We don't want + * to produce undefined behavior by actually providing uninitialized + * structs. */ + memset(&invalid_keyagg_cache, 0, sizeof(invalid_keyagg_cache)); + memset(&invalid_pk, 0, sizeof(invalid_pk)); + memset(&invalid_pubnonce, 0, sizeof(invalid_pubnonce)); + memset(&invalid_session, 0, sizeof(invalid_session)); + + testrand256(msg); + testrand256(tweak); + for (i = 0; i < 2; i++) { + pk_ptr[i] = &pk[i]; + invalid_pk_ptr2[i] = &invalid_pk; + invalid_pk_ptr3[i] = &pk[i]; + pubnonce_ptr[i] = &pubnonce[i]; + inf_pubnonce_ptr[i] = &inf_pubnonce[i]; + partial_sig_ptr[i] = &partial_sig[i]; + invalid_partial_sig_ptr[i] = &partial_sig[i]; + testrand256(session_secrand[i]); + testrand256(sk[i]); + CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i])); + } + invalid_pubnonce_ptr[0] = &invalid_pubnonce; + invalid_partial_sig_ptr[0] = &invalid_partial_sig; + /* invalid_pk_ptr3 has two valid, one invalid pk, which is important to test + * musig_pubkey_agg */ + invalid_pk_ptr3[2] = &invalid_pk; + + /** main test body **/ + + /** Key aggregation **/ + CHECK(rustsecp256k1_v0_11_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(rustsecp256k1_v0_11_musig_pubkey_agg(CTX, NULL, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(rustsecp256k1_v0_11_musig_pubkey_agg(CTX, &agg_pk, NULL, pk_ptr, 2) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, NULL, 2)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, invalid_pk_ptr2, 2)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, invalid_pk_ptr3, 3)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 0)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, NULL, 0)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + + CHECK(rustsecp256k1_v0_11_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + + /* pubkey_get */ + CHECK(rustsecp256k1_v0_11_musig_pubkey_get(CTX, &full_agg_pk, &keyagg_cache) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_pubkey_get(CTX, NULL, &keyagg_cache)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_pubkey_get(CTX, &full_agg_pk, NULL)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&full_agg_pk, zeros132, sizeof(full_agg_pk)) == 0); + + /** Tweaking **/ + { + int (*tweak_func[2]) (const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *output_pubkey, rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32); + tweak_func[0] = rustsecp256k1_v0_11_musig_pubkey_ec_tweak_add; + tweak_func[1] = rustsecp256k1_v0_11_musig_pubkey_xonly_tweak_add; + for (i = 0; i < 2; i++) { + rustsecp256k1_v0_11_pubkey tmp_output_pk; + rustsecp256k1_v0_11_musig_keyagg_cache tmp_keyagg_cache = keyagg_cache; + CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); + /* Reset keyagg_cache */ + tmp_keyagg_cache = keyagg_cache; + CHECK((*tweak_func[i])(CTX, NULL, &tmp_keyagg_cache, tweak) == 1); + tmp_keyagg_cache = keyagg_cache; + CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, NULL, tweak)); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); + tmp_keyagg_cache = keyagg_cache; + CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, NULL)); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); + tmp_keyagg_cache = keyagg_cache; + CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, max64) == 0); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); + tmp_keyagg_cache = keyagg_cache; + /* Uninitialized keyagg_cache */ + CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, &invalid_keyagg_cache, tweak)); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); + } + } + + /** Session creation with nonce_gen **/ + CHECK(rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); + /* nonce_gen, if successful, sets session_secrand to the zero array, which + * makes subsequent nonce_gen calls with the same session_secrand fail. So + * check that session_secrand is indeed the zero array and fill it with + * random values again. */ + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + CHECK_ILLEGAL(STATIC_CTX, rustsecp256k1_v0_11_musig_nonce_gen(STATIC_CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_gen(CTX, NULL, &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[0], NULL, session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], NULL, sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + /* session_secrand = 0 is disallowed because it indicates a faulty RNG */ + memcpy(&session_secrand[0], zeros132, sizeof(session_secrand[0])); + CHECK(rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], zeros132, sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK(rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], NULL, &pk[0], msg, &keyagg_cache, max64) == 1); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + /* invalid seckey */ + CHECK(rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], max64, &pk[0], msg, &keyagg_cache, max64) == 0); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], NULL, msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &invalid_pk, msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK(rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], NULL, &keyagg_cache, max64) == 1); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + CHECK(rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, NULL, max64) == 1); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &invalid_keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK(rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, NULL) == 1); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + /* Every in-argument except session_secrand and pubkey can be NULL */ + CHECK(rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], NULL, &pk[0], NULL, NULL, NULL) == 1); + CHECK(rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_secrand[1], sk[1], &pk[1], NULL, NULL, NULL) == 1); + + /** Session creation with nonce_gen_counter **/ + CHECK(rustsecp256k1_v0_11_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64) == 1); + CHECK_ILLEGAL(STATIC_CTX, rustsecp256k1_v0_11_musig_nonce_gen_counter(STATIC_CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_gen_counter(CTX, NULL, &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_gen_counter(CTX, &secnonce[0], NULL, nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + /* using nonce_gen_counter requires keypair */ + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, NULL, msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + /* invalid keypair */ + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &invalid_keypair, msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + CHECK(rustsecp256k1_v0_11_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], NULL, &keyagg_cache, max64) == 1); + CHECK(rustsecp256k1_v0_11_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, NULL, max64) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &invalid_keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + CHECK(rustsecp256k1_v0_11_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt,&keypair[0], msg, &keyagg_cache, NULL) == 1); + + /* Every in-argument except nonrepeating_cnt and keypair can be NULL */ + CHECK(rustsecp256k1_v0_11_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], NULL, NULL, NULL) == 1); + CHECK(rustsecp256k1_v0_11_musig_nonce_gen_counter(CTX, &secnonce[1], &pubnonce[1], nonrepeating_cnt, &keypair[1], NULL, NULL, NULL) == 1); + + + /** Serialize and parse public nonces **/ + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_pubnonce_serialize(CTX, NULL, &pubnonce[0])); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_pubnonce_serialize(CTX, pubnonce_ser, NULL)); + CHECK(memcmp_and_randomize(pubnonce_ser, zeros132, sizeof(pubnonce_ser)) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_pubnonce_serialize(CTX, pubnonce_ser, &invalid_pubnonce)); + CHECK(memcmp_and_randomize(pubnonce_ser, zeros132, sizeof(pubnonce_ser)) == 0); + CHECK(rustsecp256k1_v0_11_musig_pubnonce_serialize(CTX, pubnonce_ser, &pubnonce[0]) == 1); + + CHECK(rustsecp256k1_v0_11_musig_pubnonce_parse(CTX, &pubnonce[0], pubnonce_ser) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_pubnonce_parse(CTX, NULL, pubnonce_ser)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_pubnonce_parse(CTX, &pubnonce[0], NULL)); + CHECK(rustsecp256k1_v0_11_musig_pubnonce_parse(CTX, &pubnonce[0], zeros132) == 0); + CHECK(rustsecp256k1_v0_11_musig_pubnonce_parse(CTX, &pubnonce[0], pubnonce_ser) == 1); + + { + /* Check that serialize and parse results in the same value */ + rustsecp256k1_v0_11_musig_pubnonce tmp; + CHECK(rustsecp256k1_v0_11_musig_pubnonce_serialize(CTX, pubnonce_ser, &pubnonce[0]) == 1); + CHECK(rustsecp256k1_v0_11_musig_pubnonce_parse(CTX, &tmp, pubnonce_ser) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&tmp, &pubnonce[0], sizeof(tmp)) == 0); + } + + /** Receive nonces and aggregate **/ + CHECK(rustsecp256k1_v0_11_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_agg(CTX, NULL, pubnonce_ptr, 2)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_agg(CTX, &aggnonce, NULL, 2)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 0)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_agg(CTX, &aggnonce, invalid_pubnonce_ptr, 1)); + CHECK(rustsecp256k1_v0_11_musig_nonce_agg(CTX, &aggnonce, inf_pubnonce_ptr, 2) == 1); + { + /* Check that the aggnonce encodes two points at infinity */ + rustsecp256k1_v0_11_ge aggnonce_pt[2]; + rustsecp256k1_v0_11_musig_aggnonce_load(CTX, aggnonce_pt, &aggnonce); + for (i = 0; i < 2; i++) { + rustsecp256k1_v0_11_ge_is_infinity(&aggnonce_pt[i]); + } + } + CHECK(rustsecp256k1_v0_11_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); + + /** Serialize and parse aggregate nonces **/ + CHECK(rustsecp256k1_v0_11_musig_aggnonce_serialize(CTX, aggnonce_ser, &aggnonce) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_aggnonce_serialize(CTX, NULL, &aggnonce)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_aggnonce_serialize(CTX, aggnonce_ser, NULL)); + CHECK(memcmp_and_randomize(aggnonce_ser, zeros132, sizeof(aggnonce_ser)) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_aggnonce_serialize(CTX, aggnonce_ser, (rustsecp256k1_v0_11_musig_aggnonce*) &invalid_pubnonce)); + CHECK(memcmp_and_randomize(aggnonce_ser, zeros132, sizeof(aggnonce_ser)) == 0); + CHECK(rustsecp256k1_v0_11_musig_aggnonce_serialize(CTX, aggnonce_ser, &aggnonce) == 1); + + CHECK(rustsecp256k1_v0_11_musig_aggnonce_parse(CTX, &aggnonce, aggnonce_ser) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_aggnonce_parse(CTX, NULL, aggnonce_ser)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_aggnonce_parse(CTX, &aggnonce, NULL)); + CHECK(rustsecp256k1_v0_11_musig_aggnonce_parse(CTX, &aggnonce, zeros132) == 1); + CHECK(rustsecp256k1_v0_11_musig_aggnonce_parse(CTX, &aggnonce, aggnonce_ser) == 1); + + { + /* Check that serialize and parse results in the same value */ + rustsecp256k1_v0_11_musig_aggnonce tmp; + CHECK(rustsecp256k1_v0_11_musig_aggnonce_serialize(CTX, aggnonce_ser, &aggnonce) == 1); + CHECK(rustsecp256k1_v0_11_musig_aggnonce_parse(CTX, &tmp, aggnonce_ser) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&tmp, &aggnonce, sizeof(tmp)) == 0); + } + + /** Process nonces **/ + CHECK(rustsecp256k1_v0_11_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_process(CTX, NULL, &aggnonce, msg, &keyagg_cache)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_process(CTX, &session, NULL, msg, &keyagg_cache)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_process(CTX, &session, (rustsecp256k1_v0_11_musig_aggnonce*) &invalid_pubnonce, msg, &keyagg_cache)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_process(CTX, &session, &aggnonce, NULL, &keyagg_cache)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_process(CTX, &session, &aggnonce, msg, NULL)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_nonce_process(CTX, &session, &aggnonce, msg, &invalid_keyagg_cache)); + + CHECK(rustsecp256k1_v0_11_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache) == 1); + + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK(rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 1); + /* The secnonce is set to 0 and subsequent signing attempts fail */ + CHECK(rustsecp256k1_v0_11_memcmp_var(&secnonce_tmp, zeros132, sizeof(secnonce_tmp)) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sign(CTX, NULL, &secnonce_tmp, &keypair[0], &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[0], NULL, &keypair[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[0], &invalid_secnonce, &keypair[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, NULL, &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &invalid_keypair, &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + { + unsigned char sk_tmp[32]; + rustsecp256k1_v0_11_keypair keypair_tmp; + testrand256(sk_tmp); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair_tmp, sk_tmp)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair_tmp, &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + } + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], NULL, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &invalid_keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, NULL)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &invalid_session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + + CHECK(rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[0], &secnonce[0], &keypair[0], &keyagg_cache, &session) == 1); + CHECK(rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[1], &secnonce[1], &keypair[1], &keyagg_cache, &session) == 1); + + CHECK(rustsecp256k1_v0_11_musig_partial_sig_serialize(CTX, buf, &partial_sig[0]) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_serialize(CTX, NULL, &partial_sig[0])); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_serialize(CTX, buf, NULL)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_serialize(CTX, buf, &invalid_partial_sig)); + CHECK(rustsecp256k1_v0_11_musig_partial_sig_parse(CTX, &partial_sig[0], buf) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_parse(CTX, NULL, buf)); + { + /* Check that parsing failure results in an invalid sig */ + rustsecp256k1_v0_11_musig_partial_sig tmp; + CHECK(rustsecp256k1_v0_11_musig_partial_sig_parse(CTX, &tmp, max64) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&tmp, zeros132, sizeof(partial_sig[0])) == 0); + } + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_parse(CTX, &partial_sig[0], NULL)); + + { + /* Check that serialize and parse results in the same value */ + rustsecp256k1_v0_11_musig_partial_sig tmp; + CHECK(rustsecp256k1_v0_11_musig_partial_sig_serialize(CTX, buf, &partial_sig[0]) == 1); + CHECK(rustsecp256k1_v0_11_musig_partial_sig_parse(CTX, &tmp, buf) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&tmp, &partial_sig[0], sizeof(tmp)) == 0); + } + + /** Partial signature verification */ + CHECK(rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); + CHECK(rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, NULL, &pubnonce[0], &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &invalid_partial_sig, &pubnonce[0], &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[0], NULL, &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[0], &invalid_pubnonce, &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], NULL, &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &invalid_pk, &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], NULL, &session)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &invalid_keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, NULL)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &invalid_session)); + + CHECK(rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); + CHECK(rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[1], &pk[1], &keyagg_cache, &session) == 1); + + /** Signature aggregation and verification */ + CHECK(rustsecp256k1_v0_11_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_agg(CTX, NULL, &session, partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_agg(CTX, pre_sig, NULL, partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_agg(CTX, pre_sig, &invalid_session, partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_agg(CTX, pre_sig, &session, NULL, 2)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_agg(CTX, pre_sig, &session, invalid_partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 0)); + CHECK(rustsecp256k1_v0_11_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 1) == 1); + CHECK(rustsecp256k1_v0_11_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2) == 1); +} + +static void musig_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) { + rustsecp256k1_v0_11_scalar k1[2], k2[2]; + + rustsecp256k1_v0_11_nonce_function_musig(k1, args[0], args[1], args[2], args[3], args[4], args[5]); + testrand_flip(args[n_flip], n_bytes); + rustsecp256k1_v0_11_nonce_function_musig(k2, args[0], args[1], args[2], args[3], args[4], args[5]); + CHECK(rustsecp256k1_v0_11_scalar_eq(&k1[0], &k2[0]) == 0); + CHECK(rustsecp256k1_v0_11_scalar_eq(&k1[1], &k2[1]) == 0); +} + +static void musig_nonce_test(void) { + unsigned char *args[6]; + unsigned char session_secrand[32]; + unsigned char sk[32]; + unsigned char pk[33]; + unsigned char msg[32]; + unsigned char agg_pk[32]; + unsigned char extra_input[32]; + int i, j; + rustsecp256k1_v0_11_scalar k[6][2]; + + testrand_bytes_test(session_secrand, sizeof(session_secrand)); + testrand_bytes_test(sk, sizeof(sk)); + testrand_bytes_test(pk, sizeof(pk)); + testrand_bytes_test(msg, sizeof(msg)); + testrand_bytes_test(agg_pk, sizeof(agg_pk)); + testrand_bytes_test(extra_input, sizeof(extra_input)); + + /* Check that a bitflip in an argument results in different nonces. */ + args[0] = session_secrand; + args[1] = msg; + args[2] = sk; + args[3] = pk; + args[4] = agg_pk; + args[5] = extra_input; + for (i = 0; i < COUNT; i++) { + musig_nonce_bitflip(args, 0, sizeof(session_secrand)); + musig_nonce_bitflip(args, 1, sizeof(msg)); + musig_nonce_bitflip(args, 2, sizeof(sk)); + musig_nonce_bitflip(args, 3, sizeof(pk)); + musig_nonce_bitflip(args, 4, sizeof(agg_pk)); + musig_nonce_bitflip(args, 5, sizeof(extra_input)); + } + /* Check that if any argument is NULL, a different nonce is produced than if + * any other argument is NULL. */ + memcpy(msg, session_secrand, sizeof(msg)); + memcpy(sk, session_secrand, sizeof(sk)); + memcpy(pk, session_secrand, sizeof(session_secrand)); + memcpy(agg_pk, session_secrand, sizeof(agg_pk)); + memcpy(extra_input, session_secrand, sizeof(extra_input)); + rustsecp256k1_v0_11_nonce_function_musig(k[0], args[0], args[1], args[2], args[3], args[4], args[5]); + rustsecp256k1_v0_11_nonce_function_musig(k[1], args[0], NULL, args[2], args[3], args[4], args[5]); + rustsecp256k1_v0_11_nonce_function_musig(k[2], args[0], args[1], NULL, args[3], args[4], args[5]); + rustsecp256k1_v0_11_nonce_function_musig(k[3], args[0], args[1], args[2], NULL, args[4], args[5]); + rustsecp256k1_v0_11_nonce_function_musig(k[4], args[0], args[1], args[2], args[3], NULL, args[5]); + rustsecp256k1_v0_11_nonce_function_musig(k[5], args[0], args[1], args[2], args[3], args[4], NULL); + for (i = 0; i < 6; i++) { + CHECK(!rustsecp256k1_v0_11_scalar_eq(&k[i][0], &k[i][1])); + for (j = i+1; j < 6; j++) { + CHECK(!rustsecp256k1_v0_11_scalar_eq(&k[i][0], &k[j][0])); + CHECK(!rustsecp256k1_v0_11_scalar_eq(&k[i][1], &k[j][1])); + } + } +} + +static void sha256_tag_test_internal(rustsecp256k1_v0_11_sha256 *sha_tagged, unsigned char *tag, size_t taglen) { + rustsecp256k1_v0_11_sha256 sha; + rustsecp256k1_v0_11_sha256_initialize_tagged(&sha, tag, taglen); + test_sha256_eq(&sha, sha_tagged); +} + +/* Checks that the initialized tagged hashes have the expected + * state. */ +static void sha256_tag_test(void) { + rustsecp256k1_v0_11_sha256 sha; + { + char tag[] = "KeyAgg list"; + rustsecp256k1_v0_11_musig_keyagglist_sha256(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } + { + char tag[] = "KeyAgg coefficient"; + rustsecp256k1_v0_11_musig_keyaggcoef_sha256(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } + { + unsigned char tag[] = "MuSig/aux"; + rustsecp256k1_v0_11_nonce_function_musig_sha256_tagged_aux(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } + { + unsigned char tag[] = "MuSig/nonce"; + rustsecp256k1_v0_11_nonce_function_musig_sha256_tagged(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } + { + unsigned char tag[] = "MuSig/noncecoef"; + rustsecp256k1_v0_11_musig_compute_noncehash_sha256_tagged(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } +} + +/* Attempts to create a signature for the aggregate public key using given secret + * keys and keyagg_cache. */ +static void musig_tweak_test_helper(const rustsecp256k1_v0_11_xonly_pubkey* agg_pk, const unsigned char *sk0, const unsigned char *sk1, rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache) { + rustsecp256k1_v0_11_pubkey pk[2]; + unsigned char session_secrand[2][32]; + unsigned char msg[32]; + rustsecp256k1_v0_11_musig_secnonce secnonce[2]; + rustsecp256k1_v0_11_musig_pubnonce pubnonce[2]; + const rustsecp256k1_v0_11_musig_pubnonce *pubnonce_ptr[2]; + rustsecp256k1_v0_11_musig_aggnonce aggnonce; + rustsecp256k1_v0_11_keypair keypair[2]; + rustsecp256k1_v0_11_musig_session session; + rustsecp256k1_v0_11_musig_partial_sig partial_sig[2]; + const rustsecp256k1_v0_11_musig_partial_sig *partial_sig_ptr[2]; + unsigned char final_sig[64]; + int i; + + for (i = 0; i < 2; i++) { + pubnonce_ptr[i] = &pubnonce[i]; + partial_sig_ptr[i] = &partial_sig[i]; + + testrand256(session_secrand[i]); + } + CHECK(create_keypair_and_pk(&keypair[0], &pk[0], sk0) == 1); + CHECK(create_keypair_and_pk(&keypair[1], &pk[1], sk1) == 1); + testrand256(msg); + + CHECK(rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk0, &pk[0], NULL, NULL, NULL) == 1); + CHECK(rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_secrand[1], sk1, &pk[1], NULL, NULL, NULL) == 1); + + CHECK(rustsecp256k1_v0_11_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); + CHECK(rustsecp256k1_v0_11_musig_nonce_process(CTX, &session, &aggnonce, msg, keyagg_cache) == 1); + + CHECK(rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[0], &secnonce[0], &keypair[0], keyagg_cache, &session) == 1); + CHECK(rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig[1], &secnonce[1], &keypair[1], keyagg_cache, &session) == 1); + + CHECK(rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], keyagg_cache, &session) == 1); + CHECK(rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[1], &pk[1], keyagg_cache, &session) == 1); + + CHECK(rustsecp256k1_v0_11_musig_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, 2) == 1); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), agg_pk) == 1); +} + +/* Create aggregate public key P[0], tweak multiple times (using xonly and + * plain tweaking) and test signing. */ +static void musig_tweak_test(void) { + unsigned char sk[2][32]; + rustsecp256k1_v0_11_pubkey pk[2]; + const rustsecp256k1_v0_11_pubkey *pk_ptr[2]; + rustsecp256k1_v0_11_musig_keyagg_cache keyagg_cache; + enum { N_TWEAKS = 8 }; + rustsecp256k1_v0_11_pubkey P[N_TWEAKS + 1]; + rustsecp256k1_v0_11_xonly_pubkey P_xonly[N_TWEAKS + 1]; + int i; + + /* Key Setup */ + for (i = 0; i < 2; i++) { + pk_ptr[i] = &pk[i]; + testrand256(sk[i]); + CHECK(create_keypair_and_pk(NULL, &pk[i], sk[i]) == 1); + } + /* Compute P0 = keyagg(pk0, pk1) and test signing for it */ + CHECK(rustsecp256k1_v0_11_musig_pubkey_agg(CTX, &P_xonly[0], &keyagg_cache, pk_ptr, 2) == 1); + musig_tweak_test_helper(&P_xonly[0], sk[0], sk[1], &keyagg_cache); + CHECK(rustsecp256k1_v0_11_musig_pubkey_get(CTX, &P[0], &keyagg_cache)); + + /* Compute Pi = f(Pj) + tweaki*G where where j = i-1 and try signing for + * that key. If xonly is set to true, the function f normalizes the input + * point to have an even X-coordinate ("xonly-tweaking"). + * Otherwise, the function f is the identity function. */ + for (i = 1; i <= N_TWEAKS; i++) { + unsigned char tweak[32]; + int P_parity; + int xonly = testrand_bits(1); + + testrand256(tweak); + if (xonly) { + CHECK(rustsecp256k1_v0_11_musig_pubkey_xonly_tweak_add(CTX, &P[i], &keyagg_cache, tweak) == 1); + } else { + CHECK(rustsecp256k1_v0_11_musig_pubkey_ec_tweak_add(CTX, &P[i], &keyagg_cache, tweak) == 1); + } + CHECK(rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &P_xonly[i], &P_parity, &P[i])); + /* Check that musig_pubkey_tweak_add produces same result as + * xonly_pubkey_tweak_add or ec_pubkey_tweak_add. */ + if (xonly) { + unsigned char P_serialized[32]; + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, P_serialized, &P_xonly[i])); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, P_serialized, P_parity, &P_xonly[i-1], tweak) == 1); + } else { + rustsecp256k1_v0_11_pubkey tmp_key = P[i-1]; + CHECK(rustsecp256k1_v0_11_ec_pubkey_tweak_add(CTX, &tmp_key, tweak)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&tmp_key, &P[i], sizeof(tmp_key)) == 0); + } + /* Test signing for P[i] */ + musig_tweak_test_helper(&P_xonly[i], sk[0], sk[1], &keyagg_cache); + } +} + +int musig_vectors_keyagg_and_tweak(enum MUSIG_ERROR *error, + rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache, + unsigned char *agg_pk_ser, + const unsigned char pubkeys33[][33], + const unsigned char tweaks32[][32], + size_t key_indices_len, + const size_t *key_indices, + size_t tweak_indices_len, + const size_t *tweak_indices, + const int *is_xonly) { + rustsecp256k1_v0_11_pubkey pubkeys[MUSIG_VECTORS_MAX_PUBKEYS]; + const rustsecp256k1_v0_11_pubkey *pk_ptr[MUSIG_VECTORS_MAX_PUBKEYS]; + int i; + rustsecp256k1_v0_11_pubkey agg_pk; + rustsecp256k1_v0_11_xonly_pubkey agg_pk_xonly; + + for (i = 0; i < (int)key_indices_len; i++) { + if (!rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkeys[i], pubkeys33[key_indices[i]], 33)) { + *error = MUSIG_PUBKEY; + return 0; + } + pk_ptr[i] = &pubkeys[i]; + } + if (!rustsecp256k1_v0_11_musig_pubkey_agg(CTX, NULL, keyagg_cache, pk_ptr, key_indices_len)) { + *error = MUSIG_OTHER; + return 0; + } + + for (i = 0; i < (int)tweak_indices_len; i++) { + if (is_xonly[i]) { + if (!rustsecp256k1_v0_11_musig_pubkey_xonly_tweak_add(CTX, NULL, keyagg_cache, tweaks32[tweak_indices[i]])) { + *error = MUSIG_TWEAK; + return 0; + } + } else { + if (!rustsecp256k1_v0_11_musig_pubkey_ec_tweak_add(CTX, NULL, keyagg_cache, tweaks32[tweak_indices[i]])) { + *error = MUSIG_TWEAK; + return 0; + } + } + } + if (!rustsecp256k1_v0_11_musig_pubkey_get(CTX, &agg_pk, keyagg_cache)) { + *error = MUSIG_OTHER; + return 0; + } + + if (!rustsecp256k1_v0_11_xonly_pubkey_from_pubkey(CTX, &agg_pk_xonly, NULL, &agg_pk)) { + *error = MUSIG_OTHER; + return 0; + } + + if (agg_pk_ser != NULL) { + if (!rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, agg_pk_ser, &agg_pk_xonly)) { + *error = MUSIG_OTHER; + return 0; + } + } + + return 1; +} + +static void musig_test_vectors_keyagg(void) { + size_t i; + const struct musig_key_agg_vector *vector = &musig_key_agg_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_key_agg_valid_test_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + rustsecp256k1_v0_11_musig_keyagg_cache keyagg_cache; + unsigned char agg_pk[32]; + + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(rustsecp256k1_v0_11_memcmp_var(agg_pk, c->expected, sizeof(agg_pk)) == 0); + } + + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_key_agg_error_test_case *c = &vector->error_case[i]; + enum MUSIG_ERROR error; + rustsecp256k1_v0_11_musig_keyagg_cache keyagg_cache; + + CHECK(!musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + CHECK(c->error == error); + } +} + +static void musig_test_vectors_noncegen(void) { + size_t i; + const struct musig_nonce_gen_vector *vector = &musig_nonce_gen_vector; + + for (i = 0; i < sizeof(vector->test_case)/sizeof(vector->test_case[0]); i++) { + const struct musig_nonce_gen_test_case *c = &vector->test_case[i]; + rustsecp256k1_v0_11_musig_keyagg_cache keyagg_cache; + rustsecp256k1_v0_11_musig_keyagg_cache *keyagg_cache_ptr = NULL; + unsigned char session_secrand32[32]; + rustsecp256k1_v0_11_musig_secnonce secnonce; + rustsecp256k1_v0_11_musig_pubnonce pubnonce; + const unsigned char *sk = NULL; + const unsigned char *msg = NULL; + const unsigned char *extra_in = NULL; + rustsecp256k1_v0_11_pubkey pk; + unsigned char pubnonce66[66]; + + memcpy(session_secrand32, c->rand_, 32); + if (c->has_sk) { + sk = c->sk; + } + if (c->has_aggpk) { + /* Create keyagg_cache from aggpk */ + rustsecp256k1_v0_11_keyagg_cache_internal cache_i; + rustsecp256k1_v0_11_xonly_pubkey aggpk; + memset(&cache_i, 0, sizeof(cache_i)); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &aggpk, c->aggpk)); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_load(CTX, &cache_i.pk, &aggpk)); + rustsecp256k1_v0_11_keyagg_cache_save(&keyagg_cache, &cache_i); + keyagg_cache_ptr = &keyagg_cache; + } + if (c->has_msg) { + msg = c->msg; + } + if (c->has_extra_in) { + extra_in = c->extra_in; + } + + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pk, c->pk, sizeof(c->pk))); + CHECK(rustsecp256k1_v0_11_musig_nonce_gen(CTX, &secnonce, &pubnonce, session_secrand32, sk, &pk, msg, keyagg_cache_ptr, extra_in) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&secnonce.data[4], c->expected_secnonce, 2*32) == 0); + /* The last element of the secnonce is the public key (uncompressed in + * rustsecp256k1_v0_11_musig_secnonce, compressed in the test vector secnonce). */ + CHECK(rustsecp256k1_v0_11_memcmp_var(&secnonce.data[4+2*32], &pk, sizeof(pk)) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&c->expected_secnonce[2*32], c->pk, sizeof(c->pk)) == 0); + + CHECK(rustsecp256k1_v0_11_musig_pubnonce_serialize(CTX, pubnonce66, &pubnonce) == 1); + CHECK(sizeof(c->expected_pubnonce) == sizeof(pubnonce66)); + CHECK(rustsecp256k1_v0_11_memcmp_var(pubnonce66, c->expected_pubnonce, sizeof(pubnonce66)) == 0); + } +} + + +static void musig_test_vectors_nonceagg(void) { + size_t i; + int j; + const struct musig_nonce_agg_vector *vector = &musig_nonce_agg_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_nonce_agg_test_case *c = &vector->valid_case[i]; + rustsecp256k1_v0_11_musig_pubnonce pubnonce[2]; + const rustsecp256k1_v0_11_musig_pubnonce *pubnonce_ptr[2]; + rustsecp256k1_v0_11_musig_aggnonce aggnonce; + unsigned char aggnonce66[66]; + + for (j = 0; j < 2; j++) { + CHECK(rustsecp256k1_v0_11_musig_pubnonce_parse(CTX, &pubnonce[j], vector->pnonces[c->pnonce_indices[j]]) == 1); + pubnonce_ptr[j] = &pubnonce[j]; + } + CHECK(rustsecp256k1_v0_11_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2)); + CHECK(rustsecp256k1_v0_11_musig_aggnonce_serialize(CTX, aggnonce66, &aggnonce)); + CHECK(rustsecp256k1_v0_11_memcmp_var(aggnonce66, c->expected, 33) == 0); + } + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_nonce_agg_test_case *c = &vector->error_case[i]; + rustsecp256k1_v0_11_musig_pubnonce pubnonce[2]; + for (j = 0; j < 2; j++) { + int expected = c->invalid_nonce_idx != j; + CHECK(expected == rustsecp256k1_v0_11_musig_pubnonce_parse(CTX, &pubnonce[j], vector->pnonces[c->pnonce_indices[j]])); + } + } +} + +static void musig_test_set_secnonce(rustsecp256k1_v0_11_musig_secnonce *secnonce, const unsigned char *secnonce64, const rustsecp256k1_v0_11_pubkey *pubkey) { + rustsecp256k1_v0_11_ge pk; + rustsecp256k1_v0_11_scalar k[2]; + + rustsecp256k1_v0_11_scalar_set_b32(&k[0], &secnonce64[0], NULL); + rustsecp256k1_v0_11_scalar_set_b32(&k[1], &secnonce64[32], NULL); + CHECK(rustsecp256k1_v0_11_pubkey_load(CTX, &pk, pubkey)); + rustsecp256k1_v0_11_musig_secnonce_save(secnonce, k, &pk); +} + +static void musig_test_vectors_signverify(void) { + size_t i; + const struct musig_sign_verify_vector *vector = &musig_sign_verify_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_valid_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + rustsecp256k1_v0_11_musig_keyagg_cache keyagg_cache; + rustsecp256k1_v0_11_pubkey pubkey; + rustsecp256k1_v0_11_musig_pubnonce pubnonce; + rustsecp256k1_v0_11_musig_aggnonce aggnonce; + rustsecp256k1_v0_11_musig_session session; + rustsecp256k1_v0_11_musig_partial_sig partial_sig; + rustsecp256k1_v0_11_musig_secnonce secnonce; + rustsecp256k1_v0_11_keypair keypair; + unsigned char partial_sig32[32]; + + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, vector->sk)); + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + + CHECK(rustsecp256k1_v0_11_musig_aggnonce_parse(CTX, &aggnonce, vector->aggnonces[c->aggnonce_index])); + CHECK(rustsecp256k1_v0_11_musig_nonce_process(CTX, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache)); + + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); + musig_test_set_secnonce(&secnonce, vector->secnonces[0], &pubkey); + CHECK(rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + CHECK(rustsecp256k1_v0_11_musig_partial_sig_serialize(CTX, partial_sig32, &partial_sig)); + CHECK(rustsecp256k1_v0_11_memcmp_var(partial_sig32, c->expected, sizeof(partial_sig32)) == 0); + + CHECK(rustsecp256k1_v0_11_musig_pubnonce_parse(CTX, &pubnonce, vector->pubnonces[0])); + CHECK(rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session)); + } + for (i = 0; i < sizeof(vector->sign_error_case)/sizeof(vector->sign_error_case[0]); i++) { + const struct musig_sign_error_case *c = &vector->sign_error_case[i]; + enum MUSIG_ERROR error; + rustsecp256k1_v0_11_musig_keyagg_cache keyagg_cache; + rustsecp256k1_v0_11_pubkey pubkey; + rustsecp256k1_v0_11_musig_aggnonce aggnonce; + rustsecp256k1_v0_11_musig_session session; + rustsecp256k1_v0_11_musig_partial_sig partial_sig; + rustsecp256k1_v0_11_musig_secnonce secnonce; + rustsecp256k1_v0_11_keypair keypair; + int expected; + + if (i == 0) { + /* Skip this vector since the implementation does not error out when + * the signing key does not belong to any pubkey. */ + continue; + } + expected = c->error != MUSIG_PUBKEY; + CHECK(expected == musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(expected || c->error == error); + if (!expected) { + continue; + } + + expected = c->error != MUSIG_AGGNONCE; + CHECK(expected == rustsecp256k1_v0_11_musig_aggnonce_parse(CTX, &aggnonce, vector->aggnonces[c->aggnonce_index])); + if (!expected) { + continue; + } + CHECK(rustsecp256k1_v0_11_musig_nonce_process(CTX, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache)); + + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); + musig_test_set_secnonce(&secnonce, vector->secnonces[c->secnonce_index], &pubkey); + expected = c->error != MUSIG_SECNONCE; + if (expected) { + CHECK(rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + } else { + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + } + } + for (i = 0; i < sizeof(vector->verify_fail_case)/sizeof(vector->verify_fail_case[0]); i++) { + const struct musig_verify_fail_error_case *c = &vector->verify_fail_case[i]; + enum MUSIG_ERROR error; + rustsecp256k1_v0_11_musig_keyagg_cache keyagg_cache; + rustsecp256k1_v0_11_musig_aggnonce aggnonce; + rustsecp256k1_v0_11_musig_session session; + rustsecp256k1_v0_11_musig_partial_sig partial_sig; + enum { NUM_PUBNONCES = 3 }; + rustsecp256k1_v0_11_musig_pubnonce pubnonce[NUM_PUBNONCES]; + const rustsecp256k1_v0_11_musig_pubnonce *pubnonce_ptr[NUM_PUBNONCES]; + rustsecp256k1_v0_11_pubkey pubkey; + int expected; + size_t j; + + CHECK(NUM_PUBNONCES <= c->nonce_indices_len); + for (j = 0; j < c->nonce_indices_len; j++) { + CHECK(rustsecp256k1_v0_11_musig_pubnonce_parse(CTX, &pubnonce[j], vector->pubnonces[c->nonce_indices[j]])); + pubnonce_ptr[j] = &pubnonce[j]; + } + + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(rustsecp256k1_v0_11_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, c->nonce_indices_len) == 1); + CHECK(rustsecp256k1_v0_11_musig_nonce_process(CTX, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache)); + + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[c->signer_index], sizeof(vector->pubkeys[0]))); + + expected = c->error != MUSIG_SIG; + CHECK(expected == rustsecp256k1_v0_11_musig_partial_sig_parse(CTX, &partial_sig, c->sig)); + if (!expected) { + continue; + } + expected = c->error != MUSIG_SIG_VERIFY; + CHECK(expected == rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig, pubnonce, &pubkey, &keyagg_cache, &session)); + } + for (i = 0; i < sizeof(vector->verify_error_case)/sizeof(vector->verify_error_case[0]); i++) { + const struct musig_verify_fail_error_case *c = &vector->verify_error_case[i]; + enum MUSIG_ERROR error; + rustsecp256k1_v0_11_musig_keyagg_cache keyagg_cache; + rustsecp256k1_v0_11_musig_pubnonce pubnonce; + int expected; + + expected = c->error != MUSIG_PUBKEY; + CHECK(expected == musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(expected || c->error == error); + if (!expected) { + continue; + } + expected = c->error != MUSIG_PUBNONCE; + CHECK(expected == rustsecp256k1_v0_11_musig_pubnonce_parse(CTX, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]])); + } +} + +static void musig_test_vectors_tweak(void) { + size_t i; + const struct musig_tweak_vector *vector = &musig_tweak_vector; + rustsecp256k1_v0_11_pubkey pubkey; + rustsecp256k1_v0_11_musig_aggnonce aggnonce; + rustsecp256k1_v0_11_musig_secnonce secnonce; + + CHECK(rustsecp256k1_v0_11_musig_aggnonce_parse(CTX, &aggnonce, vector->aggnonce)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_tweak_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + rustsecp256k1_v0_11_musig_keyagg_cache keyagg_cache; + rustsecp256k1_v0_11_musig_pubnonce pubnonce; + rustsecp256k1_v0_11_musig_session session; + rustsecp256k1_v0_11_musig_partial_sig partial_sig; + rustsecp256k1_v0_11_keypair keypair; + unsigned char partial_sig32[32]; + + musig_test_set_secnonce(&secnonce, vector->secnonce, &pubkey); + + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, vector->sk)); + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + + CHECK(rustsecp256k1_v0_11_musig_nonce_process(CTX, &session, &aggnonce, vector->msg, &keyagg_cache)); + + CHECK(rustsecp256k1_v0_11_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + CHECK(rustsecp256k1_v0_11_musig_partial_sig_serialize(CTX, partial_sig32, &partial_sig)); + CHECK(rustsecp256k1_v0_11_memcmp_var(partial_sig32, c->expected, sizeof(partial_sig32)) == 0); + + CHECK(rustsecp256k1_v0_11_musig_pubnonce_parse(CTX, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]])); + CHECK(rustsecp256k1_v0_11_musig_partial_sig_verify(CTX, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session)); + } + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_tweak_case *c = &vector->error_case[i]; + enum MUSIG_ERROR error; + rustsecp256k1_v0_11_musig_keyagg_cache keyagg_cache; + CHECK(!musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + CHECK(error == MUSIG_TWEAK); + } +} + +static void musig_test_vectors_sigagg(void) { + size_t i, j; + const struct musig_sig_agg_vector *vector = &musig_sig_agg_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_sig_agg_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + unsigned char final_sig[64]; + rustsecp256k1_v0_11_musig_keyagg_cache keyagg_cache; + unsigned char agg_pk32[32]; + rustsecp256k1_v0_11_xonly_pubkey agg_pk; + rustsecp256k1_v0_11_musig_aggnonce aggnonce; + rustsecp256k1_v0_11_musig_session session; + rustsecp256k1_v0_11_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; + const rustsecp256k1_v0_11_musig_partial_sig *partial_sig_ptr[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; + + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk32, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + CHECK(rustsecp256k1_v0_11_musig_aggnonce_parse(CTX, &aggnonce, c->aggnonce)); + CHECK(rustsecp256k1_v0_11_musig_nonce_process(CTX, &session, &aggnonce, vector->msg, &keyagg_cache)); + for (j = 0; j < c->psig_indices_len; j++) { + CHECK(rustsecp256k1_v0_11_musig_partial_sig_parse(CTX, &partial_sig[j], vector->psigs[c->psig_indices[j]])); + partial_sig_ptr[j] = &partial_sig[j]; + } + + CHECK(rustsecp256k1_v0_11_musig_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, c->psig_indices_len) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(final_sig, c->expected, sizeof(final_sig)) == 0); + + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &agg_pk, agg_pk32)); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, final_sig, vector->msg, sizeof(vector->msg), &agg_pk) == 1); + } + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_sig_agg_case *c = &vector->error_case[i]; + rustsecp256k1_v0_11_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; + for (j = 0; j < c->psig_indices_len; j++) { + int expected = c->invalid_sig_idx != (int)j; + CHECK(expected == rustsecp256k1_v0_11_musig_partial_sig_parse(CTX, &partial_sig[j], vector->psigs[c->psig_indices[j]])); + } + } +} + +/* Since the BIP doesn't provide static test vectors for nonce_gen_counter, we + * define a static test here */ +static void musig_test_static_nonce_gen_counter(void) { + rustsecp256k1_v0_11_musig_secnonce secnonce; + rustsecp256k1_v0_11_musig_pubnonce pubnonce; + unsigned char pubnonce66[66]; + rustsecp256k1_v0_11_pubkey pk; + rustsecp256k1_v0_11_keypair keypair; + uint64_t nonrepeating_cnt = 0; + unsigned char sk[32] = { + 0xEE, 0xC1, 0xCB, 0x7D, 0x1B, 0x72, 0x54, 0xC5, + 0xCA, 0xB0, 0xD9, 0xC6, 0x1A, 0xB0, 0x2E, 0x64, + 0x3D, 0x46, 0x4A, 0x59, 0xFE, 0x6C, 0x96, 0xA7, + 0xEF, 0xE8, 0x71, 0xF0, 0x7C, 0x5A, 0xEF, 0x54, + }; + unsigned char expected_secnonce[64] = { + 0x84, 0x2F, 0x13, 0x80, 0xCD, 0x17, 0xA1, 0x98, + 0xFC, 0x3D, 0xAD, 0x3B, 0x7D, 0xA7, 0x49, 0x29, + 0x41, 0xF4, 0x69, 0x76, 0xF2, 0x70, 0x2F, 0xF7, + 0xC6, 0x6F, 0x24, 0xF4, 0x72, 0x03, 0x6A, 0xF1, + 0xDA, 0x3F, 0x95, 0x2D, 0xDE, 0x4A, 0x2D, 0xA6, + 0xB6, 0x32, 0x57, 0x07, 0xCE, 0x87, 0xA4, 0xE3, + 0x61, 0x6D, 0x06, 0xFC, 0x5F, 0x81, 0xA9, 0xC9, + 0x93, 0x86, 0xD2, 0x0A, 0x99, 0xCE, 0xCF, 0x99, + }; + unsigned char expected_pubnonce[66] = { + 0x03, 0xA5, 0xB9, 0xB6, 0x90, 0x79, 0x42, 0xEA, + 0xCD, 0xDA, 0x49, 0xA3, 0x66, 0x01, 0x6E, 0xC2, + 0xE6, 0x24, 0x04, 0xA1, 0xBF, 0x4A, 0xB6, 0xD4, + 0xDB, 0x82, 0x06, 0x7B, 0xC3, 0xAD, 0xF0, 0x86, + 0xD7, 0x03, 0x32, 0x05, 0xDB, 0x9E, 0xB3, 0x4D, + 0x5C, 0x7C, 0xE0, 0x28, 0x48, 0xCA, 0xC6, 0x8A, + 0x83, 0xED, 0x73, 0xE3, 0x88, 0x34, 0x77, 0xF5, + 0x63, 0xF2, 0x3C, 0xE9, 0xA1, 0x1A, 0x77, 0x21, + 0xEC, 0x64, + }; + + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk)); + CHECK(rustsecp256k1_v0_11_keypair_pub(CTX, &pk, &keypair)); + CHECK(rustsecp256k1_v0_11_musig_nonce_gen_counter(CTX, &secnonce, &pubnonce, nonrepeating_cnt, &keypair, NULL, NULL, NULL) == 1); + + CHECK(rustsecp256k1_v0_11_memcmp_var(&secnonce.data[4], expected_secnonce, 2*32) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&secnonce.data[4+2*32], &pk, sizeof(pk)) == 0); + + CHECK(rustsecp256k1_v0_11_musig_pubnonce_serialize(CTX, pubnonce66, &pubnonce) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(pubnonce66, expected_pubnonce, sizeof(pubnonce66)) == 0); +} + +static void run_musig_tests(void) { + int i; + + for (i = 0; i < COUNT; i++) { + musig_simple_test(); + } + musig_api_tests(); + musig_nonce_test(); + for (i = 0; i < COUNT; i++) { + /* Run multiple times to ensure that pk and nonce have different y + * parities */ + musig_tweak_test(); + } + sha256_tag_test(); + musig_test_vectors_keyagg(); + musig_test_vectors_noncegen(); + musig_test_vectors_nonceagg(); + musig_test_vectors_signverify(); + musig_test_vectors_tweak(); + musig_test_vectors_sigagg(); + + musig_test_static_nonce_gen_counter(); +} + +#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/vectors.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/vectors.h similarity index 97% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/vectors.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/vectors.h index b959e0a2..8407c2a6 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/musig/vectors.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/musig/vectors.h @@ -1,5 +1,5 @@ /** - * Automatically generated by contrib/musig2-vectors.py. + * Automatically generated by ./tools/test_vectors_musig2_generate.py. * * The test vectors for the KeySort function are included in this file. They can * be found in src/modules/extrakeys/tests_impl.h. */ @@ -215,13 +215,13 @@ static const struct musig_sign_verify_vector musig_sign_verify_vector = { { 3, { 0, 1, 2 }, 0, 0, 1, MUSIG_SECNONCE }, }, { - { { 0x97, 0xAC, 0x83, 0x3A, 0xDC, 0xB1, 0xAF, 0xA4, 0x2E, 0xBF, 0x9E, 0x07, 0x25, 0x61, 0x6F, 0x3C, 0x9A, 0x0D, 0x5B, 0x61, 0x4F, 0x6F, 0xE2, 0x83, 0xCE, 0xAA, 0xA3, 0x7A, 0x8F, 0xFA, 0xF4, 0x06 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG_VERIFY }, - { { 0x68, 0x53, 0x7C, 0xC5, 0x23, 0x4E, 0x50, 0x5B, 0xD1, 0x40, 0x61, 0xF8, 0xDA, 0x9E, 0x90, 0xC2, 0x20, 0xA1, 0x81, 0x85, 0x5F, 0xD8, 0xBD, 0xB7, 0xF1, 0x27, 0xBB, 0x12, 0x40, 0x3B, 0x4D, 0x3B }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 1, MUSIG_SIG_VERIFY }, + { { 0xFE, 0xD5, 0x44, 0x34, 0xAD, 0x4C, 0xFE, 0x95, 0x3F, 0xC5, 0x27, 0xDC, 0x6A, 0x5E, 0x5B, 0xE8, 0xF6, 0x23, 0x49, 0x07, 0xB7, 0xC1, 0x87, 0x55, 0x95, 0x57, 0xCE, 0x87, 0xA0, 0x54, 0x1C, 0x46 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG_VERIFY }, + { { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 1, MUSIG_SIG_VERIFY }, { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG }, }, { - { { 0x68, 0x53, 0x7C, 0xC5, 0x23, 0x4E, 0x50, 0x5B, 0xD1, 0x40, 0x61, 0xF8, 0xDA, 0x9E, 0x90, 0xC2, 0x20, 0xA1, 0x81, 0x85, 0x5F, 0xD8, 0xBD, 0xB7, 0xF1, 0x27, 0xBB, 0x12, 0x40, 0x3B, 0x4D, 0x3B }, 3, { 0, 1, 2 }, 3, { 4, 1, 2 }, 0, 0, MUSIG_PUBNONCE }, - { { 0x68, 0x53, 0x7C, 0xC5, 0x23, 0x4E, 0x50, 0x5B, 0xD1, 0x40, 0x61, 0xF8, 0xDA, 0x9E, 0x90, 0xC2, 0x20, 0xA1, 0x81, 0x85, 0x5F, 0xD8, 0xBD, 0xB7, 0xF1, 0x27, 0xBB, 0x12, 0x40, 0x3B, 0x4D, 0x3B }, 3, { 3, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_PUBKEY }, + { { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 0, 1, 2 }, 3, { 4, 1, 2 }, 0, 0, MUSIG_PUBNONCE }, + { { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 3, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_PUBKEY }, }, }; diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/Makefile.am.include b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/Makefile.am.include similarity index 77% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/Makefile.am.include rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/Makefile.am.include index 2917f4f6..4ea04f80 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/Makefile.am.include +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/Makefile.am.include @@ -1,4 +1,4 @@ -include_HEADERS += include/rustsecp256k1zkp_v0_8_0_recovery.h +include_HEADERS += include/rustsecp256k1_v0_11_recovery.h noinst_HEADERS += src/modules/recovery/main_impl.h noinst_HEADERS += src/modules/recovery/tests_impl.h noinst_HEADERS += src/modules/recovery/tests_exhaustive_impl.h diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/bench_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/bench_impl.h similarity index 66% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/bench_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/bench_impl.h index 75c3470a..defd82f6 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/bench_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/bench_impl.h @@ -7,27 +7,27 @@ #ifndef SECP256K1_MODULE_RECOVERY_BENCH_H #define SECP256K1_MODULE_RECOVERY_BENCH_H -#include "../include/secp256k1_recovery.h" +#include "../../../include/secp256k1_recovery.h" typedef struct { - rustsecp256k1zkp_v0_8_0_context *ctx; + rustsecp256k1_v0_11_context *ctx; unsigned char msg[32]; unsigned char sig[64]; } bench_recover_data; -void bench_recover(void* arg, int iters) { +static void bench_recover(void* arg, int iters) { int i; bench_recover_data *data = (bench_recover_data*)arg; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; + rustsecp256k1_v0_11_pubkey pubkey; unsigned char pubkeyc[33]; for (i = 0; i < iters; i++) { int j; size_t pubkeylen = 33; - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature sig; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED)); + rustsecp256k1_v0_11_ecdsa_recoverable_signature sig; + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2)); + CHECK(rustsecp256k1_v0_11_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED)); for (j = 0; j < 32; j++) { data->sig[j + 32] = data->msg[j]; /* Move former message to S. */ data->msg[j] = data->sig[j]; /* Move former R to message. */ @@ -36,7 +36,7 @@ void bench_recover(void* arg, int iters) { } } -void bench_recover_setup(void* arg) { +static void bench_recover_setup(void* arg) { int i; bench_recover_data *data = (bench_recover_data*)arg; @@ -48,15 +48,15 @@ void bench_recover_setup(void* arg) { } } -void run_recovery_bench(int iters, int argc, char** argv) { +static void run_recovery_bench(int iters, int argc, char** argv) { bench_recover_data data; int d = argc == 1; - data.ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_VERIFY); + data.ctx = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, iters); - rustsecp256k1zkp_v0_8_0_context_destroy(data.ctx); + rustsecp256k1_v0_11_context_destroy(data.ctx); } #endif /* SECP256K1_MODULE_RECOVERY_BENCH_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/main_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/main_impl.h new file mode 100644 index 00000000..32f182a3 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/main_impl.h @@ -0,0 +1,159 @@ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H +#define SECP256K1_MODULE_RECOVERY_MAIN_H + +#include "../../../include/secp256k1_recovery.h" + +static void rustsecp256k1_v0_11_ecdsa_recoverable_signature_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_scalar* r, rustsecp256k1_v0_11_scalar* s, int* recid, const rustsecp256k1_v0_11_ecdsa_recoverable_signature* sig) { + (void)ctx; + if (sizeof(rustsecp256k1_v0_11_scalar) == 32) { + /* When the rustsecp256k1_v0_11_scalar type is exactly 32 byte, use its + * representation inside rustsecp256k1_v0_11_ecdsa_signature, as conversion is very fast. + * Note that rustsecp256k1_v0_11_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + rustsecp256k1_v0_11_scalar_set_b32(r, &sig->data[0], NULL); + rustsecp256k1_v0_11_scalar_set_b32(s, &sig->data[32], NULL); + } + *recid = sig->data[64]; +} + +static void rustsecp256k1_v0_11_ecdsa_recoverable_signature_save(rustsecp256k1_v0_11_ecdsa_recoverable_signature* sig, const rustsecp256k1_v0_11_scalar* r, const rustsecp256k1_v0_11_scalar* s, int recid) { + if (sizeof(rustsecp256k1_v0_11_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + rustsecp256k1_v0_11_scalar_get_b32(&sig->data[0], r); + rustsecp256k1_v0_11_scalar_get_b32(&sig->data[32], s); + } + sig->data[64] = recid; +} + +int rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) { + rustsecp256k1_v0_11_scalar r, s; + int ret = 1; + int overflow = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + ARG_CHECK(recid >= 0 && recid <= 3); + + rustsecp256k1_v0_11_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + rustsecp256k1_v0_11_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + rustsecp256k1_v0_11_ecdsa_recoverable_signature_save(sig, &r, &s, recid); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + +int rustsecp256k1_v0_11_ecdsa_recoverable_signature_serialize_compact(const rustsecp256k1_v0_11_context* ctx, unsigned char *output64, int *recid, const rustsecp256k1_v0_11_ecdsa_recoverable_signature* sig) { + rustsecp256k1_v0_11_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(recid != NULL); + + rustsecp256k1_v0_11_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig); + rustsecp256k1_v0_11_scalar_get_b32(&output64[0], &r); + rustsecp256k1_v0_11_scalar_get_b32(&output64[32], &s); + return 1; +} + +int rustsecp256k1_v0_11_ecdsa_recoverable_signature_convert(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ecdsa_signature* sig, const rustsecp256k1_v0_11_ecdsa_recoverable_signature* sigin) { + rustsecp256k1_v0_11_scalar r, s; + int recid; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(sigin != NULL); + + rustsecp256k1_v0_11_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin); + rustsecp256k1_v0_11_ecdsa_signature_save(sig, &r, &s); + return 1; +} + +static int rustsecp256k1_v0_11_ecdsa_sig_recover(const rustsecp256k1_v0_11_scalar *sigr, const rustsecp256k1_v0_11_scalar* sigs, rustsecp256k1_v0_11_ge *pubkey, const rustsecp256k1_v0_11_scalar *message, int recid) { + unsigned char brx[32]; + rustsecp256k1_v0_11_fe fx; + rustsecp256k1_v0_11_ge x; + rustsecp256k1_v0_11_gej xj; + rustsecp256k1_v0_11_scalar rn, u1, u2; + rustsecp256k1_v0_11_gej qj; + int r; + + if (rustsecp256k1_v0_11_scalar_is_zero(sigr) || rustsecp256k1_v0_11_scalar_is_zero(sigs)) { + return 0; + } + + rustsecp256k1_v0_11_scalar_get_b32(brx, sigr); + r = rustsecp256k1_v0_11_fe_set_b32_limit(&fx, brx); + (void)r; + VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */ + if (recid & 2) { + if (rustsecp256k1_v0_11_fe_cmp_var(&fx, &rustsecp256k1_v0_11_ecdsa_const_p_minus_order) >= 0) { + return 0; + } + rustsecp256k1_v0_11_fe_add(&fx, &rustsecp256k1_v0_11_ecdsa_const_order_as_fe); + } + if (!rustsecp256k1_v0_11_ge_set_xo_var(&x, &fx, recid & 1)) { + return 0; + } + rustsecp256k1_v0_11_gej_set_ge(&xj, &x); + rustsecp256k1_v0_11_scalar_inverse_var(&rn, sigr); + rustsecp256k1_v0_11_scalar_mul(&u1, &rn, message); + rustsecp256k1_v0_11_scalar_negate(&u1, &u1); + rustsecp256k1_v0_11_scalar_mul(&u2, &rn, sigs); + rustsecp256k1_v0_11_ecmult(&qj, &xj, &u2, &u1); + rustsecp256k1_v0_11_ge_set_gej_var(pubkey, &qj); + return !rustsecp256k1_v0_11_gej_is_infinity(&qj); +} + +int rustsecp256k1_v0_11_ecdsa_sign_recoverable(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ecdsa_recoverable_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, rustsecp256k1_v0_11_nonce_function noncefp, const void* noncedata) { + rustsecp256k1_v0_11_scalar r, s; + int ret, recid; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(rustsecp256k1_v0_11_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msghash32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); + + ret = rustsecp256k1_v0_11_ecdsa_sign_inner(ctx, &r, &s, &recid, msghash32, seckey, noncefp, noncedata); + rustsecp256k1_v0_11_ecdsa_recoverable_signature_save(signature, &r, &s, recid); + return ret; +} + +int rustsecp256k1_v0_11_ecdsa_recover(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *pubkey, const rustsecp256k1_v0_11_ecdsa_recoverable_signature *signature, const unsigned char *msghash32) { + rustsecp256k1_v0_11_ge q; + rustsecp256k1_v0_11_scalar r, s; + rustsecp256k1_v0_11_scalar m; + int recid; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(msghash32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(pubkey != NULL); + + rustsecp256k1_v0_11_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature); + VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */ + rustsecp256k1_v0_11_scalar_set_b32(&m, msghash32, NULL); + if (rustsecp256k1_v0_11_ecdsa_sig_recover(&r, &s, &q, &m, recid)) { + rustsecp256k1_v0_11_pubkey_save(pubkey, &q); + return 1; + } else { + memset(pubkey, 0, sizeof(*pubkey)); + return 0; + } +} + +#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/tests_exhaustive_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/tests_exhaustive_impl.h similarity index 57% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/tests_exhaustive_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/tests_exhaustive_impl.h index 9b6deadd..30876a00 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/recovery/tests_exhaustive_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/tests_exhaustive_impl.h @@ -7,10 +7,10 @@ #ifndef SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H #define SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H -#include "src/modules/recovery/main_impl.h" +#include "main_impl.h" #include "../../../include/secp256k1_recovery.h" -void test_exhaustive_recovery_sign(const rustsecp256k1zkp_v0_8_0_context *ctx, const rustsecp256k1zkp_v0_8_0_ge *group) { +static void test_exhaustive_recovery_sign(const rustsecp256k1_v0_11_context *ctx, const rustsecp256k1_v0_11_ge *group) { int i, j, k; uint64_t iter = 0; @@ -20,48 +20,47 @@ void test_exhaustive_recovery_sign(const rustsecp256k1zkp_v0_8_0_context *ctx, c if (skip_section(&iter)) continue; for (k = 1; k < EXHAUSTIVE_TEST_ORDER; k++) { /* nonce */ const int starting_k = k; - rustsecp256k1zkp_v0_8_0_fe r_dot_y_normalized; - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature rsig; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig; - rustsecp256k1zkp_v0_8_0_scalar sk, msg, r, s, expected_r; + rustsecp256k1_v0_11_fe r_dot_y_normalized; + rustsecp256k1_v0_11_ecdsa_recoverable_signature rsig; + rustsecp256k1_v0_11_ecdsa_signature sig; + rustsecp256k1_v0_11_scalar sk, msg, r, s, expected_r; unsigned char sk32[32], msg32[32]; int expected_recid; int recid; int overflow; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&msg, i); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&sk, j); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(sk32, &sk); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(msg32, &msg); + rustsecp256k1_v0_11_scalar_set_int(&msg, i); + rustsecp256k1_v0_11_scalar_set_int(&sk, j); + rustsecp256k1_v0_11_scalar_get_b32(sk32, &sk); + rustsecp256k1_v0_11_scalar_get_b32(msg32, &msg); - rustsecp256k1zkp_v0_8_0_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, rustsecp256k1zkp_v0_8_0_nonce_function_smallint, &k); + rustsecp256k1_v0_11_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, rustsecp256k1_v0_11_nonce_function_smallint, &k); /* Check directly */ - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig); + rustsecp256k1_v0_11_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig); r_from_k(&expected_r, group, k, &overflow); CHECK(r == expected_r); CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); /* The recid's second bit is for conveying overflow (R.x value >= group order). * In the actual secp256k1 this is an astronomically unlikely event, but in the - * small group used here, it will be the case for all points except the ones where - * R.x=1 (which the group is specifically selected to have). + * small group used here, it will almost certainly be the case for all points. * Note that this isn't actually useful; full recovery would need to convey * floor(R.x / group_order), but only one bit is used as that is sufficient * in the real group. */ expected_recid = overflow ? 2 : 0; r_dot_y_normalized = group[k].y; - rustsecp256k1zkp_v0_8_0_fe_normalize(&r_dot_y_normalized); + rustsecp256k1_v0_11_fe_normalize(&r_dot_y_normalized); /* Also the recovery id is flipped depending if we hit the low-s branch */ if ((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER) { - expected_recid |= rustsecp256k1zkp_v0_8_0_fe_is_odd(&r_dot_y_normalized); + expected_recid |= rustsecp256k1_v0_11_fe_is_odd(&r_dot_y_normalized); } else { - expected_recid |= !rustsecp256k1zkp_v0_8_0_fe_is_odd(&r_dot_y_normalized); + expected_recid |= !rustsecp256k1_v0_11_fe_is_odd(&r_dot_y_normalized); } CHECK(recid == expected_recid); /* Convert to a standard sig then check */ - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &r, &s, &sig); + rustsecp256k1_v0_11_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + rustsecp256k1_v0_11_ecdsa_signature_load(ctx, &r, &s, &sig); /* Note that we compute expected_r *after* signing -- this is important * because our nonce-computing function function might change k during * signing. */ @@ -79,7 +78,7 @@ void test_exhaustive_recovery_sign(const rustsecp256k1zkp_v0_8_0_context *ctx, c } } -void test_exhaustive_recovery_verify(const rustsecp256k1zkp_v0_8_0_context *ctx, const rustsecp256k1zkp_v0_8_0_ge *group) { +static void test_exhaustive_recovery_verify(const rustsecp256k1_v0_11_context *ctx, const rustsecp256k1_v0_11_ge *group) { /* This is essentially a copy of test_exhaustive_verify, with recovery added */ int s, r, msg, key; uint64_t iter = 0; @@ -87,41 +86,41 @@ void test_exhaustive_recovery_verify(const rustsecp256k1zkp_v0_8_0_context *ctx, for (r = 1; r < EXHAUSTIVE_TEST_ORDER; r++) { for (msg = 1; msg < EXHAUSTIVE_TEST_ORDER; msg++) { for (key = 1; key < EXHAUSTIVE_TEST_ORDER; key++) { - rustsecp256k1zkp_v0_8_0_ge nonconst_ge; - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature rsig; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig; - rustsecp256k1zkp_v0_8_0_pubkey pk; - rustsecp256k1zkp_v0_8_0_scalar sk_s, msg_s, r_s, s_s; - rustsecp256k1zkp_v0_8_0_scalar s_times_k_s, msg_plus_r_times_sk_s; + rustsecp256k1_v0_11_ge nonconst_ge; + rustsecp256k1_v0_11_ecdsa_recoverable_signature rsig; + rustsecp256k1_v0_11_ecdsa_signature sig; + rustsecp256k1_v0_11_pubkey pk; + rustsecp256k1_v0_11_scalar sk_s, msg_s, r_s, s_s; + rustsecp256k1_v0_11_scalar s_times_k_s, msg_plus_r_times_sk_s; int recid = 0; int k, should_verify; unsigned char msg32[32]; if (skip_section(&iter)) continue; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&s_s, s); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&r_s, r); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&msg_s, msg); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&sk_s, key); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(msg32, &msg_s); + rustsecp256k1_v0_11_scalar_set_int(&s_s, s); + rustsecp256k1_v0_11_scalar_set_int(&r_s, r); + rustsecp256k1_v0_11_scalar_set_int(&msg_s, msg); + rustsecp256k1_v0_11_scalar_set_int(&sk_s, key); + rustsecp256k1_v0_11_scalar_get_b32(msg32, &msg_s); /* Verify by hand */ /* Run through every k value that gives us this r and check that *one* works. * Note there could be none, there could be multiple, ECDSA is weird. */ should_verify = 0; for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { - rustsecp256k1zkp_v0_8_0_scalar check_x_s; + rustsecp256k1_v0_11_scalar check_x_s; r_from_k(&check_x_s, group, k, NULL); if (r_s == check_x_s) { - rustsecp256k1zkp_v0_8_0_scalar_set_int(&s_times_k_s, k); - rustsecp256k1zkp_v0_8_0_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); - rustsecp256k1zkp_v0_8_0_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); - rustsecp256k1zkp_v0_8_0_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); - should_verify |= rustsecp256k1zkp_v0_8_0_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); + rustsecp256k1_v0_11_scalar_set_int(&s_times_k_s, k); + rustsecp256k1_v0_11_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); + rustsecp256k1_v0_11_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); + rustsecp256k1_v0_11_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); + should_verify |= rustsecp256k1_v0_11_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); } } /* nb we have a "high s" rule */ - should_verify &= !rustsecp256k1zkp_v0_8_0_scalar_is_high(&s_s); + should_verify &= !rustsecp256k1_v0_11_scalar_is_high(&s_s); /* We would like to try recovering the pubkey and checking that it matches, * but pubkey recovery is impossible in the exhaustive tests (the reason @@ -129,19 +128,19 @@ void test_exhaustive_recovery_verify(const rustsecp256k1zkp_v0_8_0_context *ctx, * overlap between the sets, so there are no valid signatures). */ /* Verify by converting to a standard signature and calling verify */ - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid); - rustsecp256k1zkp_v0_8_0_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + rustsecp256k1_v0_11_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid); + rustsecp256k1_v0_11_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); - rustsecp256k1zkp_v0_8_0_pubkey_save(&pk, &nonconst_ge); + rustsecp256k1_v0_11_pubkey_save(&pk, &nonconst_ge); CHECK(should_verify == - rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg32, &pk)); + rustsecp256k1_v0_11_ecdsa_verify(ctx, &sig, msg32, &pk)); } } } } } -static void test_exhaustive_recovery(const rustsecp256k1zkp_v0_8_0_context *ctx, const rustsecp256k1zkp_v0_8_0_ge *group) { +static void test_exhaustive_recovery(const rustsecp256k1_v0_11_context *ctx, const rustsecp256k1_v0_11_ge *group) { test_exhaustive_recovery_sign(ctx, group); test_exhaustive_recovery_verify(ctx, group); } diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/tests_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/tests_impl.h new file mode 100644 index 00000000..96a2a1cc --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/recovery/tests_impl.h @@ -0,0 +1,338 @@ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H +#define SECP256K1_MODULE_RECOVERY_TESTS_H + +static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + (void) msg32; + (void) key32; + (void) algo16; + (void) data; + + /* On the first run, return 0 to force a second run */ + if (counter == 0) { + memset(nonce32, 0, 32); + return 1; + } + /* On the second run, return an overflow to force a third run */ + if (counter == 1) { + memset(nonce32, 0xff, 32); + return 1; + } + /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */ + memset(nonce32, 1, 32); + return testrand_bits(1); +} + +static void test_ecdsa_recovery_api(void) { + /* Setup contexts that just count errors */ + rustsecp256k1_v0_11_pubkey pubkey; + rustsecp256k1_v0_11_pubkey recpubkey; + rustsecp256k1_v0_11_ecdsa_signature normal_sig; + rustsecp256k1_v0_11_ecdsa_recoverable_signature recsig; + unsigned char privkey[32] = { 1 }; + unsigned char message[32] = { 2 }; + int recid = 0; + unsigned char sig[74]; + unsigned char zero_privkey[32] = { 0 }; + unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + /* Construct and verify corresponding public key. */ + CHECK(rustsecp256k1_v0_11_ec_seckey_verify(CTX, privkey) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey, privkey) == 1); + + /* Check bad contexts and NULLs for signing */ + CHECK(rustsecp256k1_v0_11_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_sign_recoverable(CTX, NULL, message, privkey, NULL, NULL)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_sign_recoverable(CTX, &recsig, NULL, privkey, NULL, NULL)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_sign_recoverable(CTX, &recsig, message, NULL, NULL, NULL)); + CHECK_ILLEGAL(STATIC_CTX, rustsecp256k1_v0_11_ecdsa_sign_recoverable(STATIC_CTX, &recsig, message, privkey, NULL, NULL)); + /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */ + rustsecp256k1_v0_11_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, recovery_test_nonce_function, NULL); + /* These will all fail, but not in ARG_CHECK way */ + CHECK(rustsecp256k1_v0_11_ecdsa_sign_recoverable(CTX, &recsig, message, zero_privkey, NULL, NULL) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_sign_recoverable(CTX, &recsig, message, over_privkey, NULL, NULL) == 0); + /* This one will succeed. */ + CHECK(rustsecp256k1_v0_11_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); + + /* Check signing with a goofy nonce function */ + + /* Check bad contexts and NULLs for recovery */ + CHECK(rustsecp256k1_v0_11_ecdsa_recover(CTX, &recpubkey, &recsig, message) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_recover(CTX, NULL, &recsig, message)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_recover(CTX, &recpubkey, NULL, message)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_recover(CTX, &recpubkey, &recsig, NULL)); + + /* Check NULLs for conversion */ + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &normal_sig, message, privkey, NULL, NULL) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_recoverable_signature_convert(CTX, NULL, &recsig)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_recoverable_signature_convert(CTX, &normal_sig, NULL)); + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_convert(CTX, &normal_sig, &recsig) == 1); + + /* Check NULLs for de/serialization */ + CHECK(rustsecp256k1_v0_11_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_recoverable_signature_serialize_compact(CTX, NULL, &recid, &recsig)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_recoverable_signature_serialize_compact(CTX, sig, NULL, &recsig)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, NULL)); + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &recsig) == 1); + + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, NULL, sig, recid)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, NULL, recid)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, -1)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, 5)); + /* overflow in signature will not result in calling illegal_callback */ + memcpy(sig, over_privkey, 32); + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, recid) == 0); +} + +static void test_ecdsa_recovery_end_to_end(void) { + unsigned char extra[32] = {0x00}; + unsigned char privkey[32]; + unsigned char message[32]; + rustsecp256k1_v0_11_ecdsa_signature signature[5]; + rustsecp256k1_v0_11_ecdsa_recoverable_signature rsignature[5]; + unsigned char sig[74]; + rustsecp256k1_v0_11_pubkey pubkey; + rustsecp256k1_v0_11_pubkey recpubkey; + int recid = 0; + + /* Generate a random key and message. */ + { + rustsecp256k1_v0_11_scalar msg, key; + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); + rustsecp256k1_v0_11_scalar_get_b32(privkey, &key); + rustsecp256k1_v0_11_scalar_get_b32(message, &msg); + } + + /* Construct and verify corresponding public key. */ + CHECK(rustsecp256k1_v0_11_ec_seckey_verify(CTX, privkey) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey, privkey) == 1); + + /* Serialize/parse compact and verify/recover. */ + extra[0] = 0; + CHECK(rustsecp256k1_v0_11_ecdsa_sign_recoverable(CTX, &rsignature[0], message, privkey, NULL, NULL) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sign_recoverable(CTX, &rsignature[4], message, privkey, NULL, NULL) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sign_recoverable(CTX, &rsignature[1], message, privkey, NULL, extra) == 1); + extra[31] = 1; + CHECK(rustsecp256k1_v0_11_ecdsa_sign_recoverable(CTX, &rsignature[2], message, privkey, NULL, extra) == 1); + extra[31] = 0; + extra[0] = 1; + CHECK(rustsecp256k1_v0_11_ecdsa_sign_recoverable(CTX, &rsignature[3], message, privkey, NULL, extra) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&signature[4], &signature[0], 64) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 1); + memset(&rsignature[4], 0, sizeof(rsignature[4])); + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 1); + /* Parse compact (with recovery id) and recover. */ + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_recover(CTX, &recpubkey, &rsignature[4], message) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) == 0); + /* Serialize/destroy/parse signature and verify again. */ + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1); + sig[testrand_bits(6)] += 1 + testrand_int(255); + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 0); + /* Recover again */ + CHECK(rustsecp256k1_v0_11_ecdsa_recover(CTX, &recpubkey, &rsignature[4], message) == 0 || + rustsecp256k1_v0_11_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) != 0); +} + +/* Tests several edge cases. */ +static void test_ecdsa_recovery_edge_cases(void) { + const unsigned char msg32[32] = { + 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', + 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', + 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', + 's', 's', 'a', 'g', 'e', '.', '.', '.' + }; + const unsigned char sig64[64] = { + /* Generated by signing the above message with nonce 'This is the nonce we will use...' + * and secret key 0 (which is not valid), resulting in recid 1. */ + 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, + 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, + 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, + 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, + 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, + 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, + 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, + 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 + }; + rustsecp256k1_v0_11_pubkey pubkey; + /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ + const unsigned char sigb64[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + rustsecp256k1_v0_11_pubkey pubkeyb; + rustsecp256k1_v0_11_ecdsa_recoverable_signature rsig; + rustsecp256k1_v0_11_ecdsa_signature sig; + int recid; + + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 0)); + CHECK(!rustsecp256k1_v0_11_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 1)); + CHECK(rustsecp256k1_v0_11_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 2)); + CHECK(!rustsecp256k1_v0_11_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 3)); + CHECK(!rustsecp256k1_v0_11_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); + + for (recid = 0; recid < 4; recid++) { + int i; + int recid2; + /* (4,4) encoded in DER. */ + unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; + unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01}; + unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00}; + unsigned char sigbderalt1[39] = { + 0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt2[39] = { + 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + unsigned char sigbderalt3[40] = { + 0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt4[40] = { + 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + /* (order + r,4) encoded in DER. */ + unsigned char sigbderlong[40] = { + 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, + 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, + 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 + }; + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigb64, recid) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 1); + for (recid2 = 0; recid2 < 4; recid2++) { + rustsecp256k1_v0_11_pubkey pubkey2b; + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigb64, recid2) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_recover(CTX, &pubkey2b, &rsig, msg32) == 1); + /* Verifying with (order + r,4) should always fail. */ + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigbderlong, sizeof(sigbderlong)) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); + } + /* DER parsing tests. */ + /* Zero length r/s. */ + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); + /* Leading zeros. */ + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); + sigbderalt3[4] = 1; + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); + sigbderalt4[7] = 1; + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); + /* Damage signature. */ + sigbder[7]++; + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); + sigbder[7]--; + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigbder, 6) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder) - 1) == 0); + for(i = 0; i < 8; i++) { + int c; + unsigned char orig = sigbder[i]; + /*Try every single-byte change.*/ + for (c = 0; c < 256; c++) { + if (c == orig ) { + continue; + } + sigbder[i] = c; + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 0 || rustsecp256k1_v0_11_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); + } + sigbder[i] = orig; + } + } + + /* Test r/s equal to zero */ + { + /* (1,1) encoded in DER. */ + unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; + unsigned char sigc64[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }; + rustsecp256k1_v0_11_pubkey pubkeyc; + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_recover(CTX, &pubkeyc, &rsig, msg32) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 1); + sigcder[4] = 0; + sigc64[31] = 0; + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 0); + sigcder[4] = 1; + sigcder[7] = 0; + sigc64[31] = 1; + sigc64[63] = 0; + CHECK(rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 0); + } +} + +static void run_recovery_tests(void) { + int i; + for (i = 0; i < COUNT; i++) { + test_ecdsa_recovery_api(); + } + for (i = 0; i < 64*COUNT; i++) { + test_ecdsa_recovery_end_to_end(); + } + test_ecdsa_recovery_edge_cases(); +} + +#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/Makefile.am.include b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/Makefile.am.include similarity index 77% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/Makefile.am.include rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/Makefile.am.include index 300a8ecf..829ccdf6 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/Makefile.am.include +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/Makefile.am.include @@ -1,4 +1,4 @@ -include_HEADERS += include/rustsecp256k1zkp_v0_8_0_schnorrsig.h +include_HEADERS += include/rustsecp256k1_v0_11_schnorrsig.h noinst_HEADERS += src/modules/schnorrsig/main_impl.h noinst_HEADERS += src/modules/schnorrsig/tests_impl.h noinst_HEADERS += src/modules/schnorrsig/tests_exhaustive_impl.h diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/bench_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/bench_impl.h similarity index 62% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/bench_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/bench_impl.h index 47f83df6..f37e24bc 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/bench_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/bench_impl.h @@ -12,16 +12,16 @@ #define MSGLEN 32 typedef struct { - rustsecp256k1zkp_v0_8_0_context *ctx; + rustsecp256k1_v0_11_context *ctx; int n; - const rustsecp256k1zkp_v0_8_0_keypair **keypairs; + const rustsecp256k1_v0_11_keypair **keypairs; const unsigned char **pk; const unsigned char **sigs; const unsigned char **msgs; } bench_schnorrsig_data; -void bench_schnorrsig_sign(void* arg, int iters) { +static void bench_schnorrsig_sign(void* arg, int iters) { bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; int i; unsigned char msg[MSGLEN] = {0}; @@ -30,28 +30,28 @@ void bench_schnorrsig_sign(void* arg, int iters) { for (i = 0; i < iters; i++) { msg[0] = i; msg[1] = i >> 8; - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(data->ctx, sig, msg, MSGLEN, data->keypairs[i], NULL)); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign_custom(data->ctx, sig, msg, MSGLEN, data->keypairs[i], NULL)); } } -void bench_schnorrsig_verify(void* arg, int iters) { +static void bench_schnorrsig_verify(void* arg, int iters) { bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; int i; for (i = 0; i < iters; i++) { - rustsecp256k1zkp_v0_8_0_xonly_pubkey pk; - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(data->ctx, &pk, data->pk[i]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], MSGLEN, &pk)); + rustsecp256k1_v0_11_xonly_pubkey pk; + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(data->ctx, &pk, data->pk[i]) == 1); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], MSGLEN, &pk)); } } -void run_schnorrsig_bench(int iters, int argc, char** argv) { +static void run_schnorrsig_bench(int iters, int argc, char** argv) { int i; bench_schnorrsig_data data; int d = argc == 1; - data.ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); - data.keypairs = (const rustsecp256k1zkp_v0_8_0_keypair **)malloc(iters * sizeof(rustsecp256k1zkp_v0_8_0_keypair *)); + data.ctx = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); + data.keypairs = (const rustsecp256k1_v0_11_keypair **)malloc(iters * sizeof(rustsecp256k1_v0_11_keypair *)); data.pk = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); data.msgs = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); data.sigs = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); @@ -61,9 +61,9 @@ void run_schnorrsig_bench(int iters, int argc, char** argv) { unsigned char sk[32]; unsigned char *msg = (unsigned char *)malloc(MSGLEN); unsigned char *sig = (unsigned char *)malloc(64); - rustsecp256k1zkp_v0_8_0_keypair *keypair = (rustsecp256k1zkp_v0_8_0_keypair *)malloc(sizeof(*keypair)); + rustsecp256k1_v0_11_keypair *keypair = (rustsecp256k1_v0_11_keypair *)malloc(sizeof(*keypair)); unsigned char *pk_char = (unsigned char *)malloc(32); - rustsecp256k1zkp_v0_8_0_xonly_pubkey pk; + rustsecp256k1_v0_11_xonly_pubkey pk; msg[0] = sk[0] = i; msg[1] = sk[1] = i >> 8; msg[2] = sk[2] = i >> 16; @@ -76,10 +76,10 @@ void run_schnorrsig_bench(int iters, int argc, char** argv) { data.msgs[i] = msg; data.sigs[i] = sig; - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(data.ctx, keypair, sk)); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(data.ctx, sig, msg, MSGLEN, keypair, NULL)); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(data.ctx, &pk, NULL, keypair)); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(data.ctx, pk_char, &pk) == 1); + CHECK(rustsecp256k1_v0_11_keypair_create(data.ctx, keypair, sk)); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign_custom(data.ctx, sig, msg, MSGLEN, keypair, NULL)); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(data.ctx, &pk, NULL, keypair)); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(data.ctx, pk_char, &pk) == 1); } if (d || have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "schnorrsig_sign")) run_benchmark("schnorrsig_sign", bench_schnorrsig_sign, NULL, NULL, (void *) &data, 10, iters); @@ -91,12 +91,14 @@ void run_schnorrsig_bench(int iters, int argc, char** argv) { free((void *)data.msgs[i]); free((void *)data.sigs[i]); } - free(data.keypairs); - free(data.pk); - free(data.msgs); - free(data.sigs); - rustsecp256k1zkp_v0_8_0_context_destroy(data.ctx); + /* Casting to (void *) avoids a stupid warning in MSVC. */ + free((void *)data.keypairs); + free((void *)data.pk); + free((void *)data.msgs); + free((void *)data.sigs); + + rustsecp256k1_v0_11_context_destroy(data.ctx); } #endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/main_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/main_impl.h new file mode 100644 index 00000000..0fee9b54 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/main_impl.h @@ -0,0 +1,269 @@ +/*********************************************************************** + * Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORRSIG_MAIN_H +#define SECP256K1_MODULE_SCHNORRSIG_MAIN_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_schnorrsig.h" +#include "../../hash.h" + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("BIP0340/nonce")||SHA256("BIP0340/nonce"). */ +static void rustsecp256k1_v0_11_nonce_function_bip340_sha256_tagged(rustsecp256k1_v0_11_sha256 *sha) { + rustsecp256k1_v0_11_sha256_initialize(sha); + sha->s[0] = 0x46615b35ul; + sha->s[1] = 0xf4bfbff7ul; + sha->s[2] = 0x9f8dc671ul; + sha->s[3] = 0x83627ab3ul; + sha->s[4] = 0x60217180ul; + sha->s[5] = 0x57358661ul; + sha->s[6] = 0x21a29e54ul; + sha->s[7] = 0x68b07b4cul; + + sha->bytes = 64; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("BIP0340/aux")||SHA256("BIP0340/aux"). */ +static void rustsecp256k1_v0_11_nonce_function_bip340_sha256_tagged_aux(rustsecp256k1_v0_11_sha256 *sha) { + rustsecp256k1_v0_11_sha256_initialize(sha); + sha->s[0] = 0x24dd3219ul; + sha->s[1] = 0x4eba7e70ul; + sha->s[2] = 0xca0fabb9ul; + sha->s[3] = 0x0fa3166dul; + sha->s[4] = 0x3afbe4b1ul; + sha->s[5] = 0x4c44df97ul; + sha->s[6] = 0x4aac2739ul; + sha->s[7] = 0x249e850aul; + + sha->bytes = 64; +} + +/* algo argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340 + * by using the correct tagged hash function. */ +static const unsigned char bip340_algo[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; + +static const unsigned char schnorrsig_extraparams_magic[4] = SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC; + +static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { + rustsecp256k1_v0_11_sha256 sha; + unsigned char masked_key[32]; + int i; + + if (algo == NULL) { + return 0; + } + + if (data != NULL) { + rustsecp256k1_v0_11_nonce_function_bip340_sha256_tagged_aux(&sha); + rustsecp256k1_v0_11_sha256_write(&sha, data, 32); + rustsecp256k1_v0_11_sha256_finalize(&sha, masked_key); + for (i = 0; i < 32; i++) { + masked_key[i] ^= key32[i]; + } + } else { + /* Precomputed TaggedHash("BIP0340/aux", 0x0000...00); */ + static const unsigned char ZERO_MASK[32] = { + 84, 241, 105, 207, 201, 226, 229, 114, + 116, 128, 68, 31, 144, 186, 37, 196, + 136, 244, 97, 199, 11, 94, 165, 220, + 170, 247, 175, 105, 39, 10, 165, 20 + }; + for (i = 0; i < 32; i++) { + masked_key[i] = key32[i] ^ ZERO_MASK[i]; + } + } + + /* Tag the hash with algo which is important to avoid nonce reuse across + * algorithms. If this nonce function is used in BIP-340 signing as defined + * in the spec, an optimized tagging implementation is used. */ + if (algolen == sizeof(bip340_algo) + && rustsecp256k1_v0_11_memcmp_var(algo, bip340_algo, algolen) == 0) { + rustsecp256k1_v0_11_nonce_function_bip340_sha256_tagged(&sha); + } else { + rustsecp256k1_v0_11_sha256_initialize_tagged(&sha, algo, algolen); + } + + /* Hash masked-key||pk||msg using the tagged hash as per the spec */ + rustsecp256k1_v0_11_sha256_write(&sha, masked_key, 32); + rustsecp256k1_v0_11_sha256_write(&sha, xonly_pk32, 32); + rustsecp256k1_v0_11_sha256_write(&sha, msg, msglen); + rustsecp256k1_v0_11_sha256_finalize(&sha, nonce32); + rustsecp256k1_v0_11_sha256_clear(&sha); + return 1; +} + +const rustsecp256k1_v0_11_nonce_function_hardened rustsecp256k1_v0_11_nonce_function_bip340 = nonce_function_bip340; + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("BIP0340/challenge")||SHA256("BIP0340/challenge"). */ +static void rustsecp256k1_v0_11_schnorrsig_sha256_tagged(rustsecp256k1_v0_11_sha256 *sha) { + rustsecp256k1_v0_11_sha256_initialize(sha); + sha->s[0] = 0x9cecba11ul; + sha->s[1] = 0x23925381ul; + sha->s[2] = 0x11679112ul; + sha->s[3] = 0xd1627e0ful; + sha->s[4] = 0x97c87550ul; + sha->s[5] = 0x003cc765ul; + sha->s[6] = 0x90f61164ul; + sha->s[7] = 0x33e9b66aul; + sha->bytes = 64; +} + +static void rustsecp256k1_v0_11_schnorrsig_challenge(rustsecp256k1_v0_11_scalar* e, const unsigned char *r32, const unsigned char *msg, size_t msglen, const unsigned char *pubkey32) +{ + unsigned char buf[32]; + rustsecp256k1_v0_11_sha256 sha; + + /* tagged hash(r.x, pk.x, msg) */ + rustsecp256k1_v0_11_schnorrsig_sha256_tagged(&sha); + rustsecp256k1_v0_11_sha256_write(&sha, r32, 32); + rustsecp256k1_v0_11_sha256_write(&sha, pubkey32, 32); + rustsecp256k1_v0_11_sha256_write(&sha, msg, msglen); + rustsecp256k1_v0_11_sha256_finalize(&sha, buf); + /* Set scalar e to the challenge hash modulo the curve order as per + * BIP340. */ + rustsecp256k1_v0_11_scalar_set_b32(e, buf, NULL); +} + +static int rustsecp256k1_v0_11_schnorrsig_sign_internal(const rustsecp256k1_v0_11_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const rustsecp256k1_v0_11_keypair *keypair, rustsecp256k1_v0_11_nonce_function_hardened noncefp, void *ndata) { + rustsecp256k1_v0_11_scalar sk; + rustsecp256k1_v0_11_scalar e; + rustsecp256k1_v0_11_scalar k; + rustsecp256k1_v0_11_gej rj; + rustsecp256k1_v0_11_ge pk; + rustsecp256k1_v0_11_ge r; + unsigned char buf[32] = { 0 }; + unsigned char pk_buf[32]; + unsigned char seckey[32]; + int ret = 1; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(rustsecp256k1_v0_11_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(msg != NULL || msglen == 0); + ARG_CHECK(keypair != NULL); + + if (noncefp == NULL) { + noncefp = rustsecp256k1_v0_11_nonce_function_bip340; + } + + ret &= rustsecp256k1_v0_11_keypair_load(ctx, &sk, &pk, keypair); + /* Because we are signing for a x-only pubkey, the secret key is negated + * before signing if the point corresponding to the secret key does not + * have an even Y. */ + if (rustsecp256k1_v0_11_fe_is_odd(&pk.y)) { + rustsecp256k1_v0_11_scalar_negate(&sk, &sk); + } + + rustsecp256k1_v0_11_scalar_get_b32(seckey, &sk); + rustsecp256k1_v0_11_fe_get_b32(pk_buf, &pk.x); + ret &= !!noncefp(buf, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata); + rustsecp256k1_v0_11_scalar_set_b32(&k, buf, NULL); + ret &= !rustsecp256k1_v0_11_scalar_is_zero(&k); + rustsecp256k1_v0_11_scalar_cmov(&k, &rustsecp256k1_v0_11_scalar_one, !ret); + + rustsecp256k1_v0_11_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k); + rustsecp256k1_v0_11_ge_set_gej(&r, &rj); + + /* We declassify r to allow using it as a branch point. This is fine + * because r is not a secret. */ + rustsecp256k1_v0_11_declassify(ctx, &r, sizeof(r)); + rustsecp256k1_v0_11_fe_normalize_var(&r.y); + if (rustsecp256k1_v0_11_fe_is_odd(&r.y)) { + rustsecp256k1_v0_11_scalar_negate(&k, &k); + } + rustsecp256k1_v0_11_fe_normalize_var(&r.x); + rustsecp256k1_v0_11_fe_get_b32(&sig64[0], &r.x); + + rustsecp256k1_v0_11_schnorrsig_challenge(&e, &sig64[0], msg, msglen, pk_buf); + rustsecp256k1_v0_11_scalar_mul(&e, &e, &sk); + rustsecp256k1_v0_11_scalar_add(&e, &e, &k); + rustsecp256k1_v0_11_scalar_get_b32(&sig64[32], &e); + + rustsecp256k1_v0_11_memczero(sig64, 64, !ret); + rustsecp256k1_v0_11_scalar_clear(&k); + rustsecp256k1_v0_11_scalar_clear(&sk); + rustsecp256k1_v0_11_memclear(seckey, sizeof(seckey)); + rustsecp256k1_v0_11_gej_clear(&rj); + + return ret; +} + +int rustsecp256k1_v0_11_schnorrsig_sign32(const rustsecp256k1_v0_11_context* ctx, unsigned char *sig64, const unsigned char *msg32, const rustsecp256k1_v0_11_keypair *keypair, const unsigned char *aux_rand32) { + /* We cast away const from the passed aux_rand32 argument since we know the default nonce function does not modify it. */ + return rustsecp256k1_v0_11_schnorrsig_sign_internal(ctx, sig64, msg32, 32, keypair, rustsecp256k1_v0_11_nonce_function_bip340, (unsigned char*)aux_rand32); +} + +int rustsecp256k1_v0_11_schnorrsig_sign(const rustsecp256k1_v0_11_context* ctx, unsigned char *sig64, const unsigned char *msg32, const rustsecp256k1_v0_11_keypair *keypair, const unsigned char *aux_rand32) { + return rustsecp256k1_v0_11_schnorrsig_sign32(ctx, sig64, msg32, keypair, aux_rand32); +} + +int rustsecp256k1_v0_11_schnorrsig_sign_custom(const rustsecp256k1_v0_11_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const rustsecp256k1_v0_11_keypair *keypair, rustsecp256k1_v0_11_schnorrsig_extraparams *extraparams) { + rustsecp256k1_v0_11_nonce_function_hardened noncefp = NULL; + void *ndata = NULL; + VERIFY_CHECK(ctx != NULL); + + if (extraparams != NULL) { + ARG_CHECK(rustsecp256k1_v0_11_memcmp_var(extraparams->magic, + schnorrsig_extraparams_magic, + sizeof(extraparams->magic)) == 0); + noncefp = extraparams->noncefp; + ndata = extraparams->ndata; + } + return rustsecp256k1_v0_11_schnorrsig_sign_internal(ctx, sig64, msg, msglen, keypair, noncefp, ndata); +} + +int rustsecp256k1_v0_11_schnorrsig_verify(const rustsecp256k1_v0_11_context* ctx, const unsigned char *sig64, const unsigned char *msg, size_t msglen, const rustsecp256k1_v0_11_xonly_pubkey *pubkey) { + rustsecp256k1_v0_11_scalar s; + rustsecp256k1_v0_11_scalar e; + rustsecp256k1_v0_11_gej rj; + rustsecp256k1_v0_11_ge pk; + rustsecp256k1_v0_11_gej pkj; + rustsecp256k1_v0_11_fe rx; + rustsecp256k1_v0_11_ge r; + unsigned char buf[32]; + int overflow; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(msg != NULL || msglen == 0); + ARG_CHECK(pubkey != NULL); + + if (!rustsecp256k1_v0_11_fe_set_b32_limit(&rx, &sig64[0])) { + return 0; + } + + rustsecp256k1_v0_11_scalar_set_b32(&s, &sig64[32], &overflow); + if (overflow) { + return 0; + } + + if (!rustsecp256k1_v0_11_xonly_pubkey_load(ctx, &pk, pubkey)) { + return 0; + } + + /* Compute e. */ + rustsecp256k1_v0_11_fe_get_b32(buf, &pk.x); + rustsecp256k1_v0_11_schnorrsig_challenge(&e, &sig64[0], msg, msglen, buf); + + /* Compute rj = s*G + (-e)*pkj */ + rustsecp256k1_v0_11_scalar_negate(&e, &e); + rustsecp256k1_v0_11_gej_set_ge(&pkj, &pk); + rustsecp256k1_v0_11_ecmult(&rj, &pkj, &e, &s); + + rustsecp256k1_v0_11_ge_set_gej_var(&r, &rj); + if (rustsecp256k1_v0_11_ge_is_infinity(&r)) { + return 0; + } + + rustsecp256k1_v0_11_fe_normalize_var(&r.y); + return !rustsecp256k1_v0_11_fe_is_odd(&r.y) && + rustsecp256k1_v0_11_fe_equal(&rx, &r.x); +} + +#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h similarity index 69% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h index 24cf19e6..b8a4a90e 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h @@ -8,7 +8,7 @@ #define SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H #include "../../../include/secp256k1_schnorrsig.h" -#include "src/modules/schnorrsig/main_impl.h" +#include "main_impl.h" static const unsigned char invalid_pubkey_bytes[][32] = { /* 0 */ @@ -58,12 +58,12 @@ static const unsigned char invalid_pubkey_bytes[][32] = { #define NUM_INVALID_KEYS (sizeof(invalid_pubkey_bytes) / sizeof(invalid_pubkey_bytes[0])) -static int rustsecp256k1zkp_v0_8_0_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg, +static int rustsecp256k1_v0_11_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void* data) { - rustsecp256k1zkp_v0_8_0_scalar s; + rustsecp256k1_v0_11_scalar s; int *idata = data; (void)msg; (void)msglen; @@ -71,12 +71,12 @@ static int rustsecp256k1zkp_v0_8_0_hardened_nonce_function_smallint(unsigned cha (void)xonly_pk32; (void)algo; (void)algolen; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&s, *idata); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(nonce32, &s); + rustsecp256k1_v0_11_scalar_set_int(&s, *idata); + rustsecp256k1_v0_11_scalar_get_b32(nonce32, &s); return 1; } -static void test_exhaustive_schnorrsig_verify(const rustsecp256k1zkp_v0_8_0_context *ctx, const rustsecp256k1zkp_v0_8_0_xonly_pubkey* pubkeys, unsigned char (*xonly_pubkey_bytes)[32], const int* parities) { +static void test_exhaustive_schnorrsig_verify(const rustsecp256k1_v0_11_context *ctx, const rustsecp256k1_v0_11_xonly_pubkey* pubkeys, unsigned char (*xonly_pubkey_bytes)[32], const int* parities) { int d; uint64_t iter = 0; /* Iterate over the possible public keys to verify against (through their corresponding DL d). */ @@ -102,28 +102,28 @@ static void test_exhaustive_schnorrsig_verify(const rustsecp256k1zkp_v0_8_0_cont } /* Randomly generate messages until all challenges have been hit. */ while (e_count_done < EXHAUSTIVE_TEST_ORDER) { - rustsecp256k1zkp_v0_8_0_scalar e; + rustsecp256k1_v0_11_scalar e; unsigned char msg32[32]; - rustsecp256k1zkp_v0_8_0_testrand256(msg32); - rustsecp256k1zkp_v0_8_0_schnorrsig_challenge(&e, sig64, msg32, sizeof(msg32), pk32); + testrand256(msg32); + rustsecp256k1_v0_11_schnorrsig_challenge(&e, sig64, msg32, sizeof(msg32), pk32); /* Only do work if we hit a challenge we haven't tried before. */ if (!e_done[e]) { /* Iterate over the possible valid last 32 bytes in the signature. 0..order=that s value; order+1=random bytes */ - int count_valid = 0, s; + int count_valid = 0; + unsigned int s; for (s = 0; s <= EXHAUSTIVE_TEST_ORDER + 1; ++s) { int expect_valid, valid; if (s <= EXHAUSTIVE_TEST_ORDER) { - rustsecp256k1zkp_v0_8_0_scalar s_s; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&s_s, s); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(sig64 + 32, &s_s); + memset(sig64 + 32, 0, 32); + rustsecp256k1_v0_11_write_be32(sig64 + 60, s); expect_valid = actual_k != -1 && s != EXHAUSTIVE_TEST_ORDER && - (s_s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER); + (s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER); } else { - rustsecp256k1zkp_v0_8_0_testrand256(sig64 + 32); + testrand256(sig64 + 32); expect_valid = 0; } - valid = rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig64, msg32, sizeof(msg32), &pubkeys[d - 1]); + valid = rustsecp256k1_v0_11_schnorrsig_verify(ctx, sig64, msg32, sizeof(msg32), &pubkeys[d - 1]); CHECK(valid == expect_valid); count_valid += valid; } @@ -138,10 +138,10 @@ static void test_exhaustive_schnorrsig_verify(const rustsecp256k1zkp_v0_8_0_cont } } -static void test_exhaustive_schnorrsig_sign(const rustsecp256k1zkp_v0_8_0_context *ctx, unsigned char (*xonly_pubkey_bytes)[32], const rustsecp256k1zkp_v0_8_0_keypair* keypairs, const int* parities) { +static void test_exhaustive_schnorrsig_sign(const rustsecp256k1_v0_11_context *ctx, unsigned char (*xonly_pubkey_bytes)[32], const rustsecp256k1_v0_11_keypair* keypairs, const int* parities) { int d, k; uint64_t iter = 0; - rustsecp256k1zkp_v0_8_0_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + rustsecp256k1_v0_11_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; /* Loop over keys. */ for (d = 1; d < EXHAUSTIVE_TEST_ORDER; ++d) { @@ -155,25 +155,25 @@ static void test_exhaustive_schnorrsig_sign(const rustsecp256k1zkp_v0_8_0_contex unsigned char sig64[64]; int actual_k = k; if (skip_section(&iter)) continue; - extraparams.noncefp = rustsecp256k1zkp_v0_8_0_hardened_nonce_function_smallint; + extraparams.noncefp = rustsecp256k1_v0_11_hardened_nonce_function_smallint; extraparams.ndata = &k; if (parities[k - 1]) actual_k = EXHAUSTIVE_TEST_ORDER - k; /* Generate random messages until all challenges have been tried. */ while (e_count_done < EXHAUSTIVE_TEST_ORDER) { - rustsecp256k1zkp_v0_8_0_scalar e; - rustsecp256k1zkp_v0_8_0_testrand256(msg32); - rustsecp256k1zkp_v0_8_0_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, sizeof(msg32), xonly_pubkey_bytes[d - 1]); + rustsecp256k1_v0_11_scalar e; + testrand256(msg32); + rustsecp256k1_v0_11_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, sizeof(msg32), xonly_pubkey_bytes[d - 1]); /* Only do work if we hit a challenge we haven't tried before. */ if (!e_done[e]) { - rustsecp256k1zkp_v0_8_0_scalar expected_s = (actual_k + e * actual_d) % EXHAUSTIVE_TEST_ORDER; + rustsecp256k1_v0_11_scalar expected_s = (actual_k + e * actual_d) % EXHAUSTIVE_TEST_ORDER; unsigned char expected_s_bytes[32]; - rustsecp256k1zkp_v0_8_0_scalar_get_b32(expected_s_bytes, &expected_s); + rustsecp256k1_v0_11_scalar_get_b32(expected_s_bytes, &expected_s); /* Invoke the real function to construct a signature. */ - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(ctx, sig64, msg32, sizeof(msg32), &keypairs[d - 1], &extraparams)); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign_custom(ctx, sig64, msg32, sizeof(msg32), &keypairs[d - 1], &extraparams)); /* The first 32 bytes must match the xonly pubkey for the specified k. */ - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(sig64, xonly_pubkey_bytes[k - 1], 32) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(sig64, xonly_pubkey_bytes[k - 1], 32) == 0); /* The last 32 bytes must match the expected s value. */ - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(sig64 + 32, expected_s_bytes, 32) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(sig64 + 32, expected_s_bytes, 32) == 0); /* Don't retry other messages that result in the same challenge. */ e_done[e] = 1; ++e_count_done; @@ -183,28 +183,28 @@ static void test_exhaustive_schnorrsig_sign(const rustsecp256k1zkp_v0_8_0_contex } } -static void test_exhaustive_schnorrsig(const rustsecp256k1zkp_v0_8_0_context *ctx) { - rustsecp256k1zkp_v0_8_0_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1]; - rustsecp256k1zkp_v0_8_0_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1]; +static void test_exhaustive_schnorrsig(const rustsecp256k1_v0_11_context *ctx) { + rustsecp256k1_v0_11_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1]; + rustsecp256k1_v0_11_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1]; int parity[EXHAUSTIVE_TEST_ORDER - 1]; unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32]; unsigned i; /* Verify that all invalid_pubkey_bytes are actually invalid. */ for (i = 0; i < NUM_INVALID_KEYS; ++i) { - rustsecp256k1zkp_v0_8_0_xonly_pubkey pk; - CHECK(!rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(ctx, &pk, invalid_pubkey_bytes[i])); + rustsecp256k1_v0_11_xonly_pubkey pk; + CHECK(!rustsecp256k1_v0_11_xonly_pubkey_parse(ctx, &pk, invalid_pubkey_bytes[i])); } /* Construct keypairs and xonly-pubkeys for the entire group. */ for (i = 1; i < EXHAUSTIVE_TEST_ORDER; ++i) { - rustsecp256k1zkp_v0_8_0_scalar scalar_i; + rustsecp256k1_v0_11_scalar scalar_i; unsigned char buf[32]; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&scalar_i, i); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(buf, &scalar_i); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair[i - 1], buf)); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parity[i - 1], &keypair[i - 1])); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1])); + rustsecp256k1_v0_11_scalar_set_int(&scalar_i, i); + rustsecp256k1_v0_11_scalar_get_b32(buf, &scalar_i); + CHECK(rustsecp256k1_v0_11_keypair_create(ctx, &keypair[i - 1], buf)); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parity[i - 1], &keypair[i - 1])); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1])); } test_exhaustive_schnorrsig_sign(ctx, xonly_pubkey_bytes, keypair, parity); diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/tests_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/tests_impl.h similarity index 54% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/tests_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/tests_impl.h index 5c6a76de..ff40eff5 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/modules/schnorrsig/tests_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/modules/schnorrsig/tests_impl.h @@ -12,32 +12,21 @@ /* Checks that a bit flip in the n_flip-th argument (that has n_bytes many * bytes) changes the hash function */ -void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t msglen, size_t algolen) { +static void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t msglen, size_t algolen) { unsigned char nonces[2][32]; CHECK(nonce_function_bip340(nonces[0], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1); - rustsecp256k1zkp_v0_8_0_testrand_flip(args[n_flip], n_bytes); + testrand_flip(args[n_flip], n_bytes); CHECK(nonce_function_bip340(nonces[1], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(nonces[0], nonces[1], 32) != 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(nonces[0], nonces[1], 32) != 0); } -/* Tests for the equality of two sha256 structs. This function only produces a - * correct result if an integer multiple of 64 many bytes have been written - * into the hash functions. */ -void test_sha256_eq(const rustsecp256k1zkp_v0_8_0_sha256 *sha1, const rustsecp256k1zkp_v0_8_0_sha256 *sha2) { - /* Is buffer fully consumed? */ - CHECK((sha1->bytes & 0x3F) == 0); - - CHECK(sha1->bytes == sha2->bytes); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0); -} - -void run_nonce_function_bip340_tests(void) { - unsigned char tag[13] = "BIP0340/nonce"; - unsigned char aux_tag[11] = "BIP0340/aux"; - unsigned char algo[13] = "BIP0340/nonce"; +static void run_nonce_function_bip340_tests(void) { + unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; + unsigned char aux_tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'a', 'u', 'x'}; + unsigned char algo[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; size_t algolen = sizeof(algo); - rustsecp256k1zkp_v0_8_0_sha256 sha; - rustsecp256k1zkp_v0_8_0_sha256 sha_optimized; + rustsecp256k1_v0_11_sha256 sha; + rustsecp256k1_v0_11_sha256 sha_optimized; unsigned char nonce[32], nonce_z[32]; unsigned char msg[32]; size_t msglen = sizeof(msg); @@ -48,23 +37,23 @@ void run_nonce_function_bip340_tests(void) { int i; /* Check that hash initialized by - * rustsecp256k1zkp_v0_8_0_nonce_function_bip340_sha256_tagged has the expected + * rustsecp256k1_v0_11_nonce_function_bip340_sha256_tagged has the expected * state. */ - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, tag, sizeof(tag)); - rustsecp256k1zkp_v0_8_0_nonce_function_bip340_sha256_tagged(&sha_optimized); + rustsecp256k1_v0_11_sha256_initialize_tagged(&sha, tag, sizeof(tag)); + rustsecp256k1_v0_11_nonce_function_bip340_sha256_tagged(&sha_optimized); test_sha256_eq(&sha, &sha_optimized); /* Check that hash initialized by - * rustsecp256k1zkp_v0_8_0_nonce_function_bip340_sha256_tagged_aux has the expected + * rustsecp256k1_v0_11_nonce_function_bip340_sha256_tagged_aux has the expected * state. */ - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, aux_tag, sizeof(aux_tag)); - rustsecp256k1zkp_v0_8_0_nonce_function_bip340_sha256_tagged_aux(&sha_optimized); + rustsecp256k1_v0_11_sha256_initialize_tagged(&sha, aux_tag, sizeof(aux_tag)); + rustsecp256k1_v0_11_nonce_function_bip340_sha256_tagged_aux(&sha_optimized); test_sha256_eq(&sha, &sha_optimized); - rustsecp256k1zkp_v0_8_0_testrand256(msg); - rustsecp256k1zkp_v0_8_0_testrand256(key); - rustsecp256k1zkp_v0_8_0_testrand256(pk); - rustsecp256k1zkp_v0_8_0_testrand256(aux_rand); + testrand256(msg); + testrand256(key); + testrand256(pk); + testrand256(aux_rand); /* Check that a bitflip in an argument results in different nonces. */ args[0] = msg; @@ -72,7 +61,7 @@ void run_nonce_function_bip340_tests(void) { args[2] = pk; args[3] = algo; args[4] = aux_rand; - for (i = 0; i < count; i++) { + for (i = 0; i < COUNT; i++) { nonce_function_bip340_bitflip(args, 0, 32, msglen, algolen); nonce_function_bip340_bitflip(args, 1, 32, msglen, algolen); nonce_function_bip340_bitflip(args, 2, 32, msglen, algolen); @@ -87,187 +76,134 @@ void run_nonce_function_bip340_tests(void) { CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, NULL, 0, NULL) == 0); CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); /* Other algo is fine */ - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(algo, algolen); + testrand_bytes_test(algo, algolen); CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); - for (i = 0; i < count; i++) { + for (i = 0; i < COUNT; i++) { unsigned char nonce2[32]; - uint32_t offset = rustsecp256k1zkp_v0_8_0_testrand_int(msglen - 1); + uint32_t offset = testrand_int(msglen - 1); size_t msglen_tmp = (msglen + offset) % msglen; size_t algolen_tmp; /* Different msglen gives different nonce */ CHECK(nonce_function_bip340(nonce2, msg, msglen_tmp, key, pk, algo, algolen, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(nonce, nonce2, 32) != 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(nonce, nonce2, 32) != 0); /* Different algolen gives different nonce */ - offset = rustsecp256k1zkp_v0_8_0_testrand_int(algolen - 1); + offset = testrand_int(algolen - 1); algolen_tmp = (algolen + offset) % algolen; CHECK(nonce_function_bip340(nonce2, msg, msglen, key, pk, algo, algolen_tmp, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(nonce, nonce2, 32) != 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(nonce, nonce2, 32) != 0); } /* NULL aux_rand argument is allowed, and identical to passing all zero aux_rand. */ memset(aux_rand, 0, 32); CHECK(nonce_function_bip340(nonce_z, msg, msglen, key, pk, algo, algolen, &aux_rand) == 1); CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(nonce_z, nonce, 32) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(nonce_z, nonce, 32) == 0); } -void test_schnorrsig_api(void) { +static void test_schnorrsig_api(void) { unsigned char sk1[32]; unsigned char sk2[32]; unsigned char sk3[32]; unsigned char msg[32]; - rustsecp256k1zkp_v0_8_0_keypair keypairs[3]; - rustsecp256k1zkp_v0_8_0_keypair invalid_keypair = {{ 0 }}; - rustsecp256k1zkp_v0_8_0_xonly_pubkey pk[3]; - rustsecp256k1zkp_v0_8_0_xonly_pubkey zero_pk; + rustsecp256k1_v0_11_keypair keypairs[3]; + rustsecp256k1_v0_11_keypair invalid_keypair = {{ 0 }}; + rustsecp256k1_v0_11_xonly_pubkey pk[3]; + rustsecp256k1_v0_11_xonly_pubkey zero_pk; unsigned char sig[64]; - rustsecp256k1zkp_v0_8_0_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; - rustsecp256k1zkp_v0_8_0_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL}; - - /** setup **/ - rustsecp256k1zkp_v0_8_0_context *none = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); - rustsecp256k1zkp_v0_8_0_context *sign = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN); - rustsecp256k1zkp_v0_8_0_context *vrfy = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *both = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - rustsecp256k1zkp_v0_8_0_context *sttc = rustsecp256k1zkp_v0_8_0_context_clone(rustsecp256k1zkp_v0_8_0_context_no_precomp); - int ecount; - - rustsecp256k1zkp_v0_8_0_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); - - rustsecp256k1zkp_v0_8_0_testrand256(sk1); - rustsecp256k1zkp_v0_8_0_testrand256(sk2); - rustsecp256k1zkp_v0_8_0_testrand256(sk3); - rustsecp256k1zkp_v0_8_0_testrand256(msg); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypairs[0], sk1) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypairs[1], sk2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypairs[2], sk3) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(ctx, &pk[0], NULL, &keypairs[0]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(ctx, &pk[1], NULL, &keypairs[1]) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(ctx, &pk[2], NULL, &keypairs[2]) == 1); + rustsecp256k1_v0_11_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + rustsecp256k1_v0_11_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL}; + + testrand256(sk1); + testrand256(sk2); + testrand256(sk3); + testrand256(msg); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypairs[0], sk1) == 1); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypairs[1], sk2) == 1); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypairs[2], sk3) == 1); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &pk[0], NULL, &keypairs[0]) == 1); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &pk[1], NULL, &keypairs[1]) == 1); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &pk[2], NULL, &keypairs[2]) == 1); memset(&zero_pk, 0, sizeof(zero_pk)); /** main test body **/ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(none, sig, msg, &keypairs[0], NULL) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(vrfy, sig, msg, &keypairs[0], NULL) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(sign, sig, msg, &keypairs[0], NULL) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(sign, NULL, msg, &keypairs[0], NULL) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(sign, sig, NULL, &keypairs[0], NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(sign, sig, msg, NULL, NULL) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(sign, sig, msg, &invalid_keypair, NULL) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(sttc, sig, msg, &keypairs[0], NULL) == 0); - CHECK(ecount == 5); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(none, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(vrfy, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(sign, NULL, msg, sizeof(msg), &keypairs[0], &extraparams) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(sign, sig, NULL, sizeof(msg), &keypairs[0], &extraparams) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(sign, sig, NULL, 0, &keypairs[0], &extraparams) == 1); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), NULL, &extraparams) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &invalid_keypair, &extraparams) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(sttc, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 0); - CHECK(ecount == 6); - - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(sign, sig, msg, &keypairs[0], NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(none, sig, msg, sizeof(msg), &pk[0]) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(sign, sig, msg, sizeof(msg), &pk[0]) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), &pk[0]) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(vrfy, NULL, msg, sizeof(msg), &pk[0]) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(vrfy, sig, NULL, sizeof(msg), &pk[0]) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(vrfy, sig, NULL, 0, &pk[0]) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), NULL) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), &zero_pk) == 0); - CHECK(ecount == 4); - - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(vrfy); - rustsecp256k1zkp_v0_8_0_context_destroy(both); - rustsecp256k1zkp_v0_8_0_context_destroy(sttc); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_schnorrsig_sign32(CTX, NULL, msg, &keypairs[0], NULL)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_schnorrsig_sign32(CTX, sig, NULL, &keypairs[0], NULL)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_schnorrsig_sign32(CTX, sig, msg, NULL, NULL)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_schnorrsig_sign32(CTX, sig, msg, &invalid_keypair, NULL)); + CHECK_ILLEGAL(STATIC_CTX, rustsecp256k1_v0_11_schnorrsig_sign32(STATIC_CTX, sig, msg, &keypairs[0], NULL)); + + CHECK(rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, NULL, msg, sizeof(msg), &keypairs[0], &extraparams)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig, NULL, sizeof(msg), &keypairs[0], &extraparams)); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig, NULL, 0, &keypairs[0], &extraparams) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), NULL, &extraparams)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &invalid_keypair, &extraparams)); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams)); + CHECK_ILLEGAL(STATIC_CTX, rustsecp256k1_v0_11_schnorrsig_sign_custom(STATIC_CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams)); + + CHECK(rustsecp256k1_v0_11_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk[0]) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_schnorrsig_verify(CTX, NULL, msg, sizeof(msg), &pk[0])); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig, NULL, sizeof(msg), &pk[0])); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig, NULL, 0, &pk[0]) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig, msg, sizeof(msg), NULL)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &zero_pk)); } -/* Checks that hash initialized by rustsecp256k1zkp_v0_8_0_schnorrsig_sha256_tagged has the +/* Checks that hash initialized by rustsecp256k1_v0_11_schnorrsig_sha256_tagged has the * expected state. */ -void test_schnorrsig_sha256_tagged(void) { - unsigned char tag[17] = "BIP0340/challenge"; - rustsecp256k1zkp_v0_8_0_sha256 sha; - rustsecp256k1zkp_v0_8_0_sha256 sha_optimized; +static void test_schnorrsig_sha256_tagged(void) { + unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'c', 'h', 'a', 'l', 'l', 'e', 'n', 'g', 'e'}; + rustsecp256k1_v0_11_sha256 sha; + rustsecp256k1_v0_11_sha256 sha_optimized; - rustsecp256k1zkp_v0_8_0_sha256_initialize_tagged(&sha, (unsigned char *) tag, sizeof(tag)); - rustsecp256k1zkp_v0_8_0_schnorrsig_sha256_tagged(&sha_optimized); + rustsecp256k1_v0_11_sha256_initialize_tagged(&sha, (unsigned char *) tag, sizeof(tag)); + rustsecp256k1_v0_11_schnorrsig_sha256_tagged(&sha_optimized); test_sha256_eq(&sha, &sha_optimized); } /* Helper function for schnorrsig_bip_vectors * Signs the message and checks that it's the same as expected_sig. */ -void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg32, const unsigned char *expected_sig) { +static void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg, size_t msglen, const unsigned char *expected_sig) { unsigned char sig[64]; - rustsecp256k1zkp_v0_8_0_keypair keypair; - rustsecp256k1zkp_v0_8_0_xonly_pubkey pk, pk_expected; - - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, sk)); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(ctx, sig, msg32, &keypair, aux_rand)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(sig, expected_sig, 64) == 0); + rustsecp256k1_v0_11_keypair keypair; + rustsecp256k1_v0_11_xonly_pubkey pk, pk_expected; + + rustsecp256k1_v0_11_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + extraparams.ndata = (unsigned char*)aux_rand; + + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk)); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig, msg, msglen, &keypair, &extraparams)); + CHECK(rustsecp256k1_v0_11_memcmp_var(sig, expected_sig, 64) == 0); + if (msglen == 32) { + memset(sig, 0, 64); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign32(CTX, sig, msg, &keypair, aux_rand)); + CHECK(rustsecp256k1_v0_11_memcmp_var(sig, expected_sig, 64) == 0); + } - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(ctx, &pk_expected, pk_serialized)); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(ctx, &pk, NULL, &keypair)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig, msg32, 32, &pk)); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &pk_expected, pk_serialized)); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig, msg, msglen, &pk)); } /* Helper function for schnorrsig_bip_vectors * Checks that both verify and verify_batch (TODO) return the same value as expected. */ -void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig, int expected) { - rustsecp256k1zkp_v0_8_0_xonly_pubkey pk; +static void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg, size_t msglen, const unsigned char *sig, int expected) { + rustsecp256k1_v0_11_xonly_pubkey pk; - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(ctx, &pk, pk_serialized)); - CHECK(expected == rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig, msg32, 32, &pk)); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &pk, pk_serialized)); + CHECK(expected == rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig, msg, msglen, &pk)); } /* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See * https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv. */ -void test_schnorrsig_bip_vectors(void) { +static void test_schnorrsig_bip_vectors(void) { { /* Test vector 0 */ const unsigned char sk[32] = { @@ -282,7 +218,7 @@ void test_schnorrsig_bip_vectors(void) { 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }; - unsigned char aux_rand[32] = { + const unsigned char aux_rand[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -304,8 +240,8 @@ void test_schnorrsig_bip_vectors(void) { 0xEB, 0xEE, 0xE8, 0xFD, 0xB2, 0x17, 0x2F, 0x47, 0x7D, 0xF4, 0x90, 0x0D, 0x31, 0x05, 0x36, 0xC0 }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1); + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); } { /* Test vector 1 */ @@ -321,7 +257,7 @@ void test_schnorrsig_bip_vectors(void) { 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }; - unsigned char aux_rand[32] = { + const unsigned char aux_rand[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -343,8 +279,8 @@ void test_schnorrsig_bip_vectors(void) { 0x89, 0x7E, 0xFC, 0xB6, 0x39, 0xEA, 0x87, 0x1C, 0xFA, 0x95, 0xF6, 0xDE, 0x33, 0x9E, 0x4B, 0x0A }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1); + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); } { /* Test vector 2 */ @@ -360,7 +296,7 @@ void test_schnorrsig_bip_vectors(void) { 0x01, 0x39, 0x71, 0x53, 0x09, 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 }; - unsigned char aux_rand[32] = { + const unsigned char aux_rand[32] = { 0xC8, 0x7A, 0xA5, 0x38, 0x24, 0xB4, 0xD7, 0xAE, 0x2E, 0xB0, 0x35, 0xA2, 0xB5, 0xBB, 0xBC, 0xCC, 0x08, 0x0E, 0x76, 0xCD, 0xC6, 0xD1, 0x69, 0x2C, @@ -382,8 +318,8 @@ void test_schnorrsig_bip_vectors(void) { 0x7A, 0xDE, 0xA9, 0x8D, 0x82, 0xF8, 0x48, 0x1E, 0x0E, 0x1E, 0x03, 0x67, 0x4A, 0x6F, 0x3F, 0xB7 }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1); + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); } { /* Test vector 3 */ @@ -399,7 +335,7 @@ void test_schnorrsig_bip_vectors(void) { 0x3A, 0x0D, 0x95, 0xFB, 0xF2, 0x1D, 0x46, 0x8A, 0x1B, 0x33, 0xF8, 0xC1, 0x60, 0xD8, 0xF5, 0x17 }; - unsigned char aux_rand[32] = { + const unsigned char aux_rand[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -421,8 +357,8 @@ void test_schnorrsig_bip_vectors(void) { 0xF2, 0x5F, 0xD7, 0x88, 0x81, 0xEB, 0xB3, 0x27, 0x71, 0xFC, 0x59, 0x22, 0xEF, 0xC6, 0x6E, 0xA3 }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1); + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); } { /* Test vector 4 */ @@ -448,7 +384,7 @@ void test_schnorrsig_bip_vectors(void) { 0x60, 0xCB, 0x71, 0xC0, 0x4E, 0x80, 0xF5, 0x93, 0x06, 0x0B, 0x07, 0xD2, 0x83, 0x08, 0xD7, 0xF4 }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); } { /* Test vector 5 */ @@ -458,9 +394,9 @@ void test_schnorrsig_bip_vectors(void) { 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, 0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, 0x34 }; - rustsecp256k1zkp_v0_8_0_xonly_pubkey pk_parsed; + rustsecp256k1_v0_11_xonly_pubkey pk_parsed; /* No need to check the signature of the test vector as parsing the pubkey already fails */ - CHECK(!rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(ctx, &pk_parsed, pk)); + CHECK(!rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &pk_parsed, pk)); } { /* Test vector 6 */ @@ -486,7 +422,7 @@ void test_schnorrsig_bip_vectors(void) { 0x7A, 0x73, 0xC6, 0x43, 0xE1, 0x66, 0xBE, 0x5E, 0xBE, 0xAF, 0xA3, 0x4B, 0x1A, 0xC5, 0x53, 0xE2 }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 7 */ @@ -512,7 +448,7 @@ void test_schnorrsig_bip_vectors(void) { 0x62, 0x2A, 0x95, 0x4C, 0xFE, 0x54, 0x57, 0x35, 0xAA, 0xEA, 0x51, 0x34, 0xFC, 0xCD, 0xB2, 0xBD }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 8 */ @@ -538,7 +474,7 @@ void test_schnorrsig_bip_vectors(void) { 0xE8, 0xD7, 0xC9, 0x3E, 0x00, 0xC5, 0xED, 0x0C, 0x18, 0x34, 0xFF, 0x0D, 0x0C, 0x2E, 0x6D, 0xA6 }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 9 */ @@ -564,7 +500,7 @@ void test_schnorrsig_bip_vectors(void) { 0x4F, 0xB7, 0x34, 0x76, 0xF0, 0xD5, 0x94, 0xDC, 0xB6, 0x5C, 0x64, 0x25, 0xBD, 0x18, 0x60, 0x51 }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 10 */ @@ -590,7 +526,7 @@ void test_schnorrsig_bip_vectors(void) { 0xDB, 0xA8, 0x7F, 0x11, 0xAC, 0x67, 0x54, 0xF9, 0x37, 0x80, 0xD5, 0xA1, 0x83, 0x7C, 0xF1, 0x97 }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 11 */ @@ -616,7 +552,7 @@ void test_schnorrsig_bip_vectors(void) { 0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F, 0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 12 */ @@ -642,7 +578,7 @@ void test_schnorrsig_bip_vectors(void) { 0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F, 0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 13 */ @@ -668,7 +604,7 @@ void test_schnorrsig_bip_vectors(void) { 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 14 */ @@ -678,9 +614,150 @@ void test_schnorrsig_bip_vectors(void) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 }; - rustsecp256k1zkp_v0_8_0_xonly_pubkey pk_parsed; + rustsecp256k1_v0_11_xonly_pubkey pk_parsed; /* No need to check the signature of the test vector as parsing the pubkey already fails */ - CHECK(!rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(ctx, &pk_parsed, pk)); + CHECK(!rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &pk_parsed, pk)); + } + { + /* Test vector 15 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + /* const unsigned char msg[0] = {}; */ + const unsigned char sig[64] = { + 0x71, 0x53, 0x5D, 0xB1, 0x65, 0xEC, 0xD9, 0xFB, + 0xBC, 0x04, 0x6E, 0x5F, 0xFA, 0xEA, 0x61, 0x18, + 0x6B, 0xB6, 0xAD, 0x43, 0x67, 0x32, 0xFC, 0xCC, + 0x25, 0x29, 0x1A, 0x55, 0x89, 0x54, 0x64, 0xCF, + 0x60, 0x69, 0xCE, 0x26, 0xBF, 0x03, 0x46, 0x62, + 0x28, 0xF1, 0x9A, 0x3A, 0x62, 0xDB, 0x8A, 0x64, + 0x9F, 0x2D, 0x56, 0x0F, 0xAC, 0x65, 0x28, 0x27, + 0xD1, 0xAF, 0x05, 0x74, 0xE4, 0x27, 0xAB, 0x63, + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, NULL, 0, sig); + test_schnorrsig_bip_vectors_check_verify(pk, NULL, 0, sig, 1); + } + { + /* Test vector 16 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + const unsigned char msg[] = { 0x11 }; + const unsigned char sig[64] = { + 0x08, 0xA2, 0x0A, 0x0A, 0xFE, 0xF6, 0x41, 0x24, + 0x64, 0x92, 0x32, 0xE0, 0x69, 0x3C, 0x58, 0x3A, + 0xB1, 0xB9, 0x93, 0x4A, 0xE6, 0x3B, 0x4C, 0x35, + 0x11, 0xF3, 0xAE, 0x11, 0x34, 0xC6, 0xA3, 0x03, + 0xEA, 0x31, 0x73, 0xBF, 0xEA, 0x66, 0x83, 0xBD, + 0x10, 0x1F, 0xA5, 0xAA, 0x5D, 0xBC, 0x19, 0x96, + 0xFE, 0x7C, 0xAC, 0xFC, 0x5A, 0x57, 0x7D, 0x33, + 0xEC, 0x14, 0x56, 0x4C, 0xEC, 0x2B, 0xAC, 0xBF, + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 17 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + const unsigned char msg[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, + }; + const unsigned char sig[64] = { + 0x51, 0x30, 0xF3, 0x9A, 0x40, 0x59, 0xB4, 0x3B, + 0xC7, 0xCA, 0xC0, 0x9A, 0x19, 0xEC, 0xE5, 0x2B, + 0x5D, 0x86, 0x99, 0xD1, 0xA7, 0x1E, 0x3C, 0x52, + 0xDA, 0x9A, 0xFD, 0xB6, 0xB5, 0x0A, 0xC3, 0x70, + 0xC4, 0xA4, 0x82, 0xB7, 0x7B, 0xF9, 0x60, 0xF8, + 0x68, 0x15, 0x40, 0xE2, 0x5B, 0x67, 0x71, 0xEC, + 0xE1, 0xE5, 0xA3, 0x7F, 0xD8, 0x0E, 0x5A, 0x51, + 0x89, 0x7C, 0x55, 0x66, 0xA9, 0x7E, 0xA5, 0xA5, + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 18 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + const unsigned char sig[64] = { + 0x40, 0x3B, 0x12, 0xB0, 0xD8, 0x55, 0x5A, 0x34, + 0x41, 0x75, 0xEA, 0x7E, 0xC7, 0x46, 0x56, 0x63, + 0x03, 0x32, 0x1E, 0x5D, 0xBF, 0xA8, 0xBE, 0x6F, + 0x09, 0x16, 0x35, 0x16, 0x3E, 0xCA, 0x79, 0xA8, + 0x58, 0x5E, 0xD3, 0xE3, 0x17, 0x08, 0x07, 0xE7, + 0xC0, 0x3B, 0x72, 0x0F, 0xC5, 0x4C, 0x7B, 0x23, + 0x89, 0x7F, 0xCB, 0xA0, 0xE9, 0xD0, 0xB4, 0xA0, + 0x68, 0x94, 0xCF, 0xD2, 0x49, 0xF2, 0x23, 0x67, + }; + unsigned char msg[100]; + memset(msg, 0x99, sizeof(msg)); + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); } } @@ -725,139 +802,139 @@ static int nonce_function_overflowing(unsigned char *nonce32, const unsigned cha return 1; } -void test_schnorrsig_sign(void) { +static void test_schnorrsig_sign(void) { unsigned char sk[32]; - rustsecp256k1zkp_v0_8_0_xonly_pubkey pk; - rustsecp256k1zkp_v0_8_0_keypair keypair; - const unsigned char msg[32] = "this is a msg for a schnorrsig.."; + rustsecp256k1_v0_11_xonly_pubkey pk; + rustsecp256k1_v0_11_keypair keypair; + const unsigned char msg[] = {'t', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 'm', 's', 'g', ' ', 'f', 'o', 'r', ' ', 'a', ' ', 's', 'c', 'h', 'n', 'o', 'r', 'r', 's', 'i', 'g', '.', '.'}; unsigned char sig[64]; unsigned char sig2[64]; unsigned char zeros64[64] = { 0 }; - rustsecp256k1zkp_v0_8_0_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + rustsecp256k1_v0_11_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; unsigned char aux_rand[32]; - rustsecp256k1zkp_v0_8_0_testrand256(sk); - rustsecp256k1zkp_v0_8_0_testrand256(aux_rand); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, sk)); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(ctx, &pk, NULL, &keypair)); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk)); + testrand256(sk); + testrand256(aux_rand); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk)); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); /* Check that deprecated alias gives the same result */ - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign(ctx, sig2, msg, &keypair, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(sig, sig2, sizeof(sig)) == 0); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign(CTX, sig2, msg, &keypair, NULL) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(sig, sig2, sizeof(sig)) == 0); /* Test different nonce functions */ - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk)); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); memset(sig, 1, sizeof(sig)); extraparams.noncefp = nonce_function_failing; - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(sig, zeros64, sizeof(sig)) == 0); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(sig, zeros64, sizeof(sig)) == 0); memset(&sig, 1, sizeof(sig)); extraparams.noncefp = nonce_function_0; - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(sig, zeros64, sizeof(sig)) == 0); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(sig, zeros64, sizeof(sig)) == 0); memset(&sig, 1, sizeof(sig)); extraparams.noncefp = nonce_function_overflowing; - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk)); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); /* When using the default nonce function, schnorrsig_sign_custom produces * the same result as schnorrsig_sign with aux_rand = extraparams.ndata */ extraparams.noncefp = NULL; extraparams.ndata = aux_rand; - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(ctx, sig2, msg, &keypair, extraparams.ndata) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(sig, sig2, sizeof(sig)) == 0); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign32(CTX, sig2, msg, &keypair, extraparams.ndata) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(sig, sig2, sizeof(sig)) == 0); } #define N_SIGS 3 /* Creates N_SIGS valid signatures and verifies them with verify and * verify_batch (TODO). Then flips some bits and checks that verification now * fails. */ -void test_schnorrsig_sign_verify(void) { +static void test_schnorrsig_sign_verify(void) { unsigned char sk[32]; unsigned char msg[N_SIGS][32]; unsigned char sig[N_SIGS][64]; size_t i; - rustsecp256k1zkp_v0_8_0_keypair keypair; - rustsecp256k1zkp_v0_8_0_xonly_pubkey pk; - rustsecp256k1zkp_v0_8_0_scalar s; + rustsecp256k1_v0_11_keypair keypair; + rustsecp256k1_v0_11_xonly_pubkey pk; + rustsecp256k1_v0_11_scalar s; - rustsecp256k1zkp_v0_8_0_testrand256(sk); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, sk)); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(ctx, &pk, NULL, &keypair)); + testrand256(sk); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk)); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); for (i = 0; i < N_SIGS; i++) { - rustsecp256k1zkp_v0_8_0_testrand256(msg[i]); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(ctx, sig[i], msg[i], &keypair, NULL)); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig[i], msg[i], sizeof(msg[i]), &pk)); + testrand256(msg[i]); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign32(CTX, sig[i], msg[i], &keypair, NULL)); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig[i], msg[i], sizeof(msg[i]), &pk)); } { /* Flip a few bits in the signature and in the message and check that * verify and verify_batch (TODO) fail */ - size_t sig_idx = rustsecp256k1zkp_v0_8_0_testrand_int(N_SIGS); - size_t byte_idx = rustsecp256k1zkp_v0_8_0_testrand_bits(5); - unsigned char xorbyte = rustsecp256k1zkp_v0_8_0_testrand_int(254)+1; + size_t sig_idx = testrand_int(N_SIGS); + size_t byte_idx = testrand_bits(5); + unsigned char xorbyte = testrand_int(254)+1; sig[sig_idx][byte_idx] ^= xorbyte; - CHECK(!rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); + CHECK(!rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); sig[sig_idx][byte_idx] ^= xorbyte; - byte_idx = rustsecp256k1zkp_v0_8_0_testrand_bits(5); + byte_idx = testrand_bits(5); sig[sig_idx][32+byte_idx] ^= xorbyte; - CHECK(!rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); + CHECK(!rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); sig[sig_idx][32+byte_idx] ^= xorbyte; - byte_idx = rustsecp256k1zkp_v0_8_0_testrand_bits(5); + byte_idx = testrand_bits(5); msg[sig_idx][byte_idx] ^= xorbyte; - CHECK(!rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); + CHECK(!rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); msg[sig_idx][byte_idx] ^= xorbyte; /* Check that above bitflips have been reversed correctly */ - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); } /* Test overflowing s */ - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(ctx, sig[0], msg[0], &keypair, NULL)); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk)); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign32(CTX, sig[0], msg[0], &keypair, NULL)); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); memset(&sig[0][32], 0xFF, 32); - CHECK(!rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk)); + CHECK(!rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); /* Test negative s */ - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(ctx, sig[0], msg[0], &keypair, NULL)); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk)); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&s, &sig[0][32], NULL); - rustsecp256k1zkp_v0_8_0_scalar_negate(&s, &s); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(&sig[0][32], &s); - CHECK(!rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk)); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign32(CTX, sig[0], msg[0], &keypair, NULL)); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); + rustsecp256k1_v0_11_scalar_set_b32(&s, &sig[0][32], NULL); + rustsecp256k1_v0_11_scalar_negate(&s, &s); + rustsecp256k1_v0_11_scalar_get_b32(&sig[0][32], &s); + CHECK(!rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); /* The empty message can be signed & verified */ - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(ctx, sig[0], NULL, 0, &keypair, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig[0], NULL, 0, &pk) == 1); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig[0], NULL, 0, &keypair, NULL) == 1); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig[0], NULL, 0, &pk) == 1); { /* Test varying message lengths */ unsigned char msg_large[32 * 8]; - uint32_t msglen = rustsecp256k1zkp_v0_8_0_testrand_int(sizeof(msg_large)); + uint32_t msglen = testrand_int(sizeof(msg_large)); for (i = 0; i < sizeof(msg_large); i += 32) { - rustsecp256k1zkp_v0_8_0_testrand256(&msg_large[i]); + testrand256(&msg_large[i]); } - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign_custom(ctx, sig[0], msg_large, msglen, &keypair, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig[0], msg_large, msglen, &pk) == 1); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign_custom(CTX, sig[0], msg_large, msglen, &keypair, NULL) == 1); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig[0], msg_large, msglen, &pk) == 1); /* Verification for a random wrong message length fails */ msglen = (msglen + (sizeof(msg_large) - 1)) % sizeof(msg_large); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig[0], msg_large, msglen, &pk) == 0); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig[0], msg_large, msglen, &pk) == 0); } } #undef N_SIGS -void test_schnorrsig_taproot(void) { +static void test_schnorrsig_taproot(void) { unsigned char sk[32]; - rustsecp256k1zkp_v0_8_0_keypair keypair; - rustsecp256k1zkp_v0_8_0_xonly_pubkey internal_pk; + rustsecp256k1_v0_11_keypair keypair; + rustsecp256k1_v0_11_xonly_pubkey internal_pk; unsigned char internal_pk_bytes[32]; - rustsecp256k1zkp_v0_8_0_xonly_pubkey output_pk; + rustsecp256k1_v0_11_xonly_pubkey output_pk; unsigned char output_pk_bytes[32]; unsigned char tweak[32]; int pk_parity; @@ -865,37 +942,37 @@ void test_schnorrsig_taproot(void) { unsigned char sig[64]; /* Create output key */ - rustsecp256k1zkp_v0_8_0_testrand256(sk); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_create(ctx, &keypair, sk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1); + testrand256(sk); + CHECK(rustsecp256k1_v0_11_keypair_create(CTX, &keypair, sk) == 1); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1); /* In actual taproot the tweak would be hash of internal_pk */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, tweak, &internal_pk) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_keypair_xonly_pub(ctx, &output_pk, &pk_parity, &keypair) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, output_pk_bytes, &output_pk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, tweak, &internal_pk) == 1); + CHECK(rustsecp256k1_v0_11_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK(rustsecp256k1_v0_11_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, output_pk_bytes, &output_pk) == 1); /* Key spend */ - rustsecp256k1zkp_v0_8_0_testrand256(msg); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL) == 1); + testrand256(msg); + CHECK(rustsecp256k1_v0_11_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1); /* Verify key spend */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(ctx, &output_pk, output_pk_bytes) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &output_pk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &output_pk, output_pk_bytes) == 1); + CHECK(rustsecp256k1_v0_11_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &output_pk) == 1); /* Script spend */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_serialize(ctx, internal_pk_bytes, &internal_pk) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_serialize(CTX, internal_pk_bytes, &internal_pk) == 1); /* Verify script spend */ - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_parse(ctx, &internal_pk, internal_pk_bytes) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_xonly_pubkey_tweak_add_check(ctx, output_pk_bytes, pk_parity, &internal_pk, tweak) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_parse(CTX, &internal_pk, internal_pk_bytes) == 1); + CHECK(rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check(CTX, output_pk_bytes, pk_parity, &internal_pk, tweak) == 1); } -void run_schnorrsig_tests(void) { +static void run_schnorrsig_tests(void) { int i; run_nonce_function_bip340_tests(); test_schnorrsig_api(); test_schnorrsig_sha256_tagged(); test_schnorrsig_bip_vectors(); - for (i = 0; i < count; i++) { + for (i = 0; i < COUNT; i++) { test_schnorrsig_sign(); test_schnorrsig_sign_verify(); } diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precompute_ecmult.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precompute_ecmult.c similarity index 66% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precompute_ecmult.c rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precompute_ecmult.c index 1041d5ee..b4370e2c 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precompute_ecmult.c +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precompute_ecmult.c @@ -7,25 +7,22 @@ #include #include -/* Autotools creates libsecp256k1-config.h, of which ECMULT_WINDOW_SIZE is needed. - ifndef guard so downstream users can define their own if they do not use autotools. */ -#if !defined(ECMULT_WINDOW_SIZE) -#include "libsecp256k1-config.h" -#endif - #include "../include/secp256k1.h" + #include "assumptions.h" #include "util.h" + #include "field_impl.h" #include "group_impl.h" +#include "int128_impl.h" #include "ecmult.h" #include "ecmult_compute_table_impl.h" -static void print_table(FILE *fp, const char *name, int window_g, const rustsecp256k1zkp_v0_8_0_ge_storage* table) { +static void print_table(FILE *fp, const char *name, int window_g, const rustsecp256k1_v0_11_ge_storage* table) { int j; int i; - fprintf(fp, "const rustsecp256k1zkp_v0_8_0_ge_storage %s[ECMULT_TABLE_SIZE(WINDOW_G)] = {\n", name); + fprintf(fp, "const rustsecp256k1_v0_11_ge_storage %s[ECMULT_TABLE_SIZE(WINDOW_G)] = {\n", name); fprintf(fp, " S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32 ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")\n", SECP256K1_GE_STORAGE_CONST_GET(table[0])); @@ -44,13 +41,13 @@ static void print_table(FILE *fp, const char *name, int window_g, const rustsecp } static void print_two_tables(FILE *fp, int window_g) { - rustsecp256k1zkp_v0_8_0_ge_storage* table = malloc(ECMULT_TABLE_SIZE(window_g) * sizeof(rustsecp256k1zkp_v0_8_0_ge_storage)); - rustsecp256k1zkp_v0_8_0_ge_storage* table_128 = malloc(ECMULT_TABLE_SIZE(window_g) * sizeof(rustsecp256k1zkp_v0_8_0_ge_storage)); + rustsecp256k1_v0_11_ge_storage* table = malloc(ECMULT_TABLE_SIZE(window_g) * sizeof(rustsecp256k1_v0_11_ge_storage)); + rustsecp256k1_v0_11_ge_storage* table_128 = malloc(ECMULT_TABLE_SIZE(window_g) * sizeof(rustsecp256k1_v0_11_ge_storage)); - rustsecp256k1zkp_v0_8_0_ecmult_compute_two_tables(table, table_128, window_g, &rustsecp256k1zkp_v0_8_0_ge_const_g); + rustsecp256k1_v0_11_ecmult_compute_two_tables(table, table_128, window_g, &rustsecp256k1_v0_11_ge_const_g); - print_table(fp, "rustsecp256k1zkp_v0_8_0_pre_g", window_g, table); - print_table(fp, "rustsecp256k1zkp_v0_8_0_pre_g_128", window_g, table_128); + print_table(fp, "rustsecp256k1_v0_11_pre_g", window_g, table); + print_table(fp, "rustsecp256k1_v0_11_pre_g_128", window_g, table_128); free(table); free(table_128); @@ -59,22 +56,19 @@ static void print_two_tables(FILE *fp, int window_g) { int main(void) { /* Always compute all tables for window sizes up to 15. */ int window_g = (ECMULT_WINDOW_SIZE < 15) ? 15 : ECMULT_WINDOW_SIZE; + const char outfile[] = "src/precomputed_ecmult.c"; FILE* fp; - fp = fopen("src/precomputed_ecmult.c","w"); + fp = fopen(outfile, "w"); if (fp == NULL) { - fprintf(stderr, "Could not open src/precomputed_ecmult.h for writing!\n"); + fprintf(stderr, "Could not open %s for writing!\n", outfile); return -1; } fprintf(fp, "/* This file was automatically generated by precompute_ecmult. */\n"); - fprintf(fp, "/* This file contains an array rustsecp256k1zkp_v0_8_0_pre_g with odd multiples of the base point G and\n"); - fprintf(fp, " * an array rustsecp256k1zkp_v0_8_0_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.\n"); + fprintf(fp, "/* This file contains an array rustsecp256k1_v0_11_pre_g with odd multiples of the base point G and\n"); + fprintf(fp, " * an array rustsecp256k1_v0_11_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.\n"); fprintf(fp, " */\n"); - fprintf(fp, "#if defined HAVE_CONFIG_H\n"); - fprintf(fp, "# include \"libsecp256k1-config.h\"\n"); - fprintf(fp, "#endif\n"); - fprintf(fp, "#include \"../include/secp256k1.h\"\n"); fprintf(fp, "#include \"group.h\"\n"); fprintf(fp, "#include \"ecmult.h\"\n"); fprintf(fp, "#include \"precomputed_ecmult.h\"\n"); diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precompute_ecmult_gen.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precompute_ecmult_gen.c new file mode 100644 index 00000000..467c61b5 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precompute_ecmult_gen.c @@ -0,0 +1,100 @@ +/********************************************************************************* + * Copyright (c) 2013, 2014, 2015, 2021 Thomas Daede, Cory Fields, Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + *********************************************************************************/ + +#include +#include + +#include "../include/secp256k1.h" + +#include "assumptions.h" +#include "util.h" + +#include "group.h" +#include "int128_impl.h" +#include "ecmult_gen.h" +#include "ecmult_gen_compute_table_impl.h" + +static const int CONFIGS[][2] = { + {2, 5}, + {11, 6}, + {43, 6} +}; + +static void print_table(FILE* fp, int blocks, int teeth) { + int spacing = CEIL_DIV(256, blocks * teeth); + size_t points = ((size_t)1) << (teeth - 1); + int outer; + size_t inner; + + rustsecp256k1_v0_11_ge_storage* table = checked_malloc(&default_error_callback, blocks * points * sizeof(rustsecp256k1_v0_11_ge_storage)); + rustsecp256k1_v0_11_ecmult_gen_compute_table(table, &rustsecp256k1_v0_11_ge_const_g, blocks, teeth, spacing); + + fprintf(fp, "#elif (COMB_BLOCKS == %d) && (COMB_TEETH == %d) && (COMB_SPACING == %d)\n", blocks, teeth, spacing); + for (outer = 0; outer != blocks; outer++) { + fprintf(fp,"{"); + for (inner = 0; inner != points; inner++) { + fprintf(fp, "S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32 + ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")", + SECP256K1_GE_STORAGE_CONST_GET(table[outer * points + inner])); + if (inner != points - 1) { + fprintf(fp,",\n"); + } + } + if (outer != blocks - 1) { + fprintf(fp,"},\n"); + } else { + fprintf(fp,"}\n"); + } + } + free(table); +} + +int main(int argc, char **argv) { + const char outfile[] = "src/precomputed_ecmult_gen.c"; + FILE* fp; + size_t config; + int did_current_config = 0; + + (void)argc; + (void)argv; + + fp = fopen(outfile, "w"); + if (fp == NULL) { + fprintf(stderr, "Could not open %s for writing!\n", outfile); + return -1; + } + + fprintf(fp, "/* This file was automatically generated by precompute_ecmult_gen. */\n"); + fprintf(fp, "/* See ecmult_gen_impl.h for details about the contents of this file. */\n"); + fprintf(fp, "#include \"group.h\"\n"); + fprintf(fp, "#include \"ecmult_gen.h\"\n"); + fprintf(fp, "#include \"precomputed_ecmult_gen.h\"\n"); + fprintf(fp, "#ifdef EXHAUSTIVE_TEST_ORDER\n"); + fprintf(fp, "# error Cannot compile precomputed_ecmult_gen.c in exhaustive test mode\n"); + fprintf(fp, "#endif /* EXHAUSTIVE_TEST_ORDER */\n"); + fprintf(fp, "#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)\n"); + + fprintf(fp, "const rustsecp256k1_v0_11_ge_storage rustsecp256k1_v0_11_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS] = {\n"); + fprintf(fp, "#if 0\n"); + for (config = 0; config < sizeof(CONFIGS) / sizeof(*CONFIGS); ++config) { + print_table(fp, CONFIGS[config][0], CONFIGS[config][1]); + if (CONFIGS[config][0] == COMB_BLOCKS && CONFIGS[config][1] == COMB_TEETH) { + did_current_config = 1; + } + } + if (!did_current_config) { + print_table(fp, COMB_BLOCKS, COMB_TEETH); + } + fprintf(fp, "#else\n"); + fprintf(fp, "# error Configuration mismatch, invalid COMB_* parameters. Try deleting precomputed_ecmult_gen.c before the build.\n"); + fprintf(fp, "#endif\n"); + + fprintf(fp, "};\n"); + fprintf(fp, "#undef S\n"); + fclose(fp); + + return 0; +} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precomputed_ecmult.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precomputed_ecmult.c similarity index 99% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precomputed_ecmult.c rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precomputed_ecmult.c index 0c5ae6e9..68b7ebff 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precomputed_ecmult.c +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precomputed_ecmult.c @@ -1,11 +1,7 @@ /* This file was automatically generated by precompute_ecmult. */ -/* This file contains an array rustsecp256k1zkp_v0_8_0_pre_g with odd multiples of the base point G and - * an array rustsecp256k1zkp_v0_8_0_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G. +/* This file contains an array rustsecp256k1_v0_11_pre_g with odd multiples of the base point G and + * an array rustsecp256k1_v0_11_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G. */ -#if defined HAVE_CONFIG_H -# include "libsecp256k1-config.h" -#endif -#include "../include/secp256k1.h" #include "group.h" #include "ecmult.h" #include "precomputed_ecmult.h" @@ -17,7 +13,7 @@ # error Cannot compile precomputed_ecmult.c in exhaustive test mode #endif /* EXHAUSTIVE_TEST_ORDER */ #define WINDOW_G ECMULT_WINDOW_SIZE -const rustsecp256k1zkp_v0_8_0_ge_storage rustsecp256k1zkp_v0_8_0_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] = { +const rustsecp256k1_v0_11_ge_storage rustsecp256k1_v0_11_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] = { S(79be667e,f9dcbbac,55a06295,ce870b07,29bfcdb,2dce28d9,59f2815b,16f81798,483ada77,26a3c465,5da4fbfc,e1108a8,fd17b448,a6855419,9c47d08f,fb10d4b8) #if WINDOW_G > 2 ,S(f9308a01,9258c310,49344f85,f89d5229,b531c845,836f99b0,8601f113,bce036f9,388f7b0f,632de814,fe337e6,2a37f356,6500a999,34c2231b,6cb9fd75,84b8e672) @@ -8237,7 +8233,7 @@ const rustsecp256k1zkp_v0_8_0_ge_storage rustsecp256k1zkp_v0_8_0_pre_g[ECMULT_TA ,S(1e70619c,381a6adc,e5d925e0,c9c74f97,3c02ff64,ff2662d7,34efc485,d2bce895,c923f771,f543ffed,42935c28,8474aaaf,80a46ad4,3c579ce0,bb5e663d,668b24b3) #endif }; -const rustsecp256k1zkp_v0_8_0_ge_storage rustsecp256k1zkp_v0_8_0_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)] = { +const rustsecp256k1_v0_11_ge_storage rustsecp256k1_v0_11_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)] = { S(8f68b9d2,f63b5f33,9239c1ad,981f162e,e88c5678,723ea335,1b7b444c,9ec4c0da,662a9f2d,ba063986,de1d90c2,b6be215d,bbea2cfe,95510bfd,f23cbf79,501fff82) #if WINDOW_G > 2 ,S(38381dbe,2e509f22,8ba93363,f2451f08,fd845cb3,51d954be,18e2b8ed,d23809fa,e4a32d0a,fb917dc,b09405a5,520eb1cc,3681fccb,32d8f24d,bd707518,331fed52) diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precomputed_ecmult.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precomputed_ecmult.h similarity index 67% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precomputed_ecmult.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precomputed_ecmult.h index 1a6006b8..6b6ded95 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precomputed_ecmult.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precomputed_ecmult.h @@ -11,21 +11,24 @@ extern "C" { #endif +#include "ecmult.h" #include "group.h" #if defined(EXHAUSTIVE_TEST_ORDER) -#if EXHAUSTIVE_TEST_ORDER == 13 +# if EXHAUSTIVE_TEST_ORDER == 7 +# define WINDOW_G 3 +# elif EXHAUSTIVE_TEST_ORDER == 13 # define WINDOW_G 4 # elif EXHAUSTIVE_TEST_ORDER == 199 # define WINDOW_G 8 # else # error No known generator for the specified exhaustive test group order. # endif -static rustsecp256k1zkp_v0_8_0_ge_storage rustsecp256k1zkp_v0_8_0_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; -static rustsecp256k1zkp_v0_8_0_ge_storage rustsecp256k1zkp_v0_8_0_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; +static rustsecp256k1_v0_11_ge_storage rustsecp256k1_v0_11_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; +static rustsecp256k1_v0_11_ge_storage rustsecp256k1_v0_11_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; #else /* !defined(EXHAUSTIVE_TEST_ORDER) */ # define WINDOW_G ECMULT_WINDOW_SIZE -extern const rustsecp256k1zkp_v0_8_0_ge_storage rustsecp256k1zkp_v0_8_0_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; -extern const rustsecp256k1zkp_v0_8_0_ge_storage rustsecp256k1zkp_v0_8_0_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; +extern const rustsecp256k1_v0_11_ge_storage rustsecp256k1_v0_11_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; +extern const rustsecp256k1_v0_11_ge_storage rustsecp256k1_v0_11_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; #endif /* defined(EXHAUSTIVE_TEST_ORDER) */ #ifdef __cplusplus diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precomputed_ecmult_gen.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precomputed_ecmult_gen.c new file mode 100644 index 00000000..2d8fabc9 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precomputed_ecmult_gen.c @@ -0,0 +1,1779 @@ +/* This file was automatically generated by precompute_ecmult_gen. */ +/* See ecmult_gen_impl.h for details about the contents of this file. */ +#include "group.h" +#include "ecmult_gen.h" +#include "precomputed_ecmult_gen.h" +#ifdef EXHAUSTIVE_TEST_ORDER +# error Cannot compile precomputed_ecmult_gen.c in exhaustive test mode +#endif /* EXHAUSTIVE_TEST_ORDER */ +#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u) +const rustsecp256k1_v0_11_ge_storage rustsecp256k1_v0_11_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS] = { +#if 0 +#elif (COMB_BLOCKS == 2) && (COMB_TEETH == 5) && (COMB_SPACING == 26) +{S(7081b567,8cb87d01,99c9c76e,d1e0a5e0,1d784be9,27f6b135,161e0fd0,3f39b473,ad5222ac,f062cb39,21b234a7,15b626ae,f780b307,9b5122d1,53210f42,d9369242), +S(228af17e,df90d1cc,a40173e9,478fa445,9780dacd,c3f15b90,fda5d00e,1faa1b51,8ff47c4d,a4ba636a,f656da9,12a81f79,6252496d,1e519886,b2c2b073,25be2b4a), +S(b515ebe0,f48fb34e,9e01824c,d90553af,db116579,96667847,5ebaa700,242fd722,4cf08191,510fbf0,51f9e19a,198f11f6,ea31268c,2a6d384c,60557250,f0553c50), +S(c37581f1,35446ff3,e80cde04,ec987f08,5af3af9f,71d87494,99b03ba,dcb8f78c,9e46324a,8d8754fe,fbda7c34,2446cf72,b7472708,25cfb92f,a22a4e73,4f1e9bc7), +S(768392e3,b2ccbbc,21792f2d,6f43c63d,efcc249,bcd549cb,96abd8ef,4ae59e90,5d061a40,ac3f93d1,82f0f7a9,914fff5d,90bbacb9,1965882c,591e89bf,c49da994), +S(a9db5de9,2d96c715,8ce5ee00,3d186cf1,976f6a76,f1be0714,726594fb,6c1ba564,743df2a8,ee73fb4a,47b3d0f,2f2b8cab,5af5227,f232946a,82676e4e,8bb70c8b), +S(58921d8d,3712f640,657e762a,737ccd0a,cece1459,a2ba8323,20b43903,d4953f93,78c26959,7e422c02,c01fcbef,484a9d44,9f635c82,849bc2a3,2a9bf6ef,3e6f1e7e), +S(bae41760,ade541bb,60028015,f6906b78,aa41515a,d995dc40,afa091da,77ae8b9a,716ff74d,ad6dc24c,77ebe31f,abe19792,41d18b0f,43ff7598,c6ea04c6,6899219f), +S(e836ff6c,6f9e02e2,4e6f6bcc,2f2460b4,9de88730,6d69241f,b22fa574,7e100f80,77c41df1,4d87b6d3,de74deca,ad426635,f85daca0,ab966a4,5a26a972,32105c5), +S(c7f17d19,fbbf28e2,543fceb2,4268ff6f,1b85e189,79b09991,7457fca0,9ba1b5a4,23a6d4aa,83ee15bf,f1655575,3e4162c5,8acedadb,4c4abfc2,54b7018,f477514b), +S(79c337ad,8835046e,572eea35,df76276b,84e99172,7bbc68a6,8c0b743,28619a,af6cf2b3,9c6b51c9,f1f92e42,6598dcbe,39da6196,2abae0da,d5fc8d0a,aa16a875), +S(1e77739b,12d20887,2bfe200b,d202972a,544804f5,2b0969c5,c22fbe1c,b8b23837,880c7490,c0455322,a0f1e67d,34b3fd1e,33c1e7da,83b9b047,5aef7bc1,332ccee5), +S(b1d314c1,74d493f6,c36a893a,830d90b,f1e86d0c,6deceee0,edb77ff4,31e9607f,8a4ba010,ec3e47cb,29d8f056,e056eb73,3b6b35f6,4c742d06,9ab832f4,68bcd3be), +S(2498aea6,471f748a,f14e50e6,bc17e0a3,ee09514d,fccbd174,f8a21d02,dd0fae48,55a3949f,2e4188e2,b3d344ce,6f0276b5,99b121bc,358e8fe6,bc4f03f5,a8219d08), +S(42d0778e,27e87710,dd19285e,d531af1e,7064386d,11b1b3c9,fb788bf2,b0c112dc,37888909,d943825a,9610e37a,362549f,547b7c7d,ae64a27e,c34290f0,b4fc5fcc), +S(af09a9f8,3a21b2fd,69ce14c5,495c680e,df18e426,c1ca5a1c,af56246f,d6ea5bbd,8eae43ca,8e591017,62c4cb02,9e5cacd2,58f0fdb1,ddbef7e2,c5765208,107c96af)}, +{S(4a7f72ed,ebd8df1f,13db15be,3ab296a8,d67edee4,37965f03,eb501205,3518ddea,1f8c4dc1,2d0e59e7,7d30a326,fd4ecbf8,aacd5fb6,7dc7169,898a9708,ac46b972), +S(c4d4f8d4,949d1ff6,559925db,f4d34972,af16062b,d59493b8,b1e0d546,c2870874,cd7f93e6,c0ee3fdc,4267625a,a6620540,4f6d80c3,d0f7210a,ce6b52e,c350706e), +S(773627f7,dcc56184,7eabafa3,42fffade,325b8ee2,a96f2f77,cbe675a6,2942277d,fb0ad731,9bff4c9c,270d93d1,89a4c380,218ec9df,1f564228,641ab35c,46526bd6), +S(ff443101,befd0bd9,e1914864,3eceea06,b9cf711b,1405e3d5,3883a29f,906063ed,aa1b7d9f,59cbddf7,bc1ad03c,44c4295e,efb406ca,7960c683,eca508d1,b2a9a2dd), +S(cbfb6813,a6874b65,9234e866,c2875f70,e45f9f76,3d634752,3f86040c,880a2e56,ed85d1a,6620c1a4,85ba3038,d2ee6590,4e27206b,eaa531ec,1eb5b886,8232cbca), +S(4e85c77b,27788563,aaeba139,975f7125,f3c933b4,8d67ba6a,2e964243,bdd7bb51,200a9d9b,3400c87b,1fb98422,3200aeb8,e6a5af1d,58c061f0,d059c0b8,d431c08a), +S(d58178ed,f0ce32e3,39a524f7,ad389f7d,8817f41f,ed782612,45218816,2a67d4f0,4840df81,5dab9596,93f9284c,54bdee72,f4861d39,3944c648,ecd76ec5,6dd3225e), +S(670f8f7,9b66496d,13692558,d56d4cd7,a1eeb0d6,9e5133ab,4f0a064b,7152fce4,1a72206,6f530586,927c2e39,370d11f3,e251bd9e,eee10303,406b7592,716333d6), +S(10b41abd,ed4de2fe,b7a40050,e61e5982,89a8cf3,6eaa608c,f2a82c63,5788f1d0,532d168d,680e9c74,4d5111da,6aab902a,9a0f5283,7836b9d9,585dbc8b,1a407de4), +S(76abd21b,103aea9a,f04b4040,297894ce,a501474d,9d38d30,8ed02cc7,137bc7c9,b5a432ad,9e92935f,7040897e,3b04152f,693c5f2,cc1e1d53,2c33f70d,185318e1), +S(4335e10d,5e4f02e6,f1b58a0d,ffb473ec,15f735a3,bf96c140,50bae78c,37061db2,1301143b,1f29f122,afcd0230,d46b6b38,b154e589,92b7eeb4,16088968,a7d57485), +S(2b3966f0,7e37e771,ac4c68ad,b8eef3c0,977cb895,2f47676b,e658aa86,76057f67,5382a6c5,bcdd1a01,6d79d817,80faf650,c0a486bc,ea8fb592,1cd3492c,42c91c3e), +S(f7738800,b7fdf237,dc7f03fc,43724011,8b53aea4,4d7953d4,276f3b4d,bf5c0ff8,c1de7924,ef8dfeed,c4fb409,f1a15d4c,5e8ab42c,90ea9c92,867b5b5c,f2921605), +S(5cb07874,ac4ffb86,2da619be,4c8fa38b,e8b261ec,3ec73a12,cd4cf8fc,4f8d5dae,549d1896,4931dabf,ba4553a2,461f2660,87733454,ea8eec6b,f671e3de,60c70340), +S(5cc85d41,7b2ae9ac,dedb1b44,ce78d8a7,8f56b878,1a4b3af6,635a55c1,fead3be7,66a48c79,301e57d4,54cc8644,d2e778a8,45d85762,2c10eb98,d77eb873,e58bbeca), +S(f27211c9,a067b01c,7fe7fbf7,7b5d9b0,eb0f2475,9d541457,6eb24ba4,19fd3db8,e26d28eb,89f7b518,e9ae0b88,fadbfb9b,641d3a44,c59c6f93,ec28a541,486e041e)} +#elif (COMB_BLOCKS == 11) && (COMB_TEETH == 6) && (COMB_SPACING == 4) +{S(629bee58,a391595f,eb20c534,4933937a,cdb2eba1,86d49f8b,845c1b5f,4ca87182,8dae4162,73c6c068,2e2aede4,76efa86b,7612c07e,f72070d0,dc4486f1,47e95085), +S(6fd5e13c,a94b874b,28cd574b,726efdbf,143ab108,1089b846,7b5b2ebe,6c6a3c8f,4a4db306,52c9772a,868b2859,57c5a005,d83f6afa,6e65d87c,700da998,ce651396), +S(609b6576,191514f4,83f5b428,500cfbaf,96871b8b,3348fe5c,1a131768,bb266b6f,90abb9c1,1bf184d2,8dbc424a,bbf74eb8,de4e0582,2ea5dd93,7d1e8b30,e5f695e7), +S(b5ec0263,27cfd922,23a46abf,a755e6fc,547806ea,333666cf,a43865a3,f4ae647,143353c,cc733d02,617f7764,7dc29c65,67a2e245,aed27120,e5fc11b3,95ffb9c9), +S(ac1fff6,cd869ed5,ca920544,1ceb990c,ce304998,10e27587,6536dcd8,1d4cd15,67a7a012,3e5ea292,85dedf0a,9f138b80,58a1d23c,2a233c5d,783bec39,b6482126), +S(c1807552,644130a3,f9b8aea0,29fdccdd,59e03e27,ff2cb1f9,9d13cf0d,42da7b13,85e99587,f77a25b0,bc64b882,bd279fa3,5be0262e,c2f5253c,70a43261,bd1fe361), +S(42919187,2b3c6877,c3b91266,79266e49,9fa37a8d,74d094a8,8c4a3638,89c2717c,1e4bd2df,a9757d42,285cca1d,856b49b0,ad481ad,828d826e,8921f744,7e04d6ad), +S(d4b10124,283afe03,4b278e5a,91daf61b,be608417,fc845e1f,9b9f52a5,43659f2,fd070859,75e2bad6,b34e0396,47b81a87,cab9fb,fdba802f,6ae3cc8b,67cc98cb), +S(ec4c2c4c,722a54ae,edc37acd,cb6ac490,3077bdf6,3f2c145c,7eb25e74,87c046aa,327bfe37,d745283b,a385dfd0,8e30b61e,2b4e5499,4432be41,fd3f0d31,c00e9ed7), +S(559e40a7,e151eeeb,46442b86,aaf4922c,12030adf,7279bb2,2bca24c6,67566a05,5483756f,60d26b97,82033592,cec21681,c5b5496a,c47f600,2013e5e5,f2ea82df), +S(c1d2e92,19c0138a,9f0a34fd,acc92f4,eafe13cf,1c004b6a,3175133d,6cc7bf12,8fa653f2,a20c1262,be59c7db,20f12579,b2adb1ff,54d84ebc,e5ad4116,3d2ebc23), +S(1becc6c0,e4861825,576624e4,fa622c01,139d9cb0,50c12062,9b87ae6b,9622245,d8516472,656ea10f,5b23839d,43f64e,85fc727b,faafcb6c,fc9c6e89,bf9c038d), +S(c483c2b3,8ceefd35,a9fa9e7a,da242c,d618cd6c,8b3bcb62,e39d68e,c1effab2,71964aca,9101863a,d7c865f2,41e814ef,3c20face,f46246b6,4a742026,471b2495), +S(3487162e,40c7efa6,92bc827f,9af9121e,af5ac549,b4ab6585,6353d699,a94a3783,f5b29042,28833bd6,e3ce0deb,dc0396ca,42701752,f930f437,d042cab2,8f135c1a), +S(eb3b21fa,f733f15a,b94ee0e4,3378e9b6,47571aff,d69292ad,a1b107c8,ad511d5f,cd95b4ad,b8768858,cb750cbb,4fa64523,6b6fde59,ceb71dd4,73a7fe48,9e5a2304), +S(21c8dd7c,34d3f333,758d1d1b,72748fe0,8695af46,3d0bd9ad,e4a6498d,1d01e9df,634d8671,7b885f36,a54b6691,35c3c026,667f3cb6,f2577701,beb0d3bb,84f07940), +S(608e33b8,14998177,5d78e286,d5c6436f,99623417,4e887da0,a95274a0,d120b57d,5d094ca1,181f8dca,87d1e043,f798bfaa,f1004edf,a470fce0,7ff8b124,328397a5), +S(f77710b4,dbc5f7fb,ac6b015e,956ed26a,6bbfb540,6a931a30,d4215aed,de610c7,7508a762,a7333ca8,ac244d6,47e47647,c62c82d,387d8df6,175fb563,1de83d54), +S(f37040aa,b0347fe,976d5980,cbd83db5,4d8cb90e,7f2d2118,85159911,af769d61,df228dd7,67fa0d5c,d44c3f6d,b09e662b,99faa5c6,688b088d,949ddab1,6f11e42), +S(7bf929f3,25374a1b,a0cbaa50,db47fea2,a5d1e3f9,3c34bddc,ea5c2250,d8252071,8fe2d2bf,b23a6755,50f16760,a6511ae8,4e4d316c,45d7cd62,4411ad3f,c72805c), +S(261bc0f3,a69d636a,b82248,6132bf91,2ab7ca95,e9a4925,b3f68bb4,745ee63a,68f52f7,df1ec349,77856c74,7b280907,cb3d456f,988ff7a7,225c4ace,8457a804), +S(60ef138d,e7086d09,711defff,68dad211,88d7f878,d616efb6,dbd3d498,5b730243,ca7c3297,3c56b178,b0cfb8a,da98748a,c3d06cc0,7fe050d7,3a6a9695,52500f8e), +S(8bfef3d6,4be90cac,8b83bf20,906b4277,75a6d982,23d5141f,b74e3851,50bc5eec,ea8b6b4c,c7c8d9ba,809ca811,3621c72c,b82006d7,81ff5f25,32010fc9,57858324), +S(9ca85f3d,4ba47ab0,e9fc0a28,74cd10a4,a8ba9aeb,ff319405,6140fea9,6e395ff3,41182ce8,96554f45,93768fc3,a656981e,69719f05,5469f9e4,ba79de22,bcfe8a8e), +S(38cd0c79,437b1299,9567999a,f54d4f8e,82a6354c,8a93a5ef,56ca2ff5,8a1ce180,c96f5ed,d78de5,9f560716,82b60b13,f06de5f9,49206258,80544bfc,73dfa76a), +S(be37e05b,9369b159,6b390290,3eb8fa0f,f221f599,1270c5f0,47edf62e,a1d0e6e2,4fc860a7,1fa69a27,fbefd8c0,906fc68f,4713fa2a,b37aaa2a,7edd3c8c,d100963c), +S(aa640e99,b091512f,85faed73,a3ac8ede,ee120513,b661f812,9a046a74,d624aaaf,dfb48ad1,a01fd508,e5652406,b681cc9e,13d0d600,68411dae,72d68061,6f6b94ff), +S(d08bb931,f008a1a7,38a16200,9fbf1ab3,d3d455dd,47f45cd6,617e81,8b8e0245,18d92218,21c9a2ed,bcaa5d26,2b7aba18,1f7f1e,7f2007a9,ec6f7d18,f038d723), +S(4e6ed1f6,c39c894f,eaa53e1c,e115fda,75fecf8a,55794628,d9a2202a,9dd5c719,1bb97d73,2e0e137c,e9c94d4c,763f9a6d,e1496548,904460d,df1c3a2f,73b66c1e), +S(867e83ae,610a24bf,401119d,8e1af6dd,414a7161,52b2ffdc,50f71f77,2fa8409c,d5d21ad5,ef365994,b3ad0533,92df82a5,6f677cb3,8500781b,a769dd50,1f6d235), +S(6031361c,6dffc505,dc7e1887,bc75c1d9,5a9db023,8b7240e4,c254f855,b35686fa,b9a9a979,c6b8c576,11eeb783,8b4ac2ae,66506bb0,a203fdf6,3efa9b59,98c7643d), +S(8502d0f,34684503,68784822,f4510c5c,562ad30f,be29a792,f0667e83,b6f95773,cd0e6511,763674b5,57fac9f1,bb62f9e2,3163a0a4,cf08cd52,a6d10064,d8b02ade)}, +{S(840e41bf,13203a96,f41ea041,1ec034fd,db0dac3d,53b6bbc9,4f8a3a78,d0371235,71b51550,a79af319,56c9b3de,fcb167d0,c3e318eb,a852eedc,78490dc5,fdaaca85), +S(5678a034,a24a1607,d78036b2,23eaa3c3,845c9f9e,7293f656,7390354,2f714d5f,57f624be,ff5d1774,c6962dd4,d14cc565,acae170c,7aaf8c6d,b0552daf,e3bdf48c), +S(722012a5,57ed9c9f,9d737a87,39954469,ca12ab29,9dedbaca,507c1259,7a27c6f1,6c28881e,a0e62453,80d73a7f,499f05a4,d9a9c04f,c2ba11e6,9fdd0b6,7c5d5ee4), +S(70c638d9,3eeab892,8bccf1e4,82368eac,a03ca8f1,b30f7b2d,34258539,8c95c014,f8635082,3dc2a200,67dfb293,891929cf,18a810f2,5c85c169,159a4b44,b190a029), +S(2ce4a530,b5f6c77d,c0c4d891,6e89b24b,c25c04c2,723842d4,29300f82,5e260458,6f306154,4d1195ea,98b972e,91a962e2,95a2a4eb,9be03949,a789b01c,f61dd705), +S(89e71182,851bb441,c0af4e31,cad89dc7,3947369b,fef12eb6,b1dfa71a,72498c51,20b7ffd5,878718c2,2b5bfdc,ac422794,63aac0da,4bcdec2a,8f3b538e,3a9f574d), +S(f01f06b8,da0ba34c,e1045e83,adb95fbe,b76f134b,35235539,6b07f8de,9dd25869,afa0fb5b,45ad1f24,73460f17,5ff4bfd8,f162262,65c423fd,ebd92bc1,72f3aa7b), +S(f0c217c8,1dda2201,1f46648a,e096906d,71fba006,1b4dfdb9,85dfe59c,9d8f1894,d5ddd6b7,bdf2a6f6,cba166ae,4c01c60,b012c9ee,ad954a46,6f631f9f,928b3fc), +S(bd9acff2,87cc2a2b,396aef61,b0937a49,c43a2366,a2c3c461,c1283987,a7b6f53,828de0ad,b9067b2d,8f8fefe6,ce3a5c94,e7d63ea1,7c891d2c,5f266e8c,a5fac116), +S(ee314d97,2b9c10a4,fec9f8d,ccab0015,d4923e52,d915eae8,b319911c,7a8fe379,82057aef,ff05c496,ba8b4753,c4e57832,aba9a724,adf70a9f,1b3765ef,952ab52), +S(d39fa7b,9b87ee2a,aa32454a,13470406,c8024c39,cf387143,3364de62,cb94c103,5cf1309,530f9e09,c9b38ad9,3a778ec5,533f60f6,4a42e31,1cd97c2f,c984b9cc), +S(5ab1a07e,5f6aff68,16780e5a,23c9faff,b29cd7d7,5bfb8984,4834fb6b,c6b34a14,deac47fd,6567023e,b5ec7a94,a0133bbf,158c0425,c0a6d288,23558986,314d54bd), +S(b1a4ecc6,94bb5212,98e80464,cffacd32,331ebc7c,4d545141,a129b522,a4818830,9772044f,3722ec57,d76a049b,2afce2b6,319f0bbc,b17c7f06,175a288f,3ce3534d), +S(56015e42,81aed744,a0859e29,eb913a7c,b44ebd39,2ed8c0b7,1eb42f9c,9c93c8ba,8f973650,45f7d8a9,24a276ac,20056895,fb2b0aaa,4b35468a,a51f41f,722b9d33), +S(7d99a5c5,21543229,c8f9c7b,50dbaa64,b200bf86,47c71b35,a0105dde,2b3a8e0c,eae09ef,3ffdec8b,9a30291c,244c0a72,6466c26d,fe2c8d30,174f57fd,ec6aba60), +S(ab7d21f9,1e7dac68,afd6e4e4,794551d5,55a9f42,59825109,5b25652e,946ebdae,8805a806,710ed7b0,fb99ff30,130c074c,6a0be3d2,abe6e155,f9c07496,f8b92454), +S(b31a5f85,d65e5200,8f5261cd,fd6d36f6,4b2a1f3a,6f08d7b8,defc7e84,21d0f7db,2e6d46c3,3733b3b5,597a133f,7459ee2b,570ba333,4d1e7648,1980dda,1aa8d2d3), +S(30af789e,850c8ef8,9eeb226b,27786679,442a9a0c,35cb7337,98345400,29220fc5,f6651170,c83e24e1,eb6e8da,ffa0b0bb,a6c53676,72558d44,c5b77176,3d9b5d7f), +S(8d87f808,98fb8007,ffd5093a,bc6bad2d,23e09e90,e6967031,48d5418,4c60e0ae,3d14332c,21df527f,a2e98243,d3ed4bd0,6634d799,9f62efd,e8d6c919,8ed716a3), +S(a961c219,eb9ea127,205af30d,909ef732,8cc599a,b2080966,f615796e,1126dd98,3e235ae0,37b10074,32e5cee5,56778856,1d552e3e,bf40bb82,5b527cac,8e1e5b9c), +S(b9c2de21,40cea728,2aec5293,bb77dc7b,550a72c8,84389c05,310651bc,7570f2ea,74171cd9,4a5683b7,5bc7c5d9,b4c8fc10,1fecc3b1,b7349ce,840b6ca4,877fed21), +S(cd041ff2,e8191946,8fd7ef0,c33021d2,9533cd75,64772252,c686f718,7e33166b,3f54a9af,e8597bb,faccbbd2,9280e60,93d31bc5,b366aff2,2c95e21b,fbca6041), +S(adfce0b5,8a9cef85,e690b84a,c7ccc6,8f5aa4de,ada5e265,3720412b,e1f19ae,8ae2dcdb,c6ce83be,825593d6,87f9afbe,a88af079,564c60d5,c9b88898,897515ea), +S(833a50c2,cb5507c6,60bd450e,cde341c9,64f2809a,e400215,c52dfaa0,9825df96,de85e216,493cdb4c,4541f720,201f4c67,1472b6a,d61cf8ea,3cf54ccd,a4584b77), +S(3475027a,628ea423,2d689d70,d45e975d,39d62303,282b16b,1f94a427,3d7ea746,97c3052d,9270df78,6efbd2e7,beaa58cd,f864e28,905e3ab5,507cb9aa,e3c69160), +S(cbda2707,e61d9e40,124668ef,7ed83973,dd293dfd,221396a8,d27e7aa1,392edcb3,fd5023a8,af8eff08,f0e3c8b9,b6a22a99,b3ec3aeb,7e0104dc,1f8409cc,d83d8a02), +S(963722ec,aced2105,2bf447fe,619a8532,dc78816e,2e17a111,3ffc601d,9bec0381,f31feba,259f7d0e,3c326c69,53aae60c,1e0479da,5ca839ea,77c6f1a4,9419172c), +S(fc531e1d,49d2a984,83c861b2,b299b8fd,b26831e0,3bced6da,5c4449b0,18363be7,9f9cc9b0,8d72ced1,998c6329,a17695d9,c94cfc76,ba9f6943,1c5dab83,60f2942), +S(dab255f5,b47d96d8,ec5272b,5cde4ca4,33070920,84aa4866,d53b674a,330aea2,feeda13b,a544f090,b790514a,42064cea,509bb3f3,9dbd4567,6bd75414,37579d7c), +S(ac5b161c,fcc42998,71b49d1f,8cf35bd4,dd6bf98e,5f84f2f6,420bc363,b9cac257,4511d4d3,1fa26d7f,e56f671d,7467bbd0,41358b36,b60775f8,65f7d491,3d17b685), +S(b62fbfcc,2aca0706,b0fe67f4,ed5d96b,4a65b048,f73e8f4c,9782e1ee,36189e31,6549e8c2,f77bc824,4e1a90b4,e42ca64a,5ade1768,a0996d69,8d7b047,7bfbf862), +S(56938443,5e509000,5cf3dd18,ea629078,e15097e9,da7bb5c5,737cfa0a,a40e8818,f86a1815,4f379054,11016994,9b2eba6b,477c32b8,b68091a4,4b14990a,5e8eaf92)}, +{S(7c028bd1,75367939,74871a6b,cc957d95,3813331c,87ae606c,17aecbdf,a704ebb4,4fea040b,a0ef0319,91ff9b8b,7829c0c3,93895439,d506c5c3,1a1a3fd9,e32e7e59), +S(24e966d0,bf1227ca,11eb8fd7,8dc5369d,2bb9b681,927990b6,dd02b948,fc18a169,72b7fa7c,f929a6b1,c556a372,4149a279,8d57f504,4b50a1a7,922cfddc,17308ca7), +S(a2b7db3a,265b30aa,94823577,6d5ea839,c4fe564b,97a5e3da,313f7fc4,5de617c5,5e895546,a2778162,4a91ea4e,c104c911,85f3e954,f8378fc2,bea41a3,f1cc9e15), +S(e365c695,449c9976,cb67ede3,325d9229,ee526349,e6b255f7,f4e72184,6722580b,eff99cdf,a0920505,ac37e46,b812d47b,31a29113,e491208,a19e3edb,557ac2e), +S(c3d90905,297c3a65,2c6c3d5d,915cd9c2,d741f472,4a47c8cf,35e5cf3,cac9dd11,8e9ebbd,34a7dd02,24fa6e33,193cdd72,4906dc81,a5aa41ee,4a34d3d0,4b2ee5b3), +S(6e4e23cd,ee4388d6,e8b61f8a,af7678d1,a62b3e1a,3385d278,895a02a,de4c9f00,f69b843b,ae39cf41,11fe9b99,a0287057,5695421e,e1ea690e,2e76d937,e7e32c01), +S(92eb38a6,3743088a,39b58cad,4eb4a27e,a8b08c27,444d704,6d2aa5f4,89713217,22af8d6c,d3567a6d,cf7403ef,e0afea02,48ea4266,1577005a,9afb5f2a,19611864), +S(b3c84323,e2d022fd,d2a80d07,203f4a26,f5d32dae,62842072,9663a994,3a829d08,9a899de,82329d94,83b88e1e,1bce53ed,8714cad4,c68cd491,1b71bc0a,e3839821), +S(daae5199,57a6002,8958b22e,6dbbee20,c4bbd8e1,7ed589e,b8528f35,7a4dbb40,afec8a03,321586ec,ac38e941,7fa8e342,f0542193,59decf5e,56479a39,c32f92af), +S(7afb9a56,89fd1344,cdbc5c72,62dff7b,718c2e47,a6e19ec,665af795,86ed0161,d1c2c9cb,60a191a9,a3db7e20,2ebc2eff,444bbaa8,d81ba086,6f8825f3,8c765f53), +S(8d0c4a2a,e72b54c6,236d997d,61a2a24f,ddbd39c7,ee16f1e7,d7c45b22,b4bfdac8,15a58f4f,fdad9e3f,b4d33c7e,170747cc,6a5abfdd,bfbe5814,ef0c3611,6a0a9e91), +S(24d8c0ca,53400126,347e67f3,72f19298,595b6d33,76ba2f19,2fba6dd1,7b57bda1,7c01404f,bd316814,f10734a1,559049ca,d6f20e90,d6b13ed5,f9542630,db77f9ec), +S(4c2b7a58,87a49df4,f98cfc72,22fdd832,362b8cc4,c5f4fff4,d0a20674,c9749bde,c2a1cfcd,e8636288,31a5c450,fb5cf552,c76e581f,9274e5d9,888a3a68,c37ca349), +S(2028e381,f42cc2f7,a8829308,bb72881e,94e5b54e,3331d848,898ccabc,bf971cb,16debea0,203f0709,d9b55b0d,2b8651b5,cb085d8c,8f56708d,c1fe4d33,a616dfab), +S(d11e0753,f72b7c4e,641ed50f,84dfa24d,a0baea77,98fcf062,8b2696ba,a7ec2529,55af37fe,88324646,777387e5,a9b18059,ace20e9,becd7488,5e43fee5,fa6809e2), +S(72309865,b8a1a6f3,9d6d561f,43ddf5b7,f2d022ed,95df130b,2563eaff,9008a95,f3fca0be,3ce7d9eb,e1648964,58eba87e,934d000b,a535f223,868dae11,dd5230e), +S(adca4785,cbf38a0f,28de7b36,daccc761,89b8b918,f3fafa7b,abbbd9b1,4ed5485f,880d76a6,fbcce864,657edb9b,349f124d,1b22c7af,2b0ff833,40d7a0c4,84b49de0), +S(bb43e0c0,93d58c6f,3946e58e,4727d7e2,d223c84d,513c4e2,222406bc,aafb03c2,c00f7dc8,fcbd55b3,6a95f2f4,a3a07b7f,9599736f,af099a69,e2fc2630,a2aef1d5), +S(179eb588,d1c7aa5a,24e51f5e,6d86e4ed,2e6f0f98,bf956b71,ec1caca1,b7f775cf,42f461c8,a784f643,d5a8682a,6ec9b470,455f0ab9,f269140,b1ad2376,95f64afd), +S(9144fc75,b00f8608,714f027,16b30575,be19dc01,d3689e8d,2665d967,6a077d11,b168c324,7dc6c31e,8302b6df,a2e7c053,dd849538,f9d45b87,14d889ec,cc789704), +S(d6cd2a7a,b7253b86,34231eb3,2793f062,bdf103b2,4fade912,6206e745,a3b429a7,9903e507,dc5e3a61,d73fc83c,5c4ba476,6ae92655,9b208369,bee55948,4bfe444a), +S(264845ed,623bd3f3,808ca51e,517def45,1fbc237b,e47e3ded,70c3769b,391a9f83,cb5022fe,3d535f4d,192e73d8,5d9ede23,78e0824c,e560a97,d53aabdd,f8717377), +S(2df9621c,cf3e67da,54c47ddf,81e3ba7e,7b50e713,cc7d08ac,d64f47e9,85c4f334,8058f6e8,139d8e87,cce4a389,c470e3d8,45da3537,ccead4f3,abbccf42,a5fcc49f), +S(ccfd6c4,c5966144,32d2efc4,1ccfa0eb,3e0b44ed,a4558128,c3e4d68d,949a5cac,bc77b87b,5f50d3a9,6b28d5cf,fb371b4a,36cc1360,15c548b3,f98d661a,beda8acf), +S(4e2e6052,cd35d585,6531fcf1,73bf124d,3c569bf6,6cc54ed6,9a520d42,cb836296,6381d100,e5d9ae50,f1821122,b8e91a5e,f365edee,556fee1c,2fdb6d17,3fd29c65), +S(6603d715,ed0f8725,7d9c3f29,cf86ad4c,aa0500ca,fa16a708,3168e265,b87d0255,9d2eda4a,6195e2c4,a4576e4d,5d02383,a3a01b2c,f94ab8fd,fef2f338,15807d31), +S(f09ef30d,fade81df,2fcafe31,387ed34,5a8029cb,e93fec3b,eaaeb8ac,8adc9803,f9f3039e,5b73c7cc,cf841eb8,1c15203f,ba192e,9eb39aeb,36f56c29,44b286bb), +S(ebf4611f,cb3a44a9,f9d5b00a,c559dbb5,394840c8,41a06496,bbd2011a,2508cc34,1e183324,9a610584,5d62ef4b,685152e5,c75c7525,c703f81,51bdd87c,6fda0d43), +S(31fc3226,c19aea7b,4845ff2a,ddeca6a9,36505a49,92102cb3,499d66f8,a6e1a3b5,49babd41,b1e8a6c,a728f971,d8d8cb76,47cdb94b,89767a67,fd975ac6,93f144d1), +S(be1e37d9,dadc4b4b,7a5ba74d,fb7eb55c,2b0a4fdd,81564f8d,51038afe,f716e3d2,de6f0c3d,b6efc974,975a7d6d,3c6e9d44,a712879e,4e95c612,164273bc,5de1f4b), +S(f8034e14,2425cdce,31e82b49,cde33ba8,3630d1ae,283b8b47,73960539,c67f1652,a302e3b1,860252a5,e7114568,748746ad,1e02c2e4,280bc913,dd4b4d2f,92a561af), +S(21e709bf,369cdb2d,b7f51b10,f0ff56c1,2c1938d6,18419d00,34e57d94,7b83d5e2,d7e09ab1,2e7d04f5,aab3a75f,8cf75876,ddc3cf0d,cb4b9526,ea7f755a,dfe1e495)}, +{S(638b6618,c1498946,75a1a943,8755a68,30d7dd3c,9d8a9f20,d65a7161,9c8b477f,e4e66035,e947c73a,c34a48b,b43a3762,d1038e6,893dee23,cf658a12,190d2a56), +S(4b6ce93a,acd4954e,cf0febd1,fc9a965e,ae7fbc1e,e24a12d3,a4b86573,62eb255d,8cea4838,1bdf4e5d,79e25ed0,1aab94b3,5f00267b,3ec7eeb6,63833507,583407b3), +S(e2a42110,3e8e2a80,a6451f71,b348434d,7d508023,beeed16a,d87417b8,5c7b7913,5fc15b62,124014e7,fa8f95cf,78ce8415,d46a1f97,d88be55a,76431786,8de3d605), +S(6949956,91582c2c,2e14576f,5ec0dd37,65133237,a4e43369,633edf69,933d1f75,5ca8c2a6,329882f5,2daf48e2,e291c48d,febbbd29,9ccc9ff,3ad54ed,33ccef43), +S(55d836af,2dd4b8a5,7f20eb57,6886790e,a3ccfcf9,2a2940b3,646f263d,685f62cd,7cc1ffe6,37781c72,d3cc26dd,9d4147c2,183c8e0a,95b87742,52ac47ac,19db266), +S(442a3090,46bbf3ef,503a138,b60ddfa0,ea4a5901,ae801003,f3f18ad9,9703a44e,129d9913,eff78c49,16e67c4c,cb658784,fa47da35,92ea1c98,4054b371,a275639b), +S(76981efa,29944c2d,9463fc94,67a92e1f,9403c287,dd595292,4860aee4,b78626ca,c87cb5c9,ce93ff3c,23189404,cabf8e09,996c4cde,e67935d5,874c705d,6a7f95ae), +S(42ad08fc,2a1eafc3,d793f04e,304831e,c1bae89,c7d00b24,7785d870,904bef5c,c3913fd3,6b8c08c2,553b9c48,5b90221e,ecdc8d02,6d558bc2,5fdd6ba3,df78ed63), +S(4d70ffbe,efc6254d,cee74a89,70244bd3,384b3af5,8510ca61,258fcbf8,f0c82575,ba3e19d,b022a75b,c75cbaea,84ff912b,867124d,a20e0d28,a007fb74,9a9d1c7b), +S(4ec8dca8,7079487c,adfd516,da2df139,5477b524,df4aa6d6,4db5e206,cfb14b9f,e88e5bad,c8654d60,fe1f8f6a,73328209,63bb10cd,31aae381,ea1b4d9c,eaf9cb27), +S(2e5a47c9,a47cbbb5,ef701784,34798a6c,48244df9,dab1e5d8,83c7f732,b89c7d79,7c8202dd,cf7fb6ec,471856d5,830d59e6,99c04377,c553d835,f64cb333,cc405c35), +S(3ca98150,bc5f116a,e7034a07,628d698f,67cbb8d3,74869ab1,534464f5,5e8ed24f,fad702ec,c6b738de,5b653f78,f51c98d2,1e4bad57,4db97730,58324d1e,12b89f9), +S(f414495d,9093ad22,11e001f8,b07b38bd,f5430a11,72899bcc,2c553b55,a9d4a225,bc130e93,998db229,6aef128a,5b8e5b9,9cf67eb7,713aa7d9,9fc4c902,af660f4b), +S(44e794c9,5a28ee80,f9b64193,9c626a78,4a851a4f,84f28887,9eaec508,1b60e508,b219e000,1b07a275,f63dfb3b,e977a40a,f505be1e,d3eb8194,b919b9ea,70d7198a), +S(35024622,bc17bec1,9c352280,297ddf7f,41654c08,61c3744b,13c74ed5,6673b98,64aece4c,3ec0b19c,cdbc06b7,4eb15704,50ff689e,6c5bafb7,6ae99396,12f4cca0), +S(45c4f36c,ac4c4738,ab216363,e12b2475,50b8ef09,7a986ce1,60b0462f,f8725a58,fb944806,dee59834,7d256885,3761e3a,9ae666b,9b0ee095,fea33ec7,bbce9a5f), +S(20a0b4f7,cfb58bd8,d09d008d,70e7f807,b4fa61ff,65f2e15,f00bddeb,55df1124,7961d1de,e98ca40f,4d09e5fc,52ae4916,cafdd6e,2bdb9f9d,2776239c,a3480157), +S(fa10af8c,eb2de4c9,3c0c2cb0,95f95911,755b19d9,90f17e33,69930d6,6002fcd3,68a3bfb4,533bb5f0,54fbf91c,b771b08e,e388a61a,9727bb7f,a3a1f67e,60b2eba7), +S(d417d7dd,30ebe9f1,7d52edd6,c82d91f9,25d5987f,a6f53b0e,d769a34f,e557c11e,ea89c810,619e32f2,369258ae,8ad8a456,cc36d87e,b45a42d3,83956039,62e437c8), +S(349b002d,ecee0e4,1788a3c0,cabb9ff7,c17848e2,78ef8905,63924c55,52d59853,47583a2e,7ff61b9,6fa168b5,1191b363,efa3e0a1,ce825a3c,5bb04e5b,e403b4b0), +S(4b8efc8d,7eeb3554,b5128e8d,ce20c29,697f79cb,29f61b4e,a2f7ac28,57910bb,e3cef657,7b5c0d2f,dee52c96,b6353073,b099fc9c,65688969,24cd744b,981c5ff0), +S(f356e8cf,5785b05e,e99a2b4,d202b64,2b1e98c2,57741e60,7241fb9f,d3f5ea2f,9079fd65,59d5a93f,91370d16,20ba487a,a8c6ad3d,e67f2c83,a1c335,fb5398a2), +S(bfb74aa2,15e5ce36,97cb6156,c2666ef7,1b579a50,56ff60ba,d3d5e10a,7eb2d31f,3def8a80,ddc3f407,e30d11fb,232f0e31,191bba1,d51a7eaf,b86d7f97,45d78dce), +S(658748bc,bbc75ba,30c969fa,371fc1d7,76c32a5c,7e632201,264deb36,b296ad2a,c173fe4b,14ead07c,2c6574c,8887500b,53f6c02e,dbd4048b,e69aab41,9267ef9f), +S(f51a5ca6,fd6dde25,447fa46f,c0984d26,66004c02,8d402624,8886d0d4,604f6ad8,fd4290e1,7b2928aa,f2e03b98,97252b82,d481c4c5,ad4edda6,16dc1cd8,e7ee83b2), +S(20ef1ab3,491b8d0d,a1565e2,8dd92dff,efcb88f,e88c6c2f,6b100b30,b58249b6,6814d32,7b5b94c4,12fb770e,2fc4077f,fa9a336c,9e7db2a4,bc7dffa4,286eee0), +S(d98785a,82dfe5de,343bea0,d91cd8c4,93344b86,7fffe1e6,efd7758a,90cdd899,37ad7f7c,5783d262,5204bac3,4405c207,972b7fb4,cccc3585,ee152f0a,48ee16c4), +S(3885e910,18a66e64,2d3f0c76,bca6dc82,a6916cb,1e46a858,7aff5ea2,d9390689,20765590,83ba89c2,14be9178,46e40553,ea195c49,de203c9,d175296e,a4430819), +S(c88cf650,3b50f5eb,7bac15fe,2097ff76,9c57b983,1b5d05c9,fbd8dc58,d4a9a746,b6443b76,64984192,e7056478,e9f372cb,21a0c7c0,cfcb0e84,850443a0,25ff42b6), +S(2831fddb,2ba2d301,2dedd58,a3f47434,3450985e,80e4e4c1,646745cb,1abc69d4,1b04e1b7,db84b6c4,882f264c,7bba91d5,2256dc97,fdd22e58,483dec32,5020a257), +S(5e492bf,c9d19dcb,c3bcb9a8,b7bec84c,23c359de,a78aa0a1,e0522232,df037abc,614fe5b7,cffedd76,35d371b5,2d89baf0,55af687d,e6c12d80,b221d0b3,9d03d0ac), +S(bbc64d06,681957e9,685c9864,c5f9bfda,34b4dd02,6b749399,a12bd8de,87f311e7,3c525096,dd6b7d11,26c6ca50,5064da63,f7f6a203,87594f4f,e4ae0403,fb4d66b6)}, +{S(2b00c7db,16887372,753ab219,17092563,8c603992,f501b07c,9d8442b3,721addf9,8e7c5f66,4c2493ec,77cc74ef,d9221235,f26bd3bd,6f505347,39f0fe19,c41b9fad), +S(56b9a3eb,d9360224,56267f52,21ade9f9,674863ee,4bacb7c9,ef0155ca,b36b336e,2e2b1a4d,f6c150c8,6dcfe9d2,e2836579,f82ac4d4,2f8fa4d5,d814b952,e92da69e), +S(ff52bbc2,83bd15ad,523e6d08,873a8896,9449a1c1,c5ec8570,ed532000,5a92aa3f,dd9c534b,e59d3845,a1943435,1a20513d,1a829424,e65ed8ad,60342b38,6578b21), +S(84f79356,86b0d45a,13a1ce22,7e7c925e,d80be5d9,9fd7e671,270c4c35,7254e9ce,3dfe2058,1e91dc25,12c16951,c667fbe6,83192bf3,3fc0bdec,c760dff6,730f82be), +S(db14da0a,86bcd275,71cb9348,36268bb,85c306c8,9ee1b78b,83c247a1,71c7355d,66ba535e,81e877b4,71b0b75a,6545970d,6e33cbe0,ff011e3f,d653d026,f4fff395), +S(28bfbd9e,44554371,74a4c24a,cc65ef45,5fd4d39e,b466e94,358cef4b,b0eeaa5,5f5ce6de,2925acc9,e503d731,d46601aa,7e668001,669819cf,fa54b3e3,dbb98f32), +S(a7b21a3f,a07b4049,7f9f5087,c763b431,d5f04cd0,e7b7e0dc,f9c6c664,df7c6ac7,daf23f35,b903ecc,af4f50cf,459deac9,85d0d008,3b5afa73,7131a61d,8591bf9c), +S(12fac42a,40935aa,e881894d,245b9691,cd1f6ad0,e0481e1f,444e0ccb,6ee88781,c519e0b9,e3c19fc8,f67c07e4,f357f43d,589ec23c,7714f7a0,4347be96,4ca572fb), +S(5c2e28bc,94f8639e,50133dba,9b6c8a35,348eefdd,2fdbc18f,2abb792,eb8807dd,c546b3c2,5f2809e2,7977a8e2,3a1c3ddf,36229f31,434c90e9,1386ee84,b64e8fdb), +S(e8e73382,fbe8b94e,58bef90b,aeb28305,d27ea48d,9c5f6e08,ef47e4dd,5fad6b78,d3529a2e,86240f06,a63ba03b,ce419c05,24d22622,fab9107d,aaf3016c,6ff7fe3e), +S(26b93629,ebe68d1e,878e94b7,5babd663,6fe1f6f8,659b155a,e10801eb,c2cc51d9,f4630056,b3e532f7,32238911,555c0ffd,f4951c9a,b2f45119,cb12e774,aaa2666), +S(57b3b642,431f793f,24862328,dbd271ae,19d343eb,c3b0ca7c,affe4fcb,319d8d94,1d7ed35a,5abc7e39,1858a9fd,b90f907e,6a065648,c00f94a7,75f06d2b,1cacef1a), +S(c2123794,d98f0311,c1327522,1767236a,6f45cb14,8fcd65d7,e0be8d13,2a650953,d5a382f,fcc2ffba,3917763d,ebe0549d,66f358b,d727c281,288551f8,4ecd193b), +S(16789662,9208b510,7528efd1,36036980,994d6c3e,5b34c69f,ef3b86a4,3db9e8f2,217105f8,39b0ae0e,932b5207,e8e7c190,3ea463c5,40c043aa,e4f8b106,97ccc84b), +S(3a0b8ffc,83a1702e,214adfc3,79bec5a9,753274ef,9e3271ca,8ec5b067,a5f3b6cf,2c3de01b,f27dd574,4496c2a4,75a07e60,71ee60ef,7eaf1c94,c257418b,744d1338), +S(482e5ac2,6477feb7,6c848d58,40173d87,1687c5b7,3b2970ec,b8dd69e9,3393f923,dfb3995a,ca5b54a3,b48e1dc,107023d4,dbd7a918,6adf2af0,61f92160,76e7f78c), +S(3869373d,638a30cb,63177204,bfb194f0,2c6ff503,3cb4ef1f,b146741a,f3b495ed,f2ac9f3a,ca159c7,c2ce9f48,e895c543,d3f19066,74f335b9,efdc4b47,4ccc23c3), +S(98c16ec8,54b34ea2,f08aa4fd,3ce1877d,4a36f2a6,4e673191,17f74e5d,86e57f4e,3448646f,c9aaab0f,4d9ec298,8f7c07ef,448888e7,6318e0ac,552d7cc,b59820a3), +S(1b3a4ebc,8ad1c200,2847e182,de7c9eba,f0f7a408,e2aa172d,484bb9d3,ab897b73,b93decef,69cf2da4,5c3a2373,ac2abd77,311fc1f9,21e7df8,5f5b3504,a5ecbdb4), +S(57b5b2d2,87bec103,e4aa7b96,16129718,64780441,fb5ef847,19f16d,a1c909fe,2c2d983c,d8c37a7d,653716e6,15756121,9e5ad5ab,25664967,67a0fbd8,e8180c71), +S(cd7e277b,ae1498a1,8e7bc00c,2c299a49,69f6862b,bf96e6d9,f5143db8,7b582115,f9548ddf,c27108bb,38f80025,6ffdc25e,28621c17,c370a40e,5009b968,d40660bc), +S(80615f12,82ed7a8f,bdd70890,77c24f18,c03fa395,3cbea7bd,32a26c7c,260102e7,8d54a3a2,83383d6c,a633d17d,e2f4f756,3bcc3826,10cc1012,3f2f192b,e654c2cb), +S(9b16f5dd,c8c8c8d,53786b49,e2d025a6,838f6322,700fe105,7de6d78e,92281a9e,a36aa3c2,f2034285,76f5c570,63bb1bd7,e6e0410,2e1cd2dd,f100a54e,431ca08f), +S(f1d04075,35ffd40f,2a0b59f9,14ecf368,67700c5,b33e15c5,153fa9b1,c724d36c,22a8b48e,4db1d3d1,28cc735f,99db74d9,ba7457cc,67b8fb39,7b38fcbb,153f7c0a), +S(c252ae6b,cb711704,659c37a6,f425b215,1ac8a4c6,63420eba,899127e8,1d8df3b7,8e9a75ab,c5a2cd8c,d44331ea,b07e5d97,a30c6619,8e382261,642c0e10,8f6d46b3), +S(59f6fadb,4a8a3389,999b93d4,cdf1f8f0,4735b397,9fa5397e,64df420b,85876ed5,c6e8baae,fdeb7019,23a68b71,9c88596f,60742a38,db04d7e5,76bd1b8d,1ae25a6b), +S(3c2e03c9,3f610ffd,db519c7,80c201ce,b58ffed8,ee10e21f,d1610e99,33fd08c7,d339d979,38e1c5de,7492e7d2,d64fe34d,ed889d48,54670345,1c51432f,ec6c829), +S(59d16070,f9147ce5,5bac599e,aaace0ef,24c02ea6,85249cc6,ccfbeecb,a4bba83f,8105bf41,47f22f7b,18c73941,3a85ef06,40bf6805,51c68a10,e16be920,193977f), +S(3aca1182,3f31b2b,a12e628b,604b1010,62c45fce,22e15dd0,8b9b5ef9,a53dc02,bdca8ab2,d2dcab6e,3a98e7f8,7e192c19,cae60952,fc6f54bb,d46acb49,60d51c0a), +S(261e9b93,3648c7d8,d5255219,fd0634eb,112e1dd3,fcce0a04,135b2784,e67b5e32,e0eb5ec4,30b1f9ef,2bd10916,b21f4fe1,4cfc80c,2bc179e0,fceb8678,ff933068), +S(75918e0c,a0f03b34,40cd6239,c108bb72,f293a881,a1f2e9a,73c604b8,8c451c39,7f02a925,80e50aa2,5b786d10,422f1d80,2c42cb37,27f09ff1,1f5e0dd9,bf6a6c1c), +S(42025e76,3c05c64c,311a275d,d6f1fb3f,2da2108a,39ed24be,3de83123,b1c1d1e9,dba2eec,7405b67c,a1915b13,45702062,7bfeebb8,6b90dbd4,87849e5a,756921c6)}, +{S(ef2c5fa8,b23285e3,50d7f05d,bd8c96bc,6e662824,5b10e1cb,4b659bc5,ded5836f,1b37679e,1177b653,8975790a,4d5d2abe,3626d636,1d863e0e,1db5881e,8e0c54a8), +S(a1d5a92c,93df3c75,a06f9c2b,a604789d,fd487513,62d957be,68c033e8,3e202fe7,64c1c00a,3964fd5,b35fb52,b423b285,77c8d269,bb1ffd16,325c5e0f,7be08bdb), +S(ef13ec66,d46813ce,68038fcd,541e5e8,bdbc970d,337d7b5b,9099d0e4,3fa4288,7ad7f4f0,c8345229,96341248,b1455ebb,89aaeb6e,1ae9db25,1b86930c,9f779fd9), +S(aea7cf4c,afc1079e,e61396b6,2df9bac3,bf334745,54af4678,8621e337,4c7486c7,c0538605,5911c893,459b98b0,4be449f1,2e9f98cf,ef4cc292,9975d42a,f460d65), +S(8f082b3b,6476b4e9,ffb317e6,1fec0cbe,8e389041,1fdc87d6,8d4d26f5,44c2e6e3,eafc2bd0,d6570a7a,cf8bb5d1,6cdc1020,456473c9,e7fec1b7,fc6217cd,89d0a2a1), +S(e0d6310d,e5e664b3,164faddf,39c93676,4ddd3f0d,f5e007ef,5293ee35,980ae0cc,de093cfa,ca1033bf,47e88723,4978758a,74b93cc5,2cef48a3,daf4dda9,adc79ccb), +S(2518110d,5d064422,5ead0e2a,5ac8b8b6,b1fb7fe1,55e351c5,1d39673d,dab0f6a7,84f0d6e4,b497043a,95b6af9d,e72cd502,a7b6a68d,ecaa01b0,9e0d8ff9,9d8a16c9), +S(6dc820b8,5db42353,c97453eb,d7d768cc,af9732d7,c261bc6f,8399caab,34cf5b93,30b168c0,2509e2f7,2035f60,8be8b89d,577b6e72,540f521,934fe980,7412459c), +S(bddc1c75,5bca9911,3c9ae05d,c14441e,2c707fe5,8a329f8d,feaa36ff,12771376,8c0087ca,b7688dcf,5a3cf1a3,3c27c7b9,cee36007,3aeb9b9f,d7088623,af20f62a), +S(b6e5ef5a,a84c6d2c,a209d50e,8fa8e1d7,93c61ed9,bfbc22d5,2ecf293c,9489ac13,f76e3adc,a89cb983,b6b670f9,5a7e774a,c015de5,1ba56417,40ac1f68,e3df377a), +S(26699dfe,93788eb8,d91cb601,cae628e5,75e8468e,73f6cefe,588755b8,c396071c,e5f9e00f,bcf6f1cc,cd39ab13,41cd06b0,ef2e789a,17d761f6,6a7a83b1,c036791f), +S(72f7e16f,77f0a4f7,92db2cd0,354382af,34282dc0,7b8cb290,a89a5d60,894e8090,54d32ecc,2cd022c6,c03f1379,657450b0,db9f08e9,6e2be5ab,5233dd84,62733cf), +S(f84ae7f8,a03b60,af9cc359,36f0ae78,96935b2c,534f852,8ad159bb,6c0b44e7,68f4dfc6,20a354d9,d6904bae,67792622,337e3180,ab340828,80bf04fd,f47cc23b), +S(5dea33b1,b5207880,6debbcbf,83ca17db,4617488c,ac5c6997,ad4092a9,8a7bff7b,99976fe5,ae88d36f,597e16bc,6dbbd4b4,547f4dcd,7e85786c,d10af30e,1d81bbaa), +S(31be76bd,4f946e41,7de73037,ceaa0dd7,c6eccedd,74399e14,2ae6fb2f,d2b59def,54ad8748,ef129085,dc3172aa,904cc376,e203fa69,38783007,2af33889,52cc6549), +S(b6124d0b,f603a00a,22662897,8dd0da87,fcaca5c4,fb04ebaa,81a7d13b,39f2e307,34ce08c7,4463b06c,afb03c02,583288eb,7bfa6f2d,3eedfed4,91e31781,dcff10da), +S(6aa4bd60,90bee70a,295c451c,c8af72bd,3665680f,545f46c0,bf5af990,aab5f43d,9c2364d8,25406b76,94ec9db,a0ea2f9d,bb36fb2c,5bda62a2,bec941c6,874e68f7), +S(f72faef0,e268a7b0,a9b00a57,3674d846,c1f0dcab,c9a586da,be318b1c,d2874d8b,16b3cfda,65db0f3d,1b5274cd,20b1329e,61ea0404,1f702e71,cd98708e,28c9307), +S(1d26df15,98a6b9a8,7c0a6171,767539e1,86d51d1d,cef130da,1001226f,87872c5c,f227cd82,becf5493,e2fc7635,6a37bb48,3e681a19,ab4d9dc7,92edb114,3a7b072e), +S(28690cb1,db697840,13e9eec4,d9388723,4c28451c,cf9dd51a,746d1274,b13b4610,d9bc39ef,19228981,a1ead1f8,94deb254,162fed5d,cbb58a76,6d361e04,3d8f62ea), +S(4b0b5258,22dbc31b,1966b004,4d39c5de,f2e16d5,1e032045,f9973b1e,fe83ca12,2db33ff4,3631fdc3,b3608b40,7dd494f6,ae730212,9619ae35,f6ea08eb,51aded12), +S(a5b4e205,462ae419,8fffc1e7,393d366f,c5a9eea4,e98c67ee,1684d63f,cc09aa64,d3c11017,de4ad175,17cd076f,cf6c0ce0,4d3108ed,60eabdf0,935499f9,4226078b), +S(d4f1af69,2a3e9fee,1f92d892,b14eef6a,a0ec1f4e,d4d455f3,c70bcb19,52fa9837,115c7ee,73b90adf,f142191b,eca0be01,7d5a651f,93e2e90,5a36646e,21790294), +S(c275c715,9d6e9757,d2adef47,2ee53856,dcf067db,bd4f380e,892c9832,708d46b6,70da1cdd,853a0dc8,a6a9043,3c319371,25590c9,5807284c,ae168f65,62e4465e), +S(d2e38b27,83156e2a,a8e4eac0,149bf2bd,bc2918af,1cfa2a23,d1c7136e,15dca7b,738a0fe,751ecfa3,459e005f,72b7461f,a4b5e1ed,736420d2,22c5428e,2ec1348c), +S(f8f5b3d,b3659174,e0149fc6,fa747c22,9607c434,8f9eab60,900bfe92,b23f9a4d,d89eff33,94a093fb,549fece1,4e11028a,614cdce2,21d5ac26,1bc25f32,dca3919c), +S(5e266403,e49fb860,e6ed0928,45bc0811,a214a0e,dcd6174b,290ecca9,3539d862,ab300acf,5d8b8a14,2fc9e93f,ea995d2c,d7a2bdb8,6a146f65,2b8bd49c,4e8dac1e), +S(8ff869a7,60230ba6,aa5adf91,1ba61702,17cbfdc,5ffa4018,b8a09b9e,4088d634,db5a5aae,bdb946db,80e4c207,22ce38c9,4921bf41,47eea510,70e5aac5,c592f32a), +S(f3d39b65,95bd5ab9,aeedc43f,f49bdb20,73a211f4,5ec2c1b7,72226a97,a31c059b,ea41abf,9322d733,bb5971ac,194da6a0,a6d41c6c,a0d0acaf,a53e17bd,dabcdc68), +S(18ba0c34,10169914,7f7589f9,179b94f9,daed92c9,287f3468,d283bdcc,d71cc637,b3512d25,c199d2a4,c115bd11,eb53d6a1,6ef16c3d,97be6291,5ff76b76,890ba675), +S(2cf3354d,7f96c58f,3c6336a0,6fa30c83,8da767af,48f89fc5,5ced5b40,e0b86cee,403ac306,f6c3ad55,be1ee5bc,29cdd46e,2e3d83ac,71050909,5f117d21,7ef015cf), +S(5d31d140,f754d6c,5943deb7,6aa4d867,cac81abd,9911618b,82327795,da8d085f,c25f99d0,5bc5d583,a3a72b41,4e5eac5f,c14ced01,98247ded,79ba482c,882bec49)}, +{S(e0ad91c6,6ca95326,d440f44,df91c1cd,cd3ec344,e906d0ef,51fd4a48,31ce293d,3559f3c,e349f7b3,cf66c17b,2c3fe7e6,8ba3804e,438c0816,b68ecfe2,30da18d), +S(d8b8c50c,ae9f285f,d6d9282c,373607d8,5fda59dc,71ba0066,148b378b,37440076,ef83dd08,ddc115cc,24948009,f9eb4afe,dcd65c64,b6ef2194,bb4ddd0f,ece180e6), +S(881fbbf1,a9627bd,369abbc2,edda8026,a61b10f,4161e442,530a5e36,447a0290,6a63cb8f,7e5094d3,c8beba5a,2a1d7b54,bc33005c,efdd5a1b,20d51f74,d00c2fcc), +S(36bc0df,fd1441be,1a4efd6a,43ab9d83,243d44bc,a6e108dc,fa9a79fe,23106f0e,eeec58b7,dc37eedb,4432dcff,4de7f88b,2a0e0721,da2c0a72,eadac4dd,71037ed9), +S(7652c155,c2ca8a23,7680f015,a62c7c31,31682752,a99c4329,77ccfb9d,cb58b03e,5339a51b,36ad4548,197d3018,4bde4428,b38ed983,d624bd18,a5f8c4e7,21871c5), +S(904774bb,fb8b0c12,e2b3f91a,e5a2a0c1,a92971f9,86e29fda,9edc609e,e85b222d,ee843f1,8039e251,9c7b23b3,725ca099,114b4f0,26970111,35ded92b,94445e2d), +S(1c7c82cb,fc14b9b2,cdb3c12c,32df33b6,a08e7af9,df62f310,79fa0710,f28f5f95,93471b5a,17c84eea,a45948df,80c0f56,d8684f35,1aa2ce73,ab84b3c,1b8250a4), +S(bb060f5d,971ce062,427a5630,8f114532,40ec54fe,6479d5e7,9ce81444,27f07927,fcbeaa69,8278eff3,d4dad904,836c0233,40a866b2,d8f66774,70d1159e,201501dd), +S(287c5b8b,8dc168ea,197200ea,97c4f63d,db0b620c,7f30d623,7934f856,a558438a,260630e6,ce310eb0,366acd78,bb58f4ef,27fe4836,edc8ff0f,5d5ff987,b659bd20), +S(7d4c5c6a,d6bb0f0a,47b45a35,1264f4e6,a81ee0b1,65a7e665,4b226c95,feb59dbb,e89691f3,ceb4c57f,5aabc1b7,4acd9aef,41531851,b41ec1c6,608f16a2,2243ab5e), +S(ff806f2b,9eaea4f6,47d85077,d8aa5052,9d4b96d2,1e0b31e0,7c86b14b,73b7ab4f,9acc2f77,a994997c,7a2b1aa0,79c0b5d4,c84f6715,e4a50e33,628b871f,8885ef9), +S(3ce795ba,1d91a9bc,b0260654,3450ced8,c94184dc,8a41ac5,e1b84856,e88927de,3492e696,cd1ab2dd,587d4707,ae34fd67,3ab7902c,d0c0972f,ef419795,1ad88a1), +S(299ad528,afa3f36b,c80a757f,f081a8d,c4a6ddc2,d2b57fbe,1e3d361b,ee5a5d8c,9fe823da,74eda2f,266a8e9b,331d511b,623dcd32,ef9ab7a7,f1d1cb4a,7e6fa65c), +S(bc4b0549,16177aa9,b52b29b7,cb91673c,9ffce4c,7d0066b,e4249383,4467e3b9,55bc6436,7db68687,e699cf6c,f2db9dd8,c2b9a438,8202fef5,11acdce0,ab06f969), +S(a8e8b02c,ff5de02a,9e6652cc,6fbe41cf,6e87ae0a,abb14ac5,a178b3d9,e697d0a1,285d4af9,405b03da,c57c993e,4b40df8e,82c6979,f8de57ce,4543b7ef,3381e0a8), +S(e50aa8b6,d7dcc055,4f406959,b056dac5,21a7842c,ffaf09a1,ac24a3d9,8aef5228,46656395,ee84d061,a9f5788a,cb05975d,5ffa5fae,edced564,1f81b5cd,2491c23f), +S(cb516899,98a214c3,c31e4f2,692cd7d,fad6f1aa,eb8afd1f,b29c23ce,429c224b,2292b8a4,5a89eb80,167238ef,2027f975,98a2aea9,a4460c5,3646d088,82403c63), +S(ded04c06,74c6eb16,557b5bed,4b6703d2,cc37c6aa,bae466e,ee7b5665,6693c3c9,4f3ea70f,8e75b02b,76934cc3,645d2af,eee8e9d0,8d100117,40e8a16c,dbf01113), +S(f3d0a253,edb74436,897e6cc6,621c74e1,30457b41,e0690b6f,7b2a203e,8ccf8ac8,89cb07e0,97495bdf,403490fa,d58eefe3,e79ffa33,1deb5cfd,2c548ec0,8771be67), +S(d4c66267,aa73ed55,bd68fee3,2a166a4a,4ec660fc,4cb13e18,fb6ab0fb,19a5f330,7c2efa2e,4509b221,97589483,40b6c74a,8ee2b5b6,5fbb794,7f838c47,ee03e2f0), +S(dbe9a638,f262f9a4,b3a8955f,22293feb,50ef4b32,20df0184,f363a373,d7110981,4c563e83,5e957756,5e6a8996,97510c67,9561972e,5601c1cb,2f2f789a,c1e0b5dc), +S(70c7c07,1b1e6fd0,a97b55cc,5ee34297,166f4d02,417a796b,eadcfd43,96e1b338,b5c49a6e,2ab03e55,f4755f37,e5211d4b,e23339d9,d464fd28,6781bb29,56db23bb), +S(aabc501c,6d52961a,a613fe66,96f0bacf,fad74fcf,8386cbf8,b18704bc,a1392ffc,cb72ba86,70bc3f7c,85a00d3d,76b11596,6cfa0fc7,44b31e01,9129da9,a5b04b77), +S(47f72ec6,e7820788,f0f7814f,aefd6e2e,af5d90f3,f877677d,ae72569f,c6a2e8f5,6709731b,ef2dd880,4696a6,a0661d13,fe579704,5e0a9bc0,e5fdc0af,789c5830), +S(20026251,d9413e42,47a5884c,209b144c,98e36f7d,8ef3f56a,68efd475,8a2ba8c6,9c5531b6,94ba0d24,a943d0c0,94bb623,75c798ca,c9716181,a9d659af,2acb978c), +S(8dfc6293,9b300c9b,fb617d23,6885f652,424b4f12,d04f8bf1,151d1ccf,935e445d,9a519433,18e94107,5472aa9d,6ec3390,59bd3bcb,bbbf6937,c9290e48,9da25f8f), +S(afef3520,3b558495,6fde0eff,5cfab48d,8fb08806,3c1d7cbe,d7e352c2,9d49176f,a764e6e7,bd0c8fa0,8a6f7f30,aa38d7de,fe71773,fb7ea484,68b3fd9a,8adfd650), +S(354c0a98,1628dfff,8be8ede,ed809db4,bc39c686,39a26828,ff28dd47,90801c46,8ff40299,d607036b,acd7c0ab,66a102ab,38f8d3a8,a271e2a5,20b43cbb,687cce6e), +S(da2e7eb1,1a1e66d9,5001ec4,f7b66c1e,d9f7d0ba,ea3bb326,672b9069,5cf4bebb,cbc1c7da,b9bf7e0c,dea9297c,5f45ad0b,9c4fb093,318b55f6,1e4a8951,726c4021), +S(6f780994,d0662667,8fa74156,4232bafb,b3a7f54b,a5b66507,9df32545,c192c3fb,5f11f0f3,af1a763e,4c9fdcb1,1e5e57a5,6dfe0d0f,f27535b4,4343a312,90e375e3), +S(8e28948c,729c1438,5bd09316,31ed3eb8,7acfc5f4,2a9eb4f8,afa50362,33591cec,2c09fa1c,bf0044eb,a78ae81f,bdbd4271,2a89ffdc,f7d476af,881d29fa,2627f250), +S(4011cf05,a85ef14f,1875cf3f,4f78a51,a52a89bd,a8930a4b,8e13802d,b85f319f,35045b10,45c4f71c,c762fa78,5b8d4daf,aa2a1c07,ba37d82d,ee0592ae,ad807810)}, +{S(9089bcb7,1c1559bf,e17f6c0b,91fc098,c63785fa,18a42d69,798b063f,a0930175,de229175,5e4ebf17,1047f79a,37d81b9f,9004a7cf,df747589,7365e174,ae367969), +S(4d1caeb3,41f25459,3b06f715,9e9418df,e29ee076,76c26e6a,51d8add2,5c70a5d1,bf773e4e,4151d17,650aa7ed,1d6a5505,2d622264,75c50f31,3261aea2,cf68dc37), +S(b0760330,517c0d66,2571cfae,830da7fc,a7e0d86c,1ca7f75f,5150f625,db50ad2,d8d10ef3,9c84bc13,32c2cc01,4d4df0fb,45e5c546,1849fb1b,81b7fdd0,7484d35b), +S(3db731e4,273e5b20,2de984c9,74b4112a,d0feebe3,7bb0d2c7,db38c7a,21bd8c67,b425c1d3,46b6a61f,2893a3aa,a243d60f,5563cba2,40018cca,3f80925f,71f4f1b1), +S(3a74a50d,cfbf2ff2,5c99c4d0,1a13a917,9f510c2d,eca1d5a,7ac8fb69,7eb9795,d2b468b6,714681f4,57bc586f,40585c01,e1dc14a1,a42ce887,9ce044d9,ddb92d82), +S(b9139ad5,4f44fed8,4917ad55,c49c23c7,8d62aadc,e83c9ebd,9efde865,cb1eb298,18068856,c80abc3e,2a02a441,bb7a7609,aae8d2d7,8abf4e2e,378fa3d0,a27aa900), +S(bcf5cf94,5887f183,e58a0128,4ed9a4f9,fcf918dd,4e68d70c,5a54eeff,166cb44c,8235f63b,bb06a1a6,d9ad2ae8,47aeb2b3,4838c962,9608943a,93294c6d,e21a3ab9), +S(4b598ce3,a77680c4,c5f66e90,1b76627a,27f35301,9641520f,53ea3894,dcbbd187,357af043,f77cb9fe,c04ce1f4,dd9b610f,9151d15b,3b7383e4,ecc5384a,8ff7c5cd), +S(b588aec9,2dc045e9,a95abd7e,da929837,28b5a7dc,d637001,ce7f0917,1283b16e,e682f53b,5e94fd84,914b7bed,5afc28a,30ae6f53,e12d948b,3c0d88fd,adc5d0e6), +S(eb8f5080,218ac5c3,cd792042,b59e80ed,e3857a75,a81d67e0,7c2221de,d3b7a677,c5f272cc,3734e0f4,6a5cf40,626973ae,1aa76839,1953f211,eb52693d,254a7fc3), +S(87d119ee,65a60dd9,aac3e784,22049cfb,4123d262,ac9e7473,4c9cc418,fb7ce4f0,5185ac,7bcaee8f,f1334eeb,cdf2c39e,83b8b665,1ef9d8f5,48a029c6,464242da), +S(cfd0438b,186d0f5,c64b5f38,a190baf7,35b67512,a439f486,fb79d501,90294683,985edeea,243e9c6b,d9c57cb5,c7372202,7492156f,e10bd2e5,67edd14,8603daf6), +S(52abfb67,5fa8b12f,1b0cf0d,8e85f402,47696662,64c7252f,69562590,839ce4f8,8483ab43,2d4851d7,4f432c0a,8e3863b9,783cff58,3d4c390a,9865d7f7,d1aed67f), +S(52926df,cf12eebd,3008459d,3c91dc1,73532f1d,ce3c5d0a,874ea4c,67331787,18b48fe6,1bd74ac6,4b34f2d0,e7de8920,2c875625,bcad84bd,cb3c81dc,cc86dd87), +S(695e09db,8c4479cf,4c305005,b5737ca0,63f89d02,aced2010,5600d65f,58e26401,32123a91,8bb23fd8,79715cc7,488184b7,53e0eb00,6dbbc95a,ef9d815f,3833c08d), +S(97c35716,e5aac70c,45dcdd45,a5ca0155,5962f09a,cc22c16b,c79ec272,ce1c12d3,93869464,6470f8e3,c0db18b6,2e4378e6,5caa7203,c4d6a079,a10c8182,b8eaec3a), +S(35197cbb,8da9188a,fc60faf9,71cf08fe,73372e15,f857b93b,6afd77e6,bf4db7ed,4e0efeb5,2db601dc,a539c777,14f4aede,c5ff121d,77dbdeee,7f16fb0c,4cfc19af), +S(afb2f842,e0818237,46c294b5,9ae8afd2,279e834f,100f7d1a,58a9551a,98408d49,5bf5ac43,a3609b4f,f058d6dc,6ae09fec,19a19864,6d12096b,6bd3e06d,95d15ae8), +S(a37f6113,882459,b1dc6335,26253a8d,287c9285,b7862721,f9bee74a,d2c4c09b,9ed3252a,303c6d,e01c9985,c5b3edce,1074d478,db56b961,d91fdaf5,1b1d07cd), +S(4579a503,cb12a345,182b28f6,9a3fb98c,4a80579b,2ff592d1,ab18b32d,212098d8,8c61c503,df79dcf2,6083f15b,c3ee1f99,9e1e0960,8bf6af9f,b3175699,cb0e32d5), +S(545031f7,883a2c8e,bd56a405,52719096,4aa1d40d,b22a1730,242f3064,530ce326,ecb024e8,e762b456,f62072e,5f471180,bbc817e7,54e830ee,7757ed7b,df5c9300), +S(b127fb32,bb3e193c,99d232e,d50dcad0,3b45c072,e0d521dd,de72daa9,e20e97b4,b198428,12a344b9,2e8a8d26,f7964c66,82cb3652,66ab3e28,2ba56197,a159f1a), +S(28cb3582,d312cfcc,75ab637d,66c646f7,5157dc74,7a464e9b,933c0820,2326b6cd,a87042b8,510ef9b3,ecf918d,916128e5,f946f43,6f18fd5f,ad62c46c,5882a23c), +S(8a46cb3,27efbeb6,850e3861,c4845ab1,21414f12,9fb27387,4560826d,c9116886,ab09eda1,9156f1f7,194b7b17,fce15268,ba041c96,24765ce,fd964ede,d1f05b3e), +S(b73af914,10ad56f7,d490dc37,1a2584bb,633de0f5,3f00cd0f,6b8a6019,53c7ef16,3dbf4e52,753e5d33,3fd23cc1,c839f278,38eacb3d,5980cba5,bf1be426,b27641a4), +S(b38c1896,427a0108,3f24a917,2a64314c,d9dc1759,60971135,1b2db6f7,d66ab745,d3a71a74,f80d6919,b65629f9,80c7757a,cc49c2aa,78dc67d3,d6f76d06,91a90d85), +S(6f6ac108,aa819a27,6dae862e,276b3ebd,8ed5a3ad,9b0296e0,4f8b65a7,f6a5ac1a,e3048583,7aa2140e,de381363,788d6d95,25a7ee33,9e3a3ed1,2518619b,30d9f71), +S(72f5809c,7c282ab3,4dd81851,33070d85,53999a6f,14fd753f,2ed8deec,ed7adc5b,112bf5fc,8cfd71e1,84ca1967,d05da765,801f12b4,c852768f,60afa7f1,e9576534), +S(4c348833,10f7dd6f,b385ce25,e2d6eef9,8556a59b,5e79a084,ec83425b,37150085,9c4c97e1,be47b073,5209ecf1,5f05cd8a,58ece74c,1b35a92d,96a70287,11d95add), +S(f16e4513,2291b577,ab360b42,c1babcdd,ac61e623,da85819,e9c4c73d,463204b2,5556d7d3,a2d45955,28781d15,16b59aad,941ea356,1b5c88ec,94d09314,555ea64b), +S(3580d3f7,896fb70e,d48d40f8,1b31a72b,51405574,2c2b4369,e3e7dcb,aca4ca22,e38da3af,f409e459,82098305,87aa0eb3,b2339959,75af2e33,501115ce,648360ee), +S(407e63d2,c0cd6d37,84c27734,f7e517fb,4bdf7847,296dc7c,a8714fab,16199828,2dbe5da7,4b29bcc,fe9adabb,69157830,987ac51f,389c6001,2577f298,710025f1)}, +{S(f61f644b,e2414c07,66c6caf7,5d32683d,efafb133,cb4d341d,7eb565e8,9f6e4158,2848548f,15a6e7d7,2b2eefc1,1b76e318,15ebb4b2,1e3bb938,e0c2e9d4,5ad4f7d1), +S(5b891f8,ec902550,429a5ea8,33fc29c0,bfdddf6b,a6f62c19,87a14050,a9689a9e,77901539,1ef92985,6d3e3b35,4e4ba2db,3bad967c,dedf331a,c0bff08e,f25f2e99), +S(d8c5a617,62655ffa,c943ba35,3b595b46,88012282,af068e52,d918bbec,46bec87b,9263db7f,6f74aa,df0dbdaa,7e7ccd76,cb3a498b,44de2bd5,f9b23029,2ebc6009), +S(2e940645,cd189edd,2d6cc2f4,f9b49e4d,305cfe8a,46f2a596,fbb55200,89fa5b21,4c197028,e89ef8a5,b5b6cbb1,3733e90,408877fe,7425d58,1f4bd063,ce286fb2), +S(396c3bd0,9c6af07d,123a8441,c9f79ab3,a783b8f3,fdd69dba,ba61c7ec,f65e3098,534c8657,aeb8cdc6,ea34b372,68f1c70,70881797,46b8e335,477c8525,cd17aa8b), +S(c34e6be,b079f3e8,d1355754,4246d2b7,a82d551b,740b4b59,b9220bbb,768796fe,57806a7,653ff7f9,3d7cb6,b3acf68e,aed049c5,75988fa5,f03b1ab5,1103aee8), +S(5d2d6aa5,252fc9b2,55d89773,e920891e,7021f233,5f7d0ff8,c6bde5eb,b65c5149,1fdbd2c5,6b8bd095,2d16c304,8d9c588b,2a26379a,17f748d,f1345695,1c5959c4), +S(dec812f5,745fcbed,fc36c635,76874bc5,96dde8ef,68a8724c,201b6af3,be7c6e2c,1715328a,f75f9661,d58c667e,5c5514d4,c99dc881,8cfbe702,e0c3c8cf,662e6906), +S(32499061,83487250,f65684b9,9434489d,3a83ec93,61531dfe,48086b2e,b2bd18fa,53217af1,2a25fc6f,45555d93,98fe46df,4247d38d,7b162e34,945f8928,bfe148ba), +S(d3e9381d,83f31116,ee161490,c9b5d1e5,7e086c6c,1552160,2c913315,af033ddb,97ae863d,34271b26,a4d6577a,32028c12,f092a54,8a18ae1b,a83de384,3b8fb84), +S(1347dca6,d097faa5,7c6583c1,c292c6b3,ed87b31e,9f7afe8f,d0d151ee,50ebdeb0,570a9be,e4806ee3,e30696c9,71b5d905,65d09ee6,8b4fa8e2,8acc54c0,7fabb492), +S(691f9995,af2bccbb,f556f624,b28a1da0,67854c15,4f014e92,a56a8cdd,9a43c25c,81babe0,ae44984c,bfdfa958,4dc5c677,881d1b0f,63993075,a3fc462d,e986866a), +S(cbfb62c0,b91cedb2,5a9d4b3,ada43cac,7839dd18,33174711,24688ca5,5f162cb,77c12161,e8199410,b040dd57,4d90c39c,2f1b499e,6b7c17c7,fb21438d,aff4e674), +S(53627516,8de62d6,2c792f64,f87996af,3ed8ec88,653532a8,ad60942e,cae4a339,d8449a0c,c6ae32ff,45a11652,97b3d3a0,57e67c64,42d3bdb1,ea2cbcbc,cf0655cc), +S(2a81679,7505601c,763e6f6d,f7ed5c0c,14ee7fbf,d75b8755,7bd57f3b,e2d3c7c,99f26af2,10540397,b8423da2,c4809942,63734d99,f0d642d8,96b5f216,767b759e), +S(54b2c03b,7a7ea964,220a255b,bb688767,99ff1b83,f0934e4f,fd03c2bb,51490e22,b3cc56a9,ada9240a,a3730828,26733090,ace3d7e3,91200d08,2cbfacfc,bcdb9c08), +S(aac88c8b,7c96e629,6f023e5e,8f260324,9f4e645,bd701705,8f38e9f3,a034eb57,da03ca87,b98ab6fb,e4869756,7c2db04b,7f9948d9,ea65d93f,d222d52f,6d48c552), +S(bfdd8394,fb49f93d,630f6b8d,469da38b,105529d6,70b9a1ab,e3196816,d2a13978,39a97919,4249f78e,c336b00e,475722e8,7ca734d4,3d1e97d4,d2aed074,abfacbe9), +S(5b5dc3d8,66ba3647,d2aab2ac,3338abbe,4d1ca08c,6cc6fb26,4335f40d,4dfb2331,3432ba31,46a0f15a,beca45e4,1ded8729,e6a0a49e,70315745,bfcb3388,4e1b9e64), +S(77057b28,a1d139a1,91e05ad,a8d72f3a,c7bbd198,7647070a,b6a21355,7bc0c73c,46f32321,4519afd2,f830cf7d,567aacc9,47ae6b8f,8c841adf,988e39ad,e7b9757b), +S(f6c8d1da,e28a3d23,2a388998,1b638b23,f381618f,18dc81ed,67bfa696,4cf1626f,2ad8c92d,43378941,8d298dc8,2cbf288e,86d21467,ac73c0e3,383ef3e0,a03142fe), +S(b75b5cc3,77a55310,a3b97067,34f1929,fc0db732,3265e6da,71405f37,729d5a90,be077940,4dc94ea3,3cff505c,e1aef457,bc120359,521eae05,1de1963d,b1948053), +S(a66d54d4,4b4d06ea,f141307e,27e1c225,41274eef,5c0b1743,e6398b22,fbaa4068,51b6b8a8,48e1c27f,107f82cd,d0554643,b9e16611,fa93b789,a2199b3e,3bdce296), +S(56b2f9,ab707dde,3479d0ea,baeb62a7,6cb9bf03,66278eed,559e027e,a1ea6b3b,27c47e9d,646684dd,2a54db0f,c245fcdd,721416f7,22ed568b,736e3e1b,f195b379), +S(a9642a49,83b19c3f,f5f63ea2,9e76afbf,a25dd0c0,221b32b7,6e67373,36e7f5db,8ada3766,9207c6b6,a6b6006b,5240a4d6,cdb8b807,c0c16a56,91289b7d,62b3a051), +S(18eef8d,f9e64c1c,548db40,ad77d92b,11f3ac43,60c63792,5f7d598d,7d8d5155,806db24,eefc3a64,c84da338,937811e1,20c6d0e6,9cde79ee,9957a4fe,c53d0e12), +S(d11359fe,61861a36,8b3809cc,c727320e,42905036,774d0e83,98453ac0,68d404b9,d4182ce7,2500637c,8e14b977,34fcad09,f061838d,57c555fa,420fbd50,9abf6b81), +S(7ea072e8,f60ff273,9cad1d8f,c560f208,b54149a2,5748900b,50830e3f,738b2db2,af09e54b,d44feb44,b39956af,fdca6894,91c7c6fd,f029e71b,e780f8f6,77a48a0f), +S(f53406ab,9fb1317,b038dc28,f0165abc,115b37fa,77d23bc9,e51993a7,8a15ba00,a293f429,f7fb281,9cb60b53,b2e6f07,afb6537a,39a18be,a5ad4cfa,55aea13a), +S(b1674e5f,9f194a16,94fd12d1,4b64ac8,bba69432,241aefd9,9a1c49d,23287635,83cb0060,1f5c33be,9436d946,22c3b3ce,68d20733,ee1e2392,8c3d6c14,a7cde085), +S(22b72e08,66b96344,ee53b898,ea725f7a,b5832c12,7c0881ce,862ea945,5eafee85,b886e8e9,cba29b15,be5c22d6,ada99b02,1098be69,d1c500fe,6fd2ef8b,f1ecae25), +S(9b7151af,698a85d,2246c88e,8ffb14a0,c762c2e2,64ab70b7,e30e2434,9b8370b7,fd9c3d89,46ee9d90,e7fb6d26,796062eb,4cb6c160,76df4834,eecd2748,c8a7bb4b)}, +{S(5ba26c2d,53b04b63,d260c6cf,392786d9,41a1a7c,b88331c1,149cd3b9,9c207f5c,9c7f6303,bd72850e,d4da618,3427e7f3,eee078,6f67cf9,85d483ef,79c2eab7), +S(f7d26944,6d29f81e,39a44a88,49f12184,b9f42eef,16c5d88f,60c96a28,cf0c3e48,e7ec965e,d0a966a7,45087e09,a058421b,852c8a7c,3790a3ef,7abc6ccc,e17c6084), +S(98590b7d,36bd2ef9,37ce788b,22cab951,d921724b,87c3ad83,8263416f,b5a67dc9,b711c21e,5af72a36,5cc1b220,7ed09ebe,be918555,55e9239a,e9b03d75,c0261d5c), +S(92e1cc4e,5f57514e,9ed13535,5f3e2cda,b0b22f8,8f56a972,a657dba4,7263463d,14d296bd,452f2faa,7d6f42e1,550fe35b,3c47eb2e,fe7636c6,2eef90b2,e7822da8), +S(33de9b1b,e153bdd6,efaf9d1a,30aa9b3d,faf26a32,4486b6aa,ecb1f958,f11c4673,7ef29223,4d3a565b,c0f0e295,deffa3c9,a86a6bf1,933a084f,9334b790,51eb0270), +S(f9fad0b7,e1dfd4b2,47cd2cbe,bd863e1,95b3be25,6cf7a707,5d422b9b,f5631ca6,fd5262f9,e6ca0cee,e1c7e531,83d9f3c0,7ac518b,c024681b,56c06a1d,1826f5ef), +S(455ec5ea,f34c02c6,961469ed,27bc7883,c07c9a18,663e22ca,83830a66,569b2b36,4dbf1b57,a7de2fdd,7c0380c2,b38fa5d3,697a5995,8ca0c0f7,6405244d,bff4c9), +S(940fa05,d96fb400,bac8fa39,e696c536,71a490d7,c98b3851,ef76ed35,c62bac19,b6de17b4,1a045978,5755497f,1c2a953f,17554b4,20f2ccaa,9fcfedf3,5afb9b46), +S(16012402,4ded6478,72374af4,6daf9c2d,a9000841,9a7d4672,98b627c2,420981b,7c2607e0,a4b86f7a,d5df7371,60987d21,35d2ce2d,bc422ab9,b643d080,26f84323), +S(caf887e3,339046ff,42c629ff,c954873,2c629ecf,319c44be,6701a9f7,c81bf842,d253a688,3b3d51c5,a914ffb7,46e7ab68,70c2b1ab,5b7e46c1,7a5119e8,4ab6c878), +S(41a5b720,595bfc66,18406547,d59ec09b,4efba0ec,5bbd3191,9e9256ce,f40a7afb,87ee1be5,2233ba8c,82dc06a3,6fd0a1b,4ee8d7d3,ce89cb56,1dc96c19,dad79613), +S(8bdcbe80,fe8533a,174045a8,3cf9d89a,ca438ef0,8f6393cf,6e24d923,edb02586,8d21379f,c053e8dc,c628f0cb,83a7782c,b4e946e3,ca88d467,36232762,fc6f8fdf), +S(409a4482,6b6f0ff6,36178d65,aedd64cd,2d28b39f,3e9cd93d,a0afe712,b75fcd19,25a3bec4,74216dae,d686825b,bee6aac,487a6d07,606e5aed,7c3032df,f4911eba), +S(b7f414a8,4c0af927,64ed5b52,e96dad38,6995771c,2cd90af1,1986bdc3,cbeb61c0,702b0a68,4e93f0a6,26b807d8,8049db6a,3e65001a,d75a476c,e4be230,89574e8e), +S(58b0cdd7,bed4f327,bcecd493,d835c0f0,e45f6fa4,3687d1d2,f19de285,5bcb5c11,21b0a478,2c1d14db,9c67817d,7b23db21,a96e456e,62a85c3f,2a02c76d,78dcad10), +S(c75cbf00,893447ba,5b3f8462,9d6897ff,64be841a,9a6bb714,54adb849,8df03900,15f68903,ae20ae4b,9b3fc7c4,f8135936,c09de15,18317dde,bcf66190,2db79f72), +S(e6258fd4,b63be23f,38361a16,cf3f81cf,f2d7343e,515b2d0c,ea0bfe38,6d4400a9,aedca212,9b73e49b,9757cd7d,a39a1e92,f885b267,a188521b,32089ae7,6d351eb0), +S(7c61b66d,d76f759f,be92708,8b075147,2ba10db2,eee4f0a4,2eac1ad0,d2dac3a6,c2b79de,70372e1a,6c9449af,2612e34a,8e101cc2,81ef378b,97cd77aa,bff004af), +S(29c71194,bbe41f4e,b2f58bf5,799616c3,7b247283,c993bce4,630929d7,55f7c8c4,c0fb083f,d68f63d3,599c2da,9d0c1f03,b6903545,a47581ff,3caecbf4,359e0235), +S(f1cd983,5bd3eb61,f8207495,48da075b,ff4191ff,d5b1521a,a1f4413f,2173a68e,beac8102,13b643a9,4658cdbc,71713894,39b72abc,f8644697,2fe6310b,4ff0233f), +S(94f2137a,ae170855,3af3dd45,8f8fc9d3,c1bf07e4,35a62798,25d5b93a,37380144,e952d6af,b27f9b2b,80ccbe89,59fb8b15,5fe1b2db,f3ffbf14,cf9c1fe9,b8e8209d), +S(f4f0cd2,e28cb8a1,9b469b18,90033912,4a40a39e,67ae1642,a3a677b9,fa1a9a3c,75412f04,5c41770d,73d7cd77,bce0da96,1e6fc69,cfc6cb9,8f691d43,dce1e548), +S(15ba2fd,b652ea98,f2b326ee,e5e1629b,ec8f8e7a,36078d7,cb8a80c8,c943e98a,db416844,cf757376,cfcd5a9a,9a318b51,184f8c89,fcda3d97,e735c120,43d47c35), +S(5754903c,ffa8cb6a,3ffe3488,e484c498,69163b77,7c07183e,8d2da037,78b8da34,508312e,6c2fd008,fac12bd,afdf8e50,1940a81b,d05efd38,5277a85c,ccf125da), +S(3bc76f6b,8abc155a,dbba76a1,9c0fef85,373bb1bc,9775f431,1b3ccb12,9c7fb29c,48036702,aea467ec,daa8b809,97c41c07,9e38c414,f798bdc3,a531b08b,fb4ae303), +S(2992c410,306d3d40,313ef69c,a2e3383,88f592d4,a9c2bd36,ebd9f51e,883aa33,cdecc5df,41cd193a,ecb26700,baa42486,a0506372,d56de3e2,2fa09156,7b525519), +S(baa7d83d,6d70a528,e6392adb,b2af797c,72772b92,ace96a25,90d65c37,b0ff1bc,9943b555,4e44b480,28815d8b,e50189d3,6617e9b6,c8f07393,8309e04c,9978fad7), +S(935488ea,4c88c2e3,cda6c0ab,5b42d519,e7fabe09,fdd3e36a,7c78c9bd,730612fe,705c8f8b,228be0c5,539eae13,1f4f4bdc,2fecf6ce,6cc567c4,dc692af9,7c1d506d), +S(8edeb68d,e63c35e2,5e36bc8,61445a63,8b0637ab,d14557bc,f0b0648b,db43f86a,d20bd0ec,14ef4f35,68954130,6577ef85,baeeeed1,c1004130,80687a5a,94a9e9a3), +S(9a39617a,27c2ff2d,9869acff,b22fad1e,a7d04271,be154547,43234f54,7f21924b,917bf9f3,fe0563a9,8daacf90,dfdcd8eb,e657f023,3fb15711,79bc5ce6,e6f5dd56), +S(41dcb02d,21137ea3,a179b469,199f9ed7,9b831923,68719a4e,5c727ce0,d42e95d,4669d53,82147266,8327cd6b,31c21b80,d3394bf7,fa29a43c,2ed7441,d866f5e1), +S(d4e3e3cc,387e0364,6688a62d,9390d585,a69ff43e,1060811,431dea8,d868355e,3309af2c,b3d7ca6,55334f2e,c53de6aa,debf5d57,1618ecc2,9dc9830f,ec46144a)}, +{S(90edfd0,61871350,b7f1f029,c4114190,b050065b,2030a400,9a8a7a6f,4b92aae8,872d4f07,5f60ae2d,dcec2f12,98a22da2,53d54de4,fde85560,690dde89,1628db56), +S(27e3ce53,b4258f97,a499f408,ecab24f0,60aabae1,dafe992e,5a34952d,5e6e486,d393fad2,9be684f4,7ecec306,332ad969,75b79d29,b5863d98,5f959c4c,b8ffb442), +S(420f1078,27c75c95,d5bc657b,a46cbe2b,415a7d42,ad62cdf1,6c84ee89,22215379,8b257a28,e0b15fcc,ae0b555a,cdadf4a,be93bbb3,a208ee45,77710a9e,d58da7fa), +S(28859abc,b60a95e6,b26c0996,566bf798,60c1a194,2d3342f7,9655f286,32f9d5df,2a770426,5eeca5d8,87840cab,3923d868,aa7b7b18,f9d19941,738ca006,54ccba6b), +S(c33c317b,490e2266,2649a021,e87f6596,3897633c,90be208a,193f1d52,28614059,af850be0,d18708bf,d0e1f523,c1a4fda8,9a6c156a,55f82518,2bd99bb9,b999a358), +S(2333793d,b961d3d6,740fc725,6cf9d833,81b5dc92,85b6d83c,5c343aa8,5baea83b,accc199a,ced3012f,b6db99c4,7a36c30a,f88e7eee,b62c2ed4,1352b488,ba0167bd), +S(4834aa89,caa9c25,a99ee4da,e4a64c15,25a5d74f,9ce573ab,ff44b63f,c3a578aa,fb189539,448a265b,eb87a268,b71a18db,f12fe8ac,e502720,c83ca156,c1cc7a39), +S(432cc05f,c78b0d56,e605391f,e4708bda,a1ff3edc,96a729ca,aad3cb0,300c4d4d,6675d8ee,ece8c078,e1bad373,247ce383,d4c65519,4a6aed20,a7ca5eca,34a89c30), +S(874fda6c,b284ca2d,a216bbda,28249388,88da3968,7f615ab,52c8e61f,b72a1fd,2d7199e2,b0b88f45,18e6eeb1,240b2ffd,a9bfcee4,6f754a4a,3db7959,dfe857e6), +S(7fe21a0f,3ef67d60,1de05f67,2b163285,a5577948,ee78274b,19fc35cf,2d2f6801,62fb2ade,5e2fffe1,28542038,91a6ea73,aabfa35b,1f7fb000,95190adc,de6663f6), +S(cd0540e9,efe497b6,2beb2227,a2da819,a1ac3bed,8eae24c2,6e2991c0,a707dd69,446c3218,7d0c9229,d65dad2,1392e4a1,66445386,4a5c1620,bf768fad,20a45c06), +S(a533c295,74e78024,52218573,66c30001,6159d772,f5bedcff,28d7f7cc,3051457,b61a106e,e0166d54,5e1b945a,f3e4e285,31a34cb8,56a34dd0,cd21184a,9555eeee), +S(5e144f44,ed88845a,c089331c,eb58811e,4c164e02,5d1758ee,51a7a522,c66deb30,ff95cab7,597cf62f,e1aa8df8,a2cd3844,d71ab4dd,4eb02a9e,6175077d,261e2540), +S(97487a40,9562ee2,7620fc2b,c5bd55ac,6509d487,8ab41257,53884b97,7c5a84be,e52a282,1430c540,5f1143d0,62b69faa,16592f02,cb9b8602,d52c9fc3,70769091), +S(906f9ac1,d3db4690,d74771b7,f1940679,b0de7731,a68d7d35,89caae34,c3760eea,6f2be7,2275dd5,1e77a066,b8d3c303,f565cb97,b8fb0dd3,14445d18,876665a6), +S(4c355a31,d17617f3,5d4066c7,a125b2bf,1d6f77e6,27b585ba,2d271a29,a88c81b1,6a686e69,237b75a1,a1ecb86f,b715e858,35aa0686,e2ef10bb,38b762ca,5646e9db), +S(15aac1a8,9b6b7629,57375d4e,aad87c9d,e1fc2617,89e57d29,731fe96c,1380140c,2968c0b2,2c3dd83f,3286d37a,639bcc14,3d89e75f,cac1da56,7e07799a,62af1008), +S(4642f29b,37b87118,65767998,d00b41b9,fca6718d,bfc55785,1c459efc,2ea15037,a1ded31c,be33cc1,425df851,998ddd11,1518ed13,f84756c1,c7cc46cf,3f5e9a72), +S(9554abe,9e092bd2,c4ff46a0,abd0b7c7,fb73d85f,1c01fd96,83146559,306ea727,89e2c07d,db1fe6b0,9872ce91,66ce9ca8,1124986c,c7e48e09,f80aa3cd,70987711), +S(1c0977a,a773c56,2e36dd15,58b95fff,d35b4dea,ac464011,ad7b79cd,26227238,e04ce4c5,b0b165e9,87dfef97,d32094ea,3e86e6dc,33a4c96f,c9470336,34b0db68), +S(71d44171,60361c39,6295e5cf,b1540ef2,1ca046b5,98645a23,e8c9772,ac21be4f,7122d5b,32a654a0,1476a47f,d3317a25,ed51536,4a21253,f4068dc8,14660c55), +S(d906f59b,4d56bc12,f26d60e6,6fc31733,e5450707,89025ea3,8a6193c8,520ddbc7,cd7f414b,c6cc79aa,4c65b943,ff914234,a9d85cf1,9853be59,2a71fe1d,dbb20163), +S(11b7dfb3,17dd5c23,6b8084d4,f3cc157f,c25c0e70,8248b472,240963dd,9a3fbca7,dd2c8caa,2a2d14d7,fbec267c,9fe87ab2,8b1ddd92,dd100449,f75ef1da,97d4e5e), +S(3ef8274a,fca8fbb3,1894d7a2,d1ad59a9,4951b21,328b1e84,ecaa6df9,cc1ef473,2e4f0c04,f5da671d,4a2b641,46ae749,27bc35b5,98a54190,3883469b,3e7874de), +S(a861fc27,f5e6300d,ec0fbf6c,3315d053,98f90b84,2422992,bdfba11b,1c1c7e34,75a7458,5d98bca4,e3517897,afef848,8e524168,a586d8da,18834171,4b51846b), +S(9537019f,57d7869,2a358758,47e885bd,1594a426,4412c595,62eea9ba,4ab34de8,21bfd84e,a66650dd,79cc8c13,7217a351,57b9c046,938f20b7,246362c8,6637d5f4), +S(71c80c38,b1889d4f,507132a1,87af0c91,79994b84,1b816c8a,6d130a,df1b500f,8de1f76c,100e75b5,1572da6,d08c76b2,10cdc447,cf903e0e,2b00e002,5dee0ce2), +S(2fa9ce2f,59865d10,17880d74,d31cd446,5c28ff56,50f29e6b,d74a810,977ef9ec,6c5a2073,55c0dd3a,b994778a,6bd02b87,80ba8e1a,899330ee,cd8781b7,6e15cddc), +S(96ca6bb4,bf74c748,75703386,ae02dc29,13329d9e,a5395892,df1c6f57,4a84fa4a,fcb510b6,dcfe8da5,690f8fc9,4dea8ac0,e42af209,35c33347,b088cc79,52e98b1d), +S(36a066ae,694f2645,25cba884,956ebd46,ae568acf,11664965,63cee00d,a32f2199,5d1e975a,856ebd1a,cb1fe254,101e89ab,ea089e8a,b38bbd0f,1100e914,709fd965), +S(4922879f,800234c9,63f4b572,d236843,4c4da5c8,ff741982,c3d1e341,841d1309,9b259470,24b5f4cb,97c68d18,f7f8dfca,1e57f7de,63208765,2ce15770,98f35494), +S(ee27e2b,acf95f6d,dbb5ebae,bbf181bb,43322a3d,6db87e78,14e57a3d,41b581e0,3d6a18a,daf69ae4,88ecc9d8,7d6b1bf2,c8d65544,3f4b45b4,c5a0ac51,7b1dc3ca)} +#elif (COMB_BLOCKS == 43) && (COMB_TEETH == 6) && (COMB_SPACING == 1) +{S(e3adcb1a,fe947e6e,7cc4f5a2,df78310a,b235e2c3,bcd75eba,1904de80,c8814c50,e0b27ead,c4bbb9d2,37dad580,6e366674,4a9f9c3d,e024f2bd,1edb11d2,fafc0a22), +S(612c2ec6,f0e9c4ec,c2200d23,ddca77eb,d003be35,61e52b1,890bf846,3bb53ea5,9e944d7b,dfc7a952,c1c5ee15,485d7199,dda19551,2d729628,c215a9e0,285f656a), +S(42053dc0,9f90a7f7,86feca60,d68a5c3c,789e44d2,3479aa13,2d1a427c,621373a3,b338f891,f3930ec7,738669bb,3a29ae2d,637be08a,954f2a8c,acb661af,a660bd22), +S(4d227ea1,5194ed57,10f8ea4d,a639be04,fa68ecb4,f3d2d9c9,43ec32f2,80f74051,28a94075,bda4c195,40c20493,b5391df7,166b1264,b957fef9,683cfbec,4c6e6875), +S(8ec4abf4,d4db3b0,2b0712dc,ef54a405,54b6cac9,3f88fa9d,d8cad4c0,9b94eb1e,4e37e159,517346ee,17e948c4,a17912b0,b29c303e,497cfb38,16796752,99aaf9e8), +S(ab186398,117fb83d,db8b9392,cc888fe2,50d2f604,5a0c3f89,92d8a82c,382175c0,79437224,b3b1604c,fae64902,e3030448,51ef17b8,9af02d7c,54a92c34,7fa2abda), +S(2bd09ae7,1e8d85a2,ba550bf2,9c1787a2,3d2c8985,e2ed07bd,1d39e7b9,8ef8135,ddaebb19,195bfd6c,a44ce82f,b7f3c65a,8af935ae,52e2d2fb,33cc231d,c4b16082), +S(e6da6560,c8265e7c,8f62edca,78dc739b,74bd6543,44a939cd,bac0f489,12b920af,147f5ce4,a98377cb,981dfaf0,1a1e4740,238f1c5d,ee69cfff,a54f3aeb,e53980eb), +S(7df5abfa,d6b46a37,30bd5892,69edb6fa,b70a0d31,936c0787,407d5d6,96506263,bc5cbafd,1f5fee67,1aa449ff,bacefc67,cf7c529f,86100d7c,a8160e4c,376c76d4), +S(ad672823,cfe3ac01,50038d30,81a1a109,d8629b4a,a4e26779,373ee0db,44a466d9,c288397c,f91157e6,770c401e,dc84b328,87b22534,d11e11c,c8415a4b,743fef9b), +S(72032cac,3177c280,ceb3076d,7f510405,2413706c,956ecf38,acf410ad,a12473a6,8bbaf50b,95797824,2994e6d0,a4bf6d07,149792bf,f2a74847,1095f845,bb332036), +S(36a1f78c,3bebf8c7,1fae5e29,cf08485d,d9debdae,348a20,ad84ba5d,4308fec9,842f57e2,e900d07b,eefda7e5,9dc40139,c5deefcf,11c07c42,4629c59d,593e01af), +S(5f418454,72e80d51,1c1b8bc2,b6b89224,9119ed43,5b915809,f7b26d01,8427f579,dfc29fdc,f3c65221,a6615262,cebd9a14,acba91ba,cca22ec5,d84303cc,1fe0085e), +S(5577ced2,f6bf41f9,503aa4a7,c0060fae,6d33cda6,e3c8ec55,1eaec315,bb91fedb,858ded64,6c3d6231,87c0967a,84ee5253,2b21c4e5,b329bdbb,76f6a6d4,93cdcb4b), +S(bc74b56a,c94ef36f,2b356bc5,dfd11d2e,7a371087,653ad607,dbfcfeb8,27abc502,d57d74e7,39e758ee,96a422e2,f1fa61f7,4f6308f5,71e6dca6,3b0b0103,e83cf1f3), +S(727ed91f,be4c5086,50a0d365,b28ae4aa,c9434c0,735fce3c,7b3ebb42,f4be911a,8c595547,5e627c22,6bfa855a,22ebbc56,d3d0b331,9120d8e9,13bed868,7d3bf331), +S(6286bb90,71f8887b,c4fbb3f0,a9ecb19e,fcdd2cf1,5e286da7,1bb60c9b,5ff5e644,73731ec5,ea3e537c,c6060ac5,dde716b7,2aef4117,ba747b12,1c26fc9,eddbda74), +S(3905682b,72282a78,2b8d8dba,72cf147a,de0025dc,a21521e1,ea989040,c248852b,5da3bf52,dceaa14a,a3534068,c05bb015,2cf9c722,cc80c56,cf828ace,d96fc390), +S(561a2ccd,ca12b67f,dad28ee2,c3cee78a,cf811766,9e4a2543,c81b1ca6,eb4bd16e,3b386a9d,553c2746,893477f5,17a05e99,bbc8ddf0,896249e3,85e406d6,a57b9ed9), +S(75bdfa06,6a1a42a7,50f283e8,3ec91cc0,a5b68829,6e6aa24a,28a61e33,65f378e5,c73224ec,797d6736,c1a541ab,34523d91,e1ec3754,fe7fed44,474f9cba,29f305e5), +S(e881a840,847aa2e2,2417cd3d,3e798c56,1e630290,5dff6bf7,754d9419,98d401e3,8816d775,f1555452,f624e45,710a240e,90fc5e23,7536d217,cf555349,b5e31bac), +S(1fb527e9,4e9c70e8,657de745,8b81ef9e,e3c2b4e0,128a675b,f7e28980,e18b201e,bab00a09,1145407e,693d5353,7818bd30,49e1f364,757d228,58b8aac5,416e3e78), +S(1c2bd878,b94169da,722a9de0,c4e317ce,a8802aa9,60458301,11a89d1d,9de4270c,95b7d99,bc3df31e,f0dbf17a,a09ef148,71ae6c5d,870ebe75,1f52aaad,a48dfcc5), +S(41f7fa0a,9a59513a,e221e3b8,4b91995f,c9d40eb5,d120a6d8,e663452a,d92099c8,813dbbe,92ec4b62,25d1cc5e,5820ebb7,dbdc2964,d5dd1ab3,deabceb9,5e793d32), +S(e5cbd627,89c6a843,25a24407,89b88dbb,1dc55afb,9e8296e6,bb8af7de,57a50e60,2cf01cea,ae4f4fed,46c4efd7,86ca5e4d,ef5af524,e9393d74,e9dd224c,604b9408), +S(eb3bc68c,623b1f46,ab905412,c7f2d588,fa25abb7,7a7bd782,ba9bb3aa,c05a70ae,df9f46e0,5dc1d126,2f72ef3e,8db01fbc,11915af6,4aee0c51,da1cfa,b4d15ef0), +S(5702fb8a,2602f41f,52699f68,8d4b005a,128762e1,1dfd13fd,22ea751c,cbedb2ef,a77105b3,7af534e6,46f58c3,b02543fd,9e0666c1,58051952,a61f8389,73f5847), +S(66954eca,5434263,4036fc7,fc0fe33,81f5195e,88433bc3,2c5a8a60,341e2859,d8b1b14,40e9f123,f39c8658,f9d64e7d,fe4071f0,ada879ea,42eebad6,4d37f4fc), +S(592152c3,98d6c719,636a03a6,dad64246,a5a6814a,a62c156b,ce5332f,6759b031,8d22d1e2,d93dcccc,889f3b6e,dd5e2098,2f5586d4,bac06842,d689a37b,4b845c12), +S(5699b93f,c6e1bd29,e09a328d,657a607b,4155b61a,6b5fcbed,d7c12df7,c67df8f5,c147ee87,14325497,6b2e534c,e6902748,2a5c33dc,867732a5,8338f05,73368388), +S(c62c910e,502cb615,a27c5851,2b6cc2c9,4f5742f7,6cb3d12e,c993400a,3695d413,e80c2522,898d8a22,2c4dc0b9,8dc9ce88,740fe252,5144656a,c30f978d,dba83c1f), +S(0,0,3b,78ce563f,89a0ed94,14f5aa28,ad0d96d6,795f9c63,3f3979bf,72ae8202,983dc989,aec7f2ff,2ed91bdd,69ce02fc,700ca10,e59ddf3)}, +{S(efbbec14,ff6d7e18,a8015d68,ba3ceb19,d4cbfbb8,a1bbc09c,ce755a23,e9d4b3f4,a76faa08,2b02b8a4,405573c9,5ac067f3,ab936127,24bfc14e,a27f923d,3adf0133), +S(f02f6744,a0ee7b0c,7bf0abb3,c7ec0a5a,3275d109,92be2893,7e9ef649,23fa932d,955f3630,c5621787,13e6d8f,39efee26,d91a0947,8da36db9,4ab4a89f,aaf9019a), +S(1c6f9f0f,d6ecbca1,fbcfbe9d,1f3d2476,dbd3b6ca,ac8e18a5,949b993d,8c0063e5,e3e3770e,33081dc9,5125d69d,c631450e,5494d21b,2ddf48f1,fbc3169f,3cc1eb91), +S(2062725b,739b793d,c9798397,dfc7b1a7,24ebe8f7,5e5654df,536adff1,25970841,22f3e3e5,c0201265,5e6d8e58,b8ba633d,9a9216b5,445a7f78,a2605688,4a5b6092), +S(57ffda66,e0c29448,7a1570f7,e2f5dc58,ecf9b906,5f374046,5bd1734,841785df,22ae8728,a8800436,1264c380,3beddb65,a9dee575,6f0cfa97,c01dc047,3c806def), +S(4b49fa7d,463cbb43,b14928c6,7b3a85a6,8132ad9c,427d3cc3,bba76d1a,7c9a69dc,7e7e3133,3782b30,5c7c3bd6,94e3c306,b3f9829f,86f76f08,d44b1a76,a207f2c5), +S(411a3b18,c9b638fa,38a0e811,ee370f34,5c9476db,61df1843,863d6d7f,4e803ccf,bb306f97,e97e492d,e74afcd0,a771570a,8210b51,9e61df78,4e6e97e0,ac23e109), +S(c8227510,49de1572,37afdf55,d175196d,5d315001,3670b478,a0255a4c,ebe95075,16be5950,a3f12be9,5905fb52,8d5bd93,23eb5908,211d2e8c,26204b32,556c5c45), +S(e46bdb74,8692d0fa,e6fc9f50,6685487,31d61f8a,5717fb88,4e1f7a41,70e4997e,35398e06,48bea42,cc48fa4f,2805efbe,6bead663,c054eb08,2c15ad46,c0611052), +S(d18293cb,d0902dab,e4c014e1,22969601,84aedbbf,a01526a8,6978e144,88ca794f,3a5b423e,32c1d2f4,bf754f42,9da3c9b6,84bb798c,ea73f637,1777ba77,1aae6086), +S(7b9cbbfa,a53923fd,e9f50845,3130101,3b17548a,8097433,79d3a526,d1c90c31,3fd7b71,5b6801cf,30fe22a9,8b7895d8,1b483f6e,9fdefe7e,6c59fec8,fb9786b4), +S(ab6e185c,be9ee393,5ad6278c,167396fa,aa4d936,80524d16,27ca8e93,48fce67c,7154007d,3f96ce60,d09499a5,1262c7bc,3ab5e9aa,929e0594,994a9671,8f912987), +S(56ffb418,8b9c9c13,4a110c03,8df8636a,71141ff9,8448cb79,eb6dece8,a28b65b4,1d728ed5,23ab821,ac0c40e2,b9348e27,191536c6,79a73835,8bd9b3c,b43dcafe), +S(bdba1eff,bf6af786,dca1da26,cc226102,1f95d56f,245298c0,b87a40e1,fa9a0cbc,fa18673b,41f765b8,25d13f2d,7963f1c6,b3308a14,b033fecd,e1d0d597,583440b2), +S(d9a4a7f5,5b3af93b,1c49ffa7,4f8154e8,23aa1477,16b16441,39fbc86b,2d9346ef,19ca90e7,538ac3d8,a28e1aad,5d8b1dcc,756f8a84,240e5769,a0f561d,f53289b), +S(ee5c17b2,74c78b87,9eda9341,256b1506,25582835,60a0bdcc,c8eba320,32d58638,d7d02f4a,b81215b1,7843e3c6,abb63755,c7e05d20,6c61a4f6,bb08d1b0,256409ee), +S(6953ae81,7ec599fa,5f739bef,dc4cd8b,4670eac6,912bd03a,a3fbe91a,5122ba0b,61bca3fe,36245ced,31cae918,fab6d463,50856947,f64a3be,d0eb62d6,f9f16059), +S(3bd721f7,59f7c3a9,93474472,4ffd3e34,503cbe45,fa7fa5ef,40a5a173,b8bebcea,bd7cbfbb,797034c2,d293aa64,1bf175dc,74a44dba,84b8d99b,8182d2be,6512ef2), +S(ab6e36ae,f5b7ff2f,fd2f42f5,8c408b7f,3ac84253,e1d8a43a,55cac222,678dd38e,ff0dc59e,51e504b2,9a0ba824,3ef26eb1,2446f628,78293da2,d924028c,21f57342), +S(bf1a1f6d,7f73b09d,3efbd73,eb9ea2c6,23e17911,9063489b,42fb1303,7b53fce4,236566ae,5371fc97,b5449b9c,2db32175,90e02412,b44539d3,bda7a814,3cd4a634), +S(fa0c6aa3,4c4825de,304cfece,37a20bbb,f72044e3,94cad202,c9e1edc3,b288ed57,df8e64ba,5f5e8381,4b6891b6,14dd4753,fed5f566,956a6dd,95540bdd,25c73995), +S(d2ea634d,ab56961f,52e39ba8,ebc5c150,ba9eeb1c,6178aef9,64fa97d5,e80581c6,2928f71e,a09a35b9,6fc1976c,f6cd3c1c,7d1fcea0,2142eb80,9666917d,c9a0621b), +S(827d6a36,697cb2f1,cf19e27a,ac30c06d,20d818c9,fe869309,6435f1f2,171c9b75,53237d41,3781a1df,d0d977c2,9690d488,b051dc2a,841ba226,c552cc28,12ae7caf), +S(59dafec5,4df05695,e123004d,38d9aa12,6a06c399,e5215245,5392e5e3,f1a47dd6,ff7d173d,ceda39ec,ca8d2c95,ab1658a8,6ad99618,e3fdb7cb,b07b03c5,2f96a86b), +S(5c4f5b9,2acb30ee,8c7ec4b0,ec577f41,a9502af9,a5a384dd,3386f230,3e62a830,8aea5f7,145de3a3,679c86ce,72e8b36,f3d6ac81,bb1d2043,9d719c32,ca2f8b30), +S(38add3d6,209080c8,efb65551,3d9420aa,457f06ac,d3ec84e8,db84e208,a0664ba9,ad95a891,c60f01a1,5fcddf2c,923790e2,d5596334,4d83a21c,dfe5f6bc,4c2b32b3), +S(9038876f,21c3bc14,111d5f6a,4749d07,34e40a53,7d398c68,809355f,764cf1ba,da030216,5e661aff,53367578,4a4d3447,707f14af,cf0d771a,53e8e687,b9dc29e5), +S(b07d3e8,dbbe686e,5e163725,8402cac3,e1e4f29,fdf154f7,bf008c5f,9969da10,c8b668e0,56bf8173,2d9778e2,eaa069d0,cdfbf826,47f615c3,6d0b311a,b2e14922), +S(8bc89c2,f919ed15,8885c356,844d49,890905c7,9b357322,609c4570,6ce6b514,2cec0c32,283233e9,21889013,c4a76d3e,e8d2cfa9,eed8890f,909c0b30,5736aad8), +S(308913a2,7a52d922,2bc77683,8f73f576,a4d04712,2a9b184b,5ec32ad,51b03f6c,b5a4f6a,bc0141a0,6e1cace0,993fc8a2,57ccc015,7d42e0ed,9f54a102,1701afc8), +S(3f0e80e5,74456d8f,8fa64e04,4b2eb72e,a22eb53f,e1efe3a4,43933aca,7f8cb0e3,34992828,d693436e,16f463f7,b7a2fe4c,6afedac5,59a4ac5b,34fd761c,15a0bbe0), +S(d30199d7,4fb5a22d,47b6e054,e2f378ce,dacffcb8,9904a61d,75d0dbd4,7143e65,6afc7262,f51c2a3c,4c292136,167c7f9a,e089f33c,9b127e69,fa4c00df,dbef9176)}, +{S(983e1ca0,5dd64afe,8d39e15e,43c1cf9f,6badf550,12cdea89,5fd85021,b49f173b,18200e81,d75a745,c1ecfe5a,3ead988e,4327693b,7e3c0e04,329b0c80,3d9934ba), +S(4e1200fe,d3e5048f,f6c9fe53,cdff8ef7,5d78e601,4df471fe,369f3d1e,80e46674,a62aca58,4ecf32bd,cc297b38,c1951c71,a66966f,b9ceb2ad,de411da7,d175df94), +S(82f5f27b,83d49042,63e69f48,b676c9a9,2446955,cbc18ec7,fd4346fe,37e0b0a1,e523d039,d0b8ccae,737bfc11,9b83dfd3,d6878403,862618bd,40ddfc89,9a688557), +S(a8c0fd4e,ab1f0e3a,cab37da6,58fbab3d,949ad9a4,31d6461,b2648308,35762d19,950200a9,63c3dc2e,6d2771e2,eff401d1,f9ce037e,75782943,3fd3c560,a169713a), +S(25c1b464,33068900,bff89a4,ee973937,b03c11a,5b33d16c,4f672fd4,bfaa11f9,471f1f8c,df18e73a,e12cae35,43506cf2,c57894a8,f633ad4c,e1c5330f,eae42b43), +S(497e56ce,8793bfec,4dc6f972,dbaf4a72,aa5d8412,3bcac5d4,2aa9baf8,ccfd6723,1d3d028e,b70105b6,eae66785,5dfe7e0b,7c0a6b3a,b069a475,bd913aa9,c29cf426), +S(68a285b0,d30c2dbb,b543e480,f66824b1,69aa339f,7e2282c1,5dc60f50,8e3f2fa6,87529a0e,1d53588d,21064447,99a8fee8,ffc791a7,cacc9e26,f7a7d94b,25e74cdf), +S(721c92ae,931712f6,15f4d7c,498dda23,e1029dbc,944cea16,9442b22e,d755a100,7ef052e6,a0d2646c,a5dff39f,3b2a1019,de43e3b2,5e51913f,d636281d,cee74a85), +S(aae8418f,1b124d79,ad15f773,1bdcea1b,453493ad,4cb0cd6b,ee5c9a8e,34335ba3,c2558bb1,4a7addab,62d1f308,1a9e6fd5,92a06976,3be877d2,af9ae1e8,b510d98c), +S(b6a06052,b492d74,c68640de,8bd3251d,fbaaeb0,ce1eb997,f2127ead,4bd0b81,7bb4269c,4a9ece8b,e8ea2f0f,d663a193,2a571249,2814eb73,4ae1493a,6a97b39a), +S(42fbe048,38761203,11e43178,6af555ed,d7bea551,d4d5aa18,afaa4c05,2c6d0c19,9ba562c0,a4cdc664,87caf55c,291d8246,65c29f32,2a56360e,90138b06,f109d83b), +S(9d6dcb88,b378e7bd,233464e0,25e97bf9,97768e29,6e4aac31,301fa1c8,bfbcc27b,f434ea54,3f7269cb,1ae1279d,4178dd25,bbc337ad,2f0d5141,610dc061,80daa8c0), +S(fa6fa5c8,1e6713d8,90cd6f29,cc8b7d03,c5f8f2d5,88963652,7c199f6e,8f98e060,726194a,2a5da1b5,85eba1a5,5e06ce36,5aebb89d,ba5f7971,db3c1571,c848c5f9), +S(809167d6,85e432c7,372dc111,8573e620,d9ce7e9b,c3ebc15b,ea7e866a,3a8addf4,bf0cb694,f00fd1b4,b62119b3,9dd6c88a,22ef1fed,a94ac0a0,9cf33225,9298b968), +S(99d28ee0,962c1bd2,fa63109d,f5485653,964059df,bd514206,24117eb4,e582ad46,8cbdbb66,4ee209b3,419c0b80,36affa24,85cdfbc6,e6644429,33908490,f6f6353e), +S(559d0617,e0860cd1,87f1c68,e9a9951b,fef7dba,3a67594a,eade6e25,e2df593f,194595af,721e3b26,786fc25a,cf5b2d77,1fe00649,b0cc4938,7168a9ea,1fd2947e), +S(ab9a7228,f0d533a3,4a95af3a,51021b55,bb324229,8d101a66,eb362c97,eac48b02,80a6d111,e451eb09,cbebdd5,a3ce4fdb,42b3665,f8974df8,912221b0,fc7db6af), +S(42c6680d,18b0f528,274c2eb5,422e4731,560ea862,adcc4419,68bb5f3a,5bbfcf16,c8961934,e5bd6e7d,d64d4b1d,f7867c7b,978d182e,48315ae4,3fe2e082,a9455792), +S(e8bc0f9a,c3687bb,69627de1,df71fb34,21e0252a,e33d15da,3039a200,43ec3374,15de9e9e,2ac74839,5116ef76,1267300d,78c2e583,9286e6b6,366c8a6a,540036cf), +S(604ee928,4ea1c8a9,a0a75bf7,be3a5c02,8f52d71,b5fb6340,53401e8d,8f5d3d6,43bc16af,5875b25d,8e2427b3,3913f6e0,bda886a7,52a3b812,f8f191cf,f7bee54b), +S(7f589067,5b771ce,ac754412,a9984352,4f2a4a6b,a5cecae8,5106bb81,f7e4d9dd,a74f2eee,584696c6,88157a3f,fc27085c,6445c7eb,e363c6ed,7a1f5902,63de2024), +S(80aa63b3,1fdd0d2d,ef602bab,dd88a15,71abd052,270988a4,63abe269,fc489fcb,9a145d0f,6dcf0edb,a4873287,a2f221dc,4be613df,f70f7755,f28879a,6e7d9978), +S(ca9793bd,796ae0c1,d778f3,6445bb8b,aa50d859,4be28fe0,ea1e2d16,30972503,7304af4,4c56106e,f0064436,c09b411b,926c4c56,cd82577f,f8c01ab9,9f7c4c6), +S(4cca305c,baf6615e,8cdc8a58,f3a9e52e,97ee20f3,ef080793,ce105a03,a1f1d3d2,637ea84c,9578321b,b5dcc239,7f6206bd,abdfff2a,128d3645,47d474f4,8a8ae493), +S(cb7813b1,a7227a24,cc53b458,1985592a,a9077113,28fb2a05,1d4972a2,3127a913,208b7263,f8f8193b,76dbfb1a,6c4f9264,dd12f63f,e852aa8f,8375fd00,eef83482), +S(d61676be,a11dd1a5,79164cfb,b2488e54,555d7d55,23ddc8a5,454c49e,4a86d8ea,1875b5d5,6db950bc,60b1eeb8,17a94af6,5a19f690,d48aacb0,e483ad52,61995cd9), +S(7142872,6f59c2c8,b398b22f,2ab5c3ca,e803a34c,ab580947,9b7b4d83,1f8e8c0d,3702510e,324c0911,b3154c61,e064ba23,68eff5fe,6f05353a,34980ec1,87ab9ad), +S(72a73d15,9cf7f79b,950971b7,1c66f362,54d13783,c5ef67b8,4da61dcd,4cf432aa,77d711e5,c1793c36,eabf9b86,bf3a692d,234f02db,e4d5854f,5deef926,b9818d2f), +S(ab3b2de,c0a8f23a,a7d3b9d2,88870969,2e45ef47,37a792a5,d65af92b,e58f6347,ac4e4ac9,1bbb57cc,1437e612,e4d4ce37,3d4f0286,5905b621,56826d80,895cb48f), +S(fe5efdb4,32715fed,f9bbb16f,d65ddf6,4ce9bb13,14a491c3,3bfedeba,cb4704ef,e5dc36f5,5fac6974,eaf9d8e4,232a22c3,8aacc6b9,1225a97c,2e695940,ec795c21), +S(5f94851c,a4149e75,e44a0d8,17e81c75,132eb242,c96ae41f,53f30ab9,c8c828a,d9473c47,505e0117,1a0f8682,777d0ca1,7399208a,b03974fb,4014f5bf,c8cbaeaf), +S(5d1bdb4e,a172fa79,fce4cc29,83d8f8d9,fc318b85,f423de0d,edcb6306,9b920471,d7bc7d98,86c861d1,86b4466b,c75dd9a9,8614e166,693a9184,8fccf998,847cb2c)}, +{S(8cf1437b,d87e7faf,550fcbe8,81b0741c,ae0b48e6,e0b3c3d9,9b1b1924,2a925a26,17b40146,c313b1c5,3bdf52e0,efebda45,80d86783,910996fb,8b2d0acf,9bd253a8), +S(fedc65f0,d622743c,53fa6172,e68d983c,2c9b8fbc,58943f48,ad06a852,c98403e1,ca5dcf28,1a2f20d1,5fed06db,89dfd290,8c9d32a,cf40fe6,817e861f,7f168ea9), +S(846c6a48,e771b90,4ae1e8d9,d3daf1ff,d1cb4c88,bbd1de98,454bc817,954654f0,5a4947a5,8a0ab994,3cd0a90,6c1d1f0c,3fb73d2a,49b9c0d1,a9bd35b2,99475dd7), +S(4998795e,a7d80937,e4abee13,6c14585b,40b2dbbb,3fd3c80f,c8c61b45,cd1d59e8,8c817eab,e210398b,59b31660,267c099,baf29e4c,894e09d9,a50894b4,ebbe97f6), +S(76c29921,eb3f3d12,5c11b906,3d1ac276,a205804b,b3e7484b,72ae0483,e4b3c517,48d8a8a5,fe658e1a,4d736bd1,8f07b5ad,28cbb775,d9388e7c,4fecd837,c8eb964e), +S(78de8fb2,b15ff39a,487135a2,636bdcea,57bb3a14,efc329f5,a06bcefa,7ffeaf09,a55c9e98,5e1f529b,ba7ccb6d,3a5c00ce,28cb14f3,e9012d5f,9f66d8cd,5e45113d), +S(71fb3464,b0600c08,7fe70906,2792a676,27830e50,a0bfb473,ec909530,30799282,fe036726,cb928a8a,8affed30,38977377,2a016e7b,1dbde8f3,6db810d7,cd423f36), +S(f1f23de6,bf779cfc,d864dbc7,b46009cd,d2306b1d,cd0de2c3,65f3006e,565d9e21,84f5a011,74ff8e7c,c9a98f52,3f2980eb,4b013695,f6239016,9cc5a1d2,acd8193), +S(f18909a5,a5db0daa,ece22ac7,12ae04ee,53484793,6fd8355f,9ff5ffcc,ab6ca78d,6306f08d,13ce2b0c,b60b3b8a,b0bd5f46,b3ef2a83,7edce51f,2cb5ce41,79f46344), +S(7598d96b,189f476c,bcb1992d,9a38adcf,9d1b6ce9,6c87058e,24584514,a0df4770,7f288be1,b82da02c,a37f655b,d23643ba,bf3d5cff,3b6c2726,9ece7409,ed78bcd6), +S(1e44193e,8223b57d,8fc68641,924cded8,3a04d806,cf9dc18b,7af06010,4e6216eb,45ea3ada,fd726fbe,2b1d6fd1,858ccc2d,57b237bb,bc2965ca,ebcd1b63,53c2f2e1), +S(80954b78,4872286,8fe38891,2d76dfba,d676b4e7,7901e559,dd5983e4,e908f13b,6fe564cd,a0966639,e0237f29,46e92d29,4aee124f,cb33da53,974e8882,b0acf22f), +S(6dd8a9a9,ad7196c1,3c36464a,5cb9fb41,aad8b0cc,423b99fa,a281c5d5,a6ce6ead,79a51469,8767adcf,ed287aa4,914eedc5,8382af71,5485c2aa,c3a77c4,efe2aafe), +S(1895cc13,f99534a1,187a3d65,d1480669,f0d0c0bf,b42b2a9f,1a6392d8,7e1d2c6e,b7905afa,c0eb9b66,51de3583,2cfb9ac7,ae8d2355,1e334d59,32909de9,ed400a0c), +S(f1efcb8a,86f94997,65b38fa5,8edced68,7737b8e9,49dc05f2,190b359d,9ed2c0a9,79b2c874,22de216b,904572b7,a39f320d,f53e392,8dd8e533,a1a28d93,fdd4945e), +S(2944af80,c207d107,ce89fb90,ea6daa2a,c65c1360,503c36c5,ad798333,90432ce4,44b53d27,fd6730f2,33b8c29,f1256136,c637740,86e001a7,60bc1ff0,f8b6211a), +S(938a1dff,117540c8,f6ee7df6,2d3c2cf3,31b38593,131527c3,9804c6d9,874752fb,4683d049,f096bc21,2e0dc20,a8600b8a,a02133d5,d0ae8d6c,b26e4694,ed6f2aa9), +S(b1b3b2c9,54d1fb6e,98fcf939,efc18803,2f693989,81f19c32,f5e55b30,1f59eb16,423a6754,1a29bb01,95adfe15,c1df1c9d,81394e96,2bd1926c,cc789f5b,eef9ec29), +S(52e23f2b,19048d43,b1725695,e3bdfc7a,f4ebd2bf,594f013b,b80d6d0c,ec10632f,258a6236,67090b8a,73881e39,746906f8,eabb6683,4bc3473e,1c6fa8b6,54641cdc), +S(5799a463,cc817bfa,26bcc543,efe0e00b,ca9d2320,1989e854,620fc9b1,ffc14afe,645238d1,8c69338f,9c9395fa,5ef7c9b0,f62b7dc9,c4c6b9e,c545c850,95b6b7ad), +S(1c493b52,3f5a4467,6268220a,58246228,608a603d,f6edb1c9,1a90b060,70b16069,8d311a45,5af92640,e9fe08f0,2981db57,3b22bf4,8fd5e76f,31c175be,23e24fd4), +S(84f5a9c9,cda291c0,71aa9f8d,d7af5a8b,f2ee0dda,fb9139ed,fee08f0f,3f9cec2,df381327,16527be1,d86991a9,bc28966a,c3c6c081,4fc0def8,85e5d160,f59f4458), +S(712c18a0,ae87e7e,87856c8b,ff6e3f6d,996ae157,970e754f,bba80bee,421fcde7,b2788ba,e69d34ba,eb5dfd62,830396df,3b8934a9,551c6070,ae8203c,ccc50ac9), +S(a5104184,ee996a34,7122a460,cd2eba5a,11d04aaa,a47d2ede,25ea13fa,41ee01f4,f4b5f2b3,f7ec9061,7ab5f3cb,763233d0,afc8d4bf,fc535076,5dc5fd41,cc547ffc), +S(79383075,a46a8eb,559ac95e,7dbeb9ee,51b6e906,27e55b9b,922473fd,5f2eb63a,243f56e9,84fd2673,58754a67,2bac56a7,9ae71a5d,68150740,8eaf8c2d,b55ef1a0), +S(2b22635f,b83ab0d4,9b82edfa,a54d6234,8d3bee6f,edbe3315,9470b18a,96f97821,41d9f3a9,52f17182,ccf02725,b58ebd7a,1f37235,1fbb8f2c,15403890,e8b25b82), +S(272fdefe,148ef7e6,957fb8a1,4a07f0ad,b17c27ea,49532547,5114c1f4,76170a0,789b8eb,5846e50b,d489bf66,cebd873f,7cf05619,3674e7d7,147ea691,6a9b8451), +S(2c2da4c0,8a6e73c0,2efd6e7d,13006135,f09990a1,4c0a0eac,1f286108,f4a2a0e0,8011a521,d7fa0ab2,75765bcf,50dba163,9e89c9,300e8a25,31942cc3,fdade63d), +S(19a9e5f,1c4cae30,797a98db,a24051a4,38ea755c,7b062094,a34ed6e8,8a8ff2cf,e199e398,157a50a1,56f9d6d,afed48cf,f3181411,77b792ca,c5881898,24f1b8dd), +S(f7a4be3d,fc6579fb,43c5a960,890893a,f4026165,ed9e3ab2,e6929378,b63968b6,29221093,17dc39ea,de2d6fcf,c735ad2d,668fd047,2eefefa1,b6b225cc,2f3cb3ad), +S(e5380fe8,575f26ad,b7924ae0,d58138d2,68112776,b11bd34b,3eb5e196,33f0e9aa,4680278c,6f784be2,a496ec9c,6db371fe,9046b1a2,b97ce71,3b45bec8,bf7d8a20), +S(4c1b9866,ed9a7e9b,553973c6,c93b02bf,b62fb01,2edfb59d,d2712a5c,af92c541,3e086d2c,df4175f0,804348ac,31a91963,39ad1528,1bc14e52,8d3b0c01,39701c0f)}, +{S(5a13b9b2,5aa6944,1b0b5fb7,f7665dda,95aff48,e3250b4e,34cf8e28,87406c1c,245f250d,78fd66ef,24745e09,f067f16d,d400c387,66d2a1a9,af51e84f,733d0ba2), +S(617b41c6,8534072f,2302290a,4956171e,902634bb,4356bd27,ab83a377,13d8ef6,c867779b,97383817,dfd0971f,64c09c71,7c468a5d,e1bb8ed0,feb98f5a,305d8e6a), +S(ac118ae,ed46b08b,488202f6,96d9469a,e9af3cc7,ddc8eb71,44903a3c,ee43c654,f992fcea,8268ca6b,79f5ce69,c87dcfa8,42ea0345,d7c85a5e,a1b89f1c,9d0217aa), +S(741dc47d,2e0d1424,3f2bd96d,9033d8c2,9008c1e3,66bfb5a1,1434f1cb,3d85310f,c3135d44,e86f574c,266f97d0,f0279dc7,52aee0ab,8e3ed78b,ee0fc646,c133000e), +S(2e973138,f6cea9c0,5adfbb5f,49a7b928,5ae0c15d,120a8b1f,2d0c76ea,1fdcc7e,a05bc93e,68bc82da,7a7c7e38,95a647d8,7f724f20,c5b312b,738c6dee,90de771a), +S(9d938d6a,cf56104b,5522351a,3c424e01,e4d21c33,771ca94c,f55357fc,fe51f91e,881d05fd,4658b08b,edf87396,be3fbb95,ec9f371d,79ff4586,6ddc803b,65ae763f), +S(37a8ed2b,4085961b,84645ad9,8f2c901d,fe9a9a8b,4de8fc89,2cfbca5,c8909835,b1bdacde,94fdc3a8,78cd0eac,f8865d64,77e2cff5,efef834,97b93835,5b7b401a), +S(da1ba954,899cb05,dae6fea2,dc8ddd7c,5ef9e91c,3455838c,a49d2858,ec217d66,14051c3a,12332d70,f8ad8ffa,567765fb,def69640,4291b81e,d3978bf4,51f788a0), +S(92d2ef44,5a10dbc6,73f8c1e6,af093596,13bd1e3,c1b24705,bad2b3de,e8f11b81,adfed916,800d3e94,91a42c59,dd72e3ea,57d47081,b9afe668,f853cec2,c72cbab7), +S(e62208bd,52620df8,91b3ddbf,e6cf0641,6059ce50,be3b00ce,14e7a53,6d1acb07,1fb71455,53b2f4c,431fd86f,c72d51af,5e2edb41,dd3f69a1,9a971371,d9679dc5), +S(191fec47,a48ee268,35ed37ff,6758a80a,532f7011,ab099048,b024efbf,cde1d0ab,47b6389,b3f5534d,a632924d,5b65918d,f65c9c2a,2904ee95,4f24aeb8,c6a02557), +S(60c822fe,a74d52b7,d5203720,b2c2a361,b7628aea,d2a683bd,80655636,bed15714,5d9a9c0,120211b2,e8285b77,8f8d4bc0,b06240d9,22944248,e1cfce73,826bb67d), +S(f602da1c,788ea65b,cc339a38,c353bc08,1c43c2f2,6e05ea6d,ab52648f,890c9101,21468929,89348f8c,67cfdeda,31ef3429,23b5a450,9fbe9a49,f011d42e,57f998e6), +S(756240c0,5274101b,3059d23c,76d9ecdf,33e1312b,7a36af,ea21e6a6,c52cdbb5,ab24e853,900c7ff1,3e4f813d,a2acdd5f,53ce1710,b785ffbd,e74494ab,43e583ee), +S(8e815b45,7adf482e,e30e475a,4949e5ae,c7ff494a,a918f07f,c39441e2,360d112c,a966f04,2dd9edb9,436b0005,7473aa66,dd19b4d2,cbb3bd95,932ba98e,f1a1f406), +S(216d5970,36c661f2,cf6122c0,a136cc33,9660306f,1c190ee5,5f3bf438,e7189261,5bd23797,c6753eee,6fb934bf,dc897ec1,25b31c9b,9e797ef1,56d8cdda,2ec1d128), +S(a30ed06e,ce34d29,a92fdeef,6954b5ed,4065d592,3af09be4,f0ad4a73,e7c24346,f6aea418,6b38c188,b84fb6f4,2b6559be,f52dc13e,b7ddeccb,6e85a76a,8d4efeaa), +S(aa42d20d,8acf7c47,fe40ac15,3fcaf1ac,6c4ecc37,dfa39c39,fe5c7657,c78444d5,bc3becdf,464ce930,e42a05b2,c52d3589,fd45ff37,c7d1767e,f8462811,89634059), +S(7585f8cb,4812e306,de02393c,c06e9871,1953133c,bcb67ec5,c6a79228,69124ff5,c242853d,1a2c1c9,a1cd1b5b,364888fd,28bb23c1,2b0e169,67961b3,e7c8b95b), +S(b096a1aa,fb969483,185ba1fb,a5fa3f3a,d1da87dc,a10344a4,d74ef471,45cc45ce,edbc9490,23801861,44ee39a5,7bdec0a,230df57a,72649e04,c4c99883,a147f0f), +S(7034d8cf,df226df1,6b310628,35dc02c9,f3e3f91a,635ad93c,46be292d,56c0ec2d,f783b6e8,29447cf2,32769a13,7ff33f82,f9fb166a,aec8c3ad,1679c48,c1a913a0), +S(9f88b01b,b936defd,f61156a,b55ca290,cf282a2f,3718b0cc,2d32dd3c,49248b4f,c24ebc35,27052f77,41087cb0,e772ce12,1035042e,603f1301,e19cee0d,30029230), +S(14443190,51f05d23,343367e9,6add133d,fcb63209,2f218847,59ad81ba,c65e7445,745216d2,d11f2556,7e3b224b,6dce478c,bb988b96,a1240093,964e4ba6,f3b15554), +S(54aa2e02,3038fd83,f17a633f,d9ab441f,e039dd0c,57f9368,3da013f1,751c6813,f4d163ac,a9af3e08,c009b44c,b358ebaf,31aacc5e,e0bdb917,d1b4df5,420d2d34), +S(fd44e742,b04ca4df,693e3109,3ec52ad6,1f67264e,100618e5,88d638d6,d96efa41,7ac09cb1,2134a246,b17ce054,b38f3bb7,7d794f9b,2fca3786,a0ba665d,3eb0f14e), +S(f662f214,10cf6e6b,7f79fca8,7ea3925,6760d83,17478419,ff4671f0,2bd2ab6c,be4ad0b7,a56c87a4,8fbc166b,da8473ba,6518385d,bd004b5d,c85126bf,7b9309bb), +S(520e2755,1cd804d2,67f9b4ca,b3986952,612bb099,cbd3f3be,a54f505e,bba4db64,e3c75cd2,c831c539,b095ac18,3bb13a72,ba7cb152,5b9c214c,288509a3,98a9cc3b), +S(4d16fa3,2d74de13,111b3f22,c4133ea5,377921ba,e54af1d,666d6e9f,b01e117d,a63bdf75,78d73f03,75aed657,fbb8675,67230c3f,868f2cf7,b7275ec8,b02ac46f), +S(ab928c61,ad1c2f68,905b9e95,3c2629ad,9bb7c8cf,ad9f5a4b,35b35fad,69a92568,bf39ec2f,6c1ae222,ff383375,6bd83882,c05be6ae,692539a4,5124b972,e72159ee), +S(8731aaa4,93580732,66b96577,7bc24a46,17fb8363,51c5ad8f,c8bc053e,802dd07d,36957f16,1020430f,69a3b1c3,1a6df993,d9ca8e2a,8f487b7f,b2ccd44c,7f528ce9), +S(3514d41e,8b9388e4,33d1155c,c777c398,22ab36c6,3c2aaad7,ce674831,21231d11,7657cdaf,e9fe8147,10bb2ee1,a97c6100,6c7b0ce2,f5086141,ac2904be,1c7a9e3a), +S(9bb8a13,2dcad2f2,c8731a0b,37cbcafd,b3b2dd82,4f23cd3e,7f64eae,9ad1b1f7,6ba44d4d,50111c46,490622d7,b079c17a,f0ab57bf,b8ad2ac,9becf9d7,3c7edfaf)}, +{S(e60e88f1,dc24f079,f835b687,778307af,83446e,71809086,e6dac0db,9f191de4,25a0b86e,ff05c849,d79a176,1a634d82,29d2a759,fbd003c,b6ca4147,85726362), +S(55a5e6cd,c9e11103,749d469,dae84a88,9e744dd5,d9309762,15050a83,fef66fe,31278ace,a971a41,e2f9fb16,8e80ec03,37009cd5,b0a49938,c28c902c,a7c71fd2), +S(5f25326d,e99a7c5a,d81bf2ea,61a9195d,48832bfa,8caa9777,53e483f2,b5a62580,40b69a1b,baa2d0d1,5cb78a3d,3d184c08,5b4c16d2,90751ec9,bf3eb3c1,d3ec2ab5), +S(1a32cc7a,f88976b6,cbc89865,89e685ac,49381a29,1579bd2a,13f9488,c0333d19,4667a3e2,2048f781,11f009ae,5d7b1b97,850a3a5b,86f77880,b128c8c6,a9720acc), +S(1d78e74c,66247be9,352c9797,5fbc1299,743f9c74,68c64d1,f2d8affd,1b098769,37adf553,fa2a11e2,6913ab02,e59c4f2a,48133fe7,d9aa3c24,a76e9af9,48a29d8f), +S(8bb6f83f,6be5c2e2,b2bb265a,9bb3c931,bd5cce6a,48efccdf,daa040da,535dbc86,eb96a982,23278b81,6284fee7,b5b8a121,7350cdba,d56b6078,89602bba,bc003481), +S(a9f19ca8,1d2ebafc,4bb5d881,76bce19a,d2d2564e,185f905b,8f9eeca5,d6b12d6b,ab23a468,3279a9f8,e2e8f880,e0accbba,844bd4e9,4d3e4b43,74db2b55,d998771e), +S(19680305,c887467a,c3bfe44a,dbe65431,7323d8e5,62271e25,1a794b78,618befcc,48e9303a,3d6371f7,cf0a904c,cf16f606,b0007583,87ae0952,c6119521,dde25532), +S(18b3bd03,ed4696c4,7c3f896e,5df7481d,6f19a5ef,53d62ff8,2948f1b2,154175c,85fb04fd,6573a19f,2c136753,a1ca2585,d39dd64e,6e6e3fa5,fba362b4,ae9dad36), +S(38e3bee1,3cc3e18,a57aef97,4ffee58a,a392c311,14ac8baa,1376b56d,f8ac017e,8596c7f9,8abf3e44,4ab5491b,fe659619,f6defb58,f48e2b7b,57842193,cd48fb5c), +S(dba5da08,8cd17c33,3e892bcc,46261694,d2ff3a22,2a26f92c,17c5e1e2,797b235f,ebc15bfc,5729e986,85a19afb,d7f9a219,e60d2784,e9b283cd,3697f782,630fe222), +S(60456426,caea7fc4,48970eea,fab9c632,3e66fcee,50f92630,7b130937,25b85ee8,dd22df89,c5dae339,49459593,1433f2f6,5f719379,68e56f92,a38d1290,17881924), +S(f1ceac82,15670212,279f36e,f0c8ce28,3a192f66,460e4875,d90b2f51,a38f5712,ec11f026,c76c271e,fabd7d55,c8488d99,3298f6ff,c05ad4a1,26be9447,7d878b9e), +S(2c2fb5de,5dea249a,7bf6b196,8bdec8d6,1838da2c,12147045,18d6494,f09e50e,6c0d020a,d6bfd730,5ee73634,e939ac89,ca2b7d4f,dcbe760c,2d14ade2,659a5b8c), +S(2858ea8c,d40ce264,3c9a305,c0e2c758,af5b0b4d,5c57ed21,60cf7ec4,154ffdc2,33586bf,a61a3cde,4f402bea,123c69e2,2410c0e,590a71d8,9a1e8130,85cbb579), +S(2749a250,4e7cefa3,a3647088,6bec22fa,339fec0d,ec63c02,19e6af39,7fdec3e0,d3415104,a9070af8,b61acdf0,77954d37,57fcf742,a006129a,5c0d3529,3aa95407), +S(8edf3ad8,39e661b5,f7f16a85,dce3caf5,d571acf4,d0c6195c,53b618e,5311ac65,fca0efba,35a14d3a,9944367e,db4ac982,7dcb7aa0,12438c5b,aa5627c4,c4a15ed1), +S(dbb92358,8b083294,5d6d3b62,9cced57d,7085d3e2,d0890bde,95d80400,98c22745,42816661,5515429a,aa023737,5fb77804,624546f2,1f0a34ac,1ed4e4ee,dceddccd), +S(aaca9896,6196ce2,e13df3c7,d058a5e5,10566df0,5fefc04e,51f9dd,85a4349d,be389d02,789548e0,aaf67c57,3b91b389,c7e6ed80,ca3e637a,2a147262,80cd5620), +S(104804ab,e621b098,61fc540f,f4d6be9a,750e3cfb,706170db,e34c06ed,e0a431ea,14b700ed,a465915a,eff84ab9,fa568535,f63e4f44,1387ab4b,d841072d,97739071), +S(b2215070,a8ea71f9,b71f1a73,d6ce366,c322b8ac,4d135b3d,ccea68e5,a51f1c0f,9e415cce,3bcc4e62,6f3c8caf,fd632eea,862a046e,bb45e8bc,84fc05a7,a4b87e00), +S(600c6e28,be5ebd28,d83e6c86,bbbd9b0b,aca22006,42234634,6124133f,3348e6f7,822b1816,79e253db,a47ddd76,c0023991,5c0c0206,8f422415,94ac38b8,ff7994fc), +S(f8b9b45f,c6298dc7,13355bf1,3ee33ca9,c4c1aace,c09776e2,56b3746d,ccae0dc,bf4b7f96,1844aa2c,6ed8c8a5,6626386d,174e77fb,98c0c23e,e2b6de90,3f1f79cd), +S(63987b18,67fe5a17,333eef28,5385a0a6,576163e,2c74cd00,ba87b6fc,96a57faa,23ce6655,51d48ca3,c702a5be,87a05d98,b5aa1097,dd5877e8,11e32d76,4873e6cc), +S(2eb06c4f,5ea9ad2b,124a1202,cb13c1ae,aec4394f,4af7c96,d6a9ecba,540ee04d,b96173dc,77b46ef0,6f4141ec,96ce8d1,4adfcfde,f0bd7ea2,479ba6d7,522d037f), +S(5db39904,153002b3,1498bb01,16efd0b5,838e3495,62d9428c,912987f1,3aae5ae,2115b896,479d0d0f,75ffcb54,ff9e3f73,d1356ff1,4b14292c,6bfe8d54,e9e08861), +S(c0f14110,7f324ffc,f3d3e6c,78d5a628,6000d57d,7e85bc7c,fda15f75,79cef3ed,6eb03650,c8142b12,b330b96b,81214a4d,d01b068a,74827611,53d2c52e,e1315ce5), +S(7e3d1510,ed767345,bbb3515b,6f9819bf,33ed9dea,fab35d01,a7284cc2,371b0e66,4c6b3aca,5159023b,d43ec0b2,57e77e87,e5a6b745,178bb017,9960c89,361fd97), +S(f98b5dbc,3e54c227,b002f458,94850ff4,3b15b2d6,1607851c,50d1e4d1,8b20907d,1d2af742,b0b5ec05,bd6c648f,94563361,be03261f,da56f1ca,7caece63,a336d580), +S(188ef3bf,ab103784,37e1859a,7d53e899,6124c395,ca422c05,d6b21b3c,efc76ac1,19036685,fad04566,2ffa04e7,30c671c7,1b299217,c389c78a,cae9fcd4,ad70fb73), +S(b89070ae,96ead4dc,49be16f6,a1a30bc2,41b4e98b,c18d0227,4c9d9d87,dcbf00eb,90db373d,375d2770,b8dd6b1b,3e3b5899,34f274f9,49469598,e480e431,e4f195e1), +S(381c4ad7,a7a97bfd,a61c6031,c118495f,c4ea4bc0,8f6766d6,76bee908,47d297fd,6c950ac4,dc71111b,70c1a058,f66ea133,fbaefcd,246c63ff,6c531ce6,82b6bc6a)}, +{S(704a26e5,19071bb0,24eb2a16,48b66a6e,157b07a5,52fc4258,381f7d02,e8fd9b9e,d169ea55,8650aa3b,ce52c645,278422a3,69326e74,46039381,920f5857,fa3492fa), +S(705063f5,e481735,60afe9dd,5b2beeda,d6e46391,75ad7fb6,f73350df,51edf53c,32290956,61cacec9,472dd014,bda52364,3399d7cd,9ce2bb31,a5b23590,22c6ee5c), +S(972e7585,f8b1725f,4a7d18e7,77939aa6,3600a7b,a07c4d94,5da9511e,889473f5,aae4382a,49b4c97a,bc3edb7d,26ba7bad,16752047,dc99b434,f306c673,2851310b), +S(260530bb,e338f4a9,71930b12,4f18c82d,e33f22d7,32de9375,81e2b0d5,15e59d97,77c66c36,d6b09205,8ade9c0c,a311b60,a705c8c8,73fd2d4,8e6327cb,71eefd4a), +S(15464351,d21d2513,f792ee32,aca3eca7,a52cdaaf,9862172a,e7224a03,804581dd,d9ee19f4,502f1c44,f656ad4e,add6adbb,d8a04f5e,5344b554,894721eb,8e3e2285), +S(4fcc68a3,caf3ff91,dcce9770,11ad5157,6c844132,321791ca,a652593f,6cafcd04,e8db3aea,a35371bf,9700a9bf,b85e90b3,93cc088,9cd655e3,fb18635b,49fb59eb), +S(301c65ad,567952dc,6b39134e,c361030b,3f5203ed,da89784b,225548ec,45c75eee,95e2c0bc,7b4a7cde,8ce3dace,a691bafb,f78fb03f,3170b347,ee807f42,6b947560), +S(96ca5edd,8047ec6f,b5f8c37c,a734533d,13f0e6e7,f55d28,b8b10b5,121f4abe,1a21f1ba,f6a2e336,247f6ee0,88cca9ff,816b0667,3badc241,d9ed00fc,d2070f1f), +S(c94633f5,783c4e68,12143fc4,6e670978,8e8a526,819afea9,404dfa00,df1bd839,874f8760,33dba9,de463f86,b597219a,c1ea37f3,970bdadf,97c96c48,feec4ec5), +S(963146d4,5bdaa05a,b5115ac2,3ee862a0,2305ba9c,75003f4e,ab838f7,e9adcdfa,d75766de,299e5cf3,c8796234,5db9866c,cf011c5c,f108a794,5642a6b9,dd33eb0f), +S(dde8c870,ec4e9890,2a820a7b,c5784034,19ac261e,de5afd0b,82b8c5a0,7c2863df,e7833936,50d4af7,427158e4,6c753ac1,a5143c9b,c09de97b,3b27065,6f622b82), +S(546c6b00,c5e34a8c,4cc7255c,2edea33,d9f77e7a,c67ee629,bbdf1879,4622265e,5ae149da,f65aba8d,e214fa63,be9bbf11,3dd3c220,12d206bd,d56026e7,4a019897), +S(4340c850,d91b63fd,bdaf41bc,f8d8c010,d3f30eb5,79eeefc9,e67c127a,33324071,dd66033e,eb5ae8b3,3c47a940,2482bcdd,4db5c8e,dda3b422,35627434,dc3bad1f), +S(f796431f,679d9cb5,77bce62d,236d1fe9,b5042a83,fdd1cf94,1a2e00c0,5a261d11,718fffe7,68aa2591,d3fb1fd6,1a00537,3b529f9d,f9c27f79,31ad0df9,9aa74859), +S(f3d17ae9,d5b4cf41,27423894,916318bc,adfb5a9a,6c2ca219,1b918e43,eb5ed129,9da6d033,49c64d79,7ad09a33,bf71cf87,8e0ae6a7,9fa7bc3f,1451126,18415960), +S(23899a73,a4b52d27,29ab52a8,370ceef8,4c7684c,cd535f4a,ec360eab,cfa5a787,f1bcde3c,5c4740c7,37b066b3,8a1a88fa,c43357f7,f3fa23a7,b00815a3,85336320), +S(5805914f,5418971b,106305cf,c397dc12,f63a3b2d,8b451e5d,c1b60c2e,3d9e9208,616e2764,67a5f1b6,46279ee9,6e8645f3,76a80192,31e17a5,c92e26ec,1b76e62b), +S(85ffc326,1991848b,5e918c4a,53f291a8,31796b52,d56a5c38,8bebe625,d78cd07e,95fd6f12,7b155e6f,806c089f,3f5abe95,344e9014,e2c72fdb,e720bb8a,93d864a6), +S(6f1a57d0,6566bf81,f4b16329,19f477ef,aab4f829,e29dda4b,27627b96,1cbfe3eb,de1e8359,7ff20c63,3d28b909,caef273a,a57898f1,a797fd91,e00e2e7,da1872f4), +S(3d28eba0,4d0ae2f6,208adc71,cd6af3b0,e208860c,722903ab,e106feb0,af3185e9,cf8bad18,40d3d2b4,abfb5b28,b50702dc,512527d9,5bcd403d,9713ec7b,ef1dda13), +S(46511979,2b845113,1b32663e,baa14c4,20a5408c,1f53afb2,43cd496e,c4b18118,40bd602b,d740096e,842b40fd,8304ee73,842b074e,415d5ac,c5e2243,28b241f9), +S(393a8bb8,7ffe4265,51678524,8ac940c6,4aa70e71,512ebbc2,3485596c,a6d9da5,25773032,d2c1f80b,3954715a,6e4132a1,74b4468e,658f6cc,4d5f5d63,d458980b), +S(aeb37eed,35274696,2b85a21c,86b9fe34,60433606,9ae4ce6e,3a8235a5,e43c48ad,d94165e1,5372330a,7b5507f0,377a966a,541b6fcb,949398c8,dd6d6f52,2411d86d), +S(b0bbb4d3,100ce417,dec58f46,95ed8b30,4306f21f,ee11f899,585fb37e,a9905c59,89141fcc,9344e617,7742e31c,42c565d0,45c7ccb8,6f88df7c,5c36d23e,45e51d75), +S(49694de7,330b4c3,1431d452,f3e9e562,eddfe029,1cce58c,73b69cdc,b89e0f49,4715ea3,b6fdccf8,e224b93a,ffdfd1ac,ad8baf44,c5bce735,e7c9b4ef,3faa2656), +S(9a7720b3,ff0363dd,7263e1ad,83c32526,67b67d3b,72c2c14c,95f0804a,dd20f7a8,815a769c,494824a,a819ea,54b560ed,e1df9bca,d7df2d63,aae69c4,a02f9f20), +S(b89c399f,cdb3aacf,99796fd0,95c17cc9,786d79b4,9a1a255d,5c9ee510,38d3620e,ee3c4936,d4f9d1f9,d2642043,d25b21a1,aa32fa3e,ef44f409,73db47a,96965cdc), +S(add68bac,d7180ac1,4e9bbc5d,1e0c3911,f2202d90,1f9ba649,46b06507,b86ed5e9,fcffc13e,a9be67be,8d090a77,9fd9107b,f62bc785,3f98e97a,c0358b3b,7719944d), +S(9bf62cdc,cdabe928,c1ab44ce,38cd0611,135971ed,81ce6c6f,dfc5eb5b,d9c3996f,885b2381,e0e785d3,cc3f78c7,f9fd54b,ecdd9d9f,c2979e23,f97e9bd2,a4f10d3c), +S(bb223cee,f11450d5,c5e0b75d,20eb44be,9d44dcff,28574117,12fc5875,3b839339,8bb29985,87eb6f5c,c8cb615,285d9e69,71db8e31,8d81fd5d,6318909b,8311a00b), +S(9ed73f09,2263e84c,d022388e,da82361b,445f573d,b646cc62,fa0bf5c5,1d33fd27,49ce7698,144e1115,118a4b0c,bdb98dab,6b57dc1a,4d1bb6cb,a68d4d20,d8e937d7), +S(e747333f,d75d5175,5a0cc9f0,a7287084,65a02c58,7737a7b8,b8fa1b8b,4bb2629a,d5001fe,baf8f3ee,b33bc9fc,7fb3da7e,377c8955,91e56965,607269e4,96b90559)}, +{S(516ea742,3f956765,a15f856,182f1e7c,18d3e548,b9fdca94,ea46024a,1a8fcbc0,cfddd98f,be500604,28beb901,92c01282,aaf9ed93,76f0e26b,e912ac42,a378d542), +S(8ed072cb,13eb90c9,e5c107f6,ba576a87,ac75a431,53025e6a,86addb95,bba7862f,eece8a5a,f28d356b,f1a84c14,2549ae7f,894f7c07,305194f3,18e30e0c,873fb5b0), +S(3e0e488b,1c8acc24,f81bfa1a,f6761afd,b4fa5f5e,6317ba72,bfba2f07,6c2ff593,2c4ec39b,2f37b948,fdbc9e3b,a3fa82c0,dcfde2e2,57830a04,4c178759,ef5bbc8b), +S(f6b3f19f,cd7eac5a,13630ad1,bbf331b9,5608b7a0,ceaa67e2,4a1e830b,5eed9825,a2a64078,19ba0f7e,7a890df9,523c6736,50ad08d5,c2557cd1,53c6ee65,ef493ce5), +S(e2de599a,879285ad,398b1031,8e1a8387,21a5c4f7,1105469e,affc8e37,189548a,dd977e62,3dc05cd6,3155a71d,d87d91d1,d74d6e31,5f73434b,679b605d,9db264df), +S(bc52359,683840a8,59fc2c8e,22d72ec5,da2493a4,bb5073a7,f658517a,de83f867,76a13651,712ff42e,a0c10f09,45c4ce41,2cc8c4f2,ac3ae446,7cb383c8,656d3186), +S(d87e2b08,154e38c0,13847a5a,2f84c276,dc088b6f,c19a9bf3,90a8a433,fa937fda,d91447f,7c9042e4,6f64a9c6,40a5c294,1a6f08f5,d3eed464,b09b2a1,1c402c0c), +S(4359ac5c,5dd70bf1,d4f24f00,1301b9f6,17d9c69b,63350dad,9a8cd192,655ea801,c9e14f94,d8ec39aa,46092657,5d770426,350794a4,b1ef2410,a9b0118c,ac5d55c1), +S(3ab3f503,29e22bf6,8fe9882b,3b4dc989,36dfd840,be6af588,ab6d61de,48094b9e,4a40c435,9f4dd21b,11664095,4b55e6b9,f0308786,eec32fca,6bcdd5d5,8d055ac6), +S(a0f1ac27,d046d987,b9a98bf3,f770205,931fce93,59b75944,6494d221,dc2752b2,bf1bfdc6,47a15997,97b5b6cf,2d8a2a44,e9c36b9a,20b53abe,58ce9e0a,395fab70), +S(a9aa63ed,3b0260d2,b35b030c,7a5511c8,679b6170,b8a4f386,fae0bfa8,92735905,2f654620,4dba9b31,99bd648c,cb1605f7,62f312d1,67123d98,ed66f02e,4d794e90), +S(e51da157,5e566ef3,bad3fa66,e55432e1,29be6c36,32e390c0,f4d76719,bae34b7b,55930b79,2ffc91de,674820b1,eec290d7,74ecd79d,1ca07d6f,5ea2f817,4759984e), +S(8b69a891,b417ea65,7ba52bae,58920eb7,f101bb92,e150dc1b,c961c37e,73cd18b7,5b824edb,f4a68988,39de0d70,ec16ee1c,a01a4692,f29263e1,1069aec8,6b149214), +S(ee5c1186,77462649,6d37fba,e48e797,dc69f31c,d6ad22cc,937c7224,ef7ce8db,13f7987c,f2cc4551,e058d410,3d5c24d5,13c2d602,ddccadae,fddcab82,d14d5310), +S(b961cb45,5de8b5b6,c4c5c2d5,75303c81,35b5d278,503a15d2,371b0551,5b236b,3ed18486,5ca969ba,31c734a,19055129,1cd664be,576925a3,2a142769,4fc40df2), +S(83effa4,c127b5ad,7a0c53df,5be5596b,d4a42987,2eafd8f1,5498a6d2,47b87314,efa99759,c9360b14,7643de2d,64ad07ea,39cfabe0,2bc94e00,dc9b2e70,c2e2c217), +S(f253fc52,4fb0254e,e772f50e,5d6c16d8,48692455,c855d4be,15ea9f9e,9a5411dc,59bd1f8,2cece609,8a63fa1d,48e4166a,d79174ec,5f8216c3,16c48c1f,e5c9a0d7), +S(6b61024e,e6451d97,1446b55,1476c3ec,eb6b19ec,16155acd,317bc2be,11086411,8de5c6e,37b562da,ca5a203e,ea028b76,e6befaff,e54b49d2,6605f169,592242cd), +S(1691a90b,9cf72621,3680a72d,af59ef24,985448ff,5f35372a,ab6e2aef,df8b33e5,83d2032b,6ca761d1,286c1348,31250054,5a230558,cba391e6,f0db9c9f,97c2d618), +S(42a078dd,cf749f25,aec7a1f2,8e976f79,e268c36,a7b5b0cd,6aaee3e0,925746ea,c60f1846,6f025987,e0ea6ca0,3eb98df6,99389753,b57abbf4,f5739509,bfd09d1e), +S(21bfc1a7,16b09543,5142c31e,5038d4ea,4643d9c3,2fd4728d,1374dba8,1ca1f07a,a991d491,2601ca23,8e289e71,e9d743da,4385aed6,c732f808,6dc21406,74540acb), +S(e75223e8,fe247a98,5220cbfe,52151978,c98d1460,746f8de2,8696d235,71f3336b,dbbb8075,ab489582,52472982,c7b0c3bb,d82a0762,36c07c05,44417ff3,883f6f18), +S(7a756a,72fee88c,7a2758a5,3294da85,6b06129c,1978e217,2bc7952c,92b05265,c4ad3a0d,be72fd27,bfa475d0,fbd16a92,5e939362,bc0748c,c39ba9f0,3ad84133), +S(2bc697fa,d947fd62,63bb2841,1a274520,f5d582f6,7f039114,293438fc,9aad7c82,543109b9,82097efc,cb44d854,11fc5230,6c7a219f,2f58b37e,3dd354a8,2ffb28ad), +S(3862db95,1ed8994b,a8cc0178,f6dc97ef,db6e1380,c18719ab,cd24a88c,87039744,af1e8ac9,2b195d3,6fe1b1be,a68e9215,a453e638,67e65d88,64a8baf3,ff5c1267), +S(7b648cfa,40ce7274,59a6fae2,2836ea1d,b18ada4,9b18a61d,748127f7,7ceee771,f2a30c56,42887135,30124a69,da2c0355,8688bac3,dae6d95f,a252855,a85a9b4f), +S(f803d7c6,1820f980,ebe0b297,87aa688c,ddadefca,229b99b3,a6bde5e9,922f94d2,a5f8b450,34dc7de1,461dfb74,e7ed9c49,80407bf0,4b0d9159,af703a9e,1e0f9c61), +S(2247f630,9be2f3aa,e30c5907,c29095d4,b9198d25,1a17bb34,7cf5cb35,a2ecb1f1,82685964,20d87b07,1c5a4044,b79b069f,7fa6ecf2,cfc0f839,b2161475,5728c2f1), +S(1d770ace,ceb2183,fea7c924,a8fba197,579df37a,908992be,d42c8e80,8bd98ee1,d87077fa,b910a21,8769cfc7,49aad579,c809e35b,f1c2a813,6047e85,e2c6fc65), +S(5d134e5c,5da47f7b,a495f216,b4994d90,4a79057a,3d0076be,34f09013,99f1f366,fc4e10b2,c1f7bafb,d241d5b5,1c57d48c,30fd29e9,df5774c6,1d4f2c15,3b66ed03), +S(a49ed10e,aaab9323,3a5f485d,4bd18c06,28ab2629,f0b8c3db,4d05956d,6c953fa9,338d476b,99f0ac67,1fcb893f,5f202204,a5178acb,6971e7e4,984d42dc,b904afbd), +S(4d000b62,1adb87e1,c53261af,9db2e179,141ecae0,b331a187,aa4040a,ee752b08,95f2a470,e71f2daa,34927daa,7d268d33,34820a0e,e638d6c5,c18d7adf,b7cfcf45)}, +{S(44d42980,eb92b3e3,b16816f5,56858355,e031b88c,99117385,def6599e,f274e56f,6e3de5ba,4f693fdc,747caacd,b2cf0107,f29fa7c,9c6a1a09,a527cd16,4c2c1484), +S(9812d508,d6da303,6f08fa7b,54cae319,232f925d,6af91d71,fe6c2fb3,bc86be5,735081a0,35fc17f6,7547b9b8,f0f91ac7,f0ddb965,19f6f398,dea745a9,81441e2c), +S(5a022ba,a90ddc87,42246783,4f692ecf,dd2c2dcf,b054308f,4afeb17a,7ff6ddcf,6fc2a9a5,4c7a130d,fd26ca48,82406fb9,f67db0ab,7e6a6d95,1675fef,2e2d4256), +S(c181ffeb,a8ea7d69,c524cd42,18af3030,1cac8e97,69eaf6f6,ba73027d,30fb7bd6,e88959e5,b07b7d3e,693756a,f94590bf,997763b,afa7d850,a80dd9fb,88e6e904), +S(e29375b8,21c056c,30954b81,4f9ce795,c1493dfb,ebf06f6f,f32c92c8,c74839f1,a9040ad0,95c9d45b,1527c624,bac86841,a1f28b7,ccf8dd37,b7e950b4,858e6e18), +S(69445948,ebec5ae3,9fcb505d,7efb7902,6bc1e8fd,5d3024ac,2b772439,72142d80,5b6c2694,abac3938,db899396,62635c21,e64fe2aa,40d18678,9c246e9,fe3f4be6), +S(a86f3aad,85d0bbb3,8270956f,58c2fd65,f5425428,27d7a658,da1b111f,64c02c36,dec740b0,ee35208c,dbec5b7f,69bb94f0,7fccd075,7868a37,6ecec7b6,dcbe20e0), +S(ba2bf65f,aac92da5,6c252b50,8dd74e3e,99ace1bc,42b9d2db,9d0ead3d,b6820306,37bcd01a,75027b42,eb0d7b85,564bedf9,67153930,6fc97106,ab6623e9,90b031ba), +S(78419e61,4e8b5eb9,d09e0c09,79ce4eaa,26271696,fcc68269,4cddf1d9,6a4c7fa,a32dbb3b,46f9b6b4,9adf4dde,f1986af9,72662a6,2ed6b6a2,f8b920b6,82b32363), +S(71163271,204207c8,a84b5993,88beb505,640898ab,b24c4c10,42195dd8,15d77985,aab43609,9370f246,7035ddc2,e71d73f3,c0f1aa13,148303bd,840459da,ae307e8d), +S(473f52a1,fb7c3920,f09ba6e0,a3c891c3,3f4a13cd,9dbf51f0,f3d39ef2,d6bc07d0,b2c403d2,4aef71eb,1b834df2,8bc08b67,5130897f,a6d9855a,eb21ccf2,780444cc), +S(581e93b2,99b8c50e,e6338c0f,f426502a,d8699563,f17935dd,abe08a73,6932b71f,46e7c7c5,1e076fd8,9b8aa98c,f0b3933b,8ca82cc4,d21783a4,d74ae1b6,ca9896e6), +S(e65d9e24,e7340122,875a9d86,d6071a48,691ed5e5,a94b315c,76f169f7,f3d69c48,73575103,a70b7a59,90d9b880,8698b651,271c8c0c,ac93122a,66873bf1,fa3c6fab), +S(cceab216,41d0597,f9c7ab64,7f99154c,b22d4827,70395d6f,ddd6db5a,dc752825,4084c57d,5aafc328,e7a250d0,a7c3c0a9,627ddd70,c77c2be7,e5a1af34,359b9b86), +S(4222ee66,5baff421,17f47df5,c1c1df5a,dbafb790,d5c75bb7,2646cf85,7ae85923,43088d6c,a029903f,f5a789f8,16730345,5a5cd0af,cab57e15,12781396,fcc9b6da), +S(391c5d0b,17a8c11,3440cd30,83434841,969b0833,71758b30,27e38a25,e778da6a,69f3d295,be55f859,4bbb2fb4,116de5d0,b24b5a80,ed62c1e2,8fca9b8,3f6d7439), +S(803b7149,f87e86c0,13599898,b0c9050c,d4a6e030,e07e8d7c,a49c46a3,8a6ea6a1,6b367fcc,6d5916e,72f670a6,5ada9c39,54800e90,a8830fad,c9ea17c0,494cd9aa), +S(f7aa1c64,f8f92f20,1319f316,353d89bb,eaa4d65a,e148b01f,ab66aff6,c9deb179,e9b407d9,4c2b385a,74f22eba,93dc35e9,bebca7d5,17401b7b,576b7d2b,e13ff0c0), +S(f1c34d52,2b7493ec,cefd49da,99732e00,85ace2c9,fd14e9b0,69b67dcd,5acd5e23,29460fc7,dd77494e,a5a7764c,7ca6db5d,5d7a5e3f,65e865b9,e5f85d58,e77713e9), +S(db19a1f6,38ef7034,5340e3df,8d384944,7500640d,cdbc3be4,df3b191c,edb9db87,baac873,a76e0b91,c4847770,9dbe88e9,6195e9c4,ac4d7749,71ca204d,4a5e748b), +S(4ad12e00,f384c7f6,ea669c71,3649da6,55e0abec,67551a58,224b9f9d,de6bdaf9,2e0314a,8e3f32da,33a22ecf,ccac4965,1f1f6f5,20baeddf,39a02bd8,423cd40c), +S(c9130b88,cd451d4f,6eafffc8,357ba391,ae920c27,69e7c48b,49881070,fd088ad5,aac7c2f,4f2f8b90,bea9267,897e0079,7d6515e1,937fa4fb,1043111,6b5e1de), +S(88260ca,df81b391,be79bde7,b54f8a98,428aeacf,970cd843,d683e6e9,50686db9,3b9b187a,b998a22b,56b2933c,fcd09333,9c23889d,1180e365,10dc086,9869cf2c), +S(3984fce2,ab73c70f,a5538206,c2a61e60,2f160b1d,2eb61980,fe174cbe,fe464dac,b7e65c1a,46b50c72,621e3fc8,4f4c7cf3,6860567f,abf00743,5fd1b13f,7400326a), +S(e6b48495,c8277598,23b73f35,762c55fd,8cd20420,fe5be6ad,f27f12b0,68bdd63c,ccbb7124,3b0300fd,993dc9d3,4b55534a,12515243,e07ab78a,8d8fd528,46e5a69b), +S(6af5144f,342f492f,3f506ee7,fc515d3d,d3c93d02,27ba841d,74bc6548,97d4830e,b195d9e0,8113eeaf,fab92a2,81ddeaa0,95356053,a51cf84a,b5d60fec,5368f98), +S(14439b7f,e40ca407,374da12e,217edd9a,86c84397,e2fcf6fc,965023,ba984a1f,112ad656,47c47c30,f19ae62,e0c06b35,effd49bf,d5e604d,6d621471,9f088fee), +S(d4a7e4b3,863fece9,660baefc,ee57d09f,6f60cd25,f4aa178c,cb6f8a17,5fda9d4f,4985a973,ab0e8627,f6de7ef4,470de4c7,1adecaf9,f3766197,a86f4e40,14ea474c), +S(facc2a9b,9d3ad0e8,9fa479e0,ba777a0c,90a0c229,59d4b719,a9304df5,f1e96ff0,6e12c914,70c78733,3e5a65b9,8c01d342,827810aa,be3e4e33,cba0b7bf,eb283b91), +S(3d1b3f54,2809a7d7,79ca2416,a7b7d007,4a728599,e4f30cc9,14bbbba8,3daa091f,dccd0d01,e56c7e6b,90829ec1,f0fc733c,8f1cbcb8,79916982,3b466448,cc21674e), +S(a8c1ec56,3cf9596,d761e41a,bd6bc960,562eeaf5,b54eb83e,3d7e7259,f69671d5,a03c9fae,e160ba53,8aaf38cd,96ebe3a6,db59a04c,ce7074e7,dc3757f1,ccc244e9), +S(219b4f9c,ef6c6000,7659c79c,45b0533b,3cc9d916,ce29dbff,133b40ca,a2e96db8,db2639fa,26a61015,a5bbe7f,3fc8d591,c6b0753a,c16fa89a,d820fe57,72c49068)}, +{S(b445babc,55be50ee,bedb8c27,dfc6c37b,492649ef,8a65de02,111b9f74,29b8c3af,6f74c5b9,f9a022b1,8d3a706c,5c608b31,9f7ce25d,8424d893,4cbd2f90,84b78bcb), +S(dbed76fb,7e46e1d4,1b507edd,8994fefc,f94bd651,a9720d9f,8d62dc3e,9f329104,c047fc1a,41689ba6,9855f063,c563bfe8,49bd8b5d,37b3836b,d8bc57ca,fd02ef64), +S(844426e0,860ff2db,f012ed29,ad2919d6,f46eb102,68073862,c1792e99,f1b2b33c,243512c9,c6ca739f,fb181482,a901ecc6,a41893f1,371d6b12,31d5427b,fb486394), +S(1df697b5,9a2f9c91,b2c5d4a7,8035ea2a,351dc000,4e1c3bd5,5973020c,24836aa1,e89f949c,f6af652e,d7e79758,74a994ff,46475df5,4f7b17f2,a5c29cd9,7f722831), +S(cf4ffa86,87d9a39,7b4727ba,a033cd02,7d8a5377,46903db3,34c35f1d,855999a1,d1316b65,e027ed02,b4be11bc,4c21c1a8,585bb247,45cdfa67,5fb9cccc,faf0c546), +S(e3eed1d6,1813e3ec,d1b9fcfe,3e8bd700,bf3412ff,78a0a9b9,724d4dde,ddfd98b,dcb09803,b70d4c34,ee2bd7ae,6444724e,9ab27c20,5c3c736b,172af37f,cc673105), +S(3a202c1d,94a94eef,18fa396e,5cb8a867,8c3ae45a,e4ee64b0,822d207e,6c814fe7,147992e5,ab565bc2,ad1b1355,60f37dc6,b5cbee74,fef8e5ca,4e4f418f,811a0482), +S(6ce8f558,a853dacf,205db4a5,80c4cbab,8ef477a6,47bca6cc,9e676cb6,5f3f696a,e88e3934,b2857ec,6edb911f,acd132fa,f0078971,2805aa59,9afb3d80,942dc23c), +S(7fef9aa5,b2df37ac,99ca488a,ba598b4d,eb222149,55e1cb4d,c3ef1e7e,7bd38945,d4b7cb4a,8f9edfd2,3a0efd1,9882baf,98312b6f,7b5775ca,65e9dbf1,f2c32870), +S(6ec1ce91,d1eff7ed,9beba2b8,2f4a526f,736e717d,6442dd29,b55ae2e5,3371e0a2,28240ee,12e2b1ed,b40698e,ba6f087a,145eb772,caece880,b3e94b97,700dbd58), +S(645b9fba,2cb739ee,9b148b29,8fbe9884,f284893d,968c21d9,50696d2f,efbbf0bd,b06977a1,2d19836f,add50b7,b73399bc,698729fb,fd182026,d918a267,eab4b7c6), +S(7b930561,3a4a7cc5,ce1e7f5f,29314e1b,40bc8b93,40604f81,76578c18,69abf6c5,55a7e3e3,3f19805e,b5056d15,deaaa4f7,aea07a46,f9dc6a09,6ce15392,e146fb3c), +S(bbcc74ca,3697ef46,e7415ec6,b31a0808,1e6ade01,c7e2264c,f9d4d94d,d849ccaf,27bf64e,e1005f13,989639a0,8772c42c,b4249ba6,9d90cae,3f542ee1,78929f26), +S(4a45fd82,af96af67,9e640bbf,561cb385,2585a8e6,1b57df7a,e028ed33,a017c680,4ba76ea1,19a0267a,f019b3b9,89cde9ce,7b1c0b6e,da3c773d,ca31e44,61e048ed), +S(c3efb1ce,ddc6a749,a5db9daf,48032a6f,3f1a848b,aef9e44c,ebd76127,a9c90d0e,3de258cf,e593b489,8f92e8ac,50be894c,3636019b,a9f31f70,28468eac,687b8f89), +S(ec71a2a4,6f24acb2,8fda6bbd,ab9326e9,6590a96f,b9b9a4ef,405949a5,e3d2858d,31a91fa1,71207da3,1b0acc25,cace1e7c,5126ca2b,4c8d9733,4c50a7f5,29bc61d2), +S(65dc268e,cfd191fa,f07421f0,dcb16701,f979ad24,81ac5ddb,1f77d3ab,41a773e0,f8c9ac90,255d6460,15ddd1d3,57b92522,53bb55c7,e2f5d843,d7d9a025,2766d2c0), +S(62152eaf,df564900,4379891,4b53ddd7,3b91fb60,f16f2d18,941caa96,18d8ffd3,3a185ef0,a8d8a35d,112f678a,6a04a654,df565a8f,87e99abd,95fb4977,1b278ce1), +S(f68e6fcd,b2c49661,ae59bff1,f24e97e6,fffe7cfd,f185d0b8,133d58e3,bec1c89b,223dee27,5e9cc518,af12be21,ee7ef3a9,ab39c7d4,4f950fdd,9ce5c78e,b50514a2), +S(5d02e9c4,108860e8,2b1ae04a,4afbe1e2,9e0a8444,89876776,7e5b60d9,3fe5c753,25fdcc35,5f1970c1,43dae96c,a1ef0a7c,f95853e4,102548f3,d869d3d5,8bcf962d), +S(f6217e4d,4e6d06d1,27668a01,8225f88f,a1e0fcd8,e8654fd,ab26c8a5,4c6d4751,65a6acbc,19bb2835,13eea5d2,5fae521d,aeed63ca,50f9aed8,edb74dd9,c43d066b), +S(c18bb768,bae77077,35b4d3d0,e82cac24,fe3d7ee8,dcba20b6,a320ba6b,4695a406,b7a7ded3,a589153f,8ee504cf,fb5b45eb,b2d8e121,40f2f475,186153df,1fcf84d6), +S(36fc443c,1350b40b,881e41c4,d3c15952,31f8da9f,cdcac4be,f1d0c5da,ceb9844b,9843bb7b,fd0ebca1,762785cd,55669233,16c36aa2,d2c37b3f,2b196f78,bfa5830a), +S(ba7b8c09,d5293e6b,a2548e6f,ff3c939b,80d2ac54,34903039,dfb8b661,29e19cfc,54fe2a,9353fc1d,a0d34e07,b6d34d1f,f3a1f67d,f4aafa7e,57919142,95c2a5e3), +S(50a8ddf1,17a91c92,37a48fe8,f1a00e72,a5dff682,7398a4c5,d2f78b4d,d49ee339,f91d9b20,da28e51b,99fa102f,13f5e451,ab22e139,80052384,6b9c66bf,b7da1578), +S(642ece53,832d1859,c6543147,56b618f9,520a5888,2549277f,6b27f16,e08e3d1f,d9963beb,2c6da204,339a49c5,f253498c,48cc3e99,b715ea8f,a5eb00cb,1d6cffbb), +S(a68c0d3c,13d764d0,7b513390,5842c9,a7171e4f,755a9737,609db06e,1a44e5e0,a2c3fdd7,b7938a87,86f3756d,dbc66b29,72469e79,839a1448,b367db5a,2bc52c15), +S(5b33d730,288fde53,b123fdee,177758b1,ec113adf,74e79eac,513eadd4,cef377ac,1bbc10e,9d45cb00,db58fceb,bc4bcf4,a0e2bcd2,a7d3ec12,7d87beb7,a134a20b), +S(aa6dc4d3,ce531af3,e68590fc,acbe7816,c8293af0,d77914a3,c7119e23,e50ce56e,14386670,5dbe1ad6,91e09123,a19a199c,3ee67b25,708ef57,4620c5ca,821224f6), +S(180a4ece,d74ceaab,e0f7db3b,b038034e,5e659c61,3c66a534,8d962d14,efa32402,b675b2a8,b845281d,524403d0,db01417a,59fd3a6c,80232e74,cdfc87f1,3b76b0e1), +S(3a55690d,abb5e00d,c2d0d8a4,96d16c44,76ee767c,a9d0d1d3,694c856e,e5b7ad0d,3c1d71e6,8a5f9a84,4de0453,6810660c,fe353475,353cede7,2936786e,4d173828), +S(33b35baa,195e729d,c350f319,996950df,3bc15b8d,3d0389e7,77d2808b,f13f0351,5a75fe7a,9bf54078,6b9bfc9,db72ad43,559a9f10,4377648f,d43afc32,34728817)}, +{S(52f79560,fdfadd45,6165a204,6bf61bbb,726cd726,3a3ed2d2,45f07631,5b0b6ae8,e6c46e55,5b4a0410,bf38965e,5a7ba381,fd259482,2280482f,877a7ec5,84d14012), +S(29eeb07c,7b27f82a,1b031881,11d324a9,4df77713,a8cadb36,2ce4012f,52cafb19,b7538574,28faf258,f240d4a9,f464797c,dffd0a68,f9f978fc,476f9bf0,1a0a2df5), +S(2191ebbd,a95c29f8,e7062f21,a70cb368,ac67ed59,dc44b167,66e52120,cfe8e742,2812f1fe,557496f8,f21b1f11,2df7bd19,db6aad90,59494ad4,eaed4d77,49f66a4c), +S(3c29d849,e25364d7,576779ec,78755ff1,8aa64e2a,65140a2,bbcf22e3,da33a4f3,3658d9ff,e2e283c,f8973cc0,ede5af6b,69ac4970,3c6b1370,f6a2ba4a,78a28a97), +S(37230e16,e11db299,f54ca0f9,f5423ac6,5f05840a,e166175a,ff0732be,c72ba88d,2a26ac2c,e8f9ebdd,20f1f5f0,f628d3d,d0e02745,6132cbf8,78b614b4,51db28f2), +S(8fbb3be7,98e16bfd,b738a512,ceeea92c,1be8eeb8,5374702b,e927c614,ab1f1baa,8280f387,64a48061,26392be0,c95f0c58,3607343f,d0b24b98,afe3605b,8f7e79f4), +S(fb639ee6,29dd1f03,8e12330c,bf40ec7e,129d7da7,655c1c21,86452fe4,9589c89e,171adbae,2efe213c,8d01e273,ed9c5d47,c4e85503,de3849b4,d909823a,bb1da898), +S(2399064b,876b7584,8c977bf8,e35d6b32,2e45d1a0,c4243fe1,2a31a581,d1d5d826,79c1ef29,c1af9497,f3b3db13,17432d42,86fa014e,17e5d780,a0d39df,b61369c1), +S(dd5663da,63acee49,eb7fde29,6ac1215a,772512ee,6a080f3b,1266c7ef,51da5dd2,d19c7348,3754112e,9cb3a4ce,8986f748,3eba26ab,c415abdc,5effc956,27efb7dc), +S(30862c58,43b161ba,c127bea6,7b23d3cc,46b6c42f,8faaa281,6ae47092,8ae47993,44ea1101,26a7c448,dfed4995,46a0fc8a,3658e540,d7d0c2b4,18f8cba0,accf9537), +S(df7ebbdd,4e416e4d,6b1e67aa,34915da2,cc15bf8f,f6d79ebf,273b63a8,32d6610a,d05fddd7,e9618753,21f473b1,bfb5ff48,65b3c4f7,5cf4ae26,549989a9,e13056d8), +S(13adba8d,2485bda5,1ac7994b,c45a7e4a,1b21aa9e,8188e631,59b217a,29d4237c,6256a795,3f24b25a,c1f59384,aac3eabb,4458e504,af3b99c1,99ae614f,8def4ff4), +S(c160f7ac,9a453a1f,8811d031,9849be43,22d8bbe4,89cad7a9,cb815927,d4b54720,7958b41c,751ef3a1,fb985ea9,c7cc85f6,c16282a4,c374fed,5999d8d6,3227b720), +S(c66af931,82a7a9d6,588e9c7b,3eda3b49,40fdcb99,346aa55e,e6549d4f,f9382228,ffe4d0df,43f00af4,fe885b10,92ae38fb,97d21a8d,26aa5f69,9751d52c,a9ccea4b), +S(d3a4f4d7,d208b43e,c4c2fd00,798d882d,922f302d,a199b707,76a70f36,5ff404aa,8df220d9,63faa827,1c4ee360,67a536ab,25813239,82252483,311616d0,1458e1b), +S(47bdd428,d57ed451,cd8754ea,817c5f5f,9658274c,ef6757b8,70527b4e,96f372f9,fbcf0ee,9fb14de6,3c288dbd,b1888fcf,72f0265d,3fe2209e,12c85841,2c375b53), +S(6e6deb95,7f2eea30,5d625288,3cb311c7,f0365a42,480fb807,36315c4c,62495438,ba0fdd63,9b8678f2,ab0fe3e9,a16512e,ffd9ec23,e691cd4f,86146969,534978aa), +S(dcd2775,7cd691e8,28e21987,d6eb6b54,e8def24d,27238cd5,dfb36a3d,d0f05caf,40bf37e7,bd776a62,ab420209,c71df7df,74d185c,f0d6b038,dea9c8e0,c1dad163), +S(eda569f9,9bccdc21,580da94f,92d89312,cef87d13,f08d8ad5,f1574e12,30a64ce6,4e1da1ac,dd274e3,f9d7def7,746f0652,678e549,ad5476d1,410adbbf,aa3c1e42), +S(5d3d4a29,734fb7ad,2846ae12,4c803364,ea3d57bf,e8d77d9e,6a3b3f8c,9cff26b6,d3e598a7,1a469323,a357df08,319dcd1a,d7337a32,c9894b80,6a30c575,b19756b0), +S(10161fa4,61e87595,f269da7a,ae3ccf01,40e910fa,891276c2,df1bd91a,95e4d046,b36eb5f4,b8291a01,18691f1e,50235d8b,f66e14a7,f0641dd6,18ad7ddd,ea150196), +S(7ba1b276,3df207f3,cfd1d58d,5190eb91,99cf82f4,9d2d0927,f5f260f7,2ea0f178,cb9fcac,4be96ef5,3134f513,5509c178,99af24c6,4eabd650,afc599d8,3927969d), +S(4bd6edd3,aaa1802a,b0f46e05,418ada37,e75728e8,6ea4b293,6619c92f,57674dc3,c9e962d3,de71eafc,7fc9a329,3bfd721f,305e876e,a2a4755a,f9567dca,21aa3c0b), +S(95fa0b32,40b24ba,29a484d7,f8f022eb,b3f30349,9d8abc1,9a69b690,3e885b68,dfe6b88e,56d7b923,dcf8bac6,2241d663,3ac2ae55,c3a01fcb,9f966d62,8f3acadd), +S(d0fd4d10,18c37114,2d5f8a86,617c250e,b6c3d5,210ca465,6ec84e87,d0ae42b3,4e3bf443,290404a9,3af38e72,a54fa06c,3b2d6a81,161fc8de,554edd9b,f3399587), +S(992e1183,d4e7afde,166c45e1,37c71c88,d4039709,4262163,b4ae38e,538293f1,c29534fb,55e47a08,ecee311c,8f0ba4c0,39096edf,b2d7ed63,21a2810,32e85900), +S(9c124ecd,4e6ce167,f60dcf38,25976f33,64cc30ff,61f7dde,966f8c23,4c13a4d9,7ad73bdb,e0afe3c2,c89d9135,d445ba4c,796066eb,1909349,9e6ec14a,f74f664c), +S(b09cdc9b,d102f89f,bcca0ed5,888519b,7c5c02b1,64ccbfa0,3d0fe42,b1b113e4,f409865f,6ab4371d,f52790eb,88df67d,84b3b74,f17edbc1,29b802cb,d5e49a59), +S(6b4f628e,beb6d619,1d616e87,3233ae37,ca4cc3f2,ac881e59,9c2c8e3d,295ccdc0,1140b988,60f4ac7b,659eb012,6fdfb796,c0baa652,2202cce0,bf54b3a4,865f171b), +S(a728c830,10169439,3af3f780,b1ceae3a,6ca08ea,4bdc7554,2ae84564,f542c28b,7b68fde9,8c97db32,eb3cdbd7,15816e51,9aa58458,259dc74f,5d722dc,f48f1933), +S(21ce4401,4ce959de,f16b3912,e88ff48b,d44ef79f,5fed2d35,bdd2dc78,de8f7605,cdc598fd,c5d30508,a2690299,e0e25b91,b1ccb69,97b99fd3,eca1baed,76aae6d0), +S(89912259,11b9132d,28f5c6bc,763ceab7,d18c3706,e8bd1d7,ed44db75,60788c1e,2574b267,83365364,d84789ca,a64ec905,c969637b,21061ee,9ca3bddc,7170ed3e)}, +{S(5914f66e,28c1a0a3,47f461d8,1d7f2c55,845e35eb,3dc39945,584b5efa,8d71a215,cd2ac885,3f681e4d,884e308e,ed3ca185,b47e2d63,3fdfff6e,efb6dc67,4d7de056), +S(519834c0,d16c807a,7867b8fe,c99dc93c,3b9ed218,87a9ca17,9343729d,3ba9e294,b867d57e,fe2dd7c7,8586303,152f02fd,f67b5648,78a7727a,190d304e,64f97203), +S(959eda70,cbabcb05,fa8fae96,7227b6be,876db942,ae38bfea,a9c3d359,977e1c52,86373396,9338053b,b00d206c,5d67abd,f95d35e6,992ad69d,8d8a3322,7370fdc), +S(a40279c8,48dc042b,a3ee929c,2910e326,eded6051,9d9eb1a4,98fdd7e1,fc88a6bd,f2c962a9,f2950d2c,acbfcf29,35bad39e,2709c0e7,36378968,fa04d957,1dadc4ee), +S(650b8181,edcfe46c,eea03ec9,f8ee5af2,c288e618,7d634961,6c95554e,25957334,ce140ddc,c2e2b07,a57e5627,62da3eb5,ca1acba5,463e97,fff7eae3,55b954c0), +S(eb04688d,5f4c8d2e,4ccd509a,3d003b30,8c5539b2,dd160a45,cbe71efe,36fd9005,37d80690,2062bde0,b96fc8ba,7a7f751f,9461f774,a1d6f3e8,8999c676,a2ae76b), +S(f79206b6,7813cd64,9f946313,3bac4aca,3762975e,954e0ef5,a876b78e,4b5a5d24,6033d4ee,936e956a,af117dca,6086eb1f,6466ab18,d503503d,4b011315,365242d8), +S(539c99d7,728cf662,13e024c0,9f1226f5,ca5d09cf,67bac12d,47814b2b,b1e7d611,87efd14e,e58fbff,5491bf85,aafd48ae,6680f37,e0d928f0,13fb6cec,6f417f76), +S(2308281d,e761f602,66fb8228,45eec88b,e32f8fdd,4a06b8b9,3dfad9c3,75d64a8e,933f4071,e4f2a9ae,95f4a299,f4267098,94b661de,c96443c5,f03f6cb,f3be87ed), +S(a93d05ae,fa31c0c1,54c02f68,9184c1ff,344c670b,e13eb304,2de517f2,1f6124ed,b7549c5,4651fa60,61f4103e,27d316a5,db531e3e,d7396a46,e360341e,f53ed274), +S(35717dcb,4feada90,b039aa79,10cf064a,c8c998b5,fcbb037c,22bf9e92,eba560d8,b6ff9371,d98bf532,f82d7fdb,24fffa69,2afeb0e6,59ba30da,602b3399,2bbe5a5), +S(941d37ef,1671d5f5,675be9d0,d5cb1f0a,ab6dffdd,2bd342c5,c5b62be9,88d5a0aa,4834d5ee,a8f9ae8e,ba5cc8b,2fb52260,33e35767,d55b6aa6,d204e0e1,a38b42ed), +S(c22cecb,aff78c61,f6e34c9d,9367c4f4,1acc9c35,29e9d894,7989a874,1d70bccf,38a37fb0,5fd9036e,762e2f0c,fef8fcbd,c04a92a5,4cb72ee2,ba08213c,4b58f1e1), +S(7863ac2f,1704fd,5015f0ed,30edf5d4,33c5ea2c,e150833b,a15c1db8,a5e4d2f4,7468fa15,eeab5653,c9f982b4,ad9e4c99,2f44083f,a7a93e9a,25ff70e5,b8742b4d), +S(f702cfa6,f0cfd275,a2c7af50,b53d0c94,bb965063,c433f4f2,cfd13d99,800da48d,3da4a4e1,bc5f2c6d,2f8daec4,599a9704,7c1b930a,b37d6b2c,f8a586cd,ef7dce1), +S(c3a1da3c,6e6b8f2c,2a8eb81a,1875f2b9,1e9cd286,414862d6,57626b47,a413d7dd,983d0892,5983d42e,bdbce2d8,df116bc2,f5cf8c87,aeb833da,e5e7e9ca,f9699798), +S(df0a4106,d61fc3c6,b2a14ecf,ebea3dcf,7e38069b,8faac576,a0b8a1b,7c8e7b5e,dd97a06b,840d64db,1798cee4,9334b033,e8d3f4a,79da565d,c6130da,f0bea75b), +S(ee9901fd,9312a21c,879d4e1b,24d5a299,b8200a15,6e65e147,4a2055c8,a2363423,1bb2933c,8b10f8e8,ab93ecee,16f861ff,a86781ea,59b891b7,740fdc2d,f6c206d), +S(52890b99,c8dc48c4,b6b1e4ae,5b823fca,ad9495b9,8217fa4a,b4f8e960,77cdaf9,6ca2ba73,72606e82,9c3395fb,dd2e4b74,8c771231,e86fade,5e2d728f,e5e7391e), +S(a372b545,bf56b58,b7c4628d,aca9bc14,e8bc634d,d79d139d,8eb7a2d4,13465c3e,afde23df,fad41c68,df94abdf,90a642b,31d62f84,c6254c4b,4cad2934,376372f2), +S(89d02f41,f88b1f7c,90b01078,d7599a70,a1eb9c23,1059e856,4237b0a3,2c18010a,7e8e810b,b063d75b,c224f41,a842972d,6fe065c2,aa6b16e5,7bf224fe,e44b2275), +S(7ef367d7,23fedacf,86425861,f67c5ba2,2deaf04,69e31988,7a3a3a12,2f39576a,4b81e743,e00bfbc,1d98cbc2,5c98c516,55e574,fc7fa1f5,86f15d9b,1b5b7ac1), +S(2eec37a1,5fdd1caf,b4c0855f,e86c5534,1a78cdc,b3944798,311b1cf4,7df768ac,1c18cf5c,1a98fe9,70d1e635,ab133668,4e0d964b,4df0b16d,7c51ea01,c9a63), +S(72208b8c,fd9840d,76dfa6e0,f36cf57e,502f285b,422f0ba1,9b119500,6b2ddd11,fa09196e,a89ce6a,888415ec,a8eb92f4,149bb39a,50174a85,8a29bf63,65b4e577), +S(9f46479a,69411d57,c3c7ea6a,dfa833f9,1fb2109a,fd30c790,2ce323ae,4b14be0c,6cd6d7e0,8494cb95,9e67c258,1be426f6,4eee4514,83e9a9a1,278b073d,758487c3), +S(a9aaf56b,5016db58,5b8116dd,cbad1169,4b16de8d,9db5ea5a,279ccf4d,91b1d7a,218fed41,389a4abc,44fb2a83,7016eb50,99c40e86,bb419265,7f57714e,194a5900), +S(5f950f20,b610c06b,76949dab,52fc6149,97d254be,a1330a0,493f1ea2,1d608864,d9098481,823b3ff9,d1c0b7d0,bce90856,186b45ec,6f20da26,9b158283,8a4c96df), +S(ed621f77,98add722,b0dc5e52,9c6fec6b,dff60827,b0b12c85,18d798dc,761f1075,a8973e79,a9caf1fc,e3165145,df08b7db,6b7187a5,28b12712,6c62bb5d,4f0c46d7), +S(15b8390d,652d7338,e18ee091,97e0e176,74f8c4ba,fa2e7b85,8f5badc9,9c89240f,87930df3,710172f7,c5422833,385a6066,4cfc9854,a3e5ccca,d1d06106,1cd90be5), +S(ac2acb9b,21999a70,540708ab,68338266,aef650ee,d81c5b30,da1e87d8,a8a923b7,897bbd7a,ee3e8db2,e36505f2,ec2614c,9f4f2f40,ed2d85b0,5d23edb4,2832db89), +S(17c072d5,6bdd1382,a782481b,8aa4d223,2db79438,5870bcad,c3063330,a5cd5379,26fe420b,d7c25f9b,1883edb8,50e2fcb0,76a65389,d9a452f2,8351fad,4ef72f0a), +S(8d262002,50cebdae,120ef31b,4c80cd5,d4cddc8,eadbcf29,fc696d32,c0ade462,1412c44b,8ea40bc8,2ce090d2,3c11c945,e2b504b1,8d9874c5,271f5745,f0d9b523)}, +{S(ad9144f1,bdcc3673,26d51685,a047ea9c,3c4feb3c,da4b9b83,80e1ada6,300ba487,68003744,ab5b2c8a,cca5bcfd,e1c4262e,88ffbc0f,b0ad4206,2d57dcf8,62c93c47), +S(f3b90a0d,7a8cbf1d,9b994b19,7ce215f9,b8ed861d,d526228,59fe1811,68727bab,95f48e8b,c05a7bf1,e47fdc86,87513ae,5a56472a,44f384f6,1153a954,2db68b81), +S(24af6d7a,99122466,45b07a1d,29b4bb1,a68b5b0e,f9422065,b5bb0050,61d43cdb,f9dc7725,f628cc4e,d4e5554e,f0166b22,566d59e0,4d55c28,a4d0e975,8306c31a), +S(f704aa4c,2bf19c9b,128311c7,1bab5f8a,f2a3865b,728f4838,b8ccc7d7,82574cdf,ae7c46ce,c44d54a7,2e3f758a,e855710,dee6b189,1223d120,9e059620,38d12453), +S(f701adf5,a1bd988d,d7e1fadd,9903c453,e6798760,252579c8,b90cdce2,a046d9a7,db39a987,48aa20d0,5d8b8538,fc4b7d77,95e2810b,160198c7,ad98305,96407c31), +S(bfe36081,c492ed7e,3b91059d,bb1af376,47dca509,69be6665,50f94903,d948ca7c,a1fc9468,2c3dc954,764ee858,822b8c1a,5d0184e0,93f12bbe,21e9931,18911f03), +S(e707057a,297a3d7d,904a615d,ac1b8e81,78f52481,32fa166e,afb621e3,af3f4f34,9161a930,bfd583c0,bfd3b121,acf574a3,6eb534ab,5198aa84,ef38253d,9ca19bc1), +S(27a6c7a7,970a9e3a,7cd42b6b,4478be62,31f53ff8,481791c,4394e78a,968fdddb,e4bf1b16,6bd56269,9e2c341b,b1a51c8a,c2ac7d28,807899e1,3ab1f726,90f44108), +S(e65f799a,8fb3b6c,ad088351,614db5c3,d64660ef,8c977ec1,2bbe58fa,a53314d6,5897f680,253a948e,fc260fa2,8ac39377,4e6a445d,d2bde00e,4e01ff03,b4398e2), +S(8406a84c,e9e63204,761dd406,9651f20d,6fc3efe3,f98951d0,d0a2db9b,cf86e0a4,ef81aeb3,eac17e5,676f4455,b4372ccc,e405b786,f11a871b,d781e54c,6307d1f2), +S(c012cad9,4742fd49,8daaedfe,5b847f34,7a45c792,53c8a645,2192e905,e256c7a1,c4866f98,48f31660,8a81da9f,da112a71,34232f9c,75e388,7ff987b6,8404cd42), +S(73795313,e9de1efe,3d91ae5,15c620c4,4f9c6bb3,a21e3097,c8794710,b2032683,548ce754,93817f22,cb96c674,5d67708d,c7b9b133,c71cba5f,fede1316,c55245f7), +S(352b89f4,78a47e86,b5575fbe,ee1373bc,e93ca316,1f594564,9efaf048,a60bfebe,d784e6cd,88d7862a,d82747d9,b23340cd,b50235c7,65f30be2,ab5d313b,edb0624d), +S(8a0b3d0a,80d41abc,4b8a028c,6c523923,7b040445,525dc345,d2d8a319,c4708316,7b7a427a,f0e1f902,dd1b9bb4,65b6b376,ee68b9a3,f495cffa,c52fcb9c,705443e9), +S(b4bf6756,61462829,53f9a44a,ee3b5427,2485b45,951013a2,8d59346d,62f65894,85d0c26d,2987dbd9,e26c9673,71ca86af,3b8cfb4f,cbf97404,c99ef900,5379a1c6), +S(bff69744,3ac23a6e,574bd1ac,d0fea305,2f05ea65,14814f1c,65e86e9d,5b46a2a5,36961462,5b998565,9324f5f,c8714d9d,57ff314b,5d5c2cc6,99a4ab39,69add4f4), +S(ecb09f5d,122adf91,e68e98ea,d39e5790,27e7c4ca,405bcaf2,e086d4a3,e68242ed,aa214cca,8a601fa0,a92633cd,a353ca02,7a7dee71,cf335af8,fc75de56,a3405f60), +S(310d957f,10fb34ef,ca3a2a0b,35c901f5,35c0862c,68310134,10982d7d,e74af8ae,289cda3f,29a489a8,86121f4b,4e75a90d,2bc4ff20,e95aa103,4044ea80,cff56378), +S(3a5f1ad7,c59ee6cf,e090f210,7040b419,4ca15fa7,dc8e9f69,20825fc4,e012ac2e,8ac8986b,48d7bd1f,5ae99535,2505b0ad,78f855e,d8411b03,15725571,dc99c920), +S(725f136d,1b426894,c24f8782,43fdc1d3,79636a23,d682f389,dbaf71de,d4672067,db0ffaac,ec5ffadd,f32396be,3f01fe2f,45bb0cbe,eb0d98bc,2390f3ca,c3dfec84), +S(b28e523e,6fc68192,445180d9,5da3e411,2fe0db1a,5b3bd5e8,e00a1090,39c69d53,7c172a4b,31339fb3,47db74a6,beedf59d,c24e6aea,c71e2a0c,434714b4,d61a2f70), +S(b808db0c,e34b5607,8166b308,1dd4b2ca,cf9d2d51,3079648f,fc3c617b,8e45ba09,d69c4ab2,fc7e490f,6887f2c2,49e0b71a,746e3e2b,97a7415f,34475bd6,f6dee79), +S(5e0b091f,3144d7bd,c7e40dbc,98c716cf,d7e64eda,ee9c1fa4,6838bcd9,e0c6878f,1586cf7c,da66b005,8b2d0d49,f588d444,65eecf42,1d94c004,a078dbd,47e0bd20), +S(1c3e88b3,ba46410d,8e08f9fd,5db8b53f,8dff33c6,4f5314f5,e005442d,10cef1f8,ba365020,5f85aa9f,71a42c0,392345b7,4a17a5ab,9ff91109,4d81252c,d8c8f72f), +S(b4926018,fb0e9c,e80c5614,37c3f22c,cc223412,384321e3,6f408e4c,ec0d81ac,55544f6e,cea3575d,e81649b8,4950f225,8a94e78f,13325ffb,16debe1a,8387173d), +S(f4bfac1c,b0834e1a,e332b7b7,1ab84500,b1c8460d,c8c2efad,6a5efbb8,ae78cd1d,5faab691,59ce9d3f,6bdb1818,676684b1,cc2309af,1401b5d5,137e1c61,5fbe287), +S(220ed3d1,fe028d87,b96e8ad9,37ede03e,ed8f262,ce877c0a,42718ab9,cb2ddfb6,5ee2d60d,f96a1b8b,e11c9139,7abf9b4f,a0671966,34bf37a2,8d26864,31933fb6), +S(dca5fad2,d045526,b6a4c309,de1d95b5,23f9a7db,e669b558,edd75ca9,40c85878,f350337e,877c9c61,98fc912b,5d53876c,78ea94cb,bbf3744b,62a52fa5,f5ae4399), +S(486ba509,3272eb1d,16ece443,861eae7b,2d8604f3,37014bc5,11267485,9872642,688d4585,9fa732c4,f582d65c,45930567,8c27dc6e,5525d47c,3908daff,f0a534fe), +S(96bc1bd3,b4840354,14aa92eb,6db81f5,403e2858,c0552d5a,6b21d33e,c468f31a,83027873,f4066b5e,ba6f413d,6a7d4d18,d57f4a62,25cc9289,b514f153,91ede3b9), +S(9f131ffa,b53e20b4,e9cd9e33,793f4614,922c03df,7d11222c,7fffec33,42fddec6,c4deffeb,3f4cd90b,102cb6b,3f713728,2c5cdcab,bc6e7153,91ea890d,76207bdd), +S(c15c8c23,d90c8e35,c1a214dd,e2d4383c,735ae45,bef61f10,aa1a1c25,5984cf74,d456ab27,d7adddca,372390ba,1da02845,b84088d2,af4fea5d,3b5b7326,c6334c2f)}, +{S(e24b71ae,8fdea24b,2d42a2c6,5cb022a8,2aa9e03a,3067a889,e778caf8,34903fa,f87d5757,cae83263,1233b840,296d6066,52cd1ddc,e8334629,25c992db,7e0ee14a), +S(886a7626,6203c559,807acbf6,7e1631ae,1f6bcacf,3fde277b,ddcd795b,292c38f6,b1f590a1,52d3ecc3,2b699c23,a89b2601,de78be2d,fa11b20a,1ef1235d,93ed9e99), +S(3079f709,3d5270f2,95fee75e,a6c5cd3a,5638ee37,aef535b6,523604d2,eed0d57e,492dd2cf,d76705d7,42187f38,f38982d1,85efa30a,fd1639cb,984a8772,3e912a91), +S(7773469e,c557e3e9,4097bd55,33a87583,a79e3eb4,2e421cd6,592363c2,76641966,f827b0dd,46f4b5fb,4a656731,d827cf21,df1ec610,f36dc2d1,215f33fa,20a08020), +S(ebeec367,eb032a6f,7c421ae6,f8fb56f9,3fcdaa68,f6741e46,1992d019,7567336d,6e78af43,e10c742c,35467149,3323f8c4,a6cff91e,7b1f1c2c,65b21fa1,e63f3a6f), +S(b41658a,3683b512,c751d817,f5d92f8e,5d158632,1f2eb836,b446aebf,d276030,9396ba60,ca61b35e,4e52e879,a457ce5b,fee9121a,b2673c19,15e78236,483e069a), +S(2e2ed965,a926700a,1428af7b,68b7dbf7,61d1bf53,6eb9f75e,d56afa0b,63852cd6,8d77656e,d5f11224,3a94e462,3dcfbbdc,61749930,dfcca6cd,c4303cc4,617e9133), +S(4b54bd22,e5604384,9ff2268e,88c695d6,4766e0c8,4f598f5b,634e1dac,d03063ba,176c68e4,a1f25683,37c14fee,dcf9a64b,17cba4f7,283428c,1514990c,98d29d71), +S(b6cf7c38,2d4c63cf,78557116,55b5de99,1fd32da6,8b8d2dd4,cfcd6f5c,59c45251,c4c190ac,2870142f,2a13d7bd,5d6768b8,fb5ccdfa,b99d0e3f,6bda805f,7741ff52), +S(857b6db4,79177eca,82a6c801,bd763647,c1a49021,e5b4f405,ad02e6ec,7ccc3629,586cde8e,cbf7907f,704a6610,f7a8a910,16599e9a,93bc6a6b,1b70d59e,39c0db4b), +S(a18a23b7,6643d92a,9e1bd2c7,7bfee61d,c5171b33,12f64d7f,821fbe05,6a771ee2,321f460b,b9525303,c159fe3a,6762dd97,60432307,919a2f1d,6120c946,47cd8568), +S(19b91028,cc2e5434,b162cee8,c77351d9,d38d9eb6,8ff9b09b,f26cb25f,4b88510e,cbcf2e52,3335ee5c,56ee2a06,7c565627,a5c60f16,808ea8e9,94250c15,e427c883), +S(657e2f30,b1e0241,82c0e57d,996cccf4,7bdf8eec,5a4da875,1638b3f4,9bcdbd2e,8e0a3117,12da36b2,2d0cd048,a9a99b26,5faadec2,14162083,5210f1bc,bb79fe3), +S(576879e4,f4a8e697,45014bee,36ba4267,cf72038a,f5997d38,cf512f08,f0ccf6b0,3f313f,388c011c,18ba0938,51b0e7e,84627277,2e9da999,b839b58,92ede5c0), +S(ed72d681,6516c2f2,7a9e97c7,1a7c99f2,faeb8e31,a5f29260,faa0bbf8,6475117f,331fb25b,e71c24fe,f4d2133b,f1591f3f,e5f8830b,15615134,36fc47fc,522ad4b), +S(e4ed422d,9152f00b,96bce64b,bc3ddaee,6089e1a4,1ffbb58a,109c688e,ba44699f,6dae6420,2dc6cec2,e4a49203,6b16c9f5,9c517436,bf3b9d9b,7e8f458f,7fcba8e9), +S(fc3b8afc,fe39404c,29622db5,b06c989a,8d7a0c4d,85018796,d006bd5e,43dec087,7b77feef,2211c1a5,724af5e9,a841e09c,d7940bc5,43d70c7e,51676689,7682ef15), +S(9c2421ee,e2e7e66b,decbd152,a8839f1e,4cf03808,649399bd,ba55cfbd,9dda6360,8d9477c1,c66a532b,967895ae,66c7585e,608e9653,4f870bd2,c97d7398,74a84700), +S(22040517,334bb5cd,2252d1b9,8a9da91f,a0bd32b5,562c8218,4d991e01,d94e8f13,167d3dd5,738a467e,f8e03064,d6482c2d,64503892,b4f5b9d3,c4b04684,fe2f15c0), +S(b648a617,3c728243,f3c0c7ec,2aadcb13,dfab92fd,77da9aca,1602d47a,80022dd4,7199a3cf,89c596e0,d607d05e,de95c8db,ad763ac0,76fa7ee8,ba7ae6e1,4c14308a), +S(a7d7ab3,6722b9d7,940b2a15,c94bb9fb,41a139d4,26215286,bfff84ec,57386dae,25ea853a,c3e772b6,f400d850,a7cf5760,ed568add,a145ea75,6f20b77a,c32d9f28), +S(9787a21d,ea3dab74,366214b4,933a702c,7a07c4ab,696eddb7,3a84cb5f,80f2ba41,8663b959,2214a018,e373e360,a9e035be,f68d9e01,f6fff1ab,f8ad9b8d,3f6f324), +S(1d2ebbd0,65bd4f50,8dd697db,9c8bafff,b548edef,856fa4e,39f893cd,349ff205,85d0716b,109ab208,a96367e3,bd0a2314,ad2c8586,169096ef,9521d780,61df01a4), +S(d0a506ce,14e88414,46c08a61,98ea0aaf,75b9dfc2,c4d2cc58,1238a597,154981b4,dc8c863c,7c4611a1,85744975,34c8c02d,7cb7504b,dffa91f5,96765a25,98d1f506), +S(b6c4d103,a57d0af,27e93627,f55a34b7,75b2ef48,47d7612a,5fac0748,b41afee9,dc9440a1,596cbfd9,ff87fade,8b426091,4799dad1,ce0f7b60,d032e94b,bbaf53f9), +S(5b5d965c,f2f37462,86f088e8,b58887ab,2182f874,484686dd,43a245e3,dcbc55c7,6718ba28,cf43ba30,eeba6e49,a7234ec8,7f01762,e915ff12,41fb461b,6d87a875), +S(bc85aec9,55e6e99a,c5fa7738,c7972354,57b3935b,bb69e8e1,ddc69d01,d34a47f5,59dd49e8,cb3100a0,9c48ceaa,20cbde82,5072e13a,7af0a44e,601044a,361dd971), +S(66b7ffeb,a34d8cbc,e00b4d1b,a0558741,5123d8b2,89ebdba0,47587d66,b260bc99,43bafb96,c88a5917,c6333dd9,b4a546b5,1c37ab48,3f3873a3,6932ab97,efd79712), +S(3cf9208a,b230b73d,68470411,bf3d4899,e0f19675,f829e32f,cd148d,3c07d7c8,21fc39b3,ea5079a2,ae131935,9a3e98df,62b97b37,2a473a63,f3b56e24,25b30e27), +S(66e3fcef,b7b24cf7,af0f8de2,8e53c2df,2bd1dfb2,c0289b10,31239da0,948e129e,df4074b0,488f3f09,a674a40c,b3207f34,a0282661,2e5ac4ae,8d443c9e,d1184045), +S(28df781d,4ec05680,590f4658,713c8a91,fef23763,87ddb6dd,674a35c8,b0e74459,eb66159,95ecf0e8,34f24e87,6f0dd86b,5c86a45a,fe5190f5,721f833e,10a196c0), +S(85d8da47,48ad1a73,dec8409b,e84f1a13,16e65c51,96aad27e,766746f,3d477c2d,a76b74ac,99a3996f,a794ac9a,ce103843,6b4f5fdf,cc3b2a59,df867e8f,382e1ebf)}, +{S(39ca1e6b,9fd848fb,ac24c444,5a9f398b,8639fa6f,c0c2f2b0,8058d84e,6c0caf1a,8797227c,f956ba7e,5228a452,91cdd51f,8958ab7f,43f6c8b5,e06176b0,dc9048e4), +S(4c87e538,c9eac9ba,d5a2a81e,43a6f1e5,f8403c01,68ad5020,4adef77d,5e3aecde,6ee8b74d,dd0b9bb7,c8b7ed7a,728dd99d,a9fab941,f0132d0e,998e65b9,ffbcb9a), +S(1226617,9f5dabe4,6d963b7,e96247e1,e29f2440,f831c8be,578d628a,78561987,2d3552bf,ddb5ec6e,a7758830,9badce7b,41d71926,857962d3,c3bb28cd,5d68ce7f), +S(866c0a90,893b6b3d,807a96fe,3c67b928,67c1d95,e05146fb,40038476,26981201,8d8f3188,da86e510,b7a7642a,97778201,3926dae6,4ce80663,335bc448,d204413d), +S(8eeb2e94,9a66824,26a6f474,9e7578d3,1b356aa8,d1b42049,5fb83e5f,5d08f723,e439d710,c45063c6,d23aad9e,ac0cae8e,36552ab,ca6f2c02,6eeb03ff,6162a052), +S(ffc93fcd,85fd9502,78369b3d,291f1ffd,5da44964,888d5eba,3c3f60c,95082bfa,9aa66635,a4b0defc,b2514e97,515aa0ec,3f65ce8,6f6962f7,72eaca41,d5ea7983), +S(605ccd66,4f18c83d,edf36f62,e5089f14,4ed23f4,f88635fa,ab161567,fd20c8d5,cfccf020,363a805c,1d614aa5,b9a912ec,99cfea61,5c088789,275ef531,dddf2418), +S(d1e4f37e,7d3902aa,dfdd7254,fc727a44,98eb9303,a12fe71b,4d193be4,8dba6913,bdd29d53,4881cbc6,c2e301fb,7d757bc9,9224f12f,4296e834,9badb88f,84fcc289), +S(f30b6d53,f330e6b6,b23d21df,7b4350a0,c42ad202,4a92751a,5dfed94c,47bbe60f,b5ca6c03,b31d06cb,183b0b18,4432a06d,8143d511,8af4bc01,c364f024,b46e0c38), +S(540944cd,42101851,c2cdb0ad,61264e18,cbf948cf,2090df68,54482628,74271ecf,cd16820b,4ccf9131,476b8778,ba3e83,f5970507,7110686c,653be572,2e99db3f), +S(846e5478,5d9cad5b,5109c7e4,6fd62b04,f686c723,1fc3c0af,66bea20a,d9d60dd0,4b1a28c1,78bd097f,aeee951f,fd4f46a9,4658a76c,268ee7b7,9aea4bcd,e75fc8ff), +S(16e732f4,43b4c616,24a495d5,4497a23c,c95612d0,58df9f81,11d1340c,4b2b8b5f,61ee476f,30ac2be7,e3ff09f3,ebf0b3e,2d76177a,30573465,101f4cc4,ec0585be), +S(4f30ef37,2c730ba,a6a40ff1,94b6b58f,436111d6,848b4e60,10be9b9f,abef17b7,b579a133,7f3247f2,8c6afc05,644778f2,3668e73a,a7c6d14b,649bf948,ef126142), +S(595a0d2f,1668c0b4,9ba0994f,3b681c42,6e3a67be,e957bf52,47acd9c4,7cb7d009,fb10684b,3ef1b0ee,37684ba7,53858b3,3586b837,aba6d82a,958eb947,2eca319e), +S(85dfb59e,d7ef6e0e,355e0ce1,304fe5dc,8bc6a3ad,74de3352,2089f224,8894e0c4,7a9b9ad1,10099903,d0d84a33,6838d422,5f98abde,32d82ab1,a383969c,1fb98bb2), +S(c8e13980,cf58416d,8719bc94,96e21774,c29f2e1c,5a36e760,2ce7783e,2c810fd5,5bdcded7,bb484d46,48bc40e3,ee6a3761,cf995e36,2af21f0,10048a91,6fbd4717), +S(80b98fb8,e48f44e,db69fd8b,18eec95,2404fb59,45c8a35c,bf3616e8,c746aecd,d44010a7,20622d14,6af5319e,155fe4ff,591bb829,f5086c7b,1fc1ed6a,32ccbaa5), +S(17629b1,cf015e58,eccdc7a,de049215,fca806e7,805e0e35,951df2ed,5cb87d38,afd56698,44f6aefb,528dcea4,29438e0c,d10c4b21,23f02444,a950834,97a61f17), +S(592677f8,695479dc,b215af2d,bbc90621,e7f3cba8,650563fe,1b2a8765,6c44107b,3741e4e1,b39b0e2a,58373166,854a1d31,ed062a25,c4e3e1fe,bc82e941,eeaaf50d), +S(98d5f85a,a93c9d87,e34e3bb3,597d9380,f0a7e5c5,b03ec219,4025c89e,42126453,dbe42a83,66753aec,61f7f01d,e5dfde1e,b4b989cf,95bd36bc,a66ddc0e,ffeea196), +S(9187b546,70d2b9a6,b711c88d,353bee60,72a1f5d9,ce75288d,4e6c9111,80dd4126,80e73529,d211ea24,d4bccff2,b9de3e31,c6307ee2,3cd9267e,b2d372ef,78f8d2c0), +S(e38c81ad,8ddfd8ca,4e01f380,78eafecb,f8edba6,8e33e565,309a3ad9,f0abe0eb,9f0ace1,f05f0a85,a1488644,88cce81a,2cf55eb3,a91fc10a,e6b82f47,60dbe618), +S(7ee9955f,99e218e7,dadfed94,dad7054e,3e0b97ba,932338db,69ed056b,6f8adf55,5244e198,524a105e,2b5de11,81d7bfe9,ad56aa0,128a3d87,8cbcc5c0,25b41ca), +S(eb9e5ae8,cdf64b28,76349aab,c3f75c9c,9d95a335,3214d0cd,d43123c,265b08d,858611ee,f67a32b9,7b8a9090,6639e998,a05d9bbf,8ccb7c1b,9e5eb711,4216b877), +S(2aa74ebd,7e8b6b2d,952effaf,e5545eb9,e99b9678,a2515698,975247ac,c83ff081,1ec12cbe,6877aafc,f353f641,1a5edf9f,e4bcc09f,31422df,d076932d,8f0defbf), +S(1b7b8fee,a3ed4af1,cf9b07fe,b435ef76,1d081b1d,f1007697,f78fe5d9,89076aec,b4aa0d8a,efbc71d9,d338e998,197054f0,20c5a2df,7a9504b1,ca7cb603,6641f85d), +S(3f293b75,9f152a4c,b92e319d,e5d02b82,f5dcfbc,2ee7a53d,fdf7ef6c,e2595c32,b67babb8,d1d1963,fd742c22,5ad5bbe4,27e57d6e,b9e17bbb,f91d2c1e,a455c1d0), +S(3eb9968a,c9b01fd0,882ec65a,8f9f5a5a,b0fbec2d,e2dcbf88,cc9a70b7,887ca59a,1a4de130,4a46fcc7,6719c254,dad5e88e,9d6a0839,9a9a28ac,7f171aa5,9624ee2d), +S(a559381a,f41b944f,e2bab9d9,62ec7c53,efb25ce4,1ff1a456,54a99f46,d97ce20c,ebc6f66f,75ad7322,4c1319c6,4268c997,4142,11ca65b4,58c5f79a,be0ba0cd), +S(a8bc942f,c60ff2e1,140f9a97,3d7e0b8b,77698254,57098005,f9186e97,9e430593,2a82070f,25480267,c4fca773,3173b354,fcd5cc1b,ae497af8,58b7d451,8f048c73), +S(2f456ca2,c4f8806b,ce4caf12,32446b07,3405dcab,7b3cdcc0,247dd079,adc7a626,7308e58,5b9bafab,b2dee049,9bbf60ac,fdb37242,3e915156,15314ffe,5ad866fd), +S(b56f4e9f,9e4fd1fc,7d8edde0,98f935f8,4c750d70,5f0c132b,d8c465b6,6a540f17,cd171acb,d63357a9,2c23ee52,fa7d2e2,de2bd69c,343357ab,b95d0350,fdffec02)}, +{S(ec474055,43c52e68,5c9e6c75,97616fbe,edb70df4,fe3c375d,d7d24729,2b120851,22c1c1a7,30066375,5ef8c2fc,86452667,90347223,f11a32d7,9f1c0169,a467530c), +S(3f50e502,c45fd922,94fcc46c,b3118a86,43af00d1,634bd694,dfc0eeb8,be2dd4d5,7cb992e0,f29fbc5f,2887161e,6d1e266d,f11fb723,3b6c020f,26eee393,fe96b526), +S(443007f2,43c3f6f9,76914031,c41e0d49,61337340,9bd4a681,f20e4c79,934fc2de,df67adec,c9ce5f6a,e6c8312,699e0353,68ee87e3,1e96790f,f0bd3408,94af74e2), +S(1e15b9e9,c28f77df,75837a0,cc9504ab,a3a49aef,26a88d99,543fa7d2,a875620b,2a081093,6afbc025,3808ba31,f5597287,e32898ac,77fd0021,9e6fc298,26b0370c), +S(cfff0258,ff6c0d97,99823447,775b75b9,1881e06e,bbd72ba4,28f8248c,5cf2144e,61e63569,5c4a8fb4,f68f974,219bbf4e,e0c277dd,4b74b843,88f99041,f97809e8), +S(2824f4b,f72f9229,2aa04058,7a0c5395,4c87e7dd,bc5dd199,af6918e,6db62f1e,16ab1473,3bf8382c,521af6fd,27f8b2b3,b421dbdd,bcf06c62,3bcd86b6,4bf33274), +S(5dc7571e,27d6b955,6c789b4a,80d49fd3,17416fa4,e04a7eb2,3cdbb88c,9c253a44,b7261e2e,39327d68,a5456abc,9d4600c7,fb6d6e51,a732c7f6,c64cbd0d,56de4a17), +S(e93f3aaa,5d9edc53,6029d332,9ac0bffe,af27d4dd,40f550e5,3df879a2,a5c1d993,25b442d7,f2e2e03e,c7f1588,16a1af43,b5d2870f,e0cdf429,babb19e8,951c0982), +S(8f91f5a5,7aa40d62,ba407d8,6ea5678b,65c84ea8,f241e2aa,dd6df242,52635a86,e9333d7b,d6c319be,3ff4f5b6,f286a8eb,27d5a1bd,29646cdf,77441c40,f716a6f0), +S(77d398e0,228add30,e9e120ea,b16436be,30c254ae,65016672,8bea1198,de1fb17f,749a20c8,ad6f4312,fb6e6fa,c390a4a8,209704be,3355362f,31db9b45,f3876963), +S(96976a85,b6dfc4b6,13dde357,c21c3518,a5f55c7b,a2d22976,592d7632,3b5a8546,96dc660f,8ef3b0b6,adbe77b5,69024fb5,dd713566,617cfc51,c8013f2,5b424e9a), +S(49093c4d,26194278,623c2ff9,6c8e2f11,f9edf3b,13c33099,57b57f1,9db451c6,5d53ff56,50b82edc,9dee9f43,ed6db93b,f6a26233,2dbcd699,130aa9ce,5130384f), +S(49187f03,d5f5f628,b9210b88,8ac4f1b5,2f754015,541e9f38,162e969d,6a99f4f8,276aacaf,d38d0bbb,416bcd0b,8ea590d9,7735a3f2,8de72aaa,76bed0d,6644bd80), +S(7d64e446,65c03917,87fe0b14,16ab1048,3a6025af,b20e8c19,3bbba444,2864c587,2c0da181,6507f8b6,4c9e5684,a4d53d98,d6b88215,772def9f,fa5a7a1b,f2b2ccee), +S(2223484b,9ee12b26,2a21a18d,2682ab01,c291ee1c,fe3b4b9e,2e93fb67,aa08535d,4cd26418,bf0d62fd,b266a768,5f7aaffe,d7bc95e1,be41c6bc,7a0c9076,1ace3974), +S(aac92330,7d6a55d8,552ce6f3,9c531d5e,afdd5313,f801242c,21df07b3,a656c618,93d9be6c,590901a9,1413cc23,94cb426e,e6a61593,93511c,e67e1ffe,68b8f3c4), +S(6ec1a0c7,fe40c40a,f3515ff6,60f0b53b,8fb6be3d,d912f8b2,c7a473d2,3e49d201,b10f000c,191e9423,60fe6b5b,2b6b7b85,73c0c2ee,384dedd6,e3dc04a9,7834f93b), +S(bd982a5d,a4d0291c,38568fae,ebc76df3,f2b0e5b9,1cd0d3b6,d2f32077,6c35c43,48566068,d5142f6a,90b13105,e7841d32,38d869d4,fcc7319,3e3cc9ea,76739c5b), +S(25d54513,b9084ddc,a3f20e18,94382290,115ad5f2,dc72c267,ba845b3c,6ade39f9,e908508,7fc5efab,a6f62c41,ea8fe856,226c8e2f,95dc31fd,2b49a7c3,6aa53b39), +S(29ab6cd5,add595d0,cb64ead9,c3d275a6,ce383f15,9340faf5,118ec2d2,9bb9a62d,54584613,dc27c249,d5d1210e,9e121aa4,7d606fad,1c4621e1,67f67b90,d8f3434c), +S(4cfd960,86f86d5,bd805667,55979c32,d5419dbc,946d63a3,40dcc6f,6d6dcd48,f032b7b5,9d85d0a9,fdc290bd,a1fc703,55b5404c,f70d45c,d15fa9e1,33ee9319), +S(9c786066,b6642e11,139aa303,800314b0,6afd4d97,e8314a1,de9d7002,5b7bbbf4,463a2ded,e2185c8d,944f29f0,140f6b66,9ad6e3aa,8ab6e292,a2af551e,685e58ca), +S(4e98485,f15c506d,6cd29d7c,3f9a59ea,4bfab065,78d86b63,f25e74e3,e7aea96,2baf3fb1,c26f2b0b,1a0725b1,5d1ceeaa,7ccece9,a1dd8f2,7f80d825,d8cf1d71), +S(8412c389,bc88e9bc,b157d835,85af0dfd,48689532,e38044b9,117b8acd,ce3b62cb,17eaa404,ffc1f62a,38f7ce99,6216b1f,40bb62e9,6d1f7a5,8bca370,c0d30b44), +S(31b9b8dd,7d37b38e,892e94c7,a5e817c8,ffaa1c1c,f56979ff,7f25815b,758b6d09,cdb680a,ae795ef1,f94e7e87,50ad9077,7a55eec6,c6f0795a,ef951e3c,ab45d186), +S(2be45d05,e89c58b1,8212890b,b6eaf935,6f03e37a,fd957291,4ab71a97,7af8350d,c3b05f04,c9f7a1db,b6689fe0,6ecf7a80,3ecaa147,8d09a1ec,9a7d71dd,a75406da), +S(5185cfa5,fe6302c,b5573594,61f375dd,c483a66b,c615b5f9,30abbd4a,5c7ae0c,83cc447e,53c91e07,6f44d265,389bef06,549b8d78,9776000b,5c35ce36,5fcff98d), +S(cd42328d,e4a16323,c51ef888,b7e67ba,f9ee1c53,82161b90,65e1db15,bddcffd9,caed06b1,7e86b470,b665de93,74725fdc,94792c57,5509ebfd,f012133e,122302f3), +S(7a1ffea,8fe5114b,8a638306,3b7811c3,25a40c19,42451557,679e75e2,b304ab91,1ef3fbde,4f0283ab,96efbc83,bcbb5a6a,d781a215,e6ff6262,ca50b9c3,986816db), +S(cf0bdf47,a3f15b24,5c7136c2,3a3e38f2,661fa8a9,4df29fbd,8b41ef22,c291dc6e,c73d1fe3,919e0aee,5b3adc4b,1a86e709,4b039302,d44a0d56,638c3eba,24857a99), +S(3a571630,935c1f02,d6fd8744,2c082060,cd5e792a,1c6f92bd,c4eed01,686df50d,7a1ec78c,4a660cd0,ae90c00d,1a8f5f22,1f5507e1,4487e5ee,2dea74d6,17a69494), +S(1c5e5481,32b49a7f,66ae9fed,8323480e,d1ab974,622e7cf0,8993895e,ec87fac,b00309f0,7c80b970,d446a605,e2b3d52c,5c215314,d901cdb3,aaa284c1,a03d2740)}, +{S(2b081f0,268d6ff4,1090561d,79144bb9,554b1f3f,1f0f2cfb,c9344e2,b692157a,597920fb,c528543c,26499af1,8b5e7d7b,5ebf5ada,5df4a46c,edef52f2,1e2fda5e), +S(2ce45dc7,d84d3143,884d6696,73738e55,e30f6045,8bac95cc,c30e86f8,71779827,deb79108,80a1b675,a628fb09,725c9307,d1629b07,8027f566,29f8560c,2ea80458), +S(9dfa0cb6,2a63244a,35ce3a0c,f102e7c7,93a4530e,21c6c03f,15a4fb91,e116c480,b01c1aff,902f0831,bc8cd268,663f0ce3,6d8e22be,86026460,a8950636,ce44626b), +S(61a32d1d,cbd7e887,def51ffc,9c1dfd55,d06d72f6,a73ee2df,f83cfa0f,52d47bb4,69a3b17c,fa91e3d6,faf28d83,2695aa66,c87b14ee,7b2d987c,80242fc,ce2cc42e), +S(8cbbac63,5414c0ac,b6d7f659,5c6eca39,886c3ceb,82549f72,d07a4019,e3076eb8,c838dc49,fd5af1b5,e503a430,71901bcc,90e1ea38,9f735e31,236491ec,43e7b621), +S(d3f77c5f,663c6efa,670b46bf,dfa96af4,fc4720d8,e1df6e8c,1ffc5696,f37cb55,aeea0c3e,50eee6a9,16462a13,90ce5d47,c060efff,1fd3108,1db77513,34300332), +S(6f774118,4a0210a0,79695d20,f93f861b,658137c,3a072076,7d80e5fb,8b1ebdff,c12aecc9,b55bff04,bd6b6e73,870deadc,666973b8,ec498bfd,bcc4c33d,23f5d674), +S(fecfabd4,897a948e,5fab7200,969f9955,9eb1c9dd,2a31325f,34dc4f80,13da72c9,ba70c9bc,c8048aee,6fdaf5f1,8ef638ba,ce739c0c,76ec4c13,fd4dd6c1,1663d02d), +S(d1a1a1d4,24fb5ab1,3e985c86,9bd7c02f,f81b4633,dcd22e96,c3f33489,2e80d543,cd5b79ae,af62769f,dce99530,8b921b5e,39a60fd6,f989dd7e,1d0d7219,e9ee8865), +S(7099682a,c3c083a8,80467746,fb924d4a,56f23d16,a3b57f10,1a824b9e,653d45,6a9c296b,cdd72c93,df840003,24ce78b9,1f9df6b2,bfa33922,ef32733,fe49cb31), +S(1035866a,4e9ff0fe,6b0066c6,3f0a2392,c0b8cd61,36e13ada,21f6dae9,f22c39eb,6390f9ae,ec1989de,2146cd00,a5eee99e,76ea4536,423e9bf2,c778ff29,85538fa8), +S(e18351cf,163e4df7,d31851c0,409b5705,a5ffd472,dbda5dd3,bf05e66b,fae50fec,264c1d26,41f185e2,72b908d4,77222484,c651e8e1,9a9e1fb0,1ec5ed4a,8a4b6c08), +S(dfbee778,ae4bc89,24f32c18,bc0a740f,d01922b1,28e1a595,283bfb4a,fd8f2f76,d11f9b3c,25ae3619,99ec2c9c,2f1a5903,d80eae59,e096c5d,c5e37201,81756acb), +S(842cdb54,414fa977,58ae3fb1,9316ef32,af9c4f0d,649f0abd,cb94267a,124b59fe,a016f899,288f4caf,dcc6edcc,3cbcb561,fdb4047a,f789e1a8,51ad21b3,be62f5c8), +S(3deb5d22,a81540ef,cff29ac5,585a056a,204e4d67,2fb858f3,5c23e939,790c744f,20d73911,5b24b1a0,a4b31302,73321dc5,d8b74398,d6516439,4e1423f8,b4022d6f), +S(3108e61a,1e0f079,f76e3ab0,d69cf068,779674e6,49768aab,718a09b0,640251bc,245a9f2d,141f390c,f1a17bcc,a06c5a66,5cf3a87c,1096f5e9,b04c4fd6,737d9a56), +S(63b9eaa,ce6b32cb,e4cf4a69,6599f8fb,3797bff5,9103ba0,c1351e78,b16cb0fa,938ac414,ef911df6,bda32b5f,1f69cd7a,87a25d82,177763de,568ca95,e846fa5a), +S(f37a5a41,cc96a04c,c882c27e,e362d054,7d6267f1,c91c5403,2daa5c12,1700abda,108bd6ad,27aa72de,48406693,758a74df,53a3ff98,d490e303,54c45ffa,c64638bc), +S(52afb7fd,6a16dc6b,98f9d7d9,555068d2,c2317035,b7492e8a,fbf28aea,3b1fcaf3,548d8ca1,2cf7a11a,b0100455,c7240290,6cb2e92b,101d1e2e,32ab263a,3f3de413), +S(f644fce7,874e9154,8f3fb284,b7d1ba17,fad6eb6e,c581f57d,5aa11804,86de9889,b2acbd8f,5bed4270,ec131ea,1891c99d,ddb46648,60acaf39,d68d2a54,a58b92bc), +S(863cdfdc,66065a4,50c2b7c3,1d694c58,e63ccc09,fccfacdb,4fdf0b1a,b150e937,14d168dc,c84d859b,55a3d5af,9d17ce4e,83bd90ed,55e099f2,50932dad,b5d2693a), +S(9f5569e0,50a26288,5d91f82e,9cacdf9e,f4487676,730f4da1,46ce8769,3d8807ba,cba008af,547e01f,6a9c6c45,8f9d71e1,8ad062c4,4b305b52,3f3a6655,3979a2b9), +S(a0f14b6b,99f0bd74,cf9864bb,17b1c43d,51ade513,6cd72a15,89312dee,706d50c1,e2bd2d82,c549b4da,cebfb888,c1a7c5d2,f0757fe8,53e07fb4,747eb7a1,542137cc), +S(9e7bd727,fbab45a9,db36d17d,5e5437eb,f028a10b,392ea470,d5cff0d3,2e9bb0fc,fb52eb32,e43133db,28125280,e3cc55a6,76877c58,b4051f70,9c031f84,24f12d9f), +S(7d8b1a30,4c0c8931,2d5d712d,ab396efc,7a117483,7f62bb38,62a81a3,660b1068,472a2dbf,ee99c398,94d14c1e,ce87cf17,c8aee10a,4720357c,c5ce79a6,19aafe2b), +S(d5eb073c,a5afa126,70602de8,417fe50d,bd8f0768,d615ef2f,565e421b,4e7842f9,52571e4c,e4f0c424,fd288f3e,8b6c54b7,7481c3a,43230fc7,4c6f48b,d4041089), +S(3c41cd8a,77728b07,ea592254,5ac45462,2c7927fb,6a7aeefd,61635cc4,217acc90,eab0f00e,84099fcc,c2f4d339,77ff7d68,4c035b3f,34c6c4e6,aa812c9f,43af366c), +S(1eeeca5e,cadfae31,188218ae,7beda45,57f85c25,5c99dd64,1d00d8ce,2e6f7809,d7e5c2ff,4ddf421f,cf09b655,113b8cf1,a4c25e90,d02b871,91dbac55,d6606ef1), +S(54c13737,454414e1,76bfaf1e,b4402bf8,678daab1,555412d0,c6d3fd44,653510ae,753f6a,f382d0be,f1dab47c,1b9368f9,57d586c4,acef0d19,dc241ce,f008ea3a), +S(4d608c37,1fd6f635,9ffc57c1,9f1aa5b3,5b0f5702,55851cec,34278d2f,465fc8f4,12d1592d,c2cbccc3,7e5c9fae,4b864e9a,ca6967e,9d4852e,9adc9e31,1000670f), +S(71157d64,8c0a1a33,19b713af,f806cf9b,c91a446e,2ba48ca2,fdd1ed4e,8c43da59,c2ac2aeb,a298fcfa,c0d5eefc,6eae54ec,330f5c0,5b34952a,9821ded3,9b72d383), +S(327f876c,93652555,fa80a054,968b4712,930dc930,12ee6b8d,c10263ed,3b89a762,4d2bfb15,4cadbfd9,4f6696da,a1e66846,8aacaf8f,1428201,636026a5,46dfc92e)}, +{S(4d3b98d0,b5926a8b,3e5622d6,10b30e88,caa6e7ba,eb10bc3c,38aec3c9,c1267578,e84056d8,4726291d,e6880a2f,2d3b0b01,371dfa27,5b8c9cff,4805d18e,a5bdc788), +S(6e463689,111d1a5d,d10b09e1,5d0f438b,1cebdb67,7a6cd230,bf6349c3,70667db9,de10eb3f,5d2f4320,7265952f,b33fc23f,154972fd,d3394cc0,21b66276,1b51db3), +S(48235e7b,76c94c32,b0d21bf1,7fc215ed,df036366,a9ef494,19723485,78db8943,4f5ac8ce,36c77403,b2fa83ba,1fd0e88a,3da4c8cd,3c10ddb,aafe2d0,5da40a2d), +S(668af7c1,4063dfba,1a4187f3,f69cb457,cae4edbf,a3bf9669,4080b6de,bc3e2f0e,ec95f37c,7bac26a0,df23275a,283828a8,5a102d8,f33eef1e,87cb56c1,850740cf), +S(d4426fcd,cbdfd904,725fb501,656b9f2e,2a9f9ee3,c6522064,f078165f,61c31d97,e73f2a38,c56838a7,174ee704,948d28fa,5b5fdc34,7774df9f,72f27834,a85eb4d), +S(d0f49ec3,42076b68,4cd91172,f15584fc,ea38aaf0,a3201063,f854ff1d,f68d4600,28d95ef2,82dd7d6d,72be7854,e8858b1d,a142002b,ad7b7b4d,bd1e582e,94341e16), +S(8a36f3c3,50bc0f1a,1b1687ed,4ff83a68,1578d74c,c28fa875,f6969e52,4887bbb1,15ab9e05,c3ff823d,ba090e21,1033c34c,fa713d39,feec4346,88e3ecba,4b431e10), +S(4d1ef23b,b316e821,7d2cc409,a1baa273,cc06f79,8fdd4d16,5d5b6805,3718e238,fc37e62b,db18154a,2add98b0,ec221e8b,bd1a2096,ac2dd1fb,cf8e2e64,821301fe), +S(eec1f8e5,76e87803,bac48bb4,65ed923a,a68b2965,64365d45,bd1c24c4,cf7041b0,2c6985e4,7cccbc38,3b85be66,ab34a166,c98a8000,aad08f73,616e4d2,2a15a009), +S(9fbc20e4,de372a38,90443786,bd7cfc40,c6195b29,4cf51874,6ccd9ecb,cee223e9,f734bfc8,a6973209,903edaf8,52f63bca,b23fc1a4,879906b9,1c5df169,9d24683a), +S(7984c8ec,a2b02dd4,e8b9c69c,6f803418,48f108fc,b63d7038,de58e567,e64a894,49adeb11,13c705a0,9eb01e50,dea5be48,86e5d424,689282ba,6d64f745,74f45e8c), +S(29a7400b,16f5712a,2324becc,29fc4b98,57fbb926,f8741dcb,324c26d9,6cd178a3,90770be5,5c0a94a8,16bcfa38,aeab11aa,5ec3b7d9,eb4e7d29,1bee1c02,69e87267), +S(8299d2fc,84770bff,a4e630b9,8f2e6744,99b1c7f5,719e907a,d70515f5,140a00c0,c790968f,a3c3d4ee,3e25a1ee,8e1d4923,3c22f034,ba7c172,b5d7d91c,99eabfa8), +S(5cfbd498,5b608db3,5d1a2872,b9cd03fd,d775e498,4629f41,61a2bde4,fb2582f1,8288fa89,81056333,acd1720b,bde757b4,e83d0a49,9c5f2220,521a0bc8,dbe827f8), +S(281f1fb8,e144e39d,9ec2104a,96bf0f1d,494eaff3,57fe084,63825228,ecd286e1,ae40e075,d19ee5f1,1dd7e22b,f1c277ed,9a02abe9,975609c,a7c811f9,7c54e493), +S(51698bc6,73d3289d,6b4882b0,cab14e67,97d31221,e5bc6e53,af061aa1,9f546daf,7b850099,fe977f6c,f50abe00,bb3a0b68,90f47c45,24e9ae02,94304b6b,20bd986c), +S(db701e92,9b696c86,d7fb459c,97af90df,ef847bf5,1d235337,2a2a4792,5fa8ae53,edc7e98f,1a108bc4,8fdbe65c,2904058f,7da5e188,e71d194c,4e9dbfe6,8a55d18), +S(c900f57f,e9a31d4c,9715a822,5a906e90,22d81c12,714006d5,81be0c7b,aeb5a490,8493eb00,90517d9c,b70a4bc,39043ffb,e0863475,17cde2,a9bd0d95,f616bb66), +S(d74e842a,fe2da0df,df6342bb,582fc223,717e0641,f1ce0e14,584c5c63,f379ad72,cefdbd7b,b4ecbdaf,409a0fa3,9a0a305,b1bd986,4913f977,bec6c47d,5d525c10), +S(b00a5f4,f033d126,64366147,a1bbb9b6,ea60a38b,863c5f3a,e323e8e5,1aee200c,11e9f1f7,b7701a4c,26a881ce,30fac1e0,92e157d7,b9c2e4ce,cffeb38a,172ead87), +S(5772b134,68bf9f09,d26074c5,16dd7472,d3a83624,92306cc5,c7544ec0,d73de280,2e2a7931,aefe2a31,6dbad1c,e7f9d42b,7f38197f,43024f16,9e27fbc,7af31d0b), +S(8bf8af02,ccdafb15,598f6725,5f172fb4,ba8960e0,6c81ffa5,b4c1c313,6f95f29b,96041af,1efd128,ef133e5e,b0aa3d9a,6ac3a651,92598b09,ed649847,385a9b2c), +S(292889a2,d8329139,3410385f,cf5bf489,7e1ee23c,e0e3b5ed,82ceb340,d89f87a5,41099fb2,bcec7e07,d4d4ad14,3cf605d1,b0a32487,1736063b,e49b06f6,d648aa69), +S(ad227b2b,737dfd02,665c15d5,9b28c7e8,76413dfa,25c9068b,90efa79,ce83142b,82f1eef1,7e2f6b86,87137302,741f8486,26fad679,9c6a22fb,3a49e341,c7e51e9a), +S(b4245dc5,5df02839,4cff2610,4a4255ef,89f3e708,21541c3a,4631ee4c,145bf85,5a40f72b,7a67540b,6858e5e,b15005c1,3fee862f,3cc54a52,7643204f,d0b8be2f), +S(15aaef61,568537a4,695c1990,c05ecb9,2c605232,f705c3e3,729720de,7e9c2400,e6efd1fb,b74e9e43,ec1244e0,bb4cff2,2a5ede8c,848a4f5f,5eec6f8c,77b6f5af), +S(ade2e63d,4a828328,b4c53763,30790331,734d7f90,37c1a584,59570c8,f31e72d1,c42898ab,3633dc7b,f3a454f9,d5475c4e,fcf1f786,d1f609fa,23616f26,b23a1a97), +S(d8a9043d,297681ea,c5ed63a5,de306500,6b66e4fb,167aa5ec,c76a8e2e,df426e7a,cd3de058,a0a93d7d,7122d777,1446b2b4,d4cf53a7,1759fea3,78adcf03,5093f4f6), +S(30651cb,592d282b,5348f192,5be3f04d,da5033bc,39e2fc7b,1e61500d,9769b57c,dadf77cc,44853f67,53b1dbdc,17a97d3c,e6d5b2e7,8c6087fa,800c5af9,ccdc54c), +S(aa21c60d,6f7d6253,9d42bafe,95c58f30,33c0396c,fa0ceef9,6d2f91ed,d6569044,4d519779,3b19515,92e2d952,2be520b1,11a5453e,ec6d7ccb,3e6db3bd,3d0c84c9), +S(5335cea5,e99eeb23,765b3444,d9bc7be6,1da67d6,91bcc42f,d43ae543,e9c22bc,c4072fdf,8963addb,5f980f7f,f314795,373cf3dc,935e0e64,c3d3d98c,342530cf), +S(708a530e,9e52c73b,ee87c9d8,8161c810,5d5762,2c29ae69,1cf999a8,3a1187a5,6477b7ee,1e065768,569a923,4492c7d7,c13258c3,92cac175,a75b0e63,b8c2426f)}, +{S(3fbd5a4d,ebbeff54,8c2271e5,33dbaed3,fb8ccc23,e3fa2579,4c8f7fd4,47ae186e,fdee4625,45bf75f5,5c29a724,6496d970,4616c54,ba01d0ba,feb9155b,cafdb555), +S(c1483ec1,78ba8414,c371b57c,49c687fa,69669e2,e3e1067,cc6d2a93,b1a9d24e,edf94395,962adfed,c2ebb3bb,29346136,e4dc870c,5c76299e,3b07da35,6bb26bed), +S(26df4b09,693a3905,2cb7a1be,5bc2cc97,222b70e3,3d297a54,43741228,beb77017,a3d6b908,cc6d5f80,aecda93,99e17a8,ce33c423,f00cfc4,dea8354,af502760), +S(b6c265d5,90475506,e15b2388,b894718b,be67aee5,ba40ceca,51876946,e336d903,b451d3f1,2c666c85,bf9486cb,296c39f9,49f9f98e,96d50a19,80f86f85,a1efb999), +S(da6cf69c,feec7b1f,c848639a,7e27932a,f49cd695,a2e56a50,693fa862,6e257c66,4506f44e,e6e0d822,7e67dc4a,9f8e2ec2,d3ec0c3a,c2a70c7d,d25fa9c,34cbe3ae), +S(d57648db,adf18b77,db185ffe,3f86f859,6adeec05,ffb86215,4b894a0,75776eac,a3f2fec7,7186d81e,4228cb1f,691e00e4,82a125a5,bbe9e6ec,45a53604,4932491e), +S(4de6cc4,d64d52c8,49c0e8d2,45409ba0,88248399,1916df3c,238be4de,ee2504d2,b389e7f1,ca72e9e,1cec2ed7,70f21441,590f0bab,1b963f1c,411f9bff,d3df03f0), +S(15f1bb11,78b01439,f26412,1d36a44d,b8333fbc,eabeb471,da2e6c1,1b8b3ee3,bf137117,35e10854,95acf3ad,97fe510b,33d6628f,e67d0067,499169e6,6c12274c), +S(badc76d5,481e77,9df71d6e,223c6965,9e9ecba5,8415a95b,eb7118cc,b1f931a4,475e47ee,115d258,3f0607f1,7542ccde,626e6d57,6ea884f9,61b41354,aef37247), +S(13015ae5,d770f4a9,75825bae,a6cbbece,78536dcb,78d7116e,d304aaca,199add2b,f5e28585,7a99ff0d,a4fd15e,8ac650a,98421629,aa102bca,25df3930,7e5cfcbb), +S(7734d2ac,707b9b53,afbd2a64,50c9b609,1905c391,958d7215,f92353ee,fd3c7be5,751d38f,ef48bfea,8fa5de06,8188a658,ae6c9c75,a359a4ea,efaac5e0,b5e859aa), +S(91814384,7fe2ed34,e9cc9c61,3fc2c67f,2b76a208,561d0e06,271b812f,6c678856,9a97f6e0,9888e076,93c9ebec,b8773485,c3c5d208,c793a77c,6984fb09,cdfd67b2), +S(98c516fa,2a2c8073,70ca9d7c,b4187108,ea345652,c8f814b8,b4a9405f,b48c2469,7b3446f3,2e8c4764,a8eb0846,4be3bc6d,f42b8d14,b7da65a2,ac96a018,d0831c7a), +S(5691d1e3,713302c7,48bf633,189ce032,10832e4a,9af1dbc2,abc3e99b,cb4faa01,d802e21a,fab84c54,5d665ed3,54130d9d,f7f18283,30b3a1fe,e30c2298,8b71654b), +S(1f8cb624,6440b640,aadba62d,c02f4ce7,a0ba9be7,d535987,64072fed,95c0d1a1,647a9dea,abf8247e,f46b60c6,53cdcd5e,cff0d1c6,88b7519b,a778f9ff,c894e1f6), +S(1489af53,94878f07,5cfb2e20,931fa3a4,e585d494,78818e4,f47f05e1,2be54d14,cd5bd721,4e535822,43270bc2,dc692ba4,c57e494c,eba92d4c,dd2e13c8,e24d8550), +S(66159248,2b2229d,ea70ff76,d2a5e70f,ad1905c0,9211e3d6,2d1d652f,ccd709a7,8f5ab85,57948aec,67e7b538,fa9c704b,ae939c22,4041e6e1,65f6045b,a6fd0fdf), +S(bc894efc,d0fb7497,ba70d654,961aa79b,6ac5a795,95537c80,82c525c,2c44c3a1,d5254292,ef0fb6fc,db587393,3b17adfd,87d13320,858ff783,75e356fb,b0d3415e), +S(f117d7f6,85457601,9b559bf5,f5bc150c,13363e7b,72123435,b441d98b,d169dd27,a8f4a23e,dd0d8f2f,8950c124,1abac43e,e629b0e1,8505c3bf,780ea378,20c8623f), +S(2a8d99c2,65a66a51,56b60556,775c61bc,b2a81a62,34896a31,16238c2a,b7716ec3,5e842306,efe11f66,5a049c0b,fe3ac74d,d72c5033,6dbd04bf,2a77b0d2,4d7ea651), +S(ea747597,1a6b6d94,2e368bcd,9979876e,afa4622d,313d819d,5e8291c8,2da95830,41d4a478,e0950bb9,e6595bef,3c197e5,d0f77ae,6340ca8f,2947fec4,70465193), +S(114150c3,fe8853ed,9f3e26f7,bc9f3d6f,aa50ba0e,6ae2d8ff,97924b04,dd9678b4,5530c22f,4ac30716,2b272015,460426ba,9602256c,ab735174,1a2fbbfd,cd71d134), +S(65d96017,c91a746a,656eb595,d39dc9bb,3476dc0b,1a1036f2,df7a4ea8,1846631,de46bfad,6999b108,1f358edd,7809919e,4de768f1,fb21dc09,4b248bbd,56b3dc76), +S(f2aec214,61c040c0,ebd18204,bc277312,732b452,266bfd55,aa071853,e458bea7,52a1b71a,eefe2c48,5ae2918,e236f1d2,1622d37,13b4bc04,36124567,d48cc453), +S(370ef89d,c39e637e,8bf6be31,63a4f76,7cebb202,c868647e,db18f991,977681de,e6d402ba,9769363a,b963729,822bd6aa,9794592f,36e54461,579ae53d,4c8bc4cd), +S(8db6356c,4f31f46f,961e4342,a1ff50a1,8240629c,a0decc36,e1bb24af,f6742e57,8ee033bb,96958466,15626ad6,736e9025,fb76320b,c2d0ceb8,ce3400cd,743f934f), +S(14a1a08,502510e7,1060f291,1316ee01,b1fc2bd3,c88eaa1b,656cba0e,8e3515e4,5a4dc536,b62c349b,c9bfc6d7,fb677231,1368655e,fcb9c89e,572aa58d,a57f08c6), +S(d530fc7c,4d5b4fd1,5f44ba0,c0f08f24,889b278a,93ee30ab,935fc112,5e244a58,39c0ea88,5984c2d1,d5119a28,7cd842ca,d3cb54c8,ab6aa222,c01e7152,98aad10f), +S(50f3c13c,a474f604,ca992658,bca68207,76acff7d,d507d63a,b5e18b28,5c5be81,685e151c,7d8fddee,6c9d8513,dbf167e2,c32dd70f,b6932397,38eb63fb,3e4f7afe), +S(c0a72dda,13174682,726ede1f,7ecbaa68,b4b137f6,d44298d3,4e17b7fc,10e19d4a,1e45ff3e,4a4239ba,4a897489,a265a60d,9a91f3f2,83fe2e75,9e770156,c9ebb3ca), +S(7121e14e,7e2a2c57,76b5702e,c83a845c,28785c79,9099a007,54b50fca,b4d9279c,e6b3ff5,ce62fa35,adf45e69,2ccafb91,b805d7cc,b6eff2e1,38dfd680,d0684401), +S(c0c01f34,ae41b8cf,e466b4c9,c6a5d5f6,14f570d6,fcbef768,a81a6c8f,5ff4adb,f47b0a41,1bca80a3,836c85f4,bf8a4731,3243bc2e,8f2ea47a,3b1008b,53caebca)}, +{S(4f20ce51,84fb2949,443286cd,8ea201eb,15248749,6e15aab6,f3ea2597,d4cbf47c,bf37770,62691c5a,d6c6cb8d,c30fd3b1,73578a3,bcac43c2,c8404b6e,c085c97c), +S(17ceec36,7fad4365,520599d7,62c66c12,5abeff81,ce7242dc,bde4e799,402759c0,91e024e1,e2147fe9,73091001,984dd3c0,9f887257,73bbbedf,47f00c7b,c5c9f626), +S(dcffc4a,5557f2a6,ac7a3527,5a8228ec,325ea0bd,d9bf52c3,8a78217,6bd716,87658163,dcfc39e2,ad08a499,898a1505,988d9b86,72b6d1e9,64e6845b,cb41129e), +S(625fff43,45337aa2,1efa0884,73a6662e,d5340470,a79576a4,362e30dc,bcf762d4,92ad0a66,d0bea2a6,d7eedfe0,e33295b9,3a656e45,9220026a,5ff3be8f,83184187), +S(410b96fe,7db23faa,7d123e97,c1a82a9,7b24a26a,80143e50,dcc6d9a9,1a6e81d2,ca0da356,dce88799,5f8cc790,64d197aa,6532dcf1,20fe93c3,7e2ff4e2,f14394a7), +S(8136e51d,ca68170b,136d40fe,76980b4d,d4f435fd,e38f3017,99de734c,b2491551,823dd1ed,de1d326,676649a3,9d5ba083,7c48e180,ecd0a648,eaffe7c8,2894e819), +S(64a67d9a,a7a31390,3ed9e348,e7300917,6c1d52d0,be63f54b,aa3ee8f3,f1227a52,ef770581,df4aa013,6d191e99,cde7f42,a14fdfbb,11e1b709,bb540100,1dcda1ed), +S(5fcf0465,a905aa8a,a1da5073,d524e8a3,30af663e,f4307359,c03a4c6c,c423dd9a,58641e67,fa821fc1,2307a66e,fe0129e6,4ace7c36,c3f5395c,db87667e,5e742a42), +S(aae6747f,ac3d8c9a,148009ea,c2d25574,39a8b546,455fb3a4,5016891a,f9372dbc,66084f19,b1d97f2c,22e182c,d5450d43,d56636e4,92651cf6,22772a7c,5b46d9), +S(377dc2c8,13e36bb4,642d1e02,cafce754,2ac6d9fd,c2212edb,5432674f,38e242c7,8395dc2a,39d3b1cd,ae9d7d37,d0c4597a,11f931d8,75c8bcf5,8eab03d3,674d5841), +S(35c598c0,7ac5dc3,7afe6895,29d815e9,406e2608,292ffa0e,7b24df65,3278d8ce,e793aaf1,45f538f6,c133309e,53cb5343,dc1dcc74,985c57f,27361c6,aae23e7b), +S(e9666336,6bb286d6,c86f425a,2d5658cc,1d733223,9ec2e9de,c8ab7295,4b329845,908dc533,b6098e9e,9b737e4,b96e7345,e635f591,60bb3df2,75e165bd,d1cc5998), +S(46fab0d4,7fc6586a,31cf861d,ff5e0bb8,cc12b60a,53103007,c8974ab8,204af703,845ab7de,7654fb36,618dbfb1,287534a9,2d43db6f,2a2cdfe4,5365b4b1,893fbe9d), +S(4d80486f,fe748d1e,f88aabff,76bb82c6,a45db736,76ee0ff7,d77cdffa,2c69d07c,2a52044b,d4fc6a59,fd16dabb,df35bb6,8057ad4c,292e87b5,528a3847,c8784638), +S(2c1d108b,f4945c0e,df62cc15,6bf0830f,7a45ca,1baa636e,9f759bb8,bf078a55,81e34495,d269afbc,1be39ce7,5417ebf7,d45decb6,eaddb635,4480a7f7,8d7dd34d), +S(320a08af,eac009eb,7f254b8d,395d836f,ca6ea527,4e2f309d,dfb7f120,2f1b3cdb,75269a2,41199c0e,5f1cd9e2,d102a294,2324a3ea,cfae231f,99ccc5f3,e0af00c2), +S(8b893fcb,9a524af2,6de5aa38,8ac3dc,2159817c,7062e5c9,d5c9e7f7,dd889ad8,cec6a5ba,481f7e3,88c1cab,c11505f2,39afa143,68977ed6,52ea2d6a,19d2cbfd), +S(ea89b95b,36cd5203,22c8e5af,7461f9e1,a054f23d,2720469,fa74cd67,3a52aab5,5325d16c,4b866865,2437b6b8,598b31c4,59e6101,2cc1b147,e0473527,5935ada5), +S(cdfea79a,8c16ce78,75a9fa1c,5b7647fb,ad641ffc,5b73fb31,d9354a1c,3c1cabfc,184c309b,b0f52999,2a3f6b93,77b9e6a7,6da6b943,d8031408,b71223cf,b3ba9100), +S(3daaaf0f,785a6397,c652331,630931ee,a975c522,35899736,1b7e5fcb,409880fa,952efec1,ebd4c107,b26a98f3,c6683903,a498c840,ff4a36c7,ade569e4,c899919b), +S(7cea5226,a56d21cd,45bfdbb0,7fea6670,40247c70,ef43da28,d1f8bbf0,6e4ef2a6,b03edff9,6a5f32c5,6f8f63f6,ba9feb68,f43cca62,391ea587,81396c7,5d963b67), +S(1f5f4c27,847ba921,c63cef52,8b57fef5,5bdb5344,ea67a23,c173828d,c59199e1,d37f6918,e0b774ad,317dbcac,75c82188,c8a421f0,ff5756bd,853a05b0,c95ef089), +S(36cd4da9,2a77613b,6417deac,1d9a0dad,1bf0e506,de26b529,7fffbd03,4a4663f3,ec1dd8f6,6226bf5f,fedb071f,7027f9d8,d931e6af,e378396c,d0d296eb,a63737e3), +S(9835c156,1be21ce5,db788f1,3c0aea13,fde6861e,97cb2cc7,a67fbd37,17eefadc,7fad454b,7372d969,a6e754ef,c73415d7,fcd4d589,c8e255c5,1adf5a9a,82228f42), +S(5e218414,d9c9f0ad,35ded20e,76a484a1,d41b3894,ba9d3be4,bcb4546b,371d0e4d,76966ecf,9c8f1c9a,452cf971,10ca6555,2ca59d31,21092e93,333bbd61,6eb9cfcb), +S(b105f4f4,40e7ea66,e3272da9,d6b2b76e,d00e96a5,6f95224,34ca0df1,5340c585,9e8fea7f,35bc9eec,f82ae118,bcb6dc33,acae587b,f37b149,1f8312e2,4ffc86d8), +S(81d5713e,a732b4d,98d085a9,75cac9b5,3fa65171,e5cf49f4,684a7856,7c24fea9,32480cf7,a0bc0c50,a4de8200,9343b524,4a0f2aa8,ce67b11f,4a5482cc,6fa00bf2), +S(d47b4f1,88f5e7ed,a9eab2e5,8ad2c140,c6278d63,517bfaca,8cfb64aa,cfbcc7ec,524f6580,9d3ee034,afb1e64b,1a0f8ae1,1e464915,3722e345,bfda9671,1b94a5), +S(16e85ad8,6a953564,39b97957,7bedd0e9,6e2eed72,76ba269a,626fbd58,447996c0,8bf74f51,4bdbb6c1,4de81a3,1ff12aa5,de49bd52,63a962ab,b777439a,47eadee7), +S(c299c6b0,6e6c78ae,852bd55c,dea35f99,d264cb5a,e836b77d,ab209ac9,c05201e1,a558c66d,c9ee7fa4,c777b0db,288b328,428b230a,7c53d516,522ccec4,af0ae08c), +S(63c4624,35ef974b,393b05b3,7d1c89d7,b0d8958,ebd541d7,584e2bbc,7235c795,1d806446,ecfc7bfb,bce099f2,6ce37a49,61b53453,5b65642,c0cd23f5,a4eef9d7), +S(6d36d105,ed8cc5ce,53f2cb69,8ab620f9,469a3e5c,b25bf6e6,d413f414,c5af726a,1b45a3cb,1c889961,8d273993,6a3affd6,233a66c9,4bef75ca,3a8fb6e4,ec05ffb2)}, +{S(abdd85c7,a2f8bc31,343382d4,e405978,3874c8d0,1405ef14,85047cf7,f0f71d50,d5a03157,798fe828,a03ab63e,84bb007,b53a5315,1db7af14,e4ab612a,736232d4), +S(31297c6c,f567267b,3c8d65a9,72afc752,e8525eb3,de2958aa,76f72e14,5ad903d7,f4735877,a6c6d89b,d1beb50b,edd1235b,5f5e5d0a,878e4610,e7d756c5,34813389), +S(64706e69,11a7d0a1,2e587c86,91117a27,cbfa64ad,1d5617fc,81e55b8f,64e0da86,59d9af3a,419957d2,b3de7570,15fd8531,a5d07430,5cfd7444,5e7e70b3,57e62772), +S(a4988ed2,89d8397c,f1b897d3,b81d80fa,92658ce,2b935f4e,e2e3f0f9,b193af51,813fb8,73270570,50f23c3,f8082bcb,563ee366,1f6b2af3,f631f5f,916c8478), +S(3c2769bf,af401993,595a01d9,9c72a6f2,699591fe,4b869077,8c6b5ee0,f172a866,f3e0d8b6,cff168c,95873f44,871d27b,df1e79a2,d9e0bd4f,6f90f682,538c1f24), +S(49d93e09,df655edd,19548fbe,affce201,4c6822a7,e196eb98,b9ddfad7,3cb70125,26e6957f,84ced17b,c64f710f,b37656d,31ba088a,98350337,8f7323cf,c57f0eee), +S(53c06842,49997cb2,6e5b4cc,5f166fe7,db0ec0bd,52639a27,d8fedea7,214a78bb,8a8dd3f1,b3081dd4,948255ed,dd178089,a0fa7342,1ea616a5,1f639057,34a489c6), +S(7a8e7d18,3f2aa640,d0e2ea02,4cdca5fa,1767d9f,9ae38805,5d38e8e4,a81d33b7,c2fb92e3,5556fd14,4a894be2,3d97c6d4,30872ccb,25e239c0,d959a24f,aaa77397), +S(a5221a2d,29cf3ef2,f066897e,4ee74ac2,95b34cd7,54390814,297537ae,abdf603f,ec0ff395,8c3a1d1b,5a379417,5a61cd97,782c9683,aa2c7c07,5d147db0,2b134278), +S(3f49da9c,1d62eccc,afc4b88c,814e44dc,8440341d,f347de1,fb60126d,59578dbd,c3cf8e96,2fa9478a,f1be08dc,961734ca,5021a65d,b1b45f80,78fa8e8f,d2813a79), +S(47b16636,f5a64b07,534be14d,6ae37af1,9da79b42,666b201d,d0afda9a,2daeb6b6,f1218111,31ebd87e,e1fd7c9b,d24a0a11,a12e842c,6c00f445,6a342309,9b171f12), +S(a7b5a8ea,1f23ff1e,c1768eaa,2fef0d66,b75744c6,dc925d3f,9068beff,d69b32f4,fe01a23c,b0e5acac,e60058a2,889f9434,9ffce6c,b24f4a3a,662e0079,99bcb690), +S(3e14e2c,e7044716,d42e9b6e,54cb0500,a1e4374e,18917336,e3205e31,4a878b47,18af982d,2c78ac23,818644f1,ec657da8,ad66bdb,3d5a9b84,3f8bb988,4ef8dc3f), +S(71393e6,746d3072,830299c6,c1244303,750742be,361c5f08,6eb314a4,76f1736a,dc30a7ea,9b644339,ce8f1fe4,eeeba07,5bb08934,8135e819,cb061559,aa14e42f), +S(37721b73,e6861f15,7993696d,aded49d3,78994f3d,e2b573a7,defc907e,d6f301f2,ee0e1755,d8efb25a,5cf4d783,ec847425,746fa442,d460cead,56e73a69,42561de1), +S(7803c663,509fc9cc,55b372e1,dc0fa76f,149a0ca6,3db4516c,4abc0ad7,5961e4ac,356c72f7,794a70e4,db3463be,eaa847cb,256c58cd,b6a7d862,fde4feef,d896a46f), +S(32976d3d,a3d033cd,c073b0f,c7d2f445,25646893,fbded1c8,1a0a1761,a8703206,5e6b7900,a069ce4c,65cd84cd,f290f092,2b936bda,af6ea40d,9c36a321,a7c9dcfc), +S(c52c7b18,b5fae5fd,a4e3597f,39c96b8c,6d6c856a,80f1210d,a1ebfc15,34850763,b87e50f6,20b66865,307d0747,a02ba22a,b310712b,cb0bab6b,963c589c,c5a208b1), +S(7de59c8c,3922fd51,68f4151e,cb783775,cd0bc0b,1185ecd3,6ee075e1,14e66cf7,688e2cad,e4d49da7,fe691497,412c9372,c67288e8,ca4b64de,308eabeb,723fda15), +S(ac49d6f3,32cda691,c345f099,667ace08,f6496126,830c39ed,877223a8,cedc8be7,267e6a52,5ddae4f6,7e05f0e8,52b9dfe,5101c491,64d791c9,82249937,c3a7b031), +S(5a92401b,698cc394,c9b714c8,bdcd92d1,20fa72e9,b1311839,1c383024,f469ed22,e29f2926,84c255a9,a739ef0e,5d13cc55,987f5b3a,5c6ed623,29431033,70edb4a2), +S(3609dfba,51616095,ab060e77,d6779025,6456eddb,f4b651c6,442cd673,f893878b,f85fa9b9,442050d8,ad9d9314,9ede8698,91dfc99e,c05a2a48,5854cbeb,55a6c380), +S(332bb85e,92c90a15,3bf602f,45dc33ab,3dea5ef8,7034af81,944113a7,4edc94d9,59b6c879,5f2a824,96d631b5,ceff8708,507db41a,375c7257,7533d8f1,461fbaf1), +S(16e9e054,916b894e,730d7126,27b1bc81,e7689efc,23cfeacb,a423362,df49d87f,303d0428,b701f1e5,fe8ae460,e54adeb2,d4b5aa93,a9c7d7ec,7b903cdb,20e440f3), +S(4e62ab89,1d4c4cf0,2c44915a,4e2fd522,88d75aa8,e22b7463,30dbfbca,97ed9515,a7c21be3,3b5cd522,4de0bd25,faa9c2de,5d6b2f50,b50a6901,b7167b3,c4def4fc), +S(649eedbd,5612c429,2aedbacc,b846e759,4a2b5870,f21452f3,1ac9e697,fc055db9,ca694303,ee206a4a,acfc4cb3,1aa9f117,8fcbe37f,d6bd11a4,669289cc,7c37b0a), +S(e858f72a,5fe2314,951ca096,8ba59760,e3d2a667,e76dcae8,c3ae2d7a,4721afbc,f1c7131d,3e2d0468,ebb89bce,700e0eca,ae83afee,75620938,60e1fc70,cfc7810a), +S(cd351498,29ccb1e6,9b18e35a,72a24b30,e074793d,aab4028b,1c5eefe2,b7b3163d,6bbd52b2,93b43cb3,a19f6291,69ba5b2a,59785099,16842093,1e58dc1,a040c57b), +S(19ffe344,69ba3e43,7d901863,3be7c298,ad8b65a0,49c30dc1,bae30ca5,97ab38fb,c33ca345,efeec662,96802e95,69f0f34d,12ceb64f,30fc704b,b77261f0,ce5c98eb), +S(8a2f772a,a38a5b55,a7081d0a,61bc27d5,89f9832b,1326a230,d81b9f58,4d634293,a4707a0e,a7bf528c,ac62e361,6f09287c,182aa3b6,6862430,dcfef3c2,69d1567), +S(e583bee3,1dbc8f0e,572eb18f,366f88e9,3a7a0484,b4299b9d,335f7836,a222636,8a4fae1b,be122228,be9d8afe,be223c53,dac161ae,ca77ff4f,e14d9c78,894fdfec), +S(8b6e862a,35566848,50b6d4f4,39a25950,47abf695,c08b6414,f95a1335,8dd553fd,15a1f76e,f12ee34b,f2ef43d2,b14605e,db53c3a5,e7cc7c2f,27fc252b,c1641642)}, +{S(1c185b5d,e988ae93,eebe0aa4,a98396aa,fff2671d,8246ce2a,4394db96,7a541ad4,dddf4244,3532024f,d225f86d,133b8156,3ea8c92b,f0ddc354,88e6a04a,d41da5fc), +S(addee173,b29de510,58dc107a,47fad47e,c48bf332,2f7c138d,51060322,571faacd,3890624e,c6920ca8,6a9aadb9,90a15156,799dd771,901823e4,9f3bfcb6,8bf05d5c), +S(9e20bbed,ccdd5c05,d683b2ef,852760b8,e246e5d9,6a8900ea,999ac8bf,5e8f12e3,9f28e5a,b4257f6b,b826d076,ffff259e,1caeda5b,7d34f658,ddfa0401,7cd4768e), +S(dc825d1,5f707c17,46920014,9d7be56,acf2d1d3,c444fa27,cefe5019,6f5b317f,226d4960,2f349d4e,9cd10a57,6bf01681,e4981cb6,4235d347,72a1e5ce,7694a20c), +S(812e2cda,3f473919,1f2ac087,7d70d0e0,2ca0551f,10c96d95,51ba4199,22780f90,c8d05855,6b6364bc,d9aff119,5b9ef26b,85cffa72,1e880b83,eed73cbd,d23b91e1), +S(aebb0870,76f5918e,68194fce,42d0b925,cfd2a506,359af62,146c8ceb,8502231a,c1c19605,e0456cb1,3e57229b,45c83ff7,c3695a2a,31908bc0,31b08140,9c2040fb), +S(af7332f3,3ec274c8,d34f47ac,fcbacf8f,7980cca5,7220012b,8fd5ff94,cbf3d8b,d439f1a2,89799dc8,92b7e53d,a84a9e82,7bf7bdb,7240c34a,caef59a,777188a8), +S(baf71cf,7851a758,12d7e09b,192741f2,1b5d2a36,6e31892e,e54c282c,81163a6b,1ef3bf2c,a81acdfe,17cd6b45,266241a0,22caf299,ed4d87cd,68d3d4d4,526b4d38), +S(615991c5,d250cebf,8c7bd1b2,969213f0,403c7da1,a3ba913,44fd0490,88c2474d,4f014177,12142cca,163f29a1,f5790004,32726712,93c2e87e,f46d2138,c14040b6), +S(b1574b39,26ff27c7,b2dace6,6108b93f,3fc75d48,478567cc,66bba29e,750c0c86,2759967d,8d05be25,3f88a66f,830dfb83,5139e32d,6f42cf3a,43b199ce,ab85b55c), +S(5fe92a7f,d1c407fc,967dbb19,e9fd4d,8361aefc,a3d5a9a4,2f8237a3,458e5e90,9b89ce35,57d469b6,9b9034d6,cee93609,c291d023,d1d9349a,d9bcf47a,aed8b2a9), +S(d65b0a5c,41b2dc6b,e5aa87e4,adfef952,621f9d99,550e424d,176ee180,65f666e,a76fad91,3b80b0cc,3d3ceac3,9a465cb9,4d8c79de,92adf9cd,7a4efae7,c85c30a4), +S(61d7de65,fe34ec4c,f82f67b1,75887263,11683263,145cbeae,18ed192d,14ced48d,effac049,d7e5412c,5052160a,6d1b2230,7157669b,856af0e,e3e46a25,2d2ee19), +S(9a77de66,5165a9be,3dd2758c,39aa7a14,1f052358,fbac634,5ea701c8,c93bc4a9,1044e428,bb381024,70108d56,b8b3e3bc,7512300c,5a6ae44b,93b2098f,a13fc023), +S(4ccb2426,b6eed0f9,651f80d5,72b23e78,d84d6928,57648077,3663216a,bc8a418f,1840c,bf5ccdd7,19f7fa8a,33e7151,aa351d,2f620972,6ec67d1f,fdada8c6), +S(53f96bb7,86516e0f,2ac7611a,1aac61d3,cfbca76a,9609fe,e4cae036,52f68271,97e3acbc,468b777b,bd1c8263,5332dcc4,b08b9fb1,9608fb35,cd51e49b,f09d9087), +S(395253a1,b6a349a6,dfdb0d6e,65695572,2a597411,fdea9294,6e48d107,596d8ac8,c57110d4,dd0d35a7,663fb3aa,e15d8c4,dce5cb67,d3173d91,a6ff7ea2,1bd28107), +S(d7becbeb,c47d0de0,899ffdff,8620124d,b29c8e5a,fd71a0ed,76e0df76,bd4e26e6,d8b52fa3,e16e7f19,e925e769,3b5a731e,18f3163b,1ad4db34,7f878381,da75fc15), +S(fa3afae0,4f8c1fa2,778446af,88e29150,256b0413,d9bfeb44,45288e41,29be15a5,9dc76b39,574453ab,2d46cf23,ce8cdb06,cbe7df15,d03fd390,4470a86a,822028df), +S(da56da00,dfdd788f,90a12219,db03cac1,403efef3,ae706031,e153aa16,b3a52eb3,1012ca8e,ae20efdf,41c77128,93fce97,fc66b187,caec55db,7aaa81ef,cc12838f), +S(f07866f0,cca3474c,40e7fa59,26df41c0,e46fbfce,faab92e8,9ccd1170,3ccf79bf,37ed66d5,5e891f4,e644fa04,182f34b6,1f1aedbc,d2a71aac,dd1523bf,f579dace), +S(853f72d1,edc4d953,348528b8,3656894d,67032333,28a16801,64a84511,15c5e968,197737d0,de83e73b,247d861,510ac76c,3ca214d8,ebbb958a,74ce1c31,5e715e87), +S(7c7eae74,dce7ef76,9ef0ce86,cf6ac861,ffc3d4a9,6313f379,fb2c0325,daa91aba,131e1689,fb017e15,e869d858,2dcfc4f9,153d1e8d,246fd613,b3922302,5b5c3767), +S(56028652,bce9dc6c,c8b4ad5c,f9f222c3,412e5bb7,8d556225,2c06c2e4,25a6e31a,2aa8e093,d8653f6,2153972c,e54806ba,666d49ba,3787934a,a37bd65e,79374ac0), +S(2eb98b01,550a00dc,59d280b0,71e472b5,a65eea89,298fe4b0,9f6f0e07,9315ad7b,74e22fc5,3daecdee,6a0b50be,e17f1d7d,d9481e77,28778957,274c8d29,a0d89fdc), +S(7268b61b,f65d73aa,37766a99,9960d998,18aa4ef2,ae8a97b1,db8476fb,32f891a4,824e99db,3157b706,38573513,618f6901,ce1fcff8,f25019d7,c5c45bb2,f3bb4d47), +S(cdea8771,4a764e3f,a94e7356,879b7d9e,da7c5b6f,28c172a6,1c0ab012,9b9ddd7b,daf49b12,34ce20aa,263b4349,f9f88cc5,1334db26,59b7c587,212f407f,cbb2644b), +S(38831af3,193c8860,690a9d74,cc0079c0,9e3ae0fa,ebe0da02,67ad6e23,99059d19,be188500,5193f11f,e34e70a7,e470cedc,902bee92,e7041403,c2f1ae53,7a8bb077), +S(df3acf55,bc6d97ce,34ebeb46,34fe1010,ed3d6d6,383c11a7,53a93123,e9c8381f,94c22735,ae6f858a,59f663e2,12532e14,4efe6a81,981c7619,e5002968,dcb81df5), +S(a8b08b86,4946ac6d,a101eb85,ee7bdf55,24282ca1,a9956e4a,eeb1afe9,87a43ddc,80ff0174,375c95fe,cea6e00,20f17123,5cda4bba,d4ef893c,78ffe37c,205d5577), +S(fd9941ce,e1c26864,248f7035,352787d1,aba9e93e,f5edd333,d08c89b8,4bb9dc8f,85be138a,42bf190b,921681fa,8777a619,878d4d02,11016c72,8bc151ab,1a687b5a), +S(7e2cd40e,f8c94077,f44b1d15,48425e3d,7e125be6,46707bad,2818b0ed,a7dc0151,6fa48af7,d523054c,7d59e574,cde106a2,776411bf,5111f7d3,65c43ac5,df8ddd68)}, +{S(282c5bc7,5b9c3f76,73e244af,29f22b80,c171bcac,d7e39b4f,ac7ba6cc,656d9010,e8db2eb0,a56699f1,73d5b5f7,99d39e14,dde34648,f159ad0d,c1c7767a,19ae72aa), +S(d5a3eb7,cad9c548,839ceb7f,67145e0e,96c60d8d,68415f76,73b73700,5ce3a8b,34ae4e12,355d1df1,25149efb,1a9050fd,490e251c,4404fb37,31b6dcc9,e233b9f1), +S(68718b29,86197989,3c5f7b1b,48abc254,13bd23c8,96c8828,7000ebe6,6db742a2,bef9d2a1,bb596fdb,3caeef3b,4d950568,8a94b436,4fd85f37,30b20de,b9e9a4fe), +S(a5ed1709,7932011f,9a597511,a526e61d,f22d0bd8,ae3e15ce,655820e6,b1ff1238,dd6dc7d0,81e70b57,4f235c10,c7c3dbed,a57743c1,15e6fe01,a20ac751,34cdace), +S(ec37904d,9662a487,1a471d9f,778bdef3,430df9e2,26fc42e4,7fc4bf5f,80e3a9c4,8413f2f,1ed55d8b,8448e336,ac9d1418,c48846e2,acb43509,f1a3d935,8cd18ed6), +S(b09f9c76,1cbbb685,f695328,61c459a4,d2b16989,3cbbad2f,dd49c87,1d860db4,dbbf9049,31b18454,21c41f2d,2185e3d6,c8f55dad,f1514ab0,655c856e,3391278e), +S(ed1a335,48864e9d,b41abcad,3344f4e7,ebe57841,9371095a,6b95fe4e,ae59edd7,d1146be9,83adc77d,bd9c107f,3092a9c2,9c271248,d78ce913,7831127c,c403f44c), +S(d39507d2,6ba377f5,c7116aca,78df331d,a795cdfb,54e5c912,8558c0e,997b74f3,fa7971d4,32cb5a44,589dc705,de28ad0,382206f1,6e11229f,86ff82a,efef3131), +S(641dc311,baa77b14,35f408e1,528445df,53c5ac5c,32803a3d,84e8fb66,60d71d,2b355a47,76980bfc,8a4e0ac6,a3bd7b02,a6b20ffb,f8650b16,89010456,6953e49c), +S(c3dd73bc,cfb744bc,57bc95f9,3c260df7,7f3b7e74,9e4a5237,f3865f8f,f0c89489,15d58dfb,83654754,80e53bb2,a1ba430a,ce213c38,ea71c7b7,51b4143a,fe2bd124), +S(3f883fa2,e834df1a,6e9b5c46,b663880e,9a0b42f1,891b92c,eb30600d,5641813e,7acff194,a5fb76e5,bd3d8fd4,2c7f07a8,3a991ba6,7f0e4edd,c55e1d8d,3025d590), +S(70c8d4f5,21d808e7,221bd5c6,31f171a9,5e7aa358,4477068c,2549c59e,228688bf,52badf20,6106d5a8,d7bff921,580eb5f5,3a53aeff,e0369f9a,1bcb282d,7b4cc26c), +S(ae08db34,874d39ff,bfb9c92c,5e4253ca,7ed508fd,d12841e9,63600461,b2b3a0e1,dc0504ef,d209be71,381eefd2,91508120,fb6ec1e,df62d24a,cb1d77a9,4eebf1be), +S(627027ad,4aa88477,c6240517,87a25b88,7d5b98f,b968221e,8e45d584,3db6e0bc,34b553a7,c6ac7004,69367afd,17c5eaf8,7605ca18,6a57667b,650fd8c7,18ab76aa), +S(573ef2ae,72ae8fd5,eeb0b720,f8967b44,f7d9d96d,c8a4825c,23a3dbed,fd2bb442,264f508e,efe5e0a2,55e55a54,bbf739b5,757d0a15,994ea9b8,4e139738,7c484786), +S(28907848,cf84eec6,773a384,ce5f4a5a,24c8afc8,606488a2,ccdeff25,6f896dab,ea87d4f,41df8727,2fe84537,d11126d5,62618bee,a51008ca,895a8375,4f05ec5e), +S(163db4c4,536114f0,75521627,c61f62d9,14214d64,ac9e66b0,d85b9991,62c54c5b,7ffc24e1,11c0c845,1c574e9b,e4b56610,696d3667,a6e6abbe,9d1a5ea9,4122aa1f), +S(2ec11f2b,71ffc28c,fb5e779e,7739098e,c969bc78,3cca5a22,77d2bf53,e6574d1c,c5e9fdf2,89a3090d,e24d13a1,bc8377d9,de0bcf4,63482ebd,9620cbdf,8b238fb0), +S(30549ae0,9a46820f,f49423b8,9c6fdd48,703132fd,ac166dc9,90609a32,49039f0a,b8c94b4b,36d39247,732976e,fc16d500,ccdc07f0,d7b97db5,7a1d9fbf,d8cb5d2), +S(98685f94,a043399c,89e74674,240322ac,5a595bf5,41aaa44e,d781781a,10fe9225,4506b1ef,7561b811,53f44e8f,325f9222,e999013,30523885,d8c59864,db13a3ef), +S(9acba196,3014ea9,1baba28c,e273c6e5,b9a2e1a0,98216c3b,194a0b56,dbda7db6,f0a3358e,eec737af,2e313262,b29ddf6,2adb9e97,9f56def2,65102272,6b976290), +S(e81e91a1,7aeec75c,19df0ef7,fd07ce2b,e477c031,179e3f99,4ca13857,e2b5ff93,65236424,aaa8b6cb,fdb2fb20,46ae3c3d,839d97ed,217edc6c,c774f889,d2ce8b45), +S(61e60aeb,821c3f80,b53ca78,2c3b4d21,960eb0d2,c90202f0,a5fba651,1725ddba,b029275f,690d10bc,b52e8bb2,acceb071,f07834fe,64175088,a97e26f9,8ff34432), +S(a931c410,8fcb4346,6802dd4a,8ec2cf62,cf4c5558,8129299c,b3a87e95,6fba2a34,c21a8dd1,43d4a639,339fec49,f56d717c,658a55af,ad72da1,c754fb9a,117cf6e7), +S(fb5c106f,da32fcfe,ffe9b5a2,7ac8cfd8,d9a73da1,5fa6340f,e09d187a,7a83cb88,a3f4c60f,90003375,11c39100,ba4c4721,c6c138c1,cbae09dc,46d1a1d2,5baa95fb), +S(dc25e18a,18f0035c,2a05e80d,d6b38830,7fb3b176,a66ae451,8c5640db,7540dd24,3ba83beb,3e6b29c2,97a0ead6,148f9b93,711556e2,e5fd513e,ee649228,c62d8f3c), +S(ecf7b689,ca03b840,739283e9,c3003a01,65ea3f,3bd17e06,9260c0e9,ad403273,5e0dbad6,47997fca,c0d7ba2a,170a7954,67036ae8,e61dc532,b5fe184a,deb8a7ea), +S(263e593b,10c982d5,1bf89ec9,71f6a3f4,60e53bf4,cb2f6af3,2381214b,2e981bbc,e255bc11,11470eb8,894ead67,c618d7ca,a6b76ae1,a230ef05,3830d028,4a7faf37), +S(f79781e7,a4137ac4,7a9a9d00,9d239b37,6cd0fa3c,b9f5de46,8cba5a11,ffcdd69,d10ba78,896e086d,5e25444,165e79d9,7b3d485,1a448e03,26d8906b,2f27745b), +S(a4d28024,11f577c1,c5d08fbc,457a46bd,428f4d2a,b29475ea,ef622876,593e49f0,e4855491,ac0342b1,dc804bc2,7ae23877,82eeaf22,52874a00,4d4e0d66,b07b434f), +S(87195a80,dc83be4e,cfc9d4b8,29725cbe,11101c26,13c98f2,641753af,1ee840f8,f9fce233,66931c51,4ea09224,b565dec7,22763d8f,6f572057,fdd7d96e,9811289a), +S(210a917a,d9df2779,6746ff30,1ad9ccc8,78f61a5f,1ff4082b,5364dacd,57b4a278,98f1e4ab,af4a1a84,85c6417e,7298c82,c87619e5,500df403,80d8ec01,f384d9fe)}, +{S(6c16768c,433a000b,adc47b10,ba4e132c,f5480e65,ae83d1a6,8aec34d2,c00c76dd,ca1a47dd,66c2d74a,ddb69283,2ea289a6,ae679669,edd80bdd,4ffdab2a,defbb542), +S(f757e860,ed04db61,594bd647,5ae81b7e,d6d2fa58,80cad10a,7756fa26,810b8543,f2aad599,4e491e02,9b1ae256,2c90912a,1c9aa6cd,dfc2331d,a0069a79,861208a), +S(d9f269d2,9aa777c6,9989d706,91403dfd,9025b491,ba03ddf2,dab8c9,af7dc764,1b39b85c,cb4749fb,7f47086a,ce63924f,3ebb4213,af5dfc95,fda796e6,c6b0b8b0), +S(d05e14f6,fe6ca50,a23e9339,e449f771,98e842d4,80a72d5f,8f5e4c06,43547cb9,869e3bea,6b19e0f2,de83fa8a,e932086d,d66e838b,637ea603,5f0fa081,5912c8f1), +S(9f723d81,1818046f,b7512abb,faeb46d3,52d8da9b,3abe819f,3861f9c9,963c583b,37df0657,3f2bb428,6c8b3efe,f6941e2c,4e48d90b,931cd0a5,78a4b52c,6581ee7a), +S(e65f0b42,54ad9df9,681c0db,3428ccaa,11194df3,9e837aab,4564e1fa,254e6f97,43e59d10,54aa35b5,80373e08,cfc02aaa,4f581406,58341e67,7e50977e,5bd893dc), +S(605d61db,589fd91,78a65cb5,99697001,73afca81,23f663ac,5fffd0b9,8f5e7a64,a976a9d,a47745f,447ad4dd,7eb63875,c228b979,a7dda50a,d994df7b,545d0ede), +S(43298aaa,faf20e9d,c2240256,493ef19f,5630db6b,f6376e4a,356bd034,98f1be7e,737551c3,653af1cb,4f8c1e8a,347f50ca,142c03e0,29007f29,c76bb763,b52ed053), +S(8afba782,d6373f0c,54734f1b,4b854e63,bf2a3b4f,23f57a3e,6c2eae86,25c691c6,da3054aa,228b9757,b7321da0,64516249,652fd814,15017584,2c7683ce,1a3638a2), +S(3156d359,e01d64fa,9c8fd8b2,c47c3492,82dd459a,fe89d94f,35906da2,c6d0208,85a23f48,f0a7448f,c57ee545,3978e2cb,6f2bbe54,864477d8,a63775f7,7ff7289f), +S(88e1a44b,1e206eab,49fe97af,30be5e47,25e1011f,312a5222,e9e80819,b3f26357,63dfe52e,10317c4e,227b2a5a,d61b713e,2d93aba7,f0a51e0,b5621191,40c58ded), +S(d10de96b,f2e4a6f8,78e0f37e,15569f3c,b9717a38,7fb98928,6d65d171,4b81b301,2c0a46c9,6a2e3884,e7f3b146,acc170d2,6d12b959,4b75a901,dd535016,f0355ae2), +S(eb36b865,812ae4bd,7893e50,5aef6f14,bfc90c1b,42e75ea5,91615aa,a2101784,1523537b,790b2a61,fb6696d0,a622ff31,efea1255,e1dceb86,763985e2,6c5ca8df), +S(d54be697,e41396c6,3d63f96f,bde9bba2,36ab1649,3c156159,3df81d69,c906fe60,89de1769,433b5678,1f7a2206,ca98258,20d0c7dd,a6d5b672,f77029c2,6bb59f33), +S(d5aa72fc,9063c2f8,bd0fec97,da30dcd2,a5b36aee,7894463a,f7042795,1998c979,ed90095d,bf2d3a67,2d2f1a0f,9737c4d,e8f3e773,c04b77d3,a2345dda,ab662199), +S(ee8cd53e,8ab64281,b5cad323,f03fd06d,7aa166eb,df9185b4,8d0eb0e6,1bd0bc61,4781263d,fc518e4,809e5ea7,7f9df238,1ee7b6ee,ab25c1d9,5cbf3fce,72fdd615), +S(ddc5e95e,2a46736d,9bbeee74,74364bf9,e1d2724f,c43522c,cffa05a8,7d078be9,60908fb,809ae964,98a26cd9,67532df2,409491aa,73c46803,eb58861,7ad86745), +S(ae503a2b,b6250ff6,6ee615d8,41cae4e,751160fe,aef7f33b,dd1feaad,ab236b58,6e53d2a8,8f09f78f,96d49a6,2f98773b,a282b575,ab6e24f8,4d604c3c,8583a66c), +S(8a502d08,bb3cc1da,438c5780,e2120c50,12c1a972,8aaab6bc,5d908b6e,2a83dbdb,fa02e62b,85d7de78,8cf11d9e,ab406523,bba1f912,53006a89,f3a491cc,dd99575c), +S(b52891bf,5acb0019,a8d10b94,87fa47c4,22f83a00,ef539e91,44bd9f7a,d5075716,ae58653a,b167a9e4,b71eecd7,4f4a8786,19c19026,29c0018d,9f082e7d,5920b2f), +S(176170af,b40a3e79,8a88b98f,fb6c578c,d1ab56b5,b7f4142e,b2d84a59,1b009f97,6e1d5682,36176d58,ce5fcac6,4d4d2885,5db107dd,5215c71f,b4076aaf,d31c5d24), +S(27359f7e,8d3e3dcd,ea35f603,d8fb15c0,bd63c08c,3ae4d2fe,8cb6434a,ae2e716d,a0d64207,8fba00dd,4683d597,27f3c67f,3c25075d,802a4ea8,eb08c20b,47a941f9), +S(1e9d955a,2f68478,5227e866,491990a5,62c802ed,1b106bb5,42d02d29,93542067,fbf5f466,57707b3,3f116a23,fe5991a8,90a9583f,fd063943,37a19aa7,e125ccab), +S(b5c4c10b,1b0e0813,37deef6f,c089d2e1,ee14da2d,cbb48e6,74b7dbd4,429e22eb,fdac245,b109947,8f6a53a2,8a1ec4fe,da43b4a9,2ef49e25,8f9296c2,88c48378), +S(bd2f651c,ff6e614b,1d6535cf,c3a2c5d2,da5307b0,1cbd3f48,655623c2,55503916,3715b0bd,bcf29d97,63d7fb35,f9c5b54c,769a863,3517a2d6,8dde74e4,c4277779), +S(c4c2a8e8,f1e257a8,fcd0b11b,30635c5e,782fedcf,f99b0b95,828e1369,3ee0af73,3a08abb4,777a066b,49ec4c01,aa5b0868,f100a473,e555def1,7c5a9d84,b1fd9ae), +S(4aa77ce,15dd97ff,47c1125a,77bcf0e9,d302b79a,e8a919c6,a875e5ed,eab8c2ec,31a09dc4,89a90240,334836f6,302d7e81,57f19762,a9b5f727,6c276e63,560a9d10), +S(3731162e,66a8d2d8,ff4df3e,95950103,f5a03f9a,86bf37e5,605746,cf4be846,e19d7835,10af5daf,724be4b1,932dfac6,23899ccf,7e3e58ab,5bf3265c,667cbf28), +S(6e2114ed,297ba44f,c3926603,bc03a87c,af3e9f2c,8bd84e64,afcd9846,bd9c8f0a,faa6e5f3,3d90f91d,82592af0,7f3a26e2,f6f4138a,2f06a6a1,4286eb71,2e95cf94), +S(50d775b5,f72d186b,266a14e5,254cb5aa,49fd8633,81c36b09,842632d7,ff004130,cbfe11c4,f0b15aa8,3ae8dbcb,9feff9c0,d68a26ba,11095b3c,ba94739a,2091bbc2), +S(8f3ccf31,f8b74b9b,624a5d1b,7cb1096e,202fe5e7,233777aa,859864d3,775732c0,980e32c1,d2c61ace,7610b926,6831ac27,56f19788,ab7a77da,18c421a0,9a46bad4), +S(24cfc017,6da2b46f,a8bb5bf9,636be1ef,fd7e297f,29122fb3,e84c9ab0,c18ada5f,14007044,f8639e59,67978eb2,a21256d8,126a635e,5b07eb0d,97059ec5,6875a3c4)}, +{S(6efcde8b,e99d9ee8,ee0d6b8f,a76584bd,5deb67b1,415e729b,48f3d41a,f1cc1386,4ddcef4a,a6ad5be2,d1e83449,9eca4a8c,73219f80,464a4a9e,ebb7f3f1,b70c9fd2), +S(24fdd052,a1e535e2,4eb79ffd,f03093f8,5778241a,b845b548,31b9a82,730ee3e,c6ff8ebc,7edfd9df,9b7410a,7f54c93d,ff0c682b,152bf4db,1b79c0a6,9889797d), +S(aaaf86ed,31dbf395,687c959,6c445b6c,dcd1fe7e,ba2aa13d,1bf41867,dc87b30b,582b9683,729be5c,85fa83e,2ba2abac,e3037262,2a24aa35,c7753312,1de2fb93), +S(23930d0d,2400db1d,56525bb4,67172fe5,e930bf86,21124fa4,6c5a421e,10b059ea,5e11f202,beca3d5e,dc9b282c,2e86d5d9,30f8f5d,27a5c4d,d2cd6dde,6d1497ef), +S(76ad10d0,bc92ad8f,55b665a1,8ee84e01,2e92dcc9,37e0c604,59bd6fd4,ded2d9d2,d4ca7386,ce0c4c5,fd37da9b,eb8fb040,97d98891,35a5ecc0,320dfffc,95ed3c10), +S(10b324b,e959f0c8,c8a82142,4a8f87c1,fdeb7f88,258e1021,c9cfaa66,b131f3a4,590e672a,daa8d547,161f635f,153fa12,b3500694,677af3f8,90dd4ca6,9620bb56), +S(afdb2acb,ebfdc11b,3577177c,d8bcde00,65151495,79c6ad2b,f7386275,a9314317,87d7786f,5ba775c0,ea47b141,cd0d4274,c7e58634,b64e4c58,f7f0c595,5a307250), +S(574cddbd,59b34df5,30f5dc4,61884ebd,1c867ed5,6cb60832,4a11b1f5,29ebf733,1bfea852,34256807,1fdb4f5c,485caa73,7136e3c3,b4b8a39a,389d7dc8,724f16fa), +S(97ffea2b,5de34e1d,495ce082,d0097b72,e7daddb8,1cb622c,2c14e814,bb0ae278,45fd3d2a,9d1e6530,61b4a356,65aa9e70,43766950,622e1c25,2baab265,6d4ed95f), +S(de627f6a,a7b56d85,535c398,80d0276b,b910ce4a,6066435b,512e5e0,21ef55ef,753033a6,ef89f053,c0e662c8,1557e6cc,d8b4c8d4,5204f5d,e1c8c742,72b96277), +S(b126c35a,d7993bd0,164867c,58c88421,d2cddb6f,d16a5966,7d9683bb,1b428eb5,a9ed1bb9,e9eacf9e,e712bcda,be629143,ad0e7652,82cbfab8,e586cb07,131e5b1d), +S(847b90cb,8837f488,ef027a05,71b2be6c,620cf86f,ead235ad,e76e3408,d0dd1073,9a2667be,6ce36e7b,d76117a9,fdb8f1b8,7c7cb45e,1a03f53e,7b32bc63,6f274b4e), +S(8ea21457,6f1bc2c8,fbee9065,c2cf5c3e,7a3b9fe5,403fb980,96040c2e,c6fe1488,dd75b454,acef4d3b,1b355a63,f0cd17a6,66aa9e65,f1262629,f0c7d1e0,33571b58), +S(9e11bb60,ba4b2d5d,fe53bb9c,598edb16,f3926bea,1cc90eb4,3e05ca34,e83f1896,263d7ea,50d83b8,791fc911,a4f73cac,4d42a09a,85f5ae68,86cb268a,fd562dd0), +S(f741856e,f353a7c7,17db9a13,4ab4aaf9,13c1f7da,cef08bfd,6f81dce5,b1130e20,ee63dd2f,48e15f68,d1acbf49,705fe010,231e26b5,14146c47,1a689960,d568eca4), +S(671ef05a,410b41d9,3b092b04,e523468d,44837d2d,26dba670,27400715,eeefa2b5,686d318b,b49eccbf,40dc18af,f1938fa9,b16d4d2c,c19dd2ac,47c7830f,89b8d55c), +S(59ea10a1,e5bffd6,a34593f4,b986e37b,5294ddbc,60d92906,52c6e9d5,75f88c55,c0a2eb5,6d04ab99,abb5b76f,7b2b55c9,c09d44f3,3785e3d4,64554c3e,dc7a334c), +S(37f2c7c5,69c6fd15,9b721d8b,8d40138e,a8873b6b,452af0a7,89a50551,e9703c1e,d114109f,f9e6d7c0,c51a542f,b2e3ef5b,74654bef,5eb84aef,c87f5096,2a30c078), +S(1d280637,9d77e509,126a440e,b1e56f1a,8723728e,97c92420,5ed13081,98c868b9,85003989,93a4a600,dfd0f092,b13a1186,c1c52dd8,8fc8eace,9bd4f1c1,b47741d8), +S(39aed6e6,a123061c,228d3d1f,857e0c9b,29b70cdc,549b4ea1,9fb6802a,8d8beacf,6bf86967,98e3dbf6,75865a1a,b86d5bbb,10f16e8,4f9104a0,87602c,e6946aec), +S(aa770804,4a996b1d,5bda074c,941b30c1,d1474da6,47d7c4ed,248d3a9f,c3c3c525,10ba5652,b20482f,fc2434ce,ac185d8d,af6cc6e3,61e77d3f,258abc0b,55610879), +S(7626a96,9f9ef188,3ea82737,83e5571e,4054fb73,6190977a,299c2a05,d29f60c7,172d4618,e5f88055,ebfcdf9f,55267ee5,cdf18396,1d5a2a22,55b87ba3,c7d7d2b9), +S(1a550684,d1195da7,c4b09349,f149eae2,5a1ef23,c9a81109,115d93e4,c98cdbda,c31d7dc1,b7efd019,c491010e,30f90ed8,7503c4bb,1b37fbce,3dae199,6609e3b1), +S(8d2306d2,dd8c753f,2b093e62,86fc282,ba3e1dbd,7b4ba101,83d1070e,d2d06e67,97dd14c2,d2c1d147,486a3dfc,d608ba28,d63fc03,251a106c,9811b088,978e3a5e), +S(f31a69ab,97039589,940851f3,cdc98bc5,d400ff93,63794f81,4d88215,4f00db99,56e510be,7f41b009,89792401,13641590,40f5f305,f27fe1e2,db1cd7ae,887ff5e2), +S(ce96b3e9,6eb94b7c,8bdc7b57,efd2186f,62e23e72,f11337ab,be7405d3,43b4d762,cc0dc898,33e7a632,d0fed52d,487f2c60,96c69664,f698a71c,3f7f8a29,4f181add), +S(bed97e25,7d31b5fd,36b41227,462d9122,706da670,d432ceff,5d37d83e,fefda56c,c0cfe30a,2c3b3074,1af492b6,e3797c4f,3b00593c,6806e2e2,f2cff401,6e877ff6), +S(923bc6c9,960f6e4d,ca2a7070,6d160e19,83a16b6c,8535783f,12c5ac69,4aad226a,c47f08b,6b2056d2,8e9f119,9ec6d5ce,b48801b8,7ee56280,d6a48352,b2b42b1), +S(b3cb28fb,7465cdda,85823dcf,819400b,357bce11,23d9229a,eddb8262,53b246c3,cf035ed0,b624dd68,8a31eb5f,3b28e83e,c0bf9453,649dfe4f,44078eac,9345f2a6), +S(c69aa2b9,ab3c5e45,8713a912,e7f95bb,4e5498a6,d4090323,5cfed1c9,c2a60709,2e95e198,85637d55,744e32a7,98c02c7e,b29f3bf5,7cf7c870,7cafdf41,f6710f0c), +S(45996af,5795ea6e,43e0fd29,671e119b,8b8d6ad2,4eac90ec,d27d5db1,b4fb6a39,2c0651f3,1c7d93cc,98d79d7d,f21110fc,8c1dd74b,f1ffefac,a3d52484,f8da40cd), +S(264559d8,7829256b,ed116900,d82d0c37,9f0e4d12,53c68e6f,cf2d41ae,7cddab8b,861a42e6,d92caed3,108439c8,fcbf8d28,8579ce50,c6350e19,3609b4b9,ffe217bc)}, +{S(ac13e0db,846df259,fc38d6,3b0248ec,9fcfa8d4,bcee368b,1f4a66c6,d41f9163,6721b0df,2ed06fda,9b485cc2,aa56f1f3,3a913e99,f6809577,95280451,9ddc96ec), +S(b6b7227f,228da269,a0e5640b,8a2cfa34,555ccdec,2243dd0d,4b2da0a9,b4cb5e4,6afe41f9,dc129d28,4786bb76,17786c8d,42597435,240f998a,f970620,90d32059), +S(460672e4,4f2768b9,842a98a5,ca8b90df,7d9f52bc,3fa2665c,4272d7ad,5f48b992,6d7f8b36,13b38fa5,80ed1d4a,21d196bf,be491b46,49c96da8,342441d3,f4af4ca2), +S(1d3d4ab8,b7c06136,8dfd612a,25f04016,2bd3f6cd,cd9cf58d,c11647a0,d28b629f,434dca08,17bbf964,eb0a316c,b2b0df20,eb2e965d,c4d8d795,1d4a6e66,5ed23d38), +S(9c5d6342,303bc7c,73763cb9,2e3d7069,7d913f6c,1a6e2f47,39470da3,22b7c1b,825c1a54,395b9b41,ccc2e3b5,3fe1092,f04c382f,b2ee3a29,fd59e255,5f22fc15), +S(5c751285,a4b55535,fe24fe27,568868f3,afb43cf,aad1d2b1,c6367daa,ac9493b2,e2388ab4,414c4e4f,e34a4c78,c869dd93,7094ce2d,4f4666a8,2eef8047,3b681fb6), +S(8c1592f3,8d73e277,d3c18d4,ee3eabce,32e86f92,2b27c2f0,1f50509e,74dbc211,399c9507,43cd9e7b,200c255b,bd25670e,cc111462,2d5dfacf,9dbebdb,53ee59ab), +S(85320e36,5f40235e,621171d5,c8008845,890f521b,d7e2cccb,88c7fb7f,a08200c,96bbe8ec,74b5f1b1,2a6ecbee,2aea6f0c,b6d0657,aac3556c,ddc4e46f,17cd31f1), +S(5fc21f20,13403705,687b8ad3,387a725a,f2e6300e,13d28403,569d4cb6,5dda7f34,bb709fbf,be95aeef,c00846b6,a4645b72,dbb4e1ed,866edb57,7bc5d9a8,2b774b0b), +S(fa40e658,588f8a5e,29d380e9,c1a6482c,888f53e5,e331f8ed,9b1273a,56d094e5,5486cff5,3b7baaaa,de8a51a6,1d1a9255,95ecbea3,39955c0e,172de4c3,4762eca1), +S(9f87d04c,5fcc48f,375c40af,3197c28f,c62cf3c5,10fcdbde,5aec79a7,4e6a6bc0,9a6cc172,23a770c7,a03b5333,6922170d,e9409f3b,9846b9f4,41832ae1,f70f5c57), +S(bb66dd5b,2f88786e,736b50,e536a0f0,3d59b86,511e95ca,1bab2cb8,875bb187,f8215527,c76a5af,e5e76a33,eb2622d,5f822ad1,d284c68b,c840f65d,4f731c63), +S(74d223e4,bce2d6b9,b2fa9482,46327e04,18eda6c,cfdd76c7,cda8be62,3f6dd3a9,b7276bb3,817c0e72,e1ab002d,50531065,e1c4ca30,9c6d6f18,bb5796ee,457b4270), +S(80298b62,eb4d3ff2,e10607dd,dbcacda4,3bb30e57,f3c8c7e7,6f9f3968,bf391316,fc72362b,48c8b606,4e428e6d,1ef2ac87,931caf75,e936a33c,228a5caa,c460c5f0), +S(8519f27d,9560acdc,509fddee,9b4a4a7a,8b13496f,14760a08,22609f3b,2ae07963,193aa9db,b98293f8,e70d7253,51d3893,a9f5fc73,6f3c8e65,28a2dfd6,5dedc220), +S(49d734f9,c8eff915,fd66757b,d6484bc9,548f20a,d8c05959,f651eb36,e45cb88,4c594f79,7651b49e,929932a4,59e3bf21,3e74c0b8,acb20907,697a25a7,ed21057b), +S(6a528c6d,19b1e28d,b4d9ec9e,19c4f7be,184ef845,1f41b322,e5932f05,575bcc4a,7350b90b,c22ab41f,40c13a80,18749e8c,275d3e5e,5d687df0,ddd47133,c092eadc), +S(6f3df40f,5647143f,cb93b23,4795d9a7,708db6b8,2e2df53c,f214de4b,61eebaa9,dee10664,54b625ba,34ce4b54,f7285714,7874b5d0,6b38b1dc,37b7471f,9208dcbe), +S(5abfd7eb,c4c5dc14,cbf0e335,f2e87e7a,7db96a2c,b78000aa,64fa8aca,517ee1e5,d65a98d4,20d872e4,4c43997,55cca5c0,bb94ccc0,b25e30fe,8b5a4fcc,7006364f), +S(1bf3714b,da04d769,782e37cb,c4a4b347,f9fc769d,a18e4940,d19a205a,bdd22a23,d0852b21,33b04274,183f4de4,9a20769e,4a08ea16,ca8782bd,84a4da7c,64c928a2), +S(773ab884,a4e90454,ea467caf,f18c3b64,e316468c,b5789fa6,4958f73e,ec3204f1,62213b85,b4838d8a,fa3a14f9,32db7d79,dec538c7,d872d9d2,be1640a2,4e367caa), +S(33a283d9,9b7564ed,6ed10d88,ba26ba,fbf3a375,e00e10d1,577fce27,2c204324,bf84dac3,40736625,cf0e6be6,98072c6c,5fb8bf9d,2850be84,ded3f652,569370d2), +S(62bdb467,596ffefa,22b735fd,d3dfd959,d4a6e187,a19d4c1f,4d647b4e,db380c3b,210a8e93,d1a184d0,a3548be7,6283d180,8e4f32d9,52834c,515953f0,4ecf9acf), +S(ef16d3a3,233f03da,5864801a,c246756b,d1356137,971bc164,b5512067,b369dad2,480e3d32,7f1df8b0,646c3b58,a51126a3,e91522de,ab77d6d2,f2bedadf,1219b877), +S(a6834869,c006d044,a9dcfb9,8a5a14df,86469fd1,fd0cba06,a4e8ec1e,1fba89d6,c1a3e0ff,7abeb1e,8cac11a6,8c1b4c1c,f663e615,9f508c35,f4747f50,84b247e9), +S(203d13c6,53a3c36e,55a836de,b38c7443,681d7b7,c681d71a,38fb0fde,986ce9c3,5d7dba97,573ffd85,b3fd4417,f09192e1,92461c4c,125a9947,ced9c737,ecac65b2), +S(c48819,b8f32966,bd50f162,30f5c0a1,45cb3570,d9c4b104,4c306696,2f4d6667,feb08ff9,1f543c1,35b6e0f0,b21d7624,91ac096a,181bf093,fcf8f4b7,bf6559a2), +S(31441031,ceabfbf8,59bcdd8b,6e177f91,df7bfe08,f9015172,1ead3acd,ab64acff,e36315bf,6f087118,32894704,8d2fd259,6b8beae2,e1917341,d690a1f,786db5f9), +S(e3e4750a,310c48,38920654,b6afa032,79589d52,74e48139,6e22d9cd,3c05fbdd,f05868fe,5452da6f,fadcafb6,69e5edfb,4b9a7840,3a305004,345ddce1,eaca43ac), +S(3659ba70,60d8200c,9512facb,5c730111,4cdc2b9b,aa5bde14,8ad9bf9d,d8f8fb8c,b1185617,f91fe5e8,ec68da07,138b6780,e1ebd12b,1bb44eca,8a1b9472,8337585e), +S(1a46b7e9,fe99a4ea,492fbc90,3281b924,6831fe59,9360af53,bde4ce8b,43ed5996,97c317e1,5c0e23a8,f1c11f7b,5f9c140a,af786b56,10ad8ba3,d11b12ed,17379f81), +S(f16a409c,677a40be,402f8efb,3752373c,aced053c,6f702b82,8bda222c,a412b6fd,d5becee8,ebacd866,285958a5,8b1cf1b1,e9abf9a6,db61435b,d9725187,135fa955)}, +{S(32c932eb,6fa35974,90a408a6,ce962d7a,ef2bd22,72cdaa,cb80f798,9836abc3,3e145848,c2f8197e,f0264d7c,370d1784,7d21a09c,77fd9f7a,73245ce7,2ce5f3f6), +S(49d837bb,63890b4e,8a4a63ea,6d88599a,c9961c20,80dcc955,aca6a101,bc935f16,358a7f6d,b540ac03,78d83bc,304cabf1,84c7580c,46c258ec,58f22254,e3e03aa), +S(23516ddd,40dab9d8,63dcad6c,cd325503,b783379,d870ace0,9a0b238c,d7b6b2bf,b1fb8268,a7814efc,54f3d637,88956b67,a3997a31,10a738a4,94786d95,a5fa1c59), +S(6b4e215e,df56e6ce,6378fa98,5d604f68,e3561275,788283d6,c40cb249,6d16310e,cdf9537e,e6f4304,dbcb9df,f8b97a71,a12f014e,29867e5,6b09b388,78c9ce8d), +S(f4f30433,c933dddb,949ad868,cc0d52e5,247149a,7ec98f12,3e7f63b4,acf6b7b9,949123eb,9fb848fc,d7b94401,a64b21a3,53fde44c,d93dae3e,b7a2d3d4,78055af2), +S(dc3523f4,cd24be1b,30787dd7,5140fff,b66e4487,55e9a3c9,6124fe59,c07faa28,47b945d7,6d37b855,8ede59fe,e297a8e7,81d3ea96,f0a81588,b68db767,9b9641f5), +S(b92cace4,e31dc724,3b3530b1,f90de1c3,47cc39e5,5b247455,a1296912,4e3c2a09,78f89163,c735cb13,b1d8fe7e,547027f,68d8f864,a1f093b,22c0d9cb,95fe28c2), +S(8f7ed1f1,77238a68,bbe32e4d,ae6d67fd,be07c9a2,9fc6b940,6ef81a77,65a8fb75,98e627d8,d32095bd,5913daa5,920c5c60,334691be,537b08d6,da5b8c19,7bf81c8f), +S(47fa27ac,e035176f,34c59581,8d3dca2c,a2b40e53,29756c55,7cf81f75,4f99316a,ddee5921,f381ce26,3634a34d,1b4f9513,4d9f0e50,5e96bb79,b87d98b5,282aee7c), +S(7584cb68,60ae81f2,e0df701c,97d7aa29,8132cb96,fee4ad59,15424bec,2e280dcd,4b76458b,e3926b5b,bf59ad77,da4a96c9,1f9147bd,88a234c0,74b0e09c,a6993228), +S(2cd4c11e,70d432ff,38550aca,481667f4,d09ad11f,9aed62d4,968492d7,5de28dae,82514708,3e5bf46,341177e8,9ad2cfb3,a215578c,52f9436,d3952432,e9acd430), +S(2b524c99,2b18a6e0,30863716,362d236d,e385a10c,3679eec,2774edb7,a1a89be9,1abb3b28,3477769a,5c7b4580,93efb22e,f2e61296,da90d4d3,1d6b2ff9,1766f89d), +S(d642c258,9d0e47ef,f5b2b60d,9321db58,727315ad,522daf58,3bdf35d3,336f1081,1019505a,994030be,484e5340,abea0b7a,51276c99,29cd1f1b,9d19798d,aaacf3d9), +S(3e5e09b,451bcf5d,549f1d66,b96da0ea,25e63270,dae59606,bfc3165b,f89f29fd,2ce591f5,32d57be6,4fc48aa4,ba40231d,9c104615,b76ed6bf,11957694,16d2f0e9), +S(4756965b,82fc23bf,64041d23,a23cba32,cb71d3e7,ef3e6c03,51b20f3f,dec049b6,75f3a293,eae07f4,362c47e9,44a78561,323244ac,bcecef0c,6ba2f5fe,d1933679), +S(f296e9c1,41694ce2,c197ba85,bb9f172,54fc0bc7,f89347,a0e92b8,58491a39,73c7fbdd,91c88ce2,bbcadaae,df8880f6,aff07e8d,3a1ce05,a468e3c2,3008d98d), +S(b437d387,ddae39cf,e26edc85,b0e600bc,2a199b6d,b521f9c9,88d921dd,7e6fc761,ce2111f4,d937905e,2af7f2dc,559f9eb8,bef286dd,909a5965,53c7f61c,f51aed18), +S(bacd4a38,f3e1b7b1,b601fa5a,2a579e87,459fd189,a607314,5a0dcfb6,1ad3c21b,8be8d6b3,9553648f,2a94754f,4c6c14,c4917296,aa9987f0,deeb7e66,d81c3777), +S(d8164748,8ac6bca,945fce70,e8f6a256,90512c8c,dd4c8fbf,b553c131,96f7f607,16b75474,65a80a67,86b5246f,e086d32c,4db03b83,58271938,41877c38,2b5bebed), +S(9c2b0749,cef57b4e,36b31328,e01503dd,ddbd2834,5cd86ca2,5224b967,1b7897d5,f020f978,4eed44cf,cc4aa33f,b2eb4b71,f24b5f3a,a8dc1d72,569bdefb,5f6276fc), +S(ea277814,9f0ab428,63b05bb1,c113ea7b,91afb815,e8f0791,12c11573,eb044e4d,8199dc4f,4e72b691,1c562ded,1220aec3,ab967029,139d30ac,58c753d2,f4548030), +S(4be6fcf8,40673659,5a9e4f2e,877ad7bf,28e25177,63d74238,6e43e6da,1c1c43fd,eb5456f3,d1c40592,2eec37ab,3e0d08da,b7cd257d,9babab02,44e5b2d6,a827a7cb), +S(3f1e9ab5,160733e2,9e7aeb6a,378d169f,9be5c266,a6462e2d,e736be07,f88c1da1,907fa0b9,814da057,9bb11309,aab51902,a0699aad,9422e1f,b8f1a8c4,aa9d4399), +S(eb730dbb,1ba9b2f,50453837,35ec6da2,ac4b5019,86cf03f0,3f5061e2,a28285f9,41dc3a0f,f42fb1b5,d3b464a5,6e305fe5,c60c4561,d6e5a6a7,8cba87ce,15c392fa), +S(aeac891d,f7032059,54d0bab7,41927702,1a595a4c,37bfc34c,5d315876,3e85f3ce,168f8260,1331b5c5,edf941d9,9f1cfe0b,72fd2a1c,3e4bbc2c,c62d47e6,6399105d), +S(667e04e6,daca6315,4888ac26,a268876a,f4b754fb,87687ca7,3c4cff77,d6dac204,1826a26a,cdca828,8e2ac81b,855a4d40,86f3009b,162fba82,83cb1d17,b9f7aa4c), +S(240ec754,24e46326,8e2e4ce0,240f335c,78c46150,1e18cedc,b32e3c51,77ade3e5,be09c744,cf6e9c6a,75976c03,530329af,5e11e5ed,3fb13e8c,af40bc5f,95872645), +S(7b83e4b7,70e7a442,3efbb501,c23881c5,2bbde4b9,d5aacc38,7071decf,79690025,d242ed74,441d1ae6,61b97c83,70be2f52,dcbc2831,1e8707e0,1b44c827,420dcd45), +S(63589c41,fa8975f4,c8738f57,579cc0d8,447218c,69da1a34,ee06af0c,215f6c27,c34f2ede,7589760b,80dbae48,94a3c13c,7351bf5c,33a35351,9988ba67,c2a56d48), +S(db092b0f,4638ee45,190473c7,cb60cfec,45c94d96,99aaf289,82d28af,16ba1c66,8a96ecdf,29ad2fd6,3a85a7fc,b73ab6d7,719bbd6b,98d052b3,3a0cd91,ab924f46), +S(11c4dd8d,3eddc0cd,9a832dd2,dc91c8bd,491fdb51,f5da21c5,732dfb7a,362b8df9,ba4c2789,740b53d5,51bc9fbc,776f049b,e848182d,9d13abb7,e7cd860,96911eff), +S(a65a3a01,df3b5ef2,e620d431,49fbe1,4d71457f,19d1ed35,aea39d57,89303fdd,86715f6b,f300a390,470bc272,6f12d389,7979e2fd,b0512c35,252bb571,fd19752c)}, +{S(d8558716,b7033a9b,29afb346,fd71663a,79b6e86,2719bf12,6e532dc3,f581b7d,a790d460,1e5b2630,1ad6ec43,62f79120,d75449d,8a500e2e,6f17c021,8037a405), +S(842c01b3,54353026,c43dedc7,8829ead1,db35b63d,8c4d0d36,8cd7b661,2eb5e11,f173cab1,a37ee0d0,68e097af,17bf859c,13bb4823,255abddb,f0dbeffc,573e06e7), +S(acac5cae,414c3556,38e293fa,e7cda051,18924e9d,abb81bdd,29123768,c7f21443,5d17b909,5b997254,5f56770c,dcb8af40,e37e1a8b,6e01a989,34ec22fb,f7d04537), +S(c8e73810,c024c6eb,d5398bda,3784261e,542279e5,3438d49e,83b2639f,80889aea,7a2183e7,be4f81,b0337993,935657c4,c55d20df,729d2e8d,b25af238,f3d85f4b), +S(f78c5f53,5e7ccb53,555a6f2c,b1de1c5f,da379360,f6a7fc52,eaf86ecb,dbb3bf90,cf2d33f5,eab2ee1d,5a32eea3,18f9927b,cc982fed,cc9add2e,2461ba14,9def0292), +S(4cd40c43,bdb8a042,2babc95d,eb00a405,59519074,5906a8b7,b5ea00da,b7f995f5,a0bd1c74,79125d2f,5baec520,21fb7c62,415817f7,2afb80,b2315dda,40cf4c4b), +S(647c5950,f8a7fe9,e6945b3d,6da91932,b486a4fb,ed903836,9fbc20f9,a849ac08,d331cf32,d72e148,b47af547,6794a33d,55f49ffb,be47db02,7d2de73c,542bbbc5), +S(97664e78,980a49f0,8269ff19,649e86cd,7da88a76,eb1441d8,a5f3fd2a,6ea335d2,b2898268,9a8cd91b,b1b16be8,ee46b4bc,252f7016,f72432c0,431f1264,8d7450a7), +S(523f68b,b39c2ded,81d22a4e,575483ee,d8748c9f,52c06081,391c27d7,7afe3805,5c331672,4464dc47,cc9cfe32,864b6095,ee8bd6a8,42c1af98,b3e33183,a46e2471), +S(cad866de,5cbf4938,989b835d,5aed958,cd7c316b,980b7c76,2109d688,d7ef5b25,3ae79c30,e77d6d4e,fe404b8f,324179c2,f677f434,8a1c4367,2a0fb5eb,b706607a), +S(ba065cef,b47170a,d6796033,d157fd1c,f22052d0,7b7f9992,6cd58e03,316f95a5,26177c08,bc535702,7f5d03a4,9d982637,d74a6b20,696be76e,742243be,b9ecddca), +S(27ca8178,be756f12,22cebe6c,d05310d8,5a6c4f59,eec71613,7777b625,e6d44c97,de547a17,ddee9fc5,1fecee01,45f9cda1,b65f097,5d1b9544,aa2317f5,102537cb), +S(bfab1d94,d04f4909,dee00998,78f77cc7,d9de94a7,96b5b770,5f3c759d,2ae97ec1,6ec39a8d,9e900a79,b8b88098,d1e5d79d,b75ef91,e442cb2f,27ea531a,2db21bb9), +S(b48a4f25,9d82242,59f08a08,29b05ac8,ae6b97b5,56cccb84,20a479f5,df92701e,beef137f,9f9acdc,8d31a780,2290fe79,9d9470a7,3c8a01a,35abcbee,9730d17a), +S(e3f5d307,ed2f2f13,d23ae5b5,9dd567f0,8161996,776d506f,b53e14f2,70a52370,40ecc697,7da3771f,32a66438,cf70ea9e,550194be,1af85a08,c8a4515d,32365803), +S(818b0462,d5a815b1,57216ab2,4d795886,17cc99bb,7a7abd91,655cacb7,ba99335e,c6ad05a6,7d2a391,a15b6600,7716e02c,9fe40db2,f82283ef,c9c0a7d5,ebe854f4), +S(7e3c52ed,23220b73,ba47613a,bf39a9fb,b3a6bb6e,22c972a9,3ef21a61,50cdf830,b3e4a95b,875719b3,bec1b113,9e29670d,4ba8f39a,2fb76700,f69961fc,bd01fa2c), +S(594e4129,9c1a117e,ce8564bf,ba88ce04,297f2e14,7ecda07c,5f12913c,14d9a5cc,60bd54c8,7395fee2,7fedccfb,ca9524a9,b5750b2d,d712621d,e73e0692,46c2e347), +S(3686bf4c,f387e340,6fc314e,f02c637,ee6f5062,ee9bb567,235b00e6,4d516648,915e5904,b106e057,a0db43,151ac9f8,4871e843,126d5285,337dc3b4,52c67165), +S(338dbd1f,42480753,516d3cb2,c535492b,72849870,a7828b48,643dc143,b966ea61,e51f11ec,86104334,9e9dae17,78116032,949c66c5,3c4d441d,3c88cf4,c7ad61c9), +S(56f935ae,f58bb403,7649198d,1a5da704,26fd944e,c5694c18,38c94287,2130215e,a9c48fd0,3b059474,e528016f,9c998e02,cac7c40b,8c859852,b58b9082,b638222b), +S(1faadcd3,da472591,cc723754,82546c81,c4f53c14,d0d8dc5e,ab95a58f,379e6899,5bdcc45f,42d0ba3f,783a0806,a5d08c74,a1b1b9f5,a559248a,8681b153,74e74958), +S(532d8cd8,fdf838c7,70b87ca1,4703a884,116dd928,74acc660,6ddddd61,8eb053e8,67a31325,853db4d,3e5877b1,c76e7e39,468d2d77,37cb8a6d,af4f16b8,17cd8ad8), +S(8a8cbfd6,d45e5740,aa9f0a21,f40e3671,ef897fe,bf2bf753,ee2d2f75,844ab648,d00eed6,efefa26,46c36895,3a54045d,96da4cce,8ffc554b,9bc989ac,2f62acaf), +S(38ae095a,3c705343,38e542ff,6789902b,cc1b0b5,7763cc43,2f50cd9a,d26d0f1f,100de239,87026f09,e483839c,fe9e1f10,11bcfafa,662a9331,95a8e4ec,e4fc804c), +S(82d9e5a8,385de1f4,fa541796,a00533d9,a3aa4656,74583d07,c4b3c344,b6ff8cb6,70bf2bd3,5765165b,a466171e,f26439e8,f790e178,f67ef5,d2e15e98,435b4261), +S(1843988b,42ddec86,dcc6c9ab,36b381ad,a0ca745e,aba36bf0,237e2830,579aaafb,f1bdc95c,d76337e,cb3cfd65,d9c30b7a,e7c7d667,65c9db5a,6130edf5,e240cec4), +S(a32f7415,9c2743c7,2ef192bf,4a68e838,97a86a0a,3997d1ce,fda3c581,b4fbe683,8862903b,db791be1,dbab5031,ca57f161,b6449bcc,db061438,f45e610d,50ff3bef), +S(b09dcc04,d9c30c35,2bd63880,a766da1,f6314287,dc201bbf,9605516,3db2a09,7580cf9b,7e30dbf2,8f72e9c,a5152ff1,956ae42b,3e952b18,512824c4,7f4e5b9c), +S(ca07cbfb,b24ad1a5,edd9a12a,8ac54157,6f3f2ba1,4b878d82,ab7dc996,bd7e2c95,5123ceef,cd20f120,b575dd98,43ef9936,c53cf90c,c481f340,fa166452,72af1c8d), +S(f8058324,c6b9c2e7,e62147e9,a41ad78d,60e3ecf4,17524c05,80832add,f11349e2,6a39f1a5,f577a932,3217e559,f15eeddc,af6b674a,9d921772,a053b960,a4dfd633), +S(2e3c0532,6255d80f,a42fc69,d5c92aa4,cd326a5,3e8535f0,435efb7b,694a09ec,ffe0076e,9a93904a,42251dbf,47d03e54,1fb75ac3,8f8499ae,dacb797d,7738c9b1)}, +{S(7bd8469f,80f009fa,b4960cdc,bbfbd4ad,d8e37bb,a4b2a34e,d5c95d17,7a94c207,f3062154,c3bcc160,b2aee99,aac98446,516a277d,85b37fe9,34be9359,4af905c6), +S(139b7c10,ce844844,f5d0a9db,bd7e1679,17b37e93,9bb6fd2b,4f19643,f22a6af1,32d4e929,27f5951b,ffa4ddde,4b091ec8,531a6f23,f1772c9d,ada292db,2b88c1da), +S(f49cdd14,14b38e5a,2dd34bff,3d01e1cf,ddefb954,2a641edb,df698d83,774ee70,5c10a6d9,200253e4,a932a42d,2e770f18,69d0336f,3c44f480,ce4a3305,83050c31), +S(ee145304,4771c862,745f03b,4776ade3,104ea0cf,eda8710a,5fa108eb,1e946826,b91f14,b6127808,f1175b72,2c09e02c,66eae622,109f4156,261d65ff,506b88bd), +S(c9ebbdda,867f333d,39142483,2e4150a8,c98090ec,d8ba9c09,3673330a,8777d790,c46d72c6,6028477c,e4754960,d40bd10b,b2defc1a,17dbf018,538b71b2,d208372b), +S(707bf0e3,9f2c8c6c,73a5d0d3,3edb32e3,46e73ac5,dbeef6c,60fb5ebe,b95ece24,adc6edbe,151bcb7c,2ed5fab,1cb9b2de,3ba2f3c5,ca762082,902582cd,e9e27f54), +S(4a002722,9fda7d33,320fc533,27b6c9cb,88a09c2d,e95aad01,65f68f45,1c82e2a9,233416cf,1cc1ee38,90816a09,17c5fd0d,da0bb8f5,d33c709f,6f1b07b9,916282e0), +S(8efefe27,b45a4cc0,3088b6e2,2a0baeb0,3e772763,58af3217,f39c7222,1e20b59a,b9f3fcdf,65771acf,cc7b7486,9b10bc3f,b0e8fb2,960cad82,24ea2430,fdad1634), +S(7bd3815d,6779f321,195047a5,b1772b19,ab29a99f,cc082e93,c442e927,b1ddb235,eeeb4bb7,480f3dd0,92e627a,a042533d,a9eb598a,6cd1ed9,2d75aa89,a592ae8f), +S(883f939b,6bc9169a,3860d36,9894c4b5,2863b5d8,d0348c4c,62368a94,737fc3cb,96e37629,c05b7231,8800ad96,8e922f7e,5b8a2c39,62a25210,9b3e4949,4b24934f), +S(4ad8cfb8,e8ba3265,4d32a656,76822176,95c40b92,e97c6d3b,af26449e,149f4b3c,491d3eda,89930ffe,e401b994,54919947,7ef33a8d,6cfdfb9,eb28295a,c5ce94fa), +S(ff15cd1a,4b185632,c6f11ee7,19319bd3,abce5167,65539608,b1ee3a4e,1671369,24df322b,ab157296,40aeb039,c00ab8,91c96833,4142f87a,1e00d105,b08c63a2), +S(3fc8e63e,995fda97,1d09d96d,4c84e18c,3e0f4d6a,9f8bca41,20c7c832,c4e9d49b,e17b239d,8e6f7fe7,3c4e46d,3aef9040,6bd631f2,da1677c8,db698484,85922ae0), +S(d88b3d3,6bfe995e,45812e9f,63e8b6e7,d5a87562,1c4a23b7,ab46f6ad,2f7d1e81,63079694,7c97b00e,311bfdb6,198c2c4e,eda57d09,b17fd74f,7140b40e,d2842d06), +S(da6971d1,4c0e9c37,e5b1379b,9cedd83e,218ba47,95e4af56,7956922,c64750cc,a14a0bd1,ebd0727a,258c1246,3aaff478,fcb490f0,53d08a40,44cedc97,61be43fa), +S(d098ccf,e2fee442,74377e1c,57d0b924,45f0954f,7af643d8,b7ed5d9e,956fba23,85c99754,17df24ef,2786621b,c0be5069,a9c59da1,61e14759,ee26b524,e9587d18), +S(633f9b18,9dd98f3d,8c4de,528f7170,1c9d5972,cabe3219,cc4e5f0e,e7e094e0,3d69c877,28c859e5,d9e8ea27,3c04ec98,ca084df5,d7c9cb34,9fa537ad,f7da0b5e), +S(2e14be9,af0dda46,8d59df19,9ac9edb0,c875f829,5715cdda,5ba3bed5,d54fcab2,a04688b,64c5d34c,752396d7,f864a9e1,59eea9aa,db8c93c1,5b4d7cd2,539bfa0), +S(adc92567,7678b197,1e45ed31,38a991dd,a4cd3586,a1ce1498,3ea30be0,642a2dbf,70f2c69b,7e47aa55,cab6ab22,e6482571,e8e1ea52,a52df934,d5ab99d9,acce2770), +S(ab89aaff,b04be186,183e8076,46c64111,476c552d,10df84ba,10a1efdb,32c01162,fccc1e20,17ac63a4,b9f78ca5,af245a74,4174c952,cfe29491,11ce1d71,e4be8f87), +S(1195576c,ca3a49b9,4db3f827,1ff2308e,66b66739,a30d73cd,e8acda4,a382002c,6a2be3a1,c6ae9f0d,b314a7d4,728977f2,17e7c7d0,199868fb,c7f79d31,6cd7d32), +S(8a15bed9,bfa215f5,42c62c89,da0adb8,c68cbc33,d9c879d7,a2f2803,b7068556,ef437bc1,1786cd73,6dc321d0,a3360517,3e7572f5,bce04b7a,3c8cdb85,cb56e697), +S(b4521d6d,f9b20080,4d3799ca,4cdc87bc,ea970d60,a3005071,e910210f,5654da88,c4ddf348,2a23e98f,b86ab9e8,4decc6b6,ad18d879,e96435d7,4b944d8c,f7cc1587), +S(4074523e,b75634f7,6442c3bf,ed9a52d4,5f6636f0,77a10e84,5e6ed950,b673a9ea,d8889a02,ec95b511,aa74db1a,10c91547,45b89b57,981011a0,9d4ce57b,e4e1f032), +S(b2e71794,e6ac98d1,ce532974,df79215e,bed8c668,561dc391,505e9e26,8444a858,94d8ff19,b8a74599,fbe5f471,e7f3e1ff,e0238cc9,2504f99a,9c4f5fbc,2e482854), +S(2e672209,8a6b4ca3,905a8910,6d23daf5,aeee63e4,34e7bade,70395df0,e5a1af87,708e9fd2,a3c0a3b1,b0e03f96,c3d477d2,abf6dc0c,bb8a7181,ca4b18db,ed12e3f7), +S(7ec0fbda,63fe7404,438e36,d567d9b0,bdf18b09,d929329b,24a8bc91,816fd433,f80ab84a,99d214fa,5d288e3b,c2b5560f,a1791412,9c3d16ff,cabed23,736e4f85), +S(f166252a,34572146,8bf3a3d7,bdd2c67c,b0d36b02,d7a70033,add26f97,128b1637,134eea4a,42b482c7,ad625407,bb89a615,656e3a2d,232f4bbb,a33660b2,403d6f63), +S(7af860e0,27d3b1df,aa0244e2,51f9459e,488afbce,6a3aa610,e5e223b7,81ba2d93,6ad22116,415c668,7dd3f4f7,b5a00599,bd35705,951e1093,3f85f815,4d0c8af7), +S(e4ad03b7,e01c5d04,7030fe59,6e7e7960,77d9847a,e604d2c1,d801a5eb,e21c0731,c7757ea8,f57af58f,b64f3eb9,c7762bc9,544f28d,a80d760f,c46b0c9,589019e8), +S(ffb2f941,f27aa8ad,6a59ed01,24e83bb,d49f2588,a5602389,15329f6d,f77220dc,6812c00,7dd44185,fc3f0687,6f7a62d0,d31adc40,c0a1a060,c67df13b,e4cd4873), +S(42ca15ab,9f245041,ce991e19,3d696f4f,4c277df9,8cad603,8ad0772c,2da6e03,972d10d9,37e3a836,9b831b2e,347ff11,29917a59,7ef94158,7c977604,73cb849c)}, +{S(576abbcb,8b768480,882aefc,81380709,831625a4,b9de63a7,b9c3390b,9cb4c7fe,b49453e4,6e17bbae,2f1f8f9b,91c3ed04,80d5f194,33917cbb,d28b878,bc6e6c4e), +S(f9d8a157,c151181,3e085c1d,ef2958fb,df2a17b2,6b330a0b,2d512c87,69e5c14,7eacca29,26aa402f,f8b78d57,f5e02add,91087da9,d607bb41,b56a40f8,f7b19b78), +S(d31dff73,7d2d3422,7fe39dee,b2eb4bcf,dc84bd39,d6cfc4ea,ff09812,23400a80,4af55e8a,fe8e8ab1,2e2c4463,d41824df,7b53e44d,efd946ad,b6128214,4244055d), +S(9ff2bce8,a9fe6c7e,e68a8292,f0d2f4c4,8d963c47,63018a55,89a2c130,667bc861,eb138923,94aadfc9,6eca7c5,78c0fcc,bb31a40f,98d02e93,a140abd3,cdf041b3), +S(1397cd8b,aed3c601,b6eee616,243a61dc,fead22fa,da50db4c,1f9e2776,6e5bc9da,534a8e23,59316503,cae233f0,3b6ef0bf,1c7e0105,119d1a49,ee688f04,40695c66), +S(4ee38986,511024ab,5385f710,42bc3778,7cbedd0a,ad13ba24,b77f42c8,2ae935d6,cf87468,24a38404,f313965,a64c927e,4ba0b7e0,140f6b36,47e2049e,35a74e4f), +S(7614cd7f,9b5f1455,74d0d38a,370f69ca,f3050297,10af5242,e5ccf19b,187dd189,b946eded,e4b72db1,6dad876e,396e836a,875d7c9a,28a9c739,f665c741,29ab7648), +S(67fd2372,5bfb445e,5254bc42,f7dbc1a1,65bd4017,cd1019b0,8a3f96cb,7b3c7cec,b556e950,a144febd,a81dd3f2,f729ecb,fe43fc78,8658bb7d,2b9735d7,b06a920a), +S(57572b1f,1f17070e,e9b30b6b,c7168cb2,4741ec5a,b3496b1a,c06ec0f2,5f910fce,8cfe2940,3dc97084,7ab28da7,167e78fe,f2310c83,ca476a97,91ca35a9,610bc560), +S(1f111332,1e31a294,cab4df73,5a0ef333,e753c2f,7c83705c,9a5bf27,1321c4f8,8fed26de,202c92dc,5b51b13b,6e9bae41,3c7c88d7,b858dd72,a11f073b,e2945f9b), +S(23c9e313,b04eebff,15fb0625,43de6975,d19decf6,6416f4d1,855083bb,d738f882,90673370,f380ca49,e876d5f4,b6649de0,24f4454,29cf9d91,96f4f196,8a49ed99), +S(b9251407,6ef7f01e,379aafe8,8f22c156,65a85ead,f671d8c9,89602c5f,804725e7,b3a9409f,7bf973b4,aebe08e1,5ac65562,56983f89,23415e0d,eeda4f4a,c0d7c5f2), +S(1bf9deee,948b3fe1,b4345800,51c67266,8fdb7af2,99275a83,706f9716,7e38e38a,688fc563,771b7d27,f9c09953,c40cf009,a55d7329,5fae0b7d,8fc37710,729a3911), +S(34e20de5,9d00dd45,19a70b3f,2994fc4,588ca9b2,beaf6afe,4a1daae2,10692f33,7804aff0,a43f1ba0,438c05ff,8d013e3b,e5180bb7,3a969825,fc97ef52,6da1b6a8), +S(80fc119e,85e88b0c,8c84d23f,9e44e96,1c7722d8,51d4c9bf,f1824fb3,365823ef,efee941a,a60743a,28b6ffd,39762f9e,437d2b00,206e718,7fc423bf,4eff0caa), +S(89ab0f45,e3860393,f24b1845,7578fe79,b812926a,6bff3788,c8baf283,89fdbf0e,57d4fc21,42bf446f,8e4d9331,659e7673,90391fe6,62e77ee7,f7a4886c,8f440c8d), +S(1f092931,664bb98b,79d8fb4c,efb287a0,f72641fb,1cebe711,820c92e0,42f26437,59f63ca0,b8e2e959,a97b1c1d,1cfa4c02,380dc42f,db7cb5b0,995ceba1,d7e45d94), +S(95ac9f36,f447928f,344eb4e1,9ea806,717600e5,148ad222,fdd52a83,86bc3537,cdef5355,e928b1e8,225b5a53,bb976822,6fb50d1f,6c6cde20,758d5ab0,e9f28543), +S(a9ce5ddd,9941ea69,1343ea71,c85fcd73,6269826d,6eda5008,44cdd1b9,4a66044d,29504563,1fcb7590,27d904c5,4ffc325,2ce3c8a2,169f4649,907db751,2ef3ce43), +S(2edf81,45c4bcf9,62425707,ccb36a3e,7fa1fadb,4062d14d,f78771eb,f3ec15d9,dcfc961c,547548f2,73206d9e,aa0d829,a235f66c,5afbba92,68fdf9e6,abc8260b), +S(fcf5b985,c935e207,92907b93,e9976ceb,ed320a14,3cf286ad,b38540ad,b4077dee,8a0e0b4d,1ab114b1,caf7d0d,f749f219,b75acea5,6a71b3f6,aa18557b,1da85262), +S(2bd4391f,42b70803,2baf4816,54569f48,95f1434e,be6f146d,41447f45,f14581b3,dbc9937a,61f43af7,42635810,5cdfa02c,49a5186,ce67bbbd,7ced2842,19a37506), +S(eb00deae,6cf69ccb,abe6b93e,e5493e05,d22e53c1,b069a6c,4660330a,4e3bc069,18002f2f,61b08dbb,60c784b8,4c6d71d4,6b004e6a,3089a0d5,f853d659,83242d9b), +S(c7c62a5f,ce15326f,25b2fc5b,697cc7f7,26d231e9,e7e9f15f,5998b8b0,10605524,8ad4b370,ea0506f6,f25eb16a,78f87ef2,f408cd17,fa4ec63d,4ee21448,1d5286b7), +S(aa1c2baf,632673de,6f6704aa,5a76c077,be0c24b5,223de654,88d1386f,15a1a002,de4648e4,fda7db79,41efc5e8,6fec516b,c6aef164,62d6dc08,fe93ebc7,a85261f5), +S(11871161,13c3c670,e7f5366,edd22282,1f76ec98,d1a3500d,f0e483d1,e53f2666,d0042c9e,8dc1d72c,f53836f3,2c76b5b6,52fd5ec1,9e8fde42,aed1a7e0,9d242745), +S(e232a92c,9ffdabcf,24422182,34078534,6b6b79f5,983ddd57,2580c3df,e4ee4118,6c1144c7,471342d8,7a784fe1,587ef576,483f8980,bbab12f9,35aa0d84,83c1d76d), +S(1ab6237,3998ded,e50aec45,8043f830,8a7b4564,2dd3c9bb,4804f98e,a7c2e0c9,5528e158,6a23aec9,81f04b51,b90576a9,a9e7feb5,53200e51,e604898f,e55996f3), +S(3bc24bc9,cbc58de3,46644de9,b17ffa7,39a0f7d8,83eb9f52,af19eaf4,d8d52891,f71cf5b,7587c275,8014127b,f404b70b,b257bad7,f5b78d2e,c792e1d6,b2fa4493), +S(a2bf9afe,e6eec182,ef5866a,b4bdfe2e,9d045323,343aa422,8c1a13ae,fee515dd,a5ee438e,3aa35484,c5f5a1d5,43fa15d7,ff0d1c55,6571678b,a3c5694e,f93cfa1d), +S(a0b2b4f,ed0ddd23,8812806c,fccdfa9,7fb3b42a,748721ae,6477dc9b,18953133,325ee7d3,4a540d0,fc3e3935,79ba7372,905c7b17,4f12b456,b43db5c7,cb50ec66), +S(e7b9796b,5ca006d1,632f482d,7f0fe393,2cf16a5a,e104eea7,a7ea1c25,1073e879,ed476773,e6e961d0,20bdefd5,8c833e35,634a40da,1256750c,c718ef75,45575e97)}, +{S(a8565dfb,75f8eea8,ca9ca6e7,c7d18a5,bf3e437,5d1f4e87,68d5f51a,57199ac5,daa7d7c6,cb86b215,a682141f,2308d9b,4c204196,eb779f32,fcddf0a2,da194921), +S(974619cb,86016199,20f507ee,62d10295,44abdd66,456952a0,54e945bd,7890250f,6c8d8bc8,21da8234,1ffd0cf0,548be1dc,a1bb7e1f,47354dc8,3e5d96c8,2c9676f3), +S(24bbdc24,1396b6e1,75f23a6,4bfb41fe,f8329b80,d306586a,ecb69e41,2a2014b8,aa6448ec,f00a0710,27b46f09,d696642b,9274ce3a,11a3e986,e84536e3,7fd7b2f8), +S(eed9a6b4,68004486,e3bd388d,591d3b65,2f35a3f1,9401e5de,81a86f5e,b7cd972c,c81f9aaa,d7300671,b3dbdd73,a095c79a,d73ffbd5,9f845eed,9fe3a57f,a41e9468), +S(5260e0f6,fdc6858a,8d519d3f,6c71929e,36979b65,431a6f3a,a7507797,e54654e2,5af860e5,fbcf9676,bb00c329,d3e2e058,efc860e5,cb9006ad,224caa32,9fd49f07), +S(11e53f67,d844c511,b8118f28,de6ed9b8,66b70bf,214d4d1,ed79adfc,18f7d6bb,20dd984d,7b9eb626,77e411da,2e823045,685a4bc5,2a3f4e5a,3aedea95,1060b330), +S(98c9f3f6,81e220e6,d4bba711,fa8b212a,dcc21bc4,8219b813,eabdfac5,70e6fffe,bd0890be,d9cf4ec9,44f6abb1,56250329,a37d2cc4,64c931ba,8606c2ce,55127aa2), +S(f644f4f0,43d7713,ba4380d8,26ad0f3f,44106352,142fef13,7c6e05ce,5e9f1571,3192280b,f3971223,c00ed336,94779866,536020b6,79ba8cb5,c4f9c515,69d2f97d), +S(334ab869,32c4097c,8d8d8a23,d529b079,6a759d47,a907b047,548e735,5b3b766b,18f11736,d54c9d00,89149b07,35f5a9de,b15d9c,cde4ee06,155a4f3f,de98a7bb), +S(983542dc,61b43ee5,c4a7f36f,22da008e,832d4eac,6791d838,1a095d0e,6d8a14b5,cd225f2c,334d1ba9,94b0a681,d6be7696,16bfb2a2,426e9939,d2238cd4,43bebd02), +S(dbbac008,1b678270,4a0fcef0,73683822,a3d4107,d7f1a71b,41497da2,9cc942a0,cd25ef66,36f21a8b,532371ae,b91b67a,deea5797,983dc36f,54aed202,d9845515), +S(477949e6,9ed28a74,879bc8cc,660696cb,115e6392,5a63817b,60e5187f,1f77f3be,dd8ca490,fb8e3bc1,44f5fe9f,aa41ce73,56a1dce1,cc8e11c3,ca5725e,d1b764ae), +S(7616b9e8,b451d4e2,e4826586,9bfad6c8,ddbf5fd2,2342c6c8,42d6bbe0,398f94a2,4e3bb1a9,76efd345,3c4474ad,e6a494f6,4f97c6dc,c98cf68,72bca24b,dd9e946f), +S(b87fb86f,6ec4ad7d,5bec3bee,e8d68618,c8e4906d,1c584368,ec819f2f,871ca8c3,c64723c0,aa587911,4dda9c75,493f739b,e8c2221b,b2e75ee5,b25def54,a1d40c2f), +S(56ea4572,61a6ccfb,46fced99,1258b31e,8573a488,aa53b7ad,65333452,b06d41c4,d8529601,4145e12e,a72ae4d1,5ae6e5f6,9cc88ba1,4d79467a,3df3bfef,33d84290), +S(e4c6540a,19682e0d,e1f1258a,103037a0,af4df5ad,f27cbb7c,9e3ce67d,e23e13d8,a31e1b08,4bdb5728,36e53d93,1de035,c90b1efe,b5343b23,cac0e7a2,bf5b3868), +S(1902cf3b,90fae93,1855d758,24995b03,e1604861,199853c6,ece84903,c8bd67de,3b3d41e3,a2dd4c28,16d492c3,e6c53c83,e5203c7c,a8100d41,24cbdcd0,e12fe222), +S(6519f4d3,b5d731fe,eada6806,727623a4,daf924d9,b6337a51,56096ec4,16ab42d4,62e2c1ea,afa990bd,6dd91675,e3b2d1e2,acb2fee8,e56ec30b,eb25bdce,2d3ad30e), +S(e1128682,519b965e,a933f197,eb0997a0,16114459,4c0915cc,9c55ea4,a30c1ad1,cb1370ba,f8707c78,84817ee2,8227da3b,7b7c97c8,266af491,e0d52bc4,ea0f9614), +S(4366960c,6ff595d4,143d4cd4,f0f0df2d,3bf864d5,73790abc,23419c7d,6ed9201b,623faab8,2caebb5a,b4c42bf6,b2a686cd,4640cde1,a95a65a1,f8d32836,9e5ee0cb), +S(5acdf691,3c1e283,c1220355,6efd99c5,d347ef69,bda1d040,44cbf0d1,ae41b16a,1bca567a,71698c35,e35e031c,e8a98dd,e34270d1,4e2e2439,9276a7c3,6a1f35df), +S(807ecc04,81aae374,1efec46c,8c6c194b,faa0607c,cf5b7cda,fc270fb5,f5b416bd,cc60be6a,6736dd94,848fbb05,375f6459,d556866d,165a2c16,41984411,dda33fc3), +S(29c470bd,97737284,765adcaa,68a98af7,5e6c275f,fa4fcd5d,6c71d428,bd3bfd79,b19ab40f,33c15201,41fed31f,681f176,4a464373,23283677,a40b4018,99a6eec0), +S(41a6d6f9,40bb8abd,9e8748,dcfd23f0,5333eafc,4ce311a3,161440a6,619efabb,b2a3702e,900788cd,bf35204,27e0facd,b090804,62f65418,89a3c34f,ae2cc008), +S(d5f5096d,776ffdb,f694b9c5,c9a9ae0,ab5897ff,c5ca3320,82cb2a2b,8afcfe89,6461e24e,28560d11,336244da,2038e13,c69ed5,a7a435a6,d07a1d72,be43daa0), +S(f65a00d9,5707ce6c,6bd55e8b,4b0ef381,1eca65b2,9845433,d7b307e,518ea724,7ae079e,9aecabf0,4ec5210a,b85328f7,e60c8ff7,3deb037b,c8e6e1d3,34774734), +S(346cff42,23c9ed2d,a1082d46,eeaff341,f7866e72,d95561b9,678def2d,9f7cd187,f97f85d8,92002750,11efcc9e,f8ff58e4,894f105f,b94e7390,7e185806,575698b3), +S(d0e3cdff,a47417f3,86f64a2,4029e3fd,9bc7a464,6e839bf9,232a0d50,349ecaac,5bdbecfa,2a2b35d3,ce2e9837,222535c1,57ec5bda,5fd70186,1920803d,a279989e), +S(f6bbbd77,b8dba8fd,704a3f02,1bc418c0,f8524c49,ccfcd14d,fcbf7f04,c9a18d,38184001,f39b257b,6755a132,86bdfd92,1a8ff771,fdd5530d,48eb8227,ea70be1), +S(6717bbd0,f019990a,c01a2996,e34f0912,9bf60a3a,71d8124e,fd86c777,9cfad879,9581f790,a16825d8,f44f316f,db3f0bde,108643cc,b390bdc0,75f3dccb,6520029f), +S(417c765,ca91a120,2b07459e,3713d5e1,bbcdfa82,bbc26cc9,279fa2d2,59251fa2,8d281a2a,ed38a80a,cb697989,9839d7c5,265b4e78,8a9e1176,66cfb6fc,4143a935), +S(e2f349b0,f89c69bd,3c8cf2a4,10730dc5,8e0beed4,7048c58c,15f9ffc2,508d2cc2,e014d0d7,f07d8dc8,7e79f513,89fdea45,bdcbb417,1f63424c,81cb8426,1f2b3be0)}, +{S(aceb57c9,187a5202,118c4dbe,573906e1,646b0325,781c1352,574ed15,e02b87b,68ece7f4,4037ff05,d4b89120,d90f08c6,f0499fee,d4e9e02a,a2e68bcc,2d7b70a), +S(365e555e,de9130af,99f996b2,106229c,c36c1ea5,8b065cb5,38af3a5d,2cec1145,81fc523c,b4b97bd3,cccce1e1,d1980769,fbc25a9f,a403adba,8e7e8074,13c87f9c), +S(d0a3812c,b9244d7b,c1f5b652,adbb0df,22d15d41,b1724071,fd297d00,bc8cbb01,f8d7650e,fda2be30,24ded196,eb3baf7f,351d2013,2479640,16ee4c6,b469951), +S(8f4ce1e2,a51c0ebf,f5e34cb1,c6aedd87,85e415dc,e7307119,143bbe9a,3e7fc632,617009a,ee7d4d81,1ba2bf14,d1647911,bf1a3bbe,cba8dfda,9030ead3,803fc217), +S(ea23d837,54cb2e9f,9b884ef,f4d1a708,bc1826c6,59fea53b,f52c51b4,9fe0e21b,7e8c691b,cfc3b7e,56a7699c,4f56a11a,fca5710d,963d602b,b102e1c5,b36dc3f7), +S(e3c970b2,c764c9f4,ad8bdc15,cf995690,807f5d09,4a849787,9d278d18,eed6ceea,aad8c7d7,13ce5439,b9125d9e,c14b5d8a,1c694cfc,f84e6922,b7e58df1,4ab8a34), +S(8ade30a,94b236b9,9597be14,bd421130,b6843895,a85f3613,efcfa0ce,9781a96e,78e4bf57,974cfc0f,c310330e,6aa47de8,2b0f5009,5a703fa,50093d5b,a8e8f0ef), +S(fa5f1cd3,4427d71a,de7e79b2,b0a17ba9,66d05324,1f9996e,be8143c1,9186d24a,3481bd18,2319ddf8,f344e4b0,196b3ddb,10deef4,d8d75c0e,49fc5fe4,cbd6e1fc), +S(8b88b79e,8cd28dc8,58e3f1a6,155146b9,af1e3697,d57b7435,c649f6c3,bf8574ca,e736106c,8ffb9bf4,d83d79f2,4faf8fe2,ba5dc258,e4ae1b1b,b58a1a7e,4922c95b), +S(12078a5,5c46d721,96a148d2,fdf6505b,d059e423,c5d5295e,facc2b82,aec51f5d,66a4332d,cd265085,add9a141,2fae2562,17441d7,dd9596ad,46309a0d,bfb4e55e), +S(841523ef,29f5bffa,b31a526d,bf74b16b,fac3a3aa,391f7404,6675cba8,7808c171,7a3fc3f5,bac300b5,7ef843df,e334c995,cf66de11,2283fdfc,767cb57e,e7e7329c), +S(c8831ece,f4545c2b,387378b4,f88173d3,f1cc7db9,d064774d,60394f0a,ecaf5af6,f32f1a48,bb802757,34e66cbe,58a3ed3f,adf28dd9,374a42a,a824a095,6701322a), +S(30001ff3,7b1b1691,9a135a31,287e3a3d,383ef3ca,94748e33,a52c146,586dc4b9,9d71b25d,6fc35db7,26b58d1f,642dabb,46dfa64d,e0ec2a12,c53c414a,9dd2574b), +S(a17d3621,74d3c789,c4e00888,fd4b0f4e,ea3929cf,afea9e9f,7439901e,d6b0fe44,2bcf09ef,2d374194,510fc057,dc973fe1,bb687428,91e9056d,a5b4df7a,de79bf), +S(4725e2cb,19f95359,2da72565,d8405e09,92a64299,9ad74ed5,b41f5d24,44cb6b0f,be23fa82,7aec3121,7b90028d,b61d1092,764b2824,9f3fa0ef,91929db9,b2e0246b), +S(67c560dd,74c276c4,df3efbe3,b95dca4e,a56c4563,cc7ae225,ebea90e0,f5e212fa,2c9e3120,d52ef31d,7e9e36d6,eafbcdbf,ed8a28c6,7edefb94,1df7f38b,cb05c160), +S(8468da98,7b33b79b,e08da5fd,57cee298,ef86f624,3bb975da,2f4261e8,f7531d92,455d8a8e,b4f45693,2e8b6f77,ddefe070,591dd37f,d6ad3a27,5774055b,8a63e650), +S(3416d4bb,78de7570,b1e9e912,83a3e8fc,be6524d7,4463dee6,82e84e52,72c0953c,94e55458,2c17fffd,321364c9,16658093,986b56,f88b4818,129e19c8,ce685dcc), +S(5c66928c,a39a6e22,672c1dba,8bb6331b,41a7f43c,a72276a6,afd3e209,6416a9c5,181cdfc4,15e7d6a3,c24be94b,7fe328cc,ab624c0d,dfabb1b8,f9a73b56,cdfe1b28), +S(971f7a13,210680a3,ff6a12ad,17481a63,ef624d0c,e4121166,7e63aaf7,9cafce,5de2fd1b,3149e321,2980c7d,88a49018,26f83f18,7438061e,9bdb8d33,6a4b08f6), +S(650277a7,9ae7682d,c5f3526b,8411342e,b48277a4,9876caa7,61ec6815,9a1f13c3,a903255,fcf09808,cd97d92a,26dbd2e4,7a29571f,ae91107a,7cb6f0cc,3aea1985), +S(76a79cc9,7fb80ab3,e8d31e5a,d11f5ce4,74696d23,f1ee7aab,3928848b,556f483e,1779bc5d,c763d1ef,7611b402,4583f07d,c7dc9c96,7afcf83f,e6b6ee42,da75972e), +S(6e0b4015,474fe250,d372400f,13efa0b,70c4e8df,816c0e8b,8d27a7,a8168d54,f01dafc8,8178dcf7,15f8fcc2,e7163137,9e1dd4cb,6c88cfbd,e9a051f,ad204c3f), +S(ee5dd472,b5efeba9,d0e354dc,21228d22,40a69088,842d00dd,6b6358e4,309d1f5b,bce93ac,3fd4a098,9e74448f,5832643a,a2a172f2,eff1e2c6,c61ea99,cc6e7cdc), +S(df99a925,ef2e9f9e,57208fe6,5373ff94,876b1448,368dd453,436c59d0,f2a857e2,88dcfe81,4397f990,56f92a27,143c902a,2a6a66f7,f7e9652e,e0b16f13,33252a1e), +S(9186f095,43dc64db,ad582561,cab96a38,89be54ad,e1cdb27d,674af836,22b5d284,71ae31d5,a73b29f,54af1aa3,2d8e541b,14f7cebc,9279ac26,c846d466,aa975e20), +S(645da454,63357bfb,61b5b932,1897a73b,87af6077,81487bc8,af1a66ba,49bc5e37,4b925aab,aa7bbc19,5963025e,f1896cb5,b6463242,cd8a35f3,b1b404b0,7faf8e94), +S(5cd9a6c4,e9d372db,90a65f11,1f1a1b5,f28bc3b8,3d05f599,39979c91,5277eab1,c147420f,7dfc4ef4,d7d1f08c,1c523771,86a8d7a7,10cd7017,82b97c55,63287aa8), +S(4fd699b1,2c720ccd,7b977e5b,dc622671,18ac3028,bd635b26,fce648cf,335cacbb,3936f10c,aee5f51,26b86240,3249e1d3,5566714d,17ddc19e,cc4d1056,71e523f6), +S(b3fa0545,83510d6b,91226711,4bac7f4,ba4ae5fb,baad7230,3003efcc,4c3c18e1,57a3db8a,6cbf0a94,845e7d67,f9b01902,55aa5b66,ef31abd,34ee0410,ed55d0e0), +S(fd73c052,b194c6c6,dd46aca9,d640981a,ec796009,17a565eb,e77fd534,649a2115,9df8973e,37e877bb,fdf5454f,d9082926,fb09fea9,d162bde0,fb635483,59458f55), +S(2982dbbc,5f366c9f,78e29ebb,ecb1bb22,3deb5c4e,e638b458,3bd3a9af,3149f8ef,59e4a416,5099ddf5,4605acc6,384a4362,f6a2466b,ed1c127b,a918d94e,e93859e7)}, +{S(8aff982a,fbe09f67,6d6e0f49,e2b68f88,8f20dd2e,6387b420,8157ab24,d19027ed,f2350ea9,d00fd861,41259f03,b51b5326,6ce05a34,74508bd4,31ca74e1,366eaf92), +S(27ff285b,1e14961d,a042bd31,56aa44af,5e73717d,fa413a47,b300f358,e1960dd0,8b578851,264a8fea,2e29bbcb,cb9c90e4,93e8c731,983f4bba,65381e88,bc83a8a7), +S(fc6acf61,4a214859,1418ab5e,e0f0274a,309a8248,2cf01f73,db8a9790,825486df,190b9c0d,46953d99,c9de2bdc,bcc15d23,ee90485c,c4c152d8,e28322e5,4c927d54), +S(743bcc6,ac86b0be,a25cce81,1fdcfc13,73f23926,e3116fc8,9415b8c0,4c1983ac,f3df10fd,4afbd3b2,dc0678c9,102150e6,3d005680,6a5e45fe,c95ea495,9f2b8555), +S(bb165428,2c13362b,b1e017e6,6402613e,f82bbe22,9429f29c,6a1a522e,4956d67c,ec542c4f,7fbf3c6c,32e71aaa,86e3e4e7,e52b0d43,98589e15,1f17417a,40b31b07), +S(b3f74ed2,5a7fd474,5820a2f6,221349aa,e41af762,25c2b706,160a463d,1d59e7bc,a9af9d2d,89dcdfe0,21ca46e8,5f09bdb5,197c8f23,bc56d705,851974da,1608dad2), +S(20c0914e,f88902a8,6af0ff68,a08f96ea,25f15ea6,b1128900,120028a1,1049a77a,339567f2,71a1f1c7,16eb1d56,2f009537,68ff4cd3,9a81c6d9,6359d2f5,5d04db9c), +S(a3555aea,2e96f05,d25a145e,4ad0d2f7,fb453974,8c4a3097,a703c0f5,404a0e7a,ee236b76,8fa04380,b0448beb,d2589665,e43299ee,b9fc78fe,5a64db69,ac92b7df), +S(37191a66,1d2a7bd,c96a0767,ce47d97d,7acfb8c0,ce251e9a,1421e2d6,29230c2b,57093393,4783afd7,2df6524e,871c8e67,ff2f48c9,c73e2054,fb219cf,d3c2a68c), +S(1a2f5b6c,5fbe300,8b01407a,b0b28c3d,c823cca9,b4c71a1e,4fc814f1,e186e062,b2f1c632,a9d92a4c,82d31a55,f4fd50bd,d53ee99a,2e1452a4,e43e5ac4,b8cbb7c6), +S(2976575c,c5e70e47,cd9c10e1,32a593dd,12b65215,38613cb7,22390022,73fb41d0,c3f0b08d,a2a3a046,d87dcb13,38c35824,1a8b9959,e2567543,852dcf73,c4f5cba2), +S(bca28e75,5cd6ab74,85884b30,ef399f,44188695,fe9c4143,6016bdec,25d502f7,b67538d4,a571e935,cbefe237,c5a01f77,4ade337c,fec9f95f,3e9cf042,f0dbab6c), +S(3dfe1718,beafee83,b858048d,25d46ee6,7741d3bc,bec1e52d,3ce308cf,738b715,8499a8b3,a0c7c599,f62f056a,a8364494,ec6e0198,2c47bbf8,7e2df591,de0ff537), +S(bde6252e,a9e4823f,36bd1737,ce188fae,be4a271,9984c9e6,76f9f4ff,d070c1c1,2e5db82d,e02a1fe1,39d903,7e7adeef,12d40366,de0eb164,c04b2ef4,b1e849b6), +S(2c74b766,eebac93c,479fc0bd,78a3805,de50be2d,a6ad70c6,9048e43e,c91343af,ab7a929d,588ff993,55094f83,6e7b3b58,c6381bfb,b284f9bf,7dc44cc2,67cc741c), +S(f0e084a7,af9abfaf,b6ebf3c5,b526d545,b8b1cf5e,8e09a06c,3670aa37,6af83a3d,6bb279db,abdb2b2d,fcc97510,2b075dfe,b42d9e6a,5a8af760,f4b63788,c315f8dc), +S(715aa28f,4e52fc26,a2f4b9f,391894b0,6adc3b69,b508827b,4732396f,5eb7edb5,c5d0d68b,3a8c6532,2f6303ab,99b6c48a,88572c4c,56c780d1,d51d2441,86ba110c), +S(8f980e69,3511ec3,cca89b2c,362835bd,24d9c8a6,97deff86,5540f7c2,b0bacf8b,2d5e8470,f2041ca6,f158ac83,e92a2345,4059492f,af27ada2,92bbe51a,d67ee5aa), +S(6823a4e9,d80838b2,750dada3,cc31f59f,3cc9d6c8,3f33aa5,38d949aa,c4d6d657,e087127a,3ddc19cb,e4088a2a,6df61863,e8e81cf5,c5cea4a8,8cd2ab51,bfbcba8d), +S(8c9af14b,11add28a,818f85f3,276d1d7a,1e3478f4,23e74b72,caaf2440,24558538,a7c17174,da1eed2,7eeb7b6,c1d93e4e,9e4515c5,3cd888d5,e4527cdb,94a64fb1), +S(5fadb7c4,74b13592,a1a27f76,b7c2011a,102b66a0,c6ffbc02,a7306e1b,a9ccf49c,7bf61c4f,134f8b4,7a5f90a1,938918a1,4d151f2c,7f1c4bea,cb8c4773,cf11609d), +S(79a21b82,9325fbe5,c01ac979,8b89cc47,379eac4b,682fd747,47e0c04b,879b404d,abfa4d5c,7ff916c4,9f489c12,5235bd9d,a0395b6b,84d6699f,c96f9c0a,5a4cab2b), +S(b213d11d,e4b5601a,5f10827e,d39a7825,adc36bc0,1130a055,cf8b3e8e,fc96d10b,27c0e5b7,a739fcd0,5eb73321,3fd1bbb7,873de0a1,2b92cbc,21de57c6,2bc812b1), +S(299ef8e,e131f523,72949d7e,fc2f0f7f,9965e69b,56725b55,4d513435,ac8b0b3e,8ba93fa0,2a4d97b3,54d47c10,d5d791c5,f724b68,4f501eda,1931e563,2c6faf06), +S(5143ab76,43a21de7,7ffd0f3b,c4746fb0,589be22d,9d9ca2fb,89403a39,86d1cd37,20991000,a7c01e4b,26d9236a,45568bbd,91c968d6,c87dbe05,15063af,d8db5a03), +S(738ce787,49783066,923ceec9,a841d60b,56855e09,93e67cb9,9d52a0ca,7a64b5b2,aba44aa,272945fc,5eee0330,976b659a,a6455dde,feb5c894,cd274414,71610384), +S(6bb9bbe0,4c3dbaf,6c60adcf,5ec5fa59,29cdb04b,14633c10,5dfca2c,183e1d97,b7dac59b,5c35c3cc,15521da5,89c0d333,9dac05c6,614acaf1,d8b9e834,8e02c3c9), +S(f325eeb8,49a32b2a,fb19491d,8c3c112f,a7ca3443,438c8c19,99bdf791,6981472a,169df94,a26f26b1,e5aaf810,7a148faa,17742c3,10cac320,6daa69,f8aad67b), +S(d279bc0c,f7f58a85,b5abbe25,936d5088,4d8ae8a4,b415ea30,2c0f1133,de98603c,1e69875e,2e38f9af,222e03b1,6c833bd1,12bc10f8,1724da7e,bc780e6f,5228fd17), +S(224d079c,750eb1b4,2d70aa25,5fa0c3fd,c2d07c1d,ae4d6cb1,17c1e61c,5ec1c6b3,e54dc4fa,b0e05362,60d27fa7,ba53c37c,a37ce30e,617365dd,1c58a59d,2c93ed00), +S(f4741ca2,b3de5414,49426531,d546272d,ab8fc55d,8f65eb3d,5ea780a,d25cb53b,3b7290bf,dda0d0f,e3704f27,d8537063,f2fe9571,4a0791a3,e1a25865,96a5b0b1), +S(e931258e,8eb5559c,6d697272,8a704c17,b775a26,5b4527d4,a4d4d742,bbfd71fa,4e1ccc9,b3c0211f,17a14be9,636ab4bf,4c6b931e,44a1ca0c,c2642f2b,e8b2c928)}, +{S(fa01dd32,fada2843,c51845e6,3cdc1b76,79dee47b,d2f4b767,5133aa5e,62029057,6ea6596a,b0ea0201,b6c8bbbc,e9d07fd0,8040e1fa,198c8767,67ab6055,34a33), +S(97ec9d33,a9d88115,471619b5,3fc58a08,e6997662,7a28afc0,b75b2f49,55eba300,92ad1d6a,f8a0a100,27d9ba90,4f7fea6a,571f3c32,53393a7c,79abb0cf,9a558390), +S(ef364ba7,626d72a6,87bc9776,3f2c0833,50640bec,6ff4d80,9dabcf2,9ea9145c,7f8d7c48,1bd80ff4,8eccfa9d,2de5eeb9,800cb98,c02da539,3b3d6c83,8fe4a2ff), +S(45961303,a778b47a,89109231,3242304,30a17859,7d940e9f,fc2f25bd,1be61c00,5fa356b6,daad2b1d,7bb19cce,b9148d31,58d2651a,b4b436c0,b99193f6,61cb037d), +S(8aa677f4,d73c0725,e2163e5d,ed3dc312,7ad5ee29,f9bad8b8,5ab8f50d,ec6d77e9,1fcb9da0,d3fb9bc3,3a45bcdc,50aa2ba1,16c2b05e,836b539c,863163c7,2436c334), +S(8c6b2873,33082bf5,a3597a26,7cc14696,2b689f20,59caf1d9,35972c98,9b14c86b,aa86d282,a1107f8e,21307e0,2ad1420a,a4061fea,3e3dd6f5,9b5d6900,6bf4827c), +S(46c963f0,3bdbf433,cbd60858,5a4d659e,9815c286,9f684eaa,cd879d66,ceed05ed,be2a8d60,636c5b80,e443b13a,9e21c91e,90a9e781,1c35101a,dfd61a49,88193e86), +S(cdbe43bc,582f3936,314a88f9,fa21b29d,f4b5acf5,96cdac3,4667e9c4,b02b926b,8f2a5b62,4f20b20d,cce97348,d73d5653,8651dd41,dfedd476,8792fa61,1bac16fa), +S(6f9c5a84,1ffededc,ec45dc63,7ad15aea,207116aa,a3036ea,ddfb0656,1dfd074d,ddf1c22f,9168232d,cf9c36a5,dfb7835e,62d28405,bd32ec15,5e3ddb3e,df834088), +S(42000663,3223b99,e15a2a65,bd95b229,820abee9,5ba5be39,6f8879b7,3f421e7b,9f3f3d66,40de91bf,c6872619,87487226,57e60a4,3ac633cc,48f684c0,cf42696b), +S(f02335b9,9cb524b7,45fa9167,41da4259,f70279d8,efe851ab,f5b0b8a5,32a087ff,e1bc6767,ba068b22,cb7389e1,36805da5,c30ca62a,e59b92f5,48e4dd1d,5327cfbc), +S(5bbda2dc,cf8154e8,28ed49b1,2fdabc3e,eb8c3f9,d0da5878,77611ff4,49d72e7c,312377c3,6277addb,d5b044e,fe136626,d5f7e7e7,a73cfc4b,9751e8ec,e4f77084), +S(5cd5cb83,ba2f225d,1ef4faf6,22e226e1,eaa85a5e,99721d3,82aae23a,f9dff565,254f58ba,9c49244a,4178a067,b0e4bf6f,dd7f3e15,65e21637,bc41f9f3,55045908), +S(3b20ebc6,b453aa16,e5b61381,1d81ca1,f87dce6d,b54ba85b,d8578ee3,23bff228,8c9d3054,56627a,7313505b,4aa5140d,9fc40d83,bcc298a6,43842f04,70a335f4), +S(cd531999,cf33db75,df4430c6,bbcf32d0,642be18,5736d79b,f2947989,e52c8da8,c7e99c34,2a5c1112,400edc69,f58246e3,d3cebbef,2c43ff47,7520b027,e2aa7d78), +S(40b3856b,273bd2a5,145b70f,d16a2972,e488b33a,f3719143,db7bc567,26ff23c4,d8bf895f,71d96e6e,20d523dd,1256bd56,44e11442,c4757d74,f116ae44,69dc9b21), +S(1a0cf029,2d7cce75,32b74bae,acec6864,9e682788,3cef4bbd,c8b24fdb,53e885a5,32c87d92,6f969f69,7989837d,d8ec8ef1,c284d9db,2a86ecd3,5bbb6772,dea06692), +S(7fd5d251,93dd6c17,8d0be92c,342f94a3,c92c061,27998f4d,54f7dfb6,1326fefa,ea7d0755,e0a804bb,8b7ac8f2,dbe1dd7f,9ccd36ca,2fa94365,631ae455,5d080075), +S(51820145,6c07fa3e,70d7b24a,7754b11,e42828e9,c1b96b0f,fd79bead,2f44050e,126f5526,1a55b724,7d08c868,366d697f,a6898c66,d14094f3,44b0a6b3,613d043c), +S(86f2c87d,46038770,3be5ddc6,c2ba1ccc,7dfdd56c,a9986663,882f85da,345886da,ed34fc59,4b66f7e,f06f54de,84f3c7f6,ea1d877b,bbfc4185,3df800f2,fa805027), +S(7f7d8a69,5b86ca13,d6a0ba07,99e60cbe,f5c4e1f4,c74a62bb,93d94d4f,8c1f296e,44a14061,b2c741c4,6a52639e,9bf08776,5db5d496,92bb6d1b,e97f9ced,a89953e7), +S(ec61e956,83714c55,1b72ed5f,c5b09663,6dbdea9a,64d13ef8,c9cf0c55,89da5ae4,39a6e38f,9f7927cf,ffcd0847,df91e856,4188bf58,276bb4df,3721335a,5357c77a), +S(e5906c85,4a75bee9,322d70be,a5d31c76,31a59389,2f479bf,8dc11bef,9ad5101c,125b3a58,8c6c1c5f,288402f4,3ce74ec5,fe9c2dd3,3f3605df,9ab41210,32641524), +S(6c9faca8,b1b435b9,213fde17,ce967f05,46e6f27a,cf0e131,8496bcfd,d856b092,a04ac67d,4bb07624,6b59df97,2fbe2c1f,bb04be99,e269d33f,ccc81f76,3f567577), +S(61031a0c,730cf279,d929b4f,5608f16e,6b1b1440,c04e5a9,fa300ff8,27303def,acc4d732,afb4730e,39a10c0f,5ae2cee9,5099be03,bf5612ac,391900fd,b51238c2), +S(e58fa07f,ebc3aa4c,61ff4fe3,bfc8d04d,48a1e3c9,935317e1,83d537f9,7f35826b,d2402844,7e63c3e0,be630190,8139a75e,2e1a2b22,b05ce52b,e453ccf7,7c35f1fa), +S(4d4d2982,b45a339,1720af,cf6b92df,2c201d38,5b9b6c3a,8fc53b4f,fd3bfdd1,d72650fb,d130482d,116524fa,e2b3dd71,c68b4bbd,54fc55a8,f9824578,cff67503), +S(9adeb6f9,6ffcbb56,f171919c,a8a64c70,9b8ae835,828bd573,b7a1bbc1,3efb0360,6d920a2e,d2e3f41b,4820d838,ca342b66,9af35a7f,7b6d09fd,b1ba4298,9abe027c), +S(64ba9514,d8680f6c,dd66895d,9c5ad45f,6e29,33506f8e,d7be9770,822aa9b8,7ed8c0dd,59bce424,481f88d7,3e641b61,a010e490,97cf84ca,16c2e045,49e9c6ca), +S(9e4ac64d,9ca58a04,46ca18bf,c1700f2c,16937ef9,c82e8b55,9ccbd751,2a0c0222,315ba2e2,601b18b2,cf7f1720,9c4cff2f,e39dfcf0,c2546fb1,e930898b,5b023274), +S(f13a99e5,8dc72fcb,c62a492,d2850704,621ddf48,f1f433e6,9a9814c4,17d4b84a,cc3d3732,f0f4166a,55946e32,e1c01f91,491c82b8,ef0d269d,7a66f039,ac02dfae), +S(fd6451fb,84cfb18d,3ef0acf8,56c4ef4d,553c562,f7ae4d2a,303f2ea3,3e8f62bb,18ba314d,4e78ea87,490185a3,e43cbb33,5d54b6d,2dff17c0,2f526f78,ecd3f31e)}, +{S(f1a749e,6cab100e,2aeef8ee,6a654551,c0ff906e,e7d11d77,f390955e,9d29d783,a60f7295,3c8c3bf7,f1dc1358,e39baf76,3dba22a0,1ce7917e,aeabd996,e21e845b), +S(e8c45020,4c9d9ad,f7878aa4,184a1576,d4c65d5a,c1c4d494,ff427e86,8b42ec1e,aabff02d,8a715c2c,34414b27,808882c3,f656389c,71c26d6b,d7ac8013,83f4c57c), +S(c1febd79,1784fea9,bf378237,a05522de,1081df6c,27d22ea2,aad805dc,7c2f1c4c,c38782e9,fcc1004e,aa677f79,536aa069,7dd9002d,ac16936a,1f0b8736,8734174e), +S(91925564,4d9bdf2d,4522825b,5758b3f0,4d32da73,3a4e772,bfe3eb2c,9909f4ef,2568e18c,1a0448ab,d038ae62,a652d152,4bdec1c1,a0293695,9772bb65,d78450af), +S(25bb4202,9880c39,f5bde432,c1fa357c,7f4867f,6fee48b9,24ecc824,5e1a5253,5d43db2,64c23715,b4b0eeae,63127cf6,9b4bc79e,f96ea8cc,d17cb53c,c3ac0fc5), +S(2597e080,e772d36f,df500782,5f92f797,c61c72c7,8d801dd1,3deb1bfb,9e91b12a,fd5918b8,938ded17,a458d0ae,559c552f,bd45feb2,5b4f59a8,f5b735cb,bdab92c1), +S(70231b28,f578dc12,9f8ac54d,fd4e3577,73d0fcbf,65be0dcd,51132882,5a36e7e1,d12aaf89,4dff3e42,405a4140,58524e30,b7c6c4a1,83763268,6852acff,83d2b7cb), +S(f8ddfd5e,5f3b46a1,ab363169,12b74c97,b0bd654d,87824040,bf6d2cad,b4fcbf95,931fc58f,5b429636,5e080d5a,8fb35ba0,f92104d3,891d6584,8d24c0f7,fc95bda3), +S(a033f432,670a382c,57e2408d,3bdcd2a6,6758e63d,77574598,6b123e4,d927bf10,83b52f69,d79e7445,b6e33545,c23f16fd,52691151,96ee60d6,2ecf6de5,b2961a0c), +S(8e77f9ed,9a643f3c,bf197b09,80f92860,f37d8b83,93633230,6c902c38,3bb7f96d,71b4da9f,f736f9f1,f8c3c099,c34c1bc4,30bb5d26,3c861e2c,726fe891,cdf7d1ce), +S(f34153e2,29934c71,5d895102,778425f5,e92f4ee5,b96d1333,df207e62,6761b328,954584f1,64c8f35f,2c4e0188,76186ceb,3e91523a,5e8ac03,d5998253,49b7b8ac), +S(e133aa94,c0252f05,379b5bd7,75ba3f1f,92de2876,68613613,28946904,11b3ed52,40363801,613423b7,cc6c0cc5,af3641f4,dc2a7ac4,48b178ae,d1393605,103bd6dc), +S(28119c6f,a57d02ac,856edb00,f594c7be,22772b0d,700ad14,713affe5,7e385b5c,969b6cb2,8ef483a0,db4a96bb,92e2d332,6e6d86a1,73bc3d5,831bcbf2,5efc437d), +S(8c728d65,8b78d96,44003708,dadb48b,65dcf6f,6d9412c0,e31cce3d,b5384d00,bb3cf660,9908467d,285f1c7f,40f4f18,ca618093,92633beb,b4ce30c4,72680662), +S(477321b6,1fd5b4ef,3acd1e8d,8432ef5d,e70576ee,6b8490e6,839f1985,dec96490,88008466,2244e3f9,7d2ded5d,2193c70e,2d72c67b,9b7cd70e,9f14cb05,70306bee), +S(ebedd345,ccdd0e04,4bd3d4d7,e1f1cb6b,ec06ad10,5ec2cec8,821580f5,d08a63d4,4278bfb0,88e4ff81,a3fe15bb,e01be36,40450f85,885da0ae,e15c6b9f,e78ad14a), +S(f4795df9,41b315e2,24a98dac,d9149ff2,8b9a7bf,e758a1f3,5cb6336e,8e1f9814,6982bc20,285c27d8,12c5c648,d0635c7,fdab85e6,fc6905d8,65da387e,596da791), +S(65a5964e,ea76e30c,74c472bd,3ddd5169,11dcfb3e,1f2d7ff2,9661e254,4a38ea30,a7c394af,80ebbd32,e442271f,b061bb42,a7b1758f,44d7d952,89152fa2,a88fe3f9), +S(f3d10725,da6b6c76,6da6fb5b,969ba7c6,3e33b4f2,d062a446,4ffb20bc,dea2d376,4d65ff69,64518942,bc3142a6,2148137,7bb609dd,6545bc26,9678ea19,62812ddb), +S(f5fe0f35,cde00589,301584a2,f4f5b1e9,3977082e,9c9bd50d,7c2c672b,ef05cc9f,1b49ac82,486e6344,dea32ca3,c96cd5c1,446ac2fb,2a658a42,50425f32,e8d72e94), +S(fce17cd4,d9519a53,f0a100f,ca54d1f9,fa87eded,98a12654,769c95be,151e33c3,40d342ef,83a4d715,bd13df0,f21197c6,e189681b,efa0d925,248733f,5ee07b8), +S(fd5d90d4,a97c1d1c,4fe18a10,6808f46,f6ea4422,c4408860,c2256b66,618af8e0,7ffc76c3,539bdec8,f59a9a7b,b36fd534,99306cf3,2dd1fe43,a2db5b59,af2f7e3b), +S(1c71f824,1b147abd,9e3c1ca3,fad5146b,e531dae7,c9c0d586,4f2d8bd8,7a6457aa,23e7e758,2cfc92dd,e498c0af,b942182a,92e02bb0,7e95bc1b,763d8030,9ddc9137), +S(dfb018bd,9bc352,f36889b8,2a46512,8850a158,872554cb,3a3dad28,a0496f20,2daa780b,d615d778,3de8f5e8,25cbd934,5c021df1,9ef80a6d,39ff87db,67a1e5ca), +S(bbd320ee,dacc1282,d3fd2109,c26f6bcd,46205ec1,d96b806,dca35dc1,4baa823d,ae7beed,3b5f72bc,ba66c794,89c05666,efa85966,14bacc45,9a99d882,8edbdbfe), +S(c9cd8f21,a068f78b,ce5129c0,9084be52,e48d688b,f474e690,b7720360,e362dfce,a10b9fe2,78c7814e,37851b5a,36aa4246,54c6279e,89df8fc2,ed189ad8,11518f22), +S(ddcf39db,aba52181,72c36a53,50883245,39ccddd8,46ec4258,e72dcd71,40041491,85cadc4a,a569265d,412c8fa9,4872bce1,51a750f7,b43385e2,2db405e3,54428a5b), +S(391562c3,f19436b1,a6e41d06,7435fbe8,27de66b5,555540c5,3ca7a0cc,c7876457,c3a5d917,5b56f67c,66ff269f,72c0a1ac,74503106,9059aaad,f3e66dad,45a80ee0), +S(63d4b224,7b2d441d,680a0437,604533cf,1dc48c9,bdcb9e10,e0249960,f966b2d4,e25cb896,ba165d4,46f73344,61e6856d,4c186736,402dc6a0,d866f97e,bd5cdfff), +S(5fe057df,5d2508c7,611dc21d,412739fe,3e7cf9e9,670812df,cbb00255,4d44cb22,33b88e83,9f22a7bd,17c149bb,65bd4a49,29b2a29e,b975776c,e82189de,80c7d45c), +S(5ac83bf,498f7eb0,79507ac,d5fbc587,f758afa9,b6a1ee51,4c857f8d,608a7b1f,1c866393,8a91904,f0530bdd,ba15390a,4c10fc4c,ef8a2f07,d799c89f,69a33097), +S(b0f9e4b9,b29790b6,33bcc04f,d860cb0f,823d8d1a,4cc1a1c1,413c1606,cc9a8e2c,b617d40e,7bc52192,be344f46,f9021c0f,ccaf33fd,3e8e3118,93df993a,20c2ee7b)}, +{S(eccf169c,9514a854,8f7e1131,a7438469,4df7dc2,fab96462,20e5799d,6d3f672d,452e53a2,aaf17617,37055bb7,24b64f4a,8fef29ed,f8571ff9,a3a6d2c4,6acdb91e), +S(a77bcddd,a0fecd39,a99c6387,57bda1bf,30257248,6a3fa08a,e2d6ff17,e6e4b6ea,debf4c03,b4bb5c7a,8a386a7b,1e459426,6c78eec6,55f01cd9,f137ff18,c5fbdb1d), +S(a77b91ec,6db6a66e,a48de424,65079a2e,ce220fba,da221601,840546ec,2295c2a2,3c721fea,81f5fe05,163562a9,849bdb15,90bc818e,86674ea2,57fe8d0f,4050086c), +S(99a28a1a,3bf2af79,ef2bf134,d31880a,71c2aad3,824fb7df,23fc4fb7,d54b2910,620e2918,df14e3c5,dbfceada,1905941d,32d77592,89ec607a,f9851a6c,5592803d), +S(7eb52616,71402db8,905c7097,2af96b72,2bd77d,f124bbcc,5418f217,f6d8c7be,ce1e663c,8276bf42,99919592,11feb13b,66aefa37,5d6dca15,8b7b66a3,ffc6d7ec), +S(c88b1815,f183e6ea,3ce8469f,ada5b88b,805288d6,828473ba,368d52f,2145e7a4,55e78f2d,3784952e,cb47f6b0,113eb471,8cc58225,85f9d1e,2198dc60,af3f90c9), +S(dd893c5e,a2e4e70a,fcc161ac,47232d3b,77f16c95,54c98770,9a7a6f64,c0cf7ab1,a1a58b41,c7d4d0c5,6d6c908b,32d97467,b8b6ed20,73e6a677,54935665,6a92a480), +S(591b8422,eddbfaf9,d2c27c28,dd84dd30,712a15a0,deb752dd,dee682cc,34722ea7,877b0c99,6a248082,fd442509,b0ce4cc1,b181d4f8,8ff755dd,5f0dba66,ebf95d1f), +S(75f9e3a1,ffdd902,be5d1d2b,3ed18b37,62e42e95,8b024ce8,f892ee13,ab35c674,57fabc84,7c68cfdf,272effee,e7a6ee2c,5fecdeb4,8e4877c,ccf2a8de,2e2264cc), +S(c8a53d5,e1895cdf,db61c1a2,395a866b,ad803773,23ea43ca,775408f7,a4141cc6,ddeff9c9,97a11e4d,d0afab30,f63229f8,1b52ac,c25749ae,2749ddb4,2b201196), +S(8827d23,668f3006,b966cb19,698a066d,aea556b7,4108739d,d6414d8,e8dd78c9,3d009ac7,2baabb53,2e3658e1,8941d4b1,efe512b8,fd7696d5,14b12216,215f10e0), +S(dde6b713,5cf165c6,53c7f5db,542501bc,b0a41e3c,c6779aa6,194ac1d1,8a830b01,25c04b4a,937e16b6,e72616e2,d64a413b,6a7c29ac,71dfcbf6,826261dc,2507c16), +S(8cf6210c,5426b3a5,ed594699,da6cb8b9,8069a3d7,b926cae9,fedb2e96,25d20010,78017fc1,7915e3c8,62557896,acd002fc,7263bd7f,aed38fca,d63ccaa3,57391f30), +S(35772904,91661db6,340e7d1c,a98db8bc,2f50f557,283ccf11,8e446f71,925ade9b,fd8a4a56,b82dff95,a59e29ea,bd5d8e8b,a876bf95,4abf0537,60832d1b,d7edc31c), +S(60e4201c,4dbd9c99,c5eda030,f041f51d,f648f77b,13ec2072,4d89b6be,f249d793,ebd96057,d60b7cae,71349c51,1a3ca99e,847419ff,cdcaa0c8,54d75d40,8263d81b), +S(f39d686,b17ad518,3a7d300f,1bfd015c,57541f08,a96b5943,43d2ef82,bf20bb6e,f1298c9c,633a958a,a0d12b87,8c95836d,f9f93b5f,5e3a6bbd,93a75ba1,1b96d4d0), +S(37ea7dc7,2a3a0b4e,72412814,bc1e1233,17ea3e1c,c4ede35f,cab5d31c,93cc330b,aebaca93,8b14b315,708360e,5662e6a1,af25069b,cc07f581,225dd131,c656c607), +S(ff1f61ed,ba3cfc6f,2fdf3043,37205bab,301c965b,501e4f2f,fcacde00,dd127b25,fb1edca5,90e00f87,eeb56ef9,94e9bb12,b64ad1ea,f5ef0afe,6f0125b4,e100a483), +S(3376e0a5,b93f15b6,c46b92ea,e313ea2d,c5d0b961,a2623487,8919cf5e,25e9ae38,a4cfc1be,fd24647a,20ae014b,2041ab3f,6cb7585d,48a607f8,299e0c10,96bcfdf1), +S(be575f99,842187b,30bcb312,987ea218,3d613442,8878804,b5e7d920,12e58d9c,154e02b0,b573c81b,d2079a4f,4a6efe5f,5f37502b,33225064,4eb38b2c,3f0a1767), +S(5a215836,f1f2997d,9b09d4d0,6473c55c,46cd3006,70d85d6f,6b5531aa,c8da043f,ef5fba1e,b6e1deaf,bd83e480,fcd4984d,cf60f91f,4799e8b4,3f4edd15,f94b6d33), +S(d73fee2,16a503e3,a7d6b0a2,675adb1d,197c3fae,4d43835c,b6b043f5,d44909f5,6f2cc9ee,fbc36b4d,a5b3e704,c13daee9,cb81ce9d,470f1290,8b32f047,ae231053), +S(26fda2e4,d07ec613,ded58e14,ee84e421,ea58e5b9,5beed698,d847f6a6,db185f6,683c0002,bcd6d8b7,1d06e592,db4b961d,f2518fbb,47cb4ad9,96020d84,ed8a5909), +S(cd3d4e87,e433f2b5,5dc55c6,a3f280fc,57f899e1,f8f0777f,32705f3,eb24551c,2315d85b,7521e4e3,8e69f29b,a49a3203,abc7f280,ad49365a,4c78f21c,3ee12542), +S(652476ac,2c9b871c,e108fa13,6a739766,879a76ec,60d787ac,a1b7447a,67f8afd8,b66bf6db,cd3a1393,f70ac7b6,d53069d2,5f084dd7,f05c97a8,76f7f646,c7b67fa8), +S(61ab4f97,61c96446,ea7a75de,7ed36224,7b5ce8b9,e7b442c3,432f9fa0,ec74355e,f391652b,17a910f,6d476c29,89e854f7,d31a5f31,fead5fbd,5013ea56,e44985db), +S(36e4bb36,e62f78a6,a6155351,36a73637,13fe8be8,1c8c3460,a94bb642,4f7c80de,12b38983,c10079f9,b0016df7,fba0685d,5eb87518,234c65c0,7dff006,dbb6a563), +S(f5e4cb89,101e90d4,b2f50097,aa0b22fa,df076932,f4045e9b,7a9ce8d6,ba178780,c12ec4ae,56db7971,3a1bb0f,2559e3a1,de3f8200,650c809,74101940,181eb52b), +S(1138ad12,333790f9,20e979f6,a6471274,2a9bb567,2356e3c,80ffff89,a9de533,4caada48,a78ae26b,790f23c1,606a5820,98642f4,bab5bfff,95748f6a,2ccd6bc), +S(e0346d21,121ff741,fe4eaa23,938a4347,a71df442,9e55359e,aa20d691,c9f40840,c1197c8e,c36676a9,28a92b56,811845d5,d9632c65,9142cc12,3c65e54f,c282dbd), +S(d42011d6,1061388,fec6b7f,3f332b20,24ab318f,2a9ba7ed,23731207,3e32478e,451a2b16,5c82b1f3,e4d2a0a0,bb407b84,904db4d0,caaf733c,e31fa97d,2fb1735b), +S(63964eee,619074e0,780140fe,2e90836,e72328d2,448386d4,59c5be23,187f5048,c49304c5,947630be,5c60064e,3cb40436,c2a7f46c,b221937b,c7c5d7b1,76cf5e37)}, +{S(8f741868,43906722,ab9f5c6e,c796573b,622fa2ae,6d985bfe,ea4d51a1,8f141792,61ecd858,d6992c4a,bdc22472,fb8fd242,929dc5b5,36ea8e35,d1c8c513,bcb9e31e), +S(f2dd67e5,6f75c397,76b29366,149ba4ff,69385651,53afb385,3853acb7,9fc2bd59,3a24641c,d48ca39f,fe992bf1,50291604,79066af4,a0cf364c,9e52a9f,9b51eb66), +S(9386aa5e,c3452728,a8f65141,e2f43a14,c250173,9349c96d,e1968a4e,48cd30,a3a38a85,4f68048,d8f81002,3eef9966,780262cb,aacbe859,a8fc66fc,27c37f32), +S(6c9901ea,920c0f4c,ce51fde7,ab283f98,eebc30dd,c76a3219,1df4c4c9,db467aac,6773f8ae,e601201a,84dd4485,fa560e22,81d5eabb,25a3b3d8,525f4a56,65f79d05), +S(ed1eafec,876154e0,58597caa,8250b0ef,7262ff70,b719ec9b,63c0b2ff,9d167fe3,73505073,2b563f93,89078cc3,93ff9837,227ab8a6,c7d789c,6d2bc835,2018f77b), +S(515806b5,13d4d4bf,83533b56,3b39bf9c,4e808426,f2e4cf16,562e759,cf2d56ab,83c2fb,673a08a6,b8a86b1f,e1ba23d9,3347903a,d6855059,130d8d39,737ddead), +S(30a726d4,d8db1cfa,d59331a0,8f4b5376,36848547,914dcd75,37a80e40,109b8e35,8f628b92,6a11ddc0,dfb1cebb,934aeaa4,3840d442,a61145d1,803f771f,7bf65d7d), +S(116867a8,d72fb00e,80a6f267,e8163770,34affeff,36d667cd,38219f0a,e3c9038d,270f15be,b2a3d50a,4088720a,e9a2c3dd,df00817e,31e1a5b1,d850fe23,dfe51657), +S(abea2899,e4575c6a,201c96fb,a60a24ee,1f1fe0c9,b718b54d,18981938,4f33a1f4,d43d54e3,9e8d433a,ce66ad94,e52662fa,8013e778,f8bc2e3f,31938a6d,5681c660), +S(1fa796d,9f658aa8,6ccd0fb4,6a735651,102e3181,302e371b,8c965dd4,5f078b30,69815d18,43c3b4d9,f7fa4af7,3d2e5dda,390e5372,28608912,79826a53,a437031b), +S(f5022faa,c8caa29f,304ab6c3,d00931c5,e09085e2,73beab04,c1d18f87,1c0fde73,c6abd143,73213fe8,ffa5ec64,8a22dddd,fdf2cb25,e32afd58,4f92dca7,838e8249), +S(8190b10b,97bc72b9,301b1dc,cc60e69e,460e389e,ce7d5d11,4e2284de,853ea02f,f1ffb850,dbff0f06,561b75f6,5d2ae823,cb13881f,d1150eff,274db4cf,112d2253), +S(ea230fbe,c58d7e2f,1a3cea60,f9018562,d2fefb49,8efa312f,4beafcd3,139da094,6045d69d,b27bee6f,3357180c,e92d3866,b480faf4,2debc033,cfa118fb,b89c3bd2), +S(333d063,ccef6aa1,f78c81b3,4a84975c,82bc2cc2,bb897608,f0bed49d,cd08829,90ad105e,f72b7e4f,a927240d,9c69729b,a0aae3a2,3a45342,3be2c385,488840a1), +S(4d95cb48,58d808a3,be82f42c,da4f64a8,c64ae176,3b50257f,2e4ae655,fcc4802,5f6efffc,99bdde54,6d8ffde5,e9a551d0,121a39c3,86db540d,1caf74b4,894c5559), +S(b87b5eca,6e0111bc,5b756816,fa82acf9,77f81376,af796cdd,1e8fcb09,4d363d1,442fa845,9c2a7799,2c09015a,db80f26a,28428851,62432660,56026009,5f2f9d8), +S(34baf43a,a82cce1b,19945590,ef3cb582,2ab03142,6538ea5f,74571582,ee14cf00,9a76705b,c0141e29,75d11543,215377b5,3c051c31,156697cb,e8f56721,da386e2b), +S(f07c5d98,a2579c17,53b3fb58,22a139a1,53e7deeb,ae9304b,114bb188,d61cdd0a,ec18ce0c,1e51b8bc,e12f3d85,23739f8,bc25708f,32deb81d,a780cc4a,1010692d), +S(9a146c80,5ee261ad,3e708885,aa41041a,53bd3758,b3d1ab7a,1a44aa7e,29acca7,fc553e71,4ad8a192,90f94ed7,7c171f9d,9ad9a047,6791f045,4a3ab7d3,f8834f02), +S(c8088409,650feb74,9f9fe21,61772279,128db1d7,58610a9a,8b9fc4b,ef9683b7,692a6be3,132a08d3,82295ee7,1c469465,ae7d63d6,c20c7357,36935003,28799639), +S(53bdc8b2,3edd83b6,b149b79,c88130c6,b207f999,e7045285,7e828f81,b325b9d8,a9a039d1,79486167,8fda727b,1706e9ec,7ec3eba3,26e6a4a7,e27db3f0,8a6ee238), +S(fd08fb47,4af98207,3d8b4ef6,d39012f4,78225f1a,bde3c841,6fe3881b,4fd276c6,d38b53a9,100da1fd,1d2a987e,6907370e,7bca492e,98a22e5d,74a10c9b,93a197e1), +S(5c42ad93,2306363e,a0edf86d,31d14b04,c3f7bc09,c9fe1326,d1ad085d,c84fb7ca,1bdbf812,e9ad6486,ff572d4e,de5be4c9,59de7be3,f21e0dd8,76534091,f13ca3d3), +S(66257876,115e7eef,fc0e6132,9f177d3a,437c81c4,1150f86b,45904f86,30bae971,df830e1e,33aeded,721a0a6a,62a3a402,1d2b7ab7,438b7b3c,d834d67,3a857aed), +S(4feea8d8,2cc6601,c847deff,35581c1d,bf1f4070,402bb948,ce9a41ee,16661627,c09a7686,ad6bcec4,ea9ab0f7,8316adc0,7c7a2899,9332cee7,5d70c50d,249a0007), +S(2d3bb180,73f5345e,cff0c901,9a6f2fb4,e0a237a3,9315fc11,fd53c7d5,aec43670,58a9459c,2710ac75,ff2510ce,4c9c5fb8,b4f739c9,c6611494,daf896db,e43b080), +S(bd539f5f,47b25116,7159153,f402e0af,8650c17a,de7c5dde,2d9d9cc2,d0a3103d,407cab4f,ca581f10,eb386e20,9158541b,8649951e,b2f5e454,2a7032b6,53f0caa), +S(c7a72935,87ba5114,744c3d0,9030be19,9ccea57c,7f80be87,bfb5b79a,8f8e200,7c2a98f8,b4526422,b211bea0,875a81f1,d379012,486db005,e31b9682,404e14a3), +S(cdf20316,f4b63ca4,c472e1cd,b3a938be,291d98b9,3ad8f3f2,4f3e1a4d,f1a6cc80,ab993e8a,68988d4d,2749760f,241399c8,136ee9d2,3d4ae7d1,e6d26df4,6056587b), +S(1d341e6,2eca1f48,165bb2f3,86207da1,f2c7fc86,dff7a75,cb63976e,f21bb074,923b53ed,fe2f5bb5,56aa7cae,2a08ff86,160e3344,c4adc09a,e7aeadfd,f31e2b9c), +S(8704f69d,9d335975,f0e3bb83,5aa3024a,60103d89,e5578253,fbb3d537,1983ce4e,94f4adfa,31dbd13d,95c738b2,8a569453,cba45efd,1cfd20b6,78f6a724,e9a8d025), +S(7175407f,1b58f010,d4cda4c6,2511e59d,b7edcf28,f5476d99,5cf39944,b26b64f1,bc4baabc,bb1c2aaf,c92cbfe,ecb33791,4fe01748,8bb8e2d5,bd918104,4dbdc75a)}, +{S(a16a4734,9afd167f,d5e79d24,9784d87,5121fa24,2c3a54a,88f9b176,72669aa1,4df3fb81,7021efdc,e5296735,3a177b5c,51cc7762,4755ba28,1084db5c,4809e02c), +S(91d1abe3,8d3f9671,54337e03,d27fa6f8,c3007f32,323d15c8,31306b3a,30900328,b1b8c71d,b388009b,98000f9f,291b66e3,f890d42c,a5812f34,5c070f6,e73b89f6), +S(61b64b1c,f2a0e720,e9bb4853,537b9f38,66baff87,388df7f9,f14c06c7,12080b96,44444011,b6ddadc5,7ee00eed,b6af3772,e4116711,c3853f13,7f9c7b00,2bf2a1dc), +S(3b96b2ee,d9cf1ed6,3aaed8e9,aca3a464,d6a6fbf5,e6fd48f0,5aacc318,dfdbc87,51c41c26,506cac9e,bd0c5dbc,8ce8788a,3469e42d,de794707,9e0cd0d9,826e9c58), +S(7bbd147f,77b293ac,ff797b9,a52778de,5874b754,c08df397,72ed8ef7,53242efc,3e843df6,75abef2b,e4d32c83,205322cb,f53bde0,2563eb8e,b5dfbe6f,27d4cada), +S(becb7fc5,de84f994,9f97e55d,bdb6981e,f38c0c45,1e0e454,519c9411,5bae3d7,754145ec,ee6f9c7c,f91963fb,5b0a683a,ef24313f,1125570c,c9b9c7d2,afab99a8), +S(87936626,aa88346d,6d4330d9,3a188ed6,992bdbb8,387b395e,d21dab93,63d833eb,a28c868a,18dbe0e7,12ca5237,53f6a50b,9313e687,85f3b31f,ec778fac,87aa9327), +S(e79d4b2d,e33de1e2,e7eeeb44,d197aec1,f5883ad6,1394dd79,de274ef9,76e3b022,9c73ade7,7c661527,ec2ec6cd,b370c130,380bdd9a,4bcb668a,86e8259a,ca85f293), +S(863f0d65,34de1222,237a07bd,ebb066b5,2c1cdd83,d7a6d3df,278e57c8,bb59b8c7,c546940b,99d04ae2,5cf7c881,28a985cc,9b6223a6,ffc06fe9,8a3e0f68,439b9db6), +S(71e9b0d1,3972d9e0,2225bbda,5a1024e9,c373eeb,f6514eb1,c113ef88,dffdc3a,4436c52e,c58a34c,562638c7,8d76e3fa,29e3586d,fa667577,2fe0b932,c4a1ade2), +S(ef4a500d,c9369125,78fcfcbe,3c313bbf,f0323caa,75750b6b,a317e1e3,dd8054e3,e807e9cf,7911c919,fef82e40,a3ae1b9b,ed8ded38,e74126ed,863199de,c031f2a1), +S(806dd4e0,fbf72904,c7b0080b,4e7526bc,c71fc52d,f143da80,e571041,dd964915,2f4e2e67,3348c32d,6bcc0741,2e76f4fe,944f96bb,d73382c8,c6880cf6,629eac8a), +S(9ea889e8,acf0441d,6e299687,c532ea8f,8b9453ed,5fea0d47,f735056b,1eb3bfa1,e43f79a8,4d302f3c,88698896,5fa7b8f1,a92c620,dfcb3462,c4befe3f,4afbff5e), +S(9a990a22,1d27d8f3,40e79489,58cff3ca,2720dd3d,ac71688d,9c3c9e2f,afeee215,4957ac76,db370918,7992b0b,63370656,7e0f4a0a,9e5f1d9a,be8f7d5e,8a950eef), +S(d3291003,98ad3d92,1d6cbc6e,b37ac3f3,9360cea6,23edd794,64d34a51,fa7adc60,657c110,5bd8df6b,fe52addb,2fdfc41b,810a1ff7,8662021c,7c220b0d,b3509d14), +S(65eac576,e149d97,3cbd772c,60570870,e437e92c,2e5138ac,9c0534df,b7a45582,ebecb6a,edb87cc1,417e066e,fef8e52e,c61eb00c,dfd98205,91d63c08,9dfd5347), +S(b6976b99,c2515be2,2bc901fd,8671255b,f8fd76ca,1f3474cd,5eebe39e,98f6f14f,84ab17d,da67b61c,fd01881e,b1087e69,845aecc9,ce1535fe,1c7245fa,8df98181), +S(c7f5967f,f9910e10,54c93e1e,d0290102,9bf31787,15f53758,f5c53cd3,c79a52bf,bfb01210,5c1ec69c,847ceffc,d1105ac0,528129fe,3b4d3086,2b6e9562,836f5eb2), +S(ffa0da7a,e8984e4,d02a0fe3,acfb4e81,2a63d6b1,682dcd78,fd2635bf,88cfdf1d,49459ee5,3fad1097,2da786fe,45a2d201,e4a52260,7779b1d4,23defafe,29e70098), +S(5a53d683,3bc1740f,d02f278b,2ac15a87,f137f2,c798f157,725a4aac,63f1798d,ac5e7ec5,86d5960f,e25f9e25,7cf9ee05,110d9595,e440d032,c416d444,6242d10), +S(70f67487,9b030a4d,9ccc0bf2,90d5b78,c455f8bd,a1fa2b52,efaf0200,6b70a6cb,10f5b1c5,dc46c0c0,68757804,93805aa7,5a259dbd,95b4bd14,d031daef,a81bf7bb), +S(a4baf0d7,d3a53c29,e78ff81a,52d634a,e009391b,30a9aa91,df8f7bb6,13e3c16,c9f9d001,7f388f09,b6802c45,e1fa036e,99443467,c3847937,8b384a9,dada35cc), +S(351b8e4a,dd336c28,5d140c57,9f2b089d,3c656a05,b1ed6,4cdbaf7e,e5bc671b,b996e61c,cb14553c,b7b79803,c82332b6,704ce97,fb4e19a5,1f70b13d,f8e2732f), +S(d248350,92898c0,5dbb4465,18695efa,e59ac007,d58b5df5,bb3b7038,82f18e61,23455e7f,5104051a,44600be5,2e242a90,95213d25,b4fd65a7,62c3f9fc,9234c2a5), +S(d3fc6d75,10cb0b20,77b52b00,93e84d47,54dd1a28,4f3928f2,a9e3cc02,f1869588,26e86b02,c16171d4,4238aecf,666146f4,9386e0eb,52dfed87,7ac0b409,51ced10b), +S(1c611335,3d115906,182b0e4a,7eb3d39f,552c49f0,c5928aa1,15ae00dd,c23a3b70,1c3e3c4e,ed65ce47,ea82a33f,df8fa6b5,532977d9,53aed38a,f0f4dab3,98477c6b), +S(6487c5c6,abb6e673,821c4b0,2c485f83,3e149af1,83b3f025,71a81fbe,660e98e3,63c4f6b4,7eb37ed6,7668b41,1e83d9c8,9ea323f3,2d9e8918,20b65276,a8a7b7d6), +S(1b0baf63,6daaf2c4,28a62bce,bdd41de2,a4d7cf69,93f0b931,222a40cb,9f5f9a2f,af9a62cd,f91e2c6b,47f308af,e2de8f16,def4972f,24bf4c5b,2b1f92ac,f63a21d2), +S(95bbd974,78e1b8a4,1622e460,8aa82fe9,e77d43e7,492a0d21,1146d987,f9b8f255,412bc52e,d61c3880,210d3df7,f0d2f27,d458d51,388803e,fef1c016,d7c9e7f6), +S(a3466715,5b6ea598,2d3945fb,743a1510,c671b96f,a3494a57,e0349010,55ae087,de35a05a,1a943a42,7210165e,55d5cfae,3ac15490,dc6b0f43,34c0c99b,dd778608), +S(2ed76c11,52ac3600,7aa17c85,a5f902f1,7c845a05,a4e0aaa0,7b05e836,cbcad59,9c60b2bf,bc47a0dd,d3259151,37e89812,a08d39fe,cf5806be,eb538575,3b159531), +S(20e6e2e7,96946bb6,30c7071e,f1b92ea3,d53d280e,e450111,5f5da36f,840dd273,2c528501,b0eaa61b,b5f45e52,6878b9aa,7ee13686,c25796c3,3f8302e9,44b9469c)}, +{S(f040a2fa,b839c753,4e216425,6c2e8dd8,57c52dac,e75cab3d,512a7b1d,562075d2,9e211cf4,bab24e0e,f745e2a0,9b59565b,be7b2449,8123f6b2,ba383b25,29554b36), +S(c66813b,904831cc,12f89e3f,bde93eb3,11ade6dd,f6cfdf72,21cc61a2,ff46bf26,3b60c8c9,9da35a58,7b9650af,f85ca785,ece41146,e7ed8d6d,ef8d26d1,f3d055ce), +S(cd38ece8,7c7a9cbb,e23b58ef,59925633,734de285,f93b3ac4,eb01e03a,adab904b,a5f48fcd,afe414f4,1a44917a,5dcb80b9,30373af9,70e9f22d,c1af80f,a8b06320), +S(72d6f7db,199564a2,6e823a49,eb0171cb,ebb76a2a,add56c7c,6d3102a,9c3ee18c,bd2039ec,c390839f,e2d4451c,9437fef6,3e98dc62,3ab0eea4,c56376f2,e270f626), +S(2ea6c313,1e101867,2454e15c,d34d5fad,13829d5,4ca86062,f074e512,a274167e,67e3d34a,56f12e1b,43687f51,c2d56395,14355d7d,9cc52726,22f62ab8,91c8d5de), +S(d66bdd78,8b20da57,b2485804,a2f6e2ef,78c7ca87,ae1c5c66,fc533533,5b624162,1a8688a1,300e6d39,e130037d,3f074ccc,57addd1b,88977e64,2ab296ac,d6e054c9), +S(6d6458d5,d1683d85,8f9e40,15e5a94a,73868bda,54f6139c,446b5283,6d211542,e44c7ca8,33761e13,ca5458ff,dc682f22,3819411c,a3c5feb6,24f06412,471b9f5a), +S(49f8063,b3d98f6,f159f2e6,65b0e07,8ef8c7df,44da06c3,55b592ac,13402b9d,b0b2d838,4b24ab11,de895013,e897e825,45c3e8dd,6cdb0990,555cd871,5841f8cd), +S(8b2fb6bd,e60449da,2684f8e3,6267fff7,254051ac,faea37cb,102c9bfa,91abb2ca,c82cb9ab,c33c1817,10d3fb19,60f2850b,5072eb47,404266f7,c7964fb,f98027d3), +S(cf90331d,73644476,47c8f86e,eaa6e67b,f3fb4b3c,4c895b82,30ab2f38,80df1e42,9c493d94,3471efd5,ea90f723,db576a35,8cd1ee6,1a119b56,6c65b16,112eb2b4), +S(e70667cd,8d2759e,43f99417,ecc505a7,953d80dd,e7ce2cba,3c8c948b,d43a912a,92a534b3,51449a66,82395a3,b75877ae,851923a2,e791acc3,7293d728,777a2247), +S(4cc07d11,4a715e9f,4b4d0811,f0337c7e,f4bdff74,2fb008d2,1ce8a9ea,50520d47,478b279,613d92d3,dd24ae31,2658eda8,28a7d628,f0346e04,5d5d9dff,7178f093), +S(2a1cee60,4cdd3b2c,1f859bfa,af63d7e3,9aaad910,92c2a38f,a9362798,9753c30d,325c248e,d409e8f3,b96dccab,6fdb62a6,83b7eaf3,36d2864e,b821663d,ed31a6f5), +S(7c18d0bb,9a01969d,302616cb,bad8722e,d00103fa,9985a50b,765f0e2b,9a2ea14c,f6365a6c,b06e4749,c48c212c,63fff571,8f46e0cf,6fdc8c42,34d4db64,ceb72080), +S(a706754,65cde407,e853e882,8fb7a2fe,98638d7e,64b8df0f,b0a7a0b4,e629d0ee,fd694b2c,1354a5e9,415926d0,1590eaac,dbd1b36b,5ecc46b5,72467c3f,e2cc5393), +S(7ff57a63,36ec73da,cc1dc527,928cc6ff,4ec063b1,56b36292,23b8bbb0,a8ba2c7d,4d6dfc43,da0fe33a,1e75dbf5,5e5d669e,be6471d,eb8a4102,6db1a41e,9d5da637), +S(d4b1f7bc,87558c27,7e0fdf91,22bfe488,b3182555,599dd384,5cc039b5,93218e9f,992f79dd,c8f46682,5c44a54d,626b352f,7f59139b,d545f78b,44bd0b10,55c3c1fa), +S(897773f,a9de63a7,46ebf58e,248d0c21,10f90230,a792f0b6,ea5a25a0,9d1940d2,b7c7dd27,d561dde6,ca7588b,8e3a09c7,16297ba3,9d501744,f9639a25,b16b4f64), +S(2f9cb312,b071a600,e5d24cfc,79b0fdbb,f6da1527,10ec395d,53078453,1a3b07e7,49260f95,757b9b66,feeb5c20,16aa051,b444bfc8,836fd8a2,ab913e98,731fa97e), +S(5c53b27c,4c0ae241,8569c806,8dd43a5c,6fa23ac6,74d001b4,eee6a748,d86c9e6d,4e0e720a,f430972f,b0ab89b8,79a56eb4,f0af5161,cae83ca1,964a8099,f9d497c1), +S(2671ef50,5a321387,9560f0d9,e8588707,1c2b87b5,d06bb9d,dec3d179,6275b098,750ea18b,dbdcbd58,be994eb5,cb3539f5,8c3dc630,7d50bbf1,f69050d6,235826be), +S(59baa5ce,9d6e707b,b0738f4f,d37c9890,801ed796,a82afb2a,ecd2c5ba,195be65b,e6b66356,20a8a106,b58dc202,10cccdd1,e0e8c579,c92f3fbf,8b335765,b30d8291), +S(bb422d0,88abedca,e4686479,295aa1a1,77d7e68b,293bcd31,4097ddc1,af764b90,a96d33f6,46d4861d,a471f853,e0c6ae32,b1eea619,a7441504,a773f5e6,fc548805), +S(8d7df8a5,f08ba2b0,923662fc,e594f111,5295cf6e,c5aec9ca,df0f7236,fe51b362,26452215,7d8572d0,f057ec9,6f572f11,ebad3fd0,56032240,26b54df2,991f9046), +S(9e2b1637,352d8988,1e76fdec,c2dc8533,6a71b18b,3c98e59d,397602f5,8b9087d7,b997404f,1c0b1e64,90cff078,fdc47c42,aedf245a,e69d844c,18a146fa,6d8c3d13), +S(972c7bc4,6362bca6,b58f1d0b,87c0b8dc,fe91a217,7f0cd7af,404f6f06,47e09358,cfda778,a59d944b,4ec08bcb,3aabd70a,cd6f29c5,204c9161,fe2e5bd5,71d03f6c), +S(f7dd32ed,89ceaace,52e7f26b,202ea6a5,c7e8ff42,6c7ebc16,12106f7c,6fe51a54,7349c17d,d8ea6ad1,cb346e3d,26989950,3de00c11,4205b3b5,50d27ff7,67efe75d), +S(c9f96f88,3e34aed,97351928,fa77b07a,f4b01bb4,e4515f0,59745ee5,decc9fbc,6fd62453,dd6c9dab,10fb7d79,c15b4822,178eba31,258800e4,519e627e,91ef20c9), +S(9c28cc93,809b35b3,96a4c9cd,d6976391,17402ffb,5588cd76,7c41a92f,e971a9a,ca3b2634,28513516,86a661c4,747aece4,c8130d93,ff4108a6,3365e725,2bbb80ce), +S(263a3fca,437c4dbf,48ca36e6,aa892d61,abf58f6a,d3c82b1f,fe945dc,c45a15f8,604c5bec,69e0f1a7,3e8f8a80,4f762cda,96ba2198,35268887,910c8df0,e83d3044), +S(7fe42dfb,b3466ed4,d7cb8242,5e66b5e1,14a70516,b118911f,9170656a,3dbb04fa,d11385f4,b0a3a0bc,cf09374f,868cb30f,55175d77,2d3e463a,a298b6ed,1e6f6fa6), +S(53f2432b,a8171714,3fa9df3d,ff41ced2,4a29b314,bc5a8c96,f5f6400a,d7c0979,42ad1004,3e0f8648,332b1c1f,6ee4f821,b42a5b0a,361747ba,60816f2,ac84c58d)}, +{S(b8b52efd,bc367a5c,a1534bb2,f339a048,50fc4941,1668780,dcdb8b51,2daa7526,306a2236,856070ea,1e0fd846,cd571889,e20968cf,cd490bc9,facfc4e5,a5970b2a), +S(27e226b6,ed59c89,5bd20232,bc677c35,495d9601,5f37493f,5075718c,2017e42c,a130a5c8,54ed8ab3,ed657e0f,ee4a04cc,1b59a291,6e96465a,74b36144,7cc621f0), +S(1733f1c0,da38fa79,a7b37988,1822ef51,2392d8cb,59d1ad1e,afaf535a,e151fb64,a93ddb00,af779565,eeb230af,815f9434,958ad39b,387d9069,a03cfcb,8563a920), +S(e3f4b777,d06c8839,c63dfb41,73281787,72debac0,ed45b991,724c19bd,85ab3c58,2d6a84ea,745decd9,e6444b7a,dbb59fa3,21957b7c,3f8141e6,fd633d3f,7539dcdb), +S(a2b42fb8,9ac10df9,ebe804b6,c105e855,25cb05eb,7407d383,3031e216,64491ff5,d0973dbd,346a87b4,f4ddfddd,12be3131,e6c6a397,8e17be2c,bda23683,62f80765), +S(66d441a2,6b28378b,cf23d33b,ffac1163,7c23bbb7,7ad352e7,ff5cc09f,41bf6e91,982aa46e,5fa0b19a,28ecfdee,539c0ec,b5f06e2a,217f7687,6c3cbf1d,e92a6068), +S(3721fccc,20338f8a,779aceb8,eae3fc7f,bb0e4040,1de2c8e5,27941ad7,f789d0f7,d9516c54,8f457b6e,d44f6bbb,23f36c7c,e6fdc548,60e5042a,b3dd4f67,ad5ae3ea), +S(959e980,4618bed2,73b5cc48,5565df27,b8e09c9,a128a9e5,ea92e347,66e02015,cee3a227,1bddee01,3582d65d,c3e26c8a,f80a4601,abcff432,b1737127,91ca15a4), +S(f2e81d16,c19466a6,1b56931,935d03e2,aad6b8d0,7f193d97,bacdc29e,13cdcf38,afb8e973,8d563dc4,1e7688f6,c6b43b71,f366b576,9479f093,88fd09e5,faa1063f), +S(98305a48,800f92e0,bd815192,7b8658fc,60a97c64,c9f97383,68812614,3563910e,d32db8e2,6699b969,5b644c08,39f2399,f8ef45ad,a0d857c5,2d0c7c3f,96a62993), +S(8dbd4fba,113c50ba,ff3f251c,96aba9c0,440d8e69,8a1e4ec1,84fba97a,e497c443,f642b1d9,b012eef2,40c6ad38,fe441d11,cfb42ec2,a3c15540,45e64c76,c15be491), +S(deea5bb6,c7eac0a2,93e90817,836a3e55,2a7f1354,395296c8,97964c2a,4527a727,4cbe143c,c9fde617,c6142335,4323b9d8,bba13dd7,fbd46db5,cbf4ce2a,11c9c00), +S(349f46a5,8621034,9f207a07,4558787d,336cb0cf,a56c1e67,8dd3b04a,4d717f4b,a6479d8,f7f017a6,32c369c0,8679fecd,985b3c16,ff444ba0,3fe43575,8b96455a), +S(a6d818c9,dc182fd7,81343bc,b737811f,611c8499,e44a6cdb,33a36beb,7e44b545,1a8ee36e,d6e9b191,b9cbf840,3924e6b8,ac3c3f8a,cbc9a0b5,ff965d6c,734d741d), +S(f9cad333,7b82ea41,b00f3ef1,bba37b8b,fcb24e8a,175fe380,8e399b67,d21837e7,cb206854,4e7f2cda,28c035f1,b8b50009,319797da,bb498b99,d31e24e2,4fa27ca9), +S(25042b59,f9b29a9c,83d04515,c78f1c25,5b72f97f,7b387113,e88c36b9,9da3ebdc,d966ba9e,a7eb9734,e1481cb7,2df63252,7492e1c4,43f1fc9,c0efe0af,442b5a13), +S(e19c4319,b5c9a01e,b588c629,8a7c6b76,1b80bf4b,e39424e0,666ddc45,fd57e0f6,1b0a2c30,4a1bb1b1,9dd0b50d,29df625,bf958a73,46cc6b1d,81a213a3,b6636285), +S(59c26fc1,6d151c0c,7da0edf6,c474463c,587c45cb,7e407589,d15aad89,de223fa0,f7b227b5,4855c1c4,1e576431,8a7106eb,ea214686,ef815b42,db8c18ae,d5c940a5), +S(d967d546,e07ac1c2,31fd50df,a1d25a51,60594d88,3e816f6a,bd62c15c,446aeff6,8eee6c03,6e22a014,5d9cf3af,9b44e005,cd1d36ce,d7c420f5,e2db918b,e4fbf83a), +S(424b149d,9104254e,3f5772b3,7d973cf2,a46bd110,89d8f850,7666f04d,382c972b,7272ad07,54c18fbd,66e2abb3,952c526,d8113d5b,166283a3,9ac8ecb6,2b7a3e46), +S(40b4b2ac,bd299270,e64bc470,8607c586,3bb50913,45e573f3,a5e2461b,47dbc053,d094311e,fd81bb1f,4622d17e,68044107,a2a8ed54,3cd5ff8c,b531b28b,9b8ec99e), +S(79e79ded,6bc0d851,fa769b5e,8d65857c,f3c1c18e,6c990cb6,116fc45b,63e9f924,4fa89e89,ae4214fc,ba2aecdb,41984788,8154eaa6,bcbbe29f,f04a6262,7299f469), +S(a11ad5ea,59c644b2,8dd7402a,5f96a970,68d96e2e,eb77d59a,fe0c2fc,cc6b252f,38e379d5,150109df,36ed7ad3,a2daa41b,4fb9c731,718cf5e3,8f8f8cf7,d1f3d770), +S(b3002b00,ec5be154,cd8e5226,4b97f5c9,f444b305,8f59c4c,bcda5edf,9d10dc88,f7e9ae65,6ad2c823,8e8e0436,e007d821,b17d9405,984eccc4,617e3977,2f25d636), +S(8d1267b1,94da1334,fd20cb8f,77fa01cf,9e9ced90,43107e41,d1ec4057,eb6115a2,a7ba1b9e,2c6f0f19,5ff1f50a,7a8da22f,da3003fa,44b818b9,953b44d3,e6d6a0df), +S(dde6a3a0,87ef41db,2359e4e7,ca7cb064,424301e7,c5cbb5bc,4b6e504a,f3af4837,24175b1c,b4b39b7e,23718e26,be4a22bb,8bf54302,1f156234,e7f18010,d538aeb), +S(79efa584,2fb89f4e,85f556e,c4be170d,5c1ef88a,3f3f75cf,6b20fc1a,96984ad,b0704aaf,e4d8f30f,4f29fa85,6d55da13,91f5f3ce,36cdef6f,25133999,cc8541a), +S(3aa09dc0,5546977f,7369fa0a,7b60c94b,eab86a1,10d85af7,7b826475,7d67eaf5,343b4cf3,aa6c5ebc,ed041d7f,2381be57,f7fd32d0,29a2f42,a7c8821,4f425d8), +S(53fe8af9,8f9419fb,1445bb6a,94750d46,46be9f37,b7155763,88b11064,df2e6ffa,6cd77e81,84aeab9d,e9bf3093,bb9b21a3,a04a0719,fc428f3d,d5e14c8c,9b16cd7a), +S(fc395dc4,a5114dc8,bcb0f7f0,3a4d3e9,38a87a3d,78d33864,d1dc4cba,9e41e20e,c7991f6e,f72f82f6,b3147e56,74224929,fddeb8a5,97a1b1d4,8852733c,1830b941), +S(b1d25d51,b4558f5f,d0ccb868,3af9a9cf,62a169c6,91627fa5,92d80b18,36695f94,8f92258d,fcf16f4e,8415f53,e65457e8,9f090e72,5479c123,5a481464,a11cd4f9), +S(b866d6b1,42df940f,2cf28b54,c92f0c12,94e0b6a2,2a91f2ef,44bcd88c,4384480d,e6eb4f4c,bd95148f,765d8728,15652853,db1add7f,b4e27929,f19a64b7,f3b34c87)}, +{S(d4aaf32e,dd897f48,5ab16466,76d747cd,fec5b7a0,a05c917b,60c07311,45d16f89,4857e649,beff4089,2470f700,cadb73ae,d4866a84,c3f0b975,6fd8570e,df9d29d8), +S(4ebe5b8a,f3b1583c,9f41bd98,afaba549,f45c381e,c93ec9d1,4a543d87,9cefbaf3,63ed1d17,9b215f34,f1f580be,4b3f671f,2fa14689,74cd03d1,19fadae3,c92935ff), +S(20df6160,556dd3c5,a26620a8,70ff5323,cbbab94,be3e3bdd,ad8b936c,554f28f1,7168e7ab,cdbafad,26fbb5be,a09dadde,ed36c20f,c8deafaf,75a480b5,f980e981), +S(86c663f2,cc6f7ee2,50be25fd,fb35fd8e,5873481b,c477bf5b,c0f1bc1e,3f1320f,c13c5795,cce0ad92,e31240da,90a823d0,d2352314,f2852e67,cb62e0c2,8570994a), +S(3fd8085e,57f6870,b25e41d9,7df00126,150f6022,a7ede22f,d27da581,d234ccaa,c6657746,98d6ac03,ed1ea2d7,bd3f70be,86351c5d,407a4d7c,227fd7d0,c330ef04), +S(1510fcf0,b0fb5a23,c15e041,2a7f6d89,9fac4244,8ce316bf,d88fb58b,10e23118,1879dc07,b34d0a62,f0b9517f,3629ae0f,e8aa6d30,5a783f37,69bdf65,3b40408e), +S(67e9982b,c40f427,98df055c,2d8bdcc0,2ea97bad,68d34024,85498e27,d99e19e4,4f087caa,efc5fd7f,b099c134,a273635c,d1d5ace3,26e3103f,9b2fe22c,e95f288e), +S(e8eeab21,6c3395d6,d16338ea,de4108da,1c25e471,67fb13d5,99e8daaf,93e7345f,7fd2ba87,7c7266a5,65a31548,99950ea1,e5e3d73f,612addea,318ad5bc,a965228d), +S(ab20c7c8,9dd74c20,447bc762,e374c548,e7a8ac31,eec11123,1a040cd1,36e9a546,facacfb2,52eb9532,9106a26a,60128a0f,ae1d7e5c,fd39483c,aeb54dd9,231b55ee), +S(a9004211,b7cf5494,1c530a0e,d658fb6e,3b5d2ee1,37b7d7de,45fef6b5,efddbf0f,58cbaf67,5cc5a131,54eef7a1,462b5d1c,408d5d56,3553ca55,45388d77,c6391d4f), +S(8db64274,422ae0f5,6474b83a,89912fa,e3a39b6c,b3fb8370,308a572e,b6b3c020,9b71a72d,431fd44,aa8632ee,23bc678,61d96edd,b7ec72ab,4b1679b8,a4ba73e4), +S(301b330,c478189d,dce4314f,380cb2d8,38bbd416,5dfad8c4,90f2443f,2a56148b,737da0,1c05cf73,db36a1a4,5005f562,1327167f,d3b60ece,3da3705d,131903fe), +S(b9cbc7a3,4a1cbdd1,300e789d,b7ffec1c,dfe1f738,fbe1fe19,67dd7c14,92ee3ba7,5a816a0,9d08c4be,2b8d062f,200fde4c,534fbdbf,854c7e53,64532c08,60c97c01), +S(6a15e51,6f9f0a7c,25f2eac7,649285ea,d86a1e01,5a386dc,c7f94ba8,4782b45b,63eafaf4,660642ef,988aeee7,642e7c4b,71124a1c,2ca2f5c3,d4f2eec9,ea72d70e), +S(f4c696f3,34c56e08,2ab2e627,4d450f34,fa7fbce,29f3e14d,332bcadf,87d5fe0d,6ee44edf,f574d9a8,363f98b6,b863a648,27d3020,1e652935,be12041c,1bbcc7c3), +S(d2f3d5ad,237ba177,ed312bbb,1d02fb2a,e4bda20f,41f5c217,8b70dd9a,c26ee9b0,cc5912d4,2ea1af01,aa914b98,8c42cef8,46a5a059,664c8545,fc00b662,e0327920), +S(5588b0a4,757beb33,e668af5f,adf87fb3,2aed8e16,e6ceabf1,1576ae17,c6a2b843,70d8961b,ac203e89,c437b88b,ce331309,c4f7eca8,d614299c,74aef9b2,17c741de), +S(f993cd07,f6eb75ad,d41426d5,cc653886,18dde1f0,88aaf3cd,b2631eea,158373e0,1e74f804,5f60349e,a85b90e1,206f0ea4,b0cd3740,861186be,648063e8,58c2b395), +S(2cd04170,78291a50,750218b9,44a11a64,1cb75e7d,cd5cc4f9,64f53c8d,a1ef08f4,1f54a70f,f66ce343,c7ed3001,78d7b99e,49129e23,90b5a026,7ba25af5,3467b6d3), +S(52fc09a1,d4f0cc2e,c7ba6cba,1b30e1f0,b9e37f31,3bf59c33,60fc02e3,3b0c15e8,9bd14bcd,a7c7b6ab,dd7e17dd,ab81a1cf,846be336,a76858a1,8e8a0194,776f0a80), +S(90d29aba,764a9b49,1e2878c2,9b964bf6,e510af,3dd5aeb9,3fe29e13,b8f03b23,396b1f6d,e9b8fd1f,463ca064,11b09823,26cb6ab7,4bbbcaef,43031497,f149a620), +S(ce1d6e8e,ddd063f4,316cb006,b4a4213d,9e0952c8,43e6e1e7,570a35e,aad7fa53,a1abcd7,e2c23ad0,895c5aa8,82a805cd,1d7d434c,72f0c528,2ceec0b7,a7016f7c), +S(4df6e1d3,93a4be66,6fd88c75,e1e686a1,e2cb1844,f5f1303e,f7b0a751,99b42bf5,262d8b9,f7e202a3,78a51928,91ee3fc9,f269ef5d,e14dd0ff,f1fec9f4,4cdb9058), +S(f71b9bfa,bcc353a4,11a055eb,a7d6f48f,47c4e437,96382bcc,d5b882cd,a9059638,bfc1c3f8,fea7df8b,d1cd088c,b1f02e47,377d6656,9b3bd8a2,8b457ba5,e6453468), +S(ad5e9212,d3ef76d,8319fd98,72ee753f,ec99fab0,6244f4e2,a9567068,a635eb53,65fb538f,cb570092,7b0f775a,73ffb0c1,4e6c2274,e253f3a6,2dba9caa,27a3e5e4), +S(81a7dfa0,7659fdbd,57e1c8ae,20c14a80,ee8bfc51,46caa8db,b077b653,23bad4a,ac9d2438,3ef0d99f,26744be4,77e69d51,49d44ab9,84801bb,759d3a5b,7fed1e2e), +S(3bf8c1d0,a613316b,e90eab62,6788c8c3,b1641d65,d0e50245,9e5b19c1,ab1eb617,e1edb59a,8594d73,669e6f93,ca10e210,1254946b,8c9e8eac,3fa84a49,e4e2944f), +S(30f9283a,767c551c,e9fe87d9,5730eff6,fc302a4a,1810e4de,11ba62af,fa17eaae,1f383ac5,e714240d,67980617,d96b0c05,76008599,f8e3fa04,d57454e9,927e729b), +S(1c5d4ac6,91d37d0c,9db5e071,c809a59e,99056263,fbd83028,ee9530e9,c2b3f3c9,b98c7be9,7a2fb196,3d3d4a75,4f7fecce,2fbeb8fd,cf23c229,73b6875,86bd276a), +S(3dfe48e5,2f055be1,1db79fa4,501b44d8,f5ae8447,c5a1293a,a79f683f,1e1e9bf,2d7e8303,b988fc17,18c9b64c,1c03373d,27fd0c32,13c26e6c,b684ca94,49f79d5e), +S(adc4251b,c3ef6d5a,a4d6eb22,46ab2787,bc835b65,1d17ceae,489f181d,57d37248,4f0c489d,1c3a1814,a2f9c1c9,d6fe908f,4623aa44,ebaf4143,79fb8352,15234014), +S(edfe16b2,db401803,11f98920,7a2fef7,d05b2a3b,b676899f,9c6e2192,d38f93e0,1196fd0e,35a24c9,6b28b055,b4fa2f2d,a4c2aeff,3b91dd81,c2fe86c1,1d6bf682)}, +{S(b4b57b34,6e1b41b,7394e655,e059cc93,44c5d83e,f0ef17db,2789db5d,13777b78,6fa187a7,4d983b7e,cea6a268,61039430,63e599e7,cba73144,fe3eb23,677c6265), +S(9937238,7300054a,1a8713b7,6942f003,99818b28,6c6fba5d,ca60b9da,1aa7767,6c003e1,848ce30a,65601eb,e7b76acf,b2e122b6,882d7439,f463c042,ef1b31a), +S(ebd177f8,b5757665,58851c7f,a7ada38b,e3596080,f2679181,f994efd3,82714784,d0fe8eb0,97c852f7,b284d5f,bd81f77f,79c35af7,cc30338f,4e63211e,9e20a244), +S(367ef258,b279f923,a18215b7,67d396e4,c6bc874d,2be6b369,b01afffa,2e041741,bd961242,2452eddb,33831dcf,fb3a0273,30ef141f,6db77d91,5bec2ecb,553b6e6c), +S(d89f40c4,f752cff4,5bae5762,37f5096e,f27d46d0,d934d4de,c3011a28,59464e8e,9d32661e,e2319d6,f6427ea,a3014b5,cf98306c,666c4a9e,970dba2e,65e04886), +S(ef6ff862,1d84c5d5,22e490f4,db21181f,a17bafea,3e097868,4f1f0215,759772b9,ae006f11,aa85db2d,3624cf51,ae319ad2,8b4970e7,eac03301,1eb15db8,dc59d62b), +S(8b0a1b1b,d476bbfb,6da1d071,68d3a988,3b49802f,8ffa04a3,bbba1313,17c67a00,d8c74ae5,65c38597,8d9fda2e,dff6b932,1512e40b,ec5b62e2,59d4d81c,9b657b55), +S(9aa9250f,12ffde38,21384434,849d7eb7,bcafbae5,9a3b861f,68a3addb,d75d3715,19b4b1a8,8d8bfeee,38b54564,30d5f73e,ed0365fe,49092d4a,2f52fa12,b65e3ac7), +S(aaccc00f,55e96f0c,e66d9b43,12f9abd2,6772d8b4,30a6c62,edd2aab4,97acbc22,5af203cf,97d11147,82374056,f012f5f9,2825476a,820dce2e,6e1c4b33,cef5337c), +S(43c34546,2836b544,ddd6e432,6aa19b4a,9de7fdfb,86f43cae,ce98ce7c,32b1ccaf,dd518249,f1fbc1c7,1f905860,17a6f60b,15be97d4,18c66d42,f4f9adcd,d722c096), +S(9a38eb25,935441ab,8983097a,d58c821f,d784f091,5f85dc26,3f0c020b,b80c39a0,d8e6dc57,41e4ba5c,576179e8,9a6dcb4a,bd7178c6,13a1100b,e2bd731b,f3e819e2), +S(6b10527,204a4f7c,e8afcacc,fe771634,376f18da,f12774e,50f23a90,9efe0223,b443a451,529b4208,c8c98904,f5eb2ee,2e2ede2d,80ca50c5,aa29b95a,714181a), +S(1a88fecc,71d7550a,abf7faf0,8e884e95,835f6dc8,1815d2d7,7dab66ea,b238d6b2,82cf6711,1dd38ff,d0daebbc,ea2c064b,17b6b21d,34804f93,4a037936,9edec692), +S(a6b1751,f30507fe,5927b6d4,a92ebbbd,77358c02,9b750d05,a56e4d41,efb99144,ccf7c048,a2a0983d,fdcccfd,a071b80,e8035866,c479ea3a,3bbe7c80,12dfd618), +S(e186601e,8b545292,f23ae7fa,4cadc80f,1fcaa1a3,430ddec6,cfd2af47,c835cdf9,fd471f16,7c3683c9,2e5fc0c2,89b646a5,c8ebda6d,5b6da213,d862c3f6,2c292e9c), +S(91b3935,d8ce2b80,c179ee0b,87850140,4c418c7f,7cf94e4a,64b9fc9c,e396a093,45a5043b,8184546c,9083982f,550807d7,d61fe677,ce73ef21,9b3aa573,97c4eca1), +S(3fbe61fd,2a387654,dfc428e7,dac09e91,5e1ae7d6,d3794288,743f2535,20858ef5,206fd9a0,e3265118,e0a6475c,4df87e43,cc7c8898,59d8aa08,23b6dfff,b68b34d7), +S(31a35020,697d9d52,55476289,ce4fcbdc,4e1e0690,c2c36d1b,a4f4640f,e4c5ba18,91f660f9,159d463a,857f08ad,fc3c5ddd,804507c5,92f73de4,2ee44555,da538553), +S(7dc6b83a,10f26e71,e12c0bd,7ebcccc6,61b4394a,68f576fe,bfca1c23,256e8aa2,b4796977,bd386b98,f3e2fa8e,798b6548,fae52a80,40bb12ea,7e6ad675,64fc8736), +S(67a9c3ff,9c7b99b2,5318ff9e,2b85ee23,ec244655,8042ea8b,d880e23e,7d3ce221,a7bcbbbb,895ca7b1,847a43fa,98809ce4,98016123,bbb3c099,7d34debd,cb023f8d), +S(36602997,eba2c6c5,aab4cb65,8d4efd46,65ab3965,f643ff66,831646dc,f6443bf3,c82d0e80,ef775f9c,7ec7862a,e3158556,a57038d,e6850dd1,e349629c,2546239), +S(9eb9244b,299bfd76,f63bb140,ae2f42a1,4af1e072,83f8259f,6478ac03,d411df24,e43f91da,13c2ba21,a9d17d2f,7a8a629d,9051346,93a6552a,538d590,9d2bdd38), +S(ba4450fa,27d57993,3d949a1a,66013906,7d1a9716,6794993d,e45d9426,b4bfc5ed,8e3f3b9b,d8cb8210,7a5ae2af,92b96259,b73633f,6528ac04,20c3e101,6bb6d8a8), +S(e6d5335f,b67abd36,2712c7fe,575ee769,53d488b,236e8589,5664fb04,7f385248,9e255154,e070a5bb,e98e97f6,281fb999,a75e68ea,7681fdf6,fea093bd,919aa5a4), +S(63c099a9,300a331a,3bc4348a,a373e514,c84a810e,1ea8a8d1,4ac8d7cb,818eb534,ed7d4029,3cc4a086,b1d40c24,6086109,a02dbcb5,a864777,27939024,6fd6bf91), +S(7088617f,66cd93f,8130eaeb,874c3f77,3bcb0daa,78923b70,a65512a2,992554dc,5a3ff995,3c712066,291ac4a2,dfc2573e,1d0aed56,75ef526b,b15f61b0,d20f8156), +S(cc354aaf,746d756b,9387730f,2f12b999,4fcd815c,6d25cdab,2e1185aa,4aa639b3,fb1dead9,4fd76859,1aac8d79,5c337924,dc155fbe,5cd5c953,4d55ee31,f6d284a6), +S(e7e47c3a,e2bf4307,7f33ec3d,ac1ae2a7,5c669e61,e248f588,590cfe07,3e2186e0,46e9c4d5,4429fdcf,5efb375e,18f46cc8,3fa7a403,6013777f,e450e228,aebd4cd0), +S(c6ed5e63,28ec31b1,37041108,42d4ac23,fbb883bb,349d88db,1d747cf7,325fe9cc,21b8bfa4,b62807cf,d6cd11ed,a38084d5,7bb068d4,9f0dd30e,f3f431e2,b57022e4), +S(331924c7,50b3417e,48e279ff,6ed7f3dc,ba2e121e,9f69f8fb,e64093b6,c38a8cc6,357086be,e4cc0fe7,d45a49fe,41d004ce,80466165,316164ab,3b171f03,b9a7841f), +S(b4319cc9,f3e0d3b,313626ae,5385796b,c49b300c,88ba4553,dec0aa4a,77829372,b8f82bb6,6590afd4,48501f,63de3a5d,8f84edea,35c1ee44,88d6333e,f522a808), +S(da433d5e,11ceccc0,abc5c762,6ce7bab4,2e89b221,f785c409,282de545,f3fceb19,1b67242c,de57efcf,e214423b,506a1ade,718803d2,6dd84d88,97b18ede,590a2fcb)}, +{S(ebae7464,ece277b8,309d056c,cf3775e2,11a77aa,81c316a4,b6b7b953,6f90f539,62a4d6a2,95fdd811,f2051715,322f17e5,1753c9d0,835ef9a0,3e8dc9f5,c69bda31), +S(5b20700c,1af63394,a3e4cadb,b0ea682e,19cf495a,b908418a,d41f4c6c,ea4477f0,8435d15e,34b03a22,ca89c73d,326c2f88,142d2e23,8964ef6d,99287125,79738f78), +S(b2f25f91,138b974b,561328c0,92f50fdf,8a694004,fd4879d0,12a4a6cc,c8059d1d,d9ec0b2d,b8e81b2,f6feaf55,9776ff78,cda3401b,47826de0,ca06e579,9d866c09), +S(64e79790,7783d6fb,321eb785,acdeb2ff,4628270,fec3342c,527c8db0,a34c516e,c0c4da5d,abf3da9c,a8613f82,ca28e84,a1a18376,c9967c08,aaf70bea,7a2f34c2), +S(a50cae84,a08f4f32,4984853a,d4c6bdaf,77eaa788,9cb8fe95,72fd56e,9078ee73,120ecbf,76e47b38,503067c8,36853003,60ed261a,40fdf440,161ef2cd,19786b93), +S(76ff3ac8,80a451a9,6741fc70,82bc4c82,7bd51c08,95eea8c8,b422b8a9,96ba4794,25555d71,d4313a60,b189a154,58e0a40,c643c204,277334e,966e2abd,3a23f6c3), +S(307e5caa,8b708760,3d9f845b,b78f4f10,72c49c10,9747f91d,192f8d6e,70c0f4be,f5992f76,37167e1d,55cd31a6,1cdb4756,85eb1503,34fb6009,e0240a18,fa8302b8), +S(d8e62e47,b28fd165,4d420137,884dcf21,c10cb159,d9885843,da34b0d9,d09b2758,675c75b4,b903ad28,2055a71b,2c470e2b,1dce69bf,ecf160cf,3a027de2,55b723a9), +S(ec5639c7,73dac23d,3008dabf,732dc005,3154703d,26ee3bbc,7689286e,4a73e39f,aaa5ea4a,2cf5c23d,57cdd0d8,8accbbf9,9fd2c213,97bb45f8,83547876,3aab1248), +S(3d928ee3,2065557a,27722f08,5202f48f,40917ed6,c7ac1963,2a122226,8b0cb9df,ece112a4,e7a05ad6,17c2fd83,76f89102,9eb94eb0,930fb23c,a342d7f1,f021a0c7), +S(616228a5,cc6c3a92,cd694cec,4b2b8574,5dfffa90,b2a36d8f,32eaa6cc,2530de51,50d8d140,4d506a78,700f8e82,967b36a5,1b4de644,a8e22271,d509c8d2,4adf3148), +S(6f85f308,e847b145,c13a07be,bebdd4ba,6c138939,6afd8670,733f44a8,969406d0,864bcde1,be36c9c7,b7e04ef8,cd2366e2,b3c22902,5ee7efce,d005ef5b,ff7dae2b), +S(f3d1ecc3,53a82621,1bd78f0f,aa029076,c6ca779,9bdc54b2,128fa3d2,aec00c6d,75aa0cf9,fd0b7bed,19183e34,58142f66,c94a5aa9,3915435e,ae51c1fe,96625ccd), +S(a5918de3,f18cd8d1,2a234f9f,3a19fcaa,2d83671d,ad566f16,8aea2b1f,b9de41b0,c515dda6,43c0f6c8,d8fea16,5d595917,16b7f521,43d3b941,f28585ed,8a49c06c), +S(3c49e2ef,1d2d3464,81e05fa0,33366609,1615ebcf,535f68,be257f35,7bd91592,57901e0a,c8af3a31,aa404987,72c903fd,175c9b00,5c7458ee,ed667f11,57754132), +S(6c45ff2,c0c30320,83c343e6,dc80b4f7,bb64502a,52f412ff,ada521d4,a544a9f0,e9936037,f1e641eb,1cd6f801,a25271d3,cffe67d,c9bd7162,babf9855,9628a9a8), +S(66df5d95,acdf4260,ee0e465c,e3916d79,395df522,aa086aeb,6c283bb7,18296d46,cb1f3deb,8aea0337,625f46dd,903416d1,5647be91,1633c4c0,cf0e629a,413476fc), +S(428bbba5,ef351762,9eee4059,a3339213,40c7fee2,5ccb051c,88d75e53,ba618858,ef18809c,28227ccc,115876df,b3f378cd,374c0670,2c658501,7990e767,922c3999), +S(e8993820,d782657,ed8badc2,d515e360,df336730,860ef49e,65ca58dd,1a385815,feb41189,16c7e8f6,53c7f5a6,5fd7b6be,7a029814,149c4645,847073be,770959de), +S(2b77e42a,63502244,d6c7d1be,54b7857,9e2742d2,7143d689,fa3f70a3,5986ccf1,721e9da8,bee88ad4,2155dc9a,28be505,86648378,1d6af5b1,382cd47d,771e6428), +S(acffce3a,ed6beea3,2ad71633,21e1ca53,6f69ce76,fb5cd394,9d9dcc14,bbcee96,5384c97d,eac946c0,afc85b54,f3a56b79,fe263bff,63e1894c,6d52ef1b,9b456602), +S(e13d8d4b,25bece8d,90a008e4,c004824e,223b06b,7cf65ebd,1215e910,2e67b639,3e92b1f,14cbee57,9640b377,6ed5938f,9aee0e11,b139a678,3f207cf4,6dd7e20b), +S(d8f356d9,d2498eaa,b3fa12a,cb64562b,dff3e270,c7809a31,25a9ae65,9cb1f3c5,a5403cda,2d499a7c,7402b57c,c9f99e3,64f5085a,91fd8cfd,8a67c7a8,dbce04fb), +S(350062b5,22fb5d0a,8c79a5db,29e92216,79b9fbc6,3e1f95ca,e7d087f3,fedffc49,74cacf57,5e79c85b,d7e77a40,796e8750,a3ca57f2,a47cce8f,3d2de02d,b014df0b), +S(c159e630,9ab23135,58ebfb6b,22edaf93,eac8e16,77cd9f3b,1cd9492,20bf8e54,99244263,53f32608,831c6d74,da51d61,c344defe,f4c1e401,6a3db44b,4c57f4ae), +S(9e568b70,36a2daa2,fe7a3a52,49c56eb8,3fe4afa2,decebd60,c6c3245f,17bc6a13,b6643644,274eab9f,5e83c598,14978681,17c5a078,765156ae,3cb65fd3,830e06ae), +S(9bee7471,6b6c1ff5,62c1bc36,57a65de3,99a91d72,115703f4,4c3819a1,87828478,bb23a3da,ed34028a,7d39a7ed,fe2e23b,73e085a2,d6c2e51a,ef2a2076,a7c902ad), +S(c430c044,91228a7a,ea835698,ecf0f552,9aeef469,a36305cb,52902ccd,1c897473,40d0ee56,61cca82,80d11da,bffe97c4,f10c93aa,5e07224c,154b666e,bcd58c74), +S(2be073f6,b294a01b,eda0b0db,6832e4bc,23ef3889,7a859853,5ee726ef,ae0f15b1,6153f846,349c2a98,26008065,8be2a7d8,311a5e70,cc310ff8,7935a901,8d575813), +S(2934de46,a6d921f8,720567e6,b46e6362,36a7ed53,483b13ed,20958452,3225accd,5979698,26927cd7,abfe4c57,c53fc72a,48b71679,174c749d,aecdb057,e6a2d961), +S(4e9991b,92fa8c4e,4e8efe45,66966073,319e80d3,a54d4b7a,b61cfcc4,7ddaa5d5,9d03ea22,21d4d80e,261952e2,73f6a8cf,c31f6091,e5aa0a8f,2281ffbf,1345df9e), +S(ff3d6136,ffac5b0c,bfc6c5c0,c30dc01a,7ea3d56c,20bd3103,b178e3d3,ae180068,eccdc641,7b1bfff1,bf2fc8d3,2269523e,ab89890d,bffe0a19,8f594490,e7739bb8)} +#else +# error Configuration mismatch, invalid COMB_* parameters. Try deleting precomputed_ecmult_gen.c before the build. +#endif +}; +#undef S diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precomputed_ecmult_gen.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precomputed_ecmult_gen.h similarity index 68% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precomputed_ecmult_gen.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precomputed_ecmult_gen.h index ab06d7df..a548cdce 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/precomputed_ecmult_gen.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/precomputed_ecmult_gen.h @@ -14,9 +14,9 @@ extern "C" { #include "group.h" #include "ecmult_gen.h" #ifdef EXHAUSTIVE_TEST_ORDER -static rustsecp256k1zkp_v0_8_0_ge_storage rustsecp256k1zkp_v0_8_0_ecmult_gen_prec_table[ECMULT_GEN_PREC_N(ECMULT_GEN_PREC_BITS)][ECMULT_GEN_PREC_G(ECMULT_GEN_PREC_BITS)]; +static rustsecp256k1_v0_11_ge_storage rustsecp256k1_v0_11_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS]; #else -extern const rustsecp256k1zkp_v0_8_0_ge_storage rustsecp256k1zkp_v0_8_0_ecmult_gen_prec_table[ECMULT_GEN_PREC_N(ECMULT_GEN_PREC_BITS)][ECMULT_GEN_PREC_G(ECMULT_GEN_PREC_BITS)]; +extern const rustsecp256k1_v0_11_ge_storage rustsecp256k1_v0_11_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS]; #endif /* defined(EXHAUSTIVE_TEST_ORDER) */ #ifdef __cplusplus diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar.h new file mode 100644 index 00000000..a1347d84 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar.h @@ -0,0 +1,105 @@ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCALAR_H +#define SECP256K1_SCALAR_H + +#include "util.h" + +#if defined(EXHAUSTIVE_TEST_ORDER) +#include "scalar_low.h" +#elif defined(SECP256K1_WIDEMUL_INT128) +#include "scalar_4x64.h" +#elif defined(SECP256K1_WIDEMUL_INT64) +#include "scalar_8x32.h" +#else +#error "Please select wide multiplication implementation" +#endif + +/** Clear a scalar to prevent the leak of sensitive data. */ +static void rustsecp256k1_v0_11_scalar_clear(rustsecp256k1_v0_11_scalar *r); + +/** Access bits (1 < count <= 32) from a scalar. All requested bits must belong to the same 32-bit limb. */ +static uint32_t rustsecp256k1_v0_11_scalar_get_bits_limb32(const rustsecp256k1_v0_11_scalar *a, unsigned int offset, unsigned int count); + +/** Access bits (1 < count <= 32) from a scalar. offset + count must be < 256. Not constant time in offset and count. */ +static uint32_t rustsecp256k1_v0_11_scalar_get_bits_var(const rustsecp256k1_v0_11_scalar *a, unsigned int offset, unsigned int count); + +/** Set a scalar from a big endian byte array. The scalar will be reduced modulo group order `n`. + * In: bin: pointer to a 32-byte array. + * Out: r: scalar to be set. + * overflow: non-zero if the scalar was bigger or equal to `n` before reduction, zero otherwise (can be NULL). + */ +static void rustsecp256k1_v0_11_scalar_set_b32(rustsecp256k1_v0_11_scalar *r, const unsigned char *bin, int *overflow); + +/** Set a scalar from a big endian byte array and returns 1 if it is a valid + * seckey and 0 otherwise. */ +static int rustsecp256k1_v0_11_scalar_set_b32_seckey(rustsecp256k1_v0_11_scalar *r, const unsigned char *bin); + +/** Set a scalar to an unsigned integer. */ +static void rustsecp256k1_v0_11_scalar_set_int(rustsecp256k1_v0_11_scalar *r, unsigned int v); + +/** Convert a scalar to a byte array. */ +static void rustsecp256k1_v0_11_scalar_get_b32(unsigned char *bin, const rustsecp256k1_v0_11_scalar* a); + +/** Add two scalars together (modulo the group order). Returns whether it overflowed. */ +static int rustsecp256k1_v0_11_scalar_add(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b); + +/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */ +static void rustsecp256k1_v0_11_scalar_cadd_bit(rustsecp256k1_v0_11_scalar *r, unsigned int bit, int flag); + +/** Multiply two scalars (modulo the group order). */ +static void rustsecp256k1_v0_11_scalar_mul(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b); + +/** Compute the inverse of a scalar (modulo the group order). */ +static void rustsecp256k1_v0_11_scalar_inverse(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a); + +/** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */ +static void rustsecp256k1_v0_11_scalar_inverse_var(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a); + +/** Compute the complement of a scalar (modulo the group order). */ +static void rustsecp256k1_v0_11_scalar_negate(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a); + +/** Multiply a scalar with the multiplicative inverse of 2. */ +static void rustsecp256k1_v0_11_scalar_half(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a); + +/** Check whether a scalar equals zero. */ +static int rustsecp256k1_v0_11_scalar_is_zero(const rustsecp256k1_v0_11_scalar *a); + +/** Check whether a scalar equals one. */ +static int rustsecp256k1_v0_11_scalar_is_one(const rustsecp256k1_v0_11_scalar *a); + +/** Check whether a scalar, considered as an nonnegative integer, is even. */ +static int rustsecp256k1_v0_11_scalar_is_even(const rustsecp256k1_v0_11_scalar *a); + +/** Check whether a scalar is higher than the group order divided by 2. */ +static int rustsecp256k1_v0_11_scalar_is_high(const rustsecp256k1_v0_11_scalar *a); + +/** Conditionally negate a number, in constant time. + * Returns -1 if the number was negated, 1 otherwise */ +static int rustsecp256k1_v0_11_scalar_cond_negate(rustsecp256k1_v0_11_scalar *a, int flag); + +/** Compare two scalars. */ +static int rustsecp256k1_v0_11_scalar_eq(const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b); + +/** Find r1 and r2 such that r1+r2*2^128 = k. */ +static void rustsecp256k1_v0_11_scalar_split_128(rustsecp256k1_v0_11_scalar *r1, rustsecp256k1_v0_11_scalar *r2, const rustsecp256k1_v0_11_scalar *k); +/** Find r1 and r2 such that r1+r2*lambda = k, where r1 and r2 or their + * negations are maximum 128 bits long (see rustsecp256k1_v0_11_ge_mul_lambda). It is + * required that r1, r2, and k all point to different objects. */ +static void rustsecp256k1_v0_11_scalar_split_lambda(rustsecp256k1_v0_11_scalar * SECP256K1_RESTRICT r1, rustsecp256k1_v0_11_scalar * SECP256K1_RESTRICT r2, const rustsecp256k1_v0_11_scalar * SECP256K1_RESTRICT k); + +/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ +static void rustsecp256k1_v0_11_scalar_mul_shift_var(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b, unsigned int shift); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +static void rustsecp256k1_v0_11_scalar_cmov(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, int flag); + +/** Check invariants on a scalar (no-op unless VERIFY is enabled). */ +static void rustsecp256k1_v0_11_scalar_verify(const rustsecp256k1_v0_11_scalar *r); +#define SECP256K1_SCALAR_VERIFY(r) rustsecp256k1_v0_11_scalar_verify(r) + +#endif /* SECP256K1_SCALAR_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_4x64.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_4x64.h similarity index 95% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_4x64.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_4x64.h index e6d25aa4..5be54acd 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_4x64.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_4x64.h @@ -12,7 +12,7 @@ /** A scalar modulo the group order of the secp256k1 curve. */ typedef struct { uint64_t d[4]; -} rustsecp256k1zkp_v0_8_0_scalar; +} rustsecp256k1_v0_11_scalar; #define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}} diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_4x64_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_4x64_impl.h new file mode 100644 index 00000000..4a147c6a --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_4x64_impl.h @@ -0,0 +1,1000 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H + +#include "checkmem.h" +#include "int128.h" +#include "modinv64_impl.h" +#include "util.h" + +/* Limbs of the secp256k1 order. */ +#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) +#define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL) +#define SECP256K1_N_2 ((uint64_t)0xFFFFFFFFFFFFFFFEULL) +#define SECP256K1_N_3 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) + +/* Limbs of 2^256 minus the secp256k1 order. */ +#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) +#define SECP256K1_N_C_1 (~SECP256K1_N_1) +#define SECP256K1_N_C_2 (1) + +/* Limbs of half the secp256k1 order. */ +#define SECP256K1_N_H_0 ((uint64_t)0xDFE92F46681B20A0ULL) +#define SECP256K1_N_H_1 ((uint64_t)0x5D576E7357A4501DULL) +#define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) +#define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL) + +SECP256K1_INLINE static void rustsecp256k1_v0_11_scalar_set_int(rustsecp256k1_v0_11_scalar *r, unsigned int v) { + r->d[0] = v; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; + + SECP256K1_SCALAR_VERIFY(r); +} + +SECP256K1_INLINE static uint32_t rustsecp256k1_v0_11_scalar_get_bits_limb32(const rustsecp256k1_v0_11_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + VERIFY_CHECK(count > 0 && count <= 32); + VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6); + + return (a->d[offset >> 6] >> (offset & 0x3F)) & (0xFFFFFFFF >> (32 - count)); +} + +SECP256K1_INLINE static uint32_t rustsecp256k1_v0_11_scalar_get_bits_var(const rustsecp256k1_v0_11_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + VERIFY_CHECK(count > 0 && count <= 32); + VERIFY_CHECK(offset + count <= 256); + + if ((offset + count - 1) >> 6 == offset >> 6) { + return rustsecp256k1_v0_11_scalar_get_bits_limb32(a, offset, count); + } else { + VERIFY_CHECK((offset >> 6) + 1 < 4); + return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & (0xFFFFFFFF >> (32 - count)); + } +} + +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_check_overflow(const rustsecp256k1_v0_11_scalar *a) { + int yes = 0; + int no = 0; + no |= (a->d[3] < SECP256K1_N_3); /* No need for a > check. */ + no |= (a->d[2] < SECP256K1_N_2); + yes |= (a->d[2] > SECP256K1_N_2) & ~no; + no |= (a->d[1] < SECP256K1_N_1); + yes |= (a->d[1] > SECP256K1_N_1) & ~no; + yes |= (a->d[0] >= SECP256K1_N_0) & ~no; + return yes; +} + +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_reduce(rustsecp256k1_v0_11_scalar *r, unsigned int overflow) { + rustsecp256k1_v0_11_uint128 t; + VERIFY_CHECK(overflow <= 1); + + rustsecp256k1_v0_11_u128_from_u64(&t, r->d[0]); + rustsecp256k1_v0_11_u128_accum_u64(&t, overflow * SECP256K1_N_C_0); + r->d[0] = rustsecp256k1_v0_11_u128_to_u64(&t); rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, r->d[1]); + rustsecp256k1_v0_11_u128_accum_u64(&t, overflow * SECP256K1_N_C_1); + r->d[1] = rustsecp256k1_v0_11_u128_to_u64(&t); rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, r->d[2]); + rustsecp256k1_v0_11_u128_accum_u64(&t, overflow * SECP256K1_N_C_2); + r->d[2] = rustsecp256k1_v0_11_u128_to_u64(&t); rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, r->d[3]); + r->d[3] = rustsecp256k1_v0_11_u128_to_u64(&t); + + SECP256K1_SCALAR_VERIFY(r); + return overflow; +} + +static int rustsecp256k1_v0_11_scalar_add(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b) { + int overflow; + rustsecp256k1_v0_11_uint128 t; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + rustsecp256k1_v0_11_u128_from_u64(&t, a->d[0]); + rustsecp256k1_v0_11_u128_accum_u64(&t, b->d[0]); + r->d[0] = rustsecp256k1_v0_11_u128_to_u64(&t); rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, a->d[1]); + rustsecp256k1_v0_11_u128_accum_u64(&t, b->d[1]); + r->d[1] = rustsecp256k1_v0_11_u128_to_u64(&t); rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, a->d[2]); + rustsecp256k1_v0_11_u128_accum_u64(&t, b->d[2]); + r->d[2] = rustsecp256k1_v0_11_u128_to_u64(&t); rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, a->d[3]); + rustsecp256k1_v0_11_u128_accum_u64(&t, b->d[3]); + r->d[3] = rustsecp256k1_v0_11_u128_to_u64(&t); rustsecp256k1_v0_11_u128_rshift(&t, 64); + overflow = rustsecp256k1_v0_11_u128_to_u64(&t) + rustsecp256k1_v0_11_scalar_check_overflow(r); + VERIFY_CHECK(overflow == 0 || overflow == 1); + rustsecp256k1_v0_11_scalar_reduce(r, overflow); + + SECP256K1_SCALAR_VERIFY(r); + return overflow; +} + +static void rustsecp256k1_v0_11_scalar_cadd_bit(rustsecp256k1_v0_11_scalar *r, unsigned int bit, int flag) { + rustsecp256k1_v0_11_uint128 t; + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(bit < 256); + + bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ + rustsecp256k1_v0_11_u128_from_u64(&t, r->d[0]); + rustsecp256k1_v0_11_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); + r->d[0] = rustsecp256k1_v0_11_u128_to_u64(&t); rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, r->d[1]); + rustsecp256k1_v0_11_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); + r->d[1] = rustsecp256k1_v0_11_u128_to_u64(&t); rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, r->d[2]); + rustsecp256k1_v0_11_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F)); + r->d[2] = rustsecp256k1_v0_11_u128_to_u64(&t); rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, r->d[3]); + rustsecp256k1_v0_11_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F)); + r->d[3] = rustsecp256k1_v0_11_u128_to_u64(&t); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(rustsecp256k1_v0_11_u128_hi_u64(&t) == 0); +} + +static void rustsecp256k1_v0_11_scalar_set_b32(rustsecp256k1_v0_11_scalar *r, const unsigned char *b32, int *overflow) { + int over; + r->d[0] = rustsecp256k1_v0_11_read_be64(&b32[24]); + r->d[1] = rustsecp256k1_v0_11_read_be64(&b32[16]); + r->d[2] = rustsecp256k1_v0_11_read_be64(&b32[8]); + r->d[3] = rustsecp256k1_v0_11_read_be64(&b32[0]); + over = rustsecp256k1_v0_11_scalar_reduce(r, rustsecp256k1_v0_11_scalar_check_overflow(r)); + if (overflow) { + *overflow = over; + } + + SECP256K1_SCALAR_VERIFY(r); +} + +static void rustsecp256k1_v0_11_scalar_get_b32(unsigned char *bin, const rustsecp256k1_v0_11_scalar* a) { + SECP256K1_SCALAR_VERIFY(a); + + rustsecp256k1_v0_11_write_be64(&bin[0], a->d[3]); + rustsecp256k1_v0_11_write_be64(&bin[8], a->d[2]); + rustsecp256k1_v0_11_write_be64(&bin[16], a->d[1]); + rustsecp256k1_v0_11_write_be64(&bin[24], a->d[0]); +} + +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_is_zero(const rustsecp256k1_v0_11_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; +} + +static void rustsecp256k1_v0_11_scalar_negate(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a) { + uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (rustsecp256k1_v0_11_scalar_is_zero(a) == 0); + rustsecp256k1_v0_11_uint128 t; + SECP256K1_SCALAR_VERIFY(a); + + rustsecp256k1_v0_11_u128_from_u64(&t, ~a->d[0]); + rustsecp256k1_v0_11_u128_accum_u64(&t, SECP256K1_N_0 + 1); + r->d[0] = rustsecp256k1_v0_11_u128_to_u64(&t) & nonzero; rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, ~a->d[1]); + rustsecp256k1_v0_11_u128_accum_u64(&t, SECP256K1_N_1); + r->d[1] = rustsecp256k1_v0_11_u128_to_u64(&t) & nonzero; rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, ~a->d[2]); + rustsecp256k1_v0_11_u128_accum_u64(&t, SECP256K1_N_2); + r->d[2] = rustsecp256k1_v0_11_u128_to_u64(&t) & nonzero; rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, ~a->d[3]); + rustsecp256k1_v0_11_u128_accum_u64(&t, SECP256K1_N_3); + r->d[3] = rustsecp256k1_v0_11_u128_to_u64(&t) & nonzero; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void rustsecp256k1_v0_11_scalar_half(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a) { + /* Writing `/` for field division and `//` for integer division, we compute + * + * a/2 = (a - (a&1))/2 + (a&1)/2 + * = (a >> 1) + (a&1 ? 1/2 : 0) + * = (a >> 1) + (a&1 ? n//2+1 : 0), + * + * where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n). + * For n//2, we have the constants SECP256K1_N_H_0, ... + * + * This sum does not overflow. The most extreme case is a = -2, the largest odd scalar. Here: + * - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2 + * - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2 + * Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n. + */ + uint64_t mask = -(uint64_t)(a->d[0] & 1U); + rustsecp256k1_v0_11_uint128 t; + SECP256K1_SCALAR_VERIFY(a); + + rustsecp256k1_v0_11_u128_from_u64(&t, (a->d[0] >> 1) | (a->d[1] << 63)); + rustsecp256k1_v0_11_u128_accum_u64(&t, (SECP256K1_N_H_0 + 1U) & mask); + r->d[0] = rustsecp256k1_v0_11_u128_to_u64(&t); rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, (a->d[1] >> 1) | (a->d[2] << 63)); + rustsecp256k1_v0_11_u128_accum_u64(&t, SECP256K1_N_H_1 & mask); + r->d[1] = rustsecp256k1_v0_11_u128_to_u64(&t); rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, (a->d[2] >> 1) | (a->d[3] << 63)); + rustsecp256k1_v0_11_u128_accum_u64(&t, SECP256K1_N_H_2 & mask); + r->d[2] = rustsecp256k1_v0_11_u128_to_u64(&t); rustsecp256k1_v0_11_u128_rshift(&t, 64); + r->d[3] = rustsecp256k1_v0_11_u128_to_u64(&t) + (a->d[3] >> 1) + (SECP256K1_N_H_3 & mask); +#ifdef VERIFY + /* The line above only computed the bottom 64 bits of r->d[3]; redo the computation + * in full 128 bits to make sure the top 64 bits are indeed zero. */ + rustsecp256k1_v0_11_u128_accum_u64(&t, a->d[3] >> 1); + rustsecp256k1_v0_11_u128_accum_u64(&t, SECP256K1_N_H_3 & mask); + rustsecp256k1_v0_11_u128_rshift(&t, 64); + VERIFY_CHECK(rustsecp256k1_v0_11_u128_to_u64(&t) == 0); + + SECP256K1_SCALAR_VERIFY(r); +#endif +} + +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_is_one(const rustsecp256k1_v0_11_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0; +} + +static int rustsecp256k1_v0_11_scalar_is_high(const rustsecp256k1_v0_11_scalar *a) { + int yes = 0; + int no = 0; + SECP256K1_SCALAR_VERIFY(a); + + no |= (a->d[3] < SECP256K1_N_H_3); + yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; + no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; /* No need for a > check. */ + no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; + yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; + return yes; +} + +static int rustsecp256k1_v0_11_scalar_cond_negate(rustsecp256k1_v0_11_scalar *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to rustsecp256k1_v0_11_scalar_negate */ + volatile int vflag = flag; + uint64_t mask = -vflag; + uint64_t nonzero = (rustsecp256k1_v0_11_scalar_is_zero(r) != 0) - 1; + rustsecp256k1_v0_11_uint128 t; + SECP256K1_SCALAR_VERIFY(r); + + rustsecp256k1_v0_11_u128_from_u64(&t, r->d[0] ^ mask); + rustsecp256k1_v0_11_u128_accum_u64(&t, (SECP256K1_N_0 + 1) & mask); + r->d[0] = rustsecp256k1_v0_11_u128_to_u64(&t) & nonzero; rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, r->d[1] ^ mask); + rustsecp256k1_v0_11_u128_accum_u64(&t, SECP256K1_N_1 & mask); + r->d[1] = rustsecp256k1_v0_11_u128_to_u64(&t) & nonzero; rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, r->d[2] ^ mask); + rustsecp256k1_v0_11_u128_accum_u64(&t, SECP256K1_N_2 & mask); + r->d[2] = rustsecp256k1_v0_11_u128_to_u64(&t) & nonzero; rustsecp256k1_v0_11_u128_rshift(&t, 64); + rustsecp256k1_v0_11_u128_accum_u64(&t, r->d[3] ^ mask); + rustsecp256k1_v0_11_u128_accum_u64(&t, SECP256K1_N_3 & mask); + r->d[3] = rustsecp256k1_v0_11_u128_to_u64(&t) & nonzero; + + SECP256K1_SCALAR_VERIFY(r); + return 2 * (mask == 0) - 1; +} + +/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ + +/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd(a,b) { \ + uint64_t tl, th; \ + { \ + rustsecp256k1_v0_11_uint128 t; \ + rustsecp256k1_v0_11_u128_mul(&t, a, b); \ + th = rustsecp256k1_v0_11_u128_hi_u64(&t); /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = rustsecp256k1_v0_11_u128_to_u64(&t); \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \ + c1 += th; /* overflow is handled on the next line */ \ + c2 += (c1 < th); /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ +} + +/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ +#define muladd_fast(a,b) { \ + uint64_t tl, th; \ + { \ + rustsecp256k1_v0_11_uint128 t; \ + rustsecp256k1_v0_11_u128_mul(&t, a, b); \ + th = rustsecp256k1_v0_11_u128_hi_u64(&t); /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = rustsecp256k1_v0_11_u128_to_u64(&t); \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \ + c1 += th; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK(c1 >= th); \ +} + +/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define sumadd(a) { \ + unsigned int over; \ + c0 += (a); /* overflow is handled on the next line */ \ + over = (c0 < (a)); \ + c1 += over; /* overflow is handled on the next line */ \ + c2 += (c1 < over); /* never overflows by contract */ \ +} + +/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ +#define sumadd_fast(a) { \ + c0 += (a); /* overflow is handled on the next line */ \ + c1 += (c0 < (a)); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ + VERIFY_CHECK(c2 == 0); \ +} + +/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. */ +#define extract(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = c2; \ + c2 = 0; \ +} + +/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. c2 is required to be zero. */ +#define extract_fast(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = 0; \ + VERIFY_CHECK(c2 == 0); \ +} + +static void rustsecp256k1_v0_11_scalar_reduce_512(rustsecp256k1_v0_11_scalar *r, const uint64_t *l) { +#ifdef USE_ASM_X86_64 + /* Reduce 512 bits into 385. */ + uint64_t m0, m1, m2, m3, m4, m5, m6; + uint64_t p0, p1, p2, p3, p4; + uint64_t c; + + __asm__ __volatile__( + /* Preload. */ + "movq 32(%%rsi), %%r11\n" + "movq 40(%%rsi), %%r12\n" + "movq 48(%%rsi), %%r13\n" + "movq 56(%%rsi), %%r14\n" + /* Initialize r8,r9,r10 */ + "movq 0(%%rsi), %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9) += n0 * c0 */ + "movq %8, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* extract m0 */ + "movq %%r8, %q0\n" + "xorq %%r8, %%r8\n" + /* (r9,r10) += l1 */ + "addq 8(%%rsi), %%r9\n" + "adcq $0, %%r10\n" + /* (r9,r10,r8) += n1 * c0 */ + "movq %8, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += n0 * c1 */ + "movq %9, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* extract m1 */ + "movq %%r9, %q1\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += l2 */ + "addq 16(%%rsi), %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n2 * c0 */ + "movq %8, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n1 * c1 */ + "movq %9, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n0 */ + "addq %%r11, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* extract m2 */ + "movq %%r10, %q2\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += l3 */ + "addq 24(%%rsi), %%r8\n" + "adcq $0, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n3 * c0 */ + "movq %8, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n2 * c1 */ + "movq %9, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n1 */ + "addq %%r12, %%r8\n" + "adcq $0, %%r9\n" + "adcq $0, %%r10\n" + /* extract m3 */ + "movq %%r8, %q3\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += n3 * c1 */ + "movq %9, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += n2 */ + "addq %%r13, %%r9\n" + "adcq $0, %%r10\n" + "adcq $0, %%r8\n" + /* extract m4 */ + "movq %%r9, %q4\n" + /* (r10,r8) += n3 */ + "addq %%r14, %%r10\n" + "adcq $0, %%r8\n" + /* extract m5 */ + "movq %%r10, %q5\n" + /* extract m6 */ + "movq %%r8, %q6\n" + : "=&g"(m0), "=&g"(m1), "=&g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6) + : "S"(l), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc"); + + SECP256K1_CHECKMEM_MSAN_DEFINE(&m0, sizeof(m0)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m1, sizeof(m1)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m2, sizeof(m2)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m3, sizeof(m3)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m4, sizeof(m4)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m5, sizeof(m5)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m6, sizeof(m6)); + + /* Reduce 385 bits into 258. */ + __asm__ __volatile__( + /* Preload */ + "movq %q9, %%r11\n" + "movq %q10, %%r12\n" + "movq %q11, %%r13\n" + /* Initialize (r8,r9,r10) */ + "movq %q5, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9) += m4 * c0 */ + "movq %12, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* extract p0 */ + "movq %%r8, %q0\n" + "xorq %%r8, %%r8\n" + /* (r9,r10) += m1 */ + "addq %q6, %%r9\n" + "adcq $0, %%r10\n" + /* (r9,r10,r8) += m5 * c0 */ + "movq %12, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += m4 * c1 */ + "movq %13, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* extract p1 */ + "movq %%r9, %q1\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += m2 */ + "addq %q7, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m6 * c0 */ + "movq %12, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m5 * c1 */ + "movq %13, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m4 */ + "addq %%r11, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* extract p2 */ + "movq %%r10, %q2\n" + /* (r8,r9) += m3 */ + "addq %q8, %%r8\n" + "adcq $0, %%r9\n" + /* (r8,r9) += m6 * c1 */ + "movq %13, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* (r8,r9) += m5 */ + "addq %%r12, %%r8\n" + "adcq $0, %%r9\n" + /* extract p3 */ + "movq %%r8, %q3\n" + /* (r9) += m6 */ + "addq %%r13, %%r9\n" + /* extract p4 */ + "movq %%r9, %q4\n" + : "=&g"(p0), "=&g"(p1), "=&g"(p2), "=g"(p3), "=g"(p4) + : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc"); + + SECP256K1_CHECKMEM_MSAN_DEFINE(&p0, sizeof(p0)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&p1, sizeof(p1)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&p2, sizeof(p2)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&p3, sizeof(p3)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&p4, sizeof(p4)); + + /* Reduce 258 bits into 256. */ + __asm__ __volatile__( + /* Preload */ + "movq %q5, %%r10\n" + /* (rax,rdx) = p4 * c0 */ + "movq %7, %%rax\n" + "mulq %%r10\n" + /* (rax,rdx) += p0 */ + "addq %q1, %%rax\n" + "adcq $0, %%rdx\n" + /* extract r0 */ + "movq %%rax, 0(%q6)\n" + /* Move to (r8,r9) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + /* (r8,r9) += p1 */ + "addq %q2, %%r8\n" + "adcq $0, %%r9\n" + /* (r8,r9) += p4 * c1 */ + "movq %8, %%rax\n" + "mulq %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* Extract r1 */ + "movq %%r8, 8(%q6)\n" + "xorq %%r8, %%r8\n" + /* (r9,r8) += p4 */ + "addq %%r10, %%r9\n" + "adcq $0, %%r8\n" + /* (r9,r8) += p2 */ + "addq %q3, %%r9\n" + "adcq $0, %%r8\n" + /* Extract r2 */ + "movq %%r9, 16(%q6)\n" + "xorq %%r9, %%r9\n" + /* (r8,r9) += p3 */ + "addq %q4, %%r8\n" + "adcq $0, %%r9\n" + /* Extract r3 */ + "movq %%r8, 24(%q6)\n" + /* Extract c */ + "movq %%r9, %q0\n" + : "=g"(c) + : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "cc", "memory"); + + SECP256K1_CHECKMEM_MSAN_DEFINE(r, sizeof(*r)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&c, sizeof(c)); + +#else + rustsecp256k1_v0_11_uint128 c128; + uint64_t c, c0, c1, c2; + uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7]; + uint64_t m0, m1, m2, m3, m4, m5; + uint32_t m6; + uint64_t p0, p1, p2, p3; + uint32_t p4; + + /* Reduce 512 bits into 385. */ + /* m[0..6] = l[0..3] + n[0..3] * SECP256K1_N_C. */ + c0 = l[0]; c1 = 0; c2 = 0; + muladd_fast(n0, SECP256K1_N_C_0); + extract_fast(m0); + sumadd_fast(l[1]); + muladd(n1, SECP256K1_N_C_0); + muladd(n0, SECP256K1_N_C_1); + extract(m1); + sumadd(l[2]); + muladd(n2, SECP256K1_N_C_0); + muladd(n1, SECP256K1_N_C_1); + sumadd(n0); + extract(m2); + sumadd(l[3]); + muladd(n3, SECP256K1_N_C_0); + muladd(n2, SECP256K1_N_C_1); + sumadd(n1); + extract(m3); + muladd(n3, SECP256K1_N_C_1); + sumadd(n2); + extract(m4); + sumadd_fast(n3); + extract_fast(m5); + VERIFY_CHECK(c0 <= 1); + m6 = c0; + + /* Reduce 385 bits into 258. */ + /* p[0..4] = m[0..3] + m[4..6] * SECP256K1_N_C. */ + c0 = m0; c1 = 0; c2 = 0; + muladd_fast(m4, SECP256K1_N_C_0); + extract_fast(p0); + sumadd_fast(m1); + muladd(m5, SECP256K1_N_C_0); + muladd(m4, SECP256K1_N_C_1); + extract(p1); + sumadd(m2); + muladd(m6, SECP256K1_N_C_0); + muladd(m5, SECP256K1_N_C_1); + sumadd(m4); + extract(p2); + sumadd_fast(m3); + muladd_fast(m6, SECP256K1_N_C_1); + sumadd_fast(m5); + extract_fast(p3); + p4 = c0 + m6; + VERIFY_CHECK(p4 <= 2); + + /* Reduce 258 bits into 256. */ + /* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */ + rustsecp256k1_v0_11_u128_from_u64(&c128, p0); + rustsecp256k1_v0_11_u128_accum_mul(&c128, SECP256K1_N_C_0, p4); + r->d[0] = rustsecp256k1_v0_11_u128_to_u64(&c128); rustsecp256k1_v0_11_u128_rshift(&c128, 64); + rustsecp256k1_v0_11_u128_accum_u64(&c128, p1); + rustsecp256k1_v0_11_u128_accum_mul(&c128, SECP256K1_N_C_1, p4); + r->d[1] = rustsecp256k1_v0_11_u128_to_u64(&c128); rustsecp256k1_v0_11_u128_rshift(&c128, 64); + rustsecp256k1_v0_11_u128_accum_u64(&c128, p2); + rustsecp256k1_v0_11_u128_accum_u64(&c128, p4); + r->d[2] = rustsecp256k1_v0_11_u128_to_u64(&c128); rustsecp256k1_v0_11_u128_rshift(&c128, 64); + rustsecp256k1_v0_11_u128_accum_u64(&c128, p3); + r->d[3] = rustsecp256k1_v0_11_u128_to_u64(&c128); + c = rustsecp256k1_v0_11_u128_hi_u64(&c128); +#endif + + /* Final reduction of r. */ + rustsecp256k1_v0_11_scalar_reduce(r, c + rustsecp256k1_v0_11_scalar_check_overflow(r)); +} + +static void rustsecp256k1_v0_11_scalar_mul_512(uint64_t *l8, const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b) { +#ifdef USE_ASM_X86_64 + const uint64_t *pb = b->d; + __asm__ __volatile__( + /* Preload */ + "movq 0(%%rdi), %%r15\n" + "movq 8(%%rdi), %%rbx\n" + "movq 16(%%rdi), %%rcx\n" + "movq 0(%%rdx), %%r11\n" + "movq 8(%%rdx), %%r12\n" + "movq 16(%%rdx), %%r13\n" + "movq 24(%%rdx), %%r14\n" + /* (rax,rdx) = a0 * b0 */ + "movq %%r15, %%rax\n" + "mulq %%r11\n" + /* Extract l8[0] */ + "movq %%rax, 0(%%rsi)\n" + /* (r8,r9,r10) = (rdx) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += a0 * b1 */ + "movq %%r15, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a1 * b0 */ + "movq %%rbx, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l8[1] */ + "movq %%r8, 8(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += a0 * b2 */ + "movq %%r15, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a1 * b1 */ + "movq %%rbx, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a2 * b0 */ + "movq %%rcx, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l8[2] */ + "movq %%r9, 16(%%rsi)\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += a0 * b3 */ + "movq %%r15, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Preload a3 */ + "movq 24(%%rdi), %%r15\n" + /* (r10,r8,r9) += a1 * b2 */ + "movq %%rbx, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += a2 * b1 */ + "movq %%rcx, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += a3 * b0 */ + "movq %%r15, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Extract l8[3] */ + "movq %%r10, 24(%%rsi)\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += a1 * b3 */ + "movq %%rbx, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a2 * b2 */ + "movq %%rcx, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a3 * b1 */ + "movq %%r15, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l8[4] */ + "movq %%r8, 32(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += a2 * b3 */ + "movq %%rcx, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a3 * b2 */ + "movq %%r15, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l8[5] */ + "movq %%r9, 40(%%rsi)\n" + /* (r10,r8) += a3 * b3 */ + "movq %%r15, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + /* Extract l8[6] */ + "movq %%r10, 48(%%rsi)\n" + /* Extract l8[7] */ + "movq %%r8, 56(%%rsi)\n" + : "+d"(pb) + : "S"(l8), "D"(a->d) + : "rax", "rbx", "rcx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "cc", "memory"); + + SECP256K1_CHECKMEM_MSAN_DEFINE(l8, sizeof(*l8) * 8); + +#else + /* 160 bit accumulator. */ + uint64_t c0 = 0, c1 = 0; + uint32_t c2 = 0; + + /* l8[0..7] = a[0..3] * b[0..3]. */ + muladd_fast(a->d[0], b->d[0]); + extract_fast(l8[0]); + muladd(a->d[0], b->d[1]); + muladd(a->d[1], b->d[0]); + extract(l8[1]); + muladd(a->d[0], b->d[2]); + muladd(a->d[1], b->d[1]); + muladd(a->d[2], b->d[0]); + extract(l8[2]); + muladd(a->d[0], b->d[3]); + muladd(a->d[1], b->d[2]); + muladd(a->d[2], b->d[1]); + muladd(a->d[3], b->d[0]); + extract(l8[3]); + muladd(a->d[1], b->d[3]); + muladd(a->d[2], b->d[2]); + muladd(a->d[3], b->d[1]); + extract(l8[4]); + muladd(a->d[2], b->d[3]); + muladd(a->d[3], b->d[2]); + extract(l8[5]); + muladd_fast(a->d[3], b->d[3]); + extract_fast(l8[6]); + VERIFY_CHECK(c1 == 0); + l8[7] = c0; +#endif +} + +#undef sumadd +#undef sumadd_fast +#undef muladd +#undef muladd_fast +#undef extract +#undef extract_fast + +static void rustsecp256k1_v0_11_scalar_mul(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b) { + uint64_t l[8]; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + rustsecp256k1_v0_11_scalar_mul_512(l, a, b); + rustsecp256k1_v0_11_scalar_reduce_512(r, l); + + SECP256K1_SCALAR_VERIFY(r); +} + +static void rustsecp256k1_v0_11_scalar_split_128(rustsecp256k1_v0_11_scalar *r1, rustsecp256k1_v0_11_scalar *r2, const rustsecp256k1_v0_11_scalar *k) { + SECP256K1_SCALAR_VERIFY(k); + + r1->d[0] = k->d[0]; + r1->d[1] = k->d[1]; + r1->d[2] = 0; + r1->d[3] = 0; + r2->d[0] = k->d[2]; + r2->d[1] = k->d[3]; + r2->d[2] = 0; + r2->d[3] = 0; + + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); +} + +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_eq(const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b) { + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0; +} + +SECP256K1_INLINE static void rustsecp256k1_v0_11_scalar_mul_shift_var(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b, unsigned int shift) { + uint64_t l[8]; + unsigned int shiftlimbs; + unsigned int shiftlow; + unsigned int shifthigh; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + VERIFY_CHECK(shift >= 256); + + rustsecp256k1_v0_11_scalar_mul_512(l, a, b); + shiftlimbs = shift >> 6; + shiftlow = shift & 0x3F; + shifthigh = 64 - shiftlow; + r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0; + rustsecp256k1_v0_11_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); + + SECP256K1_SCALAR_VERIFY(r); +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_scalar_cmov(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, int flag) { + uint64_t mask0, mask1; + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d)); + + mask0 = vflag + ~((uint64_t)0); + mask1 = ~mask0; + r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); + r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1); + r->d[2] = (r->d[2] & mask0) | (a->d[2] & mask1); + r->d[3] = (r->d[3] & mask0) | (a->d[3] & mask1); + + SECP256K1_SCALAR_VERIFY(r); +} + +static void rustsecp256k1_v0_11_scalar_from_signed62(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_modinv64_signed62 *a) { + const uint64_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4]; + + /* The output from rustsecp256k1_v0_11_modinv64{_var} should be normalized to range [0,modulus), and + * have limbs in [0,2^62). The modulus is < 2^256, so the top limb must be below 2^(256-62*4). + */ + VERIFY_CHECK(a0 >> 62 == 0); + VERIFY_CHECK(a1 >> 62 == 0); + VERIFY_CHECK(a2 >> 62 == 0); + VERIFY_CHECK(a3 >> 62 == 0); + VERIFY_CHECK(a4 >> 8 == 0); + + r->d[0] = a0 | a1 << 62; + r->d[1] = a1 >> 2 | a2 << 60; + r->d[2] = a2 >> 4 | a3 << 58; + r->d[3] = a3 >> 6 | a4 << 56; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void rustsecp256k1_v0_11_scalar_to_signed62(rustsecp256k1_v0_11_modinv64_signed62 *r, const rustsecp256k1_v0_11_scalar *a) { + const uint64_t M62 = UINT64_MAX >> 2; + const uint64_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3]; + SECP256K1_SCALAR_VERIFY(a); + + r->v[0] = a0 & M62; + r->v[1] = (a0 >> 62 | a1 << 2) & M62; + r->v[2] = (a1 >> 60 | a2 << 4) & M62; + r->v[3] = (a2 >> 58 | a3 << 6) & M62; + r->v[4] = a3 >> 56; +} + +static const rustsecp256k1_v0_11_modinv64_modinfo rustsecp256k1_v0_11_const_modinfo_scalar = { + {{0x3FD25E8CD0364141LL, 0x2ABB739ABD2280EELL, -0x15LL, 0, 256}}, + 0x34F20099AA774EC1LL +}; + +static void rustsecp256k1_v0_11_scalar_inverse(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *x) { + rustsecp256k1_v0_11_modinv64_signed62 s; +#ifdef VERIFY + int zero_in = rustsecp256k1_v0_11_scalar_is_zero(x); +#endif + SECP256K1_SCALAR_VERIFY(x); + + rustsecp256k1_v0_11_scalar_to_signed62(&s, x); + rustsecp256k1_v0_11_modinv64(&s, &rustsecp256k1_v0_11_const_modinfo_scalar); + rustsecp256k1_v0_11_scalar_from_signed62(r, &s); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(rustsecp256k1_v0_11_scalar_is_zero(r) == zero_in); +} + +static void rustsecp256k1_v0_11_scalar_inverse_var(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *x) { + rustsecp256k1_v0_11_modinv64_signed62 s; +#ifdef VERIFY + int zero_in = rustsecp256k1_v0_11_scalar_is_zero(x); +#endif + SECP256K1_SCALAR_VERIFY(x); + + rustsecp256k1_v0_11_scalar_to_signed62(&s, x); + rustsecp256k1_v0_11_modinv64_var(&s, &rustsecp256k1_v0_11_const_modinfo_scalar); + rustsecp256k1_v0_11_scalar_from_signed62(r, &s); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(rustsecp256k1_v0_11_scalar_is_zero(r) == zero_in); +} + +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_is_even(const rustsecp256k1_v0_11_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return !(a->d[0] & 1); +} + +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_8x32.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_8x32.h similarity index 95% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_8x32.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_8x32.h index 2e70db25..8946c40c 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_8x32.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_8x32.h @@ -12,7 +12,7 @@ /** A scalar modulo the group order of the secp256k1 curve. */ typedef struct { uint32_t d[8]; -} rustsecp256k1zkp_v0_8_0_scalar; +} rustsecp256k1_v0_11_scalar; #define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_8x32_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_8x32_impl.h similarity index 58% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_8x32_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_8x32_impl.h index 0ce9a058..ccb4b22b 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_8x32_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_8x32_impl.h @@ -7,9 +7,9 @@ #ifndef SECP256K1_SCALAR_REPR_IMPL_H #define SECP256K1_SCALAR_REPR_IMPL_H -#include - +#include "checkmem.h" #include "modinv32_impl.h" +#include "util.h" /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint32_t)0xD0364141UL) @@ -38,18 +38,7 @@ #define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL) #define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL) -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_scalar_clear(rustsecp256k1zkp_v0_8_0_scalar *r) { - r->d[0] = 0; - r->d[1] = 0; - r->d[2] = 0; - r->d[3] = 0; - r->d[4] = 0; - r->d[5] = 0; - r->d[6] = 0; - r->d[7] = 0; -} - -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_scalar_set_int(rustsecp256k1zkp_v0_8_0_scalar *r, unsigned int v) { +SECP256K1_INLINE static void rustsecp256k1_v0_11_scalar_set_int(rustsecp256k1_v0_11_scalar *r, unsigned int v) { r->d[0] = v; r->d[1] = 0; r->d[2] = 0; @@ -58,36 +47,32 @@ SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_scalar_set_int(rustsecp256k r->d[5] = 0; r->d[6] = 0; r->d[7] = 0; -} -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_scalar_set_u64(rustsecp256k1zkp_v0_8_0_scalar *r, uint64_t v) { - r->d[0] = v; - r->d[1] = v >> 32; - r->d[2] = 0; - r->d[3] = 0; - r->d[4] = 0; - r->d[5] = 0; - r->d[6] = 0; - r->d[7] = 0; + SECP256K1_SCALAR_VERIFY(r); } -SECP256K1_INLINE static unsigned int rustsecp256k1zkp_v0_8_0_scalar_get_bits(const rustsecp256k1zkp_v0_8_0_scalar *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static uint32_t rustsecp256k1_v0_11_scalar_get_bits_limb32(const rustsecp256k1_v0_11_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + VERIFY_CHECK(count > 0 && count <= 32); VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); - return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1); + + return (a->d[offset >> 5] >> (offset & 0x1F)) & (0xFFFFFFFF >> (32 - count)); } -SECP256K1_INLINE static unsigned int rustsecp256k1zkp_v0_8_0_scalar_get_bits_var(const rustsecp256k1zkp_v0_8_0_scalar *a, unsigned int offset, unsigned int count) { - VERIFY_CHECK(count < 32); +SECP256K1_INLINE static uint32_t rustsecp256k1_v0_11_scalar_get_bits_var(const rustsecp256k1_v0_11_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + VERIFY_CHECK(count > 0 && count <= 32); VERIFY_CHECK(offset + count <= 256); + if ((offset + count - 1) >> 5 == offset >> 5) { - return rustsecp256k1zkp_v0_8_0_scalar_get_bits(a, offset, count); + return rustsecp256k1_v0_11_scalar_get_bits_limb32(a, offset, count); } else { VERIFY_CHECK((offset >> 5) + 1 < 8); - return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & ((((uint32_t)1) << count) - 1); + return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & (0xFFFFFFFF >> (32 - count)); } } -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_check_overflow(const rustsecp256k1zkp_v0_8_0_scalar *a) { +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_check_overflow(const rustsecp256k1_v0_11_scalar *a) { int yes = 0; int no = 0; no |= (a->d[7] < SECP256K1_N_7); /* No need for a > check. */ @@ -105,9 +90,10 @@ SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_check_overflow(const return yes; } -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_reduce(rustsecp256k1zkp_v0_8_0_scalar *r, uint32_t overflow) { +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_reduce(rustsecp256k1_v0_11_scalar *r, uint32_t overflow) { uint64_t t; VERIFY_CHECK(overflow <= 1); + t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; r->d[0] = t & 0xFFFFFFFFUL; t >>= 32; t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1; @@ -124,12 +110,17 @@ SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_reduce(rustsecp256k1z r->d[6] = t & 0xFFFFFFFFUL; t >>= 32; t += (uint64_t)r->d[7]; r->d[7] = t & 0xFFFFFFFFUL; + + SECP256K1_SCALAR_VERIFY(r); return overflow; } -static int rustsecp256k1zkp_v0_8_0_scalar_add(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b) { +static int rustsecp256k1_v0_11_scalar_add(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b) { int overflow; uint64_t t = (uint64_t)a->d[0] + b->d[0]; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)a->d[1] + b->d[1]; r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; @@ -145,16 +136,21 @@ static int rustsecp256k1zkp_v0_8_0_scalar_add(rustsecp256k1zkp_v0_8_0_scalar *r, r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)a->d[7] + b->d[7]; r->d[7] = t & 0xFFFFFFFFULL; t >>= 32; - overflow = t + rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r); + overflow = t + rustsecp256k1_v0_11_scalar_check_overflow(r); VERIFY_CHECK(overflow == 0 || overflow == 1); - rustsecp256k1zkp_v0_8_0_scalar_reduce(r, overflow); + rustsecp256k1_v0_11_scalar_reduce(r, overflow); + + SECP256K1_SCALAR_VERIFY(r); return overflow; } -static void rustsecp256k1zkp_v0_8_0_scalar_cadd_bit(rustsecp256k1zkp_v0_8_0_scalar *r, unsigned int bit, int flag) { +static void rustsecp256k1_v0_11_scalar_cadd_bit(rustsecp256k1_v0_11_scalar *r, unsigned int bit, int flag) { uint64_t t; + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(r); VERIFY_CHECK(bit < 256); - bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ + + bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F)); @@ -171,46 +167,53 @@ static void rustsecp256k1zkp_v0_8_0_scalar_cadd_bit(rustsecp256k1zkp_v0_8_0_scal r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F)); r->d[7] = t & 0xFFFFFFFFULL; -#ifdef VERIFY + + SECP256K1_SCALAR_VERIFY(r); VERIFY_CHECK((t >> 32) == 0); - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r) == 0); -#endif } -static void rustsecp256k1zkp_v0_8_0_scalar_set_b32(rustsecp256k1zkp_v0_8_0_scalar *r, const unsigned char *b32, int *overflow) { +static void rustsecp256k1_v0_11_scalar_set_b32(rustsecp256k1_v0_11_scalar *r, const unsigned char *b32, int *overflow) { int over; - r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24; - r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24; - r->d[2] = (uint32_t)b32[23] | (uint32_t)b32[22] << 8 | (uint32_t)b32[21] << 16 | (uint32_t)b32[20] << 24; - r->d[3] = (uint32_t)b32[19] | (uint32_t)b32[18] << 8 | (uint32_t)b32[17] << 16 | (uint32_t)b32[16] << 24; - r->d[4] = (uint32_t)b32[15] | (uint32_t)b32[14] << 8 | (uint32_t)b32[13] << 16 | (uint32_t)b32[12] << 24; - r->d[5] = (uint32_t)b32[11] | (uint32_t)b32[10] << 8 | (uint32_t)b32[9] << 16 | (uint32_t)b32[8] << 24; - r->d[6] = (uint32_t)b32[7] | (uint32_t)b32[6] << 8 | (uint32_t)b32[5] << 16 | (uint32_t)b32[4] << 24; - r->d[7] = (uint32_t)b32[3] | (uint32_t)b32[2] << 8 | (uint32_t)b32[1] << 16 | (uint32_t)b32[0] << 24; - over = rustsecp256k1zkp_v0_8_0_scalar_reduce(r, rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r)); + r->d[0] = rustsecp256k1_v0_11_read_be32(&b32[28]); + r->d[1] = rustsecp256k1_v0_11_read_be32(&b32[24]); + r->d[2] = rustsecp256k1_v0_11_read_be32(&b32[20]); + r->d[3] = rustsecp256k1_v0_11_read_be32(&b32[16]); + r->d[4] = rustsecp256k1_v0_11_read_be32(&b32[12]); + r->d[5] = rustsecp256k1_v0_11_read_be32(&b32[8]); + r->d[6] = rustsecp256k1_v0_11_read_be32(&b32[4]); + r->d[7] = rustsecp256k1_v0_11_read_be32(&b32[0]); + over = rustsecp256k1_v0_11_scalar_reduce(r, rustsecp256k1_v0_11_scalar_check_overflow(r)); if (overflow) { *overflow = over; } + + SECP256K1_SCALAR_VERIFY(r); } -static void rustsecp256k1zkp_v0_8_0_scalar_get_b32(unsigned char *bin, const rustsecp256k1zkp_v0_8_0_scalar* a) { - bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7]; - bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6]; - bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5]; - bin[12] = a->d[4] >> 24; bin[13] = a->d[4] >> 16; bin[14] = a->d[4] >> 8; bin[15] = a->d[4]; - bin[16] = a->d[3] >> 24; bin[17] = a->d[3] >> 16; bin[18] = a->d[3] >> 8; bin[19] = a->d[3]; - bin[20] = a->d[2] >> 24; bin[21] = a->d[2] >> 16; bin[22] = a->d[2] >> 8; bin[23] = a->d[2]; - bin[24] = a->d[1] >> 24; bin[25] = a->d[1] >> 16; bin[26] = a->d[1] >> 8; bin[27] = a->d[1]; - bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; +static void rustsecp256k1_v0_11_scalar_get_b32(unsigned char *bin, const rustsecp256k1_v0_11_scalar* a) { + SECP256K1_SCALAR_VERIFY(a); + + rustsecp256k1_v0_11_write_be32(&bin[0], a->d[7]); + rustsecp256k1_v0_11_write_be32(&bin[4], a->d[6]); + rustsecp256k1_v0_11_write_be32(&bin[8], a->d[5]); + rustsecp256k1_v0_11_write_be32(&bin[12], a->d[4]); + rustsecp256k1_v0_11_write_be32(&bin[16], a->d[3]); + rustsecp256k1_v0_11_write_be32(&bin[20], a->d[2]); + rustsecp256k1_v0_11_write_be32(&bin[24], a->d[1]); + rustsecp256k1_v0_11_write_be32(&bin[28], a->d[0]); } -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_is_zero(const rustsecp256k1zkp_v0_8_0_scalar *a) { +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_is_zero(const rustsecp256k1_v0_11_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; } -static void rustsecp256k1zkp_v0_8_0_scalar_negate(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a) { - uint32_t nonzero = 0xFFFFFFFFUL * (rustsecp256k1zkp_v0_8_0_scalar_is_zero(a) == 0); +static void rustsecp256k1_v0_11_scalar_negate(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a) { + uint32_t nonzero = 0xFFFFFFFFUL * (rustsecp256k1_v0_11_scalar_is_zero(a) == 0); uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1; + SECP256K1_SCALAR_VERIFY(a); + r->d[0] = t & nonzero; t >>= 32; t += (uint64_t)(~a->d[1]) + SECP256K1_N_1; r->d[1] = t & nonzero; t >>= 32; @@ -226,15 +229,69 @@ static void rustsecp256k1zkp_v0_8_0_scalar_negate(rustsecp256k1zkp_v0_8_0_scalar r->d[6] = t & nonzero; t >>= 32; t += (uint64_t)(~a->d[7]) + SECP256K1_N_7; r->d[7] = t & nonzero; -} -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_is_one(const rustsecp256k1zkp_v0_8_0_scalar *a) { + SECP256K1_SCALAR_VERIFY(r); +} + +static void rustsecp256k1_v0_11_scalar_half(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a) { + /* Writing `/` for field division and `//` for integer division, we compute + * + * a/2 = (a - (a&1))/2 + (a&1)/2 + * = (a >> 1) + (a&1 ? 1/2 : 0) + * = (a >> 1) + (a&1 ? n//2+1 : 0), + * + * where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n). + * For n//2, we have the constants SECP256K1_N_H_0, ... + * + * This sum does not overflow. The most extreme case is a = -2, the largest odd scalar. Here: + * - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2 + * - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2 + * Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n. + */ + uint32_t mask = -(uint32_t)(a->d[0] & 1U); + uint64_t t = (uint32_t)((a->d[0] >> 1) | (a->d[1] << 31)); + SECP256K1_SCALAR_VERIFY(a); + + t += (SECP256K1_N_H_0 + 1U) & mask; + r->d[0] = t; t >>= 32; + t += (uint32_t)((a->d[1] >> 1) | (a->d[2] << 31)); + t += SECP256K1_N_H_1 & mask; + r->d[1] = t; t >>= 32; + t += (uint32_t)((a->d[2] >> 1) | (a->d[3] << 31)); + t += SECP256K1_N_H_2 & mask; + r->d[2] = t; t >>= 32; + t += (uint32_t)((a->d[3] >> 1) | (a->d[4] << 31)); + t += SECP256K1_N_H_3 & mask; + r->d[3] = t; t >>= 32; + t += (uint32_t)((a->d[4] >> 1) | (a->d[5] << 31)); + t += SECP256K1_N_H_4 & mask; + r->d[4] = t; t >>= 32; + t += (uint32_t)((a->d[5] >> 1) | (a->d[6] << 31)); + t += SECP256K1_N_H_5 & mask; + r->d[5] = t; t >>= 32; + t += (uint32_t)((a->d[6] >> 1) | (a->d[7] << 31)); + t += SECP256K1_N_H_6 & mask; + r->d[6] = t; t >>= 32; + r->d[7] = (uint32_t)t + (uint32_t)(a->d[7] >> 1) + (SECP256K1_N_H_7 & mask); + + /* The line above only computed the bottom 32 bits of r->d[7]. Redo the computation + * in full 64 bits to make sure the top 32 bits are indeed zero. */ + VERIFY_CHECK((t + (a->d[7] >> 1) + (SECP256K1_N_H_7 & mask)) >> 32 == 0); + + SECP256K1_SCALAR_VERIFY(r); +} + +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_is_one(const rustsecp256k1_v0_11_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; } -static int rustsecp256k1zkp_v0_8_0_scalar_is_high(const rustsecp256k1zkp_v0_8_0_scalar *a) { +static int rustsecp256k1_v0_11_scalar_is_high(const rustsecp256k1_v0_11_scalar *a) { int yes = 0; int no = 0; + SECP256K1_SCALAR_VERIFY(a); + no |= (a->d[7] < SECP256K1_N_H_7); yes |= (a->d[7] > SECP256K1_N_H_7) & ~no; no |= (a->d[6] < SECP256K1_N_H_6) & ~yes; /* No need for a > check. */ @@ -250,12 +307,15 @@ static int rustsecp256k1zkp_v0_8_0_scalar_is_high(const rustsecp256k1zkp_v0_8_0_ return yes; } -static int rustsecp256k1zkp_v0_8_0_scalar_cond_negate(rustsecp256k1zkp_v0_8_0_scalar *r, int flag) { +static int rustsecp256k1_v0_11_scalar_cond_negate(rustsecp256k1_v0_11_scalar *r, int flag) { /* If we are flag = 0, mask = 00...00 and this is a no-op; - * if we are flag = 1, mask = 11...11 and this is identical to rustsecp256k1zkp_v0_8_0_scalar_negate */ - uint32_t mask = !flag - 1; - uint32_t nonzero = 0xFFFFFFFFUL * (rustsecp256k1zkp_v0_8_0_scalar_is_zero(r) == 0); + * if we are flag = 1, mask = 11...11 and this is identical to rustsecp256k1_v0_11_scalar_negate */ + volatile int vflag = flag; + uint32_t mask = -vflag; + uint32_t nonzero = 0xFFFFFFFFUL * (rustsecp256k1_v0_11_scalar_is_zero(r) == 0); uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + SECP256K1_SCALAR_VERIFY(r); + r->d[0] = t & nonzero; t >>= 32; t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); r->d[1] = t & nonzero; t >>= 32; @@ -271,6 +331,8 @@ static int rustsecp256k1zkp_v0_8_0_scalar_cond_negate(rustsecp256k1zkp_v0_8_0_sc r->d[6] = t & nonzero; t >>= 32; t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask); r->d[7] = t & nonzero; + + SECP256K1_SCALAR_VERIFY(r); return 2 * (mask == 0) - 1; } @@ -306,28 +368,6 @@ static int rustsecp256k1zkp_v0_8_0_scalar_cond_negate(rustsecp256k1zkp_v0_8_0_sc VERIFY_CHECK(c1 >= th); \ } -/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define muladd2(a,b) { \ - uint32_t tl, th, th2, tl2; \ - { \ - uint64_t t = (uint64_t)a * b; \ - th = t >> 32; /* at most 0xFFFFFFFE */ \ - tl = t; \ - } \ - th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \ - c2 += (th2 < th); /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ - tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \ - th2 += (tl2 < tl); /* at most 0xFFFFFFFF */ \ - c0 += tl2; /* overflow is handled on the next line */ \ - th2 += (c0 < tl2); /* second overflow is handled on the next line */ \ - c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ - c1 += th2; /* overflow is handled on the next line */ \ - c2 += (c1 < th2); /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ -} - /** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ #define sumadd(a) { \ unsigned int over; \ @@ -361,7 +401,7 @@ static int rustsecp256k1zkp_v0_8_0_scalar_cond_negate(rustsecp256k1zkp_v0_8_0_sc VERIFY_CHECK(c2 == 0); \ } -static void rustsecp256k1zkp_v0_8_0_scalar_reduce_512(rustsecp256k1zkp_v0_8_0_scalar *r, const uint32_t *l) { +static void rustsecp256k1_v0_11_scalar_reduce_512(rustsecp256k1_v0_11_scalar *r, const uint32_t *l) { uint64_t c; uint32_t n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15]; uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12; @@ -500,10 +540,10 @@ static void rustsecp256k1zkp_v0_8_0_scalar_reduce_512(rustsecp256k1zkp_v0_8_0_sc r->d[7] = c & 0xFFFFFFFFUL; c >>= 32; /* Final reduction of r. */ - rustsecp256k1zkp_v0_8_0_scalar_reduce(r, c + rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r)); + rustsecp256k1_v0_11_scalar_reduce(r, c + rustsecp256k1_v0_11_scalar_check_overflow(r)); } -static void rustsecp256k1zkp_v0_8_0_scalar_mul_512(uint32_t *l, const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b) { +static void rustsecp256k1_v0_11_scalar_mul_512(uint32_t *l, const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b) { /* 96 bit accumulator. */ uint32_t c0 = 0, c1 = 0, c2 = 0; @@ -591,103 +631,27 @@ static void rustsecp256k1zkp_v0_8_0_scalar_mul_512(uint32_t *l, const rustsecp25 l[15] = c0; } -static void rustsecp256k1zkp_v0_8_0_scalar_sqr_512(uint32_t *l, const rustsecp256k1zkp_v0_8_0_scalar *a) { - /* 96 bit accumulator. */ - uint32_t c0 = 0, c1 = 0, c2 = 0; - - /* l[0..15] = a[0..7]^2. */ - muladd_fast(a->d[0], a->d[0]); - extract_fast(l[0]); - muladd2(a->d[0], a->d[1]); - extract(l[1]); - muladd2(a->d[0], a->d[2]); - muladd(a->d[1], a->d[1]); - extract(l[2]); - muladd2(a->d[0], a->d[3]); - muladd2(a->d[1], a->d[2]); - extract(l[3]); - muladd2(a->d[0], a->d[4]); - muladd2(a->d[1], a->d[3]); - muladd(a->d[2], a->d[2]); - extract(l[4]); - muladd2(a->d[0], a->d[5]); - muladd2(a->d[1], a->d[4]); - muladd2(a->d[2], a->d[3]); - extract(l[5]); - muladd2(a->d[0], a->d[6]); - muladd2(a->d[1], a->d[5]); - muladd2(a->d[2], a->d[4]); - muladd(a->d[3], a->d[3]); - extract(l[6]); - muladd2(a->d[0], a->d[7]); - muladd2(a->d[1], a->d[6]); - muladd2(a->d[2], a->d[5]); - muladd2(a->d[3], a->d[4]); - extract(l[7]); - muladd2(a->d[1], a->d[7]); - muladd2(a->d[2], a->d[6]); - muladd2(a->d[3], a->d[5]); - muladd(a->d[4], a->d[4]); - extract(l[8]); - muladd2(a->d[2], a->d[7]); - muladd2(a->d[3], a->d[6]); - muladd2(a->d[4], a->d[5]); - extract(l[9]); - muladd2(a->d[3], a->d[7]); - muladd2(a->d[4], a->d[6]); - muladd(a->d[5], a->d[5]); - extract(l[10]); - muladd2(a->d[4], a->d[7]); - muladd2(a->d[5], a->d[6]); - extract(l[11]); - muladd2(a->d[5], a->d[7]); - muladd(a->d[6], a->d[6]); - extract(l[12]); - muladd2(a->d[6], a->d[7]); - extract(l[13]); - muladd_fast(a->d[7], a->d[7]); - extract_fast(l[14]); - VERIFY_CHECK(c1 == 0); - l[15] = c0; -} - #undef sumadd #undef sumadd_fast #undef muladd #undef muladd_fast -#undef muladd2 #undef extract #undef extract_fast -static void rustsecp256k1zkp_v0_8_0_scalar_mul(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b) { - uint32_t l[16]; - rustsecp256k1zkp_v0_8_0_scalar_mul_512(l, a, b); - rustsecp256k1zkp_v0_8_0_scalar_reduce_512(r, l); -} - -static int rustsecp256k1zkp_v0_8_0_scalar_shr_int(rustsecp256k1zkp_v0_8_0_scalar *r, int n) { - int ret; - VERIFY_CHECK(n > 0); - VERIFY_CHECK(n < 16); - ret = r->d[0] & ((1 << n) - 1); - r->d[0] = (r->d[0] >> n) + (r->d[1] << (32 - n)); - r->d[1] = (r->d[1] >> n) + (r->d[2] << (32 - n)); - r->d[2] = (r->d[2] >> n) + (r->d[3] << (32 - n)); - r->d[3] = (r->d[3] >> n) + (r->d[4] << (32 - n)); - r->d[4] = (r->d[4] >> n) + (r->d[5] << (32 - n)); - r->d[5] = (r->d[5] >> n) + (r->d[6] << (32 - n)); - r->d[6] = (r->d[6] >> n) + (r->d[7] << (32 - n)); - r->d[7] = (r->d[7] >> n); - return ret; -} - -static void rustsecp256k1zkp_v0_8_0_scalar_sqr(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a) { +static void rustsecp256k1_v0_11_scalar_mul(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b) { uint32_t l[16]; - rustsecp256k1zkp_v0_8_0_scalar_sqr_512(l, a); - rustsecp256k1zkp_v0_8_0_scalar_reduce_512(r, l); + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + rustsecp256k1_v0_11_scalar_mul_512(l, a, b); + rustsecp256k1_v0_11_scalar_reduce_512(r, l); + + SECP256K1_SCALAR_VERIFY(r); } -static void rustsecp256k1zkp_v0_8_0_scalar_split_128(rustsecp256k1zkp_v0_8_0_scalar *r1, rustsecp256k1zkp_v0_8_0_scalar *r2, const rustsecp256k1zkp_v0_8_0_scalar *k) { +static void rustsecp256k1_v0_11_scalar_split_128(rustsecp256k1_v0_11_scalar *r1, rustsecp256k1_v0_11_scalar *r2, const rustsecp256k1_v0_11_scalar *k) { + SECP256K1_SCALAR_VERIFY(k); + r1->d[0] = k->d[0]; r1->d[1] = k->d[1]; r1->d[2] = k->d[2]; @@ -704,19 +668,28 @@ static void rustsecp256k1zkp_v0_8_0_scalar_split_128(rustsecp256k1zkp_v0_8_0_sca r2->d[5] = 0; r2->d[6] = 0; r2->d[7] = 0; + + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); } -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_eq(const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b) { +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_eq(const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b) { + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0; } -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_scalar_mul_shift_var(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, const rustsecp256k1zkp_v0_8_0_scalar *b, unsigned int shift) { +SECP256K1_INLINE static void rustsecp256k1_v0_11_scalar_mul_shift_var(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b, unsigned int shift) { uint32_t l[16]; unsigned int shiftlimbs; unsigned int shiftlow; unsigned int shifthigh; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); VERIFY_CHECK(shift >= 256); - rustsecp256k1zkp_v0_8_0_scalar_mul_512(l, a, b); + + rustsecp256k1_v0_11_scalar_mul_512(l, a, b); shiftlimbs = shift >> 5; shiftlow = shift & 0x1F; shifthigh = 32 - shiftlow; @@ -728,13 +701,18 @@ SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_scalar_mul_shift_var(rustse r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0; - rustsecp256k1zkp_v0_8_0_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); + rustsecp256k1_v0_11_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); + + SECP256K1_SCALAR_VERIFY(r); } -static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_scalar_cmov(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *a, int flag) { +static SECP256K1_INLINE void rustsecp256k1_v0_11_scalar_cmov(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, int flag) { uint32_t mask0, mask1; - VG_CHECK_VERIFY(r->d, sizeof(r->d)); - mask0 = flag + ~((uint32_t)0); + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d)); + + mask0 = vflag + ~((uint32_t)0); mask1 = ~mask0; r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1); @@ -744,108 +722,15 @@ static SECP256K1_INLINE void rustsecp256k1zkp_v0_8_0_scalar_cmov(rustsecp256k1zk r->d[5] = (r->d[5] & mask0) | (a->d[5] & mask1); r->d[6] = (r->d[6] & mask0) | (a->d[6] & mask1); r->d[7] = (r->d[7] & mask0) | (a->d[7] & mask1); -} - -#define ROTL32(x,n) ((x) << (n) | (x) >> (32-(n))) -#define QUARTERROUND(a,b,c,d) \ - a += b; d = ROTL32(d ^ a, 16); \ - c += d; b = ROTL32(b ^ c, 12); \ - a += b; d = ROTL32(d ^ a, 8); \ - c += d; b = ROTL32(b ^ c, 7); -#if defined(SECP256K1_BIG_ENDIAN) -#define LE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) -#elif defined(SECP256K1_LITTLE_ENDIAN) -#define LE32(p) (p) -#endif + SECP256K1_SCALAR_VERIFY(r); +} -static void rustsecp256k1zkp_v0_8_0_scalar_chacha20(rustsecp256k1zkp_v0_8_0_scalar *r1, rustsecp256k1zkp_v0_8_0_scalar *r2, const unsigned char *seed, uint64_t idx) { - size_t n; - size_t over_count = 0; - uint32_t seed32[8]; - uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; - int over1, over2; - - memcpy((void *) seed32, (const void *) seed, 32); - do { - x0 = 0x61707865; - x1 = 0x3320646e; - x2 = 0x79622d32; - x3 = 0x6b206574; - x4 = LE32(seed32[0]); - x5 = LE32(seed32[1]); - x6 = LE32(seed32[2]); - x7 = LE32(seed32[3]); - x8 = LE32(seed32[4]); - x9 = LE32(seed32[5]); - x10 = LE32(seed32[6]); - x11 = LE32(seed32[7]); - x12 = idx; - x13 = idx >> 32; - x14 = 0; - x15 = over_count; - - n = 10; - while (n--) { - QUARTERROUND(x0, x4, x8,x12) - QUARTERROUND(x1, x5, x9,x13) - QUARTERROUND(x2, x6,x10,x14) - QUARTERROUND(x3, x7,x11,x15) - QUARTERROUND(x0, x5,x10,x15) - QUARTERROUND(x1, x6,x11,x12) - QUARTERROUND(x2, x7, x8,x13) - QUARTERROUND(x3, x4, x9,x14) - } - - x0 += 0x61707865; - x1 += 0x3320646e; - x2 += 0x79622d32; - x3 += 0x6b206574; - x4 += LE32(seed32[0]); - x5 += LE32(seed32[1]); - x6 += LE32(seed32[2]); - x7 += LE32(seed32[3]); - x8 += LE32(seed32[4]); - x9 += LE32(seed32[5]); - x10 += LE32(seed32[6]); - x11 += LE32(seed32[7]); - x12 += idx; - x13 += idx >> 32; - x14 += 0; - x15 += over_count; - - r1->d[7] = x0; - r1->d[6] = x1; - r1->d[5] = x2; - r1->d[4] = x3; - r1->d[3] = x4; - r1->d[2] = x5; - r1->d[1] = x6; - r1->d[0] = x7; - r2->d[7] = x8; - r2->d[6] = x9; - r2->d[5] = x10; - r2->d[4] = x11; - r2->d[3] = x12; - r2->d[2] = x13; - r2->d[1] = x14; - r2->d[0] = x15; - - over1 = rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r1); - over2 = rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r2); - over_count++; - } while (over1 | over2); -} - -#undef ROTL32 -#undef QUARTERROUND -#undef LE32 - -static void rustsecp256k1zkp_v0_8_0_scalar_from_signed30(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_modinv32_signed30 *a) { +static void rustsecp256k1_v0_11_scalar_from_signed30(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_modinv32_signed30 *a) { const uint32_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4], a5 = a->v[5], a6 = a->v[6], a7 = a->v[7], a8 = a->v[8]; - /* The output from rustsecp256k1zkp_v0_8_0_modinv32{_var} should be normalized to range [0,modulus), and + /* The output from rustsecp256k1_v0_11_modinv32{_var} should be normalized to range [0,modulus), and * have limbs in [0,2^30). The modulus is < 2^256, so the top limb must be below 2^(256-30*8). */ VERIFY_CHECK(a0 >> 30 == 0); @@ -867,19 +752,14 @@ static void rustsecp256k1zkp_v0_8_0_scalar_from_signed30(rustsecp256k1zkp_v0_8_0 r->d[6] = a6 >> 12 | a7 << 18; r->d[7] = a7 >> 14 | a8 << 16; -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_scalar_check_overflow(r) == 0); -#endif + SECP256K1_SCALAR_VERIFY(r); } -static void rustsecp256k1zkp_v0_8_0_scalar_to_signed30(rustsecp256k1zkp_v0_8_0_modinv32_signed30 *r, const rustsecp256k1zkp_v0_8_0_scalar *a) { +static void rustsecp256k1_v0_11_scalar_to_signed30(rustsecp256k1_v0_11_modinv32_signed30 *r, const rustsecp256k1_v0_11_scalar *a) { const uint32_t M30 = UINT32_MAX >> 2; const uint32_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3], a4 = a->d[4], a5 = a->d[5], a6 = a->d[6], a7 = a->d[7]; - -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_scalar_check_overflow(a) == 0); -#endif + SECP256K1_SCALAR_VERIFY(a); r->v[0] = a0 & M30; r->v[1] = (a0 >> 30 | a1 << 2) & M30; @@ -892,40 +772,44 @@ static void rustsecp256k1zkp_v0_8_0_scalar_to_signed30(rustsecp256k1zkp_v0_8_0_m r->v[8] = a7 >> 16; } -static const rustsecp256k1zkp_v0_8_0_modinv32_modinfo rustsecp256k1zkp_v0_8_0_const_modinfo_scalar = { +static const rustsecp256k1_v0_11_modinv32_modinfo rustsecp256k1_v0_11_const_modinfo_scalar = { {{0x10364141L, 0x3F497A33L, 0x348A03BBL, 0x2BB739ABL, -0x146L, 0, 0, 0, 65536}}, 0x2A774EC1L }; -static void rustsecp256k1zkp_v0_8_0_scalar_inverse(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *x) { - rustsecp256k1zkp_v0_8_0_modinv32_signed30 s; +static void rustsecp256k1_v0_11_scalar_inverse(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *x) { + rustsecp256k1_v0_11_modinv32_signed30 s; #ifdef VERIFY - int zero_in = rustsecp256k1zkp_v0_8_0_scalar_is_zero(x); + int zero_in = rustsecp256k1_v0_11_scalar_is_zero(x); #endif - rustsecp256k1zkp_v0_8_0_scalar_to_signed30(&s, x); - rustsecp256k1zkp_v0_8_0_modinv32(&s, &rustsecp256k1zkp_v0_8_0_const_modinfo_scalar); - rustsecp256k1zkp_v0_8_0_scalar_from_signed30(r, &s); + SECP256K1_SCALAR_VERIFY(x); -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_scalar_is_zero(r) == zero_in); -#endif + rustsecp256k1_v0_11_scalar_to_signed30(&s, x); + rustsecp256k1_v0_11_modinv32(&s, &rustsecp256k1_v0_11_const_modinfo_scalar); + rustsecp256k1_v0_11_scalar_from_signed30(r, &s); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(rustsecp256k1_v0_11_scalar_is_zero(r) == zero_in); } -static void rustsecp256k1zkp_v0_8_0_scalar_inverse_var(rustsecp256k1zkp_v0_8_0_scalar *r, const rustsecp256k1zkp_v0_8_0_scalar *x) { - rustsecp256k1zkp_v0_8_0_modinv32_signed30 s; +static void rustsecp256k1_v0_11_scalar_inverse_var(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *x) { + rustsecp256k1_v0_11_modinv32_signed30 s; #ifdef VERIFY - int zero_in = rustsecp256k1zkp_v0_8_0_scalar_is_zero(x); + int zero_in = rustsecp256k1_v0_11_scalar_is_zero(x); #endif - rustsecp256k1zkp_v0_8_0_scalar_to_signed30(&s, x); - rustsecp256k1zkp_v0_8_0_modinv32_var(&s, &rustsecp256k1zkp_v0_8_0_const_modinfo_scalar); - rustsecp256k1zkp_v0_8_0_scalar_from_signed30(r, &s); + SECP256K1_SCALAR_VERIFY(x); -#ifdef VERIFY - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_scalar_is_zero(r) == zero_in); -#endif + rustsecp256k1_v0_11_scalar_to_signed30(&s, x); + rustsecp256k1_v0_11_modinv32_var(&s, &rustsecp256k1_v0_11_const_modinfo_scalar); + rustsecp256k1_v0_11_scalar_from_signed30(r, &s); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(rustsecp256k1_v0_11_scalar_is_zero(r) == zero_in); } -SECP256K1_INLINE static int rustsecp256k1zkp_v0_8_0_scalar_is_even(const rustsecp256k1zkp_v0_8_0_scalar *a) { +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_is_even(const rustsecp256k1_v0_11_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + return !(a->d[0] & 1); } diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_impl.h similarity index 67% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_impl.h index 3b8d0f7d..6bf4178a 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scalar_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_impl.h @@ -14,10 +14,6 @@ #include "scalar.h" #include "util.h" -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - #if defined(EXHAUSTIVE_TEST_ORDER) #include "scalar_low_impl.h" #elif defined(SECP256K1_WIDEMUL_INT128) @@ -28,24 +24,39 @@ #error "Please select wide multiplication implementation" #endif -static const rustsecp256k1zkp_v0_8_0_scalar rustsecp256k1zkp_v0_8_0_scalar_one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); -static const rustsecp256k1zkp_v0_8_0_scalar rustsecp256k1zkp_v0_8_0_scalar_zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); +static const rustsecp256k1_v0_11_scalar rustsecp256k1_v0_11_scalar_one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); +static const rustsecp256k1_v0_11_scalar rustsecp256k1_v0_11_scalar_zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + +SECP256K1_INLINE static void rustsecp256k1_v0_11_scalar_clear(rustsecp256k1_v0_11_scalar *r) { + rustsecp256k1_v0_11_memclear(r, sizeof(rustsecp256k1_v0_11_scalar)); +} -static int rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(rustsecp256k1zkp_v0_8_0_scalar *r, const unsigned char *bin) { +static int rustsecp256k1_v0_11_scalar_set_b32_seckey(rustsecp256k1_v0_11_scalar *r, const unsigned char *bin) { int overflow; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(r, bin, &overflow); - return (!overflow) & (!rustsecp256k1zkp_v0_8_0_scalar_is_zero(r)); + rustsecp256k1_v0_11_scalar_set_b32(r, bin, &overflow); + + SECP256K1_SCALAR_VERIFY(r); + return (!overflow) & (!rustsecp256k1_v0_11_scalar_is_zero(r)); +} + +static void rustsecp256k1_v0_11_scalar_verify(const rustsecp256k1_v0_11_scalar *r) { + VERIFY_CHECK(rustsecp256k1_v0_11_scalar_check_overflow(r) == 0); + + (void)r; } -/* These parameters are generated using sage/gen_exhaustive_groups.sage. */ #if defined(EXHAUSTIVE_TEST_ORDER) -# if EXHAUSTIVE_TEST_ORDER == 13 +/* Begin of section generated by sage/gen_exhaustive_groups.sage. */ +# if EXHAUSTIVE_TEST_ORDER == 7 +# define EXHAUSTIVE_TEST_LAMBDA 2 +# elif EXHAUSTIVE_TEST_ORDER == 13 # define EXHAUSTIVE_TEST_LAMBDA 9 # elif EXHAUSTIVE_TEST_ORDER == 199 # define EXHAUSTIVE_TEST_LAMBDA 92 # else # error No known lambda for the specified exhaustive test group order. # endif +/* End of section generated by sage/gen_exhaustive_groups.sage. */ /** * Find r1 and r2 given k, such that r1 + r2 * lambda == k mod n; unlike in the @@ -53,21 +64,29 @@ static int rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(rustsecp256k1zkp_v0_8_0 * nontrivial to get full test coverage for the exhaustive tests. We therefore * (arbitrarily) set r2 = k + 5 (mod n) and r1 = k - r2 * lambda (mod n). */ -static void rustsecp256k1zkp_v0_8_0_scalar_split_lambda(rustsecp256k1zkp_v0_8_0_scalar *r1, rustsecp256k1zkp_v0_8_0_scalar *r2, const rustsecp256k1zkp_v0_8_0_scalar *k) { +static void rustsecp256k1_v0_11_scalar_split_lambda(rustsecp256k1_v0_11_scalar * SECP256K1_RESTRICT r1, rustsecp256k1_v0_11_scalar * SECP256K1_RESTRICT r2, const rustsecp256k1_v0_11_scalar * SECP256K1_RESTRICT k) { + SECP256K1_SCALAR_VERIFY(k); + VERIFY_CHECK(r1 != k); + VERIFY_CHECK(r2 != k); + VERIFY_CHECK(r1 != r2); + *r2 = (*k + 5) % EXHAUSTIVE_TEST_ORDER; *r1 = (*k + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; + + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); } #else /** * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where * lambda is: */ -static const rustsecp256k1zkp_v0_8_0_scalar rustsecp256k1zkp_v0_8_0_const_lambda = SECP256K1_SCALAR_CONST( +static const rustsecp256k1_v0_11_scalar rustsecp256k1_v0_11_const_lambda = SECP256K1_SCALAR_CONST( 0x5363AD4CUL, 0xC05C30E0UL, 0xA5261C02UL, 0x8812645AUL, 0x122E22EAUL, 0x20816678UL, 0xDF02967CUL, 0x1B23BD72UL ); #ifdef VERIFY -static void rustsecp256k1zkp_v0_8_0_scalar_split_lambda_verify(const rustsecp256k1zkp_v0_8_0_scalar *r1, const rustsecp256k1zkp_v0_8_0_scalar *r2, const rustsecp256k1zkp_v0_8_0_scalar *k); +static void rustsecp256k1_v0_11_scalar_split_lambda_verify(const rustsecp256k1_v0_11_scalar *r1, const rustsecp256k1_v0_11_scalar *r2, const rustsecp256k1_v0_11_scalar *k); #endif /* @@ -120,44 +139,49 @@ static void rustsecp256k1zkp_v0_8_0_scalar_split_lambda_verify(const rustsecp256 * * See proof below. */ -static void rustsecp256k1zkp_v0_8_0_scalar_split_lambda(rustsecp256k1zkp_v0_8_0_scalar *r1, rustsecp256k1zkp_v0_8_0_scalar *r2, const rustsecp256k1zkp_v0_8_0_scalar *k) { - rustsecp256k1zkp_v0_8_0_scalar c1, c2; - static const rustsecp256k1zkp_v0_8_0_scalar minus_b1 = SECP256K1_SCALAR_CONST( +static void rustsecp256k1_v0_11_scalar_split_lambda(rustsecp256k1_v0_11_scalar * SECP256K1_RESTRICT r1, rustsecp256k1_v0_11_scalar * SECP256K1_RESTRICT r2, const rustsecp256k1_v0_11_scalar * SECP256K1_RESTRICT k) { + rustsecp256k1_v0_11_scalar c1, c2; + static const rustsecp256k1_v0_11_scalar minus_b1 = SECP256K1_SCALAR_CONST( 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL ); - static const rustsecp256k1zkp_v0_8_0_scalar minus_b2 = SECP256K1_SCALAR_CONST( + static const rustsecp256k1_v0_11_scalar minus_b2 = SECP256K1_SCALAR_CONST( 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL ); - static const rustsecp256k1zkp_v0_8_0_scalar g1 = SECP256K1_SCALAR_CONST( + static const rustsecp256k1_v0_11_scalar g1 = SECP256K1_SCALAR_CONST( 0x3086D221UL, 0xA7D46BCDUL, 0xE86C90E4UL, 0x9284EB15UL, 0x3DAA8A14UL, 0x71E8CA7FUL, 0xE893209AUL, 0x45DBB031UL ); - static const rustsecp256k1zkp_v0_8_0_scalar g2 = SECP256K1_SCALAR_CONST( + static const rustsecp256k1_v0_11_scalar g2 = SECP256K1_SCALAR_CONST( 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C4UL, 0x221208ACUL, 0x9DF506C6UL, 0x1571B4AEUL, 0x8AC47F71UL ); + SECP256K1_SCALAR_VERIFY(k); VERIFY_CHECK(r1 != k); VERIFY_CHECK(r2 != k); + VERIFY_CHECK(r1 != r2); + /* these _var calls are constant time since the shift amount is constant */ - rustsecp256k1zkp_v0_8_0_scalar_mul_shift_var(&c1, k, &g1, 384); - rustsecp256k1zkp_v0_8_0_scalar_mul_shift_var(&c2, k, &g2, 384); - rustsecp256k1zkp_v0_8_0_scalar_mul(&c1, &c1, &minus_b1); - rustsecp256k1zkp_v0_8_0_scalar_mul(&c2, &c2, &minus_b2); - rustsecp256k1zkp_v0_8_0_scalar_add(r2, &c1, &c2); - rustsecp256k1zkp_v0_8_0_scalar_mul(r1, r2, &rustsecp256k1zkp_v0_8_0_const_lambda); - rustsecp256k1zkp_v0_8_0_scalar_negate(r1, r1); - rustsecp256k1zkp_v0_8_0_scalar_add(r1, r1, k); + rustsecp256k1_v0_11_scalar_mul_shift_var(&c1, k, &g1, 384); + rustsecp256k1_v0_11_scalar_mul_shift_var(&c2, k, &g2, 384); + rustsecp256k1_v0_11_scalar_mul(&c1, &c1, &minus_b1); + rustsecp256k1_v0_11_scalar_mul(&c2, &c2, &minus_b2); + rustsecp256k1_v0_11_scalar_add(r2, &c1, &c2); + rustsecp256k1_v0_11_scalar_mul(r1, r2, &rustsecp256k1_v0_11_const_lambda); + rustsecp256k1_v0_11_scalar_negate(r1, r1); + rustsecp256k1_v0_11_scalar_add(r1, r1, k); + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); #ifdef VERIFY - rustsecp256k1zkp_v0_8_0_scalar_split_lambda_verify(r1, r2, k); + rustsecp256k1_v0_11_scalar_split_lambda_verify(r1, r2, k); #endif } #ifdef VERIFY /* - * Proof for rustsecp256k1zkp_v0_8_0_scalar_split_lambda's bounds. + * Proof for rustsecp256k1_v0_11_scalar_split_lambda's bounds. * * Let * - epsilon1 = 2^256 * |g1/2^384 - b2/d| @@ -209,7 +233,7 @@ static void rustsecp256k1zkp_v0_8_0_scalar_split_lambda(rustsecp256k1zkp_v0_8_0_ * <= {triangle inequality} * a1*|k*b2/n - c1| + a2*|k*(-b1)/n - c2| * < {Lemma 1 and Lemma 2} - * a1*(2^-1 + epslion1) + a2*(2^-1 + epsilon2) + * a1*(2^-1 + epsilon1) + a2*(2^-1 + epsilon2) * < {rounding up to an integer} * (a1 + a2 + 1)/2 * < {rounding up to a power of 2} @@ -227,7 +251,7 @@ static void rustsecp256k1zkp_v0_8_0_scalar_split_lambda(rustsecp256k1zkp_v0_8_0_ * <= {triangle inequality} * (-b1)*|k*b2/n - c1| + b2*|k*(-b1)/n - c2| * < {Lemma 1 and Lemma 2} - * (-b1)*(2^-1 + epslion1) + b2*(2^-1 + epsilon2) + * (-b1)*(2^-1 + epsilon1) + b2*(2^-1 + epsilon2) * < {rounding up to an integer} * (-b1 + b2)/2 + 1 * < {rounding up to a power of 2} @@ -260,8 +284,8 @@ static void rustsecp256k1zkp_v0_8_0_scalar_split_lambda(rustsecp256k1zkp_v0_8_0_ * * Q.E.D. */ -static void rustsecp256k1zkp_v0_8_0_scalar_split_lambda_verify(const rustsecp256k1zkp_v0_8_0_scalar *r1, const rustsecp256k1zkp_v0_8_0_scalar *r2, const rustsecp256k1zkp_v0_8_0_scalar *k) { - rustsecp256k1zkp_v0_8_0_scalar s; +static void rustsecp256k1_v0_11_scalar_split_lambda_verify(const rustsecp256k1_v0_11_scalar *r1, const rustsecp256k1_v0_11_scalar *r2, const rustsecp256k1_v0_11_scalar *k) { + rustsecp256k1_v0_11_scalar s; unsigned char buf1[32]; unsigned char buf2[32]; @@ -277,19 +301,19 @@ static void rustsecp256k1zkp_v0_8_0_scalar_split_lambda_verify(const rustsecp256 0x8a, 0x65, 0x28, 0x7b, 0xd4, 0x71, 0x79, 0xfb, 0x2b, 0xe0, 0x88, 0x46, 0xce, 0xa2, 0x67, 0xed }; - rustsecp256k1zkp_v0_8_0_scalar_mul(&s, &rustsecp256k1zkp_v0_8_0_const_lambda, r2); - rustsecp256k1zkp_v0_8_0_scalar_add(&s, &s, r1); - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&s, k)); + rustsecp256k1_v0_11_scalar_mul(&s, &rustsecp256k1_v0_11_const_lambda, r2); + rustsecp256k1_v0_11_scalar_add(&s, &s, r1); + VERIFY_CHECK(rustsecp256k1_v0_11_scalar_eq(&s, k)); - rustsecp256k1zkp_v0_8_0_scalar_negate(&s, r1); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(buf1, r1); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(buf2, &s); - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(buf1, k1_bound, 32) < 0 || rustsecp256k1zkp_v0_8_0_memcmp_var(buf2, k1_bound, 32) < 0); + rustsecp256k1_v0_11_scalar_negate(&s, r1); + rustsecp256k1_v0_11_scalar_get_b32(buf1, r1); + rustsecp256k1_v0_11_scalar_get_b32(buf2, &s); + VERIFY_CHECK(rustsecp256k1_v0_11_memcmp_var(buf1, k1_bound, 32) < 0 || rustsecp256k1_v0_11_memcmp_var(buf2, k1_bound, 32) < 0); - rustsecp256k1zkp_v0_8_0_scalar_negate(&s, r2); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(buf1, r2); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(buf2, &s); - VERIFY_CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(buf1, k2_bound, 32) < 0 || rustsecp256k1zkp_v0_8_0_memcmp_var(buf2, k2_bound, 32) < 0); + rustsecp256k1_v0_11_scalar_negate(&s, r2); + rustsecp256k1_v0_11_scalar_get_b32(buf1, r2); + rustsecp256k1_v0_11_scalar_get_b32(buf2, &s); + VERIFY_CHECK(rustsecp256k1_v0_11_memcmp_var(buf1, k2_bound, 32) < 0 || rustsecp256k1_v0_11_memcmp_var(buf2, k2_bound, 32) < 0); } #endif /* VERIFY */ #endif /* !defined(EXHAUSTIVE_TEST_ORDER) */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_low.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_low.h new file mode 100644 index 00000000..1995c146 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_low.h @@ -0,0 +1,24 @@ +/*********************************************************************** + * Copyright (c) 2015, 2022 Andrew Poelstra, Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef uint32_t rustsecp256k1_v0_11_scalar; + +/* A compile-time constant equal to 2^32 (modulo order). */ +#define SCALAR_2P32 ((0xffffffffUL % EXHAUSTIVE_TEST_ORDER) + 1U) + +/* Compute a*2^32 + b (modulo order). */ +#define SCALAR_HORNER(a, b) (((uint64_t)(a) * SCALAR_2P32 + (b)) % EXHAUSTIVE_TEST_ORDER) + +/* Evaluates to the provided 256-bit constant reduced modulo order. */ +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER((d7), (d6)), (d5)), (d4)), (d3)), (d2)), (d1)), (d0)) + +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_low_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_low_impl.h new file mode 100644 index 00000000..b0fb66f1 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scalar_low_impl.h @@ -0,0 +1,206 @@ +/*********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H + +#include "checkmem.h" +#include "scalar.h" +#include "util.h" + +#include + +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_is_even(const rustsecp256k1_v0_11_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return !(*a & 1); +} + +SECP256K1_INLINE static void rustsecp256k1_v0_11_scalar_set_int(rustsecp256k1_v0_11_scalar *r, unsigned int v) { + *r = v % EXHAUSTIVE_TEST_ORDER; + + SECP256K1_SCALAR_VERIFY(r); +} + +SECP256K1_INLINE static uint32_t rustsecp256k1_v0_11_scalar_get_bits_limb32(const rustsecp256k1_v0_11_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + + VERIFY_CHECK(count > 0 && count <= 32); + if (offset < 32) { + return (*a >> offset) & (0xFFFFFFFF >> (32 - count)); + } else { + return 0; + } +} + +SECP256K1_INLINE static uint32_t rustsecp256k1_v0_11_scalar_get_bits_var(const rustsecp256k1_v0_11_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + + return rustsecp256k1_v0_11_scalar_get_bits_limb32(a, offset, count); +} + +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_check_overflow(const rustsecp256k1_v0_11_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; } + +static int rustsecp256k1_v0_11_scalar_add(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b) { + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER; + + SECP256K1_SCALAR_VERIFY(r); + return *r < *b; +} + +static void rustsecp256k1_v0_11_scalar_cadd_bit(rustsecp256k1_v0_11_scalar *r, unsigned int bit, int flag) { + SECP256K1_SCALAR_VERIFY(r); + + if (flag && bit < 32) + *r += ((uint32_t)1 << bit); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(bit < 32); + /* Verify that adding (1 << bit) will not overflow any in-range scalar *r by overflowing the underlying uint32_t. */ + VERIFY_CHECK(((uint32_t)1 << bit) - 1 <= UINT32_MAX - EXHAUSTIVE_TEST_ORDER); +} + +static void rustsecp256k1_v0_11_scalar_set_b32(rustsecp256k1_v0_11_scalar *r, const unsigned char *b32, int *overflow) { + int i; + int over = 0; + *r = 0; + for (i = 0; i < 32; i++) { + *r = (*r * 0x100) + b32[i]; + if (*r >= EXHAUSTIVE_TEST_ORDER) { + over = 1; + *r %= EXHAUSTIVE_TEST_ORDER; + } + } + if (overflow) *overflow = over; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void rustsecp256k1_v0_11_scalar_get_b32(unsigned char *bin, const rustsecp256k1_v0_11_scalar* a) { + SECP256K1_SCALAR_VERIFY(a); + + memset(bin, 0, 32); + bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a; +} + +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_is_zero(const rustsecp256k1_v0_11_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return *a == 0; +} + +static void rustsecp256k1_v0_11_scalar_negate(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + if (*a == 0) { + *r = 0; + } else { + *r = EXHAUSTIVE_TEST_ORDER - *a; + } + + SECP256K1_SCALAR_VERIFY(r); +} + +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_is_one(const rustsecp256k1_v0_11_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return *a == 1; +} + +static int rustsecp256k1_v0_11_scalar_is_high(const rustsecp256k1_v0_11_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return *a > EXHAUSTIVE_TEST_ORDER / 2; +} + +static int rustsecp256k1_v0_11_scalar_cond_negate(rustsecp256k1_v0_11_scalar *r, int flag) { + SECP256K1_SCALAR_VERIFY(r); + + if (flag) rustsecp256k1_v0_11_scalar_negate(r, r); + + SECP256K1_SCALAR_VERIFY(r); + return flag ? -1 : 1; +} + +static void rustsecp256k1_v0_11_scalar_mul(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b) { + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void rustsecp256k1_v0_11_scalar_split_128(rustsecp256k1_v0_11_scalar *r1, rustsecp256k1_v0_11_scalar *r2, const rustsecp256k1_v0_11_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + *r1 = *a; + *r2 = 0; + + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); +} + +SECP256K1_INLINE static int rustsecp256k1_v0_11_scalar_eq(const rustsecp256k1_v0_11_scalar *a, const rustsecp256k1_v0_11_scalar *b) { + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + return *a == *b; +} + +static SECP256K1_INLINE void rustsecp256k1_v0_11_scalar_cmov(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a, int flag) { + uint32_t mask0, mask1; + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_CHECKMEM_CHECK_VERIFY(r, sizeof(*r)); + + mask0 = vflag + ~((uint32_t)0); + mask1 = ~mask0; + *r = (*r & mask0) | (*a & mask1); + + SECP256K1_SCALAR_VERIFY(r); +} + +static void rustsecp256k1_v0_11_scalar_inverse(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *x) { + int i; + uint32_t res = 0; + SECP256K1_SCALAR_VERIFY(x); + + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) { + res = i; + break; + } + } + + /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus + * have a composite group order; fix it in exhaustive_tests.c). */ + VERIFY_CHECK(res != 0); + *r = res; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void rustsecp256k1_v0_11_scalar_inverse_var(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *x) { + SECP256K1_SCALAR_VERIFY(x); + + rustsecp256k1_v0_11_scalar_inverse(r, x); + + SECP256K1_SCALAR_VERIFY(r); +} + +static void rustsecp256k1_v0_11_scalar_half(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + *r = (*a + ((-(uint32_t)(*a & 1)) & EXHAUSTIVE_TEST_ORDER)) >> 1; + + SECP256K1_SCALAR_VERIFY(r); +} + +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scratch.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scratch.h new file mode 100644 index 00000000..9a9cffa3 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scratch.h @@ -0,0 +1,40 @@ +/*********************************************************************** + * Copyright (c) 2017 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCRATCH_H +#define SECP256K1_SCRATCH_H + +/* The typedef is used internally; the struct name is used in the public API + * (where it is exposed as a different typedef) */ +typedef struct rustsecp256k1_v0_11_scratch_space_struct { + /** guard against interpreting this object as other types */ + unsigned char magic[8]; + /** actual allocated data */ + void *data; + /** amount that has been allocated (i.e. `data + offset` is the next + * available pointer) */ + size_t alloc_size; + /** maximum size available to allocate */ + size_t max_size; +} rustsecp256k1_v0_11_scratch; + +typedef struct rustsecp256k1_v0_11_scratch_space_struct rustsecp256k1_v0_11_scratch_space; + +/** Returns an opaque object used to "checkpoint" a scratch space. Used + * with `rustsecp256k1_v0_11_scratch_apply_checkpoint` to undo allocations. */ +static size_t rustsecp256k1_v0_11_scratch_checkpoint(const rustsecp256k1_v0_11_callback* error_callback, const rustsecp256k1_v0_11_scratch* scratch); + +/** Applies a check point received from `rustsecp256k1_v0_11_scratch_checkpoint`, + * undoing all allocations since that point. */ +static void rustsecp256k1_v0_11_scratch_apply_checkpoint(const rustsecp256k1_v0_11_callback* error_callback, rustsecp256k1_v0_11_scratch* scratch, size_t checkpoint); + +/** Returns the maximum allocation the scratch space will allow */ +static size_t rustsecp256k1_v0_11_scratch_max_allocation(const rustsecp256k1_v0_11_callback* error_callback, const rustsecp256k1_v0_11_scratch* scratch, size_t n_objects); + +/** Returns a pointer into the most recently allocated frame, or NULL if there is insufficient available space */ +static void *rustsecp256k1_v0_11_scratch_alloc(const rustsecp256k1_v0_11_callback* error_callback, rustsecp256k1_v0_11_scratch* scratch, size_t n); + +#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scratch_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scratch_impl.h similarity index 50% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scratch_impl.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scratch_impl.h index 5aaed95e..98677ddb 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/scratch_impl.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/scratch_impl.h @@ -10,29 +10,29 @@ #include "util.h" #include "scratch.h" -static size_t rustsecp256k1zkp_v0_8_0_scratch_checkpoint(const rustsecp256k1zkp_v0_8_0_callback* error_callback, const rustsecp256k1zkp_v0_8_0_scratch* scratch) { - if (rustsecp256k1zkp_v0_8_0_memcmp_var(scratch->magic, "scratch", 8) != 0) { - rustsecp256k1zkp_v0_8_0_callback_call(error_callback, "invalid scratch space"); +static size_t rustsecp256k1_v0_11_scratch_checkpoint(const rustsecp256k1_v0_11_callback* error_callback, const rustsecp256k1_v0_11_scratch* scratch) { + if (rustsecp256k1_v0_11_memcmp_var(scratch->magic, "scratch", 8) != 0) { + rustsecp256k1_v0_11_callback_call(error_callback, "invalid scratch space"); return 0; } return scratch->alloc_size; } -static void rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(const rustsecp256k1zkp_v0_8_0_callback* error_callback, rustsecp256k1zkp_v0_8_0_scratch* scratch, size_t checkpoint) { - if (rustsecp256k1zkp_v0_8_0_memcmp_var(scratch->magic, "scratch", 8) != 0) { - rustsecp256k1zkp_v0_8_0_callback_call(error_callback, "invalid scratch space"); +static void rustsecp256k1_v0_11_scratch_apply_checkpoint(const rustsecp256k1_v0_11_callback* error_callback, rustsecp256k1_v0_11_scratch* scratch, size_t checkpoint) { + if (rustsecp256k1_v0_11_memcmp_var(scratch->magic, "scratch", 8) != 0) { + rustsecp256k1_v0_11_callback_call(error_callback, "invalid scratch space"); return; } if (checkpoint > scratch->alloc_size) { - rustsecp256k1zkp_v0_8_0_callback_call(error_callback, "invalid checkpoint"); + rustsecp256k1_v0_11_callback_call(error_callback, "invalid checkpoint"); return; } scratch->alloc_size = checkpoint; } -static size_t rustsecp256k1zkp_v0_8_0_scratch_max_allocation(const rustsecp256k1zkp_v0_8_0_callback* error_callback, const rustsecp256k1zkp_v0_8_0_scratch* scratch, size_t objects) { - if (rustsecp256k1zkp_v0_8_0_memcmp_var(scratch->magic, "scratch", 8) != 0) { - rustsecp256k1zkp_v0_8_0_callback_call(error_callback, "invalid scratch space"); +static size_t rustsecp256k1_v0_11_scratch_max_allocation(const rustsecp256k1_v0_11_callback* error_callback, const rustsecp256k1_v0_11_scratch* scratch, size_t objects) { + if (rustsecp256k1_v0_11_memcmp_var(scratch->magic, "scratch", 8) != 0) { + rustsecp256k1_v0_11_callback_call(error_callback, "invalid scratch space"); return 0; } /* Ensure that multiplication will not wrap around */ @@ -45,7 +45,7 @@ static size_t rustsecp256k1zkp_v0_8_0_scratch_max_allocation(const rustsecp256k1 return scratch->max_size - scratch->alloc_size - objects * (ALIGNMENT - 1); } -static void *rustsecp256k1zkp_v0_8_0_scratch_alloc(const rustsecp256k1zkp_v0_8_0_callback* error_callback, rustsecp256k1zkp_v0_8_0_scratch* scratch, size_t size) { +static void *rustsecp256k1_v0_11_scratch_alloc(const rustsecp256k1_v0_11_callback* error_callback, rustsecp256k1_v0_11_scratch* scratch, size_t size) { void *ret; size_t rounded_size; @@ -56,8 +56,8 @@ static void *rustsecp256k1zkp_v0_8_0_scratch_alloc(const rustsecp256k1zkp_v0_8_0 } size = rounded_size; - if (rustsecp256k1zkp_v0_8_0_memcmp_var(scratch->magic, "scratch", 8) != 0) { - rustsecp256k1zkp_v0_8_0_callback_call(error_callback, "invalid scratch space"); + if (rustsecp256k1_v0_11_memcmp_var(scratch->magic, "scratch", 8) != 0) { + rustsecp256k1_v0_11_callback_call(error_callback, "invalid scratch space"); return NULL; } diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/secp256k1.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/secp256k1.c new file mode 100644 index 00000000..56564193 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/secp256k1.c @@ -0,0 +1,785 @@ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +/* This is a C project. It should not be compiled with a C++ compiler, + * and we error out if we detect one. + * + * We still want to be able to test the project with a C++ compiler + * because it is still good to know if this will lead to real trouble, so + * there is a possibility to override the check. But be warned that + * compiling with a C++ compiler is not supported. */ +#if defined(__cplusplus) && !defined(SECP256K1_CPLUSPLUS_TEST_OVERRIDE) +#error Trying to compile a C project with a C++ compiler. +#endif + +#define SECP256K1_BUILD + +#include "../include/secp256k1.h" +#include "../include/secp256k1_preallocated.h" + +#include "assumptions.h" +#include "checkmem.h" +#include "util.h" + +#include "field_impl.h" +#include "scalar_impl.h" +#include "group_impl.h" +#include "ecmult_impl.h" +#include "ecmult_const_impl.h" +#include "ecmult_gen_impl.h" +#include "ecdsa_impl.h" +#include "eckey_impl.h" +#include "hash_impl.h" +#include "int128_impl.h" +#include "scratch_impl.h" +#include "selftest.h" +#include "hsort_impl.h" + +#ifdef SECP256K1_NO_BUILD +# error "secp256k1.h processed without SECP256K1_BUILD defined while building secp256k1.c" +#endif + +#define ARG_CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + rustsecp256k1_v0_11_callback_call(&ctx->illegal_callback, #cond); \ + return 0; \ + } \ +} while(0) + +#define ARG_CHECK_VOID(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + rustsecp256k1_v0_11_callback_call(&ctx->illegal_callback, #cond); \ + return; \ + } \ +} while(0) + +/* Note that whenever you change the context struct, you must also change the + * context_eq function. */ +struct rustsecp256k1_v0_11_context_struct { + rustsecp256k1_v0_11_ecmult_gen_context ecmult_gen_ctx; + rustsecp256k1_v0_11_callback illegal_callback; + rustsecp256k1_v0_11_callback error_callback; + int declassify; +}; + +static const rustsecp256k1_v0_11_context rustsecp256k1_v0_11_context_static_ = { + { 0 }, + { rustsecp256k1_v0_11_default_illegal_callback_fn, 0 }, + { rustsecp256k1_v0_11_default_error_callback_fn, 0 }, + 0 +}; +const rustsecp256k1_v0_11_context *rustsecp256k1_v0_11_context_static = &rustsecp256k1_v0_11_context_static_; +const rustsecp256k1_v0_11_context *rustsecp256k1_v0_11_context_no_precomp = &rustsecp256k1_v0_11_context_static_; + +/* Helper function that determines if a context is proper, i.e., is not the static context or a copy thereof. + * + * This is intended for "context" functions such as rustsecp256k1_v0_11_context_clone. Functions that need specific + * features of a context should still check for these features directly. For example, a function that needs + * ecmult_gen should directly check for the existence of the ecmult_gen context. */ +static int rustsecp256k1_v0_11_context_is_proper(const rustsecp256k1_v0_11_context* ctx) { + return rustsecp256k1_v0_11_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx); +} + +void rustsecp256k1_v0_11_selftest(void) { + if (!rustsecp256k1_v0_11_selftest_passes()) { + rustsecp256k1_v0_11_callback_call(&default_error_callback, "self test failed"); + } +} + +size_t rustsecp256k1_v0_11_context_preallocated_size(unsigned int flags) { + size_t ret = sizeof(rustsecp256k1_v0_11_context); + /* A return value of 0 is reserved as an indicator for errors when we call this function internally. */ + VERIFY_CHECK(ret != 0); + + if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { + rustsecp256k1_v0_11_callback_call(&default_illegal_callback, + "Invalid flags"); + return 0; + } + + if (EXPECT(!SECP256K1_CHECKMEM_RUNNING() && (flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY), 0)) { + rustsecp256k1_v0_11_callback_call(&default_illegal_callback, + "Declassify flag requires running with memory checking"); + return 0; + } + + return ret; +} + +size_t rustsecp256k1_v0_11_context_preallocated_clone_size(const rustsecp256k1_v0_11_context* ctx) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(rustsecp256k1_v0_11_context_is_proper(ctx)); + return sizeof(rustsecp256k1_v0_11_context); +} + +rustsecp256k1_v0_11_context* rustsecp256k1_v0_11_context_preallocated_create(void* prealloc, unsigned int flags) { + size_t prealloc_size; + rustsecp256k1_v0_11_context* ret; + + rustsecp256k1_v0_11_selftest(); + + prealloc_size = rustsecp256k1_v0_11_context_preallocated_size(flags); + if (prealloc_size == 0) { + return NULL; + } + VERIFY_CHECK(prealloc != NULL); + ret = (rustsecp256k1_v0_11_context*)prealloc; + ret->illegal_callback = default_illegal_callback; + ret->error_callback = default_error_callback; + + /* Flags have been checked by rustsecp256k1_v0_11_context_preallocated_size. */ + VERIFY_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_CONTEXT); + rustsecp256k1_v0_11_ecmult_gen_context_build(&ret->ecmult_gen_ctx); + ret->declassify = !!(flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY); + + return ret; +} + +rustsecp256k1_v0_11_context* rustsecp256k1_v0_11_context_preallocated_clone(const rustsecp256k1_v0_11_context* ctx, void* prealloc) { + rustsecp256k1_v0_11_context* ret; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(prealloc != NULL); + ARG_CHECK(rustsecp256k1_v0_11_context_is_proper(ctx)); + + ret = (rustsecp256k1_v0_11_context*)prealloc; + *ret = *ctx; + return ret; +} + +void rustsecp256k1_v0_11_context_preallocated_destroy(rustsecp256k1_v0_11_context* ctx) { + ARG_CHECK_VOID(ctx == NULL || rustsecp256k1_v0_11_context_is_proper(ctx)); + + /* Defined as noop */ + if (ctx == NULL) { + return; + } + + rustsecp256k1_v0_11_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); +} + +void rustsecp256k1_v0_11_context_set_illegal_callback(rustsecp256k1_v0_11_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + /* We compare pointers instead of checking rustsecp256k1_v0_11_context_is_proper() here + because setting callbacks is allowed on *copies* of the static context: + it's harmless and makes testing easier. */ + ARG_CHECK_VOID(ctx != rustsecp256k1_v0_11_context_static); + if (fun == NULL) { + fun = rustsecp256k1_v0_11_default_illegal_callback_fn; + } + ctx->illegal_callback.fn = fun; + ctx->illegal_callback.data = data; +} + +void rustsecp256k1_v0_11_context_set_error_callback(rustsecp256k1_v0_11_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + /* We compare pointers instead of checking rustsecp256k1_v0_11_context_is_proper() here + because setting callbacks is allowed on *copies* of the static context: + it's harmless and makes testing easier. */ + ARG_CHECK_VOID(ctx != rustsecp256k1_v0_11_context_static); + if (fun == NULL) { + fun = rustsecp256k1_v0_11_default_error_callback_fn; + } + ctx->error_callback.fn = fun; + ctx->error_callback.data = data; +} + +/* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour + * of the software. + */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_declassify(const rustsecp256k1_v0_11_context* ctx, const void *p, size_t len) { + if (EXPECT(ctx->declassify, 0)) SECP256K1_CHECKMEM_DEFINE(p, len); +} + +static int rustsecp256k1_v0_11_pubkey_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ge* ge, const rustsecp256k1_v0_11_pubkey* pubkey) { + rustsecp256k1_v0_11_ge_from_bytes(ge, pubkey->data); + ARG_CHECK(!rustsecp256k1_v0_11_fe_is_zero(&ge->x)); + return 1; +} + +static void rustsecp256k1_v0_11_pubkey_save(rustsecp256k1_v0_11_pubkey* pubkey, rustsecp256k1_v0_11_ge* ge) { + rustsecp256k1_v0_11_ge_to_bytes(pubkey->data, ge); +} + +int rustsecp256k1_v0_11_ec_pubkey_parse(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey* pubkey, const unsigned char *input, size_t inputlen) { + rustsecp256k1_v0_11_ge Q; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(input != NULL); + if (!rustsecp256k1_v0_11_eckey_pubkey_parse(&Q, input, inputlen)) { + return 0; + } + if (!rustsecp256k1_v0_11_ge_is_in_correct_subgroup(&Q)) { + return 0; + } + rustsecp256k1_v0_11_pubkey_save(pubkey, &Q); + rustsecp256k1_v0_11_ge_clear(&Q); + return 1; +} + +int rustsecp256k1_v0_11_ec_pubkey_serialize(const rustsecp256k1_v0_11_context* ctx, unsigned char *output, size_t *outputlen, const rustsecp256k1_v0_11_pubkey* pubkey, unsigned int flags) { + rustsecp256k1_v0_11_ge Q; + size_t len; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33u : 65u)); + len = *outputlen; + *outputlen = 0; + ARG_CHECK(output != NULL); + memset(output, 0, len); + ARG_CHECK(pubkey != NULL); + ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); + if (rustsecp256k1_v0_11_pubkey_load(ctx, &Q, pubkey)) { + ret = rustsecp256k1_v0_11_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); + if (ret) { + *outputlen = len; + } + } + return ret; +} + +int rustsecp256k1_v0_11_ec_pubkey_cmp(const rustsecp256k1_v0_11_context* ctx, const rustsecp256k1_v0_11_pubkey* pubkey0, const rustsecp256k1_v0_11_pubkey* pubkey1) { + unsigned char out[2][33]; + const rustsecp256k1_v0_11_pubkey* pk[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + pk[0] = pubkey0; pk[1] = pubkey1; + for (i = 0; i < 2; i++) { + size_t out_size = sizeof(out[i]); + /* If the public key is NULL or invalid, ec_pubkey_serialize will call + * the illegal_callback and return 0. In that case we will serialize the + * key as all zeros which is less than any valid public key. This + * results in consistent comparisons even if NULL or invalid pubkeys are + * involved and prevents edge cases such as sorting algorithms that use + * this function and do not terminate as a result. */ + if (!rustsecp256k1_v0_11_ec_pubkey_serialize(ctx, out[i], &out_size, pk[i], SECP256K1_EC_COMPRESSED)) { + /* Note that ec_pubkey_serialize should already set the output to + * zero in that case, but it's not guaranteed by the API, we can't + * test it and writing a VERIFY_CHECK is more complex than + * explicitly memsetting (again). */ + memset(out[i], 0, sizeof(out[i])); + } + } + return rustsecp256k1_v0_11_memcmp_var(out[0], out[1], sizeof(out[0])); +} + +static int rustsecp256k1_v0_11_ec_pubkey_sort_cmp(const void* pk1, const void* pk2, void *ctx) { + return rustsecp256k1_v0_11_ec_pubkey_cmp((rustsecp256k1_v0_11_context *)ctx, + *(rustsecp256k1_v0_11_pubkey **)pk1, + *(rustsecp256k1_v0_11_pubkey **)pk2); +} + +int rustsecp256k1_v0_11_ec_pubkey_sort(const rustsecp256k1_v0_11_context* ctx, const rustsecp256k1_v0_11_pubkey **pubkeys, size_t n_pubkeys) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkeys != NULL); + + /* Suppress wrong warning (fixed in MSVC 19.33) */ + #if defined(_MSC_VER) && (_MSC_VER < 1933) + #pragma warning(push) + #pragma warning(disable: 4090) + #endif + + /* Casting away const is fine because neither rustsecp256k1_v0_11_hsort nor + * rustsecp256k1_v0_11_ec_pubkey_sort_cmp modify the data pointed to by the cmp_data + * argument. */ + rustsecp256k1_v0_11_hsort(pubkeys, n_pubkeys, sizeof(*pubkeys), rustsecp256k1_v0_11_ec_pubkey_sort_cmp, (void *)ctx); + + #if defined(_MSC_VER) && (_MSC_VER < 1933) + #pragma warning(pop) + #endif + + return 1; +} + +static void rustsecp256k1_v0_11_ecdsa_signature_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_scalar* r, rustsecp256k1_v0_11_scalar* s, const rustsecp256k1_v0_11_ecdsa_signature* sig) { + (void)ctx; + if (sizeof(rustsecp256k1_v0_11_scalar) == 32) { + /* When the rustsecp256k1_v0_11_scalar type is exactly 32 byte, use its + * representation inside rustsecp256k1_v0_11_ecdsa_signature, as conversion is very fast. + * Note that rustsecp256k1_v0_11_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + rustsecp256k1_v0_11_scalar_set_b32(r, &sig->data[0], NULL); + rustsecp256k1_v0_11_scalar_set_b32(s, &sig->data[32], NULL); + } +} + +static void rustsecp256k1_v0_11_ecdsa_signature_save(rustsecp256k1_v0_11_ecdsa_signature* sig, const rustsecp256k1_v0_11_scalar* r, const rustsecp256k1_v0_11_scalar* s) { + if (sizeof(rustsecp256k1_v0_11_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + rustsecp256k1_v0_11_scalar_get_b32(&sig->data[0], r); + rustsecp256k1_v0_11_scalar_get_b32(&sig->data[32], s); + } +} + +int rustsecp256k1_v0_11_ecdsa_signature_parse_der(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + rustsecp256k1_v0_11_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input != NULL); + + if (rustsecp256k1_v0_11_ecdsa_sig_parse(&r, &s, input, inputlen)) { + rustsecp256k1_v0_11_ecdsa_signature_save(sig, &r, &s); + return 1; + } else { + memset(sig, 0, sizeof(*sig)); + return 0; + } +} + +int rustsecp256k1_v0_11_ecdsa_signature_parse_compact(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ecdsa_signature* sig, const unsigned char *input64) { + rustsecp256k1_v0_11_scalar r, s; + int ret = 1; + int overflow = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + + rustsecp256k1_v0_11_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + rustsecp256k1_v0_11_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + rustsecp256k1_v0_11_ecdsa_signature_save(sig, &r, &s); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + +int rustsecp256k1_v0_11_ecdsa_signature_serialize_der(const rustsecp256k1_v0_11_context* ctx, unsigned char *output, size_t *outputlen, const rustsecp256k1_v0_11_ecdsa_signature* sig) { + rustsecp256k1_v0_11_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(sig != NULL); + + rustsecp256k1_v0_11_ecdsa_signature_load(ctx, &r, &s, sig); + return rustsecp256k1_v0_11_ecdsa_sig_serialize(output, outputlen, &r, &s); +} + +int rustsecp256k1_v0_11_ecdsa_signature_serialize_compact(const rustsecp256k1_v0_11_context* ctx, unsigned char *output64, const rustsecp256k1_v0_11_ecdsa_signature* sig) { + rustsecp256k1_v0_11_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + + rustsecp256k1_v0_11_ecdsa_signature_load(ctx, &r, &s, sig); + rustsecp256k1_v0_11_scalar_get_b32(&output64[0], &r); + rustsecp256k1_v0_11_scalar_get_b32(&output64[32], &s); + return 1; +} + +int rustsecp256k1_v0_11_ecdsa_signature_normalize(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ecdsa_signature *sigout, const rustsecp256k1_v0_11_ecdsa_signature *sigin) { + rustsecp256k1_v0_11_scalar r, s; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sigin != NULL); + + rustsecp256k1_v0_11_ecdsa_signature_load(ctx, &r, &s, sigin); + ret = rustsecp256k1_v0_11_scalar_is_high(&s); + if (sigout != NULL) { + if (ret) { + rustsecp256k1_v0_11_scalar_negate(&s, &s); + } + rustsecp256k1_v0_11_ecdsa_signature_save(sigout, &r, &s); + } + + return ret; +} + +int rustsecp256k1_v0_11_ecdsa_verify(const rustsecp256k1_v0_11_context* ctx, const rustsecp256k1_v0_11_ecdsa_signature *sig, const unsigned char *msghash32, const rustsecp256k1_v0_11_pubkey *pubkey) { + rustsecp256k1_v0_11_ge q; + rustsecp256k1_v0_11_scalar r, s; + rustsecp256k1_v0_11_scalar m; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(msghash32 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(pubkey != NULL); + + rustsecp256k1_v0_11_scalar_set_b32(&m, msghash32, NULL); + rustsecp256k1_v0_11_ecdsa_signature_load(ctx, &r, &s, sig); + return (!rustsecp256k1_v0_11_scalar_is_high(&s) && + rustsecp256k1_v0_11_pubkey_load(ctx, &q, pubkey) && + rustsecp256k1_v0_11_ecdsa_sig_verify(&r, &s, &q, &m)); +} + +static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *offset, const void *data, unsigned int len) { + memcpy(buf + *offset, data, len); + *offset += len; +} + +static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + unsigned char keydata[112]; + unsigned int offset = 0; + rustsecp256k1_v0_11_rfc6979_hmac_sha256 rng; + unsigned int i; + rustsecp256k1_v0_11_scalar msg; + unsigned char msgmod32[32]; + rustsecp256k1_v0_11_scalar_set_b32(&msg, msg32, NULL); + rustsecp256k1_v0_11_scalar_get_b32(msgmod32, &msg); + /* We feed a byte array to the PRNG as input, consisting of: + * - the private key (32 bytes) and reduced message (32 bytes), see RFC 6979 3.2d. + * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. + * - optionally 16 extra bytes with the algorithm name. + * Because the arguments have distinct fixed lengths it is not possible for + * different argument mixtures to emulate each other and result in the same + * nonces. + */ + buffer_append(keydata, &offset, key32, 32); + buffer_append(keydata, &offset, msgmod32, 32); + if (data != NULL) { + buffer_append(keydata, &offset, data, 32); + } + if (algo16 != NULL) { + buffer_append(keydata, &offset, algo16, 16); + } + rustsecp256k1_v0_11_rfc6979_hmac_sha256_initialize(&rng, keydata, offset); + for (i = 0; i <= counter; i++) { + rustsecp256k1_v0_11_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + } + rustsecp256k1_v0_11_rfc6979_hmac_sha256_finalize(&rng); + + rustsecp256k1_v0_11_memclear(keydata, sizeof(keydata)); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_clear(&rng); + return 1; +} + +const rustsecp256k1_v0_11_nonce_function rustsecp256k1_v0_11_nonce_function_rfc6979 = nonce_function_rfc6979; +const rustsecp256k1_v0_11_nonce_function rustsecp256k1_v0_11_nonce_function_default = nonce_function_rfc6979; + +static int rustsecp256k1_v0_11_ecdsa_sign_inner(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_scalar* r, rustsecp256k1_v0_11_scalar* s, int* recid, const unsigned char *msg32, const unsigned char *seckey, rustsecp256k1_v0_11_nonce_function noncefp, const void* noncedata) { + rustsecp256k1_v0_11_scalar sec, non, msg; + int ret = 0; + int is_sec_valid; + unsigned char nonce32[32]; + unsigned int count = 0; + /* Default initialization here is important so we won't pass uninit values to the cmov in the end */ + *r = rustsecp256k1_v0_11_scalar_zero; + *s = rustsecp256k1_v0_11_scalar_zero; + if (recid) { + *recid = 0; + } + if (noncefp == NULL) { + noncefp = rustsecp256k1_v0_11_nonce_function_default; + } + + /* Fail if the secret key is invalid. */ + is_sec_valid = rustsecp256k1_v0_11_scalar_set_b32_seckey(&sec, seckey); + rustsecp256k1_v0_11_scalar_cmov(&sec, &rustsecp256k1_v0_11_scalar_one, !is_sec_valid); + rustsecp256k1_v0_11_scalar_set_b32(&msg, msg32, NULL); + while (1) { + int is_nonce_valid; + ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + is_nonce_valid = rustsecp256k1_v0_11_scalar_set_b32_seckey(&non, nonce32); + /* The nonce is still secret here, but it being invalid is less likely than 1:2^255. */ + rustsecp256k1_v0_11_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid)); + if (is_nonce_valid) { + ret = rustsecp256k1_v0_11_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, r, s, &sec, &msg, &non, recid); + /* The final signature is no longer a secret, nor is the fact that we were successful or not. */ + rustsecp256k1_v0_11_declassify(ctx, &ret, sizeof(ret)); + if (ret) { + break; + } + } + count++; + } + /* We don't want to declassify is_sec_valid and therefore the range of + * seckey. As a result is_sec_valid is included in ret only after ret was + * used as a branching variable. */ + ret &= is_sec_valid; + rustsecp256k1_v0_11_memclear(nonce32, sizeof(nonce32)); + rustsecp256k1_v0_11_scalar_clear(&msg); + rustsecp256k1_v0_11_scalar_clear(&non); + rustsecp256k1_v0_11_scalar_clear(&sec); + rustsecp256k1_v0_11_scalar_cmov(r, &rustsecp256k1_v0_11_scalar_zero, !ret); + rustsecp256k1_v0_11_scalar_cmov(s, &rustsecp256k1_v0_11_scalar_zero, !ret); + if (recid) { + const int zero = 0; + rustsecp256k1_v0_11_int_cmov(recid, &zero, !ret); + } + return ret; +} + +int rustsecp256k1_v0_11_ecdsa_sign(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ecdsa_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, rustsecp256k1_v0_11_nonce_function noncefp, const void* noncedata) { + rustsecp256k1_v0_11_scalar r, s; + int ret; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(rustsecp256k1_v0_11_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msghash32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); + + ret = rustsecp256k1_v0_11_ecdsa_sign_inner(ctx, &r, &s, NULL, msghash32, seckey, noncefp, noncedata); + rustsecp256k1_v0_11_ecdsa_signature_save(signature, &r, &s); + return ret; +} + +int rustsecp256k1_v0_11_ec_seckey_verify(const rustsecp256k1_v0_11_context* ctx, const unsigned char *seckey) { + rustsecp256k1_v0_11_scalar sec; + int ret; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + + ret = rustsecp256k1_v0_11_scalar_set_b32_seckey(&sec, seckey); + rustsecp256k1_v0_11_scalar_clear(&sec); + return ret; +} + +static int rustsecp256k1_v0_11_ec_pubkey_create_helper(const rustsecp256k1_v0_11_ecmult_gen_context *ecmult_gen_ctx, rustsecp256k1_v0_11_scalar *seckey_scalar, rustsecp256k1_v0_11_ge *p, const unsigned char *seckey) { + rustsecp256k1_v0_11_gej pj; + int ret; + + ret = rustsecp256k1_v0_11_scalar_set_b32_seckey(seckey_scalar, seckey); + rustsecp256k1_v0_11_scalar_cmov(seckey_scalar, &rustsecp256k1_v0_11_scalar_one, !ret); + + rustsecp256k1_v0_11_ecmult_gen(ecmult_gen_ctx, &pj, seckey_scalar); + rustsecp256k1_v0_11_ge_set_gej(p, &pj); + rustsecp256k1_v0_11_gej_clear(&pj); + return ret; +} + +int rustsecp256k1_v0_11_ec_pubkey_create(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *seckey) { + rustsecp256k1_v0_11_ge p; + rustsecp256k1_v0_11_scalar seckey_scalar; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(rustsecp256k1_v0_11_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey != NULL); + + ret = rustsecp256k1_v0_11_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey); + rustsecp256k1_v0_11_pubkey_save(pubkey, &p); + rustsecp256k1_v0_11_memczero(pubkey, sizeof(*pubkey), !ret); + + rustsecp256k1_v0_11_scalar_clear(&seckey_scalar); + return ret; +} + +int rustsecp256k1_v0_11_ec_seckey_negate(const rustsecp256k1_v0_11_context* ctx, unsigned char *seckey) { + rustsecp256k1_v0_11_scalar sec; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + + ret = rustsecp256k1_v0_11_scalar_set_b32_seckey(&sec, seckey); + rustsecp256k1_v0_11_scalar_cmov(&sec, &rustsecp256k1_v0_11_scalar_zero, !ret); + rustsecp256k1_v0_11_scalar_negate(&sec, &sec); + rustsecp256k1_v0_11_scalar_get_b32(seckey, &sec); + + rustsecp256k1_v0_11_scalar_clear(&sec); + return ret; +} + +int rustsecp256k1_v0_11_ec_privkey_negate(const rustsecp256k1_v0_11_context* ctx, unsigned char *seckey) { + return rustsecp256k1_v0_11_ec_seckey_negate(ctx, seckey); +} + +int rustsecp256k1_v0_11_ec_pubkey_negate(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *pubkey) { + int ret = 0; + rustsecp256k1_v0_11_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + + ret = rustsecp256k1_v0_11_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + rustsecp256k1_v0_11_ge_neg(&p, &p); + rustsecp256k1_v0_11_pubkey_save(pubkey, &p); + } + return ret; +} + + +static int rustsecp256k1_v0_11_ec_seckey_tweak_add_helper(rustsecp256k1_v0_11_scalar *sec, const unsigned char *tweak32) { + rustsecp256k1_v0_11_scalar term; + int overflow = 0; + int ret = 0; + + rustsecp256k1_v0_11_scalar_set_b32(&term, tweak32, &overflow); + ret = (!overflow) & rustsecp256k1_v0_11_eckey_privkey_tweak_add(sec, &term); + rustsecp256k1_v0_11_scalar_clear(&term); + return ret; +} + +int rustsecp256k1_v0_11_ec_seckey_tweak_add(const rustsecp256k1_v0_11_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { + rustsecp256k1_v0_11_scalar sec; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak32 != NULL); + + ret = rustsecp256k1_v0_11_scalar_set_b32_seckey(&sec, seckey); + ret &= rustsecp256k1_v0_11_ec_seckey_tweak_add_helper(&sec, tweak32); + rustsecp256k1_v0_11_scalar_cmov(&sec, &rustsecp256k1_v0_11_scalar_zero, !ret); + rustsecp256k1_v0_11_scalar_get_b32(seckey, &sec); + + rustsecp256k1_v0_11_scalar_clear(&sec); + return ret; +} + +int rustsecp256k1_v0_11_ec_privkey_tweak_add(const rustsecp256k1_v0_11_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { + return rustsecp256k1_v0_11_ec_seckey_tweak_add(ctx, seckey, tweak32); +} + +static int rustsecp256k1_v0_11_ec_pubkey_tweak_add_helper(rustsecp256k1_v0_11_ge *p, const unsigned char *tweak32) { + rustsecp256k1_v0_11_scalar term; + int overflow = 0; + rustsecp256k1_v0_11_scalar_set_b32(&term, tweak32, &overflow); + return !overflow && rustsecp256k1_v0_11_eckey_pubkey_tweak_add(p, &term); +} + +int rustsecp256k1_v0_11_ec_pubkey_tweak_add(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *tweak32) { + rustsecp256k1_v0_11_ge p; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak32 != NULL); + + ret = rustsecp256k1_v0_11_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + ret = ret && rustsecp256k1_v0_11_ec_pubkey_tweak_add_helper(&p, tweak32); + if (ret) { + rustsecp256k1_v0_11_pubkey_save(pubkey, &p); + } + + return ret; +} + +int rustsecp256k1_v0_11_ec_seckey_tweak_mul(const rustsecp256k1_v0_11_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { + rustsecp256k1_v0_11_scalar factor; + rustsecp256k1_v0_11_scalar sec; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak32 != NULL); + + rustsecp256k1_v0_11_scalar_set_b32(&factor, tweak32, &overflow); + ret = rustsecp256k1_v0_11_scalar_set_b32_seckey(&sec, seckey); + ret &= (!overflow) & rustsecp256k1_v0_11_eckey_privkey_tweak_mul(&sec, &factor); + rustsecp256k1_v0_11_scalar_cmov(&sec, &rustsecp256k1_v0_11_scalar_zero, !ret); + rustsecp256k1_v0_11_scalar_get_b32(seckey, &sec); + + rustsecp256k1_v0_11_scalar_clear(&sec); + rustsecp256k1_v0_11_scalar_clear(&factor); + return ret; +} + +int rustsecp256k1_v0_11_ec_privkey_tweak_mul(const rustsecp256k1_v0_11_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { + return rustsecp256k1_v0_11_ec_seckey_tweak_mul(ctx, seckey, tweak32); +} + +int rustsecp256k1_v0_11_ec_pubkey_tweak_mul(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *tweak32) { + rustsecp256k1_v0_11_ge p; + rustsecp256k1_v0_11_scalar factor; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak32 != NULL); + + rustsecp256k1_v0_11_scalar_set_b32(&factor, tweak32, &overflow); + ret = !overflow && rustsecp256k1_v0_11_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + if (rustsecp256k1_v0_11_eckey_pubkey_tweak_mul(&p, &factor)) { + rustsecp256k1_v0_11_pubkey_save(pubkey, &p); + } else { + ret = 0; + } + } + + return ret; +} + +int rustsecp256k1_v0_11_context_randomize(rustsecp256k1_v0_11_context* ctx, const unsigned char *seed32) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(rustsecp256k1_v0_11_context_is_proper(ctx)); + + if (rustsecp256k1_v0_11_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) { + rustsecp256k1_v0_11_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + } + return 1; +} + +int rustsecp256k1_v0_11_ec_pubkey_combine(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *pubnonce, const rustsecp256k1_v0_11_pubkey * const *pubnonces, size_t n) { + size_t i; + rustsecp256k1_v0_11_gej Qj; + rustsecp256k1_v0_11_ge Q; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubnonce != NULL); + memset(pubnonce, 0, sizeof(*pubnonce)); + ARG_CHECK(n >= 1); + ARG_CHECK(pubnonces != NULL); + + rustsecp256k1_v0_11_gej_set_infinity(&Qj); + + for (i = 0; i < n; i++) { + ARG_CHECK(pubnonces[i] != NULL); + rustsecp256k1_v0_11_pubkey_load(ctx, &Q, pubnonces[i]); + rustsecp256k1_v0_11_gej_add_ge(&Qj, &Qj, &Q); + } + if (rustsecp256k1_v0_11_gej_is_infinity(&Qj)) { + return 0; + } + rustsecp256k1_v0_11_ge_set_gej(&Q, &Qj); + rustsecp256k1_v0_11_pubkey_save(pubnonce, &Q); + return 1; +} + +int rustsecp256k1_v0_11_tagged_sha256(const rustsecp256k1_v0_11_context* ctx, unsigned char *hash32, const unsigned char *tag, size_t taglen, const unsigned char *msg, size_t msglen) { + rustsecp256k1_v0_11_sha256 sha; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(hash32 != NULL); + ARG_CHECK(tag != NULL); + ARG_CHECK(msg != NULL); + + rustsecp256k1_v0_11_sha256_initialize_tagged(&sha, tag, taglen); + rustsecp256k1_v0_11_sha256_write(&sha, msg, msglen); + rustsecp256k1_v0_11_sha256_finalize(&sha, hash32); + rustsecp256k1_v0_11_sha256_clear(&sha); + return 1; +} + +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_EXTRAKEYS +# include "modules/extrakeys/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_MUSIG +# include "modules/musig/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT +# include "modules/ellswift/main_impl.h" +#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/secp256k1.c.orig b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/secp256k1.c.orig new file mode 100644 index 00000000..6dc6cfc2 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/secp256k1.c.orig @@ -0,0 +1,831 @@ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +/* This is a C project. It should not be compiled with a C++ compiler, + * and we error out if we detect one. + * + * We still want to be able to test the project with a C++ compiler + * because it is still good to know if this will lead to real trouble, so + * there is a possibility to override the check. But be warned that + * compiling with a C++ compiler is not supported. */ +#if defined(__cplusplus) && !defined(SECP256K1_CPLUSPLUS_TEST_OVERRIDE) +#error Trying to compile a C project with a C++ compiler. +#endif + +#define SECP256K1_BUILD + +#include "../include/secp256k1.h" +#include "../include/secp256k1_preallocated.h" + +#include "assumptions.h" +#include "checkmem.h" +#include "util.h" + +#include "field_impl.h" +#include "scalar_impl.h" +#include "group_impl.h" +#include "ecmult_impl.h" +#include "ecmult_const_impl.h" +#include "ecmult_gen_impl.h" +#include "ecdsa_impl.h" +#include "eckey_impl.h" +#include "hash_impl.h" +#include "int128_impl.h" +#include "scratch_impl.h" +#include "selftest.h" +#include "hsort_impl.h" + +#ifdef SECP256K1_NO_BUILD +# error "secp256k1.h processed without SECP256K1_BUILD defined while building secp256k1.c" +#endif + +#define ARG_CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + rustsecp256k1_v0_11_callback_call(&ctx->illegal_callback, #cond); \ + return 0; \ + } \ +} while(0) + +#define ARG_CHECK_VOID(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + rustsecp256k1_v0_11_callback_call(&ctx->illegal_callback, #cond); \ + return; \ + } \ +} while(0) + +/* Note that whenever you change the context struct, you must also change the + * context_eq function. */ +struct rustsecp256k1_v0_11_context_struct { + rustsecp256k1_v0_11_ecmult_gen_context ecmult_gen_ctx; + rustsecp256k1_v0_11_callback illegal_callback; + rustsecp256k1_v0_11_callback error_callback; + int declassify; +}; + +static const rustsecp256k1_v0_11_context rustsecp256k1_v0_11_context_static_ = { + { 0 }, + { rustsecp256k1_v0_11_default_illegal_callback_fn, 0 }, + { rustsecp256k1_v0_11_default_error_callback_fn, 0 }, + 0 +}; +const rustsecp256k1_v0_11_context *rustsecp256k1_v0_11_context_static = &rustsecp256k1_v0_11_context_static_; +const rustsecp256k1_v0_11_context *rustsecp256k1_v0_11_context_no_precomp = &rustsecp256k1_v0_11_context_static_; + +/* Helper function that determines if a context is proper, i.e., is not the static context or a copy thereof. + * + * This is intended for "context" functions such as rustsecp256k1_v0_11_context_clone. Functions that need specific + * features of a context should still check for these features directly. For example, a function that needs + * ecmult_gen should directly check for the existence of the ecmult_gen context. */ +static int rustsecp256k1_v0_11_context_is_proper(const rustsecp256k1_v0_11_context* ctx) { + return rustsecp256k1_v0_11_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx); +} + +void rustsecp256k1_v0_11_selftest(void) { + if (!rustsecp256k1_v0_11_selftest_passes()) { + rustsecp256k1_v0_11_callback_call(&default_error_callback, "self test failed"); + } +} + +size_t rustsecp256k1_v0_11_context_preallocated_size(unsigned int flags) { + size_t ret = sizeof(rustsecp256k1_v0_11_context); + /* A return value of 0 is reserved as an indicator for errors when we call this function internally. */ + VERIFY_CHECK(ret != 0); + + if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { + rustsecp256k1_v0_11_callback_call(&default_illegal_callback, + "Invalid flags"); + return 0; + } + + if (EXPECT(!SECP256K1_CHECKMEM_RUNNING() && (flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY), 0)) { + rustsecp256k1_v0_11_callback_call(&default_illegal_callback, + "Declassify flag requires running with memory checking"); + return 0; + } + + return ret; +} + +size_t rustsecp256k1_v0_11_context_preallocated_clone_size(const rustsecp256k1_v0_11_context* ctx) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(rustsecp256k1_v0_11_context_is_proper(ctx)); + return sizeof(rustsecp256k1_v0_11_context); +} + +rustsecp256k1_v0_11_context* rustsecp256k1_v0_11_context_preallocated_create(void* prealloc, unsigned int flags) { + size_t prealloc_size; + rustsecp256k1_v0_11_context* ret; + + rustsecp256k1_v0_11_selftest(); + + prealloc_size = rustsecp256k1_v0_11_context_preallocated_size(flags); + if (prealloc_size == 0) { + return NULL; + } + VERIFY_CHECK(prealloc != NULL); + ret = (rustsecp256k1_v0_11_context*)prealloc; + ret->illegal_callback = default_illegal_callback; + ret->error_callback = default_error_callback; + + /* Flags have been checked by rustsecp256k1_v0_11_context_preallocated_size. */ + VERIFY_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_CONTEXT); + rustsecp256k1_v0_11_ecmult_gen_context_build(&ret->ecmult_gen_ctx); + ret->declassify = !!(flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY); + + return ret; +} + +rustsecp256k1_v0_11_context* rustsecp256k1_v0_11_context_create(unsigned int flags) { + size_t const prealloc_size = rustsecp256k1_v0_11_context_preallocated_size(flags); + rustsecp256k1_v0_11_context* ctx = (rustsecp256k1_v0_11_context*)checked_malloc(&default_error_callback, prealloc_size); + if (EXPECT(rustsecp256k1_v0_11_context_preallocated_create(ctx, flags) == NULL, 0)) { + free(ctx); + return NULL; + } + + return ctx; +} + +rustsecp256k1_v0_11_context* rustsecp256k1_v0_11_context_preallocated_clone(const rustsecp256k1_v0_11_context* ctx, void* prealloc) { + rustsecp256k1_v0_11_context* ret; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(prealloc != NULL); + ARG_CHECK(rustsecp256k1_v0_11_context_is_proper(ctx)); + + ret = (rustsecp256k1_v0_11_context*)prealloc; + *ret = *ctx; + return ret; +} + +rustsecp256k1_v0_11_context* rustsecp256k1_v0_11_context_clone(const rustsecp256k1_v0_11_context* ctx) { + rustsecp256k1_v0_11_context* ret; + size_t prealloc_size; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(rustsecp256k1_v0_11_context_is_proper(ctx)); + + prealloc_size = rustsecp256k1_v0_11_context_preallocated_clone_size(ctx); + ret = (rustsecp256k1_v0_11_context*)checked_malloc(&ctx->error_callback, prealloc_size); + ret = rustsecp256k1_v0_11_context_preallocated_clone(ctx, ret); + return ret; +} + +void rustsecp256k1_v0_11_context_preallocated_destroy(rustsecp256k1_v0_11_context* ctx) { + ARG_CHECK_VOID(ctx == NULL || rustsecp256k1_v0_11_context_is_proper(ctx)); + + /* Defined as noop */ + if (ctx == NULL) { + return; + } + + rustsecp256k1_v0_11_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); +} + +void rustsecp256k1_v0_11_context_destroy(rustsecp256k1_v0_11_context* ctx) { + ARG_CHECK_VOID(ctx == NULL || rustsecp256k1_v0_11_context_is_proper(ctx)); + + /* Defined as noop */ + if (ctx == NULL) { + return; + } + + rustsecp256k1_v0_11_context_preallocated_destroy(ctx); + free(ctx); +} + +void rustsecp256k1_v0_11_context_set_illegal_callback(rustsecp256k1_v0_11_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + /* We compare pointers instead of checking rustsecp256k1_v0_11_context_is_proper() here + because setting callbacks is allowed on *copies* of the static context: + it's harmless and makes testing easier. */ + ARG_CHECK_VOID(ctx != rustsecp256k1_v0_11_context_static); + if (fun == NULL) { + fun = rustsecp256k1_v0_11_default_illegal_callback_fn; + } + ctx->illegal_callback.fn = fun; + ctx->illegal_callback.data = data; +} + +void rustsecp256k1_v0_11_context_set_error_callback(rustsecp256k1_v0_11_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + /* We compare pointers instead of checking rustsecp256k1_v0_11_context_is_proper() here + because setting callbacks is allowed on *copies* of the static context: + it's harmless and makes testing easier. */ + ARG_CHECK_VOID(ctx != rustsecp256k1_v0_11_context_static); + if (fun == NULL) { + fun = rustsecp256k1_v0_11_default_error_callback_fn; + } + ctx->error_callback.fn = fun; + ctx->error_callback.data = data; +} + +static rustsecp256k1_v0_11_scratch_space* rustsecp256k1_v0_11_scratch_space_create(const rustsecp256k1_v0_11_context* ctx, size_t max_size) { + VERIFY_CHECK(ctx != NULL); + return rustsecp256k1_v0_11_scratch_create(&ctx->error_callback, max_size); +} + +static void rustsecp256k1_v0_11_scratch_space_destroy(const rustsecp256k1_v0_11_context *ctx, rustsecp256k1_v0_11_scratch_space* scratch) { + VERIFY_CHECK(ctx != NULL); + rustsecp256k1_v0_11_scratch_destroy(&ctx->error_callback, scratch); +} + +/* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour + * of the software. + */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_declassify(const rustsecp256k1_v0_11_context* ctx, const void *p, size_t len) { + if (EXPECT(ctx->declassify, 0)) SECP256K1_CHECKMEM_DEFINE(p, len); +} + +static int rustsecp256k1_v0_11_pubkey_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ge* ge, const rustsecp256k1_v0_11_pubkey* pubkey) { + rustsecp256k1_v0_11_ge_from_bytes(ge, pubkey->data); + ARG_CHECK(!rustsecp256k1_v0_11_fe_is_zero(&ge->x)); + return 1; +} + +static void rustsecp256k1_v0_11_pubkey_save(rustsecp256k1_v0_11_pubkey* pubkey, rustsecp256k1_v0_11_ge* ge) { + rustsecp256k1_v0_11_ge_to_bytes(pubkey->data, ge); +} + +int rustsecp256k1_v0_11_ec_pubkey_parse(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey* pubkey, const unsigned char *input, size_t inputlen) { + rustsecp256k1_v0_11_ge Q; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(input != NULL); + if (!rustsecp256k1_v0_11_eckey_pubkey_parse(&Q, input, inputlen)) { + return 0; + } + if (!rustsecp256k1_v0_11_ge_is_in_correct_subgroup(&Q)) { + return 0; + } + rustsecp256k1_v0_11_pubkey_save(pubkey, &Q); + rustsecp256k1_v0_11_ge_clear(&Q); + return 1; +} + +int rustsecp256k1_v0_11_ec_pubkey_serialize(const rustsecp256k1_v0_11_context* ctx, unsigned char *output, size_t *outputlen, const rustsecp256k1_v0_11_pubkey* pubkey, unsigned int flags) { + rustsecp256k1_v0_11_ge Q; + size_t len; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33u : 65u)); + len = *outputlen; + *outputlen = 0; + ARG_CHECK(output != NULL); + memset(output, 0, len); + ARG_CHECK(pubkey != NULL); + ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); + if (rustsecp256k1_v0_11_pubkey_load(ctx, &Q, pubkey)) { + ret = rustsecp256k1_v0_11_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); + if (ret) { + *outputlen = len; + } + } + return ret; +} + +int rustsecp256k1_v0_11_ec_pubkey_cmp(const rustsecp256k1_v0_11_context* ctx, const rustsecp256k1_v0_11_pubkey* pubkey0, const rustsecp256k1_v0_11_pubkey* pubkey1) { + unsigned char out[2][33]; + const rustsecp256k1_v0_11_pubkey* pk[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + pk[0] = pubkey0; pk[1] = pubkey1; + for (i = 0; i < 2; i++) { + size_t out_size = sizeof(out[i]); + /* If the public key is NULL or invalid, ec_pubkey_serialize will call + * the illegal_callback and return 0. In that case we will serialize the + * key as all zeros which is less than any valid public key. This + * results in consistent comparisons even if NULL or invalid pubkeys are + * involved and prevents edge cases such as sorting algorithms that use + * this function and do not terminate as a result. */ + if (!rustsecp256k1_v0_11_ec_pubkey_serialize(ctx, out[i], &out_size, pk[i], SECP256K1_EC_COMPRESSED)) { + /* Note that ec_pubkey_serialize should already set the output to + * zero in that case, but it's not guaranteed by the API, we can't + * test it and writing a VERIFY_CHECK is more complex than + * explicitly memsetting (again). */ + memset(out[i], 0, sizeof(out[i])); + } + } + return rustsecp256k1_v0_11_memcmp_var(out[0], out[1], sizeof(out[0])); +} + +static int rustsecp256k1_v0_11_ec_pubkey_sort_cmp(const void* pk1, const void* pk2, void *ctx) { + return rustsecp256k1_v0_11_ec_pubkey_cmp((rustsecp256k1_v0_11_context *)ctx, + *(rustsecp256k1_v0_11_pubkey **)pk1, + *(rustsecp256k1_v0_11_pubkey **)pk2); +} + +int rustsecp256k1_v0_11_ec_pubkey_sort(const rustsecp256k1_v0_11_context* ctx, const rustsecp256k1_v0_11_pubkey **pubkeys, size_t n_pubkeys) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkeys != NULL); + + /* Suppress wrong warning (fixed in MSVC 19.33) */ + #if defined(_MSC_VER) && (_MSC_VER < 1933) + #pragma warning(push) + #pragma warning(disable: 4090) + #endif + + /* Casting away const is fine because neither rustsecp256k1_v0_11_hsort nor + * rustsecp256k1_v0_11_ec_pubkey_sort_cmp modify the data pointed to by the cmp_data + * argument. */ + rustsecp256k1_v0_11_hsort(pubkeys, n_pubkeys, sizeof(*pubkeys), rustsecp256k1_v0_11_ec_pubkey_sort_cmp, (void *)ctx); + + #if defined(_MSC_VER) && (_MSC_VER < 1933) + #pragma warning(pop) + #endif + + return 1; +} + +static void rustsecp256k1_v0_11_ecdsa_signature_load(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_scalar* r, rustsecp256k1_v0_11_scalar* s, const rustsecp256k1_v0_11_ecdsa_signature* sig) { + (void)ctx; + if (sizeof(rustsecp256k1_v0_11_scalar) == 32) { + /* When the rustsecp256k1_v0_11_scalar type is exactly 32 byte, use its + * representation inside rustsecp256k1_v0_11_ecdsa_signature, as conversion is very fast. + * Note that rustsecp256k1_v0_11_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + rustsecp256k1_v0_11_scalar_set_b32(r, &sig->data[0], NULL); + rustsecp256k1_v0_11_scalar_set_b32(s, &sig->data[32], NULL); + } +} + +static void rustsecp256k1_v0_11_ecdsa_signature_save(rustsecp256k1_v0_11_ecdsa_signature* sig, const rustsecp256k1_v0_11_scalar* r, const rustsecp256k1_v0_11_scalar* s) { + if (sizeof(rustsecp256k1_v0_11_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + rustsecp256k1_v0_11_scalar_get_b32(&sig->data[0], r); + rustsecp256k1_v0_11_scalar_get_b32(&sig->data[32], s); + } +} + +int rustsecp256k1_v0_11_ecdsa_signature_parse_der(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + rustsecp256k1_v0_11_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input != NULL); + + if (rustsecp256k1_v0_11_ecdsa_sig_parse(&r, &s, input, inputlen)) { + rustsecp256k1_v0_11_ecdsa_signature_save(sig, &r, &s); + return 1; + } else { + memset(sig, 0, sizeof(*sig)); + return 0; + } +} + +int rustsecp256k1_v0_11_ecdsa_signature_parse_compact(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ecdsa_signature* sig, const unsigned char *input64) { + rustsecp256k1_v0_11_scalar r, s; + int ret = 1; + int overflow = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + + rustsecp256k1_v0_11_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + rustsecp256k1_v0_11_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + rustsecp256k1_v0_11_ecdsa_signature_save(sig, &r, &s); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + +int rustsecp256k1_v0_11_ecdsa_signature_serialize_der(const rustsecp256k1_v0_11_context* ctx, unsigned char *output, size_t *outputlen, const rustsecp256k1_v0_11_ecdsa_signature* sig) { + rustsecp256k1_v0_11_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(sig != NULL); + + rustsecp256k1_v0_11_ecdsa_signature_load(ctx, &r, &s, sig); + return rustsecp256k1_v0_11_ecdsa_sig_serialize(output, outputlen, &r, &s); +} + +int rustsecp256k1_v0_11_ecdsa_signature_serialize_compact(const rustsecp256k1_v0_11_context* ctx, unsigned char *output64, const rustsecp256k1_v0_11_ecdsa_signature* sig) { + rustsecp256k1_v0_11_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + + rustsecp256k1_v0_11_ecdsa_signature_load(ctx, &r, &s, sig); + rustsecp256k1_v0_11_scalar_get_b32(&output64[0], &r); + rustsecp256k1_v0_11_scalar_get_b32(&output64[32], &s); + return 1; +} + +int rustsecp256k1_v0_11_ecdsa_signature_normalize(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ecdsa_signature *sigout, const rustsecp256k1_v0_11_ecdsa_signature *sigin) { + rustsecp256k1_v0_11_scalar r, s; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sigin != NULL); + + rustsecp256k1_v0_11_ecdsa_signature_load(ctx, &r, &s, sigin); + ret = rustsecp256k1_v0_11_scalar_is_high(&s); + if (sigout != NULL) { + if (ret) { + rustsecp256k1_v0_11_scalar_negate(&s, &s); + } + rustsecp256k1_v0_11_ecdsa_signature_save(sigout, &r, &s); + } + + return ret; +} + +int rustsecp256k1_v0_11_ecdsa_verify(const rustsecp256k1_v0_11_context* ctx, const rustsecp256k1_v0_11_ecdsa_signature *sig, const unsigned char *msghash32, const rustsecp256k1_v0_11_pubkey *pubkey) { + rustsecp256k1_v0_11_ge q; + rustsecp256k1_v0_11_scalar r, s; + rustsecp256k1_v0_11_scalar m; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(msghash32 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(pubkey != NULL); + + rustsecp256k1_v0_11_scalar_set_b32(&m, msghash32, NULL); + rustsecp256k1_v0_11_ecdsa_signature_load(ctx, &r, &s, sig); + return (!rustsecp256k1_v0_11_scalar_is_high(&s) && + rustsecp256k1_v0_11_pubkey_load(ctx, &q, pubkey) && + rustsecp256k1_v0_11_ecdsa_sig_verify(&r, &s, &q, &m)); +} + +static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *offset, const void *data, unsigned int len) { + memcpy(buf + *offset, data, len); + *offset += len; +} + +static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + unsigned char keydata[112]; + unsigned int offset = 0; + rustsecp256k1_v0_11_rfc6979_hmac_sha256 rng; + unsigned int i; + rustsecp256k1_v0_11_scalar msg; + unsigned char msgmod32[32]; + rustsecp256k1_v0_11_scalar_set_b32(&msg, msg32, NULL); + rustsecp256k1_v0_11_scalar_get_b32(msgmod32, &msg); + /* We feed a byte array to the PRNG as input, consisting of: + * - the private key (32 bytes) and reduced message (32 bytes), see RFC 6979 3.2d. + * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. + * - optionally 16 extra bytes with the algorithm name. + * Because the arguments have distinct fixed lengths it is not possible for + * different argument mixtures to emulate each other and result in the same + * nonces. + */ + buffer_append(keydata, &offset, key32, 32); + buffer_append(keydata, &offset, msgmod32, 32); + if (data != NULL) { + buffer_append(keydata, &offset, data, 32); + } + if (algo16 != NULL) { + buffer_append(keydata, &offset, algo16, 16); + } + rustsecp256k1_v0_11_rfc6979_hmac_sha256_initialize(&rng, keydata, offset); + for (i = 0; i <= counter; i++) { + rustsecp256k1_v0_11_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + } + rustsecp256k1_v0_11_rfc6979_hmac_sha256_finalize(&rng); + + rustsecp256k1_v0_11_memclear(keydata, sizeof(keydata)); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_clear(&rng); + return 1; +} + +const rustsecp256k1_v0_11_nonce_function rustsecp256k1_v0_11_nonce_function_rfc6979 = nonce_function_rfc6979; +const rustsecp256k1_v0_11_nonce_function rustsecp256k1_v0_11_nonce_function_default = nonce_function_rfc6979; + +static int rustsecp256k1_v0_11_ecdsa_sign_inner(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_scalar* r, rustsecp256k1_v0_11_scalar* s, int* recid, const unsigned char *msg32, const unsigned char *seckey, rustsecp256k1_v0_11_nonce_function noncefp, const void* noncedata) { + rustsecp256k1_v0_11_scalar sec, non, msg; + int ret = 0; + int is_sec_valid; + unsigned char nonce32[32]; + unsigned int count = 0; + /* Default initialization here is important so we won't pass uninit values to the cmov in the end */ + *r = rustsecp256k1_v0_11_scalar_zero; + *s = rustsecp256k1_v0_11_scalar_zero; + if (recid) { + *recid = 0; + } + if (noncefp == NULL) { + noncefp = rustsecp256k1_v0_11_nonce_function_default; + } + + /* Fail if the secret key is invalid. */ + is_sec_valid = rustsecp256k1_v0_11_scalar_set_b32_seckey(&sec, seckey); + rustsecp256k1_v0_11_scalar_cmov(&sec, &rustsecp256k1_v0_11_scalar_one, !is_sec_valid); + rustsecp256k1_v0_11_scalar_set_b32(&msg, msg32, NULL); + while (1) { + int is_nonce_valid; + ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + is_nonce_valid = rustsecp256k1_v0_11_scalar_set_b32_seckey(&non, nonce32); + /* The nonce is still secret here, but it being invalid is less likely than 1:2^255. */ + rustsecp256k1_v0_11_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid)); + if (is_nonce_valid) { + ret = rustsecp256k1_v0_11_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, r, s, &sec, &msg, &non, recid); + /* The final signature is no longer a secret, nor is the fact that we were successful or not. */ + rustsecp256k1_v0_11_declassify(ctx, &ret, sizeof(ret)); + if (ret) { + break; + } + } + count++; + } + /* We don't want to declassify is_sec_valid and therefore the range of + * seckey. As a result is_sec_valid is included in ret only after ret was + * used as a branching variable. */ + ret &= is_sec_valid; + rustsecp256k1_v0_11_memclear(nonce32, sizeof(nonce32)); + rustsecp256k1_v0_11_scalar_clear(&msg); + rustsecp256k1_v0_11_scalar_clear(&non); + rustsecp256k1_v0_11_scalar_clear(&sec); + rustsecp256k1_v0_11_scalar_cmov(r, &rustsecp256k1_v0_11_scalar_zero, !ret); + rustsecp256k1_v0_11_scalar_cmov(s, &rustsecp256k1_v0_11_scalar_zero, !ret); + if (recid) { + const int zero = 0; + rustsecp256k1_v0_11_int_cmov(recid, &zero, !ret); + } + return ret; +} + +int rustsecp256k1_v0_11_ecdsa_sign(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_ecdsa_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, rustsecp256k1_v0_11_nonce_function noncefp, const void* noncedata) { + rustsecp256k1_v0_11_scalar r, s; + int ret; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(rustsecp256k1_v0_11_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msghash32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); + + ret = rustsecp256k1_v0_11_ecdsa_sign_inner(ctx, &r, &s, NULL, msghash32, seckey, noncefp, noncedata); + rustsecp256k1_v0_11_ecdsa_signature_save(signature, &r, &s); + return ret; +} + +int rustsecp256k1_v0_11_ec_seckey_verify(const rustsecp256k1_v0_11_context* ctx, const unsigned char *seckey) { + rustsecp256k1_v0_11_scalar sec; + int ret; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + + ret = rustsecp256k1_v0_11_scalar_set_b32_seckey(&sec, seckey); + rustsecp256k1_v0_11_scalar_clear(&sec); + return ret; +} + +static int rustsecp256k1_v0_11_ec_pubkey_create_helper(const rustsecp256k1_v0_11_ecmult_gen_context *ecmult_gen_ctx, rustsecp256k1_v0_11_scalar *seckey_scalar, rustsecp256k1_v0_11_ge *p, const unsigned char *seckey) { + rustsecp256k1_v0_11_gej pj; + int ret; + + ret = rustsecp256k1_v0_11_scalar_set_b32_seckey(seckey_scalar, seckey); + rustsecp256k1_v0_11_scalar_cmov(seckey_scalar, &rustsecp256k1_v0_11_scalar_one, !ret); + + rustsecp256k1_v0_11_ecmult_gen(ecmult_gen_ctx, &pj, seckey_scalar); + rustsecp256k1_v0_11_ge_set_gej(p, &pj); + rustsecp256k1_v0_11_gej_clear(&pj); + return ret; +} + +int rustsecp256k1_v0_11_ec_pubkey_create(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *seckey) { + rustsecp256k1_v0_11_ge p; + rustsecp256k1_v0_11_scalar seckey_scalar; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(rustsecp256k1_v0_11_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey != NULL); + + ret = rustsecp256k1_v0_11_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey); + rustsecp256k1_v0_11_pubkey_save(pubkey, &p); + rustsecp256k1_v0_11_memczero(pubkey, sizeof(*pubkey), !ret); + + rustsecp256k1_v0_11_scalar_clear(&seckey_scalar); + return ret; +} + +int rustsecp256k1_v0_11_ec_seckey_negate(const rustsecp256k1_v0_11_context* ctx, unsigned char *seckey) { + rustsecp256k1_v0_11_scalar sec; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + + ret = rustsecp256k1_v0_11_scalar_set_b32_seckey(&sec, seckey); + rustsecp256k1_v0_11_scalar_cmov(&sec, &rustsecp256k1_v0_11_scalar_zero, !ret); + rustsecp256k1_v0_11_scalar_negate(&sec, &sec); + rustsecp256k1_v0_11_scalar_get_b32(seckey, &sec); + + rustsecp256k1_v0_11_scalar_clear(&sec); + return ret; +} + +int rustsecp256k1_v0_11_ec_privkey_negate(const rustsecp256k1_v0_11_context* ctx, unsigned char *seckey) { + return rustsecp256k1_v0_11_ec_seckey_negate(ctx, seckey); +} + +int rustsecp256k1_v0_11_ec_pubkey_negate(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *pubkey) { + int ret = 0; + rustsecp256k1_v0_11_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + + ret = rustsecp256k1_v0_11_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + rustsecp256k1_v0_11_ge_neg(&p, &p); + rustsecp256k1_v0_11_pubkey_save(pubkey, &p); + } + return ret; +} + + +static int rustsecp256k1_v0_11_ec_seckey_tweak_add_helper(rustsecp256k1_v0_11_scalar *sec, const unsigned char *tweak32) { + rustsecp256k1_v0_11_scalar term; + int overflow = 0; + int ret = 0; + + rustsecp256k1_v0_11_scalar_set_b32(&term, tweak32, &overflow); + ret = (!overflow) & rustsecp256k1_v0_11_eckey_privkey_tweak_add(sec, &term); + rustsecp256k1_v0_11_scalar_clear(&term); + return ret; +} + +int rustsecp256k1_v0_11_ec_seckey_tweak_add(const rustsecp256k1_v0_11_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { + rustsecp256k1_v0_11_scalar sec; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak32 != NULL); + + ret = rustsecp256k1_v0_11_scalar_set_b32_seckey(&sec, seckey); + ret &= rustsecp256k1_v0_11_ec_seckey_tweak_add_helper(&sec, tweak32); + rustsecp256k1_v0_11_scalar_cmov(&sec, &rustsecp256k1_v0_11_scalar_zero, !ret); + rustsecp256k1_v0_11_scalar_get_b32(seckey, &sec); + + rustsecp256k1_v0_11_scalar_clear(&sec); + return ret; +} + +int rustsecp256k1_v0_11_ec_privkey_tweak_add(const rustsecp256k1_v0_11_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { + return rustsecp256k1_v0_11_ec_seckey_tweak_add(ctx, seckey, tweak32); +} + +static int rustsecp256k1_v0_11_ec_pubkey_tweak_add_helper(rustsecp256k1_v0_11_ge *p, const unsigned char *tweak32) { + rustsecp256k1_v0_11_scalar term; + int overflow = 0; + rustsecp256k1_v0_11_scalar_set_b32(&term, tweak32, &overflow); + return !overflow && rustsecp256k1_v0_11_eckey_pubkey_tweak_add(p, &term); +} + +int rustsecp256k1_v0_11_ec_pubkey_tweak_add(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *tweak32) { + rustsecp256k1_v0_11_ge p; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak32 != NULL); + + ret = rustsecp256k1_v0_11_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + ret = ret && rustsecp256k1_v0_11_ec_pubkey_tweak_add_helper(&p, tweak32); + if (ret) { + rustsecp256k1_v0_11_pubkey_save(pubkey, &p); + } + + return ret; +} + +int rustsecp256k1_v0_11_ec_seckey_tweak_mul(const rustsecp256k1_v0_11_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { + rustsecp256k1_v0_11_scalar factor; + rustsecp256k1_v0_11_scalar sec; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak32 != NULL); + + rustsecp256k1_v0_11_scalar_set_b32(&factor, tweak32, &overflow); + ret = rustsecp256k1_v0_11_scalar_set_b32_seckey(&sec, seckey); + ret &= (!overflow) & rustsecp256k1_v0_11_eckey_privkey_tweak_mul(&sec, &factor); + rustsecp256k1_v0_11_scalar_cmov(&sec, &rustsecp256k1_v0_11_scalar_zero, !ret); + rustsecp256k1_v0_11_scalar_get_b32(seckey, &sec); + + rustsecp256k1_v0_11_scalar_clear(&sec); + rustsecp256k1_v0_11_scalar_clear(&factor); + return ret; +} + +int rustsecp256k1_v0_11_ec_privkey_tweak_mul(const rustsecp256k1_v0_11_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { + return rustsecp256k1_v0_11_ec_seckey_tweak_mul(ctx, seckey, tweak32); +} + +int rustsecp256k1_v0_11_ec_pubkey_tweak_mul(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *pubkey, const unsigned char *tweak32) { + rustsecp256k1_v0_11_ge p; + rustsecp256k1_v0_11_scalar factor; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak32 != NULL); + + rustsecp256k1_v0_11_scalar_set_b32(&factor, tweak32, &overflow); + ret = !overflow && rustsecp256k1_v0_11_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + if (rustsecp256k1_v0_11_eckey_pubkey_tweak_mul(&p, &factor)) { + rustsecp256k1_v0_11_pubkey_save(pubkey, &p); + } else { + ret = 0; + } + } + + return ret; +} + +int rustsecp256k1_v0_11_context_randomize(rustsecp256k1_v0_11_context* ctx, const unsigned char *seed32) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(rustsecp256k1_v0_11_context_is_proper(ctx)); + + if (rustsecp256k1_v0_11_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) { + rustsecp256k1_v0_11_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + } + return 1; +} + +int rustsecp256k1_v0_11_ec_pubkey_combine(const rustsecp256k1_v0_11_context* ctx, rustsecp256k1_v0_11_pubkey *pubnonce, const rustsecp256k1_v0_11_pubkey * const *pubnonces, size_t n) { + size_t i; + rustsecp256k1_v0_11_gej Qj; + rustsecp256k1_v0_11_ge Q; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubnonce != NULL); + memset(pubnonce, 0, sizeof(*pubnonce)); + ARG_CHECK(n >= 1); + ARG_CHECK(pubnonces != NULL); + + rustsecp256k1_v0_11_gej_set_infinity(&Qj); + + for (i = 0; i < n; i++) { + ARG_CHECK(pubnonces[i] != NULL); + rustsecp256k1_v0_11_pubkey_load(ctx, &Q, pubnonces[i]); + rustsecp256k1_v0_11_gej_add_ge(&Qj, &Qj, &Q); + } + if (rustsecp256k1_v0_11_gej_is_infinity(&Qj)) { + return 0; + } + rustsecp256k1_v0_11_ge_set_gej(&Q, &Qj); + rustsecp256k1_v0_11_pubkey_save(pubnonce, &Q); + return 1; +} + +int rustsecp256k1_v0_11_tagged_sha256(const rustsecp256k1_v0_11_context* ctx, unsigned char *hash32, const unsigned char *tag, size_t taglen, const unsigned char *msg, size_t msglen) { + rustsecp256k1_v0_11_sha256 sha; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(hash32 != NULL); + ARG_CHECK(tag != NULL); + ARG_CHECK(msg != NULL); + + rustsecp256k1_v0_11_sha256_initialize_tagged(&sha, tag, taglen); + rustsecp256k1_v0_11_sha256_write(&sha, msg, msglen); + rustsecp256k1_v0_11_sha256_finalize(&sha, hash32); + rustsecp256k1_v0_11_sha256_clear(&sha); + return 1; +} + +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_EXTRAKEYS +# include "modules/extrakeys/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_MUSIG +# include "modules/musig/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT +# include "modules/ellswift/main_impl.h" +#endif diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/selftest.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/selftest.h similarity index 65% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/selftest.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/selftest.h index 2f280263..6675a19f 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/selftest.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/selftest.h @@ -11,22 +11,22 @@ #include -static int rustsecp256k1zkp_v0_8_0_selftest_sha256(void) { +static int rustsecp256k1_v0_11_selftest_sha256(void) { static const char *input63 = "For this sample, this 63-byte string will be used as input data"; static const unsigned char output32[32] = { 0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42, }; unsigned char out[32]; - rustsecp256k1zkp_v0_8_0_sha256 hasher; - rustsecp256k1zkp_v0_8_0_sha256_initialize(&hasher); - rustsecp256k1zkp_v0_8_0_sha256_write(&hasher, (const unsigned char*)input63, 63); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&hasher, out); - return rustsecp256k1zkp_v0_8_0_memcmp_var(out, output32, 32) == 0; + rustsecp256k1_v0_11_sha256 hasher; + rustsecp256k1_v0_11_sha256_initialize(&hasher); + rustsecp256k1_v0_11_sha256_write(&hasher, (const unsigned char*)input63, 63); + rustsecp256k1_v0_11_sha256_finalize(&hasher, out); + return rustsecp256k1_v0_11_memcmp_var(out, output32, 32) == 0; } -static int rustsecp256k1zkp_v0_8_0_selftest(void) { - return rustsecp256k1zkp_v0_8_0_selftest_sha256(); +static int rustsecp256k1_v0_11_selftest_passes(void) { + return rustsecp256k1_v0_11_selftest_sha256(); } #endif /* SECP256K1_SELFTEST_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/testrand.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/testrand.h similarity index 54% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/testrand.h rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/testrand.h index 94c961a4..3c1ed3d4 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/testrand.h +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/testrand.h @@ -7,47 +7,42 @@ #ifndef SECP256K1_TESTRAND_H #define SECP256K1_TESTRAND_H -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif +#include "util.h" /* A non-cryptographic RNG used only for test infrastructure. */ /** Seed the pseudorandom number generator for testing. */ -SECP256K1_INLINE static void rustsecp256k1zkp_v0_8_0_testrand_seed(const unsigned char *seed16); +SECP256K1_INLINE static void testrand_seed(const unsigned char *seed16); /** Generate a pseudorandom number in the range [0..2**32-1]. */ -SECP256K1_INLINE static uint32_t rustsecp256k1zkp_v0_8_0_testrand32(void); +SECP256K1_INLINE static uint32_t testrand32(void); /** Generate a pseudorandom number in the range [0..2**64-1]. */ -SECP256K1_INLINE static uint64_t rustsecp256k1zkp_v0_8_0_testrand64(void); +SECP256K1_INLINE static uint64_t testrand64(void); /** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or * more. */ -SECP256K1_INLINE static uint64_t rustsecp256k1zkp_v0_8_0_testrand_bits(int bits); +SECP256K1_INLINE static uint64_t testrand_bits(int bits); /** Generate a pseudorandom number in the range [0..range-1]. */ -static uint32_t rustsecp256k1zkp_v0_8_0_testrand_int(uint32_t range); +static uint32_t testrand_int(uint32_t range); /** Generate a pseudorandom 32-byte array. */ -static void rustsecp256k1zkp_v0_8_0_testrand256(unsigned char *b32); +static void testrand256(unsigned char *b32); /** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ -static void rustsecp256k1zkp_v0_8_0_testrand256_test(unsigned char *b32); +static void testrand256_test(unsigned char *b32); /** Generate pseudorandom bytes with long sequences of zero and one bits. */ -static void rustsecp256k1zkp_v0_8_0_testrand_bytes_test(unsigned char *bytes, size_t len); - -/** Generate a pseudorandom 64-bit integer in the range min..max, inclusive. */ -static int64_t rustsecp256k1zkp_v0_8_0_testrandi64(uint64_t min, uint64_t max); +static void testrand_bytes_test(unsigned char *bytes, size_t len); /** Flip a single random bit in a byte array */ -static void rustsecp256k1zkp_v0_8_0_testrand_flip(unsigned char *b, size_t len); +static void testrand_flip(unsigned char *b, size_t len); /** Initialize the test RNG using (hex encoded) array up to 16 bytes, or randomly if hexseed is NULL. */ -static void rustsecp256k1zkp_v0_8_0_testrand_init(const char* hexseed); +static void testrand_init(const char* hexseed); /** Print final test information. */ -static void rustsecp256k1zkp_v0_8_0_testrand_finish(void); +static void testrand_finish(void); #endif /* SECP256K1_TESTRAND_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/testrand_impl.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/testrand_impl.h new file mode 100644 index 00000000..d23155ee --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/testrand_impl.h @@ -0,0 +1,167 @@ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_TESTRAND_IMPL_H +#define SECP256K1_TESTRAND_IMPL_H + +#include +#include +#include + +#include "testrand.h" +#include "hash.h" +#include "util.h" + +static uint64_t rustsecp256k1_v0_11_test_state[4]; + +SECP256K1_INLINE static void testrand_seed(const unsigned char *seed16) { + static const unsigned char PREFIX[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', ' ', 't', 'e', 's', 't', ' ', 'i', 'n', 'i', 't'}; + unsigned char out32[32]; + rustsecp256k1_v0_11_sha256 hash; + int i; + + /* Use SHA256(PREFIX || seed16) as initial state. */ + rustsecp256k1_v0_11_sha256_initialize(&hash); + rustsecp256k1_v0_11_sha256_write(&hash, PREFIX, sizeof(PREFIX)); + rustsecp256k1_v0_11_sha256_write(&hash, seed16, 16); + rustsecp256k1_v0_11_sha256_finalize(&hash, out32); + for (i = 0; i < 4; ++i) { + uint64_t s = 0; + int j; + for (j = 0; j < 8; ++j) s = (s << 8) | out32[8*i + j]; + rustsecp256k1_v0_11_test_state[i] = s; + } +} + +SECP256K1_INLINE static uint64_t rotl(const uint64_t x, int k) { + return (x << k) | (x >> (64 - k)); +} + +SECP256K1_INLINE static uint64_t testrand64(void) { + /* Test-only Xoshiro256++ RNG. See https://prng.di.unimi.it/ */ + const uint64_t result = rotl(rustsecp256k1_v0_11_test_state[0] + rustsecp256k1_v0_11_test_state[3], 23) + rustsecp256k1_v0_11_test_state[0]; + const uint64_t t = rustsecp256k1_v0_11_test_state[1] << 17; + rustsecp256k1_v0_11_test_state[2] ^= rustsecp256k1_v0_11_test_state[0]; + rustsecp256k1_v0_11_test_state[3] ^= rustsecp256k1_v0_11_test_state[1]; + rustsecp256k1_v0_11_test_state[1] ^= rustsecp256k1_v0_11_test_state[2]; + rustsecp256k1_v0_11_test_state[0] ^= rustsecp256k1_v0_11_test_state[3]; + rustsecp256k1_v0_11_test_state[2] ^= t; + rustsecp256k1_v0_11_test_state[3] = rotl(rustsecp256k1_v0_11_test_state[3], 45); + return result; +} + +SECP256K1_INLINE static uint64_t testrand_bits(int bits) { + if (bits == 0) return 0; + return testrand64() >> (64 - bits); +} + +SECP256K1_INLINE static uint32_t testrand32(void) { + return testrand64() >> 32; +} + +static uint32_t testrand_int(uint32_t range) { + uint32_t mask = 0; + uint32_t range_copy; + /* Reduce range by 1, changing its meaning to "maximum value". */ + VERIFY_CHECK(range != 0); + range -= 1; + /* Count the number of bits in range. */ + range_copy = range; + while (range_copy) { + mask = (mask << 1) | 1U; + range_copy >>= 1; + } + /* Generation loop. */ + while (1) { + uint32_t val = testrand64() & mask; + if (val <= range) return val; + } +} + +static void testrand256(unsigned char *b32) { + int i; + for (i = 0; i < 4; ++i) { + uint64_t val = testrand64(); + b32[0] = val; + b32[1] = val >> 8; + b32[2] = val >> 16; + b32[3] = val >> 24; + b32[4] = val >> 32; + b32[5] = val >> 40; + b32[6] = val >> 48; + b32[7] = val >> 56; + b32 += 8; + } +} + +static void testrand_bytes_test(unsigned char *bytes, size_t len) { + size_t bits = 0; + memset(bytes, 0, len); + while (bits < len * 8) { + int now; + uint32_t val; + now = 1 + (testrand_bits(6) * testrand_bits(5) + 16) / 31; + val = testrand_bits(1); + while (now > 0 && bits < len * 8) { + bytes[bits / 8] |= val << (bits % 8); + now--; + bits++; + } + } +} + +static void testrand256_test(unsigned char *b32) { + testrand_bytes_test(b32, 32); +} + +static void testrand_flip(unsigned char *b, size_t len) { + b[testrand_int(len)] ^= (1 << testrand_bits(3)); +} + +static void testrand_init(const char* hexseed) { + unsigned char seed16[16] = {0}; + if (hexseed && strlen(hexseed) != 0) { + int pos = 0; + while (pos < 16 && hexseed[0] != 0 && hexseed[1] != 0) { + unsigned short sh; + if ((sscanf(hexseed, "%2hx", &sh)) == 1) { + seed16[pos] = sh; + } else { + break; + } + hexseed += 2; + pos++; + } + } else { + FILE *frand = fopen("/dev/urandom", "rb"); + if ((frand == NULL) || fread(&seed16, 1, sizeof(seed16), frand) != sizeof(seed16)) { + uint64_t t = time(NULL) * (uint64_t)1337; + fprintf(stderr, "WARNING: could not read 16 bytes from /dev/urandom; falling back to insecure PRNG\n"); + seed16[0] ^= t; + seed16[1] ^= t >> 8; + seed16[2] ^= t >> 16; + seed16[3] ^= t >> 24; + seed16[4] ^= t >> 32; + seed16[5] ^= t >> 40; + seed16[6] ^= t >> 48; + seed16[7] ^= t >> 56; + } + if (frand) { + fclose(frand); + } + } + + printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); + testrand_seed(seed16); +} + +static void testrand_finish(void) { + unsigned char run32[32]; + testrand256(run32); + printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); +} + +#endif /* SECP256K1_TESTRAND_IMPL_H */ diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/tests.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/tests.c similarity index 55% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/tests.c rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/tests.c index 51423e58..5939d8c5 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/src/tests.c +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/tests.c @@ -1,23 +1,29 @@ /*********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille, Gregory Maxwell * + * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * * Distributed under the MIT software license, see the accompanying * * file COPYING or https://www.opensource.org/licenses/mit-license.php.* ***********************************************************************/ -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - #include #include #include #include +#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS + #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in tests.") + #undef USE_EXTERNAL_DEFAULT_CALLBACKS +#endif +#if defined(VERIFY) && defined(COVERAGE) + #pragma message("Defining VERIFY for tests being built for coverage analysis support is meaningless.") +#endif #include "secp256k1.c" + #include "../include/secp256k1.h" #include "../include/secp256k1_preallocated.h" #include "testrand_impl.h" +#include "checkmem.h" +#include "testutil.h" #include "util.h" #include "../contrib/lax_der_parsing.c" @@ -26,18 +32,58 @@ #include "modinv32_impl.h" #ifdef SECP256K1_WIDEMUL_INT128 #include "modinv64_impl.h" +#include "int128_impl.h" #endif -#define CONDITIONAL_TEST(cnt, nam) if (count < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else +#define CONDITIONAL_TEST(cnt, nam) if (COUNT < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else + +static int COUNT = 16; +static rustsecp256k1_v0_11_context *CTX = NULL; +static rustsecp256k1_v0_11_context *STATIC_CTX = NULL; + +static int all_bytes_equal(const void* s, unsigned char value, size_t n) { + const unsigned char *p = s; + size_t i; + + for (i = 0; i < n; i++) { + if (p[i] != value) { + return 0; + } + } + return 1; +} + +#define CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, callback, callback_setter) do { \ + int32_t _calls_to_callback = 0; \ + rustsecp256k1_v0_11_callback _saved_callback = ctx->callback; \ + callback_setter(ctx, counting_callback_fn, &_calls_to_callback); \ + { expr_or_stmt; } \ + ctx->callback = _saved_callback; \ + CHECK(_calls_to_callback == 1); \ +} while(0); -static int count = 64; -static rustsecp256k1zkp_v0_8_0_context *ctx = NULL; +/* CHECK that expr_or_stmt calls the error or illegal callback of ctx exactly once + * + * Useful for checking functions that return void (e.g., API functions that use ARG_CHECK_VOID) */ +#define CHECK_ERROR_VOID(ctx, expr_or_stmt) \ + CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, error_callback, rustsecp256k1_v0_11_context_set_error_callback) +#define CHECK_ILLEGAL_VOID(ctx, expr_or_stmt) \ + CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, illegal_callback, rustsecp256k1_v0_11_context_set_illegal_callback) + +/* CHECK that + * - expr calls the illegal callback of ctx exactly once and, + * - expr == 0 (or equivalently, expr == NULL) + * + * Useful for checking functions that return an integer or a pointer. */ +#define CHECK_ILLEGAL(ctx, expr) CHECK_ILLEGAL_VOID(ctx, CHECK((expr) == 0)) +#define CHECK_ERROR(ctx, expr) CHECK_ERROR_VOID(ctx, CHECK((expr) == 0)) -static void counting_illegal_callback_fn(const char* str, void* data) { +static void counting_callback_fn(const char* str, void* data) { /* Dummy callback function that just counts. */ int32_t *p; (void)str; p = data; + CHECK(*p != INT32_MAX); (*p)++; } @@ -46,458 +92,364 @@ static void uncounting_illegal_callback_fn(const char* str, void* data) { int32_t *p; (void)str; p = data; + CHECK(*p != INT32_MIN); (*p)--; } -void random_field_element_test(rustsecp256k1zkp_v0_8_0_fe *fe) { - do { - unsigned char b32[32]; - rustsecp256k1zkp_v0_8_0_testrand256_test(b32); - if (rustsecp256k1zkp_v0_8_0_fe_set_b32(fe, b32)) { - break; +static void run_xoshiro256pp_tests(void) { + { + size_t i; + /* Sanity check that we run before the actual seeding. */ + for (i = 0; i < sizeof(rustsecp256k1_v0_11_test_state)/sizeof(rustsecp256k1_v0_11_test_state[0]); i++) { + CHECK(rustsecp256k1_v0_11_test_state[i] == 0); } - } while(1); -} - -void random_field_element_magnitude(rustsecp256k1zkp_v0_8_0_fe *fe) { - rustsecp256k1zkp_v0_8_0_fe zero; - int n = rustsecp256k1zkp_v0_8_0_testrand_int(9); - rustsecp256k1zkp_v0_8_0_fe_normalize(fe); - if (n == 0) { - return; } - rustsecp256k1zkp_v0_8_0_fe_clear(&zero); - rustsecp256k1zkp_v0_8_0_fe_negate(&zero, &zero, 0); - rustsecp256k1zkp_v0_8_0_fe_mul_int(&zero, n - 1); - rustsecp256k1zkp_v0_8_0_fe_add(fe, &zero); -#ifdef VERIFY - CHECK(fe->magnitude == n); -#endif + { + int i; + unsigned char buf32[32]; + unsigned char seed16[16] = { + 'C', 'H', 'I', 'C', 'K', 'E', 'N', '!', + 'C', 'H', 'I', 'C', 'K', 'E', 'N', '!', + }; + unsigned char buf32_expected[32] = { + 0xAF, 0xCC, 0xA9, 0x16, 0xB5, 0x6C, 0xE3, 0xF0, + 0x44, 0x3F, 0x45, 0xE0, 0x47, 0xA5, 0x08, 0x36, + 0x4C, 0xCC, 0xC1, 0x18, 0xB2, 0xD8, 0x8F, 0xEF, + 0x43, 0x26, 0x15, 0x57, 0x37, 0x00, 0xEF, 0x30, + }; + testrand_seed(seed16); + for (i = 0; i < 17; i++) { + testrand256(buf32); + } + CHECK(rustsecp256k1_v0_11_memcmp_var(buf32, buf32_expected, sizeof(buf32)) == 0); + } } -void random_group_element_test(rustsecp256k1zkp_v0_8_0_ge *ge) { - rustsecp256k1zkp_v0_8_0_fe fe; - do { - random_field_element_test(&fe); - if (rustsecp256k1zkp_v0_8_0_ge_set_xo_var(ge, &fe, rustsecp256k1zkp_v0_8_0_testrand_bits(1))) { - rustsecp256k1zkp_v0_8_0_fe_normalize(&ge->y); - break; - } - } while(1); - ge->infinity = 0; +static void run_selftest_tests(void) { + /* Test public API */ + rustsecp256k1_v0_11_selftest(); } -void random_group_element_jacobian_test(rustsecp256k1zkp_v0_8_0_gej *gej, const rustsecp256k1zkp_v0_8_0_ge *ge) { - rustsecp256k1zkp_v0_8_0_fe z2, z3; - do { - random_field_element_test(&gej->z); - if (!rustsecp256k1zkp_v0_8_0_fe_is_zero(&gej->z)) { - break; - } - } while(1); - rustsecp256k1zkp_v0_8_0_fe_sqr(&z2, &gej->z); - rustsecp256k1zkp_v0_8_0_fe_mul(&z3, &z2, &gej->z); - rustsecp256k1zkp_v0_8_0_fe_mul(&gej->x, &ge->x, &z2); - rustsecp256k1zkp_v0_8_0_fe_mul(&gej->y, &ge->y, &z3); - gej->infinity = ge->infinity; +static int ecmult_gen_context_eq(const rustsecp256k1_v0_11_ecmult_gen_context *a, const rustsecp256k1_v0_11_ecmult_gen_context *b) { + return a->built == b->built + && rustsecp256k1_v0_11_scalar_eq(&a->scalar_offset, &b->scalar_offset) + && rustsecp256k1_v0_11_ge_eq_var(&a->ge_offset, &b->ge_offset) + && rustsecp256k1_v0_11_fe_equal(&a->proj_blind, &b->proj_blind); } -void random_gej_test(rustsecp256k1zkp_v0_8_0_gej *gej) { - rustsecp256k1zkp_v0_8_0_ge ge; - random_group_element_test(&ge); - random_group_element_jacobian_test(gej, &ge); +static int context_eq(const rustsecp256k1_v0_11_context *a, const rustsecp256k1_v0_11_context *b) { + return a->declassify == b->declassify + && ecmult_gen_context_eq(&a->ecmult_gen_ctx, &b->ecmult_gen_ctx) + && a->illegal_callback.fn == b->illegal_callback.fn + && a->illegal_callback.data == b->illegal_callback.data + && a->error_callback.fn == b->error_callback.fn + && a->error_callback.data == b->error_callback.data; } -void random_scalar_order_test(rustsecp256k1zkp_v0_8_0_scalar *num) { - do { - unsigned char b32[32]; - int overflow = 0; - rustsecp256k1zkp_v0_8_0_testrand256_test(b32); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(num, b32, &overflow); - if (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(num)) { - continue; - } - break; - } while(1); +static void run_deprecated_context_flags_test(void) { + /* Check that a context created with any of the flags in the flags array is + * identical to the NONE context. */ + unsigned int flags[] = { SECP256K1_CONTEXT_SIGN, + SECP256K1_CONTEXT_VERIFY, + SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY }; + rustsecp256k1_v0_11_context *none_ctx = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); + int i; + for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++) { + rustsecp256k1_v0_11_context *tmp_ctx; + CHECK(rustsecp256k1_v0_11_context_preallocated_size(SECP256K1_CONTEXT_NONE) == rustsecp256k1_v0_11_context_preallocated_size(flags[i])); + tmp_ctx = rustsecp256k1_v0_11_context_create(flags[i]); + CHECK(context_eq(none_ctx, tmp_ctx)); + rustsecp256k1_v0_11_context_destroy(tmp_ctx); + } + rustsecp256k1_v0_11_context_destroy(none_ctx); } -void random_scalar_order(rustsecp256k1zkp_v0_8_0_scalar *num) { - do { - unsigned char b32[32]; - int overflow = 0; - rustsecp256k1zkp_v0_8_0_testrand256(b32); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(num, b32, &overflow); - if (overflow || rustsecp256k1zkp_v0_8_0_scalar_is_zero(num)) { - continue; +static void run_ec_illegal_argument_tests(void) { + rustsecp256k1_v0_11_pubkey pubkey; + rustsecp256k1_v0_11_pubkey zero_pubkey; + rustsecp256k1_v0_11_ecdsa_signature sig; + unsigned char ctmp[32]; + + /* Setup */ + memset(ctmp, 1, 32); + memset(&zero_pubkey, 0, sizeof(zero_pubkey)); + + /* Verify context-type checking illegal-argument errors. */ + CHECK_ILLEGAL(STATIC_CTX, rustsecp256k1_v0_11_ec_pubkey_create(STATIC_CTX, &pubkey, ctmp)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(STATIC_CTX, rustsecp256k1_v0_11_ecdsa_sign(STATIC_CTX, &sig, ctmp, ctmp, NULL, NULL)); + SECP256K1_CHECKMEM_UNDEFINE(&sig, sizeof(sig)); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig, ctmp, ctmp, NULL, NULL) == 1); + SECP256K1_CHECKMEM_CHECK(&sig, sizeof(sig)); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &sig, ctmp, &pubkey) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(STATIC_CTX, &sig, ctmp, &pubkey) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_tweak_add(CTX, &pubkey, ctmp) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_tweak_add(STATIC_CTX, &pubkey, ctmp) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_tweak_mul(CTX, &pubkey, ctmp) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_negate(STATIC_CTX, &pubkey) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_negate(CTX, &pubkey) == 1); + CHECK_ILLEGAL(STATIC_CTX, rustsecp256k1_v0_11_ec_pubkey_negate(STATIC_CTX, &zero_pubkey)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_negate(CTX, NULL)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_tweak_mul(STATIC_CTX, &pubkey, ctmp) == 1); +} + +static void run_static_context_tests(int use_prealloc) { + /* Check that deprecated rustsecp256k1_v0_11_context_no_precomp is an alias to rustsecp256k1_v0_11_context_static. */ + CHECK(rustsecp256k1_v0_11_context_no_precomp == rustsecp256k1_v0_11_context_static); + + { + unsigned char seed[32] = {0x17}; + + /* Randomizing rustsecp256k1_v0_11_context_static is not supported. */ + CHECK_ILLEGAL(STATIC_CTX, rustsecp256k1_v0_11_context_randomize(STATIC_CTX, seed)); + CHECK_ILLEGAL(STATIC_CTX, rustsecp256k1_v0_11_context_randomize(STATIC_CTX, NULL)); + + /* Destroying or cloning rustsecp256k1_v0_11_context_static is not supported. */ + if (use_prealloc) { + CHECK_ILLEGAL(STATIC_CTX, rustsecp256k1_v0_11_context_preallocated_clone_size(STATIC_CTX)); + { + rustsecp256k1_v0_11_context *my_static_ctx = malloc(sizeof(*STATIC_CTX)); + CHECK(my_static_ctx != NULL); + memset(my_static_ctx, 0x2a, sizeof(*my_static_ctx)); + CHECK_ILLEGAL(STATIC_CTX, rustsecp256k1_v0_11_context_preallocated_clone(STATIC_CTX, my_static_ctx)); + CHECK(all_bytes_equal(my_static_ctx, 0x2a, sizeof(*my_static_ctx))); + free(my_static_ctx); + } + CHECK_ILLEGAL_VOID(STATIC_CTX, rustsecp256k1_v0_11_context_preallocated_destroy(STATIC_CTX)); + } else { + CHECK_ILLEGAL(STATIC_CTX, rustsecp256k1_v0_11_context_clone(STATIC_CTX)); + CHECK_ILLEGAL_VOID(STATIC_CTX, rustsecp256k1_v0_11_context_destroy(STATIC_CTX)); } - break; - } while(1); -} + } -void random_scalar_order_b32(unsigned char *b32) { - rustsecp256k1zkp_v0_8_0_scalar num; - random_scalar_order(&num); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(b32, &num); + { + /* Verify that setting and resetting illegal callback works */ + int32_t dummy = 0; + rustsecp256k1_v0_11_context_set_illegal_callback(STATIC_CTX, counting_callback_fn, &dummy); + CHECK(STATIC_CTX->illegal_callback.fn == counting_callback_fn); + CHECK(STATIC_CTX->illegal_callback.data == &dummy); + rustsecp256k1_v0_11_context_set_illegal_callback(STATIC_CTX, NULL, NULL); + CHECK(STATIC_CTX->illegal_callback.fn == rustsecp256k1_v0_11_default_illegal_callback_fn); + CHECK(STATIC_CTX->illegal_callback.data == NULL); + } } -void run_util_tests(void) { - int i; - uint64_t r; - uint64_t r2; - uint64_t r3; - int64_t s; - CHECK(rustsecp256k1zkp_v0_8_0_clz64_var(0) == 64); - CHECK(rustsecp256k1zkp_v0_8_0_clz64_var(1) == 63); - CHECK(rustsecp256k1zkp_v0_8_0_clz64_var(2) == 62); - CHECK(rustsecp256k1zkp_v0_8_0_clz64_var(3) == 62); - CHECK(rustsecp256k1zkp_v0_8_0_clz64_var(~0ULL) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_clz64_var((~0ULL) - 1) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_clz64_var((~0ULL) >> 1) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_clz64_var((~0ULL) >> 2) == 2); - CHECK(rustsecp256k1zkp_v0_8_0_sign_and_abs64(&r, INT64_MAX) == 0); - CHECK(r == INT64_MAX); - CHECK(rustsecp256k1zkp_v0_8_0_sign_and_abs64(&r, INT64_MAX - 1) == 0); - CHECK(r == INT64_MAX - 1); - CHECK(rustsecp256k1zkp_v0_8_0_sign_and_abs64(&r, INT64_MIN) == 1); - CHECK(r == (uint64_t)INT64_MAX + 1); - CHECK(rustsecp256k1zkp_v0_8_0_sign_and_abs64(&r, INT64_MIN + 1) == 1); - CHECK(r == (uint64_t)INT64_MAX); - CHECK(rustsecp256k1zkp_v0_8_0_sign_and_abs64(&r, 0) == 0); - CHECK(r == 0); - CHECK(rustsecp256k1zkp_v0_8_0_sign_and_abs64(&r, 1) == 0); - CHECK(r == 1); - CHECK(rustsecp256k1zkp_v0_8_0_sign_and_abs64(&r, -1) == 1); - CHECK(r == 1); - CHECK(rustsecp256k1zkp_v0_8_0_sign_and_abs64(&r, 2) == 0); - CHECK(r == 2); - CHECK(rustsecp256k1zkp_v0_8_0_sign_and_abs64(&r, -2) == 1); - CHECK(r == 2); - for (i = 0; i < 10; i++) { - CHECK(rustsecp256k1zkp_v0_8_0_clz64_var((~0ULL) - rustsecp256k1zkp_v0_8_0_testrand32()) == 0); - r = ((uint64_t)rustsecp256k1zkp_v0_8_0_testrand32() << 32) | rustsecp256k1zkp_v0_8_0_testrand32(); - r2 = rustsecp256k1zkp_v0_8_0_testrandi64(0, r); - CHECK(r2 <= r); - r3 = rustsecp256k1zkp_v0_8_0_testrandi64(r2, r); - CHECK((r3 >= r2) && (r3 <= r)); - r = rustsecp256k1zkp_v0_8_0_testrandi64(0, INT64_MAX); - s = (int64_t)r * (rustsecp256k1zkp_v0_8_0_testrand32()&1?-1:1); - CHECK(rustsecp256k1zkp_v0_8_0_sign_and_abs64(&r2, s) == (s < 0)); - CHECK(r2 == r); - } -} - -void run_context_tests(int use_prealloc) { - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_pubkey zero_pubkey; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig; - unsigned char ctmp[32]; - int32_t ecount; - int32_t ecount2; - rustsecp256k1zkp_v0_8_0_context *none; - rustsecp256k1zkp_v0_8_0_context *sign; - rustsecp256k1zkp_v0_8_0_context *vrfy; - rustsecp256k1zkp_v0_8_0_context *both; - rustsecp256k1zkp_v0_8_0_context *sttc; - void *none_prealloc = NULL; - void *sign_prealloc = NULL; - void *vrfy_prealloc = NULL; - void *both_prealloc = NULL; - void *sttc_prealloc = NULL; - - rustsecp256k1zkp_v0_8_0_gej pubj; - rustsecp256k1zkp_v0_8_0_ge pub; - rustsecp256k1zkp_v0_8_0_scalar msg, key, nonce; - rustsecp256k1zkp_v0_8_0_scalar sigr, sigs; +static void run_proper_context_tests(int use_prealloc) { + int32_t dummy = 0; + rustsecp256k1_v0_11_context *my_ctx, *my_ctx_fresh; + void *my_ctx_prealloc = NULL; + unsigned char seed[32] = {0x17}; + + rustsecp256k1_v0_11_gej pubj; + rustsecp256k1_v0_11_ge pub; + rustsecp256k1_v0_11_scalar msg, key, nonce; + rustsecp256k1_v0_11_scalar sigr, sigs; + + /* Fresh reference context for comparison */ + my_ctx_fresh = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); if (use_prealloc) { - none_prealloc = malloc(rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_NONE)); - sign_prealloc = malloc(rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); - vrfy_prealloc = malloc(rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); - both_prealloc = malloc(rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); - sttc_prealloc = malloc(rustsecp256k1zkp_v0_8_0_context_preallocated_clone_size(rustsecp256k1zkp_v0_8_0_context_no_precomp)); - CHECK(none_prealloc != NULL); - CHECK(sign_prealloc != NULL); - CHECK(vrfy_prealloc != NULL); - CHECK(both_prealloc != NULL); - CHECK(sttc_prealloc != NULL); - none = rustsecp256k1zkp_v0_8_0_context_preallocated_create(none_prealloc, SECP256K1_CONTEXT_NONE); - sign = rustsecp256k1zkp_v0_8_0_context_preallocated_create(sign_prealloc, SECP256K1_CONTEXT_SIGN); - vrfy = rustsecp256k1zkp_v0_8_0_context_preallocated_create(vrfy_prealloc, SECP256K1_CONTEXT_VERIFY); - both = rustsecp256k1zkp_v0_8_0_context_preallocated_create(both_prealloc, SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - sttc = rustsecp256k1zkp_v0_8_0_context_preallocated_clone(rustsecp256k1zkp_v0_8_0_context_no_precomp, sttc_prealloc); + my_ctx_prealloc = malloc(rustsecp256k1_v0_11_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + CHECK(my_ctx_prealloc != NULL); + my_ctx = rustsecp256k1_v0_11_context_preallocated_create(my_ctx_prealloc, SECP256K1_CONTEXT_NONE); } else { - none = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); - sign = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN); - vrfy = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_VERIFY); - both = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - sttc = rustsecp256k1zkp_v0_8_0_context_clone(rustsecp256k1zkp_v0_8_0_context_no_precomp); + my_ctx = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); } - memset(&zero_pubkey, 0, sizeof(zero_pubkey)); + /* Randomize and reset randomization */ + CHECK(context_eq(my_ctx, my_ctx_fresh)); + CHECK(rustsecp256k1_v0_11_context_randomize(my_ctx, seed) == 1); + CHECK(!context_eq(my_ctx, my_ctx_fresh)); + CHECK(rustsecp256k1_v0_11_context_randomize(my_ctx, NULL) == 1); + CHECK(context_eq(my_ctx, my_ctx_fresh)); - ecount = 0; - ecount2 = 10; - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2); - /* set error callback (to a function that still aborts in case malloc() fails in rustsecp256k1zkp_v0_8_0_context_clone() below) */ - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sign, rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn, NULL); - CHECK(sign->error_callback.fn != vrfy->error_callback.fn); - CHECK(sign->error_callback.fn == rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn); + /* set error callback (to a function that still aborts in case malloc() fails in rustsecp256k1_v0_11_context_clone() below) */ + rustsecp256k1_v0_11_context_set_error_callback(my_ctx, rustsecp256k1_v0_11_default_illegal_callback_fn, NULL); + CHECK(my_ctx->error_callback.fn != rustsecp256k1_v0_11_default_error_callback_fn); + CHECK(my_ctx->error_callback.fn == rustsecp256k1_v0_11_default_illegal_callback_fn); /* check if sizes for cloning are consistent */ - CHECK(rustsecp256k1zkp_v0_8_0_context_preallocated_clone_size(none) == rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_NONE)); - CHECK(rustsecp256k1zkp_v0_8_0_context_preallocated_clone_size(sign) == rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); - CHECK(rustsecp256k1zkp_v0_8_0_context_preallocated_clone_size(vrfy) == rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); - CHECK(rustsecp256k1zkp_v0_8_0_context_preallocated_clone_size(both) == rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); - CHECK(rustsecp256k1zkp_v0_8_0_context_preallocated_clone_size(sttc) >= sizeof(rustsecp256k1zkp_v0_8_0_context)); + CHECK(rustsecp256k1_v0_11_context_preallocated_clone_size(my_ctx) == rustsecp256k1_v0_11_context_preallocated_size(SECP256K1_CONTEXT_NONE)); /*** clone and destroy all of them to make sure cloning was complete ***/ { - rustsecp256k1zkp_v0_8_0_context *ctx_tmp; + rustsecp256k1_v0_11_context *ctx_tmp; if (use_prealloc) { /* clone into a non-preallocated context and then again into a new preallocated one. */ - ctx_tmp = none; none = rustsecp256k1zkp_v0_8_0_context_clone(none); rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(ctx_tmp); - free(none_prealloc); none_prealloc = malloc(rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(none_prealloc != NULL); - ctx_tmp = none; none = rustsecp256k1zkp_v0_8_0_context_preallocated_clone(none, none_prealloc); rustsecp256k1zkp_v0_8_0_context_destroy(ctx_tmp); - - ctx_tmp = sign; sign = rustsecp256k1zkp_v0_8_0_context_clone(sign); rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(ctx_tmp); - free(sign_prealloc); sign_prealloc = malloc(rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); CHECK(sign_prealloc != NULL); - ctx_tmp = sign; sign = rustsecp256k1zkp_v0_8_0_context_preallocated_clone(sign, sign_prealloc); rustsecp256k1zkp_v0_8_0_context_destroy(ctx_tmp); - - ctx_tmp = vrfy; vrfy = rustsecp256k1zkp_v0_8_0_context_clone(vrfy); rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(ctx_tmp); - free(vrfy_prealloc); vrfy_prealloc = malloc(rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); CHECK(vrfy_prealloc != NULL); - ctx_tmp = vrfy; vrfy = rustsecp256k1zkp_v0_8_0_context_preallocated_clone(vrfy, vrfy_prealloc); rustsecp256k1zkp_v0_8_0_context_destroy(ctx_tmp); - - ctx_tmp = both; both = rustsecp256k1zkp_v0_8_0_context_clone(both); rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(ctx_tmp); - free(both_prealloc); both_prealloc = malloc(rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); CHECK(both_prealloc != NULL); - ctx_tmp = both; both = rustsecp256k1zkp_v0_8_0_context_preallocated_clone(both, both_prealloc); rustsecp256k1zkp_v0_8_0_context_destroy(ctx_tmp); + ctx_tmp = my_ctx; + my_ctx = rustsecp256k1_v0_11_context_clone(my_ctx); + CHECK(context_eq(ctx_tmp, my_ctx)); + rustsecp256k1_v0_11_context_preallocated_destroy(ctx_tmp); + + free(my_ctx_prealloc); + my_ctx_prealloc = malloc(rustsecp256k1_v0_11_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + CHECK(my_ctx_prealloc != NULL); + ctx_tmp = my_ctx; + my_ctx = rustsecp256k1_v0_11_context_preallocated_clone(my_ctx, my_ctx_prealloc); + CHECK(context_eq(ctx_tmp, my_ctx)); + rustsecp256k1_v0_11_context_destroy(ctx_tmp); } else { /* clone into a preallocated context and then again into a new non-preallocated one. */ void *prealloc_tmp; - prealloc_tmp = malloc(rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(prealloc_tmp != NULL); - ctx_tmp = none; none = rustsecp256k1zkp_v0_8_0_context_preallocated_clone(none, prealloc_tmp); rustsecp256k1zkp_v0_8_0_context_destroy(ctx_tmp); - ctx_tmp = none; none = rustsecp256k1zkp_v0_8_0_context_clone(none); rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(ctx_tmp); - free(prealloc_tmp); - - prealloc_tmp = malloc(rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); CHECK(prealloc_tmp != NULL); - ctx_tmp = sign; sign = rustsecp256k1zkp_v0_8_0_context_preallocated_clone(sign, prealloc_tmp); rustsecp256k1zkp_v0_8_0_context_destroy(ctx_tmp); - ctx_tmp = sign; sign = rustsecp256k1zkp_v0_8_0_context_clone(sign); rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(ctx_tmp); - free(prealloc_tmp); - - prealloc_tmp = malloc(rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); CHECK(prealloc_tmp != NULL); - ctx_tmp = vrfy; vrfy = rustsecp256k1zkp_v0_8_0_context_preallocated_clone(vrfy, prealloc_tmp); rustsecp256k1zkp_v0_8_0_context_destroy(ctx_tmp); - ctx_tmp = vrfy; vrfy = rustsecp256k1zkp_v0_8_0_context_clone(vrfy); rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(ctx_tmp); - free(prealloc_tmp); - - prealloc_tmp = malloc(rustsecp256k1zkp_v0_8_0_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); CHECK(prealloc_tmp != NULL); - ctx_tmp = both; both = rustsecp256k1zkp_v0_8_0_context_preallocated_clone(both, prealloc_tmp); rustsecp256k1zkp_v0_8_0_context_destroy(ctx_tmp); - ctx_tmp = both; both = rustsecp256k1zkp_v0_8_0_context_clone(both); rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(ctx_tmp); + prealloc_tmp = malloc(rustsecp256k1_v0_11_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + CHECK(prealloc_tmp != NULL); + ctx_tmp = my_ctx; + my_ctx = rustsecp256k1_v0_11_context_preallocated_clone(my_ctx, prealloc_tmp); + CHECK(context_eq(ctx_tmp, my_ctx)); + rustsecp256k1_v0_11_context_destroy(ctx_tmp); + + ctx_tmp = my_ctx; + my_ctx = rustsecp256k1_v0_11_context_clone(my_ctx); + CHECK(context_eq(ctx_tmp, my_ctx)); + rustsecp256k1_v0_11_context_preallocated_destroy(ctx_tmp); free(prealloc_tmp); } } /* Verify that the error callback makes it across the clone. */ - CHECK(sign->error_callback.fn != vrfy->error_callback.fn); - CHECK(sign->error_callback.fn == rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn); + CHECK(my_ctx->error_callback.fn != rustsecp256k1_v0_11_default_error_callback_fn); + CHECK(my_ctx->error_callback.fn == rustsecp256k1_v0_11_default_illegal_callback_fn); /* And that it resets back to default. */ - rustsecp256k1zkp_v0_8_0_context_set_error_callback(sign, NULL, NULL); - CHECK(vrfy->error_callback.fn == sign->error_callback.fn); + rustsecp256k1_v0_11_context_set_error_callback(my_ctx, NULL, NULL); + CHECK(my_ctx->error_callback.fn == rustsecp256k1_v0_11_default_error_callback_fn); + CHECK(context_eq(my_ctx, my_ctx_fresh)); + + /* Verify that setting and resetting illegal callback works */ + rustsecp256k1_v0_11_context_set_illegal_callback(my_ctx, counting_callback_fn, &dummy); + CHECK(my_ctx->illegal_callback.fn == counting_callback_fn); + CHECK(my_ctx->illegal_callback.data == &dummy); + rustsecp256k1_v0_11_context_set_illegal_callback(my_ctx, NULL, NULL); + CHECK(my_ctx->illegal_callback.fn == rustsecp256k1_v0_11_default_illegal_callback_fn); + CHECK(my_ctx->illegal_callback.data == NULL); + CHECK(context_eq(my_ctx, my_ctx_fresh)); /*** attempt to use them ***/ - random_scalar_order_test(&msg); - random_scalar_order_test(&key); - rustsecp256k1zkp_v0_8_0_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&pub, &pubj); - - /* Verify context-type checking illegal-argument errors. */ - memset(ctmp, 1, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(sttc, &pubkey, ctmp) == 0); - CHECK(ecount == 1); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(sign, &pubkey, ctmp) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(sttc, &sig, ctmp, ctmp, NULL, NULL) == 0); - CHECK(ecount == 2); - VG_UNDEF(&sig, sizeof(sig)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1); - VG_CHECK(&sig, sizeof(sig)); - CHECK(ecount2 == 10); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 1); - CHECK(ecount2 == 10); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(sttc, &sig, ctmp, &pubkey) == 1); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 1); - CHECK(ecount2 == 10); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(sttc, &pubkey, ctmp) == 1); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 1); - CHECK(ecount2 == 10); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_negate(sttc, &pubkey) == 1); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_negate(sign, &pubkey) == 1); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_negate(sign, NULL) == 0); - CHECK(ecount2 == 11); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_negate(sttc, &zero_pubkey) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_mul(sttc, &pubkey, ctmp) == 1); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_context_randomize(sttc, ctmp) == 1); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_context_randomize(sttc, NULL) == 1); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_context_randomize(sign, ctmp) == 1); - CHECK(ecount2 == 11); - CHECK(rustsecp256k1zkp_v0_8_0_context_randomize(sign, NULL) == 1); - CHECK(ecount2 == 11); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sttc, NULL, NULL); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(sign, NULL, NULL); + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); + rustsecp256k1_v0_11_ecmult_gen(&my_ctx->ecmult_gen_ctx, &pubj, &key); + rustsecp256k1_v0_11_ge_set_gej(&pub, &pubj); /* obtain a working nonce */ do { - random_scalar_order_test(&nonce); - } while(!rustsecp256k1zkp_v0_8_0_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + testutil_random_scalar_order_test(&nonce); + } while(!rustsecp256k1_v0_11_ecdsa_sig_sign(&my_ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); /* try signing */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_sign(&my_ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); /* try verifying */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); /* cleanup */ if (use_prealloc) { - rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(none); - rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(vrfy); - rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(both); - rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(sttc); - free(none_prealloc); - free(sign_prealloc); - free(vrfy_prealloc); - free(both_prealloc); - free(sttc_prealloc); + rustsecp256k1_v0_11_context_preallocated_destroy(my_ctx); + free(my_ctx_prealloc); } else { - rustsecp256k1zkp_v0_8_0_context_destroy(none); - rustsecp256k1zkp_v0_8_0_context_destroy(sign); - rustsecp256k1zkp_v0_8_0_context_destroy(vrfy); - rustsecp256k1zkp_v0_8_0_context_destroy(both); - rustsecp256k1zkp_v0_8_0_context_destroy(sttc); + rustsecp256k1_v0_11_context_destroy(my_ctx); } - /* Defined as no-op. */ - rustsecp256k1zkp_v0_8_0_context_destroy(NULL); - rustsecp256k1zkp_v0_8_0_context_preallocated_destroy(NULL); + rustsecp256k1_v0_11_context_destroy(my_ctx_fresh); + /* Defined as no-op. */ + rustsecp256k1_v0_11_context_destroy(NULL); + rustsecp256k1_v0_11_context_preallocated_destroy(NULL); } -void run_scratch_tests(void) { +static void run_scratch_tests(void) { const size_t adj_alloc = ((500 + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; - int32_t ecount = 0; size_t checkpoint; size_t checkpoint_2; - rustsecp256k1zkp_v0_8_0_context *none = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); - rustsecp256k1zkp_v0_8_0_scratch_space *scratch; - rustsecp256k1zkp_v0_8_0_scratch_space local_scratch; + rustsecp256k1_v0_11_scratch_space *scratch; + rustsecp256k1_v0_11_scratch_space local_scratch; /* Test public API */ - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - rustsecp256k1zkp_v0_8_0_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - - scratch = rustsecp256k1zkp_v0_8_0_scratch_space_create(none, 1000); + scratch = rustsecp256k1_v0_11_scratch_space_create(CTX, 1000); CHECK(scratch != NULL); - CHECK(ecount == 0); /* Test internal API */ - CHECK(rustsecp256k1zkp_v0_8_0_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000); - CHECK(rustsecp256k1zkp_v0_8_0_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - (ALIGNMENT - 1)); + CHECK(rustsecp256k1_v0_11_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000); + CHECK(rustsecp256k1_v0_11_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - (ALIGNMENT - 1)); CHECK(scratch->alloc_size == 0); CHECK(scratch->alloc_size % ALIGNMENT == 0); /* Allocating 500 bytes succeeds */ - checkpoint = rustsecp256k1zkp_v0_8_0_scratch_checkpoint(&none->error_callback, scratch); - CHECK(rustsecp256k1zkp_v0_8_0_scratch_alloc(&none->error_callback, scratch, 500) != NULL); - CHECK(rustsecp256k1zkp_v0_8_0_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc); - CHECK(rustsecp256k1zkp_v0_8_0_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); + checkpoint = rustsecp256k1_v0_11_scratch_checkpoint(&CTX->error_callback, scratch); + CHECK(rustsecp256k1_v0_11_scratch_alloc(&CTX->error_callback, scratch, 500) != NULL); + CHECK(rustsecp256k1_v0_11_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000 - adj_alloc); + CHECK(rustsecp256k1_v0_11_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); CHECK(scratch->alloc_size != 0); CHECK(scratch->alloc_size % ALIGNMENT == 0); /* Allocating another 501 bytes fails */ - CHECK(rustsecp256k1zkp_v0_8_0_scratch_alloc(&none->error_callback, scratch, 501) == NULL); - CHECK(rustsecp256k1zkp_v0_8_0_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc); - CHECK(rustsecp256k1zkp_v0_8_0_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); + CHECK(rustsecp256k1_v0_11_scratch_alloc(&CTX->error_callback, scratch, 501) == NULL); + CHECK(rustsecp256k1_v0_11_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000 - adj_alloc); + CHECK(rustsecp256k1_v0_11_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); CHECK(scratch->alloc_size != 0); CHECK(scratch->alloc_size % ALIGNMENT == 0); /* ...but it succeeds once we apply the checkpoint to undo it */ - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint); + rustsecp256k1_v0_11_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint); CHECK(scratch->alloc_size == 0); - CHECK(rustsecp256k1zkp_v0_8_0_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000); - CHECK(rustsecp256k1zkp_v0_8_0_scratch_alloc(&none->error_callback, scratch, 500) != NULL); + CHECK(rustsecp256k1_v0_11_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000); + CHECK(rustsecp256k1_v0_11_scratch_alloc(&CTX->error_callback, scratch, 500) != NULL); CHECK(scratch->alloc_size != 0); /* try to apply a bad checkpoint */ - checkpoint_2 = rustsecp256k1zkp_v0_8_0_scratch_checkpoint(&none->error_callback, scratch); - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint); - CHECK(ecount == 0); - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint_2); /* checkpoint_2 is after checkpoint */ - CHECK(ecount == 1); - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(&none->error_callback, scratch, (size_t) -1); /* this is just wildly invalid */ - CHECK(ecount == 2); + checkpoint_2 = rustsecp256k1_v0_11_scratch_checkpoint(&CTX->error_callback, scratch); + rustsecp256k1_v0_11_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint); + CHECK_ERROR_VOID(CTX, rustsecp256k1_v0_11_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint_2)); /* checkpoint_2 is after checkpoint */ + CHECK_ERROR_VOID(CTX, rustsecp256k1_v0_11_scratch_apply_checkpoint(&CTX->error_callback, scratch, (size_t) -1)); /* this is just wildly invalid */ /* try to use badly initialized scratch space */ - rustsecp256k1zkp_v0_8_0_scratch_space_destroy(none, scratch); + rustsecp256k1_v0_11_scratch_space_destroy(CTX, scratch); memset(&local_scratch, 0, sizeof(local_scratch)); scratch = &local_scratch; - CHECK(!rustsecp256k1zkp_v0_8_0_scratch_max_allocation(&none->error_callback, scratch, 0)); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_scratch_alloc(&none->error_callback, scratch, 500) == NULL); - CHECK(ecount == 4); - rustsecp256k1zkp_v0_8_0_scratch_space_destroy(none, scratch); - CHECK(ecount == 5); + CHECK_ERROR(CTX, rustsecp256k1_v0_11_scratch_max_allocation(&CTX->error_callback, scratch, 0)); + CHECK_ERROR(CTX, rustsecp256k1_v0_11_scratch_alloc(&CTX->error_callback, scratch, 500)); + CHECK_ERROR_VOID(CTX, rustsecp256k1_v0_11_scratch_space_destroy(CTX, scratch)); /* Test that large integers do not wrap around in a bad way */ - scratch = rustsecp256k1zkp_v0_8_0_scratch_space_create(none, 1000); + scratch = rustsecp256k1_v0_11_scratch_space_create(CTX, 1000); /* Try max allocation with a large number of objects. Only makes sense if * ALIGNMENT is greater than 1 because otherwise the objects take no extra * space. */ - CHECK(ALIGNMENT <= 1 || !rustsecp256k1zkp_v0_8_0_scratch_max_allocation(&none->error_callback, scratch, (SIZE_MAX / (ALIGNMENT - 1)) + 1)); + CHECK(ALIGNMENT <= 1 || !rustsecp256k1_v0_11_scratch_max_allocation(&CTX->error_callback, scratch, (SIZE_MAX / (ALIGNMENT - 1)) + 1)); /* Try allocating SIZE_MAX to test wrap around which only happens if * ALIGNMENT > 1, otherwise it returns NULL anyway because the scratch * space is too small. */ - CHECK(rustsecp256k1zkp_v0_8_0_scratch_alloc(&none->error_callback, scratch, SIZE_MAX) == NULL); - rustsecp256k1zkp_v0_8_0_scratch_space_destroy(none, scratch); + CHECK(rustsecp256k1_v0_11_scratch_alloc(&CTX->error_callback, scratch, SIZE_MAX) == NULL); + rustsecp256k1_v0_11_scratch_space_destroy(CTX, scratch); /* cleanup */ - rustsecp256k1zkp_v0_8_0_scratch_space_destroy(none, NULL); /* no-op */ - rustsecp256k1zkp_v0_8_0_context_destroy(none); + rustsecp256k1_v0_11_scratch_space_destroy(CTX, NULL); /* no-op */ } -void run_ctz_tests(void) { +static void run_ctz_tests(void) { static const uint32_t b32[] = {1, 0xffffffff, 0x5e56968f, 0xe0d63129}; static const uint64_t b64[] = {1, 0xffffffffffffffff, 0xbcd02462139b3fc3, 0x98b5f80c769693ef}; int shift; unsigned i; for (i = 0; i < sizeof(b32) / sizeof(b32[0]); ++i) { for (shift = 0; shift < 32; ++shift) { - CHECK(rustsecp256k1zkp_v0_8_0_ctz32_var_debruijn(b32[i] << shift) == shift); - CHECK(rustsecp256k1zkp_v0_8_0_ctz32_var(b32[i] << shift) == shift); + CHECK(rustsecp256k1_v0_11_ctz32_var_debruijn(b32[i] << shift) == shift); + CHECK(rustsecp256k1_v0_11_ctz32_var(b32[i] << shift) == shift); } } for (i = 0; i < sizeof(b64) / sizeof(b64[0]); ++i) { for (shift = 0; shift < 64; ++shift) { - CHECK(rustsecp256k1zkp_v0_8_0_ctz64_var_debruijn(b64[i] << shift) == shift); - CHECK(rustsecp256k1zkp_v0_8_0_ctz64_var(b64[i] << shift) == shift); + CHECK(rustsecp256k1_v0_11_ctz64_var_debruijn(b64[i] << shift) == shift); + CHECK(rustsecp256k1_v0_11_ctz64_var(b64[i] << shift) == shift); } } } /***** HASH TESTS *****/ -void run_sha256_known_output_tests(void) { +static void run_sha256_known_output_tests(void) { static const char *inputs[] = { "", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", @@ -527,29 +479,29 @@ void run_sha256_known_output_tests(void) { for (i = 0; i < ninputs; i++) { unsigned char out[32]; - rustsecp256k1zkp_v0_8_0_sha256 hasher; + rustsecp256k1_v0_11_sha256 hasher; unsigned int j; /* 1. Run: simply write the input bytestrings */ j = repeat[i]; - rustsecp256k1zkp_v0_8_0_sha256_initialize(&hasher); + rustsecp256k1_v0_11_sha256_initialize(&hasher); while (j > 0) { - rustsecp256k1zkp_v0_8_0_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + rustsecp256k1_v0_11_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); j--; } - rustsecp256k1zkp_v0_8_0_sha256_finalize(&hasher, out); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(out, outputs[i], 32) == 0); + rustsecp256k1_v0_11_sha256_finalize(&hasher, out); + CHECK(rustsecp256k1_v0_11_memcmp_var(out, outputs[i], 32) == 0); /* 2. Run: split the input bytestrings randomly before writing */ if (strlen(inputs[i]) > 0) { - int split = rustsecp256k1zkp_v0_8_0_testrand_int(strlen(inputs[i])); - rustsecp256k1zkp_v0_8_0_sha256_initialize(&hasher); + int split = testrand_int(strlen(inputs[i])); + rustsecp256k1_v0_11_sha256_initialize(&hasher); j = repeat[i]; while (j > 0) { - rustsecp256k1zkp_v0_8_0_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); - rustsecp256k1zkp_v0_8_0_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + rustsecp256k1_v0_11_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + rustsecp256k1_v0_11_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); j--; } - rustsecp256k1zkp_v0_8_0_sha256_finalize(&hasher, out); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(out, outputs[i], 32) == 0); + rustsecp256k1_v0_11_sha256_finalize(&hasher, out); + CHECK(rustsecp256k1_v0_11_memcmp_var(out, outputs[i], 32) == 0); } } } @@ -598,9 +550,9 @@ for x in digests: print(x + ',') ``` */ -void run_sha256_counter_tests(void) { +static void run_sha256_counter_tests(void) { static const char *input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"; - static const rustsecp256k1zkp_v0_8_0_sha256 midstates[] = { + static const rustsecp256k1_v0_11_sha256 midstates[] = { {{0xa2b5c8bb, 0x26c88bb3, 0x2abdc3d2, 0x9def99a3, 0xdfd21a6e, 0x41fe585b, 0x7ef2c440, 0x2b79adda}, {0x00}, 0xfffc0}, {{0xa0d29445, 0x9287de66, 0x76aabd71, 0x41acd765, 0x0c7528b4, 0x84e14906, 0x942faec6, 0xcc5a7b26}, @@ -649,14 +601,25 @@ void run_sha256_counter_tests(void) { unsigned int i; for (i = 0; i < sizeof(midstates)/sizeof(midstates[0]); i++) { unsigned char out[32]; - rustsecp256k1zkp_v0_8_0_sha256 hasher = midstates[i]; - rustsecp256k1zkp_v0_8_0_sha256_write(&hasher, (const unsigned char*)input, strlen(input)); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&hasher, out); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(out, outputs[i], 32) == 0); + rustsecp256k1_v0_11_sha256 hasher = midstates[i]; + rustsecp256k1_v0_11_sha256_write(&hasher, (const unsigned char*)input, strlen(input)); + rustsecp256k1_v0_11_sha256_finalize(&hasher, out); + CHECK(rustsecp256k1_v0_11_memcmp_var(out, outputs[i], 32) == 0); } } -void run_hmac_sha256_tests(void) { +/* Tests for the equality of two sha256 structs. This function only produces a + * correct result if an integer multiple of 64 many bytes have been written + * into the hash functions. This function is used by some module tests. */ +static void test_sha256_eq(const rustsecp256k1_v0_11_sha256 *sha1, const rustsecp256k1_v0_11_sha256 *sha2) { + /* Is buffer fully consumed? */ + CHECK((sha1->bytes & 0x3F) == 0); + + CHECK(sha1->bytes == sha2->bytes); + CHECK(rustsecp256k1_v0_11_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0); +} + +static void run_hmac_sha256_tests(void) { static const char *keys[6] = { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", "\x4a\x65\x66\x65", @@ -683,24 +646,24 @@ void run_hmac_sha256_tests(void) { }; int i; for (i = 0; i < 6; i++) { - rustsecp256k1zkp_v0_8_0_hmac_sha256 hasher; + rustsecp256k1_v0_11_hmac_sha256 hasher; unsigned char out[32]; - rustsecp256k1zkp_v0_8_0_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); - rustsecp256k1zkp_v0_8_0_hmac_sha256_finalize(&hasher, out); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(out, outputs[i], 32) == 0); + rustsecp256k1_v0_11_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + rustsecp256k1_v0_11_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + rustsecp256k1_v0_11_hmac_sha256_finalize(&hasher, out); + CHECK(rustsecp256k1_v0_11_memcmp_var(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { - int split = rustsecp256k1zkp_v0_8_0_testrand_int(strlen(inputs[i])); - rustsecp256k1zkp_v0_8_0_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); - rustsecp256k1zkp_v0_8_0_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); - rustsecp256k1zkp_v0_8_0_hmac_sha256_finalize(&hasher, out); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(out, outputs[i], 32) == 0); + int split = testrand_int(strlen(inputs[i])); + rustsecp256k1_v0_11_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + rustsecp256k1_v0_11_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + rustsecp256k1_v0_11_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + rustsecp256k1_v0_11_hmac_sha256_finalize(&hasher, out); + CHECK(rustsecp256k1_v0_11_memcmp_var(out, outputs[i], 32) == 0); } } } -void run_rfc6979_hmac_sha256_tests(void) { +static void run_rfc6979_hmac_sha256_tests(void) { static const unsigned char key1[65] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a, 0}; static const unsigned char out1[3][32] = { {0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb}, @@ -715,35 +678,33 @@ void run_rfc6979_hmac_sha256_tests(void) { {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94} }; - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256 rng; + rustsecp256k1_v0_11_rfc6979_hmac_sha256 rng; unsigned char out[32]; int i; - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_initialize(&rng, key1, 64); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_initialize(&rng, key1, 64); for (i = 0; i < 3; i++) { - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(out, out1[i], 32) == 0); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(rustsecp256k1_v0_11_memcmp_var(out, out1[i], 32) == 0); } - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_finalize(&rng); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_finalize(&rng); - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_initialize(&rng, key1, 65); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_initialize(&rng, key1, 65); for (i = 0; i < 3; i++) { - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(out, out1[i], 32) != 0); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(rustsecp256k1_v0_11_memcmp_var(out, out1[i], 32) != 0); } - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_finalize(&rng); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_finalize(&rng); - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_initialize(&rng, key2, 64); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_initialize(&rng, key2, 64); for (i = 0; i < 3; i++) { - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(out, out2[i], 32) == 0); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(rustsecp256k1_v0_11_memcmp_var(out, out2[i], 32) == 0); } - rustsecp256k1zkp_v0_8_0_rfc6979_hmac_sha256_finalize(&rng); + rustsecp256k1_v0_11_rfc6979_hmac_sha256_finalize(&rng); } -void run_tagged_sha256_tests(void) { - int ecount = 0; - rustsecp256k1zkp_v0_8_0_context *none = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_NONE); +static void run_tagged_sha256_tests(void) { unsigned char tag[32] = { 0 }; unsigned char msg[32] = { 0 }; unsigned char hash32[32]; @@ -754,101 +715,23 @@ void run_tagged_sha256_tests(void) { 0xE2, 0x76, 0x55, 0x9A, 0x3B, 0xDE, 0x55, 0xB3 }; - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - /* API test */ - CHECK(rustsecp256k1zkp_v0_8_0_tagged_sha256(none, hash32, tag, sizeof(tag), msg, sizeof(msg)) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_tagged_sha256(none, NULL, tag, sizeof(tag), msg, sizeof(msg)) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_tagged_sha256(none, hash32, NULL, 0, msg, sizeof(msg)) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_tagged_sha256(none, hash32, tag, sizeof(tag), NULL, 0) == 0); - CHECK(ecount == 3); + CHECK(rustsecp256k1_v0_11_tagged_sha256(CTX, hash32, tag, sizeof(tag), msg, sizeof(msg)) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_tagged_sha256(CTX, NULL, tag, sizeof(tag), msg, sizeof(msg))); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_tagged_sha256(CTX, hash32, NULL, 0, msg, sizeof(msg))); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_tagged_sha256(CTX, hash32, tag, sizeof(tag), NULL, 0)); /* Static test vector */ memcpy(tag, "tag", 3); memcpy(msg, "msg", 3); - CHECK(rustsecp256k1zkp_v0_8_0_tagged_sha256(none, hash32, tag, 3, msg, 3) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(hash32, hash_expected, sizeof(hash32)) == 0); - rustsecp256k1zkp_v0_8_0_context_destroy(none); -} - -/***** RANDOM TESTS *****/ - -void test_rand_bits(int rand32, int bits) { - /* (1-1/2^B)^rounds[B] < 1/10^9, so rounds is the number of iterations to - * get a false negative chance below once in a billion */ - static const unsigned int rounds[7] = {1, 30, 73, 156, 322, 653, 1316}; - /* We try multiplying the results with various odd numbers, which shouldn't - * influence the uniform distribution modulo a power of 2. */ - static const uint32_t mults[6] = {1, 3, 21, 289, 0x9999, 0x80402011}; - /* We only select up to 6 bits from the output to analyse */ - unsigned int usebits = bits > 6 ? 6 : bits; - unsigned int maxshift = bits - usebits; - /* For each of the maxshift+1 usebits-bit sequences inside a bits-bit - number, track all observed outcomes, one per bit in a uint64_t. */ - uint64_t x[6][27] = {{0}}; - unsigned int i, shift, m; - /* Multiply the output of all rand calls with the odd number m, which - should not change the uniformity of its distribution. */ - for (i = 0; i < rounds[usebits]; i++) { - uint32_t r = (rand32 ? rustsecp256k1zkp_v0_8_0_testrand32() : rustsecp256k1zkp_v0_8_0_testrand_bits(bits)); - CHECK((((uint64_t)r) >> bits) == 0); - for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { - uint32_t rm = r * mults[m]; - for (shift = 0; shift <= maxshift; shift++) { - x[m][shift] |= (((uint64_t)1) << ((rm >> shift) & ((1 << usebits) - 1))); - } - } - } - for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { - for (shift = 0; shift <= maxshift; shift++) { - /* Test that the lower usebits bits of x[shift] are 1 */ - CHECK(((~x[m][shift]) << (64 - (1 << usebits))) == 0); - } - } -} - -/* Subrange must be a whole divisor of range, and at most 64 */ -void test_rand_int(uint32_t range, uint32_t subrange) { - /* (1-1/subrange)^rounds < 1/10^9 */ - int rounds = (subrange * 2073) / 100; - int i; - uint64_t x = 0; - CHECK((range % subrange) == 0); - for (i = 0; i < rounds; i++) { - uint32_t r = rustsecp256k1zkp_v0_8_0_testrand_int(range); - CHECK(r < range); - r = r % subrange; - x |= (((uint64_t)1) << r); - } - /* Test that the lower subrange bits of x are 1. */ - CHECK(((~x) << (64 - subrange)) == 0); -} - -void run_rand_bits(void) { - size_t b; - test_rand_bits(1, 32); - for (b = 1; b <= 32; b++) { - test_rand_bits(0, b); - } -} - -void run_rand_int(void) { - static const uint32_t ms[] = {1, 3, 17, 1000, 13771, 999999, 33554432}; - static const uint32_t ss[] = {1, 3, 6, 9, 13, 31, 64}; - unsigned int m, s; - for (m = 0; m < sizeof(ms) / sizeof(ms[0]); m++) { - for (s = 0; s < sizeof(ss) / sizeof(ss[0]); s++) { - test_rand_int(ms[m] * ss[s], ss[s]); - } - } + CHECK(rustsecp256k1_v0_11_tagged_sha256(CTX, hash32, tag, 3, msg, 3) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(hash32, hash_expected, sizeof(hash32)) == 0); } /***** MODINV TESTS *****/ /* Compute the modular inverse of (odd) x mod 2^64. */ -uint64_t modinv2p64(uint64_t x) { +static uint64_t modinv2p64(uint64_t x) { /* If w = 1/x mod 2^(2^L), then w*(2 - w*x) = 1/x mod 2^(2^(L+1)). See * Hacker's Delight second edition, Henry S. Warren, Jr., pages 245-247 for * why. Start with L=0, for which it is true for every odd x that @@ -860,11 +743,12 @@ uint64_t modinv2p64(uint64_t x) { return w; } -/* compute out = (a*b) mod m; if b=NULL, treat b=1. + +/* compute out = (a*b) mod m; if b=NULL, treat b=1; if m=NULL, treat m=infinity. * * Out is a 512-bit number (represented as 32 uint16_t's in LE order). The other * arguments are 256-bit numbers (represented as 16 uint16_t's in LE order). */ -void mulmod256(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint16_t* m) { +static void mulmod256(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint16_t* m) { uint16_t mul[32]; uint64_t c = 0; int i, j; @@ -902,51 +786,53 @@ void mulmod256(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint16 } } - /* Compute the highest set bit in m. */ - for (i = 255; i >= 0; --i) { - if ((m[i >> 4] >> (i & 15)) & 1) { - m_bitlen = i; - break; + if (m) { + /* Compute the highest set bit in m. */ + for (i = 255; i >= 0; --i) { + if ((m[i >> 4] >> (i & 15)) & 1) { + m_bitlen = i; + break; + } } - } - /* Try do mul -= m<= 0; --i) { - uint16_t mul2[32]; - int64_t cs; - - /* Compute mul2 = mul - m<= 0 && bitpos < 256) { - sub |= ((m[bitpos >> 4] >> (bitpos & 15)) & 1) << p; + /* Try do mul -= m<= 0; --i) { + uint16_t mul2[32]; + int64_t cs; + + /* Compute mul2 = mul - m<= 0 && bitpos < 256) { + sub |= ((m[bitpos >> 4] >> (bitpos & 15)) & 1) << p; + } } + /* Add mul[j]-sub to accumulator, and shift bottom 16 bits out to mul2[j]. */ + cs += mul[j]; + cs -= sub; + mul2[j] = (cs & 0xFFFF); + cs >>= 16; + } + /* If remainder of subtraction is 0, set mul = mul2. */ + if (cs == 0) { + memcpy(mul, mul2, sizeof(mul)); } - /* Add mul[j]-sub to accumulator, and shift bottom 16 bits out to mul2[j]. */ - cs += mul[j]; - cs -= sub; - mul2[j] = (cs & 0xFFFF); - cs >>= 16; } - /* If remainder of subtraction is 0, set mul = mul2. */ - if (cs == 0) { - memcpy(mul, mul2, sizeof(mul)); + /* Sanity check: test that all limbs higher than m's highest are zero */ + for (i = (m_bitlen >> 4) + 1; i < 32; ++i) { + CHECK(mul[i] == 0); } } - /* Sanity check: test that all limbs higher than m's highest are zero */ - for (i = (m_bitlen >> 4) + 1; i < 32; ++i) { - CHECK(mul[i] == 0); - } memcpy(out, mul, 32); } /* Convert a 256-bit number represented as 16 uint16_t's to signed30 notation. */ -void uint16_to_signed30(rustsecp256k1zkp_v0_8_0_modinv32_signed30* out, const uint16_t* in) { +static void uint16_to_signed30(rustsecp256k1_v0_11_modinv32_signed30* out, const uint16_t* in) { int i; memset(out->v, 0, sizeof(out->v)); for (i = 0; i < 256; ++i) { @@ -955,7 +841,7 @@ void uint16_to_signed30(rustsecp256k1zkp_v0_8_0_modinv32_signed30* out, const ui } /* Convert a 256-bit number in signed30 notation to a representation as 16 uint16_t's. */ -void signed30_to_uint16(uint16_t* out, const rustsecp256k1zkp_v0_8_0_modinv32_signed30* in) { +static void signed30_to_uint16(uint16_t* out, const rustsecp256k1_v0_11_modinv32_signed30* in) { int i; memset(out, 0, 32); for (i = 0; i < 256; ++i) { @@ -964,10 +850,10 @@ void signed30_to_uint16(uint16_t* out, const rustsecp256k1zkp_v0_8_0_modinv32_si } /* Randomly mutate the sign of limbs in signed30 representation, without changing the value. */ -void mutate_sign_signed30(rustsecp256k1zkp_v0_8_0_modinv32_signed30* x) { +static void mutate_sign_signed30(rustsecp256k1_v0_11_modinv32_signed30* x) { int i; for (i = 0; i < 16; ++i) { - int pos = rustsecp256k1zkp_v0_8_0_testrand_bits(3); + int pos = testrand_bits(3); if (x->v[pos] > 0 && x->v[pos + 1] <= 0x3fffffff) { x->v[pos] -= 0x40000000; x->v[pos + 1] += 1; @@ -978,25 +864,45 @@ void mutate_sign_signed30(rustsecp256k1zkp_v0_8_0_modinv32_signed30* x) { } } -/* Test rustsecp256k1zkp_v0_8_0_modinv32{_var}, using inputs in 16-bit limb format, and returning inverse. */ -void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) { +/* Test rustsecp256k1_v0_11_modinv32{_var}, using inputs in 16-bit limb format, and returning inverse. */ +static void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) { uint16_t tmp[16]; - rustsecp256k1zkp_v0_8_0_modinv32_signed30 x; - rustsecp256k1zkp_v0_8_0_modinv32_modinfo m; + rustsecp256k1_v0_11_modinv32_signed30 x; + rustsecp256k1_v0_11_modinv32_modinfo m; int i, vartime, nonzero; uint16_to_signed30(&x, in); nonzero = (x.v[0] | x.v[1] | x.v[2] | x.v[3] | x.v[4] | x.v[5] | x.v[6] | x.v[7] | x.v[8]) != 0; uint16_to_signed30(&m.modulus, mod); - mutate_sign_signed30(&m.modulus); /* compute 1/modulus mod 2^30 */ m.modulus_inv30 = modinv2p64(m.modulus.v[0]) & 0x3fffffff; CHECK(((m.modulus_inv30 * m.modulus.v[0]) & 0x3fffffff) == 1); + /* Test rustsecp256k1_v0_11_jacobi32_maybe_var. */ + if (nonzero) { + int jac; + uint16_t sqr[16], negone[16]; + mulmod256(sqr, in, in, mod); + uint16_to_signed30(&x, sqr); + /* Compute jacobi symbol of in^2, which must be 1 (or uncomputable). */ + jac = rustsecp256k1_v0_11_jacobi32_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1); + /* Then compute the jacobi symbol of -(in^2). x and -x have opposite + * jacobi symbols if and only if (mod % 4) == 3. */ + negone[0] = mod[0] - 1; + for (i = 1; i < 16; ++i) negone[i] = mod[i]; + mulmod256(sqr, sqr, negone, mod); + uint16_to_signed30(&x, sqr); + jac = rustsecp256k1_v0_11_jacobi32_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1 - (mod[0] & 2)); + } + + uint16_to_signed30(&x, in); + mutate_sign_signed30(&m.modulus); for (vartime = 0; vartime < 2; ++vartime) { /* compute inverse */ - (vartime ? rustsecp256k1zkp_v0_8_0_modinv32_var : rustsecp256k1zkp_v0_8_0_modinv32)(&x, &m); + (vartime ? rustsecp256k1_v0_11_modinv32_var : rustsecp256k1_v0_11_modinv32)(&x, &m); /* produce output */ signed30_to_uint16(out, &x); @@ -1007,7 +913,7 @@ void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod for (i = 1; i < 16; ++i) CHECK(tmp[i] == 0); /* invert again */ - (vartime ? rustsecp256k1zkp_v0_8_0_modinv32_var : rustsecp256k1zkp_v0_8_0_modinv32)(&x, &m); + (vartime ? rustsecp256k1_v0_11_modinv32_var : rustsecp256k1_v0_11_modinv32)(&x, &m); /* check if the result is equal to the input */ signed30_to_uint16(tmp, &x); @@ -1017,7 +923,7 @@ void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod #ifdef SECP256K1_WIDEMUL_INT128 /* Convert a 256-bit number represented as 16 uint16_t's to signed62 notation. */ -void uint16_to_signed62(rustsecp256k1zkp_v0_8_0_modinv64_signed62* out, const uint16_t* in) { +static void uint16_to_signed62(rustsecp256k1_v0_11_modinv64_signed62* out, const uint16_t* in) { int i; memset(out->v, 0, sizeof(out->v)); for (i = 0; i < 256; ++i) { @@ -1026,7 +932,7 @@ void uint16_to_signed62(rustsecp256k1zkp_v0_8_0_modinv64_signed62* out, const ui } /* Convert a 256-bit number in signed62 notation to a representation as 16 uint16_t's. */ -void signed62_to_uint16(uint16_t* out, const rustsecp256k1zkp_v0_8_0_modinv64_signed62* in) { +static void signed62_to_uint16(uint16_t* out, const rustsecp256k1_v0_11_modinv64_signed62* in) { int i; memset(out, 0, 32); for (i = 0; i < 256; ++i) { @@ -1035,11 +941,11 @@ void signed62_to_uint16(uint16_t* out, const rustsecp256k1zkp_v0_8_0_modinv64_si } /* Randomly mutate the sign of limbs in signed62 representation, without changing the value. */ -void mutate_sign_signed62(rustsecp256k1zkp_v0_8_0_modinv64_signed62* x) { +static void mutate_sign_signed62(rustsecp256k1_v0_11_modinv64_signed62* x) { static const int64_t M62 = (int64_t)(UINT64_MAX >> 2); int i; for (i = 0; i < 8; ++i) { - int pos = rustsecp256k1zkp_v0_8_0_testrand_bits(2); + int pos = testrand_bits(2); if (x->v[pos] > 0 && x->v[pos + 1] <= M62) { x->v[pos] -= (M62 + 1); x->v[pos + 1] += 1; @@ -1050,26 +956,46 @@ void mutate_sign_signed62(rustsecp256k1zkp_v0_8_0_modinv64_signed62* x) { } } -/* Test rustsecp256k1zkp_v0_8_0_modinv64{_var}, using inputs in 16-bit limb format, and returning inverse. */ -void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) { +/* Test rustsecp256k1_v0_11_modinv64{_var}, using inputs in 16-bit limb format, and returning inverse. */ +static void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) { static const int64_t M62 = (int64_t)(UINT64_MAX >> 2); uint16_t tmp[16]; - rustsecp256k1zkp_v0_8_0_modinv64_signed62 x; - rustsecp256k1zkp_v0_8_0_modinv64_modinfo m; + rustsecp256k1_v0_11_modinv64_signed62 x; + rustsecp256k1_v0_11_modinv64_modinfo m; int i, vartime, nonzero; uint16_to_signed62(&x, in); nonzero = (x.v[0] | x.v[1] | x.v[2] | x.v[3] | x.v[4]) != 0; uint16_to_signed62(&m.modulus, mod); - mutate_sign_signed62(&m.modulus); /* compute 1/modulus mod 2^62 */ m.modulus_inv62 = modinv2p64(m.modulus.v[0]) & M62; CHECK(((m.modulus_inv62 * m.modulus.v[0]) & M62) == 1); + /* Test rustsecp256k1_v0_11_jacobi64_maybe_var. */ + if (nonzero) { + int jac; + uint16_t sqr[16], negone[16]; + mulmod256(sqr, in, in, mod); + uint16_to_signed62(&x, sqr); + /* Compute jacobi symbol of in^2, which must be 1 (or uncomputable). */ + jac = rustsecp256k1_v0_11_jacobi64_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1); + /* Then compute the jacobi symbol of -(in^2). x and -x have opposite + * jacobi symbols if and only if (mod % 4) == 3. */ + negone[0] = mod[0] - 1; + for (i = 1; i < 16; ++i) negone[i] = mod[i]; + mulmod256(sqr, sqr, negone, mod); + uint16_to_signed62(&x, sqr); + jac = rustsecp256k1_v0_11_jacobi64_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1 - (mod[0] & 2)); + } + + uint16_to_signed62(&x, in); + mutate_sign_signed62(&m.modulus); for (vartime = 0; vartime < 2; ++vartime) { /* compute inverse */ - (vartime ? rustsecp256k1zkp_v0_8_0_modinv64_var : rustsecp256k1zkp_v0_8_0_modinv64)(&x, &m); + (vartime ? rustsecp256k1_v0_11_modinv64_var : rustsecp256k1_v0_11_modinv64)(&x, &m); /* produce output */ signed62_to_uint16(out, &x); @@ -1080,7 +1006,7 @@ void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod for (i = 1; i < 16; ++i) CHECK(tmp[i] == 0); /* invert again */ - (vartime ? rustsecp256k1zkp_v0_8_0_modinv64_var : rustsecp256k1zkp_v0_8_0_modinv64)(&x, &m); + (vartime ? rustsecp256k1_v0_11_modinv64_var : rustsecp256k1_v0_11_modinv64)(&x, &m); /* check if the result is equal to the input */ signed62_to_uint16(tmp, &x); @@ -1090,7 +1016,7 @@ void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod #endif /* test if a and b are coprime */ -int coprime(const uint16_t* a, const uint16_t* b) { +static int coprime(const uint16_t* a, const uint16_t* b) { uint16_t x[16], y[16], t[16]; int i; int iszero; @@ -1120,7 +1046,7 @@ int coprime(const uint16_t* a, const uint16_t* b) { return 1; } -void run_modinv_tests(void) { +static void run_modinv_tests(void) { /* Fixed test cases. Each tuple is (input, modulus, output), each as 16x16 bits in LE order. */ static const uint16_t CASES[][3][16] = { /* Test cases triggering edge cases in divsteps */ @@ -1722,7 +1648,7 @@ void run_modinv_tests(void) { #endif } - for (i = 0; i < 100 * count; ++i) { + for (i = 0; i < 100 * COUNT; ++i) { /* 256-bit numbers in 16-uint16_t's notation */ static const uint16_t ZERO[16] = {0}; uint16_t xd[16]; /* the number (in range [0,2^256)) to be inverted */ @@ -1732,8 +1658,8 @@ void run_modinv_tests(void) { /* generate random xd and md, so that md is odd, md>1, xd>= 16; + } +} + +/* Negate a 256-bit number (represented as 16 uint16_t's in LE order) mod 2^256. */ +static void neg256(uint16_t* out, const uint16_t* a) { + int i; + uint32_t carry = 1; + for (i = 0; i < 16; ++i) { + carry += (uint16_t)~a[i]; + out[i] = carry; + carry >>= 16; + } +} + +/* Right-shift a 256-bit number (represented as 16 uint16_t's in LE order). */ +static void rshift256(uint16_t* out, const uint16_t* a, int n, int sign_extend) { + uint16_t sign = sign_extend && (a[15] >> 15); + int i, j; + for (i = 15; i >= 0; --i) { + uint16_t v = 0; + for (j = 0; j < 16; ++j) { + int frompos = i*16 + j + n; + if (frompos >= 256) { + v |= sign << j; + } else { + v |= ((uint16_t)((a[frompos >> 4] >> (frompos & 15)) & 1)) << j; + } + } + out[i] = v; + } +} + +/* Load a 64-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */ +static void load256u64(uint16_t* out, uint64_t v, int is_signed) { + int i; + uint64_t sign = is_signed && (v >> 63) ? UINT64_MAX : 0; + for (i = 0; i < 4; ++i) { + out[i] = v >> (16 * i); + } + for (i = 4; i < 16; ++i) { + out[i] = sign; + } +} + +/* Load a 128-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */ +static void load256two64(uint16_t* out, uint64_t hi, uint64_t lo, int is_signed) { + int i; + uint64_t sign = is_signed && (hi >> 63) ? UINT64_MAX : 0; + for (i = 0; i < 4; ++i) { + out[i] = lo >> (16 * i); + } + for (i = 4; i < 8; ++i) { + out[i] = hi >> (16 * (i - 4)); + } + for (i = 8; i < 16; ++i) { + out[i] = sign; + } +} + +/* Check whether the 256-bit value represented by array of 16-bit values is in range -2^127 < v < 2^127. */ +static int int256is127(const uint16_t* v) { + int all_0 = ((v[7] & 0x8000) == 0), all_1 = ((v[7] & 0x8000) == 0x8000); + int i; + for (i = 8; i < 16; ++i) { + if (v[i] != 0) all_0 = 0; + if (v[i] != 0xffff) all_1 = 0; + } + return all_0 || all_1; +} + +static void load256u128(uint16_t* out, const rustsecp256k1_v0_11_uint128* v) { + uint64_t lo = rustsecp256k1_v0_11_u128_to_u64(v), hi = rustsecp256k1_v0_11_u128_hi_u64(v); + load256two64(out, hi, lo, 0); +} + +static void load256i128(uint16_t* out, const rustsecp256k1_v0_11_int128* v) { + uint64_t lo; + int64_t hi; + rustsecp256k1_v0_11_int128 c = *v; + lo = rustsecp256k1_v0_11_i128_to_u64(&c); + rustsecp256k1_v0_11_i128_rshift(&c, 64); + hi = rustsecp256k1_v0_11_i128_to_i64(&c); + load256two64(out, hi, lo, 1); +} + +static void run_int128_test_case(void) { + unsigned char buf[32]; + uint64_t v[4]; + rustsecp256k1_v0_11_int128 swa, swz; + rustsecp256k1_v0_11_uint128 uwa, uwz; + uint64_t ub, uc; + int64_t sb, sc; + uint16_t rswa[16], rswz[32], rswr[32], ruwa[16], ruwz[32], ruwr[32]; + uint16_t rub[16], ruc[16], rsb[16], rsc[16]; + int i; + + /* Generate 32-byte random value. */ + testrand256_test(buf); + /* Convert into 4 64-bit integers. */ + for (i = 0; i < 4; ++i) { + uint64_t vi = 0; + int j; + for (j = 0; j < 8; ++j) vi = (vi << 8) + buf[8*i + j]; + v[i] = vi; + } + /* Convert those into a 128-bit value and two 64-bit values (signed and unsigned). */ + rustsecp256k1_v0_11_u128_load(&uwa, v[1], v[0]); + rustsecp256k1_v0_11_i128_load(&swa, v[1], v[0]); + ub = v[2]; + sb = v[2]; + uc = v[3]; + sc = v[3]; + /* Load those also into 16-bit array representations. */ + load256u128(ruwa, &uwa); + load256i128(rswa, &swa); + load256u64(rub, ub, 0); + load256u64(rsb, sb, 1); + load256u64(ruc, uc, 0); + load256u64(rsc, sc, 1); + /* test rustsecp256k1_v0_11_u128_mul */ + mulmod256(ruwr, rub, ruc, NULL); + rustsecp256k1_v0_11_u128_mul(&uwz, ub, uc); + load256u128(ruwz, &uwz); + CHECK(rustsecp256k1_v0_11_memcmp_var(ruwr, ruwz, 16) == 0); + /* test rustsecp256k1_v0_11_u128_accum_mul */ + mulmod256(ruwr, rub, ruc, NULL); + add256(ruwr, ruwr, ruwa); + uwz = uwa; + rustsecp256k1_v0_11_u128_accum_mul(&uwz, ub, uc); + load256u128(ruwz, &uwz); + CHECK(rustsecp256k1_v0_11_memcmp_var(ruwr, ruwz, 16) == 0); + /* test rustsecp256k1_v0_11_u128_accum_u64 */ + add256(ruwr, rub, ruwa); + uwz = uwa; + rustsecp256k1_v0_11_u128_accum_u64(&uwz, ub); + load256u128(ruwz, &uwz); + CHECK(rustsecp256k1_v0_11_memcmp_var(ruwr, ruwz, 16) == 0); + /* test rustsecp256k1_v0_11_u128_rshift */ + rshift256(ruwr, ruwa, uc % 128, 0); + uwz = uwa; + rustsecp256k1_v0_11_u128_rshift(&uwz, uc % 128); + load256u128(ruwz, &uwz); + CHECK(rustsecp256k1_v0_11_memcmp_var(ruwr, ruwz, 16) == 0); + /* test rustsecp256k1_v0_11_u128_to_u64 */ + CHECK(rustsecp256k1_v0_11_u128_to_u64(&uwa) == v[0]); + /* test rustsecp256k1_v0_11_u128_hi_u64 */ + CHECK(rustsecp256k1_v0_11_u128_hi_u64(&uwa) == v[1]); + /* test rustsecp256k1_v0_11_u128_from_u64 */ + rustsecp256k1_v0_11_u128_from_u64(&uwz, ub); + load256u128(ruwz, &uwz); + CHECK(rustsecp256k1_v0_11_memcmp_var(rub, ruwz, 16) == 0); + /* test rustsecp256k1_v0_11_u128_check_bits */ + { + int uwa_bits = 0; + int j; + for (j = 0; j < 128; ++j) { + if (ruwa[j / 16] >> (j % 16)) uwa_bits = 1 + j; + } + for (j = 0; j < 128; ++j) { + CHECK(rustsecp256k1_v0_11_u128_check_bits(&uwa, j) == (uwa_bits <= j)); + } + } + /* test rustsecp256k1_v0_11_i128_mul */ + mulmod256(rswr, rsb, rsc, NULL); + rustsecp256k1_v0_11_i128_mul(&swz, sb, sc); + load256i128(rswz, &swz); + CHECK(rustsecp256k1_v0_11_memcmp_var(rswr, rswz, 16) == 0); + /* test rustsecp256k1_v0_11_i128_accum_mul */ + mulmod256(rswr, rsb, rsc, NULL); + add256(rswr, rswr, rswa); + if (int256is127(rswr)) { + swz = swa; + rustsecp256k1_v0_11_i128_accum_mul(&swz, sb, sc); + load256i128(rswz, &swz); + CHECK(rustsecp256k1_v0_11_memcmp_var(rswr, rswz, 16) == 0); + } + /* test rustsecp256k1_v0_11_i128_det */ + { + uint16_t rsd[16], rse[16], rst[32]; + int64_t sd = v[0], se = v[1]; + load256u64(rsd, sd, 1); + load256u64(rse, se, 1); + mulmod256(rst, rsc, rsd, NULL); + neg256(rst, rst); + mulmod256(rswr, rsb, rse, NULL); + add256(rswr, rswr, rst); + rustsecp256k1_v0_11_i128_det(&swz, sb, sc, sd, se); + load256i128(rswz, &swz); + CHECK(rustsecp256k1_v0_11_memcmp_var(rswr, rswz, 16) == 0); + } + /* test rustsecp256k1_v0_11_i128_rshift */ + rshift256(rswr, rswa, uc % 127, 1); + swz = swa; + rustsecp256k1_v0_11_i128_rshift(&swz, uc % 127); + load256i128(rswz, &swz); + CHECK(rustsecp256k1_v0_11_memcmp_var(rswr, rswz, 16) == 0); + /* test rustsecp256k1_v0_11_i128_to_u64 */ + CHECK(rustsecp256k1_v0_11_i128_to_u64(&swa) == v[0]); + /* test rustsecp256k1_v0_11_i128_from_i64 */ + rustsecp256k1_v0_11_i128_from_i64(&swz, sb); + load256i128(rswz, &swz); + CHECK(rustsecp256k1_v0_11_memcmp_var(rsb, rswz, 16) == 0); + /* test rustsecp256k1_v0_11_i128_to_i64 */ + CHECK(rustsecp256k1_v0_11_i128_to_i64(&swz) == sb); + /* test rustsecp256k1_v0_11_i128_eq_var */ + { + int expect = (uc & 1); + swz = swa; + if (!expect) { + /* Make sure swz != swa */ + uint64_t v0c = v[0], v1c = v[1]; + if (ub & 64) { + v1c ^= (((uint64_t)1) << (ub & 63)); + } else { + v0c ^= (((uint64_t)1) << (ub & 63)); + } + rustsecp256k1_v0_11_i128_load(&swz, v1c, v0c); + } + CHECK(rustsecp256k1_v0_11_i128_eq_var(&swa, &swz) == expect); + } + /* test rustsecp256k1_v0_11_i128_check_pow2 (sign == 1) */ + { + int expect = (uc & 1); + int pos = ub % 127; + if (expect) { + /* If expect==1, set swz to exactly 2^pos. */ + uint64_t hi = 0; + uint64_t lo = 0; + if (pos >= 64) { + hi = (((uint64_t)1) << (pos & 63)); + } else { + lo = (((uint64_t)1) << (pos & 63)); + } + rustsecp256k1_v0_11_i128_load(&swz, hi, lo); + } else { + /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal 2^pos. */ + if (pos >= 64) { + if ((v[1] == (((uint64_t)1) << (pos & 63))) && v[0] == 0) expect = 1; + } else { + if ((v[0] == (((uint64_t)1) << (pos & 63))) && v[1] == 0) expect = 1; + } + swz = swa; + } + CHECK(rustsecp256k1_v0_11_i128_check_pow2(&swz, pos, 1) == expect); + } + /* test rustsecp256k1_v0_11_i128_check_pow2 (sign == -1) */ + { + int expect = (uc & 1); + int pos = ub % 127; + if (expect) { + /* If expect==1, set swz to exactly -2^pos. */ + uint64_t hi = ~(uint64_t)0; + uint64_t lo = ~(uint64_t)0; + if (pos >= 64) { + hi <<= (pos & 63); + lo = 0; + } else { + lo <<= (pos & 63); + } + rustsecp256k1_v0_11_i128_load(&swz, hi, lo); + } else { + /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal -2^pos. */ + if (pos >= 64) { + if ((v[1] == ((~(uint64_t)0) << (pos & 63))) && v[0] == 0) expect = 1; + } else { + if ((v[0] == ((~(uint64_t)0) << (pos & 63))) && v[1] == ~(uint64_t)0) expect = 1; + } + swz = swa; + } + CHECK(rustsecp256k1_v0_11_i128_check_pow2(&swz, pos, -1) == expect); + } +} + +static void run_int128_tests(void) { + { /* rustsecp256k1_v0_11_u128_accum_mul */ + rustsecp256k1_v0_11_uint128 res; + + /* Check rustsecp256k1_v0_11_u128_accum_mul overflow */ + rustsecp256k1_v0_11_u128_mul(&res, UINT64_MAX, UINT64_MAX); + rustsecp256k1_v0_11_u128_accum_mul(&res, UINT64_MAX, UINT64_MAX); + CHECK(rustsecp256k1_v0_11_u128_to_u64(&res) == 2); + CHECK(rustsecp256k1_v0_11_u128_hi_u64(&res) == 18446744073709551612U); + } + { /* rustsecp256k1_v0_11_u128_accum_mul */ + rustsecp256k1_v0_11_int128 res; + + /* Compute INT128_MAX = 2^127 - 1 with rustsecp256k1_v0_11_i128_accum_mul */ + rustsecp256k1_v0_11_i128_mul(&res, INT64_MAX, INT64_MAX); + rustsecp256k1_v0_11_i128_accum_mul(&res, INT64_MAX, INT64_MAX); + CHECK(rustsecp256k1_v0_11_i128_to_u64(&res) == 2); + rustsecp256k1_v0_11_i128_accum_mul(&res, 4, 9223372036854775807); + rustsecp256k1_v0_11_i128_accum_mul(&res, 1, 1); + CHECK(rustsecp256k1_v0_11_i128_to_u64(&res) == UINT64_MAX); + rustsecp256k1_v0_11_i128_rshift(&res, 64); + CHECK(rustsecp256k1_v0_11_i128_to_i64(&res) == INT64_MAX); + + /* Compute INT128_MIN = - 2^127 with rustsecp256k1_v0_11_i128_accum_mul */ + rustsecp256k1_v0_11_i128_mul(&res, INT64_MAX, INT64_MIN); + CHECK(rustsecp256k1_v0_11_i128_to_u64(&res) == (uint64_t)INT64_MIN); + rustsecp256k1_v0_11_i128_accum_mul(&res, INT64_MAX, INT64_MIN); + CHECK(rustsecp256k1_v0_11_i128_to_u64(&res) == 0); + rustsecp256k1_v0_11_i128_accum_mul(&res, 2, INT64_MIN); + CHECK(rustsecp256k1_v0_11_i128_to_u64(&res) == 0); + rustsecp256k1_v0_11_i128_rshift(&res, 64); + CHECK(rustsecp256k1_v0_11_i128_to_i64(&res) == INT64_MIN); + } + { + /* Randomized tests. */ + int i; + for (i = 0; i < 256 * COUNT; ++i) run_int128_test_case(); + } +} +#endif +/***** SCALAR TESTS *****/ -void scalar_test(void) { - rustsecp256k1zkp_v0_8_0_scalar s; - rustsecp256k1zkp_v0_8_0_scalar s1; - rustsecp256k1zkp_v0_8_0_scalar s2; +static void scalar_test(void) { + rustsecp256k1_v0_11_scalar s; + rustsecp256k1_v0_11_scalar s1; + rustsecp256k1_v0_11_scalar s2; unsigned char c[32]; /* Set 's' to a random scalar, with value 'snum'. */ - random_scalar_order_test(&s); + testutil_random_scalar_order_test(&s); /* Set 's1' to a random scalar, with value 's1num'. */ - random_scalar_order_test(&s1); + testutil_random_scalar_order_test(&s1); /* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */ - random_scalar_order_test(&s2); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(c, &s2); + testutil_random_scalar_order_test(&s2); + rustsecp256k1_v0_11_scalar_get_b32(c, &s2); { int i; /* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */ - rustsecp256k1zkp_v0_8_0_scalar n; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&n, 0); + rustsecp256k1_v0_11_scalar n; + rustsecp256k1_v0_11_scalar_set_int(&n, 0); for (i = 0; i < 256; i += 4) { - rustsecp256k1zkp_v0_8_0_scalar t; + rustsecp256k1_v0_11_scalar t; int j; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&t, rustsecp256k1zkp_v0_8_0_scalar_get_bits(&s, 256 - 4 - i, 4)); + rustsecp256k1_v0_11_scalar_set_int(&t, rustsecp256k1_v0_11_scalar_get_bits_limb32(&s, 256 - 4 - i, 4)); for (j = 0; j < 4; j++) { - rustsecp256k1zkp_v0_8_0_scalar_add(&n, &n, &n); + rustsecp256k1_v0_11_scalar_add(&n, &n, &n); } - rustsecp256k1zkp_v0_8_0_scalar_add(&n, &n, &t); + rustsecp256k1_v0_11_scalar_add(&n, &n, &t); } - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&n, &s)); + CHECK(rustsecp256k1_v0_11_scalar_eq(&n, &s)); } { /* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */ - rustsecp256k1zkp_v0_8_0_scalar n; + rustsecp256k1_v0_11_scalar n; int i = 0; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&n, 0); + rustsecp256k1_v0_11_scalar_set_int(&n, 0); while (i < 256) { - rustsecp256k1zkp_v0_8_0_scalar t; + rustsecp256k1_v0_11_scalar t; int j; - int now = rustsecp256k1zkp_v0_8_0_testrand_int(15) + 1; + int now = testrand_int(15) + 1; if (now + i > 256) { now = 256 - i; } - rustsecp256k1zkp_v0_8_0_scalar_set_int(&t, rustsecp256k1zkp_v0_8_0_scalar_get_bits_var(&s, 256 - now - i, now)); + rustsecp256k1_v0_11_scalar_set_int(&t, rustsecp256k1_v0_11_scalar_get_bits_var(&s, 256 - now - i, now)); for (j = 0; j < now; j++) { - rustsecp256k1zkp_v0_8_0_scalar_add(&n, &n, &n); + rustsecp256k1_v0_11_scalar_add(&n, &n, &n); } - rustsecp256k1zkp_v0_8_0_scalar_add(&n, &n, &t); + rustsecp256k1_v0_11_scalar_add(&n, &n, &t); i += now; } - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&n, &s)); - } - - { - /* test rustsecp256k1zkp_v0_8_0_scalar_shr_int */ - rustsecp256k1zkp_v0_8_0_scalar r; - int i; - random_scalar_order_test(&r); - for (i = 0; i < 100; ++i) { - int low; - int shift = 1 + rustsecp256k1zkp_v0_8_0_testrand_int(15); - int expected = r.d[0] % (1 << shift); - low = rustsecp256k1zkp_v0_8_0_scalar_shr_int(&r, shift); - CHECK(expected == low); - } + CHECK(rustsecp256k1_v0_11_scalar_eq(&n, &s)); } { /* Test commutativity of add. */ - rustsecp256k1zkp_v0_8_0_scalar r1, r2; - rustsecp256k1zkp_v0_8_0_scalar_add(&r1, &s1, &s2); - rustsecp256k1zkp_v0_8_0_scalar_add(&r2, &s2, &s1); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&r1, &r2)); + rustsecp256k1_v0_11_scalar r1, r2; + rustsecp256k1_v0_11_scalar_add(&r1, &s1, &s2); + rustsecp256k1_v0_11_scalar_add(&r2, &s2, &s1); + CHECK(rustsecp256k1_v0_11_scalar_eq(&r1, &r2)); } { - rustsecp256k1zkp_v0_8_0_scalar r1, r2; - rustsecp256k1zkp_v0_8_0_scalar b; + rustsecp256k1_v0_11_scalar r1, r2; + rustsecp256k1_v0_11_scalar b; int i; /* Test add_bit. */ - int bit = rustsecp256k1zkp_v0_8_0_testrand_bits(8); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&b, 1); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_is_one(&b)); + int bit = testrand_bits(8); + rustsecp256k1_v0_11_scalar_set_int(&b, 1); + CHECK(rustsecp256k1_v0_11_scalar_is_one(&b)); for (i = 0; i < bit; i++) { - rustsecp256k1zkp_v0_8_0_scalar_add(&b, &b, &b); + rustsecp256k1_v0_11_scalar_add(&b, &b, &b); } r1 = s1; r2 = s1; - if (!rustsecp256k1zkp_v0_8_0_scalar_add(&r1, &r1, &b)) { + if (!rustsecp256k1_v0_11_scalar_add(&r1, &r1, &b)) { /* No overflow happened. */ - rustsecp256k1zkp_v0_8_0_scalar_cadd_bit(&r2, bit, 1); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&r1, &r2)); + rustsecp256k1_v0_11_scalar_cadd_bit(&r2, bit, 1); + CHECK(rustsecp256k1_v0_11_scalar_eq(&r1, &r2)); /* cadd is a noop when flag is zero */ - rustsecp256k1zkp_v0_8_0_scalar_cadd_bit(&r2, bit, 0); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&r1, &r2)); + rustsecp256k1_v0_11_scalar_cadd_bit(&r2, bit, 0); + CHECK(rustsecp256k1_v0_11_scalar_eq(&r1, &r2)); } } { /* Test commutativity of mul. */ - rustsecp256k1zkp_v0_8_0_scalar r1, r2; - rustsecp256k1zkp_v0_8_0_scalar_mul(&r1, &s1, &s2); - rustsecp256k1zkp_v0_8_0_scalar_mul(&r2, &s2, &s1); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&r1, &r2)); + rustsecp256k1_v0_11_scalar r1, r2; + rustsecp256k1_v0_11_scalar_mul(&r1, &s1, &s2); + rustsecp256k1_v0_11_scalar_mul(&r2, &s2, &s1); + CHECK(rustsecp256k1_v0_11_scalar_eq(&r1, &r2)); } { /* Test associativity of add. */ - rustsecp256k1zkp_v0_8_0_scalar r1, r2; - rustsecp256k1zkp_v0_8_0_scalar_add(&r1, &s1, &s2); - rustsecp256k1zkp_v0_8_0_scalar_add(&r1, &r1, &s); - rustsecp256k1zkp_v0_8_0_scalar_add(&r2, &s2, &s); - rustsecp256k1zkp_v0_8_0_scalar_add(&r2, &s1, &r2); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&r1, &r2)); + rustsecp256k1_v0_11_scalar r1, r2; + rustsecp256k1_v0_11_scalar_add(&r1, &s1, &s2); + rustsecp256k1_v0_11_scalar_add(&r1, &r1, &s); + rustsecp256k1_v0_11_scalar_add(&r2, &s2, &s); + rustsecp256k1_v0_11_scalar_add(&r2, &s1, &r2); + CHECK(rustsecp256k1_v0_11_scalar_eq(&r1, &r2)); } { /* Test associativity of mul. */ - rustsecp256k1zkp_v0_8_0_scalar r1, r2; - rustsecp256k1zkp_v0_8_0_scalar_mul(&r1, &s1, &s2); - rustsecp256k1zkp_v0_8_0_scalar_mul(&r1, &r1, &s); - rustsecp256k1zkp_v0_8_0_scalar_mul(&r2, &s2, &s); - rustsecp256k1zkp_v0_8_0_scalar_mul(&r2, &s1, &r2); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&r1, &r2)); + rustsecp256k1_v0_11_scalar r1, r2; + rustsecp256k1_v0_11_scalar_mul(&r1, &s1, &s2); + rustsecp256k1_v0_11_scalar_mul(&r1, &r1, &s); + rustsecp256k1_v0_11_scalar_mul(&r2, &s2, &s); + rustsecp256k1_v0_11_scalar_mul(&r2, &s1, &r2); + CHECK(rustsecp256k1_v0_11_scalar_eq(&r1, &r2)); } { /* Test distributitivity of mul over add. */ - rustsecp256k1zkp_v0_8_0_scalar r1, r2, t; - rustsecp256k1zkp_v0_8_0_scalar_add(&r1, &s1, &s2); - rustsecp256k1zkp_v0_8_0_scalar_mul(&r1, &r1, &s); - rustsecp256k1zkp_v0_8_0_scalar_mul(&r2, &s1, &s); - rustsecp256k1zkp_v0_8_0_scalar_mul(&t, &s2, &s); - rustsecp256k1zkp_v0_8_0_scalar_add(&r2, &r2, &t); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&r1, &r2)); - } - - { - /* Test square. */ - rustsecp256k1zkp_v0_8_0_scalar r1, r2; - rustsecp256k1zkp_v0_8_0_scalar_sqr(&r1, &s1); - rustsecp256k1zkp_v0_8_0_scalar_mul(&r2, &s1, &s1); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&r1, &r2)); + rustsecp256k1_v0_11_scalar r1, r2, t; + rustsecp256k1_v0_11_scalar_add(&r1, &s1, &s2); + rustsecp256k1_v0_11_scalar_mul(&r1, &r1, &s); + rustsecp256k1_v0_11_scalar_mul(&r2, &s1, &s); + rustsecp256k1_v0_11_scalar_mul(&t, &s2, &s); + rustsecp256k1_v0_11_scalar_add(&r2, &r2, &t); + CHECK(rustsecp256k1_v0_11_scalar_eq(&r1, &r2)); } { /* Test multiplicative identity. */ - rustsecp256k1zkp_v0_8_0_scalar r1, v1; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&v1,1); - rustsecp256k1zkp_v0_8_0_scalar_mul(&r1, &s1, &v1); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&r1, &s1)); + rustsecp256k1_v0_11_scalar r1; + rustsecp256k1_v0_11_scalar_mul(&r1, &s1, &rustsecp256k1_v0_11_scalar_one); + CHECK(rustsecp256k1_v0_11_scalar_eq(&r1, &s1)); } { /* Test additive identity. */ - rustsecp256k1zkp_v0_8_0_scalar r1, v0; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&v0,0); - rustsecp256k1zkp_v0_8_0_scalar_add(&r1, &s1, &v0); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&r1, &s1)); + rustsecp256k1_v0_11_scalar r1; + rustsecp256k1_v0_11_scalar_add(&r1, &s1, &rustsecp256k1_v0_11_scalar_zero); + CHECK(rustsecp256k1_v0_11_scalar_eq(&r1, &s1)); } { /* Test zero product property. */ - rustsecp256k1zkp_v0_8_0_scalar r1, v0; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&v0,0); - rustsecp256k1zkp_v0_8_0_scalar_mul(&r1, &s1, &v0); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&r1, &v0)); + rustsecp256k1_v0_11_scalar r1; + rustsecp256k1_v0_11_scalar_mul(&r1, &s1, &rustsecp256k1_v0_11_scalar_zero); + CHECK(rustsecp256k1_v0_11_scalar_eq(&r1, &rustsecp256k1_v0_11_scalar_zero)); } + { + /* Test halving. */ + rustsecp256k1_v0_11_scalar r; + rustsecp256k1_v0_11_scalar_add(&r, &s, &s); + rustsecp256k1_v0_11_scalar_half(&r, &r); + CHECK(rustsecp256k1_v0_11_scalar_eq(&r, &s)); + } } -void run_scalar_set_b32_seckey_tests(void) { +static void run_scalar_set_b32_seckey_tests(void) { unsigned char b32[32]; - rustsecp256k1zkp_v0_8_0_scalar s1; - rustsecp256k1zkp_v0_8_0_scalar s2; + rustsecp256k1_v0_11_scalar s1; + rustsecp256k1_v0_11_scalar s2; /* Usually set_b32 and set_b32_seckey give the same result */ - random_scalar_order_b32(b32); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&s1, b32, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&s2, b32) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&s1, &s2) == 1); + testutil_random_scalar_order_b32(b32); + rustsecp256k1_v0_11_scalar_set_b32(&s1, b32, NULL); + CHECK(rustsecp256k1_v0_11_scalar_set_b32_seckey(&s2, b32) == 1); + CHECK(rustsecp256k1_v0_11_scalar_eq(&s1, &s2) == 1); memset(b32, 0, sizeof(b32)); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&s2, b32) == 0); + CHECK(rustsecp256k1_v0_11_scalar_set_b32_seckey(&s2, b32) == 0); memset(b32, 0xFF, sizeof(b32)); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_set_b32_seckey(&s2, b32) == 0); -} - -void scalar_chacha_tests(void) { - /* Test vectors 1 to 4 from https://tools.ietf.org/html/rfc8439#appendix-A - * Note that scalar_set_b32 and scalar_get_b32 represent integers - * underlying the scalar in big-endian format. */ - unsigned char expected1[64] = { - 0xad, 0xe0, 0xb8, 0x76, 0x90, 0x3d, 0xf1, 0xa0, - 0xe5, 0x6a, 0x5d, 0x40, 0x28, 0xbd, 0x86, 0x53, - 0xb8, 0x19, 0xd2, 0xbd, 0x1a, 0xed, 0x8d, 0xa0, - 0xcc, 0xef, 0x36, 0xa8, 0xc7, 0x0d, 0x77, 0x8b, - 0x7c, 0x59, 0x41, 0xda, 0x8d, 0x48, 0x57, 0x51, - 0x3f, 0xe0, 0x24, 0x77, 0x37, 0x4a, 0xd8, 0xb8, - 0xf4, 0xb8, 0x43, 0x6a, 0x1c, 0xa1, 0x18, 0x15, - 0x69, 0xb6, 0x87, 0xc3, 0x86, 0x65, 0xee, 0xb2 - }; - unsigned char expected2[64] = { - 0xbe, 0xe7, 0x07, 0x9f, 0x7a, 0x38, 0x51, 0x55, - 0x7c, 0x97, 0xba, 0x98, 0x0d, 0x08, 0x2d, 0x73, - 0xa0, 0x29, 0x0f, 0xcb, 0x69, 0x65, 0xe3, 0x48, - 0x3e, 0x53, 0xc6, 0x12, 0xed, 0x7a, 0xee, 0x32, - 0x76, 0x21, 0xb7, 0x29, 0x43, 0x4e, 0xe6, 0x9c, - 0xb0, 0x33, 0x71, 0xd5, 0xd5, 0x39, 0xd8, 0x74, - 0x28, 0x1f, 0xed, 0x31, 0x45, 0xfb, 0x0a, 0x51, - 0x1f, 0x0a, 0xe1, 0xac, 0x6f, 0x4d, 0x79, 0x4b - }; - unsigned char seed3[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 - }; - unsigned char expected3[64] = { - 0x24, 0x52, 0xeb, 0x3a, 0x92, 0x49, 0xf8, 0xec, - 0x8d, 0x82, 0x9d, 0x9b, 0xdd, 0xd4, 0xce, 0xb1, - 0xe8, 0x25, 0x20, 0x83, 0x60, 0x81, 0x8b, 0x01, - 0xf3, 0x84, 0x22, 0xb8, 0x5a, 0xaa, 0x49, 0xc9, - 0xbb, 0x00, 0xca, 0x8e, 0xda, 0x3b, 0xa7, 0xb4, - 0xc4, 0xb5, 0x92, 0xd1, 0xfd, 0xf2, 0x73, 0x2f, - 0x44, 0x36, 0x27, 0x4e, 0x25, 0x61, 0xb3, 0xc8, - 0xeb, 0xdd, 0x4a, 0xa6, 0xa0, 0x13, 0x6c, 0x00 - }; - unsigned char seed4[32] = { - 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - unsigned char expected4[64] = { - 0xfb, 0x4d, 0xd5, 0x72, 0x4b, 0xc4, 0x2e, 0xf1, - 0xdf, 0x92, 0x26, 0x36, 0x32, 0x7f, 0x13, 0x94, - 0xa7, 0x8d, 0xea, 0x8f, 0x5e, 0x26, 0x90, 0x39, - 0xa1, 0xbe, 0xbb, 0xc1, 0xca, 0xf0, 0x9a, 0xae, - 0xa2, 0x5a, 0xb2, 0x13, 0x48, 0xa6, 0xb4, 0x6c, - 0x1b, 0x9d, 0x9b, 0xcb, 0x09, 0x2c, 0x5b, 0xe6, - 0x54, 0x6c, 0xa6, 0x24, 0x1b, 0xec, 0x45, 0xd5, - 0x87, 0xf4, 0x74, 0x73, 0x96, 0xf0, 0x99, 0x2e - }; - unsigned char seed5[32] = { - 0x32, 0x56, 0x56, 0xf4, 0x29, 0x02, 0xc2, 0xf8, - 0xa3, 0x4b, 0x96, 0xf5, 0xa7, 0xf7, 0xe3, 0x6c, - 0x92, 0xad, 0xa5, 0x18, 0x1c, 0xe3, 0x41, 0xae, - 0xc3, 0xf3, 0x18, 0xd0, 0xfa, 0x5b, 0x72, 0x53 - }; - unsigned char expected5[64] = { - 0xe7, 0x56, 0xd3, 0x28, 0xe9, 0xc6, 0x19, 0x5c, - 0x6f, 0x17, 0x8e, 0x21, 0x8c, 0x1e, 0x72, 0x11, - 0xe7, 0xbd, 0x17, 0x0d, 0xac, 0x14, 0xad, 0xe9, - 0x3d, 0x9f, 0xb6, 0x92, 0xd6, 0x09, 0x20, 0xfb, - 0x43, 0x8e, 0x3b, 0x6d, 0xe3, 0x33, 0xdc, 0xc7, - 0x6c, 0x07, 0x6f, 0xbb, 0x1f, 0xb4, 0xc8, 0xb5, - 0xe3, 0x6c, 0xe5, 0x12, 0xd9, 0xd7, 0x64, 0x0c, - 0xf5, 0xa7, 0x0d, 0xab, 0x79, 0x03, 0xf1, 0x81 - }; + CHECK(rustsecp256k1_v0_11_scalar_set_b32_seckey(&s2, b32) == 0); +} - rustsecp256k1zkp_v0_8_0_scalar exp_r1, exp_r2; - rustsecp256k1zkp_v0_8_0_scalar r1, r2; - unsigned char seed0[32] = { 0 }; - - rustsecp256k1zkp_v0_8_0_scalar_chacha20(&r1, &r2, seed0, 0); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&exp_r1, &expected1[0], NULL); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&exp_r2, &expected1[32], NULL); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&exp_r1, &r1)); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&exp_r2, &r2)); - - rustsecp256k1zkp_v0_8_0_scalar_chacha20(&r1, &r2, seed0, 1); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&exp_r1, &expected2[0], NULL); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&exp_r2, &expected2[32], NULL); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&exp_r1, &r1)); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&exp_r2, &r2)); - - rustsecp256k1zkp_v0_8_0_scalar_chacha20(&r1, &r2, seed3, 1); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&exp_r1, &expected3[0], NULL); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&exp_r2, &expected3[32], NULL); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&exp_r1, &r1)); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&exp_r2, &r2)); - - rustsecp256k1zkp_v0_8_0_scalar_chacha20(&r1, &r2, seed4, 2); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&exp_r1, &expected4[0], NULL); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&exp_r2, &expected4[32], NULL); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&exp_r1, &r1)); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&exp_r2, &r2)); - - rustsecp256k1zkp_v0_8_0_scalar_chacha20(&r1, &r2, seed5, 0x6ff8602a7a78e2f2ULL); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&exp_r1, &expected5[0], NULL); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&exp_r2, &expected5[32], NULL); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&exp_r1, &r1)); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&exp_r2, &r2)); -} - -void run_scalar_tests(void) { +static void run_scalar_tests(void) { int i; - for (i = 0; i < 128 * count; i++) { + for (i = 0; i < 128 * COUNT; i++) { scalar_test(); } - for (i = 0; i < count; i++) { + for (i = 0; i < COUNT; i++) { run_scalar_set_b32_seckey_tests(); } - scalar_chacha_tests(); + { + /* Check that the scalar constants rustsecp256k1_v0_11_scalar_zero and + rustsecp256k1_v0_11_scalar_one contain the expected values. */ + rustsecp256k1_v0_11_scalar zero, one; + + CHECK(rustsecp256k1_v0_11_scalar_is_zero(&rustsecp256k1_v0_11_scalar_zero)); + rustsecp256k1_v0_11_scalar_set_int(&zero, 0); + CHECK(rustsecp256k1_v0_11_scalar_eq(&zero, &rustsecp256k1_v0_11_scalar_zero)); + + CHECK(rustsecp256k1_v0_11_scalar_is_one(&rustsecp256k1_v0_11_scalar_one)); + rustsecp256k1_v0_11_scalar_set_int(&one, 1); + CHECK(rustsecp256k1_v0_11_scalar_eq(&one, &rustsecp256k1_v0_11_scalar_one)); + } { /* (-1)+1 should be zero. */ - rustsecp256k1zkp_v0_8_0_scalar s, o; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&s, 1); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_is_one(&s)); - rustsecp256k1zkp_v0_8_0_scalar_negate(&o, &s); - rustsecp256k1zkp_v0_8_0_scalar_add(&o, &o, &s); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_is_zero(&o)); - rustsecp256k1zkp_v0_8_0_scalar_negate(&o, &o); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_is_zero(&o)); + rustsecp256k1_v0_11_scalar o; + rustsecp256k1_v0_11_scalar_negate(&o, &rustsecp256k1_v0_11_scalar_one); + rustsecp256k1_v0_11_scalar_add(&o, &o, &rustsecp256k1_v0_11_scalar_one); + CHECK(rustsecp256k1_v0_11_scalar_is_zero(&o)); + rustsecp256k1_v0_11_scalar_negate(&o, &o); + CHECK(rustsecp256k1_v0_11_scalar_is_zero(&o)); + } + + { + /* Test that halving and doubling roundtrips on some fixed values. */ + static const rustsecp256k1_v0_11_scalar HALF_TESTS[] = { + /* 0 */ + SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0), + /* 1 */ + SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1), + /* -1 */ + SECP256K1_SCALAR_CONST(0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffeul, 0xbaaedce6ul, 0xaf48a03bul, 0xbfd25e8cul, 0xd0364140ul), + /* -2 (largest odd value) */ + SECP256K1_SCALAR_CONST(0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffeul, 0xbaaedce6ul, 0xaf48a03bul, 0xbfd25e8cul, 0xd036413Ful), + /* Half the secp256k1 order */ + SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0x5d576e73ul, 0x57a4501dul, 0xdfe92f46ul, 0x681b20a0ul), + /* Half the secp256k1 order + 1 */ + SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0x5d576e73ul, 0x57a4501dul, 0xdfe92f46ul, 0x681b20a1ul), + /* 2^255 */ + SECP256K1_SCALAR_CONST(0x80000000ul, 0, 0, 0, 0, 0, 0, 0), + /* 2^255 - 1 */ + SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful), + }; + unsigned n; + for (n = 0; n < sizeof(HALF_TESTS) / sizeof(HALF_TESTS[0]); ++n) { + rustsecp256k1_v0_11_scalar s; + rustsecp256k1_v0_11_scalar_half(&s, &HALF_TESTS[n]); + rustsecp256k1_v0_11_scalar_add(&s, &s, &s); + CHECK(rustsecp256k1_v0_11_scalar_eq(&s, &HALF_TESTS[n])); + rustsecp256k1_v0_11_scalar_add(&s, &s, &s); + rustsecp256k1_v0_11_scalar_half(&s, &s); + CHECK(rustsecp256k1_v0_11_scalar_eq(&s, &HALF_TESTS[n])); + } } { /* Does check_overflow check catch all ones? */ - static const rustsecp256k1zkp_v0_8_0_scalar overflowed = SECP256K1_SCALAR_CONST( + static const rustsecp256k1_v0_11_scalar overflowed = SECP256K1_SCALAR_CONST( 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL ); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_check_overflow(&overflowed)); + CHECK(rustsecp256k1_v0_11_scalar_check_overflow(&overflowed)); } { @@ -2095,14 +2262,13 @@ void run_scalar_tests(void) { * and edge-case coverage on 32-bit and 64-bit implementations. * The responses were generated with Sage 5.9. */ - rustsecp256k1zkp_v0_8_0_scalar x; - rustsecp256k1zkp_v0_8_0_scalar y; - rustsecp256k1zkp_v0_8_0_scalar z; - rustsecp256k1zkp_v0_8_0_scalar zz; - rustsecp256k1zkp_v0_8_0_scalar one; - rustsecp256k1zkp_v0_8_0_scalar r1; - rustsecp256k1zkp_v0_8_0_scalar r2; - rustsecp256k1zkp_v0_8_0_scalar zzv; + rustsecp256k1_v0_11_scalar x; + rustsecp256k1_v0_11_scalar y; + rustsecp256k1_v0_11_scalar z; + rustsecp256k1_v0_11_scalar zz; + rustsecp256k1_v0_11_scalar r1; + rustsecp256k1_v0_11_scalar r2; + rustsecp256k1_v0_11_scalar zzv; int overflow; unsigned char chal[33][2][32] = { {{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, @@ -2636,278 +2802,312 @@ void run_scalar_tests(void) { 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}} }; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&one, 1); for (i = 0; i < 33; i++) { - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&x, chal[i][0], &overflow); + rustsecp256k1_v0_11_scalar_set_b32(&x, chal[i][0], &overflow); CHECK(!overflow); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&y, chal[i][1], &overflow); + rustsecp256k1_v0_11_scalar_set_b32(&y, chal[i][1], &overflow); CHECK(!overflow); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&r1, res[i][0], &overflow); + rustsecp256k1_v0_11_scalar_set_b32(&r1, res[i][0], &overflow); CHECK(!overflow); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&r2, res[i][1], &overflow); + rustsecp256k1_v0_11_scalar_set_b32(&r2, res[i][1], &overflow); CHECK(!overflow); - rustsecp256k1zkp_v0_8_0_scalar_mul(&z, &x, &y); - CHECK(!rustsecp256k1zkp_v0_8_0_scalar_check_overflow(&z)); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&r1, &z)); - if (!rustsecp256k1zkp_v0_8_0_scalar_is_zero(&y)) { - rustsecp256k1zkp_v0_8_0_scalar_inverse(&zz, &y); - CHECK(!rustsecp256k1zkp_v0_8_0_scalar_check_overflow(&zz)); - rustsecp256k1zkp_v0_8_0_scalar_inverse_var(&zzv, &y); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&zzv, &zz)); - rustsecp256k1zkp_v0_8_0_scalar_mul(&z, &z, &zz); - CHECK(!rustsecp256k1zkp_v0_8_0_scalar_check_overflow(&z)); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&x, &z)); - rustsecp256k1zkp_v0_8_0_scalar_mul(&zz, &zz, &y); - CHECK(!rustsecp256k1zkp_v0_8_0_scalar_check_overflow(&zz)); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&one, &zz)); + rustsecp256k1_v0_11_scalar_mul(&z, &x, &y); + CHECK(rustsecp256k1_v0_11_scalar_eq(&r1, &z)); + if (!rustsecp256k1_v0_11_scalar_is_zero(&y)) { + rustsecp256k1_v0_11_scalar_inverse(&zz, &y); + rustsecp256k1_v0_11_scalar_inverse_var(&zzv, &y); + CHECK(rustsecp256k1_v0_11_scalar_eq(&zzv, &zz)); + rustsecp256k1_v0_11_scalar_mul(&z, &z, &zz); + CHECK(rustsecp256k1_v0_11_scalar_eq(&x, &z)); + rustsecp256k1_v0_11_scalar_mul(&zz, &zz, &y); + CHECK(rustsecp256k1_v0_11_scalar_eq(&rustsecp256k1_v0_11_scalar_one, &zz)); } - rustsecp256k1zkp_v0_8_0_scalar_mul(&z, &x, &x); - CHECK(!rustsecp256k1zkp_v0_8_0_scalar_check_overflow(&z)); - rustsecp256k1zkp_v0_8_0_scalar_sqr(&zz, &x); - CHECK(!rustsecp256k1zkp_v0_8_0_scalar_check_overflow(&zz)); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&zz, &z)); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&r2, &zz)); + rustsecp256k1_v0_11_scalar_mul(&z, &x, &x); + CHECK(rustsecp256k1_v0_11_scalar_eq(&r2, &z)); } } } /***** FIELD TESTS *****/ -void random_fe(rustsecp256k1zkp_v0_8_0_fe *x) { - unsigned char bin[32]; - do { - rustsecp256k1zkp_v0_8_0_testrand256(bin); - if (rustsecp256k1zkp_v0_8_0_fe_set_b32(x, bin)) { - return; - } - } while(1); -} - -void random_fe_test(rustsecp256k1zkp_v0_8_0_fe *x) { - unsigned char bin[32]; - do { - rustsecp256k1zkp_v0_8_0_testrand256_test(bin); - if (rustsecp256k1zkp_v0_8_0_fe_set_b32(x, bin)) { - return; - } - } while(1); -} - -void random_fe_non_zero(rustsecp256k1zkp_v0_8_0_fe *nz) { - int tries = 10; - while (--tries >= 0) { - random_fe(nz); - rustsecp256k1zkp_v0_8_0_fe_normalize(nz); - if (!rustsecp256k1zkp_v0_8_0_fe_is_zero(nz)) { - break; - } +static void random_fe_non_square(rustsecp256k1_v0_11_fe *ns) { + rustsecp256k1_v0_11_fe r; + testutil_random_fe_non_zero(ns); + if (rustsecp256k1_v0_11_fe_sqrt(&r, ns)) { + rustsecp256k1_v0_11_fe_negate(ns, ns, 1); } - /* Infinitesimal probability of spurious failure here */ - CHECK(tries >= 0); } -void random_fe_non_square(rustsecp256k1zkp_v0_8_0_fe *ns) { - rustsecp256k1zkp_v0_8_0_fe r; - random_fe_non_zero(ns); - if (rustsecp256k1zkp_v0_8_0_fe_sqrt(&r, ns)) { - rustsecp256k1zkp_v0_8_0_fe_negate(ns, ns, 1); - } +static int fe_equal(const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe *b) { + rustsecp256k1_v0_11_fe an = *a; + rustsecp256k1_v0_11_fe bn = *b; + rustsecp256k1_v0_11_fe_normalize_weak(&an); + return rustsecp256k1_v0_11_fe_equal(&an, &bn); } -int check_fe_equal(const rustsecp256k1zkp_v0_8_0_fe *a, const rustsecp256k1zkp_v0_8_0_fe *b) { - rustsecp256k1zkp_v0_8_0_fe an = *a; - rustsecp256k1zkp_v0_8_0_fe bn = *b; - rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&an); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&bn); - return rustsecp256k1zkp_v0_8_0_fe_equal_var(&an, &bn); -} - -void run_field_convert(void) { +static void run_field_convert(void) { static const unsigned char b32[32] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40 }; - static const rustsecp256k1zkp_v0_8_0_fe_storage fes = SECP256K1_FE_STORAGE_CONST( + static const rustsecp256k1_v0_11_fe_storage fes = SECP256K1_FE_STORAGE_CONST( 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL ); - static const rustsecp256k1zkp_v0_8_0_fe fe = SECP256K1_FE_CONST( + static const rustsecp256k1_v0_11_fe fe = SECP256K1_FE_CONST( 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL ); - rustsecp256k1zkp_v0_8_0_fe fe2; + rustsecp256k1_v0_11_fe fe2; unsigned char b322[32]; - rustsecp256k1zkp_v0_8_0_fe_storage fes2; + rustsecp256k1_v0_11_fe_storage fes2; /* Check conversions to fe. */ - CHECK(rustsecp256k1zkp_v0_8_0_fe_set_b32(&fe2, b32)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&fe, &fe2)); - rustsecp256k1zkp_v0_8_0_fe_from_storage(&fe2, &fes); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&fe, &fe2)); + CHECK(rustsecp256k1_v0_11_fe_set_b32_limit(&fe2, b32)); + CHECK(rustsecp256k1_v0_11_fe_equal(&fe, &fe2)); + rustsecp256k1_v0_11_fe_from_storage(&fe2, &fes); + CHECK(rustsecp256k1_v0_11_fe_equal(&fe, &fe2)); /* Check conversion from fe. */ - rustsecp256k1zkp_v0_8_0_fe_get_b32(b322, &fe); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(b322, b32, 32) == 0); - rustsecp256k1zkp_v0_8_0_fe_to_storage(&fes2, &fe); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&fes2, &fes, sizeof(fes)) == 0); + rustsecp256k1_v0_11_fe_get_b32(b322, &fe); + CHECK(rustsecp256k1_v0_11_memcmp_var(b322, b32, 32) == 0); + rustsecp256k1_v0_11_fe_to_storage(&fes2, &fe); + CHECK(rustsecp256k1_v0_11_memcmp_var(&fes2, &fes, sizeof(fes)) == 0); +} + +static void run_field_be32_overflow(void) { + { + static const unsigned char zero_overflow[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, + }; + static const unsigned char zero[32] = { 0x00 }; + unsigned char out[32]; + rustsecp256k1_v0_11_fe fe; + CHECK(rustsecp256k1_v0_11_fe_set_b32_limit(&fe, zero_overflow) == 0); + rustsecp256k1_v0_11_fe_set_b32_mod(&fe, zero_overflow); + CHECK(rustsecp256k1_v0_11_fe_normalizes_to_zero(&fe) == 1); + rustsecp256k1_v0_11_fe_normalize(&fe); + CHECK(rustsecp256k1_v0_11_fe_is_zero(&fe) == 1); + rustsecp256k1_v0_11_fe_get_b32(out, &fe); + CHECK(rustsecp256k1_v0_11_memcmp_var(out, zero, 32) == 0); + } + { + static const unsigned char one_overflow[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30, + }; + static const unsigned char one[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }; + unsigned char out[32]; + rustsecp256k1_v0_11_fe fe; + CHECK(rustsecp256k1_v0_11_fe_set_b32_limit(&fe, one_overflow) == 0); + rustsecp256k1_v0_11_fe_set_b32_mod(&fe, one_overflow); + rustsecp256k1_v0_11_fe_normalize(&fe); + CHECK(rustsecp256k1_v0_11_fe_cmp_var(&fe, &rustsecp256k1_v0_11_fe_one) == 0); + rustsecp256k1_v0_11_fe_get_b32(out, &fe); + CHECK(rustsecp256k1_v0_11_memcmp_var(out, one, 32) == 0); + } + { + static const unsigned char ff_overflow[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + }; + static const unsigned char ff[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xD0, + }; + unsigned char out[32]; + rustsecp256k1_v0_11_fe fe; + const rustsecp256k1_v0_11_fe fe_ff = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0x01, 0x000003d0); + CHECK(rustsecp256k1_v0_11_fe_set_b32_limit(&fe, ff_overflow) == 0); + rustsecp256k1_v0_11_fe_set_b32_mod(&fe, ff_overflow); + rustsecp256k1_v0_11_fe_normalize(&fe); + CHECK(rustsecp256k1_v0_11_fe_cmp_var(&fe, &fe_ff) == 0); + rustsecp256k1_v0_11_fe_get_b32(out, &fe); + CHECK(rustsecp256k1_v0_11_memcmp_var(out, ff, 32) == 0); + } } /* Returns true if two field elements have the same representation. */ -int fe_identical(const rustsecp256k1zkp_v0_8_0_fe *a, const rustsecp256k1zkp_v0_8_0_fe *b) { +static int fe_identical(const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe *b) { int ret = 1; -#ifdef VERIFY - ret &= (a->magnitude == b->magnitude); - ret &= (a->normalized == b->normalized); -#endif /* Compare the struct member that holds the limbs. */ - ret &= (rustsecp256k1zkp_v0_8_0_memcmp_var(a->n, b->n, sizeof(a->n)) == 0); + ret &= (rustsecp256k1_v0_11_memcmp_var(a->n, b->n, sizeof(a->n)) == 0); return ret; } -void run_field_half(void) { - rustsecp256k1zkp_v0_8_0_fe t, u; +static void run_field_half(void) { + rustsecp256k1_v0_11_fe t, u; int m; /* Check magnitude 0 input */ - rustsecp256k1zkp_v0_8_0_fe_get_bounds(&t, 0); - rustsecp256k1zkp_v0_8_0_fe_half(&t); + rustsecp256k1_v0_11_fe_get_bounds(&t, 0); + rustsecp256k1_v0_11_fe_half(&t); #ifdef VERIFY CHECK(t.magnitude == 1); CHECK(t.normalized == 0); #endif - CHECK(rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(&t)); + CHECK(rustsecp256k1_v0_11_fe_normalizes_to_zero(&t)); /* Check non-zero magnitudes in the supported range */ for (m = 1; m < 32; m++) { /* Check max-value input */ - rustsecp256k1zkp_v0_8_0_fe_get_bounds(&t, m); + rustsecp256k1_v0_11_fe_get_bounds(&t, m); u = t; - rustsecp256k1zkp_v0_8_0_fe_half(&u); + rustsecp256k1_v0_11_fe_half(&u); #ifdef VERIFY CHECK(u.magnitude == (m >> 1) + 1); CHECK(u.normalized == 0); #endif - rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&u); - rustsecp256k1zkp_v0_8_0_fe_add(&u, &u); - CHECK(check_fe_equal(&t, &u)); + rustsecp256k1_v0_11_fe_normalize_weak(&u); + rustsecp256k1_v0_11_fe_add(&u, &u); + CHECK(fe_equal(&t, &u)); /* Check worst-case input: ensure the LSB is 1 so that P will be added, * which will also cause all carries to be 1, since all limbs that can * generate a carry are initially even and all limbs of P are odd in * every existing field implementation. */ - rustsecp256k1zkp_v0_8_0_fe_get_bounds(&t, m); + rustsecp256k1_v0_11_fe_get_bounds(&t, m); CHECK(t.n[0] > 0); CHECK((t.n[0] & 1) == 0); --t.n[0]; u = t; - rustsecp256k1zkp_v0_8_0_fe_half(&u); + rustsecp256k1_v0_11_fe_half(&u); #ifdef VERIFY CHECK(u.magnitude == (m >> 1) + 1); CHECK(u.normalized == 0); #endif - rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&u); - rustsecp256k1zkp_v0_8_0_fe_add(&u, &u); - CHECK(check_fe_equal(&t, &u)); + rustsecp256k1_v0_11_fe_normalize_weak(&u); + rustsecp256k1_v0_11_fe_add(&u, &u); + CHECK(fe_equal(&t, &u)); } } -void run_field_misc(void) { - rustsecp256k1zkp_v0_8_0_fe x; - rustsecp256k1zkp_v0_8_0_fe y; - rustsecp256k1zkp_v0_8_0_fe z; - rustsecp256k1zkp_v0_8_0_fe q; - rustsecp256k1zkp_v0_8_0_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); +static void run_field_misc(void) { + rustsecp256k1_v0_11_fe x; + rustsecp256k1_v0_11_fe y; + rustsecp256k1_v0_11_fe z; + rustsecp256k1_v0_11_fe q; + int v; + rustsecp256k1_v0_11_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); int i, j; - for (i = 0; i < 1000 * count; i++) { - rustsecp256k1zkp_v0_8_0_fe_storage xs, ys, zs; + for (i = 0; i < 1000 * COUNT; i++) { + rustsecp256k1_v0_11_fe_storage xs, ys, zs; if (i & 1) { - random_fe(&x); + testutil_random_fe(&x); } else { - random_fe_test(&x); + testutil_random_fe_test(&x); } - random_fe_non_zero(&y); + testutil_random_fe_non_zero(&y); + v = testrand_bits(15); + /* Test that fe_add_int is equivalent to fe_set_int + fe_add. */ + rustsecp256k1_v0_11_fe_set_int(&q, v); /* q = v */ + z = x; /* z = x */ + rustsecp256k1_v0_11_fe_add(&z, &q); /* z = x+v */ + q = x; /* q = x */ + rustsecp256k1_v0_11_fe_add_int(&q, v); /* q = x+v */ + CHECK(fe_equal(&q, &z)); /* Test the fe equality and comparison operations. */ - CHECK(rustsecp256k1zkp_v0_8_0_fe_cmp_var(&x, &x) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&x, &x)); + CHECK(rustsecp256k1_v0_11_fe_cmp_var(&x, &x) == 0); + CHECK(rustsecp256k1_v0_11_fe_equal(&x, &x)); z = x; - rustsecp256k1zkp_v0_8_0_fe_add(&z,&y); + rustsecp256k1_v0_11_fe_add(&z,&y); /* Test fe conditional move; z is not normalized here. */ q = x; - rustsecp256k1zkp_v0_8_0_fe_cmov(&x, &z, 0); + rustsecp256k1_v0_11_fe_cmov(&x, &z, 0); #ifdef VERIFY - CHECK(x.normalized && x.magnitude == 1); + CHECK(!x.normalized); + CHECK((x.magnitude == q.magnitude) || (x.magnitude == z.magnitude)); + CHECK((x.magnitude >= q.magnitude) && (x.magnitude >= z.magnitude)); #endif - rustsecp256k1zkp_v0_8_0_fe_cmov(&x, &x, 1); + x = q; + rustsecp256k1_v0_11_fe_cmov(&x, &x, 1); CHECK(!fe_identical(&x, &z)); CHECK(fe_identical(&x, &q)); - rustsecp256k1zkp_v0_8_0_fe_cmov(&q, &z, 1); + rustsecp256k1_v0_11_fe_cmov(&q, &z, 1); #ifdef VERIFY - CHECK(!q.normalized && q.magnitude == z.magnitude); + CHECK(!q.normalized); + CHECK((q.magnitude == x.magnitude) || (q.magnitude == z.magnitude)); + CHECK((q.magnitude >= x.magnitude) && (q.magnitude >= z.magnitude)); #endif CHECK(fe_identical(&q, &z)); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&x); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&z); - CHECK(!rustsecp256k1zkp_v0_8_0_fe_equal_var(&x, &z)); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&q); - rustsecp256k1zkp_v0_8_0_fe_cmov(&q, &z, (i&1)); + q = z; + rustsecp256k1_v0_11_fe_normalize_var(&x); + rustsecp256k1_v0_11_fe_normalize_var(&z); + CHECK(!rustsecp256k1_v0_11_fe_equal(&x, &z)); + rustsecp256k1_v0_11_fe_normalize_var(&q); + rustsecp256k1_v0_11_fe_cmov(&q, &z, (i&1)); #ifdef VERIFY CHECK(q.normalized && q.magnitude == 1); #endif for (j = 0; j < 6; j++) { - rustsecp256k1zkp_v0_8_0_fe_negate(&z, &z, j+1); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&q); - rustsecp256k1zkp_v0_8_0_fe_cmov(&q, &z, (j&1)); + rustsecp256k1_v0_11_fe_negate_unchecked(&z, &z, j+1); + rustsecp256k1_v0_11_fe_normalize_var(&q); + rustsecp256k1_v0_11_fe_cmov(&q, &z, (j&1)); #ifdef VERIFY - CHECK((q.normalized != (j&1)) && q.magnitude == ((j&1) ? z.magnitude : 1)); + CHECK(!q.normalized && q.magnitude == z.magnitude); #endif } - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&z); + rustsecp256k1_v0_11_fe_normalize_var(&z); /* Test storage conversion and conditional moves. */ - rustsecp256k1zkp_v0_8_0_fe_to_storage(&xs, &x); - rustsecp256k1zkp_v0_8_0_fe_to_storage(&ys, &y); - rustsecp256k1zkp_v0_8_0_fe_to_storage(&zs, &z); - rustsecp256k1zkp_v0_8_0_fe_storage_cmov(&zs, &xs, 0); - rustsecp256k1zkp_v0_8_0_fe_storage_cmov(&zs, &zs, 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&xs, &zs, sizeof(xs)) != 0); - rustsecp256k1zkp_v0_8_0_fe_storage_cmov(&ys, &xs, 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&xs, &ys, sizeof(xs)) == 0); - rustsecp256k1zkp_v0_8_0_fe_from_storage(&x, &xs); - rustsecp256k1zkp_v0_8_0_fe_from_storage(&y, &ys); - rustsecp256k1zkp_v0_8_0_fe_from_storage(&z, &zs); + rustsecp256k1_v0_11_fe_to_storage(&xs, &x); + rustsecp256k1_v0_11_fe_to_storage(&ys, &y); + rustsecp256k1_v0_11_fe_to_storage(&zs, &z); + rustsecp256k1_v0_11_fe_storage_cmov(&zs, &xs, 0); + rustsecp256k1_v0_11_fe_storage_cmov(&zs, &zs, 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&xs, &zs, sizeof(xs)) != 0); + rustsecp256k1_v0_11_fe_storage_cmov(&ys, &xs, 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&xs, &ys, sizeof(xs)) == 0); + rustsecp256k1_v0_11_fe_from_storage(&x, &xs); + rustsecp256k1_v0_11_fe_from_storage(&y, &ys); + rustsecp256k1_v0_11_fe_from_storage(&z, &zs); /* Test that mul_int, mul, and add agree. */ - rustsecp256k1zkp_v0_8_0_fe_add(&y, &x); - rustsecp256k1zkp_v0_8_0_fe_add(&y, &x); + rustsecp256k1_v0_11_fe_add(&y, &x); + rustsecp256k1_v0_11_fe_add(&y, &x); z = x; - rustsecp256k1zkp_v0_8_0_fe_mul_int(&z, 3); - CHECK(check_fe_equal(&y, &z)); - rustsecp256k1zkp_v0_8_0_fe_add(&y, &x); - rustsecp256k1zkp_v0_8_0_fe_add(&z, &x); - CHECK(check_fe_equal(&z, &y)); + rustsecp256k1_v0_11_fe_mul_int(&z, 3); + CHECK(fe_equal(&y, &z)); + rustsecp256k1_v0_11_fe_add(&y, &x); + rustsecp256k1_v0_11_fe_add(&z, &x); + CHECK(fe_equal(&z, &y)); z = x; - rustsecp256k1zkp_v0_8_0_fe_mul_int(&z, 5); - rustsecp256k1zkp_v0_8_0_fe_mul(&q, &x, &fe5); - CHECK(check_fe_equal(&z, &q)); - rustsecp256k1zkp_v0_8_0_fe_negate(&x, &x, 1); - rustsecp256k1zkp_v0_8_0_fe_add(&z, &x); - rustsecp256k1zkp_v0_8_0_fe_add(&q, &x); - CHECK(check_fe_equal(&y, &z)); - CHECK(check_fe_equal(&q, &y)); - /* Check rustsecp256k1zkp_v0_8_0_fe_half. */ + rustsecp256k1_v0_11_fe_mul_int(&z, 5); + rustsecp256k1_v0_11_fe_mul(&q, &x, &fe5); + CHECK(fe_equal(&z, &q)); + rustsecp256k1_v0_11_fe_negate(&x, &x, 1); + rustsecp256k1_v0_11_fe_add(&z, &x); + rustsecp256k1_v0_11_fe_add(&q, &x); + CHECK(fe_equal(&y, &z)); + CHECK(fe_equal(&q, &y)); + /* Check rustsecp256k1_v0_11_fe_half. */ z = x; - rustsecp256k1zkp_v0_8_0_fe_half(&z); - rustsecp256k1zkp_v0_8_0_fe_add(&z, &z); - CHECK(check_fe_equal(&x, &z)); - rustsecp256k1zkp_v0_8_0_fe_add(&z, &z); - rustsecp256k1zkp_v0_8_0_fe_half(&z); - CHECK(check_fe_equal(&x, &z)); + rustsecp256k1_v0_11_fe_half(&z); + rustsecp256k1_v0_11_fe_add(&z, &z); + CHECK(fe_equal(&x, &z)); + rustsecp256k1_v0_11_fe_add(&z, &z); + rustsecp256k1_v0_11_fe_half(&z); + CHECK(fe_equal(&x, &z)); } } -void test_fe_mul(const rustsecp256k1zkp_v0_8_0_fe* a, const rustsecp256k1zkp_v0_8_0_fe* b, int use_sqr) +static void test_fe_mul(const rustsecp256k1_v0_11_fe* a, const rustsecp256k1_v0_11_fe* b, int use_sqr) { - rustsecp256k1zkp_v0_8_0_fe c, an, bn; + rustsecp256k1_v0_11_fe c, an, bn; /* Variables in BE 32-byte format. */ unsigned char a32[32], b32[32], c32[32]; /* Variables in LE 16x uint16_t format. */ @@ -2923,20 +3123,20 @@ void test_fe_mul(const rustsecp256k1zkp_v0_8_0_fe* a, const rustsecp256k1zkp_v0_ /* Compute C = A * B in fe format. */ c = *a; if (use_sqr) { - rustsecp256k1zkp_v0_8_0_fe_sqr(&c, &c); + rustsecp256k1_v0_11_fe_sqr(&c, &c); } else { - rustsecp256k1zkp_v0_8_0_fe_mul(&c, &c, b); + rustsecp256k1_v0_11_fe_mul(&c, &c, b); } /* Convert A, B, C into LE 16x uint16_t format. */ an = *a; bn = *b; - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&c); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&an); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&bn); - rustsecp256k1zkp_v0_8_0_fe_get_b32(a32, &an); - rustsecp256k1zkp_v0_8_0_fe_get_b32(b32, &bn); - rustsecp256k1zkp_v0_8_0_fe_get_b32(c32, &c); + rustsecp256k1_v0_11_fe_normalize_var(&c); + rustsecp256k1_v0_11_fe_normalize_var(&an); + rustsecp256k1_v0_11_fe_normalize_var(&bn); + rustsecp256k1_v0_11_fe_get_b32(a32, &an); + rustsecp256k1_v0_11_fe_get_b32(b32, &bn); + rustsecp256k1_v0_11_fe_get_b32(c32, &c); for (i = 0; i < 16; ++i) { a16[i] = a32[31 - 2*i] + ((uint16_t)a32[30 - 2*i] << 8); b16[i] = b32[31 - 2*i] + ((uint16_t)b32[30 - 2*i] << 8); @@ -2945,21 +3145,21 @@ void test_fe_mul(const rustsecp256k1zkp_v0_8_0_fe* a, const rustsecp256k1zkp_v0_ /* Compute T = A * B in LE 16x uint16_t format. */ mulmod256(t16, a16, b16, m16); /* Compare */ - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(t16, c16, 32) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(t16, c16, 32) == 0); } -void run_fe_mul(void) { +static void run_fe_mul(void) { int i; - for (i = 0; i < 100 * count; ++i) { - rustsecp256k1zkp_v0_8_0_fe a, b, c, d; - random_fe(&a); - random_field_element_magnitude(&a); - random_fe(&b); - random_field_element_magnitude(&b); - random_fe_test(&c); - random_field_element_magnitude(&c); - random_fe_test(&d); - random_field_element_magnitude(&d); + for (i = 0; i < 100 * COUNT; ++i) { + rustsecp256k1_v0_11_fe a, b, c, d; + testutil_random_fe(&a); + testutil_random_fe_magnitude(&a, 8); + testutil_random_fe(&b); + testutil_random_fe_magnitude(&b, 8); + testutil_random_fe_test(&c); + testutil_random_fe_magnitude(&c, 8); + testutil_random_fe_test(&d); + testutil_random_fe_magnitude(&d, 8); test_fe_mul(&a, &a, 1); test_fe_mul(&c, &c, 1); test_fe_mul(&a, &b, 0); @@ -2969,51 +3169,64 @@ void run_fe_mul(void) { } } -void run_sqr(void) { - rustsecp256k1zkp_v0_8_0_fe x, s; +static void run_sqr(void) { + int i; + rustsecp256k1_v0_11_fe x, y, lhs, rhs, tmp; - { - int i; - rustsecp256k1zkp_v0_8_0_fe_set_int(&x, 1); - rustsecp256k1zkp_v0_8_0_fe_negate(&x, &x, 1); + rustsecp256k1_v0_11_fe_set_int(&x, 1); + rustsecp256k1_v0_11_fe_negate(&x, &x, 1); - for (i = 1; i <= 512; ++i) { - rustsecp256k1zkp_v0_8_0_fe_mul_int(&x, 2); - rustsecp256k1zkp_v0_8_0_fe_normalize(&x); - rustsecp256k1zkp_v0_8_0_fe_sqr(&s, &x); - } + for (i = 1; i <= 512; ++i) { + rustsecp256k1_v0_11_fe_mul_int(&x, 2); + rustsecp256k1_v0_11_fe_normalize(&x); + + /* Check that (x+y)*(x-y) = x^2 - y*2 for some random values y */ + testutil_random_fe_test(&y); + + lhs = x; + rustsecp256k1_v0_11_fe_add(&lhs, &y); /* lhs = x+y */ + rustsecp256k1_v0_11_fe_negate(&tmp, &y, 1); /* tmp = -y */ + rustsecp256k1_v0_11_fe_add(&tmp, &x); /* tmp = x-y */ + rustsecp256k1_v0_11_fe_mul(&lhs, &lhs, &tmp); /* lhs = (x+y)*(x-y) */ + + rustsecp256k1_v0_11_fe_sqr(&rhs, &x); /* rhs = x^2 */ + rustsecp256k1_v0_11_fe_sqr(&tmp, &y); /* tmp = y^2 */ + rustsecp256k1_v0_11_fe_negate(&tmp, &tmp, 1); /* tmp = -y^2 */ + rustsecp256k1_v0_11_fe_add(&rhs, &tmp); /* rhs = x^2 - y^2 */ + + CHECK(fe_equal(&lhs, &rhs)); } } -void test_sqrt(const rustsecp256k1zkp_v0_8_0_fe *a, const rustsecp256k1zkp_v0_8_0_fe *k) { - rustsecp256k1zkp_v0_8_0_fe r1, r2; - int v = rustsecp256k1zkp_v0_8_0_fe_sqrt(&r1, a); +static void test_sqrt(const rustsecp256k1_v0_11_fe *a, const rustsecp256k1_v0_11_fe *k) { + rustsecp256k1_v0_11_fe r1, r2; + int v = rustsecp256k1_v0_11_fe_sqrt(&r1, a); CHECK((v == 0) == (k == NULL)); if (k != NULL) { /* Check that the returned root is +/- the given known answer */ - rustsecp256k1zkp_v0_8_0_fe_negate(&r2, &r1, 1); - rustsecp256k1zkp_v0_8_0_fe_add(&r1, k); rustsecp256k1zkp_v0_8_0_fe_add(&r2, k); - rustsecp256k1zkp_v0_8_0_fe_normalize(&r1); rustsecp256k1zkp_v0_8_0_fe_normalize(&r2); - CHECK(rustsecp256k1zkp_v0_8_0_fe_is_zero(&r1) || rustsecp256k1zkp_v0_8_0_fe_is_zero(&r2)); + rustsecp256k1_v0_11_fe_negate(&r2, &r1, 1); + rustsecp256k1_v0_11_fe_add(&r1, k); rustsecp256k1_v0_11_fe_add(&r2, k); + rustsecp256k1_v0_11_fe_normalize(&r1); rustsecp256k1_v0_11_fe_normalize(&r2); + CHECK(rustsecp256k1_v0_11_fe_is_zero(&r1) || rustsecp256k1_v0_11_fe_is_zero(&r2)); } } -void run_sqrt(void) { - rustsecp256k1zkp_v0_8_0_fe ns, x, s, t; +static void run_sqrt(void) { + rustsecp256k1_v0_11_fe ns, x, s, t; int i; /* Check sqrt(0) is 0 */ - rustsecp256k1zkp_v0_8_0_fe_set_int(&x, 0); - rustsecp256k1zkp_v0_8_0_fe_sqr(&s, &x); + rustsecp256k1_v0_11_fe_set_int(&x, 0); + rustsecp256k1_v0_11_fe_sqr(&s, &x); test_sqrt(&s, &x); /* Check sqrt of small squares (and their negatives) */ for (i = 1; i <= 100; i++) { - rustsecp256k1zkp_v0_8_0_fe_set_int(&x, i); - rustsecp256k1zkp_v0_8_0_fe_sqr(&s, &x); + rustsecp256k1_v0_11_fe_set_int(&x, i); + rustsecp256k1_v0_11_fe_sqr(&s, &x); test_sqrt(&s, &x); - rustsecp256k1zkp_v0_8_0_fe_negate(&t, &s, 1); + rustsecp256k1_v0_11_fe_negate(&t, &s, 1); test_sqrt(&t, NULL); } @@ -3021,13 +3234,15 @@ void run_sqrt(void) { for (i = 0; i < 10; i++) { int j; random_fe_non_square(&ns); - for (j = 0; j < count; j++) { - random_fe(&x); - rustsecp256k1zkp_v0_8_0_fe_sqr(&s, &x); + for (j = 0; j < COUNT; j++) { + testutil_random_fe(&x); + rustsecp256k1_v0_11_fe_sqr(&s, &x); + CHECK(rustsecp256k1_v0_11_fe_is_square_var(&s)); test_sqrt(&s, &x); - rustsecp256k1zkp_v0_8_0_fe_negate(&t, &s, 1); + rustsecp256k1_v0_11_fe_negate(&t, &s, 1); + CHECK(!rustsecp256k1_v0_11_fe_is_square_var(&t)); test_sqrt(&t, NULL); - rustsecp256k1zkp_v0_8_0_fe_mul(&t, &s, &ns); + rustsecp256k1_v0_11_fe_mul(&t, &s, &ns); test_sqrt(&t, NULL); } } @@ -3035,12 +3250,12 @@ void run_sqrt(void) { /***** FIELD/SCALAR INVERSE TESTS *****/ -static const rustsecp256k1zkp_v0_8_0_scalar scalar_minus_one = SECP256K1_SCALAR_CONST( +static const rustsecp256k1_v0_11_scalar scalar_minus_one = SECP256K1_SCALAR_CONST( 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xBAAEDCE6, 0xAF48A03B, 0xBFD25E8C, 0xD0364140 ); -static const rustsecp256k1zkp_v0_8_0_fe fe_minus_one = SECP256K1_FE_CONST( +static const rustsecp256k1_v0_11_fe fe_minus_one = SECP256K1_FE_CONST( 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFC2E ); @@ -3052,57 +3267,57 @@ static const rustsecp256k1zkp_v0_8_0_fe fe_minus_one = SECP256K1_FE_CONST( * for x!=0 and x!=1: 1/(1/x - 1) + 1 == -1/(x-1) */ -void test_inverse_scalar(rustsecp256k1zkp_v0_8_0_scalar* out, const rustsecp256k1zkp_v0_8_0_scalar* x, int var) +static void test_inverse_scalar(rustsecp256k1_v0_11_scalar* out, const rustsecp256k1_v0_11_scalar* x, int var) { - rustsecp256k1zkp_v0_8_0_scalar l, r, t; + rustsecp256k1_v0_11_scalar l, r, t; - (var ? rustsecp256k1zkp_v0_8_0_scalar_inverse_var : rustsecp256k1zkp_v0_8_0_scalar_inverse)(&l, x); /* l = 1/x */ + (var ? rustsecp256k1_v0_11_scalar_inverse_var : rustsecp256k1_v0_11_scalar_inverse)(&l, x); /* l = 1/x */ if (out) *out = l; - if (rustsecp256k1zkp_v0_8_0_scalar_is_zero(x)) { - CHECK(rustsecp256k1zkp_v0_8_0_scalar_is_zero(&l)); + if (rustsecp256k1_v0_11_scalar_is_zero(x)) { + CHECK(rustsecp256k1_v0_11_scalar_is_zero(&l)); return; } - rustsecp256k1zkp_v0_8_0_scalar_mul(&t, x, &l); /* t = x*(1/x) */ - CHECK(rustsecp256k1zkp_v0_8_0_scalar_is_one(&t)); /* x*(1/x) == 1 */ - rustsecp256k1zkp_v0_8_0_scalar_add(&r, x, &scalar_minus_one); /* r = x-1 */ - if (rustsecp256k1zkp_v0_8_0_scalar_is_zero(&r)) return; - (var ? rustsecp256k1zkp_v0_8_0_scalar_inverse_var : rustsecp256k1zkp_v0_8_0_scalar_inverse)(&r, &r); /* r = 1/(x-1) */ - rustsecp256k1zkp_v0_8_0_scalar_add(&l, &scalar_minus_one, &l); /* l = 1/x-1 */ - (var ? rustsecp256k1zkp_v0_8_0_scalar_inverse_var : rustsecp256k1zkp_v0_8_0_scalar_inverse)(&l, &l); /* l = 1/(1/x-1) */ - rustsecp256k1zkp_v0_8_0_scalar_add(&l, &l, &rustsecp256k1zkp_v0_8_0_scalar_one); /* l = 1/(1/x-1)+1 */ - rustsecp256k1zkp_v0_8_0_scalar_add(&l, &r, &l); /* l = 1/(1/x-1)+1 + 1/(x-1) */ - CHECK(rustsecp256k1zkp_v0_8_0_scalar_is_zero(&l)); /* l == 0 */ + rustsecp256k1_v0_11_scalar_mul(&t, x, &l); /* t = x*(1/x) */ + CHECK(rustsecp256k1_v0_11_scalar_is_one(&t)); /* x*(1/x) == 1 */ + rustsecp256k1_v0_11_scalar_add(&r, x, &scalar_minus_one); /* r = x-1 */ + if (rustsecp256k1_v0_11_scalar_is_zero(&r)) return; + (var ? rustsecp256k1_v0_11_scalar_inverse_var : rustsecp256k1_v0_11_scalar_inverse)(&r, &r); /* r = 1/(x-1) */ + rustsecp256k1_v0_11_scalar_add(&l, &scalar_minus_one, &l); /* l = 1/x-1 */ + (var ? rustsecp256k1_v0_11_scalar_inverse_var : rustsecp256k1_v0_11_scalar_inverse)(&l, &l); /* l = 1/(1/x-1) */ + rustsecp256k1_v0_11_scalar_add(&l, &l, &rustsecp256k1_v0_11_scalar_one); /* l = 1/(1/x-1)+1 */ + rustsecp256k1_v0_11_scalar_add(&l, &r, &l); /* l = 1/(1/x-1)+1 + 1/(x-1) */ + CHECK(rustsecp256k1_v0_11_scalar_is_zero(&l)); /* l == 0 */ } -void test_inverse_field(rustsecp256k1zkp_v0_8_0_fe* out, const rustsecp256k1zkp_v0_8_0_fe* x, int var) +static void test_inverse_field(rustsecp256k1_v0_11_fe* out, const rustsecp256k1_v0_11_fe* x, int var) { - rustsecp256k1zkp_v0_8_0_fe l, r, t; + rustsecp256k1_v0_11_fe l, r, t; - (var ? rustsecp256k1zkp_v0_8_0_fe_inv_var : rustsecp256k1zkp_v0_8_0_fe_inv)(&l, x) ; /* l = 1/x */ + (var ? rustsecp256k1_v0_11_fe_inv_var : rustsecp256k1_v0_11_fe_inv)(&l, x) ; /* l = 1/x */ if (out) *out = l; t = *x; /* t = x */ - if (rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(&t)) { - CHECK(rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(&l)); + if (rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&t)) { + CHECK(rustsecp256k1_v0_11_fe_normalizes_to_zero(&l)); return; } - rustsecp256k1zkp_v0_8_0_fe_mul(&t, x, &l); /* t = x*(1/x) */ - rustsecp256k1zkp_v0_8_0_fe_add(&t, &fe_minus_one); /* t = x*(1/x)-1 */ - CHECK(rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero(&t)); /* x*(1/x)-1 == 0 */ + rustsecp256k1_v0_11_fe_mul(&t, x, &l); /* t = x*(1/x) */ + rustsecp256k1_v0_11_fe_add(&t, &fe_minus_one); /* t = x*(1/x)-1 */ + CHECK(rustsecp256k1_v0_11_fe_normalizes_to_zero(&t)); /* x*(1/x)-1 == 0 */ r = *x; /* r = x */ - rustsecp256k1zkp_v0_8_0_fe_add(&r, &fe_minus_one); /* r = x-1 */ - if (rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(&r)) return; - (var ? rustsecp256k1zkp_v0_8_0_fe_inv_var : rustsecp256k1zkp_v0_8_0_fe_inv)(&r, &r); /* r = 1/(x-1) */ - rustsecp256k1zkp_v0_8_0_fe_add(&l, &fe_minus_one); /* l = 1/x-1 */ - (var ? rustsecp256k1zkp_v0_8_0_fe_inv_var : rustsecp256k1zkp_v0_8_0_fe_inv)(&l, &l); /* l = 1/(1/x-1) */ - rustsecp256k1zkp_v0_8_0_fe_add(&l, &rustsecp256k1zkp_v0_8_0_fe_one); /* l = 1/(1/x-1)+1 */ - rustsecp256k1zkp_v0_8_0_fe_add(&l, &r); /* l = 1/(1/x-1)+1 + 1/(x-1) */ - CHECK(rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(&l)); /* l == 0 */ + rustsecp256k1_v0_11_fe_add(&r, &fe_minus_one); /* r = x-1 */ + if (rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&r)) return; + (var ? rustsecp256k1_v0_11_fe_inv_var : rustsecp256k1_v0_11_fe_inv)(&r, &r); /* r = 1/(x-1) */ + rustsecp256k1_v0_11_fe_add(&l, &fe_minus_one); /* l = 1/x-1 */ + (var ? rustsecp256k1_v0_11_fe_inv_var : rustsecp256k1_v0_11_fe_inv)(&l, &l); /* l = 1/(1/x-1) */ + rustsecp256k1_v0_11_fe_add_int(&l, 1); /* l = 1/(1/x-1)+1 */ + rustsecp256k1_v0_11_fe_add(&l, &r); /* l = 1/(1/x-1)+1 + 1/(x-1) */ + CHECK(rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&l)); /* l == 0 */ } -void run_inverse_tests(void) +static void run_inverse_tests(void) { /* Fixed test cases for field inverses: pairs of (x, 1/x) mod p. */ - static const rustsecp256k1zkp_v0_8_0_fe fe_cases[][2] = { + static const rustsecp256k1_v0_11_fe fe_cases[][2] = { /* 0 */ {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}, @@ -3207,7 +3422,7 @@ void run_inverse_tests(void) SECP256K1_FE_CONST(0x9a94b9b5, 0x57eb71ee, 0x4c975b8b, 0xac5262a8, 0x077b0595, 0xe12a6b1f, 0xd728edef, 0x1a6bf956)} }; /* Fixed test cases for scalar inverses: pairs of (x, 1/x) mod n. */ - static const rustsecp256k1zkp_v0_8_0_scalar scalar_cases[][2] = { + static const rustsecp256k1_v0_11_scalar scalar_cases[][2] = { /* 0 */ {SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0)}, @@ -3294,38 +3509,38 @@ void run_inverse_tests(void) }; int i, var, testrand; unsigned char b32[32]; - rustsecp256k1zkp_v0_8_0_fe x_fe; - rustsecp256k1zkp_v0_8_0_scalar x_scalar; + rustsecp256k1_v0_11_fe x_fe; + rustsecp256k1_v0_11_scalar x_scalar; memset(b32, 0, sizeof(b32)); /* Test fixed test cases through test_inverse_{scalar,field}, both ways. */ for (i = 0; (size_t)i < sizeof(fe_cases)/sizeof(fe_cases[0]); ++i) { for (var = 0; var <= 1; ++var) { test_inverse_field(&x_fe, &fe_cases[i][0], var); - check_fe_equal(&x_fe, &fe_cases[i][1]); + CHECK(fe_equal(&x_fe, &fe_cases[i][1])); test_inverse_field(&x_fe, &fe_cases[i][1], var); - check_fe_equal(&x_fe, &fe_cases[i][0]); + CHECK(fe_equal(&x_fe, &fe_cases[i][0])); } } for (i = 0; (size_t)i < sizeof(scalar_cases)/sizeof(scalar_cases[0]); ++i) { for (var = 0; var <= 1; ++var) { test_inverse_scalar(&x_scalar, &scalar_cases[i][0], var); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&x_scalar, &scalar_cases[i][1])); + CHECK(rustsecp256k1_v0_11_scalar_eq(&x_scalar, &scalar_cases[i][1])); test_inverse_scalar(&x_scalar, &scalar_cases[i][1], var); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&x_scalar, &scalar_cases[i][0])); + CHECK(rustsecp256k1_v0_11_scalar_eq(&x_scalar, &scalar_cases[i][0])); } } /* Test inputs 0..999 and their respective negations. */ for (i = 0; i < 1000; ++i) { b32[31] = i & 0xff; b32[30] = (i >> 8) & 0xff; - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&x_scalar, b32, NULL); - rustsecp256k1zkp_v0_8_0_fe_set_b32(&x_fe, b32); + rustsecp256k1_v0_11_scalar_set_b32(&x_scalar, b32, NULL); + rustsecp256k1_v0_11_fe_set_b32_mod(&x_fe, b32); for (var = 0; var <= 1; ++var) { test_inverse_scalar(NULL, &x_scalar, var); test_inverse_field(NULL, &x_fe, var); } - rustsecp256k1zkp_v0_8_0_scalar_negate(&x_scalar, &x_scalar); - rustsecp256k1zkp_v0_8_0_fe_negate(&x_fe, &x_fe, 1); + rustsecp256k1_v0_11_scalar_negate(&x_scalar, &x_scalar); + rustsecp256k1_v0_11_fe_negate(&x_fe, &x_fe, 1); for (var = 0; var <= 1; ++var) { test_inverse_scalar(NULL, &x_scalar, var); test_inverse_field(NULL, &x_fe, var); @@ -3333,10 +3548,10 @@ void run_inverse_tests(void) } /* test 128*count random inputs; half with testrand256_test, half with testrand256 */ for (testrand = 0; testrand <= 1; ++testrand) { - for (i = 0; i < 64 * count; ++i) { - (testrand ? rustsecp256k1zkp_v0_8_0_testrand256_test : rustsecp256k1zkp_v0_8_0_testrand256)(b32); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&x_scalar, b32, NULL); - rustsecp256k1zkp_v0_8_0_fe_set_b32(&x_fe, b32); + for (i = 0; i < 64 * COUNT; ++i) { + (testrand ? testrand256_test : testrand256)(b32); + rustsecp256k1_v0_11_scalar_set_b32(&x_scalar, b32, NULL); + rustsecp256k1_v0_11_fe_set_b32_mod(&x_fe, b32); for (var = 0; var <= 1; ++var) { test_inverse_scalar(NULL, &x_scalar, var); test_inverse_field(NULL, &x_fe, var); @@ -3345,57 +3560,103 @@ void run_inverse_tests(void) } } -/***** GROUP TESTS *****/ +/***** HSORT TESTS *****/ -void ge_equals_ge(const rustsecp256k1zkp_v0_8_0_ge *a, const rustsecp256k1zkp_v0_8_0_ge *b) { - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; +static void test_heap_swap(void) { + unsigned char a[600]; + unsigned char e[sizeof(a)]; + memset(a, 21, 200); + memset(a + 200, 99, 200); + memset(a + 400, 42, 200); + memset(e, 42, 200); + memset(e + 200, 99, 200); + memset(e + 400, 21, 200); + rustsecp256k1_v0_11_heap_swap(a, 0, 2, 200); + CHECK(rustsecp256k1_v0_11_memcmp_var(a, e, sizeof(a)) == 0); +} + +static void test_hsort_is_sorted(unsigned char *elements, size_t n, size_t len) { + size_t i; + for (i = 1; i < n; i++) { + CHECK(rustsecp256k1_v0_11_memcmp_var(&elements[(i-1) * len], &elements[i * len], len) <= 0); } - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&a->x, &b->x)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&a->y, &b->y)); } +struct test_hsort_cmp_data { + size_t counter; + size_t element_len; +}; + + +static int test_hsort_cmp(const void *ele1, const void *ele2, void *data) { + struct test_hsort_cmp_data *d = (struct test_hsort_cmp_data *) data; + d->counter += 1; + return rustsecp256k1_v0_11_memcmp_var((unsigned char *)ele1, (unsigned char *)ele2, d->element_len); +} + +#define NUM 65 +#define MAX_ELEMENT_LEN 65 +static void test_hsort(size_t element_len) { + unsigned char elements[NUM * MAX_ELEMENT_LEN] = { 0 }; + struct test_hsort_cmp_data data; + int i; + + VERIFY_CHECK(element_len <= MAX_ELEMENT_LEN); + data.counter = 0; + data.element_len = element_len; + + rustsecp256k1_v0_11_hsort(elements, 0, element_len, test_hsort_cmp, &data); + CHECK(data.counter == 0); + rustsecp256k1_v0_11_hsort(elements, 1, element_len, test_hsort_cmp, &data); + CHECK(data.counter == 0); + rustsecp256k1_v0_11_hsort(elements, NUM, element_len, test_hsort_cmp, &data); + CHECK(data.counter >= NUM - 1); + test_hsort_is_sorted(elements, NUM, element_len); + + /* Test hsort with array of random length n */ + for (i = 0; i < COUNT; i++) { + int n = testrand_int(NUM); + testrand_bytes_test(elements, n*element_len); + rustsecp256k1_v0_11_hsort(elements, n, element_len, test_hsort_cmp, &data); + test_hsort_is_sorted(elements, n, element_len); + } +} +#undef NUM +#undef MAX_ELEMENT_LEN + + +static void run_hsort_tests(void) { + test_heap_swap(); + test_hsort(1); + test_hsort(64); + test_hsort(65); +} + +/***** GROUP TESTS *****/ + /* This compares jacobian points including their Z, not just their geometric meaning. */ -int gej_xyz_equals_gej(const rustsecp256k1zkp_v0_8_0_gej *a, const rustsecp256k1zkp_v0_8_0_gej *b) { - rustsecp256k1zkp_v0_8_0_gej a2; - rustsecp256k1zkp_v0_8_0_gej b2; +static int gej_xyz_equals_gej(const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_gej *b) { + rustsecp256k1_v0_11_gej a2; + rustsecp256k1_v0_11_gej b2; int ret = 1; ret &= a->infinity == b->infinity; if (ret && !a->infinity) { a2 = *a; b2 = *b; - rustsecp256k1zkp_v0_8_0_fe_normalize(&a2.x); - rustsecp256k1zkp_v0_8_0_fe_normalize(&a2.y); - rustsecp256k1zkp_v0_8_0_fe_normalize(&a2.z); - rustsecp256k1zkp_v0_8_0_fe_normalize(&b2.x); - rustsecp256k1zkp_v0_8_0_fe_normalize(&b2.y); - rustsecp256k1zkp_v0_8_0_fe_normalize(&b2.z); - ret &= rustsecp256k1zkp_v0_8_0_fe_cmp_var(&a2.x, &b2.x) == 0; - ret &= rustsecp256k1zkp_v0_8_0_fe_cmp_var(&a2.y, &b2.y) == 0; - ret &= rustsecp256k1zkp_v0_8_0_fe_cmp_var(&a2.z, &b2.z) == 0; + rustsecp256k1_v0_11_fe_normalize(&a2.x); + rustsecp256k1_v0_11_fe_normalize(&a2.y); + rustsecp256k1_v0_11_fe_normalize(&a2.z); + rustsecp256k1_v0_11_fe_normalize(&b2.x); + rustsecp256k1_v0_11_fe_normalize(&b2.y); + rustsecp256k1_v0_11_fe_normalize(&b2.z); + ret &= rustsecp256k1_v0_11_fe_cmp_var(&a2.x, &b2.x) == 0; + ret &= rustsecp256k1_v0_11_fe_cmp_var(&a2.y, &b2.y) == 0; + ret &= rustsecp256k1_v0_11_fe_cmp_var(&a2.z, &b2.z) == 0; } return ret; } -void ge_equals_gej(const rustsecp256k1zkp_v0_8_0_ge *a, const rustsecp256k1zkp_v0_8_0_gej *b) { - rustsecp256k1zkp_v0_8_0_fe z2s; - rustsecp256k1zkp_v0_8_0_fe u1, u2, s1, s2; - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; - } - /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ - rustsecp256k1zkp_v0_8_0_fe_sqr(&z2s, &b->z); - rustsecp256k1zkp_v0_8_0_fe_mul(&u1, &a->x, &z2s); - u2 = b->x; rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&u2); - rustsecp256k1zkp_v0_8_0_fe_mul(&s1, &a->y, &z2s); rustsecp256k1zkp_v0_8_0_fe_mul(&s1, &s1, &b->z); - s2 = b->y; rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&s2); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&u1, &u2)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&s1, &s2)); -} - -void test_ge(void) { +static void test_ge(void) { int i, i1; int runs = 6; /* 25 points are used: @@ -3404,230 +3665,263 @@ void test_ge(void) { * negation, and then those two again but with randomized Z coordinate. * - The same is then done for lambda*p1 and lambda^2*p1. */ - rustsecp256k1zkp_v0_8_0_ge *ge = (rustsecp256k1zkp_v0_8_0_ge *)checked_malloc(&ctx->error_callback, sizeof(rustsecp256k1zkp_v0_8_0_ge) * (1 + 4 * runs)); - rustsecp256k1zkp_v0_8_0_gej *gej = (rustsecp256k1zkp_v0_8_0_gej *)checked_malloc(&ctx->error_callback, sizeof(rustsecp256k1zkp_v0_8_0_gej) * (1 + 4 * runs)); - rustsecp256k1zkp_v0_8_0_fe zf; - rustsecp256k1zkp_v0_8_0_fe zfi2, zfi3; - - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&gej[0]); - rustsecp256k1zkp_v0_8_0_ge_clear(&ge[0]); - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&ge[0], &gej[0]); + rustsecp256k1_v0_11_ge *ge = (rustsecp256k1_v0_11_ge *)checked_malloc(&CTX->error_callback, sizeof(rustsecp256k1_v0_11_ge) * (1 + 4 * runs)); + rustsecp256k1_v0_11_gej *gej = (rustsecp256k1_v0_11_gej *)checked_malloc(&CTX->error_callback, sizeof(rustsecp256k1_v0_11_gej) * (1 + 4 * runs)); + rustsecp256k1_v0_11_fe zf, r; + rustsecp256k1_v0_11_fe zfi2, zfi3; + + rustsecp256k1_v0_11_gej_set_infinity(&gej[0]); + rustsecp256k1_v0_11_ge_set_infinity(&ge[0]); for (i = 0; i < runs; i++) { - int j; - rustsecp256k1zkp_v0_8_0_ge g; - random_group_element_test(&g); + int j, k; + rustsecp256k1_v0_11_ge g; + testutil_random_ge_test(&g); if (i >= runs - 2) { - rustsecp256k1zkp_v0_8_0_ge_mul_lambda(&g, &ge[1]); + rustsecp256k1_v0_11_ge_mul_lambda(&g, &ge[1]); + CHECK(!rustsecp256k1_v0_11_ge_eq_var(&g, &ge[1])); } if (i >= runs - 1) { - rustsecp256k1zkp_v0_8_0_ge_mul_lambda(&g, &g); + rustsecp256k1_v0_11_ge_mul_lambda(&g, &g); } ge[1 + 4 * i] = g; ge[2 + 4 * i] = g; - rustsecp256k1zkp_v0_8_0_ge_neg(&ge[3 + 4 * i], &g); - rustsecp256k1zkp_v0_8_0_ge_neg(&ge[4 + 4 * i], &g); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&gej[1 + 4 * i], &ge[1 + 4 * i]); - random_group_element_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]); - random_group_element_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); + rustsecp256k1_v0_11_ge_neg(&ge[3 + 4 * i], &g); + rustsecp256k1_v0_11_ge_neg(&ge[4 + 4 * i], &g); + rustsecp256k1_v0_11_gej_set_ge(&gej[1 + 4 * i], &ge[1 + 4 * i]); + testutil_random_ge_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]); + rustsecp256k1_v0_11_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]); + testutil_random_ge_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); for (j = 0; j < 4; j++) { - random_field_element_magnitude(&ge[1 + j + 4 * i].x); - random_field_element_magnitude(&ge[1 + j + 4 * i].y); - random_field_element_magnitude(&gej[1 + j + 4 * i].x); - random_field_element_magnitude(&gej[1 + j + 4 * i].y); - random_field_element_magnitude(&gej[1 + j + 4 * i].z); + testutil_random_ge_x_magnitude(&ge[1 + j + 4 * i]); + testutil_random_ge_y_magnitude(&ge[1 + j + 4 * i]); + testutil_random_gej_x_magnitude(&gej[1 + j + 4 * i]); + testutil_random_gej_y_magnitude(&gej[1 + j + 4 * i]); + testutil_random_gej_z_magnitude(&gej[1 + j + 4 * i]); + } + + for (j = 0; j < 4; ++j) { + for (k = 0; k < 4; ++k) { + int expect_equal = (j >> 1) == (k >> 1); + CHECK(rustsecp256k1_v0_11_ge_eq_var(&ge[1 + j + 4 * i], &ge[1 + k + 4 * i]) == expect_equal); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&gej[1 + j + 4 * i], &gej[1 + k + 4 * i]) == expect_equal); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&gej[1 + j + 4 * i], &ge[1 + k + 4 * i]) == expect_equal); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&gej[1 + k + 4 * i], &ge[1 + j + 4 * i]) == expect_equal); + } } } /* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */ - do { - random_field_element_test(&zf); - } while(rustsecp256k1zkp_v0_8_0_fe_is_zero(&zf)); - random_field_element_magnitude(&zf); - rustsecp256k1zkp_v0_8_0_fe_inv_var(&zfi3, &zf); - rustsecp256k1zkp_v0_8_0_fe_sqr(&zfi2, &zfi3); - rustsecp256k1zkp_v0_8_0_fe_mul(&zfi3, &zfi3, &zfi2); + testutil_random_fe_non_zero_test(&zf); + testutil_random_fe_magnitude(&zf, 8); + rustsecp256k1_v0_11_fe_inv_var(&zfi3, &zf); + rustsecp256k1_v0_11_fe_sqr(&zfi2, &zfi3); + rustsecp256k1_v0_11_fe_mul(&zfi3, &zfi3, &zfi2); + + /* Generate random r */ + testutil_random_fe_non_zero_test(&r); for (i1 = 0; i1 < 1 + 4 * runs; i1++) { int i2; for (i2 = 0; i2 < 1 + 4 * runs; i2++) { /* Compute reference result using gej + gej (var). */ - rustsecp256k1zkp_v0_8_0_gej refj, resj; - rustsecp256k1zkp_v0_8_0_ge ref; - rustsecp256k1zkp_v0_8_0_fe zr; - rustsecp256k1zkp_v0_8_0_gej_add_var(&refj, &gej[i1], &gej[i2], rustsecp256k1zkp_v0_8_0_gej_is_infinity(&gej[i1]) ? NULL : &zr); + rustsecp256k1_v0_11_gej refj, resj; + rustsecp256k1_v0_11_ge ref; + rustsecp256k1_v0_11_fe zr; + rustsecp256k1_v0_11_gej_add_var(&refj, &gej[i1], &gej[i2], rustsecp256k1_v0_11_gej_is_infinity(&gej[i1]) ? NULL : &zr); /* Check Z ratio. */ - if (!rustsecp256k1zkp_v0_8_0_gej_is_infinity(&gej[i1]) && !rustsecp256k1zkp_v0_8_0_gej_is_infinity(&refj)) { - rustsecp256k1zkp_v0_8_0_fe zrz; rustsecp256k1zkp_v0_8_0_fe_mul(&zrz, &zr, &gej[i1].z); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&zrz, &refj.z)); + if (!rustsecp256k1_v0_11_gej_is_infinity(&gej[i1]) && !rustsecp256k1_v0_11_gej_is_infinity(&refj)) { + rustsecp256k1_v0_11_fe zrz; rustsecp256k1_v0_11_fe_mul(&zrz, &zr, &gej[i1].z); + CHECK(rustsecp256k1_v0_11_fe_equal(&zrz, &refj.z)); } - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&ref, &refj); + rustsecp256k1_v0_11_ge_set_gej_var(&ref, &refj); /* Test gej + ge with Z ratio result (var). */ - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&resj, &gej[i1], &ge[i2], rustsecp256k1zkp_v0_8_0_gej_is_infinity(&gej[i1]) ? NULL : &zr); - ge_equals_gej(&ref, &resj); - if (!rustsecp256k1zkp_v0_8_0_gej_is_infinity(&gej[i1]) && !rustsecp256k1zkp_v0_8_0_gej_is_infinity(&resj)) { - rustsecp256k1zkp_v0_8_0_fe zrz; rustsecp256k1zkp_v0_8_0_fe_mul(&zrz, &zr, &gej[i1].z); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&zrz, &resj.z)); + rustsecp256k1_v0_11_gej_add_ge_var(&resj, &gej[i1], &ge[i2], rustsecp256k1_v0_11_gej_is_infinity(&gej[i1]) ? NULL : &zr); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&resj, &ref)); + if (!rustsecp256k1_v0_11_gej_is_infinity(&gej[i1]) && !rustsecp256k1_v0_11_gej_is_infinity(&resj)) { + rustsecp256k1_v0_11_fe zrz; rustsecp256k1_v0_11_fe_mul(&zrz, &zr, &gej[i1].z); + CHECK(rustsecp256k1_v0_11_fe_equal(&zrz, &resj.z)); } /* Test gej + ge (var, with additional Z factor). */ { - rustsecp256k1zkp_v0_8_0_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */ - rustsecp256k1zkp_v0_8_0_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2); - rustsecp256k1zkp_v0_8_0_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3); - random_field_element_magnitude(&ge2_zfi.x); - random_field_element_magnitude(&ge2_zfi.y); - rustsecp256k1zkp_v0_8_0_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf); - ge_equals_gej(&ref, &resj); + rustsecp256k1_v0_11_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */ + rustsecp256k1_v0_11_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2); + rustsecp256k1_v0_11_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3); + testutil_random_ge_x_magnitude(&ge2_zfi); + testutil_random_ge_y_magnitude(&ge2_zfi); + rustsecp256k1_v0_11_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&resj, &ref)); } /* Test gej + ge (const). */ if (i2 != 0) { - /* rustsecp256k1zkp_v0_8_0_gej_add_ge does not support its second argument being infinity. */ - rustsecp256k1zkp_v0_8_0_gej_add_ge(&resj, &gej[i1], &ge[i2]); - ge_equals_gej(&ref, &resj); + /* rustsecp256k1_v0_11_gej_add_ge does not support its second argument being infinity. */ + rustsecp256k1_v0_11_gej_add_ge(&resj, &gej[i1], &ge[i2]); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&resj, &ref)); } /* Test doubling (var). */ if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 == ((i2 + 3)%4)/2)) { - rustsecp256k1zkp_v0_8_0_fe zr2; + rustsecp256k1_v0_11_fe zr2; /* Normal doubling with Z ratio result. */ - rustsecp256k1zkp_v0_8_0_gej_double_var(&resj, &gej[i1], &zr2); - ge_equals_gej(&ref, &resj); + rustsecp256k1_v0_11_gej_double_var(&resj, &gej[i1], &zr2); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&resj, &ref)); /* Check Z ratio. */ - rustsecp256k1zkp_v0_8_0_fe_mul(&zr2, &zr2, &gej[i1].z); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&zr2, &resj.z)); + rustsecp256k1_v0_11_fe_mul(&zr2, &zr2, &gej[i1].z); + CHECK(rustsecp256k1_v0_11_fe_equal(&zr2, &resj.z)); /* Normal doubling. */ - rustsecp256k1zkp_v0_8_0_gej_double_var(&resj, &gej[i2], NULL); - ge_equals_gej(&ref, &resj); + rustsecp256k1_v0_11_gej_double_var(&resj, &gej[i2], NULL); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&resj, &ref)); /* Constant-time doubling. */ - rustsecp256k1zkp_v0_8_0_gej_double(&resj, &gej[i2]); - ge_equals_gej(&ref, &resj); + rustsecp256k1_v0_11_gej_double(&resj, &gej[i2]); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&resj, &ref)); } /* Test adding opposites. */ if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 != ((i2 + 3)%4)/2)) { - CHECK(rustsecp256k1zkp_v0_8_0_ge_is_infinity(&ref)); + CHECK(rustsecp256k1_v0_11_ge_is_infinity(&ref)); } /* Test adding infinity. */ if (i1 == 0) { - CHECK(rustsecp256k1zkp_v0_8_0_ge_is_infinity(&ge[i1])); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&gej[i1])); - ge_equals_gej(&ref, &gej[i2]); + CHECK(rustsecp256k1_v0_11_ge_is_infinity(&ge[i1])); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&gej[i1])); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&gej[i2], &ref)); } if (i2 == 0) { - CHECK(rustsecp256k1zkp_v0_8_0_ge_is_infinity(&ge[i2])); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&gej[i2])); - ge_equals_gej(&ref, &gej[i1]); + CHECK(rustsecp256k1_v0_11_ge_is_infinity(&ge[i2])); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&gej[i2])); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&gej[i1], &ref)); } } } /* Test adding all points together in random order equals infinity. */ { - rustsecp256k1zkp_v0_8_0_gej sum = SECP256K1_GEJ_CONST_INFINITY; - rustsecp256k1zkp_v0_8_0_gej *gej_shuffled = (rustsecp256k1zkp_v0_8_0_gej *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(rustsecp256k1zkp_v0_8_0_gej)); + rustsecp256k1_v0_11_gej sum = SECP256K1_GEJ_CONST_INFINITY; + rustsecp256k1_v0_11_gej *gej_shuffled = (rustsecp256k1_v0_11_gej *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(rustsecp256k1_v0_11_gej)); for (i = 0; i < 4 * runs + 1; i++) { gej_shuffled[i] = gej[i]; } for (i = 0; i < 4 * runs + 1; i++) { - int swap = i + rustsecp256k1zkp_v0_8_0_testrand_int(4 * runs + 1 - i); + int swap = i + testrand_int(4 * runs + 1 - i); if (swap != i) { - rustsecp256k1zkp_v0_8_0_gej t = gej_shuffled[i]; + rustsecp256k1_v0_11_gej t = gej_shuffled[i]; gej_shuffled[i] = gej_shuffled[swap]; gej_shuffled[swap] = t; } } for (i = 0; i < 4 * runs + 1; i++) { - rustsecp256k1zkp_v0_8_0_gej_add_var(&sum, &sum, &gej_shuffled[i], NULL); + rustsecp256k1_v0_11_gej_add_var(&sum, &sum, &gej_shuffled[i], NULL); } - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&sum)); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&sum)); free(gej_shuffled); } /* Test batch gej -> ge conversion without known z ratios. */ { - rustsecp256k1zkp_v0_8_0_ge *ge_set_all = (rustsecp256k1zkp_v0_8_0_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(rustsecp256k1zkp_v0_8_0_ge)); - rustsecp256k1zkp_v0_8_0_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1); + rustsecp256k1_v0_11_ge *ge_set_all = (rustsecp256k1_v0_11_ge *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(rustsecp256k1_v0_11_ge)); + rustsecp256k1_v0_11_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1); for (i = 0; i < 4 * runs + 1; i++) { - rustsecp256k1zkp_v0_8_0_fe s; - random_fe_non_zero(&s); - rustsecp256k1zkp_v0_8_0_gej_rescale(&gej[i], &s); - ge_equals_gej(&ge_set_all[i], &gej[i]); + rustsecp256k1_v0_11_fe s; + testutil_random_fe_non_zero(&s); + rustsecp256k1_v0_11_gej_rescale(&gej[i], &s); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&gej[i], &ge_set_all[i])); } free(ge_set_all); } + /* Test that all elements have X coordinates on the curve. */ + for (i = 1; i < 4 * runs + 1; i++) { + rustsecp256k1_v0_11_fe n; + CHECK(rustsecp256k1_v0_11_ge_x_on_curve_var(&ge[i].x)); + /* And the same holds after random rescaling. */ + rustsecp256k1_v0_11_fe_mul(&n, &zf, &ge[i].x); + CHECK(rustsecp256k1_v0_11_ge_x_frac_on_curve_var(&n, &zf)); + } + + /* Test correspondence of rustsecp256k1_v0_11_ge_x{,_frac}_on_curve_var with ge_set_xo. */ + { + rustsecp256k1_v0_11_fe n; + rustsecp256k1_v0_11_ge q; + int ret_on_curve, ret_frac_on_curve, ret_set_xo; + rustsecp256k1_v0_11_fe_mul(&n, &zf, &r); + ret_on_curve = rustsecp256k1_v0_11_ge_x_on_curve_var(&r); + ret_frac_on_curve = rustsecp256k1_v0_11_ge_x_frac_on_curve_var(&n, &zf); + ret_set_xo = rustsecp256k1_v0_11_ge_set_xo_var(&q, &r, 0); + CHECK(ret_on_curve == ret_frac_on_curve); + CHECK(ret_on_curve == ret_set_xo); + if (ret_set_xo) CHECK(rustsecp256k1_v0_11_fe_equal(&r, &q.x)); + } + /* Test batch gej -> ge conversion with many infinities. */ for (i = 0; i < 4 * runs + 1; i++) { int odd; - random_group_element_test(&ge[i]); - odd = rustsecp256k1zkp_v0_8_0_fe_is_odd(&ge[i].x); + testutil_random_ge_test(&ge[i]); + odd = rustsecp256k1_v0_11_fe_is_odd(&ge[i].x); CHECK(odd == 0 || odd == 1); /* randomly set half the points to infinity */ if (odd == i % 2) { - rustsecp256k1zkp_v0_8_0_ge_set_infinity(&ge[i]); + rustsecp256k1_v0_11_ge_set_infinity(&ge[i]); } - rustsecp256k1zkp_v0_8_0_gej_set_ge(&gej[i], &ge[i]); + rustsecp256k1_v0_11_gej_set_ge(&gej[i], &ge[i]); } /* batch convert */ - rustsecp256k1zkp_v0_8_0_ge_set_all_gej_var(ge, gej, 4 * runs + 1); + rustsecp256k1_v0_11_ge_set_all_gej_var(ge, gej, 4 * runs + 1); /* check result */ for (i = 0; i < 4 * runs + 1; i++) { - ge_equals_gej(&ge[i], &gej[i]); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&gej[i], &ge[i])); } /* Test batch gej -> ge conversion with all infinities. */ for (i = 0; i < 4 * runs + 1; i++) { - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&gej[i]); + rustsecp256k1_v0_11_gej_set_infinity(&gej[i]); } /* batch convert */ - rustsecp256k1zkp_v0_8_0_ge_set_all_gej_var(ge, gej, 4 * runs + 1); + rustsecp256k1_v0_11_ge_set_all_gej_var(ge, gej, 4 * runs + 1); /* check result */ for (i = 0; i < 4 * runs + 1; i++) { - CHECK(rustsecp256k1zkp_v0_8_0_ge_is_infinity(&ge[i])); + CHECK(rustsecp256k1_v0_11_ge_is_infinity(&ge[i])); } free(ge); free(gej); } - -void test_intialized_inf(void) { - rustsecp256k1zkp_v0_8_0_ge p; - rustsecp256k1zkp_v0_8_0_gej pj, npj, infj1, infj2, infj3; - rustsecp256k1zkp_v0_8_0_fe zinv; +static void test_intialized_inf(void) { + rustsecp256k1_v0_11_ge p; + rustsecp256k1_v0_11_gej pj, npj, infj1, infj2, infj3; + rustsecp256k1_v0_11_fe zinv; /* Test that adding P+(-P) results in a fully initialized infinity*/ - random_group_element_test(&p); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&pj, &p); - rustsecp256k1zkp_v0_8_0_gej_neg(&npj, &pj); + testutil_random_ge_test(&p); + rustsecp256k1_v0_11_gej_set_ge(&pj, &p); + rustsecp256k1_v0_11_gej_neg(&npj, &pj); - rustsecp256k1zkp_v0_8_0_gej_add_var(&infj1, &pj, &npj, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&infj1)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_is_zero(&infj1.x)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_is_zero(&infj1.y)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_is_zero(&infj1.z)); + rustsecp256k1_v0_11_gej_add_var(&infj1, &pj, &npj, NULL); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&infj1)); + CHECK(rustsecp256k1_v0_11_fe_is_zero(&infj1.x)); + CHECK(rustsecp256k1_v0_11_fe_is_zero(&infj1.y)); + CHECK(rustsecp256k1_v0_11_fe_is_zero(&infj1.z)); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&infj2, &npj, &p, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&infj2)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_is_zero(&infj2.x)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_is_zero(&infj2.y)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_is_zero(&infj2.z)); + rustsecp256k1_v0_11_gej_add_ge_var(&infj2, &npj, &p, NULL); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&infj2)); + CHECK(rustsecp256k1_v0_11_fe_is_zero(&infj2.x)); + CHECK(rustsecp256k1_v0_11_fe_is_zero(&infj2.y)); + CHECK(rustsecp256k1_v0_11_fe_is_zero(&infj2.z)); - rustsecp256k1zkp_v0_8_0_fe_set_int(&zinv, 1); - rustsecp256k1zkp_v0_8_0_gej_add_zinv_var(&infj3, &npj, &p, &zinv); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&infj3)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_is_zero(&infj3.x)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_is_zero(&infj3.y)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_is_zero(&infj3.z)); + rustsecp256k1_v0_11_fe_set_int(&zinv, 1); + rustsecp256k1_v0_11_gej_add_zinv_var(&infj3, &npj, &p, &zinv); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&infj3)); + CHECK(rustsecp256k1_v0_11_fe_is_zero(&infj3.x)); + CHECK(rustsecp256k1_v0_11_fe_is_zero(&infj3.y)); + CHECK(rustsecp256k1_v0_11_fe_is_zero(&infj3.z)); } -void test_add_neg_y_diff_x(void) { +static void test_add_neg_y_diff_x(void) { /* The point of this test is to check that we can add two points * whose y-coordinates are negatives of each other but whose x * coordinates differ. If the x-coordinates were the same, these @@ -3641,284 +3935,213 @@ void test_add_neg_y_diff_x(void) { * which this test is a regression test for. * * These points were generated in sage as - * # secp256k1 params - * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) - * C = EllipticCurve ([F (0), F (7)]) - * G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) - * N = FiniteField(G.order()) * - * # endomorphism values (lambda is 1^{1/3} in N, beta is 1^{1/3} in F) - * x = polygen(N) - * lam = (1 - x^3).roots()[1][0] + * load("rustsecp256k1_v0_11_params.sage") * * # random "bad pair" * P = C.random_element() - * Q = -int(lam) * P - * print " P: %x %x" % P.xy() - * print " Q: %x %x" % Q.xy() - * print "P + Q: %x %x" % (P + Q).xy() + * Q = -int(LAMBDA) * P + * print(" P: %x %x" % P.xy()) + * print(" Q: %x %x" % Q.xy()) + * print("P + Q: %x %x" % (P + Q).xy()) */ - rustsecp256k1zkp_v0_8_0_gej aj = SECP256K1_GEJ_CONST( + rustsecp256k1_v0_11_gej aj = SECP256K1_GEJ_CONST( 0x8d24cd95, 0x0a355af1, 0x3c543505, 0x44238d30, 0x0643d79f, 0x05a59614, 0x2f8ec030, 0xd58977cb, 0x001e337a, 0x38093dcd, 0x6c0f386d, 0x0b1293a8, 0x4d72c879, 0xd7681924, 0x44e6d2f3, 0x9190117d ); - rustsecp256k1zkp_v0_8_0_gej bj = SECP256K1_GEJ_CONST( + rustsecp256k1_v0_11_gej bj = SECP256K1_GEJ_CONST( 0xc7b74206, 0x1f788cd9, 0xabd0937d, 0x164a0d86, 0x95f6ff75, 0xf19a4ce9, 0xd013bd7b, 0xbf92d2a7, 0xffe1cc85, 0xc7f6c232, 0x93f0c792, 0xf4ed6c57, 0xb28d3786, 0x2897e6db, 0xbb192d0b, 0x6e6feab2 ); - rustsecp256k1zkp_v0_8_0_gej sumj = SECP256K1_GEJ_CONST( + rustsecp256k1_v0_11_gej sumj = SECP256K1_GEJ_CONST( 0x671a63c0, 0x3efdad4c, 0x389a7798, 0x24356027, 0xb3d69010, 0x278625c3, 0x5c86d390, 0x184a8f7a, 0x5f6409c2, 0x2ce01f2b, 0x511fd375, 0x25071d08, 0xda651801, 0x70e95caf, 0x8f0d893c, 0xbed8fbbe ); - rustsecp256k1zkp_v0_8_0_ge b; - rustsecp256k1zkp_v0_8_0_gej resj; - rustsecp256k1zkp_v0_8_0_ge res; - rustsecp256k1zkp_v0_8_0_ge_set_gej(&b, &bj); + rustsecp256k1_v0_11_ge b; + rustsecp256k1_v0_11_gej resj; + rustsecp256k1_v0_11_ge res; + rustsecp256k1_v0_11_ge_set_gej(&b, &bj); + + rustsecp256k1_v0_11_gej_add_var(&resj, &aj, &bj, NULL); + rustsecp256k1_v0_11_ge_set_gej(&res, &resj); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&sumj, &res)); + + rustsecp256k1_v0_11_gej_add_ge(&resj, &aj, &b); + rustsecp256k1_v0_11_ge_set_gej(&res, &resj); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&sumj, &res)); + + rustsecp256k1_v0_11_gej_add_ge_var(&resj, &aj, &b, NULL); + rustsecp256k1_v0_11_ge_set_gej(&res, &resj); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&sumj, &res)); +} - rustsecp256k1zkp_v0_8_0_gej_add_var(&resj, &aj, &bj, NULL); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&res, &resj); - ge_equals_gej(&res, &sumj); +static void test_ge_bytes(void) { + int i; + + for (i = 0; i < COUNT + 1; i++) { + unsigned char buf[64]; + rustsecp256k1_v0_11_ge p, q; + + if (i == 0) { + rustsecp256k1_v0_11_ge_set_infinity(&p); + } else { + testutil_random_ge_test(&p); + } + + if (!rustsecp256k1_v0_11_ge_is_infinity(&p)) { + rustsecp256k1_v0_11_ge_to_bytes(buf, &p); - rustsecp256k1zkp_v0_8_0_gej_add_ge(&resj, &aj, &b); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&res, &resj); - ge_equals_gej(&res, &sumj); + rustsecp256k1_v0_11_ge_from_bytes(&q, buf); + CHECK(rustsecp256k1_v0_11_ge_eq_var(&p, &q)); - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&resj, &aj, &b, NULL); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&res, &resj); - ge_equals_gej(&res, &sumj); + rustsecp256k1_v0_11_ge_from_bytes_ext(&q, buf); + CHECK(rustsecp256k1_v0_11_ge_eq_var(&p, &q)); + } + rustsecp256k1_v0_11_ge_to_bytes_ext(buf, &p); + rustsecp256k1_v0_11_ge_from_bytes_ext(&q, buf); + CHECK(rustsecp256k1_v0_11_ge_eq_var(&p, &q)); + } } -void run_ge(void) { +static void run_ge(void) { int i; - for (i = 0; i < count * 32; i++) { + for (i = 0; i < COUNT * 32; i++) { test_ge(); } test_add_neg_y_diff_x(); test_intialized_inf(); + test_ge_bytes(); } -void test_gej_cmov(const rustsecp256k1zkp_v0_8_0_gej *a, const rustsecp256k1zkp_v0_8_0_gej *b) { - rustsecp256k1zkp_v0_8_0_gej t = *a; - rustsecp256k1zkp_v0_8_0_gej_cmov(&t, b, 0); +static void test_gej_cmov(const rustsecp256k1_v0_11_gej *a, const rustsecp256k1_v0_11_gej *b) { + rustsecp256k1_v0_11_gej t = *a; + rustsecp256k1_v0_11_gej_cmov(&t, b, 0); CHECK(gej_xyz_equals_gej(&t, a)); - rustsecp256k1zkp_v0_8_0_gej_cmov(&t, b, 1); + rustsecp256k1_v0_11_gej_cmov(&t, b, 1); CHECK(gej_xyz_equals_gej(&t, b)); } -void run_gej(void) { +static void run_gej(void) { int i; - rustsecp256k1zkp_v0_8_0_gej a, b; + rustsecp256k1_v0_11_gej a, b; - /* Tests for rustsecp256k1zkp_v0_8_0_gej_cmov */ - for (i = 0; i < count; i++) { - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&a); - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&b); + /* Tests for rustsecp256k1_v0_11_gej_cmov */ + for (i = 0; i < COUNT; i++) { + rustsecp256k1_v0_11_gej_set_infinity(&a); + rustsecp256k1_v0_11_gej_set_infinity(&b); test_gej_cmov(&a, &b); - random_gej_test(&a); + testutil_random_gej_test(&a); test_gej_cmov(&a, &b); test_gej_cmov(&b, &a); b = a; test_gej_cmov(&a, &b); - random_gej_test(&b); + testutil_random_gej_test(&b); test_gej_cmov(&a, &b); test_gej_cmov(&b, &a); } + + /* Tests for rustsecp256k1_v0_11_gej_eq_var */ + for (i = 0; i < COUNT; i++) { + rustsecp256k1_v0_11_fe fe; + testutil_random_gej_test(&a); + testutil_random_gej_test(&b); + CHECK(!rustsecp256k1_v0_11_gej_eq_var(&a, &b)); + + b = a; + testutil_random_fe_non_zero_test(&fe); + rustsecp256k1_v0_11_gej_rescale(&a, &fe); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&a, &b)); + } } -void test_ec_combine(void) { - rustsecp256k1zkp_v0_8_0_scalar sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - rustsecp256k1zkp_v0_8_0_pubkey data[6]; - const rustsecp256k1zkp_v0_8_0_pubkey* d[6]; - rustsecp256k1zkp_v0_8_0_pubkey sd; - rustsecp256k1zkp_v0_8_0_pubkey sd2; - rustsecp256k1zkp_v0_8_0_gej Qj; - rustsecp256k1zkp_v0_8_0_ge Q; +static void test_ec_combine(void) { + rustsecp256k1_v0_11_scalar sum = rustsecp256k1_v0_11_scalar_zero; + rustsecp256k1_v0_11_pubkey data[6]; + const rustsecp256k1_v0_11_pubkey* d[6]; + rustsecp256k1_v0_11_pubkey sd; + rustsecp256k1_v0_11_pubkey sd2; + rustsecp256k1_v0_11_gej Qj; + rustsecp256k1_v0_11_ge Q; int i; for (i = 1; i <= 6; i++) { - rustsecp256k1zkp_v0_8_0_scalar s; - random_scalar_order_test(&s); - rustsecp256k1zkp_v0_8_0_scalar_add(&sum, &sum, &s); - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &s); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&Q, &Qj); - rustsecp256k1zkp_v0_8_0_pubkey_save(&data[i - 1], &Q); + rustsecp256k1_v0_11_scalar s; + testutil_random_scalar_order_test(&s); + rustsecp256k1_v0_11_scalar_add(&sum, &sum, &s); + rustsecp256k1_v0_11_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &s); + rustsecp256k1_v0_11_ge_set_gej(&Q, &Qj); + rustsecp256k1_v0_11_pubkey_save(&data[i - 1], &Q); d[i - 1] = &data[i - 1]; - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sum); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&Q, &Qj); - rustsecp256k1zkp_v0_8_0_pubkey_save(&sd, &Q); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_combine(ctx, &sd2, d, i) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&sd, &sd2, sizeof(sd)) == 0); + rustsecp256k1_v0_11_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &sum); + rustsecp256k1_v0_11_ge_set_gej(&Q, &Qj); + rustsecp256k1_v0_11_pubkey_save(&sd, &Q); + CHECK(rustsecp256k1_v0_11_ec_pubkey_combine(CTX, &sd2, d, i) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&sd, &sd2, sizeof(sd)) == 0); } } -void run_ec_combine(void) { +static void run_ec_combine(void) { int i; - for (i = 0; i < count * 8; i++) { + for (i = 0; i < COUNT * 8; i++) { test_ec_combine(); } } -void test_ec_commit(void) { - rustsecp256k1zkp_v0_8_0_scalar seckey_s; - rustsecp256k1zkp_v0_8_0_ge pubkey; - rustsecp256k1zkp_v0_8_0_gej pubkeyj; - rustsecp256k1zkp_v0_8_0_ge commitment; - unsigned char data[32]; - rustsecp256k1zkp_v0_8_0_sha256 sha; - - /* Create random keypair and data */ - random_scalar_order_test(&seckey_s); - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj, &seckey_s); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&pubkey, &pubkeyj); - rustsecp256k1zkp_v0_8_0_testrand256_test(data); - - /* Commit to data and verify */ - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - CHECK(rustsecp256k1zkp_v0_8_0_ec_commit(&commitment, &pubkey, &sha, data, 32) == 1); - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - CHECK(rustsecp256k1zkp_v0_8_0_ec_commit_verify(&commitment, &pubkey, &sha, data, 32) == 1); - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - CHECK(rustsecp256k1zkp_v0_8_0_ec_commit_seckey(&seckey_s, &pubkey, &sha, data, 32) == 1); - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj, &seckey_s); - ge_equals_gej(&commitment, &pubkeyj); - - /* Check that verification fails with different data */ - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - CHECK(rustsecp256k1zkp_v0_8_0_ec_commit_verify(&commitment, &pubkey, &sha, data, 31) == 0); - - /* Check that commmitting fails when the inner pubkey is the point at - * infinity */ - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - rustsecp256k1zkp_v0_8_0_ge_set_infinity(&pubkey); - CHECK(rustsecp256k1zkp_v0_8_0_ec_commit(&commitment, &pubkey, &sha, data, 32) == 0); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&seckey_s, 0); - CHECK(rustsecp256k1zkp_v0_8_0_ec_commit_seckey(&seckey_s, &pubkey, &sha, data, 32) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ec_commit_verify(&commitment, &pubkey, &sha, data, 32) == 0); -} - -void test_ec_commit_api(void) { - unsigned char seckey[32]; - rustsecp256k1zkp_v0_8_0_scalar seckey_s; - rustsecp256k1zkp_v0_8_0_ge pubkey; - rustsecp256k1zkp_v0_8_0_gej pubkeyj; - rustsecp256k1zkp_v0_8_0_ge commitment; - unsigned char data[32]; - rustsecp256k1zkp_v0_8_0_sha256 sha; - - memset(data, 23, sizeof(data)); - - /* Create random keypair */ - random_scalar_order_test(&seckey_s); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(seckey, &seckey_s); - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj, &seckey_s); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&pubkey, &pubkeyj); - - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - CHECK(rustsecp256k1zkp_v0_8_0_ec_commit(&commitment, &pubkey, &sha, data, 1) == 1); - /* The same pubkey can be both input and output of the function */ - { - rustsecp256k1zkp_v0_8_0_ge pubkey_tmp = pubkey; - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - CHECK(rustsecp256k1zkp_v0_8_0_ec_commit(&pubkey_tmp, &pubkey_tmp, &sha, data, 1) == 1); - ge_equals_ge(&commitment, &pubkey_tmp); - } - - rustsecp256k1zkp_v0_8_0_sha256_initialize(&sha); - CHECK(rustsecp256k1zkp_v0_8_0_ec_commit_verify(&commitment, &pubkey, &sha, data, 1) == 1); -} - -void run_ec_commit(void) { - int i; - for (i = 0; i < count * 8; i++) { - test_ec_commit(); - } - test_ec_commit_api(); -} - -void test_group_decompress(const rustsecp256k1zkp_v0_8_0_fe* x) { +static void test_group_decompress(const rustsecp256k1_v0_11_fe* x) { /* The input itself, normalized. */ - rustsecp256k1zkp_v0_8_0_fe fex = *x; - rustsecp256k1zkp_v0_8_0_fe fez; - /* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */ - rustsecp256k1zkp_v0_8_0_ge ge_quad, ge_even, ge_odd; - rustsecp256k1zkp_v0_8_0_gej gej_quad; + rustsecp256k1_v0_11_fe fex = *x; + /* Results of set_xo_var(..., 0), set_xo_var(..., 1). */ + rustsecp256k1_v0_11_ge ge_even, ge_odd; /* Return values of the above calls. */ - int res_quad, res_even, res_odd; + int res_even, res_odd; - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&fex); + rustsecp256k1_v0_11_fe_normalize_var(&fex); - res_quad = rustsecp256k1zkp_v0_8_0_ge_set_xquad(&ge_quad, &fex); - res_even = rustsecp256k1zkp_v0_8_0_ge_set_xo_var(&ge_even, &fex, 0); - res_odd = rustsecp256k1zkp_v0_8_0_ge_set_xo_var(&ge_odd, &fex, 1); + res_even = rustsecp256k1_v0_11_ge_set_xo_var(&ge_even, &fex, 0); + res_odd = rustsecp256k1_v0_11_ge_set_xo_var(&ge_odd, &fex, 1); - CHECK(res_quad == res_even); - CHECK(res_quad == res_odd); + CHECK(res_even == res_odd); - if (res_quad) { - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge_quad.x); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge_odd.x); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge_even.x); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge_quad.y); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge_odd.y); - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&ge_even.y); + if (res_even) { + rustsecp256k1_v0_11_fe_normalize_var(&ge_odd.x); + rustsecp256k1_v0_11_fe_normalize_var(&ge_even.x); + rustsecp256k1_v0_11_fe_normalize_var(&ge_odd.y); + rustsecp256k1_v0_11_fe_normalize_var(&ge_even.y); /* No infinity allowed. */ - CHECK(!ge_quad.infinity); CHECK(!ge_even.infinity); CHECK(!ge_odd.infinity); /* Check that the x coordinates check out. */ - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&ge_quad.x, x)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&ge_even.x, x)); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&ge_odd.x, x)); - - /* Check that the Y coordinate result in ge_quad is a square. */ - CHECK(rustsecp256k1zkp_v0_8_0_fe_is_quad_var(&ge_quad.y)); + CHECK(rustsecp256k1_v0_11_fe_equal(&ge_even.x, x)); + CHECK(rustsecp256k1_v0_11_fe_equal(&ge_odd.x, x)); /* Check odd/even Y in ge_odd, ge_even. */ - CHECK(rustsecp256k1zkp_v0_8_0_fe_is_odd(&ge_odd.y)); - CHECK(!rustsecp256k1zkp_v0_8_0_fe_is_odd(&ge_even.y)); - - /* Check rustsecp256k1zkp_v0_8_0_gej_has_quad_y_var. */ - rustsecp256k1zkp_v0_8_0_gej_set_ge(&gej_quad, &ge_quad); - CHECK(rustsecp256k1zkp_v0_8_0_gej_has_quad_y_var(&gej_quad)); - do { - random_fe_test(&fez); - } while (rustsecp256k1zkp_v0_8_0_fe_is_zero(&fez)); - rustsecp256k1zkp_v0_8_0_gej_rescale(&gej_quad, &fez); - CHECK(rustsecp256k1zkp_v0_8_0_gej_has_quad_y_var(&gej_quad)); - rustsecp256k1zkp_v0_8_0_gej_neg(&gej_quad, &gej_quad); - CHECK(!rustsecp256k1zkp_v0_8_0_gej_has_quad_y_var(&gej_quad)); - do { - random_fe_test(&fez); - } while (rustsecp256k1zkp_v0_8_0_fe_is_zero(&fez)); - rustsecp256k1zkp_v0_8_0_gej_rescale(&gej_quad, &fez); - CHECK(!rustsecp256k1zkp_v0_8_0_gej_has_quad_y_var(&gej_quad)); - rustsecp256k1zkp_v0_8_0_gej_neg(&gej_quad, &gej_quad); - CHECK(rustsecp256k1zkp_v0_8_0_gej_has_quad_y_var(&gej_quad)); + CHECK(rustsecp256k1_v0_11_fe_is_odd(&ge_odd.y)); + CHECK(!rustsecp256k1_v0_11_fe_is_odd(&ge_even.y)); } } -void run_group_decompress(void) { +static void run_group_decompress(void) { int i; - for (i = 0; i < count * 4; i++) { - rustsecp256k1zkp_v0_8_0_fe fe; - random_fe_test(&fe); + for (i = 0; i < COUNT * 4; i++) { + rustsecp256k1_v0_11_fe fe; + testutil_random_fe_test(&fe); test_group_decompress(&fe); } } /***** ECMULT TESTS *****/ -void test_pre_g_table(const rustsecp256k1zkp_v0_8_0_ge_storage * pre_g, size_t n) { +static void test_pre_g_table(const rustsecp256k1_v0_11_ge_storage * pre_g, size_t n) { /* Tests the pre_g / pre_g_128 tables for consistency. * For independent verification we take a "geometric" approach to verification. * We check that every entry is on-curve. @@ -3929,175 +4152,168 @@ void test_pre_g_table(const rustsecp256k1zkp_v0_8_0_ge_storage * pre_g, size_t n * * Checking the table's generators are correct is done in run_ecmult_pre_g. */ - rustsecp256k1zkp_v0_8_0_gej g2; - rustsecp256k1zkp_v0_8_0_ge p, q, gg; - rustsecp256k1zkp_v0_8_0_fe dpx, dpy, dqx, dqy; + rustsecp256k1_v0_11_gej g2; + rustsecp256k1_v0_11_ge p, q, gg; + rustsecp256k1_v0_11_fe dpx, dpy, dqx, dqy; size_t i; CHECK(0 < n); - rustsecp256k1zkp_v0_8_0_ge_from_storage(&p, &pre_g[0]); - CHECK(rustsecp256k1zkp_v0_8_0_ge_is_valid_var(&p)); + rustsecp256k1_v0_11_ge_from_storage(&p, &pre_g[0]); + CHECK(rustsecp256k1_v0_11_ge_is_valid_var(&p)); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&g2, &p); - rustsecp256k1zkp_v0_8_0_gej_double_var(&g2, &g2, NULL); - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&gg, &g2); + rustsecp256k1_v0_11_gej_set_ge(&g2, &p); + rustsecp256k1_v0_11_gej_double_var(&g2, &g2, NULL); + rustsecp256k1_v0_11_ge_set_gej_var(&gg, &g2); for (i = 1; i < n; ++i) { - rustsecp256k1zkp_v0_8_0_fe_negate(&dpx, &p.x, 1); rustsecp256k1zkp_v0_8_0_fe_add(&dpx, &gg.x); rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&dpx); - rustsecp256k1zkp_v0_8_0_fe_negate(&dpy, &p.y, 1); rustsecp256k1zkp_v0_8_0_fe_add(&dpy, &gg.y); rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&dpy); + rustsecp256k1_v0_11_fe_negate(&dpx, &p.x, 1); rustsecp256k1_v0_11_fe_add(&dpx, &gg.x); rustsecp256k1_v0_11_fe_normalize_weak(&dpx); + rustsecp256k1_v0_11_fe_negate(&dpy, &p.y, 1); rustsecp256k1_v0_11_fe_add(&dpy, &gg.y); rustsecp256k1_v0_11_fe_normalize_weak(&dpy); /* Check that p is not equal to gg */ - CHECK(!rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(&dpx) || !rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(&dpy)); + CHECK(!rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&dpx) || !rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&dpy)); - rustsecp256k1zkp_v0_8_0_ge_from_storage(&q, &pre_g[i]); - CHECK(rustsecp256k1zkp_v0_8_0_ge_is_valid_var(&q)); + rustsecp256k1_v0_11_ge_from_storage(&q, &pre_g[i]); + CHECK(rustsecp256k1_v0_11_ge_is_valid_var(&q)); - rustsecp256k1zkp_v0_8_0_fe_negate(&dqx, &q.x, 1); rustsecp256k1zkp_v0_8_0_fe_add(&dqx, &gg.x); rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&dqx); - dqy = q.y; rustsecp256k1zkp_v0_8_0_fe_add(&dqy, &gg.y); rustsecp256k1zkp_v0_8_0_fe_normalize_weak(&dqy); + rustsecp256k1_v0_11_fe_negate(&dqx, &q.x, 1); rustsecp256k1_v0_11_fe_add(&dqx, &gg.x); + dqy = q.y; rustsecp256k1_v0_11_fe_add(&dqy, &gg.y); /* Check that -q is not equal to gg */ - CHECK(!rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(&dqx) || !rustsecp256k1zkp_v0_8_0_fe_normalizes_to_zero_var(&dqy)); + CHECK(!rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&dqx) || !rustsecp256k1_v0_11_fe_normalizes_to_zero_var(&dqy)); /* Check that -q is not equal to p */ - CHECK(!rustsecp256k1zkp_v0_8_0_fe_equal_var(&dpx, &dqx) || !rustsecp256k1zkp_v0_8_0_fe_equal_var(&dpy, &dqy)); + CHECK(!rustsecp256k1_v0_11_fe_equal(&dpx, &dqx) || !rustsecp256k1_v0_11_fe_equal(&dpy, &dqy)); /* Check that p, -q and gg are colinear */ - rustsecp256k1zkp_v0_8_0_fe_mul(&dpx, &dpx, &dqy); - rustsecp256k1zkp_v0_8_0_fe_mul(&dpy, &dpy, &dqx); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&dpx, &dpy)); + rustsecp256k1_v0_11_fe_mul(&dpx, &dpx, &dqy); + rustsecp256k1_v0_11_fe_mul(&dpy, &dpy, &dqx); + CHECK(rustsecp256k1_v0_11_fe_equal(&dpx, &dpy)); p = q; } } -void run_ecmult_pre_g(void) { - rustsecp256k1zkp_v0_8_0_ge_storage gs; - rustsecp256k1zkp_v0_8_0_gej gj; - rustsecp256k1zkp_v0_8_0_ge g; +static void run_ecmult_pre_g(void) { + rustsecp256k1_v0_11_ge_storage gs; + rustsecp256k1_v0_11_gej gj; + rustsecp256k1_v0_11_ge g; size_t i; /* Check that the pre_g and pre_g_128 tables are consistent. */ - test_pre_g_table(rustsecp256k1zkp_v0_8_0_pre_g, ECMULT_TABLE_SIZE(WINDOW_G)); - test_pre_g_table(rustsecp256k1zkp_v0_8_0_pre_g_128, ECMULT_TABLE_SIZE(WINDOW_G)); + test_pre_g_table(rustsecp256k1_v0_11_pre_g, ECMULT_TABLE_SIZE(WINDOW_G)); + test_pre_g_table(rustsecp256k1_v0_11_pre_g_128, ECMULT_TABLE_SIZE(WINDOW_G)); /* Check the first entry from the pre_g table. */ - rustsecp256k1zkp_v0_8_0_ge_to_storage(&gs, &rustsecp256k1zkp_v0_8_0_ge_const_g); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&gs, &rustsecp256k1zkp_v0_8_0_pre_g[0], sizeof(gs)) == 0); + rustsecp256k1_v0_11_ge_to_storage(&gs, &rustsecp256k1_v0_11_ge_const_g); + CHECK(rustsecp256k1_v0_11_memcmp_var(&gs, &rustsecp256k1_v0_11_pre_g[0], sizeof(gs)) == 0); /* Check the first entry from the pre_g_128 table. */ - rustsecp256k1zkp_v0_8_0_gej_set_ge(&gj, &rustsecp256k1zkp_v0_8_0_ge_const_g); + rustsecp256k1_v0_11_gej_set_ge(&gj, &rustsecp256k1_v0_11_ge_const_g); for (i = 0; i < 128; ++i) { - rustsecp256k1zkp_v0_8_0_gej_double_var(&gj, &gj, NULL); + rustsecp256k1_v0_11_gej_double_var(&gj, &gj, NULL); } - rustsecp256k1zkp_v0_8_0_ge_set_gej(&g, &gj); - rustsecp256k1zkp_v0_8_0_ge_to_storage(&gs, &g); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&gs, &rustsecp256k1zkp_v0_8_0_pre_g_128[0], sizeof(gs)) == 0); + rustsecp256k1_v0_11_ge_set_gej(&g, &gj); + rustsecp256k1_v0_11_ge_to_storage(&gs, &g); + CHECK(rustsecp256k1_v0_11_memcmp_var(&gs, &rustsecp256k1_v0_11_pre_g_128[0], sizeof(gs)) == 0); } -void run_ecmult_chain(void) { +static void run_ecmult_chain(void) { /* random starting point A (on the curve) */ - rustsecp256k1zkp_v0_8_0_gej a = SECP256K1_GEJ_CONST( + rustsecp256k1_v0_11_gej a = SECP256K1_GEJ_CONST( 0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3, 0x727fd8bc, 0x04d3362c, 0x6c7bf458, 0xe2846004, 0xa357ae91, 0x5c4a6528, 0x1309edf2, 0x0504740f, 0x0eb33439, 0x90216b4f, 0x81063cb6, 0x5f2f7e0f ); /* two random initial factors xn and gn */ - rustsecp256k1zkp_v0_8_0_scalar xn = SECP256K1_SCALAR_CONST( + rustsecp256k1_v0_11_scalar xn = SECP256K1_SCALAR_CONST( 0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c, 0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407 ); - rustsecp256k1zkp_v0_8_0_scalar gn = SECP256K1_SCALAR_CONST( + rustsecp256k1_v0_11_scalar gn = SECP256K1_SCALAR_CONST( 0xa1e58d22, 0x553dcd42, 0xb2398062, 0x5d4c57a9, 0x6e9323d4, 0x2b3152e5, 0xca2c3990, 0xedc7c9de ); /* two small multipliers to be applied to xn and gn in every iteration: */ - static const rustsecp256k1zkp_v0_8_0_scalar xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); - static const rustsecp256k1zkp_v0_8_0_scalar gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); + static const rustsecp256k1_v0_11_scalar xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); + static const rustsecp256k1_v0_11_scalar gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); /* accumulators with the resulting coefficients to A and G */ - rustsecp256k1zkp_v0_8_0_scalar ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); - rustsecp256k1zkp_v0_8_0_scalar ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + rustsecp256k1_v0_11_scalar ae = rustsecp256k1_v0_11_scalar_one; + rustsecp256k1_v0_11_scalar ge = rustsecp256k1_v0_11_scalar_zero; /* actual points */ - rustsecp256k1zkp_v0_8_0_gej x; - rustsecp256k1zkp_v0_8_0_gej x2; + rustsecp256k1_v0_11_gej x; + rustsecp256k1_v0_11_gej x2; int i; /* the point being computed */ x = a; - for (i = 0; i < 200*count; i++) { + for (i = 0; i < 200*COUNT; i++) { /* in each iteration, compute X = xn*X + gn*G; */ - rustsecp256k1zkp_v0_8_0_ecmult(&x, &x, &xn, &gn); + rustsecp256k1_v0_11_ecmult(&x, &x, &xn, &gn); /* also compute ae and ge: the actual accumulated factors for A and G */ /* if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) */ - rustsecp256k1zkp_v0_8_0_scalar_mul(&ae, &ae, &xn); - rustsecp256k1zkp_v0_8_0_scalar_mul(&ge, &ge, &xn); - rustsecp256k1zkp_v0_8_0_scalar_add(&ge, &ge, &gn); + rustsecp256k1_v0_11_scalar_mul(&ae, &ae, &xn); + rustsecp256k1_v0_11_scalar_mul(&ge, &ge, &xn); + rustsecp256k1_v0_11_scalar_add(&ge, &ge, &gn); /* modify xn and gn */ - rustsecp256k1zkp_v0_8_0_scalar_mul(&xn, &xn, &xf); - rustsecp256k1zkp_v0_8_0_scalar_mul(&gn, &gn, &gf); + rustsecp256k1_v0_11_scalar_mul(&xn, &xn, &xf); + rustsecp256k1_v0_11_scalar_mul(&gn, &gn, &gf); /* verify */ if (i == 19999) { /* expected result after 19999 iterations */ - rustsecp256k1zkp_v0_8_0_gej rp = SECP256K1_GEJ_CONST( + rustsecp256k1_v0_11_gej rp = SECP256K1_GEJ_CONST( 0xD6E96687, 0xF9B10D09, 0x2A6F3543, 0x9D86CEBE, 0xA4535D0D, 0x409F5358, 0x6440BD74, 0xB933E830, 0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D, 0x3B4F566A, 0xE6580454, 0x07ED6015, 0xEE1B2A88 ); - - rustsecp256k1zkp_v0_8_0_gej_neg(&rp, &rp); - rustsecp256k1zkp_v0_8_0_gej_add_var(&rp, &rp, &x, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&rp)); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&rp, &x)); } } /* redo the computation, but directly with the resulting ae and ge coefficients: */ - rustsecp256k1zkp_v0_8_0_ecmult(&x2, &a, &ae, &ge); - rustsecp256k1zkp_v0_8_0_gej_neg(&x2, &x2); - rustsecp256k1zkp_v0_8_0_gej_add_var(&x2, &x2, &x, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&x2)); + rustsecp256k1_v0_11_ecmult(&x2, &a, &ae, &ge); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&x, &x2)); } -void test_point_times_order(const rustsecp256k1zkp_v0_8_0_gej *point) { +static void test_point_times_order(const rustsecp256k1_v0_11_gej *point) { /* X * (point + G) + (order-X) * (pointer + G) = 0 */ - rustsecp256k1zkp_v0_8_0_scalar x; - rustsecp256k1zkp_v0_8_0_scalar nx; - rustsecp256k1zkp_v0_8_0_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - rustsecp256k1zkp_v0_8_0_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); - rustsecp256k1zkp_v0_8_0_gej res1, res2; - rustsecp256k1zkp_v0_8_0_ge res3; + rustsecp256k1_v0_11_scalar x; + rustsecp256k1_v0_11_scalar nx; + rustsecp256k1_v0_11_gej res1, res2; + rustsecp256k1_v0_11_ge res3; unsigned char pub[65]; size_t psize = 65; - random_scalar_order_test(&x); - rustsecp256k1zkp_v0_8_0_scalar_negate(&nx, &x); - rustsecp256k1zkp_v0_8_0_ecmult(&res1, point, &x, &x); /* calc res1 = x * point + x * G; */ - rustsecp256k1zkp_v0_8_0_ecmult(&res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ - rustsecp256k1zkp_v0_8_0_gej_add_var(&res1, &res1, &res2, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&res1)); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&res3, &res1); - CHECK(rustsecp256k1zkp_v0_8_0_ge_is_infinity(&res3)); - CHECK(rustsecp256k1zkp_v0_8_0_ge_is_valid_var(&res3) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0); + testutil_random_scalar_order_test(&x); + rustsecp256k1_v0_11_scalar_negate(&nx, &x); + rustsecp256k1_v0_11_ecmult(&res1, point, &x, &x); /* calc res1 = x * point + x * G; */ + rustsecp256k1_v0_11_ecmult(&res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ + rustsecp256k1_v0_11_gej_add_var(&res1, &res1, &res2, NULL); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&res1)); + rustsecp256k1_v0_11_ge_set_gej(&res3, &res1); + CHECK(rustsecp256k1_v0_11_ge_is_infinity(&res3)); + CHECK(rustsecp256k1_v0_11_ge_is_valid_var(&res3) == 0); + CHECK(rustsecp256k1_v0_11_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0); psize = 65; - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0); + CHECK(rustsecp256k1_v0_11_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0); /* check zero/one edge cases */ - rustsecp256k1zkp_v0_8_0_ecmult(&res1, point, &zero, &zero); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&res3, &res1); - CHECK(rustsecp256k1zkp_v0_8_0_ge_is_infinity(&res3)); - rustsecp256k1zkp_v0_8_0_ecmult(&res1, point, &one, &zero); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&res3, &res1); - ge_equals_gej(&res3, point); - rustsecp256k1zkp_v0_8_0_ecmult(&res1, point, &zero, &one); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&res3, &res1); - ge_equals_ge(&res3, &rustsecp256k1zkp_v0_8_0_ge_const_g); -} - -/* These scalars reach large (in absolute value) outputs when fed to rustsecp256k1zkp_v0_8_0_scalar_split_lambda. + rustsecp256k1_v0_11_ecmult(&res1, point, &rustsecp256k1_v0_11_scalar_zero, &rustsecp256k1_v0_11_scalar_zero); + rustsecp256k1_v0_11_ge_set_gej(&res3, &res1); + CHECK(rustsecp256k1_v0_11_ge_is_infinity(&res3)); + rustsecp256k1_v0_11_ecmult(&res1, point, &rustsecp256k1_v0_11_scalar_one, &rustsecp256k1_v0_11_scalar_zero); + rustsecp256k1_v0_11_ge_set_gej(&res3, &res1); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(point, &res3)); + rustsecp256k1_v0_11_ecmult(&res1, point, &rustsecp256k1_v0_11_scalar_zero, &rustsecp256k1_v0_11_scalar_one); + rustsecp256k1_v0_11_ge_set_gej(&res3, &res1); + CHECK(rustsecp256k1_v0_11_ge_eq_var(&rustsecp256k1_v0_11_ge_const_g, &res3)); +} + +/* These scalars reach large (in absolute value) outputs when fed to rustsecp256k1_v0_11_scalar_split_lambda. * * They are computed as: * - For a in [-2, -1, 0, 1, 2]: * - For b in [-3, -1, 1, 3]: * - Output (a*LAMBDA + (ORDER+b)/2) % ORDER */ -static const rustsecp256k1zkp_v0_8_0_scalar scalars_near_split_bounds[20] = { +static const rustsecp256k1_v0_11_scalar scalars_near_split_bounds[20] = { SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fc), SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fd), SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fe), @@ -4120,49 +4336,48 @@ static const rustsecp256k1zkp_v0_8_0_scalar scalars_near_split_bounds[20] = { SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a45) }; -void test_ecmult_target(const rustsecp256k1zkp_v0_8_0_scalar* target, int mode) { +static void test_ecmult_target(const rustsecp256k1_v0_11_scalar* target, int mode) { /* Mode: 0=ecmult_gen, 1=ecmult, 2=ecmult_const */ - rustsecp256k1zkp_v0_8_0_scalar n1, n2; - rustsecp256k1zkp_v0_8_0_ge p; - rustsecp256k1zkp_v0_8_0_gej pj, p1j, p2j, ptj; - static const rustsecp256k1zkp_v0_8_0_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + rustsecp256k1_v0_11_scalar n1, n2; + rustsecp256k1_v0_11_ge p; + rustsecp256k1_v0_11_gej pj, p1j, p2j, ptj; /* Generate random n1,n2 such that n1+n2 = -target. */ - random_scalar_order_test(&n1); - rustsecp256k1zkp_v0_8_0_scalar_add(&n2, &n1, target); - rustsecp256k1zkp_v0_8_0_scalar_negate(&n2, &n2); + testutil_random_scalar_order_test(&n1); + rustsecp256k1_v0_11_scalar_add(&n2, &n1, target); + rustsecp256k1_v0_11_scalar_negate(&n2, &n2); /* Generate a random input point. */ if (mode != 0) { - random_group_element_test(&p); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&pj, &p); + testutil_random_ge_test(&p); + rustsecp256k1_v0_11_gej_set_ge(&pj, &p); } /* EC multiplications */ if (mode == 0) { - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &p1j, &n1); - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &p2j, &n2); - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &ptj, target); + rustsecp256k1_v0_11_ecmult_gen(&CTX->ecmult_gen_ctx, &p1j, &n1); + rustsecp256k1_v0_11_ecmult_gen(&CTX->ecmult_gen_ctx, &p2j, &n2); + rustsecp256k1_v0_11_ecmult_gen(&CTX->ecmult_gen_ctx, &ptj, target); } else if (mode == 1) { - rustsecp256k1zkp_v0_8_0_ecmult(&p1j, &pj, &n1, &zero); - rustsecp256k1zkp_v0_8_0_ecmult(&p2j, &pj, &n2, &zero); - rustsecp256k1zkp_v0_8_0_ecmult(&ptj, &pj, target, &zero); + rustsecp256k1_v0_11_ecmult(&p1j, &pj, &n1, &rustsecp256k1_v0_11_scalar_zero); + rustsecp256k1_v0_11_ecmult(&p2j, &pj, &n2, &rustsecp256k1_v0_11_scalar_zero); + rustsecp256k1_v0_11_ecmult(&ptj, &pj, target, &rustsecp256k1_v0_11_scalar_zero); } else { - rustsecp256k1zkp_v0_8_0_ecmult_const(&p1j, &p, &n1, 256); - rustsecp256k1zkp_v0_8_0_ecmult_const(&p2j, &p, &n2, 256); - rustsecp256k1zkp_v0_8_0_ecmult_const(&ptj, &p, target, 256); + rustsecp256k1_v0_11_ecmult_const(&p1j, &p, &n1); + rustsecp256k1_v0_11_ecmult_const(&p2j, &p, &n2); + rustsecp256k1_v0_11_ecmult_const(&ptj, &p, target); } /* Add them all up: n1*P + n2*P + target*P = (n1+n2+target)*P = (n1+n1-n1-n2)*P = 0. */ - rustsecp256k1zkp_v0_8_0_gej_add_var(&ptj, &ptj, &p1j, NULL); - rustsecp256k1zkp_v0_8_0_gej_add_var(&ptj, &ptj, &p2j, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&ptj)); + rustsecp256k1_v0_11_gej_add_var(&ptj, &ptj, &p1j, NULL); + rustsecp256k1_v0_11_gej_add_var(&ptj, &ptj, &p2j, NULL); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&ptj)); } -void run_ecmult_near_split_bound(void) { +static void run_ecmult_near_split_bound(void) { int i; unsigned j; - for (i = 0; i < 4*count; ++i) { + for (i = 0; i < 4*COUNT; ++i) { for (j = 0; j < sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); ++j) { test_ecmult_target(&scalars_near_split_bounds[j], 0); test_ecmult_target(&scalars_near_split_bounds[j], 1); @@ -4171,143 +4386,247 @@ void run_ecmult_near_split_bound(void) { } } -void run_point_times_order(void) { +static void run_point_times_order(void) { int i; - rustsecp256k1zkp_v0_8_0_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); - static const rustsecp256k1zkp_v0_8_0_fe xr = SECP256K1_FE_CONST( + rustsecp256k1_v0_11_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); + static const rustsecp256k1_v0_11_fe xr = SECP256K1_FE_CONST( 0x7603CB59, 0xB0EF6C63, 0xFE608479, 0x2A0C378C, 0xDB3233A8, 0x0F8A9A09, 0xA877DEAD, 0x31B38C45 ); for (i = 0; i < 500; i++) { - rustsecp256k1zkp_v0_8_0_ge p; - if (rustsecp256k1zkp_v0_8_0_ge_set_xo_var(&p, &x, 1)) { - rustsecp256k1zkp_v0_8_0_gej j; - CHECK(rustsecp256k1zkp_v0_8_0_ge_is_valid_var(&p)); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&j, &p); + rustsecp256k1_v0_11_ge p; + if (rustsecp256k1_v0_11_ge_set_xo_var(&p, &x, 1)) { + rustsecp256k1_v0_11_gej j; + CHECK(rustsecp256k1_v0_11_ge_is_valid_var(&p)); + rustsecp256k1_v0_11_gej_set_ge(&j, &p); test_point_times_order(&j); } - rustsecp256k1zkp_v0_8_0_fe_sqr(&x, &x); + rustsecp256k1_v0_11_fe_sqr(&x, &x); } - rustsecp256k1zkp_v0_8_0_fe_normalize_var(&x); - CHECK(rustsecp256k1zkp_v0_8_0_fe_equal_var(&x, &xr)); + rustsecp256k1_v0_11_fe_normalize_var(&x); + CHECK(rustsecp256k1_v0_11_fe_equal(&x, &xr)); } -void ecmult_const_random_mult(void) { +static void ecmult_const_random_mult(void) { /* random starting point A (on the curve) */ - rustsecp256k1zkp_v0_8_0_ge a = SECP256K1_GE_CONST( + rustsecp256k1_v0_11_ge a = SECP256K1_GE_CONST( 0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b, 0xa97f9263, 0xb1e88044, 0x93351325, 0x91bc450a, 0x535c59f7, 0x325e5d2b, 0xc391fbe8, 0x3c12787c, 0x337e4a98, 0xe82a9011, 0x0123ba37, 0xdd769c7d ); /* random initial factor xn */ - rustsecp256k1zkp_v0_8_0_scalar xn = SECP256K1_SCALAR_CONST( + rustsecp256k1_v0_11_scalar xn = SECP256K1_SCALAR_CONST( 0x649d4f77, 0xc4242df7, 0x7f2079c9, 0x14530327, 0xa31b876a, 0xd2d8ce2a, 0x2236d5c6, 0xd7b2029b ); /* expected xn * A (from sage) */ - rustsecp256k1zkp_v0_8_0_ge expected_b = SECP256K1_GE_CONST( + rustsecp256k1_v0_11_ge expected_b = SECP256K1_GE_CONST( 0x23773684, 0x4d209dc7, 0x098a786f, 0x20d06fcd, 0x070a38bf, 0xc11ac651, 0x03004319, 0x1e2a8786, 0xed8c3b8e, 0xc06dd57b, 0xd06ea66e, 0x45492b0f, 0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956 ); - rustsecp256k1zkp_v0_8_0_gej b; - rustsecp256k1zkp_v0_8_0_ecmult_const(&b, &a, &xn, 256); - - CHECK(rustsecp256k1zkp_v0_8_0_ge_is_valid_var(&a)); - ge_equals_gej(&expected_b, &b); -} - -void ecmult_const_commutativity(void) { - rustsecp256k1zkp_v0_8_0_scalar a; - rustsecp256k1zkp_v0_8_0_scalar b; - rustsecp256k1zkp_v0_8_0_gej res1; - rustsecp256k1zkp_v0_8_0_gej res2; - rustsecp256k1zkp_v0_8_0_ge mid1; - rustsecp256k1zkp_v0_8_0_ge mid2; - random_scalar_order_test(&a); - random_scalar_order_test(&b); - - rustsecp256k1zkp_v0_8_0_ecmult_const(&res1, &rustsecp256k1zkp_v0_8_0_ge_const_g, &a, 256); - rustsecp256k1zkp_v0_8_0_ecmult_const(&res2, &rustsecp256k1zkp_v0_8_0_ge_const_g, &b, 256); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&mid1, &res1); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&mid2, &res2); - rustsecp256k1zkp_v0_8_0_ecmult_const(&res1, &mid1, &b, 256); - rustsecp256k1zkp_v0_8_0_ecmult_const(&res2, &mid2, &a, 256); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&mid1, &res1); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&mid2, &res2); - ge_equals_ge(&mid1, &mid2); -} - -void ecmult_const_mult_zero_one(void) { - rustsecp256k1zkp_v0_8_0_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - rustsecp256k1zkp_v0_8_0_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); - rustsecp256k1zkp_v0_8_0_scalar negone; - rustsecp256k1zkp_v0_8_0_gej res1; - rustsecp256k1zkp_v0_8_0_ge res2; - rustsecp256k1zkp_v0_8_0_ge point; - rustsecp256k1zkp_v0_8_0_scalar_negate(&negone, &one); - - random_group_element_test(&point); - rustsecp256k1zkp_v0_8_0_ecmult_const(&res1, &point, &zero, 3); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&res2, &res1); - CHECK(rustsecp256k1zkp_v0_8_0_ge_is_infinity(&res2)); - rustsecp256k1zkp_v0_8_0_ecmult_const(&res1, &point, &one, 2); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&res2, &res1); - ge_equals_ge(&res2, &point); - rustsecp256k1zkp_v0_8_0_ecmult_const(&res1, &point, &negone, 256); - rustsecp256k1zkp_v0_8_0_gej_neg(&res1, &res1); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&res2, &res1); - ge_equals_ge(&res2, &point); -} - -void ecmult_const_chain_multiply(void) { + rustsecp256k1_v0_11_gej b; + rustsecp256k1_v0_11_ecmult_const(&b, &a, &xn); + + CHECK(rustsecp256k1_v0_11_ge_is_valid_var(&a)); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&b, &expected_b)); +} + +static void ecmult_const_commutativity(void) { + rustsecp256k1_v0_11_scalar a; + rustsecp256k1_v0_11_scalar b; + rustsecp256k1_v0_11_gej res1; + rustsecp256k1_v0_11_gej res2; + rustsecp256k1_v0_11_ge mid1; + rustsecp256k1_v0_11_ge mid2; + testutil_random_scalar_order_test(&a); + testutil_random_scalar_order_test(&b); + + rustsecp256k1_v0_11_ecmult_const(&res1, &rustsecp256k1_v0_11_ge_const_g, &a); + rustsecp256k1_v0_11_ecmult_const(&res2, &rustsecp256k1_v0_11_ge_const_g, &b); + rustsecp256k1_v0_11_ge_set_gej(&mid1, &res1); + rustsecp256k1_v0_11_ge_set_gej(&mid2, &res2); + rustsecp256k1_v0_11_ecmult_const(&res1, &mid1, &b); + rustsecp256k1_v0_11_ecmult_const(&res2, &mid2, &a); + rustsecp256k1_v0_11_ge_set_gej(&mid1, &res1); + rustsecp256k1_v0_11_ge_set_gej(&mid2, &res2); + CHECK(rustsecp256k1_v0_11_ge_eq_var(&mid1, &mid2)); +} + +static void ecmult_const_mult_zero_one(void) { + rustsecp256k1_v0_11_scalar s; + rustsecp256k1_v0_11_scalar negone; + rustsecp256k1_v0_11_gej res1; + rustsecp256k1_v0_11_ge res2; + rustsecp256k1_v0_11_ge point; + rustsecp256k1_v0_11_ge inf; + + testutil_random_scalar_order_test(&s); + rustsecp256k1_v0_11_scalar_negate(&negone, &rustsecp256k1_v0_11_scalar_one); + testutil_random_ge_test(&point); + rustsecp256k1_v0_11_ge_set_infinity(&inf); + + /* 0*point */ + rustsecp256k1_v0_11_ecmult_const(&res1, &point, &rustsecp256k1_v0_11_scalar_zero); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&res1)); + + /* s*inf */ + rustsecp256k1_v0_11_ecmult_const(&res1, &inf, &s); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&res1)); + + /* 1*point */ + rustsecp256k1_v0_11_ecmult_const(&res1, &point, &rustsecp256k1_v0_11_scalar_one); + rustsecp256k1_v0_11_ge_set_gej(&res2, &res1); + CHECK(rustsecp256k1_v0_11_ge_eq_var(&res2, &point)); + + /* -1*point */ + rustsecp256k1_v0_11_ecmult_const(&res1, &point, &negone); + rustsecp256k1_v0_11_gej_neg(&res1, &res1); + rustsecp256k1_v0_11_ge_set_gej(&res2, &res1); + CHECK(rustsecp256k1_v0_11_ge_eq_var(&res2, &point)); +} + +static void ecmult_const_check_result(const rustsecp256k1_v0_11_ge *A, const rustsecp256k1_v0_11_scalar* q, const rustsecp256k1_v0_11_gej *res) { + rustsecp256k1_v0_11_gej pointj, res2j; + rustsecp256k1_v0_11_ge res2; + rustsecp256k1_v0_11_gej_set_ge(&pointj, A); + rustsecp256k1_v0_11_ecmult(&res2j, &pointj, q, &rustsecp256k1_v0_11_scalar_zero); + rustsecp256k1_v0_11_ge_set_gej(&res2, &res2j); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(res, &res2)); +} + +static void ecmult_const_edges(void) { + rustsecp256k1_v0_11_scalar q; + rustsecp256k1_v0_11_ge point; + rustsecp256k1_v0_11_gej res; + size_t i; + size_t cases = 1 + sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); + + /* We are trying to reach the following edge cases (variables are defined as + * in ecmult_const_impl.h): + * 1. i = 0: s = 0 <=> q = -K + * 2. i > 0: v1, v2 large values + * <=> s1, s2 large values + * <=> s = scalars_near_split_bounds[i] + * <=> q = 2*scalars_near_split_bounds[i] - K + */ + for (i = 0; i < cases; ++i) { + rustsecp256k1_v0_11_scalar_negate(&q, &rustsecp256k1_v0_11_ecmult_const_K); + if (i > 0) { + rustsecp256k1_v0_11_scalar_add(&q, &q, &scalars_near_split_bounds[i - 1]); + rustsecp256k1_v0_11_scalar_add(&q, &q, &scalars_near_split_bounds[i - 1]); + } + testutil_random_ge_test(&point); + rustsecp256k1_v0_11_ecmult_const(&res, &point, &q); + ecmult_const_check_result(&point, &q, &res); + } +} + +static void ecmult_const_mult_xonly(void) { + int i; + + /* Test correspondence between rustsecp256k1_v0_11_ecmult_const and rustsecp256k1_v0_11_ecmult_const_xonly. */ + for (i = 0; i < 2*COUNT; ++i) { + rustsecp256k1_v0_11_ge base; + rustsecp256k1_v0_11_gej basej, resj; + rustsecp256k1_v0_11_fe n, d, resx, v; + rustsecp256k1_v0_11_scalar q; + int res; + /* Random base point. */ + testutil_random_ge_test(&base); + /* Random scalar to multiply it with. */ + testutil_random_scalar_order_test(&q); + /* If i is odd, n=d*base.x for random non-zero d */ + if (i & 1) { + testutil_random_fe_non_zero_test(&d); + rustsecp256k1_v0_11_fe_mul(&n, &base.x, &d); + } else { + n = base.x; + } + /* Perform x-only multiplication. */ + res = rustsecp256k1_v0_11_ecmult_const_xonly(&resx, &n, (i & 1) ? &d : NULL, &q, i & 2); + CHECK(res); + /* Perform normal multiplication. */ + rustsecp256k1_v0_11_gej_set_ge(&basej, &base); + rustsecp256k1_v0_11_ecmult(&resj, &basej, &q, NULL); + /* Check that resj's X coordinate corresponds with resx. */ + rustsecp256k1_v0_11_fe_sqr(&v, &resj.z); + rustsecp256k1_v0_11_fe_mul(&v, &v, &resx); + CHECK(fe_equal(&v, &resj.x)); + } + + /* Test that rustsecp256k1_v0_11_ecmult_const_xonly correctly rejects X coordinates not on curve. */ + for (i = 0; i < 2*COUNT; ++i) { + rustsecp256k1_v0_11_fe x, n, d, r; + int res; + rustsecp256k1_v0_11_scalar q; + testutil_random_scalar_order_test(&q); + /* Generate random X coordinate not on the curve. */ + do { + testutil_random_fe_test(&x); + } while (rustsecp256k1_v0_11_ge_x_on_curve_var(&x)); + /* If i is odd, n=d*x for random non-zero d. */ + if (i & 1) { + testutil_random_fe_non_zero_test(&d); + rustsecp256k1_v0_11_fe_mul(&n, &x, &d); + } else { + n = x; + } + res = rustsecp256k1_v0_11_ecmult_const_xonly(&r, &n, (i & 1) ? &d : NULL, &q, 0); + CHECK(res == 0); + } +} + +static void ecmult_const_chain_multiply(void) { /* Check known result (randomly generated test problem from sage) */ - const rustsecp256k1zkp_v0_8_0_scalar scalar = SECP256K1_SCALAR_CONST( + const rustsecp256k1_v0_11_scalar scalar = SECP256K1_SCALAR_CONST( 0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d, 0xcd83d307, 0x827bed62, 0x05fad0ce, 0x18fae63b ); - const rustsecp256k1zkp_v0_8_0_gej expected_point = SECP256K1_GEJ_CONST( + const rustsecp256k1_v0_11_gej expected_point = SECP256K1_GEJ_CONST( 0x5494c15d, 0x32099706, 0xc2395f94, 0x348745fd, 0x757ce30e, 0x4e8c90fb, 0xa2bad184, 0xf883c69f, 0x5d195d20, 0xe191bf7f, 0x1be3e55f, 0x56a80196, 0x6071ad01, 0xf1462f66, 0xc997fa94, 0xdb858435 ); - rustsecp256k1zkp_v0_8_0_gej point; - rustsecp256k1zkp_v0_8_0_ge res; + rustsecp256k1_v0_11_gej point; + rustsecp256k1_v0_11_ge res; int i; - rustsecp256k1zkp_v0_8_0_gej_set_ge(&point, &rustsecp256k1zkp_v0_8_0_ge_const_g); + rustsecp256k1_v0_11_gej_set_ge(&point, &rustsecp256k1_v0_11_ge_const_g); for (i = 0; i < 100; ++i) { - rustsecp256k1zkp_v0_8_0_ge tmp; - rustsecp256k1zkp_v0_8_0_ge_set_gej(&tmp, &point); - rustsecp256k1zkp_v0_8_0_ecmult_const(&point, &tmp, &scalar, 256); + rustsecp256k1_v0_11_ge tmp; + rustsecp256k1_v0_11_ge_set_gej(&tmp, &point); + rustsecp256k1_v0_11_ecmult_const(&point, &tmp, &scalar); } - rustsecp256k1zkp_v0_8_0_ge_set_gej(&res, &point); - ge_equals_gej(&res, &expected_point); + rustsecp256k1_v0_11_ge_set_gej(&res, &point); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&expected_point, &res)); } -void run_ecmult_const_tests(void) { +static void run_ecmult_const_tests(void) { ecmult_const_mult_zero_one(); + ecmult_const_edges(); ecmult_const_random_mult(); ecmult_const_commutativity(); ecmult_const_chain_multiply(); + ecmult_const_mult_xonly(); } typedef struct { - rustsecp256k1zkp_v0_8_0_scalar *sc; - rustsecp256k1zkp_v0_8_0_ge *pt; + rustsecp256k1_v0_11_scalar *sc; + rustsecp256k1_v0_11_ge *pt; } ecmult_multi_data; -static int ecmult_multi_callback(rustsecp256k1zkp_v0_8_0_scalar *sc, rustsecp256k1zkp_v0_8_0_ge *pt, size_t idx, void *cbdata) { +static int ecmult_multi_callback(rustsecp256k1_v0_11_scalar *sc, rustsecp256k1_v0_11_ge *pt, size_t idx, void *cbdata) { ecmult_multi_data *data = (ecmult_multi_data*) cbdata; *sc = data->sc[idx]; *pt = data->pt[idx]; return 1; } -static int ecmult_multi_false_callback(rustsecp256k1zkp_v0_8_0_scalar *sc, rustsecp256k1zkp_v0_8_0_ge *pt, size_t idx, void *cbdata) { +static int ecmult_multi_false_callback(rustsecp256k1_v0_11_scalar *sc, rustsecp256k1_v0_11_ge *pt, size_t idx, void *cbdata) { (void)sc; (void)pt; (void)idx; @@ -4315,238 +4634,222 @@ static int ecmult_multi_false_callback(rustsecp256k1zkp_v0_8_0_scalar *sc, rusts return 0; } -void test_ecmult_multi(rustsecp256k1zkp_v0_8_0_scratch *scratch, rustsecp256k1zkp_v0_8_0_ecmult_multi_func ecmult_multi) { +static void test_ecmult_multi(rustsecp256k1_v0_11_scratch *scratch, rustsecp256k1_v0_11_ecmult_multi_func ecmult_multi) { int ncount; - rustsecp256k1zkp_v0_8_0_scalar szero; - rustsecp256k1zkp_v0_8_0_scalar sc[32]; - rustsecp256k1zkp_v0_8_0_ge pt[32]; - rustsecp256k1zkp_v0_8_0_gej r; - rustsecp256k1zkp_v0_8_0_gej r2; + rustsecp256k1_v0_11_scalar sc[32]; + rustsecp256k1_v0_11_ge pt[32]; + rustsecp256k1_v0_11_gej r; + rustsecp256k1_v0_11_gej r2; ecmult_multi_data data; data.sc = sc; data.pt = pt; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&szero, 0); /* No points to multiply */ - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, NULL, ecmult_multi_callback, &data, 0)); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, NULL, ecmult_multi_callback, &data, 0)); /* Check 1- and 2-point multiplies against ecmult */ - for (ncount = 0; ncount < count; ncount++) { - rustsecp256k1zkp_v0_8_0_ge ptg; - rustsecp256k1zkp_v0_8_0_gej ptgj; - random_scalar_order(&sc[0]); - random_scalar_order(&sc[1]); - - random_group_element_test(&ptg); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&ptgj, &ptg); + for (ncount = 0; ncount < COUNT; ncount++) { + rustsecp256k1_v0_11_ge ptg; + rustsecp256k1_v0_11_gej ptgj; + testutil_random_scalar_order(&sc[0]); + testutil_random_scalar_order(&sc[1]); + + testutil_random_ge_test(&ptg); + rustsecp256k1_v0_11_gej_set_ge(&ptgj, &ptg); pt[0] = ptg; - pt[1] = rustsecp256k1zkp_v0_8_0_ge_const_g; + pt[1] = rustsecp256k1_v0_11_ge_const_g; /* only G scalar */ - rustsecp256k1zkp_v0_8_0_ecmult(&r2, &ptgj, &szero, &sc[0]); - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0)); - rustsecp256k1zkp_v0_8_0_gej_neg(&r2, &r2); - rustsecp256k1zkp_v0_8_0_gej_add_var(&r, &r, &r2, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); + rustsecp256k1_v0_11_ecmult(&r2, &ptgj, &rustsecp256k1_v0_11_scalar_zero, &sc[0]); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0)); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&r, &r2)); /* 1-point */ - rustsecp256k1zkp_v0_8_0_ecmult(&r2, &ptgj, &sc[0], &szero); - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 1)); - rustsecp256k1zkp_v0_8_0_gej_neg(&r2, &r2); - rustsecp256k1zkp_v0_8_0_gej_add_var(&r, &r, &r2, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); + rustsecp256k1_v0_11_ecmult(&r2, &ptgj, &sc[0], &rustsecp256k1_v0_11_scalar_zero); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_callback, &data, 1)); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&r, &r2)); /* Try to multiply 1 point, but callback returns false */ - CHECK(!ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1)); + CHECK(!ecmult_multi(&CTX->error_callback, scratch, &r, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_false_callback, &data, 1)); /* 2-point */ - rustsecp256k1zkp_v0_8_0_ecmult(&r2, &ptgj, &sc[0], &sc[1]); - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 2)); - rustsecp256k1zkp_v0_8_0_gej_neg(&r2, &r2); - rustsecp256k1zkp_v0_8_0_gej_add_var(&r, &r, &r2, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); + rustsecp256k1_v0_11_ecmult(&r2, &ptgj, &sc[0], &sc[1]); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_callback, &data, 2)); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&r, &r2)); /* 2-point with G scalar */ - rustsecp256k1zkp_v0_8_0_ecmult(&r2, &ptgj, &sc[0], &sc[1]); - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1)); - rustsecp256k1zkp_v0_8_0_gej_neg(&r2, &r2); - rustsecp256k1zkp_v0_8_0_gej_add_var(&r, &r, &r2, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); + rustsecp256k1_v0_11_ecmult(&r2, &ptgj, &sc[0], &sc[1]); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1)); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&r, &r2)); } /* Check infinite outputs of various forms */ - for (ncount = 0; ncount < count; ncount++) { - rustsecp256k1zkp_v0_8_0_ge ptg; + for (ncount = 0; ncount < COUNT; ncount++) { + rustsecp256k1_v0_11_ge ptg; size_t i, j; size_t sizes[] = { 2, 10, 32 }; for (j = 0; j < 3; j++) { for (i = 0; i < 32; i++) { - random_scalar_order(&sc[i]); - rustsecp256k1zkp_v0_8_0_ge_set_infinity(&pt[i]); + testutil_random_scalar_order(&sc[i]); + rustsecp256k1_v0_11_ge_set_infinity(&pt[i]); } - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_callback, &data, sizes[j])); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&r)); } for (j = 0; j < 3; j++) { for (i = 0; i < 32; i++) { - random_group_element_test(&ptg); + testutil_random_ge_test(&ptg); pt[i] = ptg; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&sc[i], 0); + rustsecp256k1_v0_11_scalar_set_int(&sc[i], 0); } - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_callback, &data, sizes[j])); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&r)); } for (j = 0; j < 3; j++) { - random_group_element_test(&ptg); + testutil_random_ge_test(&ptg); for (i = 0; i < 16; i++) { - random_scalar_order(&sc[2*i]); - rustsecp256k1zkp_v0_8_0_scalar_negate(&sc[2*i + 1], &sc[2*i]); + testutil_random_scalar_order(&sc[2*i]); + rustsecp256k1_v0_11_scalar_negate(&sc[2*i + 1], &sc[2*i]); pt[2 * i] = ptg; pt[2 * i + 1] = ptg; } - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_callback, &data, sizes[j])); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&r)); - random_scalar_order(&sc[0]); + testutil_random_scalar_order(&sc[0]); for (i = 0; i < 16; i++) { - random_group_element_test(&ptg); + testutil_random_ge_test(&ptg); sc[2*i] = sc[0]; sc[2*i+1] = sc[0]; pt[2 * i] = ptg; - rustsecp256k1zkp_v0_8_0_ge_neg(&pt[2*i+1], &pt[2*i]); + rustsecp256k1_v0_11_ge_neg(&pt[2*i+1], &pt[2*i]); } - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_callback, &data, sizes[j])); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&r)); } - random_group_element_test(&ptg); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&sc[0], 0); + testutil_random_ge_test(&ptg); + rustsecp256k1_v0_11_scalar_set_int(&sc[0], 0); pt[0] = ptg; for (i = 1; i < 32; i++) { pt[i] = ptg; - random_scalar_order(&sc[i]); - rustsecp256k1zkp_v0_8_0_scalar_add(&sc[0], &sc[0], &sc[i]); - rustsecp256k1zkp_v0_8_0_scalar_negate(&sc[i], &sc[i]); + testutil_random_scalar_order(&sc[i]); + rustsecp256k1_v0_11_scalar_add(&sc[0], &sc[0], &sc[i]); + rustsecp256k1_v0_11_scalar_negate(&sc[i], &sc[i]); } - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 32)); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_callback, &data, 32)); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&r)); } /* Check random points, constant scalar */ - for (ncount = 0; ncount < count; ncount++) { + for (ncount = 0; ncount < COUNT; ncount++) { size_t i; - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&r); + rustsecp256k1_v0_11_gej_set_infinity(&r); - random_scalar_order(&sc[0]); + testutil_random_scalar_order(&sc[0]); for (i = 0; i < 20; i++) { - rustsecp256k1zkp_v0_8_0_ge ptg; + rustsecp256k1_v0_11_ge ptg; sc[i] = sc[0]; - random_group_element_test(&ptg); + testutil_random_ge_test(&ptg); pt[i] = ptg; - rustsecp256k1zkp_v0_8_0_gej_add_ge_var(&r, &r, &pt[i], NULL); + rustsecp256k1_v0_11_gej_add_ge_var(&r, &r, &pt[i], NULL); } - rustsecp256k1zkp_v0_8_0_ecmult(&r2, &r, &sc[0], &szero); - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); - rustsecp256k1zkp_v0_8_0_gej_neg(&r2, &r2); - rustsecp256k1zkp_v0_8_0_gej_add_var(&r, &r, &r2, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); + rustsecp256k1_v0_11_ecmult(&r2, &r, &sc[0], &rustsecp256k1_v0_11_scalar_zero); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_callback, &data, 20)); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&r, &r2)); } /* Check random scalars, constant point */ - for (ncount = 0; ncount < count; ncount++) { + for (ncount = 0; ncount < COUNT; ncount++) { size_t i; - rustsecp256k1zkp_v0_8_0_ge ptg; - rustsecp256k1zkp_v0_8_0_gej p0j; - rustsecp256k1zkp_v0_8_0_scalar rs; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&rs, 0); + rustsecp256k1_v0_11_ge ptg; + rustsecp256k1_v0_11_gej p0j; + rustsecp256k1_v0_11_scalar rs; + rustsecp256k1_v0_11_scalar_set_int(&rs, 0); - random_group_element_test(&ptg); + testutil_random_ge_test(&ptg); for (i = 0; i < 20; i++) { - random_scalar_order(&sc[i]); + testutil_random_scalar_order(&sc[i]); pt[i] = ptg; - rustsecp256k1zkp_v0_8_0_scalar_add(&rs, &rs, &sc[i]); + rustsecp256k1_v0_11_scalar_add(&rs, &rs, &sc[i]); } - rustsecp256k1zkp_v0_8_0_gej_set_ge(&p0j, &pt[0]); - rustsecp256k1zkp_v0_8_0_ecmult(&r2, &p0j, &rs, &szero); - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); - rustsecp256k1zkp_v0_8_0_gej_neg(&r2, &r2); - rustsecp256k1zkp_v0_8_0_gej_add_var(&r, &r, &r2, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); + rustsecp256k1_v0_11_gej_set_ge(&p0j, &pt[0]); + rustsecp256k1_v0_11_ecmult(&r2, &p0j, &rs, &rustsecp256k1_v0_11_scalar_zero); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_callback, &data, 20)); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&r, &r2)); } /* Sanity check that zero scalars don't cause problems */ for (ncount = 0; ncount < 20; ncount++) { - random_scalar_order(&sc[ncount]); - random_group_element_test(&pt[ncount]); + testutil_random_scalar_order(&sc[ncount]); + testutil_random_ge_test(&pt[ncount]); } - rustsecp256k1zkp_v0_8_0_scalar_clear(&sc[0]); - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sc[1]); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sc[2]); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sc[3]); - rustsecp256k1zkp_v0_8_0_scalar_clear(&sc[4]); - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 6)); - CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 5)); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); + rustsecp256k1_v0_11_scalar_set_int(&sc[0], 0); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_callback, &data, 20)); + rustsecp256k1_v0_11_scalar_set_int(&sc[1], 0); + rustsecp256k1_v0_11_scalar_set_int(&sc[2], 0); + rustsecp256k1_v0_11_scalar_set_int(&sc[3], 0); + rustsecp256k1_v0_11_scalar_set_int(&sc[4], 0); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_callback, &data, 6)); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_callback, &data, 5)); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&r)); /* Run through s0*(t0*P) + s1*(t1*P) exhaustively for many small values of s0, s1, t0, t1 */ { const size_t TOP = 8; size_t s0i, s1i; size_t t0i, t1i; - rustsecp256k1zkp_v0_8_0_ge ptg; - rustsecp256k1zkp_v0_8_0_gej ptgj; + rustsecp256k1_v0_11_ge ptg; + rustsecp256k1_v0_11_gej ptgj; - random_group_element_test(&ptg); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&ptgj, &ptg); + testutil_random_ge_test(&ptg); + rustsecp256k1_v0_11_gej_set_ge(&ptgj, &ptg); for(t0i = 0; t0i < TOP; t0i++) { for(t1i = 0; t1i < TOP; t1i++) { - rustsecp256k1zkp_v0_8_0_gej t0p, t1p; - rustsecp256k1zkp_v0_8_0_scalar t0, t1; + rustsecp256k1_v0_11_gej t0p, t1p; + rustsecp256k1_v0_11_scalar t0, t1; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&t0, (t0i + 1) / 2); - rustsecp256k1zkp_v0_8_0_scalar_cond_negate(&t0, t0i & 1); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&t1, (t1i + 1) / 2); - rustsecp256k1zkp_v0_8_0_scalar_cond_negate(&t1, t1i & 1); + rustsecp256k1_v0_11_scalar_set_int(&t0, (t0i + 1) / 2); + rustsecp256k1_v0_11_scalar_cond_negate(&t0, t0i & 1); + rustsecp256k1_v0_11_scalar_set_int(&t1, (t1i + 1) / 2); + rustsecp256k1_v0_11_scalar_cond_negate(&t1, t1i & 1); - rustsecp256k1zkp_v0_8_0_ecmult(&t0p, &ptgj, &t0, &szero); - rustsecp256k1zkp_v0_8_0_ecmult(&t1p, &ptgj, &t1, &szero); + rustsecp256k1_v0_11_ecmult(&t0p, &ptgj, &t0, &rustsecp256k1_v0_11_scalar_zero); + rustsecp256k1_v0_11_ecmult(&t1p, &ptgj, &t1, &rustsecp256k1_v0_11_scalar_zero); for(s0i = 0; s0i < TOP; s0i++) { for(s1i = 0; s1i < TOP; s1i++) { - rustsecp256k1zkp_v0_8_0_scalar tmp1, tmp2; - rustsecp256k1zkp_v0_8_0_gej expected, actual; - - rustsecp256k1zkp_v0_8_0_ge_set_gej(&pt[0], &t0p); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&pt[1], &t1p); - - rustsecp256k1zkp_v0_8_0_scalar_set_int(&sc[0], (s0i + 1) / 2); - rustsecp256k1zkp_v0_8_0_scalar_cond_negate(&sc[0], s0i & 1); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&sc[1], (s1i + 1) / 2); - rustsecp256k1zkp_v0_8_0_scalar_cond_negate(&sc[1], s1i & 1); - - rustsecp256k1zkp_v0_8_0_scalar_mul(&tmp1, &t0, &sc[0]); - rustsecp256k1zkp_v0_8_0_scalar_mul(&tmp2, &t1, &sc[1]); - rustsecp256k1zkp_v0_8_0_scalar_add(&tmp1, &tmp1, &tmp2); - - rustsecp256k1zkp_v0_8_0_ecmult(&expected, &ptgj, &tmp1, &szero); - CHECK(ecmult_multi(&ctx->error_callback, scratch, &actual, &szero, ecmult_multi_callback, &data, 2)); - rustsecp256k1zkp_v0_8_0_gej_neg(&expected, &expected); - rustsecp256k1zkp_v0_8_0_gej_add_var(&actual, &actual, &expected, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&actual)); + rustsecp256k1_v0_11_scalar tmp1, tmp2; + rustsecp256k1_v0_11_gej expected, actual; + + rustsecp256k1_v0_11_ge_set_gej(&pt[0], &t0p); + rustsecp256k1_v0_11_ge_set_gej(&pt[1], &t1p); + + rustsecp256k1_v0_11_scalar_set_int(&sc[0], (s0i + 1) / 2); + rustsecp256k1_v0_11_scalar_cond_negate(&sc[0], s0i & 1); + rustsecp256k1_v0_11_scalar_set_int(&sc[1], (s1i + 1) / 2); + rustsecp256k1_v0_11_scalar_cond_negate(&sc[1], s1i & 1); + + rustsecp256k1_v0_11_scalar_mul(&tmp1, &t0, &sc[0]); + rustsecp256k1_v0_11_scalar_mul(&tmp2, &t1, &sc[1]); + rustsecp256k1_v0_11_scalar_add(&tmp1, &tmp1, &tmp2); + + rustsecp256k1_v0_11_ecmult(&expected, &ptgj, &tmp1, &rustsecp256k1_v0_11_scalar_zero); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &actual, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_callback, &data, 2)); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&actual, &expected)); } } } @@ -4554,7 +4857,7 @@ void test_ecmult_multi(rustsecp256k1zkp_v0_8_0_scratch *scratch, rustsecp256k1zk } } -int test_ecmult_multi_random(rustsecp256k1zkp_v0_8_0_scratch *scratch) { +static int test_ecmult_multi_random(rustsecp256k1_v0_11_scratch *scratch) { /* Large random test for ecmult_multi_* functions which exercises: * - Few or many inputs (0 up to 128, roughly exponentially distributed). * - Few or many 0*P or a*INF inputs (roughly uniformly distributed). @@ -4568,60 +4871,60 @@ int test_ecmult_multi_random(rustsecp256k1zkp_v0_8_0_scratch *scratch) { * scalars[0..filled-1] and gejs[0..filled-1] are the scalars and points * which form its normal inputs. */ int filled = 0; - rustsecp256k1zkp_v0_8_0_scalar g_scalar = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - rustsecp256k1zkp_v0_8_0_scalar scalars[128]; - rustsecp256k1zkp_v0_8_0_gej gejs[128]; + rustsecp256k1_v0_11_scalar g_scalar = rustsecp256k1_v0_11_scalar_zero; + rustsecp256k1_v0_11_scalar scalars[128]; + rustsecp256k1_v0_11_gej gejs[128]; /* The expected result, and the computed result. */ - rustsecp256k1zkp_v0_8_0_gej expected, computed; + rustsecp256k1_v0_11_gej expected, computed; /* Temporaries. */ - rustsecp256k1zkp_v0_8_0_scalar sc_tmp; - rustsecp256k1zkp_v0_8_0_ge ge_tmp; + rustsecp256k1_v0_11_scalar sc_tmp; + rustsecp256k1_v0_11_ge ge_tmp; /* Variables needed for the actual input to ecmult_multi. */ - rustsecp256k1zkp_v0_8_0_ge ges[128]; + rustsecp256k1_v0_11_ge ges[128]; ecmult_multi_data data; int i; /* Which multiplication function to use */ - int fn = rustsecp256k1zkp_v0_8_0_testrand_int(3); - rustsecp256k1zkp_v0_8_0_ecmult_multi_func ecmult_multi = fn == 0 ? rustsecp256k1zkp_v0_8_0_ecmult_multi_var : - fn == 1 ? rustsecp256k1zkp_v0_8_0_ecmult_strauss_batch_single : - rustsecp256k1zkp_v0_8_0_ecmult_pippenger_batch_single; + int fn = testrand_int(3); + rustsecp256k1_v0_11_ecmult_multi_func ecmult_multi = fn == 0 ? rustsecp256k1_v0_11_ecmult_multi_var : + fn == 1 ? rustsecp256k1_v0_11_ecmult_strauss_batch_single : + rustsecp256k1_v0_11_ecmult_pippenger_batch_single; /* Simulate exponentially distributed num. */ - int num_bits = 2 + rustsecp256k1zkp_v0_8_0_testrand_int(6); + int num_bits = 2 + testrand_int(6); /* Number of (scalar, point) inputs (excluding g). */ - int num = rustsecp256k1zkp_v0_8_0_testrand_int((1 << num_bits) + 1); + int num = testrand_int((1 << num_bits) + 1); /* Number of those which are nonzero. */ - int num_nonzero = rustsecp256k1zkp_v0_8_0_testrand_int(num + 1); + int num_nonzero = testrand_int(num + 1); /* Whether we're aiming to create an input with nonzero expected result. */ - int nonzero_result = rustsecp256k1zkp_v0_8_0_testrand_bits(1); + int nonzero_result = testrand_bits(1); /* Whether we will provide nonzero g multiplicand. In some cases our hand * is forced here based on num_nonzero and nonzero_result. */ int g_nonzero = num_nonzero == 0 ? nonzero_result : num_nonzero == 1 && !nonzero_result ? 1 : - (int)rustsecp256k1zkp_v0_8_0_testrand_bits(1); + (int)testrand_bits(1); /* Which g_scalar pointer to pass into ecmult_multi(). */ - const rustsecp256k1zkp_v0_8_0_scalar* g_scalar_ptr = (g_nonzero || rustsecp256k1zkp_v0_8_0_testrand_bits(1)) ? &g_scalar : NULL; + const rustsecp256k1_v0_11_scalar* g_scalar_ptr = (g_nonzero || testrand_bits(1)) ? &g_scalar : NULL; /* How many EC multiplications were performed in this function. */ int mults = 0; /* How many randomization steps to apply to the input list. */ - int rands = (int)rustsecp256k1zkp_v0_8_0_testrand_bits(3); + int rands = (int)testrand_bits(3); if (rands > num_nonzero) rands = num_nonzero; - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&expected); - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&gejs[0]); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&scalars[0], 0); + rustsecp256k1_v0_11_gej_set_infinity(&expected); + rustsecp256k1_v0_11_gej_set_infinity(&gejs[0]); + rustsecp256k1_v0_11_scalar_set_int(&scalars[0], 0); if (g_nonzero) { /* If g_nonzero, set g_scalar to nonzero value r. */ - random_scalar_order_test(&g_scalar); + testutil_random_scalar_order_test(&g_scalar); if (!nonzero_result) { /* If expected=0 is desired, add a (a*r, -(1/a)*g) term to compensate. */ CHECK(num_nonzero > filled); - random_scalar_order_test(&sc_tmp); - rustsecp256k1zkp_v0_8_0_scalar_mul(&scalars[filled], &sc_tmp, &g_scalar); - rustsecp256k1zkp_v0_8_0_scalar_inverse_var(&sc_tmp, &sc_tmp); - rustsecp256k1zkp_v0_8_0_scalar_negate(&sc_tmp, &sc_tmp); - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &gejs[filled], &sc_tmp); + testutil_random_scalar_order_test(&sc_tmp); + rustsecp256k1_v0_11_scalar_mul(&scalars[filled], &sc_tmp, &g_scalar); + rustsecp256k1_v0_11_scalar_inverse_var(&sc_tmp, &sc_tmp); + rustsecp256k1_v0_11_scalar_negate(&sc_tmp, &sc_tmp); + rustsecp256k1_v0_11_ecmult_gen(&CTX->ecmult_gen_ctx, &gejs[filled], &sc_tmp); ++filled; ++mults; } @@ -4629,16 +4932,16 @@ int test_ecmult_multi_random(rustsecp256k1zkp_v0_8_0_scratch *scratch) { if (nonzero_result && filled < num_nonzero) { /* If a nonzero result is desired, and there is space, add a random nonzero term. */ - random_scalar_order_test(&scalars[filled]); - random_group_element_test(&ge_tmp); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&gejs[filled], &ge_tmp); + testutil_random_scalar_order_test(&scalars[filled]); + testutil_random_ge_test(&ge_tmp); + rustsecp256k1_v0_11_gej_set_ge(&gejs[filled], &ge_tmp); ++filled; } if (nonzero_result) { /* Compute the expected result using normal ecmult. */ CHECK(filled <= 1); - rustsecp256k1zkp_v0_8_0_ecmult(&expected, &gejs[0], &scalars[0], &g_scalar); + rustsecp256k1_v0_11_ecmult(&expected, &gejs[0], &scalars[0], &g_scalar); mults += filled + g_nonzero; } @@ -4649,13 +4952,13 @@ int test_ecmult_multi_random(rustsecp256k1zkp_v0_8_0_scratch *scratch) { /* Add entries to scalars,gejs so that there are num of them. All the added entries * either have scalar=0 or point=infinity, so these do not change the expected result. */ while (filled < num) { - if (rustsecp256k1zkp_v0_8_0_testrand_bits(1)) { - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&gejs[filled]); - random_scalar_order_test(&scalars[filled]); + if (testrand_bits(1)) { + rustsecp256k1_v0_11_gej_set_infinity(&gejs[filled]); + testutil_random_scalar_order_test(&scalars[filled]); } else { - rustsecp256k1zkp_v0_8_0_scalar_set_int(&scalars[filled], 0); - random_group_element_test(&ge_tmp); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&gejs[filled], &ge_tmp); + rustsecp256k1_v0_11_scalar_set_int(&scalars[filled], 0); + testutil_random_ge_test(&ge_tmp); + rustsecp256k1_v0_11_gej_set_ge(&gejs[filled], &ge_tmp); } ++filled; } @@ -4665,13 +4968,13 @@ int test_ecmult_multi_random(rustsecp256k1zkp_v0_8_0_scratch *scratch) { * convert some of them to be both non-0-scalar and non-infinity-point. */ for (i = 0; i < rands; ++i) { int j; - rustsecp256k1zkp_v0_8_0_scalar v, iv; + rustsecp256k1_v0_11_scalar v, iv; /* Shuffle the entries. */ for (j = 0; j < num_nonzero; ++j) { - int k = rustsecp256k1zkp_v0_8_0_testrand_int(num_nonzero - j); + int k = testrand_int(num_nonzero - j); if (k != 0) { - rustsecp256k1zkp_v0_8_0_gej gej = gejs[j]; - rustsecp256k1zkp_v0_8_0_scalar sc = scalars[j]; + rustsecp256k1_v0_11_gej gej = gejs[j]; + rustsecp256k1_v0_11_scalar sc = scalars[j]; gejs[j] = gejs[j + k]; scalars[j] = scalars[j + k]; gejs[j + k] = gej; @@ -4681,26 +4984,26 @@ int test_ecmult_multi_random(rustsecp256k1zkp_v0_8_0_scratch *scratch) { /* Perturb all consecutive pairs of inputs: * a*P + b*Q -> (a+b)*P + b*(Q-P). */ for (j = 0; j + 1 < num_nonzero; j += 2) { - rustsecp256k1zkp_v0_8_0_gej gej; - rustsecp256k1zkp_v0_8_0_scalar_add(&scalars[j], &scalars[j], &scalars[j+1]); - rustsecp256k1zkp_v0_8_0_gej_neg(&gej, &gejs[j]); - rustsecp256k1zkp_v0_8_0_gej_add_var(&gejs[j+1], &gejs[j+1], &gej, NULL); + rustsecp256k1_v0_11_gej gej; + rustsecp256k1_v0_11_scalar_add(&scalars[j], &scalars[j], &scalars[j+1]); + rustsecp256k1_v0_11_gej_neg(&gej, &gejs[j]); + rustsecp256k1_v0_11_gej_add_var(&gejs[j+1], &gejs[j+1], &gej, NULL); } /* Transform the last input: a*P -> (v*a) * ((1/v)*P). */ CHECK(num_nonzero >= 1); - random_scalar_order_test(&v); - rustsecp256k1zkp_v0_8_0_scalar_inverse(&iv, &v); - rustsecp256k1zkp_v0_8_0_scalar_mul(&scalars[num_nonzero - 1], &scalars[num_nonzero - 1], &v); - rustsecp256k1zkp_v0_8_0_ecmult(&gejs[num_nonzero - 1], &gejs[num_nonzero - 1], &iv, NULL); + testutil_random_scalar_order_test(&v); + rustsecp256k1_v0_11_scalar_inverse(&iv, &v); + rustsecp256k1_v0_11_scalar_mul(&scalars[num_nonzero - 1], &scalars[num_nonzero - 1], &v); + rustsecp256k1_v0_11_ecmult(&gejs[num_nonzero - 1], &gejs[num_nonzero - 1], &iv, NULL); ++mults; } /* Shuffle all entries (0..num-1). */ for (i = 0; i < num; ++i) { - int j = rustsecp256k1zkp_v0_8_0_testrand_int(num - i); + int j = testrand_int(num - i); if (j != 0) { - rustsecp256k1zkp_v0_8_0_gej gej = gejs[i]; - rustsecp256k1zkp_v0_8_0_scalar sc = scalars[i]; + rustsecp256k1_v0_11_gej gej = gejs[i]; + rustsecp256k1_v0_11_scalar sc = scalars[i]; gejs[i] = gejs[i + j]; scalars[i] = scalars[i + j]; gejs[i + j] = gej; @@ -4709,51 +5012,47 @@ int test_ecmult_multi_random(rustsecp256k1zkp_v0_8_0_scratch *scratch) { } /* Compute affine versions of all inputs. */ - rustsecp256k1zkp_v0_8_0_ge_set_all_gej_var(ges, gejs, filled); + rustsecp256k1_v0_11_ge_set_all_gej_var(ges, gejs, filled); /* Invoke ecmult_multi code. */ data.sc = scalars; data.pt = ges; - CHECK(ecmult_multi(&ctx->error_callback, scratch, &computed, g_scalar_ptr, ecmult_multi_callback, &data, filled)); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &computed, g_scalar_ptr, ecmult_multi_callback, &data, filled)); mults += num_nonzero + g_nonzero; /* Compare with expected result. */ - rustsecp256k1zkp_v0_8_0_gej_neg(&computed, &computed); - rustsecp256k1zkp_v0_8_0_gej_add_var(&computed, &computed, &expected, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&computed)); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&computed, &expected)); return mults; } -void test_ecmult_multi_batch_single(rustsecp256k1zkp_v0_8_0_ecmult_multi_func ecmult_multi) { - rustsecp256k1zkp_v0_8_0_scalar szero; - rustsecp256k1zkp_v0_8_0_scalar sc; - rustsecp256k1zkp_v0_8_0_ge pt; - rustsecp256k1zkp_v0_8_0_gej r; +static void test_ecmult_multi_batch_single(rustsecp256k1_v0_11_ecmult_multi_func ecmult_multi) { + rustsecp256k1_v0_11_scalar sc; + rustsecp256k1_v0_11_ge pt; + rustsecp256k1_v0_11_gej r; ecmult_multi_data data; - rustsecp256k1zkp_v0_8_0_scratch *scratch_empty; + rustsecp256k1_v0_11_scratch *scratch_empty; - random_group_element_test(&pt); - random_scalar_order(&sc); + testutil_random_ge_test(&pt); + testutil_random_scalar_order(&sc); data.sc = ≻ data.pt = &pt; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&szero, 0); /* Try to multiply 1 point, but scratch space is empty.*/ - scratch_empty = rustsecp256k1zkp_v0_8_0_scratch_create(&ctx->error_callback, 0); - CHECK(!ecmult_multi(&ctx->error_callback, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1)); - rustsecp256k1zkp_v0_8_0_scratch_destroy(&ctx->error_callback, scratch_empty); + scratch_empty = rustsecp256k1_v0_11_scratch_create(&CTX->error_callback, 0); + CHECK(!ecmult_multi(&CTX->error_callback, scratch_empty, &r, &rustsecp256k1_v0_11_scalar_zero, ecmult_multi_callback, &data, 1)); + rustsecp256k1_v0_11_scratch_destroy(&CTX->error_callback, scratch_empty); } -void test_rustsecp256k1zkp_v0_8_0_pippenger_bucket_window_inv(void) { +static void test_rustsecp256k1_v0_11_pippenger_bucket_window_inv(void) { int i; - CHECK(rustsecp256k1zkp_v0_8_0_pippenger_bucket_window_inv(0) == 0); + CHECK(rustsecp256k1_v0_11_pippenger_bucket_window_inv(0) == 0); for(i = 1; i <= PIPPENGER_MAX_BUCKET_WINDOW; i++) { /* Bucket_window of 8 is not used with endo */ if (i == 8) { continue; } - CHECK(rustsecp256k1zkp_v0_8_0_pippenger_bucket_window(rustsecp256k1zkp_v0_8_0_pippenger_bucket_window_inv(i)) == i); + CHECK(rustsecp256k1_v0_11_pippenger_bucket_window(rustsecp256k1_v0_11_pippenger_bucket_window_inv(i)) == i); if (i != PIPPENGER_MAX_BUCKET_WINDOW) { - CHECK(rustsecp256k1zkp_v0_8_0_pippenger_bucket_window(rustsecp256k1zkp_v0_8_0_pippenger_bucket_window_inv(i)+1) > i); + CHECK(rustsecp256k1_v0_11_pippenger_bucket_window(rustsecp256k1_v0_11_pippenger_bucket_window_inv(i)+1) > i); } } } @@ -4762,10 +5061,10 @@ void test_rustsecp256k1zkp_v0_8_0_pippenger_bucket_window_inv(void) { * Probabilistically test the function returning the maximum number of possible points * for a given scratch space. */ -void test_ecmult_multi_pippenger_max_points(void) { - size_t scratch_size = rustsecp256k1zkp_v0_8_0_testrand_bits(8); - size_t max_size = rustsecp256k1zkp_v0_8_0_pippenger_scratch_size(rustsecp256k1zkp_v0_8_0_pippenger_bucket_window_inv(PIPPENGER_MAX_BUCKET_WINDOW-1)+512, 12); - rustsecp256k1zkp_v0_8_0_scratch *scratch; +static void test_ecmult_multi_pippenger_max_points(void) { + size_t scratch_size = testrand_bits(8); + size_t max_size = rustsecp256k1_v0_11_pippenger_scratch_size(rustsecp256k1_v0_11_pippenger_bucket_window_inv(PIPPENGER_MAX_BUCKET_WINDOW-1)+512, 12); + rustsecp256k1_v0_11_scratch *scratch; size_t n_points_supported; int bucket_window = 0; @@ -4773,183 +5072,181 @@ void test_ecmult_multi_pippenger_max_points(void) { size_t i; size_t total_alloc; size_t checkpoint; - scratch = rustsecp256k1zkp_v0_8_0_scratch_create(&ctx->error_callback, scratch_size); + scratch = rustsecp256k1_v0_11_scratch_create(&CTX->error_callback, scratch_size); CHECK(scratch != NULL); - checkpoint = rustsecp256k1zkp_v0_8_0_scratch_checkpoint(&ctx->error_callback, scratch); - n_points_supported = rustsecp256k1zkp_v0_8_0_pippenger_max_points(&ctx->error_callback, scratch); + checkpoint = rustsecp256k1_v0_11_scratch_checkpoint(&CTX->error_callback, scratch); + n_points_supported = rustsecp256k1_v0_11_pippenger_max_points(&CTX->error_callback, scratch); if (n_points_supported == 0) { - rustsecp256k1zkp_v0_8_0_scratch_destroy(&ctx->error_callback, scratch); + rustsecp256k1_v0_11_scratch_destroy(&CTX->error_callback, scratch); continue; } - bucket_window = rustsecp256k1zkp_v0_8_0_pippenger_bucket_window(n_points_supported); + bucket_window = rustsecp256k1_v0_11_pippenger_bucket_window(n_points_supported); /* allocate `total_alloc` bytes over `PIPPENGER_SCRATCH_OBJECTS` many allocations */ - total_alloc = rustsecp256k1zkp_v0_8_0_pippenger_scratch_size(n_points_supported, bucket_window); + total_alloc = rustsecp256k1_v0_11_pippenger_scratch_size(n_points_supported, bucket_window); for (i = 0; i < PIPPENGER_SCRATCH_OBJECTS - 1; i++) { - CHECK(rustsecp256k1zkp_v0_8_0_scratch_alloc(&ctx->error_callback, scratch, 1)); + CHECK(rustsecp256k1_v0_11_scratch_alloc(&CTX->error_callback, scratch, 1)); total_alloc--; } - CHECK(rustsecp256k1zkp_v0_8_0_scratch_alloc(&ctx->error_callback, scratch, total_alloc)); - rustsecp256k1zkp_v0_8_0_scratch_apply_checkpoint(&ctx->error_callback, scratch, checkpoint); - rustsecp256k1zkp_v0_8_0_scratch_destroy(&ctx->error_callback, scratch); + CHECK(rustsecp256k1_v0_11_scratch_alloc(&CTX->error_callback, scratch, total_alloc)); + rustsecp256k1_v0_11_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint); + rustsecp256k1_v0_11_scratch_destroy(&CTX->error_callback, scratch); } CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW); } -void test_ecmult_multi_batch_size_helper(void) { +static void test_ecmult_multi_batch_size_helper(void) { size_t n_batches, n_batch_points, max_n_batch_points, n; max_n_batch_points = 0; n = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 0); + CHECK(rustsecp256k1_v0_11_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 0); max_n_batch_points = 1; n = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(rustsecp256k1_v0_11_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); CHECK(n_batches == 0); CHECK(n_batch_points == 0); max_n_batch_points = 2; n = 5; - CHECK(rustsecp256k1zkp_v0_8_0_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(rustsecp256k1_v0_11_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); CHECK(n_batches == 3); CHECK(n_batch_points == 2); max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH; n = ECMULT_MAX_POINTS_PER_BATCH; - CHECK(rustsecp256k1zkp_v0_8_0_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(rustsecp256k1_v0_11_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); CHECK(n_batches == 1); CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH); max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH + 1; n = ECMULT_MAX_POINTS_PER_BATCH + 1; - CHECK(rustsecp256k1zkp_v0_8_0_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(rustsecp256k1_v0_11_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); CHECK(n_batches == 2); CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH/2 + 1); max_n_batch_points = 1; n = SIZE_MAX; - CHECK(rustsecp256k1zkp_v0_8_0_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(rustsecp256k1_v0_11_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); CHECK(n_batches == SIZE_MAX); CHECK(n_batch_points == 1); max_n_batch_points = 2; n = SIZE_MAX; - CHECK(rustsecp256k1zkp_v0_8_0_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(rustsecp256k1_v0_11_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); CHECK(n_batches == SIZE_MAX/2 + 1); CHECK(n_batch_points == 2); } /** - * Run rustsecp256k1zkp_v0_8_0_ecmult_multi_var with num points and a scratch space restricted to + * Run rustsecp256k1_v0_11_ecmult_multi_var with num points and a scratch space restricted to * 1 <= i <= num points. */ -void test_ecmult_multi_batching(void) { +static void test_ecmult_multi_batching(void) { static const int n_points = 2*ECMULT_PIPPENGER_THRESHOLD; - rustsecp256k1zkp_v0_8_0_scalar scG; - rustsecp256k1zkp_v0_8_0_scalar szero; - rustsecp256k1zkp_v0_8_0_scalar *sc = (rustsecp256k1zkp_v0_8_0_scalar *)checked_malloc(&ctx->error_callback, sizeof(rustsecp256k1zkp_v0_8_0_scalar) * n_points); - rustsecp256k1zkp_v0_8_0_ge *pt = (rustsecp256k1zkp_v0_8_0_ge *)checked_malloc(&ctx->error_callback, sizeof(rustsecp256k1zkp_v0_8_0_ge) * n_points); - rustsecp256k1zkp_v0_8_0_gej r; - rustsecp256k1zkp_v0_8_0_gej r2; + rustsecp256k1_v0_11_scalar scG; + rustsecp256k1_v0_11_scalar *sc = (rustsecp256k1_v0_11_scalar *)checked_malloc(&CTX->error_callback, sizeof(rustsecp256k1_v0_11_scalar) * n_points); + rustsecp256k1_v0_11_ge *pt = (rustsecp256k1_v0_11_ge *)checked_malloc(&CTX->error_callback, sizeof(rustsecp256k1_v0_11_ge) * n_points); + rustsecp256k1_v0_11_gej r; + rustsecp256k1_v0_11_gej r2; ecmult_multi_data data; int i; - rustsecp256k1zkp_v0_8_0_scratch *scratch; + rustsecp256k1_v0_11_scratch *scratch; - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&r2); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&szero, 0); + rustsecp256k1_v0_11_gej_set_infinity(&r2); /* Get random scalars and group elements and compute result */ - random_scalar_order(&scG); - rustsecp256k1zkp_v0_8_0_ecmult(&r2, &r2, &szero, &scG); + testutil_random_scalar_order(&scG); + rustsecp256k1_v0_11_ecmult(&r2, &r2, &rustsecp256k1_v0_11_scalar_zero, &scG); for(i = 0; i < n_points; i++) { - rustsecp256k1zkp_v0_8_0_ge ptg; - rustsecp256k1zkp_v0_8_0_gej ptgj; - random_group_element_test(&ptg); - rustsecp256k1zkp_v0_8_0_gej_set_ge(&ptgj, &ptg); + rustsecp256k1_v0_11_ge ptg; + rustsecp256k1_v0_11_gej ptgj; + testutil_random_ge_test(&ptg); + rustsecp256k1_v0_11_gej_set_ge(&ptgj, &ptg); pt[i] = ptg; - random_scalar_order(&sc[i]); - rustsecp256k1zkp_v0_8_0_ecmult(&ptgj, &ptgj, &sc[i], NULL); - rustsecp256k1zkp_v0_8_0_gej_add_var(&r2, &r2, &ptgj, NULL); + testutil_random_scalar_order(&sc[i]); + rustsecp256k1_v0_11_ecmult(&ptgj, &ptgj, &sc[i], NULL); + rustsecp256k1_v0_11_gej_add_var(&r2, &r2, &ptgj, NULL); } data.sc = sc; data.pt = pt; - rustsecp256k1zkp_v0_8_0_gej_neg(&r2, &r2); + rustsecp256k1_v0_11_gej_neg(&r2, &r2); /* Test with empty scratch space. It should compute the correct result using * ecmult_mult_simple algorithm which doesn't require a scratch space. */ - scratch = rustsecp256k1zkp_v0_8_0_scratch_create(&ctx->error_callback, 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecmult_multi_var(&ctx->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); - rustsecp256k1zkp_v0_8_0_gej_add_var(&r, &r, &r2, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); - rustsecp256k1zkp_v0_8_0_scratch_destroy(&ctx->error_callback, scratch); + scratch = rustsecp256k1_v0_11_scratch_create(&CTX->error_callback, 0); + CHECK(rustsecp256k1_v0_11_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); + rustsecp256k1_v0_11_gej_add_var(&r, &r, &r2, NULL); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&r)); + rustsecp256k1_v0_11_scratch_destroy(&CTX->error_callback, scratch); /* Test with space for 1 point in pippenger. That's not enough because * ecmult_multi selects strauss which requires more memory. It should * therefore select the simple algorithm. */ - scratch = rustsecp256k1zkp_v0_8_0_scratch_create(&ctx->error_callback, rustsecp256k1zkp_v0_8_0_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); - CHECK(rustsecp256k1zkp_v0_8_0_ecmult_multi_var(&ctx->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); - rustsecp256k1zkp_v0_8_0_gej_add_var(&r, &r, &r2, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); - rustsecp256k1zkp_v0_8_0_scratch_destroy(&ctx->error_callback, scratch); + scratch = rustsecp256k1_v0_11_scratch_create(&CTX->error_callback, rustsecp256k1_v0_11_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); + CHECK(rustsecp256k1_v0_11_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); + rustsecp256k1_v0_11_gej_add_var(&r, &r, &r2, NULL); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&r)); + rustsecp256k1_v0_11_scratch_destroy(&CTX->error_callback, scratch); for(i = 1; i <= n_points; i++) { if (i > ECMULT_PIPPENGER_THRESHOLD) { - int bucket_window = rustsecp256k1zkp_v0_8_0_pippenger_bucket_window(i); - size_t scratch_size = rustsecp256k1zkp_v0_8_0_pippenger_scratch_size(i, bucket_window); - scratch = rustsecp256k1zkp_v0_8_0_scratch_create(&ctx->error_callback, scratch_size + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); + int bucket_window = rustsecp256k1_v0_11_pippenger_bucket_window(i); + size_t scratch_size = rustsecp256k1_v0_11_pippenger_scratch_size(i, bucket_window); + scratch = rustsecp256k1_v0_11_scratch_create(&CTX->error_callback, scratch_size + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); } else { - size_t scratch_size = rustsecp256k1zkp_v0_8_0_strauss_scratch_size(i); - scratch = rustsecp256k1zkp_v0_8_0_scratch_create(&ctx->error_callback, scratch_size + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); + size_t scratch_size = rustsecp256k1_v0_11_strauss_scratch_size(i); + scratch = rustsecp256k1_v0_11_scratch_create(&CTX->error_callback, scratch_size + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); } - CHECK(rustsecp256k1zkp_v0_8_0_ecmult_multi_var(&ctx->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); - rustsecp256k1zkp_v0_8_0_gej_add_var(&r, &r, &r2, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_gej_is_infinity(&r)); - rustsecp256k1zkp_v0_8_0_scratch_destroy(&ctx->error_callback, scratch); + CHECK(rustsecp256k1_v0_11_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); + rustsecp256k1_v0_11_gej_add_var(&r, &r, &r2, NULL); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&r)); + rustsecp256k1_v0_11_scratch_destroy(&CTX->error_callback, scratch); } free(sc); free(pt); } -void run_ecmult_multi_tests(void) { - rustsecp256k1zkp_v0_8_0_scratch *scratch; - int64_t todo = (int64_t)320 * count; +static void run_ecmult_multi_tests(void) { + rustsecp256k1_v0_11_scratch *scratch; + int64_t todo = (int64_t)320 * COUNT; - test_rustsecp256k1zkp_v0_8_0_pippenger_bucket_window_inv(); + test_rustsecp256k1_v0_11_pippenger_bucket_window_inv(); test_ecmult_multi_pippenger_max_points(); - scratch = rustsecp256k1zkp_v0_8_0_scratch_create(&ctx->error_callback, 819200); - test_ecmult_multi(scratch, rustsecp256k1zkp_v0_8_0_ecmult_multi_var); - test_ecmult_multi(NULL, rustsecp256k1zkp_v0_8_0_ecmult_multi_var); - test_ecmult_multi(scratch, rustsecp256k1zkp_v0_8_0_ecmult_pippenger_batch_single); - test_ecmult_multi_batch_single(rustsecp256k1zkp_v0_8_0_ecmult_pippenger_batch_single); - test_ecmult_multi(scratch, rustsecp256k1zkp_v0_8_0_ecmult_strauss_batch_single); - test_ecmult_multi_batch_single(rustsecp256k1zkp_v0_8_0_ecmult_strauss_batch_single); + scratch = rustsecp256k1_v0_11_scratch_create(&CTX->error_callback, 819200); + test_ecmult_multi(scratch, rustsecp256k1_v0_11_ecmult_multi_var); + test_ecmult_multi(NULL, rustsecp256k1_v0_11_ecmult_multi_var); + test_ecmult_multi(scratch, rustsecp256k1_v0_11_ecmult_pippenger_batch_single); + test_ecmult_multi_batch_single(rustsecp256k1_v0_11_ecmult_pippenger_batch_single); + test_ecmult_multi(scratch, rustsecp256k1_v0_11_ecmult_strauss_batch_single); + test_ecmult_multi_batch_single(rustsecp256k1_v0_11_ecmult_strauss_batch_single); while (todo > 0) { todo -= test_ecmult_multi_random(scratch); } - rustsecp256k1zkp_v0_8_0_scratch_destroy(&ctx->error_callback, scratch); + rustsecp256k1_v0_11_scratch_destroy(&CTX->error_callback, scratch); /* Run test_ecmult_multi with space for exactly one point */ - scratch = rustsecp256k1zkp_v0_8_0_scratch_create(&ctx->error_callback, rustsecp256k1zkp_v0_8_0_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); - test_ecmult_multi(scratch, rustsecp256k1zkp_v0_8_0_ecmult_multi_var); - rustsecp256k1zkp_v0_8_0_scratch_destroy(&ctx->error_callback, scratch); + scratch = rustsecp256k1_v0_11_scratch_create(&CTX->error_callback, rustsecp256k1_v0_11_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); + test_ecmult_multi(scratch, rustsecp256k1_v0_11_ecmult_multi_var); + rustsecp256k1_v0_11_scratch_destroy(&CTX->error_callback, scratch); test_ecmult_multi_batch_size_helper(); test_ecmult_multi_batching(); } -void test_wnaf(const rustsecp256k1zkp_v0_8_0_scalar *number, int w) { - rustsecp256k1zkp_v0_8_0_scalar x, two, t; +static void test_wnaf(const rustsecp256k1_v0_11_scalar *number, int w) { + rustsecp256k1_v0_11_scalar x, two, t; int wnaf[256]; int zeroes = -1; int i; int bits; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&x, 0); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&two, 2); - bits = rustsecp256k1zkp_v0_8_0_ecmult_wnaf(wnaf, 256, number, w); + rustsecp256k1_v0_11_scalar_set_int(&x, 0); + rustsecp256k1_v0_11_scalar_set_int(&two, 2); + bits = rustsecp256k1_v0_11_ecmult_wnaf(wnaf, 256, number, w); CHECK(bits <= 256); for (i = bits-1; i >= 0; i--) { int v = wnaf[i]; - rustsecp256k1zkp_v0_8_0_scalar_mul(&x, &x, &two); + rustsecp256k1_v0_11_scalar_mul(&x, &x, &two); if (v) { CHECK(zeroes == -1 || zeroes >= w-1); /* check that distance between non-zero elements is at least w-1 */ zeroes=0; @@ -4961,109 +5258,53 @@ void test_wnaf(const rustsecp256k1zkp_v0_8_0_scalar *number, int w) { zeroes++; } if (v >= 0) { - rustsecp256k1zkp_v0_8_0_scalar_set_int(&t, v); - } else { - rustsecp256k1zkp_v0_8_0_scalar_set_int(&t, -v); - rustsecp256k1zkp_v0_8_0_scalar_negate(&t, &t); - } - rustsecp256k1zkp_v0_8_0_scalar_add(&x, &x, &t); - } - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&x, number)); /* check that wnaf represents number */ -} - -void test_constant_wnaf_negate(const rustsecp256k1zkp_v0_8_0_scalar *number) { - rustsecp256k1zkp_v0_8_0_scalar neg1 = *number; - rustsecp256k1zkp_v0_8_0_scalar neg2 = *number; - int sign1 = 1; - int sign2 = 1; - - if (!rustsecp256k1zkp_v0_8_0_scalar_get_bits(&neg1, 0, 1)) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&neg1, &neg1); - sign1 = -1; - } - sign2 = rustsecp256k1zkp_v0_8_0_scalar_cond_negate(&neg2, rustsecp256k1zkp_v0_8_0_scalar_is_even(&neg2)); - CHECK(sign1 == sign2); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&neg1, &neg2)); -} - -void test_constant_wnaf(const rustsecp256k1zkp_v0_8_0_scalar *number, int w) { - rustsecp256k1zkp_v0_8_0_scalar x, shift; - int wnaf[256] = {0}; - int i; - int skew; - int bits = 256; - rustsecp256k1zkp_v0_8_0_scalar num = *number; - rustsecp256k1zkp_v0_8_0_scalar scalar_skew; - - rustsecp256k1zkp_v0_8_0_scalar_set_int(&x, 0); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&shift, 1 << w); - for (i = 0; i < 16; ++i) { - rustsecp256k1zkp_v0_8_0_scalar_shr_int(&num, 8); - } - bits = 128; - skew = rustsecp256k1zkp_v0_8_0_wnaf_const(wnaf, &num, w, bits); - - for (i = WNAF_SIZE_BITS(bits, w); i >= 0; --i) { - rustsecp256k1zkp_v0_8_0_scalar t; - int v = wnaf[i]; - CHECK(v != 0); /* check nonzero */ - CHECK(v & 1); /* check parity */ - CHECK(v > -(1 << w)); /* check range above */ - CHECK(v < (1 << w)); /* check range below */ - - rustsecp256k1zkp_v0_8_0_scalar_mul(&x, &x, &shift); - if (v >= 0) { - rustsecp256k1zkp_v0_8_0_scalar_set_int(&t, v); + rustsecp256k1_v0_11_scalar_set_int(&t, v); } else { - rustsecp256k1zkp_v0_8_0_scalar_set_int(&t, -v); - rustsecp256k1zkp_v0_8_0_scalar_negate(&t, &t); + rustsecp256k1_v0_11_scalar_set_int(&t, -v); + rustsecp256k1_v0_11_scalar_negate(&t, &t); } - rustsecp256k1zkp_v0_8_0_scalar_add(&x, &x, &t); + rustsecp256k1_v0_11_scalar_add(&x, &x, &t); } - /* Skew num because when encoding numbers as odd we use an offset */ - rustsecp256k1zkp_v0_8_0_scalar_set_int(&scalar_skew, skew); - rustsecp256k1zkp_v0_8_0_scalar_add(&num, &num, &scalar_skew); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&x, &num)); + CHECK(rustsecp256k1_v0_11_scalar_eq(&x, number)); /* check that wnaf represents number */ } -void test_fixed_wnaf(const rustsecp256k1zkp_v0_8_0_scalar *number, int w) { - rustsecp256k1zkp_v0_8_0_scalar x, shift; +static void test_fixed_wnaf(const rustsecp256k1_v0_11_scalar *number, int w) { + rustsecp256k1_v0_11_scalar x, shift; int wnaf[256] = {0}; int i; int skew; - rustsecp256k1zkp_v0_8_0_scalar num = *number; + rustsecp256k1_v0_11_scalar num, unused; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&x, 0); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&shift, 1 << w); - for (i = 0; i < 16; ++i) { - rustsecp256k1zkp_v0_8_0_scalar_shr_int(&num, 8); - } - skew = rustsecp256k1zkp_v0_8_0_wnaf_fixed(wnaf, &num, w); + rustsecp256k1_v0_11_scalar_set_int(&x, 0); + rustsecp256k1_v0_11_scalar_set_int(&shift, 1 << w); + /* Make num a 128-bit scalar. */ + rustsecp256k1_v0_11_scalar_split_128(&num, &unused, number); + skew = rustsecp256k1_v0_11_wnaf_fixed(wnaf, &num, w); for (i = WNAF_SIZE(w)-1; i >= 0; --i) { - rustsecp256k1zkp_v0_8_0_scalar t; + rustsecp256k1_v0_11_scalar t; int v = wnaf[i]; CHECK(v == 0 || v & 1); /* check parity */ CHECK(v > -(1 << w)); /* check range above */ CHECK(v < (1 << w)); /* check range below */ - rustsecp256k1zkp_v0_8_0_scalar_mul(&x, &x, &shift); + rustsecp256k1_v0_11_scalar_mul(&x, &x, &shift); if (v >= 0) { - rustsecp256k1zkp_v0_8_0_scalar_set_int(&t, v); + rustsecp256k1_v0_11_scalar_set_int(&t, v); } else { - rustsecp256k1zkp_v0_8_0_scalar_set_int(&t, -v); - rustsecp256k1zkp_v0_8_0_scalar_negate(&t, &t); + rustsecp256k1_v0_11_scalar_set_int(&t, -v); + rustsecp256k1_v0_11_scalar_negate(&t, &t); } - rustsecp256k1zkp_v0_8_0_scalar_add(&x, &x, &t); + rustsecp256k1_v0_11_scalar_add(&x, &x, &t); } /* If skew is 1 then add 1 to num */ - rustsecp256k1zkp_v0_8_0_scalar_cadd_bit(&num, 0, skew == 1); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&x, &num)); + rustsecp256k1_v0_11_scalar_cadd_bit(&num, 0, skew == 1); + CHECK(rustsecp256k1_v0_11_scalar_eq(&x, &num)); } /* Checks that the first 8 elements of wnaf are equal to wnaf_expected and the * rest is 0.*/ -void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) { +static void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) { int i; for (i = WNAF_SIZE(w)-1; i >= 8; --i) { CHECK(wnaf[i] == 0); @@ -5073,23 +5314,23 @@ void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) { } } -void test_fixed_wnaf_small(void) { +static void test_fixed_wnaf_small(void) { int w = 4; int wnaf[256] = {0}; int i; int skew; - rustsecp256k1zkp_v0_8_0_scalar num; + rustsecp256k1_v0_11_scalar num; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&num, 0); - skew = rustsecp256k1zkp_v0_8_0_wnaf_fixed(wnaf, &num, w); + rustsecp256k1_v0_11_scalar_set_int(&num, 0); + skew = rustsecp256k1_v0_11_wnaf_fixed(wnaf, &num, w); for (i = WNAF_SIZE(w)-1; i >= 0; --i) { int v = wnaf[i]; CHECK(v == 0); } CHECK(skew == 0); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&num, 1); - skew = rustsecp256k1zkp_v0_8_0_wnaf_fixed(wnaf, &num, w); + rustsecp256k1_v0_11_scalar_set_int(&num, 1); + skew = rustsecp256k1_v0_11_wnaf_fixed(wnaf, &num, w); for (i = WNAF_SIZE(w)-1; i >= 1; --i) { int v = wnaf[i]; CHECK(v == 0); @@ -5099,122 +5340,94 @@ void test_fixed_wnaf_small(void) { { int wnaf_expected[8] = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&num, 0xffffffff); - skew = rustsecp256k1zkp_v0_8_0_wnaf_fixed(wnaf, &num, w); + rustsecp256k1_v0_11_scalar_set_int(&num, 0xffffffff); + skew = rustsecp256k1_v0_11_wnaf_fixed(wnaf, &num, w); test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); CHECK(skew == 0); } { int wnaf_expected[8] = { -1, -1, -1, -1, -1, -1, -1, 0xf }; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&num, 0xeeeeeeee); - skew = rustsecp256k1zkp_v0_8_0_wnaf_fixed(wnaf, &num, w); + rustsecp256k1_v0_11_scalar_set_int(&num, 0xeeeeeeee); + skew = rustsecp256k1_v0_11_wnaf_fixed(wnaf, &num, w); test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); CHECK(skew == 1); } { int wnaf_expected[8] = { 1, 0, 1, 0, 1, 0, 1, 0 }; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&num, 0x01010101); - skew = rustsecp256k1zkp_v0_8_0_wnaf_fixed(wnaf, &num, w); + rustsecp256k1_v0_11_scalar_set_int(&num, 0x01010101); + skew = rustsecp256k1_v0_11_wnaf_fixed(wnaf, &num, w); test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); CHECK(skew == 0); } { int wnaf_expected[8] = { -0xf, 0, 0xf, -0xf, 0, 0xf, 1, 0 }; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&num, 0x01ef1ef1); - skew = rustsecp256k1zkp_v0_8_0_wnaf_fixed(wnaf, &num, w); + rustsecp256k1_v0_11_scalar_set_int(&num, 0x01ef1ef1); + skew = rustsecp256k1_v0_11_wnaf_fixed(wnaf, &num, w); test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); CHECK(skew == 0); } } -void run_wnaf(void) { +static void run_wnaf(void) { int i; - rustsecp256k1zkp_v0_8_0_scalar n = {{0}}; - - test_constant_wnaf(&n, 4); - /* Sanity check: 1 and 2 are the smallest odd and even numbers and should - * have easier-to-diagnose failure modes */ - n.d[0] = 1; - test_constant_wnaf(&n, 4); - n.d[0] = 2; - test_constant_wnaf(&n, 4); - /* Test -1, because it's a special case in wnaf_const */ - n = rustsecp256k1zkp_v0_8_0_scalar_one; - rustsecp256k1zkp_v0_8_0_scalar_negate(&n, &n); - test_constant_wnaf(&n, 4); - - /* Test -2, which may not lead to overflows in wnaf_const */ - rustsecp256k1zkp_v0_8_0_scalar_add(&n, &rustsecp256k1zkp_v0_8_0_scalar_one, &rustsecp256k1zkp_v0_8_0_scalar_one); - rustsecp256k1zkp_v0_8_0_scalar_negate(&n, &n); - test_constant_wnaf(&n, 4); - - /* Test (1/2) - 1 = 1/-2 and 1/2 = (1/-2) + 1 - as corner cases of negation handling in wnaf_const */ - rustsecp256k1zkp_v0_8_0_scalar_inverse(&n, &n); - test_constant_wnaf(&n, 4); - - rustsecp256k1zkp_v0_8_0_scalar_add(&n, &n, &rustsecp256k1zkp_v0_8_0_scalar_one); - test_constant_wnaf(&n, 4); + rustsecp256k1_v0_11_scalar n; /* Test 0 for fixed wnaf */ test_fixed_wnaf_small(); /* Random tests */ - for (i = 0; i < count; i++) { - random_scalar_order(&n); + for (i = 0; i < COUNT; i++) { + testutil_random_scalar_order(&n); test_wnaf(&n, 4+(i%10)); - test_constant_wnaf_negate(&n); - test_constant_wnaf(&n, 4 + (i % 10)); test_fixed_wnaf(&n, 4 + (i % 10)); } - rustsecp256k1zkp_v0_8_0_scalar_set_int(&n, 0); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_cond_negate(&n, 1) == -1); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_is_zero(&n)); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_cond_negate(&n, 0) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_is_zero(&n)); + rustsecp256k1_v0_11_scalar_set_int(&n, 0); + CHECK(rustsecp256k1_v0_11_scalar_cond_negate(&n, 1) == -1); + CHECK(rustsecp256k1_v0_11_scalar_is_zero(&n)); + CHECK(rustsecp256k1_v0_11_scalar_cond_negate(&n, 0) == 1); + CHECK(rustsecp256k1_v0_11_scalar_is_zero(&n)); } -static int test_ecmult_accumulate_cb(rustsecp256k1zkp_v0_8_0_scalar* sc, rustsecp256k1zkp_v0_8_0_ge* pt, size_t idx, void* data) { - const rustsecp256k1zkp_v0_8_0_scalar* indata = (const rustsecp256k1zkp_v0_8_0_scalar*)data; +static int test_ecmult_accumulate_cb(rustsecp256k1_v0_11_scalar* sc, rustsecp256k1_v0_11_ge* pt, size_t idx, void* data) { + const rustsecp256k1_v0_11_scalar* indata = (const rustsecp256k1_v0_11_scalar*)data; *sc = *indata; - *pt = rustsecp256k1zkp_v0_8_0_ge_const_g; + *pt = rustsecp256k1_v0_11_ge_const_g; CHECK(idx == 0); return 1; } -void test_ecmult_accumulate(rustsecp256k1zkp_v0_8_0_sha256* acc, const rustsecp256k1zkp_v0_8_0_scalar* x, rustsecp256k1zkp_v0_8_0_scratch* scratch) { +static void test_ecmult_accumulate(rustsecp256k1_v0_11_sha256* acc, const rustsecp256k1_v0_11_scalar* x, rustsecp256k1_v0_11_scratch* scratch) { /* Compute x*G in 6 different ways, serialize it uncompressed, and feed it into acc. */ - rustsecp256k1zkp_v0_8_0_gej rj1, rj2, rj3, rj4, rj5, rj6, gj, infj; - rustsecp256k1zkp_v0_8_0_ge r; - const rustsecp256k1zkp_v0_8_0_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + rustsecp256k1_v0_11_gej rj1, rj2, rj3, rj4, rj5, rj6, gj, infj; + rustsecp256k1_v0_11_ge r; unsigned char bytes[65]; size_t size = 65; - rustsecp256k1zkp_v0_8_0_gej_set_ge(&gj, &rustsecp256k1zkp_v0_8_0_ge_const_g); - rustsecp256k1zkp_v0_8_0_gej_set_infinity(&infj); - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &rj1, x); - rustsecp256k1zkp_v0_8_0_ecmult(&rj2, &gj, x, &zero); - rustsecp256k1zkp_v0_8_0_ecmult(&rj3, &infj, &zero, x); - rustsecp256k1zkp_v0_8_0_ecmult_multi_var(NULL, scratch, &rj4, x, NULL, NULL, 0); - rustsecp256k1zkp_v0_8_0_ecmult_multi_var(NULL, scratch, &rj5, &zero, test_ecmult_accumulate_cb, (void*)x, 1); - rustsecp256k1zkp_v0_8_0_ecmult_const(&rj6, &rustsecp256k1zkp_v0_8_0_ge_const_g, x, 256); - rustsecp256k1zkp_v0_8_0_ge_set_gej_var(&r, &rj1); - ge_equals_gej(&r, &rj2); - ge_equals_gej(&r, &rj3); - ge_equals_gej(&r, &rj4); - ge_equals_gej(&r, &rj5); - ge_equals_gej(&r, &rj6); - if (rustsecp256k1zkp_v0_8_0_ge_is_infinity(&r)) { + rustsecp256k1_v0_11_gej_set_ge(&gj, &rustsecp256k1_v0_11_ge_const_g); + rustsecp256k1_v0_11_gej_set_infinity(&infj); + rustsecp256k1_v0_11_ecmult_gen(&CTX->ecmult_gen_ctx, &rj1, x); + rustsecp256k1_v0_11_ecmult(&rj2, &gj, x, &rustsecp256k1_v0_11_scalar_zero); + rustsecp256k1_v0_11_ecmult(&rj3, &infj, &rustsecp256k1_v0_11_scalar_zero, x); + CHECK(rustsecp256k1_v0_11_ecmult_multi_var(&CTX->error_callback, scratch, &rj4, x, NULL, NULL, 0)); + CHECK(rustsecp256k1_v0_11_ecmult_multi_var(&CTX->error_callback, scratch, &rj5, &rustsecp256k1_v0_11_scalar_zero, test_ecmult_accumulate_cb, (void*)x, 1)); + rustsecp256k1_v0_11_ecmult_const(&rj6, &rustsecp256k1_v0_11_ge_const_g, x); + rustsecp256k1_v0_11_ge_set_gej_var(&r, &rj1); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&rj2, &r)); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&rj3, &r)); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&rj4, &r)); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&rj5, &r)); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&rj6, &r)); + if (rustsecp256k1_v0_11_ge_is_infinity(&r)) { /* Store infinity as 0x00 */ const unsigned char zerobyte[1] = {0}; - rustsecp256k1zkp_v0_8_0_sha256_write(acc, zerobyte, 1); + rustsecp256k1_v0_11_sha256_write(acc, zerobyte, 1); } else { /* Store other points using their uncompressed serialization. */ - rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&r, bytes, &size, 0); + rustsecp256k1_v0_11_eckey_pubkey_serialize(&r, bytes, &size, 0); CHECK(size == 65); - rustsecp256k1zkp_v0_8_0_sha256_write(acc, bytes, size); + rustsecp256k1_v0_11_sha256_write(acc, bytes, size); } } -void test_ecmult_constants_2bit(void) { +static void test_ecmult_constants_2bit(void) { /* Using test_ecmult_accumulate, test ecmult for: * - For i in 0..36: * - Key i @@ -5223,11 +5436,11 @@ void test_ecmult_constants_2bit(void) { * - For j in 1..255 (only odd values): * - Key (j*2^i) mod order */ - rustsecp256k1zkp_v0_8_0_scalar x; - rustsecp256k1zkp_v0_8_0_sha256 acc; + rustsecp256k1_v0_11_scalar x; + rustsecp256k1_v0_11_sha256 acc; unsigned char b32[32]; int i, j; - rustsecp256k1zkp_v0_8_0_scratch_space *scratch = rustsecp256k1zkp_v0_8_0_scratch_space_create(ctx, 65536); + rustsecp256k1_v0_11_scratch_space *scratch = rustsecp256k1_v0_11_scratch_space_create(CTX, 65536); /* Expected hash of all the computed points; created with an independent * implementation. */ @@ -5237,28 +5450,28 @@ void test_ecmult_constants_2bit(void) { 0x3a, 0x75, 0x87, 0x60, 0x1a, 0xf9, 0x63, 0x60, 0xd0, 0xcb, 0x1f, 0xaa, 0x85, 0x9a, 0xb7, 0xb4 }; - rustsecp256k1zkp_v0_8_0_sha256_initialize(&acc); + rustsecp256k1_v0_11_sha256_initialize(&acc); for (i = 0; i <= 36; ++i) { - rustsecp256k1zkp_v0_8_0_scalar_set_int(&x, i); + rustsecp256k1_v0_11_scalar_set_int(&x, i); test_ecmult_accumulate(&acc, &x, scratch); - rustsecp256k1zkp_v0_8_0_scalar_negate(&x, &x); + rustsecp256k1_v0_11_scalar_negate(&x, &x); test_ecmult_accumulate(&acc, &x, scratch); }; for (i = 0; i < 256; ++i) { for (j = 1; j < 256; j += 2) { int k; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&x, j); - for (k = 0; k < i; ++k) rustsecp256k1zkp_v0_8_0_scalar_add(&x, &x, &x); + rustsecp256k1_v0_11_scalar_set_int(&x, j); + for (k = 0; k < i; ++k) rustsecp256k1_v0_11_scalar_add(&x, &x, &x); test_ecmult_accumulate(&acc, &x, scratch); } } - rustsecp256k1zkp_v0_8_0_sha256_finalize(&acc, b32); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(b32, expected32, 32) == 0); + rustsecp256k1_v0_11_sha256_finalize(&acc, b32); + CHECK(rustsecp256k1_v0_11_memcmp_var(b32, expected32, 32) == 0); - rustsecp256k1zkp_v0_8_0_scratch_space_destroy(ctx, scratch); + rustsecp256k1_v0_11_scratch_space_destroy(CTX, scratch); } -void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char* expected32) { +static void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char* expected32) { /* Using test_ecmult_accumulate, test ecmult for: * - Key 0 * - Key 1 @@ -5266,42 +5479,42 @@ void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char * - For i in range(iter): * - Key SHA256(LE32(prefix) || LE16(i)) */ - rustsecp256k1zkp_v0_8_0_scalar x; - rustsecp256k1zkp_v0_8_0_sha256 acc; + rustsecp256k1_v0_11_scalar x; + rustsecp256k1_v0_11_sha256 acc; unsigned char b32[32]; unsigned char inp[6]; size_t i; - rustsecp256k1zkp_v0_8_0_scratch_space *scratch = rustsecp256k1zkp_v0_8_0_scratch_space_create(ctx, 65536); + rustsecp256k1_v0_11_scratch_space *scratch = rustsecp256k1_v0_11_scratch_space_create(CTX, 65536); inp[0] = prefix & 0xFF; inp[1] = (prefix >> 8) & 0xFF; inp[2] = (prefix >> 16) & 0xFF; inp[3] = (prefix >> 24) & 0xFF; - rustsecp256k1zkp_v0_8_0_sha256_initialize(&acc); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&x, 0); + rustsecp256k1_v0_11_sha256_initialize(&acc); + rustsecp256k1_v0_11_scalar_set_int(&x, 0); test_ecmult_accumulate(&acc, &x, scratch); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&x, 1); + rustsecp256k1_v0_11_scalar_set_int(&x, 1); test_ecmult_accumulate(&acc, &x, scratch); - rustsecp256k1zkp_v0_8_0_scalar_negate(&x, &x); + rustsecp256k1_v0_11_scalar_negate(&x, &x); test_ecmult_accumulate(&acc, &x, scratch); for (i = 0; i < iter; ++i) { - rustsecp256k1zkp_v0_8_0_sha256 gen; + rustsecp256k1_v0_11_sha256 gen; inp[4] = i & 0xff; inp[5] = (i >> 8) & 0xff; - rustsecp256k1zkp_v0_8_0_sha256_initialize(&gen); - rustsecp256k1zkp_v0_8_0_sha256_write(&gen, inp, sizeof(inp)); - rustsecp256k1zkp_v0_8_0_sha256_finalize(&gen, b32); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&x, b32, NULL); + rustsecp256k1_v0_11_sha256_initialize(&gen); + rustsecp256k1_v0_11_sha256_write(&gen, inp, sizeof(inp)); + rustsecp256k1_v0_11_sha256_finalize(&gen, b32); + rustsecp256k1_v0_11_scalar_set_b32(&x, b32, NULL); test_ecmult_accumulate(&acc, &x, scratch); } - rustsecp256k1zkp_v0_8_0_sha256_finalize(&acc, b32); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(b32, expected32, 32) == 0); + rustsecp256k1_v0_11_sha256_finalize(&acc, b32); + CHECK(rustsecp256k1_v0_11_memcmp_var(b32, expected32, 32) == 0); - rustsecp256k1zkp_v0_8_0_scratch_space_destroy(ctx, scratch); + rustsecp256k1_v0_11_scratch_space_destroy(CTX, scratch); } -void run_ecmult_constants(void) { +static void run_ecmult_constants(void) { /* Expected hashes of all points in the tests below. Computed using an * independent implementation. */ static const unsigned char expected32_6bit20[32] = { @@ -5330,96 +5543,117 @@ void run_ecmult_constants(void) { test_ecmult_constants_sha(1607366309u, 2048, expected32_8bit8); } - CONDITIONAL_TEST(35, "test_ecmult_constants_2bit") { + CONDITIONAL_TEST(16, "test_ecmult_constants_2bit") { test_ecmult_constants_2bit(); } } -void test_ecmult_gen_blind(void) { +static void test_ecmult_gen_blind(void) { /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ - rustsecp256k1zkp_v0_8_0_scalar key; - rustsecp256k1zkp_v0_8_0_scalar b; + rustsecp256k1_v0_11_scalar key; + rustsecp256k1_v0_11_scalar b; unsigned char seed32[32]; - rustsecp256k1zkp_v0_8_0_gej pgej; - rustsecp256k1zkp_v0_8_0_gej pgej2; - rustsecp256k1zkp_v0_8_0_gej i; - rustsecp256k1zkp_v0_8_0_ge pge; - random_scalar_order_test(&key); - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key); - rustsecp256k1zkp_v0_8_0_testrand256(seed32); - b = ctx->ecmult_gen_ctx.blind; - i = ctx->ecmult_gen_ctx.initial; - rustsecp256k1zkp_v0_8_0_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); - CHECK(!rustsecp256k1zkp_v0_8_0_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej2, &key); + rustsecp256k1_v0_11_gej pgej; + rustsecp256k1_v0_11_gej pgej2; + rustsecp256k1_v0_11_ge p; + rustsecp256k1_v0_11_ge pge; + testutil_random_scalar_order_test(&key); + rustsecp256k1_v0_11_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej, &key); + testrand256(seed32); + b = CTX->ecmult_gen_ctx.scalar_offset; + p = CTX->ecmult_gen_ctx.ge_offset; + rustsecp256k1_v0_11_ecmult_gen_blind(&CTX->ecmult_gen_ctx, seed32); + CHECK(!rustsecp256k1_v0_11_scalar_eq(&b, &CTX->ecmult_gen_ctx.scalar_offset)); + rustsecp256k1_v0_11_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej2, &key); CHECK(!gej_xyz_equals_gej(&pgej, &pgej2)); - CHECK(!gej_xyz_equals_gej(&i, &ctx->ecmult_gen_ctx.initial)); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&pge, &pgej); - ge_equals_gej(&pge, &pgej2); + CHECK(!rustsecp256k1_v0_11_ge_eq_var(&p, &CTX->ecmult_gen_ctx.ge_offset)); + rustsecp256k1_v0_11_ge_set_gej(&pge, &pgej); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&pgej2, &pge)); } -void test_ecmult_gen_blind_reset(void) { +static void test_ecmult_gen_blind_reset(void) { /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ - rustsecp256k1zkp_v0_8_0_scalar b; - rustsecp256k1zkp_v0_8_0_gej initial; - rustsecp256k1zkp_v0_8_0_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); - b = ctx->ecmult_gen_ctx.blind; - initial = ctx->ecmult_gen_ctx.initial; - rustsecp256k1zkp_v0_8_0_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); - CHECK(gej_xyz_equals_gej(&initial, &ctx->ecmult_gen_ctx.initial)); + rustsecp256k1_v0_11_scalar b; + rustsecp256k1_v0_11_ge p1, p2; + rustsecp256k1_v0_11_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0); + b = CTX->ecmult_gen_ctx.scalar_offset; + p1 = CTX->ecmult_gen_ctx.ge_offset; + rustsecp256k1_v0_11_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0); + CHECK(rustsecp256k1_v0_11_scalar_eq(&b, &CTX->ecmult_gen_ctx.scalar_offset)); + p2 = CTX->ecmult_gen_ctx.ge_offset; + CHECK(rustsecp256k1_v0_11_ge_eq_var(&p1, &p2)); +} + +/* Verify that ecmult_gen for scalars gn for which gn + scalar_offset = {-1,0,1}. */ +static void test_ecmult_gen_edge_cases(void) { + int i; + rustsecp256k1_v0_11_gej res1, res2, res3; + rustsecp256k1_v0_11_scalar gn = rustsecp256k1_v0_11_scalar_one; /* gn = 1 */ + rustsecp256k1_v0_11_scalar_add(&gn, &gn, &CTX->ecmult_gen_ctx.scalar_offset); /* gn = 1 + scalar_offset */ + rustsecp256k1_v0_11_scalar_negate(&gn, &gn); /* gn = -1 - scalar_offset */ + + for (i = -1; i < 2; ++i) { + /* Run test with gn = i - scalar_offset (so that the ecmult_gen recoded value represents i). */ + rustsecp256k1_v0_11_ecmult_gen(&CTX->ecmult_gen_ctx, &res1, &gn); + rustsecp256k1_v0_11_ecmult(&res2, NULL, &rustsecp256k1_v0_11_scalar_zero, &gn); + rustsecp256k1_v0_11_ecmult_const(&res3, &rustsecp256k1_v0_11_ge_const_g, &gn); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&res1, &res2)); + CHECK(rustsecp256k1_v0_11_gej_eq_var(&res1, &res3)); + rustsecp256k1_v0_11_scalar_add(&gn, &gn, &rustsecp256k1_v0_11_scalar_one); + } } -void run_ecmult_gen_blind(void) { +static void run_ecmult_gen_blind(void) { int i; test_ecmult_gen_blind_reset(); + test_ecmult_gen_edge_cases(); for (i = 0; i < 10; i++) { test_ecmult_gen_blind(); } } /***** ENDOMORPHISH TESTS *****/ -void test_scalar_split(const rustsecp256k1zkp_v0_8_0_scalar* full) { - rustsecp256k1zkp_v0_8_0_scalar s, s1, slam; +static void test_scalar_split(const rustsecp256k1_v0_11_scalar* full) { + rustsecp256k1_v0_11_scalar s, s1, slam; const unsigned char zero[32] = {0}; unsigned char tmp[32]; - rustsecp256k1zkp_v0_8_0_scalar_split_lambda(&s1, &slam, full); + rustsecp256k1_v0_11_scalar_split_lambda(&s1, &slam, full); /* check slam*lambda + s1 == full */ - rustsecp256k1zkp_v0_8_0_scalar_mul(&s, &rustsecp256k1zkp_v0_8_0_const_lambda, &slam); - rustsecp256k1zkp_v0_8_0_scalar_add(&s, &s, &s1); - CHECK(rustsecp256k1zkp_v0_8_0_scalar_eq(&s, full)); + rustsecp256k1_v0_11_scalar_mul(&s, &rustsecp256k1_v0_11_const_lambda, &slam); + rustsecp256k1_v0_11_scalar_add(&s, &s, &s1); + CHECK(rustsecp256k1_v0_11_scalar_eq(&s, full)); /* check that both are <= 128 bits in size */ - if (rustsecp256k1zkp_v0_8_0_scalar_is_high(&s1)) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&s1, &s1); + if (rustsecp256k1_v0_11_scalar_is_high(&s1)) { + rustsecp256k1_v0_11_scalar_negate(&s1, &s1); } - if (rustsecp256k1zkp_v0_8_0_scalar_is_high(&slam)) { - rustsecp256k1zkp_v0_8_0_scalar_negate(&slam, &slam); + if (rustsecp256k1_v0_11_scalar_is_high(&slam)) { + rustsecp256k1_v0_11_scalar_negate(&slam, &slam); } - rustsecp256k1zkp_v0_8_0_scalar_get_b32(tmp, &s1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zero, tmp, 16) == 0); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(tmp, &slam); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zero, tmp, 16) == 0); + rustsecp256k1_v0_11_scalar_get_b32(tmp, &s1); + CHECK(rustsecp256k1_v0_11_memcmp_var(zero, tmp, 16) == 0); + rustsecp256k1_v0_11_scalar_get_b32(tmp, &slam); + CHECK(rustsecp256k1_v0_11_memcmp_var(zero, tmp, 16) == 0); } -void run_endomorphism_tests(void) { +static void run_endomorphism_tests(void) { unsigned i; - static rustsecp256k1zkp_v0_8_0_scalar s; - test_scalar_split(&rustsecp256k1zkp_v0_8_0_scalar_zero); - test_scalar_split(&rustsecp256k1zkp_v0_8_0_scalar_one); - rustsecp256k1zkp_v0_8_0_scalar_negate(&s,&rustsecp256k1zkp_v0_8_0_scalar_one); + static rustsecp256k1_v0_11_scalar s; + test_scalar_split(&rustsecp256k1_v0_11_scalar_zero); + test_scalar_split(&rustsecp256k1_v0_11_scalar_one); + rustsecp256k1_v0_11_scalar_negate(&s,&rustsecp256k1_v0_11_scalar_one); test_scalar_split(&s); - test_scalar_split(&rustsecp256k1zkp_v0_8_0_const_lambda); - rustsecp256k1zkp_v0_8_0_scalar_add(&s, &rustsecp256k1zkp_v0_8_0_const_lambda, &rustsecp256k1zkp_v0_8_0_scalar_one); + test_scalar_split(&rustsecp256k1_v0_11_const_lambda); + rustsecp256k1_v0_11_scalar_add(&s, &rustsecp256k1_v0_11_const_lambda, &rustsecp256k1_v0_11_scalar_one); test_scalar_split(&s); - for (i = 0; i < 100U * count; ++i) { - rustsecp256k1zkp_v0_8_0_scalar full; - random_scalar_order_test(&full); + for (i = 0; i < 100U * COUNT; ++i) { + rustsecp256k1_v0_11_scalar full; + testutil_random_scalar_order_test(&full); test_scalar_split(&full); } for (i = 0; i < sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); ++i) { @@ -5427,19 +5661,17 @@ void run_endomorphism_tests(void) { } } -void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { +static void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { unsigned char pubkeyc[65]; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_ge ge; + rustsecp256k1_v0_11_pubkey pubkey; + rustsecp256k1_v0_11_ge ge; size_t pubkeyclen; - int32_t ecount; - ecount = 0; - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) { /* Smaller sizes are tested exhaustively elsewhere. */ int32_t i; memcpy(&pubkeyc[1], input, 64); - VG_UNDEF(&pubkeyc[pubkeyclen], 65 - pubkeyclen); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeyc[pubkeyclen], 65 - pubkeyclen); for (i = 0; i < 256; i++) { /* Try all type bytes. */ int xpass; @@ -5458,51 +5690,45 @@ void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvali unsigned char pubkeyo[65]; size_t outl; memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); outl = 65; - VG_UNDEF(pubkeyo, 65); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - VG_CHECK(pubkeyo, outl); + SECP256K1_CHECKMEM_UNDEFINE(pubkeyo, 65); + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(CTX, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + SECP256K1_CHECKMEM_CHECK(pubkeyo, outl); CHECK(outl == 33); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkeyo[1], &pubkeyc[1], 32) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkeyo[1], &pubkeyc[1], 32) == 0); CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0])); if (ypass) { /* This test isn't always done because we decode with alternative signs, so the y won't match. */ CHECK(pubkeyo[0] == ysign); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &ge, &pubkey) == 1); + CHECK(rustsecp256k1_v0_11_pubkey_load(CTX, &ge, &pubkey) == 1); memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - rustsecp256k1zkp_v0_8_0_pubkey_save(&pubkey, &ge); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + rustsecp256k1_v0_11_pubkey_save(&pubkey, &ge); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); outl = 65; - VG_UNDEF(pubkeyo, 65); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); - VG_CHECK(pubkeyo, outl); + SECP256K1_CHECKMEM_UNDEFINE(pubkeyo, 65); + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(CTX, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + SECP256K1_CHECKMEM_CHECK(pubkeyo, outl); CHECK(outl == 65); CHECK(pubkeyo[0] == 4); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkeyo[1], input, 64) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkeyo[1], input, 64) == 0); } - CHECK(ecount == 0); } else { /* These cases must fail to parse. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_pubkey_load(CTX, &ge, &pubkey)); } } } - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(ctx, NULL, NULL); } -void run_ec_pubkey_parse_test(void) { +static void run_ec_pubkey_parse_test(void) { #define SECP256K1_EC_PARSE_TEST_NVALID (12) const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = { { @@ -5682,142 +5908,99 @@ void run_ec_pubkey_parse_test(void) { 0xB8, 0x00 }; unsigned char sout[65]; - unsigned char shortkey[2]; - rustsecp256k1zkp_v0_8_0_ge ge; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; + unsigned char shortkey[2] = { 0 }; + rustsecp256k1_v0_11_ge ge; + rustsecp256k1_v0_11_pubkey pubkey; size_t len; int32_t i; - int32_t ecount; - int32_t ecount2; - ecount = 0; + /* Nothing should be reading this far into pubkeyc. */ - VG_UNDEF(&pubkeyc[65], 1); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeyc[65], 1); /* Zero length claimed, fail, zeroize, no illegal arg error. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(shortkey, 2); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, shortkey, 0) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); + SECP256K1_CHECKMEM_UNDEFINE(shortkey, 2); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, shortkey, 0) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_pubkey_load(CTX, &ge, &pubkey)); /* Length one claimed, fail, zeroize, no illegal arg error. */ for (i = 0; i < 256 ; i++) { memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; shortkey[0] = i; - VG_UNDEF(&shortkey[1], 1); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, shortkey, 1) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); + SECP256K1_CHECKMEM_UNDEFINE(&shortkey[1], 1); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, shortkey, 1) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_pubkey_load(CTX, &ge, &pubkey)); } /* Length two claimed, fail, zeroize, no illegal arg error. */ for (i = 0; i < 65536 ; i++) { memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; shortkey[0] = i & 255; shortkey[1] = i >> 8; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, shortkey, 2) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, shortkey, 2) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_pubkey_load(CTX, &ge, &pubkey)); } memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 33) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 33) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_pubkey_load(CTX, &ge, &pubkey)); /* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, NULL, pubkeyc, 65) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_parse(CTX, NULL, pubkeyc, 65)); /* NULL input string. Illegal arg and zeroize output. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, NULL, 65) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 2); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, NULL, 65)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_pubkey_load(CTX, &ge, &pubkey)); /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 64) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 64) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_pubkey_load(CTX, &ge, &pubkey)); /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 66) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 66) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_pubkey_load(CTX, &ge, &pubkey)); /* Valid parse. */ memset(&pubkey, 0, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(rustsecp256k1zkp_v0_8_0_context_no_precomp, &pubkey, pubkeyc, 65) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - VG_UNDEF(&ge, sizeof(ge)); - CHECK(rustsecp256k1zkp_v0_8_0_pubkey_load(ctx, &ge, &pubkey) == 1); - VG_CHECK(&ge.x, sizeof(ge.x)); - VG_CHECK(&ge.y, sizeof(ge.y)); - VG_CHECK(&ge.infinity, sizeof(ge.infinity)); - ge_equals_ge(&rustsecp256k1zkp_v0_8_0_ge_const_g, &ge); - CHECK(ecount == 0); - /* rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize illegal args. */ - ecount = 0; + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 65) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(rustsecp256k1_v0_11_context_static, &pubkey, pubkeyc, 65) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&ge, sizeof(ge)); + CHECK(rustsecp256k1_v0_11_pubkey_load(CTX, &ge, &pubkey) == 1); + SECP256K1_CHECKMEM_CHECK(&ge.x, sizeof(ge.x)); + SECP256K1_CHECKMEM_CHECK(&ge.y, sizeof(ge.y)); + SECP256K1_CHECKMEM_CHECK(&ge.infinity, sizeof(ge.infinity)); + CHECK(rustsecp256k1_v0_11_ge_eq_var(&ge, &rustsecp256k1_v0_11_ge_const_g)); + /* rustsecp256k1_v0_11_ec_pubkey_serialize illegal args. */ len = 65; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_serialize(CTX, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED)); CHECK(len == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_serialize(CTX, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED)); len = 65; - VG_UNDEF(sout, 65); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0); - VG_CHECK(sout, 65); - CHECK(ecount == 3); + SECP256K1_CHECKMEM_UNDEFINE(sout, 65); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_serialize(CTX, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED)); + SECP256K1_CHECKMEM_CHECK(sout, 65); CHECK(len == 0); len = 65; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, sout, &len, &pubkey, ~0) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_serialize(CTX, sout, &len, &pubkey, ~0)); CHECK(len == 0); len = 65; - VG_UNDEF(sout, 65); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); - VG_CHECK(sout, 65); - CHECK(ecount == 4); + SECP256K1_CHECKMEM_UNDEFINE(sout, 65); + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(CTX, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + SECP256K1_CHECKMEM_CHECK(sout, 65); CHECK(len == 65); /* Multiple illegal args. Should still set arg error only once. */ - ecount = 0; - ecount2 = 11; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); - CHECK(ecount == 1); - /* Does the illegal arg callback actually change the behavior? */ - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(ctx, uncounting_illegal_callback_fn, &ecount2); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); - CHECK(ecount == 1); - CHECK(ecount2 == 10); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(ctx, NULL, NULL); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_parse(CTX, NULL, NULL, 65)); /* Try a bunch of prefabbed points with all possible encodings. */ for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) { ec_pubkey_parse_pointtest(valid[i], 1, 1); @@ -5830,317 +6013,283 @@ void run_ec_pubkey_parse_test(void) { } } -void run_eckey_edge_case_test(void) { +static void run_eckey_edge_case_test(void) { const unsigned char orderc[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 }; - const unsigned char zeros[sizeof(rustsecp256k1zkp_v0_8_0_pubkey)] = {0x00}; + const unsigned char zeros[sizeof(rustsecp256k1_v0_11_pubkey)] = {0x00}; unsigned char ctmp[33]; unsigned char ctmp2[33]; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_pubkey pubkey2; - rustsecp256k1zkp_v0_8_0_pubkey pubkey_one; - rustsecp256k1zkp_v0_8_0_pubkey pubkey_negone; - const rustsecp256k1zkp_v0_8_0_pubkey *pubkeys[3]; + rustsecp256k1_v0_11_pubkey pubkey; + rustsecp256k1_v0_11_pubkey pubkey2; + rustsecp256k1_v0_11_pubkey pubkey_one; + rustsecp256k1_v0_11_pubkey pubkey_negone; + const rustsecp256k1_v0_11_pubkey *pubkeys[3]; size_t len; - int32_t ecount; /* Group order is too large, reject. */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, orderc) == 0); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, orderc) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_verify(CTX, orderc) == 0); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey, orderc) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1_v0_11_pubkey)) == 0); /* Maximum value is too large, reject. */ memset(ctmp, 255, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, ctmp) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_verify(CTX, ctmp) == 0); memset(&pubkey, 1, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) == 0); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1_v0_11_pubkey)) == 0); /* Zero is too small, reject. */ memset(ctmp, 0, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, ctmp) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_verify(CTX, ctmp) == 0); memset(&pubkey, 1, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) == 0); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1_v0_11_pubkey)) == 0); /* One must be accepted. */ ctmp[31] = 0x01; - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, ctmp) == 1); + CHECK(rustsecp256k1_v0_11_ec_seckey_verify(CTX, ctmp) == 1); memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) > 0); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1_v0_11_pubkey)) > 0); pubkey_one = pubkey; /* Group order + 1 is too large, reject. */ memcpy(ctmp, orderc, 32); ctmp[31] = 0x42; - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, ctmp) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_verify(CTX, ctmp) == 0); memset(&pubkey, 1, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) == 0); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1_v0_11_pubkey)) == 0); /* -1 must be accepted. */ ctmp[31] = 0x40; - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, ctmp) == 1); + CHECK(rustsecp256k1_v0_11_ec_seckey_verify(CTX, ctmp) == 1); memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) > 0); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1_v0_11_pubkey)) > 0); pubkey_negone = pubkey; /* Tweak of zero leaves the value unchanged. */ memset(ctmp2, 0, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add(ctx, ctmp, ctmp2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); + CHECK(rustsecp256k1_v0_11_ec_seckey_tweak_add(CTX, ctmp, ctmp2) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); memcpy(&pubkey2, &pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); /* Multiply tweak of zero zeroizes the output. */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul(ctx, ctmp, ctmp2) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros, ctmp, 32) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_tweak_mul(CTX, ctmp, ctmp2) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros, ctmp, 32) == 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_tweak_mul(CTX, &pubkey, ctmp2) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); /* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing seckey, the seckey is zeroized. */ memcpy(ctmp, orderc, 32); memset(ctmp2, 0, 32); ctmp2[31] = 0x01; - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, ctmp2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, ctmp) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add(ctx, ctmp, ctmp2) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros, ctmp, 32) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_verify(CTX, ctmp2) == 1); + CHECK(rustsecp256k1_v0_11_ec_seckey_verify(CTX, ctmp) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_tweak_add(CTX, ctmp, ctmp2) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros, ctmp, 32) == 0); memcpy(ctmp, orderc, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul(ctx, ctmp, ctmp2) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros, ctmp, 32) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_tweak_mul(CTX, ctmp, ctmp2) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros, ctmp, 32) == 0); /* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing tweak, the seckey is zeroized. */ memcpy(ctmp, orderc, 32); ctmp[31] = 0x40; - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add(ctx, ctmp, orderc) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros, ctmp, 32) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_tweak_add(CTX, ctmp, orderc) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros, ctmp, 32) == 0); memcpy(ctmp, orderc, 32); ctmp[31] = 0x40; - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul(ctx, ctmp, orderc) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros, ctmp, 32) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_tweak_mul(CTX, ctmp, orderc) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros, ctmp, 32) == 0); memcpy(ctmp, orderc, 32); ctmp[31] = 0x40; /* If pubkey_tweak_add or pubkey_tweak_mul are called with an overflowing tweak, the pubkey is zeroized. */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_tweak_add(CTX, &pubkey, orderc) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_tweak_mul(CTX, &pubkey, orderc) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - /* If the resulting key in rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add and - * rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add is 0 the functions fail and in the latter + /* If the resulting key in rustsecp256k1_v0_11_ec_seckey_tweak_add and + * rustsecp256k1_v0_11_ec_pubkey_tweak_add is 0 the functions fail and in the latter * case the pubkey is zeroized. */ memcpy(ctmp, orderc, 32); ctmp[31] = 0x40; memset(ctmp2, 0, 32); ctmp2[31] = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add(ctx, ctmp2, ctmp) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(zeros, ctmp2, 32) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_tweak_add(CTX, ctmp2, ctmp) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(zeros, ctmp2, 32) == 0); ctmp2[31] = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); /* Tweak computation wraps and results in a key of 1. */ ctmp2[31] = 2; - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add(ctx, ctmp2, ctmp) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); + CHECK(rustsecp256k1_v0_11_ec_seckey_tweak_add(CTX, ctmp2, ctmp) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); ctmp2[31] = 2; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1); ctmp2[31] = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey2, ctmp2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey2, ctmp2) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); /* Tweak mul * 2 = 1+1. */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1); ctmp2[31] = 2; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); - /* Test argument errors. */ - ecount = 0; - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); - CHECK(ecount == 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); /* Zeroize pubkey on parse error. */ memset(&pubkey, 0, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); memset(&pubkey2, 0, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey2, zeros, sizeof(pubkey2)) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey2, zeros, sizeof(pubkey2)) == 0); /* Plain argument errors. */ - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, ctmp) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, NULL) == 0); - CHECK(ecount == 1); - ecount = 0; + CHECK(rustsecp256k1_v0_11_ec_seckey_verify(CTX, ctmp) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_seckey_verify(CTX, NULL)); memset(ctmp2, 0, 32); ctmp2[31] = 4; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(ctx, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(ctx, &pubkey, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_tweak_add(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_tweak_add(CTX, &pubkey, NULL)); memset(ctmp2, 0, 32); ctmp2[31] = 4; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_mul(ctx, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_mul(ctx, &pubkey, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_tweak_mul(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_tweak_mul(CTX, &pubkey, NULL)); memset(ctmp2, 0, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add(ctx, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add(ctx, ctmp, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_seckey_tweak_add(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_seckey_tweak_add(CTX, ctmp, NULL)); memset(ctmp2, 0, 32); ctmp2[31] = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul(ctx, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul(ctx, ctmp, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, NULL, ctmp) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_seckey_tweak_mul(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_seckey_tweak_mul(CTX, ctmp, NULL)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_create(CTX, NULL, ctmp)); memset(&pubkey, 1, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, NULL) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) == 0); - /* rustsecp256k1zkp_v0_8_0_ec_pubkey_combine tests. */ - ecount = 0; + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey, NULL)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1_v0_11_pubkey)) == 0); + /* rustsecp256k1_v0_11_ec_pubkey_combine tests. */ pubkeys[0] = &pubkey_one; - VG_UNDEF(&pubkeys[0], sizeof(rustsecp256k1zkp_v0_8_0_pubkey *)); - VG_UNDEF(&pubkeys[1], sizeof(rustsecp256k1zkp_v0_8_0_pubkey *)); - VG_UNDEF(&pubkeys[2], sizeof(rustsecp256k1zkp_v0_8_0_pubkey *)); - memset(&pubkey, 255, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - VG_UNDEF(&pubkey, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_combine(ctx, &pubkey, pubkeys, 0) == 0); - VG_CHECK(&pubkey, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_combine(ctx, NULL, pubkeys, 1) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) == 0); - CHECK(ecount == 2); - memset(&pubkey, 255, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - VG_UNDEF(&pubkey, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_combine(ctx, &pubkey, NULL, 1) == 0); - VG_CHECK(&pubkey, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) == 0); - CHECK(ecount == 3); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[0], sizeof(rustsecp256k1_v0_11_pubkey *)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[1], sizeof(rustsecp256k1_v0_11_pubkey *)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[2], sizeof(rustsecp256k1_v0_11_pubkey *)); + memset(&pubkey, 255, sizeof(rustsecp256k1_v0_11_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(rustsecp256k1_v0_11_pubkey)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_combine(CTX, &pubkey, pubkeys, 0)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(rustsecp256k1_v0_11_pubkey)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1_v0_11_pubkey)) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_combine(CTX, NULL, pubkeys, 1)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1_v0_11_pubkey)) == 0); + memset(&pubkey, 255, sizeof(rustsecp256k1_v0_11_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(rustsecp256k1_v0_11_pubkey)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_combine(CTX, &pubkey, NULL, 1)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(rustsecp256k1_v0_11_pubkey)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1_v0_11_pubkey)) == 0); pubkeys[0] = &pubkey_negone; - memset(&pubkey, 255, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - VG_UNDEF(&pubkey, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_combine(ctx, &pubkey, pubkeys, 1) == 1); - VG_CHECK(&pubkey, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) > 0); - CHECK(ecount == 3); + memset(&pubkey, 255, sizeof(rustsecp256k1_v0_11_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(rustsecp256k1_v0_11_pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_combine(CTX, &pubkey, pubkeys, 1) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(rustsecp256k1_v0_11_pubkey)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1_v0_11_pubkey)) > 0); len = 33; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(ctmp, ctmp2, 33) == 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(ctmp, ctmp2, 33) == 0); /* Result is infinity. */ pubkeys[0] = &pubkey_one; pubkeys[1] = &pubkey_negone; - memset(&pubkey, 255, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - VG_UNDEF(&pubkey, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 0); - VG_CHECK(&pubkey, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) == 0); - CHECK(ecount == 3); + memset(&pubkey, 255, sizeof(rustsecp256k1_v0_11_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(rustsecp256k1_v0_11_pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(rustsecp256k1_v0_11_pubkey)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1_v0_11_pubkey)) == 0); /* Passes through infinity but comes out one. */ pubkeys[2] = &pubkey_one; - memset(&pubkey, 255, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - VG_UNDEF(&pubkey, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_combine(ctx, &pubkey, pubkeys, 3) == 1); - VG_CHECK(&pubkey, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) > 0); - CHECK(ecount == 3); + memset(&pubkey, 255, sizeof(rustsecp256k1_v0_11_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(rustsecp256k1_v0_11_pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_combine(CTX, &pubkey, pubkeys, 3) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(rustsecp256k1_v0_11_pubkey)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1_v0_11_pubkey)) > 0); len = 33; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(ctmp, ctmp2, 33) == 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(ctmp, ctmp2, 33) == 0); /* Adds to two. */ pubkeys[1] = &pubkey_one; - memset(&pubkey, 255, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - VG_UNDEF(&pubkey, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 1); - VG_CHECK(&pubkey, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1zkp_v0_8_0_pubkey)) > 0); - CHECK(ecount == 3); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(ctx, NULL, NULL); + memset(&pubkey, 255, sizeof(rustsecp256k1_v0_11_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(rustsecp256k1_v0_11_pubkey)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(rustsecp256k1_v0_11_pubkey)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, zeros, sizeof(rustsecp256k1_v0_11_pubkey)) > 0); } -void run_eckey_negate_test(void) { +static void run_eckey_negate_test(void) { unsigned char seckey[32]; unsigned char seckey_tmp[32]; - random_scalar_order_b32(seckey); + testutil_random_scalar_order_b32(seckey); memcpy(seckey_tmp, seckey, 32); /* Verify negation changes the key and changes it back */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_negate(ctx, seckey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(seckey, seckey_tmp, 32) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_negate(ctx, seckey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(seckey, seckey_tmp, 32) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_negate(CTX, seckey) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(seckey, seckey_tmp, 32) != 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_negate(CTX, seckey) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(seckey, seckey_tmp, 32) == 0); /* Check that privkey alias gives same result */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_negate(ctx, seckey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_privkey_negate(ctx, seckey_tmp) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(seckey, seckey_tmp, 32) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_negate(CTX, seckey) == 1); + CHECK(rustsecp256k1_v0_11_ec_privkey_negate(CTX, seckey_tmp) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(seckey, seckey_tmp, 32) == 0); /* Negating all 0s fails */ memset(seckey, 0, 32); memset(seckey_tmp, 0, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_negate(ctx, seckey) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_negate(CTX, seckey) == 0); /* Check that seckey is not modified */ - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(seckey, seckey_tmp, 32) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(seckey, seckey_tmp, 32) == 0); /* Negating an overflowing seckey fails and the seckey is zeroed. In this * test, the seckey has 16 random bytes to ensure that ec_seckey_negate * doesn't just set seckey to a constant value in case of failure. */ - random_scalar_order_b32(seckey); + testutil_random_scalar_order_b32(seckey); memset(seckey, 0xFF, 16); memset(seckey_tmp, 0, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_negate(ctx, seckey) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(seckey, seckey_tmp, 32) == 0); + CHECK(rustsecp256k1_v0_11_ec_seckey_negate(CTX, seckey) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(seckey, seckey_tmp, 32) == 0); } -void random_sign(rustsecp256k1zkp_v0_8_0_scalar *sigr, rustsecp256k1zkp_v0_8_0_scalar *sigs, const rustsecp256k1zkp_v0_8_0_scalar *key, const rustsecp256k1zkp_v0_8_0_scalar *msg, int *recid) { - rustsecp256k1zkp_v0_8_0_scalar nonce; +static void random_sign(rustsecp256k1_v0_11_scalar *sigr, rustsecp256k1_v0_11_scalar *sigs, const rustsecp256k1_v0_11_scalar *key, const rustsecp256k1_v0_11_scalar *msg, int *recid) { + rustsecp256k1_v0_11_scalar nonce; do { - random_scalar_order_test(&nonce); - } while(!rustsecp256k1zkp_v0_8_0_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); + testutil_random_scalar_order_test(&nonce); + } while(!rustsecp256k1_v0_11_ecdsa_sig_sign(&CTX->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); } -void test_ecdsa_sign_verify(void) { - rustsecp256k1zkp_v0_8_0_gej pubj; - rustsecp256k1zkp_v0_8_0_ge pub; - rustsecp256k1zkp_v0_8_0_scalar one; - rustsecp256k1zkp_v0_8_0_scalar msg, key; - rustsecp256k1zkp_v0_8_0_scalar sigr, sigs; +static void test_ecdsa_sign_verify(void) { + rustsecp256k1_v0_11_gej pubj; + rustsecp256k1_v0_11_ge pub; + rustsecp256k1_v0_11_scalar one; + rustsecp256k1_v0_11_scalar msg, key; + rustsecp256k1_v0_11_scalar sigr, sigs; int getrec; int recid; - random_scalar_order_test(&msg); - random_scalar_order_test(&key); - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&pub, &pubj); - getrec = rustsecp256k1zkp_v0_8_0_testrand_bits(1); + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); + rustsecp256k1_v0_11_ecmult_gen(&CTX->ecmult_gen_ctx, &pubj, &key); + rustsecp256k1_v0_11_ge_set_gej(&pub, &pubj); + getrec = testrand_bits(1); /* The specific way in which this conditional is written sidesteps a potential bug in clang. See the commit messages of the commit that introduced this comment for details. */ if (getrec) { @@ -6149,15 +6298,15 @@ void test_ecdsa_sign_verify(void) { } else { random_sign(&sigr, &sigs, &key, &msg, NULL); } - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&one, 1); - rustsecp256k1zkp_v0_8_0_scalar_add(&msg, &msg, &one); - CHECK(!rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); + rustsecp256k1_v0_11_scalar_set_int(&one, 1); + rustsecp256k1_v0_11_scalar_add(&msg, &msg, &one); + CHECK(!rustsecp256k1_v0_11_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); } -void run_ecdsa_sign_verify(void) { +static void run_ecdsa_sign_verify(void) { int i; - for (i = 0; i < 10*count; i++) { + for (i = 0; i < 10*COUNT; i++) { test_ecdsa_sign_verify(); } } @@ -6209,201 +6358,201 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5); } -int is_empty_signature(const rustsecp256k1zkp_v0_8_0_ecdsa_signature *sig) { - static const unsigned char res[sizeof(rustsecp256k1zkp_v0_8_0_ecdsa_signature)] = {0}; - return rustsecp256k1zkp_v0_8_0_memcmp_var(sig, res, sizeof(rustsecp256k1zkp_v0_8_0_ecdsa_signature)) == 0; +static int is_empty_signature(const rustsecp256k1_v0_11_ecdsa_signature *sig) { + static const unsigned char res[sizeof(rustsecp256k1_v0_11_ecdsa_signature)] = {0}; + return rustsecp256k1_v0_11_memcmp_var(sig, res, sizeof(rustsecp256k1_v0_11_ecdsa_signature)) == 0; } -void test_ecdsa_end_to_end(void) { +static void test_ecdsa_end_to_end(void) { unsigned char extra[32] = {0x00}; unsigned char privkey[32]; unsigned char message[32]; unsigned char privkey2[32]; - rustsecp256k1zkp_v0_8_0_ecdsa_signature signature[6]; - rustsecp256k1zkp_v0_8_0_scalar r, s; + rustsecp256k1_v0_11_ecdsa_signature signature[6]; + rustsecp256k1_v0_11_scalar r, s; unsigned char sig[74]; size_t siglen = 74; unsigned char pubkeyc[65]; size_t pubkeyclen = 65; - rustsecp256k1zkp_v0_8_0_pubkey pubkey; - rustsecp256k1zkp_v0_8_0_pubkey pubkey_tmp; + rustsecp256k1_v0_11_pubkey pubkey; + rustsecp256k1_v0_11_pubkey pubkey_tmp; unsigned char seckey[300]; size_t seckeylen = 300; /* Generate a random key and message. */ { - rustsecp256k1zkp_v0_8_0_scalar msg, key; - random_scalar_order_test(&msg); - random_scalar_order_test(&key); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(privkey, &key); - rustsecp256k1zkp_v0_8_0_scalar_get_b32(message, &msg); + rustsecp256k1_v0_11_scalar msg, key; + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); + rustsecp256k1_v0_11_scalar_get_b32(privkey, &key); + rustsecp256k1_v0_11_scalar_get_b32(message, &msg); } /* Construct and verify corresponding public key. */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_seckey_verify(ctx, privkey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + CHECK(rustsecp256k1_v0_11_ec_seckey_verify(CTX, privkey) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey, privkey) == 1); /* Verify exporting and importing public key. */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, rustsecp256k1zkp_v0_8_0_testrand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_serialize(CTX, pubkeyc, &pubkeyclen, &pubkey, testrand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); memset(&pubkey, 0, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 1); /* Verify negation changes the key and changes it back */ memcpy(&pubkey_tmp, &pubkey, sizeof(pubkey)); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_negate(ctx, &pubkey_tmp) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_negate(ctx, &pubkey_tmp) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_negate(CTX, &pubkey_tmp) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_negate(CTX, &pubkey_tmp) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0); /* Verify private key import and export. */ - CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, rustsecp256k1zkp_v0_8_0_testrand_bits(1) == 1)); - CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(privkey, privkey2, 32) == 0); + CHECK(ec_privkey_export_der(CTX, seckey, &seckeylen, privkey, testrand_bits(1) == 1)); + CHECK(ec_privkey_import_der(CTX, privkey2, seckey, seckeylen) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(privkey, privkey2, 32) == 0); /* Optionally tweak the keys using addition. */ - if (rustsecp256k1zkp_v0_8_0_testrand_int(3) == 0) { + if (testrand_int(3) == 0) { int ret1; int ret2; int ret3; unsigned char rnd[32]; unsigned char privkey_tmp[32]; - rustsecp256k1zkp_v0_8_0_pubkey pubkey2; - rustsecp256k1zkp_v0_8_0_testrand256_test(rnd); + rustsecp256k1_v0_11_pubkey pubkey2; + testrand256_test(rnd); memcpy(privkey_tmp, privkey, 32); - ret1 = rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_add(ctx, privkey, rnd); - ret2 = rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_add(ctx, &pubkey, rnd); + ret1 = rustsecp256k1_v0_11_ec_seckey_tweak_add(CTX, privkey, rnd); + ret2 = rustsecp256k1_v0_11_ec_pubkey_tweak_add(CTX, &pubkey, rnd); /* Check that privkey alias gives same result */ - ret3 = rustsecp256k1zkp_v0_8_0_ec_privkey_tweak_add(ctx, privkey_tmp, rnd); + ret3 = rustsecp256k1_v0_11_ec_privkey_tweak_add(CTX, privkey_tmp, rnd); CHECK(ret1 == ret2); CHECK(ret2 == ret3); if (ret1 == 0) { return; } - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(privkey, privkey_tmp, 32) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(privkey, privkey_tmp, 32) == 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey2, privkey) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Optionally tweak the keys using multiplication. */ - if (rustsecp256k1zkp_v0_8_0_testrand_int(3) == 0) { + if (testrand_int(3) == 0) { int ret1; int ret2; int ret3; unsigned char rnd[32]; unsigned char privkey_tmp[32]; - rustsecp256k1zkp_v0_8_0_pubkey pubkey2; - rustsecp256k1zkp_v0_8_0_testrand256_test(rnd); + rustsecp256k1_v0_11_pubkey pubkey2; + testrand256_test(rnd); memcpy(privkey_tmp, privkey, 32); - ret1 = rustsecp256k1zkp_v0_8_0_ec_seckey_tweak_mul(ctx, privkey, rnd); - ret2 = rustsecp256k1zkp_v0_8_0_ec_pubkey_tweak_mul(ctx, &pubkey, rnd); + ret1 = rustsecp256k1_v0_11_ec_seckey_tweak_mul(CTX, privkey, rnd); + ret2 = rustsecp256k1_v0_11_ec_pubkey_tweak_mul(CTX, &pubkey, rnd); /* Check that privkey alias gives same result */ - ret3 = rustsecp256k1zkp_v0_8_0_ec_privkey_tweak_mul(ctx, privkey_tmp, rnd); + ret3 = rustsecp256k1_v0_11_ec_privkey_tweak_mul(CTX, privkey_tmp, rnd); CHECK(ret1 == ret2); CHECK(ret2 == ret3); if (ret1 == 0) { return; } - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(privkey, privkey_tmp, 32) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(privkey, privkey_tmp, 32) == 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey2, privkey) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Sign. */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &signature[4], message, privkey, NULL, NULL) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &signature[1], message, privkey, NULL, extra) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &signature[4], message, privkey, NULL, NULL) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &signature[1], message, privkey, NULL, extra) == 1); extra[31] = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &signature[2], message, privkey, NULL, extra) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &signature[2], message, privkey, NULL, extra) == 1); extra[31] = 0; extra[0] = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &signature[3], message, privkey, NULL, extra) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&signature[0], &signature[4], sizeof(signature[0])) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&signature[0], &signature[1], sizeof(signature[0])) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&signature[0], &signature[2], sizeof(signature[0])) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&signature[0], &signature[3], sizeof(signature[0])) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&signature[1], &signature[2], sizeof(signature[0])) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&signature[1], &signature[3], sizeof(signature[0])) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&signature[2], &signature[3], sizeof(signature[0])) != 0); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &signature[3], message, privkey, NULL, extra) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&signature[0], &signature[4], sizeof(signature[0])) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&signature[0], &signature[1], sizeof(signature[0])) != 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&signature[0], &signature[2], sizeof(signature[0])) != 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&signature[0], &signature[3], sizeof(signature[0])) != 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&signature[1], &signature[2], sizeof(signature[0])) != 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&signature[1], &signature[3], sizeof(signature[0])) != 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&signature[2], &signature[3], sizeof(signature[0])) != 0); /* Verify. */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &signature[1], message, &pubkey) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &signature[2], message, &pubkey) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &signature[3], message, &pubkey) == 1); /* Test lower-S form, malleate, verify and fail, test again, malleate again */ - CHECK(!rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize(ctx, NULL, &signature[0])); - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &r, &s, &signature[0]); - rustsecp256k1zkp_v0_8_0_scalar_negate(&s, &s); - rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(&signature[5], &r, &s); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize(ctx, NULL, &signature[5])); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); - CHECK(!rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize(ctx, NULL, &signature[5])); - CHECK(!rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); - rustsecp256k1zkp_v0_8_0_scalar_negate(&s, &s); - rustsecp256k1zkp_v0_8_0_ecdsa_signature_save(&signature[5], &r, &s); - CHECK(!rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize(ctx, NULL, &signature[5])); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&signature[5], &signature[0], 64) == 0); + CHECK(!rustsecp256k1_v0_11_ecdsa_signature_normalize(CTX, NULL, &signature[0])); + rustsecp256k1_v0_11_ecdsa_signature_load(CTX, &r, &s, &signature[0]); + rustsecp256k1_v0_11_scalar_negate(&s, &s); + rustsecp256k1_v0_11_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_normalize(CTX, NULL, &signature[5])); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_normalize(CTX, &signature[5], &signature[5])); + CHECK(!rustsecp256k1_v0_11_ecdsa_signature_normalize(CTX, NULL, &signature[5])); + CHECK(!rustsecp256k1_v0_11_ecdsa_signature_normalize(CTX, &signature[5], &signature[5])); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 1); + rustsecp256k1_v0_11_scalar_negate(&s, &s); + rustsecp256k1_v0_11_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(!rustsecp256k1_v0_11_ecdsa_signature_normalize(CTX, NULL, &signature[5])); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&signature[5], &signature[0], 64) == 0); /* Serialize/parse DER and verify again */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_serialize_der(CTX, sig, &siglen, &signature[0]) == 1); memset(&signature[0], 0, sizeof(signature[0])); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &signature[0], sig, siglen) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 1); /* Serialize/destroy/parse DER and verify again. */ siglen = 74; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); - sig[rustsecp256k1zkp_v0_8_0_testrand_int(siglen)] += 1 + rustsecp256k1zkp_v0_8_0_testrand_int(255); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 || - rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_serialize_der(CTX, sig, &siglen, &signature[0]) == 1); + sig[testrand_int(siglen)] += 1 + testrand_int(255); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &signature[0], sig, siglen) == 0 || + rustsecp256k1_v0_11_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 0); } -void test_random_pubkeys(void) { - rustsecp256k1zkp_v0_8_0_ge elem; - rustsecp256k1zkp_v0_8_0_ge elem2; +static void test_random_pubkeys(void) { + rustsecp256k1_v0_11_ge elem; + rustsecp256k1_v0_11_ge elem2; unsigned char in[65]; /* Generate some randomly sized pubkeys. */ - size_t len = rustsecp256k1zkp_v0_8_0_testrand_bits(2) == 0 ? 65 : 33; - if (rustsecp256k1zkp_v0_8_0_testrand_bits(2) == 0) { - len = rustsecp256k1zkp_v0_8_0_testrand_bits(6); + size_t len = testrand_bits(2) == 0 ? 65 : 33; + if (testrand_bits(2) == 0) { + len = testrand_bits(6); } if (len == 65) { - in[0] = rustsecp256k1zkp_v0_8_0_testrand_bits(1) ? 4 : (rustsecp256k1zkp_v0_8_0_testrand_bits(1) ? 6 : 7); + in[0] = testrand_bits(1) ? 4 : (testrand_bits(1) ? 6 : 7); } else { - in[0] = rustsecp256k1zkp_v0_8_0_testrand_bits(1) ? 2 : 3; + in[0] = testrand_bits(1) ? 2 : 3; } - if (rustsecp256k1zkp_v0_8_0_testrand_bits(3) == 0) { - in[0] = rustsecp256k1zkp_v0_8_0_testrand_bits(8); + if (testrand_bits(3) == 0) { + in[0] = testrand_bits(8); } if (len > 1) { - rustsecp256k1zkp_v0_8_0_testrand256(&in[1]); + testrand256(&in[1]); } if (len > 33) { - rustsecp256k1zkp_v0_8_0_testrand256(&in[33]); + testrand256(&in[33]); } - if (rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&elem, in, len)) { + if (rustsecp256k1_v0_11_eckey_pubkey_parse(&elem, in, len)) { unsigned char out[65]; unsigned char firstb; int res; size_t size = len; firstb = in[0]; /* If the pubkey can be parsed, it should round-trip... */ - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&elem, out, &size, len == 33)); + CHECK(rustsecp256k1_v0_11_eckey_pubkey_serialize(&elem, out, &size, len == 33)); CHECK(size == len); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&in[1], &out[1], len-1) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&in[1], &out[1], len-1) == 0); /* ... except for the type of hybrid inputs. */ if ((in[0] != 6) && (in[0] != 7)) { CHECK(in[0] == out[0]); } size = 65; - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&elem, in, &size, 0)); + CHECK(rustsecp256k1_v0_11_eckey_pubkey_serialize(&elem, in, &size, 0)); CHECK(size == 65); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&elem2, in, size)); - ge_equals_ge(&elem,&elem2); + CHECK(rustsecp256k1_v0_11_eckey_pubkey_parse(&elem2, in, size)); + CHECK(rustsecp256k1_v0_11_ge_eq_var(&elem2, &elem)); /* Check that the X9.62 hybrid type is checked. */ - in[0] = rustsecp256k1zkp_v0_8_0_testrand_bits(1) ? 6 : 7; - res = rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&elem2, in, size); + in[0] = testrand_bits(1) ? 6 : 7; + res = rustsecp256k1_v0_11_eckey_pubkey_parse(&elem2, in, size); if (firstb == 2 || firstb == 3) { if (in[0] == firstb + 4) { CHECK(res); @@ -6412,14 +6561,14 @@ void test_random_pubkeys(void) { } } if (res) { - ge_equals_ge(&elem,&elem2); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_serialize(&elem, out, &size, 0)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&in[1], &out[1], 64) == 0); + CHECK(rustsecp256k1_v0_11_ge_eq_var(&elem, &elem2)); + CHECK(rustsecp256k1_v0_11_eckey_pubkey_serialize(&elem, out, &size, 0)); + CHECK(rustsecp256k1_v0_11_memcmp_var(&in[1], &out[1], 64) == 0); } } } -void run_pubkey_comparison(void) { +static void run_pubkey_comparison(void) { unsigned char pk1_ser[33] = { 0x02, 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, @@ -6430,93 +6579,236 @@ void run_pubkey_comparison(void) { 0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d, 0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c }; - rustsecp256k1zkp_v0_8_0_pubkey pk1; - rustsecp256k1zkp_v0_8_0_pubkey pk2; - int32_t ecount = 0; - - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pk1, pk1_ser, sizeof(pk1_ser)) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pk2, pk2_ser, sizeof(pk2_ser)) == 1); - - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp(ctx, NULL, &pk2) < 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp(ctx, &pk1, NULL) > 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp(ctx, &pk1, &pk2) < 0); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp(ctx, &pk2, &pk1) > 0); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp(ctx, &pk1, &pk1) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp(ctx, &pk2, &pk2) == 0); - CHECK(ecount == 2); + rustsecp256k1_v0_11_pubkey pk1; + rustsecp256k1_v0_11_pubkey pk2; + + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pk1, pk1_ser, sizeof(pk1_ser)) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pk2, pk2_ser, sizeof(pk2_ser)) == 1); + + CHECK_ILLEGAL_VOID(CTX, CHECK(rustsecp256k1_v0_11_ec_pubkey_cmp(CTX, NULL, &pk2) < 0)); + CHECK_ILLEGAL_VOID(CTX, CHECK(rustsecp256k1_v0_11_ec_pubkey_cmp(CTX, &pk1, NULL) > 0)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_cmp(CTX, &pk1, &pk2) < 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_cmp(CTX, &pk2, &pk1) > 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_cmp(CTX, &pk1, &pk1) == 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_cmp(CTX, &pk2, &pk2) == 0); { - rustsecp256k1zkp_v0_8_0_pubkey pk_tmp; + rustsecp256k1_v0_11_pubkey pk_tmp; memset(&pk_tmp, 0, sizeof(pk_tmp)); /* illegal pubkey */ - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp(ctx, &pk_tmp, &pk2) < 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp(ctx, &pk_tmp, &pk_tmp) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp(ctx, &pk2, &pk_tmp) > 0); - CHECK(ecount == 6); + CHECK_ILLEGAL_VOID(CTX, CHECK(rustsecp256k1_v0_11_ec_pubkey_cmp(CTX, &pk_tmp, &pk2) < 0)); + { + int32_t ecount = 0; + rustsecp256k1_v0_11_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); + CHECK(rustsecp256k1_v0_11_ec_pubkey_cmp(CTX, &pk_tmp, &pk_tmp) == 0); + CHECK(ecount == 2); + rustsecp256k1_v0_11_context_set_illegal_callback(CTX, NULL, NULL); + } + CHECK_ILLEGAL_VOID(CTX, CHECK(rustsecp256k1_v0_11_ec_pubkey_cmp(CTX, &pk2, &pk_tmp) > 0)); } - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(ctx, NULL, NULL); - /* Make pk2 the same as pk1 but with 3 rather than 2. Note that in * an uncompressed encoding, these would have the opposite ordering */ pk1_ser[0] = 3; - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_parse(ctx, &pk2, pk1_ser, sizeof(pk1_ser)) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp(ctx, &pk1, &pk2) < 0); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_cmp(ctx, &pk2, &pk1) > 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pk2, pk1_ser, sizeof(pk1_ser)) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_cmp(CTX, &pk1, &pk2) < 0); + CHECK(rustsecp256k1_v0_11_ec_pubkey_cmp(CTX, &pk2, &pk1) > 0); +} + +static void test_sort_helper(rustsecp256k1_v0_11_pubkey *pk, size_t *pk_order, size_t n_pk) { + size_t i; + const rustsecp256k1_v0_11_pubkey *pk_test[5]; + + for (i = 0; i < n_pk; i++) { + pk_test[i] = &pk[pk_order[i]]; + } + rustsecp256k1_v0_11_ec_pubkey_sort(CTX, pk_test, n_pk); + for (i = 0; i < n_pk; i++) { + CHECK(rustsecp256k1_v0_11_memcmp_var(pk_test[i], &pk[i], sizeof(*pk_test[i])) == 0); + } +} + +static void permute(size_t *arr, size_t n) { + size_t i; + for (i = n - 1; i >= 1; i--) { + size_t tmp, j; + j = testrand_int(i + 1); + tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } } -void run_random_pubkeys(void) { +static void test_sort_api(void) { + rustsecp256k1_v0_11_pubkey pks[2]; + const rustsecp256k1_v0_11_pubkey *pks_ptr[2]; + + pks_ptr[0] = &pks[0]; + pks_ptr[1] = &pks[1]; + + testutil_random_pubkey_test(&pks[0]); + testutil_random_pubkey_test(&pks[1]); + + CHECK(rustsecp256k1_v0_11_ec_pubkey_sort(CTX, pks_ptr, 2) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_sort(CTX, NULL, 2)); + CHECK(rustsecp256k1_v0_11_ec_pubkey_sort(CTX, pks_ptr, 0) == 1); + /* Test illegal public keys */ + memset(&pks[0], 0, sizeof(pks[0])); + CHECK_ILLEGAL_VOID(CTX, CHECK(rustsecp256k1_v0_11_ec_pubkey_sort(CTX, pks_ptr, 2) == 1)); + memset(&pks[1], 0, sizeof(pks[1])); + { + int32_t ecount = 0; + rustsecp256k1_v0_11_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); + CHECK(rustsecp256k1_v0_11_ec_pubkey_sort(CTX, pks_ptr, 2) == 1); + CHECK(ecount == 2); + rustsecp256k1_v0_11_context_set_illegal_callback(CTX, NULL, NULL); + } +} + +static void test_sort(void) { + rustsecp256k1_v0_11_pubkey pk[5]; + unsigned char pk_ser[5][33] = { + { 0x02, 0x08 }, + { 0x02, 0x0b }, + { 0x02, 0x0c }, + { 0x03, 0x05 }, + { 0x03, 0x0a }, + }; int i; - for (i = 0; i < 10*count; i++) { + size_t pk_order[5] = { 0, 1, 2, 3, 4 }; + + for (i = 0; i < 5; i++) { + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pk[i], pk_ser[i], sizeof(pk_ser[i]))); + } + + permute(pk_order, 1); + test_sort_helper(pk, pk_order, 1); + permute(pk_order, 2); + test_sort_helper(pk, pk_order, 2); + permute(pk_order, 3); + test_sort_helper(pk, pk_order, 3); + for (i = 0; i < COUNT; i++) { + permute(pk_order, 4); + test_sort_helper(pk, pk_order, 4); + } + for (i = 0; i < COUNT; i++) { + permute(pk_order, 5); + test_sort_helper(pk, pk_order, 5); + } + /* Check that sorting also works for random pubkeys */ + for (i = 0; i < COUNT; i++) { + int j; + const rustsecp256k1_v0_11_pubkey *pk_ptr[5]; + for (j = 0; j < 5; j++) { + testutil_random_pubkey_test(&pk[j]); + pk_ptr[j] = &pk[j]; + } + rustsecp256k1_v0_11_ec_pubkey_sort(CTX, pk_ptr, 5); + for (j = 1; j < 5; j++) { + CHECK(rustsecp256k1_v0_11_ec_pubkey_sort_cmp(&pk_ptr[j - 1], &pk_ptr[j], CTX) <= 0); + } + } +} + +/* Test vectors from BIP-MuSig2 */ +static void test_sort_vectors(void) { + enum { N_PUBKEYS = 6 }; + unsigned char pk_ser[N_PUBKEYS][33] = { + { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, + 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, + 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 }, + { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, + 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, + 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, + { 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, + 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, + 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }, + { 0x02, 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, 0x15, 0xC2, + 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, 0x14, 0x93, 0x16, 0xC3, 0x51, + 0x8C, 0xE7, 0xB7, 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 }, + { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, + 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, + 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xFF }, + { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, + 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, + 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 } + }; + rustsecp256k1_v0_11_pubkey pubkeys[N_PUBKEYS]; + rustsecp256k1_v0_11_pubkey *sorted[N_PUBKEYS]; + const rustsecp256k1_v0_11_pubkey *pks_ptr[N_PUBKEYS]; + int i; + + sorted[0] = &pubkeys[3]; + sorted[1] = &pubkeys[0]; + sorted[2] = &pubkeys[0]; + sorted[3] = &pubkeys[4]; + sorted[4] = &pubkeys[1]; + sorted[5] = &pubkeys[2]; + + for (i = 0; i < N_PUBKEYS; i++) { + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkeys[i], pk_ser[i], sizeof(pk_ser[i]))); + pks_ptr[i] = &pubkeys[i]; + } + CHECK(rustsecp256k1_v0_11_ec_pubkey_sort(CTX, pks_ptr, N_PUBKEYS) == 1); + for (i = 0; i < N_PUBKEYS; i++) { + CHECK(rustsecp256k1_v0_11_memcmp_var(pks_ptr[i], sorted[i], sizeof(rustsecp256k1_v0_11_pubkey)) == 0); + } +} + +static void run_pubkey_sort(void) { + test_sort_api(); + test_sort(); + test_sort_vectors(); +} + + +static void run_random_pubkeys(void) { + int i; + for (i = 0; i < 10*COUNT; i++) { test_random_pubkeys(); } } -void run_ecdsa_end_to_end(void) { +static void run_ecdsa_end_to_end(void) { int i; - for (i = 0; i < 64*count; i++) { + for (i = 0; i < 64*COUNT; i++) { test_ecdsa_end_to_end(); } } -int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { +static int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { static const unsigned char zeroes[32] = {0}; int ret = 0; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig_der; + rustsecp256k1_v0_11_ecdsa_signature sig_der; unsigned char roundtrip_der[2048]; unsigned char compact_der[64]; size_t len_der = 2048; int parsed_der = 0, valid_der = 0, roundtrips_der = 0; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig_der_lax; + rustsecp256k1_v0_11_ecdsa_signature sig_der_lax; unsigned char roundtrip_der_lax[2048]; unsigned char compact_der_lax[64]; size_t len_der_lax = 2048; int parsed_der_lax = 0, valid_der_lax = 0, roundtrips_der_lax = 0; - parsed_der = rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig_der, sig, siglen); + parsed_der = rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig_der, sig, siglen); if (parsed_der) { - ret |= (!rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact(ctx, compact_der, &sig_der)) << 0; - valid_der = (rustsecp256k1zkp_v0_8_0_memcmp_var(compact_der, zeroes, 32) != 0) && (rustsecp256k1zkp_v0_8_0_memcmp_var(compact_der + 32, zeroes, 32) != 0); + ret |= (!rustsecp256k1_v0_11_ecdsa_signature_serialize_compact(CTX, compact_der, &sig_der)) << 0; + valid_der = (rustsecp256k1_v0_11_memcmp_var(compact_der, zeroes, 32) != 0) && (rustsecp256k1_v0_11_memcmp_var(compact_der + 32, zeroes, 32) != 0); } if (valid_der) { - ret |= (!rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der(ctx, roundtrip_der, &len_der, &sig_der)) << 1; - roundtrips_der = (len_der == siglen) && rustsecp256k1zkp_v0_8_0_memcmp_var(roundtrip_der, sig, siglen) == 0; + ret |= (!rustsecp256k1_v0_11_ecdsa_signature_serialize_der(CTX, roundtrip_der, &len_der, &sig_der)) << 1; + roundtrips_der = (len_der == siglen) && rustsecp256k1_v0_11_memcmp_var(roundtrip_der, sig, siglen) == 0; } - parsed_der_lax = rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen); + parsed_der_lax = rustsecp256k1_v0_11_ecdsa_signature_parse_der_lax(CTX, &sig_der_lax, sig, siglen); if (parsed_der_lax) { - ret |= (!rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10; - valid_der_lax = (rustsecp256k1zkp_v0_8_0_memcmp_var(compact_der_lax, zeroes, 32) != 0) && (rustsecp256k1zkp_v0_8_0_memcmp_var(compact_der_lax + 32, zeroes, 32) != 0); + ret |= (!rustsecp256k1_v0_11_ecdsa_signature_serialize_compact(CTX, compact_der_lax, &sig_der_lax)) << 10; + valid_der_lax = (rustsecp256k1_v0_11_memcmp_var(compact_der_lax, zeroes, 32) != 0) && (rustsecp256k1_v0_11_memcmp_var(compact_der_lax + 32, zeroes, 32) != 0); } if (valid_der_lax) { - ret |= (!rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der(ctx, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11; - roundtrips_der_lax = (len_der_lax == siglen) && rustsecp256k1zkp_v0_8_0_memcmp_var(roundtrip_der_lax, sig, siglen) == 0; + ret |= (!rustsecp256k1_v0_11_ecdsa_signature_serialize_der(CTX, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11; + roundtrips_der_lax = (len_der_lax == siglen) && rustsecp256k1_v0_11_memcmp_var(roundtrip_der_lax, sig, siglen) == 0; } if (certainly_der) { @@ -6532,7 +6824,7 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_ if (valid_der) { ret |= (!roundtrips_der_lax) << 12; ret |= (len_der != len_der_lax) << 13; - ret |= ((len_der != len_der_lax) || (rustsecp256k1zkp_v0_8_0_memcmp_var(roundtrip_der_lax, roundtrip_der, len_der) != 0)) << 14; + ret |= ((len_der != len_der_lax) || (rustsecp256k1_v0_11_memcmp_var(roundtrip_der_lax, roundtrip_der, len_der) != 0)) << 14; } ret |= (roundtrips_der != roundtrips_der_lax) << 15; if (parsed_der) { @@ -6556,27 +6848,27 @@ static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) { static void damage_array(unsigned char *sig, size_t *len) { int pos; - int action = rustsecp256k1zkp_v0_8_0_testrand_bits(3); + int action = testrand_bits(3); if (action < 1 && *len > 3) { /* Delete a byte. */ - pos = rustsecp256k1zkp_v0_8_0_testrand_int(*len); + pos = testrand_int(*len); memmove(sig + pos, sig + pos + 1, *len - pos - 1); (*len)--; return; } else if (action < 2 && *len < 2048) { /* Insert a byte. */ - pos = rustsecp256k1zkp_v0_8_0_testrand_int(1 + *len); + pos = testrand_int(1 + *len); memmove(sig + pos + 1, sig + pos, *len - pos); - sig[pos] = rustsecp256k1zkp_v0_8_0_testrand_bits(8); + sig[pos] = testrand_bits(8); (*len)++; return; } else if (action < 4) { /* Modify a byte. */ - sig[rustsecp256k1zkp_v0_8_0_testrand_int(*len)] += 1 + rustsecp256k1zkp_v0_8_0_testrand_int(255); + sig[testrand_int(*len)] += 1 + testrand_int(255); return; } else { /* action < 8 */ /* Modify a bit. */ - sig[rustsecp256k1zkp_v0_8_0_testrand_int(*len)] ^= 1 << rustsecp256k1zkp_v0_8_0_testrand_bits(3); + sig[testrand_int(*len)] ^= 1 << testrand_bits(3); return; } } @@ -6589,23 +6881,23 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly int n; *len = 0; - der = rustsecp256k1zkp_v0_8_0_testrand_bits(2) == 0; + der = testrand_bits(2) == 0; *certainly_der = der; *certainly_not_der = 0; - indet = der ? 0 : rustsecp256k1zkp_v0_8_0_testrand_int(10) == 0; + indet = der ? 0 : testrand_int(10) == 0; for (n = 0; n < 2; n++) { /* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */ - nlow[n] = der ? 1 : (rustsecp256k1zkp_v0_8_0_testrand_bits(3) != 0); + nlow[n] = der ? 1 : (testrand_bits(3) != 0); /* The length of the number in bytes (the first byte of which will always be nonzero) */ - nlen[n] = nlow[n] ? rustsecp256k1zkp_v0_8_0_testrand_int(33) : 32 + rustsecp256k1zkp_v0_8_0_testrand_int(200) * rustsecp256k1zkp_v0_8_0_testrand_bits(3) / 8; + nlen[n] = nlow[n] ? testrand_int(33) : 32 + testrand_int(200) * testrand_bits(3) / 8; CHECK(nlen[n] <= 232); /* The top bit of the number. */ - nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : rustsecp256k1zkp_v0_8_0_testrand_bits(1)); + nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : testrand_bits(1)); /* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */ - nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + rustsecp256k1zkp_v0_8_0_testrand_bits(7) : 1 + rustsecp256k1zkp_v0_8_0_testrand_int(127)); + nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + testrand_bits(7) : 1 + testrand_int(127)); /* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */ - nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? rustsecp256k1zkp_v0_8_0_testrand_int(3) : rustsecp256k1zkp_v0_8_0_testrand_int(300 - nlen[n]) * rustsecp256k1zkp_v0_8_0_testrand_bits(3) / 8); + nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? testrand_int(3) : testrand_int(300 - nlen[n]) * testrand_bits(3) / 8); if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) { *certainly_not_der = 1; } @@ -6614,7 +6906,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2); if (!der) { /* nlenlen[n] max 127 bytes */ - int add = rustsecp256k1zkp_v0_8_0_testrand_int(127 - nlenlen[n]) * rustsecp256k1zkp_v0_8_0_testrand_bits(4) * rustsecp256k1zkp_v0_8_0_testrand_bits(4) / 256; + int add = testrand_int(127 - nlenlen[n]) * testrand_bits(4) * testrand_bits(4) / 256; nlenlen[n] += add; if (add != 0) { *certainly_not_der = 1; @@ -6628,7 +6920,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly CHECK(tlen <= 856); /* The length of the garbage inside the tuple. */ - elen = (der || indet) ? 0 : rustsecp256k1zkp_v0_8_0_testrand_int(980 - tlen) * rustsecp256k1zkp_v0_8_0_testrand_bits(3) / 8; + elen = (der || indet) ? 0 : testrand_int(980 - tlen) * testrand_bits(3) / 8; if (elen != 0) { *certainly_not_der = 1; } @@ -6636,7 +6928,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly CHECK(tlen <= 980); /* The length of the garbage after the end of the tuple. */ - glen = der ? 0 : rustsecp256k1zkp_v0_8_0_testrand_int(990 - tlen) * rustsecp256k1zkp_v0_8_0_testrand_bits(3) / 8; + glen = der ? 0 : testrand_int(990 - tlen) * testrand_bits(3) / 8; if (glen != 0) { *certainly_not_der = 1; } @@ -6651,7 +6943,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly } else { int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2); if (!der) { - int add = rustsecp256k1zkp_v0_8_0_testrand_int(127 - tlenlen) * rustsecp256k1zkp_v0_8_0_testrand_bits(4) * rustsecp256k1zkp_v0_8_0_testrand_bits(4) / 256; + int add = testrand_int(127 - tlenlen) * testrand_bits(4) * testrand_bits(4) / 256; tlenlen += add; if (add != 0) { *certainly_not_der = 1; @@ -6702,13 +6994,13 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly nlen[n]--; } /* Generate remaining random bytes of number */ - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(sig + *len, nlen[n]); + testrand_bytes_test(sig + *len, nlen[n]); *len += nlen[n]; nlen[n] = 0; } /* Generate random garbage inside tuple. */ - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(sig + *len, elen); + testrand_bytes_test(sig + *len, elen); *len += elen; /* Generate end-of-contents bytes. */ @@ -6720,16 +7012,16 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly CHECK(tlen + glen <= 1121); /* Generate random garbage outside tuple. */ - rustsecp256k1zkp_v0_8_0_testrand_bytes_test(sig + *len, glen); + testrand_bytes_test(sig + *len, glen); *len += glen; tlen += glen; CHECK(tlen <= 1121); CHECK(tlen == *len); } -void run_ecdsa_der_parse(void) { +static void run_ecdsa_der_parse(void) { int i,j; - for (i = 0; i < 200 * count; i++) { + for (i = 0; i < 200 * COUNT; i++) { unsigned char buffer[2048]; size_t buflen = 0; int certainly_der = 0; @@ -6759,24 +7051,24 @@ void run_ecdsa_der_parse(void) { } /* Tests several edge cases. */ -void test_ecdsa_edge_cases(void) { +static void test_ecdsa_edge_cases(void) { int t; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig; + rustsecp256k1_v0_11_ecdsa_signature sig; /* Test the case where ECDSA recomputes a point that is infinity. */ { - rustsecp256k1zkp_v0_8_0_gej keyj; - rustsecp256k1zkp_v0_8_0_ge key; - rustsecp256k1zkp_v0_8_0_scalar msg; - rustsecp256k1zkp_v0_8_0_scalar sr, ss; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&ss, 1); - rustsecp256k1zkp_v0_8_0_scalar_negate(&ss, &ss); - rustsecp256k1zkp_v0_8_0_scalar_inverse(&ss, &ss); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&sr, 1); - rustsecp256k1zkp_v0_8_0_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr); - rustsecp256k1zkp_v0_8_0_ge_set_gej(&key, &keyj); + rustsecp256k1_v0_11_gej keyj; + rustsecp256k1_v0_11_ge key; + rustsecp256k1_v0_11_scalar msg; + rustsecp256k1_v0_11_scalar sr, ss; + rustsecp256k1_v0_11_scalar_set_int(&ss, 1); + rustsecp256k1_v0_11_scalar_negate(&ss, &ss); + rustsecp256k1_v0_11_scalar_inverse(&ss, &ss); + rustsecp256k1_v0_11_scalar_set_int(&sr, 1); + rustsecp256k1_v0_11_ecmult_gen(&CTX->ecmult_gen_ctx, &keyj, &sr); + rustsecp256k1_v0_11_ge_set_gej(&key, &keyj); msg = ss; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); } /* Verify signature with r of zero fails. */ @@ -6788,14 +7080,14 @@ void test_ecdsa_edge_cases(void) { 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 }; - rustsecp256k1zkp_v0_8_0_ge key; - rustsecp256k1zkp_v0_8_0_scalar msg; - rustsecp256k1zkp_v0_8_0_scalar sr, ss; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&ss, 1); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&msg, 0); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&sr, 0); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&key, pubkey_mods_zero, 33)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify( &sr, &ss, &key, &msg) == 0); + rustsecp256k1_v0_11_ge key; + rustsecp256k1_v0_11_scalar msg; + rustsecp256k1_v0_11_scalar sr, ss; + rustsecp256k1_v0_11_scalar_set_int(&ss, 1); + rustsecp256k1_v0_11_scalar_set_int(&msg, 0); + rustsecp256k1_v0_11_scalar_set_int(&sr, 0); + CHECK(rustsecp256k1_v0_11_eckey_pubkey_parse(&key, pubkey_mods_zero, 33)); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify( &sr, &ss, &key, &msg) == 0); } /* Verify signature with s of zero fails. */ @@ -6807,14 +7099,14 @@ void test_ecdsa_edge_cases(void) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; - rustsecp256k1zkp_v0_8_0_ge key; - rustsecp256k1zkp_v0_8_0_scalar msg; - rustsecp256k1zkp_v0_8_0_scalar sr, ss; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&ss, 0); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&msg, 0); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&sr, 1); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&key, pubkey, 33)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); + rustsecp256k1_v0_11_ge key; + rustsecp256k1_v0_11_scalar msg; + rustsecp256k1_v0_11_scalar sr, ss; + rustsecp256k1_v0_11_scalar_set_int(&ss, 0); + rustsecp256k1_v0_11_scalar_set_int(&msg, 0); + rustsecp256k1_v0_11_scalar_set_int(&sr, 1); + CHECK(rustsecp256k1_v0_11_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); } /* Verify signature with message 0 passes. */ @@ -6833,23 +7125,23 @@ void test_ecdsa_edge_cases(void) { 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x43 }; - rustsecp256k1zkp_v0_8_0_ge key; - rustsecp256k1zkp_v0_8_0_ge key2; - rustsecp256k1zkp_v0_8_0_scalar msg; - rustsecp256k1zkp_v0_8_0_scalar sr, ss; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&ss, 2); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&msg, 0); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&sr, 2); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&key, pubkey, 33)); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&key2, pubkey2, 33)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); - rustsecp256k1zkp_v0_8_0_scalar_negate(&ss, &ss); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&ss, 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 0); + rustsecp256k1_v0_11_ge key; + rustsecp256k1_v0_11_ge key2; + rustsecp256k1_v0_11_scalar msg; + rustsecp256k1_v0_11_scalar sr, ss; + rustsecp256k1_v0_11_scalar_set_int(&ss, 2); + rustsecp256k1_v0_11_scalar_set_int(&msg, 0); + rustsecp256k1_v0_11_scalar_set_int(&sr, 2); + CHECK(rustsecp256k1_v0_11_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(rustsecp256k1_v0_11_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); + rustsecp256k1_v0_11_scalar_negate(&ss, &ss); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); + rustsecp256k1_v0_11_scalar_set_int(&ss, 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 0); } /* Verify signature with message 1 passes. */ @@ -6874,24 +7166,24 @@ void test_ecdsa_edge_cases(void) { 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xeb }; - rustsecp256k1zkp_v0_8_0_ge key; - rustsecp256k1zkp_v0_8_0_ge key2; - rustsecp256k1zkp_v0_8_0_scalar msg; - rustsecp256k1zkp_v0_8_0_scalar sr, ss; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&ss, 1); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&msg, 1); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&sr, csr, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&key, pubkey, 33)); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&key2, pubkey2, 33)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); - rustsecp256k1zkp_v0_8_0_scalar_negate(&ss, &ss); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&ss, 2); - rustsecp256k1zkp_v0_8_0_scalar_inverse_var(&ss, &ss); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 0); + rustsecp256k1_v0_11_ge key; + rustsecp256k1_v0_11_ge key2; + rustsecp256k1_v0_11_scalar msg; + rustsecp256k1_v0_11_scalar sr, ss; + rustsecp256k1_v0_11_scalar_set_int(&ss, 1); + rustsecp256k1_v0_11_scalar_set_int(&msg, 1); + rustsecp256k1_v0_11_scalar_set_b32(&sr, csr, NULL); + CHECK(rustsecp256k1_v0_11_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(rustsecp256k1_v0_11_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); + rustsecp256k1_v0_11_scalar_negate(&ss, &ss); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); + rustsecp256k1_v0_11_scalar_set_int(&ss, 2); + rustsecp256k1_v0_11_scalar_inverse_var(&ss, &ss); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 0); } /* Verify signature with message -1 passes. */ @@ -6909,27 +7201,26 @@ void test_ecdsa_edge_cases(void) { 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xee }; - rustsecp256k1zkp_v0_8_0_ge key; - rustsecp256k1zkp_v0_8_0_scalar msg; - rustsecp256k1zkp_v0_8_0_scalar sr, ss; - rustsecp256k1zkp_v0_8_0_scalar_set_int(&ss, 1); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&msg, 1); - rustsecp256k1zkp_v0_8_0_scalar_negate(&msg, &msg); - rustsecp256k1zkp_v0_8_0_scalar_set_b32(&sr, csr, NULL); - CHECK(rustsecp256k1zkp_v0_8_0_eckey_pubkey_parse(&key, pubkey, 33)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); - rustsecp256k1zkp_v0_8_0_scalar_negate(&ss, &ss); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); - rustsecp256k1zkp_v0_8_0_scalar_set_int(&ss, 3); - rustsecp256k1zkp_v0_8_0_scalar_inverse_var(&ss, &ss); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); + rustsecp256k1_v0_11_ge key; + rustsecp256k1_v0_11_scalar msg; + rustsecp256k1_v0_11_scalar sr, ss; + rustsecp256k1_v0_11_scalar_set_int(&ss, 1); + rustsecp256k1_v0_11_scalar_set_int(&msg, 1); + rustsecp256k1_v0_11_scalar_negate(&msg, &msg); + rustsecp256k1_v0_11_scalar_set_b32(&sr, csr, NULL); + CHECK(rustsecp256k1_v0_11_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + rustsecp256k1_v0_11_scalar_negate(&ss, &ss); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + rustsecp256k1_v0_11_scalar_set_int(&ss, 3); + rustsecp256k1_v0_11_scalar_inverse_var(&ss, &ss); + CHECK(rustsecp256k1_v0_11_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); } /* Signature where s would be zero. */ { - rustsecp256k1zkp_v0_8_0_pubkey pubkey; + rustsecp256k1_v0_11_pubkey pubkey; size_t siglen; - int32_t ecount; unsigned char signature[72]; static const unsigned char nonce[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -6955,72 +7246,42 @@ void test_ecdsa_edge_cases(void) { 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, }; - ecount = 0; - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); msg[31] = 0xaa; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1); - CHECK(ecount == 0); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, NULL, msg, key, precomputed_nonce_function, nonce2) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, key) == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, NULL, msg, &pubkey) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, NULL, &pubkey) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg, NULL) == 0); - CHECK(ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1); - CHECK(ecount == 6); - CHECK(rustsecp256k1zkp_v0_8_0_ec_pubkey_create(ctx, &pubkey, NULL) == 0); - CHECK(ecount == 7); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_sign(CTX, NULL, msg, key, precomputed_nonce_function, nonce2)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig, NULL, key, precomputed_nonce_function, nonce2)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig, msg, NULL, precomputed_nonce_function, nonce2)); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); + CHECK(rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey, key) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_verify(CTX, NULL, msg, &pubkey)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_verify(CTX, &sig, NULL, &pubkey)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_verify(CTX, &sig, msg, NULL)); + CHECK(rustsecp256k1_v0_11_ecdsa_verify(CTX, &sig, msg, &pubkey) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ec_pubkey_create(CTX, &pubkey, NULL)); /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_verify(ctx, &sig, msg, &pubkey) == 0); - CHECK(ecount == 8); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_verify(CTX, &sig, msg, &pubkey)); siglen = 72; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der(ctx, NULL, &siglen, &sig) == 0); - CHECK(ecount == 9); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der(ctx, signature, NULL, &sig) == 0); - CHECK(ecount == 10); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der(ctx, signature, &siglen, NULL) == 0); - CHECK(ecount == 11); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1); - CHECK(ecount == 11); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, NULL, signature, siglen) == 0); - CHECK(ecount == 12); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, NULL, siglen) == 0); - CHECK(ecount == 13); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_der(ctx, &sig, signature, siglen) == 1); - CHECK(ecount == 13); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_signature_serialize_der(CTX, NULL, &siglen, &sig)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_signature_serialize_der(CTX, signature, NULL, &sig)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_signature_serialize_der(CTX, signature, &siglen, NULL)); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, NULL, signature, siglen)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, NULL, siglen)); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &sig, signature, siglen) == 1); siglen = 10; /* Too little room for a signature does not fail via ARGCHECK. */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0); - CHECK(ecount == 13); - ecount = 0; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_normalize(ctx, NULL, NULL) == 0); - CHECK(ecount == 1); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact(ctx, NULL, &sig) == 0); - CHECK(ecount == 2); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact(ctx, signature, NULL) == 0); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_serialize_compact(ctx, signature, &sig) == 1); - CHECK(ecount == 3); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact(ctx, NULL, signature) == 0); - CHECK(ecount == 4); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact(ctx, &sig, NULL) == 0); - CHECK(ecount == 5); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact(ctx, &sig, signature) == 1); - CHECK(ecount == 5); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 0); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_signature_normalize(CTX, NULL, NULL)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_signature_serialize_compact(CTX, NULL, &sig)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_signature_serialize_compact(CTX, signature, NULL)); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_serialize_compact(CTX, signature, &sig) == 1); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_signature_parse_compact(CTX, NULL, signature)); + CHECK_ILLEGAL(CTX, rustsecp256k1_v0_11_ecdsa_signature_parse_compact(CTX, &sig, NULL)); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_compact(CTX, &sig, signature) == 1); memset(signature, 255, 64); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_signature_parse_compact(ctx, &sig, signature) == 0); - CHECK(ecount == 5); - rustsecp256k1zkp_v0_8_0_context_set_illegal_callback(ctx, NULL, NULL); + CHECK(rustsecp256k1_v0_11_ecdsa_signature_parse_compact(CTX, &sig, signature) == 0); } /* Nonce function corner cases. */ @@ -7029,43 +7290,43 @@ void test_ecdsa_edge_cases(void) { int i; unsigned char key[32]; unsigned char msg[32]; - rustsecp256k1zkp_v0_8_0_ecdsa_signature sig2; - rustsecp256k1zkp_v0_8_0_scalar sr[512], ss; + rustsecp256k1_v0_11_ecdsa_signature sig2; + rustsecp256k1_v0_11_scalar sr[512], ss; const unsigned char *extra; extra = t == 0 ? NULL : zero; memset(msg, 0, 32); msg[31] = 1; /* High key results in signature failure. */ memset(key, 0xFF, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig, msg, key, NULL, extra) == 0); CHECK(is_empty_signature(&sig)); /* Zero key results in signature failure. */ memset(key, 0, 32); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig, msg, key, NULL, extra) == 0); CHECK(is_empty_signature(&sig)); /* Nonce function failure results in signature failure. */ key[31] = 1; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_fail, extra) == 0); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig, msg, key, nonce_function_test_fail, extra) == 0); CHECK(is_empty_signature(&sig)); /* The retry loop successfully makes its way to the first good value. */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_retry, extra) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig, msg, key, nonce_function_test_retry, extra) == 1); CHECK(!is_empty_signature(&sig)); - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); CHECK(!is_empty_signature(&sig2)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&sig, &sig2, sizeof(sig)) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&sig, &sig2, sizeof(sig)) == 0); /* The default nonce function is deterministic. */ - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); CHECK(!is_empty_signature(&sig2)); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&sig, &sig2, sizeof(sig)) == 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&sig, &sig2, sizeof(sig)) == 0); /* The default nonce function changes output with different messages. */ for(i = 0; i < 256; i++) { int j; msg[0] = i; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); CHECK(!is_empty_signature(&sig2)); - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); + rustsecp256k1_v0_11_ecdsa_signature_load(CTX, &sr[i], &ss, &sig2); for (j = 0; j < i; j++) { - CHECK(!rustsecp256k1zkp_v0_8_0_scalar_eq(&sr[i], &sr[j])); + CHECK(!rustsecp256k1_v0_11_scalar_eq(&sr[i], &sr[j])); } } msg[0] = 0; @@ -7074,11 +7335,11 @@ void test_ecdsa_edge_cases(void) { for(i = 256; i < 512; i++) { int j; key[0] = i - 256; - CHECK(rustsecp256k1zkp_v0_8_0_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(rustsecp256k1_v0_11_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); CHECK(!is_empty_signature(&sig2)); - rustsecp256k1zkp_v0_8_0_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); + rustsecp256k1_v0_11_ecdsa_signature_load(CTX, &sr[i], &ss, &sig2); for (j = 0; j < i; j++) { - CHECK(!rustsecp256k1zkp_v0_8_0_scalar_eq(&sr[i], &sr[j])); + CHECK(!rustsecp256k1_v0_11_scalar_eq(&sr[i], &sr[j])); } } key[0] = 0; @@ -7091,24 +7352,24 @@ void test_ecdsa_edge_cases(void) { unsigned char nonce2[32]; unsigned char nonce3[32]; unsigned char nonce4[32]; - VG_UNDEF(nonce,32); - VG_UNDEF(nonce2,32); - VG_UNDEF(nonce3,32); - VG_UNDEF(nonce4,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce2,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce3,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce4,32); CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1); - VG_CHECK(nonce,32); + SECP256K1_CHECKMEM_CHECK(nonce,32); CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1); - VG_CHECK(nonce2,32); + SECP256K1_CHECKMEM_CHECK(nonce2,32); CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1); - VG_CHECK(nonce3,32); + SECP256K1_CHECKMEM_CHECK(nonce3,32); CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1); - VG_CHECK(nonce4,32); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(nonce, nonce2, 32) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(nonce, nonce3, 32) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(nonce, nonce4, 32) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(nonce2, nonce3, 32) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(nonce2, nonce4, 32) != 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(nonce3, nonce4, 32) != 0); + SECP256K1_CHECKMEM_CHECK(nonce4,32); + CHECK(rustsecp256k1_v0_11_memcmp_var(nonce, nonce2, 32) != 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(nonce, nonce3, 32) != 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(nonce, nonce4, 32) != 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(nonce2, nonce3, 32) != 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(nonce2, nonce4, 32) != 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(nonce3, nonce4, 32) != 0); } @@ -7122,240 +7383,279 @@ void test_ecdsa_edge_cases(void) { 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, }; size_t outlen = 300; - CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0)); + CHECK(!ec_privkey_export_der(CTX, privkey, &outlen, seckey, 0)); outlen = 300; - CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1)); + CHECK(!ec_privkey_export_der(CTX, privkey, &outlen, seckey, 1)); } } -void run_ecdsa_edge_cases(void) { +static void run_ecdsa_edge_cases(void) { test_ecdsa_edge_cases(); } -#ifdef ENABLE_MODULE_BPPP -#include "modules/bppp/tests_impl.h" -#endif - -#ifdef ENABLE_MODULE_ECDH -#include "modules/ecdh/tests_impl.h" -#endif +/** Wycheproof tests -#ifdef ENABLE_MODULE_MUSIG -#include "modules/musig/tests_impl.h" -#endif - -#ifdef ENABLE_MODULE_RECOVERY -#include "modules/recovery/tests_impl.h" -#endif +The tests check for known attacks (range checks in (r,s), arithmetic errors, malleability). +*/ +static void test_ecdsa_wycheproof(void) { + #include "wycheproof/ecdsa_rustsecp256k1_v0_11_sha256_bitcoin_test.h" -#ifdef ENABLE_MODULE_GENERATOR -#include "modules/generator/tests_impl.h" -#endif + int t; + for (t = 0; t < SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS; t++) { + rustsecp256k1_v0_11_ecdsa_signature signature; + rustsecp256k1_v0_11_sha256 hasher; + rustsecp256k1_v0_11_pubkey pubkey; + const unsigned char *msg, *sig, *pk; + unsigned char out[32] = {0}; + int actual_verify = 0; + + memset(&pubkey, 0, sizeof(pubkey)); + pk = &wycheproof_ecdsa_public_keys[testvectors[t].pk_offset]; + CHECK(rustsecp256k1_v0_11_ec_pubkey_parse(CTX, &pubkey, pk, 65) == 1); + + rustsecp256k1_v0_11_sha256_initialize(&hasher); + msg = &wycheproof_ecdsa_messages[testvectors[t].msg_offset]; + rustsecp256k1_v0_11_sha256_write(&hasher, msg, testvectors[t].msg_len); + rustsecp256k1_v0_11_sha256_finalize(&hasher, out); + + sig = &wycheproof_ecdsa_signatures[testvectors[t].sig_offset]; + if (rustsecp256k1_v0_11_ecdsa_signature_parse_der(CTX, &signature, sig, testvectors[t].sig_len) == 1) { + actual_verify = rustsecp256k1_v0_11_ecdsa_verify(CTX, (const rustsecp256k1_v0_11_ecdsa_signature *)&signature, out, &pubkey); + } + CHECK(testvectors[t].expected_verify == actual_verify); + } +} -#ifdef ENABLE_MODULE_RANGEPROOF -#include "modules/rangeproof/tests_impl.h" -#endif +/* Tests cases from Wycheproof test suite. */ +static void run_ecdsa_wycheproof(void) { + test_ecdsa_wycheproof(); +} -#ifdef ENABLE_MODULE_WHITELIST -#include "modules/whitelist/tests_impl.h" +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/tests_impl.h" #endif -#ifdef ENABLE_MODULE_SURJECTIONPROOF -#include "modules/surjection/tests_impl.h" +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/tests_impl.h" #endif #ifdef ENABLE_MODULE_EXTRAKEYS -#include "modules/extrakeys/tests_impl.h" +# include "modules/extrakeys/tests_impl.h" #endif #ifdef ENABLE_MODULE_SCHNORRSIG -#include "modules/schnorrsig/tests_impl.h" +# include "modules/schnorrsig/tests_impl.h" #endif -#ifdef ENABLE_MODULE_ECDSA_S2C -#include "modules/ecdsa_s2c/tests_impl.h" +#ifdef ENABLE_MODULE_MUSIG +# include "modules/musig/tests_impl.h" #endif -#ifdef ENABLE_MODULE_ECDSA_ADAPTOR -#include "modules/ecdsa_adaptor/tests_impl.h" +#ifdef ENABLE_MODULE_ELLSWIFT +# include "modules/ellswift/tests_impl.h" #endif -void run_rustsecp256k1zkp_v0_8_0_memczero_test(void) { +static void run_rustsecp256k1_v0_11_memczero_test(void) { unsigned char buf1[6] = {1, 2, 3, 4, 5, 6}; unsigned char buf2[sizeof(buf1)]; - /* rustsecp256k1zkp_v0_8_0_memczero(..., ..., 0) is a noop. */ + /* rustsecp256k1_v0_11_memczero(..., ..., 0) is a noop. */ memcpy(buf2, buf1, sizeof(buf1)); - rustsecp256k1zkp_v0_8_0_memczero(buf1, sizeof(buf1), 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(buf1, buf2, sizeof(buf1)) == 0); + rustsecp256k1_v0_11_memczero(buf1, sizeof(buf1), 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(buf1, buf2, sizeof(buf1)) == 0); - /* rustsecp256k1zkp_v0_8_0_memczero(..., ..., 1) zeros the buffer. */ + /* rustsecp256k1_v0_11_memczero(..., ..., 1) zeros the buffer. */ memset(buf2, 0, sizeof(buf2)); - rustsecp256k1zkp_v0_8_0_memczero(buf1, sizeof(buf1) , 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(buf1, buf2, sizeof(buf1)) == 0); + rustsecp256k1_v0_11_memczero(buf1, sizeof(buf1) , 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(buf1, buf2, sizeof(buf1)) == 0); +} + + +static void run_rustsecp256k1_v0_11_is_zero_array_test(void) { + unsigned char buf1[3] = {0, 1}; + unsigned char buf2[3] = {1, 0}; + + CHECK(rustsecp256k1_v0_11_is_zero_array(buf1, 0) == 1); + CHECK(rustsecp256k1_v0_11_is_zero_array(buf1, 1) == 1); + CHECK(rustsecp256k1_v0_11_is_zero_array(buf1, 2) == 0); + CHECK(rustsecp256k1_v0_11_is_zero_array(buf2, 1) == 0); + CHECK(rustsecp256k1_v0_11_is_zero_array(buf2, 2) == 0); } -void run_rustsecp256k1zkp_v0_8_0_byteorder_tests(void) { - const uint32_t x = 0xFF03AB45; - const unsigned char x_be[4] = {0xFF, 0x03, 0xAB, 0x45}; - unsigned char buf[4]; - uint32_t x_; +static void run_rustsecp256k1_v0_11_byteorder_tests(void) { + { + const uint32_t x = 0xFF03AB45; + const unsigned char x_be[4] = {0xFF, 0x03, 0xAB, 0x45}; + unsigned char buf[4]; + uint32_t x_; + + rustsecp256k1_v0_11_write_be32(buf, x); + CHECK(rustsecp256k1_v0_11_memcmp_var(buf, x_be, sizeof(buf)) == 0); + + x_ = rustsecp256k1_v0_11_read_be32(buf); + CHECK(x == x_); + } - rustsecp256k1zkp_v0_8_0_write_be32(buf, x); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(buf, x_be, sizeof(buf)) == 0); + { + const uint64_t x = 0xCAFE0123BEEF4567; + const unsigned char x_be[8] = {0xCA, 0xFE, 0x01, 0x23, 0xBE, 0xEF, 0x45, 0x67}; + unsigned char buf[8]; + uint64_t x_; + + rustsecp256k1_v0_11_write_be64(buf, x); + CHECK(rustsecp256k1_v0_11_memcmp_var(buf, x_be, sizeof(buf)) == 0); - x_ = rustsecp256k1zkp_v0_8_0_read_be32(buf); - CHECK(x == x_); + x_ = rustsecp256k1_v0_11_read_be64(buf); + CHECK(x == x_); + } } -void int_cmov_test(void) { +static void int_cmov_test(void) { int r = INT_MAX; int a = 0; - rustsecp256k1zkp_v0_8_0_int_cmov(&r, &a, 0); + rustsecp256k1_v0_11_int_cmov(&r, &a, 0); CHECK(r == INT_MAX); r = 0; a = INT_MAX; - rustsecp256k1zkp_v0_8_0_int_cmov(&r, &a, 1); + rustsecp256k1_v0_11_int_cmov(&r, &a, 1); CHECK(r == INT_MAX); a = 0; - rustsecp256k1zkp_v0_8_0_int_cmov(&r, &a, 1); + rustsecp256k1_v0_11_int_cmov(&r, &a, 1); CHECK(r == 0); a = 1; - rustsecp256k1zkp_v0_8_0_int_cmov(&r, &a, 1); + rustsecp256k1_v0_11_int_cmov(&r, &a, 1); CHECK(r == 1); r = 1; a = 0; - rustsecp256k1zkp_v0_8_0_int_cmov(&r, &a, 0); + rustsecp256k1_v0_11_int_cmov(&r, &a, 0); CHECK(r == 1); } -void fe_cmov_test(void) { - static const rustsecp256k1zkp_v0_8_0_fe zero = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0); - static const rustsecp256k1zkp_v0_8_0_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); - static const rustsecp256k1zkp_v0_8_0_fe max = SECP256K1_FE_CONST( +static void fe_cmov_test(void) { + static const rustsecp256k1_v0_11_fe zero = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0); + static const rustsecp256k1_v0_11_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + static const rustsecp256k1_v0_11_fe max = SECP256K1_FE_CONST( 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL ); - rustsecp256k1zkp_v0_8_0_fe r = max; - rustsecp256k1zkp_v0_8_0_fe a = zero; + rustsecp256k1_v0_11_fe r = max; + rustsecp256k1_v0_11_fe a = zero; - rustsecp256k1zkp_v0_8_0_fe_cmov(&r, &a, 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &max, sizeof(r)) == 0); + rustsecp256k1_v0_11_fe_cmov(&r, &a, 0); + CHECK(fe_identical(&r, &max)); r = zero; a = max; - rustsecp256k1zkp_v0_8_0_fe_cmov(&r, &a, 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &max, sizeof(r)) == 0); + rustsecp256k1_v0_11_fe_cmov(&r, &a, 1); + CHECK(fe_identical(&r, &max)); a = zero; - rustsecp256k1zkp_v0_8_0_fe_cmov(&r, &a, 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &zero, sizeof(r)) == 0); + rustsecp256k1_v0_11_fe_cmov(&r, &a, 1); + CHECK(fe_identical(&r, &zero)); a = one; - rustsecp256k1zkp_v0_8_0_fe_cmov(&r, &a, 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &one, sizeof(r)) == 0); + rustsecp256k1_v0_11_fe_cmov(&r, &a, 1); + CHECK(fe_identical(&r, &one)); r = one; a = zero; - rustsecp256k1zkp_v0_8_0_fe_cmov(&r, &a, 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &one, sizeof(r)) == 0); + rustsecp256k1_v0_11_fe_cmov(&r, &a, 0); + CHECK(fe_identical(&r, &one)); } -void fe_storage_cmov_test(void) { - static const rustsecp256k1zkp_v0_8_0_fe_storage zero = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0); - static const rustsecp256k1zkp_v0_8_0_fe_storage one = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1); - static const rustsecp256k1zkp_v0_8_0_fe_storage max = SECP256K1_FE_STORAGE_CONST( +static void fe_storage_cmov_test(void) { + static const rustsecp256k1_v0_11_fe_storage zero = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0); + static const rustsecp256k1_v0_11_fe_storage one = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + static const rustsecp256k1_v0_11_fe_storage max = SECP256K1_FE_STORAGE_CONST( 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL ); - rustsecp256k1zkp_v0_8_0_fe_storage r = max; - rustsecp256k1zkp_v0_8_0_fe_storage a = zero; + rustsecp256k1_v0_11_fe_storage r = max; + rustsecp256k1_v0_11_fe_storage a = zero; - rustsecp256k1zkp_v0_8_0_fe_storage_cmov(&r, &a, 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &max, sizeof(r)) == 0); + rustsecp256k1_v0_11_fe_storage_cmov(&r, &a, 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &max, sizeof(r)) == 0); r = zero; a = max; - rustsecp256k1zkp_v0_8_0_fe_storage_cmov(&r, &a, 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &max, sizeof(r)) == 0); + rustsecp256k1_v0_11_fe_storage_cmov(&r, &a, 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &max, sizeof(r)) == 0); a = zero; - rustsecp256k1zkp_v0_8_0_fe_storage_cmov(&r, &a, 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &zero, sizeof(r)) == 0); + rustsecp256k1_v0_11_fe_storage_cmov(&r, &a, 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &zero, sizeof(r)) == 0); a = one; - rustsecp256k1zkp_v0_8_0_fe_storage_cmov(&r, &a, 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &one, sizeof(r)) == 0); + rustsecp256k1_v0_11_fe_storage_cmov(&r, &a, 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &one, sizeof(r)) == 0); r = one; a = zero; - rustsecp256k1zkp_v0_8_0_fe_storage_cmov(&r, &a, 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &one, sizeof(r)) == 0); + rustsecp256k1_v0_11_fe_storage_cmov(&r, &a, 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &one, sizeof(r)) == 0); } -void scalar_cmov_test(void) { - static const rustsecp256k1zkp_v0_8_0_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - static const rustsecp256k1zkp_v0_8_0_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); - static const rustsecp256k1zkp_v0_8_0_scalar max = SECP256K1_SCALAR_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL +static void scalar_cmov_test(void) { + static const rustsecp256k1_v0_11_scalar max = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364140UL ); - rustsecp256k1zkp_v0_8_0_scalar r = max; - rustsecp256k1zkp_v0_8_0_scalar a = zero; + rustsecp256k1_v0_11_scalar r = max; + rustsecp256k1_v0_11_scalar a = rustsecp256k1_v0_11_scalar_zero; - rustsecp256k1zkp_v0_8_0_scalar_cmov(&r, &a, 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &max, sizeof(r)) == 0); + rustsecp256k1_v0_11_scalar_cmov(&r, &a, 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &max, sizeof(r)) == 0); - r = zero; a = max; - rustsecp256k1zkp_v0_8_0_scalar_cmov(&r, &a, 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &max, sizeof(r)) == 0); + r = rustsecp256k1_v0_11_scalar_zero; a = max; + rustsecp256k1_v0_11_scalar_cmov(&r, &a, 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &max, sizeof(r)) == 0); - a = zero; - rustsecp256k1zkp_v0_8_0_scalar_cmov(&r, &a, 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &zero, sizeof(r)) == 0); + a = rustsecp256k1_v0_11_scalar_zero; + rustsecp256k1_v0_11_scalar_cmov(&r, &a, 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &rustsecp256k1_v0_11_scalar_zero, sizeof(r)) == 0); - a = one; - rustsecp256k1zkp_v0_8_0_scalar_cmov(&r, &a, 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &one, sizeof(r)) == 0); + a = rustsecp256k1_v0_11_scalar_one; + rustsecp256k1_v0_11_scalar_cmov(&r, &a, 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &rustsecp256k1_v0_11_scalar_one, sizeof(r)) == 0); - r = one; a = zero; - rustsecp256k1zkp_v0_8_0_scalar_cmov(&r, &a, 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &one, sizeof(r)) == 0); + r = rustsecp256k1_v0_11_scalar_one; a = rustsecp256k1_v0_11_scalar_zero; + rustsecp256k1_v0_11_scalar_cmov(&r, &a, 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &rustsecp256k1_v0_11_scalar_one, sizeof(r)) == 0); } -void ge_storage_cmov_test(void) { - static const rustsecp256k1zkp_v0_8_0_ge_storage zero = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - static const rustsecp256k1zkp_v0_8_0_ge_storage one = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1); - static const rustsecp256k1zkp_v0_8_0_ge_storage max = SECP256K1_GE_STORAGE_CONST( +static void ge_storage_cmov_test(void) { + static const rustsecp256k1_v0_11_ge_storage zero = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + static const rustsecp256k1_v0_11_ge_storage one = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1); + static const rustsecp256k1_v0_11_ge_storage max = SECP256K1_GE_STORAGE_CONST( 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL ); - rustsecp256k1zkp_v0_8_0_ge_storage r = max; - rustsecp256k1zkp_v0_8_0_ge_storage a = zero; + rustsecp256k1_v0_11_ge_storage r = max; + rustsecp256k1_v0_11_ge_storage a = zero; - rustsecp256k1zkp_v0_8_0_ge_storage_cmov(&r, &a, 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &max, sizeof(r)) == 0); + rustsecp256k1_v0_11_ge_storage_cmov(&r, &a, 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &max, sizeof(r)) == 0); r = zero; a = max; - rustsecp256k1zkp_v0_8_0_ge_storage_cmov(&r, &a, 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &max, sizeof(r)) == 0); + rustsecp256k1_v0_11_ge_storage_cmov(&r, &a, 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &max, sizeof(r)) == 0); a = zero; - rustsecp256k1zkp_v0_8_0_ge_storage_cmov(&r, &a, 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &zero, sizeof(r)) == 0); + rustsecp256k1_v0_11_ge_storage_cmov(&r, &a, 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &zero, sizeof(r)) == 0); a = one; - rustsecp256k1zkp_v0_8_0_ge_storage_cmov(&r, &a, 1); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &one, sizeof(r)) == 0); + rustsecp256k1_v0_11_ge_storage_cmov(&r, &a, 1); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &one, sizeof(r)) == 0); r = one; a = zero; - rustsecp256k1zkp_v0_8_0_ge_storage_cmov(&r, &a, 0); - CHECK(rustsecp256k1zkp_v0_8_0_memcmp_var(&r, &one, sizeof(r)) == 0); + rustsecp256k1_v0_11_ge_storage_cmov(&r, &a, 0); + CHECK(rustsecp256k1_v0_11_memcmp_var(&r, &one, sizeof(r)) == 0); } -void run_cmov_tests(void) { +static void run_cmov_tests(void) { int_cmov_test(); fe_cmov_test(); fe_storage_cmov_test(); @@ -7374,41 +7674,71 @@ int main(int argc, char **argv) { /* find iteration count */ if (argc > 1) { - count = strtol(argv[1], NULL, 0); + COUNT = strtol(argv[1], NULL, 0); } else { const char* env = getenv("SECP256K1_TEST_ITERS"); if (env && strlen(env) > 0) { - count = strtol(env, NULL, 0); + COUNT = strtol(env, NULL, 0); } } - if (count <= 0) { + if (COUNT <= 0) { fputs("An iteration count of 0 or less is not allowed.\n", stderr); return EXIT_FAILURE; } - printf("test count = %i\n", count); + printf("test count = %i\n", COUNT); + + /* run test RNG tests (must run before we really initialize the test RNG) */ + run_xoshiro256pp_tests(); /* find random seed */ - rustsecp256k1zkp_v0_8_0_testrand_init(argc > 2 ? argv[2] : NULL); + testrand_init(argc > 2 ? argv[2] : NULL); - /* initialize */ - run_context_tests(0); - run_context_tests(1); - run_scratch_tests(); - ctx = rustsecp256k1zkp_v0_8_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - if (rustsecp256k1zkp_v0_8_0_testrand_bits(1)) { + /*** Setup test environment ***/ + + /* Create a global context available to all tests */ + CTX = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); + /* Randomize the context only with probability 15/16 + to make sure we test without context randomization from time to time. + TODO Reconsider this when recalibrating the tests. */ + if (testrand_bits(4)) { unsigned char rand32[32]; - rustsecp256k1zkp_v0_8_0_testrand256(rand32); - CHECK(rustsecp256k1zkp_v0_8_0_context_randomize(ctx, rustsecp256k1zkp_v0_8_0_testrand_bits(1) ? rand32 : NULL)); + testrand256(rand32); + CHECK(rustsecp256k1_v0_11_context_randomize(CTX, rand32)); } + /* Make a writable copy of rustsecp256k1_v0_11_context_static in order to test the effect of API functions + that write to the context. The API does not support cloning the static context, so we use + memcpy instead. The user is not supposed to copy a context but we should still ensure that + the API functions handle copies of the static context gracefully. */ + STATIC_CTX = malloc(sizeof(*rustsecp256k1_v0_11_context_static)); + CHECK(STATIC_CTX != NULL); + memcpy(STATIC_CTX, rustsecp256k1_v0_11_context_static, sizeof(rustsecp256k1_v0_11_context)); + CHECK(!rustsecp256k1_v0_11_context_is_proper(STATIC_CTX)); - run_rand_bits(); - run_rand_int(); - run_util_tests(); + /*** Run actual tests ***/ + /* selftest tests */ + run_selftest_tests(); + + /* context tests */ + run_proper_context_tests(0); run_proper_context_tests(1); + run_static_context_tests(0); run_static_context_tests(1); + run_deprecated_context_flags_test(); + + /* scratch tests */ + run_scratch_tests(); + + /* integer arithmetic tests */ +#ifdef SECP256K1_WIDEMUL_INT128 + run_int128_tests(); +#endif run_ctz_tests(); run_modinv_tests(); run_inverse_tests(); + /* sorting tests */ + run_hsort_tests(); + + /* hash tests */ run_sha256_known_output_tests(); run_sha256_counter_tests(); run_hmac_sha256_tests(); @@ -7422,6 +7752,7 @@ int main(int argc, char **argv) { run_field_half(); run_field_misc(); run_field_convert(); + run_field_be32_overflow(); run_fe_mul(); run_sqr(); run_sqrt(); @@ -7442,7 +7773,6 @@ int main(int argc, char **argv) { run_ecmult_const_tests(); run_ecmult_multi_tests(); run_ec_combine(); - run_ec_commit(); /* endomorphism tests */ run_endomorphism_tests(); @@ -7456,49 +7786,27 @@ int main(int argc, char **argv) { /* EC key arithmetic test */ run_eckey_negate_test(); -#ifdef ENABLE_MODULE_BPPP - run_bppp_tests(); -#endif - #ifdef ENABLE_MODULE_ECDH /* ecdh tests */ run_ecdh_tests(); #endif -#ifdef ENABLE_MODULE_MUSIG - run_musig_tests(); -#endif - /* ecdsa tests */ + run_ec_illegal_argument_tests(); run_pubkey_comparison(); + run_pubkey_sort(); run_random_pubkeys(); run_ecdsa_der_parse(); run_ecdsa_sign_verify(); run_ecdsa_end_to_end(); run_ecdsa_edge_cases(); + run_ecdsa_wycheproof(); #ifdef ENABLE_MODULE_RECOVERY /* ECDSA pubkey recovery tests */ run_recovery_tests(); #endif -#ifdef ENABLE_MODULE_GENERATOR - run_generator_tests(); -#endif - -#ifdef ENABLE_MODULE_RANGEPROOF - run_rangeproof_tests(); -#endif - -#ifdef ENABLE_MODULE_WHITELIST - /* Key whitelisting tests */ - run_whitelist_tests(); -#endif - -#ifdef ENABLE_MODULE_SURJECTIONPROOF - run_surjection_tests(); -#endif - #ifdef ENABLE_MODULE_EXTRAKEYS run_extrakeys_tests(); #endif @@ -7507,25 +7815,26 @@ int main(int argc, char **argv) { run_schnorrsig_tests(); #endif -#ifdef ENABLE_MODULE_ECDSA_S2C - /* ECDSA sign to contract */ - run_ecdsa_s2c_tests(); +#ifdef ENABLE_MODULE_MUSIG + run_musig_tests(); #endif -#ifdef ENABLE_MODULE_ECDSA_ADAPTOR - run_ecdsa_adaptor_tests(); +#ifdef ENABLE_MODULE_ELLSWIFT + run_ellswift_tests(); #endif /* util tests */ - run_rustsecp256k1zkp_v0_8_0_memczero_test(); - run_rustsecp256k1zkp_v0_8_0_byteorder_tests(); + run_rustsecp256k1_v0_11_memczero_test(); + run_rustsecp256k1_v0_11_is_zero_array_test(); + run_rustsecp256k1_v0_11_byteorder_tests(); run_cmov_tests(); - rustsecp256k1zkp_v0_8_0_testrand_finish(); + /*** Tear down test environment ***/ + free(STATIC_CTX); + rustsecp256k1_v0_11_context_destroy(CTX); - /* shutdown */ - rustsecp256k1zkp_v0_8_0_context_destroy(ctx); + testrand_finish(); printf("no problems found\n"); return 0; diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/tests_exhaustive.c b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/tests_exhaustive.c new file mode 100644 index 00000000..722b03c5 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/tests_exhaustive.c @@ -0,0 +1,466 @@ +/*********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#include +#include +#include + +#ifndef EXHAUSTIVE_TEST_ORDER +/* see group_impl.h for allowable values */ +#define EXHAUSTIVE_TEST_ORDER 13 +#endif + +/* These values of B are all values in [1, 8] that result in a curve with even order. */ +#define EXHAUSTIVE_TEST_CURVE_HAS_EVEN_ORDER (SECP256K1_B == 1 || SECP256K1_B == 6 || SECP256K1_B == 8) + +#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS + #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in exhaustive_tests.") + #undef USE_EXTERNAL_DEFAULT_CALLBACKS +#endif +#include "secp256k1.c" + +#include "../include/secp256k1.h" +#include "assumptions.h" +#include "group.h" +#include "testrand_impl.h" +#include "ecmult_compute_table_impl.h" +#include "ecmult_gen_compute_table_impl.h" +#include "testutil.h" +#include "util.h" + +static int count = 2; + +static uint32_t num_cores = 1; +static uint32_t this_core = 0; + +SECP256K1_INLINE static int skip_section(uint64_t* iter) { + if (num_cores == 1) return 0; + *iter += 0xe7037ed1a0b428dbULL; + return ((((uint32_t)*iter ^ (*iter >> 32)) * num_cores) >> 32) != this_core; +} + +static int rustsecp256k1_v0_11_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, + const unsigned char *key32, const unsigned char *algo16, + void *data, unsigned int attempt) { + rustsecp256k1_v0_11_scalar s; + int *idata = data; + (void)msg32; + (void)key32; + (void)algo16; + /* Some nonces cannot be used because they'd cause s and/or r to be zero. + * The signing function has retry logic here that just re-calls the nonce + * function with an increased `attempt`. So if attempt > 0 this means we + * need to change the nonce to avoid an infinite loop. */ + if (attempt > 0) { + *idata = (*idata + 1) % EXHAUSTIVE_TEST_ORDER; + } + rustsecp256k1_v0_11_scalar_set_int(&s, *idata); + rustsecp256k1_v0_11_scalar_get_b32(nonce32, &s); + return 1; +} + +static void test_exhaustive_endomorphism(const rustsecp256k1_v0_11_ge *group) { + int i; + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + rustsecp256k1_v0_11_ge res; + rustsecp256k1_v0_11_ge_mul_lambda(&res, &group[i]); + CHECK(rustsecp256k1_v0_11_ge_eq_var(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res)); + } +} + +static void test_exhaustive_addition(const rustsecp256k1_v0_11_ge *group, const rustsecp256k1_v0_11_gej *groupj) { + int i, j; + uint64_t iter = 0; + + /* Sanity-check (and check infinity functions) */ + CHECK(rustsecp256k1_v0_11_ge_is_infinity(&group[0])); + CHECK(rustsecp256k1_v0_11_gej_is_infinity(&groupj[0])); + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + CHECK(!rustsecp256k1_v0_11_ge_is_infinity(&group[i])); + CHECK(!rustsecp256k1_v0_11_gej_is_infinity(&groupj[i])); + } + + /* Check all addition formulae */ + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { + rustsecp256k1_v0_11_fe fe_inv; + if (skip_section(&iter)) continue; + rustsecp256k1_v0_11_fe_inv(&fe_inv, &groupj[j].z); + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + rustsecp256k1_v0_11_ge zless_gej; + rustsecp256k1_v0_11_gej tmp; + /* add_var */ + rustsecp256k1_v0_11_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); + /* add_ge */ + if (j > 0) { + rustsecp256k1_v0_11_gej_add_ge(&tmp, &groupj[i], &group[j]); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); + } + /* add_ge_var */ + rustsecp256k1_v0_11_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); + /* add_zinv_var */ + zless_gej.infinity = groupj[j].infinity; + zless_gej.x = groupj[j].x; + zless_gej.y = groupj[j].y; + rustsecp256k1_v0_11_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); + } + } + + /* Check doubling */ + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + rustsecp256k1_v0_11_gej tmp; + rustsecp256k1_v0_11_gej_double(&tmp, &groupj[i]); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&tmp, &group[(2 * i) % EXHAUSTIVE_TEST_ORDER])); + rustsecp256k1_v0_11_gej_double_var(&tmp, &groupj[i], NULL); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&tmp, &group[(2 * i) % EXHAUSTIVE_TEST_ORDER])); + } + + /* Check negation */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + rustsecp256k1_v0_11_ge tmp; + rustsecp256k1_v0_11_gej tmpj; + rustsecp256k1_v0_11_ge_neg(&tmp, &group[i]); + CHECK(rustsecp256k1_v0_11_ge_eq_var(&tmp, &group[EXHAUSTIVE_TEST_ORDER - i])); + rustsecp256k1_v0_11_gej_neg(&tmpj, &groupj[i]); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&tmpj, &group[EXHAUSTIVE_TEST_ORDER - i])); + } +} + +static void test_exhaustive_ecmult(const rustsecp256k1_v0_11_ge *group, const rustsecp256k1_v0_11_gej *groupj) { + int i, j, r_log; + uint64_t iter = 0; + for (r_log = 1; r_log < EXHAUSTIVE_TEST_ORDER; r_log++) { + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { + if (skip_section(&iter)) continue; + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + rustsecp256k1_v0_11_gej tmp; + rustsecp256k1_v0_11_scalar na, ng; + rustsecp256k1_v0_11_scalar_set_int(&na, i); + rustsecp256k1_v0_11_scalar_set_int(&ng, j); + + rustsecp256k1_v0_11_ecmult(&tmp, &groupj[r_log], &na, &ng); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&tmp, &group[(i * r_log + j) % EXHAUSTIVE_TEST_ORDER])); + } + } + } + + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + int ret; + rustsecp256k1_v0_11_gej tmp; + rustsecp256k1_v0_11_fe xn, xd, tmpf; + rustsecp256k1_v0_11_scalar ng; + + if (skip_section(&iter)) continue; + + rustsecp256k1_v0_11_scalar_set_int(&ng, j); + + /* Test rustsecp256k1_v0_11_ecmult_const. */ + rustsecp256k1_v0_11_ecmult_const(&tmp, &group[i], &ng); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&tmp, &group[(i * j) % EXHAUSTIVE_TEST_ORDER])); + + if (i != 0 && j != 0) { + /* Test rustsecp256k1_v0_11_ecmult_const_xonly with all curve X coordinates, and xd=NULL. */ + ret = rustsecp256k1_v0_11_ecmult_const_xonly(&tmpf, &group[i].x, NULL, &ng, 0); + CHECK(ret); + CHECK(rustsecp256k1_v0_11_fe_equal(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); + + /* Test rustsecp256k1_v0_11_ecmult_const_xonly with all curve X coordinates, with random xd. */ + testutil_random_fe_non_zero(&xd); + rustsecp256k1_v0_11_fe_mul(&xn, &xd, &group[i].x); + ret = rustsecp256k1_v0_11_ecmult_const_xonly(&tmpf, &xn, &xd, &ng, 0); + CHECK(ret); + CHECK(rustsecp256k1_v0_11_fe_equal(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); + } + } + } +} + +typedef struct { + rustsecp256k1_v0_11_scalar sc[2]; + rustsecp256k1_v0_11_ge pt[2]; +} ecmult_multi_data; + +static int ecmult_multi_callback(rustsecp256k1_v0_11_scalar *sc, rustsecp256k1_v0_11_ge *pt, size_t idx, void *cbdata) { + ecmult_multi_data *data = (ecmult_multi_data*) cbdata; + *sc = data->sc[idx]; + *pt = data->pt[idx]; + return 1; +} + +static void test_exhaustive_ecmult_multi(const rustsecp256k1_v0_11_context *ctx, const rustsecp256k1_v0_11_ge *group) { + int i, j, k, x, y; + uint64_t iter = 0; + rustsecp256k1_v0_11_scratch *scratch = rustsecp256k1_v0_11_scratch_create(&ctx->error_callback, 4096); + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { + for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { + for (x = 0; x < EXHAUSTIVE_TEST_ORDER; x++) { + if (skip_section(&iter)) continue; + for (y = 0; y < EXHAUSTIVE_TEST_ORDER; y++) { + rustsecp256k1_v0_11_gej tmp; + rustsecp256k1_v0_11_scalar g_sc; + ecmult_multi_data data; + + rustsecp256k1_v0_11_scalar_set_int(&data.sc[0], i); + rustsecp256k1_v0_11_scalar_set_int(&data.sc[1], j); + rustsecp256k1_v0_11_scalar_set_int(&g_sc, k); + data.pt[0] = group[x]; + data.pt[1] = group[y]; + + rustsecp256k1_v0_11_ecmult_multi_var(&ctx->error_callback, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2); + CHECK(rustsecp256k1_v0_11_gej_eq_ge_var(&tmp, &group[(i * x + j * y + k) % EXHAUSTIVE_TEST_ORDER])); + } + } + } + } + } + rustsecp256k1_v0_11_scratch_destroy(&ctx->error_callback, scratch); +} + +static void r_from_k(rustsecp256k1_v0_11_scalar *r, const rustsecp256k1_v0_11_ge *group, int k, int* overflow) { + rustsecp256k1_v0_11_fe x; + unsigned char x_bin[32]; + k %= EXHAUSTIVE_TEST_ORDER; + x = group[k].x; + rustsecp256k1_v0_11_fe_normalize(&x); + rustsecp256k1_v0_11_fe_get_b32(x_bin, &x); + rustsecp256k1_v0_11_scalar_set_b32(r, x_bin, overflow); +} + +static void test_exhaustive_verify(const rustsecp256k1_v0_11_context *ctx, const rustsecp256k1_v0_11_ge *group) { + int s, r, msg, key; + uint64_t iter = 0; + for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) { + for (r = 1; r < EXHAUSTIVE_TEST_ORDER; r++) { + for (msg = 1; msg < EXHAUSTIVE_TEST_ORDER; msg++) { + for (key = 1; key < EXHAUSTIVE_TEST_ORDER; key++) { + rustsecp256k1_v0_11_ge nonconst_ge; + rustsecp256k1_v0_11_ecdsa_signature sig; + rustsecp256k1_v0_11_pubkey pk; + rustsecp256k1_v0_11_scalar sk_s, msg_s, r_s, s_s; + rustsecp256k1_v0_11_scalar s_times_k_s, msg_plus_r_times_sk_s; + int k, should_verify; + unsigned char msg32[32]; + + if (skip_section(&iter)) continue; + + rustsecp256k1_v0_11_scalar_set_int(&s_s, s); + rustsecp256k1_v0_11_scalar_set_int(&r_s, r); + rustsecp256k1_v0_11_scalar_set_int(&msg_s, msg); + rustsecp256k1_v0_11_scalar_set_int(&sk_s, key); + + /* Verify by hand */ + /* Run through every k value that gives us this r and check that *one* works. + * Note there could be none, there could be multiple, ECDSA is weird. */ + should_verify = 0; + for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { + rustsecp256k1_v0_11_scalar check_x_s; + r_from_k(&check_x_s, group, k, NULL); + if (r_s == check_x_s) { + rustsecp256k1_v0_11_scalar_set_int(&s_times_k_s, k); + rustsecp256k1_v0_11_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); + rustsecp256k1_v0_11_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); + rustsecp256k1_v0_11_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); + should_verify |= rustsecp256k1_v0_11_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); + } + } + /* nb we have a "high s" rule */ + should_verify &= !rustsecp256k1_v0_11_scalar_is_high(&s_s); + + /* Verify by calling verify */ + rustsecp256k1_v0_11_ecdsa_signature_save(&sig, &r_s, &s_s); + memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); + rustsecp256k1_v0_11_pubkey_save(&pk, &nonconst_ge); + rustsecp256k1_v0_11_scalar_get_b32(msg32, &msg_s); + CHECK(should_verify == + rustsecp256k1_v0_11_ecdsa_verify(ctx, &sig, msg32, &pk)); + } + } + } + } +} + +static void test_exhaustive_sign(const rustsecp256k1_v0_11_context *ctx, const rustsecp256k1_v0_11_ge *group) { + int i, j, k; + uint64_t iter = 0; + + /* Loop */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { /* message */ + for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { /* key */ + if (skip_section(&iter)) continue; + for (k = 1; k < EXHAUSTIVE_TEST_ORDER; k++) { /* nonce */ + const int starting_k = k; + int ret; + rustsecp256k1_v0_11_ecdsa_signature sig; + rustsecp256k1_v0_11_scalar sk, msg, r, s, expected_r; + unsigned char sk32[32], msg32[32]; + rustsecp256k1_v0_11_scalar_set_int(&msg, i); + rustsecp256k1_v0_11_scalar_set_int(&sk, j); + rustsecp256k1_v0_11_scalar_get_b32(sk32, &sk); + rustsecp256k1_v0_11_scalar_get_b32(msg32, &msg); + + ret = rustsecp256k1_v0_11_ecdsa_sign(ctx, &sig, msg32, sk32, rustsecp256k1_v0_11_nonce_function_smallint, &k); + CHECK(ret == 1); + + rustsecp256k1_v0_11_ecdsa_signature_load(ctx, &r, &s, &sig); + /* Note that we compute expected_r *after* signing -- this is important + * because our nonce-computing function function might change k during + * signing. */ + r_from_k(&expected_r, group, k, NULL); + CHECK(r == expected_r); + CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); + + /* Overflow means we've tried every possible nonce */ + if (k < starting_k) { + break; + } + } + } + } + + /* We would like to verify zero-knowledge here by counting how often every + * possible (s, r) tuple appears, but because the group order is larger + * than the field order, when coercing the x-values to scalar values, some + * appear more often than others, so we are actually not zero-knowledge. + * (This effect also appears in the real code, but the difference is on the + * order of 1/2^128th the field order, so the deviation is not useful to a + * computationally bounded attacker.) + */ +} + +#ifdef ENABLE_MODULE_RECOVERY +#include "modules/recovery/tests_exhaustive_impl.h" +#endif + +#ifdef ENABLE_MODULE_EXTRAKEYS +#include "modules/extrakeys/tests_exhaustive_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +#include "modules/schnorrsig/tests_exhaustive_impl.h" +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT +#include "modules/ellswift/tests_exhaustive_impl.h" +#endif + +int main(int argc, char** argv) { + int i; + rustsecp256k1_v0_11_gej groupj[EXHAUSTIVE_TEST_ORDER]; + rustsecp256k1_v0_11_ge group[EXHAUSTIVE_TEST_ORDER]; + unsigned char rand32[32]; + rustsecp256k1_v0_11_context *ctx; + + /* Disable buffering for stdout to improve reliability of getting + * diagnostic information. Happens right at the start of main because + * setbuf must be used before any other operation on the stream. */ + setbuf(stdout, NULL); + /* Also disable buffering for stderr because it's not guaranteed that it's + * unbuffered on all systems. */ + setbuf(stderr, NULL); + + printf("Exhaustive tests for order %lu\n", (unsigned long)EXHAUSTIVE_TEST_ORDER); + + /* find iteration count */ + if (argc > 1) { + count = strtol(argv[1], NULL, 0); + } + printf("test count = %i\n", count); + + /* find random seed */ + testrand_init(argc > 2 ? argv[2] : NULL); + + /* set up split processing */ + if (argc > 4) { + num_cores = strtol(argv[3], NULL, 0); + this_core = strtol(argv[4], NULL, 0); + if (num_cores < 1 || this_core >= num_cores) { + fprintf(stderr, "Usage: %s [count] [seed] [numcores] [thiscore]\n", argv[0]); + return 1; + } + printf("running tests for core %lu (out of [0..%lu])\n", (unsigned long)this_core, (unsigned long)num_cores - 1); + } + + /* Recreate the ecmult{,_gen} tables using the right generator (as selected via EXHAUSTIVE_TEST_ORDER) */ + rustsecp256k1_v0_11_ecmult_gen_compute_table(&rustsecp256k1_v0_11_ecmult_gen_prec_table[0][0], &rustsecp256k1_v0_11_ge_const_g, COMB_BLOCKS, COMB_TEETH, COMB_SPACING); + rustsecp256k1_v0_11_ecmult_compute_two_tables(rustsecp256k1_v0_11_pre_g, rustsecp256k1_v0_11_pre_g_128, WINDOW_G, &rustsecp256k1_v0_11_ge_const_g); + + while (count--) { + /* Build context */ + ctx = rustsecp256k1_v0_11_context_create(SECP256K1_CONTEXT_NONE); + testrand256(rand32); + CHECK(rustsecp256k1_v0_11_context_randomize(ctx, rand32)); + + /* Generate the entire group */ + rustsecp256k1_v0_11_gej_set_infinity(&groupj[0]); + rustsecp256k1_v0_11_ge_set_gej(&group[0], &groupj[0]); + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + rustsecp256k1_v0_11_gej_add_ge(&groupj[i], &groupj[i - 1], &rustsecp256k1_v0_11_ge_const_g); + rustsecp256k1_v0_11_ge_set_gej(&group[i], &groupj[i]); + if (count != 0) { + /* Set a different random z-value for each Jacobian point, except z=1 + is used in the last iteration. */ + rustsecp256k1_v0_11_fe z; + testutil_random_fe(&z); + rustsecp256k1_v0_11_gej_rescale(&groupj[i], &z); + } + + /* Verify against ecmult_gen */ + { + rustsecp256k1_v0_11_scalar scalar_i; + rustsecp256k1_v0_11_gej generatedj; + rustsecp256k1_v0_11_ge generated; + + rustsecp256k1_v0_11_scalar_set_int(&scalar_i, i); + rustsecp256k1_v0_11_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); + rustsecp256k1_v0_11_ge_set_gej(&generated, &generatedj); + + CHECK(group[i].infinity == 0); + CHECK(generated.infinity == 0); + CHECK(rustsecp256k1_v0_11_fe_equal(&generated.x, &group[i].x)); + CHECK(rustsecp256k1_v0_11_fe_equal(&generated.y, &group[i].y)); + } + } + + /* Run the tests */ + test_exhaustive_endomorphism(group); + test_exhaustive_addition(group, groupj); + test_exhaustive_ecmult(group, groupj); + test_exhaustive_ecmult_multi(ctx, group); + test_exhaustive_sign(ctx, group); + test_exhaustive_verify(ctx, group); + +#ifdef ENABLE_MODULE_RECOVERY + test_exhaustive_recovery(ctx, group); +#endif +#ifdef ENABLE_MODULE_EXTRAKEYS + test_exhaustive_extrakeys(ctx, group); +#endif +#ifdef ENABLE_MODULE_SCHNORRSIG + test_exhaustive_schnorrsig(ctx); +#endif +#ifdef ENABLE_MODULE_ELLSWIFT + /* The ellswift algorithm does have additional edge cases when operating on + * curves of even order, which are not included in the code as secp256k1 is + * of odd order. Skip the ellswift tests if the used exhaustive tests curve + * is even-ordered accordingly. */ + #if !EXHAUSTIVE_TEST_CURVE_HAS_EVEN_ORDER + test_exhaustive_ellswift(ctx, group); + #endif +#endif + + rustsecp256k1_v0_11_context_destroy(ctx); + } + + testrand_finish(); + + printf("no problems found\n"); + return 0; +} diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/testutil.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/testutil.h new file mode 100644 index 00000000..bd4ac604 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/testutil.h @@ -0,0 +1,148 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_TESTUTIL_H +#define SECP256K1_TESTUTIL_H + +#include "field.h" +#include "group.h" +#include "testrand.h" +#include "util.h" + +static void testutil_random_fe(rustsecp256k1_v0_11_fe *x) { + unsigned char bin[32]; + do { + testrand256(bin); + if (rustsecp256k1_v0_11_fe_set_b32_limit(x, bin)) { + return; + } + } while(1); +} + +static void testutil_random_fe_non_zero(rustsecp256k1_v0_11_fe *nz) { + do { + testutil_random_fe(nz); + } while (rustsecp256k1_v0_11_fe_is_zero(nz)); +} + +static void testutil_random_fe_magnitude(rustsecp256k1_v0_11_fe *fe, int m) { + rustsecp256k1_v0_11_fe zero; + int n = testrand_int(m + 1); + rustsecp256k1_v0_11_fe_normalize(fe); + if (n == 0) { + return; + } + rustsecp256k1_v0_11_fe_set_int(&zero, 0); + rustsecp256k1_v0_11_fe_negate(&zero, &zero, 0); + rustsecp256k1_v0_11_fe_mul_int_unchecked(&zero, n - 1); + rustsecp256k1_v0_11_fe_add(fe, &zero); +#ifdef VERIFY + CHECK(fe->magnitude == n); +#endif +} + +static void testutil_random_fe_test(rustsecp256k1_v0_11_fe *x) { + unsigned char bin[32]; + do { + testrand256_test(bin); + if (rustsecp256k1_v0_11_fe_set_b32_limit(x, bin)) { + return; + } + } while(1); +} + +static void testutil_random_fe_non_zero_test(rustsecp256k1_v0_11_fe *fe) { + do { + testutil_random_fe_test(fe); + } while(rustsecp256k1_v0_11_fe_is_zero(fe)); +} + +static void testutil_random_ge_x_magnitude(rustsecp256k1_v0_11_ge *ge) { + testutil_random_fe_magnitude(&ge->x, SECP256K1_GE_X_MAGNITUDE_MAX); +} + +static void testutil_random_ge_y_magnitude(rustsecp256k1_v0_11_ge *ge) { + testutil_random_fe_magnitude(&ge->y, SECP256K1_GE_Y_MAGNITUDE_MAX); +} + +static void testutil_random_gej_x_magnitude(rustsecp256k1_v0_11_gej *gej) { + testutil_random_fe_magnitude(&gej->x, SECP256K1_GEJ_X_MAGNITUDE_MAX); +} + +static void testutil_random_gej_y_magnitude(rustsecp256k1_v0_11_gej *gej) { + testutil_random_fe_magnitude(&gej->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX); +} + +static void testutil_random_gej_z_magnitude(rustsecp256k1_v0_11_gej *gej) { + testutil_random_fe_magnitude(&gej->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX); +} + +static void testutil_random_ge_test(rustsecp256k1_v0_11_ge *ge) { + rustsecp256k1_v0_11_fe fe; + do { + testutil_random_fe_test(&fe); + if (rustsecp256k1_v0_11_ge_set_xo_var(ge, &fe, testrand_bits(1))) { + rustsecp256k1_v0_11_fe_normalize(&ge->y); + break; + } + } while(1); + ge->infinity = 0; +} + +static void testutil_random_ge_jacobian_test(rustsecp256k1_v0_11_gej *gej, const rustsecp256k1_v0_11_ge *ge) { + rustsecp256k1_v0_11_fe z2, z3; + testutil_random_fe_non_zero_test(&gej->z); + rustsecp256k1_v0_11_fe_sqr(&z2, &gej->z); + rustsecp256k1_v0_11_fe_mul(&z3, &z2, &gej->z); + rustsecp256k1_v0_11_fe_mul(&gej->x, &ge->x, &z2); + rustsecp256k1_v0_11_fe_mul(&gej->y, &ge->y, &z3); + gej->infinity = ge->infinity; +} + +static void testutil_random_gej_test(rustsecp256k1_v0_11_gej *gej) { + rustsecp256k1_v0_11_ge ge; + testutil_random_ge_test(&ge); + testutil_random_ge_jacobian_test(gej, &ge); +} + +static void testutil_random_pubkey_test(rustsecp256k1_v0_11_pubkey *pk) { + rustsecp256k1_v0_11_ge ge; + testutil_random_ge_test(&ge); + rustsecp256k1_v0_11_pubkey_save(pk, &ge); +} + +static void testutil_random_scalar_order_test(rustsecp256k1_v0_11_scalar *num) { + do { + unsigned char b32[32]; + int overflow = 0; + testrand256_test(b32); + rustsecp256k1_v0_11_scalar_set_b32(num, b32, &overflow); + if (overflow || rustsecp256k1_v0_11_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +static void testutil_random_scalar_order(rustsecp256k1_v0_11_scalar *num) { + do { + unsigned char b32[32]; + int overflow = 0; + testrand256(b32); + rustsecp256k1_v0_11_scalar_set_b32(num, b32, &overflow); + if (overflow || rustsecp256k1_v0_11_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +static void testutil_random_scalar_order_b32(unsigned char *b32) { + rustsecp256k1_v0_11_scalar num; + testutil_random_scalar_order(&num); + rustsecp256k1_v0_11_scalar_get_b32(b32, &num); +} + +#endif /* SECP256K1_TESTUTIL_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/util.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/util.h new file mode 100644 index 00000000..702ffe1a --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/util.h @@ -0,0 +1,428 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_UTIL_H +#define SECP256K1_UTIL_H + +#include "../include/secp256k1.h" +#include "checkmem.h" + +#include +#include +#include +#include +#if defined(_MSC_VER) +/* For SecureZeroMemory */ +#include +#endif + +#define STR_(x) #x +#define STR(x) STR_(x) +#define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x +#define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x)) + +# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if SECP256K1_GNUC_PREREQ(2,7) +# define SECP256K1_INLINE __inline__ +# elif (defined(_MSC_VER)) +# define SECP256K1_INLINE __inline +# else +# define SECP256K1_INLINE +# endif +# else +# define SECP256K1_INLINE inline +# endif + +/** Assert statically that expr is true. + * + * This is a statement-like macro and can only be used inside functions. + */ +#define STATIC_ASSERT(expr) do { \ + switch(0) { \ + case 0: \ + /* If expr evaluates to 0, we have two case labels "0", which is illegal. */ \ + case /* ERROR: static assertion failed */ (expr): \ + ; \ + } \ +} while(0) + +/** Assert statically that expr is an integer constant expression, and run stmt. + * + * Useful for example to enforce that magnitude arguments are constant. + */ +#define ASSERT_INT_CONST_AND_DO(expr, stmt) do { \ + switch(42) { \ + /* C allows only integer constant expressions as case labels. */ \ + case /* ERROR: integer argument is not constant */ (expr): \ + break; \ + default: ; \ + } \ + stmt; \ +} while(0) + +typedef struct { + void (*fn)(const char *text, void* data); + const void* data; +} rustsecp256k1_v0_11_callback; + +static SECP256K1_INLINE void rustsecp256k1_v0_11_callback_call(const rustsecp256k1_v0_11_callback * const cb, const char * const text) { + cb->fn(text, (void*)cb->data); +} + +#ifndef USE_EXTERNAL_DEFAULT_CALLBACKS +static void rustsecp256k1_v0_11_default_illegal_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); + abort(); +} +static void rustsecp256k1_v0_11_default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} +#else +void rustsecp256k1_v0_11_default_illegal_callback_fn(const char* str, void* data); +void rustsecp256k1_v0_11_default_error_callback_fn(const char* str, void* data); +#endif + +static const rustsecp256k1_v0_11_callback default_illegal_callback = { + rustsecp256k1_v0_11_default_illegal_callback_fn, + NULL +}; + +static const rustsecp256k1_v0_11_callback default_error_callback = { + rustsecp256k1_v0_11_default_error_callback_fn, + NULL +}; + + +#ifdef DETERMINISTIC +#define TEST_FAILURE(msg) do { \ + fprintf(stderr, "%s\n", msg); \ + abort(); \ +} while(0); +#else +#define TEST_FAILURE(msg) do { \ + fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, msg); \ + abort(); \ +} while(0) +#endif + +#if SECP256K1_GNUC_PREREQ(3, 0) +#define EXPECT(x,c) __builtin_expect((x),(c)) +#else +#define EXPECT(x,c) (x) +#endif + +#ifdef DETERMINISTIC +#define CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + TEST_FAILURE("test condition failed"); \ + } \ +} while(0) +#else +#define CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + TEST_FAILURE("test condition failed: " #cond); \ + } \ +} while(0) +#endif + +/* Like assert(), but when VERIFY is defined. */ +#if defined(VERIFY) +#define VERIFY_CHECK CHECK +#else +#define VERIFY_CHECK(cond) +#endif + +static SECP256K1_INLINE void *checked_malloc(const rustsecp256k1_v0_11_callback* cb, size_t size) { + (void) cb; + (void) size; + return NULL; +} + +#if defined(__BIGGEST_ALIGNMENT__) +#define ALIGNMENT __BIGGEST_ALIGNMENT__ +#else +/* Using 16 bytes alignment because common architectures never have alignment + * requirements above 8 for any of the types we care about. In addition we + * leave some room because currently we don't care about a few bytes. */ +#define ALIGNMENT 16 +#endif + +/* ceil(x/y) for integers x > 0 and y > 0. Here, / denotes rational division. */ +#define CEIL_DIV(x, y) (1 + ((x) - 1) / (y)) + +#define ROUND_TO_ALIGN(size) (CEIL_DIV(size, ALIGNMENT) * ALIGNMENT) + +/* Macro for restrict, when available and not in a VERIFY build. */ +#if defined(SECP256K1_BUILD) && defined(VERIFY) +# define SECP256K1_RESTRICT +#else +# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if SECP256K1_GNUC_PREREQ(3,0) +# define SECP256K1_RESTRICT __restrict__ +# elif (defined(_MSC_VER) && _MSC_VER >= 1400) +# define SECP256K1_RESTRICT __restrict +# else +# define SECP256K1_RESTRICT +# endif +# else +# define SECP256K1_RESTRICT restrict +# endif +#endif + +#if defined(__GNUC__) +# define SECP256K1_GNUC_EXT __extension__ +#else +# define SECP256K1_GNUC_EXT +#endif + +/* Zero memory if flag == 1. Flag must be 0 or 1. Constant time. */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_memczero(void *s, size_t len, int flag) { + unsigned char *p = (unsigned char *)s; + /* Access flag with a volatile-qualified lvalue. + This prevents clang from figuring out (after inlining) that flag can + take only be 0 or 1, which leads to variable time code. */ + volatile int vflag = flag; + unsigned char mask = -(unsigned char) vflag; + while (len) { + *p &= ~mask; + p++; + len--; + } +} + +/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_memclear(void *ptr, size_t len) { +#if defined(_MSC_VER) + /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */ + SecureZeroMemory(ptr, len); +#elif defined(__GNUC__) + /* We use a memory barrier that scares the compiler away from optimizing out the memset. + * + * Quoting Adam Langley in commit ad1907fe73334d6c696c8539646c21b11178f20f + * in BoringSSL (ISC License): + * As best as we can tell, this is sufficient to break any optimisations that + * might try to eliminate "superfluous" memsets. + * This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it + * is pretty efficient, because the compiler can still implement the memset() efficently, + * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by + * Yang et al. (USENIX Security 2017) for more background. + */ + memset(ptr, 0, len); + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +#else + void *(*volatile const volatile_memset)(void *, int, size_t) = memset; + volatile_memset(ptr, 0, len); +#endif +#ifdef VERIFY + SECP256K1_CHECKMEM_UNDEFINE(ptr, len); +#endif +} + +/** Semantics like memcmp. Variable-time. + * + * We use this to avoid possible compiler bugs with memcmp, e.g. + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189 + */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_memcmp_var(const void *s1, const void *s2, size_t n) { + const unsigned char *p1 = s1, *p2 = s2; + size_t i; + + for (i = 0; i < n; i++) { + int diff = p1[i] - p2[i]; + if (diff != 0) { + return diff; + } + } + return 0; +} + +/* Return 1 if all elements of array s are 0 and otherwise return 0. + * Constant-time. */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_is_zero_array(const unsigned char *s, size_t len) { + unsigned char acc = 0; + int ret; + size_t i; + + for (i = 0; i < len; i++) { + acc |= s[i]; + } + ret = (acc == 0); + /* acc may contain secret values. Try to explicitly clear it. */ + rustsecp256k1_v0_11_memclear(&acc, sizeof(acc)); + return ret; +} + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized and non-negative.*/ +static SECP256K1_INLINE void rustsecp256k1_v0_11_int_cmov(int *r, const int *a, int flag) { + unsigned int mask0, mask1, r_masked, a_masked; + /* Access flag with a volatile-qualified lvalue. + This prevents clang from figuring out (after inlining) that flag can + take only be 0 or 1, which leads to variable time code. */ + volatile int vflag = flag; + + /* Casting a negative int to unsigned and back to int is implementation defined behavior */ + VERIFY_CHECK(*r >= 0 && *a >= 0); + + mask0 = (unsigned int)vflag + ~0u; + mask1 = ~mask0; + r_masked = ((unsigned int)*r & mask0); + a_masked = ((unsigned int)*a & mask1); + + *r = (int)(r_masked | a_masked); +} + +#if defined(USE_FORCE_WIDEMUL_INT128_STRUCT) +/* If USE_FORCE_WIDEMUL_INT128_STRUCT is set, use int128_struct. */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 +#elif defined(USE_FORCE_WIDEMUL_INT128) +/* If USE_FORCE_WIDEMUL_INT128 is set, use int128. */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_NATIVE 1 +#elif defined(USE_FORCE_WIDEMUL_INT64) +/* If USE_FORCE_WIDEMUL_INT64 is set, use int64. */ +# define SECP256K1_WIDEMUL_INT64 1 +#elif defined(UINT128_MAX) || defined(__SIZEOF_INT128__) +/* If a native 128-bit integer type exists, use int128. */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_NATIVE 1 +#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) +/* On 64-bit MSVC targets (x86_64 and arm64), use int128_struct + * (which has special logic to implement using intrinsics on those systems). */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 +#elif SIZE_MAX > 0xffffffff +/* Systems with 64-bit pointers (and thus registers) very likely benefit from + * using 64-bit based arithmetic (even if we need to fall back to 32x32->64 based + * multiplication logic). */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 +#else +/* Lastly, fall back to int64 based arithmetic. */ +# define SECP256K1_WIDEMUL_INT64 1 +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. + * This function is only intended to be used as fallback for + * rustsecp256k1_v0_11_ctz32_var, but permits it to be tested separately. */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_ctz32_var_debruijn(uint32_t x) { + static const uint8_t debruijn[32] = { + 0x00, 0x01, 0x02, 0x18, 0x03, 0x13, 0x06, 0x19, 0x16, 0x04, 0x14, 0x0A, + 0x10, 0x07, 0x0C, 0x1A, 0x1F, 0x17, 0x12, 0x05, 0x15, 0x09, 0x0F, 0x0B, + 0x1E, 0x11, 0x08, 0x0E, 0x1D, 0x0D, 0x1C, 0x1B + }; + return debruijn[(uint32_t)((x & -x) * 0x04D7651FU) >> 27]; +} + +/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. + * This function is only intended to be used as fallback for + * rustsecp256k1_v0_11_ctz64_var, but permits it to be tested separately. */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_ctz64_var_debruijn(uint64_t x) { + static const uint8_t debruijn[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 + }; + return debruijn[(uint64_t)((x & -x) * 0x022FDD63CC95386DU) >> 58]; +} + +/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_ctz32_var(uint32_t x) { + VERIFY_CHECK(x != 0); +#if (__has_builtin(__builtin_ctz) || SECP256K1_GNUC_PREREQ(3,4)) + /* If the unsigned type is sufficient to represent the largest uint32_t, consider __builtin_ctz. */ + if (((unsigned)UINT32_MAX) == UINT32_MAX) { + return __builtin_ctz(x); + } +#endif +#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4)) + /* Otherwise consider __builtin_ctzl (the unsigned long type is always at least 32 bits). */ + return __builtin_ctzl(x); +#else + /* If no suitable CTZ builtin is available, use a (variable time) software emulation. */ + return rustsecp256k1_v0_11_ctz32_var_debruijn(x); +#endif +} + +/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_ctz64_var(uint64_t x) { + VERIFY_CHECK(x != 0); +#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4)) + /* If the unsigned long type is sufficient to represent the largest uint64_t, consider __builtin_ctzl. */ + if (((unsigned long)UINT64_MAX) == UINT64_MAX) { + return __builtin_ctzl(x); + } +#endif +#if (__has_builtin(__builtin_ctzll) || SECP256K1_GNUC_PREREQ(3,4)) + /* Otherwise consider __builtin_ctzll (the unsigned long long type is always at least 64 bits). */ + return __builtin_ctzll(x); +#else + /* If no suitable CTZ builtin is available, use a (variable time) software emulation. */ + return rustsecp256k1_v0_11_ctz64_var_debruijn(x); +#endif +} + +/* Read a uint32_t in big endian */ +SECP256K1_INLINE static uint32_t rustsecp256k1_v0_11_read_be32(const unsigned char* p) { + return (uint32_t)p[0] << 24 | + (uint32_t)p[1] << 16 | + (uint32_t)p[2] << 8 | + (uint32_t)p[3]; +} + +/* Write a uint32_t in big endian */ +SECP256K1_INLINE static void rustsecp256k1_v0_11_write_be32(unsigned char* p, uint32_t x) { + p[3] = x; + p[2] = x >> 8; + p[1] = x >> 16; + p[0] = x >> 24; +} + +/* Read a uint64_t in big endian */ +SECP256K1_INLINE static uint64_t rustsecp256k1_v0_11_read_be64(const unsigned char* p) { + return (uint64_t)p[0] << 56 | + (uint64_t)p[1] << 48 | + (uint64_t)p[2] << 40 | + (uint64_t)p[3] << 32 | + (uint64_t)p[4] << 24 | + (uint64_t)p[5] << 16 | + (uint64_t)p[6] << 8 | + (uint64_t)p[7]; +} + +/* Write a uint64_t in big endian */ +SECP256K1_INLINE static void rustsecp256k1_v0_11_write_be64(unsigned char* p, uint64_t x) { + p[7] = x; + p[6] = x >> 8; + p[5] = x >> 16; + p[4] = x >> 24; + p[3] = x >> 32; + p[2] = x >> 40; + p[1] = x >> 48; + p[0] = x >> 56; +} + +/* Rotate a uint32_t to the right. */ +SECP256K1_INLINE static uint32_t rustsecp256k1_v0_11_rotr32(const uint32_t x, const unsigned int by) { +#if defined(_MSC_VER) + return _rotr(x, by); /* needs */ +#else + /* Reduce rotation amount to avoid UB when shifting. */ + const unsigned int mask = CHAR_BIT * sizeof(x) - 1; + /* Turned into a rot instruction by GCC and clang. */ + return (x >> (by & mask)) | (x << ((-by) & mask)); +#endif +} + +#endif /* SECP256K1_UTIL_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/util.h.orig b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/util.h.orig new file mode 100644 index 00000000..446ed169 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/util.h.orig @@ -0,0 +1,451 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_UTIL_H +#define SECP256K1_UTIL_H + +#include "../include/secp256k1.h" +#include "checkmem.h" + +#include +#include +#include +#include +#include +#if defined(_MSC_VER) +/* For SecureZeroMemory */ +#include +#endif + +#define STR_(x) #x +#define STR(x) STR_(x) +#define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x +#define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x)) + +/* Debug helper for printing arrays of unsigned char. */ +#define PRINT_BUF(buf, len) do { \ + printf("%s[%lu] = ", #buf, (unsigned long)len); \ + print_buf_plain(buf, len); \ +} while(0) + +static void print_buf_plain(const unsigned char *buf, size_t len) { + size_t i; + printf("{"); + for (i = 0; i < len; i++) { + if (i % 8 == 0) { + printf("\n "); + } else { + printf(" "); + } + printf("0x%02X,", buf[i]); + } + printf("\n}\n"); +} + +# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if SECP256K1_GNUC_PREREQ(2,7) +# define SECP256K1_INLINE __inline__ +# elif (defined(_MSC_VER)) +# define SECP256K1_INLINE __inline +# else +# define SECP256K1_INLINE +# endif +# else +# define SECP256K1_INLINE inline +# endif + +/** Assert statically that expr is true. + * + * This is a statement-like macro and can only be used inside functions. + */ +#define STATIC_ASSERT(expr) do { \ + switch(0) { \ + case 0: \ + /* If expr evaluates to 0, we have two case labels "0", which is illegal. */ \ + case /* ERROR: static assertion failed */ (expr): \ + ; \ + } \ +} while(0) + +/** Assert statically that expr is an integer constant expression, and run stmt. + * + * Useful for example to enforce that magnitude arguments are constant. + */ +#define ASSERT_INT_CONST_AND_DO(expr, stmt) do { \ + switch(42) { \ + /* C allows only integer constant expressions as case labels. */ \ + case /* ERROR: integer argument is not constant */ (expr): \ + break; \ + default: ; \ + } \ + stmt; \ +} while(0) + +typedef struct { + void (*fn)(const char *text, void* data); + const void* data; +} rustsecp256k1_v0_11_callback; + +static SECP256K1_INLINE void rustsecp256k1_v0_11_callback_call(const rustsecp256k1_v0_11_callback * const cb, const char * const text) { + cb->fn(text, (void*)cb->data); +} + +#ifndef USE_EXTERNAL_DEFAULT_CALLBACKS +static void rustsecp256k1_v0_11_default_illegal_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); + abort(); +} +static void rustsecp256k1_v0_11_default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} +#else +void rustsecp256k1_v0_11_default_illegal_callback_fn(const char* str, void* data); +void rustsecp256k1_v0_11_default_error_callback_fn(const char* str, void* data); +#endif + +static const rustsecp256k1_v0_11_callback default_illegal_callback = { + rustsecp256k1_v0_11_default_illegal_callback_fn, + NULL +}; + +static const rustsecp256k1_v0_11_callback default_error_callback = { + rustsecp256k1_v0_11_default_error_callback_fn, + NULL +}; + + +#ifdef DETERMINISTIC +#define TEST_FAILURE(msg) do { \ + fprintf(stderr, "%s\n", msg); \ + abort(); \ +} while(0); +#else +#define TEST_FAILURE(msg) do { \ + fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, msg); \ + abort(); \ +} while(0) +#endif + +#if SECP256K1_GNUC_PREREQ(3, 0) +#define EXPECT(x,c) __builtin_expect((x),(c)) +#else +#define EXPECT(x,c) (x) +#endif + +#ifdef DETERMINISTIC +#define CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + TEST_FAILURE("test condition failed"); \ + } \ +} while(0) +#else +#define CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + TEST_FAILURE("test condition failed: " #cond); \ + } \ +} while(0) +#endif + +/* Like assert(), but when VERIFY is defined. */ +#if defined(VERIFY) +#define VERIFY_CHECK CHECK +#else +#define VERIFY_CHECK(cond) +#endif + +static SECP256K1_INLINE void *checked_malloc(const rustsecp256k1_v0_11_callback* cb, size_t size) { + void *ret = malloc(size); + if (ret == NULL) { + rustsecp256k1_v0_11_callback_call(cb, "Out of memory"); + } + return ret; +} + +#if defined(__BIGGEST_ALIGNMENT__) +#define ALIGNMENT __BIGGEST_ALIGNMENT__ +#else +/* Using 16 bytes alignment because common architectures never have alignment + * requirements above 8 for any of the types we care about. In addition we + * leave some room because currently we don't care about a few bytes. */ +#define ALIGNMENT 16 +#endif + +/* ceil(x/y) for integers x > 0 and y > 0. Here, / denotes rational division. */ +#define CEIL_DIV(x, y) (1 + ((x) - 1) / (y)) + +#define ROUND_TO_ALIGN(size) (CEIL_DIV(size, ALIGNMENT) * ALIGNMENT) + +/* Macro for restrict, when available and not in a VERIFY build. */ +#if defined(SECP256K1_BUILD) && defined(VERIFY) +# define SECP256K1_RESTRICT +#else +# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if SECP256K1_GNUC_PREREQ(3,0) +# define SECP256K1_RESTRICT __restrict__ +# elif (defined(_MSC_VER) && _MSC_VER >= 1400) +# define SECP256K1_RESTRICT __restrict +# else +# define SECP256K1_RESTRICT +# endif +# else +# define SECP256K1_RESTRICT restrict +# endif +#endif + +#if defined(__GNUC__) +# define SECP256K1_GNUC_EXT __extension__ +#else +# define SECP256K1_GNUC_EXT +#endif + +/* Zero memory if flag == 1. Flag must be 0 or 1. Constant time. */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_memczero(void *s, size_t len, int flag) { + unsigned char *p = (unsigned char *)s; + /* Access flag with a volatile-qualified lvalue. + This prevents clang from figuring out (after inlining) that flag can + take only be 0 or 1, which leads to variable time code. */ + volatile int vflag = flag; + unsigned char mask = -(unsigned char) vflag; + while (len) { + *p &= ~mask; + p++; + len--; + } +} + +/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */ +static SECP256K1_INLINE void rustsecp256k1_v0_11_memclear(void *ptr, size_t len) { +#if defined(_MSC_VER) + /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */ + SecureZeroMemory(ptr, len); +#elif defined(__GNUC__) + /* We use a memory barrier that scares the compiler away from optimizing out the memset. + * + * Quoting Adam Langley in commit ad1907fe73334d6c696c8539646c21b11178f20f + * in BoringSSL (ISC License): + * As best as we can tell, this is sufficient to break any optimisations that + * might try to eliminate "superfluous" memsets. + * This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it + * is pretty efficient, because the compiler can still implement the memset() efficently, + * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by + * Yang et al. (USENIX Security 2017) for more background. + */ + memset(ptr, 0, len); + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +#else + void *(*volatile const volatile_memset)(void *, int, size_t) = memset; + volatile_memset(ptr, 0, len); +#endif +#ifdef VERIFY + SECP256K1_CHECKMEM_UNDEFINE(ptr, len); +#endif +} + +/** Semantics like memcmp. Variable-time. + * + * We use this to avoid possible compiler bugs with memcmp, e.g. + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189 + */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_memcmp_var(const void *s1, const void *s2, size_t n) { + const unsigned char *p1 = s1, *p2 = s2; + size_t i; + + for (i = 0; i < n; i++) { + int diff = p1[i] - p2[i]; + if (diff != 0) { + return diff; + } + } + return 0; +} + +/* Return 1 if all elements of array s are 0 and otherwise return 0. + * Constant-time. */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_is_zero_array(const unsigned char *s, size_t len) { + unsigned char acc = 0; + int ret; + size_t i; + + for (i = 0; i < len; i++) { + acc |= s[i]; + } + ret = (acc == 0); + /* acc may contain secret values. Try to explicitly clear it. */ + rustsecp256k1_v0_11_memclear(&acc, sizeof(acc)); + return ret; +} + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized and non-negative.*/ +static SECP256K1_INLINE void rustsecp256k1_v0_11_int_cmov(int *r, const int *a, int flag) { + unsigned int mask0, mask1, r_masked, a_masked; + /* Access flag with a volatile-qualified lvalue. + This prevents clang from figuring out (after inlining) that flag can + take only be 0 or 1, which leads to variable time code. */ + volatile int vflag = flag; + + /* Casting a negative int to unsigned and back to int is implementation defined behavior */ + VERIFY_CHECK(*r >= 0 && *a >= 0); + + mask0 = (unsigned int)vflag + ~0u; + mask1 = ~mask0; + r_masked = ((unsigned int)*r & mask0); + a_masked = ((unsigned int)*a & mask1); + + *r = (int)(r_masked | a_masked); +} + +#if defined(USE_FORCE_WIDEMUL_INT128_STRUCT) +/* If USE_FORCE_WIDEMUL_INT128_STRUCT is set, use int128_struct. */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 +#elif defined(USE_FORCE_WIDEMUL_INT128) +/* If USE_FORCE_WIDEMUL_INT128 is set, use int128. */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_NATIVE 1 +#elif defined(USE_FORCE_WIDEMUL_INT64) +/* If USE_FORCE_WIDEMUL_INT64 is set, use int64. */ +# define SECP256K1_WIDEMUL_INT64 1 +#elif defined(UINT128_MAX) || defined(__SIZEOF_INT128__) +/* If a native 128-bit integer type exists, use int128. */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_NATIVE 1 +#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) +/* On 64-bit MSVC targets (x86_64 and arm64), use int128_struct + * (which has special logic to implement using intrinsics on those systems). */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 +#elif SIZE_MAX > 0xffffffff +/* Systems with 64-bit pointers (and thus registers) very likely benefit from + * using 64-bit based arithmetic (even if we need to fall back to 32x32->64 based + * multiplication logic). */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 +#else +/* Lastly, fall back to int64 based arithmetic. */ +# define SECP256K1_WIDEMUL_INT64 1 +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. + * This function is only intended to be used as fallback for + * rustsecp256k1_v0_11_ctz32_var, but permits it to be tested separately. */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_ctz32_var_debruijn(uint32_t x) { + static const uint8_t debruijn[32] = { + 0x00, 0x01, 0x02, 0x18, 0x03, 0x13, 0x06, 0x19, 0x16, 0x04, 0x14, 0x0A, + 0x10, 0x07, 0x0C, 0x1A, 0x1F, 0x17, 0x12, 0x05, 0x15, 0x09, 0x0F, 0x0B, + 0x1E, 0x11, 0x08, 0x0E, 0x1D, 0x0D, 0x1C, 0x1B + }; + return debruijn[(uint32_t)((x & -x) * 0x04D7651FU) >> 27]; +} + +/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. + * This function is only intended to be used as fallback for + * rustsecp256k1_v0_11_ctz64_var, but permits it to be tested separately. */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_ctz64_var_debruijn(uint64_t x) { + static const uint8_t debruijn[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 + }; + return debruijn[(uint64_t)((x & -x) * 0x022FDD63CC95386DU) >> 58]; +} + +/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_ctz32_var(uint32_t x) { + VERIFY_CHECK(x != 0); +#if (__has_builtin(__builtin_ctz) || SECP256K1_GNUC_PREREQ(3,4)) + /* If the unsigned type is sufficient to represent the largest uint32_t, consider __builtin_ctz. */ + if (((unsigned)UINT32_MAX) == UINT32_MAX) { + return __builtin_ctz(x); + } +#endif +#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4)) + /* Otherwise consider __builtin_ctzl (the unsigned long type is always at least 32 bits). */ + return __builtin_ctzl(x); +#else + /* If no suitable CTZ builtin is available, use a (variable time) software emulation. */ + return rustsecp256k1_v0_11_ctz32_var_debruijn(x); +#endif +} + +/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. */ +static SECP256K1_INLINE int rustsecp256k1_v0_11_ctz64_var(uint64_t x) { + VERIFY_CHECK(x != 0); +#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4)) + /* If the unsigned long type is sufficient to represent the largest uint64_t, consider __builtin_ctzl. */ + if (((unsigned long)UINT64_MAX) == UINT64_MAX) { + return __builtin_ctzl(x); + } +#endif +#if (__has_builtin(__builtin_ctzll) || SECP256K1_GNUC_PREREQ(3,4)) + /* Otherwise consider __builtin_ctzll (the unsigned long long type is always at least 64 bits). */ + return __builtin_ctzll(x); +#else + /* If no suitable CTZ builtin is available, use a (variable time) software emulation. */ + return rustsecp256k1_v0_11_ctz64_var_debruijn(x); +#endif +} + +/* Read a uint32_t in big endian */ +SECP256K1_INLINE static uint32_t rustsecp256k1_v0_11_read_be32(const unsigned char* p) { + return (uint32_t)p[0] << 24 | + (uint32_t)p[1] << 16 | + (uint32_t)p[2] << 8 | + (uint32_t)p[3]; +} + +/* Write a uint32_t in big endian */ +SECP256K1_INLINE static void rustsecp256k1_v0_11_write_be32(unsigned char* p, uint32_t x) { + p[3] = x; + p[2] = x >> 8; + p[1] = x >> 16; + p[0] = x >> 24; +} + +/* Read a uint64_t in big endian */ +SECP256K1_INLINE static uint64_t rustsecp256k1_v0_11_read_be64(const unsigned char* p) { + return (uint64_t)p[0] << 56 | + (uint64_t)p[1] << 48 | + (uint64_t)p[2] << 40 | + (uint64_t)p[3] << 32 | + (uint64_t)p[4] << 24 | + (uint64_t)p[5] << 16 | + (uint64_t)p[6] << 8 | + (uint64_t)p[7]; +} + +/* Write a uint64_t in big endian */ +SECP256K1_INLINE static void rustsecp256k1_v0_11_write_be64(unsigned char* p, uint64_t x) { + p[7] = x; + p[6] = x >> 8; + p[5] = x >> 16; + p[4] = x >> 24; + p[3] = x >> 32; + p[2] = x >> 40; + p[1] = x >> 48; + p[0] = x >> 56; +} + +/* Rotate a uint32_t to the right. */ +SECP256K1_INLINE static uint32_t rustsecp256k1_v0_11_rotr32(const uint32_t x, const unsigned int by) { +#if defined(_MSC_VER) + return _rotr(x, by); /* needs */ +#else + /* Reduce rotation amount to avoid UB when shifting. */ + const unsigned int mask = CHAR_BIT * sizeof(x) - 1; + /* Turned into a rot instruction by GCC and clang. */ + return (x >> (by & mask)) | (x << ((-by) & mask)); +#endif +} + +#endif /* SECP256K1_UTIL_H */ diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/wycheproof/WYCHEPROOF_COPYING b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/wycheproof/WYCHEPROOF_COPYING new file mode 100644 index 00000000..87835e2d --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/wycheproof/WYCHEPROOF_COPYING @@ -0,0 +1,212 @@ +* The file `ecdsa_rustsecp256k1_v0_11_sha256_bitcoin_test.json` in this directory + comes from Google's project Wycheproof with git commit + `b063b4aedae951c69df014cd25fa6d69ae9e8cb9`, see + https://github.com/google/wycheproof/blob/b063b4aedae951c69df014cd25fa6d69ae9e8cb9/testvectors_v1/ecdsa_rustsecp256k1_v0_11_sha256_bitcoin_test.json + +* The file `ecdsa_rustsecp256k1_v0_11_sha256_bitcoin_test.h` is generated from + `ecdsa_rustsecp256k1_v0_11_sha256_bitcoin_test.json` using the script + `tests_wycheproof_generate.py`. + +------------------------------------------------------------------------------- + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h new file mode 100644 index 00000000..736737fd --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h @@ -0,0 +1,1564 @@ +/* Note: this file was autogenerated using tests_wycheproof_generate.py. Do not edit. */ +#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS (463) + +typedef struct { + size_t pk_offset; + size_t msg_offset; + size_t msg_len; + size_t sig_offset; + size_t sig_len; + int expected_verify; +} wycheproof_ecdsa_testvector; + +static const unsigned char wycheproof_ecdsa_messages[] = { 0x31,0x32,0x33,0x34,0x30,0x30, + 0x32,0x35,0x35,0x38,0x35, + 0x34,0x32,0x36,0x34,0x37,0x39,0x37,0x32,0x34, + 0x37,0x31,0x33,0x38,0x36,0x38,0x34,0x38,0x39,0x31, + 0x31,0x30,0x33,0x35,0x39,0x33,0x33,0x31,0x36,0x36,0x38, + 0x33,0x39,0x34,0x39,0x34,0x30,0x31,0x32,0x31,0x35, + 0x31,0x33,0x34,0x34,0x32,0x39,0x33,0x30,0x37,0x39, + 0x33,0x37,0x30,0x36,0x32,0x31,0x31,0x37,0x31,0x32, + 0x33,0x34,0x33,0x36,0x38,0x38,0x37,0x31,0x32, + 0x31,0x33,0x35,0x31,0x35,0x33,0x30,0x33,0x37,0x30, + 0x36,0x35,0x35,0x33,0x32,0x30,0x33,0x31,0x32,0x36, + 0x31,0x35,0x36,0x34,0x33,0x34,0x36,0x36,0x30,0x33, + 0x34,0x34,0x32,0x39,0x35,0x33,0x39,0x31,0x31,0x37, + 0x31,0x30,0x39,0x35,0x33,0x32,0x36,0x31,0x33,0x35,0x31, + 0x35,0x39,0x38,0x37,0x33,0x35,0x30,0x30,0x34,0x31, + 0x33,0x34,0x36,0x33,0x30,0x30,0x36,0x38,0x37,0x38, + 0x39,0x38,0x31,0x37,0x33,0x32,0x30,0x32,0x38,0x37, + 0x33,0x32,0x32,0x32,0x30,0x34,0x31,0x30,0x34,0x36, + 0x36,0x36,0x36,0x36,0x33,0x30,0x37,0x31,0x30,0x34, + 0x31,0x30,0x33,0x35,0x39,0x35,0x31,0x38,0x39,0x38, + 0x31,0x38,0x34,0x36,0x35,0x39,0x37,0x31,0x39,0x35, + 0x33,0x31,0x33,0x36,0x30,0x34,0x36,0x31,0x38,0x39, + 0x32,0x36,0x36,0x33,0x37,0x38,0x34,0x32,0x35,0x34, + 0x31,0x36,0x35,0x32,0x31,0x30,0x30,0x35,0x32,0x34, + 0x35,0x37,0x34,0x38,0x30,0x38,0x31,0x36,0x39,0x36, + 0x36,0x33,0x34,0x33,0x39,0x31,0x33,0x34,0x36,0x38, + 0x31,0x35,0x34,0x31,0x31,0x30,0x33,0x35,0x39,0x38, + 0x31,0x30,0x34,0x37,0x38,0x35,0x38,0x30,0x31,0x32,0x38, + 0x31,0x30,0x35,0x33,0x36,0x32,0x38,0x35,0x35,0x36,0x38, + 0x39,0x35,0x33,0x39,0x30,0x34,0x31,0x30,0x35, + 0x39,0x37,0x38,0x38,0x34,0x38,0x30,0x33,0x39, + 0x33,0x36,0x31,0x30,0x36,0x37,0x32,0x34,0x34,0x32, + 0x31,0x30,0x35,0x34,0x32,0x34,0x30,0x37,0x30,0x35, + 0x35,0x31,0x37,0x34,0x34,0x34,0x38,0x31,0x39,0x37, + 0x31,0x39,0x36,0x37,0x35,0x36,0x31,0x32,0x35,0x31, + 0x33,0x34,0x34,0x37,0x32,0x35,0x33,0x33,0x34,0x33, + 0x33,0x36,0x38,0x32,0x36,0x34,0x33,0x31,0x38, + 0x33,0x32,0x36,0x31,0x31,0x39,0x38,0x36,0x30,0x38, + 0x39,0x36,0x37,0x38,0x37,0x38,0x31,0x30,0x39,0x34, + 0x34,0x39,0x35,0x38,0x38,0x32,0x33,0x38,0x32,0x33, + 0x38,0x32,0x34,0x36,0x33,0x37,0x38,0x33,0x37, + 0x31,0x31,0x30,0x32,0x30,0x38,0x33,0x33,0x37,0x37,0x36, + 0x31,0x33,0x33,0x38,0x37,0x31,0x36,0x34,0x38, + 0x33,0x32,0x32,0x31,0x34,0x34,0x31,0x36,0x32, + 0x31,0x30,0x36,0x38,0x36,0x36,0x35,0x35,0x35,0x34,0x36, + 0x36,0x32,0x31,0x35,0x35,0x32,0x34,0x36, + 0x37,0x30,0x33,0x30,0x38,0x31,0x38,0x37,0x37,0x34, + 0x35,0x39,0x32,0x34,0x35,0x32,0x33,0x37,0x34,0x34, + 0x31,0x34,0x39,0x35,0x35,0x38,0x36,0x36,0x32,0x31, + 0x34,0x30,0x30,0x35,0x33,0x31,0x34,0x34,0x30,0x36, + 0x33,0x30,0x39,0x36,0x34,0x35,0x37,0x35,0x31,0x32, + 0x32,0x37,0x38,0x34,0x30,0x32,0x35,0x36,0x32,0x30, + 0x32,0x36,0x31,0x38,0x37,0x38,0x37,0x34,0x31,0x38, + 0x31,0x36,0x34,0x32,0x36,0x32,0x35,0x32,0x36,0x32, + 0x36,0x38,0x32,0x34,0x31,0x38,0x39,0x34,0x33,0x36, + 0x34,0x38,0x34,0x32,0x34,0x35,0x34,0x32,0x35, + 0x4d,0x73,0x67, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x4d,0x65,0x73,0x73,0x61,0x67,0x65}; + +static const unsigned char wycheproof_ecdsa_public_keys[] = { 0x04,0xb8,0x38,0xff,0x44,0xe5,0xbc,0x17,0x7b,0xf2,0x11,0x89,0xd0,0x76,0x60,0x82,0xfc,0x9d,0x84,0x32,0x26,0x88,0x7f,0xc9,0x76,0x03,0x71,0x10,0x0b,0x7e,0xe2,0x0a,0x6f,0xf0,0xc9,0xd7,0x5b,0xfb,0xa7,0xb3,0x1a,0x6b,0xca,0x19,0x74,0x49,0x6e,0xeb,0x56,0xde,0x35,0x70,0x71,0x95,0x5d,0x83,0xc4,0xb1,0xba,0xda,0xa0,0xb2,0x18,0x32,0xe9, + 0x04,0x07,0x31,0x0f,0x90,0xa9,0xea,0xe1,0x49,0xa0,0x84,0x02,0xf5,0x41,0x94,0xa0,0xf7,0xb4,0xac,0x42,0x7b,0xf8,0xd9,0xbd,0x6c,0x76,0x81,0x07,0x1d,0xc4,0x7d,0xc3,0x62,0x26,0xa6,0xd3,0x7a,0xc4,0x6d,0x61,0xfd,0x60,0x0c,0x0b,0xf1,0xbf,0xf8,0x76,0x89,0xed,0x11,0x7d,0xda,0x6b,0x0e,0x59,0x31,0x8a,0xe0,0x10,0xa1,0x97,0xa2,0x6c,0xa0, + 0x04,0xbc,0x97,0xe7,0x58,0x5e,0xec,0xad,0x48,0xe1,0x66,0x83,0xbc,0x40,0x91,0x70,0x8e,0x1a,0x93,0x0c,0x68,0x3f,0xc4,0x70,0x01,0xd4,0xb3,0x83,0x59,0x4f,0x2c,0x4e,0x22,0x70,0x59,0x89,0xcf,0x69,0xda,0xea,0xdd,0x4e,0x4e,0x4b,0x81,0x51,0xed,0x88,0x8d,0xfe,0xc2,0x0f,0xb0,0x17,0x28,0xd8,0x9d,0x56,0xb3,0xf3,0x8f,0x2a,0xe9,0xc8,0xc5, + 0x04,0x44,0xad,0x33,0x9a,0xfb,0xc2,0x1e,0x9a,0xbf,0x7b,0x60,0x2a,0x5c,0xa5,0x35,0xea,0x37,0x81,0x35,0xb6,0xd1,0x0d,0x81,0x31,0x0b,0xdd,0x82,0x93,0xd1,0xdf,0x32,0x52,0xb6,0x3f,0xf7,0xd0,0x77,0x47,0x70,0xf8,0xfe,0x1d,0x17,0x22,0xfa,0x83,0xac,0xd0,0x2f,0x43,0x4e,0x4f,0xc1,0x10,0xa0,0xcc,0x8f,0x6d,0xdd,0xd3,0x7d,0x56,0xc4,0x63, + 0x04,0x12,0x60,0xc2,0x12,0x2c,0x9e,0x24,0x4e,0x1a,0xf5,0x15,0x1b,0xed,0xe0,0xc3,0xae,0x23,0xb5,0x4d,0x7c,0x59,0x68,0x81,0xd3,0xee,0xba,0xd2,0x1f,0x37,0xdd,0x87,0x8c,0x5c,0x9a,0x0c,0x1a,0x9a,0xde,0x76,0x73,0x7a,0x88,0x11,0xbd,0x6a,0x7f,0x92,0x87,0xc9,0x78,0xee,0x39,0x6a,0xa8,0x9c,0x11,0xe4,0x72,0x29,0xd2,0xcc,0xb5,0x52,0xf0, + 0x04,0x18,0x77,0x04,0x5b,0xe2,0x5d,0x34,0xa1,0xd0,0x60,0x0f,0x9d,0x5c,0x00,0xd0,0x64,0x5a,0x2a,0x54,0x37,0x9b,0x6c,0xee,0xfa,0xd2,0xe6,0xbf,0x5c,0x2a,0x33,0x52,0xce,0x82,0x1a,0x53,0x2c,0xc1,0x75,0x1e,0xe1,0xd3,0x6d,0x41,0xc3,0xd6,0xab,0x4e,0x9b,0x14,0x3e,0x44,0xec,0x46,0xd7,0x34,0x78,0xea,0x6a,0x79,0xa5,0xc0,0xe5,0x41,0x59, + 0x04,0x45,0x54,0x39,0xfc,0xc3,0xd2,0xde,0xec,0xed,0xde,0xae,0xce,0x60,0xe7,0xbd,0x17,0x30,0x4f,0x36,0xeb,0xb6,0x02,0xad,0xf5,0xa2,0x2e,0x0b,0x8f,0x1d,0xb4,0x6a,0x50,0xae,0xc3,0x8f,0xb2,0xba,0xf2,0x21,0xe9,0xa8,0xd1,0x88,0x7c,0x7b,0xf6,0x22,0x2d,0xd1,0x83,0x46,0x34,0xe7,0x72,0x63,0x31,0x5a,0xf6,0xd2,0x36,0x09,0xd0,0x4f,0x77, + 0x04,0x2e,0x1f,0x46,0x6b,0x02,0x4c,0x0c,0x3a,0xce,0x24,0x37,0xde,0x09,0x12,0x7f,0xed,0x04,0xb7,0x06,0xf9,0x4b,0x19,0xa2,0x1b,0xb1,0xc2,0xac,0xf3,0x5c,0xec,0xe7,0x18,0x04,0x49,0xae,0x35,0x23,0xd7,0x25,0x34,0xe9,0x64,0x97,0x2c,0xfd,0x3b,0x38,0xaf,0x0b,0xdd,0xd9,0x61,0x9e,0x5a,0xf2,0x23,0xe4,0xd1,0xa4,0x0f,0x34,0xcf,0x9f,0x1d, + 0x04,0x8e,0x7a,0xbd,0xbb,0xd1,0x8d,0xe7,0x45,0x23,0x74,0xc1,0x87,0x9a,0x1c,0x3b,0x01,0xd1,0x32,0x61,0xe7,0xd4,0x57,0x1c,0x3b,0x47,0xa1,0xc7,0x6c,0x55,0xa2,0x33,0x73,0x26,0xed,0x89,0x7c,0xd5,0x17,0xa4,0xf5,0x34,0x9d,0xb8,0x09,0x78,0x0f,0x6d,0x2f,0x2b,0x9f,0x62,0x99,0xd8,0xb5,0xa8,0x90,0x77,0xf1,0x11,0x9a,0x71,0x8f,0xd7,0xb3, + 0x04,0x7b,0x33,0x3d,0x43,0x40,0xd3,0xd7,0x18,0xdd,0x3e,0x6a,0xff,0x7d,0xe7,0xbb,0xf8,0xb7,0x2b,0xfd,0x61,0x6c,0x84,0x20,0x05,0x60,0x52,0x84,0x23,0x76,0xb9,0xaf,0x19,0x42,0x11,0x7c,0x5a,0xfe,0xac,0x75,0x5d,0x6f,0x37,0x6f,0xc6,0x32,0x9a,0x7d,0x76,0x05,0x1b,0x87,0x12,0x3a,0x4a,0x5d,0x0b,0xc4,0xa5,0x39,0x38,0x0f,0x03,0xde,0x7b, + 0x04,0xd3,0x0c,0xa4,0xa0,0xdd,0xb6,0x61,0x6c,0x85,0x1d,0x30,0xce,0xd6,0x82,0xc4,0x0f,0x83,0xc6,0x27,0x58,0xa1,0xf2,0x75,0x99,0x88,0xd6,0x76,0x3a,0x88,0xf1,0xc0,0xe5,0x03,0xa8,0x0d,0x54,0x15,0x65,0x0d,0x41,0x23,0x97,0x84,0xe8,0xe2,0xfb,0x12,0x35,0xe9,0xfe,0x99,0x1d,0x11,0x2e,0xbb,0x81,0x18,0x6c,0xbf,0x0d,0xa2,0xde,0x3a,0xff, + 0x04,0x48,0x96,0x9b,0x39,0x99,0x12,0x97,0xb3,0x32,0xa6,0x52,0xd3,0xee,0x6e,0x01,0xe9,0x09,0xb3,0x99,0x04,0xe7,0x1f,0xa2,0x35,0x4a,0x78,0x30,0xc7,0x75,0x0b,0xaf,0x24,0xb4,0x01,0x2d,0x1b,0x83,0x0d,0x19,0x9c,0xcb,0x1f,0xc9,0x72,0xb3,0x2b,0xfd,0xed,0x55,0xf0,0x9c,0xd6,0x2d,0x25,0x7e,0x5e,0x84,0x4e,0x27,0xe5,0x7a,0x15,0x94,0xec, + 0x04,0x02,0xef,0x4d,0x6d,0x6c,0xfd,0x5a,0x94,0xf1,0xd7,0x78,0x42,0x26,0xe3,0xe2,0xa6,0xc0,0xa4,0x36,0xc5,0x58,0x39,0x61,0x9f,0x38,0xfb,0x44,0x72,0xb5,0xf9,0xee,0x77,0x7e,0xb4,0xac,0xd4,0xee,0xbd,0xa5,0xcd,0x72,0x87,0x5f,0xfd,0x2a,0x2f,0x26,0x22,0x9c,0x2d,0xc6,0xb4,0x65,0x00,0x91,0x9a,0x43,0x2c,0x86,0x73,0x9f,0x3a,0xe8,0x66, + 0x04,0x46,0x4f,0x4f,0xf7,0x15,0x72,0x9c,0xae,0x50,0x72,0xca,0x3b,0xd8,0x01,0xd3,0x19,0x5b,0x67,0xae,0xc6,0x5e,0x9b,0x01,0xaa,0xd2,0x0a,0x29,0x43,0xdc,0xbc,0xb5,0x84,0xb1,0xaf,0xd2,0x9d,0x31,0xa3,0x9a,0x11,0xd5,0x70,0xaa,0x15,0x97,0x43,0x9b,0x3b,0x2d,0x19,0x71,0xbf,0x2f,0x1a,0xbf,0x15,0x43,0x2d,0x02,0x07,0xb1,0x0d,0x1d,0x08, + 0x04,0x15,0x7f,0x8f,0xdd,0xf3,0x73,0xeb,0x5f,0x49,0xcf,0xcf,0x10,0xd8,0xb8,0x53,0xcf,0x91,0xcb,0xcd,0x7d,0x66,0x5c,0x35,0x22,0xba,0x7d,0xd7,0x38,0xdd,0xb7,0x9a,0x4c,0xde,0xad,0xf1,0xa5,0xc4,0x48,0xea,0x3c,0x9f,0x41,0x91,0xa8,0x99,0x9a,0xbf,0xcc,0x75,0x7a,0xc6,0xd6,0x45,0x67,0xef,0x07,0x2c,0x47,0xfe,0xc6,0x13,0x44,0x3b,0x8f, + 0x04,0x09,0x34,0xa5,0x37,0x46,0x6c,0x07,0x43,0x0e,0x2c,0x48,0xfe,0xb9,0x90,0xbb,0x19,0xfb,0x78,0xce,0xcc,0x9c,0xee,0x42,0x4e,0xa4,0xd1,0x30,0x29,0x1a,0xa2,0x37,0xf0,0xd4,0xf9,0x2d,0x23,0xb4,0x62,0x80,0x4b,0x5b,0x68,0xc5,0x25,0x58,0xc0,0x1c,0x99,0x96,0xdb,0xf7,0x27,0xfc,0xca,0xbb,0xee,0xdb,0x96,0x21,0xa4,0x00,0x53,0x5a,0xfa, + 0x04,0xd6,0xef,0x20,0xbe,0x66,0xc8,0x93,0xf7,0x41,0xa9,0xbf,0x90,0xd9,0xb7,0x46,0x75,0xd1,0xc2,0xa3,0x12,0x96,0x39,0x7a,0xcb,0x3e,0xf1,0x74,0xfd,0x0b,0x30,0x0c,0x65,0x4a,0x0c,0x95,0x47,0x8c,0xa0,0x03,0x99,0x16,0x2d,0x7f,0x0f,0x2d,0xc8,0x9e,0xfd,0xc2,0xb2,0x8a,0x30,0xfb,0xab,0xe2,0x85,0x85,0x72,0x95,0xa4,0xb0,0xc4,0xe2,0x65, + 0x04,0xb7,0x29,0x1d,0x14,0x04,0xe0,0xc0,0xc0,0x7d,0xab,0x93,0x72,0x18,0x9f,0x4b,0xd5,0x8d,0x2c,0xea,0xa8,0xd1,0x5e,0xde,0x54,0x4d,0x95,0x14,0x54,0x5b,0xa9,0xee,0x06,0x29,0xc9,0xa6,0x3d,0x5e,0x30,0x87,0x69,0xcc,0x30,0xec,0x27,0x6a,0x41,0x0e,0x64,0x64,0xa2,0x7e,0xea,0xfd,0x9e,0x59,0x9d,0xb1,0x0f,0x05,0x3a,0x4f,0xe4,0xa8,0x29, + 0x04,0x6e,0x28,0x30,0x33,0x05,0xd6,0x42,0xcc,0xb9,0x23,0xb7,0x22,0xea,0x86,0xb2,0xa0,0xbc,0x8e,0x37,0x35,0xec,0xb2,0x6e,0x84,0x9b,0x19,0xc9,0xf7,0x6b,0x2f,0xdb,0xb8,0x18,0x6e,0x80,0xd6,0x4d,0x8c,0xab,0x16,0x4f,0x52,0x38,0xf5,0x31,0x84,0x61,0xbf,0x89,0xd4,0xd9,0x6e,0xe6,0x54,0x4c,0x81,0x6c,0x75,0x66,0x94,0x77,0x74,0xe0,0xf6, + 0x04,0x37,0x5b,0xda,0x93,0xf6,0xaf,0x92,0xfb,0x5f,0x8f,0x4b,0x1b,0x5f,0x05,0x34,0xe3,0xba,0xfa,0xb3,0x4c,0xb7,0xad,0x9f,0xb9,0xd0,0xb7,0x22,0xe4,0xa5,0xc3,0x02,0xa9,0xa0,0x0b,0x9f,0x38,0x7a,0x5a,0x39,0x60,0x97,0xaa,0x21,0x62,0xfc,0x5b,0xbc,0xf4,0xa5,0x26,0x33,0x72,0xf6,0x81,0xc9,0x4d,0xa5,0x1e,0x97,0x99,0x12,0x09,0x90,0xfd, + 0x04,0xd7,0x5b,0x68,0x21,0x6b,0xab,0xe0,0x3a,0xe2,0x57,0xe9,0x4b,0x4e,0x3b,0xf1,0xc5,0x2f,0x44,0xe3,0xdf,0x26,0x6d,0x15,0x24,0xff,0x8c,0x5e,0xa6,0x9d,0xa7,0x31,0x97,0xda,0x4b,0xff,0x9e,0xd1,0xc5,0x3f,0x44,0x91,0x7a,0x67,0xd7,0xb9,0x78,0x59,0x8e,0x89,0xdf,0x35,0x9e,0x3d,0x59,0x13,0xea,0xea,0x24,0xf3,0xae,0x25,0x9a,0xbc,0x44, + 0x04,0x78,0xbc,0xda,0x14,0x0a,0xed,0x23,0xd4,0x30,0xcb,0x23,0xc3,0xdc,0x0d,0x01,0xf4,0x23,0xdb,0x13,0x4e,0xe9,0x4a,0x3a,0x8c,0xb4,0x83,0xf2,0xde,0xac,0x2a,0xc6,0x53,0x11,0x81,0x14,0xf6,0xf3,0x30,0x45,0xd4,0xe9,0xed,0x91,0x07,0x08,0x50,0x07,0xbf,0xbd,0xdf,0x8f,0x58,0xfe,0x7a,0x1a,0x24,0x45,0xd6,0x6a,0x99,0x00,0x45,0x47,0x6e, + 0x04,0xbb,0x79,0xf6,0x18,0x57,0xf7,0x43,0xbf,0xa1,0xb6,0xe7,0x11,0x1c,0xe4,0x09,0x43,0x77,0x25,0x69,0x69,0xe4,0xe1,0x51,0x59,0x12,0x3d,0x95,0x48,0xac,0xc3,0xbe,0x6c,0x1f,0x9d,0x9f,0x88,0x60,0xdc,0xff,0xd3,0xeb,0x36,0xdd,0x6c,0x31,0xff,0x2e,0x72,0x26,0xc2,0x00,0x9c,0x4c,0x94,0xd8,0xd7,0xd2,0xb5,0x68,0x6b,0xf7,0xab,0xd6,0x77, + 0x04,0x93,0x59,0x18,0x27,0xd9,0xe6,0x71,0x3b,0x4e,0x9f,0xae,0xa6,0x2c,0x72,0xb2,0x8d,0xfe,0xfa,0x68,0xe0,0xc0,0x51,0x60,0xb5,0xd6,0xaa,0xe8,0x8f,0xd2,0xe3,0x6c,0x36,0x07,0x3f,0x55,0x45,0xad,0x5a,0xf4,0x10,0xaf,0x26,0xaf,0xff,0x68,0x65,0x4c,0xf7,0x2d,0x45,0xe4,0x93,0x48,0x93,0x11,0x20,0x32,0x47,0x34,0x7a,0x89,0x0f,0x45,0x18, + 0x04,0x31,0xed,0x30,0x81,0xae,0xfe,0x00,0x1e,0xb6,0x40,0x20,0x69,0xee,0x2c,0xcc,0x18,0x62,0x93,0x7b,0x85,0x99,0x51,0x44,0xdb,0xa9,0x50,0x39,0x43,0x58,0x7b,0xf0,0xda,0xda,0x01,0xb8,0xcc,0x4d,0xf3,0x4f,0x5a,0xb3,0xb1,0xa3,0x59,0x61,0x52,0x08,0x94,0x6e,0x5e,0xe3,0x5f,0x98,0xee,0x77,0x5b,0x8c,0xce,0xcd,0x86,0xcc,0xc1,0x65,0x0f, + 0x04,0x7d,0xff,0x66,0xfa,0x98,0x50,0x9f,0xf3,0xe2,0xe5,0x10,0x45,0xf4,0x39,0x05,0x23,0xdc,0xcd,0xa4,0x3a,0x3b,0xc2,0x88,0x5e,0x58,0xc2,0x48,0x09,0x09,0x90,0xee,0xa8,0x54,0xc7,0x6c,0x2b,0x9a,0xde,0xb6,0xbb,0x57,0x18,0x23,0xe0,0x7f,0xd7,0xc6,0x5c,0x86,0x39,0xcf,0x9d,0x90,0x52,0x60,0x06,0x4c,0x8e,0x76,0x75,0xce,0x6d,0x98,0xb4, + 0x04,0x42,0x80,0x50,0x9a,0xab,0x64,0xed,0xfc,0x0b,0x4a,0x29,0x67,0xe4,0xcb,0xce,0x84,0x9c,0xb5,0x44,0xe4,0xa7,0x73,0x13,0xc8,0xe6,0xec,0xe5,0x79,0xfb,0xd7,0x42,0x0a,0x2e,0x89,0xfe,0x5c,0xc1,0x92,0x7d,0x55,0x4e,0x6a,0x3b,0xb1,0x40,0x33,0xea,0x7c,0x92,0x2c,0xd7,0x5c,0xba,0x2c,0x74,0x15,0xfd,0xab,0x52,0xf2,0x0b,0x18,0x60,0xf1, + 0x04,0x4f,0x8d,0xf1,0x45,0x19,0x4e,0x3c,0x4f,0xc3,0xee,0xa2,0x6d,0x43,0xce,0x75,0xb4,0x02,0xd6,0xb1,0x74,0x72,0xdd,0xcb,0xb2,0x54,0xb8,0xa7,0x9b,0x0b,0xf3,0xd9,0xcb,0x2a,0xa2,0x0d,0x82,0x84,0x4c,0xb2,0x66,0x34,0x4e,0x71,0xca,0x78,0xf2,0xad,0x27,0xa7,0x5a,0x09,0xe5,0xbc,0x0f,0xa5,0x7e,0x4e,0xfd,0x9d,0x46,0x5a,0x08,0x88,0xdb, + 0x04,0x95,0x98,0xa5,0x7d,0xd6,0x7e,0xc3,0xe1,0x6b,0x58,0x7a,0x33,0x8a,0xa3,0xa1,0x0a,0x3a,0x39,0x13,0xb4,0x1a,0x3a,0xf3,0x2e,0x3e,0xd3,0xff,0x01,0x35,0x8c,0x6b,0x14,0x12,0x28,0x19,0xed,0xf8,0x07,0x4b,0xbc,0x52,0x1f,0x7d,0x4c,0xdc,0xe8,0x2f,0xef,0x7a,0x51,0x67,0x06,0xaf,0xfb,0xa1,0xd9,0x3d,0x9d,0xea,0x9c,0xca,0xe1,0xa2,0x07, + 0x04,0x91,0x71,0xfe,0xc3,0xca,0x20,0x80,0x6b,0xc0,0x84,0xf1,0x2f,0x07,0x60,0x91,0x1b,0x60,0x99,0x0b,0xd8,0x0e,0x5b,0x2a,0x71,0xca,0x03,0xa0,0x48,0xb2,0x0f,0x83,0x7e,0x63,0x4f,0xd1,0x78,0x63,0x76,0x1b,0x29,0x58,0xd2,0xbe,0x4e,0x14,0x9f,0x8d,0x3d,0x7a,0xbb,0xdc,0x18,0xbe,0x03,0xf4,0x51,0xab,0x6c,0x17,0xfa,0x0a,0x1f,0x83,0x30, + 0x04,0x77,0x7c,0x89,0x30,0xb6,0xe1,0xd2,0x71,0x10,0x0f,0xe6,0x8c,0xe9,0x3f,0x16,0x3f,0xa3,0x76,0x12,0xc5,0xff,0xf6,0x7f,0x4a,0x62,0xfc,0x3b,0xaf,0xaf,0x3d,0x17,0xa9,0xed,0x73,0xd8,0x6f,0x60,0xa5,0x1b,0x5e,0xd9,0x13,0x53,0xa3,0xb0,0x54,0xed,0xc0,0xaa,0x92,0xc9,0xeb,0xcb,0xd0,0xb7,0x5d,0x18,0x8f,0xdc,0x88,0x27,0x91,0xd6,0x8d, + 0x04,0xea,0xbc,0x24,0x8f,0x62,0x6e,0x0a,0x63,0xe1,0xeb,0x81,0xc4,0x3d,0x46,0x1a,0x39,0xa1,0xdb,0xa8,0x81,0xeb,0x6e,0xe2,0x15,0x2b,0x07,0xc3,0x2d,0x71,0xbc,0xf4,0x70,0x06,0x03,0xca,0xa8,0xb9,0xd3,0x3d,0xb1,0x3a,0xf4,0x4c,0x6e,0xfb,0xec,0x8a,0x19,0x8e,0xd6,0x12,0x4a,0xc9,0xeb,0x17,0xea,0xaf,0xd2,0x82,0x4a,0x54,0x5e,0xc0,0x00, + 0x04,0x9f,0x7a,0x13,0xad,0xa1,0x58,0xa5,0x5f,0x9d,0xdf,0x1a,0x45,0xf0,0x44,0xf0,0x73,0xd9,0xb8,0x00,0x30,0xef,0xdc,0xfc,0x9f,0x9f,0x58,0x41,0x8f,0xbc,0xea,0xf0,0x01,0xf8,0xad,0xa0,0x17,0x50,0x90,0xf8,0x0d,0x47,0x22,0x7d,0x67,0x13,0xb6,0x74,0x0f,0x9a,0x00,0x91,0xd8,0x8a,0x83,0x7d,0x0a,0x1c,0xd7,0x7b,0x58,0xa8,0xf2,0x8d,0x73, + 0x04,0x11,0xc4,0xf3,0xe4,0x61,0xcd,0x01,0x9b,0x5c,0x06,0xea,0x0c,0xea,0x4c,0x40,0x90,0xc3,0xcc,0x3e,0x3c,0x5d,0x9f,0x3c,0x6d,0x65,0xb4,0x36,0x82,0x6d,0xa9,0xb4,0xdb,0xbb,0xeb,0x7a,0x77,0xe4,0xcb,0xfd,0xa2,0x07,0x09,0x7c,0x43,0x42,0x37,0x05,0xf7,0x2c,0x80,0x47,0x6d,0xa3,0xda,0xc4,0x0a,0x48,0x3b,0x0a,0xb0,0xf2,0xea,0xd1,0xcb, + 0x04,0xe2,0xe1,0x86,0x82,0xd5,0x31,0x23,0xaa,0x01,0xa6,0xc5,0xd0,0x0b,0x0c,0x62,0x3d,0x67,0x1b,0x46,0x2e,0xa8,0x0b,0xdd,0xd6,0x52,0x27,0xfd,0x51,0x05,0x98,0x8a,0xa4,0x16,0x19,0x07,0xb3,0xfd,0x25,0x04,0x4a,0x94,0x9e,0xa4,0x1c,0x8e,0x2e,0xa8,0x45,0x9d,0xc6,0xf1,0x65,0x48,0x56,0xb8,0xb6,0x1b,0x31,0x54,0x3b,0xb1,0xb4,0x5b,0xdb, + 0x04,0x90,0xf8,0xd4,0xca,0x73,0xde,0x08,0xa6,0x56,0x4a,0xaf,0x00,0x52,0x47,0xb6,0xf0,0xff,0xe9,0x78,0x50,0x4d,0xce,0x52,0x60,0x5f,0x46,0xb7,0xc3,0xe5,0x61,0x97,0xda,0xfa,0xdb,0xe5,0x28,0xeb,0x70,0xd9,0xee,0x7e,0xa0,0xe7,0x07,0x02,0xdb,0x54,0xf7,0x21,0x51,0x4c,0x7b,0x86,0x04,0xac,0x2c,0xb2,0x14,0xf1,0xde,0xcb,0x7e,0x38,0x3d, + 0x04,0x82,0x4c,0x19,0x5c,0x73,0xcf,0xfd,0xf0,0x38,0xd1,0x01,0xbc,0xe1,0x68,0x7b,0x5c,0x3b,0x61,0x46,0xf3,0x95,0xc8,0x85,0x97,0x6f,0x77,0x53,0xb2,0x37,0x6b,0x94,0x8e,0x3c,0xde,0xfa,0x6f,0xc3,0x47,0xd1,0x3e,0x4d,0xcb,0xc6,0x3a,0x0b,0x03,0xa1,0x65,0x18,0x0c,0xd2,0xbe,0x14,0x31,0xa0,0xcf,0x74,0xce,0x1e,0xa2,0x50,0x82,0xd2,0xbc, + 0x04,0x27,0x88,0xa5,0x2f,0x07,0x8e,0xb3,0xf2,0x02,0xc4,0xfa,0x73,0xe0,0xd3,0x38,0x6f,0xaf,0x3d,0xf6,0xbe,0x85,0x60,0x03,0x63,0x6f,0x59,0x99,0x22,0xd4,0xf5,0x26,0x8f,0x30,0xb4,0xf2,0x07,0xc9,0x19,0xbb,0xdf,0x5e,0x67,0xa8,0xbe,0x42,0x65,0xa8,0x17,0x47,0x54,0xb3,0xab,0xa8,0xf1,0x6e,0x57,0x5b,0x77,0xff,0x4d,0x5a,0x7e,0xb6,0x4f, + 0x04,0xd5,0x33,0xb7,0x89,0xa4,0xaf,0x89,0x0f,0xa7,0xa8,0x2a,0x1f,0xae,0x58,0xc4,0x04,0xf9,0xa6,0x2a,0x50,0xb4,0x9a,0xda,0xfa,0xb3,0x49,0xc5,0x13,0xb4,0x15,0x08,0x74,0x01,0xb4,0x17,0x1b,0x80,0x3e,0x76,0xb3,0x4a,0x98,0x61,0xe1,0x0f,0x7b,0xc2,0x89,0xa0,0x66,0xfd,0x01,0xbd,0x29,0xf8,0x4c,0x98,0x7a,0x10,0xa5,0xfb,0x18,0xc2,0xd4, + 0x04,0x3a,0x31,0x50,0x79,0x8c,0x8a,0xf6,0x9d,0x1e,0x6e,0x98,0x1f,0x3a,0x45,0x40,0x2b,0xa1,0xd7,0x32,0xf4,0xbe,0x83,0x30,0xc5,0x16,0x4f,0x49,0xe1,0x0e,0xc5,0x55,0xb4,0x22,0x1b,0xd8,0x42,0xbc,0x5e,0x4d,0x97,0xef,0xf3,0x71,0x65,0xf6,0x0e,0x39,0x98,0xa4,0x24,0xd7,0x2a,0x45,0x0c,0xf9,0x5e,0xa4,0x77,0xc7,0x82,0x87,0xd0,0x34,0x3a, + 0x04,0x3b,0x37,0xdf,0x5f,0xb3,0x47,0xc6,0x9a,0x0f,0x17,0xd8,0x5c,0x0c,0x7c,0xa8,0x37,0x36,0x88,0x3a,0x82,0x5e,0x13,0x14,0x3d,0x0f,0xcf,0xc8,0x10,0x1e,0x85,0x1e,0x80,0x0d,0xe3,0xc0,0x90,0xb6,0xca,0x21,0xba,0x54,0x35,0x17,0x33,0x0c,0x04,0xb1,0x2f,0x94,0x8c,0x6b,0xad,0xf1,0x4a,0x63,0xab,0xff,0xdf,0x4e,0xf8,0xc7,0x53,0x70,0x26, + 0x04,0xfe,0xb5,0x16,0x3b,0x0e,0xce,0x30,0xff,0x3e,0x03,0xc7,0xd5,0x5c,0x43,0x80,0xfa,0x2f,0xa8,0x1e,0xe2,0xc0,0x35,0x49,0x42,0xff,0x6f,0x08,0xc9,0x9d,0x0c,0xd8,0x2c,0xe8,0x7d,0xe0,0x5e,0xe1,0xbd,0xa0,0x89,0xd3,0xe4,0xe2,0x48,0xfa,0x0f,0x72,0x11,0x02,0xac,0xff,0xfd,0xf5,0x0e,0x65,0x4b,0xe2,0x81,0x43,0x39,0x99,0xdf,0x89,0x7e, + 0x04,0x23,0x8c,0xed,0x00,0x1c,0xf2,0x2b,0x88,0x53,0xe0,0x2e,0xdc,0x89,0xcb,0xec,0xa5,0x05,0x0b,0xa7,0xe0,0x42,0xa7,0xa7,0x7f,0x93,0x82,0xcd,0x41,0x49,0x22,0x89,0x76,0x40,0x68,0x3d,0x30,0x94,0x64,0x38,0x40,0xf2,0x95,0x89,0x0a,0xa4,0xc1,0x8a,0xa3,0x9b,0x41,0xd7,0x7d,0xd0,0xfb,0x3b,0xb2,0x70,0x0e,0x4f,0x9e,0xc2,0x84,0xff,0xc2, + 0x04,0x96,0x1c,0xf6,0x48,0x17,0xc0,0x6c,0x0e,0x51,0xb3,0xc2,0x73,0x6c,0x92,0x2f,0xde,0x18,0xbd,0x8c,0x49,0x06,0xfc,0xd7,0xf5,0xef,0x66,0xc4,0x67,0x85,0x08,0xf3,0x5e,0xd2,0xc5,0xd1,0x81,0x68,0xcf,0xbe,0x70,0xf2,0xf1,0x23,0xbd,0x74,0x19,0x23,0x2b,0xb9,0x2d,0xd6,0x91,0x13,0xe2,0x94,0x10,0x61,0x88,0x94,0x81,0xc5,0xa0,0x27,0xbf, + 0x04,0x13,0x68,0x1e,0xae,0x16,0x8c,0xd4,0xea,0x7c,0xf2,0xe2,0xa4,0x5d,0x05,0x27,0x42,0xd1,0x0a,0x9f,0x64,0xe7,0x96,0x86,0x7d,0xbd,0xcb,0x82,0x9f,0xe0,0xb1,0x02,0x88,0x16,0x52,0x87,0x60,0xd1,0x77,0x37,0x6c,0x09,0xdf,0x79,0xde,0x39,0x55,0x7c,0x32,0x9c,0xc1,0x75,0x35,0x17,0xac,0xff,0xe8,0xfa,0x2e,0xc2,0x98,0x02,0x6b,0x83,0x84, + 0x04,0x5a,0xa7,0xab,0xfd,0xb6,0xb4,0x08,0x6d,0x54,0x33,0x25,0xe5,0xd7,0x9c,0x6e,0x95,0xce,0x42,0xf8,0x66,0xd2,0xbb,0x84,0x90,0x96,0x33,0xa0,0x4b,0xb1,0xaa,0x31,0xc2,0x91,0xc8,0x00,0x88,0x79,0x49,0x05,0xe1,0xda,0x33,0x33,0x6d,0x87,0x4e,0x2f,0x91,0xcc,0xf4,0x5c,0xc5,0x91,0x85,0xbe,0xde,0x5d,0xd6,0xf3,0xf7,0xac,0xaa,0xe1,0x8b, + 0x04,0x00,0x27,0x77,0x91,0xb3,0x05,0xa4,0x5b,0x2b,0x39,0x59,0x0b,0x2f,0x05,0xd3,0x39,0x2a,0x6c,0x81,0x82,0xce,0xf4,0xeb,0x54,0x01,0x20,0xe0,0xf5,0xc2,0x06,0xc3,0xe4,0x64,0x10,0x82,0x33,0xfb,0x0b,0x8c,0x3a,0xc8,0x92,0xd7,0x9e,0xf8,0xe0,0xfb,0xf9,0x2e,0xd1,0x33,0xad,0xdb,0x45,0x54,0x27,0x01,0x32,0x58,0x4d,0xc5,0x2e,0xef,0x41, + 0x04,0x6e,0xfa,0x09,0x2b,0x68,0xde,0x94,0x60,0xf0,0xbc,0xc9,0x19,0x00,0x5a,0x5f,0x6e,0x80,0xe1,0x9d,0xe9,0x89,0x68,0xbe,0x3c,0xd2,0xc7,0x70,0xa9,0x94,0x9b,0xfb,0x1a,0xc7,0x5e,0x6e,0x50,0x87,0xd6,0x55,0x0d,0x5f,0x9b,0xeb,0x1e,0x79,0xe5,0x02,0x93,0x07,0xbc,0x25,0x52,0x35,0xe2,0xd5,0xdc,0x99,0x24,0x1a,0xc3,0xab,0x88,0x6c,0x49, + 0x04,0x72,0xd4,0xa1,0x9c,0x4f,0x9d,0x2c,0xf5,0x84,0x8e,0xa4,0x04,0x45,0xb7,0x0d,0x46,0x96,0xb5,0xf0,0x2d,0x63,0x2c,0x0c,0x65,0x4c,0xc7,0xd7,0xee,0xb0,0xc6,0xd0,0x58,0xe8,0xc4,0xcd,0x99,0x43,0xe4,0x59,0x17,0x4c,0x7a,0xc0,0x1f,0xa7,0x42,0x19,0x8e,0x47,0xe6,0xc1,0x9a,0x6b,0xdb,0x0c,0x4f,0x6c,0x23,0x78,0x31,0xc1,0xb3,0xf9,0x42, + 0x04,0x2a,0x8e,0xa2,0xf5,0x0d,0xcc,0xed,0x0c,0x21,0x75,0x75,0xbd,0xfa,0x7c,0xd4,0x7d,0x1c,0x6f,0x10,0x00,0x41,0xec,0x0e,0x35,0x51,0x27,0x94,0xc1,0xbe,0x7e,0x74,0x02,0x58,0xf8,0xc1,0x71,0x22,0xed,0x30,0x3f,0xda,0x71,0x43,0xeb,0x58,0xbe,0xde,0x70,0x29,0x5b,0x65,0x32,0x66,0x01,0x3b,0x0b,0x0e,0xbd,0x3f,0x05,0x31,0x37,0xf6,0xec, + 0x04,0x88,0xde,0x68,0x9c,0xe9,0xaf,0x1e,0x94,0xbe,0x6a,0x20,0x89,0xc8,0xa8,0xb1,0x25,0x3f,0xfd,0xbb,0x6c,0x8e,0x9c,0x86,0x24,0x9b,0xa2,0x20,0x00,0x1a,0x4a,0xd3,0xb8,0x0c,0x49,0x98,0xe5,0x48,0x42,0xf4,0x13,0xb9,0xed,0xb1,0x82,0x5a,0xcb,0xb6,0x33,0x5e,0x81,0xe4,0xd1,0x84,0xb2,0xb0,0x1c,0x8b,0xeb,0xdc,0x85,0xd1,0xf2,0x89,0x46, + 0x04,0xfe,0xa2,0xd3,0x1f,0x70,0xf9,0x0d,0x5f,0xb3,0xe0,0x0e,0x18,0x6a,0xc4,0x2a,0xb3,0xc1,0x61,0x5c,0xee,0x71,0x4e,0x0b,0x4e,0x11,0x31,0xb3,0xd4,0xd8,0x22,0x5b,0xf7,0xb0,0x37,0xa1,0x8d,0xf2,0xac,0x15,0x34,0x3f,0x30,0xf7,0x40,0x67,0xdd,0xf2,0x9e,0x81,0x7d,0x5f,0x77,0xf8,0xdc,0xe0,0x57,0x14,0xda,0x59,0xc0,0x94,0xf0,0xcd,0xa9, + 0x04,0x72,0x58,0x91,0x1e,0x3d,0x42,0x33,0x49,0x16,0x64,0x79,0xdb,0xe0,0xb8,0x34,0x1a,0xf7,0xfb,0xd0,0x3d,0x0a,0x7e,0x10,0xed,0xcc,0xb3,0x6b,0x6c,0xee,0xa5,0xa3,0xdb,0x17,0xac,0x2b,0x89,0x92,0x79,0x11,0x28,0xfa,0x3b,0x96,0xdc,0x2f,0xbd,0x4c,0xa3,0xbf,0xa7,0x82,0xef,0x28,0x32,0xfc,0x66,0x56,0x94,0x3d,0xb1,0x8e,0x73,0x46,0xb0, + 0x04,0x4f,0x28,0x46,0x1d,0xea,0x64,0x47,0x4d,0x6b,0xb3,0x4d,0x14,0x99,0xc9,0x7d,0x37,0xb9,0xe9,0x56,0x33,0xdf,0x1c,0xee,0xea,0xac,0xd4,0x50,0x16,0xc9,0x8b,0x39,0x14,0xc8,0x81,0x88,0x10,0xb8,0xcc,0x06,0xdd,0xb4,0x0e,0x8a,0x12,0x61,0xc5,0x28,0xfa,0xa5,0x89,0x45,0x5d,0x5a,0x6d,0xf9,0x3b,0x77,0xbc,0x5e,0x0e,0x49,0x3c,0x74,0x70, + 0x04,0x74,0xf2,0xa8,0x14,0xfb,0x5d,0x8e,0xca,0x91,0xa6,0x9b,0x5e,0x60,0x71,0x27,0x32,0xb3,0x93,0x7d,0xe3,0x28,0x29,0xbe,0x97,0x4e,0xd7,0xb6,0x8c,0x5c,0x2f,0x5d,0x66,0xef,0xf0,0xf0,0x7c,0x56,0xf9,0x87,0xa6,0x57,0xf4,0x21,0x96,0x20,0x5f,0x58,0x8c,0x0f,0x1d,0x96,0xfd,0x8a,0x63,0xa5,0xf2,0x38,0xb4,0x8f,0x47,0x87,0x88,0xfe,0x3b, + 0x04,0x19,0x5b,0x51,0xa7,0xcc,0x4a,0x21,0xb8,0x27,0x4a,0x70,0xa9,0x0d,0xe7,0x79,0x81,0x4c,0x3c,0x8c,0xa3,0x58,0x32,0x82,0x08,0xc0,0x9a,0x29,0xf3,0x36,0xb8,0x2d,0x6a,0xb2,0x41,0x6b,0x7c,0x92,0xff,0xfd,0xc2,0x9c,0x3b,0x12,0x82,0xdd,0x2a,0x77,0xa4,0xd0,0x4d,0xf7,0xf7,0x45,0x20,0x47,0x39,0x3d,0x84,0x99,0x89,0xc5,0xce,0xe9,0xad, + 0x04,0x62,0x2f,0xc7,0x47,0x32,0x03,0x4b,0xec,0x2d,0xdf,0x3b,0xc1,0x6d,0x34,0xb3,0xd1,0xf7,0xa3,0x27,0xdd,0x2a,0x8c,0x19,0xba,0xb4,0xbb,0x4f,0xe3,0xa2,0x4b,0x58,0xaa,0x73,0x6b,0x2f,0x2f,0xae,0x76,0xf4,0xdf,0xae,0xcc,0x90,0x96,0x33,0x3b,0x01,0x32,0x8d,0x51,0xeb,0x3f,0xda,0x9c,0x92,0x27,0xe9,0x0d,0x0b,0x44,0x99,0x83,0xc4,0xf0, + 0x04,0x1f,0x7f,0x85,0xca,0xf2,0xd7,0x55,0x0e,0x7a,0xf9,0xb6,0x50,0x23,0xeb,0xb4,0xdc,0xe3,0x45,0x03,0x11,0x69,0x23,0x09,0xdb,0x26,0x99,0x69,0xb8,0x34,0xb6,0x11,0xc7,0x08,0x27,0xf4,0x5b,0x78,0x02,0x0e,0xcb,0xba,0xf4,0x84,0xfd,0xd5,0xbf,0xaa,0xe6,0x87,0x0f,0x11,0x84,0xc2,0x15,0x81,0xba,0xf6,0xef,0x82,0xbd,0x7b,0x53,0x0f,0x93, + 0x04,0x49,0xc1,0x97,0xdc,0x80,0xad,0x1d,0xa4,0x7a,0x43,0x42,0xb9,0x38,0x93,0xe8,0xe1,0xfb,0x0b,0xb9,0x4f,0xc3,0x3a,0x83,0xe7,0x83,0xc0,0x0b,0x24,0xc7,0x81,0x37,0x7a,0xef,0xc2,0x0d,0xa9,0x2b,0xac,0x76,0x29,0x51,0xf7,0x24,0x74,0xbe,0xcc,0x73,0x4d,0x4c,0xc2,0x2b,0xa8,0x1b,0x89,0x5e,0x28,0x2f,0xda,0xc4,0xdf,0x7a,0xf0,0xf3,0x7d, + 0x04,0xd8,0xcb,0x68,0x51,0x7b,0x61,0x6a,0x56,0x40,0x0a,0xa3,0x86,0x86,0x35,0xe5,0x4b,0x6f,0x69,0x95,0x98,0xa2,0xf6,0x16,0x77,0x57,0x65,0x49,0x80,0xba,0xf6,0xac,0xbe,0x7e,0xc8,0xcf,0x44,0x9c,0x84,0x9a,0xa0,0x34,0x61,0xa3,0x0e,0xfa,0xda,0x41,0x45,0x3c,0x57,0xc6,0xe6,0xfb,0xc9,0x3b,0xbc,0x6f,0xa4,0x9a,0xda,0x6d,0xc0,0x55,0x5c, + 0x04,0x03,0x07,0x13,0xfb,0x63,0xf2,0xaa,0x6f,0xe2,0xca,0xdf,0x1b,0x20,0xef,0xc2,0x59,0xc7,0x74,0x45,0xda,0xfa,0x87,0xda,0xc3,0x98,0xb8,0x40,0x65,0xca,0x34,0x7d,0xf3,0xb2,0x27,0x81,0x8d,0xe1,0xa3,0x9b,0x58,0x9c,0xb0,0x71,0xd8,0x3e,0x53,0x17,0xcc,0xcd,0xc2,0x33,0x8e,0x51,0xe3,0x12,0xfe,0x31,0xd8,0xdc,0x34,0xa4,0x80,0x17,0x50, + 0x04,0xba,0xbb,0x36,0x77,0xb0,0x95,0x58,0x02,0xd8,0xe9,0x29,0xa4,0x13,0x55,0x64,0x0e,0xaf,0x1e,0xa1,0x35,0x3f,0x8a,0x77,0x13,0x31,0xc4,0x94,0x6e,0x34,0x80,0xaf,0xa7,0x25,0x2f,0x19,0x6c,0x87,0xed,0x3d,0x2a,0x59,0xd3,0xb1,0xb5,0x59,0x13,0x7f,0xed,0x00,0x13,0xfe,0xce,0xfc,0x19,0xfb,0x5a,0x92,0x68,0x2b,0x9b,0xca,0x51,0xb9,0x50, + 0x04,0x1a,0xab,0x20,0x18,0x79,0x34,0x71,0x11,0x1a,0x8a,0x0e,0x9b,0x14,0x3f,0xde,0x02,0xfc,0x95,0x92,0x07,0x96,0xd3,0xa6,0x3d,0xe3,0x29,0xb4,0x24,0x39,0x6f,0xba,0x60,0xbb,0xe4,0x13,0x07,0x05,0x17,0x47,0x92,0x44,0x1b,0x31,0x8d,0x3a,0xa3,0x1d,0xfe,0x85,0x77,0x82,0x1e,0x9b,0x44,0x6e,0xc5,0x73,0xd2,0x72,0xe0,0x36,0xc4,0xeb,0xe9, + 0x04,0x8c,0xb0,0xb9,0x09,0x49,0x9c,0x83,0xea,0x80,0x6c,0xd8,0x85,0xb1,0xdd,0x46,0x7a,0x01,0x19,0xf0,0x6a,0x88,0xa0,0x27,0x6e,0xb0,0xcf,0xda,0x27,0x45,0x35,0xa8,0xff,0x47,0xb5,0x42,0x88,0x33,0xbc,0x3f,0x2c,0x8b,0xf9,0xd9,0x04,0x11,0x58,0xcf,0x33,0x71,0x8a,0x69,0x96,0x1c,0xd0,0x17,0x29,0xbc,0x00,0x11,0xd1,0xe5,0x86,0xab,0x75, + 0x04,0x8f,0x03,0xcf,0x1a,0x42,0x27,0x2b,0xb1,0x53,0x27,0x23,0x09,0x3f,0x72,0xe6,0xfe,0xea,0xc8,0x5e,0x17,0x00,0xe9,0xfb,0xe9,0xa6,0xa2,0xdd,0x64,0x2d,0x74,0xbf,0x5d,0x3b,0x89,0xa7,0x18,0x9d,0xad,0x8c,0xf7,0x5f,0xc2,0x2f,0x6f,0x15,0x8a,0xa2,0x7f,0x9c,0x2c,0xa0,0x0d,0xac,0xa7,0x85,0xbe,0x33,0x58,0xf2,0xbd,0xa3,0x86,0x2c,0xa0, + 0x04,0x44,0xde,0x3b,0x9c,0x7a,0x57,0xa8,0xc9,0xe8,0x20,0x95,0x27,0x53,0x42,0x1e,0x7d,0x98,0x7b,0xb3,0xd7,0x9f,0x71,0xf0,0x13,0x80,0x5c,0x89,0x7e,0x01,0x8f,0x8a,0xce,0xa2,0x46,0x07,0x58,0xc8,0xf9,0x8d,0x3f,0xdc,0xe1,0x21,0xa9,0x43,0x65,0x9e,0x37,0x2c,0x32,0x6f,0xff,0x2e,0x5f,0xc2,0xae,0x7f,0xa3,0xf7,0x9d,0xaa,0xe1,0x3c,0x12, + 0x04,0x6f,0xb8,0xb2,0xb4,0x8e,0x33,0x03,0x12,0x68,0xad,0x6a,0x51,0x74,0x84,0xdc,0x88,0x39,0xea,0x90,0xf6,0x66,0x9e,0xa0,0xc7,0xac,0x32,0x33,0xe2,0xac,0x31,0x39,0x4a,0x0a,0xc8,0xbb,0xe7,0xf7,0x3c,0x2f,0xf4,0xdf,0x99,0x78,0x72,0x7a,0xc1,0xdf,0xc2,0xfd,0x58,0x64,0x7d,0x20,0xf3,0x1f,0x99,0x10,0x53,0x16,0xb6,0x46,0x71,0xf2,0x04, + 0x04,0xbe,0xa7,0x11,0x22,0xa0,0x48,0x69,0x3e,0x90,0x5f,0xf6,0x02,0xb3,0xcf,0x9d,0xd1,0x8a,0xf6,0x9b,0x9f,0xc9,0xd8,0x43,0x1d,0x2b,0x1d,0xd2,0x6b,0x94,0x2c,0x95,0xe6,0xf4,0x3c,0x7b,0x8b,0x95,0xeb,0x62,0x08,0x2c,0x12,0xdb,0x9d,0xbd,0xa7,0xfe,0x38,0xe4,0x5c,0xbe,0x4a,0x48,0x86,0x90,0x7f,0xb8,0x1b,0xdb,0x0c,0x5e,0xa9,0x24,0x6c, + 0x04,0xda,0x91,0x8c,0x73,0x1b,0xa0,0x6a,0x20,0xcb,0x94,0xef,0x33,0xb7,0x78,0xe9,0x81,0xa4,0x04,0xa3,0x05,0xf1,0x94,0x1f,0xe3,0x36,0x66,0xb4,0x5b,0x03,0x35,0x31,0x56,0xe2,0xbb,0x26,0x94,0xf5,0x75,0xb4,0x51,0x83,0xbe,0x78,0xe5,0xc9,0xb5,0x21,0x0b,0xf3,0xbf,0x48,0x8f,0xd4,0xc8,0x29,0x45,0x16,0xd8,0x95,0x72,0xca,0x4f,0x53,0x91, + 0x04,0x30,0x07,0xe9,0x2c,0x39,0x37,0xda,0xde,0x79,0x64,0xdf,0xa3,0x5b,0x0e,0xff,0x03,0x1f,0x7e,0xb0,0x2a,0xed,0x0a,0x03,0x14,0x41,0x11,0x06,0xcd,0xeb,0x70,0xfe,0x3d,0x5a,0x75,0x46,0xfc,0x05,0x52,0x99,0x7b,0x20,0xe3,0xd6,0xf4,0x13,0xe7,0x5e,0x2c,0xb6,0x6e,0x11,0x63,0x22,0x69,0x71,0x14,0xb7,0x9b,0xac,0x73,0x4b,0xfc,0x4d,0xc5, + 0x04,0x60,0xe7,0x34,0xef,0x56,0x24,0xd3,0xcb,0xf0,0xdd,0xd3,0x75,0x01,0x1b,0xd6,0x63,0xd6,0xd6,0xae,0xbc,0x64,0x4e,0xb5,0x99,0xfd,0xf9,0x8d,0xbd,0xcd,0x18,0xce,0x9b,0xd2,0xd9,0x0b,0x3a,0xc3,0x1f,0x13,0x9a,0xf8,0x32,0xcc,0xcf,0x6c,0xcb,0xbb,0x2c,0x6e,0xa1,0x1f,0xa9,0x73,0x70,0xdc,0x99,0x06,0xda,0x47,0x4d,0x7d,0x8a,0x75,0x67, + 0x04,0x85,0xa9,0x00,0xe9,0x78,0x58,0xf6,0x93,0xc0,0xb7,0xdf,0xa2,0x61,0xe3,0x80,0xda,0xd6,0xea,0x04,0x6d,0x1f,0x65,0xdd,0xee,0xed,0xd5,0xf7,0xd8,0xaf,0x0b,0xa3,0x37,0x69,0x74,0x4d,0x15,0xad,0xd4,0xf6,0xc0,0xbc,0x3b,0x0d,0xa2,0xae,0xc9,0x3b,0x34,0xcb,0x8c,0x65,0xf9,0x34,0x0d,0xdf,0x74,0xe7,0xb0,0x00,0x9e,0xee,0xcc,0xce,0x3c, + 0x04,0x38,0x06,0x6f,0x75,0xd8,0x8e,0xfc,0x4c,0x93,0xde,0x36,0xf4,0x9e,0x03,0x7b,0x23,0x4c,0xc1,0x8b,0x1d,0xe5,0x60,0x87,0x50,0xa6,0x2c,0xab,0x03,0x45,0x40,0x10,0x46,0xa3,0xe8,0x4b,0xed,0x8c,0xfc,0xb8,0x19,0xef,0x4d,0x55,0x04,0x44,0xf2,0xce,0x4b,0x65,0x17,0x66,0xb6,0x9e,0x2e,0x29,0x01,0xf8,0x88,0x36,0xff,0x90,0x03,0x4f,0xed, + 0x04,0x98,0xf6,0x81,0x77,0xdc,0x95,0xc1,0xb4,0xcb,0xfa,0x52,0x45,0x48,0x8c,0xa5,0x23,0xa7,0xd5,0x62,0x94,0x70,0xd0,0x35,0xd6,0x21,0xa4,0x43,0xc7,0x2f,0x39,0xaa,0xbf,0xa3,0x3d,0x29,0x54,0x6f,0xa1,0xc6,0x48,0xf2,0xc7,0xd5,0xcc,0xf7,0x0c,0xf1,0xce,0x4a,0xb7,0x9b,0x5d,0xb1,0xac,0x05,0x9d,0xbe,0xcd,0x06,0x8d,0xbd,0xff,0x1b,0x89, + 0x04,0x5c,0x2b,0xbf,0xa2,0x3c,0x9b,0x9a,0xd0,0x7f,0x03,0x8a,0xa8,0x9b,0x49,0x30,0xbf,0x26,0x7d,0x94,0x01,0xe4,0x25,0x5d,0xe9,0xe8,0xda,0x0a,0x50,0x78,0xec,0x82,0x77,0xe3,0xe8,0x82,0xa3,0x1d,0x5e,0x6a,0x37,0x9e,0x07,0x93,0x98,0x3c,0xcd,0xed,0x39,0xb9,0x5c,0x43,0x53,0xab,0x2f,0xf0,0x1e,0xa5,0x36,0x9b,0xa4,0x7b,0x0c,0x31,0x91, + 0x04,0x2e,0xa7,0x13,0x34,0x32,0x33,0x9c,0x69,0xd2,0x7f,0x9b,0x26,0x72,0x81,0xbd,0x2d,0xdd,0x5f,0x19,0xd6,0x33,0x8d,0x40,0x0a,0x05,0xcd,0x36,0x47,0xb1,0x57,0xa3,0x85,0x35,0x47,0x80,0x82,0x98,0x44,0x8e,0xdb,0x5e,0x70,0x1a,0xde,0x84,0xcd,0x5f,0xb1,0xac,0x95,0x67,0xba,0x5e,0x8f,0xb6,0x8a,0x6b,0x93,0x3e,0xc4,0xb5,0xcc,0x84,0xcc, + 0x04,0x2e,0xa7,0x13,0x34,0x32,0x33,0x9c,0x69,0xd2,0x7f,0x9b,0x26,0x72,0x81,0xbd,0x2d,0xdd,0x5f,0x19,0xd6,0x33,0x8d,0x40,0x0a,0x05,0xcd,0x36,0x47,0xb1,0x57,0xa3,0x85,0xca,0xb8,0x7f,0x7d,0x67,0xbb,0x71,0x24,0xa1,0x8f,0xe5,0x21,0x7b,0x32,0xa0,0x4e,0x53,0x6a,0x98,0x45,0xa1,0x70,0x49,0x75,0x94,0x6c,0xc1,0x3a,0x4a,0x33,0x77,0x63, + 0x04,0x8a,0xa2,0xc6,0x4f,0xa9,0xc6,0x43,0x75,0x63,0xab,0xfb,0xcb,0xd0,0x0b,0x20,0x48,0xd4,0x8c,0x18,0xc1,0x52,0xa2,0xa6,0xf4,0x90,0x36,0xde,0x76,0x47,0xeb,0xe8,0x2e,0x1c,0xe6,0x43,0x87,0x99,0x5c,0x68,0xa0,0x60,0xfa,0x3b,0xc0,0x39,0x9b,0x05,0xcc,0x06,0xee,0xc7,0xd5,0x98,0xf7,0x50,0x41,0xa4,0x91,0x7e,0x69,0x2b,0x7f,0x51,0xff, + 0x04,0x39,0x14,0x27,0xff,0x7e,0xe7,0x80,0x13,0xc1,0x4a,0xec,0x7d,0x96,0xa8,0xa0,0x62,0x20,0x92,0x98,0xa7,0x83,0x83,0x5e,0x94,0xfd,0x65,0x49,0xd5,0x02,0xff,0xf7,0x1f,0xdd,0x66,0x24,0xec,0x34,0x3a,0xd9,0xfc,0xf4,0xd9,0x87,0x21,0x81,0xe5,0x9f,0x84,0x2f,0x9b,0xa4,0xcc,0xca,0xe0,0x9a,0x6c,0x09,0x72,0xfb,0x6a,0xc6,0xb4,0xc6,0xbd, + 0x04,0xe7,0x62,0xb8,0xa2,0x19,0xb4,0xf1,0x80,0x21,0x9c,0xc7,0xa9,0x05,0x92,0x45,0xe4,0x96,0x1b,0xd1,0x91,0xc0,0x38,0x99,0x78,0x9c,0x7a,0x34,0xb8,0x9e,0x8c,0x13,0x8e,0xc1,0x53,0x3e,0xf0,0x41,0x9b,0xb7,0x37,0x6e,0x0b,0xfd,0xe9,0x31,0x9d,0x10,0xa0,0x69,0x68,0x79,0x1d,0x9e,0xa0,0xee,0xd9,0xc1,0xce,0x63,0x45,0xae,0xd9,0x75,0x9e, + 0x04,0x9a,0xed,0xb0,0xd2,0x81,0xdb,0x16,0x4e,0x13,0x00,0x00,0xc5,0x69,0x7f,0xae,0x0f,0x30,0x5e,0xf8,0x48,0xbe,0x6f,0xff,0xb4,0x3a,0xc5,0x93,0xfb,0xb9,0x50,0xe9,0x52,0xfa,0x6f,0x63,0x33,0x59,0xbd,0xcd,0x82,0xb5,0x6b,0x0b,0x9f,0x96,0x5b,0x03,0x77,0x89,0xd4,0x6b,0x9a,0x81,0x41,0xb7,0x91,0xb2,0xae,0xfa,0x71,0x3f,0x96,0xc1,0x75, + 0x04,0x8a,0xd4,0x45,0xdb,0x62,0x81,0x62,0x60,0xe4,0xe6,0x87,0xfd,0x18,0x84,0xe4,0x8b,0x9f,0xc0,0x63,0x6d,0x03,0x15,0x47,0xd6,0x33,0x15,0xe7,0x92,0xe1,0x9b,0xfa,0xee,0x1d,0xe6,0x4f,0x99,0xd5,0xf1,0xcd,0x8b,0x6e,0xc9,0xcb,0x0f,0x78,0x7a,0x65,0x4a,0xe8,0x69,0x93,0xba,0x3d,0xb1,0x00,0x8e,0xf4,0x3c,0xff,0x06,0x84,0xcb,0x22,0xbd, + 0x04,0x1f,0x57,0x99,0xc9,0x5b,0xe8,0x90,0x63,0xb2,0x4f,0x26,0xe4,0x0c,0xb9,0x28,0xc1,0xa8,0x68,0xa7,0x6f,0xb0,0x09,0x46,0x07,0xe8,0x04,0x3d,0xb4,0x09,0xc9,0x1c,0x32,0xe7,0x57,0x24,0xe8,0x13,0xa4,0x19,0x1e,0x3a,0x83,0x90,0x07,0xf0,0x8e,0x2e,0x89,0x73,0x88,0xb0,0x6d,0x4a,0x00,0xde,0x6d,0xe6,0x0e,0x53,0x6d,0x91,0xfa,0xb5,0x66, + 0x04,0xa3,0x33,0x1a,0x4e,0x1b,0x42,0x23,0xec,0x2c,0x02,0x7e,0xdd,0x48,0x2c,0x92,0x8a,0x14,0xed,0x35,0x8d,0x93,0xf1,0xd4,0x21,0x7d,0x39,0xab,0xf6,0x9f,0xcb,0x5c,0xcc,0x28,0xd6,0x84,0xd2,0xaa,0xab,0xcd,0x63,0x83,0x77,0x5c,0xaa,0x62,0x39,0xde,0x26,0xd4,0xc6,0x93,0x7b,0xb6,0x03,0xec,0xb4,0x19,0x60,0x82,0xf4,0xcf,0xfd,0x50,0x9d, + 0x04,0x3f,0x39,0x52,0x19,0x97,0x74,0xc7,0xcf,0x39,0xb3,0x8b,0x66,0xcb,0x10,0x42,0xa6,0x26,0x0d,0x86,0x80,0x80,0x38,0x45,0xe4,0xd4,0x33,0xad,0xba,0x3b,0xb2,0x48,0x18,0x5e,0xa4,0x95,0xb6,0x8c,0xbc,0x7e,0xd4,0x17,0x3e,0xe6,0x3c,0x90,0x42,0xdc,0x50,0x26,0x25,0xc7,0xeb,0x7e,0x21,0xfb,0x02,0xca,0x9a,0x91,0x14,0xe0,0xa3,0xa1,0x8d, + 0x04,0xcd,0xfb,0x8c,0x0f,0x42,0x2e,0x14,0x4e,0x13,0x7c,0x24,0x12,0xc8,0x6c,0x17,0x1f,0x5f,0xe3,0xfa,0x3f,0x5b,0xbb,0x54,0x4e,0x90,0x76,0x28,0x8f,0x3c,0xed,0x78,0x6e,0x05,0x4f,0xd0,0x72,0x1b,0x77,0xc1,0x1c,0x79,0xbe,0xac,0xb3,0xc9,0x42,0x11,0xb0,0xa1,0x9b,0xda,0x08,0x65,0x2e,0xfe,0xaf,0x92,0x51,0x3a,0x3b,0x0a,0x16,0x36,0x98, + 0x04,0x73,0x59,0x8a,0x6a,0x1c,0x68,0x27,0x8f,0xa6,0xbf,0xd0,0xce,0x40,0x64,0xe6,0x82,0x35,0xbc,0x1c,0x0f,0x6b,0x20,0xa9,0x28,0x10,0x8b,0xe3,0x36,0x73,0x0f,0x87,0xe3,0xcb,0xae,0x61,0x25,0x19,0xb5,0x03,0x2e,0xcc,0x85,0xae,0xd8,0x11,0x27,0x1a,0x95,0xfe,0x79,0x39,0xd5,0xd3,0x46,0x01,0x40,0xba,0x31,0x8f,0x4d,0x14,0xab,0xa3,0x1d, + 0x04,0x58,0xde,0xbd,0x9a,0x7e,0xe2,0xc9,0xd5,0x91,0x32,0x47,0x8a,0x54,0x40,0xae,0x4d,0x5d,0x7e,0xd4,0x37,0x30,0x83,0x69,0xf9,0x2e,0xa8,0x6c,0x82,0x18,0x3f,0x10,0xa1,0x67,0x73,0xe7,0x6f,0x5e,0xdb,0xf4,0xda,0x0e,0x4f,0x1b,0xdf,0xfa,0xc0,0xf5,0x72,0x57,0xe1,0xdf,0xa4,0x65,0x84,0x29,0x31,0x30,0x9a,0x24,0x24,0x5f,0xda,0x6a,0x5d, + 0x04,0x8b,0x90,0x4d,0xe4,0x79,0x67,0x34,0x0c,0x5f,0x8c,0x35,0x72,0xa7,0x20,0x92,0x4e,0xf7,0x57,0x86,0x37,0xfe,0xab,0x19,0x49,0xac,0xb2,0x41,0xa5,0xa6,0xac,0x3f,0x5b,0x95,0x09,0x04,0x49,0x6f,0x98,0x24,0xb1,0xd6,0x3f,0x33,0x13,0xba,0xe2,0x1b,0x89,0xfa,0xe8,0x9a,0xfd,0xfc,0x81,0x1b,0x5e,0xce,0x03,0xfd,0x5a,0xa3,0x01,0x86,0x4f, + 0x04,0xf4,0x89,0x2b,0x6d,0x52,0x5c,0x77,0x1e,0x03,0x5f,0x2a,0x25,0x27,0x08,0xf3,0x78,0x4e,0x48,0x23,0x86,0x04,0xb4,0xf9,0x4d,0xc5,0x6e,0xaa,0x1e,0x54,0x6d,0x94,0x1a,0x34,0x6b,0x1a,0xa0,0xbc,0xe6,0x8b,0x1c,0x50,0xe5,0xb5,0x2f,0x50,0x9f,0xb5,0x52,0x2e,0x5c,0x25,0xe0,0x28,0xbc,0x8f,0x86,0x34,0x02,0xed,0xb7,0xbc,0xad,0x8b,0x1b, + 0x04,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x48,0x3a,0xda,0x77,0x26,0xa3,0xc4,0x65,0x5d,0xa4,0xfb,0xfc,0x0e,0x11,0x08,0xa8,0xfd,0x17,0xb4,0x48,0xa6,0x85,0x54,0x19,0x9c,0x47,0xd0,0x8f,0xfb,0x10,0xd4,0xb8, + 0x04,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0xb7,0xc5,0x25,0x88,0xd9,0x5c,0x3b,0x9a,0xa2,0x5b,0x04,0x03,0xf1,0xee,0xf7,0x57,0x02,0xe8,0x4b,0xb7,0x59,0x7a,0xab,0xe6,0x63,0xb8,0x2f,0x6f,0x04,0xef,0x27,0x77, + 0x04,0x78,0x2c,0x8e,0xd1,0x7e,0x3b,0x2a,0x78,0x3b,0x54,0x64,0xf3,0x3b,0x09,0x65,0x2a,0x71,0xc6,0x78,0xe0,0x5e,0xc5,0x1e,0x84,0xe2,0xbc,0xfc,0x66,0x3a,0x3d,0xe9,0x63,0xaf,0x9a,0xcb,0x42,0x80,0xb8,0xc7,0xf7,0xc4,0x2f,0x4e,0xf9,0xab,0xa6,0x24,0x5e,0xc1,0xec,0x17,0x12,0xfd,0x38,0xa0,0xfa,0x96,0x41,0x8d,0x8c,0xd6,0xaa,0x61,0x52, + 0x04,0x6e,0x82,0x35,0x55,0x45,0x29,0x14,0x09,0x91,0x82,0xc6,0xb2,0xc1,0xd6,0xf0,0xb5,0xd2,0x8d,0x50,0xcc,0xd0,0x05,0xaf,0x2c,0xe1,0xbb,0xa5,0x41,0xaa,0x40,0xca,0xff,0x00,0x00,0x00,0x01,0x06,0x04,0x92,0xd5,0xa5,0x67,0x3e,0x0f,0x25,0xd8,0xd5,0x0f,0xb7,0xe5,0x8c,0x49,0xd8,0x6d,0x46,0xd4,0x21,0x69,0x55,0xe0,0xaa,0x3d,0x40,0xe1, + 0x04,0x6e,0x82,0x35,0x55,0x45,0x29,0x14,0x09,0x91,0x82,0xc6,0xb2,0xc1,0xd6,0xf0,0xb5,0xd2,0x8d,0x50,0xcc,0xd0,0x05,0xaf,0x2c,0xe1,0xbb,0xa5,0x41,0xaa,0x40,0xca,0xff,0xff,0xff,0xff,0xfe,0xf9,0xfb,0x6d,0x2a,0x5a,0x98,0xc1,0xf0,0xda,0x27,0x2a,0xf0,0x48,0x1a,0x73,0xb6,0x27,0x92,0xb9,0x2b,0xde,0x96,0xaa,0x1e,0x55,0xc2,0xbb,0x4e, + 0x04,0x00,0x00,0x00,0x01,0x3f,0xd2,0x22,0x48,0xd6,0x4d,0x95,0xf7,0x3c,0x29,0xb4,0x8a,0xb4,0x86,0x31,0x85,0x0b,0xe5,0x03,0xfd,0x00,0xf8,0x46,0x8b,0x5f,0x0f,0x70,0xe0,0xf6,0xee,0x7a,0xa4,0x3b,0xc2,0xc6,0xfd,0x25,0xb1,0xd8,0x26,0x92,0x41,0xcb,0xdd,0x9d,0xbb,0x0d,0xac,0x96,0xdc,0x96,0x23,0x1f,0x43,0x07,0x05,0xf8,0x38,0x71,0x7d, + 0x04,0x25,0xaf,0xd6,0x89,0xac,0xab,0xae,0xd6,0x7c,0x1f,0x29,0x6d,0xe5,0x94,0x06,0xf8,0xc5,0x50,0xf5,0x71,0x46,0xa0,0xb4,0xec,0x2c,0x97,0x87,0x6d,0xff,0xff,0xff,0xff,0xfa,0x46,0xa7,0x6e,0x52,0x03,0x22,0xdf,0xbc,0x49,0x1e,0xc4,0xf0,0xcc,0x19,0x74,0x20,0xfc,0x4e,0xa5,0x88,0x3d,0x8f,0x6d,0xd5,0x3c,0x35,0x4b,0xc4,0xf6,0x7c,0x35, + 0x04,0xd1,0x2e,0x6c,0x66,0xb6,0x77,0x34,0xc3,0xc8,0x4d,0x26,0x01,0xcf,0x5d,0x35,0xdc,0x09,0x7e,0x27,0x63,0x7f,0x0a,0xca,0x4a,0x4f,0xdb,0x74,0xb6,0xaa,0xdd,0x3b,0xb9,0x3f,0x5b,0xdf,0xf8,0x8b,0xd5,0x73,0x6d,0xf8,0x98,0xe6,0x99,0x00,0x6e,0xd7,0x50,0xf1,0x1c,0xf0,0x7c,0x58,0x66,0xcd,0x7a,0xd7,0x0c,0x71,0x21,0xff,0xff,0xff,0xff, + 0x04,0x6d,0x4a,0x7f,0x60,0xd4,0x77,0x4a,0x4f,0x0a,0xa8,0xbb,0xde,0xdb,0x95,0x3c,0x7e,0xea,0x79,0x09,0x40,0x7e,0x31,0x64,0x75,0x56,0x64,0xbc,0x28,0x00,0x00,0x00,0x00,0xe6,0x59,0xd3,0x4e,0x4d,0xf3,0x8d,0x9e,0x8c,0x9e,0xaa,0xdf,0xba,0x36,0x61,0x2c,0x76,0x91,0x95,0xbe,0x86,0xc7,0x7a,0xac,0x3f,0x36,0xe7,0x8b,0x53,0x86,0x80,0xfb}; + +static const unsigned char wycheproof_ecdsa_signatures[] = { 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0x00,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x7d,0xb3,0x7c,0x21,0xf4,0xaf,0xd3,0x20,0x3a,0xe8,0xdc,0x4a,0xe7,0x79,0x4b,0x0f,0x87, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x81,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x82,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x85,0x01,0x00,0x00,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x84,0x7f,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x84,0x80,0x00,0x00,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x84,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x85,0xff,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x47,0x00,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00, + 0x30,0x4a,0x49,0x81,0x77,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x25,0x00,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x04,0xde,0xad,0xbe,0xef, + 0x30,0x4d,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x22,0x29,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x28,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x81, + 0x30,0x4b,0xaa,0x02,0xaa,0xbb,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x80,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x80,0x31,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x05,0x00, + 0x2e,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x2f,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x31,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x32,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0xff,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x00, + 0x30,0x49,0x30,0x01,0x02,0x30,0x44,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31, + 0x30,0x44,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x82,0x10,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00,0x00,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x06,0x08,0x11,0x22,0x00,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0xfe,0x02,0xbe,0xef, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x02,0xbe,0xef, + 0x30,0x47,0x30,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x30,0x00, + 0x30,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x01,0x00, + 0x30,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xbf,0x7f,0x00, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xa0,0x02,0x05,0x00, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xa0,0x00, + 0x30,0x47,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x23,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65, + 0x30,0x67,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x64,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xca,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x13,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x08,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x81,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x82,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x22,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x20,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x02,0x85,0x01,0x00,0x00,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4e,0x02,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x84,0x7f,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x84,0x80,0x00,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x84,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x02,0x85,0xff,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x80,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x22,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x23,0x02,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x24,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02, + 0x30,0x47,0x02,0x23,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x23,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x23,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x05,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x22,0x26,0x49,0x81,0x77,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x22,0x25,0x25,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x22,0x23,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x04,0xde,0xad,0xbe,0xef,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x24,0x02,0x81,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4b,0x22,0x27,0xaa,0x02,0xaa,0xbb,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x22,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x22,0x80,0x03,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x24,0x05,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x01,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x03,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x04,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0xff,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x24,0x02,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x22,0x25,0x02,0x01,0x00,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x02,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0xe5,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x82,0x10,0x48,0x02,0x82,0x10,0x22,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x22,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x25,0x09,0x01,0x80,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x25,0x02,0x01,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xbb, + 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa4,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf7,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x01,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x81,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x82,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x85,0x01,0x00,0x00,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4e,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0x7f,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0x80,0x00,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x85,0xff,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x80,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00, + 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x25,0x49,0x81,0x77,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x24,0x25,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x22,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x04,0xde,0xad,0xbe,0xef, + 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x81, + 0x30,0x4b,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x26,0xaa,0x02,0xaa,0xbb,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x80,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x80,0x03,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x05,0x00, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x01,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x03,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x04,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0xff,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x00, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x24,0x02,0x01,0x6f,0x02,0x1f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6d,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0x3a, + 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31, + 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x82,0x10,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x82,0x10,0x21,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x26,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x09,0x01,0x80, + 0x30,0x26,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x01,0x00, + 0x30,0x45,0x02,0x21,0x01,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x83,0xb9,0x0d,0xea,0xbc,0xa4,0xb0,0x5c,0x45,0x74,0xe4,0x9b,0x58,0x99,0xb9,0x64,0xa6,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x86,0x43,0xb0,0x30,0xef,0x46,0x1f,0x1b,0xcd,0xf5,0x3f,0xde,0x3e,0xf9,0x4c,0xe2,0x24,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x22,0x01,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x84,0x3f,0xad,0x3b,0xf4,0x85,0x3e,0x07,0xf7,0xc9,0x87,0x70,0xc9,0x9b,0xff,0xc4,0x64,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xff,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x7b,0x01,0xa0,0xf2,0x2a,0x0a,0x98,0x43,0xf6,0x4a,0xed,0xc3,0x34,0x36,0x7c,0xdc,0x9b,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x79,0xbc,0x4f,0xcf,0x10,0xb9,0xe0,0xe4,0x32,0x0a,0xc0,0x21,0xc1,0x06,0xb3,0x1d,0xdc,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xfe,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x7c,0x46,0xf2,0x15,0x43,0x5b,0x4f,0xa3,0xba,0x8b,0x1b,0x64,0xa7,0x66,0x46,0x9b,0x5a,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x01,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x29,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x01,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x7f,0xc1,0xe1,0x97,0xd8,0xae,0xbe,0x20,0x3c,0x96,0xc8,0x72,0x32,0x27,0x21,0x72,0xfb,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x82,0x4c,0x83,0xde,0x0b,0x50,0x2c,0xdf,0xc5,0x17,0x23,0xb5,0x18,0x86,0xb4,0xf0,0x79,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x22,0x01,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9a,0x3b,0xb6,0x0f,0xa1,0xa1,0x48,0x15,0xbb,0xc0,0xa9,0x54,0xa0,0x75,0x8d,0x2c,0x72,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x7e,0xf8,0xcd,0x45,0x0e,0x00,0x8a,0x7f,0xff,0x29,0x09,0xec,0x5a,0xa9,0x14,0xce,0x46,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xfe,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x80,0x3e,0x1e,0x68,0x27,0x51,0x41,0xdf,0xc3,0x69,0x37,0x8d,0xcd,0xd8,0xde,0x8d,0x05,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x01,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x29,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0x00, + 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0xff, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x00, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0xff, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0x00, + 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0xff, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x08,0x02,0x01,0x00,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x06,0x02,0x01,0x00,0x09,0x01,0x42, + 0x30,0x06,0x02,0x01,0x00,0x01,0x01,0x01, + 0x30,0x06,0x02,0x01,0x00,0x01,0x01,0x00, + 0x30,0x05,0x02,0x01,0x00,0x05,0x00, + 0x30,0x05,0x02,0x01,0x00,0x0c,0x00, + 0x30,0x06,0x02,0x01,0x00,0x0c,0x01,0x30, + 0x30,0x05,0x02,0x01,0x00,0x30,0x00, + 0x30,0x08,0x02,0x01,0x00,0x30,0x03,0x02,0x01,0x00, + 0x30,0x08,0x02,0x01,0x01,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x06,0x02,0x01,0x01,0x09,0x01,0x42, + 0x30,0x06,0x02,0x01,0x01,0x01,0x01,0x01, + 0x30,0x06,0x02,0x01,0x01,0x01,0x01,0x00, + 0x30,0x05,0x02,0x01,0x01,0x05,0x00, + 0x30,0x05,0x02,0x01,0x01,0x0c,0x00, + 0x30,0x06,0x02,0x01,0x01,0x0c,0x01,0x30, + 0x30,0x05,0x02,0x01,0x01,0x30,0x00, + 0x30,0x08,0x02,0x01,0x01,0x30,0x03,0x02,0x01,0x00, + 0x30,0x08,0x02,0x01,0xff,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x06,0x02,0x01,0xff,0x09,0x01,0x42, + 0x30,0x06,0x02,0x01,0xff,0x01,0x01,0x01, + 0x30,0x06,0x02,0x01,0xff,0x01,0x01,0x00, + 0x30,0x05,0x02,0x01,0xff,0x05,0x00, + 0x30,0x05,0x02,0x01,0xff,0x0c,0x00, + 0x30,0x06,0x02,0x01,0xff,0x0c,0x01,0x30, + 0x30,0x05,0x02,0x01,0xff,0x30,0x00, + 0x30,0x08,0x02,0x01,0xff,0x30,0x03,0x02,0x01,0x00, + 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x09,0x01,0x42, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x01,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x01,0x01,0x00, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x05,0x00, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x0c,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x0c,0x01,0x30, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x30,0x00, + 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x30,0x03,0x02,0x01,0x00, + 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x09,0x01,0x42, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x01,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x01,0x01,0x00, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x05,0x00, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x0c,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x0c,0x01,0x30, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x30,0x00, + 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x30,0x03,0x02,0x01,0x00, + 0x30,0x0a,0x09,0x03,0x80,0xfe,0x01,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x06,0x09,0x01,0x42,0x09,0x01,0x42, + 0x30,0x06,0x01,0x01,0x01,0x01,0x01,0x01, + 0x30,0x06,0x01,0x01,0x00,0x01,0x01,0x00, + 0x30,0x04,0x05,0x00,0x05,0x00, + 0x30,0x04,0x0c,0x00,0x0c,0x00, + 0x30,0x06,0x0c,0x01,0x30,0x0c,0x01,0x30, + 0x30,0x04,0x30,0x00,0x30,0x00, + 0x30,0x0a,0x30,0x03,0x02,0x01,0x00,0x30,0x03,0x02,0x01,0x00, + 0x30,0x08,0x09,0x03,0x80,0xfe,0x01,0x02,0x01,0x00, + 0x30,0x06,0x09,0x01,0x42,0x02,0x01,0x00, + 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x00, + 0x30,0x06,0x01,0x01,0x00,0x02,0x01,0x00, + 0x30,0x05,0x05,0x00,0x02,0x01,0x00, + 0x30,0x05,0x0c,0x00,0x02,0x01,0x00, + 0x30,0x06,0x0c,0x01,0x30,0x02,0x01,0x00, + 0x30,0x05,0x30,0x00,0x02,0x01,0x00, + 0x30,0x08,0x30,0x03,0x02,0x01,0x00,0x02,0x01,0x00, + 0x30,0x45,0x02,0x21,0x00,0xdd,0x1b,0x7d,0x09,0xa7,0xbd,0x82,0x18,0x96,0x10,0x34,0xa3,0x9a,0x87,0xfe,0xcf,0x53,0x14,0xf0,0x0c,0x4d,0x25,0xeb,0x58,0xa0,0x7a,0xc8,0x5e,0x85,0xea,0xb5,0x16,0x02,0x20,0x35,0x13,0x8c,0x40,0x1e,0xf8,0xd3,0x49,0x3d,0x65,0xc9,0x00,0x2f,0xe6,0x2b,0x43,0xae,0xe5,0x68,0x73,0x1b,0x74,0x45,0x48,0x35,0x89,0x96,0xd9,0xcc,0x42,0x7e,0x06, + 0x30,0x45,0x02,0x21,0x00,0x95,0xc2,0x92,0x67,0xd9,0x72,0xa0,0x43,0xd9,0x55,0x22,0x45,0x46,0x22,0x2b,0xba,0x34,0x3f,0xc1,0xd4,0xdb,0x0f,0xec,0x26,0x2a,0x33,0xac,0x61,0x30,0x56,0x96,0xae,0x02,0x20,0x6e,0xdf,0xe9,0x67,0x13,0xae,0xd5,0x6f,0x8a,0x28,0xa6,0x65,0x3f,0x57,0xe0,0xb8,0x29,0x71,0x2e,0x5e,0xdd,0xc6,0x7f,0x34,0x68,0x2b,0x24,0xf0,0x67,0x6b,0x26,0x40, + 0x30,0x44,0x02,0x20,0x28,0xf9,0x4a,0x89,0x4e,0x92,0x02,0x46,0x99,0xe3,0x45,0xfe,0x66,0x97,0x1e,0x3e,0xdc,0xd0,0x50,0x02,0x33,0x86,0x13,0x5a,0xb3,0x93,0x9d,0x55,0x08,0x98,0xfb,0x25,0x02,0x20,0x32,0x96,0x3e,0x5b,0xd4,0x1f,0xa5,0x91,0x1e,0xd8,0xf3,0x7d,0xeb,0x86,0xda,0xe0,0xa7,0x62,0xbb,0x61,0x21,0xc8,0x94,0x61,0x50,0x83,0xc5,0xd9,0x5e,0xa0,0x1d,0xb3, + 0x30,0x45,0x02,0x21,0x00,0xbe,0x26,0xb1,0x8f,0x95,0x49,0xf8,0x9f,0x41,0x1a,0x9b,0x52,0x53,0x6b,0x15,0xaa,0x27,0x0b,0x84,0x54,0x8d,0x0e,0x85,0x9a,0x19,0x52,0xa2,0x7a,0xf1,0xa7,0x7a,0xc6,0x02,0x20,0x70,0xc1,0xd4,0xfa,0x9c,0xd0,0x3c,0xc8,0xea,0xa8,0xd5,0x06,0xed,0xb9,0x7e,0xed,0x7b,0x83,0x58,0xb4,0x53,0xc8,0x8a,0xef,0xbb,0x88,0x0a,0x3f,0x0e,0x8d,0x47,0x2f, + 0x30,0x45,0x02,0x21,0x00,0xb1,0xa4,0xb1,0x47,0x8e,0x65,0xcc,0x3e,0xaf,0xdf,0x22,0x5d,0x12,0x98,0xb4,0x3f,0x2d,0xa1,0x9e,0x4b,0xcf,0xf7,0xea,0xcc,0x0a,0x2e,0x98,0xcd,0x4b,0x74,0xb1,0x14,0x02,0x20,0x17,0x9a,0xa3,0x1e,0x30,0x4c,0xc1,0x42,0xcf,0x50,0x73,0x17,0x17,0x51,0xb2,0x8f,0x3f,0x5e,0x0f,0xa8,0x8c,0x99,0x4e,0x7c,0x55,0xf1,0xbc,0x07,0xb8,0xd5,0x6c,0x16, + 0x30,0x44,0x02,0x20,0x32,0x53,0x32,0x02,0x12,0x61,0xf1,0xbd,0x18,0xf2,0x71,0x2a,0xa1,0xe2,0x25,0x2d,0xa2,0x37,0x96,0xda,0x8a,0x4b,0x1f,0xf6,0xea,0x18,0xca,0xfe,0xc7,0xe1,0x71,0xf2,0x02,0x20,0x40,0xb4,0xf5,0xe2,0x87,0xee,0x61,0xfc,0x3c,0x80,0x41,0x86,0x98,0x23,0x60,0x89,0x1e,0xaa,0x35,0xc7,0x5f,0x05,0xa4,0x3e,0xcd,0x48,0xb3,0x5d,0x98,0x4a,0x66,0x48, + 0x30,0x45,0x02,0x21,0x00,0xa2,0x3a,0xd1,0x8d,0x8f,0xc6,0x6d,0x81,0xaf,0x09,0x03,0x89,0x0c,0xbd,0x45,0x3a,0x55,0x4c,0xb0,0x4c,0xdc,0x1a,0x8c,0xa7,0xf7,0xf7,0x8e,0x53,0x67,0xed,0x88,0xa0,0x02,0x20,0x23,0xe3,0xeb,0x2c,0xe1,0xc0,0x4e,0xa7,0x48,0xc3,0x89,0xbd,0x97,0x37,0x4a,0xa9,0x41,0x3b,0x92,0x68,0x85,0x1c,0x04,0xdc,0xd9,0xf8,0x8e,0x78,0x81,0x3f,0xee,0x56, + 0x30,0x44,0x02,0x20,0x2b,0xde,0xa4,0x1c,0xda,0x63,0xa2,0xd1,0x4b,0xf4,0x73,0x53,0xbd,0x20,0x88,0x0a,0x69,0x09,0x01,0xde,0x7c,0xd6,0xe3,0xcc,0x6d,0x8e,0xd5,0xba,0x0c,0xdb,0x10,0x91,0x02,0x20,0x3c,0xea,0x66,0xbc,0xcf,0xc9,0xf9,0xbf,0x8c,0x7c,0xa4,0xe1,0xc1,0x45,0x7c,0xc9,0x14,0x5e,0x13,0xe9,0x36,0xd9,0x0b,0x3d,0x9c,0x77,0x86,0xb8,0xb2,0x6c,0xf4,0xc7, + 0x30,0x45,0x02,0x21,0x00,0xd7,0xcd,0x76,0xec,0x01,0xc1,0xb1,0x07,0x9e,0xba,0x9e,0x2a,0xa2,0xa3,0x97,0x24,0x3c,0x47,0x58,0xc9,0x8a,0x1b,0xa0,0xb7,0x40,0x4a,0x34,0x0b,0x9b,0x00,0xce,0xd6,0x02,0x20,0x35,0x75,0x00,0x1e,0x19,0xd9,0x22,0xe6,0xde,0x8b,0x3d,0x6c,0x84,0xea,0x43,0xb5,0xc3,0x33,0x81,0x06,0xcf,0x29,0x99,0x01,0x34,0xe7,0x66,0x9a,0x82,0x6f,0x78,0xe6, + 0x30,0x45,0x02,0x21,0x00,0xa8,0x72,0xc7,0x44,0xd9,0x36,0xdb,0x21,0xa1,0x0c,0x36,0x1d,0xd5,0xc9,0x06,0x33,0x55,0xf8,0x49,0x02,0x21,0x96,0x52,0xf6,0xfc,0x56,0xdc,0x95,0xa7,0x13,0x9d,0x96,0x02,0x20,0x40,0x0d,0xf7,0x57,0x5d,0x97,0x56,0x21,0x0e,0x9c,0xcc,0x77,0x16,0x2c,0x6b,0x59,0x3c,0x77,0x46,0xcf,0xb4,0x8a,0xc2,0x63,0xc4,0x27,0x50,0xb4,0x21,0xef,0x4b,0xb9, + 0x30,0x45,0x02,0x21,0x00,0x9f,0xa9,0xaf,0xe0,0x77,0x52,0xda,0x10,0xb3,0x6d,0x3a,0xfc,0xd0,0xfe,0x44,0xbf,0xc4,0x02,0x44,0xd7,0x52,0x03,0x59,0x9c,0xf8,0xf5,0x04,0x7f,0xa3,0x45,0x38,0x54,0x02,0x20,0x50,0xe0,0xa7,0xc0,0x13,0xbf,0xbf,0x51,0x81,0x97,0x36,0x97,0x2d,0x44,0xb4,0xb5,0x6b,0xc2,0xa2,0xb2,0xc1,0x80,0xdf,0x6e,0xc6,0x72,0xdf,0x17,0x14,0x10,0xd7,0x7a, + 0x30,0x45,0x02,0x21,0x00,0x88,0x56,0x40,0x38,0x4d,0x0d,0x91,0x0e,0xfb,0x17,0x7b,0x46,0xbe,0x6c,0x3d,0xc5,0xca,0xc8,0x1f,0x0b,0x88,0xc3,0x19,0x0b,0xb6,0xb5,0xf9,0x9c,0x26,0x41,0xf2,0x05,0x02,0x20,0x73,0x8e,0xd9,0xbf,0xf1,0x16,0x30,0x6d,0x9c,0xaa,0x0f,0x8f,0xc6,0x08,0xbe,0x24,0x3e,0x0b,0x56,0x77,0x79,0xd8,0xda,0xb0,0x3e,0x8e,0x19,0xd5,0x53,0xf1,0xdc,0x8e, + 0x30,0x44,0x02,0x20,0x2d,0x05,0x1f,0x91,0xc5,0xa9,0xd4,0x40,0xc5,0x67,0x69,0x85,0x71,0x04,0x83,0xbc,0x4f,0x1a,0x6c,0x61,0x1b,0x10,0xc9,0x5a,0x2f,0xf0,0x36,0x3d,0x90,0xc2,0xa4,0x58,0x02,0x20,0x6d,0xdf,0x94,0xe6,0xfb,0xa5,0xbe,0x58,0x68,0x33,0xd0,0xc5,0x3c,0xf2,0x16,0xad,0x39,0x48,0xf3,0x79,0x53,0xc2,0x6c,0x1c,0xf4,0x96,0x8e,0x9a,0x9e,0x82,0x43,0xdc, + 0x30,0x45,0x02,0x21,0x00,0xf3,0xac,0x25,0x23,0x96,0x74,0x82,0xf5,0x3d,0x50,0x85,0x22,0x71,0x2d,0x58,0x3f,0x43,0x79,0xcd,0x82,0x41,0x01,0xff,0x63,0x5e,0xa0,0x93,0x51,0x17,0xba,0xa5,0x4f,0x02,0x20,0x27,0xf1,0x08,0x12,0x22,0x73,0x97,0xe0,0x2c,0xea,0x96,0xfb,0x0e,0x68,0x07,0x61,0x63,0x6d,0xab,0x2b,0x08,0x0d,0x1f,0xc5,0xd1,0x16,0x85,0xcb,0xe8,0x50,0x0c,0xfe, + 0x30,0x45,0x02,0x21,0x00,0x96,0x44,0x7c,0xf6,0x8c,0x3a,0xb7,0x26,0x6e,0xd7,0x44,0x7d,0xe3,0xac,0x52,0xfe,0xd7,0xcc,0x08,0xcb,0xdf,0xea,0x39,0x1c,0x18,0xa9,0xb8,0xab,0x37,0x0b,0xc9,0x13,0x02,0x20,0x0f,0x5e,0x78,0x74,0xd3,0xac,0x0e,0x91,0x8f,0x01,0xc8,0x85,0xa1,0x63,0x91,0x77,0xc9,0x23,0xf8,0x66,0x0d,0x1c,0xeb,0xa1,0xca,0x1f,0x30,0x1b,0xc6,0x75,0xcd,0xbc, + 0x30,0x44,0x02,0x20,0x53,0x0a,0x08,0x32,0xb6,0x91,0xda,0x0b,0x56,0x19,0xa0,0xb1,0x1d,0xe6,0x87,0x7f,0x3c,0x09,0x71,0xba,0xaa,0x68,0xed,0x12,0x27,0x58,0xc2,0x9c,0xaa,0xf4,0x6b,0x72,0x02,0x20,0x6c,0x89,0xe4,0x4f,0x5e,0xb3,0x30,0x60,0xea,0x4b,0x46,0x31,0x8c,0x39,0x13,0x8e,0xae,0xde,0xc7,0x2d,0xe4,0x2b,0xa5,0x76,0x57,0x9a,0x6a,0x46,0x90,0xe3,0x39,0xf3, + 0x30,0x45,0x02,0x21,0x00,0x9c,0x54,0xc2,0x55,0x00,0xbd,0xe0,0xb9,0x2d,0x72,0xd6,0xec,0x48,0x3d,0xc2,0x48,0x2f,0x36,0x54,0x29,0x4c,0xa7,0x4d,0xe7,0x96,0xb6,0x81,0x25,0x5e,0xd5,0x8a,0x77,0x02,0x20,0x67,0x74,0x53,0xc6,0xb5,0x6f,0x52,0x76,0x31,0xc9,0xf6,0x7b,0x3f,0x3e,0xb6,0x21,0xfd,0x88,0x58,0x2b,0x4a,0xff,0x15,0x6d,0x2f,0x15,0x67,0xd6,0x21,0x1a,0x2a,0x33, + 0x30,0x45,0x02,0x21,0x00,0xe7,0x90,0x9d,0x41,0x43,0x9e,0x2f,0x6a,0xf2,0x91,0x36,0xc7,0x34,0x8c,0xa2,0x64,0x1a,0x2b,0x07,0x0d,0x5b,0x64,0xf9,0x1e,0xa9,0xda,0x70,0x70,0xc7,0xa2,0x61,0x8b,0x02,0x20,0x42,0xd7,0x82,0xf1,0x32,0xfa,0x1d,0x36,0xc2,0xc8,0x8b,0xa2,0x7c,0x3d,0x67,0x8d,0x80,0x18,0x4a,0x5d,0x1e,0xcc,0xac,0x75,0x01,0xf0,0xb4,0x7e,0x3d,0x20,0x50,0x08, + 0x30,0x44,0x02,0x20,0x59,0x24,0x87,0x32,0x09,0x59,0x31,0x35,0xa4,0xc3,0xda,0x7b,0xb3,0x81,0x22,0x7f,0x8a,0x4b,0x6a,0xa9,0xf3,0x4f,0xe5,0xbb,0x7f,0x8f,0xbc,0x13,0x1a,0x03,0x9f,0xfe,0x02,0x20,0x1f,0x1b,0xb1,0x1b,0x44,0x1c,0x8f,0xea,0xa4,0x0f,0x44,0x21,0x3d,0x9a,0x40,0x5e,0xd7,0x92,0xd5,0x9f,0xb4,0x9d,0x5b,0xcd,0xd9,0xa4,0x28,0x5a,0xe5,0x69,0x30,0x22, + 0x30,0x45,0x02,0x21,0x00,0xee,0xb6,0x92,0xc9,0xb2,0x62,0x96,0x9b,0x23,0x1c,0x38,0xb5,0xa7,0xf6,0x06,0x49,0xe0,0xc8,0x75,0xcd,0x64,0xdf,0x88,0xf3,0x3a,0xa5,0x71,0xfa,0x3d,0x29,0xab,0x0e,0x02,0x20,0x21,0x8b,0x3a,0x1e,0xb0,0x63,0x79,0xc2,0xc1,0x8c,0xf5,0x1b,0x06,0x43,0x07,0x86,0xd1,0xc6,0x4c,0xd2,0xd2,0x4c,0x9b,0x23,0x2b,0x23,0xe5,0xba,0xc7,0x98,0x9a,0xcd, + 0x30,0x45,0x02,0x21,0x00,0xa4,0x00,0x34,0x17,0x7f,0x36,0x09,0x1c,0x2b,0x65,0x36,0x84,0xa0,0xe3,0xeb,0x5d,0x4b,0xff,0x18,0xe4,0xd0,0x9f,0x66,0x4c,0x28,0x00,0xe7,0xca,0xfd,0xa1,0xda,0xf8,0x02,0x20,0x3a,0x3e,0xc2,0x98,0x53,0x70,0x4e,0x52,0x03,0x1c,0x58,0x92,0x7a,0x80,0x0a,0x96,0x83,0x53,0xad,0xc3,0xd9,0x73,0xbe,0xba,0x91,0x72,0xcb,0xbe,0xab,0x4d,0xd1,0x49, + 0x30,0x45,0x02,0x21,0x00,0xb5,0xd7,0x95,0xcc,0x75,0xce,0xa5,0xc4,0x34,0xfa,0x41,0x85,0x18,0x0c,0xd6,0xbd,0x21,0x22,0x3f,0x3d,0x5a,0x86,0xda,0x66,0x70,0xd7,0x1d,0x95,0x68,0x0d,0xad,0xbf,0x02,0x20,0x54,0xe4,0xd8,0x81,0x0a,0x00,0x1e,0xcb,0xb9,0xf7,0xca,0x1c,0x2e,0xbf,0xdb,0x9d,0x00,0x9e,0x90,0x31,0xa4,0x31,0xac,0xa3,0xc2,0x0a,0xb4,0xe0,0xd1,0x37,0x4e,0xc1, + 0x30,0x44,0x02,0x20,0x07,0xdc,0x24,0x78,0xd4,0x3c,0x12,0x32,0xa4,0x59,0x56,0x08,0xc6,0x44,0x26,0xc3,0x55,0x10,0x05,0x1a,0x63,0x1a,0xe6,0xa5,0xa6,0xeb,0x11,0x61,0xe5,0x7e,0x42,0xe1,0x02,0x20,0x4a,0x59,0xea,0x0f,0xdb,0x72,0xd1,0x21,0x65,0xce,0xa3,0xbf,0x1c,0xa8,0x6b,0xa9,0x75,0x17,0xbd,0x18,0x8d,0xb3,0xdb,0xd2,0x1a,0x5a,0x15,0x78,0x50,0x02,0x19,0x84, + 0x30,0x45,0x02,0x21,0x00,0xdd,0xd2,0x0c,0x4a,0x05,0x59,0x6c,0xa8,0x68,0xb5,0x58,0x83,0x9f,0xce,0x9f,0x65,0x11,0xdd,0xd8,0x3d,0x1c,0xcb,0x53,0xf8,0x2e,0x52,0x69,0xd5,0x59,0xa0,0x15,0x52,0x02,0x20,0x5b,0x91,0x73,0x47,0x29,0xd9,0x30,0x93,0xff,0x22,0x12,0x3c,0x4a,0x25,0x81,0x9d,0x7f,0xeb,0x66,0xa2,0x50,0x66,0x3f,0xc7,0x80,0xcb,0x66,0xfc,0x7b,0x6e,0x6d,0x17, + 0x30,0x45,0x02,0x21,0x00,0x9c,0xde,0x6e,0x0e,0xde,0x0a,0x00,0x3f,0x02,0xfd,0xa0,0xa0,0x1b,0x59,0xfa,0xcf,0xe5,0xde,0xc0,0x63,0x31,0x8f,0x27,0x9c,0xe2,0xde,0x7a,0x9b,0x10,0x62,0xf7,0xb7,0x02,0x20,0x28,0x86,0xa5,0xb8,0xc6,0x79,0xbd,0xf8,0x22,0x4c,0x66,0xf9,0x08,0xfd,0x62,0x05,0x49,0x2c,0xb7,0x0b,0x00,0x68,0xd4,0x6a,0xe4,0xf3,0x3a,0x41,0x49,0xb1,0x2a,0x52, + 0x30,0x45,0x02,0x21,0x00,0xc5,0x77,0x10,0x16,0xd0,0xdd,0x63,0x57,0x14,0x3c,0x89,0xf6,0x84,0xcd,0x74,0x04,0x23,0x50,0x25,0x54,0xc0,0xc5,0x9a,0xa8,0xc9,0x95,0x84,0xf1,0xff,0x38,0xf6,0x09,0x02,0x20,0x54,0xb4,0x05,0xf4,0x47,0x75,0x46,0x68,0x6e,0x46,0x4c,0x54,0x63,0xb4,0xfd,0x41,0x90,0x57,0x2e,0x58,0xd0,0xf7,0xe7,0x35,0x7f,0x6e,0x61,0x94,0x7d,0x20,0x71,0x5c, + 0x30,0x45,0x02,0x21,0x00,0xa2,0x4e,0xbc,0x0e,0xc2,0x24,0xbd,0x67,0xae,0x39,0x7c,0xbe,0x6f,0xa3,0x7b,0x31,0x25,0xad,0xbd,0x34,0x89,0x1a,0xbe,0x2d,0x7c,0x73,0x56,0x92,0x19,0x16,0xdf,0xe6,0x02,0x20,0x34,0xf6,0xeb,0x63,0x74,0x73,0x1b,0xbb,0xaf,0xc4,0x92,0x4f,0xb8,0xb0,0xbd,0xcd,0xda,0x49,0x45,0x6d,0x72,0x4c,0xda,0xe6,0x17,0x8d,0x87,0x01,0x4c,0xb5,0x3d,0x8c, + 0x30,0x44,0x02,0x20,0x25,0x57,0xd6,0x4a,0x7a,0xee,0x2e,0x09,0x31,0xc0,0x12,0xe4,0xfe,0xa1,0xcd,0x3a,0x2c,0x33,0x4e,0xda,0xe6,0x8c,0xde,0xb7,0x15,0x8c,0xaf,0x21,0xb6,0x8e,0x5a,0x24,0x02,0x20,0x7f,0x06,0xcd,0xbb,0x6a,0x90,0x02,0x3a,0x97,0x38,0x82,0xed,0x97,0xb0,0x80,0xfe,0x6b,0x05,0xaf,0x3e,0xc9,0x3d,0xb6,0xf1,0xa4,0x39,0x9a,0x69,0xed,0xf7,0x67,0x0d, + 0x30,0x45,0x02,0x21,0x00,0xc4,0xf2,0xec,0xcb,0xb6,0xa2,0x43,0x50,0xc8,0x46,0x64,0x50,0xb9,0xd6,0x1b,0x20,0x7e,0xe3,0x59,0xe0,0x37,0xb3,0xdc,0xed,0xb4,0x2a,0x3f,0x2e,0x6d,0xd6,0xae,0xb5,0x02,0x20,0x32,0x63,0xc6,0xb5,0x9a,0x2f,0x55,0xcd,0xd1,0xc6,0xe1,0x48,0x94,0xd5,0xe5,0x96,0x3b,0x28,0xbc,0x3e,0x24,0x69,0xac,0x9b,0xa1,0x19,0x79,0x91,0xca,0x7f,0xf9,0xc7, + 0x30,0x45,0x02,0x21,0x00,0xef,0xf0,0x47,0x81,0xc9,0xcb,0xcd,0x16,0x2d,0x0a,0x25,0xa6,0xe2,0xeb,0xcc,0xa4,0x35,0x06,0xc5,0x23,0x38,0x5c,0xb5,0x15,0xd4,0x9e,0xa3,0x8a,0x1b,0x12,0xfc,0xad,0x02,0x20,0x15,0xac,0xd7,0x31,0x94,0xc9,0x1a,0x95,0x47,0x85,0x34,0xf2,0x30,0x15,0xb6,0x72,0xeb,0xed,0x21,0x3e,0x45,0x42,0x4d,0xd2,0xc8,0xe2,0x6a,0xc8,0xb3,0xeb,0x34,0xa5, + 0x30,0x45,0x02,0x21,0x00,0xf5,0x8b,0x4e,0x31,0x10,0xa6,0x4b,0xf1,0xb5,0xdb,0x97,0x63,0x9e,0xe0,0xe5,0xa9,0xc8,0xdf,0xa4,0x9d,0xc5,0x9b,0x67,0x98,0x91,0xf5,0x20,0xfd,0xf0,0x58,0x4c,0x87,0x02,0x20,0x2c,0xd8,0xfe,0x51,0x88,0x8a,0xee,0x9d,0xb3,0xe0,0x75,0x44,0x0f,0xd4,0xdb,0x73,0xb5,0xc7,0x32,0xfb,0x87,0xb5,0x10,0xe9,0x70,0x93,0xd6,0x64,0x15,0xf6,0x2a,0xf7, + 0x30,0x45,0x02,0x21,0x00,0xf8,0xab,0xec,0xaa,0x4f,0x0c,0x50,0x2d,0xe4,0xbf,0x59,0x03,0xd4,0x84,0x17,0xf7,0x86,0xbf,0x92,0xe8,0xad,0x72,0xfe,0xc0,0xbd,0x7f,0xcb,0x78,0x00,0xc0,0xbb,0xe3,0x02,0x20,0x4c,0x7f,0x9e,0x23,0x10,0x76,0xa3,0x0b,0x7a,0xe3,0x6b,0x0c,0xeb,0xe6,0x9c,0xce,0xf1,0xcd,0x19,0x4f,0x7c,0xce,0x93,0xa5,0x58,0x8f,0xd6,0x81,0x4f,0x43,0x7c,0x0e, + 0x30,0x44,0x02,0x20,0x5d,0x5b,0x38,0xbd,0x37,0xad,0x49,0x8b,0x22,0x27,0xa6,0x33,0x26,0x8a,0x8c,0xca,0x87,0x9a,0x5c,0x7c,0x94,0xa4,0xe4,0x16,0xbd,0x0a,0x61,0x4d,0x09,0xe6,0x06,0xd2,0x02,0x20,0x12,0xb8,0xd6,0x64,0xea,0x99,0x91,0x06,0x2e,0xcb,0xb8,0x34,0xe5,0x84,0x00,0xe2,0x5c,0x46,0x00,0x7a,0xf8,0x4f,0x60,0x07,0xd7,0xf1,0x68,0x54,0x43,0x26,0x9a,0xfe, + 0x30,0x44,0x02,0x20,0x0c,0x1c,0xd9,0xfe,0x40,0x34,0xf0,0x86,0xa2,0xb5,0x2d,0x65,0xb9,0xd3,0x83,0x4d,0x72,0xae,0xbe,0x7f,0x33,0xdf,0xe8,0xf9,0x76,0xda,0x82,0x64,0x81,0x77,0xd8,0xe3,0x02,0x20,0x13,0x10,0x57,0x82,0xe3,0xd0,0xcf,0xe8,0x5c,0x27,0x78,0xde,0xc1,0xa8,0x48,0xb2,0x7a,0xc0,0xae,0x07,0x1a,0xa6,0xda,0x34,0x1a,0x95,0x53,0xa9,0x46,0xb4,0x1e,0x59, + 0x30,0x45,0x02,0x21,0x00,0xae,0x79,0x35,0xfb,0x96,0xff,0x24,0x6b,0x7b,0x5d,0x56,0x62,0x87,0x0d,0x1b,0xa5,0x87,0xb0,0x3d,0x6e,0x13,0x60,0xba,0xf4,0x79,0x88,0xb5,0xc0,0x2c,0xcc,0x1a,0x5b,0x02,0x20,0x5f,0x00,0xc3,0x23,0x27,0x20,0x83,0x78,0x2d,0x4a,0x59,0xf2,0xdf,0xd6,0x5e,0x49,0xde,0x06,0x93,0x62,0x70,0x16,0x90,0x0e,0xf7,0xe6,0x14,0x28,0x05,0x66,0x64,0xb3, + 0x30,0x44,0x02,0x20,0x00,0xa1,0x34,0xb5,0xc6,0xcc,0xbc,0xef,0xd4,0xc8,0x82,0xb9,0x45,0xba,0xeb,0x49,0x33,0x44,0x41,0x72,0x79,0x5f,0xa6,0x79,0x6a,0xae,0x14,0x90,0x67,0x54,0x70,0x98,0x02,0x20,0x56,0x6e,0x46,0x10,0x5d,0x24,0xd8,0x90,0x15,0x1e,0x3e,0xea,0x3e,0xbf,0x88,0xf5,0xb9,0x2b,0x3f,0x5e,0xc9,0x3a,0x21,0x77,0x65,0xa6,0xdc,0xbd,0x94,0xf2,0xc5,0x5b, + 0x30,0x44,0x02,0x20,0x2e,0x47,0x21,0x36,0x3a,0xd3,0x99,0x2c,0x13,0x9e,0x5a,0x1c,0x26,0x39,0x5d,0x2c,0x2d,0x77,0x78,0x24,0xaa,0x24,0xfd,0xe0,0x75,0xe0,0xd7,0x38,0x11,0x71,0x30,0x9d,0x02,0x20,0x74,0x0f,0x7c,0x49,0x44,0x18,0xe1,0x30,0x0d,0xd4,0x51,0x2f,0x78,0x2a,0x58,0x80,0x0b,0xff,0x6a,0x7a,0xbd,0xfd,0xd2,0x0f,0xbb,0xd4,0xf0,0x55,0x15,0xca,0x1a,0x4f, + 0x30,0x44,0x02,0x20,0x68,0x52,0xe9,0xd3,0xcd,0x9f,0xe3,0x73,0xc2,0xd5,0x04,0x87,0x79,0x67,0xd3,0x65,0xab,0x14,0x56,0x70,0x7b,0x68,0x17,0xa0,0x42,0x86,0x46,0x94,0xe1,0x96,0x0c,0xcf,0x02,0x20,0x06,0x4b,0x27,0xea,0x14,0x2b,0x30,0x88,0x7b,0x84,0xc8,0x6a,0xdc,0xcb,0x2f,0xa3,0x9a,0x69,0x11,0xad,0x21,0xfc,0x7e,0x81,0x9f,0x59,0x3b,0xe5,0x2b,0xc4,0xf3,0xbd, + 0x30,0x44,0x02,0x20,0x18,0x8a,0x8c,0x56,0x48,0xdc,0x79,0xea,0xce,0x15,0x8c,0xf8,0x86,0xc6,0x2b,0x54,0x68,0xf0,0x5f,0xd9,0x5f,0x03,0xa7,0x63,0x5c,0x5b,0x4c,0x31,0xf0,0x9a,0xf4,0xc5,0x02,0x20,0x36,0x36,0x1a,0x0b,0x57,0x1a,0x00,0xc6,0xcd,0x5e,0x68,0x6c,0xcb,0xfc,0xfa,0x70,0x3c,0x4f,0x97,0xe4,0x89,0x38,0x34,0x6d,0x0c,0x10,0x3f,0xdc,0x76,0xdc,0x58,0x67, + 0x30,0x45,0x02,0x21,0x00,0xa7,0x4f,0x1f,0xb9,0xa8,0x26,0x3f,0x62,0xfc,0x44,0x16,0xa5,0xb7,0xd5,0x84,0xf4,0x20,0x6f,0x39,0x96,0xbb,0x91,0xf6,0xfc,0x8e,0x73,0xb9,0xe9,0x2b,0xad,0x0e,0x13,0x02,0x20,0x68,0x15,0x03,0x2e,0x8c,0x7d,0x76,0xc3,0xab,0x06,0xa8,0x6f,0x33,0x24,0x9c,0xe9,0x94,0x01,0x48,0xcb,0x36,0xd1,0xf4,0x17,0xc2,0xe9,0x92,0xe8,0x01,0xaf,0xa3,0xfa, + 0x30,0x44,0x02,0x20,0x07,0x24,0x48,0x65,0xb7,0x2f,0xf3,0x7e,0x62,0xe3,0x14,0x6f,0x0d,0xc1,0x46,0x82,0xba,0xdd,0x71,0x97,0x79,0x91,0x35,0xf0,0xb0,0x0a,0xde,0x76,0x71,0x74,0x2b,0xfe,0x02,0x20,0x0d,0x80,0xc2,0x23,0x8e,0xdb,0x4e,0x4a,0x7a,0x86,0xa8,0xc5,0x7c,0xa9,0xaf,0x17,0x11,0xf4,0x06,0xf7,0xf5,0xda,0x02,0x99,0xaa,0x04,0xe2,0x93,0x2d,0x96,0x07,0x54, + 0x30,0x45,0x02,0x21,0x00,0xda,0x7f,0xdd,0x05,0xb5,0xba,0xda,0xbd,0x61,0x9d,0x80,0x5c,0x4e,0xe7,0xd9,0xa8,0x4f,0x84,0xdd,0xd5,0xcf,0x9c,0x5b,0xf4,0xd4,0x33,0x81,0x40,0xd6,0x89,0xef,0x08,0x02,0x20,0x28,0xf1,0xcf,0x4f,0xa1,0xc3,0xc5,0x86,0x2c,0xfa,0x14,0x9c,0x00,0x13,0xcf,0x5f,0xe6,0xcf,0x50,0x76,0xca,0xe0,0x00,0x51,0x10,0x63,0xe7,0xde,0x25,0xbb,0x38,0xe5, + 0x30,0x45,0x02,0x21,0x00,0xd3,0x02,0x7c,0x65,0x6f,0x6d,0x4f,0xdf,0xd8,0xed,0xe2,0x20,0x93,0xe3,0xc3,0x03,0xb0,0x13,0x3c,0x34,0x0d,0x61,0x5e,0x77,0x56,0xf6,0x25,0x3a,0xea,0x92,0x72,0x38,0x02,0x20,0x09,0xae,0xf0,0x60,0xc8,0xe4,0xce,0xf9,0x72,0x97,0x40,0x11,0x55,0x8d,0xf1,0x44,0xfe,0xd2,0x5c,0xa6,0x9a,0xe8,0xd0,0xb2,0xea,0xf1,0xa8,0xfe,0xef,0xbe,0xc4,0x17, + 0x30,0x44,0x02,0x20,0x0b,0xf6,0xc0,0x18,0x8d,0xc9,0x57,0x1c,0xd0,0xe2,0x1e,0xec,0xac,0x5f,0xbb,0x19,0xd2,0x43,0x49,0x88,0xe9,0xcc,0x10,0x24,0x45,0x93,0xef,0x3a,0x98,0x09,0x9f,0x69,0x02,0x20,0x48,0x64,0xa5,0x62,0x66,0x1f,0x92,0x21,0xec,0x88,0xe3,0xdd,0x0b,0xc2,0xf6,0xe2,0x7a,0xc1,0x28,0xc3,0x0c,0xc1,0xa8,0x0f,0x79,0xec,0x67,0x0a,0x22,0xb0,0x42,0xee, + 0x30,0x45,0x02,0x21,0x00,0xae,0x45,0x96,0x40,0xd5,0xd1,0x17,0x9b,0xe4,0x7a,0x47,0xfa,0x53,0x8e,0x16,0xd9,0x4d,0xde,0xa5,0x58,0x5e,0x7a,0x24,0x48,0x04,0xa5,0x17,0x42,0xc6,0x86,0x44,0x3a,0x02,0x20,0x6c,0x8e,0x30,0xe5,0x30,0xa6,0x34,0xfa,0xe8,0x0b,0x3c,0xeb,0x06,0x29,0x78,0xb3,0x9e,0xdb,0xe1,0x97,0x77,0xe0,0xa2,0x45,0x53,0xb6,0x88,0x86,0x18,0x1f,0xd8,0x97, + 0x30,0x44,0x02,0x20,0x1c,0xf3,0x51,0x7b,0xa3,0xbf,0x2a,0xb8,0xb9,0xea,0xd4,0xeb,0xb6,0xe8,0x66,0xcb,0x88,0xa1,0xde,0xac,0xb6,0xa7,0x85,0xd3,0xb6,0x3b,0x48,0x3c,0xa0,0x2a,0xc4,0x95,0x02,0x20,0x24,0x9a,0x79,0x8b,0x73,0x60,0x6f,0x55,0xf5,0xf1,0xc7,0x0d,0xe6,0x7c,0xb1,0xa0,0xcf,0xf9,0x5d,0x7d,0xc5,0x0b,0x3a,0x61,0x7d,0xf8,0x61,0xba,0xd3,0xc6,0xb1,0xc9, + 0x30,0x45,0x02,0x21,0x00,0xe6,0x9b,0x52,0x38,0x26,0x5e,0xa3,0x5d,0x77,0xe4,0xdd,0x17,0x22,0x88,0xd8,0xce,0xa1,0x98,0x10,0xa1,0x02,0x92,0x61,0x7d,0x59,0x76,0x51,0x9d,0xc5,0x75,0x7c,0xb8,0x02,0x20,0x4b,0x03,0xc5,0xbc,0x47,0xe8,0x26,0xbd,0xb2,0x73,0x28,0xab,0xd3,0x8d,0x30,0x56,0xd7,0x74,0x76,0xb2,0x13,0x0f,0x3d,0xf6,0xec,0x48,0x91,0xaf,0x08,0xba,0x1e,0x29, + 0x30,0x44,0x02,0x20,0x5f,0x9d,0x7d,0x7c,0x87,0x0d,0x08,0x5f,0xc1,0xd4,0x9f,0xff,0x69,0xe4,0xa2,0x75,0x81,0x28,0x00,0xd2,0xcf,0x89,0x73,0xe7,0x32,0x58,0x66,0xcb,0x40,0xfa,0x2b,0x6f,0x02,0x20,0x6d,0x1f,0x54,0x91,0xd9,0xf7,0x17,0xa5,0x97,0xa1,0x5f,0xd5,0x40,0x40,0x64,0x86,0xd7,0x6a,0x44,0x69,0x7b,0x3f,0x0d,0x9d,0x6d,0xce,0xf6,0x66,0x9f,0x8a,0x0a,0x56, + 0x30,0x44,0x02,0x20,0x0a,0x7d,0x5b,0x19,0x59,0xf7,0x1d,0xf9,0xf8,0x17,0x14,0x6e,0xe4,0x9b,0xd5,0xc8,0x9b,0x43,0x1e,0x79,0x93,0xe2,0xfd,0xec,0xab,0x68,0x58,0x95,0x7d,0xa6,0x85,0xae,0x02,0x20,0x0f,0x8a,0xad,0x2d,0x25,0x46,0x90,0xbd,0xc1,0x3f,0x34,0xa4,0xfe,0xc4,0x4a,0x02,0xfd,0x74,0x5a,0x42,0x2d,0xf0,0x5c,0xcb,0xb5,0x46,0x35,0xa8,0xb8,0x6b,0x96,0x09, + 0x30,0x44,0x02,0x20,0x79,0xe8,0x8b,0xf5,0x76,0xb7,0x4b,0xc0,0x7c,0xa1,0x42,0x39,0x5f,0xda,0x28,0xf0,0x3d,0x3d,0x5e,0x64,0x0b,0x0b,0x4f,0xf0,0x75,0x2c,0x6d,0x94,0xcd,0x55,0x34,0x08,0x02,0x20,0x32,0xce,0xa0,0x5b,0xd2,0xd7,0x06,0xc8,0xf6,0x03,0x6a,0x50,0x7e,0x2a,0xb7,0x76,0x60,0x04,0xf0,0x90,0x4e,0x2e,0x5c,0x58,0x62,0x74,0x9c,0x00,0x73,0x24,0x5d,0x6a, + 0x30,0x45,0x02,0x21,0x00,0x9d,0x54,0xe0,0x37,0xa0,0x02,0x12,0xb3,0x77,0xbc,0x88,0x74,0x79,0x8b,0x8d,0xa0,0x80,0x56,0x4b,0xbd,0xf7,0xe0,0x75,0x91,0xb8,0x61,0x28,0x58,0x09,0xd0,0x14,0x88,0x02,0x20,0x18,0xb4,0xe5,0x57,0x66,0x7a,0x82,0xbd,0x95,0x96,0x5f,0x07,0x06,0xf8,0x1a,0x29,0x24,0x3f,0xbd,0xd8,0x69,0x68,0xa7,0xeb,0xeb,0x43,0x06,0x9d,0xb3,0xb1,0x8c,0x7f, + 0x30,0x44,0x02,0x20,0x26,0x64,0xf1,0xff,0xa9,0x82,0xfe,0xdb,0xcc,0x7c,0xab,0x1b,0x8b,0xc6,0xe2,0xcb,0x42,0x02,0x18,0xd2,0xa6,0x07,0x7a,0xd0,0x8e,0x59,0x1b,0xa9,0xfe,0xab,0x33,0xbd,0x02,0x20,0x49,0xf5,0xc7,0xcb,0x51,0x5e,0x83,0x87,0x2a,0x3d,0x41,0xb4,0xcd,0xb8,0x5f,0x24,0x2a,0xd9,0xd6,0x1a,0x5b,0xfc,0x01,0xde,0xbf,0xbb,0x52,0xc6,0xc8,0x4b,0xa7,0x28, + 0x30,0x44,0x02,0x20,0x58,0x27,0x51,0x83,0x44,0x84,0x4f,0xd6,0xa7,0xde,0x73,0xcb,0xb0,0xa6,0xbe,0xfd,0xea,0x7b,0x13,0xd2,0xde,0xe4,0x47,0x53,0x17,0xf0,0xf1,0x8f,0xfc,0x81,0x52,0x4b,0x02,0x20,0x4f,0x5c,0xcb,0x4e,0x0b,0x48,0x8b,0x5a,0x5d,0x76,0x0a,0xac,0xdd,0xb2,0xd7,0x91,0x97,0x0f,0xe4,0x3d,0xa6,0x1e,0xb3,0x0e,0x2e,0x90,0x20,0x8a,0x81,0x7e,0x46,0xdb, + 0x30,0x45,0x02,0x21,0x00,0x97,0xab,0x19,0xbd,0x13,0x9c,0xac,0x31,0x93,0x25,0x86,0x92,0x18,0xb1,0xbc,0xe1,0x11,0x87,0x5d,0x63,0xfb,0x12,0x09,0x8a,0x04,0xb0,0xcd,0x59,0xb6,0xfd,0xd3,0xa3,0x02,0x20,0x43,0x1d,0x9c,0xea,0x3a,0x24,0x38,0x47,0x30,0x3c,0xeb,0xda,0x56,0x47,0x64,0x31,0xd0,0x34,0x33,0x9f,0x31,0xd7,0x85,0xee,0x88,0x52,0xdb,0x4f,0x04,0x0d,0x49,0x21, + 0x30,0x44,0x02,0x20,0x52,0xc6,0x83,0x14,0x4e,0x44,0x11,0x9a,0xe2,0x01,0x37,0x49,0xd4,0x96,0x4e,0xf6,0x75,0x09,0x27,0x8f,0x6d,0x38,0xba,0x86,0x9a,0xdc,0xfa,0x69,0x97,0x0e,0x12,0x3d,0x02,0x20,0x34,0x79,0x91,0x01,0x67,0x40,0x8f,0x45,0xbd,0xa4,0x20,0xa6,0x26,0xec,0x9c,0x4e,0xc7,0x11,0xc1,0x27,0x4b,0xe0,0x92,0x19,0x8b,0x41,0x87,0xc0,0x18,0xb5,0x62,0xca, + 0x30,0x16,0x02,0x11,0x01,0x45,0x51,0x23,0x19,0x50,0xb7,0x5f,0xc4,0x40,0x2d,0xa1,0x72,0x2f,0xc9,0xba,0xeb,0x02,0x01,0x03, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2c,0x02,0x01,0x03, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x3f,0x02,0x01,0x03, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3e,0x9a,0x75,0x82,0x88,0x60,0x89,0xc6,0x2f,0xb8,0x40,0xcf,0x3b,0x83,0x06,0x1c,0xd1,0xcf,0xf3,0xae,0x43,0x41,0x80,0x8b,0xb5,0xbd,0xee,0x61,0x91,0x17,0x41,0x77, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x24,0x23,0x8e,0x70,0xb4,0x31,0xb1,0xa6,0x4e,0xfd,0xf9,0x03,0x26,0x69,0x93,0x9d,0x4b,0x77,0xf2,0x49,0x50,0x3f,0xc6,0x90,0x5f,0xeb,0x75,0x40,0xde,0xa3,0xe6,0xd2, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x02, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x03, + 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x02, + 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x03, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x43,0x02,0x01,0x03, + 0x30,0x08,0x02,0x01,0x02,0x02,0x03,0xed,0x29,0x79, + 0x30,0x26,0x02,0x02,0x01,0x01,0x02,0x20,0x3a,0x74,0xe9,0xd3,0xa7,0x4e,0x9d,0x3a,0x74,0xe9,0xd3,0xa7,0x4e,0x9d,0x3a,0x74,0x9f,0x8a,0xb3,0x73,0x2a,0x0a,0x89,0x60,0x4a,0x09,0xbc,0xe5,0xb2,0x91,0x6d,0xa4, + 0x30,0x2b,0x02,0x07,0x2d,0x9b,0x4d,0x34,0x79,0x52,0xcc,0x02,0x20,0x03,0x43,0xae,0xfc,0x2f,0x25,0xd9,0x8b,0x88,0x2e,0x86,0xeb,0x9e,0x30,0xd5,0x5a,0x6e,0xb5,0x08,0xb5,0x16,0x51,0x0b,0x34,0x02,0x4a,0xe4,0xb6,0x36,0x23,0x30,0xb3, + 0x30,0x31,0x02,0x0d,0x10,0x33,0xe6,0x7e,0x37,0xb3,0x2b,0x44,0x55,0x80,0xbf,0x4e,0xfc,0x02,0x20,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x8f,0xe1,0xca,0xb5,0xee,0xfd,0xb2,0x14,0x06,0x1d,0xce,0x3b,0x22,0x78,0x9f,0x1d,0x6f, + 0x30,0x26,0x02,0x02,0x01,0x01,0x02,0x20,0x78,0x32,0x66,0xe9,0x0f,0x43,0xda,0xfe,0x5c,0xd9,0xb3,0xb0,0xbe,0x86,0xde,0x22,0xf9,0xde,0x83,0x67,0x7d,0x0f,0x50,0x71,0x3a,0x46,0x8e,0xc7,0x2f,0xcf,0x5d,0x57, + 0x30,0x31,0x02,0x0d,0x06,0x25,0x22,0xbb,0xd3,0xec,0xbe,0x7c,0x39,0xe9,0x3e,0x7c,0x26,0x02,0x20,0x78,0x32,0x66,0xe9,0x0f,0x43,0xda,0xfe,0x5c,0xd9,0xb3,0xb0,0xbe,0x86,0xde,0x22,0xf9,0xde,0x83,0x67,0x7d,0x0f,0x50,0x71,0x3a,0x46,0x8e,0xc7,0x2f,0xcf,0x5d,0x57, + 0x30,0x45,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x40,0xc1,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, + 0x30,0x16,0x02,0x09,0x00,0x9c,0x44,0xfe,0xbf,0x31,0xc3,0x59,0x4d,0x02,0x09,0x00,0x83,0x9e,0xd2,0x82,0x47,0xc2,0xb0,0x6b, + 0x30,0x1e,0x02,0x0d,0x09,0xdf,0x8b,0x68,0x24,0x30,0xbe,0xef,0x6f,0x5f,0xd7,0xc7,0xcf,0x02,0x0d,0x0f,0xd0,0xa6,0x2e,0x13,0x77,0x8f,0x42,0x22,0xa0,0xd6,0x1c,0x8a, + 0x30,0x26,0x02,0x11,0x00,0x8a,0x59,0x8e,0x56,0x3a,0x89,0xf5,0x26,0xc3,0x2e,0xbe,0xc8,0xde,0x26,0x36,0x7a,0x02,0x11,0x00,0x84,0xf6,0x33,0xe2,0x04,0x26,0x30,0xe9,0x9d,0xd0,0xf1,0xe1,0x6f,0x7a,0x04,0xbf, + 0x30,0x2e,0x02,0x15,0x00,0xaa,0x6e,0xeb,0x58,0x23,0xf7,0xfa,0x31,0xb4,0x66,0xbb,0x47,0x37,0x97,0xf0,0xd0,0x31,0x4c,0x0b,0xdf,0x02,0x15,0x00,0xe2,0x97,0x7c,0x47,0x9e,0x6d,0x25,0x70,0x3c,0xeb,0xbc,0x6b,0xd5,0x61,0x93,0x8c,0xc9,0xd1,0xbf,0xb9, + 0x30,0x25,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x01,0x01, + 0x30,0x25,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x01,0x00, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x41,0x9d,0x98,0x1c,0x51,0x5a,0xf8,0xcc,0x82,0x54,0x5a,0xac,0x0c,0x85,0xe9,0xe3,0x08,0xfb,0xb2,0xea,0xb6,0xac,0xd7,0xed,0x49,0x7e,0x0b,0x41,0x45,0xa1,0x8f,0xd9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x1b,0x21,0x71,0x7a,0xd7,0x1d,0x23,0xbb,0xac,0x60,0xa9,0xad,0x0b,0xaf,0x75,0xb0,0x63,0xc9,0xfd,0xf5,0x2a,0x00,0xeb,0xf9,0x9d,0x02,0x21,0x72,0x91,0x09,0x93,0xc9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x2f,0x58,0x8f,0x66,0x01,0x8f,0x3d,0xd1,0x4d,0xb3,0xe2,0x8e,0x77,0x99,0x64,0x87,0xe3,0x24,0x86,0xb5,0x21,0xed,0x8e,0x5a,0x20,0xf0,0x65,0x91,0x95,0x17,0x77,0xe9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x09,0x1a,0x08,0x87,0x0f,0xf4,0xda,0xf9,0x12,0x3b,0x30,0xc2,0x0e,0x8c,0x4f,0xc8,0x50,0x57,0x58,0xdc,0xf4,0x07,0x4f,0xca,0xff,0x21,0x70,0xc9,0xbf,0xcf,0x74,0xf4, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x7c,0x37,0x0d,0xc0,0xce,0x8c,0x59,0xa8,0xb2,0x73,0xcb,0xa4,0x4a,0x7c,0x11,0x91,0xfc,0x31,0x86,0xdc,0x03,0xca,0xb9,0x6b,0x05,0x67,0x31,0x2d,0xf0,0xd0,0xb2,0x50, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x70,0xb5,0x9a,0x7d,0x1e,0xe7,0x7a,0x2f,0x9e,0x04,0x91,0xc2,0xa7,0xcf,0xcd,0x0e,0xd0,0x4d,0xf4,0xa3,0x51,0x92,0xf6,0x13,0x2d,0xcc,0x66,0x8c,0x79,0xa6,0x16,0x0e, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x27,0x36,0xd7,0x6e,0x41,0x22,0x46,0xe0,0x97,0x14,0x8e,0x2b,0xf6,0x29,0x15,0x61,0x4e,0xb7,0xc4,0x28,0x91,0x3a,0x58,0xeb,0x5e,0x9c,0xd4,0x67,0x4a,0x94,0x23,0xde, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x4a,0x1e,0x12,0x83,0x1f,0xbe,0x93,0x62,0x7b,0x02,0xd6,0xe7,0xf2,0x4b,0xcc,0xdd,0x6e,0xf4,0xb2,0xd0,0xf4,0x67,0x39,0xea,0xf3,0xb1,0xea,0xf0,0xca,0x11,0x77,0x70, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x06,0xc7,0x78,0xd4,0xdf,0xff,0x7d,0xee,0x06,0xed,0x88,0xbc,0x4e,0x0e,0xd3,0x4f,0xc5,0x53,0xaa,0xd6,0x7c,0xaf,0x79,0x6f,0x2a,0x1c,0x64,0x87,0xc1,0xb2,0xe8,0x77, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x4d,0xe4,0x59,0xef,0x91,0x59,0xaf,0xa0,0x57,0xfe,0xb3,0xec,0x40,0xfe,0xf0,0x1c,0x45,0xb8,0x09,0xf4,0xab,0x29,0x6e,0xa4,0x8c,0x20,0x6d,0x42,0x49,0xa2,0xb4,0x51, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x74,0x5d,0x29,0x49,0x78,0x00,0x73,0x02,0x03,0x35,0x02,0xe1,0xac,0xc4,0x8b,0x63,0xae,0x65,0x00,0xbe,0x43,0xad,0xbe,0xa1,0xb2,0x58,0xd6,0xb4,0x23,0xdb,0xb4,0x16, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x7b,0x2a,0x78,0x5e,0x38,0x96,0xf5,0x9b,0x2d,0x69,0xda,0x57,0x64,0x8e,0x80,0xad,0x3c,0x13,0x3a,0x75,0x0a,0x28,0x47,0xfd,0x20,0x98,0xcc,0xd9,0x02,0x04,0x2b,0x6c, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x71,0xae,0x94,0xa7,0x2c,0xa8,0x96,0x87,0x5e,0x7a,0xa4,0xa4,0xc3,0xd2,0x9a,0xfd,0xb4,0xb3,0x5b,0x69,0x96,0x27,0x3e,0x63,0xc4,0x7a,0xc5,0x19,0x25,0x6c,0x5e,0xb1, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x0f,0xa5,0x27,0xfa,0x73,0x43,0xc0,0xbc,0x9e,0xc3,0x5a,0x62,0x78,0xbf,0xbf,0xf4,0xd8,0x33,0x01,0xb1,0x54,0xfc,0x4b,0xd1,0x4a,0xee,0x7e,0xb9,0x34,0x45,0xb5,0xf9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x65,0x39,0xc0,0xad,0xad,0xd0,0x52,0x5f,0xf4,0x26,0x22,0x16,0x4c,0xe9,0x31,0x43,0x48,0xbd,0x08,0x63,0xb4,0xc8,0x0e,0x93,0x6b,0x23,0xca,0x04,0x14,0x26,0x46,0x71, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa1, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x16,0xe1,0xe4,0x59,0x45,0x76,0x79,0xdf,0x5b,0x94,0x34,0xae,0x23,0xf4,0x74,0xb3,0xe8,0xd2,0xa7,0x0b,0xd6,0xb5,0xdb,0xe6,0x92,0xba,0x16,0xda,0x01,0xf1,0xfb,0x0a, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x1c,0x94,0x0f,0x31,0x3f,0x92,0x64,0x7b,0xe2,0x57,0xec,0xcd,0x7e,0xd0,0x8b,0x0b,0xae,0xf3,0xf0,0x47,0x8f,0x25,0x87,0x1b,0x53,0x63,0x53,0x02,0xc5,0xf6,0x31,0x4a, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x15,0xd9,0x4a,0x85,0x07,0x7b,0x49,0x3f,0x91,0xcb,0x71,0x01,0xec,0x63,0xe1,0xb0,0x1b,0xe5,0x8b,0x59,0x4e,0x85,0x5f,0x45,0x05,0x0a,0x8c,0x14,0x06,0x2d,0x68,0x9b, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x5b,0x1d,0x27,0xa7,0x69,0x4c,0x14,0x62,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9d,0x9e,0xf3,0xb9,0xfb,0x58,0x38,0x54,0x18,0xd9,0xc9,0x82,0x10,0x50,0x77,0xd1,0xb7, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2d,0x85,0x89,0x6b,0x3e,0xb9,0xdb,0xb5,0xa5,0x2f,0x42,0xf9,0xc9,0x26,0x1e,0xd3,0xfc,0x46,0x64,0x4e,0xc6,0x5f,0x06,0xad,0xe3,0xfd,0x78,0xf2,0x57,0xe4,0x34,0x32, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x5b,0x0b,0x12,0xd6,0x7d,0x73,0xb7,0x6b,0x4a,0x5e,0x85,0xf3,0x92,0x4c,0x3d,0xa7,0xf8,0x8c,0xc8,0x9d,0x8c,0xbe,0x0d,0x5b,0xc7,0xfa,0xf1,0xe4,0xaf,0xc8,0x68,0x64, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x69,0x4c,0x14,0x62,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x09,0xe6,0x0e,0x68,0xb9,0x0d,0x0b,0x5e,0x6c,0x5d,0xdd,0xd0,0xcb,0x69,0x4d,0x87,0x99, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3d,0x7f,0x48,0x7c,0x07,0xbf,0xc5,0xf3,0x08,0x46,0x93,0x8a,0x3d,0xce,0xf6,0x96,0x44,0x47,0x07,0xcf,0x96,0x77,0x25,0x4a,0x92,0xb0,0x6c,0x63,0xab,0x86,0x7d,0x22, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x6c,0x76,0x48,0xfc,0x0f,0xbf,0x8a,0x06,0xad,0xb8,0xb8,0x39,0xf9,0x7b,0x4f,0xf7,0xa8,0x00,0xf1,0x1b,0x1e,0x37,0xc5,0x93,0xb2,0x61,0x39,0x45,0x99,0x79,0x2b,0xa4, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x64,0x1c,0x9c,0x5d,0x79,0x0d,0xc0,0x9c,0xdd,0x3d,0xfa,0xbb,0x62,0xcd,0xf4,0x53,0xe6,0x97,0x47,0xa7,0xe3,0xd7,0xaa,0x1a,0x71,0x41,0x89,0xef,0x53,0x17,0x1a,0x99, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x29,0x79,0x8c,0x5c,0x45,0xbd,0xf5,0x8b,0x4a,0x7b,0x2f,0xdc,0x2c,0x46,0xab,0x4a,0xf1,0x21,0x8c,0x7e,0xeb,0x9f,0x0f,0x27,0xa8,0x8f,0x12,0x67,0x67,0x4d,0xe3,0xb0, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x0b,0x70,0xf2,0x2c,0xa2,0xbb,0x3c,0xef,0xad,0xca,0x1a,0x57,0x11,0xfa,0x3a,0x59,0xf4,0x69,0x53,0x85,0xeb,0x5a,0xed,0xf3,0x49,0x5d,0x0b,0x6d,0x00,0xf8,0xfd,0x85, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x16,0xe1,0xe4,0x59,0x45,0x76,0x79,0xdf,0x5b,0x94,0x34,0xae,0x23,0xf4,0x74,0xb3,0xe8,0xd2,0xa7,0x0b,0xd6,0xb5,0xdb,0xe6,0x92,0xba,0x16,0xda,0x01,0xf1,0xfb,0x0a, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x22,0x52,0xd6,0x85,0xe8,0x31,0xb6,0xcf,0x09,0x5e,0x4f,0x05,0x35,0xee,0xaf,0x0d,0xdd,0x3b,0xfa,0x91,0xc2,0x10,0xc9,0xd9,0xdc,0x17,0x22,0x47,0x02,0xea,0xf8,0x8f, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x75,0x13,0x5a,0xbd,0x7c,0x42,0x5b,0x60,0x37,0x1a,0x47,0x7f,0x09,0xce,0x0f,0x27,0x4f,0x64,0xa8,0xc6,0xb0,0x61,0xa0,0x7b,0x5d,0x63,0xe9,0x3c,0x65,0x04,0x6c,0x53, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x17, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3e,0x88,0x83,0x77,0xac,0x6c,0x71,0xac,0x9d,0xec,0x3f,0xdb,0x9b,0x56,0xc9,0xfe,0xaf,0x0c,0xfa,0xca,0x9f,0x82,0x7f,0xc5,0xeb,0x65,0xfc,0x3e,0xac,0x81,0x12,0x10, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x30,0xbb,0xb7,0x94,0xdb,0x58,0x83,0x63,0xb4,0x06,0x79,0xf6,0xc1,0x82,0xa5,0x0d,0x3c,0xe9,0x67,0x9a,0xcd,0xd3,0xff,0xbe,0x36,0xd7,0x81,0x3d,0xac,0xbd,0xc8,0x18, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2c,0x37,0xfd,0x99,0x56,0x22,0xc4,0xfb,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc7,0xce,0xe7,0x45,0x11,0x0c,0xb4,0x5a,0xb5,0x58,0xed,0x7c,0x90,0xc1,0x5a,0x2f, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x7f,0xd9,0x95,0x62,0x2c,0x4f,0xb7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x88,0x3f,0xfa,0xb5,0xb3,0x26,0x52,0xcc,0xdc,0xaa,0x29,0x0f,0xcc,0xb9,0x7d, + 0x30,0x43,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x1f,0x4c,0xd5,0x3b,0xa7,0x60,0x8f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x9e,0x5c,0xf1,0x43,0xe2,0x53,0x96,0x26,0x19,0x0a,0x3a,0xb0,0x9c,0xce,0x47, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x56,0x22,0xc4,0xfb,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x92,0x8a,0x8f,0x1c,0x7a,0xc7,0xbe,0xc1,0x80,0x8b,0x9f,0x61,0xc0,0x1e,0xc3,0x27, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x44,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x03,0xb8,0x78,0x53,0xfd,0x3b,0x7d,0x3f,0x8e,0x17,0x51,0x25,0xb4,0x38,0x2f,0x25,0xed, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x27,0x39,0xce,0x73,0x9c,0xe7,0x39,0xce,0x73,0x9c,0xe7,0x39,0xce,0x73,0x9c,0xe7,0x05,0x56,0x02,0x98,0xd1,0xf2,0xf0,0x8d,0xc4,0x19,0xac,0x27,0x3a,0x5b,0x54,0xd9, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x48,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x31,0xc8,0x3a,0xe8,0x2e,0xbe,0x08,0x98,0x77,0x6b,0x4c,0x69,0xd1,0x1f,0x88,0xde, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x64,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x06,0xdd,0x3a,0x19,0xb8,0xd5,0xfb,0x87,0x52,0x35,0x96,0x3c,0x59,0x3b,0xd2,0xd3, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x6a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x15, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x17, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x18,0x5d,0xdb,0xca,0x6d,0xac,0x41,0xb1,0xda,0x03,0x3c,0xfb,0x60,0xc1,0x52,0x86,0x9e,0x74,0xb3,0xcd,0x66,0xe9,0xff,0xdf,0x1b,0x6b,0xc0,0x9e,0xd6,0x5e,0xe4,0x0c, + 0x30,0x44,0x02,0x20,0x32,0xb0,0xd1,0x0d,0x8d,0x0e,0x04,0xbc,0x8d,0x4d,0x06,0x4d,0x27,0x06,0x99,0xe8,0x7c,0xff,0xc9,0xb4,0x9c,0x5c,0x20,0x73,0x0e,0x1c,0x26,0xf6,0x10,0x5d,0xdc,0xda,0x02,0x20,0x29,0xed,0x3d,0x67,0xb3,0xd5,0x05,0xbe,0x95,0x58,0x0d,0x77,0xd5,0xb7,0x92,0xb4,0x36,0x88,0x11,0x79,0xb2,0xb6,0xb2,0xe0,0x4c,0x5f,0xe5,0x92,0xd3,0x8d,0x82,0xd9, + 0x30,0x44,0x02,0x20,0x32,0xb0,0xd1,0x0d,0x8d,0x0e,0x04,0xbc,0x8d,0x4d,0x06,0x4d,0x27,0x06,0x99,0xe8,0x7c,0xff,0xc9,0xb4,0x9c,0x5c,0x20,0x73,0x0e,0x1c,0x26,0xf6,0x10,0x5d,0xdc,0xda,0x02,0x20,0x29,0xed,0x3d,0x67,0xb3,0xd5,0x05,0xbe,0x95,0x58,0x0d,0x77,0xd5,0xb7,0x92,0xb4,0x36,0x88,0x11,0x79,0xb2,0xb6,0xb2,0xe0,0x4c,0x5f,0xe5,0x92,0xd3,0x8d,0x82,0xd9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0,0x02,0x20,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x32,0xf2,0x22,0xf8,0xfa,0xef,0xdb,0x53,0x3f,0x26,0x5d,0x46,0x1c,0x29,0xa4,0x73,0x73, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x0e,0xb1,0x0e,0x5a,0xb9,0x5f,0x2f,0x27,0x53,0x48,0xd8,0x2a,0xd2,0xe4,0xd7,0x94,0x9c,0x81,0x93,0x80,0x0d,0x8c,0x9c,0x75,0xdf,0x58,0xe3,0x43,0xf0,0xeb,0xba,0x7b, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x0e,0xb1,0x0e,0x5a,0xb9,0x5f,0x2f,0x27,0x53,0x48,0xd8,0x2a,0xd2,0xe4,0xd7,0x94,0x9c,0x81,0x93,0x80,0x0d,0x8c,0x9c,0x75,0xdf,0x58,0xe3,0x43,0xf0,0xeb,0xba,0x7b, + 0x30,0x45,0x02,0x21,0x00,0xbb,0x5a,0x52,0xf4,0x2f,0x9c,0x92,0x61,0xed,0x43,0x61,0xf5,0x94,0x22,0xa1,0xe3,0x00,0x36,0xe7,0xc3,0x2b,0x27,0x0c,0x88,0x07,0xa4,0x19,0xfe,0xca,0x60,0x50,0x23,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, + 0x30,0x44,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, + 0x30,0x45,0x02,0x21,0x00,0xbb,0x5a,0x52,0xf4,0x2f,0x9c,0x92,0x61,0xed,0x43,0x61,0xf5,0x94,0x22,0xa1,0xe3,0x00,0x36,0xe7,0xc3,0x2b,0x27,0x0c,0x88,0x07,0xa4,0x19,0xfe,0xca,0x60,0x50,0x23,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, + 0x30,0x44,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, + 0x30,0x45,0x02,0x21,0x00,0xf8,0x0a,0xe4,0xf9,0x6c,0xdb,0xc9,0xd8,0x53,0xf8,0x3d,0x47,0xaa,0xe2,0x25,0xbf,0x40,0x7d,0x51,0xc5,0x6b,0x77,0x76,0xcd,0x67,0xd0,0xdc,0x19,0x5d,0x99,0xa9,0xdc,0x02,0x20,0x4c,0xfc,0x1d,0x94,0x1e,0x08,0xcb,0x9a,0xce,0xad,0xde,0x0f,0x4c,0xce,0xad,0x76,0xb3,0x0d,0x33,0x2f,0xc4,0x42,0x11,0x5d,0x50,0xe6,0x73,0xe2,0x86,0x86,0xb7,0x0b, + 0x30,0x44,0x02,0x20,0x10,0x9c,0xd8,0xae,0x03,0x74,0x35,0x89,0x84,0xa8,0x24,0x9c,0x0a,0x84,0x36,0x28,0xf2,0x83,0x5f,0xfa,0xd1,0xdf,0x1a,0x9a,0x69,0xaa,0x2f,0xe7,0x23,0x55,0x54,0x5c,0x02,0x20,0x53,0x90,0xff,0x25,0x0a,0xc4,0x27,0x4e,0x1c,0xb2,0x5c,0xd6,0xca,0x64,0x91,0xf6,0xb9,0x12,0x81,0xe3,0x2f,0x5b,0x26,0x4d,0x87,0x97,0x7a,0xed,0x4a,0x94,0xe7,0x7b, + 0x30,0x45,0x02,0x21,0x00,0xd0,0x35,0xee,0x1f,0x17,0xfd,0xb0,0xb2,0x68,0x1b,0x16,0x3e,0x33,0xc3,0x59,0x93,0x26,0x59,0x99,0x0a,0xf7,0x7d,0xca,0x63,0x20,0x12,0xb3,0x0b,0x27,0xa0,0x57,0xb3,0x02,0x20,0x19,0x39,0xd9,0xf3,0xb2,0x85,0x8b,0xc1,0x3e,0x34,0x74,0xcb,0x50,0xe6,0xa8,0x2b,0xe4,0x4f,0xaa,0x71,0x94,0x0f,0x87,0x6c,0x1c,0xba,0x4c,0x3e,0x98,0x92,0x02,0xb6, + 0x30,0x44,0x02,0x20,0x4f,0x05,0x3f,0x56,0x3a,0xd3,0x4b,0x74,0xfd,0x8c,0x99,0x34,0xce,0x59,0xe7,0x9c,0x2e,0xb8,0xe6,0xec,0xa0,0xfe,0xf5,0xb3,0x23,0xca,0x67,0xd5,0xac,0x7e,0xd2,0x38,0x02,0x20,0x4d,0x4b,0x05,0xda,0xa0,0x71,0x9e,0x77,0x3d,0x86,0x17,0xdc,0xe5,0x63,0x1c,0x5f,0xd6,0xf5,0x9c,0x9b,0xdc,0x74,0x8e,0x4b,0x55,0xc9,0x70,0x04,0x0a,0xf0,0x1b,0xe5, + 0x30,0x44,0x02,0x20,0x6d,0x6a,0x4f,0x55,0x6c,0xcc,0xe1,0x54,0xe7,0xfb,0x9f,0x19,0xe7,0x6c,0x3d,0xec,0xa1,0x3d,0x59,0xcc,0x2a,0xeb,0x4e,0xca,0xd9,0x68,0xaa,0xb2,0xde,0xd4,0x59,0x65,0x02,0x20,0x53,0xb9,0xfa,0x74,0x80,0x3e,0xde,0x0f,0xc4,0x44,0x1b,0xf6,0x83,0xd5,0x6c,0x56,0x4d,0x3e,0x27,0x4e,0x09,0xcc,0xf4,0x73,0x90,0xba,0xdd,0x14,0x71,0xc0,0x5f,0xb7, + 0x30,0x44,0x02,0x21,0x00,0xaa,0xd5,0x03,0xde,0x9b,0x9f,0xd6,0x6b,0x94,0x8e,0x9a,0xcf,0x59,0x6f,0x0a,0x0e,0x65,0xe7,0x00,0xb2,0x8b,0x26,0xec,0x56,0xe6,0xe4,0x5e,0x84,0x64,0x89,0xb3,0xc4,0x02,0x1f,0x0d,0xdc,0x3a,0x2f,0x89,0xab,0xb8,0x17,0xbb,0x85,0xc0,0x62,0xce,0x02,0xf8,0x23,0xc6,0x3f,0xc2,0x6b,0x26,0x9e,0x0b,0xc9,0xb8,0x4d,0x81,0xa5,0xaa,0x12,0x3d, + 0x30,0x45,0x02,0x21,0x00,0x91,0x82,0xce,0xbd,0x3b,0xb8,0xab,0x57,0x2e,0x16,0x71,0x74,0x39,0x72,0x09,0xef,0x4b,0x1d,0x43,0x9a,0xf3,0xb2,0x00,0xcd,0xf0,0x03,0x62,0x00,0x89,0xe4,0x32,0x25,0x02,0x20,0x54,0x47,0x7c,0x98,0x2e,0xa0,0x19,0xd2,0xe1,0x00,0x04,0x97,0xfc,0x25,0xfc,0xee,0x1b,0xcc,0xae,0x55,0xf2,0xac,0x27,0x53,0x0a,0xe5,0x3b,0x29,0xc4,0xb3,0x56,0xa4, + 0x30,0x44,0x02,0x20,0x38,0x54,0xa3,0x99,0x8a,0xeb,0xdf,0x2d,0xbc,0x28,0xad,0xac,0x41,0x81,0x46,0x2c,0xca,0xc7,0x87,0x39,0x07,0xab,0x7f,0x21,0x2c,0x42,0xdb,0x0e,0x69,0xb5,0x6e,0xd8,0x02,0x20,0x3e,0xd3,0xf6,0xb8,0xa3,0x88,0xd0,0x2f,0x3e,0x4d,0xf9,0xf2,0xae,0x9c,0x1b,0xd2,0xc3,0x91,0x6a,0x68,0x64,0x60,0xdf,0xfc,0xd4,0x29,0x09,0xcd,0x7f,0x82,0x05,0x8e, + 0x30,0x45,0x02,0x21,0x00,0xe9,0x4d,0xbd,0xc3,0x87,0x95,0xfe,0x5c,0x90,0x4d,0x8f,0x16,0xd9,0x69,0xd3,0xb5,0x87,0xf0,0xa2,0x5d,0x2d,0xe9,0x0b,0x6d,0x8c,0x5c,0x53,0xff,0x88,0x7e,0x36,0x07,0x02,0x20,0x7a,0x94,0x73,0x69,0xc1,0x64,0x97,0x25,0x21,0xbb,0x8a,0xf4,0x06,0x81,0x3b,0x2d,0x9f,0x94,0xd2,0xae,0xaa,0x53,0xd4,0xc2,0x15,0xaa,0xa0,0xa2,0x57,0x8a,0x2c,0x5d, + 0x30,0x44,0x02,0x20,0x49,0xfc,0x10,0x2a,0x08,0xca,0x47,0xb6,0x0e,0x08,0x58,0xcd,0x02,0x84,0xd2,0x2c,0xdd,0xd7,0x23,0x3f,0x94,0xaa,0xff,0xbb,0x2d,0xb1,0xdd,0x2c,0xf0,0x84,0x25,0xe1,0x02,0x20,0x5b,0x16,0xfc,0xa5,0xa1,0x2c,0xdb,0x39,0x70,0x16,0x97,0xad,0x8e,0x39,0xff,0xd6,0xbd,0xec,0x00,0x24,0x29,0x8a,0xfa,0xa2,0x32,0x6a,0xea,0x09,0x20,0x0b,0x14,0xd6, + 0x30,0x44,0x02,0x20,0x41,0xef,0xa7,0xd3,0xf0,0x5a,0x00,0x10,0x67,0x5f,0xcb,0x91,0x8a,0x45,0xc6,0x93,0xda,0x4b,0x34,0x8d,0xf2,0x1a,0x59,0xd6,0xf9,0xcd,0x73,0xe0,0xd8,0x31,0xd6,0x7a,0x02,0x20,0x44,0x54,0xad,0xa6,0x93,0xe5,0xe2,0x6b,0x7b,0xd6,0x93,0x23,0x6d,0x34,0x0f,0x80,0x54,0x5c,0x83,0x45,0x77,0xb6,0xf7,0x3d,0x37,0x8c,0x7b,0xcc,0x53,0x42,0x44,0xda, + 0x30,0x45,0x02,0x21,0x00,0xb6,0x15,0x69,0x8c,0x35,0x8b,0x35,0x92,0x0d,0xd8,0x83,0xec,0xa6,0x25,0xa6,0xc5,0xf7,0x56,0x39,0x70,0xcd,0xfc,0x37,0x8f,0x8f,0xe0,0xce,0xe1,0x70,0x92,0x14,0x4c,0x02,0x20,0x25,0xf4,0x7b,0x32,0x6b,0x5b,0xe1,0xfb,0x61,0x0b,0x88,0x51,0x53,0xea,0x84,0xd4,0x1e,0xb4,0x71,0x6b,0xe6,0x6a,0x99,0x4e,0x87,0x79,0x98,0x9d,0xf1,0xc8,0x63,0xd4, + 0x30,0x45,0x02,0x21,0x00,0x87,0xcf,0x8c,0x0e,0xb8,0x2d,0x44,0xf6,0x9c,0x60,0xa2,0xff,0x54,0x57,0xd3,0xaa,0xa3,0x22,0xe7,0xec,0x61,0xae,0x5a,0xec,0xfd,0x67,0x8a,0xe1,0xc1,0x93,0x2b,0x0e,0x02,0x20,0x3a,0xdd,0x3b,0x11,0x58,0x15,0x04,0x7d,0x6e,0xb3,0x40,0xa3,0xe0,0x08,0x98,0x9e,0xaa,0x0f,0x87,0x08,0xd1,0x79,0x48,0x14,0x72,0x90,0x94,0xd0,0x8d,0x24,0x60,0xd3, + 0x30,0x44,0x02,0x20,0x62,0xf4,0x8e,0xf7,0x1a,0xce,0x27,0xbf,0x5a,0x01,0x83,0x4d,0xe1,0xf7,0xe3,0xf9,0x48,0xb9,0xdc,0xe1,0xca,0x1e,0x91,0x1d,0x5e,0x13,0xd3,0xb1,0x04,0x47,0x1d,0x82,0x02,0x20,0x5e,0xa8,0xf3,0x3f,0x0c,0x77,0x89,0x72,0xc4,0x58,0x20,0x80,0xde,0xda,0x9b,0x34,0x18,0x57,0xdd,0x64,0x51,0x4f,0x08,0x49,0xa0,0x5f,0x69,0x64,0xc2,0xe3,0x40,0x22, + 0x30,0x45,0x02,0x21,0x00,0xf6,0xb0,0xe2,0xf6,0xfe,0x02,0x0c,0xf7,0xc0,0xc2,0x01,0x37,0x43,0x43,0x44,0xed,0x7a,0xdd,0x6c,0x4b,0xe5,0x18,0x61,0xe2,0xd1,0x4c,0xbd,0xa4,0x72,0xa6,0xff,0xb4,0x02,0x20,0x64,0x16,0xc8,0xdd,0x3e,0x5c,0x52,0x82,0xb3,0x06,0xe8,0xdc,0x8f,0xf3,0x4a,0xb6,0x4c,0xc9,0x95,0x49,0x23,0x2d,0x67,0x8d,0x71,0x44,0x02,0xeb,0x6c,0xa7,0xaa,0x0f, + 0x30,0x45,0x02,0x21,0x00,0xdb,0x09,0xd8,0x46,0x0f,0x05,0xef,0xf2,0x3b,0xc7,0xe4,0x36,0xb6,0x7d,0xa5,0x63,0xfa,0x4b,0x4e,0xdb,0x58,0xac,0x24,0xce,0x20,0x1f,0xa8,0xa3,0x58,0x12,0x50,0x57,0x02,0x20,0x46,0xda,0x11,0x67,0x54,0x60,0x29,0x40,0xc8,0x99,0x9c,0x8d,0x66,0x5f,0x78,0x6c,0x50,0xf5,0x77,0x2c,0x0a,0x3c,0xdb,0xda,0x07,0x5e,0x77,0xea,0xbc,0x64,0xdf,0x16, + 0x30,0x44,0x02,0x20,0x59,0x2c,0x41,0xe1,0x65,0x17,0xf1,0x2f,0xca,0xbd,0x98,0x26,0x76,0x74,0xf9,0x74,0xb5,0x88,0xe9,0xf3,0x5d,0x35,0x40,0x6c,0x1a,0x7b,0xb2,0xed,0x1d,0x19,0xb7,0xb8,0x02,0x20,0x3e,0x65,0xa0,0x6b,0xd9,0xf8,0x3c,0xaa,0xeb,0x7b,0x00,0xf2,0x36,0x8d,0x7e,0x0d,0xec,0xe6,0xb1,0x22,0x21,0x26,0x9a,0x9b,0x5b,0x76,0x51,0x98,0xf8,0x40,0xa3,0xa1, + 0x30,0x45,0x02,0x21,0x00,0xbe,0x0d,0x70,0x88,0x7d,0x5e,0x40,0x82,0x1a,0x61,0xb6,0x80,0x47,0xde,0x4e,0xa0,0x3d,0xeb,0xfd,0xf5,0x1c,0xdf,0x4d,0x4b,0x19,0x55,0x58,0xb9,0x59,0xa0,0x32,0xb2,0x02,0x20,0x7d,0x99,0x4b,0x2d,0x8f,0x1d,0xbb,0xeb,0x13,0x53,0x4e,0xb3,0xf6,0xe5,0xdc,0xcd,0x85,0xf5,0xc4,0x13,0x3c,0x27,0xd9,0xe6,0x42,0x71,0xb1,0x82,0x6c,0xe1,0xf6,0x7d, + 0x30,0x45,0x02,0x21,0x00,0xfa,0xe9,0x2d,0xfc,0xb2,0xee,0x39,0x2d,0x27,0x0a,0xf3,0xa5,0x73,0x9f,0xaa,0x26,0xd4,0xf9,0x7b,0xfd,0x39,0xed,0x3c,0xbe,0xe4,0xd2,0x9e,0x26,0xaf,0x3b,0x20,0x6a,0x02,0x20,0x6c,0x9b,0xa3,0x7f,0x9f,0xaa,0x6a,0x1f,0xd3,0xf6,0x5f,0x23,0xb4,0xe8,0x53,0xd4,0x69,0x2a,0x72,0x74,0x24,0x0a,0x12,0xdb,0x7b,0xa3,0x88,0x48,0x30,0x63,0x0d,0x16, + 0x30,0x44,0x02,0x20,0x17,0x6a,0x25,0x57,0x56,0x6f,0xfa,0x51,0x8b,0x11,0x22,0x66,0x94,0xeb,0x98,0x02,0xed,0x20,0x98,0xbf,0xe2,0x78,0xe5,0x57,0x0f,0xe1,0xd5,0xd7,0xaf,0x18,0xa9,0x43,0x02,0x20,0x12,0x91,0xdf,0x6a,0x0e,0xd5,0xfc,0x0d,0x15,0x09,0x8e,0x70,0xbc,0xf1,0x3a,0x00,0x92,0x84,0xdf,0xd0,0x68,0x9d,0x3b,0xb4,0xbe,0x6c,0xee,0xb9,0xbe,0x14,0x87,0xc4, + 0x30,0x44,0x02,0x20,0x60,0xbe,0x20,0xc3,0xdb,0xc1,0x62,0xdd,0x34,0xd2,0x67,0x80,0x62,0x1c,0x10,0x4b,0xbe,0x5d,0xac,0xe6,0x30,0x17,0x1b,0x2d,0xae,0xf0,0xd8,0x26,0x40,0x9e,0xe5,0xc2,0x02,0x20,0x42,0x7f,0x7e,0x4d,0x88,0x9d,0x54,0x91,0x70,0xbd,0xa6,0xa9,0x40,0x9f,0xb1,0xcb,0x8b,0x0e,0x76,0x3d,0x13,0xee,0xa7,0xbd,0x97,0xf6,0x4c,0xf4,0x1d,0xc6,0xe4,0x97, + 0x30,0x45,0x02,0x21,0x00,0xed,0xf0,0x3c,0xf6,0x3f,0x65,0x88,0x83,0x28,0x9a,0x1a,0x59,0x3d,0x10,0x07,0x89,0x5b,0x9f,0x23,0x6d,0x27,0xc9,0xc1,0xf1,0x31,0x30,0x89,0xaa,0xed,0x6b,0x16,0xae,0x02,0x20,0x1a,0x4d,0xd6,0xfc,0x08,0x14,0xdc,0x52,0x3d,0x1f,0xef,0xa8,0x1c,0x64,0xfb,0xf5,0xe6,0x18,0xe6,0x51,0xe7,0x09,0x6f,0xcc,0xad,0xbb,0x94,0xcd,0x48,0xe5,0xe0,0xcd}; + +static const wycheproof_ecdsa_testvector testvectors[SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS] = { + /* tcId: 1. Signature malleability */ + {0, 0, 6, 0, 72, 0 }, + /* tcId: 2. valid */ + {0, 0, 6, 72, 71, 1 }, + /* tcId: 3. length of sequence [r, s] uses long form encoding */ + {0, 0, 6, 143, 72, 0 }, + /* tcId: 4. length of sequence [r, s] contains a leading 0 */ + {0, 0, 6, 215, 73, 0 }, + /* tcId: 5. length of sequence [r, s] uses 70 instead of 69 */ + {0, 0, 6, 288, 71, 0 }, + /* tcId: 6. length of sequence [r, s] uses 68 instead of 69 */ + {0, 0, 6, 359, 71, 0 }, + /* tcId: 7. uint32 overflow in length of sequence [r, s] */ + {0, 0, 6, 430, 76, 0 }, + /* tcId: 8. uint64 overflow in length of sequence [r, s] */ + {0, 0, 6, 506, 80, 0 }, + /* tcId: 9. length of sequence [r, s] = 2**31 - 1 */ + {0, 0, 6, 586, 75, 0 }, + /* tcId: 10. length of sequence [r, s] = 2**31 */ + {0, 0, 6, 661, 75, 0 }, + /* tcId: 11. length of sequence [r, s] = 2**32 - 1 */ + {0, 0, 6, 736, 75, 0 }, + /* tcId: 12. length of sequence [r, s] = 2**40 - 1 */ + {0, 0, 6, 811, 76, 0 }, + /* tcId: 13. length of sequence [r, s] = 2**64 - 1 */ + {0, 0, 6, 887, 79, 0 }, + /* tcId: 14. incorrect length of sequence [r, s] */ + {0, 0, 6, 966, 71, 0 }, + /* tcId: 15. replaced sequence [r, s] by an indefinite length tag without termination */ + {0, 0, 6, 1037, 71, 0 }, + /* tcId: 16. removing sequence [r, s] */ + {0, 0, 6, 1108, 0, 0 }, + /* tcId: 17. lonely sequence tag */ + {0, 0, 6, 1108, 1, 0 }, + /* tcId: 18. appending 0's to sequence [r, s] */ + {0, 0, 6, 1109, 73, 0 }, + /* tcId: 19. prepending 0's to sequence [r, s] */ + {0, 0, 6, 1182, 73, 0 }, + /* tcId: 20. appending unused 0's to sequence [r, s] */ + {0, 0, 6, 1255, 73, 0 }, + /* tcId: 21. appending null value to sequence [r, s] */ + {0, 0, 6, 1328, 73, 0 }, + /* tcId: 22. prepending garbage to sequence [r, s] */ + {0, 0, 6, 1401, 76, 0 }, + /* tcId: 23. prepending garbage to sequence [r, s] */ + {0, 0, 6, 1477, 75, 0 }, + /* tcId: 24. appending garbage to sequence [r, s] */ + {0, 0, 6, 1552, 79, 0 }, + /* tcId: 25. including undefined tags */ + {0, 0, 6, 1631, 79, 0 }, + /* tcId: 26. including undefined tags */ + {0, 0, 6, 1710, 79, 0 }, + /* tcId: 27. including undefined tags */ + {0, 0, 6, 1789, 79, 0 }, + /* tcId: 28. truncated length of sequence [r, s] */ + {0, 0, 6, 1868, 2, 0 }, + /* tcId: 29. including undefined tags to sequence [r, s] */ + {0, 0, 6, 1870, 77, 0 }, + /* tcId: 30. using composition with indefinite length for sequence [r, s] */ + {0, 0, 6, 1947, 75, 0 }, + /* tcId: 31. using composition with wrong tag for sequence [r, s] */ + {0, 0, 6, 2022, 75, 0 }, + /* tcId: 32. Replacing sequence [r, s] with NULL */ + {0, 0, 6, 2097, 2, 0 }, + /* tcId: 33. changing tag value of sequence [r, s] */ + {0, 0, 6, 2099, 71, 0 }, + /* tcId: 34. changing tag value of sequence [r, s] */ + {0, 0, 6, 2170, 71, 0 }, + /* tcId: 35. changing tag value of sequence [r, s] */ + {0, 0, 6, 2241, 71, 0 }, + /* tcId: 36. changing tag value of sequence [r, s] */ + {0, 0, 6, 2312, 71, 0 }, + /* tcId: 37. changing tag value of sequence [r, s] */ + {0, 0, 6, 2383, 71, 0 }, + /* tcId: 38. dropping value of sequence [r, s] */ + {0, 0, 6, 2454, 2, 0 }, + /* tcId: 39. using composition for sequence [r, s] */ + {0, 0, 6, 2456, 75, 0 }, + /* tcId: 40. truncated sequence [r, s] */ + {0, 0, 6, 2531, 70, 0 }, + /* tcId: 41. truncated sequence [r, s] */ + {0, 0, 6, 2601, 70, 0 }, + /* tcId: 42. sequence [r, s] of size 4166 to check for overflows */ + {0, 0, 6, 2671, 4170, 0 }, + /* tcId: 43. indefinite length */ + {0, 0, 6, 6841, 73, 0 }, + /* tcId: 44. indefinite length with truncated delimiter */ + {0, 0, 6, 6914, 72, 0 }, + /* tcId: 45. indefinite length with additional element */ + {0, 0, 6, 6986, 75, 0 }, + /* tcId: 46. indefinite length with truncated element */ + {0, 0, 6, 7061, 77, 0 }, + /* tcId: 47. indefinite length with garbage */ + {0, 0, 6, 7138, 77, 0 }, + /* tcId: 48. indefinite length with nonempty EOC */ + {0, 0, 6, 7215, 75, 0 }, + /* tcId: 49. prepend empty sequence */ + {0, 0, 6, 7290, 73, 0 }, + /* tcId: 50. append empty sequence */ + {0, 0, 6, 7363, 73, 0 }, + /* tcId: 51. append zero */ + {0, 0, 6, 7436, 74, 0 }, + /* tcId: 52. append garbage with high tag number */ + {0, 0, 6, 7510, 74, 0 }, + /* tcId: 53. append null with explicit tag */ + {0, 0, 6, 7584, 75, 0 }, + /* tcId: 54. append null with implicit tag */ + {0, 0, 6, 7659, 73, 0 }, + /* tcId: 55. sequence of sequence */ + {0, 0, 6, 7732, 73, 0 }, + /* tcId: 56. truncated sequence: removed last 1 elements */ + {0, 0, 6, 7805, 37, 0 }, + /* tcId: 57. repeating element in sequence */ + {0, 0, 6, 7842, 105, 0 }, + /* tcId: 58. flipped bit 0 in r */ + {0, 0, 6, 7947, 69, 0 }, + /* tcId: 59. flipped bit 32 in r */ + {0, 0, 6, 8016, 69, 0 }, + /* tcId: 60. flipped bit 48 in r */ + {0, 0, 6, 8085, 69, 0 }, + /* tcId: 61. flipped bit 64 in r */ + {0, 0, 6, 8154, 69, 0 }, + /* tcId: 62. length of r uses long form encoding */ + {0, 0, 6, 8223, 72, 0 }, + /* tcId: 63. length of r contains a leading 0 */ + {0, 0, 6, 8295, 73, 0 }, + /* tcId: 64. length of r uses 34 instead of 33 */ + {0, 0, 6, 8368, 71, 0 }, + /* tcId: 65. length of r uses 32 instead of 33 */ + {0, 0, 6, 8439, 71, 0 }, + /* tcId: 66. uint32 overflow in length of r */ + {0, 0, 6, 8510, 76, 0 }, + /* tcId: 67. uint64 overflow in length of r */ + {0, 0, 6, 8586, 80, 0 }, + /* tcId: 68. length of r = 2**31 - 1 */ + {0, 0, 6, 8666, 75, 0 }, + /* tcId: 69. length of r = 2**31 */ + {0, 0, 6, 8741, 75, 0 }, + /* tcId: 70. length of r = 2**32 - 1 */ + {0, 0, 6, 8816, 75, 0 }, + /* tcId: 71. length of r = 2**40 - 1 */ + {0, 0, 6, 8891, 76, 0 }, + /* tcId: 72. length of r = 2**64 - 1 */ + {0, 0, 6, 8967, 79, 0 }, + /* tcId: 73. incorrect length of r */ + {0, 0, 6, 9046, 71, 0 }, + /* tcId: 74. replaced r by an indefinite length tag without termination */ + {0, 0, 6, 9117, 71, 0 }, + /* tcId: 75. removing r */ + {0, 0, 6, 9188, 36, 0 }, + /* tcId: 76. lonely integer tag */ + {0, 0, 6, 9224, 37, 0 }, + /* tcId: 77. lonely integer tag */ + {0, 0, 6, 9261, 38, 0 }, + /* tcId: 78. appending 0's to r */ + {0, 0, 6, 9299, 73, 0 }, + /* tcId: 79. prepending 0's to r */ + {0, 0, 6, 9372, 73, 0 }, + /* tcId: 80. appending unused 0's to r */ + {0, 0, 6, 9445, 73, 0 }, + /* tcId: 81. appending null value to r */ + {0, 0, 6, 9518, 73, 0 }, + /* tcId: 82. prepending garbage to r */ + {0, 0, 6, 9591, 76, 0 }, + /* tcId: 83. prepending garbage to r */ + {0, 0, 6, 9667, 75, 0 }, + /* tcId: 84. appending garbage to r */ + {0, 0, 6, 9742, 79, 0 }, + /* tcId: 85. truncated length of r */ + {0, 0, 6, 9821, 38, 0 }, + /* tcId: 86. including undefined tags to r */ + {0, 0, 6, 9859, 77, 0 }, + /* tcId: 87. using composition with indefinite length for r */ + {0, 0, 6, 9936, 75, 0 }, + /* tcId: 88. using composition with wrong tag for r */ + {0, 0, 6, 10011, 75, 0 }, + /* tcId: 89. Replacing r with NULL */ + {0, 0, 6, 10086, 38, 0 }, + /* tcId: 90. changing tag value of r */ + {0, 0, 6, 10124, 71, 0 }, + /* tcId: 91. changing tag value of r */ + {0, 0, 6, 10195, 71, 0 }, + /* tcId: 92. changing tag value of r */ + {0, 0, 6, 10266, 71, 0 }, + /* tcId: 93. changing tag value of r */ + {0, 0, 6, 10337, 71, 0 }, + /* tcId: 94. changing tag value of r */ + {0, 0, 6, 10408, 71, 0 }, + /* tcId: 95. dropping value of r */ + {0, 0, 6, 10479, 38, 0 }, + /* tcId: 96. using composition for r */ + {0, 0, 6, 10517, 75, 0 }, + /* tcId: 97. modifying first byte of r */ + {0, 0, 6, 10592, 71, 0 }, + /* tcId: 98. modifying last byte of r */ + {0, 0, 6, 10663, 71, 0 }, + /* tcId: 99. truncated r */ + {0, 0, 6, 10734, 70, 0 }, + /* tcId: 100. truncated r */ + {0, 0, 6, 10804, 70, 0 }, + /* tcId: 101. r of size 4130 to check for overflows */ + {0, 0, 6, 10874, 4172, 0 }, + /* tcId: 102. leading ff in r */ + {0, 0, 6, 15046, 72, 0 }, + /* tcId: 103. replaced r by infinity */ + {0, 0, 6, 15118, 39, 0 }, + /* tcId: 104. replacing r with zero */ + {0, 0, 6, 15157, 39, 0 }, + /* tcId: 105. flipped bit 0 in s */ + {0, 0, 6, 15196, 69, 0 }, + /* tcId: 106. flipped bit 32 in s */ + {0, 0, 6, 15265, 69, 0 }, + /* tcId: 107. flipped bit 48 in s */ + {0, 0, 6, 15334, 69, 0 }, + /* tcId: 108. flipped bit 64 in s */ + {0, 0, 6, 15403, 69, 0 }, + /* tcId: 109. length of s uses long form encoding */ + {0, 0, 6, 15472, 72, 0 }, + /* tcId: 110. length of s contains a leading 0 */ + {0, 0, 6, 15544, 73, 0 }, + /* tcId: 111. length of s uses 33 instead of 32 */ + {0, 0, 6, 15617, 71, 0 }, + /* tcId: 112. length of s uses 31 instead of 32 */ + {0, 0, 6, 15688, 71, 0 }, + /* tcId: 113. uint32 overflow in length of s */ + {0, 0, 6, 15759, 76, 0 }, + /* tcId: 114. uint64 overflow in length of s */ + {0, 0, 6, 15835, 80, 0 }, + /* tcId: 115. length of s = 2**31 - 1 */ + {0, 0, 6, 15915, 75, 0 }, + /* tcId: 116. length of s = 2**31 */ + {0, 0, 6, 15990, 75, 0 }, + /* tcId: 117. length of s = 2**32 - 1 */ + {0, 0, 6, 16065, 75, 0 }, + /* tcId: 118. length of s = 2**40 - 1 */ + {0, 0, 6, 16140, 76, 0 }, + /* tcId: 119. length of s = 2**64 - 1 */ + {0, 0, 6, 16216, 79, 0 }, + /* tcId: 120. incorrect length of s */ + {0, 0, 6, 16295, 71, 0 }, + /* tcId: 121. replaced s by an indefinite length tag without termination */ + {0, 0, 6, 16366, 71, 0 }, + /* tcId: 122. appending 0's to s */ + {0, 0, 6, 16437, 73, 0 }, + /* tcId: 123. prepending 0's to s */ + {0, 0, 6, 16510, 73, 0 }, + /* tcId: 124. appending null value to s */ + {0, 0, 6, 16583, 73, 0 }, + /* tcId: 125. prepending garbage to s */ + {0, 0, 6, 16656, 76, 0 }, + /* tcId: 126. prepending garbage to s */ + {0, 0, 6, 16732, 75, 0 }, + /* tcId: 127. appending garbage to s */ + {0, 0, 6, 16807, 79, 0 }, + /* tcId: 128. truncated length of s */ + {0, 0, 6, 16886, 39, 0 }, + /* tcId: 129. including undefined tags to s */ + {0, 0, 6, 16925, 77, 0 }, + /* tcId: 130. using composition with indefinite length for s */ + {0, 0, 6, 17002, 75, 0 }, + /* tcId: 131. using composition with wrong tag for s */ + {0, 0, 6, 17077, 75, 0 }, + /* tcId: 132. Replacing s with NULL */ + {0, 0, 6, 17152, 39, 0 }, + /* tcId: 133. changing tag value of s */ + {0, 0, 6, 17191, 71, 0 }, + /* tcId: 134. changing tag value of s */ + {0, 0, 6, 17262, 71, 0 }, + /* tcId: 135. changing tag value of s */ + {0, 0, 6, 17333, 71, 0 }, + /* tcId: 136. changing tag value of s */ + {0, 0, 6, 17404, 71, 0 }, + /* tcId: 137. changing tag value of s */ + {0, 0, 6, 17475, 71, 0 }, + /* tcId: 138. dropping value of s */ + {0, 0, 6, 17546, 39, 0 }, + /* tcId: 139. using composition for s */ + {0, 0, 6, 17585, 75, 0 }, + /* tcId: 140. modifying first byte of s */ + {0, 0, 6, 17660, 71, 0 }, + /* tcId: 141. modifying last byte of s */ + {0, 0, 6, 17731, 71, 0 }, + /* tcId: 142. truncated s */ + {0, 0, 6, 17802, 70, 0 }, + /* tcId: 143. truncated s */ + {0, 0, 6, 17872, 70, 0 }, + /* tcId: 144. s of size 4129 to check for overflows */ + {0, 0, 6, 17942, 4172, 0 }, + /* tcId: 145. leading ff in s */ + {0, 0, 6, 22114, 72, 0 }, + /* tcId: 146. replaced s by infinity */ + {0, 0, 6, 22186, 40, 0 }, + /* tcId: 147. replacing s with zero */ + {0, 0, 6, 22226, 40, 0 }, + /* tcId: 148. replaced r by r + n */ + {0, 0, 6, 22266, 71, 0 }, + /* tcId: 149. replaced r by r - n */ + {0, 0, 6, 22337, 70, 0 }, + /* tcId: 150. replaced r by r + 256 * n */ + {0, 0, 6, 22407, 72, 0 }, + /* tcId: 151. replaced r by -r */ + {0, 0, 6, 22479, 71, 0 }, + /* tcId: 152. replaced r by n - r */ + {0, 0, 6, 22550, 70, 0 }, + /* tcId: 153. replaced r by -n - r */ + {0, 0, 6, 22620, 71, 0 }, + /* tcId: 154. replaced r by r + 2**256 */ + {0, 0, 6, 22691, 71, 0 }, + /* tcId: 155. replaced r by r + 2**320 */ + {0, 0, 6, 22762, 79, 0 }, + /* tcId: 156. replaced s by s + n */ + {0, 0, 6, 22841, 71, 0 }, + /* tcId: 157. replaced s by s - n */ + {0, 0, 6, 22912, 71, 0 }, + /* tcId: 158. replaced s by s + 256 * n */ + {0, 0, 6, 22983, 72, 0 }, + /* tcId: 159. replaced s by -s */ + {0, 0, 6, 23055, 70, 0 }, + /* tcId: 160. replaced s by -n - s */ + {0, 0, 6, 23125, 71, 0 }, + /* tcId: 161. replaced s by s + 2**256 */ + {0, 0, 6, 23196, 71, 0 }, + /* tcId: 162. replaced s by s - 2**256 */ + {0, 0, 6, 23267, 71, 0 }, + /* tcId: 163. replaced s by s + 2**320 */ + {0, 0, 6, 23338, 79, 0 }, + /* tcId: 164. Signature with special case values r=0 and s=0 */ + {0, 0, 6, 23417, 8, 0 }, + /* tcId: 165. Signature with special case values r=0 and s=1 */ + {0, 0, 6, 23425, 8, 0 }, + /* tcId: 166. Signature with special case values r=0 and s=-1 */ + {0, 0, 6, 23433, 8, 0 }, + /* tcId: 167. Signature with special case values r=0 and s=n */ + {0, 0, 6, 23441, 40, 0 }, + /* tcId: 168. Signature with special case values r=0 and s=n - 1 */ + {0, 0, 6, 23481, 40, 0 }, + /* tcId: 169. Signature with special case values r=0 and s=n + 1 */ + {0, 0, 6, 23521, 40, 0 }, + /* tcId: 170. Signature with special case values r=0 and s=p */ + {0, 0, 6, 23561, 40, 0 }, + /* tcId: 171. Signature with special case values r=0 and s=p + 1 */ + {0, 0, 6, 23601, 40, 0 }, + /* tcId: 172. Signature with special case values r=1 and s=0 */ + {0, 0, 6, 23641, 8, 0 }, + /* tcId: 173. Signature with special case values r=1 and s=1 */ + {0, 0, 6, 23649, 8, 0 }, + /* tcId: 174. Signature with special case values r=1 and s=-1 */ + {0, 0, 6, 23657, 8, 0 }, + /* tcId: 175. Signature with special case values r=1 and s=n */ + {0, 0, 6, 23665, 40, 0 }, + /* tcId: 176. Signature with special case values r=1 and s=n - 1 */ + {0, 0, 6, 23705, 40, 0 }, + /* tcId: 177. Signature with special case values r=1 and s=n + 1 */ + {0, 0, 6, 23745, 40, 0 }, + /* tcId: 178. Signature with special case values r=1 and s=p */ + {0, 0, 6, 23785, 40, 0 }, + /* tcId: 179. Signature with special case values r=1 and s=p + 1 */ + {0, 0, 6, 23825, 40, 0 }, + /* tcId: 180. Signature with special case values r=-1 and s=0 */ + {0, 0, 6, 23865, 8, 0 }, + /* tcId: 181. Signature with special case values r=-1 and s=1 */ + {0, 0, 6, 23873, 8, 0 }, + /* tcId: 182. Signature with special case values r=-1 and s=-1 */ + {0, 0, 6, 23881, 8, 0 }, + /* tcId: 183. Signature with special case values r=-1 and s=n */ + {0, 0, 6, 23889, 40, 0 }, + /* tcId: 184. Signature with special case values r=-1 and s=n - 1 */ + {0, 0, 6, 23929, 40, 0 }, + /* tcId: 185. Signature with special case values r=-1 and s=n + 1 */ + {0, 0, 6, 23969, 40, 0 }, + /* tcId: 186. Signature with special case values r=-1 and s=p */ + {0, 0, 6, 24009, 40, 0 }, + /* tcId: 187. Signature with special case values r=-1 and s=p + 1 */ + {0, 0, 6, 24049, 40, 0 }, + /* tcId: 188. Signature with special case values r=n and s=0 */ + {0, 0, 6, 24089, 40, 0 }, + /* tcId: 189. Signature with special case values r=n and s=1 */ + {0, 0, 6, 24129, 40, 0 }, + /* tcId: 190. Signature with special case values r=n and s=-1 */ + {0, 0, 6, 24169, 40, 0 }, + /* tcId: 191. Signature with special case values r=n and s=n */ + {0, 0, 6, 24209, 72, 0 }, + /* tcId: 192. Signature with special case values r=n and s=n - 1 */ + {0, 0, 6, 24281, 72, 0 }, + /* tcId: 193. Signature with special case values r=n and s=n + 1 */ + {0, 0, 6, 24353, 72, 0 }, + /* tcId: 194. Signature with special case values r=n and s=p */ + {0, 0, 6, 24425, 72, 0 }, + /* tcId: 195. Signature with special case values r=n and s=p + 1 */ + {0, 0, 6, 24497, 72, 0 }, + /* tcId: 196. Signature with special case values r=n - 1 and s=0 */ + {0, 0, 6, 24569, 40, 0 }, + /* tcId: 197. Signature with special case values r=n - 1 and s=1 */ + {0, 0, 6, 24609, 40, 0 }, + /* tcId: 198. Signature with special case values r=n - 1 and s=-1 */ + {0, 0, 6, 24649, 40, 0 }, + /* tcId: 199. Signature with special case values r=n - 1 and s=n */ + {0, 0, 6, 24689, 72, 0 }, + /* tcId: 200. Signature with special case values r=n - 1 and s=n - 1 */ + {0, 0, 6, 24761, 72, 0 }, + /* tcId: 201. Signature with special case values r=n - 1 and s=n + 1 */ + {0, 0, 6, 24833, 72, 0 }, + /* tcId: 202. Signature with special case values r=n - 1 and s=p */ + {0, 0, 6, 24905, 72, 0 }, + /* tcId: 203. Signature with special case values r=n - 1 and s=p + 1 */ + {0, 0, 6, 24977, 72, 0 }, + /* tcId: 204. Signature with special case values r=n + 1 and s=0 */ + {0, 0, 6, 25049, 40, 0 }, + /* tcId: 205. Signature with special case values r=n + 1 and s=1 */ + {0, 0, 6, 25089, 40, 0 }, + /* tcId: 206. Signature with special case values r=n + 1 and s=-1 */ + {0, 0, 6, 25129, 40, 0 }, + /* tcId: 207. Signature with special case values r=n + 1 and s=n */ + {0, 0, 6, 25169, 72, 0 }, + /* tcId: 208. Signature with special case values r=n + 1 and s=n - 1 */ + {0, 0, 6, 25241, 72, 0 }, + /* tcId: 209. Signature with special case values r=n + 1 and s=n + 1 */ + {0, 0, 6, 25313, 72, 0 }, + /* tcId: 210. Signature with special case values r=n + 1 and s=p */ + {0, 0, 6, 25385, 72, 0 }, + /* tcId: 211. Signature with special case values r=n + 1 and s=p + 1 */ + {0, 0, 6, 25457, 72, 0 }, + /* tcId: 212. Signature with special case values r=p and s=0 */ + {0, 0, 6, 25529, 40, 0 }, + /* tcId: 213. Signature with special case values r=p and s=1 */ + {0, 0, 6, 25569, 40, 0 }, + /* tcId: 214. Signature with special case values r=p and s=-1 */ + {0, 0, 6, 25609, 40, 0 }, + /* tcId: 215. Signature with special case values r=p and s=n */ + {0, 0, 6, 25649, 72, 0 }, + /* tcId: 216. Signature with special case values r=p and s=n - 1 */ + {0, 0, 6, 25721, 72, 0 }, + /* tcId: 217. Signature with special case values r=p and s=n + 1 */ + {0, 0, 6, 25793, 72, 0 }, + /* tcId: 218. Signature with special case values r=p and s=p */ + {0, 0, 6, 25865, 72, 0 }, + /* tcId: 219. Signature with special case values r=p and s=p + 1 */ + {0, 0, 6, 25937, 72, 0 }, + /* tcId: 220. Signature with special case values r=p + 1 and s=0 */ + {0, 0, 6, 26009, 40, 0 }, + /* tcId: 221. Signature with special case values r=p + 1 and s=1 */ + {0, 0, 6, 26049, 40, 0 }, + /* tcId: 222. Signature with special case values r=p + 1 and s=-1 */ + {0, 0, 6, 26089, 40, 0 }, + /* tcId: 223. Signature with special case values r=p + 1 and s=n */ + {0, 0, 6, 26129, 72, 0 }, + /* tcId: 224. Signature with special case values r=p + 1 and s=n - 1 */ + {0, 0, 6, 26201, 72, 0 }, + /* tcId: 225. Signature with special case values r=p + 1 and s=n + 1 */ + {0, 0, 6, 26273, 72, 0 }, + /* tcId: 226. Signature with special case values r=p + 1 and s=p */ + {0, 0, 6, 26345, 72, 0 }, + /* tcId: 227. Signature with special case values r=p + 1 and s=p + 1 */ + {0, 0, 6, 26417, 72, 0 }, + /* tcId: 228. Signature encoding contains incorrect types: r=0, s=0.25 */ + {0, 0, 6, 26489, 10, 0 }, + /* tcId: 229. Signature encoding contains incorrect types: r=0, s=nan */ + {0, 0, 6, 26499, 8, 0 }, + /* tcId: 230. Signature encoding contains incorrect types: r=0, s=True */ + {0, 0, 6, 26507, 8, 0 }, + /* tcId: 231. Signature encoding contains incorrect types: r=0, s=False */ + {0, 0, 6, 26515, 8, 0 }, + /* tcId: 232. Signature encoding contains incorrect types: r=0, s=Null */ + {0, 0, 6, 26523, 7, 0 }, + /* tcId: 233. Signature encoding contains incorrect types: r=0, s=empyt UTF-8 string */ + {0, 0, 6, 26530, 7, 0 }, + /* tcId: 234. Signature encoding contains incorrect types: r=0, s="0" */ + {0, 0, 6, 26537, 8, 0 }, + /* tcId: 235. Signature encoding contains incorrect types: r=0, s=empty list */ + {0, 0, 6, 26545, 7, 0 }, + /* tcId: 236. Signature encoding contains incorrect types: r=0, s=list containing 0 */ + {0, 0, 6, 26552, 10, 0 }, + /* tcId: 237. Signature encoding contains incorrect types: r=1, s=0.25 */ + {0, 0, 6, 26562, 10, 0 }, + /* tcId: 238. Signature encoding contains incorrect types: r=1, s=nan */ + {0, 0, 6, 26572, 8, 0 }, + /* tcId: 239. Signature encoding contains incorrect types: r=1, s=True */ + {0, 0, 6, 26580, 8, 0 }, + /* tcId: 240. Signature encoding contains incorrect types: r=1, s=False */ + {0, 0, 6, 26588, 8, 0 }, + /* tcId: 241. Signature encoding contains incorrect types: r=1, s=Null */ + {0, 0, 6, 26596, 7, 0 }, + /* tcId: 242. Signature encoding contains incorrect types: r=1, s=empyt UTF-8 string */ + {0, 0, 6, 26603, 7, 0 }, + /* tcId: 243. Signature encoding contains incorrect types: r=1, s="0" */ + {0, 0, 6, 26610, 8, 0 }, + /* tcId: 244. Signature encoding contains incorrect types: r=1, s=empty list */ + {0, 0, 6, 26618, 7, 0 }, + /* tcId: 245. Signature encoding contains incorrect types: r=1, s=list containing 0 */ + {0, 0, 6, 26625, 10, 0 }, + /* tcId: 246. Signature encoding contains incorrect types: r=-1, s=0.25 */ + {0, 0, 6, 26635, 10, 0 }, + /* tcId: 247. Signature encoding contains incorrect types: r=-1, s=nan */ + {0, 0, 6, 26645, 8, 0 }, + /* tcId: 248. Signature encoding contains incorrect types: r=-1, s=True */ + {0, 0, 6, 26653, 8, 0 }, + /* tcId: 249. Signature encoding contains incorrect types: r=-1, s=False */ + {0, 0, 6, 26661, 8, 0 }, + /* tcId: 250. Signature encoding contains incorrect types: r=-1, s=Null */ + {0, 0, 6, 26669, 7, 0 }, + /* tcId: 251. Signature encoding contains incorrect types: r=-1, s=empyt UTF-8 string */ + {0, 0, 6, 26676, 7, 0 }, + /* tcId: 252. Signature encoding contains incorrect types: r=-1, s="0" */ + {0, 0, 6, 26683, 8, 0 }, + /* tcId: 253. Signature encoding contains incorrect types: r=-1, s=empty list */ + {0, 0, 6, 26691, 7, 0 }, + /* tcId: 254. Signature encoding contains incorrect types: r=-1, s=list containing 0 */ + {0, 0, 6, 26698, 10, 0 }, + /* tcId: 255. Signature encoding contains incorrect types: r=n, s=0.25 */ + {0, 0, 6, 26708, 42, 0 }, + /* tcId: 256. Signature encoding contains incorrect types: r=n, s=nan */ + {0, 0, 6, 26750, 40, 0 }, + /* tcId: 257. Signature encoding contains incorrect types: r=n, s=True */ + {0, 0, 6, 26790, 40, 0 }, + /* tcId: 258. Signature encoding contains incorrect types: r=n, s=False */ + {0, 0, 6, 26830, 40, 0 }, + /* tcId: 259. Signature encoding contains incorrect types: r=n, s=Null */ + {0, 0, 6, 26870, 39, 0 }, + /* tcId: 260. Signature encoding contains incorrect types: r=n, s=empyt UTF-8 string */ + {0, 0, 6, 26909, 39, 0 }, + /* tcId: 261. Signature encoding contains incorrect types: r=n, s="0" */ + {0, 0, 6, 26948, 40, 0 }, + /* tcId: 262. Signature encoding contains incorrect types: r=n, s=empty list */ + {0, 0, 6, 26988, 39, 0 }, + /* tcId: 263. Signature encoding contains incorrect types: r=n, s=list containing 0 */ + {0, 0, 6, 27027, 42, 0 }, + /* tcId: 264. Signature encoding contains incorrect types: r=p, s=0.25 */ + {0, 0, 6, 27069, 42, 0 }, + /* tcId: 265. Signature encoding contains incorrect types: r=p, s=nan */ + {0, 0, 6, 27111, 40, 0 }, + /* tcId: 266. Signature encoding contains incorrect types: r=p, s=True */ + {0, 0, 6, 27151, 40, 0 }, + /* tcId: 267. Signature encoding contains incorrect types: r=p, s=False */ + {0, 0, 6, 27191, 40, 0 }, + /* tcId: 268. Signature encoding contains incorrect types: r=p, s=Null */ + {0, 0, 6, 27231, 39, 0 }, + /* tcId: 269. Signature encoding contains incorrect types: r=p, s=empyt UTF-8 string */ + {0, 0, 6, 27270, 39, 0 }, + /* tcId: 270. Signature encoding contains incorrect types: r=p, s="0" */ + {0, 0, 6, 27309, 40, 0 }, + /* tcId: 271. Signature encoding contains incorrect types: r=p, s=empty list */ + {0, 0, 6, 27349, 39, 0 }, + /* tcId: 272. Signature encoding contains incorrect types: r=p, s=list containing 0 */ + {0, 0, 6, 27388, 42, 0 }, + /* tcId: 273. Signature encoding contains incorrect types: r=0.25, s=0.25 */ + {0, 0, 6, 27430, 12, 0 }, + /* tcId: 274. Signature encoding contains incorrect types: r=nan, s=nan */ + {0, 0, 6, 27442, 8, 0 }, + /* tcId: 275. Signature encoding contains incorrect types: r=True, s=True */ + {0, 0, 6, 27450, 8, 0 }, + /* tcId: 276. Signature encoding contains incorrect types: r=False, s=False */ + {0, 0, 6, 27458, 8, 0 }, + /* tcId: 277. Signature encoding contains incorrect types: r=Null, s=Null */ + {0, 0, 6, 27466, 6, 0 }, + /* tcId: 278. Signature encoding contains incorrect types: r=empyt UTF-8 string, s=empyt UTF-8 string */ + {0, 0, 6, 27472, 6, 0 }, + /* tcId: 279. Signature encoding contains incorrect types: r="0", s="0" */ + {0, 0, 6, 27478, 8, 0 }, + /* tcId: 280. Signature encoding contains incorrect types: r=empty list, s=empty list */ + {0, 0, 6, 27486, 6, 0 }, + /* tcId: 281. Signature encoding contains incorrect types: r=list containing 0, s=list containing 0 */ + {0, 0, 6, 27492, 12, 0 }, + /* tcId: 282. Signature encoding contains incorrect types: r=0.25, s=0 */ + {0, 0, 6, 27504, 10, 0 }, + /* tcId: 283. Signature encoding contains incorrect types: r=nan, s=0 */ + {0, 0, 6, 27514, 8, 0 }, + /* tcId: 284. Signature encoding contains incorrect types: r=True, s=0 */ + {0, 0, 6, 27522, 8, 0 }, + /* tcId: 285. Signature encoding contains incorrect types: r=False, s=0 */ + {0, 0, 6, 27530, 8, 0 }, + /* tcId: 286. Signature encoding contains incorrect types: r=Null, s=0 */ + {0, 0, 6, 27538, 7, 0 }, + /* tcId: 287. Signature encoding contains incorrect types: r=empyt UTF-8 string, s=0 */ + {0, 0, 6, 27545, 7, 0 }, + /* tcId: 288. Signature encoding contains incorrect types: r="0", s=0 */ + {0, 0, 6, 27552, 8, 0 }, + /* tcId: 289. Signature encoding contains incorrect types: r=empty list, s=0 */ + {0, 0, 6, 27560, 7, 0 }, + /* tcId: 290. Signature encoding contains incorrect types: r=list containing 0, s=0 */ + {0, 0, 6, 27567, 10, 0 }, + /* tcId: 291. Edge case for Shamir multiplication */ + {0, 6, 5, 27577, 71, 1 }, + /* tcId: 292. special case hash */ + {0, 11, 9, 27648, 71, 1 }, + /* tcId: 293. special case hash */ + {0, 20, 10, 27719, 70, 1 }, + /* tcId: 294. special case hash */ + {0, 30, 11, 27789, 71, 1 }, + /* tcId: 295. special case hash */ + {0, 41, 10, 27860, 71, 1 }, + /* tcId: 296. special case hash */ + {0, 51, 10, 27931, 70, 1 }, + /* tcId: 297. special case hash */ + {0, 61, 10, 28001, 71, 1 }, + /* tcId: 298. special case hash */ + {0, 71, 9, 28072, 70, 1 }, + /* tcId: 299. special case hash */ + {0, 80, 10, 28142, 71, 1 }, + /* tcId: 300. special case hash */ + {0, 90, 10, 28213, 71, 1 }, + /* tcId: 301. special case hash */ + {0, 100, 10, 28284, 71, 1 }, + /* tcId: 302. special case hash */ + {0, 110, 10, 28355, 71, 1 }, + /* tcId: 303. special case hash */ + {0, 120, 11, 28426, 70, 1 }, + /* tcId: 304. special case hash */ + {0, 131, 10, 28496, 71, 1 }, + /* tcId: 305. special case hash */ + {0, 141, 10, 28567, 71, 1 }, + /* tcId: 306. special case hash */ + {0, 151, 10, 28638, 70, 1 }, + /* tcId: 307. special case hash */ + {0, 161, 10, 28708, 71, 1 }, + /* tcId: 308. special case hash */ + {0, 171, 10, 28779, 71, 1 }, + /* tcId: 309. special case hash */ + {0, 181, 10, 28850, 70, 1 }, + /* tcId: 310. special case hash */ + {0, 191, 10, 28920, 71, 1 }, + /* tcId: 311. special case hash */ + {0, 201, 10, 28991, 71, 1 }, + /* tcId: 312. special case hash */ + {0, 211, 10, 29062, 71, 1 }, + /* tcId: 313. special case hash */ + {0, 221, 10, 29133, 70, 1 }, + /* tcId: 314. special case hash */ + {0, 231, 10, 29203, 71, 1 }, + /* tcId: 315. special case hash */ + {0, 241, 10, 29274, 71, 1 }, + /* tcId: 316. special case hash */ + {0, 251, 10, 29345, 71, 1 }, + /* tcId: 317. special case hash */ + {0, 261, 11, 29416, 71, 1 }, + /* tcId: 318. special case hash */ + {0, 272, 11, 29487, 70, 1 }, + /* tcId: 319. special case hash */ + {0, 283, 9, 29557, 71, 1 }, + /* tcId: 320. special case hash */ + {0, 292, 9, 29628, 71, 1 }, + /* tcId: 321. special case hash */ + {0, 301, 10, 29699, 71, 1 }, + /* tcId: 322. special case hash */ + {0, 311, 10, 29770, 71, 1 }, + /* tcId: 323. special case hash */ + {0, 321, 10, 29841, 70, 1 }, + /* tcId: 324. special case hash */ + {0, 331, 10, 29911, 70, 1 }, + /* tcId: 325. special case hash */ + {0, 341, 10, 29981, 71, 1 }, + /* tcId: 326. special case hash */ + {0, 351, 9, 30052, 70, 1 }, + /* tcId: 327. special case hash */ + {0, 360, 10, 30122, 70, 1 }, + /* tcId: 328. special case hash */ + {0, 370, 10, 30192, 70, 1 }, + /* tcId: 329. special case hash */ + {0, 380, 10, 30262, 70, 1 }, + /* tcId: 330. special case hash */ + {0, 390, 9, 30332, 71, 1 }, + /* tcId: 331. special case hash */ + {0, 399, 11, 30403, 70, 1 }, + /* tcId: 332. special case hash */ + {0, 410, 9, 30473, 71, 1 }, + /* tcId: 333. special case hash */ + {0, 419, 9, 30544, 71, 1 }, + /* tcId: 334. special case hash */ + {0, 428, 11, 30615, 70, 1 }, + /* tcId: 335. special case hash */ + {0, 439, 8, 30685, 71, 1 }, + /* tcId: 336. special case hash */ + {0, 447, 10, 30756, 70, 1 }, + /* tcId: 337. special case hash */ + {0, 457, 10, 30826, 71, 1 }, + /* tcId: 338. special case hash */ + {0, 467, 10, 30897, 70, 1 }, + /* tcId: 339. special case hash */ + {0, 477, 10, 30967, 70, 1 }, + /* tcId: 340. special case hash */ + {0, 487, 10, 31037, 70, 1 }, + /* tcId: 341. special case hash */ + {0, 497, 10, 31107, 71, 1 }, + /* tcId: 342. special case hash */ + {0, 507, 10, 31178, 70, 1 }, + /* tcId: 343. special case hash */ + {0, 517, 10, 31248, 70, 1 }, + /* tcId: 344. special case hash */ + {0, 527, 10, 31318, 71, 1 }, + /* tcId: 345. special case hash */ + {0, 537, 9, 31389, 70, 1 }, + /* tcId: 346. k*G has a large x-coordinate */ + {65, 0, 6, 31459, 24, 1 }, + /* tcId: 347. r too large */ + {65, 0, 6, 31483, 40, 0 }, + /* tcId: 348. r,s are large */ + {130, 0, 6, 31523, 40, 1 }, + /* tcId: 349. r and s^-1 have a large Hamming weight */ + {195, 0, 6, 31563, 70, 1 }, + /* tcId: 350. r and s^-1 have a large Hamming weight */ + {260, 0, 6, 31633, 70, 1 }, + /* tcId: 351. small r and s */ + {325, 0, 6, 31703, 8, 1 }, + /* tcId: 352. small r and s */ + {390, 0, 6, 31711, 8, 1 }, + /* tcId: 353. small r and s */ + {455, 0, 6, 31719, 8, 1 }, + /* tcId: 354. small r and s */ + {520, 0, 6, 31727, 8, 1 }, + /* tcId: 355. small r and s */ + {585, 0, 6, 31735, 8, 1 }, + /* tcId: 356. small r and s */ + {650, 0, 6, 31743, 8, 1 }, + /* tcId: 357. r is larger than n */ + {650, 0, 6, 31751, 40, 0 }, + /* tcId: 358. s is larger than n */ + {715, 0, 6, 31791, 10, 0 }, + /* tcId: 359. small r and s^-1 */ + {780, 0, 6, 31801, 40, 1 }, + /* tcId: 360. smallish r and s^-1 */ + {845, 0, 6, 31841, 45, 1 }, + /* tcId: 361. 100-bit r and small s^-1 */ + {910, 0, 6, 31886, 51, 1 }, + /* tcId: 362. small r and 100 bit s^-1 */ + {975, 0, 6, 31937, 40, 1 }, + /* tcId: 363. 100-bit r and s^-1 */ + {1040, 0, 6, 31977, 51, 1 }, + /* tcId: 364. r and s^-1 are close to n */ + {1105, 0, 6, 32028, 71, 1 }, + /* tcId: 365. r and s are 64-bit integer */ + {1170, 0, 6, 32099, 24, 1 }, + /* tcId: 366. r and s are 100-bit integer */ + {1235, 0, 6, 32123, 32, 1 }, + /* tcId: 367. r and s are 128-bit integer */ + {1300, 0, 6, 32155, 40, 1 }, + /* tcId: 368. r and s are 160-bit integer */ + {1365, 0, 6, 32195, 48, 1 }, + /* tcId: 369. s == 1 */ + {1430, 0, 6, 32243, 39, 1 }, + /* tcId: 370. s == 0 */ + {1430, 0, 6, 32282, 39, 0 }, + /* tcId: 371. edge case modular inverse */ + {1495, 0, 6, 32321, 70, 1 }, + /* tcId: 372. edge case modular inverse */ + {1560, 0, 6, 32391, 70, 1 }, + /* tcId: 373. edge case modular inverse */ + {1625, 0, 6, 32461, 70, 1 }, + /* tcId: 374. edge case modular inverse */ + {1690, 0, 6, 32531, 70, 1 }, + /* tcId: 375. edge case modular inverse */ + {1755, 0, 6, 32601, 70, 1 }, + /* tcId: 376. edge case modular inverse */ + {1820, 0, 6, 32671, 70, 1 }, + /* tcId: 377. edge case modular inverse */ + {1885, 0, 6, 32741, 70, 1 }, + /* tcId: 378. edge case modular inverse */ + {1950, 0, 6, 32811, 70, 1 }, + /* tcId: 379. edge case modular inverse */ + {2015, 0, 6, 32881, 70, 1 }, + /* tcId: 380. edge case modular inverse */ + {2080, 0, 6, 32951, 70, 1 }, + /* tcId: 381. edge case modular inverse */ + {2145, 0, 6, 33021, 70, 1 }, + /* tcId: 382. edge case modular inverse */ + {2210, 0, 6, 33091, 70, 1 }, + /* tcId: 383. edge case modular inverse */ + {2275, 0, 6, 33161, 70, 1 }, + /* tcId: 384. edge case modular inverse */ + {2340, 0, 6, 33231, 70, 1 }, + /* tcId: 385. edge case modular inverse */ + {2405, 0, 6, 33301, 70, 1 }, + /* tcId: 386. point at infinity during verify */ + {2470, 0, 6, 33371, 70, 0 }, + /* tcId: 387. edge case for signature malleability */ + {2535, 0, 6, 33441, 70, 1 }, + /* tcId: 388. edge case for signature malleability */ + {2600, 0, 6, 33511, 70, 0 }, + /* tcId: 389. u1 == 1 */ + {2665, 0, 6, 33581, 70, 1 }, + /* tcId: 390. u1 == n - 1 */ + {2730, 0, 6, 33651, 70, 1 }, + /* tcId: 391. u2 == 1 */ + {2795, 0, 6, 33721, 70, 1 }, + /* tcId: 392. u2 == n - 1 */ + {2860, 0, 6, 33791, 70, 1 }, + /* tcId: 393. edge case for u1 */ + {2925, 0, 6, 33861, 70, 1 }, + /* tcId: 394. edge case for u1 */ + {2990, 0, 6, 33931, 70, 1 }, + /* tcId: 395. edge case for u1 */ + {3055, 0, 6, 34001, 70, 1 }, + /* tcId: 396. edge case for u1 */ + {3120, 0, 6, 34071, 70, 1 }, + /* tcId: 397. edge case for u1 */ + {3185, 0, 6, 34141, 70, 1 }, + /* tcId: 398. edge case for u1 */ + {3250, 0, 6, 34211, 70, 1 }, + /* tcId: 399. edge case for u1 */ + {3315, 0, 6, 34281, 70, 1 }, + /* tcId: 400. edge case for u1 */ + {3380, 0, 6, 34351, 70, 1 }, + /* tcId: 401. edge case for u1 */ + {3445, 0, 6, 34421, 70, 1 }, + /* tcId: 402. edge case for u1 */ + {3510, 0, 6, 34491, 70, 1 }, + /* tcId: 403. edge case for u1 */ + {3575, 0, 6, 34561, 70, 1 }, + /* tcId: 404. edge case for u1 */ + {3640, 0, 6, 34631, 70, 1 }, + /* tcId: 405. edge case for u1 */ + {3705, 0, 6, 34701, 70, 1 }, + /* tcId: 406. edge case for u1 */ + {3770, 0, 6, 34771, 70, 1 }, + /* tcId: 407. edge case for u1 */ + {3835, 0, 6, 34841, 70, 1 }, + /* tcId: 408. edge case for u2 */ + {3900, 0, 6, 34911, 70, 1 }, + /* tcId: 409. edge case for u2 */ + {3965, 0, 6, 34981, 70, 1 }, + /* tcId: 410. edge case for u2 */ + {4030, 0, 6, 35051, 70, 1 }, + /* tcId: 411. edge case for u2 */ + {4095, 0, 6, 35121, 70, 1 }, + /* tcId: 412. edge case for u2 */ + {4160, 0, 6, 35191, 70, 1 }, + /* tcId: 413. edge case for u2 */ + {4225, 0, 6, 35261, 69, 1 }, + /* tcId: 414. edge case for u2 */ + {4290, 0, 6, 35330, 70, 1 }, + /* tcId: 415. edge case for u2 */ + {4355, 0, 6, 35400, 70, 1 }, + /* tcId: 416. edge case for u2 */ + {4420, 0, 6, 35470, 70, 1 }, + /* tcId: 417. edge case for u2 */ + {4485, 0, 6, 35540, 70, 1 }, + /* tcId: 418. edge case for u2 */ + {4550, 0, 6, 35610, 70, 1 }, + /* tcId: 419. edge case for u2 */ + {4615, 0, 6, 35680, 70, 1 }, + /* tcId: 420. edge case for u2 */ + {4680, 0, 6, 35750, 70, 1 }, + /* tcId: 421. edge case for u2 */ + {4745, 0, 6, 35820, 70, 1 }, + /* tcId: 422. edge case for u2 */ + {4810, 0, 6, 35890, 70, 1 }, + /* tcId: 423. point duplication during verification */ + {4875, 0, 6, 35960, 70, 1 }, + /* tcId: 424. duplication bug */ + {4940, 0, 6, 36030, 70, 0 }, + /* tcId: 425. comparison with point at infinity */ + {5005, 0, 6, 36100, 70, 0 }, + /* tcId: 426. extreme value for k and edgecase s */ + {5070, 0, 6, 36170, 71, 1 }, + /* tcId: 427. extreme value for k and s^-1 */ + {5135, 0, 6, 36241, 71, 1 }, + /* tcId: 428. extreme value for k and s^-1 */ + {5200, 0, 6, 36312, 71, 1 }, + /* tcId: 429. extreme value for k and s^-1 */ + {5265, 0, 6, 36383, 71, 1 }, + /* tcId: 430. extreme value for k and s^-1 */ + {5330, 0, 6, 36454, 71, 1 }, + /* tcId: 431. extreme value for k */ + {5395, 0, 6, 36525, 71, 1 }, + /* tcId: 432. extreme value for k and edgecase s */ + {5460, 0, 6, 36596, 70, 1 }, + /* tcId: 433. extreme value for k and s^-1 */ + {5525, 0, 6, 36666, 70, 1 }, + /* tcId: 434. extreme value for k and s^-1 */ + {5590, 0, 6, 36736, 70, 1 }, + /* tcId: 435. extreme value for k and s^-1 */ + {5655, 0, 6, 36806, 70, 1 }, + /* tcId: 436. extreme value for k and s^-1 */ + {5720, 0, 6, 36876, 70, 1 }, + /* tcId: 437. extreme value for k */ + {5785, 0, 6, 36946, 70, 1 }, + /* tcId: 438. public key shares x-coordinate with generator */ + {5850, 0, 6, 37016, 71, 0 }, + /* tcId: 439. public key shares x-coordinate with generator */ + {5850, 0, 6, 37087, 70, 0 }, + /* tcId: 440. public key shares x-coordinate with generator */ + {5915, 0, 6, 37157, 71, 0 }, + /* tcId: 441. public key shares x-coordinate with generator */ + {5915, 0, 6, 37228, 70, 0 }, + /* tcId: 442. pseudorandom signature */ + {5980, 546, 0, 37298, 71, 1 }, + /* tcId: 443. pseudorandom signature */ + {5980, 546, 3, 37369, 70, 1 }, + /* tcId: 444. pseudorandom signature */ + {5980, 0, 6, 37439, 71, 1 }, + /* tcId: 445. pseudorandom signature */ + {5980, 549, 20, 37510, 70, 1 }, + /* tcId: 446. y-coordinate of the public key is small */ + {6045, 569, 7, 37580, 70, 1 }, + /* tcId: 447. y-coordinate of the public key is small */ + {6045, 569, 7, 37650, 70, 1 }, + /* tcId: 448. y-coordinate of the public key is small */ + {6045, 569, 7, 37720, 71, 1 }, + /* tcId: 449. y-coordinate of the public key is large */ + {6110, 569, 7, 37791, 70, 1 }, + /* tcId: 450. y-coordinate of the public key is large */ + {6110, 569, 7, 37861, 71, 1 }, + /* tcId: 451. y-coordinate of the public key is large */ + {6110, 569, 7, 37932, 70, 1 }, + /* tcId: 452. x-coordinate of the public key is small */ + {6175, 569, 7, 38002, 70, 1 }, + /* tcId: 453. x-coordinate of the public key is small */ + {6175, 569, 7, 38072, 71, 1 }, + /* tcId: 454. x-coordinate of the public key is small */ + {6175, 569, 7, 38143, 71, 1 }, + /* tcId: 455. x-coordinate of the public key has many trailing 1's */ + {6240, 569, 7, 38214, 70, 1 }, + /* tcId: 456. x-coordinate of the public key has many trailing 1's */ + {6240, 569, 7, 38284, 71, 1 }, + /* tcId: 457. x-coordinate of the public key has many trailing 1's */ + {6240, 569, 7, 38355, 71, 1 }, + /* tcId: 458. y-coordinate of the public key has many trailing 1's */ + {6305, 569, 7, 38426, 70, 1 }, + /* tcId: 459. y-coordinate of the public key has many trailing 1's */ + {6305, 569, 7, 38496, 71, 1 }, + /* tcId: 460. y-coordinate of the public key has many trailing 1's */ + {6305, 569, 7, 38567, 71, 1 }, + /* tcId: 461. x-coordinate of the public key has many trailing 0's */ + {6370, 569, 7, 38638, 70, 1 }, + /* tcId: 462. x-coordinate of the public key has many trailing 0's */ + {6370, 569, 7, 38708, 70, 1 }, + /* tcId: 463. x-coordinate of the public key has many trailing 0's */ + {6370, 569, 7, 38778, 71, 1 }, + +}; diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json new file mode 100644 index 00000000..9c907479 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json @@ -0,0 +1,6360 @@ +{ + "algorithm" : "ECDSA", + "schema" : "ecdsa_bitcoin_verify_schema.json", + "generatorVersion" : "0.9rc5", + "numberOfTests" : 463, + "header" : [ + "Test vectors of type EcdsaBitcoinVerify are meant for the verification", + "of a ECDSA variant used for bitcoin, that add signature non-malleability." + ], + "notes" : { + "ArithmeticError" : { + "bugType" : "EDGE_CASE", + "description" : "Some implementations of ECDSA have arithmetic errors that occur when intermediate results have extreme values. This test vector has been constructed to test such occurences.", + "cves" : [ + "CVE-2017-18146" + ] + }, + "BerEncodedSignature" : { + "bugType" : "BER_ENCODING", + "description" : "ECDSA signatures are usually DER encoded. This signature contains valid values for r and s, but it uses alternative BER encoding.", + "effect" : "Accepting alternative BER encodings may be benign in some cases, or be an issue if protocol requires signature malleability.", + "cves" : [ + "CVE-2020-14966", + "CVE-2020-13822", + "CVE-2019-14859", + "CVE-2016-1000342" + ] + }, + "EdgeCasePublicKey" : { + "bugType" : "EDGE_CASE", + "description" : "The test vector uses a special case public key. " + }, + "EdgeCaseShamirMultiplication" : { + "bugType" : "EDGE_CASE", + "description" : "Shamir proposed a fast method for computing the sum of two scalar multiplications efficiently. This test vector has been constructed so that an intermediate result is the point at infinity if Shamir's method is used." + }, + "IntegerOverflow" : { + "bugType" : "CAN_OF_WORMS", + "description" : "The test vector contains an r and s that has been modified, so that the original value is restored if the implementation ignores the most significant bits.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "InvalidEncoding" : { + "bugType" : "CAN_OF_WORMS", + "description" : "ECDSA signatures are encoded using ASN.1. This test vector contains an incorrectly encoded signature. The test vector itself was generated from a valid signature by modifying its encoding.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "InvalidSignature" : { + "bugType" : "AUTH_BYPASS", + "description" : "The signature contains special case values such as r=0 and s=0. Buggy implementations may accept such values, if the implementation does not check boundaries and computes s^(-1) == 0.", + "effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.", + "cves" : [ + "CVE-2022-21449", + "CVE-2021-43572", + "CVE-2022-24884" + ] + }, + "InvalidTypesInSignature" : { + "bugType" : "AUTH_BYPASS", + "description" : "The signature contains invalid types. Dynamic typed languages sometime coerce such values of different types into integers. If an implementation is careless and has additional bugs, such as not checking integer boundaries then it may be possible that such signatures are accepted.", + "effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.", + "cves" : [ + "CVE-2022-21449" + ] + }, + "ModifiedInteger" : { + "bugType" : "CAN_OF_WORMS", + "description" : "The test vector contains an r and s that has been modified. The goal is to check for arithmetic errors.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "ModifiedSignature" : { + "bugType" : "CAN_OF_WORMS", + "description" : "The test vector contains an invalid signature that was generated from a valid signature by modifying it.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "ModularInverse" : { + "bugType" : "EDGE_CASE", + "description" : "The test vectors contains a signature where computing the modular inverse of s hits an edge case.", + "effect" : "While the signature in this test vector is constructed and similar cases are unlikely to occur, it is important to determine if the underlying arithmetic error can be used to forge signatures.", + "cves" : [ + "CVE-2019-0865" + ] + }, + "PointDuplication" : { + "bugType" : "EDGE_CASE", + "description" : "Some implementations of ECDSA do not handle duplication and points at infinity correctly. This is a test vector that has been specially crafted to check for such an omission.", + "cves" : [ + "2020-12607", + "CVE-2015-2730" + ] + }, + "RangeCheck" : { + "bugType" : "CAN_OF_WORMS", + "description" : "The test vector contains an r and s that has been modified. By adding or subtracting the order of the group (or other values) the test vector checks whether signature verification verifies the range of r and s.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "SignatureMalleabilityBitcoin" : { + "bugType" : "SIGNATURE_MALLEABILITY", + "description" : "\"BitCoins\"-curves are curves where signature malleability can be a serious issue. An implementation should only accept a signature s where s < n/2. If an implementation is not meant for uses cases that require signature malleability then this implemenation should be tested with another set of test vectors.", + "effect" : "In bitcoin exchanges, it may be used to make a double deposits or double withdrawals", + "links" : [ + "https://en.bitcoin.it/wiki/Transaction_malleability", + "https://en.bitcoinwiki.org/wiki/Transaction_Malleability" + ] + }, + "SmallRandS" : { + "bugType" : "EDGE_CASE", + "description" : "The test vectors contains a signature where both r and s are small integers. Some libraries cannot verify such signatures.", + "effect" : "While the signature in this test vector is constructed and similar cases are unlikely to occur, it is important to determine if the underlying arithmetic error can be used to forge signatures.", + "cves" : [ + "2020-13895" + ] + }, + "SpecialCaseHash" : { + "bugType" : "EDGE_CASE", + "description" : "The test vector contains a signature where the hash of the message is a special case, e.g., contains a long run of 0 or 1 bits." + }, + "ValidSignature" : { + "bugType" : "BASIC", + "description" : "The test vector contains a valid signature that was generated pseudorandomly. Such signatures should not fail to verify unless some of the parameters (e.g. curve or hash function) are not supported." + } + }, + "testGroups" : [ + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9", + "wx" : "00b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6f", + "wy" : "00f0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEuDj/ROW8F3vyEYnQdmCC/J2EMiaIf8l2\nA3EQC37iCm/wyddb+6ezGmvKGXRJbutW3jVwcZVdg8Sxutqgshgy6Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 1, + "comment" : "Signature malleability", + "flags" : [ + "SignatureMalleabilityBitcoin" + ], + "msg" : "313233343030", + "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365022100900e75ad233fcc908509dbff5922647db37c21f4afd3203ae8dc4ae7794b0f87", + "result" : "invalid" + }, + { + "tcId" : 2, + "comment" : "valid", + "flags" : [ + "ValidSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "valid" + }, + { + "tcId" : 3, + "comment" : "length of sequence [r, s] uses long form encoding", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "308145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 4, + "comment" : "length of sequence [r, s] contains a leading 0", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "30820045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 5, + "comment" : "length of sequence [r, s] uses 70 instead of 69", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 6, + "comment" : "length of sequence [r, s] uses 68 instead of 69", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 7, + "comment" : "uint32 overflow in length of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30850100000045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 8, + "comment" : "uint64 overflow in length of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3089010000000000000045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 9, + "comment" : "length of sequence [r, s] = 2**31 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30847fffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 10, + "comment" : "length of sequence [r, s] = 2**31", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "308480000000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 11, + "comment" : "length of sequence [r, s] = 2**32 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3084ffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 12, + "comment" : "length of sequence [r, s] = 2**40 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3085ffffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 13, + "comment" : "length of sequence [r, s] = 2**64 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3088ffffffffffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 14, + "comment" : "incorrect length of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30ff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 15, + "comment" : "replaced sequence [r, s] by an indefinite length tag without termination", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 16, + "comment" : "removing sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "", + "result" : "invalid" + }, + { + "tcId" : 17, + "comment" : "lonely sequence tag", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30", + "result" : "invalid" + }, + { + "tcId" : 18, + "comment" : "appending 0's to sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 19, + "comment" : "prepending 0's to sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30470000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 20, + "comment" : "appending unused 0's to sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 21, + "comment" : "appending null value to sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0500", + "result" : "invalid" + }, + { + "tcId" : 22, + "comment" : "prepending garbage to sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a4981773045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 23, + "comment" : "prepending garbage to sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304925003045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 24, + "comment" : "appending garbage to sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30473045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0004deadbeef", + "result" : "invalid" + }, + { + "tcId" : 25, + "comment" : "including undefined tags", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "304daa00bb00cd003045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 26, + "comment" : "including undefined tags", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d2229aa00bb00cd00022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 27, + "comment" : "including undefined tags", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652228aa00bb00cd0002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 28, + "comment" : "truncated length of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3081", + "result" : "invalid" + }, + { + "tcId" : 29, + "comment" : "including undefined tags to sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "304baa02aabb3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 30, + "comment" : "using composition with indefinite length for sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30803045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 31, + "comment" : "using composition with wrong tag for sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30803145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 32, + "comment" : "Replacing sequence [r, s] with NULL", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "0500", + "result" : "invalid" + }, + { + "tcId" : 33, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "2e45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 34, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "2f45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 35, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 36, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3245022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 37, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "ff45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 38, + "comment" : "dropping value of sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3000", + "result" : "invalid" + }, + { + "tcId" : 39, + "comment" : "using composition for sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304930010230442100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 40, + "comment" : "truncated sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31", + "result" : "invalid" + }, + { + "tcId" : 41, + "comment" : "truncated sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30442100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 42, + "comment" : "sequence [r, s] of size 4166 to check for overflows", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30821046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "result" : "invalid" + }, + { + "tcId" : 43, + "comment" : "indefinite length", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 44, + "comment" : "indefinite length with truncated delimiter", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba00", + "result" : "invalid" + }, + { + "tcId" : 45, + "comment" : "indefinite length with additional element", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba05000000", + "result" : "invalid" + }, + { + "tcId" : 46, + "comment" : "indefinite length with truncated element", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba060811220000", + "result" : "invalid" + }, + { + "tcId" : 47, + "comment" : "indefinite length with garbage", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000fe02beef", + "result" : "invalid" + }, + { + "tcId" : 48, + "comment" : "indefinite length with nonempty EOC", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0002beef", + "result" : "invalid" + }, + { + "tcId" : 49, + "comment" : "prepend empty sequence", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30473000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 50, + "comment" : "append empty sequence", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba3000", + "result" : "invalid" + }, + { + "tcId" : 51, + "comment" : "append zero", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba020100", + "result" : "invalid" + }, + { + "tcId" : 52, + "comment" : "append garbage with high tag number", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31babf7f00", + "result" : "invalid" + }, + { + "tcId" : 53, + "comment" : "append null with explicit tag", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31baa0020500", + "result" : "invalid" + }, + { + "tcId" : 54, + "comment" : "append null with implicit tag", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31baa000", + "result" : "invalid" + }, + { + "tcId" : 55, + "comment" : "sequence of sequence", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30473045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 56, + "comment" : "truncated sequence: removed last 1 elements", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3023022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365", + "result" : "invalid" + }, + { + "tcId" : 57, + "comment" : "repeating element in sequence", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3067022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 58, + "comment" : "flipped bit 0 in r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236402206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 59, + "comment" : "flipped bit 32 in r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccac983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 60, + "comment" : "flipped bit 48 in r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5133ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 61, + "comment" : "flipped bit 64 in r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc08b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 62, + "comment" : "length of r uses long form encoding", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "304602812100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 63, + "comment" : "length of r contains a leading 0", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "30470282002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 64, + "comment" : "length of r uses 34 instead of 33", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022200813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 65, + "comment" : "length of r uses 32 instead of 33", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 66, + "comment" : "uint32 overflow in length of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a0285010000002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 67, + "comment" : "uint64 overflow in length of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304e028901000000000000002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 68, + "comment" : "length of r = 2**31 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304902847fffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 69, + "comment" : "length of r = 2**31", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304902848000000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 70, + "comment" : "length of r = 2**32 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30490284ffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 71, + "comment" : "length of r = 2**40 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a0285ffffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 72, + "comment" : "length of r = 2**64 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d0288ffffffffffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 73, + "comment" : "incorrect length of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304502ff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 74, + "comment" : "replaced r by an indefinite length tag without termination", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045028000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 75, + "comment" : "removing r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "302202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 76, + "comment" : "lonely integer tag", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30230202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 77, + "comment" : "lonely integer tag", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3024022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502", + "result" : "invalid" + }, + { + "tcId" : 78, + "comment" : "appending 0's to r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 79, + "comment" : "prepending 0's to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30470223000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 80, + "comment" : "appending unused 0's to r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 81, + "comment" : "appending null value to r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365050002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 82, + "comment" : "prepending garbage to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a2226498177022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 83, + "comment" : "prepending garbage to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304922252500022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 84, + "comment" : "appending garbage to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d2223022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650004deadbeef02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 85, + "comment" : "truncated length of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3024028102206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 86, + "comment" : "including undefined tags to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304b2227aa02aabb022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 87, + "comment" : "using composition with indefinite length for r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30492280022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 88, + "comment" : "using composition with wrong tag for r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30492280032100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 89, + "comment" : "Replacing r with NULL", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3024050002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 90, + "comment" : "changing tag value of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 91, + "comment" : "changing tag value of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045012100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 92, + "comment" : "changing tag value of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045032100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 93, + "comment" : "changing tag value of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045042100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 94, + "comment" : "changing tag value of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045ff2100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 95, + "comment" : "dropping value of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3024020002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 96, + "comment" : "using composition for r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304922250201000220813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 97, + "comment" : "modifying first byte of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022102813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 98, + "comment" : "modifying last byte of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323e502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 99, + "comment" : "truncated r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3044022000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832302206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 100, + "comment" : "truncated r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30440220813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 101, + "comment" : "r of size 4130 to check for overflows", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "308210480282102200813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 102, + "comment" : "leading ff in r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30460222ff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 103, + "comment" : "replaced r by infinity", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "302509018002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 104, + "comment" : "replacing r with zero", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "302502010002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 105, + "comment" : "flipped bit 0 in s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31bb", + "result" : "invalid" + }, + { + "tcId" : 106, + "comment" : "flipped bit 32 in s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a456eb31ba", + "result" : "invalid" + }, + { + "tcId" : 107, + "comment" : "flipped bit 48 in s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f713a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 108, + "comment" : "flipped bit 64 in s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758001d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 109, + "comment" : "length of s uses long form encoding", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650281206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 110, + "comment" : "length of s contains a leading 0", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028200206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 111, + "comment" : "length of s uses 33 instead of 32", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502216ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 112, + "comment" : "length of s uses 31 instead of 32", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021f6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 113, + "comment" : "uint32 overflow in length of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028501000000206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 114, + "comment" : "uint64 overflow in length of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304e022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502890100000000000000206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 115, + "comment" : "length of s = 2**31 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502847fffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 116, + "comment" : "length of s = 2**31", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650284800000006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 117, + "comment" : "length of s = 2**32 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650284ffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 118, + "comment" : "length of s = 2**40 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650285ffffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 119, + "comment" : "length of s = 2**64 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650288ffffffffffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 120, + "comment" : "incorrect length of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 121, + "comment" : "replaced s by an indefinite length tag without termination", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502806ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 122, + "comment" : "appending 0's to s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502226ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 123, + "comment" : "prepending 0's to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365022200006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 124, + "comment" : "appending null value to s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502226ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0500", + "result" : "invalid" + }, + { + "tcId" : 125, + "comment" : "prepending garbage to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222549817702206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 126, + "comment" : "prepending garbage to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652224250002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 127, + "comment" : "appending garbage to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0004deadbeef", + "result" : "invalid" + }, + { + "tcId" : 128, + "comment" : "truncated length of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650281", + "result" : "invalid" + }, + { + "tcId" : 129, + "comment" : "including undefined tags to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304b022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652226aa02aabb02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 130, + "comment" : "using composition with indefinite length for s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365228002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 131, + "comment" : "using composition with wrong tag for s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365228003206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 132, + "comment" : "Replacing s with NULL", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650500", + "result" : "invalid" + }, + { + "tcId" : 133, + "comment" : "changing tag value of s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236500206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 134, + "comment" : "changing tag value of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236501206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 135, + "comment" : "changing tag value of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236503206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 136, + "comment" : "changing tag value of s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236504206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 137, + "comment" : "changing tag value of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365ff206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 138, + "comment" : "dropping value of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650200", + "result" : "invalid" + }, + { + "tcId" : 139, + "comment" : "using composition for s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222402016f021ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 140, + "comment" : "modifying first byte of s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206df18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 141, + "comment" : "modifying last byte of s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb313a", + "result" : "invalid" + }, + { + "tcId" : 142, + "comment" : "truncated s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021f6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31", + "result" : "invalid" + }, + { + "tcId" : 143, + "comment" : "truncated s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 144, + "comment" : "s of size 4129 to check for overflows", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30821048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028210216ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "result" : "invalid" + }, + { + "tcId" : 145, + "comment" : "leading ff in s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650221ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 146, + "comment" : "replaced s by infinity", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365090180", + "result" : "invalid" + }, + { + "tcId" : 147, + "comment" : "replacing s with zero", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365020100", + "result" : "invalid" + }, + { + "tcId" : 148, + "comment" : "replaced r by r + n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "3045022101813ef79ccefa9a56f7ba805f0e478583b90deabca4b05c4574e49b5899b964a602206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 149, + "comment" : "replaced r by r - n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "30440220813ef79ccefa9a56f7ba805f0e47858643b030ef461f1bcdf53fde3ef94ce22402206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 150, + "comment" : "replaced r by r + 256 * n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "304602220100813ef79ccefa9a56f7ba805f0e47843fad3bf4853e07f7c98770c99bffc4646502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 151, + "comment" : "replaced r by -r", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "30450221ff7ec10863310565a908457fa0f1b87a7b01a0f22a0a9843f64aedc334367cdc9b02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 152, + "comment" : "replaced r by n - r", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "304402207ec10863310565a908457fa0f1b87a79bc4fcf10b9e0e4320ac021c106b31ddc02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 153, + "comment" : "replaced r by -n - r", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "30450221fe7ec10863310565a908457fa0f1b87a7c46f215435b4fa3ba8b1b64a766469b5a02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 154, + "comment" : "replaced r by r + 2**256", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "3045022101813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 155, + "comment" : "replaced r by r + 2**320", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "304d0229010000000000000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 156, + "comment" : "replaced s by s + n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "30450221016ff18a52dcc0336f7af62400a6dd9b7fc1e197d8aebe203c96c87232272172fb02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 157, + "comment" : "replaced s by s - n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "30450221ff6ff18a52dcc0336f7af62400a6dd9b824c83de0b502cdfc51723b51886b4f07902206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 158, + "comment" : "replaced s by s + 256 * n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "3046022201006ff18a52dcc0336f7af62400a6dd9a3bb60fa1a14815bbc0a954a0758d2c72ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 159, + "comment" : "replaced s by -s", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "30440220900e75ad233fcc908509dbff5922647ef8cd450e008a7fff2909ec5aa914ce4602206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 160, + "comment" : "replaced s by -n - s", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "30450221fe900e75ad233fcc908509dbff592264803e1e68275141dfc369378dcdd8de8d0502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 161, + "comment" : "replaced s by s + 2**256", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "30450221016ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 162, + "comment" : "replaced s by s - 2**256", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "30450221ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 163, + "comment" : "replaced s by s + 2**320", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "304d02290100000000000000006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 164, + "comment" : "Signature with special case values r=0 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100020100", + "result" : "invalid" + }, + { + "tcId" : 165, + "comment" : "Signature with special case values r=0 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100020101", + "result" : "invalid" + }, + { + "tcId" : 166, + "comment" : "Signature with special case values r=0 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201000201ff", + "result" : "invalid" + }, + { + "tcId" : 167, + "comment" : "Signature with special case values r=0 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 168, + "comment" : "Signature with special case values r=0 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 169, + "comment" : "Signature with special case values r=0 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 170, + "comment" : "Signature with special case values r=0 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 171, + "comment" : "Signature with special case values r=0 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 172, + "comment" : "Signature with special case values r=1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101020100", + "result" : "invalid" + }, + { + "tcId" : 173, + "comment" : "Signature with special case values r=1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101020101", + "result" : "invalid" + }, + { + "tcId" : 174, + "comment" : "Signature with special case values r=1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201010201ff", + "result" : "invalid" + }, + { + "tcId" : 175, + "comment" : "Signature with special case values r=1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 176, + "comment" : "Signature with special case values r=1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 177, + "comment" : "Signature with special case values r=1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 178, + "comment" : "Signature with special case values r=1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 179, + "comment" : "Signature with special case values r=1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 180, + "comment" : "Signature with special case values r=-1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff020100", + "result" : "invalid" + }, + { + "tcId" : 181, + "comment" : "Signature with special case values r=-1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff020101", + "result" : "invalid" + }, + { + "tcId" : 182, + "comment" : "Signature with special case values r=-1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff0201ff", + "result" : "invalid" + }, + { + "tcId" : 183, + "comment" : "Signature with special case values r=-1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 184, + "comment" : "Signature with special case values r=-1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 185, + "comment" : "Signature with special case values r=-1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 186, + "comment" : "Signature with special case values r=-1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 187, + "comment" : "Signature with special case values r=-1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 188, + "comment" : "Signature with special case values r=n and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020100", + "result" : "invalid" + }, + { + "tcId" : 189, + "comment" : "Signature with special case values r=n and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101", + "result" : "invalid" + }, + { + "tcId" : 190, + "comment" : "Signature with special case values r=n and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410201ff", + "result" : "invalid" + }, + { + "tcId" : 191, + "comment" : "Signature with special case values r=n and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 192, + "comment" : "Signature with special case values r=n and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 193, + "comment" : "Signature with special case values r=n and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 194, + "comment" : "Signature with special case values r=n and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 195, + "comment" : "Signature with special case values r=n and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 196, + "comment" : "Signature with special case values r=n - 1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140020100", + "result" : "invalid" + }, + { + "tcId" : 197, + "comment" : "Signature with special case values r=n - 1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140020101", + "result" : "invalid" + }, + { + "tcId" : 198, + "comment" : "Signature with special case values r=n - 1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641400201ff", + "result" : "invalid" + }, + { + "tcId" : 199, + "comment" : "Signature with special case values r=n - 1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 200, + "comment" : "Signature with special case values r=n - 1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 201, + "comment" : "Signature with special case values r=n - 1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 202, + "comment" : "Signature with special case values r=n - 1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 203, + "comment" : "Signature with special case values r=n - 1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 204, + "comment" : "Signature with special case values r=n + 1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142020100", + "result" : "invalid" + }, + { + "tcId" : 205, + "comment" : "Signature with special case values r=n + 1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142020101", + "result" : "invalid" + }, + { + "tcId" : 206, + "comment" : "Signature with special case values r=n + 1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641420201ff", + "result" : "invalid" + }, + { + "tcId" : 207, + "comment" : "Signature with special case values r=n + 1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 208, + "comment" : "Signature with special case values r=n + 1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 209, + "comment" : "Signature with special case values r=n + 1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 210, + "comment" : "Signature with special case values r=n + 1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 211, + "comment" : "Signature with special case values r=n + 1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 212, + "comment" : "Signature with special case values r=p and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f020100", + "result" : "invalid" + }, + { + "tcId" : 213, + "comment" : "Signature with special case values r=p and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f020101", + "result" : "invalid" + }, + { + "tcId" : 214, + "comment" : "Signature with special case values r=p and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0201ff", + "result" : "invalid" + }, + { + "tcId" : 215, + "comment" : "Signature with special case values r=p and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 216, + "comment" : "Signature with special case values r=p and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 217, + "comment" : "Signature with special case values r=p and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 218, + "comment" : "Signature with special case values r=p and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 219, + "comment" : "Signature with special case values r=p and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 220, + "comment" : "Signature with special case values r=p + 1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30020100", + "result" : "invalid" + }, + { + "tcId" : 221, + "comment" : "Signature with special case values r=p + 1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30020101", + "result" : "invalid" + }, + { + "tcId" : 222, + "comment" : "Signature with special case values r=p + 1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc300201ff", + "result" : "invalid" + }, + { + "tcId" : 223, + "comment" : "Signature with special case values r=p + 1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 224, + "comment" : "Signature with special case values r=p + 1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 225, + "comment" : "Signature with special case values r=p + 1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 226, + "comment" : "Signature with special case values r=p + 1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 227, + "comment" : "Signature with special case values r=p + 1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 228, + "comment" : "Signature encoding contains incorrect types: r=0, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3008020100090380fe01", + "result" : "invalid" + }, + { + "tcId" : 229, + "comment" : "Signature encoding contains incorrect types: r=0, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100090142", + "result" : "invalid" + }, + { + "tcId" : 230, + "comment" : "Signature encoding contains incorrect types: r=0, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100010101", + "result" : "invalid" + }, + { + "tcId" : 231, + "comment" : "Signature encoding contains incorrect types: r=0, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100010100", + "result" : "invalid" + }, + { + "tcId" : 232, + "comment" : "Signature encoding contains incorrect types: r=0, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201000500", + "result" : "invalid" + }, + { + "tcId" : 233, + "comment" : "Signature encoding contains incorrect types: r=0, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201000c00", + "result" : "invalid" + }, + { + "tcId" : 234, + "comment" : "Signature encoding contains incorrect types: r=0, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201000c0130", + "result" : "invalid" + }, + { + "tcId" : 235, + "comment" : "Signature encoding contains incorrect types: r=0, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201003000", + "result" : "invalid" + }, + { + "tcId" : 236, + "comment" : "Signature encoding contains incorrect types: r=0, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30080201003003020100", + "result" : "invalid" + }, + { + "tcId" : 237, + "comment" : "Signature encoding contains incorrect types: r=1, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3008020101090380fe01", + "result" : "invalid" + }, + { + "tcId" : 238, + "comment" : "Signature encoding contains incorrect types: r=1, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101090142", + "result" : "invalid" + }, + { + "tcId" : 239, + "comment" : "Signature encoding contains incorrect types: r=1, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101010101", + "result" : "invalid" + }, + { + "tcId" : 240, + "comment" : "Signature encoding contains incorrect types: r=1, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101010100", + "result" : "invalid" + }, + { + "tcId" : 241, + "comment" : "Signature encoding contains incorrect types: r=1, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201010500", + "result" : "invalid" + }, + { + "tcId" : 242, + "comment" : "Signature encoding contains incorrect types: r=1, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201010c00", + "result" : "invalid" + }, + { + "tcId" : 243, + "comment" : "Signature encoding contains incorrect types: r=1, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201010c0130", + "result" : "invalid" + }, + { + "tcId" : 244, + "comment" : "Signature encoding contains incorrect types: r=1, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201013000", + "result" : "invalid" + }, + { + "tcId" : 245, + "comment" : "Signature encoding contains incorrect types: r=1, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30080201013003020100", + "result" : "invalid" + }, + { + "tcId" : 246, + "comment" : "Signature encoding contains incorrect types: r=-1, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30080201ff090380fe01", + "result" : "invalid" + }, + { + "tcId" : 247, + "comment" : "Signature encoding contains incorrect types: r=-1, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff090142", + "result" : "invalid" + }, + { + "tcId" : 248, + "comment" : "Signature encoding contains incorrect types: r=-1, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff010101", + "result" : "invalid" + }, + { + "tcId" : 249, + "comment" : "Signature encoding contains incorrect types: r=-1, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff010100", + "result" : "invalid" + }, + { + "tcId" : 250, + "comment" : "Signature encoding contains incorrect types: r=-1, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201ff0500", + "result" : "invalid" + }, + { + "tcId" : 251, + "comment" : "Signature encoding contains incorrect types: r=-1, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201ff0c00", + "result" : "invalid" + }, + { + "tcId" : 252, + "comment" : "Signature encoding contains incorrect types: r=-1, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff0c0130", + "result" : "invalid" + }, + { + "tcId" : 253, + "comment" : "Signature encoding contains incorrect types: r=-1, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201ff3000", + "result" : "invalid" + }, + { + "tcId" : 254, + "comment" : "Signature encoding contains incorrect types: r=-1, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30080201ff3003020100", + "result" : "invalid" + }, + { + "tcId" : 255, + "comment" : "Signature encoding contains incorrect types: r=n, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3028022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141090380fe01", + "result" : "invalid" + }, + { + "tcId" : 256, + "comment" : "Signature encoding contains incorrect types: r=n, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141090142", + "result" : "invalid" + }, + { + "tcId" : 257, + "comment" : "Signature encoding contains incorrect types: r=n, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141010101", + "result" : "invalid" + }, + { + "tcId" : 258, + "comment" : "Signature encoding contains incorrect types: r=n, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141010100", + "result" : "invalid" + }, + { + "tcId" : 259, + "comment" : "Signature encoding contains incorrect types: r=n, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410500", + "result" : "invalid" + }, + { + "tcId" : 260, + "comment" : "Signature encoding contains incorrect types: r=n, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410c00", + "result" : "invalid" + }, + { + "tcId" : 261, + "comment" : "Signature encoding contains incorrect types: r=n, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410c0130", + "result" : "invalid" + }, + { + "tcId" : 262, + "comment" : "Signature encoding contains incorrect types: r=n, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641413000", + "result" : "invalid" + }, + { + "tcId" : 263, + "comment" : "Signature encoding contains incorrect types: r=n, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3028022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641413003020100", + "result" : "invalid" + }, + { + "tcId" : 264, + "comment" : "Signature encoding contains incorrect types: r=p, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3028022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f090380fe01", + "result" : "invalid" + }, + { + "tcId" : 265, + "comment" : "Signature encoding contains incorrect types: r=p, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f090142", + "result" : "invalid" + }, + { + "tcId" : 266, + "comment" : "Signature encoding contains incorrect types: r=p, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f010101", + "result" : "invalid" + }, + { + "tcId" : 267, + "comment" : "Signature encoding contains incorrect types: r=p, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f010100", + "result" : "invalid" + }, + { + "tcId" : 268, + "comment" : "Signature encoding contains incorrect types: r=p, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0500", + "result" : "invalid" + }, + { + "tcId" : 269, + "comment" : "Signature encoding contains incorrect types: r=p, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0c00", + "result" : "invalid" + }, + { + "tcId" : 270, + "comment" : "Signature encoding contains incorrect types: r=p, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0c0130", + "result" : "invalid" + }, + { + "tcId" : 271, + "comment" : "Signature encoding contains incorrect types: r=p, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f3000", + "result" : "invalid" + }, + { + "tcId" : 272, + "comment" : "Signature encoding contains incorrect types: r=p, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3028022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f3003020100", + "result" : "invalid" + }, + { + "tcId" : 273, + "comment" : "Signature encoding contains incorrect types: r=0.25, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "300a090380fe01090380fe01", + "result" : "invalid" + }, + { + "tcId" : 274, + "comment" : "Signature encoding contains incorrect types: r=nan, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006090142090142", + "result" : "invalid" + }, + { + "tcId" : 275, + "comment" : "Signature encoding contains incorrect types: r=True, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006010101010101", + "result" : "invalid" + }, + { + "tcId" : 276, + "comment" : "Signature encoding contains incorrect types: r=False, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006010100010100", + "result" : "invalid" + }, + { + "tcId" : 277, + "comment" : "Signature encoding contains incorrect types: r=Null, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "300405000500", + "result" : "invalid" + }, + { + "tcId" : 278, + "comment" : "Signature encoding contains incorrect types: r=empyt UTF-8 string, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30040c000c00", + "result" : "invalid" + }, + { + "tcId" : 279, + "comment" : "Signature encoding contains incorrect types: r=\"0\", s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060c01300c0130", + "result" : "invalid" + }, + { + "tcId" : 280, + "comment" : "Signature encoding contains incorrect types: r=empty list, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "300430003000", + "result" : "invalid" + }, + { + "tcId" : 281, + "comment" : "Signature encoding contains incorrect types: r=list containing 0, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "300a30030201003003020100", + "result" : "invalid" + }, + { + "tcId" : 282, + "comment" : "Signature encoding contains incorrect types: r=0.25, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3008090380fe01020100", + "result" : "invalid" + }, + { + "tcId" : 283, + "comment" : "Signature encoding contains incorrect types: r=nan, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006090142020100", + "result" : "invalid" + }, + { + "tcId" : 284, + "comment" : "Signature encoding contains incorrect types: r=True, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006010101020100", + "result" : "invalid" + }, + { + "tcId" : 285, + "comment" : "Signature encoding contains incorrect types: r=False, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006010100020100", + "result" : "invalid" + }, + { + "tcId" : 286, + "comment" : "Signature encoding contains incorrect types: r=Null, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050500020100", + "result" : "invalid" + }, + { + "tcId" : 287, + "comment" : "Signature encoding contains incorrect types: r=empyt UTF-8 string, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050c00020100", + "result" : "invalid" + }, + { + "tcId" : 288, + "comment" : "Signature encoding contains incorrect types: r=\"0\", s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060c0130020100", + "result" : "invalid" + }, + { + "tcId" : 289, + "comment" : "Signature encoding contains incorrect types: r=empty list, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30053000020100", + "result" : "invalid" + }, + { + "tcId" : 290, + "comment" : "Signature encoding contains incorrect types: r=list containing 0, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30083003020100020100", + "result" : "invalid" + }, + { + "tcId" : 291, + "comment" : "Edge case for Shamir multiplication", + "flags" : [ + "EdgeCaseShamirMultiplication" + ], + "msg" : "3235353835", + "sig" : "3045022100dd1b7d09a7bd8218961034a39a87fecf5314f00c4d25eb58a07ac85e85eab516022035138c401ef8d3493d65c9002fe62b43aee568731b744548358996d9cc427e06", + "result" : "valid" + }, + { + "tcId" : 292, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "343236343739373234", + "sig" : "304502210095c29267d972a043d955224546222bba343fc1d4db0fec262a33ac61305696ae02206edfe96713aed56f8a28a6653f57e0b829712e5eddc67f34682b24f0676b2640", + "result" : "valid" + }, + { + "tcId" : 293, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "37313338363834383931", + "sig" : "3044022028f94a894e92024699e345fe66971e3edcd050023386135ab3939d550898fb25022032963e5bd41fa5911ed8f37deb86dae0a762bb6121c894615083c5d95ea01db3", + "result" : "valid" + }, + { + "tcId" : 294, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130333539333331363638", + "sig" : "3045022100be26b18f9549f89f411a9b52536b15aa270b84548d0e859a1952a27af1a77ac6022070c1d4fa9cd03cc8eaa8d506edb97eed7b8358b453c88aefbb880a3f0e8d472f", + "result" : "valid" + }, + { + "tcId" : 295, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33393439343031323135", + "sig" : "3045022100b1a4b1478e65cc3eafdf225d1298b43f2da19e4bcff7eacc0a2e98cd4b74b1140220179aa31e304cc142cf5073171751b28f3f5e0fa88c994e7c55f1bc07b8d56c16", + "result" : "valid" + }, + { + "tcId" : 296, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31333434323933303739", + "sig" : "30440220325332021261f1bd18f2712aa1e2252da23796da8a4b1ff6ea18cafec7e171f2022040b4f5e287ee61fc3c804186982360891eaa35c75f05a43ecd48b35d984a6648", + "result" : "valid" + }, + { + "tcId" : 297, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33373036323131373132", + "sig" : "3045022100a23ad18d8fc66d81af0903890cbd453a554cb04cdc1a8ca7f7f78e5367ed88a0022023e3eb2ce1c04ea748c389bd97374aa9413b9268851c04dcd9f88e78813fee56", + "result" : "valid" + }, + { + "tcId" : 298, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "333433363838373132", + "sig" : "304402202bdea41cda63a2d14bf47353bd20880a690901de7cd6e3cc6d8ed5ba0cdb109102203cea66bccfc9f9bf8c7ca4e1c1457cc9145e13e936d90b3d9c7786b8b26cf4c7", + "result" : "valid" + }, + { + "tcId" : 299, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31333531353330333730", + "sig" : "3045022100d7cd76ec01c1b1079eba9e2aa2a397243c4758c98a1ba0b7404a340b9b00ced602203575001e19d922e6de8b3d6c84ea43b5c3338106cf29990134e7669a826f78e6", + "result" : "valid" + }, + { + "tcId" : 300, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "36353533323033313236", + "sig" : "3045022100a872c744d936db21a10c361dd5c9063355f84902219652f6fc56dc95a7139d960220400df7575d9756210e9ccc77162c6b593c7746cfb48ac263c42750b421ef4bb9", + "result" : "valid" + }, + { + "tcId" : 301, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31353634333436363033", + "sig" : "30450221009fa9afe07752da10b36d3afcd0fe44bfc40244d75203599cf8f5047fa3453854022050e0a7c013bfbf51819736972d44b4b56bc2a2b2c180df6ec672df171410d77a", + "result" : "valid" + }, + { + "tcId" : 302, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "34343239353339313137", + "sig" : "3045022100885640384d0d910efb177b46be6c3dc5cac81f0b88c3190bb6b5f99c2641f2050220738ed9bff116306d9caa0f8fc608be243e0b567779d8dab03e8e19d553f1dc8e", + "result" : "valid" + }, + { + "tcId" : 303, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130393533323631333531", + "sig" : "304402202d051f91c5a9d440c5676985710483bc4f1a6c611b10c95a2ff0363d90c2a45802206ddf94e6fba5be586833d0c53cf216ad3948f37953c26c1cf4968e9a9e8243dc", + "result" : "valid" + }, + { + "tcId" : 304, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "35393837333530303431", + "sig" : "3045022100f3ac2523967482f53d508522712d583f4379cd824101ff635ea0935117baa54f022027f10812227397e02cea96fb0e680761636dab2b080d1fc5d11685cbe8500cfe", + "result" : "valid" + }, + { + "tcId" : 305, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33343633303036383738", + "sig" : "304502210096447cf68c3ab7266ed7447de3ac52fed7cc08cbdfea391c18a9b8ab370bc91302200f5e7874d3ac0e918f01c885a1639177c923f8660d1ceba1ca1f301bc675cdbc", + "result" : "valid" + }, + { + "tcId" : 306, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "39383137333230323837", + "sig" : "30440220530a0832b691da0b5619a0b11de6877f3c0971baaa68ed122758c29caaf46b7202206c89e44f5eb33060ea4b46318c39138eaedec72de42ba576579a6a4690e339f3", + "result" : "valid" + }, + { + "tcId" : 307, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33323232303431303436", + "sig" : "30450221009c54c25500bde0b92d72d6ec483dc2482f3654294ca74de796b681255ed58a770220677453c6b56f527631c9f67b3f3eb621fd88582b4aff156d2f1567d6211a2a33", + "result" : "valid" + }, + { + "tcId" : 308, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "36363636333037313034", + "sig" : "3045022100e7909d41439e2f6af29136c7348ca2641a2b070d5b64f91ea9da7070c7a2618b022042d782f132fa1d36c2c88ba27c3d678d80184a5d1eccac7501f0b47e3d205008", + "result" : "valid" + }, + { + "tcId" : 309, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31303335393531383938", + "sig" : "304402205924873209593135a4c3da7bb381227f8a4b6aa9f34fe5bb7f8fbc131a039ffe02201f1bb11b441c8feaa40f44213d9a405ed792d59fb49d5bcdd9a4285ae5693022", + "result" : "valid" + }, + { + "tcId" : 310, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31383436353937313935", + "sig" : "3045022100eeb692c9b262969b231c38b5a7f60649e0c875cd64df88f33aa571fa3d29ab0e0220218b3a1eb06379c2c18cf51b06430786d1c64cd2d24c9b232b23e5bac7989acd", + "result" : "valid" + }, + { + "tcId" : 311, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33313336303436313839", + "sig" : "3045022100a40034177f36091c2b653684a0e3eb5d4bff18e4d09f664c2800e7cafda1daf802203a3ec29853704e52031c58927a800a968353adc3d973beba9172cbbeab4dd149", + "result" : "valid" + }, + { + "tcId" : 312, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "32363633373834323534", + "sig" : "3045022100b5d795cc75cea5c434fa4185180cd6bd21223f3d5a86da6670d71d95680dadbf022054e4d8810a001ecbb9f7ca1c2ebfdb9d009e9031a431aca3c20ab4e0d1374ec1", + "result" : "valid" + }, + { + "tcId" : 313, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31363532313030353234", + "sig" : "3044022007dc2478d43c1232a4595608c64426c35510051a631ae6a5a6eb1161e57e42e102204a59ea0fdb72d12165cea3bf1ca86ba97517bd188db3dbd21a5a157850021984", + "result" : "valid" + }, + { + "tcId" : 314, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "35373438303831363936", + "sig" : "3045022100ddd20c4a05596ca868b558839fce9f6511ddd83d1ccb53f82e5269d559a0155202205b91734729d93093ff22123c4a25819d7feb66a250663fc780cb66fc7b6e6d17", + "result" : "valid" + }, + { + "tcId" : 315, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "36333433393133343638", + "sig" : "30450221009cde6e0ede0a003f02fda0a01b59facfe5dec063318f279ce2de7a9b1062f7b702202886a5b8c679bdf8224c66f908fd6205492cb70b0068d46ae4f33a4149b12a52", + "result" : "valid" + }, + { + "tcId" : 316, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31353431313033353938", + "sig" : "3045022100c5771016d0dd6357143c89f684cd740423502554c0c59aa8c99584f1ff38f609022054b405f4477546686e464c5463b4fd4190572e58d0f7e7357f6e61947d20715c", + "result" : "valid" + }, + { + "tcId" : 317, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130343738353830313238", + "sig" : "3045022100a24ebc0ec224bd67ae397cbe6fa37b3125adbd34891abe2d7c7356921916dfe6022034f6eb6374731bbbafc4924fb8b0bdcdda49456d724cdae6178d87014cb53d8c", + "result" : "valid" + }, + { + "tcId" : 318, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130353336323835353638", + "sig" : "304402202557d64a7aee2e0931c012e4fea1cd3a2c334edae68cdeb7158caf21b68e5a2402207f06cdbb6a90023a973882ed97b080fe6b05af3ec93db6f1a4399a69edf7670d", + "result" : "valid" + }, + { + "tcId" : 319, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "393533393034313035", + "sig" : "3045022100c4f2eccbb6a24350c8466450b9d61b207ee359e037b3dcedb42a3f2e6dd6aeb502203263c6b59a2f55cdd1c6e14894d5e5963b28bc3e2469ac9ba1197991ca7ff9c7", + "result" : "valid" + }, + { + "tcId" : 320, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "393738383438303339", + "sig" : "3045022100eff04781c9cbcd162d0a25a6e2ebcca43506c523385cb515d49ea38a1b12fcad022015acd73194c91a95478534f23015b672ebed213e45424dd2c8e26ac8b3eb34a5", + "result" : "valid" + }, + { + "tcId" : 321, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33363130363732343432", + "sig" : "3045022100f58b4e3110a64bf1b5db97639ee0e5a9c8dfa49dc59b679891f520fdf0584c8702202cd8fe51888aee9db3e075440fd4db73b5c732fb87b510e97093d66415f62af7", + "result" : "valid" + }, + { + "tcId" : 322, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31303534323430373035", + "sig" : "3045022100f8abecaa4f0c502de4bf5903d48417f786bf92e8ad72fec0bd7fcb7800c0bbe302204c7f9e231076a30b7ae36b0cebe69ccef1cd194f7cce93a5588fd6814f437c0e", + "result" : "valid" + }, + { + "tcId" : 323, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "35313734343438313937", + "sig" : "304402205d5b38bd37ad498b2227a633268a8cca879a5c7c94a4e416bd0a614d09e606d2022012b8d664ea9991062ecbb834e58400e25c46007af84f6007d7f1685443269afe", + "result" : "valid" + }, + { + "tcId" : 324, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31393637353631323531", + "sig" : "304402200c1cd9fe4034f086a2b52d65b9d3834d72aebe7f33dfe8f976da82648177d8e3022013105782e3d0cfe85c2778dec1a848b27ac0ae071aa6da341a9553a946b41e59", + "result" : "valid" + }, + { + "tcId" : 325, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33343437323533333433", + "sig" : "3045022100ae7935fb96ff246b7b5d5662870d1ba587b03d6e1360baf47988b5c02ccc1a5b02205f00c323272083782d4a59f2dfd65e49de0693627016900ef7e61428056664b3", + "result" : "valid" + }, + { + "tcId" : 326, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "333638323634333138", + "sig" : "3044022000a134b5c6ccbcefd4c882b945baeb4933444172795fa6796aae1490675470980220566e46105d24d890151e3eea3ebf88f5b92b3f5ec93a217765a6dcbd94f2c55b", + "result" : "valid" + }, + { + "tcId" : 327, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33323631313938363038", + "sig" : "304402202e4721363ad3992c139e5a1c26395d2c2d777824aa24fde075e0d7381171309d0220740f7c494418e1300dd4512f782a58800bff6a7abdfdd20fbbd4f05515ca1a4f", + "result" : "valid" + }, + { + "tcId" : 328, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "39363738373831303934", + "sig" : "304402206852e9d3cd9fe373c2d504877967d365ab1456707b6817a042864694e1960ccf0220064b27ea142b30887b84c86adccb2fa39a6911ad21fc7e819f593be52bc4f3bd", + "result" : "valid" + }, + { + "tcId" : 329, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "34393538383233383233", + "sig" : "30440220188a8c5648dc79eace158cf886c62b5468f05fd95f03a7635c5b4c31f09af4c5022036361a0b571a00c6cd5e686ccbfcfa703c4f97e48938346d0c103fdc76dc5867", + "result" : "valid" + }, + { + "tcId" : 330, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "383234363337383337", + "sig" : "3045022100a74f1fb9a8263f62fc4416a5b7d584f4206f3996bb91f6fc8e73b9e92bad0e1302206815032e8c7d76c3ab06a86f33249ce9940148cb36d1f417c2e992e801afa3fa", + "result" : "valid" + }, + { + "tcId" : 331, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3131303230383333373736", + "sig" : "3044022007244865b72ff37e62e3146f0dc14682badd7197799135f0b00ade7671742bfe02200d80c2238edb4e4a7a86a8c57ca9af1711f406f7f5da0299aa04e2932d960754", + "result" : "valid" + }, + { + "tcId" : 332, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "313333383731363438", + "sig" : "3045022100da7fdd05b5badabd619d805c4ee7d9a84f84ddd5cf9c5bf4d4338140d689ef08022028f1cf4fa1c3c5862cfa149c0013cf5fe6cf5076cae000511063e7de25bb38e5", + "result" : "valid" + }, + { + "tcId" : 333, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "333232313434313632", + "sig" : "3045022100d3027c656f6d4fdfd8ede22093e3c303b0133c340d615e7756f6253aea927238022009aef060c8e4cef972974011558df144fed25ca69ae8d0b2eaf1a8feefbec417", + "result" : "valid" + }, + { + "tcId" : 334, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130363836363535353436", + "sig" : "304402200bf6c0188dc9571cd0e21eecac5fbb19d2434988e9cc10244593ef3a98099f6902204864a562661f9221ec88e3dd0bc2f6e27ac128c30cc1a80f79ec670a22b042ee", + "result" : "valid" + }, + { + "tcId" : 335, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3632313535323436", + "sig" : "3045022100ae459640d5d1179be47a47fa538e16d94ddea5585e7a244804a51742c686443a02206c8e30e530a634fae80b3ceb062978b39edbe19777e0a24553b68886181fd897", + "result" : "valid" + }, + { + "tcId" : 336, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "37303330383138373734", + "sig" : "304402201cf3517ba3bf2ab8b9ead4ebb6e866cb88a1deacb6a785d3b63b483ca02ac4950220249a798b73606f55f5f1c70de67cb1a0cff95d7dc50b3a617df861bad3c6b1c9", + "result" : "valid" + }, + { + "tcId" : 337, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "35393234353233373434", + "sig" : "3045022100e69b5238265ea35d77e4dd172288d8cea19810a10292617d5976519dc5757cb802204b03c5bc47e826bdb27328abd38d3056d77476b2130f3df6ec4891af08ba1e29", + "result" : "valid" + }, + { + "tcId" : 338, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31343935353836363231", + "sig" : "304402205f9d7d7c870d085fc1d49fff69e4a275812800d2cf8973e7325866cb40fa2b6f02206d1f5491d9f717a597a15fd540406486d76a44697b3f0d9d6dcef6669f8a0a56", + "result" : "valid" + }, + { + "tcId" : 339, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "34303035333134343036", + "sig" : "304402200a7d5b1959f71df9f817146ee49bd5c89b431e7993e2fdecab6858957da685ae02200f8aad2d254690bdc13f34a4fec44a02fd745a422df05ccbb54635a8b86b9609", + "result" : "valid" + }, + { + "tcId" : 340, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33303936343537353132", + "sig" : "3044022079e88bf576b74bc07ca142395fda28f03d3d5e640b0b4ff0752c6d94cd553408022032cea05bd2d706c8f6036a507e2ab7766004f0904e2e5c5862749c0073245d6a", + "result" : "valid" + }, + { + "tcId" : 341, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "32373834303235363230", + "sig" : "30450221009d54e037a00212b377bc8874798b8da080564bbdf7e07591b861285809d01488022018b4e557667a82bd95965f0706f81a29243fbdd86968a7ebeb43069db3b18c7f", + "result" : "valid" + }, + { + "tcId" : 342, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "32363138373837343138", + "sig" : "304402202664f1ffa982fedbcc7cab1b8bc6e2cb420218d2a6077ad08e591ba9feab33bd022049f5c7cb515e83872a3d41b4cdb85f242ad9d61a5bfc01debfbb52c6c84ba728", + "result" : "valid" + }, + { + "tcId" : 343, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31363432363235323632", + "sig" : "304402205827518344844fd6a7de73cbb0a6befdea7b13d2dee4475317f0f18ffc81524b02204f5ccb4e0b488b5a5d760aacddb2d791970fe43da61eb30e2e90208a817e46db", + "result" : "valid" + }, + { + "tcId" : 344, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "36383234313839343336", + "sig" : "304502210097ab19bd139cac319325869218b1bce111875d63fb12098a04b0cd59b6fdd3a30220431d9cea3a243847303cebda56476431d034339f31d785ee8852db4f040d4921", + "result" : "valid" + }, + { + "tcId" : 345, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "343834323435343235", + "sig" : "3044022052c683144e44119ae2013749d4964ef67509278f6d38ba869adcfa69970e123d02203479910167408f45bda420a626ec9c4ec711c1274be092198b4187c018b562ca", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0407310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc36226a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0", + "wx" : "07310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc362", + "wy" : "26a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000407310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc36226a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEBzEPkKnq4UmghAL1QZSg97SsQnv42b1s\ndoEHHcR9w2ImptN6xG1h/WAMC/G/+HaJ7RF92msOWTGK4BChl6JsoA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 346, + "comment" : "k*G has a large x-coordinate", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30160211014551231950b75fc4402da1722fc9baeb020103", + "result" : "valid" + }, + { + "tcId" : 347, + "comment" : "r too large", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c020103", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5", + "wx" : "00bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22", + "wy" : "705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEvJfnWF7srUjhZoO8QJFwjhqTDGg/xHAB\n1LODWU8sTiJwWYnPadrq3U5OS4FR7YiN/sIPsBco2J1Ws/OPKunIxQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 348, + "comment" : "r,s are large", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f020103", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0444ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463", + "wx" : "44ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252", + "wy" : "00b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000444ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERK0zmvvCHpq/e2AqXKU16jeBNbbRDYEx\nC92Ck9HfMlK2P/fQd0dw+P4dFyL6g6zQL0NOT8EQoMyPbd3TfVbEYw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 349, + "comment" : "r and s^-1 have a large Hamming weight", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203e9a7582886089c62fb840cf3b83061cd1cff3ae4341808bb5bdee6191174177", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0", + "wx" : "1260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c", + "wy" : "5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEmDCEiyeJE4a9RUb7eDDriO1TXxZaIHT\n7rrSHzfdh4xcmgwamt52c3qIEb1qf5KHyXjuOWqonBHkcinSzLVS8A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 350, + "comment" : "r and s^-1 have a large Hamming weight", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022024238e70b431b1a64efdf9032669939d4b77f249503fc6905feb7540dea3e6d2", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159", + "wx" : "1877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce", + "wy" : "00821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGHcEW+JdNKHQYA+dXADQZFoqVDebbO76\n0ua/XCozUs6CGlMswXUe4dNtQcPWq06bFD5E7EbXNHjqanmlwOVBWQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 351, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020101020101", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77", + "wx" : "455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50", + "wy" : "00aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERVQ5/MPS3uzt3q7OYOe9FzBPNuu2Aq31\noi4Ljx20alCuw4+yuvIh6ajRiHx79iIt0YNGNOdyYzFa9tI2CdBPdw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 352, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020101020102", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece7180449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d", + "wx" : "2e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece718", + "wy" : "0449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece7180449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELh9GawJMDDrOJDfeCRJ/7QS3BvlLGaIb\nscKs81zs5xgESa41I9clNOlklyz9OzivC93ZYZ5a8iPk0aQPNM+fHQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 353, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020101020103", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a2337326ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3", + "wx" : "008e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a23373", + "wy" : "26ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a2337326ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjnq9u9GN50UjdMGHmhw7AdEyYefUVxw7\nR6HHbFWiM3Mm7Yl81Rek9TSduAl4D20vK59imdi1qJB38RGacY/Xsw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 354, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020102020101", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "047b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af1942117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b", + "wx" : "7b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af19", + "wy" : "42117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af1942117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEezM9Q0DT1xjdPmr/fee7+Lcr/WFshCAF\nYFKEI3a5rxlCEXxa/qx1XW83b8Yymn12BRuHEjpKXQvEpTk4DwPeew==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 355, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020102020102", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e503a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff", + "wx" : "00d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e5", + "wy" : "03a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e503a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0wykoN22YWyFHTDO1oLED4PGJ1ih8nWZ\niNZ2OojxwOUDqA1UFWUNQSOXhOji+xI16f6ZHREuu4EYbL8Not46/w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 356, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020102020103", + "result" : "valid" + }, + { + "tcId" : 357, + "comment" : "r is larger than n", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364143020103", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0448969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec", + "wx" : "48969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24", + "wy" : "00b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000448969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAESJabOZkSl7MyplLT7m4B6QmzmQTnH6I1\nSngwx3ULryS0AS0bgw0ZnMsfyXKzK/3tVfCc1i0lfl6ETiflehWU7A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 358, + "comment" : "s is larger than n", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30080201020203ed2979", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0402ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee777eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866", + "wx" : "02ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee77", + "wy" : "7eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000402ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee777eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAu9NbWz9WpTx13hCJuPipsCkNsVYOWGf\nOPtEcrX57nd+tKzU7r2lzXKHX/0qLyYinC3GtGUAkZpDLIZznzroZg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 359, + "comment" : "small r and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30260202010102203a74e9d3a74e9d3a74e9d3a74e9d3a749f8ab3732a0a89604a09bce5b2916da4", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08", + "wx" : "464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584", + "wy" : "00b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERk9P9xVynK5Qcso72AHTGVtnrsZemwGq\n0gopQ9y8tYSxr9KdMaOaEdVwqhWXQ5s7LRlxvy8avxVDLQIHsQ0dCA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 360, + "comment" : "smallish r and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "302b02072d9b4d347952cc02200343aefc2f25d98b882e86eb9e30d55a6eb508b516510b34024ae4b6362330b3", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4cdeadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f", + "wx" : "157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4c", + "wy" : "00deadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4cdeadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEFX+P3fNz619Jz88Q2LhTz5HLzX1mXDUi\nun3XON23mkzerfGlxEjqPJ9BkaiZmr/MdXrG1kVn7wcsR/7GE0Q7jw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 361, + "comment" : "100-bit r and small s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3031020d1033e67e37b32b445580bf4efc02206f906f906f906f906f906f906f906f8fe1cab5eefdb214061dce3b22789f1d6f", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "040934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa", + "wx" : "0934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0", + "wy" : "00d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200040934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECTSlN0ZsB0MOLEj+uZC7Gft4zsyc7kJO\npNEwKRqiN/DU+S0jtGKAS1toxSVYwByZltv3J/zKu+7bliGkAFNa+g==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 362, + "comment" : "small r and 100 bit s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3026020201010220783266e90f43dafe5cd9b3b0be86de22f9de83677d0f50713a468ec72fcf5d57", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c654a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265", + "wx" : "00d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c65", + "wy" : "4a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c654a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1u8gvmbIk/dBqb+Q2bdGddHCoxKWOXrL\nPvF0/QswDGVKDJVHjKADmRYtfw8tyJ79wrKKMPur4oWFcpWksMTiZQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 363, + "comment" : "100-bit r and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3031020d062522bbd3ecbe7c39e93e7c260220783266e90f43dafe5cd9b3b0be86de22f9de83677d0f50713a468ec72fcf5d57", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee0629c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829", + "wx" : "00b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee06", + "wy" : "29c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee0629c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEtykdFATgwMB9q5NyGJ9L1Y0s6qjRXt5U\nTZUUVFup7gYpyaY9XjCHacww7CdqQQ5kZKJ+6v2eWZ2xDwU6T+SoKQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 364, + "comment" : "r and s^-1 are close to n", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03640c1022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6", + "wx" : "6e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8", + "wy" : "186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbigwMwXWQsy5I7ci6oayoLyONzXssm6E\nmxnJ92sv27gYboDWTYyrFk9SOPUxhGG/idTZbuZUTIFsdWaUd3Tg9g==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 365, + "comment" : "r and s are 64-bit integer", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30160209009c44febf31c3594d020900839ed28247c2b06b", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd", + "wx" : "375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9", + "wy" : "00a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEN1vak/avkvtfj0sbXwU047r6s0y3rZ+5\n0Lci5KXDAqmgC584elo5YJeqIWL8W7z0pSYzcvaByU2lHpeZEgmQ/Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 366, + "comment" : "r and s are 100-bit integer", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "301e020d09df8b682430beef6f5fd7c7cf020d0fd0a62e13778f4222a0d61c8a", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44", + "wx" : "00d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197", + "wy" : "00da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE11toIWur4DriV+lLTjvxxS9E498mbRUk\n/4xepp2nMZfaS/+e0cU/RJF6Z9e5eFmOid81nj1ZE+rqJPOuJZq8RA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 367, + "comment" : "r and s are 128-bit integer", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30260211008a598e563a89f526c32ebec8de26367a02110084f633e2042630e99dd0f1e16f7a04bf", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0478bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e", + "wx" : "78bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653", + "wy" : "118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000478bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeLzaFArtI9QwyyPD3A0B9CPbE07pSjqM\ntIPy3qwqxlMRgRT28zBF1OntkQcIUAe/vd+PWP56GiRF1mqZAEVHbg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 368, + "comment" : "r and s are 160-bit integer", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "302e021500aa6eeb5823f7fa31b466bb473797f0d0314c0bdf021500e2977c479e6d25703cebbc6bd561938cc9d1bfb9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677", + "wx" : "00bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c", + "wy" : "1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEu3n2GFf3Q7+htucRHOQJQ3claWnk4VFZ\nEj2VSKzDvmwfnZ+IYNz/0+s23Wwx/y5yJsIAnEyU2NfStWhr96vWdw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 369, + "comment" : "s == 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3025022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1020101", + "result" : "valid" + }, + { + "tcId" : 370, + "comment" : "s == 0", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3025022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1020100", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0493591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518", + "wx" : "0093591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36", + "wy" : "073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000493591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEk1kYJ9nmcTtOn66mLHKyjf76aODAUWC1\n1qroj9LjbDYHP1VFrVr0EK8mr/9oZUz3LUXkk0iTESAyRzR6iQ9FGA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 371, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220419d981c515af8cc82545aac0c85e9e308fbb2eab6acd7ed497e0b4145a18fd9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0431ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0dada01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f", + "wx" : "31ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0da", + "wy" : "00da01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000431ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0dada01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMe0wga7+AB62QCBp7izMGGKTe4WZUUTb\nqVA5Q1h78NraAbjMTfNPWrOxo1lhUgiUbl7jX5jud1uMzs2GzMFlDw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 372, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102201b21717ad71d23bbac60a9ad0baf75b063c9fdf52a00ebf99d022172910993c9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "047dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea854c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4", + "wx" : "7dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea8", + "wy" : "54c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea854c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEff9m+phQn/Pi5RBF9DkFI9zNpDo7wohe\nWMJICQmQ7qhUx2wrmt62u1cYI+B/18ZchjnPnZBSYAZMjnZ1zm2YtA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 373, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102202f588f66018f3dd14db3e28e77996487e32486b521ed8e5a20f06591951777e9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "044280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1", + "wx" : "4280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a", + "wy" : "2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEQoBQmqtk7fwLSiln5MvOhJy1ROSncxPI\n5uzlefvXQgouif5cwZJ9VU5qO7FAM+p8kizXXLosdBX9q1LyCxhg8Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 374, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220091a08870ff4daf9123b30c20e8c4fc8505758dcf4074fcaff2170c9bfcf74f4", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "044f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db", + "wx" : "4f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb", + "wy" : "2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAET43xRRlOPE/D7qJtQ851tALWsXRy3cuy\nVLinmwvz2csqog2ChEyyZjROccp48q0np1oJ5bwPpX5O/Z1GWgiI2w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 375, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102207c370dc0ce8c59a8b273cba44a7c1191fc3186dc03cab96b0567312df0d0b250", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "049598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207", + "wx" : "009598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14", + "wy" : "122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElZilfdZ+w+FrWHoziqOhCjo5E7QaOvMu\nPtP/ATWMaxQSKBnt+AdLvFIffUzc6C/velFnBq/7odk9neqcyuGiBw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 376, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022070b59a7d1ee77a2f9e0491c2a7cfcd0ed04df4a35192f6132dcc668c79a6160e", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "049171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330", + "wx" : "009171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e", + "wy" : "634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEkXH+w8oggGvAhPEvB2CRG2CZC9gOWypx\nygOgSLIPg35jT9F4Y3YbKVjSvk4Un409ervcGL4D9FGrbBf6Ch+DMA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 377, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102202736d76e412246e097148e2bf62915614eb7c428913a58eb5e9cd4674a9423de", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d", + "wx" : "777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9", + "wy" : "00ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEd3yJMLbh0nEQD+aM6T8WP6N2EsX/9n9K\nYvw7r689F6ntc9hvYKUbXtkTU6OwVO3AqpLJ68vQt10Yj9yIJ5HWjQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 378, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102204a1e12831fbe93627b02d6e7f24bccdd6ef4b2d0f46739eaf3b1eaf0ca117770", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf4700603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000", + "wx" : "00eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf470", + "wy" : "0603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf4700603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE6rwkj2JuCmPh64HEPUYaOaHbqIHrbuIV\nKwfDLXG89HAGA8qoudM9sTr0TG777IoZjtYSSsnrF+qv0oJKVF7AAA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 379, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022006c778d4dfff7dee06ed88bc4e0ed34fc553aad67caf796f2a1c6487c1b2e877", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "049f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73", + "wx" : "009f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001", + "wy" : "00f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEn3oTraFYpV+d3xpF8ETwc9m4ADDv3Pyf\nn1hBj7zq8AH4raAXUJD4DUcifWcTtnQPmgCR2IqDfQoc13tYqPKNcw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 380, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102204de459ef9159afa057feb3ec40fef01c45b809f4ab296ea48c206d4249a2b451", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0411c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4dbbbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb", + "wx" : "11c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4db", + "wy" : "00bbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000411c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4dbbbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEcTz5GHNAZtcBuoM6kxAkMPMPjxdnzxt\nZbQ2gm2ptNu763p35Mv9ogcJfENCNwX3LIBHbaPaxApIOwqw8urRyw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 381, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220745d294978007302033502e1acc48b63ae6500be43adbea1b258d6b423dbb416", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb", + "wx" : "00e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4", + "wy" : "161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE4uGGgtUxI6oBpsXQCwxiPWcbRi6oC93W\nUif9UQWYiqQWGQez/SUESpSepByOLqhFncbxZUhWuLYbMVQ7sbRb2w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 382, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102207b2a785e3896f59b2d69da57648e80ad3c133a750a2847fd2098ccd902042b6c", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0490f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197dafadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d", + "wx" : "0090f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197da", + "wy" : "00fadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000490f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197dafadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEkPjUynPeCKZWSq8AUke28P/peFBNzlJg\nX0a3w+Vhl9r62+Uo63DZ7n6g5wcC21T3IVFMe4YErCyyFPHey344PQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 383, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022071ae94a72ca896875e7aa4a4c3d29afdb4b35b6996273e63c47ac519256c5eb1", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc", + "wx" : "00824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e", + "wy" : "3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEgkwZXHPP/fA40QG84Wh7XDthRvOVyIWX\nb3dTsjdrlI483vpvw0fRPk3LxjoLA6FlGAzSvhQxoM90zh6iUILSvA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 384, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102200fa527fa7343c0bc9ec35a6278bfbff4d83301b154fc4bd14aee7eb93445b5f9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f", + "wx" : "2788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f", + "wy" : "30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJ4ilLweOs/ICxPpz4NM4b6899r6FYANj\nb1mZItT1Jo8wtPIHyRm7315nqL5CZagXR1Szq6jxbldbd/9NWn62Tw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 385, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102206539c0adadd0525ff42622164ce9314348bd0863b4c80e936b23ca0414264671", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b415087401b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4", + "wx" : "00d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b4150874", + "wy" : "01b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b415087401b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1TO3iaSviQ+nqCofrljEBPmmKlC0mtr6\ns0nFE7QVCHQBtBcbgD52s0qYYeEPe8KJoGb9Ab0p+EyYehCl+xjC1A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 386, + "comment" : "point at infinity during verify", + "flags" : [ + "PointDuplication", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "043a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a", + "wx" : "3a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4", + "wy" : "221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOjFQeYyK9p0ebpgfOkVAK6HXMvS+gzDF\nFk9J4Q7FVbQiG9hCvF5Nl+/zcWX2DjmYpCTXKkUM+V6kd8eCh9A0Og==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 387, + "comment" : "edge case for signature malleability", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a002207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "043b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e800de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026", + "wx" : "3b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e80", + "wy" : "0de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e800de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOzffX7NHxpoPF9hcDHyoNzaIOoJeExQ9\nD8/IEB6FHoAN48CQtsohulQ1FzMMBLEvlIxrrfFKY6v/3074x1NwJg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 388, + "comment" : "edge case for signature malleability", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a002207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82ce87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e", + "wx" : "00feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82c", + "wy" : "00e87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82ce87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE/rUWOw7OMP8+A8fVXEOA+i+oHuLANUlC\n/28IyZ0M2CzofeBe4b2gidPk4kj6D3IRAqz//fUOZUvigUM5md+Jfg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 389, + "comment" : "u1 == 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd414922897640683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2", + "wx" : "238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd4149228976", + "wy" : "40683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd414922897640683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEI4ztABzyK4hT4C7cicvspQULp+BCp6d/\nk4LNQUkiiXZAaD0wlGQ4QPKViQqkwYqjm0HXfdD7O7JwDk+ewoT/wg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 390, + "comment" : "u1 == n - 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35ed2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf", + "wx" : "00961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35e", + "wy" : "00d2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35ed2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElhz2SBfAbA5Rs8JzbJIv3hi9jEkG/Nf1\n72bEZ4UI817SxdGBaM++cPLxI710GSMruS3WkRPilBBhiJSBxaAnvw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 391, + "comment" : "u2 == 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0413681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b1028816528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384", + "wx" : "13681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b10288", + "wy" : "16528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000413681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b1028816528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEE2gerhaM1Op88uKkXQUnQtEKn2TnloZ9\nvcuCn+CxAogWUodg0Xc3bAnfed45VXwynMF1NRes/+j6LsKYAmuDhA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 392, + "comment" : "u2 == n - 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "045aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c291c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b", + "wx" : "5aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c2", + "wy" : "0091c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200045aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c291c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWqer/ba0CG1UMyXl15xulc5C+GbSu4SQ\nljOgS7GqMcKRyACIeUkF4dozM22HTi+RzPRcxZGFvt5d1vP3rKrhiw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 393, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022016e1e459457679df5b9434ae23f474b3e8d2a70bd6b5dbe692ba16da01f1fb0a", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0400277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e464108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41", + "wx" : "277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e4", + "wy" : "64108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000400277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e464108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEACd3kbMFpFsrOVkLLwXTOSpsgYLO9OtU\nASDg9cIGw+RkEIIz+wuMOsiS15744Pv5LtEzrdtFVCcBMlhNxS7vQQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 394, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02201c940f313f92647be257eccd7ed08b0baef3f0478f25871b53635302c5f6314a", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1ac75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49", + "wx" : "6efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1a", + "wy" : "00c75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1ac75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbvoJK2jelGDwvMkZAFpfboDhnemJaL48\n0sdwqZSb+xrHXm5Qh9ZVDV+b6x555QKTB7wlUjXi1dyZJBrDq4hsSQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 395, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022015d94a85077b493f91cb7101ec63e1b01be58b594e855f45050a8c14062d689b", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0472d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942", + "wx" : "72d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058", + "wy" : "00e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000472d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEctShnE+dLPWEjqQERbcNRpa18C1jLAxl\nTMfX7rDG0FjoxM2ZQ+RZF0x6wB+nQhmOR+bBmmvbDE9sI3gxwbP5Qg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 396, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205b1d27a7694c146244a5ad0bd0636d9d9ef3b9fb58385418d9c982105077d1b7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e740258f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec", + "wx" : "2a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e7402", + "wy" : "58f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e740258f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEKo6i9Q3M7QwhdXW9+nzUfRxvEABB7A41\nUSeUwb5+dAJY+MFxIu0wP9pxQ+tYvt5wKVtlMmYBOwsOvT8FMTf27A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 397, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202d85896b3eb9dbb5a52f42f9c9261ed3fc46644ec65f06ade3fd78f257e43432", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0488de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b80c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946", + "wx" : "0088de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b8", + "wy" : "0c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000488de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b80c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEiN5onOmvHpS+aiCJyKixJT/9u2yOnIYk\nm6IgABpK07gMSZjlSEL0E7ntsYJay7YzXoHk0YSysByL69yF0fKJRg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 398, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205b0b12d67d73b76b4a5e85f3924c3da7f88cc89d8cbe0d5bc7faf1e4afc86864", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9", + "wx" : "00fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7", + "wy" : "00b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE/qLTH3D5DV+z4A4YasQqs8FhXO5xTgtO\nETGz1NgiW/ewN6GN8qwVND8w90Bn3fKegX1fd/jc4FcU2lnAlPDNqQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 399, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220694c146244a5ad0bd0636d9e12bc9e09e60e68b90d0b5e6c5dddd0cb694d8799", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "047258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0", + "wx" : "7258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db", + "wy" : "17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEcliRHj1CM0kWZHnb4Lg0Gvf70D0KfhDt\nzLNrbO6lo9sXrCuJknkRKPo7ltwvvUyjv6eC7ygy/GZWlD2xjnNGsA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 400, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203d7f487c07bfc5f30846938a3dcef696444707cf9677254a92b06c63ab867d22", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "044f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470", + "wx" : "4f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914", + "wy" : "00c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAETyhGHepkR01rs00Umcl9N7npVjPfHO7q\nrNRQFsmLORTIgYgQuMwG3bQOihJhxSj6pYlFXVpt+Tt3vF4OSTx0cA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 401, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206c7648fc0fbf8a06adb8b839f97b4ff7a800f11b1e37c593b261394599792ba4", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0474f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b", + "wx" : "74f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66", + "wy" : "00eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000474f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEdPKoFPtdjsqRppteYHEnMrOTfeMoKb6X\nTte2jFwvXWbv8PB8VvmHplf0IZYgX1iMDx2W/YpjpfI4tI9Hh4j+Ow==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 402, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220641c9c5d790dc09cdd3dfabb62cdf453e69747a7e3d7aa1a714189ef53171a99", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6ab2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad", + "wx" : "195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6a", + "wy" : "00b2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6ab2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGVtRp8xKIbgnSnCpDed5gUw8jKNYMoII\nwJop8za4LWqyQWt8kv/9wpw7EoLdKnek0E3390UgRzk9hJmJxc7prQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 403, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022029798c5c45bdf58b4a7b2fdc2c46ab4af1218c7eeb9f0f27a88f1267674de3b0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0", + "wx" : "622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa", + "wy" : "736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYi/HRzIDS+wt3zvBbTSz0fejJ90qjBm6\ntLtP46JLWKpzay8vrnb0367MkJYzOwEyjVHrP9qckifpDQtEmYPE8A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 404, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02200b70f22ca2bb3cefadca1a5711fa3a59f4695385eb5aedf3495d0b6d00f8fd85", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c70827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93", + "wx" : "1f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c7", + "wy" : "0827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c70827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEH3+FyvLXVQ56+bZQI+u03ONFAxFpIwnb\nJplpuDS2EccIJ/RbeAIOy7r0hP3Vv6rmhw8RhMIVgbr274K9e1MPkw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 405, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022016e1e459457679df5b9434ae23f474b3e8d2a70bd6b5dbe692ba16da01f1fb0a", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0449c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377aefc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d", + "wx" : "49c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377a", + "wy" : "00efc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000449c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377aefc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEScGX3ICtHaR6Q0K5OJPo4fsLuU/DOoPn\ng8ALJMeBN3rvwg2pK6x2KVH3JHS+zHNNTMIrqBuJXigv2sTfevDzfQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 406, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202252d685e831b6cf095e4f0535eeaf0ddd3bfa91c210c9d9dc17224702eaf88f", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c", + "wx" : "00d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe", + "wy" : "7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE2MtoUXthalZACqOGhjXlS29plZii9hZ3\nV2VJgLr2rL5+yM9EnISaoDRhow762kFFPFfG5vvJO7xvpJrabcBVXA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 407, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022075135abd7c425b60371a477f09ce0f274f64a8c6b061a07b5d63e93c65046c53", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750", + "wx" : "030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3", + "wy" : "00b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAwcT+2Pyqm/iyt8bIO/CWcd0Rdr6h9rD\nmLhAZco0ffOyJ4GN4aObWJywcdg+UxfMzcIzjlHjEv4x2Nw0pIAXUA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 408, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b17", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950", + "wx" : "00babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7", + "wy" : "252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEurs2d7CVWALY6SmkE1VkDq8eoTU/incT\nMcSUbjSAr6clLxlsh+09KlnTsbVZE3/tABP+zvwZ+1qSaCubylG5UA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 409, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203e888377ac6c71ac9dec3fdb9b56c9feaf0cfaca9f827fc5eb65fc3eac811210", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9", + "wx" : "1aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60", + "wy" : "00bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGqsgGHk0cREaig6bFD/eAvyVkgeW06Y9\n4ym0JDlvumC75BMHBRdHkkQbMY06ox3+hXeCHptEbsVz0nLgNsTr6Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 410, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022030bbb794db588363b40679f6c182a50d3ce9679acdd3ffbe36d7813dacbdc818", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75", + "wx" : "008cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff", + "wy" : "47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjLC5CUmcg+qAbNiFsd1GegEZ8GqIoCdu\nsM/aJ0U1qP9HtUKIM7w/LIv52QQRWM8zcYpplhzQFym8ABHR5YardQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 411, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202c37fd995622c4fb7fffffffffffffffc7cee745110cb45ab558ed7c90c15a2f", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0", + "wx" : "008f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d", + "wy" : "3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjwPPGkInK7FTJyMJP3Lm/urIXhcA6fvp\npqLdZC10v107iacYna2M91/CL28ViqJ/nCygDaynhb4zWPK9o4YsoA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 412, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02207fd995622c4fb7ffffffffffffffffff5d883ffab5b32652ccdcaa290fccb97d", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0444de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8acea2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12", + "wx" : "44de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8ace", + "wy" : "00a2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000444de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8acea2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERN47nHpXqMnoIJUnU0IefZh7s9efcfAT\ngFyJfgGPis6iRgdYyPmNP9zhIalDZZ43LDJv/y5fwq5/o/edquE8Eg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 413, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304302207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc021f4cd53ba7608fffffffffffffffffffff9e5cf143e2539626190a3ab09cce47", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204", + "wx" : "6fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a", + "wy" : "0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEb7iytI4zAxJorWpRdITciDnqkPZmnqDH\nrDIz4qwxOUoKyLvn9zwv9N+ZeHJ6wd/C/VhkfSDzH5kQUxa2RnHyBA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 414, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205622c4fb7fffffffffffffffffffffff928a8f1c7ac7bec1808b9f61c01ec327", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c", + "wx" : "00bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6", + "wy" : "00f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEvqcRIqBIaT6QX/YCs8+d0Yr2m5/J2EMd\nKx3Sa5Qsleb0PHuLletiCCwS2529p/445Fy+SkiGkH+4G9sMXqkkbA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 415, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022044104104104104104104104104104103b87853fd3b7d3f8e175125b4382f25ed", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391", + "wx" : "00da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156", + "wy" : "00e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE2pGMcxugaiDLlO8zt3jpgaQEowXxlB/j\nNma0WwM1MVbiuyaU9XW0UYO+eOXJtSEL879Ij9TIKUUW2JVyyk9TkQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 416, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202739ce739ce739ce739ce739ce739ce705560298d1f2f08dc419ac273a5b54d9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "043007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5", + "wx" : "3007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d", + "wy" : "5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMAfpLDk32t55ZN+jWw7/Ax9+sCrtCgMU\nQREGzetw/j1adUb8BVKZeyDj1vQT514stm4RYyJpcRS3m6xzS/xNxQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 417, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02204888888888888888888888888888888831c83ae82ebe0898776b4c69d11f88de", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0460e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9bd2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567", + "wx" : "60e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9b", + "wy" : "00d2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000460e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9bd2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYOc071Yk08vw3dN1ARvWY9bWrrxkTrWZ\n/fmNvc0YzpvS2Qs6wx8TmvgyzM9sy7ssbqEfqXNw3JkG2kdNfYp1Zw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 418, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206492492492492492492492492492492406dd3a19b8d5fb875235963c593bd2d3", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0485a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba33769744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c", + "wx" : "0085a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba337", + "wy" : "69744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000485a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba33769744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEhakA6XhY9pPAt9+iYeOA2tbqBG0fZd3u\n7dX32K8LozdpdE0VrdT2wLw7DaKuyTs0y4xl+TQN33TnsACe7szOPA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 419, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b15", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0438066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed", + "wx" : "38066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046", + "wy" : "00a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000438066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOAZvddiO/EyT3jb0ngN7I0zBix3lYIdQ\npiyrA0VAEEaj6EvtjPy4Ge9NVQRE8s5LZRdmtp4uKQH4iDb/kANP7Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 420, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b17", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0498f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabfa33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89", + "wx" : "0098f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabf", + "wy" : "00a33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000498f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabfa33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEmPaBd9yVwbTL+lJFSIylI6fVYpRw0DXW\nIaRDxy85qr+jPSlUb6HGSPLH1cz3DPHOSrebXbGsBZ2+zQaNvf8biQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 421, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "045c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191", + "wx" : "5c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277", + "wy" : "00e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200045c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEXCu/ojybmtB/A4qom0kwvyZ9lAHkJV3p\n6NoKUHjsgnfj6IKjHV5qN54Hk5g8ze05uVxDU6sv8B6lNpukewwxkQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 422, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220185ddbca6dac41b1da033cfb60c152869e74b3cd66e9ffdf1b6bc09ed65ee40c", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a3853547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc", + "wx" : "2ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385", + "wy" : "3547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a3853547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELqcTNDIznGnSf5smcoG9Ld1fGdYzjUAK\nBc02R7FXo4U1R4CCmESO215wGt6EzV+xrJVnul6Ptoprkz7EtcyEzA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 423, + "comment" : "point duplication during verification", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3044022032b0d10d8d0e04bc8d4d064d270699e87cffc9b49c5c20730e1c26f6105ddcda022029ed3d67b3d505be95580d77d5b792b436881179b2b6b2e04c5fe592d38d82d9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763", + "wx" : "2ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385", + "wy" : "00cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELqcTNDIznGnSf5smcoG9Ld1fGdYzjUAK\nBc02R7FXo4XKuH99Z7txJKGP5SF7MqBOU2qYRaFwSXWUbME6SjN3Yw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 424, + "comment" : "duplication bug", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3044022032b0d10d8d0e04bc8d4d064d270699e87cffc9b49c5c20730e1c26f6105ddcda022029ed3d67b3d505be95580d77d5b792b436881179b2b6b2e04c5fe592d38d82d9", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff", + "wx" : "008aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e", + "wy" : "1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEiqLGT6nGQ3Vjq/vL0AsgSNSMGMFSoqb0\nkDbedkfr6C4c5kOHmVxooGD6O8A5mwXMBu7H1Zj3UEGkkX5pK39R/w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 425, + "comment" : "comparison with point at infinity ", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0022033333333333333333333333333333332f222f8faefdb533f265d461c29a47373", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71fdd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd", + "wx" : "391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71f", + "wy" : "00dd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71fdd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEORQn/37ngBPBSux9lqigYiCSmKeDg16U\n/WVJ1QL/9x/dZiTsNDrZ/PTZhyGB5Z+EL5ukzMrgmmwJcvtqxrTGvQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 426, + "comment" : "extreme value for k and edgecase s", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138ec1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e", + "wx" : "00e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138e", + "wy" : "00c1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138ec1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE52K4ohm08YAhnMepBZJF5JYb0ZHAOJl4\nnHo0uJ6ME47BUz7wQZu3N24L/ekxnRCgaWh5HZ6g7tnBzmNFrtl1ng==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 427, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "049aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175", + "wx" : "009aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952", + "wy" : "00fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEmu2w0oHbFk4TAADFaX+uDzBe+Ei+b/+0\nOsWT+7lQ6VL6b2MzWb3NgrVrC5+WWwN3idRrmoFBt5GyrvpxP5bBdQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 428, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd", + "wx" : "008ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee", + "wy" : "1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEitRF22KBYmDk5of9GITki5/AY20DFUfW\nMxXnkuGb+u4d5k+Z1fHNi27Jyw94emVK6GmTuj2xAI70PP8GhMsivQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 429, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566", + "wx" : "1f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32", + "wy" : "00e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEH1eZyVvokGOyTybkDLkowahop2+wCUYH\n6AQ9tAnJHDLnVyToE6QZHjqDkAfwji6Jc4iwbUoA3m3mDlNtkfq1Zg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 430, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d", + "wx" : "00a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc", + "wy" : "28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEozMaThtCI+wsAn7dSCySihTtNY2T8dQh\nfTmr9p/LXMwo1oTSqqvNY4N3XKpiOd4m1MaTe7YD7LQZYIL0z/1QnQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 431, + "comment" : "extreme value for k", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee502200eb10e5ab95f2f275348d82ad2e4d7949c8193800d8c9c75df58e343f0ebba7b", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "043f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb248185ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d", + "wx" : "3f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb24818", + "wy" : "5ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb248185ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEPzlSGZd0x885s4tmyxBCpiYNhoCAOEXk\n1DOtujuySBhepJW2jLx+1Bc+5jyQQtxQJiXH634h+wLKmpEU4KOhjQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 432, + "comment" : "extreme value for k and edgecase s", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698", + "wx" : "00cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e", + "wy" : "054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEzfuMD0IuFE4TfCQSyGwXH1/j+j9bu1RO\nkHYojzzteG4FT9ByG3fBHHm+rLPJQhGwoZvaCGUu/q+SUTo7ChY2mA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 433, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0473598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d", + "wx" : "73598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3", + "wy" : "00cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000473598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEc1mKahxoJ4+mv9DOQGTmgjW8HA9rIKko\nEIvjNnMPh+PLrmElGbUDLsyFrtgRJxqV/nk51dNGAUC6MY9NFKujHQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 434, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0458debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a16773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d", + "wx" : "58debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a1", + "wy" : "6773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000458debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a16773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWN69mn7iydWRMkeKVECuTV1+1Dcwg2n5\nLqhsghg/EKFnc+dvXtv02g5PG9/6wPVyV+HfpGWEKTEwmiQkX9pqXQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 435, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f", + "wx" : "008b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b", + "wy" : "00950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEi5BN5HlnNAxfjDVypyCSTvdXhjf+qxlJ\nrLJBpaasP1uVCQRJb5gksdY/MxO64huJ+uia/fyBG17OA/1aowGGTw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 436, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b", + "wx" : "00f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a", + "wy" : "346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE9IkrbVJcdx4DXyolJwjzeE5II4YEtPlN\nxW6qHlRtlBo0axqgvOaLHFDltS9Qn7VSLlwl4Ci8j4Y0Au23vK2LGw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 437, + "comment" : "extreme value for k", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179802200eb10e5ab95f2f275348d82ad2e4d7949c8193800d8c9c75df58e343f0ebba7b", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "wx" : "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "wy" : "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeb5mfvncu6xVoGKVzocLBwKb/NstzijZ\nWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 438, + "comment" : "public key shares x-coordinate with generator", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3045022100bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca60502302202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result" : "invalid" + }, + { + "tcId" : 439, + "comment" : "public key shares x-coordinate with generator", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3044022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e02202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777", + "wx" : "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "wy" : "00b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeb5mfvncu6xVoGKVzocLBwKb/NstzijZ\nWfKBWxb4F5i3xSWI2Vw7mqJbBAPx7vdXAuhLt1l6q+ZjuC9vBO8ndw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 440, + "comment" : "public key shares x-coordinate with generator", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3045022100bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca60502302202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result" : "invalid" + }, + { + "tcId" : 441, + "comment" : "public key shares x-coordinate with generator", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3044022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e02202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152", + "wx" : "782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963", + "wy" : "00af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeCyO0X47Kng7VGTzOwllKnHGeOBexR6E\n4rz8Zjo96WOvmstCgLjH98QvTvmrpiRewewXEv04oPqWQY2M1qphUg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 442, + "comment" : "pseudorandom signature", + "flags" : [ + "ValidSignature" + ], + "msg" : "", + "sig" : "3045022100f80ae4f96cdbc9d853f83d47aae225bf407d51c56b7776cd67d0dc195d99a9dc02204cfc1d941e08cb9aceadde0f4ccead76b30d332fc442115d50e673e28686b70b", + "result" : "valid" + }, + { + "tcId" : 443, + "comment" : "pseudorandom signature", + "flags" : [ + "ValidSignature" + ], + "msg" : "4d7367", + "sig" : "30440220109cd8ae0374358984a8249c0a843628f2835ffad1df1a9a69aa2fe72355545c02205390ff250ac4274e1cb25cd6ca6491f6b91281e32f5b264d87977aed4a94e77b", + "result" : "valid" + }, + { + "tcId" : 444, + "comment" : "pseudorandom signature", + "flags" : [ + "ValidSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100d035ee1f17fdb0b2681b163e33c359932659990af77dca632012b30b27a057b302201939d9f3b2858bc13e3474cb50e6a82be44faa71940f876c1cba4c3e989202b6", + "result" : "valid" + }, + { + "tcId" : 445, + "comment" : "pseudorandom signature", + "flags" : [ + "ValidSignature" + ], + "msg" : "0000000000000000000000000000000000000000", + "sig" : "304402204f053f563ad34b74fd8c9934ce59e79c2eb8e6eca0fef5b323ca67d5ac7ed23802204d4b05daa0719e773d8617dce5631c5fd6f59c9bdc748e4b55c970040af01be5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff00000001060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1", + "wx" : "6e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff", + "wy" : "01060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff00000001060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEboI1VUUpFAmRgsaywdbwtdKNUMzQBa8s\n4bulQapAyv8AAAABBgSS1aVnPg8l2NUPt+WMSdhtRtQhaVXgqj1A4Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 446, + "comment" : "y-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "304402206d6a4f556ccce154e7fb9f19e76c3deca13d59cc2aeb4ecad968aab2ded45965022053b9fa74803ede0fc4441bf683d56c564d3e274e09ccf47390badd1471c05fb7", + "result" : "valid" + }, + { + "tcId" : 447, + "comment" : "y-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022100aad503de9b9fd66b948e9acf596f0a0e65e700b28b26ec56e6e45e846489b3c4021f0ddc3a2f89abb817bb85c062ce02f823c63fc26b269e0bc9b84d81a5aa123d", + "result" : "valid" + }, + { + "tcId" : 448, + "comment" : "y-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "30450221009182cebd3bb8ab572e167174397209ef4b1d439af3b200cdf003620089e43225022054477c982ea019d2e1000497fc25fcee1bccae55f2ac27530ae53b29c4b356a4", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40cafffffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e", + "wx" : "6e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff", + "wy" : "00fffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40cafffffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEboI1VUUpFAmRgsaywdbwtdKNUMzQBa8s\n4bulQapAyv/////++fttKlqYwfDaJyrwSBpztieSuSvelqoeVcK7Tg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 449, + "comment" : "y-coordinate of the public key is large", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "304402203854a3998aebdf2dbc28adac4181462ccac7873907ab7f212c42db0e69b56ed802203ed3f6b8a388d02f3e4df9f2ae9c1bd2c3916a686460dffcd42909cd7f82058e", + "result" : "valid" + }, + { + "tcId" : 450, + "comment" : "y-coordinate of the public key is large", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100e94dbdc38795fe5c904d8f16d969d3b587f0a25d2de90b6d8c5c53ff887e360702207a947369c164972521bb8af406813b2d9f94d2aeaa53d4c215aaa0a2578a2c5d", + "result" : "valid" + }, + { + "tcId" : 451, + "comment" : "y-coordinate of the public key is large", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022049fc102a08ca47b60e0858cd0284d22cddd7233f94aaffbb2db1dd2cf08425e102205b16fca5a12cdb39701697ad8e39ffd6bdec0024298afaa2326aea09200b14d6", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04000000013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d", + "wx" : "013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0", + "wy" : "00f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004000000013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAAAAAT/SIkjWTZX3PCm0irSGMYUL5QP9\nAPhGi18PcOD27nqkO8LG/SWx2CaSQcvdnbsNrJbcliMfQwcF+DhxfQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 452, + "comment" : "x-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022041efa7d3f05a0010675fcb918a45c693da4b348df21a59d6f9cd73e0d831d67a02204454ada693e5e26b7bd693236d340f80545c834577b6f73d378c7bcc534244da", + "result" : "valid" + }, + { + "tcId" : 453, + "comment" : "x-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100b615698c358b35920dd883eca625a6c5f7563970cdfc378f8fe0cee17092144c022025f47b326b5be1fb610b885153ea84d41eb4716be66a994e8779989df1c863d4", + "result" : "valid" + }, + { + "tcId" : 454, + "comment" : "x-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "304502210087cf8c0eb82d44f69c60a2ff5457d3aaa322e7ec61ae5aecfd678ae1c1932b0e02203add3b115815047d6eb340a3e008989eaa0f8708d1794814729094d08d2460d3", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0425afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dfffffffffa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35", + "wx" : "25afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dffffffff", + "wy" : "00fa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000425afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dfffffffffa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJa/WiayrrtZ8Hylt5ZQG+MVQ9XFGoLTs\nLJeHbf/////6RqduUgMi37xJHsTwzBl0IPxOpYg9j23VPDVLxPZ8NQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 455, + "comment" : "x-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022062f48ef71ace27bf5a01834de1f7e3f948b9dce1ca1e911d5e13d3b104471d8202205ea8f33f0c778972c4582080deda9b341857dd64514f0849a05f6964c2e34022", + "result" : "valid" + }, + { + "tcId" : 456, + "comment" : "x-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100f6b0e2f6fe020cf7c0c20137434344ed7add6c4be51861e2d14cbda472a6ffb402206416c8dd3e5c5282b306e8dc8ff34ab64cc99549232d678d714402eb6ca7aa0f", + "result" : "valid" + }, + { + "tcId" : 457, + "comment" : "x-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100db09d8460f05eff23bc7e436b67da563fa4b4edb58ac24ce201fa8a358125057022046da116754602940c8999c8d665f786c50f5772c0a3cdbda075e77eabc64df16", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb93f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff", + "wx" : "00d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb9", + "wy" : "3f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb93f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0S5sZrZ3NMPITSYBz1013Al+J2N/CspK\nT9t0tqrdO7k/W9/4i9VzbfiY5pkAbtdQ8RzwfFhmzXrXDHEh/////w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 458, + "comment" : "y-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "30440220592c41e16517f12fcabd98267674f974b588e9f35d35406c1a7bb2ed1d19b7b802203e65a06bd9f83caaeb7b00f2368d7e0dece6b12221269a9b5b765198f840a3a1", + "result" : "valid" + }, + { + "tcId" : 459, + "comment" : "y-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100be0d70887d5e40821a61b68047de4ea03debfdf51cdf4d4b195558b959a032b202207d994b2d8f1dbbeb13534eb3f6e5dccd85f5c4133c27d9e64271b1826ce1f67d", + "result" : "valid" + }, + { + "tcId" : 460, + "comment" : "y-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100fae92dfcb2ee392d270af3a5739faa26d4f97bfd39ed3cbee4d29e26af3b206a02206c9ba37f9faa6a1fd3f65f23b4e853d4692a7274240a12db7ba3884830630d16", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb", + "wx" : "6d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000", + "wy" : "00e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbUp/YNR3Sk8KqLve25U8fup5CUB+MWR1\nVmS8KAAAAADmWdNOTfONnoyeqt+6NmEsdpGVvobHeqw/NueLU4aA+w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 461, + "comment" : "x-coordinate of the public key has many trailing 0's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "30440220176a2557566ffa518b11226694eb9802ed2098bfe278e5570fe1d5d7af18a94302201291df6a0ed5fc0d15098e70bcf13a009284dfd0689d3bb4be6ceeb9be1487c4", + "result" : "valid" + }, + { + "tcId" : 462, + "comment" : "x-coordinate of the public key has many trailing 0's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022060be20c3dbc162dd34d26780621c104bbe5dace630171b2daef0d826409ee5c20220427f7e4d889d549170bda6a9409fb1cb8b0e763d13eea7bd97f64cf41dc6e497", + "result" : "valid" + }, + { + "tcId" : 463, + "comment" : "x-coordinate of the public key has many trailing 0's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100edf03cf63f658883289a1a593d1007895b9f236d27c9c1f1313089aaed6b16ae02201a4dd6fc0814dc523d1fefa81c64fbf5e618e651e7096fccadbb94cd48e5e0cd", + "result" : "valid" + } + ] + } + ] +} diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/tools/check-abi.sh b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/tools/check-abi.sh new file mode 100755 index 00000000..601a64ba --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/tools/check-abi.sh @@ -0,0 +1,74 @@ +#!/bin/sh + +set -eu + +default_base_version="$(git describe --match "v*.*.*" --abbrev=0)" +default_new_version="HEAD" + +display_help_and_exit() { + echo "Usage: $0 [ []]" + echo "" + echo "Description: This script uses the ABI Compliance Checker tool to determine if the ABI" + echo " of a new version of libsecp256k1 has changed in a backward-incompatible way." + echo "" + echo "Options:" + echo " base_ver Specify the base version as a git commit-ish" + echo " (default: most recent reachable tag matching \"v.*.*\", currently \"$default_base_version\")" + echo " new_ver Specify the new version as a git commit-ish" + echo " (default: $default_new_version)" + echo " -h, --help Display this help message" + exit 0 +} + +if [ "$#" -eq 0 ]; then + base_version="$default_base_version" + new_version="$default_new_version" +elif [ "$#" -eq 1 ] && { [ "$1" = "-h" ] || [ "$1" = "--help" ]; }; then + display_help_and_exit +elif [ "$#" -eq 1 ] || [ "$#" -eq 2 ]; then + base_version="$1" + if [ "$#" -eq 2 ]; then + new_version="$2" + fi +else + echo "Invalid usage. See help:" + echo "" + display_help_and_exit +fi + +checkout_and_build() { + _orig_dir="$(pwd)" + git worktree add --detach "$1" "$2" + cd "$1" + mkdir build && cd build + cmake -S .. --preset dev-mode \ + -DCMAKE_C_COMPILER=gcc -DCMAKE_BUILD_TYPE=None -DCMAKE_C_FLAGS="-g -Og -gdwarf-4" \ + -DSECP256K1_BUILD_BENCHMARK=OFF \ + -DSECP256K1_BUILD_TESTS=OFF \ + -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF \ + -DSECP256K1_BUILD_CTIME_TESTS=OFF \ + -DSECP256K1_BUILD_EXAMPLES=OFF + cmake --build . -j "$(nproc)" + # FIXME: Just set LIBPATH to lib/libsecp256k1.so once version 0.6.0 is + # released. + if [ -f "src/libsecp256k1.so" ]; then + LIBPATH="src/libsecp256k1.so" + else + LIBPATH="lib/libsecp256k1.so" + fi + abi-dumper $LIBPATH -o ABI.dump -lver "$2" -public-headers ../include/ + cd "$_orig_dir" +} + +echo "Comparing $base_version (base version) to $new_version (new version)" +echo + +base_source_dir="$(mktemp -d)" +checkout_and_build "$base_source_dir" "$base_version" + +new_source_dir="$(mktemp -d)" +checkout_and_build "$new_source_dir" "$new_version" + +abi-compliance-checker -lib libsecp256k1 -old "${base_source_dir}/build/ABI.dump" -new "${new_source_dir}/build/ABI.dump" +git worktree remove "$base_source_dir" +git worktree remove "$new_source_dir" diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/musig2-vectors.py b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/tools/test_vectors_musig2_generate.py similarity index 99% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/musig2-vectors.py rename to ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/tools/test_vectors_musig2_generate.py index 8df3870f..97424419 100755 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/depend/secp256k1/contrib/musig2-vectors.py +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/tools/test_vectors_musig2_generate.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import sys import json diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/tools/tests_wycheproof_generate.py b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/tools/tests_wycheproof_generate.py new file mode 100755 index 00000000..b26dfa89 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/secp256k1/tools/tests_wycheproof_generate.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Random "Randy" Lattice and Sean Andersen +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://www.opensource.org/licenses/mit-license.php. +''' +Generate a C file with ECDSA testvectors from the Wycheproof project. +''' + +import json +import sys + +filename_input = sys.argv[1] + +with open(filename_input) as f: + doc = json.load(f) + +num_groups = len(doc['testGroups']) + +def to_c_array(x): + if x == "": + return "" + s = ',0x'.join(a+b for a,b in zip(x[::2], x[1::2])) + return "0x" + s + + +num_vectors = 0 +offset_msg_running, offset_pk_running, offset_sig = 0, 0, 0 +out = "" +messages = "" +signatures = "" +public_keys = "" +cache_msgs = {} +cache_public_keys = {} + +for i in range(num_groups): + group = doc['testGroups'][i] + num_tests = len(group['tests']) + public_key = group['publicKey'] + for j in range(num_tests): + test_vector = group['tests'][j] + # // 2 to convert hex to byte length + sig_size = len(test_vector['sig']) // 2 + msg_size = len(test_vector['msg']) // 2 + + if test_vector['result'] == "invalid": + expected_verify = 0 + elif test_vector['result'] == "valid": + expected_verify = 1 + else: + raise ValueError("invalid result field") + + if num_vectors != 0 and sig_size != 0: + signatures += ",\n " + + new_msg = False + msg = to_c_array(test_vector['msg']) + msg_offset = offset_msg_running + # check for repeated msg + if msg not in cache_msgs: + if num_vectors != 0 and msg_size != 0: + messages += ",\n " + cache_msgs[msg] = offset_msg_running + messages += msg + new_msg = True + else: + msg_offset = cache_msgs[msg] + + new_pk = False + pk = to_c_array(public_key['uncompressed']) + pk_offset = offset_pk_running + # check for repeated pk + if pk not in cache_public_keys: + if num_vectors != 0: + public_keys += ",\n " + cache_public_keys[pk] = offset_pk_running + public_keys += pk + new_pk = True + else: + pk_offset = cache_public_keys[pk] + + signatures += to_c_array(test_vector['sig']) + + out += " /" + "* tcId: " + str(test_vector['tcId']) + ". " + test_vector['comment'] + " *" + "/\n" + out += f" {{{pk_offset}, {msg_offset}, {msg_size}, {offset_sig}, {sig_size}, {expected_verify} }},\n" + if new_msg: + offset_msg_running += msg_size + if new_pk: + offset_pk_running += 65 + offset_sig += sig_size + num_vectors += 1 + +struct_definition = """ +typedef struct { + size_t pk_offset; + size_t msg_offset; + size_t msg_len; + size_t sig_offset; + size_t sig_len; + int expected_verify; +} wycheproof_ecdsa_testvector; +""" + + +print("/* Note: this file was autogenerated using tests_wycheproof_generate.py. Do not edit. */") +print(f"#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS ({num_vectors})") + +print(struct_definition) + +print("static const unsigned char wycheproof_ecdsa_messages[] = { " + messages + "};\n") +print("static const unsigned char wycheproof_ecdsa_public_keys[] = { " + public_keys + "};\n") +print("static const unsigned char wycheproof_ecdsa_signatures[] = { " + signatures + "};\n") + +print("static const wycheproof_ecdsa_testvector testvectors[SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS] = {") +print(out) +print("};") diff --git a/ark-rust-secp256k1/secp256k1-sys/depend/util.h.patch b/ark-rust-secp256k1/secp256k1-sys/depend/util.h.patch new file mode 100644 index 00000000..3135cec7 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/depend/util.h.patch @@ -0,0 +1,33 @@ +14d13 +< #include +22,41d20 +< /* Debug helper for printing arrays of unsigned char. */ +< #define PRINT_BUF(buf, len) do { \ +< printf("%s[%lu] = ", #buf, (unsigned long)len); \ +< print_buf_plain(buf, len); \ +< } while(0) +< +< static void print_buf_plain(const unsigned char *buf, size_t len) { +< size_t i; +< printf("{"); +< for (i = 0; i < len; i++) { +< if (i % 8 == 0) { +< printf("\n "); +< } else { +< printf(" "); +< } +< printf("0x%02X,", buf[i]); +< } +< printf("\n}\n"); +< } +< +148,152c127,129 +< void *ret = malloc(size); +< if (ret == NULL) { +< secp256k1_callback_call(cb, "Out of memory"); +< } +< return ret; +--- +> (void) cb; +> (void) size; +> return NULL; diff --git a/ark-rust-secp256k1/secp256k1-sys/src/lib.rs b/ark-rust-secp256k1/secp256k1-sys/src/lib.rs new file mode 100644 index 00000000..4641826f --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/src/lib.rs @@ -0,0 +1,2096 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! # secp256k1-sys FFI bindings +//! Direct bindings to the underlying C library functions. These should +//! not be needed for most users. + +#![allow(warnings)] +// Coding conventions +#![deny(non_upper_case_globals, non_camel_case_types, non_snake_case, unused_mut)] +#![cfg_attr(all(not(test), not(feature = "std")), no_std)] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] + +#[cfg(any(test, feature = "std"))] +extern crate core; + +#[cfg(feature = "alloc")] +extern crate alloc; + +#[cfg(secp256k1_fuzz)] +const THIS_UNUSED_CONSTANT_IS_YOUR_WARNING_THAT_ALL_THE_CRYPTO_IN_THIS_LIB_IS_DISABLED_FOR_FUZZING: usize = 0; + +mod macros; +pub mod types; + +#[cfg(feature = "recovery")] +pub mod recovery; + +use core::ptr::NonNull; +use core::{ptr, slice}; + +use types::*; + +/// Flag for context to enable no precomputation +pub const SECP256K1_START_NONE: c_uint = 1; +/// Flag for context to enable verification precomputation +pub const SECP256K1_START_VERIFY: c_uint = 1 | (1 << 8); +/// Flag for context to enable signing precomputation +pub const SECP256K1_START_SIGN: c_uint = 1 | (1 << 9); +/// Flag for keys to indicate uncompressed serialization format +#[allow(unused_parens)] +pub const SECP256K1_SER_UNCOMPRESSED: c_uint = (1 << 1); +/// Flag for keys to indicate compressed serialization format +pub const SECP256K1_SER_COMPRESSED: c_uint = (1 << 1) | (1 << 8); + +/// A nonce generation function. +/// +/// Ordinary users of the library never need to see this type; the default +/// nonce generation function should be sufficient for almost all usecases. +/// +/// To use this type, you must write your own (unsafe) wrapper. It is unsafe +/// because any secure implementation must dereference the passed-in raw +/// pointers and/or call FFI functions. +pub type NonceFn = Option< + unsafe extern "C" fn( + nonce32: *mut c_uchar, + msg32: *const c_uchar, + key32: *const c_uchar, + algo16: *const c_uchar, + data: *mut c_void, + attempt: c_uint, + ) -> c_int, +>; + +/// Hash function to use to post-process an ECDH point to get +/// a shared secret. +pub type EcdhHashFn = Option< + unsafe extern "C" fn( + output: *mut c_uchar, + x: *const c_uchar, + y: *const c_uchar, + data: *mut c_void, + ) -> c_int, +>; + +/// Same as [`NonceFn`], but accepts an additional pubkey argument and does not +/// accept an attempt argument. +/// +/// The pubkey argument will protect signature schemes with tweaked keys from +/// reusing the nonce when signing with a different precomputed pubkey, which +/// for BIP 340 signatures is just as bad as reusing a nonce across different +/// messages. +/// +/// As with [`NonceFn`] ordinary users should never need to touch this type. +pub type SchnorrNonceFn = Option< + unsafe extern "C" fn( + nonce32: *mut c_uchar, + msg32: *const c_uchar, + msg_len: size_t, + key32: *const c_uchar, + xonly_pk32: *const c_uchar, + algo16: *const c_uchar, + algo_len: size_t, + data: *mut c_void, + ) -> c_int, +>; + +/// A hash function used by `ellswift_ecdh` to hash the final ECDH shared secret. +pub type EllswiftEcdhHashFn = Option< + unsafe extern "C" fn( + output: *mut c_uchar, + x32: *const c_uchar, + ell_a64: *const c_uchar, + ell_b64: *const c_uchar, + data: *mut c_void, + ) -> c_int, +>; + +/// Data structure that contains additional arguments for schnorrsig_sign_custom. +#[repr(C)] +pub struct SchnorrSigExtraParams { + magic: [c_uchar; 4], + nonce_fp: SchnorrNonceFn, + ndata: *const c_void, +} + +impl SchnorrSigExtraParams { + /// Create a new SchnorrSigExtraParams properly initialized. + /// + /// `nonce_fp`: pointer to a nonce generation function. If NULL + /// rustsecp256k1_v0_5_0_nonce_function_bip340 is used + /// + /// `ndata`: pointer to arbitrary data used by the nonce generation function + /// (can be NULL). If it is non-NULL and + /// rustsecp256k1_v0_5_0_nonce_function_bip340 is used, + /// then ndata must be a pointer to 32-byte auxiliary randomness as per + /// BIP-340. + pub fn new(nonce_fp: SchnorrNonceFn, ndata: *const c_void) -> Self { + SchnorrSigExtraParams { magic: [0xda, 0x6f, 0xb3, 0x8c], nonce_fp, ndata } + } +} + +/// An opaque Secp256k1 context. +/// +/// Currently this object contains a blinding factor used internally to +/// randomize computations to protect against sidechannel attacks. In the +/// past it has contained precomputation tables to speed up crypto operations. +/// +/// It should be assumed to be expensive to create and therefore should be +/// reused when possible. +/// +/// If you create one of these with `secp256k1_context_create` you must +/// destroy it with `secp256k1_context_destroy`. (Failure to destroy it is +/// a memory leak; destroying it using any other allocator is undefined +/// behavior.) +#[derive(Clone, Debug)] +#[repr(C)] +pub struct Context(c_int); + +/// Library-internal representation of a Secp256k1 public key +#[repr(C)] +#[derive(Copy, Clone)] +#[cfg_attr(secp256k1_fuzz, derive(PartialEq, Eq, PartialOrd, Ord, Hash))] +pub struct PublicKey([c_uchar; 64]); +impl_array_newtype!(PublicKey, c_uchar, 64); +impl_raw_debug!(PublicKey); + +impl PublicKey { + /// Creates an "uninitialized" FFI public key which is zeroed out + /// + /// # Safety + /// + /// If you pass this to any FFI functions, except as an out-pointer, + /// the result is likely to be an assertation failure and process + /// termination. + pub unsafe fn new() -> Self { Self::from_array_unchecked([0; 64]) } + + /// Create a new public key usable for the FFI interface from raw bytes + /// + /// # Safety + /// + /// Does not check the validity of the underlying representation. If it is + /// invalid the result may be assertation failures (and process aborts) from + /// the underlying library. You should not use this method except with data + /// that you obtained from the FFI interface of the same version of this + /// library. + pub unsafe fn from_array_unchecked(data: [c_uchar; 64]) -> Self { PublicKey(data) } + + /// Returns the underlying FFI opaque representation of the public key + /// + /// You should not use this unless you really know what you are doing. It is + /// essentially only useful for extending the FFI interface itself. + pub fn underlying_bytes(self) -> [c_uchar; 64] { self.0 } + + /// Serializes this public key as a byte-encoded pair of values, in compressed form. + fn serialize(&self) -> [u8; 33] { + let mut buf = [0u8; 33]; + let mut len = 33; + unsafe { + let ret = secp256k1_ec_pubkey_serialize( + secp256k1_context_no_precomp, + buf.as_mut_c_ptr(), + &mut len, + self, + SECP256K1_SER_COMPRESSED, + ); + debug_assert_eq!(ret, 1); + debug_assert_eq!(len, 33); + }; + buf + } +} + +#[cfg(not(secp256k1_fuzz))] +impl PartialOrd for PublicKey { + fn partial_cmp(&self, other: &PublicKey) -> Option { + Some(self.cmp(other)) + } +} + +#[cfg(not(secp256k1_fuzz))] +impl Ord for PublicKey { + fn cmp(&self, other: &PublicKey) -> core::cmp::Ordering { + let ret = unsafe { secp256k1_ec_pubkey_cmp(secp256k1_context_no_precomp, self, other) }; + ret.cmp(&0i32) + } +} + +#[cfg(not(secp256k1_fuzz))] +impl PartialEq for PublicKey { + fn eq(&self, other: &Self) -> bool { self.cmp(other) == core::cmp::Ordering::Equal } +} + +#[cfg(not(secp256k1_fuzz))] +impl Eq for PublicKey {} + +#[cfg(not(secp256k1_fuzz))] +impl core::hash::Hash for PublicKey { + fn hash(&self, state: &mut H) { + let ser = self.serialize(); + ser.hash(state); + } +} + +/// Library-internal representation of a Secp256k1 signature +#[repr(C)] +#[derive(Copy, Clone)] +#[cfg_attr(secp256k1_fuzz, derive(PartialEq, Eq, PartialOrd, Ord, Hash))] +pub struct Signature([c_uchar; 64]); +impl_array_newtype!(Signature, c_uchar, 64); +impl_raw_debug!(Signature); + +impl Signature { + /// Creates an "uninitialized" FFI signature which is zeroed out + /// + /// # Safety + /// + /// If you pass this to any FFI functions, except as an out-pointer, + /// the result is likely to be an assertation failure and process + /// termination. + pub unsafe fn new() -> Self { Self::from_array_unchecked([0; 64]) } + + /// Create a new signature usable for the FFI interface from raw bytes + /// + /// # Safety + /// + /// Does not check the validity of the underlying representation. If it is + /// invalid the result may be assertation failures (and process aborts) from + /// the underlying library. You should not use this method except with data + /// that you obtained from the FFI interface of the same version of this + /// library. + pub unsafe fn from_array_unchecked(data: [c_uchar; 64]) -> Self { Signature(data) } + + /// Returns the underlying FFI opaque representation of the signature + /// + /// You should not use this unless you really know what you are doing. It is + /// essentially only useful for extending the FFI interface itself. + pub fn underlying_bytes(self) -> [c_uchar; 64] { self.0 } + + /// Serializes the signature in compact format. + fn serialize(&self) -> [u8; 64] { + let mut buf = [0u8; 64]; + unsafe { + let ret = secp256k1_ecdsa_signature_serialize_compact( + secp256k1_context_no_precomp, + buf.as_mut_c_ptr(), + self, + ); + debug_assert!(ret == 1); + } + buf + } +} + +#[cfg(not(secp256k1_fuzz))] +impl PartialOrd for Signature { + fn partial_cmp(&self, other: &Signature) -> Option { + Some(self.cmp(other)) + } +} + +#[cfg(not(secp256k1_fuzz))] +impl Ord for Signature { + fn cmp(&self, other: &Signature) -> core::cmp::Ordering { + let this = self.serialize(); + let that = other.serialize(); + this.cmp(&that) + } +} + +#[cfg(not(secp256k1_fuzz))] +impl PartialEq for Signature { + fn eq(&self, other: &Self) -> bool { self.cmp(other) == core::cmp::Ordering::Equal } +} + +#[cfg(not(secp256k1_fuzz))] +impl Eq for Signature {} + +#[cfg(not(secp256k1_fuzz))] +impl core::hash::Hash for Signature { + fn hash(&self, state: &mut H) { + let ser = self.serialize(); + ser.hash(state); + } +} + +#[repr(C)] +#[derive(Copy, Clone)] +#[cfg_attr(secp256k1_fuzz, derive(PartialEq, Eq, PartialOrd, Ord, Hash))] +pub struct XOnlyPublicKey([c_uchar; 64]); +impl_array_newtype!(XOnlyPublicKey, c_uchar, 64); +impl_raw_debug!(XOnlyPublicKey); + +impl XOnlyPublicKey { + /// Creates an "uninitialized" FFI x-only public key which is zeroed out + /// + /// # Safety + /// + /// If you pass this to any FFI functions, except as an out-pointer, + /// the result is likely to be an assertation failure and process + /// termination. + pub unsafe fn new() -> Self { Self::from_array_unchecked([0; 64]) } + + /// Create a new x-only public key usable for the FFI interface from raw bytes + /// + /// # Safety + /// + /// Does not check the validity of the underlying representation. If it is + /// invalid the result may be assertation failures (and process aborts) from + /// the underlying library. You should not use this method except with data + /// that you obtained from the FFI interface of the same version of this + /// library. + pub unsafe fn from_array_unchecked(data: [c_uchar; 64]) -> Self { XOnlyPublicKey(data) } + + /// Returns the underlying FFI opaque representation of the x-only public key + /// + /// You should not use this unless you really know what you are doing. It is + /// essentially only useful for extending the FFI interface itself. + pub fn underlying_bytes(self) -> [c_uchar; 64] { self.0 } + + /// Serializes this key as a byte-encoded x coordinate value (32 bytes). + fn serialize(&self) -> [u8; 32] { + let mut buf = [0u8; 32]; + unsafe { + let ret = secp256k1_xonly_pubkey_serialize( + secp256k1_context_no_precomp, + buf.as_mut_c_ptr(), + self, + ); + assert_eq!(ret, 1); + }; + buf + } +} + +#[cfg(not(secp256k1_fuzz))] +impl PartialOrd for XOnlyPublicKey { + fn partial_cmp(&self, other: &XOnlyPublicKey) -> Option { + Some(self.cmp(other)) + } +} + +#[cfg(not(secp256k1_fuzz))] +impl Ord for XOnlyPublicKey { + fn cmp(&self, other: &XOnlyPublicKey) -> core::cmp::Ordering { + let ret = unsafe { secp256k1_xonly_pubkey_cmp(secp256k1_context_no_precomp, self, other) }; + ret.cmp(&0i32) + } +} + +#[cfg(not(secp256k1_fuzz))] +impl PartialEq for XOnlyPublicKey { + fn eq(&self, other: &Self) -> bool { self.cmp(other) == core::cmp::Ordering::Equal } +} + +#[cfg(not(secp256k1_fuzz))] +impl Eq for XOnlyPublicKey {} + +#[cfg(not(secp256k1_fuzz))] +impl core::hash::Hash for XOnlyPublicKey { + fn hash(&self, state: &mut H) { + let ser = self.serialize(); + ser.hash(state); + } +} + +#[repr(C)] +#[derive(Copy, Clone)] +#[cfg_attr(secp256k1_fuzz, derive(PartialEq, Eq, PartialOrd, Ord, Hash))] +pub struct Keypair([c_uchar; 96]); +impl_array_newtype!(Keypair, c_uchar, 96); +impl_raw_debug!(Keypair); + +impl Keypair { + /// Creates an "uninitialized" FFI keypair which is zeroed out + /// + /// # Safety + /// + /// If you pass this to any FFI functions, except as an out-pointer, + /// the result is likely to be an assertation failure and process + /// termination. + pub unsafe fn new() -> Self { Self::from_array_unchecked([0; 96]) } + + /// Create a new keypair usable for the FFI interface from raw bytes + /// + /// # Safety + /// + /// Does not check the validity of the underlying representation. If it is + /// invalid the result may be assertation failures (and process aborts) from + /// the underlying library. You should not use this method except with data + /// that you obtained from the FFI interface of the same version of this + /// library. + pub unsafe fn from_array_unchecked(data: [c_uchar; 96]) -> Self { Keypair(data) } + + /// Returns the underlying FFI opaque representation of the x-only public key + /// + /// You should not use this unless you really know what you are doing. It is + /// essentially only useful for extending the FFI interface itself. + pub fn underlying_bytes(self) -> [c_uchar; 96] { self.0 } + + /// Creates a new compressed public key from this key pair. + fn public_key(&self) -> PublicKey { + unsafe { + let mut pk = PublicKey::new(); + let ret = secp256k1_keypair_pub(secp256k1_context_no_precomp, &mut pk, self); + debug_assert_eq!(ret, 1); + pk + } + } + + /// Attempts to erase the contents of the underlying array. + /// + /// Note, however, that the compiler is allowed to freely copy or move the + /// contents of this array to other places in memory. Preventing this behavior + /// is very subtle. For more discussion on this, please see the documentation + /// of the [`zeroize`](https://docs.rs/zeroize) crate. + #[inline] + pub fn non_secure_erase(&mut self) { non_secure_erase_impl(&mut self.0, DUMMY_KEYPAIR); } +} + +// DUMMY_KEYPAIR is the internal repr of a valid key pair with secret key `[1u8; 32]` +#[cfg(target_endian = "little")] +const DUMMY_KEYPAIR: [c_uchar; 96] = [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 143, 7, 221, 213, 233, 245, 23, 156, 255, 25, 72, 96, 52, 24, 30, 215, 101, 5, 186, 170, 213, + 62, 93, 153, 64, 100, 18, 123, 86, 197, 132, 27, 209, 232, 168, 105, 122, 212, 34, 81, 222, 57, + 246, 167, 32, 129, 223, 223, 66, 171, 197, 66, 166, 214, 254, 7, 21, 84, 139, 88, 143, 175, + 190, 112, +]; +#[cfg(all(target_endian = "big", target_pointer_width = "32"))] +const DUMMY_KEYPAIR: [c_uchar; 96] = [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 213, 221, 7, 143, 156, 23, 245, 233, 96, 72, 25, 255, 215, 30, 24, 52, 170, 186, 5, 101, 153, + 93, 62, 213, 123, 18, 100, 64, 27, 132, 197, 86, 105, 168, 232, 209, 81, 34, 212, 122, 167, + 246, 57, 222, 223, 223, 129, 32, 66, 197, 171, 66, 7, 254, 214, 166, 88, 139, 84, 21, 112, 190, + 175, 143, +]; +#[cfg(all(target_endian = "big", target_pointer_width = "64"))] +const DUMMY_KEYPAIR: [c_uchar; 96] = [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 156, 23, 245, 233, 213, 221, 7, 143, 215, 30, 24, 52, 96, 72, 25, 255, 153, 93, 62, 213, 170, + 186, 5, 101, 27, 132, 197, 86, 123, 18, 100, 64, 81, 34, 212, 122, 105, 168, 232, 209, 223, + 223, 129, 32, 167, 246, 57, 222, 7, 254, 214, 166, 66, 197, 171, 66, 112, 190, 175, 143, 88, + 139, 84, 21, +]; + +/// Does a best attempt at secure erasure using Rust intrinsics. +/// +/// The implementation is based on the approach used by the [`zeroize`](https://docs.rs/zeroize) crate. +#[inline(always)] +pub fn non_secure_erase_impl(dst: &mut T, src: T) { + use core::sync::atomic; + // overwrite using volatile value + unsafe { + ptr::write_volatile(dst, src); + } + + // prevent future accesses from being reordered to before erasure + atomic::compiler_fence(atomic::Ordering::SeqCst); +} + +#[cfg(not(secp256k1_fuzz))] +impl PartialOrd for Keypair { + fn partial_cmp(&self, other: &Keypair) -> Option { Some(self.cmp(other)) } +} + +#[cfg(not(secp256k1_fuzz))] +impl Ord for Keypair { + fn cmp(&self, other: &Keypair) -> core::cmp::Ordering { + let this = self.public_key(); + let that = other.public_key(); + this.cmp(&that) + } +} + +#[cfg(not(secp256k1_fuzz))] +impl PartialEq for Keypair { + fn eq(&self, other: &Self) -> bool { self.cmp(other) == core::cmp::Ordering::Equal } +} + +#[cfg(not(secp256k1_fuzz))] +impl Eq for Keypair {} + +#[cfg(not(secp256k1_fuzz))] +impl core::hash::Hash for Keypair { + fn hash(&self, state: &mut H) { + // To hash the key pair we just hash the serialized public key. Since any change to the + // secret key would also be a change to the public key this is a valid one way function from + // the key pair to the digest. + let pk = self.public_key(); + let ser = pk.serialize(); + ser.hash(state); + } +} + +/// Library-internal representation of a ElligatorSwift encoded group element. +#[repr(C)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ElligatorSwift([u8; 64]); + +impl ElligatorSwift { + pub fn from_array(arr: [u8; 64]) -> Self { ElligatorSwift(arr) } + pub fn to_array(self) -> [u8; 64] { self.0 } +} + +impl_array_newtype!(ElligatorSwift, u8, 64); +impl_raw_debug!(ElligatorSwift); + +extern "C" { + /// Default ECDH hash function + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdh_hash_function_default" + )] + pub static secp256k1_ecdh_hash_function_default: EcdhHashFn; + + /// Default ECDH hash function for BIP324 key establishment + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ellswift_xdh_hash_function_bip324" + )] + pub static secp256k1_ellswift_xdh_hash_function_bip324: EllswiftEcdhHashFn; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_nonce_function_rfc6979" + )] + pub static secp256k1_nonce_function_rfc6979: NonceFn; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_nonce_function_default" + )] + pub static secp256k1_nonce_function_default: NonceFn; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_nonce_function_bip340" + )] + pub static secp256k1_nonce_function_bip340: SchnorrNonceFn; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_context_no_precomp" + )] + pub static secp256k1_context_no_precomp: *const Context; + + // Contexts + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_context_preallocated_destroy" + )] + pub fn secp256k1_context_preallocated_destroy(cx: NonNull); + + // Signatures + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_signature_parse_der" + )] + pub fn secp256k1_ecdsa_signature_parse_der( + cx: *const Context, + sig: *mut Signature, + input: *const c_uchar, + in_len: size_t, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_signature_parse_compact" + )] + pub fn secp256k1_ecdsa_signature_parse_compact( + cx: *const Context, + sig: *mut Signature, + input64: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_signature_parse_der_lax" + )] + pub fn ecdsa_signature_parse_der_lax( + cx: *const Context, + sig: *mut Signature, + input: *const c_uchar, + in_len: size_t, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_signature_serialize_der" + )] + pub fn secp256k1_ecdsa_signature_serialize_der( + cx: *const Context, + output: *mut c_uchar, + out_len: *mut size_t, + sig: *const Signature, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_signature_serialize_compact" + )] + pub fn secp256k1_ecdsa_signature_serialize_compact( + cx: *const Context, + output64: *mut c_uchar, + sig: *const Signature, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ecdsa_signature_normalize" + )] + pub fn secp256k1_ecdsa_signature_normalize( + cx: *const Context, + out_sig: *mut Signature, + in_sig: *const Signature, + ) -> c_int; + + // Secret Keys + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_seckey_verify" + )] + pub fn secp256k1_ec_seckey_verify(cx: *const Context, sk: *const c_uchar) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_seckey_negate" + )] + pub fn secp256k1_ec_seckey_negate(cx: *const Context, sk: *mut c_uchar) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_seckey_tweak_add" + )] + pub fn secp256k1_ec_seckey_tweak_add( + cx: *const Context, + sk: *mut c_uchar, + tweak: *const c_uchar, + ) -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_seckey_tweak_mul" + )] + pub fn secp256k1_ec_seckey_tweak_mul( + cx: *const Context, + sk: *mut c_uchar, + tweak: *const c_uchar, + ) -> c_int; + + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_keypair_sec")] + pub fn secp256k1_keypair_sec( + cx: *const Context, + output_seckey: *mut c_uchar, + keypair: *const Keypair, + ) -> c_int; + + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_keypair_pub")] + pub fn secp256k1_keypair_pub( + cx: *const Context, + output_pubkey: *mut PublicKey, + keypair: *const Keypair, + ) -> c_int; + // Elligator Swift + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ellswift_encode" + )] + pub fn secp256k1_ellswift_encode( + ctx: *const Context, + ell64: *mut c_uchar, + pubkey: *const PublicKey, + rnd32: *const c_uchar, + ) -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ellswift_decode" + )] + pub fn secp256k1_ellswift_decode( + ctx: *const Context, + pubkey: *mut u8, + ell64: *const c_uchar, + ) -> c_int; + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ellswift_create" + )] + pub fn secp256k1_ellswift_create( + ctx: *const Context, + ell64: *mut c_uchar, + seckey32: *const c_uchar, + aux_rand32: *const c_uchar, + ) -> c_int; + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ellswift_xdh")] + pub fn secp256k1_ellswift_xdh( + ctx: *const Context, + output: *mut c_uchar, + ell_a64: *const c_uchar, + ell_b64: *const c_uchar, + seckey32: *const c_uchar, + party: c_int, + hashfp: EllswiftEcdhHashFn, + data: *mut c_void, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_pubnonce_parse" + )] + pub fn secp256k1_musig_pubnonce_parse( + cx: *const Context, + nonce: *mut MusigPubNonce, + in66: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_pubnonce_serialize" + )] + pub fn secp256k1_musig_pubnonce_serialize( + cx: *const Context, + out66: *mut c_uchar, + nonce: *const MusigPubNonce, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_aggnonce_parse" + )] + pub fn secp256k1_musig_aggnonce_parse( + cx: *const Context, + nonce: *mut MusigAggNonce, + in66: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_aggnonce_serialize" + )] + pub fn secp256k1_musig_aggnonce_serialize( + cx: *const Context, + out66: *mut c_uchar, + nonce: *const MusigAggNonce, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_partial_sig_parse" + )] + pub fn secp256k1_musig_partial_sig_parse( + cx: *const Context, + sig: *mut MusigPartialSignature, + in32: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_partial_sig_serialize" + )] + pub fn secp256k1_musig_partial_sig_serialize( + cx: *const Context, + out32: *mut c_uchar, + sig: *const MusigPartialSignature, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_pubkey_agg" + )] + pub fn secp256k1_musig_pubkey_agg( + cx: *const Context, + agg_pk: *mut XOnlyPublicKey, + keyagg_cache: *mut MusigKeyAggCache, + pubkeys: *const *const PublicKey, + n_pubkeys: size_t, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_pubkey_get" + )] + pub fn secp256k1_musig_pubkey_get( + cx: *const Context, + agg_pk: *mut PublicKey, + keyagg_cache: *const MusigKeyAggCache, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_pubkey_ec_tweak_add" + )] + pub fn secp256k1_musig_pubkey_ec_tweak_add( + cx: *const Context, + output_pubkey: *mut PublicKey, + keyagg_cache: *mut MusigKeyAggCache, + tweak32: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_pubkey_xonly_tweak_add" + )] + pub fn secp256k1_musig_pubkey_xonly_tweak_add( + cx: *const Context, + output_pubkey: *mut PublicKey, + keyagg_cache: *mut MusigKeyAggCache, + tweak32: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_nonce_gen" + )] + pub fn secp256k1_musig_nonce_gen( + cx: *const Context, + secnonce: *mut MusigSecNonce, + pubnonce: *mut MusigPubNonce, + session_secrand32: *const c_uchar, + seckey: *const c_uchar, + pubkey: *const PublicKey, + msg32: *const c_uchar, + keyagg_cache: *const MusigKeyAggCache, + extra_input32: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_nonce_agg" + )] + pub fn secp256k1_musig_nonce_agg( + cx: *const Context, + aggnonce: *mut MusigAggNonce, + pubnonces: *const *const MusigPubNonce, + n_pubnonces: size_t, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_nonce_process" + )] + pub fn secp256k1_musig_nonce_process( + cx: *const Context, + session: *mut MusigSession, + aggnonce: *const MusigAggNonce, + msg32: *const c_uchar, + keyagg_cache: *const MusigKeyAggCache, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_partial_sign" + )] + pub fn secp256k1_musig_partial_sign( + cx: *const Context, + partial_sig: *mut MusigPartialSignature, + secnonce: *mut MusigSecNonce, + keypair: *const Keypair, + keyagg_cache: *const MusigKeyAggCache, + session: *const MusigSession, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_partial_sig_verify" + )] + pub fn secp256k1_musig_partial_sig_verify( + cx: *const Context, + partial_sig: *const MusigPartialSignature, + pubnonce: *const MusigPubNonce, + pubkey: *const PublicKey, + keyagg_cache: *const MusigKeyAggCache, + session: *const MusigSession, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_musig_partial_sig_agg" + )] + pub fn secp256k1_musig_partial_sig_agg( + cx: *const Context, + sig64: *mut c_uchar, + session: *const MusigSession, + partial_sigs: *const *const MusigPartialSignature, + n_sigs: size_t, + ) -> c_int; + + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_pubkey_sort")] + pub fn secp256k1_ec_pubkey_sort( + ctx: *const Context, + pubkeys: *mut *const PublicKey, + n_pubkeys: size_t, + ) -> c_int; +} + +#[cfg(not(secp256k1_fuzz))] +extern "C" { + // Contexts + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_context_preallocated_size" + )] + pub fn secp256k1_context_preallocated_size(flags: c_uint) -> size_t; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_context_preallocated_create" + )] + pub fn secp256k1_context_preallocated_create( + prealloc: NonNull, + flags: c_uint, + ) -> NonNull; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_context_preallocated_clone_size" + )] + pub fn secp256k1_context_preallocated_clone_size(cx: *const Context) -> size_t; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_context_preallocated_clone" + )] + pub fn secp256k1_context_preallocated_clone( + cx: *const Context, + prealloc: NonNull, + ) -> NonNull; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_context_randomize" + )] + pub fn secp256k1_context_randomize(cx: NonNull, seed32: *const c_uchar) -> c_int; + // Pubkeys + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_pubkey_parse" + )] + pub fn secp256k1_ec_pubkey_parse( + cx: *const Context, + pk: *mut PublicKey, + input: *const c_uchar, + in_len: size_t, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_pubkey_serialize" + )] + pub fn secp256k1_ec_pubkey_serialize( + cx: *const Context, + output: *mut c_uchar, + out_len: *mut size_t, + pk: *const PublicKey, + compressed: c_uint, + ) -> c_int; + + // EC + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_pubkey_create" + )] + pub fn secp256k1_ec_pubkey_create( + cx: *const Context, + pk: *mut PublicKey, + sk: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_pubkey_negate" + )] + pub fn secp256k1_ec_pubkey_negate(cx: *const Context, pk: *mut PublicKey) -> c_int; + + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ec_pubkey_cmp")] + pub fn secp256k1_ec_pubkey_cmp( + cx: *const Context, + pubkey1: *const PublicKey, + pubkey2: *const PublicKey, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_pubkey_tweak_add" + )] + pub fn secp256k1_ec_pubkey_tweak_add( + cx: *const Context, + pk: *mut PublicKey, + tweak: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_pubkey_tweak_mul" + )] + pub fn secp256k1_ec_pubkey_tweak_mul( + cx: *const Context, + pk: *mut PublicKey, + tweak: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_ec_pubkey_combine" + )] + pub fn secp256k1_ec_pubkey_combine( + cx: *const Context, + out: *mut PublicKey, + ins: *const *const PublicKey, + n: size_t, + ) -> c_int; + + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdh")] + pub fn secp256k1_ecdh( + cx: *const Context, + output: *mut c_uchar, + pubkey: *const PublicKey, + seckey: *const c_uchar, + hashfp: EcdhHashFn, + data: *mut c_void, + ) -> c_int; + + // ECDSA + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_verify")] + pub fn secp256k1_ecdsa_verify( + cx: *const Context, + sig: *const Signature, + msg32: *const c_uchar, + pk: *const PublicKey, + ) -> c_int; + + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_sign")] + pub fn secp256k1_ecdsa_sign( + cx: *const Context, + sig: *mut Signature, + msg32: *const c_uchar, + sk: *const c_uchar, + noncefn: NonceFn, + noncedata: *const c_void, + ) -> c_int; + + // Schnorr Signatures + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_schnorrsig_sign" + )] + pub fn secp256k1_schnorrsig_sign( + cx: *const Context, + sig: *mut c_uchar, + msg32: *const c_uchar, + keypair: *const Keypair, + aux_rand32: *const c_uchar, + ) -> c_int; + + // Schnorr Signatures with extra parameters (see [`SchnorrSigExtraParams`]) + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_schnorrsig_sign_custom" + )] + pub fn secp256k1_schnorrsig_sign_custom( + cx: *const Context, + sig: *mut c_uchar, + msg: *const c_uchar, + msg_len: size_t, + keypair: *const Keypair, + extra_params: *const SchnorrSigExtraParams, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_schnorrsig_verify" + )] + pub fn secp256k1_schnorrsig_verify( + cx: *const Context, + sig64: *const c_uchar, + msg32: *const c_uchar, + msglen: size_t, + pubkey: *const XOnlyPublicKey, + ) -> c_int; + + // Extra keys + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_keypair_create")] + pub fn secp256k1_keypair_create( + cx: *const Context, + keypair: *mut Keypair, + seckey: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_xonly_pubkey_parse" + )] + pub fn secp256k1_xonly_pubkey_parse( + cx: *const Context, + pubkey: *mut XOnlyPublicKey, + input32: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_xonly_pubkey_serialize" + )] + pub fn secp256k1_xonly_pubkey_serialize( + cx: *const Context, + output32: *mut c_uchar, + pubkey: *const XOnlyPublicKey, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_xonly_pubkey_from_pubkey" + )] + pub fn secp256k1_xonly_pubkey_from_pubkey( + cx: *const Context, + xonly_pubkey: *mut XOnlyPublicKey, + pk_parity: *mut c_int, + pubkey: *const PublicKey, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_xonly_pubkey_cmp" + )] + pub fn secp256k1_xonly_pubkey_cmp( + cx: *const Context, + pubkey1: *const XOnlyPublicKey, + pubkey2: *const XOnlyPublicKey, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_xonly_pubkey_tweak_add" + )] + pub fn secp256k1_xonly_pubkey_tweak_add( + cx: *const Context, + output_pubkey: *mut PublicKey, + internal_pubkey: *const XOnlyPublicKey, + tweak32: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_keypair_xonly_pub" + )] + pub fn secp256k1_keypair_xonly_pub( + cx: *const Context, + pubkey: *mut XOnlyPublicKey, + pk_parity: *mut c_int, + keypair: *const Keypair, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_keypair_xonly_tweak_add" + )] + pub fn secp256k1_keypair_xonly_tweak_add( + cx: *const Context, + keypair: *mut Keypair, + tweak32: *const c_uchar, + ) -> c_int; + + #[cfg_attr( + not(rust_secp_no_symbol_renaming), + link_name = "rustsecp256k1_v0_11_xonly_pubkey_tweak_add_check" + )] + pub fn secp256k1_xonly_pubkey_tweak_add_check( + cx: *const Context, + tweaked_pubkey32: *const c_uchar, + tweaked_pubkey_parity: c_int, + internal_pubkey: *const XOnlyPublicKey, + tweak32: *const c_uchar, + ) -> c_int; +} + +/// A reimplementation of the C function `secp256k1_context_create` in rust. +/// +/// This function allocates memory, the pointer should be deallocated using +/// `secp256k1_context_destroy`. Failure to do so will result in a memory leak. +/// +/// Input `flags` control which parts of the context to initialize. +/// +/// # Safety +/// +/// This function is unsafe because it calls unsafe functions however (assuming no bugs) no +/// undefined behavior is possible. +/// +/// # Returns +/// +/// The newly created secp256k1 raw context. +#[cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))] +pub unsafe fn secp256k1_context_create(flags: c_uint) -> NonNull { + rustsecp256k1_v0_11_context_create(flags) +} + +/// A reimplementation of the C function `secp256k1_context_create` in rust. +/// +/// See [`secp256k1_context_create`] for documentation and safety constraints. +#[no_mangle] +#[allow(clippy::missing_safety_doc)] // Documented above. +#[cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))] +pub unsafe extern "C" fn rustsecp256k1_v0_11_context_create(flags: c_uint) -> NonNull { + use core::mem; + + use crate::alloc::alloc; + assert!(ALIGN_TO >= mem::align_of::()); + assert!(ALIGN_TO >= mem::align_of::<&usize>()); + assert!(ALIGN_TO >= mem::size_of::()); + + // We need to allocate `ALIGN_TO` more bytes in order to write the amount of bytes back. + let bytes = secp256k1_context_preallocated_size(flags) + ALIGN_TO; + let layout = alloc::Layout::from_size_align(bytes, ALIGN_TO).unwrap(); + let ptr = alloc::alloc(layout); + if ptr.is_null() { + alloc::handle_alloc_error(layout); + } + (ptr as *mut usize).write(bytes); + // We must offset a whole ALIGN_TO in order to preserve the same alignment + // this means we "lose" ALIGN_TO-size_of(usize) for padding. + let ptr = ptr.add(ALIGN_TO); + let ptr = NonNull::new_unchecked(ptr as *mut c_void); // Checked above. + secp256k1_context_preallocated_create(ptr, flags) +} + +/// A reimplementation of the C function `secp256k1_context_destroy` in rust. +/// +/// This function destroys and deallcates the context created by `secp256k1_context_create`. +/// +/// The pointer shouldn't be used after passing to this function, consider it as passing it to `free()`. +/// +/// # Safety +/// +/// `ctx` must be a valid pointer to a block of memory created using [`secp256k1_context_create`]. +#[cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))] +pub unsafe fn secp256k1_context_destroy(ctx: NonNull) { + rustsecp256k1_v0_11_context_destroy(ctx) +} + +#[no_mangle] +#[allow(clippy::missing_safety_doc)] // Documented above. +#[cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))] +pub unsafe extern "C" fn rustsecp256k1_v0_11_context_destroy(mut ctx: NonNull) { + use crate::alloc::alloc; + secp256k1_context_preallocated_destroy(ctx); + let ctx: *mut Context = ctx.as_mut(); + let ptr = (ctx as *mut u8).sub(ALIGN_TO); + let bytes = (ptr as *mut usize).read(); + let layout = alloc::Layout::from_size_align(bytes, ALIGN_TO).unwrap(); + alloc::dealloc(ptr, layout); +} + +/// **This function is an override for the C function, this is the an edited version of the original description:** +/// +/// A callback function to be called when an illegal argument is passed to +/// an API call. It will only trigger for violations that are mentioned +/// explicitly in the header. **This will cause a panic**. +/// +/// The philosophy is that these shouldn't be dealt with through a +/// specific return value, as calling code should not have branches to deal with +/// the case that this code itself is broken. +/// +/// On the other hand, during debug stage, one would want to be informed about +/// such mistakes, and the default (crashing) may be inadvisable. +/// When this callback is triggered, the API function called is guaranteed not +/// to cause a crash, though its return value and output arguments are +/// undefined. +/// +/// See also secp256k1_default_error_callback_fn. +/// +/// +/// # Safety +/// +/// `message` string should be a null terminated C string and, up to the first null byte, must be valid UTF8. +/// +/// For exact safety constraints see [`std::slice::from_raw_parts`] and [`std::str::from_utf8_unchecked`]. +#[no_mangle] +#[cfg(not(rust_secp_no_symbol_renaming))] +pub unsafe extern "C" fn rustsecp256k1_v0_11_default_illegal_callback_fn( + message: *const c_char, + _data: *mut c_void, +) { + use core::str; + let msg_slice = slice::from_raw_parts(message as *const u8, strlen(message)); + let msg = str::from_utf8_unchecked(msg_slice); + panic!("[libsecp256k1] illegal argument. {}", msg); +} + +/// **This function is an override for the C function, this is the an edited version of the original description:** +/// +/// A callback function to be called when an internal consistency check +/// fails. **This will cause a panic**. +/// +/// This can only trigger in case of a hardware failure, miscompilation, +/// memory corruption, serious bug in the library, or other error would can +/// otherwise result in undefined behaviour. It will not trigger due to mere +/// incorrect usage of the API (see secp256k1_default_illegal_callback_fn +/// for that). After this callback returns, anything may happen, including +/// crashing. +/// +/// See also secp256k1_default_illegal_callback_fn. +/// +/// # Safety +/// +/// `message` string should be a null terminated C string and, up to the first null byte, must be valid UTF8. +/// +/// For exact safety constraints see [`std::slice::from_raw_parts`] and [`std::str::from_utf8_unchecked`]. +#[no_mangle] +#[cfg(not(rust_secp_no_symbol_renaming))] +pub unsafe extern "C" fn rustsecp256k1_v0_11_default_error_callback_fn( + message: *const c_char, + _data: *mut c_void, +) { + use core::str; + let msg_slice = slice::from_raw_parts(message as *const u8, strlen(message)); + let msg = str::from_utf8_unchecked(msg_slice); + panic!("[libsecp256k1] internal consistency check failed {}", msg); +} + +/// Returns the length of the `str_ptr` string. +/// +/// # Safety +/// +/// `str_ptr` must be valid pointer and point to a valid null terminated C string. +#[cfg(not(rust_secp_no_symbol_renaming))] +unsafe fn strlen(mut str_ptr: *const c_char) -> usize { + let mut ctr = 0; + while *str_ptr != '\0' as c_char { + ctr += 1; + str_ptr = str_ptr.offset(1); + } + ctr +} + +/// A trait for producing pointers that will always be valid in C (assuming NULL pointer is a valid +/// no-op). +/// +/// Rust does not guarantee pointers to Zero Sized Types +/// (). In case the type +/// is empty this trait will return a NULL pointer, which should be handled in C. +pub trait CPtr { + type Target; + fn as_c_ptr(&self) -> *const Self::Target; + fn as_mut_c_ptr(&mut self) -> *mut Self::Target; +} + +impl CPtr for [T] { + type Target = T; + fn as_c_ptr(&self) -> *const Self::Target { + if self.is_empty() { + ptr::null() + } else { + self.as_ptr() + } + } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { + if self.is_empty() { + ptr::null_mut::() + } else { + self.as_mut_ptr() + } + } +} + +impl CPtr for &[T] { + type Target = T; + fn as_c_ptr(&self) -> *const Self::Target { + if self.is_empty() { + ptr::null() + } else { + self.as_ptr() + } + } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { + if self.is_empty() { + ptr::null_mut() + } else { + self.as_ptr() as *mut Self::Target + } + } +} + +impl CPtr for [u8; 32] { + type Target = u8; + fn as_c_ptr(&self) -> *const Self::Target { self.as_ptr() } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() } +} + +impl CPtr for Option { + type Target = T::Target; + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { + match self { + Some(contents) => contents.as_mut_c_ptr(), + None => ptr::null_mut(), + } + } + fn as_c_ptr(&self) -> *const Self::Target { + match self { + Some(content) => content.as_c_ptr(), + None => ptr::null(), + } + } +} +/// Total length (in bytes) of the key aggregation context. +/// This structure packs all metadata needed for aggregating individual public keys +/// into a single MuSig2 aggregated key (including coefficients and any extra metadata). +pub const MUSIG_KEYAGG_LEN: usize = 197; + +/// Length (in bytes) of the secret nonce structure used in a MuSig2 session. +/// It holds the secret (ephemeral) nonces used internally for nonce derivation +/// before the corresponding public nonces are computed. +pub const MUSIG_SECNONCE_LEN: usize = 132; + +/// Length (in bytes) of the public nonce structure. +/// This is derived from the secret nonce and shared among participants to build +/// nonce commitments in the MuSig2 protocol. +pub const MUSIG_PUBNONCE_LEN: usize = 132; + +/// Length (in bytes) of the aggregated nonce structure. +/// Represents the combined nonce obtained by aggregating the individual public nonces +/// from all participants for the final signature computation. +pub const MUSIG_AGGNONCE_LEN: usize = 132; + +/// Serialized length (in bytes) of the aggregated nonce. +/// This is the compact form (typically using a compressed representation) used for +/// transmitting or storing the aggregated nonce. +pub const MUSIG_AGGNONCE_SERIALIZED_LEN: usize = 66; + +/// Serialized length (in bytes) of an individual public nonce. +/// This compact serialized form is what gets exchanged between signers. +pub const MUSIG_PUBNONCE_SERIALIZED_LEN: usize = 66; + +/// Length (in bytes) of the session structure. +/// The session object holds all state needed for a MuSig2 signing session (e.g. aggregated nonce, +/// key aggregation info, and other state necessary for computing partial signatures). +pub const MUSIG_SESSION_LEN: usize = 133; + +/// Length (in bytes) of the internal representation of a partial signature. +/// This structure include magic bytes ([0xeb, 0xfb, 0x1a, 0x32]) alongside the actual signature scalar. +pub const MUSIG_PART_SIG_LEN: usize = 36; + +/// Serialized length (in bytes) of a partial signature. +/// This is the compact form (typically just the 32-byte scalar) that is used when communicating +/// partial signatures to be combined into the final signature. +pub const MUSIG_PART_SIG_SERIALIZED_LEN: usize = 32; + +#[repr(C)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct MusigKeyAggCache([c_uchar; MUSIG_KEYAGG_LEN]); +impl_array_newtype!(MusigKeyAggCache, c_uchar, MUSIG_KEYAGG_LEN); +impl_raw_debug!(MusigKeyAggCache); + +#[repr(C)] +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct MusigSecNonce([c_uchar; MUSIG_SECNONCE_LEN]); +impl_array_newtype!(MusigSecNonce, c_uchar, MUSIG_SECNONCE_LEN); +impl_raw_debug!(MusigSecNonce); + +impl MusigSecNonce { + pub fn dangerous_from_bytes(bytes: [c_uchar; MUSIG_SECNONCE_LEN]) -> Self { + MusigSecNonce(bytes) + } + + pub fn dangerous_into_bytes(self) -> [c_uchar; MUSIG_SECNONCE_LEN] { self.0 } +} + +#[repr(C)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct MusigPubNonce([c_uchar; MUSIG_PUBNONCE_LEN]); +impl_array_newtype!(MusigPubNonce, c_uchar, MUSIG_PUBNONCE_LEN); +impl_raw_debug!(MusigPubNonce); + +#[repr(C)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct MusigAggNonce([c_uchar; MUSIG_AGGNONCE_LEN]); +impl_array_newtype!(MusigAggNonce, c_uchar, MUSIG_AGGNONCE_LEN); +impl_raw_debug!(MusigAggNonce); + +#[repr(C)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct MusigSession([c_uchar; MUSIG_SESSION_LEN]); +impl_array_newtype!(MusigSession, c_uchar, MUSIG_SESSION_LEN); +impl_raw_debug!(MusigSession); + +#[repr(C)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct MusigPartialSignature([c_uchar; MUSIG_PART_SIG_LEN]); +impl_array_newtype!(MusigPartialSignature, c_uchar, MUSIG_PART_SIG_LEN); +impl_raw_debug!(MusigPartialSignature); + +#[cfg(secp256k1_fuzz)] +mod fuzz_dummy { + use core::sync::atomic::{AtomicUsize, Ordering}; + + use super::*; + + #[cfg(rust_secp_no_symbol_renaming)] + compile_error!("We do not support fuzzing with rust_secp_no_symbol_renaming"); + + extern "C" { + fn rustsecp256k1_v0_11_context_preallocated_size(flags: c_uint) -> size_t; + fn rustsecp256k1_v0_11_context_preallocated_create( + prealloc: NonNull, + flags: c_uint, + ) -> NonNull; + fn rustsecp256k1_v0_11_context_preallocated_clone( + cx: *const Context, + prealloc: NonNull, + ) -> NonNull; + } + + #[cfg(feature = "lowmemory")] + const CTX_SIZE: usize = 1024 * 65; + #[cfg(not(feature = "lowmemory"))] + const CTX_SIZE: usize = 1024 * (1024 + 128); + // Contexts + pub unsafe fn secp256k1_context_preallocated_size(flags: c_uint) -> size_t { + assert!( + rustsecp256k1_v0_11_context_preallocated_size(flags) + std::mem::size_of::() + <= CTX_SIZE + ); + CTX_SIZE + } + + static HAVE_PREALLOCATED_CONTEXT: AtomicUsize = AtomicUsize::new(0); + const HAVE_CONTEXT_NONE: usize = 0; + const HAVE_CONTEXT_WORKING: usize = 1; + const HAVE_CONTEXT_DONE: usize = 2; + static mut PREALLOCATED_CONTEXT: [u8; CTX_SIZE] = [0; CTX_SIZE]; + pub unsafe fn secp256k1_context_preallocated_create( + prealloc: NonNull, + flags: c_uint, + ) -> NonNull { + // While applications should generally avoid creating too many contexts, sometimes fuzzers + // perform tasks repeatedly which real applications may only do rarely. Thus, we want to + // avoid being overly slow here. We do so by having a static context and copying it into + // new buffers instead of recalculating it. Because we shouldn't rely on std, we use a + // simple hand-written OnceFlag built out of an atomic to gate the global static. + let mut have_ctx = HAVE_PREALLOCATED_CONTEXT.load(Ordering::Relaxed); + while have_ctx != HAVE_CONTEXT_DONE { + if have_ctx == HAVE_CONTEXT_NONE { + have_ctx = HAVE_PREALLOCATED_CONTEXT.swap(HAVE_CONTEXT_WORKING, Ordering::AcqRel); + if have_ctx == HAVE_CONTEXT_NONE { + assert!( + rustsecp256k1_v0_11_context_preallocated_size( + SECP256K1_START_SIGN | SECP256K1_START_VERIFY + ) + std::mem::size_of::() + <= CTX_SIZE + ); + assert_eq!( + rustsecp256k1_v0_11_context_preallocated_create( + NonNull::new_unchecked( + PREALLOCATED_CONTEXT[..].as_mut_ptr() as *mut c_void + ), + SECP256K1_START_SIGN | SECP256K1_START_VERIFY + ), + NonNull::new_unchecked( + PREALLOCATED_CONTEXT[..].as_mut_ptr() as *mut Context + ) + ); + assert_eq!( + HAVE_PREALLOCATED_CONTEXT.swap(HAVE_CONTEXT_DONE, Ordering::AcqRel), + HAVE_CONTEXT_WORKING + ); + } else if have_ctx == HAVE_CONTEXT_DONE { + // Another thread finished while we were swapping. + HAVE_PREALLOCATED_CONTEXT.store(HAVE_CONTEXT_DONE, Ordering::Release); + } + } else { + // Another thread is building, just busy-loop until they're done. + assert_eq!(have_ctx, HAVE_CONTEXT_WORKING); + have_ctx = HAVE_PREALLOCATED_CONTEXT.load(Ordering::Acquire); + #[cfg(feature = "std")] + std::thread::yield_now(); + } + } + ptr::copy_nonoverlapping( + PREALLOCATED_CONTEXT[..].as_ptr(), + prealloc.as_ptr() as *mut u8, + CTX_SIZE, + ); + let ptr = (prealloc.as_ptr()).add(CTX_SIZE).sub(std::mem::size_of::()); + (ptr as *mut c_uint).write(flags); + NonNull::new_unchecked(prealloc.as_ptr() as *mut Context) + } + pub unsafe fn secp256k1_context_preallocated_clone_size(_cx: *const Context) -> size_t { + CTX_SIZE + } + pub unsafe fn secp256k1_context_preallocated_clone( + cx: *const Context, + prealloc: NonNull, + ) -> NonNull { + let orig_ptr = (cx as *mut u8).add(CTX_SIZE).sub(std::mem::size_of::()); + let new_ptr = + (prealloc.as_ptr() as *mut u8).add(CTX_SIZE).sub(std::mem::size_of::()); + let flags = (orig_ptr as *mut c_uint).read(); + (new_ptr as *mut c_uint).write(flags); + rustsecp256k1_v0_11_context_preallocated_clone(cx, prealloc) + } + + pub unsafe fn secp256k1_context_randomize( + cx: NonNull, + _seed32: *const c_uchar, + ) -> c_int { + // This function is really slow, and unsuitable for fuzzing + check_context_flags(cx.as_ptr(), 0); + 1 + } + + unsafe fn check_context_flags(cx: *const Context, required_flags: c_uint) { + assert!(!cx.is_null()); + let cx_flags = if cx == secp256k1_context_no_precomp { + 1 + } else { + let ptr = (cx as *const u8).add(CTX_SIZE).sub(std::mem::size_of::()); + (ptr as *const c_uint).read() + }; + assert_eq!(cx_flags & 1, 1); // SECP256K1_FLAGS_TYPE_CONTEXT + assert_eq!(cx_flags & required_flags, required_flags); + } + + /// Checks that pk != 0xffff...ffff and pk[1..32] == pk[33..64] + unsafe fn test_pk_validate(cx: *const Context, pk: *const PublicKey) -> c_int { + check_context_flags(cx, 0); + if (*pk).0[1..32] != (*pk).0[33..64] + || ((*pk).0[32] != 0 && (*pk).0[32] != 0xff) + || secp256k1_ec_seckey_verify(cx, (*pk).0[0..32].as_ptr()) == 0 + { + 0 + } else { + 1 + } + } + unsafe fn test_cleanup_pk(pk: *mut PublicKey) { + (*pk).0[32..].copy_from_slice(&(*pk).0[..32]); + if (*pk).0[32] <= 0x7f { + (*pk).0[32] = 0; + } else { + (*pk).0[32] = 0xff; + } + } + + // Pubkeys + pub unsafe fn secp256k1_ec_pubkey_parse( + cx: *const Context, + pk: *mut PublicKey, + input: *const c_uchar, + in_len: size_t, + ) -> c_int { + check_context_flags(cx, 0); + match in_len { + 33 => + if *input != 2 && *input != 3 { + 0 + } else { + ptr::copy(input.offset(1), (*pk).0[0..32].as_mut_ptr(), 32); + ptr::copy(input.offset(2), (*pk).0[33..64].as_mut_ptr(), 31); + if *input == 3 { + (*pk).0[32] = 0xff; + } else { + (*pk).0[32] = 0; + } + test_pk_validate(cx, pk) + }, + 65 => + if *input != 4 && *input != 6 && *input != 7 { + 0 + } else { + ptr::copy(input.offset(1), (*pk).0.as_mut_ptr(), 64); + test_cleanup_pk(pk); + test_pk_validate(cx, pk) + }, + _ => 0, + } + } + + /// Serialize PublicKey back to 33/65 byte pubkey + pub unsafe fn secp256k1_ec_pubkey_serialize( + cx: *const Context, + output: *mut c_uchar, + out_len: *mut size_t, + pk: *const PublicKey, + compressed: c_uint, + ) -> c_int { + check_context_flags(cx, 0); + assert_eq!(test_pk_validate(cx, pk), 1); + if compressed == SECP256K1_SER_COMPRESSED { + assert_eq!(*out_len, 33); + if (*pk).0[32] <= 0x7f { + *output = 2; + } else { + *output = 3; + } + ptr::copy((*pk).0.as_ptr(), output.offset(1), 32); + } else if compressed == SECP256K1_SER_UNCOMPRESSED { + assert_eq!(*out_len, 65); + *output = 4; + ptr::copy((*pk).0.as_ptr(), output.offset(1), 64); + } else { + panic!("Bad flags"); + } + 1 + } + + // EC + /// Sets pk to sk||sk + pub unsafe fn secp256k1_ec_pubkey_create( + cx: *const Context, + pk: *mut PublicKey, + sk: *const c_uchar, + ) -> c_int { + check_context_flags(cx, SECP256K1_START_SIGN); + if secp256k1_ec_seckey_verify(cx, sk) != 1 { + return 0; + } + ptr::copy(sk, (*pk).0[0..32].as_mut_ptr(), 32); + test_cleanup_pk(pk); + assert_eq!(test_pk_validate(cx, pk), 1); + 1 + } + + pub unsafe fn secp256k1_ec_pubkey_negate(cx: *const Context, pk: *mut PublicKey) -> c_int { + check_context_flags(cx, 0); + assert_eq!(test_pk_validate(cx, pk), 1); + if secp256k1_ec_seckey_negate(cx, (*pk).0[..32].as_mut_ptr()) != 1 { + return 0; + } + test_cleanup_pk(pk); + assert_eq!(test_pk_validate(cx, pk), 1); + 1 + } + + /// The PublicKey equivalent of secp256k1_ec_privkey_tweak_add + pub unsafe fn secp256k1_ec_pubkey_tweak_add( + cx: *const Context, + pk: *mut PublicKey, + tweak: *const c_uchar, + ) -> c_int { + check_context_flags(cx, SECP256K1_START_VERIFY); + assert_eq!(test_pk_validate(cx, pk), 1); + if secp256k1_ec_seckey_tweak_add(cx, (*pk).0[..32].as_mut_ptr(), tweak) != 1 { + return 0; + } + test_cleanup_pk(pk); + assert_eq!(test_pk_validate(cx, pk), 1); + 1 + } + + /// The PublicKey equivalent of secp256k1_ec_privkey_tweak_mul + pub unsafe fn secp256k1_ec_pubkey_tweak_mul( + cx: *const Context, + pk: *mut PublicKey, + tweak: *const c_uchar, + ) -> c_int { + check_context_flags(cx, 0); + assert_eq!(test_pk_validate(cx, pk), 1); + if secp256k1_ec_seckey_tweak_mul(cx, (*pk).0[..32].as_mut_ptr(), tweak) != 1 { + return 0; + } + test_cleanup_pk(pk); + assert_eq!(test_pk_validate(cx, pk), 1); + 1 + } + + pub unsafe fn secp256k1_ec_pubkey_combine( + cx: *const Context, + out: *mut PublicKey, + ins: *const *const PublicKey, + n: size_t, + ) -> c_int { + check_context_flags(cx, 0); + assert!(n >= 1); + (*out) = **ins; + for i in 1..n { + assert_eq!(test_pk_validate(cx, *ins.offset(i as isize)), 1); + if secp256k1_ec_seckey_tweak_add( + cx, + (*out).0[..32].as_mut_ptr(), + (**ins.offset(i as isize)).0[..32].as_ptr(), + ) != 1 + { + return 0; + } + } + test_cleanup_pk(out); + assert_eq!(test_pk_validate(cx, out), 1); + 1 + } + + /// Sets out to point^scalar^1s + pub unsafe fn secp256k1_ecdh( + cx: *const Context, + out: *mut c_uchar, + point: *const PublicKey, + scalar: *const c_uchar, + hashfp: EcdhHashFn, + data: *mut c_void, + ) -> c_int { + check_context_flags(cx, 0); + assert_eq!(test_pk_validate(cx, point), 1); + if secp256k1_ec_seckey_verify(cx, scalar) != 1 { + return 0; + } + + let scalar_slice = slice::from_raw_parts(scalar, 32); + let pk_slice = &(*point).0[..32]; + + let mut res_arr = [0u8; 32]; + for i in 0..32 { + res_arr[i] = scalar_slice[i] ^ pk_slice[i] ^ 1; + } + + if let Some(hashfn) = hashfp { + (hashfn)(out, res_arr.as_ptr(), res_arr.as_ptr(), data); + } else { + res_arr[16] = 0x00; // result should always be a valid secret key + let out_slice = slice::from_raw_parts_mut(out, 32); + out_slice.copy_from_slice(&res_arr); + } + 1 + } + + // ECDSA + /// Verifies that sig is msg32||pk[..32] + pub unsafe fn secp256k1_ecdsa_verify( + cx: *const Context, + sig: *const Signature, + msg32: *const c_uchar, + pk: *const PublicKey, + ) -> c_int { + check_context_flags(cx, SECP256K1_START_VERIFY); + // Actually verify + let sig_sl = slice::from_raw_parts(sig as *const u8, 64); + let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32); + if &sig_sl[..32] == msg_sl && sig_sl[32..] == (*pk).0[0..32] { + 1 + } else { + 0 + } + } + + /// Sets sig to msg32||pk[..32] + pub unsafe fn secp256k1_ecdsa_sign( + cx: *const Context, + sig: *mut Signature, + msg32: *const c_uchar, + sk: *const c_uchar, + _noncefn: NonceFn, + _noncedata: *const c_void, + ) -> c_int { + check_context_flags(cx, SECP256K1_START_SIGN); + // Check context is built for signing (and compute pk) + let mut new_pk = PublicKey::new(); + if secp256k1_ec_pubkey_create(cx, &mut new_pk, sk) != 1 { + return 0; + } + // Sign + let sig_sl = slice::from_raw_parts_mut(sig as *mut u8, 64); + let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32); + sig_sl[..32].copy_from_slice(msg_sl); + sig_sl[32..].copy_from_slice(&new_pk.0[..32]); + 1 + } + + // Schnorr Signatures + /// Verifies that sig is msg32||pk[32..] + pub unsafe fn secp256k1_schnorrsig_verify( + cx: *const Context, + sig64: *const c_uchar, + msg32: *const c_uchar, + msglen: size_t, + pubkey: *const XOnlyPublicKey, + ) -> c_int { + check_context_flags(cx, SECP256K1_START_VERIFY); + // Check context is built for verification + let mut new_pk = PublicKey::new(); + let _ = secp256k1_xonly_pubkey_tweak_add(cx, &mut new_pk, pubkey, msg32); + // Actually verify + let sig_sl = slice::from_raw_parts(sig64 as *const u8, 64); + let msg_sl = slice::from_raw_parts(msg32 as *const u8, msglen); + if &sig_sl[..32] == msg_sl && sig_sl[32..] == (*pubkey).0[..32] { + 1 + } else { + 0 + } + } + + /// Sets sig to msg32||pk[..32] + pub unsafe fn secp256k1_schnorrsig_sign( + cx: *const Context, + sig64: *mut c_uchar, + msg32: *const c_uchar, + keypair: *const Keypair, + _aux_rand32: *const c_uchar, + ) -> c_int { + check_context_flags(cx, SECP256K1_START_SIGN); + // Check context is built for signing + let mut new_kp = Keypair::new(); + if secp256k1_keypair_create(cx, &mut new_kp, (*keypair).0.as_ptr()) != 1 { + return 0; + } + assert_eq!(new_kp, *keypair); + // Sign + let sig_sl = slice::from_raw_parts_mut(sig64 as *mut u8, 64); + let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32); + sig_sl[..32].copy_from_slice(msg_sl); + sig_sl[32..].copy_from_slice(&new_kp.0[32..64]); + 1 + } + + // Forwards to regular schnorrsig_sign function. + pub unsafe fn secp256k1_schnorrsig_sign_custom( + cx: *const Context, + sig: *mut c_uchar, + msg: *const c_uchar, + _msg_len: size_t, + keypair: *const Keypair, + _extra_params: *const SchnorrSigExtraParams, + ) -> c_int { + secp256k1_schnorrsig_sign(cx, sig, msg, keypair, ptr::null()) + } + + // Extra keys + pub unsafe fn secp256k1_keypair_create( + cx: *const Context, + keypair: *mut Keypair, + seckey: *const c_uchar, + ) -> c_int { + check_context_flags(cx, SECP256K1_START_SIGN); + if secp256k1_ec_seckey_verify(cx, seckey) == 0 { + return 0; + } + + let mut pk = PublicKey::new(); + if secp256k1_ec_pubkey_create(cx, &mut pk, seckey) == 0 { + return 0; + } + + let seckey_slice = slice::from_raw_parts(seckey, 32); + (*keypair).0[..32].copy_from_slice(seckey_slice); + (*keypair).0[32..].copy_from_slice(&pk.0); + 1 + } + + pub unsafe fn secp256k1_xonly_pubkey_parse( + cx: *const Context, + pubkey: *mut XOnlyPublicKey, + input32: *const c_uchar, + ) -> c_int { + check_context_flags(cx, 0); + let inslice = slice::from_raw_parts(input32, 32); + (*pubkey).0[..32].copy_from_slice(inslice); + (*pubkey).0[32..].copy_from_slice(inslice); + test_cleanup_pk(pubkey as *mut PublicKey); + test_pk_validate(cx, pubkey as *mut PublicKey) + } + + pub unsafe fn secp256k1_xonly_pubkey_serialize( + cx: *const Context, + output32: *mut c_uchar, + pubkey: *const XOnlyPublicKey, + ) -> c_int { + check_context_flags(cx, 0); + let outslice = slice::from_raw_parts_mut(output32, 32); + outslice.copy_from_slice(&(*pubkey).0[..32]); + 1 + } + + pub unsafe fn secp256k1_xonly_pubkey_from_pubkey( + cx: *const Context, + xonly_pubkey: *mut XOnlyPublicKey, + pk_parity: *mut c_int, + pubkey: *const PublicKey, + ) -> c_int { + check_context_flags(cx, 0); + if !pk_parity.is_null() { + *pk_parity = ((*pubkey).0[32] == 0).into(); + } + (*xonly_pubkey).0.copy_from_slice(&(*pubkey).0); + assert_eq!(test_pk_validate(cx, pubkey), 1); + 1 + } + + pub unsafe fn secp256k1_xonly_pubkey_tweak_add( + cx: *const Context, + output_pubkey: *mut PublicKey, + internal_pubkey: *const XOnlyPublicKey, + tweak32: *const c_uchar, + ) -> c_int { + check_context_flags(cx, SECP256K1_START_VERIFY); + (*output_pubkey).0.copy_from_slice(&(*internal_pubkey).0); + secp256k1_ec_pubkey_tweak_add(cx, output_pubkey, tweak32) + } + + pub unsafe fn secp256k1_keypair_xonly_pub( + cx: *const Context, + pubkey: *mut XOnlyPublicKey, + pk_parity: *mut c_int, + keypair: *const Keypair, + ) -> c_int { + check_context_flags(cx, 0); + if !pk_parity.is_null() { + *pk_parity = ((*keypair).0[64] == 0).into(); + } + (*pubkey).0.copy_from_slice(&(*keypair).0[32..]); + 1 + } + + pub unsafe fn secp256k1_keypair_xonly_tweak_add( + cx: *const Context, + keypair: *mut Keypair, + tweak32: *const c_uchar, + ) -> c_int { + check_context_flags(cx, SECP256K1_START_VERIFY); + let mut pk = PublicKey::new(); + pk.0.copy_from_slice(&(*keypair).0[32..]); + let mut sk = [0u8; 32]; + sk.copy_from_slice(&(*keypair).0[..32]); + assert_eq!(secp256k1_ec_pubkey_tweak_add(cx, &mut pk, tweak32), 1); + assert_eq!(secp256k1_ec_seckey_tweak_add(cx, (&mut sk[..]).as_mut_ptr(), tweak32), 1); + (*keypair).0[..32].copy_from_slice(&sk); + (*keypair).0[32..].copy_from_slice(&pk.0); + 1 + } + + pub unsafe fn secp256k1_xonly_pubkey_tweak_add_check( + cx: *const Context, + tweaked_pubkey32: *const c_uchar, + tweaked_pubkey_parity: c_int, + internal_pubkey: *const XOnlyPublicKey, + tweak32: *const c_uchar, + ) -> c_int { + check_context_flags(cx, SECP256K1_START_VERIFY); + let mut tweaked_pk = PublicKey::new(); + assert_eq!( + secp256k1_xonly_pubkey_tweak_add(cx, &mut tweaked_pk, internal_pubkey, tweak32), + 1 + ); + let in_slice = slice::from_raw_parts(tweaked_pubkey32, 32); + if &tweaked_pk.0[..32] == in_slice + && tweaked_pubkey_parity == (tweaked_pk.0[32] == 0).into() + { + 1 + } else { + 0 + } + } +} + +#[cfg(secp256k1_fuzz)] +pub use self::fuzz_dummy::*; + +#[cfg(test)] +mod tests { + #[cfg(not(rust_secp_no_symbol_renaming))] + #[test] + fn test_strlen() { + use std::ffi::CString; + + use super::strlen; + + let orig = "test strlen \t \n"; + let test = CString::new(orig).unwrap(); + + assert_eq!(orig.len(), unsafe { strlen(test.as_ptr()) }); + } +} diff --git a/ark-rust-secp256k1/secp256k1-sys/src/macros.rs b/ark-rust-secp256k1/secp256k1-sys/src/macros.rs new file mode 100644 index 00000000..ec225ab4 --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/src/macros.rs @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: CC0-1.0 + +/// Implement methods and traits for types that contain an inner array. +#[macro_export] +macro_rules! impl_array_newtype { + ($thing:ident, $ty:ty, $len:expr) => { + impl $thing { + /// Like `cmp::Ord` but faster and with no guarantees across library versions. + /// + /// The inner byte array of `Self` is passed across the FFI boundry, as such there are + /// no guarantees on its layout and it is subject to change across library versions, + /// even minor versions. For this reason comparison function implementations (e.g. + /// `Ord`, `PartialEq`) take measures to ensure the data will remain constant (e.g., by + /// serializing it to a guaranteed format). This means they may be slow, this function + /// provides a faster comparison if you know that your types come from the same library + /// version. + pub fn cmp_fast_unstable(&self, other: &Self) -> core::cmp::Ordering { + self[..].cmp(&other[..]) + } + + /// Like `cmp::Eq` but faster and with no guarantees across library versions. + /// + /// The inner byte array of `Self` is passed across the FFI boundry, as such there are + /// no guarantees on its layout and it is subject to change across library versions, + /// even minor versions. For this reason comparison function implementations (e.g. + /// `Ord`, `PartialEq`) take measures to ensure the data will remain constant (e.g., by + /// serializing it to a guaranteed format). This means they may be slow, this function + /// provides a faster equality check if you know that your types come from the same + /// library version. + pub fn eq_fast_unstable(&self, other: &Self) -> bool { + self[..].eq(&other[..]) + } + } + + impl AsRef<[$ty; $len]> for $thing { + #[inline] + /// Gets a reference to the underlying array + fn as_ref(&self) -> &[$ty; $len] { + let &$thing(ref dat) = self; + dat + } + } + + impl core::ops::Index for $thing + where + [$ty]: core::ops::Index, + { + type Output = <[$ty] as core::ops::Index>::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { &self.0[index] } + } + + impl $crate::CPtr for $thing { + type Target = $ty; + + fn as_c_ptr(&self) -> *const Self::Target { + let &$thing(ref dat) = self; + dat.as_ptr() + } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { + let &mut $thing(ref mut dat) = self; + dat.as_mut_ptr() + } + } + } +} + +#[macro_export] +macro_rules! impl_raw_debug { + ($thing:ident) => { + impl core::fmt::Debug for $thing { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + for i in self[..].iter().cloned() { + write!(f, "{:02x}", i)?; + } + Ok(()) + } + } + } +} diff --git a/ark-rust-secp256k1/secp256k1-sys/src/recovery.rs b/ark-rust-secp256k1/secp256k1-sys/src/recovery.rs new file mode 100644 index 00000000..0a5c2aae --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/src/recovery.rs @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! # FFI of the recovery module + +use crate::{Context, Signature, NonceFn, PublicKey, CPtr, impl_array_newtype, secp256k1_context_no_precomp}; +use crate::types::*; +use core::fmt; + +/// Library-internal representation of a Secp256k1 signature + recovery ID +#[repr(C)] +#[derive(Copy, Clone)] +#[cfg_attr(secp256k1_fuzz, derive(PartialEq, Eq, PartialOrd, Ord, Hash))] +pub struct RecoverableSignature([c_uchar; 65]); +impl_array_newtype!(RecoverableSignature, c_uchar, 65); + +impl RecoverableSignature { + /// Create a new (zeroed) signature usable for the FFI interface + pub fn new() -> RecoverableSignature { RecoverableSignature([0; 65]) } + + /// Serializes the signature in compact format. + fn serialize(&self) -> [u8; 65] { + let mut buf = [0u8; 65]; + let mut recid = 0; + unsafe { + let ret = secp256k1_ecdsa_recoverable_signature_serialize_compact( + secp256k1_context_no_precomp, + buf.as_mut_c_ptr(), + &mut recid, + self, + ); + debug_assert!(ret == 1); + } + buf[64] = (recid & 0xFF) as u8; + buf + } +} + +impl Default for RecoverableSignature { + fn default() -> Self { + RecoverableSignature::new() + } +} + +impl fmt::Debug for RecoverableSignature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut ret = [0u8; 64]; + let mut recid = 0i32; + + unsafe { + let err = secp256k1_ecdsa_recoverable_signature_serialize_compact( + super::secp256k1_context_no_precomp, + ret.as_mut_c_ptr(), + &mut recid, + self, + ); + assert!(err == 1); + } + + for byte in ret.iter() { + write!(f, "{:02x}", byte)?; + } + write!(f, "{:02x}", recid as u8)?; + + Ok(()) + } +} + +#[cfg(not(secp256k1_fuzz))] +impl PartialOrd for RecoverableSignature { + fn partial_cmp(&self, other: &RecoverableSignature) -> Option { + Some(self.cmp(other)) + } +} + +#[cfg(not(secp256k1_fuzz))] +impl Ord for RecoverableSignature { + fn cmp(&self, other: &RecoverableSignature) -> core::cmp::Ordering { + let this = self.serialize(); + let that = other.serialize(); + this.cmp(&that) + } +} + +#[cfg(not(secp256k1_fuzz))] +impl PartialEq for RecoverableSignature { + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == core::cmp::Ordering::Equal + } +} + +#[cfg(not(secp256k1_fuzz))] +impl Eq for RecoverableSignature {} + +#[cfg(not(secp256k1_fuzz))] +impl core::hash::Hash for RecoverableSignature { + fn hash(&self, state: &mut H) { + let ser = self.serialize(); + ser.hash(state); + } +} + +extern "C" { + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_recoverable_signature_parse_compact")] + pub fn secp256k1_ecdsa_recoverable_signature_parse_compact(cx: *const Context, sig: *mut RecoverableSignature, + input64: *const c_uchar, recid: c_int) + -> c_int; + + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_recoverable_signature_serialize_compact")] + pub fn secp256k1_ecdsa_recoverable_signature_serialize_compact(cx: *const Context, output64: *mut c_uchar, + recid: *mut c_int, sig: *const RecoverableSignature) + -> c_int; + + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_recoverable_signature_convert")] + pub fn secp256k1_ecdsa_recoverable_signature_convert(cx: *const Context, sig: *mut Signature, + input: *const RecoverableSignature) + -> c_int; +} + +#[cfg(not(secp256k1_fuzz))] +extern "C" { + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_sign_recoverable")] + pub fn secp256k1_ecdsa_sign_recoverable(cx: *const Context, + sig: *mut RecoverableSignature, + msg32: *const c_uchar, + sk: *const c_uchar, + noncefn: NonceFn, + noncedata: *const c_void) + -> c_int; + + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_11_ecdsa_recover")] + pub fn secp256k1_ecdsa_recover(cx: *const Context, + pk: *mut PublicKey, + sig: *const RecoverableSignature, + msg32: *const c_uchar) + -> c_int; +} + + +#[cfg(secp256k1_fuzz)] +mod fuzz_dummy { + use core::slice; + + use crate::{secp256k1_ec_pubkey_create, secp256k1_ec_pubkey_parse, secp256k1_ec_pubkey_serialize, SECP256K1_SER_COMPRESSED}; + use super::*; + + /// Sets sig to msg32||full pk + pub unsafe fn secp256k1_ecdsa_sign_recoverable( + cx: *const Context, + sig: *mut RecoverableSignature, + msg32: *const c_uchar, + sk: *const c_uchar, + _noncefn: NonceFn, + _noncedata: *const c_void, + ) -> c_int { + // Check context is built for signing (and compute pk) + let mut new_pk = PublicKey::new(); + if secp256k1_ec_pubkey_create(cx, &mut new_pk, sk) != 1 { + return 0; + } + // Sign + let sig_sl = slice::from_raw_parts_mut(sig as *mut u8, 65); + let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32); + sig_sl[..32].copy_from_slice(msg_sl); + let mut out_len: size_t = 33; + secp256k1_ec_pubkey_serialize(cx, sig_sl[32..].as_mut_ptr(), &mut out_len, &new_pk, SECP256K1_SER_COMPRESSED); + // Encode the parity of the pubkey in the final byte as 0/1, + // which is the same encoding (though the parity is computed + // differently) as real recoverable signatures. + sig_sl.swap(32, 64); + sig_sl[64] -= 2; + 1 + } + + pub unsafe fn secp256k1_ecdsa_recover( + cx: *const Context, + pk: *mut PublicKey, + sig: *const RecoverableSignature, + msg32: *const c_uchar + ) -> c_int { + let sig_sl = slice::from_raw_parts(sig as *const u8, 65); + let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32); + + if sig_sl[64] >= 4 { + return 0; + } + // Pull the original pk out of the siganture + let mut pk_ser = [0u8; 33]; + pk_ser.copy_from_slice(&sig_sl[32..]); + pk_ser.swap(0, 32); + pk_ser[0] += 2; + // Check that it parses (in a real sig, this would be the R value, + // so it is actually required to be a valid point) + if secp256k1_ec_pubkey_parse(cx, pk, pk_ser.as_ptr(), 33) == 0 { + return 0; + } + // Munge it up so that a different message will give a different pk + for i in 0..32 { + pk_ser[i + 1] ^= sig_sl[i] ^ msg_sl[i]; + } + // If any munging happened, this will fail parsing half the time, so + // tweak-and-loop until we find a key that works. + let mut idx = 0; + while secp256k1_ec_pubkey_parse(cx, pk, pk_ser.as_ptr(), 33) == 0 { + pk_ser[1 + idx / 8] ^= 1 << (idx % 8); + idx += 1; + } + 1 + } +} + +#[cfg(secp256k1_fuzz)] +pub use self::fuzz_dummy::*; diff --git a/ark-rust-secp256k1/secp256k1-sys/src/types.rs b/ark-rust-secp256k1/secp256k1-sys/src/types.rs new file mode 100644 index 00000000..e52b5bfc --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/src/types.rs @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: CC0-1.0 + +#![allow(non_camel_case_types)] + +pub type c_int = i32; +pub type c_uchar = u8; +pub type c_uint = u32; +pub type size_t = usize; + +/// This might not match C's `c_char` exactly. +/// The way we use it makes it fine either way but this type shouldn't be used outside of the library. +pub type c_char = i8; + +pub use core::ffi::c_void; + +/// A type that is as aligned as the biggest alignment for fundamental types in C +/// since C11 that means as aligned as `max_align_t` is. +/// the exact size/alignment is unspecified. +// 16 matches is as big as the biggest alignment in any arch that rust currently supports https://github.com/rust-lang/rust/blob/2c31b45ae878b821975c4ebd94cc1e49f6073fd0/library/std/src/sys_common/alloc.rs +#[repr(align(16))] +#[derive(Default, Copy, Clone)] +#[allow(dead_code)] // We never access the inner data directly, only by way of a pointer. +pub struct AlignedType([u8; 16]); + +impl AlignedType { + pub fn zeroed() -> Self { + AlignedType([0u8; 16]) + } + + /// A static zeroed out AlignedType for use in static assignments of [AlignedType; _] + pub const ZERO: AlignedType = AlignedType([0u8; 16]); +} + +#[cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))] +pub(crate) const ALIGN_TO: usize = core::mem::align_of::(); + +#[cfg(test)] +mod tests { + extern crate libc; + use std::any::TypeId; + use std::mem; + use std::os::raw; + use crate::{types, AlignedType}; + + #[test] + fn verify_types() { + assert_eq!(TypeId::of::(), TypeId::of::()); + assert_eq!(TypeId::of::(), TypeId::of::()); + assert_eq!(TypeId::of::(), TypeId::of::()); + assert_eq!(TypeId::of::(), TypeId::of::()); + + assert!(mem::align_of::() >= mem::align_of::()); + } +} + +#[doc(hidden)] +#[cfg(target_arch = "wasm32")] +pub fn sanity_checks_for_wasm() { + use core::mem::{align_of, size_of}; + extern "C" { + pub static WASM32_INT_SIZE: c_uchar; + pub static WASM32_INT_ALIGN: c_uchar; + + pub static WASM32_UNSIGNED_INT_SIZE: c_uchar; + pub static WASM32_UNSIGNED_INT_ALIGN: c_uchar; + + pub static WASM32_SIZE_T_SIZE: c_uchar; + pub static WASM32_SIZE_T_ALIGN: c_uchar; + + pub static WASM32_UNSIGNED_CHAR_SIZE: c_uchar; + pub static WASM32_UNSIGNED_CHAR_ALIGN: c_uchar; + + pub static WASM32_PTR_SIZE: c_uchar; + pub static WASM32_PTR_ALIGN: c_uchar; + } + unsafe { + assert_eq!(size_of::(), WASM32_INT_SIZE as usize); + assert_eq!(align_of::(), WASM32_INT_ALIGN as usize); + + assert_eq!(size_of::(), WASM32_UNSIGNED_INT_SIZE as usize); + assert_eq!(align_of::(), WASM32_UNSIGNED_INT_ALIGN as usize); + + assert_eq!(size_of::(), WASM32_SIZE_T_SIZE as usize); + assert_eq!(align_of::(), WASM32_SIZE_T_ALIGN as usize); + + assert_eq!(size_of::(), WASM32_UNSIGNED_CHAR_SIZE as usize); + assert_eq!(align_of::(), WASM32_UNSIGNED_CHAR_ALIGN as usize); + + assert_eq!(size_of::<*const ()>(), WASM32_PTR_SIZE as usize); + assert_eq!(align_of::<*const ()>(), WASM32_PTR_ALIGN as usize); + } +} diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/vendor-libsecp.sh b/ark-rust-secp256k1/secp256k1-sys/vendor-libsecp.sh similarity index 82% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/vendor-libsecp.sh rename to ark-rust-secp256k1/secp256k1-sys/vendor-libsecp.sh index 02fb18d7..03c50bb5 100755 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/vendor-libsecp.sh +++ b/ark-rust-secp256k1/secp256k1-sys/vendor-libsecp.sh @@ -7,10 +7,10 @@ if [ -z "$SECP_VENDOR_GIT_ROOT" ]; then else SECP_VENDOR_GIT_ROOT="$(realpath "$SECP_VENDOR_GIT_ROOT")" fi -SECP_SYS="$SECP_VENDOR_GIT_ROOT"/secp256k1-zkp-sys -DEFAULT_VERSION_CODE=$(grep version "$SECP_SYS/Cargo.toml" | sed 's/\./_/g' | sed 's/.*"\(.*\)".*/\1/') +SECP_SYS="$SECP_VENDOR_GIT_ROOT"/secp256k1-sys +DEFAULT_VERSION_CODE=$(grep "^version" "$SECP_SYS/Cargo.toml" | sed 's/\./_/g' | sed 's/.*"\(.*\)".*/\1/' | cut -d_ -f1-2) DEFAULT_DEPEND_DIR="$SECP_SYS/depend" -DEFAULT_SECP_REPO=https://github.com/ElementsProject/secp256k1-zkp.git +DEFAULT_SECP_REPO=https://github.com/bitcoin-core/secp256k1.git : "${SECP_VENDOR_VERSION_CODE:=$DEFAULT_VERSION_CODE}" : "${SECP_VENDOR_DEPEND_DIR:=$DEFAULT_DEPEND_DIR}" @@ -96,34 +96,33 @@ echo "$SOURCE_REV" >> ./secp256k1-HEAD-revision.txt # To compensate, the secp_context_create and _destroy methods are redefined in Rust. patch "$DIR/include/secp256k1.h" "./secp256k1.h.patch" patch "$DIR/src/secp256k1.c" "./secp256k1.c.patch" +patch "$DIR/src/scratch.h" "./scratch.h.patch" patch "$DIR/src/scratch_impl.h" "./scratch_impl.h.patch" patch "$DIR/src/util.h" "./util.h.patch" -git apply "./surjection_impl.h.patch" -git apply "./surjection_main_impl.h.patch" -# Make sure none of the includes have a space -find "$DIR" -not -path '*/\.*' -type f -print0 | xargs -0 sed -i "s/# include/#include/g" +# Fix a linking error while cross-compiling to windowns with mingw +patch "$DIR/contrib/lax_der_parsing.c" "./lax_der_parsing.c.patch" # Prefix all methods with rustsecp and a version prefix find "$DIR" \ -not -path '*/\.*' \ -not -name "CHANGELOG.md" \ -type f \ - -print0 | xargs -0 sed -i "/^#include/! s/secp256k1_/rustsecp256k1zkp_v${SECP_VENDOR_VERSION_CODE}_/g" + -print0 | xargs -0 sed -i "/^#include/! s/secp256k1_/rustsecp256k1_v${SECP_VENDOR_VERSION_CODE}_/g" # special rule for a method that is not prefixed in libsecp find "$DIR" \ -not -path '*/\.*' \ -type f \ - -print0 | xargs -0 sed -i "/^#include/! s/ecdsa_signature_parse_der_lax/rustsecp256k1zkp_v${SECP_VENDOR_VERSION_CODE}_ecdsa_signature_parse_der_lax/g" + -print0 | xargs -0 sed -i "/^#include/! s/ecdsa_signature_parse_der_lax/rustsecp256k1_v${SECP_VENDOR_VERSION_CODE}_ecdsa_signature_parse_der_lax/g" cd "$SECP_SYS" # Update the `links = ` in the manifest file. -sed -i -r "s/^links = \".*\"$/links = \"rustsecp256k1zkp_v${SECP_VENDOR_VERSION_CODE}\"/" Cargo.toml +sed -i -r "s/^links = \".*\"$/links = \"rustsecp256k1_v${SECP_VENDOR_VERSION_CODE}\"/" Cargo.toml # Update the extern references in the Rust FFI source files. find "./src/" \ -name "*.rs" \ -type f \ - -print0 | xargs -0 sed -i -r "s/rustsecp256k1zkp_v[0-9]+_[0-9]+_[0-9]+_(.*)([\"\(])/rustsecp256k1zkp_v${SECP_VENDOR_VERSION_CODE}_\1\2/g" + -print0 | xargs -0 sed -i -r "s/rustsecp256k1_v[0-9]+_[0-9]+_[0-9]+_(.*)([\"\(])/rustsecp256k1_v${SECP_VENDOR_VERSION_CODE}_\1\2/g" popd > /dev/null diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/wasm-sysroot/stdio.h b/ark-rust-secp256k1/secp256k1-sys/wasm/wasm-sysroot/stdio.h similarity index 100% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/wasm-sysroot/stdio.h rename to ark-rust-secp256k1/secp256k1-sys/wasm/wasm-sysroot/stdio.h diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/wasm-sysroot/stdlib.h b/ark-rust-secp256k1/secp256k1-sys/wasm/wasm-sysroot/stdlib.h similarity index 100% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/wasm-sysroot/stdlib.h rename to ark-rust-secp256k1/secp256k1-sys/wasm/wasm-sysroot/stdlib.h diff --git a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/wasm-sysroot/string.h b/ark-rust-secp256k1/secp256k1-sys/wasm/wasm-sysroot/string.h similarity index 70% rename from ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/wasm-sysroot/string.h rename to ark-rust-secp256k1/secp256k1-sys/wasm/wasm-sysroot/string.h index a8428a9c..7580db53 100644 --- a/ark-rust-secp256k1-zkp/ark-secp256k1-zkp-sys/wasm-sysroot/string.h +++ b/ark-rust-secp256k1/secp256k1-sys/wasm/wasm-sysroot/string.h @@ -1,9 +1,4 @@ -#ifndef WASM_SYSROOT_STRING_H -#define WASM_SYSROOT_STRING_H - #include void *memset(void *s, int c, size_t n); void *memcpy(void *dest, const void *src, size_t n); int memcmp(const void *s1, const void *s2, size_t n); - -#endif diff --git a/ark-rust-secp256k1/secp256k1-sys/wasm/wasm.c b/ark-rust-secp256k1/secp256k1-sys/wasm/wasm.c new file mode 100644 index 00000000..8eacae6f --- /dev/null +++ b/ark-rust-secp256k1/secp256k1-sys/wasm/wasm.c @@ -0,0 +1,17 @@ +#include +#define alignof(type) offsetof (struct { char c; type member; }, member) + +const unsigned char WASM32_INT_SIZE = sizeof(int); +const unsigned char WASM32_INT_ALIGN = alignof(int); + +const unsigned char WASM32_UNSIGNED_INT_SIZE = sizeof(unsigned int); +const unsigned char WASM32_UNSIGNED_INT_ALIGN = alignof(unsigned int); + +const unsigned char WASM32_SIZE_T_SIZE = sizeof(size_t); +const unsigned char WASM32_SIZE_T_ALIGN = alignof(size_t); + +const unsigned char WASM32_UNSIGNED_CHAR_SIZE = sizeof(unsigned char); +const unsigned char WASM32_UNSIGNED_CHAR_ALIGN = alignof(unsigned char); + +const unsigned char WASM32_PTR_SIZE = sizeof(void*); +const unsigned char WASM32_PTR_ALIGN = alignof(void*); diff --git a/ark-rust-secp256k1/src/constants.rs b/ark-rust-secp256k1/src/constants.rs new file mode 100644 index 00000000..23c54cd5 --- /dev/null +++ b/ark-rust-secp256k1/src/constants.rs @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Constants related to the API and the underlying curve. +//! + +/// The size (in bytes) of a message. +pub const MESSAGE_SIZE: usize = 32; + +/// The size (in bytes) of a secret key. +pub const SECRET_KEY_SIZE: usize = 32; + +/// The size (in bytes) of a serialized public key. +pub const PUBLIC_KEY_SIZE: usize = 33; + +/// The size (in bytes) of an serialized uncompressed public key. +pub const UNCOMPRESSED_PUBLIC_KEY_SIZE: usize = 65; + +/// The maximum size of a signature. +pub const MAX_SIGNATURE_SIZE: usize = 72; + +/// The maximum size of a compact signature. +pub const COMPACT_SIGNATURE_SIZE: usize = 64; + +/// The size of a schnorr signature. +pub const SCHNORR_SIGNATURE_SIZE: usize = 64; + +/// The size of a schnorr public key. +pub const SCHNORR_PUBLIC_KEY_SIZE: usize = 32; + +/// The size of a key pair. +pub const KEY_PAIR_SIZE: usize = 96; + +/// The size of a full ElligatorSwift encoding. +pub const ELLSWIFT_ENCODING_SIZE: usize = 64; + +/// The Prime for the secp256k1 field element. +#[rustfmt::skip] +pub const FIELD_SIZE: [u8; 32] = [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f +]; + +/// The order of the secp256k1 curve. +#[rustfmt::skip] +pub const CURVE_ORDER: [u8; 32] = [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 +]; + +/// The X coordinate of the generator. +#[rustfmt::skip] +pub const GENERATOR_X: [u8; 32] = [ + 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, + 0x55, 0xa0, 0x62, 0x95, 0xce, 0x87, 0x0b, 0x07, + 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, + 0x59, 0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98 +]; + +/// The Y coordinate of the generator. +#[rustfmt::skip] +pub const GENERATOR_Y: [u8; 32] = [ + 0x48, 0x3a, 0xda, 0x77, 0x26, 0xa3, 0xc4, 0x65, + 0x5d, 0xa4, 0xfb, 0xfc, 0x0e, 0x11, 0x08, 0xa8, + 0xfd, 0x17, 0xb4, 0x48, 0xa6, 0x85, 0x54, 0x19, + 0x9c, 0x47, 0xd0, 0x8f, 0xfb, 0x10, 0xd4, 0xb8 +]; + +/// The value zero as an array of bytes. +pub const ZERO: [u8; 32] = [0; 32]; + +/// The value one as big-endian array of bytes. +pub const ONE: [u8; 32] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, +]; diff --git a/ark-rust-secp256k1/src/context.rs b/ark-rust-secp256k1/src/context.rs new file mode 100644 index 00000000..c10b8404 --- /dev/null +++ b/ark-rust-secp256k1/src/context.rs @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: CC0-1.0 + +use core::marker::PhantomData; +use core::mem::ManuallyDrop; +use core::ptr::NonNull; + +#[cfg(feature = "alloc")] +pub use self::alloc_only::{All, SignOnly, VerifyOnly}; +use crate::ffi::types::{c_uint, c_void, AlignedType}; +use crate::ffi::{self, CPtr}; +use crate::{Error, Secp256k1}; + +#[cfg(all(feature = "global-context", feature = "std"))] +/// Module implementing a singleton pattern for a global `Secp256k1` context. +pub mod global { + + use std::ops::Deref; + use std::sync::Once; + + use crate::{All, Secp256k1}; + + /// Proxy struct for global `SECP256K1` context. + #[derive(Debug, Copy, Clone)] + pub struct GlobalContext { + __private: (), + } + + /// A global static context to avoid repeatedly creating contexts. + /// + /// If `rand` and `std` feature is enabled, context will have been randomized using + /// `thread_rng`. + /// + /// ``` + /// # #[cfg(all(feature = "global-context", feature = "rand", feature = "std"))] { + /// use secp256k1::{PublicKey, SECP256K1}; + /// let _ = SECP256K1.generate_keypair(&mut rand::thread_rng()); + /// # } + /// ``` + pub static SECP256K1: &GlobalContext = &GlobalContext { __private: () }; + + impl Deref for GlobalContext { + type Target = Secp256k1; + + #[allow(unused_mut)] // Unused when `rand` + `std` is not enabled. + fn deref(&self) -> &Self::Target { + static ONCE: Once = Once::new(); + static mut CONTEXT: Option> = None; + ONCE.call_once(|| unsafe { + CONTEXT = Some(Secp256k1::new()); + }); + unsafe { CONTEXT.as_ref().unwrap() } + } + } +} + +/// A trait for all kinds of contexts that lets you define the exact flags and a function to +/// deallocate memory. It isn't possible to implement this for types outside this crate. +/// +/// # Safety +/// +/// This trait is marked unsafe to allow unsafe implementations of `deallocate`. +pub unsafe trait Context: private::Sealed { + /// Flags for the ffi. + const FLAGS: c_uint; + /// A constant description of the context. + const DESCRIPTION: &'static str; + /// A function to deallocate the memory when the context is dropped. + /// + /// # Safety + /// + /// `ptr` must be valid. Further safety constraints may be imposed by [`std::alloc::dealloc`]. + unsafe fn deallocate(ptr: *mut u8, size: usize); +} + +/// Marker trait for indicating that an instance of [`Secp256k1`] can be used for signing. +pub trait Signing: Context {} + +/// Marker trait for indicating that an instance of [`Secp256k1`] can be used for verification. +pub trait Verification: Context {} + +/// Represents the set of capabilities needed for signing (preallocated memory). +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct SignOnlyPreallocated<'buf> { + phantom: PhantomData<&'buf ()>, +} + +/// Represents the set of capabilities needed for verification (preallocated memory). +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct VerifyOnlyPreallocated<'buf> { + phantom: PhantomData<&'buf ()>, +} + +/// Represents the set of all capabilities (preallocated memory). +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct AllPreallocated<'buf> { + phantom: PhantomData<&'buf ()>, +} + +mod private { + use super::*; + pub trait Sealed {} + + impl<'buf> Sealed for AllPreallocated<'buf> {} + impl<'buf> Sealed for VerifyOnlyPreallocated<'buf> {} + impl<'buf> Sealed for SignOnlyPreallocated<'buf> {} +} + +#[cfg(feature = "alloc")] +mod alloc_only { + use core::marker::PhantomData; + use core::ptr::NonNull; + + use super::private; + use crate::alloc::alloc; + use crate::ffi::types::{c_uint, c_void}; + use crate::ffi::{self}; + use crate::{AlignedType, Context, Secp256k1, Signing, Verification}; + + impl private::Sealed for SignOnly {} + impl private::Sealed for All {} + impl private::Sealed for VerifyOnly {} + + const ALIGN_TO: usize = core::mem::align_of::(); + + /// Represents the set of capabilities needed for signing. + #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub enum SignOnly {} + + /// Represents the set of capabilities needed for verification. + #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub enum VerifyOnly {} + + /// Represents the set of all capabilities. + #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub enum All {} + + impl Signing for SignOnly {} + impl Signing for All {} + + impl Verification for VerifyOnly {} + impl Verification for All {} + + unsafe impl Context for SignOnly { + const FLAGS: c_uint = ffi::SECP256K1_START_SIGN; + const DESCRIPTION: &'static str = "signing only"; + + unsafe fn deallocate(ptr: *mut u8, size: usize) { + let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap(); + alloc::dealloc(ptr, layout); + } + } + + unsafe impl Context for VerifyOnly { + const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY; + const DESCRIPTION: &'static str = "verification only"; + + unsafe fn deallocate(ptr: *mut u8, size: usize) { + let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap(); + alloc::dealloc(ptr, layout); + } + } + + unsafe impl Context for All { + const FLAGS: c_uint = VerifyOnly::FLAGS | SignOnly::FLAGS; + const DESCRIPTION: &'static str = "all capabilities"; + + unsafe fn deallocate(ptr: *mut u8, size: usize) { + let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap(); + alloc::dealloc(ptr, layout); + } + } + + impl Secp256k1 { + /// Lets you create a context in a generic manner (sign/verify/all). + /// + /// If `rand` and `std` feature is enabled, context will have been randomized using + /// `thread_rng`. + /// If `rand` or `std` feature is not enabled please consider randomizing the context as + /// follows: + /// ``` + /// # #[cfg(all(feature = "rand", feature = "std"))] { + /// # use secp256k1::Secp256k1; + /// # use secp256k1::rand::{thread_rng, RngCore}; + /// let mut ctx = Secp256k1::new(); + /// # let mut rng = thread_rng(); + /// # let mut seed = [0u8; 32]; + /// # rng.fill_bytes(&mut seed); + /// // let seed = <32 bytes of random data> + /// ctx.seeded_randomize(&seed); + /// # } + /// ``` + #[cfg_attr( + not(all(feature = "rand", feature = "std")), + allow(clippy::let_and_return, unused_mut) + )] + pub fn gen_new() -> Secp256k1 { + #[cfg(target_arch = "wasm32")] + ffi::types::sanity_checks_for_wasm(); + + let size = unsafe { ffi::secp256k1_context_preallocated_size(C::FLAGS) }; + let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap(); + let ptr = unsafe { alloc::alloc(layout) }; + let ptr = NonNull::new(ptr as *mut c_void) + .unwrap_or_else(|| alloc::handle_alloc_error(layout)); + + #[allow(unused_mut)] // ctx is not mutated under some feature combinations. + let mut ctx = Secp256k1 { + ctx: unsafe { ffi::secp256k1_context_preallocated_create(ptr, C::FLAGS) }, + phantom: PhantomData, + }; + + #[cfg(all( + not(target_arch = "wasm32"), + feature = "rand", + feature = "std", + not(feature = "global-context-less-secure") + ))] + { + ctx.randomize(&mut rand::thread_rng()); + } + + #[allow(clippy::let_and_return)] // as for unusted_mut + ctx + } + } + + impl Secp256k1 { + /// Creates a new Secp256k1 context with all capabilities. + /// + /// If `rand` and `std` feature is enabled, context will have been randomized using + /// `thread_rng`. + /// If `rand` or `std` feature is not enabled please consider randomizing the context (see + /// docs for `Secp256k1::gen_new()`). + pub fn new() -> Secp256k1 { Secp256k1::gen_new() } + } + + impl Secp256k1 { + /// Creates a new Secp256k1 context that can only be used for signing. + /// + /// If `rand` and `std` feature is enabled, context will have been randomized using + /// `thread_rng`. + /// If `rand` or `std` feature is not enabled please consider randomizing the context (see + /// docs for `Secp256k1::gen_new()`). + pub fn signing_only() -> Secp256k1 { Secp256k1::gen_new() } + } + + impl Secp256k1 { + /// Creates a new Secp256k1 context that can only be used for verification. + /// + /// If `rand` and `std` feature is enabled, context will have been randomized using + /// `thread_rng`. + /// If `rand` or `std` feature is not enabled please consider randomizing the context (see + /// docs for `Secp256k1::gen_new()`). + pub fn verification_only() -> Secp256k1 { Secp256k1::gen_new() } + } + + impl Default for Secp256k1 { + fn default() -> Self { Self::new() } + } + + impl Clone for Secp256k1 { + fn clone(&self) -> Secp256k1 { + let size = unsafe { ffi::secp256k1_context_preallocated_clone_size(self.ctx.as_ptr()) }; + let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap(); + let ptr = unsafe { alloc::alloc(layout) }; + let ptr = NonNull::new(ptr as *mut c_void) + .unwrap_or_else(|| alloc::handle_alloc_error(layout)); + + Secp256k1 { + ctx: unsafe { ffi::secp256k1_context_preallocated_clone(self.ctx.as_ptr(), ptr) }, + phantom: PhantomData, + } + } + } +} + +impl<'buf> Signing for SignOnlyPreallocated<'buf> {} +impl<'buf> Signing for AllPreallocated<'buf> {} + +impl<'buf> Verification for VerifyOnlyPreallocated<'buf> {} +impl<'buf> Verification for AllPreallocated<'buf> {} + +unsafe impl<'buf> Context for SignOnlyPreallocated<'buf> { + const FLAGS: c_uint = ffi::SECP256K1_START_SIGN; + const DESCRIPTION: &'static str = "signing only"; + + unsafe fn deallocate(_ptr: *mut u8, _size: usize) { + // Allocated by the user + } +} + +unsafe impl<'buf> Context for VerifyOnlyPreallocated<'buf> { + const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY; + const DESCRIPTION: &'static str = "verification only"; + + unsafe fn deallocate(_ptr: *mut u8, _size: usize) { + // Allocated by the user. + } +} + +unsafe impl<'buf> Context for AllPreallocated<'buf> { + const FLAGS: c_uint = SignOnlyPreallocated::FLAGS | VerifyOnlyPreallocated::FLAGS; + const DESCRIPTION: &'static str = "all capabilities"; + + unsafe fn deallocate(_ptr: *mut u8, _size: usize) { + // Allocated by the user. + } +} + +/// Trait marking that a particular context object internally points to +/// memory that must outlive `'a` +/// +/// # Safety +/// +/// This trait is used internally to gate which context markers can safely +/// be used with the `preallocated_gen_new` function. Do not implement it +/// on your own structures. +pub unsafe trait PreallocatedContext<'a> {} + +unsafe impl<'buf> PreallocatedContext<'buf> for AllPreallocated<'buf> {} +unsafe impl<'buf> PreallocatedContext<'buf> for SignOnlyPreallocated<'buf> {} +unsafe impl<'buf> PreallocatedContext<'buf> for VerifyOnlyPreallocated<'buf> {} + +impl<'buf, C: Context + PreallocatedContext<'buf>> Secp256k1 { + /// Lets you create a context with a preallocated buffer in a generic manner (sign/verify/all). + pub fn preallocated_gen_new(buf: &'buf mut [AlignedType]) -> Result, Error> { + #[cfg(target_arch = "wasm32")] + ffi::types::sanity_checks_for_wasm(); + + if buf.len() < Self::preallocate_size_gen() { + return Err(Error::NotEnoughMemory); + } + // Safe because buf is not null since it is not empty. + let buf = unsafe { NonNull::new_unchecked(buf.as_mut_c_ptr() as *mut c_void) }; + + Ok(Secp256k1 { + ctx: unsafe { ffi::secp256k1_context_preallocated_create(buf, AllPreallocated::FLAGS) }, + phantom: PhantomData, + }) + } +} + +impl<'buf> Secp256k1> { + /// Creates a new Secp256k1 context with all capabilities. + pub fn preallocated_new( + buf: &'buf mut [AlignedType], + ) -> Result>, Error> { + Secp256k1::preallocated_gen_new(buf) + } + /// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for a context. + pub fn preallocate_size() -> usize { Self::preallocate_size_gen() } + + /// Creates a context from a raw context. + /// + /// The returned [`core::mem::ManuallyDrop`] context will never deallocate the memory pointed to + /// by `raw_ctx` nor destroy the context. This may lead to memory leaks. `ManuallyDrop::drop` + /// (or [`core::ptr::drop_in_place`]) will only destroy the context; the caller is required to + /// free the memory. + /// + /// # Safety + /// + /// This is highly unsafe due to a number of conditions that aren't checked, specifically: + /// + /// * `raw_ctx` must be a valid pointer (live, aligned...) to memory that was initialized by + /// `secp256k1_context_preallocated_create` (either called directly or from this library by + /// one of the context creation methods - all of which call it internally). + /// * The version of `libsecp256k1` used to create `raw_ctx` must be **exactly the one linked + /// into this library**. + /// * The lifetime of the `raw_ctx` pointer must outlive `'buf`. + /// * `raw_ctx` must point to writable memory (cannot be `ffi::secp256k1_context_no_precomp`). + pub unsafe fn from_raw_all( + raw_ctx: NonNull, + ) -> ManuallyDrop>> { + ManuallyDrop::new(Secp256k1 { ctx: raw_ctx, phantom: PhantomData }) + } +} + +impl<'buf> Secp256k1> { + /// Creates a new Secp256k1 context that can only be used for signing. + pub fn preallocated_signing_only( + buf: &'buf mut [AlignedType], + ) -> Result>, Error> { + Secp256k1::preallocated_gen_new(buf) + } + + /// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for the context. + #[inline] + pub fn preallocate_signing_size() -> usize { Self::preallocate_size_gen() } + + /// Creates a context from a raw context that can only be used for signing. + /// + /// # Safety + /// + /// Please see [`Secp256k1::from_raw_all`] for full documentation and safety requirements. + pub unsafe fn from_raw_signing_only( + raw_ctx: NonNull, + ) -> ManuallyDrop>> { + ManuallyDrop::new(Secp256k1 { ctx: raw_ctx, phantom: PhantomData }) + } +} + +impl<'buf> Secp256k1> { + /// Creates a new Secp256k1 context that can only be used for verification + pub fn preallocated_verification_only( + buf: &'buf mut [AlignedType], + ) -> Result>, Error> { + Secp256k1::preallocated_gen_new(buf) + } + + /// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for the context. + #[inline] + pub fn preallocate_verification_size() -> usize { Self::preallocate_size_gen() } + + /// Creates a context from a raw context that can only be used for verification. + /// + /// # Safety + /// + /// Please see [`Secp256k1::from_raw_all`] for full documentation and safety requirements. + pub unsafe fn from_raw_verification_only( + raw_ctx: NonNull, + ) -> ManuallyDrop>> { + ManuallyDrop::new(Secp256k1 { ctx: raw_ctx, phantom: PhantomData }) + } +} diff --git a/ark-rust-secp256k1/src/ecdh.rs b/ark-rust-secp256k1/src/ecdh.rs new file mode 100644 index 00000000..382b3e44 --- /dev/null +++ b/ark-rust-secp256k1/src/ecdh.rs @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Support for shared secret computations. +//! + +use core::borrow::Borrow; +use core::{ptr, str}; + +use secp256k1_sys::types::{c_int, c_uchar, c_void}; + +use crate::ffi::{self, CPtr}; +use crate::key::{PublicKey, SecretKey}; +use crate::{constants, Error}; + +// The logic for displaying shared secrets relies on this (see `secret.rs`). +const SHARED_SECRET_SIZE: usize = constants::SECRET_KEY_SIZE; + +/// Enables two parties to create a shared secret without revealing their own secrets. +/// +/// # Examples +/// +/// ``` +/// # #[cfg(all(feature = "rand", feature = "std"))] { +/// # use secp256k1::{rand, Secp256k1}; +/// # use secp256k1::ecdh::SharedSecret; +/// let s = Secp256k1::new(); +/// let (sk1, pk1) = s.generate_keypair(&mut rand::thread_rng()); +/// let (sk2, pk2) = s.generate_keypair(&mut rand::thread_rng()); +/// let sec1 = SharedSecret::new(&pk2, &sk1); +/// let sec2 = SharedSecret::new(&pk1, &sk2); +/// assert_eq!(sec1, sec2); +/// # } +// ``` +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct SharedSecret([u8; SHARED_SECRET_SIZE]); +impl_display_secret!(SharedSecret); +impl_non_secure_erase!(SharedSecret, 0, [0u8; SHARED_SECRET_SIZE]); + +impl SharedSecret { + /// Creates a new shared secret from a pubkey and secret key. + #[inline] + pub fn new(point: &PublicKey, scalar: &SecretKey) -> SharedSecret { + let mut buf = [0u8; SHARED_SECRET_SIZE]; + let res = unsafe { + ffi::secp256k1_ecdh( + ffi::secp256k1_context_no_precomp, + buf.as_mut_ptr(), + point.as_c_ptr(), + scalar.as_c_ptr(), + ffi::secp256k1_ecdh_hash_function_default, + ptr::null_mut(), + ) + }; + debug_assert_eq!(res, 1); + SharedSecret(buf) + } + + /// Returns the shared secret as a byte value. + #[inline] + pub fn secret_bytes(&self) -> [u8; SHARED_SECRET_SIZE] { self.0 } + + /// Creates a shared secret from `bytes` array. + #[inline] + pub fn from_bytes(bytes: [u8; SHARED_SECRET_SIZE]) -> SharedSecret { SharedSecret(bytes) } + + /// Creates a shared secret from `bytes` slice. + #[deprecated(since = "TBD", note = "Use `from_bytes` instead.")] + #[inline] + pub fn from_slice(bytes: &[u8]) -> Result { + match bytes.len() { + SHARED_SECRET_SIZE => { + let mut ret = [0u8; SHARED_SECRET_SIZE]; + ret[..].copy_from_slice(bytes); + Ok(SharedSecret(ret)) + } + _ => Err(Error::InvalidSharedSecret), + } + } +} + +impl str::FromStr for SharedSecret { + type Err = Error; + fn from_str(s: &str) -> Result { + let mut res = [0u8; SHARED_SECRET_SIZE]; + match crate::from_hex(s, &mut res) { + Ok(SHARED_SECRET_SIZE) => Ok(SharedSecret::from_bytes(res)), + _ => Err(Error::InvalidSharedSecret), + } + } +} + +impl Borrow<[u8]> for SharedSecret { + fn borrow(&self) -> &[u8] { &self.0 } +} + +impl AsRef<[u8]> for SharedSecret { + fn as_ref(&self) -> &[u8] { &self.0 } +} + +/// Creates a shared point from public key and secret key. +/// +/// **Important: use of a strong cryptographic hash function may be critical to security! Do NOT use +/// unless you understand cryptographical implications.** If not, use SharedSecret instead. +/// +/// Can be used like `SharedSecret` but caller is responsible for then hashing the returned buffer. +/// This allows for the use of a custom hash function since `SharedSecret` uses SHA256. +/// +/// # Returns +/// +/// 64 bytes representing the (x,y) co-ordinates of a point on the curve (32 bytes each). +/// +/// # Examples +/// ``` +/// # #[cfg(all(feature = "hashes", feature = "rand", feature = "std"))] { +/// # use secp256k1::{ecdh, rand, Secp256k1, PublicKey, SecretKey}; +/// # use secp256k1::hashes::{Hash, sha512}; +/// +/// let s = Secp256k1::new(); +/// let (sk1, pk1) = s.generate_keypair(&mut rand::thread_rng()); +/// let (sk2, pk2) = s.generate_keypair(&mut rand::thread_rng()); +/// +/// let point1 = ecdh::shared_secret_point(&pk2, &sk1); +/// let secret1 = sha512::Hash::hash(&point1); +/// let point2 = ecdh::shared_secret_point(&pk1, &sk2); +/// let secret2 = sha512::Hash::hash(&point2); +/// assert_eq!(secret1, secret2) +/// # } +/// ``` +pub fn shared_secret_point(point: &PublicKey, scalar: &SecretKey) -> [u8; 64] { + let mut xy = [0u8; 64]; + + let res = unsafe { + ffi::secp256k1_ecdh( + ffi::secp256k1_context_no_precomp, + xy.as_mut_ptr(), + point.as_c_ptr(), + scalar.as_c_ptr(), + Some(c_callback), + ptr::null_mut(), + ) + }; + // Our callback *always* returns 1. + // The scalar was verified to be valid (0 > scalar > group_order) via the type system. + debug_assert_eq!(res, 1); + xy +} + +unsafe extern "C" fn c_callback( + output: *mut c_uchar, + x: *const c_uchar, + y: *const c_uchar, + _data: *mut c_void, +) -> c_int { + ptr::copy_nonoverlapping(x, output, 32); + ptr::copy_nonoverlapping(y, output.offset(32), 32); + 1 +} + +#[cfg(feature = "serde")] +impl ::serde::Serialize for SharedSecret { + fn serialize(&self, s: S) -> Result { + if s.is_human_readable() { + let mut buf = [0u8; SHARED_SECRET_SIZE * 2]; + s.serialize_str(crate::to_hex(&self.0, &mut buf).expect("fixed-size hex serialization")) + } else { + s.serialize_bytes(self.as_ref()) + } + } +} + +#[cfg(feature = "serde")] +impl<'de> ::serde::Deserialize<'de> for SharedSecret { + fn deserialize>(d: D) -> Result { + if d.is_human_readable() { + d.deserialize_str(super::serde_util::FromStrVisitor::new( + "a hex string representing 32 byte SharedSecret", + )) + } else { + d.deserialize_bytes(super::serde_util::BytesVisitor::new( + "raw 32 bytes SharedSecret", + SharedSecret::from_slice, + )) + } + } +} + +#[cfg(test)] +#[allow(unused_imports)] +mod tests { + #[cfg(target_arch = "wasm32")] + use wasm_bindgen_test::wasm_bindgen_test as test; + + use super::SharedSecret; + use crate::Secp256k1; + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn ecdh() { + let s = Secp256k1::signing_only(); + let (sk1, pk1) = s.generate_keypair(&mut rand::thread_rng()); + let (sk2, pk2) = s.generate_keypair(&mut rand::thread_rng()); + + let sec1 = SharedSecret::new(&pk2, &sk1); + let sec2 = SharedSecret::new(&pk1, &sk2); + let sec_odd = SharedSecret::new(&pk1, &sk1); + assert_eq!(sec1, sec2); + assert!(sec_odd != sec2); + } + + #[test] + fn test_c_callback() { + let x = [5u8; 32]; + let y = [7u8; 32]; + let mut output = [0u8; 64]; + let res = unsafe { + super::c_callback(output.as_mut_ptr(), x.as_ptr(), y.as_ptr(), core::ptr::null_mut()) + }; + assert_eq!(res, 1); + let mut new_x = [0u8; 32]; + let mut new_y = [0u8; 32]; + new_x.copy_from_slice(&output[..32]); + new_y.copy_from_slice(&output[32..]); + assert_eq!(x, new_x); + assert_eq!(y, new_y); + } + + #[test] + #[cfg(not(secp256k1_fuzz))] + #[cfg(all(feature = "hashes", feature = "rand", feature = "std"))] + fn hashes_and_sys_generate_same_secret() { + use hashes::{sha256, Hash, HashEngine}; + + use crate::ecdh::shared_secret_point; + + let s = Secp256k1::signing_only(); + let (sk1, _) = s.generate_keypair(&mut rand::thread_rng()); + let (_, pk2) = s.generate_keypair(&mut rand::thread_rng()); + + let secret_sys = SharedSecret::new(&pk2, &sk1); + + let xy = shared_secret_point(&pk2, &sk1); + + // Mimics logic in `bitcoin-core/secp256k1/src/module/main_impl.h` + let version = (xy[63] & 0x01) | 0x02; + let mut engine = sha256::HashEngine::default(); + engine.input(&[version]); + engine.input(&xy.as_ref()[..32]); + let secret_bh = sha256::Hash::from_engine(engine); + + assert_eq!(secret_bh.as_byte_array(), secret_sys.as_ref()); + } + + #[test] + #[cfg(all(feature = "serde", feature = "alloc"))] + fn serde() { + use serde_test::{assert_tokens, Configure, Token}; + #[rustfmt::skip] + static BYTES: [u8; 32] = [ + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 2, 3, 4, 5, 6, 7, + 0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0, + 99, 99, 99, 99, 99, 99, 99, 99 + ]; + static STR: &str = "01010101010101010001020304050607ffff0000ffff00006363636363636363"; + + let secret = SharedSecret::from_slice(&BYTES).unwrap(); + + assert_tokens(&secret.compact(), &[Token::BorrowedBytes(&BYTES[..])]); + assert_tokens(&secret.compact(), &[Token::Bytes(&BYTES)]); + assert_tokens(&secret.compact(), &[Token::ByteBuf(&BYTES)]); + + assert_tokens(&secret.readable(), &[Token::BorrowedStr(STR)]); + assert_tokens(&secret.readable(), &[Token::Str(STR)]); + assert_tokens(&secret.readable(), &[Token::String(STR)]); + } +} + +#[cfg(bench)] +#[cfg(all(feature = "rand", feature = "std"))] // Currently only a single bench that requires "rand" + "std". +mod benches { + use test::{black_box, Bencher}; + + use super::SharedSecret; + use crate::Secp256k1; + + #[bench] + pub fn bench_ecdh(bh: &mut Bencher) { + let s = Secp256k1::signing_only(); + let (sk, pk) = s.generate_keypair(&mut rand::thread_rng()); + + bh.iter(|| { + let res = SharedSecret::new(&pk, &sk); + black_box(res); + }); + } +} diff --git a/ark-rust-secp256k1/src/ecdsa/mod.rs b/ark-rust-secp256k1/src/ecdsa/mod.rs new file mode 100644 index 00000000..1cf57c13 --- /dev/null +++ b/ark-rust-secp256k1/src/ecdsa/mod.rs @@ -0,0 +1,489 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Structs and functionality related to the ECDSA signature algorithm. +//! + +#[cfg(feature = "recovery")] +mod recovery; +pub mod serialized_signature; + +use core::{fmt, ptr, str}; + +#[cfg(feature = "recovery")] +pub use self::recovery::{RecoverableSignature, RecoveryId}; +pub use self::serialized_signature::SerializedSignature; +use crate::ffi::CPtr; +#[cfg(feature = "global-context")] +use crate::SECP256K1; +use crate::{ + ffi, from_hex, Error, Message, PublicKey, Secp256k1, SecretKey, Signing, Verification, +}; + +/// An ECDSA signature +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub struct Signature(pub(crate) ffi::Signature); +impl_fast_comparisons!(Signature); + +impl fmt::Debug for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } +} + +impl fmt::Display for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let sig = self.serialize_der(); + sig.fmt(f) + } +} + +impl str::FromStr for Signature { + type Err = Error; + fn from_str(s: &str) -> Result { + let mut res = [0u8; 72]; + match from_hex(s, &mut res) { + Ok(x) => Signature::from_der(&res[0..x]), + _ => Err(Error::InvalidSignature), + } + } +} + +impl Signature { + #[inline] + /// Converts a DER-encoded byte slice to a signature + pub fn from_der(data: &[u8]) -> Result { + if data.is_empty() { + return Err(Error::InvalidSignature); + } + + unsafe { + let mut ret = ffi::Signature::new(); + if ffi::secp256k1_ecdsa_signature_parse_der( + ffi::secp256k1_context_no_precomp, + &mut ret, + data.as_c_ptr(), + data.len(), + ) == 1 + { + Ok(Signature(ret)) + } else { + Err(Error::InvalidSignature) + } + } + } + + /// Converts a 64-byte compact-encoded byte slice to a signature + pub fn from_compact(data: &[u8]) -> Result { + if data.len() != 64 { + return Err(Error::InvalidSignature); + } + + unsafe { + let mut ret = ffi::Signature::new(); + if ffi::secp256k1_ecdsa_signature_parse_compact( + ffi::secp256k1_context_no_precomp, + &mut ret, + data.as_c_ptr(), + ) == 1 + { + Ok(Signature(ret)) + } else { + Err(Error::InvalidSignature) + } + } + } + + /// Converts a "lax DER"-encoded byte slice to a signature. This is basically + /// only useful for validating signatures in the Bitcoin blockchain from before + /// 2016. It should never be used in new applications. This library does not + /// support serializing to this "format" + pub fn from_der_lax(data: &[u8]) -> Result { + if data.is_empty() { + return Err(Error::InvalidSignature); + } + + unsafe { + let mut ret = ffi::Signature::new(); + if ffi::ecdsa_signature_parse_der_lax( + ffi::secp256k1_context_no_precomp, + &mut ret, + data.as_c_ptr(), + data.len(), + ) == 1 + { + Ok(Signature(ret)) + } else { + Err(Error::InvalidSignature) + } + } + } + + /// Normalizes a signature to a "low S" form. In ECDSA, signatures are + /// of the form (r, s) where r and s are numbers lying in some finite + /// field. The verification equation will pass for (r, s) iff it passes + /// for (r, -s), so it is possible to ``modify'' signatures in transit + /// by flipping the sign of s. This does not constitute a forgery since + /// the signed message still cannot be changed, but for some applications, + /// changing even the signature itself can be a problem. Such applications + /// require a "strong signature". It is believed that ECDSA is a strong + /// signature except for this ambiguity in the sign of s, so to accommodate + /// these applications libsecp256k1 considers signatures for which s is in + /// the upper half of the field range invalid. This eliminates the + /// ambiguity. + /// + /// However, for some systems, signatures with high s-values are considered + /// valid. (For example, parsing the historic Bitcoin blockchain requires + /// this.) For these applications we provide this normalization function, + /// which ensures that the s value lies in the lower half of its range. + pub fn normalize_s(&mut self) { + unsafe { + // Ignore return value, which indicates whether the sig + // was already normalized. We don't care. + ffi::secp256k1_ecdsa_signature_normalize( + ffi::secp256k1_context_no_precomp, + self.as_mut_c_ptr(), + self.as_c_ptr(), + ); + } + } + + /// Obtains a raw pointer suitable for use with FFI functions + #[inline] + #[deprecated(since = "0.25.0", note = "Use Self::as_c_ptr if you need to access the FFI layer")] + pub fn as_ptr(&self) -> *const ffi::Signature { self.as_c_ptr() } + + /// Obtains a raw mutable pointer suitable for use with FFI functions + #[inline] + #[deprecated( + since = "0.25.0", + note = "Use Self::as_mut_c_ptr if you need to access the FFI layer" + )] + pub fn as_mut_ptr(&mut self) -> *mut ffi::Signature { self.as_mut_c_ptr() } + + #[inline] + /// Serializes the signature in DER format + pub fn serialize_der(&self) -> SerializedSignature { + let mut data = [0u8; serialized_signature::MAX_LEN]; + let mut len: usize = serialized_signature::MAX_LEN; + unsafe { + let err = ffi::secp256k1_ecdsa_signature_serialize_der( + ffi::secp256k1_context_no_precomp, + data.as_mut_ptr(), + &mut len, + self.as_c_ptr(), + ); + debug_assert!(err == 1); + SerializedSignature::from_raw_parts(data, len) + } + } + + #[inline] + /// Serializes the signature in compact format + pub fn serialize_compact(&self) -> [u8; 64] { + let mut ret = [0u8; 64]; + unsafe { + let err = ffi::secp256k1_ecdsa_signature_serialize_compact( + ffi::secp256k1_context_no_precomp, + ret.as_mut_c_ptr(), + self.as_c_ptr(), + ); + debug_assert!(err == 1); + } + ret + } + + /// Verifies an ECDSA signature for `msg` using `pk` and the global [`SECP256K1`] context. + /// The signature must be normalized or verification will fail (see [`Signature::normalize_s`]). + #[inline] + #[cfg(feature = "global-context")] + pub fn verify(&self, msg: impl Into, pk: &PublicKey) -> Result<(), Error> { + SECP256K1.verify_ecdsa(msg, self, pk) + } +} + +impl CPtr for Signature { + type Target = ffi::Signature; + + fn as_c_ptr(&self) -> *const Self::Target { &self.0 } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { &mut self.0 } +} + +/// Creates a new signature from a FFI signature +impl From for Signature { + #[inline] + fn from(sig: ffi::Signature) -> Signature { Signature(sig) } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for Signature { + fn serialize(&self, s: S) -> Result { + if s.is_human_readable() { + s.collect_str(self) + } else { + s.serialize_bytes(&self.serialize_der()) + } + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for Signature { + fn deserialize>(d: D) -> Result { + if d.is_human_readable() { + d.deserialize_str(crate::serde_util::FromStrVisitor::new( + "a hex string representing a DER encoded Signature", + )) + } else { + d.deserialize_bytes(crate::serde_util::BytesVisitor::new( + "raw byte stream, that represents a DER encoded Signature", + Signature::from_der, + )) + } + } +} + +impl Secp256k1 { + fn sign_ecdsa_with_noncedata_pointer( + &self, + msg: impl Into, + sk: &SecretKey, + noncedata: Option<&[u8; 32]>, + ) -> Signature { + let msg = msg.into(); + unsafe { + let mut ret = ffi::Signature::new(); + let noncedata_ptr = match noncedata { + Some(arr) => arr.as_c_ptr() as *const _, + None => ptr::null(), + }; + // We can assume the return value because it's not possible to construct + // an invalid signature from a valid `Message` and `SecretKey` + assert_eq!( + ffi::secp256k1_ecdsa_sign( + self.ctx.as_ptr(), + &mut ret, + msg.as_c_ptr(), + sk.as_c_ptr(), + ffi::secp256k1_nonce_function_rfc6979, + noncedata_ptr + ), + 1 + ); + Signature::from(ret) + } + } + + /// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce + /// Requires a signing-capable context. + pub fn sign_ecdsa(&self, msg: impl Into, sk: &SecretKey) -> Signature { + self.sign_ecdsa_with_noncedata_pointer(msg, sk, None) + } + + /// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce + /// and includes 32 bytes of noncedata in the nonce generation via inclusion in + /// one of the hash operations during nonce generation. This is useful when multiple + /// signatures are needed for the same Message and SecretKey while still using RFC6979. + /// Requires a signing-capable context. + pub fn sign_ecdsa_with_noncedata( + &self, + msg: impl Into, + sk: &SecretKey, + noncedata: &[u8; 32], + ) -> Signature { + self.sign_ecdsa_with_noncedata_pointer(msg, sk, Some(noncedata)) + } + + fn sign_grind_with_check( + &self, + msg: impl Into, + sk: &SecretKey, + check: impl Fn(&ffi::Signature) -> bool, + ) -> Signature { + let mut entropy_p: *const ffi::types::c_void = ptr::null(); + let mut counter: u32 = 0; + let mut extra_entropy = [0u8; 32]; + let msg = msg.into(); + loop { + unsafe { + let mut ret = ffi::Signature::new(); + // We can assume the return value because it's not possible to construct + // an invalid signature from a valid `Message` and `SecretKey` + assert_eq!( + ffi::secp256k1_ecdsa_sign( + self.ctx.as_ptr(), + &mut ret, + msg.as_c_ptr(), + sk.as_c_ptr(), + ffi::secp256k1_nonce_function_rfc6979, + entropy_p + ), + 1 + ); + if check(&ret) { + return Signature::from(ret); + } + + counter += 1; + extra_entropy[..4].copy_from_slice(&counter.to_le_bytes()); + entropy_p = extra_entropy.as_c_ptr().cast::(); + + // When fuzzing, these checks will usually spinloop forever, so just short-circuit them. + #[cfg(secp256k1_fuzz)] + return Signature::from(ret); + } + } + } + + /// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce + /// and "grinds" the nonce by passing extra entropy if necessary to produce + /// a signature that is less than 71 - `bytes_to_grind` bytes. The number + /// of signing operation performed by this function is exponential in the + /// number of bytes grinded. + /// Requires a signing capable context. + pub fn sign_ecdsa_grind_r( + &self, + msg: impl Into, + sk: &SecretKey, + bytes_to_grind: usize, + ) -> Signature { + let len_check = |s: &ffi::Signature| der_length_check(s, 71 - bytes_to_grind); + self.sign_grind_with_check(msg, sk, len_check) + } + + /// Constructs a signature for `msg` using the secret key `sk`, RFC6979 nonce + /// and "grinds" the nonce by passing extra entropy if necessary to produce + /// a signature that is less than 71 bytes and compatible with the low r + /// signature implementation of bitcoin core. In average, this function + /// will perform two signing operations. + /// Requires a signing capable context. + pub fn sign_ecdsa_low_r(&self, msg: impl Into, sk: &SecretKey) -> Signature { + self.sign_grind_with_check(msg, sk, compact_sig_has_zero_first_bit) + } +} + +impl Secp256k1 { + /// Checks that `sig` is a valid ECDSA signature for `msg` using the public + /// key `pubkey`. Returns `Ok(())` on success. Note that this function cannot + /// be used for Bitcoin consensus checking since there may exist signatures + /// which OpenSSL would verify but not libsecp256k1, or vice-versa. Requires a + /// verify-capable context. + /// + /// ```rust + /// # #[cfg(all(feature = "rand", feature = "std"))] { + /// # use secp256k1::{rand, Secp256k1, Message, Error}; + /// # + /// # let secp = Secp256k1::new(); + /// # let (secret_key, public_key) = secp.generate_keypair(&mut rand::thread_rng()); + /// # + /// let message = Message::from_digest_slice(&[0xab; 32]).expect("32 bytes"); + /// let sig = secp.sign_ecdsa(message, &secret_key); + /// assert_eq!(secp.verify_ecdsa(message, &sig, &public_key), Ok(())); + /// + /// let message = Message::from_digest_slice(&[0xcd; 32]).expect("32 bytes"); + /// assert_eq!(secp.verify_ecdsa(message, &sig, &public_key), Err(Error::IncorrectSignature)); + /// # } + /// ``` + #[inline] + pub fn verify_ecdsa( + &self, + msg: impl Into, + sig: &Signature, + pk: &PublicKey, + ) -> Result<(), Error> { + let msg = msg.into(); + unsafe { + if ffi::secp256k1_ecdsa_verify( + self.ctx.as_ptr(), + sig.as_c_ptr(), + msg.as_c_ptr(), + pk.as_c_ptr(), + ) == 0 + { + Err(Error::IncorrectSignature) + } else { + Ok(()) + } + } + } +} + +pub(crate) fn compact_sig_has_zero_first_bit(sig: &ffi::Signature) -> bool { + let mut compact = [0u8; 64]; + unsafe { + let err = ffi::secp256k1_ecdsa_signature_serialize_compact( + ffi::secp256k1_context_no_precomp, + compact.as_mut_c_ptr(), + sig, + ); + debug_assert!(err == 1); + } + compact[0] < 0x80 +} + +pub(crate) fn der_length_check(sig: &ffi::Signature, max_len: usize) -> bool { + let mut ser_ret = [0u8; 72]; + let mut len: usize = ser_ret.len(); + unsafe { + let err = ffi::secp256k1_ecdsa_signature_serialize_der( + ffi::secp256k1_context_no_precomp, + ser_ret.as_mut_c_ptr(), + &mut len, + sig, + ); + debug_assert!(err == 1); + } + len <= max_len +} + +#[cfg(test)] +mod tests { + use crate::ecdsa::Signature; + use crate::Scalar; + + #[test] + fn test_from_compact_min_r_and_min_s() { + // From libsecp256k1: "The signature must consist of a 32-byte big endian R value, followed + // by a 32-byte big endian S value. If R or S fall outside of [0..order-1], the encoding is + // invalid. R and S with value 0 are allowed in the encoding." + let r = Scalar::ZERO; + let s = Scalar::ZERO; + let mut bytes: [u8; 64] = [0; 64]; + bytes[..32].copy_from_slice(&r.to_be_bytes()); + bytes[32..].copy_from_slice(&s.to_be_bytes()); + + assert!(Signature::from_compact(&bytes).is_ok()) + } + + #[test] + fn test_from_compact_max_r_and_max_s() { + let r = Scalar::MAX; + let s = Scalar::MAX; + let mut bytes: [u8; 64] = [0; 64]; + bytes[..32].copy_from_slice(&r.to_be_bytes()); + bytes[32..].copy_from_slice(&s.to_be_bytes()); + + assert!(Signature::from_compact(&bytes).is_ok()) + } + + #[test] + fn test_from_compact_invalid_r() { + let r = Scalar::MAX; + let s = Scalar::MAX; + let mut bytes: [u8; 64] = [0; 64]; + bytes[..32].copy_from_slice(&r.to_be_bytes()); + bytes[32..].copy_from_slice(&s.to_be_bytes()); + bytes[31] += 1; + + assert!(Signature::from_compact(&bytes).is_err()) + } + + #[test] + fn test_from_compact_invalid_s() { + let r = Scalar::MAX; + let s = Scalar::MAX; + let mut bytes: [u8; 64] = [0; 64]; + bytes[..32].copy_from_slice(&r.to_be_bytes()); + bytes[32..].copy_from_slice(&s.to_be_bytes()); + bytes[63] += 1; + + assert!(Signature::from_compact(&bytes).is_err()) + } +} diff --git a/ark-rust-secp256k1/src/ecdsa/recovery.rs b/ark-rust-secp256k1/src/ecdsa/recovery.rs new file mode 100644 index 00000000..04aaf369 --- /dev/null +++ b/ark-rust-secp256k1/src/ecdsa/recovery.rs @@ -0,0 +1,467 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Provides a signing function that allows recovering the public key from the +//! signature. +//! + +use core::ptr; + +use self::super_ffi::CPtr; +use super::ffi as super_ffi; +use crate::ecdsa::Signature; +use crate::ffi::recovery as ffi; +use crate::{key, Error, Message, Secp256k1, Signing, Verification}; + +/// A tag used for recovering the public key from a compact signature. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum RecoveryId { + /// Signature recovery ID 0 + Zero, + /// Signature recovery ID 1 + One, + /// Signature recovery ID 2 + Two, + /// Signature recovery ID 3 + Three, +} + +impl TryFrom for RecoveryId { + type Error = Error; + #[inline] + fn try_from(id: i32) -> Result { + match id { + 0 => Ok(RecoveryId::Zero), + 1 => Ok(RecoveryId::One), + 2 => Ok(RecoveryId::Two), + 3 => Ok(RecoveryId::Three), + _ => Err(Error::InvalidRecoveryId), + } + } +} + +impl From for i32 { + #[inline] + fn from(val: RecoveryId) -> Self { + match val { + RecoveryId::Zero => 0, + RecoveryId::One => 1, + RecoveryId::Two => 2, + RecoveryId::Three => 3, + } + } +} + +/// An ECDSA signature with a recovery ID for pubkey recovery. +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Ord, PartialOrd)] +pub struct RecoverableSignature(ffi::RecoverableSignature); + +impl RecoverableSignature { + #[inline] + /// Converts a compact-encoded byte slice to a signature. This + /// representation is nonstandard and defined by the libsecp256k1 library. + pub fn from_compact(data: &[u8], recid: RecoveryId) -> Result { + if data.is_empty() { + return Err(Error::InvalidSignature); + } + + let mut ret = ffi::RecoverableSignature::new(); + + unsafe { + if data.len() != 64 { + Err(Error::InvalidSignature) + } else if ffi::secp256k1_ecdsa_recoverable_signature_parse_compact( + super_ffi::secp256k1_context_no_precomp, + &mut ret, + data.as_c_ptr(), + recid.into(), + ) == 1 + { + Ok(RecoverableSignature(ret)) + } else { + Err(Error::InvalidSignature) + } + } + } + + /// Obtains a raw pointer suitable for use with FFI functions. + #[inline] + #[deprecated(since = "0.25.0", note = "Use Self::as_c_ptr if you need to access the FFI layer")] + pub fn as_ptr(&self) -> *const ffi::RecoverableSignature { self.as_c_ptr() } + + /// Obtains a raw mutable pointer suitable for use with FFI functions. + #[inline] + #[deprecated( + since = "0.25.0", + note = "Use Self::as_mut_c_ptr if you need to access the FFI layer" + )] + pub fn as_mut_ptr(&mut self) -> *mut ffi::RecoverableSignature { self.as_mut_c_ptr() } + + #[inline] + /// Serializes the recoverable signature in compact format. + pub fn serialize_compact(&self) -> (RecoveryId, [u8; 64]) { + let mut ret = [0u8; 64]; + let mut recid = RecoveryId::Zero.into(); + unsafe { + let err = ffi::secp256k1_ecdsa_recoverable_signature_serialize_compact( + super_ffi::secp256k1_context_no_precomp, + ret.as_mut_c_ptr(), + &mut recid, + self.as_c_ptr(), + ); + assert!(err == 1); + } + (recid.try_into().expect("ffi returned invalid RecoveryId!"), ret) + } + + /// Converts a recoverable signature to a non-recoverable one (this is needed + /// for verification). + #[inline] + pub fn to_standard(&self) -> Signature { + unsafe { + let mut ret = super_ffi::Signature::new(); + let err = ffi::secp256k1_ecdsa_recoverable_signature_convert( + super_ffi::secp256k1_context_no_precomp, + &mut ret, + self.as_c_ptr(), + ); + assert!(err == 1); + Signature(ret) + } + } + + /// Determines the public key for which this [`Signature`] is valid for `msg`. Requires a + /// verify-capable context. + #[inline] + #[cfg(feature = "global-context")] + pub fn recover(&self, msg: impl Into) -> Result { + crate::SECP256K1.recover_ecdsa(msg, self) + } +} + +impl CPtr for RecoverableSignature { + type Target = ffi::RecoverableSignature; + fn as_c_ptr(&self) -> *const Self::Target { &self.0 } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { &mut self.0 } +} + +/// Creates a new recoverable signature from a FFI one. +impl From for RecoverableSignature { + #[inline] + fn from(sig: ffi::RecoverableSignature) -> RecoverableSignature { RecoverableSignature(sig) } +} + +impl Secp256k1 { + fn sign_ecdsa_recoverable_with_noncedata_pointer( + &self, + msg: impl Into, + sk: &key::SecretKey, + noncedata_ptr: *const super_ffi::types::c_void, + ) -> RecoverableSignature { + let msg = msg.into(); + let mut ret = ffi::RecoverableSignature::new(); + unsafe { + // We can assume the return value because it's not possible to construct + // an invalid signature from a valid `Message` and `SecretKey` + assert_eq!( + ffi::secp256k1_ecdsa_sign_recoverable( + self.ctx.as_ptr(), + &mut ret, + msg.as_c_ptr(), + sk.as_c_ptr(), + super_ffi::secp256k1_nonce_function_rfc6979, + noncedata_ptr + ), + 1 + ); + } + + RecoverableSignature::from(ret) + } + + /// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce + /// Requires a signing-capable context. + pub fn sign_ecdsa_recoverable( + &self, + msg: impl Into, + sk: &key::SecretKey, + ) -> RecoverableSignature { + self.sign_ecdsa_recoverable_with_noncedata_pointer(msg, sk, ptr::null()) + } + + /// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce + /// and includes 32 bytes of noncedata in the nonce generation via inclusion in + /// one of the hash operations during nonce generation. This is useful when multiple + /// signatures are needed for the same Message and SecretKey while still using RFC6979. + /// Requires a signing-capable context. + pub fn sign_ecdsa_recoverable_with_noncedata( + &self, + msg: impl Into, + sk: &key::SecretKey, + noncedata: &[u8; 32], + ) -> RecoverableSignature { + let noncedata_ptr = noncedata.as_ptr() as *const super_ffi::types::c_void; + self.sign_ecdsa_recoverable_with_noncedata_pointer(msg, sk, noncedata_ptr) + } +} + +impl Secp256k1 { + /// Determines the public key for which `sig` is a valid signature for + /// `msg`. Requires a verify-capable context. + pub fn recover_ecdsa( + &self, + msg: impl Into, + sig: &RecoverableSignature, + ) -> Result { + let msg = msg.into(); + unsafe { + let mut pk = super_ffi::PublicKey::new(); + if ffi::secp256k1_ecdsa_recover( + self.ctx.as_ptr(), + &mut pk, + sig.as_c_ptr(), + msg.as_c_ptr(), + ) != 1 + { + return Err(Error::InvalidSignature); + } + Ok(key::PublicKey::from(pk)) + } + } +} + +#[cfg(test)] +#[allow(unused_imports)] +mod tests { + #[cfg(target_arch = "wasm32")] + use wasm_bindgen_test::wasm_bindgen_test as test; + + use super::{RecoverableSignature, RecoveryId}; + use crate::constants::ONE; + use crate::{Error, Message, Secp256k1, SecretKey}; + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn capabilities() { + let sign = Secp256k1::signing_only(); + let vrfy = Secp256k1::verification_only(); + let full = Secp256k1::new(); + + let msg = crate::random_32_bytes(&mut rand::thread_rng()); + let msg = Message::from_digest_slice(&msg).unwrap(); + + // Try key generation + let (sk, pk) = full.generate_keypair(&mut rand::thread_rng()); + + // Try signing + assert_eq!(sign.sign_ecdsa_recoverable(msg, &sk), full.sign_ecdsa_recoverable(msg, &sk)); + let sigr = full.sign_ecdsa_recoverable(msg, &sk); + + // Try pk recovery + assert!(vrfy.recover_ecdsa(msg, &sigr).is_ok()); + assert!(full.recover_ecdsa(msg, &sigr).is_ok()); + + assert_eq!(vrfy.recover_ecdsa(msg, &sigr), full.recover_ecdsa(msg, &sigr)); + assert_eq!(full.recover_ecdsa(msg, &sigr), Ok(pk)); + } + + #[test] + fn recid_sanity_check() { + let one = RecoveryId::One; + assert_eq!(one, one.clone()); + } + + #[test] + #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs + #[cfg(all(feature = "rand", feature = "std"))] + #[rustfmt::skip] + fn sign() { + let mut s = Secp256k1::new(); + s.randomize(&mut rand::thread_rng()); + + let sk = SecretKey::from_slice(&ONE).unwrap(); + let msg = Message::from_digest_slice(&ONE).unwrap(); + + let sig = s.sign_ecdsa_recoverable(msg, &sk); + + assert_eq!(Ok(sig), RecoverableSignature::from_compact(&[ + 0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f, + 0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6, + 0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65, + 0xc3, 0x6d, 0xed, 0xf4, 0x09, 0x2e, 0x88, 0x98, + 0x4c, 0x1a, 0x97, 0x16, 0x52, 0xe0, 0xad, 0xa8, + 0x80, 0x12, 0x0e, 0xf8, 0x02, 0x5e, 0x70, 0x9f, + 0xff, 0x20, 0x80, 0xc4, 0xa3, 0x9a, 0xae, 0x06, + 0x8d, 0x12, 0xee, 0xd0, 0x09, 0xb6, 0x8c, 0x89], + RecoveryId::One)) + } + + #[test] + #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs + #[cfg(all(feature = "rand", feature = "std"))] + #[rustfmt::skip] + fn sign_with_noncedata() { + let mut s = Secp256k1::new(); + s.randomize(&mut rand::thread_rng()); + + let sk = SecretKey::from_slice(&ONE).unwrap(); + let msg = Message::from_digest_slice(&ONE).unwrap(); + let noncedata = [42u8; 32]; + + let sig = s.sign_ecdsa_recoverable_with_noncedata(msg, &sk, &noncedata); + + assert_eq!(Ok(sig), RecoverableSignature::from_compact(&[ + 0xb5, 0x0b, 0xb6, 0x79, 0x5f, 0x31, 0x74, 0x8a, + 0x4d, 0x37, 0xc3, 0xa9, 0x7e, 0xbd, 0x06, 0xa2, + 0x2e, 0xa3, 0x37, 0x71, 0x04, 0x0f, 0x5c, 0x05, + 0xd6, 0xe2, 0xbb, 0x2d, 0x38, 0xc6, 0x22, 0x7c, + 0x34, 0x3b, 0x66, 0x59, 0xdb, 0x96, 0x99, 0x59, + 0xd9, 0xfd, 0xdb, 0x44, 0xbd, 0x0d, 0xd9, 0xb9, + 0xdd, 0x47, 0x66, 0x6a, 0xb5, 0x28, 0x71, 0x90, + 0x1d, 0x17, 0x61, 0xeb, 0x82, 0xec, 0x87, 0x22], + RecoveryId::Zero)) + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn sign_and_verify_fail() { + let mut s = Secp256k1::new(); + s.randomize(&mut rand::thread_rng()); + + let msg = crate::random_32_bytes(&mut rand::thread_rng()); + let msg = Message::from_digest_slice(&msg).unwrap(); + + let (sk, pk) = s.generate_keypair(&mut rand::thread_rng()); + + let sigr = s.sign_ecdsa_recoverable(msg, &sk); + let sig = sigr.to_standard(); + + let msg = crate::random_32_bytes(&mut rand::thread_rng()); + let msg = Message::from_digest_slice(&msg).unwrap(); + assert_eq!(s.verify_ecdsa(msg, &sig, &pk), Err(Error::IncorrectSignature)); + + let recovered_key = s.recover_ecdsa(msg, &sigr).unwrap(); + assert!(recovered_key != pk); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn sign_with_recovery() { + let mut s = Secp256k1::new(); + s.randomize(&mut rand::thread_rng()); + + let msg = crate::random_32_bytes(&mut rand::thread_rng()); + let msg = Message::from_digest_slice(&msg).unwrap(); + + let (sk, pk) = s.generate_keypair(&mut rand::thread_rng()); + + let sig = s.sign_ecdsa_recoverable(msg, &sk); + + assert_eq!(s.recover_ecdsa(msg, &sig), Ok(pk)); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn sign_with_recovery_and_noncedata() { + let mut s = Secp256k1::new(); + s.randomize(&mut rand::thread_rng()); + + let msg = crate::random_32_bytes(&mut rand::thread_rng()); + let msg = Message::from_digest_slice(&msg).unwrap(); + + let noncedata = [42u8; 32]; + + let (sk, pk) = s.generate_keypair(&mut rand::thread_rng()); + + let sig = s.sign_ecdsa_recoverable_with_noncedata(msg, &sk, &noncedata); + + assert_eq!(s.recover_ecdsa(msg, &sig), Ok(pk)); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn bad_recovery() { + let mut s = Secp256k1::new(); + s.randomize(&mut rand::thread_rng()); + + let msg = Message::from_digest_slice(&[0x55; 32]).unwrap(); + + // Zero is not a valid sig + let sig = RecoverableSignature::from_compact(&[0; 64], RecoveryId::Zero).unwrap(); + assert_eq!(s.recover_ecdsa(msg, &sig), Err(Error::InvalidSignature)); + // ...but 111..111 is + let sig = RecoverableSignature::from_compact(&[1; 64], RecoveryId::Zero).unwrap(); + assert!(s.recover_ecdsa(msg, &sig).is_ok()); + } + + #[test] + fn test_debug_output() { + #[rustfmt::skip] + let sig = RecoverableSignature::from_compact(&[ + 0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f, + 0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6, + 0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65, + 0xc3, 0x6d, 0xed, 0xf4, 0x09, 0x2e, 0x88, 0x98, + 0x4c, 0x1a, 0x97, 0x16, 0x52, 0xe0, 0xad, 0xa8, + 0x80, 0x12, 0x0e, 0xf8, 0x02, 0x5e, 0x70, 0x9f, + 0xff, 0x20, 0x80, 0xc4, 0xa3, 0x9a, 0xae, 0x06, + 0x8d, 0x12, 0xee, 0xd0, 0x09, 0xb6, 0x8c, 0x89], + RecoveryId::One).unwrap(); + assert_eq!(&format!("{:?}", sig), "RecoverableSignature(6673ffad2147741f04772b6f921f0ba6af0c1e77fc439e65c36dedf4092e88984c1a971652e0ada880120ef8025e709fff2080c4a39aae068d12eed009b68c8901)"); + } + + #[test] + fn test_recov_sig_serialize_compact() { + let recid_in = RecoveryId::One; + #[rustfmt::skip] + let bytes_in = &[ + 0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f, + 0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6, + 0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65, + 0xc3, 0x6d, 0xed, 0xf4, 0x09, 0x2e, 0x88, 0x98, + 0x4c, 0x1a, 0x97, 0x16, 0x52, 0xe0, 0xad, 0xa8, + 0x80, 0x12, 0x0e, 0xf8, 0x02, 0x5e, 0x70, 0x9f, + 0xff, 0x20, 0x80, 0xc4, 0xa3, 0x9a, 0xae, 0x06, + 0x8d, 0x12, 0xee, 0xd0, 0x09, 0xb6, 0x8c, 0x89]; + let sig = RecoverableSignature::from_compact(bytes_in, recid_in).unwrap(); + let (recid_out, bytes_out) = sig.serialize_compact(); + assert_eq!(recid_in, recid_out); + assert_eq!(&bytes_in[..], &bytes_out[..]); + } + + #[test] + fn test_recov_id_conversion_between_i32() { + assert!(RecoveryId::try_from(-1i32).is_err()); + assert!(RecoveryId::try_from(0i32).is_ok()); + assert!(RecoveryId::try_from(1i32).is_ok()); + assert!(RecoveryId::try_from(2i32).is_ok()); + assert!(RecoveryId::try_from(3i32).is_ok()); + assert!(RecoveryId::try_from(4i32).is_err()); + let id0 = RecoveryId::Zero; + assert_eq!(Into::::into(id0), 0i32); + let id1 = RecoveryId::One; + assert_eq!(Into::::into(id1), 1i32); + } +} + +#[cfg(bench)] +#[cfg(all(feature = "rand", feature = "std"))] // Currently only a single bench that requires "rand" + "std". +mod benches { + use test::{black_box, Bencher}; + + use super::{Message, Secp256k1}; + + #[bench] + pub fn bench_recover(bh: &mut Bencher) { + let s = Secp256k1::new(); + let msg = crate::random_32_bytes(&mut rand::thread_rng()); + let msg = Message::from_digest_slice(&msg).unwrap(); + let (sk, _) = s.generate_keypair(&mut rand::thread_rng()); + let sig = s.sign_ecdsa_recoverable(&msg, &sk); + + bh.iter(|| { + let res = s.recover_ecdsa(&msg, &sig).unwrap(); + black_box(res); + }); + } +} diff --git a/ark-rust-secp256k1/src/ecdsa/serialized_signature.rs b/ark-rust-secp256k1/src/ecdsa/serialized_signature.rs new file mode 100644 index 00000000..f8be36a2 --- /dev/null +++ b/ark-rust-secp256k1/src/ecdsa/serialized_signature.rs @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Implements [`SerializedSignature`] and related types. +//! +//! DER-serialized signatures have the issue that they can have different lengths. +//! We want to avoid using `Vec` since that would require allocations making the code slower and +//! unable to run on platforms without allocator. We implement a special type to encapsulate +//! serialized signatures and since it's a bit more complicated it has its own module. + +use core::borrow::Borrow; +use core::{fmt, ops}; + +pub use into_iter::IntoIter; + +use super::Signature; +use crate::Error; + +pub(crate) const MAX_LEN: usize = 72; + +/// A DER serialized Signature +#[derive(Copy, Clone)] +pub struct SerializedSignature { + data: [u8; MAX_LEN], + len: usize, +} + +impl fmt::Debug for SerializedSignature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } +} + +impl fmt::Display for SerializedSignature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for v in self { + write!(f, "{:02x}", v)?; + } + Ok(()) + } +} + +impl PartialEq for SerializedSignature { + #[inline] + fn eq(&self, other: &SerializedSignature) -> bool { **self == **other } +} + +impl PartialEq<[u8]> for SerializedSignature { + #[inline] + fn eq(&self, other: &[u8]) -> bool { **self == *other } +} + +impl PartialEq for [u8] { + #[inline] + fn eq(&self, other: &SerializedSignature) -> bool { *self == **other } +} + +impl PartialOrd for SerializedSignature { + fn partial_cmp(&self, other: &SerializedSignature) -> Option { + Some((**self).cmp(&**other)) + } +} + +impl Ord for SerializedSignature { + fn cmp(&self, other: &SerializedSignature) -> core::cmp::Ordering { (**self).cmp(&**other) } +} + +impl PartialOrd<[u8]> for SerializedSignature { + fn partial_cmp(&self, other: &[u8]) -> Option { + (**self).partial_cmp(other) + } +} + +impl PartialOrd for [u8] { + fn partial_cmp(&self, other: &SerializedSignature) -> Option { + self.partial_cmp(&**other) + } +} + +impl core::hash::Hash for SerializedSignature { + fn hash(&self, state: &mut H) { (**self).hash(state) } +} + +impl AsRef<[u8]> for SerializedSignature { + #[inline] + fn as_ref(&self) -> &[u8] { self } +} + +impl Borrow<[u8]> for SerializedSignature { + #[inline] + fn borrow(&self) -> &[u8] { self } +} + +impl ops::Deref for SerializedSignature { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { &self.data[..self.len] } +} + +impl Eq for SerializedSignature {} + +impl IntoIterator for SerializedSignature { + type IntoIter = IntoIter; + type Item = u8; + + #[inline] + fn into_iter(self) -> Self::IntoIter { IntoIter::new(self) } +} + +impl<'a> IntoIterator for &'a SerializedSignature { + type IntoIter = core::slice::Iter<'a, u8>; + type Item = &'a u8; + + #[inline] + fn into_iter(self) -> Self::IntoIter { self.iter() } +} + +impl From for SerializedSignature { + fn from(value: Signature) -> Self { Self::from_signature(&value) } +} + +impl<'a> From<&'a Signature> for SerializedSignature { + fn from(value: &'a Signature) -> Self { Self::from_signature(value) } +} + +impl TryFrom for Signature { + type Error = Error; + + fn try_from(value: SerializedSignature) -> Result { value.to_signature() } +} + +impl<'a> TryFrom<&'a SerializedSignature> for Signature { + type Error = Error; + + fn try_from(value: &'a SerializedSignature) -> Result { + value.to_signature() + } +} + +impl SerializedSignature { + /// Creates `SerializedSignature` from data and length. + /// + /// ## Panics + /// + /// If `len` > `MAX_LEN` + #[inline] + pub(crate) fn from_raw_parts(data: [u8; MAX_LEN], len: usize) -> Self { + assert!(len <= MAX_LEN, "attempt to set length to {} but the maximum is {}", len, MAX_LEN); + SerializedSignature { data, len } + } + + /// Get the capacity of the underlying data buffer. + #[deprecated = "This always returns 72"] + #[inline] + pub fn capacity(&self) -> usize { self.data.len() } + + /// Get the len of the used data. + #[inline] + pub fn len(&self) -> usize { self.len } + + /// Set the length of the object. + #[inline] + pub(crate) fn set_len_unchecked(&mut self, len: usize) { self.len = len; } + + /// Convert the serialized signature into the Signature struct. + /// (This DER deserializes it) + #[inline] + pub fn to_signature(&self) -> Result { Signature::from_der(self) } + + /// Create a SerializedSignature from a Signature. + /// (this DER serializes it) + #[inline] + pub fn from_signature(sig: &Signature) -> SerializedSignature { sig.serialize_der() } + + /// Check if the space is zero. + #[deprecated = "This always returns false"] + #[inline] + pub fn is_empty(&self) -> bool { self.len() == 0 } +} + +/// Separate mod to prevent outside code accidentally breaking invariants. +mod into_iter { + use super::*; + + /// Owned iterator over the bytes of [`SerializedSignature`] + /// + /// Created by [`IntoIterator::into_iter`] method. + // allowed because of https://github.com/rust-lang/rust/issues/98348 + #[allow(missing_copy_implementations)] + #[derive(Debug, Clone)] + pub struct IntoIter { + signature: SerializedSignature, + // invariant: pos <= signature.len() + pos: usize, + } + + impl IntoIter { + #[inline] + pub(crate) fn new(signature: SerializedSignature) -> Self { + IntoIter { + signature, + // for all unsigned n: 0 <= n + pos: 0, + } + } + + /// Returns the remaining bytes as a slice. + /// + /// This method is analogous to [`core::slice::Iter::as_slice`]. + #[inline] + pub fn as_slice(&self) -> &[u8] { &self.signature[self.pos..] } + } + + impl Iterator for IntoIter { + type Item = u8; + + #[inline] + fn next(&mut self) -> Option { + let byte = *self.signature.get(self.pos)?; + // can't overflow or break invariant because if pos is too large we return early + self.pos += 1; + Some(byte) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + // can't underlflow thanks to the invariant + let len = self.signature.len() - self.pos; + (len, Some(len)) + } + + // override for speed + #[inline] + fn nth(&mut self, n: usize) -> Option { + if n >= self.len() { + // upholds invariant becasue the values will be equal + self.pos = self.signature.len(); + None + } else { + // if n < signtature.len() - self.pos then n + self.pos < signature.len() which neither + // overflows nor breaks the invariant + self.pos += n; + self.next() + } + } + } + + impl ExactSizeIterator for IntoIter {} + + impl core::iter::FusedIterator for IntoIter {} + + impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + if self.pos == self.signature.len() { + return None; + } + + // if len is 0 then pos is also 0 thanks to the invariant so we would return before we + // reach this + let new_len = self.signature.len() - 1; + let byte = self.signature[new_len]; + self.signature.set_len_unchecked(new_len); + Some(byte) + } + } +} + +#[cfg(test)] +mod tests { + use super::{SerializedSignature, MAX_LEN}; + + #[test] + fn iterator_ops_are_homomorphic() { + let mut fake_signature_data = [0; MAX_LEN]; + for (i, byte) in fake_signature_data.iter_mut().enumerate() { + *byte = i as u8; // cast ok because MAX_LEN fits in u8. + } + + let fake_signature = SerializedSignature { data: fake_signature_data, len: MAX_LEN }; + + let mut iter1 = fake_signature.into_iter(); + let mut iter2 = fake_signature.iter(); + + // while let so we can compare size_hint and as_slice + while let (Some(a), Some(b)) = (iter1.next(), iter2.next()) { + assert_eq!(a, *b); + assert_eq!(iter1.size_hint(), iter2.size_hint()); + assert_eq!(iter1.as_slice(), iter2.as_slice()); + } + + let mut iter1 = fake_signature.into_iter(); + let mut iter2 = fake_signature.iter(); + + // manual next_back instead of rev() so that we can check as_slice() + // if next_back is implemented correctly then rev() is also correct - provided by `core` + while let (Some(a), Some(b)) = (iter1.next_back(), iter2.next_back()) { + assert_eq!(a, *b); + assert_eq!(iter1.size_hint(), iter2.size_hint()); + assert_eq!(iter1.as_slice(), iter2.as_slice()); + } + } +} diff --git a/ark-rust-secp256k1/src/ellswift.rs b/ark-rust-secp256k1/src/ellswift.rs new file mode 100644 index 00000000..c3007f34 --- /dev/null +++ b/ark-rust-secp256k1/src/ellswift.rs @@ -0,0 +1,744 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! This module provides an implementation of ElligatorSwift as well as a +//! version of x-only ECDH using it (including compatibility with BIP324). +//! +//! `ElligatorSwift` is described in `https://eprint.iacr.org/2022/759` by +//! Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding +//! uniformly chosen public keys as 64-byte arrays which are indistinguishable +//! from uniformly random arrays. +//! +//! Let f be the function from pairs of field elements to point X coordinates, +//! defined as follows (all operations modulo p = 2^256 - 2^32 - 977) +//! f(u,t): +//! - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852, +//! a square root of -3. +//! - If u=0, set u=1 instead. +//! - If t=0, set t=1 instead. +//! - If u^3 + t^2 + 7 = 0, multiply t by 2. +//! - Let X = (u^3 + 7 - t^2) / (2 * t) +//! - Let Y = (X + t) / (C * u) +//! - Return the first in [u + 4 * Y^2, (-X/Y - u) / 2, (X/Y - u) / 2] that is an +//! X coordinate on the curve (at least one of them is, for any u and t). +//! +//! Then an `ElligatorSwift` encoding of x consists of the 32-byte big-endian +//! encodings of field elements u and t concatenated, where f(u,t) = x. +//! The encoding algorithm is described in the paper, and effectively picks a +//! uniformly random pair (u,t) among those which encode x. +//! +//! If the Y coordinate is relevant, it is given the same parity as t. +//! +//! Changes w.r.t. the paper: +//! - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point +//! at infinity in the paper. Here they are remapped to finite points. +//! - The paper uses an additional encoding bit for the parity of y. Here the +//! parity of t is used (negating t does not affect the decoded x coordinate, +//! so this is possible). + +use core::fmt::{self, Display, Formatter}; +use core::ptr; +use core::str::FromStr; + +use ffi::CPtr; +use secp256k1_sys::types::{c_int, c_uchar, c_void}; + +use crate::{constants, ffi, from_hex, Error, PublicKey, Secp256k1, SecretKey, Verification}; + +unsafe extern "C" fn hash_callback( + output: *mut c_uchar, + x32: *const c_uchar, + ell_a64: *const c_uchar, + ell_b64: *const c_uchar, + hash_func: *mut c_void, +) -> c_int +where + F: FnMut([u8; 32], [u8; 64], [u8; 64]) -> ElligatorSwiftSharedSecret, +{ + let callback: &mut F = &mut *(hash_func as *mut F); + let mut x32_array = [0u8; 32]; + let mut ell_a64_array = [0u8; 64]; + let mut ell_b64_array = [0u8; 64]; + + // Copy the data into Rust slices + ptr::copy_nonoverlapping(x32, x32_array.as_mut_c_ptr(), 32); + ptr::copy_nonoverlapping(ell_a64, ell_a64_array.as_mut_c_ptr(), 64); + ptr::copy_nonoverlapping(ell_b64, ell_b64_array.as_mut_c_ptr(), 64); + // Call the hash function that was passed in through the `data` pointer + let secret = callback(x32_array, ell_a64_array, ell_b64_array); + // Copy the output from a [ElligatorSwiftSharedSecret] into the output pointer + ptr::copy_nonoverlapping(secret.0.as_ptr(), output, secret.0.len()); + // Always returns 1 + 1 +} + +/// An encoding of an elliptic curvepoint such that a uniformly random on-curve +/// point will be encoded as uniformly random bits. +/// +/// This object holds two field elements u and t, which are the inputs to +/// the `ElligatorSwift` encoding function. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ElligatorSwift(ffi::ElligatorSwift); + +impl ElligatorSwift { + /// Create a new `ElligatorSwift` object from a 64-byte array. + pub fn new(secret_key: SecretKey, rand: [u8; 32]) -> ElligatorSwift { + let mut ell_out = [0u8; constants::ELLSWIFT_ENCODING_SIZE]; + unsafe { + let ret = ffi::secp256k1_ellswift_create( + ffi::secp256k1_context_no_precomp, + ell_out.as_mut_c_ptr(), + secret_key.as_c_ptr(), + rand.as_ptr(), + ); + debug_assert_eq!(ret, 1); + } + ElligatorSwift(ffi::ElligatorSwift::from_array(ell_out)) + } + + /// Creates an `ElligatorSwift` object from a 64-byte array. + pub fn from_array(ellswift: [u8; 64]) -> ElligatorSwift { + ElligatorSwift(ffi::ElligatorSwift::from_array(ellswift)) + } + + /// Returns the 64-byte array representation of this `ElligatorSwift` object. + pub fn to_array(&self) -> [u8; 64] { self.0.to_array() } + + /// Creates the Elligator Swift encoding from a secret key, using some aux_rand if defined. + /// This method is preferred instead of just decoding, because the private key offers extra + /// entropy. + /// # Example + /// ``` + /// # #[cfg(feature = "alloc")] { + /// use secp256k1::{ellswift::ElligatorSwift, PublicKey, Secp256k1, SecretKey}; + /// let secp = Secp256k1::new(); + /// let sk = SecretKey::from_slice(&[1; 32]).unwrap(); + /// let es = ElligatorSwift::from_seckey(&secp, sk, None); + /// # } + /// ``` + pub fn from_seckey( + secp: &Secp256k1, + sk: SecretKey, + aux_rand: Option<[u8; 32]>, + ) -> ElligatorSwift { + let mut es_out = [0u8; constants::ELLSWIFT_ENCODING_SIZE]; + let aux_rand_ptr = aux_rand.as_c_ptr(); + unsafe { + let ret = ffi::secp256k1_ellswift_create( + secp.ctx().as_ptr(), + es_out.as_mut_c_ptr(), + sk.as_c_ptr(), + aux_rand_ptr, + ); + debug_assert_eq!(ret, 1); + } + ElligatorSwift(ffi::ElligatorSwift::from_array(es_out)) + } + + /// Computes the `ElligatorSwift` encoding for a valid public key + /// # Example + /// ``` + /// # #[cfg(feature = "alloc")] { + /// use secp256k1::{ellswift::ElligatorSwift, PublicKey, Secp256k1, SecretKey}; + /// let secp = Secp256k1::new(); + /// let sk = SecretKey::from_slice(&[1; 32]).unwrap(); + /// let pk = PublicKey::from_secret_key(&secp, &sk); + /// let es = ElligatorSwift::from_pubkey(pk); + /// # } + /// + /// ``` + pub fn from_pubkey(pk: PublicKey) -> ElligatorSwift { Self::encode(pk) } + + /// Computes a shared secret only known by Alice and Bob. This is obtained by computing + /// the x-only Elliptic Curve Diffie-Hellman (ECDH) shared secret between Alice and Bob. + /// # Example + /// ``` + /// # #[cfg(feature = "alloc")] { + /// use secp256k1::{ + /// ellswift::{ElligatorSwift, Party}, + /// PublicKey, SecretKey, XOnlyPublicKey, Secp256k1, + /// }; + /// use core::str::FromStr; + /// + /// let secp = Secp256k1::new(); + /// + /// let alice_sk = SecretKey::from_str("e714e76bdd67ad9f495683c37934148f4efc25ce3f01652c8a906498339e1f3a").unwrap(); + /// let bob_sk = SecretKey::from_str("b6c4b0e2f8c4359caf356a618cd1649d18790a1d67f7c2d1e4760e04c785db4f").unwrap(); + /// + /// let alice_es = ElligatorSwift::from_seckey(&secp, alice_sk, None); + /// let bob_es = ElligatorSwift::from_seckey(&secp, bob_sk, None); + /// + /// let alice_shared_secret = ElligatorSwift::shared_secret(alice_es, bob_es, alice_sk, Party::Initiator, None); + /// let bob_shared_secret = ElligatorSwift::shared_secret(alice_es, bob_es, bob_sk, Party::Responder, None); + /// + /// assert_eq!(alice_shared_secret, bob_shared_secret); + /// # } + /// ``` + pub fn shared_secret( + ellswift_a: ElligatorSwift, + ellswift_b: ElligatorSwift, + secret_key: SecretKey, + party: impl Into, + data: Option<&[u8]>, + ) -> ElligatorSwiftSharedSecret { + let mut shared_secret = [0u8; 32]; + let p: Party = party.into(); + unsafe { + let ret = ffi::secp256k1_ellswift_xdh( + ffi::secp256k1_context_no_precomp, + shared_secret.as_mut_c_ptr(), + ellswift_a.as_c_ptr(), + ellswift_b.as_c_ptr(), + secret_key.as_c_ptr(), + p.to_ffi_int(), + ffi::secp256k1_ellswift_xdh_hash_function_bip324, + data.as_c_ptr() as *mut c_void, + ); + debug_assert_eq!(ret, 1); + } + ElligatorSwiftSharedSecret(shared_secret) + } + + /// Computes a shared secret, just like `shared_secret`, but with a custom hash function + /// for computing the shared secret. For compatibility with other libraries, you should + /// use `shared_secret` instead, which is already compatible with BIP324. + /// The hash function takes three arguments: the shared point, and the `ElligatorSwift` + /// encodings of the two parties and returns a 32-byte shared secret. + pub fn shared_secret_with_hasher( + ellswift_a: ElligatorSwift, + ellswift_b: ElligatorSwift, + secret_key: SecretKey, + party: impl Into, + mut hash_function: F, + ) -> ElligatorSwiftSharedSecret + where + F: FnMut([u8; 32], [u8; 64], [u8; 64]) -> ElligatorSwiftSharedSecret, + { + let mut shared_secret = [0u8; 32]; + let hashfp = hash_callback::; + let p: Party = party.into(); + unsafe { + let ret = ffi::secp256k1_ellswift_xdh( + ffi::secp256k1_context_no_precomp, + shared_secret.as_mut_c_ptr(), + ellswift_a.0.as_c_ptr(), + ellswift_b.0.as_c_ptr(), + secret_key.as_c_ptr(), + p.to_ffi_int(), + Some(hashfp), + &mut hash_function as *mut F as *mut c_void, + ); + debug_assert_eq!(ret, 1); + } + ElligatorSwiftSharedSecret(shared_secret) + } + + /// Encodes a public key into an `ElligatorSwift` encoding + fn encode(pk: PublicKey) -> ElligatorSwift { + let mut ell_out = [0u8; constants::ELLSWIFT_ENCODING_SIZE]; + unsafe { + let ret = ffi::secp256k1_ellswift_encode( + ffi::secp256k1_context_no_precomp, + ell_out.as_mut_c_ptr(), + pk.as_c_ptr(), + [0u8; 32].as_ptr(), + ); + debug_assert_eq!(ret, 1); + } + ElligatorSwift(ffi::ElligatorSwift::from_array(ell_out)) + } + + /// Decodes an `ElligatorSwift` encoding into a [`PublicKey`]. + pub(crate) fn decode(ell: ElligatorSwift) -> PublicKey { + unsafe { + let mut pk = ffi::PublicKey::new(); + + let ret = ffi::secp256k1_ellswift_decode( + ffi::secp256k1_context_no_precomp, + pk.as_mut_c_ptr(), + ell.as_c_ptr(), + ); + debug_assert_eq!(ret, 1); + PublicKey::from(pk) + } + } +} + +/// The result of `ElligatorSwift::shared_secret`, which is a shared secret +/// computed from the x-only ECDH using both parties' public keys (`ElligatorSwift` encoded) and our own +/// private key. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ElligatorSwiftSharedSecret([u8; 32]); + +impl ElligatorSwiftSharedSecret { + /// Creates shared secret from bytes. + /// + /// This is generally not needed except for unusual cases like restoring the secret from a + /// database. + pub const fn from_secret_bytes(bytes: [u8; 32]) -> Self { Self(bytes) } + + /// Returns the secret bytes as an array. + pub const fn to_secret_bytes(self) -> [u8; 32] { self.0 } + + /// Returns the secret bytes as a reference to an array. + pub const fn as_secret_bytes(&self) -> &[u8; 32] { &self.0 } +} + +/// Represents which party we are in the ECDH. +/// +/// Here `A` is the initiator and `B` is the responder. +/// +/// this context, "we" means the party that possesses the secret key passed to +/// [`ElligatorSwift::shared_secret`]. +/// +/// This distinction is important because the different parties compute different +/// hashes of the shared secret. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[deprecated(since = "0.30.0", note = "Use `Party` instead.")] +pub enum ElligatorSwiftParty { + /// We are the initiator of the ECDH + A, + /// We are the responder of the ECDH + B, +} + +/// Represents the two parties in ECDH +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Party { + /// The party that starts the key exchange or communication process + Initiator, + /// The party that responds to the initiator's communications + Responder, +} + +#[allow(deprecated)] +impl From for Party { + fn from(value: ElligatorSwiftParty) -> Self { + match value { + ElligatorSwiftParty::A => Party::Initiator, + ElligatorSwiftParty::B => Party::Responder, + } + } +} + +impl Party { + fn to_ffi_int(self) -> c_int { + match self { + Party::Initiator => 0, + Party::Responder => 1, + } + } +} + +impl FromStr for ElligatorSwift { + fn from_str(hex: &str) -> Result { + let mut ser = [0u8; 64]; + let parsed = from_hex(hex, &mut ser); + match parsed { + Ok(64) => Ok(ElligatorSwift::from_array(ser)), + _ => Err(Error::InvalidEllSwift), + } + } + type Err = Error; +} + +impl fmt::LowerHex for ElligatorSwift { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let ser = self.to_array(); + for ch in ser.iter() { + write!(f, "{:02x}", ch)?; + } + Ok(()) + } +} + +impl Display for ElligatorSwift { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { core::fmt::LowerHex::fmt(&self, f) } +} + +impl ffi::CPtr for ElligatorSwift { + type Target = u8; + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.0.as_mut_c_ptr() } + fn as_c_ptr(&self) -> *const Self::Target { self.0.as_c_ptr() } +} + +#[cfg(test)] +mod tests { + use core::str::FromStr; + + use crate::ellswift::ElligatorSwift; + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + use crate::ellswift::{ElligatorSwiftSharedSecret, Party}; + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + use crate::SecretKey; + use crate::{from_hex, PublicKey, XOnlyPublicKey}; + + #[test] + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + fn test_elligator_swift_rtt() { + // Test that we can round trip an ElligatorSwift encoding + let secp = crate::Secp256k1::new(); + let public_key = + PublicKey::from_secret_key(&secp, &SecretKey::from_slice(&[1u8; 32]).unwrap()); + + let ell = ElligatorSwift::from_pubkey(public_key); + let pk = PublicKey::from_ellswift(ell); + assert_eq!(pk, public_key); + } + #[test] + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + fn test_create_elligator_swift_create_rtt() { + // Test that we can round trip an ElligatorSwift created from a secret key + let secp = crate::Secp256k1::new(); + let rand32 = [1u8; 32]; + let priv32 = [1u8; 32]; + let ell = ElligatorSwift::from_seckey(&secp, SecretKey::from_slice(&rand32).unwrap(), None); + let pk = PublicKey::from_ellswift(ell); + let expected = PublicKey::from_secret_key(&secp, &SecretKey::from_slice(&priv32).unwrap()); + + assert_eq!(pk, expected); + } + #[test] + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + fn test_xdh_with_custom_hasher() { + // Test the ECDH with a custom hash function + let secp = crate::Secp256k1::new(); + let rand32 = [1u8; 32]; + let priv32 = [2u8; 32]; + let ell = ElligatorSwift::from_seckey( + &secp, + SecretKey::from_slice(&rand32).unwrap(), + Some(rand32), + ); + let pk = ElligatorSwift::shared_secret_with_hasher( + ell, + ell, + SecretKey::from_slice(&priv32).unwrap(), + Party::Initiator, + |_, _, _| ElligatorSwiftSharedSecret([0xff; 32]), + ); + assert_eq!(pk, ElligatorSwiftSharedSecret([0xff; 32])); + } + #[test] + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + fn ellswift_ecdh_test() { + let tests = vec![ + ( + [ + 0x61, 0x06, 0x2e, 0xa5, 0x07, 0x1d, 0x80, 0x0b, 0xbf, 0xd5, 0x9e, 0x2e, 0x8b, + 0x53, 0xd4, 0x7d, 0x19, 0x4b, 0x09, 0x5a, 0xe5, 0xa4, 0xdf, 0x04, 0x93, 0x6b, + 0x49, 0x77, 0x2e, 0xf0, 0xd4, 0xd7, + ], + [ + 0xec, 0x0a, 0xdf, 0xf2, 0x57, 0xbb, 0xfe, 0x50, 0x0c, 0x18, 0x8c, 0x80, 0xb4, + 0xfd, 0xd6, 0x40, 0xf6, 0xb4, 0x5a, 0x48, 0x2b, 0xbc, 0x15, 0xfc, 0x7c, 0xef, + 0x59, 0x31, 0xde, 0xff, 0x0a, 0xa1, 0x86, 0xf6, 0xeb, 0x9b, 0xba, 0x7b, 0x85, + 0xdc, 0x4d, 0xcc, 0x28, 0xb2, 0x87, 0x22, 0xde, 0x1e, 0x3d, 0x91, 0x08, 0xb9, + 0x85, 0xe2, 0x96, 0x70, 0x45, 0x66, 0x8f, 0x66, 0x09, 0x8e, 0x47, 0x5b, + ], + [ + 0xa4, 0xa9, 0x4d, 0xfc, 0xe6, 0x9b, 0x4a, 0x2a, 0x0a, 0x09, 0x93, 0x13, 0xd1, + 0x0f, 0x9f, 0x7e, 0x7d, 0x64, 0x9d, 0x60, 0x50, 0x1c, 0x9e, 0x1d, 0x27, 0x4c, + 0x30, 0x0e, 0x0d, 0x89, 0xaa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xaf, 0x88, 0xd5, + ], + 1, + [ + 0xc6, 0x99, 0x2a, 0x11, 0x7f, 0x5e, 0xdb, 0xea, 0x70, 0xc3, 0xf5, 0x11, 0xd3, + 0x2d, 0x26, 0xb9, 0x79, 0x8b, 0xe4, 0xb8, 0x1a, 0x62, 0xea, 0xee, 0x1a, 0x5a, + 0xca, 0xa8, 0x45, 0x9a, 0x35, 0x92, + ], + ), + ( + [ + 0x1f, 0x9c, 0x58, 0x1b, 0x35, 0x23, 0x18, 0x38, 0xf0, 0xf1, 0x7c, 0xf0, 0xc9, + 0x79, 0x83, 0x5b, 0xac, 0xcb, 0x7f, 0x3a, 0xbb, 0xbb, 0x96, 0xff, 0xcc, 0x31, + 0x8a, 0xb7, 0x1e, 0x6e, 0x12, 0x6f, + ], + [ + 0xa1, 0x85, 0x5e, 0x10, 0xe9, 0x4e, 0x00, 0xba, 0xa2, 0x30, 0x41, 0xd9, 0x16, + 0xe2, 0x59, 0xf7, 0x04, 0x4e, 0x49, 0x1d, 0xa6, 0x17, 0x12, 0x69, 0x69, 0x47, + 0x63, 0xf0, 0x18, 0xc7, 0xe6, 0x36, 0x93, 0xd2, 0x95, 0x75, 0xdc, 0xb4, 0x64, + 0xac, 0x81, 0x6b, 0xaa, 0x1b, 0xe3, 0x53, 0xba, 0x12, 0xe3, 0x87, 0x6c, 0xba, + 0x76, 0x28, 0xbd, 0x0b, 0xd8, 0xe7, 0x55, 0xe7, 0x21, 0xeb, 0x01, 0x40, + ], + [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + 0, + [ + 0xa0, 0x13, 0x8f, 0x56, 0x4f, 0x74, 0xd0, 0xad, 0x70, 0xbc, 0x33, 0x7d, 0xac, + 0xc9, 0xd0, 0xbf, 0x1d, 0x23, 0x49, 0x36, 0x4c, 0xaf, 0x11, 0x88, 0xa1, 0xe6, + 0xe8, 0xdd, 0xb3, 0xb7, 0xb1, 0x84, + ], + ), + ( + [ + 0x02, 0x86, 0xc4, 0x1c, 0xd3, 0x09, 0x13, 0xdb, 0x0f, 0xdf, 0xf7, 0xa6, 0x4e, + 0xbd, 0xa5, 0xc8, 0xe3, 0xe7, 0xce, 0xf1, 0x0f, 0x2a, 0xeb, 0xc0, 0x0a, 0x76, + 0x50, 0x44, 0x3c, 0xf4, 0xc6, 0x0d, + ], + [ + 0xd1, 0xee, 0x8a, 0x93, 0xa0, 0x11, 0x30, 0xcb, 0xf2, 0x99, 0x24, 0x9a, 0x25, + 0x8f, 0x94, 0xfe, 0xb5, 0xf4, 0x69, 0xe7, 0xd0, 0xf2, 0xf2, 0x8f, 0x69, 0xee, + 0x5e, 0x9a, 0xa8, 0xf9, 0xb5, 0x4a, 0x60, 0xf2, 0xc3, 0xff, 0x2d, 0x02, 0x36, + 0x34, 0xec, 0x7f, 0x41, 0x27, 0xa9, 0x6c, 0xc1, 0x16, 0x62, 0xe4, 0x02, 0x89, + 0x4c, 0xf1, 0xf6, 0x94, 0xfb, 0x9a, 0x7e, 0xaa, 0x5f, 0x1d, 0x92, 0x44, + ], + [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x22, 0xd5, 0xe4, 0x41, 0x52, 0x4d, 0x57, 0x1a, 0x52, 0xb3, 0xde, + 0xf1, 0x26, 0x18, 0x9d, 0x3f, 0x41, 0x68, 0x90, 0xa9, 0x9d, 0x4d, 0xa6, 0xed, + 0xe2, 0xb0, 0xcd, 0xe1, 0x76, 0x0c, 0xe2, 0xc3, 0xf9, 0x84, 0x57, 0xae, + ], + 1, + [ + 0x25, 0x0b, 0x93, 0x57, 0x0d, 0x41, 0x11, 0x49, 0x10, 0x5a, 0xb8, 0xcb, 0x0b, + 0xc5, 0x07, 0x99, 0x14, 0x90, 0x63, 0x06, 0x36, 0x8c, 0x23, 0xe9, 0xd7, 0x7c, + 0x2a, 0x33, 0x26, 0x5b, 0x99, 0x4c, + ], + ), + ( + [ + 0x6c, 0x77, 0x43, 0x2d, 0x1f, 0xda, 0x31, 0xe9, 0xf9, 0x42, 0xf8, 0xaf, 0x44, + 0x60, 0x7e, 0x10, 0xf3, 0xad, 0x38, 0xa6, 0x5f, 0x8a, 0x4b, 0xdd, 0xae, 0x82, + 0x3e, 0x5e, 0xff, 0x90, 0xdc, 0x38, + ], + [ + 0xd2, 0x68, 0x50, 0x70, 0xc1, 0xe6, 0x37, 0x6e, 0x63, 0x3e, 0x82, 0x52, 0x96, + 0x63, 0x4f, 0xd4, 0x61, 0xfa, 0x9e, 0x5b, 0xdf, 0x21, 0x09, 0xbc, 0xeb, 0xd7, + 0x35, 0xe5, 0xa9, 0x1f, 0x3e, 0x58, 0x7c, 0x5c, 0xb7, 0x82, 0xab, 0xb7, 0x97, + 0xfb, 0xf6, 0xbb, 0x50, 0x74, 0xfd, 0x15, 0x42, 0xa4, 0x74, 0xf2, 0xa4, 0x5b, + 0x67, 0x37, 0x63, 0xec, 0x2d, 0xb7, 0xfb, 0x99, 0xb7, 0x37, 0xbb, 0xb9, + ], + [ + 0x56, 0xbd, 0x0c, 0x06, 0xf1, 0x03, 0x52, 0xc3, 0xa1, 0xa9, 0xf4, 0xb4, 0xc9, + 0x2f, 0x6f, 0xa2, 0xb2, 0x6d, 0xf1, 0x24, 0xb5, 0x78, 0x78, 0x35, 0x3c, 0x1f, + 0xc6, 0x91, 0xc5, 0x1a, 0xbe, 0xa7, 0x7c, 0x88, 0x17, 0xda, 0xee, 0xb9, 0xfa, + 0x54, 0x6b, 0x77, 0xc8, 0xda, 0xf7, 0x9d, 0x89, 0xb2, 0x2b, 0x0e, 0x1b, 0x87, + 0x57, 0x4e, 0xce, 0x42, 0x37, 0x1f, 0x00, 0x23, 0x7a, 0xa9, 0xd8, 0x3a, + ], + 0, + [ + 0x19, 0x18, 0xb7, 0x41, 0xef, 0x5f, 0x9d, 0x1d, 0x76, 0x70, 0xb0, 0x50, 0xc1, + 0x52, 0xb4, 0xa4, 0xea, 0xd2, 0xc3, 0x1b, 0xe9, 0xae, 0xcb, 0x06, 0x81, 0xc0, + 0xcd, 0x43, 0x24, 0x15, 0x08, 0x53, + ], + ), + ( + [ + 0xa6, 0xec, 0x25, 0x12, 0x7c, 0xa1, 0xaa, 0x4c, 0xf1, 0x6b, 0x20, 0x08, 0x4b, + 0xa1, 0xe6, 0x51, 0x6b, 0xaa, 0xe4, 0xd3, 0x24, 0x22, 0x28, 0x8e, 0x9b, 0x36, + 0xd8, 0xbd, 0xdd, 0x2d, 0xe3, 0x5a, + ], + [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x05, 0x3d, 0x7e, 0xcc, 0xa5, 0x3e, 0x33, 0xe1, 0x85, 0xa8, 0xb9, + 0xbe, 0x4e, 0x76, 0x99, 0xa9, 0x7c, 0x6f, 0xf4, 0xc7, 0x95, 0x52, 0x2e, 0x59, + 0x18, 0xab, 0x7c, 0xd6, 0xb6, 0x88, 0x4f, 0x67, 0xe6, 0x83, 0xf3, 0xdc, + ], + [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xa7, 0x73, 0x0b, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + 1, + [ + 0xdd, 0x21, 0x0a, 0xa6, 0x62, 0x9f, 0x20, 0xbb, 0x32, 0x8e, 0x5d, 0x89, 0xda, + 0xa6, 0xeb, 0x2a, 0xc3, 0xd1, 0xc6, 0x58, 0xa7, 0x25, 0x53, 0x6f, 0xf1, 0x54, + 0xf3, 0x1b, 0x53, 0x6c, 0x23, 0xb2, + ], + ), + ( + [ + 0x0a, 0xf9, 0x52, 0x65, 0x9e, 0xd7, 0x6f, 0x80, 0xf5, 0x85, 0x96, 0x6b, 0x95, + 0xab, 0x6e, 0x6f, 0xd6, 0x86, 0x54, 0x67, 0x28, 0x27, 0x87, 0x86, 0x84, 0xc8, + 0xb5, 0x47, 0xb1, 0xb9, 0x4f, 0x5a, + ], + [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xc8, 0x10, 0x17, 0xfd, 0x92, 0xfd, 0x31, 0x63, 0x7c, 0x26, 0xc9, + 0x06, 0xb4, 0x20, 0x92, 0xe1, 0x1c, 0xc0, 0xd3, 0xaf, 0xae, 0x8d, 0x90, 0x19, + 0xd2, 0x57, 0x8a, 0xf2, 0x27, 0x35, 0xce, 0x7b, 0xc4, 0x69, 0xc7, 0x2d, + ], + [ + 0x96, 0x52, 0xd7, 0x8b, 0xae, 0xfc, 0x02, 0x8c, 0xd3, 0x7a, 0x6a, 0x92, 0x62, + 0x5b, 0x8b, 0x8f, 0x85, 0xfd, 0xe1, 0xe4, 0xc9, 0x44, 0xad, 0x3f, 0x20, 0xe1, + 0x98, 0xbe, 0xf8, 0xc0, 0x2f, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0xe9, 0x18, 0x70, + ], + 0, + [ + 0x35, 0x68, 0xf2, 0xae, 0xa2, 0xe1, 0x4e, 0xf4, 0xee, 0x4a, 0x3c, 0x2a, 0x8b, + 0x8d, 0x31, 0xbc, 0x5e, 0x31, 0x87, 0xba, 0x86, 0xdb, 0x10, 0x73, 0x9b, 0x4f, + 0xf8, 0xec, 0x92, 0xff, 0x66, 0x55, + ], + ), + ( + [ + 0xf9, 0x0e, 0x08, 0x0c, 0x64, 0xb0, 0x58, 0x24, 0xc5, 0xa2, 0x4b, 0x25, 0x01, + 0xd5, 0xae, 0xaf, 0x08, 0xaf, 0x38, 0x72, 0xee, 0x86, 0x0a, 0xa8, 0x0b, 0xdc, + 0xd4, 0x30, 0xf7, 0xb6, 0x34, 0x94, + ], + [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x11, 0x51, 0x73, 0x76, 0x5d, 0xc2, 0x02, 0xcf, 0x02, 0x9a, 0xd3, + 0xf1, 0x54, 0x79, 0x73, 0x5d, 0x57, 0x69, 0x7a, 0xf1, 0x2b, 0x01, 0x31, 0xdd, + 0x21, 0x43, 0x0d, 0x57, 0x72, 0xe4, 0xef, 0x11, 0x47, 0x4d, 0x58, 0xb9, + ], + [ + 0x12, 0xa5, 0x0f, 0x3f, 0xaf, 0xea, 0x7c, 0x1e, 0xea, 0xda, 0x4c, 0xf8, 0xd3, + 0x37, 0x77, 0x70, 0x4b, 0x77, 0x36, 0x14, 0x53, 0xaf, 0xc8, 0x3b, 0xda, 0x91, + 0xee, 0xf3, 0x49, 0xae, 0x04, 0x4d, 0x20, 0x12, 0x6c, 0x62, 0x00, 0x54, 0x7e, + 0xa5, 0xa6, 0x91, 0x17, 0x76, 0xc0, 0x5d, 0xee, 0x2a, 0x7f, 0x1a, 0x9b, 0xa7, + 0xdf, 0xba, 0xbb, 0xbd, 0x27, 0x3c, 0x3e, 0xf2, 0x9e, 0xf4, 0x6e, 0x46, + ], + 1, + [ + 0xe2, 0x54, 0x61, 0xfb, 0x0e, 0x4c, 0x16, 0x2e, 0x18, 0x12, 0x3e, 0xcd, 0xe8, + 0x83, 0x42, 0xd5, 0x4d, 0x44, 0x96, 0x31, 0xe9, 0xb7, 0x5a, 0x26, 0x6f, 0xd9, + 0x26, 0x0c, 0x2b, 0xb2, 0xf4, 0x1d, + ], + ), + ]; + for (my_secret, ellswift_ours, ellswift_theirs, initiator, shared_secret) in tests { + // We are not the initiator, so we are B + let (el_a, el_b) = if initiator == 0 { + ( + ElligatorSwift::from_array(ellswift_theirs), + ElligatorSwift::from_array(ellswift_ours), + ) + } else { + // We are the initiator, so we are A + ( + ElligatorSwift::from_array(ellswift_ours), + ElligatorSwift::from_array(ellswift_theirs), + ) + }; + let sec_key = SecretKey::from_slice(&my_secret).unwrap(); + let initiator = if initiator == 0 { Party::Responder } else { Party::Initiator }; + + let shared = ElligatorSwift::shared_secret(el_a, el_b, sec_key, initiator, None); + + assert_eq!(shared.0, shared_secret); + } + } + #[test] + #[cfg(not(secp256k1_fuzz))] + fn ellswift_decode_test() { + struct EllswiftDecodeTest { + enc: [u8; 64], + key: PublicKey, + } + #[inline] + fn parse_test(ell: &str, x: &str, parity: u32) -> EllswiftDecodeTest { + let mut enc = [0u8; 64]; + from_hex(ell, &mut enc).unwrap(); + let xo = XOnlyPublicKey::from_str(x).unwrap(); + let parity = if parity == 0 { crate::Parity::Even } else { crate::Parity::Odd }; + let pk = PublicKey::from_x_only_public_key(xo, parity); + EllswiftDecodeTest { enc, key: pk } + } + macro_rules! make_tests { + ($(($ell: literal, $x: literal, $parity: literal)),+) => { + [$( + parse_test($ell, $x, $parity), + )+] + }; + } + let tests = make_tests!( + ("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c", 0), + ("000000000000000000000000000000000000000000000000000000000000000001d3475bf7655b0fb2d852921035b2ef607f49069b97454e6795251062741771","b5da00b73cd6560520e7c364086e7cd23a34bf60d0e707be9fc34d4cd5fdfa2c", 1), + ("000000000000000000000000000000000000000000000000000000000000000082277c4a71f9d22e66ece523f8fa08741a7c0912c66a69ce68514bfd3515b49f","f482f2e241753ad0fb89150d8491dc1e34ff0b8acfbb442cfe999e2e5e6fd1d2", 1), + ("00000000000000000000000000000000000000000000000000000000000000008421cc930e77c9f514b6915c3dbe2a94c6d8f690b5b739864ba6789fb8a55dd0","9f59c40275f5085a006f05dae77eb98c6fd0db1ab4a72ac47eae90a4fc9e57e0", 0), + ("0000000000000000000000000000000000000000000000000000000000000000bde70df51939b94c9c24979fa7dd04ebd9b3572da7802290438af2a681895441","aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9fffffd6b", 1), + ("0000000000000000000000000000000000000000000000000000000000000000d19c182d2759cd99824228d94799f8c6557c38a1c0d6779b9d4b729c6f1ccc42","70720db7e238d04121f5b1afd8cc5ad9d18944c6bdc94881f502b7a3af3aecff", 0), + ("0000000000000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c", 0), + ("0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2664bbd5","50873db31badcc71890e4f67753a65757f97aaa7dd5f1e82b753ace32219064b", 0), + ("0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7028de7d","1eea9cc59cfcf2fa151ac6c274eea4110feb4f7b68c5965732e9992e976ef68e", 0), + ("0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffcbcfb7e7","12303941aedc208880735b1f1795c8e55be520ea93e103357b5d2adb7ed59b8e", 0), + ("0000000000000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffff3113ad9","7eed6b70e7b0767c7d7feac04e57aa2a12fef5e0f48f878fcbb88b3b6b5e0783", 0), + ("0a2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f8530000000000000000000000000000000000000000000000000000000000000000","532167c11200b08c0e84a354e74dcc40f8b25f4fe686e30869526366278a0688", 0), + ("0a2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f853fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","532167c11200b08c0e84a354e74dcc40f8b25f4fe686e30869526366278a0688", 0), + ("0ffde9ca81d751e9cdaffc1a50779245320b28996dbaf32f822f20117c22fbd6c74d99efceaa550f1ad1c0f43f46e7ff1ee3bd0162b7bf55f2965da9c3450646","74e880b3ffd18fe3cddf7902522551ddf97fa4a35a3cfda8197f947081a57b8f", 0), + ("0ffde9ca81d751e9cdaffc1a50779245320b28996dbaf32f822f20117c22fbd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffff156ca896","377b643fce2271f64e5c8101566107c1be4980745091783804f654781ac9217c", 1), + ("123658444f32be8f02ea2034afa7ef4bbe8adc918ceb49b12773b625f490b368ffffffffffffffffffffffffffffffffffffffffffffffffffffffff8dc5fe11","ed16d65cf3a9538fcb2c139f1ecbc143ee14827120cbc2659e667256800b8142", 0), + ("146f92464d15d36e35382bd3ca5b0f976c95cb08acdcf2d5b3570617990839d7ffffffffffffffffffffffffffffffffffffffffffffffffffffffff3145e93b","0d5cd840427f941f65193079ab8e2e83024ef2ee7ca558d88879ffd879fb6657", 0), + ("15fdf5cf09c90759add2272d574d2bb5fe1429f9f3c14c65e3194bf61b82aa73ffffffffffffffffffffffffffffffffffffffffffffffffffffffff04cfd906","16d0e43946aec93f62d57eb8cde68951af136cf4b307938dd1447411e07bffe1", 1), + ("1f67edf779a8a649d6def60035f2fa22d022dd359079a1a144073d84f19b92d50000000000000000000000000000000000000000000000000000000000000000","025661f9aba9d15c3118456bbe980e3e1b8ba2e047c737a4eb48a040bb566f6c", 0), + ("1f67edf779a8a649d6def60035f2fa22d022dd359079a1a144073d84f19b92d5fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","025661f9aba9d15c3118456bbe980e3e1b8ba2e047c737a4eb48a040bb566f6c", 0), + ("1fe1e5ef3fceb5c135ab7741333ce5a6e80d68167653f6b2b24bcbcfaaaff507fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","98bec3b2a351fa96cfd191c1778351931b9e9ba9ad1149f6d9eadca80981b801", 0), + ("4056a34a210eec7892e8820675c860099f857b26aad85470ee6d3cf1304a9dcf375e70374271f20b13c9986ed7d3c17799698cfc435dbed3a9f34b38c823c2b4","868aac2003b29dbcad1a3e803855e078a89d16543ac64392d122417298cec76e", 0), + ("4197ec3723c654cfdd32ab075506648b2ff5070362d01a4fff14b336b78f963fffffffffffffffffffffffffffffffffffffffffffffffffffffffffb3ab1e95","ba5a6314502a8952b8f456e085928105f665377a8ce27726a5b0eb7ec1ac0286", 0), + ("47eb3e208fedcdf8234c9421e9cd9a7ae873bfbdbc393723d1ba1e1e6a8e6b24ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7cd12cb1","d192d52007e541c9807006ed0468df77fd214af0a795fe119359666fdcf08f7c", 0), + ("5eb9696a2336fe2c3c666b02c755db4c0cfd62825c7b589a7b7bb442e141c1d693413f0052d49e64abec6d5831d66c43612830a17df1fe4383db896468100221","ef6e1da6d6c7627e80f7a7234cb08a022c1ee1cf29e4d0f9642ae924cef9eb38", 1), + ("7bf96b7b6da15d3476a2b195934b690a3a3de3e8ab8474856863b0de3af90b0e0000000000000000000000000000000000000000000000000000000000000000","50851dfc9f418c314a437295b24feeea27af3d0cd2308348fda6e21c463e46ff", 0), + ("7bf96b7b6da15d3476a2b195934b690a3a3de3e8ab8474856863b0de3af90b0efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","50851dfc9f418c314a437295b24feeea27af3d0cd2308348fda6e21c463e46ff", 0), + ("851b1ca94549371c4f1f7187321d39bf51c6b7fb61f7cbf027c9da62021b7a65fc54c96837fb22b362eda63ec52ec83d81bedd160c11b22d965d9f4a6d64d251","3e731051e12d33237eb324f2aa5b16bb868eb49a1aa1fadc19b6e8761b5a5f7b", 1), + ("943c2f775108b737fe65a9531e19f2fc2a197f5603e3a2881d1d83e4008f91250000000000000000000000000000000000000000000000000000000000000000","311c61f0ab2f32b7b1f0223fa72f0a78752b8146e46107f8876dd9c4f92b2942", 0), + ("943c2f775108b737fe65a9531e19f2fc2a197f5603e3a2881d1d83e4008f9125fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","311c61f0ab2f32b7b1f0223fa72f0a78752b8146e46107f8876dd9c4f92b2942", 0), + ("a0f18492183e61e8063e573606591421b06bc3513631578a73a39c1c3306239f2f32904f0d2a33ecca8a5451705bb537d3bf44e071226025cdbfd249fe0f7ad6","97a09cf1a2eae7c494df3c6f8a9445bfb8c09d60832f9b0b9d5eabe25fbd14b9", 0), + ("a1ed0a0bd79d8a23cfe4ec5fef5ba5cccfd844e4ff5cb4b0f2e71627341f1c5b17c499249e0ac08d5d11ea1c2c8ca7001616559a7994eadec9ca10fb4b8516dc","65a89640744192cdac64b2d21ddf989cdac7500725b645bef8e2200ae39691f2", 0), + ("ba94594a432721aa3580b84c161d0d134bc354b690404d7cd4ec57c16d3fbe98ffffffffffffffffffffffffffffffffffffffffffffffffffffffffea507dd7","5e0d76564aae92cb347e01a62afd389a9aa401c76c8dd227543dc9cd0efe685a", 0), + ("bcaf7219f2f6fbf55fe5e062dce0e48c18f68103f10b8198e974c184750e1be3932016cbf69c4471bd1f656c6a107f1973de4af7086db897277060e25677f19a","2d97f96cac882dfe73dc44db6ce0f1d31d6241358dd5d74eb3d3b50003d24c2b", 0), + ("bcaf7219f2f6fbf55fe5e062dce0e48c18f68103f10b8198e974c184750e1be3ffffffffffffffffffffffffffffffffffffffffffffffffffffffff6507d09a","e7008afe6e8cbd5055df120bd748757c686dadb41cce75e4addcc5e02ec02b44", 1), + ("c5981bae27fd84401c72a155e5707fbb811b2b620645d1028ea270cbe0ee225d4b62aa4dca6506c1acdbecc0552569b4b21436a5692e25d90d3bc2eb7ce24078","948b40e7181713bc018ec1702d3d054d15746c59a7020730dd13ecf985a010d7", 0), + ("c894ce48bfec433014b931a6ad4226d7dbd8eaa7b6e3faa8d0ef94052bcf8cff336eeb3919e2b4efb746c7f71bbca7e9383230fbbc48ffafe77e8bcc69542471","f1c91acdc2525330f9b53158434a4d43a1c547cff29f15506f5da4eb4fe8fa5a", 1), + ("cbb0deab125754f1fdb2038b0434ed9cb3fb53ab735391129994a535d925f6730000000000000000000000000000000000000000000000000000000000000000","872d81ed8831d9998b67cb7105243edbf86c10edfebb786c110b02d07b2e67cd", 0), + ("d917b786dac35670c330c9c5ae5971dfb495c8ae523ed97ee2420117b171f41effffffffffffffffffffffffffffffffffffffffffffffffffffffff2001f6f6","e45b71e110b831f2bdad8651994526e58393fde4328b1ec04d59897142584691", 1), + ("e28bd8f5929b467eb70e04332374ffb7e7180218ad16eaa46b7161aa679eb4260000000000000000000000000000000000000000000000000000000000000000","66b8c980a75c72e598d383a35a62879f844242ad1e73ff12edaa59f4e58632b5", 0), + ("e28bd8f5929b467eb70e04332374ffb7e7180218ad16eaa46b7161aa679eb426fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","66b8c980a75c72e598d383a35a62879f844242ad1e73ff12edaa59f4e58632b5", 0), + ("e7ee5814c1706bf8a89396a9b032bc014c2cac9c121127dbf6c99278f8bb53d1dfd04dbcda8e352466b6fcd5f2dea3e17d5e133115886eda20db8a12b54de71b","e842c6e3529b234270a5e97744edc34a04d7ba94e44b6d2523c9cf0195730a50", 1), + ("f292e46825f9225ad23dc057c1d91c4f57fcb1386f29ef10481cb1d22518593fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7011c989","3cea2c53b8b0170166ac7da67194694adacc84d56389225e330134dab85a4d55", 0), + ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0000000000000000000000000000000000000000000000000000000000000000","edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c", 0), + ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f01d3475bf7655b0fb2d852921035b2ef607f49069b97454e6795251062741771","b5da00b73cd6560520e7c364086e7cd23a34bf60d0e707be9fc34d4cd5fdfa2c", 1), + ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f4218f20ae6c646b363db68605822fb14264ca8d2587fdd6fbc750d587e76a7ee","aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9fffffd6b", 0), + ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f82277c4a71f9d22e66ece523f8fa08741a7c0912c66a69ce68514bfd3515b49f","f482f2e241753ad0fb89150d8491dc1e34ff0b8acfbb442cfe999e2e5e6fd1d2", 1), + ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8421cc930e77c9f514b6915c3dbe2a94c6d8f690b5b739864ba6789fb8a55dd0","9f59c40275f5085a006f05dae77eb98c6fd0db1ab4a72ac47eae90a4fc9e57e0", 0), + ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fd19c182d2759cd99824228d94799f8c6557c38a1c0d6779b9d4b729c6f1ccc42","70720db7e238d04121f5b1afd8cc5ad9d18944c6bdc94881f502b7a3af3aecff", 0), + ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c", 0), + ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fffffffffffffffffffffffffffffffffffffffffffffffffffffffff2664bbd5","50873db31badcc71890e4f67753a65757f97aaa7dd5f1e82b753ace32219064b", 0), + ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7028de7d","1eea9cc59cfcf2fa151ac6c274eea4110feb4f7b68c5965732e9992e976ef68e", 0), + ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcbcfb7e7","12303941aedc208880735b1f1795c8e55be520ea93e103357b5d2adb7ed59b8e", 0), + ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3113ad9","7eed6b70e7b0767c7d7feac04e57aa2a12fef5e0f48f878fcbb88b3b6b5e0783", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff13cea4a70000000000000000000000000000000000000000000000000000000000000000","649984435b62b4a25d40c6133e8d9ab8c53d4b059ee8a154a3be0fcf4e892edb", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff13cea4a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","649984435b62b4a25d40c6133e8d9ab8c53d4b059ee8a154a3be0fcf4e892edb", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff15028c590063f64d5a7f1c14915cd61eac886ab295bebd91992504cf77edb028bdd6267f","3fde5713f8282eead7d39d4201f44a7c85a5ac8a0681f35e54085c6b69543374", 1), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2715de860000000000000000000000000000000000000000000000000000000000000000","3524f77fa3a6eb4389c3cb5d27f1f91462086429cd6c0cb0df43ea8f1e7b3fb4", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2715de86fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","3524f77fa3a6eb4389c3cb5d27f1f91462086429cd6c0cb0df43ea8f1e7b3fb4", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2c2c5709e7156c417717f2feab147141ec3da19fb759575cc6e37b2ea5ac9309f26f0f66","d2469ab3e04acbb21c65a1809f39caafe7a77c13d10f9dd38f391c01dc499c52", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff3a08cc1efffffffffffffffffffffffffffffffffffffffffffffffffffffffff760e9f0","38e2a5ce6a93e795e16d2c398bc99f0369202ce21e8f09d56777b40fc512bccc", 1), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff3e91257d932016cbf69c4471bd1f656c6a107f1973de4af7086db897277060e25677f19a","864b3dc902c376709c10a93ad4bbe29fce0012f3dc8672c6286bba28d7d6d6fc", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff795d6c1c322cadf599dbb86481522b3cc55f15a67932db2afa0111d9ed6981bcd124bf44","766dfe4a700d9bee288b903ad58870e3d4fe2f0ef780bcac5c823f320d9a9bef", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff8e426f0392389078c12b1a89e9542f0593bc96b6bfde8224f8654ef5d5cda935a3582194","faec7bc1987b63233fbc5f956edbf37d54404e7461c58ab8631bc68e451a0478", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff91192139ffffffffffffffffffffffffffffffffffffffffffffffffffffffff45f0f1eb","ec29a50bae138dbf7d8e24825006bb5fc1a2cc1243ba335bc6116fb9e498ec1f", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff98eb9ab76e84499c483b3bf06214abfe065dddf43b8601de596d63b9e45a166a580541fe","1e0ff2dee9b09b136292a9e910f0d6ac3e552a644bba39e64e9dd3e3bbd3d4d4", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff9b77b7f2c74d99efceaa550f1ad1c0f43f46e7ff1ee3bd0162b7bf55f2965da9c3450646","8b7dd5c3edba9ee97b70eff438f22dca9849c8254a2f3345a0a572ffeaae0928", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff9b77b7f2ffffffffffffffffffffffffffffffffffffffffffffffffffffffff156ca896","0881950c8f51d6b9a6387465d5f12609ef1bb25412a08a74cb2dfb200c74bfbf", 1), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffa2f5cd838816c16c4fe8a1661d606fdb13cf9af04b979a2e159a09409ebc8645d58fde02","2f083207b9fd9b550063c31cd62b8746bd543bdc5bbf10e3a35563e927f440c8", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffb13f75c00000000000000000000000000000000000000000000000000000000000000000","4f51e0be078e0cddab2742156adba7e7a148e73157072fd618cd60942b146bd0", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffb13f75c0fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","4f51e0be078e0cddab2742156adba7e7a148e73157072fd618cd60942b146bd0", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7bc1f8d0000000000000000000000000000000000000000000000000000000000000000","16c2ccb54352ff4bd794f6efd613c72197ab7082da5b563bdf9cb3edaafe74c2", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7bc1f8dfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","16c2ccb54352ff4bd794f6efd613c72197ab7082da5b563bdf9cb3edaafe74c2", 0), + ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffef64d162750546ce42b0431361e52d4f5242d8f24f33e6b1f99b591647cbc808f462af51","d41244d11ca4f65240687759f95ca9efbab767ededb38fd18c36e18cd3b6f6a9", 1), + ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0e5be52372dd6e894b2a326fc3605a6e8f3c69c710bf27d630dfe2004988b78eb6eab36","64bf84dd5e03670fdb24c0f5d3c2c365736f51db6c92d95010716ad2d36134c8", 0), + ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffefbb982fffffffffffffffffffffffffffffffffffffffffffffffffffffffff6d6db1f","1c92ccdfcf4ac550c28db57cff0c8515cb26936c786584a70114008d6c33a34b", 0) + ); + + for test in tests.iter() { + let pk = PublicKey::from_ellswift(ElligatorSwift::from_array(test.enc)); + assert_eq!(pk, test.key); + } + } +} diff --git a/ark-rust-secp256k1/src/key.rs b/ark-rust-secp256k1/src/key.rs new file mode 100644 index 00000000..5dee2022 --- /dev/null +++ b/ark-rust-secp256k1/src/key.rs @@ -0,0 +1,2523 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Public and secret keys. +//! + +use core::ops::{self, BitXor}; +use core::{fmt, ptr, str}; + +use secp256k1_sys::secp256k1_ec_pubkey_sort; +#[cfg(feature = "serde")] +use serde::ser::SerializeTuple; + +use crate::ellswift::ElligatorSwift; +use crate::ffi::types::c_uint; +use crate::ffi::{self, CPtr}; +use crate::Error::{self, InvalidPublicKey, InvalidPublicKeySum, InvalidSecretKey}; +#[cfg(feature = "hashes")] +#[allow(deprecated)] +use crate::ThirtyTwoByteHash; +#[cfg(feature = "global-context")] +use crate::SECP256K1; +use crate::{ + constants, ecdsa, from_hex, schnorr, Message, Scalar, Secp256k1, Signing, Verification, +}; + +/// Secret key - a 256-bit key used to create ECDSA and Taproot signatures. +/// +/// This value should be generated using a [cryptographically secure pseudorandom number generator]. +/// +/// # Side channel attacks +/// +/// We have attempted to reduce the side channel attack surface by implementing a constant time `eq` +/// method. For similar reasons we explicitly do not implement `PartialOrd`, `Ord`, or `Hash` on +/// `SecretKey`. If you really want to order secret keys then you can use `AsRef` to get at the +/// underlying bytes and compare them - however this is almost certainly a bad idea. +/// +/// # Serde support +/// +/// Implements de/serialization with the `serde` feature enabled. We treat the byte value as a tuple +/// of 32 `u8`s for non-human-readable formats. This representation is optimal for some formats +/// (e.g. [`bincode`]) however other formats may be less optimal (e.g. [`cbor`]). +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// # #[cfg(all(feature = "rand", feature = "std"))] { +/// use secp256k1::{rand, Secp256k1, SecretKey}; +/// +/// let secp = Secp256k1::new(); +/// let secret_key = SecretKey::new(&mut rand::thread_rng()); +/// # } +/// ``` +/// [`bincode`]: https://docs.rs/bincode +/// [`cbor`]: https://docs.rs/cbor +/// [cryptographically secure pseudorandom number generator]: https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator +#[derive(Copy, Clone)] +pub struct SecretKey([u8; constants::SECRET_KEY_SIZE]); +impl_display_secret!(SecretKey); +impl_non_secure_erase!(SecretKey, 0, [1u8; constants::SECRET_KEY_SIZE]); + +impl PartialEq for SecretKey { + /// This implementation is designed to be constant time to help prevent side channel attacks. + #[inline] + fn eq(&self, other: &Self) -> bool { + let accum = self.0.iter().zip(&other.0).fold(0, |accum, (a, b)| accum | a ^ b); + unsafe { core::ptr::read_volatile(&accum) == 0 } + } +} + +impl Eq for SecretKey {} + +impl AsRef<[u8; constants::SECRET_KEY_SIZE]> for SecretKey { + /// Gets a reference to the underlying array. + /// + /// # Side channel attacks + /// + /// Using ordering functions (`PartialOrd`/`Ord`) on a reference to secret keys leaks data + /// because the implementations are not constant time. Doing so will make your code vulnerable + /// to side channel attacks. [`SecretKey::eq`] is implemented using a constant time algorithm, + /// please consider using it to do comparisons of secret keys. + #[inline] + fn as_ref(&self) -> &[u8; constants::SECRET_KEY_SIZE] { + let SecretKey(dat) = self; + dat + } +} + +impl ops::Index for SecretKey +where + [u8]: ops::Index, +{ + type Output = <[u8] as ops::Index>::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { &self.0[index] } +} + +impl ffi::CPtr for SecretKey { + type Target = u8; + + fn as_c_ptr(&self) -> *const Self::Target { + let SecretKey(dat) = self; + dat.as_ptr() + } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { + let &mut SecretKey(ref mut dat) = self; + dat.as_mut_ptr() + } +} + +impl str::FromStr for SecretKey { + type Err = Error; + fn from_str(s: &str) -> Result { + let mut res = [0u8; constants::SECRET_KEY_SIZE]; + match from_hex(s, &mut res) { + Ok(constants::SECRET_KEY_SIZE) => SecretKey::from_byte_array(&res), + _ => Err(Error::InvalidSecretKey), + } + } +} + +/// Public key - used to verify ECDSA signatures and to do Taproot tweaks. +/// +/// # Serde support +/// +/// Implements de/serialization with the `serde` feature enabled. We treat the byte value as a tuple +/// of 33 `u8`s for non-human-readable formats. This representation is optimal for some formats +/// (e.g. [`bincode`]) however other formats may be less optimal (e.g. [`cbor`]). +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// # #[cfg(feature = "alloc")] { +/// use secp256k1::{SecretKey, Secp256k1, PublicKey}; +/// +/// let secp = Secp256k1::new(); +/// let secret_key = SecretKey::from_byte_array(&[0xcd; 32]).expect("32 bytes, within curve order"); +/// let public_key = PublicKey::from_secret_key(&secp, &secret_key); +/// # } +/// ``` +/// [`bincode`]: https://docs.rs/bincode +/// [`cbor`]: https://docs.rs/cbor +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct PublicKey(ffi::PublicKey); +impl_fast_comparisons!(PublicKey); + +impl fmt::LowerHex for PublicKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let ser = self.serialize(); + for ch in &ser[..] { + write!(f, "{:02x}", *ch)?; + } + Ok(()) + } +} + +impl fmt::Display for PublicKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) } +} + +impl fmt::Debug for PublicKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) } +} + +impl str::FromStr for PublicKey { + type Err = Error; + fn from_str(s: &str) -> Result { + let mut res = [0u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]; + match from_hex(s, &mut res) { + Ok(constants::PUBLIC_KEY_SIZE) => { + let bytes: [u8; constants::PUBLIC_KEY_SIZE] = + res[0..constants::PUBLIC_KEY_SIZE].try_into().unwrap(); + PublicKey::from_byte_array_compressed(&bytes) + } + Ok(constants::UNCOMPRESSED_PUBLIC_KEY_SIZE) => + PublicKey::from_byte_array_uncompressed(&res), + _ => Err(Error::InvalidPublicKey), + } + } +} + +impl SecretKey { + /// Generates a new random secret key. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(all(feature = "std", feature = "rand"))] { + /// use secp256k1::{rand, SecretKey}; + /// let secret_key = SecretKey::new(&mut rand::thread_rng()); + /// # } + /// ``` + #[inline] + #[cfg(feature = "rand")] + pub fn new(rng: &mut R) -> SecretKey { + let mut data = crate::random_32_bytes(rng); + unsafe { + while ffi::secp256k1_ec_seckey_verify( + ffi::secp256k1_context_no_precomp, + data.as_c_ptr(), + ) == 0 + { + data = crate::random_32_bytes(rng); + } + } + SecretKey(data) + } + + /// Converts a 32-byte slice to a secret key. + /// + /// # Examples + /// + /// ``` + /// use secp256k1::SecretKey; + /// let sk = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order"); + /// ``` + #[deprecated(since = "TBD", note = "Use `from_byte_array` instead.")] + #[inline] + pub fn from_slice(data: &[u8]) -> Result { + match <[u8; constants::SECRET_KEY_SIZE]>::try_from(data) { + Ok(data) => Self::from_byte_array(&data), + Err(_) => Err(InvalidSecretKey), + } + } + + /// Converts a 32-byte array to a secret key. + /// + /// # Examples + /// + /// ``` + /// use secp256k1::SecretKey; + /// let sk = SecretKey::from_byte_array(&[0xcd; 32]).expect("32 bytes, within curve order"); + /// ``` + #[inline] + pub fn from_byte_array(data: &[u8; constants::SECRET_KEY_SIZE]) -> Result { + unsafe { + if ffi::secp256k1_ec_seckey_verify(ffi::secp256k1_context_no_precomp, data.as_c_ptr()) + == 0 + { + return Err(InvalidSecretKey); + } + } + Ok(SecretKey(*data)) + } + + /// Creates a new secret key using data from BIP-340 [`Keypair`]. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(all(feature = "rand", feature = "std"))] { + /// use secp256k1::{rand, Secp256k1, SecretKey, Keypair}; + /// + /// let secp = Secp256k1::new(); + /// let keypair = Keypair::new(&secp, &mut rand::thread_rng()); + /// let secret_key = SecretKey::from_keypair(&keypair); + /// # } + /// ``` + #[inline] + pub fn from_keypair(keypair: &Keypair) -> Self { + let mut sk = [0u8; constants::SECRET_KEY_SIZE]; + unsafe { + let ret = ffi::secp256k1_keypair_sec( + ffi::secp256k1_context_no_precomp, + sk.as_mut_c_ptr(), + keypair.as_c_ptr(), + ); + debug_assert_eq!(ret, 1); + } + SecretKey(sk) + } + + /// Returns the secret key as a byte value. + #[inline] + pub fn secret_bytes(&self) -> [u8; constants::SECRET_KEY_SIZE] { self.0 } + + /// Negates the secret key. + #[inline] + #[must_use = "you forgot to use the negated secret key"] + pub fn negate(mut self) -> SecretKey { + unsafe { + let res = ffi::secp256k1_ec_seckey_negate( + ffi::secp256k1_context_no_precomp, + self.as_mut_c_ptr(), + ); + debug_assert_eq!(res, 1); + } + self + } + + /// Tweaks a [`SecretKey`] by adding `tweak` modulo the curve order. + /// + /// # Errors + /// + /// Returns an error if the resulting key would be invalid. + #[inline] + pub fn add_tweak(mut self, tweak: &Scalar) -> Result { + unsafe { + if ffi::secp256k1_ec_seckey_tweak_add( + ffi::secp256k1_context_no_precomp, + self.as_mut_c_ptr(), + tweak.as_c_ptr(), + ) != 1 + { + Err(Error::InvalidTweak) + } else { + Ok(self) + } + } + } + + /// Tweaks a [`SecretKey`] by multiplying by `tweak` modulo the curve order. + /// + /// # Errors + /// + /// Returns an error if the resulting key would be invalid. + #[inline] + pub fn mul_tweak(mut self, tweak: &Scalar) -> Result { + unsafe { + if ffi::secp256k1_ec_seckey_tweak_mul( + ffi::secp256k1_context_no_precomp, + self.as_mut_c_ptr(), + tweak.as_c_ptr(), + ) != 1 + { + Err(Error::InvalidTweak) + } else { + Ok(self) + } + } + } + + /// Constructs an ECDSA signature for `msg` using the global [`SECP256K1`] context. + #[inline] + #[cfg(feature = "global-context")] + pub fn sign_ecdsa(&self, msg: impl Into) -> ecdsa::Signature { + SECP256K1.sign_ecdsa(msg, self) + } + + /// Returns the [`Keypair`] for this [`SecretKey`]. + /// + /// This is equivalent to using [`Keypair::from_secret_key`]. + #[inline] + pub fn keypair(&self, secp: &Secp256k1) -> Keypair { + Keypair::from_secret_key(secp, self) + } + + /// Returns the [`PublicKey`] for this [`SecretKey`]. + /// + /// This is equivalent to using [`PublicKey::from_secret_key`]. + #[inline] + pub fn public_key(&self, secp: &Secp256k1) -> PublicKey { + PublicKey::from_secret_key(secp, self) + } + + /// Returns the [`XOnlyPublicKey`] (and its [`Parity`]) for this [`SecretKey`]. + /// + /// This is equivalent to `XOnlyPublicKey::from_keypair(self.keypair(secp))`. + #[inline] + pub fn x_only_public_key(&self, secp: &Secp256k1) -> (XOnlyPublicKey, Parity) { + let kp = self.keypair(secp); + XOnlyPublicKey::from_keypair(&kp) + } +} + +#[cfg(feature = "hashes")] +#[allow(deprecated)] +impl From for SecretKey { + /// Converts a 32-byte hash directly to a secret key without error paths. + fn from(t: T) -> SecretKey { + SecretKey::from_byte_array(&t.into_32()).expect("failed to create secret key") + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for SecretKey { + fn serialize(&self, s: S) -> Result { + if s.is_human_readable() { + let mut buf = [0u8; constants::SECRET_KEY_SIZE * 2]; + s.serialize_str(crate::to_hex(&self.0, &mut buf).expect("fixed-size hex serialization")) + } else { + let mut tuple = s.serialize_tuple(constants::SECRET_KEY_SIZE)?; + for byte in self.0.iter() { + tuple.serialize_element(byte)?; + } + tuple.end() + } + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for SecretKey { + fn deserialize>(d: D) -> Result { + if d.is_human_readable() { + d.deserialize_str(super::serde_util::FromStrVisitor::new( + "a hex string representing 32 byte SecretKey", + )) + } else { + let visitor = super::serde_util::Tuple32Visitor::new( + "raw 32 bytes SecretKey", + SecretKey::from_slice, + ); + d.deserialize_tuple(constants::SECRET_KEY_SIZE, visitor) + } + } +} + +impl PublicKey { + /// Obtains a raw const pointer suitable for use with FFI functions. + #[inline] + #[deprecated(since = "0.25.0", note = "Use Self::as_c_ptr if you need to access the FFI layer")] + pub fn as_ptr(&self) -> *const ffi::PublicKey { self.as_c_ptr() } + + /// Obtains a raw mutable pointer suitable for use with FFI functions. + #[inline] + #[deprecated( + since = "0.25.0", + note = "Use Self::as_mut_c_ptr if you need to access the FFI layer" + )] + pub fn as_mut_ptr(&mut self) -> *mut ffi::PublicKey { self.as_mut_c_ptr() } + + /// Creates a new public key from a [`SecretKey`]. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(all(feature = "rand", feature = "std"))] { + /// use secp256k1::{rand, Secp256k1, SecretKey, PublicKey}; + /// + /// let secp = Secp256k1::new(); + /// let secret_key = SecretKey::new(&mut rand::thread_rng()); + /// let public_key = PublicKey::from_secret_key(&secp, &secret_key); + /// # } + /// ``` + #[inline] + pub fn from_secret_key(secp: &Secp256k1, sk: &SecretKey) -> PublicKey { + unsafe { + let mut pk = ffi::PublicKey::new(); + // We can assume the return value because it's not possible to construct + // an invalid `SecretKey` without transmute trickery or something. + let res = ffi::secp256k1_ec_pubkey_create(secp.ctx.as_ptr(), &mut pk, sk.as_c_ptr()); + debug_assert_eq!(res, 1); + PublicKey(pk) + } + } + /// Creates a new public key from an [`ElligatorSwift`]. + #[inline] + pub fn from_ellswift(ellswift: ElligatorSwift) -> PublicKey { ElligatorSwift::decode(ellswift) } + + /// Creates a new public key from a [`SecretKey`] and the global [`SECP256K1`] context. + #[inline] + #[cfg(feature = "global-context")] + pub fn from_secret_key_global(sk: &SecretKey) -> PublicKey { + PublicKey::from_secret_key(SECP256K1, sk) + } + + /// Creates a public key directly from a slice. + #[inline] + pub fn from_slice(data: &[u8]) -> Result { + match data.len() { + constants::PUBLIC_KEY_SIZE => PublicKey::from_byte_array_compressed( + &<[u8; constants::PUBLIC_KEY_SIZE]>::try_from(data).unwrap(), + ), + constants::UNCOMPRESSED_PUBLIC_KEY_SIZE => PublicKey::from_byte_array_uncompressed( + &<[u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]>::try_from(data).unwrap(), + ), + _ => Err(InvalidPublicKey), + } + } + + /// Creates a public key from a serialized array in compressed format. + #[inline] + pub fn from_byte_array_compressed( + data: &[u8; constants::PUBLIC_KEY_SIZE], + ) -> Result { + unsafe { + let mut pk = ffi::PublicKey::new(); + if ffi::secp256k1_ec_pubkey_parse( + ffi::secp256k1_context_no_precomp, + &mut pk, + data.as_c_ptr(), + constants::PUBLIC_KEY_SIZE, + ) == 1 + { + Ok(PublicKey(pk)) + } else { + Err(InvalidPublicKey) + } + } + } + + /// Creates a public key from a serialized array in uncompressed format. + #[inline] + pub fn from_byte_array_uncompressed( + data: &[u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE], + ) -> Result { + unsafe { + let mut pk = ffi::PublicKey::new(); + if ffi::secp256k1_ec_pubkey_parse( + ffi::secp256k1_context_no_precomp, + &mut pk, + data.as_c_ptr(), + constants::UNCOMPRESSED_PUBLIC_KEY_SIZE, + ) == 1 + { + Ok(PublicKey(pk)) + } else { + Err(InvalidPublicKey) + } + } + } + + /// Creates a new compressed public key using data from BIP-340 [`Keypair`]. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(all(feature = "rand", feature = "std"))] { + /// use secp256k1::{rand, Secp256k1, PublicKey, Keypair}; + /// + /// let secp = Secp256k1::new(); + /// let keypair = Keypair::new(&secp, &mut rand::thread_rng()); + /// let public_key = PublicKey::from_keypair(&keypair); + /// # } + /// ``` + #[inline] + pub fn from_keypair(keypair: &Keypair) -> Self { + unsafe { + let mut pk = ffi::PublicKey::new(); + let ret = ffi::secp256k1_keypair_pub( + ffi::secp256k1_context_no_precomp, + &mut pk, + keypair.as_c_ptr(), + ); + debug_assert_eq!(ret, 1); + PublicKey(pk) + } + } + + /// Creates a [`PublicKey`] using the key material from `pk` combined with the `parity`. + pub fn from_x_only_public_key(pk: XOnlyPublicKey, parity: Parity) -> PublicKey { + let mut buf = [0u8; 33]; + + // First byte of a compressed key should be `0x02 AND parity`. + buf[0] = match parity { + Parity::Even => 0x02, + Parity::Odd => 0x03, + }; + buf[1..].clone_from_slice(&pk.serialize()); + + PublicKey::from_byte_array_compressed(&buf).expect("we know the buffer is valid") + } + + #[inline] + /// Serializes the key as a byte-encoded pair of values. In compressed form the y-coordinate is + /// represented by only a single bit, as x determines it up to one bit. + pub fn serialize(&self) -> [u8; constants::PUBLIC_KEY_SIZE] { + let mut ret = [0u8; constants::PUBLIC_KEY_SIZE]; + self.serialize_internal(&mut ret, ffi::SECP256K1_SER_COMPRESSED); + ret + } + + #[inline] + /// Serializes the key as a byte-encoded pair of values, in uncompressed form. + pub fn serialize_uncompressed(&self) -> [u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE] { + let mut ret = [0u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]; + self.serialize_internal(&mut ret, ffi::SECP256K1_SER_UNCOMPRESSED); + ret + } + + #[inline(always)] + fn serialize_internal(&self, ret: &mut [u8], flag: c_uint) { + let mut ret_len = ret.len(); + let res = unsafe { + ffi::secp256k1_ec_pubkey_serialize( + ffi::secp256k1_context_no_precomp, + ret.as_mut_c_ptr(), + &mut ret_len, + self.as_c_ptr(), + flag, + ) + }; + debug_assert_eq!(res, 1); + debug_assert_eq!(ret_len, ret.len()); + } + + /// Negates the public key. + #[inline] + #[must_use = "you forgot to use the negated public key"] + pub fn negate(mut self, secp: &Secp256k1) -> PublicKey { + unsafe { + let res = ffi::secp256k1_ec_pubkey_negate(secp.ctx.as_ptr(), &mut self.0); + debug_assert_eq!(res, 1); + } + self + } + + /// Tweaks a [`PublicKey`] by adding `tweak * G` modulo the curve order. + /// + /// # Errors + /// + /// Returns an error if the resulting key would be invalid. + #[inline] + pub fn add_exp_tweak( + mut self, + secp: &Secp256k1, + tweak: &Scalar, + ) -> Result { + unsafe { + if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx.as_ptr(), &mut self.0, tweak.as_c_ptr()) + == 1 + { + Ok(self) + } else { + Err(Error::InvalidTweak) + } + } + } + + /// Tweaks a [`PublicKey`] by multiplying by `tweak` modulo the curve order. + /// + /// # Errors + /// + /// Returns an error if the resulting key would be invalid. + #[inline] + pub fn mul_tweak( + mut self, + secp: &Secp256k1, + other: &Scalar, + ) -> Result { + unsafe { + if ffi::secp256k1_ec_pubkey_tweak_mul(secp.ctx.as_ptr(), &mut self.0, other.as_c_ptr()) + == 1 + { + Ok(self) + } else { + Err(Error::InvalidTweak) + } + } + } + + /// Adds a second key to this one, returning the sum. + /// + /// # Errors + /// + /// If the result would be the point at infinity, i.e. adding this point to its own negation. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(all(feature = "rand", feature = "std"))] { + /// use secp256k1::{rand, Secp256k1}; + /// + /// let secp = Secp256k1::new(); + /// let mut rng = rand::thread_rng(); + /// let (_, pk1) = secp.generate_keypair(&mut rng); + /// let (_, pk2) = secp.generate_keypair(&mut rng); + /// let sum = pk1.combine(&pk2).expect("It's improbable to fail for 2 random public keys"); + /// # } + /// ``` + pub fn combine(&self, other: &PublicKey) -> Result { + PublicKey::combine_keys(&[self, other]) + } + + /// Adds the keys in the provided slice together, returning the sum. + /// + /// # Errors + /// + /// Errors under any of the following conditions: + /// - The result would be the point at infinity, i.e. adding a point to its own negation. + /// - The provided slice is empty. + /// - The number of elements in the provided slice is greater than `i32::MAX`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(all(feature = "rand", feature = "std"))] { + /// use secp256k1::{rand, Secp256k1, PublicKey}; + /// + /// let secp = Secp256k1::new(); + /// let mut rng = rand::thread_rng(); + /// let (_, pk1) = secp.generate_keypair(&mut rng); + /// let (_, pk2) = secp.generate_keypair(&mut rng); + /// let (_, pk3) = secp.generate_keypair(&mut rng); + /// let sum = PublicKey::combine_keys(&[&pk1, &pk2, &pk3]).expect("It's improbable to fail for 3 random public keys"); + /// # } + /// ``` + pub fn combine_keys(keys: &[&PublicKey]) -> Result { + use core::mem::transmute; + + if keys.is_empty() || keys.len() > i32::MAX as usize { + return Err(InvalidPublicKeySum); + } + + unsafe { + let mut ret = ffi::PublicKey::new(); + let ptrs: &[*const ffi::PublicKey] = + transmute::<&[&PublicKey], &[*const ffi::PublicKey]>(keys); + if ffi::secp256k1_ec_pubkey_combine( + ffi::secp256k1_context_no_precomp, + &mut ret, + ptrs.as_c_ptr(), + keys.len(), + ) == 1 + { + Ok(PublicKey(ret)) + } else { + Err(InvalidPublicKeySum) + } + } + } + + /// Returns the [`XOnlyPublicKey`] (and its [`Parity`]) for this [`PublicKey`]. + #[inline] + pub fn x_only_public_key(&self) -> (XOnlyPublicKey, Parity) { + let mut pk_parity = 0; + unsafe { + let mut xonly_pk = ffi::XOnlyPublicKey::new(); + let ret = ffi::secp256k1_xonly_pubkey_from_pubkey( + ffi::secp256k1_context_no_precomp, + &mut xonly_pk, + &mut pk_parity, + self.as_c_ptr(), + ); + debug_assert_eq!(ret, 1); + let parity = + Parity::from_i32(pk_parity).expect("should not panic, pk_parity is 0 or 1"); + + (XOnlyPublicKey(xonly_pk), parity) + } + } + + /// Checks that `sig` is a valid ECDSA signature for `msg` using this public key. + pub fn verify( + &self, + secp: &Secp256k1, + msg: impl Into, + sig: &ecdsa::Signature, + ) -> Result<(), Error> { + secp.verify_ecdsa(msg, sig, self) + } +} + +/// This trait enables interaction with the FFI layer and even though it is part of the public API +/// normal users should never need to directly interact with FFI types. +impl CPtr for PublicKey { + type Target = ffi::PublicKey; + + /// Obtains a const pointer suitable for use with FFI functions. + fn as_c_ptr(&self) -> *const Self::Target { &self.0 } + + /// Obtains a mutable pointer suitable for use with FFI functions. + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { &mut self.0 } +} + +/// Creates a new public key from a FFI public key. +/// +/// Note, normal users should never need to interact directly with FFI types. +impl From for PublicKey { + #[inline] + fn from(pk: ffi::PublicKey) -> PublicKey { PublicKey(pk) } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for PublicKey { + fn serialize(&self, s: S) -> Result { + if s.is_human_readable() { + s.collect_str(self) + } else { + let mut tuple = s.serialize_tuple(constants::PUBLIC_KEY_SIZE)?; + // Serialize in compressed form. + for byte in self.serialize().iter() { + tuple.serialize_element(&byte)?; + } + tuple.end() + } + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for PublicKey { + fn deserialize>(d: D) -> Result { + if d.is_human_readable() { + d.deserialize_str(super::serde_util::FromStrVisitor::new( + "an ASCII hex string representing a public key", + )) + } else { + let visitor = super::serde_util::Tuple33Visitor::new( + "33 bytes compressed public key", + PublicKey::from_slice, + ); + d.deserialize_tuple(constants::PUBLIC_KEY_SIZE, visitor) + } + } +} + +/// Opaque data structure that holds a keypair consisting of a secret and a public key. +/// +/// # Serde support +/// +/// Implements de/serialization with the `serde` and `global-context` features enabled. Serializes +/// the secret bytes only. We treat the byte value as a tuple of 32 `u8`s for non-human-readable +/// formats. This representation is optimal for some formats (e.g. [`bincode`]) however other +/// formats may be less optimal (e.g. [`cbor`]). For human-readable formats we use a hex string. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// # #[cfg(all(feature = "rand", feature = "std"))] { +/// use secp256k1::{rand, Keypair, Secp256k1}; +/// +/// let secp = Secp256k1::new(); +/// let (secret_key, public_key) = secp.generate_keypair(&mut rand::thread_rng()); +/// let keypair = Keypair::from_secret_key(&secp, &secret_key); +/// # } +/// ``` +/// [`bincode`]: https://docs.rs/bincode +/// [`cbor`]: https://docs.rs/cbor +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub struct Keypair(ffi::Keypair); +impl_fast_comparisons!(Keypair); + +impl Keypair { + /// Obtains a raw const pointer suitable for use with FFI functions. + #[inline] + #[deprecated(since = "0.25.0", note = "Use Self::as_c_ptr if you need to access the FFI layer")] + pub fn as_ptr(&self) -> *const ffi::Keypair { self.as_c_ptr() } + + /// Obtains a raw mutable pointer suitable for use with FFI functions. + #[inline] + #[deprecated( + since = "0.25.0", + note = "Use Self::as_mut_c_ptr if you need to access the FFI layer" + )] + pub fn as_mut_ptr(&mut self) -> *mut ffi::Keypair { self.as_mut_c_ptr() } + + /// Creates a [`Keypair`] directly from a Secp256k1 secret key. + #[inline] + pub fn from_secret_key(secp: &Secp256k1, sk: &SecretKey) -> Keypair { + unsafe { + let mut kp = ffi::Keypair::new(); + if ffi::secp256k1_keypair_create(secp.ctx.as_ptr(), &mut kp, sk.as_c_ptr()) == 1 { + Keypair(kp) + } else { + panic!("the provided secret key is invalid: it is corrupted or was not produced by Secp256k1 library") + } + } + } + + /// Creates a [`Keypair`] directly from a secret key slice. + /// + /// # Errors + /// + /// [`Error::InvalidSecretKey`] if the provided data has an incorrect length, exceeds Secp256k1 + /// field `p` value or the corresponding public key is not even. + #[inline] + pub fn from_seckey_slice( + secp: &Secp256k1, + data: &[u8], + ) -> Result { + if data.is_empty() || data.len() != constants::SECRET_KEY_SIZE { + return Err(Error::InvalidSecretKey); + } + + unsafe { + let mut kp = ffi::Keypair::new(); + if ffi::secp256k1_keypair_create(secp.ctx.as_ptr(), &mut kp, data.as_c_ptr()) == 1 { + Ok(Keypair(kp)) + } else { + Err(Error::InvalidSecretKey) + } + } + } + + /// Creates a [`Keypair`] directly from a secret key string. + /// + /// # Errors + /// + /// [`Error::InvalidSecretKey`] if corresponding public key for the provided secret key is not even. + #[inline] + pub fn from_seckey_str(secp: &Secp256k1, s: &str) -> Result { + let mut res = [0u8; constants::SECRET_KEY_SIZE]; + match from_hex(s, &mut res) { + Ok(constants::SECRET_KEY_SIZE) => + Keypair::from_seckey_slice(secp, &res[0..constants::SECRET_KEY_SIZE]), + _ => Err(Error::InvalidPublicKey), + } + } + + /// Creates a [`Keypair`] directly from a secret key string and the global [`SECP256K1`] context. + /// + /// # Errors + /// + /// [`Error::InvalidSecretKey`] if corresponding public key for the provided secret key is not even. + #[inline] + #[cfg(feature = "global-context")] + pub fn from_seckey_str_global(s: &str) -> Result { + Keypair::from_seckey_str(SECP256K1, s) + } + + /// Generates a new random key pair. + /// # Examples + /// + /// ``` + /// # #[cfg(all(feature = "rand", feature = "std"))] { + /// use secp256k1::{rand, Secp256k1, SecretKey, Keypair}; + /// + /// let secp = Secp256k1::new(); + /// let keypair = Keypair::new(&secp, &mut rand::thread_rng()); + /// # } + /// ``` + #[inline] + #[cfg(feature = "rand")] + pub fn new(secp: &Secp256k1, rng: &mut R) -> Keypair { + let mut data = crate::random_32_bytes(rng); + unsafe { + let mut keypair = ffi::Keypair::new(); + while ffi::secp256k1_keypair_create(secp.ctx.as_ptr(), &mut keypair, data.as_c_ptr()) + == 0 + { + data = crate::random_32_bytes(rng); + } + Keypair(keypair) + } + } + + /// Generates a new random secret key using the global [`SECP256K1`] context. + #[inline] + #[cfg(all(feature = "global-context", feature = "rand"))] + pub fn new_global(rng: &mut R) -> Keypair { + Keypair::new(SECP256K1, rng) + } + + /// Returns the secret bytes for this key pair. + #[inline] + pub fn secret_bytes(&self) -> [u8; constants::SECRET_KEY_SIZE] { + *SecretKey::from_keypair(self).as_ref() + } + + /// Tweaks a keypair by first converting the public key to an xonly key and tweaking it. + /// + /// # Errors + /// + /// Returns an error if the resulting key would be invalid. + /// + /// NB: Will not error if the tweaked public key has an odd value and can't be used for + /// BIP 340-342 purposes. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(all(feature = "rand", feature = "std"))] { + /// use secp256k1::{Secp256k1, Keypair, Scalar}; + /// + /// let secp = Secp256k1::new(); + /// let tweak = Scalar::random(); + /// + /// let mut keypair = Keypair::new(&secp, &mut rand::thread_rng()); + /// let tweaked = keypair.add_xonly_tweak(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak"); + /// # } + /// ``` + // TODO: Add checked implementation + #[inline] + pub fn add_xonly_tweak( + mut self, + secp: &Secp256k1, + tweak: &Scalar, + ) -> Result { + unsafe { + let err = ffi::secp256k1_keypair_xonly_tweak_add( + secp.ctx.as_ptr(), + &mut self.0, + tweak.as_c_ptr(), + ); + if err != 1 { + return Err(Error::InvalidTweak); + } + + Ok(self) + } + } + + /// Returns the [`SecretKey`] for this [`Keypair`]. + /// + /// This is equivalent to using [`SecretKey::from_keypair`]. + #[inline] + pub fn secret_key(&self) -> SecretKey { SecretKey::from_keypair(self) } + + /// Returns the [`PublicKey`] for this [`Keypair`]. + /// + /// This is equivalent to using [`PublicKey::from_keypair`]. + #[inline] + pub fn public_key(&self) -> PublicKey { PublicKey::from_keypair(self) } + + /// Returns the [`XOnlyPublicKey`] (and its [`Parity`]) for this [`Keypair`]. + /// + /// This is equivalent to using [`XOnlyPublicKey::from_keypair`]. + #[inline] + pub fn x_only_public_key(&self) -> (XOnlyPublicKey, Parity) { + XOnlyPublicKey::from_keypair(self) + } + + /// Constructs a schnorr signature for `msg` using the global [`SECP256K1`] context. + #[inline] + #[cfg(all(feature = "global-context", feature = "rand", feature = "std"))] + pub fn sign_schnorr(&self, msg: &[u8]) -> schnorr::Signature { + SECP256K1.sign_schnorr(msg, self) + } + + /// Constructs a schnorr signature without aux rand for `msg` using the global + /// [`SECP256K1`] context. + #[inline] + #[cfg(all(feature = "global-context", feature = "std"))] + pub fn sign_schnorr_no_aux_rand(&self, msg: &[u8]) -> schnorr::Signature { + SECP256K1.sign_schnorr_no_aux_rand(msg, self) + } + + /// Attempts to erase the secret within the underlying array. + /// + /// Note, however, that the compiler is allowed to freely copy or move the contents + /// of this array to other places in memory. Preventing this behavior is very subtle. + /// For more discussion on this, please see the documentation of the + /// [`zeroize`](https://docs.rs/zeroize) crate. + #[inline] + pub fn non_secure_erase(&mut self) { self.0.non_secure_erase(); } +} + +impl fmt::Debug for Keypair { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + f.debug_struct("Keypair") + .field("pubkey", &self.public_key()) + .field("secret", &"") + .finish() + } +} + +impl From for SecretKey { + #[inline] + fn from(pair: Keypair) -> Self { SecretKey::from_keypair(&pair) } +} + +impl<'a> From<&'a Keypair> for SecretKey { + #[inline] + fn from(pair: &'a Keypair) -> Self { SecretKey::from_keypair(pair) } +} + +impl From for PublicKey { + #[inline] + fn from(pair: Keypair) -> Self { PublicKey::from_keypair(&pair) } +} + +impl<'a> From<&'a Keypair> for PublicKey { + #[inline] + fn from(pair: &'a Keypair) -> Self { PublicKey::from_keypair(pair) } +} + +#[cfg(any(feature = "global-context", feature = "alloc"))] +impl str::FromStr for Keypair { + type Err = Error; + + #[allow(unused_variables, unreachable_code)] // When built with no default features. + fn from_str(s: &str) -> Result { + #[cfg(feature = "global-context")] + let ctx = SECP256K1; + + #[cfg(all(not(feature = "global-context"), feature = "alloc"))] + let ctx = Secp256k1::signing_only(); + + #[allow(clippy::needless_borrow)] + Keypair::from_seckey_str(&ctx, s) + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for Keypair { + fn serialize(&self, s: S) -> Result { + if s.is_human_readable() { + let mut buf = [0u8; constants::SECRET_KEY_SIZE * 2]; + s.serialize_str( + crate::to_hex(&self.secret_bytes(), &mut buf) + .expect("fixed-size hex serialization"), + ) + } else { + let mut tuple = s.serialize_tuple(constants::SECRET_KEY_SIZE)?; + for byte in self.secret_bytes().iter() { + tuple.serialize_element(&byte)?; + } + tuple.end() + } + } +} + +#[cfg(feature = "serde")] +#[allow(unused_variables)] // For `data` under some feature combinations (the unconditional panic below). +#[cfg(all(feature = "serde", any(feature = "global-context", feature = "alloc")))] +impl<'de> serde::Deserialize<'de> for Keypair { + fn deserialize>(d: D) -> Result { + if d.is_human_readable() { + d.deserialize_str(super::serde_util::FromStrVisitor::new( + "a hex string representing 32 byte Keypair", + )) + } else { + let visitor = super::serde_util::Tuple32Visitor::new("raw 32 bytes Keypair", |data| { + #[cfg(feature = "global-context")] + let ctx = SECP256K1; + + #[cfg(all(not(feature = "global-context"), feature = "alloc"))] + let ctx = Secp256k1::signing_only(); + + #[allow(clippy::needless_borrow)] + Keypair::from_seckey_slice(&ctx, data) + }); + d.deserialize_tuple(constants::SECRET_KEY_SIZE, visitor) + } + } +} + +impl CPtr for Keypair { + type Target = ffi::Keypair; + fn as_c_ptr(&self) -> *const Self::Target { &self.0 } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { &mut self.0 } +} + +/// An x-only public key, used for verification of Taproot signatures and serialized according to BIP-340. +/// +/// # Serde support +/// +/// Implements de/serialization with the `serde` feature enabled. We treat the byte value as a tuple +/// of 32 `u8`s for non-human-readable formats. This representation is optimal for some formats +/// (e.g. [`bincode`]) however other formats may be less optimal (e.g. [`cbor`]). +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// # #[cfg(all(feature = "rand", feature = "std"))] { +/// use secp256k1::{rand, Secp256k1, Keypair, XOnlyPublicKey}; +/// +/// let secp = Secp256k1::new(); +/// let keypair = Keypair::new(&secp, &mut rand::thread_rng()); +/// let xonly = XOnlyPublicKey::from_keypair(&keypair); +/// # } +/// ``` +/// [`bincode`]: https://docs.rs/bincode +/// [`cbor`]: https://docs.rs/cbor +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub struct XOnlyPublicKey(ffi::XOnlyPublicKey); +impl_fast_comparisons!(XOnlyPublicKey); + +impl fmt::LowerHex for XOnlyPublicKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let ser = self.serialize(); + for ch in &ser[..] { + write!(f, "{:02x}", *ch)?; + } + Ok(()) + } +} + +impl fmt::Display for XOnlyPublicKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) } +} + +impl fmt::Debug for XOnlyPublicKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) } +} + +impl str::FromStr for XOnlyPublicKey { + type Err = Error; + fn from_str(s: &str) -> Result { + let mut res = [0u8; constants::SCHNORR_PUBLIC_KEY_SIZE]; + match from_hex(s, &mut res) { + Ok(constants::SCHNORR_PUBLIC_KEY_SIZE) => XOnlyPublicKey::from_byte_array(&res), + _ => Err(Error::InvalidPublicKey), + } + } +} + +impl XOnlyPublicKey { + /// Obtains a raw const pointer suitable for use with FFI functions. + #[inline] + #[deprecated(since = "0.25.0", note = "Use Self::as_c_ptr if you need to access the FFI layer")] + pub fn as_ptr(&self) -> *const ffi::XOnlyPublicKey { self.as_c_ptr() } + + /// Obtains a raw mutable pointer suitable for use with FFI functions. + #[inline] + #[deprecated( + since = "0.25.0", + note = "Use Self::as_mut_c_ptr if you need to access the FFI layer" + )] + pub fn as_mut_ptr(&mut self) -> *mut ffi::XOnlyPublicKey { self.as_mut_c_ptr() } + + /// Returns the [`XOnlyPublicKey`] (and its [`Parity`]) for `keypair`. + #[inline] + pub fn from_keypair(keypair: &Keypair) -> (XOnlyPublicKey, Parity) { + let mut pk_parity = 0; + unsafe { + let mut xonly_pk = ffi::XOnlyPublicKey::new(); + let ret = ffi::secp256k1_keypair_xonly_pub( + ffi::secp256k1_context_no_precomp, + &mut xonly_pk, + &mut pk_parity, + keypair.as_c_ptr(), + ); + debug_assert_eq!(ret, 1); + let parity = + Parity::from_i32(pk_parity).expect("should not panic, pk_parity is 0 or 1"); + + (XOnlyPublicKey(xonly_pk), parity) + } + } + + /// Creates a schnorr public key directly from a slice. + /// + /// # Errors + /// + /// Returns [`Error::InvalidPublicKey`] if the length of the data slice is not 32 bytes or the + /// slice does not represent a valid Secp256k1 point x coordinate. + #[deprecated(since = "TBD", note = "Use `from_byte_array` instead.")] + #[inline] + pub fn from_slice(data: &[u8]) -> Result { + match <[u8; constants::SCHNORR_PUBLIC_KEY_SIZE]>::try_from(data) { + Ok(data) => Self::from_byte_array(&data), + Err(_) => Err(InvalidPublicKey), + } + } + + /// Creates a schnorr public key directly from a byte array. + /// + /// # Errors + /// + /// Returns [`Error::InvalidPublicKey`] if the array does not represent a valid Secp256k1 point + /// x coordinate. + #[inline] + pub fn from_byte_array( + data: &[u8; constants::SCHNORR_PUBLIC_KEY_SIZE], + ) -> Result { + unsafe { + let mut pk = ffi::XOnlyPublicKey::new(); + if ffi::secp256k1_xonly_pubkey_parse( + ffi::secp256k1_context_no_precomp, + &mut pk, + data.as_c_ptr(), + ) == 1 + { + Ok(XOnlyPublicKey(pk)) + } else { + Err(Error::InvalidPublicKey) + } + } + } + + #[inline] + /// Serializes the key as a byte-encoded x coordinate value (32 bytes). + pub fn serialize(&self) -> [u8; constants::SCHNORR_PUBLIC_KEY_SIZE] { + let mut ret = [0u8; constants::SCHNORR_PUBLIC_KEY_SIZE]; + + unsafe { + let err = ffi::secp256k1_xonly_pubkey_serialize( + ffi::secp256k1_context_no_precomp, + ret.as_mut_c_ptr(), + self.as_c_ptr(), + ); + debug_assert_eq!(err, 1); + } + ret + } + + /// Tweaks an [`XOnlyPublicKey`] by adding the generator multiplied with the given tweak to it. + /// + /// # Returns + /// + /// The newly tweaked key plus an opaque type representing the parity of the tweaked key, this + /// should be provided to `tweak_add_check` which can be used to verify a tweak more efficiently + /// than regenerating it and checking equality. + /// + /// # Errors + /// + /// If the resulting key would be invalid. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(all(feature = "rand", feature = "std"))] { + /// use secp256k1::{Secp256k1, Keypair, Scalar, XOnlyPublicKey}; + /// + /// let secp = Secp256k1::new(); + /// let tweak = Scalar::random(); + /// + /// let mut keypair = Keypair::new(&secp, &mut rand::thread_rng()); + /// let (xonly, _parity) = keypair.x_only_public_key(); + /// let tweaked = xonly.add_tweak(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak"); + /// # } + /// ``` + pub fn add_tweak( + mut self, + secp: &Secp256k1, + tweak: &Scalar, + ) -> Result<(XOnlyPublicKey, Parity), Error> { + let mut pk_parity = 0; + unsafe { + let mut pubkey = ffi::PublicKey::new(); + let mut err = ffi::secp256k1_xonly_pubkey_tweak_add( + secp.ctx.as_ptr(), + &mut pubkey, + self.as_c_ptr(), + tweak.as_c_ptr(), + ); + if err != 1 { + return Err(Error::InvalidTweak); + } + + err = ffi::secp256k1_xonly_pubkey_from_pubkey( + secp.ctx.as_ptr(), + &mut self.0, + &mut pk_parity, + &pubkey, + ); + if err == 0 { + return Err(Error::InvalidPublicKey); + } + + let parity = Parity::from_i32(pk_parity)?; + Ok((self, parity)) + } + } + + /// Verifies that a tweak produced by [`XOnlyPublicKey::add_tweak`] was computed correctly. + /// + /// Should be called on the original untweaked key. Takes the tweaked key and output parity from + /// [`XOnlyPublicKey::add_tweak`] as input. + /// + /// Currently this is not much more efficient than just recomputing the tweak and checking + /// equality. However, in future this API will support batch verification, which is + /// significantly faster, so it is wise to design protocols with this in mind. + /// + /// # Returns + /// + /// True if tweak and check is successful, false otherwise. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(all(feature = "rand", feature = "std"))] { + /// use secp256k1::{Secp256k1, Keypair, Scalar}; + /// + /// let secp = Secp256k1::new(); + /// let tweak = Scalar::random(); + /// + /// let mut keypair = Keypair::new(&secp, &mut rand::thread_rng()); + /// let (mut public_key, _) = keypair.x_only_public_key(); + /// let original = public_key; + /// let (tweaked, parity) = public_key.add_tweak(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak"); + /// assert!(original.tweak_add_check(&secp, &tweaked, parity, tweak)); + /// # } + /// ``` + pub fn tweak_add_check( + &self, + secp: &Secp256k1, + tweaked_key: &Self, + tweaked_parity: Parity, + tweak: Scalar, + ) -> bool { + let tweaked_ser = tweaked_key.serialize(); + unsafe { + let err = ffi::secp256k1_xonly_pubkey_tweak_add_check( + secp.ctx.as_ptr(), + tweaked_ser.as_c_ptr(), + tweaked_parity.to_i32(), + &self.0, + tweak.as_c_ptr(), + ); + + err == 1 + } + } + + /// Returns the [`PublicKey`] for this [`XOnlyPublicKey`]. + /// + /// This is equivalent to using [`PublicKey::from_xonly_and_parity(self, parity)`]. + #[inline] + pub fn public_key(&self, parity: Parity) -> PublicKey { + PublicKey::from_x_only_public_key(*self, parity) + } + + /// Checks that `sig` is a valid schnorr signature for `msg` using this public key. + pub fn verify( + &self, + secp: &Secp256k1, + msg: &[u8], + sig: &schnorr::Signature, + ) -> Result<(), Error> { + secp.verify_schnorr(sig, msg, self) + } +} + +/// Represents the parity passed between FFI function calls. +#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)] +pub enum Parity { + /// Even parity. + Even = 0, + /// Odd parity. + Odd = 1, +} + +impl Parity { + /// Converts parity into an integer (byte) value. + /// + /// This returns `0` for even parity and `1` for odd parity. + pub fn to_u8(self) -> u8 { self as u8 } + + /// Converts parity into an integer value. + /// + /// This returns `0` for even parity and `1` for odd parity. + pub fn to_i32(self) -> i32 { self as i32 } + + /// Constructs a [`Parity`] from a byte. + /// + /// The only allowed values are `0` meaning even parity and `1` meaning odd. + /// Other values result in error being returned. + pub fn from_u8(parity: u8) -> Result { + Parity::from_i32(parity.into()) + } + + /// Constructs a [`Parity`] from a signed integer. + /// + /// The only allowed values are `0` meaning even parity and `1` meaning odd. + /// Other values result in error being returned. + pub fn from_i32(parity: i32) -> Result { + match parity { + 0 => Ok(Parity::Even), + 1 => Ok(Parity::Odd), + _ => Err(InvalidParityValue(parity)), + } + } +} + +/// `Even` for `0`, `Odd` for `1`, error for anything else +impl TryFrom for Parity { + type Error = InvalidParityValue; + + fn try_from(parity: i32) -> Result { Self::from_i32(parity) } +} + +/// `Even` for `0`, `Odd` for `1`, error for anything else +impl TryFrom for Parity { + type Error = InvalidParityValue; + + fn try_from(parity: u8) -> Result { Self::from_u8(parity) } +} + +/// The conversion returns `0` for even parity and `1` for odd. +impl From for i32 { + fn from(parity: Parity) -> i32 { parity.to_i32() } +} + +/// The conversion returns `0` for even parity and `1` for odd. +impl From for u8 { + fn from(parity: Parity) -> u8 { parity.to_u8() } +} + +/// Returns even parity if the operands are equal, odd otherwise. +impl BitXor for Parity { + type Output = Parity; + + fn bitxor(self, rhs: Parity) -> Self::Output { + // This works because Parity has only two values (i.e. only 1 bit of information). + if self == rhs { + Parity::Even // 1^1==0 and 0^0==0 + } else { + Parity::Odd // 1^0==1 and 0^1==1 + } + } +} + +/// Error returned when conversion from an integer to `Parity` fails. +// +// Note that we don't allow inspecting the value because we may change the type. +// Yes, this comment is intentionally NOT doc comment. +// Too many derives for compatibility with current Error type. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct InvalidParityValue(i32); + +impl fmt::Display for InvalidParityValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "invalid value {} for Parity - must be 0 or 1", self.0) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for InvalidParityValue {} + +impl From for Error { + fn from(error: InvalidParityValue) -> Self { Error::InvalidParityValue(error) } +} + +/// The parity is serialized as `u8` - `0` for even, `1` for odd. +#[cfg(feature = "serde")] +impl serde::Serialize for Parity { + fn serialize(&self, s: S) -> Result { + s.serialize_u8(self.to_u8()) + } +} + +/// The parity is deserialized as `u8` - `0` for even, `1` for odd. +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for Parity { + fn deserialize>(d: D) -> Result { + struct Visitor; + + impl<'de> serde::de::Visitor<'de> for Visitor { + type Value = Parity; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("8-bit integer (byte) with value 0 or 1") + } + + fn visit_u8(self, v: u8) -> Result + where + E: serde::de::Error, + { + use serde::de::Unexpected; + + Parity::from_u8(v) + .map_err(|_| E::invalid_value(Unexpected::Unsigned(v.into()), &"0 or 1")) + } + } + + d.deserialize_u8(Visitor) + } +} + +impl CPtr for XOnlyPublicKey { + type Target = ffi::XOnlyPublicKey; + fn as_c_ptr(&self) -> *const Self::Target { &self.0 } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { &mut self.0 } +} + +/// Creates a new schnorr public key from a FFI x-only public key. +impl From for XOnlyPublicKey { + #[inline] + fn from(pk: ffi::XOnlyPublicKey) -> XOnlyPublicKey { XOnlyPublicKey(pk) } +} + +impl From for XOnlyPublicKey { + fn from(src: PublicKey) -> XOnlyPublicKey { + unsafe { + let mut pk = ffi::XOnlyPublicKey::new(); + assert_eq!( + 1, + ffi::secp256k1_xonly_pubkey_from_pubkey( + ffi::secp256k1_context_no_precomp, + &mut pk, + ptr::null_mut(), + src.as_c_ptr(), + ) + ); + XOnlyPublicKey(pk) + } + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for XOnlyPublicKey { + fn serialize(&self, s: S) -> Result { + if s.is_human_readable() { + s.collect_str(self) + } else { + let mut tuple = s.serialize_tuple(constants::SCHNORR_PUBLIC_KEY_SIZE)?; + for byte in self.serialize().iter() { + tuple.serialize_element(&byte)?; + } + tuple.end() + } + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for XOnlyPublicKey { + fn deserialize>(d: D) -> Result { + if d.is_human_readable() { + d.deserialize_str(super::serde_util::FromStrVisitor::new( + "a hex string representing 32 byte schnorr public key", + )) + } else { + let visitor = super::serde_util::Tuple32Visitor::new( + "raw 32 bytes schnorr public key", + XOnlyPublicKey::from_slice, + ); + d.deserialize_tuple(constants::SCHNORR_PUBLIC_KEY_SIZE, visitor) + } + } +} + +/// Sort public keys using lexicographic (of compressed serialization) order. +/// Example: +/// +/// ```rust +/// # # [cfg(any(test, feature = "rand-std"))] { +/// # use secp256k1::rand::{thread_rng, RngCore}; +/// # use secp256k1::{Secp256k1, SecretKey, Keypair, PublicKey, pubkey_sort}; +/// # let secp = Secp256k1::new(); +/// # let sk1 = SecretKey::new(&mut thread_rng()); +/// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); +/// # let sk2 = SecretKey::new(&mut thread_rng()); +/// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); +/// # +/// # let pubkeys = [pub_key1, pub_key2]; +/// # let mut pubkeys_ref: Vec<&PublicKey> = pubkeys.iter().collect(); +/// # let pubkeys_ref = pubkeys_ref.as_mut_slice(); +/// # +/// # pubkey_sort(&secp, pubkeys_ref); +/// # } +/// ``` +pub fn pubkey_sort(secp: &Secp256k1, pubkeys: &mut [&PublicKey]) { + let cx = secp.ctx().as_ptr(); + unsafe { + let mut pubkeys_ref = core::slice::from_raw_parts( + pubkeys.as_c_ptr() as *mut *const ffi::PublicKey, + pubkeys.len(), + ); + if secp256k1_ec_pubkey_sort(cx, pubkeys_ref.as_mut_c_ptr(), pubkeys_ref.len()) == 0 { + unreachable!("Invalid public keys for sorting function") + } + } +} + +#[cfg(test)] +#[allow(unused_imports)] +mod test { + use core::str::FromStr; + + #[cfg(not(secp256k1_fuzz))] + use hex_lit::hex; + #[cfg(feature = "rand")] + use rand::{self, rngs::mock::StepRng, RngCore}; + use serde_test::{Configure, Token}; + #[cfg(target_arch = "wasm32")] + use wasm_bindgen_test::wasm_bindgen_test as test; + + use super::{Keypair, Parity, PublicKey, Secp256k1, SecretKey, XOnlyPublicKey, *}; + use crate::Error::{InvalidPublicKey, InvalidSecretKey}; + use crate::{constants, from_hex, to_hex, Scalar}; + + #[test] + fn skey_from_slice() { + let sk = SecretKey::from_slice(&[1; 31]); + assert_eq!(sk, Err(InvalidSecretKey)); + + let sk = SecretKey::from_slice(&[1; 32]); + assert!(sk.is_ok()); + } + + #[test] + fn pubkey_from_slice() { + assert_eq!(PublicKey::from_slice(&[]), Err(InvalidPublicKey)); + assert_eq!(PublicKey::from_slice(&[1, 2, 3]), Err(InvalidPublicKey)); + + let uncompressed = PublicKey::from_slice(&[ + 4, 54, 57, 149, 239, 162, 148, 175, 246, 254, 239, 75, 154, 152, 10, 82, 234, 224, 85, + 220, 40, 100, 57, 121, 30, 162, 94, 156, 135, 67, 74, 49, 179, 57, 236, 53, 162, 124, + 149, 144, 168, 77, 74, 30, 72, 211, 229, 110, 111, 55, 96, 193, 86, 227, 183, 152, 195, + 155, 51, 247, 123, 113, 60, 228, 188, + ]); + assert!(uncompressed.is_ok()); + + let compressed = PublicKey::from_slice(&[ + 3, 23, 183, 225, 206, 31, 159, 148, 195, 42, 67, 115, 146, 41, 248, 140, 11, 3, 51, 41, + 111, 180, 110, 143, 114, 134, 88, 73, 198, 174, 52, 184, 78, + ]); + assert!(compressed.is_ok()); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn keypair_slice_round_trip() { + let s = Secp256k1::new(); + + let (sk1, pk1) = s.generate_keypair(&mut rand::thread_rng()); + assert_eq!(SecretKey::from_slice(&sk1[..]), Ok(sk1)); + assert_eq!(PublicKey::from_slice(&pk1.serialize()[..]), Ok(pk1)); + assert_eq!(PublicKey::from_slice(&pk1.serialize_uncompressed()[..]), Ok(pk1)); + } + + #[test] + #[cfg(all(feature = "std", not(secp256k1_fuzz)))] + fn erased_keypair_is_valid() { + let s = Secp256k1::new(); + let kp = Keypair::from_seckey_slice(&s, &[1u8; constants::SECRET_KEY_SIZE]) + .expect("valid secret key"); + let mut kp2 = kp; + kp2.non_secure_erase(); + assert!(kp.eq_fast_unstable(&kp2)); + } + + #[test] + #[rustfmt::skip] + fn invalid_secret_key() { + // Zero + assert_eq!(SecretKey::from_slice(&[0; 32]), Err(InvalidSecretKey)); + assert_eq!( + SecretKey::from_str("0000000000000000000000000000000000000000000000000000000000000000"), + Err(InvalidSecretKey) + ); + // -1 + assert_eq!(SecretKey::from_slice(&[0xff; 32]), Err(InvalidSecretKey)); + // Top of range + assert!(SecretKey::from_slice(&[ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, + 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40, + ]).is_ok()); + // One past top of range + assert!(SecretKey::from_slice(&[ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, + 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41, + ]).is_err()); + } + + #[test] + fn test_pubkey_from_bad_slice() { + // Bad sizes + assert_eq!( + PublicKey::from_slice(&[0; constants::PUBLIC_KEY_SIZE - 1]), + Err(InvalidPublicKey) + ); + assert_eq!( + PublicKey::from_slice(&[0; constants::PUBLIC_KEY_SIZE + 1]), + Err(InvalidPublicKey) + ); + assert_eq!( + PublicKey::from_slice(&[0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE - 1]), + Err(InvalidPublicKey) + ); + assert_eq!( + PublicKey::from_slice(&[0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE + 1]), + Err(InvalidPublicKey) + ); + + // Bad parse + assert_eq!( + PublicKey::from_slice(&[0xff; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]), + Err(InvalidPublicKey) + ); + assert_eq!( + PublicKey::from_slice(&[0x55; constants::PUBLIC_KEY_SIZE]), + Err(InvalidPublicKey) + ); + assert_eq!(PublicKey::from_slice(&[]), Err(InvalidPublicKey)); + } + + #[test] + fn test_seckey_from_bad_slice() { + // Bad sizes + assert_eq!( + SecretKey::from_slice(&[0; constants::SECRET_KEY_SIZE - 1]), + Err(InvalidSecretKey) + ); + assert_eq!( + SecretKey::from_slice(&[0; constants::SECRET_KEY_SIZE + 1]), + Err(InvalidSecretKey) + ); + // Bad parse + assert_eq!( + SecretKey::from_slice(&[0xff; constants::SECRET_KEY_SIZE]), + Err(InvalidSecretKey) + ); + assert_eq!( + SecretKey::from_slice(&[0x00; constants::SECRET_KEY_SIZE]), + Err(InvalidSecretKey) + ); + assert_eq!(SecretKey::from_slice(&[]), Err(InvalidSecretKey)); + } + + #[test] + #[cfg(all(feature = "rand", feature = "alloc", not(feature = "hashes")))] + fn test_debug_output() { + let s = Secp256k1::new(); + let (sk, _) = s.generate_keypair(&mut StepRng::new(1, 1)); + + assert_eq!( + &format!("{:?}", sk), + "" + ); + + let mut buf = [0u8; constants::SECRET_KEY_SIZE * 2]; + assert_eq!( + to_hex(&sk[..], &mut buf).unwrap(), + "0100000000000000020000000000000003000000000000000400000000000000" + ); + } + + #[test] + #[cfg(feature = "alloc")] + fn test_display_output() { + #[rustfmt::skip] + static SK_BYTES: [u8; 32] = [ + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + ]; + + #[cfg(not(secp256k1_fuzz))] + let s = Secp256k1::signing_only(); + let sk = SecretKey::from_slice(&SK_BYTES).expect("sk"); + + // In fuzzing mode secret->public key derivation is different, so + // hard-code the expected result. + #[cfg(not(secp256k1_fuzz))] + let pk = PublicKey::from_secret_key(&s, &sk); + #[cfg(secp256k1_fuzz)] + let pk = PublicKey::from_slice(&[ + 0x02, 0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f, 0x1c, 0x97, 0x09, 0xe2, 0x30, + 0x92, 0x06, 0x7d, 0x06, 0x83, 0x7f, 0x30, 0xaa, 0x0c, 0xd0, 0x54, 0x4a, 0xc8, 0x87, + 0xfe, 0x91, 0xdd, 0xd1, 0x66, + ]) + .expect("pk"); + + assert_eq!( + sk.display_secret().to_string(), + "01010101010101010001020304050607ffff0000ffff00006363636363636363" + ); + assert_eq!( + SecretKey::from_str("01010101010101010001020304050607ffff0000ffff00006363636363636363") + .unwrap(), + sk + ); + assert_eq!( + pk.to_string(), + "0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166" + ); + assert_eq!( + PublicKey::from_str( + "0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166" + ) + .unwrap(), + pk + ); + assert_eq!( + PublicKey::from_str( + "04\ + 18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166\ + 84B84DB303A340CD7D6823EE88174747D12A67D2F8F2F9BA40846EE5EE7A44F6" + ) + .unwrap(), + pk + ); + + assert!(SecretKey::from_str( + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + ) + .is_err()); + assert!(SecretKey::from_str( + "01010101010101010001020304050607ffff0000ffff0000636363636363636363" + ) + .is_err()); + assert!(SecretKey::from_str( + "01010101010101010001020304050607ffff0000ffff0000636363636363636" + ) + .is_err()); + assert!(SecretKey::from_str( + "01010101010101010001020304050607ffff0000ffff000063636363636363" + ) + .is_err()); + assert!(SecretKey::from_str( + "01010101010101010001020304050607ffff0000ffff000063636363636363xx" + ) + .is_err()); + assert!(PublicKey::from_str( + "0300000000000000000000000000000000000000000000000000000000000000000" + ) + .is_err()); + assert!(PublicKey::from_str( + "0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16601" + ) + .is_err()); + assert!(PublicKey::from_str( + "0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16" + ) + .is_err()); + assert!(PublicKey::from_str( + "0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1" + ) + .is_err()); + assert!(PublicKey::from_str( + "xx0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1" + ) + .is_err()); + + let long_str = "a".repeat(1024 * 1024); + assert!(SecretKey::from_str(&long_str).is_err()); + assert!(PublicKey::from_str(&long_str).is_err()); + } + + #[test] + // In fuzzing mode the Y coordinate is expected to match the X, so this + // test uses invalid public keys. + #[cfg(not(secp256k1_fuzz))] + #[cfg(all(feature = "alloc", feature = "rand"))] + fn test_pubkey_serialize() { + let s = Secp256k1::new(); + let (_, pk1) = s.generate_keypair(&mut StepRng::new(1, 1)); + assert_eq!( + &pk1.serialize_uncompressed()[..], + &[ + 4, 124, 121, 49, 14, 253, 63, 197, 50, 39, 194, 107, 17, 193, 219, 108, 154, 126, + 9, 181, 248, 2, 12, 149, 233, 198, 71, 149, 134, 250, 184, 154, 229, 185, 28, 165, + 110, 27, 3, 162, 126, 238, 167, 157, 242, 221, 76, 251, 237, 34, 231, 72, 39, 245, + 3, 191, 64, 111, 170, 117, 103, 82, 28, 102, 163 + ][..] + ); + assert_eq!( + &pk1.serialize()[..], + &[ + 3, 124, 121, 49, 14, 253, 63, 197, 50, 39, 194, 107, 17, 193, 219, 108, 154, 126, + 9, 181, 248, 2, 12, 149, 233, 198, 71, 149, 134, 250, 184, 154, 229 + ][..] + ); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn tweak_add_arbitrary_data() { + let s = Secp256k1::new(); + + let (sk, pk) = s.generate_keypair(&mut rand::thread_rng()); + assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check. + + // TODO: This would be better tested with a _lot_ of different tweaks. + let tweak = Scalar::random(); + + let tweaked_sk = sk.add_tweak(&tweak).unwrap(); + assert_ne!(sk, tweaked_sk); // Make sure we did something. + let tweaked_pk = pk.add_exp_tweak(&s, &tweak).unwrap(); + assert_ne!(pk, tweaked_pk); + + assert_eq!(PublicKey::from_secret_key(&s, &tweaked_sk), tweaked_pk); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn tweak_add_zero() { + let s = Secp256k1::new(); + + let (sk, pk) = s.generate_keypair(&mut rand::thread_rng()); + + let tweak = Scalar::ZERO; + + let tweaked_sk = sk.add_tweak(&tweak).unwrap(); + assert_eq!(sk, tweaked_sk); // Tweak by zero does nothing. + let tweaked_pk = pk.add_exp_tweak(&s, &tweak).unwrap(); + assert_eq!(pk, tweaked_pk); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn tweak_mul_arbitrary_data() { + let s = Secp256k1::new(); + + let (sk, pk) = s.generate_keypair(&mut rand::thread_rng()); + assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check. + + // TODO: This would be better tested with a _lot_ of different tweaks. + let tweak = Scalar::random(); + + let tweaked_sk = sk.mul_tweak(&tweak).unwrap(); + assert_ne!(sk, tweaked_sk); // Make sure we did something. + let tweaked_pk = pk.mul_tweak(&s, &tweak).unwrap(); + assert_ne!(pk, tweaked_pk); + + assert_eq!(PublicKey::from_secret_key(&s, &tweaked_sk), tweaked_pk); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn tweak_mul_zero() { + let s = Secp256k1::new(); + let (sk, _) = s.generate_keypair(&mut rand::thread_rng()); + + let tweak = Scalar::ZERO; + assert!(sk.mul_tweak(&tweak).is_err()) + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn test_negation() { + let s = Secp256k1::new(); + + let (sk, pk) = s.generate_keypair(&mut rand::thread_rng()); + + assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check. + + let neg = sk.negate(); + assert_ne!(sk, neg); + let back_sk = neg.negate(); + assert_eq!(sk, back_sk); + + let neg = pk.negate(&s); + assert_ne!(pk, neg); + let back_pk = neg.negate(&s); + assert_eq!(pk, back_pk); + + assert_eq!(PublicKey::from_secret_key(&s, &back_sk), pk); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn pubkey_hash() { + use std::collections::hash_map::DefaultHasher; + use std::collections::HashSet; + use std::hash::{Hash, Hasher}; + + fn hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + + let s = Secp256k1::new(); + let mut set = HashSet::new(); + const COUNT: usize = 1024; + for _ in 0..COUNT { + let (_, pk) = s.generate_keypair(&mut rand::thread_rng()); + let hash = hash(&pk); + assert!(!set.contains(&hash)); + set.insert(hash); + } + assert_eq!(set.len(), COUNT); + } + + #[test] + #[cfg(not(secp256k1_fuzz))] + fn pubkey_combine() { + let compressed1 = PublicKey::from_slice(&hex!( + "0241cc121c419921942add6db6482fb36243faf83317c866d2a28d8c6d7089f7ba" + )) + .unwrap(); + let compressed2 = PublicKey::from_slice(&hex!( + "02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443" + )) + .unwrap(); + let exp_sum = PublicKey::from_slice(&hex!( + "0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07" + )) + .unwrap(); + + let sum1 = compressed1.combine(&compressed2); + assert!(sum1.is_ok()); + let sum2 = compressed2.combine(&compressed1); + assert!(sum2.is_ok()); + assert_eq!(sum1, sum2); + assert_eq!(sum1.unwrap(), exp_sum); + } + + #[test] + #[cfg(not(secp256k1_fuzz))] + fn pubkey_combine_keys() { + let compressed1 = PublicKey::from_slice(&hex!( + "0241cc121c419921942add6db6482fb36243faf83317c866d2a28d8c6d7089f7ba" + )) + .unwrap(); + let compressed2 = PublicKey::from_slice(&hex!( + "02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443" + )) + .unwrap(); + let compressed3 = PublicKey::from_slice(&hex!( + "03e74897d8644eb3e5b391ca2ab257aec2080f4d1a95cad57e454e47f021168eb0" + )) + .unwrap(); + let exp_sum = PublicKey::from_slice(&hex!( + "0252d73a47f66cf341e5651542f0348f452b7c793af62a6d8bff75ade703a451ad" + )) + .unwrap(); + + let sum1 = PublicKey::combine_keys(&[&compressed1, &compressed2, &compressed3]); + assert!(sum1.is_ok()); + let sum2 = PublicKey::combine_keys(&[&compressed1, &compressed2, &compressed3]); + assert!(sum2.is_ok()); + assert_eq!(sum1, sum2); + assert_eq!(sum1.unwrap(), exp_sum); + } + + #[test] + #[cfg(not(secp256k1_fuzz))] + fn pubkey_combine_keys_empty_slice() { + assert!(PublicKey::combine_keys(&[]).is_err()); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn create_pubkey_combine() { + let s = Secp256k1::new(); + + let (sk1, pk1) = s.generate_keypair(&mut rand::thread_rng()); + let (sk2, pk2) = s.generate_keypair(&mut rand::thread_rng()); + + let sum1 = pk1.combine(&pk2); + assert!(sum1.is_ok()); + let sum2 = pk2.combine(&pk1); + assert!(sum2.is_ok()); + assert_eq!(sum1, sum2); + + let tweaked = sk1.add_tweak(&Scalar::from(sk2)).unwrap(); + let sksum = PublicKey::from_secret_key(&s, &tweaked); + assert_eq!(Ok(sksum), sum1); + } + + #[cfg(not(secp256k1_fuzz))] + #[test] + #[allow(clippy::nonminimal_bool)] + fn pubkey_equal() { + let pk1 = PublicKey::from_slice(&hex!( + "0241cc121c419921942add6db6482fb36243faf83317c866d2a28d8c6d7089f7ba" + )) + .unwrap(); + let pk2 = pk1; + let pk3 = PublicKey::from_slice(&hex!( + "02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443" + )) + .unwrap(); + + assert_eq!(pk1, pk2); + assert!(pk1 <= pk2); + assert!(pk2 <= pk1); + assert!(!(pk2 < pk1)); + assert!(!(pk1 < pk2)); + + assert!(pk3 > pk1); + assert!(pk1 < pk3); + assert!(pk3 >= pk1); + assert!(pk1 <= pk3); + } + + #[test] + #[cfg(all(feature = "serde", feature = "alloc"))] + fn test_serde() { + use serde_test::{assert_tokens, Configure, Token}; + #[rustfmt::skip] + static SK_BYTES: [u8; 32] = [ + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 2, 3, 4, 5, 6, 7, + 0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0, + 99, 99, 99, 99, 99, 99, 99, 99 + ]; + static SK_STR: &str = "01010101010101010001020304050607ffff0000ffff00006363636363636363"; + + #[cfg(secp256k1_fuzz)] + #[rustfmt::skip] + static PK_BYTES: [u8; 33] = [ + 0x02, + 0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f, + 0x1c, 0x97, 0x09, 0xe2, 0x30, 0x92, 0x06, 0x7d, + 0x06, 0x83, 0x7f, 0x30, 0xaa, 0x0c, 0xd0, 0x54, + 0x4a, 0xc8, 0x87, 0xfe, 0x91, 0xdd, 0xd1, 0x66, + ]; + static PK_STR: &str = "0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"; + + #[cfg(not(secp256k1_fuzz))] + let s = Secp256k1::new(); + let sk = SecretKey::from_slice(&SK_BYTES).unwrap(); + + // In fuzzing mode secret->public key derivation is different, so + // hard-code the expected result. + #[cfg(not(secp256k1_fuzz))] + let pk = PublicKey::from_secret_key(&s, &sk); + #[cfg(secp256k1_fuzz)] + let pk = PublicKey::from_slice(&PK_BYTES).expect("pk"); + + #[rustfmt::skip] + assert_tokens(&sk.compact(), &[ + Token::Tuple{ len: 32 }, + Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), + Token::U8(0), Token::U8(1), Token::U8(2), Token::U8(3), Token::U8(4), Token::U8(5), Token::U8(6), Token::U8(7), + Token::U8(0xff), Token::U8(0xff), Token::U8(0), Token::U8(0), Token::U8(0xff), Token::U8(0xff), Token::U8(0), Token::U8(0), + Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), + Token::TupleEnd + ]); + + assert_tokens(&sk.readable(), &[Token::BorrowedStr(SK_STR)]); + assert_tokens(&sk.readable(), &[Token::Str(SK_STR)]); + assert_tokens(&sk.readable(), &[Token::String(SK_STR)]); + + #[rustfmt::skip] + assert_tokens(&pk.compact(), &[ + Token::Tuple{ len: 33 }, + Token::U8(0x02), + Token::U8(0x18), Token::U8(0x84), Token::U8(0x57), Token::U8(0x81), Token::U8(0xf6), Token::U8(0x31), Token::U8(0xc4), Token::U8(0x8f), + Token::U8(0x1c), Token::U8(0x97), Token::U8(0x09), Token::U8(0xe2), Token::U8(0x30), Token::U8(0x92), Token::U8(0x06), Token::U8(0x7d), + Token::U8(0x06), Token::U8(0x83), Token::U8(0x7f), Token::U8(0x30), Token::U8(0xaa), Token::U8(0x0c), Token::U8(0xd0), Token::U8(0x54), + Token::U8(0x4a), Token::U8(0xc8), Token::U8(0x87), Token::U8(0xfe), Token::U8(0x91), Token::U8(0xdd), Token::U8(0xd1), Token::U8(0x66), + Token::TupleEnd + ]); + + assert_tokens(&pk.readable(), &[Token::BorrowedStr(PK_STR)]); + assert_tokens(&pk.readable(), &[Token::Str(PK_STR)]); + assert_tokens(&pk.readable(), &[Token::String(PK_STR)]); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn test_tweak_add_then_tweak_add_check() { + let s = Secp256k1::new(); + + // TODO: 10 times is arbitrary, we should test this a _lot_ of times. + for _ in 0..10 { + let tweak = Scalar::random(); + + let kp = Keypair::new(&s, &mut rand::thread_rng()); + let (xonly, _) = XOnlyPublicKey::from_keypair(&kp); + + let tweaked_kp = kp.add_xonly_tweak(&s, &tweak).expect("keypair tweak add failed"); + let (tweaked_xonly, parity) = + xonly.add_tweak(&s, &tweak).expect("xonly pubkey tweak failed"); + + let (want_tweaked_xonly, tweaked_kp_parity) = XOnlyPublicKey::from_keypair(&tweaked_kp); + + assert_eq!(tweaked_xonly, want_tweaked_xonly); + assert_eq!(parity, tweaked_kp_parity); + + assert!(xonly.tweak_add_check(&s, &tweaked_xonly, parity, tweak)); + } + } + + #[test] + fn test_from_key_pubkey() { + let kpk1 = PublicKey::from_str( + "02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443", + ) + .unwrap(); + let kpk2 = PublicKey::from_str( + "0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07", + ) + .unwrap(); + + let pk1 = XOnlyPublicKey::from(kpk1); + let pk2 = XOnlyPublicKey::from(kpk2); + + assert_eq!(pk1.serialize()[..], kpk1.serialize()[1..]); + assert_eq!(pk2.serialize()[..], kpk2.serialize()[1..]); + } + + #[test] + #[cfg(all(feature = "global-context", feature = "serde"))] + fn test_serde_keypair() { + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + use serde_test::{assert_tokens, Configure, Token}; + + use crate::key::Keypair; + use crate::SECP256K1; + + #[rustfmt::skip] + static SK_BYTES: [u8; 32] = [ + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 2, 3, 4, 5, 6, 7, + 0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0, + 99, 99, 99, 99, 99, 99, 99, 99 + ]; + static SK_STR: &str = "01010101010101010001020304050607ffff0000ffff00006363636363636363"; + + let sk = Keypair::from_seckey_slice(SECP256K1, &SK_BYTES).unwrap(); + #[rustfmt::skip] + assert_tokens(&sk.compact(), &[ + Token::Tuple{ len: 32 }, + Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), + Token::U8(0), Token::U8(1), Token::U8(2), Token::U8(3), Token::U8(4), Token::U8(5), Token::U8(6), Token::U8(7), + Token::U8(0xff), Token::U8(0xff), Token::U8(0), Token::U8(0), Token::U8(0xff), Token::U8(0xff), Token::U8(0), Token::U8(0), + Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), + Token::TupleEnd + ]); + + assert_tokens(&sk.readable(), &[Token::BorrowedStr(SK_STR)]); + assert_tokens(&sk.readable(), &[Token::Str(SK_STR)]); + assert_tokens(&sk.readable(), &[Token::String(SK_STR)]); + } + + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + fn keys() -> (SecretKey, PublicKey, Keypair, XOnlyPublicKey) { + let secp = Secp256k1::new(); + + #[rustfmt::skip] + static SK_BYTES: [u8; 32] = [ + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + ]; + + #[rustfmt::skip] + static PK_BYTES: [u8; 32] = [ + 0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f, + 0x1c, 0x97, 0x09, 0xe2, 0x30, 0x92, 0x06, 0x7d, + 0x06, 0x83, 0x7f, 0x30, 0xaa, 0x0c, 0xd0, 0x54, + 0x4a, 0xc8, 0x87, 0xfe, 0x91, 0xdd, 0xd1, 0x66 + ]; + + let mut pk_bytes = [0u8; 33]; + pk_bytes[0] = 0x02; // Use positive Y co-ordinate. + pk_bytes[1..].clone_from_slice(&PK_BYTES); + + let sk = SecretKey::from_slice(&SK_BYTES).expect("failed to parse sk bytes"); + let pk = PublicKey::from_slice(&pk_bytes).expect("failed to create pk from iterator"); + let kp = Keypair::from_secret_key(&secp, &sk); + let xonly = XOnlyPublicKey::from_slice(&PK_BYTES).expect("failed to get xonly from slice"); + + (sk, pk, kp, xonly) + } + + #[test] + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + fn convert_public_key_to_xonly_public_key() { + let (_sk, pk, _kp, want) = keys(); + let (got, parity) = pk.x_only_public_key(); + + assert_eq!(parity, Parity::Even); + assert_eq!(got, want) + } + + #[test] + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + fn convert_secret_key_to_public_key() { + let secp = Secp256k1::new(); + + let (sk, want, _kp, _xonly) = keys(); + let got = sk.public_key(&secp); + + assert_eq!(got, want) + } + + #[test] + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + fn convert_secret_key_to_x_only_public_key() { + let secp = Secp256k1::new(); + + let (sk, _pk, _kp, want) = keys(); + let (got, parity) = sk.x_only_public_key(&secp); + + assert_eq!(parity, Parity::Even); + assert_eq!(got, want) + } + + #[test] + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + fn convert_keypair_to_public_key() { + let (_sk, want, kp, _xonly) = keys(); + let got = kp.public_key(); + + assert_eq!(got, want) + } + + #[test] + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + fn convert_keypair_to_x_only_public_key() { + let (_sk, _pk, kp, want) = keys(); + let (got, parity) = kp.x_only_public_key(); + + assert_eq!(parity, Parity::Even); + assert_eq!(got, want) + } + + // SecretKey -> Keypair -> SecretKey + #[test] + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + fn roundtrip_secret_key_via_keypair() { + let secp = Secp256k1::new(); + let (sk, _pk, _kp, _xonly) = keys(); + + let kp = sk.keypair(&secp); + let back = kp.secret_key(); + + assert_eq!(back, sk) + } + + // Keypair -> SecretKey -> Keypair + #[test] + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + fn roundtrip_keypair_via_secret_key() { + let secp = Secp256k1::new(); + let (_sk, _pk, kp, _xonly) = keys(); + + let sk = kp.secret_key(); + let back = sk.keypair(&secp); + + assert_eq!(back, kp) + } + + // XOnlyPublicKey -> PublicKey -> XOnlyPublicKey + #[test] + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + fn roundtrip_x_only_public_key_via_public_key() { + let (_sk, _pk, _kp, xonly) = keys(); + + let pk = xonly.public_key(Parity::Even); + let (back, parity) = pk.x_only_public_key(); + + assert_eq!(parity, Parity::Even); + assert_eq!(back, xonly) + } + + // PublicKey -> XOnlyPublicKey -> PublicKey + #[test] + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + fn roundtrip_public_key_via_x_only_public_key() { + let (_sk, pk, _kp, _xonly) = keys(); + + let (xonly, parity) = pk.x_only_public_key(); + let back = xonly.public_key(parity); + + assert_eq!(back, pk) + } + + #[test] + fn public_key_from_x_only_public_key_and_odd_parity() { + let s = "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"; + let mut want = String::from("03"); + want.push_str(s); + + let xonly = XOnlyPublicKey::from_str(s).expect("failed to parse xonly pubkey string"); + let pk = xonly.public_key(Parity::Odd); + let got = format!("{}", pk); + + assert_eq!(got, want) + } + + #[test] + #[cfg(not(secp256k1_fuzz))] + #[cfg(all(feature = "global-context", feature = "serde"))] + fn test_serde_x_only_pubkey() { + use serde_test::{assert_tokens, Configure, Token}; + + #[rustfmt::skip] + static SK_BYTES: [u8; 32] = [ + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 2, 3, 4, 5, 6, 7, + 0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0, + 99, 99, 99, 99, 99, 99, 99, 99 + ]; + + static PK_STR: &str = "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"; + + let kp = Keypair::from_seckey_slice(crate::SECP256K1, &SK_BYTES).unwrap(); + let (pk, _parity) = XOnlyPublicKey::from_keypair(&kp); + + #[rustfmt::skip] + assert_tokens(&pk.compact(), &[ + Token::Tuple{ len: 32 }, + Token::U8(0x18), Token::U8(0x84), Token::U8(0x57), Token::U8(0x81), Token::U8(0xf6), Token::U8(0x31), Token::U8(0xc4), Token::U8(0x8f), + Token::U8(0x1c), Token::U8(0x97), Token::U8(0x09), Token::U8(0xe2), Token::U8(0x30), Token::U8(0x92), Token::U8(0x06), Token::U8(0x7d), + Token::U8(0x06), Token::U8(0x83), Token::U8(0x7f), Token::U8(0x30), Token::U8(0xaa), Token::U8(0x0c), Token::U8(0xd0), Token::U8(0x54), + Token::U8(0x4a), Token::U8(0xc8), Token::U8(0x87), Token::U8(0xfe), Token::U8(0x91), Token::U8(0xdd), Token::U8(0xd1), Token::U8(0x66), + Token::TupleEnd + ]); + + assert_tokens(&pk.readable(), &[Token::BorrowedStr(PK_STR)]); + assert_tokens(&pk.readable(), &[Token::Str(PK_STR)]); + assert_tokens(&pk.readable(), &[Token::String(PK_STR)]); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn test_keypair_from_str() { + let ctx = crate::Secp256k1::new(); + let keypair = Keypair::new(&ctx, &mut rand::thread_rng()); + let mut buf = [0_u8; constants::SECRET_KEY_SIZE * 2]; // Holds hex digits. + let s = to_hex(&keypair.secret_key().secret_bytes(), &mut buf).unwrap(); + let parsed_key = Keypair::from_str(s).unwrap(); + assert_eq!(parsed_key, keypair); + } + + #[test] + #[cfg(all(any(feature = "alloc", feature = "global-context"), feature = "serde"))] + fn test_keypair_deserialize_serde() { + let ctx = crate::Secp256k1::new(); + let sec_key_str = "4242424242424242424242424242424242424242424242424242424242424242"; + let keypair = Keypair::from_seckey_str(&ctx, sec_key_str).unwrap(); + + serde_test::assert_tokens(&keypair.readable(), &[Token::String(sec_key_str)]); + + let sec_key_bytes = keypair.secret_key().secret_bytes(); + let tokens = std::iter::once(Token::Tuple { len: 32 }) + .chain(sec_key_bytes.iter().copied().map(Token::U8)) + .chain(std::iter::once(Token::TupleEnd)) + .collect::>(); + serde_test::assert_tokens(&keypair.compact(), &tokens); + } +} + +#[cfg(bench)] +mod benches { + use std::collections::BTreeSet; + + use test::Bencher; + + use crate::constants::GENERATOR_X; + use crate::PublicKey; + + #[bench] + fn bench_pk_ordering(b: &mut Bencher) { + let mut map = BTreeSet::new(); + let mut g_slice = [02u8; 33]; + g_slice[1..].copy_from_slice(&GENERATOR_X); + let g = PublicKey::from_slice(&g_slice).unwrap(); + let mut pk = g; + b.iter(|| { + map.insert(pk); + pk = pk.combine(&pk).unwrap(); + }) + } +} diff --git a/ark-rust-secp256k1/src/lib.rs b/ark-rust-secp256k1/src/lib.rs new file mode 100644 index 00000000..8473dedc --- /dev/null +++ b/ark-rust-secp256k1/src/lib.rs @@ -0,0 +1,1057 @@ +// SPDX-License-Identifier: CC0-1.0 + +#![allow(warnings)] + +//! Rust bindings for Pieter Wuille's secp256k1 library, which is used for +//! fast and accurate manipulation of ECDSA and Schnorr signatures on the secp256k1 +//! curve. Such signatures are used extensively by the Bitcoin network +//! and its derivatives. +//! +//! To minimize dependencies, some functions are feature-gated. To generate +//! random keys or to re-randomize a context object, compile with the +//! `rand` and `std` features. If you are willing to use these features, we +//! have enabled an additional defense-in-depth sidechannel protection for +//! our context objects, which re-blinds certain operations on secret key +//! data. To de/serialize objects with serde, compile with "serde". +//! **Important**: `serde` encoding is **not** the same as consensus +//! encoding! +//! +//! Where possible, the bindings use the Rust type system to ensure that +//! API usage errors are impossible. For example, the library uses context +//! objects that contain precomputation tables which are created on object +//! construction. Since this is a slow operation (10+ milliseconds, vs ~50 +//! microseconds for typical crypto operations, on a 2.70 Ghz i7-6820HQ) +//! the tables are optional, giving a performance boost for users who only +//! care about signing, only care about verification, or only care about +//! parsing. In the upstream library, if you attempt to sign a message using +//! a context that does not support this, it will trigger an assertion +//! failure and terminate the program. In `rust-secp256k1`, this is caught +//! at compile-time; in fact, it is impossible to compile code that will +//! trigger any assertion failures in the upstream library. +//! +//! ```rust +//! # #[cfg(all(feature = "rand", feature = "hashes", feature = "std"))] { +//! use secp256k1::rand::rngs::OsRng; +//! use secp256k1::{Secp256k1, Message}; +//! use secp256k1::hashes::{sha256, Hash}; +//! +//! let secp = Secp256k1::new(); +//! let (secret_key, public_key) = secp.generate_keypair(&mut OsRng); +//! let digest = sha256::Hash::hash("Hello World!".as_bytes()); +//! let message = Message::from_digest(digest.to_byte_array()); +//! +//! let sig = secp.sign_ecdsa(message, &secret_key); +//! assert!(secp.verify_ecdsa(message, &sig, &public_key).is_ok()); +//! # } +//! ``` +//! +//! If the "global-context" feature is enabled you have access to an alternate API. +//! +//! ```rust +//! # #[cfg(all(feature = "global-context", feature = "hashes", feature = "rand", feature = "std"))] { +//! use secp256k1::{generate_keypair, Message}; +//! use secp256k1::hashes::{sha256, Hash}; +//! +//! let (secret_key, public_key) = generate_keypair(&mut rand::thread_rng()); +//! let digest = sha256::Hash::hash("Hello World!".as_bytes()); +//! let message = Message::from_digest(digest.to_byte_array()); +//! +//! let sig = secret_key.sign_ecdsa(message); +//! assert!(sig.verify(message, &public_key).is_ok()); +//! # } +//! ``` +//! +//! The above code requires `rust-secp256k1` to be compiled with the `rand`, `hashes`, and `std` +//! feature enabled, to get access to [`generate_keypair`](struct.Secp256k1.html#method.generate_keypair) +//! Alternately, keys and messages can be parsed from slices, like +//! +//! ```rust +//! # #[cfg(feature = "alloc")] { +//! use secp256k1::{Secp256k1, Message, SecretKey, PublicKey}; +//! # fn compute_hash(_: &[u8]) -> [u8; 32] { [0xab; 32] } +//! +//! let secp = Secp256k1::new(); +//! let secret_key = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order"); +//! let public_key = PublicKey::from_secret_key(&secp, &secret_key); +//! // If the supplied byte slice was *not* the output of a cryptographic hash function this would +//! // be cryptographically broken. It has been trivially used in the past to execute attacks. +//! let message = Message::from_digest(compute_hash(b"CSW is not Satoshi")); +//! +//! let sig = secp.sign_ecdsa(message, &secret_key); +//! assert!(secp.verify_ecdsa(message, &sig, &public_key).is_ok()); +//! # } +//! ``` +//! +//! Users who only want to verify signatures can use a cheaper context, like so: +//! +//! ```rust +//! # #[cfg(feature = "alloc")] { +//! use secp256k1::{Secp256k1, Message, ecdsa, PublicKey}; +//! +//! let secp = Secp256k1::verification_only(); +//! +//! let public_key = PublicKey::from_slice(&[ +//! 0x02, +//! 0xc6, 0x6e, 0x7d, 0x89, 0x66, 0xb5, 0xc5, 0x55, +//! 0xaf, 0x58, 0x05, 0x98, 0x9d, 0xa9, 0xfb, 0xf8, +//! 0xdb, 0x95, 0xe1, 0x56, 0x31, 0xce, 0x35, 0x8c, +//! 0x3a, 0x17, 0x10, 0xc9, 0x62, 0x67, 0x90, 0x63, +//! ]).expect("public keys must be 33 or 65 bytes, serialized according to SEC 2"); +//! +//! let message = Message::from_digest([ +//! 0xaa, 0xdf, 0x7d, 0xe7, 0x82, 0x03, 0x4f, 0xbe, +//! 0x3d, 0x3d, 0xb2, 0xcb, 0x13, 0xc0, 0xcd, 0x91, +//! 0xbf, 0x41, 0xcb, 0x08, 0xfa, 0xc7, 0xbd, 0x61, +//! 0xd5, 0x44, 0x53, 0xcf, 0x6e, 0x82, 0xb4, 0x50, +//! ]); +//! +//! let sig = ecdsa::Signature::from_compact(&[ +//! 0xdc, 0x4d, 0xc2, 0x64, 0xa9, 0xfe, 0xf1, 0x7a, +//! 0x3f, 0x25, 0x34, 0x49, 0xcf, 0x8c, 0x39, 0x7a, +//! 0xb6, 0xf1, 0x6f, 0xb3, 0xd6, 0x3d, 0x86, 0x94, +//! 0x0b, 0x55, 0x86, 0x82, 0x3d, 0xfd, 0x02, 0xae, +//! 0x3b, 0x46, 0x1b, 0xb4, 0x33, 0x6b, 0x5e, 0xcb, +//! 0xae, 0xfd, 0x66, 0x27, 0xaa, 0x92, 0x2e, 0xfc, +//! 0x04, 0x8f, 0xec, 0x0c, 0x88, 0x1c, 0x10, 0xc4, +//! 0xc9, 0x42, 0x8f, 0xca, 0x69, 0xc1, 0x32, 0xa2, +//! ]).expect("compact signatures are 64 bytes; DER signatures are 68-72 bytes"); +//! +//! # #[cfg(not(secp256k1_fuzz))] +//! assert!(secp.verify_ecdsa(message, &sig, &public_key).is_ok()); +//! # } +//! ``` +//! +//! Observe that the same code using, say [`signing_only`](struct.Secp256k1.html#method.signing_only) +//! to generate a context would simply not compile. +//! +//! ## Crate features/optional dependencies +//! +//! This crate provides the following opt-in Cargo features: +//! +//! * `std` - use standard Rust library, enabled by default. +//! * `alloc` - use the `alloc` standard Rust library to provide heap allocations. +//! * `rand` - use `rand` library to provide random generator (e.g. to generate keys). +//! * `hashes` - use the `hashes` library. +//! * `recovery` - enable functions that can compute the public key from signature. +//! * `lowmemory` - optimize the library for low-memory environments. +//! * `global-context` - enable use of global secp256k1 context (implies `std`). +//! * `serde` - implements serialization and deserialization for types in this crate using `serde`. +//! **Important**: `serde` encoding is **not** the same as consensus encoding! +//! + +// Coding conventions +#![deny(non_upper_case_globals, non_camel_case_types, non_snake_case)] +#![warn(missing_docs, missing_copy_implementations, missing_debug_implementations)] +#![cfg_attr(all(not(test), not(feature = "std")), no_std)] +// Experimental features we need. +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(bench, feature(test))] + +#[cfg(feature = "alloc")] +extern crate alloc; +#[cfg(any(test, feature = "std"))] +extern crate core; +#[cfg(bench)] +extern crate test; + +#[cfg(feature = "hashes")] +pub extern crate hashes; + +#[macro_use] +mod macros; +#[macro_use] +mod secret; +mod context; +mod key; + +pub mod constants; +pub mod ecdh; +pub mod ecdsa; +pub mod ellswift; +pub mod musig; +pub mod scalar; +pub mod schnorr; +#[cfg(feature = "serde")] +mod serde_util; + +use core::marker::PhantomData; +use core::ptr::NonNull; +use core::{fmt, mem, str}; + +#[cfg(all(feature = "global-context", feature = "std"))] +pub use context::global::{self, SECP256K1}; +#[cfg(feature = "rand")] +pub use rand; +pub use secp256k1_sys as ffi; +#[cfg(feature = "serde")] +pub use serde; + +#[cfg(feature = "alloc")] +pub use crate::context::{All, SignOnly, VerifyOnly}; +pub use crate::context::{ + AllPreallocated, Context, PreallocatedContext, SignOnlyPreallocated, Signing, Verification, + VerifyOnlyPreallocated, +}; +use crate::ffi::types::AlignedType; +use crate::ffi::CPtr; +pub use crate::key::{ + pubkey_sort, InvalidParityValue, Keypair, Parity, PublicKey, SecretKey, XOnlyPublicKey, +}; +pub use crate::scalar::Scalar; + +/// Trait describing something that promises to be a 32-byte uniformly random number. +/// +/// In particular, anything implementing this trait must have neglibile probability +/// of being zero, overflowing the group order, or equalling any specific value. +/// +/// Since version 0.29 this has been deprecated; users should instead implement +/// `Into` for types that satisfy these properties. +#[deprecated( + since = "0.29.0", + note = "Please see v0.29.0 rust-secp256k1/CHANGELOG.md for suggestion" +)] +pub trait ThirtyTwoByteHash { + /// Converts the object into a 32-byte array + fn into_32(self) -> [u8; 32]; +} + +/// A (hashed) message input to an ECDSA signature. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Message([u8; constants::MESSAGE_SIZE]); +impl_array_newtype!(Message, u8, constants::MESSAGE_SIZE); +impl_pretty_debug!(Message); + +impl Message { + /// Creates a [`Message`] from a 32 byte slice `digest`. + /// + /// Converts a `MESSAGE_SIZE`-byte slice to a message object. **WARNING:** the slice has to be a + /// cryptographically secure hash of the actual message that's going to be signed. Otherwise + /// the result of signing isn't a + /// [secure signature](https://twitter.com/pwuille/status/1063582706288586752). + #[inline] + #[deprecated(since = "0.28.0", note = "use from_digest instead")] + pub fn from_slice(digest: &[u8]) -> Result { + #[allow(deprecated)] + Message::from_digest_slice(digest) + } + + /// Creates a [`Message`] from a `digest`. + /// + /// The `digest` array has to be a cryptographically secure hash of the actual message that's + /// going to be signed. Otherwise the result of signing isn't a [secure signature]. + /// + /// [secure signature]: https://twitter.com/pwuille/status/1063582706288586752 + #[inline] + pub fn from_digest(digest: [u8; 32]) -> Message { Message(digest) } + + /// Creates a [`Message`] from a 32 byte slice `digest`. + /// + /// The slice has to be 32 bytes long and be a cryptographically secure hash of the actual + /// message that's going to be signed. Otherwise the result of signing isn't a [secure + /// signature]. + /// + /// This method is deprecated. It's best to use [`Message::from_digest`] directly with an + /// array. If your hash engine doesn't return an array for some reason use `.try_into()` on its + /// output. + /// + /// # Errors + /// + /// If `digest` is not exactly 32 bytes long. + /// + /// [secure signature]: https://twitter.com/pwuille/status/1063582706288586752 + #[inline] + #[deprecated(since = "TBD", note = "use from_digest instead")] + pub fn from_digest_slice(digest: &[u8]) -> Result { + Ok(Message::from_digest(digest.try_into().map_err(|_| Error::InvalidMessage)?)) + } +} + +#[allow(deprecated)] +impl From for Message { + /// Converts a 32-byte hash directly to a message without error paths. + fn from(t: T) -> Message { Message(t.into_32()) } +} + +impl fmt::LowerHex for Message { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for byte in self.0.iter() { + write!(f, "{:02x}", byte)?; + } + Ok(()) + } +} + +impl fmt::Display for Message { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) } +} + +/// The main error type for this library. +#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug)] +pub enum Error { + /// Signature failed verification. + IncorrectSignature, + /// Bad sized message ("messages" are actually fixed-sized digests [`constants::MESSAGE_SIZE`]). + InvalidMessage, + /// Bad public key. + InvalidPublicKey, + /// Bad signature. + InvalidSignature, + /// Bad secret key. + InvalidSecretKey, + /// Bad shared secret. + InvalidSharedSecret, + /// Bad recovery id. + InvalidRecoveryId, + /// Tried to add/multiply by an invalid tweak. + InvalidTweak, + /// Didn't pass enough memory to context creation with preallocated memory. + NotEnoughMemory, + /// Bad set of public keys. + InvalidPublicKeySum, + /// The only valid parity values are 0 or 1. + InvalidParityValue(key::InvalidParityValue), + /// Bad EllSwift value + InvalidEllSwift, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + use Error::*; + + match *self { + IncorrectSignature => f.write_str("signature failed verification"), + InvalidMessage => f.write_str("message was not 32 bytes (do you need to hash?)"), + InvalidPublicKey => f.write_str("malformed public key"), + InvalidSignature => f.write_str("malformed signature"), + InvalidSecretKey => f.write_str("malformed or out-of-range secret key"), + InvalidSharedSecret => f.write_str("malformed or out-of-range shared secret"), + InvalidRecoveryId => f.write_str("bad recovery id"), + InvalidTweak => f.write_str("bad tweak"), + NotEnoughMemory => f.write_str("not enough memory allocated"), + InvalidPublicKeySum => f.write_str( + "the sum of public keys was invalid or the input vector lengths was less than 1", + ), + InvalidParityValue(e) => write_err!(f, "couldn't create parity"; e), + InvalidEllSwift => f.write_str("malformed EllSwift value"), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Error::IncorrectSignature => None, + Error::InvalidMessage => None, + Error::InvalidPublicKey => None, + Error::InvalidSignature => None, + Error::InvalidSecretKey => None, + Error::InvalidSharedSecret => None, + Error::InvalidRecoveryId => None, + Error::InvalidTweak => None, + Error::NotEnoughMemory => None, + Error::InvalidPublicKeySum => None, + Error::InvalidParityValue(error) => Some(error), + Error::InvalidEllSwift => None, + } + } +} + +/// The secp256k1 engine, used to execute all signature operations. +pub struct Secp256k1 { + ctx: NonNull, + phantom: PhantomData, +} + +// The underlying secp context does not contain any references to memory it does not own. +unsafe impl Send for Secp256k1 {} +// The API does not permit any mutation of `Secp256k1` objects except through `&mut` references. +unsafe impl Sync for Secp256k1 {} + +impl PartialEq for Secp256k1 { + fn eq(&self, _other: &Secp256k1) -> bool { true } +} + +impl Eq for Secp256k1 {} + +impl Drop for Secp256k1 { + fn drop(&mut self) { + unsafe { + let size = ffi::secp256k1_context_preallocated_clone_size(self.ctx.as_ptr()); + ffi::secp256k1_context_preallocated_destroy(self.ctx); + + C::deallocate(self.ctx.as_ptr() as _, size); + } + } +} + +impl fmt::Debug for Secp256k1 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "", self.ctx, C::DESCRIPTION) + } +} + +impl Secp256k1 { + /// Getter for the raw pointer to the underlying secp256k1 context. This + /// shouldn't be needed with normal usage of the library. It enables + /// extending the Secp256k1 with more cryptographic algorithms outside of + /// this crate. + pub fn ctx(&self) -> NonNull { self.ctx } + + /// Returns the required memory for a preallocated context buffer in a generic manner(sign/verify/all). + pub fn preallocate_size_gen() -> usize { + let word_size = mem::size_of::(); + let bytes = unsafe { ffi::secp256k1_context_preallocated_size(C::FLAGS) }; + + (bytes + word_size - 1) / word_size + } + + /// (Re)randomizes the Secp256k1 context for extra sidechannel resistance. + /// + /// Requires compilation with "rand" feature. See comment by Gregory Maxwell in + /// [libsecp256k1](https://github.com/bitcoin-core/secp256k1/commit/d2275795ff22a6f4738869f5528fbbb61738aa48). + #[cfg(feature = "rand")] + pub fn randomize(&mut self, rng: &mut R) { + let mut seed = [0u8; 32]; + rng.fill_bytes(&mut seed); + self.seeded_randomize(&seed); + } + + /// (Re)randomizes the Secp256k1 context for extra sidechannel resistance given 32 bytes of + /// cryptographically-secure random data; + /// see comment in libsecp256k1 commit d2275795f by Gregory Maxwell. + pub fn seeded_randomize(&mut self, seed: &[u8; 32]) { + unsafe { + let err = ffi::secp256k1_context_randomize(self.ctx, seed.as_c_ptr()); + // This function cannot fail; it has an error return for future-proofing. + // We do not expose this error since it is impossible to hit, and we have + // precedent for not exposing impossible errors (for example in + // `PublicKey::from_secret_key` where it is impossible to create an invalid + // secret key through the API.) + // However, if this DOES fail, the result is potentially weaker side-channel + // resistance, which is deadly and undetectable, so we take out the entire + // thread to be on the safe side. + assert_eq!(err, 1); + } + } +} + +impl Secp256k1 { + /// Generates a random keypair. Convenience function for [`SecretKey::new`] and + /// [`PublicKey::from_secret_key`]. + #[inline] + #[cfg(feature = "rand")] + pub fn generate_keypair( + &self, + rng: &mut R, + ) -> (key::SecretKey, key::PublicKey) { + let sk = key::SecretKey::new(rng); + let pk = key::PublicKey::from_secret_key(self, &sk); + (sk, pk) + } +} + +/// Generates a random keypair using the global [`SECP256K1`] context. +#[inline] +#[cfg(all(feature = "global-context", feature = "rand"))] +pub fn generate_keypair(rng: &mut R) -> (key::SecretKey, key::PublicKey) { + SECP256K1.generate_keypair(rng) +} + +/// Utility function used to parse hex into a target u8 buffer. Returns +/// the number of bytes converted or an error if it encounters an invalid +/// character or unexpected end of string. +fn from_hex(hex: &str, target: &mut [u8]) -> Result { + if hex.len() % 2 == 1 || hex.len() > target.len() * 2 { + return Err(()); + } + + let mut b = 0; + let mut idx = 0; + for c in hex.bytes() { + b <<= 4; + match c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + _ => return Err(()), + } + if (idx & 1) == 1 { + target[idx / 2] = b; + b = 0; + } + idx += 1; + } + Ok(idx / 2) +} + +/// Utility function used to encode hex into a target u8 buffer. Returns +/// a reference to the target buffer as an str. Returns an error if the target +/// buffer isn't big enough. +#[inline] +fn to_hex<'a>(src: &[u8], target: &'a mut [u8]) -> Result<&'a str, ()> { + let hex_len = src.len() * 2; + if target.len() < hex_len { + return Err(()); + } + const HEX_TABLE: [u8; 16] = *b"0123456789abcdef"; + + let mut i = 0; + for &b in src { + target[i] = HEX_TABLE[usize::from(b >> 4)]; + target[i + 1] = HEX_TABLE[usize::from(b & 0b00001111)]; + i += 2; + } + let result = &target[..hex_len]; + debug_assert!(str::from_utf8(result).is_ok()); + return unsafe { Ok(str::from_utf8_unchecked(result)) }; +} + +#[cfg(feature = "rand")] +pub(crate) fn random_32_bytes(rng: &mut R) -> [u8; 32] { + let mut ret = [0u8; 32]; + rng.fill(&mut ret); + ret +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use hex_lit::hex; + #[cfg(target_arch = "wasm32")] + use wasm_bindgen_test::wasm_bindgen_test as test; + + use super::*; + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + // In rustc 1.72 this Clippy lint was pulled out of clippy and into rustc, and + // was made deny-by-default, breaking compilation of this test. Aside from this + // breaking change, which there is no point in bugging, the rename was done so + // clumsily that you need four separate "allow"s to disable this wrong lint. + #[allow(unknown_lints)] + #[allow(renamed_and_removed_lints)] + #[allow(undropped_manually_drops)] + #[allow(clippy::unknown_manually_drops)] + fn test_raw_ctx() { + use std::mem::{forget, ManuallyDrop}; + + let ctx_full = Secp256k1::new(); + let ctx_sign = Secp256k1::signing_only(); + let ctx_vrfy = Secp256k1::verification_only(); + + let full = unsafe { Secp256k1::from_raw_all(ctx_full.ctx) }; + let sign = unsafe { Secp256k1::from_raw_signing_only(ctx_sign.ctx) }; + let mut vrfy = unsafe { Secp256k1::from_raw_verification_only(ctx_vrfy.ctx) }; + + let (sk, pk) = full.generate_keypair(&mut rand::thread_rng()); + let msg = Message::from_digest([2u8; 32]); + // Try signing + assert_eq!(sign.sign_ecdsa(msg, &sk), full.sign_ecdsa(msg, &sk)); + let sig = full.sign_ecdsa(msg, &sk); + + // Try verifying + assert!(vrfy.verify_ecdsa(msg, &sig, &pk).is_ok()); + assert!(full.verify_ecdsa(msg, &sig, &pk).is_ok()); + + // The following drop will have no effect; in fact, they will trigger a compiler + // error because manually dropping a `ManuallyDrop` is almost certainly incorrect. + // If you want to drop the inner object you should called `ManuallyDrop::drop`. + drop(full); + // This will actually drop the context, though it will leave `full` accessible and + // in an invalid state. However, this is almost certainly what you want to do. + drop(ctx_full); + unsafe { + // Need to compute the allocation size, and need to do so *before* dropping + // anything. + let sz = ffi::secp256k1_context_preallocated_clone_size(ctx_sign.ctx.as_ptr()); + // We can alternately drop the `ManuallyDrop` by unwrapping it and then letting + // it be dropped. This is actually a safe function, but it will destruct the + // underlying context without deallocating it... + ManuallyDrop::into_inner(sign); + // ...leaving us holding the bag to deallocate the context's memory without + // double-calling `secp256k1_context_destroy`, which cannot be done safely. + SignOnly::deallocate(ctx_sign.ctx.as_ptr() as *mut u8, sz); + forget(ctx_sign); + } + + unsafe { + // Finally, we can call `ManuallyDrop::drop`, which has the same effect, but + let sz = ffi::secp256k1_context_preallocated_clone_size(ctx_vrfy.ctx.as_ptr()); + // leaves the `ManuallyDrop` itself accessible. This is marked unsafe. + ManuallyDrop::drop(&mut vrfy); + VerifyOnly::deallocate(ctx_vrfy.ctx.as_ptr() as *mut u8, sz); + forget(ctx_vrfy); + } + } + + #[cfg(not(target_arch = "wasm32"))] + #[test] + #[ignore] // Panicking from C may trap (SIGILL) intentionally, so we test this manually. + #[cfg(feature = "alloc")] + fn test_panic_raw_ctx_should_terminate_abnormally() { + // Trying to use an all-zeros public key should cause an ARG_CHECK to trigger. + let pk = PublicKey::from(unsafe { ffi::PublicKey::new() }); + pk.serialize(); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn test_preallocation() { + use crate::ffi::types::AlignedType; + + let mut buf_ful = vec![AlignedType::zeroed(); Secp256k1::preallocate_size()]; + let mut buf_sign = vec![AlignedType::zeroed(); Secp256k1::preallocate_signing_size()]; + let mut buf_vfy = vec![AlignedType::zeroed(); Secp256k1::preallocate_verification_size()]; + + let full = Secp256k1::preallocated_new(&mut buf_ful).unwrap(); + let sign = Secp256k1::preallocated_signing_only(&mut buf_sign).unwrap(); + let vrfy = Secp256k1::preallocated_verification_only(&mut buf_vfy).unwrap(); + + // drop(buf_vfy); // The buffer can't get dropped before the context. + // println!("{:?}", buf_ful[5]); // Can't even read the data thanks to the borrow checker. + + let (sk, pk) = full.generate_keypair(&mut rand::thread_rng()); + let msg = Message::from_digest([2u8; 32]); + // Try signing + assert_eq!(sign.sign_ecdsa(msg, &sk), full.sign_ecdsa(msg, &sk)); + let sig = full.sign_ecdsa(msg, &sk); + + // Try verifying + assert!(vrfy.verify_ecdsa(msg, &sig, &pk).is_ok()); + assert!(full.verify_ecdsa(msg, &sig, &pk).is_ok()); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn capabilities() { + let sign = Secp256k1::signing_only(); + let vrfy = Secp256k1::verification_only(); + let full = Secp256k1::new(); + + let msg = crate::random_32_bytes(&mut rand::thread_rng()); + let msg = Message::from_digest(msg); + + // Try key generation + let (sk, pk) = full.generate_keypair(&mut rand::thread_rng()); + + // Try signing + assert_eq!(sign.sign_ecdsa(msg, &sk), full.sign_ecdsa(msg, &sk)); + let sig = full.sign_ecdsa(msg, &sk); + + // Try verifying + assert!(vrfy.verify_ecdsa(msg, &sig, &pk).is_ok()); + assert!(full.verify_ecdsa(msg, &sig, &pk).is_ok()); + + // Check that we can produce keys from slices with no precomputation + let (pk_slice, sk_slice) = (&pk.serialize(), &sk[..]); + let new_pk = PublicKey::from_slice(pk_slice).unwrap(); + let new_sk = SecretKey::from_slice(sk_slice).unwrap(); + assert_eq!(sk, new_sk); + assert_eq!(pk, new_pk); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn signature_serialize_roundtrip() { + let mut s = Secp256k1::new(); + s.randomize(&mut rand::thread_rng()); + + for _ in 0..100 { + let msg = crate::random_32_bytes(&mut rand::thread_rng()); + let msg = Message::from_digest(msg); + + let (sk, _) = s.generate_keypair(&mut rand::thread_rng()); + let sig1 = s.sign_ecdsa(msg, &sk); + let der = sig1.serialize_der(); + let sig2 = ecdsa::Signature::from_der(&der[..]).unwrap(); + assert_eq!(sig1, sig2); + + let compact = sig1.serialize_compact(); + let sig2 = ecdsa::Signature::from_compact(&compact[..]).unwrap(); + assert_eq!(sig1, sig2); + + assert!(ecdsa::Signature::from_compact(&der[..]).is_err()); + assert!(ecdsa::Signature::from_compact(&compact[0..4]).is_err()); + assert!(ecdsa::Signature::from_der(&compact[..]).is_err()); + assert!(ecdsa::Signature::from_der(&der[0..4]).is_err()); + } + } + + #[test] + fn signature_display() { + const HEX_STR: &str = "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45"; + let byte_str = hex!(HEX_STR); + + assert_eq!( + ecdsa::Signature::from_der(&byte_str).expect("byte str decode"), + ecdsa::Signature::from_str(HEX_STR).expect("byte str decode") + ); + + let sig = ecdsa::Signature::from_str(HEX_STR).expect("byte str decode"); + assert_eq!(&sig.to_string(), HEX_STR); + assert_eq!(&format!("{:?}", sig), HEX_STR); + + assert!(ecdsa::Signature::from_str( + "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\ + 72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab4" + ) + .is_err()); + assert!(ecdsa::Signature::from_str( + "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\ + 72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab" + ) + .is_err()); + assert!(ecdsa::Signature::from_str( + "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\ + 72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eabxx" + ) + .is_err()); + assert!(ecdsa::Signature::from_str( + "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a\ + 72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45\ + 72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45\ + 72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45\ + 72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45\ + 72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45" + ) + .is_err()); + + // 71 byte signature + let hex_str = "30450221009d0bad576719d32ae76bedb34c774866673cbde3f4e12951555c9408e6ce774b02202876e7102f204f6bfee26c967c3926ce702cf97d4b010062e193f763190f6776"; + let sig = ecdsa::Signature::from_str(hex_str).expect("byte str decode"); + assert_eq!(&format!("{}", sig), hex_str); + } + + #[test] + fn signature_lax_der() { + macro_rules! check_lax_sig( + ($hex:expr) => ({ + let sig = hex!($hex); + assert!(ecdsa::Signature::from_der_lax(&sig[..]).is_ok()); + }) + ); + + check_lax_sig!("304402204c2dd8a9b6f8d425fcd8ee9a20ac73b619906a6367eac6cb93e70375225ec0160220356878eff111ff3663d7e6bf08947f94443845e0dcc54961664d922f7660b80c"); + check_lax_sig!("304402202ea9d51c7173b1d96d331bd41b3d1b4e78e66148e64ed5992abd6ca66290321c0220628c47517e049b3e41509e9d71e480a0cdc766f8cdec265ef0017711c1b5336f"); + check_lax_sig!("3045022100bf8e050c85ffa1c313108ad8c482c4849027937916374617af3f2e9a881861c9022023f65814222cab09d5ec41032ce9c72ca96a5676020736614de7b78a4e55325a"); + check_lax_sig!("3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45"); + check_lax_sig!("3046022100eaa5f90483eb20224616775891397d47efa64c68b969db1dacb1c30acdfc50aa022100cf9903bbefb1c8000cf482b0aeeb5af19287af20bd794de11d82716f9bae3db1"); + check_lax_sig!("3045022047d512bc85842ac463ca3b669b62666ab8672ee60725b6c06759e476cebdc6c102210083805e93bd941770109bcc797784a71db9e48913f702c56e60b1c3e2ff379a60"); + check_lax_sig!("3044022023ee4e95151b2fbbb08a72f35babe02830d14d54bd7ed1320e4751751d1baa4802206235245254f58fd1be6ff19ca291817da76da65c2f6d81d654b5185dd86b8acf"); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn sign_and_verify_ecdsa() { + let mut s = Secp256k1::new(); + s.randomize(&mut rand::thread_rng()); + + let noncedata = [42u8; 32]; + for _ in 0..100 { + let msg = crate::random_32_bytes(&mut rand::thread_rng()); + let msg = Message::from_digest(msg); + + let (sk, pk) = s.generate_keypair(&mut rand::thread_rng()); + let sig = s.sign_ecdsa(msg, &sk); + assert_eq!(s.verify_ecdsa(msg, &sig, &pk), Ok(())); + let noncedata_sig = s.sign_ecdsa_with_noncedata(msg, &sk, &noncedata); + assert_eq!(s.verify_ecdsa(msg, &noncedata_sig, &pk), Ok(())); + let low_r_sig = s.sign_ecdsa_low_r(msg, &sk); + assert_eq!(s.verify_ecdsa(msg, &low_r_sig, &pk), Ok(())); + let grind_r_sig = s.sign_ecdsa_grind_r(msg, &sk, 1); + assert_eq!(s.verify_ecdsa(msg, &grind_r_sig, &pk), Ok(())); + let compact = sig.serialize_compact(); + if compact[0] < 0x80 { + assert_eq!(sig, low_r_sig); + } else { + #[cfg(not(secp256k1_fuzz))] // mocked sig generation doesn't produce low-R sigs + assert_ne!(sig, low_r_sig); + } + #[cfg(not(secp256k1_fuzz))] // mocked sig generation doesn't produce low-R sigs + assert!(ecdsa::compact_sig_has_zero_first_bit(&low_r_sig.0)); + #[cfg(not(secp256k1_fuzz))] // mocked sig generation doesn't produce low-R sigs + assert!(ecdsa::der_length_check(&grind_r_sig.0, 70)); + } + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn sign_and_verify_extreme() { + let mut s = Secp256k1::new(); + s.randomize(&mut rand::thread_rng()); + + // Wild keys: 1, CURVE_ORDER - 1 + // Wild msgs: 1, CURVE_ORDER - 1 + let mut wild_keys = [[0u8; 32]; 2]; + let mut wild_msgs = [[0u8; 32]; 2]; + + wild_keys[0][0] = 1; + wild_msgs[0][0] = 1; + + use constants; + wild_keys[1][..].copy_from_slice(&constants::CURVE_ORDER[..]); + wild_msgs[1][..].copy_from_slice(&constants::CURVE_ORDER[..]); + + wild_keys[1][0] -= 1; + wild_msgs[1][0] -= 1; + + for key in wild_keys.iter().map(|k| SecretKey::from_slice(&k[..]).unwrap()) { + for msg in wild_msgs.into_iter().map(Message::from_digest) { + let sig = s.sign_ecdsa(msg, &key); + let low_r_sig = s.sign_ecdsa_low_r(msg, &key); + let grind_r_sig = s.sign_ecdsa_grind_r(msg, &key, 1); + let pk = PublicKey::from_secret_key(&s, &key); + assert_eq!(s.verify_ecdsa(msg, &sig, &pk), Ok(())); + assert_eq!(s.verify_ecdsa(msg, &low_r_sig, &pk), Ok(())); + assert_eq!(s.verify_ecdsa(msg, &grind_r_sig, &pk), Ok(())); + } + } + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn sign_and_verify_fail() { + let mut s = Secp256k1::new(); + s.randomize(&mut rand::thread_rng()); + + let msg = crate::random_32_bytes(&mut rand::thread_rng()); + let msg = Message::from_digest(msg); + + let (sk, pk) = s.generate_keypair(&mut rand::thread_rng()); + + let sig = s.sign_ecdsa(msg, &sk); + + let msg = crate::random_32_bytes(&mut rand::thread_rng()); + let msg = Message::from_digest(msg); + assert_eq!(s.verify_ecdsa(msg, &sig, &pk), Err(Error::IncorrectSignature)); + } + + #[test] + #[allow(deprecated)] + fn test_bad_slice() { + assert_eq!( + ecdsa::Signature::from_der(&[0; constants::MAX_SIGNATURE_SIZE + 1]), + Err(Error::InvalidSignature) + ); + assert_eq!( + ecdsa::Signature::from_der(&[0; constants::MAX_SIGNATURE_SIZE]), + Err(Error::InvalidSignature) + ); + + assert_eq!( + Message::from_digest_slice(&[0; constants::MESSAGE_SIZE - 1]), + Err(Error::InvalidMessage) + ); + assert_eq!( + Message::from_digest_slice(&[0; constants::MESSAGE_SIZE + 1]), + Err(Error::InvalidMessage) + ); + assert!(Message::from_digest_slice(&[0; constants::MESSAGE_SIZE]).is_ok()); + assert!(Message::from_digest_slice(&[1; constants::MESSAGE_SIZE]).is_ok()); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn test_hex() { + use rand::RngCore; + + use super::to_hex; + + let mut rng = rand::thread_rng(); + const AMOUNT: usize = 1024; + for i in 0..AMOUNT { + // 255 isn't a valid utf8 character. + let mut hex_buf = [255u8; AMOUNT * 2]; + let mut src_buf = [0u8; AMOUNT]; + let mut result_buf = [0u8; AMOUNT]; + let src = &mut src_buf[0..i]; + rng.fill_bytes(src); + + let hex = to_hex(src, &mut hex_buf).unwrap(); + assert_eq!(from_hex(hex, &mut result_buf).unwrap(), i); + assert_eq!(src, &result_buf[..i]); + } + + assert!(to_hex(&[1; 2], &mut [0u8; 3]).is_err()); + assert!(to_hex(&[1; 2], &mut [0u8; 4]).is_ok()); + assert!(from_hex("deadbeaf", &mut [0u8; 3]).is_err()); + assert!(from_hex("deadbeaf", &mut [0u8; 4]).is_ok()); + assert!(from_hex("a", &mut [0u8; 4]).is_err()); + assert!(from_hex("ag", &mut [0u8; 4]).is_err()); + } + + #[test] + #[cfg(not(secp256k1_fuzz))] // fuzz-sigs have fixed size/format + #[cfg(any(feature = "alloc", feature = "std"))] + fn test_noncedata() { + let secp = Secp256k1::new(); + let msg = hex!("887d04bb1cf1b1554f1b268dfe62d13064ca67ae45348d50d1392ce2d13418ac"); + let msg = Message::from_digest(msg); + let noncedata = [42u8; 32]; + let sk = + SecretKey::from_str("57f0148f94d13095cfda539d0da0d1541304b678d8b36e243980aab4e1b7cead") + .unwrap(); + let expected_sig = hex!("24861b3edd4e7da43319c635091405feced6efa4ec99c3c3c35f6c3ba0ed8816116772e84994084db85a6c20589f6a85af569d42275c2a5dd900da5776b99d5d"); + let expected_sig = ecdsa::Signature::from_compact(&expected_sig).unwrap(); + + let sig = secp.sign_ecdsa_with_noncedata(msg, &sk, &noncedata); + + assert_eq!(expected_sig, sig); + } + + #[test] + #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs + #[cfg(any(feature = "alloc", feature = "std"))] + fn test_low_s() { + // nb this is a transaction on testnet + // txid 8ccc87b72d766ab3128f03176bb1c98293f2d1f85ebfaf07b82cc81ea6891fa9 + // input number 3 + let sig = hex!("3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45"); + let pk = hex!("031ee99d2b786ab3b0991325f2de8489246a6a3fdb700f6d0511b1d80cf5f4cd43"); + let msg = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d"); + + let secp = Secp256k1::new(); + let mut sig = ecdsa::Signature::from_der(&sig[..]).unwrap(); + let pk = PublicKey::from_slice(&pk[..]).unwrap(); + let msg = Message::from_digest(msg); + + // without normalization we expect this will fail + assert_eq!(secp.verify_ecdsa(msg, &sig, &pk), Err(Error::IncorrectSignature)); + // after normalization it should pass + sig.normalize_s(); + assert_eq!(secp.verify_ecdsa(msg, &sig, &pk), Ok(())); + } + + #[test] + #[cfg(not(secp256k1_fuzz))] // fuzz-sigs have fixed size/format + #[cfg(any(feature = "alloc", feature = "std"))] + fn test_low_r() { + let secp = Secp256k1::new(); + let msg = hex!("887d04bb1cf1b1554f1b268dfe62d13064ca67ae45348d50d1392ce2d13418ac"); + let msg = Message::from_digest(msg); + let sk = + SecretKey::from_str("57f0148f94d13095cfda539d0da0d1541304b678d8b36e243980aab4e1b7cead") + .unwrap(); + let expected_sig = hex!("047dd4d049db02b430d24c41c7925b2725bcd5a85393513bdec04b4dc363632b1054d0180094122b380f4cfa391e6296244da773173e78fc745c1b9c79f7b713"); + let expected_sig = ecdsa::Signature::from_compact(&expected_sig).unwrap(); + + let sig = secp.sign_ecdsa_low_r(msg, &sk); + + assert_eq!(expected_sig, sig); + } + + #[test] + #[cfg(not(secp256k1_fuzz))] // fuzz-sigs have fixed size/format + #[cfg(any(feature = "alloc", feature = "std"))] + fn test_grind_r() { + let secp = Secp256k1::new(); + let msg = hex!("ef2d5b9a7c61865a95941d0f04285420560df7e9d76890ac1b8867b12ce43167"); + let msg = Message::from_digest(msg); + let sk = + SecretKey::from_str("848355d75fe1c354cf05539bb29b2015f1863065bcb6766b44d399ab95c3fa0b") + .unwrap(); + let expected_sig = ecdsa::Signature::from_str("304302202ffc447100d518c8ba643d11f3e6a83a8640488e7d2537b1954b942408be6ea3021f26e1248dd1e52160c3a38af9769d91a1a806cab5f9d508c103464d3c02d6e1").unwrap(); + + let sig = secp.sign_ecdsa_grind_r(msg, &sk, 2); + + assert_eq!(expected_sig, sig); + } + + #[cfg(feature = "serde")] + #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs + #[cfg(any(feature = "alloc", feature = "std"))] + #[test] + fn test_serde() { + use serde_test::{assert_tokens, Configure, Token}; + + let s = Secp256k1::new(); + + let msg = Message::from_digest([1; 32]); + let sk = SecretKey::from_slice(&[2; 32]).unwrap(); + let sig = s.sign_ecdsa(msg, &sk); + static SIG_BYTES: [u8; 71] = [ + 48, 69, 2, 33, 0, 157, 11, 173, 87, 103, 25, 211, 42, 231, 107, 237, 179, 76, 119, 72, + 102, 103, 60, 189, 227, 244, 225, 41, 81, 85, 92, 148, 8, 230, 206, 119, 75, 2, 32, 40, + 118, 231, 16, 47, 32, 79, 107, 254, 226, 108, 150, 124, 57, 38, 206, 112, 44, 249, 125, + 75, 1, 0, 98, 225, 147, 247, 99, 25, 15, 103, 118, + ]; + static SIG_STR: &str = "\ + 30450221009d0bad576719d32ae76bedb34c774866673cbde3f4e12951555c9408e6ce77\ + 4b02202876e7102f204f6bfee26c967c3926ce702cf97d4b010062e193f763190f6776\ + "; + + assert_tokens(&sig.compact(), &[Token::BorrowedBytes(&SIG_BYTES[..])]); + assert_tokens(&sig.compact(), &[Token::Bytes(&SIG_BYTES)]); + assert_tokens(&sig.compact(), &[Token::ByteBuf(&SIG_BYTES)]); + + assert_tokens(&sig.readable(), &[Token::BorrowedStr(SIG_STR)]); + assert_tokens(&sig.readable(), &[Token::Str(SIG_STR)]); + assert_tokens(&sig.readable(), &[Token::String(SIG_STR)]); + } + + #[cfg(feature = "global-context")] + #[test] + fn test_global_context() { + use crate::SECP256K1; + let sk_data = hex!("e6dd32f8761625f105c39a39f19370b3521d845a12456d60ce44debd0a362641"); + let sk = SecretKey::from_slice(&sk_data).unwrap(); + let msg_data = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d"); + let msg = Message::from_digest(msg_data); + + // Check usage as explicit parameter + let pk = PublicKey::from_secret_key(SECP256K1, &sk); + + // Check usage as self + let sig = SECP256K1.sign_ecdsa(msg, &sk); + assert!(SECP256K1.verify_ecdsa(msg, &sig, &pk).is_ok()); + } +} + +#[cfg(bench)] +#[cfg(all(feature = "rand", feature = "std"))] +mod benches { + use rand::rngs::mock::StepRng; + use test::{black_box, Bencher}; + + use super::{Message, Secp256k1}; + + #[bench] + pub fn generate(bh: &mut Bencher) { + let s = Secp256k1::new(); + let mut r = StepRng::new(1, 1); + bh.iter(|| { + let (sk, pk) = s.generate_keypair(&mut r); + black_box(sk); + black_box(pk); + }); + } + + #[bench] + pub fn bench_sign_ecdsa(bh: &mut Bencher) { + let s = Secp256k1::new(); + let msg = crate::random_32_bytes(&mut rand::thread_rng()); + let msg = Message::from_digest(msg); + let (sk, _) = s.generate_keypair(&mut rand::thread_rng()); + + bh.iter(|| { + let sig = s.sign_ecdsa(msg, &sk); + black_box(sig); + }); + } + + #[bench] + pub fn bench_verify_ecdsa(bh: &mut Bencher) { + let s = Secp256k1::new(); + let msg = crate::random_32_bytes(&mut rand::thread_rng()); + let msg = Message::from_digest(msg); + let (sk, pk) = s.generate_keypair(&mut rand::thread_rng()); + let sig = s.sign_ecdsa(msg, &sk); + + bh.iter(|| { + let res = s.verify_ecdsa(msg, &sig, &pk).unwrap(); + black_box(res); + }); + } +} diff --git a/ark-rust-secp256k1/src/macros.rs b/ark-rust-secp256k1/src/macros.rs new file mode 100644 index 00000000..4111b3f0 --- /dev/null +++ b/ark-rust-secp256k1/src/macros.rs @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: CC0-1.0 + +/// Implement methods and traits for types that contain an inner array. +#[macro_export] +macro_rules! impl_array_newtype { + ($thing:ident, $ty:ty, $len:expr) => { + impl AsRef<[$ty; $len]> for $thing { + #[inline] + /// Gets a reference to the underlying array + fn as_ref(&self) -> &[$ty; $len] { + let &$thing(ref dat) = self; + dat + } + } + + impl core::ops::Index for $thing + where + [$ty]: core::ops::Index, + { + type Output = <[$ty] as core::ops::Index>::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { &self.0[index] } + } + + impl $crate::ffi::CPtr for $thing { + type Target = $ty; + + fn as_c_ptr(&self) -> *const Self::Target { + let &$thing(ref dat) = self; + dat.as_ptr() + } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { + let &mut $thing(ref mut dat) = self; + dat.as_mut_ptr() + } + } + }; +} + +macro_rules! impl_pretty_debug { + ($thing:ident) => { + impl core::fmt::Debug for $thing { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{}(", stringify!($thing))?; + for i in &self[..] { + write!(f, "{:02x}", i)?; + } + f.write_str(")") + } + } + }; +} + +macro_rules! impl_non_secure_erase { + ($thing:ident, $target:tt, $value:expr) => { + impl $thing { + /// Attempts to erase the contents of the underlying array. + /// + /// Note, however, that the compiler is allowed to freely copy or move the + /// contents of this array to other places in memory. Preventing this behavior + /// is very subtle. For more discussion on this, please see the documentation + /// of the [`zeroize`](https://docs.rs/zeroize) crate. + #[inline] + pub fn non_secure_erase(&mut self) { + secp256k1_sys::non_secure_erase_impl(&mut self.$target, $value); + } + } + }; +} + +/// Formats error. If `std` feature is OFF appends error source (delimited by `: `). We do this +/// because `e.source()` is only available in std builds, without this macro the error source is +/// lost for no-std builds. +macro_rules! write_err { + ($writer:expr, $string:literal $(, $args:expr),*; $source:expr) => { + { + #[cfg(feature = "std")] + { + let _ = &$source; // Prevents clippy warnings. + write!($writer, $string $(, $args)*) + } + #[cfg(not(feature = "std"))] + { + write!($writer, concat!($string, ": {}") $(, $args)*, $source) + } + } + } +} + +/// Implements fast unstable comparison methods for `$ty`. +macro_rules! impl_fast_comparisons { + ($ty:ident) => { + impl $ty { + /// Like `cmp::Cmp` but faster and with no guarantees across library versions. + /// + /// The `Cmp` implementation for FFI types is stable but slow because it first + /// serializes `self` and `other` before comparing them. This function provides a faster + /// comparison if you know that your types come from the same library version. + pub fn cmp_fast_unstable(&self, other: &Self) -> core::cmp::Ordering { + self.0.cmp_fast_unstable(&other.0) + } + + /// Like `cmp::Eq` but faster and with no guarantees across library versions. + /// + /// The `Eq` implementation for FFI types is stable but slow because it first serializes + /// `self` and `other` before comparing them. This function provides a faster equality + /// check if you know that your types come from the same library version. + pub fn eq_fast_unstable(&self, other: &Self) -> bool { + self.0.eq_fast_unstable(&other.0) + } + } + }; +} diff --git a/ark-rust-secp256k1/src/musig.rs b/ark-rust-secp256k1/src/musig.rs new file mode 100644 index 00000000..0919626c --- /dev/null +++ b/ark-rust-secp256k1/src/musig.rs @@ -0,0 +1,1158 @@ +//! This module implements high-level Rust bindings for a Schnorr-based +//! multi-signature scheme called MuSig2 [paper](https://eprint.iacr.org/2020/1261). +//! It is compatible with bip-schnorr. +//! +//! The documentation in this module is for reference and may not be sufficient +//! for advanced use-cases. A full description of the C API usage along with security considerations +//! can be found in [C-musig.md](secp256k1-sys/depend/secp256k1/src/modules/musig/musig.md). +use core; +use core::fmt; +use core::mem::MaybeUninit; +#[cfg(feature = "std")] +use std; + +use crate::ffi::{self, CPtr}; +use crate::{ + schnorr, Error, Keypair, Message, PublicKey, Scalar, Secp256k1, SecretKey, Signing, Verification, XOnlyPublicKey +}; + +/// Musig partial signature parsing errors +#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)] +pub enum ParseError { + /// Parse Argument is malformed. This might occur if the point is on the secp order, + /// or if the secp scalar is outside of group order + MalformedArg, +} + +#[cfg(feature = "std")] +impl std::error::Error for ParseError {} + +impl fmt::Display for ParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + ParseError::MalformedArg => write!(f, "Malformed parse argument"), + } + } +} + +/// Session Id for a MuSig session. +#[allow(missing_copy_implementations)] +#[derive(Debug, Eq, PartialEq)] +pub struct SessionSecretRand([u8; 32]); + +impl SessionSecretRand { + /// Generates a new session ID using thread RNG. + #[cfg(all(feature = "rand", feature = "std"))] + pub fn new() -> Self { + Self::from_rng(&mut rand::thread_rng()) + } + + /// Creates a new [`SessionSecretRand`] with random bytes from the given rng + #[cfg(feature = "rand")] + pub fn from_rng(rng: &mut R) -> Self { + let session_secrand = crate::random_32_bytes(rng); + SessionSecretRand(session_secrand) + } + + /// Creates a new [`SessionSecretRand`] with the given bytes. + /// + /// Special care must be taken that the bytes are unique for each call to + /// [`KeyAggCache::nonce_gen`] or [`new_nonce_pair`]. The simplest + /// recommendation is to use a cryptographicaly random 32-byte value. + /// + /// In rand-std environment, [`SessionSecretRand::new`] can be used to generate a random + /// session id using thread rng. + pub fn assume_unique_per_nonce_gen(inner: [u8; 32]) -> Self { SessionSecretRand(inner) } + + /// Obtains the inner bytes of the [`SessionSecretRand`]. + pub fn to_bytes(&self) -> [u8; 32] { self.0 } + + /// Obtains a reference to the inner bytes of the [`SessionSecretRand`]. + pub fn as_bytes(&self) -> &[u8; 32] { &self.0 } +} + +/// Cached data related to a key aggregation. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct KeyAggCache{ + data: ffi::MusigKeyAggCache, + aggregated_xonly_public_key: XOnlyPublicKey +} + +impl CPtr for KeyAggCache { + type Target = ffi::MusigKeyAggCache; + + fn as_c_ptr(&self) -> *const Self::Target { self.as_ptr() } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() } +} + + +/// Musig tweaking related error. +#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)] +pub struct InvalidTweakErr; + +#[cfg(feature = "std")] +impl std::error::Error for InvalidTweakErr {} + +impl fmt::Display for InvalidTweakErr { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "The tweak is negation of secret key") + } +} + +/// Low level API for starting a signing session by generating a nonce. +/// +/// Use [`KeyAggCache::nonce_gen`] whenever +/// possible. This API provides full flexibility in providing custom nonce generation, +/// but should be use with care. +/// +/// This function outputs a secret nonce that will be required for signing and a +/// corresponding public nonce that is intended to be sent to other signers. +/// +/// MuSig differs from regular Schnorr signing in that implementers _must_ take +/// special care to not reuse a nonce. If you cannot provide a `sec_key`, `session_secrand` +/// UNIFORMLY RANDOM AND KEPT SECRET (even from other signers). Refer to libsecp256k1 +/// documentation for additional considerations. +/// +/// MuSig2 nonces can be precomputed without knowing the aggregate public key, the message to sign. +/// Refer to libsecp256k1 documentation for additional considerations. +/// +/// # Arguments: +/// +/// * `secp` : [`Secp256k1`] context object initialized for signing +/// * `session_secrand`: [`SessionSecretRand`] Uniform random identifier for this session. Each call to this +/// function must have a UNIQUE `session_secrand`. +/// * `sec_key`: Optional [`SecretKey`] that we will use to sign to a create partial signature. Provide this +/// for maximal mis-use resistance. +/// * `pub_key`: [`PublicKey`] that we will use to create partial signature. The secnonce +/// output of this function cannot be used to sign for any other public key. +/// * `msg`: Optional [`Message`] that will be signed later on. Provide this for maximal misuse resistance. +/// * `extra_rand`: Additional randomness for mis-use resistance. Provide this for maximal misuse resistance +/// +/// Remember that nonce reuse will immediately leak the secret key! +/// +/// # Errors: +/// +/// * `ZeroSession`: if the `session_secrand` is supplied is all zeros. +/// +/// Example: +/// +/// ```rust +/// # # [cfg(any(test, feature = "rand-std"))] { +/// # use secp256k1::rand::{thread_rng, RngCore}; +/// # use secp256k1::{PublicKey, Secp256k1, SecretKey, new_nonce_pair, SessionSecretRand}; +/// # let secp = Secp256k1::new(); +/// // The session id must be sampled at random. Read documentation for more details. +/// let session_secrand = SessionSecretRand::new(&mut thread_rng()); +/// let sk = SecretKey::new(&mut thread_rng()); +/// let pk = PublicKey::from_secret_key(&secp, &sk); +/// +/// // Supply extra auxillary randomness to prevent misuse(for example, time of day) +/// let extra_rand : Option<[u8; 32]> = None; +/// +/// let (_sec_nonce, _pub_nonce) = new_nonce_pair(&secp, session_secrand, None, Some(sk), pk, None, None) +/// .expect("non zero session id"); +/// # } +/// ``` +pub fn new_nonce_pair( + secp: &Secp256k1, + session_secrand: SessionSecretRand, + key_agg_cache: Option<&KeyAggCache>, + sec_key: Option, + pub_key: PublicKey, + msg: Option, + extra_rand: Option<[u8; 32]>, +) -> (SecretNonce, PublicNonce) { + let cx = secp.ctx().as_ptr(); + let extra_ptr = extra_rand.as_ref().map(|e| e.as_ptr()).unwrap_or(core::ptr::null()); + let sk_ptr = sec_key.as_ref().map(|e| e.as_c_ptr()).unwrap_or(core::ptr::null()); + let msg_ptr = msg.as_ref().map(|e| e.as_c_ptr()).unwrap_or(core::ptr::null()); + let cache_ptr = key_agg_cache.map(|e| e.as_ptr()).unwrap_or(core::ptr::null()); + unsafe { + let mut sec_nonce = MaybeUninit::::uninit(); + let mut pub_nonce = MaybeUninit::::uninit(); + if ffi::secp256k1_musig_nonce_gen( + cx, + sec_nonce.as_mut_ptr(), + pub_nonce.as_mut_ptr(), + session_secrand.as_bytes().as_ptr(), + sk_ptr, + pub_key.as_c_ptr(), + msg_ptr, + cache_ptr, + extra_ptr, + ) == 0 + { + // Rust type system guarantees that + // - input secret key is valid + // - msg is 32 bytes + // - Key agg cache is valid + // - extra input is 32 bytes + // This can only happen when the session id is all zeros + panic!("A zero session id was supplied") + } else { + let pub_nonce = PublicNonce(pub_nonce.assume_init()); + let sec_nonce = SecretNonce(sec_nonce.assume_init()); + (sec_nonce, pub_nonce) + } + } +} + +/// A Musig partial signature. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct PartialSignature(ffi::MusigPartialSignature); + +impl CPtr for PartialSignature { + type Target = ffi::MusigPartialSignature; + + fn as_c_ptr(&self) -> *const Self::Target { self.as_ptr() } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() } +} + +impl PartialSignature { + /// Serialize a PartialSignature. + /// + /// # Returns + /// + /// 32-byte array + pub fn serialize(&self) -> [u8; 32] { + let mut data = MaybeUninit::<[u8; 32]>::uninit(); + unsafe { + if ffi::secp256k1_musig_partial_sig_serialize( + ffi::secp256k1_context_no_precomp, + data.as_mut_ptr() as *mut u8, + self.as_ptr(), + ) == 0 + { + // Only fails if args are null pointer which is possible in safe rust + unreachable!("Serialization cannot fail") + } else { + data.assume_init() + } + } + } + + /// Deserialize a PartialSignature from bytes. + /// + /// # Errors: + /// + /// - MalformedArg: If the signature [`PartialSignature`] is out of curve order + pub fn from_byte_array(data: &[u8; ffi::MUSIG_PART_SIG_SERIALIZED_LEN]) -> Result { + let mut partial_sig = MaybeUninit::::uninit(); + unsafe { + if ffi::secp256k1_musig_partial_sig_parse( + ffi::secp256k1_context_no_precomp, + partial_sig.as_mut_ptr(), + data.as_ptr(), + ) == 0 + { + Err(ParseError::MalformedArg) + } else { + Ok(PartialSignature(partial_sig.assume_init())) + } + } + } + + /// Get a const pointer to the inner PartialSignature + pub fn as_ptr(&self) -> *const ffi::MusigPartialSignature { &self.0 } + + /// Get a mut pointer to the inner PartialSignature + pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigPartialSignature { &mut self.0 } +} + +impl KeyAggCache { + /// Creates a new [`KeyAggCache`] by supplying a list of PublicKeys used in the session. + /// + /// Computes a combined public key and the hash of the given public keys. + /// + /// Different orders of `pubkeys` result in different `agg_pk`s. + /// The pubkeys can be sorted lexicographically before combining with which + /// ensures the same resulting `agg_pk` for the same multiset of pubkeys. + /// This is useful to do before aggregating pubkeys, such that the order of pubkeys + /// does not affect the combined public key. + /// + /// # Returns + /// + /// A [`KeyAggCache`] the can be used [`KeyAggCache::nonce_gen`] and [`Session::new`]. + /// + /// # Args: + /// + /// * `secp` - Secp256k1 context object initialized for verification + /// * `pubkeys` - Input array of public keys to combine. The order is important; a + /// different order will result in a different combined public key + /// + /// Example: + /// + /// ```rust + /// # # [cfg(any(test, feature = "rand-std"))] { + /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey}; + /// # let secp = Secp256k1::new(); + /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// # + /// let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// let _agg_pk = key_agg_cache.agg_pk(); + /// # } + /// ``` + pub fn new(secp: &Secp256k1, pubkeys: &[&PublicKey]) -> Self { + let cx = secp.ctx().as_ptr(); + + let mut key_agg_cache = MaybeUninit::::uninit(); + let mut agg_pk = MaybeUninit::::uninit(); + + unsafe { + let pubkeys_ref = core::slice::from_raw_parts(pubkeys.as_c_ptr() as *const *const ffi::PublicKey, pubkeys.len()); + + if ffi::secp256k1_musig_pubkey_agg( + cx, + agg_pk.as_mut_ptr(), + key_agg_cache.as_mut_ptr(), + pubkeys_ref.as_ptr(), + pubkeys_ref.len(), + ) == 0 + { + // Returns 0 only if the keys are malformed that never happens in safe rust type system. + unreachable!("Invalid XOnlyPublicKey in input pubkeys") + } else { + // secp256k1_musig_pubkey_agg overwrites the cache and the key so this is sound. + let key_agg_cache = key_agg_cache.assume_init(); + let agg_pk = XOnlyPublicKey::from(agg_pk.assume_init()); + KeyAggCache{ data: key_agg_cache, aggregated_xonly_public_key: agg_pk } + } + } + } + + /// Obtains the aggregate public key for this [`KeyAggCache`] + pub fn agg_pk(&self) -> XOnlyPublicKey { self.aggregated_xonly_public_key } + + /// Obtains the aggregate public key for this [`KeyAggCache`] as a full [`PublicKey`]. + /// + /// This is only useful if you need the non-xonly public key, in particular for + /// plain (non-xonly) tweaking or batch-verifying multiple key aggregations + /// (not supported yet). + pub fn agg_pk_full(&self) -> PublicKey { + unsafe { + let mut pk = PublicKey::from(ffi::PublicKey::new()); + if ffi::secp256k1_musig_pubkey_get( + ffi::secp256k1_context_no_precomp, + pk.as_mut_c_ptr(), + self.as_ptr(), + ) == 0 + { + // Returns 0 only if the keys are malformed that never happens in safe rust type system. + unreachable!("All the arguments are valid") + } else { + pk + } + } + } + + /// Apply ordinary "EC" tweaking to a public key in a [`KeyAggCache`]. + /// + /// This is done by adding the generator multiplied with `tweak32` to it. Returns the tweaked [`PublicKey`]. + /// This is useful for deriving child keys from an aggregate public key via BIP32. + /// This function is required if you want to _sign_ for a tweaked aggregate key. + /// + /// # Arguments: + /// + /// * `secp` : [`Secp256k1`] context object initialized for verification + /// * `tweak`: tweak of type [`Scalar`] with which to tweak the aggregated key + /// + /// # Errors: + /// + /// If resulting public key would be invalid (only when the tweak is the negation of the corresponding + /// secret key). For uniformly random 32-byte arrays(for example, in BIP 32 derivation) the chance of + /// being invalid is negligible (around 1 in 2^128). + /// + /// Example: + /// + /// ```rust + /// # # [cfg(any(test, feature = "rand-std"))] { + /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey}; + /// # let secp = Secp256k1::new(); + /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// # + /// let mut key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// + /// let tweak: [u8; 32] = *b"this could be a BIP32 tweak....\0"; + /// let tweak = Scalar::from_be_bytes(tweak).unwrap(); + /// let tweaked_key = key_agg_cache.pubkey_ec_tweak_add(&secp, tweak).unwrap(); + /// # } + /// ``` + pub fn pubkey_ec_tweak_add( + &mut self, + secp: &Secp256k1, + tweak: &Scalar, + ) -> Result { + let cx = secp.ctx().as_ptr(); + unsafe { + let mut out = PublicKey::from(ffi::PublicKey::new()); + if ffi::secp256k1_musig_pubkey_ec_tweak_add( + cx, + out.as_mut_c_ptr(), + self.as_mut_ptr(), + tweak.as_c_ptr(), + ) == 0 + { + Err(InvalidTweakErr) + } else { + self.aggregated_xonly_public_key = out.x_only_public_key().0; + Ok(out) + } + } + } + + /// Apply "x-only" tweaking to a public key in a [`KeyAggCache`]. + /// + /// This is done by adding the generator multiplied with `tweak32` to it. Returns the tweaked [`XOnlyPublicKey`]. + /// This is useful in creating taproot outputs. + /// This function is required if you want to _sign_ for a tweaked aggregate key. + /// + /// # Arguments: + /// + /// * `secp` : [`Secp256k1`] context object initialized for verification + /// * `tweak`: tweak of type [`SecretKey`] with which to tweak the aggregated key + /// + /// # Errors: + /// + /// If resulting public key would be invalid (only when the tweak is the negation of the corresponding + /// secret key). For uniformly random 32-byte arrays(for example, in BIP341 taproot tweaks) the chance of + /// being invalid is negligible (around 1 in 2^128) + /// + /// Example: + /// + /// ```rust + /// # # [cfg(any(test, feature = "rand-std"))] { + /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey}; + /// # let secp = Secp256k1::new(); + /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// + /// let mut key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// + /// let tweak = SecretKey::from_slice(b"Insecure tweak, Don't use this!!").unwrap(); // tweak could be from tap + /// let _x_only_key_tweaked = key_agg_cache.pubkey_xonly_tweak_add(&secp, tweak).unwrap(); + /// # } + /// ``` + pub fn pubkey_xonly_tweak_add( + &mut self, + secp: &Secp256k1, + tweak: &Scalar, + ) -> Result { + let cx = secp.ctx().as_ptr(); + unsafe { + let mut out = PublicKey::from(ffi::PublicKey::new()); + if ffi::secp256k1_musig_pubkey_xonly_tweak_add( + cx, + out.as_mut_c_ptr(), + self.as_mut_ptr(), + tweak.as_c_ptr(), + ) == 0 + { + Err(InvalidTweakErr) + } else { + self.aggregated_xonly_public_key = out.x_only_public_key().0; + Ok(out) + } + } + } + + /// Starts a signing session by generating a nonce + /// + /// This function outputs a secret nonce that will be required for signing and a + /// corresponding public nonce that is intended to be sent to other signers. + /// + /// MuSig differs from regular Schnorr signing in that implementers _must_ take + /// special care to not reuse a nonce. If you cannot provide a `sec_key`, `session_secrand` + /// UNIFORMLY RANDOM AND KEPT SECRET (even from other signers). + /// Refer to libsecp256k1 documentation for additional considerations. + /// + /// MuSig2 nonces can be precomputed without knowing the aggregate public key, the message to sign. + /// See the `new_nonce_pair` method that allows generating [`SecretNonce`] and [`PublicNonce`] + /// with only the `session_secrand` field. + /// + /// Remember that nonce reuse will immediately leak the secret key! + /// + /// # Returns: + /// + /// A pair of ([`SecretNonce`], [`PublicNonce`]) that can be later used signing and aggregation + /// + /// # Arguments: + /// + /// * `secp` : [`Secp256k1`] context object initialized for signing + /// * `session_secrand`: [`SessionSecretRand`] Uniform random identifier for this session. Each call to this + /// function must have a UNIQUE `session_secrand`. + /// * `pub_key`: [`PublicKey`] of the signer creating the nonce. + /// * `msg`: [`Message`] that will be signed later on. + /// * `extra_rand`: Additional randomness for mis-use resistance + /// + /// # Errors: + /// + /// * `ZeroSession`: if the `session_secrand` is supplied is all zeros. + /// + /// Example: + /// + /// ```rust + /// # # [cfg(any(test, feature = "rand-std"))] { + /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message}; + /// # let secp = Secp256k1::new(); + /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// # + /// let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// // The session id must be sampled at random. Read documentation for more details. + /// let session_secrand = SessionSecretRand::new(&mut thread_rng()); + /// + /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); + /// + /// // Provide the current time for mis-use resistance + /// let extra_rand : Option<[u8; 32]> = None; + /// let (_sec_nonce, _pub_nonce) = key_agg_cache.nonce_gen(&secp, session_secrand, pub_key1, msg, extra_rand) + /// .expect("non zero session id"); + /// # } + /// ``` + pub fn nonce_gen( + &self, + secp: &Secp256k1, + session_secrand: SessionSecretRand, + pub_key: PublicKey, + msg: Message, + extra_rand: Option<[u8; 32]>, + ) -> (SecretNonce, PublicNonce) { + // The secret key here is supplied as NULL. This is okay because we supply the + // public key and the message. + // This makes a simple API for the user because it does not require them to pass here. + new_nonce_pair(secp, session_secrand, Some(self), None, pub_key, Some(msg), extra_rand) + } + + /// Get a const pointer to the inner KeyAggCache + pub fn as_ptr(&self) -> *const ffi::MusigKeyAggCache { &self.data } + + /// Get a mut pointer to the inner KeyAggCache + pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigKeyAggCache { &mut self.data } +} + +/// Musig Secret Nonce. +/// +/// This structure MUST NOT be copied or +/// read or written to it directly. A signer who is online throughout the whole +/// process and can keep this structure in memory can use the provided API +/// functions for a safe standard workflow. See +/// for +/// more details about the risks associated with serializing or deserializing +/// this structure. There are no serialization and parsing functions (yet). +/// +/// Note this deliberately does not implement `Copy` or `Clone`. After creation, the only +/// use of this nonce is [`Session::partial_sign`] API that takes ownership of this +/// and drops it. This is to prevent accidental misuse of this nonce. +/// +/// A signer who is online throughout the whole process and can keep this +/// structure in memory can use the provided API functions for a safe standard +/// workflow. +/// +/// Signers that pre-compute and save these nonces are not yet supported. Users +/// who want to serialize this must use unsafe rust to do so. +#[allow(missing_copy_implementations)] +#[derive(Debug)] +pub struct SecretNonce(ffi::MusigSecNonce); + +impl CPtr for SecretNonce { + type Target = ffi::MusigSecNonce; + + fn as_c_ptr(&self) -> *const Self::Target { self.as_ptr() } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() } +} + +impl SecretNonce { + /// Get a const pointer to the inner KeyAggCache + pub fn as_ptr(&self) -> *const ffi::MusigSecNonce { &self.0 } + + /// Get a mut pointer to the inner KeyAggCache + pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigSecNonce { &mut self.0 } + + /// Function to return a copy of the internal array. See WARNING before using this function. + /// + /// # Warning: + /// This structure MUST NOT be copied or read or written to directly. A + /// signer who is online throughout the whole process and can keep this + /// structure in memory can use the provided API functions for a safe standard + /// workflow. + /// + /// We repeat, copying this data structure can result in nonce reuse which will + /// leak the secret signing key. + pub fn dangerous_into_bytes(self) -> [u8; secp256k1_sys::MUSIG_SECNONCE_LEN] { + self.0.dangerous_into_bytes() + } + + /// Function to create a new MusigKeyAggCoef from a 32 byte array. See WARNING before using this function. + /// + /// Refer to [`SecretNonce::dangerous_into_bytes`] for more details. + pub fn dangerous_from_bytes(array: [u8; secp256k1_sys::MUSIG_SECNONCE_LEN]) -> Self { + SecretNonce(ffi::MusigSecNonce::dangerous_from_bytes(array)) + } +} + +/// An individual MuSig public nonce. Not to be confused with [`AggregatedNonce`]. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct PublicNonce(ffi::MusigPubNonce); + +impl CPtr for PublicNonce { + type Target = ffi::MusigPubNonce; + + fn as_c_ptr(&self) -> *const Self::Target { self.as_ptr() } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() } +} + +impl PublicNonce { + /// Serialize a PublicNonce + pub fn serialize(&self) -> [u8; ffi::MUSIG_PUBNONCE_SERIALIZED_LEN] { + let mut data = [0; ffi::MUSIG_PUBNONCE_SERIALIZED_LEN]; + unsafe { + if ffi::secp256k1_musig_pubnonce_serialize( + ffi::secp256k1_context_no_precomp, + data.as_mut_ptr(), + self.as_ptr(), + ) == 0 + { + // Only fails when the arguments are invalid which is not possible in safe rust + unreachable!("Arguments must be valid and well-typed") + } else { + data + } + } + } + + /// Deserialize a PublicNonce from a portable byte representation + /// + /// # Errors: + /// + /// - MalformedArg: If the [`PublicNonce`] is 132 bytes, but out of curve order + pub fn from_byte_array(data: &[u8; ffi::MUSIG_PUBNONCE_SERIALIZED_LEN]) -> Result { + let mut pub_nonce = MaybeUninit::::uninit(); + unsafe { + if ffi::secp256k1_musig_pubnonce_parse( + ffi::secp256k1_context_no_precomp, + pub_nonce.as_mut_ptr(), + data.as_ptr(), + ) == 0 + { + Err(ParseError::MalformedArg) + } else { + Ok(PublicNonce(pub_nonce.assume_init())) + } + } + } + + /// Get a const pointer to the inner PublicNonce + pub fn as_ptr(&self) -> *const ffi::MusigPubNonce { &self.0 } + + /// Get a mut pointer to the inner PublicNonce + pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigPubNonce { &mut self.0 } +} + +/// Musig aggregated nonce computed by aggregating all individual public nonces +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct AggregatedNonce(ffi::MusigAggNonce); + +impl CPtr for AggregatedNonce { + type Target = ffi::MusigAggNonce; + + fn as_c_ptr(&self) -> *const Self::Target { self.as_ptr() } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() } +} + +impl AggregatedNonce { + /// Combine received public nonces into a single aggregated nonce + /// + /// This is useful to reduce the communication between signers, because instead + /// of everyone sending nonces to everyone else, there can be one party + /// receiving all nonces, combining the nonces with this function and then + /// sending only the combined nonce back to the signers. + /// + /// Example: + /// + /// ```rust + /// # # [cfg(any(test, feature = "rand-std"))] { + /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message, AggregatedNonce}; + /// # let secp = Secp256k1::new(); + /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// + /// # let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// // The session id must be sampled at random. Read documentation for more details. + /// + /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); + /// + /// let session_secrand1 = SessionSecretRand::new(&mut thread_rng()); + /// let (_sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_secrand1, pub_key1, msg, None) + /// .expect("non zero session id"); + /// + /// // Signer two does the same: Possibly on a different device + /// let session_secrand2 = SessionSecretRand::new(&mut thread_rng()); + /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pub_key2, msg, None) + /// .expect("non zero session id"); + /// + /// let aggnonce = AggregatedNonce::new(&secp, &[pub_nonce1, pub_nonce2]); + /// # } + /// ``` + pub fn new(secp: &Secp256k1, nonces: &[&PublicNonce]) -> Self { + + if nonces.is_empty() { + panic!("Cannot aggregate an empty slice of nonces"); + } + + let mut aggnonce = MaybeUninit::::uninit(); + + unsafe { + let pubnonces = core::slice::from_raw_parts(nonces.as_c_ptr() as *const *const ffi::MusigPubNonce, nonces.len()); + + if ffi::secp256k1_musig_nonce_agg( + secp.ctx().as_ptr(), + aggnonce.as_mut_ptr(), + pubnonces.as_ptr(), + pubnonces.len(), + ) == 0 + { + // This can only crash if the individual nonces are invalid which is not possible is rust. + // Note that even if aggregate nonce is point at infinity, the musig spec sets it as `G` + unreachable!("Public key nonces are well-formed and valid in rust typesystem") + } else { + AggregatedNonce(aggnonce.assume_init()) + } + } + } + + /// Serialize a AggregatedNonce into a 66 bytes array. + pub fn serialize(&self) -> [u8; ffi::MUSIG_AGGNONCE_SERIALIZED_LEN] { + let mut data = [0; ffi::MUSIG_AGGNONCE_SERIALIZED_LEN]; + unsafe { + if ffi::secp256k1_musig_aggnonce_serialize( + ffi::secp256k1_context_no_precomp, + data.as_mut_ptr(), + self.as_ptr(), + ) == 0 + { + // Only fails when the arguments are invalid which is not possible in safe rust + unreachable!("Arguments must be valid and well-typed") + } else { + data + } + } + } + + /// Deserialize a AggregatedNonce from byte slice + /// + /// # Errors: + /// + /// - MalformedArg: If the byte slice is 66 bytes, but the [`AggregatedNonce`] is invalid + pub fn from_byte_array(data: &[u8; ffi::MUSIG_AGGNONCE_SERIALIZED_LEN]) -> Result { + let mut aggnonce = MaybeUninit::::uninit(); + unsafe { + if ffi::secp256k1_musig_aggnonce_parse( + ffi::secp256k1_context_no_precomp, + aggnonce.as_mut_ptr(), + data.as_ptr(), + ) == 0 + { + Err(ParseError::MalformedArg) + } else { + Ok(AggregatedNonce(aggnonce.assume_init())) + } + } + } + + /// Get a const pointer to the inner AggregatedNonce + pub fn as_ptr(&self) -> *const ffi::MusigAggNonce { &self.0 } + + /// Get a mut pointer to the inner AggregatedNonce + pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigAggNonce { &mut self.0 } +} + +/// The aggregated signature of all partial signatures. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct AggregatedSignature([u8; 64]); + +impl AggregatedSignature { + /// Returns the aggregated signature [`schnorr::Signature`] assuming it is valid. + /// + /// The `partial_sig_agg` function cannot guarantee that the produced signature is valid because participants + /// may send invalid signatures. In some applications this doesn't matter because the invalid message is simply + /// dropped with no consequences. These can simply call this function to obtain the resulting signature. However + /// in applications that require having valid signatures before continuing (e.g. presigned transactions in Bitcoin Lightning Network) this would be exploitable. Such applications MUST verify the resulting signature using the + /// [`verify`](Self::verify) method. + /// + /// Note that while an alternative approach of verifying partial signatures is valid, verifying the aggregated + /// signature is more performant. Thus it should be generally better to verify the signature using this function first + /// and fall back to detection of violators if it fails. + pub fn assume_valid(self) -> schnorr::Signature { + schnorr::Signature::from_slice(&self.0) + .expect("Invalid signature data") + } + + /// Verify the aggregated signature against the aggregate public key and message + /// before returning the signature. + pub fn verify(self, secp: &Secp256k1, aggregate_key: &XOnlyPublicKey, message: &[u8]) -> Result { + let sig = schnorr::Signature::from_slice(&self.0)?; + secp.verify_schnorr(&sig, message, aggregate_key) + .map(|_| sig) + .map_err(|_| Error::IncorrectSignature) + } +} + +/// A musig Siging session. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Session(ffi::MusigSession); + +impl Session { + /// Creates a new musig signing session. + /// + /// Takes the public nonces of all signers and computes a session that is + /// required for signing and verification of partial signatures. + /// + /// # Returns: + /// + /// A [`Session`] that can be later used for signing. + /// + /// # Arguments: + /// + /// * `secp` : [`Secp256k1`] context object initialized for signing + /// * `key_agg_cache`: [`KeyAggCache`] to be used for this session + /// * `agg_nonce`: [`AggregatedNonce`], the aggregate nonce + /// * `msg`: [`Message`] that will be signed later on. + /// + /// Example: + /// + /// ```rust + /// # # [cfg(any(test, feature = "rand-std"))] { + /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message, AggregatedNonce, Session}; + /// # let secp = Secp256k1::new(); + /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// + /// # let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// // The session id must be sampled at random. Read documentation for more details. + /// + /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); + /// + /// // Provide the current time for mis-use resistance + /// let session_secrand1 = SessionSecretRand::new(&mut thread_rng()); + /// let extra_rand1 : Option<[u8; 32]> = None; + /// let (_sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_secrand1, pub_key1, msg, extra_rand1) + /// .expect("non zero session id"); + /// + /// // Signer two does the same. Possibly on a different device + /// let session_secrand2 = SessionSecretRand::new(&mut thread_rng()); + /// let extra_rand2 : Option<[u8; 32]> = None; + /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pub_key2, msg, extra_rand2) + /// .expect("non zero session id"); + /// + /// let aggnonce = AggregatedNonce::new(&secp, &[pub_nonce1, pub_nonce2]); + /// + /// let session = Session::new( + /// &secp, + /// &key_agg_cache, + /// aggnonce, + /// msg, + /// ); + /// # } + /// ``` + pub fn new( + secp: &Secp256k1, + key_agg_cache: &KeyAggCache, + agg_nonce: AggregatedNonce, + msg: Message, + ) -> Self { + let mut session = MaybeUninit::::uninit(); + + unsafe { + if ffi::secp256k1_musig_nonce_process( + secp.ctx().as_ptr(), + session.as_mut_ptr(), + agg_nonce.as_ptr(), + msg.as_c_ptr(), + key_agg_cache.as_ptr(), + ) == 0 + { + // Only fails on cryptographically unreachable codes or if the args are invalid. + // None of which can occur in safe rust. + unreachable!("Impossible to construct invalid arguments in safe rust. + Also reaches here if R1 + R2*b == point at infinity, but only occurs with 2^128 probability") + } else { + Session(session.assume_init()) + } + } + } + + /// Produces a partial signature for a given key pair and secret nonce. + /// + /// Remember that nonce reuse will immediately leak the secret key! + /// + /// # Returns: + /// + /// A [`PartialSignature`] that can be later be aggregated into a [`schnorr::Signature`] + /// + /// # Arguments: + /// + /// * `secp` : [`Secp256k1`] context object initialized for signing + /// * `sec_nonce`: [`SecretNonce`] to be used for this session that has never + /// been used before. For mis-use resistance, this API takes a mutable reference + /// to `sec_nonce` and sets it to zero even if the partial signing fails. + /// * `key_pair`: The [`Keypair`] to sign the message + /// * `key_agg_cache`: [`KeyAggCache`] containing the aggregate pubkey used in + /// the creation of this session + /// + /// # Errors: + /// + /// - If the provided [`SecretNonce`] has already been used for signing + /// + pub fn partial_sign( + &self, + secp: &Secp256k1, + mut secnonce: SecretNonce, + keypair: &Keypair, + key_agg_cache: &KeyAggCache, + ) -> PartialSignature { + unsafe { + let mut partial_sig = MaybeUninit::::uninit(); + + let res = ffi::secp256k1_musig_partial_sign( + secp.ctx().as_ptr(), + partial_sig.as_mut_ptr(), + secnonce.as_mut_ptr(), + keypair.as_c_ptr(), + key_agg_cache.as_ptr(), + self.as_ptr(), + ); + + assert_eq!(res, 1); + PartialSignature(partial_sig.assume_init()) + } + } + + /// Checks that an individual partial signature verifies + /// + /// This function is essential when using protocols with adaptor signatures. + /// However, it is not essential for regular MuSig's, in the sense that if any + /// partial signatures does not verify, the full signature will also not verify, so the + /// problem will be caught. But this function allows determining the specific party + /// who produced an invalid signature, so that signing can be restarted without them. + /// + /// # Returns: + /// + /// true if the partial signature successfully verifies, otherwise returns false + /// + /// # Arguments: + /// + /// * `secp` : [`Secp256k1`] context object initialized for signing + /// * `key_agg_cache`: [`KeyAggCache`] containing the aggregate pubkey used in + /// the creation of this session + /// * `partial_sig`: [`PartialSignature`] sent by the signer associated with + /// the given `pub_nonce` and `pubkey` + /// * `pub_nonce`: The [`PublicNonce`] of the signer associated with the `partial_sig` + /// and `pub_key` + /// * `pub_key`: The [`XOnlyPublicKey`] of the signer associated with the given + /// `partial_sig` and `pub_nonce` + /// + /// Example: + /// + /// ```rust + /// # # [cfg(any(test, feature = "rand-std"))] { + /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message, AggregatedNonce, Session}; + /// # let secp = Secp256k1::new(); + /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// + /// # let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// // The session id must be sampled at random. Read documentation for more details. + /// + /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); + /// + /// // Provide the current time for mis-use resistance + /// let session_secrand1 = SessionSecretRand::new(&mut thread_rng()); + /// let (mut sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_secrand1, pub_key1, msg, None) + /// .expect("non zero session id"); + /// + /// // Signer two does the same. Possibly on a different device + /// let session_secrand2 = SessionSecretRand::new(&mut thread_rng()); + /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pub_key2, msg, None) + /// .expect("non zero session id"); + /// + /// let aggnonce = AggregatedNonce::new(&secp, &[pub_nonce1, pub_nonce2]); + /// + /// let session = Session::new( + /// &secp, + /// &key_agg_cache, + /// aggnonce, + /// msg, + /// ); + /// + /// let keypair = Keypair::from_secret_key(&secp, &sk1); + /// let partial_sig1 = session.partial_sign( + /// &secp, + /// sec_nonce1, + /// &keypair, + /// &key_agg_cache, + /// ).unwrap(); + /// + /// assert!(session.partial_verify( + /// &secp, + /// &key_agg_cache, + /// partial_sig1, + /// pub_nonce1, + /// pub_key1, + /// )); + /// # } + /// ``` + pub fn partial_verify( + &self, + secp: &Secp256k1, + key_agg_cache: &KeyAggCache, + partial_sig: PartialSignature, + pub_nonce: PublicNonce, + pub_key: PublicKey, + ) -> bool { + let cx = secp.ctx().as_ptr(); + unsafe { + ffi::secp256k1_musig_partial_sig_verify( + cx, + partial_sig.as_ptr(), + pub_nonce.as_ptr(), + pub_key.as_c_ptr(), + key_agg_cache.as_ptr(), + self.as_ptr(), + ) == 1 + } + } + + /// Aggregate partial signatures for this session into a single [`schnorr::Signature`] + /// + /// # Returns: + /// + /// A single [`schnorr::Signature`]. Note that this does *NOT* mean that the signature verifies with respect to the + /// aggregate public key. + /// + /// # Arguments: + /// + /// * `partial_sigs`: Array of [`PartialSignature`] to be aggregated + /// + /// ```rust + /// # # [cfg(any(test, feature = "rand-std"))] { + /// # use secp256k1::rand::{thread_rng, RngCore}; + /// # use secp256k1::{KeyAggCache, Secp256k1, SecretKey, Keypair, PublicKey, SessionSecretRand, Message, AggregatedNonce, Session}; + /// # let secp = Secp256k1::new(); + /// # let sk1 = SecretKey::new(&mut thread_rng()); + /// # let pub_key1 = PublicKey::from_secret_key(&secp, &sk1); + /// # let sk2 = SecretKey::new(&mut thread_rng()); + /// # let pub_key2 = PublicKey::from_secret_key(&secp, &sk2); + /// + /// let key_agg_cache = KeyAggCache::new(&secp, &[pub_key1, pub_key2]); + /// // The session id must be sampled at random. Read documentation for more details. + /// + /// let msg = Message::from_digest_slice(b"Public Message we want to sign!!").unwrap(); + /// + /// // Provide the current time for mis-use resistance + /// let session_secrand1 = SessionSecretRand::new(&mut thread_rng()); + /// let (mut sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(&secp, session_secrand1, pub_key1, msg, None) + /// .expect("non zero session id"); + /// + /// // Signer two does the same. Possibly on a different device + /// let session_secrand2 = SessionSecretRand::new(&mut thread_rng()); + /// let (mut sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(&secp, session_secrand2, pub_key2, msg, None) + /// .expect("non zero session id"); + /// + /// let aggnonce = AggregatedNonce::new(&secp, &[pub_nonce1, pub_nonce2]); + /// + /// let session = Session::new( + /// &secp, + /// &key_agg_cache, + /// aggnonce, + /// msg, + /// ); + /// + /// let partial_sig1 = session.partial_sign( + /// &secp, + /// sec_nonce1, + /// &Keypair::from_secret_key(&secp, &sk1), + /// &key_agg_cache, + /// ).unwrap(); + /// + /// // Other party creates the other partial signature + /// let partial_sig2 = session.partial_sign( + /// &secp, + /// sec_nonce2, + /// &Keypair::from_secret_key(&secp, &sk2), + /// &key_agg_cache, + /// ).unwrap(); + /// + /// let partial_sigs = [partial_sign1, partial_sign2]; + /// let partial_sigs_ref: Vec<&PartialSignature> = partial_sigs.iter().collect(); + /// let partial_sigs_ref = partial_sigs_ref.as_slice(); + /// + /// let aggregated_signature = session.partial_sig_agg(partial_sigs_ref); + /// + /// // Get the final schnorr signature + /// assert!(aggregated_signature.verify(&secp, &agg_pk, &msg_bytes).is_ok()); + /// # } + /// ``` + pub fn partial_sig_agg(&self, partial_sigs: &[&PartialSignature]) -> AggregatedSignature { + + if partial_sigs.is_empty() { + panic!("Cannot aggregate an empty slice of partial signatures"); + } + + let mut sig = [0u8; 64]; + unsafe { + + let partial_sigs_ref = core::slice::from_raw_parts(partial_sigs.as_ptr() as *const *const ffi::MusigPartialSignature, partial_sigs.len()); + + if ffi::secp256k1_musig_partial_sig_agg( + ffi::secp256k1_context_no_precomp, + sig.as_mut_ptr(), + self.as_ptr(), + partial_sigs_ref.as_ptr(), + partial_sigs_ref.len(), + ) == 0 + { + // All arguments are well-typed partial signatures + unreachable!("Impossible to construct invalid(not well-typed) partial signatures") + } else { + // Resulting signature must be well-typed. Does not mean that will be succeed verification + AggregatedSignature(sig) + } + } + } + + /// Get a const pointer to the inner Session + pub fn as_ptr(&self) -> *const ffi::MusigSession { &self.0 } + + /// Get a mut pointer to the inner Session + pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigSession { &mut self.0 } +} diff --git a/ark-rust-secp256k1/src/scalar.rs b/ark-rust-secp256k1/src/scalar.rs new file mode 100644 index 00000000..4bd4d55f --- /dev/null +++ b/ark-rust-secp256k1/src/scalar.rs @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Provides [`Scalar`] and related types. +//! +//! In elliptic curve cryptography scalars are non-point values that can be used to multiply +//! points. The most common type of scalars are private keys. However not all scalars are private +//! keys. They can even be public *values*. To make handling them safer and easier this module +//! provides the `Scalar` type and related. +//! + +use core::{fmt, ops}; + +use crate::constants; + +/// Positive 256-bit integer guaranteed to be less than the secp256k1 curve order. +/// +/// The difference between `SecretKey` and `Scalar` is that `Scalar` doesn't guarantee being +/// securely usable as a private key. +/// +/// **Warning: the operations on this type are NOT constant time!** +/// Using this with secret values is not advised. +// Internal represenation is big endian to match what `libsecp256k1` uses. +// Also easier to implement comparison. +// Debug impl omitted for now, the bytes may be secret +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct Scalar([u8; 32]); +impl_pretty_debug!(Scalar); +impl_non_secure_erase!(Scalar, 0, [0u8; 32]); + +const MAX_RAW: [u8; 32] = [ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40, +]; + +impl Scalar { + /// Scalar representing `0` + pub const ZERO: Scalar = Scalar(constants::ZERO); + /// Scalar representing `1` + pub const ONE: Scalar = Scalar(constants::ONE); + /// Maximum valid value: `curve_order - 1` + pub const MAX: Scalar = Scalar(MAX_RAW); + + /// Generates a random scalar + #[cfg(all(feature = "rand", feature = "std"))] + pub fn random() -> Self { Self::random_custom(rand::thread_rng()) } + + /// Generates a random scalar using supplied RNG + #[cfg(feature = "rand")] + pub fn random_custom(mut rng: R) -> Self { + let mut bytes = [0u8; 32]; + loop { + rng.fill_bytes(&mut bytes); + // unlikely to go past MAX + if let Ok(scalar) = Scalar::from_be_bytes(bytes) { + break scalar; + } + } + } + + /// Tries to deserialize from big endian bytes + /// + /// **Security warning:** this function is not constant time! + /// Passing secret data is not recommended. + /// + /// # Errors + /// + /// Returns error when the value is above the curve order. + pub fn from_be_bytes(value: [u8; 32]) -> Result { + // Lexicographic ordering of arrays of the same length is same as ordering of BE numbers + if value <= MAX_RAW { + Ok(Scalar(value)) + } else { + Err(OutOfRangeError {}) + } + } + + /// Tries to deserialize from little endian bytes + /// + /// **Security warning:** this function is not constant time! + /// Passing secret data is not recommended. + /// + /// # Errors + /// + /// Returns error when the value is above the curve order. + pub fn from_le_bytes(mut value: [u8; 32]) -> Result { + value.reverse(); + Self::from_be_bytes(value) + } + + /// Serializes to big endian bytes + pub fn to_be_bytes(self) -> [u8; 32] { self.0 } + + /// Serializes to little endian bytes + pub fn to_le_bytes(self) -> [u8; 32] { + let mut res = self.0; + res.reverse(); + res + } + + // returns a reference to internal bytes + // non-public to not leak the internal representation + pub(crate) fn as_be_bytes(&self) -> &[u8; 32] { &self.0 } + + pub(crate) fn as_c_ptr(&self) -> *const u8 { + use secp256k1_sys::CPtr; + + self.as_be_bytes().as_c_ptr() + } +} + +impl ops::Index for Scalar +where + [u8]: ops::Index, +{ + type Output = <[u8] as ops::Index>::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { &self.0[index] } +} + +impl From for Scalar { + fn from(value: crate::SecretKey) -> Self { Scalar(value.secret_bytes()) } +} + +/// Error returned when the value of scalar is invalid - larger than the curve order. +// Intentionally doesn't implement `Copy` to improve forward compatibility. +// Same reason for `non_exhaustive`. +#[allow(missing_copy_implementations)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[non_exhaustive] +pub struct OutOfRangeError {} + +impl fmt::Display for OutOfRangeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt("the value is not a member of secp256k1 field", f) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for OutOfRangeError {} diff --git a/ark-rust-secp256k1/src/schnorr.rs b/ark-rust-secp256k1/src/schnorr.rs new file mode 100644 index 00000000..e83bd8fe --- /dev/null +++ b/ark-rust-secp256k1/src/schnorr.rs @@ -0,0 +1,723 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Support for schnorr signatures. +//! + +use core::{fmt, ptr, str}; + +#[cfg(feature = "rand")] +use rand::{CryptoRng, Rng}; +use secp256k1_sys::SchnorrSigExtraParams; + +use crate::ffi::{self, CPtr}; +use crate::key::{Keypair, XOnlyPublicKey}; +#[cfg(feature = "global-context")] +use crate::SECP256K1; +use crate::{constants, from_hex, Error, Secp256k1, Signing, Verification}; + +/// Represents a schnorr signature. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Signature([u8; constants::SCHNORR_SIGNATURE_SIZE]); +impl_array_newtype!(Signature, u8, constants::SCHNORR_SIGNATURE_SIZE); +impl_pretty_debug!(Signature); + +#[cfg(feature = "serde")] +impl serde::Serialize for Signature { + fn serialize(&self, s: S) -> Result { + if s.is_human_readable() { + s.collect_str(self) + } else { + s.serialize_bytes(&self[..]) + } + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for Signature { + fn deserialize>(d: D) -> Result { + if d.is_human_readable() { + d.deserialize_str(super::serde_util::FromStrVisitor::new( + "a hex string representing 64 byte schnorr signature", + )) + } else { + d.deserialize_bytes(super::serde_util::BytesVisitor::new( + "raw 64 bytes schnorr signature", + Signature::from_slice, + )) + } + } +} + +impl fmt::LowerHex for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for ch in &self.0[..] { + write!(f, "{:02x}", ch)?; + } + Ok(()) + } +} + +impl fmt::Display for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) } +} + +impl str::FromStr for Signature { + type Err = Error; + fn from_str(s: &str) -> Result { + let mut res = [0u8; constants::SCHNORR_SIGNATURE_SIZE]; + match from_hex(s, &mut res) { + Ok(constants::SCHNORR_SIGNATURE_SIZE) => Ok(Signature::from_byte_array(res)), + _ => Err(Error::InvalidSignature), + } + } +} + +impl Signature { + /// Construct a `Signature` from a 64 bytes array. + #[inline] + pub fn from_byte_array(sig: [u8; constants::SCHNORR_SIGNATURE_SIZE]) -> Self { Self(sig) } + + /// Creates a `Signature` directly from a slice. + #[deprecated(since = "TBD", note = "Use `from_byte_array` instead.")] + #[inline] + pub fn from_slice(data: &[u8]) -> Result { + match data.len() { + constants::SCHNORR_SIGNATURE_SIZE => { + let mut ret = [0u8; constants::SCHNORR_SIGNATURE_SIZE]; + ret[..].copy_from_slice(data); + Ok(Signature(ret)) + } + _ => Err(Error::InvalidSignature), + } + } + + /// Returns a signature as a byte array. + #[deprecated(since = "0.30.0", note = "Use `to_byte_array` instead.")] + pub fn serialize(&self) -> [u8; constants::SCHNORR_SIGNATURE_SIZE] { self.0 } + + /// Returns a signature as a byte array. + #[inline] + pub fn to_byte_array(self) -> [u8; constants::SCHNORR_SIGNATURE_SIZE] { self.0 } + + /// Returns a signature as a byte array. + #[inline] + pub fn as_byte_array(&self) -> &[u8; constants::SCHNORR_SIGNATURE_SIZE] { &self.0 } + + /// Verifies a schnorr signature for `msg` using `pk` and the global [`SECP256K1`] context. + #[inline] + #[cfg(feature = "global-context")] + pub fn verify(&self, msg: &[u8], pk: &XOnlyPublicKey) -> Result<(), Error> { + SECP256K1.verify_schnorr(self, msg, pk) + } +} + +impl Secp256k1 { + fn sign_schnorr_helper( + &self, + msg: &[u8], + keypair: &Keypair, + nonce_data: *const ffi::types::c_uchar, + ) -> Signature { + unsafe { + let mut sig = [0u8; constants::SCHNORR_SIGNATURE_SIZE]; + let extra = SchnorrSigExtraParams::new(None, nonce_data.cast()); + assert_eq!( + 1, + ffi::secp256k1_schnorrsig_sign_custom( + self.ctx.as_ptr(), + sig.as_mut_c_ptr(), + msg.as_c_ptr(), + msg.len(), + keypair.as_c_ptr(), + &extra, + ) + ); + + Signature(sig) + } + } + + /// Creates a schnorr signature internally using the [`rand::rngs::ThreadRng`] random number + /// generator to generate the auxiliary random data. + #[cfg(all(feature = "rand", feature = "std"))] + pub fn sign_schnorr(&self, msg: &[u8], keypair: &Keypair) -> Signature { + self.sign_schnorr_with_rng(msg, keypair, &mut rand::thread_rng()) + } + + /// Creates a schnorr signature without using any auxiliary random data. + pub fn sign_schnorr_no_aux_rand(&self, msg: &[u8], keypair: &Keypair) -> Signature { + self.sign_schnorr_helper(msg, keypair, ptr::null()) + } + + /// Creates a schnorr signature using the given auxiliary random data. + pub fn sign_schnorr_with_aux_rand( + &self, + msg: &[u8], + keypair: &Keypair, + aux_rand: &[u8; 32], + ) -> Signature { + self.sign_schnorr_helper(msg, keypair, aux_rand.as_c_ptr() as *const ffi::types::c_uchar) + } + + /// Creates a schnorr signature using the given random number generator to + /// generate the auxiliary random data. + #[cfg(feature = "rand")] + pub fn sign_schnorr_with_rng( + &self, + msg: &[u8], + keypair: &Keypair, + rng: &mut R, + ) -> Signature { + let mut aux = [0u8; 32]; + rng.fill_bytes(&mut aux); + self.sign_schnorr_helper(msg, keypair, aux.as_c_ptr() as *const ffi::types::c_uchar) + } +} + +impl Secp256k1 { + /// Verifies a schnorr signature. + pub fn verify_schnorr( + &self, + sig: &Signature, + msg: &[u8], + pubkey: &XOnlyPublicKey, + ) -> Result<(), Error> { + unsafe { + let ret = ffi::secp256k1_schnorrsig_verify( + self.ctx.as_ptr(), + sig.as_c_ptr(), + msg.as_c_ptr(), + msg.len(), + pubkey.as_c_ptr(), + ); + + if ret == 1 { + Ok(()) + } else { + Err(Error::IncorrectSignature) + } + } + } +} + +#[cfg(test)] +#[allow(unused_imports)] +mod tests { + use core::str::FromStr; + + #[cfg(all(feature = "rand", feature = "std"))] + use rand::rngs::ThreadRng; + #[cfg(target_arch = "wasm32")] + use wasm_bindgen_test::wasm_bindgen_test as test; + + use super::*; + use crate::schnorr::{Keypair, Signature, XOnlyPublicKey}; + use crate::Error::InvalidPublicKey; + use crate::{constants, from_hex, Message, Secp256k1, SecretKey}; + + #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))] + macro_rules! hex_32 { + ($hex:expr) => {{ + let mut result = [0u8; 32]; + from_hex($hex, &mut result).expect("valid hex string"); + result + }}; + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn schnorr_sign_with_aux_rand_verify() { + sign_helper(|secp, msg, seckey, rng| { + let aux_rand = crate::random_32_bytes(rng); + secp.sign_schnorr_with_aux_rand(msg, seckey, &aux_rand) + }) + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn schnor_sign_with_rng_verify() { + sign_helper(|secp, msg, seckey, rng| secp.sign_schnorr_with_rng(msg, seckey, rng)) + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn schnorr_sign_verify() { sign_helper(|secp, msg, seckey, _| secp.sign_schnorr(msg, seckey)) } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn schnorr_sign_no_aux_rand_verify() { + sign_helper(|secp, msg, seckey, _| secp.sign_schnorr_no_aux_rand(msg, seckey)) + } + + #[cfg(all(feature = "rand", feature = "std"))] + fn sign_helper(sign: fn(&Secp256k1, &[u8], &Keypair, &mut ThreadRng) -> Signature) { + let secp = Secp256k1::new(); + + let mut rng = rand::thread_rng(); + let kp = Keypair::new(&secp, &mut rng); + let (pk, _parity) = kp.x_only_public_key(); + + for _ in 0..100 { + let msg = crate::random_32_bytes(&mut rand::thread_rng()); + + let sig = sign(&secp, &msg, &kp, &mut rng); + + assert!(secp.verify_schnorr(&sig, &msg, &pk).is_ok()); + } + } + + #[test] + #[cfg(feature = "alloc")] + #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs + fn schnorr_sign() { + let secp = Secp256k1::new(); + + let msg = hex_32!("E48441762FB75010B2AA31A512B62B4148AA3FB08EB0765D76B252559064A614"); + let sk = Keypair::from_seckey_str( + &secp, + "688C77BC2D5AAFF5491CF309D4753B732135470D05B7B2CD21ADD0744FE97BEF", + ) + .unwrap(); + let aux_rand: [u8; 32] = + hex_32!("02CCE08E913F22A36C5648D6405A2C7C50106E7AA2F1649E381C7F09D16B80AB"); + let expected_sig = Signature::from_str("6470FD1303DDA4FDA717B9837153C24A6EAB377183FC438F939E0ED2B620E9EE5077C4A8B8DCA28963D772A94F5F0DDF598E1C47C137F91933274C7C3EDADCE8").unwrap(); + + let sig = secp.sign_schnorr_with_aux_rand(&msg, &sk, &aux_rand); + + assert_eq!(expected_sig, sig); + } + + #[test] + #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs + #[cfg(feature = "alloc")] + fn schnorr_verify() { + let secp = Secp256k1::new(); + + let msg = hex_32!("E48441762FB75010B2AA31A512B62B4148AA3FB08EB0765D76B252559064A614"); + let sig = Signature::from_str("6470FD1303DDA4FDA717B9837153C24A6EAB377183FC438F939E0ED2B620E9EE5077C4A8B8DCA28963D772A94F5F0DDF598E1C47C137F91933274C7C3EDADCE8").unwrap(); + let pubkey = XOnlyPublicKey::from_str( + "B33CC9EDC096D0A83416964BD3C6247B8FECD256E4EFA7870D2C854BDEB33390", + ) + .unwrap(); + + assert!(secp.verify_schnorr(&sig, &msg, &pubkey).is_ok()); + } + + #[test] + fn test_serialize() { + let sig = Signature::from_str("6470FD1303DDA4FDA717B9837153C24A6EAB377183FC438F939E0ED2B620E9EE5077C4A8B8DCA28963D772A94F5F0DDF598E1C47C137F91933274C7C3EDADCE8").unwrap(); + let sig_bytes = sig.to_byte_array(); + let bytes = [ + 100, 112, 253, 19, 3, 221, 164, 253, 167, 23, 185, 131, 113, 83, 194, 74, 110, 171, 55, + 113, 131, 252, 67, 143, 147, 158, 14, 210, 182, 32, 233, 238, 80, 119, 196, 168, 184, + 220, 162, 137, 99, 215, 114, 169, 79, 95, 13, 223, 89, 142, 28, 71, 193, 55, 249, 25, + 51, 39, 76, 124, 62, 218, 220, 232, + ]; + assert_eq!(sig_bytes, bytes); + } + + #[test] + fn test_pubkey_from_slice() { + assert_eq!(XOnlyPublicKey::from_slice(&[]), Err(InvalidPublicKey)); + assert_eq!(XOnlyPublicKey::from_slice(&[1, 2, 3]), Err(InvalidPublicKey)); + let pk = XOnlyPublicKey::from_slice(&[ + 0xB3, 0x3C, 0xC9, 0xED, 0xC0, 0x96, 0xD0, 0xA8, 0x34, 0x16, 0x96, 0x4B, 0xD3, 0xC6, + 0x24, 0x7B, 0x8F, 0xEC, 0xD2, 0x56, 0xE4, 0xEF, 0xA7, 0x87, 0x0D, 0x2C, 0x85, 0x4B, + 0xDE, 0xB3, 0x33, 0x90, + ]); + assert!(pk.is_ok()); + } + + #[test] + #[cfg(all(feature = "rand", feature = "std"))] + fn test_pubkey_serialize_roundtrip() { + let secp = Secp256k1::new(); + let kp = Keypair::new(&secp, &mut rand::thread_rng()); + let (pk, _parity) = kp.x_only_public_key(); + + let ser = pk.serialize(); + let pubkey2 = XOnlyPublicKey::from_slice(&ser).unwrap(); + assert_eq!(pk, pubkey2); + } + + #[test] + #[cfg(feature = "alloc")] + fn test_xonly_key_extraction() { + let secp = Secp256k1::new(); + let sk_str = "688C77BC2D5AAFF5491CF309D4753B732135470D05B7B2CD21ADD0744FE97BEF"; + let keypair = Keypair::from_seckey_str(&secp, sk_str).unwrap(); + let sk = SecretKey::from_keypair(&keypair); + assert_eq!(SecretKey::from_str(sk_str).unwrap(), sk); + let pk = crate::key::PublicKey::from_keypair(&keypair); + assert_eq!(crate::key::PublicKey::from_secret_key(&secp, &sk), pk); + let (xpk, _parity) = keypair.x_only_public_key(); + assert_eq!(XOnlyPublicKey::from(pk), xpk); + } + + #[test] + fn test_pubkey_from_bad_slice() { + // Bad sizes + assert_eq!( + XOnlyPublicKey::from_slice(&[0; constants::SCHNORR_PUBLIC_KEY_SIZE - 1]), + Err(InvalidPublicKey) + ); + assert_eq!( + XOnlyPublicKey::from_slice(&[0; constants::SCHNORR_PUBLIC_KEY_SIZE + 1]), + Err(InvalidPublicKey) + ); + + // Bad parse + assert_eq!( + XOnlyPublicKey::from_slice(&[0xff; constants::SCHNORR_PUBLIC_KEY_SIZE]), + Err(InvalidPublicKey) + ); + // In fuzzing mode restrictions on public key validity are much more + // relaxed, thus the invalid check below is expected to fail. + #[cfg(not(secp256k1_fuzz))] + assert_eq!( + XOnlyPublicKey::from_slice(&[0x55; constants::SCHNORR_PUBLIC_KEY_SIZE]), + Err(InvalidPublicKey) + ); + assert_eq!(XOnlyPublicKey::from_slice(&[]), Err(InvalidPublicKey)); + } + + #[test] + #[cfg(feature = "std")] + fn test_pubkey_display_output() { + #[cfg(not(secp256k1_fuzz))] + let pk = { + let secp = Secp256k1::new(); + static SK_BYTES: [u8; 32] = [ + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, + ]; + + let kp = Keypair::from_seckey_slice(&secp, &SK_BYTES).expect("sk"); + + // In fuzzing mode secret->public key derivation is different, so + // hard-code the expected result. + let (pk, _parity) = kp.x_only_public_key(); + pk + }; + #[cfg(secp256k1_fuzz)] + let pk = XOnlyPublicKey::from_slice(&[ + 0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f, 0x1c, 0x97, 0x09, 0xe2, 0x30, 0x92, + 0x06, 0x7d, 0x06, 0x83, 0x7f, 0x30, 0xaa, 0x0c, 0xd0, 0x54, 0x4a, 0xc8, 0x87, 0xfe, + 0x91, 0xdd, 0xd1, 0x66, + ]) + .expect("pk"); + + assert_eq!( + pk.to_string(), + "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166" + ); + assert_eq!( + XOnlyPublicKey::from_str( + "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166" + ) + .unwrap(), + pk + ); + + assert!(XOnlyPublicKey::from_str( + "00000000000000000000000000000000000000000000000000000000000000000" + ) + .is_err()); + assert!(XOnlyPublicKey::from_str( + "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16601" + ) + .is_err()); + assert!(XOnlyPublicKey::from_str( + "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16" + ) + .is_err()); + assert!(XOnlyPublicKey::from_str( + "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1" + ) + .is_err()); + assert!(XOnlyPublicKey::from_str( + "xx18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1" + ) + .is_err()); + + let long_str: String = "a".repeat(1024 * 1024); + assert!(XOnlyPublicKey::from_str(&long_str).is_err()); + } + + #[test] + // In fuzzing mode secret->public key derivation is different, so + // this test will never correctly derive the static pubkey. + #[cfg(not(secp256k1_fuzz))] + #[cfg(all(feature = "rand", feature = "alloc"))] + fn test_pubkey_serialize() { + use rand::rngs::mock::StepRng; + let secp = Secp256k1::new(); + let kp = Keypair::new(&secp, &mut StepRng::new(1, 1)); + let (pk, _parity) = kp.x_only_public_key(); + assert_eq!( + &pk.serialize()[..], + &[ + 124, 121, 49, 14, 253, 63, 197, 50, 39, 194, 107, 17, 193, 219, 108, 154, 126, 9, + 181, 248, 2, 12, 149, 233, 198, 71, 149, 134, 250, 184, 154, 229 + ][..] + ); + } + + #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs + #[test] + #[cfg(all(feature = "serde", feature = "alloc"))] + fn test_serde() { + use serde_test::{assert_tokens, Configure, Token}; + + let s = Secp256k1::new(); + + let msg = [1; 32]; + let keypair = Keypair::from_seckey_slice(&s, &[2; 32]).unwrap(); + let aux = [3u8; 32]; + let sig = s.sign_schnorr_with_aux_rand(&msg, &keypair, &aux); + static SIG_BYTES: [u8; constants::SCHNORR_SIGNATURE_SIZE] = [ + 0x14, 0xd0, 0xbf, 0x1a, 0x89, 0x53, 0x50, 0x6f, 0xb4, 0x60, 0xf5, 0x8b, 0xe1, 0x41, + 0xaf, 0x76, 0x7f, 0xd1, 0x12, 0x53, 0x5f, 0xb3, 0x92, 0x2e, 0xf2, 0x17, 0x30, 0x8e, + 0x2c, 0x26, 0x70, 0x6f, 0x1e, 0xeb, 0x43, 0x2b, 0x3d, 0xba, 0x9a, 0x01, 0x08, 0x2f, + 0x9e, 0x4d, 0x4e, 0xf5, 0x67, 0x8a, 0xd0, 0xd9, 0xd5, 0x32, 0xc0, 0xdf, 0xa9, 0x07, + 0xb5, 0x68, 0x72, 0x2d, 0x0b, 0x01, 0x19, 0xba, + ]; + static SIG_STR: &str = "\ + 14d0bf1a8953506fb460f58be141af767fd112535fb3922ef217308e2c26706f1eeb432b3dba9a01082f9e4d4ef5678ad0d9d532c0dfa907b568722d0b0119ba\ + "; + + static PK_BYTES: [u8; 32] = [ + 24, 132, 87, 129, 246, 49, 196, 143, 28, 151, 9, 226, 48, 146, 6, 125, 6, 131, 127, 48, + 170, 12, 208, 84, 74, 200, 135, 254, 145, 221, 209, 102, + ]; + static PK_STR: &str = "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"; + let pk = XOnlyPublicKey::from_slice(&PK_BYTES).unwrap(); + + assert_tokens(&sig.compact(), &[Token::BorrowedBytes(&SIG_BYTES[..])]); + assert_tokens(&sig.compact(), &[Token::Bytes(&SIG_BYTES[..])]); + assert_tokens(&sig.compact(), &[Token::ByteBuf(&SIG_BYTES[..])]); + + assert_tokens(&sig.readable(), &[Token::BorrowedStr(SIG_STR)]); + assert_tokens(&sig.readable(), &[Token::Str(SIG_STR)]); + assert_tokens(&sig.readable(), &[Token::String(SIG_STR)]); + + #[rustfmt::skip] + assert_tokens(&pk.compact(), &[ + Token::Tuple{ len: 32 }, + Token::U8(24), Token::U8(132), Token::U8(87), Token::U8(129), Token::U8(246), Token::U8(49), Token::U8(196), Token::U8(143), + Token::U8(28), Token::U8(151), Token::U8(9), Token::U8(226), Token::U8(48), Token::U8(146), Token::U8(6), Token::U8(125), + Token::U8(6), Token::U8(131), Token::U8(127), Token::U8(48), Token::U8(170), Token::U8(12), Token::U8(208), Token::U8(84), + Token::U8(74), Token::U8(200), Token::U8(135), Token::U8(254), Token::U8(145), Token::U8(221), Token::U8(209), Token::U8(102), + Token::TupleEnd + ]); + + assert_tokens(&pk.readable(), &[Token::BorrowedStr(PK_STR)]); + assert_tokens(&pk.readable(), &[Token::Str(PK_STR)]); + assert_tokens(&pk.readable(), &[Token::String(PK_STR)]); + } + + #[test] + #[cfg(feature = "alloc")] + #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs + fn bip340_test_vectors() { + struct TestVector { + secret_key: Option<[u8; 32]>, + public_key: [u8; 32], + aux_rand: Option<[u8; 32]>, + message: Vec, + signature: [u8; 64], + should_fail_verify: bool, + } + fn hex_arr, const N: usize>(s: &str) -> T { + let mut out = [0; N]; + from_hex(s, &mut out).unwrap(); + out.into() + } + let hex_vec = |s: &str| { + let mut v = vec![0u8; s.len() / 2]; + from_hex(s, v.as_mut_slice()).unwrap(); + v + }; + + let vectors = [ + TestVector { + secret_key: hex_arr("0000000000000000000000000000000000000000000000000000000000000003"), + public_key: hex_arr("F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9"), + aux_rand: hex_arr("0000000000000000000000000000000000000000000000000000000000000000"), + message: hex_vec("0000000000000000000000000000000000000000000000000000000000000000"), + signature: hex_arr("E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA821525F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0"), + should_fail_verify: false, + }, + TestVector { + secret_key: hex_arr("B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF"), + public_key: hex_arr("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), + aux_rand: hex_arr("0000000000000000000000000000000000000000000000000000000000000001"), + message: hex_vec("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), + signature: hex_arr("6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A"), + should_fail_verify: false, + }, + TestVector { + secret_key: hex_arr("C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9"), + public_key: hex_arr("DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8"), + aux_rand: hex_arr("C87AA53824B4D7AE2EB035A2B5BBBCCC080E76CDC6D1692C4B0B62D798E6D906"), + message: hex_vec("7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C"), + signature: hex_arr("5831AAEED7B44BB74E5EAB94BA9D4294C49BCF2A60728D8B4C200F50DD313C1BAB745879A5AD954A72C45A91C3A51D3C7ADEA98D82F8481E0E1E03674A6F3FB7"), + should_fail_verify: false, + }, + TestVector { + secret_key: hex_arr("0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710"), + public_key: hex_arr("25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517"), + aux_rand: hex_arr("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), + message: hex_vec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), + signature: hex_arr("7EB0509757E246F19449885651611CB965ECC1A187DD51B64FDA1EDC9637D5EC97582B9CB13DB3933705B32BA982AF5AF25FD78881EBB32771FC5922EFC66EA3"), + should_fail_verify: false, + }, + TestVector { + secret_key: None, + public_key: hex_arr("D69C3509BB99E412E68B0FE8544E72837DFA30746D8BE2AA65975F29D22DC7B9"), + aux_rand: None, + message: hex_vec("4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703"), + signature: hex_arr("00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6376AFB1548AF603B3EB45C9F8207DEE1060CB71C04E80F593060B07D28308D7F4"), + should_fail_verify: false, + }, + TestVector { + secret_key: None, + public_key: hex_arr("EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34"), + aux_rand: None, + message: hex_vec("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), + signature: hex_arr("6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"), + should_fail_verify: true, + }, + TestVector { + secret_key: None, + public_key: hex_arr("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), + aux_rand: None, + message: hex_vec("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), + signature: hex_arr("FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A14602975563CC27944640AC607CD107AE10923D9EF7A73C643E166BE5EBEAFA34B1AC553E2"), + should_fail_verify: true, + }, + TestVector { + secret_key: None, + public_key: hex_arr("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), + aux_rand: None, + message: hex_vec("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), + signature: hex_arr("1FA62E331EDBC21C394792D2AB1100A7B432B013DF3F6FF4F99FCB33E0E1515F28890B3EDB6E7189B630448B515CE4F8622A954CFE545735AAEA5134FCCDB2BD"), + should_fail_verify: true, + }, + TestVector { + secret_key: None, + public_key: hex_arr("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), + aux_rand: None, + message: hex_vec("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), + signature: hex_arr("6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769961764B3AA9B2FFCB6EF947B6887A226E8D7C93E00C5ED0C1834FF0D0C2E6DA6"), + should_fail_verify: true, + }, + TestVector { + secret_key: None, + public_key: hex_arr("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), + aux_rand: None, + message: hex_vec("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), + signature: hex_arr("0000000000000000000000000000000000000000000000000000000000000000123DDA8328AF9C23A94C1FEECFD123BA4FB73476F0D594DCB65C6425BD186051"), + should_fail_verify: true, + }, + TestVector { + secret_key: None, + public_key: hex_arr("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), + aux_rand: None, + message: hex_vec("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), + signature: hex_arr("00000000000000000000000000000000000000000000000000000000000000017615FBAF5AE28864013C099742DEADB4DBA87F11AC6754F93780D5A1837CF197"), + should_fail_verify: true, + }, + TestVector { + secret_key: None, + public_key: hex_arr("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), + aux_rand: None, + message: hex_vec("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), + signature: hex_arr("4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"), + should_fail_verify: true, + }, + TestVector { + secret_key: None, + public_key: hex_arr("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), + aux_rand: None, + message: hex_vec("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), + signature: hex_arr("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"), + should_fail_verify: true, + }, + TestVector { + secret_key: None, + public_key: hex_arr("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), + aux_rand: None, + message: hex_vec("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), + signature: hex_arr("6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"), + should_fail_verify: true, + }, + TestVector { + secret_key: None, + public_key: hex_arr("778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117"), + aux_rand: None, + message: hex_vec("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), + signature: hex_arr("6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"), + should_fail_verify: true, + }, + TestVector { + secret_key: hex_arr("0340034003400340034003400340034003400340034003400340034003400340"), + public_key: hex_arr("778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117"), + aux_rand: hex_arr("0000000000000000000000000000000000000000000000000000000000000000"), + message: hex_vec(""), + signature: hex_arr("71535DB165ECD9FBBC046E5FFAEA61186BB6AD436732FCCC25291A55895464CF6069CE26BF03466228F19A3A62DB8A649F2D560FAC652827D1AF0574E427AB63"), + should_fail_verify: false, + }, + TestVector { + secret_key: hex_arr("0340034003400340034003400340034003400340034003400340034003400340"), + public_key: hex_arr("778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117"), + aux_rand: hex_arr("0000000000000000000000000000000000000000000000000000000000000000"), + message: hex_vec("11"), + signature: hex_arr("08A20A0AFEF64124649232E0693C583AB1B9934AE63B4C3511F3AE1134C6A303EA3173BFEA6683BD101FA5AA5DBC1996FE7CACFC5A577D33EC14564CEC2BACBF"), + should_fail_verify: false, + }, + TestVector { + secret_key: hex_arr("0340034003400340034003400340034003400340034003400340034003400340"), + public_key: hex_arr("778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117"), + aux_rand: hex_arr("0000000000000000000000000000000000000000000000000000000000000000"), + message: hex_vec("0102030405060708090A0B0C0D0E0F1011"), + signature: hex_arr("5130F39A4059B43BC7CAC09A19ECE52B5D8699D1A71E3C52DA9AFDB6B50AC370C4A482B77BF960F8681540E25B6771ECE1E5A37FD80E5A51897C5566A97EA5A5"), + should_fail_verify: false, + }, + TestVector { + secret_key: hex_arr("0340034003400340034003400340034003400340034003400340034003400340"), + public_key: hex_arr("778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117"), + aux_rand: hex_arr("0000000000000000000000000000000000000000000000000000000000000000"), + message: hex_vec("99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"), + signature: hex_arr("403B12B0D8555A344175EA7EC746566303321E5DBFA8BE6F091635163ECA79A8585ED3E3170807E7C03B720FC54C7B23897FCBA0E9D0B4A06894CFD249F22367"), + should_fail_verify: false, + }, + ]; + let secp = Secp256k1::new(); + + for TestVector { + secret_key, + public_key, + aux_rand, + message, + signature, + should_fail_verify, + } in vectors + { + if let (Some(secret_key), Some(aux_rand)) = (secret_key, aux_rand) { + let keypair = Keypair::from_seckey_slice(&secp, &secret_key).unwrap(); + assert_eq!(keypair.x_only_public_key().0.serialize(), public_key); + let sig = secp.sign_schnorr_with_aux_rand(&message, &keypair, &aux_rand); + assert_eq!(sig.to_byte_array(), signature); + } + let sig = Signature::from_byte_array(signature); + let is_verified = if let Ok(pubkey) = XOnlyPublicKey::from_slice(&public_key) { + secp.verify_schnorr(&sig, &message, &pubkey).is_ok() + } else { + false + }; + assert_eq!(is_verified, !should_fail_verify); + } + } +} diff --git a/ark-rust-secp256k1/src/secret.rs b/ark-rust-secp256k1/src/secret.rs new file mode 100644 index 00000000..f5fc1060 --- /dev/null +++ b/ark-rust-secp256k1/src/secret.rs @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Helpers for displaying secret values + +use core::fmt; + +use crate::constants::SECRET_KEY_SIZE; +use crate::ecdh::SharedSecret; +use crate::key::{Keypair, SecretKey}; +use crate::to_hex; +macro_rules! impl_display_secret { + // Default hasher exists only in standard library and not alloc + ($thing:ident) => { + #[cfg(feature = "hashes")] + impl ::core::fmt::Debug for $thing { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use hashes::{sha256, Hash, HashEngine}; + + let tag = "rust-secp256k1DEBUG"; + + let mut engine = sha256::Hash::engine(); + let tag_hash = sha256::Hash::hash(tag.as_bytes()); + engine.input(&tag_hash.as_ref()); + engine.input(&tag_hash.as_ref()); + engine.input(&self.secret_bytes()); + let hash = sha256::Hash::from_engine(engine); + + f.debug_tuple(stringify!($thing)).field(&format_args!("#{:.16}", hash)).finish() + } + } + + #[cfg(not(feature = "hashes"))] + impl ::core::fmt::Debug for $thing { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!( + f, + "" + ) + } + } + }; +} + +/// Helper struct for safely printing secrets (like [`SecretKey`] value). +/// Formats the explicit byte value of the secret kept inside the type as a +/// little-endian hexadecimal string using the provided formatter. +/// +/// Secrets should not implement neither [`Debug`] and [`Display`] traits directly, +/// and instead provide `fn display_secret<'a>(&'a self) -> DisplaySecret<'a>` +/// function to be used in different display contexts (see "examples" below). +/// +/// [`Display`]: fmt::Display +/// [`Debug`]: fmt::Debug +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct DisplaySecret { + secret: [u8; SECRET_KEY_SIZE], +} +impl_non_secure_erase!(DisplaySecret, secret, [0u8; SECRET_KEY_SIZE]); + +impl fmt::Debug for DisplaySecret { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut slice = [0u8; SECRET_KEY_SIZE * 2]; + let hex = to_hex(&self.secret, &mut slice).expect("fixed-size hex serializer failed"); + f.debug_tuple("DisplaySecret").field(&hex).finish() + } +} + +impl fmt::Display for DisplaySecret { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for byte in &self.secret { + write!(f, "{:02x}", byte)?; + } + Ok(()) + } +} + +impl SecretKey { + /// Formats the explicit byte value of the secret key kept inside the type as a + /// little-endian hexadecimal string using the provided formatter. + /// + /// This is the only method that outputs the actual secret key value, and, thus, + /// should be used with extreme caution. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "std")] { + /// # use std::str::FromStr; + /// use secp256k1::SecretKey; + /// let key = SecretKey::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); + /// + /// // Normal debug hides value (`Display` is not implemented for `SecretKey`). + /// // E.g., `format!("{:?}", key)` prints "SecretKey(#2518682f7819fb2d)". + /// + /// // Here we explicitly display the secret value: + /// assert_eq!( + /// "0000000000000000000000000000000000000000000000000000000000000001", + /// format!("{}", key.display_secret()) + /// ); + /// // Also, we can explicitly display with `Debug`: + /// assert_eq!( + /// format!("{:?}", key.display_secret()), + /// format!("DisplaySecret(\"{}\")", key.display_secret()) + /// ); + /// # } + /// ``` + #[inline] + pub fn display_secret(&self) -> DisplaySecret { DisplaySecret { secret: self.secret_bytes() } } +} + +impl Keypair { + /// Formats the explicit byte value of the secret key kept inside the type as a + /// little-endian hexadecimal string using the provided formatter. + /// + /// This is the only method that outputs the actual secret key value, and, thus, + /// should be used with extreme precaution. + /// + /// # Example + /// + /// ``` + /// # #[cfg(feature = "std")] { + /// # use std::str::FromStr; + /// use secp256k1::{Keypair, Secp256k1, SecretKey}; + /// + /// let secp = Secp256k1::new(); + /// let key = SecretKey::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); + /// let key = Keypair::from_secret_key(&secp, &key); + /// // Here we explicitly display the secret value: + /// assert_eq!( + /// "0000000000000000000000000000000000000000000000000000000000000001", + /// format!("{}", key.display_secret()) + /// ); + /// // Also, we can explicitly display with `Debug`: + /// assert_eq!( + /// format!("{:?}", key.display_secret()), + /// format!("DisplaySecret(\"{}\")", key.display_secret()) + /// ); + /// # } + /// ``` + #[inline] + pub fn display_secret(&self) -> DisplaySecret { DisplaySecret { secret: self.secret_bytes() } } +} + +impl SharedSecret { + /// Formats the explicit byte value of the shared secret kept inside the type as a + /// little-endian hexadecimal string using the provided formatter. + /// + /// This is the only method that outputs the actual shared secret value, and, thus, + /// should be used with extreme caution. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(not(secp256k1_fuzz))] + /// # #[cfg(feature = "std")] { + /// # use std::str::FromStr; + /// use secp256k1::{SecretKey, PublicKey}; + /// use secp256k1::ecdh::SharedSecret; + /// + /// # let pk = PublicKey::from_slice(&[3, 23, 183, 225, 206, 31, 159, 148, 195, 42, 67, 115, 146, 41, 248, 140, 11, 3, 51, 41, 111, 180, 110, 143, 114, 134, 88, 73, 198, 174, 52, 184, 78]).expect("hard coded slice should parse correctly"); + /// # let sk = SecretKey::from_str("57f0148f94d13095cfda539d0da0d1541304b678d8b36e243980aab4e1b7cead").unwrap(); + /// + /// let secret = SharedSecret::new(&pk, &sk); + /// // Here we explicitly display the secret value: + /// assert_eq!( + /// format!("{}", secret.display_secret()), + /// "cf05ae7da039ddce6d56dd57d3000c6dd91c6f1695eae47e05389f11e2467043" + /// ); + /// // Also, we can explicitly display with `Debug`: + /// assert_eq!( + /// format!("{:?}", secret.display_secret()), + /// format!("DisplaySecret(\"{}\")", secret.display_secret()) + /// ); + /// # } + /// ``` + #[inline] + pub fn display_secret(&self) -> DisplaySecret { DisplaySecret { secret: self.secret_bytes() } } +} diff --git a/ark-rust-secp256k1/src/serde_util.rs b/ark-rust-secp256k1/src/serde_util.rs new file mode 100644 index 00000000..3b851b2c --- /dev/null +++ b/ark-rust-secp256k1/src/serde_util.rs @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: CC0-1.0 + +use core::fmt; +use core::marker::PhantomData; +use core::str::{self, FromStr}; + +use serde::de; + +/// A serde visitor that works for `T`s implementing `FromStr`. +pub struct FromStrVisitor { + expectation: &'static str, + _pd: PhantomData, +} + +impl FromStrVisitor { + pub fn new(expectation: &'static str) -> Self { + FromStrVisitor { expectation, _pd: PhantomData } + } +} + +impl<'de, T> de::Visitor<'de> for FromStrVisitor +where + T: FromStr, + ::Err: fmt::Display, +{ + type Value = T; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(self.expectation) + } + + fn visit_str(self, v: &str) -> Result { + FromStr::from_str(v).map_err(E::custom) + } +} + +pub struct BytesVisitor { + expectation: &'static str, + parse_fn: F, +} + +impl BytesVisitor +where + F: FnOnce(&[u8]) -> Result, + Err: fmt::Display, +{ + pub fn new(expectation: &'static str, parse_fn: F) -> Self { + BytesVisitor { expectation, parse_fn } + } +} + +impl<'de, F, T, Err> de::Visitor<'de> for BytesVisitor +where + F: FnOnce(&[u8]) -> Result, + Err: fmt::Display, +{ + type Value = T; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(self.expectation) + } + + fn visit_bytes(self, v: &[u8]) -> Result { + (self.parse_fn)(v).map_err(E::custom) + } +} + +macro_rules! impl_tuple_visitor { + ($thing:ident, $len:expr) => { + pub(crate) struct $thing { + expectation: &'static str, + parse_fn: F, + } + + impl $thing + where + F: FnOnce(&[u8]) -> Result, + E: fmt::Display, + { + pub fn new(expectation: &'static str, parse_fn: F) -> Self { + $thing { expectation, parse_fn } + } + } + + impl<'de, F, T, E> de::Visitor<'de> for $thing + where + F: FnOnce(&[u8]) -> Result, + E: fmt::Display, + { + type Value = T; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(self.expectation) + } + + fn visit_seq(self, mut seq: V) -> Result + where + V: de::SeqAccess<'de>, + { + let mut bytes = [0u8; $len]; + + for (i, byte) in bytes.iter_mut().enumerate() { + if let Some(value) = seq.next_element()? { + *byte = value; + } else { + return Err(de::Error::invalid_length(i, &self)); + } + } + (self.parse_fn)(&bytes).map_err(de::Error::custom) + } + } + }; +} + +impl_tuple_visitor!(Tuple32Visitor, 32); +impl_tuple_visitor!(Tuple33Visitor, 33); diff --git a/dprint.json b/dprint.json index 239183fa..594867e5 100644 --- a/dprint.json +++ b/dprint.json @@ -10,7 +10,7 @@ ], "excludes": [ "**/target", - "ark-rust-secp256k1-zkp/*" + "ark-rust-secp256k1/*" ], "exec": { "commands": [ diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 0c541693..9f3d9737 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -15,6 +15,7 @@ bitcoin = { version = "0.32.4", features = ["rand"] } bitcoinconsensus = "0.106.0" esplora-client = { version = "0.10.0", features = ["async-https", "blocking-https"] } futures = "0.3.31" +musig = { package = "ark-secp256k1", path = "../ark-rust-secp256k1", features = ["serde"] } prost = "0.13.3" rand = "0.8.5" regex = "1" @@ -22,4 +23,3 @@ tokio = { version = "1.41.0", features = ["full"] } tonic = "0.12.3" tracing = "0.1.37" tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt", "ansi", "env-filter", "time", "tracing-log", "json"] } -zkp = { package = "ark-secp256k1-zkp", version = "0.10.0", path = "../ark-rust-secp256k1-zkp", features = ["serde", "rand-std"] }