nim-libp2p/libp2p/crypto/secp.nim

253 lines
9.1 KiB
Nim

## Nim-Libp2p
## Copyright (c) 2018 Status Research & Development GmbH
## Licensed under either of
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
## at your option.
## This file may not be copied, modified, or distributed except according to
## those terms.
import secp256k1 as s, stew/byteutils, nimcrypto/hash, nimcrypto/sha2
export sha2
const
SkRawPrivateKeySize* = 256 div 8
## Size of private key in octets (bytes)
SkRawSignatureSize* = SkRawPrivateKeySize * 2 + 1
## Size of signature in octets (bytes)
SkRawPublicKeySize* = SkRawPrivateKeySize + 1
## Size of public key in octets (bytes)
type
SkPublicKey* = distinct s.SkPublicKey
SkPrivateKey* = distinct s.SkSecretKey
SkKeyPair* = distinct s.SkKeyPair
SkSignature* = distinct s.SkSignature
Secp256k1Error* = object of CatchableError
## Exceptions generated by `libsecp256k1`
template toException(v: cstring): (ref Secp256k1Error) =
(ref Secp256k1Error)(msg: $v)
template pubkey*(v: SkKeyPair): SkPublicKey = SkPublicKey(s.SkKeyPair(v).pubkey)
template seckey*(v: SkKeyPair): SkPrivateKey = SkPrivateKey(s.SkKeyPair(v).seckey)
proc init*(key: var SkPrivateKey, data: openarray[byte]): bool {.raises: [Defect].} =
## Initialize Secp256k1 `private key` ``key`` from raw binary
## representation ``data``.
##
## Procedure returns ``true`` on success.
if (let v = SkSecretKey.fromRaw(data); v.isOk):
key = SkPrivateKey(v[])
return true
proc init*(key: var SkPrivateKey, data: string): bool {.raises: [Defect].} =
## Initialize Secp256k1 `private key` ``key`` from hexadecimal string
## representation ``data``.
##
## Procedure returns ``true`` on success.
try:
key = SkPrivateKey(SkSecretKey.fromHex(data).tryGet())
return true
except Secp256k1Error:
discard
proc init*(key: var SkPublicKey, data: openarray[byte]): bool {.raises: [Defect].} =
## Initialize Secp256k1 `public key` ``key`` from raw binary
## representation ``data``.
##
## Procedure returns ``true`` on success.
try:
key = SkPublicKey(s.SkPublicKey.fromRaw(data).tryGet())
return true
except Secp256k1Error:
discard
proc init*(key: var SkPublicKey, data: string): bool {.raises: [Defect].} =
## Initialize Secp256k1 `public key` ``key`` from hexadecimal string
## representation ``data``.
##
## Procedure returns ``true`` on success.
try:
key = SkPublicKey(s.SkPublicKey.fromHex(data).tryGet())
return true
except Secp256k1Error:
discard
proc init*(sig: var SkSignature, data: openarray[byte]): bool {.raises: [Defect].} =
## Initialize Secp256k1 `signature` ``sig`` from raw binary
## representation ``data``.
##
## Procedure returns ``true`` on success.
try:
sig = SkSignature(s.SkSignature.fromDer(data).tryGet())
return true
except Secp256k1Error:
discard
proc init*(sig: var SkSignature, data: string): bool {.raises: [Defect].} =
## Initialize Secp256k1 `signature` ``sig`` from hexadecimal string
## representation ``data``.
##
## Procedure returns ``true`` on success.
# TODO DER vs raw here is fishy
var buffer: seq[byte]
try:
buffer = hexToSeqByte(data)
except ValueError:
return false
result = init(sig, buffer)
proc init*(t: typedesc[SkPrivateKey],
data: openarray[byte]): SkPrivateKey {.raises: [Defect, Secp256k1Error].} =
## Initialize Secp256k1 `private key` from raw binary
## representation ``data``.
##
## Procedure returns `private key` on success.
SkPrivateKey(s.SkSecretKey.fromRaw(data).tryGet())
proc init*(t: typedesc[SkPrivateKey],
data: string): SkPrivateKey {.raises: [Defect, Secp256k1Error].} =
## Initialize Secp256k1 `private key` from hexadecimal string
## representation ``data``.
##
## Procedure returns `private key` on success.
s.SkSecretKey.fromHex(data).tryGet()
proc init*(t: typedesc[SkPublicKey],
data: openarray[byte]): SkPublicKey {.raises: [Defect, Secp256k1Error].} =
## Initialize Secp256k1 `public key` from raw binary
## representation ``data``.
##
## Procedure returns `public key` on success.
if not init(result, data):
raise newException(Secp256k1Error, "Incorrect binary form")
proc init*(t: typedesc[SkPublicKey],
data: string): SkPublicKey {.raises: [Defect, Secp256k1Error].} =
## Initialize Secp256k1 `public key` from hexadecimal string
## representation ``data``.
##
## Procedure returns `public key` on success.
if not init(result, data):
raise newException(Secp256k1Error, "Incorrect binary form")
proc init*(t: typedesc[SkSignature],
data: openarray[byte]): SkSignature {.raises: [Defect, Secp256k1Error].} =
## Initialize Secp256k1 `signature` from raw binary
## representation ``data``.
##
## Procedure returns `signature` on success.
if not init(result, data):
raise newException(Secp256k1Error, "Incorrect binary form")
proc init*(t: typedesc[SkSignature],
data: string): SkSignature {.raises: [Defect, Secp256k1Error].} =
## Initialize Secp256k1 `signature` from hexadecimal string
## representation ``data``.
##
## Procedure returns `signature` on success.
if not init(result, data):
raise newException(Secp256k1Error, "Incorrect binary form")
proc getKey*(key: SkPrivateKey): SkPublicKey {.raises: [Defect, Secp256k1Error].} =
## Calculate and return Secp256k1 `public key` from `private key` ``key``.
SkPublicKey(s.SkSecretKey(key).toPublicKey().tryGet())
proc random*(t: typedesc[SkPrivateKey]): SkPrivateKey =
## Generates new random private key.
SkPrivateKey(s.SkSecretKey.random().tryGet())
proc random*(t: typedesc[SkKeyPair]): SkKeyPair {.inline.} =
## Generates new random key pair.
SkKeyPair(s.SkKeyPair.random().tryGet())
proc toBytes*(key: SkPrivateKey, data: var openarray[byte]): int =
## Serialize Secp256k1 `private key` ``key`` to raw binary form and store it
## to ``data``.
##
## Procedure returns number of bytes (octets) needed to store
## Secp256k1 private key.
result = SkRawPrivateKeySize
if len(data) >= SkRawPrivateKeySize:
data[0..<SkRawPrivateKeySize] = s.SkSecretKey(key).toRaw()
proc toBytes*(key: SkPublicKey, data: var openarray[byte]): int =
## Serialize Secp256k1 `public key` ``key`` to raw binary form and store it
## to ``data``.
##
## Procedure returns number of bytes (octets) needed to store
## Secp256k1 public key.
result = SkRawPublicKeySize
if len(data) >= SkRawPublicKeySize:
data[0..<SkRawPublicKeySize] = s.SkPublicKey(key).toRawCompressed()
proc toBytes*(sig: SkSignature, data: var openarray[byte]): int =
## Serialize Secp256k1 `signature` ``sig`` to raw binary form and store it
## to ``data``.
##
## Procedure returns number of bytes (octets) needed to store
## Secp256k1 signature.
s.SkSignature(sig).toDer(data)
proc getBytes*(key: SkPrivateKey): seq[byte] {.inline.} =
## Serialize Secp256k1 `private key` and return it.
result = @(s.SkSecretKey(key).toRaw())
proc getBytes*(key: SkPublicKey): seq[byte] {.inline.} =
## Serialize Secp256k1 `public key` and return it.
result = @(s.SkPublicKey(key).toRawCompressed())
proc getBytes*(sig: SkSignature): seq[byte] {.inline.} =
## Serialize Secp256k1 `signature` and return it.
result = newSeq[byte](72)
let length = toBytes(sig, result)
result.setLen(length)
proc `==`*(ska, skb: SkPrivateKey): bool =
## Compare Secp256k1 `private key` objects for equality.
result = (s.SkSecretKey(ska).toRaw == s.SkSecretKey(skb).toRaw)
proc `==`*(pka, pkb: SkPublicKey): bool =
## Compare Secp256k1 `public key` objects for equality.
result = (s.SkPublicKey(pka).toRaw == s.SkPublicKey(pkb).toRaw)
proc `==`*(sia, sib: SkSignature): bool =
## Compare Secp256k1 `signature` objects for equality.
result = (s.SkSignature(sia).toRaw == s.SkSignature(sib).toRaw)
proc `$`*(key: SkPrivateKey): string = s.SkSecretKey(key).toHex()
## Return string representation of Secp256k1 `private key`.
proc `$`*(key: SkPublicKey): string =
## Return string representation of Secp256k1 `private key`.s
result = toHex(s.SkPublicKey(key).toRawCompressed())
proc `$`*(sig: SkSignature): string =
## Return string representation of Secp256k1 `signature`.s
result = toHex(s.SkSignature(sig).toDer())
proc sign*[T: byte|char](key: SkPrivateKey, msg: openarray[T]): SkSignature =
## Sign message `msg` using private key `key` and return signature object.
let h = sha256.digest(msg)
SkSignature(sign(s.SkSecretKey(key), h).tryGet())
proc verify*[T: byte|char](sig: SkSignature, msg: openarray[T],
key: SkPublicKey): bool =
let h = sha256.digest(msg)
verify(s.SkSignature(sig), h, s.SkPublicKey(key))
proc clear*(key: var SkPrivateKey) {.borrow.}
## Wipe and clear memory of Secp256k1 `private key`.
proc clear*(key: var SkPublicKey) {.borrow.}
## Wipe and clear memory of Secp256k1 `public key`.
proc clear*(sig: var SkSignature) {.borrow.}
## Wipe and clear memory of Secp256k1 `signature`.
# Internal memory representation size of signature object is 64 bytes.
proc clear*(pair: var SkKeyPair) {.borrow.}
proc verify*(seckey: SkPrivateKey): bool {.borrow.}