Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Falcon precompiled #2

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/crypto/bn256"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/params"
"github.com/open-quantum-safe/liboqs-go/oqs"
"golang.org/x/crypto/ripemd160"
)

Expand Down Expand Up @@ -121,6 +122,10 @@ var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{18}): &bls12381MapG2{},
}

var PrecompiledContractsPostQuantum = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{19}): &falcon512{},
}

var (
PrecompiledAddressesCancun []common.Address
PrecompiledAddressesBerlin []common.Address
Expand Down Expand Up @@ -1135,3 +1140,101 @@ func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash {

return h
}

// FALCON512 implementation precompile
type falcon512 struct{}

func (c *falcon512) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.Falcon512PerWordGas + params.Falcon512BaseGas
}

const (
falcon512SignatureName = "Falcon-512"
falcon512MethodSignature = 0xde8f50a1 // verify(bytes,bytes,bytes)
falcon512PublicKeyLength = 897
)

var (
errFalcon512InvalidMethodSignatureLength = errors.New("invalid input format")
errFalcon512FailedVerifierInitilization = errors.New("error initializing Falcon verifier")
errFalconInvalidMethodSignature = errors.New("invalid method signature")
)

// returns bytes32(0) if signature is valid, bytes32(1) otherwise
func (c *falcon512) Run(input []byte) ([]byte, error) {
verifier := oqs.Signature{}
defer verifier.Clean() // clean up even in case of panic

if err := verifier.Init(falcon512SignatureName, nil); err != nil {
return nil, errFalcon512FailedVerifierInitilization
}

if len(input) < 4 { // verifes method signature
return nil, errFalcon512InvalidMethodSignatureLength
}

if new(big.Int).SetBytes(getData(input, 0, 4)).Uint64() != falcon512MethodSignature {
return nil, errFalconInvalidMethodSignature
}

digest := make([]byte, 32)
digest[31] = 1

input = getData(input, 4, uint64(len(input)))

if len(input) < 96 {
return digest, nil
}

signatureOffset := new(big.Int).SetBytes(getData(input, 0, 32)).Uint64()
pubKeyOffset := new(big.Int).SetBytes(getData(input, 32, 32)).Uint64()
dataOffset := new(big.Int).SetBytes(getData(input, 64, 32)).Uint64()

if signatureOffset == 0 || pubKeyOffset == 0 || dataOffset == 0 {
return digest, nil
}
if len(input) < int(signatureOffset)+32 || signatureOffset == 0 {
return digest, nil
}
signatureLength := new(big.Int).SetBytes(getData(input, signatureOffset, 32)).Uint64()
if signatureLength == 0 {
return digest, nil
}
if len(input) < int(signatureOffset)+32+int(signatureLength) {
return digest, nil
}
signatureSlice := getData(input, signatureOffset+32, signatureLength)

if len(input) < int(pubKeyOffset)+32 {
return digest, nil
}
pubKeyLength := new(big.Int).SetBytes(getData(input, pubKeyOffset, 32)).Uint64()
if pubKeyLength == 0 {
return digest, nil
}
if len(input) < int(pubKeyOffset)+32+int(pubKeyLength) {
return digest, nil
}
pubKeySlice := getData(input, pubKeyOffset+32, pubKeyLength)

if len(input) < int(dataOffset)+32 {
return digest, nil
}
dataLength := new(big.Int).SetBytes(getData(input, dataOffset, 32)).Uint64()
if dataLength == 0 {
return digest, nil
}
if len(input) < int(dataOffset)+32+int(dataLength) {
return digest, nil
}
dataSlice := getData(input, dataOffset+32, dataLength)

isValid, err := verifier.Verify(dataSlice, signatureSlice, pubKeySlice)
if err != nil {
return digest, nil
}
if isValid {
digest[31] = 0
}
return digest, nil
}
114 changes: 114 additions & 0 deletions core/vm/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ var allPrecompiles = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{17}): &bls12381MapG1{},
common.BytesToAddress([]byte{18}): &bls12381MapG2{},
common.BytesToAddress([]byte{20}): &kzgPointEvaluation{},
common.BytesToAddress([]byte{19}): &falcon512{},
}

// EIP-152 test vectors
Expand All @@ -92,6 +93,101 @@ var blake2FMalformedInputTests = []precompiledFailureTest{
},
}

