Get rid of ecdhRaw and export ecdh with custom hash func

This commit is contained in:
jangko 2023-04-20 10:09:47 +07:00
parent 05b4bde6d0
commit 206e5360b8
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
4 changed files with 55 additions and 49 deletions

2
.gitignore vendored
View File

@ -7,3 +7,5 @@ nimble.paths
ci/build_nim.sh ci/build_nim.sh
ci/NimBinaries/ ci/NimBinaries/
ci/nim/ ci/nim/
*.exe

View File

@ -72,9 +72,6 @@ const
SkEdchSecretSize* = 32 SkEdchSecretSize* = 32
## ECDH-agreed key size ## ECDH-agreed key size
SkEcdhRawSecretSize* = 33
## ECDH-agreed raw key size
type type
SkPublicKey* {.requiresInit.} = object SkPublicKey* {.requiresInit.} = object
## Representation of public key. ## Representation of public key.
@ -116,10 +113,7 @@ type
## Representation of ECDH shared secret ## Representation of ECDH shared secret
data*: array[SkEdchSecretSize, byte] data*: array[SkEdchSecretSize, byte]
SkEcdhRawSecret* {.requiresInit.} = object SkEcdhHashFunc* = secp256k1_ecdh_hash_function
## Representation of ECDH shared secret, with leading `y` byte
# (`y` is 0x02 when pubkey.y is even or 0x03 when odd)
data*: array[SkEcdhRawSecretSize, byte]
SkResult*[T] = Result[T, cstring] SkResult*[T] = Result[T, cstring]
@ -607,26 +601,26 @@ func recover*(sig: SkRecoverableSignature, msg: SkMessage): SkResult[SkPublicKey
ok(SkPublicKey(data: data)) ok(SkPublicKey(data: data))
func ecdh*(seckey: SkSecretKey, pubkey: SkPublicKey): SkEcdhSecret = func ecdh*(seckey: SkSecretKey, pubkey: SkPublicKey): SkResult[SkEcdhSecret] =
## Calculate ECDH shared secret. ## Calculate ECDH shared secret.
var secret {.noinit.}: array[SkEdchSecretSize, byte] var secret {.noinit.}: array[SkEdchSecretSize, byte]
let res = secp256k1_ecdh( if secp256k1_ecdh(
secp256k1_context_no_precomp, secret.baseAddr, unsafeAddr pubkey.data, secp256k1_context_no_precomp, secret.baseAddr, unsafeAddr pubkey.data,
seckey.data.baseAddr) seckey.data.baseAddr) != 1:
doAssert res == 1, "cannot compute ECDH secret, keys invalid?" return err("cannot compute ECDH secret, keys invalid?")
SkEcdhSecret(data: secret) ok(SkEcdhSecret(data: secret))
func ecdhRaw*(seckey: SkSecretKey, pubkey: SkPublicKey): SkEcdhRawSecret = func ecdh*[N: static[int]](seckey: SkSecretKey, pubkey: SkPublicKey,
## Calculate ECDH shared secret, ethereum style hashfn: SkEcdhHashFunc, data: pointer): SkResult[array[N, byte]] =
# TODO - deprecate: https://github.com/status-im/nim-eth/issues/222 ## Calculate ECDH shared secret using custom hash function.
var secret {.noinit.}: array[SkEcdhRawSecretSize, byte] var secret {.noinit.}: array[N, byte]
let res = secp256k1_ecdh_raw( if secp256k1_ecdh(
secp256k1_context_no_precomp, secret.baseAddr, unsafeAddr pubkey.data, secp256k1_context_no_precomp, secret.baseAddr, unsafeAddr pubkey.data,
seckey.data.baseAddr) seckey.data.baseAddr, hashfn, data) != 1:
doAssert res == 1, "cannot compute raw ECDH secret, keys invalid?" return err("cannot compute ECDH secret, keys invalid?")
SkEcdhRawSecret(data: secret) ok(secret)
func clear*(v: var SkSecretKey) = func clear*(v: var SkSecretKey) =
## Wipe and clear memory of Secp256k1 `private key`. ## Wipe and clear memory of Secp256k1 `private key`.
@ -640,12 +634,6 @@ func clear*(v: var SkEcdhSecret) =
## result in undefined behaviour or Defect ## result in undefined behaviour or Defect
burnMem(v.data) burnMem(v.data)
func clear*(v: var SkEcdhRawSecret) =
## Wipe and clear memory of ECDH `shared secret`.
## After calling this function, the key is invalid and using it elsewhere will
## result in undefined behaviour or Defect
burnMem(v.data)
func `$`*( func `$`*(
v: SkPublicKey | SkSecretKey | SkXOnlyPublicKey | SkSignature | SkRecoverableSignature | SkSchnorrSignature): string = v: SkPublicKey | SkSecretKey | SkXOnlyPublicKey | SkSignature | SkRecoverableSignature | SkSchnorrSignature): string =
toHex(v) toHex(v)
@ -665,7 +653,6 @@ proc default*(T: type SkSignature): T {.error: "loophole".}
proc default*(T: type SkRecoverableSignature): T {.error: "loophole".} proc default*(T: type SkRecoverableSignature): T {.error: "loophole".}
proc default*(T: type SkSchnorrSignature): T {.error: "loophole".} proc default*(T: type SkSchnorrSignature): T {.error: "loophole".}
proc default*(T: type SkEcdhSecret): T {.error: "loophole".} proc default*(T: type SkEcdhSecret): T {.error: "loophole".}
proc default*(T: type SkEcdhRawSecret): T {.error: "loophole".}
func tweakAdd*(secretKey: var SkSecretKey, tweak: openArray[byte]): SkResult[void] = func tweakAdd*(secretKey: var SkSecretKey, tweak: openArray[byte]): SkResult[void] =
let res = secp256k1_ec_privkey_tweak_add( let res = secp256k1_ec_privkey_tweak_add(

View File

@ -35,7 +35,7 @@ type
secp256k1_ecdh_hash_function* = proc (output: ptr byte, secp256k1_ecdh_hash_function* = proc (output: ptr byte,
x32, y32: ptr byte, x32, y32: ptr byte,
data: pointer) {.cdecl, raises: [].} data: pointer): cint {.cdecl, raises: [].}
secp256k1_context* = object secp256k1_context* = object
secp256k1_scratch_space* = object secp256k1_scratch_space* = object
@ -312,23 +312,6 @@ template secp256k1_ecdh*(ctx: ptr secp256k1_context; output32: ptr byte;
secp256k1_ecdh(ctx, output32, pubkey, privkey, secp256k1_ecdh(ctx, output32, pubkey, privkey,
secp256k1_ecdh_hash_function_default(), nil) secp256k1_ecdh_hash_function_default(), nil)
proc secp256k1_ecdh_raw*(ctx: ptr secp256k1_context; output32: ptr byte;
pubkey: ptr secp256k1_pubkey;
input32: ptr byte): cint {.secp.}
## 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 33-byte array which will be populated by an ECDH
## secret computed from the point and scalar in form
## of compressed point
## In: pubkey: a pointer to a secp256k1_pubkey containing an
## initialized public key
## privkey: a 32-byte scalar with which to multiply the point
##
## Multikey interface follows
type type
secp256k1_xonly_pubkey* = object secp256k1_xonly_pubkey* = object
## Opaque data structure that holds a parsed and valid "x-only" public key. ## Opaque data structure that holds a parsed and valid "x-only" public key.

View File

@ -1,4 +1,7 @@
import ../secp256k1, unittest import
../secp256k1,
unittest,
stew/ptrops
{.used.} {.used.}
@ -15,13 +18,13 @@ const
1'u8, 0, 0, 0, 0, 0, 0, 0, 1'u8, 0, 0, 0, 0, 0, 0, 0,
1'u8, 0, 0, 0, 0, 0, 0, 0, 1'u8, 0, 0, 0, 0, 0, 0, 0,
]) ])
msg2 = array[40, byte]([ msg2: array[40, byte] = [
0'u8, 0, 0, 0, 0, 0, 0, 0, 0'u8, 0, 0, 0, 0, 0, 0, 0,
0'u8, 0, 0, 0, 0, 0, 0, 0, 0'u8, 0, 0, 0, 0, 0, 0, 0,
0'u8, 0, 0, 0, 0, 0, 0, 0, 0'u8, 0, 0, 0, 0, 0, 0, 0,
0'u8, 0, 0, 0, 0, 0, 0, 0, 0'u8, 0, 0, 0, 0, 0, 0, 0,
0'u8, 0, 0, 0, 0, 0, 0, 0, 0'u8, 0, 0, 0, 0, 0, 0, 0,
]) ]
proc workingRng(data: var openArray[byte]): bool = proc workingRng(data: var openArray[byte]): bool =
data[0] += 1 data[0] += 1
@ -72,3 +75,34 @@ suite "secp256k1":
SkMessage.fromBytes([]).isErr() SkMessage.fromBytes([]).isErr()
SkMessage.fromBytes([0'u8]).isErr() SkMessage.fromBytes([0'u8]).isErr()
SkMessage.fromBytes(array[32, byte](msg0)).isOk() SkMessage.fromBytes(array[32, byte](msg0)).isOk()
test "Custom hash function":
proc customHash(output: ptr byte, x32, y32: ptr byte, data: pointer): cint
{.cdecl, raises: [].} =
# Save x and y as uncompressed public key
output[] = 0x04
copyMem(output.offset(1), x32, 32)
copyMem(output.offset(33), y32, 32)
return 1
proc skone(_: type SkSecretKey): SkSecretKey =
# silence noisy warning: Cannot prove that 'result' is initialized.
result = SkSecretKey.random(workingRng)[]
var data: array[SkRawSecretKeySize, byte]
zeroMem(data[0].addr, data.len)
data[31] = 1
copyMem(result.addr, data[0].addr, data.len)
let
sone = SkSecretKey.skone()
sb32 = SkSecretKey.random(workingRng)[]
pk0 = sone.toPublicKey
pk1 = sb32.toPublicKey
var
# compute using ECDH function with custom hash function
outputEcdh = ecdh[65](sb32, pk0, customHash, nil).get
# compute "explicitly"
pointSer = pk1.toRaw
check equalMem(outputEcdh.addr, pointSer.addr, 65)