-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
243 additions
and
163 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// This vrf package makes the VRF API in Algorand's libsodium C library available to golang. | ||
package vrf | ||
|
||
/* | ||
#cgo CFLAGS: -I./libsodium/src/libsodium/include | ||
#cgo LDFLAGS: -lsodium | ||
#include "./libsodium/src/libsodium/include/sodium.h" | ||
*/ | ||
import "C" | ||
import ( | ||
"encoding/hex" | ||
"errors" | ||
"fmt" | ||
"unsafe" | ||
) | ||
|
||
const PUBLICKEYBYTES = uint32(C.crypto_vrf_PUBLICKEYBYTES) | ||
|
||
const SECRETKEYBYTES = uint32(C.crypto_vrf_SECRETKEYBYTES) | ||
|
||
const SEEDBYTES = uint32(C.crypto_vrf_SEEDBYTES) | ||
|
||
const PROOFBYTES = uint32(C.crypto_vrf_PROOFBYTES) | ||
|
||
const OUTPUTBYTES = uint32(C.crypto_vrf_OUTPUTBYTES) | ||
|
||
const PRIMITIVE = C.crypto_vrf_PRIMITIVE | ||
|
||
// Generate an Ed25519 key pair for use with VRF. | ||
func KeyPair() ([PUBLICKEYBYTES]byte, [SECRETKEYBYTES]byte) { | ||
var publicKey [PUBLICKEYBYTES]byte | ||
var privateKey [SECRETKEYBYTES]byte | ||
publicKeyPtr := (*C.uchar)(unsafe.Pointer(&publicKey)) | ||
privateKeyPtr := (*C.uchar)(unsafe.Pointer(&privateKey)) | ||
C.crypto_vrf_keypair(publicKeyPtr, privateKeyPtr) | ||
return publicKey, privateKey | ||
} | ||
|
||
// Generate an Ed25519 key pair for use with VRF. Parameter `seed` means the cofactor in Curve25519 and EdDSA. | ||
func KeyPairFromSeed(seed [SEEDBYTES]byte) ([PUBLICKEYBYTES]byte, [SECRETKEYBYTES]byte) { | ||
var publicKey [PUBLICKEYBYTES]byte | ||
var privateKey [SECRETKEYBYTES]byte | ||
publicKeyPtr := (*C.uchar)(unsafe.Pointer(&publicKey)) | ||
privateKeyPtr := (*C.uchar)(unsafe.Pointer(&privateKey)) | ||
seedPtr := (*C.uchar)(unsafe.Pointer(&seed)) | ||
C.crypto_vrf_keypair_from_seed(publicKeyPtr, privateKeyPtr, seedPtr) | ||
return publicKey, privateKey | ||
} | ||
|
||
// Verifies that the specified public key is valid. | ||
func IsValidKey(publicKey [PUBLICKEYBYTES]byte) bool { | ||
publicKeyPtr := (*C.uchar)(unsafe.Pointer(&publicKey)) | ||
return C.crypto_vrf_is_valid_key(publicKeyPtr) != 0 | ||
} | ||
|
||
// Construct a VRF proof from given secret key and message. | ||
func Prove(privateKey [SECRETKEYBYTES]byte, message []byte) ([PROOFBYTES]byte, error) { | ||
var proof [PROOFBYTES]byte | ||
proofPtr := (*C.uchar)(unsafe.Pointer(&proof)) | ||
privateKeyPtr := (*C.uchar)(unsafe.Pointer(&privateKey)) | ||
messagePtr := (*C.uchar)(unsafe.Pointer(&message)) | ||
messageLen := (C.ulonglong)(len(message)) | ||
if C.crypto_vrf_prove(proofPtr, privateKeyPtr, messagePtr, messageLen) != 0 { | ||
return proof, errors.New(fmt.Sprintf("unable to decode the given privateKey: %s", | ||
hex.EncodeToString(privateKey[:]))) | ||
} | ||
return proof, nil | ||
} | ||
|
||
// Verifies that proof was legitimately generated by private key for the given public key, and stores the | ||
// VRF hash in output. Note that VRF "verify()" means the process of generating output from public key, | ||
// proof, and message. | ||
// https://tools.ietf.org/html/draft-irtf-cfrg-vrf-04#section-5.3 | ||
func Verify(publicKey [PUBLICKEYBYTES]byte, proof [PROOFBYTES]byte, message []byte) ([OUTPUTBYTES]byte, error) { | ||
var output [OUTPUTBYTES]byte | ||
outputPtr := (*C.uchar)(unsafe.Pointer(&output)) | ||
publicKeyPtr := (*C.uchar)(unsafe.Pointer(&publicKey)) | ||
proofPtr := (*C.uchar)(unsafe.Pointer(&proof)) | ||
messagePtr := (*C.uchar)(unsafe.Pointer(&message)) | ||
messageLen := (C.ulonglong)(len(message)) | ||
if C.crypto_vrf_verify(outputPtr, publicKeyPtr, proofPtr, messagePtr, messageLen) != 0 { | ||
return output, errors.New(fmt.Sprintf( | ||
"given public key is invalid, or the proof isn't legitimately generated for the message:"+ | ||
" public_key=%s, proof=%s, message=%s", | ||
hex.EncodeToString(publicKey[:]), hex.EncodeToString(proof[:]), hex.EncodeToString(message[:]))) | ||
} | ||
return output, nil | ||
} | ||
|
||
// Calculate the output (hash value) from the specified proof. | ||
// In essence, this function returns a valid value if given proof is any point on the finite field. Otherwise, | ||
// this will return an error. | ||
func ProofToHash(proof [PROOFBYTES]byte) ([OUTPUTBYTES]byte, error) { | ||
var output [OUTPUTBYTES]byte | ||
outputPtr := (*C.uchar)(unsafe.Pointer(&output)) | ||
proofPtr := (*C.uchar)(unsafe.Pointer(&proof)) | ||
if C.crypto_vrf_proof_to_hash(outputPtr, proofPtr) != 0 { | ||
return output, errors.New(fmt.Sprintf( | ||
"given proof isn't legitimately generated: proof=%s", hex.EncodeToString(proof[:]))) | ||
} | ||
return output, nil | ||
} | ||
|
||
func SkToPk(privateKey [SECRETKEYBYTES]byte) [PUBLICKEYBYTES]byte { | ||
var publicKey [PUBLICKEYBYTES]byte | ||
publicKeyPtr := (*C.uchar)(unsafe.Pointer(&publicKey)) | ||
privateKeyPtr := (*C.uchar)(unsafe.Pointer(&privateKey)) | ||
C.crypto_vrf_sk_to_pk(publicKeyPtr, privateKeyPtr) // void | ||
return publicKey | ||
} | ||
|
||
func SkToSeed(privateKey [SECRETKEYBYTES]byte) [SEEDBYTES]byte { | ||
var seed [SEEDBYTES]byte | ||
seedPtr := (*C.uchar)(unsafe.Pointer(&seed)) | ||
privateKeyPtr := (*C.uchar)(unsafe.Pointer(&privateKey)) | ||
C.crypto_vrf_sk_to_seed(seedPtr, privateKeyPtr) // void | ||
return seed | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,123 +1,32 @@ | ||
// This vrf package makes the VRF API in Algorand's libsodium C library available to golang. | ||
package vrf | ||
|
||
/* | ||
#cgo CFLAGS: -I./internal/vrf/libsodium/src/libsodium/include | ||
#cgo LDFLAGS: -lsodium | ||
#include <sodium.h> | ||
*/ | ||
import "C" | ||
import ( | ||
"encoding/hex" | ||
"errors" | ||
"fmt" | ||
"github.com/tendermint/tendermint/crypto/ed25519" | ||
vrfimpl "github.com/tendermint/tendermint/crypto/vrf/internal/vrf" | ||
"unsafe" | ||
) | ||
|
||
const PUBLICKEYBYTES = uint32(C.crypto_vrf_PUBLICKEYBYTES) | ||
const PROOFBYTES = vrfimpl.PROOFBYTES | ||
|
||
const SECRETKEYBYTES = uint32(C.crypto_vrf_SECRETKEYBYTES) | ||
const OUTPUTBYTES = vrfimpl.OUTPUTBYTES | ||
|
||
const SEEDBYTES = uint32(C.crypto_vrf_SEEDBYTES) | ||
|
||
const PROOFBYTES = uint32(C.crypto_vrf_PROOFBYTES) | ||
|
||
const OUTPUTBYTES = uint32(C.crypto_vrf_OUTPUTBYTES) | ||
|
||
const PRIMITIVE = C.crypto_vrf_PRIMITIVE | ||
|
||
// Generate an Ed25519 key pair for use with VRF. | ||
// Note that this key pair is proprietary to libsodium and is NOT compatible with the Ed25519 key | ||
// used by Tendermint. | ||
func KeyPair() ([PUBLICKEYBYTES]byte, [SECRETKEYBYTES]byte) { | ||
var publicKey [PUBLICKEYBYTES]byte | ||
var privateKey [SECRETKEYBYTES]byte | ||
var publicKeyPtr = (*C.uchar)(unsafe.Pointer(&publicKey)) | ||
var privateKeyPtr = (*C.uchar)(unsafe.Pointer(&privateKey)) | ||
C.crypto_vrf_keypair(publicKeyPtr, privateKeyPtr) | ||
return publicKey, privateKey | ||
} | ||
|
||
// Generate an Ed25519 key pair for use with VRF. Parameter `seed` means the cofactor (secret) | ||
// in Curve25519 and EdDSA. | ||
// Note that this key pair is proprietary to libsodium and is NOT compatible with the Ed25519 key | ||
// used by Tendermint. | ||
func KeyPairFromSeed(seed [SEEDBYTES]byte) ([PUBLICKEYBYTES]byte, [SECRETKEYBYTES]byte) { | ||
var publicKey [PUBLICKEYBYTES]byte | ||
var privateKey [SECRETKEYBYTES]byte | ||
var publicKeyPtr = (*C.uchar)(unsafe.Pointer(&publicKey)) | ||
var privateKeyPtr = (*C.uchar)(unsafe.Pointer(&privateKey)) | ||
var seedPtr = (*C.uchar)(unsafe.Pointer(&seed)) | ||
C.crypto_vrf_keypair_from_seed(publicKeyPtr, privateKeyPtr, seedPtr) | ||
return publicKey, privateKey | ||
} | ||
|
||
// Verifies that the specified public key is valid. | ||
func IsValidKey(publicKey [PUBLICKEYBYTES]byte) bool { | ||
var publicKeyPtr = (*C.uchar)(unsafe.Pointer(&publicKey)) | ||
return C.crypto_vrf_is_valid_key(publicKeyPtr) != 0 | ||
func convertSK(privateKey ed25519.PrivKeyEd25519) [64]byte { | ||
return *(*[64]byte)(unsafe.Pointer(&privateKey[0])) | ||
} | ||
|
||
// If the proof was legitimately generated for the message using the public key, return its output (hash value). | ||
// Otherwise an error is returned. | ||
func Prove(privateKey [SECRETKEYBYTES]byte, message []byte) ([PROOFBYTES]byte, error) { | ||
var proof [PROOFBYTES]byte | ||
var proofPtr = (*C.uchar)(unsafe.Pointer(&proof)) | ||
var privateKeyPtr = (*C.uchar)(unsafe.Pointer(&privateKey)) | ||
var messagePtr = (*C.uchar)(unsafe.Pointer(&message)) | ||
var messageLen = (C.ulonglong)(len(message)) | ||
if C.crypto_vrf_prove(proofPtr, privateKeyPtr, messagePtr, messageLen) != 0 { | ||
// TODO determine error message | ||
return proof, errors.New("failed to ") | ||
} | ||
return proof, nil | ||
func convertPK(publicKey ed25519.PubKeyEd25519) [ed25519.PubKeyEd25519Size]byte { | ||
return *(*[ed25519.PubKeyEd25519Size]byte)(unsafe.Pointer(&publicKey[0])) | ||
} | ||
|
||
// VRF "verify()" means the process of generating output from public key, proof, and message. If verification | ||
// succeeds, return the VRF output hash that specified in IRFT Draft section 5.3. | ||
// https://tools.ietf.org/html/draft-irtf-cfrg-vrf-04#section-5.3 | ||
// | ||
// For a given public key and message, there are many possible proofs but only one possible output hash. | ||
func Verify(publicKey [PUBLICKEYBYTES]byte, proof [PROOFBYTES]byte, message []byte) ([OUTPUTBYTES]byte, error) { | ||
var output [OUTPUTBYTES]byte | ||
var outputPtr = (*C.uchar)(unsafe.Pointer(&output)) | ||
var publicKeyPtr = (*C.uchar)(unsafe.Pointer(&publicKey)) | ||
var proofPtr = (*C.uchar)(unsafe.Pointer(&proof)) | ||
var messagePtr = (*C.uchar)(unsafe.Pointer(&message)) | ||
var messageLen = (C.ulonglong)(len(message)) | ||
if C.crypto_vrf_verify(outputPtr, publicKeyPtr, proofPtr, messagePtr, messageLen) != 0 { | ||
return output, errors.New(fmt.Sprintf("verification failed: pk=%s, pi=%s, m=%s", | ||
hex.EncodeToString(publicKey[:]), hex.EncodeToString(proof[:]), hex.EncodeToString(message[:]))) | ||
} | ||
return output, nil | ||
func Prove(privateKey ed25519.PrivKeyEd25519, message []byte) ([PROOFBYTES]byte, error) { | ||
return vrfimpl.Prove(convertSK(privateKey), message) | ||
} | ||
|
||
// Calculate the output (hash value) from the specified proof. | ||
// In essence, this function returns a valid value if given proof is any point on the finite field. Otherwise, | ||
// this will return an error. | ||
func ProofToHash(proof [PROOFBYTES]byte) ([OUTPUTBYTES]byte, error) { | ||
var output [OUTPUTBYTES]byte | ||
var outputPtr = (*C.uchar)(unsafe.Pointer(&output)) | ||
var proofPtr = (*C.uchar)(unsafe.Pointer(&proof)) | ||
if C.crypto_vrf_proof_to_hash(outputPtr, proofPtr) != 0 { | ||
// TODO determine error message | ||
return output, errors.New("") | ||
} | ||
return output, nil | ||
} | ||
|
||
func SkToPk(privateKey [SECRETKEYBYTES]byte) [PUBLICKEYBYTES]byte { | ||
var publicKey [PUBLICKEYBYTES]byte | ||
var publicKeyPtr = (*C.uchar)(unsafe.Pointer(&publicKey)) | ||
var privateKeyPtr = (*C.uchar)(unsafe.Pointer(&privateKey)) | ||
C.crypto_vrf_sk_to_pk(publicKeyPtr, privateKeyPtr) // void | ||
return publicKey | ||
return vrfimpl.ProofToHash(proof) | ||
} | ||
|
||
func SkToSeed(privateKey [SECRETKEYBYTES]byte) [SEEDBYTES]byte { | ||
var seed [SEEDBYTES]byte | ||
var seedPtr = (*C.uchar)(unsafe.Pointer(&seed)) | ||
var privateKeyPtr = (*C.uchar)(unsafe.Pointer(&privateKey)) | ||
C.crypto_vrf_sk_to_seed(seedPtr, privateKeyPtr) // void | ||
return seed | ||
func Verify(publicKey ed25519.PubKeyEd25519, proof [PROOFBYTES]byte, message []byte) ([OUTPUTBYTES]byte, error) { | ||
return vrfimpl.Verify(convertPK(publicKey), proof, message) | ||
} |
Oops, something went wrong.