herumi / bls

288 stars 132 forks source link

Serialize BN254 public key to uncompressed format #104

Closed darcys22 closed 10 months ago

darcys22 commented 10 months ago

I have been trying send a bls::PublicKey to an ethereum smart contract which will eventually call their ecAdd precompile.

Under the hood it looks like they are using cloudflares golang bn256 library. Which unmarshals using this function:

https://github.com/ethereum/go-ethereum/blob/e501b3b05db8e169f67dc78b7b59bc352b3c638d/crypto/bn256/cloudflare/bn256.go#L129

They appear to want the bytes in an uncompressed big endian format, then converts from normal to mont using montEncode()

I'm having issues with serializing into something that function will accept. Originally tried the getStr() methods but couldnt get them to work. Currently doing this which is similar to the serializeuncompressedpublicKey function, but for BN254 rather than BLS12_384

    bls::PublicKey publicKey;                                                                                                                                                  
    secretKey.getPublicKey(publicKey);                                                                                                                                         
    //return publicKey.serializeToHexStr();                                                                                                                                    
    mclSize serializedPublicKeySize = 32;                                                                                                                                      
    std::vector<unsigned char> serialized_pubkey(serializedPublicKeySize*2);                                                                                                   
    const blsPublicKey* pub = publicKey.getPtr();                                                                                                                              
    uint8_t *dst = serialized_pubkey.data();                                                                                                                                   
    const mcl::bn::G1* g1Point = reinterpret_cast<const mcl::bn::G1*>(&pub->v);                                                                                                
    mcl::bn::G1 g1Point2 = *g1Point;                                                                                                                                           
    g1Point2.normalize();  
    g1Point2.x.fromMont();  
    g1Point2.y.fromMont();  
    if (g1Point2.x.serialize(dst, serializedPublicKeySize, mcl::IoSerialize | mcl::IoBigEndian) == 0)  
        throw std::runtime_error("size of x is zero");  
    if (g1Point2.y.serialize(dst + serializedPublicKeySize, serializedPublicKeySize, mcl::IoSerialize | mcl::IoBigEndian) == 0)  
        throw std::runtime_error("size of y is zero"); 

and sending the serialized_pubkey over cloudflare library. Which is giving malformed point and coordinate exceeds modulus errors depending on how I do it.

Im initializing the bls library like this:

#define BLS_ETH
#define MCLBN_FP_UNIT_SIZE 4
#define MCLBN_FR_UNIT_SIZE 4

and initializing the secret key like this:

    bls::SecretKey secretKey;
    secretKey.init();

I've honestly run out of ideas on what the difference between the two libraries are. Would appreciate any hints?

herumi commented 10 months ago

I have not run that code, so the following description may be incorrect.

g1Point2.x.fromMont();
g1Point2.y.fromMont();

You don't have to call fromMont because serialize calls them if necessary.

darcys22 commented 10 months ago

Think I've realised the issue:

The BN254 curve used by this library is a different curve than the one used by ethereums precompiled contracts. Although sharing a similar name.