Common Lisp CFFI bindings to bitcoin-core/secp256k1 library that provides public-key cryptography over secp256k1 curve. secp256k1 signatures are used in Bitcoin, Ethereum and other blockchains.
See your package manager for installation instructions.
Note that basic build of secp256k1 supports only simple signing and verification and some features might not work such as recoverable signatures, public key comparisons, etc. For example, libsecp256k1 from ubuntu does not have functions for public key comparisons. Its always possible to build library from source to have all required features.
Example:
# Arch Linux
pacman -S libsecp256k1
# Ubuntu
apt install libsecp256k1-dev
# macos
brew tap cuber/homebrew-libsecp256k1
brew install libsecp256k1
This library is not on quicklisp.
- Clone this library to somewhere where asdf or quicklisp could find it (e.g.
~/common-lisp/
) - Load it to your image. (e.g.
(ql:quickload "secp256k1")
)
;; create secret key from 32 byte array
(secp256k1:make-secret-key #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1))
;; create public key from secret key
(secp256k1:public-key-create sec-key)
;; parse public key from bytes (see `public-key-serialize` for creating this byte array)
(secp256k1:public-key-parse
#(4 121 190 102 126 249 220 187 172 85 160 98 149 206 135 11 7 2 155 252 219 45
206 40 217 89 242 129 91 22 248 23 152 72 58 218 119 38 163 196 101 93 164
251 252 14 17 8 168 253 23 180 72 166 133 84 25 156 71 208 143 251 16 212 184))
There are 2 types of signatures and methods associated with them: signature*
and recov-signature*
.
They both are created using secret key. Signature contains only R and S value and verification assumes knowledge of the public key. Recoverable signature contains R, S and V (recovery id which is 0-3) and recovery procedure returns public key that was used for signature creation.
;; signature
(secp256k1:signature-sign message-hash32 secret-key) ; => signature
(secp256k1:signature-verify signature message-hash32 public-key) ; => nil or t
;; recoverable signature
(secp256k1:recov-signature-sign message-hash32 secret-key) ; => recov-signature
(secp256k1:recov-signature-recover recov-signature message-hash32) ; => nil or public key
public-key
, signature
, recov-signature
has data field with internal byte field representation that should not be used for persistance, hashing, etc.
Instead each structure has *-parse
, *-serialize
methods for working with portable byte representations and *-destructure
, *-from-components
for creating more structured representations.
For example:
(secp256k1:public-key-destructure public-key)
;; =>
;; (:X
;; #(121 190 102 126 249 220 187 172 85 160 98 149 206 135 11 7 2 155 252 219 45
;; 206 40 217 89 242 129 91 22 248 23 152)
;; :Y
;; #(72 58 218 119 38 163 196 101 93 164 251 252 14 17 8 168 253 23 180 72 166
;; 133 84 25 156 71 208 143 251 16 212 184))
Library raises specific error conditions if signing and parsing fails.
Conditions:
incorrect-secret-key-error
public-key-parse-error
signature-parse-error
signature-failure-error
recov-signature-parse-error
recov-signature-failure-error
Library has two packages secp256k1-ffi with raw CFFI bindings and secp256k1 with lispy wrapper that takes care of low-level details of CFFI bindings, secp256k1-context managment.
Message signing is ~30 times faster than Ironclad out of the box. AFAIC ironclad does not use deterministic nonce generation so its numbers could be inflated because of RNG.
CL-USER> (secp256k1-test:benchmark-report-compare-ironclad)
secp256k1 signing:
- SAMPLES TOTAL MINIMUM MAXIMUM MEDIAN AVERAGE DEVIATION
REAL-TIME 100 0.007999 0 0.001 0 0.00008 0.000271
RUN-TIME 100 0.00734 0.000072 0.000132 0.000073 0.000073 0.000006
USER-RUN-TIME 100 0.007338 0.000072 0.000125 0.000073 0.000073 0.000005
SYSTEM-RUN-TIME 100 0.000006 0 0.000003 0 0.0 0.0
PAGE-FAULTS 100 0 0 0 0 0 0.0
GC-RUN-TIME 100 0 0 0 0 0 0.0
BYTES-CONSED 100 260384 0 32768 0 2603.84 8830.112
EVAL-CALLS 100 0 0 0 0 0 0.0
ironclad signing:
- SAMPLES TOTAL MINIMUM MAXIMUM MEDIAN AVERAGE DEVIATION
REAL-TIME 100 0.238002 0.002 0.008 0.002 0.00238 0.000892
RUN-TIME 100 0.236695 0.001912 0.008223 0.002017 0.002367 0.000881
USER-RUN-TIME 100 0.236744 0.001913 0.008224 0.002018 0.002367 0.000881
SYSTEM-RUN-TIME 100 0.000011 0 0.000005 0 0.0 0.000001
PAGE-FAULTS 100 0 0 0 0 0 0.0
GC-RUN-TIME 100 14.443 0 4.154 0 0.14443 0.603128
BYTES-CONSED 100 271772736 2586672 2750592 2717440 2717727.3 24254.49
EVAL-CALLS 100 0 0 0 0 0 0.0