hi', 1758412800000 ) ), hash( 'sha256', "BNS-SITE1\nexample.bch\nindex.html\n" . hash( 'sha256', '

hi

' ) . "\n1758412800000" ), 'the upload digest matches the gateway formula' ); $headers = SP_Message::site_headers( 'example.bch', 'index.html', '

hi

', $key['private'], 1758412800000 ); T::is( $headers['x-bns-ts'], '1758412800000', 'the timestamp header is the one signed' ); T::is( strlen( base64_decode( $headers['x-bns-sig'], true ) ), 65, 'the signature header decodes to 65 bytes' ); // The gateway recovers the signer and compares it to the on-chain owner. // Reproduce that here so a change to either side is caught. T::is( SP_CashAddr::from_public_key( SP_Secp256k1::recover( base64_decode( $headers['x-bns-sig'], true ), SP_Message::site_digest( 'example.bch', 'index.html', '

hi

', 1758412800000 ) ), 'bchtest' ), $key['address'], 'the gateway would recover the publishing address from the header' ); // Changing any signed component must invalidate it. T::ok( SP_CashAddr::from_public_key( SP_Secp256k1::recover( base64_decode( $headers['x-bns-sig'], true ), SP_Message::site_digest( 'example.bch', 'index.html', '

TAMPERED

', 1758412800000 ) ), 'bchtest' ) !== $key['address'], 'altered upload bytes no longer recover the publishing address' ); T::group( 'canonical JSON' ); T::is( SP_Message::canonical_json( array( 'b' => 1, 'a' => 2 ) ), '{"a":2,"b":1}', 'keys are sorted' ); T::is( SP_Message::canonical_json( array( 'a' => null, 'b' => 1 ) ), '{"b":1}', 'null members are dropped' ); T::is( SP_Message::canonical_json( array( 'z' => array( 'y' => 1, 'x' => 2 ) ) ), '{"z":{"x":2,"y":1}}', 'nested keys are sorted too' ); T::is( SP_Message::canonical_json( array( 'url' => 'https://a/b' ) ), '{"url":"https://a/b"}', 'slashes are not escaped, matching JSON.stringify' ); // Written as a concatenation so the expected value cannot itself be stored as // a literal e-acute, which would make this assertion test nothing. T::is( SP_Message::canonical_json( array( 'note' => 'caf' . chr( 0xc3 ) . chr( 0xa9 ) ) ), '{"note":"caf' . chr( 92 ) . 'u00e9"}', 'non-ASCII is backslash-u escaped' ); T::is( SP_Message::canonical_json( array( 'list' => array( 3, 1, 2 ) ) ), '{"list":[3,1,2]}', 'array order is preserved' ); exit( T::summary() );