2024-01-20 java后台rsa方式进行签名合约soli

2024-01-19  本文已影响0人  gdlooker

首先进入Java后台生成签名示例代码如下:

package cn.gdchent.springbootsell;

import cn.gdchent.springbootsell.utils.SolidityUtil;
import org.apache.catalina.connector.Connector;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ImportResource;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.Hash;
import org.web3j.crypto.Sign;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;
import org.web3j.utils.Numeric;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@ServletComponentScan  //Servlet 注解的扫描
@SpringBootApplication(scanBasePackages = {"cn.gdchent.springbootsell"})
//@MapperScan(basePackages={"cn.gdchent.springbootsell.generator"}) //如果你自己使用自定义配置数据源配置扫描mybatis生成的mapper路径 就不需要这个注解
@ImportResource(locations = {"classpath:beans.xml"}) //自己定义xml文件 然后来读取
public class SpringbootsellApplication {
   //私钥地址对应账号是9698
   private static final String PRIVATE_KEY ="fec4de8b60d3f9ef0003fc4143d2675eb6c3dbced35633e8aa7854abbe8e0459";
   public static void main(String[] args) {
      SpringApplication.run(SpringbootsellApplication.class, args);
      getSign();
   }
   public static String getSign(){
       // 连接到以太坊网络
       Web3j web3j = Web3j.build(new HttpService("https://ropsten.infura.io/v3/YOUR_INFURA_PROJECT_ID"));
       // 设置私钥
       Credentials credentials = Credentials.create(PRIVATE_KEY);

       List<BigInteger> list = Arrays.asList(
               BigInteger.valueOf(36),
               BigInteger.valueOf(69),
               BigInteger.valueOf(555)
       );
       String address = "0x21e35e6e68E465C96e0186a8FeEE356aD9A79Ee3";
       String dataString = "0xabcdef123456";

       // 设置参数值
       BigInteger num = BigInteger.valueOf(123);
       // 构建要签名的数据
       byte[] encodedNum = Numeric.toBytesPadded(num, 32);

       //将interger类型的数组转换为字节数组
       List<Byte> byteList = new ArrayList<>();
       for (BigInteger value : list) {
           byte[] paddedBytes = Numeric.toBytesPadded(value, 32);
           for (byte b : paddedBytes) {
               byteList.add(b);
           }
       }
       byte[] encodedList = new byte[byteList.size()];
       for (int i = 0; i < byteList.size(); i++) {
           encodedList[i] = byteList.get(i);
       }
       byte[] encodedAddress = Numeric.hexStringToByteArray(address);
       byte[] encodedDataString = Numeric.hexStringToByteArray(dataString);

       byte[] message = SolidityUtil.concatenate(encodedNum, encodedList, encodedAddress, encodedDataString);

       // keccak256哈希
       byte[] hash = Hash.sha3(message);
       // 使用私钥签名消息
       Sign.SignatureData signatureData = Sign.signPrefixedMessage(hash, credentials.getEcKeyPair());
       byte[] signature = SolidityUtil.concatenate(signatureData.getR(), signatureData.getS(), signatureData.getV());
       String signResult = Hex.toHexString(signature);
       // 打印签名结果
       System.out.println("Signature1: 0x" +signResult);
       return signResult;
   }
   /**
    * 处理url地址带数组作参数错误情况
    * @return
    */
   @Bean
   public TomcatServletWebServerFactory webServerFactory() {
       TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
       factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
           @Override
           public void customize(Connector connector) {
               connector.setProperty("relaxedPathChars", "\"<>[\\]^`{|}");
               connector.setProperty("relaxedQueryChars", "\"<>[\\]^`{|}");
           }
       });
       return factory;
   }
}

运行生成的Java签名输出如下图所示:0x9fc0a4d018440dd8067914b31aa9cec8f95101d65991c686e5c98051ae314e0c57729ea5c261a225cbc9dab6656e1dc8e424e46564c28d64c308ce7b25bcd9f91c


web3j生成签名.png

接下来进入到solidity的验签示例代码如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract VerfityJava {
    address public signAccount = 0x1D99d05a9616973Ba67751e7DD3600aBB29d9698;
    address public javaAccount;
    bytes32 public byteSig;
    bytes32 public byteSig2;

    event Check(address account);

    function genMsg(
        uint256 num,
        uint256[] memory list,
        address _address,
        bytes memory dataString
    ) public returns (bytes32) {
        byteSig = keccak256(abi.encodePacked(num, list, _address, dataString));
        byteSig2 = getEthSignedMessageHash(byteSig);
        return byteSig2;
    }

    //第二次得到签名hash
    function getEthSignedMessageHash(bytes32 sig)
        public
        pure
        returns (bytes32)
    {
        return
            keccak256(
                abi.encodePacked("\x19Ethereum Signed Message:\n32", sig)
            );
    }

    function check(
        uint256 num,
        uint256[] memory list,
        address _address,
        bytes memory dataString,
        bytes memory sign
    ) external returns (bool) {
        bytes32 messageHash = genMsg(num, list, _address, dataString);
        javaAccount = recoverSigner(messageHash, sign);
        emit Check(signAccount);
        return javaAccount == signAccount;
    }

    function splitSignature(bytes memory sign)
        internal
        pure
        returns (
            uint8,
            bytes32,
            bytes32
        )
    {
        require(sign.length == 65, "invalid signature length");
        bytes32 r;
        bytes32 s;
        uint8 v;

        assembly {
            // first 32 bytes, after the length prefix
            r := mload(add(sign, 32))
            // second 32 bytes
            s := mload(add(sign, 64))
            // final byte (first byte of the next 32 bytes)
            v := byte(0, mload(add(sign, 96)))
        }

        return (v, r, s);
    }

    function recoverSigner(bytes32 message, bytes memory sign)
        internal
        pure
        returns (address)
    {
        uint8 v;
        bytes32 r;
        bytes32 s;

        (v, r, s) = splitSignature(sign);

        return ecrecover(message, v, r, s);
    }
}

验签结果如下


合约验签成功.png
上一篇 下一篇

猜你喜欢

热点阅读