mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-20 19:11:08 +03:00
Initial import.
This commit is contained in:
commit
f73a308bf3
144 changed files with 29870 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*.swp
|
||||||
|
target
|
40
README.md
Normal file
40
README.md
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# Grin
|
||||||
|
|
||||||
|
Grin is an in-progress implementation of the MimbleWimble protocol. Many characteristics are still undefined but the following constitutes a first set of choices:
|
||||||
|
|
||||||
|
* Clean and minimal implementation, aiming to stay as such.
|
||||||
|
* Follows the MimbleWimble protocol, which provides great anonymity and scaling characteristics.
|
||||||
|
* Cuckoo Cycle proof of work (at least to start with).
|
||||||
|
* Relatively fast block time (a minute or less, possibly decreasing as networks improve).
|
||||||
|
* Fixed block reward, both over time and in blocks (fees are not additive).
|
||||||
|
* Transaction fees are based on the number of UTXO created/destroyed and total transaction size.
|
||||||
|
* Smooth curve for difficulty adjustments.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Grin is still an infant, much is left to be done and contributions are welcome (see below). Our [status file](TODO.md) may help.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Find an area you can help with and do it. Open source is about collaboration and open participation. Try to make your code look like what already exists and submit a pull request. If you're looking for additional ideas, the code includes TODO comments for minor to major improvements. Grep is your friend.
|
||||||
|
|
||||||
|
Additional tests are rewarded with an immense amount of positive karma. So is documentation.
|
||||||
|
|
||||||
|
Find us on Gitter: https://gitter.im/grin_community
|
||||||
|
|
||||||
|
## Philosophy
|
||||||
|
|
||||||
|
Grin likes itself small and easy on the eyes. It wants to be inclusive and welcoming for all walks of life, without judgement. Grin is terribly ambitious, but not at the detriment of others, rather to further us all. It may have strong opinions to stay in line with its objectives, which doesn't mean disrepect of others' ideas.
|
||||||
|
|
||||||
|
We believe in pull requests, data and scientific research. We do not believe in unfounded beliefs.
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
Tom Elvis Jedusor for the first formulation of MimbleWimble.
|
||||||
|
Andrew Poelstra for his related work and improvements.
|
||||||
|
John Tromp for the Cuckoo Cycles proof of work.
|
||||||
|
J.K. Rowling for making it despite extraordinary adversity.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Apache License v2.0.
|
16
TODO.md
Normal file
16
TODO.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# Rolling up our sleeves
|
||||||
|
|
||||||
|
Grin is still an infant, much is left to be done and contributions are welcome. Here's a (non exhaustive) list of what's left to implement:
|
||||||
|
|
||||||
|
* Transaction signatures aggregation.
|
||||||
|
* Proper API to author transactions.
|
||||||
|
* Protocol layer (handshake, send blocks, ask for blocks, send txs, ask for them, sync, etc.).
|
||||||
|
* Maintenance of the UTXO set and its Merkle tree.
|
||||||
|
* Transaction pool and related validation.
|
||||||
|
* Chain logic and related validation.
|
||||||
|
* Efficient miner (as a distinct project).
|
||||||
|
* User-friendly wallet (as a distinct project).
|
||||||
|
* Figure out if the rangeproofs can be eliminated under some cicrumstances while keeping security guarantes.
|
||||||
|
* Website, logo design and all the cool stuff.
|
||||||
|
|
||||||
|
Don't worry, we'll get there, with your help.
|
15
chain/Cargo.toml
Normal file
15
chain/Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "grin_chain"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Ignotus Peverell <igno.peverell@protonmail.com>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bitflags = "^0.7.0"
|
||||||
|
byteorder = "^0.5"
|
||||||
|
|
||||||
|
grin_core = { path = "../core" }
|
||||||
|
grin_store = { path = "../store" }
|
||||||
|
secp256k1zkp = { path = "../secp256k1zkp" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
rand = "^0.3"
|
3
chain/rustfmt.toml
Normal file
3
chain/rustfmt.toml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
hard_tabs = true
|
||||||
|
wrap_comments = true
|
||||||
|
write_mode = "Overwrite"
|
26
chain/src/lib.rs
Normal file
26
chain/src/lib.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
//! The block chain itself, validates and accepts new blocks, handles reorgs.
|
||||||
|
|
||||||
|
#![deny(non_upper_case_globals)]
|
||||||
|
#![deny(non_camel_case_types)]
|
||||||
|
#![deny(non_snake_case)]
|
||||||
|
#![deny(unused_mut)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate bitflags;
|
||||||
|
extern crate byteorder;
|
||||||
|
|
||||||
|
#[macro_use(try_m)]
|
||||||
|
extern crate grin_core as core;
|
||||||
|
extern crate grin_store;
|
||||||
|
extern crate secp256k1zkp as secp;
|
||||||
|
|
||||||
|
pub mod pipe;
|
||||||
|
pub mod store;
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
|
// Re-export the base interface
|
||||||
|
|
||||||
|
pub use types::ChainStore;
|
||||||
|
pub use chain::Options;
|
||||||
|
pub use chain::process_block;
|
118
chain/src/pipe.rs
Normal file
118
chain/src/pipe.rs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
//! Implementation of the chain block acceptance (or refusal) pipeline.
|
||||||
|
|
||||||
|
use secp;
|
||||||
|
|
||||||
|
use core::core::{Hash, BlockHeader, Block, Proof};
|
||||||
|
use core::pow;
|
||||||
|
use types;
|
||||||
|
use types::{Tip, ChainStore};
|
||||||
|
use store;
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
/// Options for block validation
|
||||||
|
pub flags Options: u32 {
|
||||||
|
/// Runs with the easier version of the Proof of Work, mostly to make testing easier.
|
||||||
|
const EASY_POW = 0b00000001,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contextual information required to process a new block and either reject or
|
||||||
|
/// accept it.
|
||||||
|
pub struct BlockContext<'a> {
|
||||||
|
opts: Options,
|
||||||
|
store: &'a ChainStore,
|
||||||
|
head: Tip,
|
||||||
|
tip: Option<Tip>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// The block doesn't fit anywhere in our chain
|
||||||
|
Unfit(String),
|
||||||
|
/// The proof of work is invalid
|
||||||
|
InvalidPow,
|
||||||
|
/// The block doesn't sum correctly or a tx signature is invalid
|
||||||
|
InvalidBlockProof(secp::Error),
|
||||||
|
/// Internal issue when trying to save the block
|
||||||
|
StoreErr(types::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_block(b: &Block, store: &ChainStore, opts: Options) -> Option<Error> {
|
||||||
|
// TODO should just take a promise for a block with a full header so we don't
|
||||||
|
// spend resources reading the full block when its header is invalid
|
||||||
|
|
||||||
|
let head = match store.head() {
|
||||||
|
Ok(head) => head,
|
||||||
|
Err(err) => return Some(Error::StoreErr(err)),
|
||||||
|
};
|
||||||
|
let mut ctx = BlockContext {
|
||||||
|
opts: opts,
|
||||||
|
store: store,
|
||||||
|
head: head,
|
||||||
|
tip: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
try_m!(validate_header(&b, &mut ctx));
|
||||||
|
try_m!(set_tip(&b.header, &mut ctx));
|
||||||
|
try_m!(validate_block(b, &mut ctx));
|
||||||
|
try_m!(add_block(b, &mut ctx));
|
||||||
|
try_m!(update_tips(&mut ctx));
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// block processing pipeline
|
||||||
|
// 1. is the header valid (time, PoW, etc.)
|
||||||
|
// 2. is it the next head, a new fork, or extension of a fork (not a too old
|
||||||
|
// fork tho)
|
||||||
|
// 3. ok fine, is all of it valid (txs, merkle, utxo merkle, etc.)
|
||||||
|
// 4. add the sucker to the head/fork
|
||||||
|
// 5. did we increase a fork difficulty over the head?
|
||||||
|
// 6. ok fine, swap them up (can be tricky, think addresses invalidation)
|
||||||
|
|
||||||
|
/// First level of black validation that only needs to act on the block header
|
||||||
|
/// to make it as cheap as possible. The different validations are also
|
||||||
|
/// arranged by order of cost to have as little DoS surface as possible.
|
||||||
|
/// TODO actually require only the block header (with length information)
|
||||||
|
fn validate_header(b: &Block, ctx: &mut BlockContext) -> Option<Error> {
|
||||||
|
let header = &b.header;
|
||||||
|
println!("{} {}", header.height, ctx.head.height);
|
||||||
|
if header.height > ctx.head.height + 1 {
|
||||||
|
// TODO actually handle orphans and add them to a size-limited set
|
||||||
|
return Some(Error::Unfit("orphan".to_string()));
|
||||||
|
}
|
||||||
|
// TODO check time wrt to chain time, refuse older than 100 blocks or too far
|
||||||
|
// in future
|
||||||
|
|
||||||
|
// TODO maintain current difficulty
|
||||||
|
let diff_target = Proof(pow::MAX_TARGET);
|
||||||
|
|
||||||
|
if ctx.opts.intersects(EASY_POW) {
|
||||||
|
if !pow::verify20(b, diff_target) {
|
||||||
|
return Some(Error::InvalidPow);
|
||||||
|
}
|
||||||
|
} else if !pow::verify(b, diff_target) {
|
||||||
|
return Some(Error::InvalidPow);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_tip(h: &BlockHeader, ctx: &mut BlockContext) -> Option<Error> {
|
||||||
|
ctx.tip = Some(ctx.head.clone());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_block(b: &Block, ctx: &mut BlockContext) -> Option<Error> {
|
||||||
|
// TODO check tx merkle tree
|
||||||
|
let curve = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
|
||||||
|
try_m!(b.verify(&curve).err().map(&Error::InvalidBlockProof));
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_block(b: &Block, ctx: &mut BlockContext) -> Option<Error> {
|
||||||
|
ctx.tip = ctx.tip.as_ref().map(|t| t.append(b.hash()));
|
||||||
|
ctx.store.save_block(b).map(&Error::StoreErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_tips(ctx: &mut BlockContext) -> Option<Error> {
|
||||||
|
ctx.store.save_head(ctx.tip.as_ref().unwrap()).map(&Error::StoreErr)
|
||||||
|
}
|
69
chain/src/store.rs
Normal file
69
chain/src/store.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
//! Implements storage primitives required by the chain
|
||||||
|
|
||||||
|
use byteorder::{WriteBytesExt, BigEndian};
|
||||||
|
|
||||||
|
use types::*;
|
||||||
|
use core::core::Block;
|
||||||
|
use grin_store;
|
||||||
|
|
||||||
|
const STORE_PATH: &'static str = ".grin/chain";
|
||||||
|
|
||||||
|
const SEP: u8 = ':' as u8;
|
||||||
|
|
||||||
|
const BLOCK_PREFIX: u8 = 'B' as u8;
|
||||||
|
const TIP_PREFIX: u8 = 'T' as u8;
|
||||||
|
const HEAD_PREFIX: u8 = 'H' as u8;
|
||||||
|
|
||||||
|
/// An implementation of the ChainStore trait backed by a simple key-value
|
||||||
|
/// store.
|
||||||
|
pub struct ChainKVStore {
|
||||||
|
db: grin_store::Store,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChainKVStore {
|
||||||
|
pub fn new() -> Result<ChainKVStore, Error> {
|
||||||
|
let db = try!(grin_store::Store::open(STORE_PATH).map_err(to_store_err));
|
||||||
|
Ok(ChainKVStore { db: db })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChainStore for ChainKVStore {
|
||||||
|
fn head(&self) -> Result<Tip, Error> {
|
||||||
|
option_to_not_found(self.db.get_ser(&vec![HEAD_PREFIX]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_block(&self, b: &Block) -> Option<Error> {
|
||||||
|
self.db.put_ser(&to_key(BLOCK_PREFIX, &mut b.hash().to_vec())[..], b).map(&to_store_err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_head(&self, t: &Tip) -> Option<Error> {
|
||||||
|
try_m!(self.save_tip(t));
|
||||||
|
self.db.put_ser(&vec![HEAD_PREFIX], t).map(&to_store_err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_tip(&self, t: &Tip) -> Option<Error> {
|
||||||
|
let last_branch = t.lineage.last_branch();
|
||||||
|
let mut k = vec![TIP_PREFIX, SEP];
|
||||||
|
k.write_u32::<BigEndian>(last_branch);
|
||||||
|
self.db.put_ser(&mut k, t).map(&to_store_err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_key(prefix: u8, val: &mut Vec<u8>) -> &mut Vec<u8> {
|
||||||
|
val.insert(0, SEP);
|
||||||
|
val.insert(0, prefix);
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_store_err(e: grin_store::Error) -> Error {
|
||||||
|
Error::StorageErr(format!("{:?}", e))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// unwraps the inner option by converting the none case to a not found error
|
||||||
|
fn option_to_not_found<T>(res: Result<Option<T>, grin_store::Error>) -> Result<T, Error> {
|
||||||
|
match res {
|
||||||
|
Ok(None) => Err(Error::NotFoundErr),
|
||||||
|
Ok(Some(o)) => Ok(o),
|
||||||
|
Err(e) => Err(to_store_err(e)),
|
||||||
|
}
|
||||||
|
}
|
133
chain/src/types.rs
Normal file
133
chain/src/types.rs
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
//! Base types that the block chain pipeline requires.
|
||||||
|
|
||||||
|
use core::core::{Hash, Block};
|
||||||
|
use core::ser;
|
||||||
|
|
||||||
|
/// The lineage of a fork, defined as a series of numbers. Each new branch gets
|
||||||
|
/// a new number that gets added to a fork's ancestry to form a new fork.
|
||||||
|
/// Example:
|
||||||
|
/// head [1] -> fork1 [1, 2]
|
||||||
|
/// fork2 [1, 3]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Lineage(Vec<u32>);
|
||||||
|
|
||||||
|
impl Lineage {
|
||||||
|
/// New lineage initialized just with branch 0
|
||||||
|
pub fn new() -> Lineage {
|
||||||
|
Lineage(vec![0])
|
||||||
|
}
|
||||||
|
/// The last branch that was added to the lineage. Also the only branch
|
||||||
|
/// that's
|
||||||
|
/// unique to this lineage.
|
||||||
|
pub fn last_branch(&self) -> u32 {
|
||||||
|
*self.0.last().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialization for lineage, necessary to serialize fork tips.
|
||||||
|
impl ser::Writeable for Lineage {
|
||||||
|
fn write(&self, writer: &mut ser::Writer) -> Option<ser::Error> {
|
||||||
|
try_m!(writer.write_u32(self.0.len() as u32));
|
||||||
|
for num in &self.0 {
|
||||||
|
try_m!(writer.write_u32(*num));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Deserialization for lineage, necessary to deserialize fork tips.
|
||||||
|
impl ser::Readable<Lineage> for Lineage {
|
||||||
|
fn read(reader: &mut ser::Reader) -> Result<Lineage, ser::Error> {
|
||||||
|
let len = try!(reader.read_u32());
|
||||||
|
let mut branches = Vec::with_capacity(len as usize);
|
||||||
|
for _ in 0..len {
|
||||||
|
branches.push(try!(reader.read_u32()));
|
||||||
|
}
|
||||||
|
Ok(Lineage(branches))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The tip of a fork. A handle to the fork ancestry from its leaf in the
|
||||||
|
/// blockchain tree. References both the lineage of the fork as well as its max
|
||||||
|
/// height and its latest and previous blocks for convenience.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Tip {
|
||||||
|
/// Height of the tip (max height of the fork)
|
||||||
|
pub height: u64,
|
||||||
|
/// Last block pushed to the fork
|
||||||
|
pub last_block_h: Hash,
|
||||||
|
/// Block previous to last
|
||||||
|
pub prev_block_h: Hash,
|
||||||
|
/// Lineage in branch numbers of the fork
|
||||||
|
pub lineage: Lineage,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tip {
|
||||||
|
/// Creates a new tip at height zero and the provided genesis hash.
|
||||||
|
pub fn new(gbh: Hash) -> Tip {
|
||||||
|
Tip {
|
||||||
|
height: 0,
|
||||||
|
last_block_h: gbh,
|
||||||
|
prev_block_h: gbh,
|
||||||
|
lineage: Lineage::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append a new block hash to this tip, returning a new updated tip.
|
||||||
|
pub fn append(&self, bh: Hash) -> Tip {
|
||||||
|
Tip {
|
||||||
|
height: self.height + 1,
|
||||||
|
last_block_h: bh,
|
||||||
|
prev_block_h: self.last_block_h,
|
||||||
|
lineage: self.lineage.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialization of a tip, required to save to datastore.
|
||||||
|
impl ser::Writeable for Tip {
|
||||||
|
fn write(&self, writer: &mut ser::Writer) -> Option<ser::Error> {
|
||||||
|
try_m!(writer.write_u64(self.height));
|
||||||
|
try_m!(writer.write_fixed_bytes(&self.last_block_h));
|
||||||
|
try_m!(writer.write_fixed_bytes(&self.prev_block_h));
|
||||||
|
self.lineage.write(writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ser::Readable<Tip> for Tip {
|
||||||
|
fn read(reader: &mut ser::Reader) -> Result<Tip, ser::Error> {
|
||||||
|
let height = try!(reader.read_u64());
|
||||||
|
let last = try!(reader.read_fixed_bytes(32));
|
||||||
|
let prev = try!(reader.read_fixed_bytes(32));
|
||||||
|
let line = try!(Lineage::read(reader));
|
||||||
|
Ok(Tip {
|
||||||
|
height: height,
|
||||||
|
last_block_h: Hash::from_vec(last),
|
||||||
|
prev_block_h: Hash::from_vec(prev),
|
||||||
|
lineage: line,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Couldn't find what we were looking for
|
||||||
|
NotFoundErr,
|
||||||
|
/// Error generated by the underlying storage layer
|
||||||
|
StorageErr(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait the chain pipeline requires an implementor for in order to process
|
||||||
|
/// blocks.
|
||||||
|
pub trait ChainStore {
|
||||||
|
/// Get the tip that's also the head of the chain
|
||||||
|
fn head(&self) -> Result<Tip, Error>;
|
||||||
|
|
||||||
|
/// Save the provided block in store
|
||||||
|
fn save_block(&self, b: &Block) -> Option<Error>;
|
||||||
|
|
||||||
|
/// Save the provided tip as the current head of our chain
|
||||||
|
fn save_head(&self, t: &Tip) -> Option<Error>;
|
||||||
|
|
||||||
|
/// Save the provided tip without setting it as head
|
||||||
|
fn save_tip(&self, t: &Tip) -> Option<Error>;
|
||||||
|
}
|
50
chain/tests/mine_simple_chain.rs
Normal file
50
chain/tests/mine_simple_chain.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
extern crate grin_core;
|
||||||
|
extern crate grin_chain;
|
||||||
|
extern crate rand;
|
||||||
|
extern crate secp256k1zkp as secp;
|
||||||
|
|
||||||
|
use rand::os::OsRng;
|
||||||
|
|
||||||
|
use grin_chain::types::*;
|
||||||
|
use grin_core::pow;
|
||||||
|
use grin_core::core;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mine_empty_chain() {
|
||||||
|
let curve = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
|
||||||
|
let mut rng = OsRng::new().unwrap();
|
||||||
|
let store = grin_chain::store::ChainKVStore::new().unwrap();
|
||||||
|
|
||||||
|
// save a genesis block
|
||||||
|
let gen = grin_core::genesis::genesis();
|
||||||
|
assert!(store.save_block(&gen).is_none());
|
||||||
|
|
||||||
|
// setup a new head tip
|
||||||
|
let tip = Tip::new(gen.hash());
|
||||||
|
assert!(store.save_head(&tip).is_none());
|
||||||
|
|
||||||
|
// mine and add a few blocks
|
||||||
|
let mut prev = gen;
|
||||||
|
let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
|
||||||
|
let reward_key = secp::key::SecretKey::new(&secp, &mut rng);
|
||||||
|
|
||||||
|
for n in 1..6 {
|
||||||
|
let mut b = core::Block::new(prev.header, vec![], reward_key).unwrap();
|
||||||
|
println!("=> {} {:?}", b.header.height, b.verify(&curve));
|
||||||
|
|
||||||
|
let (proof, nonce) = pow::pow20(&b, core::Proof(pow::MAX_TARGET)).unwrap();
|
||||||
|
b.header.pow = proof;
|
||||||
|
b.header.nonce = nonce;
|
||||||
|
if let Some(e) = grin_chain::pipe::process_block(&b, &store, grin_chain::pipe::EASY_POW) {
|
||||||
|
println!("err: {:?}", e);
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
||||||
|
// checking our new head
|
||||||
|
let head = store.head().unwrap();
|
||||||
|
assert_eq!(head.height, n);
|
||||||
|
assert_eq!(head.last_block_h, b.hash());
|
||||||
|
|
||||||
|
prev = b;
|
||||||
|
}
|
||||||
|
}
|
13
core/Cargo.toml
Normal file
13
core/Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[package]
|
||||||
|
name = "grin_core"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Ignotus Peverell <igno.peverell@protonmail.com>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
byteorder = "^0.5"
|
||||||
|
rust-crypto = "^0.2"
|
||||||
|
rand = "^0.3"
|
||||||
|
time = "^0.1"
|
||||||
|
tiny-keccak = "1.1"
|
||||||
|
|
||||||
|
secp256k1zkp = { path = "../secp256k1zkp" }
|
3
core/rustfmt.toml
Normal file
3
core/rustfmt.toml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
hard_tabs = true
|
||||||
|
wrap_comments = true
|
||||||
|
write_mode = "Overwrite"
|
1028
core/src/core/mod.rs
Normal file
1028
core/src/core/mod.rs
Normal file
File diff suppressed because it is too large
Load diff
308
core/src/core/ser.rs
Normal file
308
core/src/core/ser.rs
Normal file
|
@ -0,0 +1,308 @@
|
||||||
|
//! Binary stream serialization and deserialzation for core types from trusted
|
||||||
|
//! Write or Read implementations. Issues like starvation or too big sends are
|
||||||
|
//! expected to be handled upstream.
|
||||||
|
|
||||||
|
use time;
|
||||||
|
|
||||||
|
use std::io::{Write, Read};
|
||||||
|
use core;
|
||||||
|
use ser::*;
|
||||||
|
|
||||||
|
use secp::Signature;
|
||||||
|
use secp::key::SecretKey;
|
||||||
|
use secp::pedersen::{Commitment, RangeProof};
|
||||||
|
|
||||||
|
const MAX_IN_OUT_LEN: u64 = 50000;
|
||||||
|
|
||||||
|
macro_rules! impl_slice_bytes {
|
||||||
|
($byteable: ty) => {
|
||||||
|
impl AsFixedBytes for $byteable {
|
||||||
|
fn as_fixed_bytes(&self) -> &[u8] {
|
||||||
|
&self[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_slice_bytes!(SecretKey);
|
||||||
|
impl_slice_bytes!(Signature);
|
||||||
|
impl_slice_bytes!(Commitment);
|
||||||
|
impl_slice_bytes!(Vec<u8>);
|
||||||
|
|
||||||
|
impl AsFixedBytes for core::Hash {
|
||||||
|
fn as_fixed_bytes(&self) -> &[u8] {
|
||||||
|
self.to_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsFixedBytes for RangeProof {
|
||||||
|
fn as_fixed_bytes(&self) -> &[u8] {
|
||||||
|
&self.bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of Writeable for a transaction Input, defines how to write
|
||||||
|
/// an Input as binary.
|
||||||
|
impl Writeable for core::Input {
|
||||||
|
fn write(&self, writer: &mut Writer) -> Option<Error> {
|
||||||
|
writer.write_fixed_bytes(&self.output_hash())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of Writeable for a transaction Output, defines how to write
|
||||||
|
/// an Output as binary.
|
||||||
|
impl Writeable for core::Output {
|
||||||
|
fn write(&self, writer: &mut Writer) -> Option<Error> {
|
||||||
|
try_m!(writer.write_fixed_bytes(&self.commitment().unwrap()));
|
||||||
|
writer.write_vec(&mut self.proof().unwrap().bytes().to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of Writeable for a fully blinded transaction, defines how to
|
||||||
|
/// write the transaction as binary.
|
||||||
|
impl Writeable for core::Transaction {
|
||||||
|
fn write(&self, writer: &mut Writer) -> Option<Error> {
|
||||||
|
try_m!(writer.write_u64(self.fee));
|
||||||
|
try_m!(writer.write_vec(&mut self.zerosig.clone()));
|
||||||
|
try_m!(writer.write_u64(self.inputs.len() as u64));
|
||||||
|
try_m!(writer.write_u64(self.outputs.len() as u64));
|
||||||
|
for inp in &self.inputs {
|
||||||
|
try_m!(inp.write(writer));
|
||||||
|
}
|
||||||
|
for out in &self.outputs {
|
||||||
|
try_m!(out.write(writer));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Writeable for core::TxProof {
|
||||||
|
fn write(&self, writer: &mut Writer) -> Option<Error> {
|
||||||
|
try_m!(writer.write_fixed_bytes(&self.remainder));
|
||||||
|
writer.write_vec(&mut self.sig.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of Writeable for a block, defines how to write the full
|
||||||
|
/// block as binary.
|
||||||
|
impl Writeable for core::Block {
|
||||||
|
fn write(&self, writer: &mut Writer) -> Option<Error> {
|
||||||
|
try_m!(self.header.write(writer));
|
||||||
|
|
||||||
|
try_m!(writer.write_u64(self.inputs.len() as u64));
|
||||||
|
try_m!(writer.write_u64(self.outputs.len() as u64));
|
||||||
|
try_m!(writer.write_u64(self.proofs.len() as u64));
|
||||||
|
for inp in &self.inputs {
|
||||||
|
try_m!(inp.write(writer));
|
||||||
|
}
|
||||||
|
for out in &self.outputs {
|
||||||
|
try_m!(out.write(writer));
|
||||||
|
}
|
||||||
|
for proof in &self.proofs {
|
||||||
|
try_m!(proof.write(writer));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of Readable for a transaction Input, defines how to read
|
||||||
|
/// an Input from a binary stream.
|
||||||
|
impl Readable<core::Input> for core::Input {
|
||||||
|
fn read(reader: &mut Reader) -> Result<core::Input, Error> {
|
||||||
|
reader.read_fixed_bytes(32)
|
||||||
|
.map(|h| core::Input::BareInput { output: core::Hash::from_vec(h) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of Readable for a transaction Output, defines how to read
|
||||||
|
/// an Output from a binary stream.
|
||||||
|
impl Readable<core::Output> for core::Output {
|
||||||
|
fn read(reader: &mut Reader) -> Result<core::Output, Error> {
|
||||||
|
let commit = try!(reader.read_fixed_bytes(33));
|
||||||
|
let proof = try!(reader.read_vec());
|
||||||
|
Ok(core::Output::BlindOutput {
|
||||||
|
commit: Commitment::from_vec(commit),
|
||||||
|
proof: RangeProof::from_vec(proof),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of Readable for a transaction, defines how to read a full
|
||||||
|
/// transaction from a binary stream.
|
||||||
|
impl Readable<core::Transaction> for core::Transaction {
|
||||||
|
fn read(reader: &mut Reader) -> Result<core::Transaction, Error> {
|
||||||
|
let fee = try!(reader.read_u64());
|
||||||
|
let zerosig = try!(reader.read_vec());
|
||||||
|
let input_len = try!(reader.read_u64());
|
||||||
|
let output_len = try!(reader.read_u64());
|
||||||
|
|
||||||
|
// in case a facetious miner sends us more than what we can allocate
|
||||||
|
if input_len > MAX_IN_OUT_LEN || output_len > MAX_IN_OUT_LEN {
|
||||||
|
return Err(Error::TooLargeReadErr("Too many inputs or outputs.".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let inputs = try!((0..input_len).map(|_| core::Input::read(reader)).collect());
|
||||||
|
let outputs = try!((0..output_len).map(|_| core::Output::read(reader)).collect());
|
||||||
|
|
||||||
|
Ok(core::Transaction {
|
||||||
|
fee: fee,
|
||||||
|
zerosig: zerosig,
|
||||||
|
inputs: inputs,
|
||||||
|
outputs: outputs,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Readable<core::TxProof> for core::TxProof {
|
||||||
|
fn read(reader: &mut Reader) -> Result<core::TxProof, Error> {
|
||||||
|
let remainder = try!(reader.read_fixed_bytes(33));
|
||||||
|
let sig = try!(reader.read_vec());
|
||||||
|
Ok(core::TxProof {
|
||||||
|
remainder: Commitment::from_vec(remainder),
|
||||||
|
sig: sig,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of Readable for a block, defines how to read a full block
|
||||||
|
/// from a binary stream.
|
||||||
|
impl Readable<core::Block> for core::Block {
|
||||||
|
fn read(reader: &mut Reader) -> Result<core::Block, Error> {
|
||||||
|
let height = try!(reader.read_u64());
|
||||||
|
let previous = try!(reader.read_fixed_bytes(32));
|
||||||
|
let timestamp = try!(reader.read_i64());
|
||||||
|
let utxo_merkle = try!(reader.read_fixed_bytes(32));
|
||||||
|
let tx_merkle = try!(reader.read_fixed_bytes(32));
|
||||||
|
let total_fees = try!(reader.read_u64());
|
||||||
|
let nonce = try!(reader.read_u64());
|
||||||
|
// cuckoo cycle of 42 nodes
|
||||||
|
let mut pow = [0; core::PROOFSIZE];
|
||||||
|
for n in 0..core::PROOFSIZE {
|
||||||
|
pow[n] = try!(reader.read_u32());
|
||||||
|
}
|
||||||
|
let td = try!(reader.read_u64());
|
||||||
|
|
||||||
|
let input_len = try!(reader.read_u64());
|
||||||
|
let output_len = try!(reader.read_u64());
|
||||||
|
let proof_len = try!(reader.read_u64());
|
||||||
|
if input_len > MAX_IN_OUT_LEN || output_len > MAX_IN_OUT_LEN || proof_len > MAX_IN_OUT_LEN {
|
||||||
|
return Err(Error::TooLargeReadErr("Too many inputs, outputs or proofs.".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let inputs = try!((0..input_len).map(|_| core::Input::read(reader)).collect());
|
||||||
|
let outputs = try!((0..output_len).map(|_| core::Output::read(reader)).collect());
|
||||||
|
let proofs = try!((0..proof_len).map(|_| core::TxProof::read(reader)).collect());
|
||||||
|
Ok(core::Block {
|
||||||
|
header: core::BlockHeader {
|
||||||
|
height: height,
|
||||||
|
previous: core::Hash::from_vec(previous),
|
||||||
|
timestamp: time::at_utc(time::Timespec {
|
||||||
|
sec: timestamp,
|
||||||
|
nsec: 0,
|
||||||
|
}),
|
||||||
|
td: td,
|
||||||
|
utxo_merkle: core::Hash::from_vec(utxo_merkle),
|
||||||
|
tx_merkle: core::Hash::from_vec(tx_merkle),
|
||||||
|
total_fees: total_fees,
|
||||||
|
pow: core::Proof(pow),
|
||||||
|
nonce: nonce,
|
||||||
|
},
|
||||||
|
inputs: inputs,
|
||||||
|
outputs: outputs,
|
||||||
|
proofs: proofs,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use ser::{serialize, deserialize};
|
||||||
|
use secp;
|
||||||
|
use secp::*;
|
||||||
|
use secp::key::*;
|
||||||
|
use core::*;
|
||||||
|
use rand::Rng;
|
||||||
|
use rand::os::OsRng;
|
||||||
|
|
||||||
|
fn new_secp() -> Secp256k1 {
|
||||||
|
secp::Secp256k1::with_caps(secp::ContextFlag::Commit)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_tx_ser() {
|
||||||
|
let mut rng = OsRng::new().unwrap();
|
||||||
|
let ref secp = new_secp();
|
||||||
|
|
||||||
|
let tx = tx2i1o(secp, &mut rng);
|
||||||
|
let btx = tx.blind(&secp).unwrap();
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
if let Some(e) = serialize(&mut vec, &btx) {
|
||||||
|
panic!(e);
|
||||||
|
}
|
||||||
|
assert!(vec.len() > 5320);
|
||||||
|
assert!(vec.len() < 5340);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_tx_ser_deser() {
|
||||||
|
let mut rng = OsRng::new().unwrap();
|
||||||
|
let ref secp = new_secp();
|
||||||
|
|
||||||
|
let tx = tx2i1o(secp, &mut rng);
|
||||||
|
let mut btx = tx.blind(&secp).unwrap();
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
if let Some(e) = serialize(&mut vec, &btx) {
|
||||||
|
panic!(e);
|
||||||
|
}
|
||||||
|
// let mut dtx = Transaction::read(&mut BinReader { source: &mut &vec[..]
|
||||||
|
// }).unwrap();
|
||||||
|
let mut dtx: Transaction = deserialize(&mut &vec[..]).unwrap();
|
||||||
|
assert_eq!(dtx.fee, 1);
|
||||||
|
assert_eq!(dtx.inputs.len(), 2);
|
||||||
|
assert_eq!(dtx.outputs.len(), 1);
|
||||||
|
assert_eq!(btx.hash(), dtx.hash());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tx_double_ser_deser() {
|
||||||
|
// checks serializing doesn't mess up the tx and produces consistent results
|
||||||
|
let mut rng = OsRng::new().unwrap();
|
||||||
|
let ref secp = new_secp();
|
||||||
|
|
||||||
|
let tx = tx2i1o(secp, &mut rng);
|
||||||
|
let mut btx = tx.blind(&secp).unwrap();
|
||||||
|
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
assert!(serialize(&mut vec, &btx).is_none());
|
||||||
|
let mut dtx: Transaction = deserialize(&mut &vec[..]).unwrap();
|
||||||
|
|
||||||
|
let mut vec2 = Vec::new();
|
||||||
|
assert!(serialize(&mut vec2, &btx).is_none());
|
||||||
|
let mut dtx2: Transaction = deserialize(&mut &vec2[..]).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(btx.hash(), dtx.hash());
|
||||||
|
assert_eq!(dtx.hash(), dtx2.hash());
|
||||||
|
}
|
||||||
|
|
||||||
|
// utility producing a transaction with 2 inputs and a single outputs
|
||||||
|
fn tx2i1o<R: Rng>(secp: &Secp256k1, rng: &mut R) -> Transaction {
|
||||||
|
let outh = ZERO_HASH;
|
||||||
|
Transaction::new(vec![Input::OvertInput {
|
||||||
|
output: outh,
|
||||||
|
value: 10,
|
||||||
|
blindkey: SecretKey::new(secp, rng),
|
||||||
|
},
|
||||||
|
Input::OvertInput {
|
||||||
|
output: outh,
|
||||||
|
value: 11,
|
||||||
|
blindkey: SecretKey::new(secp, rng),
|
||||||
|
}],
|
||||||
|
vec![Output::OvertOutput {
|
||||||
|
value: 20,
|
||||||
|
blindkey: SecretKey::new(secp, rng),
|
||||||
|
}],
|
||||||
|
1)
|
||||||
|
}
|
||||||
|
}
|
38
core/src/genesis.rs
Normal file
38
core/src/genesis.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//! Definition of the genesis block. Placeholder for now.
|
||||||
|
|
||||||
|
use time;
|
||||||
|
|
||||||
|
use core;
|
||||||
|
|
||||||
|
use tiny_keccak::Keccak;
|
||||||
|
|
||||||
|
// Genesis block definition. It has no rewards, no inputs, no outputs, no
|
||||||
|
// fees and a height of zero.
|
||||||
|
pub fn genesis() -> core::Block {
|
||||||
|
let mut sha3 = Keccak::new_sha3_256();
|
||||||
|
let mut empty_h = [0; 32];
|
||||||
|
sha3.update(&[]);
|
||||||
|
sha3.finalize(&mut empty_h);
|
||||||
|
|
||||||
|
core::Block {
|
||||||
|
header: core::BlockHeader {
|
||||||
|
height: 0,
|
||||||
|
previous: core::ZERO_HASH,
|
||||||
|
timestamp: time::Tm {
|
||||||
|
tm_year: 1997,
|
||||||
|
tm_mon: 7,
|
||||||
|
tm_mday: 4,
|
||||||
|
..time::empty_tm()
|
||||||
|
},
|
||||||
|
td: 0,
|
||||||
|
utxo_merkle: core::Hash::from_vec(empty_h.to_vec()),
|
||||||
|
tx_merkle: core::Hash::from_vec(empty_h.to_vec()),
|
||||||
|
total_fees: 0,
|
||||||
|
nonce: 0,
|
||||||
|
pow: core::Proof::zero(), // TODO get actual PoW solution
|
||||||
|
},
|
||||||
|
inputs: vec![],
|
||||||
|
outputs: vec![],
|
||||||
|
proofs: vec![],
|
||||||
|
}
|
||||||
|
}
|
24
core/src/lib.rs
Normal file
24
core/src/lib.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
//! Implementation of the MimbleWimble paper.
|
||||||
|
//! https://download.wpsoftware.net/bitcoin/wizardry/mimblewimble.txt
|
||||||
|
|
||||||
|
#![deny(non_upper_case_globals)]
|
||||||
|
#![deny(non_camel_case_types)]
|
||||||
|
#![deny(non_snake_case)]
|
||||||
|
#![deny(unused_mut)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
extern crate byteorder;
|
||||||
|
extern crate crypto;
|
||||||
|
extern crate rand;
|
||||||
|
extern crate secp256k1zkp as secp;
|
||||||
|
extern crate time;
|
||||||
|
extern crate tiny_keccak;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub mod macros;
|
||||||
|
|
||||||
|
pub mod core;
|
||||||
|
pub mod genesis;
|
||||||
|
pub mod pow;
|
||||||
|
pub mod ser;
|
||||||
|
// mod chain;
|
59
core/src/macros.rs
Normal file
59
core/src/macros.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
//! Generic macros used here and there to simplify and make code more
|
||||||
|
//! readable.
|
||||||
|
|
||||||
|
/// Eliminates some of the verbosity in having iter and collect
|
||||||
|
/// around every map call.
|
||||||
|
macro_rules! map_vec {
|
||||||
|
($thing:expr, $mapfn:expr ) => {
|
||||||
|
$thing.iter()
|
||||||
|
.map($mapfn)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as map_vec when the map closure returns Results. Makes sure the
|
||||||
|
/// results are "pushed up" and wraps with a try.
|
||||||
|
macro_rules! try_map_vec {
|
||||||
|
($thing:expr, $mapfn:expr ) => {
|
||||||
|
try!($thing.iter()
|
||||||
|
.map($mapfn)
|
||||||
|
.collect::<Result<Vec<_>, _>>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Eliminates some of the verbosity in having iter and collect
|
||||||
|
/// around every fitler_map call.
|
||||||
|
macro_rules! filter_map_vec {
|
||||||
|
($thing:expr, $mapfn:expr ) => {
|
||||||
|
$thing.iter()
|
||||||
|
.filter_map($mapfn)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allows the conversion of an expression that doesn't return anything to one
|
||||||
|
/// that returns the provided identifier.
|
||||||
|
/// Example:
|
||||||
|
/// let foo = vec![1,2,3]
|
||||||
|
/// println!(tee!(foo, foo.append(vec![3,4,5]))
|
||||||
|
macro_rules! tee {
|
||||||
|
($thing:ident, $thing_expr:expr) => {
|
||||||
|
{
|
||||||
|
$thing_expr;
|
||||||
|
$thing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Simple equivalent of try! but for a Maybe<Error>. Motivated mostly by the
|
||||||
|
/// io package and our serialization as an alternative to silly Result<(),
|
||||||
|
/// Error>.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! try_m {
|
||||||
|
($trying:expr) => {
|
||||||
|
let tried = $trying;
|
||||||
|
if let Some(_) = tried {
|
||||||
|
return tried;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
444
core/src/pow/.cuckoo.rs.rustfmt
Normal file
444
core/src/pow/.cuckoo.rs.rustfmt
Normal file
|
@ -0,0 +1,444 @@
|
||||||
|
//! Implementation of Cuckoo Cycle designed by John Tromp. Ported to Rust from
|
||||||
|
//! the C and Java code at https://github.com/tromp/cuckoo. Note that only the
|
||||||
|
//! simple miner is included, mostly for testing purposes. John Tromp's Tomato
|
||||||
|
//! miner will be much faster in almost every environment.
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::cmp;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use crypto::digest::Digest;
|
||||||
|
use crypto::sha2::Sha256;
|
||||||
|
|
||||||
|
use pow::siphash::siphash24;
|
||||||
|
|
||||||
|
const PROOFSIZE: usize = 42;
|
||||||
|
const MAXPATHLEN: usize = 8192;
|
||||||
|
|
||||||
|
/// A Cuckoo proof representing the nonces for a cycle of the right size.
|
||||||
|
pub struct Proof([u32; PROOFSIZE]);
|
||||||
|
|
||||||
|
impl fmt::Debug for Proof {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
try!(write!(f, "Cuckoo("));
|
||||||
|
for (i, val) in self.0[..].iter().enumerate() {
|
||||||
|
try!(write!(f, "{:x}", val));
|
||||||
|
if i < PROOFSIZE - 1 {
|
||||||
|
write!(f, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl PartialEq for Proof {
|
||||||
|
fn eq(&self, other: &Proof) -> bool {
|
||||||
|
self.0[..] == other.0[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Eq for Proof {}
|
||||||
|
impl Clone for Proof {
|
||||||
|
#[inline]
|
||||||
|
fn clone(&self) -> Proof {
|
||||||
|
let mut cp = [0; PROOFSIZE];
|
||||||
|
for (i, n) in self.0.iter().enumerate() {
|
||||||
|
cp[i] = *n;
|
||||||
|
}
|
||||||
|
Proof(cp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Proof {
|
||||||
|
fn to_u64s(&self) -> Vec<u64> {
|
||||||
|
let mut nonces = Vec::with_capacity(PROOFSIZE);
|
||||||
|
for n in self.0.iter() {
|
||||||
|
nonces.push(*n as u64);
|
||||||
|
}
|
||||||
|
nonces
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An edge in the Cuckoo graph, simply references two u64 nodes.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
|
struct Edge {
|
||||||
|
u: u64,
|
||||||
|
v: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Cuckoo {
|
||||||
|
mask: u64,
|
||||||
|
size: u64,
|
||||||
|
v: [u64; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cuckoo {
|
||||||
|
/// Initializes a new Cuckoo Cycle setup, using the provided byte array to
|
||||||
|
/// generate a seed. In practice for PoW applications the byte array is a
|
||||||
|
/// serialized block header.
|
||||||
|
pub fn new(header: &[u8], sizeshift: u32) -> Cuckoo {
|
||||||
|
let size = 1 << sizeshift;
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
let mut hashed = [0; 32];
|
||||||
|
hasher.input(header);
|
||||||
|
hasher.result(&mut hashed);
|
||||||
|
|
||||||
|
let k0 = u8_to_u64(hashed, 0);
|
||||||
|
let k1 = u8_to_u64(hashed, 8);
|
||||||
|
let mut v = [0; 4];
|
||||||
|
v[0] = k0 ^ 0x736f6d6570736575;
|
||||||
|
v[1] = k1 ^ 0x646f72616e646f6d;
|
||||||
|
v[2] = k0 ^ 0x6c7967656e657261;
|
||||||
|
v[3] = k1 ^ 0x7465646279746573;
|
||||||
|
// println!("{:?} {:?} {:?} {:?}", v[0], v[1], v[2], v[3]);
|
||||||
|
Cuckoo {
|
||||||
|
v: v,
|
||||||
|
size: size,
|
||||||
|
mask: (1 << sizeshift) / 2 - 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a node in the cuckoo graph generated from our seed. A node is
|
||||||
|
/// simply materialized as a u64 from a nonce and an offset (generally 0 or
|
||||||
|
/// 1).
|
||||||
|
pub fn new_node(&self, nonce: u64, uorv: u64) -> u64 {
|
||||||
|
return ((siphash24(self.v, 2 * nonce + uorv) & self.mask) << 1) | uorv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new edge in the cuckoo graph generated by our seed from a
|
||||||
|
/// nonce. Generates two node coordinates from the nonce and links them
|
||||||
|
/// together.
|
||||||
|
pub fn new_edge(&self, nonce: u64) -> Edge {
|
||||||
|
Edge {
|
||||||
|
u: self.new_node(nonce, 0),
|
||||||
|
v: self.new_node(nonce, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assuming increasing nonces all smaller than easiness, verifies the
|
||||||
|
/// nonces form a cycle in a Cuckoo graph. Each nonce generates an edge, we
|
||||||
|
/// build the nodes on both side of that edge and count the connections.
|
||||||
|
pub fn verify(&self, proof: Proof, ease: u64) -> bool {
|
||||||
|
let easiness = ease * (self.size as u64) / 100;
|
||||||
|
let nonces = proof.to_u64s();
|
||||||
|
let mut us = [0; PROOFSIZE];
|
||||||
|
let mut vs = [0; PROOFSIZE];
|
||||||
|
for n in 0..PROOFSIZE {
|
||||||
|
if nonces[n] >= easiness || (n != 0 && nonces[n] <= nonces[n - 1]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
us[n] = self.new_node(nonces[n], 0);
|
||||||
|
vs[n] = self.new_node(nonces[n], 1);
|
||||||
|
}
|
||||||
|
let mut i = 0;
|
||||||
|
let mut count = PROOFSIZE;
|
||||||
|
loop {
|
||||||
|
let mut j = i;
|
||||||
|
for k in 0..PROOFSIZE {
|
||||||
|
// find unique other j with same vs[j]
|
||||||
|
if k != i && vs[k] == vs[i] {
|
||||||
|
if j != i {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
j = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if j == i {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i = j;
|
||||||
|
for k in 0..PROOFSIZE {
|
||||||
|
// find unique other i with same us[i]
|
||||||
|
if k != j && us[k] == us[j] {
|
||||||
|
if i != j {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i == j {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
count -= 2;
|
||||||
|
if i == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
PathError,
|
||||||
|
NoSolutionError,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Miner for the Cuckoo Cycle algorithm. While the verifier will work for
|
||||||
|
/// graph sizes up to a u64, the miner is limited to u32 to be more memory
|
||||||
|
/// compact (so shift <= 32). Non-optimized for now and and so mostly used for
|
||||||
|
/// tests, being impractical with sizes greater than 2^22.
|
||||||
|
pub struct Miner {
|
||||||
|
easiness: u64,
|
||||||
|
size: usize,
|
||||||
|
cuckoo: Cuckoo,
|
||||||
|
graph: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// What type of cycle we have found?
|
||||||
|
enum CycleSol {
|
||||||
|
/// A cycle of the right length is a valid proof.
|
||||||
|
ValidProof([u32; PROOFSIZE]),
|
||||||
|
/// A cycle of the wrong length is great, but not a proof.
|
||||||
|
InvalidCycle(usize),
|
||||||
|
/// No cycles have been found.
|
||||||
|
NoCycle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Miner {
|
||||||
|
pub fn new(header: &[u8], ease: u64, sizeshift: u32) -> Miner {
|
||||||
|
let cuckoo = Cuckoo::new(header, sizeshift);
|
||||||
|
let size = 1 << sizeshift;
|
||||||
|
let graph = vec![0; size + 1];
|
||||||
|
let easiness = ease * (size as u64) / 100;
|
||||||
|
Miner {
|
||||||
|
easiness: easiness,
|
||||||
|
size: size,
|
||||||
|
cuckoo: cuckoo,
|
||||||
|
graph: graph,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mine(&mut self) -> Result<Proof, Error> {
|
||||||
|
let mut us = [0; MAXPATHLEN];
|
||||||
|
let mut vs = [0; MAXPATHLEN];
|
||||||
|
// println!("{}", self.easiness);
|
||||||
|
let mut m = 0;
|
||||||
|
for nonce in 0..self.easiness {
|
||||||
|
m += 1;
|
||||||
|
// println!("- {}", nonce);
|
||||||
|
us[0] = self.cuckoo.new_node(nonce, 0) as u32;
|
||||||
|
vs[0] = self.cuckoo.new_node(nonce, 1) as u32;
|
||||||
|
let u = self.graph[us[0] as usize];
|
||||||
|
let v = self.graph[vs[0] as usize];
|
||||||
|
if us[0] == 0 {
|
||||||
|
continue; // ignore duplicate edges
|
||||||
|
}
|
||||||
|
// println!("{}, {}, {}, {}", us[0], vs[0], u, v);
|
||||||
|
// println!(" ^{}, {}", us[0], vs[0]);
|
||||||
|
// println!(" _{}, {}", u, v);
|
||||||
|
let nu = try!(if nonce == 481921 {
|
||||||
|
self.path_p(u, &mut us)
|
||||||
|
} else {
|
||||||
|
self.path(u, &mut us)
|
||||||
|
}) as usize;
|
||||||
|
let nv = try!(if nonce == 481921 {
|
||||||
|
self.path_p(v, &mut vs)
|
||||||
|
} else {
|
||||||
|
self.path(v, &mut vs)
|
||||||
|
}) as usize;
|
||||||
|
// println!(" &{}, {}", nu, nv);
|
||||||
|
|
||||||
|
let sol = self.find_sol(nu, &us, nv, &vs);
|
||||||
|
match sol {
|
||||||
|
CycleSol::ValidProof(res) => return Ok(Proof(res)),
|
||||||
|
CycleSol::InvalidCycle(_) => continue,
|
||||||
|
CycleSol::NoCycle => {
|
||||||
|
self.update_graph(nu, &us, nv, &vs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// println!("== {}", m);
|
||||||
|
Err(Error::NoSolutionError)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path(&self, mut u: u32, us: &mut [u32]) -> Result<u32, Error> {
|
||||||
|
let mut nu = 0;
|
||||||
|
while u != 0 {
|
||||||
|
nu += 1;
|
||||||
|
if nu >= MAXPATHLEN {
|
||||||
|
while nu != 0 && us[(nu - 1) as usize] != u {
|
||||||
|
nu -= 1;
|
||||||
|
}
|
||||||
|
return Err(Error::PathError);
|
||||||
|
}
|
||||||
|
us[nu as usize] = u;
|
||||||
|
u = self.graph[u as usize];
|
||||||
|
}
|
||||||
|
Ok(nu as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path_p(&self, mut u: u32, us: &mut [u32]) -> Result<u32, Error> {
|
||||||
|
let mut nu = 0;
|
||||||
|
while u != 0 {
|
||||||
|
// println!("{}", u);
|
||||||
|
nu += 1;
|
||||||
|
if nu >= MAXPATHLEN {
|
||||||
|
while nu != 0 && us[(nu - 1) as usize] != u {
|
||||||
|
nu -= 1;
|
||||||
|
}
|
||||||
|
return Err(Error::PathError);
|
||||||
|
}
|
||||||
|
us[nu as usize] = u;
|
||||||
|
u = self.graph[u as usize];
|
||||||
|
}
|
||||||
|
Ok(nu as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_graph(&mut self, mut nu: usize, us: &[u32], mut nv: usize, vs: &[u32]) {
|
||||||
|
if nu < nv {
|
||||||
|
while nu != 0 {
|
||||||
|
nu -= 1;
|
||||||
|
// self.graph[us[nu + 1] as usize] = us[nu];
|
||||||
|
self.set_graph(us[nu + 1] as usize, us[nu]);
|
||||||
|
}
|
||||||
|
// self.graph[us[0] as usize] = vs[0];
|
||||||
|
self.set_graph(us[0] as usize, vs[0]);
|
||||||
|
} else {
|
||||||
|
while nv != 0 {
|
||||||
|
nv -= 1;
|
||||||
|
// self.graph[vs[nv + 1] as usize] = vs[nv];
|
||||||
|
self.set_graph(vs[nv + 1] as usize, vs[nv]);
|
||||||
|
}
|
||||||
|
// self.graph[vs[0] as usize] = us[0];
|
||||||
|
self.set_graph(vs[0] as usize, us[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_graph(&mut self, idx: usize, val: u32) {
|
||||||
|
// println!("set {} = {}", idx, val);
|
||||||
|
self.graph[idx] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_sol(&self, mut nu: usize, us: &[u32], mut nv: usize, vs: &[u32]) -> CycleSol {
|
||||||
|
if us[nu] == vs[nv] {
|
||||||
|
let min = cmp::min(nu, nv);
|
||||||
|
nu -= min;
|
||||||
|
nv -= min;
|
||||||
|
while us[nu] != vs[nv] {
|
||||||
|
nu += 1;
|
||||||
|
nv += 1;
|
||||||
|
}
|
||||||
|
if nu + nv + 1 == PROOFSIZE {
|
||||||
|
self.solution(&us, nu as u32, &vs, nv as u32)
|
||||||
|
} else {
|
||||||
|
CycleSol::InvalidCycle(nu + nv + 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CycleSol::NoCycle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solution(&self, us: &[u32], mut nu: u32, vs: &[u32], mut nv: u32) -> CycleSol {
|
||||||
|
let mut cycle = HashSet::new();
|
||||||
|
cycle.insert(Edge {
|
||||||
|
u: us[0] as u64,
|
||||||
|
v: vs[0] as u64,
|
||||||
|
});
|
||||||
|
while nu != 0 {
|
||||||
|
// u's in even position; v's in odd
|
||||||
|
nu -= 1;
|
||||||
|
cycle.insert(Edge {
|
||||||
|
u: us[((nu + 1) & !1) as usize] as u64,
|
||||||
|
v: us[(nu | 1) as usize] as u64,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
while nv != 0 {
|
||||||
|
// u's in odd position; v's in even
|
||||||
|
nv -= 1;
|
||||||
|
cycle.insert(Edge {
|
||||||
|
u: vs[(nv | 1) as usize] as u64,
|
||||||
|
v: vs[((nv + 1) & !1) as usize] as u64,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let mut n = 0;
|
||||||
|
let mut sol = [0; PROOFSIZE];
|
||||||
|
for nonce in 0..self.easiness {
|
||||||
|
let edge = self.cuckoo.new_edge(nonce);
|
||||||
|
if cycle.contains(&edge) {
|
||||||
|
sol[n] = nonce as u32;
|
||||||
|
n += 1;
|
||||||
|
cycle.remove(&edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return if n == PROOFSIZE {
|
||||||
|
CycleSol::ValidProof(sol)
|
||||||
|
} else {
|
||||||
|
CycleSol::NoCycle
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Utility to transform a 8 bytes of a byte array into a u64.
|
||||||
|
fn u8_to_u64(p: [u8; 32], i: usize) -> u64 {
|
||||||
|
(p[i] as u64) | (p[i + 1] as u64) << 8 | (p[i + 2] as u64) << 16 | (p[i + 3] as u64) << 24 |
|
||||||
|
(p[i + 4] as u64) << 32 | (p[i + 5] as u64) << 40 |
|
||||||
|
(p[i + 6] as u64) << 48 | (p[i + 7] as u64) << 56
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
static V1: Proof = Proof([0xe13, 0x410c, 0x7974, 0x8317, 0xb016, 0xb992, 0xe3c8, 0x1038a,
|
||||||
|
0x116f0, 0x15ed2, 0x165a2, 0x17793, 0x17dd1, 0x1f885, 0x20932,
|
||||||
|
0x20936, 0x2171b, 0x28968, 0x2b184, 0x30b8e, 0x31d28, 0x35782,
|
||||||
|
0x381ea, 0x38321, 0x3b414, 0x3e14b, 0x43615, 0x49a51, 0x4a319,
|
||||||
|
0x58271, 0x5dbb9, 0x5dbcf, 0x62db4, 0x653d2, 0x655f6, 0x66382,
|
||||||
|
0x7057d, 0x765b0, 0x79c7c, 0x83167, 0x86e7b, 0x8a5f4]);
|
||||||
|
static V2: Proof = Proof([0x33b8, 0x3fd9, 0x8f2b, 0xba0d, 0x11e2d, 0x1d51d, 0x2786e, 0x29625,
|
||||||
|
0x2a862, 0x2a972, 0x2e6d7, 0x319df, 0x37ce7, 0x3f771, 0x4373b,
|
||||||
|
0x439b7, 0x48626, 0x49c7d, 0x4a6f1, 0x4a808, 0x4e518, 0x519e3,
|
||||||
|
0x526bb, 0x54988, 0x564e9, 0x58a6c, 0x5a4dd, 0x63fa2, 0x68ad1,
|
||||||
|
0x69e52, 0x6bf53, 0x70841, 0x76343, 0x763a4, 0x79681, 0x7d006,
|
||||||
|
0x7d633, 0x7eebe, 0x7fe7c, 0x811fa, 0x863c1, 0x8b149]);
|
||||||
|
static V3: Proof = Proof([0x24ae, 0x5180, 0x9f3d, 0xd379, 0x102c9, 0x15787, 0x16df4, 0x19509,
|
||||||
|
0x19a78, 0x235a0, 0x24210, 0x24410, 0x2567f, 0x282c3, 0x2d986,
|
||||||
|
0x2efde, 0x319d7, 0x334d7, 0x336dd, 0x34296, 0x35809, 0x3ad40,
|
||||||
|
0x46d81, 0x48c92, 0x4b374, 0x4c353, 0x4fe4c, 0x50e4f, 0x53202,
|
||||||
|
0x5d167, 0x6527c, 0x6a8b5, 0x6c70d, 0x76d90, 0x794f4, 0x7c411,
|
||||||
|
0x7c5d4, 0x7f59f, 0x7fead, 0x872d8, 0x875b4, 0x95c6b]);
|
||||||
|
|
||||||
|
/// Find a 42-cycle on Cuckoo20 at 75% easiness and verifiy against a few
|
||||||
|
/// known cycle proofs
|
||||||
|
/// generated by other implementations.
|
||||||
|
#[test]
|
||||||
|
fn mine20_vectors() {
|
||||||
|
let nonces1 = Miner::new(&[49], 75, 20).mine().unwrap();
|
||||||
|
assert_eq!(V1, nonces1);
|
||||||
|
|
||||||
|
let nonces2 = Miner::new(&[50], 70, 20).mine().unwrap();
|
||||||
|
assert_eq!(V2, nonces2);
|
||||||
|
|
||||||
|
let nonces3 = Miner::new(&[51], 70, 20).mine().unwrap();
|
||||||
|
assert_eq!(V3, nonces3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate20_vectors() {
|
||||||
|
assert!(Cuckoo::new(&[49], 20).verify(V1.clone(), 75));
|
||||||
|
assert!(Cuckoo::new(&[50], 20).verify(V2.clone(), 70));
|
||||||
|
assert!(Cuckoo::new(&[51], 20).verify(V3.clone(), 70));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_fail() {
|
||||||
|
assert!(!Cuckoo::new(&[49], 20).verify(Proof([0; 42]), 75));
|
||||||
|
assert!(!Cuckoo::new(&[50], 20).verify(V1.clone(), 75));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mine20_validate() {
|
||||||
|
// cuckoo20
|
||||||
|
for n in 1..5 {
|
||||||
|
let h = [n; 32];
|
||||||
|
let nonces = Miner::new(&h, 75, 20).mine().unwrap();
|
||||||
|
assert!(Cuckoo::new(&h, 20).verify(nonces, 75));
|
||||||
|
}
|
||||||
|
// cuckoo18
|
||||||
|
for n in 1..5 {
|
||||||
|
let h = [n; 32];
|
||||||
|
let nonces = Miner::new(&h, 75, 18).mine().unwrap();
|
||||||
|
assert!(Cuckoo::new(&h, 18).verify(nonces, 75));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
374
core/src/pow/cuckoo.rs
Normal file
374
core/src/pow/cuckoo.rs
Normal file
|
@ -0,0 +1,374 @@
|
||||||
|
//! Implementation of Cuckoo Cycle designed by John Tromp. Ported to Rust from
|
||||||
|
//! the C and Java code at https://github.com/tromp/cuckoo. Note that only the
|
||||||
|
//! simple miner is included, mostly for testing purposes. John Tromp's Tomato
|
||||||
|
//! miner will be much faster in almost every environment.
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::cmp;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use crypto::digest::Digest;
|
||||||
|
use crypto::sha2::Sha256;
|
||||||
|
|
||||||
|
use core::{Proof, PROOFSIZE};
|
||||||
|
use pow::siphash::siphash24;
|
||||||
|
|
||||||
|
const MAXPATHLEN: usize = 8192;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
PathError,
|
||||||
|
NoSolutionError,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An edge in the Cuckoo graph, simply references two u64 nodes.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
|
struct Edge {
|
||||||
|
u: u64,
|
||||||
|
v: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Cuckoo {
|
||||||
|
mask: u64,
|
||||||
|
size: u64,
|
||||||
|
v: [u64; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cuckoo {
|
||||||
|
/// Initializes a new Cuckoo Cycle setup, using the provided byte array to
|
||||||
|
/// generate a seed. In practice for PoW applications the byte array is a
|
||||||
|
/// serialized block header.
|
||||||
|
pub fn new(header: &[u8], sizeshift: u32) -> Cuckoo {
|
||||||
|
let size = 1 << sizeshift;
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
let mut hashed = [0; 32];
|
||||||
|
hasher.input(header);
|
||||||
|
hasher.result(&mut hashed);
|
||||||
|
|
||||||
|
let k0 = u8_to_u64(hashed, 0);
|
||||||
|
let k1 = u8_to_u64(hashed, 8);
|
||||||
|
let mut v = [0; 4];
|
||||||
|
v[0] = k0 ^ 0x736f6d6570736575;
|
||||||
|
v[1] = k1 ^ 0x646f72616e646f6d;
|
||||||
|
v[2] = k0 ^ 0x6c7967656e657261;
|
||||||
|
v[3] = k1 ^ 0x7465646279746573;
|
||||||
|
Cuckoo {
|
||||||
|
v: v,
|
||||||
|
size: size,
|
||||||
|
mask: (1 << sizeshift) / 2 - 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a node in the cuckoo graph generated from our seed. A node is
|
||||||
|
/// simply materialized as a u64 from a nonce and an offset (generally 0 or
|
||||||
|
/// 1).
|
||||||
|
pub fn new_node(&self, nonce: u64, uorv: u64) -> u64 {
|
||||||
|
return ((siphash24(self.v, 2 * nonce + uorv) & self.mask) << 1) | uorv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new edge in the cuckoo graph generated by our seed from a
|
||||||
|
/// nonce. Generates two node coordinates from the nonce and links them
|
||||||
|
/// together.
|
||||||
|
pub fn new_edge(&self, nonce: u64) -> Edge {
|
||||||
|
Edge {
|
||||||
|
u: self.new_node(nonce, 0),
|
||||||
|
v: self.new_node(nonce, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assuming increasing nonces all smaller than easiness, verifies the
|
||||||
|
/// nonces form a cycle in a Cuckoo graph. Each nonce generates an edge, we
|
||||||
|
/// build the nodes on both side of that edge and count the connections.
|
||||||
|
pub fn verify(&self, proof: Proof, ease: u64) -> bool {
|
||||||
|
let easiness = ease * (self.size as u64) / 100;
|
||||||
|
let nonces = proof.to_u64s();
|
||||||
|
let mut us = [0; PROOFSIZE];
|
||||||
|
let mut vs = [0; PROOFSIZE];
|
||||||
|
for n in 0..PROOFSIZE {
|
||||||
|
if nonces[n] >= easiness || (n != 0 && nonces[n] <= nonces[n - 1]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
us[n] = self.new_node(nonces[n], 0);
|
||||||
|
vs[n] = self.new_node(nonces[n], 1);
|
||||||
|
}
|
||||||
|
let mut i = 0;
|
||||||
|
let mut count = PROOFSIZE;
|
||||||
|
loop {
|
||||||
|
let mut j = i;
|
||||||
|
for k in 0..PROOFSIZE {
|
||||||
|
// find unique other j with same vs[j]
|
||||||
|
if k != i && vs[k] == vs[i] {
|
||||||
|
if j != i {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
j = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if j == i {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i = j;
|
||||||
|
for k in 0..PROOFSIZE {
|
||||||
|
// find unique other i with same us[i]
|
||||||
|
if k != j && us[k] == us[j] {
|
||||||
|
if i != j {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i == j {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
count -= 2;
|
||||||
|
if i == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Miner for the Cuckoo Cycle algorithm. While the verifier will work for
|
||||||
|
/// graph sizes up to a u64, the miner is limited to u32 to be more memory
|
||||||
|
/// compact (so shift <= 32). Non-optimized for now and and so mostly used for
|
||||||
|
/// tests, being impractical with sizes greater than 2^22.
|
||||||
|
pub struct Miner {
|
||||||
|
easiness: u64,
|
||||||
|
cuckoo: Cuckoo,
|
||||||
|
graph: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// What type of cycle we have found?
|
||||||
|
enum CycleSol {
|
||||||
|
/// A cycle of the right length is a valid proof.
|
||||||
|
ValidProof([u32; PROOFSIZE]),
|
||||||
|
/// A cycle of the wrong length is great, but not a proof.
|
||||||
|
InvalidCycle(usize),
|
||||||
|
/// No cycles have been found.
|
||||||
|
NoCycle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Miner {
|
||||||
|
pub fn new(header: &[u8], ease: u32, sizeshift: u32) -> Miner {
|
||||||
|
let cuckoo = Cuckoo::new(header, sizeshift);
|
||||||
|
let size = 1 << sizeshift;
|
||||||
|
let graph = vec![0; size + 1];
|
||||||
|
let easiness = (ease as u64) * (size as u64) / 100;
|
||||||
|
Miner {
|
||||||
|
easiness: easiness,
|
||||||
|
cuckoo: cuckoo,
|
||||||
|
graph: graph,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mine(&mut self) -> Result<Proof, Error> {
|
||||||
|
let mut us = [0; MAXPATHLEN];
|
||||||
|
let mut vs = [0; MAXPATHLEN];
|
||||||
|
for nonce in 0..self.easiness {
|
||||||
|
us[0] = self.cuckoo.new_node(nonce, 0) as u32;
|
||||||
|
vs[0] = self.cuckoo.new_node(nonce, 1) as u32;
|
||||||
|
let u = self.graph[us[0] as usize];
|
||||||
|
let v = self.graph[vs[0] as usize];
|
||||||
|
if us[0] == 0 {
|
||||||
|
continue; // ignore duplicate edges
|
||||||
|
}
|
||||||
|
let nu = try!(self.path(u, &mut us)) as usize;
|
||||||
|
let nv = try!(self.path(v, &mut vs)) as usize;
|
||||||
|
|
||||||
|
let sol = self.find_sol(nu, &us, nv, &vs);
|
||||||
|
match sol {
|
||||||
|
CycleSol::ValidProof(res) => return Ok(Proof(res)),
|
||||||
|
CycleSol::InvalidCycle(_) => continue,
|
||||||
|
CycleSol::NoCycle => {
|
||||||
|
self.update_graph(nu, &us, nv, &vs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Error::NoSolutionError)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path(&self, mut u: u32, us: &mut [u32]) -> Result<u32, Error> {
|
||||||
|
let mut nu = 0;
|
||||||
|
while u != 0 {
|
||||||
|
nu += 1;
|
||||||
|
if nu >= MAXPATHLEN {
|
||||||
|
while nu != 0 && us[(nu - 1) as usize] != u {
|
||||||
|
nu -= 1;
|
||||||
|
}
|
||||||
|
return Err(Error::PathError);
|
||||||
|
}
|
||||||
|
us[nu as usize] = u;
|
||||||
|
u = self.graph[u as usize];
|
||||||
|
}
|
||||||
|
Ok(nu as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_graph(&mut self, mut nu: usize, us: &[u32], mut nv: usize, vs: &[u32]) {
|
||||||
|
if nu < nv {
|
||||||
|
while nu != 0 {
|
||||||
|
nu -= 1;
|
||||||
|
self.graph[us[nu + 1] as usize] = us[nu];
|
||||||
|
}
|
||||||
|
self.graph[us[0] as usize] = vs[0];
|
||||||
|
} else {
|
||||||
|
while nv != 0 {
|
||||||
|
nv -= 1;
|
||||||
|
self.graph[vs[nv + 1] as usize] = vs[nv];
|
||||||
|
}
|
||||||
|
self.graph[vs[0] as usize] = us[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_sol(&self, mut nu: usize, us: &[u32], mut nv: usize, vs: &[u32]) -> CycleSol {
|
||||||
|
if us[nu] == vs[nv] {
|
||||||
|
let min = cmp::min(nu, nv);
|
||||||
|
nu -= min;
|
||||||
|
nv -= min;
|
||||||
|
while us[nu] != vs[nv] {
|
||||||
|
nu += 1;
|
||||||
|
nv += 1;
|
||||||
|
}
|
||||||
|
if nu + nv + 1 == PROOFSIZE {
|
||||||
|
self.solution(&us, nu as u32, &vs, nv as u32)
|
||||||
|
} else {
|
||||||
|
CycleSol::InvalidCycle(nu + nv + 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CycleSol::NoCycle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solution(&self, us: &[u32], mut nu: u32, vs: &[u32], mut nv: u32) -> CycleSol {
|
||||||
|
let mut cycle = HashSet::new();
|
||||||
|
cycle.insert(Edge {
|
||||||
|
u: us[0] as u64,
|
||||||
|
v: vs[0] as u64,
|
||||||
|
});
|
||||||
|
while nu != 0 {
|
||||||
|
// u's in even position; v's in odd
|
||||||
|
nu -= 1;
|
||||||
|
cycle.insert(Edge {
|
||||||
|
u: us[((nu + 1) & !1) as usize] as u64,
|
||||||
|
v: us[(nu | 1) as usize] as u64,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
while nv != 0 {
|
||||||
|
// u's in odd position; v's in even
|
||||||
|
nv -= 1;
|
||||||
|
cycle.insert(Edge {
|
||||||
|
u: vs[(nv | 1) as usize] as u64,
|
||||||
|
v: vs[((nv + 1) & !1) as usize] as u64,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let mut n = 0;
|
||||||
|
let mut sol = [0; PROOFSIZE];
|
||||||
|
for nonce in 0..self.easiness {
|
||||||
|
let edge = self.cuckoo.new_edge(nonce);
|
||||||
|
if cycle.contains(&edge) {
|
||||||
|
sol[n] = nonce as u32;
|
||||||
|
n += 1;
|
||||||
|
cycle.remove(&edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return if n == PROOFSIZE {
|
||||||
|
CycleSol::ValidProof(sol)
|
||||||
|
} else {
|
||||||
|
CycleSol::NoCycle
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Utility to transform a 8 bytes of a byte array into a u64.
|
||||||
|
fn u8_to_u64(p: [u8; 32], i: usize) -> u64 {
|
||||||
|
(p[i] as u64) | (p[i + 1] as u64) << 8 | (p[i + 2] as u64) << 16 | (p[i + 3] as u64) << 24 |
|
||||||
|
(p[i + 4] as u64) << 32 | (p[i + 5] as u64) << 40 |
|
||||||
|
(p[i + 6] as u64) << 48 | (p[i + 7] as u64) << 56
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use core::Proof;
|
||||||
|
|
||||||
|
static V1: Proof = Proof([0xe13, 0x410c, 0x7974, 0x8317, 0xb016, 0xb992, 0xe3c8, 0x1038a,
|
||||||
|
0x116f0, 0x15ed2, 0x165a2, 0x17793, 0x17dd1, 0x1f885, 0x20932,
|
||||||
|
0x20936, 0x2171b, 0x28968, 0x2b184, 0x30b8e, 0x31d28, 0x35782,
|
||||||
|
0x381ea, 0x38321, 0x3b414, 0x3e14b, 0x43615, 0x49a51, 0x4a319,
|
||||||
|
0x58271, 0x5dbb9, 0x5dbcf, 0x62db4, 0x653d2, 0x655f6, 0x66382,
|
||||||
|
0x7057d, 0x765b0, 0x79c7c, 0x83167, 0x86e7b, 0x8a5f4]);
|
||||||
|
static V2: Proof = Proof([0x33b8, 0x3fd9, 0x8f2b, 0xba0d, 0x11e2d, 0x1d51d, 0x2786e, 0x29625,
|
||||||
|
0x2a862, 0x2a972, 0x2e6d7, 0x319df, 0x37ce7, 0x3f771, 0x4373b,
|
||||||
|
0x439b7, 0x48626, 0x49c7d, 0x4a6f1, 0x4a808, 0x4e518, 0x519e3,
|
||||||
|
0x526bb, 0x54988, 0x564e9, 0x58a6c, 0x5a4dd, 0x63fa2, 0x68ad1,
|
||||||
|
0x69e52, 0x6bf53, 0x70841, 0x76343, 0x763a4, 0x79681, 0x7d006,
|
||||||
|
0x7d633, 0x7eebe, 0x7fe7c, 0x811fa, 0x863c1, 0x8b149]);
|
||||||
|
static V3: Proof = Proof([0x24ae, 0x5180, 0x9f3d, 0xd379, 0x102c9, 0x15787, 0x16df4, 0x19509,
|
||||||
|
0x19a78, 0x235a0, 0x24210, 0x24410, 0x2567f, 0x282c3, 0x2d986,
|
||||||
|
0x2efde, 0x319d7, 0x334d7, 0x336dd, 0x34296, 0x35809, 0x3ad40,
|
||||||
|
0x46d81, 0x48c92, 0x4b374, 0x4c353, 0x4fe4c, 0x50e4f, 0x53202,
|
||||||
|
0x5d167, 0x6527c, 0x6a8b5, 0x6c70d, 0x76d90, 0x794f4, 0x7c411,
|
||||||
|
0x7c5d4, 0x7f59f, 0x7fead, 0x872d8, 0x875b4, 0x95c6b]);
|
||||||
|
// cuckoo28 at 50% edges of letter 'u'
|
||||||
|
static V4: Proof = Proof([0x1abd16, 0x7bb47e, 0x860253, 0xfad0b2, 0x121aa4d, 0x150a10b,
|
||||||
|
0x20605cb, 0x20ae7e3, 0x235a9be, 0x2640f4a, 0x2724c36, 0x2a6d38c,
|
||||||
|
0x2c50b28, 0x30850f2, 0x309668a, 0x30c85bd, 0x345f42c, 0x3901676,
|
||||||
|
0x432838f, 0x472158a, 0x4d04e9d, 0x4d6a987, 0x4f577bf, 0x4fbc49c,
|
||||||
|
0x593978d, 0x5acd98f, 0x5e60917, 0x6310602, 0x6385e88, 0x64f149c,
|
||||||
|
0x66d472e, 0x68e4df9, 0x6b4a89c, 0x6bb751d, 0x6e09792, 0x6e57e1d,
|
||||||
|
0x6ecfcdd, 0x70abddc, 0x7291dfd, 0x788069e, 0x79a15b1, 0x7d1a1e9]);
|
||||||
|
|
||||||
|
/// Find a 42-cycle on Cuckoo20 at 75% easiness and verifiy against a few
|
||||||
|
/// known cycle proofs
|
||||||
|
/// generated by other implementations.
|
||||||
|
#[test]
|
||||||
|
fn mine20_vectors() {
|
||||||
|
let nonces1 = Miner::new(&[49], 75, 20).mine().unwrap();
|
||||||
|
assert_eq!(V1, nonces1);
|
||||||
|
|
||||||
|
let nonces2 = Miner::new(&[50], 70, 20).mine().unwrap();
|
||||||
|
assert_eq!(V2, nonces2);
|
||||||
|
|
||||||
|
let nonces3 = Miner::new(&[51], 70, 20).mine().unwrap();
|
||||||
|
assert_eq!(V3, nonces3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate20_vectors() {
|
||||||
|
assert!(Cuckoo::new(&[49], 20).verify(V1.clone(), 75));
|
||||||
|
assert!(Cuckoo::new(&[50], 20).verify(V2.clone(), 70));
|
||||||
|
assert!(Cuckoo::new(&[51], 20).verify(V3.clone(), 70));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate28_vectors() {
|
||||||
|
assert!(Cuckoo::new(&[117], 28).verify(V4.clone(), 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_fail() {
|
||||||
|
// edge checks
|
||||||
|
assert!(!Cuckoo::new(&[49], 20).verify(Proof([0; 42]), 75));
|
||||||
|
assert!(!Cuckoo::new(&[49], 20).verify(Proof([0xffff; 42]), 75));
|
||||||
|
// wrong data for proof
|
||||||
|
assert!(!Cuckoo::new(&[50], 20).verify(V1.clone(), 75));
|
||||||
|
assert!(!Cuckoo::new(&[117], 20).verify(V4.clone(), 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mine20_validate() {
|
||||||
|
// cuckoo20
|
||||||
|
for n in 1..5 {
|
||||||
|
let h = [n; 32];
|
||||||
|
let nonces = Miner::new(&h, 75, 20).mine().unwrap();
|
||||||
|
assert!(Cuckoo::new(&h, 20).verify(nonces, 75));
|
||||||
|
}
|
||||||
|
// cuckoo18
|
||||||
|
for n in 1..5 {
|
||||||
|
let h = [n; 32];
|
||||||
|
let nonces = Miner::new(&h, 75, 18).mine().unwrap();
|
||||||
|
assert!(Cuckoo::new(&h, 18).verify(nonces, 75));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
178
core/src/pow/mod.rs
Normal file
178
core/src/pow/mod.rs
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
//! The proof of work needs to strike a balance between fast header
|
||||||
|
//! verification to avoid DoS attacks and difficulty for block verifiers to
|
||||||
|
//! build new blocks. In addition, mining new blocks should also be as
|
||||||
|
//! difficult on high end custom-made hardware (ASICs) as on commodity hardware
|
||||||
|
//! or smartphones. For this reason we use Cuckoo Cycles (see the cuckoo
|
||||||
|
//! module for more information).
|
||||||
|
//!
|
||||||
|
//! Note that this miner implementation is here mostly for tests and
|
||||||
|
//! reference. It's not optimized for speed.
|
||||||
|
|
||||||
|
mod siphash;
|
||||||
|
mod cuckoo;
|
||||||
|
|
||||||
|
use time;
|
||||||
|
|
||||||
|
use core::{Block, BlockHeader, Hashed, Hash, Proof, PROOFSIZE};
|
||||||
|
use pow::cuckoo::{Cuckoo, Miner, Error};
|
||||||
|
|
||||||
|
use ser;
|
||||||
|
use ser::{Writeable, Writer, ser_vec};
|
||||||
|
|
||||||
|
/// Default Cuckoo Cycle size shift used is 28. We may decide to increase it.
|
||||||
|
/// when difficuty increases.
|
||||||
|
const SIZESHIFT: u32 = 28;
|
||||||
|
|
||||||
|
/// Default Cuckoo Cycle easiness, high enough to have good likeliness to find
|
||||||
|
/// a solution.
|
||||||
|
const EASINESS: u32 = 70;
|
||||||
|
|
||||||
|
/// Max target hash, lowest difficulty
|
||||||
|
pub const MAX_TARGET: [u32; PROOFSIZE] =
|
||||||
|
[0xfff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||||
|
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||||
|
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||||
|
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff];
|
||||||
|
|
||||||
|
/// Subset of a block header that goes into hashing for proof of work.
|
||||||
|
/// Basically the whole thing minus the PoW solution itself and the total
|
||||||
|
/// difficulty (yet unknown). We also add the count of every variable length
|
||||||
|
/// elements in a header to make lying on those much harder.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct PowHeader {
|
||||||
|
pub nonce: u64,
|
||||||
|
pub height: u64,
|
||||||
|
pub previous: Hash,
|
||||||
|
pub timestamp: time::Tm,
|
||||||
|
pub utxo_merkle: Hash,
|
||||||
|
pub tx_merkle: Hash,
|
||||||
|
pub total_fees: u64,
|
||||||
|
pub n_in: u64,
|
||||||
|
pub n_out: u64,
|
||||||
|
pub n_proofs: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The binary definition of a PoW header is material for consensus as that's
|
||||||
|
/// the data that gets hashed for PoW calculation. The nonce is written first
|
||||||
|
/// to make incrementing from the serialized form trivial.
|
||||||
|
impl Writeable for PowHeader {
|
||||||
|
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
|
||||||
|
try_m!(writer.write_u64(self.nonce));
|
||||||
|
try_m!(writer.write_u64(self.height));
|
||||||
|
try_m!(writer.write_fixed_bytes(&self.previous));
|
||||||
|
try_m!(writer.write_i64(self.timestamp.to_timespec().sec));
|
||||||
|
try_m!(writer.write_fixed_bytes(&self.utxo_merkle));
|
||||||
|
try_m!(writer.write_fixed_bytes(&self.tx_merkle));
|
||||||
|
try_m!(writer.write_u64(self.total_fees));
|
||||||
|
try_m!(writer.write_u64(self.n_in));
|
||||||
|
try_m!(writer.write_u64(self.n_out));
|
||||||
|
writer.write_u64(self.n_proofs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hashed for PowHeader {
|
||||||
|
fn bytes(&self) -> Vec<u8> {
|
||||||
|
// no serialization errors are applicable in this specific case
|
||||||
|
ser_vec(self).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PowHeader {
|
||||||
|
fn from_block(b: &Block) -> PowHeader {
|
||||||
|
let ref h = b.header;
|
||||||
|
PowHeader {
|
||||||
|
nonce: h.nonce,
|
||||||
|
height: h.height,
|
||||||
|
previous: h.previous,
|
||||||
|
timestamp: h.timestamp,
|
||||||
|
utxo_merkle: h.utxo_merkle,
|
||||||
|
tx_merkle: h.tx_merkle,
|
||||||
|
total_fees: h.total_fees,
|
||||||
|
n_in: b.inputs.len() as u64,
|
||||||
|
n_out: b.outputs.len() as u64,
|
||||||
|
n_proofs: b.proofs.len() as u64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validates the proof of work of a given header.
|
||||||
|
pub fn verify(b: &Block, target: Proof) -> bool {
|
||||||
|
verify_size(b, target, SIZESHIFT)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as default verify function but uses the much easier Cuckoo20 (mostly
|
||||||
|
/// for tests).
|
||||||
|
pub fn verify20(b: &Block, target: Proof) -> bool {
|
||||||
|
verify_size(b, target, 20)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify_size(b: &Block, target: Proof, sizeshift: u32) -> bool {
|
||||||
|
let hash = PowHeader::from_block(b).hash();
|
||||||
|
// make sure the hash is smaller than our target before going into more
|
||||||
|
// expensive validation
|
||||||
|
if target < b.header.pow {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Cuckoo::new(hash.to_slice(), sizeshift).verify(b.header.pow, EASINESS as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs a naive single-threaded proof of work computation over the provided
|
||||||
|
/// block, until the required difficulty target is reached. May take a
|
||||||
|
/// while for a low target...
|
||||||
|
pub fn pow(b: &Block, target: Proof) -> Result<(Proof, u64), Error> {
|
||||||
|
pow_size(b, target, SIZESHIFT)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as default pow function but uses the much easier Cuckoo20 (mostly for
|
||||||
|
/// tests).
|
||||||
|
pub fn pow20(b: &Block, target: Proof) -> Result<(Proof, u64), Error> {
|
||||||
|
pow_size(b, target, 20)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pow_size(b: &Block, target: Proof, sizeshift: u32) -> Result<(Proof, u64), Error> {
|
||||||
|
let mut pow_header = PowHeader::from_block(b);
|
||||||
|
let start_nonce = pow_header.nonce;
|
||||||
|
|
||||||
|
// try to find a cuckoo cycle on that header hash
|
||||||
|
loop {
|
||||||
|
// can be trivially optimized by avoiding re-serialization every time but this
|
||||||
|
// is not meant as a fast miner implementation
|
||||||
|
let pow_hash = pow_header.hash();
|
||||||
|
|
||||||
|
// if we found a cycle (not guaranteed) and the proof is lower that the target,
|
||||||
|
// we're all good
|
||||||
|
if let Ok(proof) = Miner::new(pow_hash.to_slice(), EASINESS, sizeshift).mine() {
|
||||||
|
if proof <= target {
|
||||||
|
return Ok((proof, pow_header.nonce));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise increment the nonce
|
||||||
|
pow_header.nonce += 1;
|
||||||
|
|
||||||
|
// and if we're back where we started, update the time (changes the hash as
|
||||||
|
// well)
|
||||||
|
if pow_header.nonce == start_nonce {
|
||||||
|
pow_header.timestamp = time::at_utc(time::Timespec { sec: 0, nsec: 0 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use core::{BlockHeader, Hash, Proof};
|
||||||
|
use std::time::Instant;
|
||||||
|
use genesis;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn genesis_pow() {
|
||||||
|
let mut b = genesis::genesis();
|
||||||
|
let (proof, nonce) = pow20(&b, Proof(MAX_TARGET)).unwrap();
|
||||||
|
assert!(nonce > 0);
|
||||||
|
assert!(proof < Proof(MAX_TARGET));
|
||||||
|
b.header.pow = proof;
|
||||||
|
b.header.nonce = nonce;
|
||||||
|
assert!(verify20(&b, Proof(MAX_TARGET)));
|
||||||
|
}
|
||||||
|
}
|
68
core/src/pow/siphash.rs
Normal file
68
core/src/pow/siphash.rs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
//! Simple implementation of the siphash 2-4 hashing function from
|
||||||
|
//! Jean-Philippe Aumasson and Daniel J. Bernstein.
|
||||||
|
|
||||||
|
/// Implements siphash 2-4 specialized for a 4 u64 array key and a u64 nonce
|
||||||
|
pub fn siphash24(v: [u64; 4], nonce: u64) -> u64 {
|
||||||
|
let mut v0 = v[0];
|
||||||
|
let mut v1 = v[1];
|
||||||
|
let mut v2 = v[2];
|
||||||
|
let mut v3 = v[3] ^ nonce;
|
||||||
|
|
||||||
|
// macro for left rotation
|
||||||
|
macro_rules! rotl {
|
||||||
|
($num:ident, $shift:expr) => {
|
||||||
|
$num = ($num << $shift) | ($num >> (64 - $shift));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// macro for a single siphash round
|
||||||
|
macro_rules! round {
|
||||||
|
() => {
|
||||||
|
v0 = v0.wrapping_add(v1);
|
||||||
|
v2 = v2.wrapping_add(v3);
|
||||||
|
rotl!(v1, 13);
|
||||||
|
rotl!(v3, 16);
|
||||||
|
v1 ^= v0;
|
||||||
|
v3 ^= v2;
|
||||||
|
rotl!(v0, 32);
|
||||||
|
v2 = v2.wrapping_add(v1);
|
||||||
|
v0 = v0.wrapping_add(v3);
|
||||||
|
rotl!(v1, 17);
|
||||||
|
rotl!(v3, 21);
|
||||||
|
v1 ^= v2;
|
||||||
|
v3 ^= v0;
|
||||||
|
rotl!(v2, 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2 rounds
|
||||||
|
round!();
|
||||||
|
round!();
|
||||||
|
|
||||||
|
v0 ^= nonce;
|
||||||
|
v2 ^= 0xff;
|
||||||
|
|
||||||
|
// and then 4 rounds, hence siphash 2-4
|
||||||
|
round!();
|
||||||
|
round!();
|
||||||
|
round!();
|
||||||
|
round!();
|
||||||
|
|
||||||
|
return v0 ^ v1 ^ v2 ^ v3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Some test vectors hoisted from the Java implementation (adjusted from
|
||||||
|
/// the
|
||||||
|
/// fact that the Java impl uses a long, aka a signed 64 bits number).
|
||||||
|
#[test]
|
||||||
|
fn hash_some() {
|
||||||
|
assert_eq!(siphash24([1, 2, 3, 4], 10), 928382149599306901);
|
||||||
|
assert_eq!(siphash24([1, 2, 3, 4], 111), 10524991083049122233);
|
||||||
|
assert_eq!(siphash24([9, 7, 6, 7], 12), 1305683875471634734);
|
||||||
|
assert_eq!(siphash24([9, 7, 6, 7], 10), 11589833042187638814);
|
||||||
|
}
|
||||||
|
}
|
158
core/src/ser.rs
Normal file
158
core/src/ser.rs
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
//! Serialization and deserialization layer specialized for binary encoding.
|
||||||
|
//! Ensures consistency and safety. Basically a minimal subset or
|
||||||
|
//! rustc_serialize customized for our need.
|
||||||
|
//!
|
||||||
|
//! To use it simply implement `Writeable` or `Readable` and then use the
|
||||||
|
//! `serialize` or `deserialize` functions on them as appropriate.
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
use std::io::{Write, Read};
|
||||||
|
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
|
||||||
|
|
||||||
|
/// Possible errors deriving from serializing or deserializing.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Wraps an io error produced when reading or writing
|
||||||
|
IOErr(io::Error),
|
||||||
|
/// When asked to read too much data
|
||||||
|
TooLargeReadErr(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Useful trait to implement on types that can be translated to byte slices
|
||||||
|
/// directly. Allows the use of `write_fixed_bytes` on them.
|
||||||
|
pub trait AsFixedBytes {
|
||||||
|
/// The slice representation of self
|
||||||
|
fn as_fixed_bytes(&self) -> &[u8];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementations defined how different numbers and binary structures are
|
||||||
|
/// written to an underlying stream or container (depending on implementation).
|
||||||
|
pub trait Writer {
|
||||||
|
/// Writes a u32 as bytes
|
||||||
|
fn write_u32(&mut self, n: u32) -> Option<Error>;
|
||||||
|
/// Writes a u64 as bytes
|
||||||
|
fn write_u64(&mut self, n: u64) -> Option<Error>;
|
||||||
|
/// Writes a i64 as bytes
|
||||||
|
fn write_i64(&mut self, n: i64) -> Option<Error>;
|
||||||
|
/// Writes a variable length `Vec`, the length of the `Vec` is encoded as a
|
||||||
|
/// prefix.
|
||||||
|
fn write_vec(&mut self, vec: &mut Vec<u8>) -> Option<Error>;
|
||||||
|
/// Writes a fixed number of bytes from something that can turn itself into
|
||||||
|
/// a `&[u8]`. The reader is expected to know the actual length on read.
|
||||||
|
fn write_fixed_bytes(&mut self, b32: &AsFixedBytes) -> Option<Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementations defined how different numbers and binary structures are
|
||||||
|
/// read from an underlying stream or container (depending on implementation).
|
||||||
|
pub trait Reader {
|
||||||
|
/// Read a u32 from the underlying Read
|
||||||
|
fn read_u32(&mut self) -> Result<u32, Error>;
|
||||||
|
/// Read a u64 from the underlying Read
|
||||||
|
fn read_u64(&mut self) -> Result<u64, Error>;
|
||||||
|
/// Read a i32 from the underlying Read
|
||||||
|
fn read_i64(&mut self) -> Result<i64, Error>;
|
||||||
|
/// first before the data bytes.
|
||||||
|
fn read_vec(&mut self) -> Result<Vec<u8>, Error>;
|
||||||
|
/// Read a fixed number of bytes from the underlying reader.
|
||||||
|
fn read_fixed_bytes(&mut self, length: usize) -> Result<Vec<u8>, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait that every type that can be serialized as binary must implement.
|
||||||
|
/// Writes directly to a Writer, a utility type thinly wrapping an
|
||||||
|
/// underlying Write implementation.
|
||||||
|
pub trait Writeable {
|
||||||
|
/// Write the data held by this Writeable to the provided writer
|
||||||
|
fn write(&self, writer: &mut Writer) -> Option<Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait that every type that can be deserialized from binary must implement.
|
||||||
|
/// Reads directly to a Reader, a utility type thinly wrapping an
|
||||||
|
/// underlying Read implementation.
|
||||||
|
pub trait Readable<T> {
|
||||||
|
/// Reads the data necessary to this Readable from the provided reader
|
||||||
|
fn read(reader: &mut Reader) -> Result<T, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserializes a Readeable from any std::io::Read implementation.
|
||||||
|
pub fn deserialize<T: Readable<T>>(mut source: &mut Read) -> Result<T, Error> {
|
||||||
|
let mut reader = BinReader { source: source };
|
||||||
|
T::read(&mut reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serializes a Writeable into any std::io::Write implementation.
|
||||||
|
pub fn serialize(mut sink: &mut Write, thing: &Writeable) -> Option<Error> {
|
||||||
|
let mut writer = BinWriter { sink: sink };
|
||||||
|
thing.write(&mut writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility function to serialize a writeable directly in memory using a
|
||||||
|
/// Vec<u8>.
|
||||||
|
pub fn ser_vec(thing: &Writeable) -> Result<Vec<u8>, Error> {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
if let Some(err) = serialize(&mut vec, thing) {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BinReader<'a> {
|
||||||
|
source: &'a mut Read,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility wrapper for an underlying byte Reader. Defines higher level methods
|
||||||
|
/// to read numbers, byte vectors, hashes, etc.
|
||||||
|
impl<'a> Reader for BinReader<'a> {
|
||||||
|
fn read_u32(&mut self) -> Result<u32, Error> {
|
||||||
|
self.source.read_u32::<BigEndian>().map_err(Error::IOErr)
|
||||||
|
}
|
||||||
|
fn read_u64(&mut self) -> Result<u64, Error> {
|
||||||
|
self.source.read_u64::<BigEndian>().map_err(Error::IOErr)
|
||||||
|
}
|
||||||
|
fn read_i64(&mut self) -> Result<i64, Error> {
|
||||||
|
self.source.read_i64::<BigEndian>().map_err(Error::IOErr)
|
||||||
|
}
|
||||||
|
/// Read a variable size vector from the underlying Read. Expects a usize
|
||||||
|
fn read_vec(&mut self) -> Result<Vec<u8>, Error> {
|
||||||
|
let len = try!(self.read_u64());
|
||||||
|
self.read_fixed_bytes(len as usize)
|
||||||
|
}
|
||||||
|
fn read_fixed_bytes(&mut self, length: usize) -> Result<Vec<u8>, Error> {
|
||||||
|
// not reading more than 100k in a single read
|
||||||
|
if length > 100000 {
|
||||||
|
return Err(Error::TooLargeReadErr(format!("fixed bytes length too large: {}", length)));
|
||||||
|
}
|
||||||
|
let mut buf = vec![0; length];
|
||||||
|
self.source.read_exact(&mut buf).map(move |_| buf).map_err(Error::IOErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility wrapper for an underlying byte Writer. Defines higher level methods
|
||||||
|
/// to write numbers, byte vectors, hashes, etc.
|
||||||
|
struct BinWriter<'a> {
|
||||||
|
sink: &'a mut Write,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Writer for BinWriter<'a> {
|
||||||
|
fn write_u32(&mut self, n: u32) -> Option<Error> {
|
||||||
|
self.sink.write_u32::<BigEndian>(n).err().map(Error::IOErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_u64(&mut self, n: u64) -> Option<Error> {
|
||||||
|
self.sink.write_u64::<BigEndian>(n).err().map(Error::IOErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_i64(&mut self, n: i64) -> Option<Error> {
|
||||||
|
self.sink.write_i64::<BigEndian>(n).err().map(Error::IOErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn write_vec(&mut self, vec: &mut Vec<u8>) -> Option<Error> {
|
||||||
|
try_m!(self.write_u64(vec.len() as u64));
|
||||||
|
self.sink.write_all(vec).err().map(Error::IOErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_fixed_bytes(&mut self, b32: &AsFixedBytes) -> Option<Error> {
|
||||||
|
let bs = b32.as_fixed_bytes();
|
||||||
|
self.sink.write_all(bs).err().map(Error::IOErr)
|
||||||
|
}
|
||||||
|
}
|
8
grin/Cargo.toml
Normal file
8
grin/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "grin"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Ignotus Peverell <igno.peverell@protonmail.com>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
grin_core = { path = "../core" }
|
||||||
|
grin_store = { path = "../store" }
|
3
grin/rustfmt.toml
Normal file
3
grin/rustfmt.toml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
hard_tabs = true
|
||||||
|
wrap_comments = true
|
||||||
|
write_mode = "Overwrite"
|
23
grin/src/main.rs
Normal file
23
grin/src/main.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//! Main crate putting together all the other crates that compose Grin into a
|
||||||
|
//! binary.
|
||||||
|
|
||||||
|
#![deny(non_upper_case_globals)]
|
||||||
|
#![deny(non_camel_case_types)]
|
||||||
|
#![deny(non_snake_case)]
|
||||||
|
#![deny(unused_mut)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
extern crate grin_core as core;
|
||||||
|
extern crate grin_store as store;
|
||||||
|
|
||||||
|
use store::Store;
|
||||||
|
use core::genesis::genesis;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let gen = genesis();
|
||||||
|
let db = Store::open("./store").unwrap();
|
||||||
|
let mut key = "block:".to_string().into_bytes();
|
||||||
|
let mut hash_vec = gen.hash().to_vec();
|
||||||
|
key.append(&mut hash_vec);
|
||||||
|
db.put_ser(&key[..], &gen);
|
||||||
|
}
|
2
secp256k1zkp/.gitignore
vendored
Normal file
2
secp256k1zkp/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
target/
|
||||||
|
Cargo.lock
|
23
secp256k1zkp/.travis.yml
Normal file
23
secp256k1zkp/.travis.yml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
language: rust
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- rust: stable
|
||||||
|
- rust: beta
|
||||||
|
- rust: nightly
|
||||||
|
|
||||||
|
install:
|
||||||
|
- |
|
||||||
|
pip install 'travis-cargo<0.2' --user &&
|
||||||
|
export PATH=$HOME/.local/bin:$PATH
|
||||||
|
|
||||||
|
script:
|
||||||
|
- |
|
||||||
|
travis-cargo build &&
|
||||||
|
travis-cargo build -- --release &&
|
||||||
|
travis-cargo test &&
|
||||||
|
travis-cargo test -- --release &&
|
||||||
|
travis-cargo bench &&
|
||||||
|
travis-cargo --only stable doc
|
||||||
|
|
34
secp256k1zkp/Cargo.toml
Normal file
34
secp256k1zkp/Cargo.toml
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
[package]
|
||||||
|
|
||||||
|
name = "secp256k1zkp"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = [ "Dawid Ciężarkiewicz <dpc@ucore.info>",
|
||||||
|
"Andrew Poelstra <apoelstra@wpsoftware.net>",
|
||||||
|
"Ignotus Peverell <igno.peverell@protonmail.com>" ]
|
||||||
|
license = "CC0-1.0"
|
||||||
|
description = "Rust bindings for Pieter Wuille's `libsecp256k1` library, augmented with pedersen commitments. Implements ECDSA for the SECG elliptic curve group secp256k1 and related utilities."
|
||||||
|
keywords = [ "crypto", "ECDSA", "secp256k1", "libsecp256k1", "bitcoin" ]
|
||||||
|
readme = "README.md"
|
||||||
|
|
||||||
|
build = "build.rs"
|
||||||
|
[build-dependencies]
|
||||||
|
gcc = "0.3"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "secp256k1zkp"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
unstable = []
|
||||||
|
default = []
|
||||||
|
dev = ["clippy"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
arrayvec = "0.3"
|
||||||
|
clippy = {version = "0.0", optional = true}
|
||||||
|
rand = "0.3"
|
||||||
|
libc = "0.1"
|
||||||
|
rustc-serialize = "0.3"
|
||||||
|
serde = "0.6"
|
||||||
|
serde_json = "0.6"
|
||||||
|
|
122
secp256k1zkp/LICENSE
Normal file
122
secp256k1zkp/LICENSE
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
Creative Commons Legal Code
|
||||||
|
|
||||||
|
CC0 1.0 Universal
|
||||||
|
|
||||||
|
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||||
|
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||||
|
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||||
|
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||||
|
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||||
|
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||||
|
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||||
|
HEREUNDER.
|
||||||
|
|
||||||
|
Statement of Purpose
|
||||||
|
|
||||||
|
The laws of most jurisdictions throughout the world automatically confer
|
||||||
|
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||||
|
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||||
|
authorship and/or a database (each, a "Work").
|
||||||
|
|
||||||
|
Certain owners wish to permanently relinquish those rights to a Work for
|
||||||
|
the purpose of contributing to a commons of creative, cultural and
|
||||||
|
scientific works ("Commons") that the public can reliably and without fear
|
||||||
|
of later claims of infringement build upon, modify, incorporate in other
|
||||||
|
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||||
|
and for any purposes, including without limitation commercial purposes.
|
||||||
|
These owners may contribute to the Commons to promote the ideal of a free
|
||||||
|
culture and the further production of creative, cultural and scientific
|
||||||
|
works, or to gain reputation or greater distribution for their Work in
|
||||||
|
part through the use and efforts of others.
|
||||||
|
|
||||||
|
For these and/or other purposes and motivations, and without any
|
||||||
|
expectation of additional consideration or compensation, the person
|
||||||
|
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||||
|
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||||
|
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||||
|
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||||
|
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||||
|
|
||||||
|
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||||
|
protected by copyright and related or neighboring rights ("Copyright and
|
||||||
|
Related Rights"). Copyright and Related Rights include, but are not
|
||||||
|
limited to, the following:
|
||||||
|
|
||||||
|
i. the right to reproduce, adapt, distribute, perform, display,
|
||||||
|
communicate, and translate a Work;
|
||||||
|
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||||
|
iii. publicity and privacy rights pertaining to a person's image or
|
||||||
|
likeness depicted in a Work;
|
||||||
|
iv. rights protecting against unfair competition in regards to a Work,
|
||||||
|
subject to the limitations in paragraph 4(a), below;
|
||||||
|
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||||
|
in a Work;
|
||||||
|
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||||
|
European Parliament and of the Council of 11 March 1996 on the legal
|
||||||
|
protection of databases, and under any national implementation
|
||||||
|
thereof, including any amended or successor version of such
|
||||||
|
directive); and
|
||||||
|
vii. other similar, equivalent or corresponding rights throughout the
|
||||||
|
world based on applicable law or treaty, and any national
|
||||||
|
implementations thereof.
|
||||||
|
|
||||||
|
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||||
|
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||||
|
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||||
|
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||||
|
of action, whether now known or unknown (including existing as well as
|
||||||
|
future claims and causes of action), in the Work (i) in all territories
|
||||||
|
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||||
|
treaty (including future time extensions), (iii) in any current or future
|
||||||
|
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||||
|
including without limitation commercial, advertising or promotional
|
||||||
|
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||||
|
member of the public at large and to the detriment of Affirmer's heirs and
|
||||||
|
successors, fully intending that such Waiver shall not be subject to
|
||||||
|
revocation, rescission, cancellation, termination, or any other legal or
|
||||||
|
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||||
|
as contemplated by Affirmer's express Statement of Purpose.
|
||||||
|
|
||||||
|
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||||
|
be judged legally invalid or ineffective under applicable law, then the
|
||||||
|
Waiver shall be preserved to the maximum extent permitted taking into
|
||||||
|
account Affirmer's express Statement of Purpose. In addition, to the
|
||||||
|
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||||
|
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||||
|
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||||
|
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||||
|
maximum duration provided by applicable law or treaty (including future
|
||||||
|
time extensions), (iii) in any current or future medium and for any number
|
||||||
|
of copies, and (iv) for any purpose whatsoever, including without
|
||||||
|
limitation commercial, advertising or promotional purposes (the
|
||||||
|
"License"). The License shall be deemed effective as of the date CC0 was
|
||||||
|
applied by Affirmer to the Work. Should any part of the License for any
|
||||||
|
reason be judged legally invalid or ineffective under applicable law, such
|
||||||
|
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||||
|
of the License, and in such case Affirmer hereby affirms that he or she
|
||||||
|
will not (i) exercise any of his or her remaining Copyright and Related
|
||||||
|
Rights in the Work or (ii) assert any associated claims and causes of
|
||||||
|
action with respect to the Work, in either case contrary to Affirmer's
|
||||||
|
express Statement of Purpose.
|
||||||
|
|
||||||
|
4. Limitations and Disclaimers.
|
||||||
|
|
||||||
|
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||||
|
surrendered, licensed or otherwise affected by this document.
|
||||||
|
b. Affirmer offers the Work as-is and makes no representations or
|
||||||
|
warranties of any kind concerning the Work, express, implied,
|
||||||
|
statutory or otherwise, including without limitation warranties of
|
||||||
|
title, merchantability, fitness for a particular purpose, non
|
||||||
|
infringement, or the absence of latent or other defects, accuracy, or
|
||||||
|
the present or absence of errors, whether or not discoverable, all to
|
||||||
|
the greatest extent permissible under applicable law.
|
||||||
|
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||||
|
that may apply to the Work or any use thereof, including without
|
||||||
|
limitation any person's Copyright and Related Rights in the Work.
|
||||||
|
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||||
|
consents, permissions or other rights required for any use of the
|
||||||
|
Work.
|
||||||
|
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||||
|
party to this document and has no duty or obligation with respect to
|
||||||
|
this CC0 or use of the Work.
|
||||||
|
|
6
secp256k1zkp/Makefile
Normal file
6
secp256k1zkp/Makefile
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
test:
|
||||||
|
cargo test
|
||||||
|
|
||||||
|
build:
|
||||||
|
cargo build
|
||||||
|
|
15
secp256k1zkp/README.md
Normal file
15
secp256k1zkp/README.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[![Build Status](https://travis-ci.org/apoelstra/rust-secp256k1.png?branch=master)](https://travis-ci.org/apoelstra/rust-secp256k1)
|
||||||
|
|
||||||
|
### rust-secp256k1
|
||||||
|
|
||||||
|
`rust-secp256k1` is a wrapper around ![libsecp256k1](https://github.com/bitcoin/secp256k1),
|
||||||
|
a C library by Peter Wuille for producing ECDSA signatures using the SECG curve
|
||||||
|
`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
|
||||||
|
|
||||||
|
[Full documentation](https://www.wpsoftware.net/rustdoc/secp256k1/)
|
||||||
|
|
50
secp256k1zkp/build.rs
Normal file
50
secp256k1zkp/build.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
// 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 <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
//! # 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 gcc;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut base_config = gcc::Config::new();
|
||||||
|
base_config.include("depend/secp256k1-zkp/")
|
||||||
|
.include("depend/secp256k1-zkp/include")
|
||||||
|
.include("depend/secp256k1-zkp/src")
|
||||||
|
.flag("-g")
|
||||||
|
// 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"))
|
||||||
|
// TODO these should use 64-bit variants on 64-bit systems
|
||||||
|
.define("USE_FIELD_10X26", Some("1"))
|
||||||
|
.define("USE_SCALAR_8X32", Some("1"))
|
||||||
|
.define("USE_ENDOMORPHISM", Some("1"))
|
||||||
|
// These all are OK.
|
||||||
|
.define("ENABLE_MODULE_ECDH", Some("1"))
|
||||||
|
.define("ENABLE_MODULE_SCHNORR", Some("1"))
|
||||||
|
.define("ENABLE_MODULE_RECOVERY", Some("1"))
|
||||||
|
.define("ENABLE_MODULE_RANGEPROOF", Some("1"));
|
||||||
|
|
||||||
|
// secp256k1
|
||||||
|
base_config.file("depend/secp256k1-zkp/contrib/lax_der_parsing.c")
|
||||||
|
.file("depend/secp256k1-zkp/src/secp256k1.c")
|
||||||
|
.compile("libsecp256k1-zkp.a");
|
||||||
|
}
|
48
secp256k1zkp/depend/secp256k1-zkp/.gitignore
vendored
Normal file
48
secp256k1zkp/depend/secp256k1-zkp/.gitignore
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
bench_inv
|
||||||
|
bench_ecdh
|
||||||
|
bench_sign
|
||||||
|
bench_verify
|
||||||
|
bench_schnorr_verify
|
||||||
|
bench_recover
|
||||||
|
bench_internal
|
||||||
|
tests
|
||||||
|
gen_context
|
||||||
|
*.exe
|
||||||
|
*.so
|
||||||
|
*.a
|
||||||
|
!.gitignore
|
||||||
|
|
||||||
|
Makefile
|
||||||
|
configure
|
||||||
|
.libs/
|
||||||
|
Makefile.in
|
||||||
|
aclocal.m4
|
||||||
|
autom4te.cache/
|
||||||
|
config.log
|
||||||
|
config.status
|
||||||
|
*.tar.gz
|
||||||
|
*.la
|
||||||
|
libtool
|
||||||
|
.deps/
|
||||||
|
.dirstamp
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
*~
|
||||||
|
src/libsecp256k1-config.h
|
||||||
|
src/libsecp256k1-config.h.in
|
||||||
|
src/ecmult_static_context.h
|
||||||
|
build-aux/config.guess
|
||||||
|
build-aux/config.sub
|
||||||
|
build-aux/depcomp
|
||||||
|
build-aux/install-sh
|
||||||
|
build-aux/ltmain.sh
|
||||||
|
build-aux/m4/libtool.m4
|
||||||
|
build-aux/m4/lt~obsolete.m4
|
||||||
|
build-aux/m4/ltoptions.m4
|
||||||
|
build-aux/m4/ltsugar.m4
|
||||||
|
build-aux/m4/ltversion.m4
|
||||||
|
build-aux/missing
|
||||||
|
build-aux/compile
|
||||||
|
build-aux/test-driver
|
||||||
|
src/stamp-h1
|
||||||
|
libsecp256k1.pc
|
70
secp256k1zkp/depend/secp256k1-zkp/.travis.yml
Normal file
70
secp256k1zkp/depend/secp256k1-zkp/.travis.yml
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
language: c
|
||||||
|
sudo: false
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages: libgmp-dev
|
||||||
|
compiler:
|
||||||
|
- clang
|
||||||
|
- gcc
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- src/java/guava/
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no EXPERIMENTAL=no
|
||||||
|
- GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar
|
||||||
|
matrix:
|
||||||
|
- SCALAR=32bit RECOVERY=yes
|
||||||
|
- SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes
|
||||||
|
- SCALAR=64bit
|
||||||
|
- FIELD=64bit RECOVERY=yes
|
||||||
|
- FIELD=64bit ENDOMORPHISM=yes
|
||||||
|
- FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes
|
||||||
|
- FIELD=64bit ASM=x86_64
|
||||||
|
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
|
||||||
|
- FIELD=32bit SCHNORR=yes EXPERIMENTAL=yes
|
||||||
|
- FIELD=32bit ENDOMORPHISM=yes
|
||||||
|
- BIGNUM=no
|
||||||
|
- BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes EXPERIMENTAL=yes
|
||||||
|
- BIGNUM=no STATICPRECOMPUTATION=no
|
||||||
|
- BUILD=distcheck
|
||||||
|
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
|
||||||
|
- EXTRAFLAGS=CFLAGS=-O0
|
||||||
|
- BUILD=check-java ECDH=yes SCHNORR=yes EXPERIMENTAL=yes
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
include:
|
||||||
|
- compiler: clang
|
||||||
|
env: HOST=i686-linux-gnu ENDOMORPHISM=yes
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- gcc-multilib
|
||||||
|
- libgmp-dev:i386
|
||||||
|
- compiler: clang
|
||||||
|
env: HOST=i686-linux-gnu
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- gcc-multilib
|
||||||
|
- compiler: gcc
|
||||||
|
env: HOST=i686-linux-gnu ENDOMORPHISM=yes
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- gcc-multilib
|
||||||
|
- compiler: gcc
|
||||||
|
env: HOST=i686-linux-gnu
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- gcc-multilib
|
||||||
|
- libgmp-dev:i386
|
||||||
|
before_install: mkdir -p `dirname $GUAVA_JAR`
|
||||||
|
install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi
|
||||||
|
before_script: ./autogen.sh
|
||||||
|
script:
|
||||||
|
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
|
||||||
|
- if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
|
||||||
|
- ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
|
||||||
|
os: linux
|
19
secp256k1zkp/depend/secp256k1-zkp/COPYING
Normal file
19
secp256k1zkp/depend/secp256k1-zkp/COPYING
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright (c) 2013 Pieter Wuille
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
167
secp256k1zkp/depend/secp256k1-zkp/Makefile.am
Normal file
167
secp256k1zkp/depend/secp256k1-zkp/Makefile.am
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
ACLOCAL_AMFLAGS = -I build-aux/m4
|
||||||
|
|
||||||
|
lib_LTLIBRARIES = libsecp256k1.la
|
||||||
|
if USE_JNI
|
||||||
|
JNI_LIB = libsecp256k1_jni.la
|
||||||
|
noinst_LTLIBRARIES = $(JNI_LIB)
|
||||||
|
else
|
||||||
|
JNI_LIB =
|
||||||
|
endif
|
||||||
|
include_HEADERS = include/secp256k1.h
|
||||||
|
noinst_HEADERS =
|
||||||
|
noinst_HEADERS += src/scalar.h
|
||||||
|
noinst_HEADERS += src/scalar_4x64.h
|
||||||
|
noinst_HEADERS += src/scalar_8x32.h
|
||||||
|
noinst_HEADERS += src/scalar_impl.h
|
||||||
|
noinst_HEADERS += src/scalar_4x64_impl.h
|
||||||
|
noinst_HEADERS += src/scalar_8x32_impl.h
|
||||||
|
noinst_HEADERS += src/group.h
|
||||||
|
noinst_HEADERS += src/group_impl.h
|
||||||
|
noinst_HEADERS += src/num_gmp.h
|
||||||
|
noinst_HEADERS += src/num_gmp_impl.h
|
||||||
|
noinst_HEADERS += src/ecdsa.h
|
||||||
|
noinst_HEADERS += src/ecdsa_impl.h
|
||||||
|
noinst_HEADERS += src/eckey.h
|
||||||
|
noinst_HEADERS += src/eckey_impl.h
|
||||||
|
noinst_HEADERS += src/ecmult.h
|
||||||
|
noinst_HEADERS += src/ecmult_impl.h
|
||||||
|
noinst_HEADERS += src/ecmult_const.h
|
||||||
|
noinst_HEADERS += src/ecmult_const_impl.h
|
||||||
|
noinst_HEADERS += src/ecmult_gen.h
|
||||||
|
noinst_HEADERS += src/ecmult_gen_impl.h
|
||||||
|
noinst_HEADERS += src/num.h
|
||||||
|
noinst_HEADERS += src/num_impl.h
|
||||||
|
noinst_HEADERS += src/field_10x26.h
|
||||||
|
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/java/org_bitcoin_NativeSecp256k1.h
|
||||||
|
noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h
|
||||||
|
noinst_HEADERS += src/util.h
|
||||||
|
noinst_HEADERS += src/testrand.h
|
||||||
|
noinst_HEADERS += src/testrand_impl.h
|
||||||
|
noinst_HEADERS += src/hash.h
|
||||||
|
noinst_HEADERS += src/hash_impl.h
|
||||||
|
noinst_HEADERS += src/field.h
|
||||||
|
noinst_HEADERS += src/field_impl.h
|
||||||
|
noinst_HEADERS += src/bench.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
|
||||||
|
|
||||||
|
if USE_EXTERNAL_ASM
|
||||||
|
COMMON_LIB = libsecp256k1_common.la
|
||||||
|
noinst_LTLIBRARIES = $(COMMON_LIB)
|
||||||
|
else
|
||||||
|
COMMON_LIB =
|
||||||
|
endif
|
||||||
|
|
||||||
|
pkgconfigdir = $(libdir)/pkgconfig
|
||||||
|
pkgconfig_DATA = libsecp256k1.pc
|
||||||
|
|
||||||
|
if USE_EXTERNAL_ASM
|
||||||
|
if USE_ASM_ARM
|
||||||
|
libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
libsecp256k1_la_SOURCES = src/secp256k1.c
|
||||||
|
libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
|
||||||
|
libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB)
|
||||||
|
|
||||||
|
libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c
|
||||||
|
libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES)
|
||||||
|
|
||||||
|
noinst_PROGRAMS =
|
||||||
|
if USE_BENCHMARK
|
||||||
|
noinst_PROGRAMS += bench_verify bench_sign bench_internal
|
||||||
|
bench_verify_SOURCES = src/bench_verify.c
|
||||||
|
bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
|
||||||
|
bench_sign_SOURCES = src/bench_sign.c
|
||||||
|
bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
|
||||||
|
bench_internal_SOURCES = src/bench_internal.c
|
||||||
|
bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB)
|
||||||
|
bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if USE_TESTS
|
||||||
|
noinst_PROGRAMS += tests
|
||||||
|
tests_SOURCES = src/tests.c
|
||||||
|
tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
|
||||||
|
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
|
||||||
|
tests_LDFLAGS = -static
|
||||||
|
TESTS = tests
|
||||||
|
endif
|
||||||
|
|
||||||
|
JAVAROOT=src/java
|
||||||
|
JAVAORG=org/bitcoin
|
||||||
|
JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar
|
||||||
|
CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA)
|
||||||
|
JAVA_FILES= \
|
||||||
|
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \
|
||||||
|
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \
|
||||||
|
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \
|
||||||
|
$(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java
|
||||||
|
|
||||||
|
if USE_JNI
|
||||||
|
|
||||||
|
$(JAVA_GUAVA):
|
||||||
|
@echo Guava is missing. Fetch it via: \
|
||||||
|
wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@)
|
||||||
|
@false
|
||||||
|
|
||||||
|
.stamp-java: $(JAVA_FILES)
|
||||||
|
@echo Compiling $^
|
||||||
|
$(AM_V_at)$(CLASSPATH_ENV) javac $^
|
||||||
|
@touch $@
|
||||||
|
|
||||||
|
if USE_TESTS
|
||||||
|
|
||||||
|
check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java
|
||||||
|
$(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test
|
||||||
|
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if USE_ECMULT_STATIC_PRECOMPUTATION
|
||||||
|
CPPFLAGS_FOR_BUILD +=-I$(top_srcdir)
|
||||||
|
CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function
|
||||||
|
|
||||||
|
gen_context_OBJECTS = gen_context.o
|
||||||
|
gen_context_BIN = gen_context$(BUILD_EXEEXT)
|
||||||
|
gen_%.o: src/gen_%.c
|
||||||
|
$(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@
|
||||||
|
|
||||||
|
$(gen_context_BIN): $(gen_context_OBJECTS)
|
||||||
|
$(CC_FOR_BUILD) $^ -o $@
|
||||||
|
|
||||||
|
$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h
|
||||||
|
$(tests_OBJECTS): src/ecmult_static_context.h
|
||||||
|
$(bench_internal_OBJECTS): src/ecmult_static_context.h
|
||||||
|
|
||||||
|
src/ecmult_static_context.h: $(gen_context_BIN)
|
||||||
|
./$(gen_context_BIN)
|
||||||
|
|
||||||
|
CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java
|
||||||
|
endif
|
||||||
|
|
||||||
|
EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES)
|
||||||
|
|
||||||
|
if ENABLE_MODULE_ECDH
|
||||||
|
include src/modules/ecdh/Makefile.am.include
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ENABLE_MODULE_SCHNORR
|
||||||
|
include src/modules/schnorr/Makefile.am.include
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ENABLE_MODULE_RECOVERY
|
||||||
|
include src/modules/recovery/Makefile.am.include
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ENABLE_MODULE_RANGEPROOF
|
||||||
|
include src/modules/rangeproof/Makefile.am.include
|
||||||
|
endif
|
61
secp256k1zkp/depend/secp256k1-zkp/README.md
Normal file
61
secp256k1zkp/depend/secp256k1-zkp/README.md
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
libsecp256k1
|
||||||
|
============
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1)
|
||||||
|
|
||||||
|
Optimized C library for EC operations on curve secp256k1.
|
||||||
|
|
||||||
|
This library is a work in progress and is being used to research best practices. Use at your own risk.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
* secp256k1 ECDSA signing/verification and key generation.
|
||||||
|
* Adding/multiplying private/public keys.
|
||||||
|
* Serialization/parsing of private keys, public keys, signatures.
|
||||||
|
* Constant time, constant memory access signing and pubkey generation.
|
||||||
|
* Derandomized DSA (via RFC6979 or with a caller provided function.)
|
||||||
|
* Very efficient implementation.
|
||||||
|
|
||||||
|
Implementation details
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
* General
|
||||||
|
* No runtime heap allocation.
|
||||||
|
* Extensive testing infrastructure.
|
||||||
|
* Structured to facilitate review and analysis.
|
||||||
|
* Intended to be portable to any system with a C89 compiler and uint64_t support.
|
||||||
|
* 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 10 26-bit limbs.
|
||||||
|
* Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman).
|
||||||
|
* Scalar operations
|
||||||
|
* Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
|
||||||
|
* Using 4 64-bit limbs (relying on __int128 support in the compiler).
|
||||||
|
* Using 8 32-bit limbs.
|
||||||
|
* Group operations
|
||||||
|
* Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7).
|
||||||
|
* Use addition between points in Jacobian and affine coordinates where possible.
|
||||||
|
* Use a unified addition/doubling formula where necessary to avoid data-dependent branches.
|
||||||
|
* Point/x comparison without a field inversion by comparison in the Jacobian coordinate space.
|
||||||
|
* Point multiplication for verification (a*P + b*G).
|
||||||
|
* Use wNAF notation for point multiplicands.
|
||||||
|
* Use a much larger window for multiples of G, using precomputed multiples.
|
||||||
|
* Use Shamir's trick to do the multiplication with the public key and the generator simultaneously.
|
||||||
|
* Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones.
|
||||||
|
* Point multiplication for signing
|
||||||
|
* Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions.
|
||||||
|
* Access the table with branch-free conditional moves so memory access is uniform.
|
||||||
|
* No data-dependent branches
|
||||||
|
* The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally.
|
||||||
|
|
||||||
|
Build steps
|
||||||
|
-----------
|
||||||
|
|
||||||
|
libsecp256k1 is built using autotools:
|
||||||
|
|
||||||
|
$ ./autogen.sh
|
||||||
|
$ ./configure
|
||||||
|
$ make
|
||||||
|
$ ./tests
|
||||||
|
$ sudo make install # optional
|
3
secp256k1zkp/depend/secp256k1-zkp/TODO
Normal file
3
secp256k1zkp/depend/secp256k1-zkp/TODO
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
* Unit tests for fieldelem/groupelem, including ones intended to
|
||||||
|
trigger fieldelem's boundary cases.
|
||||||
|
* Complete constant-time operations for signing/keygen
|
3
secp256k1zkp/depend/secp256k1-zkp/autogen.sh
Executable file
3
secp256k1zkp/depend/secp256k1-zkp/autogen.sh
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
autoreconf -if --warnings=all
|
|
@ -0,0 +1,140 @@
|
||||||
|
# ===========================================================================
|
||||||
|
# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html
|
||||||
|
# ===========================================================================
|
||||||
|
#
|
||||||
|
# SYNOPSIS
|
||||||
|
#
|
||||||
|
# AX_JNI_INCLUDE_DIR
|
||||||
|
#
|
||||||
|
# DESCRIPTION
|
||||||
|
#
|
||||||
|
# AX_JNI_INCLUDE_DIR finds include directories needed for compiling
|
||||||
|
# programs using the JNI interface.
|
||||||
|
#
|
||||||
|
# JNI include directories are usually in the Java distribution. This is
|
||||||
|
# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in
|
||||||
|
# that order. When this macro completes, a list of directories is left in
|
||||||
|
# the variable JNI_INCLUDE_DIRS.
|
||||||
|
#
|
||||||
|
# Example usage follows:
|
||||||
|
#
|
||||||
|
# AX_JNI_INCLUDE_DIR
|
||||||
|
#
|
||||||
|
# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS
|
||||||
|
# do
|
||||||
|
# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR"
|
||||||
|
# done
|
||||||
|
#
|
||||||
|
# If you want to force a specific compiler:
|
||||||
|
#
|
||||||
|
# - at the configure.in level, set JAVAC=yourcompiler before calling
|
||||||
|
# AX_JNI_INCLUDE_DIR
|
||||||
|
#
|
||||||
|
# - at the configure level, setenv JAVAC
|
||||||
|
#
|
||||||
|
# Note: This macro can work with the autoconf M4 macros for Java programs.
|
||||||
|
# This particular macro is not part of the original set of macros.
|
||||||
|
#
|
||||||
|
# LICENSE
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008 Don Anderson <dda@sleepycat.com>
|
||||||
|
#
|
||||||
|
# Copying and distribution of this file, with or without modification, are
|
||||||
|
# permitted in any medium without royalty provided the copyright notice
|
||||||
|
# and this notice are preserved. This file is offered as-is, without any
|
||||||
|
# warranty.
|
||||||
|
|
||||||
|
#serial 10
|
||||||
|
|
||||||
|
AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR])
|
||||||
|
AC_DEFUN([AX_JNI_INCLUDE_DIR],[
|
||||||
|
|
||||||
|
JNI_INCLUDE_DIRS=""
|
||||||
|
|
||||||
|
if test "x$JAVA_HOME" != x; then
|
||||||
|
_JTOPDIR="$JAVA_HOME"
|
||||||
|
else
|
||||||
|
if test "x$JAVAC" = x; then
|
||||||
|
JAVAC=javac
|
||||||
|
fi
|
||||||
|
AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no])
|
||||||
|
if test "x$_ACJNI_JAVAC" = xno; then
|
||||||
|
AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME])
|
||||||
|
fi
|
||||||
|
_ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC")
|
||||||
|
_JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'`
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$host_os" in
|
||||||
|
darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
|
||||||
|
_JINC="$_JTOPDIR/Headers";;
|
||||||
|
*) _JINC="$_JTOPDIR/include";;
|
||||||
|
esac
|
||||||
|
_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR])
|
||||||
|
_AS_ECHO_LOG([_JINC=$_JINC])
|
||||||
|
|
||||||
|
# On Mac OS X 10.6.4, jni.h is a symlink:
|
||||||
|
# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h
|
||||||
|
# -> ../../CurrentJDK/Headers/jni.h.
|
||||||
|
|
||||||
|
AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path,
|
||||||
|
[
|
||||||
|
if test -f "$_JINC/jni.h"; then
|
||||||
|
ac_cv_jni_header_path="$_JINC"
|
||||||
|
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
|
||||||
|
else
|
||||||
|
_JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
|
||||||
|
if test -f "$_JTOPDIR/include/jni.h"; then
|
||||||
|
ac_cv_jni_header_path="$_JTOPDIR/include"
|
||||||
|
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
|
||||||
|
else
|
||||||
|
ac_cv_jni_header_path=none
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# get the likely subdirectories for system specific java includes
|
||||||
|
case "$host_os" in
|
||||||
|
bsdi*) _JNI_INC_SUBDIRS="bsdos";;
|
||||||
|
darwin*) _JNI_INC_SUBDIRS="darwin";;
|
||||||
|
freebsd*) _JNI_INC_SUBDIRS="freebsd";;
|
||||||
|
linux*) _JNI_INC_SUBDIRS="linux genunix";;
|
||||||
|
osf*) _JNI_INC_SUBDIRS="alpha";;
|
||||||
|
solaris*) _JNI_INC_SUBDIRS="solaris";;
|
||||||
|
mingw*) _JNI_INC_SUBDIRS="win32";;
|
||||||
|
cygwin*) _JNI_INC_SUBDIRS="win32";;
|
||||||
|
*) _JNI_INC_SUBDIRS="genunix";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if test "x$ac_cv_jni_header_path" != "xnone"; then
|
||||||
|
# add any subdirectories that are present
|
||||||
|
for JINCSUBDIR in $_JNI_INC_SUBDIRS
|
||||||
|
do
|
||||||
|
if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then
|
||||||
|
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
# _ACJNI_FOLLOW_SYMLINKS <path>
|
||||||
|
# Follows symbolic links on <path>,
|
||||||
|
# finally setting variable _ACJNI_FOLLOWED
|
||||||
|
# ----------------------------------------
|
||||||
|
AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[
|
||||||
|
# find the include directory relative to the javac executable
|
||||||
|
_cur="$1"
|
||||||
|
while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do
|
||||||
|
AC_MSG_CHECKING([symlink for $_cur])
|
||||||
|
_slink=`ls -ld "$_cur" | sed 's/.* -> //'`
|
||||||
|
case "$_slink" in
|
||||||
|
/*) _cur="$_slink";;
|
||||||
|
# 'X' avoids triggering unwanted echo options.
|
||||||
|
*) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";;
|
||||||
|
esac
|
||||||
|
AC_MSG_RESULT([$_cur])
|
||||||
|
done
|
||||||
|
_ACJNI_FOLLOWED="$_cur"
|
||||||
|
])# _ACJNI
|
|
@ -0,0 +1,125 @@
|
||||||
|
# ===========================================================================
|
||||||
|
# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html
|
||||||
|
# ===========================================================================
|
||||||
|
#
|
||||||
|
# SYNOPSIS
|
||||||
|
#
|
||||||
|
# AX_PROG_CC_FOR_BUILD
|
||||||
|
#
|
||||||
|
# DESCRIPTION
|
||||||
|
#
|
||||||
|
# This macro searches for a C compiler that generates native executables,
|
||||||
|
# that is a C compiler that surely is not a cross-compiler. This can be
|
||||||
|
# useful if you have to generate source code at compile-time like for
|
||||||
|
# example GCC does.
|
||||||
|
#
|
||||||
|
# The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything
|
||||||
|
# needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD).
|
||||||
|
# The value of these variables can be overridden by the user by specifying
|
||||||
|
# a compiler with an environment variable (like you do for standard CC).
|
||||||
|
#
|
||||||
|
# It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object
|
||||||
|
# file extensions for the build platform, and GCC_FOR_BUILD to `yes' if
|
||||||
|
# the compiler we found is GCC. All these variables but GCC_FOR_BUILD are
|
||||||
|
# substituted in the Makefile.
|
||||||
|
#
|
||||||
|
# LICENSE
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008 Paolo Bonzini <bonzini@gnu.org>
|
||||||
|
#
|
||||||
|
# Copying and distribution of this file, with or without modification, are
|
||||||
|
# permitted in any medium without royalty provided the copyright notice
|
||||||
|
# and this notice are preserved. This file is offered as-is, without any
|
||||||
|
# warranty.
|
||||||
|
|
||||||
|
#serial 8
|
||||||
|
|
||||||
|
AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD])
|
||||||
|
AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl
|
||||||
|
AC_REQUIRE([AC_PROG_CC])dnl
|
||||||
|
AC_REQUIRE([AC_PROG_CPP])dnl
|
||||||
|
AC_REQUIRE([AC_EXEEXT])dnl
|
||||||
|
AC_REQUIRE([AC_CANONICAL_HOST])dnl
|
||||||
|
|
||||||
|
dnl Use the standard macros, but make them use other variable names
|
||||||
|
dnl
|
||||||
|
pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl
|
||||||
|
pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl
|
||||||
|
pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl
|
||||||
|
pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl
|
||||||
|
pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl
|
||||||
|
pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl
|
||||||
|
pushdef([ac_cv_objext], ac_cv_build_objext)dnl
|
||||||
|
pushdef([ac_exeext], ac_build_exeext)dnl
|
||||||
|
pushdef([ac_objext], ac_build_objext)dnl
|
||||||
|
pushdef([CC], CC_FOR_BUILD)dnl
|
||||||
|
pushdef([CPP], CPP_FOR_BUILD)dnl
|
||||||
|
pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl
|
||||||
|
pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl
|
||||||
|
pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl
|
||||||
|
pushdef([host], build)dnl
|
||||||
|
pushdef([host_alias], build_alias)dnl
|
||||||
|
pushdef([host_cpu], build_cpu)dnl
|
||||||
|
pushdef([host_vendor], build_vendor)dnl
|
||||||
|
pushdef([host_os], build_os)dnl
|
||||||
|
pushdef([ac_cv_host], ac_cv_build)dnl
|
||||||
|
pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl
|
||||||
|
pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl
|
||||||
|
pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl
|
||||||
|
pushdef([ac_cv_host_os], ac_cv_build_os)dnl
|
||||||
|
pushdef([ac_cpp], ac_build_cpp)dnl
|
||||||
|
pushdef([ac_compile], ac_build_compile)dnl
|
||||||
|
pushdef([ac_link], ac_build_link)dnl
|
||||||
|
|
||||||
|
save_cross_compiling=$cross_compiling
|
||||||
|
save_ac_tool_prefix=$ac_tool_prefix
|
||||||
|
cross_compiling=no
|
||||||
|
ac_tool_prefix=
|
||||||
|
|
||||||
|
AC_PROG_CC
|
||||||
|
AC_PROG_CPP
|
||||||
|
AC_EXEEXT
|
||||||
|
|
||||||
|
ac_tool_prefix=$save_ac_tool_prefix
|
||||||
|
cross_compiling=$save_cross_compiling
|
||||||
|
|
||||||
|
dnl Restore the old definitions
|
||||||
|
dnl
|
||||||
|
popdef([ac_link])dnl
|
||||||
|
popdef([ac_compile])dnl
|
||||||
|
popdef([ac_cpp])dnl
|
||||||
|
popdef([ac_cv_host_os])dnl
|
||||||
|
popdef([ac_cv_host_vendor])dnl
|
||||||
|
popdef([ac_cv_host_cpu])dnl
|
||||||
|
popdef([ac_cv_host_alias])dnl
|
||||||
|
popdef([ac_cv_host])dnl
|
||||||
|
popdef([host_os])dnl
|
||||||
|
popdef([host_vendor])dnl
|
||||||
|
popdef([host_cpu])dnl
|
||||||
|
popdef([host_alias])dnl
|
||||||
|
popdef([host])dnl
|
||||||
|
popdef([LDFLAGS])dnl
|
||||||
|
popdef([CPPFLAGS])dnl
|
||||||
|
popdef([CFLAGS])dnl
|
||||||
|
popdef([CPP])dnl
|
||||||
|
popdef([CC])dnl
|
||||||
|
popdef([ac_objext])dnl
|
||||||
|
popdef([ac_exeext])dnl
|
||||||
|
popdef([ac_cv_objext])dnl
|
||||||
|
popdef([ac_cv_exeext])dnl
|
||||||
|
popdef([ac_cv_prog_cc_g])dnl
|
||||||
|
popdef([ac_cv_prog_cc_cross])dnl
|
||||||
|
popdef([ac_cv_prog_cc_works])dnl
|
||||||
|
popdef([ac_cv_prog_gcc])dnl
|
||||||
|
popdef([ac_cv_prog_CPP])dnl
|
||||||
|
|
||||||
|
dnl Finally, set Makefile variables
|
||||||
|
dnl
|
||||||
|
BUILD_EXEEXT=$ac_build_exeext
|
||||||
|
BUILD_OBJEXT=$ac_build_objext
|
||||||
|
AC_SUBST(BUILD_EXEEXT)dnl
|
||||||
|
AC_SUBST(BUILD_OBJEXT)dnl
|
||||||
|
AC_SUBST([CFLAGS_FOR_BUILD])dnl
|
||||||
|
AC_SUBST([CPPFLAGS_FOR_BUILD])dnl
|
||||||
|
AC_SUBST([LDFLAGS_FOR_BUILD])dnl
|
||||||
|
])
|
|
@ -0,0 +1,65 @@
|
||||||
|
dnl libsecp25k1 helper checks
|
||||||
|
AC_DEFUN([SECP_INT128_CHECK],[
|
||||||
|
has_int128=$ac_cv_type___int128
|
||||||
|
])
|
||||||
|
|
||||||
|
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_MSG_CHECKING(for x86_64 assembly availability)
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||||
|
#include <stdint.h>]],[[
|
||||||
|
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])
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl
|
||||||
|
AC_DEFUN([SECP_OPENSSL_CHECK],[
|
||||||
|
has_libcrypto=no
|
||||||
|
m4_ifdef([PKG_CHECK_MODULES],[
|
||||||
|
PKG_CHECK_MODULES([CRYPTO], [libcrypto], [has_libcrypto=yes],[has_libcrypto=no])
|
||||||
|
if test x"$has_libcrypto" = x"yes"; then
|
||||||
|
TEMP_LIBS="$LIBS"
|
||||||
|
LIBS="$LIBS $CRYPTO_LIBS"
|
||||||
|
AC_CHECK_LIB(crypto, main,[AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])],[has_libcrypto=no])
|
||||||
|
LIBS="$TEMP_LIBS"
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
if test x$has_libcrypto = xno; then
|
||||||
|
AC_CHECK_HEADER(openssl/crypto.h,[
|
||||||
|
AC_CHECK_LIB(crypto, main,[
|
||||||
|
has_libcrypto=yes
|
||||||
|
CRYPTO_LIBS=-lcrypto
|
||||||
|
AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
LIBS=
|
||||||
|
fi
|
||||||
|
if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then
|
||||||
|
AC_MSG_CHECKING(for EC functions in libcrypto)
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||||
|
#include <openssl/ec.h>
|
||||||
|
#include <openssl/ecdsa.h>
|
||||||
|
#include <openssl/obj_mac.h>]],[[
|
||||||
|
EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||||
|
ECDSA_sign(0, NULL, 0, NULL, NULL, eckey);
|
||||||
|
ECDSA_verify(0, NULL, 0, NULL, 0, eckey);
|
||||||
|
EC_KEY_free(eckey);
|
||||||
|
]])],[has_openssl_ec=yes],[has_openssl_ec=no])
|
||||||
|
AC_MSG_RESULT([$has_openssl_ec])
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl
|
||||||
|
AC_DEFUN([SECP_GMP_CHECK],[
|
||||||
|
if test x"$has_gmp" != x"yes"; then
|
||||||
|
CPPFLAGS_TEMP="$CPPFLAGS"
|
||||||
|
CPPFLAGS="$GMP_CPPFLAGS $CPPFLAGS"
|
||||||
|
LIBS_TEMP="$LIBS"
|
||||||
|
LIBS="$GMP_LIBS $LIBS"
|
||||||
|
AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS="$GMP_LIBS -lgmp"; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])])
|
||||||
|
CPPFLAGS="$CPPFLAGS_TEMP"
|
||||||
|
LIBS="$LIBS_TEMP"
|
||||||
|
fi
|
||||||
|
])
|
510
secp256k1zkp/depend/secp256k1-zkp/configure.ac
Normal file
510
secp256k1zkp/depend/secp256k1-zkp/configure.ac
Normal file
|
@ -0,0 +1,510 @@
|
||||||
|
AC_PREREQ([2.60])
|
||||||
|
AC_INIT([libsecp256k1],[0.1])
|
||||||
|
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*/])
|
||||||
|
AM_INIT_AUTOMAKE([foreign subdir-objects])
|
||||||
|
LT_INIT
|
||||||
|
|
||||||
|
dnl make the compilation flags quiet unless V=1 is used
|
||||||
|
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||||
|
|
||||||
|
PKG_PROG_PKG_CONFIG
|
||||||
|
|
||||||
|
AC_PATH_TOOL(AR, ar)
|
||||||
|
AC_PATH_TOOL(RANLIB, ranlib)
|
||||||
|
AC_PATH_TOOL(STRIP, strip)
|
||||||
|
AX_PROG_CC_FOR_BUILD
|
||||||
|
|
||||||
|
if test "x$CFLAGS" = "x"; then
|
||||||
|
CFLAGS="-O3 -g"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AM_PROG_CC_C_O
|
||||||
|
|
||||||
|
AC_PROG_CC_C89
|
||||||
|
if test x"$ac_cv_prog_cc_c89" = x"no"; then
|
||||||
|
AC_MSG_ERROR([c89 compiler support required])
|
||||||
|
fi
|
||||||
|
AM_PROG_AS
|
||||||
|
|
||||||
|
case $host_os in
|
||||||
|
*darwin*)
|
||||||
|
if test x$cross_compiling != xyes; then
|
||||||
|
AC_PATH_PROG([BREW],brew,)
|
||||||
|
if test x$BREW != x; then
|
||||||
|
dnl These Homebrew packages may be keg-only, meaning that they won't be found
|
||||||
|
dnl in expected paths because they may conflict with system files. Ask
|
||||||
|
dnl Homebrew where each one is located, then adjust paths accordingly.
|
||||||
|
|
||||||
|
openssl_prefix=`$BREW --prefix openssl 2>/dev/null`
|
||||||
|
gmp_prefix=`$BREW --prefix gmp 2>/dev/null`
|
||||||
|
if test x$openssl_prefix != x; then
|
||||||
|
PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||||
|
export PKG_CONFIG_PATH
|
||||||
|
fi
|
||||||
|
if test x$gmp_prefix != x; then
|
||||||
|
GMP_CPPFLAGS="-I$gmp_prefix/include"
|
||||||
|
GMP_LIBS="-L$gmp_prefix/lib"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AC_PATH_PROG([PORT],port,)
|
||||||
|
dnl if homebrew isn't installed and macports is, add the macports default paths
|
||||||
|
dnl as a last resort.
|
||||||
|
if test x$PORT != x; then
|
||||||
|
CPPFLAGS="$CPPFLAGS -isystem /opt/local/include"
|
||||||
|
LDFLAGS="$LDFLAGS -L/opt/local/lib"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CFLAGS="$CFLAGS -W"
|
||||||
|
|
||||||
|
warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings"
|
||||||
|
saved_CFLAGS="$CFLAGS"
|
||||||
|
CFLAGS="$CFLAGS $warn_CFLAGS"
|
||||||
|
AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}])
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
|
||||||
|
[ AC_MSG_RESULT([yes]) ],
|
||||||
|
[ AC_MSG_RESULT([no])
|
||||||
|
CFLAGS="$saved_CFLAGS"
|
||||||
|
])
|
||||||
|
|
||||||
|
saved_CFLAGS="$CFLAGS"
|
||||||
|
CFLAGS="$CFLAGS -fvisibility=hidden"
|
||||||
|
AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
|
||||||
|
[ AC_MSG_RESULT([yes]) ],
|
||||||
|
[ AC_MSG_RESULT([no])
|
||||||
|
CFLAGS="$saved_CFLAGS"
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(benchmark,
|
||||||
|
AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]),
|
||||||
|
[use_benchmark=$enableval],
|
||||||
|
[use_benchmark=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(tests,
|
||||||
|
AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]),
|
||||||
|
[use_tests=$enableval],
|
||||||
|
[use_tests=yes])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(openssl_tests,
|
||||||
|
AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]),
|
||||||
|
[enable_openssl_tests=$enableval],
|
||||||
|
[enable_openssl_tests=auto])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(experimental,
|
||||||
|
AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]),
|
||||||
|
[use_experimental=$enableval],
|
||||||
|
[use_experimental=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(endomorphism,
|
||||||
|
AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]),
|
||||||
|
[use_endomorphism=$enableval],
|
||||||
|
[use_endomorphism=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(ecmult_static_precomputation,
|
||||||
|
AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]),
|
||||||
|
[use_ecmult_static_precomputation=$enableval],
|
||||||
|
[use_ecmult_static_precomputation=auto])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(module_ecdh,
|
||||||
|
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]),
|
||||||
|
[enable_module_ecdh=$enableval],
|
||||||
|
[enable_module_ecdh=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(module_schnorr,
|
||||||
|
AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (experimental)]),
|
||||||
|
[enable_module_schnorr=$enableval],
|
||||||
|
[enable_module_schnorr=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(module_recovery,
|
||||||
|
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]),
|
||||||
|
[enable_module_recovery=$enableval],
|
||||||
|
[enable_module_recovery=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(module_rangeproof,
|
||||||
|
AS_HELP_STRING([--enable-module-rangeproof],[enable Pedersen / zero-knowledge range proofs module (default is no)]),
|
||||||
|
[enable_module_rangeproof=$enableval],
|
||||||
|
[enable_module_rangeproof=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(jni,
|
||||||
|
AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]),
|
||||||
|
[use_jni=$enableval],
|
||||||
|
[use_jni=auto])
|
||||||
|
|
||||||
|
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
|
||||||
|
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
|
||||||
|
|
||||||
|
AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto],
|
||||||
|
[Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto])
|
||||||
|
|
||||||
|
AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
|
||||||
|
[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto])
|
||||||
|
|
||||||
|
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto]
|
||||||
|
[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto])
|
||||||
|
|
||||||
|
AC_CHECK_TYPES([__int128])
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for __builtin_expect])
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
|
||||||
|
[ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ],
|
||||||
|
[ AC_MSG_RESULT([no])
|
||||||
|
])
|
||||||
|
|
||||||
|
if test x"$use_ecmult_static_precomputation" != x"no"; then
|
||||||
|
save_cross_compiling=$cross_compiling
|
||||||
|
cross_compiling=no
|
||||||
|
TEMP_CC="$CC"
|
||||||
|
CC="$CC_FOR_BUILD"
|
||||||
|
AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}])
|
||||||
|
AC_RUN_IFELSE(
|
||||||
|
[AC_LANG_PROGRAM([], [return 0])],
|
||||||
|
[working_native_cc=yes],
|
||||||
|
[working_native_cc=no],[dnl])
|
||||||
|
CC="$TEMP_CC"
|
||||||
|
cross_compiling=$save_cross_compiling
|
||||||
|
|
||||||
|
if test x"$working_native_cc" = x"no"; then
|
||||||
|
set_precomp=no
|
||||||
|
if test x"$use_ecmult_static_precomputation" = x"yes"; then
|
||||||
|
AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([ok])
|
||||||
|
set_precomp=yes
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
set_precomp=no
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for __builtin_clzll])
|
||||||
|
AC_COMPILE_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
|
||||||
|
|
||||||
|
if test x"$req_field" = x"auto"; then
|
||||||
|
if test x"set_asm" = x"x86_64"; then
|
||||||
|
set_field=64bit
|
||||||
|
fi
|
||||||
|
if test x"$set_field" = x; then
|
||||||
|
SECP_INT128_CHECK
|
||||||
|
if test x"$has_int128" = x"yes"; then
|
||||||
|
set_field=64bit
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if test x"$set_field" = x; then
|
||||||
|
set_field=32bit
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
set_field=$req_field
|
||||||
|
case $set_field in
|
||||||
|
64bit)
|
||||||
|
if test x"$set_asm" != x"x86_64"; then
|
||||||
|
SECP_INT128_CHECK
|
||||||
|
if test x"$has_int128" != x"yes"; then
|
||||||
|
AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
32bit)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR([invalid field implementation selection])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test x"$req_scalar" = x"auto"; then
|
||||||
|
SECP_INT128_CHECK
|
||||||
|
if test x"$has_int128" = x"yes"; then
|
||||||
|
set_scalar=64bit
|
||||||
|
fi
|
||||||
|
if test x"$set_scalar" = x; then
|
||||||
|
set_scalar=32bit
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
set_scalar=$req_scalar
|
||||||
|
case $set_scalar in
|
||||||
|
64bit)
|
||||||
|
SECP_INT128_CHECK
|
||||||
|
if test x"$has_int128" != x"yes"; then
|
||||||
|
AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available])
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
32bit)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR([invalid scalar implementation selected])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test x"$req_bignum" = x"auto"; then
|
||||||
|
SECP_GMP_CHECK
|
||||||
|
if test x"$has_gmp" = x"yes"; then
|
||||||
|
set_bignum=gmp
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test x"$set_bignum" = x; then
|
||||||
|
set_bignum=no
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
set_bignum=$req_bignum
|
||||||
|
case $set_bignum in
|
||||||
|
gmp)
|
||||||
|
SECP_GMP_CHECK
|
||||||
|
if test x"$has_gmp" != x"yes"; then
|
||||||
|
AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available])
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
no)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR([invalid bignum implementation selection])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# select assembly optimization
|
||||||
|
use_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)
|
||||||
|
use_external_asm=yes
|
||||||
|
;;
|
||||||
|
no)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR([invalid assembly optimizations])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# select field implementation
|
||||||
|
case $set_field in
|
||||||
|
64bit)
|
||||||
|
AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation])
|
||||||
|
;;
|
||||||
|
32bit)
|
||||||
|
AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation])
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR([invalid field implementation])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# select bignum implementation
|
||||||
|
case $set_bignum in
|
||||||
|
gmp)
|
||||||
|
AC_DEFINE(HAVE_LIBGMP, 1, [Define this symbol if libgmp is installed])
|
||||||
|
AC_DEFINE(USE_NUM_GMP, 1, [Define this symbol to use the gmp implementation for num])
|
||||||
|
AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation])
|
||||||
|
AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation])
|
||||||
|
;;
|
||||||
|
no)
|
||||||
|
AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation])
|
||||||
|
AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation])
|
||||||
|
AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation])
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR([invalid bignum implementation])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
#select scalar implementation
|
||||||
|
case $set_scalar in
|
||||||
|
64bit)
|
||||||
|
AC_DEFINE(USE_SCALAR_4X64, 1, [Define this symbol to use the 4x64 scalar implementation])
|
||||||
|
;;
|
||||||
|
32bit)
|
||||||
|
AC_DEFINE(USE_SCALAR_8X32, 1, [Define this symbol to use the 8x32 scalar implementation])
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR([invalid scalar implementation])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if test x"$use_tests" = x"yes"; then
|
||||||
|
SECP_OPENSSL_CHECK
|
||||||
|
if test x"$has_openssl_ec" = x"yes"; then
|
||||||
|
if test x"$enable_openssl_tests" != x"no"; then
|
||||||
|
AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])
|
||||||
|
SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS"
|
||||||
|
SECP_TEST_LIBS="$CRYPTO_LIBS"
|
||||||
|
|
||||||
|
case $host in
|
||||||
|
*mingw*)
|
||||||
|
SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if test x"$enable_openssl_tests" = x"yes"; then
|
||||||
|
AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if test x"$enable_openssl_tests" = x"yes"; then
|
||||||
|
AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test x"$use_jni" != x"no"; then
|
||||||
|
AX_JNI_INCLUDE_DIR
|
||||||
|
have_jni_dependencies=yes
|
||||||
|
if test x"$enable_module_schnorr" = x"no"; then
|
||||||
|
have_jni_dependencies=no
|
||||||
|
fi
|
||||||
|
if test x"$enable_module_ecdh" = x"no"; then
|
||||||
|
have_jni_dependencies=no
|
||||||
|
fi
|
||||||
|
if test "x$JNI_INCLUDE_DIRS" = "x"; then
|
||||||
|
have_jni_dependencies=no
|
||||||
|
fi
|
||||||
|
if test "x$have_jni_dependencies" = "xno"; then
|
||||||
|
if test x"$use_jni" = x"yes"; then
|
||||||
|
AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and Schnorr and try again.])
|
||||||
|
fi
|
||||||
|
AC_MSG_WARN([jni headers/dependencies not found. jni support disabled])
|
||||||
|
use_jni=no
|
||||||
|
else
|
||||||
|
use_jni=yes
|
||||||
|
for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do
|
||||||
|
JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test x"$set_bignum" = x"gmp"; then
|
||||||
|
SECP_LIBS="$SECP_LIBS $GMP_LIBS"
|
||||||
|
SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test x"$use_endomorphism" = x"yes"; then
|
||||||
|
AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test x"$use_ecmult_static_precomputation" = x"yes"; then
|
||||||
|
AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table])
|
||||||
|
fi
|
||||||
|
|
||||||
|
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_schnorr" = x"yes"; then
|
||||||
|
AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature module])
|
||||||
|
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_rangeproof" = x"yes"; then
|
||||||
|
AC_DEFINE(ENABLE_MODULE_RANGEPROOF, 1, [Define this symbol to enable the Pedersen / zero knowledge range proof module])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_C_BIGENDIAN()
|
||||||
|
|
||||||
|
if test x"$use_external_asm" = x"yes"; then
|
||||||
|
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_NOTICE([Using static precomputation: $set_precomp])
|
||||||
|
AC_MSG_NOTICE([Using assembly optimizations: $set_asm])
|
||||||
|
AC_MSG_NOTICE([Using field implementation: $set_field])
|
||||||
|
AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
|
||||||
|
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
|
||||||
|
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
|
||||||
|
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
|
||||||
|
AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
|
||||||
|
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
|
||||||
|
AC_MSG_NOTICE([Using jni: $use_jni])
|
||||||
|
|
||||||
|
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([Building ECDH module: $enable_module_ecdh])
|
||||||
|
AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
|
||||||
|
AC_MSG_NOTICE([Building range proof module: $enable_module_rangeproof])
|
||||||
|
AC_MSG_NOTICE([******])
|
||||||
|
else
|
||||||
|
if test x"$enable_module_schnorr" = x"yes"; then
|
||||||
|
AC_MSG_ERROR([Schnorr signature module is experimental. Use --enable-experimental to allow.])
|
||||||
|
fi
|
||||||
|
if test x"$enable_module_ecdh" = x"yes"; then
|
||||||
|
AC_MSG_ERROR([ECDH 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
|
||||||
|
if test x"$enable_module_rangeproof" = x"yes"; then
|
||||||
|
AC_MSG_ERROR([Range proof module is experimental. Use --enable-experimental to allow.])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
|
||||||
|
AC_CONFIG_FILES([Makefile libsecp256k1.pc])
|
||||||
|
AC_SUBST(JNI_INCLUDES)
|
||||||
|
AC_SUBST(SECP_INCLUDES)
|
||||||
|
AC_SUBST(SECP_LIBS)
|
||||||
|
AC_SUBST(SECP_TEST_LIBS)
|
||||||
|
AC_SUBST(SECP_TEST_INCLUDES)
|
||||||
|
AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
|
||||||
|
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
|
||||||
|
AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_precomputation" = x"yes"])
|
||||||
|
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
|
||||||
|
AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"])
|
||||||
|
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
||||||
|
AM_CONDITIONAL([ENABLE_MODULE_RANGEPROOF], [test x"$enable_module_rangeproof" = x"yes"])
|
||||||
|
AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"])
|
||||||
|
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
|
||||||
|
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
|
||||||
|
|
||||||
|
dnl make sure nothing new is exported so that we don't break the cache
|
||||||
|
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
|
||||||
|
unset PKG_CONFIG_PATH
|
||||||
|
PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP"
|
||||||
|
|
||||||
|
AC_OUTPUT
|
150
secp256k1zkp/depend/secp256k1-zkp/contrib/lax_der_parsing.c
Normal file
150
secp256k1zkp/depend/secp256k1-zkp/contrib/lax_der_parsing.c
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2015 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <secp256k1.h>
|
||||||
|
|
||||||
|
#include "lax_der_parsing.h"
|
||||||
|
|
||||||
|
int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
|
||||||
|
size_t rpos, rlen, spos, slen;
|
||||||
|
size_t pos = 0;
|
||||||
|
size_t lenbyte;
|
||||||
|
unsigned char tmpsig[64] = {0};
|
||||||
|
int overflow = 0;
|
||||||
|
|
||||||
|
/* Hack to initialize sig with a correctly-parsed but invalid signature. */
|
||||||
|
secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
|
||||||
|
|
||||||
|
/* Sequence tag byte */
|
||||||
|
if (pos == inputlen || input[pos] != 0x30) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
/* Sequence length bytes */
|
||||||
|
if (pos == inputlen) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
lenbyte = input[pos++];
|
||||||
|
if (lenbyte & 0x80) {
|
||||||
|
lenbyte -= 0x80;
|
||||||
|
if (pos + lenbyte > inputlen) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pos += lenbyte;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Integer tag byte for R */
|
||||||
|
if (pos == inputlen || input[pos] != 0x02) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
/* Integer length for R */
|
||||||
|
if (pos == inputlen) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
lenbyte = input[pos++];
|
||||||
|
if (lenbyte & 0x80) {
|
||||||
|
lenbyte -= 0x80;
|
||||||
|
if (pos + lenbyte > inputlen) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while (lenbyte > 0 && input[pos] == 0) {
|
||||||
|
pos++;
|
||||||
|
lenbyte--;
|
||||||
|
}
|
||||||
|
if (lenbyte >= sizeof(size_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rlen = 0;
|
||||||
|
while (lenbyte > 0) {
|
||||||
|
rlen = (rlen << 8) + input[pos];
|
||||||
|
pos++;
|
||||||
|
lenbyte--;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rlen = lenbyte;
|
||||||
|
}
|
||||||
|
if (rlen > inputlen - pos) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rpos = pos;
|
||||||
|
pos += rlen;
|
||||||
|
|
||||||
|
/* Integer tag byte for S */
|
||||||
|
if (pos == inputlen || input[pos] != 0x02) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
/* Integer length for S */
|
||||||
|
if (pos == inputlen) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
lenbyte = input[pos++];
|
||||||
|
if (lenbyte & 0x80) {
|
||||||
|
lenbyte -= 0x80;
|
||||||
|
if (pos + lenbyte > inputlen) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while (lenbyte > 0 && input[pos] == 0) {
|
||||||
|
pos++;
|
||||||
|
lenbyte--;
|
||||||
|
}
|
||||||
|
if (lenbyte >= sizeof(size_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
slen = 0;
|
||||||
|
while (lenbyte > 0) {
|
||||||
|
slen = (slen << 8) + input[pos];
|
||||||
|
pos++;
|
||||||
|
lenbyte--;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
slen = lenbyte;
|
||||||
|
}
|
||||||
|
if (slen > inputlen - pos) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
spos = pos;
|
||||||
|
pos += slen;
|
||||||
|
|
||||||
|
/* Ignore leading zeroes in R */
|
||||||
|
while (rlen > 0 && input[rpos] == 0) {
|
||||||
|
rlen--;
|
||||||
|
rpos++;
|
||||||
|
}
|
||||||
|
/* Copy R value */
|
||||||
|
if (rlen > 32) {
|
||||||
|
overflow = 1;
|
||||||
|
} else {
|
||||||
|
memcpy(tmpsig + 32 - rlen, input + rpos, rlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ignore leading zeroes in S */
|
||||||
|
while (slen > 0 && input[spos] == 0) {
|
||||||
|
slen--;
|
||||||
|
spos++;
|
||||||
|
}
|
||||||
|
/* Copy S value */
|
||||||
|
if (slen > 32) {
|
||||||
|
overflow = 1;
|
||||||
|
} else {
|
||||||
|
memcpy(tmpsig + 64 - slen, input + spos, slen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!overflow) {
|
||||||
|
overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
|
||||||
|
}
|
||||||
|
if (overflow) {
|
||||||
|
memset(tmpsig, 0, 64);
|
||||||
|
secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
91
secp256k1zkp/depend/secp256k1-zkp/contrib/lax_der_parsing.h
Normal file
91
secp256k1zkp/depend/secp256k1-zkp/contrib/lax_der_parsing.h
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2015 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
/****
|
||||||
|
* Please do not link this file directly. It is not part of the libsecp256k1
|
||||||
|
* project and does not promise any stability in its API, functionality or
|
||||||
|
* presence. Projects which use this code should instead copy this header
|
||||||
|
* and its accompanying .c file directly into their codebase.
|
||||||
|
****/
|
||||||
|
|
||||||
|
/* This file defines a function that parses DER with various errors and
|
||||||
|
* violations. This is not a part of the library itself, because the allowed
|
||||||
|
* violations are chosen arbitrarily and do not follow or establish any
|
||||||
|
* standard.
|
||||||
|
*
|
||||||
|
* In many places it matters that different implementations do not only accept
|
||||||
|
* the same set of valid signatures, but also reject the same set of signatures.
|
||||||
|
* The only means to accomplish that is by strictly obeying a standard, and not
|
||||||
|
* accepting anything else.
|
||||||
|
*
|
||||||
|
* Nonetheless, sometimes there is a need for compatibility with systems that
|
||||||
|
* use signatures which do not strictly obey DER. The snippet below shows how
|
||||||
|
* 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 secp256k1_ecdsa_signature_parse_der and
|
||||||
|
* secp256k1_ecdsa_signature_parse_compact).
|
||||||
|
*
|
||||||
|
* The supported violations are:
|
||||||
|
* - All numbers are parsed as nonnegative integers, even though X.609-0207
|
||||||
|
* section 8.3.3 specifies that integers are always encoded as two's
|
||||||
|
* complement.
|
||||||
|
* - Integers can have length 0, even though section 8.3.1 says they can't.
|
||||||
|
* - Integers with overly long padding are accepted, violation section
|
||||||
|
* 8.3.2.
|
||||||
|
* - 127-byte long length descriptors are accepted, even though section
|
||||||
|
* 8.1.3.5.c says that they are not.
|
||||||
|
* - Trailing garbage data inside or after the signature is ignored.
|
||||||
|
* - The length descriptor of the sequence is ignored.
|
||||||
|
*
|
||||||
|
* Compared to for example OpenSSL, many violations are NOT supported:
|
||||||
|
* - Using overly long tag descriptors for the sequence or integers inside,
|
||||||
|
* violating section 8.1.2.2.
|
||||||
|
* - Encoding primitive integers as constructed values, violating section
|
||||||
|
* 8.3.1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
|
||||||
|
#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
|
||||||
|
|
||||||
|
#include <secp256k1.h>
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/** Parse a signature in "lax DER" 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: input: a 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. In addition, it will accept signatures
|
||||||
|
* which violate the DER spec in various ways. Its purpose is to allow
|
||||||
|
* validation of the Bitcoin blockchain, which includes non-DER signatures
|
||||||
|
* from before the network rules were updated to enforce DER. Note that
|
||||||
|
* the set of supported violations is a strict subset of what OpenSSL will
|
||||||
|
* accept.
|
||||||
|
*
|
||||||
|
* After the call, sig will always be initialized. If parsing failed or the
|
||||||
|
* encoded numbers are out of range, signature validation with it is
|
||||||
|
* guaranteed to fail for every message and public key.
|
||||||
|
*/
|
||||||
|
int ecdsa_signature_parse_der_lax(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_ecdsa_signature* sig,
|
||||||
|
const unsigned char *input,
|
||||||
|
size_t inputlen
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,113 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2014, 2015 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <secp256k1.h>
|
||||||
|
|
||||||
|
#include "lax_der_privatekey_parsing.h"
|
||||||
|
|
||||||
|
int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) {
|
||||||
|
const unsigned char *end = privkey + privkeylen;
|
||||||
|
int lenb = 0;
|
||||||
|
int len = 0;
|
||||||
|
memset(out32, 0, 32);
|
||||||
|
/* sequence header */
|
||||||
|
if (end < privkey+1 || *privkey != 0x30) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
privkey++;
|
||||||
|
/* sequence length constructor */
|
||||||
|
if (end < privkey+1 || !(*privkey & 0x80)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
lenb = *privkey & ~0x80; privkey++;
|
||||||
|
if (lenb < 1 || lenb > 2) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (end < privkey+lenb) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* sequence length */
|
||||||
|
len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);
|
||||||
|
privkey += lenb;
|
||||||
|
if (end < privkey+len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* sequence element 0: version number (=1) */
|
||||||
|
if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
privkey += 3;
|
||||||
|
/* sequence element 1: octet string, up to 32 bytes */
|
||||||
|
if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]);
|
||||||
|
if (!secp256k1_ec_seckey_verify(ctx, out32)) {
|
||||||
|
memset(out32, 0, 32);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) {
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
size_t pubkeylen = 0;
|
||||||
|
if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) {
|
||||||
|
*privkeylen = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (compressed) {
|
||||||
|
static const unsigned char begin[] = {
|
||||||
|
0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20
|
||||||
|
};
|
||||||
|
static const unsigned char middle[] = {
|
||||||
|
0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
|
||||||
|
0xCE,0x3D,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,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
|
||||||
|
0x21,0x02,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,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,0xA1,0x24,0x03,0x22,0x00
|
||||||
|
};
|
||||||
|
unsigned char *ptr = privkey;
|
||||||
|
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
|
||||||
|
memcpy(ptr, key32, 32); ptr += 32;
|
||||||
|
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
|
||||||
|
pubkeylen = 33;
|
||||||
|
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED);
|
||||||
|
ptr += pubkeylen;
|
||||||
|
*privkeylen = ptr - privkey;
|
||||||
|
} else {
|
||||||
|
static const unsigned char begin[] = {
|
||||||
|
0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20
|
||||||
|
};
|
||||||
|
static const unsigned char middle[] = {
|
||||||
|
0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
|
||||||
|
0xCE,0x3D,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,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
|
||||||
|
0x41,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,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,0xA1,0x44,0x03,0x42,0x00
|
||||||
|
};
|
||||||
|
unsigned char *ptr = privkey;
|
||||||
|
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
|
||||||
|
memcpy(ptr, key32, 32); ptr += 32;
|
||||||
|
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
|
||||||
|
pubkeylen = 65;
|
||||||
|
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
|
||||||
|
ptr += pubkeylen;
|
||||||
|
*privkeylen = ptr - privkey;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2014, 2015 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
/****
|
||||||
|
* Please do not link this file directly. It is not part of the libsecp256k1
|
||||||
|
* project and does not promise any stability in its API, functionality or
|
||||||
|
* presence. Projects which use this code should instead copy this header
|
||||||
|
* and its accompanying .c file directly into their codebase.
|
||||||
|
****/
|
||||||
|
|
||||||
|
/* This file contains code snippets that parse DER private keys with
|
||||||
|
* various errors and violations. This is not a part of the library
|
||||||
|
* itself, because the allowed violations are chosen arbitrarily and
|
||||||
|
* do not follow or establish any standard.
|
||||||
|
*
|
||||||
|
* It also contains code to serialize private keys in a compatible
|
||||||
|
* manner.
|
||||||
|
*
|
||||||
|
* These functions are meant for compatibility with applications
|
||||||
|
* that require BER encoded keys. When working with secp256k1-specific
|
||||||
|
* code, the simple 32-byte private keys normally used by the
|
||||||
|
* library are sufficient.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
|
||||||
|
#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
|
||||||
|
|
||||||
|
#include <secp256k1.h>
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/** 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)
|
||||||
|
* 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
|
||||||
|
* privkey will be stored.
|
||||||
|
* In: seckey: pointer to a 32-byte secret key to export.
|
||||||
|
* compressed: 1 if the key should be exported in
|
||||||
|
* compressed format, 0 otherwise
|
||||||
|
*
|
||||||
|
* This function is purely meant for compatibility with applications that
|
||||||
|
* require BER encoded keys. When working with secp256k1-specific code, the
|
||||||
|
* simple 32-byte private keys are sufficient.
|
||||||
|
*
|
||||||
|
* Note that this function does not guarantee correct DER output. It is
|
||||||
|
* guaranteed to be parsable by secp256k1_ec_privkey_import_der
|
||||||
|
*/
|
||||||
|
SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *privkey,
|
||||||
|
size_t *privkeylen,
|
||||||
|
const unsigned char *seckey,
|
||||||
|
int compressed
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
/** Import a private key in DER format.
|
||||||
|
* Returns: 1 if a private key was extracted.
|
||||||
|
* Args: ctx: pointer to a context object (cannot be NULL).
|
||||||
|
* Out: seckey: pointer to a 32-byte array for storing the private key.
|
||||||
|
* (cannot be NULL).
|
||||||
|
* In: privkey: pointer to a private key in DER format (cannot be NULL).
|
||||||
|
* privkeylen: length of the DER private key pointed to be privkey.
|
||||||
|
*
|
||||||
|
* This function will accept more than just strict DER, and even allow some BER
|
||||||
|
* violations. The public key stored inside the DER-encoded private key is not
|
||||||
|
* verified for correctness, nor are the curve parameters. Use this function
|
||||||
|
* only if you know in advance it is supposed to contain a secp256k1 private
|
||||||
|
* key.
|
||||||
|
*/
|
||||||
|
SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *seckey,
|
||||||
|
const unsigned char *privkey,
|
||||||
|
size_t privkeylen
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
583
secp256k1zkp/depend/secp256k1-zkp/include/secp256k1.h
Normal file
583
secp256k1zkp/depend/secp256k1-zkp/include/secp256k1.h
Normal file
|
@ -0,0 +1,583 @@
|
||||||
|
#ifndef _SECP256K1_
|
||||||
|
# define _SECP256K1_
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* These rules specify the order of arguments in API calls:
|
||||||
|
*
|
||||||
|
* 1. Context pointers go first, followed by output arguments, combined
|
||||||
|
* output/input arguments, and finally input-only arguments.
|
||||||
|
* 2. Array lengths always immediately the follow the argument whose length
|
||||||
|
* they describe, even if this violates rule 1.
|
||||||
|
* 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated
|
||||||
|
* later go first. This means: signatures, public nonces, private nonces,
|
||||||
|
* messages, public keys, secret keys, tweaks.
|
||||||
|
* 4. Arguments that are not data pointers go last, from more complex to less
|
||||||
|
* complex: function pointers, algorithm names, messages, void pointers,
|
||||||
|
* counts, flags, booleans.
|
||||||
|
* 5. Opaque data pointers follow the function pointer they are to be passed to.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Opaque data structure that holds context information (precomputed tables etc.).
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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 constructed context can safely be used from multiple threads
|
||||||
|
* simultaneously, but API call that take a non-const pointer to a context
|
||||||
|
* need exclusive access to it. In particular this is the case for
|
||||||
|
* secp256k1_context_destroy and secp256k1_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 secp256k1_context_struct secp256k1_context;
|
||||||
|
|
||||||
|
/** Opaque data structure that holds a parsed and valid public key.
|
||||||
|
*
|
||||||
|
* 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 or transmission, use
|
||||||
|
* secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse.
|
||||||
|
*
|
||||||
|
* Furthermore, it is guaranteed that identical public keys (ignoring
|
||||||
|
* compression) will have identical representation, so they can be memcmp'ed.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
unsigned char data[64];
|
||||||
|
} secp256k1_pubkey;
|
||||||
|
|
||||||
|
/** Opaque data structured 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 or transmission, use
|
||||||
|
* the secp256k1_ecdsa_signature_serialize_* and
|
||||||
|
* secp256k1_ecdsa_signature_serialize_* functions.
|
||||||
|
*
|
||||||
|
* Furthermore, it is guaranteed to identical signatures will have identical
|
||||||
|
* representation, so they can be memcmp'ed.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
unsigned char data[64];
|
||||||
|
} secp256k1_ecdsa_signature;
|
||||||
|
|
||||||
|
/** A pointer to a function to deterministically generate a nonce.
|
||||||
|
*
|
||||||
|
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail.
|
||||||
|
* Out: nonce32: pointer to a 32-byte array to be filled by the function.
|
||||||
|
* In: msg32: the 32-byte message hash being verified (will not be NULL)
|
||||||
|
* key32: pointer to a 32-byte secret key (will not be NULL)
|
||||||
|
* algo16: pointer to a 16-byte array describing the signature
|
||||||
|
* algorithm (will be NULL for ECDSA for compatibility).
|
||||||
|
* data: Arbitrary data pointer that is passed through.
|
||||||
|
* attempt: how many iterations we have tried to find a nonce.
|
||||||
|
* This will almost always be 0, but different attempt values
|
||||||
|
* are required to result in a different nonce.
|
||||||
|
*
|
||||||
|
* Except for test cases, this function should compute some cryptographic hash of
|
||||||
|
* the message, the algorithm, the key and the attempt.
|
||||||
|
*/
|
||||||
|
typedef int (*secp256k1_nonce_function)(
|
||||||
|
unsigned char *nonce32,
|
||||||
|
const unsigned char *msg32,
|
||||||
|
const unsigned char *key32,
|
||||||
|
const unsigned char *algo16,
|
||||||
|
void *data,
|
||||||
|
unsigned int attempt
|
||||||
|
);
|
||||||
|
|
||||||
|
# if !defined(SECP256K1_GNUC_PREREQ)
|
||||||
|
# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
|
||||||
|
# define SECP256K1_GNUC_PREREQ(_maj,_min) \
|
||||||
|
((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
|
||||||
|
# else
|
||||||
|
# define SECP256K1_GNUC_PREREQ(_maj,_min) 0
|
||||||
|
# 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
|
||||||
|
|
||||||
|
#ifndef SECP256K1_API
|
||||||
|
# if defined(_WIN32)
|
||||||
|
# ifdef SECP256K1_BUILD
|
||||||
|
# define SECP256K1_API __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define SECP256K1_API
|
||||||
|
# endif
|
||||||
|
# elif defined(__GNUC__) && defined(SECP256K1_BUILD)
|
||||||
|
# define SECP256K1_API __attribute__ ((visibility ("default")))
|
||||||
|
# else
|
||||||
|
# define SECP256K1_API
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**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
|
||||||
|
# define SECP256K1_WARN_UNUSED_RESULT
|
||||||
|
# endif
|
||||||
|
# if !defined(SECP256K1_BUILD) && defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4)
|
||||||
|
# define SECP256K1_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x)))
|
||||||
|
# else
|
||||||
|
# define SECP256K1_ARG_NONNULL(_x)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/** 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. */
|
||||||
|
#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8)
|
||||||
|
#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9)
|
||||||
|
#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8)
|
||||||
|
|
||||||
|
/** Flags to pass to secp256k1_context_create. */
|
||||||
|
#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)
|
||||||
|
#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
|
||||||
|
|
||||||
|
/** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */
|
||||||
|
#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
|
||||||
|
#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION)
|
||||||
|
|
||||||
|
/** Create a secp256k1 context object.
|
||||||
|
*
|
||||||
|
* Returns: a newly created context object.
|
||||||
|
* In: flags: which parts of the context to initialize.
|
||||||
|
*/
|
||||||
|
SECP256K1_API secp256k1_context* secp256k1_context_create(
|
||||||
|
unsigned int flags
|
||||||
|
) SECP256K1_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
/** Copies a secp256k1 context object.
|
||||||
|
*
|
||||||
|
* Returns: a newly created context object.
|
||||||
|
* Args: ctx: an existing context to copy (cannot be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API secp256k1_context* secp256k1_context_clone(
|
||||||
|
const secp256k1_context* ctx
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
/** Destroy a secp256k1 context object.
|
||||||
|
*
|
||||||
|
* The context pointer may not be used afterwards.
|
||||||
|
* Args: ctx: an existing context to destroy (cannot be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API void secp256k1_context_destroy(
|
||||||
|
secp256k1_context* ctx
|
||||||
|
);
|
||||||
|
|
||||||
|
/** 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Args: ctx: an existing context object (cannot be NULL)
|
||||||
|
* In: fun: a pointer to a function to call when an illegal argument is
|
||||||
|
* passed to the API, taking a message and an opaque pointer
|
||||||
|
* (NULL restores a default handler that calls abort).
|
||||||
|
* data: the opaque pointer to pass to fun above.
|
||||||
|
*/
|
||||||
|
SECP256K1_API void secp256k1_context_set_illegal_callback(
|
||||||
|
secp256k1_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.
|
||||||
|
*
|
||||||
|
* 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_context_set_illegal_callback
|
||||||
|
* for that). After this callback returns, anything may happen, including
|
||||||
|
* crashing.
|
||||||
|
*
|
||||||
|
* Args: ctx: an existing context object (cannot be NULL)
|
||||||
|
* In: fun: a pointer to a function to call when an internal error occurs,
|
||||||
|
* taking a message and an opaque pointer (NULL restores a default
|
||||||
|
* handler that calls abort).
|
||||||
|
* data: the opaque pointer to pass to fun above.
|
||||||
|
*/
|
||||||
|
SECP256K1_API void secp256k1_context_set_error_callback(
|
||||||
|
secp256k1_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.
|
||||||
|
* 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
|
||||||
|
* inputlen: length of the array pointed to by input
|
||||||
|
*
|
||||||
|
* This function supports parsing compressed (33 bytes, header byte 0x02 or
|
||||||
|
* 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 secp256k1_ec_pubkey_parse(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_pubkey* pubkey,
|
||||||
|
const unsigned char *input,
|
||||||
|
size_t inputlen
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** 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
|
||||||
|
* compressed==1) byte array to place the serialized key
|
||||||
|
* in.
|
||||||
|
* 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: pubkey: a pointer to a secp256k1_pubkey containing an
|
||||||
|
* initialized public key.
|
||||||
|
* flags: SECP256K1_EC_COMPRESSED if serialization should be in
|
||||||
|
* compressed format, otherwise SECP256K1_EC_UNCOMPRESSED.
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_ec_pubkey_serialize(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *output,
|
||||||
|
size_t *outputlen,
|
||||||
|
const secp256k1_pubkey* pubkey,
|
||||||
|
unsigned int flags
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
/** 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
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_ecdsa_signature_parse_compact(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_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
|
||||||
|
* 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
|
||||||
|
* guaranteed to fail for every message and public key.
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_ecdsa_signature_parse_der(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_ecdsa_signature* sig,
|
||||||
|
const unsigned char *input,
|
||||||
|
size_t inputlen
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** 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
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_ecdsa_signature_serialize_der(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *output,
|
||||||
|
size_t *outputlen,
|
||||||
|
const secp256k1_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
|
||||||
|
*
|
||||||
|
* See secp256k1_ecdsa_signature_parse_compact for details about the encoding.
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *output64,
|
||||||
|
const secp256k1_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.
|
||||||
|
* In: sig: the signature being verified (cannot be NULL)
|
||||||
|
* msg32: the 32-byte message hash being verified (cannot be NULL)
|
||||||
|
* pubkey: pointer to an initialized public key to verify with (cannot be NULL)
|
||||||
|
*
|
||||||
|
* To avoid accepting malleable signatures, only ECDSA signatures in lower-S
|
||||||
|
* form are accepted.
|
||||||
|
*
|
||||||
|
* If you need to accept ECDSA signatures from sources that do not obey this
|
||||||
|
* rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to
|
||||||
|
* validation, 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 secp256k1_ecdsa_verify(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
const secp256k1_ecdsa_signature *sig,
|
||||||
|
const unsigned char *msg32,
|
||||||
|
const secp256k1_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,
|
||||||
|
* 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 (cannot be NULL,
|
||||||
|
* 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
|
||||||
|
* is done by negating the S value modulo the order of the curve, 'flipping'
|
||||||
|
* the sign of the random point R which is not included in the signature.
|
||||||
|
*
|
||||||
|
* Forgery of the same message isn't universally problematic, but in systems
|
||||||
|
* where message malleability or uniqueness of signatures is important this can
|
||||||
|
* cause issues. This forgery can be blocked by all verifiers forcing signers
|
||||||
|
* to use a normalized form.
|
||||||
|
*
|
||||||
|
* The lower-S form reduces the size of signatures slightly on average when
|
||||||
|
* variable length encodings (such as DER) are used and is cheap to verify,
|
||||||
|
* making it a good choice. Security of always using lower-S is assured because
|
||||||
|
* anyone can trivially modify a signature after the fact to enforce this
|
||||||
|
* property anyway.
|
||||||
|
*
|
||||||
|
* The lower S value is always between 0x1 and
|
||||||
|
* 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
|
||||||
|
* inclusive.
|
||||||
|
*
|
||||||
|
* No other forms of ECDSA malleability are known and none seem likely, but
|
||||||
|
* there is no formal proof that ECDSA, even with this additional restriction,
|
||||||
|
* is free of other malleability. Commonly used serialization schemes will also
|
||||||
|
* accept various non-unique encodings, so care should be taken when this
|
||||||
|
* property is required for an application.
|
||||||
|
*
|
||||||
|
* The secp256k1_ecdsa_sign function will by default create signatures in the
|
||||||
|
* lower-S form, and secp256k1_ecdsa_verify will not accept others. In case
|
||||||
|
* signatures come from a system that cannot enforce this property,
|
||||||
|
* secp256k1_ecdsa_signature_normalize must be called before verification.
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_ecdsa_signature_normalize(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_ecdsa_signature *sigout,
|
||||||
|
const secp256k1_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 secp256k1_nonce_function secp256k1_nonce_function_rfc6979;
|
||||||
|
|
||||||
|
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
|
||||||
|
SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default;
|
||||||
|
|
||||||
|
/** Create an ECDSA signature.
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
|
||||||
|
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
|
||||||
|
*
|
||||||
|
* The created signature is always in lower-S form. See
|
||||||
|
* secp256k1_ecdsa_signature_normalize for more details.
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_ecdsa_sign(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_ecdsa_signature *sig,
|
||||||
|
const unsigned char *msg32,
|
||||||
|
const unsigned char *seckey,
|
||||||
|
secp256k1_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.
|
||||||
|
*
|
||||||
|
* Returns: 1: secret key is valid
|
||||||
|
* 0: secret key is invalid
|
||||||
|
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||||
|
* In: seckey: pointer to a 32-byte secret key (cannot be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
const unsigned char *seckey
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||||
|
|
||||||
|
/** Compute the public key for a secret key.
|
||||||
|
*
|
||||||
|
* Returns: 1: secret was valid, public key stores
|
||||||
|
* 0: secret was invalid, try again
|
||||||
|
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
|
||||||
|
* Out: pubkey: pointer to the created public key (cannot be NULL)
|
||||||
|
* In: seckey: pointer to a 32-byte private key (cannot be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_pubkey *pubkey,
|
||||||
|
const unsigned char *seckey
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Tweak a private key by adding tweak to it.
|
||||||
|
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
|
||||||
|
* uniformly random 32-byte arrays, or if the resulting private key
|
||||||
|
* would be invalid (only when the tweak is the complement of the
|
||||||
|
* private key). 1 otherwise.
|
||||||
|
* Args: ctx: pointer to a context object (cannot be NULL).
|
||||||
|
* In/Out: seckey: pointer to a 32-byte private key.
|
||||||
|
* In: tweak: pointer to a 32-byte tweak.
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *seckey,
|
||||||
|
const unsigned char *tweak
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Tweak a public key by adding tweak times the generator to it.
|
||||||
|
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
|
||||||
|
* uniformly random 32-byte arrays, or if the resulting public key
|
||||||
|
* would be invalid (only when the tweak is the complement of the
|
||||||
|
* corresponding private key). 1 otherwise.
|
||||||
|
* Args: ctx: pointer to a context object initialized for validation
|
||||||
|
* (cannot be NULL).
|
||||||
|
* In/Out: pubkey: pointer to a public key object.
|
||||||
|
* In: tweak: pointer to a 32-byte tweak.
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_pubkey *pubkey,
|
||||||
|
const unsigned char *tweak
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Tweak a private key by multiplying it by a tweak.
|
||||||
|
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
|
||||||
|
* uniformly random 32-byte arrays, or equal to zero. 1 otherwise.
|
||||||
|
* Args: ctx: pointer to a context object (cannot be NULL).
|
||||||
|
* In/Out: seckey: pointer to a 32-byte private key.
|
||||||
|
* In: tweak: pointer to a 32-byte tweak.
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *seckey,
|
||||||
|
const unsigned char *tweak
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Tweak a public key by multiplying it by a tweak value.
|
||||||
|
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
|
||||||
|
* uniformly random 32-byte arrays, or equal to zero. 1 otherwise.
|
||||||
|
* Args: ctx: pointer to a context object initialized for validation
|
||||||
|
* (cannot be NULL).
|
||||||
|
* In/Out: pubkey: pointer to a public key obkect.
|
||||||
|
* In: tweak: pointer to a 32-byte tweak.
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_pubkey *pubkey,
|
||||||
|
const unsigned char *tweak
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Updates the context randomization.
|
||||||
|
* Returns: 1: randomization successfully updated
|
||||||
|
* 0: error
|
||||||
|
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||||
|
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state)
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
|
||||||
|
secp256k1_context* ctx,
|
||||||
|
const unsigned char *seed32
|
||||||
|
) SECP256K1_ARG_NONNULL(1);
|
||||||
|
|
||||||
|
/** Add a number of public keys together.
|
||||||
|
* Returns: 1: the sum of the public keys is valid.
|
||||||
|
* 0: the sum of the public keys is not valid.
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: out: pointer to a public key object for placing the resulting public key
|
||||||
|
* (cannot be NULL)
|
||||||
|
* In: ins: pointer to array of pointers to public keys (cannot be NULL)
|
||||||
|
* n: the number of public keys to add together (must be at least 1)
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_pubkey *out,
|
||||||
|
const secp256k1_pubkey * const * ins,
|
||||||
|
size_t n
|
||||||
|
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
31
secp256k1zkp/depend/secp256k1-zkp/include/secp256k1_ecdh.h
Normal file
31
secp256k1zkp/depend/secp256k1-zkp/include/secp256k1_ecdh.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef _SECP256K1_ECDH_
|
||||||
|
# define _SECP256K1_ECDH_
|
||||||
|
|
||||||
|
# include "secp256k1.h"
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/** Compute an EC Diffie-Hellman secret in constant time
|
||||||
|
* Returns: 1: exponentiation was successful
|
||||||
|
* 0: scalar was invalid (zero or overflow)
|
||||||
|
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||||
|
* Out: result: a 32-byte array which will be populated by an ECDH
|
||||||
|
* secret computed from the point and scalar
|
||||||
|
* In: pubkey: a pointer to a secp256k1_pubkey containing an
|
||||||
|
* initialized public key
|
||||||
|
* privkey: a 32-byte scalar with which to multiply the point
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *result,
|
||||||
|
const secp256k1_pubkey *pubkey,
|
||||||
|
const unsigned char *privkey
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
204
secp256k1zkp/depend/secp256k1-zkp/include/secp256k1_rangeproof.h
Normal file
204
secp256k1zkp/depend/secp256k1-zkp/include/secp256k1_rangeproof.h
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
#ifndef _SECP256K1_RANGEPROOF_
|
||||||
|
# define _SECP256K1_RANGEPROOF_
|
||||||
|
|
||||||
|
# include "secp256k1.h"
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/** Initialize a context for usage with Pedersen commitments. */
|
||||||
|
void secp256k1_pedersen_context_initialize(secp256k1_context* ctx);
|
||||||
|
|
||||||
|
/** Generate a pedersen commitment.
|
||||||
|
* Returns 1: commitment successfully created.
|
||||||
|
* 0: error
|
||||||
|
* 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.
|
||||||
|
* Out: commit: pointer to a 33-byte array for the commitment (cannot be NULL)
|
||||||
|
*
|
||||||
|
* Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA.
|
||||||
|
*/
|
||||||
|
SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *commit,
|
||||||
|
unsigned char *blind,
|
||||||
|
uint64_t value
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Computes the sum of multiple positive and negative blinding factors.
|
||||||
|
* Returns 1: sum successfully computed.
|
||||||
|
* 0: error
|
||||||
|
* 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.
|
||||||
|
* nneg: 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_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *blind_out,
|
||||||
|
const unsigned char * const *blinds,
|
||||||
|
int n,
|
||||||
|
int npositive
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Computes the sum of multiple positive and negative pedersen commitments
|
||||||
|
* Returns 1: sum successfully computed.
|
||||||
|
* In: ctx: pointer to a context object, initialized for Pedersen commitment (cannot be NULL)
|
||||||
|
* commits: pointer to pointers to 33-byte character arrays for the commitments. (cannot be NULL if pcnt is non-zero)
|
||||||
|
* pcnt: number of commitments pointed to by commits.
|
||||||
|
* ncommits: pointer to pointers to 33-byte character arrays for negative commitments. (cannot be NULL if ncnt is non-zero)
|
||||||
|
* ncnt: number of commitments pointed to by ncommits.
|
||||||
|
* Out: commit_out: pointer to a 33-byte array for the sum (cannot be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit_sum(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *commit_out,
|
||||||
|
const unsigned char * const *commits,
|
||||||
|
int pcnt,
|
||||||
|
const unsigned char * const *ncommits,
|
||||||
|
int ncnt
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
/** 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, initialized for Pedersen commitment (cannot be NULL)
|
||||||
|
* commits: pointer to pointers to 33-byte character arrays for the commitments. (cannot be NULL if pcnt is non-zero)
|
||||||
|
* pcnt: number of commitments pointed to by commits.
|
||||||
|
* ncommits: pointer to pointers to 33-byte character arrays for negative commitments. (cannot be NULL if ncnt is non-zero)
|
||||||
|
* ncnt: number of commitments pointed to by ncommits.
|
||||||
|
* excess: signed 64bit amount to add to the total to bring it to zero, can be negative.
|
||||||
|
*
|
||||||
|
* This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) - excess*H == 0.
|
||||||
|
*
|
||||||
|
* A pedersen commitment is xG + vH where G and H 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 both their blinding factors and
|
||||||
|
* values must sum to zero.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
const unsigned char * const *commits,
|
||||||
|
int pcnt,
|
||||||
|
const unsigned char * const *ncommits,
|
||||||
|
int ncnt,
|
||||||
|
int64_t excess
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
/** Initialize a context for usage with Pedersen commitments. */
|
||||||
|
void secp256k1_rangeproof_context_initialize(secp256k1_context* ctx);
|
||||||
|
|
||||||
|
/** 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 33-byte commitment being proved. (cannot be NULL)
|
||||||
|
* proof: pointer to character array with the proof. (cannot be NULL)
|
||||||
|
* plen: length of proof in bytes.
|
||||||
|
* 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_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
uint64_t *min_value,
|
||||||
|
uint64_t *max_value,
|
||||||
|
const unsigned char *commit,
|
||||||
|
const unsigned char *proof,
|
||||||
|
int plen
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||||
|
|
||||||
|
/** 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 33-byte 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)
|
||||||
|
* 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.
|
||||||
|
* 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_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *blind_out,
|
||||||
|
uint64_t *value_out,
|
||||||
|
unsigned char *message_out,
|
||||||
|
int *outlen,
|
||||||
|
const unsigned char *nonce,
|
||||||
|
uint64_t *min_value,
|
||||||
|
uint64_t *max_value,
|
||||||
|
const unsigned char *commit,
|
||||||
|
const unsigned char *proof,
|
||||||
|
int plen
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(9) SECP256K1_ARG_NONNULL(10);
|
||||||
|
|
||||||
|
/** 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: 33-byte array with the commitment being proved.
|
||||||
|
* blind: 32-byte blinding factor used by commit.
|
||||||
|
* 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.
|
||||||
|
* 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_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *proof,
|
||||||
|
int *plen,
|
||||||
|
uint64_t min_value,
|
||||||
|
const unsigned char *commit,
|
||||||
|
const unsigned char *blind,
|
||||||
|
const unsigned char *nonce,
|
||||||
|
int exp,
|
||||||
|
int min_bits,
|
||||||
|
uint64_t value
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7);
|
||||||
|
|
||||||
|
/** 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_WARN_UNUSED_RESULT int secp256k1_rangeproof_info(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
int *exp,
|
||||||
|
int *mantissa,
|
||||||
|
uint64_t *min_value,
|
||||||
|
uint64_t *max_value,
|
||||||
|
const unsigned char *proof,
|
||||||
|
int plen
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
110
secp256k1zkp/depend/secp256k1-zkp/include/secp256k1_recovery.h
Normal file
110
secp256k1zkp/depend/secp256k1-zkp/include/secp256k1_recovery.h
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
#ifndef _SECP256K1_RECOVERY_
|
||||||
|
# define _SECP256K1_RECOVERY_
|
||||||
|
|
||||||
|
# include "secp256k1.h"
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/** Opaque data structured 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 secp256k1_ecdsa_signature_serialize_* and
|
||||||
|
* secp256k1_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 {
|
||||||
|
unsigned char data[65];
|
||||||
|
} secp256k1_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
|
||||||
|
* recid: the recovery id (0, 1, 2 or 3)
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_ecdsa_recoverable_signature* sig,
|
||||||
|
const unsigned char *input64,
|
||||||
|
int recid
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Convert a recoverable signature into a normal signature.
|
||||||
|
*
|
||||||
|
* Returns: 1
|
||||||
|
* Out: sig: a pointer to a normal signature (cannot be NULL).
|
||||||
|
* In: sigin: a pointer to a recoverable signature (cannot be NULL).
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_ecdsa_signature* sig,
|
||||||
|
const secp256k1_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 (cannot be NULL)
|
||||||
|
* recid: a pointer to an integer to hold the recovery id (can be NULL).
|
||||||
|
* In: sig: a pointer to an initialized signature object (cannot be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *output64,
|
||||||
|
int *recid,
|
||||||
|
const secp256k1_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 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)
|
||||||
|
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
|
||||||
|
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_ecdsa_sign_recoverable(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_ecdsa_recoverable_signature *sig,
|
||||||
|
const unsigned char *msg32,
|
||||||
|
const unsigned char *seckey,
|
||||||
|
secp256k1_nonce_function noncefp,
|
||||||
|
const void *ndata
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
/** Recover an ECDSA public key from a signature.
|
||||||
|
*
|
||||||
|
* Returns: 1: public key successfully recovered (which guarantees a correct signature).
|
||||||
|
* 0: otherwise.
|
||||||
|
* Args: ctx: pointer to a context object, initialized for verification (cannot be NULL)
|
||||||
|
* Out: pubkey: pointer to the recovered public key (cannot be NULL)
|
||||||
|
* In: sig: pointer to initialized signature that supports pubkey recovery (cannot be NULL)
|
||||||
|
* msg32: the 32-byte message hash assumed to be signed (cannot be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_pubkey *pubkey,
|
||||||
|
const secp256k1_ecdsa_recoverable_signature *sig,
|
||||||
|
const unsigned char *msg32
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
173
secp256k1zkp/depend/secp256k1-zkp/include/secp256k1_schnorr.h
Normal file
173
secp256k1zkp/depend/secp256k1-zkp/include/secp256k1_schnorr.h
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
#ifndef _SECP256K1_SCHNORR_
|
||||||
|
# define _SECP256K1_SCHNORR_
|
||||||
|
|
||||||
|
# include "secp256k1.h"
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/** Create a signature using a custom EC-Schnorr-SHA256 construction. It
|
||||||
|
* produces non-malleable 64-byte signatures which support public key recovery
|
||||||
|
* batch validation, and multiparty signing.
|
||||||
|
* 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: sig64: pointer to a 64-byte 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)
|
||||||
|
* noncefp:pointer to a nonce generation function. If NULL,
|
||||||
|
* secp256k1_nonce_function_default is used
|
||||||
|
* ndata: pointer to arbitrary data used by the nonce generation
|
||||||
|
* function (can be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_schnorr_sign(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *sig64,
|
||||||
|
const unsigned char *msg32,
|
||||||
|
const unsigned char *seckey,
|
||||||
|
secp256k1_nonce_function noncefp,
|
||||||
|
const void *ndata
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
/** Verify a signature created by secp256k1_schnorr_sign.
|
||||||
|
* Returns: 1: correct signature
|
||||||
|
* 0: incorrect signature
|
||||||
|
* Args: ctx: a secp256k1 context object, initialized for verification.
|
||||||
|
* In: sig64: the 64-byte signature being verified (cannot be NULL)
|
||||||
|
* msg32: the 32-byte message hash being verified (cannot be NULL)
|
||||||
|
* pubkey: the public key to verify with (cannot be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
const unsigned char *sig64,
|
||||||
|
const unsigned char *msg32,
|
||||||
|
const secp256k1_pubkey *pubkey
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
/** Recover an EC public key from a Schnorr signature created using
|
||||||
|
* secp256k1_schnorr_sign.
|
||||||
|
* Returns: 1: public key successfully recovered (which guarantees a correct
|
||||||
|
* signature).
|
||||||
|
* 0: otherwise.
|
||||||
|
* Args: ctx: pointer to a context object, initialized for
|
||||||
|
* verification (cannot be NULL)
|
||||||
|
* Out: pubkey: pointer to a pubkey to set to the recovered public key
|
||||||
|
* (cannot be NULL).
|
||||||
|
* In: sig64: signature as 64 byte array (cannot be NULL)
|
||||||
|
* msg32: the 32-byte message hash assumed to be signed (cannot
|
||||||
|
* be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_schnorr_recover(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_pubkey *pubkey,
|
||||||
|
const unsigned char *sig64,
|
||||||
|
const unsigned char *msg32
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
/** Generate a nonce pair deterministically for use with
|
||||||
|
* secp256k1_schnorr_partial_sign.
|
||||||
|
* Returns: 1: valid nonce pair was generated.
|
||||||
|
* 0: otherwise (nonce generation function failed)
|
||||||
|
* Args: ctx: pointer to a context object, initialized for signing
|
||||||
|
* (cannot be NULL)
|
||||||
|
* Out: pubnonce: public side of the nonce (cannot be NULL)
|
||||||
|
* privnonce32: private side of the nonce (32 byte) (cannot be NULL)
|
||||||
|
* In: msg32: the 32-byte message hash assumed to be signed (cannot
|
||||||
|
* be NULL)
|
||||||
|
* sec32: the 32-byte private key (cannot be NULL)
|
||||||
|
* noncefp: pointer to a nonce generation function. If NULL,
|
||||||
|
* secp256k1_nonce_function_default is used
|
||||||
|
* noncedata: pointer to arbitrary data used by the nonce generation
|
||||||
|
* function (can be NULL)
|
||||||
|
*
|
||||||
|
* Do not use the output as a private/public key pair for signing/validation.
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_schnorr_generate_nonce_pair(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
secp256k1_pubkey *pubnonce,
|
||||||
|
unsigned char *privnonce32,
|
||||||
|
const unsigned char *msg32,
|
||||||
|
const unsigned char *sec32,
|
||||||
|
secp256k1_nonce_function noncefp,
|
||||||
|
const void* noncedata
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Produce a partial Schnorr signature, which can be combined using
|
||||||
|
* secp256k1_schnorr_partial_combine, to end up with a full signature that is
|
||||||
|
* verifiable using secp256k1_schnorr_verify.
|
||||||
|
* Returns: 1: signature created successfully.
|
||||||
|
* 0: no valid signature exists with this combination of keys, nonces
|
||||||
|
* and message (chance around 1 in 2^128)
|
||||||
|
* -1: invalid private key, nonce, or public nonces.
|
||||||
|
* Args: ctx: pointer to context object, initialized for signing (cannot
|
||||||
|
* be NULL)
|
||||||
|
* Out: sig64: pointer to 64-byte array to put partial signature in
|
||||||
|
* In: msg32: pointer to 32-byte message to sign
|
||||||
|
* sec32: pointer to 32-byte private key
|
||||||
|
* pubnonce_others: pointer to pubkey containing the sum of the other's
|
||||||
|
* nonces (see secp256k1_ec_pubkey_combine)
|
||||||
|
* secnonce32: pointer to 32-byte array containing our nonce
|
||||||
|
*
|
||||||
|
* The intended procedure for creating a multiparty signature is:
|
||||||
|
* - Each signer S[i] with private key x[i] and public key Q[i] runs
|
||||||
|
* secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of
|
||||||
|
* private/public nonces.
|
||||||
|
* - All signers communicate their public nonces to each other (revealing your
|
||||||
|
* private nonce can lead to discovery of your private key, so it should be
|
||||||
|
* considered secret).
|
||||||
|
* - All signers combine all the public nonces they received (excluding their
|
||||||
|
* own) using secp256k1_ec_pubkey_combine to obtain an
|
||||||
|
* Rall[i] = sum(R[0..i-1,i+1..n]).
|
||||||
|
* - All signers produce a partial signature using
|
||||||
|
* secp256k1_schnorr_partial_sign, passing in their own private key x[i],
|
||||||
|
* their own private nonce k[i], and the sum of the others' public nonces
|
||||||
|
* Rall[i].
|
||||||
|
* - All signers communicate their partial signatures to each other.
|
||||||
|
* - Someone combines all partial signatures using
|
||||||
|
* secp256k1_schnorr_partial_combine, to obtain a full signature.
|
||||||
|
* - The resulting signature is validatable using secp256k1_schnorr_verify, with
|
||||||
|
* public key equal to the result of secp256k1_ec_pubkey_combine of the
|
||||||
|
* signers' public keys (sum(Q[0..n])).
|
||||||
|
*
|
||||||
|
* Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine
|
||||||
|
* function take their arguments in any order, and it is possible to
|
||||||
|
* pre-combine several inputs already with one call, and add more inputs later
|
||||||
|
* by calling the function again (they are commutative and associative).
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *sig64,
|
||||||
|
const unsigned char *msg32,
|
||||||
|
const unsigned char *sec32,
|
||||||
|
const secp256k1_pubkey *pubnonce_others,
|
||||||
|
const unsigned char *secnonce32
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
|
||||||
|
|
||||||
|
/** Combine multiple Schnorr partial signatures.
|
||||||
|
* Returns: 1: the passed signatures were successfully combined.
|
||||||
|
* 0: the resulting signature is not valid (chance of 1 in 2^256)
|
||||||
|
* -1: some inputs were invalid, or the signatures were not created
|
||||||
|
* using the same set of nonces
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: sig64: pointer to a 64-byte array to place the combined signature
|
||||||
|
* (cannot be NULL)
|
||||||
|
* In: sig64sin: pointer to an array of n pointers to 64-byte input
|
||||||
|
* signatures
|
||||||
|
* n: the number of signatures to combine (at least 1)
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_combine(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *sig64,
|
||||||
|
const unsigned char * const * sig64sin,
|
||||||
|
size_t n
|
||||||
|
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
13
secp256k1zkp/depend/secp256k1-zkp/libsecp256k1.pc.in
Normal file
13
secp256k1zkp/depend/secp256k1-zkp/libsecp256k1.pc.in
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
prefix=@prefix@
|
||||||
|
exec_prefix=@exec_prefix@
|
||||||
|
libdir=@libdir@
|
||||||
|
includedir=@includedir@
|
||||||
|
|
||||||
|
Name: libsecp256k1
|
||||||
|
Description: Optimized C library for EC operations on curve secp256k1
|
||||||
|
URL: https://github.com/bitcoin-core/secp256k1
|
||||||
|
Version: @PACKAGE_VERSION@
|
||||||
|
Cflags: -I${includedir}
|
||||||
|
Libs.private: @SECP_LIBS@
|
||||||
|
Libs: -L${libdir} -lsecp256k1
|
||||||
|
|
0
secp256k1zkp/depend/secp256k1-zkp/obj/.gitignore
vendored
Normal file
0
secp256k1zkp/depend/secp256k1-zkp/obj/.gitignore
vendored
Normal file
322
secp256k1zkp/depend/secp256k1-zkp/sage/group_prover.sage
Normal file
322
secp256k1zkp/depend/secp256k1-zkp/sage/group_prover.sage
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
# This code supports verifying group implementations which have branches
|
||||||
|
# or conditional statements (like cmovs), by allowing each execution path
|
||||||
|
# to independently set assumptions on input or intermediary variables.
|
||||||
|
#
|
||||||
|
# The general approach is:
|
||||||
|
# * A constraint is a tuple of two sets of of symbolic expressions:
|
||||||
|
# the first of which are required to evaluate to zero, the second of which
|
||||||
|
# are required to evaluate to nonzero.
|
||||||
|
# - A constraint is said to be conflicting if any of its nonzero expressions
|
||||||
|
# is in the ideal with basis the zero expressions (in other words: when the
|
||||||
|
# zero expressions imply that one of the nonzero expressions are zero).
|
||||||
|
# * There is a list of laws that describe the intended behaviour, including
|
||||||
|
# laws for addition and doubling. Each law is called with the symbolic point
|
||||||
|
# coordinates as arguments, and returns:
|
||||||
|
# - A constraint describing the assumptions under which it is applicable,
|
||||||
|
# called "assumeLaw"
|
||||||
|
# - A constraint describing the requirements of the law, called "require"
|
||||||
|
# * Implementations are transliterated into functions that operate as well on
|
||||||
|
# algebraic input points, and are called once per combination of branches
|
||||||
|
# exectured. Each execution returns:
|
||||||
|
# - A constraint describing the assumptions this implementation requires
|
||||||
|
# (such as Z1=1), called "assumeFormula"
|
||||||
|
# - A constraint describing the assumptions this specific branch requires,
|
||||||
|
# but which is by construction guaranteed to cover the entire space by
|
||||||
|
# merging the results from all branches, called "assumeBranch"
|
||||||
|
# - The result of the computation
|
||||||
|
# * All combinations of laws with implementation branches are tried, and:
|
||||||
|
# - If the combination of assumeLaw, assumeFormula, and assumeBranch results
|
||||||
|
# in a conflict, it means this law does not apply to this branch, and it is
|
||||||
|
# skipped.
|
||||||
|
# - For others, we try to prove the require constraints hold, assuming the
|
||||||
|
# information in assumeLaw + assumeFormula + assumeBranch, and if this does
|
||||||
|
# not succeed, we fail.
|
||||||
|
# + To prove an expression is zero, we check whether it belongs to the
|
||||||
|
# ideal with the assumed zero expressions as basis. This test is exact.
|
||||||
|
# + To prove an expression is nonzero, we check whether each of its
|
||||||
|
# factors is contained in the set of nonzero assumptions' factors.
|
||||||
|
# This test is not exact, so various combinations of original and
|
||||||
|
# reduced expressions' factors are tried.
|
||||||
|
# - If we succeed, we print out the assumptions from assumeFormula that
|
||||||
|
# weren't implied by assumeLaw already. Those from assumeBranch are skipped,
|
||||||
|
# as we assume that all constraints in it are complementary with each other.
|
||||||
|
#
|
||||||
|
# Based on the sage verification scripts used in the Explicit-Formulas Database
|
||||||
|
# by Tanja Lange and others, see http://hyperelliptic.org/EFD
|
||||||
|
|
||||||
|
class fastfrac:
|
||||||
|
"""Fractions over rings."""
|
||||||
|
|
||||||
|
def __init__(self,R,top,bot=1):
|
||||||
|
"""Construct a fractional, given a ring, a numerator, and denominator."""
|
||||||
|
self.R = R
|
||||||
|
if parent(top) == ZZ or parent(top) == R:
|
||||||
|
self.top = R(top)
|
||||||
|
self.bot = R(bot)
|
||||||
|
elif top.__class__ == fastfrac:
|
||||||
|
self.top = top.top
|
||||||
|
self.bot = top.bot * bot
|
||||||
|
else:
|
||||||
|
self.top = R(numerator(top))
|
||||||
|
self.bot = R(denominator(top)) * bot
|
||||||
|
|
||||||
|
def iszero(self,I):
|
||||||
|
"""Return whether this fraction is zero given an ideal."""
|
||||||
|
return self.top in I and self.bot not in I
|
||||||
|
|
||||||
|
def reduce(self,assumeZero):
|
||||||
|
zero = self.R.ideal(map(numerator, assumeZero))
|
||||||
|
return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot))
|
||||||
|
|
||||||
|
def __add__(self,other):
|
||||||
|
"""Add two fractions."""
|
||||||
|
if parent(other) == ZZ:
|
||||||
|
return fastfrac(self.R,self.top + self.bot * other,self.bot)
|
||||||
|
if other.__class__ == fastfrac:
|
||||||
|
return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot)
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __sub__(self,other):
|
||||||
|
"""Subtract two fractions."""
|
||||||
|
if parent(other) == ZZ:
|
||||||
|
return fastfrac(self.R,self.top - self.bot * other,self.bot)
|
||||||
|
if other.__class__ == fastfrac:
|
||||||
|
return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot)
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __neg__(self):
|
||||||
|
"""Return the negation of a fraction."""
|
||||||
|
return fastfrac(self.R,-self.top,self.bot)
|
||||||
|
|
||||||
|
def __mul__(self,other):
|
||||||
|
"""Multiply two fractions."""
|
||||||
|
if parent(other) == ZZ:
|
||||||
|
return fastfrac(self.R,self.top * other,self.bot)
|
||||||
|
if other.__class__ == fastfrac:
|
||||||
|
return fastfrac(self.R,self.top * other.top,self.bot * other.bot)
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __rmul__(self,other):
|
||||||
|
"""Multiply something else with a fraction."""
|
||||||
|
return self.__mul__(other)
|
||||||
|
|
||||||
|
def __div__(self,other):
|
||||||
|
"""Divide two fractions."""
|
||||||
|
if parent(other) == ZZ:
|
||||||
|
return fastfrac(self.R,self.top,self.bot * other)
|
||||||
|
if other.__class__ == fastfrac:
|
||||||
|
return fastfrac(self.R,self.top * other.bot,self.bot * other.top)
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __pow__(self,other):
|
||||||
|
"""Compute a power of a fraction."""
|
||||||
|
if parent(other) == ZZ:
|
||||||
|
if other < 0:
|
||||||
|
# Negative powers require flipping top and bottom
|
||||||
|
return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other))
|
||||||
|
else:
|
||||||
|
return fastfrac(self.R,self.top ^ other,self.bot ^ other)
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))"
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s" % self
|
||||||
|
|
||||||
|
def numerator(self):
|
||||||
|
return self.top
|
||||||
|
|
||||||
|
class constraints:
|
||||||
|
"""A set of constraints, consisting of zero and nonzero expressions.
|
||||||
|
|
||||||
|
Constraints can either be used to express knowledge or a requirement.
|
||||||
|
|
||||||
|
Both the fields zero and nonzero are maps from expressions to description
|
||||||
|
strings. The expressions that are the keys in zero are required to be zero,
|
||||||
|
and the expressions that are the keys in nonzero are required to be nonzero.
|
||||||
|
|
||||||
|
Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in
|
||||||
|
nonzero could be multiplied into a single key. This is often much less
|
||||||
|
efficient to work with though, so we keep them separate inside the
|
||||||
|
constraints. This allows higher-level code to do fast checks on the individual
|
||||||
|
nonzero elements, or combine them if needed for stronger checks.
|
||||||
|
|
||||||
|
We can't multiply the different zero elements, as it would suffice for one of
|
||||||
|
the factors to be zero, instead of all of them. Instead, the zero elements are
|
||||||
|
typically combined into an ideal first.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
if 'zero' in kwargs:
|
||||||
|
self.zero = dict(kwargs['zero'])
|
||||||
|
else:
|
||||||
|
self.zero = dict()
|
||||||
|
if 'nonzero' in kwargs:
|
||||||
|
self.nonzero = dict(kwargs['nonzero'])
|
||||||
|
else:
|
||||||
|
self.nonzero = dict()
|
||||||
|
|
||||||
|
def negate(self):
|
||||||
|
return constraints(zero=self.nonzero, nonzero=self.zero)
|
||||||
|
|
||||||
|
def __add__(self, other):
|
||||||
|
zero = self.zero.copy()
|
||||||
|
zero.update(other.zero)
|
||||||
|
nonzero = self.nonzero.copy()
|
||||||
|
nonzero.update(other.nonzero)
|
||||||
|
return constraints(zero=zero, nonzero=nonzero)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s" % self
|
||||||
|
|
||||||
|
|
||||||
|
def conflicts(R, con):
|
||||||
|
"""Check whether any of the passed non-zero assumptions is implied by the zero assumptions"""
|
||||||
|
zero = R.ideal(map(numerator, con.zero))
|
||||||
|
if 1 in zero:
|
||||||
|
return True
|
||||||
|
# First a cheap check whether any of the individual nonzero terms conflict on
|
||||||
|
# their own.
|
||||||
|
for nonzero in con.nonzero:
|
||||||
|
if nonzero.iszero(zero):
|
||||||
|
return True
|
||||||
|
# It can be the case that entries in the nonzero set do not individually
|
||||||
|
# conflict with the zero set, but their combination does. For example, knowing
|
||||||
|
# that either x or y is zero is equivalent to having x*y in the zero set.
|
||||||
|
# Having x or y individually in the nonzero set is not a conflict, but both
|
||||||
|
# simultaneously is, so that is the right thing to check for.
|
||||||
|
if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_nonzero_set(R, assume):
|
||||||
|
"""Calculate a simple set of nonzero expressions"""
|
||||||
|
zero = R.ideal(map(numerator, assume.zero))
|
||||||
|
nonzero = set()
|
||||||
|
for nz in map(numerator, assume.nonzero):
|
||||||
|
for (f,n) in nz.factor():
|
||||||
|
nonzero.add(f)
|
||||||
|
rnz = zero.reduce(nz)
|
||||||
|
for (f,n) in rnz.factor():
|
||||||
|
nonzero.add(f)
|
||||||
|
return nonzero
|
||||||
|
|
||||||
|
|
||||||
|
def prove_nonzero(R, exprs, assume):
|
||||||
|
"""Check whether an expression is provably nonzero, given assumptions"""
|
||||||
|
zero = R.ideal(map(numerator, assume.zero))
|
||||||
|
nonzero = get_nonzero_set(R, assume)
|
||||||
|
expl = set()
|
||||||
|
ok = True
|
||||||
|
for expr in exprs:
|
||||||
|
if numerator(expr) in zero:
|
||||||
|
return (False, [exprs[expr]])
|
||||||
|
allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1)
|
||||||
|
for (f, n) in allexprs.factor():
|
||||||
|
if f not in nonzero:
|
||||||
|
ok = False
|
||||||
|
if ok:
|
||||||
|
return (True, None)
|
||||||
|
ok = True
|
||||||
|
for (f, n) in zero.reduce(numerator(allexprs)).factor():
|
||||||
|
if f not in nonzero:
|
||||||
|
ok = False
|
||||||
|
if ok:
|
||||||
|
return (True, None)
|
||||||
|
ok = True
|
||||||
|
for expr in exprs:
|
||||||
|
for (f,n) in numerator(expr).factor():
|
||||||
|
if f not in nonzero:
|
||||||
|
ok = False
|
||||||
|
if ok:
|
||||||
|
return (True, None)
|
||||||
|
ok = True
|
||||||
|
for expr in exprs:
|
||||||
|
for (f,n) in zero.reduce(numerator(expr)).factor():
|
||||||
|
if f not in nonzero:
|
||||||
|
expl.add(exprs[expr])
|
||||||
|
if expl:
|
||||||
|
return (False, list(expl))
|
||||||
|
else:
|
||||||
|
return (True, None)
|
||||||
|
|
||||||
|
|
||||||
|
def prove_zero(R, exprs, assume):
|
||||||
|
"""Check whether all of the passed expressions are provably zero, given assumptions"""
|
||||||
|
r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume)
|
||||||
|
if not r:
|
||||||
|
return (False, map(lambda x: "Possibly zero denominator: %s" % x, e))
|
||||||
|
zero = R.ideal(map(numerator, assume.zero))
|
||||||
|
nonzero = prod(x for x in assume.nonzero)
|
||||||
|
expl = []
|
||||||
|
for expr in exprs:
|
||||||
|
if not expr.iszero(zero):
|
||||||
|
expl.append(exprs[expr])
|
||||||
|
if not expl:
|
||||||
|
return (True, None)
|
||||||
|
return (False, expl)
|
||||||
|
|
||||||
|
|
||||||
|
def describe_extra(R, assume, assumeExtra):
|
||||||
|
"""Describe what assumptions are added, given existing assumptions"""
|
||||||
|
zerox = assume.zero.copy()
|
||||||
|
zerox.update(assumeExtra.zero)
|
||||||
|
zero = R.ideal(map(numerator, assume.zero))
|
||||||
|
zeroextra = R.ideal(map(numerator, zerox))
|
||||||
|
nonzero = get_nonzero_set(R, assume)
|
||||||
|
ret = set()
|
||||||
|
# Iterate over the extra zero expressions
|
||||||
|
for base in assumeExtra.zero:
|
||||||
|
if base not in zero:
|
||||||
|
add = []
|
||||||
|
for (f, n) in numerator(base).factor():
|
||||||
|
if f not in nonzero:
|
||||||
|
add += ["%s" % f]
|
||||||
|
if add:
|
||||||
|
ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base])
|
||||||
|
# Iterate over the extra nonzero expressions
|
||||||
|
for nz in assumeExtra.nonzero:
|
||||||
|
nzr = zeroextra.reduce(numerator(nz))
|
||||||
|
if nzr not in zeroextra:
|
||||||
|
for (f,n) in nzr.factor():
|
||||||
|
if zeroextra.reduce(f) not in nonzero:
|
||||||
|
ret.add("%s != 0" % zeroextra.reduce(f))
|
||||||
|
return ", ".join(x for x in ret)
|
||||||
|
|
||||||
|
|
||||||
|
def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require):
|
||||||
|
"""Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions"""
|
||||||
|
assume = assumeLaw + assumeAssert + assumeBranch
|
||||||
|
|
||||||
|
if conflicts(R, assume):
|
||||||
|
# This formula does not apply
|
||||||
|
return None
|
||||||
|
|
||||||
|
describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert)
|
||||||
|
|
||||||
|
ok, msg = prove_zero(R, require.zero, assume)
|
||||||
|
if not ok:
|
||||||
|
return "FAIL, %s fails (assuming %s)" % (str(msg), describe)
|
||||||
|
|
||||||
|
res, expl = prove_nonzero(R, require.nonzero, assume)
|
||||||
|
if not res:
|
||||||
|
return "FAIL, %s fails (assuming %s)" % (str(expl), describe)
|
||||||
|
|
||||||
|
if describe != "":
|
||||||
|
return "OK (assuming %s)" % describe
|
||||||
|
else:
|
||||||
|
return "OK"
|
||||||
|
|
||||||
|
|
||||||
|
def concrete_verify(c):
|
||||||
|
for k in c.zero:
|
||||||
|
if k != 0:
|
||||||
|
return (False, c.zero[k])
|
||||||
|
for k in c.nonzero:
|
||||||
|
if k == 0:
|
||||||
|
return (False, c.nonzero[k])
|
||||||
|
return (True, None)
|
306
secp256k1zkp/depend/secp256k1-zkp/sage/secp256k1.sage
Normal file
306
secp256k1zkp/depend/secp256k1-zkp/sage/secp256k1.sage
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
# Test libsecp256k1' group operation implementations using prover.sage
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
load("group_prover.sage")
|
||||||
|
load("weierstrass_prover.sage")
|
||||||
|
|
||||||
|
def formula_secp256k1_gej_double_var(a):
|
||||||
|
"""libsecp256k1's secp256k1_gej_double_var, used by various addition functions"""
|
||||||
|
rz = a.Z * a.Y
|
||||||
|
rz = rz * 2
|
||||||
|
t1 = a.X^2
|
||||||
|
t1 = t1 * 3
|
||||||
|
t2 = t1^2
|
||||||
|
t3 = a.Y^2
|
||||||
|
t3 = t3 * 2
|
||||||
|
t4 = t3^2
|
||||||
|
t4 = t4 * 2
|
||||||
|
t3 = t3 * a.X
|
||||||
|
rx = t3
|
||||||
|
rx = rx * 4
|
||||||
|
rx = -rx
|
||||||
|
rx = rx + t2
|
||||||
|
t2 = -t2
|
||||||
|
t3 = t3 * 6
|
||||||
|
t3 = t3 + t2
|
||||||
|
ry = t1 * t3
|
||||||
|
t2 = -t4
|
||||||
|
ry = ry + t2
|
||||||
|
return jacobianpoint(rx, ry, rz)
|
||||||
|
|
||||||
|
def formula_secp256k1_gej_add_var(branch, a, b):
|
||||||
|
"""libsecp256k1's secp256k1_gej_add_var"""
|
||||||
|
if branch == 0:
|
||||||
|
return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b)
|
||||||
|
if branch == 1:
|
||||||
|
return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a)
|
||||||
|
z22 = b.Z^2
|
||||||
|
z12 = a.Z^2
|
||||||
|
u1 = a.X * z22
|
||||||
|
u2 = b.X * z12
|
||||||
|
s1 = a.Y * z22
|
||||||
|
s1 = s1 * b.Z
|
||||||
|
s2 = b.Y * z12
|
||||||
|
s2 = s2 * a.Z
|
||||||
|
h = -u1
|
||||||
|
h = h + u2
|
||||||
|
i = -s1
|
||||||
|
i = i + s2
|
||||||
|
if branch == 2:
|
||||||
|
r = formula_secp256k1_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
|
||||||
|
h2 = h^2
|
||||||
|
h3 = h2 * h
|
||||||
|
h = h * b.Z
|
||||||
|
rz = a.Z * h
|
||||||
|
t = u1 * h2
|
||||||
|
rx = t
|
||||||
|
rx = rx * 2
|
||||||
|
rx = rx + h3
|
||||||
|
rx = -rx
|
||||||
|
rx = rx + i2
|
||||||
|
ry = -rx
|
||||||
|
ry = ry + t
|
||||||
|
ry = ry * 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_secp256k1_gej_add_ge_var(branch, a, b):
|
||||||
|
"""libsecp256k1's secp256k1_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:
|
||||||
|
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a)
|
||||||
|
z12 = a.Z^2
|
||||||
|
u1 = a.X
|
||||||
|
u2 = b.X * z12
|
||||||
|
s1 = a.Y
|
||||||
|
s2 = b.Y * z12
|
||||||
|
s2 = s2 * a.Z
|
||||||
|
h = -u1
|
||||||
|
h = h + u2
|
||||||
|
i = -s1
|
||||||
|
i = i + s2
|
||||||
|
if (branch == 2):
|
||||||
|
r = formula_secp256k1_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
|
||||||
|
t = u1 * h2
|
||||||
|
rx = t
|
||||||
|
rx = rx * 2
|
||||||
|
rx = rx + h3
|
||||||
|
rx = -rx
|
||||||
|
rx = rx + i2
|
||||||
|
ry = -rx
|
||||||
|
ry = ry + t
|
||||||
|
ry = ry * 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_secp256k1_gej_add_zinv_var(branch, a, b):
|
||||||
|
"""libsecp256k1's secp256k1_gej_add_zinv_var"""
|
||||||
|
bzinv = b.Z^(-1)
|
||||||
|
if branch == 0:
|
||||||
|
return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a)
|
||||||
|
if branch == 1:
|
||||||
|
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))
|
||||||
|
azz = a.Z * bzinv
|
||||||
|
z12 = azz^2
|
||||||
|
u1 = a.X
|
||||||
|
u2 = b.X * z12
|
||||||
|
s1 = a.Y
|
||||||
|
s2 = b.Y * z12
|
||||||
|
s2 = s2 * azz
|
||||||
|
h = -u1
|
||||||
|
h = h + u2
|
||||||
|
i = -s1
|
||||||
|
i = i + s2
|
||||||
|
if branch == 2:
|
||||||
|
r = formula_secp256k1_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
|
||||||
|
h2 = h^2
|
||||||
|
h3 = h * h2
|
||||||
|
rz = a.Z
|
||||||
|
rz = rz * h
|
||||||
|
t = u1 * h2
|
||||||
|
rx = t
|
||||||
|
rx = rx * 2
|
||||||
|
rx = rx + h3
|
||||||
|
rx = -rx
|
||||||
|
rx = rx + i2
|
||||||
|
ry = -rx
|
||||||
|
ry = ry + t
|
||||||
|
ry = ry * 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_secp256k1_gej_add_ge(branch, a, b):
|
||||||
|
"""libsecp256k1's secp256k1_gej_add_ge"""
|
||||||
|
zeroes = {}
|
||||||
|
nonzeroes = {}
|
||||||
|
a_infinity = False
|
||||||
|
if (branch & 4) != 0:
|
||||||
|
nonzeroes.update({a.Infinity : 'a_infinite'})
|
||||||
|
a_infinity = True
|
||||||
|
else:
|
||||||
|
zeroes.update({a.Infinity : 'a_finite'})
|
||||||
|
zz = a.Z^2
|
||||||
|
u1 = a.X
|
||||||
|
u2 = b.X * zz
|
||||||
|
s1 = a.Y
|
||||||
|
s2 = b.Y * zz
|
||||||
|
s2 = s2 * a.Z
|
||||||
|
t = u1
|
||||||
|
t = t + u2
|
||||||
|
m = s1
|
||||||
|
m = m + s2
|
||||||
|
rr = t^2
|
||||||
|
m_alt = -u2
|
||||||
|
tt = u1 * m_alt
|
||||||
|
rr = rr + tt
|
||||||
|
degenerate = (branch & 3) == 3
|
||||||
|
if (branch & 1) != 0:
|
||||||
|
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
|
||||||
|
if not degenerate:
|
||||||
|
rr_alt = rr
|
||||||
|
m_alt = m
|
||||||
|
n = m_alt^2
|
||||||
|
q = n * t
|
||||||
|
n = n^2
|
||||||
|
if degenerate:
|
||||||
|
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'})
|
||||||
|
rz = rz * 2
|
||||||
|
q = -q
|
||||||
|
t = t + q
|
||||||
|
rx = t
|
||||||
|
t = t * 2
|
||||||
|
t = t + q
|
||||||
|
t = t * rr_alt
|
||||||
|
t = t + n
|
||||||
|
ry = -t
|
||||||
|
rx = rx * 4
|
||||||
|
ry = ry * 4
|
||||||
|
if a_infinity:
|
||||||
|
rx = b.X
|
||||||
|
ry = b.Y
|
||||||
|
rz = 1
|
||||||
|
if infinity:
|
||||||
|
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity())
|
||||||
|
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz))
|
||||||
|
|
||||||
|
def formula_secp256k1_gej_add_ge_old(branch, a, b):
|
||||||
|
"""libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx"""
|
||||||
|
a_infinity = (branch & 1) != 0
|
||||||
|
zero = {}
|
||||||
|
nonzero = {}
|
||||||
|
if a_infinity:
|
||||||
|
nonzero.update({a.Infinity : 'a_infinite'})
|
||||||
|
else:
|
||||||
|
zero.update({a.Infinity : 'a_finite'})
|
||||||
|
zz = a.Z^2
|
||||||
|
u1 = a.X
|
||||||
|
u2 = b.X * zz
|
||||||
|
s1 = a.Y
|
||||||
|
s2 = b.Y * zz
|
||||||
|
s2 = s2 * a.Z
|
||||||
|
z = a.Z
|
||||||
|
t = u1
|
||||||
|
t = t + u2
|
||||||
|
m = s1
|
||||||
|
m = m + s2
|
||||||
|
n = m^2
|
||||||
|
q = n * t
|
||||||
|
n = n^2
|
||||||
|
rr = t^2
|
||||||
|
t = u1 * u2
|
||||||
|
t = -t
|
||||||
|
rr = rr + t
|
||||||
|
t = rr^2
|
||||||
|
rz = m * z
|
||||||
|
infinity = False
|
||||||
|
if (branch & 2) != 0:
|
||||||
|
if not a_infinity:
|
||||||
|
infinity = True
|
||||||
|
else:
|
||||||
|
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity())
|
||||||
|
zero.update({rz : 'r.z=0'})
|
||||||
|
else:
|
||||||
|
nonzero.update({rz : 'r.z!=0'})
|
||||||
|
rz = rz * (0 if a_infinity else 2)
|
||||||
|
rx = t
|
||||||
|
q = -q
|
||||||
|
rx = rx + q
|
||||||
|
q = q * 3
|
||||||
|
t = t * 2
|
||||||
|
t = t + q
|
||||||
|
t = t * rr
|
||||||
|
t = t + n
|
||||||
|
ry = -t
|
||||||
|
rx = rx * (0 if a_infinity else 4)
|
||||||
|
ry = ry * (0 if a_infinity else 4)
|
||||||
|
t = b.X
|
||||||
|
t = t * (1 if a_infinity else 0)
|
||||||
|
rx = rx + t
|
||||||
|
t = b.Y
|
||||||
|
t = t * (1 if a_infinity else 0)
|
||||||
|
ry = ry + t
|
||||||
|
t = (1 if a_infinity else 0)
|
||||||
|
rz = rz + t
|
||||||
|
if infinity:
|
||||||
|
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity())
|
||||||
|
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var)
|
||||||
|
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var)
|
||||||
|
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)
|
||||||
|
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge)
|
||||||
|
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old)
|
||||||
|
|
||||||
|
if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive":
|
||||||
|
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43)
|
||||||
|
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)
|
||||||
|
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)
|
||||||
|
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43)
|
||||||
|
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43)
|
264
secp256k1zkp/depend/secp256k1-zkp/sage/weierstrass_prover.sage
Normal file
264
secp256k1zkp/depend/secp256k1-zkp/sage/weierstrass_prover.sage
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
# Prover implementation for Weierstrass curves of the form
|
||||||
|
# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws
|
||||||
|
# operating on affine and Jacobian coordinates, including the point at infinity
|
||||||
|
# represented by a 4th variable in coordinates.
|
||||||
|
|
||||||
|
load("group_prover.sage")
|
||||||
|
|
||||||
|
|
||||||
|
class affinepoint:
|
||||||
|
def __init__(self, x, y, infinity=0):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.infinity = infinity
|
||||||
|
def __str__(self):
|
||||||
|
return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity)
|
||||||
|
|
||||||
|
|
||||||
|
class jacobianpoint:
|
||||||
|
def __init__(self, x, y, z, infinity=0):
|
||||||
|
self.X = x
|
||||||
|
self.Y = y
|
||||||
|
self.Z = z
|
||||||
|
self.Infinity = infinity
|
||||||
|
def __str__(self):
|
||||||
|
return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity)
|
||||||
|
|
||||||
|
|
||||||
|
def point_at_infinity():
|
||||||
|
return jacobianpoint(1, 1, 1, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def negate(p):
|
||||||
|
if p.__class__ == affinepoint:
|
||||||
|
return affinepoint(p.x, -p.y)
|
||||||
|
if p.__class__ == jacobianpoint:
|
||||||
|
return jacobianpoint(p.X, -p.Y, p.Z)
|
||||||
|
assert(False)
|
||||||
|
|
||||||
|
|
||||||
|
def on_weierstrass_curve(A, B, p):
|
||||||
|
"""Return a set of zero-expressions for an affine point to be on the curve"""
|
||||||
|
return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'})
|
||||||
|
|
||||||
|
|
||||||
|
def tangential_to_weierstrass_curve(A, B, p12, p3):
|
||||||
|
"""Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)"""
|
||||||
|
return constraints(zero={
|
||||||
|
(p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve'
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def colinear(p1, p2, p3):
|
||||||
|
"""Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear"""
|
||||||
|
return constraints(zero={
|
||||||
|
(p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1',
|
||||||
|
(p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2',
|
||||||
|
(p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3'
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def good_affine_point(p):
|
||||||
|
return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'})
|
||||||
|
|
||||||
|
|
||||||
|
def good_jacobian_point(p):
|
||||||
|
return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'})
|
||||||
|
|
||||||
|
|
||||||
|
def good_point(p):
|
||||||
|
return constraints(nonzero={p.Z^6 : 'nonzero_X'})
|
||||||
|
|
||||||
|
|
||||||
|
def finite(p, *affine_fns):
|
||||||
|
con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'})
|
||||||
|
if p.Z != 0:
|
||||||
|
return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con)
|
||||||
|
else:
|
||||||
|
return con
|
||||||
|
|
||||||
|
def infinite(p):
|
||||||
|
return constraints(nonzero={p.Infinity : 'infinite_point'})
|
||||||
|
|
||||||
|
|
||||||
|
def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC):
|
||||||
|
"""Check whether the passed set of coordinates is a valid Jacobian add, given assumptions"""
|
||||||
|
assumeLaw = (good_affine_point(pa) +
|
||||||
|
good_affine_point(pb) +
|
||||||
|
good_jacobian_point(pA) +
|
||||||
|
good_jacobian_point(pB) +
|
||||||
|
on_weierstrass_curve(A, B, pa) +
|
||||||
|
on_weierstrass_curve(A, B, pb) +
|
||||||
|
finite(pA) +
|
||||||
|
finite(pB) +
|
||||||
|
constraints(nonzero={pa.x - pb.x : 'different_x'}))
|
||||||
|
require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) +
|
||||||
|
colinear(pa, pb, negate(pc))))
|
||||||
|
return (assumeLaw, require)
|
||||||
|
|
||||||
|
|
||||||
|
def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC):
|
||||||
|
"""Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions"""
|
||||||
|
assumeLaw = (good_affine_point(pa) +
|
||||||
|
good_affine_point(pb) +
|
||||||
|
good_jacobian_point(pA) +
|
||||||
|
good_jacobian_point(pB) +
|
||||||
|
on_weierstrass_curve(A, B, pa) +
|
||||||
|
on_weierstrass_curve(A, B, pb) +
|
||||||
|
finite(pA) +
|
||||||
|
finite(pB) +
|
||||||
|
constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'}))
|
||||||
|
require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) +
|
||||||
|
tangential_to_weierstrass_curve(A, B, pa, negate(pc))))
|
||||||
|
return (assumeLaw, require)
|
||||||
|
|
||||||
|
|
||||||
|
def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC):
|
||||||
|
assumeLaw = (good_affine_point(pa) +
|
||||||
|
good_affine_point(pb) +
|
||||||
|
good_jacobian_point(pA) +
|
||||||
|
good_jacobian_point(pB) +
|
||||||
|
on_weierstrass_curve(A, B, pa) +
|
||||||
|
on_weierstrass_curve(A, B, pb) +
|
||||||
|
finite(pA) +
|
||||||
|
finite(pB) +
|
||||||
|
constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'}))
|
||||||
|
require = infinite(pC)
|
||||||
|
return (assumeLaw, require)
|
||||||
|
|
||||||
|
|
||||||
|
def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC):
|
||||||
|
assumeLaw = (good_affine_point(pa) +
|
||||||
|
good_affine_point(pb) +
|
||||||
|
good_jacobian_point(pA) +
|
||||||
|
good_jacobian_point(pB) +
|
||||||
|
on_weierstrass_curve(A, B, pb) +
|
||||||
|
infinite(pA) +
|
||||||
|
finite(pB))
|
||||||
|
require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'}))
|
||||||
|
return (assumeLaw, require)
|
||||||
|
|
||||||
|
|
||||||
|
def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC):
|
||||||
|
assumeLaw = (good_affine_point(pa) +
|
||||||
|
good_affine_point(pb) +
|
||||||
|
good_jacobian_point(pA) +
|
||||||
|
good_jacobian_point(pB) +
|
||||||
|
on_weierstrass_curve(A, B, pa) +
|
||||||
|
infinite(pB) +
|
||||||
|
finite(pA))
|
||||||
|
require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'}))
|
||||||
|
return (assumeLaw, require)
|
||||||
|
|
||||||
|
|
||||||
|
def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC):
|
||||||
|
assumeLaw = (good_affine_point(pa) +
|
||||||
|
good_affine_point(pb) +
|
||||||
|
good_jacobian_point(pA) +
|
||||||
|
good_jacobian_point(pB) +
|
||||||
|
infinite(pA) +
|
||||||
|
infinite(pB))
|
||||||
|
require = infinite(pC)
|
||||||
|
return (assumeLaw, require)
|
||||||
|
|
||||||
|
|
||||||
|
laws_jacobian_weierstrass = {
|
||||||
|
'add': law_jacobian_weierstrass_add,
|
||||||
|
'double': law_jacobian_weierstrass_double,
|
||||||
|
'add_opposite': law_jacobian_weierstrass_add_opposites,
|
||||||
|
'add_infinite_a': law_jacobian_weierstrass_add_infinite_a,
|
||||||
|
'add_infinite_b': law_jacobian_weierstrass_add_infinite_b,
|
||||||
|
'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
|
||||||
|
"""Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field"""
|
||||||
|
F = Integers(p)
|
||||||
|
print "Formula %s on Z%i:" % (name, p)
|
||||||
|
points = []
|
||||||
|
for x in xrange(0, p):
|
||||||
|
for y in xrange(0, p):
|
||||||
|
point = affinepoint(F(x), F(y))
|
||||||
|
r, e = concrete_verify(on_weierstrass_curve(A, B, point))
|
||||||
|
if r:
|
||||||
|
points.append(point)
|
||||||
|
|
||||||
|
for za in xrange(1, p):
|
||||||
|
for zb in xrange(1, p):
|
||||||
|
for pa in points:
|
||||||
|
for pb in points:
|
||||||
|
for ia in xrange(2):
|
||||||
|
for ib in xrange(2):
|
||||||
|
pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia)
|
||||||
|
pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib)
|
||||||
|
for branch in xrange(0, branches):
|
||||||
|
assumeAssert, assumeBranch, pC = formula(branch, pA, pB)
|
||||||
|
pC.X = F(pC.X)
|
||||||
|
pC.Y = F(pC.Y)
|
||||||
|
pC.Z = F(pC.Z)
|
||||||
|
pC.Infinity = F(pC.Infinity)
|
||||||
|
r, e = concrete_verify(assumeAssert + assumeBranch)
|
||||||
|
if r:
|
||||||
|
match = False
|
||||||
|
for key in laws_jacobian_weierstrass:
|
||||||
|
assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC)
|
||||||
|
r, e = concrete_verify(assumeLaw)
|
||||||
|
if r:
|
||||||
|
if match:
|
||||||
|
print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity)
|
||||||
|
else:
|
||||||
|
match = True
|
||||||
|
r, e = concrete_verify(require)
|
||||||
|
if not r:
|
||||||
|
print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e)
|
||||||
|
print
|
||||||
|
|
||||||
|
|
||||||
|
def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC):
|
||||||
|
assumeLaw, require = f(A, B, pa, pb, pA, pB, pC)
|
||||||
|
return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require)
|
||||||
|
|
||||||
|
def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
|
||||||
|
"""Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically"""
|
||||||
|
R.<ax,bx,ay,by,Az,Bz,Ai,Bi> = PolynomialRing(QQ,8,order='invlex')
|
||||||
|
lift = lambda x: fastfrac(R,x)
|
||||||
|
ax = lift(ax)
|
||||||
|
ay = lift(ay)
|
||||||
|
Az = lift(Az)
|
||||||
|
bx = lift(bx)
|
||||||
|
by = lift(by)
|
||||||
|
Bz = lift(Bz)
|
||||||
|
Ai = lift(Ai)
|
||||||
|
Bi = lift(Bi)
|
||||||
|
|
||||||
|
pa = affinepoint(ax, ay, Ai)
|
||||||
|
pb = affinepoint(bx, by, Bi)
|
||||||
|
pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai)
|
||||||
|
pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi)
|
||||||
|
|
||||||
|
res = {}
|
||||||
|
|
||||||
|
for key in laws_jacobian_weierstrass:
|
||||||
|
res[key] = []
|
||||||
|
|
||||||
|
print ("Formula " + name + ":")
|
||||||
|
count = 0
|
||||||
|
for branch in xrange(branches):
|
||||||
|
assumeFormula, assumeBranch, pC = formula(branch, pA, pB)
|
||||||
|
pC.X = lift(pC.X)
|
||||||
|
pC.Y = lift(pC.Y)
|
||||||
|
pC.Z = lift(pC.Z)
|
||||||
|
pC.Infinity = lift(pC.Infinity)
|
||||||
|
|
||||||
|
for key in laws_jacobian_weierstrass:
|
||||||
|
res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch))
|
||||||
|
|
||||||
|
for key in res:
|
||||||
|
print " %s:" % key
|
||||||
|
val = res[key]
|
||||||
|
for x in val:
|
||||||
|
if x[0] is not None:
|
||||||
|
print " branch %i: %s" % (x[1], x[0])
|
||||||
|
|
||||||
|
print
|
919
secp256k1zkp/depend/secp256k1-zkp/src/asm/field_10x26_arm.s
Normal file
919
secp256k1zkp/depend/secp256k1-zkp/src/asm/field_10x26_arm.s
Normal file
|
@ -0,0 +1,919 @@
|
||||||
|
@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm:
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2014 Wladimir J. van der Laan *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
/*
|
||||||
|
ARM implementation of field_10x26 inner loops.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
|
||||||
|
- To avoid unnecessary loads and make use of available registers, two
|
||||||
|
'passes' have every time been interleaved, with the odd passes accumulating c' and d'
|
||||||
|
which will be added to c and d respectively in the the even passes
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
.syntax unified
|
||||||
|
.arch armv7-a
|
||||||
|
@ eabi attributes - see readelf -A
|
||||||
|
.eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes
|
||||||
|
.eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no
|
||||||
|
.eabi_attribute 10, 0 @ Tag_FP_arch = none
|
||||||
|
.eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte
|
||||||
|
.eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP
|
||||||
|
.eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed
|
||||||
|
.eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6
|
||||||
|
.text
|
||||||
|
|
||||||
|
@ Field constants
|
||||||
|
.set field_R0, 0x3d10
|
||||||
|
.set field_R1, 0x400
|
||||||
|
.set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff
|
||||||
|
|
||||||
|
.align 2
|
||||||
|
.global secp256k1_fe_mul_inner
|
||||||
|
.type secp256k1_fe_mul_inner, %function
|
||||||
|
@ Arguments:
|
||||||
|
@ r0 r Restrict: can overlap with a, not with b
|
||||||
|
@ r1 a
|
||||||
|
@ r2 b
|
||||||
|
@ 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
|
||||||
|
secp256k1_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
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* Main computation code.
|
||||||
|
******************************************
|
||||||
|
|
||||||
|
Allocation:
|
||||||
|
r0,r14,r7,r8 scratch
|
||||||
|
r1 a (pointer)
|
||||||
|
r2 b (pointer)
|
||||||
|
r3:r4 c
|
||||||
|
r5:r6 d
|
||||||
|
r11:r12 c'
|
||||||
|
r9:r10 d'
|
||||||
|
|
||||||
|
Note: do not write to r[] here, it may overlap with a[]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* A - interleaved with B */
|
||||||
|
ldr r7, [r1, #0*4] @ a[0]
|
||||||
|
ldr r8, [r2, #9*4] @ b[9]
|
||||||
|
ldr r0, [r1, #1*4] @ a[1]
|
||||||
|
umull r5, r6, r7, r8 @ d = a[0] * b[9]
|
||||||
|
ldr r14, [r2, #8*4] @ b[8]
|
||||||
|
umull r9, r10, r0, r8 @ d' = a[1] * b[9]
|
||||||
|
ldr r7, [r1, #2*4] @ a[2]
|
||||||
|
umlal r5, r6, r0, r14 @ d += a[1] * b[8]
|
||||||
|
ldr r8, [r2, #7*4] @ b[7]
|
||||||
|
umlal r9, r10, r7, r14 @ d' += a[2] * b[8]
|
||||||
|
ldr r0, [r1, #3*4] @ a[3]
|
||||||
|
umlal r5, r6, r7, r8 @ d += a[2] * b[7]
|
||||||
|
ldr r14, [r2, #6*4] @ b[6]
|
||||||
|
umlal r9, r10, r0, r8 @ d' += a[3] * b[7]
|
||||||
|
ldr r7, [r1, #4*4] @ a[4]
|
||||||
|
umlal r5, r6, r0, r14 @ d += a[3] * b[6]
|
||||||
|
ldr r8, [r2, #5*4] @ b[5]
|
||||||
|
umlal r9, r10, r7, r14 @ d' += a[4] * b[6]
|
||||||
|
ldr r0, [r1, #5*4] @ a[5]
|
||||||
|
umlal r5, r6, r7, r8 @ d += a[4] * b[5]
|
||||||
|
ldr r14, [r2, #4*4] @ b[4]
|
||||||
|
umlal r9, r10, r0, r8 @ d' += a[5] * b[5]
|
||||||
|
ldr r7, [r1, #6*4] @ a[6]
|
||||||
|
umlal r5, r6, r0, r14 @ d += a[5] * b[4]
|
||||||
|
ldr r8, [r2, #3*4] @ b[3]
|
||||||
|
umlal r9, r10, r7, r14 @ d' += a[6] * b[4]
|
||||||
|
ldr r0, [r1, #7*4] @ a[7]
|
||||||
|
umlal r5, r6, r7, r8 @ d += a[6] * b[3]
|
||||||
|
ldr r14, [r2, #2*4] @ b[2]
|
||||||
|
umlal r9, r10, r0, r8 @ d' += a[7] * b[3]
|
||||||
|
ldr r7, [r1, #8*4] @ a[8]
|
||||||
|
umlal r5, r6, r0, r14 @ d += a[7] * b[2]
|
||||||
|
ldr r8, [r2, #1*4] @ b[1]
|
||||||
|
umlal r9, r10, r7, r14 @ d' += a[8] * b[2]
|
||||||
|
ldr r0, [r1, #9*4] @ a[9]
|
||||||
|
umlal r5, r6, r7, r8 @ d += a[8] * b[1]
|
||||||
|
ldr r14, [r2, #0*4] @ b[0]
|
||||||
|
umlal r9, r10, r0, r8 @ d' += a[9] * b[1]
|
||||||
|
ldr r7, [r1, #0*4] @ a[0]
|
||||||
|
umlal r5, r6, r0, r14 @ d += a[9] * b[0]
|
||||||
|
@ r7,r14 used in B
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ t9 = d & M
|
||||||
|
str r0, [sp, #4 + 4*9]
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
|
||||||
|
/* B */
|
||||||
|
umull r3, r4, r7, r14 @ c = a[0] * b[0]
|
||||||
|
adds r5, r5, r9 @ d += d'
|
||||||
|
adc r6, r6, r10
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u0 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u0 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
bic r14, r3, field_not_M @ t0 = c & M
|
||||||
|
str r14, [sp, #4 + 0*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u0 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* C - interleaved with D */
|
||||||
|
ldr r7, [r1, #0*4] @ a[0]
|
||||||
|
ldr r8, [r2, #2*4] @ b[2]
|
||||||
|
ldr r14, [r2, #1*4] @ b[1]
|
||||||
|
umull r11, r12, r7, r8 @ c' = a[0] * b[2]
|
||||||
|
ldr r0, [r1, #1*4] @ a[1]
|
||||||
|
umlal r3, r4, r7, r14 @ c += a[0] * b[1]
|
||||||
|
ldr r8, [r2, #0*4] @ b[0]
|
||||||
|
umlal r11, r12, r0, r14 @ c' += a[1] * b[1]
|
||||||
|
ldr r7, [r1, #2*4] @ a[2]
|
||||||
|
umlal r3, r4, r0, r8 @ c += a[1] * b[0]
|
||||||
|
ldr r14, [r2, #9*4] @ b[9]
|
||||||
|
umlal r11, r12, r7, r8 @ c' += a[2] * b[0]
|
||||||
|
ldr r0, [r1, #3*4] @ a[3]
|
||||||
|
umlal r5, r6, r7, r14 @ d += a[2] * b[9]
|
||||||
|
ldr r8, [r2, #8*4] @ b[8]
|
||||||
|
umull r9, r10, r0, r14 @ d' = a[3] * b[9]
|
||||||
|
ldr r7, [r1, #4*4] @ a[4]
|
||||||
|
umlal r5, r6, r0, r8 @ d += a[3] * b[8]
|
||||||
|
ldr r14, [r2, #7*4] @ b[7]
|
||||||
|
umlal r9, r10, r7, r8 @ d' += a[4] * b[8]
|
||||||
|
ldr r0, [r1, #5*4] @ a[5]
|
||||||
|
umlal r5, r6, r7, r14 @ d += a[4] * b[7]
|
||||||
|
ldr r8, [r2, #6*4] @ b[6]
|
||||||
|
umlal r9, r10, r0, r14 @ d' += a[5] * b[7]
|
||||||
|
ldr r7, [r1, #6*4] @ a[6]
|
||||||
|
umlal r5, r6, r0, r8 @ d += a[5] * b[6]
|
||||||
|
ldr r14, [r2, #5*4] @ b[5]
|
||||||
|
umlal r9, r10, r7, r8 @ d' += a[6] * b[6]
|
||||||
|
ldr r0, [r1, #7*4] @ a[7]
|
||||||
|
umlal r5, r6, r7, r14 @ d += a[6] * b[5]
|
||||||
|
ldr r8, [r2, #4*4] @ b[4]
|
||||||
|
umlal r9, r10, r0, r14 @ d' += a[7] * b[5]
|
||||||
|
ldr r7, [r1, #8*4] @ a[8]
|
||||||
|
umlal r5, r6, r0, r8 @ d += a[7] * b[4]
|
||||||
|
ldr r14, [r2, #3*4] @ b[3]
|
||||||
|
umlal r9, r10, r7, r8 @ d' += a[8] * b[4]
|
||||||
|
ldr r0, [r1, #9*4] @ a[9]
|
||||||
|
umlal r5, r6, r7, r14 @ d += a[8] * b[3]
|
||||||
|
ldr r8, [r2, #2*4] @ b[2]
|
||||||
|
umlal r9, r10, r0, r14 @ d' += a[9] * b[3]
|
||||||
|
umlal r5, r6, r0, r8 @ d += a[9] * b[2]
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u1 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u1 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
bic r14, r3, field_not_M @ t1 = c & M
|
||||||
|
str r14, [sp, #4 + 1*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u1 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* D */
|
||||||
|
adds r3, r3, r11 @ c += c'
|
||||||
|
adc r4, r4, r12
|
||||||
|
adds r5, r5, r9 @ d += d'
|
||||||
|
adc r6, r6, r10
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u2 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u2 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
bic r14, r3, field_not_M @ t2 = c & M
|
||||||
|
str r14, [sp, #4 + 2*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u2 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* E - interleaved with F */
|
||||||
|
ldr r7, [r1, #0*4] @ a[0]
|
||||||
|
ldr r8, [r2, #4*4] @ b[4]
|
||||||
|
umull r11, r12, r7, r8 @ c' = a[0] * b[4]
|
||||||
|
ldr r8, [r2, #3*4] @ b[3]
|
||||||
|
umlal r3, r4, r7, r8 @ c += a[0] * b[3]
|
||||||
|
ldr r7, [r1, #1*4] @ a[1]
|
||||||
|
umlal r11, r12, r7, r8 @ c' += a[1] * b[3]
|
||||||
|
ldr r8, [r2, #2*4] @ b[2]
|
||||||
|
umlal r3, r4, r7, r8 @ c += a[1] * b[2]
|
||||||
|
ldr r7, [r1, #2*4] @ a[2]
|
||||||
|
umlal r11, r12, r7, r8 @ c' += a[2] * b[2]
|
||||||
|
ldr r8, [r2, #1*4] @ b[1]
|
||||||
|
umlal r3, r4, r7, r8 @ c += a[2] * b[1]
|
||||||
|
ldr r7, [r1, #3*4] @ a[3]
|
||||||
|
umlal r11, r12, r7, r8 @ c' += a[3] * b[1]
|
||||||
|
ldr r8, [r2, #0*4] @ b[0]
|
||||||
|
umlal r3, r4, r7, r8 @ c += a[3] * b[0]
|
||||||
|
ldr r7, [r1, #4*4] @ a[4]
|
||||||
|
umlal r11, r12, r7, r8 @ c' += a[4] * b[0]
|
||||||
|
ldr r8, [r2, #9*4] @ b[9]
|
||||||
|
umlal r5, r6, r7, r8 @ d += a[4] * b[9]
|
||||||
|
ldr r7, [r1, #5*4] @ a[5]
|
||||||
|
umull r9, r10, r7, r8 @ d' = a[5] * b[9]
|
||||||
|
ldr r8, [r2, #8*4] @ b[8]
|
||||||
|
umlal r5, r6, r7, r8 @ d += a[5] * b[8]
|
||||||
|
ldr r7, [r1, #6*4] @ a[6]
|
||||||
|
umlal r9, r10, r7, r8 @ d' += a[6] * b[8]
|
||||||
|
ldr r8, [r2, #7*4] @ b[7]
|
||||||
|
umlal r5, r6, r7, r8 @ d += a[6] * b[7]
|
||||||
|
ldr r7, [r1, #7*4] @ a[7]
|
||||||
|
umlal r9, r10, r7, r8 @ d' += a[7] * b[7]
|
||||||
|
ldr r8, [r2, #6*4] @ b[6]
|
||||||
|
umlal r5, r6, r7, r8 @ d += a[7] * b[6]
|
||||||
|
ldr r7, [r1, #8*4] @ a[8]
|
||||||
|
umlal r9, r10, r7, r8 @ d' += a[8] * b[6]
|
||||||
|
ldr r8, [r2, #5*4] @ b[5]
|
||||||
|
umlal r5, r6, r7, r8 @ d += a[8] * b[5]
|
||||||
|
ldr r7, [r1, #9*4] @ a[9]
|
||||||
|
umlal r9, r10, r7, r8 @ d' += a[9] * b[5]
|
||||||
|
ldr r8, [r2, #4*4] @ b[4]
|
||||||
|
umlal r5, r6, r7, r8 @ d += a[9] * b[4]
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u3 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u3 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
bic r14, r3, field_not_M @ t3 = c & M
|
||||||
|
str r14, [sp, #4 + 3*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u3 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* F */
|
||||||
|
adds r3, r3, r11 @ c += c'
|
||||||
|
adc r4, r4, r12
|
||||||
|
adds r5, r5, r9 @ d += d'
|
||||||
|
adc r6, r6, r10
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u4 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u4 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
bic r14, r3, field_not_M @ t4 = c & M
|
||||||
|
str r14, [sp, #4 + 4*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u4 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* G - interleaved with H */
|
||||||
|
ldr r7, [r1, #0*4] @ a[0]
|
||||||
|
ldr r8, [r2, #6*4] @ b[6]
|
||||||
|
ldr r14, [r2, #5*4] @ b[5]
|
||||||
|
umull r11, r12, r7, r8 @ c' = a[0] * b[6]
|
||||||
|
ldr r0, [r1, #1*4] @ a[1]
|
||||||
|
umlal r3, r4, r7, r14 @ c += a[0] * b[5]
|
||||||
|
ldr r8, [r2, #4*4] @ b[4]
|
||||||
|
umlal r11, r12, r0, r14 @ c' += a[1] * b[5]
|
||||||
|
ldr r7, [r1, #2*4] @ a[2]
|
||||||
|
umlal r3, r4, r0, r8 @ c += a[1] * b[4]
|
||||||
|
ldr r14, [r2, #3*4] @ b[3]
|
||||||
|
umlal r11, r12, r7, r8 @ c' += a[2] * b[4]
|
||||||
|
ldr r0, [r1, #3*4] @ a[3]
|
||||||
|
umlal r3, r4, r7, r14 @ c += a[2] * b[3]
|
||||||
|
ldr r8, [r2, #2*4] @ b[2]
|
||||||
|
umlal r11, r12, r0, r14 @ c' += a[3] * b[3]
|
||||||
|
ldr r7, [r1, #4*4] @ a[4]
|
||||||
|
umlal r3, r4, r0, r8 @ c += a[3] * b[2]
|
||||||
|
ldr r14, [r2, #1*4] @ b[1]
|
||||||
|
umlal r11, r12, r7, r8 @ c' += a[4] * b[2]
|
||||||
|
ldr r0, [r1, #5*4] @ a[5]
|
||||||
|
umlal r3, r4, r7, r14 @ c += a[4] * b[1]
|
||||||
|
ldr r8, [r2, #0*4] @ b[0]
|
||||||
|
umlal r11, r12, r0, r14 @ c' += a[5] * b[1]
|
||||||
|
ldr r7, [r1, #6*4] @ a[6]
|
||||||
|
umlal r3, r4, r0, r8 @ c += a[5] * b[0]
|
||||||
|
ldr r14, [r2, #9*4] @ b[9]
|
||||||
|
umlal r11, r12, r7, r8 @ c' += a[6] * b[0]
|
||||||
|
ldr r0, [r1, #7*4] @ a[7]
|
||||||
|
umlal r5, r6, r7, r14 @ d += a[6] * b[9]
|
||||||
|
ldr r8, [r2, #8*4] @ b[8]
|
||||||
|
umull r9, r10, r0, r14 @ d' = a[7] * b[9]
|
||||||
|
ldr r7, [r1, #8*4] @ a[8]
|
||||||
|
umlal r5, r6, r0, r8 @ d += a[7] * b[8]
|
||||||
|
ldr r14, [r2, #7*4] @ b[7]
|
||||||
|
umlal r9, r10, r7, r8 @ d' += a[8] * b[8]
|
||||||
|
ldr r0, [r1, #9*4] @ a[9]
|
||||||
|
umlal r5, r6, r7, r14 @ d += a[8] * b[7]
|
||||||
|
ldr r8, [r2, #6*4] @ b[6]
|
||||||
|
umlal r9, r10, r0, r14 @ d' += a[9] * b[7]
|
||||||
|
umlal r5, r6, r0, r8 @ d += a[9] * b[6]
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u5 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u5 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
bic r14, r3, field_not_M @ t5 = c & M
|
||||||
|
str r14, [sp, #4 + 5*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u5 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* H */
|
||||||
|
adds r3, r3, r11 @ c += c'
|
||||||
|
adc r4, r4, r12
|
||||||
|
adds r5, r5, r9 @ d += d'
|
||||||
|
adc r6, r6, r10
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u6 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u6 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
bic r14, r3, field_not_M @ t6 = c & M
|
||||||
|
str r14, [sp, #4 + 6*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u6 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* I - interleaved with J */
|
||||||
|
ldr r8, [r2, #8*4] @ b[8]
|
||||||
|
ldr r7, [r1, #0*4] @ a[0]
|
||||||
|
ldr r14, [r2, #7*4] @ b[7]
|
||||||
|
umull r11, r12, r7, r8 @ c' = a[0] * b[8]
|
||||||
|
ldr r0, [r1, #1*4] @ a[1]
|
||||||
|
umlal r3, r4, r7, r14 @ c += a[0] * b[7]
|
||||||
|
ldr r8, [r2, #6*4] @ b[6]
|
||||||
|
umlal r11, r12, r0, r14 @ c' += a[1] * b[7]
|
||||||
|
ldr r7, [r1, #2*4] @ a[2]
|
||||||
|
umlal r3, r4, r0, r8 @ c += a[1] * b[6]
|
||||||
|
ldr r14, [r2, #5*4] @ b[5]
|
||||||
|
umlal r11, r12, r7, r8 @ c' += a[2] * b[6]
|
||||||
|
ldr r0, [r1, #3*4] @ a[3]
|
||||||
|
umlal r3, r4, r7, r14 @ c += a[2] * b[5]
|
||||||
|
ldr r8, [r2, #4*4] @ b[4]
|
||||||
|
umlal r11, r12, r0, r14 @ c' += a[3] * b[5]
|
||||||
|
ldr r7, [r1, #4*4] @ a[4]
|
||||||
|
umlal r3, r4, r0, r8 @ c += a[3] * b[4]
|
||||||
|
ldr r14, [r2, #3*4] @ b[3]
|
||||||
|
umlal r11, r12, r7, r8 @ c' += a[4] * b[4]
|
||||||
|
ldr r0, [r1, #5*4] @ a[5]
|
||||||
|
umlal r3, r4, r7, r14 @ c += a[4] * b[3]
|
||||||
|
ldr r8, [r2, #2*4] @ b[2]
|
||||||
|
umlal r11, r12, r0, r14 @ c' += a[5] * b[3]
|
||||||
|
ldr r7, [r1, #6*4] @ a[6]
|
||||||
|
umlal r3, r4, r0, r8 @ c += a[5] * b[2]
|
||||||
|
ldr r14, [r2, #1*4] @ b[1]
|
||||||
|
umlal r11, r12, r7, r8 @ c' += a[6] * b[2]
|
||||||
|
ldr r0, [r1, #7*4] @ a[7]
|
||||||
|
umlal r3, r4, r7, r14 @ c += a[6] * b[1]
|
||||||
|
ldr r8, [r2, #0*4] @ b[0]
|
||||||
|
umlal r11, r12, r0, r14 @ c' += a[7] * b[1]
|
||||||
|
ldr r7, [r1, #8*4] @ a[8]
|
||||||
|
umlal r3, r4, r0, r8 @ c += a[7] * b[0]
|
||||||
|
ldr r14, [r2, #9*4] @ b[9]
|
||||||
|
umlal r11, r12, r7, r8 @ c' += a[8] * b[0]
|
||||||
|
ldr r0, [r1, #9*4] @ a[9]
|
||||||
|
umlal r5, r6, r7, r14 @ d += a[8] * b[9]
|
||||||
|
ldr r8, [r2, #8*4] @ b[8]
|
||||||
|
umull r9, r10, r0, r14 @ d' = a[9] * b[9]
|
||||||
|
umlal r5, r6, r0, r8 @ d += a[9] * b[8]
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u7 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u7 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
bic r14, r3, field_not_M @ t7 = c & M
|
||||||
|
str r14, [sp, #4 + 7*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u7 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* J */
|
||||||
|
adds r3, r3, r11 @ c += c'
|
||||||
|
adc r4, r4, r12
|
||||||
|
adds r5, r5, r9 @ d += d'
|
||||||
|
adc r6, r6, r10
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u8 = d & M
|
||||||
|
str r0, [sp, #4 + 8*4]
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u8 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* compute and write back result
|
||||||
|
******************************************
|
||||||
|
Allocation:
|
||||||
|
r0 r
|
||||||
|
r3:r4 c
|
||||||
|
r5:r6 d
|
||||||
|
r7 t0
|
||||||
|
r8 t1
|
||||||
|
r9 t2
|
||||||
|
r11 u8
|
||||||
|
r12 t9
|
||||||
|
r1,r2,r10,r14 scratch
|
||||||
|
|
||||||
|
Note: do not read from a[] after here, it may overlap with r[]
|
||||||
|
*/
|
||||||
|
ldr r0, [sp, #0]
|
||||||
|
add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9
|
||||||
|
ldmia r1, {r2,r7,r8,r9,r10,r11,r12}
|
||||||
|
add r1, r0, #3*4
|
||||||
|
stmia r1, {r2,r7,r8,r9,r10}
|
||||||
|
|
||||||
|
bic r2, r3, field_not_M @ r[8] = c & M
|
||||||
|
str r2, [r0, #8*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u8 * R1
|
||||||
|
umlal r3, r4, r11, r14
|
||||||
|
movw r14, field_R0 @ c += d * R0
|
||||||
|
umlal r3, r4, r5, r14
|
||||||
|
adds r3, r3, r12 @ c += t9
|
||||||
|
adc r4, r4, #0
|
||||||
|
|
||||||
|
add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2
|
||||||
|
ldmia r1, {r7,r8,r9}
|
||||||
|
|
||||||
|
ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4)
|
||||||
|
str r2, [r0, #9*4]
|
||||||
|
mov r3, r3, lsr #22 @ c >>= 22
|
||||||
|
orr r3, r3, r4, asl #10
|
||||||
|
mov r4, r4, lsr #22
|
||||||
|
movw r14, field_R1 << 4 @ c += d * (R1 << 4)
|
||||||
|
umlal r3, r4, r5, r14
|
||||||
|
|
||||||
|
movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add)
|
||||||
|
umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4)
|
||||||
|
adds r5, r5, r7 @ d.lo += t0
|
||||||
|
mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4)
|
||||||
|
adc r6, r6, 0 @ d.hi += carry
|
||||||
|
|
||||||
|
bic r2, r5, field_not_M @ r[0] = d & M
|
||||||
|
str r2, [r0, #0*4]
|
||||||
|
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
|
||||||
|
movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add)
|
||||||
|
umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4)
|
||||||
|
adds r5, r5, r8 @ d.lo += t1
|
||||||
|
adc r6, r6, #0 @ d.hi += carry
|
||||||
|
adds r5, r5, r1 @ d.lo += tmp.lo
|
||||||
|
mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4)
|
||||||
|
adc r6, r6, r2 @ d.hi += carry + tmp.hi
|
||||||
|
|
||||||
|
bic r2, r5, field_not_M @ r[1] = d & M
|
||||||
|
str r2, [r0, #1*4]
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26 (ignore hi)
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
|
||||||
|
add r5, r5, r9 @ d += t2
|
||||||
|
str r5, [r0, #2*4] @ r[2] = d
|
||||||
|
|
||||||
|
add sp, sp, #48
|
||||||
|
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
|
||||||
|
.size secp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner
|
||||||
|
|
||||||
|
.align 2
|
||||||
|
.global secp256k1_fe_sqr_inner
|
||||||
|
.type secp256k1_fe_sqr_inner, %function
|
||||||
|
@ 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
|
||||||
|
secp256k1_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
|
||||||
|
/******************************************
|
||||||
|
* Main computation code.
|
||||||
|
******************************************
|
||||||
|
|
||||||
|
Allocation:
|
||||||
|
r0,r14,r2,r7,r8 scratch
|
||||||
|
r1 a (pointer)
|
||||||
|
r3:r4 c
|
||||||
|
r5:r6 d
|
||||||
|
r11:r12 c'
|
||||||
|
r9:r10 d'
|
||||||
|
|
||||||
|
Note: do not write to r[] here, it may overlap with a[]
|
||||||
|
*/
|
||||||
|
/* A interleaved with B */
|
||||||
|
ldr r0, [r1, #1*4] @ a[1]*2
|
||||||
|
ldr r7, [r1, #0*4] @ a[0]
|
||||||
|
mov r0, r0, asl #1
|
||||||
|
ldr r14, [r1, #9*4] @ a[9]
|
||||||
|
umull r3, r4, r7, r7 @ c = a[0] * a[0]
|
||||||
|
ldr r8, [r1, #8*4] @ a[8]
|
||||||
|
mov r7, r7, asl #1
|
||||||
|
umull r5, r6, r7, r14 @ d = a[0]*2 * a[9]
|
||||||
|
ldr r7, [r1, #2*4] @ a[2]*2
|
||||||
|
umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9]
|
||||||
|
ldr r14, [r1, #7*4] @ a[7]
|
||||||
|
umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8]
|
||||||
|
mov r7, r7, asl #1
|
||||||
|
ldr r0, [r1, #3*4] @ a[3]*2
|
||||||
|
umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8]
|
||||||
|
ldr r8, [r1, #6*4] @ a[6]
|
||||||
|
umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7]
|
||||||
|
mov r0, r0, asl #1
|
||||||
|
ldr r7, [r1, #4*4] @ a[4]*2
|
||||||
|
umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7]
|
||||||
|
ldr r14, [r1, #5*4] @ a[5]
|
||||||
|
mov r7, r7, asl #1
|
||||||
|
umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6]
|
||||||
|
umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6]
|
||||||
|
umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5]
|
||||||
|
umlal r9, r10, r14, r14 @ d' += a[5] * a[5]
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ t9 = d & M
|
||||||
|
str r0, [sp, #4 + 9*4]
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
|
||||||
|
/* B */
|
||||||
|
adds r5, r5, r9 @ d += d'
|
||||||
|
adc r6, r6, r10
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u0 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u0 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
bic r14, r3, field_not_M @ t0 = c & M
|
||||||
|
str r14, [sp, #4 + 0*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u0 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* C interleaved with D */
|
||||||
|
ldr r0, [r1, #0*4] @ a[0]*2
|
||||||
|
ldr r14, [r1, #1*4] @ a[1]
|
||||||
|
mov r0, r0, asl #1
|
||||||
|
ldr r8, [r1, #2*4] @ a[2]
|
||||||
|
umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1]
|
||||||
|
mov r7, r8, asl #1 @ a[2]*2
|
||||||
|
umull r11, r12, r14, r14 @ c' = a[1] * a[1]
|
||||||
|
ldr r14, [r1, #9*4] @ a[9]
|
||||||
|
umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2]
|
||||||
|
ldr r0, [r1, #3*4] @ a[3]*2
|
||||||
|
ldr r8, [r1, #8*4] @ a[8]
|
||||||
|
umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9]
|
||||||
|
mov r0, r0, asl #1
|
||||||
|
ldr r7, [r1, #4*4] @ a[4]*2
|
||||||
|
umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9]
|
||||||
|
ldr r14, [r1, #7*4] @ a[7]
|
||||||
|
umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8]
|
||||||
|
mov r7, r7, asl #1
|
||||||
|
ldr r0, [r1, #5*4] @ a[5]*2
|
||||||
|
umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8]
|
||||||
|
ldr r8, [r1, #6*4] @ a[6]
|
||||||
|
mov r0, r0, asl #1
|
||||||
|
umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7]
|
||||||
|
umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7]
|
||||||
|
umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6]
|
||||||
|
umlal r9, r10, r8, r8 @ d' += a[6] * a[6]
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u1 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u1 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
bic r14, r3, field_not_M @ t1 = c & M
|
||||||
|
str r14, [sp, #4 + 1*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u1 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* D */
|
||||||
|
adds r3, r3, r11 @ c += c'
|
||||||
|
adc r4, r4, r12
|
||||||
|
adds r5, r5, r9 @ d += d'
|
||||||
|
adc r6, r6, r10
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u2 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u2 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
bic r14, r3, field_not_M @ t2 = c & M
|
||||||
|
str r14, [sp, #4 + 2*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u2 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* E interleaved with F */
|
||||||
|
ldr r7, [r1, #0*4] @ a[0]*2
|
||||||
|
ldr r0, [r1, #1*4] @ a[1]*2
|
||||||
|
ldr r14, [r1, #2*4] @ a[2]
|
||||||
|
mov r7, r7, asl #1
|
||||||
|
ldr r8, [r1, #3*4] @ a[3]
|
||||||
|
ldr r2, [r1, #4*4]
|
||||||
|
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3]
|
||||||
|
mov r0, r0, asl #1
|
||||||
|
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4]
|
||||||
|
mov r2, r2, asl #1 @ a[4]*2
|
||||||
|
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3]
|
||||||
|
ldr r8, [r1, #9*4] @ a[9]
|
||||||
|
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2]
|
||||||
|
ldr r0, [r1, #5*4] @ a[5]*2
|
||||||
|
umlal r11, r12, r14, r14 @ c' += a[2] * a[2]
|
||||||
|
ldr r14, [r1, #8*4] @ a[8]
|
||||||
|
mov r0, r0, asl #1
|
||||||
|
umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9]
|
||||||
|
ldr r7, [r1, #6*4] @ a[6]*2
|
||||||
|
umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9]
|
||||||
|
mov r7, r7, asl #1
|
||||||
|
ldr r8, [r1, #7*4] @ a[7]
|
||||||
|
umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8]
|
||||||
|
umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8]
|
||||||
|
umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7]
|
||||||
|
umlal r9, r10, r8, r8 @ d' += a[7] * a[7]
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u3 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u3 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
bic r14, r3, field_not_M @ t3 = c & M
|
||||||
|
str r14, [sp, #4 + 3*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u3 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* F */
|
||||||
|
adds r3, r3, r11 @ c += c'
|
||||||
|
adc r4, r4, r12
|
||||||
|
adds r5, r5, r9 @ d += d'
|
||||||
|
adc r6, r6, r10
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u4 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u4 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
bic r14, r3, field_not_M @ t4 = c & M
|
||||||
|
str r14, [sp, #4 + 4*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u4 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* G interleaved with H */
|
||||||
|
ldr r7, [r1, #0*4] @ a[0]*2
|
||||||
|
ldr r0, [r1, #1*4] @ a[1]*2
|
||||||
|
mov r7, r7, asl #1
|
||||||
|
ldr r8, [r1, #5*4] @ a[5]
|
||||||
|
ldr r2, [r1, #6*4] @ a[6]
|
||||||
|
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5]
|
||||||
|
ldr r14, [r1, #4*4] @ a[4]
|
||||||
|
mov r0, r0, asl #1
|
||||||
|
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6]
|
||||||
|
ldr r7, [r1, #2*4] @ a[2]*2
|
||||||
|
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5]
|
||||||
|
mov r7, r7, asl #1
|
||||||
|
ldr r8, [r1, #3*4] @ a[3]
|
||||||
|
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4]
|
||||||
|
mov r0, r2, asl #1 @ a[6]*2
|
||||||
|
umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4]
|
||||||
|
ldr r14, [r1, #9*4] @ a[9]
|
||||||
|
umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3]
|
||||||
|
ldr r7, [r1, #7*4] @ a[7]*2
|
||||||
|
umlal r11, r12, r8, r8 @ c' += a[3] * a[3]
|
||||||
|
mov r7, r7, asl #1
|
||||||
|
ldr r8, [r1, #8*4] @ a[8]
|
||||||
|
umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9]
|
||||||
|
umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9]
|
||||||
|
umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8]
|
||||||
|
umlal r9, r10, r8, r8 @ d' += a[8] * a[8]
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u5 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u5 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
bic r14, r3, field_not_M @ t5 = c & M
|
||||||
|
str r14, [sp, #4 + 5*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u5 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* H */
|
||||||
|
adds r3, r3, r11 @ c += c'
|
||||||
|
adc r4, r4, r12
|
||||||
|
adds r5, r5, r9 @ d += d'
|
||||||
|
adc r6, r6, r10
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u6 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u6 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
bic r14, r3, field_not_M @ t6 = c & M
|
||||||
|
str r14, [sp, #4 + 6*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u6 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* I interleaved with J */
|
||||||
|
ldr r7, [r1, #0*4] @ a[0]*2
|
||||||
|
ldr r0, [r1, #1*4] @ a[1]*2
|
||||||
|
mov r7, r7, asl #1
|
||||||
|
ldr r8, [r1, #7*4] @ a[7]
|
||||||
|
ldr r2, [r1, #8*4] @ a[8]
|
||||||
|
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7]
|
||||||
|
ldr r14, [r1, #6*4] @ a[6]
|
||||||
|
mov r0, r0, asl #1
|
||||||
|
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8]
|
||||||
|
ldr r7, [r1, #2*4] @ a[2]*2
|
||||||
|
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7]
|
||||||
|
ldr r8, [r1, #5*4] @ a[5]
|
||||||
|
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6]
|
||||||
|
ldr r0, [r1, #3*4] @ a[3]*2
|
||||||
|
mov r7, r7, asl #1
|
||||||
|
umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6]
|
||||||
|
ldr r14, [r1, #4*4] @ a[4]
|
||||||
|
mov r0, r0, asl #1
|
||||||
|
umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5]
|
||||||
|
mov r2, r2, asl #1 @ a[8]*2
|
||||||
|
umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5]
|
||||||
|
umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4]
|
||||||
|
umlal r11, r12, r14, r14 @ c' += a[4] * a[4]
|
||||||
|
ldr r8, [r1, #9*4] @ a[9]
|
||||||
|
umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9]
|
||||||
|
@ r8 will be used in J
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u7 = d & M
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u7 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
bic r14, r3, field_not_M @ t7 = c & M
|
||||||
|
str r14, [sp, #4 + 7*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u7 * R1
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/* J */
|
||||||
|
adds r3, r3, r11 @ c += c'
|
||||||
|
adc r4, r4, r12
|
||||||
|
umlal r5, r6, r8, r8 @ d += a[9] * a[9]
|
||||||
|
|
||||||
|
bic r0, r5, field_not_M @ u8 = d & M
|
||||||
|
str r0, [sp, #4 + 8*4]
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
movw r14, field_R0 @ c += u8 * R0
|
||||||
|
umlal r3, r4, r0, r14
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* compute and write back result
|
||||||
|
******************************************
|
||||||
|
Allocation:
|
||||||
|
r0 r
|
||||||
|
r3:r4 c
|
||||||
|
r5:r6 d
|
||||||
|
r7 t0
|
||||||
|
r8 t1
|
||||||
|
r9 t2
|
||||||
|
r11 u8
|
||||||
|
r12 t9
|
||||||
|
r1,r2,r10,r14 scratch
|
||||||
|
|
||||||
|
Note: do not read from a[] after here, it may overlap with r[]
|
||||||
|
*/
|
||||||
|
ldr r0, [sp, #0]
|
||||||
|
add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9
|
||||||
|
ldmia r1, {r2,r7,r8,r9,r10,r11,r12}
|
||||||
|
add r1, r0, #3*4
|
||||||
|
stmia r1, {r2,r7,r8,r9,r10}
|
||||||
|
|
||||||
|
bic r2, r3, field_not_M @ r[8] = c & M
|
||||||
|
str r2, [r0, #8*4]
|
||||||
|
mov r3, r3, lsr #26 @ c >>= 26
|
||||||
|
orr r3, r3, r4, asl #6
|
||||||
|
mov r4, r4, lsr #26
|
||||||
|
mov r14, field_R1 @ c += u8 * R1
|
||||||
|
umlal r3, r4, r11, r14
|
||||||
|
movw r14, field_R0 @ c += d * R0
|
||||||
|
umlal r3, r4, r5, r14
|
||||||
|
adds r3, r3, r12 @ c += t9
|
||||||
|
adc r4, r4, #0
|
||||||
|
|
||||||
|
add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2
|
||||||
|
ldmia r1, {r7,r8,r9}
|
||||||
|
|
||||||
|
ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4)
|
||||||
|
str r2, [r0, #9*4]
|
||||||
|
mov r3, r3, lsr #22 @ c >>= 22
|
||||||
|
orr r3, r3, r4, asl #10
|
||||||
|
mov r4, r4, lsr #22
|
||||||
|
movw r14, field_R1 << 4 @ c += d * (R1 << 4)
|
||||||
|
umlal r3, r4, r5, r14
|
||||||
|
|
||||||
|
movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add)
|
||||||
|
umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4)
|
||||||
|
adds r5, r5, r7 @ d.lo += t0
|
||||||
|
mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4)
|
||||||
|
adc r6, r6, 0 @ d.hi += carry
|
||||||
|
|
||||||
|
bic r2, r5, field_not_M @ r[0] = d & M
|
||||||
|
str r2, [r0, #0*4]
|
||||||
|
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
mov r6, r6, lsr #26
|
||||||
|
|
||||||
|
movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add)
|
||||||
|
umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4)
|
||||||
|
adds r5, r5, r8 @ d.lo += t1
|
||||||
|
adc r6, r6, #0 @ d.hi += carry
|
||||||
|
adds r5, r5, r1 @ d.lo += tmp.lo
|
||||||
|
mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4)
|
||||||
|
adc r6, r6, r2 @ d.hi += carry + tmp.hi
|
||||||
|
|
||||||
|
bic r2, r5, field_not_M @ r[1] = d & M
|
||||||
|
str r2, [r0, #1*4]
|
||||||
|
mov r5, r5, lsr #26 @ d >>= 26 (ignore hi)
|
||||||
|
orr r5, r5, r6, asl #6
|
||||||
|
|
||||||
|
add r5, r5, r9 @ d += t2
|
||||||
|
str r5, [r0, #2*4] @ r[2] = d
|
||||||
|
|
||||||
|
add sp, sp, #48
|
||||||
|
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
|
||||||
|
.size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner
|
||||||
|
|
32
secp256k1zkp/depend/secp256k1-zkp/src/basic-config.h
Normal file
32
secp256k1zkp/depend/secp256k1-zkp/src/basic-config.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_BASIC_CONFIG_
|
||||||
|
#define _SECP256K1_BASIC_CONFIG_
|
||||||
|
|
||||||
|
#ifdef USE_BASIC_CONFIG
|
||||||
|
|
||||||
|
#undef USE_ASM_X86_64
|
||||||
|
#undef USE_ENDOMORPHISM
|
||||||
|
#undef USE_FIELD_10X26
|
||||||
|
#undef USE_FIELD_5X52
|
||||||
|
#undef USE_FIELD_INV_BUILTIN
|
||||||
|
#undef USE_FIELD_INV_NUM
|
||||||
|
#undef USE_NUM_GMP
|
||||||
|
#undef USE_NUM_NONE
|
||||||
|
#undef USE_SCALAR_4X64
|
||||||
|
#undef USE_SCALAR_8X32
|
||||||
|
#undef USE_SCALAR_INV_BUILTIN
|
||||||
|
#undef USE_SCALAR_INV_NUM
|
||||||
|
|
||||||
|
#define USE_NUM_NONE 1
|
||||||
|
#define USE_FIELD_INV_BUILTIN 1
|
||||||
|
#define USE_SCALAR_INV_BUILTIN 1
|
||||||
|
#define USE_FIELD_10X26 1
|
||||||
|
#define USE_SCALAR_8X32 1
|
||||||
|
|
||||||
|
#endif // USE_BASIC_CONFIG
|
||||||
|
#endif // _SECP256K1_BASIC_CONFIG_
|
66
secp256k1zkp/depend/secp256k1-zkp/src/bench.h
Normal file
66
secp256k1zkp/depend/secp256k1-zkp/src/bench.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_BENCH_H_
|
||||||
|
#define _SECP256K1_BENCH_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "sys/time.h"
|
||||||
|
|
||||||
|
static double gettimedouble(void) {
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
return tv.tv_usec * 0.000001 + tv.tv_sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_number(double x) {
|
||||||
|
double y = x;
|
||||||
|
int c = 0;
|
||||||
|
if (y < 0.0) {
|
||||||
|
y = -y;
|
||||||
|
}
|
||||||
|
while (y < 100.0) {
|
||||||
|
y *= 10.0;
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
printf("%.*f", c, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) {
|
||||||
|
int i;
|
||||||
|
double min = HUGE_VAL;
|
||||||
|
double sum = 0.0;
|
||||||
|
double max = 0.0;
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
double begin, total;
|
||||||
|
if (setup != NULL) {
|
||||||
|
setup(data);
|
||||||
|
}
|
||||||
|
begin = gettimedouble();
|
||||||
|
benchmark(data);
|
||||||
|
total = gettimedouble() - begin;
|
||||||
|
if (teardown != NULL) {
|
||||||
|
teardown(data);
|
||||||
|
}
|
||||||
|
if (total < min) {
|
||||||
|
min = total;
|
||||||
|
}
|
||||||
|
if (total > max) {
|
||||||
|
max = total;
|
||||||
|
}
|
||||||
|
sum += total;
|
||||||
|
}
|
||||||
|
printf("%s: min ", name);
|
||||||
|
print_number(min * 1000000.0 / iter);
|
||||||
|
printf("us / avg ");
|
||||||
|
print_number((sum / count) * 1000000.0 / iter);
|
||||||
|
printf("us / max ");
|
||||||
|
print_number(max * 1000000.0 / iter);
|
||||||
|
printf("us\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
54
secp256k1zkp/depend/secp256k1-zkp/src/bench_ecdh.c
Normal file
54
secp256k1zkp/depend/secp256k1-zkp/src/bench_ecdh.c
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2015 Pieter Wuille, Andrew Poelstra *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "include/secp256k1.h"
|
||||||
|
#include "include/secp256k1_ecdh.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "bench.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
secp256k1_context *ctx;
|
||||||
|
secp256k1_pubkey point;
|
||||||
|
unsigned char scalar[32];
|
||||||
|
} bench_ecdh_t;
|
||||||
|
|
||||||
|
static void bench_ecdh_setup(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_ecdh_t *data = (bench_ecdh_t*)arg;
|
||||||
|
const unsigned char point[] = {
|
||||||
|
0x03,
|
||||||
|
0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,
|
||||||
|
0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd,
|
||||||
|
0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb,
|
||||||
|
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
|
||||||
|
};
|
||||||
|
|
||||||
|
/* create a context with no capabilities */
|
||||||
|
data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
data->scalar[i] = i + 1;
|
||||||
|
}
|
||||||
|
CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bench_ecdh(void* arg) {
|
||||||
|
int i;
|
||||||
|
unsigned char res[32];
|
||||||
|
bench_ecdh_t *data = (bench_ecdh_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
bench_ecdh_t data;
|
||||||
|
|
||||||
|
run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000);
|
||||||
|
return 0;
|
||||||
|
}
|
382
secp256k1zkp/depend/secp256k1-zkp/src/bench_internal.c
Normal file
382
secp256k1zkp/depend/secp256k1-zkp/src/bench_internal.c
Normal file
|
@ -0,0 +1,382 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2014-2015 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "include/secp256k1.h"
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "hash_impl.h"
|
||||||
|
#include "num_impl.h"
|
||||||
|
#include "field_impl.h"
|
||||||
|
#include "group_impl.h"
|
||||||
|
#include "scalar_impl.h"
|
||||||
|
#include "ecmult_const_impl.h"
|
||||||
|
#include "ecmult_impl.h"
|
||||||
|
#include "bench.h"
|
||||||
|
#include "secp256k1.c"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
secp256k1_scalar scalar_x, scalar_y;
|
||||||
|
secp256k1_fe fe_x, fe_y;
|
||||||
|
secp256k1_ge ge_x, ge_y;
|
||||||
|
secp256k1_gej gej_x, gej_y;
|
||||||
|
unsigned char data[64];
|
||||||
|
int wnaf[256];
|
||||||
|
} bench_inv_t;
|
||||||
|
|
||||||
|
void bench_setup(void* arg) {
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
static const unsigned char init_x[32] = {
|
||||||
|
0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13,
|
||||||
|
0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35,
|
||||||
|
0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59,
|
||||||
|
0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned char init_y[32] = {
|
||||||
|
0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83,
|
||||||
|
0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5,
|
||||||
|
0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9,
|
||||||
|
0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3
|
||||||
|
};
|
||||||
|
|
||||||
|
secp256k1_scalar_set_b32(&data->scalar_x, init_x, NULL);
|
||||||
|
secp256k1_scalar_set_b32(&data->scalar_y, init_y, NULL);
|
||||||
|
secp256k1_fe_set_b32(&data->fe_x, init_x);
|
||||||
|
secp256k1_fe_set_b32(&data->fe_y, init_y);
|
||||||
|
CHECK(secp256k1_ge_set_xo_var(&data->ge_x, &data->fe_x, 0));
|
||||||
|
CHECK(secp256k1_ge_set_xo_var(&data->ge_y, &data->fe_y, 1));
|
||||||
|
secp256k1_gej_set_ge(&data->gej_x, &data->ge_x);
|
||||||
|
secp256k1_gej_set_ge(&data->gej_y, &data->ge_y);
|
||||||
|
memcpy(data->data, init_x, 32);
|
||||||
|
memcpy(data->data + 32, init_y, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_scalar_add(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 2000000; i++) {
|
||||||
|
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_scalar_negate(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 2000000; i++) {
|
||||||
|
secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_scalar_sqr(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 200000; i++) {
|
||||||
|
secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_scalar_mul(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 200000; i++) {
|
||||||
|
secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
void bench_scalar_split(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
secp256k1_scalar l, r;
|
||||||
|
secp256k1_scalar_split_lambda(&l, &r, &data->scalar_x);
|
||||||
|
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void bench_scalar_inverse(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 2000; i++) {
|
||||||
|
secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x);
|
||||||
|
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_scalar_inverse_var(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 2000; i++) {
|
||||||
|
secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x);
|
||||||
|
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_field_normalize(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 2000000; i++) {
|
||||||
|
secp256k1_fe_normalize(&data->fe_x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_field_normalize_weak(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 2000000; i++) {
|
||||||
|
secp256k1_fe_normalize_weak(&data->fe_x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_field_mul(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 200000; i++) {
|
||||||
|
secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_field_sqr(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 200000; i++) {
|
||||||
|
secp256k1_fe_sqr(&data->fe_x, &data->fe_x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_field_inverse(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
secp256k1_fe_inv(&data->fe_x, &data->fe_x);
|
||||||
|
secp256k1_fe_add(&data->fe_x, &data->fe_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_field_inverse_var(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
secp256k1_fe_inv_var(&data->fe_x, &data->fe_x);
|
||||||
|
secp256k1_fe_add(&data->fe_x, &data->fe_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_field_sqrt(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
secp256k1_fe_sqrt(&data->fe_x, &data->fe_x);
|
||||||
|
secp256k1_fe_add(&data->fe_x, &data->fe_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_group_double_var(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 200000; i++) {
|
||||||
|
secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_group_add_var(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 200000; i++) {
|
||||||
|
secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_group_add_affine(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 200000; i++) {
|
||||||
|
secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_group_add_affine_var(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 200000; i++) {
|
||||||
|
secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_group_jacobi_var(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
secp256k1_gej_has_quad_y_var(&data->gej_x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_ecmult_wnaf(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A);
|
||||||
|
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_wnaf_const(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A);
|
||||||
|
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bench_sha256(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
secp256k1_sha256_t sha;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
secp256k1_sha256_initialize(&sha);
|
||||||
|
secp256k1_sha256_write(&sha, data->data, 32);
|
||||||
|
secp256k1_sha256_finalize(&sha, data->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_hmac_sha256(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
secp256k1_hmac_sha256_t hmac;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
secp256k1_hmac_sha256_initialize(&hmac, data->data, 32);
|
||||||
|
secp256k1_hmac_sha256_write(&hmac, data->data, 32);
|
||||||
|
secp256k1_hmac_sha256_finalize(&hmac, data->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_rfc6979_hmac_sha256(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
secp256k1_rfc6979_hmac_sha256_t rng;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64);
|
||||||
|
secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_context_verify(void* arg) {
|
||||||
|
int i;
|
||||||
|
(void)arg;
|
||||||
|
for (i = 0; i < 20; i++) {
|
||||||
|
secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_context_sign(void* arg) {
|
||||||
|
int i;
|
||||||
|
(void)arg;
|
||||||
|
for (i = 0; i < 200; i++) {
|
||||||
|
secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef USE_NUM_NONE
|
||||||
|
void bench_num_jacobi(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_inv_t *data = (bench_inv_t*)arg;
|
||||||
|
secp256k1_num nx, norder;
|
||||||
|
|
||||||
|
secp256k1_scalar_get_num(&nx, &data->scalar_x);
|
||||||
|
secp256k1_scalar_order_get_num(&norder);
|
||||||
|
secp256k1_scalar_get_num(&norder, &data->scalar_y);
|
||||||
|
|
||||||
|
for (i = 0; i < 200000; i++) {
|
||||||
|
secp256k1_num_jacobi(&nx, &norder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int have_flag(int argc, char** argv, char *flag) {
|
||||||
|
char** argm = argv + argc;
|
||||||
|
argv++;
|
||||||
|
if (argv == argm) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
while (argv != NULL && argv != argm) {
|
||||||
|
if (strcmp(*argv, flag) == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
bench_inv_t data;
|
||||||
|
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000);
|
||||||
|
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000);
|
||||||
|
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000);
|
||||||
|
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, 200000);
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, 20000);
|
||||||
|
#endif
|
||||||
|
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, 2000);
|
||||||
|
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, 2000);
|
||||||
|
|
||||||
|
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, 2000000);
|
||||||
|
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, 2000000);
|
||||||
|
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, 200000);
|
||||||
|
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000);
|
||||||
|
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000);
|
||||||
|
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000);
|
||||||
|
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000);
|
||||||
|
|
||||||
|
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000);
|
||||||
|
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000);
|
||||||
|
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000);
|
||||||
|
if (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, 200000);
|
||||||
|
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000);
|
||||||
|
|
||||||
|
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000);
|
||||||
|
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000);
|
||||||
|
|
||||||
|
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, 20000);
|
||||||
|
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, 20000);
|
||||||
|
if (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, 20000);
|
||||||
|
|
||||||
|
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20);
|
||||||
|
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200);
|
||||||
|
|
||||||
|
#ifndef USE_NUM_NONE
|
||||||
|
if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
65
secp256k1zkp/depend/secp256k1-zkp/src/bench_rangeproof.c
Normal file
65
secp256k1zkp/depend/secp256k1-zkp/src/bench_rangeproof.c
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* 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 <stdint.h>
|
||||||
|
|
||||||
|
#include "include/secp256k1_rangeproof.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "bench.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
secp256k1_context* ctx;
|
||||||
|
unsigned char commit[33];
|
||||||
|
unsigned char proof[5134];
|
||||||
|
unsigned char blind[32];
|
||||||
|
int 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(secp256k1_pedersen_commit(data->ctx, data->commit, data->blind, data->v));
|
||||||
|
data->len = 5134;
|
||||||
|
CHECK(secp256k1_rangeproof_sign(data->ctx, data->proof, &data->len, 0, data->commit, data->blind, data->commit, 0, data->min_bits, data->v));
|
||||||
|
CHECK(secp256k1_rangeproof_verify(data->ctx, &minv, &maxv, data->commit, data->proof, data->len));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bench_rangeproof(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_rangeproof_t *data = (bench_rangeproof_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 1000; i++) {
|
||||||
|
int j;
|
||||||
|
uint64_t minv;
|
||||||
|
uint64_t maxv;
|
||||||
|
j = secp256k1_rangeproof_verify(data->ctx, &minv, &maxv, data->commit, data->proof, data->len);
|
||||||
|
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;
|
||||||
|
|
||||||
|
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||||
|
secp256k1_pedersen_context_initialize(data.ctx);
|
||||||
|
secp256k1_rangeproof_context_initialize(data.ctx);
|
||||||
|
|
||||||
|
data.min_bits = 32;
|
||||||
|
|
||||||
|
run_benchmark("rangeproof_verify_bit", bench_rangeproof, bench_rangeproof_setup, NULL, &data, 10, 1000 * data.min_bits);
|
||||||
|
|
||||||
|
secp256k1_context_destroy(data.ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
60
secp256k1zkp/depend/secp256k1-zkp/src/bench_recover.c
Normal file
60
secp256k1zkp/depend/secp256k1-zkp/src/bench_recover.c
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2014-2015 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#include "include/secp256k1.h"
|
||||||
|
#include "include/secp256k1_recovery.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "bench.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
secp256k1_context *ctx;
|
||||||
|
unsigned char msg[32];
|
||||||
|
unsigned char sig[64];
|
||||||
|
} bench_recover_t;
|
||||||
|
|
||||||
|
void bench_recover(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_recover_t *data = (bench_recover_t*)arg;
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
unsigned char pubkeyc[33];
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
int j;
|
||||||
|
size_t pubkeylen = 33;
|
||||||
|
secp256k1_ecdsa_recoverable_signature sig;
|
||||||
|
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2));
|
||||||
|
CHECK(secp256k1_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg));
|
||||||
|
CHECK(secp256k1_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. */
|
||||||
|
data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_recover_setup(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_recover_t *data = (bench_recover_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
data->msg[i] = 1 + i;
|
||||||
|
}
|
||||||
|
for (i = 0; i < 64; i++) {
|
||||||
|
data->sig[i] = 65 + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
bench_recover_t data;
|
||||||
|
|
||||||
|
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
||||||
|
|
||||||
|
run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, 20000);
|
||||||
|
|
||||||
|
secp256k1_context_destroy(data.ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
73
secp256k1zkp/depend/secp256k1-zkp/src/bench_schnorr_verify.c
Normal file
73
secp256k1zkp/depend/secp256k1-zkp/src/bench_schnorr_verify.c
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "include/secp256k1.h"
|
||||||
|
#include "include/secp256k1_schnorr.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "bench.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char key[32];
|
||||||
|
unsigned char sig[64];
|
||||||
|
unsigned char pubkey[33];
|
||||||
|
size_t pubkeylen;
|
||||||
|
} benchmark_schnorr_sig_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
secp256k1_context *ctx;
|
||||||
|
unsigned char msg[32];
|
||||||
|
benchmark_schnorr_sig_t sigs[64];
|
||||||
|
int numsigs;
|
||||||
|
} benchmark_schnorr_verify_t;
|
||||||
|
|
||||||
|
static void benchmark_schnorr_init(void* arg) {
|
||||||
|
int i, k;
|
||||||
|
benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
data->msg[i] = 1 + i;
|
||||||
|
}
|
||||||
|
for (k = 0; k < data->numsigs; k++) {
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
data->sigs[k].key[i] = 33 + i + k;
|
||||||
|
}
|
||||||
|
secp256k1_schnorr_sign(data->ctx, data->sigs[k].sig, data->msg, data->sigs[k].key, NULL, NULL);
|
||||||
|
data->sigs[k].pubkeylen = 33;
|
||||||
|
CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->sigs[k].key));
|
||||||
|
CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->sigs[k].pubkey, &data->sigs[k].pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void benchmark_schnorr_verify(void* arg) {
|
||||||
|
int i;
|
||||||
|
benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000 / data->numsigs; i++) {
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF);
|
||||||
|
CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->sigs[0].pubkey, data->sigs[0].pubkeylen));
|
||||||
|
CHECK(secp256k1_schnorr_verify(data->ctx, data->sigs[0].sig, data->msg, &pubkey) == ((i & 0xFF) == 0));
|
||||||
|
data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
benchmark_schnorr_verify_t data;
|
||||||
|
|
||||||
|
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||||
|
|
||||||
|
data.numsigs = 1;
|
||||||
|
run_benchmark("schnorr_verify", benchmark_schnorr_verify, benchmark_schnorr_init, NULL, &data, 10, 20000);
|
||||||
|
|
||||||
|
secp256k1_context_destroy(data.ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
56
secp256k1zkp/depend/secp256k1-zkp/src/bench_sign.c
Normal file
56
secp256k1zkp/depend/secp256k1-zkp/src/bench_sign.c
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#include "include/secp256k1.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "bench.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
secp256k1_context* ctx;
|
||||||
|
unsigned char msg[32];
|
||||||
|
unsigned char key[32];
|
||||||
|
} bench_sign_t;
|
||||||
|
|
||||||
|
static void bench_sign_setup(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_sign_t *data = (bench_sign_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
data->msg[i] = i + 1;
|
||||||
|
}
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
data->key[i] = i + 65;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bench_sign(void* arg) {
|
||||||
|
int i;
|
||||||
|
bench_sign_t *data = (bench_sign_t*)arg;
|
||||||
|
|
||||||
|
unsigned char sig[74];
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
size_t siglen = 74;
|
||||||
|
int j;
|
||||||
|
secp256k1_ecdsa_signature signature;
|
||||||
|
CHECK(secp256k1_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL));
|
||||||
|
CHECK(secp256k1_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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
bench_sign_t data;
|
||||||
|
|
||||||
|
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||||
|
|
||||||
|
run_benchmark("ecdsa_sign", bench_sign, bench_sign_setup, NULL, &data, 10, 20000);
|
||||||
|
|
||||||
|
secp256k1_context_destroy(data.ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
112
secp256k1zkp/depend/secp256k1-zkp/src/bench_verify.c
Normal file
112
secp256k1zkp/depend/secp256k1-zkp/src/bench_verify.c
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "include/secp256k1.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "bench.h"
|
||||||
|
|
||||||
|
#ifdef ENABLE_OPENSSL_TESTS
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/ecdsa.h>
|
||||||
|
#include <openssl/obj_mac.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
secp256k1_context *ctx;
|
||||||
|
unsigned char msg[32];
|
||||||
|
unsigned char key[32];
|
||||||
|
unsigned char sig[72];
|
||||||
|
size_t siglen;
|
||||||
|
unsigned char pubkey[33];
|
||||||
|
size_t pubkeylen;
|
||||||
|
#ifdef ENABLE_OPENSSL_TESTS
|
||||||
|
EC_GROUP* ec_group;
|
||||||
|
#endif
|
||||||
|
} benchmark_verify_t;
|
||||||
|
|
||||||
|
static void benchmark_verify(void* arg) {
|
||||||
|
int i;
|
||||||
|
benchmark_verify_t* data = (benchmark_verify_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
secp256k1_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(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1);
|
||||||
|
CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1);
|
||||||
|
CHECK(secp256k1_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_OPENSSL_TESTS
|
||||||
|
static void benchmark_verify_openssl(void* arg) {
|
||||||
|
int i;
|
||||||
|
benchmark_verify_t* data = (benchmark_verify_t*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) {
|
||||||
|
data->sig[data->siglen - 1] ^= (i & 0xFF);
|
||||||
|
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
|
||||||
|
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
|
||||||
|
{
|
||||||
|
EC_KEY *pkey = EC_KEY_new();
|
||||||
|
const unsigned char *pubkey = &data->pubkey[0];
|
||||||
|
int result;
|
||||||
|
|
||||||
|
CHECK(pkey != NULL);
|
||||||
|
result = EC_KEY_set_group(pkey, data->ec_group);
|
||||||
|
CHECK(result);
|
||||||
|
result = (o2i_ECPublicKey(&pkey, &pubkey, data->pubkeylen)) != NULL;
|
||||||
|
CHECK(result);
|
||||||
|
result = ECDSA_verify(0, &data->msg[0], sizeof(data->msg), &data->sig[0], data->siglen, pkey) == (i == 0);
|
||||||
|
CHECK(result);
|
||||||
|
EC_KEY_free(pkey);
|
||||||
|
}
|
||||||
|
data->sig[data->siglen - 1] ^= (i & 0xFF);
|
||||||
|
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
|
||||||
|
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int i;
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
secp256k1_ecdsa_signature sig;
|
||||||
|
benchmark_verify_t data;
|
||||||
|
|
||||||
|
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||||
|
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
data.msg[i] = 1 + i;
|
||||||
|
}
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
data.key[i] = 33 + i;
|
||||||
|
}
|
||||||
|
data.siglen = 72;
|
||||||
|
CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL));
|
||||||
|
CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig));
|
||||||
|
CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key));
|
||||||
|
data.pubkeylen = 33;
|
||||||
|
CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
|
||||||
|
|
||||||
|
run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000);
|
||||||
|
#ifdef ENABLE_OPENSSL_TESTS
|
||||||
|
data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1);
|
||||||
|
run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000);
|
||||||
|
EC_GROUP_free(data.ec_group);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
secp256k1_context_destroy(data.ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
21
secp256k1zkp/depend/secp256k1-zkp/src/ecdsa.h
Normal file
21
secp256k1zkp/depend/secp256k1-zkp/src/ecdsa.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_ECDSA_
|
||||||
|
#define _SECP256K1_ECDSA_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "scalar.h"
|
||||||
|
#include "group.h"
|
||||||
|
#include "ecmult.h"
|
||||||
|
|
||||||
|
static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *r, secp256k1_scalar *s, const unsigned char *sig, size_t size);
|
||||||
|
static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar *r, const secp256k1_scalar *s);
|
||||||
|
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message);
|
||||||
|
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid);
|
||||||
|
|
||||||
|
#endif
|
303
secp256k1zkp/depend/secp256k1-zkp/src/ecdsa_impl.h
Normal file
303
secp256k1zkp/depend/secp256k1-zkp/src/ecdsa_impl.h
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013-2015 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_ECDSA_IMPL_H_
|
||||||
|
#define _SECP256K1_ECDSA_IMPL_H_
|
||||||
|
|
||||||
|
#include "scalar.h"
|
||||||
|
#include "field.h"
|
||||||
|
#include "group.h"
|
||||||
|
#include "ecmult.h"
|
||||||
|
#include "ecmult_gen.h"
|
||||||
|
#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'
|
||||||
|
*/
|
||||||
|
static const secp256k1_fe secp256k1_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'
|
||||||
|
*/
|
||||||
|
static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST(
|
||||||
|
0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL
|
||||||
|
);
|
||||||
|
|
||||||
|
static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned char *sigend) {
|
||||||
|
int lenleft, b1;
|
||||||
|
size_t ret = 0;
|
||||||
|
if (*sigp >= sigend) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
b1 = *((*sigp)++);
|
||||||
|
if (b1 == 0xFF) {
|
||||||
|
/* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((b1 & 0x80) == 0) {
|
||||||
|
/* X.690-0207 8.1.3.4 short form length octets */
|
||||||
|
return b1;
|
||||||
|
}
|
||||||
|
if (b1 == 0x80) {
|
||||||
|
/* Indefinite length is not allowed in DER. */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* X.690-207 8.1.3.5 long form length octets */
|
||||||
|
lenleft = b1 & 0x7F;
|
||||||
|
if (lenleft > sigend - *sigp) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (**sigp == 0) {
|
||||||
|
/* Not the shortest possible length encoding. */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((size_t)lenleft > sizeof(size_t)) {
|
||||||
|
/* The resulting length would exceed the range of a size_t, so
|
||||||
|
* certainly longer than the passed array size.
|
||||||
|
*/
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
while (lenleft > 0) {
|
||||||
|
if ((ret >> ((sizeof(size_t) - 1) * 8)) != 0) {
|
||||||
|
}
|
||||||
|
ret = (ret << 8) | **sigp;
|
||||||
|
if (ret + lenleft > (size_t)(sigend - *sigp)) {
|
||||||
|
/* Result exceeds the length of the passed array. */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
(*sigp)++;
|
||||||
|
lenleft--;
|
||||||
|
}
|
||||||
|
if (ret < 128) {
|
||||||
|
/* Not the shortest possible length encoding. */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) {
|
||||||
|
int overflow = 0;
|
||||||
|
unsigned char ra[32] = {0};
|
||||||
|
int rlen;
|
||||||
|
|
||||||
|
if (*sig == sigend || **sig != 0x02) {
|
||||||
|
/* Not a primitive integer (X.690-0207 8.3.1). */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
(*sig)++;
|
||||||
|
rlen = secp256k1_der_read_len(sig, sigend);
|
||||||
|
if (rlen <= 0 || (*sig) + rlen > sigend) {
|
||||||
|
/* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) {
|
||||||
|
/* Excessive 0x00 padding. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) {
|
||||||
|
/* Excessive 0xFF padding. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ((**sig & 0x80) == 0x80) {
|
||||||
|
/* Negative. */
|
||||||
|
overflow = 1;
|
||||||
|
}
|
||||||
|
while (rlen > 0 && **sig == 0) {
|
||||||
|
/* Skip leading zero bytes */
|
||||||
|
rlen--;
|
||||||
|
(*sig)++;
|
||||||
|
}
|
||||||
|
if (rlen > 32) {
|
||||||
|
overflow = 1;
|
||||||
|
}
|
||||||
|
if (!overflow) {
|
||||||
|
memcpy(ra + 32 - rlen, *sig, rlen);
|
||||||
|
secp256k1_scalar_set_b32(r, ra, &overflow);
|
||||||
|
}
|
||||||
|
if (overflow) {
|
||||||
|
secp256k1_scalar_set_int(r, 0);
|
||||||
|
}
|
||||||
|
(*sig) += rlen;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) {
|
||||||
|
const unsigned char *sigend = sig + size;
|
||||||
|
int rlen;
|
||||||
|
if (sig == sigend || *(sig++) != 0x30) {
|
||||||
|
/* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rlen = secp256k1_der_read_len(&sig, sigend);
|
||||||
|
if (rlen < 0 || sig + rlen > sigend) {
|
||||||
|
/* Tuple exceeds bounds */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (sig + rlen != sigend) {
|
||||||
|
/* Garbage after tuple. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!secp256k1_der_parse_integer(rr, &sig, sigend)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!secp256k1_der_parse_integer(rs, &sig, sigend)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sig != sigend) {
|
||||||
|
/* Trailing garbage inside tuple. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar* ar, const secp256k1_scalar* as) {
|
||||||
|
unsigned char r[33] = {0}, s[33] = {0};
|
||||||
|
unsigned char *rp = r, *sp = s;
|
||||||
|
size_t lenR = 33, lenS = 33;
|
||||||
|
secp256k1_scalar_get_b32(&r[1], ar);
|
||||||
|
secp256k1_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) {
|
||||||
|
*size = 6 + lenS + lenR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*size = 6 + lenS + lenR;
|
||||||
|
sig[0] = 0x30;
|
||||||
|
sig[1] = 4 + lenS + lenR;
|
||||||
|
sig[2] = 0x02;
|
||||||
|
sig[3] = lenR;
|
||||||
|
memcpy(sig+4, rp, lenR);
|
||||||
|
sig[4+lenR] = 0x02;
|
||||||
|
sig[5+lenR] = lenS;
|
||||||
|
memcpy(sig+lenR+6, sp, lenS);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) {
|
||||||
|
unsigned char c[32];
|
||||||
|
secp256k1_scalar sn, u1, u2;
|
||||||
|
secp256k1_fe xr;
|
||||||
|
secp256k1_gej pubkeyj;
|
||||||
|
secp256k1_gej pr;
|
||||||
|
|
||||||
|
if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
secp256k1_scalar_inverse_var(&sn, sigs);
|
||||||
|
secp256k1_scalar_mul(&u1, &sn, message);
|
||||||
|
secp256k1_scalar_mul(&u2, &sn, sigr);
|
||||||
|
secp256k1_gej_set_ge(&pubkeyj, pubkey);
|
||||||
|
secp256k1_ecmult(ctx, &pr, &pubkeyj, &u2, &u1);
|
||||||
|
if (secp256k1_gej_is_infinity(&pr)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
secp256k1_scalar_get_b32(c, sigr);
|
||||||
|
secp256k1_fe_set_b32(&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),
|
||||||
|
* compute the remainder modulo n, and compare it to xr. However:
|
||||||
|
*
|
||||||
|
* xr == X(pr) mod n
|
||||||
|
* <=> exists h. (xr + h * n < p && xr + h * n == X(pr))
|
||||||
|
* [Since 2 * n > p, h can only be 0 or 1]
|
||||||
|
* <=> (xr == X(pr)) || (xr + n < p && xr + n == X(pr))
|
||||||
|
* [In Jacobian coordinates, X(pr) is pr.x / pr.z^2 mod p]
|
||||||
|
* <=> (xr == pr.x / pr.z^2 mod p) || (xr + n < p && xr + n == pr.x / pr.z^2 mod p)
|
||||||
|
* [Multiplying both sides of the equations by pr.z^2 mod p]
|
||||||
|
* <=> (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.
|
||||||
|
* secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test.
|
||||||
|
*/
|
||||||
|
if (secp256k1_gej_eq_x_var(&xr, &pr)) {
|
||||||
|
/* xr * pr.z^2 mod p == pr.x, so the signature is valid. */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
|
||||||
|
/* xr + n >= p, so we can skip testing the second case. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe);
|
||||||
|
if (secp256k1_gej_eq_x_var(&xr, &pr)) {
|
||||||
|
/* (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid. */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) {
|
||||||
|
unsigned char b[32];
|
||||||
|
secp256k1_gej rp;
|
||||||
|
secp256k1_ge r;
|
||||||
|
secp256k1_scalar n;
|
||||||
|
int overflow = 0;
|
||||||
|
|
||||||
|
secp256k1_ecmult_gen(ctx, &rp, nonce);
|
||||||
|
secp256k1_ge_set_gej(&r, &rp);
|
||||||
|
secp256k1_fe_normalize(&r.x);
|
||||||
|
secp256k1_fe_normalize(&r.y);
|
||||||
|
secp256k1_fe_get_b32(b, &r.x);
|
||||||
|
secp256k1_scalar_set_b32(sigr, b, &overflow);
|
||||||
|
if (secp256k1_scalar_is_zero(sigr)) {
|
||||||
|
/* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature.
|
||||||
|
* This branch is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N.
|
||||||
|
*/
|
||||||
|
secp256k1_gej_clear(&rp);
|
||||||
|
secp256k1_ge_clear(&r);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
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 ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
|
||||||
|
}
|
||||||
|
secp256k1_scalar_mul(&n, sigr, seckey);
|
||||||
|
secp256k1_scalar_add(&n, &n, message);
|
||||||
|
secp256k1_scalar_inverse(sigs, nonce);
|
||||||
|
secp256k1_scalar_mul(sigs, sigs, &n);
|
||||||
|
secp256k1_scalar_clear(&n);
|
||||||
|
secp256k1_gej_clear(&rp);
|
||||||
|
secp256k1_ge_clear(&r);
|
||||||
|
if (secp256k1_scalar_is_zero(sigs)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (secp256k1_scalar_is_high(sigs)) {
|
||||||
|
secp256k1_scalar_negate(sigs, sigs);
|
||||||
|
if (recid) {
|
||||||
|
*recid ^= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
25
secp256k1zkp/depend/secp256k1-zkp/src/eckey.h
Normal file
25
secp256k1zkp/depend/secp256k1-zkp/src/eckey.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_ECKEY_
|
||||||
|
#define _SECP256K1_ECKEY_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "group.h"
|
||||||
|
#include "scalar.h"
|
||||||
|
#include "ecmult.h"
|
||||||
|
#include "ecmult_gen.h"
|
||||||
|
|
||||||
|
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size);
|
||||||
|
static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed);
|
||||||
|
|
||||||
|
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak);
|
||||||
|
static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak);
|
||||||
|
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak);
|
||||||
|
static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak);
|
||||||
|
|
||||||
|
#endif
|
99
secp256k1zkp/depend/secp256k1-zkp/src/eckey_impl.h
Normal file
99
secp256k1zkp/depend/secp256k1-zkp/src/eckey_impl.h
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://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 secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {
|
||||||
|
if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
|
||||||
|
secp256k1_fe x;
|
||||||
|
return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03);
|
||||||
|
} else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
|
||||||
|
secp256k1_fe x, y;
|
||||||
|
if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
secp256k1_ge_set_xy(elem, &x, &y);
|
||||||
|
if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return secp256k1_ge_is_valid_var(elem);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) {
|
||||||
|
if (secp256k1_ge_is_infinity(elem)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
secp256k1_fe_normalize_var(&elem->x);
|
||||||
|
secp256k1_fe_normalize_var(&elem->y);
|
||||||
|
secp256k1_fe_get_b32(&pub[1], &elem->x);
|
||||||
|
if (compressed) {
|
||||||
|
*size = 33;
|
||||||
|
pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00);
|
||||||
|
} else {
|
||||||
|
*size = 65;
|
||||||
|
pub[0] = 0x04;
|
||||||
|
secp256k1_fe_get_b32(&pub[33], &elem->y);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
|
||||||
|
secp256k1_scalar_add(key, key, tweak);
|
||||||
|
if (secp256k1_scalar_is_zero(key)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) {
|
||||||
|
secp256k1_gej pt;
|
||||||
|
secp256k1_scalar one;
|
||||||
|
secp256k1_gej_set_ge(&pt, key);
|
||||||
|
secp256k1_scalar_set_int(&one, 1);
|
||||||
|
secp256k1_ecmult(ctx, &pt, &pt, &one, tweak);
|
||||||
|
|
||||||
|
if (secp256k1_gej_is_infinity(&pt)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
secp256k1_ge_set_gej(key, &pt);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
|
||||||
|
if (secp256k1_scalar_is_zero(tweak)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
secp256k1_scalar_mul(key, key, tweak);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) {
|
||||||
|
secp256k1_scalar zero;
|
||||||
|
secp256k1_gej pt;
|
||||||
|
if (secp256k1_scalar_is_zero(tweak)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
secp256k1_scalar_set_int(&zero, 0);
|
||||||
|
secp256k1_gej_set_ge(&pt, key);
|
||||||
|
secp256k1_ecmult(ctx, &pt, &pt, tweak, &zero);
|
||||||
|
secp256k1_ge_set_gej(key, &pt);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
31
secp256k1zkp/depend/secp256k1-zkp/src/ecmult.h
Normal file
31
secp256k1zkp/depend/secp256k1-zkp/src/ecmult.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_ECMULT_
|
||||||
|
#define _SECP256K1_ECMULT_
|
||||||
|
|
||||||
|
#include "num.h"
|
||||||
|
#include "group.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* For accelerating the computation of a*P + b*G: */
|
||||||
|
secp256k1_ge_storage (*pre_g)[]; /* odd multiples of the generator */
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */
|
||||||
|
#endif
|
||||||
|
} secp256k1_ecmult_context;
|
||||||
|
|
||||||
|
static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx);
|
||||||
|
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb);
|
||||||
|
static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst,
|
||||||
|
const secp256k1_ecmult_context *src, const secp256k1_callback *cb);
|
||||||
|
static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx);
|
||||||
|
static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx);
|
||||||
|
|
||||||
|
/** Double multiply: R = na*A + ng*G */
|
||||||
|
static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng);
|
||||||
|
|
||||||
|
#endif
|
15
secp256k1zkp/depend/secp256k1-zkp/src/ecmult_const.h
Normal file
15
secp256k1zkp/depend/secp256k1-zkp/src/ecmult_const.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2015 Andrew Poelstra *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_ECMULT_CONST_
|
||||||
|
#define _SECP256K1_ECMULT_CONST_
|
||||||
|
|
||||||
|
#include "scalar.h"
|
||||||
|
#include "group.h"
|
||||||
|
|
||||||
|
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
|
||||||
|
|
||||||
|
#endif
|
239
secp256k1zkp/depend/secp256k1-zkp/src/ecmult_const_impl.h
Normal file
239
secp256k1zkp/depend/secp256k1-zkp/src/ecmult_const_impl.h
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2015 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_ECMULT_CONST_IMPL_
|
||||||
|
#define _SECP256K1_ECMULT_CONST_IMPL_
|
||||||
|
|
||||||
|
#include "scalar.h"
|
||||||
|
#include "group.h"
|
||||||
|
#include "ecmult_const.h"
|
||||||
|
#include "ecmult_impl.h"
|
||||||
|
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
#define WNAF_BITS 128
|
||||||
|
#else
|
||||||
|
#define WNAF_BITS 256
|
||||||
|
#endif
|
||||||
|
#define WNAF_SIZE(w) ((WNAF_BITS + (w) - 1) / (w))
|
||||||
|
|
||||||
|
/* This is like `ECMULT_TABLE_GET_GE` but is constant time */
|
||||||
|
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
|
||||||
|
int m; \
|
||||||
|
int abs_n = (n) * (((n) > 0) * 2 - 1); \
|
||||||
|
int idx_n = abs_n / 2; \
|
||||||
|
secp256k1_fe neg_y; \
|
||||||
|
VERIFY_CHECK(((n) & 1) == 1); \
|
||||||
|
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
|
||||||
|
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
|
||||||
|
VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \
|
||||||
|
VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \
|
||||||
|
for (m = 0; 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. */ \
|
||||||
|
secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \
|
||||||
|
secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \
|
||||||
|
} \
|
||||||
|
(r)->infinity = 0; \
|
||||||
|
secp256k1_fe_negate(&neg_y, &(r)->y, 1); \
|
||||||
|
secp256k1_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..return_val)
|
||||||
|
* with 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 returned; this is always (WNAF_BITS + w - 1) / w
|
||||||
|
*
|
||||||
|
* 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-Verlagy Berlin Heidelberg 2003
|
||||||
|
*
|
||||||
|
* Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335
|
||||||
|
*/
|
||||||
|
static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
|
||||||
|
int global_sign;
|
||||||
|
int skew = 0;
|
||||||
|
int word = 0;
|
||||||
|
|
||||||
|
/* 1 2 3 */
|
||||||
|
int u_last;
|
||||||
|
int u;
|
||||||
|
|
||||||
|
int flip;
|
||||||
|
int bit;
|
||||||
|
secp256k1_scalar neg_s;
|
||||||
|
int not_neg_one;
|
||||||
|
/* 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 technique from
|
||||||
|
* Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even)
|
||||||
|
* or 2 (for odd) to the number we are encoding, returning a skew value indicating
|
||||||
|
* this, and having the caller compensate after doing the multiplication. */
|
||||||
|
|
||||||
|
/* Negative numbers will be negated to keep their bit representation below the maximum width */
|
||||||
|
flip = secp256k1_scalar_is_high(&s);
|
||||||
|
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
|
||||||
|
bit = flip ^ (s.d[0] & 1);
|
||||||
|
/* We check for negative one, since adding 2 to it will cause an overflow */
|
||||||
|
secp256k1_scalar_negate(&neg_s, &s);
|
||||||
|
not_neg_one = !secp256k1_scalar_is_one(&neg_s);
|
||||||
|
secp256k1_scalar_cadd_bit(&s, bit, not_neg_one);
|
||||||
|
/* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects
|
||||||
|
* that we added two to it and flipped it. In fact for -1 these operations are
|
||||||
|
* identical. We only flipped, but since skewing is required (in the sense that
|
||||||
|
* the skew must be 1 or 2, never zero) and flipping is not, we need to change
|
||||||
|
* our flags to claim that we only skewed. */
|
||||||
|
global_sign = secp256k1_scalar_cond_negate(&s, flip);
|
||||||
|
global_sign *= not_neg_one * 2 - 1;
|
||||||
|
skew = 1 << bit;
|
||||||
|
|
||||||
|
/* 4 */
|
||||||
|
u_last = secp256k1_scalar_shr_int(&s, w);
|
||||||
|
while (word * w < WNAF_BITS) {
|
||||||
|
int sign;
|
||||||
|
int even;
|
||||||
|
|
||||||
|
/* 4.1 4.4 */
|
||||||
|
u = secp256k1_scalar_shr_int(&s, w);
|
||||||
|
/* 4.2 */
|
||||||
|
even = ((u & 1) == 0);
|
||||||
|
sign = 2 * (u_last > 0) - 1;
|
||||||
|
u += sign * even;
|
||||||
|
u_last -= sign * even * (1 << w);
|
||||||
|
|
||||||
|
/* 4.3, adapted for global sign change */
|
||||||
|
wnaf[word++] = u_last * global_sign;
|
||||||
|
|
||||||
|
u_last = u;
|
||||||
|
}
|
||||||
|
wnaf[word] = u * global_sign;
|
||||||
|
|
||||||
|
VERIFY_CHECK(secp256k1_scalar_is_zero(&s));
|
||||||
|
VERIFY_CHECK(word == WNAF_SIZE(w));
|
||||||
|
return skew;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) {
|
||||||
|
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||||
|
secp256k1_ge tmpa;
|
||||||
|
secp256k1_fe Z;
|
||||||
|
|
||||||
|
int skew_1;
|
||||||
|
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||||
|
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||||
|
int skew_lam;
|
||||||
|
secp256k1_scalar q_1, q_lam;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int i;
|
||||||
|
secp256k1_scalar sc = *scalar;
|
||||||
|
|
||||||
|
/* build wnaf representation for q. */
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
|
||||||
|
secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);
|
||||||
|
skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1);
|
||||||
|
skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1);
|
||||||
|
#else
|
||||||
|
skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
secp256k1_gej_set_ge(r, a);
|
||||||
|
secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r);
|
||||||
|
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
||||||
|
secp256k1_fe_normalize_weak(&pre_a[i].y);
|
||||||
|
}
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
||||||
|
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 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(WINDOW_A - 1)];
|
||||||
|
VERIFY_CHECK(i != 0);
|
||||||
|
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
|
||||||
|
secp256k1_gej_set_ge(r, &tmpa);
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)];
|
||||||
|
VERIFY_CHECK(i != 0);
|
||||||
|
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
|
||||||
|
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||||
|
#endif
|
||||||
|
/* remaining loop iterations */
|
||||||
|
for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) {
|
||||||
|
int n;
|
||||||
|
int j;
|
||||||
|
for (j = 0; j < WINDOW_A - 1; ++j) {
|
||||||
|
secp256k1_gej_double_nonzero(r, r, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
n = wnaf_1[i];
|
||||||
|
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
|
||||||
|
VERIFY_CHECK(n != 0);
|
||||||
|
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
n = wnaf_lam[i];
|
||||||
|
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
|
||||||
|
VERIFY_CHECK(n != 0);
|
||||||
|
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
secp256k1_fe_mul(&r->z, &r->z, &Z);
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Correct for wNAF skew */
|
||||||
|
secp256k1_ge correction = *a;
|
||||||
|
secp256k1_ge_storage correction_1_stor;
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
secp256k1_ge_storage correction_lam_stor;
|
||||||
|
#endif
|
||||||
|
secp256k1_ge_storage a2_stor;
|
||||||
|
secp256k1_gej tmpj;
|
||||||
|
secp256k1_gej_set_ge(&tmpj, &correction);
|
||||||
|
secp256k1_gej_double_var(&tmpj, &tmpj, NULL);
|
||||||
|
secp256k1_ge_set_gej(&correction, &tmpj);
|
||||||
|
secp256k1_ge_to_storage(&correction_1_stor, a);
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
secp256k1_ge_to_storage(&correction_lam_stor, a);
|
||||||
|
#endif
|
||||||
|
secp256k1_ge_to_storage(&a2_stor, &correction);
|
||||||
|
|
||||||
|
/* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */
|
||||||
|
secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2);
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Apply the correction */
|
||||||
|
secp256k1_ge_from_storage(&correction, &correction_1_stor);
|
||||||
|
secp256k1_ge_neg(&correction, &correction);
|
||||||
|
secp256k1_gej_add_ge(r, r, &correction);
|
||||||
|
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
secp256k1_ge_from_storage(&correction, &correction_lam_stor);
|
||||||
|
secp256k1_ge_neg(&correction, &correction);
|
||||||
|
secp256k1_ge_mul_lambda(&correction, &correction);
|
||||||
|
secp256k1_gej_add_ge(r, r, &correction);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
43
secp256k1zkp/depend/secp256k1-zkp/src/ecmult_gen.h
Normal file
43
secp256k1zkp/depend/secp256k1-zkp/src/ecmult_gen.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_ECMULT_GEN_
|
||||||
|
#define _SECP256K1_ECMULT_GEN_
|
||||||
|
|
||||||
|
#include "scalar.h"
|
||||||
|
#include "group.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* For accelerating the computation of a*G:
|
||||||
|
* To harden against timing attacks, use the following mechanism:
|
||||||
|
* * Break up the multiplicand into groups of 4 bits, called n_0, n_1, n_2, ..., n_63.
|
||||||
|
* * Compute sum(n_i * 16^i * G + U_i, i=0..63), where:
|
||||||
|
* * U_i = U * 2^i (for i=0..62)
|
||||||
|
* * U_i = U * (1-2^63) (for i=63)
|
||||||
|
* where U is a point with no known corresponding scalar. Note that sum(U_i, i=0..63) = 0.
|
||||||
|
* For each i, and each of the 16 possible values of n_i, (n_i * 16^i * G + U_i) is
|
||||||
|
* precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63).
|
||||||
|
* None of the resulting prec group elements have a known scalar, and neither do any of
|
||||||
|
* the intermediate sums while computing a*G.
|
||||||
|
*/
|
||||||
|
secp256k1_ge_storage (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */
|
||||||
|
secp256k1_scalar blind;
|
||||||
|
secp256k1_gej initial;
|
||||||
|
} secp256k1_ecmult_gen_context;
|
||||||
|
|
||||||
|
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx);
|
||||||
|
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_callback* cb);
|
||||||
|
static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst,
|
||||||
|
const secp256k1_ecmult_gen_context* src, const secp256k1_callback* cb);
|
||||||
|
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx);
|
||||||
|
static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx);
|
||||||
|
|
||||||
|
/** Multiply with the generator: R = a*G */
|
||||||
|
static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a);
|
||||||
|
|
||||||
|
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32);
|
||||||
|
|
||||||
|
#endif
|
210
secp256k1zkp/depend/secp256k1-zkp/src/ecmult_gen_impl.h
Normal file
210
secp256k1zkp/depend/secp256k1-zkp/src/ecmult_gen_impl.h
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 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.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_ECMULT_GEN_IMPL_H_
|
||||||
|
#define _SECP256K1_ECMULT_GEN_IMPL_H_
|
||||||
|
|
||||||
|
#include "scalar.h"
|
||||||
|
#include "group.h"
|
||||||
|
#include "ecmult_gen.h"
|
||||||
|
#include "hash_impl.h"
|
||||||
|
#ifdef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||||
|
#include "ecmult_static_context.h"
|
||||||
|
#endif
|
||||||
|
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) {
|
||||||
|
ctx->prec = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_callback* cb) {
|
||||||
|
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||||
|
secp256k1_ge prec[1024];
|
||||||
|
secp256k1_gej gj;
|
||||||
|
secp256k1_gej nums_gej;
|
||||||
|
int i, j;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ctx->prec != NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||||
|
ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec));
|
||||||
|
|
||||||
|
/* get the generator */
|
||||||
|
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
|
||||||
|
|
||||||
|
/* 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";
|
||||||
|
secp256k1_fe nums_x;
|
||||||
|
secp256k1_ge nums_ge;
|
||||||
|
int r;
|
||||||
|
r = secp256k1_fe_set_b32(&nums_x, nums_b32);
|
||||||
|
(void)r;
|
||||||
|
VERIFY_CHECK(r);
|
||||||
|
r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0);
|
||||||
|
(void)r;
|
||||||
|
VERIFY_CHECK(r);
|
||||||
|
secp256k1_gej_set_ge(&nums_gej, &nums_ge);
|
||||||
|
/* Add G to make the bits in x uniformly distributed. */
|
||||||
|
secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compute prec. */
|
||||||
|
{
|
||||||
|
secp256k1_gej precj[1024]; /* Jacobian versions of prec. */
|
||||||
|
secp256k1_gej gbase;
|
||||||
|
secp256k1_gej numsbase;
|
||||||
|
gbase = gj; /* 16^j * G */
|
||||||
|
numsbase = nums_gej; /* 2^j * nums. */
|
||||||
|
for (j = 0; j < 64; j++) {
|
||||||
|
/* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */
|
||||||
|
precj[j*16] = numsbase;
|
||||||
|
for (i = 1; i < 16; i++) {
|
||||||
|
secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL);
|
||||||
|
}
|
||||||
|
/* Multiply gbase by 16. */
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
secp256k1_gej_double_var(&gbase, &gbase, NULL);
|
||||||
|
}
|
||||||
|
/* Multiply numbase by 2. */
|
||||||
|
secp256k1_gej_double_var(&numsbase, &numsbase, NULL);
|
||||||
|
if (j == 62) {
|
||||||
|
/* In the last iteration, numsbase is (1 - 2^j) * nums instead. */
|
||||||
|
secp256k1_gej_neg(&numsbase, &numsbase);
|
||||||
|
secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
secp256k1_ge_set_all_gej_var(1024, prec, precj, cb);
|
||||||
|
}
|
||||||
|
for (j = 0; j < 64; j++) {
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)cb;
|
||||||
|
ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context;
|
||||||
|
#endif
|
||||||
|
secp256k1_ecmult_gen_blind(ctx, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) {
|
||||||
|
return ctx->prec != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst,
|
||||||
|
const secp256k1_ecmult_gen_context *src, const secp256k1_callback* cb) {
|
||||||
|
if (src->prec == NULL) {
|
||||||
|
dst->prec = NULL;
|
||||||
|
} else {
|
||||||
|
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||||
|
dst->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*dst->prec));
|
||||||
|
memcpy(dst->prec, src->prec, sizeof(*dst->prec));
|
||||||
|
#else
|
||||||
|
(void)cb;
|
||||||
|
dst->prec = src->prec;
|
||||||
|
#endif
|
||||||
|
dst->initial = src->initial;
|
||||||
|
dst->blind = src->blind;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) {
|
||||||
|
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||||
|
free(ctx->prec);
|
||||||
|
#endif
|
||||||
|
secp256k1_scalar_clear(&ctx->blind);
|
||||||
|
secp256k1_gej_clear(&ctx->initial);
|
||||||
|
ctx->prec = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) {
|
||||||
|
secp256k1_ge add;
|
||||||
|
secp256k1_ge_storage adds;
|
||||||
|
secp256k1_scalar gnb;
|
||||||
|
int bits;
|
||||||
|
int i, j;
|
||||||
|
memset(&adds, 0, sizeof(adds));
|
||||||
|
*r = ctx->initial;
|
||||||
|
/* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */
|
||||||
|
secp256k1_scalar_add(&gnb, gn, &ctx->blind);
|
||||||
|
add.infinity = 0;
|
||||||
|
for (j = 0; j < 64; j++) {
|
||||||
|
bits = secp256k1_scalar_get_bits(&gnb, j * 4, 4);
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
/** 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
|
||||||
|
* (http://www.tau.ac.il/~tromer/papers/cache.pdf)
|
||||||
|
*/
|
||||||
|
secp256k1_ge_storage_cmov(&adds, &(*ctx->prec)[j][i], i == bits);
|
||||||
|
}
|
||||||
|
secp256k1_ge_from_storage(&add, &adds);
|
||||||
|
secp256k1_gej_add_ge(r, r, &add);
|
||||||
|
}
|
||||||
|
bits = 0;
|
||||||
|
secp256k1_ge_clear(&add);
|
||||||
|
secp256k1_scalar_clear(&gnb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup blinding values for secp256k1_ecmult_gen. */
|
||||||
|
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) {
|
||||||
|
secp256k1_scalar b;
|
||||||
|
secp256k1_gej gb;
|
||||||
|
secp256k1_fe s;
|
||||||
|
unsigned char nonce32[32];
|
||||||
|
secp256k1_rfc6979_hmac_sha256_t rng;
|
||||||
|
int retry;
|
||||||
|
unsigned char keydata[64] = {0};
|
||||||
|
if (seed32 == NULL) {
|
||||||
|
/* When seed is NULL, reset the initial point and blinding value. */
|
||||||
|
secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g);
|
||||||
|
secp256k1_gej_neg(&ctx->initial, &ctx->initial);
|
||||||
|
secp256k1_scalar_set_int(&ctx->blind, 1);
|
||||||
|
}
|
||||||
|
/* The prior blinding value (if not reset) is chained forward by including it in the hash. */
|
||||||
|
secp256k1_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);
|
||||||
|
}
|
||||||
|
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32);
|
||||||
|
memset(keydata, 0, sizeof(keydata));
|
||||||
|
/* Retry for out of range results to achieve uniformity. */
|
||||||
|
do {
|
||||||
|
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||||
|
retry = !secp256k1_fe_set_b32(&s, nonce32);
|
||||||
|
retry |= secp256k1_fe_is_zero(&s);
|
||||||
|
} while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */
|
||||||
|
/* Randomize the projection to defend against multiplier sidechannels. */
|
||||||
|
secp256k1_gej_rescale(&ctx->initial, &s);
|
||||||
|
secp256k1_fe_clear(&s);
|
||||||
|
do {
|
||||||
|
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||||
|
secp256k1_scalar_set_b32(&b, nonce32, &retry);
|
||||||
|
/* A blinding value of 0 works, but would undermine the projection hardening. */
|
||||||
|
retry |= secp256k1_scalar_is_zero(&b);
|
||||||
|
} while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */
|
||||||
|
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
||||||
|
memset(nonce32, 0, 32);
|
||||||
|
secp256k1_ecmult_gen(ctx, &gb, &b);
|
||||||
|
secp256k1_scalar_negate(&b, &b);
|
||||||
|
ctx->blind = b;
|
||||||
|
ctx->initial = gb;
|
||||||
|
secp256k1_scalar_clear(&b);
|
||||||
|
secp256k1_gej_clear(&gb);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
389
secp256k1zkp/depend/secp256k1-zkp/src/ecmult_impl.h
Normal file
389
secp256k1zkp/depend/secp256k1-zkp/src/ecmult_impl.h
Normal file
|
@ -0,0 +1,389 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_ECMULT_IMPL_H_
|
||||||
|
#define _SECP256K1_ECMULT_IMPL_H_
|
||||||
|
|
||||||
|
#include "group.h"
|
||||||
|
#include "scalar.h"
|
||||||
|
#include "ecmult.h"
|
||||||
|
|
||||||
|
/* optimal for 128-bit and 256-bit exponents. */
|
||||||
|
#define WINDOW_A 5
|
||||||
|
|
||||||
|
/** larger numbers may result in slightly better performance, at the cost of
|
||||||
|
exponentially larger precomputed tables. */
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
/** Two tables for window size 15: 1.375 MiB. */
|
||||||
|
#define WINDOW_G 15
|
||||||
|
#else
|
||||||
|
/** One table for window size 16: 1.375 MiB. */
|
||||||
|
#define WINDOW_G 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** The number of entries a table with precomputed multiples needs to have. */
|
||||||
|
#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2))
|
||||||
|
|
||||||
|
/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain
|
||||||
|
* the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will
|
||||||
|
* contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z.
|
||||||
|
* Prej's Z values are undefined, except for the last value.
|
||||||
|
*/
|
||||||
|
static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, secp256k1_fe *zr, const secp256k1_gej *a) {
|
||||||
|
secp256k1_gej d;
|
||||||
|
secp256k1_ge a_ge, d_ge;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
VERIFY_CHECK(!a->infinity);
|
||||||
|
|
||||||
|
secp256k1_gej_double_var(&d, a, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate
|
||||||
|
* of 'd', and scale the 1P starting value's x/y coordinates without changing its z.
|
||||||
|
*/
|
||||||
|
d_ge.x = d.x;
|
||||||
|
d_ge.y = d.y;
|
||||||
|
d_ge.infinity = 0;
|
||||||
|
|
||||||
|
secp256k1_ge_set_gej_zinv(&a_ge, a, &d.z);
|
||||||
|
prej[0].x = a_ge.x;
|
||||||
|
prej[0].y = a_ge.y;
|
||||||
|
prej[0].z = a->z;
|
||||||
|
prej[0].infinity = 0;
|
||||||
|
|
||||||
|
zr[0] = d.z;
|
||||||
|
for (i = 1; i < n; i++) {
|
||||||
|
secp256k1_gej_add_ge_var(&prej[i], &prej[i-1], &d_ge, &zr[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only
|
||||||
|
* the final point's z coordinate is actually used though, so just update that.
|
||||||
|
*/
|
||||||
|
secp256k1_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fill a table 'pre' with precomputed odd multiples of a.
|
||||||
|
*
|
||||||
|
* There are two versions of this function:
|
||||||
|
* - secp256k1_ecmult_odd_multiples_table_globalz_windowa which brings its
|
||||||
|
* resulting point set to a single constant Z denominator, stores the X and Y
|
||||||
|
* coordinates as ge_storage points in pre, and stores the global Z in rz.
|
||||||
|
* It only operates on tables sized for WINDOW_A wnaf multiples.
|
||||||
|
* - secp256k1_ecmult_odd_multiples_table_storage_var, which converts its
|
||||||
|
* resulting point set to actually affine points, and stores those in pre.
|
||||||
|
* It operates on tables of any size, but uses heap-allocated temporaries.
|
||||||
|
*
|
||||||
|
* To compute a*P + b*G, we compute a table for P using the first function,
|
||||||
|
* and for G using the second (which requires an inverse, but it only needs to
|
||||||
|
* happen once).
|
||||||
|
*/
|
||||||
|
static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {
|
||||||
|
secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||||
|
secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||||
|
|
||||||
|
/* Compute the odd multiples in Jacobian form. */
|
||||||
|
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a);
|
||||||
|
/* Bring them to the same Z denominator. */
|
||||||
|
secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge_storage *pre, const secp256k1_gej *a, const secp256k1_callback *cb) {
|
||||||
|
secp256k1_gej *prej = (secp256k1_gej*)checked_malloc(cb, sizeof(secp256k1_gej) * n);
|
||||||
|
secp256k1_ge *prea = (secp256k1_ge*)checked_malloc(cb, sizeof(secp256k1_ge) * n);
|
||||||
|
secp256k1_fe *zr = (secp256k1_fe*)checked_malloc(cb, sizeof(secp256k1_fe) * n);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Compute the odd multiples in Jacobian form. */
|
||||||
|
secp256k1_ecmult_odd_multiples_table(n, prej, zr, a);
|
||||||
|
/* Convert them in batch to affine coordinates. */
|
||||||
|
secp256k1_ge_set_table_gej_var(n, prea, prej, zr);
|
||||||
|
/* Convert them to compact storage form. */
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
secp256k1_ge_to_storage(&pre[i], &prea[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(prea);
|
||||||
|
free(prej);
|
||||||
|
free(zr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The following two macro retrieves a particular odd multiple from a table
|
||||||
|
* of precomputed multiples. */
|
||||||
|
#define ECMULT_TABLE_GET_GE(r,pre,n,w) do { \
|
||||||
|
VERIFY_CHECK(((n) & 1) == 1); \
|
||||||
|
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
|
||||||
|
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
|
||||||
|
if ((n) > 0) { \
|
||||||
|
*(r) = (pre)[((n)-1)/2]; \
|
||||||
|
} else { \
|
||||||
|
secp256k1_ge_neg((r), &(pre)[(-(n)-1)/2]); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \
|
||||||
|
VERIFY_CHECK(((n) & 1) == 1); \
|
||||||
|
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
|
||||||
|
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
|
||||||
|
if ((n) > 0) { \
|
||||||
|
secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \
|
||||||
|
} else { \
|
||||||
|
secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \
|
||||||
|
secp256k1_ge_neg((r), (r)); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) {
|
||||||
|
ctx->pre_g = NULL;
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
ctx->pre_g_128 = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) {
|
||||||
|
secp256k1_gej gj;
|
||||||
|
|
||||||
|
if (ctx->pre_g != NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the generator */
|
||||||
|
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
|
||||||
|
|
||||||
|
ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G));
|
||||||
|
|
||||||
|
/* precompute the tables with odd multiples */
|
||||||
|
secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj, cb);
|
||||||
|
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
{
|
||||||
|
secp256k1_gej g_128j;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ctx->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G));
|
||||||
|
|
||||||
|
/* calculate 2^128*generator */
|
||||||
|
g_128j = gj;
|
||||||
|
for (i = 0; i < 128; i++) {
|
||||||
|
secp256k1_gej_double_var(&g_128j, &g_128j, NULL);
|
||||||
|
}
|
||||||
|
secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j, cb);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst,
|
||||||
|
const secp256k1_ecmult_context *src, const secp256k1_callback *cb) {
|
||||||
|
if (src->pre_g == NULL) {
|
||||||
|
dst->pre_g = NULL;
|
||||||
|
} else {
|
||||||
|
size_t size = sizeof((*dst->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G);
|
||||||
|
dst->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);
|
||||||
|
memcpy(dst->pre_g, src->pre_g, size);
|
||||||
|
}
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
if (src->pre_g_128 == NULL) {
|
||||||
|
dst->pre_g_128 = NULL;
|
||||||
|
} else {
|
||||||
|
size_t size = sizeof((*dst->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G);
|
||||||
|
dst->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);
|
||||||
|
memcpy(dst->pre_g_128, src->pre_g_128, size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx) {
|
||||||
|
return ctx->pre_g != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) {
|
||||||
|
free(ctx->pre_g);
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
free(ctx->pre_g_128);
|
||||||
|
#endif
|
||||||
|
secp256k1_ecmult_context_init(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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 secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, int w) {
|
||||||
|
secp256k1_scalar s = *a;
|
||||||
|
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]));
|
||||||
|
|
||||||
|
if (secp256k1_scalar_get_bits(&s, 255, 1)) {
|
||||||
|
secp256k1_scalar_negate(&s, &s);
|
||||||
|
sign = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (bit < len) {
|
||||||
|
int now;
|
||||||
|
int word;
|
||||||
|
if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) {
|
||||||
|
bit++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
now = w;
|
||||||
|
if (now > len - bit) {
|
||||||
|
now = len - bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
word = secp256k1_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(secp256k1_scalar_get_bits(&s, bit++, 1) == 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return last_set_bit + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {
|
||||||
|
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||||
|
secp256k1_ge tmpa;
|
||||||
|
secp256k1_fe Z;
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||||
|
secp256k1_scalar na_1, na_lam;
|
||||||
|
/* Splitted G factors. */
|
||||||
|
secp256k1_scalar ng_1, ng_128;
|
||||||
|
int wnaf_na_1[130];
|
||||||
|
int wnaf_na_lam[130];
|
||||||
|
int bits_na_1;
|
||||||
|
int bits_na_lam;
|
||||||
|
int wnaf_ng_1[129];
|
||||||
|
int bits_ng_1;
|
||||||
|
int wnaf_ng_128[129];
|
||||||
|
int bits_ng_128;
|
||||||
|
#else
|
||||||
|
int wnaf_na[256];
|
||||||
|
int bits_na;
|
||||||
|
int wnaf_ng[256];
|
||||||
|
int bits_ng;
|
||||||
|
#endif
|
||||||
|
int i;
|
||||||
|
int bits;
|
||||||
|
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
/* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */
|
||||||
|
secp256k1_scalar_split_lambda(&na_1, &na_lam, na);
|
||||||
|
|
||||||
|
/* build wnaf representation for na_1 and na_lam. */
|
||||||
|
bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, 130, &na_1, WINDOW_A);
|
||||||
|
bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, 130, &na_lam, WINDOW_A);
|
||||||
|
VERIFY_CHECK(bits_na_1 <= 130);
|
||||||
|
VERIFY_CHECK(bits_na_lam <= 130);
|
||||||
|
bits = bits_na_1;
|
||||||
|
if (bits_na_lam > bits) {
|
||||||
|
bits = bits_na_lam;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* build wnaf representation for na. */
|
||||||
|
bits_na = secp256k1_ecmult_wnaf(wnaf_na, 256, na, WINDOW_A);
|
||||||
|
bits = bits_na;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 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 secp256k1_gej_add_zinv_var, which uses the same
|
||||||
|
* isomorphism to efficiently add with a known Z inverse.
|
||||||
|
*/
|
||||||
|
secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, a);
|
||||||
|
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
||||||
|
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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) */
|
||||||
|
secp256k1_scalar_split_128(&ng_1, &ng_128, ng);
|
||||||
|
|
||||||
|
/* Build wnaf representation for ng_1 and ng_128 */
|
||||||
|
bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G);
|
||||||
|
bits_ng_128 = secp256k1_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;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G);
|
||||||
|
if (bits_ng > bits) {
|
||||||
|
bits = bits_ng;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
secp256k1_gej_set_infinity(r);
|
||||||
|
|
||||||
|
for (i = bits - 1; i >= 0; i--) {
|
||||||
|
int n;
|
||||||
|
secp256k1_gej_double_var(r, r, NULL);
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
if (i < bits_na_1 && (n = wnaf_na_1[i])) {
|
||||||
|
ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
|
||||||
|
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
|
||||||
|
}
|
||||||
|
if (i < bits_na_lam && (n = wnaf_na_lam[i])) {
|
||||||
|
ECMULT_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
|
||||||
|
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
|
||||||
|
}
|
||||||
|
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
|
||||||
|
ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G);
|
||||||
|
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
|
||||||
|
}
|
||||||
|
if (i < bits_ng_128 && (n = wnaf_ng_128[i])) {
|
||||||
|
ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G);
|
||||||
|
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (i < bits_na && (n = wnaf_na[i])) {
|
||||||
|
ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
|
||||||
|
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
|
||||||
|
}
|
||||||
|
if (i < bits_ng && (n = wnaf_ng[i])) {
|
||||||
|
ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G);
|
||||||
|
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!r->infinity) {
|
||||||
|
secp256k1_fe_mul(&r->z, &r->z, &Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
127
secp256k1zkp/depend/secp256k1-zkp/src/field.h
Normal file
127
secp256k1zkp/depend/secp256k1-zkp/src/field.h
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_FIELD_
|
||||||
|
#define _SECP256K1_FIELD_
|
||||||
|
|
||||||
|
/** 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 1, but a magnitude of 1 doesn't imply
|
||||||
|
* normality.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined HAVE_CONFIG_H
|
||||||
|
#include "libsecp256k1-config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_FIELD_10X26)
|
||||||
|
#include "field_10x26.h"
|
||||||
|
#elif defined(USE_FIELD_5X52)
|
||||||
|
#include "field_5x52.h"
|
||||||
|
#else
|
||||||
|
#error "Please select field implementation"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Normalize a field element. */
|
||||||
|
static void secp256k1_fe_normalize(secp256k1_fe *r);
|
||||||
|
|
||||||
|
/** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */
|
||||||
|
static void secp256k1_fe_normalize_weak(secp256k1_fe *r);
|
||||||
|
|
||||||
|
/** Normalize a field element, without constant-time guarantee. */
|
||||||
|
static void secp256k1_fe_normalize_var(secp256k1_fe *r);
|
||||||
|
|
||||||
|
/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field
|
||||||
|
* implementation may optionally normalize the input, but this should not be relied upon. */
|
||||||
|
static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r);
|
||||||
|
|
||||||
|
/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field
|
||||||
|
* implementation may optionally normalize the input, but this should not be relied upon. */
|
||||||
|
static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r);
|
||||||
|
|
||||||
|
/** Set a field element equal to a small integer. Resulting field element is normalized. */
|
||||||
|
static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
|
||||||
|
|
||||||
|
/** Verify whether a field element is zero. Requires the input to be normalized. */
|
||||||
|
static int secp256k1_fe_is_zero(const secp256k1_fe *a);
|
||||||
|
|
||||||
|
/** Check the "oddness" of a field element. Requires the input to be normalized. */
|
||||||
|
static int secp256k1_fe_is_odd(const secp256k1_fe *a);
|
||||||
|
|
||||||
|
/** Compare two field elements. Requires magnitude-1 inputs. */
|
||||||
|
static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||||
|
|
||||||
|
/** Same as secp256k1_fe_equal, but may be variable time. */
|
||||||
|
static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||||
|
|
||||||
|
/** Compare two field elements. Requires both inputs to be normalized */
|
||||||
|
static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||||
|
|
||||||
|
/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */
|
||||||
|
static int secp256k1_fe_set_b32(secp256k1_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 secp256k1_fe_get_b32(unsigned char *r, const secp256k1_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 secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
|
||||||
|
|
||||||
|
/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that
|
||||||
|
* small integer. */
|
||||||
|
static void secp256k1_fe_mul_int(secp256k1_fe *r, int a);
|
||||||
|
|
||||||
|
/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */
|
||||||
|
static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_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 secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_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 secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_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 secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a);
|
||||||
|
|
||||||
|
/** Checks whether a field element is a quadratic residue. */
|
||||||
|
static int secp256k1_fe_is_quad_var(const secp256k1_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 secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a);
|
||||||
|
|
||||||
|
/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */
|
||||||
|
static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a);
|
||||||
|
|
||||||
|
/** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be
|
||||||
|
* at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and
|
||||||
|
* outputs must not overlap in memory. */
|
||||||
|
static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a);
|
||||||
|
|
||||||
|
/** Convert a field element to the storage type. */
|
||||||
|
static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
|
||||||
|
|
||||||
|
/** Convert a field element back from the storage type. */
|
||||||
|
static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
|
||||||
|
|
||||||
|
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
|
||||||
|
static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag);
|
||||||
|
|
||||||
|
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
|
||||||
|
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
|
||||||
|
|
||||||
|
#endif
|
47
secp256k1zkp/depend/secp256k1-zkp/src/field_10x26.h
Normal file
47
secp256k1zkp/depend/secp256k1-zkp/src/field_10x26.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_FIELD_REPR_
|
||||||
|
#define _SECP256K1_FIELD_REPR_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* X = sum(i=0..9, elem[i]*2^26) mod n */
|
||||||
|
uint32_t n[10];
|
||||||
|
#ifdef VERIFY
|
||||||
|
int magnitude;
|
||||||
|
int normalized;
|
||||||
|
#endif
|
||||||
|
} secp256k1_fe;
|
||||||
|
|
||||||
|
/* Unpacks a constant into a overlapping multi-limbed FE element. */
|
||||||
|
#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \
|
||||||
|
(d0) & 0x3FFFFFFUL, \
|
||||||
|
(((uint32_t)d0) >> 26) | (((uint32_t)(d1) & 0xFFFFFUL) << 6), \
|
||||||
|
(((uint32_t)d1) >> 20) | (((uint32_t)(d2) & 0x3FFFUL) << 12), \
|
||||||
|
(((uint32_t)d2) >> 14) | (((uint32_t)(d3) & 0xFFUL) << 18), \
|
||||||
|
(((uint32_t)d3) >> 8) | (((uint32_t)(d4) & 0x3UL) << 24), \
|
||||||
|
(((uint32_t)d4) >> 2) & 0x3FFFFFFUL, \
|
||||||
|
(((uint32_t)d4) >> 28) | (((uint32_t)(d5) & 0x3FFFFFUL) << 4), \
|
||||||
|
(((uint32_t)d5) >> 22) | (((uint32_t)(d6) & 0xFFFFUL) << 10), \
|
||||||
|
(((uint32_t)d6) >> 16) | (((uint32_t)(d7) & 0x3FFUL) << 16), \
|
||||||
|
(((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];
|
||||||
|
} secp256k1_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]
|
||||||
|
#endif
|
1144
secp256k1zkp/depend/secp256k1-zkp/src/field_10x26_impl.h
Normal file
1144
secp256k1zkp/depend/secp256k1-zkp/src/field_10x26_impl.h
Normal file
File diff suppressed because it is too large
Load diff
47
secp256k1zkp/depend/secp256k1-zkp/src/field_5x52.h
Normal file
47
secp256k1zkp/depend/secp256k1-zkp/src/field_5x52.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_FIELD_REPR_
|
||||||
|
#define _SECP256K1_FIELD_REPR_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* X = sum(i=0..4, elem[i]*2^52) mod n */
|
||||||
|
uint64_t n[5];
|
||||||
|
#ifdef VERIFY
|
||||||
|
int magnitude;
|
||||||
|
int normalized;
|
||||||
|
#endif
|
||||||
|
} secp256k1_fe;
|
||||||
|
|
||||||
|
/* Unpacks a constant into a overlapping multi-limbed FE element. */
|
||||||
|
#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \
|
||||||
|
(d0) | (((uint64_t)(d1) & 0xFFFFFUL) << 32), \
|
||||||
|
((uint64_t)(d1) >> 20) | (((uint64_t)(d2)) << 12) | (((uint64_t)(d3) & 0xFFUL) << 44), \
|
||||||
|
((uint64_t)(d3) >> 8) | (((uint64_t)(d4) & 0xFFFFFFFUL) << 24), \
|
||||||
|
((uint64_t)(d4) >> 28) | (((uint64_t)(d5)) << 4) | (((uint64_t)(d6) & 0xFFFFUL) << 36), \
|
||||||
|
((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];
|
||||||
|
} secp256k1_fe_storage;
|
||||||
|
|
||||||
|
#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \
|
||||||
|
(d0) | (((uint64_t)(d1)) << 32), \
|
||||||
|
(d2) | (((uint64_t)(d3)) << 32), \
|
||||||
|
(d4) | (((uint64_t)(d5)) << 32), \
|
||||||
|
(d6) | (((uint64_t)(d7)) << 32) \
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif
|
502
secp256k1zkp/depend/secp256k1-zkp/src/field_5x52_asm_impl.h
Normal file
502
secp256k1zkp/depend/secp256k1-zkp/src/field_5x52_asm_impl.h
Normal file
|
@ -0,0 +1,502 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://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 secp256k1_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 secp256k1_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
|
455
secp256k1zkp/depend/secp256k1-zkp/src/field_5x52_impl.h
Normal file
455
secp256k1zkp/depend/secp256k1-zkp/src/field_5x52_impl.h
Normal file
|
@ -0,0 +1,455 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
|
||||||
|
#define _SECP256K1_FIELD_REPR_IMPL_H_
|
||||||
|
|
||||||
|
#if defined HAVE_CONFIG_H
|
||||||
|
#include "libsecp256k1-config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "num.h"
|
||||||
|
#include "field.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. The values are allowed to contain >52 each. In particular,
|
||||||
|
* each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element
|
||||||
|
* is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations
|
||||||
|
* accept any input with magnitude at most M, and have different rules for propagating magnitude to their
|
||||||
|
* output.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef VERIFY
|
||||||
|
static void secp256k1_fe_verify(const secp256k1_fe *a) {
|
||||||
|
const uint64_t *d = a->n;
|
||||||
|
int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;
|
||||||
|
/* 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);
|
||||||
|
if (a->normalized) {
|
||||||
|
r &= (a->magnitude <= 1);
|
||||||
|
if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) {
|
||||||
|
r &= (d[0] < 0xFFFFEFFFFFC2FULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VERIFY_CHECK(r == 1);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void secp256k1_fe_verify(const secp256k1_fe *a) {
|
||||||
|
(void)a;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void secp256k1_fe_normalize(secp256k1_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 */
|
||||||
|
uint64_t m;
|
||||||
|
uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;
|
||||||
|
|
||||||
|
/* The first pass ensures the magnitude is 1, ... */
|
||||||
|
t0 += x * 0x1000003D1ULL;
|
||||||
|
t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;
|
||||||
|
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1;
|
||||||
|
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2;
|
||||||
|
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3;
|
||||||
|
|
||||||
|
/* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */
|
||||||
|
VERIFY_CHECK(t4 >> 49 == 0);
|
||||||
|
|
||||||
|
/* At most a single final reduction is needed; check if the value is >= the field characteristic */
|
||||||
|
x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL)
|
||||||
|
& (t0 >= 0xFFFFEFFFFFC2FULL));
|
||||||
|
|
||||||
|
/* Apply the final reduction (for constant-time behaviour, we do it always) */
|
||||||
|
t0 += x * 0x1000003D1ULL;
|
||||||
|
t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;
|
||||||
|
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL;
|
||||||
|
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL;
|
||||||
|
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL;
|
||||||
|
|
||||||
|
/* If t4 didn't carry to bit 48 already, then it should have after any final reduction */
|
||||||
|
VERIFY_CHECK(t4 >> 48 == x);
|
||||||
|
|
||||||
|
/* Mask off the possible multiple of 2^256 from the final reduction */
|
||||||
|
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;
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_fe_normalize_weak(secp256k1_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 */
|
||||||
|
uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;
|
||||||
|
|
||||||
|
/* The first pass ensures the magnitude is 1, ... */
|
||||||
|
t0 += x * 0x1000003D1ULL;
|
||||||
|
t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;
|
||||||
|
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL;
|
||||||
|
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL;
|
||||||
|
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL;
|
||||||
|
|
||||||
|
/* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */
|
||||||
|
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;
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_fe_normalize_var(secp256k1_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 */
|
||||||
|
uint64_t m;
|
||||||
|
uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;
|
||||||
|
|
||||||
|
/* The first pass ensures the magnitude is 1, ... */
|
||||||
|
t0 += x * 0x1000003D1ULL;
|
||||||
|
t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;
|
||||||
|
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1;
|
||||||
|
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2;
|
||||||
|
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3;
|
||||||
|
|
||||||
|
/* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */
|
||||||
|
VERIFY_CHECK(t4 >> 49 == 0);
|
||||||
|
|
||||||
|
/* At most a single final reduction is needed; check if the value is >= the field characteristic */
|
||||||
|
x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL)
|
||||||
|
& (t0 >= 0xFFFFEFFFFFC2FULL));
|
||||||
|
|
||||||
|
if (x) {
|
||||||
|
t0 += 0x1000003D1ULL;
|
||||||
|
t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;
|
||||||
|
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL;
|
||||||
|
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL;
|
||||||
|
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL;
|
||||||
|
|
||||||
|
/* If t4 didn't carry to bit 48 already, then it should have after any final reduction */
|
||||||
|
VERIFY_CHECK(t4 >> 48 == x);
|
||||||
|
|
||||||
|
/* Mask off the possible multiple of 2^256 from the final reduction */
|
||||||
|
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;
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_fe_normalizes_to_zero(secp256k1_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 */
|
||||||
|
uint64_t z0, z1;
|
||||||
|
|
||||||
|
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
|
||||||
|
uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;
|
||||||
|
|
||||||
|
/* The first pass ensures the magnitude is 1, ... */
|
||||||
|
t0 += x * 0x1000003D1ULL;
|
||||||
|
t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; z0 = t0; z1 = t0 ^ 0x1000003D0ULL;
|
||||||
|
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1;
|
||||||
|
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2;
|
||||||
|
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3;
|
||||||
|
z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL;
|
||||||
|
|
||||||
|
/* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */
|
||||||
|
VERIFY_CHECK(t4 >> 49 == 0);
|
||||||
|
|
||||||
|
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) {
|
||||||
|
uint64_t t0, t1, t2, t3, t4;
|
||||||
|
uint64_t z0, z1;
|
||||||
|
uint64_t x;
|
||||||
|
|
||||||
|
t0 = r->n[0];
|
||||||
|
t4 = r->n[4];
|
||||||
|
|
||||||
|
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
|
||||||
|
x = t4 >> 48;
|
||||||
|
|
||||||
|
/* The first pass ensures the magnitude is 1, ... */
|
||||||
|
t0 += x * 0x1000003D1ULL;
|
||||||
|
|
||||||
|
/* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
|
||||||
|
z0 = t0 & 0xFFFFFFFFFFFFFULL;
|
||||||
|
z1 = z0 ^ 0x1000003D0ULL;
|
||||||
|
|
||||||
|
/* Fast return path should catch the majority of cases */
|
||||||
|
if ((z0 != 0ULL) & (z1 != 0xFFFFFFFFFFFFFULL)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
t1 = r->n[1];
|
||||||
|
t2 = r->n[2];
|
||||||
|
t3 = r->n[3];
|
||||||
|
|
||||||
|
t4 &= 0x0FFFFFFFFFFFFULL;
|
||||||
|
|
||||||
|
t1 += (t0 >> 52);
|
||||||
|
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1;
|
||||||
|
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2;
|
||||||
|
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3;
|
||||||
|
z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL;
|
||||||
|
|
||||||
|
/* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */
|
||||||
|
VERIFY_CHECK(t4 >> 49 == 0);
|
||||||
|
|
||||||
|
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_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 = 1;
|
||||||
|
r->normalized = 1;
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
|
||||||
|
const uint64_t *t = a->n;
|
||||||
|
#ifdef VERIFY
|
||||||
|
VERIFY_CHECK(a->normalized);
|
||||||
|
secp256k1_fe_verify(a);
|
||||||
|
#endif
|
||||||
|
return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
|
||||||
|
#ifdef VERIFY
|
||||||
|
VERIFY_CHECK(a->normalized);
|
||||||
|
secp256k1_fe_verify(a);
|
||||||
|
#endif
|
||||||
|
return a->n[0] & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_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 secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||||
|
int i;
|
||||||
|
#ifdef VERIFY
|
||||||
|
VERIFY_CHECK(a->normalized);
|
||||||
|
VERIFY_CHECK(b->normalized);
|
||||||
|
secp256k1_fe_verify(a);
|
||||||
|
secp256k1_fe_verify(b);
|
||||||
|
#endif
|
||||||
|
for (i = 4; i >= 0; i--) {
|
||||||
|
if (a->n[i] > b->n[i]) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (a->n[i] < b->n[i]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
|
||||||
|
int i;
|
||||||
|
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
|
||||||
|
for (i=0; i<32; i++) {
|
||||||
|
int j;
|
||||||
|
for (j=0; j<2; j++) {
|
||||||
|
int limb = (8*i+4*j)/52;
|
||||||
|
int shift = (8*i+4*j)%52;
|
||||||
|
r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#ifdef VERIFY
|
||||||
|
r->magnitude = 1;
|
||||||
|
r->normalized = 1;
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
|
||||||
|
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
|
||||||
|
int i;
|
||||||
|
#ifdef VERIFY
|
||||||
|
VERIFY_CHECK(a->normalized);
|
||||||
|
secp256k1_fe_verify(a);
|
||||||
|
#endif
|
||||||
|
for (i=0; i<32; i++) {
|
||||||
|
int j;
|
||||||
|
int c = 0;
|
||||||
|
for (j=0; j<2; j++) {
|
||||||
|
int limb = (8*i+4*j)/52;
|
||||||
|
int shift = (8*i+4*j)%52;
|
||||||
|
c |= ((a->n[limb] >> shift) & 0xF) << (4 * j);
|
||||||
|
}
|
||||||
|
r[31-i] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||||
|
#ifdef VERIFY
|
||||||
|
VERIFY_CHECK(a->magnitude <= m);
|
||||||
|
secp256k1_fe_verify(a);
|
||||||
|
#endif
|
||||||
|
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;
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_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;
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||||
|
#ifdef VERIFY
|
||||||
|
secp256k1_fe_verify(a);
|
||||||
|
#endif
|
||||||
|
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;
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
|
||||||
|
#ifdef VERIFY
|
||||||
|
VERIFY_CHECK(a->magnitude <= 8);
|
||||||
|
VERIFY_CHECK(b->magnitude <= 8);
|
||||||
|
secp256k1_fe_verify(a);
|
||||||
|
secp256k1_fe_verify(b);
|
||||||
|
VERIFY_CHECK(r != b);
|
||||||
|
#endif
|
||||||
|
secp256k1_fe_mul_inner(r->n, a->n, b->n);
|
||||||
|
#ifdef VERIFY
|
||||||
|
r->magnitude = 1;
|
||||||
|
r->normalized = 0;
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||||
|
#ifdef VERIFY
|
||||||
|
VERIFY_CHECK(a->magnitude <= 8);
|
||||||
|
secp256k1_fe_verify(a);
|
||||||
|
#endif
|
||||||
|
secp256k1_fe_sqr_inner(r->n, a->n);
|
||||||
|
#ifdef VERIFY
|
||||||
|
r->magnitude = 1;
|
||||||
|
r->normalized = 0;
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
|
||||||
|
uint64_t mask0, mask1;
|
||||||
|
mask0 = flag + ~((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 (a->magnitude > r->magnitude) {
|
||||||
|
r->magnitude = a->magnitude;
|
||||||
|
}
|
||||||
|
r->normalized &= a->normalized;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
|
||||||
|
uint64_t mask0, mask1;
|
||||||
|
mask0 = flag + ~((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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
|
||||||
|
#ifdef VERIFY
|
||||||
|
VERIFY_CHECK(a->normalized);
|
||||||
|
#endif
|
||||||
|
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 secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_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;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
277
secp256k1zkp/depend/secp256k1-zkp/src/field_5x52_int128_impl.h
Normal file
277
secp256k1zkp/depend/secp256k1-zkp/src/field_5x52_int128_impl.h
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
|
||||||
|
#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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 secp256k1_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);
|
||||||
|
|
||||||
|
/* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.
|
||||||
|
* px is a shorthand for sum(a[i]*b[x-i], i=0..x).
|
||||||
|
* 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 += (c & M) * R; c >>= 52;
|
||||||
|
VERIFY_BITS(d, 115);
|
||||||
|
VERIFY_BITS(c, 60);
|
||||||
|
/* [c 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 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 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
|
||||||
|
d += c * R;
|
||||||
|
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 += (d & M) * R; d >>= 52;
|
||||||
|
VERIFY_BITS(c, 115);
|
||||||
|
VERIFY_BITS(d, 62);
|
||||||
|
/* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||||
|
|
||||||
|
/* [d 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 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||||
|
c += d * R + 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 secp256k1_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 += (c & M) * R; c >>= 52;
|
||||||
|
VERIFY_BITS(d, 115);
|
||||||
|
VERIFY_BITS(c, 60);
|
||||||
|
/* [c 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 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 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
|
||||||
|
d += c * R;
|
||||||
|
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 += (d & M) * R; d >>= 52;
|
||||||
|
VERIFY_BITS(c, 115);
|
||||||
|
VERIFY_BITS(d, 62);
|
||||||
|
/* [d 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 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||||
|
|
||||||
|
c += d * R + 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
|
315
secp256k1zkp/depend/secp256k1-zkp/src/field_impl.h
Normal file
315
secp256k1zkp/depend/secp256k1-zkp/src/field_impl.h
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://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(USE_FIELD_10X26)
|
||||||
|
#include "field_10x26_impl.h"
|
||||||
|
#elif defined(USE_FIELD_5X52)
|
||||||
|
#include "field_5x52_impl.h"
|
||||||
|
#else
|
||||||
|
#error "Please select field implementation"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||||
|
secp256k1_fe na;
|
||||||
|
secp256k1_fe_negate(&na, a, 1);
|
||||||
|
secp256k1_fe_add(&na, b);
|
||||||
|
return secp256k1_fe_normalizes_to_zero(&na);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||||
|
secp256k1_fe na;
|
||||||
|
secp256k1_fe_negate(&na, a, 1);
|
||||||
|
secp256k1_fe_add(&na, b);
|
||||||
|
return secp256k1_fe_normalizes_to_zero_var(&na);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_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)).
|
||||||
|
*/
|
||||||
|
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
/** 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]
|
||||||
|
*/
|
||||||
|
|
||||||
|
secp256k1_fe_sqr(&x2, a);
|
||||||
|
secp256k1_fe_mul(&x2, &x2, a);
|
||||||
|
|
||||||
|
secp256k1_fe_sqr(&x3, &x2);
|
||||||
|
secp256k1_fe_mul(&x3, &x3, a);
|
||||||
|
|
||||||
|
x6 = x3;
|
||||||
|
for (j=0; j<3; j++) {
|
||||||
|
secp256k1_fe_sqr(&x6, &x6);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x6, &x6, &x3);
|
||||||
|
|
||||||
|
x9 = x6;
|
||||||
|
for (j=0; j<3; j++) {
|
||||||
|
secp256k1_fe_sqr(&x9, &x9);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x9, &x9, &x3);
|
||||||
|
|
||||||
|
x11 = x9;
|
||||||
|
for (j=0; j<2; j++) {
|
||||||
|
secp256k1_fe_sqr(&x11, &x11);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x11, &x11, &x2);
|
||||||
|
|
||||||
|
x22 = x11;
|
||||||
|
for (j=0; j<11; j++) {
|
||||||
|
secp256k1_fe_sqr(&x22, &x22);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x22, &x22, &x11);
|
||||||
|
|
||||||
|
x44 = x22;
|
||||||
|
for (j=0; j<22; j++) {
|
||||||
|
secp256k1_fe_sqr(&x44, &x44);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x44, &x44, &x22);
|
||||||
|
|
||||||
|
x88 = x44;
|
||||||
|
for (j=0; j<44; j++) {
|
||||||
|
secp256k1_fe_sqr(&x88, &x88);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x88, &x88, &x44);
|
||||||
|
|
||||||
|
x176 = x88;
|
||||||
|
for (j=0; j<88; j++) {
|
||||||
|
secp256k1_fe_sqr(&x176, &x176);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x176, &x176, &x88);
|
||||||
|
|
||||||
|
x220 = x176;
|
||||||
|
for (j=0; j<44; j++) {
|
||||||
|
secp256k1_fe_sqr(&x220, &x220);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x220, &x220, &x44);
|
||||||
|
|
||||||
|
x223 = x220;
|
||||||
|
for (j=0; j<3; j++) {
|
||||||
|
secp256k1_fe_sqr(&x223, &x223);
|
||||||
|
}
|
||||||
|
secp256k1_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++) {
|
||||||
|
secp256k1_fe_sqr(&t1, &t1);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&t1, &t1, &x22);
|
||||||
|
for (j=0; j<6; j++) {
|
||||||
|
secp256k1_fe_sqr(&t1, &t1);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&t1, &t1, &x2);
|
||||||
|
secp256k1_fe_sqr(&t1, &t1);
|
||||||
|
secp256k1_fe_sqr(r, &t1);
|
||||||
|
|
||||||
|
/* Check that a square root was actually calculated */
|
||||||
|
|
||||||
|
secp256k1_fe_sqr(&t1, r);
|
||||||
|
return secp256k1_fe_equal(&t1, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||||
|
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
/** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in
|
||||||
|
* { 1, 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]
|
||||||
|
*/
|
||||||
|
|
||||||
|
secp256k1_fe_sqr(&x2, a);
|
||||||
|
secp256k1_fe_mul(&x2, &x2, a);
|
||||||
|
|
||||||
|
secp256k1_fe_sqr(&x3, &x2);
|
||||||
|
secp256k1_fe_mul(&x3, &x3, a);
|
||||||
|
|
||||||
|
x6 = x3;
|
||||||
|
for (j=0; j<3; j++) {
|
||||||
|
secp256k1_fe_sqr(&x6, &x6);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x6, &x6, &x3);
|
||||||
|
|
||||||
|
x9 = x6;
|
||||||
|
for (j=0; j<3; j++) {
|
||||||
|
secp256k1_fe_sqr(&x9, &x9);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x9, &x9, &x3);
|
||||||
|
|
||||||
|
x11 = x9;
|
||||||
|
for (j=0; j<2; j++) {
|
||||||
|
secp256k1_fe_sqr(&x11, &x11);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x11, &x11, &x2);
|
||||||
|
|
||||||
|
x22 = x11;
|
||||||
|
for (j=0; j<11; j++) {
|
||||||
|
secp256k1_fe_sqr(&x22, &x22);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x22, &x22, &x11);
|
||||||
|
|
||||||
|
x44 = x22;
|
||||||
|
for (j=0; j<22; j++) {
|
||||||
|
secp256k1_fe_sqr(&x44, &x44);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x44, &x44, &x22);
|
||||||
|
|
||||||
|
x88 = x44;
|
||||||
|
for (j=0; j<44; j++) {
|
||||||
|
secp256k1_fe_sqr(&x88, &x88);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x88, &x88, &x44);
|
||||||
|
|
||||||
|
x176 = x88;
|
||||||
|
for (j=0; j<88; j++) {
|
||||||
|
secp256k1_fe_sqr(&x176, &x176);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x176, &x176, &x88);
|
||||||
|
|
||||||
|
x220 = x176;
|
||||||
|
for (j=0; j<44; j++) {
|
||||||
|
secp256k1_fe_sqr(&x220, &x220);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&x220, &x220, &x44);
|
||||||
|
|
||||||
|
x223 = x220;
|
||||||
|
for (j=0; j<3; j++) {
|
||||||
|
secp256k1_fe_sqr(&x223, &x223);
|
||||||
|
}
|
||||||
|
secp256k1_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++) {
|
||||||
|
secp256k1_fe_sqr(&t1, &t1);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&t1, &t1, &x22);
|
||||||
|
for (j=0; j<5; j++) {
|
||||||
|
secp256k1_fe_sqr(&t1, &t1);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&t1, &t1, a);
|
||||||
|
for (j=0; j<3; j++) {
|
||||||
|
secp256k1_fe_sqr(&t1, &t1);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&t1, &t1, &x2);
|
||||||
|
for (j=0; j<2; j++) {
|
||||||
|
secp256k1_fe_sqr(&t1, &t1);
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(r, a, &t1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||||
|
#if defined(USE_FIELD_INV_BUILTIN)
|
||||||
|
secp256k1_fe_inv(r, a);
|
||||||
|
#elif defined(USE_FIELD_INV_NUM)
|
||||||
|
secp256k1_num n, m;
|
||||||
|
static const secp256k1_fe negone = SECP256K1_FE_CONST(
|
||||||
|
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
|
||||||
|
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xFFFFFC2EUL
|
||||||
|
);
|
||||||
|
/* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
|
||||||
|
static const unsigned char prime[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
|
||||||
|
};
|
||||||
|
unsigned char b[32];
|
||||||
|
int res;
|
||||||
|
secp256k1_fe c = *a;
|
||||||
|
secp256k1_fe_normalize_var(&c);
|
||||||
|
secp256k1_fe_get_b32(b, &c);
|
||||||
|
secp256k1_num_set_bin(&n, b, 32);
|
||||||
|
secp256k1_num_set_bin(&m, prime, 32);
|
||||||
|
secp256k1_num_mod_inverse(&n, &n, &m);
|
||||||
|
secp256k1_num_get_bin(b, 32, &n);
|
||||||
|
res = secp256k1_fe_set_b32(r, b);
|
||||||
|
(void)res;
|
||||||
|
VERIFY_CHECK(res);
|
||||||
|
/* Verify the result is the (unique) valid inverse using non-GMP code. */
|
||||||
|
secp256k1_fe_mul(&c, &c, r);
|
||||||
|
secp256k1_fe_add(&c, &negone);
|
||||||
|
CHECK(secp256k1_fe_normalizes_to_zero_var(&c));
|
||||||
|
#else
|
||||||
|
#error "Please select field inverse implementation"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a) {
|
||||||
|
secp256k1_fe u;
|
||||||
|
size_t i;
|
||||||
|
if (len < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VERIFY_CHECK((r + len <= a) || (a + len <= r));
|
||||||
|
|
||||||
|
r[0] = a[0];
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (++i < len) {
|
||||||
|
secp256k1_fe_mul(&r[i], &r[i - 1], &a[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
secp256k1_fe_inv_var(&u, &r[--i]);
|
||||||
|
|
||||||
|
while (i > 0) {
|
||||||
|
size_t j = i--;
|
||||||
|
secp256k1_fe_mul(&r[j], &r[i], &u);
|
||||||
|
secp256k1_fe_mul(&u, &u, &a[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
r[0] = u;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {
|
||||||
|
#ifndef USE_NUM_NONE
|
||||||
|
unsigned char b[32];
|
||||||
|
secp256k1_num n;
|
||||||
|
secp256k1_num m;
|
||||||
|
/* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
|
||||||
|
static const unsigned char prime[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
|
||||||
|
};
|
||||||
|
|
||||||
|
secp256k1_fe c = *a;
|
||||||
|
secp256k1_fe_normalize_var(&c);
|
||||||
|
secp256k1_fe_get_b32(b, &c);
|
||||||
|
secp256k1_num_set_bin(&n, b, 32);
|
||||||
|
secp256k1_num_set_bin(&m, prime, 32);
|
||||||
|
return secp256k1_num_jacobi(&n, &m) >= 0;
|
||||||
|
#else
|
||||||
|
secp256k1_fe r;
|
||||||
|
return secp256k1_fe_sqrt(&r, a);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
74
secp256k1zkp/depend/secp256k1-zkp/src/gen_context.c
Normal file
74
secp256k1zkp/depend/secp256k1-zkp/src/gen_context.c
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#define USE_BASIC_CONFIG 1
|
||||||
|
|
||||||
|
#include "basic-config.h"
|
||||||
|
#include "include/secp256k1.h"
|
||||||
|
#include "field_impl.h"
|
||||||
|
#include "scalar_impl.h"
|
||||||
|
#include "group_impl.h"
|
||||||
|
#include "ecmult_gen_impl.h"
|
||||||
|
|
||||||
|
static void default_error_callback_fn(const char* str, void* data) {
|
||||||
|
(void)data;
|
||||||
|
fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const secp256k1_callback default_error_callback = {
|
||||||
|
default_error_callback_fn,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
secp256k1_ecmult_gen_context ctx;
|
||||||
|
int inner;
|
||||||
|
int outer;
|
||||||
|
FILE* fp;
|
||||||
|
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
fp = fopen("src/ecmult_static_context.h","w");
|
||||||
|
if (fp == NULL) {
|
||||||
|
fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
|
||||||
|
fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
|
||||||
|
fprintf(fp, "#include \"group.h\"\n");
|
||||||
|
fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n");
|
||||||
|
fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n");
|
||||||
|
|
||||||
|
secp256k1_ecmult_gen_context_init(&ctx);
|
||||||
|
secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback);
|
||||||
|
for(outer = 0; outer != 64; outer++) {
|
||||||
|
fprintf(fp,"{\n");
|
||||||
|
for(inner = 0; inner != 16; inner++) {
|
||||||
|
fprintf(fp," SC(%uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu)", SECP256K1_GE_STORAGE_CONST_GET((*ctx.prec)[outer][inner]));
|
||||||
|
if (inner != 15) {
|
||||||
|
fprintf(fp,",\n");
|
||||||
|
} else {
|
||||||
|
fprintf(fp,"\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (outer != 63) {
|
||||||
|
fprintf(fp,"},\n");
|
||||||
|
} else {
|
||||||
|
fprintf(fp,"}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(fp,"};\n");
|
||||||
|
secp256k1_ecmult_gen_context_clear(&ctx);
|
||||||
|
|
||||||
|
fprintf(fp, "#undef SC\n");
|
||||||
|
fprintf(fp, "#endif\n");
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
144
secp256k1zkp/depend/secp256k1-zkp/src/group.h
Normal file
144
secp256k1zkp/depend/secp256k1-zkp/src/group.h
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_GROUP_
|
||||||
|
#define _SECP256K1_GROUP_
|
||||||
|
|
||||||
|
#include "num.h"
|
||||||
|
#include "field.h"
|
||||||
|
|
||||||
|
/** A group element of the secp256k1 curve, in affine coordinates. */
|
||||||
|
typedef struct {
|
||||||
|
secp256k1_fe x;
|
||||||
|
secp256k1_fe y;
|
||||||
|
int infinity; /* whether this represents the point at infinity */
|
||||||
|
} secp256k1_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. */
|
||||||
|
typedef struct {
|
||||||
|
secp256k1_fe x; /* actual X: x/z^2 */
|
||||||
|
secp256k1_fe y; /* actual Y: y/z^3 */
|
||||||
|
secp256k1_fe z;
|
||||||
|
int infinity; /* whether this represents the point at infinity */
|
||||||
|
} secp256k1_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 {
|
||||||
|
secp256k1_fe_storage x;
|
||||||
|
secp256k1_fe_storage y;
|
||||||
|
} secp256k1_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 secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_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 secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_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 secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd);
|
||||||
|
|
||||||
|
/** Check whether a group element is the point at infinity. */
|
||||||
|
static int secp256k1_ge_is_infinity(const secp256k1_ge *a);
|
||||||
|
|
||||||
|
/** Check whether a group element is valid (i.e., on the curve). */
|
||||||
|
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a);
|
||||||
|
|
||||||
|
static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a);
|
||||||
|
|
||||||
|
/** Set a group element equal to another which is given in jacobian coordinates */
|
||||||
|
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a);
|
||||||
|
|
||||||
|
/** Set a batch of group elements equal to the inputs given in jacobian coordinates */
|
||||||
|
static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb);
|
||||||
|
|
||||||
|
/** Set a batch of group elements equal to the inputs given in jacobian
|
||||||
|
* coordinates (with known z-ratios). zr must contain the known z-ratios such
|
||||||
|
* that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */
|
||||||
|
static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr);
|
||||||
|
|
||||||
|
/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to
|
||||||
|
* the same global z "denominator". zr must contain the known z-ratios such
|
||||||
|
* that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y
|
||||||
|
* coordinates of the result are stored in r, the common z coordinate is
|
||||||
|
* stored in globalz. */
|
||||||
|
static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr);
|
||||||
|
|
||||||
|
/** Set a group element (jacobian) equal to the point at infinity. */
|
||||||
|
static void secp256k1_gej_set_infinity(secp256k1_gej *r);
|
||||||
|
|
||||||
|
/** Set a group element (jacobian) equal to another which is given in affine coordinates. */
|
||||||
|
static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a);
|
||||||
|
|
||||||
|
/** Compare the X coordinate of a group element (jacobian). */
|
||||||
|
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a);
|
||||||
|
|
||||||
|
/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */
|
||||||
|
static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a);
|
||||||
|
|
||||||
|
/** Check whether a group element is the point at infinity. */
|
||||||
|
static int secp256k1_gej_is_infinity(const secp256k1_gej *a);
|
||||||
|
|
||||||
|
/** Check whether a group element's y coordinate is a quadratic residue. */
|
||||||
|
static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a);
|
||||||
|
|
||||||
|
/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0).
|
||||||
|
* a may not be zero. Constant time. */
|
||||||
|
static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
|
||||||
|
|
||||||
|
/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). */
|
||||||
|
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
|
||||||
|
|
||||||
|
/** Set r equal to the sum of a and b. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */
|
||||||
|
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr);
|
||||||
|
|
||||||
|
/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */
|
||||||
|
static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b);
|
||||||
|
|
||||||
|
/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient
|
||||||
|
than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time
|
||||||
|
guarantee, and b is allowed to be infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */
|
||||||
|
static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_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 secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv);
|
||||||
|
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */
|
||||||
|
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Clear a secp256k1_gej to prevent leaking sensitive information. */
|
||||||
|
static void secp256k1_gej_clear(secp256k1_gej *r);
|
||||||
|
|
||||||
|
/** Clear a secp256k1_ge to prevent leaking sensitive information. */
|
||||||
|
static void secp256k1_ge_clear(secp256k1_ge *r);
|
||||||
|
|
||||||
|
/** Convert a group element to the storage type. */
|
||||||
|
static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a);
|
||||||
|
|
||||||
|
/** Convert a group element back from the storage type. */
|
||||||
|
static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a);
|
||||||
|
|
||||||
|
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
|
||||||
|
static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag);
|
||||||
|
|
||||||
|
/** Rescale a jacobian point by b which must be non-zero. Constant-time. */
|
||||||
|
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
|
||||||
|
|
||||||
|
#endif
|
650
secp256k1zkp/depend/secp256k1-zkp/src/group_impl.h
Normal file
650
secp256k1zkp/depend/secp256k1-zkp/src/group_impl.h
Normal file
|
@ -0,0 +1,650 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_GROUP_IMPL_H_
|
||||||
|
#define _SECP256K1_GROUP_IMPL_H_
|
||||||
|
|
||||||
|
#include "num.h"
|
||||||
|
#include "field.h"
|
||||||
|
#include "group.h"
|
||||||
|
|
||||||
|
/** Generator for secp256k1, value 'g' defined in
|
||||||
|
* "Standards for Efficient Cryptography" (SEC2) 2.7.1.
|
||||||
|
*/
|
||||||
|
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
|
||||||
|
0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL,
|
||||||
|
0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL,
|
||||||
|
0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL,
|
||||||
|
0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL
|
||||||
|
);
|
||||||
|
|
||||||
|
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
|
||||||
|
secp256k1_fe zi2;
|
||||||
|
secp256k1_fe zi3;
|
||||||
|
secp256k1_fe_sqr(&zi2, zi);
|
||||||
|
secp256k1_fe_mul(&zi3, &zi2, zi);
|
||||||
|
secp256k1_fe_mul(&r->x, &a->x, &zi2);
|
||||||
|
secp256k1_fe_mul(&r->y, &a->y, &zi3);
|
||||||
|
r->infinity = a->infinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) {
|
||||||
|
r->infinity = 0;
|
||||||
|
r->x = *x;
|
||||||
|
r->y = *y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_ge_is_infinity(const secp256k1_ge *a) {
|
||||||
|
return a->infinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) {
|
||||||
|
*r = *a;
|
||||||
|
secp256k1_fe_normalize_weak(&r->y);
|
||||||
|
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
|
||||||
|
secp256k1_fe z2, z3;
|
||||||
|
r->infinity = a->infinity;
|
||||||
|
secp256k1_fe_inv(&a->z, &a->z);
|
||||||
|
secp256k1_fe_sqr(&z2, &a->z);
|
||||||
|
secp256k1_fe_mul(&z3, &a->z, &z2);
|
||||||
|
secp256k1_fe_mul(&a->x, &a->x, &z2);
|
||||||
|
secp256k1_fe_mul(&a->y, &a->y, &z3);
|
||||||
|
secp256k1_fe_set_int(&a->z, 1);
|
||||||
|
r->x = a->x;
|
||||||
|
r->y = a->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
|
||||||
|
secp256k1_fe z2, z3;
|
||||||
|
r->infinity = a->infinity;
|
||||||
|
if (a->infinity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
secp256k1_fe_inv_var(&a->z, &a->z);
|
||||||
|
secp256k1_fe_sqr(&z2, &a->z);
|
||||||
|
secp256k1_fe_mul(&z3, &a->z, &z2);
|
||||||
|
secp256k1_fe_mul(&a->x, &a->x, &z2);
|
||||||
|
secp256k1_fe_mul(&a->y, &a->y, &z3);
|
||||||
|
secp256k1_fe_set_int(&a->z, 1);
|
||||||
|
r->x = a->x;
|
||||||
|
r->y = a->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb) {
|
||||||
|
secp256k1_fe *az;
|
||||||
|
secp256k1_fe *azi;
|
||||||
|
size_t i;
|
||||||
|
size_t count = 0;
|
||||||
|
az = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * len);
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (!a[i].infinity) {
|
||||||
|
az[count++] = a[i].z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count);
|
||||||
|
secp256k1_fe_inv_all_var(count, azi, az);
|
||||||
|
free(az);
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
r[i].infinity = a[i].infinity;
|
||||||
|
if (!a[i].infinity) {
|
||||||
|
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(azi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr) {
|
||||||
|
size_t i = len - 1;
|
||||||
|
secp256k1_fe zi;
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
/* Compute the inverse of the last z coordinate, and use it to compute the last affine output. */
|
||||||
|
secp256k1_fe_inv(&zi, &a[i].z);
|
||||||
|
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi);
|
||||||
|
|
||||||
|
/* Work out way backwards, using the z-ratios to scale the x/y values. */
|
||||||
|
while (i > 0) {
|
||||||
|
secp256k1_fe_mul(&zi, &zi, &zr[i]);
|
||||||
|
i--;
|
||||||
|
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr) {
|
||||||
|
size_t i = len - 1;
|
||||||
|
secp256k1_fe zs;
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
/* The z of the final point gives us the "global Z" for the table. */
|
||||||
|
r[i].x = a[i].x;
|
||||||
|
r[i].y = a[i].y;
|
||||||
|
*globalz = a[i].z;
|
||||||
|
r[i].infinity = 0;
|
||||||
|
zs = zr[i];
|
||||||
|
|
||||||
|
/* Work our way backwards, using the z-ratios to scale the x/y values. */
|
||||||
|
while (i > 0) {
|
||||||
|
if (i != len - 1) {
|
||||||
|
secp256k1_fe_mul(&zs, &zs, &zr[i]);
|
||||||
|
}
|
||||||
|
i--;
|
||||||
|
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
|
||||||
|
r->infinity = 1;
|
||||||
|
secp256k1_fe_set_int(&r->x, 0);
|
||||||
|
secp256k1_fe_set_int(&r->y, 0);
|
||||||
|
secp256k1_fe_set_int(&r->z, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_gej_clear(secp256k1_gej *r) {
|
||||||
|
r->infinity = 0;
|
||||||
|
secp256k1_fe_clear(&r->x);
|
||||||
|
secp256k1_fe_clear(&r->y);
|
||||||
|
secp256k1_fe_clear(&r->z);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ge_clear(secp256k1_ge *r) {
|
||||||
|
r->infinity = 0;
|
||||||
|
secp256k1_fe_clear(&r->x);
|
||||||
|
secp256k1_fe_clear(&r->y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) {
|
||||||
|
secp256k1_fe x2, x3, c;
|
||||||
|
r->x = *x;
|
||||||
|
secp256k1_fe_sqr(&x2, x);
|
||||||
|
secp256k1_fe_mul(&x3, x, &x2);
|
||||||
|
r->infinity = 0;
|
||||||
|
secp256k1_fe_set_int(&c, 7);
|
||||||
|
secp256k1_fe_add(&c, &x3);
|
||||||
|
return secp256k1_fe_sqrt(&r->y, &c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
|
||||||
|
if (!secp256k1_ge_set_xquad(r, x)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
secp256k1_fe_normalize_var(&r->y);
|
||||||
|
if (secp256k1_fe_is_odd(&r->y) != odd) {
|
||||||
|
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) {
|
||||||
|
r->infinity = a->infinity;
|
||||||
|
r->x = a->x;
|
||||||
|
r->y = a->y;
|
||||||
|
secp256k1_fe_set_int(&r->z, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) {
|
||||||
|
secp256k1_fe r, r2;
|
||||||
|
VERIFY_CHECK(!a->infinity);
|
||||||
|
secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x);
|
||||||
|
r2 = a->x; secp256k1_fe_normalize_weak(&r2);
|
||||||
|
return secp256k1_fe_equal_var(&r, &r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) {
|
||||||
|
r->infinity = a->infinity;
|
||||||
|
r->x = a->x;
|
||||||
|
r->y = a->y;
|
||||||
|
r->z = a->z;
|
||||||
|
secp256k1_fe_normalize_weak(&r->y);
|
||||||
|
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_gej_is_infinity(const secp256k1_gej *a) {
|
||||||
|
return a->infinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) {
|
||||||
|
secp256k1_fe y2, x3, z2, z6;
|
||||||
|
if (a->infinity) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/** y^2 = x^3 + 7
|
||||||
|
* (Y/Z^3)^2 = (X/Z^2)^3 + 7
|
||||||
|
* Y^2 / Z^6 = X^3 / Z^6 + 7
|
||||||
|
* Y^2 = X^3 + 7*Z^6
|
||||||
|
*/
|
||||||
|
secp256k1_fe_sqr(&y2, &a->y);
|
||||||
|
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
|
||||||
|
secp256k1_fe_sqr(&z2, &a->z);
|
||||||
|
secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);
|
||||||
|
secp256k1_fe_mul_int(&z6, 7);
|
||||||
|
secp256k1_fe_add(&x3, &z6);
|
||||||
|
secp256k1_fe_normalize_weak(&x3);
|
||||||
|
return secp256k1_fe_equal_var(&y2, &x3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
|
||||||
|
secp256k1_fe y2, x3, c;
|
||||||
|
if (a->infinity) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* y^2 = x^3 + 7 */
|
||||||
|
secp256k1_fe_sqr(&y2, &a->y);
|
||||||
|
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
|
||||||
|
secp256k1_fe_set_int(&c, 7);
|
||||||
|
secp256k1_fe_add(&x3, &c);
|
||||||
|
secp256k1_fe_normalize_weak(&x3);
|
||||||
|
return secp256k1_fe_equal_var(&y2, &x3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
|
||||||
|
/* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate.
|
||||||
|
*
|
||||||
|
* Note that there is an implementation described at
|
||||||
|
* https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
|
||||||
|
* which trades a multiply for a square, but in practice this is actually slower,
|
||||||
|
* mainly because it requires more normalizations.
|
||||||
|
*/
|
||||||
|
secp256k1_fe t1,t2,t3,t4;
|
||||||
|
/** 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).
|
||||||
|
*/
|
||||||
|
r->infinity = a->infinity;
|
||||||
|
if (r->infinity) {
|
||||||
|
if (rzr != NULL) {
|
||||||
|
secp256k1_fe_set_int(rzr, 1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rzr != NULL) {
|
||||||
|
*rzr = a->y;
|
||||||
|
secp256k1_fe_normalize_weak(rzr);
|
||||||
|
secp256k1_fe_mul_int(rzr, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
secp256k1_fe_mul(&r->z, &a->z, &a->y);
|
||||||
|
secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */
|
||||||
|
secp256k1_fe_sqr(&t1, &a->x);
|
||||||
|
secp256k1_fe_mul_int(&t1, 3); /* T1 = 3*X^2 (3) */
|
||||||
|
secp256k1_fe_sqr(&t2, &t1); /* T2 = 9*X^4 (1) */
|
||||||
|
secp256k1_fe_sqr(&t3, &a->y);
|
||||||
|
secp256k1_fe_mul_int(&t3, 2); /* T3 = 2*Y^2 (2) */
|
||||||
|
secp256k1_fe_sqr(&t4, &t3);
|
||||||
|
secp256k1_fe_mul_int(&t4, 2); /* T4 = 8*Y^4 (2) */
|
||||||
|
secp256k1_fe_mul(&t3, &t3, &a->x); /* T3 = 2*X*Y^2 (1) */
|
||||||
|
r->x = t3;
|
||||||
|
secp256k1_fe_mul_int(&r->x, 4); /* X' = 8*X*Y^2 (4) */
|
||||||
|
secp256k1_fe_negate(&r->x, &r->x, 4); /* X' = -8*X*Y^2 (5) */
|
||||||
|
secp256k1_fe_add(&r->x, &t2); /* X' = 9*X^4 - 8*X*Y^2 (6) */
|
||||||
|
secp256k1_fe_negate(&t2, &t2, 1); /* T2 = -9*X^4 (2) */
|
||||||
|
secp256k1_fe_mul_int(&t3, 6); /* T3 = 12*X*Y^2 (6) */
|
||||||
|
secp256k1_fe_add(&t3, &t2); /* T3 = 12*X*Y^2 - 9*X^4 (8) */
|
||||||
|
secp256k1_fe_mul(&r->y, &t1, &t3); /* Y' = 36*X^3*Y^2 - 27*X^6 (1) */
|
||||||
|
secp256k1_fe_negate(&t2, &t4, 2); /* T2 = -8*Y^4 (3) */
|
||||||
|
secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */
|
||||||
|
}
|
||||||
|
|
||||||
|
static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
|
||||||
|
VERIFY_CHECK(!secp256k1_gej_is_infinity(a));
|
||||||
|
secp256k1_gej_double_var(r, a, rzr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {
|
||||||
|
/* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */
|
||||||
|
secp256k1_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) {
|
||||||
|
secp256k1_fe_set_int(rzr, 1);
|
||||||
|
}
|
||||||
|
*r = *a;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->infinity = 0;
|
||||||
|
secp256k1_fe_sqr(&z22, &b->z);
|
||||||
|
secp256k1_fe_sqr(&z12, &a->z);
|
||||||
|
secp256k1_fe_mul(&u1, &a->x, &z22);
|
||||||
|
secp256k1_fe_mul(&u2, &b->x, &z12);
|
||||||
|
secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z);
|
||||||
|
secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
|
||||||
|
secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
|
||||||
|
secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
|
||||||
|
if (secp256k1_fe_normalizes_to_zero_var(&h)) {
|
||||||
|
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
|
||||||
|
secp256k1_gej_double_var(r, a, rzr);
|
||||||
|
} else {
|
||||||
|
if (rzr != NULL) {
|
||||||
|
secp256k1_fe_set_int(rzr, 0);
|
||||||
|
}
|
||||||
|
r->infinity = 1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
secp256k1_fe_sqr(&i2, &i);
|
||||||
|
secp256k1_fe_sqr(&h2, &h);
|
||||||
|
secp256k1_fe_mul(&h3, &h, &h2);
|
||||||
|
secp256k1_fe_mul(&h, &h, &b->z);
|
||||||
|
if (rzr != NULL) {
|
||||||
|
*rzr = h;
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&r->z, &a->z, &h);
|
||||||
|
secp256k1_fe_mul(&t, &u1, &h2);
|
||||||
|
r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
|
||||||
|
secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
|
||||||
|
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
|
||||||
|
secp256k1_fe_add(&r->y, &h3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) {
|
||||||
|
/* 8 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */
|
||||||
|
secp256k1_fe z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;
|
||||||
|
if (a->infinity) {
|
||||||
|
VERIFY_CHECK(rzr == NULL);
|
||||||
|
secp256k1_gej_set_ge(r, b);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (b->infinity) {
|
||||||
|
if (rzr != NULL) {
|
||||||
|
secp256k1_fe_set_int(rzr, 1);
|
||||||
|
}
|
||||||
|
*r = *a;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r->infinity = 0;
|
||||||
|
|
||||||
|
secp256k1_fe_sqr(&z12, &a->z);
|
||||||
|
u1 = a->x; secp256k1_fe_normalize_weak(&u1);
|
||||||
|
secp256k1_fe_mul(&u2, &b->x, &z12);
|
||||||
|
s1 = a->y; secp256k1_fe_normalize_weak(&s1);
|
||||||
|
secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
|
||||||
|
secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
|
||||||
|
secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
|
||||||
|
if (secp256k1_fe_normalizes_to_zero_var(&h)) {
|
||||||
|
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
|
||||||
|
secp256k1_gej_double_var(r, a, rzr);
|
||||||
|
} else {
|
||||||
|
if (rzr != NULL) {
|
||||||
|
secp256k1_fe_set_int(rzr, 0);
|
||||||
|
}
|
||||||
|
r->infinity = 1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
secp256k1_fe_sqr(&i2, &i);
|
||||||
|
secp256k1_fe_sqr(&h2, &h);
|
||||||
|
secp256k1_fe_mul(&h3, &h, &h2);
|
||||||
|
if (rzr != NULL) {
|
||||||
|
*rzr = h;
|
||||||
|
}
|
||||||
|
secp256k1_fe_mul(&r->z, &a->z, &h);
|
||||||
|
secp256k1_fe_mul(&t, &u1, &h2);
|
||||||
|
r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
|
||||||
|
secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
|
||||||
|
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
|
||||||
|
secp256k1_fe_add(&r->y, &h3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) {
|
||||||
|
/* 9 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */
|
||||||
|
secp256k1_fe az, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;
|
||||||
|
|
||||||
|
if (b->infinity) {
|
||||||
|
*r = *a;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (a->infinity) {
|
||||||
|
secp256k1_fe bzinv2, bzinv3;
|
||||||
|
r->infinity = b->infinity;
|
||||||
|
secp256k1_fe_sqr(&bzinv2, bzinv);
|
||||||
|
secp256k1_fe_mul(&bzinv3, &bzinv2, bzinv);
|
||||||
|
secp256k1_fe_mul(&r->x, &b->x, &bzinv2);
|
||||||
|
secp256k1_fe_mul(&r->y, &b->y, &bzinv3);
|
||||||
|
secp256k1_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.
|
||||||
|
*/
|
||||||
|
secp256k1_fe_mul(&az, &a->z, bzinv);
|
||||||
|
|
||||||
|
secp256k1_fe_sqr(&z12, &az);
|
||||||
|
u1 = a->x; secp256k1_fe_normalize_weak(&u1);
|
||||||
|
secp256k1_fe_mul(&u2, &b->x, &z12);
|
||||||
|
s1 = a->y; secp256k1_fe_normalize_weak(&s1);
|
||||||
|
secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az);
|
||||||
|
secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
|
||||||
|
secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
|
||||||
|
if (secp256k1_fe_normalizes_to_zero_var(&h)) {
|
||||||
|
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
|
||||||
|
secp256k1_gej_double_var(r, a, NULL);
|
||||||
|
} else {
|
||||||
|
r->infinity = 1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
secp256k1_fe_sqr(&i2, &i);
|
||||||
|
secp256k1_fe_sqr(&h2, &h);
|
||||||
|
secp256k1_fe_mul(&h3, &h, &h2);
|
||||||
|
r->z = a->z; secp256k1_fe_mul(&r->z, &r->z, &h);
|
||||||
|
secp256k1_fe_mul(&t, &u1, &h2);
|
||||||
|
r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
|
||||||
|
secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
|
||||||
|
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
|
||||||
|
secp256k1_fe_add(&r->y, &h3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) {
|
||||||
|
/* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */
|
||||||
|
static const secp256k1_fe fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
|
||||||
|
secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
|
||||||
|
secp256k1_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 = 4*(R^2-Q)
|
||||||
|
* Y3 = 4*(R*(3*Q-2*R^2)-M^4)
|
||||||
|
* Z3 = 2*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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */
|
||||||
|
u1 = a->x; secp256k1_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */
|
||||||
|
secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */
|
||||||
|
s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */
|
||||||
|
secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */
|
||||||
|
secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */
|
||||||
|
t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */
|
||||||
|
m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */
|
||||||
|
secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */
|
||||||
|
secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */
|
||||||
|
secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */
|
||||||
|
secp256k1_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 = secp256k1_fe_normalizes_to_zero(&m) &
|
||||||
|
secp256k1_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;
|
||||||
|
secp256k1_fe_mul_int(&rr_alt, 2); /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */
|
||||||
|
secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 */
|
||||||
|
|
||||||
|
secp256k1_fe_cmov(&rr_alt, &rr, !degenerate);
|
||||||
|
secp256k1_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. */
|
||||||
|
secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */
|
||||||
|
secp256k1_fe_mul(&q, &n, &t); /* 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. */
|
||||||
|
secp256k1_fe_sqr(&n, &n);
|
||||||
|
secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */
|
||||||
|
secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */
|
||||||
|
secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Malt*Z (1) */
|
||||||
|
infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity);
|
||||||
|
secp256k1_fe_mul_int(&r->z, 2); /* r->z = Z3 = 2*Malt*Z (2) */
|
||||||
|
secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */
|
||||||
|
secp256k1_fe_add(&t, &q); /* t = Ralt^2-Q (3) */
|
||||||
|
secp256k1_fe_normalize_weak(&t);
|
||||||
|
r->x = t; /* r->x = Ralt^2-Q (1) */
|
||||||
|
secp256k1_fe_mul_int(&t, 2); /* t = 2*x3 (2) */
|
||||||
|
secp256k1_fe_add(&t, &q); /* t = 2*x3 - Q: (4) */
|
||||||
|
secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*x3 - Q) (1) */
|
||||||
|
secp256k1_fe_add(&t, &n); /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */
|
||||||
|
secp256k1_fe_negate(&r->y, &t, 3); /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */
|
||||||
|
secp256k1_fe_normalize_weak(&r->y);
|
||||||
|
secp256k1_fe_mul_int(&r->x, 4); /* r->x = X3 = 4*(Ralt^2-Q) */
|
||||||
|
secp256k1_fe_mul_int(&r->y, 4); /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */
|
||||||
|
|
||||||
|
/** In case a->infinity == 1, replace r with (b->x, b->y, 1). */
|
||||||
|
secp256k1_fe_cmov(&r->x, &b->x, a->infinity);
|
||||||
|
secp256k1_fe_cmov(&r->y, &b->y, a->infinity);
|
||||||
|
secp256k1_fe_cmov(&r->z, &fe_1, a->infinity);
|
||||||
|
r->infinity = infinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {
|
||||||
|
/* Operations: 4 mul, 1 sqr */
|
||||||
|
secp256k1_fe zz;
|
||||||
|
VERIFY_CHECK(!secp256k1_fe_is_zero(s));
|
||||||
|
secp256k1_fe_sqr(&zz, s);
|
||||||
|
secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */
|
||||||
|
secp256k1_fe_mul(&r->y, &r->y, &zz);
|
||||||
|
secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */
|
||||||
|
secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) {
|
||||||
|
secp256k1_fe x, y;
|
||||||
|
VERIFY_CHECK(!a->infinity);
|
||||||
|
x = a->x;
|
||||||
|
secp256k1_fe_normalize(&x);
|
||||||
|
y = a->y;
|
||||||
|
secp256k1_fe_normalize(&y);
|
||||||
|
secp256k1_fe_to_storage(&r->x, &x);
|
||||||
|
secp256k1_fe_to_storage(&r->y, &y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a) {
|
||||||
|
secp256k1_fe_from_storage(&r->x, &a->x);
|
||||||
|
secp256k1_fe_from_storage(&r->y, &a->y);
|
||||||
|
r->infinity = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) {
|
||||||
|
secp256k1_fe_storage_cmov(&r->x, &a->x, flag);
|
||||||
|
secp256k1_fe_storage_cmov(&r->y, &a->y, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
|
||||||
|
static const secp256k1_fe beta = SECP256K1_FE_CONST(
|
||||||
|
0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,
|
||||||
|
0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul
|
||||||
|
);
|
||||||
|
*r = *a;
|
||||||
|
secp256k1_fe_mul(&r->x, &r->x, &beta);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
|
||||||
|
secp256k1_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 */
|
||||||
|
secp256k1_fe_mul(&yz, &a->y, &a->z);
|
||||||
|
return secp256k1_fe_is_quad_var(&yz);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
41
secp256k1zkp/depend/secp256k1-zkp/src/hash.h
Normal file
41
secp256k1zkp/depend/secp256k1-zkp/src/hash.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_HASH_
|
||||||
|
#define _SECP256K1_HASH_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t s[8];
|
||||||
|
uint32_t buf[16]; /* In big endian */
|
||||||
|
size_t bytes;
|
||||||
|
} secp256k1_sha256_t;
|
||||||
|
|
||||||
|
static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash);
|
||||||
|
static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t size);
|
||||||
|
static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
secp256k1_sha256_t inner, outer;
|
||||||
|
} secp256k1_hmac_sha256_t;
|
||||||
|
|
||||||
|
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t size);
|
||||||
|
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size);
|
||||||
|
static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char v[32];
|
||||||
|
unsigned char k[32];
|
||||||
|
int retry;
|
||||||
|
} secp256k1_rfc6979_hmac_sha256_t;
|
||||||
|
|
||||||
|
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen);
|
||||||
|
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen);
|
||||||
|
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng);
|
||||||
|
|
||||||
|
#endif
|
281
secp256k1zkp/depend/secp256k1-zkp/src/hash_impl.h
Normal file
281
secp256k1zkp/depend/secp256k1-zkp/src/hash_impl.h
Normal file
|
@ -0,0 +1,281 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2014 Pieter Wuille *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SECP256K1_HASH_IMPL_H_
|
||||||
|
#define _SECP256K1_HASH_IMPL_H_
|
||||||
|
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||||
|
#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
|
||||||
|
#define Sigma0(x) (((x) >> 2 | (x) << 30) ^ ((x) >> 13 | (x) << 19) ^ ((x) >> 22 | (x) << 10))
|
||||||
|
#define Sigma1(x) (((x) >> 6 | (x) << 26) ^ ((x) >> 11 | (x) << 21) ^ ((x) >> 25 | (x) << 7))
|
||||||
|
#define sigma0(x) (((x) >> 7 | (x) << 25) ^ ((x) >> 18 | (x) << 14) ^ ((x) >> 3))
|
||||||
|
#define sigma1(x) (((x) >> 17 | (x) << 15) ^ ((x) >> 19 | (x) << 13) ^ ((x) >> 10))
|
||||||
|
|
||||||
|
#define Round(a,b,c,d,e,f,g,h,k,w) do { \
|
||||||
|
uint32_t t1 = (h) + Sigma1(e) + Ch((e), (f), (g)) + (k) + (w); \
|
||||||
|
uint32_t t2 = Sigma0(a) + Maj((a), (b), (c)); \
|
||||||
|
(d) += t1; \
|
||||||
|
(h) = t1 + t2; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
#define BE32(x) (x)
|
||||||
|
#else
|
||||||
|
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) {
|
||||||
|
hash->s[0] = 0x6a09e667ul;
|
||||||
|
hash->s[1] = 0xbb67ae85ul;
|
||||||
|
hash->s[2] = 0x3c6ef372ul;
|
||||||
|
hash->s[3] = 0xa54ff53aul;
|
||||||
|
hash->s[4] = 0x510e527ful;
|
||||||
|
hash->s[5] = 0x9b05688cul;
|
||||||
|
hash->s[6] = 0x1f83d9abul;
|
||||||
|
hash->s[7] = 0x5be0cd19ul;
|
||||||
|
hash->bytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */
|
||||||
|
static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) {
|
||||||
|
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 = BE32(chunk[0]));
|
||||||
|
Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = BE32(chunk[1]));
|
||||||
|
Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = BE32(chunk[2]));
|
||||||
|
Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = BE32(chunk[3]));
|
||||||
|
Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = BE32(chunk[4]));
|
||||||
|
Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = BE32(chunk[5]));
|
||||||
|
Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = BE32(chunk[6]));
|
||||||
|
Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = BE32(chunk[7]));
|
||||||
|
Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = BE32(chunk[8]));
|
||||||
|
Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = BE32(chunk[9]));
|
||||||
|
Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = BE32(chunk[10]));
|
||||||
|
Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = BE32(chunk[11]));
|
||||||
|
Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = BE32(chunk[12]));
|
||||||
|
Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = BE32(chunk[13]));
|
||||||
|
Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = BE32(chunk[14]));
|
||||||
|
Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = BE32(chunk[15]));
|
||||||
|
|
||||||
|
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));
|
||||||
|
Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3));
|
||||||
|
Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4));
|
||||||
|
Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5));
|
||||||
|
Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6));
|
||||||
|
Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7));
|
||||||
|
Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8));
|
||||||
|
Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9));
|
||||||
|
Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10));
|
||||||
|
Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11));
|
||||||
|
Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12));
|
||||||
|
Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13));
|
||||||
|
Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14));
|
||||||
|
Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15));
|
||||||
|
Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0));
|
||||||
|
|
||||||
|
Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1));
|
||||||
|
Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2));
|
||||||
|
Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3));
|
||||||
|
Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4));
|
||||||
|
Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5));
|
||||||
|
Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6));
|
||||||
|
Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7));
|
||||||
|
Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8));
|
||||||
|
Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9));
|
||||||
|
Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10));
|
||||||
|
Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11));
|
||||||
|
Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12));
|
||||||
|
Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13));
|
||||||
|
Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14));
|
||||||
|
Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15));
|
||||||
|
Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0));
|
||||||
|
|
||||||
|
Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1));
|
||||||
|
Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2));
|
||||||
|
Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3));
|
||||||
|
Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4));
|
||||||
|
Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5));
|
||||||
|
Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6));
|
||||||
|
Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7));
|
||||||
|
Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8));
|
||||||
|
Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9));
|
||||||
|
Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10));
|
||||||
|
Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11));
|
||||||
|
Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12));
|
||||||
|
Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13));
|
||||||
|
Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14));
|
||||||
|
Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15));
|
||||||
|
Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0));
|
||||||
|
|
||||||
|
s[0] += a;
|
||||||
|
s[1] += b;
|
||||||
|
s[2] += c;
|
||||||
|
s[3] += d;
|
||||||
|
s[4] += e;
|
||||||
|
s[5] += f;
|
||||||
|
s[6] += g;
|
||||||
|
s[7] += h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t len) {
|
||||||
|
size_t bufsize = hash->bytes & 0x3F;
|
||||||
|
hash->bytes += len;
|
||||||
|
while (bufsize + len >= 64) {
|
||||||
|
/* Fill the buffer, and process it. */
|
||||||
|
memcpy(((unsigned char*)hash->buf) + bufsize, data, 64 - bufsize);
|
||||||
|
data += 64 - bufsize;
|
||||||
|
len -= 64 - bufsize;
|
||||||
|
secp256k1_sha256_transform(hash->s, hash->buf);
|
||||||
|
bufsize = 0;
|
||||||
|
}
|
||||||
|
if (len) {
|
||||||
|
/* Fill the buffer with what remains. */
|
||||||
|
memcpy(((unsigned char*)hash->buf) + bufsize, data, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32) {
|
||||||
|
static const unsigned char pad[64] = {0x80, 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, 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};
|
||||||
|
uint32_t sizedesc[2];
|
||||||
|
uint32_t out[8];
|
||||||
|
int i = 0;
|
||||||
|
sizedesc[0] = BE32(hash->bytes >> 29);
|
||||||
|
sizedesc[1] = BE32(hash->bytes << 3);
|
||||||
|
secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));
|
||||||
|
secp256k1_sha256_write(hash, (const unsigned char*)sizedesc, 8);
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
out[i] = BE32(hash->s[i]);
|
||||||
|
hash->s[i] = 0;
|
||||||
|
}
|
||||||
|
memcpy(out32, (const unsigned char*)out, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t keylen) {
|
||||||
|
int n;
|
||||||
|
unsigned char rkey[64];
|
||||||
|
if (keylen <= 64) {
|
||||||
|
memcpy(rkey, key, keylen);
|
||||||
|
memset(rkey + keylen, 0, 64 - keylen);
|
||||||
|
} else {
|
||||||
|
secp256k1_sha256_t sha256;
|
||||||
|
secp256k1_sha256_initialize(&sha256);
|
||||||
|
secp256k1_sha256_write(&sha256, key, keylen);
|
||||||
|
secp256k1_sha256_finalize(&sha256, rkey);
|
||||||
|
memset(rkey + 32, 0, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
secp256k1_sha256_initialize(&hash->outer);
|
||||||
|
for (n = 0; n < 64; n++) {
|
||||||
|
rkey[n] ^= 0x5c;
|
||||||
|
}
|
||||||
|
secp256k1_sha256_write(&hash->outer, rkey, 64);
|
||||||
|
|
||||||
|
secp256k1_sha256_initialize(&hash->inner);
|
||||||
|
for (n = 0; n < 64; n++) {
|
||||||
|
rkey[n] ^= 0x5c ^ 0x36;
|
||||||
|
}
|
||||||
|
secp256k1_sha256_write(&hash->inner, rkey, 64);
|
||||||
|
memset(rkey, 0, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size) {
|
||||||
|
secp256k1_sha256_write(&hash->inner, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32) {
|
||||||
|
unsigned char temp[32];
|
||||||
|
secp256k1_sha256_finalize(&hash->inner, temp);
|
||||||
|
secp256k1_sha256_write(&hash->outer, temp, 32);
|
||||||
|
memset(temp, 0, 32);
|
||||||
|
secp256k1_sha256_finalize(&hash->outer, out32);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen) {
|
||||||
|
secp256k1_hmac_sha256_t hmac;
|
||||||
|
static const unsigned char zero[1] = {0x00};
|
||||||
|
static const unsigned char one[1] = {0x01};
|
||||||
|
|
||||||
|
memset(rng->v, 0x01, 32); /* RFC6979 3.2.b. */
|
||||||
|
memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */
|
||||||
|
|
||||||
|
/* RFC6979 3.2.d. */
|
||||||
|
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||||
|
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||||
|
secp256k1_hmac_sha256_write(&hmac, zero, 1);
|
||||||
|
secp256k1_hmac_sha256_write(&hmac, key, keylen);
|
||||||
|
secp256k1_hmac_sha256_finalize(&hmac, rng->k);
|
||||||
|
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||||
|
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||||
|
secp256k1_hmac_sha256_finalize(&hmac, rng->v);
|
||||||
|
|
||||||
|
/* RFC6979 3.2.f. */
|
||||||
|
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||||
|
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||||
|
secp256k1_hmac_sha256_write(&hmac, one, 1);
|
||||||
|
secp256k1_hmac_sha256_write(&hmac, key, keylen);
|
||||||
|
secp256k1_hmac_sha256_finalize(&hmac, rng->k);
|
||||||
|
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||||
|
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||||
|
secp256k1_hmac_sha256_finalize(&hmac, rng->v);
|
||||||
|
rng->retry = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen) {
|
||||||
|
/* RFC6979 3.2.h. */
|
||||||
|
static const unsigned char zero[1] = {0x00};
|
||||||
|
if (rng->retry) {
|
||||||
|
secp256k1_hmac_sha256_t hmac;
|
||||||
|
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||||
|
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||||
|
secp256k1_hmac_sha256_write(&hmac, zero, 1);
|
||||||
|
secp256k1_hmac_sha256_finalize(&hmac, rng->k);
|
||||||
|
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||||
|
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||||
|
secp256k1_hmac_sha256_finalize(&hmac, rng->v);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (outlen > 0) {
|
||||||
|
secp256k1_hmac_sha256_t hmac;
|
||||||
|
int now = outlen;
|
||||||
|
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||||
|
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||||
|
secp256k1_hmac_sha256_finalize(&hmac, rng->v);
|
||||||
|
if (now > 32) {
|
||||||
|
now = 32;
|
||||||
|
}
|
||||||
|
memcpy(out, rng->v, now);
|
||||||
|
out += now;
|
||||||
|
outlen -= now;
|
||||||
|
}
|
||||||
|
|
||||||
|
rng->retry = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng) {
|
||||||
|
memset(rng->k, 0, 32);
|
||||||
|
memset(rng->v, 0, 32);
|
||||||
|
rng->retry = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef BE32
|
||||||
|
#undef Round
|
||||||
|
#undef sigma1
|
||||||
|
#undef sigma0
|
||||||
|
#undef Sigma1
|
||||||
|
#undef Sigma0
|
||||||
|
#undef Maj
|
||||||
|
#undef Ch
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,478 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Google Inc.
|
||||||
|
* Copyright 2014-2016 the libsecp256k1 contributors
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.bitcoin;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
import static org.bitcoin.NativeSecp256k1Util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>This class holds native methods to handle ECDSA verification.</p>
|
||||||
|
*
|
||||||
|
* <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
|
||||||
|
*
|
||||||
|
* <p>To build secp256k1 for use with bitcoinj, run
|
||||||
|
* `./configure --enable-jni --enable-experimental --enable-module-schnorr --enable-module-ecdh`
|
||||||
|
* and `make` then copy `.libs/libsecp256k1.so` to your system library path
|
||||||
|
* or point the JVM to the folder containing it with -Djava.library.path
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class NativeSecp256k1 {
|
||||||
|
|
||||||
|
private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
|
||||||
|
private static final Lock r = rwl.readLock();
|
||||||
|
private static final Lock w = rwl.writeLock();
|
||||||
|
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
|
||||||
|
/**
|
||||||
|
* Verifies the given secp256k1 signature in native code.
|
||||||
|
* Calling when enabled == false is undefined (probably library not loaded)
|
||||||
|
*
|
||||||
|
* @param data The data which was signed, must be exactly 32 bytes
|
||||||
|
* @param signature The signature
|
||||||
|
* @param pub The public key which did the signing
|
||||||
|
*/
|
||||||
|
public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < 520) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(520);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(data);
|
||||||
|
byteBuff.put(signature);
|
||||||
|
byteBuff.put(pub);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 Create an ECDSA signature.
|
||||||
|
*
|
||||||
|
* @param data Message hash, 32 bytes
|
||||||
|
* @param key Secret key, 32 bytes
|
||||||
|
*
|
||||||
|
* Return values
|
||||||
|
* @param sig byte array of signature
|
||||||
|
*/
|
||||||
|
public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < 32 + 32) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(32 + 32);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(data);
|
||||||
|
byteBuff.put(sec);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] sigArr = retByteArray[0];
|
||||||
|
int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(sigArr.length, sigLen, "Got bad signature length.");
|
||||||
|
|
||||||
|
return retVal == 0 ? new byte[0] : sigArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid
|
||||||
|
*
|
||||||
|
* @param seckey ECDSA Secret key, 32 bytes
|
||||||
|
*/
|
||||||
|
public static boolean secKeyVerify(byte[] seckey) {
|
||||||
|
Preconditions.checkArgument(seckey.length == 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < seckey.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(seckey.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(seckey);
|
||||||
|
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1;
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 Compute Pubkey - computes public key from secret key
|
||||||
|
*
|
||||||
|
* @param seckey ECDSA Secret key, 32 bytes
|
||||||
|
*
|
||||||
|
* Return values
|
||||||
|
* @param pubkey ECDSA Public key, 33 or 65 bytes
|
||||||
|
*/
|
||||||
|
//TODO add a 'compressed' arg
|
||||||
|
public static byte[] computePubkey(byte[] seckey) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(seckey.length == 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < seckey.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(seckey.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(seckey);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext());
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] pubArr = retByteArray[0];
|
||||||
|
int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
|
||||||
|
|
||||||
|
return retVal == 0 ? new byte[0]: pubArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 Cleanup - This destroys the secp256k1 context object
|
||||||
|
* This should be called at the end of the program for proper cleanup of the context.
|
||||||
|
*/
|
||||||
|
public static synchronized void cleanup() {
|
||||||
|
w.lock();
|
||||||
|
try {
|
||||||
|
secp256k1_destroy_context(Secp256k1Context.getContext());
|
||||||
|
} finally {
|
||||||
|
w.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long cloneContext() {
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
return secp256k1_ctx_clone(Secp256k1Context.getContext());
|
||||||
|
} finally { r.unlock(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
|
||||||
|
*
|
||||||
|
* @param tweak some bytes to tweak with
|
||||||
|
* @param seckey 32-byte seckey
|
||||||
|
*/
|
||||||
|
public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(privkey.length == 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(privkey);
|
||||||
|
byteBuff.put(tweak);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext());
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] privArr = retByteArray[0];
|
||||||
|
|
||||||
|
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(privArr.length, privLen, "Got bad pubkey length.");
|
||||||
|
|
||||||
|
assertEquals(retVal, 1, "Failed return value check.");
|
||||||
|
|
||||||
|
return privArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
|
||||||
|
*
|
||||||
|
* @param tweak some bytes to tweak with
|
||||||
|
* @param seckey 32-byte seckey
|
||||||
|
*/
|
||||||
|
public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(privkey.length == 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(privkey);
|
||||||
|
byteBuff.put(tweak);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext());
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] privArr = retByteArray[0];
|
||||||
|
|
||||||
|
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(privArr.length, privLen, "Got bad pubkey length.");
|
||||||
|
|
||||||
|
assertEquals(retVal, 1, "Failed return value check.");
|
||||||
|
|
||||||
|
return privArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
|
||||||
|
*
|
||||||
|
* @param tweak some bytes to tweak with
|
||||||
|
* @param pubkey 32-byte seckey
|
||||||
|
*/
|
||||||
|
public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(pubkey);
|
||||||
|
byteBuff.put(tweak);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length);
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] pubArr = retByteArray[0];
|
||||||
|
|
||||||
|
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
|
||||||
|
|
||||||
|
assertEquals(retVal, 1, "Failed return value check.");
|
||||||
|
|
||||||
|
return pubArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it
|
||||||
|
*
|
||||||
|
* @param tweak some bytes to tweak with
|
||||||
|
* @param pubkey 32-byte seckey
|
||||||
|
*/
|
||||||
|
public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(pubkey);
|
||||||
|
byteBuff.put(tweak);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length);
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] pubArr = retByteArray[0];
|
||||||
|
|
||||||
|
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
|
||||||
|
|
||||||
|
assertEquals(retVal, 1, "Failed return value check.");
|
||||||
|
|
||||||
|
return pubArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 create ECDH secret - constant time ECDH calculation
|
||||||
|
*
|
||||||
|
* @param seckey byte array of secret key used in exponentiaion
|
||||||
|
* @param pubkey byte array of public key used in exponentiaion
|
||||||
|
*/
|
||||||
|
public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(seckey);
|
||||||
|
byteBuff.put(pubkey);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length);
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] resArr = retByteArray[0];
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(resArr.length, 32, "Got bad result length.");
|
||||||
|
assertEquals(retVal, 1, "Failed return value check.");
|
||||||
|
|
||||||
|
return resArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 randomize - updates the context randomization
|
||||||
|
*
|
||||||
|
* @param seed 32-byte random seed
|
||||||
|
*/
|
||||||
|
public static synchronized boolean randomize(byte[] seed) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(seed.length == 32 || seed == null);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < seed.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(seed.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(seed);
|
||||||
|
|
||||||
|
w.lock();
|
||||||
|
try {
|
||||||
|
return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1;
|
||||||
|
} finally {
|
||||||
|
w.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] schnorrSign(byte[] data, byte[] sec) throws AssertFailException {
|
||||||
|
Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(32 + 32);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(data);
|
||||||
|
byteBuff.put(sec);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_schnorr_sign(byteBuff, Secp256k1Context.getContext());
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] sigArr = retByteArray[0];
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(sigArr.length, 64, "Got bad signature length.");
|
||||||
|
|
||||||
|
return retVal == 0 ? new byte[0] : sigArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native long secp256k1_ctx_clone(long context);
|
||||||
|
|
||||||
|
private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);
|
||||||
|
|
||||||
|
private static native void secp256k1_destroy_context(long context);
|
||||||
|
|
||||||
|
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_schnorr_sign(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,247 @@
|
||||||
|
package org.bitcoin;
|
||||||
|
|
||||||
|
import com.google.common.io.BaseEncoding;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import javax.xml.bind.DatatypeConverter;
|
||||||
|
import static org.bitcoin.NativeSecp256k1Util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class holds test cases defined for testing this library.
|
||||||
|
*/
|
||||||
|
public class NativeSecp256k1Test {
|
||||||
|
|
||||||
|
//TODO improve comments/add more tests
|
||||||
|
/**
|
||||||
|
* This tests verify() for a valid signature
|
||||||
|
*/
|
||||||
|
public static void testVerifyPos() throws AssertFailException{
|
||||||
|
boolean result = false;
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
|
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||||
|
|
||||||
|
result = NativeSecp256k1.verify( data, sig, pub);
|
||||||
|
assertEquals( result, true , "testVerifyPos");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests verify() for a non-valid signature
|
||||||
|
*/
|
||||||
|
public static void testVerifyNeg() throws AssertFailException{
|
||||||
|
boolean result = false;
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
|
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||||
|
|
||||||
|
result = NativeSecp256k1.verify( data, sig, pub);
|
||||||
|
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||||
|
assertEquals( result, false , "testVerifyNeg");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests secret key verify() for a valid secretkey
|
||||||
|
*/
|
||||||
|
public static void testSecKeyVerifyPos() throws AssertFailException{
|
||||||
|
boolean result = false;
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
|
||||||
|
result = NativeSecp256k1.secKeyVerify( sec );
|
||||||
|
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||||
|
assertEquals( result, true , "testSecKeyVerifyPos");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests secret key verify() for a invalid secretkey
|
||||||
|
*/
|
||||||
|
public static void testSecKeyVerifyNeg() throws AssertFailException{
|
||||||
|
boolean result = false;
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
|
||||||
|
|
||||||
|
result = NativeSecp256k1.secKeyVerify( sec );
|
||||||
|
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||||
|
assertEquals( result, false , "testSecKeyVerifyNeg");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests public key create() for a valid secretkey
|
||||||
|
*/
|
||||||
|
public static void testPubKeyCreatePos() throws AssertFailException{
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.computePubkey( sec);
|
||||||
|
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests public key create() for a invalid secretkey
|
||||||
|
*/
|
||||||
|
public static void testPubKeyCreateNeg() throws AssertFailException{
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.computePubkey( sec);
|
||||||
|
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( pubkeyString, "" , "testPubKeyCreateNeg");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests sign() for a valid secretkey
|
||||||
|
*/
|
||||||
|
public static void testSignPos() throws AssertFailException{
|
||||||
|
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.sign(data, sec);
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests sign() for a invalid secretkey
|
||||||
|
*/
|
||||||
|
public static void testSignNeg() throws AssertFailException{
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.sign(data, sec);
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString, "" , "testSignNeg");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key tweak-add
|
||||||
|
*/
|
||||||
|
public static void testPrivKeyTweakAdd_1() throws AssertFailException {
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data );
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key tweak-mul
|
||||||
|
*/
|
||||||
|
public static void testPrivKeyTweakMul_1() throws AssertFailException {
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data );
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key tweak-add uncompressed
|
||||||
|
*/
|
||||||
|
public static void testPrivKeyTweakAdd_2() throws AssertFailException {
|
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data );
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key tweak-mul uncompressed
|
||||||
|
*/
|
||||||
|
public static void testPrivKeyTweakMul_2() throws AssertFailException {
|
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data );
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests seed randomization
|
||||||
|
*/
|
||||||
|
public static void testRandomize() throws AssertFailException {
|
||||||
|
byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random"
|
||||||
|
boolean result = NativeSecp256k1.randomize(seed);
|
||||||
|
assertEquals( result, true, "testRandomize");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests signSchnorr() for a valid secretkey
|
||||||
|
*/
|
||||||
|
public static void testSchnorrSign() throws AssertFailException{
|
||||||
|
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.schnorrSign(data, sec);
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString, "C5E929AA058B982048760422D3B563749B7D0E50C5EBD8CD2FFC23214BD6A2F1B072C13880997EBA847CF20F2F90FCE07C1CA33A890A4127095A351127F8D95F" , "testSchnorrSign");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests signSchnorr() for a valid secretkey
|
||||||
|
*/
|
||||||
|
public static void testCreateECDHSecret() throws AssertFailException{
|
||||||
|
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub);
|
||||||
|
String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws AssertFailException{
|
||||||
|
|
||||||
|
|
||||||
|
System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n");
|
||||||
|
|
||||||
|
assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" );
|
||||||
|
|
||||||
|
//Test verify() success/fail
|
||||||
|
testVerifyPos();
|
||||||
|
testVerifyNeg();
|
||||||
|
|
||||||
|
//Test secKeyVerify() success/fail
|
||||||
|
testSecKeyVerifyPos();
|
||||||
|
testSecKeyVerifyNeg();
|
||||||
|
|
||||||
|
//Test computePubkey() success/fail
|
||||||
|
testPubKeyCreatePos();
|
||||||
|
testPubKeyCreateNeg();
|
||||||
|
|
||||||
|
//Test sign() success/fail
|
||||||
|
testSignPos();
|
||||||
|
testSignNeg();
|
||||||
|
|
||||||
|
//Test Schnorr (partial support) //TODO
|
||||||
|
testSchnorrSign();
|
||||||
|
//testSchnorrVerify
|
||||||
|
//testSchnorrRecovery
|
||||||
|
|
||||||
|
//Test privKeyTweakAdd() 1
|
||||||
|
testPrivKeyTweakAdd_1();
|
||||||
|
|
||||||
|
//Test privKeyTweakMul() 2
|
||||||
|
testPrivKeyTweakMul_1();
|
||||||
|
|
||||||
|
//Test privKeyTweakAdd() 3
|
||||||
|
testPrivKeyTweakAdd_2();
|
||||||
|
|
||||||
|
//Test privKeyTweakMul() 4
|
||||||
|
testPrivKeyTweakMul_2();
|
||||||
|
|
||||||
|
//Test randomize()
|
||||||
|
testRandomize();
|
||||||
|
|
||||||
|
//Test ECDH
|
||||||
|
testCreateECDHSecret();
|
||||||
|
|
||||||
|
NativeSecp256k1.cleanup();
|
||||||
|
|
||||||
|
System.out.println(" All tests passed." );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014-2016 the libsecp256k1 contributors
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.bitcoin;
|
||||||
|
|
||||||
|
public class NativeSecp256k1Util{
|
||||||
|
|
||||||
|
public static void assertEquals( int val, int val2, String message ) throws AssertFailException{
|
||||||
|
if( val != val2 )
|
||||||
|
throw new AssertFailException("FAIL: " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{
|
||||||
|
if( val != val2 )
|
||||||
|
throw new AssertFailException("FAIL: " + message);
|
||||||
|
else
|
||||||
|
System.out.println("PASS: " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertEquals( String val, String val2, String message ) throws AssertFailException{
|
||||||
|
if( !val.equals(val2) )
|
||||||
|
throw new AssertFailException("FAIL: " + message);
|
||||||
|
else
|
||||||
|
System.out.println("PASS: " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AssertFailException extends Exception {
|
||||||
|
public AssertFailException(String message) {
|
||||||
|
super( message );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014-2016 the libsecp256k1 contributors
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.bitcoin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class holds the context reference used in native methods
|
||||||
|
* to handle ECDSA operations.
|
||||||
|
*/
|
||||||
|
public class Secp256k1Context {
|
||||||
|
private static final boolean enabled; //true if the library is loaded
|
||||||
|
private static final long context; //ref to pointer to context obj
|
||||||
|
|
||||||
|
static { //static initializer
|
||||||
|
boolean isEnabled = true;
|
||||||
|
long contextRef = -1;
|
||||||
|
try {
|
||||||
|
System.loadLibrary("secp256k1");
|
||||||
|
contextRef = secp256k1_init_context();
|
||||||
|
} catch (UnsatisfiedLinkError e) {
|
||||||
|
System.out.println("UnsatisfiedLinkError: " + e.toString());
|
||||||
|
isEnabled = false;
|
||||||
|
}
|
||||||
|
enabled = isEnabled;
|
||||||
|
context = contextRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getContext() {
|
||||||
|
if(!enabled) return -1; //sanity check
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native long secp256k1_init_context();
|
||||||
|
}
|
|
@ -0,0 +1,411 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "org_bitcoin_NativeSecp256k1.h"
|
||||||
|
#include "include/secp256k1.h"
|
||||||
|
#include "include/secp256k1_ecdh.h"
|
||||||
|
#include "include/secp256k1_recovery.h"
|
||||||
|
#include "include/secp256k1_schnorr.h"
|
||||||
|
|
||||||
|
|
||||||
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
|
||||||
|
(JNIEnv* env, jclass classObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
|
||||||
|
jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx);
|
||||||
|
|
||||||
|
(void)classObject;(void)env;
|
||||||
|
|
||||||
|
return ctx_clone_l;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
|
||||||
|
const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return secp256k1_context_randomize(ctx, seed);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
|
||||||
|
(JNIEnv* env, jclass classObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
|
||||||
|
secp256k1_context_destroy(ctx);
|
||||||
|
|
||||||
|
(void)classObject;(void)env;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
|
||||||
|
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* sigdata = { (unsigned char*) (data + 32) };
|
||||||
|
const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) };
|
||||||
|
|
||||||
|
secp256k1_ecdsa_signature sig;
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
|
||||||
|
int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen);
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
unsigned char* secKey = (unsigned char*) (data + 32);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray sigArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
secp256k1_ecdsa_signature sig[72];
|
||||||
|
|
||||||
|
int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL );
|
||||||
|
|
||||||
|
unsigned char outputSer[72];
|
||||||
|
size_t outputLen = 72;
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2;
|
||||||
|
}
|
||||||
|
|
||||||
|
intsarray[0] = outputLen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
sigArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return secp256k1_ec_seckey_verify(ctx, secKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray pubkeyArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey);
|
||||||
|
|
||||||
|
unsigned char outputSer[65];
|
||||||
|
size_t outputLen = 65;
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
|
||||||
|
}
|
||||||
|
|
||||||
|
intsarray[0] = outputLen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
pubkeyArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* tweak = (unsigned char*) (privkey + 32);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray privArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
int privkeylen = 32;
|
||||||
|
|
||||||
|
int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak);
|
||||||
|
|
||||||
|
intsarray[0] = privkeylen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
privArray = (*env)->NewByteArray(env, privkeylen);
|
||||||
|
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, privArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* tweak = (unsigned char*) (privkey + 32);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray privArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
int privkeylen = 32;
|
||||||
|
|
||||||
|
int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak);
|
||||||
|
|
||||||
|
intsarray[0] = privkeylen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
privArray = (*env)->NewByteArray(env, privkeylen);
|
||||||
|
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, privArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/
|
||||||
|
unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* tweak = (unsigned char*) (pkey + publen);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray pubArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
unsigned char outputSer[65];
|
||||||
|
size_t outputLen = 65;
|
||||||
|
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
|
||||||
|
}
|
||||||
|
|
||||||
|
intsarray[0] = outputLen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
pubArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* tweak = (unsigned char*) (pkey + publen);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray pubArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
unsigned char outputSer[65];
|
||||||
|
size_t outputLen = 65;
|
||||||
|
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
|
||||||
|
|
||||||
|
if ( ret ) {
|
||||||
|
ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
|
||||||
|
}
|
||||||
|
|
||||||
|
intsarray[0] = outputLen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
pubArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine
|
||||||
|
(JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys)
|
||||||
|
{
|
||||||
|
(void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
unsigned char* secKey = (unsigned char*) (data + 32);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray sigArray, intsByteArray;
|
||||||
|
unsigned char intsarray[1];
|
||||||
|
unsigned char sig[64];
|
||||||
|
|
||||||
|
int ret = secp256k1_schnorr_sign(ctx, sig, data, secKey, NULL, NULL);
|
||||||
|
|
||||||
|
intsarray[0] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
sigArray = (*env)->NewByteArray(env, 64);
|
||||||
|
(*env)->SetByteArrayRegion(env, sigArray, 0, 64, (jbyte*)sig);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 1);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* pubdata = (const unsigned char*) (secdata + 32);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray outArray, intsByteArray;
|
||||||
|
unsigned char intsarray[1];
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
unsigned char nonce_res[32];
|
||||||
|
size_t outputLen = 32;
|
||||||
|
|
||||||
|
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
ret = secp256k1_ecdh(
|
||||||
|
ctx,
|
||||||
|
nonce_res,
|
||||||
|
&pubkey,
|
||||||
|
secdata
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
intsarray[0] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
outArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, outArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 1);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||||
|
#include <jni.h>
|
||||||
|
#include "include/secp256k1.h"
|
||||||
|
/* Header for class org_bitcoin_NativeSecp256k1 */
|
||||||
|
|
||||||
|
#ifndef _Included_org_bitcoin_NativeSecp256k1
|
||||||
|
#define _Included_org_bitcoin_NativeSecp256k1
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ctx_clone
|
||||||
|
* Signature: (J)J
|
||||||
|
*/
|
||||||
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
|
||||||
|
(JNIEnv *, jclass, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_context_randomize
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)I
|
||||||
|
*/
|
||||||
|
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_privkey_tweak_add
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_privkey_tweak_mul
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_pubkey_tweak_add
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_pubkey_tweak_mul
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_destroy_context
|
||||||
|
* Signature: (J)V
|
||||||
|
*/
|
||||||
|
SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
|
||||||
|
(JNIEnv *, jclass, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ecdsa_verify
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JII)I
|
||||||
|
*/
|
||||||
|
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ecdsa_sign
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ec_seckey_verify
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)I
|
||||||
|
*/
|
||||||
|
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ec_pubkey_create
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ec_pubkey_parse
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_schnorr_sign
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ecdh
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "org_bitcoin_Secp256k1Context.h"
|
||||||
|
#include "include/secp256k1.h"
|
||||||
|
|
||||||
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
|
||||||
|
(JNIEnv* env, jclass classObject)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||||
|
|
||||||
|
(void)classObject;(void)env;
|
||||||
|
|
||||||
|
return (uintptr_t)ctx;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||||
|
#include <jni.h>
|
||||||
|
#include "include/secp256k1.h"
|
||||||
|
/* Header for class org_bitcoin_Secp256k1Context */
|
||||||
|
|
||||||
|
#ifndef _Included_org_bitcoin_Secp256k1Context
|
||||||
|
#define _Included_org_bitcoin_Secp256k1Context
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_Secp256k1Context
|
||||||
|
* Method: secp256k1_init_context
|
||||||
|
* Signature: ()J
|
||||||
|
*/
|
||||||
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
|
||||||
|
(JNIEnv *, jclass);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,8 @@
|
||||||
|
include_HEADERS += include/secp256k1_ecdh.h
|
||||||
|
noinst_HEADERS += src/modules/ecdh/main_impl.h
|
||||||
|
noinst_HEADERS += src/modules/ecdh/tests_impl.h
|
||||||
|
if USE_BENCHMARK
|
||||||
|
noinst_PROGRAMS += bench_ecdh
|
||||||
|
bench_ecdh_SOURCES = src/bench_ecdh.c
|
||||||
|
bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
|
||||||
|
endif
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2015 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_ECDH_MAIN_
|
||||||
|
#define _SECP256K1_MODULE_ECDH_MAIN_
|
||||||
|
|
||||||
|
#include "include/secp256k1_ecdh.h"
|
||||||
|
#include "ecmult_const_impl.h"
|
||||||
|
|
||||||
|
int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) {
|
||||||
|
int ret = 0;
|
||||||
|
int overflow = 0;
|
||||||
|
secp256k1_gej res;
|
||||||
|
secp256k1_ge pt;
|
||||||
|
secp256k1_scalar s;
|
||||||
|
ARG_CHECK(result != NULL);
|
||||||
|
ARG_CHECK(point != NULL);
|
||||||
|
ARG_CHECK(scalar != NULL);
|
||||||
|
(void)ctx;
|
||||||
|
|
||||||
|
secp256k1_pubkey_load(ctx, &pt, point);
|
||||||
|
secp256k1_scalar_set_b32(&s, scalar, &overflow);
|
||||||
|
if (overflow || secp256k1_scalar_is_zero(&s)) {
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
unsigned char x[32];
|
||||||
|
unsigned char y[1];
|
||||||
|
secp256k1_sha256_t sha;
|
||||||
|
|
||||||
|
secp256k1_ecmult_const(&res, &pt, &s);
|
||||||
|
secp256k1_ge_set_gej(&pt, &res);
|
||||||
|
/* Compute a hash of the point in compressed form
|
||||||
|
* Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not
|
||||||
|
* expect its output to be secret and has a timing sidechannel. */
|
||||||
|
secp256k1_fe_normalize(&pt.x);
|
||||||
|
secp256k1_fe_normalize(&pt.y);
|
||||||
|
secp256k1_fe_get_b32(x, &pt.x);
|
||||||
|
y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y);
|
||||||
|
|
||||||
|
secp256k1_sha256_initialize(&sha);
|
||||||
|
secp256k1_sha256_write(&sha, y, sizeof(y));
|
||||||
|
secp256k1_sha256_write(&sha, x, sizeof(x));
|
||||||
|
secp256k1_sha256_finalize(&sha, result);
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
secp256k1_scalar_clear(&s);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue