Develop branch. Convert ecdsa.PublicKey to []uints.U8 for ethereum address recovery #802
-
Hi guys! I wonder what is the best way to convert |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
Hi @NikitaMasych, right now we don't have convenience methods. Some time ago I also needed something similar and realised that it is easier to provide the public key serialised as bytes as additional witness, convert it to pubkey using the method See the following snippet. It is for P384, but should be easily modifiable for P256. func byteArrayToLimbs(api frontend.API, array []uints.U8) ([]frontend.Variable, error) {
ret := make([]frontend.Variable, (len(array)+7)/8)
ap := make([]uints.U8, 8*len(ret)-len(array))
for i := range ap {
ap[i] = uints.NewU8(0)
}
array = append(ap, array...)
for i := range ret {
ret[len(ret)-1-i] = api.Add(
api.Mul(1<<0, array[8*i+7].Val),
api.Mul(1<<8, array[8*i+6].Val),
api.Mul(1<<16, array[8*i+5].Val),
api.Mul(1<<24, array[8*i+4].Val),
api.Mul(1<<32, array[8*i+3].Val),
api.Mul(1<<40, array[8*i+2].Val),
api.Mul(1<<48, array[8*i+1].Val),
api.Mul(1<<56, array[8*i+0].Val),
)
}
return ret, nil
}
func BytesToPubkey(api frontend.API, pubkey []uints.U8) (*ecdsa.PublicKey[p384.P384Fp, p384.P384Fr], error) {
xb, err := byteArrayToLimbs(api, pubkey[1:49])
if err != nil {
return nil, fmt.Errorf("xb: %w", err)
}
yb, err := byteArrayToLimbs(api, pubkey[49:97])
if err != nil {
return nil, fmt.Errorf("yb: %w", err)
}
var pub ecdsa.PublicKey[p384.P384Fp, p384.P384Fr]
efp, err := emulated.NewField[p384.P384Fp](api)
if err != nil {
return nil, fmt.Errorf("field: %w", err)
}
pub.X = *efp.NewElement(xb)
pub.Y = *efp.NewElement(yb)
return &pub, nil
} |
Beta Was this translation helpful? Give feedback.
-
I've decided that I'll leave here a direct solution I came with, inspired by the proposition of @ivokub, in case anyone will face the same issue🙂: func pubKeyToBytes(api frontend.API, pubKey *ecdsa.PublicKey[emulated.Secp256k1Fp, emulated.Secp256k1Fr]) ([]uints.U8, error) {
xLimbs := pubKey.X.Limbs
yLimbs := pubKey.Y.Limbs
u64api, err := uints.New[uints.U64](api)
if err != nil {
return nil, err
}
result := limbsToBytes(u64api, xLimbs)
return append(result, limbsToBytes(u64api, yLimbs)...), nil
}
func limbsToBytes(u64api *uints.BinaryField[uints.U64], limbs []frontend.Variable) []uints.U8 {
result := make([]uints.U8, 0, len(limbs)*8)
for i := range limbs {
u64 := u64api.ValueOf(limbs[len(limbs)-1-i])
result = append(result, u64api.UnpackMSB(u64)...)
}
return result
} |
Beta Was this translation helpful? Give feedback.
Hi @NikitaMasych, right now we don't have convenience methods. Some time ago I also needed something similar and realised that it is easier to provide the public key serialised as bytes as additional witness, convert it to pubkey using the method
BytesToPublicKey
below and then show that the obtained pubkey corresponds to the one we are checking against.See the following snippet. It is for P384, but should be easily modifiable for P256.