tiny-secp256k1
This library is under development, and, like the secp256k1 C library (through secp256k1-sys Rust crate) it depends on, this is a research effort to determine an optimal API for end-users of the bitcoinjs ecosystem.
Installation
npm
npm install tiny-secp256k1
yarn
yarn add tiny-secp256k1
WebAssembly and Node.js version
Previous version of tiny-secp256k1
implement C++ addon through NAN (Native Abstractions for Node.js) and elliptic as fallback when addon can not be built or in browser-like environement.
Current version use Rust crate (which use C library) compiled to WebAssembly. With Wasm same code executed in any environment. Wasm is faster than elliptic
but slower than node bindings (results in PR or you can run own benchmark in benches
directory).
Building
For building locally you need C/C++ toolchain, Rust version >=1.50.0 and wasm-opt
from binaryen.
rustup is a recommended way to install Rust
. You also will need wasm32-unknown-unknown
target.
rustup toolchain install stable --target wasm32-unknown-unknown --component clippy --component rustfmt
After installing development dependencies with npm
you can build Wasm:
make build-wasm
or run tests:
make test
Alternative way is to use Docker:
% docker build -t tiny-secp256k1 .
% docker run -it --rm -v `pwd`:/tiny-secp256k1 -w /tiny-secp256k1 tiny-secp256k1
# make build
Examples
tiny-secp256k1
includes two examples. First is simple script for Node.js which generate random data and print arguments and methods results. Second is React app.
React app is builded in GitHub Actions on each commit to master branch and uploaded to gh-pages branch, which is always available online: https://bitcoinjs.github.io/tiny-secp256k1/
Documentation
isPoint (A)
isPoint :: Buffer -> Bool
Returns false
if
A
is not encoded with a sequence tag of 0x02
, 0x03
or 0x04
A.x
is not in [1...p - 1]
A.y
is not in [1...p - 1]
isPointCompressed (A)
isPointCompressed :: Buffer -> Bool
Returns false
if the pubkey is not compressed.
isXOnlyPoint (A)
isXOnlyPoint :: Buffer -> Bool
Returns false
if the pubkey is not an xOnlyPubkey.
isPrivate (d)
isPrivate :: Buffer -> Bool
Returns false
if
d
is not 256-bit, ord
is not in [1..order - 1]
pointAdd (A, B[, compressed])
pointAdd :: Buffer -> Buffer [-> Bool] -> Maybe Buffer
Returns null
if result is at infinity.
Throws:
Expected Point
if !isPoint(A)
Expected Point
if !isPoint(B)
pointAddScalar (A, tweak[, compressed])
pointAddScalar :: Buffer -> Buffer [-> Bool] -> Maybe Buffer
Returns null
if result is at infinity.
Throws:
Expected Point
if !isPoint(A)
Expected Tweak
if tweak
is not in [0...order - 1]
pointCompress (A, compressed)
pointCompress :: Buffer -> Bool -> Buffer
Throws:
Expected Point
if !isPoint(A)
pointFromScalar (d[, compressed])
pointFromScalar :: Buffer [-> Bool] -> Maybe Buffer
Returns null
if result is at infinity.
Throws:
Expected Private
if !isPrivate(d)
xOnlyPointFromScalar (d)
xOnlyPointFromScalar :: Buffer -> Buffer
Returns the xOnlyPubkey for a given private key
Throws:
Expected Private
if !isPrivate(d)
xOnlyPointFromPoint (p)
xOnlyPointFromPoint :: Buffer -> Buffer
Returns the xOnlyPubkey for a given DER public key
Throws:
Expected Point
if !isPoint(p)
pointMultiply (A, tweak[, compressed])
pointMultiply :: Buffer -> Buffer [-> Bool] -> Maybe Buffer
Returns null
if result is at infinity.
Throws:
Expected Point
if !isPoint(A)
Expected Tweak
if tweak
is not in [0...order - 1]
privateAdd (d, tweak)
privateAdd :: Buffer -> Buffer -> Maybe Buffer
Returns null
if result is equal to 0
.
Throws:
Expected Private
if !isPrivate(d)
Expected Tweak
if tweak
is not in [0...order - 1]
privateSub (d, tweak)
privateSub :: Buffer -> Buffer -> Maybe Buffer
Returns null
if result is equal to 0
.
Throws:
Expected Private
if !isPrivate(d)
Expected Tweak
if tweak
is not in [0...order - 1]
privateNegate (d)
privateNegate :: Buffer -> Buffer
Returns the negation of d on the order n (n - d
)
Throws:
Expected Private
if !isPrivate(d)
xOnlyPointAddTweak (p, tweak)
xOnlyPointAddTweak :: Buffer -> Buffer -> { parity: 1 | 0; xOnlyPubkey: Buffer; }
Returns the tweaked xOnlyPubkey along with the parity bit (number type of 1|0)
Throws:
Expected Point
if !isXOnlyPoint(p)
Expected Tweak
if !isXOnlyPoint(tweak)
xOnlyPointAddTweakCheck (p1, p2, tweak[, tweakParity])
xOnlyPointAddTweakCheck :: Buffer -> Buffer -> Buffer [-> 1 | 0] -> Bool
Checks the tweaked pubkey (p2) against the original pubkey (p1) and tweak.
This is slightly slower if you include tweakParity, tweakParity will make it
faster for aggregation later on.
Throws:
Expected Point
if !isXOnlyPoint(p1)
Expected Point
if !isXOnlyPoint(p2)
Expected Tweak
if !isXOnlyPoint(tweak)
Expected Parity
if tweakParity is not 1 or 0
sign (h, d[, e])
sign :: Buffer -> Buffer [-> Buffer] -> Buffer
Returns normalized signatures, each of (r, s) values are guaranteed to less than order / 2
.
Uses RFC6979.
Adds e
as Added Entropy to the deterministic k generation.
Throws:
Expected Private
if !isPrivate(d)
Expected Scalar
if h
is not 256-bitExpected Extra Data (32 bytes)
if e
is not 256-bit
signRecoverable (h, d[, e])
signRecoverable :: Buffer -> Buffer [-> Buffer] -> { recoveryId: 0 | 1 | 2 | 3; signature: Buffer; }
Returns normalized signatures and recovery Id, each of (r, s) values are guaranteed to less than order / 2
.
Uses RFC6979.
Adds e
as Added Entropy to the deterministic k generation.
Throws:
Expected Private
if !isPrivate(d)
Expected Scalar
if h
is not 256-bitExpected Extra Data (32 bytes)
if e
is not 256-bit
signSchnorr (h, d[, e])
signSchnorr :: Buffer -> Buffer [-> Buffer] -> Buffer
Returns normalized schnorr signature.
Uses BIP340 nonce generation.
Adds e
as Added Entropy.
Throws:
Expected Private
if !isPrivate(d)
Expected Scalar
if h
is not 256-bitExpected Extra Data (32 bytes)
if e
is not 256-bit
verify (h, Q, signature[, strict = false])
verify :: Buffer -> Buffer -> Buffer [-> Bool] -> Bool
Returns false
if any of (r, s) values are equal to 0
, or if the signature is rejected.
If strict
is true
, valid signatures with any of (r, s) values greater than order / 2
are rejected.
Throws:
Expected Point
if !isPoint(Q)
Expected Signature
if signature
has any (r, s) values not in range [0...order - 1]
Expected Scalar
if h
is not 256-bit
recover (h, signature, recoveryId[, compressed = false])
verify :: Buffer -> Buffer -> Number [-> Bool] -> Maybe Buffer
Returns the ECDSA public key from a signature if it can be recovered, null
otherwise.
Throws:
Expected Signature
if signature
has any (r, s) values not in range (0...order - 1]
Bad Recovery Id
if recid & 2 !== 0
and signature
has any r value not in range (0...P - N - 1]
Expected Hash
if h
is not 256-bit
verifySchnorr (h, Q, signature)
verifySchnorr :: Buffer -> Buffer -> Buffer -> Bool
Returns false
if any of (r, s) values are equal to 0
, or if the signature is rejected.
Throws:
Expected Point
if !isPoint(Q)
Expected Signature
if signature
has any (r, s) values not in range [0...order - 1]
Expected Scalar
if h
is not 256-bit
Credit
This library uses the native library secp256k1 by the bitcoin-core developers through Rust crate secp256k1-sys, including derivatives of its tests and test vectors.
LICENSE MIT