Priv to pub blst (#69)
* Add test vector to detect priv_to_pub bugs * Bug "narrowed" down to hesenbug that disappears when using fsanitize=address * Fix -d:release incompat with BLST * change privToPub comment * actually only GCC is affected, not Clang
This commit is contained in:
parent
ecfb3b6219
commit
7e5dfb906d
|
@ -9,3 +9,6 @@ build/
|
|||
*.la
|
||||
*.exe
|
||||
*.dll
|
||||
|
||||
# Sage
|
||||
*.sage.py
|
||||
|
|
1
amcl
1
amcl
|
@ -1 +0,0 @@
|
|||
Subproject commit fa0a45a35dfb0e6d16b5d4f9e0bca19b5460fe4b
|
|
@ -15,6 +15,8 @@ proc test(env, path: string, lang = "c") =
|
|||
mkDir "build"
|
||||
exec "nim " & lang & " " & env &
|
||||
" --outdir:build -r --hints:off --warnings:off " & path
|
||||
exec "nim " & lang & " -d:release " & env &
|
||||
" --outdir:build -r --hints:off --warnings:off " & path
|
||||
|
||||
### tasks
|
||||
task test, "Run all tests":
|
||||
|
@ -30,10 +32,13 @@ task test, "Run all tests":
|
|||
test "-d:BLS_BACKEND=miracl", "tests/eth2_vectors.nim"
|
||||
# key Derivation - EIP 2333
|
||||
test "-d:BLS_BACKEND=miracl", "tests/eip2333_key_derivation.nim"
|
||||
# Secret key to pubkey
|
||||
test "-d:BLS_BACKEND=miracl", "tests/priv_to_pub.nim"
|
||||
|
||||
when sizeof(int) == 8 and (defined(arm64) or defined(amd64)):
|
||||
test "-d:BLS_BACKEND=blst", "tests/eth2_vectors.nim"
|
||||
test "-d:BLS_BACKEND=blst", "tests/eip2333_key_derivation.nim"
|
||||
test "-d:BLS_BACKEND=blst", "tests/priv_to_pub.nim"
|
||||
|
||||
# # Ensure benchmarks stay relevant. Ignore Windows 32-bit at the moment
|
||||
# if not defined(windows) or not existsEnv"PLATFORM" or getEnv"PLATFORM" == "x64":
|
||||
|
|
|
@ -93,6 +93,30 @@ func `==`*(a, b: PublicKey or Signature or ProofOfPossession): bool {.inline.} =
|
|||
# ----------------------------------------------------------------------
|
||||
# Serialization / Deserialization
|
||||
|
||||
func toHex*(
|
||||
obj: SecretKey|PublicKey|Signature|ProofOfPossession|AggregateSignature,
|
||||
): string =
|
||||
## Return the hex representation of a BLS signature scheme object
|
||||
## They are serialized in compressed form
|
||||
when obj is SecretKey:
|
||||
const size = 32
|
||||
var bytes{.noInit.}: array[size, byte]
|
||||
bytes.blst_bendian_from_scalar(obj.scalar)
|
||||
elif obj is PublicKey:
|
||||
const size = 48
|
||||
var bytes{.noInit.}: array[size, byte]
|
||||
bytes.blst_p1_affine_compress(obj.point)
|
||||
elif obj is (Signature or ProofOfPossession):
|
||||
const size = 96
|
||||
var bytes{.noInit.}: array[size, byte]
|
||||
bytes.blst_p2_affine_compress(obj.point)
|
||||
elif obj is AggregateSignature:
|
||||
const size = 96
|
||||
var bytes{.noInit.}: array[size, byte]
|
||||
bytes.blst_p2_compress(obj.point)
|
||||
|
||||
result = bytes.toHex()
|
||||
|
||||
func fromBytes*(
|
||||
obj: var (Signature|ProofOfPossession),
|
||||
raw: openarray[byte] or array[96, byte]
|
||||
|
@ -100,7 +124,6 @@ func fromBytes*(
|
|||
## Initialize a BLS signature scheme object from
|
||||
## its raw bytes representation.
|
||||
## Returns true on success and false otherwise
|
||||
# TODO: consider using affine coordinates everywhere beside
|
||||
const L = 96
|
||||
when raw is array:
|
||||
result = obj.point.blst_p2_uncompress(raw) == BLST_SUCCESS
|
||||
|
@ -164,30 +187,6 @@ func fromHex*(
|
|||
except:
|
||||
return false
|
||||
|
||||
func toHex*(
|
||||
obj: SecretKey|PublicKey|Signature|ProofOfPossession|AggregateSignature,
|
||||
): string =
|
||||
## Return the hex representation of a BLS signature scheme object
|
||||
## They are serialized in compressed form
|
||||
when obj is SecretKey:
|
||||
const size = 32
|
||||
var bytes{.noInit.}: array[size, byte]
|
||||
bytes.blst_bendian_from_scalar(obj.scalar)
|
||||
elif obj is PublicKey:
|
||||
const size = 48
|
||||
var bytes{.noInit.}: array[size, byte]
|
||||
bytes.blst_p1_affine_compress(obj.point)
|
||||
elif obj is (Signature or ProofOfPossession):
|
||||
const size = 96
|
||||
var bytes{.noInit.}: array[size, byte]
|
||||
bytes.blst_p2_affine_compress(obj.point)
|
||||
elif obj is AggregateSignature:
|
||||
const size = 96
|
||||
var bytes{.noInit.}: array[size, byte]
|
||||
bytes.blst_p2_compress(obj.point)
|
||||
|
||||
result = bytes.toHex()
|
||||
|
||||
func serialize*(
|
||||
dst: var array[32, byte],
|
||||
obj: SecretKey): bool {.inline.} =
|
||||
|
@ -232,8 +231,10 @@ func exportRaw*(signature: Signature): array[96, byte] {.inline.}=
|
|||
|
||||
func privToPub*(secretKey: SecretKey): PublicKey {.inline.} =
|
||||
## Generates a public key from a secret key
|
||||
# TODO, small secret keys like "1000" are not properly
|
||||
# computed, those are used in test suites
|
||||
## Generates a public key from a secret key
|
||||
## This requires some -O3 compiler optimizations to be off
|
||||
## as such {.passC: "-fno-peel-loops -fno-tree-loop-vectorize".}
|
||||
## is automatically added to the compiler flags
|
||||
var pk {.noInit.}: blst_p1
|
||||
pk.blst_sk_to_pk_in_g1(secretKey.scalar)
|
||||
result.point.blst_p1_to_affine(pk)
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
|
||||
import std/os
|
||||
|
||||
when defined(gcc):
|
||||
# Using this option will miscompile
|
||||
# scalar multiplication. Clang works fine.
|
||||
{.passC: "-fno-tree-loop-vectorize".}
|
||||
|
||||
{.compile: ".."/".."/"vendor"/"blst"/"build"/"assembly.S".}
|
||||
{.compile: ".."/".."/"vendor"/"blst"/"src"/"server.c".}
|
||||
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
# Nim-BLSCurve
|
||||
# Copyright (c) 2018-Present 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 ../blscurve
|
||||
|
||||
# This test ensures that fake secret keys can be used for testing
|
||||
# In particular this caught compiler options that miscompile BLST,
|
||||
# namely -fpeel-loops -ftree-loop-vectorize
|
||||
# which are unfortunately enabled at -O3
|
||||
|
||||
proc test_sk_to_pk(seckey, pubkey: string) =
|
||||
|
||||
var sk{.noInit.}: SecretKey
|
||||
let ok = sk.fromHex(seckey)
|
||||
doAssert ok
|
||||
let pk = sk.privToPub()
|
||||
|
||||
doAssert pk.toHex() == pubkey, "\ncomputed: " & pk.toHex() & "\nexpected: " & pubkey & '\n'
|
||||
echo "SUCCESS"
|
||||
|
||||
test_sk_to_pk(
|
||||
seckey = "00000000000000000000000000000000000000000000000000000000000003e8",
|
||||
pubkey = "a60e75190e62b6a54142d147289a735c4ce11a9d997543da539a3db57def5ed83ba40b74e55065f02b35aa1d504c404b"
|
||||
)
|
||||
|
||||
test_sk_to_pk(
|
||||
seckey = "00000000000000000000000000000000000000000000000000000000000003e9",
|
||||
pubkey = "ae12039459c60491672b6a6282355d8765ba6272387fb91a3e9604fa2a81450cf16b870bb446fc3a3e0a187fff6f8945"
|
||||
)
|
||||
|
||||
test_sk_to_pk(
|
||||
seckey = "00000000000000000000000000000000000000000000000000000000000003ea",
|
||||
pubkey = "947b327c8a15b39634a426af70c062b50632a744eddd41b5a4686414ef4cd9746bb11d0a53c6c2ff21bbcf331e07ac92"
|
||||
)
|
||||
|
||||
test_sk_to_pk(
|
||||
seckey = "00000000000000000000000000000000000000000000000000000000000003eb",
|
||||
pubkey = "85fc4ae543ca162474586e76d72c47d0151c3cb7b77e82c87e554abf72548e2e746bc675805b688b5016269e18ff4250"
|
||||
)
|
||||
|
||||
test_sk_to_pk(
|
||||
seckey = "00000000000000000000000000000000000000000000000000000000000003ec",
|
||||
pubkey = "8caa0de862793e567c6050aa822db2d6cb2b520bc62b6dbcba7e773067ed09c7ba0282d7c20e01500c6c2fa76408aded"
|
||||
)
|
||||
|
||||
# From BLST Rust test
|
||||
# cargo test test_sign -- --show-output
|
||||
#
|
||||
# [test]
|
||||
# fn test_sign() {
|
||||
# let ikm: [u8; 32] = [
|
||||
# 0x93, 0xad, 0x7e, 0x65, 0xde, 0xad, 0x05, 0x2a, 0x08, 0x3a,
|
||||
# 0x91, 0x0c, 0x8b, 0x72, 0x85, 0x91, 0x46, 0x4c, 0xca, 0x56,
|
||||
# 0x60, 0x5b, 0xb0, 0x56, 0xed, 0xfe, 0x2b, 0x60, 0xa6, 0x3c,
|
||||
# 0x48, 0x99,
|
||||
# ];
|
||||
#
|
||||
# let sk = SecretKey::key_gen(&ikm, &[]).unwrap();
|
||||
# print_bytes(&sk.serialize(), "sk: ");
|
||||
# let pk = sk.sk_to_pk();
|
||||
# print_bytes(&pk.compress(), "pk: ");
|
||||
#
|
||||
# ---- min_pk::tests::test_sign stdout ----
|
||||
# sk: 47faea55fe00a78306449165c017c9db86411a4c2467b4b89e21323c746406a0
|
||||
# pk: a18e29d0185a5a6d19edf052ae098fd2924f579b6dfb4905332b8f4fc78adeb3188ad8315bf279a144be026ac08f3441
|
||||
|
||||
test_sk_to_pk(
|
||||
seckey = "47faea55fe00a78306449165c017c9db86411a4c2467b4b89e21323c746406a0",
|
||||
pubkey = "a18e29d0185a5a6d19edf052ae098fd2924f579b6dfb4905332b8f4fc78adeb3188ad8315bf279a144be026ac08f3441"
|
||||
)
|
|
@ -0,0 +1,124 @@
|
|||
# Nim-BLSCurve
|
||||
# Copyright (c) 2018-Present 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.
|
||||
|
||||
# Test case generator
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Parameters
|
||||
# ------------------------------------------------------------------------------
|
||||
x = -(2^63 + 2^62 + 2^60 + 2^57 + 2^48 + 2^16)
|
||||
p = (x - 1)^2 * (x^4 - x^2 + 1)//3 + x
|
||||
r = x^4 - x^2 + 1
|
||||
cofactor = Integer('0x396c8c005555e1568c00aaab0000aaab')
|
||||
|
||||
# Effective cofactor for the G2 curve (that leads to equivalent hashToG2 when using endomorphisms)
|
||||
g2_h_eff = Integer('0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551')
|
||||
|
||||
# Finite fields
|
||||
Fp = GF(p)
|
||||
K2.<u> = PolynomialRing(Fp)
|
||||
Fp2.<beta> = Fp.extension(u^2+1)
|
||||
# K6.<v> = PolynomialRing(Fp2)
|
||||
# Fp6.<eta> = Fp2.extension(v^3-Fp2([1, 1])
|
||||
# K12.<w> = PolynomialRing(Fp6)
|
||||
# K12.<gamma> = F6.extension(w^2-eta)
|
||||
|
||||
# Curves
|
||||
b = 4
|
||||
SNR = Fp2([1, 1])
|
||||
G1 = EllipticCurve(Fp, [0, b])
|
||||
G2 = EllipticCurve(Fp2, [0, b*SNR])
|
||||
|
||||
# Generator points
|
||||
if False:
|
||||
P1 = G1.gen(0)
|
||||
(P1x, P1y, P1z) = P1
|
||||
print('P1x: ' + Integer(P1x).hex())
|
||||
print('P1y: ' + Integer(P1y).hex())
|
||||
else:
|
||||
# https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-02#section-4.3.2
|
||||
P1 = G1(
|
||||
Integer('0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'),
|
||||
Integer('0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'),
|
||||
Integer(1)
|
||||
)
|
||||
|
||||
def priv_to_pub(scalar):
|
||||
return scalar * P1
|
||||
|
||||
def pointToString(P):
|
||||
(Px, Py, Pz) = P
|
||||
return '(x: ' + Integer(Px).hex() + ', y: ' + Integer(Py).hex() + ')'
|
||||
|
||||
def pointToCompressed(P):
|
||||
(Px, Py, Pz) = P
|
||||
rawX = Integer(Px)
|
||||
if Py > p - Py:
|
||||
rawX |= 1 << 381
|
||||
rawX |= 1 << 383
|
||||
return int(rawX).to_bytes(48, 'big').hex()
|
||||
|
||||
for i in range(1000, 1010):
|
||||
print('---------------------------------------')
|
||||
print(f'seckey: {i}')
|
||||
print(f'seckey hex: {i.to_bytes(32, "big").hex()}')
|
||||
pubkey = priv_to_pub(i)
|
||||
print(f'pubKey (uncompressed): {pointToString(pubkey)}')
|
||||
print(f'pubKey (compressed): {pointToCompressed(pubkey)}')
|
||||
|
||||
# ---------------------------------------
|
||||
# seckey: 1000
|
||||
# seckey hex: 00000000000000000000000000000000000000000000000000000000000003e8
|
||||
# pubKey (uncompressed): (x: 60e75190e62b6a54142d147289a735c4ce11a9d997543da539a3db57def5ed83ba40b74e55065f02b35aa1d504c404b, y: 17ecb08d4bb31b7eeb6581e6808c6abf58958845b917e085baaab098b9a8a3ecc8caf6f1a06c46b0f7812b09aa52e7a0)
|
||||
# pubKey (compressed): a60e75190e62b6a54142d147289a735c4ce11a9d997543da539a3db57def5ed83ba40b74e55065f02b35aa1d504c404b
|
||||
# ---------------------------------------
|
||||
# seckey: 1001
|
||||
# seckey hex: 00000000000000000000000000000000000000000000000000000000000003e9
|
||||
# pubKey (uncompressed): (x: e12039459c60491672b6a6282355d8765ba6272387fb91a3e9604fa2a81450cf16b870bb446fc3a3e0a187fff6f8945, y: 18b6c1ed9f45d3cbc0b01b9d038dcecacbd702eb26469a0eb3905bd421461712f67f782b4735849644c1772c93fe3d09)
|
||||
# pubKey (compressed): ae12039459c60491672b6a6282355d8765ba6272387fb91a3e9604fa2a81450cf16b870bb446fc3a3e0a187fff6f8945
|
||||
# ---------------------------------------
|
||||
# seckey: 1002
|
||||
# seckey hex: 00000000000000000000000000000000000000000000000000000000000003ea
|
||||
# pubKey (uncompressed): (x: 147b327c8a15b39634a426af70c062b50632a744eddd41b5a4686414ef4cd9746bb11d0a53c6c2ff21bbcf331e07ac92, y: 78c2e9782fa5d9ab4e728684382717aa2b8fad61b5f5e7cf3baa0bc9465f57342bb7c6d7b232e70eebcdbf70f903a45)
|
||||
# pubKey (compressed): 947b327c8a15b39634a426af70c062b50632a744eddd41b5a4686414ef4cd9746bb11d0a53c6c2ff21bbcf331e07ac92
|
||||
# ---------------------------------------
|
||||
# seckey: 1003
|
||||
# seckey hex: 00000000000000000000000000000000000000000000000000000000000003eb
|
||||
# pubKey (uncompressed): (x: 5fc4ae543ca162474586e76d72c47d0151c3cb7b77e82c87e554abf72548e2e746bc675805b688b5016269e18ff4250, y: 7c13f661fd28bf1ea1cf51c762dda21547877eedf54e9263b3b5d0923820b58ed81503beb24fc4cd50bd47d9d67d7e)
|
||||
# pubKey (compressed): 85fc4ae543ca162474586e76d72c47d0151c3cb7b77e82c87e554abf72548e2e746bc675805b688b5016269e18ff4250
|
||||
# ---------------------------------------
|
||||
# seckey: 1004
|
||||
# seckey hex: 00000000000000000000000000000000000000000000000000000000000003ec
|
||||
# pubKey (uncompressed): (x: caa0de862793e567c6050aa822db2d6cb2b520bc62b6dbcba7e773067ed09c7ba0282d7c20e01500c6c2fa76408aded, y: c7c359be46db8efd81618b29cea252fdbfff8229dd3e3c7f98c10801fdc9bb65403d124b43a934f8a1cf8ca351ee1df)
|
||||
# pubKey (compressed): 8caa0de862793e567c6050aa822db2d6cb2b520bc62b6dbcba7e773067ed09c7ba0282d7c20e01500c6c2fa76408aded
|
||||
# ---------------------------------------
|
||||
# seckey: 1005
|
||||
# seckey hex: 00000000000000000000000000000000000000000000000000000000000003ed
|
||||
# pubKey (uncompressed): (x: a273fd05323e1381e10e93e683c34647328127020b3507fc8cddc337038e33fbd7a99ef0d2c7b6a278d7f8116162560, y: 134e59e38d0cdda7464634c997d9f08b7e336bdfa895b764f8c4e24e52e3f46683d8e798ada2d65f055adb4a7bf6c279)
|
||||
# pubKey (compressed): aa273fd05323e1381e10e93e683c34647328127020b3507fc8cddc337038e33fbd7a99ef0d2c7b6a278d7f8116162560
|
||||
# ---------------------------------------
|
||||
# seckey: 1006
|
||||
# seckey hex: 00000000000000000000000000000000000000000000000000000000000003ee
|
||||
# pubKey (uncompressed): (x: fcecff9ae0490f723123822c66f36996d237490d6769ee68f9f7a7da1c6bac8b5c3d0c4348e8ce8fc3d5159f8333484, y: 86e75481cf86317947ced9b0c52a631a22a213e49b9ea0cd016184d48541e9f2424a5e01a800673b7a2b2601cb77bea)
|
||||
# pubKey (compressed): 8fcecff9ae0490f723123822c66f36996d237490d6769ee68f9f7a7da1c6bac8b5c3d0c4348e8ce8fc3d5159f8333484
|
||||
# ---------------------------------------
|
||||
# seckey: 1007
|
||||
# seckey hex: 00000000000000000000000000000000000000000000000000000000000003ef
|
||||
# pubKey (uncompressed): (x: f4ffe81a50cf117069c9a66ad9f2776eeeae94fe02ba2a0f9596cb798f9e5bdf4719fceaa61746ffe2408f25b56d96e, y: 326c5937def2d0725be78d653b1e107c8faf40fea0759caf640ae0be5c569ef73ecdcc1d8552725f8de69e95f4cf53c)
|
||||
# pubKey (compressed): 8f4ffe81a50cf117069c9a66ad9f2776eeeae94fe02ba2a0f9596cb798f9e5bdf4719fceaa61746ffe2408f25b56d96e
|
||||
# ---------------------------------------
|
||||
# seckey: 1008
|
||||
# seckey hex: 00000000000000000000000000000000000000000000000000000000000003f0
|
||||
# pubKey (uncompressed): (x: 785405f275ee2fd934e83835a79ba651f80b0f432df1b806350dc949c169c60e60767e41faed8eaac5ed0e9e210787c, y: c82aaba7cb0db559d0eb9cb1bebb8d9de2ac1bbceda92518b16bdca4be5bda5b219b345ec2b3719fac5891eb3ee531a)
|
||||
# pubKey (compressed): 8785405f275ee2fd934e83835a79ba651f80b0f432df1b806350dc949c169c60e60767e41faed8eaac5ed0e9e210787c
|
||||
# ---------------------------------------
|
||||
# seckey: 1009
|
||||
# seckey hex: 00000000000000000000000000000000000000000000000000000000000003f1
|
||||
# pubKey (uncompressed): (x: ade2091378293a63d55328cef23736f4dbdc49bd3c0787b8c18cd6a8ddc2d42a279242e87b22d1909f3f1d55e5da66, y: 14f22ce1b5483fa15b71f81d998cbb695a369948214bf7d7c9841c26903cee7b5485bc1331061f1c9c17cce8778b15e)
|
||||
# pubKey (compressed): 80ade2091378293a63d55328cef23736f4dbdc49bd3c0787b8c18cd6a8ddc2d42a279242e87b22d1909f3f1d55e5da66
|
Loading…
Reference in New Issue