ftu/fstoken.c

158 lines
5.8 KiB
C
Raw Normal View History

2022-09-09 06:47:49 +00:00
#include "fstoken.h"
void fstoken_keygen(byte* ikm, byte* sk_byte, byte* pk_byte){
blst_scalar sk;
blst_p2 pk;
blst_p2_affine pk_affine;
blst_keygen(&sk, ikm, 32, 0, 0); // generate a secret key from IKM
blst_bendian_from_scalar(sk_byte, &sk); // convert it to 32 big-endian bytes in sk_byte to return
blst_sk_to_pk_in_g2(&pk, &sk); // get a public key from the secret key
blst_p2_to_affine(&pk_affine, &pk); // convert it to an affine point, which is what most uses of the public key use
blst_p2_affine_compress(pk_byte, &pk_affine); // compress it to 96 bytes in pk_byte to return
}
void fstoken_get_pk_from_sk(byte* sk_byte, byte* pk_byte){
blst_p2 pk;
blst_p2_affine pk_affine;
blst_scalar sk;
blst_scalar_from_bendian(&sk, sk_byte); //convert the SK to a blst_scalar
blst_sk_to_pk_in_g2(&pk, &sk); // get a PK from it
blst_p2_to_affine(&pk_affine, &pk); // convert the PK to affine
blst_p2_affine_compress(pk_byte, &pk_affine); // compress the PK
}
void fstoken_gen_request(fstoken_request* req, fstoken_request_descriptor* reqdesc, fstoken_target_descriptor* target, byte* token_id, byte* blinding_factor){
byte debug_print_buf[256]; //get rid of this
int targ_idbytes;
blst_p1 hash, blinded_id;
blst_scalar blinding_r;
targ_idbytes = (target->idbits + 7)/8;
//printf("IDBYTES_MAX: %i, IDBYTES for target: %i\n", IDBYTES_MAX, targ_idbytes);
memcpy(&reqdesc->blinding_factor, blinding_factor, 32);
bit_truncated_copy(token_id, reqdesc->token_id, IDBYTES_MAX, target->idbits); //cut down the supplied token ID to match the target's IDBITS value
//debug_print_bytes("Working with ID: ", reqdesc->token_id, IDBYTES_MAX);
//debug_print_bytes("Working with Blinding Factor: ", blinding_factor, 32);
// Hash the Token ID to a BLST P1
blst_hash_to_g1(&hash, token_id, targ_idbytes, FSTOKEN_DST, strlen((char *) FSTOKEN_DST), target->pk, 96);
// Get the blinding factor as a BLST scalar
blst_scalar_from_bendian(&blinding_r, blinding_factor);
blst_p1_serialize(debug_print_buf, &hash);
//debug_print_bytes("HASH: ", debug_print_buf, 96);
// Sign the hash as if the blinding factor was a private key
blst_sign_pk_in_g2(&blinded_id, &hash, &blinding_r);
// Compress the resulting signature and put it in the signature request
blst_p1_compress(req->id_blind, &blinded_id);
//debug_print_bytes("Blinded and compressed for wire: ", req->id_blind, 48);
}
int fstoken_sign_request(fstoken_request* req, fstoken_signature* sig, fstoken_target_descriptor* targ){
blst_scalar sk;
blst_p1 req_id, signature;
blst_p1_affine req_id_affine;
// get the secret key as a scalar
blst_scalar_from_bendian(&sk, targ->sk);
// Deserialize the request - it's already a serialized P1 point, we don't need to (literally) rehash it
blst_p1_uncompress(&req_id_affine, req->id_blind);
// i do not know why deserializing always gives you affine points
blst_p1_from_affine(&req_id, &req_id_affine);
// Return 1 if the point isn't in G1, this is basically a sanity check
if(!blst_p1_in_g1(&req_id)) return 1;
// sign with it
blst_sign_pk_in_g2(&signature, &req_id, &sk);
// Compress and print the signature
blst_p1_compress(sig->signature, &signature);
//debug_print_bytes("Compressed signature:", sig->signature, 48);
return 0;
}
int fstoken_gen_token(fstoken_request_descriptor* req, fstoken_signature* sig, fstoken_token* token){
blst_p1 returned_signature, unblinded_signature;
blst_p1_affine returned_signature_affine;
blst_scalar blinding_r, inverse_r;
// We now have the signature back. returned_signature is a blst_p1_affine because this is pk_in_g2.
blst_p1_uncompress(&returned_signature_affine, sig->signature);
// Convert the decompressed returned signature from an affine to a P1
blst_p1_from_affine(&returned_signature, &returned_signature_affine);
// Confirm the signature point is in the G1 group
if(!blst_p1_in_g1(&returned_signature)) return 1;
// Retreive the blinding factor and take its inverse
blst_scalar_from_bendian(&blinding_r, req->blinding_factor);
blst_sk_inverse(&inverse_r, &blinding_r);
//print_scalar("Inverse R: ", &inverse_r);
// Unblind the signature using the inverse of the blinding factor
blst_sign_pk_in_g2(&unblinded_signature, &returned_signature, &inverse_r);
memcpy(token->token_id, req->token_id, IDBYTES_MAX);
blst_p1_compress(token->signature, &unblinded_signature);
return 0;
}
// 0 = valid token, 1 = signature check failed, 2 = signature point invalid
int fstoken_verify_token(fstoken_token* token, fstoken_target_descriptor* targ){
int targ_idbytes;
blst_p1_affine sig;
blst_p2_affine pk;
blst_p1_uncompress(&sig, token->signature);
blst_p2_uncompress(&pk, targ->pk);
BLST_ERROR returned;
if(!blst_p1_affine_in_g1(&sig)) return 2;
targ_idbytes = (targ->idbits + 7) / 8;
returned = blst_core_verify_pk_in_g2(&pk, &sig, 1, token->token_id, targ_idbytes, FSTOKEN_DST, strlen((char *) FSTOKEN_DST), targ->pk, 96);
return (returned != BLST_SUCCESS);
}
void bit_truncated_copy(byte* src, byte* dest, size_t destlen, int bits){
uint8_t bitmask;
int bytes;
bytes = (bits + 7) / 8;
memset(dest, 0, destlen); //clear out the destination
memcpy(dest, src, bytes); //copy over as many bytes as are needed for the number of bits
//bitmask out the high (fsp is little-endian) bits of the destination if bits is not a round number of bytes
bitmask = 0xFF >> (bits % 8);
//printf("mask: 0x%0x\n", bitmask);
dest[bytes - 1] = dest[bytes - 1] & bitmask;
}
// Helper function to get the length (in bytes) of an (unshortened) token for the target
int fstoken_target_token_length(fstoken_target_descriptor* target){
return 48 + (target->idbits + 7) / 8;
2022-09-09 06:47:49 +00:00
}