109 lines
3.2 KiB
Nim
109 lines
3.2 KiB
Nim
import
|
|
../secp256k1,
|
|
unittest,
|
|
stew/ptrops
|
|
|
|
{.used.}
|
|
|
|
const
|
|
msg0 = SkMessage([
|
|
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,
|
|
])
|
|
msg1 = SkMessage([
|
|
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] = [
|
|
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 =
|
|
data[0] += 1
|
|
true
|
|
|
|
proc brokenRng(data: var openArray[byte]): bool = false
|
|
|
|
suite "secp256k1":
|
|
test "Key ops":
|
|
let
|
|
sk = SkSecretKey.random(workingRng).expect("should get a key")
|
|
pk = sk.toPublicKey()
|
|
|
|
check:
|
|
SkSecretKey.fromRaw(sk.toRaw())[].toHex() == sk.toHex()
|
|
SkSecretKey.fromHex(sk.toHex())[].toHex() == sk.toHex()
|
|
SkPublicKey.fromRaw(pk.toRaw())[].toHex() == pk.toHex()
|
|
SkPublicKey.fromRaw(pk.toRawCompressed())[].toHex() == pk.toHex()
|
|
SkPublicKey.fromHex(pk.toHex())[].toHex() == pk.toHex()
|
|
SkXOnlyPublicKey.fromRaw(pk.toXOnly.toRaw())[].toHex() == pk.toXOnly.toHex()
|
|
SkXOnlyPublicKey.fromHex(pk.toXOnly.toHex())[].toHex() == pk.toXOnly.toHex()
|
|
SkSecretKey.random(brokenRng).isErr
|
|
|
|
test "Signatures":
|
|
let
|
|
sk = SkSecretKey.random(workingRng)[]
|
|
pk = sk.toPublicKey()
|
|
otherPk = SkSecretKey.random(workingRng)[].toPublicKey()
|
|
sig = sign(sk, msg0)
|
|
sig2 = signRecoverable(sk, msg0)
|
|
sig3 = signSchnorr(sk, msg0, workingRng)[]
|
|
sig4 = signSchnorr(sk, cast[array[SkMessageSize, byte]](msg0), workingRng)[]
|
|
sig5 = signSchnorr(sk, msg2, workingRng)[]
|
|
|
|
check:
|
|
verify(sig, msg0, pk)
|
|
not verify(sig, msg0, otherPk)
|
|
not verify(sig, msg1, pk)
|
|
recover(sig2, msg0)[] == pk
|
|
recover(sig2, msg1)[] != pk
|
|
SkSignature.fromDer(sig.toDer())[].toHex() == sig.toHex()
|
|
verify(sig3, msg0, pk)
|
|
sig3 == sig4
|
|
verify(sig5, msg2, pk)
|
|
|
|
test "Message":
|
|
check:
|
|
SkMessage.fromBytes([]).isErr()
|
|
SkMessage.fromBytes([0'u8]).isErr()
|
|
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)
|