// EIP-7213 test vectors
var falcon512MalformedInputTests = []precompiledFailureTest{
{
Input: "",
ExpectedError: errFalcon512InvalidMethodSignatureLength.Error(),
Name: "vector 0: empty input",
},
{
Input: "111111110000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000006e0",
ExpectedError: errFalconInvalidMethodSignature.Error(),
Name: "vector 1: 4 method signature bytes is not de8f50a1",
},
}

var falcon512InvalidSignatureTests = []precompiledTest{
{
Input: "de8f50a1",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 2: No data after method signature",
},
{
Input: "de8f50a1abc",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 3: No enough data after method signature",
},
{
Input: "de8f50a100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000e0",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 4: Signature offset is zero",
},
{
Input: "de8f50a10000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 5: Public key offset is zero",
},
{
Input: "de8f50a1000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 6: data offset is zero",
},

{
Input: "de8f50a1000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 7: signature lenght not present in input",
},
{
Input: "de8f50a1000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 8: signature length is present but its value is zero",
},
{
Input: "de8f50a1000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000600000000",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 9: Signature indicated length is too long",
},

{
Input: "de8f50a1000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000201111111111111111111111111111111111111111111111111111111111111111",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 10: public key lenght not present in input",
},
{
Input: "de8f50a1000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 11: public key length is present but its value is zero",
},
{
Input: "de8f50a1000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000800000000000000",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 12: Public Key indicated length is too long",
},

{
Input: "de8f50a1000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000202222222222222222222222222222222222222222222222222222222222222222",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 13: data lenght not present in input",
},
{
Input: "de8f50a1000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000201111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000002022222222222222222222222222222222222222222222222222222222222222220000000000000000000000000000000000000000000000000000000000000000",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 14: data length is present but its value is zero",
},
{
Input: "de8f50a1000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002011111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000020222222222222222222222222222222222222222222222222222222222222222200000000000000000000000000000000000000000000000050000000000000000",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 15: Data indicated length is too long",
},
{
Input: "de8f50a10000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000031200000000000000000000000000000000000000000000000000000000000006b30000000000000000000000000000000000000000000000000000000000000292390191ef48486eb9d9a6823d8e6ff0d7f4df8bed13af7fa55a7e8dfa0d19725842a5451bcf4c061982d021c63a7d666c2024fe57033b1a1bda8c2179c518c94d434947eacc109efe792857ff6450cc853e8bb9d5d951b3ddb1397fadc2210762b479e386e660a68eb2ad034a58a3d0cce2370edf257ff4f81fe97c9bb10c1a96ee87d2414fdf4ea39f9f7c0604d1a3aebe5d73a6a1f7221a99eb2389b905da94766cd27a9a89f13d56b97cdd346689cfc5b3bdbbdc5102d3b5f93a2a95be40afcaac416d831391474c2298da0a359bc958a5f227de991a338944d6ebe4963f1a4ba5bb3d5c672526992329c84c5770c03a5e43504a28fa86f3b9bd72354c0b1921d1b568e5212856d8436f79a8c409e631082a4e28b7cb99d89c2a9ab3c196c56a77e6d05718196b316d8e9bedcfc214e2a33c02f0afd821dbfcb966c8bb8dde01c812a2045b6bc8de767f97b739dc8ed262f43dfc092e49f34c7728839895e4620620e4a193e94dbf2a9d439e249e6ec3377ed6734030acd43d138b982c36df814a4257f971a53aa5d92a7670915469013e68124edae3fc11b4ca470938ee2f218bc0e11468a6092f233de914790c972f77d95f968ac5f6e0968e0efa8d628825f3fbad2254e04e9ba34defc698b2e19e9629290f4e5682270595035b07404b091f5325293ed4021c619d7f0914ac47219b9e5df6fda5acbb398adb5c8540dc3390a548d82be42fac8f6ef9963546bcf278e63fdd49d0abbe62208e3956468771df4a50dd7a3aa197d81f58c14425ee166d29aef3eb2c171ff9b24f575e0ae9a65227d1e57ab6c5df11a369645dac717ab671a4c10aef72824134d0e68676bb138ca20eb5e08a0d1f90ee48af1cce1f21c72394ac427f382ced545183689cdb72cec8ea30c77389a16204356259e4b1142d000000000000000000000000000000000000000000000000000000000000038109b7107f987f937ea7566bca38e1578b8d0b59294e68bd208bfa90133101f5efd8755e9f1fd20564762585baa5a4f165ebec6df80ab5248a22bba940a7754abe5329b5c60345f395ad2a33ac106e65f14b91d0dca308ae4cc6db5fe69eee9fe4a392ff64f52865070eb5587e7f83ab6c187cc0584b3552920a3d4b50ab0a4a1e8d9dea3d4b5eb015a2f4ab59ae3d0ad2c081d8d2428a83806de7973ec65975ff8fd7287c642b6a83250255b61838cb4d68c52600b8c5330fce48aaeb806d4fb99a9add5e56577454a5a5ad5699711dd04854bf11484713dea5d9abd17f9214c33c4f4d47a6600bc241011f52e29d9820ac85ab70dfccb1d08c003b489c0826bf28ccee71945637b7161e6a99584451bf8351a43a0b0755ce3044f0840b7ad0489e6572c896666463e2cfc8ebe1258e3a963ab1433b173865705c15f044bcfde1b780d29e422604a9081d2349f6d6b40671b7c6ae77f44c16a22412e9e32cb116363d99ca4d2c3ace6730fd45fc6612d389edcd1c9b2201ba32a4705fac61005e184b89a4c90983acd7afee694ac9d904473eb512ec2d4875c1c954b791506f02c9e65f5d04976ea4e81d22d4884eb1c47eeb1a7ee109e12e61ce0ee4dfa88fdacb78ed61b0a327c2069d8cd33d184e68a60c22f6804faceca968cf5c1c276c7d16386f38bb82d5ea1e11d801f5ef33d3a3b0171dc870741ce8373c779ae8935211348c436285703681f1e6b0adc05c35c56196c246731ee2a4a998ef918a165023a76d324c58419cd9e76ebca0e13823d90b2ebc641717b404e2ee2937d48b38441e88f1086c15c95de8a48632bee5fb56f99f07ac31037323000317c291e2eace7865ece23548e804679241f1366748b1656cd58c28b86d5e08e269d0e3a668a834f4178a188dd63384042773fac10b3d96f533ecabe3a8a27e091d5846d6ead8ac9241437240ad4f7d274b78403402210ad042ddf73d59e02abf657aa41e101455df638d44c181e4ca219f2c6679088ff11af439115d8ef38f3614b957e1ebb9cc2e6bee0c0664da7ba3f1268404a5bac8ed45854881972382908861cc7f14f5d03b112273917854617590aad70eeedf398cb206ff5c7f7a9c5390dfa27e14b1148518833b3375cdfaf5a73680cdd7d0ea5f664672fe91ae6700032a3ee21aeb3ab7b6a0f66b0f65597a7fb6f5c1a9b1459d48885db3734abec9918c0f3a8135bbb2279984a054115e9c12a8f10ca25b93be8a3acfb94dc6a90d4da0e0a7ada80000000000000000000000000000000000000000000000000000000000000064486c8e99de7f81a3b0f4610bb555be687d67e079f5b03ee9d18c21d766fe3d2d36ea378a89294f839dc9bcd9a8251f92cfd39aacc1e228f44442e95b3c59ef904613ece9d312028b07a3cb26b3c9844dcdb2699299d7d47fd63f7889d6c5ce34626b583b",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "vector 16: Correct format but invalid Signature",
},
}

func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
p := allPrecompiles[common.HexToAddress(addr)]
in := common.Hex2Bytes(test.Input)
Expand Down Expand Up @@ -393,3 +489,21 @@ func BenchmarkPrecompiledBLS12381G2MultiExpWorstCase(b *testing.B) {
}
benchmarkPrecompiled("0f", testcase, b)
}

func BenchmarkPrecompiledFalcon512(b *testing.B) { benchJson("falconBenchVectors", "13", b) }

func TestPrecompileFalcon512MalformedInput(t *testing.T) {
for _, test := range falcon512MalformedInputTests {
testPrecompiledFailure("13", test, t)
}
}

func TestPrecompiledFalcon512InvalidSignature(t *testing.T) {
p := allPrecompiles[common.HexToAddress("13")]
for _, test := range falcon512InvalidSignatureTests {
in := common.Hex2Bytes(test.Input)
reqGas := p.RequiredGas(in)
test.Gas = reqGas
testPrecompiled("13", test, t)
}
}
Loading